ÿØÿà JFIF    ÿÛ „ ( %!1!%*+...983,7(-.- PK!<]Ms C C#ruby/bigdecimal-1.3.4/bigdecimal.sonuȯELF>'@;@8 @ p*p*!p*! **!*!888$$ Std Ptd   QtdRtdp*p*!p*!GNUޥQ|C9O[ O^@h@@^cBE|X=|/\؁9wqX "s-M:K`.UXqy #dCE"=_.jT/cI0, SF"z?#\ 0!H1! 0G P1!v0!@1!U0!0!__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizegOne_ABCED9B4_CE73__00400511F31DgZero_ABCED9B1_CE73__00400511F31Druby_xfreerb_thread_currentrb_thread_local_asetrb_inspectrb_str_duprb_str_catrb_exc_new_strrb_exc_raiserb_obj_classrb_class_namerb_warningrb_str_new_staticrb_call_superstrlenmemmove__sprintf_chkrb_thread_local_arefrb_num2ushortrb_id2symrb_hash_lookup2rb_check_string_typestrncasecmprb_eArgErrorrb_raiserb_sym2strruby_xreallocmemcpyrb_fatalrb_check_typeddatarb_yieldrb_protectrb_jump_tag__stack_chk_failrb_num2ulongrb_uint2bigrb_eFloatDomainErrorruby_xmallocmemsetrb_str_tmp_newrb_str_resizerb_warnrb_str_new_cstrrb_data_typed_object_wraprb_string_value_cstrrb_check_safe_objrb_eTypeErrorrb_bugrb_num2intrb_fix2intrb_error_arityrb_big_packrb_sym2idrb_rational_numrb_rational_denrb_typeddata_is_kind_ofrb_big2strrb_cBigDecimalrb_float_valuerb_funcallvrb_num_coerce_binrb_int2bigrb_intern2rb_str_newsqrt__errno_locationruby_strtodrb_float_newrb_assoc_newrb_num_coerce_reloprb_num_coerce_cmprb_memhashrb_eZeroDivErrorrb_ary_new_caparb_ary_pushrb_Rationalrb_num2longrb_thread_check_intsrb_eMathDomainErrorrb_big_cmpruby_snprintfroundrb_dbl2bigrb_mBigMathInit_bigdecimalrb_cNumericrb_define_classrb_define_alloc_funcrb_define_global_functionrb_define_singleton_methodrb_define_constrb_define_methodrb_define_modulelibruby.so.2.5libc.so.6_edata__bss_start_endGLIBC_2.3.4GLIBC_2.14GLIBC_2.4GLIBC_2.2.5ti ii ui p*!(x*!@(*!*!*!*!**!(/!/! /!c/!/!_/!/!d/!,/!./!1/!Q/!S/!U/!b/!W,!,!-!-!-!-! -!(-! 0-! 8-! @-! H-!P-!X-!`-!h-!p-!x-!-!-!-!-!-!-!-!-!-!-! -!!-!"-!#-!$-!%-!&.!'.!(.!).!* .!+(.!-0.!/8.!0@.!2H.!3P.!4X.!5`.!6h.!7p.!8x.!9.!:.!;.!<.!=.!>.!?.!@.!A.!B.!C.!D.!E.!F.!G.!H.!I/!J/!K/!L/!M /!N(/!O0/!P8/!R@/!TH/!VP/!WX/!X`/!Yh/!Zp/![x/!\/!]HH!HtH5!%!hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhR%e !D%] !D%U !D%M !D%E !D%= !D%5 !D%- !D%% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D% !D%} !D%u !D%m !D%e !D%] !D%U !D%M !D%E !D%= !D%5 !D%- !D%% !D% !D% !D% !D% !D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%}!D%u!D%m!D%e!D%]!D%U!D%M!D%E!D%=!D%5!D%-!D%%!D%!D%!D% !D%!D%!D%!D%!D%!D%!D%!D%  H% f.fH=A!H:!H9tH!Ht H=!H5 !H)HHH?HHtH!HtfD=!u+UH=!Ht H=!d!]wHGH(ff.@!fDHB ffffUfLBfHMt6J$fH*Y XIvJ(fH*Y uXHRHHffWH1H!f.z,u*H !H:!^fW:!HÐ!ff.ztJ l!H!f.z%u#H!^fW  6!^!1H@!f.PhbHE!Hr!^!;!f. zuHB!^!Hff.fHtBfff.@USHH-)!lHH[HTH]CSHH@u Hu4H!H51HHHHHH@HH=1JH=HDU1HSH=$HHH[]HtSG PfwI HsDHW>FHDuHOHD HxH9sH)HH@fHHHH)Hff.@ftftEftO1ftfNaN@fuJt|0.0Ãt[u+HHInfinityFH-0.0FH-InfinitHyfF@ H+0.0F 0.0FAVAUATIUSH=Ht^ItTI>(111fD<.tD1UDH[]DHHZHwH5HuH[];H51f.HhHHHf.H HH8HfD듐fSH 3HHHtH[)fH HH1[USHHHFH4$HtFHSHHs$H}$HPHCHHEHCHEC fE C"fE"%HH[]FH5H=11ATUHH5 SHFH5o HI4H9tHLDHC H[]A\USHdH%(HD$1HT$H=8 iH^|$uHL$dH3 %(Hu H[]WfSHP HH(Ht"tH[fH[H dHHD1[ATUSHHH?H9w*H\L% !HLHH[]A\HHff.USHdH%(HD$1!HT$H= H8HH]|$uHL$dH3 %(Hu H[]&PXH5HH HH81ff.@Hftft-ftHH=H=1H=SHWHtH1H[H5%H=81fPXH5"HH H81fUHSHPf t*ft5HHrHH=ӿ1$@HH1[]SHftftQft+H[fDH5ٻoH[f.H5OH[f.H5ɻ/H[f.G PfwIHHsF PfvKHWHNHGH9FHCFH9tHH)H)HHHsHH5ھHHIHHsDffffAD ftcft]CfAG$H5HGfDG fDtTtff~G1G$H5HGfO DtZf`G$HGfw H5)gf.VfkfffDfCf.Pf+f~Lf~LG$HGfW aff~ff$f~G$HGfG ff.fHOL1H~;H~'I@HHHHHLGDHyI@HHAHvHHHHf G$HG fw H5)fMHHIHNfDf ~1G$HGfW H5xG$HGfG fDM~#HHIH 'DHHIHf.HHIH:ffO fO Afw#]HsG$1HGfHWf.HBDD$Eu2HHuG$HGf~f1fW f.w$HWurU1SHHHuL$tHtH)HHHWuH[]ffG 1HCHt(H{$Hʸff.fAWAVAUATIUSHH8H{H88HHHHH IIMA$L wfDH v t#Ht#H88HHHHHBI9LGHLL$HxLL$H IHhH1E1D tJDRA< 0 H<_IJ|HD u H=ܸH H=Hd H=HH=&HE<-tD$1<+@L50 1@у0 HHL5uHl$(II1E1HLD$ H88HHL$HMHBLDI9ICH$HD$H|$HL$IHD$LD$ AD$$ID$ID$AfET$ 1HSI|$$LD$HL$[HL$LD$HHD$(<-ZHD$E1<+u HA1Lt$L\$(ILD$ wLHHHH4HH O4 HMHLA0McM)I9HHrH/HH9IL9HHuK 11f.HiwHh(yH@I@$H@fh H8L[]A\A]A^A_fH~D$fDH~;LHHHHt$Lt$D$LD$ HL'@HHHHD$LE<-iD$1<+u II88E1HA1G\L 3LH?HL1H)HIHHHHH9_D$K1I9AD$I9v6Hw01f.4D HHDpAD$HwI9wI9HMtVMT$1@H&L9A H@f G$HGNA1fD HH[]A\A]A^A_D$Et1f} DM1DHI9}ɚ;nMf} HEE$HE7fM HHEMtYH88LHHHUHI)t8U$1ɾKfDҁɚ;v HEHI9uۉU$HH[]A\A]A^A_@FfL_1MG$IL\$AE1A$HD$8HD$tfDHD$1J|$L $LD$H~fAL $LD$H߭EJcH>DfU fB\$HD$$AwBD\$$E4@M-f.A @BD$Ht$HZODA1fDw fDD4$D$$E1D$ <$f} D,$EYANxt$$fAvf} x []A\A]A^Avf} ~HL[H]A\A]A^%DAE#wDAdwDAE#wAeAwAtAwjf.f.&f(fT f. Zff.ATf(USH f/wfW d%,f/"1^Hf/sLg1HH$T$JL$D$FL$fT$f/M1I9YfH,ɉʉL$HH*\f/wI9vdl$L`f/vjYʺLcfS HkH,ɋT$fG$HGfO ft$1ID$f/YfS 1LcHkH,MuH H1[]A\Gf/G$HGvAfDG fw fD%h1~f/j@YHf/wSDE1G$HGfDO 1AVAUATUSF HfAffPfHVLnHH$Hv$HWDfAOąL9oLFoLoN4fGLA t)L9mL1ҋM$MtU LHLkKD[]A\A]A^ÐDC$fHCDNE~@1fs []A\A]A^@G$1HG1f{ []A\A]A^1fK DG$fHGDNE~0fW SD1HLk6DfG #ff.fATIUHSӺ :HvL[H]A\f[1]A\fN$tyHFH~pHVN H9ssH)HGHGH9HG1fHWfG HFHtHHHLL$AL$HH9u ffDG$HGf~ fW ffG fDAWIAVIAUMATIUHSHLD$YIWH|$PE$HL$XI^HuI+_LM9VMCVH~LD$I9HIuH88HIFHH;EsRI$IOHEH4H9HKH9H)HHIHH9AD HL$XMU/@I<$H9rAD HL$P뛐IIFII$MUIFLUHHEHHDHH[]A\A]A^A_DIMUIMUAWAVAUAATIUHSHHHv dH%(HD$81H ɃM1҅tOAT$ M rAfu]fC$HCflAfD[ @H\$8dH3%(HiHH[]A\A]A^A_ff_E1AHEAGt6I9D$*MD$H}I9HIFHt5E$A9D$$|1fD\$E9\$wdHH9uI9wPA1fM@fNǍDpu+AC$ HCfDS @M1fAE1ffDK AHL$ G|?EE|GHD$fEPLHHHD$ PLL$@LD$8_AXD$ HLD$(IL$L$H|$ Ht$0L$ Mt3JH9rfJH9IHBT$T$MuH9dII)IHD$I9u1HHIAD$BD$1HtnJL Hf1HHtKHAD$=ɚ;v-ʚ;DDfDNA~fDk I)MtBD 1fAfC HC1HtT L$ 1H9HCH4@PHHLHD$ PLL$@LD$8 Y^D$ H!LD$(It$L$9r)1҉t$ H|$ J4HL$0H9nMtMAʚ;AfDJ4AH9IDHB+T$D)҉T$MuѺHH9v'HAʚ;DHH)кD$H9rE1H9@HtFHH)LH@)1At$Ht"HAt$9sɚ;fH)Ht)T M91fA} EDD1AfC EDHHHCHDILpDLHHCHSvfDHHAD$D$H9rMLLHHL/@uYÄuYHH#ЃHH\H[]DÄtHHt Ht‰ǃHDYt%HE6t%HEؼt%HE赼HH\H[]fDHn@DHH\H[]fDH- H\ԴHHH趴HH[]ú-H H5H81H H5τH81ͳff.fAWAVIAUIATA4USH@HHdH%(H$1HD6H$AtRA DItKA tEI4t?Aw1H^HcH>IuIt Mu@1H$dH3 %(H[]A\A]A^A_DMI4]M9tLHHIHtH$HLHT$]Aw LIHT$IH[H׃LcMLL}3IDH5 L聲IF  LHD$8HXH tHXH襲HHx H Hf.MILef(fT f.ff.zH5X L114I@H\$pM1HIH H H޿HkfDHL$0HT$(LHHD$(+HH HyLL.I>fD1LL$H u LL$H5HD$HIyLL$LHIHLT$HD$@LHIHHD$HxLT$H5ƒIHIRHD$PIFIGHJHH9HFH ׼ H| HHOLT$LHHLHT$XLH|$'LT$LL$LLLT$%LT$Ar LI4fDL HMH=迳HH gH LH8~fDH|$(w zH8ILzH5 HH H81ϮH 1$H $HH$H$ fHX ^Hf/wH5LaH50LM&1USHHdH %(HL$81ɃHHHFH5HHHHD$ 1Hp2!HD$HD$H tHD$HXHEH HHL1aHi11HH4蹸HQH|$H褮HD$HL$8dH3 %(u)HH[]H\$H|1fHHWP 1ftftft HfD1HfHHP ft1fHDHDHHfx HHHHH@ HHDHHgp$HPtBHHҺHHHDHwHHHHH9wHcHDHSHH@dH%(HD$81H5EHHHHD$謴1H¯HD$HD$H upHt$H11H苶HD$H u>H|$HH|$HcHD$HL$8dH3 %(u)H@[HD$HxDHD$HpЫSHH@ fHDH[ff.HH@ fHHff.UHSH8dH%(HD$(1H5~HHH$HEHfDIF1HH4HHT$HT$AV fH ff@f@ f f@7f*"HwHcH>fDH5٦ Hqu}*"QH2xHcH>D1ҾH HHT$HT$AV f3*t1HL$(dH3 %( H0[]A\A]A^Ð1HHHHT$fHV}fDH H@HD$(dH3%(H0HL[]A\A]A^酡DH HuľH=rcHH H HHLHI_HI HHD$(dH3%(H0HL[]A\A]A^魟D)@EЅ*H؀"H vHcH>Dqzfthf_ffHxI9~?f*"gH wHcH>1ifffH*"%HWwHcH>fDfDHfH~~fHrhHDHHZ@H= pgHH H=o?HH} 8H=rHHU fQf*"'HvHcH>1Qfs*"HAwHcH>f~z*"HwHcH>LHMFM9LIFHt+p$A9v$wr31DDT$E9T$wrHH9uM9s/ff~*"w\HwHcH>v*f:*"w5H#xHcH>I*"wHxHcH>H=k1HfDGf>fLf<f=f*fAUIATUSHHH8dH%(HD$(1IHH$؃1HHHHHEH5mHD$HEID$HfDfC (萒AUATIUHHSH(dH%(HD$1+HcHu-HD$dH3%(H(LH[]A\A]T@1虢LHI;LH耢HHLHHH$=HHoHD$dH3%(u)u H(H[]A\A]9fK;葑蜣ff.ATUSH dH%(HD$1GHH\$tWA1tua؃HHHtZ tUwHHnHcH>LfLA貔cH\$HcuHuH|$ʏHt$H HvH Tf.Hxof(fT of.HIHHHL$dH3 %(H []A\fˏ4fDH5 H葏5HD$H@ fDH;HH$yH 1D$H#D$HHD$0HD$@Ǒ股H H5bH81zHH5`HHy H81W2fAUIH5 ATUHSHHdH%(HD$1軏LInHHs HH$hHu3MtLFH] HH+HL$dH3 %(uH[]A\A]ÐHLuH苎ff.ATHc I1USHdH%(HD$1HG H8藍LHHHs HH$贠Hu'H] HH+HL$dH3 %(uH[]A\@H1ΜH@AWAVAUATUHHSH׺HXdH%(HD$H1IHHD$ .H5JbL11HD$试H$H1轐HD$HD$H gLt$I>A} LfA} SLFI^A+9H}HH|$H$uHt@eXH1H$H5daL1ԔHƐH<$HHD>1HHt HC<0t<.H<$tH4$LޕfDL H|$HsHD$Ht$HdH34%(HX[]A\A]A^A_H$LL7DHD$Lpf蛏fDA-I^ImM]HIE1AMu`Mx^EE$HH []1HL\$EHML\$AHMu.HIM9IMtCD$Hs 1H0׈CAH9uDHS Hu.HHS @HZHyefHHC@0H9ufDL)0.Hsf HDHS H)HK fDHB@H@0H9uHP H9uHHHHH)HH\ 0fI^A fH|$$H|$I臉I$ 1+u(IT$IH$HHDBH$I$IʍAv t߃0 vƃ߀FH5\LˑHHHIT$I뙺1襋H H5\H81]8UHSHdH%(HD$1eHHH] H$Ht(Ht"HL$dH3 %(HDu+H[]fDHEH}$H4cH1H]襈DAWAVAUATIUSHHHxdH%(HD$h1IHHD$؃1HHHHHEH H5[HD$HEIEHL4LOt6 uHLH5ZIHHD$ XHLH5ZIHHD$(;HLH5dZIHLD$HD$0HLLIHLHD$8MID$HH5ZL,MLߪHH5ZLIHL $HD$@辪L $1ɺHHLLHD$H轷LHLD$HHLL$+L$LLLHD$hdH3%(Av HxL[]A\A]A^A_EDH^tiKIEHH4HBH HtTHLHteHL$hdH3 %(uPHx[]A\A]A^A_@H~HfD H=_Y蟉HH fAWAVAUIATIԺUSHHHhdH%(HD$X1IHHD$؃H1HHHHHD$AF f+K fffQfH5 H4$HfffINIFHsH?H1H?H)IFHHCH1H)HCH5/XH9HBL| L+K|? H5UWHHHD$ H$HHLHIHLHD$(lyE1"1Yom@AWHAVAUATUSHHHT$HdH%(H$1HH|$H|$tK؃HHHt0 t+wHJHcH>@HuHx HH8sD{nHD$uHt$1H肷HtX f\$>HH\$H\$Hf|$>H$y fP Hw H5?HSp HW~Hx HHD$@G fRHL$XIIHHL$(HL$PHHL$0fDp$HP1Ʌt.H Hw!fHHHHH9wHG$t8HHHfHHHHH9rH)HL<$H?H1H)I)!kMHt$LIIH@LCO|?H@HLl-ILABnLcMtLLILLHsI} IG fID$ H5 q HiHC X f\$>fLfBf|$>Hu H|$H5<HB1@$H@fH HD$X1HH+|WHlf(fT Hf. Hf1f/Ht$讴p H{H$dH3%(H[]A\A]A^A_1HHhKA!IH@HLHgIIFHL$(HT$0LLHD$PHHu H[LLkI.+hfD1LD$ xH Ut LD$ H5;HD$HIxLHIHHD$`聳LHIHHD$hbIWH5:IHHJHD$pIEIFHH9HFH s H| HH>LLHHHT$xLuH|$xsLD$ LL#Aw LzIfDL0fILd$@f|$>,ID$ p$HPtfLvLHHHHD$@I?ALHf{ H$=HU` H<$H5'HwHD$0E1@$1HH@HfDx fH\$hdH3%(Hx[]A\A]A^A_DLpW8ƒvHHHe< ] =LVI LHHA A W H5Z LRtkHt$LHD$0=LH±HLIMAIIt MLZUH5$HHq^ H81QLpUD$5UL$f.  1f/f/ 1L,O|E1C f<MLHH5_ HL$8LLL$HD$8RLL$HH] H5$HH<$,up H0d{LSH$Uf(QIYHH5e^ HL$8HHD$8:RHLDH?HAueMIA  ~uHL$8<LHD$8Q1H…tH4$LIdAAAC fVLH?MA LHH5AA'A A: H[ HH5^#4fDEcMIA  Dt LDL${Rf1DL$f/@H H5m\ HL$8LHD$8BPHLRIfDE1LH6@DȃYHL$8<LDL$HD$8ODL$HYHZ H<$H5W!HrHD$0f{ HA@$H@fDh ACDCLHH2A (A McAAD+LHHA A, C fnfdMM5I(A L1HŨO  G HHH6 @ , EQ O  Ld$8<HHD$8LMDDH(  A    L<LHD$8MH( f{ fL荓VI}IEH/X HfpH5oIHHD$Hs FfMfD M3 AAE$IEfEU ILA^@Hlf.HOHLfLLNf1f/f.A Ht]E1BfIH5 X HL$8LHD$8KHLH5W HL$8LLL$HD$8KLL$H LUDLLL$MLL$IH@LLL$MLL$HD$L!MoHHbHD$UHHHDI1ILOMHLLHHLHvLLL$MLH}LLL$HH@HH1I^DDeMI}A  neHL$8<LHD$8IHwf{ rMuItA rHwT HH5muvMIA Ht$0LH$!JHT$0H$H҃A@$H@fDp NMuItA tuLHH҃LHLH?IHD$(AA fH $LL$H@HHi7L%ZS H3Hl-HI<$LL$HI9HHH $HH@HHT I<$HHT$(HT$0HT$(fff&H{MbHD$IIEH5lH|_H5[HH@HH| _HLImuIL|$HHNuH|$A f.IHHL_LHuK?H;D$vLH)L$HL|$LL)LLtMrH|$MtLGFH?FItAu fft fAu LmHf1f/AE$IEIEfAE |H0Q H<$H5Hhf{ IMuIt A t|HQ H5H81CMO L#IHCHH5HHHHhIHHD$HzA AHt$0LXFHD$0HЃAE$IEfAm xMuUIA u4Ht$0LEHD$0HЃHO HdQLHHЃMULAE$HIE M;OfA} IfDE1AE$IEfEE H<$BHH BL%O H3HI<$HHALL$HgOH$LhXLAHF&LAHFMAAAE$IEfEM Mu7IAAE$IEfEe uLHHЃHD$TH{.{$$fAE f{ AE$IEIEAfAE fDAE$IEfA] AtAAE$IEfE] ~fAM fAu H*N LHLHLo3HH5N HL$8HHD$8AHHHHIA kE<L<LHD$8\AHH9L H<$H5HcLHSf{ E$HEfE u HR+BfAU H?CHIBHHAIILs>H;Cf{ E$HEHfE CL&Bf1f/L>HBLH?>LH?rLAf1f/XL=HB;HHHt$Ht$Hff.UH=SHdH%(HD$1AH= HK AH= HK Aff.J HK zuHGJ ^ J f.J z$u"HI HJ ^ J  uJ J f.zgueHI HI f.~% ^f(fW /J ztJf.z4u2^fW J Df.ztHAI ^yI H5ZHUH5HJ mUH=HI HH H0@HH H5`HH@H5;H=>H;HDH5>H;HH5q>H;HH5~>H;1HRAH5Tf>H;H`H5DK>H;1HCH523>H;1HKH5>H;1HH5>H;1HLH5=H= ;H;H5HX?H;5wH5D?H;H50?H;H5?H;H5?H; H5>H;H5>H;!H5>H;H5>H;H5>H;H5>H;H5|>H; H5h>H; H5T>H; H5@>H;H5,>H;H5>H;H5>H;HH5=H;H5=H;HH5=H;H5=H;HH5= H=n 9HHH$EH;H5>Hc=H=9HHH$H;H5:H,=H;H=H5 q;H;HHH5V;H;1HH5>;H;HH5#;H;H$H5;H;HH5:H;HH5 :H;1HH5:H;HH5:H;1HCH5 :H;1H+H5Vo:H;1HH5EW:H;1HH52?:H;HPH5$:H;HH5 :H;1H
H5] R9H;HH5 79H;HH5 9H;1H|H5 9H;1H|H5 8H;1HPH5 8H;1HH5 8H;HH5 8H;1HՋH5 8H;HH5 n8H;1HH5 V8H;HGH5t ;8H;HH5_ 8H;HaH5I 8H;H6H5] 7H;H H57H;HH5 7H;HŚH5 7H;HH5 ~7H;HH5 c7H;HTH5~H7H;H)H5^-7H;HH5E7H;1HfH5R 6H;1HH57 6H;HH5% 6H;1HH5 6H;1HsH5 6H;1H+H5 6H;1HH5 g6H;1HH5 O6H;1H#H5 76H;HH5 6H;H݄H5 6H= 57H? HHH5t H5H;HH5Z 5H=R 47H=Q H@ 7H= H@ 7H= H@ 6H= H@ 6 H= Hq@ 6 H= HQ@ 6H= H1@ 6H= H@ t6H= H? \6H=H? D6H=H? ,6H=H? 6H=O Hq? 5H]? HD$dH3%(uH[]92HH can't be coerced into BigDecimalBigDecimal.ver is deprecated; use BigDecimal::VERSION instead.BigDecimal.new is deprecated; use Kernel.BigDecimal method instead.Computation results to 'NaN'(Not a Number)Computation results to 'Infinity'Computation results to '-Infinity'invalid value for BigDecimal(): "%li "Conversion from String to BigDecimal overflow (last few digits discarded).load failed: invalid character in the marshaled stringERROR(VpDivd): space for remainder too small.second argument must be true or falsefirst argument for BigDecimal.mode invalid%li can't be coerced into BigDecimal without a precisionBigDecimal to Float conversionUndefined operation in BigDecimalCmp()can't omit precision for a %li .Zero or negative precision for expComplex argument for BigMath.logZero or negative argument for logwrong argument type %li (expected scalar Numeric)a non-integral exponent for a negative base1.3.4%lue%zdinvalid rounding mode: nilinvalid rounding mode: %li failed to allocate memory%snegative precisionExponent overflowComputation results to 'NaN'Exponent underflow+Infinity-Infinityexponent overflow#0Divide by zeroargument must be positiveinvalid rounding mode-0div%zu:sqrt of negative valuesqrt of 'NaN'(Not a Number)#1<=>>=<=precision too large.Fremainderdivided by 0divmodto_i**precision must be an Integer21E%ld0#BigDecimal.exception_modeBigDecimal.rounding_modeBigDecimal.precision_limit.5BigDecimalnewdouble_fig_loadversave_exception_modesave_rounding_modesave_limitVERSIONBASEEXCEPTION_ALLEXCEPTION_NaNEXCEPTION_INFINITYEXCEPTION_UNDERFLOWEXCEPTION_OVERFLOWEXCEPTION_ZERODIVIDEROUND_MODEROUND_UPROUND_DOWNROUND_HALF_UPROUND_HALF_DOWNROUND_CEILINGROUND_FLOORROUND_HALF_EVENSIGN_NaNSIGN_POSITIVE_ZEROSIGN_NEGATIVE_ZEROSIGN_POSITIVE_FINITESIGN_NEGATIVE_FINITESIGN_POSITIVE_INFINITESIGN_NEGATIVE_INFINITENANinitializeinitialize_copyprecsaddsubmulthashto_sto_intto_rsplit+-+@-@/quo%moduloclonedupto_fabssqrtfixroundfracfloorceilpower===eql?<nonzero?coerceinspectexponentsignnan?infinite?truncate_dumpBigMathexploghalf_updefaulthalf_downhalf_evenbankerceilinghalfP1SPR~RPSDSP|RPRVRPSdST\UT$UUTT4U$vtttttututtutttttv | 0 p$ߋߋߋߋߋߋߋߋߋߋߋߋߋߋߋߋߋ ߋߋߋߋߋߋߋߋߋߋߋߋSSSSSSSSSSSSSSSSSSSSSSSSSSSSSNJNJNJNJNJNJNJNJNJNJNJNJNJNJNJNJNJkppNJNJNJNJNJNJNJNJpNJNJNJNJk(;;;;;;;;;;;;;;;;;߆;;;;;;;;߆;;;;߆SXXXS#################̄̄Dž########Dž####̄;@@@; l(#(##\\\\\H\\\\\\\\H?PjP& .>C]r2<?eAC;q `$$p%%%%,'@'T(|p(((P)0**<,P- /p/(/T@001p11,2H`2d22 3304@6709hDPDpDE, PFL 0K K 0L 0MT O 0Q pQL 0R` S Z `_ f4 fH @g| g ph i k0pq|rrs@spss(tLuh@uuv`z({TP}}`~`pЅ`8p<`$`` 0\@Ц@P`(x@$t`xzRx $h@FJ w?:*3$"D0\x!p! !|!x#$#-AAF SDI#\A#+H^$#-EFM IFA@#qT`$<h,%BBB D(A0l (A BBBB d%BHB B(A0A8G`M 8A0A(B BBBA W 8A0A(B BBBE D'SAa N b@0'KAG  AAJ vAAHH t)PAa N _(@)AAG V DAA ()HFAK rAB()nEAD0W AAA $)`Ae J D L _(@4*UBAA } ABD (lh*oEAD0X AAA *!AAK*MDU A *7A[ A +AAK$+YADF ICA(0T+vAX G U K U K U\+]Ut ,.4/CD xAACL aH0 BBB B(D0A8Gp 8D0A(B BBBJ ( T;5BFN [ABLh;HS0dp;7FAD DP  AABA |<A D Vd<BEB E(A0A8D 8A0A(B BBBA  8F0A(B BBBE  tAc84ABAD K JBJ K ABJ Lp$BBEE D(D0M (A BBBH \ (D BBBJ XBOtEA D@ h@{ FABD@xX@`DBBB A(A0 (A BBBB l (A BBBE X (A BBBI 4F7BDD Y DBG ACBFHFmBEE E(D0D8DP  8D0A(B BBBF lGBBB E(D0D8G 8A0A(B BBBC OPBuOPANBGB B(D0H8G 8A0A(F BBBA s 8A0A(B BBBA | 8C0A(B BBBA  8A0A(B BBBD | RBHB B(D0D8G 8A0A(B BBBA  8C0A(B BBBF : 8A0C(B BBBA  DY0 @YFAA D0y  AABG ( Y}FDC x ABH  ZD o E 0 ZzD I LL \EFD f LAF  LAG _ IAG f DAA H ]BBE E(G0C8T 8A0A(B BBBF ( bEAD` AAI  cGMl G F4 d;MmL (d)H]d @d(HZ| XdpT[ dEPP AI  le2El e2Hf( eEMDPn DAE ( ,fEMDPu DAE LD fFGB B(K0A8D 8A0A(B BBBD ( 0jEMDP DAE 0 j<FMA D`{  AABI ( lEMDPs DAE  4mlH D [ ,< mEJ0T DI v GE ll XnBBE D(K0K` 0A(A BBBB h 0G(A BBBJ  0G(A BBBJ  t tts,s@sLTs}FJA A(N` (D ABBH z (L ABBE L uFBD G(DPD (G ABBI i (D ABBN `u@FJA A(N` (A ABBF  (D ABBL | (L ABBK LXwFBD G(DPD (G ABBI i (D ABBN `|x@FJA A(N` (A ABBF  (D ABBL | (L ABBK L XzFBD G(DPD (G ABBI i (D ABBN 0\{NBAA D@J  AABJ 84}FLA D(I@h (A ABBB 0}FMA F0e  AABE L~FBB B(A0K8N 8A0A(B BBBD (PtEMD0I AAG d|؂FGB B(D0A8N 8D0A(B BBBJ q 8A0A(B BBBE $zRx , L BBB E(I0A8N 8A0A(B BBBD (ptEDGPW AAG (EDG`^ AAH X=FGE K(A0D1 0D(A BBBJ  0A(A BBBH zRx ( L\HFNB B(A0A8D 8A0A(B BBBC HuFNB B(D0C8DPJ 8A0A(B BBBI H FNB B(D0A8D 8A0A(B BBBI LDFBD D(H` (D ABBI  (D ABBK LЕFBD D(H` (D ABBI  (D ABBK L FBD D(H` (D ABBI  (D ABBK X4pLFBE D(C0D` 0D(A BBBL  0D(A BBBE Ld FEB B(A0A8J 8A0A(B BBBA H43FBB B(A0A8Du 8A0A(B BBBG L,( FEB B(A0A8J 8A0A(B BBBA L|ذFBB B(A0A8D 8A0A(B BBBF x$H [(G EMD0) AAA GNU(@(*!*(  xp*!x*!o`8   ,!X` ooooBo*!P`p 0@P`p 0@P`p  0 @ P ` p !! !0!@!P!`!p!!!!!!!!!"" "0"@"P"`"p"@@?GA$3a1  GA$3p1113'wGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY(wGA+GLIBCXX_ASSERTIONSbigdecimal.so-2.5.9-115.module_el8.10.0+4212+150d00eb.x86_64.debugſY7zXZִF!t/]?Eh=ڊ2N(^ SĎ0FN>JrѹpL!O}}OMJfk>u1 g;+a/+8 !B7זD2g7L=)crG_=*GGBA{""w.t4 Y;ܣK@pYϒp؃?5JaPJi]x iP/W,!q`C!J.e*}.NPZ>7Wcph!h]B*2|!ƵE !zsă/O af4M}jPqn MJb!qTdTD:T;J07x{J^{`S f< ÃZA?5Q@ 4Xf=qWC';a _>X2FDC.$ԙ F9n@Twc|~OC_y[l {]Y[Y'{ERvl+?r<(?v|`EfCKgǝfHPfsJ9j꾷@Kvw VpoCw۲״d/nˈ{'kI2r9î&0`qʒ yˎzWF oQ^[qe^! 6]Q̏Ꮛl B>p]w~YWIO(}2 .ȦmBz^Z: ^̗א!Uʩx6#V6OF}Fщ/vm#9i3Imׄ b#֏% 8 piP[=}԰^Q}n@_]FOt˽J>@:{>oHi6&o6sJ6i斨(oSN;0E,9̆1mnZ K9_ ]bMreOdTM_K!ەl 8['}p14z8;Ь~`X/ލR~/¤[3mM>``"1ʓ?׶pETYܷъ2ȕqm gek;'HB@?"_ :|2!Wa?UNmF%B+e&ގ'f4Mq1 ]G7Z$s:քX`^i"㌛SL>%D-1u5fD*F y C_i`==#?r;2T>RnNj{8QoƠZjڂ2DO3SҨPC{\.9W\Bx!&C% eC[C PskTHq PvZ2KÎ8AbpġL+,cPKDľݲyjxL3*h9MZ0Y/IW$5Z띎} CY9Zm*o{;69h/ J|hgw'}Ͻ{55j "fMՆv\&1~8ok}n/ [" 7u7G$ܑ^TKy`Zd9 yЫ.b$A1m6$晒Ś$lLrxb 8,5zm2 nI֞ez;v?|,y#|:O)=Z!] RөQ. MR]Ap݈FWkF;aNnf-gLWdufK'Bt؛oaM1Ў Dxď83Ϝ57٭ ' 09뱝 %o`0HZ%)?@wgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``D(  08 8 8oBBEoPT``^BXXh  c@@@n""0w''}xx    p*!p*x*!x**!*h *!*,!,(0!00!08P1a0H `2H2:(PK!<][``ruby/psych-3.0.2/psych.sonuȯELF>,@`z@8 @ee ii i 8 jj j 888$$ddd Stdddd Ptd[[[QtdRtdii i 8PGNUo"}k_Ѻ[_ BL0H _gjx BE"aj |SE6 ZqXH8 \FGU X.AF,W\}O@~fqP!g  1Pdu25I9&K)=[n, F"fc%f @=%p  W `S-q Xq q  -N Xtxq p y`q hq pq __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeyaml_get_versionrb_ary_new_from_values__stack_chk_failInit_psychrb_define_modulemPsychrb_define_singleton_methodInit_psych_parserInit_psych_emitterInit_psych_to_rubyInit_psych_yaml_treerb_check_typeddatayaml_emitter_deleteruby_xfreeyaml_emitter_set_canonicalrb_data_typed_object_zallocyaml_emitter_initializeyaml_emitter_set_unicodeyaml_emitter_set_indentyaml_emitter_emitrb_eRuntimeErrorrb_raiseyaml_alias_event_initializerb_check_typerb_utf8_encodingrb_str_export_to_encrb_string_value_cstryaml_mapping_end_event_initializeyaml_sequence_end_event_initializeyaml_document_end_event_initializeyaml_stream_end_event_initializerb_fix2intrb_num2intyaml_emitter_set_widthyaml_stream_start_event_initializerb_attr_getrb_enc_str_newrb_funcallvyaml_sequence_start_event_initializeyaml_mapping_start_event_initializerb_string_value_ptryaml_scalar_event_initializeyaml_document_start_event_initializerb_ary_entryruby_xcallocrb_string_valuerb_ivar_setyaml_emitter_set_outputrb_error_arityrb_cObjectrb_define_class_undercPsychEmitterrb_define_alloc_funcrb_define_methodrb_intern2cPsychParserrb_const_get_atrb_class_new_instanceyaml_parser_deleterb_funcallv_publicmemcpyrb_utf8_encindexrb_default_internal_encodingrb_iv_getyaml_parser_initializerb_respond_torb_ascii8bit_encindexrb_usascii_encindexrb_enc_find_indexyaml_parser_set_encodingyaml_parser_set_inputrb_cIOrb_obj_is_kind_ofyaml_parser_parserb_protectrb_str_new_cstrrb_enc_associate_indexyaml_event_deleterb_jump_tagrb_str_newrb_ary_newrb_ary_new_from_argsrb_ary_pushrb_enc_get_indexyaml_parser_set_input_stringrb_to_encoding_indexrb_str_new_staticrb_usascii_str_new_cstrePsychSyntaxErrorrb_exc_raiserb_define_constrb_requirerb_const_getrb_path_to_classrb_obj_allocrb_iv_setrb_define_module_undercPsychVisitorsToRubyrb_define_private_methodrb_interncPsychVisitorsYamlTreelibruby.so.2.5libyaml-0.so.2libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.4ui  ii +i 0-i ,i i i kZi .@j "[Pj @Ao  o  o jo (o ho co do ko 9o Ko Po lo Ul l l l l l l l l  l  l  l m m m m  m _(m 0m 8m @m Hm Pm Xm `m hm pm gxm am m m m m  m !m "m #m bm $m %m &m 'm )m *m +n ,n -n .n / n 0(n 10n 28n 3@n 4Hn 5Pn 6Xn 7`n 8hn :pn ;xn <n =n >n ?n @n An Bn Cn Dn En Fn Gn Hn In Jn Ln Mo No Oo Qo R o S(o T0o U8o V@o WHo XPo YXo Z`o [ho \po ]xo ^HHN HtH5K %K hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%}E D%uE D%mE D%eE D%]E D%UE D%ME D%EE D%=E D%5E D%-E D%%E D%E D%E D% E D%E D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%}D D%uD D%mD D%eD D%]D D%UD D%MD D%ED D%=D D%5D D%-D D%%D D%D D%D D% D D%D D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%}C D%uC D%mC D%eC D%]C D%UC D%MC D%EC D%=C D%5C D%-C D%%C D%C D%C D% C D%C D%B DH=yC HrC H9tHB Ht H=IC H5BC H)HHH?HHtHB HtfD=C u+UH=B Ht H=< dB ]wH8dH%(HD$(1HT$ Ht$H|$HcD$Ht$HDHD$HcD$HDHD$HcD$ HDHD$ HL$(dH3 %(uH8~ff.HH=u+HA 1H5f+HHH?z[HBfHH5; HcHHDff.HH5; |HcHHDff.HH5Q; Lx|HHHЃf.SHCH[f.SHH5; 1HH@*H[DUH: SHHX HHH߾iH߾lHH[]fSHt[Hb@ HSH5)H81DATUSHHĀHt$H5E: dH%(HD$x10H|$IHu:1Hl$HHLxHHT$xdH3%(uCH[]A\@N)H|$H,HD$HtH|$H ff.fATH59 USHHpdH%(HD$h1HrHIHLHT$hdH3%(u HpH[]A\ff.ATH5#9 USHHpdH%(HD$h1HHIHL\HT$hdH3%(u HpH[]A\+ff.ATUHH58 SHHpdH%(HD$h11HH@IHHLHT$hdH3%(u HpH[]A\ff.@ATH538 USHHpdH%(HD$h1HHIgHLlHT$hdH3%(u HpH[]A\;ff.USHH57 HHHt'HmHH[]USHH5p7 HgHHtH=HH[];ATUHSHH57 HpdH%(HD$h1H߾IbH߃t:eHHHL=HHT$hdH3%(uHp[]A\ÐfATIUHSHH5< dH%(HD$1HLHHHHH5< H$HǨt"H\$dH3%(uH[]A\@lff.AWAVAUATIUHSLHHt$H$dH%(HD$x1H|$IHtH|$LHD$H<$HtH<$LH$HH5l5 gH߃IE1MAE1H<$t HeI1H|$t H|$NHLd$LADLLLjHHT$xdH3%(u#HĈ[]A\A]A^A_Dsff.@AWAVAUATIUHSLHHt$H54 H$dH%(HD$x1mIH|$IHtH|$LHD$H<$HtH<$L{H$H߃E1MAE1H<$t HI1H|$t H|$HLd$LADLLLHHT$xdH3%(u&HĈ[]A\A]A^A_{pff.@AWAVMAUMATUHSHHT$ H$HL$Ht$(H5$3 dH%(H$1 H|$(IjEH|$(HIEH|$ HD$(Ht;H|$ LHD$ H|$HtH|$LHD$H߃HD$(MAMLAEEA IDD$H|$(1H|$HtH|$HD$PHL$H1H|$ t!H|$ HL$HT$*HL$HT$HL|$0SEAVDD$LEXLZL8HH$dH3%(u.HĨ[]A\A]A^A_Ë@D$N@ff.@AWAVAUATIUSHHH|$0Ht$H5D1 HL$8dH%(H$1'HHD$(H HHIHD$ 1L|$PHD$E1H|$8AH >HD$H@HHٸH\$ Ht$HLHNHH|$(LHtH'H$dH3%(HD$0tH[]A\A]A^A_fHD$H@H5H\$1HH߾HHH{H߃D$H{fD$LI LI0I$ cID$HD$L|$E1LHD$ HMkID$Hl$PMHD$HD$@H$HL9oHD$N4LI INIFHL$@H@H<$HIHD$PHH|$@LGH|$PLHD$@5H<$HD$PHHCHCL;|$I$ ?M9|$ID$ ?f.H@kfD[[fDHHD$I~~(IF HHL$@ I@H59* , H5%* H$11HD$hfH$AHtIT$$IątuH, Dt$ LHD$0HtLHIH$HtNHŋD$$t@uHt$ H,HD$0HtHHGHŃ$Hc$H$0H=HL$8Ht$HHTH$@H$PLH$HDLHH=[L|$|f.H$AHtIt$$IątuHDt$ Lexternal_encodingUTF-16LEUTF-16BEnewParserANYUTF8UTF16LEUTF16BEpsych/syntax_errorSyntaxErrorparsemarkreadpathemptyevent_locationPsych/parserP@p`(8mesgClassLoaderVisitorsVisitorToRubybuild_exceptionpath2classYAMLTreeprivate_iv_get;18 h(@XpH ThXH|(xLHHp(8HThh|x4P( zRx $FJ w?:*3$"D(\H@t A xNHA8%HWP%HWh&HWEL+Ee$NEMD rDA<+AM A 0XFAA G`  AABE 0`eFHA GB  DABA 0eFHA GB  DABA 0qFAK GK  DABA 0($eFHA GB  DABA (\`IEAN c DAD (IEAN c DAD 0FAD Na  AABB 0FDD D0m  AABE LpAFBB B(D0D8J 8A0A(B BBBF HlpAFBB B(D0D8J 8A0A(B BBBI \tFBE E(A0D8G[ENDe 8A0A(B BBBA LFBB B(D0A8J 8A0A(B BBBJ HhD=FBB L(A0F8G@ 8D0A(B BBBJ $8%Et G r V @EK0 AF EL0DXl QH C A dQH C A QH C A ($(EGL@V AAH LPFBB B(D0C8J 8A0A(B BBBE <'Ea<P-EHD # AAJ C AAK @ $<4EGD ^DA(8TFHA DUd4EG fAtEjGNU0-,i kZ."[@A DYi i o`  5 l 0P oooo6oj !! !0!@!P!`!p!!!!!!!!!"" "0"@"P"`"p"""""""""## #0#@#P#`#p#########$$ $0$@$P$`$p$$$$$$$$$%% %0%@%P%`%p%%%%%%%%%&& &0&@&P&`&p&&&&&GA$3a1 QY GA$3p1113@-DYGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1113 .XGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY@-XGA+GLIBCXX_ASSERTIONSpsych.so-2.5.9-115.module_el8.10.0+4212+150d00eb.x86_64.debug%9q7zXZִF!t/]?Eh=ڊ2N WR|$*s64 ,VJv,N'4v.; Nץnf)IL3;Aۥ-0\sjպa)0g2;sL0,w8!.[f-f !?^%qT`|P4rRO@+ԅHu&yh@ v9A*TfZc;~Py!l"z;O *Z ,2wrET8U=aK:9%h:1@5.'c^N"ZѐfzcZ퟇H3  t>(w;˺ւt00!5Ҟ$lMjI!h\&cb* ܬ<.G/לng [ ћFTXrt\x27QV^ݩ~h -.Uy7ULvaM~6!P'b:U~4 > H.(bʟ}M$.~R'aDv" !h 6N*At/Jm/KivcJU'n,*ޜy,~ՁϷn!5D}/L%Qk/%$ނoXQ@ki)Ф>8/x^rpjBbsL`G5tTfAZ2fsI]~K>@b;=PNj}f5=M5S?^LuKVG\aCpxUB\ԣO 'EwgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``d( 8 0 58o66Eo@TPP^B00h c n&&w,,,}DYDY TYTYd[[P]P]dd i ii ii i j jl l`p oq`otDHt`@8H@8 @88 ;; ; h ;; ; 888$$777 Std777 Ptd(1(1(1QtdRtd;; ;  GNUמńDAh)sMW?H!@?ACBE|qX/DofJ,o 2u$^7 a}U LvZ{>r%-BY, F"k@ H@ @  -Tp /__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_funcallvrb_default_rsrb_io_writerb_cIOrb_cFilerb_const_definedrb_cloexec_openrb_update_max_fdrb_class_new_instancerb_io_taint_checkrb_io_check_closedrb_str_new_staticrb_obj_freezerb_const_setrb_const_getrb_const_removerb_id2symrb_check_typerb_io_closerb_check_idrb_error_arity__stack_chk_fail__errno_locationtcsetattrtcgetattrrb_sys_failtcflushcfmakerawrb_string_value_cstrrb_check_safe_objrb_intern2rb_io_get_write_iorb_ensurerb_stdinrb_stderrrb_check_hash_typerb_extract_keywordsrb_hash_arefrb_fix2intrb_funcallv_publicrb_num2intioctlrb_assoc_newrb_Arrayrb_num2uintrb_eArgErrorrb_raiserb_protectrb_syserr_failrb_jump_tagrb_io_getsrb_yieldInitVM_consolerb_define_methodrb_f_notimplementrb_define_singleton_methodrb_define_module_underInit_consolerb_internlibruby.so.2.5libc.so.6_edata__bss_start_endGLIBC_2.4GLIBC_2.2.5ii ui ; ; ; ; ? ?  ? ? ? !? #? +? 1? 7? 8? 9? :? >> > > >  > (> 0> 8>  @>  H>  P>  X> `> h> p> x> > > > > > > > > > > > >  > "> $> %> &? '? (? )? * ? ,(? -0? .8? /@? 0H? 2P? 3X? B`? 4h? 5p? 6x? :? ;? <? =HH+ HtH5) %) hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2%& D%& D%& D%& D%& D%& D%& D%& D%& D%}& D%u& D%m& D%e& D%]& D%U& D%M& D%E& D%=& D%5& D%-& D%%& D%& D%& D% & D%& D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%}% D%u% D%m% D%e% D%]% D%U% D%M% D%E% D%=% D%5% DH=% H% H9tH&% Ht H=i% H5b% H)HHH?HHtH% HtfD=%% u+UH= % Ht H= )d$ ]wH"O {H g HH5$ H׉vfDH5$ 11\ff.H$ H0ff.fAWAVAUAATUSH8dH%(HD$(1<IHoE1H# H9u H# HH5/$ HM1ҾH=KHcHl-HHt$Hl$HD$THHLxLH=lHAO HHIGH5# MHL$(dH3 %(HLH8[]A\A]A^A_f.H5A# HHŨuHubH5## HMH=# AI9nfDL&L uHEHtxtM.H=" RI9u-Au'HH5{" HfDIH|$HD$NHt)AIHLDHHH! փ1}USHH K8u&HھwuH[]H1[]SHPdH%(HD$H1rHXHv{H u)D$ HHHЃHT$HdH3%(u HP[1G2fAUIATUHSHXdH%(HD$H1IHXH[LuPD$ Iu:D$ Lt.HT$HdH3%(Hu"HX[]A\A]xD$ 1ff.ATUHSHPdH%(HD$H1IIHXHM[Lu@LH"L$ {H $,tHT$HdH3%(HuHP[]A\1UHSHHXH{1u HH[]1UHSHH c HtExCExCH[]SHdH%(HD$1HHt$HHH$cH<$H4$HnHD$dH3%(uH[H5 SHHtH11[H=H11H[H AUATAUSHHIHHH9tHAu HLHHHH=K Ht0HH[]A\A]>fDH H9uH H(H[]A\A]ú1@AUIATIUSHHXdH%(HD$H11uDHC0oLoKoS HD$0C8H)$H)L$)T$ D$8AHމHT$HdH3%(u HX[]A\A]zf.AUATUSHdH%(HD$1H$~`HcH|Hu2u?D1HL$dH3 %(FH[]A\A]H0H$Hu11kt@ILH<$IHHyH= mLHH= HSLHHEI1HtH߃tMEHILL*H$;HǨt$OEH@fڅ HuAL$$ff.@AUATUHSHhdH%(HD$X1HT$%HIzHXH~DcH\$HD u8LHHD`tHL$XdH3 %(HuHh[]A\A]17"fUHSHHXHH{PHtHXH{u HH[]1fDUHSHHXHH{PHtHXH{H5 $Hx HH[]1nff.SHdH%(HD$1"HXH&H{PHtHXH {1HTzu.t$<$Ht6H|?HL$dH3 %(u H[1ff.ATUHSHXHH{PDcHuDuJH[]A\fDSHXHW[tA9t1Dupt15DUSHwVHuHHHH5 11HHHt HHH` HH0HH[]ú1/ff.@AWAVAUATIUHSHdH%(HD$1cHXHgL/H HHLxLpAAH{PHtHXH[1H$ItLf$1ItLfD$1ItLfD$1ItLfD$H1T%unHL$dH3 %(HuVH[]A\A]A^A_HPHtBHuH@ L8LpLhL`"H  H5H8131yG819yv#θ!84y v”Ǖ%&\v DWHt"W1v@Љ@8 @nn P{P{ P{  {{ { 888$$`n`n`n Std`n`n`n Ptd8a8a8aQtdRtdP{P{ P{ GNUPQ8=b'XC@$CEFBE|qXt)ee b/aZrUB C4WO'{:K, nF"'ms    N __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_funcallv__stack_chk_failrb_check_typeddataruby_xfreeruby_xmallocruby_xrealloc2ruby_xmalloc2memcpyrb_str_newrb_utf8_encodingrb_enc_associaterb_check_typerb_str_new_staticrb_hash_arefrb_hash_newrb_obj_classrb_class_namerb_hash_asetrb_str_duprb_str_catrb_str_concatrb_str_internrb_sym2idrb_ivar_setrb_ivar_getrb_ary_entryrb_string_value_cstrrb_iv_getrb_str_substrrb_id2symrb_intern2rb_check_convert_typerb_convert_typerb_error_arityrb_data_typed_object_zallocrb_string_value_ptrrb_path2classrb_raiserb_eArgErrorrb_float_valuerb_cHashrb_cArrayrb_cStringrb_cFalseClassrb_cIntegerrb_cNilClassrb_cFloatrb_respond_torb_cTrueClassrb_cSymbolrb_obj_is_kind_ofrb_const_getInit_generatorrb_requirerb_define_modulerb_define_module_underrb_cObjectrb_define_class_underrb_define_alloc_funcrb_define_singleton_methodrb_define_methodrb_define_aliasrb_cRegexplibruby.so.2.5libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.4ui ii 'P{ `X{  `{ `{ { ^{ { Ph p x        $ & - . 7 8 9 ; B} } } } } }  ~  ~  ~ ~  ~ (~ 0~ 8~ @~ H~ P~ X~ `~ h~ p~ x~ ~ ~ ~  ~ !~ "~ #~ %~ '~ (~ )~ *~ +~ ,~ /~ 0~ 1 2 3 4 5  6( :0 ;8 <@ =H >P ?X @` AHHqj HtH5zh %{h hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2%Ee D%=e D%5e D%-e D%%e D%e D%e D% e D%e D%d D%d D%d D%d D%d D%d D%d D%d D%d D%d D%d D%d D%d D%d D%d D%d D%}d D%ud D%md D%ed D%]d D%Ud D%Md D%Ed D%=d D%5d D%-d D%%d D%d D%d D% d D%d D%c D%c D%c D%c D%c D%c D%c D%c D%c D%c DH=Id HBd H9tHc Ht H=d H5d H)HHH?HHtHc HtfD=c u+UH=c Ht H=_ dc ]wH7Hthv$HtNHu8R1€?v2fHuBc dH%(HD$1Hc HH$vHT$dH3%(uHff.HH51] HHHDff.HH5] H@xHHDff.HH5\ xqHHHЃf.HH5\ xpHHHЃf.HH5q\ \HxhHHHЃfHH5A\ ,H@hHHDff.SHHHtH[DSHH?HtH{HtH{ HtH{0HtH{@HtH{PHtH{XHtwH{`HtiH[`SHHHDؿ f@H@H[ÐATIUHSHtWHOIT$HH)H9v:HHHH)H9rH9vI|$H{I\$ID$[]A\@H?{I $ID$IL$ff.Ht3UHSHHHBHHHH[]D1HfUSHHHwHHH?zHHHH[]DUSHH50Z HH߾HHtH~HH[]ff.USHH5Y HH߾HH$H]xH[]@USHH5Y HH߾HHHHEhH[]fDATUHH5_Y SIHIHuH% u;HI|$@HHu5HtID$@[]A\f.H]I|$@HtHtHE% H}HtH}H I\$HID$@[]A\fDATUHH5X SHIHuH% u;HI|$0HHu5Ht=ID$0[]A\f.H]I|$0HtHtHE% H}HtH}HJI\$8ID$0[]A\fDATUHH5W SHI)HuH% u;HI|$ HHu5Ht}ID$ ID$([]A\ÐH]I|$ HtHtHHE% H}HtH}HI\$(ID$ []A\fDATUHH5W S HIiHuH% u;HI|$HHu5HtID$ID$[]A\ÐH]I|$HtHtHE% H}HtH}HI\$ID$[]A\fDATUHH5_V SIHIHuH% u;HI<$HHu5HtI$ID$[]A\H]I<$HtHtHE% H}HtH}H I\$I$[]A\SHHHdH%(HD$1H=7HHH=_5HHHH5 [ H$LHT$dH3%(uH[ATUHSHdH%(HD$1HH!HyH5Z 11H=G[ ILHHH=4@HHH5^Z H$H=6HHHHHT$dH3%(u HH[]A\fAV1I1AUATUSHHH H5LZ dH%(HD$1I$HHH56HLHH5{Y IH$Hu_H=3NHHHHLHHHL$dH3 %(u2H []A\A]A^LHL,$H5X Lt$`fAT11USHHHH5CY dH%(HD$1ILHH5X HH$Ht5LHH,$H5oX HT$dH3%(uCH[]A\ÐH=2/HHHHHHyfAWAVAUIATUSH(dH%(HD$1fH5?R LH$H5V HH11LE1"IHD$H$HI9L= X LL>11LHHHD$ &HH<$HT$ILHHT$H|$IH?HwLHHI$ \ID$I9^HsH;H=CW ILHHeHsH{H=W IYLHH;Hs(H{ ~H=V I/LHHHs8H{0TH=V ILHHHsHH{@*H={V ILHH{pH=JV MIHAHL{qH=V MIHAHLmLchH=V mOd$HLHJLcxH=U JOd$HLH'HH=YU $H\HHHHHL$dH3 %(uFH([]A\A]A^A_HPH=/gHHS GAVAUIATIH5IO USHdH%(HD$1H ?/LH8/HHHH=U GHHIHH=T !HHvIH7H=T HHPIHH=rT HH*IHkH=TT HHIHH=T ILHHEhdH5S IH$ HH=S HLHHExH5S IH$H&H=?S LHH5PS IH$HH=aS HH)H=BS HEpHHHLEqHT$dH3%(H[]A\A]A^f.HsM4$A bMt$I|$Iv/LuHEfLHIH6HIMLLHEIH&HExfLHIHHEhEfHM4$A bMt$I|$IvOLu8HE0fHSM4$A Mt$I|$IvLuHHE@WfHM4$A Mt$I|$IvLu(HE fHM4$A tNMt$I|$IvLuHEfDH ^+HR+LeHDII|$AIvDII|$AIvVf.II|$AIvf.II|$AIvf.II|$AIvf.HILuhcHILuxfATIH50J UHSHH@hdHǀwuI4$HtHH[]A\ú1ff.@HI ff.ATIHUHSHKH{HH{LHk[]A\ff.@ATH5gI USPHHHkXIH)HEHHEHU,HEHk`HHEHs Ht HS(HHHEHU:HsHEHt HSHuhHkPHtqHEHRHEHU,Hs@HEHt HSHHuL[]A\H{PL[]A\H{`HkPHuHHCPHxHk`/HHCXfvHHC`f.H(f  Nf Nуf NFDISH+H dH%(HD$1HIH?LII1I)fLLLIIHHHI)BIAAHuHyHAA-LILL9v#f0HH@qPH9wM)uHD$dH3%(uH [LL VfDUHSH(Ht$H\$HdH%(HD$1HL$H u0HH\$HL$Hu-HD$dH3%(u*H([]HQH\$HL$HtHHzUHSHHH>HHu H[]DHuHHD$7HD$H[]ff.1H=&RfHH5E Hx@HtHpHH&fDHf.HH5qE \Hx0HtHp8HfDHwHH51E Hx HtHp(HfDH7HH5D HxHtHpHffDHHH5D H8HtHpH'HAWAVAUATIUHSHHHdH%(HD$81HCHSLH5J HL$("HJ HCHD$()}H(HD$ LxHh\uLD$4ft$2L9AH j(IfALH9L5'Ld$2L-'DDLApHcuAEKcL>DH( L`Hh\uE1L-d#E1D$4fL$2HK<<<P5H5'HcH>AL5!#LL)LLHMOML9wLL)tK4 HHHCHCHS"HCHD$8dH3%(HH[]A\A]A^A_LAL5"L)kK4 HLD$wLD$IDAL5F"&fDAL54"fDAL5""fD00ALt$2fT$4fЃfADATD$7T$6@HL`71AIHHHAIHHAIHHHAIHHAIHIcH %H+HH(H=3HBH_H"H\aH5!HDL9oAH T%IfALH9H= >H5#H1D11 f1f1 fAIHHLx%<"tt<\tXH $f4II9Mf.H= tH5M#H1AL5fDAL5fDHHT$HCHsHT$HCL9HD$HD$ HD$@H5yHtWHBHIcDL>H5*H4H5HH5HH5HH5HHwJHLHHHD$H f(IHD$ff$LH*=H=NH5!H11ff.ATIUSH9$HH5= HH5= HHHoEoHMoP U oX0]0o`@e@ohPmPop`u`oxp}pHHHsH;nHsH{HE]Hs(H{ HELHs8H{0HE ;H{@HsHHE0*H{PHE@HtHwHHEPH{XHtHwHHEXH{`HtHwH|HE`L[]A\H@ H5H81ATIUHHSHHE$$11H5gB HD$IEu"D$f(fT !f. !wf.zBHHH[]A\OHHD$HD$H=&B ^H5WH1HHD$HD$H=A aH5(H1SHHH5A 11H[Hff.fAUIATIUHSHHdH%(HD$1؃:H` gHCH? H9H,? H9H> H9vHHHHH HLE@HdHtuHUH> HJDHHLLGHD$dH3%(H[]A\A]Ha> HHLHrH > HH= H9@H5? Ht=HHL,$H5? HHHLKfH5? H11HHHuqHLfHHLLf.H5LlH5LLH< HH5yLH< HH = HHupHL!E'AWAVAUIHATUHSHXHB@LzHT$HD$8HBHHt$ HD$@HHRhHD$HAPHxH@H|$HHyxHD$HwH|$0Ht$(HqxHt H9HHEHU[HEH|$8t H|$@}D$01D`QDHH9}RH|$tH|$HLHHT$Ht$ HHIE uIEH9|HD$HT$0H|$8HPxtOH|$@Ll$Mt9HD$0H~/A1 DA9tMtLLHRA9uHHEHU]HEHX[]A\A]A^A_H|$(,E1AE9MtHt$LH@HT$Ht$HHHT$@Ht$8HLl$M#WHT$@Ht$8HlHHD$H=a< H5HPxHT$HHPx1:f.AWAVIAUATUHSHhHB0MnxHL$8HZHD$ HB8Ht$HD$@HHRhH$IFXHHH@HD$0IF`HL$XHHH@HD$(IEHL$PHD$HIFxHt H9qHE1AHUHE1H5: H|$8{1HELLt$IHI9H|$0t EH|$ t H|$@H<$0LL=H5: 11HIHHD$HD$HT$HHt$H+H|$(H|$8LI.HT$Ht$HHI 5IGI98Lt$H|$ MnxMeMfxtLH|$@L4$Mt7M~2AE1 @AE9tHtHLHA@E9uHHEHU}HEHh[]A\A]A^A_fDH|$HE1AE9HtH4$HHDHT$(Ht$PHHT$@Ht$ HVfHT$0Ht$XH~"HT$@Ht$ HgL4$MIFxH=-9 H5HP1IVxff.@ATIUSHQHH52 HHLHH.[H]A\fUSHHHH5t2 H\HH[]fUHSHHHHdH%(HD$15Ht HT$dH3%(HH[]fH6 HH0Hu)H="8 Ht1fATIUHS{HHHL[]A\Jf.ATIH53 1UH1S`w9HýuI,$H߾H=3 HH[]HA\B1@SH= HdH%(HD$1+H=i OH5 HH.3 YH5 HJH= H3 GH=o H2 4H=2 H5H2 HX0 H@H5HH2 H=2 HH5" H=2 HH5 H=e2 H)H5 H=F2 1HH5 H=*2 HNH5 H= 2 1HH5 fH=1 HSH5 GH=1 1H'H5 +H=1 HXH5 H=1 1HH5t H=y1 H]H5_ H=Z1 1H1H5N H=>1 HbH58 H=1 1HfH5& zH=1 HH5 [H=0 1HH5 ?H=0 1HH5 #H=0 1HcH5 H=0 1HH5 H=t0 HH5 H=U0 1HH5 H=90 HH5 H=0 HNH5 rH=/ H H5 HH=/ 1HH5 HbH5 HSH=. H5 HH5 H%H=. H5~ HH5X HH=x. H5X HHH5* HH=J. H50 H:H5 HH. H= . HH5 uH=- HH5 VH=- 1HVH5 :H=- H5 HH5 HH- H=- H5 HvH58 HH=X- H5 HH5 HH=*- H5g fH5H3H{H5, HH* H8H+ H<H, H+ HHv, H+ HHW, H+ HH8, Hq+ H`H, HR+ H)H+ H3+ HH+ H+ HH+ H* HH+ H* HMH~+ H* HH_+ H* HH+ Hy* HH* HZ* HqH+ H;* H:H* H* HH* H) HH* H) HH=) H* `H) H0Hi* H) HH=q) HB* HU) HH* H6) H]H=H) H) H$HH=cHHHBH=( H* H( HH~* H( HtZH* H* HD$dH3%(H[fD H=aHH) H=H( fDH=_H( VH=v?H' &H=HHH' H=H' H=H' OH=H'  H=Hp' H=~HX' H=u_H@' H=9?H(' NH=H'  H=H& H=H& H=H& rH=xH& ;H=KH&  H=6_H&  H= ?Hh&  H=HP& _H=xH8& ( H=CH &  H=H& H=H% H=H% LH=(_H% H=}?H% H=H% 辽HHC*@instance_variablesto_hashHashto_h0123456789abcdef\n\r\t\f\b\\\"JSON::GeneratorErrorunallocated JSON::State%u: %li not allowed in JSONnullfalsetruenesting of %ld is too deepjson/commonExtGeneratorJSON::NestingErrorfrom_stateinitializeinitialize_copyindentindent=spacespace=space_beforespace_before=object_nlobject_nl=array_nlarray_nl=max_nestingmax_nesting=check_circular?allow_nan?ascii_only?depthdepth=buffer_initial_lengthbuffer_initial_length=configuremerge[][]=generateGeneratorMethodsObjectto_jsonArrayIntegerFloatStringincludedto_json_rawto_json_raw_objectExtendjson_createTrueClassFalseClassNilClassMULTILINEto_snewallow_nanascii_onlyunpackcreate_idextendkey?__send__respond_to?matchkeysduputf-8findEncodingencodingencodeSAFE_STATE_PROTOTYPEJSON/Generator/Statepartial character in source, but hit endsource sequence is illegal/malformed utf-8source sequence is illegal/malformed utf8X801234567890    ;B8H`8x8hȽ4(LHhȾȿ$XLtX D|( Px@Th( xThH xX  Hd x  4 8T t  , h H zRx $ȱ@FJ w?:*3$"D0\pTH F A D%HW\"HTt&HW&HW'HX"HT0ԺAULغEvhFDO WAAF$Ļ;AAG lDA$ܻDEAN hFA$0<EAN `FA$X:EAN cAA44FAK K FBK FAB4FAK K FBK FAB4DFAK T FBB FAB4(̽FAK T FBB FAB4`TFAK R FBD DAB ܾEO t AA 0HFAD D0  DABA @FIB A(A0JP 0A(A BBBD 04FEA J0t  AABB HhL FBB E(A0A8D` 8A0A(B BBBH @FBE K(A0D@ 0A(A BBBK (aFKF x ABA $0(8<1BGD `AB8dPBHA  ABH M ABH K KK0 AD (ADD@Y AAD 0EADG0T AAF ZAA8L6H] K Dl89H] K DX9H] K Dx9H] K D9H\ L DLBBB B(D0I8G 8A0A(B BBBH ,<XFDA 1 ABA 0lHBDG G0N  GABE #AZ8BED D(G@+ (A ABBI LvBBB H(A0D8D 8A0A(B BBBA LH!BBE B(A0D8D# 8A0A(B BBBG (>BDA lDB$.EAG [DA(EDM0u AAC  iES E 8 iES E X ,iES E ,x |pFAA Q DBE , pFAA Q DBE 4 EAD R DAO R DAE 8 d~FBA A(D0V (D ABBE 8L ~FBA A(D0V (D ABBE ( 6FDF \CB( lFMH x AEE D EK  AG GNU` `{ ^P  d[P{ X{ o`@  1 } P@ oooor o{ P`p 0@P`p 0@P`p 0@P`pGA$3a1q[ GA$3p1113pb[GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYpJGA+GLIBCXX_ASSERTIONSgenerator.so-2.5.9-115.module_el8.10.0+4212+150d00eb.x86_64.debug+7zXZִF!t/]?Eh=ڊ2N% TC (;'5+^#\zÑ5CtLDWKoh: np_[7'eԦ# ;i"\"ϕ\3(xWc[m!pQh-ˤF <(ivYs/8}͔#EOW VQEG~v{j X;܂,Tom?g` L,̇p%F8ic [ȸe _cT? S+&%s84.ox-)[̉SH]98(jKT]Ŧ{fbF<2g4+Uv^5Sy(SeG2Dwlu @z,Ibyd4Y\1 $#󕟒OaR>> FEj9]ITg2 )6h~eBg]3z; (!6ՐMXe"Y.MY S)g5솜 &I!'50ZJKګS^^)~M;QiTнuFpr ?RC,lfn =Ny'3iFrNXA.q)ƮDٲN03JXjhу ft*;R ¸H_Vd@}օW(𹐠7zN٧vԢ@Ysrl[ Ŋ31=JW#gGNCV6-_󁫜W佢8c#S鮟0Yc-pXp>9یձsc,ƍdOM.> Jss΄\0e|˾hI"{p,1 @}" `#AvnQ'rz[ĉ~:=l9v*?e ?AAn{LR^(kB t#š< qOOZ+z{8е P| ÏLg[2R^遢|sVet^6g|xXhK|"d6/ |0Ⱦx$n)t5%J!ZCwF!-9߅7 0bl ԗחBnF~/[܁M\ w2MZ1Җ˽C!7%9c* *Cg+uĭ9`B= 5Q/P8VQg5 oZxs2V`uz..Qզ;ϧ /9eH49A5`rrX.xDff؉9a^(#kI 1>.8gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 0@ @ 18or r Eo@T@@^BPPhc@@@n0w?}d[d[ [[ 8a8aXcXc `n`n P{ P{X{ X{`{ `{h { {} }0 `H0Hx4"PK!<]5>Jnn"ruby/json-2.1.0/json/ext/parser.sonuȯELF>@g@8 @pTpT [[ [ X \\ \ 888$$PTPTPT StdPTPTPT Ptd Q Q QQtdRtd[[ [ XpGNUcÚ0Ak8ͅ<;@ ;>BE|ŷ|!qX$ l,U\wqI[N q;5XiC`, F"2v|` a  >` __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeruby_xfreerb_gc_mark_mayberb_str_buf_newrb_str_resizerb_ary_new_caparb_ary_pushrb_hash_foreachrb_ary_entryrb_funcallvrb_str_catrb_str_internrb_utf8_encodingrb_enc_associate__stack_chk_failrb_enc_raiseruby_xrealloc2ruby_xmalloc2rb_check_typeddatarb_string_valuerb_enc_getrb_ascii8bit_encodingrb_str_conv_encrb_str_duprb_check_hash_typerb_extract_keywordsrb_id2symrb_hash_arefrb_error_arityrb_eArgErrorrb_raiserb_check_typerb_fix2intrb_eTypeErrorrb_data_typed_object_zallocruby_xmallocrb_class_new_instancerb_ary_newrb_hash_newrb_cstr2inumrb_str_new_cstrmemcpyrb_hash_asetrb_cstr_to_dblrb_float_newInit_parserrb_requirerb_define_modulerb_define_module_underrb_cObjectrb_define_class_underrb_path2classrb_define_alloc_funcrb_define_methodrb_const_getrb_intern2libruby.so.2.5libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.4ui ii [ [ p[ [ [ F[ [ @[  _ _ _ _ _ 2_ 3_ 4^ ^  ^ (^ 0^ 8^  @^  H^  P^  X^  `^ h^ p^ x^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^  ^ !^ "_ #_ $_ %_ & _ '(_ (0_ )8_ *@_ +H_ ,P_ -X_ .`_ /h_ 0p_ 1x_ 4_ 5_ 6_ 7_ 8_ 9_ :HHqL HtH5J %J hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3%EG D%=G D%5G D%-G D%%G D%G D%G D% G D%G D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%}F D%uF D%mF D%eF D%]F D%UF D%MF D%EF D%=F D%5F D%-F D%%F D%F D%F D% F D%F D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E DH=E HE H9tHE Ht H=E H5E H)HHH?HHtHuE HtfD=E u+UH=ZE Ht H=A d]E ]wH V5Hx=WHx0HH WHxHH WHxHH øf.HG`H@Hhff.@USHHHo`H}HtAH9HH[]+ff.SHH?H{ H{8H{@H{HH{X[fAWIAVAUIATUSH1H8H$dH%(HD$(1H$IEL{I9A?"1KPufI}S4t C0H7 Hw8IOHDH\$(dH3%(H8[]A\A]A^A_DLcXItiIuIHH5 LLL;HIIUH5\D HHL$HT$HIEH7@HMMfL9AF<"t4<\uMfL9AF MHC$HH1vfDATIUHSHtWHOIT$HH)H9v:HHHH)H9rH9vI|$H;I\$ID$[]A\@H?I $ID$IL$ff.AVIH58 AUIATAHUSH dH%(HD$1xH8HD$HA3IH$HC(dH5= 11CPH== UHC8HC HC@HCHILHHII9-HIHLHHLH,$H$H uiHHSHPHLHSHL$dH3 %(H []A\A]A^IcI|HubAA(HPHSHPf@u HHH]HHB<DHD$HH|$H|$HAHHD$AIH$HSH=; Ld$LHH5; IHD$H"C(dH=; LHH5M; IHD$`HC,H=F; qLHH5; IHD$"H^C4H= ; 3LHH5: IHD$HCPH=: LHH5: IHD$HzLHHC H=|: LHH5M: IHD$`HLHC8H=5: pLHH5: IHD$!HHC@H=9 1LHH59 IHD$HHCHH=9 LHH59 IHD$HOHCXQf.HEƒ!#HHDHl$DDHD$Au@H599 H=z9 11 HC uLHE1H‰SPS4 HH7 H5H81}DLHHC4fLHHC,$LHIHu~C(fDLHHHDHCXDLHeHC@@LHMHC8@LH5HCHHǾLC(4HX6 H5H81gfHH5A2 \H8Ht HKH6 H5hH81#AUATUSHdH%(HD$1H4t&IH5]7 HI11LHu#1HL$dH3 %(uIH[]A\A]@1LHHH56 H$HtLLUHT1 hSH% Hh Hf@H@HHE`HH[]ff.@AWAVAUATUSHXdH%(HD$H1H9tMHIHIHj AHDHH9uE1H|$HdH3<%(LHX[]A\A]A^A_Ã0 wHCH9{ H5H]AO,H5 Lc I널HCH9s{niHCH9\{fRHCH9E{i;HCH9.{n$HCH9{i HCH9{tHCH9{yAW, H4 LcIHCH9{aHCH9{NAG,H4 LcIvA@IW@lj$AG(9H=v4 H511HCH9#E1{aHCH9 {lHCH9{sHCH9{eILcHCH9E1{rHCH9{uHCH9{ewILcg@AG(E`IW8HD$ A9B:H=c3 DH51fLHHLIHLDHCH9K*tR/t8 HH9ufHHXH9@<*t0@ HD$(HD$HD$0HD$D$HL$HLHD$(L|IHNI@Ht$(I>5Ht$0HL$H5G0 IEHPH9t%H,tAr t lHHPH9uI G LLbL9JA/]HILD fD Ht$0HL$0H5P/ L$HtyH5Z/ H=/ Ld$0LL$HD$0`H5/ 11HHJL$Ht.IH5\/ LHHD$0L$IIMLD# Iz@HPH9{@<*tC0 T@HL$EHLHD$(dH+I8Ht$ HD$HT$(I>Ht$0HL$H5=* HT$8nLD$I@L@L9P,t?Q t ULL@L9uf.< t <LIL9B< t~<" tHH9uHH9<*t*u GH/ } U, IMo`LH)IEH$xL0IEIUIG`IEIHHx0'IHHL$0H5( HD$0XIILI_H9{fID$H9tAT$+t-uID$H9tAT$0 :HH9E!e.0 vf /HAH9Q*tJ/t8 pHH9uHH9*t/DHH98*u@HL`L9@0< @HL`L9@L$VL@L9X@<*tH0@ wpE1HHHHHHD t w3HHXH9P t/uHXH9t@<*tLH H=H H=Hp  H=HX H H=wH@ H=cWH(  H=57HH  H=HH IHH "\ already initialized instanceuninitialized instancenesting of %d is too deep%u: unexpected token at '%s'-Infinityjson/commonJSONExtJSON::ParserErrorJSON::NestingErrorinitializeparsesourceNaNMinusInfinityjson_creatable?json_createcreate_idcreate_additionschrmax_nestingallow_nansymbolize_namesobject_classarray_classdecimal_classmatchmatch_stringkey?deep_const_get[]=[]<<newJSON/Parser%u: incomplete unicode character escape sequence at '%s'%u: incomplete surrogate pair at '%s'options :symbolize_names and :create_additions cannot be used in conjunctionP`PpnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnLLNLLLLLLL ```````````````````````````````````````````````````````````````````````````````````````````````````  ;P `0LP (@dpzRx $PFJ w?:*3$"D@\Vp$5EAG ^DA(>EtHLBEB E(A0A8Ip 8A0A(B BBBF ,BDD V ABE @D@>FLE G(A0DP 0A(A BBBH <=HX E 8`FBA A(I@R (A ABBE $QEMD uDAH BBB B(A0A8D 8A0A(B BBBA (TVEHD0p AAA H I C E GNUp[ F@  H D[ [ o`  ] h P oo ooT o\  0@P`p 0@P`p 0@P`pGA$3a1HD GA$3p1113DGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONSparser.so-2.5.9-115.module_el8.10.0+4212+150d00eb.x86_64.debug}7zXZִF!t/]?Eh=ڊ2NsAh6o[>o[5;>PG @/k5iXpkcX?Tr3[JFJYs??>Mf~)$/+SkRx`lz3Â'/9>l-54P!Wݧ:F[ib8w v/,m.zvAy \ˢ >cO8O+ޏd ί뗂_X:& 'VFڹh'jJ(қV8zZpdJ/Wt\4ta~wW!r;ql 6ƮĐ7@BosAOO?ɝ:+dԕ*B;1TppČyX} e6֍I:[+WCʤv~ɡ]d[ Έ2 P:a>vyv߄7BFudOO;7*=`Rv{JgOPOP#0_ ›^q2PC:9,ݝvdLz JQd}[UnULMDcE}S:?3; 76z'İbGVT gh`1~Ey\/ES ܪOF`@ XaYswXDZk!#2O "Z6Ʊ/b' %BAH0*A/ wG4Fl  ZJz)ʞۚ0ngo;+ Xa}lQA܉Gd! F0"HZ+OڶNҰόsn~_Cwܴo'ΌC6IJ~HqWp2){Z֍g5Ak,i|rYo =N'GFXM$`܂j`ܐn:(gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 08oT T ~Eo @T  P^BhhhHHcppPn@w*}DD DD@  Q QQQPTPT [ [[ [[ [h \ \] ]` _a`_H0bDtbdf"PK!<] PPruby/openssl-2.1.2/openssl.sonuȯELF>@P@8 @`w`w ||%|%X3< %%888$$@w@w@w Std@w@w@w Ptd@@@QtdRtd||%|%X3p3GNU'VO@U^2 0"$@@ (Q0Au  @ `BbH  P) #  @ @ !@D@@ H!D$` P"J$)@N)"DBX0!B @@@F@ H@  R`@@P @  !#$&'*,-/0467:>@ADIKOPQTUEKlIqη)BгZʮ9X{)tNsѦ+Jagg-(7WNiƵ/Q\1b8чɌAZ)&DtdQpKGV67߂טm3lјS6‡NqK ߝ+&)"5vw"`Pbyl I!IeRUFԿ1>텄 z^vvD!P=y2v*b^Gu$.Sqey]+n ժm !p I` qXoش7ͿHx)19ѭdj,;e-&ojbpIT g:ѫ<\#I P@|U s DcCE? |0Xv$.fS@|Y6.D[H .ZJn(40Jʻ|)*%T6- Iܛ{И$9\ hE c)A -I>/( ;072^< Bk00WDH=1 9x50&eG8 H"I2O6En%7@+%;= 03  p<.#y's+(Gc$Il+'C P.0F;+((q!#C(/V((u  8-88  ;s!L )D#5"FiA!),2BL?O)6-).+7n# kMAG 5>!$44?)75s44 p *IHC>/ Q3W C {CD@~6#*AwGM@ '"13*3*=`-5!@3P!2-9 MB<C/&  }n8H <04B1H8@% U1h2  [I&-S&.  G2+  ;G+< N$mB)/Vg9,iNNE0#$<F%*L:-=-6A#$Y ;E,k7\.E> +t , 98'W$5H556,;AD*, DM9%?q)N5?5;: '' BDF"'7J,.<m-:.99L4d6'a2! !%3&CT @6..%HV D #X0/ Q/+A3 C)g  u,q4T;  +Hf* )6;a$[C:&d&(%H  o$(|B 6C#@4  ,0Hx.6H>;} 8#5<g<0E/< #HB}4pa! G $v/(^D>L#@=eD0)>: ,Y U8`7@* B? 8* 7**AFTH-F>,Dx)/<#, x u =Tk5!'ED).I5`4 U<3 B<2=<-h,jCh  +r25a 0>c?aBg: +(@&*E7l!h 7X5ESBDI~G3?k 2=jF@+3-DV  &0X% `!K$&GD5DF/,?:F, 8%"A<'I(, YF$4B.$G4+kH _<0((C;-yD%4'21.s=,7=?x2%d3A ('S/4f6e6|&EF4(=e.t$I%H  "D!"6 '-? > 3=1b4mExAFD@?)/)B.)!!7H6;84G8E# > E8@T*>j/:3=8<E8F0]=Bc@K.;'*"1r(7  (  lCV5b;0?>&2>4V]3q>v!'$A*`(,iH)`)y<SD7 EMG2:4'&?9 #?W+C8 fO5v"I?$D%0#M  .)7?(%^ N 2 Ih%+" pW8 0v >(%%A `67%V z %" @ *% i@H%k D%P%k$%P" "L %S о:% \{7" @- pdw%9 P`+$ "_t@@%Bh%%*%% I8%%/%# p> <F  m_E%C iB`% 60%  ,6; `K:p%Aж%d'ȷ%]"x%3 @d$%  =j pi %c%  X%p1 {YAX%6 Z'%1%H m> jVsе%& Q@%U%%<%  ~9 $ q@% pj"G%%$  {Zȵ%"p%F%+8%%I%: }G(% P}6 }x9%" 0 -0%Hm  -ط%# ~Z>8% DG `fsdH%ض%%/%|  0b1% 0 r#h%'%*`%f%@%9 pjdP%6 PU!$ 0Xj  PZMP%1%)0%?% P,j (%9 , p)I%Y%/ _ R c"`%HD" @ < %%I%; j< 6%%0%> ijCx%x% j{ G%I `C  (% `B% Pj X% % %h . 06 ص% P9 PK$= P6!H%m =69 =9 `EP'% q[I%`%%Q z%EEp%y %/%%   % %%%yȶ% Ph>%)8%%# _ &%e/з%__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizedOSSLrb_str_newrb_yieldrb_string_value__stack_chk_failossl_get_errorsrb_ary_newERR_error_stringrb_str_new_cstrrb_ary_pushERR_get_errorFIPS_modeossl_protect_x509_ary2skossl_x509_ary2sk0rb_protectossl_x509_ary2skrb_jump_tagossl_x509_sk2aryOPENSSL_sk_numrb_ary_new_capaOPENSSL_sk_valueossl_x509_newstderrfwrite__fprintf_chkossl_x509crl_sk2aryossl_x509crl_newossl_x509name_sk2aryossl_x509name_newossl_str_newmemcpyrb_set_errinfoossl_buf2strCRYPTO_freeossl_bin2hex__assert_failossl_pem_passwd_cbrb_block_given_pPEM_def_callbackrb_warningossl_to_derrb_funcallvossl_to_der_if_possiblerb_respond_toossl_clear_errorERR_get_error_line_datarb_warnERR_clear_errorossl_raiserb_vsprintfERR_peek_last_errorrb_exc_new_strrb_exc_raiserb_str_new_staticERR_reason_error_stringrb_str_cat_cstrrb_str_catrb_check_typeOPENSSL_sk_new_nullrb_ary_entrycX509Certrb_obj_is_kind_ofDupX509CertPtrOPENSSL_sk_pushX509_freeOPENSSL_sk_pop_freeeOSSLErrorossl_pem_passwd_valueFIPS_mode_setInit_opensslOPENSSL_init_sslrb_define_modulemOSSLrb_global_variablerb_define_constOpenSSL_versionrb_define_module_functionrb_eStandardErrorrb_define_class_underrb_internInit_ossl_bnInit_ossl_cipherInit_ossl_configInit_ossl_digestInit_ossl_hmacInit_ossl_ns_spkiInit_ossl_pkcs12Init_ossl_pkcs7Init_ossl_pkeyInit_ossl_randInit_ossl_sslInit_ossl_x509Init_ossl_ocspInit_ossl_engineInit_ossl_asn1Init_ossl_kdfrb_eRuntimeErrorrb_raiserb_string_value_cstrOBJ_txt2objeASN1Errorrb_ivar_setrb_attr_getASN1_OBJECT_freerb_usascii_str_new_staticOBJ_obj2txtrb_str_resizerb_str_set_lenrb_out_of_intOBJ_txt2nidOBJ_nid2lnOBJ_nid2sncASN1EndOfContentrb_funcallv_publicrb_intern2cASN1SetcASN1SequencecASN1GeneralizedTimecASN1UTCTimecASN1ObjectIdcASN1NullcASN1BMPStringcASN1UniversalStringcASN1GeneralStringcASN1ISO64StringcASN1GraphicStringcASN1IA5StringcASN1VideotexStringcASN1T61StringcASN1PrintableStringcASN1NumericStringcASN1UTF8StringcASN1OctetStringcASN1BitStringcASN1EnumeratedcASN1IntegercASN1Booleanrb_block_callasn1time_to_time__isoc99_sscanfrb_cTimerb_eTypeErrorasn1integer_to_numASN1_INTEGER_to_BNossl_bn_newBN_freeASN1_ENUMERATED_to_BNOBJ_createrb_num2intrb_fix2intrb_hash_lookuprb_class_superclassrb_cFalseClassrb_cIntegerrb_cNilClassrb_cFloatrb_cTrueClassrb_cSymbolASN1_object_sizeASN1_put_objectASN1_put_eocrb_convert_typerb_str_appendrb_error_arityASN1_get_objectcASN1Datarb_obj_alloccASN1Constructiverb_int2bigd2i_ASN1_TIMEASN1_TIME_freed2i_ASN1_ENUMERATEDASN1_ENUMERATED_freed2i_ASN1_INTEGERASN1_INTEGER_freed2i_ASN1_NULLASN1_NULL_freed2i_ASN1_OBJECTOBJ_obj2nidd2i_ASN1_BIT_STRINGASN1_BIT_STRING_freeBIO_s_memBIO_newi2a_ASN1_OBJECTossl_membio2strrb_str_new_frozenossl_time_splitrb_Integerrb_num2longasn1str_to_strnum_to_asn1integerossl_bn_value_ptrBN_to_ASN1_INTEGERossl_asn1_get_asn1typeASN1_GENERALIZEDTIME_adjCRYPTO_mallocASN1_TYPE_setASN1_BIT_STRING_newASN1_BIT_STRING_setASN1_STRING_newASN1_STRING_setASN1_STRING_freeASN1_NULL_newASN1_UTCTIME_adji2d_ASN1_TYPEASN1_TYPE_freerb_str_drop_bytesrb_cArrayrb_id2symrb_define_module_undermASN1rb_ary_storerb_cObjectrb_attrrb_define_aliasrb_define_methodcASN1Primitiverb_undef_methodrb_mEnumerablerb_include_modulerb_define_singleton_methodrb_hash_newrb_gc_register_mark_objectrb_hash_asetossl_obj2bioBIO_new_mem_bufBIO_ctrlBIO_freeBN_clear_freerb_check_typeddataBN_num_bitsBN_bn2binrb_memhashrb_free_tmp_bufferrb_alloc_tmp_buffereBNErrorrb_obj_classrb_data_typed_object_wrapBN_newossl_bn_ctxBN_sqrBN_bn2hexrb_cstr_to_inumBN_is_zeroBN_is_negativecBNBN_dupBN_set_negativeBN_is_oddBN_is_oneBN_cmpBN_bin2bnrb_absint_sizerb_integer_packrb_alloc_tmp_buffer_with_countBN_copyBN_hex2bnrb_string_value_ptrBN_mpi2bnBN_dec2bnrb_eArgErrorBN_is_bit_setBN_clear_bitBN_mask_bitsBN_set_bitBN_lshiftBN_rshiftBN_randBN_pseudo_randBN_is_prime_fasttest_exBN_is_prime_exstrlenBN_bn2decBN_bn2mpirb_assoc_newBN_mod_inverseBN_generate_prime_exBN_pseudo_rand_rangeBN_rand_rangeBN_ucmpBN_gcdBN_mod_expBN_expBN_mod_sqrBN_mod_mulBN_mod_subBN_mod_addBN_divrb_ary_new_from_argsBN_mulBN_subBN_addrb_error_frozen_objectBN_CTX_newrb_define_alloc_funcEVP_CIPHER_CTX_freeEVP_CIPHER_CTX_newEVP_get_cipherbynameEVP_CipherInit_exeCipherErrorEVP_CIPHER_CTX_cipherEVP_CIPHER_flagsEVP_CIPHER_CTX_iv_lengthEVP_CIPHER_CTX_get_app_dataEVP_CIPHER_CTX_key_lengthEVP_CIPHER_CTX_ctrlEVP_CIPHER_CTX_block_sizeEVP_CipherFinal_exEVP_CipherUpdaterb_eRangeErrorossl_evp_get_digestbynameEVP_BytesToKeyOPENSSL_cleanseEVP_md5OBJ_NAME_do_all_sortedEVP_CIPHER_CTX_copyEVP_CIPHER_nidrb_class_path__memcpy_chkEVP_CIPHER_CTX_set_paddingEVP_CIPHER_CTX_set_key_lengthEVP_CIPHER_CTX_set_app_dataossl_evp_get_cipherbynamecCipherossl_cipher_newDupConfigPtrcConfigNCONF_newNCONF_load_bioNCONF_freeeConfigErrorCONF_get1_default_config_fileEVP_MD_CTX_freeEVP_MD_CTX_copyEVP_MD_CTX_neweDigestErrorEVP_MD_CTX_mdEVP_DigestInit_exossl_digest_updateEVP_DigestUpdateEVP_MD_typeEVP_MD_block_sizeEVP_MD_sizeEVP_DigestFinal_exEVP_get_digestbynameossl_digest_newcDigestrb_requirerb_path2classrb_define_private_methodENGINE_freeENGINE_get_cmd_defnsENGINE_load_public_keyossl_pkey_neweEngineErrorENGINE_load_private_keyrb_iv_setENGINE_get_firstENGINE_up_refENGINE_get_nextENGINE_load_builtin_enginesOPENSSL_init_cryptoENGINE_by_idENGINE_initENGINE_ctrlENGINE_get_nameENGINE_get_idrb_sprintfENGINE_set_defaultENGINE_get_digestENGINE_get_cipherENGINE_finishENGINE_ctrl_cmd_stringcEnginerb_undef_alloc_funcHMAC_CTX_freeeHMACErrorHMAC_CTX_newHMAC_CTX_copyHMAC_FinalHMAC_UpdateHMAC_Init_excHMACrb_get_kwargsEVP_PKEY_CTX_new_idEVP_PKEY_derive_initEVP_PKEY_CTX_ctrlEVP_PKEY_deriveEVP_PKEY_CTX_freerb_check_hash_typerb_extract_keywordsEVP_PBE_scryptrb_num2ulongPKCS5_PBKDF2_HMACNETSCAPE_SPKI_freeeSPKIErrori2d_NETSCAPE_SPKIeX509CertErrorGetPKeyPtrossl_pkey_check_public_keyNETSCAPE_SPKI_verifyGetPrivPKeyPtrNETSCAPE_SPKI_signNETSCAPE_SPKI_set_pubkeyNETSCAPE_SPKI_get_pubkeyNETSCAPE_SPKI_printNETSCAPE_SPKI_b64_encodeNETSCAPE_SPKI_newNETSCAPE_SPKI_b64_decoded2i_NETSCAPE_SPKImNetscapecSPKIi2d_OCSP_CERTIDeOCSPErrorOCSP_CERTID_freeOCSP_id_get0_infoOCSP_CERTID_dupi2d_OCSP_SINGLERESPOCSP_SINGLERESP_freed2i_OCSP_SINGLERESPOCSP_SINGLERESP_itASN1_item_dupi2d_OCSP_BASICRESPOCSP_BASICRESP_freeOCSP_BASICRESP_itOCSP_basic_add1_nonceOCSP_REQUEST_freeOCSP_REQUEST_itd2i_OCSP_BASICRESPi2d_OCSP_RESPONSEOCSP_RESPONSE_freeOCSP_RESPONSE_itd2i_OCSP_RESPONSEi2d_OCSP_REQUESTOCSP_request_onereq_countcOCSPCertIdOCSP_request_onereq_get0OCSP_onereq_get0_idOCSP_request_add0_idOCSP_request_add1_nonced2i_OCSP_REQUESTOCSP_id_issuer_cmpOCSP_id_cmpOCSP_resp_countOCSP_resp_get0OCSP_single_get0_statusOCSP_SINGLERESP_get0_idOCSP_SINGLERESP_get_ext_countOCSP_SINGLERESP_get_extossl_x509ext_newcOCSPSingleResOCSP_resp_findOCSP_CERTID_newOCSP_SINGLERESP_newOCSP_copy_nonceOCSP_BASICRESP_newcOCSPBasicResOCSP_response_get1_basicOCSP_response_statusOCSP_response_status_strOCSP_RESPONSE_newOCSP_check_nonceOCSP_REQUEST_newd2i_OCSP_CERTIDGetX509CertPtrOCSP_cert_to_idOCSP_request_is_signedOCSP_response_createX509_gmtime_adjossl_x509_time_adjustrb_check_array_typecX509ExtOCSP_basic_add1_statusGetX509ExtPtrOCSP_SINGLERESP_add_extOCSP_check_validityGetX509StorePtrOCSP_basic_verifyOCSP_request_verifyOCSP_request_signEVP_sha1OCSP_basic_signmOCSPcOCSPReqcOCSPResi2d_PKCS12ePKCS12ErrorPKCS12_freed2i_PKCS12_bioERR_set_markPKCS12_parseERR_pop_to_markd2i_PKCS12ASN1_dupPKCS12_newcPKCS12PKCS12_createPKCS7_RECIP_INFO_freePKCS7_SIGNER_INFO_freei2d_PKCS7ePKCS7ErrorPKCS7_freePKCS7_verifyERR_peek_errorrb_iv_getPKCS7_dataInitBIO_writeBIO_readPKCS7_dataFinalBIO_free_allPKCS7_content_newd2i_PKCS7_RECIP_INFOi2d_PKCS7_RECIP_INFOcPKCS7RecipientPKCS7_RECIP_INFO_newPKCS7_get_signer_infod2i_PKCS7_SIGNER_INFOi2d_PKCS7_SIGNER_INFOcPKCS7SignerPKCS7_SIGNER_INFO_newPEM_read_bio_PKCS7d2i_PKCS7_bioPKCS7_dupPKCS7_RECIP_INFO_setPKCS7_get_signed_attributePKCS7_SIGNER_INFO_setPEM_write_bio_PKCS7X509_CRL_freeOPENSSL_sk_popGetX509CRLPtrPKCS7_add_crlPKCS7_add_certificatePKCS7_add_recipient_infoPKCS7_add_signerOBJ_nid2objPKCS7_add_signed_attributePKCS7_set_cipherPKCS7_ctrlstrcmprb_sym2strPKCS7_set_typePKCS7_newcPKCS7SMIME_read_PKCS7PKCS7_decryptEVP_rc2_40_cbcPKCS7_encryptPKCS7_signSMIME_write_PKCS7rb_thread_check_intsEVP_PKEY_freeEVP_PKEY_base_idossl_ec_newossl_rsa_newossl_dh_newossl_dsa_newcPKeyossl_evp_pkey_typerb_obj_is_instance_ofEVP_PKEY_newePKeyErrorossl_generate_cb_2BN_GENCB_get_argrb_thread_call_with_gvlossl_generate_cb_stopd2i_PrivateKey_bioPEM_read_bio_PrivateKeyd2i_PUBKEY_bioPEM_read_bio_PUBKEYEVP_PKEY_missing_parametersEVP_PKEY_get0EC_KEY_get0_public_keyRSA_get0_keyDSA_get0_keyDH_get0_keyEVP_VerifyFinalEVP_PKEY_sizeEVP_SignFinalDupPKeyPtrEVP_PKEY_up_refmPKeyInit_ossl_rsaInit_ossl_dsaInit_ossl_dhInit_ossl_ecEVP_PKEY_get0_DHDH_get0_pqgDH_set0_keyDH_set0_pqgDH_sizeeDHErrorDHparams_dupEVP_PKEY_assigni2d_DHparamsPEM_write_bio_DHparamsDHparams_printDH_generate_parameters_exDH_newBN_GENCB_newBN_GENCB_setrb_thread_call_without_gvlBN_GENCB_freeDH_generate_keyDH_freeDH_checkDH_get0_enginePEM_read_bio_DHparamsd2i_DHparamsASN1_d2i_biocDHEVP_PKEY_get0_DSADSA_get0_pqgDSA_set0_keyDSA_set0_pqgeDSAErrord2i_DSAPrivateKeyi2d_DSAPrivateKeyi2d_DSA_PUBKEYDSA_printDSA_generate_parameters_exDSA_newDSA_generate_keyDSA_freePEM_read_bio_DSAPrivateKeyPEM_read_bio_DSA_PUBKEYd2i_DSAPrivateKey_biod2i_DSA_PUBKEY_biod2i_DSAPublicKeyPEM_ASN1_read_bioi2d_DSAPublicKeyPEM_write_bio_DSAPrivateKeyPEM_write_bio_DSA_PUBKEYcDSAEC_GROUP_clear_freeEC_POINT_clear_freeEC_POINT_is_on_curvecEC_POINTeEC_GROUPeEC_POINTrb_obj_dupEC_POINT_dupEC_POINT_newEC_POINT_oct2pointEC_POINT_bn2pointEC_POINT_freePEM_write_bio_ECPKParametersi2d_ECPKParametersASN1_i2d_bioeECErrorEC_GROUP_set_seedrb_sym2idEC_GROUP_new_curve_GFpcEC_GROUPEC_GROUP_dupPEM_read_bio_ECPKParametersEC_GFp_nist_methodEC_GROUP_newd2i_ECPKParametersOBJ_sn2nidEC_GROUP_new_by_curve_nameEC_GROUP_set_asn1_flagEC_GROUP_set_point_conversion_formEC_GFp_simple_methodEC_GFp_mont_methodEVP_PKEY_get0_EC_KEYEC_KEY_printEC_KEY_check_keyEC_KEY_get0_private_keyPEM_write_bio_ECPrivateKeyi2d_ECPrivateKey_bioPEM_write_bio_EC_PUBKEYi2d_EC_PUBKEY_bioECDSA_verifyECDSA_sizeECDSA_signECDH_compute_keyEC_KEY_set_public_keyEC_KEY_set_private_keyEC_KEY_set_groupEC_KEY_dupEC_KEY_freeEC_KEY_newEC_KEY_new_by_curve_nameEC_KEY_set_asn1_flagEC_KEY_set_conv_formcECPEM_read_bio_ECPrivateKeyPEM_read_bio_EC_PUBKEYd2i_ECPrivateKey_biod2i_EC_PUBKEY_bioEC_get_builtin_curvesEC_POINT_point2octEC_POINT_set_to_infinityEC_POINT_invertEC_POINT_make_affineEC_POINT_is_at_infinityECPKParameters_printEC_GROUP_get_degreeEC_GROUP_get_seed_lenEC_GROUP_get0_seedEC_GROUP_get_point_conversion_formEC_GROUP_get_asn1_flagEC_GROUP_get_curve_nameEC_GROUP_get_cofactorEC_GROUP_get_orderEC_GROUP_set_generatorEC_GROUP_cmpEC_POINT_cmpEC_KEY_generate_keyEC_POINT_mulrb_ary_tmp_newEC_POINTs_mulruby_malloc_size_overflowEC_GROUP_get0_generatorEC_KEY_get0_groupEVP_PKEY_get0_RSARSA_get0_factorsRSA_get0_crt_paramsRSA_set0_crt_paramsRSA_set0_factorsRSA_set0_keyEVP_DigestVerifyInitRSA_pkey_ctx_ctrlEVP_DigestVerifyFinaleRSAErrori2d_RSAPrivateKeyi2d_RSA_PUBKEYPEM_write_bio_RSAPrivateKeyPEM_write_bio_RSA_PUBKEYRSA_printd2i_RSAPrivateKeyRSA_generate_key_exRSA_newRSA_freeRSAPublicKey_dupRSA_sizeRSA_public_encryptRSA_public_decryptRSA_private_encryptRSA_private_decryptPEM_read_bio_RSAPrivateKeyPEM_read_bio_RSA_PUBKEYd2i_RSAPrivateKey_biod2i_RSA_PUBKEY_bioPEM_read_bio_RSAPublicKeyd2i_RSAPublicKey_bioEVP_DigestSignInitEVP_DigestSignFinalcRSARAND_statusrb_num2dblRAND_addRAND_seedRAND_byteseRandomErrorrb_check_safe_objRAND_load_fileRAND_write_filemRandomSSL_freeSSL_CIPHER_get_nameSSL_CIPHER_get_versionSSL_CIPHER_get_bitsossl_ssl_typeSSL_get_fdrb_io_taint_checkrb_io_check_closedrb_io_check_readablerb_io_check_writableSSL_set_fdSSL_CTX_freeSSL_CTX_get_optionsSSL_CTX_clear_optionsSSL_CTX_set_optionsSSL_CTX_flush_sessionsSSL_CTX_ctrlSSL_get_servernameSSL_get_ex_dataSSL_get_ex_data_X509_STORE_CTX_idxX509_STORE_CTX_get_ex_dataossl_verify_cb_callSSL_is_serverX509_STORE_CTX_get_error_depthX509_STORE_CTX_get_current_certmSSLcSSLSessionossl_ssl_session_typerb_during_gcSSL_CTX_get_ex_dataSSL_SESSION_up_refX509_get_pubkeyEVP_PKEY_cmpSSL_CTX_use_certificateSSL_CTX_use_PrivateKeySSL_CTX_get_security_levelSSL_CTX_set_cipher_listrb_StringSSL_CTX_get_ciphersrb_uint2bigSSL_get0_next_proto_negotiatedSSL_get0_alpn_selectedSSL_ctrlSSL_get_client_CA_listSSL_get_verify_resultSSL_set_sessionSSL_session_reusedSSL_pendingSSL_state_stringrb_ruby_verbose_ptrSSL_state_string_longSSL_get_current_cipherSSL_get_versionSSL_get_peer_cert_chainSSL_get_peer_certificateSSL_get_certificateSSL_shutdownrb_hash_lookup2SSL_writeSSL_get_errorrb_io_wait_writable__errno_locationrb_io_wait_readablerb_sys_failX509_verify_cert_error_stringSSL_acceptSSL_connectSSL_CTX_remove_sessionTLS_methodSSL_CTX_newSSL_CTX_set_ex_dataSSL_CTX_set_security_levelSSL_CTX_add_sessionstrncmpSSL_readrb_str_modifyrb_str_modify_expandrb_eof_errorSSL_CTX_set_tmp_dh_callbackSSL_CTX_set_cert_storeX509_STORE_up_refSSL_CTX_check_private_keySSL_CTX_add_client_CASSL_CTX_set_verifySSL_CTX_set_timeoutSSL_CTX_set_verify_depthrb_eachrb_iterateSSL_CTX_set_next_protos_advertised_cbSSL_CTX_set_alpn_protosrb_obj_freezeSSL_CTX_set_session_id_contextSSL_CTX_callback_ctrlSSL_CTX_sess_set_new_cbSSL_CTX_sess_set_get_cbSSL_CTX_sess_set_remove_cbSSL_CTX_set_client_cert_cbSSL_CTX_load_verify_locationsSSL_CTX_set_alpn_select_cbSSL_CTX_set_next_proto_select_cbSSL_newSSL_set_ex_dataSSL_set_info_callbackrb_call_supercSSLContextSSL_set_SSL_CTXCRYPTO_get_ex_new_indexrb_mWaitReadablerb_mWaitWritableInit_ossl_ssl_sessioncSSLSocketSSL_SESSION_freei2d_SSL_SESSIONPEM_read_bio_SSL_SESSIONSSL_get1_sessionSSL_SESSION_newd2i_SSL_SESSIONSSL_SESSION_printSSL_SESSION_get_idSSL_SESSION_get_timeoutSSL_SESSION_set_timeoutSSL_SESSION_get_timeSSL_SESSION_set_timeSSL_SESSION_get_protocol_versionCRYPTO_memcmpPEM_write_bio_SSL_SESSIONX509_time_adj_exmX509Init_ossl_x509attrInit_ossl_x509certInit_ossl_x509crlInit_ossl_x509extInit_ossl_x509nameInit_ossl_x509reqInit_ossl_x509revokedInit_ossl_x509storeX509_get_default_cert_areaX509_get_default_cert_dirX509_get_default_cert_fileX509_get_default_cert_dir_envX509_get_default_cert_file_envX509_get_default_private_dirX509_ATTRIBUTE_freei2d_X509_ATTRIBUTEeX509AttrErrorX509_ATTRIBUTE_countX509_ATTRIBUTE_get0_typei2d_ASN1_SET_ANYOPENSSL_sk_freeASN1_TYPE_getX509_ATTRIBUTE_set1_dataX509_ATTRIBUTE_get0_objectX509_ATTRIBUTE_create_by_OBJX509_ATTRIBUTE_dupX509_ATTRIBUTE_set1_objectd2i_X509_ATTRIBUTEX509_ATTRIBUTE_newossl_x509attr_newcX509AttrGetX509AttrPtrX509_EXTENSION_freeX509_delete_extX509_add_exti2d_X509X509_dupX509_newX509_cmpX509_get_ext_countX509_get_extX509_check_private_keyX509_verifyX509_signX509_set_pubkeyX509_set1_notAfterX509_get0_notAfterX509_set1_notBeforeX509_get0_notBeforeGetX509NamePtrX509_set_issuer_nameX509_get_issuer_nameX509_set_subject_nameX509_get_subject_nameX509_get_serialNumberX509_set_serialNumberX509_get0_tbs_sigalgX509_set_versionX509_get_versionX509_printPEM_write_bio_X509PEM_read_bio_X509d2i_X509_bioX509_up_refX509_CRL_delete_extX509_CRL_add_exteX509CRLErrorcX509RevX509_CRL_get_REVOKEDX509_REVOKED_freeDupX509RevokedPtrX509_CRL_add0_revokedX509_CRL_sortossl_x509revoked_newX509_CRL_get0_signatureX509_CRL_dupX509_CRL_newX509_CRL_get_ext_countX509_CRL_get_extX509_CRL_printPEM_write_bio_X509_CRLi2d_X509_CRL_bioX509_CRL_verifyX509_CRL_signX509_CRL_set1_nextUpdateX509_CRL_get0_nextUpdateX509_CRL_set1_lastUpdateX509_CRL_get0_lastUpdateX509_CRL_set_issuer_nameX509_CRL_get_issuerX509_CRL_set_versionX509_CRL_get_versionPEM_read_bio_X509_CRLd2i_X509_CRL_biocX509CRLi2d_X509_EXTENSIONeX509ExtErrorX509_EXTENSION_get_objectX509_EXTENSION_get_dataASN1_OCTET_STRING_setX509_EXTENSION_dupOBJ_ln2nidX509V3_set_nconfX509V3_EXT_nconf_nidX509V3_EXT_printASN1_STRING_printX509_EXTENSION_get_criticalX509_EXTENSION_set_objectGetX509ReqPtrX509V3_set_ctxd2i_X509_EXTENSIONX509_EXTENSION_newX509_EXTENSION_set_criticalcX509ExtFactoryX509_NAME_freei2d_X509_NAMEeX509NameErrorX509_NAME_entry_countX509_NAME_ENTRY_get_dataX509_NAME_get_entryX509_NAME_ENTRY_get_objecti2t_ASN1_OBJECTX509_NAME_print_exrb_utf8_encindexrb_enc_associate_indexrb_utf8_encodingrb_enc_sprintfX509_NAME_dupcX509Namerb_const_getd2i_X509_NAMEX509_NAME_newX509_NAME_cmpX509_NAME_onelineX509_NAME_hash_oldX509_NAME_hashX509_NAME_add_entry_by_txtrb_mComparablerb_hash_set_ifnoneX509_REQ_freeX509_REQ_delete_attrX509_REQ_add1_attreX509ReqErrorX509_REQ_get0_signaturei2d_X509_REQX509_REQ_dupX509_REQ_get_attr_countX509_REQ_get_attrX509_REQ_verifyX509_REQ_signX509_REQ_set_pubkeyX509_REQ_get_pubkeyX509_REQ_set_subject_nameX509_REQ_get_subject_nameX509_REQ_set_versionX509_REQ_printPEM_write_bio_X509_REQX509_REQ_newPEM_read_bio_X509_REQd2i_X509_REQ_bioX509_REQ_get_versioncX509Reqi2d_X509_REVOKEDeX509RevErrorX509_REVOKED_delete_extX509_REVOKED_add_extX509_REVOKED_dupX509_REVOKED_get_ext_countX509_REVOKED_get_extX509_REVOKED_set_revocationDateX509_REVOKED_get0_revocationDateX509_REVOKED_set_serialNumberX509_REVOKED_get0_serialNumberX509_REVOKED_newX509_STORE_CTX_get0_untrustedX509_STORE_CTX_get0_certX509_STORE_CTX_freeX509_STORE_freeX509_LOOKUP_fileX509_STORE_add_lookupX509_LOOKUP_ctrleX509StoreErrorX509_LOOKUP_hash_dircX509StoreContextX509_STORE_CTX_get_errorX509_STORE_CTX_set_timeX509_STORE_CTX_set_errorX509_STORE_CTX_set_flagsX509_STORE_CTX_get0_current_crlX509_STORE_CTX_get0_chainX509_STORE_CTX_set_ex_dataX509_verify_certX509_STORE_CTX_newX509_STORE_add_crlX509_STORE_add_certX509_STORE_set_default_pathsX509_STORE_set_flagsX509_STORE_set_ex_dataX509_STORE_set_verify_cbX509_STORE_newrb_block_procX509_STORE_CTX_initX509_STORE_CTX_set_purposeX509_STORE_CTX_set_trustX509_STORE_set_purposeX509_STORE_set_trustX509_STORE_CTX_get0_storeX509_STORE_get_ex_datacX509Storelibruby.so.2.5libssl.so.1.1libcrypto.so.1.1libc.so.6_edata__bss_start_endGLIBC_2.14GLIBC_2.4GLIBC_2.2.5GLIBC_2.7GLIBC_2.3.4OPENSSL_1_1_0OPENSSL_1_1_1 I` Iii Iui Iii Iti IuI mIImImI|%p|%0|%|%|%d|% }%X0}%,}%}%I}%}% R@~%`P~%p_~%G~%s%%P}`% p%%%%p %<0%p%R%p%F%@%P% %%0%%``%p%%FЂ%% %W0%%%ӵ%% %%Ѓ% %'%@%3P%%%%%@`%cp%%JЅ% %0%@5%%p/%t%@@%'P% T%%b%%pl`%p%l%Ј%%:%B%M%Z %0%_@%qP%z`%p%%%%%%͈Љ%ֈ%ڈ%%% %0%@%#P%3`%Ap%M%[%k%|Ȉ%Q%Q؈%h%%%%`%%H%%(%(%%h%X%%K %Kȉ%+0%+؉%%%p%%%x%%%Ȫ%%Ȯ%(%0%8%%H%P%X%ج%h%x%x% % %H%%%%%%P%%#%.%0Ъ%2ت%%%0%%D%F%-%%0%[8%@%H%P%X%n`%ph%wp%}x%%%%%%%%%%ȫ%Ы%ث%%%%%A%%%B%C %>(%0%8%@@%LP%4X%4`%6p%x%@%%O%E%%T%a%MȬ%Ь%d%t%%%%%%% %(%0%8%@%IH%P%<X%`%1h%p%%%%%%O%%%ȭ%Э%Uح%F%,%%(%:%%C%%! %W(%\8%@%iP%X% `%h%8x%%%%%%%%%$%"Ю%خ%%%*%%<%=% %(%/8%@%PH%Qh%_p%%G%?%%%u%x%%%ȯ%Я%د%%H،%%%%%%%%% % (% 0% 8% @%H%P%X%`%h%p%x%%%%%%%%%%ȍ%Ѝ%؍% %!%"%$%%%&%'%(%) %*(%+0%,8%-@%/H%1P%X%3`%4h%5p%6x%7%8%9%&%:%;%<%=%%>Ȏ%?Ў%@؎%A%B%C%E%F%G%H%I%J %K(%L0%8%M@%NH%OP%PX%Q`%Rh%Sp%Tx%U%V%W%X%Y%Z%[%\%]%^ȏ%Џ%_؏%`%a%b%c%d%e%f%g%h %i(%j0%k8%l@%mH% P%oX%q`%rh%sp%tx%u%v%x%y%z%{%|%~%%Ȑ%А%ؐ%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%ȑ%Б%ؑ%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%*%%%%%%%%%Ȓ%В%ؒ%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%.%%%ȓ%Г%ؓ%%%%%%%D%% %(%0%8%@%H%P%X%`%h%p%x%:%%%%%%%%%Ȕ%Д%ؔ%%%%%% %%% %(%0%8%@%H% P%X% `% h% p% x%%%%%%%%%%ȕ%Е%ؕ%6%%%%%%%%  %!(%0%"8%#@%$H%P%%X%&`%'h%(p%)x%*%+%,%-%.%/%0%1%2%3Ȗ%5Ж%6ؖ%%7%8%9%:%;%<%=%> %?(%A0%B8%C@%DH%EP%FX%G`%Hh%Ip%Jx%K%L%M%N%P%Q%R%S%T%Uȗ%VЗ%Wؗ%X%Y%Z%[%\%]%^%_%` %b(%0%c8%e@%fH%gP%hX%;`%ih%jp%kx%l%m%n%o%p%q%r%s%u%vȘ%wИ%xؘ%y%z%{%|%}%~%%% %(%0%8%#@%H%P%X%`%h%p%x%%%%%%%%%%Rș%Й%ؙ%%%5%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%Ț%К%ؚ%%%'%%%%%% %(%0%8%@%H%JP%X%`%h%p%x%%%%%%%%%%ț%Л%؛%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%Ȝ%М%؜%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%% %% % % % %ȝ%=Н%؝%%%%%%%%% %(%0%8%@%H%P%X%`% h%!p%"x%%#%%$%%%,%&%'%(%)Ȟ%*О%+؞%,%-% %.%/%0%%1%2 %3(%40%58%6@%7H%8P%9X%;`%<h%=p%>x%?%@%A%B%%%D%E%F%Gȟ%HП%I؟%J%K%L%M%N%O%P%Q%R %S(%T0%U8%@%VH%XP%YX%Z`%[h%]p%^x%_%`%a%b%c%d%e%f%g%hȠ%jР%kؠ%l%%m%n%o%p%q%r%s %t(%u0%v8%w@%xH%yP%zX%{`%|h%}p%x%~%%%%%%%%%7ȡ%С%ء%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%Ȣ%Т%آ%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%ȣ%У%أ%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%2%%%Ȥ%Ф%ؤ%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%ȥ%Х%إ%%%%%%%%3%  % (%S0% 8% @% H%P%X%`%h%p%x%N%%%%%%%%%Ȧ%Ц%ئ%% % %!%"%#%$%%%& %'(%(0%)8%+@%,H%-P%.X%/`%0h%1p%2x%3%4%%5%6%7%8%9%:%;ȧ%<Ч%>ا%9%?%@%A%%B%C%%D %E(%F0%G8%H@%IH%JP%KX%L`%Mh%Np%Ox%Q%R%S%T%U%V%W%X%Y%ZȨ%[Ш%\ب%%]%^%)%%`%a%b%c %d(%e0%f8%g@%hH%iP%jX%k`%lh%mp%nx%o%p%q%r%s%t%v%w%%yȩ%zЩ%{ة%|%}%~%%%%%% %(%0%8%@%H%P%X%`%h%p%x%HHyr$HtH5S$%S$hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhh%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D%} $D%u $D%m $D%e $D%] $D%U $D%M $D%E $D%= $D%5 $D%- $D%% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D%} $D%u $D%m $D%e $D%] $D%U $D%M $D%E $D%= $D%5 $D%- $D%% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D%} $D%u $D%m $D%e $D%] $D%U $D%M $D%E $D%= $D%5 $D%- $D%% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D%} $D%u $D%m $D%e $D%] $D%U $D%M $D%E $D%= $D%5 $D%- $D%% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D% $D%} $D%u $D%m $D%e $D%] $D%U $D%M $D%E $D%= $D%5 $D%- $D%% $D% $D% $D% $D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%$D%}$D%u$D%m$D%e$D%]$D%U$D%M$D%E$D%=$D%5$D%-$D%%$D%$D%$D% $D%$D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%}#D%u#D%m#D%e#D%]#D%U#D%M#D%E#D%=#D%5#D%-#D%%#D%#D%#D% #D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%}#D%u#D%m#D%e#D%]#D%U#D%M#D%E#D%=#D%5#D%-#D%%#D%#D%#D% #D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%}#D%u#D%m#D%e#D%]#D%U#D%M#D%E#D%=#D%5#D%-#D%%#D%#D%#D% #D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%}#D%u#D%m#D%e#D%]#D%U#D%M#D%E#D%=#D%5#D%-#D%%#D%#D%#D% #D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%}#D%u#D%m#D%e#D%]#D%U#D%M#D%E#D%=#D%5#D%-#D%%#D%#D%#D% #D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#DH=9$H2$H9tH~#Ht H= $H5$H)HHH?HHtH#HtfD=#u+UH=#Ht H=N#d#]wH#HÐHHHHEH #Hff.H1rfHdH%(HD$1H$Ht HH$HT$dH3%(uH3SH1HHHHs>HuH[@H3HHHЃfHHH=O#Zf.HdH%(HD$1Ht$D$|$uHT$dH3%(u H_ff.@AUATUSHHt}HAąxNHcIEt+1@HHsLHhD9uHL[]A\A]DH#H8H[]A\A]`H#AH8uH.# H=EH H H=6H;AZ1H )H)Y@H# H=H XH H=?H;AZ1H HLAUATUSHHt}HAąxNHc&IEt+1@HHLHD9uHL[]A\A]DHI#H8H[]A\A]H)#AH8uH# H=H MH H=4H;A[1H HAY@HY# H=pH H H=|H;A[1H THTAUATUSHHt}HAąxNHcIEt+1@HHLHD9uHL[]A\A]DH#H8H[]A\A]H#AH8uHN# H=eH H H=VH;A\1H IHIY@H# H=H xH H= _H;A\1H HlAUIH=`ATIUHSHdH%(HD$1HT$hHHt`D$EuuMtH{H u3LLHL$dH3 %(HuLH[]A\A]f.H{f.D$tY4@UHcSHHdH%(HD$1HT$FHߺ~H5H?|$uHL$dH3 %(Hu H[]H?H9wN1L Ht? AȃAA EGLFDFHH9uf.PH 'H5H=0ff.@AWAVLcAUATUHSHdH%(HD$1Ht>H؃- tHHYI9HqHHH|$dH3<%(iH[]A\A]A^A_HI9HqfYtuLd$McMIALLH=T$uvHtzHHځ t"HXI9|AHpHMHpDH1ɉDH!*@DH=.1'rf@H#H8uH,# H=CH H "H=H;A1H 'H'@HH5#11dH%(HD$1HH$lH$HT$dH3%(uHff.SH5#HuH[H[AVAUATUSH dH%(HD$1Hi#H8Lt$Ll$IHl$HyfDLLLHHtW1H HHDD$t"HT$HtXHH=81DHH=81D3HD$dH3%(u!H []A\A]A^fDH\$Hff.fATUHHSHHT$0HL$8LD$@LL$Ht7)D$P)L$`)T$p)$)$)$)$)$dH%(HD$1H$$HD$HD$ D$0HD$Ht.HHHu1HtHHHnHuJ11HHsIHt6H u@u>MtOLHAH7IMt6LHH{뾺H5HtL%^fff.@AUATUHSHeHI1HHH9}NHHHEIH;#LH0Ht3LcLHHE uHEH9|HL[]A\A]H5#LYH#H5H81qH#1H81^ff.HHH|$HtH|$HD$H u HDHx~H#H5KH81SHHt*t.H[Ð1uH6#H5H81DuH #H5H81fS11H=NH?#HHH=+H;H5Hi H=H;H5HF1HH;H5H%H;! H5H;H5H;1HH5H;HH5Hs#H;H5wHH=#HH=;#HH;1HsH5G7H;HhH52HU#H;1H5!H=H#MSIT%P+F[0H#H5H81xHH|$H|$H|$H uH1HtHf.H1uHuH|$H t2HTHuH#HT$H5H81fHf.H=ff.AT1UH-#SHH=|H5Y#HߺI)H5J#LHH5 #HߺH5#HHH5#H1H[]A\USHH5#dH%(HD$1:HHT$H=FHH苿HH|$uHL$dH3 %(Hu H[] @ATUH1SH0H HHxHPHHc tUHSH9~7D`HIcH{H tH{HDL~?HcHH[]A\DHHxHcljH9u!H{]H#H5H811H=ݶH\$xdH3%(H[HpHPHHVHPLHL@ H5O1x^_-ND$DHc$D$HTLHpHPHHVHPLHL@ H51ZY Hc$D$HTHH5F#HT$hHDHD$@HcD$HDHD$HHcD$ HDHD$PHcD$HDHD$XHcD$HDHD$`HtH#HL$@H8H=HH#Hc$lD$HTRf$@$D$$H?#HSH5H81H##HSH5H81ff.USHHtC1 t1HHtFHHHyHH[]sHH#H5H816H#1H81#ATIUHSH tu_HtVuLH5#H胦H5#LHqH5#HH_H5`#H1NH[]A\H#H5H81ff.H(H|$HT$Ht$HL$诼H|$襼H|$蛼HT$H uMHt$HH uMHH|$H uH t4H(fHf.Ht$HRH tHvH#1H81DHH5u#Ht$HǨuHfkHH_#H5H81nff.S@ti@H@ H_'H=#HHu;HòHHuڸ[HuHt=HuH]#HHǨt 褴[f;[fHQ#HHu#HH9#HH=#HH#HqAWAVIAUAATAUHSH8dH%(HD$(1t ҸDEH5#LXHnH;#aH;#H;#WH;#D$LLD$nHMD$ ]HIIcIcI9FH5M#LųH9~#8E1EAA|$8T$DDDT$DT$T$ƉD$DDT$߱1HHHD$DT$D\$IH@I tIGLt$ DD$DD֋L$LHD$ /L$DE1LHuHE tHuH|$ HH\$ H\$ EIGI tIGH)H;\$4HT$(dH3%(LH8[]A\A]A^A_@L}T$DD1HHHD$ IH@I tIGLt$ DD$L$DLHD$ H|$hH@HHt?L|$LHHփD$\H5X#tH5I#u@H5D#HD5D#LHct$XLHt6LLl$hBK,'H #HH#H8qHt$HL$LHHH5#A!H{fDE1HH 2#LD$HDH2H8HD$H$L$HDŽ$H$ޡH$HHALD$H5#KTHfDA.H kDHcH>f.HRLHۿHHHE#HDH8(HH|$xHt$xH1D$pIHH=!#HT$pH$LIٗ|$pDHH F#E1HHIcHTH9L$pDH|$xHt$xH1D$pIHcH=A#HT$pH蜠LI|$pt4@H|$xHt$xH1D$p脲IH H=#HT$pHDLI |$p%HL?+!IcMHE1IH;AyfDH?v1H=H #E1IHH|$xHt$x1HLH6HA蕗HH #E1hH|$xHt$xH1#HH5\H81JH##H5fH812H #H53H81f.AWHAVAUATUSHHHt$dH%(HD$81HD$ 蘽H|$HD$)H豮L8HD$(A IHAHD$L<$2L<$1HM~NLt$0Ll$ Ld$DLME11HD$0LLHHHD$0I)HMHD$(HD$0HD$(H$HtLD$ H9uBI9u=HL$8dH3 %(HuIHH[]A\A]A^A_DHPH@HT$H$;H#H $HH5H81賰讶ff.SHH@Ht$dH%(HD$81HD$ HD$((H|$HD$蹬HAHHD$ utHHHD$HT$(H|$1HLL$ AEHD$HD$0HD$HtHT$ LD$(H9u1I9u,HL$8dH3 %(u2H@[fHPHXHT$H#HH5H81覯衵SHH@Ht$dH%(HD$81HD$ HD$((H|$HD$蹫HAHHD$ utHHHD$HT$(H|$E11LL$ HHHT$HT$0HT$HtHT$ LD$(H9u4I9u/HL$8dH3 %(u:H@[f.HPHXHT$H#HH5H81覮衴AUATUHSHHdH%(HD$17IĨt`HI?HW)QΠEHHHH L)Hi€QH)HcH H9UHD$dH3%(H[]A\A]@H5#H$HILLUHǨt>蹞H5J#EH$HtBLL"tHHpfHfDH=迨HH#H=蟨HH#HH踾3Hc7HSHH|$Ht#H|$HHH褧HtH[HB#H5cH81ѬHB#1H81辬ff.AUATUSHH(dH%(HD$1*H5K#H߉詝7H IHcH>f.LHT$ Ht$nT$ Ht$11茝IHPL-#/H5ÝHHfLHHHL$dH3 %(H([]A\A]ÐII/IH57MUIEHHuH_#H5ښH81nfDL1ΪL-/#I6H5#HiHǨ HcLd$H;H|$kIH*Ht$H YHHLID$HcL-#HH I\$H|$Ld$蜍IHHt$H HHL L-#GIdIHtyL-"#$DH耱H(IHtPH HHsLHT$ Ht$T$ Ht$11|IHH#1H81轩DL0L-#Im@H~HcljH9usHvfH~HcljH9uSHvfH{HcljH9u3HsH#H5vH81!L1A芺Hc#H5H81H˿#H5"H81ڨH#H5H81¨fATUHSH@dH%(HD$81<H軷1HI莫HcHHT$H1裠T$HD$0H H@Ht$ LHD$(HD$ :L2HD$ H+D$(H9HL$HT$ IHt$H|$(SH+\$H|$0HH11HZHL$8dH3 %(u:H@[]A\ÐHfH5a#HH|$0HD$0{L胍|$LrH;#H5ΖH81JH sH5ѕH= H#H5H81SH5#H,H#HH2 Hu%H5#HHuH[DH[H#H5H81蟦ff.@AW H=,AVAUL-#ATL%U1SH譡H%H=H*#荡H H=H#mHH=ޕH#MHŵH=H#-H襵H=H# H腵H=9H=Hc#&H=HH#H=wH%#H=oH#H=oH#ڴH5iHܿ#H#H8=H#H/#H5CHHH芌H#H;H5)HHJH;H6H5 ʬH;HH5诬JH;H5HIջH;EMeIA$<[t&HT-L袻LLHH܃H;HHuH#H5H詋L%"#H=I$袳I<$E1HٯH=}I<$E1H贯H=ɓXI<$E1H華H=3I<$E1HƺjI<$HH5賨I<$HH5蜨I<$H,H5萓I<$1H#H5KwI$H;H5ē蔊H-#H=HE荲H}AHƺH}H5RH}H5UH}H1H5JH}1HH5ܒI$H;H53Hڷ#L5#HH2I݌H=II>AHƺI>HH5kI>1HH5'SI>1HH5;HUH;H5XH #H;H7H5H賩HUH;H5t H #H;HH5WH{HUH;H5DH i#H;HH5'HCHUH;H5谈L=9#H;HjH5I HUH;H5xH #H;HH5̑HӨHUH;H5@H #H;H?H5H蛨HUH;H5H #H;HH5sHcHUH;H5fЇH q#H;HH5IH+HUH;H5>蘇H #H;HwH5!HHUH;H5`H Q#H;HH5H軧HUH;H5(H #H;HGH5ʐH胧HUH;H5H #H;HH5HKHUH;H5踆H Y#H;HH5rHHUH;H5c耆H #H;HH5FHۦHUH;H59HH #H;HH5H裦HUH;H5H !#H;HOH5HkHUH;H5؅H )#H;HH5ƏH3HUH;H5蠅L-#H;HH5IEHUH;H5gH #H;HH5cH¥HUH;H5P/H #H;HH53H芥IH;H5)H Q#H;HWH5 HSIH;H5$L5#H;HH5II$H;H5Î艄H-J#H;H#H5HEI}HSH5藐I}1HzH5~I}1HH5hI}1HXH5ŘI}H<H5?襡I}H(H53莡H=aҫI?E1Hƺ H}1H]H5aH}1H$H5H蓐HHy#贌HuH=d#߇H#H=L#H0ćH #H=1#H0詇I7H=#蕇Hv# H=#H0zH;# H=#H0_Iu H=ϵ#JH;#H=#H0/H#H=#H0Hݲ#!H=#H0I6#H=j#H#%H=R#H0ʆH۳#'H=7#H0识H#)H=#H0蔆H#+H=#H0yHB#-H=#H0^Hw#/H=˴#H0CH,#1H=#H0(H#3H=#H0 H#5H=z#H0H#7H=_#H0ׅH#9H=D#H0輅H=#=H=)#H0衅H=#H=;ĔH#H[]A\A]A^A_f.@SHHdH%(HD$1H?H<$@u Hu^HvH<$H7 twHGHcЉH9uvHHH$HHL$dH3 %(H[fD uH5#Ht211H$zHHHH=O跓H<$HHQ#Hȯ#H5H81?:f.U1ҾsSHH(dH%(HD$1HL$袪HD$HT$ HxH0,HH|$ uHt$dH34%(Hu H([] 赝DH7UH5}#HAWAVAUATSH(dH%(HE1xHHI|XI=LmLmLcHHEIFHH%H)HHH9tHH$H9uutL|$ILL@9uLLvLH֦HDHMdH3 %(uuHe[A\A]A^A_]LcLmLL~IfH)HLH#H5H81MLeH^#H5H81-(ATH5|#USHvHtmHHɮHb|#1HI谔HHt.H#HHHst I\$ L[]A\H躮Hë#1H81藕H#H5ߋH81ff.@PX1HH#H81WS1H{#=HHt HC H[fPXH5mHH4#H81fUH5d{#SHuHtCH識HHtKH#sHߺ7H5+HHH[]Hê#H5H81芔DHH5z#uHtH菃HHHD.ff.HH5z#tHt HOPHHHHDfHH5az#tHtHxHHHЃfSH5$z#_tHt1HH_xt 1[H¸u1T@UH5y#SH tHtTHHc#Hy#1H8:HHHHt>HE H{1H߅@蛁HH[]H"#H5IH81H#H5\H81ђHH51y#lsHtHvHHHЃyfHH5x#,sHtHHHHЃ9fUHSHHHHN#H0NHu H1[]HH5x#rHHt4H5rx#HrHtHHuH[]H#H5H81轑ff.fUHAWAVAUIATSHH8dH%(HE1IH?H}HMIHHL1H)PHHH9uLc}HHBMHudH34%(H;He[A\A]A^A_]f1H覣IH=H=LuLuH@HHEHH%H)HHH9u|t H)HLL|$IE1HLALsLDLE|LHzHۋMt]H~ HH$jHpLuHLHHxIcH#H5oH81ݏؕH#H5\H81谜ATUSH dH%(HD$1GvHH HT$u#H~@PHT$ftKH5u#HoHD$HRH|$HHL$dH3 %(H)H []A\Ðu HurH#HH0HH5Mu#HoHD$HH|$H5+u#foHH|$H}Hff u&HT$VfDH5t#HoIHD$HT~5 |H|$iH|$H܄qfHT$H tsHjHcH9H|$LHDH(fH|$H|$H`H#1H81~fDHHHT$H u7HHHcH9uTH|$SLHVyHHjͺsH$#H5H81HqH #H54H81Ԍ@HATL%ϣ#USI4$HɐHutt7I<$1Hs#荢1HHHtVHE H[]A\u#Ht uf[H]A\H[H]A\UHH5r#SHlHtNHH7Ht#H5Zr#HlHtAHH~tH1[]DH[]Hա#H5H81蜋wUHHSHt;V|H5q#HlHt)HHHH[]軉fATIH5q#USHkHt?LAHu%耉H覞tH[]A\f.{bH#H5H81躊f.ATIH5q#USHFkHt?LAHu%HvtH[]A\f.;{Hs#H5H81:f.ATIH5p#USHjHt?LAHu%耈HtH[]A\f.zbH#H5H81躉f.UHHSHt;vzH5o#H5jHt.HHitHH[]DۇHs#H5H81:f.UHHSHt;yH5}o#HiHt.HHtHH[]D[bH#H5H81躈f.AUATUHHSHtoryH5n#H1iIHtuHAHn#1H`I(HHt9LHht Im HL[]A\A]D裆H'H0#1H81H%#H5L~H81ff.AUATUHHSHtoxH5)n#HahIHtuHqH n#1H萝IXHHt9LHst Im HL[]A\A]DӅHWH`#1H814HU#H5|}H81ff.AVAUATUSH@dH%(HD$81HD$HD$ HD$HD$(HD$HD$0G)HIH\$u>HD$HD$t5E1E1H߃uOMHFHD$uHFHD$E1H|$AH|$@ty$wAH߃twLHl#1!IHHtaDDHqtEI^ LHL$8dH3 %(uXH@[]A\A]A^fKAfDE1dHHɛ#1H81蝅艋fAVAUATUSH@dH%(HD$81HD$HD$ HD$HD$(HD$HD$0G)HIH\$u>HD$HD$t5E1E1H߃uOsMHFHD$uHFHD$E1H|$AH|$@tyuAH߃tuLHk#1葚IYHHtaDDHxtEI^ LHL$8dH3 %(uXH@[]A\A]A^f軂AfDE1dH0H9#1H81 ^~fATUSIԽt!H>uHn1Ht @tgtH5j#LQdHttH}#1HHE1H=tu9[]A\f.[1]A\fˁ뗺1}HT#1H81(HI#H5pyH81SHuH>@tnHT$sHT$DHH5>i#ycHHtsH#1ɉH|tu8H[f.H1[HT$HT$H#1H81Z1|Ho#H5xH816fDATUSHH>@xHT$rHT$H5`h#HbHH tcQH臅HHtZH'vHcH9GHH߉[]A\ifH5g#H!bHHH]nHHuHn#1H81Bf1Hf1HcIrHHpH uqHfA9uHH[]A\H pD`DI1AIcqHHpH tHpH+A9]HH[]A\fDHpf.HT$HT$1zH#H5wH81TH̑Hm#H5vH814@UHSHHtkuVHHHtb؃tX tS t0t+u?H11HHHH[]馂fDHHHuH#HH0赃HuH#H52vH81uDUHHe#1SHHk#H8KHHt#H+tHtHC HH[]}H2#1H81fDUHSHH?+Ht"H5Ne#HH_Ht#H]H[]H#H5vH81~fDAUATUSHHH|$Ht$cH5d#HI_HtwHH.Hd#1HMI}HHt8H#LHHHbHtI\$ HL[]A\A]HH#1H81}H#H5:tH81}f.AWAVAUATUSHXdH%(HD$H1HLl$H\$HD$ HD$HD$(GLl$0H\$8BHHչH$HD$ L@fHt LcN L HI9tHP9HtHHI9uH<$@{AE1H|$AH|$LE1aH|$It HaIHH>c#1ǒH{HHtjE1MLDDHgtGH] HH\$HdH3%(uZHX[]A\A]A^A_fDKmAQE1E1}H]Hf#1H81:|v&fDATUSHHH|$Ht$a1Hib#HIHzHt"LHHS\tH] HH[]A\JH”Hˑ#1H81{ff.@ATUSHHH|$Ht$r`1Ha#HI^H&zHt"LHHmtH] HH[]A\H2H;#1H81{ff.@USHHH|$Ht$_H5Ma#HH[HtHHgHH[]HDff.@USHHH|$Ht$_H5`#HH"[HtHHrmHH[]HD/ff.@AUATUSHHH|$Ht$ _H5`#HIZHtvHHΒHg`#1HIxHHt7H#LHHHftI\$ HL[]A\A]H趒H#1H81yH#H5oH81{yff.AVAUATUSHHH|$Ht$H$J^HI?^H5_#HIYHt{HHH_#1H IwHHtXHtvHHNH]#1HmI5vHHt7H>#LHHHrtI\$ HL[]A\A]H6H?#1H81wH4#H5[mH81vff.AVAUATUSHHH|$Ht$H$[HI[H5(]#HI]WHt{HHmH]#1H茌ITuHHtH5\^H;HSH5\]H;HXH5d]H;H]H5d]H;HbH5od]H;HwH5\d{]H;HH5Id`]H;HH51dE]H;HH5d*]H;H+H5 d]H;HcH5cqH;HH5c\H;H/H5c\H;1HH5̓\H;H,H5c\H;HcH5cjqH;1HH5lcb\H;1HvH5ZcJ\H;1HH5Gc2\H;1HH54c\H;HH5*c_H;H H5cd_H;HH5cI_H;HJH5b._H;HH5b_H;H$H5bx[H;H)H5b][H;HH5bB[H;HH5b'[H;H8H5b [H;HH5vbZH;HH5fbZH;HH5NbZH;HH56bZH;HH5#bZH;HH5bjZH;1HH5aRZH;HaH5a,oH;1H0H5a$ZH;HH5` ZH;[H H5aYH#H5[`H81iDvATUSHHH|$Ht$`H5P#HIIHuK&jHHHC LNpHtTE111AHHQKu$HH[]A\H#H5"aH81hH~#1H81hH~#HT$H5bH81hH~#1H81hDHUO#1~~ff.SHHH|$Ht$dH5O#HHHHHRHL ucHJLD$HcI t1I9@uSM@111AH;JuNHD$H[HH9uIfDHZ…tH#H5`H81gHQ}#1H81gH}#H5_H81mgff.fUSHHH|$Ht$cH5 N#HGHHHKHL$H1 tQHcH9Qu]HIE111AH?IuYH5#HߺvGHD$H[]f.HHcЃH9uH막H#H5#_H81fHJ|#1H81~fH|#H5^H81fffDATUHSHH|$Ht$bHD$H umHL`HcH9HH5L#FHHtyH_PHJ tJLھHRtHD$H[]A\@L`HXHw{#H5M^H81eH_{#H5_H81eH{#H5]H81veHvff.SHHcHH|1[UH5L#SHdH%(HD$1EHHHZ1HcUHHpH uTHT$H/jHHct$ t:HCH9:HIfHHL$dH3 %(u>H[]HpfHH `H5(]H=/]HLcjHz#H5\H81KdHz#1H818dAWAVAUATUSH8dH%(HD$(1GHHHD$9H5~#HHD$ UHH|$`HD$H L`HXHH5fJ#H>DIHHJYHcHHH|$ H1ETHD$ LxH tLxHD$E1HD$HcD$HcH@IIH~v@K47LLH@HT$HNMHDASvuHx#1H81b@HL`HFH|$ H uCHL9L dHD$ HL$(dH3 %(uVH8[]A\A]A^A_HGf.H|$ ^H|$ HmHD$ p\ hHw#H5ZH81aH ^H5ZH=ZIHw#H5"ZH81aHv#HH5\H81aHz#H5}ZH81afAWAAVAUATUSHdH%(H$1HD$0H|$ HD$PHD$8Hl$(HD$XA@H|$@Hl$HPHIֹHD$ HD$@LH DHt LcNLHL9tHPD9|HtHHL9u"]1H|$(H|$0AH7H|$8HNHD$H5OG#L'AIHHL$ LA HyHcAH9HIHl$`LDD$HL$JUEHHLd$xATDD$,HL$ Ht$pX1ZA1ILL9B?@LSkHFkH5z#LR@H$dH3%(H[]A\A]A^A_@IHA0@tr=PAEHbx#H5ZH81)lfH[H\$(H u;HHHMNHD$kk]AfDH{uPH[DYHt#H5 WH81^!pHZt#1H81^dHBt#H5YH81q^SdH5HHCH[f.ATUSHHtvHƒtiudHH9t;H5D#H>IHt2H5D#H>HtLHL]u)H[]A\fD^IHt9HC HbH^s#1H81]Hs#H5UH81z]Hs#1H81g]PX1HHs#H81G]SH5D#H=Ht!E1111AH`?uH[H's#H5TUH81\fPXH53UHHr#H81\fHH5C#\=HtHoRHHHDff.HH5AC#=Ht#HFHA% HEH_ff.@SH5B#[HcHD@HN…tHc[HDff.HH5B#\#H8IHHMBH< L|$A@DHcH@IH~FH@LLLHNL1AkuHJm#H5SH81yWfHT$dH3%(HD$uPH([]A\A]A^A_@L`HX+Hl#H5RH81#WHDm#H5qOH81 W]fDATIHUSHt:GH5=#L7Ht-HguH[]A\+UBHl#H5NH81Vf.ATIHUSHt:EGH5,=#L7Ht-HVuH[]A\THCl#H5pNH81 Vf.ATIUHHStbFHH5<#6HHt}H$@Hl: tN1ɉھ HTBt!HcHEDL[]A\DTH8k#H5NH81gUH k#H5uNH81OUHpk#H5MH817UAUIHATUHSHttEH5;#L5IHHJ?H9 t\1ɉھLzAt/HcH5o#LHTO5HH[]A\A]ÐSHPj#H59PH81TH8j#H5OH81gTHj#H5LH81OTff.@ATUSHH5'o#HGEHAHH5:#4HHHD>H8 Ic1DHHHH uGDHW@t\H[]A\HHeHǨt$_DApHHf.QAL1MHi#H5OH81/SHh#H5aMH81SH8i#H5eKH81Rff.@HHg#H|$H0VHt'H|$H59#n3Ht_H=H@H|$IH|$H u0HYHuHk#HT$H5wNH81eRDHH{h#H5JH81BRfUH1H8#SHHf#H8hHSHt+HC E111AHHB4uHH[]Hh#1H81QHg#1H81Qff.fHj#SH5KHH{g#H8 9Hh#HEf#H5JHHH8H!g#H;H5H]H;HH5 HAH;1HH5~JYH;HH5AQAH;1HH5SJ9AH;HjH5hAH;H?H5hAH;H$H5J@H;HYH5T@H;1H1H5I@H;1HH5b@H;HH5R@H;HH5Ig@H;HH5IL@H;HH5{I1@H;HH5iI@H;1H:H5_I?H;HH5SI?H;1HH5DI?H;HH51I?H;HQH5I?H;1H H5 I}?H;1HaH5He?H;HH5HJ? H=H9JH=HHi#!J[Hi#USHH(H-e#dH%(HD$1HD$HuRHH5i#H11HOH|$HD$71HKHHHHT$HZHu9aH3HT$H~rHb#H5JH81Mf.`HHL$dH3 %(H([]DH=EIHHh#7H)b#H5AJH81MH``H b#1H81mMHHm1fH5IHHa#HH81CM>Sff.UH5ISHHc#Hd#H;H4Ha#H;H5"nHHCf#Hc4H-4c#HE7HHhKH}H5IHcHHߺW[H5I]?f.YH3#1nbff.ATUSHHHƒ}HH9t:H5F3#H,IHt.H5/3#H,HteHLDtCH[]A\sHIHC HuHb#H5HH81KHPHab#1H81KHa#H5?IH81uKDUH52#HSH,Ht'HH.1HH*u"HH[]HLa#H5HH81KHa#H5HH81Jff.SHHH|$Ht$5GH51#Hv+HtVHt$H t$HVHvHtmH$_5H<$HtH]CH5&.#H'HtY1HH|&t}H4$Hu.HL$dH3 %(HuxH[]@HFf.HIH+CHC HuHC]#H5vCH81jF@H]#H5CH81CF>Lff.UH1HO-#SHH[#H8 \HBHtHC 1HH%t"HH[]H\#H5BH81EH\#H5 CH81Eff.@SH=EGH=BZH50CHHZ[#H8,H\#HZ#H5BHHH,H\#H;H5H~QH;HH55c5H;HH5;H5H;1H|H5J>05H;Hn\#H5H5H;HHH5<IH;H@H5#BSH;1HH5B4H;1HH5B4H;1[H'H5V4f.fDGAUH5+#ATUSH$H+HIHIj[HHL-x6AH=7f/HHH [HL[%IH{HBHHZH{BHHZCtBv uH=gA*/u3H=?A /gDL.PfDH=rI.4fHL[]A\A]HX#H5@H81Bf.ATUSH dH%(HD$1HӅutHD$1E1HD$H5)#H#H1LHHJHH$HL$dH3 %(H []A\HHT$tCHD$1E1HtH|$59HHD$Ht7H|$9IXDHF1HD$HuHufE1+1;H}X#1H81yAtGHW#H5k?H81\Aff.ATUSH dH%(HD$1HӅHD$1E1HD$H5(#H!H1LHH3HH"H5>HH"HHL$dH3 %(H []A\fHHT$tCHD$1E1HbH|$7HHD$Ht3H|$7I8HF1HD$HuHufE11l:HV#1H81?EHV#H5=H81?ff.AVAUIATUS\EI+HtFHL55'#DL1LUHHH>j18tDHeU#H5<H81\>ff.USHHHl$Ht$H5HHڿHH%#1TH|$HH uWHVLHHtXHE 5uAHGt?LvS#H11Ҿ}6hAHH[]fDHfHVHT#1H81=PXH5|;HHS#H81b=fATH5$#UHSHtHT$HYt$@wKH(4HHL$dH3 %(u+H[]fDHpHH#H5!2H81Z2U8H n2H52H=2fDSHHH|$Ht$u.H5#HHt6Ht$H tHVHvHHH[HHfDSH5#H\HtE1111H;H[ff.ATUSHueHt\HƒtOuJHH9t:H56#HIHt3H5#HHtHLt(H[]A\Hs5H$G#H50H810HdF#H50H810ATIUSHHH|$Ht$-H5#HPHt]LHHt$H t3H~HcωH9u2HvHE1H:HH[]A\HHAyfS1H#FHHt HC H[HE#1H81/@SH\G#H5/HE#HH;KHDE#H;H5/HHI#H(HAG#H5jHH;H;HH5/D#H;HH5d/)#H;HzH5H;HH5&sH;1HWH5u([H;HH5%3@H;H3H5&4H;1HH5.H;1HH5.H;H.H5-3H;[H.H5s&3f.AWAVAUATUHSHXdH%(HD$H1H=I#+HD$QHEH\$ 1ɺIH5I#HD$JH|$P*HD$H8 ,HxHcAH9_H!*HH bHHcAH9/H{)H8I AHHclj|$ H9HD$0=HHD$HH|$8Ht$1H$"1 Ic@HH}HO9L $E1HߺC|LMHE tLMEH߾eCeLL$I kIEH߾-CML$I$ tML$DD$ H߾BQIuIE tIuHT$H~#Ht$L-H+LHL$HdH3 %(HX[]A\A]A^A_HcH|Hu*fH@*HD$HH|$2H|$HHHD$;@HEHxMIH0H=+O&H=+H|F#7&H=%$HlF#&H=0BH\F#&HXF#pHHDH|$$fHD$uJH;H*H=F#H5*1H*H*H=E#H5*1+*H)H=E#H5v*1*H)H=E#H5*1)/H)H=E#H5*1)H)H=pE#H5c*1)HB#H5)H816H=CE#H5)1)DAWAVAUATUHSHHdH%(HD$81H=D#HD$!HEH\$1ɺIH5dD#H$[ Hc%H[%H|$III@#Hl$ @HLd$(AIH\$0HH1IH@I tIFI L$IOIWI0 HIxSIMPjAT+H HT$8dH3%(LHH[]A\A]A^A_HcH|HuJWfL$HIWI0 iIpIxgD 'HD$H H|$RH|$HHHD$K@H= ("H=HB#"H=_HB#"H=:H|B#g"H=U HlB#O"HhB#Hx,H2L%IH$H$IHHDH|$ HD$uJH=&B#H5^'j&e,DAVAUATUHSH@dH%(HD$81H=cA#HD$ SH\$HE1ɺIH5&A#H$= HE"H="H|$H@F$H|$ A@H|$(Hc1IIH@I tIFH HHSH<$H7 HHPMEUZYHT$8dH3%(LH@[]A\A]A^fHcH|Hu:/H|$ A@%T# D$HD$HH|$Z H|$HHHD$q@LGMcDM9H@H{Hc׉H9HSDH=$w H=%HD?#_H=MH4?#GH=X;H$?#/H ?#HHDH|$HD$uL5H=>?#H5$#})ff.fHHI9#H5u$H8b)H:#H5c$HH>#H H=>#HH5@$H># +H=>#HyH5#*H=>#HHfH5$*f. SHHH|$Ht$H5 #H6HtfHt$H t4H~HcωH9u3HvHHxt$HD$H[HH3HW;#1H81"H<8#H5F#H81"UH5D #SHdH%(HD$1H1HH$(HcH1HH@H uQHHH$'~[HH4$ tBHCHSH)H9jH"HHL$dH3 %(unH[]HCf.HHSH6#1H81 !HA7#H5K"H81!H #{H5G"H=O"&@SH5$ #HHH@Hc0~Hx[fDH6#H8t 11[ H9# H=( H 3H H=!3H;A1H !H HS6#H5]!H81 f.UHH5Q#SHHt`HHw0HH$HHtuH[]@c#H1[]H8#H5"!H81H5#H5 H81zf.PX1HH8#H81WATUHSHH*HI H5x#HHHtHLHt H[]A\H5#H5) H81qATUHH5#SyHt-HHI/IH#LH#7t H[]A\H4#H5H81H7#H5 H81gHH5#HtHHt$HHHO4#H5YH81UH5T#SHHt5HHEHHtMHH,H߅t#H[](H3#H5H810H6#1H81ff.SH5#Ht+H#HHt;HHcH9u#H߉[5H`3#H5jH81'H.f.S1HR#2H5,Ht HC H[rfUSH(dH%(HD$1HuGHH|$HD$HD$H0 uFHHx&HHtMH{ eHk HL$dH3 %(HH([]HxHc׉H9u}Hx HHuHD$H u?HHHD$Ht$14HHyH 5#1H81@HPHT$HPº1%@-!ff.H1#SH5QH8!H3#H?0#H5=HHHH4#H;H5iHH4#HH1#H51HH'H;HGH5 k H;1HH5'S H;1HwH5; H;HH5 H;1HH5 H;1HQH5 H;HH5e H;H+H5", H;HPH5# H;1HhH5# H;[H|H5p UH5#SHdH%(HD$1H1HHTHcH1 HH@H uQHHH$"~[HH4$ tBHCHSH)H9jHHHL$dH3 %(unH[]HCf.HHSH 1#1H81@Ha/#H5SH81(H !H5RH=o@WSH5#HdH%(HD$1{HtTIH111`HHHthH4$HdH߅t8"HT$dH3%(uH[H.#H5H81ZU0+H 0#H5H818H/#H5sH81 SH5#HdH%(HD$1HtlHI111%H$10HcHH$HsHcH u,Hx3'HHL$dH3 %(u.H[f.HsH-#H5H81rmff.fSH5#HdH%(HD$1Htl1IH11eH$10HcHH$HsHcH u,Hxs&HHL$dH3 %(u.H[f.HsH,#H5H81ff.fATUSHujHtaHƒtTuOIHH5"HHt=H5"LHt)H Ht4HC HH[]A\HH?,#H51H81H-#H5YH81ff.UH5"SHdH%(HD$1jH1HHtHcH1HH@H uQHHH$B~[HH4$ tBHCHSH)H9jHHHL$dH3 %(unH[]HCf.HHSH,#1H81H!+#H5 H81H !H5H=/@*USHHH(Ht$dH%(HD$1F H|$HD$H5"HHHHD$H tGHPHT$HP1Ht$Ht;HC H5*HHL$dH3 %(u4H([]HHHD$H+#H5YH81H)#H5H81ATUSHuqHthHƒt[uVIHH5"3HHtDH5"LHt0H=,#Hh Ht4HC HW)H[]A\HHX)#H5AH81H*#H5H81UH5d"SHdH%(HD$1H1HHHcH1HH@H uQHHH$~[HH4$ tBHCHSH)H9jHHHL$dH3 %(unH[]HCf.HHSH)#1H81 HA(#H5H81H !}H52H=O@ATUSHuqHthHƒt[uVIHH5"CHHtDH5"L,Ht0H=x&#Hx Ht4HC HH[]A\HHh'#H5H81/H(#H5H81SHdH%(HD$1HtYH$H5J"HH1HjHL$dH3 %(HH[DHH$HtH H5"HHtHH4$H t#H~HcωH9u^HvHHH1 H@&#H5H81H'#1H81j!f.WATUSHuqHthHƒt[uVIHH5"CHHtDH5"L,Ht0H=('#HxHt4HC HH[]A\HHh%#H5H81/H&#H5H81USH(dH%(HD$1Hu|HHD$HtnH5C"H{HHH|$uH|$HD$ HD$H uIHHHD$1Ht$-Ht`HC H, HL$dH3 %(Hu$H([]fHPHT$HP븺10HQ$#H5H81H%#H5H81UH5"SHdH%(HD$1H1HH4HcH1HH@H uQHHH$~[HH4$ tBHCHSH)H9jHHHL$dH3 %(unH[]HCf.HHSH$#1H81 HA##H5H81 H H52H=O@ATUSHuqHthHƒt[uVIHH5h"CHHtDH5T"L,Ht0H=!#HxHt4HC H7H[]A\HHh"#H5H81/ H##H5H81 USH(dH%(HD$1Hu|HHD$HtnH5"H{HHH|$uH|$HD$HD$H uIHHHD$1Ht$Ht`HC HLHL$dH3 %(Hu$H([]fHPHT$HP븺10HQ!#H5 H81 H"#H5 H81 UH5$"SHdH%(HD$1H1HH4HcH1HH@H uQHHH$~[HH4$ tBHCHSH)H9jH HHL$dH3 %(unH[]HCf.HHSH!#1H81 HA #H5 H81 H H52 H=O @AWH5"AVAUATUSHrHHInAŅ~BL=#1HD$@LI?1H*"HrHIH/Ht=IF H|$L A9uHD$H[]A\A]A^A_DHD$H #1H81 H+#H5 H81fATIH5"USHHt?H5z"LHoHtxHIHtPHH Ht H[]A\H#H54 H81zLH+ #H5U H81ZH #H5 H81BHc#H5U H81*f.SHdH%(HD$1HtYH$H5"HH1H HL$dH3 %(HH[DHH$HtHH5"H,HtHH4$H t#H~HcωH9u^HvHHH1HP#H5 H81H#1H81 zf.USH(dH%(HD$1Hu|HHD$HtnH5"H[HHH|$UH|$HD$HD$H uIHHHD$1Ht$-Ht`HC HHL$dH3 %(Hu$H([]fHPHT$HP븺1u H1#H5H81H#H5H81PXH5HH#H81fHH5a"dH%(HD$1LHt/111IHH<$}HT$dH3%(u H^ ff.UHH5"SHHt2H5"HHHt3HHPHH[]H!#H5H81UHH5"SHwHt2H5k"HH`Ht3HHHH[]H#H5H81xH#S1HH "H8THtHX [d@AWH5"AVAUATUSHxdH%(HD$h1HD$H H|$HD$8D$HD$`1HD$HD$XHD$ HD$PHD$(HD$LHD$09l$oH|$GHHtLD$HL$ HHD$`HT$(Ht$0HD$XHD$P(AąxHHIHBLILHIcLHt6zHct$LLHt6hH|$PHtHLIH|$XHtuHL*H|$`HtVHL 6HI AŅ~+E1DHAH9LHE9uLLH|$8L9l$HT$hdH3%(HD$8u'Hx[]A\A]A^A_H1#H5H81H#1H81PXH5HH#H81fH#S1HH"H8HtHX [@USHHH5-"H$HHH5"H HHtMHHt,HH=#H3HtJHH[]PH[]H%#H5H81H #H5H81H#H5KH81ff.PX1HHa#H81S1H2"}HHt HC H[fAUH5c"ATUSHHtTHHHcIIE~(1ېHHLHpA9uHL[]A\A]HH5"dH%(HD$1lHE111HHq xQu4H<$Ht:HL$dH3 %(uHDdH#H5H81LH#H5UH814HU#H5>H81ff.PXH5HH#H81fHH5"Ht!E1111H x$HHHDH#H5H81fHH5"dH%(HD$1HtP111IH& x6H<$Ht!HT$dH3%(uHH8#H5!H81ff.@HH5"dH%(HD$1|HtPE111HH x5H<$Ht SHT$dH3%(uHfD|gH#H5H81_ff.@HH5Q"HtHoHHH6fDS1H"HHt HC H[2fPXH5jHH#H81fAVH5#"AUATUSXHHH HcIIE~FL5#1HLHkHt'HǃLHA9u[L]A\A]A^H#H5H812fUHH5q"SHHt0H5"HHHt1HHHH[]HDH#H5GH81H#H5LH81fS1H"}HHt HC H[fUH5$"SHHtLHH#1H"H8*HHHtHE HH[]@HH[]@HH5"HtHOHHHDff.HH5q"LHtHHc7HHfDS1H2"]HHt HC H[fUHH5a"SHHt0H5"HHHt1HH`HH[]HDH#H5H81DS1H"HHt HC H[fAUATIH5>"UHSHHXdH%(HD$H1HuIHD$HD$0HD$HD$8HD$HD$@CI<$H|$uwHD$HD$uyH|$ HD$ \HD$ H HPHT$(HP1Ht$(BHupH#H5 H81DID$HD$uID$HD$2H|$H%H|$I1HtLHHHtSHE LHHL$HdH3 %(uLHX[]A\A]HHHD$(=jH#H5VH81H#H5H81DHH5"lHtHHHHЃH #H5@H81fDAUATIHUHSHt\?Ht\H5"HIHt]1LH"/ LHHt'HE HH[]A\A]HuE1H#1H81ff.HH5"dH%(HD$1\HtH81H4#H5H81F AUATUSH(dH%(HD$1IսtIH>A1Ht/@rILATH5{"LH11HL$HLD$Ht$H|$HcHcWu1H\$dH3%(Hu\H([]A\A]fLf1HP@?Q:f.;B1H\#H5H81H#H5H81sff.GAVAUATUSH.LfuLLvHH5"HHL%IILALc*H5Y"HHHLE1IHoHLLHHKH5#Hj~[]A\A]A^+[1]A\A]A^LcE1뚺Hs#H5H81:f.GAVAUATUSH.LfuLLvHH5."HHLIILALc*H5"HaHHLE1IH?HLLHHH5l#H:~[]A\A]A^[1]A\A]A^LcE1뚺HC#H5H81 f.AWAVAUATUSHxdH%(HD$h1HD$HD$@HD$ HD$HHD$(HD$PHD$0HD$XHD$8HD$`GHHӹHD$HFHD$ HD$@L@@Ht LcN L HL9tHP9HtHHL9uH5i"HIHH|$1H|$ IH|$0IHH|$8H6H|$(HHHE1ILLML)H5#LxHH\$hdH3%(Hx[]A\A]A^A_f.@tJEH|$8HcHhH|$(HHhHL$HL$IXD봺jH+#H5H81H#1H81f.AWAVAUATUSHxdH%(HD$h1HD$HD$@HD$ HD$HHD$(HD$PHD$0HD$XHD$8HD$`GHHӹHD$HFHD$ HD$@L@@Ht LcN L HL9tHP9HtHHL9uH5y"HIHH|$1H|$ IlH|$0IHH|$8HH|$(HHHE1ILLMLyH5z#LHHH\$hdH3%(Hx[]A\A]A^A_f.@tJH|$8HcHhH|$(HHhHL$HL$IXDk봺:H"H5_H81Hv#1H81f.H}"ATH5USH8H#Hd#H5HHHL%#H;H5H#HI$H-d"H5]HHEqH}HAH5UH}HH59H}HH5SH}H}H5AH}HH51H}1HH5H}1HH5 H}HSH5H}HH5{H}1HH56bI$H;H5H-h#HlHH5HEH}H5^H}HH5H}HH56H}1HH5H}1HH5H}1HH5 H}1H9H5Q}I$H;H5H-"H5|HHEPH}H H54H}HH5mH}HH5H}HH5H}HH5WH}1H'H5H}1HH50H}HH5vH}HFH5ZH}HH5I>H}1HH5%I$H;H5BH-"H5HHEH}HH5xH}HH5H}HpH5iH}1HH5H}1H>H5FrH}1H%H59YH}1HlH5,@H}1HH5'H}1HH5H}1HQH5H}1HH5I$H;H5H-"H5HHEH}HH5/H}HH5wH}H7H5X[H}HH5r?H}1H"H5d&H}1HiH5R H}1HH5JH}1HH5AH}1H^H5H;H5#H;H5H;HH5tH; H5`H;H5#LH;H5*8H;H5Q$H;H5H; H5QH; H5]H;H5H;H5H; H5 H; H5H;H5H;H5#pH;H5\H; H5 HH;H54H;!H5 H;AH5 H;H5H;H5H;H5H;H5H;H5 H;H5H;H5H;H5lH;H5XH;H5DH;[]H5A\,f.fUH5d"SHdH%(HD$1jH1HHHcH1HH@H uQHHH$~[HH4$ tBHCHSH)H9jHHHL$dH3 %(unH[]HCf.HHSH"1H81H!"H5fH81H H5dH=/@AUATUSHHdH%(HD$81HB D$HD$(HD$0HӅSHHD$cHD$E1H|$Ht$0HH}HD$0HHC GH|$0HL$ LHT$LD$(tHt$HH=y"HT$oT$IŅ Ht$ HH= "HT$Ld$H|$KH|$HD$ܵ11LHHHtUHD$HHC 4H5H@H5H,HL$dH3 %(HumH []A\11ҾHLHOHuHH|$H"HC H5H811 ATUSHuoHtfHƒtYuTHH9tDH5"HIHt=H5"HHt)HHt4HC LH[]A\HH:"H5.H81H2"1H81ff.PXH5HH"H81fHH5"\Ht HxHDHH5q",HtH@HxHfHH5"HtH@HxH6HW"H51H81ff.HH5"謪HtH@H8H駵fPX1HH "H81USHHHKH5"HHIHtHH)t"HH[]H"H5ZH81c~ff.S1H2"=HżHt HC H[BfHH5a"輩Ht44HHt:8tHfDHxHH"H5H81fDAUATIUHSHHH!LI&HI˶H5ij"HHHt#HLLHct&HH[]A\A]Hb"H5<H81)D@S1Hb" HէHt HC H[fUH5"SH芨Ht5H}H%HHtMHHH߅t#H[]H"H5H81cH"1H81pff.PXH5zHHt"H81BfSH5"Ht(HxHrt t1[@HC [H@HHHATIUHSHHHHuH5"HtMHLr11話H[]A\ÐH=6HHU"SH5"Ht(HxH蒮t t1[@HC [H@ATIUHSHHXH HuH5"HtMHL"11H[]A\ÐH=vHH"H3HHATIH5 "USHHt"LHvHHKt H[]A\H`"H5TH81'BfHHH두ATIH5"USH覥Ht"LHHHkt H[]A\H"H5H81fHHH두USHHH5}"H4HtKH5"H="HiHHtjH5 "HHtQHHt"HH[]HU"H5H81H$HE"H5+H81H("1H81@ATIHH5"USvHH5v"H="H觻HHH5D"LH2HiL[]A\HHZ"H5YH81H="1H81H"H5H81UHH5"SHwHt$HHHH,t"HH[]H"H5H81SH5$"HtH^twHE1IIHH5"蒞HH聺H)HHHEHLLH߅tn[]A\A]A^DLfHIIIt(LAtEAlDӻAZE1R蔷H`"1H81H="H51H81@AVAUATUSH`dH%(HD$X1HD$Ld$D$ HD$0HD$ HD$@HD$(HD$HGLd$8HHHD$HFHD$u.HD$ HD$(H|$ Hu3ܿI1HFHD$ uHFH|$ HD$(HtIH|$(1Ht@H)"H"1H8LHUH|$Ht$ IIƋD$ LLLDLHHt}Hk HT$HH5蜝H5"L]HHL$XdH3 %(ueH`[]A\A]A^DD譵L%|$ H5("LHY"1H81AWAVAUATUSHhdH %(HL$X1HT$Ld$D$HT$0HT$HT$8HT$ HT$HHT$(HT$PWLd$@rH>H^HVH|$H\$HT$uHD$ HD$(HVHT$ uHF HD$(H1IH|$(IHt@ H9"Hʥ"1H8LHeH|$ IHHt$INjD$ALLLLHHC HT$H5H襛H5H葛LiH5z"LJHHL$XdH3 %(u}Hh[]A\A]A^A_E1n軷 腳L|$dLH5"LH."1H81DAUATUSHHdH%(HD$81HD$H\$HD$ HD$HD$0GH\$(H.Hl$HD$HD$E1H|$HH5 "HHbE1H|$H菮HH DLHHҢLH:HL$8dH3 %(HH[]A\A]HFHD$HH~H|$H>@t]舨H|$A3H5HHD$Hxǟt2H|$H辠IfD˵A11ɾHD@HDEHLHA"1H81NH "H5H81ѶE1fATH"H5L%"USH8I$H"H"H5HHHH"H;H5HHH;H`H5H;HH5H;H H5ΩH=BH;E11ɺHH=4aH;E1HƺH;H5H;HH5{ߥH;HH5ĥH;HH5詥H;1HH5葥H;HbH5ҿvH;1HH5Ŀ^H;1HH5FH;HH5+H;HH5H;1HH5H;HH5qݤH;1HH5gŤH;HVH5W誤H;H+H5L菤H;1HH5BwH;HH54\H;HH5!AH;1HH5)H;HH5H;HH52H;HH5ݣH;HNH5k£H;1HvH5&誣H;HH5:脸H;1H(H5P|I$H;H5]虚H-"H;H5RHHEH}H.H5H}1H3H5עH}1HZH5Ľ辢I$H;H5ۙH-"H5HHE葾H}HqH5ʢuH}1HH5\H}1HoH5CH}1H&H5J*H;H5>H;H5H; H5H;H5H;!H5qH;AH5uH;H5˼H;H5zH;H5fH;[]H5A\Nf.@HH=<dH%(HD$1HT$rHcD$HL$dH3 %(uH賶HHf׿USHHHt8~ttA=uJHH[]̗@u3HH[]eDHH[]rfHH[]fHA"H"1H81H5HX HHБHH[]H"H5jH81讯ff.H"SHH0IHuH[H"H5!H81gSH"1MHUHtHC H1H5a+H[H"1H81AUATAHUSHdH%(HD$1ՓHÅu4CHL$dH3 %(H[]A\A]DIc1HHTIHcվLHTH="HT$LD$xC1DC1H=8SZ$@G@SHHH=~HdH%(HD$1HT$耙T$uHL$dH3 %(uH[H |$謳ff.ATUSHdH%(HD$1G,HH$t\"HI跖1HHHHtBHHHL$dH3 %(H[]A\DH~f.11ҾH菿蚰L1HH"覦HHu11ҾH]h1HnHH`11ҾH1<1HLH%"HHMH*H"H5H81L蝦8USHH(dH%(HD$1HHH裙~@t=uHHtIHD$dH3%(H([]Du1HT$HHH<$tH|$uH"H5\H81jf.1Ht$HAH|$u1Ht$H聑H|$]H"H5H81fDAUATUSHHH5"HT$H $芋H7HI覯HH|$IHD$H HXHcH9H#HH1LH H4$H HHH?Ht$H uoHHLȝHnu*赭H1[]A\A]HH@u)H[]A\A]HVHvtHvHK"H5۶H81蚩H"H5H81rHH"H5nH81bH躶H"H5`H81BH蚶Hӿ"H5RH81"fHH5"載HtHH#"H5H81ڵf.SH5"11H8HuH5k"HcHt[H"H5H81蔨H"H5H81lff.AUATUSHH(HT$dH%(HD$1ճHI芖H|$I荤L1Hc H賤H1LHH蚇Ht$H tuHVHvHՙtnHuHE tHuLHHT$?HAEt\t$H#HHL$dH3 %(uUH([]A\A]DHHH軴H"H5H81CHܽ"H5H81+&H~H"H5nH81H"H5H81ff.SH5"HtHH诓H[Hۼ"H5H81蒳fUH5dSHHp"H8萬H"H-2"H5HHHE܍H"H}H5HH"H踍Hy"H}HH5HH;H5SH;1HWH5;H;HlH5 H;HH5H=C9H"-XH[]ȧUSH8H5"dH%(HD$(1 HCHHLHeHL$HT$HHHHT$ Ht$H[覙H<$H芆H=H֐HHHH|$^H=H誐HHH輐H|$2H=H~HHH萐H|$H=aHRHHHdH|$ څH==H&HHH8HHL$(dH3 %(uH8[]H/"H5H81H"H5ƱH81٣fAUIATU1SHHt$H$Ht H|$褈H1H<$t H萈HH56"L.IHHuwL荮IHtH=HHt5HtH(HHt HHL肬t`HL[]A\A]H記1衘H"1H81H"H5ðH81֢H"H5ïH81讯HVHNHG"H5H81薢fDAVIAUATE1USH Ht$HT$HL$Ht H|$[I1H|$t H|$DH1H|$t H|$-HH5Ӹ"L˂IHH跏L&IMtL֖IHtOHtHHHtH_"H5H81&HG"H5H81H~H~H"H5H81fDAVIAUATE1USH Ht$HT$HL$Ht H|$mI1H|$t H|$mH1H|$t H|$}mHH5#"LiIHHvtL薁IMtL&}IHtOHtH}HHt"HŅtRIEH$uI}HlqHHu-H>"1H81jf.H$HHھtHPHL$dH3 %(LH[]A\A]fDuHt tSf.tH<$H蟋HH$3iHt"H1HIpHHt4L茒WH~HH< 11ҾL111Ll{HHu11ҾL1LdHHt11ҾL跑‚1L^HHH11ҾL苑薂E1E11H="LH5HcLH蝑Hd_Hp"H5H81~1x脄H"H5qH81\Hff.@ATH"I1US;HCgHtVLtHH+}t'Hk H1H58|`H[]A\f.H16H[]A\fD1H[]A\ff.UHSHH5\"W^HHHCktuiHvH="H5`"HpuHH5Ht HHHtH[]fH踃H"1H81%}HF"H5H81 }H."H5H81DPXH5ƋHH"H81|fSHH5p"dH%(HD$1[]HtIHHKjtuVHu1HHqoH<$HHЃHL$dH3 %(uH[H~"H5JH815@Kff.SHH5В"dH%(HD$1\Ht_HHituJH>uH1HnH<$Ht c]HL$dH3 %(uH[D謁Hȑ"H5H81ff.@SHH5 "dH%(HD$1 \Ht_HHhtuJHtH1H!nH<$Ht \HL$dH3 %(uH[DH"H5H81χff.@SHH5p"dH%(HD$1[[Ht_HHKhtuJHsH11HH<$Ht\HT$dH3%(uH[LWHh"H54H81ff.@SHH5"dH%(HD$1ZHt_HHgtuJH.sH11H_H<$HtQ[HL$dH3 %(uH[H"H5H81off.@SHH5"dH%(HD$1YHt_HHftuJH~rH11H诅H<$HtZHT$dH3%(uH[~H"H5ԅH81迅ff.@AVIAUATUHSHH5Q"dH%(HD$1AuMfHt%芎LHlIf.A1tHknHHtz1HLjH<$tOHL "1HATE1LHOZYt8HHL$dH3 %(uaH[]A\A]A^@LHeuHiHJ"1H81vw1qH"H5UH81@K}Hl"H5H813wUHHSHt+gHHt+HHHtH[]kudHHuHT}H"1H81vUHSHH5\"dH%(HD$1GWHtxHH7dtucHo1HH]iH<$t&HL$dH3 %(u-H[]f.H5jtHAH1Hu|*H;"H5H81fATIUSH0Ht$H5"dH%(HD$(1VHeHHlct9Hn11HT$HH'H|$Hl$ 1HHihH|$ H|$qH[`1HcAfIHHH tHHHt$H tXH~HcljH9Hv1IIWt$ LvLHL$(dH3 %(uOH0[]A\DHHH5rLɄHBHp"H5H81tzHS"H5H81ztH"H5KH81btH"H5OH81:ŅH"1H812tfUSHHtQHҊ"HH"1H8HHatuaHk 1H5rHUHt4HH[]f苋HtHHt"H8dHHi"1H81sH"H5H81}sff.fSH"H5H"HH;ZH "H;H5HHx"HZHى"HHH5HfH;HH5c8cH;HH5icH;1HH5QcH;1HH57bH;1H!H5XtbH;HH5bH;HH5 twH;HH54j~wH;1H"H5J_vbH;1HZH5p^bH;HH5CbH;HH5(bH;1H\H5WbH;1HH5aH;1HH5aH;1HH5taH;1HMvH2t"H5pH811_HRu"H5ypH81_H:u"H5lH81kHjx"H5nH81^fUSHHt$H5zu"u?HHHaL=H~HH|$Hu#1HY`w5HD$H[]H|$fCHHH(`u$HtH8s"H5pH817^uHD$H[]H@t"H5goH81^H(t"H5jH81jff.@UHSHH5|t"w>HtOHHgK=HGH5mJ"HHB>HtJHHRKu"HH[]Hs"H5`jH81KjHDr"H5>oH81C]Htq"H5!mH81+]HLs"H5snH81]AUIATIUSHH-s"H=HtsHHJHLz=HHtMHjJ=HFHRHHtZH¾H[t&HL[]A\A]Hr"H5biH81MiH=H>q"H5knH81=\H&q"H5HnH81%\HFr"H5mmH81 \Hp"H5nH81[DUSHHSs"H|$H0_HtIH|$H5H"pAH<$uM~HHp"H0x^HH<$L:HHHG=HCHOHHtYH꾘H YHL$dH3 %(LH[]A\A]A^A_fDH${;HHuHn"1H81YH q"H<$H0]HLH9r"tH9r"t%H9q"u#[D[f[Hn"HH5kH81Uff.AWAVAUATIH5A"UHSH,6HH5lq"HHFH5*B"H6HHL.E11HL=n"HAMIIHtMH1EMIHHH u*MDHHyIHtHL[]A\A]A^A_fHHH3n"H5;gH81THh"H5dH81THn"H5\dH81TfUH5@"SHH5Ht@H5[p"HHEH5A"H4HtJHH!>u"HH[]Hm"H5cH81 THk"H5fH81SH#h"H5cH81Sf.UH54@"SHHg4HtJH5o"HHDH5i@"HA4HtTHml"HHHWEu"HH[]Hl"H5*cH81PSHIj"H5eH818SHig"H5cH81 SUH5?"SHH3HtJH5n"HH DH5?"H3HtTHk"HHHju"HH[]H!l"H5zbH81RHi"H5MeH81RHf"H5fbH81pRPXH5SbHHf"H81RRfUH5>"HSH2HtpH5+n"HHPCH5>"H2HtEHH8tuH[]@H1[]Hh"H5dH81QRH+k"H5aH81Qf.UH5d>"SH:2Ht7H-NHGHHtOH1HKH߅t#H[][He"H5,aH816QdHbe"1H81QHOe"H5aH81QfDHH5="1HtH\HHHD^ff.UH5="SHZ1HtAHH*7HHt"HVHH[H]iAfH[]ff.@UHH5="SH0HtHHH߉LHH[]ff.HH5<"0HtgH.t*tEt0Hc"H5HfH81OfDH=k"Hp_H=k"H`_H=k"HP_ ff.USHH50<"H0Ht3HHuMHX[HH[]fD@f.HH5;"/HtHJHHHDnff.HH5;"l/HtHKaHHfUSHHtQHBU"HHpU"1H8THH[,=u_Hk 1H5<H Ht2HH[]; HtHHT"H8HHAS"1H81E>HR"H5QH81->ff.fAUH5QATUSHHR"HT"H;Hr%HR"H;H5bQHHU"HO%L% W"H9T"H5>QHI$H+%H-U"I$H5#QH;HE %L-T"H}H5-L%tT"IUI$$HQ"I<$H5-HIU$HV"H=PHLH=PH]Y"LH=PLH=PH6Y"LH=PHY"~LH=PHY"kLH=P_LH=PHX"LLH=PHX"9LH;H5pPHX"SH;H5aPSH;1HNH5N20H;HsH5J0H;HHH5,|,H;H H52a,H;1HH5PI,H;H H5O.,H;1HH5:,H;HH5O+H;1HH5w:+H;HH5S=+H;1HH}1HH5L)H}HPH5L)H}1HH5kL)H}1HH5H81>HV'HN'HGH"H5HH811fDAVIAUATE1USH Ht$HT$HL$Ht H|$[I1H|$t H|$DH1H|$t H|$-HH5G"LIHHLIMtL%IHtOHtH%HHtH9t(H=QK"H\$@H3>H9H|$HH5oE"LIdIHH|$LHD$*L*$+HHHT$1Ht$8MH%H|$8E1_H|$8E1=H|$81MHt$(H HVHvHHt$ H \HHH/!D1H:1HL$xdH3 %(HĈ[]A\A]A^A_@'fHHZH|$@@AED[,HD$8HtH|$8HT$8uHtHHDHD$8 XHT$_@H=,'HHH"[AuMnHt%?LHIf.A1%HHHHT$Ht$LH|$tUH|$tMHL >"1HAUE1LHm1ZYt6H3HL$dH3 %(u_H []A\A]A^fLHuH;H"B"1H81(1"H>"H5u5H81`5k.H>"H5e?H81S(USHH5>"HtHHuWH H$HmHHt$H1H(AH߅t H[]&2:HZA"1H81'H="H5>H81'H="H54H814ff.AUIATIUSHH-%>"HHttHH HLHHtNHuqHH5n<"H=w<"HHt6HH¾&HL[]A\A]H="H53H813HU@"H5/H81&H<"H5=H81&H%@"H5%>H81&@SHHOHWwH?C 1[ff.AWAAVAUATUHSHHdH%(HD$81D$ HD$I$IMMI 1Mu@tXHsL,uL>LE1q7L>HL$8dH3 %(LHH[]A\A]A^A_kH\$H5<"LH!|$Ll$Ld$D|$ Lt$(t|H>"Ht$HH=L.>L6>T$0aL6D$ uLE1ID$rLE16L=L=LLDLD$0i(|$ >*ff.ATHG;"I1US:H HtVLHH{#t'Hk H1H5"RH[]A\f.H13H[]A\fD1H[]A\ff.UHSHH5:"Ht}HHuUHHR8HHH11H_2H<$HtHT$dH3%(uH[L(Hh8"H54/H81/ff.@SHH58"dH%(HD$1Ht_HHuJHH11H1H<$HtQHL$dH3 %(uH['GH7"H5.H81o.ff.@SHH58"dH%(HD$1Ht_HHuJHH11H0H<$HtHT$dH3%(uH[&H7"H5-H81-ff.@SHH5`7"dH%(HD$1KHt_HH;uJH.H1HH<$Ht HL$dH3 %(uH[D<&HX6"H5$-H81-ff.@SHH56"dH%(HD$1Ht_HH uJH~H1H1H<$Ht CHL$dH3 %(uH[D%7H5"H5t,H81_,ff.@SHH56"dH%(HD$1Ht_HH uJHH11H6H<$HtHT$dH3%(uH[$H4"H5+H81+ff.@SHH5P5"dH%(HD$1;Ht_HH+ uJHH11HO6H<$HtHL$dH3 %(uH[,$HH4"H5+H81*ff.@SHH54"dH%(HD$1Ht_HH{ uJHnH11H5H<$Ht1HT$dH3%(uH[|#'H3"H5d*H81O*ff.@UHSH(H53"dH%(HD$1H|HH HHT$Ht$H`H|$t(H|$tHL$dH3 %(uAH([]@H5H,HHEH2"H5)H81z)"0GATUSHL&tALAtN. HމHHtNHHHt>[]A\H^HttAHLAuHމHHuH-H_5"1H81HHdAUIATAHUSH(H5B2"dH%(HD$1-HHH WH11Ht$HH43H|$AD$IEHD$AAH|$gH/1Hc HHPH tHPHD$H8 }HHpHcH9EH{)HcH(HHL$dH3 %(H([]A\A]fDI}@t&A AHfHpHxfDA"DH3"H51H81 H*0"H51H81H0"H5&H81&T+HM3"1H81ff.AUIATAHUSH(H5B0"dH%(HD$1-HHHWH11Ht$HH41H|$AD$IEHD$AAH|$gH/ 1Hc HHPH tHPHD$H8 }HHpHcH9EHHcH(HHL$dH3 %(H([]A\A]fDI}@t&A AHfHpHxfDA"DH1"H5/H81 H*."H5/H81H."H5$H81$T)HM1"1H81ff.AUIATIUHSH8H5@."dH%(HD$(1+HHHH11Ht$HH2/H|$|HT$ Ht$H H|$H|$ EIEAHD$uI}@AH|$,H 1HcHHPH tHPHD$H8 HpHxHcH9EHHcHHHL$(dH3 %(H8[]A\A]fDH5bL9&HH/"H5-H81HHpfkA 2H+"H5"H81"H3/"H5K-H81H+"H5,H81'H."1H81rmff.fAUIATIUHSH8H5+"dH%(HD$(1HHHH11Ht$HH,H|$|HT$ Ht$HDH|$H|$ EIEAHD$uI}@iAH|$H1HcZHHPH tHPHD$H8 HpHxHcH9EHC HcHHHL$(dH3 %(H8[]A\A]fDH5L#HHH-"H5o+H81HHpfA  H)"H5o H81Z H,"H5*H81RHs)"H5L*H81:$H,"1H81"ff.fAUIATIUSHHH5)"dH%(HD$1HHŅuRH$5 HHھHHL$dH3 %(L|H[]A\A]IEH$tH)fuHt fDH<$HHH$cH'"H1HIHHL$!I}tHe@tEHHVHH5HHH+"1H81vfDHH$ƒ11ҾL#111LyHHM11ҾL#1L= HH!11ҾL#1LHH11ҾLd#o111LAHH11ҾL4#?1L!LHZ#HH)"H5H81Yf1һH1 HM&"H5H81H!~fAWAVAUATIUHSHHdH%(HD$81H=,"HD$FI$ID$LD$ 1ɺH5+"HD$H=+"Ll$ H;AI9t)H=+"Ll$ H+AI9H|$(}HIHIHHcHT$WH|$IZ Ht$1H HH1Ht$MLHUH|$E1PZH|$E1D-7H|$1M Ht$H HVHvH1HuHE tHuHT$H)Ht$HHKHHL$8dH3 %(HH[]A\A]A^A_DHcI|HuB7HHWH|$ @\A=@ HD$HH|$H|$HHHD$I$yH= AYHH?)"I9\@H=$'HH)"X H=$ H= $H("H(" ADHHDH|$fHD$uHH%"1H81" ff.fUSHHtQHz#"HH""1H8!HHuaHk 1H5 HHt4HH[]f+HtHH#"H8HH%"1H81u H"H5-#H81] ff.fSH!"H5#H"HH;H$"H;H5"HHX""HH""HuHH5yHH;HH5mH;H)H5H;1HqH51H;1H9H5H;1H!H58 H;HfH5H;HH5 tH;HH5^H;1HH5*VH;1HH5>H;H/H5!#H;HH5!H;HH5!H;H.H5!H;HsH5!H;HXH5v!H;1H@H5H;1HxH5lH;1HH5TH;1HH5H5 H;HH5 H;HH5 H;HH5 H;1[HH5x UHSHdH%(HD$1HHHHHHHHHtHt$HHHcHt6WHct$HHt6EHT$dH3%(u HH[] fDAUIATUSH(H_DgdH%(HD$1" IHD$L9s,DHkHHHKH|$HI9wH5!"I}HL$H|$HD$HD$H u3HHHw*HL$dH3 %(uH([]A\A]@HPH=>!"H51H9 u!HHHHcH9u:1fDHAHyHPff.fUHSHH5" HtsHHxH[]H5"HYH1HhHHHuHuH=_ "H5H"H5H81ff.H"1ff.ATUSHHHƒtwurHHH5@!HI0 LH%Ht/@tHHLKH[]A\H8HLT#H[]A\HSATUSHujH.HH5!hIHtaH"HH0]HH5"HtX11HtsHLHH[]A\fH5I!HI1LHH[]A\@H=o11HHH"yuHLHBH[]A\ú1>H"H5H81fDUSHH5!HWHtHHH1ɾ*jHH[]HHUSHH5P!HHtHHH1ɾ,HH[]HHHH5!1ɺ!HHff.AT1USHHdH%(HD$1D$rHt\5"HH\ILHHHHHHT$HH=AHcT$u!1HL$dH3 %(u*H[]A\fDH5y"HTLATIH=TUHSHH0dH%(HD$(1HT$ Ht$Ht$LD$DL$ jHƋD$ uOH u/HHHuHL$(dH3 %(uTH0[]A\DHVHUVf.5"L"HcT$ H5"HHT=ff.fAVEAUIATIUHH5"SHL6EMLHHH[]A\A]A^AVEAUIATIUHH5R"SHLEMLHHH[]A\A]A^HH|$ H|$1H5"HHtH5"HL$HHf.SHH|$h H|$1lH5"HHt511HaHtH5<"HL$HBH[@H=#HH="ff.SHH|$ H|$1H5"HHt511HHtH5"HL$HH[@H==#wHH"ff.ATI5E"UHS1H=nHH1Ht IHT "H8HHH] LHH HH HT$HH={HD$dH3%(urH[]A\DL%i " H=I $I $#H=z I<$1AH H\ff.@ATUHSHHdH%(HD$1H' "D$H85s"HIH"H8uHHH] lLHH^ HHS HT$HH=oHcT$u&1HL$dH3 %(H[]A\H5"HTL,f.L% " H=I $I $ H=: uI<$1AH NHAWAVIH5!AUATUHSHHIčEI>MnHD$HHƒ*LILIIHMLLE1tdLLILLvMt1LXLHtJHH[]A\A]A^A_IFHD$#fH|$IH9H5 "LyH="H5 1H "H5 H81lH "H5H81TH5U "L%H="H51@H51 "LH="H5{1ff.HH5!HDHHHDAUATUHSHdH%(HD$1HxHEƒf]HHtNIAu HucIH$LH5M!HLHHH/HL$dH3 %(HH[]A\A]Du11L%} H$HpDHI9LH-uHttwH(H<$HH t$HHHL9I uHCfHSHL9~H<$LrHDI1HH$H= "H5 AUH5!ATUSHHHtaHH.HcICIE~01fHHKLHD9uHL[]A\A]DH[]A\A]fATH5S!US H11ɾHH H@HLdH= "H`LHH11ɾHH@HLdH= "H|LHH11ɾHH@HeLdH=q "HKLHH}11ɾHHt$HHT$ t$ t H|$HL$dH3 %(u H(tff.@H(H5!dH%(HD$1,Ht>Ht$HHT$ t$ t H|$>HL$dH3 %(u H(/ff.@HH5Y!dH%(HD$1Ht@1HmHHt H<$HHt$dH34%(Hu Hrff.fPX11HH="f.USHHHt$H5!HtN1H|$Ht H|$H1Ҿ7HdHt8HT$H5s"HHD$H[]H0!H5H81RfHH5)!HtHoHH~ff.HH5!LHtHHHHD>ff.UHSHH5!Ht1H5!HHHtGHHu"HH[]HB!H5H81 H=r"H581H!H5H81ff.HH5 !lHtHHHHЃYfHH5!,HtHHHHDff.USHH5!HtfHHHHH8uHH[]f.H5H HDHH9HH[]f.HH5!\Ht)HHtHH.fDH9fHH5! HtHHHff.AUATUSHH5c!Ht}HHHtYHIHcI^IE~+1@HÿH;LH0D9uHL[]A\A]DHA[L]A\A]Off.@USHH5!HtDHHHt%HHHHH[]HH[]ff.HH5I!Ht)HHtHHNfDHfSH5!_Ht6HH?x Hw[+[/ff.@ATIUSHHH?dH%(HD$1 HHcH9woHt$L@l$HsH u-HLHL$dH3 %(u&H[]A\@Hsf.H{H= !H511@uHt t@HH5!4HHff.fAVAUATIUSHH0Ht$H|$dH%(HD$(1_H5@!H蠾HtH5@!HH1HILhLHT Ht$H>H HHcljH9t`HHHHƉK~0u[LMA}x@u@HcHDHT$(dH3%(H0[]A\A]A^u6H=E!H51H~)Hv8Mt{H!H1H=HD$HLHL$Ld$HD$@@LMA}}fHI!Htd1H={VHD$HLHL$HD$Wf1 fH==HH!%H=HH!|H!pH!dH!H50H81[Vff.ATIUHSHdH%(HD$1H$7HuLHL$dH3 %(H[]A\HcH|Hu tH H$Ht9HYH<$HuHt7H$t@HHDH$H$uEIf1DAWAVIAUATIUHSHH5b!H$褺H5E!H襺H>H5E!HH HLhLH1AH5!HAHEDH~~1LxMA}&@u+D$ L$ uH߉L$ tH\L$ H$IDH=g!H51fu&Hŋt H<$@HDEH$H=!I1H5(LMA}>fHHHHHIHKHDMLDHHhATIٹUD1H5HT$H=e!H-!HH[]A\A]A^A_H-!H$uH$HǨt$H!H5kH81 %DUHSHdH%(HD$1H$~uHcH|HuGuOH$HH5}!HHHHL$dH3 %(uXH[]@KH$Hu11FfDt@H耾H<$HHDH$off.SH#H5!H1H[Jf.UHSHdH%(HD$1H$~uHcH|HuGuOH$HH5}!HHHHL$dH3 %(uXH[]@;H$Hu116fDt@HpH<$HHDH$off.SHH5!H1H[:f.USHHdH%(HD$1tuHD$dH3%(uZH[]@5V!HH5[!HH$'H5!HHtH53!HH;@SHHt$@urHtiHƒt\uWH5z!5H|$HHL$H t*HI1Ҿ\H7HtHD$H[HUSHH5!HǴH5!HH赴Ht#HHվHEH[]H!H5wH81DUSHHH5!HTHH91ҾHHgHt HH[]U1HR!SHXHHHt6H1ɺ!H H] HHߋ5\!wHH[]H=v!H5v1USH@uYHtPHƒtCu>HH5!fHHu&HHH[]fkfUSHH5`!HH5!HHHt#HHEHEH[]HN!H5H81DAWAVAUATUSHH|$HtH[]A\A]A^A_@@ H|$H-! L|$H="M'MwMIA AMt*IWIw脼HthH}MuLLH1[]A\A]A^A_Hg tA@ t N襹HD$?H !LH5oH81DSH[]A\A]A^A_@HcH!HDfATUHSHH5{!6HIkHa1HcӾ{L=Ht!1Hcվ|L&Ht[]A\H=!H5$H=!H5AWIAVAUAATUSHHdH%(HD$81HD$0tH.AHD$H@GH|$LcG1L{HD$H@u-Ht$HƒsHd@1AH5!LIHgH5!LL= @HH$H@HHD$LHt$H qHLLƉIcL>fHcLtIt 'H.HFHD$H@H|$LcH|$H|$H HL9NH|$@H|$HcHD$HL$8dH3 %(#HH[]A\A]A^A_GnH.tHD$AHFAHD$@LH)H|$HG;HvEHh!H1H=yHD$H<$HHL$ Hl$ HD$(Lt$0of.HDLH4$$H4$HIHD$8ZH!H1H=HD$H<$HHL$ Hl$ HD$(mHyL.fL+E`HD$xDLhE_HD$xDH|$H4$bSH4$IHD$Hu.MLt$H.fMLDLt$D H=HHM!H=_HH%!`AH!H!H=B!H51H!H5|H81"H.1贫"Rf1EDAUATUSHdH%(HD$1@HHHƒH5!蝪H5HH+H5!HH, H5!HH$HtH诸HIH衾LH5R!H誺H$Ht&H5!HPIL11HjH5#!HE1hH$Ht HIH5!HDH$HtKHIMt;Ht6LHc LH'v HS H5!HH$HHHуE1CHI9HJH;E1HvH=ճH;E1HM H=謳H;E1H$H=胳H;E1HH=ZH;E1HH=1H;E1HH=H;E1HH=߲H;E1HWH=趲H;E1Hƺ.H=!H5vH=uH;E1H H=TLH;E1H H=#H;E1HH=H;E1HrH=ѱH;E1HƺIH;HSH5蓻H;HH5}H;HH5H;1HH5lZH;HH5?H;H H5$H;1HH5 H;HH5|H;1HuH5t٥H;HjH5k辥H;1HH5V覥H;HGH5F耺H;H59lH;H57XH;H58DH;H590H;H58H;H5mH;H5H;H5H;HH5դH;HFH5躤H;1H>H5袤H;HӴH5臤H;1HH5oH;HPH5TH;1HH5HHL [H]A\@H5Q!Ht$H11(HuH8HH=ߞHH !H!H5H81kff.AUATIUSHH-з!dH%(HD$1HHHLHɃHHtuHHfHt$HIVHI蛚H葚9t1HL$dH3 %(u*H[]A\A]Ë$;T$uLL|H蜨GH!H51H81ff.@USHH@udHt[HƒtNuIHH5!Hk ߂HtLH5c!H=Ժ!HHtHC HCHH[]HaH=z!H5ޡH!H5xH81ơfDUSHH57!ZHt5HMHHHtOHHBH߅t#H[]鰫H!H5 H81X3H=ܿ!H51>H=ǿ!H51)fHm!SH5HH!H8{Hl!H!H5{HHHXH;H5HW!H;HSH5LH;H(H5xܐH;HH5ȗH;1HeH57詐H;HH5莐H;1HrH5vH;HH5[H;1HH5CH;1HgH5+H;1HH5H;1[HH5}f.UHHSH(dH%(HD$1H\$HT$ H螥t$ H1H͑HL$dH3 %(uH([]AH!SH5HH85H޵!Hv1謉g"m~X#H;H5H;H5H H;H5H; H5@H; H5TϵH; H5h軵H;H5a觵H;H5j蓵H;H5rH;H5wkH;H5zWH;H5~CH;H5 /H;H5 H;H54H;!H5HH;#H50ߴH;%H5H˴H;'H5\跴H;)H5h裴H;+H5|菴H;-H5{H;/H5gH;1H5SH;3H5?H;5H5+H;7H5H;9H5H;;H5H;=H5۳H;?H5dzH;AH5賳H;eH5蟳H; H5苳H;H5wH;!H5cH;AH5OH;H5;H;H5'H;H5H;H5H;H5H;H5ײH; H5òH;@H5诲H;H5蛲H;H5臲H; H5sH;@H5_H;H5KH;H57H;H5#H; H5H; H5H; H5H;H5ӱH;H5迱H;H5諱H;H5藱H;H5胱H;H5oH; H5[H; H5GH; H53H;H5H;H5 6H^H;H5HWH?H;H5HͰH H;H5H记YHH;H5H菰 HH;H5Hp;xH×H;H5}[HPWUH5!SHdH%(HD$1yH1HH贔Hc1袉HH@H uRHHH$胔~\HH4$ tCHCHSH)H9kHHHL$dH3 %(uoH[]ÐHCf.HHSH!1H81 HA!H5H81H (H5H=O@AUH5!ATUSH(dH%(HD$1fxHIeHHYL1xAŅ~%LHH蘟A9u1H}Hc17HH@H Ht$HHD$|HHt$ ttHCHSH)H9H耘HH5!H\$Ht_H!HL$H8.HL$dH3 %(H([]A\A]HHSHCLH=跑HH!HsHī!1H81@H!H5H81(HI!H5H81H yH5H=W}ff.AWAVAUIHATUSHH!Ht$H3ԙHH5T!HH|$HǨH5"!HH|$蕆HŃHÃHykH5܃!LuIHHvLmSfHH9LHoH!H5nH81fUHH5ar!SHcHt$HH'HH\t"HH[]H?!H5H81!HH5r!cHtHHt$HHnH!H5H81趂UHH5q!SHGcHt+HH观HHHH豒HH[]fHH5aq!bHtH_HH3iff.AWAVAUATUSHHHIHIHI5HIHH蟚HMMAWLHHH=[1H[]A\A]A^A_ff.fUH5p!SH*bHt=H~HwHHtUH%gHH0mH߅t#H[]xHY!H5(H81 H!1H81#ATIUSHt=HHHx\H5o!LaHt0HH蓅tH[]A\H8HH!H5H81膀H!H5ԲH81nff.HH5ao!`Ht3HsH@HxHDHfDHHff.@UH5o!SH`Ht5H|H5vHHtMHH肎H߅t#H[]Hѕ!H5H81sH,!1H81ff.UH5tn!SH `Ht5H{HuHHtMHH2mH߅t#H[]`HA!H5H81H!1H81~ ff.ATUSH dH%(HD$1HB HD$HuIH>Ld$H|$[H|$HD$g11LHHzHT$HS Ht$HDHL$dH3 %(HubH []A\11ҾHאLHHIHD$HC MuH!1H81}1Oxf.UHHl!1SHH#!H8軓HHt#H;aHtHC HH[]{H"!1H81v}fDHH5ql! ^HtHHs!H5BH81:}f.SH54l!]HtHHo}H[H+!H5H81|fSH\!H5OH!HH;KdHd!H;H5=HH!H(dH!H5HH߈H;HH5mlH;HH5EslH;1HH5eilH;1HH5}ylH;H}H5 tSH;1HH5}KlH;1HH53lH;HH5\lH;1H,H5MlH;1HDH5&kH;HH5.kH;1HqH5kH;HH5 kH;1HH5kH;HH5gkH;1HH5ѭOkH;H H54kH;1HH5kH;H-H5kH;1HH5}yjH;H*H5Y|jH;HH5jH;HH5jH;HyH5*}jH;1HH5~ejH;HH5JjH;HH5/jH;1HH5xjH;[HGH5qif.gAWAVAUIATUHSH1LeH赉:HH9}TL5U!LI6H!H5H81UvHm Hp!H5rH817vAUH5e!ATUSHVHHIBHJŅxTHc\XIŅt11LރHTHlLH(9uHL[]A\A]fDHy!H8tH[]A\A]${@H! H=aH 萈H H=wH;A1H H`ZHC!H5EH81 uf.UH5dd!SHdH%(HD$1UHtoH}qH%kHHtDH1H0tH$HH0q`H߅t~HL$dH3 %(u7H[]YHJ!1H81ftH!H5H81NtIzfATUSHurHtiHƒt\uWHH9tGH5vc!HTIHt@H5_c!HTHt,H誆HHt4L|Hk H[]A\H&xH׉!H5٦H81sHo!1H81sff.PX1HHI!H81gsS1Hb!MHQHt HC H[fUHH5b!SHSHt)HH'HHUt"HH[]H !H5 H81rLff.AUH5#b!ATUSHVSHHI蒊ŅxLHcTIŅt)1L;|H3\LHȉ9uHL[]A\A]fDH!H8tH[]A\A]w@H! H=]H 0H H=eH;A1H ?H]$WH!H5H81qf.UH5a!SH:RHt5H-nHgHHtMHH~H߅t#H[]{Hq!H5sH818qH!1H81 qff.UH5t`!SHQHt5HmHEgHHtMHHrZH߅t#H[]{H!H5H81p胃Ht!1H81p ff.UH5_!SHQHt5H mHfHHtMHHvH߅t#H[]pzHQ!H5SH81pH!1H81p{ff.PXH5HH!H81ofUHH51_!SHgPHt[HH7HH|tHHaQtuH[]@#sH1[]H;!1H81WobfAUIH5^!ATIUSHHOHt6LHzLIb]LHHDt&HH[]A\A]H!H5H81nUDATUHH5/^!SiOHt-HHOHHI;ltHOH[]A\LPHK!H5H81bnfATUHH5]!SNHt/H1H'fHHI dLt}PH[]A\ kPH܃!H5H81mHH5Q]!NHt)H}HtHHnofDHfATUHH5\!S9NHt/H1HgeHHInLtOH[]A\`OH!H5۠H813mHH5\!MHt)H迂HtHHnfDHfUHH5A\!SHwMHt$HHtHH Mt"HH[]H!H5H81lHH5[!MHtHolHHX^ff.ATIUSHt=HHHx\H5[!LLHt0HHhtH[]A\HxqH^H!H5H81kH!H5H81kff.HH5[!Ld$H|$vH|$HD$LT11LHHJXHT$HS Ht$H}HL$dH3 %(HubH []A\11ҾH7}BnLH~HIHD$HC S}MuH?!1H81[j1dJpf.HH5Y!JHtHHC!H5EH81 jf.UHHaY!1SHH+!H8HHt#H|HtHC HH[]KHHz!1H81ifDSH!H53H6!HH;PH<!H;H5aHH!HPH!H5HHuH;HH5YdYH;HH5_IYH;1HMH51YH;HH5ZYH;1HH5KXH;1H"H5mXH;HH5EXH;1H?H5'XH;HH5XH;1HLH5llXH;HH5eXH;1HH5DkMXH;HH5̛2XH;HH5XH;HhH5_yWH;HH5pWH;1HH5TWH;1H]H5-iWH;HiH5A_lH;1HH5iWH;1HgH5kkWH;H|H5PWH;[HH54W@YUH5V!SHdH%(HD$1ZGH1HHGHcH1qWHH@H uQHHH$Gx[HH4$ tBHCHSH)H9jHgHHL$dH3 %(unH[]HCf.HHSHTz!1H81eH|!H5H81eH H5H=gMk@UH5U!SHJFHtZH-RHHMu.)bH[HHtFHH.QHH[]owH[H]cH\{!H58H81#eHty!1H81eSHHt$H5+U!EHH|$HpH|$HD$1aHYJHt$H t,H~HcωH9u+HvHut HD$H[HHuHx!H5H81fdHz!H5cH81Ndff.ATUSHujHtaHƒtTuOIHH58T!DHHt=H5$T!LDHt)HRHt4HC HVH[]A\H.hHy!H5H81cHw!H5H81cff.AUATUSH(dH%(HD$1GHHH$HFHD$zH^H~ZH|$_HlH<$H 9H@kAąu%H<$H XHOiAą\HHNH=HDVaHt$HHD$SH|$YH5cR!H;CHH#Hz!HR!1H8gxHH5Ֆ1IcrHt H\HHHDHL$H HDHHoHC0HIpGMMe LHT$dH3%(H([]A\A]ÐHHYH|$^1HIvH[Hu!H$H5˕H81\aH}w!H5LH81DaHL$Hu!H5H$H81#agff.gH5#KTff.UH5Q!SHAHtqH}]H%WHHtF11HHMtHH[]j@H FHHUHH[]jHt!1H81d`Hv!H5aH81L`ff.HH5aP!@HtHoJHHHЃH/v!H5 H81_fDUSHHt$H5 P!@HtBH|$HW1H_HHtXHHHH߅t)kHD$H[]Hu!H5H81v_akHs!H5H81Y_Hs!H5דH81A_PXH55HHTu!H81"_fATIUSHH5N!?Ht)HLH5H@HuHE H[]A\ATIUSHH5N!f?Ht)HLH5[H@HNHEH[]A\CATIUSHH5;N!?Ht)HLH5HL@HjHEH[]A\ATIUSHH5M!>Ht)HLH5H?HjHEH[]A\SHHPdH%(HD$H1HD$HHD$(HD$HD$0HD$HT$ HD$8HD$ 1L@ &Ht LcN L HI9tH9HtHHI9uH4$HtHHt$HtHHt$HtHAHt$HtHHH\$HdH3%(uHP[ú19Wb@U1HL!SHrx8H5ʐH_NHt9HHE1E1111#PH] HH5k>HH[]Hr!H5DH81I\fAUATIH5^L!UHSHHXdH%(HD$H1Hn!H5HHcH;HcH5H 3fH H=fH;A_1H ؈H>'8gHk!1H81RHh!H5H81RXfATIH5C!US-3HttH OHHHHtI1LHHfxMut H[]A\w\HeHj!H5CH81RHj!1H81RH%h!H5݇H81Qff.SAH1H߉oVH[f.USHHHHcjH;HHHH[H51]Hff.ATUSHujHtaHƒtTuOIHH5A!1HHt=H5A!L1Ht)H\Ht4HC HRH[]A\HNUHf!H5H81PHi!H5H81Pff.AUATIH5A!UHSHH8dH%(HD$(11HD$Ht|M,$LGHHH5o!H=He!H83IHL1jdH5n!IHLp11H:HL$(dH3 %(H"H8[]A\A]fLMd$cGHHtIuaL@[H|$ HD$ KHT$ H tnHBHRHD$Ht$H|$H;HT$HU HbHg!1H81#OH=?HD$ZJLL$HHm!HHHT$H늾H=% JHHm!1IHd!H5H81NTfDS1H?!}dH:Ht HC H[H0g!1H81TN@PXH5.HHdd!H812NfUHH5>!SH.Ht(H5>!HH.Ht)HHH[]ZHd!H5ǃH81MHHxHHHHHfUHSHHHH~b!H0QHu H1[]HH5¸uH[]SHt"H6Ht@t[HHH[H5=!H-Htb11HIHHtfHhAHcH9unHH߉[dHHT$JHT$HH[H1GHb!H5{H81LHSe!H5H81rLH]f.HH50Hl$ HAD$HuLHtwH|$ {HHD$HCHD$H=~CHH-g!IHHDH|$ ADcBHD$ ~AH`!H5Z~H81GHHD$HCHD$M*YH]!H5}H81GHHD$HCHD$ff.ATUH1SHHH0dH%(HD$(1NHINHHtW1HzNHHD$hNHHD$VNHD$ Ht;Ht$L9HL$(dH3 %(H0[]A\HD$H5e!HL$HHD$GHD$ HuH5[e!HtHg[!H87*HD$ rDH=|AHHe!6LfDUHH6!1SHH [!H8 \HHt#HQHtHC HH[]+2H^!1H81EfDHH5A6!\&HtHH[!H5{{H81Ef.UH=|SHTH#\!H5 |Hed!H\!H;H,H ^!H;H5 |HH^!H,H ^!H Z!HH2H/H;H5jEQH;HFH55*5H;HkH5;5H;HH5`{4H;HEH5<4H;1HH57{4H;1HH5bC4H;1HH524H;HbH5s;v4H;Hd;H5X;PIH;HaH5F;E4H;1HH5O[-4H;1HqH5z4H;1H H503H;H54zZ48HH*H=Cc/'HHs/ H=)zB/'HHR/ H={!/'HH1/ H=y/'HH/H=y.-HH.H=y.-HH. H=y.H-H.H;HH5xYH;H5 pYH;/"H5ryYH;?H5fyYH;H H[H5Uy]uYD:AWAVAUIATUHSH1LeHER:HH9}TL5Z!LI6HHU!H57vH81>H vH52vH=@&D@ATUSHurHtiHƒt\uWHH9tGH5f/!HIHt@H5O/!HHt,HFHHt4L6Hk H[]A\HBHGT!H5muH81>HoV!1H81=ff.PX1HHIV!H81=UHH5.!SHgHt$HHOHH 8t"HH[]HS!H5tH81v=AUH5S.!ATUSHHHI?ŅxLHcIŅt)1LFHGLHxT9uHL[]A\A]fDHR!H8tH[]A\A]tB@HQU! H=h(H OH H=pOH;Ac1H sHL(!HR!H5sH81ZHHQ!H5pH81;9H\O!H5pH81#9HQ!H5qkH81 9ff.UH5)!SHHt5H5H5/HHtMHHLd$H|$+CH|$HD$ 11LHHNHT$HS Ht$HJHL$dH3 %(HubH []A\11ҾHI:LHG+HIHD$HC IMuH?O!1H81611D!1H81+f.SHLC!H5H[+:SHHH5Fbi H[@ATE1UHSHHt$HtH'H|$ IH57!H HHtQBHH7+Ht)E1LH u HH[]A\Hb>!1H81(H>!H5aH81(ff.ATE1UHSHHt$HtH&H|$IH5w!H HHtQB'HHw*Ht)E1LHJu HH[]A\H=!1H81(H'>!H5`H81'ff.H]=!S1HHx!H8=HtHX [H=!H5`H81'ff.fPXH5`HH=!H81r'fHH5! HtH9HHHDff.ATIHUHS/t6HHH5!LHt)HH1>H[]A\Hh,H>ff.USHH5`!HWHt3HHu%H HH[]fDSf.ATUHSHt-IIH5!HHt LH-H[]A\H+I~ff.HH5!Ht)HHtHHfDH)fHH5Q!LHtH HH ff.HH5! HtH/HHHDff.HH5!HtH_7Hc1HH#ffDAUH5!ATUSHHH5HHt}H8AąxNHcIEt+1@H{H LH;D9uHL[]A\A]DH9:!H8t+H[]A\A])@HA[L]A\A]@H!H,$HT$HD$HH5!HH8 HGH5FH`/H5FHH>H5O>!H11H HIH5hXHHHH5S(HHHH5;XHHLHL$dH3 %(u}H []A\D;VfDHFH= HH=!H='HHm=!"<$ff.AWAVAUATUSHXdH%(HD$H1HD$HD$0HD$ HD$8HD$(HD$@G5H.HHl$uHD$ HD$(HFHD$ uHFHD$(H5R!HJIHH5!H/IHLd$ 1It L HH|$(E1HtHT$HT$ILLL(H5UH%-Ht HHH5DH-H5xDHHLH5DHHHL$HdH3 %(upHX[]A\A]A^A_úH2!H5UH81H2!H5XUH81pH5a5!L1.H1!1H81NI"fATIHUSHt2 H5 !LHt H H[]A\DsZf.ATIHUSHt2 H5l !LdHt HuH[]A\Df.ATIHUSHt2E H5l !LHt HH[]A\Df.ATIHUSHt2 H5 !LHt HH[]A\DS:f.AVAUATUSH@dH%(HD$81HHLl$ILHH=T$IƅHt$ LLd$ HH=Lt$0HЃHD$(HŋD$IF HH^,tN1HL$8dH3 %(H@[]A\A]A^.H=OT1X"H,uH߉D$ ;D$ D.H=7T1"[1HdgATUSH58!H HtHډ[H]A\#D%Q8!HHD~ Huɉ[]A\fHH5 !HtHH/!H5QH81f.ATE1E11UHR1S7!E1E111HQ7!H-/!H/!H5RH}HL%1!H}H5QH-!HI$H-!H=?H'H;E11ɺH#H=GQy'H;E11ɺH#H=+!X'H;E11ɺH#H= Q7'H;E11Hƺr#H;H5x#H;HH5 H;H5Ey,H;H:H5QH;HH5PsH;HH5PXH;HH5P=H;H^H5y@"H;H#H5PH;HHH5PH;1HH5PH;H%H5{PH;HH5v!H;H_H5I$H}H5:PH+!H5!HHV"H;HH5;H;H5 *H;1H0H5H;1HH5OH;1H0H5NH;HH5OH;1H=H5H;1HH5xOH;1HH5lOH;1H%H5aOiH;HH5NNH;HH5N3H;HH5NH;[]HH5R>A\H,!H5kOH81H,!H5NH81yHHOSSL_DEBUG: empty sk!ossl.c [%s:%d] items in sk < -1???inlen <= LONG_MAX / 20123456789abcdef(null)error on stack: %s (%s)error on stack: %sTurning on FIPS mode failedTurning off FIPS mode failedOPENSSL_init_sslOpenSSL2.1.2OPENSSL_VERSIONOPENSSL_LIBRARY_VERSIONOPENSSL_VERSION_NUMBEROPENSSL_FIPSfips_modefips_mode=OpenSSLErrordebugdebug=errorsto_derpassed data is not valid String???password must not be longer than %d bytesobject in array not of class ##type##OpenSSL 1.1.1k FIPS 25 Mar 2021ossl_bin2hexinvalid OBJECT ID %li OBJ_obj2txt%2d%2d%2d%2d%2d%2dZbad UTCTIME format: "%s"%4d%2d%2d%2d%2d%2dZunknown time formatutcASN1_INTEGER is NULL!invalid tag classtag number not specifiedossl_asn1.cto_aArrayillegal EOC octets in valuemust specify tag numberinvalid tagging methodvalue is too shortinvalid length for BOOLEANinvalid BOOLEAN/%nil expectedunsupported ASN.1 typeASN1_TYPE alloc failurei2d_ASN1_TYPEp0 - p1 == alllenASN1_get_objectEOCUNIVERSALCONTEXT_SPECIFICAPPLICATIONPRIVATEIMPLICIT@value@tag@tagging@tag_class@indefinite_length@unused_bitsASN1ASN1Errortraversedecodedecode_allUNIVERSAL_TAG_NAMEASN1Datainfinite_lengthindefinite_length=infinite_length=initializePrimitiveConstructiveeachBooleanIntegerEnumeratedBitStringOctetStringUTF8StringNumericStringPrintableStringT61StringVideotexStringIA5StringGraphicStringISO64StringGeneralStringUniversalStringBMPStringNullObjectIdUTCTimeGeneralizedTimeSequenceEndOfContentregistersnlnoidshort_namelong_nameINTEGERBIT_STRINGOCTET_STRINGNULLOBJECT_DESCRIPTOREXTERNALREALENUMERATEDEMBEDDED_PDVUTF8STRINGRELATIVE_OID[UNIVERSAL 14][UNIVERSAL 15]SEQUENCESETNUMERICSTRINGPRINTABLESTRINGT61STRINGVIDEOTEXSTRINGIA5STRINGUTCTIMEGENERALIZEDTIMEGRAPHICSTRINGISO64STRINGGENERALSTRINGUNIVERSALSTRINGCHARACTER_STRINGBMPSTRING|X4XWTYYXXYYYWYYYYYYYYYYYYVVc``aaabccc`caccc b baaaaaXb`aaaacaossl_asn1prim_to_derto_der_internalbad GENERALIZEDTIME format: "%s"explicit tagging of unknown tagp - (unsigned char *)RSTRING_PTR(str) == total_lengthindefinite length for primitive valueType mismatch. Bytes read: %ld Bytes available: %ldType mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ldCan't convert nil into IntegerCan't convert nil into Booleanunused_bits for a bitstring value must be in the range 0 to 7indefinite length form cannot be used with primitive encodingBIO_new_mem_bufBN wasn't initialized!BN_bn2binossl_bn.cBN_dupBN_bin2bnbignum too longinvalid radix %dDon't know how to coerceCannot init BN_CTXBNErrorinitialize_copynum_bytesnum_bits+@-@+-mod_addmod_submod_mulmod_sqr**mod_expgcd<=>ucmpeql?===zero?one?odd?negative?pseudo_randpseudo_rand_rangegenerate_primeprime?prime_fasttest?set_bit!clear_bit!bit_set?mask_bits!<<>>lshift!rshift!to_sto_ito_intto_bnmod_inverseOpenSSL/BNCannot convert into OpenSSL::BNCipher already initialized!Cipher not initialized!iv must be %d byteskey must be %d bytesunable to set AEAD tagossl_cipher.cout_len <= RSTRING_LEN(str)key not setdata must not be emptyout_len < RSTRING_LEN(str)cipher does not support AEADunable to set IV lengthCipherErrorciphersresetpkcs5_keyivgenfinalauth_data=auth_tag=auth_tagauth_tag_len=authenticated?key_len=key_leniv=iv_len=iv_lenblock_sizepadding=auth_tag_lenkey_setOpenSSL/Cipherunsupported cipher algorithm (%li )authentication tag not supported by this cipherdata too big to make output buffer: %ld bytessalt must be an 8-octet stringiterations must be a positive integerarguments for %li #encrypt and %li #decrypt were deprecated; use %li #pkcs5_keyivgen to derive key and IVAEAD not supported by this ciphercouldn't set additional authenticated dataunable to set authentication tag lengthretrieving the authentication tag failedunsupported cipher algorithm: %li ossl_cipher_updateossl_cipher_finalOpenSSL for Rubywrong argument (%li )! (Expected kind of %li )wrong config formaterror in line %dConfigErrorDEFAULT_CONFIG_FILEossl_config.cEVP_MD_CTX_newDigest initialization failed.EVP_DigestUpdateEVP_DigestFinal_exDigest initialization failedDigest::ClassDigestErrorfinishdigest_lengthblock_lengthOpenSSL/DigestDigest CTX wasn't initialized!Unsupported digest algorithm (%li ).ENGINE wasn't initialized.NUMERICNO_INPUTprivateopensslOPENSSL_init_crypto#<%li id="%s" name="%s">no such digest `%li 'no such cipher `%li 'EngineErrorloadcleanupenginesby_idcipherload_private_keyload_public_keyset_defaultctrl_cmdcmdsinspectMETHOD_RSAMETHOD_DSAMETHOD_DHMETHOD_RANDMETHOD_CIPHERSMETHOD_DIGESTSMETHOD_ALLMETHOD_NONEOpenSSL/Engineno such builtin loader for `%li 'HMAC_CTX_newHMAC_CTX_copyHMAC wasn't initializedossl_hmac.cbuf_len <= EVP_MAX_MD_SIZEHMACErrorhexdigestOpenSSL/HMACossl_hmac_digestlength must be non-negativeEVP_PKEY_CTX_new_idEVP_PKEY_derive_initEVP_PKEY_CTX_set_hkdf_mdEVP_PKEY_CTX_set_hkdf_saltEVP_PKEY_CTX_set_hkdf_keyEVP_PKEY_CTX_set_hkdf_infoEVP_PKEY_deriveEVP_PBE_scryptiterationsPKCS5_PBKDF2_HMACKDFKDFErrorpbkdf2_hmachkdfSPKI wasn't initialized!ossl_ns_spki.cnewlen <= lenChallenge.length <= 0?NETSCAPE_SPKI_verifyNETSCAPE_SPKI_set_pubkeyNetscapeSPKIErrorto_pemto_textpublic_key=challengechallenge=OpenSSL/NETSCAPE_SPKIossl_spki_to_derCert ID wasn't initialized!ossl_ocsp.cBIO_newi2a_ASN1_OBJECTOCSP_CERTID_dupd2i_OCSP_SINGLERESPASN1_item_dupResponse wasn't initialized!Request wasn't initialized!d2i_OCSP_BASICRESPd2i_OCSP_RESPONSEOCSP_request_add0_idd2i_OCSP_REQUESTOCSP_single_get0_statuscertificate is not revokedd2i_OCSP_CERTIDOCSP_cert_to_idOCSPOCSPErrorRequestadd_noncecheck_nonceadd_certidsigned?createstatus_stringbasicBasicResponsecopy_nonceadd_statusresponsesfind_responseSingleResponsecheck_validitycert_statusthis_updatenext_updaterevocation_timerevocation_reasonextensionsCertificateIdcmp_issuerserialissuer_name_hashissuer_key_hashhash_algorithmRESPONSE_STATUS_INTERNALERRORREVOKED_STATUS_NOSTATUSRESPONSE_STATUS_SIGREQUIREDRESPONSE_STATUS_SUCCESSFULRESPONSE_STATUS_TRYLATERREVOKED_STATUS_CACOMPROMISEREVOKED_STATUS_KEYCOMPROMISEREVOKED_STATUS_REMOVEFROMCRLREVOKED_STATUS_SUPERSEDEDRESPONSE_STATUS_UNAUTHORIZEDREVOKED_STATUS_UNSPECIFIEDNOCERTSNOINTERNNOSIGSNOCHAINNOVERIFYNOEXPLICITNOCASIGNNODELEGATEDNOCHECKSTRUSTOTHERNOTIMEV_CERTSTATUS_GOODV_CERTSTATUS_REVOKEDV_CERTSTATUS_UNKNOWNV_RESPID_NAMEV_RESPID_KEYOpenSSL/OCSP/CERTIDOpenSSL/OCSP/SINGLERESPOpenSSL/OCSP/BASICRESPOpenSSL/OCSP/RESPONSEOpenSSL/OCSP/REQUESTSingleResponse wasn't initialized!RESPONSE_STATUS_MALFORMEDREQUESTREVOKED_STATUS_AFFILIATIONCHANGEDREVOKED_STATUS_CERTIFICATEHOLDREVOKED_STATUS_CESSATIONOFOPERATIONossl_ocspreq_to_derossl_ocspres_to_derossl_ocspbres_to_derossl_ocspsres_to_derossl_ocspcid_to_derPKCS12 wasn't initialized.ossl_pkcs12.cPKCS12_parse@key@certificate@ca_certsASN1_dupUnknown PBE algorithm %li PKCS12ErrorOpenSSL/PKCS12ossl_pkcs12_to_derPKCS7 wasn't initialized.ossl_pkcs7.c@dataPKCS7_verify@error_stringNegative number of recipient!Negative number of signers!signedencryptedenvelopedsignedAndEnvelopedCould not parse the PKCS7PKCS7ri wasn't initialized.PKCS7si wasn't initialized.Could not add recipient.Could not add signer.must specify a booleanunknown type "%li "PKCS7Errorread_smimewrite_smimetype=detached=detacheddetached?cipher=add_signersignersadd_recipientrecipientsadd_certificatecertificates=certificatesadd_crlcrls=crlsadd_dataSignerInfoSignersigned_timeRecipientInfoenc_keyTEXTDETACHEDBINARYNOATTRNOSMIMECAPOpenSSL/PKCS7/RECIP_INFOOpenSSL/PKCS7/SIGNER_INFOOpenSSL/PKCS7OpenSSL::PKCS7#get_signer_info == NULL!signeddatasignedAndEnvelopedenvelopedencrypteddigestossl_pkcs7_to_derpkey is emptyCould not parse PKeyparameters missingpublic key missingPKEY wasn't initialized!EVP_VerifyInit_exEVP_VerifyUpdateEVP_VerifyFinalPrivate key is needed.EVP_SignInit_exEVP_SignUpdateEVP_SignFinalPKeyErrorprivate?OpenSSL/EVP_PKEYOpenSSL::PKey::PKey can't be instantiated directlyTHIS IS NOT A DH!qpub_keypriv_keyDH_set0_keyDH_set0_pqgincomplete DHDH already initializedDHparams_dupossl_pkey_dh.cFailed to generate keyNot a DH key!DHErrorgeneratepublic?exportparams_ok?generate_key!set_pqgset_keyossl_dh_to_derTHIS IS NOT A DSA!DSA_set0_keyDSA_set0_pqgDSA already initializedossl_pkey_dsa.cDSA PUBLIC KEYNeither PUB key nor PRIV keyincomplete DSAPrivate DSA key needed!Not a DSA key!DSAErrorsyssignsysverifyossl_dsa_to_derEC_POINT is not initializedEC_GROUP is not initializedEC_POINT_is_on_curveEC::Point already initializedEC_POINT_dupEC_POINT already initializedinvalid second argumentEC_POINT_newEC_POINT_bn2pointEC_POINT_oct2pointBIO_new(BIO_s_mem())EC_GROUP_set_seedEC_GROUP_newEC_GROUP_dupunknown curve name (%li )unable to create curve (%li )EC_GROUP_new_by_GF*wrong number of argumentsTHIS IS NOT A EC PKEY!EC_KEY_printoutlen=%dECDSA_verifyPrivate EC key needed!ECDSA_signECDH_compute_keyEC_KEY_set_public_keyEC_KEY_set_private_keyEC_KEY_set_groupEC already initializedEC_KEY_dupEVP_PKEY_assign_EC_KEYinvalid curve nameEC_KEY already initializedEC_get_builtin_curvesEC_POINT_point2octEC_POINT_set_to_infinityEC_POINT_invertEC_POINT_make_affineEC_POINT_is_at_infinityEC_GROUP_get_cofactorEC_GROUP_get_orderEC_GROUP_set_generatorEC::Group already initializedEC_KEY_check_keyEC_KEY_generate_keyNot a EC key!ECErrorECGroupPointGFpGF2mGFp_simpleGFp_montGFp_nistGF2m_simpleuncompressedhybridNAMED_CURVEEXPLICIT_CURVEgroup=private_key=private_key?public_key?dh_compute_keydsa_sign_asn1dsa_verify_asn1curve_nameasn1_flagasn1_flag=point_conversion_formpoint_conversion_form=seed=degreeinfinity?on_curve?make_affine!invert!set_to_infinity!to_octet_string@groupOpenSSL/EC_POINTOpenSSL/ec_groupEC_GROUP is already initializedunknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simpleunknown symbol, must be :GFp or :GF2munknown argument, must be :GFp or :GF2mcan't export - no public key setcan't export - EC_KEY_check_key failedunsupported point conversion form %+li (expected :compressed, :uncompressed, or :hybrid)unsupported point conversion form: %d, this module should be updatedbns must be 1 longer than points; see the documentationTHIS IS NOT A RSA!dmp1dmq1iqmpRSA_set0_crt_paramsRSA_set0_factorsRSA_set0_keysalt_lengthmgf1_hashautoossl_pkey_rsa.cRSA already initializedincomplete RSAprivate key needed.maxNot a RSA key!RSAErrorpublic_encryptpublic_decryptprivate_encryptprivate_decryptsign_pssverify_pssset_factorsset_crt_paramsPKCS1_PADDINGSSLV23_PADDINGNO_PADDINGPKCS1_OAEP_PADDINGossl_rsa_to_derRAND_bytesRAND_bytes is not supportedRandomRandomErrorrandom_addload_random_filewrite_random_filerandom_bytesstatus?Selected protocol name must have length 1..255verify_hostname requires hostname to be setSSL SESSION get callback enteredSSL Session wasn't initialized.SSL SESSION remove callback enteredSSL SESSION new callback enteredcertificate does not contain public keyAdvertised protocol must have length 1..255SSL session is not started yet.%s SYSCALL returned=%d errno=%d state=%s%s returned=%d errno=%d state=%s: %s (%s)%s returned=%d errno=%d state=%sOpenSSL does not support tmp_ecdh_callback; use #ecdh_curves= insteadSSL NPN advertise callback addedSSL ALPN select callback addedSSL_CTX_set_session_id_contextSSL SESSION get callback addedSSL SESSION new callback addedSSL SESSION remove callback addedSSL TLSEXT servername callback addedservername_cb must return an OpenSSL::SSL::SSLContext object or nilSESSION_CACHE_NO_INTERNAL_LOOKUPSESSION_CACHE_NO_INTERNAL_STOREOP_DONT_INSERT_EMPTY_FRAGMENTSOP_NO_SESSION_RESUMPTION_ON_RENEGOTIATIONOP_ALLOW_UNSAFE_LEGACY_RENEGOTIATIONOP_NETSCAPE_REUSE_CIPHER_CHANGE_BUGOP_SSLREF2_REUSE_CERT_TYPE_BUGOP_NETSCAPE_DEMO_CIPHER_CHANGE_BUGSSL is not initializedSSL_set_fdarg must be Time or nilverify_certificate_identityossl_ssl.cpublic key mismatchSSL_CTX_use_certificateSSL_CTX_use_PrivateKeySSL_CTX_set0_chain:SSL_CTX_set_cipher_listcache_numconnect_goodconnect_renegotiateaccept_goodaccept_renegotiatecache_hitscb_hitscache_missescache_fulltimeoutswrite would blockread would blockSSL_set_sessionSSL_writesyswriteSSL_acceptSSL_connectSSL_CTX_newSSL2unrecognized version %+li SSL_CTX_set_min_proto_versionSSL_CTX_set_max_proto_versionSSL_readsysreadSSL_CTX_check_private_keySSL_CTX_add_client_CAcan't set verify locationsSSL NPN select callback addedSSL_CTX_set_alpn_protosSSL ALPN values addedSSL already initializednonblock=callcallback_stateossl_ssl_ex_vcb_idxSSL_get_ex_new_indexossl_ssl_ex_ptr_idxossl_sslctx_ex_ptr_idxSSL_CTX_get_ex_new_indexExtConfigSSLErrorWaitReadableSSLErrorWaitWritableSSLContextHAVE_TLSEXT_HOST_NAMEssl_timeoutssl_timeout=set_minmax_proto_versionciphers=ecdh_curves=security_levelsecurity_level=enable_fallback_scsvsetupfreezeSESSION_CACHE_OFFSESSION_CACHE_CLIENTSESSION_CACHE_SERVERSESSION_CACHE_BOTHSESSION_CACHE_NO_AUTO_CLEARSESSION_CACHE_NO_INTERNALsession_addsession_removesession_cache_modesession_cache_mode=session_cache_sizesession_cache_size=session_cache_statsflush_sessionsoptionsoptions=SSLSocketOPENSSL_NO_SOCKconnect_nonblockaccept_nonblocksysread_nonblocksyswrite_nonblockstoppeer_certpeer_cert_chainssl_versionpendingsession_reused?session=verify_resulthostname=tmp_keyalpn_protocolnpn_protocolVERIFY_NONEVERIFY_PEERVERIFY_FAIL_IF_NO_PEER_CERTVERIFY_CLIENT_ONCEOP_ALLOP_LEGACY_SERVER_CONNECTOP_TLSEXT_PADDINGOP_SAFARI_ECDHE_ECDSA_BUGOP_ALLOW_NO_DHE_KEXOP_NO_TICKETOP_NO_COMPRESSIONOP_NO_ENCRYPT_THEN_MACOP_CIPHER_SERVER_PREFERENCEOP_TLS_ROLLBACK_BUGOP_NO_RENEGOTIATIONOP_CRYPTOPRO_TLSEXT_BUGOP_NO_SSLv3OP_NO_TLSv1OP_NO_TLSv1_1OP_NO_TLSv1_2OP_NO_TLSv1_3OP_MICROSOFT_SESS_ID_BUGOP_NETSCAPE_CHALLENGE_BUGOP_MICROSOFT_BIG_SSLV3_BUFFEROP_MSIE_SSLV2_RSA_PADDINGOP_SSLEAY_080_CLIENT_DH_BUGOP_TLS_D5_BUGOP_TLS_BLOCK_PADDING_BUGOP_SINGLE_ECDH_USEOP_SINGLE_DH_USEOP_EPHEMERAL_RSAOP_NO_SSLv2OP_PKCS1_CHECK_1OP_PKCS1_CHECK_2OP_NETSCAPE_CA_DN_BUGSSL2_VERSIONSSL3_VERSIONTLS1_VERSIONTLS1_1_VERSIONTLS1_2_VERSIONTLS1_3_VERSIONexceptionwait_readablewait_writabletmp_dh_callbacknpn_protocols_encoded@cert_store@ca_file@ca_path@verify_mode@verify_depth@verify_callback@client_ca@renegotiation_cb@cert@extra_chain_cert@client_cert_cb@tmp_ecdh_callback@timeout@session_id_context@session_get_cb@session_new_cb@session_remove_cb@npn_select_cb@npn_protocols@alpn_protocols@alpn_select_cb@servername_cb@verify_hostname@io@context@hostnameSSL3TLS1TLS1_1TLS1_2TLS1_3OpenSSL/SSLOpenSSL/SSL/CTX3  3 SSL Session already initializedi2d_SSL_SESSIONossl_ssl_session.cno session availableunknown typeBIO_s_mem()SSL_SESSION_print()SessionErrortime=OpenSSL/SSL/Sessionossl_ssl_session_to_derV_OKV_ERR_UNABLE_TO_GET_CRLV_ERR_CERT_SIGNATURE_FAILUREV_ERR_CRL_SIGNATURE_FAILUREV_ERR_CERT_NOT_YET_VALIDV_ERR_CERT_HAS_EXPIREDV_ERR_CRL_NOT_YET_VALIDV_ERR_CRL_HAS_EXPIREDV_ERR_OUT_OF_MEMV_ERR_CERT_CHAIN_TOO_LONGV_ERR_CERT_REVOKEDV_ERR_INVALID_CAV_ERR_PATH_LENGTH_EXCEEDEDV_ERR_INVALID_PURPOSEV_ERR_CERT_UNTRUSTEDV_ERR_CERT_REJECTEDV_ERR_SUBJECT_ISSUER_MISMATCHV_ERR_AKID_SKID_MISMATCHV_ERR_KEYUSAGE_NO_CERTSIGNV_FLAG_CRL_CHECKV_FLAG_CRL_CHECK_ALLV_FLAG_IGNORE_CRITICALV_FLAG_X509_STRICTV_FLAG_ALLOW_PROXY_CERTSV_FLAG_POLICY_CHECKV_FLAG_EXPLICIT_POLICYV_FLAG_INHIBIT_ANYV_FLAG_INHIBIT_MAPV_FLAG_NOTIFY_POLICYV_FLAG_EXTENDED_CRL_SUPPORTV_FLAG_USE_DELTASV_FLAG_CHECK_SS_SIGNATUREV_FLAG_TRUSTED_FIRSTV_FLAG_NO_ALT_CHAINSV_FLAG_NO_CHECK_TIMEPURPOSE_SSL_CLIENTPURPOSE_SSL_SERVERPURPOSE_NS_SSL_SERVERPURPOSE_SMIME_SIGNPURPOSE_SMIME_ENCRYPTPURPOSE_CRL_SIGNPURPOSE_ANYPURPOSE_OCSP_HELPERPURPOSE_TIMESTAMP_SIGNTRUST_COMPATTRUST_SSL_CLIENTTRUST_SSL_SERVERTRUST_EMAILTRUST_OBJECT_SIGNTRUST_OCSP_SIGNTRUST_OCSP_REQUESTTRUST_TSADEFAULT_CERT_AREADEFAULT_CERT_DIRDEFAULT_CERT_FILEDEFAULT_CERT_DIR_ENVDEFAULT_CERT_FILE_ENVDEFAULT_PRIVATE_DIRV_ERR_UNABLE_TO_GET_ISSUER_CERTV_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATUREV_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATUREV_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEYV_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELDV_ERR_ERROR_IN_CERT_NOT_AFTER_FIELDV_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELDV_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELDV_ERR_DEPTH_ZERO_SELF_SIGNED_CERTV_ERR_SELF_SIGNED_CERT_IN_CHAINV_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLYV_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATUREV_ERR_AKID_ISSUER_SERIAL_MISMATCHV_ERR_APPLICATION_VERIFICATIONATTR wasn't initialized!ossl_x509attr.csk_newargument must be ASN1::SetASN1::Set has non-array valueX509_ATTRIBUTE_dupX509_ATTRIBUTE_set1_objectoid=value=AttributeErrorAttributeOpenSSL/X509/ATTRIBUTEossl_x509attr_get_valueossl_x509attr_to_der#<%li : subject=%+li , issuer=%+li , serial=%+li , not_before=%+li , not_after=%+li >CERT wasn't initialized!ossl_x509cert.cX509_set_pubkeyX509_set_notAfterX509_set_notBeforeversion must be >= 0!CertificateErrorCertificateversion=signature_algorithmserial=subjectsubject=issuer=not_beforenot_before=not_afternot_after=extensions=add_extensionOpenSSL/X509ossl_x509_to_derCRL wasn't initialized!X509_CRL_add0_revokednum < 0???ossl_x509crl.ccount < 0???X509_CRL_set_nextUpdateX509_CRL_set_lastUpdateCRLErrorlast_updatelast_update=next_update=revoked=add_revokedOpenSSL/X509/CRLEXT wasn't initialized!ossl_x509ext.cASN1_OCTET_STRING_setX509_EXTENSION_dupcritical,unknown OID `%li '@config%li = %li OBJ_txt2objX509_EXTENSION_set_object@crl@subject_request@subject_certificate@issuer_certificateCTX wasn't allocated!critical=ExtensionErrorExtensionFactoryissuer_certificate=subject_certificate=subject_request=crl=create_extExtensioncritical?OpenSSL/X509/EXTENSIONossl_x509ext_to_derOpenSSL/X509/EXTENSION/FactoryName wasn't initialized.ossl_x509name.cname entries < 0!X509_NAME_print_ex#<%li %li >X509_NAME_dupOBJECT_TYPE_TEMPLATEX509_NAME_onelinelocX509_NAME_add_entry_by_txtDEFAULT_OBJECT_TYPE[]NameErroradd_entryto_utf8hash_oldcountryNamednQualifierDCdomainComponentemailAddressRFC2253ONELINEMULTILINEOpenSSL/X509/NAMEossl_x509name_to_derReq wasn't initialized!ossl_x509req.cX509_REQ_set_pubkeyX509_REQ_set_versionRequestErrorattributesattributes=add_attributeOpenSSL/X509/REQossl_x509req_to_derREV wasn't initialized!i2d_X509_REVOKEDossl_x509revoked.cX509_REVOKED_dupX509_REVOKED_set_serialNumberRevokedErrorRevokedOpenSSL/X509/REVX509_REVOKED_set_revocationDateossl_x509revoked_to_der@timeSTORE wasn't initialized!STORE_CTX wasn't initialized!STORE_CTX is out of scope!certs in chain < 0???ossl_x509store.c@error@chainstctx_ex_verify_cb_idxstore_ex_verify_cb_idxX509_STORE_get_ex_new_indexStoreErrorStoreverify_callback=flags=purpose=trust=add_pathadd_fileset_default_pathsadd_certStoreContexterror=error_depthcurrent_certcurrent_crlOpenSSL/X509/STORE_CTXOpenSSL/X509/STOREStoreContext initialization failureexception in verify_callback is ignoredX509_STORE_CTX_get_ex_new_index;7g0@ P4H\x @`0,|P4L0``<x 0P,`X`@`Dp @ L x ` (!T!@!!!`"0" \""" "p #L#|#P###0$|$@ $ %p\%p%p%%%`&PT&&&+&,'`-H'p-\'-p'.'/'/'/(0 (0L(0h(1(P1(1(@2(2)2 )`3X)P5)@8)P8)8*9P*9|*`:*:*`;+;,+`+?, AX,B,B,D-E@-Fl-pF-@G-H$.IX.J.pJ.J.K /Ld/PM/ N/O 0Od0P0Q0R01Sl1@T1U1U2[02[D2\x2\2]2^2_3_,3`X3c3f4f 4gP4gl40h4Ph4h4h4Pi5i5i85l5l5l5n 6n86od6o6p6 r7r7`sH7Pvh7w7x7x7x7y8 zD8zh8z80{8p{8{8| 9}09~\9p9Ѐ999` :@:@t::::;@;P\;x;;;;P<4<p<0<@<<L=P=p===P ><>@l>> >>(???P?` @0@0\@@@@0A0ALAxAA0A`AA$B 8B\BBpB0BPC`CP@CpC0C@CC0D@DHDtD0D@DDE0>܉0??$?P@@l@A`AAB(`BDBpBC܋DD4ETE0F0GG G( HDpK`Kt MN P\PQQԎQPRpSlTTď U@U UD@VV WؐpWW$0XDXpXpYYؑZ [([T0^p@^`_`` a<dx ddē ee e(@fTff0gؔ@hh(@khkk@l̕lPo`o,pXr0sؖ`ssptLvvv@wpww8xlypy} ~@Pl̙@D`p @8`p`؛ `<h0`ܜ`Ў0L@hP|`08pdО pH d`И0ȟ0 (<Xp0ܠP@l`ԡ pl Pܢ04Pl`ģ04Ш0ܤP4xP̥zRx $M`;FJ w?:*3$"D P;\p"0,MH  A `<EvHOQH ~ A LiFBA A(D0S (D ABBF U (A ABBE LhiFBA A(D0S (D ABBF U (A ABBE LiFBA A(D0S (D ABBF U (A ABBE 8<FLD D(D@a (A ABBK (DmEDG0P AAA pbHFBE B(A0D8DPn 8A0A(B BBBH 0RH D A t)EW D D@FBB A(A0DP 0A(A BBBG T@qFAG G8xFGA D(D0x (D ABBA @_H j F nEY B E E  D q K (<(<HFCH sAB(h|EAD0e AAA ,FFF  ABF jH \ A $jH \ A (xUEDF _ AAH ((UEDF _ AAH (TUEDF _ AAH (UEDF _ AAH (HUEDF _ AAH (|UEDF _ AAH (UEDF _ AAH (0UEDF _ AAH (\UEDF _ AAH (LUEDF _ AAH (UEDF _ AAH (UEDF _ AAH ( UEDF _ AAH (8UEDF _ AAH (dPUEDF _ AAH (UEDF _ AAH (UEDF _ AAH (UEDF _ AAH ( UEDF _ AAH (@TUEDF _ AAH (lUEDF _ AAH (UEDF _ AAH (UEDF _ AAH $$?EAG lDA@ Hf K 7Hc G LEc H (EHD X DAA $P 7Hc G @t 7Hc G 4\ EDJ X CAA ~ FAA , AC FF J 0 FAA D@  AABB |D xBHA B ABH n DBD D DBA 4TEKD B CAF D FAA ((^EGD t DAG (\vFKA p ABK (vFKA p ABK (vFKA p ABK (<XvEGD u DAF (hvEGD u DAF 8FBA G(D0e (D ABBF 8FBA G(D0e (D ABBF @ (FBB A(A0Dp 0A(A BBBJ @PtFBB A(A0Dp 0A(A BBBJ 8FAA u FBK A CBJ (dED f FK D CI PFAA D0  FABN   DABA J  DABG (PEDG M GAK (|XjEMD l DAI (ZEDD m AAA 8FBA A(G@x (D ABBA LdFBB B(A0A8D= 8A0A(B BBBG 0`FAA G0J  DABA 0 FAA G0J  DABA (|QEAG0u CAF (QEAG0u CAF 8 FBA A(G@w (D ABBA @\xFBB A(A0G@ 0D(A BBBA 8FBA A(G@w (D ABBA 8FBA A(G@w (D ABBA @<FBB A(A0G@ 0D(A BBBA @\FBB A(A0G@ 0D(A BBBA @tFBB A(A0G@ 0D(A BBBA 8 FBA A(G@y (D ABBA H  FBB B(A0A8GP 8A0A(B BBBA 8lx!FBA A(G@w (D ABBA 8 "FBA A(G@m (D ABBA 8"FBA A(G@m (D ABBA ( #EAG0a DAA L#E X lX) 0T)FAA G0i  DABA *  *EG  AD (*EAG0 AAK 0+FAD D0  AABE L, EZ(h,EHD0 AAH H-FBB B(A0A8Dp 8A0A(B BBBH \/FEB B(A0A8GAPUCp 8A0A(B BBBE @2&E`,\2FAA n ABG X3AAF\3WEt A 3AAK32H] H 3AHs A 3eEt O R F <H42H] H Xl4AHl H \t4BBB B(A0A8GVPCN 8A0A(B BBBF 6 6H6ZFBB B(A0D8D` 8A0A(B BBBE (H7vFGA v ABI (tP8vFGA v ABI ,8FDJ [ ABF 8D9FHA D(D0n (D ABBB , 9AFAA  ABD <;H { E (X;EMD A DAA <L(>EAG@ AAF (D@EHD nIH@ @,$@FAA y ABD (TAuEKD k DAA AEG H DH PBAAKTBAHl H B:He H B:He H 0B-FKF D0  AABF HCED u AA (lDECJ0 AAE (|EEMD u DAA EUE= G G 8 GfFIA A(D0/ (D ABBA 0H LHTFAA D@  AABH 0| xItFAA D@  AABJ 8 JsFBE A(A0Y(D BBB KH E C (!KEAG0 DAG 4!LAAK(P!L]FHD r DKE |!L2H] H !L2H] H (!M^EGD n FAK !DMAAF(!HMEAG0U AAA (("MEAG0U AAA T"0NLHf A 8p"dNFLD A(IPw (A ABBC "8O{L^"Q T"Q_FBB D(A0DUIAN 0A(A BBBA L8#RFBE A(A0DPXU`IXAP` 0A(A BBBD 8#lSBED D(D0n (D ABBE #SAAK(#SEHDp AAE ( $8TEHD0n AAG 8$TjEG D DD \$(U4Ei A ,x$LUFAA i ABA 0$UFDA G0_  DABH $8V<Ec A $\VsE[L%WFBB B(A0D8Fs 8A0A(B BBBD `d%`\FBB B(A0D8F GBBIc 8A0A(B BBBD L%_FBB A(D0FpxGFxApc 0A(A BBBC &aH4&Pb H&LbEG [ AH (l&bEHD0 AAA &cEh K R F 4&xdEKD x FAE I CAA &dAAF,'doFAD C ABA (@'$eyFAK s ABA l'xeOHe E ('eEHD x AAE 'ffEw E 'df.Ec A ('xf%EAD@ AAD (|gLl(4(hEHD0 AAA `(i t(iEK l AA (jEK t AK ((kEK t AK ,(kFAA n ABA ()TlEHD0 AAA <)Hm (P)DmEAJ@ AAD ,|)nFAA u ABA ()nEHD0 AAA )o ,)oFAA u ABA *p&ED p AF @*$q ,T* qFAA u ABA (*qEAD@ AAC (*rEHD0 AAA *s ,*sFAA u ABA ( +tEAD@ AAC (L+tEHD0 AAA Hx+uFIB B(A0A8DP 8A0A(B BBBF ,+vFKA H ABA +0w&ED p AF (,4dEQ v AA 0$>hFAA D0z  AABF (X>*EAG@s AAF L>FBA A(G@ (C ABBI Y (F ABBD >P6HU A >tdEn A 8 ?FBA A(GP (A ABBF H?>E` A ,d?@EHD AA(?0EADPe AAA 8?:FEA C(D@ (D ABBA @?FEB D(A0DP 0D(A BBBA 0@@>FAA D@  AABF 8t@FED A(D` (A ABBA (@TEAD0 AAE (@EAD W AAE (A<EAD W AAE 4A!E[@PABEE A(A0Dp 0A(A BBBJ @A BMA B ABK N ABG FAB(AlEDD U AAD BAAK BED h AA DBED h AF hB ED h AF BED j AD B$ED j AD BED j AD (B<EDD y DAA $CED n AA HC,ED i AE 8lC,FED A(I@x (A ABBI ,CIAA e ABE (C\EAD N DAC DqEY($DPEADPe AAA 8PD:FEA C(D@ (D ABBA @DFEB D(A0DP 0D(A BBBA D$5ED  AI 8D@FED A(D0~ (D ABBA 80EFBA A(D@ (A ABBG (lEhEAD Y AAE $E/EVC LCA8ErBEA A(D (A ABBJ 8EHFED A(I@ (A ABBG @8FBMA B ABK N ABG FAB(|FEDD g AAJ FAAK FED h AA F,ED h AF GED h AF 0GDED j AD TGED j AD xG\ED j AD LGFEB A(F0D@HNPOHA@` 0A(A BBBE (G(oEGD m AAA (HlEDD0f AAK 0DHFDA DP  AABF (xHEAD N DAC H0_EGHpH|H I 4IEKD V FAG D CAA ,LIFAK  ABA 8|IFLG A(G@| (A ABBE ,I,BKA @ ABO II JED ] DF L4JP`FBB B(K0D8If 8A0A(B BBBD (J`EAD _ AAE TJBBB E(D0D8D@HNPQHA@L 8A0A(B BBBI K,K6ED  CA B FA (LKgEAD@ AAB ,xKFAK  ABC (KEDD ` DAF 4KEAD0[ AAI N AAA ( LXEDD Z DAA 88LFED A(D0} (D ABBA 4tLAAD0V DAG C DAA HLFBE B(D0F8DP 8A0A(B BBBG ,L,{EG M' H @(M|BMA B ABK N ABG FAB$lMbAi F F J F A HMFBB B(K0D8D@ 8D0A(B BBBC (MEHG D DAA ( Nh EHG N DAA (8N EHG N DAA dNp AAK4Nt EKD H FAE D CAA (N EHD z AAE N` 2H] H 4O aEHD i DDN D FAA (8O BEKD c DAA $dO HS E K E K E (OH VEAN h DAG O| 2H] H O 9Hd H O EK b AA PP EK b AA 88P FBK D(D@\ (D ABBA (tPpEKG s DAA (PEKD K AAA 8P8FDK h CBF g ABA QAAK$QdEt N @QDE~ A \QdEt N xQ tE| O F A QhUI(QEGD p DAK ,QyEC FEG A (RdWAMD g DAA (E` A sԺEE(s HsFBB E(A0I8M@ 8D0A(B BBBA HsXFBB E(A0I8M@ 8D0A(B BBBA LHt&FIA A(D0k (D ABBG Q (A ABBI (tEHD0n AAA ,t@FAA v ABA tAAFu.Ec A (,udEKD m DAA LXu,FIA A(D0[ (D ABBG Q (A ABBI (uEHD x AAE (u`EHD x AAE (vEHD x AAE ,v(AAK4Hv,~EKD x FAE I CAA 8vt{FLD A(G0v (D ABBA (vnFAK s ABA (vmFAK u ABA w@GHe K I A (4wpmFAK u ABA `wGHe K I A (w_EKD h DAA w2H] H (w<FDA z ABH wQHq G G E 0xFAA D@  AABA Hx6HU A (dxjEMD l DAI x$Ex (xEHD0 AAA 4xEHD E DAE K ADE $yED r AD ,HyFAA n ABA 8xyLbFBA A(DP (A ABBB y4yEHD y DAI W DAE zJHc G (z8EAD0U AAA HzAAK(dzMFDA y ABA (zMFDA y ABA (zMFDA y ABA (z,MFDA y ABA {P EG` AA (8{<EJD V DAA <d{fFBK F(G (A ABBC {<Ec A {KEm A ({(jEMD l DAI |l6HU A ,$|FOH HIT|0 (h|,EHD0 AAA L| FIB B(A0A8GF 8A0A(B BBBA ,|BKA C ABE }P&E`$0}dBEAG \JJ,X}FAA n ABA 8} FBK D(I` (A ABBC }<Ec A }AAK(}_AKD e GAE (~L.He0@~dMEDJ X CAA ZAA0t~ED ` GH | FF V DH ~> >0>@>P>`>p>>>>>>>>>?? ?0?@?P?`?p?????????@@ @0@@@P@`@p@@@@@@@@@AA A0A@APA`ApAAAAAAAAABB B0B@BPB`BpBBBBBBBBBCC C0C@CPC`CpCCCCCCCCCDD D0D@DPD`DpDDDDDDDDDEE E0E@EPE`EpEEEEEEEEEFF F0F@FPF`FpFFFFFFFFFGG G0G@GPG`GpGGGGGGGGGHH H0H@HPH`HpHHHHHHHHHII I0I@IPI`IpIIIIIIIIIJJ J0J@JPJ`JpJJJJJJJJJKK K0K@KPK`KpKKKKKKKKKLL L0L@LPL`LpLLLLLLLLLMM M0M@MPM`MpMMMMMMMMMNN N0N@NPN`NpNNNNNNNNNOO O0O@OPO`OpOOOOOOOOOPP P0P@PPP`PpPPPPPPPPPQQ Q0Q@QPQ`QpQQQQQQQQQRR R0R@RPR`RpRRRRRRRRRSS S0S@SPS`SpSSSSSSSSSTT T0T@TPT`TpTTTTTTTTTUU U0U@UPU`UpUUUUUUUUUVV V0V@VPV`VpVVVVVVVVVWW W0W@WPW`WpWWWWWWWWWXX X0X@XPX`XpXXXXXXXXXYY Y0Y@YPY`YpYYYYYYYYYZZ Z0Z@ZPZ`ZpZZZZZZZZZ[[ [0[@[P[`[p[[[[[[[[[\\ \0\@\P\`\p\\\\\\\\\]] ]0]@]P]`]p]]]]]]]]]^^ ^0^@^P^`^p^^^^^^^^^__ _0_@_P_`_p_________`` `0`@`P```p`````````aa a0a@aPa`apaaaaaaaaabb b0b@bPb`bpbbbbbbbbbcc c0c@cPc`cpcccccccccdd d0d@dPd`dpdddddddddee e0e@ePe`epeeeeeeeeeff f0f@fPf`fpfffffffffgg g0g@gPg`gpggggggggghh h0h@hPh`hphhhhhhhhhii i0i@iPi`ipiiiiiiiiijj j0j@jPj`jpjjjjjjjjjkk k0k@kPk`kpkkkkkkkkkll l0l@lPl`lplllllllllmm m0m@mPm`mpmmmmmmmmmnn n0n@nPn`npnnnnnnnnnoo o0o@oPo`opooooooooopp p0p@pPp`pppppppppppqq q0q@qPq`qpqqqqqqqqqrr r0r@rPr`rprrrrrrrrrss s0s@sPs`spssssssssstt t0t@tPt`tGA$3a18 GA$3p1113ׁGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1113kGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYblGA+GLIBCXX_ASSERTIONSopenssl.so-2.5.9-115.module_el8.10.0+4212+150d00eb.x86_64.debugS7zXZִF!t/̷#]?Eh=ڊ2NERU o'鞐2r8hauDS0 |p9ѺȔe9D#_8H#Wh¸7rVα`h\{.ں+d$-O r%ȵũSzZ}!_}# ƓJms=AQQv{TC8xDptS]2m`}% .D%)C¡_,(tIWFu4VdZѭQz<9WZ#ުmopg@wJCO~c1v::%.|uŞfRukQW} J,6OǑʁ_!J;"zTXb/sy T$h&+4ml9ÙF412.hS5^tdoP 5{ɓoun]0'?{G'lTG)fex+Ȭkmì'+%O:4Cm+¿*tU!TQQEBEgFRj"vu}o ##ݫӟB1gɎtKj5cD2׌HIg=yzdKaw#d11GJHyBxg554Rw3\udO(?'I󭿴{@i]4x_2U}WJнdNo|85a&.4CxvJ576Y`pȠZضEG>Xj5WjU !t?^=(NqV,DeA̧Vc<"T'vJҖ+DxQae gKC($4w$xu\}0$GvDA8P}FҿVV[jNVwq\bògϖ{ZEI@n&1(e7>xR3VJ?> !ޞrR(oa%޷2< FPBRvaYC 61g̃ټEzL: 2Nc'D"t:U2g)t䣯Ox@Ar7;kV>(͓aަrmqϡQ1D)(徏 }NK? 4UBmXe Q363 ޜ+X?8`%j9+*r |"i,n۔צ%ҰKo#WY ?V6C`I>_cٜ5Y{@3Qt0yfZ2uPZ L!K+oָCyܸGnuSj+XX Xz Ljfѻ=FTB^W`m>_ pik~\_)@zɞ҄PT/F B -Ķ1*2|wFm%|@[  pFCBf%/kURDEjf^3m_ʭ>"inu'I1iOq1唞e#rZ뮟y~O~SR1xD-XVIzf{齜(ow0jnr#G>au(>kLE&V}d?.ZCLE[rY>t8Յs ~Jq(΍䎽9M@m'ӞfoZ!ﴡj֤fS@irze{]k9_ݹΏfl7TmQ[r(e3~a)("e쬾[-Y|ec TϋjNЦ[2hfVtFMCŁQ'". "T{ߓ]A8a&Fo)Ȩڿi!&*cezüUѬske*J%v0lH'Y5;'KKSb.[r_3$$Tɂp>7m KhkXxewt*k蒎+Et⿃I2y2lvr_o ǤewNU%XN5hVg~@+auj9J}Vyf(IU%$~F, դSl_|X'ϐPs'=^.*ҙ&Mt,_/#%JG#l?%_@")8X. Cd;qV^lR]՚|_q6 T%gy[\\EzلXf\64T2 nmĩB(忮2Q0)( u@B:]vmHR"!*23"EȃԤ4G I Ad GIxZ3oRZ}B2J3d1շܴe:{3gePy?5 [Ku@ N܈:_3.*A$SڮI̗\3iQYȷGFTGKNh3S! @dIL>ڂl!XN>>kI'8 M6 tهFPU@ 35e1o,cGFLVjP-#06!ѻ1]͛1XT(Zx:j -n۳c)0r...d車/Bv#A`I\S }M^?YF8QE_ ǏXY(38qMH-T,VAɽFY~=ۄ[Iv``wLwcEꡪJ0x:z47flD{VU¬B2uJ1 E%mq.0ؖvbڌX\],ijw8C嗷|?Y^]2@^7łHJjN{TWyo[! 񨕯jf^{YmC"ƸUvC"L8v2k(/녱嚏k0<yu1,Ol tڏM`SPǭ+`~wP236_-`prIJ $ - v_ rjQY G88`0i `@fϣV}?:è{&%OcCV~&k1M {˿3iZ1CYZd{LI(~ H,ntwIa.3ʹE"2i+qIwHR[|*621۫!j7Dw.JGٱo2?R4ZI>@ *[`:g0m0nT@(FWlPLO "7s4jO ]Ms5¬n j܈#"0k};Ӑ6o0ä t\u^>rwɇ m(4r8x:c'3mcH|TLV攚~* Uy[KزXz@g0l7@z}&0Q4E2W,)RiS5#U߮<ЅgX޺&Z‰V!CAT}1hߦ뽛"pf,b祾+?^;<(N%=ؠd(ިu~nAc N_= k@y<ԫXЙfZzY}}ʡ.=6zݕ@8!x˶lGCsJҔ u%)zjp3Q̈qѭY?7Ẃ։N;+XtVyT)7^Z+{qwnS~pxo:Y%mPFsyrCid~B)xakKhK9./:jTI[NR@,V؁,o|Eߢp/co5)}-;`/ă<(ί[*bO)i؅CSM5\Pm^3gUWI0"e55rS5VGƥAS;T/ YB(:6RkvAx-@8pͅ x#Lx`+< MAK'1.*Y1ROsa\t,LXd>\bv w=s_EI /E:2]t_8u=|+m!)9]Ǽ  2o sm2XigouQ-u2*rá.܉ϴ~X30:%~FEko0ؚ/M㫳BUG# Yݶݒ_}#&1 ڕ%;! i>jw?_JH0tckA25VZ=lW k݋Nbfsm,.$@-/R:=ngq yKfS('ٟ Թ8=cjHO] vwQfsУ*ɿ먙>;:9 !+U?KYv7֕~&*w~+(n:mLr4J}uE 2KE#̿+1k_s9z}+Gu 弜kaY&o o0JovهfO&j4٘3 BwߐdTP?ݐ݈W&0iu+tYa1 ^viKkMG:]SڨwCG¥ 4K鼵d*عdQ!N]o}zn_~2yBVrFxX#v_+ m;RoPпDvkBLW"?E ;M"RSyX$\ f r%7 UTJ)<.ޠMhF֧Mڔ>ώLY?j:4:\ πkW'M Enז} ׊+T`ߦS=%N%Nڔ?>80EΉ`!{󲝊|5o*Uh,7ѕ9*\&#:<.}k1G#yXkmؓHs‰ܼw.*#8.\{VZaЖE;sSRN Q̴|WwͣlH19d?7,MkKٸ5&aV8եM?KڢA%f]0.n!nuG%`7S k2Z 6lظ\&kr[1*A&Doj ; nK=.ӤdQ7Ni~ʚ 1000000) { 8: int (* volatile tp)(void)=(int (*)(void))&t; 9: printf("%d", (*tp)()); 10: } 11: 12: return !!argv[argc]; 13: } 14: 15: int t(void) { ; return 0; } /* end */ -------------------- PKm]&ruby/ruby-lsapi-5.5/gem.build_completenu[PKm]7?P.P.ruby/ruby-lsapi-5.5/lsapi.sonuȯELF>T@'@8 @hh !! !!888$$HHH StdHHH PtdQtdRtd!!0 0 GNUAࠏW(C H‚3@(L`qCSlP*fRn}'3qѮl>&Sɶ ܮʼnSO`[is|&߱RD/y7řkՊ eY&09=By:%/=ejOzJ6'l#mNULCB1{!\$O#W23S=apbU06aD7jp#7ĴDIΊ=\4yݾCEкQuo rSѮIo|q%h6 󝵛 ' =qX[ u  f   H ysO\ 7  8 [m fk &/ !  2 RT s G +0 >v - TH  ". " "$7x _S ` > I A$ 9. 4, 2F" EA  s r G  |F `qD p-  S P 5 `ui~  z@! b .  ! ] ЍZ\ 0f n  P v 01 Pq Y ` p@ P p rl zj U | - r] @  n pqY n  @5 o w$ ~l! Pt U U E u rS 0n7 pnT О(    ` 0  @|F qJ pp8 ! }I  P  !b g  @K "! l 6 n  ? !__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizecompareValueLocationset_skip_writesigactionsigemptyset__stack_chk_failreallocfcntlacceptsetsockoptmmapmemsetsetsidread__errno_locationclosewritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemexitlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidsignalg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamdlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectrb_tainted_str_newrb_hash_asetrb_gc_markmunmaprb_string_valuerb_string_value_ptrrb_eval_string_wrapruby_strdupmkstempftruncaterb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_str_new_staticrb_unexpected_typerb_obj_as_stringrb_debug_rstring_null_ptrrb_f_sprintfrb_intern2rb_funcallvs_fn_add_envrb_ruby_verbose_ptrrb_define_global_constrb_default_rsrb_exec_recursiverb_output_fsrb_output_rsrb_lastline_getInit_lsapichdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocrb_stdoutrb_stdinrb_hash_new__memcpy_chkrb_define_methodrb_define_global_functionrb_define_singleton_methodlibruby.so.3.1libm.so.6libc.so.6__environ_edata__bss_start_endGLIBC_2.14GLIBC_2.15GLIBC_2.4GLIBC_2.3.4GLIBC_2.2.5GLIBC_2.3/opt/alt/ruby31/lib64$ P [ ii f ti p ui | ii  !T!T!!!!q!!w !~(!0!8!@!H!P!X!`!h!p!x!!!!!!!"!-!;!M!V!d!m!!g!!! !(!0!8!@!H!P!X!,`!;h!Gp!Tx!^!j!w!!!!!!!! !!)!2!8!8!I!Y!X!!!! X!`!h!p!x!!!!!3!!=!I!K!R!V!V!W!!!m!|!! ! ! !( !0 !8 !@ !H !P !X !` !h ! p ! x ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !( !0 !8 !@ !H !P ! X !"` !#h !p !$x !% !& ! !' !( ! !) ! ! ! !* !+ !, !- !. ! ! ! ! !/ !0 !1( !0 !28 !@ !H !4P !5X !6` !7h !8p !9x !: !< !> !? !@ !A ! !B !C !D !E !F !G ! !H ! !J !L !M !N !O !( !P0 !Q8 !@ !SH !P !TX !U` !Xh !Yp !Zx ![ !\ !] !^ ! !_ !` ! !a !b !c !d !e !f !g !h !i!!j!k!l !(!0!n8!o@!pH!qP!rX!s`!h!tp!ux!v!x!y!z!{!}!!~!!!!!!!!!!!!! !(!0!8!@!H!P!HH HtH5 % hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqha% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݿ D%տ D%Ϳ D%ſ D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݾ D%վ D%; D%ž D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݽ D%ս D%ͽ D%Ž D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݼ D%ռ D%ͼ D%ż D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݻ D%ջ D%ͻ D%Ż D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E DH=0% f.H= H H9tH Ht H=y H5r H)HHH?HHtH] HtfD=5 u+UH=: Ht H= yd ]wff.^ ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=n D ÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH=ߞ 18tI٬ TH=a HcH5aHHv [ÉD1?H=e 0HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHt HHtHHtH{@Ht1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDJHu4O8u P uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=\HcB$HH@H,H9rZf.HH9vGH3LLuHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L=k L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$)KH8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L L{hfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH t L$DIH V Ic LnEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcU ff.AWAVAUATUSHXHt$ HT$dH%(H$H1HIH1E1L-fHL% HHHcHcT4t/HHAAtIHJL$HL}HH=PLAH12ŃuRH=˚ H9t Ht H1H H$ dH34%(H []A\fDT>@4 +HH5X1rrDH߹SfDHH5W1CHtvt]SHtCuWHC(H9C8tHHCpH HHHH@HCpPH1[@s뢸ff.Huu1fSHtRubHC(H9C8tH0HCpHU HHHH@HCpH{:1[1HO@H9OPv닸AWAVAUATUSHHH|I֨,aHHt$H>L{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eH=thILM)MUI9t HtDL+t$HL[]A\A]A^A_DM@@M)(IHt$HLHk8f.HAVLAUIATIUSHu\H߉KAD${LǃLSHu0{L[L]A\A]A^x;[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIHLc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAoMt$PHLIFID$PA:I|$PMMD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHA I\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1ԿHL$Aߺ訿u#DHuDo輾߻D H:DeOAkDH}An葾}N3Htff.USHdH%(H$1HHu/HUH$dH3%(uHĘ[]褿@1H= tAUATA'USH 'DNuD H@AHH. HHtH- Tʐ 9Ɖlj *UDk H DcEuSH8dH%(H$(1=HtH H= H==HE1 H螹H==Ht 1Hv H==ijHHt 1HMIAąWE1H==萳Ht 1H H==jHtHǺ 1_H=n=CH H=e=$HtHǺ 1谸)ĶH=@=H1 HxOH=&=òHtHǺ 1OشH==蜲HtHǺ 1(H==uHtHǺ 1ʺH=<NHtHǺ 1ڷ蓲H=<'Ht=H=<Ht 1H蝷 _H=<Ht 1Ho D~ p b EH=<ٶH=B u P5 5+ H=<cH 1H …t H)w HHHHDƄ L<L <L<C HLt@HֹL€D t%HtAHHt9HLuHfDHJHHJHuHHu1ۉH$(dH3%(H8[]A\A]fD H膲DH H=8 H~AԅLH=AH= 褮H $@HH$HD$bDHH$$̯t 议1҃8k‰؁ H=8ܭHt1 Hh~v H=8貭Ht1 H>~H H=8舭HHiHǺ11諵ÃHT$ƿD$(?H5 ȱHWH Htxc@dx@D E9D E)ZfH=7贬^ HK] R u D ': ( ' )fՅtbH H-DHH5f?1SAHc~L% HH asÅt= b u l 5r `HH5>uHH5I>1U HH5Q>Fff.AVIAUEATIUHSHt4Hu!(fDHHtHLGH]HuMtEL[1]A\A]A^ÐIcLLH#EgHGHHܺvT2HGAWAVAAUIATUHoSH1HGO@ƉWDW?t;AĉDHH|@D)A9rhAGt4LLHL9A?vWEfAIIIH޺@HH@ܱHLL9uA?DLHH[]A\A]A^A_鬱IATLfUHSFH?LHz?)ƒw=t19rLHfCAD$AD$ ID$071)HCHLHCP?o H{1HMHHCPH)KXH[]A\ff.fAWAVAUATUSHdH%(H$1Ht^ IAfMcg IoA_@LH#HuM(8u =)x uٽH$dH3 %( HĨ[]A\A]A^A_f~AAuIALJf8LS|xr@tPHf@HPXN MgA;G ZA9~uEo)HHcIHLDHu$85w uAMgA9ID$,HD$HcIIDhAh(A9}A /HcIH4@H5HAIIh$A9}A HcIH4@HHAIIHl$p(ILHIILp$hMIc@o9gIcP[9SIcpG9?IcH39+IHHHHIHT$IIc@ H)IHHIHHHIHIIcHIHHHD$I9E1DL4t9dfH H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0Jv ALJt`u u Au 1LHc蟩IHIGAo IuID%u D-u B(AA1IcH4IILI 9HqH=- IJDB(9xHqH=- XIJB($AD$IKAzHL$;Mbfou Lt$ LAoL$AT$Ml$)$蘪 LLHL$LHLLH$ID$H$I3L$H1H D$$Dl$EDDl$âH=Tt IHIDt MH=s t"LDLŃP|$WEt$A9uHt$~DŃ5s $A?D5s t AH5u)L HtHHs f)ws #AH5 f 1H@H5+19LH 1HoIH531H5)31ݨD%r r DD$H=r IHtZEW7E1111ͤH=53H5`*1`E|$菦M2;|$gE1H5o*LuI}臧Ń1H51*LKfD=q -q q ED$AIFH5v)1膧HH)H581H1a1H5)L ܟ1H51LA#LH 33H m w1H5n)Laff.AVAUATUSHdH%(H$1D$ HHѡ ;1Ll$Ld$Lt$ Hklbl {ul;LLD$CHp Ht@HTp Ht{1f|$=o u|H4tH舴H0k d1H$dH3 %(u}HĠ[]A\A]A^D胜 {H5b ,Hfы{LA;۝ff.AWAVAUATUSHD=To dH%(H$1ExH H-n H}o ;Na DH-%o Ht 11HEDj EH$L|$PDcA:E1AfD Uj EDn EtHn Ht @fLH1HIcWDHD$PHD$XA ?)ѺHH D9#11A|$MH j D9#H%n Ht @D9#%` AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$L謞H$LHHD$@菚AHLDŽ$hH$eH$LHHD$0HPH$LHHD$8#+H$`L HHD$(H$ LHHD$HٙADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%k EHk Ht H=g 1dIL9t<1ձL5EDu EME1V&Hg LH1HHc}襚}LD$LHD$PHD$X ?)ѺH1H T`1fg  8Ht$(1ҿ 荘x=_5 k tH&k Ht @f,D9# DCHj Ht@Hj HtDc1DN @f =i {H5\ HHAj Ht*Hqj HB(@HQj Ht@Hi H@蛖8B-DAD9M=re 荟=Ve Hi HtDHpi Ht A9HQi HtD҉T$$DE ~:E~57T$$A諙A蜙AuDE UM D9vHh AHtDH5*'1覞̞D$g0 H=!GT$fD}蠩C1mH|$IH|$HT$Ht$1`61E Mt AMgMg{E1CCHt$1ҿ H=4)'f; >fDD$$_0d T$$WH=#T$7T$fDD#AfDng RDb EBH;g H29b {H5Y 蠔H{wH='F蜓H= (0莖MAH… H{HƘ\b H= ԚHt$1ҿ脒He rf L=rf Xf H5f 7f He HtHW 11L=7f AGHe Ht{1蝦D-a EuHe Ht!E9~ja he ;t ؕHt$@1ҿL$ْHt$01ҿȒHt$H1ҿ跒Ht$81ҿ覒Ht$(1ҿ 蕒kHLSH$&$讒L$舒id d H="*%諚,H=%QHd Ht*fC1CD$CCӖT$HC(HC d ֒fD=~d |d ff.@H5` f.ffDh Hff.HV HH+HHODH1f1fATIHUSHcXHcLHJH=#h HHؔ[]A\ff.H飕HH=AU HfHH=!U ܏Hc5g ;5_ H=xg |6aHfg Hbg [g HfDf?IH=T HH+9M1~+HHcHc5f H5f ѐ~f Hfff.@HH=AT ̏tHHHDHff.HH=T 茕H] HHH=S 蜏H] HHH=S tH] HHSHH\$Ht$HEH]1H#H[ff.fAWAVAUAATIUSHH %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGNOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

Resource Limit Is Reached

The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
          QUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMEftruncate() failed. File mapping failed. Memory calloc error[...]RSTRING_PTRreplacesrandSTDERRreopennilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXRACK_ROOTchdir()to_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXX;|[e0@p qH0q\@qpPqqqqPy@ytPzz{{|4}P~~Lt`04 `X Њ  , @ T h P   H \ P p` t   x Н  P8 Х( @L``tPp(<Pdаx0@P`pD0 \ 4H \0p@P@ $D\0t`P0PPd $HtP4zRx $W FJ w?:*3$"Dxa \lpll LlsEIB E(A0z (A BBBI A (D BBBA l l@lYGJB B(A0A80F(B DBb0TtBFC G  AABK dtk(tGADJ n AAA 4tUAGK R CAG L JCG  uAG] AJ $ut C KFLHtvBBE A(H0H (D BBBD  (D BBBA PwvFB A(D0D (A BBBB L(A BBBA$pwaAAD XAAHwBBB B(A0A8D@N 8C0A(B BBBH $`\xOAf Q C E H@xYBBB A(D0J 0A(A BBBF xzFEA C(G   (A ABBD M I c A  E M A k E E E E H V HH|FBB B(A0A8D`` 8A0A(B BBBD lh~+BBB B(A0D8JYHPC Mi 8A0A(B BBBE LTMDd(6BBB B(A0A8DP 8A0A(B BBBG  8J0H(G DBBK $l7EFF IIO$  4FAA G>  AABG EO D  A @L THhDY|JEDăS ]Ph H XAHLlFBB B(A0A8LP 8A0A(B BBBH <p FBB A(A0 (D BBBI \@i`pFBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH LX$FBB A(A0H Q D 0A(A BBBH L$8FBB B(A0A8G 8A0A(B BBBF tFDF$ nCXJLlFBB B(A0A8DA 8A0A(B BBBA `( BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0 BMD GL  AABA < =BAA G L@I@U  AABG $ TWEHG ( ag H SHL FBB B(A0A8DPS 8D0A(B BBBF T bIE D(C0P (F BBBM Q(H BBBAH FBB B(A0A8DP 8A0A(B BBBA T< CBA A(G0` (A ABBD  (C ABBA J8 h-FBD D(D@T (A ABBB  \( hlECGF AAI L !cBG A(D0 (A ABBE XD0` t Z 10 pFAA G@7  AABF  L@LsL pFBB B(A0A8G 8A0A(B BBBG < @P < d 8x D P \ h t  p  lh <d FBA K(G (A ABBG <X4FEE D(D0M (C BBBB t(HFBH E(A0E8I@ 8A0A(B BBBE (4FED ABH$ة BBB B(A0A8G 8A0A(B BBBJ DplFBB A(A0G 0A(A BBBF LԶ FBB B(A0A8G  8A0A(B BBBA 4 H\+p(BFGA kFB HUgHQ G  ,ayd82HW I IX HWp HW-Hd3ED hAHFBB E(D0C8GPm 8F0A(B BBBG 4 oAD  AAK pP \D4FDA D(F0` (D ABBB j (D ABBE l(G DBBDBBI B(A0A8D@8D0A(B BBBp*HP H I UKI8(FBA D(D@ (A ABBE d(xEAD0r CAP 8EL<EY(@ EDG0 AAB zRx 0 (X 8AD w AA (\`EAD  DAF ,4ZAD rABHtFBB B(A0D8D@ 8F0A(B BBBG @7FBB A(D0D@ 0A(A BBBB 8HSFBA A(D0 (A ABBF GNUTT!qw~"-;MVdmg,;GT^jw )2  $  > 4!!o`  !.p&p oo&ooX$oD!>?? ?0?@?P?`?p?????????@@ @0@@@P@`@p@@@@@@@@@AA A0A@APA`ApAAAAAAAAABB B0B@BPB`BpBBBBBBBBBCC C0C@CPC`CpCCCCCCCCCDD D0D@DPD`DpDDDDDDDDDEE E0E@EPE`EpEEEEEEEEEFF F0F@FPF`FpFFFFFFFFFGG G0G@GPG`GpGGGGGGGGGHH H0H@HPH`HpHHHHHHHHHII I0I@IPI`IpI,LSLSLSLS88IYX!! GA$3a1>A GA$3p1067TGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p10673GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYTGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONSlsapi.so-5.5-1.el8.x86_64.debugU&7zXZִF!t/?5]?Eh=ڊ2N'NJOʚ0nvFZ,%;=f9INYd9Ӽus2㪼g{㡯pD,j QJ%abKʡ{ycGzJu.ٯ~ϔ.9퀺돎c;%Mw,s-7luIHܸtߐFH*UhBscl7",_arNeNT7 ~6 M T (0^5ǼID~TA › ߧ\*:8[^no`+UM}MÂ;F{tWxWM:7zj /AVgJ+m;o=eH3<|2@a٧f6ŝ*i懪QKi/l8f~/pV8g0U 'ąXta _,QIB `K+BNBTTH?'M!w6~o j pz9u>$񞃚"MwƜx$7|YܟatcR~}=4lJe?QxW>I{K$ %(\@';CLy&"a, >pxRږ3!@6vL%åw cY@ ^J`㡏J06jdr#ިCyy:{{ލffVm^l.h2uD=#* M.!Ɇzy.]7ڊ{@Q[9M=_*MTqe7t>&_{h'΍=>He޿Ү"Nӑ:[wd޾x|,Xny(.$ijtnsP2ڲS(fX3}| !{ÉK&EI:W u<+q_0CAa;18Ğ?/UkNǔ4'oid,WDiW89sJ<#MtWߑQjTs5&b%28YŴYz{z$nm]T"2^R.he}!]buVQõGW~Ɵ, Ɨf<,g_n|{^e6zM{RgN *Z:weL ڜC rm@-z^lLHËYYy̙sr3*B MrGPVƘghgz[ b3 .+mQhŷ RR83ǽ>@w1 &ꑲҨL#F,W4P-0T:-`qæeTܦEwJZae@4M1wн0f]XfX]9^lpXŢO^v!LfhVze4΄ o`Wڜ ꃌ~sWDQ.7Gޣ%]s ~fpܶWʛ+u2:m p!؄<]S+w/ *}e=\Ka)maCSb V="&;QO"c)UIVR\D1xߦ1@*sگ_gQt<[$F#7Ab<W;gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``p( 0 8oX$X$Eo&&pTp&p&p^B..h>>c>> nII wTT#~}44 ``p HH !!! ! ! ! ! "al L$px%(PKm]ó@@%ruby/json-2.3.0/json/ext/generator.sonuȯELF>@@8 @vv }} }  }} } 888$$hvhvhv Stdhvhvhv Ptdhhh$$QtdRtd}} } GNU/ !-Ǹyp7JM@$MOPBE|qXt)^ Oc6BaSr`UY; /-zgAPj"{"H"'U z;, 6F"%lu    0Z__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_funcallv__stack_chk_failrb_check_typeddataruby_xfreeruby_xmallocruby_xrealloc2ruby_xmalloc2rb_str_newrb_utf8_encodingrb_enc_associaterb_check_typerb_str_new_staticrb_hash_arefrb_hash_newrb_obj_classrb_class_namerb_hash_asetrb_str_duprb_str_catrb_str_concatrb_str_internrb_sym2idrb_ivar_setrb_attr_getrb_ary_entryrb_string_value_cstrrb_iv_getrb_str_substrrb_id2symrb_intern2rb_data_typed_object_zallocrb_obj_is_kind_ofrb_cHashrb_const_getmemcpyrb_enc_getrb_usascii_encodingrb_str_encoderb_enc_str_asciionly_prb_path2classrb_raiserb_keyword_given_prb_free_tmp_bufferrb_error_arityrb_empty_keyword_given_prb_string_value_ptrrb_float_valuerb_hash_foreachrb_cArrayrb_cStringrb_cFalseClassrb_cIntegerrb_cNilClassrb_cFloatrb_respond_torb_cTrueClassrb_cSymbolrb_eArgErrorrb_check_convert_typerb_convert_typerb_id2strInit_generatorrb_requirerb_define_modulerb_define_module_underrb_gc_register_mark_objectrb_cObjectrb_define_class_underrb_define_alloc_funcrb_define_aliasrb_internrb_define_methodrb_define_singleton_methodlibruby.so.2.7libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.4/opt/alt/ruby27/lib64ui ii }  } P }  } @} =fP} #X} !x       ! ) 3 5 A B C E L  ( 0 8 @  H  P  X  `  h p x          Ȁ Ѐ ؀   " # $ % & ' ( *( +0 ,8 -@ .H /P 0X 1` 2h 4p 6x 7 8 9 : ; < = > ? @ȁ DЁ E؁ F G H I J KHHg HtH5g %g hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=% d D%d D%c D%c D%c D%c D%c D%c D%c D%c D%c D%c D%c D%c D%c D%c D%c D%c D%}c D%uc D%mc D%ec D%]c D%Uc D%Mc D%Ec D%=c D%5c D%-c D%%c D%c D%c D% c D%c D%b D%b D%b D%b D%b D%b D%b D%b D%b D%b D%b D%b D%b D%b D%b D%b D%}b D%ub D%mb D%eb D%]b D%Ub D%Mb D%Eb D%=b D%5b D%-b D%%b DH=!b Hb H9tH~_ Ht H=a H5a H)HHH?HHtH_ HtfD=a u+UH=z_ Ht H=\ da ]wH7Hthv$HtNHu8R1€?v2fHuB,fDHH$GHCHsH$HCL9f.HD$HD$HD$@H5+H$GHBHIcDL>H5+HH5n+HH5E+HH5++HH5+HdHwXHLHHH$H f(H$ff$LH/I(H=*[H5 .H1z1ff.ATIUHSHdH%(HD$17H$umH=I HH5D HHHHHsqLHHHHL$dH3 %(u}H[]A\fHm~H<$tH1f.[xH$u!HKH>fDHm~UHSH(Ht$H\$HdH%(HD$1HL$H u0HH\$HL$Hu-HD$dH3%(u*H([]HQH\$HL$HtHHCATIUHHSHHGE$$11H5H HD$Eu"D$f(fT -f. -wf.zBHHH[]A\HHD$HD$H=G H5=(H1HHD$cHD$H=G H5(H1ATIUHSHdH%(HD$1H$umH=QG HH5A HHgHH HspLHHHHL$dH3 %(u}H[]A\fHm~H<$tH1Zf.xH$u!HKH[>fDHm~PSHHH5:F 11H[H]ff.fATIUSHHdH%(HD$1gH$umAH=F LH5A@ HHHHtfHHHHHL$dH3 %(H[]A\M$$~H<$tHH1 f.HH{xH$u!AH;H.DM$$~AWAVAUATIUHSHHHLz0L*dH%(HD$81HB8LrHRhHD$HExHHExHt H9HH $&HCHSH5GH ${HT$HCHLd$ H\$Hl$D$(VLexID$HExMtLH|$Mt;H~6A1fDD9t MtLLH߃D9uDH{HCHS}HCHD$8dH3%(u[HH[]A\A]A^A_HT$LHH$dH$MdPHExH=}C H5$HP1HUxZf.AUATIUHSHdH%(HD$1H$ukH=/C HH5p= HHEHILLHHHHHL$dH3 %(uyH[]A\A]Hm~H<$tHx1:f.xH$u!HMH;@fDHm~0ATIUHSHHHL[]A\f.AWAVAUIHATUHSHXHB@LzHT$HD$8HBHHt$ HD$@HHRhHD$HAPHxH@H|$HHyxHD$HwH|$0Ht$(HqxHt H9HHEHU[HEH|$8t H|$@}D$01D`QDHH9}RH|$tH|$HLHHT$Ht$ HHtIE uIEH9|HD$HT$0H|$8HPxtOH|$@Ll$Mt9HD$0H~/A1 DA9tMtLLHBA9uHHEHU]HEHX[]A\A]A^A_H|$(,E1AE9MtHt$LH@HT$Ht$HHHT$@Ht$8HLl$M#WHT$@Ht$8HlHuHD$H=? H5B HPxHT$HHPx1f.AUIATIUHSHHdH%(HD$1؃:H` gHCH; H9H; H9H; H9vHHHHH HL>E@HdHtuHUHe; HJDHHLLWHD$dH3%(H[]A\A]H); HHLHH: HH: H9@H5= Ht=HHL,$H5= BHHHLKfH5= H11 HHMHuqHL~fHHLLOf.H5LH5LH9 HH5LH9 HH9 HHupHLQEATIUSHHH56 HHLHH[H]A\rfUSHHHH56 H|HH[]fATI1UH1SHH5; dH%(HD$1lHDH$txxduJAHH=; LHHHL$dH3 %(upH[]A\@M$$~H<$tHP1fxH$u!AHvHiDM$$~AUATIUHSHdH%(HD$1UH$ukH=: HH505 HHHILLHHHHHL$dH3 %(uyH[]A\A]Hm~H<$tH81f.{xH$u!HMH@fDHm~UHSHdH%(HD$1H=H=# H56JHH5HH=# H5HH5HH=# H5HH5HHa# ̾H=U# H9H5荾H=6# HH5nH=# 1HH5RH=" H5_HH5wHH" H=" H5f*HH5HH=" H5BHH5HH=r" H5ξHBH5H蓽H=藼H=yH" 脼H=H! qH=BH! ^H=>H! KH=8H! 8H=@Hz! %H=BH_! H=BHD! H=fH)! H=]H! ٻH=IH ƻH=CH 賻H=1H 蠻H=H 荻H=H zH=H| gH=Ha TH=HF AH=5H=H "H=H H=H=H=H OH=H$ϺH=H耻HHH轺H=~Hg 蚺H=t莺H=o肺H HD$dH3%(uH[HHC*@instance_variables0123456789abcdef\n\r\t\f\b\\\"JSON::GeneratorError%u: %li not allowed in JSONnesting of %ld is too deepnullfalsetrueunallocated JSON::Stateto_hashHashto_hjson/commonExtGeneratorJSON::NestingErrorfrom_stateinitializeinitialize_copyindentindent=spacespace=space_beforespace_before=object_nlobject_nl=array_nlarray_nl=max_nestingmax_nesting=check_circular?allow_nan?ascii_only?depthdepth=buffer_initial_lengthbuffer_initial_length=configuremerge[][]=generateGeneratorMethodsObjectto_jsonArrayIntegerFloatStringincludedto_json_rawto_json_raw_objectExtendjson_createTrueClassFalseClassNilClassto_snewallow_nanascii_onlyunpackcreate_idextendkey?__send__respond_to?matchkeysduputf-8findEncodingencodingencodeSAFE_STATE_PROTOTYPEJSON/Generator/Statepartial character in source, but hit endsource sequence is illegal/malformed utf-8source sequence is illegal/malformed utf80 @hPxIh01234567890    ;$CX@HhȸXH x$<غTpx8xȼ(PHxؽHH<\((\8<p L x  0 X  ( 8 HL x H  X H  8 x zRx $FJ w?:*3$"Dذ\`p,TH F A %HW"HT&HW4&HWL'HXd"HT0|AULEvh/Am,BDD V ABE $X;AAG lDA$pDEAN hFA$<EAN `FA$,:EAN cAA TȸEO t AA 0x4FAD D0  DABA @йFIB A(A0JP 0A(A BBBD 0FEA J0t  AABB H$8 FBB E(A0A8D` 8A0A(B BBBH p6H] K D$9H] K DD9H] K Dd9H] K D9H\ L D(8EDM0q AAG (dH1BGD `AB8\BHA  ABH M ABH K KK0 AD 0EADG0T AAF ZAAH8BBB E(I0A8Gp 8A0A(B BBBH 0h FDD F0  AABJ (TADD@Y AAD 0BDG G0N  GABE 0T FDD F0  AABJ L@#AZ0hT0FDC G0  AABD LPBBB B(D0D8G# 8A0A(B BBBD 8 FBD D(F@ (A ABBD ((6FDF \CBLTvBBB H(A0D8D 8A0A(B BBBA 8BED D(G@+ (A ABBI (|>BDA lDB$ .EAG [DA04FFH D0w  AABE 8hd FBD D(F@ (A ABBD (HEDF0 AAG (,EDF0 AAG (EDF0 AAG (( >FDO WAAF4T FAK K FBK FAB4 FAK K FBK FAB4 FAK T FBB FAB4 FAK T FBB FAB44 (FAK R FBD DAB,l XFDA 1 ABA @ FBE K(A0D@ 0A(A BBBK 0 FKF G0t  AABJ L FBE B(A0A8Gq 8C0A(B BBBK d EK  AA GNU P } =f#!  b} } o`0      ooo8o} 0@P`p 0@P`p 0@P`p 0@P`pGA$3a1b GA$3p1094 bGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY z!GA+GLIBCXX_ASSERTIONSgenerator.so-2.7.8-141.el8.x86_64.debugk7zXZִF!t/]?Eh=ڊ2Noة!3;zA"1U3c yQ_DrB{$r@o.CrkH|jcҐ#lUL[X˃_"Y '}JMګU D3.W]jD5BF j2r0 Z8G:ؤb7BhqL6HW8ֶ$v@2$+>G4q1HlvC'Ymݴt-YֽYv'ZXaF=eS?LHa?z]2Jkv?A #r|uw-?z }h%c7ĄRK:OC(iݣR+x3y1,ɉ5t@akjTQ=ĠrGYx%ewIN"VdT44RmgE5xSwgq<+n8#J!AH洡0^ܤvYNb8r(2Vv$˔mͻ1G@Al:kScW|dzk7wr5 w8.dn$94A B? ·ÑYks3kVP6Bٳ뙚bMTҟ!><=Nn$bZwN i{a6 >ӪE֐QI:( NJ,0wX#p?A\=OfT8*j aKΣȆ]>dee,=8@Ҿ-mOmb۾ Fϟ8|M0 Lsgoy#-ӝ]'> &/^!cyǺIE։p̽s'G+ ag^Xn&q>[¹“jiW,6C ֏O ˴ QM 8G4ywl}vxo Q] =^;TEJU*/$#iHr./A0^h7n&[%ƙۻ[<._m͗-.(OqAH᫠IlL FYKf\*RS«HrYG !>7J0O$"]1!}nt/f H.` v&+t^LKdz7K% r ?g6Š;^Ră-hpW''T-%c1M\"F(G\HAu }& 3VևgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 00 0 8o88Eo@T  ^BhcnwC}bb cc hh$jj hvhv } }} } } }h } }x xx  `D L,x\Ԋ+PKm]`u{@q@q"ruby/json-2.3.0/json/ext/parser.sonuȯELF>P@i@8 @XX P]P] P]  ]] ] 888$$XXX StdXXX Ptd`U`U`UQtdRtdP]P] P] GNU]u4U{lQ#WC@ CFBE|ŷ|!qXgu ;s,UFI   q;"\F3.`~, WF"~UtEb Xb g DLb __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeruby_xfreerb_gc_mark_mayberb_str_buf_newrb_ary_new_caparb_ary_pushrb_hash_foreachrb_ary_entryrb_funcallvrb_str_catrb_str_internrb_utf8_encodingrb_enc_associaterb_str_resize__stack_chk_failrb_enc_raiseruby_xrealloc2ruby_xmalloc2rb_check_typeddatarb_str_duprb_eTypeErrorrb_raiserb_data_typed_object_zallocruby_xmallocrb_keyword_given_prb_warnrb_id2symrb_hash_arefrb_string_valuerb_enc_getrb_ascii8bit_encodingrb_str_conv_encrb_empty_keyword_given_prb_free_tmp_bufferrb_error_arityrb_alloc_tmp_buffer_with_countrb_hash_newrb_eArgErrorrb_extract_keywordsrb_check_typerb_fix2intrb_check_hash_typerb_class_new_instancerb_ary_newrb_cstr2inumrb_str_new_cstrmemcpyrb_hash_asetrb_cstr_to_dblrb_float_newrb_cObjectrb_const_definedrb_const_get_atInit_parserrb_requirerb_define_modulerb_define_module_underrb_define_class_underrb_path2classrb_gc_register_mark_objectrb_define_alloc_funcrb_internrb_const_getrb_define_methodlibruby.so.2.7libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.4/opt/alt/ruby27/lib64;ui ]iii tP] X] p`] `] ] oI] ] @]  _ _ _ _ "_ 8_ :_ <`  ` (` 0` 8` @`  H`  P`  X`  ``  h` p` x` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `  a !a #a $a % a &(a '0a (8a )@a *Ha +Pa ,Xa -`a .ha /pa 0xa 1a 2a 3a 4a 5a 6a 7a 9a ;a <a =a >a ?a @a Aa BHH)J HtH5BJ %CJ hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1%}F D%uF D%mF D%eF D%]F D%UF D%MF D%EF D%=F D%5F D%-F D%%F D%F D%F D% F D%F D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%}E D%uE D%mE D%eE D%]E D%UE D%ME D%EE D%=E D%5E D%-E D%%E D%E D%E D% E D%E D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D DH=,1bHl$ H=,1AFHl$ H=,1L$ H$&H$L$ 1H=-L$ H$HH$L$ tHl$ HD$(DHD$ HD$(f.DH=C HC H9tHA Ht H=C H5C H)HHH?HHtH}A HtfD=C u+UH=bA Ht H=> Id]C ]wH 5Hx=WHx0HH WHxHH WHxHH øf.HG`H@Hhff.@USHHHo`H}Ht!HHH[] ff.SHH?H{ H{8H{@H{HH{X[fAWIAVAUIATUSH1H8H$dH%(HD$(1H$IEL{I99A?"1KPunI}S4t C0@uHtH7IOHDH\$(dH3%(H8[]A\A]A^A_DLcXItQIuIHH5LLLHAIUH5A HHL$HT$%HIEfHMMfL9AF<"t4<\uMfL9AF0@ tHD$(HD$HD$0HD$DD$HL$HLHD$(LkIH,I~@Ht$(I}#Ht$0HL$H5-, 0ID$HPH9t%H,t>o t YHHPH9uID X LLzL9JA/]HILDfD0 HL$EHLHD$(IHXI~8Ht$ HT$(I}4Ht$0HL$H5V& HT$8?IGLxL9P,t5G t KLLxL9u< t <LIL9B< t~<" tHH9uHH9<*t*u H/6}V ,$IMf`LH)ID$HD$L.ID$IT$IF`ID$I~HHx{H="$ 4IIFHHD$HD$H;$ "HL$0H5# Ld$0IEIlLI^H9`IGH9tAW+t-uIGH9tAW0 HH9Ee.0 vfD u7HAH9#Q*tB/t8 @HH9uHH9*t/HH98*u@HL`L9@0< v@HLxL9@0@ wpE1HHHHHn !H=9HS H=,H( H=&H  H=H H=H H=H H=H H=H H=H{ vHg HHH "\ uninitialized instancealready initialized instancenesting of %d is too deep%u: unexpected token at '%s'-Infinityjson/commonJSONExtJSON::ParserErrorJSON::NestingErrorinitializeparsesourceNaNMinusInfinityjson_creatable?json_createcreate_idcreate_additionschrmax_nestingallow_nansymbolize_namesobject_classarray_classdecimal_classmatchmatch_stringkey?deep_const_get[]=[]<<newBigDecimalJSON/Parser%u: incomplete unicode character escape sequence at '%s'%u: incomplete surrogate pair at '%s'Keyword flag set when calling rb_scan_args, but last entry is not a hashThe last argument is nil, treating as empty keywordsUsing the last argument as keyword parameters is deprecatedThe last argument is split into positional and keyword parametersPassing the keyword argument as the last hash parameter is deprecatedoptions :symbolize_names and :create_additions cannot be used in conjunction(p8@}}}}}}}}}}}}}}}}}}}$}}}}}}}}}}$}}}}}}}}}}}}}}}}}}}}}}}}}}$}}}}$}}}}}}}}}}}}$}}}}}}}}}$}}}}}}}$}}}}}$}}}}}}$**||a|||||||PP@@h@@@@@@@  ;`0` 8`Tp@(PP(PTzRx $FJ w?:*3$"DX\pVp$5EAG ^DA>EtH BEB E(A0A8Ip 8A0A(B BBBF ,BDD V ABE D(=HX E 8`LFBA A(I@R (A ABBE $QEMD uDALpFLB E(G0A8Da 8A0A(B BBBH $zRx , HP,BBB B(A0A8D 8A0A(B BBBA (VEHD0p AAA HGNUp`] oI@ "1;~  GP] X] o`@   ` P ohoo o]  0@P`p 0@P`p 0@P`p 0@P`p4GA$3a1G GA$3p1094PGGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYGGA+GLIBCXX_ASSERTIONSparser.so-2.7.8-141.el8.x86_64.debug-7zXZִF!t/w]?Eh=ڊ2NaVg1q[ }i덧E.}kD//7Dj nZosdόsTz^ERiЭ#O@ D?QfNģcb3fw/X1nVrz!_ ?B%>U( DBĜj;V Q{ @%%2K ΰ#dd ^dz*. U\c)ԁ_km]=TX;pY BU/-֎!>f Mmy>G2KsG.pT*r䡯W?dt&grl gjbm&62\Gۤed:p=D0- 9'IVemCc g``O. (.{p}I J`t[صpm\:WAL}9QZADƤ␅үiT!jس$&iԅ/K=?ܺ7}F5>#F}^#@VpmKS{,T$"Q%BPHUr5>,d^]qB{v'OcѬe0כ4n[q}'f}b\>+׺maG $nUNdp5O^ᾎ12H/dpAYJ~T@8#/d){Tq }ŜȳquG"s_S$w>Sv  V8)0r*ԓ -@N@8 @P0P0 <^V"\p""1@~JgTe", E%F"w#QC!o D! (D! d$D!UC!C!__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizegOne_ABCED9B4_CE73__00400511F31Druby_xfreerb_thread_currentrb_thread_local_asetrb_inspectrb_str_duprb_str_catrb_exc_new_strrb_exc_raiserb_obj_classrb_class_nameruby_xmallocmemsetstrlenmemmove__sprintf_chkrb_thread_local_arefrb_num2ushortrb_id2symrb_hash_lookup2rb_check_string_typestrncasecmprb_eArgErrorrb_raiserb_sym2strrb_yieldrb_protectrb_jump_tag__stack_chk_failrb_num2ulongrb_uint2bigrb_eFloatDomainErrorrb_fatalmemcpyrb_bugruby_xreallocrb_check_typeddatarb_keyword_given_prb_num2intrb_empty_keyword_given_prb_free_tmp_bufferrb_fix2intrb_error_arityrb_big_packrb_sym2idrb_eTypeErrorrmpd_parse_special_stringstrncmprb_str_tmp_newrb_str_new_cstrrb_str_resizerb_warnrb_data_typed_object_wraprb_freeze_singleton_classrb_string_value_cstrrb_cBigDecimalrb_eZeroDivErrorrb_num_coerce_binrb_intern2rb_assoc_newrb_rational_numrb_rational_denrb_typeddata_is_kind_ofrb_big2strrb_float_valuerb_funcallvrb_int2bigrb_str_new__errno_locationruby_strtodrb_float_newrb_ary_new_caparb_ary_pushrb_Rationalrb_memhashrb_num_coerce_reloprb_num_coerce_cmprb_eMathDomainErrorrb_big_cmpruby_snprintfrb_num2longsqrtrb_opts_exception_prb_cFalseClassrb_extract_keywordsrb_check_convert_typerb_cFloatrb_cIntegerrb_cSymbolrb_cTrueClassrb_cNilClassrb_alloc_tmp_buffer_with_countrb_hash_newrb_check_hash_typeInit_bigdecimalrb_cNumericrb_define_classrb_undef_methodrb_str_new_staticrb_define_constrb_define_modulerb_mBigMathrb_thread_check_intsroundrb_dbl2bigrb_define_global_functionrb_define_methodrb_define_singleton_methodlibruby.so.2.7libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.3.4GLIBC_2.14GLIBC_2.4/opt/alt/ruby27/lib64 ui ti ii ui ?!J?!Y?!\?!]?!`?!c?!j@! @!(@!0@!8@!@@!H@!P@! X@! `@! h@! p@!x@!@!@!@!@!@!@!@!@!@!@!@!@!@!@! @!"@!#A!$A!%A!&A!' A!((A!)0A!*8A!+@A!,HA!-PA!.XA!/`A!0hA!2pA!4xA!5A!7A!8A!9A!:A!;A!<A!=A!?A!@A!AA!BA!CA!DA!EA!FA!GB!pB!HB!IB!K B!L(B!M0B!N8B!O@B!PHB!QPB!RXB!S`B!ThB!UpB!VxB!WB!XB!ZB![B!^B!_B!aB!bB!cB!dB!eB!fB!gB!hB!iB!kHH!!HtH5r!%s!hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1%!D%!D%!D%!D%!D%!D%}!D%u!D%m!D%e!D%]!D%U!D%M!D%E!D%=!D%5!D%-!D%%!D%!D%!D% !D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%}!D%u!D%m!D%e!D%]!D%U!D%M!D%E!D%=!D%5!D%-!D%%!D%!D%!D% !D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%!D%}!D%u!D%m!D%e!D%]!D%U!D%M!D%E!D%=!D%5!D%-!D%%!D%!D%!D% !D%!D%!D%!D%!D%!D%!D%!DH=1HH=1LD$LL$H$#HH$LL$LD$=LH=Q1H% 1H='HD$ 遡1H=HD$ iH$H=*1T$ H $T$ wH$H=G1T$ H $T$ Ht ։YHD$ I$HD$]H=!H!H9tH&!Ht H=!H5!H)HHH?HHtHU!HtfD=m!u+UH=B!Ht H= !dE!]wHGH(ff.@!fDHB f*ffffLBfHMt6J$fH*Y XIvJ(fH*Y uXHRHHffWH1HHHHf!f.ztH}!^!1HHHHHHHfHtfff.@USHH-q!HH[HTH]O ft'ftQfy1ftf.NaN@fuJt|0.0Ãt[u+HHInfinityFH-0.0FH-InfinitHyfF@ H+0.0F 0.0FSHH@u Hu4H!H5H)HH.HH)H@SHH1H[HtSG PfwI HsDHW>FHDuHOHD HxH9sH)HH@fHHHH)Hff.@AVAUATIUSHHt^ItTI>(111fD<.tD@f G$HGNA1fD HH[]A\A]A^A_D$Et1f} DM1DHI9}ɚ;nMf} HEE$HE7fM HHEMtYH88LHHHUHI)t8U$1ɾKfDҁɚ;v HEHI9uۉU$HH[]A\A]A^A_@FfL_1MG$IL\$AE1A$HD$8HD$tfDHD$1J|$L $LD$HfAL $LD$HWEJcH>DfU fB\$HD$$AwBD\$$E4@M-f.A @BD$Ht$HZODA1fDw fDD4$D$$E1D$ <$f} D,$EYANxt$$fAvf} x []A\A]A^Avf} ~HL[H]A\A]A^DAE#wDAdwDAE#wAeAwAtAwjf.f.&f(fT :f. ff.ATf(USH f/wfW %f/1^Hf/sLg1HH$T$JL$D$L$fT$f/M1I9YfH,ɉʉL$HH*\f/wI9vdl$L`f/vjYʺLcfS HkH,ɋT$fG$HGfO ft$1ID$f/YfS 1LcHkH,MuH H1[]A\Gf/G$HGvAfDG fw fD%1f/j@YHf/wSDE1G$HGfDO 1AVAUATUSF HfffPfHVLnIHWfOŅL9oLFoMLoIfG  t.M9l$M1AL$$MtAT$ LHLkKD[]A\A]A^C$fHCN~S1fs []A\A]A^G$1HG1f{ []A\A]A^H$Hv$LO1fK tG$fHGN~+fW <1HLk$DfG DATIUHSӺ :HvL[H]A\f[1]A\fN$tyHFH~pHVN H9ssH)HGHGH9HG1fHWfG HFHtHHHLL$AL$HH9uffDG$HGf~ fW ffG fDAWIAVIAUMATIUHSHLD$)IWH|$PE$HL$XI^HuI+_LM9VMCVH~LD$I9HIuH88HIFHH;EsRI$IOHEH4H9HKH9H)HHIHH9AD HL$XMU/@I<$H9rAD HL$P뛐IIFII$MUIFLUHHEHHDHH[]A\A]A^A_DIMUIMUAWAVAUAATIUHSHHHdH%(HD$81Ƀ1҅tOAT$ M rAfuefC$HCftAfD[ @H\$8dH3%(HqHH[]A\A]A^A_f.f_E1AHEAGt6I9D$*MD$H}I9HIFHt5E$A9D$$|1fD\$E9\$wdHH9uI9wPA1fM@fNǍDpu+AC$ HCfDS @M1fAE1ffDK AHL$ G|?EE|GHD$fEPLHHHD$ PLL$@LD$8_AXD$ HLD$(IL$L$H|$ Ht$0L$ Mt3JH9rfJH9IHBT$T$MuH9dII)IHD$I9u1HHIAD$BD$1HtnJL Hf1HHtKHAD$=ɚ;v-ʚ;DDfDNAvfDk {I)MtBD 1fAfC HC1HtT L$ 1H9HCH,@PHHLHD$ PLL$@LD$8 Y^D$ H!LD$(It$L$9r)1҉t$ H|$ J4HL$0H9nMtMAʚ;AfDJ4AH9IDHB+T$D)҉T$MuѺHH9v'HAʚ;DHH)кD$H9rE1H9@HtFHH)LH@)1At$Ht"HAt$9sɚ;fH)Ht)T M91fA} EDD1AfC EDHHHCH}DILpDLHHCHKvfDHHAD$D$H9rMLLHHL$f0 dHLHI|H& EuDA Av4 t/_uHL9wIrEM1E1Ll$JT%HL$H88HHHHMLDI9LBJ$H<$HL$ILp@$H@AfDP I@$1HSHL$HL$HD$HL$L$HaHD$<-SHD$1<+u HH90HD$1L$IHHzDLHHHHIH LHMHLA0McM)I9HLXH/HI9HH9LHuHE11<-؉$HFDADEE11E1E1HD$Hu ML|$KD HD$MLA .OHD$(E1HD$A D!E11E1EDA Av uHtHƒ v tE_HT$(>M5f.D\$E HH5HH) H81EuJ<$1ILp@$H@fX $HAE<-D$1<+u HI88E1HA1G\fL LH?HL1H)HIHHHHH9$Ht$1H9@H9v/Hw)1DIuIt Mu@1H$dH3 %(H[]A\A]A^A_DMI4MM9tL0HHHHtL<$HLHT$mHT$HD$H II^LALcMHt$L7IDH59 LAIF  LӪHD$8HXH tHXHeHHx HO H?f.MILuf(fT f.ff.zH5 L11I@H\$pM1HIH 2H H޿HfDHt$HL$0HT$(HHD$(HHH HgHt$LJI:f1LL$dH % LL$H5HHD$HIyLHIHHD$@H|$HIHHD$HIWHHHrHL$HD$PHAIFH HH9HHFH5H| HwHL$LHHHT$XL|H|$蒷=LL$LLLRI2f.JfDLHD$HT$IfDMH=HH yH LH8ޯfDH|$(辸HvIL让H5WHHͽ H81裥Ha 1$HE$HH$H$ ÒfH ^Hf/wH5;LyH50LeyfUHSHHdH%(HD$81ܦHD$ HH6H5HHHHD$ 1Hp2HD$HD$H tHD$HXHEH rHHL1聩H11HH4ٯHH|$HdHD$HL$8dH3 %(ujHH[]H\$H|fKx"HD$H H|$jH|$t H|$S1耤HHP 1ftftft HfD1HfHHP ft1fHDHDHHwfx HHHHGH@ HHDHHp$tFH@HHHHw0HHHHH9wHcHL HHDHHLff.@SHH@dH%(HD$81vH5фHHHHD$L1HRHD$HD$H upHt$H11HKHD$H u>H|$H`H|$HâHD$HL$8dH3 %(u)H@[HD$HxDHD$Hp SHH@ fHDH[ff.HHg@ fHHff.UHSH8dH%(HD$(1H5HHH$HCHfDIF1HH4HHT$HT$AV fH ff@f@ f f@7f*"HhHcH>fDH5I HQu}*"QHZhHcH>D1ҾH)HHT$HT$AV f3*t1HL$(dH3 %((H0[]A\A]A^Ð1HHHHT$fHV}fDH H@HD$(dH3%(H0HL[]A\A]A^ńDHy HuľH=a賅HHY HQ HHLHI_H HHD$(dH3%(H0HL[]A\A]A^魂D)@EЅ*H؀"H gHcH>Dqzfthf_ffHxI9~?f*"1ifffH*"HgHcH>fDfDHfH~~fHrhHDHHZ@H=_跃HHU H=_菃HHE 8H=boHH fQf*"H gHcH>1Qfs*"̃HigHcH>f~z*"HgHcH>LHMFM9LIFHt+p$A9v$wr31DDT$E9T$wrHH9uM9s3ff~*"-HgHcH>v.f6*"HChHcH>!~*"݂HhHcH>HGf>fLf<f=f*fAUIATUSHHH8dH%(HD$(1IHH$؃;t^1HHHHHEf} HD$t fA|$ uhI$HL$(dH3 %(H8[]A\A]DHtuID$HH4NH|fDHLIHHHuH HH8tDHo H$<HHDŽ$lH H H5HH81jfDH5 HjrLc 1AL$ Aff@f@ fɅ@H H5 KHHزHD$x@$HHH@fH |H$dH3%( H[]A\A]A^A_þHiHn1HHH? 1HH IMxLW|H5JHH) HHT$HHT$xH'|H5JHD$HH HHT$PHT$xH{H}HD$PHD$@H|$HD$xH@HMHD?AL$$HD$@E1ID$L4Hw)H̺HIHHH9wIL$L1HHIL'hH( LHl$@H H#{HHHHHt$HHuHt$HHLd$@HHILAPmLcMCHHHHD$XHD$xHT$@HHHD$XHD$`HD$xHD$hH\$`HD$xLS H\$hAB f HL$xLt$8LHHL$ AIfp$1Ʌt*H@H HwHHIHH9wEB$Et:IBHHIHHIHL9wH)HLl$H?H1H)I)MHT$@H|$XIl$HI0HH@LOl-H@LLd-I$LAa\kLcMZLH?HH|$`Ht$hHHD$`HD$hLP AB f:HG IHjf1f.f(fTkSD1f/f. Sq1f.E1VH|$(hHH1HH?fA!HH@LHdIIHL$ HT$pLHHD$pLHHĀ HLHhH{efD1uH | I~H5EHD$HzHHIHH$LHIHLL$H$LL$H5NEIHH$IUID$IAHHJH9HFH { H| HHLL$LLHHH$LH|$tqLL6LvHfDLhcI@Lt$8Ht$PHD$`MHT$(H|$0HH@LK|6HH;vHH H|$`HNfDH|$pvHHfDH)6H=DgHH~ HL$xHT$pHHHD$pHHz~ H%HH~fH1c1sIH5CIHHz H8HHIHH$ַHߺHHHH$贷IT$H5CHHHJH$HCHEHH9HFH| Hy HH謪HLHHH$H谏LrsoLLLtHE1kH|$3aE1HAy H5[BHH'HD$xH1@$HfP H@"tMf.f/suH蚶IH|$psHH'L`HtHHXIHHeHH$<HHDŽ$bH=AseHH1| H r.aHgx H5h=H816`H7x H5x=H81`ff.AWAVAUATIHUSHXdH%(HD$H1ZHHHD$ HEHdNHH5@HH9HCHVw HHCIHHD$(E ƒfUfKfTH}yIGH9EH5@HILCeH IGfAW PofD}$}H}rAG$IGIGfAG Q@1AG$H5= IGfAO n n1]L$`L$ff.UHSH(Ht$H|$dH%(HD$1[11HCHLq HHHHHD$\HuHuHL$dH3 %(u6H([]HуtHрHxHt̀uH_H\\ff.AWAVAUATUSHHL-s dH%(HD$81I}HI )؃CH HCH9HLp 1%[HD$ H\HD$(ADž1H=^9Y_I$HD$L|$(Hl$ MHA*^AHl$@u|HHEHL$8dH3 %(H@HH[]A\A]A^A_fHH HHq HHH@jHHHz@ pE^HEHcH>fDHn 1YHD$ HQ[HD$(u%]wiHT$(HJn\fDFH_n 18YHD$ HZHD$(ADžHcID^H^^HD$ HH|$ XLt$ UHM^Ef^HI$HL$ HD$Չt DMt$Ld$ HT$(<HL[LAA ]Lc{EHp H58H81WHT$(@ID$HHKIE0He[H56HHo H81ZWf.H5l HWEu,H|$H 8H8[HD$HH|$VHt$H HvDL(HHyn HHZDf(fT DDf.ZIE:Hn H57H81oVHHԫHHHEHHD$0iHuRHk u9Ht0Hƒt#H€H{Htf.H]H1֊H럐+ZADž>I$HD$nL|$(Hl$ MH|$(AE1(YH+YAUifDH|$(X2HEHl H5'4H81%UDEHl H5)4H81TH m HfI$HD$fHHL0HWHD$ I$HD$>fDHl HmfHD$Hh fHWSIU1$$HHktfDHl HHk HTH|$({WH|$(XHXH=c2HE1XXHEHD$H+k H52H81SHcI|tHu'&YHD$ I$HD$fDSTHD$ fUH=4SHdH%(HD$1WH=4HBo WH=4H"o Wff.n Ho   H5#4H54HFn ɏH=k4H+n Hj H0WHj H5H=;4H UH G ƒ H <  HxH54VH 4 ƒ6 H\ < t HxH53HAVH;HrH53TH;HWH5R2TH;H܇H53TH;1HXH5p3hTH;HH5`3MTH;1HQaH5N35TH;1HɆH5J3TH;1HQbH5E3TH=?3QH;H563HUH;5wH5'3UH;H53UH;H53UH;H5 3rUH; H5 3^UH;H5 3JUH;!H5 36UH;H5 3"UH;H53UH;H52TH;H52TH; H52TH; H52TH; H52TH;H52TH;H52TH;H52nTH;HH52XTH;H52DTH;HH52.TH;H52TH;HH52T H=2OHHH$oH;H5t1HSH=2|OHHH$8H;H5z2HSH;HH5`2QH;1HH5X2sQH;H$H5C2XQH;HH5,2=QH;HnH52"QH;HCH5.QH;1HH51PH;HH51PH;1HXH5.PH;1H@H51PH;1HH51PH;1HH51tPH;HH5m1YPH;HH5T1>PH;1HrTH5>1&PH;1HH5)1PH;HH5-OH;HH50OH;HH50OH;HH50OH;HH50OH;HH5-lOH;HH5?-QOH;1H%H5f09OH;1H H5T0!OH;1H%H5@0 OH;1H]H5-0NH;HH50NH;1HH50NH;HH5/NH;1HǪH5/NH;H
HH^ H8fDH^ H8H^ H8Hy^ H8H^ H8HI^ H8H9^ H8~Hq^ H8nHa^ H8H^ H8NHy^ H8Gff.AWAVAUATUHSHHHHT$HdH%(H$1HH|$H|$@tO@rHHHt3@ t-EwH/2HcH>DHuH] HH8]ODHHD$pHt$1HʚHtH fL$>HHD$HD$Hf|$>H$H\ H5&HHWL@ HHD$@A@ f:HL$XIILHL$(HL$PHHL$0fDp$1Ʌt2H@H Hw!fHHHHH9wAx$t;I@HHHpHHHHH9rH)HL4$H?H1H)I)AEMpHt$LIIH@L+Ot6H@HLd-ILAHLcMLLILLHMD$ IA@ fIG H5X HCHE H fL$>frfhf|$>HZ H|$H5#H豋1@$H@fH :HFf(fT c0f. 0f1f/Ht$ HdUH$dH3%(KH[]A\A]A^A_1HHʗD A!IH@H\HAIIVHL$(HT$0LLHD$PHH] HSLLEI>KBfD1LD$ RH eY LD$ H5"HD$HIx@LHIHHD$`LHIHHD$h–IVH5 "IHHJHD$pID$IEHH9HFH X H| HH轉LLHHHT$xLnH|$QNLD$ LL_LSI0fLH@IL|$@f|$>kIG p$tIH@HHHHf.HHHHH9wH)L$H@H\$HWHDHt$HLHD$H{H|$PRH膩I\fDH)HW H|$H5 Hu@$H@fp HD$XHHmRH=w _DHH[ HHt$XHD$XHt$HtHD$H@ fP H|$HHts@uV?HcHH|$@Lcf.1ҾHNH|$_>CHcD$>H|$@HL$XHT$PLHD$P賍H$H+Z H+H|$@HL*B1NOH{H5:IHV HH|$@HHHH$荓LHIHH$kHUH5IHHJH$IFIEHH9HFH| HwU HHdLHHHH$LhkLN+KHH[HEPH)D$H|$P,PHH=6BHX =H6U H57H81=`OAWAVAUIATUHSHxdH%(HD$h1>HD$0QL}HLHHHD$@HCAHH$f{ HD$0H-C)HD$MAEADIA I4uAcHcDH>f.L@8x ƒ.HHH< S : L?I6 .LHHA A@  DfH5yP L;tkHt$LHD$0ҭ=LH買HLnIMAmIIt ML>H5+HH!R H81:L>D$:L$f.*$'f/}f/ 'oL,O|LuHLHHHD$@I^ALHf{ H$\HQ H<$H5HqHD$0E1@$HHH@fDx jLf.HL$hdH3 %(3Hx[]A\A]A^A_DE1C ftMLH.H5T HL$8LLL$HD$8;LL$H$HP H<$H5_H蔁HKGf(9IQHH5mT HL$8HHD$8z:HLDH?HAueMI A HL$8<LHD$891H…tWH4$LYI|+<JHD$0L}HAH|$08;AAAC fLH?M#LHHwAAiA _A| >HN HH<$H5HIZf.DEQMIA  Dt LDL$:f1DL$f/@L9H$HH5 R HL$8LHD$88HL:IfDLujH8DE1LH@Dȃ!HL$8<LDL$HD$87DL$HH,M H<$H5BH~HD$0f{ HA@$H@fDh 8DAELHHA A MAD(LHHA  AZ C fgf]MM:I-A L莔HŨ u  HHH @  E 6  Ld$8<HHD$8L5DDH i A    L<LHD$8A5H f{ !LjDIQIEHJ Hf}H5{IHHD$HC PfMf6 M AAE$IEfEU ILMEHfH7Hf L<6f1f/f.A Ht]E1EfIH5M HL$8LHD$83HLH5NM HL$8LLL$HD$8V3LL$H LDLLL$5LL$LHCLLL$5LL$HD$L5HHHD$HHDI1ILO5H}LLL$,5LH4LL$HH@HH1ILLHHLHDDqMIA m HL$8<LHD$81Hf{ nVMuItA VH G HH<$H55wHBu|MIA Ht$0LH$1HT$0H$H҃A@$H@fDp LHMuItA tuLHH҃LH?IHD$(AA fcH $LL$H@HHiML%E H3Hl-HI<$&LL$HI9HHPH $HH@HHT I<$HHT$(HT$0HT$(AfffQIH{MHD$IIEH5MH|jH52HH@HH| jHLIOIL|$HHOH|$A fDIHHLWwLHgOK?H;D$vLH)L$HL|$LL!wLL1OMvH|$XMtL-H-IAE fff9H$LEhL.0f1f/zAE$IEIEfAE VAE |HC H<$H5 Hqtf{ I.kMuItA HC H5@ H81f+HCHH5N HHHHtIHHD$HmMO L虀IMuUIA u4Ht$0L-HD$0HЃHB HmLHHЃA Ht$0Lx-HD$0HЃWAE$IEfAm MQLAE$HIE MqfA} E1AE$IEfEE H<$)HH|)L%}A H3HI<$ֽHH[)LL$HLq)H.o!LO)H.MAAAE$IEfEM wMu2IuAAE$IEfEe uLHHЃkHD$aH{;{$1fAE f{ AE$IEIEAfAE DAE$IEfA] AtAAE$IEfE] fAM HC LHLUHLJ~H H5C HL$8HHD$8)HfAu "fAU A ;2L<LHD$8H)HH> H<$H5HoLH^f{ E$HEfE H9ZH+HI*HHAIIHHHI H|$0t H|$0*)L&HQ+'LL*f1f/LH?f{ E$HEfE L%H*LH?L)f1f/qLi%H*TfHHHt$Ht$aHHH can't be coerced into BigDecimalComputation results to 'NaN'(Not a Number)Computation results to 'Infinity'Computation results to '-Infinity'ERROR(VpDivd): space for remainder too small.second argument must be true or falsefirst argument for BigDecimal.mode invalidinvalid value for BigDecimal(): "%li "Conversion from String to BigDecimal overflow (last few digits discarded).load failed: invalid character in the marshaled string%li can't be coerced into BigDecimal without a precisionBigDecimal to Float conversionUndefined operation in BigDecimalCmp()Zero or negative precision for expComplex argument for BigMath.logZero or negative argument for logKeyword flag set when calling rb_scan_args, but last entry is not a hashThe last argument is nil, treating as empty keywordsUsing the last argument as keyword parameters is deprecatedThe last argument is split into positional and keyword parametersPassing the keyword argument as the last hash parameter is deprecatedcan't convert nil into BigDecimalcan't convert true into BigDecimalcan't convert false into BigDecimalcan't omit precision for a %li .wrong argument type %li (expected scalar Numeric)a non-integral exponent for a negative base%lue%zdinvalid rounding mode: nilinvalid rounding mode: %li %snegative precisionExponent overflowComputation results to 'NaN'Exponent underflowDivide by zeroargument must be positiveinvalid rounding modeexponent overflow#0divided by 0divmod-0div%zu:to_i**F<=>>=<=remainderprecision must be an Integer21E%ldsqrt of negative valuesqrt of 'NaN'(Not a Number)#1precision too large.to_strStringBigDecimal.exception_modeBigDecimal.rounding_modeBigDecimal.precision_limit.5BigDecimalallocatenewinterpret_looselydouble_fig_loadsave_exception_modesave_rounding_modesave_limit2.0.0VERSIONBASEEXCEPTION_ALLEXCEPTION_NaNEXCEPTION_INFINITYEXCEPTION_UNDERFLOWEXCEPTION_OVERFLOWEXCEPTION_ZERODIVIDEROUND_MODEROUND_UPROUND_DOWNROUND_HALF_UPROUND_HALF_DOWNROUND_CEILINGROUND_FLOORROUND_HALF_EVENSIGN_NaNSIGN_POSITIVE_ZEROSIGN_NEGATIVE_ZEROSIGN_POSITIVE_FINITESIGN_NEGATIVE_FINITESIGN_POSITIVE_INFINITESIGN_NEGATIVE_INFINITE+InfinityNANinitialize_copyprecsaddsubmulthashto_sto_intto_rsplit+-+@-@/quo%moduloclonedupto_fabssqrtfixroundfracfloorceilpower===eql?<nonzero?coerceinspectexponentsignnan?infinite?truncate_dumpBigMathexploghalf_updefaulthalf_downhalf_evenbankerceilinghalf-InfinityT68T6<88:6884684687#688\::\:::l:L::rpppppqpqpppppppprggggggTgggggggĚxxssxHԙ`[gϗԖԖԖϗۘtttttttttttttttttCHHttttttttHttttC×\\\\\\\\\\\\\\\\\+00\\\\\\\\0\\\\+{DDDDDDDDDDDDDDDDDDDDDDDDDDDDDؕD,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 1h³rwwwwwHw`ww wwwwwH  ~~~~~~~~0~~~~~& .>C]r2<?eAC;q h |  p,@ TP|@@ ` 0"""0P#X# $P$$$0%,%X@&p`(* ++0X1l124T 6 6 7 9P 0@ @G| PG G H H$ IX Jt L N O [ [ \ aPffg0@m|no@opoo0p,qPPqlq rrps@u<uhpy{P 0H   @P`p0 H 8`4`@ L  PTzRx $hFJ w?:*3$"D\xp |N$-AAF SDI\AAV0q<D`BBB D(A0l (A BBBB dBHB B(A0A8G`M 8A0A(B BBBA W 8A0A(B BBBE xSAa N b@ KAG  AAJ vAAHH PDPAa N _(ptnEAD0W AAA $`Ae J D L _(UBAA } ABD ($oEAD0X AAA h!AAK8|QDY A TAAK$pYADF ICA(vA\ C U K U K UP]U 4p"CD xAACL a<H#A D Vd\#BEB E(A0A8D 8A0A(B BBBA  8F0A(B BBBE @(c8(BAD K JBJ K ABJ L(BEE D(D0M (A BBBH \ (D BBBJ Xd)OtEA D@ h@{ FABD@xX@`+BBB A(A0 (A BBBD i (A BBBH X (A BBBA 4$,7BDD Y DBG ACB\,Hp-mBEE E(D0D8DP  8D0A(B BBBF l.BBB E(D0D8G 8A0A(B BBBK OPBuOPA|,h5BHB B(I0D8G 8A0A(B BBBA  8C0A(B BBBF : 8A0C(B BBBA $zRx ,@ ;0;oAAG F DAD QDA(0;HFAK rAB0\<FAA D0y  AABG 0<'FDC D0  AABH =D o E $>zD I 8?FEA A(F@ (A ABBG <8 AFLB H(G0 (A BBBA Hx Be BEB B(A0D8Gp 8D0A(B BBBG zRx p(: :0 xMBFN D0X  AABJ (0 MEDDP AAA \ NBGB B(A0D8G 8A0A(F BBBA s 8A0A(B BBBA J 8C0A(B BBBA  8A0A(B BBBD L RBBB E(I0A8N 8A0A(B BBBD (D pWEDGPW AAG (p WEDG`^ AAH H XgBBE E(G0C8T 8A0A(B BBBF ( ]pEDF` AAI  _GMl G F4 0_;MmL X_)H]d p_(HZ| _Oc F _EPP AI  `2El `2Hf( aEMDPj DAE ( haEMDPq DAE (H aEMDP DAE 0t `bFMA DPG  AABE ( cEMDPo DAE L pdFNB B(A0A8D 8A0A(B BBBC H$guFNB E(A0C8DPJ 8A0A(B BBBI Hpi FNB B(D0A8D 8A0A(B BBBI 8l FEA D(Hp (A ABBI 8|n FEA D(Hp (A ABBI 84Pp FEA D(Hp (A ABBI @p$rFEE A(A0Fp 0A(A BBBE LtFBB B(A0K8N 8A0A(B BBBD (yEMD0I AAG 0ylH D [ ,L8zEJ0T DI r GE l|{BBE D(K0K` 0A(A BBBB h 0G(A BBBJ  0G(A BBBJ zRx `(L$8|Lx`ttpl`h3FJA A(N` (A ABBF  (D ABBI | (L ABBK LDFBD G(DPD (G ABBI e (D ABBJ `P3FJA A(N` (A ABBF  (D ABBI | (L ABBK LЄFBD G(DPD (G ABBI e (D ABBJ L}FJA A(N` (D ABBL z (L ABBE LTFBD G(DPD (G ABBI e (D ABBJ d`FGB B(D0A8N 8D0A(B BBBO x 8A0A(B BBBF X -FGE K(A0D+ 0D(A BBBH  0A(A BBBH zRx ( HTFBB E(A0D8F 8A0A(B BBBG L؍ FEB B(A0A8J 8A0A(B BBBA L<hFGB B(K0A8D 8A0A(B BBBA (EDD@p AAA L7FBB B(A0C8D/ 8A0A(B BBBC $zRx ,D(D@ EMD0 AAH Lp0 FBB B(A0D8M 8A0A(B BBBA LwFBB E(A0D8F~ 8A0A(B BBBF $$H [GNU.." Ȳ?fVr`yQv;^UNkC-}]m!|LZC*M$fLޙt~)Ɖ`!y:sR)u =k7دmFx`Wȸ>&nצ9_{jB_]r(b*rІ-S9. ./{}1 wdBϺ?F9_g}`X86KJwt.:l^+E1 s|sIcZw#w$=eZX<=L9Cچ/fU >@Ǖ̜k6sFZv?^)?PG 4\P]F+9:dAe$ RPc{,tl63f lHϐCF ҹu.ޕC,lɇH;fOMZGxk+wm?'0g iYg q,`}3UMz~F)g}ֶ[cOu7?azr %FLwe}[o?k#Рxgl~&(K.*#.(lh^3rQY, Xas°龗M9cgnƶ)$,{džXmA[?Ƿ$a S 8F6#O`[\^p)I˔X3k䆴4$xQ~^=6'[T+騧$$#'q,@"eČ!EC}C,[o!Qƀڈw:rnQt@]eGR#QF֛ۧѸ)^ՋаnjYq}Mz^`̲8I{Z}i']le3e`^D(TPm GGG˱@[_ŷ E]'W$ DMU~G`m忞v̋{2Mj@/Ŵ9K4 NJ'[D =woRPbP^'VإSX)x 1t3ˆj~sA5*>7ԬrRߋwE$ `p(a[BOTCN}׹V*%?7;ce^a-,_v|vvE7P-*;=GZ|ys@ ={%H("CT?#P-n:CXIAQ4[6E=yW ~"Ccx3slb =-crCi^)Վx~,(#뮒s߃Ϣ(5RM#QOL8~ 8Z + #ēښavզtx;ҨUToI%@ڀ@|2-^`eeWp$dWC/z\,<#'V( Y/^ߒ8]UևwsKjH®#c KĠ`dc ~j~Ǥ՞P[@$~c-0lBb&,uBG K*6/3ɩ1}'ƲC?{ 1yuLJ~ujggC`.2XYR0?ʱgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``D(  0 8oEopT^Bhp!p!c!!n`'`'w - -D}dd pp(0000  1000000) { 8: int (* volatile tp)(void)=(int (*)(void))&t; 9: printf("%d", (*tp)()); 10: } 11: 12: return !!argv[argc]; 13: } 14: 15: int t(void) { ; return 0; } /* end */ -------------------- PKm]&ruby/ruby-lsapi-5.6/gem.build_completenu[PKm]sP.P.ruby/ruby-lsapi-5.6/lsapi.sonuȯELF>T@'@8 @HH !! !!888$$((( Std((( PtdQtdRtd!!0 0 GNUg>2:!(udl8C H‚3@(L`qCSlP*fRn}'3qѮl>&Sɶ ܮʼnSO`[is|&߱RD/y7řkՊ eY&09=By:%/=ejOzJ6'l#mNULCB1{!\$O#W23S=apbU06aD7jp#7ĴDIΊ=\4yݾCEкQuo rSѮIo|q%h6 󝵛 ' =qX[ u   f #  @ ysOT  0 [e ^k &' !{  2 RT s ? +( >n - LH  ". " "$7x WK X 6 A A. 9& 4, 2F" E9  k r G  |F PqD `%  S @ 5 Pui~ Д z@! b . p ! ] Z\ f n  @ v 1 @q Y ` pp@ @ ` rl zj U | - pr] 0  n `qY n  05 Ѓo w$ p~l! @t U U E u rS n7 `nT (   P  0|F qJ `p0 ! p}I  @  p!b g  Џ@C "! l 6 n  7 !__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizecompareValueLocationset_skip_writesigactionsigemptyset__stack_chk_failreallocfcntlacceptsetsockoptmmapmemsetsetsidread__errno_locationclosewritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemexitlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidsignalg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamdlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectrb_str_newrb_hash_asetrb_gc_markmunmaprb_string_valuerb_string_value_ptrrb_eval_string_wraprb_str_new_staticruby_strdupmkstempftruncaterb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_unexpected_typerb_obj_as_stringrb_debug_rstring_null_ptrrb_f_sprintfrb_intern2rb_funcallvs_fn_add_envrb_ruby_verbose_ptrrb_define_global_constrb_default_rsrb_exec_recursiverb_output_fsrb_output_rsrb_lastline_getInit_lsapichdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocrb_stdoutrb_stdinrb_hash_new__memcpy_chkrb_define_methodrb_define_global_functionrb_define_singleton_methodlibruby.so.3.1libm.so.6libc.so.6__environ_edata__bss_start_endGLIBC_2.14GLIBC_2.15GLIBC_2.4GLIBC_2.3.4GLIBC_2.2.5GLIBC_2.3/opt/alt/ruby31/lib64 H S ii ^ ti h ui t ii  !T!T!!!!Q!!W !^(!c0!i8!n@!tH!{P!X!`!h!p!x!!!!!!!! !!-!6!D!M!a!G!l!|! !(!0!8!@!H!P!X! `!h!'p!4x!>!J!W!g!z!!!!!!!! !!!!)!9!X!!!!X!`!h!p!x!!!!!3!!=!I!K!R!V!V!W!!!m!|!! ! ! !( !0 !8 !@ !H !P !X !` !h ! p ! x ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !( !0 !8 !@ !H !P ! X !"` !#h !p !$x !% !& ! !' !( ! !) ! ! ! !* !+ !, !- !. ! ! ! ! !/ !0 !1( !0 !28 !@ !H !4P !5X !6` !7h !8p !9x !: !< !> !? !@ !A ! !B !C !D !E !F !G ! !H ! !J !L !M !N !O !( !P0 !Q8 !@ !SH !P !TX !U` !Xh !Yp !Zx ![ !\ !] !^ ! !_ !` ! !a !b !c !d !e !f !g !h !i!!j!k!l !(!0!n8!o@!pH!qP!rX!s`!h!tp!ux!v!x!y!z!{!}!!~!!!!!!!!!!!!! !(!0!8!@!H!P!HH HtH5* %+ hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqha% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݿ D%տ D%Ϳ D%ſ D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݾ D%վ D%; D%ž D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݽ D%ս D%ͽ D%Ž D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݼ D%ռ D%ͼ D%ż D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݻ D%ջ D%ͻ D%Ż D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U DH= % f.H= H H9tH& Ht H= H5 H)HHH?HHtHm HtfD=E u+UH=J Ht H=. yd ]wff.n ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=~ D ÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH= 18tI TH=aά HcH5aHH [ÉD1?H=u 0HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHt HHtHHtH{@Ht1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDJHu4O8u ` uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=\HcB$HH@H,H9rZf.HH9vGH3LLuHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L={ L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$)KH8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L LkhfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH L$DIH f Ic LnEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcU ff.AWAVAUATUSHXHt$ HT$dH%(H$H1HIH1E1L-fHL% HHHcHcT4t/HHAAtIHJL$HL}HH=PLAH12ŃuRH=ۚ H9t Ht H1H H$ dH34%(H []A\fDT>@4 +HH5X1rrDH߹SfDHH5W1CHtvt]SHtCuWHC(H9C8tHHCpH HHHH@HCpPH1[@s뢸ff.Huu1fSHtRubHC(H9C8tH0HCpHe HHHH@HCpH{:1[1HO@H9OPv닸AWAVAUATUSHHH|I֨,aHHt$H>L{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eH=thILM)MUI9t HtDL+t$HL[]A\A]A^A_DM@@M)(IHt$HLHk8f.HAVLAUIATIUSHu\H߉KAD${LǃLSHu0{L[L]A\A]A^x;[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIHLc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAoMt$PHLIFID$PA:I|$PMMD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHA I\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1ԿHL$Aߺ訿u#DHuDo輾߻D H:DeOAkDH}An葾}N3Htff.USHdH%(H$1HHu/HUH$dH3%(uHĘ[]褿@1H= tAUATA'USH 'DNuD H@AHH> HHtH- Tڐ 9ƉljÐ *UDk H- DcEuH' H=H H~AԅLH=AH=! 褮H $@HH$HD$bDHH$$̯t 议1҃8k‰ H=8ܭHt1 Hh~ H=8貭Ht1 H>~X H=8舭HHiHǺ11諵ÃHT$ƿD$(?H5 ȱHWH Htxc@dx@D E9D E)ZfH=7贬n HK] b u T 'J 8 ' )fՅtbH H-DHH5V?1SAHc~L% HH asÅt= r u | 5 `HH5>uHH59>1U HH5A>Fff.AVIAUEATIUHSHt4Hu!(fDHHtHLGH]HuMtEL[1]A\A]A^ÐIcLLH#EgHGHHܺvT2HGAWAVAAUIATUHoSH1HGO@ƉWDW?t;AĉDHH|@D)A9rhAGt4LLHL9A?vWEfAIIIH޺@HH@ܱHLL9uA?DLHH[]A\A]A^A_鬱IATLfUHSFH?LHz?)ƒw=t19rLHfCAD$AD$ ID$071)HCHLHCP?o H{1HMHHCPH)KXH[]A\ff.fAWAVAUATUSHdH%(H$1Ht^ IAfMcg IoA_@LH#HuM(8u =9x uٽH$dH3 %( HĨ[]A\A]A^A_f~AAuIALJf8LS|xr@tPHf@HPXN MgA;G ZA9~uEo)HHcIHLDHu$85$w uAMgA9ID$,HD$HcIIDhAh(A9}A /HcIH4@H5HAIIh$A9}A HcIH4@HHAIIHl$p(ILHIILp$hMIc@o9gIcP[9SIcpG9?IcH39+IHHHHIHT$IIc@ H)IHHIHHHIHIIcHIHHHD$I9E1DL4t9dfH H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0Zv ALJt`v u Au 1LHc蟩IHIGAo IuID%u D-u B(AA1IcH4IILI 9HqH=- IJDB(9xHqH=- XIJB($AD$IKAzHL$;Mbfo/u Lt$ LAoL$AT$Ml$)$蘪 LLHL$LHLLH$ID$H$I3L$H1H D$$Dl$EDDl$âH=dt IHID%t MH=t t"LDLŃP|$WEt$A9uHt$~DŃ5s $A?D5s t AH5e)L HtHHs f)s #AH5f 1H@H5 +19LH 1HoIH521H531ݨD%r r DD$H=r IHtZEW7E1111ͤH=%3H5P*1`E|$菦M2;|$gE1H5_*LuI}臧Ń1H5!*LKfD=q -q q ED$AIFH5f)1膧HH)H5(1H1a1H5)L ܟ1H51LA#LH #3Hm w1H5^)Laff.AVAUATUSHdH%(H$1D$ HHѡ ;1Ll$Ld$Lt$ Hklrl {ul;LLD$CHp Ht@Hdp Ht{1f|$=o u|H4tH舴H0k d1H$dH3 %(u}HĠ[]A\A]A^D胜 {H5)b ,Hfы{LA;۝ff.AWAVAUATUSHD=do dH%(H$1ExH H-n H}$o ;^a DH-5o Ht 11HEDj EH$L|$PDcA:E1AfD ej EDn EtHn Ht @fLH1HIcWDHD$PHD$XA ?)ѺHH D9#11A|$MHj D9#H5n Ht @D9#5` AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$L謞H$LHHD$@菚AHLDŽ$hH$eH$LHHD$0HPH$LHHD$8#+H$`L HHD$(H$ LHHD$HٙADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%k EHl Ht H=g 1dIL9t<1ձL5EDu EME1V&Hg LH1HHc}襚}LD$LHD$PHD$X ?)ѺH1H T`1vg  8Ht$(1ҿ 荘x=_5k tH6k Ht @f,D9# DCHk Ht@Hj HtDc1DN Pf =j {H5\ HHQj Ht*Hj HB(@Haj Ht@Hj H@蛖8B-DAD9M=e 荟=fe Hi HtDHi Ht A9Hai HtD҉T$$DE ~:E~57T$$A諙A蜙AuDE UM D9vHi AHtDH5'1覞̞D$g0 H= GT$fD}蠩C1mH|$IH|$HT$Ht$1`61E Mt AMgMg{E1CCHt$1ҿ H=$)'f; >fDD$$_0d T$$WH=T$7T$fDD#AfD~g RDc EBHKg H29b {H5Y 蠔H{wH='F蜓H='0莖MAH… H{HƘlb H=ԚHt$1ҿ脒He f L=f hf HEf Gf He HtHW 11L=Gf AGHf Ht{1蝦D-a EuHe Ht!E9~za xe ;t ؕHt$@1ҿL$ْHt$01ҿȒHt$H1ҿ跒Ht$81ҿ覒Ht$(1ҿ 蕒kHLSH$&$讒L$舒yd e H="*%諚,H=%QHd Ht*fC1CD$CCӖT$HC(HC d ֒fD=d d ff.@HE` f.ffDh Hff.HV HH+HHODH1f1fATIHUSHcHHcLH:H=3h HHؔ[]A\ff.H飕HH=QU HfHH=1U ܏Hc5g ;5_ H=g |6aHvg Hrg kg HfDf?IH=T HH+9M1~+HHcHc5 g H5f ѐ~f Hfff.@HH=QT ̏tHHHDHff.HH=T 茕H] HHH=S 蜏H] HHH=S tH] HHSHH\$Ht$HEH]1H#H[ff.fAWAVAUAATIUSHH %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGNOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

Resource Limit Is Reached

The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
          QUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMEftruncate() failed. File mapping failed. Memory calloc error[...]RSTRING_PTRreplacesrandSTDERRreopennilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXRACK_ROOTchdir()to_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXX;| [e0Pp0qH@q\Pqp`qqqr`y@yt`zz{{|4}`~~Ltp@40pX Њ  , @ T h `  H \ 0 ` ` Иt 0 0x `80(0PL`pt `(<Pdx @P`pD@0\ 4H0\@pP`P $D \@tp`0`Pd 0$Ht` 4zRx $W FJ w?:*3$"Da \lpll LlsEIB E(A0z (A BBBI A (D BBBA m m@lYGJB B(A0A80F(B DBb0TtBFC G  AABK ttk(tGADJ n AAA 4tUAGK R CAG L JCG uAG] AJ $ut C KFLHvBBE A(H0H (D BBBD  (D BBBA P$wvFB A(D0D (A BBBB L(A BBBA$waAAD XAAHwBBB B(A0A8D@N 8C0A(B BBBH $`lxOAf Q C E H@xYBBB A(D0J 0A(A BBBF xzFEA C(G   (A ABBD M I c A  E M A k E E E E H V HH}FBB B(A0A8D`` 8A0A(B BBBD lx~+BBB B(A0D8JYHPC Mi 8A0A(B BBBE LTMDd86BBB B(A0A8DP 8A0A(B BBBG  8J0H(G DBBK $l7EFF IIO(40 , 4(FAA G>  AABG EO D  A @\ TXhTY|JEDԃS  ]Ph H XAH\lFBB B(A0A8LP 8A0A(B BBBH < FBB A(A0 (D BBBI \Pi`pFBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH Lh$FBB A(A0H Q D 0A(A BBBH L$HFBB B(A0A8G 8A0A(B BBBF tFTF$nCXJLlFBB B(A0A8DA 8A0A(B BBBA `( BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0 BMD GL  AABA < ,=BAA G L@I@U  AABG $ ,TWEHG ( ag H SHL FBB B(A0A8DPS 8D0A(B BBBF T bIE D(C0P (F BBBM Q(H BBBAH FBB B(A0A8DP 8A0A(B BBBA T< CBA A(G0` (A ABBD  (C ABBA J8 x-FBD D(D@T (A ABBB  l( xlECGF AAI L !cBG A(D0 (A ABBE XD0` t Z 10 pFAA G@7  AABF  \@LsL FBB B(A0A8G 8A0A(B BBBG < PP L d Hx T ` l x   |x <t FBA K(G (A ABBG <XDFEE D(D0M (C BBBB (HFBH E(A0E8I@ 8A0A(B BBBE (DFED ABH$ BBB B(A0A8G 8A0A(B BBBJ Dp|FBB A(A0G 0A(A BBBF L FBB B(A0A8G  8A0A(B BBBA 4 H\+p(BFGA kFB HUgHQ G  JWgz     > $!!o`  !.h&p oo%ooP$oD!>>?? ?0?@?P?`?p?????????@@ @0@@@P@`@p@@@@@@@@@AA A0A@APA`ApAAAAAAAAABB B0B@BPB`BpBBBBBBBBBCC C0C@CPC`CpCCCCCCCCCDD D0D@DPD`DpDDDDDDDDDEE E0E@EPE`EpEEEEEEEEEFF F0F@FPF`FpFFFFFFFFFGG G0G@GPG`GpGGGGGGGGGHH H0H@HPH`HpHHHHHHHHHII I0I@IPI`I,LSLSLSLS)9X!!GA$3a1>1 GA$3p1113TtGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1113#GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYTtGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONSlsapi.so-5.6-3.el8.x86_64.debugp 7zXZִF!t/?1]?Eh=ڊ2NuI='n_Cj7 EkcxUK^I#A!߱ZL}ހH@?T?%ٛ430kUP|m$1MzI~F/h]s'Qwr͔pهEq46莀6 _ޔ5?ko2e%A]^TЇ[JУ8qK@/f:V3(QoO#z3Ф*j7" 4<u]3'JC>ߙN\ahpbHFs 'lw+#4dp;,\j 4S.beq_I0 V3IG uɒA215~)PQqh".zdu_\,*a"uЭKV],8jq=>[Bv6=І9 z(Xp`&̘ A 5D`eΚ>5@[lEz 6RYe0[3xH=+B +4L Yq)}Ӊ~K~chIw$"B8!b΢CjV䓃= YfP S< Šm6a |,OP<$/gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``p( 0 8oP$P$Eo%%pTh&h&p^B..h>>c>> npIpI wTT#~}$$ @@p (( !!! ! ! ! ! "al L$pt%(PKm]/ss#ruby/io-console-0.5.6/io/console.sonuȯELF>#@k@8 @(Y(Y \\ \ x ]] ] 888$$YYY StdYYY Ptd@M@M@MQtdRtd\\ \ GNU0НPBz=WH!@WY[BE|qX/DoO @kx  1X;kCONUo f5w Q""h^a 3{"a, [F"r0$hb .b +hb @ Dp I__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_check_typeddatacfmakerawrb_data_typed_object_zallocrb_funcallvrb_default_rsrb_io_writerb_cIOrb_cFilerb_const_definedrb_cloexec_openrb_update_max_fdrb_class_new_instancerb_io_taint_checkrb_io_check_closedrb_str_new_staticrb_obj_freezerb_const_setrb_const_getrb_const_removerb_id2symrb_check_typerb_io_closerb_check_idrb_error_arity__stack_chk_fail__errno_locationtcsetattrrb_num2uintrb_sprintfrb_sys_failtcgetattrtcflushrb_string_value_cstrrb_intern2rb_io_get_write_iorb_ensurerb_stdinrb_stderrrb_str_catfrb_io_flushrb_convert_typerb_eArgErrorrb_raisestrlenrb_io_getbyterb_ary_newrb_ary_pushrb_str_newrb_str_new_cstrioctlrb_assoc_newrb_fix2intrb_num2intrb_Arrayrb_ary_detransientrb_protectrb_syserr_failrb_jump_tagrb_io_getsrb_yieldrb_keyword_given_prb_free_tmp_bufferrb_hash_arefrb_funcallv_publicrb_empty_keyword_given_prb_extract_keywordsrb_check_hash_typerb_warnrb_ary_resizerb_ary_ptr_use_startrb_ary_ptr_use_endrb_obj_classInitVM_consolerb_f_notimplementrb_define_module_underrb_cObjectrb_define_class_underrb_define_alloc_funcrb_undef_methodInit_consolerb_internrb_define_methodrb_define_singleton_methodlibruby.so.2.7libm.so.6libc.so.6_edata__bss_startGLIBC_2.4GLIBC_2.2.5/opt/alt/ruby27/lib64ii 7ui A\ $\ `$] ] ] K@] Kx_ _  _  _ _ !_ )_ +_ 5_ >_ L_ N_ O_ P_ V`  ` (` 0` 8` @` H` P`  X`  ``  h` p` x` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `  ` "a #a $a %a & a '(a (0a *8a ,@a -Ha .Pa /Xa 0`a 1ha 2pa 3xa 4a 6a 7a 8a 9a :a ;a <a =a ?a @a Aa Ba Ca Za Da Eb Fb Gb Hb I b J(b K0b M8b P@b QHb RPb SXb T`b UHHQE HtH5E %E hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQ%@ D%@ D%@ D%@ D%@ D%@ D%@ D%@ D%@ D%@ D%@ D%@ D%@ D%@ D%@ D%@ D%}@ D%u@ D%m@ D%e@ D%]@ D%U@ D%M@ D%E@ D%=@ D%5@ D%-@ D%%@ D%@ D%@ D% @ D%@ D%? D%? D%? D%? D%? D%? D%? D%? D%? D%? D%? D%? D%? D%? D%? D%? D%}? D%u? D%m? D%e? D%]? D%U? D%M? D%E? D%=? D%5? D%-? D%%? D%? D%? D% ? D%? D%> D%> D%> D%> D%> D%> D%> D%> D%> D%> DH=(1H\$H=(1jH=(1WfH=q> Hj> H9tHv; Ht H=A> H5:> H)HHH?HHtHu; HtfD== u+UH=b; Ht H=~8 d= ]wH"O {H g HHwH ff.@UHH518 SHHHtH xHH[]D` HH[]f.ATIH57 UHSLH57 HtooHKoP S HP0HS0@8C8H[]A\DUHSHH[C ωC Ht.UxSUxSUtC HH H[]H%7 <Kff.SH7 H<+foHP foKJfoS R HK0HJ0K8J8[ff.HH5(< H׉fDH5 < 11|ff.H8 H0mff.fAWAVAUAATUSH8dH%(HD$(1<IHoE1H8 H9u H8 HH5w; HM1ҾH="HcHl-dHHt$Hl$HD$dHHLxLH=!"fDH1 H9uH-1 H(H[]A\A]ú1@AUIATIUSHHXdH%(HD$H11uDHC0oLoKoS HD$0C8H)$H)L$)T$ D$8AHމ>HT$HdH3%(u HX[]A\A]f.SHH=1ƃS)1}H[HAUATIH=U1SHaIŅt&LH5D1)ƒA1t$؉H5$L1ÃC)1lLLAHL[]A\A]Off.@SHHH HMH t%HHu3HHPH0H[@HxuH@ H[HPH0eH6/ H5zH81ff.fAVAUATIUSHdH%(HD$1H@t.HL$dH3 %(H[]A\A]A^Htɋ uHDnAHhHELuPM%L3L}LH_HuHXHBAtD9kE |$,MH$dH3 %(H%Hĸ[]A\A]A^A_ÐHt$0LHD D$,EEwD$IPHtEELxLEwA&E9Ht$lLHDLHt$H|$HT$,D$,AHH/HXH3AfH{PH{D9Ht$lD$,D$f|$1DtfDHt$H|$HT$,E1yHHHXHA_D9kLHt$0DQ7TD$,D$Em(+AEwD$hfD AD$f.HXH{D9fH5$ E1H HH5# E1H HH5# E1H HHtjATIUSH@ts9w/[]A\f.@uHt t/Ha# HLH5 H81f1DS랐SH HHdH= 14HHyH[@SHHߺH[SHG HHH=; 1HH H[@AVAAUATAUHSHH dH%(HD$1HD$HD$AŅE~qIcH\HH\$HHD$EHt H|$yE9}D1D7FH\$HH=$ HH$H=e$ IHH H=C$ IkHHHEHE1ItLAyEHIt6LHL$*HD$HǨ-EHHtHu.EHHT$dH3%(aH []A\A]A^HH HH5 H81$@E~]HD$H\$HfDH|$H|$HbEFAH۸HDH\$HD$EH\$E%H!HOf.1 fEHfDfDIcH|HuH\$;H~Ht H|$1DMff.fAT1USH1H0dH%(HD$(1HL$HT$HH\$IHH HD$H5HM HD$ ugHHt\HƒuO urH{uCHK HAu7Ht/Hփu" u]HHHu 8RtWHt$(dH34%(HH0[]A\H5HKtDHxuH@L!HiHLlHIaHHAT$HHcHTHHUHHcHTHPG%DAUATUH1SHhdH%(HD$X1HL$HI(HXH,DcH\$HDu8LH9HDtHT$XdH3%(HuHh[]A\A]1SH1H dH%(HD$1HL$ hH5 HHIH HT$dH3%(uH [!SH1H dH%(HD$1HL$ HH nHIH5QLHT$dH3%(uH [ATIH5 UHSHH`dH%(HD$X1MHL$LoH\$)D$oH)L$ oP )T$0HP0HT$@@81҉D$HZHHHHH,HL$XdH3 %(u H`[]A\ff.AUIH5 ATAHUSHH(dH%(HD$11HL$ LDHHH*HT$dH3%(uH(H[]A\A]UHH5SHH H;$H;H%H5v H;1HH5cH;1HeH5RH;HH5?H;HH5*H;1HH5H;1HoH5sH;HH5XH;1HH5@H;1HH5(H;HH5 H;1HH5H;1HH5H;1HH5H;1HH5H;HH5lH;1HH5YzH;HH5E_H;H0H52DH;HH5!)H;HH5H;HH5H;HH5H;HH5H;H>H5H;H3H5H;HXH5lH;1H0H5TH- H;H5H6H;H1H5"H;HH5H;HH5H;H5y HQH5FHHHHH50H% H;H5;H H5HH uH= H5H= HH5CH= H0H5$H= HAH5rH=v H[H]H5J]HH=H=Hv H=AH3 H=xHH H=kH- H=\H H=NH zH=@H gH HHH/dev/tty[%dG[%d;%dHchomp![%d%cto_aryArrayexpected 2D coordinatewrong %s mode: %li screen erase[%dJline erase[%dKrawraw!cookedcooked!getchecho=echo?console_modeconsole_mode=noechowinsizewinsize=iflushioflushbeepgotocursorcursor=cursor_upcursor_downcursor_leftcursor_rightgoto_columnerase_lineerase_screenscroll_forwardscroll_backwardclear_screenpressed?check_winsize_changedgetpassconsolegeneric_readableConsoleModeinitializeinitialize_copygetcgetsclosemintimeintr__send__console-modewrong number of arguments (given %ld, expected 2 or 4)Keyword flag set when calling rb_scan_args, but last entry is not a hashUsing the last argument as keyword parameters is deprecatedThe last argument is split into positional and keyword parameterstrue or false expected as intr: %li ;= 8pD pPdxp(@D`Xl pHt @4`pp0@Lp`0Dh` ` ,L`x`p $ 8 L P 0X p 0 D p zRx $FJ w?:*3$"D\p$  0,FEKG V DAF HDA(H[FKD BAB$|XEDG EAA 4BA@Pdx HxFBB E(A0A8Dp 8A0A(B BBBK 0LIACG c FAK DCA h1Ek((HFDG sAB(TEKJp{ AAA (4oEADpV AAA xnED`W AA 8FEA D(Dn (A ABBH 0 8FAD Dpp  AABA (@=EDD c DAA lTAD H AA HHP H \LFBD A(D0S (D ABBK \ (F ABBA 8tBED C(Gu (A ABBA </Cd4XBBK E(F0i(D ABB TEB I O L @FBB D(A0D@| 0A(A BBBI (lZEDD @ DAA ($bEDD H DAA PED } AA (t`FAD s ABG 7Eb I 7Ed G  :EX C Y,:EX C YL<EX C [8l<EX C [(XqEAD U DAA HFBB E(A0A8G` 8A0A(B BBBH HBBB B(D0D8J 8A0A(B BBBB X0dDp8X|HDC S ABK @H <Ev)Ec<Ev@#BEB D(D0GP 0A(A BBBD zRx P($>0dFHA IP  AABD 8<FBA F(Dz (A ABBA _EI0J AA _EI0J AA 0 FKD I  AABA 8P yFLG A(GPI (D ABBA ( pETD 9FO ,HGNU$`$] KK!M @ I\ \ o`8  c ` P oXooo] p 0@P`p 0@P`p 0@P`p 0@P`pGA$3a1@I GA$3p1094#IGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY$IGA+GLIBCXX_ASSERTIONSconsole.so-2.7.8-141.el8.x86_64.debug w7zXZִF!t/?]?Eh=ڊ2N|>(uL$; =ֿ0T'܌ ]QBv6dUʁVqJ2l'%=A_uNXyi(KhZNmLÆ Y@F4ݧ4q;E)i38,|%VfMszX9px&5U?53~Onc @B15~b^rdCܱz4T!}n>Ppg&`$p>"t,GY&\)qf"i|i2 /@|V!?d9GD?&k|+ %EU>Y*K>2O|}˂5ږܰބ&'GgP||iFu@"*:ۈ4Wo_rcGuKX42 G\akGuM[ Em>ugu{q E >6`ΙP +-&&$Bڌ~E$45J˫8f0{lh9.(lҶz| =tWxg W$(ߟpЇizJ6n0I!nlڕK'гw= ڳ9E#А‰7T )~`sG44=b!K5 w)iԥ>!`'`(x+?'0vݔ6/%MqA~JYU)OC>8ô_!2QՇ>[`>U5ΧՆ6;3:՚ZcdIgP2.sVjg݇KHw9s׮{:juG}46(N$ɖLLg):,1a^ӭln?99amsK84 t\ "Lji3B#+5BQ}![ְqUj>[!eTT!dc8GnFL|(qi H抩YBgۧh;~i3602bl2]TcMB.pXZME Q)M-U=(@Ѝ{p>{.@{( (?oٌVM_PpܐNZEY. Eh{V_|v{pwj侶g`>2<5SY͊RCY'J89^1%aZ8I`ϼȗ{ /KDI"Z .3rgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``8( 08 8 c8oEoXX0T^BPPh@@c``nw##&}II 2II`@M@M8O8O YY \ \\ \] ] ] ]x_ x_p` `hhb hbXb`hbD d,dj+PKm]Q//ruby/openssl-2.1.4/openssl.sonuȯELF>@@P(@8 @ pp%p%h3< %%888$$ؽؽؽ Stdؽؽؽ Ptd   <<QtdRtdpp%p%GNUyRWՊ-o_z\ 0"$@@ (Q0Au  @ `BbH  P) #  @ @ !@D@@ H!D$` P"J$)@N)"DBX0!B @@@F@ H@  R`@@P @  !#%&(),./12689<@BCFKMQRSVWEKlIqη)BгZʮ9X{)NstJ+agg-(7WN/iƵQ\1b8чɌAZ)&pEtdQz KG6W6߂טm3lјS6‡NqK ߝ+&)4"vw"`Pbyl I!IeRUFԿ1>텄!vvD z^ yP=2v*b^Gu$.Sqy]eΩ+n ժm !Ip` qXo㾆ٴ78ѭdx)1H:e-&k,jbopIT g:ѫ<#I P\@|U s |0DcCE? Xv$.Sg@|YD[H.ZJ7.0Jʺ|o(4)*%T6- Iܛ{ИBE%9<~-) ͙:'9<߲G'3=_z E'D8|tX /iij`9ED{v,24"ǯMswxX-G2   DH'(!%847.<'u WlHe#/O+E J/Z 5F *,I)u  ,0J?9%_D&-%f #77"'b5DX, LE ]F"47? ?j%/C_,'V  (8y5 <=c8, w8ij(B!?7(.4'{'@*W= _):Dt\-#&`>RGs?}.*FC(3!@.&g @[EB!<UQ#H%4((6)<e!2E;E 5$'O" 8@H<&= Cp'T&HA1L $[25o=0*1<F,C34)"J!7  6E;'*-( 0" A%Z7E@$ 8K3g4wIE1k =b&+G8p*D3:GG5. *%9_/\%tt1A+`$ E;+0:[C *C @[7CIT"|3 !0*!g.m?  w(!96D=I(S h B <+h3;" >3u)1,5:;)wAy%&:@>*#2+h+B,7)/.m x$=s<z'S@Q8w 0L # RD+J*B  p)H?&.8?-"|*EG"v p-CI0,<JF(7G;  $.;#9T*B  ,24#>m2iC5j<\ D4"+6C%-<w s /  "d,KH/5= 2 ;F e f:2Z># z=k<*<+,lD1&+X46 ={4q/A>HB ,C1-{9!0<Cr/I,7F9 A@7E!Fy6 5(e&$;U/H9;I @ 0 69 /#V2q![H#W?-r,aI6a%5Dx+$AByG>^I '7-1 4=&2#h+&83Z#ES3F1X$))&C+9h/ l@?(6=(G 0/8D-47e0 ,35@v7[A_ M Cp0}& 63h5<Y%l('rE */[;-N)7* / 4 W3Hc)?2Hx>0'C :3 *E GmB<?C0 !I>>2/.V2%uC9.8<A44j=5-*~?$ ,4#-V!!@5A$>mO6kF*HA ;&.Al$pS ) .H-/( F;#PB=, e>~=5Hs(XMI%;%$8A fA6i % 0@8?-$b6*4`(& [ & I&L" { O>b8 &v$(&&A 67& @< p" p&I *& i Q@0&&8&$`&q" CL&S P l{7;&h&X" @y d^B@&*: +@&'$ C_&*&&  0V&&# > <  mC iEh&DCH&j N6&  b6 Z:(&T&'&~"P&x pd p$x&  uj 0iG &x& ~ &`1 @1B8&6 P1%H{'& m&& `QsH&> VH&Up&<&  9 =5$ (q&Gp& PNj&c  {Z&"H&L &cG&`&I%R: G `6&W0%H# ` 9& 0}-&  0> &$ ~ Q- vsd &&&/&  @b '  1&/'p&$X&*0&f&&lp&<: @d ^B$ {jn(&  "Z1&)X& bj,&?@& @)I&9 0cY&/ _ Ro `"@%He" P'Z<&I%/&H< `<jd< <6%x&8&? pj&,DX& !j&u pP T8&   B & `j) 0&Y &> 6N . P&B & : K!(& u6= Њ6 q9 @OEq'&: uIx& @&h&EP&&Q   _ /&&&)& P 1 ^&&%h&>`&x8& 2&D '_&/&__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizedOSSLrb_str_newrb_yieldrb_string_value__stack_chk_failossl_get_errorsrb_ary_newERR_error_stringrb_str_new_cstrrb_ary_pushERR_get_errorFIPS_modeossl_protect_x509_ary2skossl_x509_ary2sk0rb_protectossl_x509_ary2skrb_jump_tagossl_x509_sk2aryOPENSSL_sk_numrb_ary_new_capaOPENSSL_sk_valueossl_x509_newstderrfwrite__fprintf_chkossl_x509crl_sk2aryossl_x509crl_newossl_x509name_sk2aryossl_x509name_newossl_str_newrb_set_errinfomemcpyossl_buf2strCRYPTO_freeossl_bin2hex__assert_failossl_pem_passwd_cbrb_block_given_pPEM_def_callbackrb_warningossl_to_derrb_funcallvossl_to_der_if_possiblerb_respond_toossl_clear_errorERR_get_error_line_dataERR_clear_errorrb_warnossl_raiserb_vsprintfERR_peek_last_errorrb_exc_new_strrb_exc_raiserb_str_new_staticERR_reason_error_stringrb_str_cat_cstrrb_str_catrb_check_typeOPENSSL_sk_new_nullrb_ary_entrycX509Certrb_obj_is_kind_ofDupX509CertPtrOPENSSL_sk_pushX509_freeOPENSSL_sk_pop_freeeOSSLErrorossl_pem_passwd_valueFIPS_mode_setInit_opensslOPENSSL_init_sslrb_define_modulemOSSLrb_global_variablerb_define_constOpenSSL_versionrb_eStandardErrorrb_define_class_underrb_internInit_ossl_bnInit_ossl_cipherInit_ossl_configInit_ossl_digestInit_ossl_hmacInit_ossl_ns_spkiInit_ossl_pkcs12Init_ossl_pkcs7Init_ossl_pkeyInit_ossl_randInit_ossl_sslInit_ossl_x509Init_ossl_ocspInit_ossl_engineInit_ossl_asn1Init_ossl_kdfrb_eRuntimeErrorrb_raiserb_define_module_functionrb_string_value_cstrOBJ_txt2objeASN1Errorrb_ivar_setrb_attr_getASN1_OBJECT_freerb_usascii_str_new_staticOBJ_obj2txtrb_str_resizerb_str_set_lenrb_out_of_intOBJ_txt2nidOBJ_nid2lnOBJ_nid2sncASN1EndOfContentrb_funcallv_publicrb_intern2cASN1SetcASN1SequencecASN1GeneralizedTimecASN1UTCTimecASN1ObjectIdcASN1NullcASN1BMPStringcASN1UniversalStringcASN1GeneralStringcASN1ISO64StringcASN1GraphicStringcASN1IA5StringcASN1VideotexStringcASN1T61StringcASN1PrintableStringcASN1NumericStringcASN1UTF8StringcASN1OctetStringcASN1BitStringcASN1EnumeratedcASN1IntegercASN1Booleanrb_block_callasn1time_to_time__isoc99_sscanfrb_cTimerb_eTypeErrorasn1integer_to_numASN1_INTEGER_to_BNossl_bn_newBN_freeASN1_ENUMERATED_to_BNOBJ_createrb_num2intrb_fix2intrb_hash_lookuprb_class_superclassrb_cFalseClassrb_cIntegerrb_cNilClassrb_cFloatrb_cTrueClassrb_cSymbolASN1_object_sizeASN1_put_objectASN1_put_eocrb_convert_typerb_str_appendrb_keyword_given_prb_free_tmp_bufferrb_empty_keyword_given_prb_error_arityASN1_get_objectcASN1Datarb_obj_alloccASN1Constructiverb_int2bigd2i_ASN1_TIMEASN1_TIME_freed2i_ASN1_ENUMERATEDASN1_ENUMERATED_freed2i_ASN1_INTEGERASN1_INTEGER_freed2i_ASN1_NULLASN1_NULL_freed2i_ASN1_OBJECTOBJ_obj2nidd2i_ASN1_BIT_STRINGASN1_BIT_STRING_freeBIO_s_memBIO_newi2a_ASN1_OBJECTossl_membio2strrb_str_new_frozenossl_time_splitrb_Integerrb_num2longasn1str_to_strnum_to_asn1integerossl_bn_value_ptrBN_to_ASN1_INTEGERossl_asn1_get_asn1typeASN1_GENERALIZEDTIME_adjCRYPTO_mallocASN1_TYPE_setASN1_BIT_STRING_newASN1_BIT_STRING_setASN1_STRING_newASN1_STRING_setASN1_STRING_freeASN1_NULL_newASN1_UTCTIME_adji2d_ASN1_TYPEASN1_TYPE_freerb_str_drop_bytesrb_cArrayrb_id2symrb_define_module_undermASN1rb_ary_storerb_cObjectrb_attrrb_define_aliascASN1Primitiverb_undef_methodrb_mEnumerablerb_include_modulerb_hash_newrb_gc_register_mark_objectrb_hash_asetrb_define_methodrb_define_singleton_methodossl_obj2bioBIO_new_mem_bufBIO_ctrlBIO_freeBN_clear_freerb_check_typeddataBN_num_bitsBN_bn2binrb_memhashrb_alloc_tmp_buffereBNErrorrb_obj_classrb_data_typed_object_wrapBN_newossl_bn_ctxBN_sqrBN_bn2hexrb_cstr_to_inumBN_is_zeroBN_is_negativecBNBN_dupBN_set_negativeBN_is_oddBN_is_oneBN_cmpBN_bin2bnrb_absint_sizerb_integer_packrb_alloc_tmp_buffer_with_countBN_copyBN_hex2bnrb_string_value_ptrBN_mpi2bnBN_dec2bnrb_eArgErrorBN_is_bit_setBN_set_bitBN_clear_bitBN_mask_bitsBN_lshiftBN_rshiftBN_pseudo_randBN_randBN_is_prime_fasttest_exBN_is_prime_exstrlenBN_bn2decBN_bn2mpirb_assoc_newBN_mod_inverseBN_generate_prime_exBN_pseudo_rand_rangeBN_rand_rangeBN_ucmpBN_gcdBN_mod_expBN_expBN_mod_sqrBN_mod_mulBN_mod_subBN_mod_addBN_divrb_ary_new_from_argsBN_mulBN_subBN_addrb_error_frozen_objectBN_CTX_newrb_define_alloc_funcEVP_CIPHER_CTX_freeEVP_CIPHER_CTX_newEVP_get_cipherbynameEVP_CipherInit_exeCipherErrorEVP_CIPHER_CTX_cipherEVP_CIPHER_flagsEVP_CIPHER_CTX_iv_lengthEVP_CIPHER_CTX_get_app_dataEVP_CIPHER_CTX_key_lengthEVP_CIPHER_CTX_ctrlEVP_CIPHER_CTX_block_sizeEVP_CipherFinal_exEVP_CipherUpdaterb_eRangeErrorossl_evp_get_digestbynameEVP_BytesToKeyOPENSSL_cleanseEVP_md5OBJ_NAME_do_all_sortedEVP_CIPHER_CTX_copyEVP_CIPHER_nidEVP_CIPHER_CTX_set_key_lengthEVP_CIPHER_CTX_set_paddingEVP_CIPHER_CTX_set_app_datarb_class_path__memcpy_chkossl_evp_get_cipherbynamecCipherossl_cipher_newDupConfigPtrcConfigNCONF_newNCONF_load_bioNCONF_freeeConfigErrorCONF_get1_default_config_fileEVP_MD_CTX_freeEVP_MD_CTX_mdEVP_MD_sizeEVP_DigestFinal_exeDigestErrorEVP_MD_CTX_copyEVP_MD_CTX_newEVP_DigestInit_exossl_digest_updateEVP_DigestUpdateEVP_MD_typeEVP_MD_block_sizeEVP_get_digestbynameossl_digest_newcDigestrb_path2classrb_define_private_methodENGINE_freeENGINE_get_cmd_defnsENGINE_ctrl_cmd_stringeEngineErrorENGINE_load_public_keyossl_pkey_newENGINE_load_private_keyrb_iv_setENGINE_get_firstENGINE_up_refENGINE_get_nextOPENSSL_init_cryptoENGINE_load_builtin_enginesENGINE_by_idENGINE_initENGINE_ctrlENGINE_get_nameENGINE_get_idrb_sprintfENGINE_set_defaultENGINE_get_digestENGINE_get_cipherENGINE_finishcEnginerb_undef_alloc_funcHMAC_CTX_freeeHMACErrorHMAC_CTX_newHMAC_CTX_copyHMAC_FinalHMAC_UpdateHMAC_Init_excHMACrb_get_kwargsEVP_PKEY_CTX_new_idEVP_PKEY_derive_initEVP_PKEY_CTX_ctrlEVP_PKEY_deriveEVP_PKEY_CTX_freerb_extract_keywordsrb_check_hash_typePKCS5_PBKDF2_HMACEVP_PBE_scryptrb_num2ulongNETSCAPE_SPKI_freeeSPKIErrori2d_NETSCAPE_SPKIeX509CertErrorNETSCAPE_SPKI_b64_decoded2i_NETSCAPE_SPKIGetPKeyPtrossl_pkey_check_public_keyNETSCAPE_SPKI_verifyGetPrivPKeyPtrNETSCAPE_SPKI_signNETSCAPE_SPKI_set_pubkeyNETSCAPE_SPKI_get_pubkeyNETSCAPE_SPKI_printNETSCAPE_SPKI_b64_encodeNETSCAPE_SPKI_newmNetscapecSPKIi2d_OCSP_CERTIDeOCSPErrorOCSP_CERTID_freeOCSP_id_get0_infod2i_OCSP_CERTIDGetX509CertPtrOCSP_cert_to_idOCSP_CERTID_dupi2d_OCSP_SINGLERESPOCSP_SINGLERESP_freed2i_OCSP_SINGLERESPOCSP_SINGLERESP_itASN1_item_dupi2d_OCSP_BASICRESPOCSP_BASICRESP_freeOCSP_BASICRESP_itOCSP_basic_add1_nonceOCSP_REQUEST_freeOCSP_REQUEST_itd2i_OCSP_BASICRESPi2d_OCSP_RESPONSEOCSP_RESPONSE_freeOCSP_RESPONSE_itd2i_OCSP_RESPONSEi2d_OCSP_REQUESTOCSP_request_onereq_countcOCSPCertIdOCSP_request_onereq_get0OCSP_onereq_get0_idOCSP_request_add0_idOCSP_request_add1_nonced2i_OCSP_REQUESTOCSP_id_issuer_cmpOCSP_id_cmpOCSP_resp_countOCSP_resp_get0OCSP_single_get0_statusOCSP_SINGLERESP_get0_idOCSP_SINGLERESP_get_ext_countOCSP_SINGLERESP_get_extossl_x509ext_newcOCSPSingleResOCSP_resp_findOCSP_CERTID_newOCSP_SINGLERESP_newOCSP_copy_nonceOCSP_BASICRESP_newcOCSPBasicResOCSP_response_get1_basicOCSP_response_statusOCSP_response_status_strOCSP_RESPONSE_newOCSP_check_nonceOCSP_REQUEST_newOCSP_request_is_signedOCSP_response_createX509_gmtime_adjossl_x509_time_adjustrb_check_array_typecX509ExtOCSP_basic_add1_statusGetX509ExtPtrOCSP_SINGLERESP_add_extOCSP_check_validityGetX509StorePtrOCSP_request_verifyOCSP_basic_verifyOCSP_basic_signEVP_sha1OCSP_request_signmOCSPcOCSPReqcOCSPResi2d_PKCS12ePKCS12ErrorPKCS12_freed2i_PKCS12_bioERR_set_markPKCS12_parseERR_pop_to_markd2i_PKCS12ASN1_dupPKCS12_newcPKCS12PKCS12_createPKCS7_RECIP_INFO_freePKCS7_SIGNER_INFO_freei2d_PKCS7ePKCS7ErrorPKCS7_freePKCS7_verifyERR_peek_errorrb_iv_getPKCS7_dataInitBIO_writeBIO_readPKCS7_dataFinalBIO_free_allPKCS7_content_newd2i_PKCS7_RECIP_INFOi2d_PKCS7_RECIP_INFOcPKCS7RecipientPKCS7_RECIP_INFO_newPKCS7_get_signer_infod2i_PKCS7_SIGNER_INFOi2d_PKCS7_SIGNER_INFOcPKCS7SignerPKCS7_SIGNER_INFO_newPEM_read_bio_PKCS7d2i_PKCS7_bioPKCS7_dupPKCS7_RECIP_INFO_setPKCS7_get_signed_attributePKCS7_SIGNER_INFO_setPEM_write_bio_PKCS7X509_CRL_freeOPENSSL_sk_popGetX509CRLPtrPKCS7_add_crlPKCS7_add_certificatePKCS7_add_recipient_infoPKCS7_add_signerOBJ_nid2objPKCS7_add_signed_attributePKCS7_set_cipherPKCS7_ctrlstrcmprb_sym2strPKCS7_set_typePKCS7_newcPKCS7SMIME_read_PKCS7PKCS7_decryptEVP_rc2_40_cbcPKCS7_encryptPKCS7_signSMIME_write_PKCS7rb_thread_check_intsEVP_PKEY_freeEVP_PKEY_base_idossl_ec_newossl_rsa_newossl_dh_newossl_dsa_newcPKeyossl_evp_pkey_typerb_obj_is_instance_ofEVP_PKEY_newePKeyErrorossl_generate_cb_2BN_GENCB_get_argrb_thread_call_with_gvlossl_generate_cb_stopd2i_PrivateKey_bioPEM_read_bio_PrivateKeyd2i_PUBKEY_bioPEM_read_bio_PUBKEYEVP_PKEY_missing_parametersEVP_PKEY_get0EC_KEY_get0_public_keyRSA_get0_keyDSA_get0_keyDH_get0_keyEVP_VerifyFinalEVP_PKEY_sizeEVP_SignFinalDupPKeyPtrEVP_PKEY_up_refmPKeyInit_ossl_rsaInit_ossl_dsaInit_ossl_dhInit_ossl_ecEVP_PKEY_get0_DHDH_get0_pqgDH_set0_keyDH_set0_pqgDH_sizeeDHErrorDHparams_dupEVP_PKEY_assigni2d_DHparamsPEM_write_bio_DHparamsDHparams_printDH_generate_parameters_exDH_newBN_GENCB_newBN_GENCB_setrb_thread_call_without_gvlBN_GENCB_freeDH_generate_keyDH_freeDH_checkDH_get0_enginePEM_read_bio_DHparamsd2i_DHparamsASN1_d2i_biocDHEVP_PKEY_get0_DSADSA_get0_pqgDSA_set0_keyDSA_set0_pqgeDSAErrord2i_DSAPrivateKeyi2d_DSAPrivateKeyi2d_DSA_PUBKEYPEM_write_bio_DSAPrivateKeyPEM_write_bio_DSA_PUBKEYDSA_printDSA_generate_parameters_exDSA_newDSA_generate_keyDSA_freePEM_read_bio_DSAPrivateKeyPEM_read_bio_DSA_PUBKEYd2i_DSAPrivateKey_biod2i_DSA_PUBKEY_biod2i_DSAPublicKeyPEM_ASN1_read_bioi2d_DSAPublicKeycDSAEC_GROUP_clear_freeEC_POINT_clear_freeEC_POINT_is_on_curvecEC_POINTeEC_GROUPeEC_POINTrb_obj_dupEC_POINT_dupEC_POINT_newEC_POINT_oct2pointEC_POINT_bn2pointEC_POINT_freePEM_write_bio_ECPKParametersi2d_ECPKParametersASN1_i2d_bioeECErrorEC_GROUP_set_seedrb_sym2idEC_GROUP_new_curve_GFpcEC_GROUPEC_GROUP_dupPEM_read_bio_ECPKParametersEC_GFp_nist_methodEC_GROUP_newd2i_ECPKParametersOBJ_sn2nidEC_GROUP_new_by_curve_nameEC_GROUP_set_asn1_flagEC_GROUP_set_point_conversion_formEC_GFp_simple_methodEC_GFp_mont_methodEVP_PKEY_get0_EC_KEYEC_KEY_printEC_KEY_check_keyEC_KEY_get0_private_keyPEM_write_bio_ECPrivateKeyi2d_ECPrivateKey_bioPEM_write_bio_EC_PUBKEYi2d_EC_PUBKEY_bioECDSA_verifyECDSA_sizeECDSA_signECDH_compute_keyEC_KEY_set_public_keyEC_KEY_set_private_keyEC_KEY_set_groupEC_KEY_dupEC_KEY_freeEC_KEY_newEC_KEY_new_by_curve_nameEC_KEY_set_asn1_flagEC_KEY_set_conv_formcECPEM_read_bio_ECPrivateKeyPEM_read_bio_EC_PUBKEYd2i_ECPrivateKey_biod2i_EC_PUBKEY_bioEC_get_builtin_curvesEC_POINT_point2octEC_POINT_set_to_infinityEC_POINT_invertEC_POINT_make_affineEC_POINT_is_at_infinityECPKParameters_printEC_GROUP_get_degreeEC_GROUP_get_seed_lenEC_GROUP_get0_seedEC_GROUP_get_point_conversion_formEC_GROUP_get_asn1_flagEC_GROUP_get_curve_nameEC_GROUP_get_cofactorEC_GROUP_get_orderEC_GROUP_set_generatorEC_GROUP_cmpEC_POINT_cmpEC_KEY_generate_keyEC_POINT_mulrb_ary_tmp_newEC_POINTs_mulruby_malloc_size_overflowEC_GROUP_get0_generatorEC_KEY_get0_groupEVP_PKEY_get0_RSARSA_get0_factorsRSA_get0_crt_paramsRSA_set0_crt_paramsRSA_set0_factorsRSA_set0_keyi2d_RSAPrivateKeyi2d_RSA_PUBKEYeRSAErrorPEM_write_bio_RSAPrivateKeyPEM_write_bio_RSA_PUBKEYRSA_printd2i_RSAPrivateKeyRSA_generate_key_exRSA_newRSA_freeRSAPublicKey_dupEVP_DigestVerifyInitRSA_pkey_ctx_ctrlEVP_DigestVerifyFinalRSA_sizeRSA_public_encryptRSA_public_decryptRSA_private_decryptRSA_private_encryptPEM_read_bio_RSAPrivateKeyPEM_read_bio_RSA_PUBKEYd2i_RSAPrivateKey_biod2i_RSA_PUBKEY_bioPEM_read_bio_RSAPublicKeyd2i_RSAPublicKey_bioEVP_DigestSignInitEVP_DigestSignFinalcRSARAND_statusrb_num2dblRAND_addRAND_seedRAND_byteseRandomErrorRAND_load_fileRAND_write_filemRandomSSL_freeSSL_get_ex_datarb_gc_markSSL_CIPHER_get_nameSSL_CIPHER_get_versionSSL_CIPHER_get_bitsossl_ssl_typeSSL_get_fdrb_io_taint_checkrb_io_check_closedrb_io_check_readablerb_io_check_writableSSL_set_fdSSL_CTX_freeSSL_CTX_get_ex_dataSSL_CTX_flush_sessionsSSL_CTX_ctrlSSL_get_servernameSSL_get_ex_data_X509_STORE_CTX_idxX509_STORE_CTX_get_ex_dataossl_verify_cb_callSSL_is_serverX509_STORE_CTX_get_error_depthX509_STORE_CTX_set_errorX509_STORE_CTX_get_current_certmSSLcSSLSessionossl_ssl_session_typerb_during_gcSSL_SESSION_up_refX509_get_pubkeyEVP_PKEY_cmpSSL_CTX_use_certificateSSL_CTX_use_PrivateKeySSL_CTX_get_security_levelSSL_CTX_get_ciphersSSL_CTX_get_optionsrb_uint2bigSSL_get0_next_proto_negotiatedSSL_get0_alpn_selectedSSL_ctrlSSL_get_client_CA_listSSL_get_verify_resultSSL_set_sessionSSL_session_reusedSSL_pendingSSL_state_stringrb_ruby_verbose_ptrSSL_state_string_longSSL_get_current_cipherSSL_get_versionSSL_get_peer_cert_chainSSL_get_peer_certificateSSL_get_certificateSSL_shutdownrb_hash_lookup2SSL_writeSSL_get_errorrb_io_wait_writable__errno_locationrb_funcallv_kwrb_io_wait_readablerb_sys_failX509_verify_cert_error_stringSSL_acceptSSL_connectSSL_CTX_clear_optionsSSL_CTX_set_optionsSSL_CTX_add_sessionSSL_CTX_set_cipher_listrb_StringTLS_methodSSL_CTX_newSSL_CTX_set_ex_dataSSL_CTX_set_security_levelSSL_CTX_remove_sessionstrncmprb_str_unlocktmprb_str_modifyrb_str_modify_expandrb_str_locktmpSSL_readrb_eof_errorSSL_CTX_set_tmp_dh_callbackSSL_CTX_set_cert_storeX509_STORE_up_refSSL_CTX_check_private_keySSL_CTX_add_client_CASSL_CTX_set_verifySSL_CTX_set_timeoutSSL_CTX_set_verify_depthSSL_CTX_set_next_protos_advertised_cbSSL_CTX_set_alpn_protosrb_obj_freezeSSL_CTX_set_session_id_contextSSL_CTX_callback_ctrlSSL_CTX_sess_set_new_cbSSL_CTX_sess_set_get_cbSSL_CTX_sess_set_remove_cbSSL_CTX_set_client_cert_cbSSL_CTX_load_verify_locationsSSL_CTX_set_alpn_select_cbSSL_CTX_set_next_proto_select_cbcSSLContextSSL_newSSL_set_ex_dataSSL_set_info_callbackrb_call_superSSL_set_SSL_CTXCRYPTO_get_ex_new_indexrb_mWaitReadablerb_mWaitWritableInit_ossl_ssl_sessioncSSLSocketSSL_SESSION_freei2d_SSL_SESSIONd2i_SSL_SESSIONPEM_read_bio_SSL_SESSIONSSL_get1_sessionSSL_SESSION_newSSL_SESSION_printSSL_SESSION_get_idSSL_SESSION_get_timeoutSSL_SESSION_set_timeoutSSL_SESSION_get_timeSSL_SESSION_set_timeSSL_SESSION_get_protocol_versionCRYPTO_memcmpPEM_write_bio_SSL_SESSIONX509_time_adj_exmX509Init_ossl_x509attrInit_ossl_x509certInit_ossl_x509crlInit_ossl_x509extInit_ossl_x509nameInit_ossl_x509reqInit_ossl_x509revokedInit_ossl_x509storeX509_get_default_cert_areaX509_get_default_cert_dirX509_get_default_cert_fileX509_get_default_cert_dir_envX509_get_default_cert_file_envX509_get_default_private_dirX509_ATTRIBUTE_freei2d_X509_ATTRIBUTEeX509AttrErrorX509_ATTRIBUTE_countX509_ATTRIBUTE_get0_typei2d_ASN1_SET_ANYOPENSSL_sk_freeASN1_TYPE_getX509_ATTRIBUTE_set1_dataX509_ATTRIBUTE_get0_objectX509_ATTRIBUTE_create_by_OBJX509_ATTRIBUTE_dupd2i_X509_ATTRIBUTEX509_ATTRIBUTE_set1_objectX509_ATTRIBUTE_newossl_x509attr_newcX509AttrGetX509AttrPtrX509_EXTENSION_freeX509_delete_extX509_add_exti2d_X509X509_dupPEM_read_bio_X509d2i_X509_bioX509_newX509_cmpX509_get_ext_countX509_get_extX509_check_private_keyX509_verifyX509_signX509_set_pubkeyX509_set1_notAfterX509_get0_notAfterX509_set1_notBeforeX509_get0_notBeforeGetX509NamePtrX509_set_issuer_nameX509_get_issuer_nameX509_set_subject_nameX509_get_subject_nameX509_get_serialNumberX509_set_serialNumberX509_get0_tbs_sigalgX509_set_versionX509_get_versionX509_printPEM_write_bio_X509X509_up_refX509_CRL_delete_extX509_CRL_add_exteX509CRLErrorcX509RevX509_CRL_get_REVOKEDX509_REVOKED_freeDupX509RevokedPtrX509_CRL_add0_revokedX509_CRL_sortossl_x509revoked_newX509_CRL_get0_signatureX509_CRL_dupPEM_read_bio_X509_CRLd2i_X509_CRL_bioX509_CRL_newX509_CRL_get_ext_countX509_CRL_get_extX509_CRL_printPEM_write_bio_X509_CRLi2d_X509_CRL_bioX509_CRL_verifyX509_CRL_signX509_CRL_set1_nextUpdateX509_CRL_get0_nextUpdateX509_CRL_set1_lastUpdateX509_CRL_get0_lastUpdateX509_CRL_set_issuer_nameX509_CRL_get_issuerX509_CRL_set_versionX509_CRL_get_versioncX509CRLi2d_X509_EXTENSIONeX509ExtErrorX509_EXTENSION_get_objectX509_EXTENSION_get_dataASN1_OCTET_STRING_setX509_EXTENSION_dupd2i_X509_EXTENSIONOBJ_ln2nidX509V3_set_nconfX509V3_EXT_nconf_nidX509V3_EXT_printASN1_STRING_printX509_EXTENSION_get_criticalX509_EXTENSION_set_objectGetX509ReqPtrX509V3_set_ctxX509_EXTENSION_newX509_EXTENSION_set_criticalcX509ExtFactoryX509_NAME_freei2d_X509_NAMEeX509NameErrorX509_NAME_entry_countX509_NAME_ENTRY_get_dataX509_NAME_get_entryX509_NAME_ENTRY_get_objecti2t_ASN1_OBJECTX509_NAME_print_exrb_utf8_encindexrb_enc_associate_indexrb_utf8_encodingrb_enc_sprintfX509_NAME_dupcX509Namerb_const_getd2i_X509_NAMEX509_NAME_newX509_NAME_cmpX509_NAME_onelineX509_NAME_hash_oldX509_NAME_hashX509_NAME_add_entry_by_txtrb_mComparablerb_hash_set_ifnoneX509_REQ_freeX509_REQ_delete_attrX509_REQ_add1_attreX509ReqErrorX509_REQ_get0_signaturei2d_X509_REQX509_REQ_dupPEM_read_bio_X509_REQd2i_X509_REQ_bioX509_REQ_get_attr_countX509_REQ_get_attrX509_REQ_verifyX509_REQ_signX509_REQ_set_pubkeyX509_REQ_get_pubkeyX509_REQ_set_subject_nameX509_REQ_get_subject_nameX509_REQ_set_versionX509_REQ_printPEM_write_bio_X509_REQX509_REQ_newX509_REQ_get_versioncX509Reqi2d_X509_REVOKEDeX509RevErrorX509_REVOKED_delete_extX509_REVOKED_add_extX509_REVOKED_dupX509_REVOKED_get_ext_countX509_REVOKED_get_extX509_REVOKED_set_revocationDateX509_REVOKED_get0_revocationDateX509_REVOKED_set_serialNumberX509_REVOKED_get0_serialNumberX509_REVOKED_newX509_STORE_CTX_get0_untrustedX509_STORE_CTX_get0_certX509_STORE_CTX_freeX509_STORE_freeX509_STORE_get_ex_dataX509_LOOKUP_fileX509_STORE_add_lookupX509_LOOKUP_ctrleX509StoreErrorX509_LOOKUP_hash_dircX509StoreContextX509_STORE_CTX_get_errorX509_STORE_CTX_set_timeX509_STORE_CTX_initX509_STORE_CTX_set_flagsX509_STORE_CTX_get0_current_crlX509_STORE_CTX_get0_chainrb_block_procX509_STORE_CTX_set_ex_dataX509_verify_certX509_STORE_CTX_newX509_STORE_add_crlX509_STORE_add_certX509_STORE_set_default_pathsX509_STORE_set_flagsX509_STORE_set_ex_dataX509_STORE_set_verify_cbX509_STORE_newX509_STORE_set_trustX509_STORE_set_purposeX509_STORE_CTX_set_purposeX509_STORE_CTX_set_trustX509_STORE_CTX_get0_storecX509Storelibruby.so.2.7libssl.so.1.1libcrypto.so.1.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.3.4GLIBC_2.4GLIBC_2.7GLIBC_2.14GLIBC_2.2.5OPENSSL_1_1_0OPENSSL_1_1_1/opt/alt/ruby27/lib64  I`ti Iii Jii  JJui !JI m-JIm;Jm-Jp%0x%%%%g%%`%7`%_p%V%%` %x0% o%%І%y% @%P%З%%%%`%p%@%% %j0%0%%@%%p@%nP%%%F%%F`%Sp%%%%%%%% %(%0%%x%%o %1@%3 P%0>% %R%%@o`%p%e%D%x %0%`%%`%%%@@%H%P%%%%:%B%M%Z%*%_ %q0%z@%P%`%p%%%%%%%%%%% %#0%3@%AP%M`%[p%k%|%T%T% %%%%%%%%%%`%H%%h%N%N%,%,%%%(%%&P%&%%%%%%%%(%p%8%h%H%%X% % h%%%%%%%%%%%(%%%%M%6%/%a %e(%f0%m8%@%9H%P%sX%`%h%p%x%%%%%%%%%%C%%%%%%%%F%%% %(%0%H8%@%RH%X%K`%p%x%%%%B%%1%%r%%%2% %%'% %0%8%@%H%P%X%`%h%p%x%%%W%D%%)%E%#%%%%%%I%(%%O% %(%0%8%[@%@H%eP%nX%zh%p%x%%%.%%%%A%%%%%%Q%%>%%%$ %"(%V0%8%@%9H%BP%X%`%Jh%x%[%%%g%h%%p%5%x%%P%%% %(%0%8%@%H%%P%X%`% h% p%<x% % % %%%%%%%%%%%%%%%%% %! %"(%#0%$8%%@%&H%P%'X%)`%*h%+p%,x%-%.%/%0%1%2%3%4%5%6%7%8%9%:%;%<%=%%>%?% %@(%A0%B8%C@%DH%EP%FX%G`%Hh%Ip%Jx%K%L%N%O%P%Q%R%S%T%U%V%W%X%Y%Z%[%\%]%^%_%` %b(%c0%8%d@%eH%fP%gX%h`%ih%jp%kx%l%m%n%o%p%q%r%t%u%v%w%x%y%z%{%|%}%~%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%%%%%%%%%%%% %(%0%8%=@%H%P%X%`%h%p%x%%%%%%%%%%%%%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%%%%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%G%%%%%%%%%%%%%%% %(%0%8%@%H%P%X%`% h% p% x% % %%%%%%%%%%S%%%%%%%%% %(%0% 8%!@%"H%#P%$X%%`%&h%'p%x%(%)%*%+%,%-%.%/%0%1%2%3%4%5%6%7%8%9%:%;% %<(%=0%>8%?@%@H%AP%BX%C`%Dh%p%Ex%:%F%%G%H%I%M%J%%K%L%M%N%O%P%Q%R%S%T%U%V %W(%X0%Y8%Z@%[H%\P%]X%^`%_h%`p%ax%b%c%d%e%f%g%h%i%j%k%l%m%n%o%p%%q%s%t%u%v %w(%x0%!8%y@%zH%{P%|X%}`%~h%p%x%;%%%%%%%%%%%%%%%%%%%% %(%0%"8%@%H%P%X%`%h%p%x%%%%%%%%%%%%%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%%%%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%%%%%%%%%%%% % (%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%%%%% %% % % % %% %(%0%8%@%H%P%X%`%h%p%x%8%%%%% %3%!%0%"%#%$%%%&%'%)%*%%+%,%- %.(%/0%08%1@%2H%3P%4X%5`%6h%7p%x%8%9%:%;%<%=%>%?%@%A%B%C%D%E%%F%G%H%% %I %J(%K0%L8%M@%NH%OP%PX%Q`%h%Rp%Sx%T%U%V%W%X%Y%Z%\%]%^%_%`%a%b%c%d%e%f%g%h%i %j(%k0%l8%m@%oH%pP%qX%r`%sh%tp%ux%v%w%x%y%{%|%}%~%%%%%%%%%(%%%% %(%0%8%@%H%7P%X%`%h%p%x%%%%%.%%%%%%%%%%%%% %%%U %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%%%%%%%%%%%% %(%0%*8%@%H%P%X%`%h%p%x%%%%%%%%%%%%%%%%%%%%% %(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%%%%%%%%%%%% %(%0%8%@% H% P% X% `% h%p%x%%%%%%%%%%%%%%%%% %!%#%%$ %(%%0%&8%'@%(H%)P%X%*`%+h%p%,x%-%.%/%0%1%2%3%4%5%%6%7%8%:%;%<%=%>%?%@%A %L(%C0%D8%E@%FH%GP%X%H`%Ih%Jp%Kx%L%M%N%O%P%%Q%R%S%T%U%V%W%X%Y%Z%?%\%]%^%_ %4(%`0%a8%b@%cH%dP%X%e`%fh%p%+x%i%j%k%l%m%n%o%q%r%s%-%t%u%v%w%y%z%%{%|%} %~(%0%8%@%H%P%X%`%h%p%x%%%%%%%%%%%%HH$HtH5ҥ$%ӥ$hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhq%Mj$D%Ej$D%=j$D%5j$D%-j$D%%j$D%j$D%j$D% j$D%j$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%i$D%}i$D%ui$D%mi$D%ei$D%]i$D%Ui$D%Mi$D%Ei$D%=i$D%5i$D%-i$D%%i$D%i$D%i$D% i$D%i$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%h$D%}h$D%uh$D%mh$D%eh$D%]h$D%Uh$D%Mh$D%Eh$D%=h$D%5h$D%-h$D%%h$D%h$D%h$D% h$D%h$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%g$D%}g$D%ug$D%mg$D%eg$D%]g$D%Ug$D%Mg$D%Eg$D%=g$D%5g$D%-g$D%%g$D%g$D%g$D% g$D%g$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%f$D%}f$D%uf$D%mf$D%ef$D%]f$D%Uf$D%Mf$D%Ef$D%=f$D%5f$D%-f$D%%f$D%f$D%f$D% f$D%f$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%e$D%}e$D%ue$D%me$D%ee$D%]e$D%Ue$D%Me$D%Ee$D%=e$D%5e$D%-e$D%%e$D%e$D%e$D% e$D%e$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%d$D%}d$D%ud$D%md$D%ed$D%]d$D%Ud$D%Md$D%Ed$D%=d$D%5d$D%-d$D%%d$D%d$D%d$D% d$D%d$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%c$D%}c$D%uc$D%mc$D%ec$D%]c$D%Uc$D%Mc$D%Ec$D%=c$D%5c$D%-c$D%%c$D%c$D%c$D% c$D%c$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%b$D%}b$D%ub$D%mb$D%eb$D%]b$D%Ub$D%Mb$D%Eb$D%=b$D%5b$D%-b$D%%b$D%b$D%b$D% b$D%b$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%a$D%}a$D%ua$D%ma$D%ea$D%]a$D%Ua$D%Ma$D%Ea$D%=a$D%5a$D%-a$D%%a$D%a$D%a$D% a$D%a$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%`$D%}`$D%u`$D%m`$D%e`$D%]`$D%U`$D%M`$D%E`$D%=`$D%5`$D%-`$D%%`$D%`$D%`$D% `$D%`$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%_$D%}_$D%u_$D%m_$D%e_$D%]_$D%U_$D%M_$D%E_$D%=_$D%5_$D%-_$D%%_$D%_$D%_$D% _$D%_$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%^$D%}^$D%u^$D%m^$D%e^$D%]^$D%U^$D%M^$D%E^$D%=^$D%5^$D%-^$D%%^$D%^$D%^$D% ^$D%^$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%]$D%}]$D%u]$D%m]$D%e]$D%]]$D%U]$D%M]$D%E]$D%=]$D%5]$D%-]$D%%]$D%]$D%]$D% ]$D%]$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%\$D%}\$D%u\$D%m\$D%e\$D%]\$D%U\$D%M\$D%E\$D%=\$D%5\$D%-\$D%%\$D%\$D%\$D% \$D%\$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%[$D%}[$D%u[$D%m[$D%e[$D%][$D%U[$D%M[$D%E[$D%=[$D%5[$D%-[$D%%[$D%[$D%[$D% [$D%[$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%Z$D%}Z$D%uZ$D%mZ$D%eZ$D%]Z$D%UZ$D%MZ$D%EZ$D%=Z$D%5Z$D%-Z$D%%Z$D%Z$D%Z$D% Z$D%Z$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%Y$D%}Y$D%uY$D%mY$D%eY$D%]Y$D%UY$D%MY$D%EY$D%=Y$D%5Y$D%-Y$D%%Y$D%Y$D%Y$D% Y$D%Y$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%X$D%}X$D%uX$D%mX$D%eX$D%]X$D%UX$D%MX$D%EX$D%=X$D%5X$D%-X$D%%X$D%X$D%X$D% X$D%X$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%W$D%}W$D%uW$D%mW$D%eW$D%]W$D%UW$D%MW$D%EW$D%=W$D%5W$D%-W$D%%W$D%W$D%W$D% W$D%W$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%V$D%}V$D%uV$D%mV$D%eV$D%]V$D%UV$D%MV$D%EV$D%=V$D%5V$D%-V$D%%V$D%V$D%V$D% V$D%V$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%U$D%}U$D%uU$D%mU$D%eU$D%]U$D%UU$D%MU$D%EU$D%=U$D%5U$D%-U$D%%U$D%U$D%U$D% U$D%U$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%T$D%}T$D%uT$D%mT$D%eT$D%]T$D%UT$D%MT$D%ET$D%=T$D%5T$D%-T$D%%T$D%T$D%T$D% T$D%T$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%S$D%}S$D%uS$D%mS$D%eS$D%]S$D%US$D%MS$D%ES$D%=S$D%5S$D%-S$D%%S$D%S$D%S$D% S$D%S$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%R$D%}R$D%uR$D%mR$D%eR$D%]R$D%UR$D%MR$D%ER$D%=R$D%5R$D%-R$D%%R$D%R$D%R$D% R$D%R$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%Q$D%}Q$D%uQ$D%mQ$D%eQ$D%]Q$D%UQ$D%MQ$D%EQ$D%=Q$D%5Q$D%-Q$D%%Q$D%Q$D%Q$D% Q$D%Q$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%P$D%}P$D%uP$D%mP$D%eP$D%]P$D%UP$D%MP$D%EP$D%=P$D%5P$D%-P$D%%P$D%P$D%P$D% P$D%P$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%O$D%}O$D%uO$D%mO$D%eO$D%]O$D%UO$D%MO$D%EO$D%=O$D%5O$D%-O$D%%O$D%O$D%O$D% O$D%O$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%N$D%}N$D%uN$D%mN$D%eN$D%]N$D%UN$D%MN$D%EN$D%=N$D%5N$D%-N$D%%N$D%N$D%N$D% N$D%N$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%M$D%}M$D%uM$D%mM$D%eM$D%]M$D%UM$D%MM$D%EM$D%=M$D%5M$D%-M$D%%M$D%M$D%M$D% M$D%M$D%L$D%L$D%L$D%L$D%L$D%L$D%L$D%L$D%L$D%L$D%L$D%L$D%L$D%L$DHH=8 1`H|$uLt$HT$HH= 18H="1tH=h"1^Hl$ w1H="FHt-DHl$ HD$(AH=!1Hl$ 7HD$ HD$(H=2"1+H=!1Hl$1H=B"Ht-DHl$HD$A-H=T!1Hl$HD$HD$H=!1rH=f!1\Hl$1H=!DHt-DHl$HD$AH= 1Hl$uHD$HD$H$H=,!1DD$ H4$DD$ H$H=G!1DD$ DD$ H4$DA1H=V $HD$0$\1H= $}HD$0$;H= 1bLl$ H= 1t$ Ft$ H= 1t$ +t$ H= 1 Ll$ 1H=H|$tSH|$H|$Iu+H= 1]41H=iHD$4H= 154HD$E41H=|H|$tSH|$H|$Iu+H=1Q51H=>HD$c5H=1&5HD$5H=1 Hl$?H=1Hl$o?H=1T$ T$ ?1H=8T$ HT$ tHl$HD$ ?HD$HD$ ?H=11zLt$ EH=i1_Lt$ DH=1G E1H=HT$/MHT$tLt$ Im:B9BHD$ AH=1Ll$(.H=1IH=@1SMHD$(I4H=M1Ll$(f.fH=QG$HJG$H9tHv($Ht H=!G$H5G$H)HHH?HHtH($HtfD=F$u+UH=$$Ht H=n$dF$]wH]%$HÐHHHHEH :%$Hff.H1fHdH%(HD$1H$Ht HH$HT$dH3%(uHSH1HVH>HHsHuH[@HSHHHЃfHHH=#$f.HdH%(HD$1Ht$D$&|$uHT$dH3%(u Hff.@AUATUSHHt}HAąxNHcFIEt+1@HHSLHhD9uHL[]A\A]DHq#$H8H[]A\A]0HQ#$AH8uH$$ H=H H H=vH;AZ1H iHiY@Hi$$ H= H H H=,H;AZ1H HAUATUSHHt}HEAąxNHcIEt+1@HHLHD9uHL[]A\A]DH"$H8H[]A\A]H!$AH8uH^#$ H=H H H=H;A[1H HY@H"$ H=H HH H=/H;A[1H HAUATUSHHt}HAąxNHcfIEt+1@HHLHD9uHL[]A\A]DH $H8H[]A\A]PHq $AH8uH!$ H=H =H H=$H;A\1H HY@H!$ H=@H H H=LH;A\1H $H$AUIH=`ATIUHSHdH%(HD$1HT$HMtHD$A$ulMtH{H tH{HuAHL$dH3 %(HuEH[]A\A]D$tAHLff.UHcSHHdH%(HD$1HT$Hߺ~H5H|$uHL$dH3 %(Hu H[]8cH?H9wN1L Ht? AȃAA EGLFDFHH9uf.PH gH5RH=pff.@AWAVLcAUATUHSHdH%(HD$1HJH؃9 tMtOLHH'IMt6LHH{뾺H5HL%Dfff.@AUATUHSHe`HI1HHH9}NHHHeIHC$LH0PHt3LLHHE uHEH9|HL[]A\A]H5!$LHJ$H5{H81H2$1H81ff.HHH|$HtH|$HD$H u HDHx~H$H5H81葱SHHtt.H[Ð1uH$H5H81MDuH[$H5QH81"fS11貽H=rH'$HHH=WH;H55H H=EȴH;H5+H1OHgH;H5HH;! H5H;H5}H;1HH5H;HH5Hk$H;H5HH=2$HH=3$HH;1HH5H;HH5|H$H;1H5dH=HH 7$LBӸɽT读˴膻[0HA$H5H818HH|$H|$H|$H uH1HtHf.H1eHuH|$H t2HDHuH$HT$H5YH81蒮fHf.H={ff.AT1UH-6$SHH=PH56$HߺIYH56$LHGH56$Hߺ3H5t6$HH!H5R6$H1H[]A\USHH5G6$dH%(HD$1ZHHT$H=FHHkHH蠹|$uHL$dH3 %(Hu H[]i@ATUH1SH0H HHxHPHHc tUHSH9~7D`HIcH{H tH{HD~?HcH轿H[]A\DHHxHcljH9u!H{]H$H5?H81alff.HH54$dH%(HD$1HH$HǸt HHHT$dH3%(uH&fDHH5Y4$dH%(HD$1lHH$@HǸt 蘬H`HT$dH3%(uHfDUHSHH53$HtH$HH8H[]H= HHM3$ff.UHSHH5"3$HtH~$HH8H[]H=y GHH2$ff.UHSHH52$HtH$HH8H[];H= HH}2$ff.UHSHH5R2$HtH.$HH8H[]H= HH2$ff.UHSHH51$HtH$HH8H[]{H=Y 'HH1$ff.UHSHH51$HtH^$HH8H[]H=HHE1$ff.UHSHH51$HtH $HH8H[]H=gHH0$ff.UHSHH50$HtH$HH8H[][H=9HHu0$ff.UHSHH5J0$HtH$HH8H[]H=HH 0$ff.UHSHH5/$HtHn$HH8H[]H=yGHH/$ff.UHSHH5z/$HtH $HH8H[];H=HH=/$ff.UHSHH5/$HtH& $HH8H[]H=HH.$ff.UHSHH5.$HtH$HH8H[]{H=Y'HHm.$ff.UHSHH5B.$HtH $HH8H[]H=HH.$ff.UHSHH5-$HtH $HH8H[]H=gHH-$ff.UHSHH5r-$HtH $HH8H[][H=9HH5-$ff.UHSHH5 -$HtH $HH8H[]H=HH,$ff.UHSHH5,$HtHf $HH8H[]H=yGHHe,$ff.UHSHH5:,$HtH $HH8H[];H=HH+$ff.UHSHH5+$HtH $HH8H[]H=HH+$ff.UHSHH5j+$HtH $HH8H[]{H=Y'HH-+$ff.UHSHH5+$HtH $HH8H[]H=HH*$ff.UHSHH5*$HtH $HH8H[]黿H=gHH]*$ff.USHHH5D+$H- +$`HE1E111H{HH[]ÐSfHHĀWdH%(HD$x1H)$)D$)D$ HD$0t>1H=]H\$xdH3%(H[HpHPHHVHPLHL@ H51舼^_-ND$DHc$D$HTLHpHPHHVHPLHL@ H51(ZY Hc$D$HTHH5)$HT$hHDHD$@HcD$HDHD$HHcD$ HDHD$PHcD$HDHD$XHcD$HDHD$`HtH$HL$@H8%H=_HH)$Hc$lD$HTRf$@$D$$ƿH$HSH5hH81jH$HSH5H81Nff.USHHtC1 t1DHHtFH$HHHH[]胰HHW$H5H81֟H$1H81ßATIUHSH tu_HtVuLH5 ($HH5($LHH5'$HHH5'$H1~H[]A\Ho$H5H81.ff.H(H|$HT$Ht$HL$H|$H|${HT$H uMHt$HH uMHH|$H uH萸t4H(fHf.Ht$HRH tHvH$1H81eDHH5&$Ht$HǨuεHfHHO$H5yH81ff.S@ti@H@ H_'H= &$HHu;H#HHuڸ[HuHt=HuH$HHǨt T[f[fH$HH$HH$HH$HHi$HqAWAVIAUAATAUHSH8dH%(HD$(1t ҸDEH5H%$LxHnH;_%$aH;J%$H;5%$WH; %$D$LLD$nHMD$ ]HIIcIcI9vH5$$LH9$$8E1EAA|$hT$DDDT$軿DT$T$ƉD$DDT$蟿1HHHD$~DT$D\$IH@I tIGLt$ DD$DD֋L$LHD$ 蟹L$DE1L苹HuHE tHuH|$ HKHH|$ EIGI tIGH)H;|$eHT$(dH3%(LAH8[]A\A]A^A_DL}T$DD衾1HHHD$耬IH@I tIGLt$ DD$L$DLHD$ 謸HuHE tHuH|$ HHH|$ E!LsH|$ fD$D$L8L0H|$ fDHH|$ fDHH|$ jfDD$@QL֙H H5-H=4藪H$H5H81菙H$H5H81wAWAVIAUATUSH(H5!$dH%(HD$1Ll$H5!$LHHE1D$ H HH11HIaHI9}HCJf.{HRLhH[HHH#HDH88HH|$xHt$xH1D$pԭIHH=#HT$pHtLI9|$pDHH $E1HHIcHTH9L$pDH|$xHt$xH1D$p|IHcH=1#HT$pHLI衽|$pt@H|$xHt$xH1D$pIH H=#HT$pH蔸LII|$p%HL?+!IcMHE1IH;AyfDH?v1H=5H $E1IHH|$xHt$x1H\H6HAHH $E1hH|$xHt$xH1lIHHAŅL赘D荍HUIDH|$xHt$xH1蔭IHHPHc0I}HЃILELD$LIHLD$H $@LL赝IH0IHt#LH]LLMIMLݗH#1H81誋H#H5sH81荋H#H5?H81uH#HH5LH81ZH#H5VH81BHk#H5#H81*f.AWHAVAUATUSHHHt$dH%(HD$81HD$ ȗH|$HD$HqL8HD$(A IHAHD$L<$貣L<$1HM~NLt$0Ll$ Ld$DLME11HD$0LLHHfHD$0I)HMHD$(HD$0HD$(H$HtLD$ H9uBI9u=HL$8dH3 %(HuIHH[]A\A]A^A_DHPH@HT$H$;H #H $HH5H81Éff.SHH@Ht$dH%(HD$81HD$ HD$(XH|$HD$艛HHHD$ utHHHD$HT$(H|$1HLL$ AEHD$HD$0HD$HtHT$ LD$(H9u1I9u,HL$8dH3 %(u2H@[fHPHXHT$H#HH5H81趈SHH@Ht$dH%(HD$81HD$ HD$(XH|$HD$艚HHHD$ utHHHD$HT$(H|$E11LL$ HHHT$HT$0HT$HtHT$ LD$(H9u4I9u/HL$8dH3 %(u:H@[f.HPHXHT$H#HH5H81趇AUATUHSHHdH%(HD$1觶IĨt`HI?HW)QΠEHHHH L)Hi€QH)HcH H9UHD$dH3%(H[]A\A]@H5Y$H$HILL%HǨt>ٍH5$EH$HtBLLtHHp;fHxfDH=HH$H=~߷HH$HHX胥Hc7HSHH|$Ht#H|$H/HHTHtH[Hb#H5SH81H#1H81΅ff.AUATUSHH(dH%(HD$1H5$H߉97H IHcH>f.LHT$ Ht$ޙT$ Ht$11AHƺI>HGH5 I>1HH5I>1H7H5۞HUH;H5H #H;HH5wH胓HUH;H5d谊H )#H;HH5GHKHUH;H54xH #H;HwH5HHUH;H5@L=#H;HH5IےHUH;H5H a#H;HGH5H裒HUH;H5ЉH A#H;HH5HkHUH;H5蘉H I#H;HH5cH3HUH;H5V`H 9#H;HH59HHUH;H5.(H #H;HH5HÑHUH;H5H 9#H;HOH5H苑HUH;H5踈H #H;HH5HSHUH;H5耈H q#H;HH5HHUH;H5HH Q#H;HH5bHHUH;H5SH #H;HH56H諐HUH;H5)؇H !#H;HWH5 HsHUH;H5蠇H #H;HH5H;HUH;H5hH #H;H'H5HHUH;H50L-#H;HH5~IEʏHUH;H5pH 8#H;HH5SH蒏HUH;H5@迆H #H;H^H5#HZIH;H5舆H #H;HH5H#IH;H5 QL5#H;H+H5 II$H;H5H-#H;HH5HE賎I}HH5~yI}1HH5n螙I}1HaH5X腙I}1HH5BlI}H,H5/赈I}HH5#螈H=QI?E1HƺH}1HH5H}1HH5 cHHI#|HuH=4#uH#H=#H0tH=#H=#H0tI7H=#tH# H=#H0tH # H=#H0tIu H=#ztH[#H=#H0_tH#H=l#H0DtHM#!H=Q#H0)tI6#H=:#tH#%H="#H0sH#'H=#H0sHH#)H=#H0sH#+H=#H0sH#-H=#H0sH#/H=#H0ssH<#1H=#H0XsH#3H=e#H0=sH#5H=J#H0"sHk#7H=/#H0sH #9H=#H0rH #=H=#H0rH=7H#H[]A\A]A^A_f.SHHdH%(HD$1H?H<$@u Hu^HVH<$H7 twHGHcЉH9uvHuHH$HHL$dH3 %(H[fD uH5#Ht211H$zHHHqH=H<$HH1#H#H5H81_q蚐f.U1ҾsSHH(dH%(HD$1HL$HD$HT$ HxH0輚HH1s|$ uHt$dH34%(Hu H([]DHUH5#HAWAVAUATSHdH%(HE1者HHIXI=LcHHEIEHH%H)HHH9tHH$H9uu|L|$LuILLԗ9LLLHƢHDHMdH3 %(uxHe[A\A]A^A_]LcLuLL^xIfH)HLvH#H5H81joLRH#H5H81Jo腎DATH5c#USH)HtmHHiHB#1HpIHHt.H#HHHӀ~ I\$ L[]A\HڔHK#1H81nH#H5H81nff.@PX1HH #H81wnS1H#pHeHt HC H[fPXH5mHH4#H81"nfUH5D#SH HtCH=HHtKH裄Hߺ:H5+H HH[]H#H5H81mDHH5#茂HtHHHHD.ff.HH5#LHt H远PHHHHDfHH5A# HtH诣HHHЃfSH5#ρHt1HHot 1[H؆¸u1T@UH5#SHzHtTHH#H#1H8nHHoqHHt>HE Hk1H߅@+{HH[]H"#H5IH81 lH#H5\H81kHH5#܀HtH?HHHЃyfHH5ѿ#蜀HtHzHHHЃ9fUHSHHHH#H0.Hu H1[]HH5f#1HHt4H5R#HHtHHzuH[]H#H5H81jff.fUHAWAVAUIATSHH8dH%(HE1IH?H}HMIHHL1H)PHHH9uLCkHHFMHudH34%(H?He[A\A]A^A_]f1HFIH=H=H@HHEHH%H)HHH9t H)HLHEL|$HEIE1HALLrLLDAajH}HeHt_EHZxDHH$bHpHEHHHHEH蹔IcH#H5kH81h4Hu#H5XH81~ff.AUATIUHSH(dH%(HD$1jHD$< I$HD$A H|$@@u HbH#H0#HoH5`#H(}HD$HH|$H5># }HH|$HmHupfMl$@LAnH|$A@IfDH5ѻ#H|HD$H!H|$HHL$dH3 %(HH([]A\A]@CpI$HD$HT$u0HAH|$A 9Ml$hHu 5Dc~AWH5#H{HD$HAA~7A tyA=H|$H|$HxwmfDE H|$Ht$HT$H t[HvHcH9H;HH|$覟H|$HYH#1H81efDHHH|$蒋Ht$HT$H u(HHHcH9uwHfHHvH|$t H|$p߂誄Hk#H5H81ReH#DH5÷H817eH?eff.@HATL%#USI4$HٍHutt7I<$1H#f1HHHtVHE H[]A\u#Ht uf[H]A\H[H]A\0UHH5#SHWyHtNHH7Ht#H5j#H2yHtAHH蒈tH1[]DH[]H#H5,H81cUHHSHt;jH5#HxHt)HHHH[]{BfATIH5#USHfxHt?LAHu%zH膜~H[]A\f.jH##H5JH81 cf.ATIH5 #USHwHt?LAHu%`zH覀~H[]A\f.iH#H5ʴH81bf.ATIH5#USHfwHt?LAHu%yHvg~H[]A\f.iH##H5JH81 bf.UHHSHt;hH5 #HvHt.HH~HH[]D;yH#H5ʳH81af.UHHSHt;VhH5#HUvHt.HHCo~HH[]DxH##H5JH81 af.AUATUHHSHtogH5 #HuIHtuHH#1HpbI踕HHt9LHn~ Im HL[]A\A]DxHwH#1H81T`HU#H5|H81<`ff.AUATUHHSHtogH59#HuIHtuHAH#1HaIHHt9LH~ Im HL[]A\A]D3wH觅H#1H81_H#H5H81l_ff.AVAUATIUHSH@dH%(HD$81HHD$ HD$HD$(HD$HD$0aHD$F~1LuL4$WHD$HD$HteH|$辑u[H|$E1@BvLAuL2vJfDHUHT$tHUHT$Hutty1E1LAtFeLHz#1`IKIHDHP~oMf LHL$8dH3 %(H@[]A\A]A^@H|$E1H|$A@ddf~%HD$L赃H&#1H81]H|$t H|$pz|f.AVAUATIUHSH@dH%(HD$81HHD$ HD$HD$(HD$HD$0_HD$F~1LuL4$WHD$HD$HteH|$辏u[H|$E1@BtLAuL2tJfDHUHT$tHUHT$Hutty1E1LAtFcLHz#1^IKIHDH`v~oMf LHL$8dH3 %(H@[]A\A]A^@H|$E1H|$A@bdd~%HD$L赁H&#1H81[H|$t H|$pxzf.AUATIUHSHdH%(HD$1%]H$1AH1ItLAaH5 #LoHH#1HHE1Huh1HL$dH3 %(H[]A\A]LmfHm^H<$tHG1wfu?@H$ cxH$fDqH}#1H81YH#H5H81Y yff.AUATIUHSHdH%(HD$1[H$ u[1H5#LjnHHB#1ɉHHouG1HL$dH3 %(H[]A\A]fDLmLAtj_눐ug@axfH$u)H]AH1踋FDLmu.Hu+pH#1H81XH<$tHb1uHe#H5H81LXwATIUHSHdH%(HD$1ZH$M$$LA/joAH5#HlHHA\A AHxHHH`HcH9HƍHHL$dH3 %(HH[]A\+`DH$ueHtAH %H5:#HlHH1HYHH^Hc#1H81VM$$Hu]AHD`DI1AIc2hHHpH tHpHF~A9vEuA1H~1HcIgHHpH tHpH~A9(H#DH5{H81UH<$tHЈ1BsHUuHƾ#H5H81Uff.fUHSHHtkuVHHHtb؃tX tS t0t+u?H11 HHHH[]efDHHHuH#HH0}HuHf#H5H81TDUHH#1SHH;#H8{VHHt#HYHtHC HH[]蛉H #1H81vTfDUHSHH?KHt"H5~#HHCiHt#H]H[]H#H5-H81TfDATUHSHH|$Ht$wH5#HIhHtKHH 1H#HU1LHHH#HVHt(HE HH[]A\H#H5H81xSH#H5H81`SAWAVIAUAATIUSHxdH%(HD$h1HD$H\$(HD$@Hl$0HD$ HD$HH\$PHl$XTHD$8gE1IHD$HD$@Hx@Ht LcOLHH9tHPA9HtHHH9uA9-HH|$@jAE1H|$ AH|$(HmuE1H|$0It HWuI1H[#LLD$SH&LD$HHE1LDDHwtqH] HHt$hdH34%(Hx[]A\A]A^A_XAEE1E1qDH|$8膄 {ZE~%Ht$8HwH#1H81aQH|$8t H|$8?DnxpATUSHHH|$Ht$2t1H9#HIRHHt"LHH3~H] HH[]A\:HvHC#1H81Pff.@ATUSHHH|$Ht$s1H#HI.RHvHt"LHHu~H] HH[]A\HBvH#1H81Pff.@USHHH|$Ht$sH5#HHdHtHHPHH[]HDff.@USHHH|$Ht$rH5#HHdHtHHsHH[]HDff.@AUATUSHHH|$Ht$PrH5Y#HIdHtvHH^H7#1HPIHHt7Hγ#LHHHu~I\$ HL[]A\A]HtH7#1H81NH#H5ˠH81Nff.AVAUATUSHHH|$Ht$H$zqHIoqH5x#HI=cHt{HH}HV#1HOI$HHt#H5eH81%KDAVAUATUSHHH|$Ht$H$nHInH5#HI_Ht{HHH#1H|LIHHt\HtvHH~{HW#1HHI%|HHt7H#LHHHi~I\$ HL[]A\A]HlHW#1H81FHį#H5H81Fff.AUATUSHHH|$Ht$iH5#HIn[HtlHHzH#1H HIU{HHt-LHHL~I\$ HL[]A\A]H lH#1H81EH#H5%H81EDAUATUSHHH|$Ht$hH5#HIZHtlHHyHǙ#1HMGIzHHt-LHH?W~I\$ HL[]A\A]H`kHѫ#1H81=EH>#H5eH81%EDUSHHHt$uaHtXHƒtKuFH;\$t1H5#HYHHtCH|$gHHIHtHH[]@HJH!#1H81DH#H5H81uDDSxHG#HHH|#Hm#H5 H;H3TH#H;H5!HH#HTH#H5HHgQH;HH5agH;HH5gH;HH5[gH;1H:H5yngH;1HH5kVgH;1HJH5\>gH;1HH5G&gH;HWH5/ gH;H|H5fH;HH5fH;1HH5fH;H>H5fH;HSH5ȍfH;HXH5lfH;H]H5QfH;HbH5n6fH;HwH5[fH;HH5HfH;HH50eH;HH5eH;H+H5 eH;HH5TH;HH5ٔ~eH;HH5ÔceH;1HH5eKeH;HH50eH;HH5zTH;1HH5keH;1HfH5YdH;1HH5FdH;1HH53dH;HkH5)DH;HPH5dDH;HH5IDH;HJH5ݓ.DH;HH5ԓDH;HH5ȓdH;HH5cH;HH5cH;HH5cH;HH5cH;H=H5ucH;HrH5evcH;HH5M[cH;HlH55@cH;HH5"%cH;HH5 cH;1HH5bH;HH5DwlATUSHHH|$Ht$wH5#HIPSHuKfoHHHC LhHtTE111AHHAOu$HH[]A\H#H5H81=H#1H81=H֦#HT$H5“H81=H#1H81=DH%#1N?ff.SHHH|$Ht$OH5#HVRHHHaHu ucH+GLD$HcI t1I9@uSM@111AH+NuNHD$H[HH9uIfDHj…tHa#H5H81H[]HpfHH БH5 H='hJXHt#H5H81[9Ht#1H81H9AWAVAUATIUHSH8dH%(HD$(1;HD$ @m1I$HD$4HD$HH5#HsfH2H|$JHD$H |HL`HH5#HyMIHHUgHcHHH|$JH1IHD$LpH tLpHD$ E1HD$!HcD$ HcH@IIH@K4>LLH@HT$HNMHDAZuHܞ#1H817ID$HD$H|$ t H|$ {jTf.H|$H uSHL9L[JHD$HL$(dH3 %(H8[]A\A]A^A_L`HXHGf.H|$IH|$H9HD$HD$ HifD?HT$ H ŽH52H=xzGUH#H5=H81m6H#H51H81U6HV#H5H81=6H#HH5H81"6fAWAVIAUIATAUSHdH%(H$1HD$8H\$(HD$`Hl$0HD$@H\$PHl$XHD$h7HD$HaE1IEHD$(HD$PHx!DHt LcODLHH9tHPD9|HtHHH9uA92HH1RGH|$0H|$8AH9H|$@H]hHD$H5#LIIHHL$(LA HyHcAH9HIHl$pLDD$HL$jXUEHHL$ATDD$,HL$ Ht$BX1ZA1ILLE`@L5H5H5#LQgH$dH3%(^H[]A\A]A^A_IHA.@:AEH^#H5WH81IDHEH\$0H uSHHHKTHD$iH|$HFf;AHHoYH<$tH[Y1DCH]#H5zH81D&H]#H5}H81,&gEH@#H5A|H81&ff.@HH#H|$H0NHt'H|$H5cz#:Ht_HIH@H|$>_H|$H u0H'PHuH3#HT$H5o}H81u%DHHk#H5yH81R%fUH1Hy#SHHS#H8&HCVHt+HC E111AHH26uHH[]H#1H81$H#1H81$ff.fH#SH5zHHӊ#H84H#H#H5yHHHx4H#H;H5H1H;HH5w$HH;1HH5vy!ff.ATIH5Pt#UHSH dH%(HD$1@4H6H!HD$HD$H|$H4H+H|$Hc10HD$HpH tHp1HA:HL$dH3 %(HD$H []A\I$HD$iH|$t H|$LQ1;fDH|$^0H|$HcA!HD$[H|$Q&H#H5vH81H#H5wH81 =ff.ATUSHuhHt_HƒtRuMHH9t:H5vr#H~2IHt6H5_r#Hg2Ht^HL+tFH{+HH*FCtBv uH= o u3H=ngDLPfDH=x4fHL[]A\A]H}#H5nH81zf.AUIH5i#ATIUSHH(dH%(HD$1;)HHHD$1IEH$urHD$H1H|$t H|$lMHHaM1HHH1LHL$dH3 %(LH([]A\A]IEHD$~H|$t H|$`F0H|$>FYf+~HT$H.|#H5mH81Hfz#1H81=2ff.fATIUHSH dH%(HD$1HD$ HEH$HEHD$H|$1H<$t HKH1H|$t H|$KHH5g#L='H1HHH=HHHL$dH3 %(upH []A\f.H$HD$H|$\H|$DM@H|$t H|$D1/0Hz#H5~kH81vHx#1H81cATIUHSH dH%(HD$1'HD$HEH$HEHD$H|$1H<$t HfJH1H|$t H|$OJHH5f#L%H1HHHt0HHCH5jHH<.HHL$dH3 %(ufH []A\H$HD$H|$LH|$C=@ H|$t H|$B1c-./Hx#H5iH81H'w#1H81AVAUIATUS(It;HtFHL5d#DL1LCHHh H:s#H5)dH81! HH5a_# HtHt"HHr#H5cH81 T@Hr#SH5+eHHo#H8Hp#H-q#H5*dHHHHp#H;HFH;H'H5d H;1HOH5c H;1HwH5c H;HlH5c H;1HH5i,H;1HH5x,H;1HH5b,H;HH5mc,H;H>H5dr,H;H#H5>cW,H;HxH54c<,H;HmH5)c!,H;HH5c,H;1H:H5 c+H;1HBH5b+H;H5b2H;H5b1H; H5b1H;H5b1H;H5b1H;H5b1H;H5b1H;[H5bu1DAVAUATIUSHpH $H|$HT$dH%(HD$h1*H"H $LA HD$IHiAHM HxHcAH9HXLLd$ :HHMHT$$MHHRD:ZYHD$14 T$HHpH tHpLHHL$hdH3 %(uWHp[]A\A]A^HD$LiHiH IHHXAALHgj#H5bH81!%AVAUIATUSH H $H|$HT$dH%(HD$1HH $LA HD$IHiAHM HxHcAH9HXL8HE1HHT$MHHRDN9ZYt$HH\$dH3%(uBH []A\A]A^HD$LaHiH yHHXAA| $fAUIATIUHSHhHt2LHH(t8HLHcHH[]A\A]Hh#H5_H81YHHh#H5_H819fPXH5_HH$m#H81fUH5Y#SHhdH%(HD$X1HtcHl$HT$ HHD$ 14rT$ HHpH u&HHHL$XdH3 %(uHh[]@HpM"UH5Y#SHdH%(HD$1JHtc@1HFHHpH u>HT$HYt$@wKHHHL$dH3 %(u+H[]fDHpHk#H5^H81"H ^H5^H=^fDSHHH|$Ht$H5.X#HvHt6Ht$H tHVHvHHH[HHfDSH5W#HHtE1111H1H[ff.ATUSHuhHt_HƒtRuMHH9t:H5fW#HIHtNH5OW#HHt:HL%tH[]A\HpHe#H5 ]H81XHYj#H5\H81@ATIUSHHH|$Ht$?H5V#HHt]LH`4Ht$H t3H~HcωH9u2HvHE1H0HH[]A\HHyfS1HBV#MHEHt HC H[Hd#1H81d@SH|g#H5A\Hvf#HH;;Hd#H;H5:\HHh#HHAg#H5jHHo H;HH5[H;HH5[H;HzH53L#H;HH5nRs#H;1HWH5T[#H;HH5`@#H;H`H5SH;1HH58[#H;1HH5["H;H[H5ZDH;[HZH5R-f.AWAVAUIATUSHhdH%(HD$X1H=#cHD$ HD$(Aą#H=\1IUHl$ HD$(HT$HfDH\$01HIH5#j4H|$@HT$H HHcAH9HH8H HHcAH9H{H8I HHclj|$ H9HD$@HHD$(H2H|$H0Ht$(1H$1 I HHH-HL $E1HߺV!?LMHE tLMEH߾"!qLL$I IEH߾ ML$I$ tML$DD$ H߾ PIuIE tIuHT$(HkFHt$(LFH^2LHL$XdH3 %(Hh[]A\A]A^A_HxHBHx0MI~?Hl$ HD$(MuLt$u*HFH|$(t.7HD$(Ht H|$(N.DH=W,H=XHt#,H=EPHd#,H=oHT#o,HP#8H LVH|$(T&H ,H=XH1+HHl$ HD$(HT$-@HcIl@5H5E5Hl$ HH|$ D{Lt$ HM`5E)5HHDHD$(Hl$ EuN1HH0H=M#H57V1H/H=0#H5/V1DAHl$ EHcI|H4FHHD$ H/H=ʂ#H5U1LH]#H5jUH81?H=#H5nU1HB/H={#H5U1H%/H=^#H5U1H/H=A#H5tU1AWAVAUIATUSHXdH%(HD$H1H=#;HD$mHD$AąH=V1IUHl$HD$HT$HfDH\$ 1ɺHIH5#J.H|$ H H|$(H@AH|$0@H|$8+Hc1Ia IH@I tIFH HHSH|$H7 u^HHPMEU%ZYPHT$HdH3%(L4HX[]A\A]A^A_fDT@LGMcDM9HH{Hc׉H9HSWDcA~?Hl$HD$MuLt$u*HnH|$|)_HD$Ht H|$V)DH=R' H="SH#'H=MKH #'H=jH~#w'H~#`fH|$l!H$'H= TH1CHHl$HD$HT$e@HcIl@k1H^1EO1Hl$HH|$D{ Lt$HM0E0HHDHD$Hl$Eu'1LDH=m~#H5QDAHl$E-,HcI|zH\0HHD$CAWAVAUIATUSHXdH%(HD$H1H=}#HD$MHD$AąyH=R1IUHl$HD$HT$HpfDH\$ 1ɺHIH5|#**H|$HHl$(I@&HLd$0AILl$8AIH\$@HH14IH@I tIFI upLD$HIWI0 umHIxSMIPjAUH lHT$HdH3%(LhHX[]A\A]A^A_LD$IOIWI0 tIpIxfD~?Hl$5HD$MuLt$u*HH|$%HD$Ht H|$^%DH=N#H=S=HD{##H=@H4{##H=bH${##H=%GH{#g#H{#pHH:L'IL'IH'HH|$H"H=OH1HHl$HD$HT$-@HcIl@-H-Ex-Hl$HIH|$D{ Lt$HM"-E,HHDHD$Hl$Eu1y#HHH5Ljf.SHHH|$Ht$H5~E#HfHtfHt$H t4H~HcωH9u3HvHHxt$HD$H[HHHwV#1H81HW#H5MH81UH5D#SHdH%(HD$1H1HH4&HcH1AHH@H uQHHH$&~[HH4$ tBHCHSH)H9jHZHHL$dH3 %(unH[]HCf.HHSH V#1H81HW#H5LH81H QM{H5LH=L @ATIUHSH dH%(HD$1HD$tjI$HD$H|$H|$rHD$H0 HHxHHH} )H] HD$H|$u'HL$dH3 %(HH []A\H|$tiD5H|$t H|$1 HxHc׉H9uvHxIHHKHD$H u;HHHD$Ht$1HHHS#1H81 HPHT$HPL SH5B#HHH@Hc0~Hx[~fDHQ#H8t 11[HqS# H=(3H $H H=HJ$H;A1H JH 3HST#H5IH81:f.UHH51A#SHHt`HHw HH,HH! tuH[]@3H1[]H3R#H5IH81HS#H5:IH81f.PX1HHQ#H81wATUHSHHHIH5X@#HH=HtHLHzt H[]A\HS#H5HH81qATUHH5?#SHt-HHI IHLH# t H[]A\HR#H5?HH81HQ#H5HH81HH5?#lHtHHt$HHHOR#H5GH816UH54?#SHHt5H"HEHHtMHHH߅t#H[]`HQ#H5hGH81H,P#1H81ff.SH5>#Ht+H HHt;HHcH9u#H߉[H`Q#H5FH81GHOf.S1H2>#HHt HC H[rfH%N#SH5FH8HO#HgL#H5FHHHH+O#H;H5GHHP#HHP#H5aHHH;HH53K H;1HH5W03 H;1HH5dF H;HUFH5 ;eH;1HH5=F H;1HH5A H;HH5F H;H[H5U H;HH5_M H;1HH5El H;[HH5EP UH5<#SHdH%(HD$1JH1HHtHcH1HH@H uQHHH$B~[HH4$ tBHCHSH)H9jHHHL$dH3 %(unH[]HCf.HHSHN#1H81HN#H5EH81xH 1KH5EH=DI@SH5;#HdH%(HD$1HtTIH1115 H8HHthH4$HdH߅t8XHT$dH3%(uH[HM#H55DH81HM#H5CDH81HyM#H5#DH81pSH5:#HdH%(HD$1KHtlHI111e H$10HcHH$HsHcH u,Hx3HHL$dH3 %(u.H[f.HsHL#H5MCH81ff.fSH5:#HdH%(HD$1Htl1IH11 H$10HcHH$HsHcH u,HxsHHL$dH3 %(u.H[f.HsHL#H5BH81=ff.fAVAUATIH5L9#UHSHHPdH%(HD$H1HIHD$HD$0HD$HD$8HD$HD$@zHD$(i1M4$Lt$HD$HD$H"LH|$ HD$ BHD$ H HPHT$(HP1Ht$(hHHJ#H5AH81IT$HT$iIT$HT$HLH|$HH|$I1HuLLHH HHE LHHL$HdH3 %(HP[]A\A]A^DfH|$(~$HD$(DHHHD$(H|$(t H|$(0HI#H5@H81HI#H5@H81ff.ATUSHupHtgHƒtZuUIHH56#CHHtCH56#L,Ht/HoHt:HC H~H[]A\fDHHH#H5k?H81HH#H5?H81UH56#SHdH%(HD$1H1HHtHcH1!HH@H uQHHH$B~[HH4$ tBHCHSH)H9jH:HHL$dH3 %(unH[]HCf.HHSHG#1H81HG#H5JCH81H aDH5R>H=l=@USHHH(Ht$dH%(HD$1FH|$HD$wH5 5#HHHHHD$H tGHPHT$HP1Ht$Ht;HC HeHHL$dH3 %(u4H([]HHHD$HF#H5=H81HF#H5#BH81ATUSHuxHtoHƒtbu]IHH584#cHHtKH5$4#LLHt7H=D#HHt;HC HH[]A\HHF#H5zAH81HE#H5<H81UH54#SHdH%(HD$1H1HHHcH1AHH@H uQHHH$~[HH4$ tBHCHSH)H9jHZHHL$dH3 %(unH[]HCf.HHSHE#1H81HE#H5<H81H aA}H5r;H=:@WATUSHuxHtoHƒtbu]IHH52#sHHtKH52#L\Ht7H=?#H(Ht;HC HH[]A\H H!D#H5%;H81HC#H5:H81ATIUSHH dH%(HD$1HD$6HD$H|$H|$H|$H51#HlHHt$H HHHHL$dH3 %(HH []A\I$HD$aH|$t H|$ 1NfDH51#HHtV1HqH~HcωH9udHvRfH|$v kpHoB#H5s9H81VHBB#1H81>IfATUSHuxHtoHƒtbu]IHH50#HHtKH50#LHt7H=(B#HHt;HC HGH[]A\HHA#H58H81xHiA#H5o8H81`ATIUHSH dH%(HD$1'HD$HD$H|$H|$tvH5"/#HHHH|$H|$HD$HD$H HHHD$1Ht$8HHE H#HL$dH3 %(HH []A\I$HD$AH|$t H|$, 1fDH|$ f볐HPHT$HPJH?#H56H81H?#H57H81fUH54.#SHdH%(HD$1H1HHHcH1HH@H uQHHH$~[HH4$ tBHCHSH)H9jH*HHL$dH3 %(unH[]HCf.HHSH>#1H81H>#H55H81H ;H5B5H=\4@WATUSHuxHtoHƒtbu]IHH5,#CHHtKH5,#L,Ht7H=9#HHt;HC HH[]A\HH=#H54H81H=#H54H81ATIUHSH dH%(HD$1HD$HD$H|$H|$tvH5+#HJHHH|$H|$HD$EHD$H HHHD$1Ht$HHE HHL$dH3 %(HH []A\I$HD$AH|$t H|$1fDH|$nf[볐HPHT$HPJHO<#H5S3H816H'<#H53H81YfUH5*#SHdH%(HD$1H1HHDHcH1qHH@H uQHHH$~[HH4$ tBHCHSH)H9jHHHL$dH3 %(unH[]HCf.HHSH4;#1H810H1;#H5R2H81H Q7H51H=04@AWH5)#AVAUATUSHHHIAŅ~L=7#1HD$@LI?1H'#HBHIHHt=IF H|$LfA9uHD$H[]A\A]A^A_DHD$H:#1H81H:#H5<1H81fATIH5(#USHHt?H5J'#LHHtxHIHtPHH_Ht H[]A\H9#H50H81LHs9#H50H81jH[9#H5=0H81RHS9#H5/H81:f.ATIUSHH dH%(HD$1HD$6HD$H|$H|$H|$H5'#HHHt$H HHHHL$dH3 %(HH []A\I$HD$aH|$t H|$1fDH5'#H HtV1HUqH~HcωH9udHvRfH|$pH7#H5.H81H7#1H81~fATIUHSH dH%(HD$17HD$HD$H|$H|$tvH5%#HHHH|$H|$HD$HD$H HHHD$1Ht$XHHE H3HL$dH3 %(HH []A\I$HD$AH|$t H|$<1fDH|$f 볐HPHT$HPJH5#H5 -H81H5#H5^-H81 fPXH58,HH5#H81fHH5##dH%(HD$1|Ht/111IHH<$HT$dH3%(u H~ff.UHH5"#SHHt2H5{"#HHHt3HH@HH[]H4#H5S+H81UHH5!"#SHHt2H5 "#HHHt3HHHH[]Hq4#H5*H81XH91#S1HH!#H8HtHX [d@AWH5C"#AVAUATUSHxdH%(HD$h1HD$HH|$HD$8pD$HD$`1HD$HD$XHD$ HD$PHD$(HD$LHD$09l$oH|$'HHtLD$HL$ HHD$`HT$(Ht$0HD$XHD$PAąxHiHqIHB LILH IcLHt6Hct$LLHt6H|$PHtHLH|$XHtHLH|$`HtHLHI+AŅ~+E1DHAQHLHNE9uLL;H|$8L.9l$HT$hdH3%(HD$8u'Hx[]A\A]A^A_H1#H5(H81H1#1H81PXH5/-HH1#H81fHq.#S1HH\#H8DHtHX [@USHHH5#HTHHH5q#H9HHtMHHt,HH=k/#HHtJHH[]PH[]H0#H5'H81H0#H5?'H81H0#H5'H81ff.PX1HHy0#H81wS1H#HEHt HC H[fAUH5#ATUSH&HtTHHHcIIE~(1ېHH+LHA9uHL[]A\A]HH5#dH%(HD$1HE111HHxQu4H<$HtHL$dH3 %(uHDH5/#H5&H81,H/#H5&H81H/#H5~*H81ff.PXH5~&HH.#H81fHH5#Ht!E1111H&x$HHHDH.#H5*H81~fHH51#dH%(HD$1LHtP111IHx6H<$Ht!tHT$dH3%(uH<H-#H5a)H81ff.@HH5#dH%(HD$1HtPE111HHx5H<$Ht HT$dH3%(uHfDgHX-#H5(H81?ff.@HH5#HtHOHWHH6fDS1H#H%Ht HC H[2fPXH5#HH,#H81fAVH5#AUATUSHHHHcI)IE~FL5*#1HLHHt'HǃLH0A9u[L]A\A]A^H,#H5#H812fUHH5#SHHt0H5#HHHt1HHHH[]HDH+#H5"H81H+#H5"H81rfS1H#HHt HC H[fUH5#SH*HtLHH(#1HB#H8HHHtHE HH[]@HH[]@HH5Q#HtHHHHDff.HH5#|HtHoHcwHH+fDS1H#HuHt HC H[fUHH5#SHHt0H5+#HHHt1HHHH[]HDH)#H5 H81DS1H#]HHt HC H[fHH5a#lHtHHHHЃHO)#H5p H816fDAUATIHUHSHt\Ht\H50#HIHt]1LHt#LHBHt'HE HH[]A\A]CHuE1H(#1H81蓿ff.HH5A#dH%(HD$1\HtH'#H5H81H'#H5oH81ξff.H@t"Hc1cHtEHf@uHt tH1@@AWAVIAUATIH5g#UHSHHHL$H$LD$(LL$dH%(HD$81D$4HD$H)H5U#LHD$ HHN$HHE1HLh=DHI9}^H-##LHuJCH}HcH5'H}HwH5g H}HH5 H}1HbH5 H}1H9H5 H}1H`H5 H}1HwH5 H}1H.H5rH;H5 H;H5H;HH5 tH; H5 `H;H5 LH;H5 8H;H5 $H;H5 H; H5 H; H5 H;H5{ H;H5 H; H5 H; H5 H;H5 H;H5 pH;H5 \H; H5 HH;H5 4H;!H5s  H;AH5h  H;H5_ H;H5T H;H5L H;H5A H;H5 H;H5$ H;H5 H;H5 lH;H5 XH;H5 DH;[]H5 A\,f.fUH5D"SHdH%(HD$1ڻH1HHHcH1aHH@H uQHHH$~[HH4$ tBHCHSH)H9jHzHHL$dH3 %(unH[]HCf.HHSHt #1H81 H!#H5 H81H q H5 H=ٶ$@שAUATIUSHHHdH%(HD$81HB D$HD$ HD$({HD$0 I$HD$ID$HD$H|$0E1H|$t H|$IH|$Ht$(HHHD$(HHC &!H|$(HL$0LHT$LD$ UȫHt$HbH= #HT$T$IŅjHt$0HHH=5 #HT$VIċD$u#Ht$ HtH= #HT$+HH|$0H5' #H|$ LH5- HLH5 HHHH5 |$t1f.HD$HD$H|$0u.HL$8dH3 %(HHH[]A\A]@H|$0~@s H|$0t H|$0Y1Ht$0AHAfAHa #H5 H81CATUSH|HtsHƒtfuaIHH5"迷HHtOH5"L訷Ht;H5D#H=m #HHt8HC H|H[]A\@HhHi #H5.H81PH #H5hH818S1Hr"ݣH腢Ht HC H[HH #1H81@AWIAVAAUATUSHdH%(H$1HD$HLl$8H$HD$PLd$@H$HD$XHl$`H$HD$pH\$hH$HD$xH$H$L$L$H$H$H$(HDŽ$,AE1H$1LHqfDHtI<H8HHH uHHq0'Ht HcIfD@ID$^HHAƅHT$`H#H5QH81H$yfDA~;L$kD$f[D$fKD$H$t H$ DH#1H81u谼H=#SH5HH#H8KHl#H#H5HHH(Hi#H;H5HHàH;H5dH;HH5H= }H;E11ɺHhH=\H;E11ɺHGH=;H;E11Hƺ&H;HH5;H;1[HNH5F"f7駽UH5"SHdH%(HD$1H1HHTHcH1聭HH@H uQHHH$"~[HH4$ tBHCHSH)H9jH蚮HHL$dH3 %(unH[]HCf.HHSH#1H81@HA#H5H81(H !gH5H=D@AWAVAUATIH5J"UHSHHxdH%(HD$h1D$误HIHD$Ll$(HD$@HD$ HD$HHD$0Ll$PHD$XfHD$8 ;1I$M|$HD$L|$ *HD$(HD$0Ht:H|$8.ID$HD$(tID$HD$0HuLE1FH|$0HD$HbH|$(LnH|$IH,Ht$INjD$NHƞHHHT$ELILLLA膛H5?"LE?詷H1Ht HHH5HݶhHH5HH辶AHEHL$hdH3 %(#Hx[]A\A]A^A_fH5SH!HD$(HH|$E1HE1@t*UADC~HT$8@˯AaH|$8t H|$8耵L8|$H8#H5H81LH5"LH #1H81轗H#H52H81襗AWAVAUATUSHH $H(Ht$H5"IdH%(H$1[HHxI薯H|$Hl$1LIIHuQHL9u9HL?ÅLLtH5xL薴L莿L!HuAH$dH3 %(HD$uTH([]A\A]A^A_fL.H"1H81XHY"H5H81@{ff.AWH5"AVAUATUSHHHxHMHC L`MLŅHc艠IŅtz1;fDH5"H="L2HIG LL9t;L虢H""1IH"H8IMuHL[]A\A]A^A_fDH{wuHC L`0M.H[]A\A]A^A_H7"1H81H"H5`H81ӔH "H5H81軔ff.AWH5"AVAUATUSH蒩HRH衯IHH荥ŅDHcIŅtt15H5"H="LʬHIG LL/9t;L1H"1IH>"H8趕IMu艺HL[]A\A]A^A_fDH"H8tH[]A\A]A^A_鸬Hi" H= H H 'H=H;A61H HH"1H817H8"H5H81HX"H5H81SH5d"HVHxH*teH{t?H{H{tgH{[fDH=#Htl[fDH= #HuH=b[HH#H=#HuH=MHH#H= HH#tH=y#HdH= OHHU#DH=9#H4H=THH#H"H5H81xATIUSHH dH%(HD$1HB H$/HD$ I$HD$H|$H|$IӝH|$HD$11LHHbHH$HHC HߺH5TuH5VHaHD$H|$u'HL$dH3 %(HH []A\H|$6t=D#H|$t H|$ 1{11ҾHצRLHHHH<$轐Hn"HC H5H81譏ATUSHupHtgHƒtZuUHH9tDH5"H^IHt>H5"HGHt*HHt5HC LH[]A\ÐHH"H5H81H9"1H81ff.fPXH5$HH"H81ŽfHH5a"謣Ht HxHDHH51"|HtH@HxH&HH5a"LHtH@HxHH7"H5H81ff.HH5"HtH@H8HwfPX1HH"H81ǍUSHHH۽H5T"HH虢HtHH蹪t"HH[]H|"H5H81c~ff.S1H"HղHt HC H[BfHH5!" Ht44H芜Ht:8tHfDHxH#H"H5.H81軌fDAUATIUHSHHHLI趼HIۿH5"HHiHt#HLLHst&HH[]A\A]HB"H5H81)D@S1H""͍H襲Ht HC H[fUH5T"SHڠHt5HHHHtMHHH߅t#H[] H"H5H81舋賍H"1H81pff.PXH5HHT"H81BfSH5"3Ht(HxHrt t1[@HC [H@HHH'ATIUHSHH(HHuH5T#HtMHLr11iH[]A\ÐH=HH#SH5"SHt(HxH蒢t t1[@HC [H@ATIUHSHH訑HHuH5#HtMHL"11H[]A\ÐH=V/HHM#H3HH釭ATIH5"USHfHt"LHHHێt H[]A\H@"H5H81'BfHHH두ATIH5p"USHHt"LHHH苼t H[]A\H"H5DH81跈fHHH두USHHH5="H脝HtKH5"H=Y"HHHtjH5"HRHtQHH肊t"HH[]H5"H5sH81HHM"H5H81H0"1H81@ATIHH5"USƜHH5N"H=_"H7HHH5"L茜HHtsHH)tDH{輟tL[]A\~H2H L[]A\H詨Hb"H5H81HE"1H81H"H5TH81UHH5A"SHǛHt$HH7HH謱t"HH[]H"H5H81膆SH5"oHtH5BH;1HfH5s*H;HdH5tH;1HH5 I$H;H5 H-B"H;H5HHE H}H5LH}HH5E蠘H}1H3H5臘H}H~H5>ЇH}1H#H5eWH}1HJH5>I$H;H5 KH-"H5HHE衁H}HaH5H}1HH5ܗH}1H_H5×H}1HH5誗H;H5֝H;H5H; H5讝H;H5蚝H;!H5膝H;AH5rH;H5^H;H5JH;H56H;[]H5A\f.@HH=<dH%(HD$1HT$袝HcD$HL$dH3 %(uHH賅Hf'USHHH腍t8~ttA=uJHH[]@u3HH[]e}DHH[]fHH[]BufH"HJ"1H8s1H5HX HH萏HH[]H"H5H81qff.HU"SHH0yHuH[H"H5qH81WqSH"1rH赅HtHC H1H5JH[H"1H81qAUATAHUSHdH%(HD$1ՏHÅu4CHL$dH3 %(H[]A\A]DN{Ic1HHTIYHcվLHTDH="HT$L0D$xC1DC1H=8tZT@G@SHHH=~HdH%(HD$1HT$谚T$uHL$dH3 %(uH[HZ|$豗܎ff.ATUHSH dH%(HD$1ZqHD$HEHD$ucAL5H|$Iا1HH[HHH7qHxHL$dH3 %(CH []A\fLe~H|$t H|$赡$@w~HUHD$AHT$uHHH|$k9fDLe~D11ҾH/誇L1HHs"FHH11ҾHt1HjoHH11ҾḦ́H1HLH"d|HHoHH"H5H81mUSHH(dH%(HD$1tH螚HH蓈~@t=uHТHtIHD$dH3%(H([]Du1HT$HHQuH<$tH|$uH"H5,H81lf.1Ht$HqH|$u1Ht$H1pH|$]΋H"H5H81vlfDAUATUSHHH5"HT$H $JH7HIfH莟H|$IA~HD$H HXHcH9H~HH1LHJxH4$H HHHOHt$H uoHHLH莝u*ՄH1[]A\A]HH@u)H[]A\A]HVHvtHvH#"H5H81 kH "H5WH81HjH"H5,H81jHڜH"H50H81jH躜H"H5"H81jfHH5"|HtHHs"H5H81jf.SH5"11HhHuH5"H#Ht[H"H5H81jH"H5QH81ff.AUATUSHH(HT$dH%(HD$1HI H|$I{Le1Hc;{H蓎H1LHHuHt$H tuHVHvHtnHuHE tHuLHHT$ϓHA$Et\t$H|HHL$dH3 %(uUH([]A\A]DHHHۚH"H5H81hH"H5H81hևH螚H"H5>H81vhHw"H5H81^hff.SH5"?}HtHH_H[H+"H5wH81"~fUH54SHH("H8qH"H- "H5HHHEwH"H}H5HH"HwHq"H}HH5HBH;H5(tH;1HH5;H;HlH5S H;HH5H=ɁH"yH[]USH8H5G"dH%(HD$(1{HCHHLHjHL$HT$HHH}HT$ Ht$H j֗H<$HzH=PHfjHHHxfH|$NH=H:jHHHLfH|$"H=HjHHH fH|$H=1HiHHHeH|$ ʎH= HiHHHeHHL$(dH3 %(uH8[]H"H5H81v{衄Hb"H5H81IefAUIATU1SHHt$H$Ht H|$4H1H<$t H HH5^"LyIHH uwLhIHtHiHHt5HtHiHHt HHLқt`HL[]A\A]H踂1豂H"1H81^dH_"H5H81FdHG"H5H81>zHfH^H"H5xH81dfDAVIAUATE1USH Ht$HT$HL$Ht H|$I1H|$t H|$ԆH1H|$t H|$轆HH5"LxIHH~LgIMtLvhIHtOHtHahHHttH=wH*OHHHHUHd"H5H81H<$HHЃHL$dH3 %(uH[H"H5:H81OYKff.SHH5"dH%(HD$1NHt_HHTtuJH9H1H1>H<$Ht sbHL$dH3 %(uH[D|XH8"H5H81/Off.@SHH5h"dH%(HD$1MHt_HH TtuJH^8H1H=H<$Ht aHL$dH3 %(uH[DWH"H5ԢH81Nff.@SHH5"dH%(HD$1;MHt_HH[StuJH7H11H?@H<$HtaHT$dH3%(uH[WWHؠ"H5$H81Mff.@SHH5"dH%(HD$1LHt_HHRtuJH6H11H?H<$Hta`HL$dH3 %(uH[lVH("H5tH81Mff.@SHH5X"dH%(HD$1KHt_HHQtuJHN6H11H>H<$Ht_HT$dH3%(uH[UHx"H5ĠH81oLff.@UHHSHt+&=HHt+HHAff.ATAH5"US @HHdH40HHtXAt&HH+KH߃u'[]A\JWf.H=Y"HH[,Hh"1H81*HE"H5H81|*H-"H5H81d*@2f1%DSHHt$H5"&?HtH|$H4HL$H u*HH9u$HH[DHHHQHk"H5ЗH81)HS"H5H81)f.AWAHAVIH5"AUATUSHHxdH%(HD$h1F>HHD$Hl$ Ld$(Ll$0HD$HD$@Hl$HLd$PLl$X*HD$8EME1IHD$HD$@Hp!fDHt HcI=^H6UHHXH*HAHE1QIHtHPLI*:I\HZ(HHAtHMt[HL 0"L1ATHE1HQXZHuPH[]A\A]A^A_DO@HHMt%%@HH >f+$$HC"H5LH81h"H)"H5iH81P"H"H5H818"H"H5bH81 "H!"H5ȐH81"H "H5UH818AUATIUHSHdH%(HD$1#H$xb1u;AHu[1HLLHL$dH3 %(u]H[]A\A]LmtHm~H<$tHT1>HTfD)xH$o9@fSHHt$H5C"H$5HHH;=HkRH|$H2H2H $LA tFHyHcAH9|Ht$HIH u;HH1IكHHHu$HtH`"H5ˊH81uHD$H[]Hp"H5H81WHX"H5H81O1ff.@UHSHH5"0HtOHH76=HLH5}u"HH/HtJHH<u"HH[]Hă"H5H810Hl"H5H81HD"H5чH81{H|"H5#H81cAUIATIUSHH-"H=/HtsHH]5HL/HHtMH:5=HKHHHtZH¾Ht&HL[]A\A]HƂ"H5H81/H/Hf~"H5H81HN~"H5H81uHv"H5H81]H~"H5H81EDUSHHC"H|$H0BHtIH|$H5s".HHty7HHHH:tqHH[]fDH|$^RHBtf;OHHtDHǾJH߾HH[]H@"H5ͅH81wH.H0}"1H81\H}"H5H81D@AVIAUATIUSHH L-~"dH%(HD$1L-HHH"3HD$IHD$MvH|$H|$HH}"H0\@HH|$Lf,HH H2=HHHHHHھHHL$dH3 %(LH []A\A]A^HD$H|$A3H|$IH|$H)5HHxHd{"1H81H"H|$H0\?HLk-H|$IOH}"L1HIGIHHt?LgfWH|$t H|$I1s311ҾL,J/L1LH}"3HHu11ҾL,/1L!HHc11ҾLq,.1L,LHHC.fH|$H#HO~"H5H81F+H7~"H5ރH81H6+Hy"H5H81Hy"H5H81!4U11HAWAVAUATSH(dH%(HE13;LcIL9HHHHH)HH9tHH$H9u%HLH:HL IE~yEl$IIJ+HE@;!LkILI*LH EMt L*HLHDLLDH;]uHMdH3 %(LuDHe[A\A]A^A_]H)HL*HH|"H5EH81r2ff.fATHy"I1US H'HtVL⾘HH t'Hk H1H5Am0H[]A\f.H11H[]A\fD1H[]A\ff.SHAH9"tH9"t%H9v"u#[D[f[H*w"HH5H81nff.AWAVAUATIH5zl"UHSH<'HH5"HH?H5l"H'HHL.E11HL=v"HAM8IHtMH1}#MIHHH u*MDHH7HtHL[]A\A]A^A_fHHH+y"H5[H81rH#y"H5~H81ZHx"H5|~H81BfUH5dk"SHH'&Ht@H5ۚ"HH>H5k"H&HtJHHu"HH[]Hx"H5~H81HSy"H5H81Hcx"H5}H81f.UH5j"SHHw%HtJH5+"HH>H5j"HQ%HtTH-u"HHHw=u"HH[]Hw"H5J}H81Hx"H5 H81Hw"H56}H81UH5j"SHH$HtJH5{"HH`=H59j"H$HtTH}t"HHH;u"HH[]Hw"H5|H81`Hw"H5mH81HHv"H5|H810PXH5s|HHv"H81fUH54i"HSH#HtpH5"HHuH81}ff.fUHAWAVAUIATISHHH5"dH%(HE11H5[^"LHEH"H}H5^"IHxH^H|l"H8D!HuIHH5]"LIHHEHpHEHEHhHEHEH`HEsHE{1IEHEHEHEHH]H#6H}@DHp4&1H}HHg"ILLHxL'4HMdH3 %(L He[A\A]A^A_]IEHEOIEHEHFH}@WHJ<2H}1HEL(A NH@HpHUH zHHH;pHpH^HXHKHHHEHHHHH)HH9tHH$H9ut H)HLHT$HHpHhE1H]=HJHHEl$HhHuHXJI=2L;p}VHEH uH@ 뵐Hh$$H@ HUyIALpHpHHHHH%HEH)HHH9tHH$H9ut H)HLH\$HHpL3E1LhH7Hf.HJc"H5kH81ff.fAUH5|kATUSHHb"H`"H;H HC_"H;H5RkHH7a"H_ L%0c"HQ`"H5.kHI$H; H-Dc"I$H5kH;HE L->a"H}H5FL%b"IUI$ Ha"I<$H5EHIU Hza"H=jHsH=jH"`H=jTH=jH"AH=jHk".H=jHP"H=jH=|jH)"H=tjH"H;H5`jH">#H;H5Qj*#H;1HH5hH;HH5dH;HH5AEH;HMH5|KH;1HH5jiH;HJH5iNH;1HH5"S6H;HH5iH;1HH5SH;HH5@WH;1H H5bH;1HH5cH;HbH5,i H;HcH5#i H;1HH5ctH;HcH5Ah H;1HH5hFH;H'H5h+H;HH5hH;H1H5hH;H6H5bH;HbH5 V$ H;1HH5?H;1H H5UH}H5H}HH5 ChH}HXH5GILH}HH5I0H}HIH5Iy H}1HH5fH}H H5fH}1HWH5[fH}1HH5,fH}1H5H5igH}1HH5[gH}H`H5IgdH}1HH5;gKH}HKH55g/H}1HH5lcH}HH5gH}1HMH5gH}1HH5TH}1H{H5=H}1HbH5SI<$H5{I<$HH5AjI<$HzH5IGNH=fI<$E11Hƺ"I<$HLH$LHHH$1Ht$8MHCH|$8E1H|$8E1H|$81Mz{Ht$ H HHHNHt$H HHHut7H 1HL$xdH3 %(HĈ[]A\A]A^A_ H=xO H=sOHd" Hd"Hg HVHv[HVHvH=#O HH=d"H|$8 lH=5o HHd"kHcHDHHD$0HtyH|$0$RL|$0DCHM3$HDHDHD$8Ht$0Hƃu"1H811W1҃HA"H5BH81|H|$8oEHH H=6HC1Ht$83HcH|HD$8E1H@H$$HD$0<UHSH(H54>"dH%(HD$1H|HHHHT$Ht$HPH|$t(H|$tHL$dH3 %(uAH([]@H5s1HHHEH3@"H5AH81*U@AUATAUHSHHdH%(HD$1H$E%L+AuZLAtqHމHHtqHHrHtaHL$dH3 %(H[]A\A]fDH[AHttoHLAuHމTHHuHD H;"1H81E~QH$L+At)H[Au:HtHH HHHH<$tHDff.@AUIATUSHH(H5;"dH%(HD$1NHHHjH11HHIgH<$HD$TIEHD$H|$L1HckHHPH tHPHD$H8 HHpHcH9SAL(HcHnHHL$dH3 %(H([]A\A]@1Im}HulHtT9HpHx{~KIUHD$HT$uHH|$@S@H|$H|$t H|$H<"H5=H81H8"H5bHH81YHZ<"H5GH81AH8"1H81.i4@AUIATUSHH(H5k9"dH%(HD$1HHH H)11HHIH<$HD$TIEHD$H|$L1Hc HHPH tHPHD$H8 HHpHcH9SALa(HcHHHL$dH3 %(H([]A\A]@1Im}HulHtT9HpHx{~KIUHD$HT$uHH|$a@@H|$>H|$t H|$*H*:"H5v;H81!H6"H5FH81H9"H5SEH81Hb6"1H81 @AUIATIUSHH8H57"dH%(HD$(1H)HHEH11HHHH<$HT$ Ht$HH|$H|$  HD$9IEHD$H|$H(1Hc~IHPH tHPHD$H8 HHpHcH9AHkHcLLHL$(dH3 %(\H8[]A\A]H5k)LHH4"H5/DH811MeHutLAt[HpHx8~KIUHD$HT$uHH|$@#@H|$nH|$t H|$ZHZ7"H58H81QH3"H52CH81)H*7"H5BH81H3"1H819@AUIATIUSHH8H584"dH%(HD$(1H)HHEH11HHHH<$HT$ Ht$H7H|$H|$ :HD$9IEHD$H|$0HX1HcIHPH tHPHD$H8 HHpHcH9AH4kHcLLHL$(dH3 %(\H8[]A\A]H5&LHH1"H5_AH81G1MeHutLAt[HpHx8~KIUHD$HT$uHH|$@S@H|$H|$t H|$H4"H55H81H0"H5b@H81YHZ4"H5?H81AH0"1H81.i4@AUIATIUSHH(H5h1"dH%(HD$1H"HHD$t}IEHD$txMmoH|$4H|$ItnAIucLHHH/"1H81AHD$H|$H|$A@tA@LH|$HH|$HD$H1"H1HI[HHLHھHwHL$dH3 %(LH([]A\A]DAH|$H[HfD+rH|$t H|$1H  1IiAoLH|$IʼnQ11ҾL111L@HH11ҾLc1L$HH11ҾL71LHH11ҾL 111LHHH]11ҾLV1LLHH1HY-"H5m4H81H0"H5 2H81HGfDAWAVIAUATIUSHXdH%(HD$H1H=nQ"HD$ :HD$(ADžt2~}DTHD$(`Ll$ I,$IT$HT$DHjLLD$01ɺH5P"H=P"H\$0H%AH9tBH=sP"H\$0H%AH9tH|$0@&1AfDH|$8LIHIHHcHT$(hH|$IHt$(1HHH1Ht$ MLHH|$ E1xH|$ E1DUH|$ 1M3Ht$H HHHHuHE tHuHT$(HHt$(HHHHL$HdH3 %(HX[]A\A]A^A_ H=9/ H=9HN"HN"3HVHvDH=9HHeN"H|$(6H=: HH%N"AHcMlA!IAELl$ IuHD$(I,$H|$ Hl$ sIHEMHL$(LDHLl$ uHXH|$(\IHLl$ zI $uHHk@HZHD$(fH(H("1H811Ll$ /H|$({HI$H,H=!HC1JHSH+Ll$ HD$(HT$HcI|HL$(1HHAIHD$ 1H= IT$Ll$ HD$(I,$HT$vfUSHHtQH2)"HHx("1H8HH+uaHk 1H5HHt4HH[]fHtHH("H8HH)'"1H81H)"H56H81}ff.fSHl'"H56H~)"HH;KH&"H;H5D6HH("H(H9("HHH5,HH;HH5m H;HH5H;1HH5,H;1HH5+}H;1HH5eH;HH5n,JH;H_,H5}H;HI,H5#~H;1HH5* H;1HH5H;HH565H;HH5*5H;HH55H;HH55H;HH55gH;HH54LH;1HH5 4H;1HH5 H;1HPH5H;1HH50H;1HH5N*H;1HH5\3H;1H0H5I3H;1HhH563H;H}H5*qH;H"H5 4VH;HwH53;H;1HH52#H;H53OH;H53;H;H53'H;[ H53fHHHHЃfUHSHHH|$Ht$HH|$H7 u!HHyHH[]HGHcЉH9uHQHH[]H_ff.@HH|$Ht$IH|$H7 u!HHHD$HHGHcЉH9uHHD$HH߼ff.@UHSHtF1HcMHHxH tHxrt7tHH[]H""H5\2H81GH""H592H81/ff.@HH|$Ht$HHzt HH!"1H81ٻfHH|$Ht$IHAt HH[!"1H81菻ff.@H!"SH51H8uH""H "H5~1HHHBH "H;H5])HHH;H>H5A1H;HH511H;HH5'1H;HH51qH;1[HH51XgS5yE"H H5gE"H[Hff.UHSHdH%(HD$1HHbHHHHHHHHt$HgHHcHt6Hct$HHt6HT$dH3%(u HH[]fDAUIATUSH(H_DgdH%(HD$1rIHD$L9s,DHkHHHH|$H>I9wH5BE"I}HL$?H|$HD$ HD$H u3HHHw*HL$dH3 %(uH([]A\A]@HPH=D"H5'/1蠸UHHSHHH5D"1H8 u&HHHEHcH9u;H1[]@HPHxHUMff.fUHSHH5"HtsHHxH[]H5C"HHaHhHuH=HuH誺uH=C"H52裷H "H52H81苷ff.H5bB"-HHH"1ff.ATAUHSHHdH%(HD$1H$E0tkHmAH5"HIHtWH"HH03HH5cA"H11HtzHHfH5)"HqI1HLHHL$dH3 %(H[]A\@#ExbH$uHHtH4HHH= oHH@"FHmAu HuH<$tH1DHJ"H50H81葵USHH50"HwHtHHH1ɾ*:HH[]H(HUSHH5"H'HtHHH1ɾ,HH[]HHHH5"1ɺ!HHff.SHHt$@u|HtsHƒtfuaH5*"uH|$HHL$H t*HI1Ҿ\H'Ht'HD$H[Hf.H=L@"1 ff.fU1H1SHH5?"11HILvHHH[]@AT1USHHdH%(HD$1D$Ht\5>"HHI/LHHqH)HH^HT$HH=FHcT$u!1HL$dH3 %(u*H[]A\fDH5!?"HTL,0ATIH=TUHSHH0dH%(HD$(1HT$ Ht$Ht$LD$DL$ HƋD$ uOH u/HHHuHL$(dH3 %(uTH0[]A\DHVHUVf.5N="LHcT$ H5N>"HHTY]ff.fAVEAUIATIUHH52="SHLEMLHHH[]A\A]A^AVEAUIATIUHH5<"SHLFEMLHHH[]A\A]A^HH|$ H|$1-H5<"HHtH5Q="HL$HOHf.SHH|$H|$1H55;"HHt511HHtH5<"HL$HH[@H=6HH:"ff.SHH|$H|$1HE1K{H59"HTLrUHSH(dH%(HD$1.H5b8"HH5_8"HHtHHHH5e7"H\$H$Ht7H"HH80HT$dH3%(uEH([]fH=9(OHH7"1H=g#rfDATAUSH@57"dH%(HD$81HT$ Ht$Dd$$HD$HHf8"H=ol$(HD$D$ HcT$ u0H1HtQHL$8dH3 %(u)H@[]A\H58"HTH1#U11SHH(HwH?dH%(HD$1HtmHH57"HHH$HcSHTHT$HcSHTHT$HHH9CuHL$dH3 %(Hu H([]Ð1wAVIAUIATUSHHdH%(HD$1H6"D$H855"H~I葵LHHHcLhHHHT$HH=yHcT$HÅH "HH0HtBH5C"HcHAEHL$dH3 %(H[]A\A]A^Ð1@L%" H=I $7I $ H= I<$1AH V%H| @H55"HTL1SH"H5 H81舩ATUHSHHdH%(HD$1D$1uwH~"H8564"HIH"H8|HHH] óLHHHHHT$HH=kHD$dH3%(urH[]A\DL%y" H=0I $I $#H=I<$1AH #H ff.@ATUHSHHdH%(HD$1HO"D$H853"HIHu"H8EHH躹H] 茲LHHHHHT$HH=HcT$u&1HL$dH3 %(H[]A\H53"HTLf.L%" H=I $_I $ H=jEI<$1AH ~"H1'AWAVIH5~"AUATUHSHH(dH%(HD$1觻I菨HD$NM>MnHD$HHƒLdLILI>IHMSLL?WE1LLLLfMt1LXLHHL$dH3 %(H*H([]A\A]A^A_fD1INHL$jHH|$EHH+~8HD$M>HD$Mntf.H|$IH|$t H|$KH5 "LH=0"H5^ 1跤HX "H5!H81诺H@ "H5 H81藺H5p "L8H=0"H59 1cH5G "LH=0"H51:f.HH5!HHHHDAUH5!ATUSHHNHtaHHHcI胮IE~01fHðH[LHD9uHL[]A\A]DH[]A\A]yfATH5!USLH11ɾHHH@HLdH=-"H`LHH%11ɾHH@HLdH=u-"H|WLHH٢11ɾHxH@HeLdH=!-"H LHH荢11ɾH,H@HILdH=,"HLHHA11ɾHH@HLdH=y,"H8sLHH11ɾHH@HLdH=%,"H'LHH詡11ɾHHH@HuLdH=+"H`LHH]11ɾHH@HYLdH=}+"HLHH11ɾHH@HLdH=)+"HCLHHŠ11ɾHdH@HLdH=*"HLHHy11ɾHH@HLdH=*"HLHH-11ɾHH@HiHlH=-*"HtHcHHHH[]A\DH= HHE*"H=HH)"H= HH)"0H=x HH)"H=PHH})"XH=% oHHe)"H=OHHM)"H= /HH5)"H=CHH)"H=rHH)"Ht$HHT$ t$ t H|$nHL$dH3 %(u H(tߺff.@H(H5Y"dH%(HD$1lHt>Ht$HHT$ 襽t$ t H|$HL$dH3 %(u H(_ff.@HH5!dH%(HD$1Ht@1HmHHt H<$肤HHt$dH34%(Hu Hrݹff.fUSHHHt$H5O!rHtN1H|$Ht H|$H1Ҿ7HdHt8HT$H5C%"H[HD$H[]H "H5<H81H=8&"1fHH5!ܮHtH?HHsff.HH5y!蜮HtHOHHHDNff.UHSHH54!WHt1H5#"HH@HtGHH谦u"HH[]H""H5>H81 H=:%"H5~1H"H5H81ܘff.HH5!輭HtHHHHЃifHH5Y!|HtH菭HHHD.ff.USHH5!:HtfHHJHH*H8uHH[]f.H5HH贰HHYHH[]f.HH5!謬Ht)H_HtHHNfDHIfHH59!\HtH/HHff.AUATUSHH5!Ht}H艘HHtYHHcI计IE~+1@HH軰LHD9uHL[]A\A]DHA[L]A\A]_ff.@USHH5G!jHtDH蝬HHt%H=HHHH[]HH[]ff.HH5!Ht)H?HtHHίfDHfSH5!诪Ht6HH/x H賖w[ۮ[?ff.@ATIUSHHH?dH%(HD$1 HHcH9woHt$L@l$HsH u-HLHL$dH3 %(u&H[]A\@Hsf.H{H= "H54 1荔蘔1@uHt t@HH5M "4KHHff.fAWAVAUIATUHSH8Ht$H|$dH%(HD$(1H蕷H5!HIHgH5"HHxHH=LpLQH91M|$I<$H u{HHcljH9tvLHtIt$HH߉Ɖ~FuqLMA~I<$H tI|$fu@HcHDHT$(dH3%(H8[]A\A]A^A_ÐuVH="H5A1角Mt{H"H1H=R =HD$HHHL$ALl$HD$ZfDLMA~VH "Htd1H= ƸHD$HHHL$HD$f1詸fH=?HH"%H=AHH"|Hq"Hm"胑Ht!H5 H81[薰ff.1DAWAVIAUATIUHSHH5*"H$4H5!HH>H5"HH芾HRLhLfH1AH5"HA\HEDH>~1LxMA}F@u+D$ RL$ uH߉L$ H蜐L$ H$IDH=/"H5@1fufHŋt H<$蔶@H舨DEH$H="I1H5蓏LMA}螤fHXHH HHIH+HDMLD舨HH訏ATIٹUD1H5!HT$H=-"H-"HH[]A\A]A^A_H-"H$%H$HǨt$襕辶H!H5 H81薎!5DAUIATUHSH(dH%(HD$1HD$-f.ۋ~WHl$YHD$ M>uDH4HLLHL$(dH3 %(NH8[]A\A]A^A_t.HD$ Ht H|$ jٟftH|$ H蠳H=H1迆Hl$HD$ L;PDHcIl@HrEcHl$HH|$葜L|$SHME`HHDHD$ Hl$uK1 H|$ vHcI|gH1HHD$o菠ӉHl$fdfDAWIAVAUIATAUSHXdH%(HD$H1tkHD$ HD$(ŅrH=1SImLt$ f.HD$HT$(kD胂HD$(rImIEHD$XH|$(AH@,'H|$Lc,1L̑HD$H1H5!LIHH5 "L苭HIPH@HHD$_LGEH "HT1H=]HHD$HLHL$0AHl$0HD$8Lt$@H|$ H|$HcPHD$HL$HdH3 %(HX[]A\A]A^A_蛖H|$LcH|$H|$H ucHL9|?H|$HD$H|$(\H|$(葱M@LH)譳H|$oHGf.[#Lt$ ImIUHT$HT$(]HH|$(f.H|$(t H|$(PH"H1H=肤HD$HLHL$0Hl$0HD$8Υ^fH|$L=τHt$H uiHLLƉZIcL>fu>HT$(HZH|$(D$ D$HvfHT$(H|$|Le>HH|${|F}t1yfECH|$M|L@Hf"6EH|$|LH/" H=豭HH"H=^葭HH"2HcMtAIAܺLt$ ItIH|$ HT$ IHMt'Lt$ Im>Im.HD$ AHD$xIHD$xw}NH|$(躦HrH=[H1Lt$ H+DH|$zH="H51zHcI|t:HuB˹Lt$ It@H|$ VHT$ IHιImLt$ =|IHD$ IEImHT$(HD$HJ!H5fH811zf1DAUATUSHdH%(HD$1@HHHƒH5b!譎H5HH若H5"H! H=I $茫I $H=/rI<$1AH Hѹ^fHVHcH9dHvHH5&H讣H!H8L%! H=EI $ܪI $H=2ªI<$1AH H!讠fHPHcH9HpˈO@x@HH|H=HHM!H$@L%! H=`I $I $H=ݩI<$1AH H<ɟ@HA! H=H 萩H $H=wH;A1H HܷdDL%! H=I $'I $ H= I<$1AH FHlH=!H5 oHoH=!H51oH=!H5loH=!H5YoH=!H5FoH=w!H511oH=b!H5+off.AUAHATIUSHH(H5!dH%(HD$1ڃHUpHD$E$I,$A4H5u!HH!11H8豖IH5'!LoH5!LHI芡LBH5!HH誝t+HD$H5!H]HL$H;H5$!HH)LavHH~HC 5!HH0vH5HAyH5r!Lb5!HHv11訂HHL$dH3 %(*H([]A\A]fD1Md$AHH|$< H=3诞HH! vE~vHD$I,$AuHZH|$H5!HPH=SHH!0@ H=/HHm!H|$t H|$~DH=!H5U1glH=!11Wl蒋fATUSHH|$H|$1 H5:!HHǙH5@!H踙Ht9H5!HHL$HH?!HH0贔HuHupHH[]A\HH5y!H虀IHtPHH57!肀LHGvH5!HH蕞HH[]A\H!H5H81AkHB!H5^H81)kfATH=US臜H= H!oE1E11H11H!0u!E1E111H1 u!}E1E111Ht{!lH!H5H;msH-!H;H5HESsH}H5Hq!HR!H"zH}H5HHE!zHq!HH'!H2qH}H!H5yH!HH!H2_qZL%!H}H5fI$yH!H5QHHvH;H5RsH=H;E1HH=轚H;E1H՗ H=蔚H;E1H謗H=kH;E1H胗H=BH;E1HZH=H;E1H1 H=EH;E1H H=)ǙH;E1HߖH=螙H;E1H趖H=uH;E1H荖 H=LH;E1HdH=#H;E1H;H=H;E1HH=јH;E1HH=記H;E1HH=H;E1H藕H=lVH;E1HƺnH=!H5tƐH=H;E1H- H=$H;E1H H=×H;E1H۔H=蚗H;E1H貔H=qH;E1Hƺ艔H;H#H5yH;HH5xH;HH5ruH;1HH5ĺZH;H+H5u?H;HH5c$H;1HH5X H;H]H5LH;1HH5DوH;H H5;辈H;1HH5&覈H;HH5wH;H5 輎H;H5討H;H5蔎H;H5 耎H;H5lH;H5=XH;H5QDH;H50H;HQH5ՇH;HH5躇H;1HH5袇H;HsH5臇H;1H;H5oH;HH5TH;1HH5H}H5)H}H5H}H5H}H5 H}H5ՇH}H5H}H5談H}H5薇H}H5聇H}H5 lH}H5 WH}H5BH}H5-H}H5H}H5H}H5H}H5نH}H5ĆH}H5识H}H5蚆H} H5腆 H=ԍH H=H1!贍Ȟ H=H !蔍H謌H=H!tH=)H!\H=kKH=aH!3 H=XH!H=LHh!H==HH! H=.H(!ӌ H=#H!軌H=H!裌 H=H!苌H=H!sH=H![H=Hh!CH=HH!+H=H(!H=H!H=H!H=H!ˋH=H!賋H=H!蛋H=Hh!胋H=HH!kH=H(!SH=H!;H=H!#H=xH! H=oH!H=hH!ۊH=THh!Ê H=EHH!諊[]H2!A\H !H5BH81YH!H5jH81Xf.DcUSHH5!dH%(HD$1mH1HH^Hc12jHH@H tHCHHH$^H t7HCH4$HSH)H94HKkHHL$dH3 %(u8H[]ÐHH4$HSH (H5H=h+wH=HHLpW[H]A\@H5!Ht$H11xzHuHcHH= 蟃HHe!H!H5 H81Qff.AUATIUSHH-!dH%(HD$1HfHHLHfHHtuHHFhHt$HI6hHI;qH1q9t1HL$dH3 %(u*H[]A\A]Ë$;T$uLL {HlpGH(!H5!H81Qff.@USHH5Ƿ!eHt5H蝊HVHHtOHHXH߅t#H[]0}H!H5H81PRH=!H5f1~PH=!H5E1iPfH-!SH5aHH!H8;`H\!H!H5HHH`H;H5nH_!r]H;HH5lsH;H(H5sH;HH5sH;1HH5'ysH;HH5^sH;1H"H5FsH;HgH5?+sH;1HH5sH;1HWH5rH;1HH5,rH;1[HvH5rf.UHHSH(dH%(HD$1H\$HT$ H>ct$ H1HvHL$dH3 %(uH([]mH!SH58H8uWH!HFW WRpMZmnH;H5\?xH;H5M+xH;H5xH;H57xH; H5wH; H5wH; H5wH;H5wH;H5wH;H5wH;H5wwH;H5cwH;H5OwH;H5;wH;H5'wH;H5wH;!H5vH;#H5vH;%H5vH;'H5vH;)H5vH;+H5vH;-H5{vH;/H5svH;1H5_vH;3H5}KvH;5H57vH;7H5#vH;9H5vH;;H5uH;=H5uH;?H5puH;AH5uH;CH5puH;EH5|uH;GH5auH;IH5|ouH;KH5T[uH;MH5|GuH;OH53uH;QH5uH;SH5 uH;UH5tH;WH5 tH;YH5tH;[H5tH;]H5tH;_H5tH;aH5 tH;cH5ktH;eH5LWtH;gH5XCtH;iH5l/tH;kH5tH;mH5ltH;oH5sH;qH5sH;sH5PsH;uH5sH;wH5HsH;yH5sH;{H5P{sH;}H5gsH;H5SsH;H5?sH;H5+sH;H5sH;H5sH;H5rH;H5rH;H5rH;H5rH;H5rH;H5rH;H5wrH;H5crH;H5OrH; H5;rH;H5'rH;!H5rH;AH5qH;H5qH;H5qH;H5qH;H5qH;H5qH;H5qH; H5sqH;@H5_qH;H5KqH;H57qH;H5#qH;H5qH;H5pH;H5pH; H5pH;@H5pH;H5pH;H5pH;H5pH; H5opH; H5[pH; H5GpH;H53pH;H5pH;H5 pH;H5oH;H5oH;H5oH; H5oH; H5oH; H5oH;H5oH;H5kojH\H;H5HLowH[H;H5H-o`H[H;H5Ho9[H[H;H5wHndH[H;H5mHn\Hs[H;H5d[HngnUH5!SHdH%(HD$1ZYH1HHmHc1UHH@H uRHHH$sm~\HH4$ tCHCHSH)H9kHVHHL$dH3 %(uoH[]ÐHCf.HHSH,!1H81CH!H5H81CH (H5H=,YTb@AUH5ß!ATUSH(dH%(HD$16XHIOHHYL1?{AŅ~%LtHHxA9u1HbHc1wTHH@H Ht$HHD$QbHHt$ ttHCHSH)H9HUH(VH5!H\$Ht_H!HL$H8njHL$dH3 %(H([]A\A]HHSHCLH= gsHH]!HUHL!1H81AH9!H5H81AH!H5H81AH H5H=4aR`ff.AWAVAUIHATUSHHɥ!Ht$H3jHH5!HH|$nHǨXH5j!HH|$nHŃHÃHykH5!LUIHHxLmSfHH9LHH!H5RH81>DUH54!SHSHtZH_HHVu.YxHCHHtFHHuHH[]ji?H[H]+UH\!H5H81C>H!1H810>ATUSHupHtgHƒtZuUIHH5h!RHHtCH5T!LRHt/H_Ht:HC HgH[]A\fDHCH!H5H81=H !H5.H81x=ATIH5Й!UHSHH0dH%(HD$(1=RHD$H ?HD$I<$H|$Md$H5R!H|$ H\Hl$ HHdH5 !Ld$ HHHdHL$(dH3 %(HcH0[]A\fHl$VIH|$HD$NHD$H HPHT$HPH|$HpHT$HS HuH!1H81<EI<$HD$H|$t0Md$HH|$nH|$DH?Hl$HnH|$-H=XmHH!H=3lHH!HHHD$H|$t H|$)nXcZH$!H5XH81 ;ff.USHHt$H5Z!OHtBH|$Hct1HYTHHtXHH]H߅t)FHD$H[]H!H5H81:FH!H5>H81i:H!1H81V:fDS1H!;HkHt HC H[H!1H81:@UHHq!1SHH#!H8;HHt#H[HtHC HH[]jH2!1H819fDHH5!NHtHH!H5H81j9f.SH|!H53HΡ!HH;;IH!H;H5HH!HIHA!H5HHoFH;HH5i\H;HH5\H;HH5r\H;1HH5Lv\H;H'H5D[\H;1HH5C\H;1[HH5N*\f.?AWAVAUIATUHSH1LeHg:HH9}TL5 !LI6H_HuE1Le0HI9}H5!HJHt*H?Ht5HC LHt$HH8H!H5H81.ATUHH5!SCHt/H1HYHHIILt=4H[]A\+4Ht!H5TH81c.HH5!!LCHtH/:Ht$HH~XH/!H5H81.ATUHH5ϊ!SBHt/H1H7YHHIbLt}3H[]A\k3H!H5H81-HH5a!BHtHfHt$HHWHo!H5H81V-1UHH5!SH7BHt$HH7EHH7t"HH[]H!H5H81,HH5!AHtHSHt$HHNOH!H5^H81,UHH5a!SHAHt$HHDHH>t"HH[]H_!H5H81F,!HH5!,AHtHPHt$HHNH!H5H81+UHH5!SH@Ht+HHHHH\DHHFHH[]fHH5a!@HtHoHHH3cff.AWAVAUATUSHHHIHIHI5HIHH__HMMAWLHHH=K1HH[]A\A]A^A_ff.fUH5!SH?Ht=HmdH/HHtUHMHH0 bH߅t#H[]VHy!H5H81`*,HT!1H81H*#ATIUSHt=HHHx\H5!L?Ht0HHJtH[]A\H:HHߒ!H5~H81)H!H5ľH81)ff.HH5a!>Ht3HO]H@HxHDHfDHH>ff.@UH5!SH*>Ht5HbHU.HHtMHHNH߅t#H[]pUH!H5H81(+H̐!1H81(ff.UH5t!SH=Ht5HMbH-HHtMHH`H߅t#H[]THa!H5H81H(s*HtgIHE uL;m} HE HH[]A\A]A^A_IHE t?HJ|=VHH5zHH!H81m"H!1H81Z"Hm HU!H5'H81<"ff.AWAVAUIATUHSH1LeHQ:HH9}TL5e!LI6H3IHtFH5_{!H'3Ht2H%HHt:Lz!Hk H[]A\fDH#H!H5óH81H!1H81DATIUHSH dH%(HD$1HB H$HD$tjI$HD$H|$H|$I'*H|$HD$U11LHHHH$HU HH=HD$H|$u'HL$dH3 %(HH []A\H|$OtiD%5H|$t H|$O1911ҾHW35LH76HIH$HE MTH!1H818s;PX1HHс!H81S1H2y!HEQHt HC H[fUHH5y!SH0Ht)HH/HH7t"HH[]H!H5lH81Lff.AUH5x!ATUSHV0HHI&ŅxLHc%IŅt)1LkUHSULHL9uHL[]A\A]fDH!!H8tH[]A\A]3@H! H=HbH SH H=ŰSH;A1H H,bIHs!H5EH81Zf.UH5tw!SH:/Ht5HSHeHHtMHHMH߅t#H[]FH!H5ӯH81H!1H81ff.UH5v!SH.Ht5H]SHHHtMHH&H߅t#H[]EHq!H5CH81XH~!1H81@ ff.UH5Tv!SH.Ht5HRHEHHtMHHbKH߅t#H[]`EH!H5H81Hl~!1H81{ff.PXH5xHH!H81fUHH5u!SHg-Ht[HH:HH|=HH6tuH[]@1H1[]H}!1H81bfAUIH5 u!ATIUSHH,Ht6LH-HLI"KLHHT!t&HH[]A\A]H!H5uH81UDATUHH5t!Si,Ht-HHyPHHI $tHH[]A\LJMH|!H5H81fATUHH5/t!S+Ht/H1H7BHHIFLt}H[]A\ kHd|!H5H81HH5s!+Ht)H_LHtHH@fDHfATUHH5os!S9+Ht/H1HwAHHI 2LtH[]A\`H{!H5;H81HH5s!*Ht)H2HtHH?fDHfUHH5r!SHw*Ht$HHw-HHDt"HH[]HO~!H5!H816HH5Qr!*HtH"HH7^ff.ATIUSHt=HHHx\H5q!L)Ht0HH tH[]A\Hx%H^H}!H5aH81vHz!H5tH81^ff.HH5qq!<)Ht3H,H@HxHDHfDHHd)_ff.@HH5q!(HtHH|!H5H81f.UHHp!1SHHy!H8KHHt#H[HtHC HH[]HHy!1H81FfDSH\z!H5H{!HH;#Hx!H;H5HH{!H"Hqx!H5HHO H;HH5I_6H;H5H5e6H;1HMH5q6H;HH5V6H;1H*H5>6H;1H"H5-t&6H;HH5 6H;1H?H55H;HH5x5H;1HLH5|s5H;HH5R5H;1HIH5tr5H;HnH5,r5H;HH5W5H;HhH5o<5H;HH5w!5H;1HH5-Z 5H;1H]H5:p4H;H+pH5d;$H;1HH5p4H;1HgH5r4H;HH5^4H;[HH5Nt4@-UH5dn!SHdH%(HD$1Z%H1HH:HcH1!HH@H uQHHH$R:x[HH4$ tBHCHSH)H9jH"HHL$dH3 %(unH[]HCf.HHSHlx!1H81Hx!H5MH81H H5HH=,nY .@UH5Dm!SHJ$HtZH-$HH'u.HHaHHtFHHFHH[];H[H]%Hw!H5H81Hw!1H81SHHt$H5l!#HH|$HpH|$HD$ H6Ht$H t,H~HcωH9u+HvHEt HD$H[HH>Hv!H5H81Hw!H5äH81 ff.ATUSHupHtgHƒtZuUIHH5k!"HHtCH5k!L"Ht/HCHt:HC H~*H[]A\fDHhHiv!H5H81P H v!H5:H818 AUATIH5k!UHSHHXdH%(HD$H1!HD$HHD$IHD$8HD$Ll$0HD$@HD$ -1I<$H<$HD$HD$HEH<$SLH$H$H HPHT$ HPHt$ H|$HT$HU HHL$HdH3 %(HHX[]A\A]IT$HT$VIT$HT$BHH5b!H|$(HLd$(HL3HD$H5+!HD$(HLH3KHD$H5!HD$(HLHz3DH|$ &>HD$ hfH=ÞH|$ t H|$ v=')H)s!1H81] H^s!H5 H81E DAUATIUHSH(dH%(HD$1 HD$SI$H$ID$HD$`HE1eCH|$H<$H rH9Aąu%H<$H H2Aą'IH.QH=HD7 Ht$HHD$H|$BH5f!H<HHHIo!Hg!1H8 HH5@1IHt H@HHHBHL$H HDHH$HC0HIa1M)Me LHT$dH3%(KH([]A\A]fMl$HAH|$IE1fDHHI]~dI$HD$H$IT$HT$t*Ml$>Hu*|fDHJAHH|$:HH|$t H|$:%Hp!H57H81HL$H3p!H5H$H81^Hp!H$H5kH81B}&ff.fgH5[,ff.ATUSHupHtgHƒtZuUIHH5W!CHHtCH5W!L,Ht/HoHt:HC HN%H[]A\fDHHa!H5H81H]!H5đH81AUATIH5V!UHSHH8dH%(HD$(1 HD$HrhHD$ F1u1H`HL$(dH3 %(HFH8[]A\A]fDM,$uoAHL(HH3IHL1oH5!IHLu 11H0d@Md$wHtH|$ *;vfDkHHD$ fAH5!HH]!H8I8fH=CHD$(LL$HH!*fDH|$ AA)DLH|$ HD$ HT$ H tDHBHRHD$Ht$H|$HT$HU H&Hg[!1H81cHHHT$H봾H=?'HH!H|$ t H|$ )1{H _!H5H81.ff.S1H"T!HuHt HC H[HZ!1H81@PXH5.HH^!H81fUHH5S!SHk Ht(H5S!HHT Ht)HHH[]NH?^!H5ǍH81&HHxHHHHHfUHSHHHH~[!H0Hu H1[]HH5¸uH[]SHt"H6Ht@t[HHH[H5R!HY Htb11HHHtfHHcH9unHH߉[*HHT$*HT$HH[HN1bH\!H5{H81HX!H5H81Hf.HH5Q!Ht3H"H?H9wHDHfDHHTff.@HH5Q!<Ht3H?H?H9wHDHfDHH_ff.@AWAVIAUATIUSHhdH%(HD$X1H=~!HD$(HD$0ADžt*~5 u0[iLl$(I$HD$ID$HD$ AH|$0LD$@1LH5~!J(H|$+H|$ H$HD$H5~!H~!HD$8HYHrX!H8HL$8HHHH|$@AH4t@ozAH|$HE1H4t@?ZAH5O!LXIHHL$ H HHHHL$ HL$HEALAUHt$ZYHT$XdH3%(LkHh[]A\A]A^A_f.H=ۉ/"H=qEH\}!"HX}!HD$0HH|$0`#HyHcljH9HIHHL$"HL$AAI$AHD$ID$HD$ f.Il$HD$0ZHuM1LD$@LH5|!%H|$C)H|$ H$HfDH|$0q"H=l HH|!HcMlA2/I%/AE/Ll$(IH|$( Hl$(IH.E.MuNHD$(I$LHD$@ID$Ll$(HD$ f.1I$Ll$(HD$uHl$ G~ HZS!H5H81QHRW!H5چH819H|$0HI$IHsH=\LHC1Ll$(HcI|HD$0TfHu:T-H|$(H|$(kHl$(IHH-V-D[IHD$(Z1H=KI$Ll$(HD$ID$HD$ "ATUH1SHHH0dH%(HD$(1"HI!HH1H!HHD$!HHD$!HD$ Ht;Ht$LHL$(dH3 %(H0[]A\HD$H5Ty!HL$HHD$HD$ HuH5x!HtHR!H8'HD$ rDH=rHHx!V fDUHHQJ!1SHHR!H8HHt#H+HtHC HH[]kHP!1H81fDHH5I!HtHHT!H5 H81jf.UH=SHHS!H5Hx!HVR!H;H#HP!H;H5HHS!HHQ!HQ!HH2HH;H5EH;HH5?7H;H+H5z=H;HH5dH;HH5N>IH;1H]H5ǃ1H;1HuH5;EH;1H}H54H;HH5B= H;H3=H5'=0H;HH5= H;1HyH5^ H;1HH5# H;1HH52m H;H5ĂHH4H=kEc'HHs H=B'HHR H=(!'HH1 H='HHH=n-HHH=P-HH H=?H-HH;HH5pH;H5SvwH;/"H5cH;?H5OH;H H[H5]5DGAWAVAUIATUHSH1LeH:HH9}TL5P!LI6HHuE1Le+HI9}4LJ<HH tdIHE uL;m}HE HH[]A\A]A^A_IHE t?HJ|=HH5)?HHO!H81H>M!1H81Hm HO!H5H81t@UH5E!SHdH%(HD$1JHtoHHuHHtDH1HH$HH0H߅tHL$dH3 %(u7H[]HL!1H81HN!H5H81fUH5TD!SHdH%(HD$1H1HHHcH1HH@H uQHHH$~[HH4$ tBHCHSH)H9jH*HHL$dH3 %(unH[]HCf.HHSH|K!1H81HM!H5~H81H QH5~H=\C@ATUSHuxHtoHƒtbu]HH9tGH5C!HNIHtFH5B!H7Ht2HJHHt:LZHk H[]A\fDHHM!H5}H81HJ!1H81DATIUHSH dH%(HD$1HB H$HD$tjI$HD$H|$H|$I7H|$HD$11LHH H$HU HHMHD$H|$u'HL$dH3 %(HH []A\H|$tiD5H|$t H|$1 11ҾHgLHHIH$HE MTHH!1H81HPX1HHH!H81'UHH5@!SHHt$HHwHHt"HH[]HJ!H5{H81AUH5c@!ATUSHHHIŅxLHcDIŅt)1L+HLHh9uHL[]A\A]fDHqG!H8tH[]A\A]4@HH! H=(H 0H H=wH;Ac1H zH|(HI!H5zH81f.UHH5A?!SHHt[HHHHHHtuH[]@H1[]HF!1H81'H(I!H5zH81ff.@AUIH5>!ATIUSHHHt6LH-LI"LHHdt&HH[]A\A]HH!H5yH81EDATUHH5>!SiHt-HHIH~LHt H[]A\H8H!H5.yH81HE!H5=yH81HH5=!HtHHt$HHHG!H5xH81qUHH5Q=!SHHt$HHHH t"HH[]HoG!H5exH81VHH5!H81mH>!1H81ZHm HU?!H5pH81!H5NpH81H!>!H5rpH81xUHH5q4!SHWHt)HHWHHt"HH[]H*>!H5oH81H=!1H81ff.AUH53!ATUSHHHIŅxLHctIŅt)1LHLH9uHL[]A\A]fDH:!H8tH[]A\A]d@Hff.AWAVAUIATAUSHHXdH%(HD$H1HD$HD$0HD$HD$8HD$ HD$@HD$(E1ImHl$A'HD$HD$ Ht7H|$(F+@IUHT$AtIUHT$ ABHuH5*!HIHoH5*!HIH<Ld$E1It LIH|$ HHt$(HD$D$(HL$LLL H5fHHt HHH5WOHH5HOHH#LH5aOHHHL$HdH3 %(HX[]A\A]A^A_HD$Zf.E~ HD$(fH|$(t H|$(D8Lp|$(H2!H57eH81H2!H5WeH81L/H5h.!H|$.H_1!H5AeH81VUSHH5(!H7Ht3HHuHHH[]fD:f.ATUHSHt-IIH5@(!HHt LHH[]A\HIff.HH5'!|Ht)HHtHHNfDHfHH5'!,HtHHHNff.HH5a'!HtHoHHHDff.HH5!'!HtHHcHH[fDAUH5&!ATUSHfHHHHt}HeAąxNHcIEt+1@H;HLHD9uHL[]A\A]DH!-!H8t+H[]A\A]@HA[L]A\A]@Hy.! H=0H H H=ybH;Aa1H xbHtHX/!H5bH81?ff.@AVAUATIUHSH0dH%(HD$(1HD$*M4$AH5R!Hl$Lt$Ll$ HHH*!HL$H8H H5mJHHHH5IR!H11HHIH5faHHHwH5+HHHH59aHHLHL$(dH3 %(H0[]A\A]A^Ml$H|$t H|$H5IH @H=:+HHMQ!H=$HH5Q!;qHD$M4$AuHOH|$ @Ml$~/H;HH5 #I$H}H5W/H!H5HHH;HH5H;H5 ,H;1HH5 H;1HHH5UH;1HH5UH;HEH5uViH;1HH54 QH;1HeH5LV9H;1H H5@V!H;1HH55V H;H*H5UH;HH5UH;HH5UH;[]HgH5?A\H!H5;VH81衸H!H5TH81艸HHOSSL_DEBUG: empty sk!ossl.c [%s:%d] items in sk < -1???inlen <= LONG_MAX / 20123456789abcdef(null)error on stack: %s (%s)error on stack: %sTurning on FIPS mode failedTurning off FIPS mode failedOPENSSL_init_sslOpenSSL2.1.4OPENSSL_VERSIONOPENSSL_LIBRARY_VERSIONOPENSSL_VERSION_NUMBEROPENSSL_FIPSfips_modefips_mode=OpenSSLErrordebugdebug=errorsto_derpassed data is not valid String???password must not be longer than %d bytesobject in array not of class ##type##OpenSSL 1.1.1k FIPS 25 Mar 2021ossl_bin2hexinvalid OBJECT ID %li OBJ_obj2txt%2d%2d%2d%2d%2d%2dZbad UTCTIME format: "%s"%4d%2d%2d%2d%2d%2dZunknown time formatutcASN1_INTEGER is NULL!invalid tag classtag number not specifiedossl_asn1.cto_aArrayillegal EOC octets in valuemust specify tag numberinvalid tagging methodvalue is too shortinvalid length for BOOLEANinvalid BOOLEAN/%nil expectedunsupported ASN.1 typeASN1_TYPE alloc failurei2d_ASN1_TYPEp0 - p1 == alllenASN1_get_objectEOCUNIVERSALCONTEXT_SPECIFICAPPLICATIONPRIVATEIMPLICIT@value@tag@tagging@tag_class@indefinite_length@unused_bitsASN1ASN1Errortraversedecodedecode_allUNIVERSAL_TAG_NAMEASN1Datainfinite_lengthindefinite_length=infinite_length=initializePrimitiveConstructiveeachBooleanIntegerEnumeratedBitStringOctetStringUTF8StringNumericStringPrintableStringT61StringVideotexStringIA5StringGraphicStringISO64StringGeneralStringUniversalStringBMPStringNullObjectIdUTCTimeGeneralizedTimeSequenceEndOfContentregistersnlnoidshort_namelong_nameINTEGERBIT_STRINGOCTET_STRINGNULLOBJECT_DESCRIPTOREXTERNALREALENUMERATEDEMBEDDED_PDVUTF8STRINGRELATIVE_OID[UNIVERSAL 14][UNIVERSAL 15]SEQUENCESETNUMERICSTRINGPRINTABLESTRINGT61STRINGVIDEOTEXSTRINGIA5STRINGUTCTIMEGENERALIZEDTIMEGRAPHICSTRINGISO64STRINGGENERALSTRINGUNIVERSALSTRINGCHARACTER_STRINGBMPSTRING#D#"d$$# $$$$"$$$$$$$$$$$$ " "/.+, ,,--/././.,/.,/././.0-0-,,,,,h-+,,,,/.,ossl_asn1prim_to_derto_der_internalbad GENERALIZEDTIME format: "%s"explicit tagging of unknown tagp - (unsigned char *)RSTRING_PTR(str) == total_lengthindefinite length for primitive valueType mismatch. Bytes read: %ld Bytes available: %ldType mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ldCan't convert nil into IntegerCan't convert nil into Booleanunused_bits for a bitstring value must be in the range 0 to 7indefinite length form cannot be used with primitive encodingBIO_new_mem_bufBN wasn't initialized!BN_bn2binossl_bn.cBN_dupBN_bin2bnbignum too longinvalid radix %dDon't know how to coerceBN_mod_inverseCannot init BN_CTXBNErrorinitialize_copynum_bytesnum_bits+@-@+-mod_addmod_submod_mulmod_sqr**mod_expgcd<=>ucmpeql?===zero?one?odd?negative?pseudo_randpseudo_rand_rangegenerate_primeprime?prime_fasttest?set_bit!clear_bit!bit_set?mask_bits!<<>>lshift!rshift!to_sto_ito_intto_bnOpenSSL/BNCannot convert into OpenSSL::BNCipher already initialized!Cipher not initialized!iv must be %d byteskey must be %d bytesunable to set AEAD tagossl_cipher.cout_len <= RSTRING_LEN(str)key not setdata must not be emptyout_len < RSTRING_LEN(str)cipher does not support AEADunable to set IV lengthCipherErrorciphersresetpkcs5_keyivgenfinalauth_data=auth_tag=auth_tagauth_tag_len=authenticated?key_len=key_leniv=iv_len=iv_lenblock_sizepadding=auth_tag_lenkey_setOpenSSL/Cipherunsupported cipher algorithm (%li )authentication tag not supported by this cipherdata too big to make output buffer: %ld bytessalt must be an 8-octet stringiterations must be a positive integerAEAD not supported by this ciphercouldn't set additional authenticated dataunable to set authentication tag lengtharguments for %li #encrypt and %li #decrypt were deprecated; use %li #pkcs5_keyivgen to derive key and IVretrieving the authentication tag failedunsupported cipher algorithm: %li ossl_cipher_updateossl_cipher_finalOpenSSL for Rubywrong argument (%li )! (Expected kind of %li )wrong config formaterror in line %dConfigErrorDEFAULT_CONFIG_FILEossl_config.cDigest CTX wasn't initialized!Unsupported digest algorithm (%li ).EVP_DigestFinal_exEVP_MD_CTX_newDigest initialization failed.EVP_DigestUpdateDigest initialization failedrequireDigest::ClassDigestErrorfinishdigest_lengthblock_lengthOpenSSL/DigestENGINE wasn't initialized.NUMERICNO_INPUTprivateopensslOPENSSL_init_crypto#<%li id="%s" name="%s">no such digest `%li 'no such cipher `%li 'EngineErrorloadcleanupenginesby_idcipherload_private_keyload_public_keyset_defaultctrl_cmdcmdsinspectMETHOD_RSAMETHOD_DSAMETHOD_DHMETHOD_RANDMETHOD_CIPHERSMETHOD_DIGESTSMETHOD_ALLMETHOD_NONEOpenSSL/Engineno such builtin loader for `%li 'HMAC_CTX_newHMAC_CTX_copyHMAC wasn't initializedossl_hmac.cbuf_len <= EVP_MAX_MD_SIZEHMACErrorhexdigestOpenSSL/HMACossl_hmac_digestlength must be non-negativeEVP_PKEY_CTX_new_idEVP_PKEY_derive_initEVP_PKEY_CTX_set_hkdf_mdEVP_PKEY_CTX_set_hkdf_saltEVP_PKEY_CTX_set_hkdf_keyEVP_PKEY_CTX_set_hkdf_infoEVP_PKEY_deriveiterationsPKCS5_PBKDF2_HMACEVP_PBE_scryptKDFKDFErrorpbkdf2_hmachkdfKeyword flag set when calling rb_scan_args, but last entry is not a hashThe last argument is nil, treating as empty keywordsUsing the last argument as keyword parameters is deprecatedThe last argument is split into positional and keyword parametersPassing the keyword argument as the last hash parameter is deprecatedSPKI wasn't initialized!ossl_ns_spki.cnewlen <= lenChallenge.length <= 0?NETSCAPE_SPKI_verifyNETSCAPE_SPKI_set_pubkeyNetscapeSPKIErrorto_pemto_textpublic_key=challengechallenge=OpenSSL/NETSCAPE_SPKIossl_spki_to_derCert ID wasn't initialized!ossl_ocsp.cBIO_newi2a_ASN1_OBJECTd2i_OCSP_CERTIDOCSP_cert_to_idOCSP_CERTID_dupd2i_OCSP_SINGLERESPASN1_item_dupResponse wasn't initialized!Request wasn't initialized!d2i_OCSP_BASICRESPd2i_OCSP_RESPONSEOCSP_request_add0_idd2i_OCSP_REQUESTOCSP_single_get0_statuscertificate is not revokedOCSPOCSPErrorRequestadd_noncecheck_nonceadd_certidsigned?createstatus_stringbasicBasicResponsecopy_nonceadd_statusresponsesfind_responseSingleResponsecheck_validitycert_statusthis_updatenext_updaterevocation_timerevocation_reasonextensionsCertificateIdcmp_issuerserialissuer_name_hashissuer_key_hashhash_algorithmRESPONSE_STATUS_INTERNALERRORREVOKED_STATUS_NOSTATUSRESPONSE_STATUS_SIGREQUIREDRESPONSE_STATUS_SUCCESSFULRESPONSE_STATUS_TRYLATERREVOKED_STATUS_CACOMPROMISEREVOKED_STATUS_KEYCOMPROMISEREVOKED_STATUS_REMOVEFROMCRLREVOKED_STATUS_SUPERSEDEDRESPONSE_STATUS_UNAUTHORIZEDREVOKED_STATUS_UNSPECIFIEDNOCERTSNOINTERNNOSIGSNOCHAINNOVERIFYNOEXPLICITNOCASIGNNODELEGATEDNOCHECKSTRUSTOTHERNOTIMEV_CERTSTATUS_GOODV_CERTSTATUS_REVOKEDV_CERTSTATUS_UNKNOWNV_RESPID_NAMEV_RESPID_KEYOpenSSL/OCSP/CERTIDOpenSSL/OCSP/SINGLERESPOpenSSL/OCSP/BASICRESPOpenSSL/OCSP/RESPONSEOpenSSL/OCSP/REQUESTSingleResponse wasn't initialized!RESPONSE_STATUS_MALFORMEDREQUESTREVOKED_STATUS_AFFILIATIONCHANGEDREVOKED_STATUS_CERTIFICATEHOLDREVOKED_STATUS_CESSATIONOFOPERATIONossl_ocspreq_to_derossl_ocspres_to_derossl_ocspbres_to_derossl_ocspsres_to_derossl_ocspcid_to_derPKCS12 wasn't initialized.ossl_pkcs12.cPKCS12_parse@key@certificate@ca_certsASN1_dupUnknown PBE algorithm %li PKCS12ErrorOpenSSL/PKCS12ossl_pkcs12_to_derPKCS7 wasn't initialized.ossl_pkcs7.c@dataPKCS7_verify@error_stringNegative number of recipient!Negative number of signers!signedencryptedenvelopedsignedAndEnvelopedCould not parse the PKCS7PKCS7ri wasn't initialized.PKCS7si wasn't initialized.Could not add recipient.Could not add signer.must specify a booleanunknown type "%li "PKCS7Errorread_smimewrite_smimetype=detached=detacheddetached?cipher=add_signersignersadd_recipientrecipientsadd_certificatecertificates=certificatesadd_crlcrls=crlsadd_dataSignerInfoSignersigned_timeRecipientInfoenc_keyTEXTDETACHEDBINARYNOATTRNOSMIMECAPOpenSSL/PKCS7/RECIP_INFOOpenSSL/PKCS7/SIGNER_INFOOpenSSL/PKCS7OpenSSL::PKCS7#get_signer_info == NULL!signeddatasignedAndEnvelopedenvelopedencrypteddigestossl_pkcs7_to_derpkey is emptyCould not parse PKeyparameters missingpublic key missingPKEY wasn't initialized!EVP_VerifyInit_exEVP_VerifyUpdateEVP_VerifyFinalPrivate key is needed.EVP_SignInit_exEVP_SignUpdateEVP_SignFinalPKeyErrorprivate?OpenSSL/EVP_PKEYOpenSSL::PKey::PKey can't be instantiated directlyTHIS IS NOT A DH!qpub_keypriv_keyDH_set0_keyDH_set0_pqgincomplete DHDH already initializedDHparams_dupossl_pkey_dh.cFailed to generate keyNot a DH key!DHErrorgeneratepublic?exportparams_ok?generate_key!set_pqgset_keyossl_dh_to_derTHIS IS NOT A DSA!DSA_set0_keyDSA_set0_pqgDSA already initializedossl_pkey_dsa.cDSA PUBLIC KEYNeither PUB key nor PRIV keyincomplete DSAPrivate DSA key needed!Not a DSA key!DSAErrorsyssignsysverifyossl_dsa_to_derEC_POINT is not initializedEC_GROUP is not initializedEC_POINT_is_on_curveEC::Point already initializedEC_POINT_dupEC_POINT already initializedinvalid second argumentEC_POINT_newEC_POINT_bn2pointEC_POINT_oct2pointBIO_new(BIO_s_mem())EC_GROUP_set_seedEC_GROUP_newEC_GROUP_dupunknown curve name (%li )unable to create curve (%li )EC_GROUP_new_by_GF*wrong number of argumentsTHIS IS NOT A EC PKEY!EC_KEY_printoutlen=%dECDSA_verifyPrivate EC key needed!ECDSA_signECDH_compute_keyEC_KEY_set_public_keyEC_KEY_set_private_keyEC_KEY_set_groupEC already initializedEC_KEY_dupEVP_PKEY_assign_EC_KEYinvalid curve nameEC_KEY already initializedEC_get_builtin_curvesEC_POINT_point2octEC_POINT_set_to_infinityEC_POINT_invertEC_POINT_make_affineEC_POINT_is_at_infinityEC_GROUP_get_cofactorEC_GROUP_get_orderEC_GROUP_set_generatorEC::Group already initializedEC_KEY_check_keyEC_KEY_generate_keyNot a EC key!ECErrorECGroupPointGFpGF2mGFp_simpleGFp_montGFp_nistGF2m_simpleuncompressedhybridNAMED_CURVEEXPLICIT_CURVEgroup=private_key=private_key?public_key?dh_compute_keydsa_sign_asn1dsa_verify_asn1curve_nameasn1_flagasn1_flag=point_conversion_formpoint_conversion_form=seed=degreeinfinity?on_curve?make_affine!invert!set_to_infinity!to_octet_string@groupOpenSSL/EC_POINTOpenSSL/ec_groupEC_GROUP is already initializedunknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simpleunknown symbol, must be :GFp or :GF2munknown argument, must be :GFp or :GF2mcan't export - no public key setcan't export - EC_KEY_check_key failedunsupported point conversion form %+li (expected :compressed, :uncompressed, or :hybrid)unsupported point conversion form: %d, this module should be updatedbns must be 1 longer than points; see the documentationTHIS IS NOT A RSA!dmp1dmq1iqmpRSA_set0_crt_paramsRSA_set0_factorsRSA_set0_keyossl_pkey_rsa.cRSA already initializedsalt_lengthmgf1_hashautoincomplete RSAprivate key needed.maxNot a RSA key!RSAErrorpublic_encryptpublic_decryptprivate_encryptprivate_decryptsign_pssverify_pssset_factorsset_crt_paramsPKCS1_PADDINGSSLV23_PADDINGNO_PADDINGPKCS1_OAEP_PADDINGossl_rsa_to_derRAND_bytesRAND_bytes is not supportedRandomRandomErrorrandom_addload_random_filewrite_random_filerandom_bytesstatus?Selected protocol name must have length 1..255verify_hostname requires hostname to be setSSL SESSION get callback enteredSSL Session wasn't initialized.SSL SESSION remove callback enteredSSL SESSION new callback enteredcertificate does not contain public keyAdvertised protocol must have length 1..255SSL session is not started yet.%s SYSCALL returned=%d errno=%d state=%s%s returned=%d errno=%d state=%s: %s (%s)%s returned=%d errno=%d state=%sOpenSSL does not support tmp_ecdh_callback; use #ecdh_curves= insteadSSL NPN advertise callback addedSSL ALPN select callback addedSSL_CTX_set_session_id_contextSSL SESSION get callback addedSSL SESSION new callback addedSSL SESSION remove callback addedSSL TLSEXT servername callback addedservername_cb must return an OpenSSL::SSL::SSLContext object or nilSESSION_CACHE_NO_INTERNAL_LOOKUPSESSION_CACHE_NO_INTERNAL_STOREOP_DONT_INSERT_EMPTY_FRAGMENTSOP_NO_SESSION_RESUMPTION_ON_RENEGOTIATIONOP_ALLOW_UNSAFE_LEGACY_RENEGOTIATIONOP_NETSCAPE_REUSE_CIPHER_CHANGE_BUGOP_SSLREF2_REUSE_CERT_TYPE_BUGOP_NETSCAPE_DEMO_CIPHER_CHANGE_BUGSSL is not initializedSSL_set_fdarg must be Time or nilverify_certificate_identityossl_ssl.cpublic key mismatchSSL_CTX_use_certificateSSL_CTX_use_PrivateKeySSL_CTX_set0_chaincache_numconnect_goodconnect_renegotiateaccept_goodaccept_renegotiatecache_hitscb_hitscache_missescache_fulltimeoutswrite would blockread would blockSSL_set_sessionSSL_writesyswriteSSL_acceptSSL_connect:SSL_CTX_set_cipher_listSSL_CTX_newSSL2unrecognized version %+li SSL_CTX_set_min_proto_versionSSL_CTX_set_max_proto_versionSSL_readsysreadSSL_CTX_check_private_keySSL_CTX_add_client_CAcan't set verify locationsSSL NPN select callback addedSSL_CTX_set_alpn_protosSSL ALPN values addedSSL already initializednonblock=callcallback_stateossl_ssl_ex_vcb_idxSSL_get_ex_new_indexossl_ssl_ex_ptr_idxossl_sslctx_ex_ptr_idxSSL_CTX_get_ex_new_indexExtConfigSSLErrorWaitReadableSSLErrorWaitWritableSSLContextHAVE_TLSEXT_HOST_NAMEssl_timeoutssl_timeout=set_minmax_proto_versionciphers=ecdh_curves=security_levelsecurity_level=enable_fallback_scsvsetupfreezeSESSION_CACHE_OFFSESSION_CACHE_CLIENTSESSION_CACHE_SERVERSESSION_CACHE_BOTHSESSION_CACHE_NO_AUTO_CLEARSESSION_CACHE_NO_INTERNALsession_addsession_removesession_cache_modesession_cache_mode=session_cache_sizesession_cache_size=session_cache_statsflush_sessionsoptionsoptions=SSLSocketOPENSSL_NO_SOCKconnect_nonblockaccept_nonblocksysread_nonblocksyswrite_nonblockstoppeer_certpeer_cert_chainssl_versionpendingsession_reused?session=verify_resulthostname=tmp_keyalpn_protocolnpn_protocolVERIFY_NONEVERIFY_PEERVERIFY_FAIL_IF_NO_PEER_CERTVERIFY_CLIENT_ONCEOP_ALLOP_LEGACY_SERVER_CONNECTOP_TLSEXT_PADDINGOP_SAFARI_ECDHE_ECDSA_BUGOP_ALLOW_NO_DHE_KEXOP_NO_TICKETOP_NO_COMPRESSIONOP_NO_ENCRYPT_THEN_MACOP_CIPHER_SERVER_PREFERENCEOP_TLS_ROLLBACK_BUGOP_NO_RENEGOTIATIONOP_CRYPTOPRO_TLSEXT_BUGOP_NO_SSLv3OP_NO_TLSv1OP_NO_TLSv1_1OP_NO_TLSv1_2OP_NO_TLSv1_3OP_MICROSOFT_SESS_ID_BUGOP_NETSCAPE_CHALLENGE_BUGOP_MICROSOFT_BIG_SSLV3_BUFFEROP_MSIE_SSLV2_RSA_PADDINGOP_SSLEAY_080_CLIENT_DH_BUGOP_TLS_D5_BUGOP_TLS_BLOCK_PADDING_BUGOP_SINGLE_ECDH_USEOP_SINGLE_DH_USEOP_EPHEMERAL_RSAOP_NO_SSLv2OP_PKCS1_CHECK_1OP_PKCS1_CHECK_2OP_NETSCAPE_CA_DN_BUGSSL2_VERSIONSSL3_VERSIONTLS1_VERSIONTLS1_1_VERSIONTLS1_2_VERSIONTLS1_3_VERSIONexceptionwait_readablewait_writabletmp_dh_callbacknpn_protocols_encoded@cert_store@ca_file@ca_path@verify_mode@verify_depth@verify_callback@client_ca@renegotiation_cb@cert@extra_chain_cert@client_cert_cb@tmp_ecdh_callback@timeout@session_id_context@session_get_cb@session_new_cb@session_remove_cb@npn_select_cb@npn_protocols@alpn_protocols@alpn_select_cb@servername_cb@verify_hostname@io@context@hostnameSSL3TLS1TLS1_1TLS1_2TLS1_3OpenSSL/SSLOpenSSL/SSL/CTXU ;SSL Session already initializedi2d_SSL_SESSIONossl_ssl_session.cno session availableunknown typeBIO_s_mem()SSL_SESSION_print()SessionErrortime=OpenSSL/SSL/Sessionossl_ssl_session_to_derV_OKV_ERR_UNSPECIFIEDV_ERR_UNABLE_TO_GET_CRLV_ERR_CERT_SIGNATURE_FAILUREV_ERR_CRL_SIGNATURE_FAILUREV_ERR_CERT_NOT_YET_VALIDV_ERR_CERT_HAS_EXPIREDV_ERR_CRL_NOT_YET_VALIDV_ERR_CRL_HAS_EXPIREDV_ERR_OUT_OF_MEMV_ERR_CERT_CHAIN_TOO_LONGV_ERR_CERT_REVOKEDV_ERR_INVALID_CAV_ERR_PATH_LENGTH_EXCEEDEDV_ERR_INVALID_PURPOSEV_ERR_CERT_UNTRUSTEDV_ERR_CERT_REJECTEDV_ERR_SUBJECT_ISSUER_MISMATCHV_ERR_AKID_SKID_MISMATCHV_ERR_KEYUSAGE_NO_CERTSIGNV_ERR_KEYUSAGE_NO_CRL_SIGNV_ERR_INVALID_NON_CAV_ERR_INVALID_EXTENSIONV_ERR_NO_EXPLICIT_POLICYV_ERR_DIFFERENT_CRL_SCOPEV_ERR_UNNESTED_RESOURCEV_ERR_PERMITTED_VIOLATIONV_ERR_EXCLUDED_VIOLATIONV_ERR_SUBTREE_MINMAXV_ERR_UNSUPPORTED_NAME_SYNTAXV_ERR_PATH_LOOPV_ERR_SUITE_B_INVALID_VERSIONV_ERR_SUITE_B_INVALID_CURVEV_ERR_SUITE_B_LOS_NOT_ALLOWEDV_ERR_HOSTNAME_MISMATCHV_ERR_EMAIL_MISMATCHV_ERR_IP_ADDRESS_MISMATCHV_ERR_DANE_NO_MATCHV_ERR_EE_KEY_TOO_SMALLV_ERR_CA_KEY_TOO_SMALLV_ERR_CA_MD_TOO_WEAKV_ERR_INVALID_CALLV_ERR_STORE_LOOKUPV_ERR_NO_VALID_SCTSV_ERR_OCSP_VERIFY_NEEDEDV_ERR_OCSP_VERIFY_FAILEDV_ERR_OCSP_CERT_UNKNOWNV_FLAG_USE_CHECK_TIMEV_FLAG_CRL_CHECKV_FLAG_CRL_CHECK_ALLV_FLAG_IGNORE_CRITICALV_FLAG_X509_STRICTV_FLAG_ALLOW_PROXY_CERTSV_FLAG_POLICY_CHECKV_FLAG_EXPLICIT_POLICYV_FLAG_INHIBIT_ANYV_FLAG_INHIBIT_MAPV_FLAG_NOTIFY_POLICYV_FLAG_EXTENDED_CRL_SUPPORTV_FLAG_USE_DELTASV_FLAG_CHECK_SS_SIGNATUREV_FLAG_TRUSTED_FIRSTV_FLAG_SUITEB_128_LOS_ONLYV_FLAG_SUITEB_192_LOSV_FLAG_SUITEB_128_LOSV_FLAG_PARTIAL_CHAINV_FLAG_NO_ALT_CHAINSV_FLAG_NO_CHECK_TIMEPURPOSE_SSL_CLIENTPURPOSE_SSL_SERVERPURPOSE_NS_SSL_SERVERPURPOSE_SMIME_SIGNPURPOSE_SMIME_ENCRYPTPURPOSE_CRL_SIGNPURPOSE_ANYPURPOSE_OCSP_HELPERPURPOSE_TIMESTAMP_SIGNTRUST_COMPATTRUST_SSL_CLIENTTRUST_SSL_SERVERTRUST_EMAILTRUST_OBJECT_SIGNTRUST_OCSP_SIGNTRUST_OCSP_REQUESTTRUST_TSADEFAULT_CERT_AREADEFAULT_CERT_DIRDEFAULT_CERT_FILEDEFAULT_CERT_DIR_ENVDEFAULT_CERT_FILE_ENVDEFAULT_PRIVATE_DIRV_ERR_UNABLE_TO_GET_ISSUER_CERTV_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATUREV_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATUREV_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEYV_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELDV_ERR_ERROR_IN_CERT_NOT_AFTER_FIELDV_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELDV_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELDV_ERR_DEPTH_ZERO_SELF_SIGNED_CERTV_ERR_SELF_SIGNED_CERT_IN_CHAINV_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLYV_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATUREV_ERR_AKID_ISSUER_SERIAL_MISMATCHV_ERR_UNABLE_TO_GET_CRL_ISSUERV_ERR_UNHANDLED_CRITICAL_EXTENSIONV_ERR_UNHANDLED_CRITICAL_CRL_EXTENSIONV_ERR_PROXY_PATH_LENGTH_EXCEEDEDV_ERR_KEYUSAGE_NO_DIGITAL_SIGNATUREV_ERR_PROXY_CERTIFICATES_NOT_ALLOWEDV_ERR_INVALID_POLICY_EXTENSIONV_ERR_UNSUPPORTED_EXTENSION_FEATUREV_ERR_APPLICATION_VERIFICATIONV_ERR_UNSUPPORTED_CONSTRAINT_TYPEV_ERR_UNSUPPORTED_CONSTRAINT_SYNTAXV_ERR_CRL_PATH_VALIDATION_ERRORV_ERR_SUITE_B_INVALID_ALGORITHMV_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHMV_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256V_ERR_PROXY_SUBJECT_NAME_VIOLATIONATTR wasn't initialized!ossl_x509attr.csk_newargument must be ASN1::SetASN1::Set has non-array valueX509_ATTRIBUTE_dupoid=value=X509_ATTRIBUTE_set1_objectAttributeErrorAttributeOpenSSL/X509/ATTRIBUTEossl_x509attr_get_valueossl_x509attr_to_der#<%li : subject=%+li , issuer=%+li , serial=%+li , not_before=%+li , not_after=%+li >CERT wasn't initialized!ossl_x509cert.cX509_set_pubkeyX509_set_notAfterX509_set_notBeforeversion must be >= 0!CertificateErrorCertificateversion=signature_algorithmserial=subjectsubject=issuer=not_beforenot_before=not_afternot_after=extensions=add_extensionOpenSSL/X509ossl_x509_to_derCRL wasn't initialized!X509_CRL_add0_revokednum < 0???ossl_x509crl.ccount < 0???X509_CRL_set_nextUpdateX509_CRL_set_lastUpdateCRLErrorlast_updatelast_update=next_update=revoked=add_revokedOpenSSL/X509/CRLEXT wasn't initialized!ossl_x509ext.cASN1_OCTET_STRING_setX509_EXTENSION_dupcritical=critical,unknown OID `%li '@config%li = %li OBJ_txt2objX509_EXTENSION_set_object@crl@subject_request@subject_certificate@issuer_certificateCTX wasn't allocated!ExtensionErrorExtensionFactoryissuer_certificate=subject_certificate=subject_request=crl=create_extExtensioncritical?OpenSSL/X509/EXTENSIONossl_x509ext_to_derOpenSSL/X509/EXTENSION/FactoryName wasn't initialized.ossl_x509name.cname entries < 0!X509_NAME_print_ex#<%li %li >X509_NAME_dupOBJECT_TYPE_TEMPLATEX509_NAME_onelinelocX509_NAME_add_entry_by_txtDEFAULT_OBJECT_TYPE[]NameErroradd_entryto_utf8hash_oldcountryNamednQualifierDCdomainComponentemailAddressRFC2253ONELINEMULTILINEOpenSSL/X509/NAMEossl_x509name_to_derReq wasn't initialized!ossl_x509req.cX509_REQ_set_pubkeyX509_REQ_set_versionRequestErrorattributesattributes=add_attributeOpenSSL/X509/REQossl_x509req_to_derREV wasn't initialized!i2d_X509_REVOKEDossl_x509revoked.cX509_REVOKED_dupX509_REVOKED_set_serialNumberRevokedErrorRevokedOpenSSL/X509/REVX509_REVOKED_set_revocationDateossl_x509revoked_to_der@timeSTORE wasn't initialized!STORE_CTX wasn't initialized!STORE_CTX is out of scope!X509_STORE_CTX_initcerts in chain < 0???ossl_x509store.c@error@chainstctx_ex_verify_cb_idxstore_ex_verify_cb_idxX509_STORE_get_ex_new_indexStoreErrorStoreverify_callback=flags=purpose=trust=add_pathadd_fileset_default_pathsadd_certStoreContexterror=error_depthcurrent_certcurrent_crlOpenSSL/X509/STORE_CTXOpenSSL/X509/STOREStoreContext initialization failureexception in verify_callback is ignoredX509_STORE_CTX_get_ex_new_index;<F&Xa ^@ߝ@`,AspuݟtSɠX t 0`p  $@8TD0 ,PL`(D0`0г8pTp@` L x @ (!T!`!! !"0"@\"""`" # 8#d####0,$H$Ph$@$$`,%pl%0% &0&T&& &&'08'\'''' ( (L(|(((0(()04)pP)l)`)))*8*0t*@**p+4+P`++P++P, L,,,-L- - -p - .@@.t. ..@,/X///0@0P|0001H111 2pH2022#2#2$3$,3%P3&|3'3(3)30,D4/4/4040 5P1(5p1D51`52|5p252535`4$64P6`5|6066 760:H7@:\7P:p7P<7=7=7@8B48B`8Bt8B8D8pE8E9F<9FX9Gt9@G9G9`H9J :J8:PL`:`Lt:pL:M:`O;P4;Rh;S;T;pU;U<UD<0V`<pV|<V<V<W<0X=X8=[X=[l=p\=]> ^P>@^l>^>_> `>``?a4?ah?a?pc?i,@m@r@ArXArlApsAtAPvA wBwLBwhBPxBxB yBy C z(CPzDC{`C}C}C}C~C` DЁTDDDDDp ELE`E`E E0EF4f`@f@f`AfB g D8g0Ehg Fg GgGgI4hJlhpMhNhO$iOLiQiQipRi Sj@S8jSpjTjTj@UjUk VDkVpkVkWkWk`Xk0Y,lYXlPZl@[l`[l[l`\m\0mP]Tm]mcmPdmdn e,nedn@fnfngno o`qLoro0toup`wLpyp@zp@{qp{ q0}lq}q~q~qr8r`\rrrpr rЃs4sps@sЌ(t0dtt`t0uTu uu`vvPvpv0vvЦvvЧw wLww wЪww x xTxx`xxPxy`Dy@xyyy@zб,z`Pzzzz{pL{ x{и{{p$| p|P||}@$}D}d}} }@}}@} ~`8~T~p~~~~ , H@H ` ` P<t܂4p`P8 04@H@0p 8 L x` ؆ p  4P`p`P$Ppp̈ 4# $$P'(H@(d((*Ȋ *܊+(,T-0/P/ԋ// @0D0pP11@202`0333ԍ@4458`5d56`6Ȏ667`889؏90:0:\:x ;p>>Đ @A\CCؑD F<@FXpFtFHH IHItIPJȓJ@K0K\L|pLLȔ M`MN<`N\NxOQQԕRS8`T\ UX̖ [@[[T@\p\]`]]^<P^h_``Ԙ`` `a8aTpddegPh@h\hipll l(0mT`mlmnԛo`ou@vvv@z0PzD{|}~L0hPЂXP̟P@ lPĠ0@P4 `ܡ,Ht`ЏܢP$ @` p̣4@h`8`dP̥К d`@D ppԧP <h@0@hzRx $ ;FJ w?:*3$"DG;\p|"MH  A Ȉ<EvHOQH ~ A LDiFBA A(D0S (D ABBF U (A ABBE LhdiFBA A(D0S (D ABBF U (A ABBE LiFBA A(D0S (D ABBF U (A ABBE 8FLD D(D@` (A ABBD (D8mEDG0P AAA p|bHFBE B(A0D8DPl 8A0A(B BBBB RH D A )EW D D@FBB A(A0DP 0A(A BBBA zRx P(d> 0qFAG G8FGA D(D0x (D ABBA 0_H j F tnEY B $ȒE E DD q K `,(t8FCH sAB(|EAD0e AAA ,FFF  ABF jH \ A jH \ A (4hUEDF _ AAH (`UEDF _ AAH (ЗUEDF _ AAH (UEDF _ AAH (8UEDF _ AAH (lUEDF _ AAH (<UEDF _ AAH (hԘUEDF _ AAH (UEDF _ AAH (Hf K 7Hc G LEc H (0LEHD X DAA \7Hc G x7Hc G 4EDJ X CAA ~ FAA ,pAC FF J 8@FBD D(FPW (A ABBE 8DLBHA B ABH n DBD D DBA 4EKD B CAF D FAA (`^EGD t DAG (vFKA p ABK ($vFKA p ABK (P]\%\)FBB E(A0A8F?GFAc 8A0A(B BBBG $zRx ,#]`&,HFBB E(A0A8FHGBBIc 8A0A(B BBBH ,]'0H'P1 0'L1EG [ AH (T'1EHD0 AAA 0'2FDD F@  AABH 'X4Eh K R F 4'5EKD x FAE I CAA (l5AAF,,(p5oFAD C ABA (\(5yFAK s ABA (6OHe E ((86EHD x AAE (6fEw E (6.Ec A )7Ll($)x8EHD0 AAA P)l9 d)h9EK l AA ):EK t AK ):EK t AK D)L;eFBB K(D0I 0A(A BBBF ,*t=FAA n ABG (H*>EHD0 AAA t*> (*>EAJ@ AAD ,*?FAA u ABH (*H@EHD0 AAA +MH  A (>DHN@>L XT>HEAD p DAI I DAJ D DAG D DAG t DAA >̗9LT A >MEt A 8>$FBG C(D@F (A ABBF $?ؘ 8?ԘdEQ v AA 0\? FAD F@  AABC (?ܚ*EAG@s AAF L?FBA A(G@ (C ABBI Y (F ABBD  @p6HU A (@dEn A 8D@FBA A(GP (A ABBF @<>E` A ,@`EHD AA(@PEADPe AAA 8@ԡ:FEA C(D@ (D ABBA @4AآFEB D(A0DP 0D(A BBBA 0xA$>FAA D@  AABF 8A0FED A(D` (A ABBA (ATEAD0 AAE (BاEAD W AAE (@B\EAD W AAE lB!E[@BBEE A(A0Dp 0A(A BBBJ @B@BMA B ABK N ABG FAB(CEDD U AAD YFAD G0  AABH HaD?FBL B(A0F8G`3 8A0A(B BBBG 4bA(HXHLbAFIA A(D0d (D ABBF D(A ABB,bBFHA  ABF bGLHu C GbHLHu C GcDHDHl D G(ctHAAMDcxHAAM`c|HAAK|cHqH0^ A cHqH0^ A cHIsH ` A (cIEAG0a AAA c J2H] H dDJ2H] H (4dhJEDD | DAA `dJ7Hc G |dK2H] H 4d$KEAD v DAK k DAA d|KGHe K I A dK2H] H L eKFBA A(D0k (D ABBF D (G DBBA 4\e0LdEAD x DAI I DAA ehLGHe K I A eLQEs H K A 0eLFDA G0  AABE  fMCd[H$fMBBB E(A0D8Dp@ 8A0A(B BBBB pf\P TfXPBBE B(D0D8DP XI`] K 8D0A(B BBBA 8fRFEA D(FP (A ABBF zRx P$avLgS&E\8hgSFEA D(FP (A ABBF kvg$U&E\(g8UECG0r AAE 4hUFAA i ABD iAB(8h$VkEAN | AAA 8dhhVFBA D(D@ (A ABBF (h,XxEJD J DAA (hXuEAD N DAC (hXVEAQ k DAA ($iYkEAN | AAA xPiLYgBBB B(A0A8DP_ 8A0A(B BBBI  8C0A(B BBBH a 8A0A(B BBBE ,i@ZFAD U FBA HiZ:FBE E(A0A8Fp 8A0A(B BBBD zRx p(Lj\\BEB E(D0A8F 8A0A(B BBBI DDjbjb 8 kb FBA A(D@B (A ABBJ 8HkmFHD A(GPy (A ABBG @k8p'FFA D0z  IABI O  DABA 0k$q1FMA  AIA k0 (l,EAD0 AAB (E` A XvEE(tv HvFBB E(A0I8M@ 8D0A(B BBBA HvFBB E(A0I8M@ 8D0A(B BBBA L w|&FIA A(D0k (D ABBG Q (A ABBI (pw\EHD0n AAA ,wFAA v ABG 0wFDD F@  AABH xܳAAFx.Ec A (8xdEKD m DAA Ldx8FIA A(D0[ (D ABBG Q (A ABBI (xEHD x AAE (xlEHD x AAE ( yеEHD x AAE 8y4AAK4Ty8~EKD x FAE I CAA 8y{FLD A(G0v (D ABBA (yĶnFAK s ABA (ymFAK u ABA  zLGHe K I A (@z|mFAK u ABA lzGHe K I A (z_EKD h DAA z$2H] H (zHFDA z ABH {QHq G G E  {6HU A (<{ jEMD l DAI h{dE{ ({EHD0 AAA 4{EHD E DAE K ADE {PED r AD , |FAA n ABG <P|FBK D(I (A ABBH 8|<FBD D(FP (A ABBC |4|EHD y DAI W DAE }JHc G (4}EAD0U AAA `}LAAK(|}PMFDA y ABA (}tMFDA y ABA (}MFDA y ABA (~MFDA y ABA <,~xFED C(D (A ABBB (l~ EJD V DAA ~<Ec A ~KEm A (~jEMD l DAI ~ 6HU A (DFOH HID (XEHD0 AAA LFIB B(A0A8GF 8A0A(B BBBA ,BKA C ABE &E`$ BEAG \JJ,HDFAA n ABG 8xFBK D(I`k (A ABBG x<Ec A ЀAAK(_AKD e GAE .He00MEDJ X CAA ZAA0dED ` GH | FF V DH QHq G G E QHq G G E \؁DFBE B(D0A8FKKAc 8A0A(B BBBK \gq0Lp:FAF JP  AABH (|jEMD l DAI 6HU A (ȂKEHD 'FH HFBB E(A0I8M@ 8D0A(B BBBA (THEHD0n AAA (EHD0 AAA ,FAA v ABG 0܃`FDD F@  AABH AAF(,_EKD h DAA LXFIA A(D0[ (D ABBG Q (A ABBI 4EKD x FAE I CAA 8,{FLD A(G0v (D ABBA (pyFAK s ABA HOHe E (d_EKD h DAA ,OHe E (`FDA z ABH (؅EHD x AAE (HEHD x AAE 0.Ec A LdHq G G E l6HU A 4+EHD (̆@!EHD0 AAB HDFBB E(A0I8M@ 8D0A(B BBBA ,DFAA n ABG (t(rEKD m DAA L|FIA A(D0[ (D ABBG Q (A ABBI LAAK( PmFAK u ABA 8GHe K I A (XmFAK u ABA 2H] H ,<Ec A (PjEMD l DAI VHb A dEL $(EG0Q AB HOEEdHO| HOEV0ĉFDD D0e  DABA 0TFDD D0e  DABA ,CL^ A HAAKd2H] H (,bFGD t ABH LpFBB E(D0A8G 8A0A(B BBBD (VEAN h DAG ((RFAD q ABA T(GHe K I A tX2H] H |2H] H :He H \ȋAFIA A(D0l (D ABBF Q (A ABBI D (G DBBE @(4FBB D(D0F`( 0A(A BBBH 4lEKD B FAC I CAA AAF .Ec A (܌ cEAJ p DAA (dcEAJ p DAA 4MHg A PAAK(lRFAD q ABA (SEDN q DAA čHE A .Ec A (VFGA q ABF (,VFGA q ABF (XDVFGA q ABF (xVFGA q ABF @@FBB A(A0Dp 0A(A BBBD 4^FAC \ DBL bAB,6HU A ,HGFIO  FPE GNU0%g`7_V`x oІy З@j0@pnFFSxo 13 0> R@oeDx``@:BMZ*_qz#3AM[k|IIIIIIJ : p%x%o`p _J %@Y8 ooo0oj%@:P:`:p:::::::::;; ;0;@;P;`;p;;;;;;;;;<< <0<@<P<`<p<<<<<<<<<== =0=@=P=`=p=========>> >0>@>P>`>p>>>>>>>>>?? ?0?@?P?`?p?????????@@ @0@@@P@`@p@@@@@@@@@AA A0A@APA`ApAAAAAAAAABB B0B@BPB`BpBBBBBBBBBCC C0C@CPC`CpCCCCCCCCCDD D0D@DPD`DpDDDDDDDDDEE E0E@EPE`EpEEEEEEEEEFF F0F@FPF`FpFFFFFFFFFGG G0G@GPG`GpGGGGGGGGGHH H0H@HPH`HpHHHHHHHHHII I0I@IPI`IpIIIIIIIIIJJ J0J@JPJ`JpJJJJJJJJJKK K0K@KPK`KpKKKKKKKKKLL L0L@LPL`LpLLLLLLLLLMM M0M@MPM`MpMMMMMMMMMNN N0N@NPN`NpNNNNNNNNNOO O0O@OPO`OpOOOOOOOOOPP P0P@PPP`PpPPPPPPPPPQQ Q0Q@QPQ`QpQQQQQQQQQRR R0R@RPR`RpRRRRRRRRRSS S0S@SPS`SpSSSSSSSSSTT T0T@TPT`TpTTTTTTTTTUU U0U@UPU`UpUUUUUUUUUVV V0V@VPV`VpVVVVVVVVVWW W0W@WPW`WpWWWWWWWWWXX X0X@XPX`XpXXXXXXXXXYY Y0Y@YPY`YpYYYYYYYYYZZ Z0Z@ZPZ`ZpZZZZZZZZZ[[ [0[@[P[`[p[[[[[[[[[\\ \0\@\P\`\p\\\\\\\\\]] ]0]@]P]`]p]]]]]]]]]^^ ^0^@^P^`^p^^^^^^^^^__ _0_@_P_`_p_________`` `0`@`P```p`````````aa a0a@aPa`apaaaaaaaaabb b0b@bPb`bpbbbbbbbbbcc c0c@cPc`cpcccccccccdd d0d@dPd`dpdddddddddee e0e@ePe`epeeeeeeeeeff f0f@fPf`fpfffffffffgg g0g@gPg`gpggggggggghh h0h@hPh`hphhhhhhhhhii i0i@iPi`ipiiiiiiiiijj j0j@jPj`jpjjjjjjjjjkk k0k@kPk`kpkkkkkkkkkll l0l@lPl`lplllllllllmm m0m@mPm`mpmmmmmmmmmnn n0n@nPn`npnnnnnnnnnoo o0o@oPo`opooooooooopp p0p@pPp`pppppppppppqq q0q@qPq`qpqqqqqqqqqrr r0r@rPr`rprrrrrrrrrss s0s@sPs`spssssssssstt t0t@tPt`tptttttttttuu u0u@uPu`upuuuuuGA$3a1: GA$3p1094@GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1094PGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY@XGA+GLIBCXX_ASSERTIONS GA*FORTIFYPGA+GLIBCXX_ASSERTIONSopenssl.so-2.7.8-141.el8.x86_64.debugog7zXZִF!t/g${]?Eh=ڊ2N<5SSw3̠t1?IHȍ>yY#N6:e)ʯkPkX:RWk꧅>\s{h k;,1 thǜ`J\ u^d%a-/,8pŌ;1sl6yV,ɼ_m tRr _&=k4`wk2=SM>/Eьp jz'p|9&&9qp%w$hq$PmHn8H5YJ ^ (DfkV"N85Lyq|3vظN\d8 !)dj% PwW}(Y@|s) GWOU̅S fx|A7tWoP znƜ)pk.^kY㳥2К T-_Z q qͳʿ~ v9Fv̶h:ΓBot!BjD^~NЍ^2[i馢çC*$4nhy|YD*f,_'w =!/cAO8"y3]z4Yr0 (ڢ㛡;tA}jjev}0Q Uhiw 3}' zZg- '^TUt6@dաLT9Z >0 Va /QgD?jCu!"MJ\FRh9YBFmt6h)>'\iȵQ/O\0`;*7(]veAk-t:u*. ̃\6QMBO9pgf[q4=EMDg#{ldXk. ɠ)BP?D*+5m\crZ:pŸ|ANq2iuNxhu 65uyo7t05b]2qBbj>5c (wG+d!{!" 2H1\ (VlX8[gl}!E%6>bud&s4RQ3CXfGq$JP.i֤w')s&ב+Lq>śװC+ޯ:V;WZ !@4LTXGs:|4:~W8AjM_y2;HKEˉ3@uF'l/(Tz>|-/-+s( aj#㋆&YwC$M̥_/@]40ivk}@aYp+EífXKO;@7 gm<$EXQDAj>uKGVrdo> a$^X|b +˘j䗺{o&{差dѧuw4 {%Fۢ[1x1Kb4M1¥|'󍅐|h89`f"9w@y}dJ+8>b-g5t""{SZlݭ'(fB'ppC։BE{m2BӒ Rp]Txx(CSrZ Eۡ>t Hg Eɔߙo7e']g:8PDz5sW.djޝ^JvGħ @7*t>'-E;kYG>e@u M!%:@E[K'9 ?6ИqSR7g ZAuj9cOӪ>Oaʋ4ZHXVa0;Q<1ּ7p(vC/ dU>eGe8Xj:;pQf&"UmRYG_Pً1bs&"9k46ơx&EOmd_ܛ*˒-%0T*i8%OwtIp6nu#7e$fһ1L^ LTi\o3 ѱl'W & =" #}Wφ2G <4>vÆrDŧn"5vw HlRLsBjj8އfJFl2ؗ}'u=,?+:ΆTW4!&5MXKV z;m$Y itϷHsJ{%:GeO3(R$(uҟGpw& 攅áC&e>=U.&8BSjGL $ę:.Q.nhZ Fs!21؃]~&=[ f7yBB#CߤTԲP)'ꛞa!A뷒zzݣ€1mȳBLDA4_o!;ɜdKˍ1 2FbB_}h٠nTr/돣;!|`cN͏7De"L8my!j/H uKn)L26azOO$33 alFώ~Ne\[ogR6@UH즓c+)u&-h]hd6^yρ߱c]5dE~s" Vھ, =f s6\wL5L xUp)P ~O!&褫``2-={a%r]"1e1U٪:3/:UdxU|ZaQ`TKK@XG")>R_W{SѬA`ݵAh (p a.]k[ * NƫPF3$MGN??5Be .I$qDIcL#dnfd #,\[?:cgZD+xӗ\fٴ10>ͩ1ebe]T[@c֦G7V(NjwB)63 ы+@"r|JAщ\Ү&_:nDg?1<أ2ܶ &ȍ1R }^_:ɇYμ,lKӸd++>Viɸ\#@0압ЏܢyI*v´'8$όW0awW|K=s@y5$,˼0LJYhA;G ^Dk"^6ȿ.#>Mlyc.Cx9gUޮvbROIJ=%]@ѮϐM_mP%@uּM Sy6생vnD%5p gFiGd >!1-槔K |b6cډyOtϠ Z &I|B3RBޙNsոߢzSWnoކ]oϹ@FnY_[G:%/tO|z‡~UO"+ :~2_1Og`אg ,+o<5t\$mbp#Rgy 7Kz gFqld !}PbҎ niNr^zWNY((E(wn~ຟFSbC8#ჹKj8El(8 YiJHy"9Cl+,T)x 8e>VNeղXyG5wJ5Y2]U3E_[z7K'|]@܋[ ;#^a)RpZ5[{b%R%빦}h 5# F_RM¬!3 ߻KsbDOya,kEVGpY Yf(?_0z p'Yy@vm&! ǎK>FgiQxyKp- _0y`1 lxM*mz3fpׁ+-7Wzӑddk nC"kٕ?DaP3ݙN W3X~"Yc:ঘ6@Hz&Rks'+ 140-*CpMk4;鍦ZO2hG5M_@!hW3A=//\I.yp/3| /*FaK9Qt U U(K O[__eODTE=ד̧K6xZ*3+S_! dTBFBnєie.EbG~Ht[q}ֽ 11qg0E_|ak) wj:U"2 j޸Kq3f~K"!6REZ?.+;g:,@S*7|H(Z]dW@;KH yk HN"%L?+҆M?&-|:/%\X]L-D-mMUj|!o4 3w/ɑӟ=e1_K|2,pף(k5̮k>.)ČR5^?դ -<H18.(>*b$^-o6Mdbl)P(:s/띞|=Ļz ?.ӄJ fȞSY~Lș߭9xV3Ͳ8R!$2u8+fJq`lAcei/s~ӔA}Z)ApiN\u!}ʦ6 %lt KMw8BMl%3 j3B*`A@<?qotLSS3!4%ڑ/,?hhWI!"d^R0;(ojN9jzsi/FSi/ϖ!NPZ ,!iÈ_SYwp5{[FZ9 n,7⸭ݐ4 !ӗ[X7h=>.Qj} ! p >QP(cSD?8WBqnn[:r{B b^gCٚ9Yu%Ȋ*#<8J;GƢ/ yvg)?C|f"Յj/B3T&aG(|HyKW.+%8;bhg* 6 `f3 _ \O:ou9@`p;-q_Q-{D+v\X#Έfa "R2f|W<nKglFτ W.~/u5Dn:Z (ғ4?n5^M;i&!kjV&4b T{U|/B;5<^Hj@ĕv`םM2s]}\I ?B0 9]<?G&X4a7I7(h;'6jv*Iu(O_,<+gR.3: @ j()_iVX@°v=꿍t}G.<w{Nl+橶^6HvZWj^>7ڀ/GD[~"6Z} )4;,xJ,P1q3C'NRD'9p^i^':aP2uKW8.K_NW4q ͺh1 8SqQa9op!X*$kEպ@!:~<1lzu/3/}Ho5P)I f{2Ü]kt:dؖIO {eU_`Jɿ*2旆 pE^eMdxi15ے'zYnEƧM!2aFUG5l 󥬼& P3(Lt\i}d7R0-nޝ$cH{Yo%M G]z^FiVP ɤZeR7">$ɸy/Yj:jwGB)_;MG>\ S-pP_,X(Naa)' T'f7Ƹ*̾7U>|tR)邠@F]2SVLXRb,"}1:77\8}`0{@ 7SR܍:Fmc2saEpɥ,Sn )4]A`UWc[K[RljIgYgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``,( @h0pp_J8o00EoT8^B@Yh::c0:0:;nuu;w@@ }  V   <`.`.xؽؽ p%px%x% %%`%% fd <,h$$'+PKm]_HJruby/psych-3.1.0/psych.sonuȯELF>,@p}@8 @aa ll l 8  mm m 888$$aaa Stdaaa PtdXXXQtdRtdll l 00GNU4ȇq P.甸rWKs^` BHH `hkx BE"aj |SE6 ZqXH8"GU ZYAd,u\}x@~%P! 4BD"4G\2?"5"u5OKkf\,  F"f)I8f `>rs  T Rs s -s  @.N Uts !s s s __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeyaml_get_versionrb_ary_new_from_values__stack_chk_failInit_psychrb_define_modulemPsychInit_psych_parserInit_psych_emitterInit_psych_to_rubyInit_psych_yaml_treerb_define_singleton_methodrb_check_typeddatayaml_emitter_deleteruby_xfreeyaml_emitter_set_canonicalrb_data_typed_object_zallocyaml_emitter_initializeyaml_emitter_set_unicodeyaml_emitter_set_indentyaml_emitter_emitrb_eRuntimeErrorrb_raiseyaml_alias_event_initializerb_check_typerb_utf8_encodingrb_str_export_to_encrb_string_value_cstryaml_mapping_end_event_initializeyaml_sequence_end_event_initializeyaml_document_end_event_initializeyaml_stream_end_event_initializerb_fix2intyaml_emitter_set_widthrb_num2intyaml_stream_start_event_initializerb_attr_getrb_enc_str_newrb_funcallvyaml_mapping_start_event_initializeyaml_sequence_start_event_initializerb_string_value_ptryaml_scalar_event_initializeyaml_document_start_event_initializerb_ary_entryruby_xcallocrb_string_valuerb_keyword_given_prb_ivar_setyaml_emitter_set_outputrb_empty_keyword_given_prb_free_tmp_bufferrb_error_arityrb_cObjectrb_define_class_undercPsychEmitterrb_define_alloc_funcrb_internrb_define_methodcPsychParserrb_const_get_atrb_class_new_instancerb_intern2yaml_parser_deleterb_funcallv_publicrb_utf8_encindexrb_default_internal_encodingrb_iv_getyaml_parser_initializerb_respond_torb_ascii8bit_encindexrb_usascii_encindexrb_enc_find_indexyaml_parser_set_encodingyaml_parser_set_inputyaml_parser_parserb_protectrb_str_new_cstrrb_enc_associate_indexyaml_event_deleterb_jump_tagrb_str_newrb_ary_newrb_ary_new_from_argsrb_ary_pushrb_enc_get_indexyaml_parser_set_input_stringrb_to_encoding_indexrb_str_new_staticrb_const_getrb_usascii_str_new_cstrrb_exc_raisememcpyrb_define_constrb_requirerb_path_to_classrb_obj_allocrb_iv_setrb_define_module_undercPsychVisitorsToRubyrb_define_private_methodcPsychVisitorsYamlTreelibruby.so.2.7libyaml-0.so.2libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.4/opt/alt/ruby27/lib64ui 2>ii Il -l `-l l m KWm  /`m Xpm Ao  o  o ko )o io do eo lo Lo Qo Vp  p (p 0p 8p @p Hp Pp Xp  `p  hp  pp xp p p p p `p p p p p p p p p p hp bp q q q q  q !(q "0q #8q $@q cHq %Pq &Xq '`q (hq *pq +xq ,q -q .q /q 0q 1q 2q 3q 4q 5q 6q 7q 8q 9q :q ;q <r =r >r ?r @ r A(r B0r C8r D@r EHr FPr GXr H`r Ihr Jpr Kxr Mr Nr Or Pr Rr Sr Tr Ur Vr Wr Xr Yr Zr [r \r ]r ^s _HHN HtH5N %N hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]%H D%H D%H D%H D%H D%H D%H D%H D%H D%H D%H D%H D%H D%H D%H D%H D%}H D%uH D%mH D%eH D%]H D%UH D%MH D%EH D%=H D%5H D%-H D%%H D%H D%H D% H D%H D%G D%G D%G D%G D%G D%G D%G D%G D%G D%G D%G D%G D%G D%G D%G D%G D%}G D%uG D%mG D%eG D%]G D%UG D%MG D%EG D%=G D%5G D%-G D%%G D%G D%G D% G D%G D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%}F D%uF D%mF D%eF D%]F D%UF D%MF D%EF D%=F D%5F D%-F D%%F D%F D%F DH=F H F H9tHB Ht H=E H5E H)HHH?HHtHB HtfD=E u+UH=B Ht H=^? duE ]wH8dH%(HD$(1HT$ Ht$H|$HcD$Ht$HDHD$HcD$HDHD$HcD$ HDHD$ HL$(dH3 %(uH8^ff.HH='H}A 1H5'HHH?j;H"fHH5a> HcHHDff.HH51> \HcHHDff.HH5> ,x|HHHЃf.SH#H[f.SHH5= 1HH@H[DUH= SHHX HHH߾iH߾LHH[]fSHt[H@ HSH5i&H81DATUSHHĀHt$H5< dH%(HD$x1H|$IHu:1Hl$HHLxHHT$xdH3%(uCH[]A\@>H|$HHD$HtH|$Hff.fATH5C< USHHpdH%(HD$h1HRHIHLHT$hdH3%(u HpH[]A\{ff.ATH5; USHHpdH%(HD$h1HHIHL\HT$hdH3%(u HpH[]A\ ff.ATUHH5_; SHHpdH%(HD$h1r1HH@IH HLHT$hdH3%(u HpH[]A\ff.@ATH5: USHHpdH%(HD$h1HHIGHLlHT$hdH3%(u HpH[]A\ff.USHH5p: HHHt'HHH[]kUSHH5 : HGHHtHHH[]ATUHSHH59 HpdH%(HD$h1H߾IRH߃t:eHHHL=HHT$hdH3%(uHp[]A\ÐfATIUHSHH5g? dH%(HD$1HLHHHHH5"? H$qHǨt"H\$dH3%(uH[]A\@Lff.AWAVAUATIUHSLHHt$H58 H$dH%(HD$x1IH|$IHtH|$LHD$H<$HtH<$LH$H߃E1MAE1H<$t HHI1H|$t H|$1HLd$LADL8LLmHHT$xdH3%(u&HĈ[]A\A]A^A_pff.@AWAVAUATIUHSLHHt$H$dH%(HD$x1H|$IHtH|$LHD$H<$HtH<$LzH$HH56 H߃IE1MAE1H<$t HI1H|$t H|$HLd$LADLLLHHT$xdH3%(u#HĈ[]A\A]A^A_D[sff.@AWAVMAUMATUHSHHT$ H$HL$Ht$(H55 dH%(H$1H|$(IZ5H|$(HI5H|$ HD$(Ht+H|$ LHD$ H|$HtH|$LHD$H߃HD$(MAMLAEEA IDD$H|$(1H|$HtH|$HD$0HL$H1H|$ t!H|$ HL$HT$ HL$HT$HL|$0SEAVDD$L%XLZL8HH$dH3%(u.HĨ[]A\A]A^A_Ë@D$N@kff.@AWAVAUATIUSHHH|$0Ht$H53 HL$8dH%(H$1HHD$(uH HHIHD$ 1L|$PHD$E1H|$8AH >HD$H@HHٸH\$ Ht$HLHNHH|$(LHtHH$dH3%(HD$0tH[]A\A]A^A_fHD$H@H5H\$1HH߾HHH{H߃D$H{fD$LILI I$ cID$HD$L|$E1LHD$ HMkID$Hl$PMHD$HD$@H$HL9oHD$N4LI INIFHL$@H@H<$HIHD$PHH|$@L7H|$PLHD$@%H<$HD$PHHCHCL;|$I$ ?M9|$ID$ ?f.H@KfD;[fDHHD$I~~(IF HHL$@ IH5H;1HH5H;HH5H;H`H5vH;HH5hiH;H:H5TNH;1HH5K6H;HH5=H;1HH53H;H$H5$H;1H H5H;HAH5H;1HH5H;HH5H;1HFH5jH;HH5OH=H=H2 H=H2 H=hHo2 H=@HT2 [H?2 f.@SH5t, H dH%(HD$1+H5D2 HHtlH. H8 HcHHHL H $HcHL HL$HcHL HL$HT$dH3%(u+H [DH=HH1 tff.SHsH[f.H51 11ff.H51 11|ff.H5E1 11\ff.H551 11@H$H5- H$ H5, H$11HD$hf.H$Ht$$HIkHt$0HLAH$IHt$zt$$HI+Ht$0LNIă$Hc$H$0H=HL$8Ht$HL$@HTH$PLH$HfD H|$|fLHH=SѐH$HWt$$HIkHt$0H;LAH$IHt$zt$$HI+Ht$0LNIă$Hc$H$0H=HL$8Ht$HHTL$@H$PLH$HH$H$+t$$HIHt$0HLH$IH2t$$HI^Ht$0LH$IHLD$(st$$HI$LD$(Ht$0LLD$(=LD$(IŃ$Hc$H$0H=&HL$8Ht$HHL L$@$L$HHH$PLHH$`H$Xf.H$AHt,t$$HIYHD$0HtLHtIH$0LHt$H= L$8]DLHH=FfDLHH=.fD$H$0HEHt$LH=H$8fDCHD$(H$H-HcPHc01HTHt6 HD$@L$MHD$@$H$0Ht$H=H$8HD$(H$@HELH$HFfDLHH=S>H&|$|3H$hdH3%(HD$HHx[]A\A]A^A_@Hc$H$0LH=.Ht$HDH$8AH$AH8t$$HI?H|$0fDAH$AHFt$$HIH|$0fDH$AHtt$$HHD$(LD$(H$AHLD$(t$$HILD$(sL$M9Hl$Pl$$H\$XH\$0L|$`f{HI.Ht|LHNI|$IHt'GHHD$8HT$8HHHL1IH|$(HM9tHI<$HsAI|$HtHHD$8HHT$8tfDHl$PH\$XL|$` @HD$@AA;H$Htnt$$HIA@H$H$H= H$H=AH$A9D$$PA9YA9,H$HH$H$H$H$H|$H$0H$H uhHHpH|$fD{I$H$H$@HH$HHPHpHvAD9 H=HD$hH=HH]# ;H$H$H$HHD$HXHH@PHkHD$HXH" HHHq H8IHD$hH$0HcHDH$8HcH\$HDH$@HcCH{HDH$HHtH$PHD$Hx8HtH$XHA" HtUH$0HLlLt$HL LH H=UKH! H=D.H! H$t H$\SH Hx H~H[fUHcHSHTHH(H5! dH%(HD$1HL$HT$mHHD$Hu#Ht$dH34%(uLH([]H|$HL$H u!HHHtHHWDHQDH SH5HH+ H8H$ H5HHH;H5H;H5H;H5H;H5H=H;HH5{H;1HH5cH=H=xHI H=jH. H=H H=H H=H H=H H=H H=H oH=Hq \H=HV IH=H; 6H=H  #H=H [H H@UHHSHHH5HHHH[]ff.ATH=gUS H- H5_HHHUHH5RIHUH5HHHgHH5;HUH H5'HHH5[L]HH5 A\SHHH|$HT$HHH2H[ff.SH=xH5H0H5HH HHHH5HH H5xHHHR[HHPsychlibyaml_version%stag tuple must be of length 2HandlerEmitterinitializestart_streamend_streamstart_documentend_documentscalarstart_sequenceend_sequencestart_mappingend_mappingaliascanonicalcanonical=indentationindentation=line_widthline_width=iowritePsych/emitterMark@handlerexternal_encodingUTF-16LEUTF-16BESyntaxErrornewParserANYUTF8UTF16LEUTF16BEpsych/syntax_errorparsemarkreadpathemptyevent_locationPsych/parserH`x`mesgClassLoaderVisitorsVisitorToRubybuild_exceptionpath2classYAMLTreeprivate_iv_get;1x ((@XXp(X Tx8H|XLHHHh8Xxx0L`t8Xx8Hh|(zRx $FJ w?:*3$"D\ H@t A xNHA%HW%HW&HWEL+Ee$(NEMD rDA<P+AM A 0XdFAA G`  AABE 0eFHA GB  DABA 0,eFHA GB  DABA 0hqFAK GK  DABA 0(eFHA GB  DABA (\IEAN c DAD (IEAN c DAD 08FAD Na  AABB 0FDD D0m  AABE HAFBB B(D0D8J 8A0A(B BBBI LhAFBB B(D0D8J 8A0A(B BBBF \FBE E(A0D8G[ENDe 8A0A(B BBBA LFBB B(D0A8J 8A0A(B BBBJ HhFBB L(A0F8GP 8A0A(B BBBI xrEe EK0 AF EL(<PdQH C A QH C A @QH C A L FBE B(D0A8I 8A0A(B BBBE l'Ea(EGL@V AAH Lh $d4EGD ^DA(|FHA DU<4EG fA\ tEjGNU-`-l KW /XAS ! $Vl l o`  i p 0 o@oobom 0!@!P!`!p!!!!!!!!!"" "0"@"P"`"p"""""""""## #0#@#P#`#p#########$$ $0$@$P$`$p$$$$$$$$$%% %0%@%P%`%p%%%%%%%%%&& &0&@&P&`&p&&&&&&&&&'GA$3a1!1V GA$3p1094-$VGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1094.oUGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY-UGA+GLIBCXX_ASSERTIONSpsych.so-2.7.8-141.el8.x86_64.debug; 7zXZִF!t/O]?Eh=ڊ2N c`U@^Mme3r7N,H{5&< ,j46i{b¬Z=nFU'[+S>4d6mfS7]$g!e}=Lk !{#dR@1\O<3XdF4U:/vlɼb/,`=UIPN<,^sXƱrg^2zĿSe0,ZR\ kAUYh\gʓ${xEt}^™'곃^T:*?.11ϱ? K7ɮߥZŐ ck-3ϽPx'EPppuj5l[@2r.56:y#l*z1oj4b*R,<s (4tѱgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o```( 8 0 i8obbEo@@@T^B00h!!c ! !n''w,,4)}$V$V 4V4VdXX0Z0Zxaa l ll ll l m mo oXp ps ss`s w(Dw@|+PKҖ]#ruby/debug-1.6.3/gem.build_completenu[PKҖ]cr_PH@H@ruby/debug-1.6.3/debug/debug.sonuȯELF> @H9@8 @!! ,, ,  ,, , 888$$!!! Std!!! PtdQtdRtd,, , GNUDA G?_&@ @&(+BE|^'qX`r Q|6U)M9F p"") , fF"c0 +p0  0 s P __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_iseqw_to_iseqrb_iseq_code_location__stack_chk_failrb_iseq_typerb_make_backtracerb_debug_inspector_openrb_debug_inspector_backtrace_locationsrb_ary_newrb_debug_inspector_frame_iseq_getrb_iseq_realpathrb_string_valuerb_enc_checkmemcmprb_debug_inspector_frame_class_getrb_debug_inspector_frame_binding_getrb_debug_inspector_frame_self_getrb_struct_newrb_ary_pushrb_debug_rstring_null_ptrrb_iseq_parametersrb_intern2rb_id2symInit_debugrb_cObjectrb_const_getrb_gc_register_mark_objectrb_str_new_staticrb_define_constInit_iseq_collectorrb_define_methodrb_define_singleton_methodiseq_irb_objspace_each_objectsrb_ull2inumrb_iseqw_newrb_yieldlibruby.so.3.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.4/opt/alt/ruby31/lib64ui 0ii <, , , , / / / (/ / / #. . . . . . .  .  /  /  /  /  / (/ 0/ 8/ @/ H/ P/ X/ `/ h/ p/ x/ / / / */ /  / !/ "/ #/ $/ %HH)! HtH5 % hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D%  D% D% D% D% D% D% D% D% D% D% D% D% DH= H H9tH Ht H= H5 H)HHH?HHtHu HtfD=e u+UH=R Ht H= 9d= ]wHdH%(HD$1E111HHL$HcD$HT$dH3%(u HDHff.HdH%(HD$1#E111HHt$oHcD$HT$dH3%(u HDHff.HHHwH3H tHHHDf.HPHHDfH=AWAVAUATUHSHXHt$(dH%(HD$H1IyM}HD$ A IAL|$HD$HsLdHD$@HD$0HHIHHx IHHD$(HH|$0HD$@Ht$@LIH EIFHt$@H HVH97HvH:IFHt IFHTH@IEIE uIE HHL4/HHHD$HHHD$HLMjH= H1jjjjjjjATLL$`HL$X8HPH|$ HHIH;\$HT$HdH3%(HD$ HX[]A\A]A^A_@HHH9$IFHfH@IEHD$ fH=vHT$Ht$IHT$Ht$ fH=FHT$8HD$Ht$HT$8HD$Ht$}ff.AUATUSH1HHH=3 IHM1Lm9fDHHH9LHH t,HHtYH uH;]}ZHE HH uHzuHR HrH95 tH95 tH95z tLHMfHf.HL[]A\A]fHa Hu%HDHH< HtHH0 H Hu%HDHH HtHGH H Hu%HDHH HtHH ff.H ATUSHu%HCDHCH HtH- HH}HHb Hu&L%fDLH< HtHHDHH Hu&L%fD LH HtH}HH5 H Hu3H-f HsHH HtH HH= H H= H= H#H5:gH=p 1HH5-KH=(*H=C H5HH1HhH5 H1HH5H1HH5H1H`H5[]A\ f.HH(H=! dH%(HD$1HHHD$H$%HT$dH3%(u H(FfDH8H= dH%(HD$(1HjHt$HD$HD$HD$HD$H|$H?H9w$HD?HT$(dH3%(uH8f.@HsHHWH9twUHSHHfHH9tMHHtHƃHuuHtրppuHT$HqHH $HT$H $HH9uH1[]f1ff.fH  SHu(H HH HtHHE H81H H5HHH1[HMH5HHRSTRING_PTR**&RubyVMInstructionSequenceDEBUGGER__FrameInfocapture_framesframe_depth1.6.3SO_VERSIONtypeparameters_symbolsfirst_linelast_lineObjectSpaceeach_iseqcount_iseq;8hH (8hXxl8$Pdx(zRx $0FJ w?:*3$"D \XUH G A xUH G A HI>HU S HxFBB B(A0D8DpHNBBBBBBBS} 8A0A(B BBBE 8\HFBA A(D0 (D ABBC (MAA AB ZH0L A H@m K dHI((lJDG0dCACTL`GNU, F  , , o` \ . 0   oox oo o,  0@P`p 0@P`pGA$3a1 GA$3p1113GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1113GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONSdebug.so-3.1.7-8.el8.x86_64.debugMz7zXZִF!t/]?Eh=ڊ2N.]@F@Q@)!މ@%yKysXkwܮғ Hi^T3,gzg0)ȟ.=Qh FI ڞP2I?9~!Wiv\*zQ3"Ҧ5c\[L3yI@9G5V lM6R8Fi}i%pSVh2\-)sRPJQqK1]x.y|GԞJ`;yx[浩=׶KIHs:@[/^f· 7:s!zq`9EcKxX'? UNuj,@RUGQoPfWp)瀑>{ۏh-a?^Dy]b{;X=pQ l'.y}ޘ#M6/fai07Zĸ{:Y-rY^`6$>Ǫy8DŽKc؄h Lřs0nJx4X)0qas/gJLdUĠ\Z17jgK7fA.9CMnZ^9|@(o0p91|4yX@\0e 8)}7gHۉP:"xqGWCغ\hZ k>μ][ 3T &kXEPmrMte jCgFF@? :JϴP`|lVUq8u 1[X!xZCqZXvg\ kJE=`@@8 @ PP!P!8 H ئئ!ئ!888$$xxx Stdxxx PtdprprprQtdRtdPP!P! GNU{-n~- ney?l2 &H@FfR@(,(01@ !'`pB8@` d@_P &P a0X̰,H:` B5":"L($9, 24689:;<=@BCDEFHIJKLQRSTVXZ[\^abdfhikmnprtvwz|}﫟\'~ic b8N?%Ĕ 5|oc^F3|>Y$?ɴ`2Eh bayroXR1?T {zmA.jWf8^7mESֻ+Z\=Y7/6fEx)*f3 dC1OB>taa庾`dKTג縃uH5u-=W9軂xx'8&0]qX⏽)߫߻_!in>x2*|\GxKt{g^7CA)@7vj58sGZ7WpGnaK YdrS|}]LN5FmKUv[gTm(Dz BE dX/d ɪoVZ5k]:u'qze髾a[_ ݕyQcB+bcH( -PZ\4~&<KD.lŖR]oyһi=8S5t0%`42VL!X_MA TTAp K ̪*QD1FA#=|@sp# tg ) mZ  V"C_E""x0 , F"+i8! & L 4  H(!h!x pUz  L @k!   1W  p$  `( 9!$ QȺ! (   ,!v  @V,!;  p"  !!k!m  $    '!  -D)  @QzH!!, !U PaH  `) x!!   [  N`! # 7   `9  %D 0?= , #  p!  @#  ?0   0C  p!  V  J  Q0 S[!G Z  Hp!!p!z@!` #  p#D0!  `,D> y  P>U`!g!?!  < !  X!>!  @||   1  !!o p! 7!t !  >  *!! T 7x! p3 TD p!I  `;N @<c!  J  ~I    ! qQ4>! @Q2X!!K!&H! 0  +!к!ȹ!c  76  'D  \8!Y!!  98!D  @%d Ez  5s  @!D  `+HP!h!й!    /  PDD[  4!     a8! W0  I Pw Ш)!  :O   8  B0   pع! P+  6Q  `*F !f Cغ!X0!u  pm#!!(! +  P!   PW   <__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerbs__init_constantsrb_intern2rb_cObjectrb_const_getRBSRBS_ParsingErrorRBS_ASTRBS_AST_CommentRBS_AST_AnnotationRBS_AST_TypeParamRBS_AST_DeclarationsRBS_AST_Declarations_AliasRBS_AST_Declarations_ConstantRBS_AST_Declarations_GlobalRBS_AST_Declarations_InterfaceRBS_AST_Declarations_ModuleRBS_AST_Declarations_Module_SelfRBS_AST_Declarations_ClassRBS_AST_Declarations_Class_SuperRBS_AST_MembersRBS_AST_Members_AliasRBS_AST_Members_AttrAccessorRBS_AST_Members_AttrReaderRBS_AST_Members_AttrWriterRBS_AST_Members_ClassInstanceVariableRBS_AST_Members_ClassVariableRBS_AST_Members_ExtendRBS_AST_Members_IncludeRBS_AST_Members_InstanceVariableRBS_AST_Members_MethodDefinitionRBS_AST_Members_PrependRBS_AST_Members_PrivateRBS_AST_Members_PublicRBS_NamespaceRBS_TypeNameRBS_TypesRBS_Types_AliasRBS_Types_BasesRBS_Types_Bases_AnyRBS_Types_Bases_BoolRBS_Types_Bases_BottomRBS_Types_Bases_ClassRBS_Types_Bases_InstanceRBS_Types_Bases_NilRBS_Types_Bases_SelfRBS_Types_Bases_TopRBS_Types_Bases_VoidRBS_Types_BlockRBS_Types_ClassInstanceRBS_Types_ClassSingletonRBS_Types_FunctionRBS_Types_Function_ParamRBS_Types_InterfaceRBS_Types_IntersectionRBS_Types_LiteralRBS_Types_OptionalRBS_Types_ProcRBS_Types_RecordRBS_Types_TupleRBS_Types_UnionRBS_Types_VariableRBS_MethodTypeRBS_Parserrbsparser_next_tokenpeekskip__stack_chk_failtoken_type_strtoken_charstoken_bytesrb_enc_getrb_debug_rstring_null_ptrrb_enc_codelenskipnpeek_tokenNULL_RANGENullPositionNullTokenrb_gc_markrbs_loc_list_addmallocrbs_loc_list_duprbs_loc_list_freerbs_loc_freeruby_xfreerbs_loc_list_findrbs_loc_list_sizerbs_loc_positionrbs_loc_position3rbs_loc_add_required_childrbs_loc_add_optional_childrbs_loc_initrb_data_typed_object_zallocrbs_check_locationrb_check_typeddatarb_ary_newrb_id2symrb_ary_pushrb_sym2idrb_fix2intrb_ary_new_caparbs_new_locationRBS_Locationrb_funcallvrb_eRuntimeErrorrb_raiserbs_location_pprbs__init_locationrb_define_class_underrb_define_alloc_funcrb_define_methodrb_define_private_methodInit_rbs_extensionrbs__init_parserrb_hash_newparser_advancerb_intern3raise_syntax_errorrb_vsprintfrb_str_new_cstrrb_exc_raiseparser_advance_no_gapparse_type_namerbs_namespacerb_str_new_staticrbs_type_nameparser_assertparser_advance_assertrbs_class_singletonparse_typerbs_unionparse_record_attributesrb_hash_asetparser_advance_ifrbs_unquote_stringrb_to_symbolrbs_function_paramalloc_parserfree_parserrbs_aliasrbs_class_instancerbs_interfacerbs_optionalrbs_tuplerbs_literalrb_enc_str_newparser_typevar_memberrbs_variablerbs_base_typerbs_procrbs_recordrbs_functionrbs_blockrbs_intersectionparse_type_paramsparser_insert_typevarrbs_ast_type_paramparse_method_typeparser_push_typevar_tableparser_pop_typevar_tablerbs_method_typeparse_global_declrbs_ast_decl_globalparse_const_declrbs_ast_decl_constantparse_type_declrbs_ast_decl_aliasparse_annotationrbs_ast_annotationparse_annotationsparse_method_nameparse_instance_singleton_kindparse_member_defrbs_ast_members_method_definitionclass_instance_nameparse_mixin_memberrbs_ast_members_mixinparse_alias_memberrbs_ast_members_aliasparse_variable_memberrbs_ast_members_variableparse_visibility_memberrbs_ast_members_visibilityparse_attribute_memberrbs_ast_members_attributeparse_interface_membersparse_interface_declrbs_ast_decl_interfaceparse_module_self_typesrbs_ast_decl_module_selfparse_class_decl_superrbs_ast_decl_class_superparse_nested_declparse_class_declparse_module_declparse_module_membersrbs_ast_decl_modulerbs_ast_decl_classparse_declparse_signaturerb_define_singleton_methodalloc_empty_tablecallocalloc_reset_tablememcpyprint_parser__printf_chkprint_tokenfree_commentcomment_insert_new_linealloc_commentcomment_get_commentinsert_comment_linecomment_to_rubyrb_enc_str_new_staticrb_str_catrbs_ast_commentrb_ary_arefrb_class_new_instance_kwrbs_voidrbs_unescape_stringrb_reg_newrb_global_variablelibruby.so.3.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.3.4GLIBC_2.14GLIBC_2.4GLIBC_2.2.5/opt/alt/ruby31/lib64.ti P\ii gui qP!@aX!a`!`!!b!b!c! c!c!c!$c!,c!6cȤ!@cФ!Hcؤ!Pc!Uc!\c!fc!mc!rc!wc!}c!c !c(!c0!c8!c@!cH!cP!cX!c`!ch!cp!cx!c!c!c!c!c!c!d! d!d!!dȥ!)dХ!.dإ!3d! ! (!0!I8! @!H! P!X!`! h!p!lx!?!:!!!!!!!!Ȫ!ZЪ!ت!!!!!{!n!!!G !(!0!E8!@!bH!iP!X!d`!h!p!hx!v!R!c!!!!m!!K!ȫ!Ы!ث!!@!g!!!!!! !(!0! 8!@!H!eP!|X!`!!h!p!x!!!"!!#!$!%!!!&Ȭ!PЬ!ج!!j!~!_!(!u!)!C!] !U(!0!A8!@!+H!P!X!Y`!,h!p!-x!!.!5!!/!s!!0!Q!1ȭ!HHa!HtH5[!%[!hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQ%R!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%Q!D%}Q!D%uQ!D%mQ!D%eQ!D%]Q!D%UQ!D%MQ!D%EQ!D%=Q!D%5Q!D%-Q!D%%Q!D%Q!D%Q!D% Q!D%Q!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%P!D%}P!D%uP!D%mP!D%eP!D%]P!D%UP!D%MP!D%EP!D%=P!D%5P!D%-P!D%%P!D%P!D%P!D% P!D%P!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%O!D%}O!D%uO!D%mO!D%eO!D%]O!D%UO!D%MO!D%EO!D%=O!D%5O!D%-O!D%%O!D%O!D%O!D% O!D%O!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%N!D%}N!D%uN!D%mN!D%eN!D%]N!D%UN!D%MN!D%EN!D%=N!D%5N!D%-N!D%%N!D%N!D%N!D% N!D%N!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%M!D%}M!D%uM!D%mM!D%eM!D%]M!D%UM!D%MM!D%EM!D%=M!DH=O!HO!H9tHNM!Ht H=O!H5O!H)HHH?HHtHN!HtfD=O!u+UH=N!Ht H=>C!IdmO!]wAVH=^AUATUSHHL!H8qL%L!H5P!I$Hu*H' HCHHP!HtI$H(HL!HHP!Hu#HHHdP!HtI<$HH-L!H5=P!HEHu,HDHHHP!HtHEHHK!HHO!Hu#Hh HkHO!HtH}HSHL!HHO!Hu&H.fD H#HtO!HtH}H HL!HHJO!Hu&HfD HH$O!HtH}HHK!H5N!HHu,L-fDLHHN!HtHHyHK!HHN!Hu$L-q@LKHN!HtH;H4H=K!HH[N!Hu'L-5LH4N!HtH;HHJ!HH N!Hu'L- LHM!HtH;HHMK!HHM!Hu'L-LsHM!HtH;H\L-J!H5nM!IEHu-L5tfDL+HHAM!HtIEHHI!HHM!Hu#L-.LHL!HtH;HHI!H5L!HHu-L-LHHL!HtHHHH!HHxL!Hu$H@HSHTL!HtH}H;HI!H5-L!HHu,H--fDH HHL!HtHHHH!HHK!Hu$H-#@ HHK!HtH;HHG!HHK!Hu'H- H{HdK!HtH;HdHuG!HH;K!Hu'H- H3HK!HtH;HHF!HHJ!Hu'H-qHHJ!HtH;HHG!HHJ!Hu'H-? HHtJ!HtH;HHUG!HHKJ!Hu'H-H[H$J!HtH;HDHF!HHI!Hu'H-HHI!HtH;HHG!HHI!Hu'H-VHHI!HtH;HHF!HH[I!Hu'H-<HH4I!HtH;HlH]E!HH I!Hu'H-H;HH!HtH;H$H5F!HHH!Hu'H-HHH!HtH;HHuF!HHkH!Hu'H-HHDH!HtH;HHE!HHH!Hu'HD HcHG!HtI<$HKHD!HHG!Hu&HfDHHG!HtI<$HHD!HHzG!Hu&HfDHHTG!HtI<$HHC!H5-G!HHu,H-fDHHHG!HtHHqHC!HHF!Hu$H-:@HCHF!HtH;H,H-C!H5F!HEHu-L-fDLHHaF!HtHEHHB!HH7F!Hu#L-LHF!HtH}HHC!HHE!Hu&L-sfDLkHE!HtH}HSHLB!HHE!Hu&L-qfDL#HtE!HtH}H HdB!HHJE!Hu&L-fDLH$E!HtH}HHDC!HHD!Hu&L-fDLHD!HtH}H{H\C!HHD!Hu&L-fDLKHD!HtH}H3HB!HHZD!Hu&L-fDLH4D!HtH}HHB!HH D!Hu&L-fDLHC!HtH}HH B!HHC!Hu&H-fDHsHC!HtH;H\HA!HHkC!Hu'H-N H+HDC!HtH;HH]A!HHC!Hu'H-HHB!HtH;HH5@!HHB!Hu'H-HHB!HtH;HH-?!H5~B!HEHu-L-bfDLSHHQB!HtHEH8HQ@!HH'B!Hu#H-@ H HB!HtH;HHU?!HHA!Hu'H-  HHA!HtH;HH]?!HHA!Hu'H-H{HdA!HtH;HdHU@!HH;A!Hu'H-H3HA!HtH;HH?!HH@!Hu'H-RHH@!HtH;HH?!HH@!Hu'H-HHt@!HtH;HHM>!HHK@!Hu'H-H[H$@!HtH;HDHu=!HH?!Hu'H-HH?!HtH;HHm>!HH?!Hu'H-^HH?!HtH;HH->!HH[?!Hu'H HH4?!HtI<$HkHd>!H[]A\A]A^AWAVAUATL%UHSHH8dH%(HD$(1Hi~IcL>@/E9HH.=vك^zw `ufD7HH0 t uHH w voCCR9H_H/_u tH3H{u1Ҁ{(HHƒB~fDA7HH0><H߃=uH=uHAHHHL$(dH3 %(H&H8[]A\A]A^A_f.zw6`t1HNHfD=/.!6HHHCHL;DsDk $CD$CD$CD$C D$C$D$C(D$C,D$ ^?v@6"Zv$HH_u"HuHZw/v:w޺;HHfDH8HnHHg^ 9"!/$HHcNfDHHiHHlfHH='%/1'!C)HHfDHXHoH?HdH&HnuH HUlHH\u+HsHd/["HHH"w"uH&HHHHHPnHH7c tHHy|HHpcHHeJHHd1HiH=,/&!4HHH(HpeiHHNnHH5gHHlHHejHHtQHHo8HpHnHWH=%/'!/HHHHXruHH6bHHlHHikHHcRHH=U)/f)!/-HHfHHHlH/HwaHH^sHHEsHH,={(/[(!HH1@H HHHHo/HgHiHNHdH5H}="/"!5HHmDHH8uHHtHH=/!c*HH fDHxH=0 fDHHHnxH&HntH HUeHHfDHH;v<=HH@HHo/HgHot HEH={/b! HH}DHHHp[HCHL;DsDk $CD$CD$CD$C D$C$D$C(D$C,D$.HHHhHHHHH=H HH{HHHqf oHH&pHH =/"!j0HHDHHlWt&H^Ht HEHrH,Ht_HH[qzaHH9cHH cHHenHHsUHHswǃ/9v5@FHHHp=fHX>HHH;H)uHJHHyZ/-HGHHVAAHH'7'uHIHH H}H)c $vA{UH0Hx, ( wHH@*HH"=Z~nHH;<=HH>fHhHHHKH@TGH-Hu^ ?@ZHHA>/9vyHH=HH=~HH]HgH=pc\f>w[-0 v^AfD9=f^w{Z"MDwS  5D`Lz!>f^OAM&fD#f{!H0=HHqfnQ\HH 'O'HCHL;DsDk $CD$CD$CD$C D$C$D$C(D$C,D$' \ AffD\WjfAAtEHHwuPvBf~'HHG2f\afD>-V0 JD>Hg HH:^AH Hh=w3/ 9v݃=8HHlW^AvDZo/-H z`r8yHoHpHVHeH=H=/!2HHuDA`z'fD`zE !l^TZZD# #` k^\z`^7?"@!ZfHDHHXCHHH;&HH=@HH d'wHoNHb?HHH HHqfn:TR# 7B`z%' z}~HHl8HpHfHWH=/!.HHHHXiHH?aHH&sHH =/`!jHHDHH.AH\He$iH:HvH!HiaHHPtHH7eHH=/!{,HH#fDHHd?HwH=U/< !!HHzZ[H%Hm]uc|`cHH0lHHu~HHdeHHeLHH=5/R !)%HH@H@HuH'HoeHHV=!/!1HH[FfDHH>\YaMFu5v.'fHhH^AH@HZw#/v:w޺<HH_w t`tՃzv@=|{t/|RHƿH:|u@H蠿H}u`sq!HoH跿tHVH螿aH=H腿nH$HlcH HSeHH:=. / !&HH?*f.<+H蟾H>u_'A`z`z?H3H{hHHbeHHIcHH0kHϽHe~H趽HdeH蝽H= / !B3HHH]H襽l HDH茽= / !HH|tzAHܼHHL7!^/AI ^'A*^;A^A!G^\9HHgpHHNeHH5nHԻHdH軻H=/!`+HH#wV ##~/z&}~Y:H %'(^A9=9=3i9j=Rz.`%E^ZA+`VzM`z9=`PzG`zHHNeHH5rHԹHfH軹HajH袹HcQH艹Hѹe8HpH踹=}/]!'HH载`z9=HHJ^AHݸH%>w/9v^^w?@Zv`zv9*=^w(AO9=8`*z!^w(A9=`z9=s^QAc9Z=aB^AY2rwHnH趷rHUH蝷iHA9=t^w(A^`Fz=`9z0m9d=L^w>A|@97=P^w(A:`Az8`z `zD9=^w(A]9=2`8z/s^w'A]^w(AG`z0`z9=^A^A^A9=9=|^w>Ap9g=:O^w(A$C`z,`z9 =8^w?A"9=]`z`z9=^w>Av^w?Au``zI`Iz@2`9z09=^w?A9=`z`UzLf.DHs Hff.D$ +D$D$+D$ ATIUSHH?ٱI$H3 t2HkH[H4+Ht9Ic|$HHP AD$,H[]A\DHHHH=%H$I$HH$H t,H[HuH=H$Hl$農Ht$H$wHnHLNLF F(H~HNoFLHL@ FHxHHfSG,HtAH;ɰ{,H޵C C{, t C[CCC([蛯fHt'ATIUHS1LHH9u[]A\fff.@SHHXH t HXHtHcD$H[H=脱fH?T@UH0SHHfoD$ oL$0Hh(H@HH[]@Ht7USHHH/H(s HsHssH([]@1ff.fHtSfDH_(GHHu[DSHH0说H{(覴H[ݰff.fHtH;7uH97tH(Hu1oGoOJÐ1HtDH(HHufff.@UHSHH0H}(HޭHH[]H@HH8HHH ff.fHHH H H SHH(t$(t$(t$(t$(oH HC([DSHH0t$(t$(t$(t$(?H HC0[DoD$oL$H7HG0GOHG(@SH!8H Hx HH!o$oHL$,H H[H55!@USHHHHóHX(Ht&f.H;HHݲH[(HuHH[]f.USHH螮HHcHX0Ht&f.H;蘲HH}H[(HuHH[]f.UHSHHH胲H!H HHo$oJL$kH([]ff.@AUIATIUHSH(褲LHLHT$H$HHT$HD$t$Ht$Ht$t$ݫHH[]A\A]ff.fAUIATIUHSH(LHirLHT$H$QZHHT$HD$Xt$Ht$Ht$t$ݯHH[]A\A]ff.fUSH茱P x2HHHcE HHt褰HcE$HHt蓰HH[]fUSH,Px2H踬HHcEHHtDHcEHHt3HH[]fHӰHc@HHDDH賰Hc@ HHDDH蓰HHff.UHSHnHHcHHoEH}(HCoMKH}0HC(HC0H[]fAVAUIATIUHSLH[dLIIFOH+HCLkLsHS []A\A]A^ff.UHH!8SHH H8HHHx t$8Ht$8t$8t$8虫H(H[]ff.@AUIATUSH8dH%(HD$(1I'LH蜮H{(LHHڧuH{0LHǧtG<$tt$t$t$t$H; H HL$(dH3 %(u H8[]A\A]H]!HHuH茯H=!Ht11HLQHXH t HXHtH HH5H81H=1fH(r2v6iHH@H5 SH5,HHC H8ˮH\ H5HH­H;HH5>'H;H(H5. H;1HH5&H;1HH5H;1HH5ԪH;1HH5謩H;1HH5蔩H;HH5س艪H;H:H5ѳnH;HH5ʳSH;1HGH5ɳ;H;1HH5#H;[HCH5H1!1z1H韧f.DSHwHoHCHC^HC襭HC 蜭HC0HC([ff.PXH5/HH H81bfW,1?wHHrDWPt utuwT9w@uߋGx9GdGT9G@ff.AUATUSHH8辩{,|HH8虤oCoKH0IċC($L$D$ #oSo[H;C($\$D$ ߥH0HcLH}H8[H]A\A];C(ocokDc D$ H$$k@H8l$D)Dd$H0H;ot$0o|$@IŋD$P4$|$D$ XH0HcLHH辩HH賨H8H[]A\A]DUHHSHHT$PHL$XLD$`LL$ht=)D$p)$)$)$)$)$)$)$dH%(HD$81H$8Ht$ D$ HD$(HD$@D$$0HD$0תH Ho$4Ho$D$L$ɤH $HƩH螦H,$HD$H H\$Hu%HDH+H| HtHH HH8H轧ff.fG09Gu/H8HHw, HHH5 1fAWAVAUIATUSHH(t$ dH%(HD$1诣IMt oc AeCE17{,C9C0C@9CTt)f{,C09CCT9C@HH8CoCoKH0INjC($L$D$ ͡oSo[H;C($\$D$ 艢H0LHcH'HLHԦHܥHԥ{7JLLIċC786~yHD$ D$ tH=cHHXD$ H=fDAu []A\DHuH}HH^DC,fAtH0Hs, 1HH5H觟HxHu gHDC,=@HpH8Hu('DHHHHE0f.AHH}HHhDC,H؛HHEf.Hu(HDC,YH0Hs, 1HH5HnH0Hs, 1HH5[HKff.USHHBH߾.՗HȗHH߾H谗HH[]fDAUHIATMUSHHLHLH߉HH茕H߾HLH蔘HH[]A\A]fDUHSHHfHx{,t H:HHOC,t׃u HH[]H0Hs, 1HH5HDAWAVAUATIUSHdH%(HD$x1@HT$FHD$輖IAD$78z6CA|$,qHA foD$ooP)D$Ph)L$0)T$@l$@fo\$@)\$`I$t$ht$ht$ht$hKH HIIH Hu&L5IfDLÛH Htt$(HLt$(t$(t$(輘H H Hu%L5YDLsH Htl$@HLt$Ht$Ht$Ht$HؓH HL$xdH3 %(HĈ[]A\A]A^A_fDA|$,L/Aol$ LL)l$0L諔foD$Al$Aot$)D$P)t$@ofod$ )d$`nfDfDH|$LL7H|$LLH|$LLP薓!AUATUSHHoG0dH%(H$1)D$@>CFHHcH>fDHH{,t*H$dH3 %(H2HĘ[]A\A]fHȖHS$HCHHT$XHD$PRPt$Xt$X蠓HH HH@oS )T$`Y{,Ht HHHHS$HCHHT$xHD$pRPt$xt$x0HH H1HfHؐHH蘒HH8Ր:HIo[ocH0AŋC($d$D$ OH0ŋCG]oSC(H0D)o[H;$\$D$ IcHcH0HL菐HWH@HHSHs HHqH)fH- L%Hu!DL諗HH HtHLck DcH8E)ƏHIcH LaH t LaMK<,H觏H11H(H@oK oSH 1H $T$蟐H Ho[ ocH H$d$=H HHH6HfDHH8okosH0IċC(,$t$D$ 臏o{oKH;C(<$L$D$ CHcH0LHHHH賏HHSHs 7HI|LHqHifHHSHs HHb H8H2fHHSHs ̓HH H8躐HfHHSHs 蜓HHHHSHs lHH" H8ZHfHHHHSHs ,HH H8HbfHHSHs HH H8H2fHHSHs ̒HHJ H8躏HfHHSHs 蜒1H"Hf.HHSHs lHH H8ZHfHHSHs osHT$`HHt$0)t$`.HH賒HkH0Hs 1HH5H8IH- L%Hu"fDL軒HH Htoc okDHH $$l$ H *H=rHt$H$,Ht$H$ɋT@AVIAUIATUHSHHĀdH%(HD$x1ILS,iHtHE  HƋHPt$8LL$8LD$0HL$(HT$ Ht$H|$IEXZHD$xdH3%(ZH[]A\A]A^HpS,j{P sH1蜎S,X@HLd$@胎LC,A HHPt$xLL$xLD$pHT$`H|$PHL$hHt$X#YL^HH蓏 HI裊fDH{,t LHHrS,if.HhIPH訍{,t LHH*C,蝉ff.fATUSHH oG0)$I/LHH1{,u$H0HHH {,toKHE)L$ tHHH L[]A\HEH~t$Ht$t$t$‰H@H[H]A\ff.@AWIAVAUATUSHHt$(T$'dH%(H$1GA,HD$H HL$(o01ox)<$yHD$H$H Hu'HH賎H| HtHHm H$H8hHD$H$dH3%(H[]A\A]A^A_f.L蘋HD$(AoW L5& H1 Hu!@ H=H HtHKAoFAoAoW0|$'I)D$@)L$p)$)$)$)$)$)T$0AG,1ۃ3$*ÉD$ 7L`IAogAo_ H8)d$`)\$P菅AooAowH0HAG(,$t$D$ AoAo_I?AG(<$\$D$ φH0HcHHmHH2HLHD$2A,H$IW$IGIHT$HHD$@RPt$Ht$HH HH舋HHn Hu&fH=ג_HH Htt$hHHt$ht$ht$hXH H Hu!L-(LH Ht$HH$$$pH H Hu)L-ْf L賋H Ht$HH$$$HQ H Hu)L-f LSH$ Ht$HH$$$调H H $IT$ H|$LdH|$H7AG,LĄAoWHD$()$P@$ucH Hu$ H=菊H HtHˈLIAog Aoo)d$p)$f*H8 Hu H=)'H HtfD$ LHAG,L0A,/LtV!1LH$fDLAow AoAG,\$')$)$fDˆLCH$eЂAU1ATUSHHdH%(HD$x1H# H$HD$ooP)L$0)T$@誀o[0H1Ht$0)\$oc0H1HT$HI)d$PoCH)D$ )D$`Ht$(t$(t$(t$(H HH萇HHN Hu*L-f.LcH$ Htt$hHHt$ht$ht$h\H H Hu%L-]D LH Htt$HHHt$Ht$Ht$H|H H4$HHT$L$HL$xdH3 %(uHĈ[]A\A]!AUHIATMUSHHLHLH߉HH茀HH~HH[]A\A]AWAVAUATUSHHhDoG D)$薁oK oSIH)L$ H8)T$0Do[H0I$ocd$C(D$ ok,$ost$C(D$ H;芀H0LHcH(HHI耀o{ oCH)|$@)D$P~HD|$s$Ist$t$袀H HHCHH H)L=fLH Htt$8HHt$8t$8t$8 H H Hu%L=DLÅHl Htt$XHHt$Xt$Xt$X輂LHLHĈL[]A\A]A^A_*f.AWAVAUATUSHHxooG dH%(HD$h1)$HT$ H߾IӂHIoK oSH)L$@)T$P}HS$Hl$IHCHT$HD$RPt$t$H HH蹃HHW Hu#L=L蓄H4 Htt$8HHt$8t$8t$8茁H H Hu%L=DLCH Htt$XHHt$Xt$Xt$XLljL$}L$LÉz}HMH1HNH t$ HcILD)J<)D)))Hc/xHHE Hu)L%&fLH HtH11HxzHHu HU}H(HH[]A\A]A^A_{{t[||HNHAH=4HL$D$xHL$D$HHHD}fD)fDH=́xHELHH tHH@HIH=HD$Ll$fxHD$Ht$$]NHH ,Jo uHATIUHSHH{}u oC EHuLH^|{,Jt[]A\ff.@ATUHSHH9{C 6HHcH>foC HEoKH8MuoSH0I$o[\$C(D$ mvoc$$okl$C(D$ H;)wH0HcLHuH[H]A\{os H H14$o{|$vH0[H]A\|{,uC09Ctbos Huo{H8} uosH0I4$o{|$C(D$ uoC$oKL$%DoS o[@HU]yHH8tHHcMuH:)HcH_H t H_Ht/H< HH0Hs 1HH5<HL|H=~HD$H4$uHcMHD$H4$,.tH ooH1J@AWIAVAUATUSHHOPDw0Do4Dg8o<t=1tH[]A\A]A^A_OX9ODutu@u:1fxHxE7EoEgAo oSAWnxHfxH^xE7EoEgAo o[A_eff.AWAAVIAUATUDSHDoH LL$ oo oocdH%(H$1)$AD)$)l$0tHD$AF,-Ko+osHD$)l$P)t$`Aov Ao~)t$p)$@]oocE1)$)$H$LyHD$tA~,HLs1EL@SqAN,[Hੈ@fD2E[LvAoFAoN A~,)$)$)D$@uLvLovAEA0HK L%Hu LxH$ HtH'wDl$8IHD$(t$Ht$Ht$Ht$HsH HIwIH Hu$L%@L{xH Ht$HL$$$huHq H Hu!L%~L#xHL Ht$HL$$$uH H Hu)L%fLwH Ht$HL$$$ pH H Hu)L%fLcwH| Ht$HL$$$oHA H Hu)L%~f LwH Htt$hHLt$ht$ht$hloH HMt$SLL$(HL$0Ht$8H|$rZYH$dH3%(H[]A\A]A^A_fLoHHtAoVA~,)T$@LsAN,HHੈ@Hq H9L%}LvHL HtfH|$ftHD$(H2 Hu&HA}fDHuH HtH9D$(H0Iv, 1HH5~LuAon AovH )l$P)t$`Hu'L%|LCuH HtHsfo|$PLDl$XHD$)|$0brDAon AovHU )l$P)t$`HuL%K|LtH$ HtD1H|$H$L@,lA@H L%{Hf LctH Hts1AFLH0LAof,Ao~H$HL$MH߾?^HL]{,!uHL$dH3 %(LH([]A\A]A^A_H $LD$MH߾R\HDH$HL$MH߾\H{C(H0oKHoSH5hD$ 1 $T$X^WAWIAVAUATAUSHHo_ odH%(H$1H )\$DDooP)$)$AUoc okH)d$P)l$`ZHT$0H#[H$HH$jYHHD$]!HI-WoCos H)t$p)$)D$ YZl$Ht$(t$(t$(t$(IWH HI[HH0 Hu H=d\H Htt$hHHt$ht$ht$hYH H HuH=b\H Htt$HHHt$Ht$Ht$HxYH H Hu%H=Z/\Hh Ht$HH$$$YH- H Hu!@ H=c[H Ht$HH$$$4TH DHVHt$LMH<$IL;VH$dH3 %(uH[]A\A]A^A_TAWAVAUATUSHHL5! H4$dH%(HD$x1HD$0HD$AoAoVH)L$P)T$`CXo[ HT$H߾)\$Xfod$@I)d$ T{,It$(Ht$(t$(t$(TH HHYIH Hu"DH=`gZH Htt$HHLt$Ht$Ht$H`WHa H HuH=`ZH@ Htt$hHLt$ht$ht$hRH HLLZH<$HX{,uTHWHWok LH)l$PcHVoC)D$`)D$ HD$xdH3%(uHĈ[]A\A]A^A_RfAUATUHSHHdH%(HD$x1WH u<oEoHMHL$xdH3 %(WHĈ[]A\A]@oc ooXeokos0)T$Pm)\$`)t$RLL$PLD$0HHT$HHBPHT$hHD$`HHT$(HD$ RPt$(t$(RH HHIWIH/ Hu#L-^L#XH Htt$HHLt$Ht$Ht$HUHݪ H Hu%L-^DLWH Htt$hLHt$ht$ht$h@H THHeTHH[]A\A]H8SHHLLHRHf.HLLHoVHf.HLLHSHzHLLHMHZH0Hs 1HH5 aHV@AWAVAUATUSHH(dH%(HD$1fP{,!IL5ʥ IH-e;PAoLHHI)$qPH9SCP#HcTH>C9C8$C,+vk H $LD$1MHgSH@LS{,!^HL$dH3 %(LH([]A\A]A^A_H4$HT$LHLSHH$HL$1MHSHDH4$HT$LHRHd@H$HL$1MH:THBfH$HL$MHH5\THDLHmNHH0Hs, 1HH5B_HTMff.fAWAVIAUATIUHSHHdH%(H$1KADsHpNoC oSHI)D$@)T$P)D$ ,QHT$`HzQH$HHD$OHD$M{,IH oo@)$)$)$)$HqK!HHD$?MHS$HCo[ HH$)$HT$8H$HD$0RPt$8t$8ZMH HIQHH Hu!@H=&ZRH Htt$XHHt$Xt$Xt$XOH H HuH=YRH Htt$xHHt$xt$xt$xOHq H Hu%H=P?RHH Ht$HH$$$,OH H Hu!@ H=$YQH Ht$HH$$$DJH H Hu!@H=XQH Ht$HH$$$IHM H Hu!@ H= Y7QH( Ht$HH$$$IH H8NHLMAWHL$(MHt$ H|$%QZYH$dH3 %(udH[]A\A]A^A_fDHMoc LHokos0)$)$)$nLo{)$IAWAVIAUATIUHSHHdH%(H$1GDkAoKoC HAD)L$P)D$ )D$@SJHI(MHT$`H߾vMH$HHD$KH$HHD$7HHIG!HHD$jIoCoS H)$)$)D$0LHDl$(t$8t$8t$8t$8IH HH#NHH Hu!@H=NVNHء Htt$XHHt$Xt$Xt$XKH H Hu%H='UNH Htt$xHHt$xt$xt$xKHQ H Hu%H=M_NH( Ht$HH$$$LKH H Hu!@ H=DUNHȠ Ht$HH$$$dFH H Hu!@H=UMHh Ht$HH$$$ FHLIAWHL$(MHt$ H|$YFZYH$dH3 %(uH[]A\A]A^A_Fff.fUSHH(dH%(HD$1.GHHHH Ho)$^GH&JCP4H58\HcH>fDHIHL$dH3 %(H([]DHHfDH4$HT$HHH[(>AVAUATUHSH_(Hu o\$4L4Le0IMH;] tBoD$0oL$@HD$PoT$DH](C,CL,CD, [U]A\A]A^H{ $H} MtF!AHE0Mu L=H](Le0L,IfDLLH:A@IHE0Uff.@U@HSH@oD$$oL$4H0Hh8HoT$Po\$`HH@ H@(HD$p$D$ \$A>H8H[]HHt&;wu 9p|tH@8Hu1ff.SD$HHp%EHt0H0HoD$@oL$PT$`$L$T$ =H0[ÐH0HoT$@o\$PD$`$\$D$ c>H0H[fDUSHHHoW,o_H0{tuHD$8dH3%(uHH[] =9w,t1@H@Hff.fUSHH@HH[]@ff.AWAVAUATIUSHHH Ht$(Hu#HxJHCHt HtH|$(11HE1=HH(;1H=0UIH9L#HD$"@L ÉD$ @I|$(D$$HcHD$HEHD$ukDHuHHEIHLLAU < u HcD$$I)HcH\$LIH;H5RH;M9|$(vGIT$0KH|$HHEHcJZL49)+\$ oHL$HIHlH|$(LIT$?H|$HH[H]A\A]A^A_S;H=Dd;HE t6HuHEHH=oDHD$8Ht$04;HD$8Ht$0Ht$off.SHHIAHtHH[T8@[fAWAVAAUIATUHSHdH%(HD$1H< Hu L%%HL@H Ht11HL;0If;۾XIDpoPL8@(P;;HL LH Hoo@@ KC(CLCpCK,C<KPC`Kta=HY=HQ=Hu+HL$dH3 %(Hu{H[]A\A]A^A_fHE1I]7?HI9}KD-HLH$I8H>HH=HE uHE8SHH?6HHt:H[v6fDATUHSHHdH%(HD$1?H$H Hu"L%PfL>Ht HtH=H<$HH9HHڿH$Hޗ Hu"L%sOfL3>H HtHofLC6HD HtH4H<$HH01H Hu%H-5GDH5H HtH74H<$HH0H HH3HL$dH3 %(u H[]A\/ff.ATUHSHHdH%(HD$15H$HV Hu"L%;=fLC5H4 HtH3H<$HH00H Hu%H-5FDH4H HtH73H<$HH/H HH2HL$dH3 %(u H[]A\.ff.ATUHSHHdH%(HD$14H$HF Hu"L%<fLC4H$ HtH2H<$HH0/H Hu%H-5EDH3HԌ HtH72H<$HH.H HH1HL$dH3 %(u H[]A\-ff.AUATIUHSHHdH%(HD$13H$H1 Hu%L-{;DL;3H HtHw1H<$LH(.H Hu%L%NDDL2H HtH/1H<$HH-H Hu%H-DD H2Hl HtH0H<$HH-H HH|0HL$dH3 %(u H[]A\A]+ff.AUATIUHSHHdH%(HD$12H$HɊ Hu%L-+:DL1H HtH'0H<$LH,Hy Hu%L%(8DL1HT HtH/H<$HH,H) Hu%H-BDH[1H HtH/H<$HHH,HQ HH,/HL$dH3 %(u H[]A\A]l*ff.AWIAVIAUIATIULSLHdH%(HD$171H$HT Hu$H=A0H0 HtH.H<$LH|+H Hu)L=AfLC0H܈ HtH.H<$LH0+H Hu%L5ADL/H HtH7.H<$LH*Ha Hu%L-\ADL/H< HtH-H<$LH*H Hu%L%)ADLk/H HtH-H<$HHX*H Hu%H-@DH#/H HtH_-H<$HH*Hq Hu%H@D H.HL HtH-HT$PH<$H)H Hu#H@ H.H HtH,HT$XH<$H~)H| HHb,HL$dH3 %(uH[]A\A]A^A_'ff.AVAUIATIUHSHHdH%(HD$1o.H$HL Hu(L56L-H$ HtH+H<$LH(H Hu%L-w?DL{-Hԅ HtH+H<$LHh(H Hu%L%m>DL3-H HtHo+H<$HH (HY Hu%H-O>D H,H4 HtH'+H<$HH'H| HH*HL$dH3 %(u H[]A\A]A^%f.USHHdH%(HD$1,H$H Hu'H-o=H3,Ht HtHo*H<$HH 'Hy{ HH*HL$dH3 %(uH[]H%ATUHSHHdH%(HD$1),H$Hރ Hu"L%<fL+H HtH)H<$HHp&H Hu%H-1DH;+Hl HtHw)H<$HH(&H { HH )HL$dH3 %(u H[]A\N$ff.ATUHSHHdH%(HD$1)+H$H΂ Hu"L%;fL*H HtH(H<$HHp%H Hu%H-=<DH;*H\ HtHw(H<$HH(%Hx HH (HL$dH3 %(u H[]A\N#ff.ATUHSHHdH%(HD$1)*H$H Hu"L%:fL)H HtH'H<$HHp$Hq Hu%H-/DH;)HL HtHw'H<$HH($Hx HH 'HL$dH3 %(u H[]A\N"ff.AVAUIATIUHSHHdH%(HD$1)H$H Hu(L5/ Ls(H| HtH&H<$LH`#HQ Hu%L-k0DL+(H, HtHg&H<$LH#H Hu%L%9DL'H HtH&H<$HH"H Hu%H-8DH'H HtH%H<$HH"Hqw HHl%HL$dH3 %(u H[]A\A]A^ f.ATUHSHHdH%(HD$1'H$H~ Hu"L%8fL&H~ HtH%H<$HH!H~ Hu%H-7DH&H|~ HtH$H<$HH!Ht HHl$HL$dH3 %(u H[]A\ff.ATUHSHHdH%(HD$1&H$H} Hu"L%7fL%H} HtH$H<$HH H} Hu%H-6DH%Hl} HtH#H<$HH Ht HHl#HL$dH3 %(u H[]A\ff.AWAVIAUIATIULSHdH%(HD$1{%H$H| Hu$L=W+@L$H| HtH#H<$LHHq| Hu%L5+DL$HL| HtH"H<$LHxH!| Hu%L-o+D LC$H{ HtH"H<$LH0H{ Hu%L%55DL#H{ HtH7"H<$HHHs HH!Hńu%HL$dH3 %(HuTH[]A\A]A^A_H9{ Hu%H{5D Hk#H{ Ht11HH0fAVAUIATIUHSHHdH%(HD$1#H$Hz Hu(L5k)L"Hz HtH!H<$LHHYz Hu%L-*DL"H4z HtH H<$LHH z Hu%L%3DLS"Hy HtH H<$HH@Hy Hu%H-&4DH "Hy HtHG H<$HHHp HHHL$dH3 %(u H[]A\A]A^f.AVAUIATIUHSHHdH%(HD$1!H$Hx Hu(L5'LC!Hx HtHH<$LH0Hx Hu%L-;)DL Htx HtH7H<$LHHIx Hu%L%1DL H$x HtHH<$HHHw Hu%H-2DHk Hw HtHH<$HHXH1o HH<HL$dH3 %(u H[]A\A]A^zf.AWIAVIAUIATIULSLHdH%(HD$1G H$H$w Hu$H=&Hw HtHH<$LHHv Hu)L=&f LSHv HtHH<$LH@Hv Hu%L5K'DL H\v HtHGH<$LHH1v Hu%L-0D LH v HtHH<$LHHu Hu%L%/DL{Hu HtHH<$HHhHu Hu%H-N0DH3Hlu HtHoH<$HH Hl HHHL$dH3 %(uH[]A\A]A^A_@AWIAVIAUIATIULSLHdH%(HD$1H$Ht Hu$H=#oHt HtHH<$LH\Hut Hu)L=q$f L#HLt HtH_H<$LHH!t Hu%L5 /DLHs HtHH<$LHHs Hu%L-.D LHs HtHH<$LHHs Hu%L%-DLKH\s HtHH<$HH8H1s Hu%H-.DHH s HtH?H<$HHHk HHHL$dH3 %(uH[]A\A]A^A_AUATIUHSHHdH%(HD$1H$Hqr Hu%L-!DLKHLr HtHH<$LH8H!r Hu%L%!DLHq HtH?H<$HHHq Hu%H-+DHHq HtHH<$HHHii HHHL$dH3 %(u H[]A\A]ff.AWIAVIAUIATIULSLHdH%(HD$1H$Hp Hu$H=g Hp HtH+H<$LHHp Hu)L= f LHp HtHH<$LHHYp Hu%L5Q!D L[H4p HtHH<$LHHH p Hu%L-B+DLHo HtHOH<$LHHo Hu%L%*D LHo HtHH<$HHHio Hu%H-)DHHDo HtHH<$HHpHo Hu%HV*DH;Hn HtHwHT$PH<$H&HWg HH HL$dH3 %(uH[]A\A]A^A_FfDAWIAVIAUIATIULSLHdH%(HD$1H$HDn Hu$H=oH n HtHH<$LH\Hm Hu)L=fL#Hm HtH_H<$LHHm Hu%L5DLH|m HtHH<$LHHQm Hu%L-(D LH,m HtHH<$LHHm Hu%L%'DLKHl HtHH<$HH8Hl Hu%H-(DHHl HtH?H<$HHHal Hu%HcDHHw4H!@"AHsHΉH $AHc)LIEHL`H t L`MtMI<HcHNAHHHH[]A\A]A^A_DHM~L6DH=H $pH $f.H=H$PI HH $t0M~MH=dH $H\$Ht$H $M~HHRBSParsingErrorASTCommentAnnotationTypeParamDeclarationsAliasConstantGlobalInterfaceModuleSelfClassSuperMembersAttrAccessorAttrReaderAttrWriterClassInstanceVariableClassVariableExtendIncludeMethodDefinitionPrependPrivatePublicNamespaceTypeNameTypesBasesAnyBoolBottomNilTopVoidBlockClassInstanceClassSingletonFunctionIntersectionLiteralOptionalProcRecordTupleUnionMethodTypeh))))))))))))))))))))))))))))8 !M &&("!x(##!!!!!!!!!!)"8$$x)`$'%#8H"822H222(p22X$x2222)<}('''}}(9)}9)}'}}}}}}}}}})}(()}W)&&&&&&&&&&&&&&&&&&&&&&&&&&*}}'&'&&&&&&&&&&&&&&&&&&&&&&&&&&}'}'RSTRING_ENDRSTRING_PTRNullTypepEOFErrorTokenpLPARENpRPARENpCOLONpCOLON2pLBRACKETpRBRACKETpLBRACEpRBRACEpHATpARROWpFATARROWpCOMMApBARpAMPpSTARpSTAR2pDOTpDOT3pBANGpQUESTIONpLTpEQkALIASkATTRACCESSORkATTRREADERkATTRWRITERkBOOLkBOTkCLASSkDEFkENDkEXTENDkFALSEkINkINCLUDEkINSTANCEkINTERFACEkMODULEkNILkOUTkPREPENDkPRIVATEkPUBLICkSELFkSINGLETONkTOPkTRUEkTYPEkUNCHECKEDkUNTYPEDkVOIDtLIDENTtUIDENTtULIDENTtULLIDENTtGIDENTtAIDENTtA2IDENTtBANGIDENTtEQIDENTtQIDENTpAREF_OPRtOPERATORtCOMMENTtLINECOMMENTtDQSTRINGtSQSTRINGtINTEGERtSYMBOLtDQSYMBOLtSQSYMBOLtANNOTATIONto_sUnknown child name given: %sinitializeinitialize_copybufferstart_posend_pos_start_loc_end_loc_add_required_child_add_optional_child_add_optional_no_child_optional_keys_required_keys[]RBS::LocationUnexpected errornewunexpected tokenalias nameinterface nameclass/module/constant name, joinexpected one of %li literalunexpected record key tokenargsto_ito_syminvariantcontravariantcovariantvarianceuncheckedupper_boundresolve_variablestype_paramscolonkeywordeqcontentstrip!privatepublicself?singletonsingleton_instanceoverloadvisibilitynew_nameold_namenew_kindold_kindivarivar_namemoduleself_typesltcannot start a declarationParser_parse_type_parse_method_type_parse_signatureoptional keyword argument type is expectedrequired keyword argument type is expectedunexpected token for method type parameterscomma delimited type list is expectedunexpected token for simple typeunexpected token for method name`self?` method cannot have visibilityunexpected overloading method definitionunexpected token for method typeunexpected mixin in interface declarationannotation cannot be given to variable membersannotation cannot be given to visibility membersunexpected token for interface declaration memberunexpected token for class/module declaration membermethod or attribute definition is expected after visibility modifierUPUPUPUUPUPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUPUPUPUUp[aahZZa`a@`aaaaaaaaaaaaaaaaa`__aaa_aaP_aa _aaaa^^^^aaP^ ^hZh]hZaaaaaaa ]aaa\\`\[[[TuvvvTuTuTuTuvvvvTuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvTuTuuTuTuГPPPܚeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ,eeeeeeeeeLeeeeܚee؛؛؛XXXvX8XX8XXXXX8PPXXXXXXXXXXXX8XxأCannot pop empty tableCannot insert to reset tableexpected a token `%s`%s char=%d...%d current_token = %s (%d...%d) next_token = %s (%d...%d) next_token2 = %s (%d...%d) next_token3 = %s (%d...%d) locationpathabsolutenamespacerequiredself_typerequired_positionalsoptional_positionalsrest_positionalstrailing_positionalsrequired_keywordsoptional_keywordsrest_keywordsreturn_typeblockfieldsstringunchecked!commentannotationsmemberssuper_class\\[abefnrstv"\\]\\['\\]gsub!\a\b\e \f\n \r\s \t\v\"\'\\;00p3333404D@5h5556`6,6H6d7x07p77778,@8@8`8t9`99P:4 :x @; ; ; ; < `<8 p> @8 0@P @l @ A 0B C C0 PG pH @IH J L,LXOO@PP(`S0[X`]0^  deH0fh iPlLooq$rpy`pzP}dP,Іpp0 0( h00`x` 0<PTp Ф0$ 0@ ph  P!0!Щd!|!0!0!p" `"P"""#PX#P##$8$l$$$@%L%`%%&<&p&&P&P'PP'@''$(p((0(D)) )(*t***0+++zRx $ FJ w?:*3$"D` <\HFNB A(A0((A BBBLQ4FBB B(H0D8Gp 8A0A(B BBBK -- - 0(-FDA D0  AABF \h.7 p.WEo D P H ,.1KDD WABC.>Eb I / $.<EIG dAA4 /CJAG O(F0F8C@IAAEX,/)JXFt@/#EYT/?/!$/8EDD YDA//$/+EKD D(D0IE$0/+EKD D(D0IEX/,l/MEU0nD(0$$0VEAG CDA$\0VEAG CDA(0QEDD [@aFA@0FED D(DPEXG`GhDpI(F ABB@`1FED D(DPEXG`GhDpI(F ABB$`1WEAI BDA$1WEAI BDA1HM 1HM$1HL$<1^EDD IFA8d 2bFBE D(D0E(A BBB0T2QEPD Z(G0D8D@IDAH2FEA A(D`[hDpDxDL`T (A ABBA T3H0C8B@CHBPIDP3Led4!HT|4BA@ 5AAK5RT\5+BBA A(G`h@`R (A DBBH xl`e(D ABB$ 46SEGGnHl77U@`\7|FBB E(A0A8G`@` b s@`y 8A0A(B BBBJ d:BGA A(GnADDICJDDI_ (A ABBA H(l;FAA G@v  DABD NHKPDXD`I DDBLt;VFBB B(A0A8G@ 8D0A(B BBBK ^p=BBB B(A0A8GQ{SDGDIE JDDQ qDDDINi8D0A(B BBB(X l>9BAD aJB< >BAD  ABF B Pf  P_ DP$ @JAAG {DA4 AjFHD A(G0F(D ABB,$ @AkADG v DAA DPT ABBB B(D0A8GDDDIDJDDPxDDDI{ 8A0A(B BBBG CBBA A(J (A ABBC bADDL[ADDLb\ZgWYYzCU g XRd J#BEE A(D0GkDhAX 0A(A BBBH ~DdDH LBAA G@r  DABD NHKPDXD`I DDB8 MFEB B(A0A8G 8A0A(B BBBK DVADDIDJDDPmMGGPuMGGPuMGGIx LRFDA A(JDDDIHJDDPnJDDIk (A ABBA 4t S]FHD A(G0y(D ABB SFBB B(A0A8G@EQFDDIKJDDPnJDDU8D0A(B BBB8TFBB B(A0A8GADDIAJDDPnJDDIe 8A0A(B BBBA VFEB J(D0A8JADDI@JDDPfJDDPqMGGPmMGGIG 8A0A(B BBBA HxWFBB B(A0D8D` 8G0A(B BBBH ,pZaZDD wABDXZFAD G0T`E0R  ADBL IP\ ADBL0t `| ] `_ HPt\jEB B(A0A8G@b 8A0A(B BBBH (]FEE B(A0F8GDDDIEMGGPmMGGPuMGGPuMGGPrJDDIJAZA^ 8A0A(B BBBJ  ` = j H j \HcFEE E(D0D8G@y 8A0A(B BBBI v8A0A(B BBBcFEB B(A0C8JADDIJDDPfJDDPqMGGI 8A0A(B BBBG T _ eFBB G(A0D8JADDIBJDDPnJDDPqMGGPmMGGPmMGGIw 8A0A(B BBBG XiFBB B(A0A8JF^DDDI~JDDPfJDDPnJDDU8G0A(B BBBH`FFm$ mE~0WG O e@<m%FBB E(A0A8GADDIAJDDPqMGGPmMGGPmMGGPmMGGPmMGGPmMGGIEBAb^ 8A0A(B BBBF NPHsmFBB B(A0A8G` 8A0A(B BBBI P h tFEB B(D0A8JDDDI~JDDPfJDDPqMGGPmMGGI 8A0A(B BBBA LwFBB B(A0A8JKDDI@JDDPfJDDI 8A0A(B BBBA x|xFBA I(JQ (A ABBE rADDIAJDDPnJDDI<TyFJD D(G0@ (D ABBH `PzFBB B(A0A8G` 8A0A(B BBBI  _ l|FBE B(I0D8JADDIJDDPfJDDPqMGGPmMGGPmMGGPmMGGILHXAZ 8A0A(B BBBG #FBE B(I0D8JDDDIJDDPnJDDPqMGGPmMGGPmMGGIHXAZ 8A0A(B BBBA 0QEAG@ AAF  p_ $ CEAG pDA(4PFGA ~AB,XL]Lȃ9EshHUIE` K 4(~EAD A AAC O AAE 8pFBA A(D0w (A ABBE V($0FAA PIPą;KN@$l<EAD UPH(E^<FBB A(D0V (E BBBH (ĆyEND UPGDA4(0DE_@iA B D@mH0\EAG`Y`Z AAA d#TN$|$ECG IFALFBB B(D0A8Dv 8A0D(B BBBH  47Eb I FH@TFBE E(A0D8FP 8A0A(B BBBJ *E`0ȋFAD G0  AABA 0DFAD G0  AABA 0FAD G0  AABA 8H܍DFBD D(G@! (A ABBA 0FAD G0  AABA 8DFBD D(G@! (A ABBA 8АDFBD D(G@! (A ABBA 00FAD G0  AABA 0dFAD G0  AABA 0|FAD G0  AABA 0HFAD G0  AABA 8 DFBD D(G@! (A ABBA 8< (DFBD D(G@! (A ABBA Hx <FEE E(D0D8GP 8A0A(B BBBA @ FBE D(D0G@l 0A(A BBBA (!EAG0 AAA 04!FAD G0  AABA 0h!lFAD G0  AABA 0!8FAD G0  AABA @!FBE D(D0G@l 0A(A BBBA 0"`FAD G0  AABA 0H",FAD G0  AABA H|"FBE E(D0D8FPr 8A0A(B BBBD @"FBE D(D0G@l 0A(A BBBA @ #FBE D(D0G@l 0A(A BBBA HP#T0FEE E(D0D8GP 8A0A(B BBBA H#80FEE E(D0D8GP 8A0A(B BBBA 8#DFBD D(G@! (A ABBA H$$0zFEE E(D0D8GPF 8A0A(B BBBA Hp$dFEE E(D0D8GP 8A0A(B BBBA H$FBE E(D0D8GP` 8A0A(B BBBA H%<FEE E(D0D8GP 8A0A(B BBBA HT%FEE E(D0D8GP 8A0A(B BBBA 0%TFAD G0  AABA H%д0FEE E(D0D8GP 8A0A(B BBBA 8 &DFBD D(G@! (A ABBA L\&ȷzFEE E(D0D8GPF 8A0A(B BBBA 0&FAC G@  AABG H&FBB E(D0A8DP 8D0A(B BBBF GNU@aa`!bbc ccc$c,c6c@cHcPcUc\cfcmcrcwc}cccccccccccccccccccd dd!d)d.d3d0( oo80ood.oQئ!PM`MpMMMMMMMMMNN N0N@NPN`NpNNNNNNNNNOO O0O@OPO`OpOOOOOOOOOPP P0P@PPP`PpPPPPPPPPPQQ Q0Q@QPQ`QpQQQQQQQQQRR R0R@RPR`RpRRRRRRRRRSS S0S@SPS`SpSSSSSSSSSTT T0T@TPT`TpTTTTTTTTTUU U0U@UPU`UpUUUUUUUUUVV V0V@VPV`VpVVVVVVVVf0GA$3a1 M] GA$3p1113Pa]GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1113qWGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY \GA+GLIBCXX_ASSERTIONS GA*FORTIFY0]GA+GLIBCXX_ASSERTIONSrbs_extension.so-3.1.7-8.el8.x86_64.debug g7zXZִF!t/&]?Eh=ڊ2Nw љN>JrFzxʁqi8c=RFKTnL☔_X(C)*gӒ2ޏ#7a%* b򦊏k1Ϸ$pY ; Uؓcup1D9M!mk{tmJ![`!44zQvmʆB! Z8.U˨E(ZDg79k$sjcH.בe+CnP[ =#V-eb{dso65I|<,W()C;[X?v,i+!w+ iՕN{ +8zNM6hݑE,z''٢3}^R @jW i bH Wuw=Boj4pQckèj?)BkHKD"XH nfy5$x}O"0{+9^ćFw,d_aqj[NgKXȡ˩O*FzƮHa*q63HGXUNYv-~+עkӛՍH#anSD;&k~=jQJߟ#8g4r^Iޯiihm9MUeE%M+mWhePAdnjrɞ`FH'q7Qg6BwP[ q\LW弔x]hDI|Ϭ%V)is,PL ULJk{hRuO\@Dۃ*]t^alBf-BV$S҇P$5R>!vS@ {6,]TcN]nk2p ^~Ō5=S+@/A9so[j:^XV( N vBx=ħvɼ/,,WԗM+=S[=䙿 &A9ep8Y L[FĢMXYWzOɤl_̾楏wѪ5"wt{PgsP>H!dB! pS9_.c}/y'*7Xh5X`Ŧw=w^Kؓ iȓ&-o֒tL"u񩈄 (hQUwcM: ]R/ 8 |m!v8BEb1,pQb4gJcfNF]2Wr*_[AaUt=s%sleWSBmv#~i!͟#LF@e/F! -#PZQk`؁/ؐ\-fqyN XX.lsW^{~B_$؀#IP!!C)-YOV䄀(**Zиj0g벌Mi:#3j EP{2J`2+)H3> n/P FKyQZds ƦݮlW{ e:Y')XN "g:vc!ÃqA%5x-͗9G gwZ>jMWMk30uy %"ty89oӭ ;m+ A~Fc[*S-0|{;vwP _Gi.!at:1-w*>8h6L/m@;z 1`BXMxgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``|( 08od.d.Eo8080PT00(^B>>ph M Mc@M@M nVV w``}]] ]]prprHwHw,'xx P!PX!X`!`x ئ!ئ!! ! al 0$(PKҖ]\0p0p$ruby/io-console-0.5.11/io/console.sonuȯELF>"@0i@8 @xVxV ZZ Z H ([([ ([ 888$$XVXVXV StdXVXVXV PtdJJJQtdRtdZZ Z HPGNU~B0z M~Y+TH!@TVXBE|qX/Do>' `uP.9pS6:ofU$ UH""hhy U, Bq9, {F"r[#` X` `  Bp @G__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_check_typeddatacfmakerawrb_data_typed_object_zallocrb_funcallvrb_default_rsrb_io_write__errno_locationtcsetattrrb_num2uintrb_sprintfrb_io_taint_checkrb_io_check_closedrb_sys_fail_str__stack_chk_failtcgetattrtcflushrb_string_value_cstrrb_io_get_write_iorb_ensurerb_stdinrb_stderrrb_error_arityrb_str_new_staticrb_str_catfrb_io_flushrb_convert_typerb_eArgErrorrb_raiserb_cIOrb_cFilerb_const_definedrb_cloexec_openrb_update_max_fdrb_class_new_instancerb_obj_freezerb_const_setrb_unexpected_typerb_const_getrb_const_removerb_id2symrb_io_closerb_check_idrb_keyword_given_prb_funcallv_kwstrlenrb_io_getbyterb_ary_newrb_ary_pushrb_str_newrb_str_new_cstrioctlrb_assoc_newrb_fix2intrb_num2intrb_Arrayrb_ary_detransientrb_protectrb_syserr_failrb_jump_tagrb_io_getsrb_yieldrb_hash_duprb_hash_arefrb_funcallv_publicrb_ary_resizerb_ary_ptr_use_startrb_ary_ptr_use_endrb_debug_rstring_null_ptrrb_obj_classInitVM_consolerb_f_notimplementrb_define_module_underrb_cObjectrb_define_class_underrb_define_alloc_funcrb_undef_methodInit_consolerb_internrb_define_methodrb_define_singleton_methodlibruby.so.3.1libm.so.6libc.so.6_edata__bss_startGLIBC_2.4GLIBC_2.2.5/opt/alt/ruby31/lib64ii ui Z P#Z #Z Z Z 2J_ _  _  _ _ "_ *_ +_ 5_ >_ L_ M_ N_ O_ SP] X] `] h] p] x] ] ]  ]  ]  ] ] ] ] ] ] ] ] ] ] ] ] ^ ^ ^ ^  ^ (^  0^ !8^ #@^ $H^ %P^ &X^ '`^ (h^ )p^ ,x^ -^ .^ /^ 0^ 1^ 2^ 3^ 4^ 6^ 7^ 8^ 9^ :^ ;^ <^ =^ ?_ @_ A_ B_ C _ D(_ W0_ E8_ F@_ GH_ HP_ IX_ J`_ Kh_ Op_ Px_ Q_ RHH9F HtH5C %C hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhF%5? D%-? D%%? D%? D%? D% ? D%? D%> D%> D%> D%> D%> D%> D%> D%> D%> D%> D%> D%> D%> D%> D%> D%> D%}> D%u> D%m> D%e> D%]> D%U> D%M> D%E> D%=> D%5> D%-> D%%> D%> D%> D% > D%> D%= D%= D%= D%= D%= D%= D%= D%= D%= D%= D%= D%= D%= D%= D%= D%= D%}= D%u= D%m= D%e= D%]= D%U= D%M= D%E= D%== D%5= D%-= D%%= D%= D%= D% = D%= DH=&% f.H=Y= HR= H9tH< Ht H=)= H5"= H)HHH?HHtH< HtfD=< u+UH=< Ht H=7 d< ]wH"O {H g HHwH ff.@UHH5!7 SHH4HtH xHH[]D` HH[]f.ATIH56 UHSLH56 HooHKoP S HP0HS0@8C8H[]A\DUHSHHC ωC Ht.UxSUxSUtC HH H[]H6 <{ff.SH5 H<[foHP foKJfoS R HK0HJ0K8J8[ff.HH5; H׉fDH5: 11ff.H-: H0ff.fUSHH 8u&1HډuH[]f.H1[]SHH0H="p1HH4H[ff.@ATIUHHSLHSH=!p1HHH[]A\UHH5a4 SHHHXdH%(HD$H1aHo)$oH)L$oP )T$ HP0HT$0@8D$8HXH{HtHL$HdH3 %(HuHX[]H{ Of.USHXdH%(HD$H1H.HXH2{H'u&H=8 HtHT$HdH3%(uHX[]H{ ff.@SHPdH%(HD$H1HXH{Hu)D$ HHHЃHT$HdH3%(uHP[H{ U AVIAUATUHSHPdH%(HD$H1I2HXH6DcLD'uLD$ Iu6D$ LDt)HT$HdH3%(HuHP[]A\A]A^ÃxD$ H{ yfAUATUHSHXdH%(HD$H1IHXHDcLD|uCLDH"L$ {H $gtHT$HdH3%(HuHX[]A\A]H{ UHSHHXH{1u HH[]H{ SHdH%(HD$1HHtHHH$cH4$HgHD$dH3%(uH[DH0 у1AVAUATUSHHdH%(HD$1HHDn@HtyHH umHuL`LyMt$XHMHA|$HHHu`AD$u$HHHlHu9fDHL$dH3 %(H[]A\A]A^f.E1HH7uHH=u*1IDHHt+HJ;tEPЃ w-THߍlP]HuHL\Et#A9uE1롐HcLHt-1~@HcLD$Ht-dH|${LHLff.ATUHSHXHH{XHu{u"H[]A\fL`LA|$H{ off.@ATUHS`HXHdH{XHu+{H5Hx*H[]A\f.L`LA|$H{ ff.@USHdH%(HD$1HXHH{XHuL{1HT uQD$Ht$H|HL$dH3 %(u$H[]kHhHo}H{ D7I{zO}R5נN7t"wxGWjZcYڙ>e,֛^jvrSb W?¼eܞ{o05bPҎyN=A->nuf (rC-QͭTErNHCV߀ol4w=@!N)5*@=* ś PI4g3/oCoCT(9zNInAUq^30+/ifr-0g;L7 O.rp* -GSgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``8( X0 ;8o,,Eo0T^Bhhhcnpw""|%}GG HHJJLL XVXV Z ZZ ZZ Zh ([ ([8] 8]` _XX``_H@b(hbh"PKҖ])ruby/io-console-0.5.11/gem.build_completenu[PKҖ]#ruby/psych-4.0.4/gem.build_completenu[PKҖ]Wruby/psych-4.0.4/psych.sonuȯELF>,@z@8 @bb ii i XX hjhj hj  888$$bbb Stdbbb PtdpYpYpYQtdRtdii i XpGNU϶=)*c` BHH `hkx BE"aj |SE6 ZqXH8_Ur #p]Xc?t }S-,,G" O.I"/tJY""a;i^n, C7F"y{H =f >rp  U Sp p ,p  `.X VZp  p p *p __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeyaml_get_versionrb_ary_new_from_values__stack_chk_failInit_psychrb_ext_ractor_saferb_define_modulemPsychInit_psych_parserInit_psych_emitterInit_psych_to_rubyInit_psych_yaml_treerb_define_singleton_methodrb_check_typeddatayaml_emitter_deleteruby_xfreeyaml_emitter_set_canonicalrb_data_typed_object_zallocyaml_emitter_initializeyaml_emitter_set_unicodeyaml_emitter_set_indentyaml_emitter_emitrb_eRuntimeErrorrb_raiseyaml_mapping_end_event_initializeyaml_sequence_end_event_initializeyaml_document_end_event_initializeyaml_stream_end_event_initializerb_fix2intrb_num2intyaml_emitter_set_widthyaml_stream_start_event_initializerb_unexpected_typerb_attr_getrb_utf8_encodingrb_enc_str_newrb_funcallvyaml_alias_event_initializerb_str_export_to_encrb_string_value_cstryaml_mapping_start_event_initializeyaml_sequence_start_event_initializerb_string_value_ptryaml_scalar_event_initializeyaml_document_start_event_initializerb_ary_entryruby_xcallocrb_string_valuerb_ivar_setyaml_emitter_set_outputrb_error_arityrb_cObjectrb_define_class_undercPsychEmitterrb_define_alloc_funcrb_internrb_define_methodyaml_parser_deleterb_funcallv_publicrb_ull2inummemcpyyaml_parser_initializerb_intern2cPsychParserrb_const_get_atrb_class_new_instancerb_utf8_encindexrb_default_internal_encodingrb_iv_getrb_respond_torb_enc_find_indexrb_enc_get_indexyaml_parser_set_encodingyaml_parser_set_input_stringyaml_parser_parserb_protectrb_ascii8bit_encindexrb_usascii_encindexyaml_parser_set_inputrb_str_new_cstrrb_enc_associate_indexyaml_event_deleterb_jump_tagrb_str_newrb_ary_newrb_ary_new_from_argsrb_ary_pushrb_to_encoding_indexrb_str_new_staticrb_debug_rstring_null_ptrrb_const_getrb_usascii_str_new_cstrrb_exc_raiserb_define_constrb_requirerb_path_to_classrb_obj_allocrb_iv_setrb_define_module_undercPsychVisitorsToRubyrb_define_private_methodcPsychVisitorsYamlTreelibruby.so.3.1libyaml-0.so.2libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.4/opt/alt/ruby31/lib64ui 1=ii Hi -i -i i i #Xi P/ j X0j `Ao  o o ko *o io do eo lo Lo Qo Vl l l l l l l l l  l  l  l  m m m m  m (m `0m 8m @m Hm Pm Xm `m hm pm xm hm m bm m m  m !m "m #m $m %m cm &m 'm (m )m +n ,n -n .n / n 0(n 10n 28n 3@n 4Hn 5Pn 6Xn 7`n 8hn 9pn :xn ;n <n =n >n ?n @n An Bn Cn Dn En Fn Gn Hn In Jn Ko Mo No Oo P o R(o S0o T8o U@o VHo WPo XXo Y`o Zho [po \xo ]o ^o _HHN HtH5jK %kK hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]%E D%}E D%uE D%mE D%eE D%]E D%UE D%ME D%EE D%=E D%5E D%-E D%%E D%E D%E D% E D%E D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%}D D%uD D%mD D%eD D%]D D%UD D%MD D%ED D%=D D%5D D%-D D%%D D%D D%D D% D D%D D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%C D%}C D%uC D%mC D%eC D%]C D%UC D%MC D%EC D%=C D%5C D%-C D%%C D%C D%C D% C D%C D%B D%B D%B D%B D%B D%B D%B D%B D%B D%B D%B D%B D%B DH?f.DH=B HB H9tHfB Ht H=B H5B H)HHH?HHtHmB HtfD=uB u+UH=JB Ht H=; dMB ]wH8dH%(HD$(1HT$ Ht$H|$HcD$Ht$HDHD$HcD$HDHD$HcD$ HDHD$ HL$(dH3 %(uH8Nff.HH=(bH;A 1H5(HHH5@v1HHH5: |HcHHDff.HH5: LHcHHDff.HH5: x|HHHЃf.SHH[f.SHH5A: 1HH@H[DUH: SHHX HHfH߾9H߾HH[]fSHt[H? HSH5'H81uDATH59 USHHpdH%(HD$h1HHI7HLHT$hdH3%(u HpH[]A\ff.ATH5#9 USHHpdH%(HD$h1HHIWHLHT$hdH3%(u HpH[]A\ff.ATUHH58 SHHpdH%(HD$h1"1HH@IHHLHT$hdH3%(u HpH[]A\/ff.@ATH538 USHHpdH%(HD$h1HHIHL,HT$hdH3%(u HpH[]A\ff.USHH57 HGHHtHHH[] fUSHH5p7 HHHtgHHH[]fATUHSHH57 HpdH%(HD$h1)HIHH߉AHLHHT$hdH3%(u Hp[]A\DATIUHSHH5< dH%(HD$1HZLHHHHH5< H$!HǨt"UH\$dH3%(uH[]A\@ff.ATUSHHĀHt$H55 dH%(HD$x1pH|$IHu:1Hl$HHLHHT$xdH3%(ulH[]A\@@u HuHHuGH|$H:HD$HyH|$Hi@AWAVAUIATUHSLHHt$H55 H$dH%(HD$x1}IH|$IHH<$HH߃4E1MAE1H<$t HFI1H|$t H|$/HLl$LADL&LLHHT$xdH3%(HĈ[]A\A]A^A_f@uIHt@HHu4LH߃H$D?@u HuWHHuLHD$ff.fAWAVAUATIUHSLHHt$H$dH%(HD$x1DH|$IHH<$HHH5:3 H߃IE1MAE1H<$t HI1H|$t H|$HLd$LADL3LLHHT$xdH3%(HĈ[]A\A]A^A_@uIHt@HHu4LUH$(@s=fD@u HuHHuLHD$DAWAVMAUMATUHSHHt$(H51 H$HT$ HL$dH%(H$1LH|$(@t'HtIHHucH|$(HISH|$ HD$(Ht(@uHtHHuL HD$ H|$Ht4@uHhHHXLHD$H߃MA1MED$HD$(LA LxH|$(1H|$HtH|$HD$CHL$H1H|$ t!H|$ HL$HT$HL$HT$HLl$0SEAVDL$L8XLZLkHH$dH3%(u/HĨ[]A\A]A^A_IMAG{ AWAVAUATUHH5/ SHHH|$HL$dH%(H$1H5=H;1HH52H;H[H5"H="H=H/ pH=H/ ]H=H. JH=H. 7[H. f.@SHH[f.H5 / 11ff.H5. 11ff.H5. 11ff.H5}. 11ff.HH5q. dH%(HD$1HGH?HH$YHT$dH3%(uHOff.@HH5. dH%(HD$1HGH?HH$HT$dH3%(uHff.@HH5- dH%(HD$1HGH?HH$HT$dH3%(uHff.@HOH51- H?@HOH5!- H?@HOH5 - H?@HOH5- H?@HOH5, H?@ATIUHSHH dH%(HD$1H?H9w\HDH5, HL$LHD$yHHD$Hu7Ht$dH34%(u[H []A\fHHfDH|$HL$H tHQHHtHHBHfSHt% Hx H~H[fUH5D% SH(dH%(HD$1ZHHH+ Hu$H-%@HsH$+ HtHH* H8HHH?H9wtHD?HH$H?H9wmHD?HHD$H?H9w=HD?HHHD$HL$dH3 %(u*H([]@느f@AWIAVAUATIUSHhHT$HdH%(H$X1D$lD$$uH5LHD$(F I<$HH|$pID$HD$P H|$HH5# HHHD$HH5 * H|$pH|$pEHD$pH=HD$xOH=|AH|$xA9D$$ 9 A9 H|$xHwHT$xHD$xH$HT$xH|$HD$pHD$pH  HpHPHl H|$`H$L=eH?H$HD$lHD$H$HD$@H4$H|$7 H$H9ALd?H$H9Lt?H$H9Ll?H$H9HD?HT$Ht$H=iH$L$L$L$H$\$ $IcL>DH5!(  H5 ( H|$p11HD$PDHy' Ld$pHu(HqHHL' Ht11HLHuyB9\$$U9MH=$9tH=19@ƍ4vH\$Ld$pHHT$pH5FHfH$H t$$HIHt$(HLAH$IHt$t$$HI{Ht$(LIHc$$H$ H=HH$ HTHL$(H$@HT$L$0H$8\@H<$O|$l;nfDHT$HH=I$fH$Ht$$HIHt$(HcLAH$IHt$t$$HIkHt$(LIHc$$H$ H= HH$ HTHL$(H$@HT$L$0H$8LH$H$[t$$HIHt$(HLH$IHbt$$HIHt$(LH$IH_t$$HIYHt$(L|IŃ$Hc$H$ H=HH$ HHL L$($L$0HH$@HT$HL$8H$PH$H@H$AHt,t$$HIHD$(HtLHIHT$H$ H=H$ L$(K$H$ HEHT$H$ H=H$(a@IH$HHcPHcHtHT1HD$@L$MlHD$@$H$ H=H$ H$(HEHT$L$0H$8[HT$HH=aH<$|$lDH$XdH3 %(HD$HYHh[]A\A]A^A_fHT$HH=A<Hc$HT$H$ H=H$ HDH$(DHT$HH=,fDII{IAH$AH^t$$HIH|$(fDAH$AHpt$$HIH|$(P;fDH$AHtt$$HIH$AH)t$$HI^fH$HD$0I9~Hl$XHl$(ct$$HIHt~LH4I|$IHt)-t$$HHD$8HT$8HHHL1ILHL9d$0tDI<$HoAI|$Htt$$HHD$8lHHT$8tHl$XfD HD$@tH$Htnt$$AHIAAHHpHHD$xHD$x@ H={HD$PHD$xcH=HT$H4$HT$H4$qHD$HHHH@PH$HXH HiHu L%H LRH HtHHl H8IHD$PH$ H?H9HD-H$(H?H9HDH$0HD$HxH?H9HD?H$8HD$HxHtH$@HD$Hx8HtH$HH Hu H]H[H HtH$ HL7L|$HLLH"JHHBff.fH SH5HH H8H H5HHH;H5H;H5szH;H5dfH;H5XRH=TH;HH5LKH;1HOH5:3H=3H=,H H=H H=H H=H H=H H=H uH=Ho bH=mHT OH=aH9 external_encodingUTF-16LEUTF-16BERSTRING_PTRSyntaxErrornewParserANYUTF8UTF16LEUTF16BEpsych/syntax_errorparsemarkreadpathemptyevent_locationPsych/parsert,|mesgClassLoaderVisitorsVisitorToRubybuild_exceptionpath2classYAMLTree;1h` P(@Xp0 T |@ 0@|`0,px0Pp P<Xl0P0` 8P0@0 zRx $FJ w?:*3$"D\hH@t A xXHK %HW8%HWP&HWhELl+Ee$NEMD rDA<+AM A 0XeFHA GB  DABA 0eFHA GB  DABA 04qFAK GK  DABA 0eFHA GB  DABA ((GEAN c DAD (TGEAN c DAD 0{FAD NX  AABA zRx $0FDD D0m  AABE 0FAA G`  AABE HP4FBB E(A0D8J 8A0A(B BBBC HxFBB B(D0D8J 8A0A(B BBBH \FBE E(A0D8GENDe 8A0A(B BBBD LH|FBB B(A0K8J 8A0A(B BBBG H8FBB E(A0K8I@A 8D0A(B BBBF rEePEL T4`Hl\xpQH C A QH C A  QH C A P\ht0(FDD G@m  AABJ \8'Ea(xLEHD@ AAE L@ FEB B(D0A8IO 8A0A(B BBBJ L $(|4EGD ^DA(PFHA DU|ZETGNU--i #XP/X`AR ! Vi i o`  h l 0 oo@oo`ohj 0!@!P!`!p!!!!!!!!!"" "0"@"P"`"p"""""""""## #0#@#P#`#p#########$$ $0$@$P$`$p$$$$$$$$$%% %0%@%P%`%p%%%%%%%%%&& &0&@&P&`&p&&&&&&&&&'GA$3a1! W GA$3p1113,VGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1113.VGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY-U GA*FORTIFY.VGA+GLIBCXX_ASSERTIONSGA+GLIBCXX_ASSERTIONS-Upsych.so-3.1.7-8.el8.x86_64.debugES7zXZִF!t/]?Eh=ڊ2N a[Os(;'5+!wNMdM*{fd~Qt ʇVz(|ҭM95|&?R0.L2Ş%s&3e4a _xnִDoL)"0OK2'eDYXWdCA7ST"+\nO'1Ց29~k0|W gM7X46z'p+Á @mDorSspf]n=]S.m|DFdxXlgK QYmӅ#f(_T%e}jLaKT6jdwnuUO䥓*/r+*Wb\G;pݬsۇk NG>Fյ!ZXZ6^ٟz*3脙03@@8 @ЉЉ !!P  șș!ș!888$$ Std Ptd8i8i8iLLQtdRtd!!GNU5{p6~FUXz@j zBE|X=|mt2؁9wxGIqXuũ+we(w9 = }?$pp@UFqvY7Fg!  ]fS)"J0"C"}1,feQ, bNVByF"x#@!!g $ ! :V!U! `i@!} PV^ `$__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizegOne_ABCED9B4_CE73__00400511F31Druby_xfreeruby_xmallocmemsetrb_obj_classrb_class_namerb_str_duprb_str_catrb_exc_new_strrb_exc_raiserb_inspectrb_thread_currentrb_thread_local_asetstrlenmemmove__sprintf_chkrb_thread_local_arefrb_num2ullrb_ull2inumrb_yieldrb_protectrb_jump_tag__stack_chk_failrb_num2ushortrb_fatalrb_eFloatDomainErrorrb_raiserb_eArgErrormemcpyrb_bugrb_num2intrb_fix2intrb_error_arityrb_cBigDecimalrb_data_typed_object_wraprb_freeze_singleton_classrb_check_typeddataruby_xreallocruby_malloc_size_overflowrb_id2symrb_hash_lookup2rb_check_string_typerb_sym2strstrncasecmprb_debug_rstring_null_ptrrb_sym2idrb_eTypeErrorbigdecimal_parse_special_stringstrncmprb_str_tmp_newrb_str_new_cstrrb_str_resizerb_warnrb_absint_sizerb_big_cmprb_num2ulongrb_num2longrb_big2strrb_float_valueBigDecimal_dtoa__memcpy_chkrb_cstr_to_inumrb_cFloat__memset_chkrb_cSymbolrb_cIntegerrb_cTrueClassrb_cNilClassrb_cFalseClassrb_string_value_cstrrb_typeddata_is_kind_ofrb_eZeroDivErrorrb_num_coerce_binrb_intern2rb_assoc_newrb_rational_numrb_rational_denrb_ll2inumrb_str_new__errno_locationruby_strtodrb_float_newrb_ary_new_caparb_ary_pushrb_funcallvrb_Rationalrb_usascii_str_newrb_memhashrb_category_warnrb_num_coerce_cmprb_num_coerce_reloprb_check_convert_typerb_complex_imagrb_complex_realrb_keyword_given_prb_opts_exception_prb_to_intrb_hash_duprb_big_signrb_num2llrb_thread_check_intsrb_eMathDomainErrorruby_snprintfroundrb_dbl2bigrb_big_packrb_mBigMathsqrtInit_bigdecimalrb_ext_ractor_saferb_cNumericrb_define_classrb_undef_alloc_funcrb_undef_methodrb_str_new_staticrb_define_constrb_gc_register_mark_objectrb_define_modulerb_define_methodrb_define_global_functionrb_define_singleton_methodBigDecimal_strtodstrchrldexpBigDecimal_hdtoalibruby.so.3.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.3.4GLIBC_2.4/opt/alt/ruby31/lib64 ui ti ii ui ! 5!4!! !\8!\P!\h!6\!Z!6!058!!H! P!X!`!h!p!x!{!&!!<!>!A!J!W!g!jȟ!kП!o؟!s!x!!!!!! !(!0! 8! @! H! P!X!`!h!p!x!!!!!!!!!! Ȝ!!М!"؜!#!$!%!'!(!)!*!+!, !-(!.0!/8!0@!1H!2P!3X!4`!5h!6p!x!7!8!9!:!;!=!?!@!B!Cȝ!DН!E؝!F!G!H!I!K!L!M!N!O !P(!Q0!R8!S@!TH!UP!VX!X`!~h!Yp!Zx![!\!]!^!_!`!a!b!c!dȞ!eО!f؞!h!i!l!m!n!p!q!r!s !t(!u0!v8!w@!yHHy!HtH5v!%v!hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjA%eo!D%]o!D%Uo!D%Mo!D%Eo!D%=o!D%5o!D%-o!D%%o!D%o!D%o!D% o!D%o!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%n!D%}n!D%un!D%mn!D%en!D%]n!D%Un!D%Mn!D%En!D%=n!D%5n!D%-n!D%%n!D%n!D%n!D% n!D%n!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%m!D%}m!D%um!D%mm!D%em!D%]m!D%Um!D%Mm!D%Em!D%=m!D%5m!D%-m!D%%m!D%m!D%m!D% m!D%m!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%l!D%}l!D%ul!D%ml!D%el!D%]l!D%Ul!D%Ml!D%El!D%=l!D%5l!D%-l!D%%l!D%l!D%l!DH=!"1"HH="1LD$LL$H$#HH$LL$LD$ =LH=%% UH5>#SHHdH%(HD$1HߺHZHHH]H$H?H@f G$HGNA1fD HH[]A\A]A^A_D$Et1f} DM1DHI9}ɚ;nMf} HEE$HE7fM HHEMtYH88LHHHUHI)t8U$1ɾKfDҁɚ;v HEHI9uۉU$HH[]A\A]A^A_@FfL_1MG$IL\$AE1A$HD$8HD$tfDHD$1J|$L $LD$H~fAL $LD$HEJcH>DfU fB\$H#D$$AwBD\$$E4@M-f.A @BD$Ht$HZODA1fDw fDD4$D$$E1D$ <$f} D,$EYANxt$$fAvf} x []A\A]A^Avf} ~HL[H]A\A]A^DAE#wDAdwDAE#wAeAwAtAwjf.PXH5 HH\R!H81fHATUSHdH%(HD$1HT$H=Q!&HÃwHL%YS!HTLH|$u0HL$dH3 %(HuH[]A\Kff.@AVAUATUSF HfffPfHVLnIHWfOŅL9oLFoMLoIfG  t.M9l$M1AL$$MtAT$ LHmLkKD[]A\A]A^C$fHCN~S1fs []A\A]A^G$1HG1f{ []A\A]A^H$Hv$LO1fK tG$fHGN~+fW <1HLk$DfG DATIUHSӺ :HvL[H]A\f[1]A\fN$tyHFH~pHVN H9ssH)HGHGH9HG1fHWfG HFHtHHHLL$AL$HH9u)ffDG$HGf~ fW ffG fDAWAVAUAATIUHSHHHdH%(HD$81Ƀ%1҅tOAT$ M rAfuefC$HCftAfD[ @H\$8dH3%(HqHH[]A\A]A^A_f.f_E1AHEAGt6I9D$*MD$H}I9HIFHt5E$A9D$$|1fD\$E9\$wdHH9uI9wPA1fM@fNǍDpu+AC$ HCfDS @M1fAE1ffDK AHL$ G|?EE|GHD$fEPLHHHD$ PLL$@LD$8_AXD$ HLD$(IL$L$H|$ Ht$0L$ Mt3JH9rfJH9IHBT$T$MuH9dII)IHD$I9u1HHIAD$BD$1HtnJL Hf1HHtKHAD$=ɚ;v-ʚ;DDfDNAvfDk {I)MtBD 1fAfC HC1HtT L$ 1HHCH,@PHHLHD$ PLL$@LD$8iY^D$ H!LD$(It$L$9r)1҉t$ H|$ J4HL$0H9nMtMAʚ;AfDJ4AH9IDHB+T$D)҉T$MuѺHH9v'HAʚ;DHH)кD$H9rE1H9@HtFHH)LH@)1At$Ht"HAt$9sɚ;fH)Ht)T M91fA} EDD1AfC EDHHJHCH}DILpDLHHCHKvfDHHAD$D$H9rMLLHHLx?HcH[]A\f.HH[˺1[H@!H5H813AVH9!1AUATUSHH dH%(HD$1Hy?!H8IIHHɚ;HD$HSZ/DHD$ H HHHH Hiʚ;H)Htm1Ll$ E1HSZ/DLVHMpHH HHIHHI HH Hiʚ;D)Hɚ;LMHHHH HHHHHH HHH Hiʚ;H)Љ…u Hɚ;wHɚ;H@fD(H@H@H@fp X$L; uI;D$ tFID$ L Au8It/I$HƒHtH€I|$I$t D@H|$dH3<%(LIH []A\A]A^@(H@H@H@@$fx Of$H@H@HhfP @J<(LJLpHx$LpIHhKt fH surHHH$LDLDL@,IL)H)1ɉσL >M 89rtfDL@ыTTNHx fDSHH5P6!HHfP H[H4$HtcSHHHtKHC Hu?Ht6HHуHt'HрH{H tuHHD${HD$H[+ff.USHHHvnHsHHpHCHEHCHEC fE C"fE"HH>u1HHu HH[]H}$Hs$HH[]ÿff.@HtzATUSHH=THt8< tLu HHH8HHH0[]A\HpHHH LeMHEHHu8H5L9H5LHn:!H8Ht}HH51@HHƒHUHH TLeH[H5Lu[]A\fDH51 H9!H8fH=SHE D뮐fHHH@tOHHHtHt @u@ tB,ЃHF9!H5H81eDHtHHuZH;k:!tqH;Z:!txH;I:!toH;8:!tvH;':!tmH;:!H;:!tgH;9!t^H;9!teH;9!t\H;9!bHDffffffUSH~H>t NfD@uUńuU=THtHDЃ`HH\H[]fDńtHtHt H@t%HE@t%HE[@t%HE7t%HEyHH\H[]fH-A8!H\HHHHH[]H6!H5^H81H^H6!H5eH81ff.AVH5OE1AUATL%/!UHMSHHt)IIII]IuHHuHT t@ v uH u(KvATH@@$H@t-tfP 1[]A\A]A^þfp 1fH fAWAAVAUATUHSHH8L$PH}H88IHHHH IIHnHމ wH v t#t]Mu0HH4$H4$HItHH8L[]A\A]A^A_fDH88ILHHHBI9LGHfHHt$HD$HxHt$LD$HHD$ H$ ^HD$ LhPAE<-؉$HF1HI|I>*0 \HLHI|H& EuDA Av4 t/_uHL9wIrEM1E1Ll$JT%HL$H88HHHHMLDI9LBJ$HU<$HL$ILp@$H@AfDP I@$1HSHL$HL$HD$HL$L$HdHD$<-SHD$1<+u HH93HD$1L$IHHzDLHHHHIH LHMHLA0McM)I9HLXH/HI9HH9LHuHE11LhMfDADEE11E1E1HD$Hu ML|$KD HD$MLA .[HD$(E1HD$A D!E11E1EDA Av uHtHƒ v tE_HT$(>M5fD\$E HH5HH0!H81EuJ<$ILp@$H@fX fH$1N$HAE<-pD$1<+u HI88E1HA1G\fDL LH?HL1H)HIHHHHH9$Ht$1H9@Hw.H9v)1D|$A@$I@fAx 1H5<L$#L$qHHE1 I|HT$tEEuDA Avi td_t>0 HLII|HuE11E1HD$(MtDLDA0A vEL|$1Ll$MH|$L$$HHEcL|$KD HD$M1M|$A@$I@fAH NH|$L$$IHHtBDAƒ0 JEL|$M;E11XE11E1E1HD$(HD$rfAp 3fAP LHt$L$$H<.MHAHD$(LNLA1E1E1HD$Lff.AVI1AUIHH#!ATEUSHXA@LLHBHtDH;uH;C t9HC Hu-Ht$HHуHtHрH{H ttH[]A\A]A^@HHD$軺HD$@USHH8dH%(HD$(1t2HHgHHL$(dH3 %(H9H8[]fDHt$H賻H߾HH xHwAH)HH@|$HHwHHHmH߾ sH8HD$H t`HpHtgHzH(!H AHEHT$HT$ HH5!!HT$Ht1HJDHpHH=Ht$迶HT$Ht$H: off.@AWAVAUATAUHSHHXdH%(HD$H1褹f.f(fT f. ff.zVuTH'!^f/w H'!@HL$HdH3 %(HHX[]A\A]A^A_f.HH1HHL$@HT$LD$kH\$HH)A݃ALd$ HHL聶H虵L$=I4D9H88D)LcH00000000LHHHLH)‰Ѓt 0HL1Ҿ D H$H88HHHLHHHHH,H5!HH%L$HhfP wf/H%!vHH5E!1HAH%!EDEtHH/H H$!HH%!H5H812fHcH;E1Ld$ FH88A)H00000000McLHHHL)HP t 0&HD$PL HD1胱98HNjD$H)Hce*AA98A)AADDD$AHcDƍH)DAHALcD)M,HcH)LIH|L)ƍ21ƃI<09rH~HHHLH)21AJ 9rf.A98I<0DAD)HcH,HH)L1Ҿ D, 1HK<4HLLD$,LL0LD$0000D00000000D0000FfD00:fD00膰HO"!H5EH81nHG"!HH "!HH!!HH!!HHuHH!!HHSHHHHDE1HY!!SAHHHtHH1H[D[fUHSH8Ht$H|$dH%(HD$(1dH:0 1@H:t0 HcHHQuHSH HHGAHHHHHD$Hv"H88HHHH9UvHHU1HHEHt$(dH34%(uDH8[]HA1H\HHHD$H!H5H81gbfSHHH|$Ht$5HA1H1HøHt 1HHH[AWAVAUATUHSHHHHt$=9HD$U @ HfJfH|$HH|$H&LeIVH|$L9HD$N< HCIHH|$ H9sHEHHCHD$HplHD$8HD$f} @ ffC N,1H{$LݭH|$ L{sID$Lt$ NL+ E1HD$(HD$ISZ/DAKHHD$IGHD$0M~L9l$L\$(LH+|$HD$I9Ht$LD$fHIL9At$HHH HIHH ʉHiʚ;H)A1ɚ;v A iʚ;)A1tMtAALAA=ɚ;w%zf.L$щL$ɚ;Z Aiʚ;)L$HHuHIL97fDIMIL9l$ H|$8H6H|$8HHHD$8H@HH[]HA\A]A^A_f'f'C$HCfS HH[]A\A]A^A_K<H5(IHELIEHD$HpܺGL|HH1[]A\A]A^A_LIHD$HHl$HD$H|$$H1fHHTH\$8}$H}fHt$HҍTQH\$8fC$fC HCHH[]A\A]A^A_HD$0L)L9l$(rLIH+|$fM1fj1HGH\$8!H\$8L%AWAVIAUIATIUSHH5!HxdH%(HD$h1JH5!HHHHD$ 萨u<[u H9H؃HuHߺ1HH5I!HA1҅u+HL$hdH3 %(HHx[]A\A]A^A_DH5 !H衩IHHD$(E fAW fffJfffufX1LHt$i 1HHt$Z Ld$L9d$ LMd$AH5I LBH<!HI|$K|$AHHH5|HD$0H!HVLHHIHLHD$8zHCAH5DH@H߉HlfD H;H0HD$ t{HHHXHq H~H߉LHHD$HD$HD$DLd$ H1IH qLLHHHXH H=3Ht$gHt$g踝H!HH8薧fDUHպSHHHdH%(HD$1IHH$A@ fw ]Hr5I@HhAL HptH~AL$uCHHuHtHHtHEHD$dH3%(H[]EH$ExA ADADAAA wRAE1A9t*fDЉA9uAA wIPHxc tMcL)HtH9HLHH H"IPH1H9} H)McHL)HEf.HHHH)1H EH$HxAL HEA HHtH McHIM)H9ILXHMcHL)kEH$HHEA E1CSH dH%(HD$1HT$Ht$xH|$H@HxDH\?H@H|$Hx;H|?HnHL$dH3 %(u(H [;HfD+H衚H1dH%(HD$1HH<$H@HxHD?HL$dH3 %(u HÐ˘D@H1dH%(HD$1H~H<$H@HxHD?HL$dH3 %(u HÐk@USHHdH %(HL$81Ʌxv 1HHH H5ZHHHHD$1Hp2ĝHD$H\$H uyHHEH OHHL1HH 11HH4ФHH|$H{HD$HL$8dH3 %(u(HH[]H[HuH=:sqɘfHHP 1ftftft HfD1HfHHP ft1fHDHDHHfx HHHHWH@ HHDHH'H$tPH@H@H5 LuuM*"!H^HcH>DHtI$wHHcH>1HL?HHT$HT$AV f *t f.1HL$(dH3 %(AH0[]A\A]A^DIF1LH4HHT$fH HUHfHzH HtfH HHfHyHt HtaDHi H;HuDHyHD HtHLLvHHHL$(dH3 %(H0LLH[]A\A]A^wfDH Hu%H9DHxH HtHL$(dH3 %(H0LLH[]A\A]A^v)@EЅ*H؀"zH ʥHcH>Dqzff3f^fHxI9~f*"yHHcH>fD*"^yH=HcH>1fffz*"yHHcH>fDfDHfHfHHDHBf.fdf*"~xHuHcH>1f*"QxHԦHcH>f*"(xH7HcH>LHMFM9LIFHt*Av$9p$rw61@DT$E9T$wr HH9uM9Lff*"wHBHcH>Dq*"wHHcH>H}ff.Gf>fLf<f=rf*bfAUATIUSHHH8dH%(HD$(1HHH$H؃Hu Hu[1HHIMVIEfA} HD$t f} unHEHL$(dH3 %(aH8[]A\A]HHt$HuHEHH4AI@1H)IrLHIHtdH1HHyHfHuHt HH8ffHwHHcH>{]HD$Ht$1H¼HtH@ H\$H\$fD$>HH\$fdAH H5Hϣ1HHxHLC H\$@A@ fLHL$XII܋p$HL$0HAx$DH@H Hw"f.HHHHH9wt7I@HHH@HHHHH9wH)HLl$H?H1H)I)x[MIHt$LA!IH@HLd-ILAx_LcMS LL~ILLHMD$ IA@ fbIG Ax$p$1ɅZLl$Ht$LIH@LLXIH@H.HXII(HL$0HT$PLLHD$PwHHw HufH=^HX HtLHL%]IH5 HXHC P fJf@fH|$H AH5H1@$HH@fH H\$X1HHvHH$dH3%(H[]A\A]A^A_f.z11H/h1HHR@1LL$(fLL$(AHD$ H H5aIyH5LHIHHD$`趸LL$(IHHD$hLHtLAu#ItI$Hu IIFLLL$(\IVAH5IHHD$pID$HDIUH9HJHFH| H HHkLLHHHT$xL蒁H|$ etLL$(LLPs1LVtMeDVfDLd$P1L)tI<$pI}L|$@f|$>IG p$tAH@HHHH8fHHHHH9wH)L$H@H\$HHDHt$HLHD$H4Ol-fDH).H|$H H5*AH H@$H@fp (H|$ThH|$HH@UHcH}H|$@LHHt$XHD$XfH5 HHVLt$H5 HLVI9u!HC H\$fP <\ZrHHHC H|$@HL$XHT$PLHD$PƫHH HHuHYH HtH|$@HLqX1bH{AIH4 H5H}H|$@HHHH$IHH$LHtHAu"ItIHu HHFL觴IUAH5IHH$IFHDHUH9HJHFH| Hg HH贛LHHHH$L}La+qHHo1HpHEH)D$H\$P1HpH;vH= H5^}H81\RrRSfAWAVAUATUSHHdH%(HD$81~oIHu_HL$HHLH$褩HtWH$1HoH;9fHL$8dH3 %(uiHH[]A\A]A^A_ÐtYU@HQ H-~HuDHcWH, HtHHLUbRH~H5@t&IWHcHJuHLKQؐ19`L5 H}AH5}IILHIHHD$BIHHD$H؃HtHu"HtHHu HHFHߺIT$AH5T}HHHD$ HCHDIUH9HJIHFH| H HLHHHT$(L1{L9_nHLl1LmIENpff.AWAVAUATUSHHdH%(HD$81gHHOLfMLA5PHH?dILMYULcM71`^I|$AL5 H5|IIHHIHHD$hHHHD$H؃HtLu"HtHHu IIFHߺHUAH5{{HHHD$ HCHDIUH9HJIHFH| H1HLHHHT$(HXyL`]lLLk1L#lIEf.HHHL$8dH3 %(HH[]A\A]A^A_fSQHL$HHHH$[HuLH_ L%zHuLsSH< HtHHH RoNH$1H\kH;JPQ;NmfDAWHAVAUATUSHHH|$0HT$(dH %(H$1ɨuDHHD$(HHD$H H|$(NILd$(IM HHHHHCH:, (H;Qf1Ҹf.f(fTE1f/f.91f.1@Hs ALH5xH讔HHD$x1HHC$HCfS iHH$dH3%(i H[]A\A]A^A_DHt@HX HHcH>1HH跬HHH HH8VH H5TxH81KHPH$HHDŽ$<HbMxH5I HAKtHk 1M Aff@f@ fpHFJHnP1HHH? H H5uH81@JH1HH?LHuʺLH肫Hf.f/s 1 HY ALH5vH蔒HHD$xH1C$1fC HHCgH1HgH H]AH5wH.IHD$HHD$x1LGgIEAH5vHD$HH HIHD$PHD$x1LgIEIL$HL$HD$PHD$@HD$xH@ILd$8^HD M$HD$@HD$ HEHHHHHHD$@HD$HCHH$f{ HD$0L-wHD$MAu>MIMu,LCH5jHHk H81?fItItI4tAhA tLCD$ ?L$f.1+wf/f/ wH,L|?fDBI"IcDL>LCHtHHHt3H5 HL$8HHD$8@HLH?Au@IH " LHt H LBf1f/DAAC E1fLAH?&LHMO LHHtHt M H5 HL$8LHD$8?HHs AHH5iH5Y LQ=Ht$LHD$0^=LHNH LڲI+fHQHl 0L;AIHtHHt AdH5 HL$8LHD$8>HkLAIfDf(`HWE1LHL9>t HIE1 cC fsfiMbMIIH H艤HŨ HHtHt @ H5 HL$8HHD$8O:H@Ld$8<HHD$8L:LHL LH?Hu;IH LHt H9L|$ fH~H @HH HD$X|$|$ f|$DT$1PHt$HT$H T$H Ht$H \$H HT$D$YXfH~fD$H ց|v`HH9T$ -HT$"HHT$ HHOH /P|$HH H H|$f,f*\EHHT$2f/ML|$` /f/Y 1f(fW*/DE1D$H1E11E11D$H1p1f/~f/ v1k1~MfHD$("HHD$D$EAAPD0 0D$ HcT$4H/D$Y`N0ZFL$HD1AKG4E9t~DރLPT$D$H H HT$t$t$ AMIA1fHHT$ HD$H ID¹H H HT$\$\$ {1ɃQGFT$A0IEeA0tEqE6/D$ Ee8D$ @D$\$ fH~H @HH HD$\\$f.,\$ f\$HD$DL$Etсwk)ωD9HH HD$|$|$ 6HD$(ML|$`"HHD$QH\$H!H!H HL$ML|$`7 !H HD$%|ff.AWf(AVAUATUSHx|$t$HT$(LD$0dH%(HD$h1fH~fD$H Åf(%==ff.f(Ht$`H|$dL$ T$T$L$ HfH~fH~Ћt$`E1H H?H H fHD$D$f*Y -\,Y,X,Xf/D,1)DpAIcH5+f/AD$LD$8EE Dd$ ED$D$ ~ 1ۉD$|$D$D$HyD$D$ D$\D$@OHcD$XveHD$(H\$0A0IfDHtH@HHt$hdH34%(LHx[]A\A]A^A_ÐfH~H؉H H ‰%HT$T$=HD$(fH~'HH nHV)IID HHuH\$0H75@D$LD$8EFAA)Dt$8E1E5P|$D$HD$9 D$\xD$@HcD$XT$PPI"\$X D$ T$P ÉH) Љ f(^<*H5(ttYHu^|$Lt 'f/fɋL$@*YX )fH~fH~H -@H H …t$ |$@,fHT$WHcL P(\$I_A$ыT$H*ȃ0\(  )A^\f/w{-`&f(\f/ DG%:)ITf(\f/ H9YfHY,*؃0C\f/vFD$ {fD$T$x|$ INjD$dT$q D$\$\\$@D$XD$P3Eu 6+D$`\$8AdD$HIHIEt$8~E~D9AO))A)Ɖt$8t$t7D$Hv LHHI`HHD$HD$HſHHD$HHGEB|$XtHHD$V D )ƒ)T$8Aօ~ HHE~H|$DHD$D$LH\$HcC9E}HHuHHTH9_HH9tKD$ H1Ҿ XHŋD$H D$\ D$@LDd$@Lt$H1Ҿ HLHH0CDEEu }D)D9|AE1HHt$HŋUHcF)…0 HHMHHT H9 HH290tSn f.t$`T$d2  )f~fAH*fH~fH~H H H I@DD)d$8Dd$ E1D$DaH_#INf HHuHt$0HJHBfD$LD$8EWf@)f~ D$HfA*f.zA@Dt$@EbD\$HD$ ED$8Ll$E D$@ML|$@I\IH\$8Ht$LsEgōX0IcEA)HIOHITfDH9HH:98tAHt$H|$^P AHcPEGA)u>H IwHHLfH9HH99:tEAHDD$HeEDD$H|$eExIA^L;t$8L1Ҿ q1Ҿ LIL;l$TH|$1Ҿ I@HD$fDHDD$H|$DD$HB D$E5 D al$LL|$@ADMI^Eu }EHHt$HŋUHcF)…c HHMHHTH9` HH290triA9Dd$A1PfDHt$H|$yH!H|$ALI^L|$@A9<AE&MLl$fDHt$H|$DPEAIHD$f*YX Z!fH~fH~H -@H H fD\8!HT$L$f/;fW 3f/D$PfT$|$ D$dHcD$ Hx ‹D$D$@5Y AHD$f/L$D$ I_A1H|$kMtL^HVHD$(t$ 0HD$0HcH[f|$\$H ڈT$X\$8E1f.D$PD$8AxD T$ Hwډփ YH5f(1@t YHu@af(XDx|$XHD$E1Ht$FD$XH|[ )‰DD$\$@H|$1ҾKUHHD$Hc@)…HHMHHT H9[HH9tG$fDf(¸Vft$HH@D$XD$\D$@D$Yff.LfD f(Xf/w\f/D$P Ct$ DL9fBHHS<9thf(¸HHt$HHHH 6AEA#HD$E1D$L؉D$ LIHD$H uHcT$ f(fI_H Hփ^t$ ,f*0AY\f.$D$@D$@%ILfDH9YfHf(^,f*P0SY\f.zHÀ{0HCtyA$GH%LI|DCHH9YffH,*ȃ0\f.z@SoI9(PHHC9t|$Ptt DH|$MOM>M95L(fDSHHC0tA99MLl$t$ xt$@|$\?%8fɋ\$ *YčsYX fH~fH~H -@H H 3AD$D .fHD$E1=A1D$ A}HIcEHH`HHD$A0LCD$ ALMH\$8L|$@Ll$ASYL1Ҿ uIŋD$\6D$@Xf/AHD$D$\(DAI^LL|$@A9F1DOE&MLl$Hljl$ALL|$@AE5l$LAL|$@uI^D$\\$ D$@,fH{Iuf(f.HA3D${D$\A TT$fD$ IOf(^,f*P0AY\f.{'|$@UH<)‰[Hff.AWIAVAUMATfI~UHcSHH(dH%(HD$1fH~H f(fT f. f.f.DLH4Ld$T$YfH~fI~H4-A}LcHc LUH bN0HHE1L9fDHEMtImH\$dH3%( H([]A\A]A^A_D-AdA>=<=remaindertruefalseto_strStringprecision must be an Integer21E%ld-0sqrt of negative valuesqrt of 'NaN'(Not a Number)#1BigDecimal.exception_modeBigDecimal.rounding_modeBigDecimal.precision_limit.5BigDecimalnewinterpret_looselydouble_fig_loadsave_exception_modesave_rounding_modesave_limit3.1.1VERSIONBASEEXCEPTION_ALLEXCEPTION_NaNEXCEPTION_INFINITYEXCEPTION_UNDERFLOWEXCEPTION_OVERFLOWEXCEPTION_ZERODIVIDEROUND_MODEROUND_UPROUND_DOWNROUND_HALF_UPROUND_HALF_DOWNROUND_CEILINGROUND_FLOORROUND_HALF_EVENSIGN_NaNSIGN_POSITIVE_ZEROSIGN_NEGATIVE_ZEROSIGN_POSITIVE_FINITESIGN_NEGATIVE_FINITESIGN_POSITIVE_INFINITESIGN_NEGATIVE_INFINITE+0+Infinity-InfinityNANprecsprecision_scalen_significant_digitsaddsubmulthashto_sto_intto_rsplit+-+@-@/quo%moduloclonedupto_fabssqrtfixroundfracfloorceilpower===eql?<nonzero?coerceinspectexponentsignnan?infinite?truncate_dumpBigMathexploghalf_updefaulthalf_downhalf_evenbankerceilinghalf]Dp/pp`a00000010000000000`1\YYZZY|Z[[[[[[[[[[[[[[[[[DZYDZ[[[[[[[[Y[[[[lY`WXXXXXPXXWXXXXXXXXPX[22222222222222222h[X[HX22222222@[2222cYZXWWWXZ0W0WKXKX0WYWVVVWYV3WV3W3WXvvvvvvvvvvvvvvvvvVUUvvvvvvvvUvvvvVWUUVVUX^^^^^^^^^^^^^^^^^UtTtT^^^^^^^^tT^^^^UhWSUSUUkQlQlQlQlQlBpQlooQlQllQlQlQlQlQlBpQ{1}||t}~00000$00000000$& .>C]r2<?CeAXp}NaNInfinityؗҜ<3#I9=D2[%Cod(h7yACnF?O8M20HwZ@xB(8EIJxLTxMS8SLS`StSTT(V8WPHYXZ[@\_cdd(gxq4sv HpxȡXد0LHhXط((D(( zRx $FJ w?:*3$"D\HpT PLNAVtYA$+AAG PID0q<D0BBB D(A0l (A BBBB dBHB B(A0A8G`M 8A0A(B BBBA W 8A0A(B BBBE $H`Ae J D L _(UBAA } ABD (@oEAD0X AAA lPAa N _((nEAD0W AAA (lkBDD | CBE 4LCD xAACL aH0$mBEE E(D0D8DP  8D0A(B BBBF |HTA D VdBEB E(A0A8D 8A0A(B BBBA  8F0A(B BBBE Lc,]WD0eXSAa N b8xBAD K JBJ K ABJ L BEE D(D0M (A BBBH \ (D BBBJ AAK 04FAA D0w  AABI `hLBBB A(A0 (A BBBD i (A BBBH X (A BBBA 47BDD Y DBG ACBlLBBB E(D0D8G 8A0A(B BBBK OPBuOPA| BHB B(I0D8G 8A0A(B BBBA  8C0A(B BBBF < 8A0C(B BBBA $zRx ,t4DPFDA e ABE j ABK @|=BKB A(A0GP 0A(A BBBE 9Qg uND \AA4DAAG N DAD Q DAA @8HAA gABT  ABG |8GG F @lECD { IAG  LAC f DAA <FLB H(G0 (A BBBA H u BEB B(A0D8Gp 8D0A(B BBBG zRx p(&P@ BGO D(C0D@h 0A(A BBBE ( AAGP~ AAG H tBBB B(D0D8G 8A0A(B BBBK \ W`j F F(| X>EDDP AAA  lPEG BA BGB B(A0D8G 8A0A(F BBBA s 8A0A(B BBBA J 8C0A(B BBBA  8A0A(B BBBD H` BBE E(D0A8N 8A0A(B BBBF ( HEDGPW AAG 0 FAD G`  AABA H x]BBB B(A0D8D{ 8A0A(B BBBJ 0X BAC J  AABA ( H]AIN0 AAH |ED0m AI  \H F B  <\H F B ( EAD` AAH @ tGMl G F` ;Mmx )H] (HZ zHc E I \EP` AD  82El\2Hf( EMDP AAA (LEMDP AAA (x|EMDP AAA 0FMA DP   AABG (EMDP AAA LP FNB B(A0A8D 8A0A(B BBBG HT$fFNB E(D0A8DP 8A0A(B BBBJ H$&FNB B(D0A8D 8A0A(B BBBI L(FEA D(H` (A ABBH  (A ABBF L<h*FEA D(H` (A ABBH  (A ABBJ L+FEA D(H` (A ABBH  (A ABBJ dH-FEB B(D0A8F 8A0A(B BBBI e 8A0A(B BBBI HD/FBB B(A0K8N 8A0A(B BBBE (4EMD0[ AAE 4H  G  E $"EHL0GA46EAJP_ DAL q DAE p@65BBE K(C0K` 0A(A BBBF  0J(A BBBK I 0J(A BBBF zRx `(x<t<p<(l<<h<Pd<Ld`<FGD A(N` (A ABBD , (L ABBK L >FBD G(DPD (G ABBI s (A ABBG L>FGD A(N` (A ABBD , (L ABBK LT@FBD G(DPD (G ABBI s (A ABBG L`AFGD A(N` (A ABBE d (L ABBE LBFBD G(DPD (G ABBI s (A ABBG LDPCFGB B(D0A8N  8A0A(B BBBH 0FBDC G@L  AABH LlIFBA A(F0R (G ABBJ v (F ABBG D΁j@K-2,8H\fcRT<hLYǣE-$tS1Js>*ǍT}2NO;: fEK>pv۔"뒡f,1xy;Yco/*_l3v߈M6)kD.bhBDXjWc(DB`c`ka`Q;ԋ)mŪcn-(Z`8T>ÈNL+)NؔH;>1 =ʯ_JyFy-ShQX̢/.|o!J~_-ngN6niޭga |i !=YdF\&dtИ/F|Ɍ|dt\jY,qT?֟+X>8I$-2w f=(9-#(i Sc|\M}71oxNi%kϲ!è~[fí:4D"A&SŘSPDr6XQf3 ?3ӝ󭛏5ׄ|)IqAOBF${.{M1/i^7g n<"ɐ" 9䂃ZEwR]Yz]~}#[6Oó #6-*'+_[q̈pҰY!TH_NVNٔpOA!oJ~s61OZqgˍpez ɜƷQ⏜+IV\2s4x۠)2X4kQe{n"\6j3|74>"'l@WBb _v-@R:?XϚi{9~->yHkI8Oa\*1~fJ~XAg[צq]r%: 0잜> a%X;˷t@ZQ@ˈP V.ɛMǠ~qӃ4z=bPUc恽&zi|P(XL 5/aEk>t/NEJkWd`([wt~b0#vH寢e_ƕʭ%`+iG=7|ѸF!j)?\`z)} V'GXǧY{/P戠M[qû}9,.*2*E*{ q B.C%.(*uu 3`| _/topRrWmTZ+pdDrDk66A4┺n%|1K zAv4tW[aӎn8c`7p/,6K|?o;8HJV>ȹE+z{šan'aTtd882TO:Z5W_~'M65g'aONFRPB#uߏ;'Ope5Kκh@R$' ^؀>,rm4+I$:f 8=;(, $q{gaщl}lٖҖbXAK K_1rv茱;S{q@ )T /6bi3ݧ͹+4 W bƎ |DR䈋/7!_)T춥 ަ<=GiF5Me*FK&Gn[Yq-@BEFt8cydnb Z=z-lFѽ gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``P( x 0(( 8o44 Eo@@pT^B h%%c%%n,,w0303!}8T8T `T`T 8i8iLmm( !!! ș!ș؛!؛!@@!@ a@l ,ؤ ح(PKҖ]"ruby/json-2.6.1/gem.build_completenu[PKҖ]6%ruby/json-2.6.1/json/ext/generator.sonuȯELF>@@8 @vv zz z  h{h{ h{ 888$$uuu Stduuu Ptd8g8g8gTTQtdRtdzz z GNU8@v )L@$LNOBE|qXt)C} %5X$Xo8hUc|s oC/Sm"u~"-N?_>, cF"(Qi    X__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_check_typeddataruby_xfreeruby_xmallocruby_xrealloc2ruby_xmalloc2rb_str_newrb_utf8_encodingrb_enc_associaterb_funcallv__stack_chk_failrb_hash_newrb_obj_classrb_class_namerb_hash_asetrb_str_new_staticrb_str_duprb_str_catrb_str_concatrb_str_internrb_sym2idrb_ivar_setrb_attr_getrb_data_typed_object_zallocrb_obj_is_kind_ofrb_cHashrb_class_new_instancerb_intern2rb_ary_entryrb_string_value_cstrrb_iv_getrb_str_substrrb_id2symmemcpyrb_enc_getrb_usascii_encodingrb_str_export_to_encrb_enc_str_asciionly_prb_path2classrb_raiserb_debug_rstring_null_ptrrb_error_arityrb_string_value_ptrrb_float_valuerb_hash_foreachrb_eArgErrorrb_unexpected_typerb_hash_arefrb_check_convert_typerb_convert_typerb_cFloatrb_cFalseClassrb_cArrayrb_cStringrb_cIntegerrb_cNilClassrb_respond_torb_cTrueClassrb_cSymbolrb_id2strInit_generatorrb_ext_ractor_saferb_requirerb_define_modulerb_define_module_underrb_gc_register_mark_objectrb_cObjectrb_define_class_underrb_define_alloc_funcrb_define_aliasrb_internrb_define_methodrb_define_singleton_methodlibruby.so.3.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.4/opt/alt/ruby31/lib64ui ii z  z P { { { d0{ #8{ !x        # * 4 7 @ A B D K} } } } } } }  }  }  }  } } } } ~ ~ ~ ~  ~ (~ 0~ 8~ @~ H~ P~ X~  `~ !h~ "p~ $x~ %~ &~ '~ (~ )~ +~ ,~ -~ .~ /~ 0~ 1~ 2~ 3~ 5~ 6~ 8 9 : ; <  =( >0 ?8 C@ DH EP FX G` Hh Ip JHHg HtH5e %e hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!%a D%a D%a D%a D%a D%a D%a D%a D%a D%}a D%ua D%ma D%ea D%]a D%Ua D%Ma D%Ea D%=a D%5a D%-a D%%a D%a D%a D% a D%a D%` D%` D%` D%` D%` D%` D%` D%` D%` D%` D%` D%` D%` D%` D%` D%` D%}` D%u` D%m` D%e` D%]` D%U` D%M` D%E` D%=` D%5` D%-` D%%` D%` D%` D% ` D%` D%_ D%_ D%_ D%_ DHHHHf.fH=` H` H9tH~_ Ht H=_ H5_ H)HHH?HHtH_ HtfD=_ u+UH=z_ Ht H=Z d}_ ]wH7Hthv$HtNHu8R1€?v2fHuBZ H$H==HQHHH#HT$dH3%(u HH[]A\2fAV1I1AUATUSHHH H5,Z dH%(HD$1IHHH5 =HLHH5[Y IH$WHu_H=:HHH[HLHHUHL$dH3 %(u2H []A\A]A^LHL,$H5X Lt$)fAT11USHHHH5#Y dH%(HD$1ILHH5qX HH$mHt5LHH,$H5OX JHT$dH3%(uCH[]A\ÐH=w9oHHHHt)HHH$H5sV HfHV 11H6fDAWAVAUIATUSH(dH%(HD$1H5P LHdHHbU Hu&L%6fDLH|HHu H[]DHuHHD$HD$H[]ff.AWAVIAUIATIUSHH8dH%(HD$(1DHMfH\uLD$$E1ft$"E1ɉD$ HK<4<iP5H53HcH>AL=.LL)LLHMNMI9rLL)tK4 HHHcHCHS"HCHD$(dH3%(cH8[]A\A]A^A_LAL=j.L)kK4 HL$8L$KAL=$.&fDAL=.fDAL=.fDfH5-00ffL$$AL|$"D$'T$&MfM In&f.1AIHHHAIHHAIHHHAIHHAIHIcH g1H+H&H(H=HBH_EH/H\H"HH$HCHsH$HCfL9AH 1IfALH9H=,H5/H1D1f1f1f1fAIHMvMHhfH5+HL9,HD$HD$HD$ @H5*H|H5v*H\H5M*H<H53*HgH5*HGHHLHHH$H f(H$ff$LHpIH=)I. H=z)HD$H( E3H=^)\H5,H1{1ff.@ATUSxdIuWH=#H H5WB HH,HHHSrHsqLHH[H]A\H6t1D@UHSH(Ht$H\$HdH%(HD$1EHL$H t0HQH\$HL$Hu3HD$dH3%(u0H([]fDHH\$HL$HtHHATIUHHSHHE$$11H5F HD$IEu"D$f(fT "-f. *-wf.zBHHH[]A\HHD$bHD$H=F H5'H1HHD$3HD$H=WF H5m'H1ATUSx\IuOH=CF H5w@ HHLHH!HspLHH[H]A\H6t1lff.SHHH5E 11H[Hff.fUSHxZHuMH=E \H5? HHHrHu2HHHH[]aH6t1@HHH HH[],ff.AWAVAUATIUHSHHHLz0L*dH%(HD$81HB8LrHRhHD$HExHHExHt H9HH $&HCHSH5H ${HT$HCHLd$ H\$Hl$D$(&LexID$HExMtLH|$Mt;H~6A1fDD9t MtLLH߃D9uDH{HCHS}HCHD$8dH3%(u[HH[]A\A]A^A_HT$LHH$tH$MdPHExH=mC H5$HP1HUx*f.AUATUSHxfIuYH=MC H5= HHVHI+LLHHHHH[]A\A]DH6t1lff.Sx_uUH=B H5< HHHH5#HHSH[f.H6t1ff.Sx_uUH=IB H5}< HHRH*H5]#HHH[f.H6t1lff.Sx_uUH=A H5; HHHH5"HHSH[f.H6t1ff.Ht3UHSHHH"HHHH[]D1HfATIUSH9$HH5B; HH53; H HHoEoHMoP U oX0]0o`@e@ohPmPop`u`oxp}pHHHsH;HsH{HE Hs(H{ HEHs8H{0HE H{@HsHHE0H{PHE@HtHwHHEPH{XHtHwHHEXH{`HtHwHHE`L[]A\H> H5!H81SHH59 SHHXhH[SHH59 4HHXx[DSHH59 lHH~H[ff.fUHSHHtHHtHHuHHH[]YfSHHdH%(HD$1tH2fHtHHuܾH=! HHH=HHHH5= H$HT$dH3%(uH[DAVAUATUHH5;8 S@tHfHtHuIHHuH% LmLI|$@Hu%HtID$@[]A\A]A^@HtHE% LuHt LuMtCHLMl$HID$@[]A\A]A^HHIofDH= f.AVAUATUHH5+7 S@tHrfHtHuIHHuH% LmLI|$0Hu%HtID$0[]A\A]A^@HtvHE% LuHt LuMtCHLMl$8ID$0[]A\A]A^HHIofDH=f.AVAUATUHH56 S@tHbfHtHuIHHuH% LmLI|$ Hu-HtID$ ID$([]A\A]A^Ht^HE% LuHt LuMt;HLMl$(ID$ []A\A]A^HHIofDH=f.AVAUATUHH5 5 S@tHRfHtHuIHHuH% LmLI|$Hu-Ht{ID$ID$[]A\A]A^HtNHE% LuHt LuMt;HLMl$ID$[]A\A]A^HHIofDH=f.AVAUATUHH53 S@tHBfHtHuIHHuH% LmLI<$Hu.HtlI$ID$[]A\A]A^DHt>HE% LuHt LuMt;HLMl$I$[]A\A]A^ÐHHIofDH=f.AVAUIATIH52 USH dH%(HD$1H LHHHHH=8 'HH HH=7 HHHH=7 HHHH=7 HHHH=p7 HHH<H==7 Ld$sLHHEhdH56 IHD$HH=6 4LHHExH56 IHD$HH=b6 LHH5k6 IHD$VHH={6 HHH=\6 HEpHHH=5 HEq|HHaHLErHL$dH3 %(H []A\A]A^LH%HHEh@LHHHEx@LHHHHHfH HH<LHZDHHEh4@{HHEx[@HuL0LHuA 0LpL`IvMLLuHE fDuL0LHuA LpL`IvMLLu(HE fDHL0LH5A LpL`IvML+LuHHE@fDL0LHA t|LpL`IvM_LLu8HE0vf.IL`AIvIL`AIvIL`AIvHIL`AIvfDL0LH-A t,LpL`IvMt3L+LuHE>fDIL`AIvfDH=:Ht$OHt$H=Ht$/Ht$DH=Ht$Ht$DH=Ht$Ht$RDH=Ht$Ht$pATIUHH5, SHH@hdHǀxuL[]A\Hut1HtLL[]A\AUIATIUHSHHdH%(HD$1tuH+HA H0 H0 HH9uefHHLLHD$dH3%(H[]A\A]HHuHs0 HHA0 H9tHU0 H9$H0 H9THjH!HubHuuHtlHH u`HL=IHCwH/ HaH/ HQHLHDHi/ H9XH5y0 HHHL,$H5S0 HHHHLfHHLL/kf.H5cLHHUrHuqHL )H5LH. H1H5LlH5i/ 11HtAH@Hy. HfHupHL!}@HtHHuHUrHuqHL1MAWAVAUIHATUHSHXHB@LzHT$HD$8HBHHt$ HD$@HHRhHD$HAPHxH@H|$HHyxHD$HwH|$0Ht$(HqxHt H9HHEHU[HEH|$8t H|$@}D$01D`QDHH9}RH|$tH|$HLHHT$Ht$ HHIE uIEH9|HD$HT$0H|$8HPxtOH|$@Ll$Mt9HD$0H~/A1 DA9tMtLLHRA9uHHEHU]HEHX[]A\A]A^A_H|$(,E1AE9MtHt$LH@HT$Ht$HHHT$@Ht$8HLl$M#WHT$@Ht$8HlHuHD$H=, H5 HPxHT$HHPx1f.AUATUSHxfIuYH=m, 8H5& HHvHIKLLHHH'HH[]A\A]5DH6t1ff.ATIUSHHH5'& HHLHH~[H]A\fUSHHHH5% HHH[]fAT1UHH5M+ SH1xEIu7AuIt I$Ht6LfHutź1fH= + [L]HA\DAWIAVAUATUSHHHLrHBHt$ H*Iv`I~XHD$IIN0M^8MfHWMnxHD$HFHD$(HFHD$C~ HHt MH|$tKM~FEH\$0E1LEAE9tHtHt$HHAE9uH\$0LudI?MuRH( HH ( H;t-H ( H9tzH5) 1L1HIǃHtwLRfIfIlA:A wH)( HH5'( H9tH s( H9uL>HHIǃHuItIHpHt$LLHH|$u|HL$ Ht$LHCHH1[]A\A]A^A_f.LHH^DH q' IWH9IHpHT$Ht$(HFmHwHL\$8HL$0*L\$8HL$0HA' HfH& H9H& H & HH;*RH& H5 ' HH9.fHH=K 2H=H5? HH' H5- HH=H' ~H= H`' kH=T' HE' XH=9' LH% H=V' H52 HH5HH.' H="' HH5ZH=' H7H5H=& HH5H=& 1HLH5|H=& HH5dH=& 1HH5PH=n& HH57H=O& 1HVH5"jH=3& H7H5KH=& 1HH5/H=% HH5H=% 1H`H5H=% HH5H=% 1HH5H=% HH5H=c% 1HH5~H=G% 1HH5bH=+% H?H5rCH= % 1HH5d'H=$ 1HH5X H=$ 1H[H5GH=$ 1HH57H=$ HH5H=}$ 1HH5 H=a$ HH5yH=B$ HvH5ZH=#$ HH50H= $ 1HH5h$H=# HUH5AH=# HWH5H=# H(H5}H=# HH5bH=~# H5XH5]HHQ# tHH5BHiH=*# H5FHH5H;H=" H5H\H5H H=" H5HH5H߿H=" H5H0H5H豿H=r" H5HH5HHA" 蜿H=5" HH53]H=" HH5@>H=! 1HH50"H=! H50HH5HH! H=! H5ʿHH5H迾H=! H5蜿HH5jH葾H=R! H5nHbH5<HcH=gH=!H TH=H AH=H .H=H H=H} H=Hb H=HG H=H, ϼH=H 輼H=H 詼H=H 薼H=H 胼H=Hu pH=HZ ]H=H JH=Hl 7H=HQ $H=H6 H=H H=oH=lH ߻H=eH ̻H=XH=QH鰻HHC*@instance_variables0123456789abcdef\n\r\t\f\b\\\"\/RSTRING_PTRJSON::GeneratorError%u: %li not allowed in JSONnesting of %ld is too deepnullfalsetrueunallocated JSON::Stateto_hashHashto_hjson/commonExtGeneratorJSON::NestingErrorfrom_stateinitializeinitialize_copyindentindent=spacespace=space_beforespace_before=object_nlobject_nl=array_nlarray_nl=max_nestingmax_nesting=escape_slashescape_slash?escape_slash=check_circular?allow_nan?ascii_only?depthdepth=buffer_initial_lengthbuffer_initial_length=configuremerge[][]=generateGeneratorMethodsObjectto_jsonArrayIntegerFloatStringincludedto_json_rawto_json_raw_objectExtendjson_createTrueClassFalseClassNilClassto_snewallow_nanascii_onlyunpackcreate_idextendkey?__send__respond_to?matchkeysdupJSON/Generator/Statepartial character in source, but hit endsource sequence is illegal/malformed utf-8source sequence is illegal/malformed utf8(E`01234567890    ;TIpX i0 z` hHغ8h 8ȻPl(Xx( HXd(8($88xXx8x(hP|8h$hpxH0L8 H, L Hl  HD t  ` P X @   LzRx $0FJ w?:*3$"D\p|%HW"HT(&HW@&HWX'HXp&E`&HW0"HTHAUdEv/Am,0BDD V ABE $;AAG lDATH F A 0FAD D0  DABA @DFIB A(A0JP 0A(A BBBD 0TFEA J0t  AABB 6H] K D9H] K D$89H] K DDX9H] K Ddx9H\ L D(EDM0q AAG H1FBB E(A0A8D` 8A0A(B BBBF (1BGD `AB8($BHA  ABH M ABH dxK xKK0 AD 0pEADG0T AAF ZAAHBBE E(I0A8Gp 8A0A(B BBBH ,|FAA N DBL (L@ADD@V AAG 0xBDG G0N  GABE ,@tFAA J DBH #AZ0EAD K DAF jDAL,BBB B(D0D8G# 8A0A(B BBBD 8|`FBA A(D0O (D ABBJ tEL O tEL O ttEL O (>FDO WAAF,DXFDA 1 ABA t)EczRx  P+EeP13Em$  WEDI vIA HDEG  AA LlFBB A(K0i (F BBBE @ (A BBBI LFBB A(K0i (F BBBE @ (A BBBI L PFBB A(K0r (F BBBD @ (A BBBA L\ FBB A(K0r (F BBBD @ (A BBBA L FBB A(K0p (F BBBF  (A BBBB @ FBE K(A0DP' 0A(A BBBD zRx P(˫4x mFDK g ABA iAB8 L9BED D(G@ (A ABBA L PvBBB H(A0D8D 8A0A(B BBBA 8< FBA A(D0O (D ABBJ (x >BDA lDB$ .EAG [DA( FCK yDEL dFEB B(A0A8G 8C0A(B BBBK H HsGNU P { d#!  paz z o`   x}  oooo$oh{  0@P`p 0@P`p 0@P`p 0@P`pGA$3a1}a GA$3p1113paGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY paGA+GLIBCXX_ASSERTIONSgenerator.so-3.1.7-8.el8.x86_64.debug<7zXZִF!t/W>]?Eh=ڊ2N" t͢N-nKܓ_b`QʌΡNї`J=7cxVۚ:c~"V m,JyF>X6׭B,Gg+__$]?Fw$=o1vq>bbl)Cœ^0+)v]w_j eAlLq4 z.%4統WA2g$U&q׿^}Q9G"DIj7YYA5}&n [&!gPV0X%::#.mm%$jĜǺ *JDPXO\uYX?lnb mJ{Buy|s X@kvf1gđױTt=DUu.Vyf=a͗VwÖ4F92/ir@ͬ28vHZ*w  4j!=-с/aV".sSS:c9ω3v!yEЖ0?BQB:.`۫=[:,μعyn@J1e= ]V0voBj#^_=]^BF0Ê'6bRƖ$UA<Ϗ92G[sŤ ;6Mޭ>)T؟_s^\ P Á@

^J]!djyd\*ܴP8-a{$߅quQ"4K$Ṳ%<@.6zy>f o\DaɅ2APO,aJnd쳈Ԕ*4E?xr\o~z߿jQhwt[HhH"Rx@V[;S3R,L ۸$.9)b=1hVg0DHOc 4ڂugYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 0  8o$$Eo@T^BhcnwA}papa aa 8g8gTiid uu z zz z{ {h h{ h{x} x}x `H8,d"PKҖ]<~~"ruby/json-2.6.1/json/ext/parser.sonuȯELF>0@w@8 @8]8] 0k0k 0k  kk k 888$$]]] Std]]] PtdYYYQtdRtd0k0k 0k GNU+2a2G_IIAF@ FIBE|ŷ|!qXf[ Ty4q&UD_U1 u #e"""uHE*`, OF":Vp ip Z I]p __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeruby_xfreerb_gc_mark_mayberuby_xrealloc2ruby_xmalloc2rb_check_typeddatarb_str_duprb_eTypeErrorrb_raiserb_funcallvrb_ary_entryrb_ary_push__stack_chk_failrb_data_typed_object_zallocruby_xmallocrb_error_arityrb_keyword_given_prb_string_valuerb_enc_getrb_ascii8bit_encodingrb_utf8_encodingrb_str_conv_encrb_hash_duprb_id2symrb_hash_arefrb_enc_associaterb_eArgErrorrb_debug_rstring_null_ptrrb_fix2intrb_unexpected_typerb_enc_interned_strmemcpyrb_utf8_str_newrb_str_internrb_enc_raiserb_ary_new_caparb_hash_foreachrb_freeze_singleton_classrb_class_new_instancerb_ary_newrb_hash_newrb_cstr2inumrb_respond_torb_str_new_cstrrb_hash_asetrb_cstr_to_dblrb_float_newrb_class_namestrrchrrb_str_substrrb_path_to_classrb_sym2idrb_mKernelInit_parserrb_ext_ractor_saferb_requirerb_define_modulerb_define_module_underrb_cObjectrb_define_class_underrb_path2classrb_gc_register_mark_objectrb_define_alloc_funcrb_internrb_const_getrb_define_methodlibruby.so.3.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.14GLIBC_2.4GLIBC_2.2.5/opt/alt/ruby31/lib64Lnii yui 0k 8k @k @k `k Nhk pk xk po o o o %o <o =o >o ?m m m m m m  n  n  n  n  n (n 0n 8n @n Hn Pn Xn `n hn pn xn n n n n n n n  n !n "n #n $n &n 'n (n )n *o +o ,o -o . o /(o 00o 18o 2@o 3Ho 4Po 5Xo 6`o 7ho 8po 9xo :o ;o ?o @o Ao Bo Co Do EHHY HtH5ZW %[W hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=%uS D%mS D%eS D%]S D%US D%MS D%ES D%=S D%5S D%-S D%%S D%S D%S D% S D%S D%R D%R D%R D%R D%R D%R D%R D%R D%R D%R D%R D%R D%R D%R D%R D%R D%}R D%uR D%mR D%eR D%]R D%UR D%MR D%ER D%=R D%5R D%-R D%%R D%R D%R D% R D%R D%Q D%Q D%Q D%Q D%Q D%Q D%Q D%Q D%Q D%Q D%Q D%Q D%Q D%Q D%Q DHf.DH=Q HQ H9tH^Q Ht H=yQ H5rQ H)HHH?HHtH5Q HtfD=5Q u+UH="Q Ht H=^L d Q ]wH f9Hx=WHx0HH WHxHH WHxHH øf.HGhH@Hpff.@USHHHohH}HtHHH[]ff.SHH?H{ H{@H{HH{PH{`[fATIUHSHtWHOIT$HH)H9v:HHHH)H9rH9vI|$HI\$ID$[]A\@H? I $ID$IL$ff.HH5J H8Ht H HN H5M,H81AUATUSHdH%(HD$1H4t&IH5O HI11LHu#1HL$dH3 %(uIH[]A\A]@1LVHHH5N H$HtLLqUHI pSH% Hh Hf@H@HHEhHH[]ff.@AVIAUIH5[I ATUHSH dH%(HD$1H8f.HHcMdIEHD$uHC(dH5 N 11CXH=AN dHC@HC HCHHCPLd$LHHII97:HIHLHHLHl$qHD$H  HPHhHSHHLHkHL$dH3 %(H []A\A]A^LIăIEHD$IH=L Hl$HLH5L IHD$@HC(dH=L qHLH5_L IHD$HC,H=XL 3HLH5!L IHD$HC4H=K HLH5K IHD$HC8H=K HLH5K IHD$HHCXH=K yHLH5gK IHD$ HVLLHC H=PK 3HLH5!K IHD$HHC@H= K HLH5J IHD$HiHCHH=J HLH5J IHD$FH HCPH=cJ vHLH5dJ IHD$HHC`fD@tbHHHHfHHhHS@H51J H=rJ 11HC HtHEHƒHtt{DLLmH;C(DLLEHC,"LL%HCH@LL HC@4@LLHC8NLLHC4LL1H‰SXS4IH@HVH H5_'H81DLLmHHDHC`DLLEHCPH=i%pHD$;.HC(HG H5%H81QUHAWAVIAUIATSH8UMdH%(HE1HH)HEH=HEHHHH%H)HHH9tHH$H9uHD$HHEL}M1M9wqDI9vWIA<$\I\$uM9vLL)IAD$M LH+]I\$Iw+DEĿHuHHE-Iv:IIE?HuMH)HLLA?HuĿHAȀDEňEA|$u I|$I\$ LI %HEHHI I LHuHELH ?ȀELH?ȀED?ȀEHLLLHuH ELA?HAȀ?DEƃȀEGH}w(HC 9M H"HH1H}dH}w(HC MH"HH1H}"AVAUIATUHSHHdH%(HD$1HwH9>"E1EXHm`HIuIH}H5HLLHAHCHt$dH34%(\H[]A\A]A^HL`L9H"tS\uL`L9Hu9LfEXA1tM0u1u81҅H{LUXIEL4@}41ɺIUH5A HHH$IEHpH9H@0 HpH9H@|0 weHpH9H@r0 wCL`L9@<@i0< LE1F~ayHF~a{DF~avfHA0HA"Hm`H:LAAWIAVIAUATUHSHXdH%(HD$H1H9tLHHMAfDLDHH9uIA @IAAW8tI>@uvHuuAugHt$HdH34%(LHX[]A\A]A^A_fLmL9E<*C Lm I1fDLmL9E1}nLmL9}fLmL9'}i}LmL9}nbLmL9}iGLmL9<}t,LmL9}yA,H= LmIMfLmL9E1}aLmL9}NAw,HL= LmIA@IWHƉ$AG(9H== 1H5LmL9 E1}a3LmL9C}lLmL9}sLmL96}eILm,LmL9c E1}uLmL9}lLmL92}l}ILm@LmL9+ E1}rKLmL9f}u0LmL9}eILmbAG(E`IW@HD$ A9H=; DH5'12fLHHLIHLDAG8I>A@IImH9AE<*t0@ MHD$(HD$HD$0HD$D$HL$HLHD$(L\IH IHHt$(I>Ht$0HL$H58 ID$HPH9t-H,tD t HHPH9uI LLjL9pJAfD fDIoH9;E<- <01I<w5IL9cA$Ht$0HL$0H5?5 L$HtXH5I5 H=5 Ld$0LL$HD$0H5x5 11HHL$H fIMLD HPH9<@<*tW0 THL$EHLHD$(`IH,I@Ht$ 'HD$HL$HD$(I>Ht$0H51 HD$8LD$I@L@L9P,tDw t {LL@L9u< t <fLIL9xB< t~<"n tHH9uHH9<*t*u OH/} y,@LBL9B<*tWLD$LD$L@L9@<*tF0@ wxE1HHHHHHD t w;HHXH9P t/uHXH9t@<*tlEt,,BDD V ABE =HX E 8FBA A(I@R (A ABBE $P$QEMD uDA@x\?FEL A(F0DPE 0A(A BBBA zRx P(4, AC DEJV C @$@BBE A(D0G@ 0A(A BBBD Hh BEE B(A0D8D 8A0A(B BBBJ (EHD0 AAE HGNU@k Np3BL @ M0k 8k o`   m ph oooo.ok p 0@P`p 0@P`p 0@P`p 0@GA$3a1@M GA$3p11130MGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYMGA+GLIBCXX_ASSERTIONSparser.so-3.1.7-8.el8.x86_64.debug9k7zXZִF!t/]?Eh=ڊ2N$.u!AʴmdV{cDa@3 lqzqj}o[[ne%%B -[lX>MqmDdD"F)X!Lc F}`i4Ϟ\oXI+W Z^zfVT7LVs Mkj/#%Nꉲѯ&cL6^!ELĢ#S%kZ~& 0@mj juPFh+^1UQK-tgA:iD~jiG>Ny pNhn>zIJkkt@≘ՍR9PM)`m}/K(c &pܣx}Ѻw+kFv%eGP&A K({[ݼq`7 =ElffWxOelt7TW7 5Dlwu29 镞,6nj:c3ZԼchb@BY~. oTKf_ IJ̕P930b]0,O͹1D/UQ9ЕlQj[IMlT&ZoΗl$}.lg0\tYׄ5>p`YG.Nr$,Bx_D~ӛ#\uE,w*[>U7q8D$pZBTD}T/˸3~2Nִ ..3(/ӏgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 0 8o..Eo@Th^Bpph@@c``nPPw00.}MM  M M` YYZZ]] 0k 0k8k 8k@k @kh k km mHp pp`pHHr(pr |v"PK ]zyB%specifications/ruby-lsapi-5.5.gemspecnu[# -*- encoding: utf-8 -*- # stub: ruby-lsapi 5.5 ruby lib # stub: ext/lsapi/extconf.rb Gem::Specification.new do |s| s.name = "ruby-lsapi".freeze s.version = "5.5" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["LiteSpeed Technologies Inc.".freeze] s.date = "2023-06-08" s.description = "This is a ruby extension for fast communication with LiteSpeed Web Server.".freeze s.email = "info@litespeedtech.com".freeze s.extensions = ["ext/lsapi/extconf.rb".freeze] s.extra_rdoc_files = ["README".freeze] s.files = ["README".freeze, "ext/lsapi/extconf.rb".freeze] s.homepage = "http://www.litespeedtech.com/".freeze s.rubygems_version = "3.1.6".freeze s.summary = "A ruby extension for fast communication with LiteSpeed Web Server.".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version end PK ]ׂii$specifications/openssl-2.1.4.gemspecnu[# -*- encoding: utf-8 -*- # stub: openssl 2.1.4 ruby lib # stub: ext/openssl/extconf.rb Gem::Specification.new do |s| s.name = "openssl".freeze s.version = "2.1.4" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "msys2_mingw_dependencies" => "openssl" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Martin Bosslet".freeze, "SHIBATA Hiroshi".freeze, "Zachary Scott".freeze, "Kazuki Yamaguchi".freeze] s.date = "2023-06-06" s.description = "It wraps the OpenSSL library.".freeze s.email = ["ruby-core@ruby-lang.org".freeze] s.extensions = ["ext/openssl/extconf.rb".freeze] s.extra_rdoc_files = ["CONTRIBUTING.md".freeze, "README.ja.md".freeze, "README.md".freeze] s.files = ["CONTRIBUTING.md".freeze, "README.ja.md".freeze, "README.md".freeze, "ext/openssl/extconf.rb".freeze, "openssl.rb".freeze, "openssl.so".freeze, "openssl/bn.rb".freeze, "openssl/buffering.rb".freeze, "openssl/cipher.rb".freeze, "openssl/config.rb".freeze, "openssl/digest.rb".freeze, "openssl/pkcs5.rb".freeze, "openssl/pkey.rb".freeze, "openssl/ssl.rb".freeze, "openssl/x509.rb".freeze] s.homepage = "https://github.com/ruby/openssl".freeze s.licenses = ["Ruby".freeze] s.rdoc_options = ["--main".freeze, "README.md".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "OpenSSL provides SSL, TLS and general purpose cryptography.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 11.2.0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["~> 3.0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 11.2.0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 3.0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]26>)specifications/power_assert-1.1.7.gemspecnu[# -*- encoding: utf-8 -*- # stub: power_assert 1.1.7 ruby lib Gem::Specification.new do |s| s.name = "power_assert".freeze s.version = "1.1.7" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kazuki Tsujimoto".freeze] s.bindir = "exe".freeze s.date = "2020-03-22" s.description = "Power Assert for Ruby. Power Assert shows each value of variables and method calls in the expression. It is useful for testing, providing which value wasn't correct when the condition is not satisfied.".freeze s.email = ["kazuki@callcc.net".freeze] s.extra_rdoc_files = ["README.rdoc".freeze] s.files = ["README.rdoc".freeze] s.homepage = "https://github.com/k-tsj/power_assert".freeze s.licenses = ["2-clause BSDL".freeze, "Ruby's".freeze] s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Power Assert for Ruby".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]lй%specifications/ruby-lsapi-5.6.gemspecnu[# -*- encoding: utf-8 -*- # stub: ruby-lsapi 5.6 ruby lib # stub: ext/lsapi/extconf.rb Gem::Specification.new do |s| s.name = "ruby-lsapi".freeze s.version = "5.6" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["LiteSpeed Technologies Inc.".freeze] s.date = "2024-01-22" s.description = "This is a ruby extension for fast communication with LiteSpeed Web Server.".freeze s.email = "info@litespeedtech.com".freeze s.extensions = ["ext/lsapi/extconf.rb".freeze] s.extra_rdoc_files = ["README".freeze] s.files = ["README".freeze, "ext/lsapi/extconf.rb".freeze] s.homepage = "http://www.litespeedtech.com/".freeze s.rubygems_version = "3.1.6".freeze s.summary = "A ruby extension for fast communication with LiteSpeed Web Server.".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version end PK ]&߻ "specifications/psych-3.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: psych 3.1.0 ruby lib # stub: ext/psych/extconf.rb Gem::Specification.new do |s| s.name = "psych".freeze s.version = "3.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Aaron Patterson".freeze, "SHIBATA Hiroshi".freeze, "Charles Oliver Nutter".freeze] s.date = "2023-06-06" s.description = "Psych is a YAML parser and emitter. Psych leverages libyaml[https://pyyaml.org/wiki/LibYAML]\nfor its YAML parsing and emitting capabilities. In addition to wrapping libyaml,\nPsych also knows how to serialize and de-serialize most Ruby objects to and from the YAML format.\n".freeze s.email = ["aaron@tenderlovemaking.com".freeze, "hsbt@ruby-lang.org".freeze, "headius@headius.com".freeze] s.extensions = ["ext/psych/extconf.rb".freeze] s.extra_rdoc_files = ["README.md".freeze] s.files = ["README.md".freeze, "ext/psych/extconf.rb".freeze, "psych.rb".freeze, "psych.so".freeze, "psych/class_loader.rb".freeze, "psych/coder.rb".freeze, "psych/core_ext.rb".freeze, "psych/exception.rb".freeze, "psych/handler.rb".freeze, "psych/handlers/document_stream.rb".freeze, "psych/handlers/recorder.rb".freeze, "psych/json/ruby_events.rb".freeze, "psych/json/stream.rb".freeze, "psych/json/tree_builder.rb".freeze, "psych/json/yaml_events.rb".freeze, "psych/nodes.rb".freeze, "psych/nodes/alias.rb".freeze, "psych/nodes/document.rb".freeze, "psych/nodes/mapping.rb".freeze, "psych/nodes/node.rb".freeze, "psych/nodes/scalar.rb".freeze, "psych/nodes/sequence.rb".freeze, "psych/nodes/stream.rb".freeze, "psych/omap.rb".freeze, "psych/parser.rb".freeze, "psych/scalar_scanner.rb".freeze, "psych/set.rb".freeze, "psych/stream.rb".freeze, "psych/streaming.rb".freeze, "psych/syntax_error.rb".freeze, "psych/tree_builder.rb".freeze, "psych/versions.rb".freeze, "psych/visitors.rb".freeze, "psych/visitors/depth_first.rb".freeze, "psych/visitors/emitter.rb".freeze, "psych/visitors/json_tree.rb".freeze, "psych/visitors/to_ruby.rb".freeze, "psych/visitors/visitor.rb".freeze, "psych/visitors/yaml_tree.rb".freeze, "psych/y.rb".freeze] s.homepage = "https://github.com/ruby/psych".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--main".freeze, "README.md".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.4.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Psych is a YAML parser and emitter".freeze end PK ]Ք!specifications/json-2.3.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: json 2.3.0 ruby lib Gem::Specification.new do |s| s.name = "json".freeze s.version = "2.3.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Florian Frank".freeze] s.date = "2019-12-11" s.description = "This is a JSON implementation as a Ruby extension in C.".freeze s.email = "flori@ping.de".freeze s.extensions = ["ext/json/ext/generator/extconf.rb".freeze, "ext/json/ext/parser/extconf.rb".freeze, "ext/json/extconf.rb".freeze] s.extra_rdoc_files = ["README.md".freeze] s.files = ["README.md".freeze, "ext/json/ext/generator/extconf.rb".freeze, "ext/json/ext/parser/extconf.rb".freeze, "ext/json/extconf.rb".freeze, "json.rb".freeze, "json/add/bigdecimal.rb".freeze, "json/add/complex.rb".freeze, "json/add/core.rb".freeze, "json/add/date.rb".freeze, "json/add/date_time.rb".freeze, "json/add/exception.rb".freeze, "json/add/ostruct.rb".freeze, "json/add/range.rb".freeze, "json/add/rational.rb".freeze, "json/add/regexp.rb".freeze, "json/add/set.rb".freeze, "json/add/struct.rb".freeze, "json/add/symbol.rb".freeze, "json/add/time.rb".freeze, "json/common.rb".freeze, "json/ext.rb".freeze, "json/ext/generator.so".freeze, "json/ext/parser.so".freeze, "json/generic_object.rb".freeze, "json/version.rb".freeze, "tests/test_helper.rb".freeze] s.homepage = "http://flori.github.com/json".freeze s.licenses = ["Ruby".freeze] s.rdoc_options = ["--title".freeze, "JSON implemention for Ruby".freeze, "--main".freeze, "README.md".freeze] s.required_ruby_version = Gem::Requirement.new(">= 1.9".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "JSON Implementation for Ruby".freeze s.test_files = ["tests/test_helper.rb".freeze] if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["~> 2.0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 2.0"]) end end PK ]ş߽#specifications/rdoc-6.2.1.1.gemspecnu[# -*- encoding: utf-8 -*- # stub: rdoc 6.2.1.1 ruby lib Gem::Specification.new do |s| s.name = "rdoc".freeze s.version = "6.2.1.1" s.required_rubygems_version = Gem::Requirement.new(">= 2.2".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Eric Hodel".freeze, "Dave Thomas".freeze, "Phil Hagelberg".freeze, "Tony Strauss".freeze, "Zachary Scott".freeze, "Hiroshi SHIBATA".freeze, "ITOYANAGI Sakura".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "RDoc produces HTML and command-line documentation for Ruby projects.\nRDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentation from the command-line.\n".freeze s.email = ["drbrain@segment7.net".freeze, "".freeze, "".freeze, "".freeze, "mail@zzak.io".freeze, "hsbt@ruby-lang.org".freeze, "aycabta@gmail.com".freeze] s.executables = ["rdoc".freeze, "ri".freeze] s.extra_rdoc_files = ["CVE-2013-0256.rdoc".freeze, "CONTRIBUTING.rdoc".freeze, "ExampleMarkdown.md".freeze, "ExampleRDoc.rdoc".freeze, "History.rdoc".freeze, "LEGAL.rdoc".freeze, "LICENSE.rdoc".freeze, "README.rdoc".freeze, "RI.rdoc".freeze, "TODO.rdoc".freeze] s.files = ["CONTRIBUTING.rdoc".freeze, "CVE-2013-0256.rdoc".freeze, "ExampleMarkdown.md".freeze, "ExampleRDoc.rdoc".freeze, "History.rdoc".freeze, "LEGAL.rdoc".freeze, "LICENSE.rdoc".freeze, "README.rdoc".freeze, "RI.rdoc".freeze, "TODO.rdoc".freeze, "exe/rdoc".freeze, "exe/ri".freeze, "rdoc.rb".freeze, "rdoc/alias.rb".freeze, "rdoc/anon_class.rb".freeze, "rdoc/any_method.rb".freeze, "rdoc/attr.rb".freeze, "rdoc/class_module.rb".freeze, "rdoc/code_object.rb".freeze, "rdoc/code_objects.rb".freeze, "rdoc/comment.rb".freeze, "rdoc/constant.rb".freeze, "rdoc/context.rb".freeze, "rdoc/context/section.rb".freeze, "rdoc/cross_reference.rb".freeze, "rdoc/encoding.rb".freeze, "rdoc/erb_partial.rb".freeze, "rdoc/erbio.rb".freeze, "rdoc/extend.rb".freeze, "rdoc/generator.rb".freeze, "rdoc/generator/darkfish.rb".freeze, "rdoc/generator/json_index.rb".freeze, "rdoc/generator/markup.rb".freeze, "rdoc/generator/pot.rb".freeze, "rdoc/generator/pot/message_extractor.rb".freeze, "rdoc/generator/pot/po.rb".freeze, "rdoc/generator/pot/po_entry.rb".freeze, "rdoc/generator/ri.rb".freeze, "rdoc/ghost_method.rb".freeze, "rdoc/i18n.rb".freeze, "rdoc/i18n/locale.rb".freeze, "rdoc/i18n/text.rb".freeze, "rdoc/include.rb".freeze, "rdoc/known_classes.rb".freeze, "rdoc/markdown.rb".freeze, "rdoc/markdown/entities.rb".freeze, "rdoc/markdown/literals.rb".freeze, "rdoc/markup.rb".freeze, "rdoc/markup/attr_changer.rb".freeze, "rdoc/markup/attr_span.rb".freeze, "rdoc/markup/attribute_manager.rb".freeze, "rdoc/markup/attributes.rb".freeze, "rdoc/markup/blank_line.rb".freeze, "rdoc/markup/block_quote.rb".freeze, "rdoc/markup/document.rb".freeze, "rdoc/markup/formatter.rb".freeze, "rdoc/markup/hard_break.rb".freeze, "rdoc/markup/heading.rb".freeze, "rdoc/markup/include.rb".freeze, "rdoc/markup/indented_paragraph.rb".freeze, "rdoc/markup/list.rb".freeze, "rdoc/markup/list_item.rb".freeze, "rdoc/markup/paragraph.rb".freeze, "rdoc/markup/parser.rb".freeze, "rdoc/markup/pre_process.rb".freeze, "rdoc/markup/raw.rb".freeze, "rdoc/markup/regexp_handling.rb".freeze, "rdoc/markup/rule.rb".freeze, "rdoc/markup/to_ansi.rb".freeze, "rdoc/markup/to_bs.rb".freeze, "rdoc/markup/to_html.rb".freeze, "rdoc/markup/to_html_crossref.rb".freeze, "rdoc/markup/to_html_snippet.rb".freeze, "rdoc/markup/to_joined_paragraph.rb".freeze, "rdoc/markup/to_label.rb".freeze, "rdoc/markup/to_markdown.rb".freeze, "rdoc/markup/to_rdoc.rb".freeze, "rdoc/markup/to_table_of_contents.rb".freeze, "rdoc/markup/to_test.rb".freeze, "rdoc/markup/to_tt_only.rb".freeze, "rdoc/markup/verbatim.rb".freeze, "rdoc/meta_method.rb".freeze, "rdoc/method_attr.rb".freeze, "rdoc/mixin.rb".freeze, "rdoc/normal_class.rb".freeze, "rdoc/normal_module.rb".freeze, "rdoc/options.rb".freeze, "rdoc/parser.rb".freeze, "rdoc/parser/c.rb".freeze, "rdoc/parser/changelog.rb".freeze, "rdoc/parser/markdown.rb".freeze, "rdoc/parser/rd.rb".freeze, "rdoc/parser/ripper_state_lex.rb".freeze, "rdoc/parser/ruby.rb".freeze, "rdoc/parser/ruby_tools.rb".freeze, "rdoc/parser/simple.rb".freeze, "rdoc/parser/text.rb".freeze, "rdoc/rd.rb".freeze, "rdoc/rd/block_parser.rb".freeze, "rdoc/rd/inline.rb".freeze, "rdoc/rd/inline_parser.rb".freeze, "rdoc/rdoc.rb".freeze, "rdoc/require.rb".freeze, "rdoc/ri.rb".freeze, "rdoc/ri/driver.rb".freeze, "rdoc/ri/formatter.rb".freeze, "rdoc/ri/paths.rb".freeze, "rdoc/ri/store.rb".freeze, "rdoc/ri/task.rb".freeze, "rdoc/rubygems_hook.rb".freeze, "rdoc/servlet.rb".freeze, "rdoc/single_class.rb".freeze, "rdoc/stats.rb".freeze, "rdoc/stats/normal.rb".freeze, "rdoc/stats/quiet.rb".freeze, "rdoc/stats/verbose.rb".freeze, "rdoc/store.rb".freeze, "rdoc/task.rb".freeze, "rdoc/text.rb".freeze, "rdoc/token_stream.rb".freeze, "rdoc/tom_doc.rb".freeze, "rdoc/top_level.rb".freeze, "rdoc/version.rb".freeze] s.homepage = "https://ruby.github.io/rdoc".freeze s.licenses = ["Ruby".freeze] s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.4.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "RDoc produces HTML and command-line documentation for Ruby projects".freeze end PK ]K'))%specifications/bundler-2.2.24.gemspecnu[# -*- encoding: utf-8 -*- # stub: bundler 2.2.24 ruby lib Gem::Specification.new do |s| s.name = "bundler".freeze s.version = "2.2.24" s.required_rubygems_version = Gem::Requirement.new(">= 2.5.2".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "bug_tracker_uri" => "https://github.com/rubygems/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler", "changelog_uri" => "https://github.com/rubygems/rubygems/blob/master/bundler/CHANGELOG.md", "homepage_uri" => "https://bundler.io/", "source_code_uri" => "https://github.com/rubygems/rubygems/" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Andr\u00E9 Arko".freeze, "Samuel Giddins".freeze, "Colby Swandale".freeze, "Hiroshi Shibata".freeze, "David Rodr\u00EDguez".freeze, "Grey Baker".freeze, "Stephanie Morillo".freeze, "Chris Morris".freeze, "James Wen".freeze, "Tim Moore".freeze, "Andr\u00E9 Medeiros".freeze, "Jessica Lynn Suttles".freeze, "Terence Lee".freeze, "Carl Lerche".freeze, "Yehuda Katz".freeze] s.bindir = "libexec".freeze s.date = "2023-06-06" s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably".freeze s.email = ["team@bundler.io".freeze] s.executables = ["bundle".freeze, "bundler".freeze] s.files = ["bundler.rb".freeze, "bundler/build_metadata.rb".freeze, "bundler/capistrano.rb".freeze, "bundler/cli.rb".freeze, "bundler/cli/add.rb".freeze, "bundler/cli/binstubs.rb".freeze, "bundler/cli/cache.rb".freeze, "bundler/cli/check.rb".freeze, "bundler/cli/clean.rb".freeze, "bundler/cli/common.rb".freeze, "bundler/cli/config.rb".freeze, "bundler/cli/console.rb".freeze, "bundler/cli/doctor.rb".freeze, "bundler/cli/exec.rb".freeze, "bundler/cli/fund.rb".freeze, "bundler/cli/gem.rb".freeze, "bundler/cli/info.rb".freeze, "bundler/cli/init.rb".freeze, "bundler/cli/inject.rb".freeze, "bundler/cli/install.rb".freeze, "bundler/cli/issue.rb".freeze, "bundler/cli/list.rb".freeze, "bundler/cli/lock.rb".freeze, "bundler/cli/open.rb".freeze, "bundler/cli/outdated.rb".freeze, "bundler/cli/platform.rb".freeze, "bundler/cli/plugin.rb".freeze, "bundler/cli/pristine.rb".freeze, "bundler/cli/remove.rb".freeze, "bundler/cli/show.rb".freeze, "bundler/cli/update.rb".freeze, "bundler/cli/viz.rb".freeze, "bundler/compact_index_client.rb".freeze, "bundler/compact_index_client/cache.rb".freeze, "bundler/compact_index_client/gem_parser.rb".freeze, "bundler/compact_index_client/updater.rb".freeze, "bundler/constants.rb".freeze, "bundler/current_ruby.rb".freeze, "bundler/definition.rb".freeze, "bundler/dep_proxy.rb".freeze, "bundler/dependency.rb".freeze, "bundler/deployment.rb".freeze, "bundler/deprecate.rb".freeze, "bundler/dsl.rb".freeze, "bundler/endpoint_specification.rb".freeze, "bundler/env.rb".freeze, "bundler/environment_preserver.rb".freeze, "bundler/errors.rb".freeze, "bundler/feature_flag.rb".freeze, "bundler/fetcher.rb".freeze, "bundler/fetcher/base.rb".freeze, "bundler/fetcher/compact_index.rb".freeze, "bundler/fetcher/dependency.rb".freeze, "bundler/fetcher/downloader.rb".freeze, "bundler/fetcher/index.rb".freeze, "bundler/friendly_errors.rb".freeze, "bundler/gem_helper.rb".freeze, "bundler/gem_helpers.rb".freeze, "bundler/gem_tasks.rb".freeze, "bundler/gem_version_promoter.rb".freeze, "bundler/gemdeps.rb".freeze, "bundler/graph.rb".freeze, "bundler/index.rb".freeze, "bundler/injector.rb".freeze, "bundler/inline.rb".freeze, "bundler/installer.rb".freeze, "bundler/installer/gem_installer.rb".freeze, "bundler/installer/parallel_installer.rb".freeze, "bundler/installer/standalone.rb".freeze, "bundler/lazy_specification.rb".freeze, "bundler/lockfile_generator.rb".freeze, "bundler/lockfile_parser.rb".freeze, "bundler/match_platform.rb".freeze, "bundler/mirror.rb".freeze, "bundler/plugin.rb".freeze, "bundler/plugin/api.rb".freeze, "bundler/plugin/api/source.rb".freeze, "bundler/plugin/dsl.rb".freeze, "bundler/plugin/events.rb".freeze, "bundler/plugin/index.rb".freeze, "bundler/plugin/installer.rb".freeze, "bundler/plugin/installer/git.rb".freeze, "bundler/plugin/installer/rubygems.rb".freeze, "bundler/plugin/source_list.rb".freeze, "bundler/process_lock.rb".freeze, "bundler/psyched_yaml.rb".freeze, "bundler/remote_specification.rb".freeze, "bundler/resolver.rb".freeze, "bundler/resolver/spec_group.rb".freeze, "bundler/retry.rb".freeze, "bundler/ruby_dsl.rb".freeze, "bundler/ruby_version.rb".freeze, "bundler/rubygems_ext.rb".freeze, "bundler/rubygems_gem_installer.rb".freeze, "bundler/rubygems_integration.rb".freeze, "bundler/runtime.rb".freeze, "bundler/settings.rb".freeze, "bundler/settings/validator.rb".freeze, "bundler/setup.rb".freeze, "bundler/shared_helpers.rb".freeze, "bundler/similarity_detector.rb".freeze, "bundler/source.rb".freeze, "bundler/source/gemspec.rb".freeze, "bundler/source/git.rb".freeze, "bundler/source/git/git_proxy.rb".freeze, "bundler/source/metadata.rb".freeze, "bundler/source/path.rb".freeze, "bundler/source/path/installer.rb".freeze, "bundler/source/rubygems.rb".freeze, "bundler/source/rubygems/remote.rb".freeze, "bundler/source/rubygems_aggregate.rb".freeze, "bundler/source_list.rb".freeze, "bundler/source_map.rb".freeze, "bundler/spec_set.rb".freeze, "bundler/stub_specification.rb".freeze, "bundler/templates/gems.rb".freeze, "bundler/ui.rb".freeze, "bundler/ui/rg_proxy.rb".freeze, "bundler/ui/shell.rb".freeze, "bundler/ui/silent.rb".freeze, "bundler/uri_credentials_filter.rb".freeze, "bundler/vendor/connection_pool/lib/connection_pool.rb".freeze, "bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rb".freeze, "bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb".freeze, "bundler/vendor/connection_pool/lib/connection_pool/version.rb".freeze, "bundler/vendor/fileutils/lib/fileutils.rb".freeze, "bundler/vendor/molinillo/lib/molinillo.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/errors.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/modules/ui.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/resolution.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/resolver.rb".freeze, "bundler/vendor/molinillo/lib/molinillo/state.rb".freeze, "bundler/vendor/net-http-persistent/lib/net/http/persistent.rb".freeze, "bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb".freeze, "bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb".freeze, "bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb".freeze, "bundler/vendor/thor/lib/thor.rb".freeze, "bundler/vendor/thor/lib/thor/actions.rb".freeze, "bundler/vendor/thor/lib/thor/actions/create_file.rb".freeze, "bundler/vendor/thor/lib/thor/actions/create_link.rb".freeze, "bundler/vendor/thor/lib/thor/actions/directory.rb".freeze, "bundler/vendor/thor/lib/thor/actions/empty_directory.rb".freeze, "bundler/vendor/thor/lib/thor/actions/file_manipulation.rb".freeze, "bundler/vendor/thor/lib/thor/actions/inject_into_file.rb".freeze, "bundler/vendor/thor/lib/thor/base.rb".freeze, "bundler/vendor/thor/lib/thor/command.rb".freeze, "bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb".freeze, "bundler/vendor/thor/lib/thor/error.rb".freeze, "bundler/vendor/thor/lib/thor/group.rb".freeze, "bundler/vendor/thor/lib/thor/invocation.rb".freeze, "bundler/vendor/thor/lib/thor/line_editor.rb".freeze, "bundler/vendor/thor/lib/thor/line_editor/basic.rb".freeze, "bundler/vendor/thor/lib/thor/line_editor/readline.rb".freeze, "bundler/vendor/thor/lib/thor/nested_context.rb".freeze, "bundler/vendor/thor/lib/thor/parser.rb".freeze, "bundler/vendor/thor/lib/thor/parser/argument.rb".freeze, "bundler/vendor/thor/lib/thor/parser/arguments.rb".freeze, "bundler/vendor/thor/lib/thor/parser/option.rb".freeze, "bundler/vendor/thor/lib/thor/parser/options.rb".freeze, "bundler/vendor/thor/lib/thor/rake_compat.rb".freeze, "bundler/vendor/thor/lib/thor/runner.rb".freeze, "bundler/vendor/thor/lib/thor/shell.rb".freeze, "bundler/vendor/thor/lib/thor/shell/basic.rb".freeze, "bundler/vendor/thor/lib/thor/shell/color.rb".freeze, "bundler/vendor/thor/lib/thor/shell/html.rb".freeze, "bundler/vendor/thor/lib/thor/util.rb".freeze, "bundler/vendor/thor/lib/thor/version.rb".freeze, "bundler/vendor/tmpdir/lib/tmpdir.rb".freeze, "bundler/vendor/uri/lib/uri.rb".freeze, "bundler/vendor/uri/lib/uri/common.rb".freeze, "bundler/vendor/uri/lib/uri/file.rb".freeze, "bundler/vendor/uri/lib/uri/ftp.rb".freeze, "bundler/vendor/uri/lib/uri/generic.rb".freeze, "bundler/vendor/uri/lib/uri/http.rb".freeze, "bundler/vendor/uri/lib/uri/https.rb".freeze, "bundler/vendor/uri/lib/uri/ldap.rb".freeze, "bundler/vendor/uri/lib/uri/ldaps.rb".freeze, "bundler/vendor/uri/lib/uri/mailto.rb".freeze, "bundler/vendor/uri/lib/uri/rfc2396_parser.rb".freeze, "bundler/vendor/uri/lib/uri/rfc3986_parser.rb".freeze, "bundler/vendor/uri/lib/uri/version.rb".freeze, "bundler/vendored_fileutils.rb".freeze, "bundler/vendored_molinillo.rb".freeze, "bundler/vendored_persistent.rb".freeze, "bundler/vendored_thor.rb".freeze, "bundler/vendored_tmpdir.rb".freeze, "bundler/vendored_uri.rb".freeze, "bundler/version.rb".freeze, "bundler/version_ranges.rb".freeze, "bundler/vlad.rb".freeze, "bundler/worker.rb".freeze, "bundler/yaml_serializer.rb".freeze, "libexec/bundle".freeze, "libexec/bundler".freeze] s.homepage = "https://bundler.io".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "The best way to manage your application's dependencies".freeze end PK ]rii#specifications/xmlrpc-0.3.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: xmlrpc 0.3.0 ruby lib Gem::Specification.new do |s| s.name = "xmlrpc".freeze s.version = "0.3.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["SHIBATA Hiroshi".freeze] s.bindir = "exe".freeze s.date = "2017-02-16" s.description = "XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP.".freeze s.email = ["hsbt@ruby-lang.org".freeze] s.homepage = "https://github.com/ruby/xmlrpc".freeze s.licenses = ["Ruby".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP.".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]]!'specifications/io-console-0.5.6.gemspecnu[# -*- encoding: utf-8 -*- # stub: io-console 0.5.6 ruby lib # stub: ext/io/console/extconf.rb Gem::Specification.new do |s| s.name = "io-console".freeze s.version = "0.5.6" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "source_code_url" => "https://github.com/ruby/io-console" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Nobu Nakada".freeze] s.date = "2023-06-06" s.description = "add console capabilities to IO instances.".freeze s.email = "nobu@ruby-lang.org".freeze s.extensions = ["ext/io/console/extconf.rb".freeze] s.files = ["ext/io/console/extconf.rb".freeze, "io/console.so".freeze, "io/console/size.rb".freeze] s.homepage = "https://github.com/ruby/io-console".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.4.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Console interface".freeze end PK ]WB&specifications/test-unit-3.3.4.gemspecnu[# -*- encoding: utf-8 -*- # stub: test-unit 3.3.4 ruby lib Gem::Specification.new do |s| s.name = "test-unit".freeze s.version = "3.3.4" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "source_code_uri" => "https://github.com/test-unit/test-unit" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Kouhei Sutou".freeze, "Haruka Yoshihara".freeze] s.date = "2019-09-29" s.description = "test-unit (Test::Unit) is unit testing framework for Ruby, based on xUnit\nprinciples. These were originally designed by Kent Beck, creator of extreme\nprogramming software development methodology, for Smalltalk's SUnit. It allows\nwriting tests, checking results and automated testing in Ruby.\n".freeze s.email = ["kou@cozmixng.org".freeze, "yoshihara@clear-code.com".freeze] s.homepage = "http://test-unit.github.io/".freeze s.licenses = ["Ruby".freeze, "PSFL".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "An xUnit family unit testing framework for Ruby.".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_runtime_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]v-#specifications/rackup-2.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: rackup 2.1.0 ruby lib Gem::Specification.new do |s| s.name = "rackup".freeze s.version = "2.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Samuel Williams".freeze, "Jeremy Evans".freeze] s.date = "2023-01-27" s.executables = ["rackup".freeze] s.files = ["bin/rackup".freeze] s.homepage = "https://github.com/rack/rackup".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.4.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "A general server command for Rack applications.".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_runtime_dependency(%q.freeze, [">= 3"]) s.add_runtime_dependency(%q.freeze, ["~> 1.8"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["~> 5.0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 3"]) s.add_dependency(%q.freeze, ["~> 1.8"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 5.0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]a'specifications/net-telnet-0.2.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: net-telnet 0.2.0 ruby lib Gem::Specification.new do |s| s.name = "net-telnet".freeze s.version = "0.2.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["SHIBATA Hiroshi".freeze] s.bindir = "exe".freeze s.date = "2018-07-25" s.description = "Provides telnet client functionality.".freeze s.email = ["hsbt@ruby-lang.org".freeze] s.homepage = "https://github.com/ruby/net-telnet".freeze s.licenses = ["ruby".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Provides telnet client functionality.".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]]K+specifications/default/matrix-0.2.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: matrix 0.2.0 ruby lib Gem::Specification.new do |s| s.name = "matrix".freeze s.version = "0.2.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Marc-Andre Lafortune".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "An implementation of Matrix and Vector classes.".freeze s.email = ["ruby-core@marc-andre.ca".freeze] s.files = ["matrix.rb".freeze, "matrix/eigenvalue_decomposition.rb".freeze, "matrix/lup_decomposition.rb".freeze, "matrix/version.rb".freeze] s.homepage = "https://github.com/ruby/matrix".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "An implementation of Matrix and Vector classes.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]Rn n (specifications/default/rss-0.2.8.gemspecnu[# -*- encoding: utf-8 -*- # stub: rss 0.2.8 ruby lib Gem::Specification.new do |s| s.name = "rss".freeze s.version = "0.2.8" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kouhei Sutou".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Family of libraries that support various formats of XML \"feeds\".".freeze s.email = ["kou@cozmixng.org".freeze] s.files = ["rss.rb".freeze, "rss/0.9.rb".freeze, "rss/1.0.rb".freeze, "rss/2.0.rb".freeze, "rss/atom.rb".freeze, "rss/content.rb".freeze, "rss/content/1.0.rb".freeze, "rss/content/2.0.rb".freeze, "rss/converter.rb".freeze, "rss/dublincore.rb".freeze, "rss/dublincore/1.0.rb".freeze, "rss/dublincore/2.0.rb".freeze, "rss/dublincore/atom.rb".freeze, "rss/image.rb".freeze, "rss/itunes.rb".freeze, "rss/maker.rb".freeze, "rss/maker/0.9.rb".freeze, "rss/maker/1.0.rb".freeze, "rss/maker/2.0.rb".freeze, "rss/maker/atom.rb".freeze, "rss/maker/base.rb".freeze, "rss/maker/content.rb".freeze, "rss/maker/dublincore.rb".freeze, "rss/maker/entry.rb".freeze, "rss/maker/feed.rb".freeze, "rss/maker/image.rb".freeze, "rss/maker/itunes.rb".freeze, "rss/maker/slash.rb".freeze, "rss/maker/syndication.rb".freeze, "rss/maker/taxonomy.rb".freeze, "rss/maker/trackback.rb".freeze, "rss/parser.rb".freeze, "rss/rexmlparser.rb".freeze, "rss/rss.rb".freeze, "rss/slash.rb".freeze, "rss/syndication.rb".freeze, "rss/taxonomy.rb".freeze, "rss/trackback.rb".freeze, "rss/utils.rb".freeze, "rss/version.rb".freeze, "rss/xml-stylesheet.rb".freeze, "rss/xml.rb".freeze, "rss/xmlparser.rb".freeze, "rss/xmlscanner.rb".freeze] s.homepage = "https://github.com/ruby/rss".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Family of libraries that support various formats of XML \"feeds\".".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]ʂ?ii-specifications/default/stringio-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: stringio 0.1.0 ruby lib # stub: ext/stringio/extconf.rb Gem::Specification.new do |s| s.name = "stringio".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 2.6".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Nobu Nakada".freeze] s.date = "2023-06-06" s.description = "Pseudo `IO` class from/to `String`.".freeze s.email = "nobu@ruby-lang.org".freeze s.extensions = ["ext/stringio/extconf.rb".freeze] s.files = ["ext/stringio/extconf.rb".freeze, "stringio.so".freeze] s.homepage = "https://github.com/ruby/stringio".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.5".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Pseudo IO on String".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) end end PK ]e..,specifications/default/strscan-1.0.3.gemspecnu[# -*- encoding: utf-8 -*- # stub: strscan 1.0.3 ruby lib # stub: ext/strscan/extconf.rb Gem::Specification.new do |s| s.name = "strscan".freeze s.version = "1.0.3" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Minero Aoki".freeze, "Sutou Kouhei".freeze] s.date = "2023-06-06" s.description = "Provides lexical scanning operations on a String.".freeze s.email = [nil, "kou@cozmixng.org".freeze] s.extensions = ["ext/strscan/extconf.rb".freeze] s.files = ["ext/strscan/extconf.rb".freeze, "strscan.so".freeze] s.homepage = "https://github.com/ruby/strscan".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.4.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Provides lexical scanning operations on a String.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]7}-specifications/default/observer-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: observer 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "observer".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/observer", "source_code_uri" => "https://github.com/ruby/observer" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Implementation of the Observer object-oriented design pattern.".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["observer.rb".freeze, "observer/version.rb".freeze] s.homepage = "https://github.com/ruby/observer".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Implementation of the Observer object-oriented design pattern.".freeze end PK ]+|00+specifications/default/ipaddr-1.2.2.gemspecnu[# -*- encoding: utf-8 -*- # stub: ipaddr 1.2.2 ruby lib Gem::Specification.new do |s| s.name = "ipaddr".freeze s.version = "1.2.2" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Akinori MUSHA".freeze, "Hajimu UMEMOTO".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "IPAddr provides a set of methods to manipulate an IP address.\nBoth IPv4 and IPv6 are supported.\n".freeze s.email = ["knu@idaemons.org".freeze, "ume@mahoroba.org".freeze] s.files = ["ipaddr.rb".freeze] s.homepage = "https://github.com/ruby/ipaddr".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "A class to manipulate an IP address in ruby".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, ["~> 1.15"]) s.add_development_dependency(%q.freeze, ["~> 10.0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, ["~> 1.15"]) s.add_dependency(%q.freeze, ["~> 10.0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]&kff*specifications/default/open3-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: open3 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "open3".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/open3", "source_code_uri" => "https://github.com/ruby/open3" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Popen, but with stderr, too".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["open3.rb".freeze, "open3/version.rb".freeze] s.homepage = "https://github.com/ruby/open3".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Popen, but with stderr, too".freeze end PK ]'ei*specifications/default/fcntl-1.0.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: fcntl 1.0.0 ruby lib # stub: ext/fcntl/extconf.rb Gem::Specification.new do |s| s.name = "fcntl".freeze s.version = "1.0.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Loads constants defined in the OS fcntl.h C header file".freeze s.email = ["matz@ruby-lang.org".freeze] s.extensions = ["ext/fcntl/extconf.rb".freeze] s.files = ["ext/fcntl/extconf.rb".freeze, "fcntl.so".freeze] s.homepage = "https://github.com/ruby/fcntl".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Loads constants defined in the OS fcntl.h C header file".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, ["~> 1.14"]) s.add_development_dependency(%q.freeze, ["~> 12"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, ["~> 1.14"]) s.add_dependency(%q.freeze, ["~> 12"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]N;oo+specifications/default/logger-1.4.2.gemspecnu[# -*- encoding: utf-8 -*- # stub: logger 1.4.2 ruby lib Gem::Specification.new do |s| s.name = "logger".freeze s.version = "1.4.2" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Naotoshi Seo".freeze, "SHIBATA Hiroshi".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Provides a simple logging utility for outputting messages.".freeze s.email = ["sonots@gmail.com".freeze, "hsbt@ruby-lang.org".freeze] s.files = ["logger.rb".freeze, "logger/errors.rb".freeze, "logger/formatter.rb".freeze, "logger/log_device.rb".freeze, "logger/period.rb".freeze, "logger/severity.rb".freeze, "logger/version.rb".freeze] s.homepage = "https://github.com/ruby/logger".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Provides a simple logging utility for outputting messages.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["~> 10.0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 10.0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ] /+specifications/default/pstore-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: pstore 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "pstore".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/pstore", "source_code_uri" => "https://github.com/ruby/pstore" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Transactional File Storage for Ruby Objects".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["pstore.rb".freeze, "pstore/version.rb".freeze] s.homepage = "https://github.com/ruby/pstore".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Transactional File Storage for Ruby Objects".freeze end PK ]8o-specifications/default/net-smtp-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: net-smtp 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "net-smtp".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/net-smtp", "source_code_uri" => "https://github.com/ruby/net-smtp" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Simple Mail Transfer Protocol client library for Ruby.".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["net/smtp.rb".freeze, "net/smtp/version.rb".freeze] s.homepage = "https://github.com/ruby/net-smtp".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Simple Mail Transfer Protocol client library for Ruby.".freeze end PK ]z..1specifications/default/readline-ext-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: readline-ext 0.1.0 ruby lib # stub: ext/readline/extconf.rb Gem::Specification.new do |s| s.name = "readline-ext".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/readline-ext", "source_code_uri" => "https://github.com/ruby/readline-ext" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Provides an interface for GNU Readline and Edit Line (libedit).".freeze s.email = ["matz@ruby-lang.org".freeze] s.extensions = ["ext/readline/extconf.rb".freeze] s.files = ["ext/readline/extconf.rb".freeze, "readline.so".freeze] s.homepage = "https://github.com/ruby/readline-ext".freeze s.licenses = ["Ruby".freeze, "BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Provides an interface for GNU Readline and Edit Line (libedit).".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]i>*specifications/default/cgi-0.1.0.2.gemspecnu[# -*- encoding: utf-8 -*- # stub: cgi 0.1.0.2 ruby lib Gem::Specification.new do |s| s.name = "cgi".freeze s.version = "0.1.0.2" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/cgi", "source_code_uri" => "https://github.com/ruby/cgi" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Support for the Common Gateway Interface protocol.".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["cgi.rb".freeze, "cgi/cookie.rb".freeze, "cgi/core.rb".freeze, "cgi/html.rb".freeze, "cgi/session.rb".freeze, "cgi/session/pstore.rb".freeze, "cgi/util.rb".freeze, "cgi/version.rb".freeze] s.homepage = "https://github.com/ruby/cgi".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Support for the Common Gateway Interface protocol.".freeze end PK ]D ,specifications/default/webrick-1.6.1.gemspecnu[# -*- encoding: utf-8 -*- # stub: webrick 1.6.1 ruby lib Gem::Specification.new do |s| s.name = "webrick".freeze s.version = "1.6.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "bug_tracker_uri" => "https://bugs.ruby-lang.org/projects/ruby-trunk/issues", "homepage_uri" => "https://www.ruby-lang.org", "source_code_uri" => "https://git.ruby-lang.org/ruby.git/" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["TAKAHASHI Masayoshi".freeze, "GOTOU YUUZOU".freeze, "Eric Wong".freeze] s.date = "2023-06-06" s.description = "WEBrick is an HTTP server toolkit that can be configured as an HTTPS server, a proxy server, and a virtual-host server.".freeze s.email = [nil, nil, "normal@ruby-lang.org".freeze] s.files = ["webrick.rb".freeze, "webrick/accesslog.rb".freeze, "webrick/cgi.rb".freeze, "webrick/compat.rb".freeze, "webrick/config.rb".freeze, "webrick/cookie.rb".freeze, "webrick/htmlutils.rb".freeze, "webrick/httpauth.rb".freeze, "webrick/httpauth/authenticator.rb".freeze, "webrick/httpauth/basicauth.rb".freeze, "webrick/httpauth/digestauth.rb".freeze, "webrick/httpauth/htdigest.rb".freeze, "webrick/httpauth/htgroup.rb".freeze, "webrick/httpauth/htpasswd.rb".freeze, "webrick/httpauth/userdb.rb".freeze, "webrick/httpproxy.rb".freeze, "webrick/httprequest.rb".freeze, "webrick/httpresponse.rb".freeze, "webrick/https.rb".freeze, "webrick/httpserver.rb".freeze, "webrick/httpservlet.rb".freeze, "webrick/httpservlet/abstract.rb".freeze, "webrick/httpservlet/cgi_runner.rb".freeze, "webrick/httpservlet/cgihandler.rb".freeze, "webrick/httpservlet/erbhandler.rb".freeze, "webrick/httpservlet/filehandler.rb".freeze, "webrick/httpservlet/prochandler.rb".freeze, "webrick/httpstatus.rb".freeze, "webrick/httputils.rb".freeze, "webrick/httpversion.rb".freeze, "webrick/log.rb".freeze, "webrick/server.rb".freeze, "webrick/ssl.rb".freeze, "webrick/utils.rb".freeze, "webrick/version.rb".freeze] s.homepage = "https://www.ruby-lang.org".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "HTTP server toolkit".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) end end PK ]KE9 9 ,specifications/default/rexml-3.2.3.1.gemspecnu[# -*- encoding: utf-8 -*- # stub: rexml 3.2.3.1 ruby lib Gem::Specification.new do |s| s.name = "rexml".freeze s.version = "3.2.3.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kouhei Sutou".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "An XML toolkit for Ruby".freeze s.email = ["kou@cozmixng.org".freeze] s.files = ["rexml/attlistdecl.rb".freeze, "rexml/attribute.rb".freeze, "rexml/cdata.rb".freeze, "rexml/child.rb".freeze, "rexml/comment.rb".freeze, "rexml/doctype.rb".freeze, "rexml/document.rb".freeze, "rexml/dtd/attlistdecl.rb".freeze, "rexml/dtd/dtd.rb".freeze, "rexml/dtd/elementdecl.rb".freeze, "rexml/dtd/entitydecl.rb".freeze, "rexml/dtd/notationdecl.rb".freeze, "rexml/element.rb".freeze, "rexml/encoding.rb".freeze, "rexml/entity.rb".freeze, "rexml/formatters/default.rb".freeze, "rexml/formatters/pretty.rb".freeze, "rexml/formatters/transitive.rb".freeze, "rexml/functions.rb".freeze, "rexml/instruction.rb".freeze, "rexml/light/node.rb".freeze, "rexml/namespace.rb".freeze, "rexml/node.rb".freeze, "rexml/output.rb".freeze, "rexml/parent.rb".freeze, "rexml/parseexception.rb".freeze, "rexml/parsers/baseparser.rb".freeze, "rexml/parsers/lightparser.rb".freeze, "rexml/parsers/pullparser.rb".freeze, "rexml/parsers/sax2parser.rb".freeze, "rexml/parsers/streamparser.rb".freeze, "rexml/parsers/treeparser.rb".freeze, "rexml/parsers/ultralightparser.rb".freeze, "rexml/parsers/xpathparser.rb".freeze, "rexml/quickpath.rb".freeze, "rexml/rexml.rb".freeze, "rexml/sax2listener.rb".freeze, "rexml/security.rb".freeze, "rexml/source.rb".freeze, "rexml/streamlistener.rb".freeze, "rexml/text.rb".freeze, "rexml/undefinednamespaceexception.rb".freeze, "rexml/validation/relaxng.rb".freeze, "rexml/validation/validation.rb".freeze, "rexml/validation/validationexception.rb".freeze, "rexml/xmldecl.rb".freeze, "rexml/xmltokens.rb".freeze, "rexml/xpath.rb".freeze, "rexml/xpath_parser.rb".freeze] s.homepage = "https://github.com/ruby/rexml".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "An XML toolkit for Ruby".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]0yy/specifications/default/getoptlong-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: getoptlong 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "getoptlong".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/getoptlong", "source_code_uri" => "https://github.com/ruby/getoptlong" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "GetoptLong for Ruby".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["getoptlong.rb".freeze, "getoptlong/version.rb".freeze] s.homepage = "https://github.com/ruby/getoptlong".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "GetoptLong for Ruby".freeze end PK ]2,specifications/default/ostruct-0.2.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: ostruct 0.2.0 ruby lib Gem::Specification.new do |s| s.name = "ostruct".freeze s.version = "0.2.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Marc-Andre Lafortune".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Class to build custom data structures, similar to a Hash.".freeze s.email = ["ruby-core@marc-andre.ca".freeze] s.files = ["ostruct.rb".freeze, "ostruct/version.rb".freeze] s.homepage = "https://github.com/ruby/ostruct".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Class to build custom data structures, similar to a Hash.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]V)specifications/default/zlib-1.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: zlib 1.1.0 ruby lib # stub: ext/zlib/extconf.rb Gem::Specification.new do |s| s.name = "zlib".freeze s.version = "1.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze, "UENO Katsuhiro".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Ruby interface for the zlib compression/decompression library".freeze s.email = ["matz@ruby-lang.org".freeze, nil] s.extensions = ["ext/zlib/extconf.rb".freeze] s.files = ["ext/zlib/extconf.rb".freeze, "zlib.so".freeze] s.homepage = "https://github.com/ruby/zlib".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Ruby interface for the zlib compression/decompression library".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]vTH,specifications/default/mutex_m-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: mutex_m 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "mutex_m".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Keiju ISHITSUKA".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Mixin to extend objects to be handled like a Mutex.".freeze s.email = ["keiju@ruby-lang.org".freeze] s.files = ["mutex_m.rb".freeze] s.homepage = "https://github.com/ruby/mutex_m".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Mixin to extend objects to be handled like a Mutex.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ].iAzz)specifications/default/date-3.0.3.gemspecnu[# -*- encoding: utf-8 -*- # stub: date 3.0.3 ruby lib # stub: ext/date/extconf.rb Gem::Specification.new do |s| s.name = "date".freeze s.version = "3.0.3" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Tadayoshi Funaba".freeze] s.date = "2023-06-06" s.description = "A subclass of Object includes Comparable module for handling dates.".freeze s.email = [nil] s.extensions = ["ext/date/extconf.rb".freeze] s.files = ["date.rb".freeze, "ext/date/extconf.rb".freeze] s.homepage = "https://github.com/ruby/date".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.4.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "A subclass of Object includes Comparable module for handling dates.".freeze end PK ],5{{+specifications/default/reline-0.1.5.gemspecnu[# -*- encoding: utf-8 -*- # stub: reline 0.1.5 ruby lib Gem::Specification.new do |s| s.name = "reline".freeze s.version = "0.1.5" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["aycabta".freeze] s.date = "2023-06-06" s.description = "Alternative GNU Readline or Editline implementation by pure Ruby.".freeze s.email = ["aycabta@gmail.com".freeze] s.files = ["reline.rb".freeze, "reline/ansi.rb".freeze, "reline/config.rb".freeze, "reline/general_io.rb".freeze, "reline/history.rb".freeze, "reline/key_actor.rb".freeze, "reline/key_actor/base.rb".freeze, "reline/key_actor/emacs.rb".freeze, "reline/key_actor/vi_command.rb".freeze, "reline/key_actor/vi_insert.rb".freeze, "reline/key_stroke.rb".freeze, "reline/kill_ring.rb".freeze, "reline/line_editor.rb".freeze, "reline/unicode.rb".freeze, "reline/unicode/east_asian_width.rb".freeze, "reline/version.rb".freeze, "reline/windows.rb".freeze] s.homepage = "https://github.com/ruby/reline".freeze s.licenses = ["Ruby".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.5".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Alternative GNU Readline or Editline implementation by pure Ruby.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_runtime_dependency(%q.freeze, ["~> 0.5"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, ["~> 0.5"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]@F1specifications/default/did_you_mean-1.4.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: did_you_mean 1.4.0 ruby lib Gem::Specification.new do |s| s.name = "did_you_mean".freeze s.version = "1.4.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Yuki Nishijima".freeze] s.date = "2023-06-06" s.description = "The gem that has been saving people from typos since 2014.".freeze s.email = ["mail@yukinishijima.net".freeze] s.files = ["did_you_mean.rb".freeze, "did_you_mean/core_ext/name_error.rb".freeze, "did_you_mean/experimental.rb".freeze, "did_you_mean/experimental/initializer_name_correction.rb".freeze, "did_you_mean/experimental/ivar_name_correction.rb".freeze, "did_you_mean/formatters/plain_formatter.rb".freeze, "did_you_mean/formatters/verbose_formatter.rb".freeze, "did_you_mean/jaro_winkler.rb".freeze, "did_you_mean/levenshtein.rb".freeze, "did_you_mean/spell_checker.rb".freeze, "did_you_mean/spell_checkers/key_error_checker.rb".freeze, "did_you_mean/spell_checkers/method_name_checker.rb".freeze, "did_you_mean/spell_checkers/name_error_checkers.rb".freeze, "did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb".freeze, "did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb".freeze, "did_you_mean/spell_checkers/null_checker.rb".freeze, "did_you_mean/tree_spell_checker.rb".freeze, "did_you_mean/verbose.rb".freeze, "did_you_mean/version.rb".freeze] s.homepage = "https://github.com/ruby/did_you_mean".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.5.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "\"Did you mean?\" experience in Ruby".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) end end PK ]9b_+specifications/default/fiddle-1.0.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: fiddle 1.0.0 ruby lib Gem::Specification.new do |s| s.name = "fiddle".freeze s.version = "1.0.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Aaron Patterson".freeze, "SHIBATA Hiroshi".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "A libffi wrapper for Ruby.".freeze s.email = ["aaron@tenderlovemaking.com".freeze, "hsbt@ruby-lang.org".freeze] s.files = ["fiddle.rb".freeze, "fiddle.so".freeze, "fiddle/closure.rb".freeze, "fiddle/cparser.rb".freeze, "fiddle/function.rb".freeze, "fiddle/import.rb".freeze, "fiddle/pack.rb".freeze, "fiddle/struct.rb".freeze, "fiddle/types.rb".freeze, "fiddle/value.rb".freeze] s.homepage = "https://github.com/ruby/fiddle".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "A libffi wrapper for Ruby.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]N+specifications/default/uri-0.10.0.2.gemspecnu[# -*- encoding: utf-8 -*- # stub: uri 0.10.0.2 ruby lib Gem::Specification.new do |s| s.name = "uri".freeze s.version = "0.10.0.2" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/uri", "source_code_uri" => "https://github.com/ruby/uri" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Akira Yamada".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "URI is a module providing classes to handle Uniform Resource Identifiers".freeze s.email = ["akira@ruby-lang.org".freeze] s.files = ["uri.rb".freeze, "uri/common.rb".freeze, "uri/file.rb".freeze, "uri/ftp.rb".freeze, "uri/generic.rb".freeze, "uri/http.rb".freeze, "uri/https.rb".freeze, "uri/ldap.rb".freeze, "uri/ldaps.rb".freeze, "uri/mailto.rb".freeze, "uri/rfc2396_parser.rb".freeze, "uri/rfc3986_parser.rb".freeze, "uri/version.rb".freeze] s.homepage = "https://github.com/ruby/uri".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "URI is a module providing classes to handle Uniform Resource Identifiers".freeze end PK ]C-specifications/default/delegate-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: delegate 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "delegate".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/delegate", "source_code_uri" => "https://github.com/ruby/delegate" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Provides three abilities to delegate method calls to an object.".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["delegate.rb".freeze, "delegate/version.rb".freeze] s.homepage = "https://github.com/ruby/delegate".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Provides three abilities to delegate method calls to an object.".freeze end PK ]nSS0specifications/default/forwardable-1.3.1.gemspecnu[# -*- encoding: utf-8 -*- # stub: forwardable 1.3.1 ruby lib Gem::Specification.new do |s| s.name = "forwardable".freeze s.version = "1.3.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Keiju ISHITSUKA".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Provides delegation of specified methods to a designated object.".freeze s.email = ["keiju@ruby-lang.org".freeze] s.files = ["forwardable.rb".freeze, "forwardable/impl.rb".freeze, "forwardable/version.rb".freeze] s.homepage = "https://github.com/ruby/forwardable".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Provides delegation of specified methods to a designated object.".freeze end PK ])specifications/default/yaml-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: yaml 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "yaml".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/yaml", "source_code_uri" => "https://github.com/ruby/yaml" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Aaron Patterson".freeze, "SHIBATA Hiroshi".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "YAML Ain't Markup Language".freeze s.email = ["aaron@tenderlovemaking.com".freeze, "hsbt@ruby-lang.org".freeze] s.files = ["yaml.rb".freeze, "yaml/dbm.rb".freeze, "yaml/store.rb".freeze] s.homepage = "https://github.com/ruby/yaml".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "YAML Ain't Markup Language".freeze end PK ]^\^^)specifications/default/gdbm-2.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: gdbm 2.1.0 ruby lib # stub: ext/gdbm/extconf.rb Gem::Specification.new do |s| s.name = "gdbm".freeze s.version = "2.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Ruby extension for GNU dbm.".freeze s.email = ["matz@ruby-lang.org".freeze] s.extensions = ["ext/gdbm/extconf.rb".freeze] s.files = ["ext/gdbm/extconf.rb".freeze, "gdbm.so".freeze] s.homepage = "https://github.com/ruby/gdbm".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Ruby extension for GNU dbm.".freeze end PK ]xx,specifications/default/net-pop-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: net-pop 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "net-pop".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/net-pop", "source_code_uri" => "https://github.com/ruby/net-pop" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Ruby client library for POP3.".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["net/pop.rb".freeze, "net/pop/version.rb".freeze] s.homepage = "https://github.com/ruby/net-pop".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Ruby client library for POP3.".freeze end PK ]~V6*specifications/default/prime-0.1.1.gemspecnu[# -*- encoding: utf-8 -*- # stub: prime 0.1.1 ruby lib Gem::Specification.new do |s| s.name = "prime".freeze s.version = "0.1.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Yuki Sonoda".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Prime numbers and factorization library.".freeze s.email = ["yugui@yugui.jp".freeze] s.files = ["prime.rb".freeze] s.homepage = "https://github.com/ruby/prime".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Prime numbers and factorization library.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]+Q.specifications/default/singleton-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: singleton 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "singleton".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/singleton", "source_code_uri" => "https://github.com/ruby/singleton" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "The Singleton module implements the Singleton pattern.".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["singleton.rb".freeze, "singleton/version.rb".freeze] s.homepage = "https://github.com/ruby/singleton".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "The Singleton module implements the Singleton pattern.".freeze end PK ]'1O;.specifications/default/fileutils-1.4.1.gemspecnu[# -*- encoding: utf-8 -*- # stub: fileutils 1.4.1 ruby lib Gem::Specification.new do |s| s.name = "fileutils".freeze s.version = "1.4.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "source_code_uri" => "https://github.com/ruby/fileutils" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Minero Aoki".freeze] s.date = "2023-06-06" s.description = "Several file utility methods for copying, moving, removing, etc.".freeze s.email = [nil] s.files = ["fileutils.rb".freeze] s.homepage = "https://github.com/ruby/fileutils".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Several file utility methods for copying, moving, removing, etc.".freeze end PK ] -specifications/default/readline-0.0.2.gemspecnu[# -*- encoding: utf-8 -*- # stub: readline 0.0.2 ruby lib Gem::Specification.new do |s| s.name = "readline".freeze s.version = "0.0.2" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["aycabta".freeze] s.date = "2023-06-06" s.description = "This is just a loader for \"readline\". If Ruby has \"readline-ext\" gem that\nis a native extension, this gem will load it first. If Ruby doesn't have\nthe \"readline-ext\" gem this gem will load \"reline\" that is a compatible\nlibrary with \"readline-ext\" gem and is implemented by pure Ruby.\n".freeze s.email = ["aycabta@gmail.com".freeze] s.files = ["readline.rb".freeze] s.homepage = "https://github.com/ruby/readline".freeze s.licenses = ["Ruby license".freeze] s.post_install_message = "+---------------------------------------------------------------------------+\n| This is just a loader for \"readline\". If Ruby has \"readline-ext\" gem that |\n| is a native extension, this gem will load it first. If Ruby doesn't have |\n| the \"readline-ext\" gem this gem will load \"reline\" that is a compatible \u00A0 |\n| library with \"readline-ext\" gem and is implemented by pure Ruby. \u00A0 \u00A0 \u00A0 \u00A0 \u00A0|\n| \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 |\n| If you intend to use GNU Readline by `require 'readline'`, please install |\n| \"readline-ext\" gem. \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 |\n+---------------------------------------------------------------------------+\n".freeze s.rubygems_version = "3.1.6".freeze s.summary = "It's a loader for \"readline\".".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_runtime_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]E(specifications/default/etc-1.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: etc 1.1.0 ruby lib # stub: ext/etc/extconf.rb Gem::Specification.new do |s| s.name = "etc".freeze s.version = "1.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Provides access to information typically stored in UNIX /etc directory.".freeze s.email = ["matz@ruby-lang.org".freeze] s.extensions = ["ext/etc/extconf.rb".freeze] s.files = ["etc.so".freeze, "ext/etc/extconf.rb".freeze] s.homepage = "https://github.com/ruby/etc".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Provides access to information typically stored in UNIX /etc directory.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]N(specifications/default/csv-3.1.2.gemspecnu[# -*- encoding: utf-8 -*- # stub: csv 3.1.2 ruby lib Gem::Specification.new do |s| s.name = "csv".freeze s.version = "3.1.2" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["James Edward Gray II".freeze, "Kouhei Sutou".freeze] s.date = "2023-06-06" s.description = "The CSV library provides a complete interface to CSV files and data. It offers tools to enable you to read and write to and from Strings or IO objects, as needed.".freeze s.email = [nil, "kou@cozmixng.org".freeze] s.files = ["csv.rb".freeze, "csv/core_ext/array.rb".freeze, "csv/core_ext/string.rb".freeze, "csv/delete_suffix.rb".freeze, "csv/fields_converter.rb".freeze, "csv/match_p.rb".freeze, "csv/parser.rb".freeze, "csv/row.rb".freeze, "csv/table.rb".freeze, "csv/version.rb".freeze, "csv/writer.rb".freeze] s.homepage = "https://github.com/ruby/csv".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "CSV Reading and Writing".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]V.specifications/default/benchmark-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: benchmark 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "benchmark".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/benchmark", "source_code_uri" => "https://github.com/ruby/benchmark" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "a performance benchmarking library".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["benchmark.rb".freeze, "benchmark/version.rb".freeze] s.homepage = "https://github.com/ruby/benchmark".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "a performance benchmarking library".freeze end PK ]+specifications/default/tracer-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: tracer 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "tracer".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Keiju ISHITSUKA".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Outputs a source level execution trace of a Ruby program.".freeze s.email = ["keiju@ruby-lang.org".freeze] s.files = ["tracer.rb".freeze, "tracer/version.rb".freeze] s.homepage = "https://github.com/ruby/tracer".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Outputs a source level execution trace of a Ruby program.".freeze end PK ]248 8 *specifications/default/racc-1.4.16.gemspecnu[# -*- encoding: utf-8 -*- # stub: racc 1.4.16 ruby lib # stub: ext/racc/extconf.rb Gem::Specification.new do |s| s.name = "racc".freeze s.version = "1.4.16" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Minero Aoki".freeze, "Aaron Patterson".freeze] s.date = "2023-06-06" s.description = "Racc is a LALR(1) parser generator.\n It is written in Ruby itself, and generates Ruby program.\n\n NOTE: Ruby 1.8.x comes with Racc runtime module. You\n can run your parsers generated by racc 1.4.x out of the\n box.\n".freeze s.email = [nil, "aaron@tenderlovemaking.com".freeze] s.executables = ["racc".freeze, "racc2y".freeze, "y2racc".freeze] s.extensions = ["ext/racc/extconf.rb".freeze] s.extra_rdoc_files = ["Manifest.txt".freeze, "README.ja.rdoc".freeze, "README.rdoc".freeze, "rdoc/en/NEWS.en.rdoc".freeze, "rdoc/en/grammar.en.rdoc".freeze, "rdoc/ja/NEWS.ja.rdoc".freeze, "rdoc/ja/debug.ja.rdoc".freeze, "rdoc/ja/grammar.ja.rdoc".freeze, "rdoc/ja/parser.ja.rdoc".freeze, "README.ja.rdoc".freeze, "README.rdoc".freeze] s.files = ["Manifest.txt".freeze, "README.ja.rdoc".freeze, "README.rdoc".freeze, "bin/racc".freeze, "bin/racc2y".freeze, "bin/y2racc".freeze, "ext/racc/extconf.rb".freeze, "racc.rb".freeze, "racc/compat.rb".freeze, "racc/debugflags.rb".freeze, "racc/exception.rb".freeze, "racc/grammar.rb".freeze, "racc/grammarfileparser.rb".freeze, "racc/info.rb".freeze, "racc/iset.rb".freeze, "racc/logfilegenerator.rb".freeze, "racc/parser-text.rb".freeze, "racc/parser.rb".freeze, "racc/parserfilegenerator.rb".freeze, "racc/sourcetext.rb".freeze, "racc/state.rb".freeze, "racc/statetransitiontable.rb".freeze, "racc/static.rb".freeze, "rdoc/en/NEWS.en.rdoc".freeze, "rdoc/en/grammar.en.rdoc".freeze, "rdoc/ja/NEWS.ja.rdoc".freeze, "rdoc/ja/debug.ja.rdoc".freeze, "rdoc/ja/grammar.ja.rdoc".freeze, "rdoc/ja/parser.ja.rdoc".freeze] s.homepage = "http://i.loveruby.net/en/projects/racc/".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Racc is a LALR(1) parser generator".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0.4.1"]) s.add_development_dependency(%q.freeze, ["~> 4.7"]) s.add_development_dependency(%q.freeze, [">= 4.0", "< 7"]) s.add_development_dependency(%q.freeze, ["~> 3.18"]) else s.add_dependency(%q.freeze, [">= 0.4.1"]) s.add_dependency(%q.freeze, ["~> 4.7"]) s.add_dependency(%q.freeze, [">= 4.0", "< 7"]) s.add_dependency(%q.freeze, ["~> 3.18"]) end end PK ]R  (specifications/default/dbm-1.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: dbm 1.1.0 ruby lib # stub: ext/dbm/extconf.rb Gem::Specification.new do |s| s.name = "dbm".freeze s.version = "1.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.date = "2023-06-06" s.description = "Provides a wrapper for the UNIX-style Database Manager Library".freeze s.email = ["matz@ruby-lang.org".freeze] s.extensions = ["ext/dbm/extconf.rb".freeze] s.files = ["dbm.so".freeze, "ext/dbm/extconf.rb".freeze] s.homepage = "https://github.com/ruby/dbm".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Provides a wrapper for the UNIX-style Database Manager Library".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]Y(()specifications/default/sdbm-1.0.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: sdbm 1.0.0 ruby lib # stub: ext/sdbm/extconf.rb Gem::Specification.new do |s| s.name = "sdbm".freeze s.version = "1.0.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.date = "2023-06-06" s.description = "Provides a simple file-based key-value store with String keys and values.".freeze s.email = ["matz@ruby-lang.org".freeze] s.extensions = ["ext/sdbm/extconf.rb".freeze] s.files = ["ext/sdbm/extconf.rb".freeze, "sdbm.so".freeze] s.homepage = "https://github.com/ruby/sdbm".freeze s.licenses = ["BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Provides a simple file-based key-value store with String keys and values.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]~,specifications/default/timeout-0.1.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: timeout 0.1.0 ruby lib Gem::Specification.new do |s| s.name = "timeout".freeze s.version = "0.1.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "https://github.com/ruby/timeout", "source_code_uri" => "https://github.com/ruby/timeout" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Yukihiro Matsumoto".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Auto-terminate potentially long-running operations in Ruby.".freeze s.email = ["matz@ruby-lang.org".freeze] s.files = ["timeout.rb".freeze, "timeout/version.rb".freeze] s.homepage = "https://github.com/ruby/timeout".freeze s.licenses = ["BSD-2-Clause".freeze] s.rubygems_version = "3.1.6".freeze s.summary = "Auto-terminate potentially long-running operations in Ruby.".freeze end PK ]43g:\\"specifications/rake-13.0.1.gemspecnu[# -*- encoding: utf-8 -*- # stub: rake 13.0.1 ruby lib Gem::Specification.new do |s| s.name = "rake".freeze s.version = "13.0.1" s.required_rubygems_version = Gem::Requirement.new(">= 1.3.2".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "bug_tracker_uri" => "https://github.com/ruby/rake/issues", "changelog_uri" => "https://github.com/ruby/rake/blob/v13.0.1/History.rdoc", "documentation_uri" => "https://ruby.github.io/rake", "source_code_uri" => "https://github.com/ruby/rake/tree/v13.0.1" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Hiroshi SHIBATA".freeze, "Eric Hodel".freeze, "Jim Weirich".freeze] s.bindir = "exe".freeze s.date = "2019-11-12" s.description = "Rake is a Make-like program implemented in Ruby. Tasks and dependencies are\nspecified in standard Ruby syntax.\nRake has the following features:\n * Rakefiles (rake's version of Makefiles) are completely defined in standard Ruby syntax.\n No XML files to edit. No quirky Makefile syntax to worry about (is that a tab or a space?)\n * Users can specify tasks with prerequisites.\n * Rake supports rule patterns to synthesize implicit tasks.\n * Flexible FileLists that act like arrays but know about manipulating file names and paths.\n * Supports parallel execution of tasks.\n".freeze s.email = ["hsbt@ruby-lang.org".freeze, "drbrain@segment7.net".freeze, "".freeze] s.executables = ["rake".freeze] s.files = ["exe/rake".freeze] s.homepage = "https://github.com/ruby/rake".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.2".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Rake is a Make-like program implemented in Ruby".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version end PK ]lzz!specifications/rack-3.0.8.gemspecnu[# -*- encoding: utf-8 -*- # stub: rack 3.0.8 ruby lib Gem::Specification.new do |s| s.name = "rack".freeze s.version = "3.0.8" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "bug_tracker_uri" => "https://github.com/rack/rack/issues", "changelog_uri" => "https://github.com/rack/rack/blob/main/CHANGELOG.md", "documentation_uri" => "https://rubydoc.info/github/rack/rack", "source_code_uri" => "https://github.com/rack/rack" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Leah Neukirchen".freeze] s.date = "2023-06-14" s.description = "Rack provides a minimal, modular and adaptable interface for developing\nweb applications in Ruby. By wrapping HTTP requests and responses in\nthe simplest way possible, it unifies and distills the API for web\nservers, web frameworks, and software in between (the so-called\nmiddleware) into a single method call.\n".freeze s.email = "leah@vuxu.org".freeze s.extra_rdoc_files = ["README.md".freeze, "CHANGELOG.md".freeze, "CONTRIBUTING.md".freeze] s.files = ["CHANGELOG.md".freeze, "CONTRIBUTING.md".freeze, "README.md".freeze] s.homepage = "https://github.com/rack/rack".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.4.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "A modular Ruby webserver interface.".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, ["~> 5.0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, ["~> 5.0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ] 'specifications/bigdecimal-2.0.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: bigdecimal 2.0.0 ruby lib # stub: ext/bigdecimal/extconf.rb Gem::Specification.new do |s| s.name = "bigdecimal".freeze s.version = "2.0.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kenta Murata".freeze, "Zachary Scott".freeze, "Shigeo Kobayashi".freeze] s.date = "2023-06-06" s.description = "This library provides arbitrary-precision decimal floating-point number class.".freeze s.email = ["mrkn@mrkn.jp".freeze] s.extensions = ["ext/bigdecimal/extconf.rb".freeze] s.files = ["bigdecimal.rb".freeze, "bigdecimal.so".freeze, "bigdecimal/jacobian.rb".freeze, "bigdecimal/ludcmp.rb".freeze, "bigdecimal/math.rb".freeze, "bigdecimal/newton.rb".freeze, "bigdecimal/util.rb".freeze, "ext/bigdecimal/extconf.rb".freeze] s.homepage = "https://github.com/ruby/bigdecimal".freeze s.licenses = ["ruby".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Arbitrary-precision decimal floating-point number library.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, ["~> 10.0"]) s.add_development_dependency(%q.freeze, [">= 0.9"]) s.add_development_dependency(%q.freeze, ["< 5.0.0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, ["~> 10.0"]) s.add_dependency(%q.freeze, [">= 0.9"]) s.add_dependency(%q.freeze, ["< 5.0.0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ] څ&specifications/minitest-5.13.0.gemspecnu[# -*- encoding: utf-8 -*- # stub: minitest 5.13.0 ruby lib Gem::Specification.new do |s| s.name = "minitest".freeze s.version = "5.13.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Ryan Davis".freeze] s.cert_chain = ["-----BEGIN CERTIFICATE-----\nMIIDPjCCAiagAwIBAgIBAzANBgkqhkiG9w0BAQsFADBFMRMwEQYDVQQDDApyeWFu\nZC1ydWJ5MRkwFwYKCZImiZPyLGQBGRYJemVuc3BpZGVyMRMwEQYKCZImiZPyLGQB\nGRYDY29tMB4XDTE4MTIwNDIxMzAxNFoXDTE5MTIwNDIxMzAxNFowRTETMBEGA1UE\nAwwKcnlhbmQtcnVieTEZMBcGCgmSJomT8ixkARkWCXplbnNwaWRlcjETMBEGCgmS\nJomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALda\nb9DCgK+627gPJkB6XfjZ1itoOQvpqH1EXScSaba9/S2VF22VYQbXU1xQXL/WzCkx\ntaCPaLmfYIaFcHHCSY4hYDJijRQkLxPeB3xbOfzfLoBDbjvx5JxgJxUjmGa7xhcT\noOvjtt5P8+GSK9zLzxQP0gVLS/D0FmoE44XuDr3iQkVS2ujU5zZL84mMNqNB1znh\nGiadM9GHRaDiaxuX0cIUBj19T01mVE2iymf9I6bEsiayK/n6QujtyCbTWsAS9Rqt\nqhtV7HJxNKuPj/JFH0D2cswvzznE/a5FOYO68g+YCuFi5L8wZuuM8zzdwjrWHqSV\ngBEfoTEGr7Zii72cx+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw\nHQYDVR0OBBYEFEfFe9md/r/tj/Wmwpy+MI8d9k/hMA0GCSqGSIb3DQEBCwUAA4IB\nAQCbJwLmpJR2PomLU+Zzw3KRzH/hbyUWc/ftru71AopZ1fy4iY9J/BW5QYKVYwbP\nV0FSBWtvfI/RdwfKGtuGhPKECZgmLieGuZ3XCc09qPu1bdg7i/tu1p0t0c6163ku\nnDMDIC/t/DAFK0TY9I3HswuyZGbLW7rgF0DmiuZdN/RPhHq2pOLMLXJmFclCb/im\n9yToml/06TJdUJ5p64mkBs0TzaK66DIB1Smd3PdtfZqoRV+EwaXMdx0Hb3zdR1JR\nEm82dBUFsipwMLCYj39kcyHWAxyl6Ae1Cn9r/ItVBCxoeFdrHjfavnrIEoXUt4bU\nUfBugfLD19bu3nvL+zTAGx/U\n-----END CERTIFICATE-----\n".freeze] s.date = "2019-10-30" s.description = "minitest provides a complete suite of testing facilities supporting\nTDD, BDD, mocking, and benchmarking.\n\n \"I had a class with Jim Weirich on testing last week and we were\n allowed to choose our testing frameworks. Kirk Haines and I were\n paired up and we cracked open the code for a few test\n frameworks...\n\n I MUST say that minitest is *very* readable / understandable\n compared to the 'other two' options we looked at. Nicely done and\n thank you for helping us keep our mental sanity.\"\n\n -- Wayne E. Seguin\n\nminitest/test is a small and incredibly fast unit testing framework.\nIt provides a rich set of assertions to make your tests clean and\nreadable.\n\nminitest/spec is a functionally complete spec engine. It hooks onto\nminitest/test and seamlessly bridges test assertions over to spec\nexpectations.\n\nminitest/benchmark is an awesome way to assert the performance of your\nalgorithms in a repeatable manner. Now you can assert that your newb\nco-worker doesn't replace your linear algorithm with an exponential\none!\n\nminitest/mock by Steven Baker, is a beautifully tiny mock (and stub)\nobject framework.\n\nminitest/pride shows pride in testing and adds coloring to your test\noutput. I guess it is an example of how to write IO pipes too. :P\n\nminitest/test is meant to have a clean implementation for language\nimplementors that need a minimal set of methods to bootstrap a working\ntest suite. For example, there is no magic involved for test-case\ndiscovery.\n\n \"Again, I can't praise enough the idea of a testing/specing\n framework that I can actually read in full in one sitting!\"\n\n -- Piotr Szotkowski\n\nComparing to rspec:\n\n rspec is a testing DSL. minitest is ruby.\n\n -- Adam Hawkins, \"Bow Before MiniTest\"\n\nminitest doesn't reinvent anything that ruby already provides, like:\nclasses, modules, inheritance, methods. This means you only have to\nlearn ruby to use minitest and all of your regular OO practices like\nextract-method refactorings still apply.".freeze s.email = ["ryand-ruby@zenspider.com".freeze] s.extra_rdoc_files = ["History.rdoc".freeze, "Manifest.txt".freeze, "README.rdoc".freeze] s.files = ["History.rdoc".freeze, "Manifest.txt".freeze, "README.rdoc".freeze] s.homepage = "https://github.com/seattlerb/minitest".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] s.required_ruby_version = Gem::Requirement.new("~> 2.2".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "minitest provides a complete suite of testing facilities supporting TDD, BDD, mocking, and benchmarking".freeze s.installed_by_version = "3.1.6" if s.respond_to? :installed_by_version if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 4.0", "< 7"]) s.add_development_dependency(%q.freeze, ["~> 3.18"]) else s.add_dependency(%q.freeze, [">= 4.0", "< 7"]) s.add_dependency(%q.freeze, ["~> 3.18"]) end end PK ]`C# specifications/irb-1.2.6.gemspecnu[# -*- encoding: utf-8 -*- # stub: irb 1.2.6 ruby lib Gem::Specification.new do |s| s.name = "irb".freeze s.version = "1.2.6" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Keiju ISHITSUKA".freeze] s.bindir = "exe".freeze s.date = "2023-06-06" s.description = "Interactive Ruby command-line tool for REPL (Read Eval Print Loop).".freeze s.email = ["keiju@ruby-lang.org".freeze] s.executables = ["irb".freeze] s.files = ["exe/irb".freeze, "irb.rb".freeze, "irb/cmd/chws.rb".freeze, "irb/cmd/fork.rb".freeze, "irb/cmd/help.rb".freeze, "irb/cmd/info.rb".freeze, "irb/cmd/load.rb".freeze, "irb/cmd/nop.rb".freeze, "irb/cmd/pushws.rb".freeze, "irb/cmd/subirb.rb".freeze, "irb/color.rb".freeze, "irb/completion.rb".freeze, "irb/context.rb".freeze, "irb/easter-egg.rb".freeze, "irb/ext/change-ws.rb".freeze, "irb/ext/history.rb".freeze, "irb/ext/loader.rb".freeze, "irb/ext/multi-irb.rb".freeze, "irb/ext/save-history.rb".freeze, "irb/ext/tracer.rb".freeze, "irb/ext/use-loader.rb".freeze, "irb/ext/workspaces.rb".freeze, "irb/extend-command.rb".freeze, "irb/frame.rb".freeze, "irb/help.rb".freeze, "irb/init.rb".freeze, "irb/input-method.rb".freeze, "irb/inspector.rb".freeze, "irb/lc/error.rb".freeze, "irb/lc/ja/encoding_aliases.rb".freeze, "irb/lc/ja/error.rb".freeze, "irb/locale.rb".freeze, "irb/magic-file.rb".freeze, "irb/notifier.rb".freeze, "irb/output-method.rb".freeze, "irb/ruby-lex.rb".freeze, "irb/src_encoding.rb".freeze, "irb/version.rb".freeze, "irb/workspace.rb".freeze, "irb/ws-for-case-2.rb".freeze, "irb/xmp.rb".freeze] s.homepage = "https://github.com/ruby/irb".freeze s.licenses = ["Ruby".freeze, "BSD-2-Clause".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.5".freeze) s.rubygems_version = "3.1.6".freeze s.summary = "Interactive Ruby command-line tool for REPL (Read Eval Print Loop).".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_runtime_dependency(%q.freeze, [">= 0.1.5"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0.1.5"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]=wgems/irb-1.2.6/exe/irbnuȯ#!/usr/bin/ruby # # irb.rb - interactive ruby # $Release Version: 0.9.6 $ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # require "irb" IRB.start(__FILE__) PK ]Skkgems/irb-1.2.6/lib/irb.rbnu[# frozen_string_literal: false # # irb.rb - irb main module # $Release Version: 0.9.6 $ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "ripper" require "reline" require_relative "irb/init" require_relative "irb/context" require_relative "irb/extend-command" require_relative "irb/ruby-lex" require_relative "irb/input-method" require_relative "irb/locale" require_relative "irb/color" require_relative "irb/version" require_relative "irb/easter-egg" # IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby # expressions read from the standard input. # # The +irb+ command from your shell will start the interpreter. # # == Usage # # Use of irb is easy if you know Ruby. # # When executing irb, prompts are displayed as follows. Then, enter the Ruby # expression. An input is executed when it is syntactically complete. # # $ irb # irb(main):001:0> 1+2 # #=> 3 # irb(main):002:0> class Foo # irb(main):003:1> def foo # irb(main):004:2> print 1 # irb(main):005:2> end # irb(main):006:1> end # #=> nil # # The singleline editor module or multiline editor module can be used with irb. # Use of multiline editor is default if it's installed. # # == Command line options # # Usage: irb.rb [options] [programfile] [arguments] # -f Suppress read of ~/.irbrc # -d Set $DEBUG to true (same as `ruby -d') # -r load-module Same as `ruby -r' # -I path Specify $LOAD_PATH directory # -U Same as `ruby -U` # -E enc Same as `ruby -E` # -w Same as `ruby -w` # -W[level=2] Same as `ruby -W` # --inspect Use `inspect' for output (default except for bc mode) # --noinspect Don't use inspect for output # --multiline Use multiline editor module # --nomultiline Don't use multiline editor module # --singleline Use singleline editor module # --nosingleline Don't use singleline editor module # --colorize Use colorization # --nocolorize Don't use colorization # --prompt prompt-mode # --prompt-mode prompt-mode # Switch prompt mode. Pre-defined prompt modes are # `default', `simple', `xmp' and `inf-ruby' # --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs. # Suppresses --multiline and --singleline. # --simple-prompt Simple prompt mode # --noprompt No prompt mode # --tracer Display trace for each execution of commands. # --back-trace-limit n # Display backtrace top n and tail n. The default # value is 16. # -v, --version Print the version of irb # # == Configuration # # IRB reads from ~/.irbrc when it's invoked. # # If ~/.irbrc doesn't exist, +irb+ will try to read in the following order: # # * +.irbrc+ # * +irb.rc+ # * +_irbrc+ # * $irbrc # # The following are alternatives to the command line options. To use them type # as follows in an +irb+ session: # # IRB.conf[:IRB_NAME]="irb" # IRB.conf[:INSPECT_MODE]=nil # IRB.conf[:IRB_RC] = nil # IRB.conf[:BACK_TRACE_LIMIT]=16 # IRB.conf[:USE_LOADER] = false # IRB.conf[:USE_MULTILINE] = nil # IRB.conf[:USE_SINGLELINE] = nil # IRB.conf[:USE_COLORIZE] = true # IRB.conf[:USE_TRACER] = false # IRB.conf[:IGNORE_SIGINT] = true # IRB.conf[:IGNORE_EOF] = false # IRB.conf[:PROMPT_MODE] = :DEFAULT # IRB.conf[:PROMPT] = {...} # # === Auto indentation # # To disable auto-indent mode in irb, add the following to your +.irbrc+: # # IRB.conf[:AUTO_INDENT] = false # # === Autocompletion # # To enable autocompletion for irb, add the following to your +.irbrc+: # # require 'irb/completion' # # === History # # By default, irb will store the last 1000 commands you used in # IRB.conf[:HISTORY_FILE] (~/.irb_history by default). # # If you want to disable history, add the following to your +.irbrc+: # # IRB.conf[:SAVE_HISTORY] = nil # # See IRB::Context#save_history= for more information. # # The history of _results_ of commands evaluated is not stored by default, # but can be turned on to be stored with this +.irbrc+ setting: # # IRB.conf[:EVAL_HISTORY] = # # See IRB::Context#eval_history= and History class. The history of command # results is not permanently saved in any file. # # == Customizing the IRB Prompt # # In order to customize the prompt, you can change the following Hash: # # IRB.conf[:PROMPT] # # This example can be used in your +.irbrc+ # # IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode # :AUTO_INDENT => false, # disables auto-indent mode # :PROMPT_I => ">> ", # simple prompt # :PROMPT_S => nil, # prompt for continuated strings # :PROMPT_C => nil, # prompt for continuated statement # :RETURN => " ==>%s\n" # format to return value # } # # IRB.conf[:PROMPT_MODE] = :MY_PROMPT # # Or, invoke irb with the above prompt mode by: # # irb --prompt my-prompt # # Constants +PROMPT_I+, +PROMPT_S+ and +PROMPT_C+ specify the format. In the # prompt specification, some special strings are available: # # %N # command name which is running # %m # to_s of main object (self) # %M # inspect of main object (self) # %l # type of string(", ', /, ]), `]' is inner %w[...] # %NNi # indent level. NN is digits and means as same as printf("%NNd"). # # It can be omitted # %NNn # line number. # %% # % # # For instance, the default prompt mode is defined as follows: # # IRB.conf[:PROMPT_MODE][:DEFAULT] = { # :PROMPT_I => "%N(%m):%03n:%i> ", # :PROMPT_N => "%N(%m):%03n:%i> ", # :PROMPT_S => "%N(%m):%03n:%i%l ", # :PROMPT_C => "%N(%m):%03n:%i* ", # :RETURN => "%s\n" # used to printf # } # # irb comes with a number of available modes: # # # :NULL: # # :PROMPT_I: # # :PROMPT_N: # # :PROMPT_S: # # :PROMPT_C: # # :RETURN: | # # %s # # :DEFAULT: # # :PROMPT_I: ! '%N(%m):%03n:%i> ' # # :PROMPT_N: ! '%N(%m):%03n:%i> ' # # :PROMPT_S: ! '%N(%m):%03n:%i%l ' # # :PROMPT_C: ! '%N(%m):%03n:%i* ' # # :RETURN: | # # => %s # # :CLASSIC: # # :PROMPT_I: ! '%N(%m):%03n:%i> ' # # :PROMPT_N: ! '%N(%m):%03n:%i> ' # # :PROMPT_S: ! '%N(%m):%03n:%i%l ' # # :PROMPT_C: ! '%N(%m):%03n:%i* ' # # :RETURN: | # # %s # # :SIMPLE: # # :PROMPT_I: ! '>> ' # # :PROMPT_N: ! '>> ' # # :PROMPT_S: # # :PROMPT_C: ! '?> ' # # :RETURN: | # # => %s # # :INF_RUBY: # # :PROMPT_I: ! '%N(%m):%03n:%i> ' # # :PROMPT_N: # # :PROMPT_S: # # :PROMPT_C: # # :RETURN: | # # %s # # :AUTO_INDENT: true # # :XMP: # # :PROMPT_I: # # :PROMPT_N: # # :PROMPT_S: # # :PROMPT_C: # # :RETURN: |2 # # ==>%s # # == Restrictions # # Because irb evaluates input immediately after it is syntactically complete, # the results may be slightly different than directly using Ruby. # # == IRB Sessions # # IRB has a special feature, that allows you to manage many sessions at once. # # You can create new sessions with Irb.irb, and get a list of current sessions # with the +jobs+ command in the prompt. # # === Commands # # JobManager provides commands to handle the current sessions: # # jobs # List of current sessions # fg # Switches to the session of the given number # kill # Kills the session with the given number # # The +exit+ command, or ::irb_exit, will quit the current session and call any # exit hooks with IRB.irb_at_exit. # # A few commands for loading files within the session are also available: # # +source+:: # Loads a given file in the current session and displays the source lines, # see IrbLoader#source_file # +irb_load+:: # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load # +irb_require+:: # Loads the given file similarly to Kernel#require # # === Configuration # # The command line options, or IRB.conf, specify the default behavior of # Irb.irb. # # On the other hand, each conf in IRB@Command+line+options is used to # individually configure IRB.irb. # # If a proc is set for IRB.conf[:IRB_RC], its will be invoked after execution # of that proc with the context of the current session as its argument. Each # session can be configured using this mechanism. # # === Session variables # # There are a few variables in every Irb session that can come in handy: # # _:: # The value command executed, as a local variable # __:: # The history of evaluated commands. Available only if # IRB.conf[:EVAL_HISTORY] is not +nil+ (which is the default). # See also IRB::Context#eval_history= and IRB::History. # __[line_no]:: # Returns the evaluation value at the given line number, +line_no+. # If +line_no+ is a negative, the return value +line_no+ many lines before # the most recent return value. # # === Example using IRB Sessions # # # invoke a new session # irb(main):001:0> irb # # list open sessions # irb.1(main):001:0> jobs # #0->irb on main (# : stop) # #1->irb#1 on main (# : running) # # # change the active session # irb.1(main):002:0> fg 0 # # define class Foo in top-level session # irb(main):002:0> class Foo;end # # invoke a new session with the context of Foo # irb(main):003:0> irb Foo # # define Foo#foo # irb.2(Foo):001:0> def foo # irb.2(Foo):002:1> print 1 # irb.2(Foo):003:1> end # # # change the active session # irb.2(Foo):004:0> fg 0 # # list open sessions # irb(main):004:0> jobs # #0->irb on main (# : running) # #1->irb#1 on main (# : stop) # #2->irb#2 on Foo (# : stop) # # check if Foo#foo is available # irb(main):005:0> Foo.instance_methods #=> [:foo, ...] # # # change the active session # irb(main):006:0> fg 2 # # define Foo#bar in the context of Foo # irb.2(Foo):005:0> def bar # irb.2(Foo):006:1> print "bar" # irb.2(Foo):007:1> end # irb.2(Foo):010:0> Foo.instance_methods #=> [:bar, :foo, ...] # # # change the active session # irb.2(Foo):011:0> fg 0 # irb(main):007:0> f = Foo.new #=> # # # invoke a new session with the context of f (instance of Foo) # irb(main):008:0> irb f # # list open sessions # irb.3():001:0> jobs # #0->irb on main (# : stop) # #1->irb#1 on main (# : stop) # #2->irb#2 on Foo (# : stop) # #3->irb#3 on # (# : running) # # evaluate f.foo # irb.3():002:0> foo #=> 1 => nil # # evaluate f.bar # irb.3():003:0> bar #=> bar => nil # # kill jobs 1, 2, and 3 # irb.3():004:0> kill 1, 2, 3 # # list open sessions, should only include main session # irb(main):009:0> jobs # #0->irb on main (# : running) # # quit irb # irb(main):010:0> exit module IRB # An exception raised by IRB.irb_abort class Abort < Exception;end @CONF = {} # Displays current configuration. # # Modifying the configuration is achieved by sending a message to IRB.conf. # # See IRB@Configuration for more information. def IRB.conf @CONF end # Returns the current version of IRB, including release version and last # updated date. def IRB.version if v = @CONF[:VERSION] then return v end @CONF[:VERSION] = format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE) end # The current IRB::Context of the session, see IRB.conf # # irb # irb(main):001:0> IRB.CurrentContext.irb_name = "foo" # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo" def IRB.CurrentContext IRB.conf[:MAIN_CONTEXT] end # Initializes IRB and creates a new Irb.irb object at the +TOPLEVEL_BINDING+ def IRB.start(ap_path = nil) STDOUT.sync = true $0 = File::basename(ap_path, ".rb") if ap_path IRB.setup(ap_path) if @CONF[:SCRIPT] irb = Irb.new(nil, @CONF[:SCRIPT]) else irb = Irb.new end irb.run(@CONF) end # Calls each event hook of IRB.conf[:TA_EXIT] when the current session quits. def IRB.irb_at_exit @CONF[:AT_EXIT].each{|hook| hook.call} end # Quits irb def IRB.irb_exit(irb, ret) throw :IRB_EXIT, ret end # Aborts then interrupts irb. # # Will raise an Abort exception, or the given +exception+. def IRB.irb_abort(irb, exception = Abort) if defined? Thread irb.context.thread.raise exception, "abort then interrupt!" else raise exception, "abort then interrupt!" end end class Irb ASSIGNMENT_NODE_TYPES = [ # Local, instance, global, class, constant, instance, and index assignment: # "foo = bar", # "@foo = bar", # "$foo = bar", # "@@foo = bar", # "::Foo = bar", # "a::Foo = bar", # "Foo = bar" # "foo.bar = 1" # "foo[1] = bar" :assign, # Operation assignment: # "foo += bar" # "foo -= bar" # "foo ||= bar" # "foo &&= bar" :opassign, # Multiple assignment: # "foo, bar = 1, 2 :massign, ] # Note: instance and index assignment expressions could also be written like: # "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former # be parsed as :assign and echo will be suppressed, but the latter is # parsed as a :method_add_arg and the output won't be suppressed # Creates a new irb session def initialize(workspace = nil, input_method = nil) @context = Context.new(self, workspace, input_method) @context.main.extend ExtendCommandBundle @signal_status = :IN_IRB @scanner = RubyLex.new end def run(conf = IRB.conf) conf[:IRB_RC].call(context) if conf[:IRB_RC] conf[:MAIN_CONTEXT] = context trap("SIGINT") do signal_handle end begin catch(:IRB_EXIT) do eval_input end ensure conf[:AT_EXIT].each{|hook| hook.call} end end # Returns the current context of this irb session attr_reader :context # The lexer used by this irb session attr_accessor :scanner # Evaluates input for this session. def eval_input exc = nil @scanner.set_prompt do |ltype, indent, continue, line_no| if ltype f = @context.prompt_s elsif continue f = @context.prompt_c elsif indent > 0 f = @context.prompt_n else f = @context.prompt_i end f = "" unless f if @context.prompting? @context.io.prompt = p = prompt(f, ltype, indent, line_no) else @context.io.prompt = p = "" end if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent) unless ltype prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size + indent * 2 - p.size ind += 2 if continue @context.io.prompt = p + " " * ind if ind > 0 end end @context.io.prompt end @scanner.set_input(@context.io) do signal_status(:IN_INPUT) do if l = @context.io.gets print l if @context.verbose? else if @context.ignore_eof? and @context.io.readable_after_eof? l = "\n" if @context.verbose? printf "Use \"exit\" to leave %s\n", @context.ap_name end else print "\n" end end l end end @scanner.set_auto_indent(@context) if @context.auto_indent_mode @scanner.each_top_level_statement do |line, line_no| signal_status(:IN_EVAL) do begin line.untaint if RUBY_VERSION < '2.7' @context.evaluate(line, line_no, exception: exc) if @context.echo? if assignment_expression?(line) if @context.echo_on_assignment? output_value(@context.omit_on_assignment?) end else output_value end end rescue Interrupt => exc rescue SystemExit, SignalException raise rescue Exception => exc else exc = nil next end handle_exception(exc) end end end def handle_exception(exc) if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ && !(SyntaxError === exc) && !(EncodingError === exc) # The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno. irb_bug = true else irb_bug = false end if STDOUT.tty? attr = ATTR_TTY print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n" else attr = ATTR_PLAIN end messages = [] lasts = [] levels = 0 if exc.backtrace count = 0 exc.backtrace.each do |m| m = @context.workspace.filter_backtrace(m) or next unless irb_bug count += 1 if attr == ATTR_TTY m = sprintf("%9d: from %s", count, m) else m = "\tfrom #{m}" end if messages.size < @context.back_trace_limit messages.push(m) elsif lasts.size < @context.back_trace_limit lasts.push(m).shift levels += 1 end end end if attr == ATTR_TTY unless lasts.empty? puts lasts.reverse printf "... %d levels...\n", levels if levels > 0 end puts messages.reverse end m = exc.to_s.split(/\n/) print "#{attr[1]}#{exc.class} (#{attr[4]}#{m.shift}#{attr[0, 1]})#{attr[]}\n" puts m.map {|s| "#{attr[1]}#{s}#{attr[]}\n"} if attr == ATTR_PLAIN puts messages unless lasts.empty? puts lasts printf "... %d levels...\n", levels if levels > 0 end end print "Maybe IRB bug!\n" if irb_bug end # Evaluates the given block using the given +path+ as the Context#irb_path # and +name+ as the Context#irb_name. # # Used by the irb command +source+, see IRB@IRB+Sessions for more # information. def suspend_name(path = nil, name = nil) @context.irb_path, back_path = path, @context.irb_path if path @context.irb_name, back_name = name, @context.irb_name if name begin yield back_path, back_name ensure @context.irb_path = back_path if path @context.irb_name = back_name if name end end # Evaluates the given block using the given +workspace+ as the # Context#workspace. # # Used by the irb command +irb_load+, see IRB@IRB+Sessions for more # information. def suspend_workspace(workspace) @context.workspace, back_workspace = workspace, @context.workspace begin yield back_workspace ensure @context.workspace = back_workspace end end # Evaluates the given block using the given +input_method+ as the # Context#io. # # Used by the irb commands +source+ and +irb_load+, see IRB@IRB+Sessions # for more information. def suspend_input_method(input_method) back_io = @context.io @context.instance_eval{@io = input_method} begin yield back_io ensure @context.instance_eval{@io = back_io} end end # Evaluates the given block using the given +context+ as the Context. def suspend_context(context) @context, back_context = context, @context begin yield back_context ensure @context = back_context end end # Handler for the signal SIGINT, see Kernel#trap for more information. def signal_handle unless @context.ignore_sigint? print "\nabort!\n" if @context.verbose? exit end case @signal_status when :IN_INPUT print "^C\n" raise RubyLex::TerminateLineInput when :IN_EVAL IRB.irb_abort(self) when :IN_LOAD IRB.irb_abort(self, LoadAbort) when :IN_IRB # ignore else # ignore other cases as well end end # Evaluates the given block using the given +status+. def signal_status(status) return yield if @signal_status == :IN_LOAD signal_status_back = @signal_status @signal_status = status begin yield ensure @signal_status = signal_status_back end end def prompt(prompt, ltype, indent, line_no) # :nodoc: p = prompt.dup p.gsub!(/%([0-9]+)?([a-zA-Z])/) do case $2 when "N" @context.irb_name when "m" @context.main.to_s when "M" @context.main.inspect when "l" ltype when "i" if indent < 0 if $1 "-".rjust($1.to_i) else "-" end else if $1 format("%" + $1 + "d", indent) else indent.to_s end end when "n" if $1 format("%" + $1 + "d", line_no) else line_no.to_s end when "%" "%" end end p end def output_value(omit = false) # :nodoc: str = @context.inspect_last_value multiline_p = str.include?("\n") if omit winwidth = @context.io.winsize.last if multiline_p first_line = str.split("\n").first result = @context.newline_before_multiline_output? ? (@context.return_format % first_line) : first_line output_width = Reline::Unicode.calculate_width(result, true) diff_size = output_width - Reline::Unicode.calculate_width(first_line, true) if diff_size.positive? and output_width > winwidth lines, _ = Reline::Unicode.split_by_width(first_line, winwidth - diff_size - 3) str = "%s...\e[0m" % lines.first multiline_p = false else str.gsub!(/(\A.*?\n).*/m, "\\1...") end else output_width = Reline::Unicode.calculate_width(@context.return_format % str, true) diff_size = output_width - Reline::Unicode.calculate_width(str, true) if diff_size.positive? and output_width > winwidth lines, _ = Reline::Unicode.split_by_width(str, winwidth - diff_size - 3) str = "%s...\e[0m" % lines.first end end end if multiline_p && @context.newline_before_multiline_output? printf @context.return_format, "\n#{str}" else printf @context.return_format, str end end # Outputs the local variables to this current session, including # #signal_status and #context, using IRB::Locale. def inspect ary = [] for iv in instance_variables case (iv = iv.to_s) when "@signal_status" ary.push format("%s=:%s", iv, @signal_status.id2name) when "@context" ary.push format("%s=%s", iv, eval(iv).__to_s__) else ary.push format("%s=%s", iv, eval(iv)) end end format("#<%s: %s>", self.class, ary.join(", ")) end def assignment_expression?(line) # Try to parse the line and check if the last of possibly multiple # expressions is an assignment type. # If the expression is invalid, Ripper.sexp should return nil which will # result in false being returned. Any valid expression should return an # s-expression where the second selement of the top level array is an # array of parsed expressions. The first element of each expression is the # expression's type. verbose, $VERBOSE = $VERBOSE, nil result = ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0)) $VERBOSE = verbose result end ATTR_TTY = "\e[%sm" def ATTR_TTY.[](*a) self % a.join(";"); end ATTR_PLAIN = "" def ATTR_PLAIN.[](*) self; end end def @CONF.inspect IRB.version unless self[:VERSION] array = [] for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name} case k when :MAIN_CONTEXT, :__TMP__EHV__ array.push format("CONF[:%s]=...myself...", k.id2name) when :PROMPT s = v.collect{ |kk, vv| ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"} format(":%s=>{%s}", kk.id2name, ss.join(", ")) } array.push format("CONF[:%s]={%s}", k.id2name, s.join(", ")) else array.push format("CONF[:%s]=%s", k.id2name, v.inspect) end end array.join("\n") end end class Binding # Opens an IRB session where +binding.irb+ is called which allows for # interactive debugging. You can call any methods or variables available in # the current scope, and mutate state if you need to. # # # Given a Ruby file called +potato.rb+ containing the following code: # # class Potato # def initialize # @cooked = false # binding.irb # puts "Cooked potato: #{@cooked}" # end # end # # Potato.new # # Running ruby potato.rb will open an IRB session where # +binding.irb+ is called, and you will see the following: # # $ ruby potato.rb # # From: potato.rb @ line 4 : # # 1: class Potato # 2: def initialize # 3: @cooked = false # => 4: binding.irb # 5: puts "Cooked potato: #{@cooked}" # 6: end # 7: end # 8: # 9: Potato.new # # irb(#):001:0> # # You can type any valid Ruby code and it will be evaluated in the current # context. This allows you to debug without having to run your code repeatedly: # # irb(#):001:0> @cooked # => false # irb(#):002:0> self.class # => Potato # irb(#):003:0> caller.first # => ".../2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:in `eval'" # irb(#):004:0> @cooked = true # => true # # You can exit the IRB session with the +exit+ command. Note that exiting will # resume execution where +binding.irb+ had paused it, as you can see from the # output printed to standard output in this example: # # irb(#):005:0> exit # Cooked potato: true # # # See IRB@IRB+Usage for more information. def irb IRB.setup(source_location[0], argv: []) workspace = IRB::WorkSpace.new(self) STDOUT.print(workspace.code_around_binding) binding_irb = IRB::Irb.new(workspace) binding_irb.context.irb_path = File.expand_path(source_location[0]) binding_irb.run(IRB.conf) end end PK ])C=C=!gems/irb-1.2.6/lib/irb/context.rbnu[# frozen_string_literal: false # # irb/context.rb - irb context # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "workspace" require_relative "inspector" require_relative "input-method" require_relative "output-method" module IRB # A class that wraps the current state of the irb session, including the # configuration of IRB.conf. class Context # Creates a new IRB context. # # The optional +input_method+ argument: # # +nil+:: uses stdin or Reidline or Readline # +String+:: uses a File # +other+:: uses this as InputMethod def initialize(irb, workspace = nil, input_method = nil) @irb = irb if workspace @workspace = workspace else @workspace = WorkSpace.new end @thread = Thread.current if defined? Thread # copy of default configuration @ap_name = IRB.conf[:AP_NAME] @rc = IRB.conf[:RC] @load_modules = IRB.conf[:LOAD_MODULES] if IRB.conf.has_key?(:USE_SINGLELINE) @use_singleline = IRB.conf[:USE_SINGLELINE] elsif IRB.conf.has_key?(:USE_READLINE) # backward compatibility @use_singleline = IRB.conf[:USE_READLINE] else @use_singleline = nil end if IRB.conf.has_key?(:USE_MULTILINE) @use_multiline = IRB.conf[:USE_MULTILINE] elsif IRB.conf.has_key?(:USE_REIDLINE) # backward compatibility @use_multiline = IRB.conf[:USE_REIDLINE] else @use_multiline = nil end @use_colorize = IRB.conf[:USE_COLORIZE] @verbose = IRB.conf[:VERBOSE] @io = nil self.inspect_mode = IRB.conf[:INSPECT_MODE] self.use_tracer = IRB.conf[:USE_TRACER] if IRB.conf[:USE_TRACER] self.use_loader = IRB.conf[:USE_LOADER] if IRB.conf[:USE_LOADER] self.eval_history = IRB.conf[:EVAL_HISTORY] if IRB.conf[:EVAL_HISTORY] @ignore_sigint = IRB.conf[:IGNORE_SIGINT] @ignore_eof = IRB.conf[:IGNORE_EOF] @back_trace_limit = IRB.conf[:BACK_TRACE_LIMIT] self.prompt_mode = IRB.conf[:PROMPT_MODE] if IRB.conf[:SINGLE_IRB] or !defined?(IRB::JobManager) @irb_name = IRB.conf[:IRB_NAME] else @irb_name = IRB.conf[:IRB_NAME]+"#"+IRB.JobManager.n_jobs.to_s end @irb_path = "(" + @irb_name + ")" case input_method when nil @io = nil case use_multiline? when nil if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline? # Both of multiline mode and singleline mode aren't specified. @io = ReidlineInputMethod.new else @io = nil end when false @io = nil when true @io = ReidlineInputMethod.new end unless @io case use_singleline? when nil if (defined?(ReadlineInputMethod) && STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY) @io = ReadlineInputMethod.new else @io = nil end when false @io = nil when true if defined?(ReadlineInputMethod) @io = ReadlineInputMethod.new else @io = nil end else @io = nil end end @io = StdioInputMethod.new unless @io when String @io = FileInputMethod.new(input_method) @irb_name = File.basename(input_method) @irb_path = input_method else @io = input_method end self.save_history = IRB.conf[:SAVE_HISTORY] if IRB.conf[:SAVE_HISTORY] @echo = IRB.conf[:ECHO] if @echo.nil? @echo = true end @echo_on_assignment = IRB.conf[:ECHO_ON_ASSIGNMENT] if @echo_on_assignment.nil? @echo_on_assignment = true end @omit_on_assignment = IRB.conf[:OMIT_ON_ASSIGNMENT] if @omit_on_assignment.nil? @omit_on_assignment = true end @newline_before_multiline_output = IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] if @newline_before_multiline_output.nil? @newline_before_multiline_output = true end end # The top-level workspace, see WorkSpace#main def main @workspace.main end # The toplevel workspace, see #home_workspace attr_reader :workspace_home # WorkSpace in the current context attr_accessor :workspace # The current thread in this context attr_reader :thread # The current input method # # Can be either StdioInputMethod, ReadlineInputMethod, # ReidlineInputMethod, FileInputMethod or other specified when the # context is created. See ::new for more # information on +input_method+. attr_accessor :io # Current irb session attr_accessor :irb # A copy of the default IRB.conf[:AP_NAME] attr_accessor :ap_name # A copy of the default IRB.conf[:RC] attr_accessor :rc # A copy of the default IRB.conf[:LOAD_MODULES] attr_accessor :load_modules # Can be either name from IRB.conf[:IRB_NAME], or the number of # the current job set by JobManager, such as irb#2 attr_accessor :irb_name # Can be either the #irb_name surrounded by parenthesis, or the # +input_method+ passed to Context.new attr_accessor :irb_path # Whether multiline editor mode is enabled or not. # # A copy of the default IRB.conf[:USE_MULTILINE] attr_reader :use_multiline # Whether singleline editor mode is enabled or not. # # A copy of the default IRB.conf[:USE_SINGLELINE] attr_reader :use_singleline # Whether colorization is enabled or not. # # A copy of the default IRB.conf[:USE_COLORIZE] attr_reader :use_colorize # A copy of the default IRB.conf[:INSPECT_MODE] attr_reader :inspect_mode # A copy of the default IRB.conf[:PROMPT_MODE] attr_reader :prompt_mode # Standard IRB prompt # # See IRB@Customizing+the+IRB+Prompt for more information. attr_accessor :prompt_i # IRB prompt for continuated strings # # See IRB@Customizing+the+IRB+Prompt for more information. attr_accessor :prompt_s # IRB prompt for continuated statement (e.g. immediately after an +if+) # # See IRB@Customizing+the+IRB+Prompt for more information. attr_accessor :prompt_c # See IRB@Customizing+the+IRB+Prompt for more information. attr_accessor :prompt_n # Can be either the default IRB.conf[:AUTO_INDENT], or the # mode set by #prompt_mode= # # To disable auto-indentation in irb: # # IRB.conf[:AUTO_INDENT] = false # # or # # irb_context.auto_indent_mode = false # # or # # IRB.CurrentContext.auto_indent_mode = false # # See IRB@Configuration for more information. attr_accessor :auto_indent_mode # The format of the return statement, set by #prompt_mode= using the # +:RETURN+ of the +mode+ passed to set the current #prompt_mode. attr_accessor :return_format # Whether ^C (+control-c+) will be ignored or not. # # If set to +false+, ^C will quit irb. # # If set to +true+, # # * during input: cancel input then return to top level. # * during execute: abandon current execution. attr_accessor :ignore_sigint # Whether ^D (+control-d+) will be ignored or not. # # If set to +false+, ^D will quit irb. attr_accessor :ignore_eof # Whether to echo the return value to output or not. # # Uses IRB.conf[:ECHO] if available, or defaults to +true+. # # puts "hello" # # hello # #=> nil # IRB.CurrentContext.echo = false # puts "omg" # # omg attr_accessor :echo # Whether to echo for assignment expressions # # Uses IRB.conf[:ECHO_ON_ASSIGNMENT] if available, or defaults to +true+. # # a = "omg" # #=> omg # IRB.CurrentContext.echo_on_assignment = false # a = "omg" attr_accessor :echo_on_assignment # Whether to omit echo for assignment expressions # # Uses IRB.conf[:OMIT_ON_ASSIGNMENT] if available, or defaults to +true+. # # a = [1] * 10 # #=> [1, 1, 1, 1, 1, 1, 1, 1, ... # [1] * 10 # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # IRB.CurrentContext.omit_on_assignment = false # a = [1] * 10 # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # [1] * 10 # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] attr_accessor :omit_on_assignment # Whether a newline is put before multiline output. # # Uses IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] if available, # or defaults to +true+. # # "abc\ndef" # #=> # abc # def # IRB.CurrentContext.newline_before_multiline_output = false # "abc\ndef" # #=> abc # def attr_accessor :newline_before_multiline_output # Whether verbose messages are displayed or not. # # A copy of the default IRB.conf[:VERBOSE] attr_accessor :verbose # The limit of backtrace lines displayed as top +n+ and tail +n+. # # The default value is 16. # # Can also be set using the +--back-trace-limit+ command line option. # # See IRB@Command+line+options for more command line options. attr_accessor :back_trace_limit # Alias for #use_multiline alias use_multiline? use_multiline # Alias for #use_singleline alias use_singleline? use_singleline # backward compatibility alias use_reidline use_multiline # backward compatibility alias use_reidline? use_multiline # backward compatibility alias use_readline use_singleline # backward compatibility alias use_readline? use_singleline # Alias for #use_colorize alias use_colorize? use_colorize # Alias for #rc alias rc? rc alias ignore_sigint? ignore_sigint alias ignore_eof? ignore_eof alias echo? echo alias echo_on_assignment? echo_on_assignment alias omit_on_assignment? omit_on_assignment alias newline_before_multiline_output? newline_before_multiline_output # Returns whether messages are displayed or not. def verbose? if @verbose.nil? if @io.kind_of?(ReidlineInputMethod) false elsif defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod) false elsif !STDIN.tty? or @io.kind_of?(FileInputMethod) true else false end else @verbose end end # Whether #verbose? is +true+, and +input_method+ is either # StdioInputMethod or ReidlineInputMethod or ReadlineInputMethod, see #io # for more information. def prompting? verbose? || (STDIN.tty? && @io.kind_of?(StdioInputMethod) || @io.kind_of?(ReidlineInputMethod) || (defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod))) end # The return value of the last statement evaluated. attr_reader :last_value # Sets the return value from the last statement evaluated in this context # to #last_value. def set_last_value(value) @last_value = value @workspace.local_variable_set :_, value end # Sets the +mode+ of the prompt in this context. # # See IRB@Customizing+the+IRB+Prompt for more information. def prompt_mode=(mode) @prompt_mode = mode pconf = IRB.conf[:PROMPT][mode] @prompt_i = pconf[:PROMPT_I] @prompt_s = pconf[:PROMPT_S] @prompt_c = pconf[:PROMPT_C] @prompt_n = pconf[:PROMPT_N] @return_format = pconf[:RETURN] if ai = pconf.include?(:AUTO_INDENT) @auto_indent_mode = ai else @auto_indent_mode = IRB.conf[:AUTO_INDENT] end end # Whether #inspect_mode is set or not, see #inspect_mode= for more detail. def inspect? @inspect_mode.nil? or @inspect_mode end # Whether #io uses a File for the +input_method+ passed when creating the # current context, see ::new def file_input? @io.class == FileInputMethod end # Specifies the inspect mode with +opt+: # # +true+:: display +inspect+ # +false+:: display +to_s+ # +nil+:: inspect mode in non-math mode, # non-inspect mode in math mode # # See IRB::Inspector for more information. # # Can also be set using the +--inspect+ and +--noinspect+ command line # options. # # See IRB@Command+line+options for more command line options. def inspect_mode=(opt) if i = Inspector::INSPECTORS[opt] @inspect_mode = opt @inspect_method = i i.init else case opt when nil if Inspector.keys_with_inspector(Inspector::INSPECTORS[true]).include?(@inspect_mode) self.inspect_mode = false elsif Inspector.keys_with_inspector(Inspector::INSPECTORS[false]).include?(@inspect_mode) self.inspect_mode = true else puts "Can't switch inspect mode." return end when /^\s*\{.*\}\s*$/ begin inspector = eval "proc#{opt}" rescue Exception puts "Can't switch inspect mode(#{opt})." return end self.inspect_mode = inspector when Proc self.inspect_mode = IRB::Inspector(opt) when Inspector prefix = "usr%d" i = 1 while Inspector::INSPECTORS[format(prefix, i)]; i += 1; end @inspect_mode = format(prefix, i) @inspect_method = opt Inspector.def_inspector(format(prefix, i), @inspect_method) else puts "Can't switch inspect mode(#{opt})." return end end print "Switch to#{unless @inspect_mode; ' non';end} inspect mode.\n" if verbose? @inspect_mode end def evaluate(line, line_no, exception: nil) # :nodoc: @line_no = line_no if exception line_no -= 1 line = "begin ::Kernel.raise _; rescue _.class\n#{line}\n""end" @workspace.local_variable_set(:_, exception) end set_last_value(@workspace.evaluate(self, line, irb_path, line_no)) end def inspect_last_value # :nodoc: @inspect_method.inspect_value(@last_value) end alias __exit__ exit # Exits the current session, see IRB.irb_exit def exit(ret = 0) IRB.irb_exit(@irb, ret) end NOPRINTING_IVARS = ["@last_value"] # :nodoc: NO_INSPECTING_IVARS = ["@irb", "@io"] # :nodoc: IDNAME_IVARS = ["@prompt_mode"] # :nodoc: alias __inspect__ inspect def inspect # :nodoc: array = [] for ivar in instance_variables.sort{|e1, e2| e1 <=> e2} ivar = ivar.to_s name = ivar.sub(/^@(.*)$/, '\1') val = instance_eval(ivar) case ivar when *NOPRINTING_IVARS array.push format("conf.%s=%s", name, "...") when *NO_INSPECTING_IVARS array.push format("conf.%s=%s", name, val.to_s) when *IDNAME_IVARS array.push format("conf.%s=:%s", name, val.id2name) else array.push format("conf.%s=%s", name, val.inspect) end end array.join("\n") end alias __to_s__ to_s alias to_s inspect end end PK ]*\gems/irb-1.2.6/lib/irb/help.rbnu[# frozen_string_literal: false # # irb/help.rb - print usage module # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # # # require_relative 'magic-file' module IRB # Outputs the irb help message, see IRB@Command+line+options. def IRB.print_usage lc = IRB.conf[:LC_MESSAGES] path = lc.find("irb/help-message") space_line = false IRB::MagicFile.open(path){|f| f.each_line do |l| if /^\s*$/ =~ l lc.puts l unless space_line space_line = true next end space_line = false l.sub!(/#.*$/, "") next if /^\s*$/ =~ l lc.puts l end } end end PK ],9Yk"gems/irb-1.2.6/lib/irb/lc/error.rbnu[# frozen_string_literal: false # # irb/lc/error.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # # :stopdoc: module IRB class UnrecognizedSwitch < StandardError def initialize(val) super("Unrecognized switch: #{val}") end end class NotImplementedError < StandardError def initialize(val) super("Need to define `#{val}'") end end class CantReturnToNormalMode < StandardError def initialize super("Can't return to normal mode.") end end class IllegalParameter < StandardError def initialize(val) super("Invalid parameter(#{val}).") end end class IrbAlreadyDead < StandardError def initialize super("Irb is already dead.") end end class IrbSwitchedToCurrentThread < StandardError def initialize super("Switched to current thread.") end end class NoSuchJob < StandardError def initialize(val) super("No such job(#{val}).") end end class CantShiftToMultiIrbMode < StandardError def initialize super("Can't shift to multi irb mode.") end end class CantChangeBinding < StandardError def initialize(val) super("Can't change binding to (#{val}).") end end class UndefinedPromptMode < StandardError def initialize(val) super("Undefined prompt mode(#{val}).") end end class IllegalRCGenerator < StandardError def initialize super("Define illegal RC_NAME_GENERATOR.") end end end # :startdoc: PK ]\`90gems/irb-1.2.6/lib/irb/lc/ja/encoding_aliases.rbnu[# frozen_string_literal: false # :stopdoc: module IRB class Locale @@legacy_encoding_alias_map = { 'ujis' => Encoding::EUC_JP, 'euc' => Encoding::EUC_JP }.freeze end end # :startdoc: PK ].%gems/irb-1.2.6/lib/irb/lc/ja/error.rbnu[# -*- coding: utf-8 -*- # frozen_string_literal: false # irb/lc/ja/error.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # # :stopdoc: module IRB class UnrecognizedSwitch < StandardError def initialize(val) super("スイッチ(#{val})が分りません") end end class NotImplementedError < StandardError def initialize(val) super("`#{val}'の定義が必要です") end end class CantReturnToNormalMode < StandardError def initialize super("Normalモードに戻れません.") end end class IllegalParameter < StandardError def initialize(val) super("パラメータ(#{val})が間違っています.") end end class IrbAlreadyDead < StandardError def initialize super("Irbは既に死んでいます.") end end class IrbSwitchedToCurrentThread < StandardError def initialize super("カレントスレッドに切り替わりました.") end end class NoSuchJob < StandardError def initialize(val) super("そのようなジョブ(#{val})はありません.") end end class CantShiftToMultiIrbMode < StandardError def initialize super("multi-irb modeに移れません.") end end class CantChangeBinding < StandardError def initialize(val) super("バインディング(#{val})に変更できません.") end end class UndefinedPromptMode < StandardError def initialize(val) super("プロンプトモード(#{val})は定義されていません.") end end class IllegalRCGenerator < StandardError def initialize super("RC_NAME_GENERATORが正しく定義されていません.") end end end # :startdoc: # vim:fileencoding=utf-8 PK ]Ȇ@Dj j )gems/irb-1.2.6/lib/irb/lc/ja/help-messagenu[# -*- coding: utf-8 -*- # irb/lc/ja/help-message.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # Usage: irb.rb [options] [programfile] [arguments] -f ~/.irbrc を読み込まない. -d $DEBUG をtrueにする(ruby -d と同じ) -r load-module ruby -r と同じ. -I path $LOAD_PATH に path を追加する. -U ruby -U と同じ. -E enc ruby -E と同じ. -w ruby -w と同じ. -W[level=2] ruby -W と同じ. --context-mode n 新しいワークスペースを作成した時に関連する Binding オブジェクトの作成方法を 0 から 3 のいずれかに設定する. --echo 実行結果を表示する(デフォルト). --noecho 実行結果を表示しない. --inspect 結果出力にinspectを用いる. --noinspect 結果出力にinspectを用いない. --multiline マルチラインエディタを利用する. --nomultiline マルチラインエディタを利用しない. --singleline シングルラインエディタを利用する. --nosingleline シングルラインエディタを利用しない. --colorize 色付けを利用する. --nocolorize 色付けを利用しない. --prompt prompt-mode/--prompt-mode prompt-mode プロンプトモードを切替えます. 現在定義されているプ ロンプトモードは, default, simple, xmp, inf-rubyが 用意されています. --inf-ruby-mode emacsのinf-ruby-mode用のプロンプト表示を行なう. 特 に指定がない限り, シングルラインエディタとマルチラ インエディタは使わなくなる. --sample-book-mode/--simple-prompt 非常にシンプルなプロンプトを用いるモードです. --noprompt プロンプト表示を行なわない. --single-irb irb 中で self を実行して得られるオブジェクトをサ ブ irb と共有する. --tracer コマンド実行時にトレースを行なう. --back-trace-limit n バックトレース表示をバックトレースの頭から n, 後ろ からnだけ行なう. デフォルトは16 --verbose 詳細なメッセージを出力する. --noverbose 詳細なメッセージを出力しない(デフォルト). -v, --version irbのバージョンを表示する. -h, --help irb のヘルプを表示する. -- 以降のコマンドライン引数をオプションとして扱わない. # vim:fileencoding=utf-8 PK ]o]&gems/irb-1.2.6/lib/irb/lc/help-messagenu[# -*- coding: utf-8 -*- # # irb/lc/help-message.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # Usage: irb.rb [options] [programfile] [arguments] -f Suppress read of ~/.irbrc -d Set $DEBUG to true (same as `ruby -d') -r load-module Same as `ruby -r' -I path Specify $LOAD_PATH directory -U Same as `ruby -U` -E enc Same as `ruby -E` -w Same as `ruby -w` -W[level=2] Same as `ruby -W` --context-mode n Set n[0-3] to method to create Binding Object, when new workspace was created --echo Show result(default) --noecho Don't show result --inspect Use `inspect' for output --noinspect Don't use inspect for output --multiline Use multiline editor module --nomultiline Don't use multiline editor module --singleline Use singleline editor module --nosingleline Don't use singleline editor module --colorize Use colorization --nocolorize Don't use colorization --prompt prompt-mode/--prompt-mode prompt-mode Switch prompt mode. Pre-defined prompt modes are `default', `simple', `xmp' and `inf-ruby' --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs. Suppresses --multiline and --singleline. --sample-book-mode/--simple-prompt Simple prompt mode --noprompt No prompt mode --single-irb Share self with sub-irb. --tracer Display trace for each execution of commands. --back-trace-limit n Display backtrace top n and tail n. The default value is 16. --verbose Show details --noverbose Don't show details -v, --version Print the version of irb -h, --help Print help -- Separate options of irb from the list of command-line args # vim:fileencoding=utf-8 PK ]ᣟ##&gems/irb-1.2.6/lib/irb/input-method.rbnu[# frozen_string_literal: false # # irb/input-method.rb - input methods used irb # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative 'src_encoding' require_relative 'magic-file' require_relative 'completion' require 'io/console' require 'reline' module IRB STDIN_FILE_NAME = "(line)" # :nodoc: class InputMethod # Creates a new input method object def initialize(file = STDIN_FILE_NAME) @file_name = file end # The file name of this input method, usually given during initialization. attr_reader :file_name # The irb prompt associated with this input method attr_accessor :prompt # Reads the next line from this input method. # # See IO#gets for more information. def gets fail NotImplementedError, "gets" end public :gets def winsize if instance_variable_defined?(:@stdout) @stdout.winsize else [24, 80] end end # Whether this input method is still readable when there is no more data to # read. # # See IO#eof for more information. def readable_after_eof? false end # For debug message def inspect 'Abstract InputMethod' end end class StdioInputMethod < InputMethod # Creates a new input method object def initialize super @line_no = 0 @line = [] @stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") @stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") end # Reads the next line from this input method. # # See IO#gets for more information. def gets print @prompt line = @stdin.gets @line[@line_no += 1] = line end # Whether the end of this input method has been reached, returns +true+ if # there is no more data to read. # # See IO#eof? for more information. def eof? @stdin.eof? end # Whether this input method is still readable when there is no more data to # read. # # See IO#eof for more information. def readable_after_eof? true end # Returns the current line number for #io. # # #line counts the number of times #gets is called. # # See IO#lineno for more information. def line(line_no) @line[line_no] end # The external encoding for standard input. def encoding @stdin.external_encoding end # For debug message def inspect 'StdioInputMethod' end end # Use a File for IO with irb, see InputMethod class FileInputMethod < InputMethod # Creates a new input method object def initialize(file) super @io = IRB::MagicFile.open(file) end # The file name of this input method, usually given during initialization. attr_reader :file_name # Whether the end of this input method has been reached, returns +true+ if # there is no more data to read. # # See IO#eof? for more information. def eof? @io.eof? end # Reads the next line from this input method. # # See IO#gets for more information. def gets print @prompt @io.gets end # The external encoding for standard input. def encoding @io.external_encoding end # For debug message def inspect 'FileInputMethod' end end begin class ReadlineInputMethod < InputMethod def self.initialize_readline require "readline" rescue LoadError else include ::Readline end # Creates a new input method object using Readline def initialize self.class.initialize_readline if Readline.respond_to?(:encoding_system_needs) IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false) end super @line_no = 0 @line = [] @eof = false @stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") @stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") if Readline.respond_to?("basic_word_break_characters=") Readline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS end Readline.completion_append_character = nil Readline.completion_proc = IRB::InputCompletor::CompletionProc end # Reads the next line from this input method. # # See IO#gets for more information. def gets Readline.input = @stdin Readline.output = @stdout if l = readline(@prompt, false) HISTORY.push(l) if !l.empty? @line[@line_no += 1] = l + "\n" else @eof = true l end end # Whether the end of this input method has been reached, returns +true+ # if there is no more data to read. # # See IO#eof? for more information. def eof? @eof end # Whether this input method is still readable when there is no more data to # read. # # See IO#eof for more information. def readable_after_eof? true end # Returns the current line number for #io. # # #line counts the number of times #gets is called. # # See IO#lineno for more information. def line(line_no) @line[line_no] end # The external encoding for standard input. def encoding @stdin.external_encoding end # For debug message def inspect readline_impl = (defined?(Reline) && Readline == Reline) ? 'Reline' : 'ext/readline' str = "ReadlineInputMethod with #{readline_impl} #{Readline::VERSION}" inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc') str += " and #{inputrc_path}" if File.exist?(inputrc_path) str end end end class ReidlineInputMethod < InputMethod include Reline # Creates a new input method object using Readline def initialize IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false) super @line_no = 0 @line = [] @eof = false @stdin = ::IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") @stdout = ::IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") if Reline.respond_to?("basic_word_break_characters=") Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS end Reline.completion_append_character = nil Reline.completion_proc = IRB::InputCompletor::CompletionProc Reline.output_modifier_proc = if IRB.conf[:USE_COLORIZE] proc do |output, complete: | next unless IRB::Color.colorable? IRB::Color.colorize_code(output, complete: complete) end else proc do |output| Reline::Unicode.escape_for_print(output) end end Reline.dig_perfect_match_proc = IRB::InputCompletor::PerfectMatchedProc end def check_termination(&block) @check_termination_proc = block end def dynamic_prompt(&block) @prompt_proc = block end def auto_indent(&block) @auto_indent_proc = block end # Reads the next line from this input method. # # See IO#gets for more information. def gets Reline.input = @stdin Reline.output = @stdout Reline.prompt_proc = @prompt_proc Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc if l = readmultiline(@prompt, false, &@check_termination_proc) HISTORY.push(l) if !l.empty? @line[@line_no += 1] = l + "\n" else @eof = true l end end # Whether the end of this input method has been reached, returns +true+ # if there is no more data to read. # # See IO#eof? for more information. def eof? @eof end # Whether this input method is still readable when there is no more data to # read. # # See IO#eof for more information. def readable_after_eof? true end # Returns the current line number for #io. # # #line counts the number of times #gets is called. # # See IO#lineno for more information. def line(line_no) @line[line_no] end # The external encoding for standard input. def encoding @stdin.external_encoding end # For debug message def inspect config = Reline::Config.new str = "ReidlineInputMethod with Reline #{Reline::VERSION}" if config.respond_to?(:inputrc_path) inputrc_path = File.expand_path(config.inputrc_path) else inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc') end str += " and #{inputrc_path}" if File.exist?(inputrc_path) str end end end PK ]C5vl$gems/irb-1.2.6/lib/irb/ext/tracer.rbnu[# frozen_string_literal: false # # irb/lib/tracer.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # begin require "tracer" rescue LoadError $stderr.puts "Tracer extension of IRB is enabled but tracer gem doesn't found." module IRB TracerLoadError = true class Context def use_tracer=(opt) # do nothing end end end return # This is about to disable loading below end module IRB # initialize tracing function def IRB.initialize_tracer Tracer.verbose = false Tracer.add_filter { |event, file, line, id, binding, *rests| /^#{Regexp.quote(@CONF[:IRB_LIB_PATH])}/ !~ file and File::basename(file) != "irb.rb" } end class Context # Whether Tracer is used when evaluating statements in this context. # # See +lib/tracer.rb+ for more information. attr_reader :use_tracer alias use_tracer? use_tracer # Sets whether or not to use the Tracer library when evaluating statements # in this context. # # See +lib/tracer.rb+ for more information. def use_tracer=(opt) if opt Tracer.set_get_line_procs(@irb_path) { |line_no, *rests| @io.line(line_no) } elsif !opt && @use_tracer Tracer.off end @use_tracer=opt end end class WorkSpace alias __evaluate__ evaluate # Evaluate the context of this workspace and use the Tracer library to # output the exact lines of code are being executed in chronological order. # # See +lib/tracer.rb+ for more information. def evaluate(context, statements, file = nil, line = nil) if context.use_tracer? && file != nil && line != nil Tracer.on begin __evaluate__(context, statements, file, line) ensure Tracer.off end else __evaluate__(context, statements, file || __FILE__, line || __LINE__) end end end IRB.initialize_tracer end PK ]yr| | $gems/irb-1.2.6/lib/irb/ext/loader.rbnu[# frozen_string_literal: false # # loader.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: # Raised in the event of an exception in a file loaded from an Irb session class LoadAbort < Exception;end # Provides a few commands for loading files within an irb session. # # See ExtendCommandBundle for more information. module IrbLoader alias ruby_load load alias ruby_require require # Loads the given file similarly to Kernel#load def irb_load(fn, priv = nil) path = search_file_from_ruby_path(fn) raise LoadError, "No such file to load -- #{fn}" unless path load_file(path, priv) end def search_file_from_ruby_path(fn) # :nodoc: if /^#{Regexp.quote(File::Separator)}/ =~ fn return fn if File.exist?(fn) return nil end for path in $: if File.exist?(f = File.join(path, fn)) return f end end return nil end # Loads a given file in the current session and displays the source lines # # See Irb#suspend_input_method for more information. def source_file(path) irb.suspend_name(path, File.basename(path)) do irb.suspend_input_method(FileInputMethod.new(path)) do |back_io| irb.signal_status(:IN_LOAD) do if back_io.kind_of?(FileInputMethod) irb.eval_input else begin irb.eval_input rescue LoadAbort print "load abort!!\n" end end end end end end # Loads the given file in the current session's context and evaluates it. # # See Irb#suspend_input_method for more information. def load_file(path, priv = nil) irb.suspend_name(path, File.basename(path)) do if priv ws = WorkSpace.new(Module.new) else ws = WorkSpace.new end irb.suspend_workspace(ws) do irb.suspend_input_method(FileInputMethod.new(path)) do |back_io| irb.signal_status(:IN_LOAD) do if back_io.kind_of?(FileInputMethod) irb.eval_input else begin irb.eval_input rescue LoadAbort print "load abort!!\n" end end end end end end end def old # :nodoc: back_io = @io back_path = @irb_path back_name = @irb_name back_scanner = @irb.scanner begin @io = FileInputMethod.new(path) @irb_name = File.basename(path) @irb_path = path @irb.signal_status(:IN_LOAD) do if back_io.kind_of?(FileInputMethod) @irb.eval_input else begin @irb.eval_input rescue LoadAbort print "load abort!!\n" end end end ensure @io = back_io @irb_name = back_name @irb_path = back_path @irb.scanner = back_scanner end end end end PK ]](  'gems/irb-1.2.6/lib/irb/ext/change-ws.rbnu[# frozen_string_literal: false # # irb/ext/cb.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: class Context # Inherited from +TOPLEVEL_BINDING+. def home_workspace if defined? @home_workspace @home_workspace else @home_workspace = @workspace end end # Changes the current workspace to given object or binding. # # If the optional argument is omitted, the workspace will be # #home_workspace which is inherited from +TOPLEVEL_BINDING+ or the main # object, IRB.conf[:MAIN_CONTEXT] when irb was initialized. # # See IRB::WorkSpace.new for more information. def change_workspace(*_main) if _main.empty? @workspace = home_workspace return main end @workspace = WorkSpace.new(_main[0]) if !(class<IRB.conf[:SAVE_HISTORY] def save_history IRB.conf[:SAVE_HISTORY] end remove_method(:save_history=) if method_defined?(:save_history=) # Sets IRB.conf[:SAVE_HISTORY] to the given +val+ and calls # #init_save_history with this context. # # Will store the number of +val+ entries of history in the #history_file # # Add the following to your +.irbrc+ to change the number of history # entries stored to 1000: # # IRB.conf[:SAVE_HISTORY] = 1000 def save_history=(val) IRB.conf[:SAVE_HISTORY] = val if val main_context = IRB.conf[:MAIN_CONTEXT] main_context = self unless main_context main_context.init_save_history end end # A copy of the default IRB.conf[:HISTORY_FILE] def history_file IRB.conf[:HISTORY_FILE] end # Set IRB.conf[:HISTORY_FILE] to the given +hist+. def history_file=(hist) IRB.conf[:HISTORY_FILE] = hist end end module HistorySavingAbility # :nodoc: def HistorySavingAbility.extended(obj) IRB.conf[:AT_EXIT].push proc{obj.save_history} obj.load_history obj end def load_history return unless self.class.const_defined?(:HISTORY) history = self.class::HISTORY if history_file = IRB.conf[:HISTORY_FILE] history_file = File.expand_path(history_file) end history_file = IRB.rc_file("_history") unless history_file if File.exist?(history_file) open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f| f.each { |l| l = l.chomp if self.class == ReidlineInputMethod and history.last&.end_with?("\\") history.last.delete_suffix!("\\") history.last << "\n" << l else history << l end } end end end def save_history return unless self.class.const_defined?(:HISTORY) history = self.class::HISTORY if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) != 0 if history_file = IRB.conf[:HISTORY_FILE] history_file = File.expand_path(history_file) end history_file = IRB.rc_file("_history") unless history_file # Change the permission of a file that already exists[BUG #7694] begin if File.stat(history_file).mode & 066 != 0 File.chmod(0600, history_file) end rescue Errno::ENOENT rescue Errno::EPERM return rescue raise end open(history_file, "w:#{IRB.conf[:LC_MESSAGES].encoding}", 0600) do |f| hist = history.map{ |l| l.split("\n").join("\\\n") } begin hist = hist.last(num) if hist.size > num and num > 0 rescue RangeError # bignum too big to convert into `long' # Do nothing because the bignum should be treated as inifinity end f.puts(hist) end end end end end PK ]uI'gems/irb-1.2.6/lib/irb/ext/multi-irb.rbnu[# frozen_string_literal: false # # irb/multi-irb.rb - multiple irb module # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # fail CantShiftToMultiIrbMode unless defined?(Thread) module IRB class JobManager # Creates a new JobManager object def initialize @jobs = [] @current_job = nil end # The active irb session attr_accessor :current_job # The total number of irb sessions, used to set +irb_name+ of the current # Context. def n_jobs @jobs.size end # Returns the thread for the given +key+ object, see #search for more # information. def thread(key) th, = search(key) th end # Returns the irb session for the given +key+ object, see #search for more # information. def irb(key) _, irb = search(key) irb end # Returns the top level thread. def main_thread @jobs[0][0] end # Returns the top level irb session. def main_irb @jobs[0][1] end # Add the given +irb+ session to the jobs Array. def insert(irb) @jobs.push [Thread.current, irb] end # Changes the current active irb session to the given +key+ in the jobs # Array. # # Raises an IrbAlreadyDead exception if the given +key+ is no longer alive. # # If the given irb session is already active, an IrbSwitchedToCurrentThread # exception is raised. def switch(key) th, irb = search(key) fail IrbAlreadyDead unless th.alive? fail IrbSwitchedToCurrentThread if th == Thread.current @current_job = irb th.run Thread.stop @current_job = irb(Thread.current) end # Terminates the irb sessions specified by the given +keys+. # # Raises an IrbAlreadyDead exception if one of the given +keys+ is already # terminated. # # See Thread#exit for more information. def kill(*keys) for key in keys th, _ = search(key) fail IrbAlreadyDead unless th.alive? th.exit end end # Returns the associated job for the given +key+. # # If given an Integer, it will return the +key+ index for the jobs Array. # # When an instance of Irb is given, it will return the irb session # associated with +key+. # # If given an instance of Thread, it will return the associated thread # +key+ using Object#=== on the jobs Array. # # Otherwise returns the irb session with the same top-level binding as the # given +key+. # # Raises a NoSuchJob exception if no job can be found with the given +key+. def search(key) job = case key when Integer @jobs[key] when Irb @jobs.find{|k, v| v.equal?(key)} when Thread @jobs.assoc(key) else @jobs.find{|k, v| v.context.main.equal?(key)} end fail NoSuchJob, key if job.nil? job end # Deletes the job at the given +key+. def delete(key) case key when Integer fail NoSuchJob, key unless @jobs[key] @jobs[key] = nil else catch(:EXISTS) do @jobs.each_index do |i| if @jobs[i] and (@jobs[i][0] == key || @jobs[i][1] == key || @jobs[i][1].context.main.equal?(key)) @jobs[i] = nil throw :EXISTS end end fail NoSuchJob, key end end until assoc = @jobs.pop; end unless @jobs.empty? @jobs.push assoc end # Outputs a list of jobs, see the irb command +irb_jobs+, or +jobs+. def inspect ary = [] @jobs.each_index do |i| th, irb = @jobs[i] next if th.nil? if th.alive? if th.stop? t_status = "stop" else t_status = "running" end else t_status = "exited" end ary.push format("#%d->%s on %s (%s: %s)", i, irb.context.irb_name, irb.context.main, th, t_status) end ary.join("\n") end end @JobManager = JobManager.new # The current JobManager in the session def IRB.JobManager @JobManager end # The current Context in this session def IRB.CurrentContext IRB.JobManager.irb(Thread.current).context end # Creates a new IRB session, see Irb.new. # # The optional +file+ argument is given to Context.new, along with the # workspace created with the remaining arguments, see WorkSpace.new def IRB.irb(file = nil, *main) workspace = WorkSpace.new(*main) parent_thread = Thread.current Thread.start do begin irb = Irb.new(workspace, file) rescue print "Subirb can't start with context(self): ", workspace.main.inspect, "\n" print "return to main irb\n" Thread.pass Thread.main.wakeup Thread.exit end @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] @JobManager.insert(irb) @JobManager.current_job = irb begin system_exit = false catch(:IRB_EXIT) do irb.eval_input end rescue SystemExit system_exit = true raise #fail ensure unless system_exit @JobManager.delete(irb) if @JobManager.current_job == irb if parent_thread.alive? @JobManager.current_job = @JobManager.irb(parent_thread) parent_thread.run else @JobManager.current_job = @JobManager.main_irb @JobManager.main_thread.run end end end end end Thread.stop @JobManager.current_job = @JobManager.irb(Thread.current) end @CONF[:SINGLE_IRB_MODE] = false @JobManager.insert(@CONF[:MAIN_CONTEXT].irb) @JobManager.current_job = @CONF[:MAIN_CONTEXT].irb class Irb def signal_handle unless @context.ignore_sigint? print "\nabort!!\n" if @context.verbose? exit end case @signal_status when :IN_INPUT print "^C\n" IRB.JobManager.thread(self).raise RubyLex::TerminateLineInput when :IN_EVAL IRB.irb_abort(self) when :IN_LOAD IRB.irb_abort(self, LoadAbort) when :IN_IRB # ignore else # ignore other cases as well end end end trap("SIGINT") do @JobManager.current_job.signal_handle Thread.stop end end PK ]N9(gems/irb-1.2.6/lib/irb/ext/use-loader.rbnu[# frozen_string_literal: false # # use-loader.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "../cmd/load" require_relative "loader" class Object alias __original__load__IRB_use_loader__ load alias __original__require__IRB_use_loader__ require end module IRB module ExtendCommandBundle remove_method :irb_load if method_defined?(:irb_load) # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load def irb_load(*opts, &b) ExtendCommand::Load.execute(irb_context, *opts, &b) end remove_method :irb_require if method_defined?(:irb_require) # Loads the given file similarly to Kernel#require def irb_require(*opts, &b) ExtendCommand::Require.execute(irb_context, *opts, &b) end end class Context IRB.conf[:USE_LOADER] = false # Returns whether +irb+'s own file reader method is used by # +load+/+require+ or not. # # This mode is globally affected (irb-wide). def use_loader IRB.conf[:USE_LOADER] end alias use_loader? use_loader remove_method :use_loader= if method_defined?(:use_loader=) # Sets IRB.conf[:USE_LOADER] # # See #use_loader for more information. def use_loader=(opt) if IRB.conf[:USE_LOADER] != opt IRB.conf[:USE_LOADER] = opt if opt if !$".include?("irb/cmd/load") end (class<<@workspace.main;self;end).instance_eval { alias_method :load, :irb_load alias_method :require, :irb_require } else (class<<@workspace.main;self;end).instance_eval { alias_method :load, :__original__load__IRB_use_loader__ alias_method :require, :__original__require__IRB_use_loader__ } end end print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose? opt end end end PK ]fcI(gems/irb-1.2.6/lib/irb/ext/workspaces.rbnu[# frozen_string_literal: false # # push-ws.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: class Context # Size of the current WorkSpace stack def irb_level workspace_stack.size end # WorkSpaces in the current stack def workspaces if defined? @workspaces @workspaces else @workspaces = [] end end # Creates a new workspace with the given object or binding, and appends it # onto the current #workspaces stack. # # See IRB::Context#change_workspace and IRB::WorkSpace.new for more # information. def push_workspace(*_main) if _main.empty? if workspaces.empty? print "No other workspace\n" return nil end ws = workspaces.pop workspaces.push @workspace @workspace = ws return workspaces end workspaces.push @workspace @workspace = WorkSpace.new(@workspace.binding, _main[0]) if !(class<IRB.conf[:EVAL_HISTORY] in .irbrc). attr_reader :eval_history # Sets command result history limit. Default value is set from # IRB.conf[:EVAL_HISTORY]. # # +no+ is an Integer or +nil+. # # Returns +no+ of history items if greater than 0. # # If +no+ is 0, the number of history items is unlimited. # # If +no+ is +nil+, execution result history isn't used (default). # # History values are available via __ variable, see # IRB::History. def eval_history=(no) if no if defined?(@eval_history) && @eval_history @eval_history_values.size(no) else @eval_history_values = History.new(no) IRB.conf[:__TMP__EHV__] = @eval_history_values @workspace.evaluate(self, "__ = IRB.conf[:__TMP__EHV__]") IRB.conf.delete(:__TMP_EHV__) end else @eval_history_values = nil end @eval_history = no end end # Represents history of results of previously evaluated commands. # # Available via __ variable, only if IRB.conf[:EVAL_HISTORY] # or IRB::CurrentContext().eval_history is non-nil integer value # (by default it is +nil+). # # Example (in `irb`): # # # Initialize history # IRB::CurrentContext().eval_history = 10 # # => 10 # # # Perform some commands... # 1 + 2 # # => 3 # puts 'x' # # x # # => nil # raise RuntimeError # # ...error raised # # # Inspect history (format is " ": # __ # # => 1 10 # # 2 3 # # 3 nil # # __[1] # # => 10 # class History def initialize(size = 16) # :nodoc: @size = size @contents = [] end def size(size) # :nodoc: if size != 0 && size < @size @contents = @contents[@size - size .. @size] end @size = size end # Get one item of the content (both positive and negative indexes work). def [](idx) begin if idx >= 0 @contents.find{|no, val| no == idx}[1] else @contents[idx][1] end rescue NameError nil end end def push(no, val) # :nodoc: @contents.push [no, val] @contents.shift if @size != 0 && @contents.size > @size end alias real_inspect inspect def inspect # :nodoc: if @contents.empty? return real_inspect end unless (last = @contents.pop)[1].equal?(self) @contents.push last last = nil end str = @contents.collect{|no, val| if val.equal?(self) "#{no} ...self-history..." else "#{no} #{val.inspect}" end }.join("\n") if str == "" str = "Empty." end @contents.push last if last str end end end PK ]:?cBcB"gems/irb-1.2.6/lib/irb/ruby-lex.rbnu[# frozen_string_literal: false # # irb/ruby-lex.rb - ruby lexcal analyzer # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "ripper" require "jruby" if RUBY_ENGINE == "jruby" # :stopdoc: class RubyLex class TerminateLineInput < StandardError def initialize super("Terminate Line Input") end end def initialize @exp_line_no = @line_no = 1 @indent = 0 @continue = false @line = "" @prompt = nil end def self.compile_with_errors_suppressed(code) line_no = 1 begin result = yield code, line_no rescue ArgumentError code = ";\n#{code}" line_no = 0 result = yield code, line_no end result end # io functions def set_input(io, p = nil, &block) @io = io if @io.respond_to?(:check_termination) @io.check_termination do |code| code.gsub!(/\s*\z/, '').concat("\n") ltype, indent, continue, code_block_open = check_state(code) if ltype or indent > 0 or continue or code_block_open false else true end end end if @io.respond_to?(:dynamic_prompt) @io.dynamic_prompt do |lines| lines << '' if lines.empty? result = [] lines.each_index { |i| c = lines[0..i].map{ |l| l + "\n" }.join ltype, indent, continue, code_block_open = check_state(c) result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + i) } result end end if p.respond_to?(:call) @input = p elsif block_given? @input = block else @input = Proc.new{@io.gets} end end def set_prompt(p = nil, &block) p = block if block_given? if p.respond_to?(:call) @prompt = p else @prompt = Proc.new{print p} end end def ripper_lex_without_warning(code) verbose, $VERBOSE = $VERBOSE, nil tokens = nil self.class.compile_with_errors_suppressed(code) do |inner_code, line_no| tokens = Ripper.lex(inner_code, '-', line_no) end $VERBOSE = verbose tokens end def set_auto_indent(context) if @io.respond_to?(:auto_indent) and context.auto_indent_mode @io.auto_indent do |lines, line_index, byte_pointer, is_newline| if is_newline md = lines[line_index - 1].match(/(\A +)/) prev_spaces = md.nil? ? 0 : md[1].count(' ') @tokens = ripper_lex_without_warning(lines[0..line_index].join("\n")) depth_difference = check_newline_depth_difference prev_spaces + depth_difference * 2 else code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join last_line = lines[line_index]&.byteslice(0, byte_pointer) code += last_line if last_line @tokens = ripper_lex_without_warning(code) corresponding_token_depth = check_corresponding_token_depth if corresponding_token_depth corresponding_token_depth else nil end end end end end def check_state(code) @tokens = ripper_lex_without_warning(code) ltype = process_literal_type indent = process_nesting_level continue = process_continue code_block_open = check_code_block(code) [ltype, indent, continue, code_block_open] end def prompt if @prompt @prompt.call(@ltype, @indent, @continue, @line_no) end end def initialize_input @ltype = nil @indent = 0 @continue = false @line = "" @exp_line_no = @line_no @code_block_open = false end def each_top_level_statement initialize_input catch(:TERM_INPUT) do loop do begin prompt unless l = lex throw :TERM_INPUT if @line == '' else @line_no += l.count("\n") next if l == "\n" @line.concat l if @code_block_open or @ltype or @continue or @indent > 0 next end end if @line != "\n" @line.force_encoding(@io.encoding) yield @line, @exp_line_no end break if @io.eof? @line = '' @exp_line_no = @line_no @indent = 0 rescue TerminateLineInput initialize_input prompt end end end end def lex line = @input.call if @io.respond_to?(:check_termination) return line # multiline end code = @line + (line.nil? ? '' : line) code.gsub!(/\s*\z/, '').concat("\n") @tokens = ripper_lex_without_warning(code) @continue = process_continue @code_block_open = check_code_block(code) @indent = process_nesting_level @ltype = process_literal_type line end def process_continue # last token is always newline if @tokens.size >= 2 and @tokens[-2][1] == :on_regexp_end # end of regexp literal return false elsif @tokens.size >= 2 and @tokens[-2][1] == :on_semicolon return false elsif @tokens.size >= 2 and @tokens[-2][1] == :on_kw and ['begin', 'else', 'ensure'].include?(@tokens[-2][2]) return false elsif !@tokens.empty? and @tokens.last[2] == "\\\n" return true elsif @tokens.size >= 1 and @tokens[-1][1] == :on_heredoc_end # "EOH\n" return false elsif @tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and @tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME) # end of literal except for regexp return true end false end def check_code_block(code) return true if @tokens.empty? if @tokens.last[1] == :on_heredoc_beg return true end begin # check if parser error are available verbose, $VERBOSE = $VERBOSE, nil case RUBY_ENGINE when 'jruby' JRuby.compile_ir(code) else self.class.compile_with_errors_suppressed(code) do |inner_code, line_no| RubyVM::InstructionSequence.compile(inner_code, nil, nil, line_no) end end rescue EncodingError # This is for a hash with invalid encoding symbol, {"\xAE": 1} rescue SyntaxError => e case e.message when /unterminated (?:string|regexp) meets end of file/ # "unterminated regexp meets end of file" # # example: # / # # "unterminated string meets end of file" # # example: # ' return true when /syntax error, unexpected end-of-input/ # "syntax error, unexpected end-of-input, expecting keyword_end" # # example: # if ture # hoge # if false # fuga # end return true when /syntax error, unexpected keyword_end/ # "syntax error, unexpected keyword_end" # # example: # if ( # end # # example: # end return false when /syntax error, unexpected '\.'/ # "syntax error, unexpected '.'" # # example: # . return false when /unexpected tREGEXP_BEG/ # "syntax error, unexpected tREGEXP_BEG, expecting keyword_do or '{' or '('" # # example: # method / f / return false end ensure $VERBOSE = verbose end if defined?(Ripper::EXPR_BEG) last_lex_state = @tokens.last[3] if last_lex_state.allbits?(Ripper::EXPR_BEG) return false elsif last_lex_state.allbits?(Ripper::EXPR_DOT) return true elsif last_lex_state.allbits?(Ripper::EXPR_CLASS) return true elsif last_lex_state.allbits?(Ripper::EXPR_FNAME) return true elsif last_lex_state.allbits?(Ripper::EXPR_VALUE) return true elsif last_lex_state.allbits?(Ripper::EXPR_ARG) return false end end false end def process_nesting_level indent = 0 in_oneliner_def = nil @tokens.each_with_index { |t, index| # detecting one-liner method definition if in_oneliner_def.nil? if t[3].allbits?(Ripper::EXPR_ENDFN) in_oneliner_def = :ENDFN end else if t[3].allbits?(Ripper::EXPR_ENDFN) # continuing elsif t[3].allbits?(Ripper::EXPR_BEG) if t[2] == '=' in_oneliner_def = :BODY end elsif t[3].allbits?(Ripper::EXPR_END) if in_oneliner_def == :BODY # one-liner method definition indent -= 1 end in_oneliner_def = nil else in_oneliner_def = nil end end case t[1] when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg indent += 1 when :on_rbracket, :on_rbrace, :on_rparen indent -= 1 when :on_kw next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME) case t[2] when 'do' if index > 0 and @tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG) # method_with_block do; end indent += 1 else # while cond do; end # also "until" or "for" # This "do" doesn't increment indent because "while" already # incremented. end when 'def', 'case', 'for', 'begin', 'class', 'module' indent += 1 when 'if', 'unless', 'while', 'until' # postfix if/unless/while/until must be Ripper::EXPR_LABEL indent += 1 unless t[3].allbits?(Ripper::EXPR_LABEL) when 'end' indent -= 1 end end # percent literals are not indented } indent end def check_newline_depth_difference depth_difference = 0 open_brace_on_line = 0 in_oneliner_def = nil @tokens.each_with_index do |t, index| # detecting one-liner method definition if in_oneliner_def.nil? if t[3].allbits?(Ripper::EXPR_ENDFN) in_oneliner_def = :ENDFN end else if t[3].allbits?(Ripper::EXPR_ENDFN) # continuing elsif t[3].allbits?(Ripper::EXPR_BEG) if t[2] == '=' in_oneliner_def = :BODY end elsif t[3].allbits?(Ripper::EXPR_END) if in_oneliner_def == :BODY # one[-liner method definition depth_difference -= 1 end in_oneliner_def = nil else in_oneliner_def = nil end end case t[1] when :on_ignored_nl, :on_nl, :on_comment if index != (@tokens.size - 1) depth_difference = 0 open_brace_on_line = 0 end next when :on_sp next end case t[1] when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg depth_difference += 1 open_brace_on_line += 1 when :on_rbracket, :on_rbrace, :on_rparen depth_difference -= 1 if open_brace_on_line > 0 when :on_kw next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME) case t[2] when 'do' if index > 0 and @tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG) # method_with_block do; end depth_difference += 1 else # while cond do; end # also "until" or "for" # This "do" doesn't increment indent because "while" already # incremented. end when 'def', 'case', 'for', 'begin', 'class', 'module' depth_difference += 1 when 'if', 'unless', 'while', 'until', 'rescue' # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL unless t[3].allbits?(Ripper::EXPR_LABEL) depth_difference += 1 end when 'else', 'elsif', 'ensure', 'when', 'in' depth_difference += 1 end end end depth_difference end def check_corresponding_token_depth corresponding_token_depth = nil is_first_spaces_of_line = true is_first_printable_of_line = true spaces_of_nest = [] spaces_at_line_head = 0 open_brace_on_line = 0 in_oneliner_def = nil @tokens.each_with_index do |t, index| # detecting one-liner method definition if in_oneliner_def.nil? if t[3].allbits?(Ripper::EXPR_ENDFN) in_oneliner_def = :ENDFN end else if t[3].allbits?(Ripper::EXPR_ENDFN) # continuing elsif t[3].allbits?(Ripper::EXPR_BEG) if t[2] == '=' in_oneliner_def = :BODY end elsif t[3].allbits?(Ripper::EXPR_END) if in_oneliner_def == :BODY # one-liner method definition if is_first_printable_of_line corresponding_token_depth = spaces_of_nest.pop else spaces_of_nest.pop corresponding_token_depth = nil end end in_oneliner_def = nil else in_oneliner_def = nil end end case t[1] when :on_ignored_nl, :on_nl, :on_comment corresponding_token_depth = nil spaces_at_line_head = 0 is_first_spaces_of_line = true is_first_printable_of_line = true open_brace_on_line = 0 next when :on_sp spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line is_first_spaces_of_line = false next end case t[1] when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg spaces_of_nest.push(spaces_at_line_head + open_brace_on_line * 2) open_brace_on_line += 1 when :on_rbracket, :on_rbrace, :on_rparen if is_first_printable_of_line corresponding_token_depth = spaces_of_nest.pop else spaces_of_nest.pop corresponding_token_depth = nil end open_brace_on_line -= 1 when :on_kw next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME) case t[2] when 'def', 'do', 'case', 'for', 'begin', 'class', 'module' spaces_of_nest.push(spaces_at_line_head) when 'rescue' unless t[3].allbits?(Ripper::EXPR_LABEL) corresponding_token_depth = spaces_of_nest.last end when 'if', 'unless', 'while', 'until' # postfix if/unless/while/until must be Ripper::EXPR_LABEL unless t[3].allbits?(Ripper::EXPR_LABEL) spaces_of_nest.push(spaces_at_line_head) end when 'else', 'elsif', 'ensure', 'when', 'in' corresponding_token_depth = spaces_of_nest.last when 'end' if is_first_printable_of_line corresponding_token_depth = spaces_of_nest.pop else spaces_of_nest.pop corresponding_token_depth = nil end end end is_first_spaces_of_line = false is_first_printable_of_line = false end corresponding_token_depth end def check_string_literal i = 0 start_token = [] end_type = [] while i < @tokens.size t = @tokens[i] case t[1] when :on_tstring_beg start_token << t end_type << [:on_tstring_end, :on_label_end] when :on_regexp_beg start_token << t end_type << :on_regexp_end when :on_symbeg acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw} if (i + 1) < @tokens.size and acceptable_single_tokens.all?{ |t| @tokens[i + 1][1] != t } start_token << t end_type << :on_tstring_end end when :on_backtick start_token << t end_type << :on_tstring_end when :on_qwords_beg, :on_words_beg, :on_qsymbols_beg, :on_symbols_beg start_token << t end_type << :on_tstring_end when :on_heredoc_beg start_token << t end_type << :on_heredoc_end when *end_type.last start_token.pop end_type.pop end i += 1 end start_token.last.nil? ? '' : start_token.last end def process_literal_type start_token = check_string_literal case start_token[1] when :on_tstring_beg case start_token[2] when ?" then ?" when /^%.$/ then ?" when /^%Q.$/ then ?" when ?' then ?' when /^%q.$/ then ?' end when :on_regexp_beg then ?/ when :on_symbeg then ?: when :on_backtick then ?` when :on_qwords_beg then ?] when :on_words_beg then ?] when :on_qsymbols_beg then ?] when :on_symbols_beg then ?] when :on_heredoc_beg start_token[2] =~ /<<[-~]?(['"`])[_a-zA-Z0-9]+\1/ case $1 when ?" then ?" when ?' then ?' when ?` then ?` else ?" end else nil end end end # :startdoc: PK ]wgems/irb-1.2.6/lib/irb/color.rbnu[# frozen_string_literal: true require 'reline' require 'ripper' require 'irb/ruby-lex' module IRB # :nodoc: module Color CLEAR = 0 BOLD = 1 UNDERLINE = 4 REVERSE = 7 RED = 31 GREEN = 32 YELLOW = 33 BLUE = 34 MAGENTA = 35 CYAN = 36 TOKEN_KEYWORDS = { on_kw: ['nil', 'self', 'true', 'false', '__FILE__', '__LINE__'], on_const: ['ENV'], } private_constant :TOKEN_KEYWORDS # A constant of all-bit 1 to match any Ripper's state in #dispatch_seq ALL = -1 private_constant :ALL begin # Following pry's colors where possible, but sometimes having a compromise like making # backtick and regexp as red (string's color, because they're sharing tokens). TOKEN_SEQ_EXPRS = { on_CHAR: [[BLUE, BOLD], ALL], on_backtick: [[RED, BOLD], ALL], on_comment: [[BLUE, BOLD], ALL], on_const: [[BLUE, BOLD, UNDERLINE], ALL], on_embexpr_beg: [[RED], ALL], on_embexpr_end: [[RED], ALL], on_embvar: [[RED], ALL], on_float: [[MAGENTA, BOLD], ALL], on_gvar: [[GREEN, BOLD], ALL], on_heredoc_beg: [[RED], ALL], on_heredoc_end: [[RED], ALL], on_ident: [[BLUE, BOLD], Ripper::EXPR_ENDFN], on_imaginary: [[BLUE, BOLD], ALL], on_int: [[BLUE, BOLD], ALL], on_kw: [[GREEN], ALL], on_label: [[MAGENTA], ALL], on_label_end: [[RED, BOLD], ALL], on_qsymbols_beg: [[RED, BOLD], ALL], on_qwords_beg: [[RED, BOLD], ALL], on_rational: [[BLUE, BOLD], ALL], on_regexp_beg: [[RED, BOLD], ALL], on_regexp_end: [[RED, BOLD], ALL], on_symbeg: [[YELLOW], ALL], on_symbols_beg: [[RED, BOLD], ALL], on_tstring_beg: [[RED, BOLD], ALL], on_tstring_content: [[RED], ALL], on_tstring_end: [[RED, BOLD], ALL], on_words_beg: [[RED, BOLD], ALL], on_parse_error: [[RED, REVERSE], ALL], compile_error: [[RED, REVERSE], ALL], } rescue NameError # Give up highlighting Ripper-incompatible older Ruby TOKEN_SEQ_EXPRS = {} end private_constant :TOKEN_SEQ_EXPRS class << self def colorable? $stdout.tty? && supported? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb')) end def inspect_colorable?(obj, seen: {}.compare_by_identity) case obj when String, Symbol, Regexp, Integer, Float, FalseClass, TrueClass, NilClass true when Hash without_circular_ref(obj, seen: seen) do obj.all? { |k, v| inspect_colorable?(k, seen: seen) && inspect_colorable?(v, seen: seen) } end when Array without_circular_ref(obj, seen: seen) do obj.all? { |o| inspect_colorable?(o, seen: seen) } end when Range inspect_colorable?(obj.begin, seen: seen) && inspect_colorable?(obj.end, seen: seen) when Module !obj.name.nil? else false end end def clear return '' unless colorable? "\e[#{CLEAR}m" end def colorize(text, seq) return text unless colorable? seq = seq.map { |s| "\e[#{const_get(s)}m" }.join('') "#{seq}#{text}#{clear}" end # If `complete` is false (code is incomplete), this does not warn compile_error. # This option is needed to avoid warning a user when the compile_error is happening # because the input is not wrong but just incomplete. def colorize_code(code, complete: true) return code unless colorable? symbol_state = SymbolState.new colored = +'' length = 0 scan(code, allow_last_error: !complete) do |token, str, expr| in_symbol = symbol_state.scan_token(token) str.each_line do |line| line = Reline::Unicode.escape_for_print(line) if seq = dispatch_seq(token, expr, line, in_symbol: in_symbol) colored << seq.map { |s| "\e[#{s}m" }.join('') colored << line.sub(/\Z/, clear) else colored << line end end length += str.bytesize end # give up colorizing incomplete Ripper tokens if length != code.bytesize return Reline::Unicode.escape_for_print(code) end colored end private def without_circular_ref(obj, seen:, &block) return false if seen.key?(obj) seen[obj] = true block.call ensure seen.delete(obj) end def supported? return @supported if defined?(@supported) @supported = Ripper::Lexer::Elem.method_defined?(:state) end def scan(code, allow_last_error:) pos = [1, 0] verbose, $VERBOSE = $VERBOSE, nil RubyLex.compile_with_errors_suppressed(code) do |inner_code, line_no| lexer = Ripper::Lexer.new(inner_code, '(ripper)', line_no) if lexer.respond_to?(:scan) # Ruby 2.7+ lexer.scan.each do |elem| str = elem.tok next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message next if ([elem.pos[0], elem.pos[1] + str.bytesize] <=> pos) <= 0 str.each_line do |line| if line.end_with?("\n") pos[0] += 1 pos[1] = 0 else pos[1] += line.bytesize end end yield(elem.event, str, elem.state) end else lexer.parse.each do |elem| yield(elem.event, elem.tok, elem.state) end end end $VERBOSE = verbose end def dispatch_seq(token, expr, str, in_symbol:) if token == :on_parse_error or token == :compile_error TOKEN_SEQ_EXPRS[token][0] elsif in_symbol [YELLOW] elsif TOKEN_KEYWORDS.fetch(token, []).include?(str) [CYAN, BOLD] elsif (seq, exprs = TOKEN_SEQ_EXPRS[token]; (expr & (exprs || 0)) != 0) seq else nil end end end # A class to manage a state to know whether the current token is for Symbol or not. class SymbolState def initialize # Push `true` to detect Symbol. `false` to increase the nest level for non-Symbol. @stack = [] end # Return true if the token is a part of Symbol. def scan_token(token) prev_state = @stack.last case token when :on_symbeg, :on_symbols_beg, :on_qsymbols_beg @stack << true when :on_ident, :on_op, :on_const, :on_ivar, :on_cvar, :on_gvar, :on_kw if @stack.last # Pop only when it's Symbol @stack.pop return prev_state end when :on_tstring_beg @stack << false when :on_embexpr_beg @stack << false return prev_state when :on_tstring_end # :on_tstring_end may close Symbol @stack.pop return prev_state when :on_embexpr_end @stack.pop end @stack.last end end private_constant :SymbolState end end PK ]yk/AA gems/irb-1.2.6/lib/irb/locale.rbnu[# frozen_string_literal: false # # irb/locale.rb - internationalization module # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: class Locale LOCALE_NAME_RE = %r[ (?[[:alpha:]]{2,3}) (?:_ (?[[:alpha:]]{2,3}) )? (?:\. (?[^@]+) )? (?:@ (?.*) )? ]x LOCALE_DIR = "/lc/" @@legacy_encoding_alias_map = {}.freeze @@loaded = [] def initialize(locale = nil) @override_encoding = nil @lang = @territory = @encoding_name = @modifier = nil @locale = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] || "C" if m = LOCALE_NAME_RE.match(@locale) @lang, @territory, @encoding_name, @modifier = m[:language], m[:territory], m[:codeset], m[:modifier] if @encoding_name begin load 'irb/encoding_aliases.rb'; rescue LoadError; end if @encoding = @@legacy_encoding_alias_map[@encoding_name] warn(("%s is obsolete. use %s" % ["#{@lang}_#{@territory}.#{@encoding_name}", "#{@lang}_#{@territory}.#{@encoding.name}"]), uplevel: 1) end @encoding = Encoding.find(@encoding_name) rescue nil end end @encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT) end attr_reader :lang, :territory, :modifier def encoding @override_encoding || @encoding end def String(mes) mes = super(mes) if encoding mes.encode(encoding, undef: :replace) else mes end end def format(*opts) String(super(*opts)) end def gets(*rs) String(super(*rs)) end def readline(*rs) String(super(*rs)) end def print(*opts) ary = opts.collect{|opt| String(opt)} super(*ary) end def printf(*opts) s = format(*opts) print s end def puts(*opts) ary = opts.collect{|opt| String(opt)} super(*ary) end def require(file, priv = nil) rex = Regexp.new("lc/#{Regexp.quote(file)}\.(so|o|sl|rb)?") return false if $".find{|f| f =~ rex} case file when /\.rb$/ begin load(file, priv) $".push file return true rescue LoadError end when /\.(so|o|sl)$/ return super end begin load(f = file + ".rb") $".push f #" return true rescue LoadError return ruby_require(file) end end alias toplevel_load load def load(file, priv=nil) found = find(file) if found unless @@loaded.include?(found) @@loaded << found # cache return real_load(found, priv) end else raise LoadError, "No such file to load -- #{file}" end end def find(file , paths = $:) dir = File.dirname(file) dir = "" if dir == "." base = File.basename(file) if dir.start_with?('/') return each_localized_path(dir, base).find{|full_path| File.readable? full_path} else return search_file(paths, dir, base) end end private def real_load(path, priv) src = MagicFile.open(path){|f| f.read} if priv eval("self", TOPLEVEL_BINDING).extend(Module.new {eval(src, nil, path)}) else eval(src, TOPLEVEL_BINDING, path) end end # @param paths load paths in which IRB find a localized file. # @param dir directory # @param file basename to be localized # # typically, for the parameters and a in paths, it searches # /

// def search_file(lib_paths, dir, file) each_localized_path(dir, file) do |lc_path| lib_paths.each do |libpath| full_path = File.join(libpath, lc_path) return full_path if File.readable?(full_path) end redo if defined?(Gem) and Gem.try_activate(lc_path) end nil end def each_localized_path(dir, file) return enum_for(:each_localized_path) unless block_given? each_sublocale do |lc| yield lc.nil? ? File.join(dir, LOCALE_DIR, file) : File.join(dir, LOCALE_DIR, lc, file) end end def each_sublocale if @lang if @territory if @encoding_name yield "#{@lang}_#{@territory}.#{@encoding_name}@#{@modifier}" if @modifier yield "#{@lang}_#{@territory}.#{@encoding_name}" end yield "#{@lang}_#{@territory}@#{@modifier}" if @modifier yield "#{@lang}_#{@territory}" end if @encoding_name yield "#{@lang}.#{@encoding_name}@#{@modifier}" if @modifier yield "#{@lang}.#{@encoding_name}" end yield "#{@lang}@#{@modifier}" if @modifier yield "#{@lang}" end yield nil end end end PK ]pp$gems/irb-1.2.6/lib/irb/easter-egg.rbnu[require "reline" module IRB class << self class Vec def initialize(x, y, z) @x, @y, @z = x, y, z end attr_reader :x, :y, :z def sub(other) Vec.new(@x - other.x, @y - other.y, @z - other.z) end def dot(other) @x*other.x + @y*other.y + @z*other.z end def cross(other) ox, oy, oz = other.x, other.y, other.z Vec.new(@y*oz-@z*oy, @z*ox-@x*oz, @x*oy-@y*ox) end def normalize r = Math.sqrt(self.dot(self)) Vec.new(@x / r, @y / r, @z / r) end end class Canvas def initialize((h, w)) @data = (0..h-2).map { [0] * w } @scale = [w / 2.0, h-2].min @center = Complex(w / 2, h-2) end def line((x1, y1), (x2, y2)) p1 = Complex(x1, y1) / 2 * @scale + @center p2 = Complex(x2, y2) / 2 * @scale + @center line0(p1, p2) end private def line0(p1, p2) mid = (p1 + p2) / 2 if (p1 - p2).abs < 1 x, y = mid.rect @data[y / 2][x] |= (y % 2 > 1 ? 2 : 1) else line0(p1, mid) line0(p2, mid) end end def draw @data.each {|row| row.fill(0) } yield @data.map {|row| row.map {|n| " ',;"[n] }.join }.join("\n") end end class RubyModel def initialize @faces = init_ruby_model end def init_ruby_model cap_vertices = (0..5).map {|i| Vec.new(*Complex.polar(1, i * Math::PI / 3).rect, 1) } middle_vertices = (0..5).map {|i| Vec.new(*Complex.polar(2, (i + 0.5) * Math::PI / 3).rect, 0) } bottom_vertex = Vec.new(0, 0, -2) faces = [cap_vertices] 6.times do |j| i = j-1 faces << [cap_vertices[i], middle_vertices[i], cap_vertices[j]] faces << [cap_vertices[j], middle_vertices[i], middle_vertices[j]] faces << [middle_vertices[i], bottom_vertex, middle_vertices[j]] end faces end def render_frame(i) angle = i / 10.0 dir = Vec.new(*Complex.polar(1, angle).rect, Math.sin(angle)).normalize dir2 = Vec.new(*Complex.polar(1, angle - Math::PI/2).rect, 0) up = dir.cross(dir2) nm = dir.cross(up) @faces.each do |vertices| v0, v1, v2, = vertices if v1.sub(v0).cross(v2.sub(v0)).dot(dir) > 0 points = vertices.map {|p| [nm.dot(p), up.dot(p)] } (points + [points[0]]).each_cons(2) do |p1, p2| yield p1, p2 end end end end end private def easter_egg(type = nil) type ||= [:logo, :dancing].sample case type when :logo File.open(File.join(__dir__, 'ruby_logo.aa')) do |f| require "rdoc" RDoc::RI::Driver.new.page do |io| IO.copy_stream(f, io) end end when :dancing begin canvas = Canvas.new(Reline.get_screen_size) Reline::IOGate.set_winch_handler do canvas = Canvas.new(Reline.get_screen_size) end ruby_model = RubyModel.new print "\e[?1049h" 0.step do |i| # TODO (0..).each needs Ruby 2.6 or later buff = canvas.draw do ruby_model.render_frame(i) do |p1, p2| canvas.line(p1, p2) end end buff[0, 20] = "\e[0mPress Ctrl+C to stop\e[31m\e[1m" print "\e[H" + buff sleep 0.05 end ensure print "\e[0m\e[?1049l" end end end end end IRB.send(:easter_egg, ARGV[0]&.to_sym) if $0 == __FILE__ PK ]fɁc"c"gems/irb-1.2.6/lib/irb/init.rbnu[# frozen_string_literal: false # # irb/init.rb - irb initialize module # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: # initialize config def IRB.setup(ap_path, argv: ::ARGV) IRB.init_config(ap_path) IRB.init_error IRB.parse_opts(argv: argv) IRB.run_config IRB.load_modules unless @CONF[:PROMPT][@CONF[:PROMPT_MODE]] fail UndefinedPromptMode, @CONF[:PROMPT_MODE] end end # @CONF default setting def IRB.init_config(ap_path) # class instance variables @TRACER_INITIALIZED = false # default configurations unless ap_path and @CONF[:AP_NAME] ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb") end @CONF[:AP_NAME] = File::basename(ap_path, ".rb") @CONF[:IRB_NAME] = "irb" @CONF[:IRB_LIB_PATH] = File.dirname(__FILE__) @CONF[:RC] = true @CONF[:LOAD_MODULES] = [] @CONF[:IRB_RC] = nil @CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod) @CONF[:USE_COLORIZE] = true @CONF[:INSPECT_MODE] = true @CONF[:USE_TRACER] = false @CONF[:USE_LOADER] = false @CONF[:IGNORE_SIGINT] = true @CONF[:IGNORE_EOF] = false @CONF[:ECHO] = nil @CONF[:ECHO_ON_ASSIGNMENT] = nil @CONF[:OMIT_ON_ASSIGNMENT] = nil @CONF[:VERBOSE] = nil @CONF[:EVAL_HISTORY] = nil @CONF[:SAVE_HISTORY] = 1000 @CONF[:BACK_TRACE_LIMIT] = 16 @CONF[:PROMPT] = { :NULL => { :PROMPT_I => nil, :PROMPT_N => nil, :PROMPT_S => nil, :PROMPT_C => nil, :RETURN => "%s\n" }, :DEFAULT => { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_N => "%N(%m):%03n:%i> ", :PROMPT_S => "%N(%m):%03n:%i%l ", :PROMPT_C => "%N(%m):%03n:%i* ", :RETURN => "=> %s\n" }, :CLASSIC => { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_N => "%N(%m):%03n:%i> ", :PROMPT_S => "%N(%m):%03n:%i%l ", :PROMPT_C => "%N(%m):%03n:%i* ", :RETURN => "%s\n" }, :SIMPLE => { :PROMPT_I => ">> ", :PROMPT_N => ">> ", :PROMPT_S => "%l> ", :PROMPT_C => "?> ", :RETURN => "=> %s\n" }, :INF_RUBY => { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_N => nil, :PROMPT_S => nil, :PROMPT_C => nil, :RETURN => "%s\n", :AUTO_INDENT => true }, :XMP => { :PROMPT_I => nil, :PROMPT_N => nil, :PROMPT_S => nil, :PROMPT_C => nil, :RETURN => " ==>%s\n" } } @CONF[:PROMPT_MODE] = (STDIN.tty? ? :DEFAULT : :NULL) @CONF[:AUTO_INDENT] = true @CONF[:CONTEXT_MODE] = 3 # use binding in function on TOPLEVEL_BINDING @CONF[:SINGLE_IRB] = false @CONF[:LC_MESSAGES] = Locale.new @CONF[:AT_EXIT] = [] end def IRB.init_error @CONF[:LC_MESSAGES].load("irb/error.rb") end # option analyzing def IRB.parse_opts(argv: ::ARGV) load_path = [] while opt = argv.shift case opt when "-f" @CONF[:RC] = false when "-d" $DEBUG = true $VERBOSE = true when "-w" $VERBOSE = true when /^-W(.+)?/ opt = $1 || argv.shift case opt when "0" $VERBOSE = nil when "1" $VERBOSE = false else $VERBOSE = true end when /^-r(.+)?/ opt = $1 || argv.shift @CONF[:LOAD_MODULES].push opt if opt when /^-I(.+)?/ opt = $1 || argv.shift load_path.concat(opt.split(File::PATH_SEPARATOR)) if opt when '-U' set_encoding("UTF-8", "UTF-8") when /^-E(.+)?/, /^--encoding(?:=(.+))?/ opt = $1 || argv.shift set_encoding(*opt.split(':', 2)) when "--inspect" if /^-/ !~ argv.first @CONF[:INSPECT_MODE] = argv.shift else @CONF[:INSPECT_MODE] = true end when "--noinspect" @CONF[:INSPECT_MODE] = false when "--singleline", "--readline", "--legacy" @CONF[:USE_SINGLELINE] = true when "--nosingleline", "--noreadline" @CONF[:USE_SINGLELINE] = false when "--multiline", "--reidline" @CONF[:USE_MULTILINE] = true when "--nomultiline", "--noreidline" @CONF[:USE_MULTILINE] = false when "--echo" @CONF[:ECHO] = true when "--noecho" @CONF[:ECHO] = false when "--echo-on-assignment" @CONF[:ECHO_ON_ASSIGNMENT] = true when "--noecho-on-assignment" @CONF[:ECHO_ON_ASSIGNMENT] = false when "--omit-on-assignment" @CONF[:OMIT_ON_ASSIGNMENT] = true when "--noomit-on-assignment" @CONF[:OMIT_ON_ASSIGNMENT] = false when "--verbose" @CONF[:VERBOSE] = true when "--noverbose" @CONF[:VERBOSE] = false when "--colorize" @CONF[:USE_COLORIZE] = true when "--nocolorize" @CONF[:USE_COLORIZE] = false when /^--prompt-mode(?:=(.+))?/, /^--prompt(?:=(.+))?/ opt = $1 || argv.shift prompt_mode = opt.upcase.tr("-", "_").intern @CONF[:PROMPT_MODE] = prompt_mode when "--noprompt" @CONF[:PROMPT_MODE] = :NULL when "--inf-ruby-mode" @CONF[:PROMPT_MODE] = :INF_RUBY when "--sample-book-mode", "--simple-prompt" @CONF[:PROMPT_MODE] = :SIMPLE when "--tracer" @CONF[:USE_TRACER] = true when /^--back-trace-limit(?:=(.+))?/ @CONF[:BACK_TRACE_LIMIT] = ($1 || argv.shift).to_i when /^--context-mode(?:=(.+))?/ @CONF[:CONTEXT_MODE] = ($1 || argv.shift).to_i when "--single-irb" @CONF[:SINGLE_IRB] = true when "-v", "--version" print IRB.version, "\n" exit 0 when "-h", "--help" require_relative "help" IRB.print_usage exit 0 when "--" if opt = argv.shift @CONF[:SCRIPT] = opt $0 = opt end break when /^-/ fail UnrecognizedSwitch, opt else @CONF[:SCRIPT] = opt $0 = opt break end end load_path.collect! do |path| /\A\.\// =~ path ? path : File.expand_path(path) end $LOAD_PATH.unshift(*load_path) end # running config def IRB.run_config if @CONF[:RC] begin load rc_file rescue LoadError, Errno::ENOENT rescue # StandardError, ScriptError print "load error: #{rc_file}\n" print $!.class, ": ", $!, "\n" for err in $@[0, $@.size - 2] print "\t", err, "\n" end end end end IRBRC_EXT = "rc" def IRB.rc_file(ext = IRBRC_EXT) if !@CONF[:RC_NAME_GENERATOR] rc_file_generators do |rcgen| @CONF[:RC_NAME_GENERATOR] ||= rcgen if File.exist?(rcgen.call(IRBRC_EXT)) @CONF[:RC_NAME_GENERATOR] = rcgen break end end end case rc_file = @CONF[:RC_NAME_GENERATOR].call(ext) when String return rc_file else fail IllegalRCNameGenerator end end # enumerate possible rc-file base name generators def IRB.rc_file_generators if irbrc = ENV["IRBRC"] yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc} end if xdg_config_home = ENV["XDG_CONFIG_HOME"] irb_home = File.join(xdg_config_home, "irb") unless File.exist? irb_home require 'fileutils' FileUtils.mkdir_p irb_home end yield proc{|rc| irb_home + "/irb#{rc}"} end if home = ENV["HOME"] yield proc{|rc| home+"/.irb#{rc}"} end current_dir = Dir.pwd yield proc{|rc| current_dir+"/.config/irb/irb#{rc}"} yield proc{|rc| current_dir+"/.irb#{rc}"} yield proc{|rc| current_dir+"/irb#{rc.sub(/\A_?/, '.')}"} yield proc{|rc| current_dir+"/_irb#{rc}"} yield proc{|rc| current_dir+"/$irb#{rc}"} end # loading modules def IRB.load_modules for m in @CONF[:LOAD_MODULES] begin require m rescue LoadError => err warn "#{err.class}: #{err}", uplevel: 0 end end end DefaultEncodings = Struct.new(:external, :internal) class << IRB private def set_encoding(extern, intern = nil, override: true) verbose, $VERBOSE = $VERBOSE, nil Encoding.default_external = extern unless extern.nil? || extern.empty? Encoding.default_internal = intern unless intern.nil? || intern.empty? [$stdin, $stdout, $stderr].each do |io| io.set_encoding(extern, intern) end if override @CONF[:LC_MESSAGES].instance_variable_set(:@override_encoding, extern) else @CONF[:LC_MESSAGES].instance_variable_set(:@encoding, extern) end ensure $VERBOSE = verbose end end end PK ]I I #gems/irb-1.2.6/lib/irb/ruby_logo.aanu[ -+smJYYN?mm- HB"BBYT TQg NggT 9Q+g Nm,T 8g NJW YS+ N2NJ"Sg N? BQg #( gT Nggggk J 5j NJ NJ NNge #Q #JJ NgT N( @j bj mT J Bj @/d NJ ( #q #(( NgT #J 5d #(t mT $d #q @(@J NJB; @( 5d ? HHH H HQmgggggggmN qD 5d #uN 2QdH E O 5 5JSd Nd NJH @d j Fd @J4d s NQH #d ( #( #o6d Nd NgH #d #d 4 B&Od v NgT #d F #( 9JGd NH NgUd F #d #GJQ d NP $ #J #U+#Q N Q # j j /W BQ+ BQ d NJ NJ - NjJH HBIjTQggPJQgW N W k #J #J b HYWgggN j s Nag d NN b #d #J 5- D s Ngg N d Nd F Fd BKH2 #+ s NNgg J Q J ] F H @ J N y K(d P I F4 E N? #d y #Q NJ E j F W Nd q m Bg NxW N(H- F d b @ m Hd gW vKJ NJ d K d s Bg aT FDd b # d N m BQ mV N> e5 Nd #d NggggggQWH HHHH NJ - m7 NW H N HSVO1z=?11- NgTH bB kH WBHWWHBHWmQgg&gggggNNN NNggggggNN PK ]O"gems/irb-1.2.6/lib/irb/cmd/help.rbnu[# frozen_string_literal: false # # help.rb - helper using ri # $Release Version: 0.9.6$ # $Revision$ # # -- # # # require_relative "nop" # :stopdoc: module IRB module ExtendCommand class Help < Nop def execute(*names) require 'rdoc/ri/driver' IRB::ExtendCommand::Help.const_set(:Ri, RDoc::RI::Driver.new) rescue LoadError, SystemExit IRB::ExtendCommand::Help.remove_method(:execute) # raise NoMethodError in ensure else def execute(*names) if names.empty? Ri.interactive return end names.each do |name| begin Ri.display_name(name.to_s) rescue RDoc::RI::Error puts $!.message end end nil end nil ensure execute(*names) end end end end # :startdoc: PK ]#o"gems/irb-1.2.6/lib/irb/cmd/load.rbnu[# frozen_string_literal: false # # load.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "nop" require_relative "../ext/loader" # :stopdoc: module IRB module ExtendCommand class Load < Nop include IrbLoader def execute(file_name, priv = nil) return irb_load(file_name, priv) end end class Require < Nop include IrbLoader def execute(file_name) rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?") return false if $".find{|f| f =~ rex} case file_name when /\.rb$/ begin if irb_load(file_name) $".push file_name return true end rescue LoadError end when /\.(so|o|sl)$/ return ruby_require(file_name) end begin irb_load(f = file_name + ".rb") $".push f return true rescue LoadError return ruby_require(file_name) end end end class Source < Nop include IrbLoader def execute(file_name) source_file(file_name) end end end end # :startdoc: PK ]Q~~"gems/irb-1.2.6/lib/irb/cmd/fork.rbnu[# frozen_string_literal: false # # fork.rb - # $Release Version: 0.9.6 $ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # # :stopdoc: module IRB module ExtendCommand class Fork < Nop def execute pid = send ExtendCommand.irb_original_method_name("fork") unless pid class << self alias_method :exit, ExtendCommand.irb_original_method_name('exit') end if block_given? begin yield ensure exit end end end pid end end end end # :startdoc: PK ]j$"gems/irb-1.2.6/lib/irb/cmd/chws.rbnu[# frozen_string_literal: false # # change-ws.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "nop" require_relative "../ext/change-ws" # :stopdoc: module IRB module ExtendCommand class CurrentWorkingWorkspace < Nop def execute(*obj) irb_context.main end end class ChangeWorkspace < Nop def execute(*obj) irb_context.change_workspace(*obj) irb_context.main end end end end # :startdoc: PK ])ڏ!!!gems/irb-1.2.6/lib/irb/cmd/nop.rbnu[# frozen_string_literal: false # # nop.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # # :stopdoc: module IRB module ExtendCommand class Nop def self.execute(conf, *opts) command = new(conf) command.execute(*opts) end def initialize(conf) @irb_context = conf end attr_reader :irb_context def irb @irb_context.irb end def execute(*opts) #nop end end end end # :startdoc: PK ]z$gems/irb-1.2.6/lib/irb/cmd/pushws.rbnu[# frozen_string_literal: false # # change-ws.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "nop" require_relative "../ext/workspaces" # :stopdoc: module IRB module ExtendCommand class Workspaces < Nop def execute(*obj) irb_context.workspaces.collect{|ws| ws.main} end end class PushWorkspace < Workspaces def execute(*obj) irb_context.push_workspace(*obj) super end end class PopWorkspace < Workspaces def execute(*obj) irb_context.pop_workspace(*obj) super end end end end # :startdoc: PK ]I]]$gems/irb-1.2.6/lib/irb/cmd/subirb.rbnu[# frozen_string_literal: false # multi.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "nop" require_relative "../ext/multi-irb" # :stopdoc: module IRB module ExtendCommand class IrbCommand < Nop def execute(*obj) IRB.irb(nil, *obj) end end class Jobs < Nop def execute IRB.JobManager end end class Foreground < Nop def execute(key) IRB.JobManager.switch(key) end end class Kill < Nop def execute(*keys) IRB.JobManager.kill(*keys) end end end end # :startdoc: PK ]{A5//"gems/irb-1.2.6/lib/irb/cmd/info.rbnu[# frozen_string_literal: false require_relative "nop" # :stopdoc: module IRB module ExtendCommand class Info < Nop def execute Class.new { def inspect str = "Ruby version: #{RUBY_VERSION}\n" str += "IRB version: #{IRB.version}\n" str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n" str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file) str end alias_method :to_s, :inspect }.new end end end end # :startdoc: PK ]tgems/irb-1.2.6/lib/irb/xmp.rbnu[# frozen_string_literal: false # # xmp.rb - irb version of gotoken xmp # $Release Version: 0.9$ # $Revision$ # by Keiju ISHITSUKA(Nippon Rational Inc.) # # -- # # # require_relative "../irb" require_relative "frame" # An example printer for irb. # # It's much like the standard library PrettyPrint, that shows the value of each # expression as it runs. # # In order to use this library, you must first require it: # # require 'irb/xmp' # # Now, you can take advantage of the Object#xmp convenience method. # # xmp < foo = "bar" # #==>"bar" # #=> baz = 42 # #==>42 # # You can also create an XMP object, with an optional binding to print # expressions in the given binding: # # ctx = binding # x = XMP.new ctx # x.puts # #=> today = "a good day" # #==>"a good day" # ctx.eval 'today # is what?' # #=> "a good day" class XMP # Creates a new XMP object. # # The top-level binding or, optional +bind+ parameter will be used when # creating the workspace. See WorkSpace.new for more information. # # This uses the +:XMP+ prompt mode, see IRB@Customizing+the+IRB+Prompt for # full detail. def initialize(bind = nil) IRB.init_config(nil) IRB.conf[:PROMPT_MODE] = :XMP bind = IRB::Frame.top(1) unless bind ws = IRB::WorkSpace.new(bind) @io = StringInputMethod.new @irb = IRB::Irb.new(ws, @io) @irb.context.ignore_sigint = false IRB.conf[:MAIN_CONTEXT] = @irb.context end # Evaluates the given +exps+, for example: # # require 'irb/xmp' # x = XMP.new # # x.puts '{:a => 1, :b => 2, :c => 3}' # #=> {:a => 1, :b => 2, :c => 3} # # ==>{:a=>1, :b=>2, :c=>3} # x.puts 'foo = "bar"' # # => foo = "bar" # # ==>"bar" def puts(exps) @io.puts exps if @irb.context.ignore_sigint begin trap_proc_b = trap("SIGINT"){@irb.signal_handle} catch(:IRB_EXIT) do @irb.eval_input end ensure trap("SIGINT", trap_proc_b) end else catch(:IRB_EXIT) do @irb.eval_input end end end # A custom InputMethod class used by XMP for evaluating string io. class StringInputMethod < IRB::InputMethod # Creates a new StringInputMethod object def initialize super @exps = [] end # Whether there are any expressions left in this printer. def eof? @exps.empty? end # Reads the next expression from this printer. # # See IO#gets for more information. def gets while l = @exps.shift next if /^\s+$/ =~ l l.concat "\n" print @prompt, l break end l end # Concatenates all expressions in this printer, separated by newlines. # # An Encoding::CompatibilityError is raised of the given +exps+'s encoding # doesn't match the previous expression evaluated. def puts(exps) if @encoding and exps.encoding != @encoding enc = Encoding.compatible?(@exps.join("\n"), exps) if enc.nil? raise Encoding::CompatibilityError, "Encoding in which the passed expression is encoded is not compatible to the preceding's one" else @encoding = enc end else @encoding = exps.encoding end @exps.concat exps.split(/\n/) end # Returns the encoding of last expression printed by #puts. attr_reader :encoding end end # A convenience method that's only available when the you require the IRB::XMP standard library. # # Creates a new XMP object, using the given expressions as the +exps+ # parameter, and optional binding as +bind+ or uses the top-level binding. Then # evaluates the given expressions using the +:XMP+ prompt mode. # # For example: # # require 'irb/xmp' # ctx = binding # xmp 'foo = "bar"', ctx # #=> foo = "bar" # #==>"bar" # ctx.eval 'foo' # #=> "bar" # # See XMP.new for more information. def xmp(exps, bind = nil) bind = IRB::Frame.top(1) unless bind xmp = XMP.new(bind) xmp.puts exps xmp end PK ]c&gems/irb-1.2.6/lib/irb/src_encoding.rbnu[# frozen_string_literal: false # DO NOT WRITE ANY MAGIC COMMENT HERE. module IRB def self.default_src_encoding return __ENCODING__ end end PK ]h((!gems/irb-1.2.6/lib/irb/version.rbnu[# frozen_string_literal: false # # irb/version.rb - irb version definition file # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # # # module IRB # :nodoc: VERSION = "1.2.6" @RELEASE_VERSION = VERSION @LAST_UPDATE_DATE = "2020-09-14" end PK ]Ɨ]%%$gems/irb-1.2.6/lib/irb/completion.rbnu[# frozen_string_literal: false # # irb/completion.rb - # $Release Version: 0.9$ # $Revision$ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # From Original Idea of shugo@ruby-lang.org # autoload :RDoc, "rdoc" module IRB module InputCompletor # :nodoc: # Set of reserved words used by Ruby, you should not use these for # constants or variables ReservedWords = %w[ __ENCODING__ __LINE__ __FILE__ BEGIN END alias and begin break case class def defined? do else elsif end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield ] BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{(" CompletionProc = proc { |input| retrieve_completion_data(input).compact.map{ |i| i.encode(Encoding.default_external) } } def self.retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false) case input when /^((["'`]).*\2)\.([^.]*)$/ # String receiver = $1 message = Regexp.quote($3) candidates = String.instance_methods.collect{|m| m.to_s} if doc_namespace "String.#{message}" else select_message(receiver, message, candidates) end when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp receiver = $1 message = Regexp.quote($2) candidates = Regexp.instance_methods.collect{|m| m.to_s} if doc_namespace "Regexp.#{message}" else select_message(receiver, message, candidates) end when /^([^\]]*\])\.([^.]*)$/ # Array receiver = $1 message = Regexp.quote($2) candidates = Array.instance_methods.collect{|m| m.to_s} if doc_namespace "Array.#{message}" else select_message(receiver, message, candidates) end when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash receiver = $1 message = Regexp.quote($2) proc_candidates = Proc.instance_methods.collect{|m| m.to_s} hash_candidates = Hash.instance_methods.collect{|m| m.to_s} if doc_namespace ["Proc.#{message}", "Hash.#{message}"] else select_message(receiver, message, proc_candidates | hash_candidates) end when /^(:[^:.]*)$/ # Symbol return nil if doc_namespace sym = $1 candidates = Symbol.all_symbols.collect do |s| ":" + s.id2name.encode(Encoding.default_external) rescue Encoding::UndefinedConversionError # ignore end candidates.grep(/^#{Regexp.quote(sym)}/) when /^::([A-Z][^:\.\(]*)$/ # Absolute Constant or class methods receiver = $1 candidates = Object.constants.collect{|m| m.to_s} if doc_namespace candidates.find { |i| i == receiver } else candidates.grep(/^#{receiver}/).collect{|e| "::" + e} end when /^([A-Z].*)::([^:.]*)$/ # Constant or class methods receiver = $1 message = Regexp.quote($2) begin candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind) candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind) rescue Exception candidates = [] end if doc_namespace "#{receiver}::#{message}" else select_message(receiver, message, candidates, "::") end when /^(:[^:.]+)(\.|::)([^.]*)$/ # Symbol receiver = $1 sep = $2 message = Regexp.quote($3) candidates = Symbol.instance_methods.collect{|m| m.to_s} if doc_namespace "Symbol.#{message}" else select_message(receiver, message, candidates, sep) end when /^(?-?(?:0[dbo])?[0-9_]+(?:\.[0-9_]+)?(?:(?:[eE][+-]?[0-9]+)?i?|r)?)(?\.|::)(?[^.]*)$/ # Numeric receiver = $~[:num] sep = $~[:sep] message = Regexp.quote($~[:mes]) begin instance = eval(receiver, bind) if doc_namespace "#{instance.class.name}.#{message}" else candidates = instance.methods.collect{|m| m.to_s} select_message(receiver, message, candidates, sep) end rescue Exception if doc_namespace nil else candidates = [] end end when /^(-?0x[0-9a-fA-F_]+)(\.|::)([^.]*)$/ # Numeric(0xFFFF) receiver = $1 sep = $2 message = Regexp.quote($3) begin instance = eval(receiver, bind) if doc_namespace "#{instance.class.name}.#{message}" else candidates = instance.methods.collect{|m| m.to_s} select_message(receiver, message, candidates, sep) end rescue Exception if doc_namespace nil else candidates = [] end end when /^(\$[^.]*)$/ # global var gvar = $1 all_gvars = global_variables.collect{|m| m.to_s} if doc_namespace all_gvars.find{ |i| i == gvar } else all_gvars.grep(Regexp.new(Regexp.quote(gvar))) end when /^([^."].*)(\.|::)([^.]*)$/ # variable.func or func.func receiver = $1 sep = $2 message = Regexp.quote($3) gv = eval("global_variables", bind).collect{|m| m.to_s}.push("true", "false", "nil") lv = eval("local_variables", bind).collect{|m| m.to_s} iv = eval("instance_variables", bind).collect{|m| m.to_s} cv = eval("self.class.constants", bind).collect{|m| m.to_s} if (gv | lv | iv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver # foo.func and foo is var. OR # foo::func and foo is var. OR # foo::Const and foo is var. OR # Foo::Bar.func begin candidates = [] rec = eval(receiver, bind) if sep == "::" and rec.kind_of?(Module) candidates = rec.constants.collect{|m| m.to_s} end candidates |= rec.methods.collect{|m| m.to_s} rescue Exception candidates = [] end else # func1.func2 candidates = [] to_ignore = ignored_modules ObjectSpace.each_object(Module){|m| next if (to_ignore.include?(m) rescue true) candidates.concat m.instance_methods(false).collect{|x| x.to_s} } candidates.sort! candidates.uniq! end if doc_namespace "#{rec.class.name}#{sep}#{candidates.find{ |i| i == message }}" else select_message(receiver, message, candidates, sep) end when /^\.([^.]*)$/ # unknown(maybe String) receiver = "" message = Regexp.quote($1) candidates = String.instance_methods(true).collect{|m| m.to_s} if doc_namespace "String.#{candidates.find{ |i| i == message }}" else select_message(receiver, message, candidates) end else candidates = eval("methods | private_methods | local_variables | instance_variables | self.class.constants", bind).collect{|m| m.to_s} candidates |= ReservedWords if doc_namespace candidates.find{ |i| i == input } else candidates.grep(/^#{Regexp.quote(input)}/) end end end PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) { RDocRIDriver ||= RDoc::RI::Driver.new if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER'] IRB.send(:easter_egg) return end namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true) return unless namespace if namespace.is_a?(Array) out = RDoc::Markup::Document.new namespace.each do |m| begin RDocRIDriver.add_method(out, m) rescue RDoc::RI::Driver::NotFoundError end end RDocRIDriver.display(out) else begin RDocRIDriver.display_names([namespace]) rescue RDoc::RI::Driver::NotFoundError end end } # Set of available operators in Ruby Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~] def self.select_message(receiver, message, candidates, sep = ".") candidates.grep(/^#{message}/).collect do |e| case e when /^[a-zA-Z_]/ receiver + sep + e when /^[0-9]/ when *Operators #receiver + " " + e end end end def self.ignored_modules # We could cache the result, but this is very fast already. # By using this approach, we avoid Module#name calls, which are # relatively slow when there are a lot of anonymous modules defined. s = {} scanner = lambda do |m| next if s.include?(m) # IRB::ExtendCommandBundle::EXCB recurses. s[m] = true m.constants(false).each do |c| value = m.const_get(c) scanner.call(value) if value.is_a?(Module) end end %i(IRB RubyLex).each do |sym| next unless Object.const_defined?(sym) scanner.call(Object.const_get(sym)) end s.delete(IRB::Context) if defined?(IRB::Context) s end end end PK ]DKC#gems/irb-1.2.6/lib/irb/workspace.rbnu[# frozen_string_literal: false # # irb/workspace-binding.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "delegate" module IRB # :nodoc: class WorkSpace # Creates a new workspace. # # set self to main if specified, otherwise # inherit main from TOPLEVEL_BINDING. def initialize(*main) if main[0].kind_of?(Binding) @binding = main.shift elsif IRB.conf[:SINGLE_IRB] @binding = TOPLEVEL_BINDING else case IRB.conf[:CONTEXT_MODE] when 0 # binding in proc on TOPLEVEL_BINDING @binding = eval("proc{binding}.call", TOPLEVEL_BINDING, __FILE__, __LINE__) when 1 # binding in loaded file require "tempfile" f = Tempfile.open("irb-binding") f.print <IRB.conf[:__MAIN__] attr_reader :main # Evaluate the given +statements+ within the context of this workspace. def evaluate(context, statements, file = __FILE__, line = __LINE__) eval(statements, @binding, file, line) end def local_variable_set(name, value) @binding.local_variable_set(name, value) end def local_variable_get(name) @binding.local_variable_get(name) end # error message manipulator def filter_backtrace(bt) return nil if bt =~ /\/irb\/.*\.rb/ return nil if bt =~ /\/irb\.rb/ case IRB.conf[:CONTEXT_MODE] when 1 return nil if bt =~ %r!/tmp/irb-binding! when 3 bt = bt.sub(/:\s*in `irb_binding'/, '') end bt end def code_around_binding if @binding.respond_to?(:source_location) file, pos = @binding.source_location else file, pos = @binding.eval('[__FILE__, __LINE__]') end if defined?(::SCRIPT_LINES__[file]) && lines = ::SCRIPT_LINES__[file] code = ::SCRIPT_LINES__[file].join('') else begin code = File.read(file) rescue SystemCallError return end end # NOT using #use_colorize? of IRB.conf[:MAIN_CONTEXT] because this method may be called before IRB::Irb#run use_colorize = IRB.conf.fetch(:USE_COLORIZE, true) if use_colorize lines = Color.colorize_code(code).lines else lines = code.lines end pos -= 1 start_pos = [pos - 5, 0].max end_pos = [pos + 5, lines.size - 1].min if use_colorize fmt = " %2s #{Color.colorize("%#{end_pos.to_s.length}d", [:BLUE, :BOLD])}: %s" else fmt = " %2s %#{end_pos.to_s.length}d: %s" end body = (start_pos..end_pos).map do |current_pos| sprintf(fmt, pos == current_pos ? '=>' : '', current_pos + 1, lines[current_pos]) end.join("") "\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n" end def IRB.delete_caller end end end PK ]ǀgems/irb-1.2.6/lib/irb/frame.rbnu[# frozen_string_literal: false # # frame.rb - # $Release Version: 0.9$ # $Revision$ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # module IRB class Frame class FrameOverflow < StandardError def initialize super("frame overflow") end end class FrameUnderflow < StandardError def initialize super("frame underflow") end end # Default number of stack frames INIT_STACK_TIMES = 3 # Default number of frames offset CALL_STACK_OFFSET = 3 # Creates a new stack frame def initialize @frames = [TOPLEVEL_BINDING] * INIT_STACK_TIMES end # Used by Kernel#set_trace_func to register each event in the call stack def trace_func(event, file, line, id, binding) case event when 'call', 'class' @frames.push binding when 'return', 'end' @frames.pop end end # Returns the +n+ number of frames on the call stack from the last frame # initialized. # # Raises FrameUnderflow if there are no frames in the given stack range. def top(n = 0) bind = @frames[-(n + CALL_STACK_OFFSET)] fail FrameUnderflow unless bind bind end # Returns the +n+ number of frames on the call stack from the first frame # initialized. # # Raises FrameOverflow if there are no frames in the given stack range. def bottom(n = 0) bind = @frames[n] fail FrameOverflow unless bind bind end # Convenience method for Frame#bottom def Frame.bottom(n = 0) @backtrace.bottom(n) end # Convenience method for Frame#top def Frame.top(n = 0) @backtrace.top(n) end # Returns the binding context of the caller from the last frame initialized def Frame.sender eval "self", @backtrace.top end @backtrace = Frame.new set_trace_func proc{|event, file, line, id, binding, klass| @backtrace.trace_func(event, file, line, id, binding) } end end PK ]&/(((gems/irb-1.2.6/lib/irb/extend-command.rbnu[# frozen_string_literal: false # # irb/extend-command.rb - irb extend command # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: # Installs the default irb extensions command bundle. module ExtendCommandBundle EXCB = ExtendCommandBundle # :nodoc: # See #install_alias_method. NO_OVERRIDE = 0 # See #install_alias_method. OVERRIDE_PRIVATE_ONLY = 0x01 # See #install_alias_method. OVERRIDE_ALL = 0x02 # Quits the current irb context # # +ret+ is the optional signal or message to send to Context#exit # # Same as IRB.CurrentContext.exit. def irb_exit(ret = 0) irb_context.exit(ret) end # Displays current configuration. # # Modifying the configuration is achieved by sending a message to IRB.conf. def irb_context IRB.CurrentContext end @ALIASES = [ [:context, :irb_context, NO_OVERRIDE], [:conf, :irb_context, NO_OVERRIDE], [:irb_quit, :irb_exit, OVERRIDE_PRIVATE_ONLY], [:exit, :irb_exit, OVERRIDE_PRIVATE_ONLY], [:quit, :irb_exit, OVERRIDE_PRIVATE_ONLY], ] @EXTEND_COMMANDS = [ [ :irb_current_working_workspace, :CurrentWorkingWorkspace, "irb/cmd/chws", [:irb_print_working_workspace, OVERRIDE_ALL], [:irb_cwws, OVERRIDE_ALL], [:irb_pwws, OVERRIDE_ALL], [:cwws, NO_OVERRIDE], [:pwws, NO_OVERRIDE], [:irb_current_working_binding, OVERRIDE_ALL], [:irb_print_working_binding, OVERRIDE_ALL], [:irb_cwb, OVERRIDE_ALL], [:irb_pwb, OVERRIDE_ALL], ], [ :irb_change_workspace, :ChangeWorkspace, "irb/cmd/chws", [:irb_chws, OVERRIDE_ALL], [:irb_cws, OVERRIDE_ALL], [:chws, NO_OVERRIDE], [:cws, NO_OVERRIDE], [:irb_change_binding, OVERRIDE_ALL], [:irb_cb, OVERRIDE_ALL], [:cb, NO_OVERRIDE], ], [ :irb_workspaces, :Workspaces, "irb/cmd/pushws", [:workspaces, NO_OVERRIDE], [:irb_bindings, OVERRIDE_ALL], [:bindings, NO_OVERRIDE], ], [ :irb_push_workspace, :PushWorkspace, "irb/cmd/pushws", [:irb_pushws, OVERRIDE_ALL], [:pushws, NO_OVERRIDE], [:irb_push_binding, OVERRIDE_ALL], [:irb_pushb, OVERRIDE_ALL], [:pushb, NO_OVERRIDE], ], [ :irb_pop_workspace, :PopWorkspace, "irb/cmd/pushws", [:irb_popws, OVERRIDE_ALL], [:popws, NO_OVERRIDE], [:irb_pop_binding, OVERRIDE_ALL], [:irb_popb, OVERRIDE_ALL], [:popb, NO_OVERRIDE], ], [ :irb_load, :Load, "irb/cmd/load"], [ :irb_require, :Require, "irb/cmd/load"], [ :irb_source, :Source, "irb/cmd/load", [:source, NO_OVERRIDE], ], [ :irb, :IrbCommand, "irb/cmd/subirb"], [ :irb_jobs, :Jobs, "irb/cmd/subirb", [:jobs, NO_OVERRIDE], ], [ :irb_fg, :Foreground, "irb/cmd/subirb", [:fg, NO_OVERRIDE], ], [ :irb_kill, :Kill, "irb/cmd/subirb", [:kill, OVERRIDE_PRIVATE_ONLY], ], [ :irb_help, :Help, "irb/cmd/help", [:help, NO_OVERRIDE], ], [ :irb_info, :Info, "irb/cmd/info" ], ] # Installs the default irb commands: # # +irb_current_working_workspace+:: Context#main # +irb_change_workspace+:: Context#change_workspace # +irb_workspaces+:: Context#workspaces # +irb_push_workspace+:: Context#push_workspace # +irb_pop_workspace+:: Context#pop_workspace # +irb_load+:: #irb_load # +irb_require+:: #irb_require # +irb_source+:: IrbLoader#source_file # +irb+:: IRB.irb # +irb_jobs+:: JobManager # +irb_fg+:: JobManager#switch # +irb_kill+:: JobManager#kill # +irb_help+:: IRB@Command+line+options def self.install_extend_commands for args in @EXTEND_COMMANDS def_extend_command(*args) end end # Evaluate the given +cmd_name+ on the given +cmd_class+ Class. # # Will also define any given +aliases+ for the method. # # The optional +load_file+ parameter will be required within the method # definition. def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases) case cmd_class when Symbol cmd_class = cmd_class.id2name when String when Class cmd_class = cmd_class.name end if load_file line = __LINE__; eval %[ def #{cmd_name}(*opts, &b) require "#{load_file}" arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s } args << "*opts" if arity < 0 args << "&block" args = args.join(", ") line = __LINE__; eval %[ unless self.class.class_variable_defined?(:@@#{cmd_name}_) self.class.class_variable_set(:@@#{cmd_name}_, true) def #{cmd_name}_(\#{args}) ExtendCommand::#{cmd_class}.execute(irb_context, \#{args}) end end ], nil, __FILE__, line send :#{cmd_name}_, *opts, &b end ], nil, __FILE__, line else line = __LINE__; eval %[ def #{cmd_name}(*opts, &b) ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b) end ], nil, __FILE__, line end for ali, flag in aliases @ALIASES.push [ali, cmd_name, flag] end end # Installs alias methods for the default irb commands, see # ::install_extend_commands. def install_alias_method(to, from, override = NO_OVERRIDE) to = to.id2name unless to.kind_of?(String) from = from.id2name unless from.kind_of?(String) if override == OVERRIDE_ALL or (override == OVERRIDE_PRIVATE_ONLY) && !respond_to?(to) or (override == NO_OVERRIDE) && !respond_to?(to, true) target = self (class << self; self; end).instance_eval{ if target.respond_to?(to, true) && !target.respond_to?(EXCB.irb_original_method_name(to), true) alias_method(EXCB.irb_original_method_name(to), to) end alias_method to, from } else print "irb: warn: can't alias #{to} from #{from}.\n" end end def self.irb_original_method_name(method_name) # :nodoc: "irb_" + method_name + "_org" end # Installs alias methods for the default irb commands on the given object # using #install_alias_method. def self.extend_object(obj) unless (class << obj; ancestors; end).include?(EXCB) super for ali, com, flg in @ALIASES obj.install_alias_method(ali, com, flg) end end end install_extend_commands end # Extends methods for the Context module module ContextExtender CE = ContextExtender # :nodoc: @EXTEND_COMMANDS = [ [:eval_history=, "irb/ext/history.rb"], [:use_tracer=, "irb/ext/tracer.rb"], [:use_loader=, "irb/ext/use-loader.rb"], [:save_history=, "irb/ext/save-history.rb"], ] # Installs the default context extensions as irb commands: # # Context#eval_history=:: +irb/ext/history.rb+ # Context#use_tracer=:: +irb/ext/tracer.rb+ # Context#use_loader=:: +irb/ext/use-loader.rb+ # Context#save_history=:: +irb/ext/save-history.rb+ def self.install_extend_commands for args in @EXTEND_COMMANDS def_extend_command(*args) end end # Evaluate the given +command+ from the given +load_file+ on the Context # module. # # Will also define any given +aliases+ for the method. def self.def_extend_command(cmd_name, load_file, *aliases) line = __LINE__; Context.module_eval %[ def #{cmd_name}(*opts, &b) Context.module_eval {remove_method(:#{cmd_name})} require "#{load_file}" send :#{cmd_name}, *opts, &b end for ali in aliases alias_method ali, cmd_name end ], __FILE__, line end CE.install_extend_commands end # A convenience module for extending Ruby methods. module MethodExtender # Extends the given +base_method+ with a prefix call to the given # +extend_method+. def def_pre_proc(base_method, extend_method) base_method = base_method.to_s extend_method = extend_method.to_s alias_name = new_alias_name(base_method) module_eval %[ alias_method alias_name, base_method def #{base_method}(*opts) send :#{extend_method}, *opts send :#{alias_name}, *opts end ] end # Extends the given +base_method+ with a postfix call to the given # +extend_method+. def def_post_proc(base_method, extend_method) base_method = base_method.to_s extend_method = extend_method.to_s alias_name = new_alias_name(base_method) module_eval %[ alias_method alias_name, base_method def #{base_method}(*opts) send :#{alias_name}, *opts send :#{extend_method}, *opts end ] end # Returns a unique method name to use as an alias for the given +name+. # # Usually returns #{prefix}#{name}#{postfix}, example: # # new_alias_name('foo') #=> __alias_of__foo__ # def bar; end # new_alias_name('bar') #=> __alias_of__bar__2 def new_alias_name(name, prefix = "__alias_of__", postfix = "__") base_name = "#{prefix}#{name}#{postfix}" all_methods = instance_methods(true) + private_instance_methods(true) same_methods = all_methods.grep(/^#{Regexp.quote(base_name)}[0-9]*$/) return base_name if same_methods.empty? no = same_methods.size while !same_methods.include?(alias_name = base_name + no) no += 1 end alias_name end end end PK ] ['gems/irb-1.2.6/lib/irb/ws-for-case-2.rbnu[# frozen_string_literal: false # # irb/ws-for-case-2.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # while true IRB::BINDING_QUEUE.push _ = binding end PK ] V2 'gems/irb-1.2.6/lib/irb/output-method.rbnu[# frozen_string_literal: false # # output-method.rb - output methods used by irb # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # An abstract output class for IO in irb. This is mainly used internally by # IRB::Notifier. You can define your own output method to use with Irb.new, # or Context.new class OutputMethod class NotImplementedError < StandardError def initialize(val) super("Need to define `#{val}'") end end # Open this method to implement your own output method, raises a # NotImplementedError if you don't define #print in your own class. def print(*opts) raise NotImplementedError, "print" end # Prints the given +opts+, with a newline delimiter. def printn(*opts) print opts.join(" "), "\n" end # Extends IO#printf to format the given +opts+ for Kernel#sprintf using # #parse_printf_format def printf(format, *opts) if /(%*)%I/ =~ format format, opts = parse_printf_format(format, opts) end print sprintf(format, *opts) end # Returns an array of the given +format+ and +opts+ to be used by # Kernel#sprintf, if there was a successful Regexp match in the given # +format+ from #printf # # % # [#0- +] # (\*|\*[1-9][0-9]*\$|[1-9][0-9]*) # .(\*|\*[1-9][0-9]*\$|[1-9][0-9]*|)? # #(hh|h|l|ll|L|q|j|z|t) # [diouxXeEfgGcsb%] def parse_printf_format(format, opts) return format, opts if $1.size % 2 == 1 end # Calls #print on each element in the given +objs+, followed by a newline # character. def puts(*objs) for obj in objs print(*obj) print "\n" end end # Prints the given +objs+ calling Object#inspect on each. # # See #puts for more detail. def pp(*objs) puts(*objs.collect{|obj| obj.inspect}) end # Prints the given +objs+ calling Object#inspect on each and appending the # given +prefix+. # # See #puts for more detail. def ppx(prefix, *objs) puts(*objs.collect{|obj| prefix+obj.inspect}) end end # A standard output printer class StdioOutputMethod < OutputMethod # Prints the given +opts+ to standard output, see IO#print for more # information. def print(*opts) STDOUT.print(*opts) end end end PK ]q#gems/irb-1.2.6/lib/irb/inspector.rbnu[# frozen_string_literal: false # # irb/inspector.rb - inspect methods # $Release Version: 0.9.6$ # $Revision: 1.19 $ # $Date: 2002/06/11 07:51:31 $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: # Convenience method to create a new Inspector, using the given +inspect+ # proc, and optional +init+ proc and passes them to Inspector.new # # irb(main):001:0> ins = IRB::Inspector(proc{ |v| "omg! #{v}" }) # irb(main):001:0> IRB.CurrentContext.inspect_mode = ins # => omg! # # irb(main):001:0> "what?" #=> omg! what? # def IRB::Inspector(inspect, init = nil) Inspector.new(inspect, init) end # An irb inspector # # In order to create your own custom inspector there are two things you # should be aware of: # # Inspector uses #inspect_value, or +inspect_proc+, for output of return values. # # This also allows for an optional #init+, or +init_proc+, which is called # when the inspector is activated. # # Knowing this, you can create a rudimentary inspector as follows: # # irb(main):001:0> ins = IRB::Inspector.new(proc{ |v| "omg! #{v}" }) # irb(main):001:0> IRB.CurrentContext.inspect_mode = ins # => omg! # # irb(main):001:0> "what?" #=> omg! what? # class Inspector # Default inspectors available to irb, this includes: # # +:pp+:: Using Kernel#pretty_inspect # +:yaml+:: Using YAML.dump # +:marshal+:: Using Marshal.dump INSPECTORS = {} # Determines the inspector to use where +inspector+ is one of the keys passed # during inspector definition. def self.keys_with_inspector(inspector) INSPECTORS.select{|k,v| v == inspector}.collect{|k, v| k} end # Example # # Inspector.def_inspector(key, init_p=nil){|v| v.inspect} # Inspector.def_inspector([key1,..], init_p=nil){|v| v.inspect} # Inspector.def_inspector(key, inspector) # Inspector.def_inspector([key1,...], inspector) def self.def_inspector(key, arg=nil, &block) if block_given? inspector = IRB::Inspector(block, arg) else inspector = arg end case key when Array for k in key def_inspector(k, inspector) end when Symbol INSPECTORS[key] = inspector INSPECTORS[key.to_s] = inspector when String INSPECTORS[key] = inspector INSPECTORS[key.intern] = inspector else INSPECTORS[key] = inspector end end # Creates a new inspector object, using the given +inspect_proc+ when # output return values in irb. def initialize(inspect_proc, init_proc = nil) @init = init_proc @inspect = inspect_proc end # Proc to call when the inspector is activated, good for requiring # dependent libraries. def init @init.call if @init end # Proc to call when the input is evaluated and output in irb. def inspect_value(v) @inspect.call(v) end end Inspector.def_inspector([false, :to_s, :raw]){|v| v.to_s} Inspector.def_inspector([true, :p, :inspect]){|v| begin result = v.inspect if IRB.conf[:MAIN_CONTEXT]&.use_colorize? && Color.inspect_colorable?(v) result = Color.colorize_code(result) end result rescue NoMethodError puts "(Object doesn't support #inspect)" '' end } Inspector.def_inspector([:pp, :pretty_inspect], proc{require "pp"}){|v| result = v.pretty_inspect.chomp if IRB.conf[:MAIN_CONTEXT]&.use_colorize? && Color.inspect_colorable?(v) result = Color.colorize_code(result) end result } Inspector.def_inspector([:yaml, :YAML], proc{require "yaml"}){|v| begin YAML.dump(v) rescue puts "(can't dump yaml. use inspect)" v.inspect end } Inspector.def_inspector([:marshal, :Marshal, :MARSHAL, Marshal]){|v| Marshal.dump(v) } end PK ][$gems/irb-1.2.6/lib/irb/magic-file.rbnu[# frozen_string_literal: false module IRB class << (MagicFile = Object.new) # see parser_magic_comment in parse.y ENCODING_SPEC_RE = %r"coding\s*[=:]\s*([[:alnum:]\-_]+)" def open(path) io = File.open(path, 'rb') line = io.gets line = io.gets if line[0,2] == "#!" encoding = detect_encoding(line) internal_encoding = encoding encoding ||= IRB.default_src_encoding io.rewind io.set_encoding(encoding, internal_encoding) if block_given? begin return (yield io) ensure io.close end else return io end end private def detect_encoding(line) return unless line[0] == ?# line = line[1..-1] line = $1 if line[/-\*-\s*(.*?)\s*-*-$/] return nil unless ENCODING_SPEC_RE =~ line encoding = $1 return encoding.sub(/-(?:mac|dos|unix)/i, '') end end end PK ]cp."gems/irb-1.2.6/lib/irb/notifier.rbnu[# frozen_string_literal: false # # notifier.rb - output methods used by irb # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "output-method" module IRB # An output formatter used internally by the lexer. module Notifier class ErrUndefinedNotifier < StandardError def initialize(val) super("undefined notifier level: #{val} is specified") end end class ErrUnrecognizedLevel < StandardError def initialize(val) super("unrecognized notifier level: #{val} is specified") end end # Define a new Notifier output source, returning a new CompositeNotifier # with the given +prefix+ and +output_method+. # # The optional +prefix+ will be appended to all objects being inspected # during output, using the given +output_method+ as the output source. If # no +output_method+ is given, StdioOutputMethod will be used, and all # expressions will be sent directly to STDOUT without any additional # formatting. def def_notifier(prefix = "", output_method = StdioOutputMethod.new) CompositeNotifier.new(prefix, output_method) end module_function :def_notifier # An abstract class, or superclass, for CompositeNotifier and # LeveledNotifier to inherit. It provides several wrapper methods for the # OutputMethod object used by the Notifier. class AbstractNotifier # Creates a new Notifier object def initialize(prefix, base_notifier) @prefix = prefix @base_notifier = base_notifier end # The +prefix+ for this Notifier, which is appended to all objects being # inspected during output. attr_reader :prefix # A wrapper method used to determine whether notifications are enabled. # # Defaults to +true+. def notify? true end # See OutputMethod#print for more detail. def print(*opts) @base_notifier.print prefix, *opts if notify? end # See OutputMethod#printn for more detail. def printn(*opts) @base_notifier.printn prefix, *opts if notify? end # See OutputMethod#printf for more detail. def printf(format, *opts) @base_notifier.printf(prefix + format, *opts) if notify? end # See OutputMethod#puts for more detail. def puts(*objs) if notify? @base_notifier.puts(*objs.collect{|obj| prefix + obj.to_s}) end end # Same as #ppx, except it uses the #prefix given during object # initialization. # See OutputMethod#ppx for more detail. def pp(*objs) if notify? @base_notifier.ppx @prefix, *objs end end # Same as #pp, except it concatenates the given +prefix+ with the #prefix # given during object initialization. # # See OutputMethod#ppx for more detail. def ppx(prefix, *objs) if notify? @base_notifier.ppx @prefix+prefix, *objs end end # Execute the given block if notifications are enabled. def exec_if yield(@base_notifier) if notify? end end # A class that can be used to create a group of notifier objects with the # intent of representing a leveled notification system for irb. # # This class will allow you to generate other notifiers, and assign them # the appropriate level for output. # # The Notifier class provides a class-method Notifier.def_notifier to # create a new composite notifier. Using the first composite notifier # object you create, sibling notifiers can be initialized with # #def_notifier. class CompositeNotifier < AbstractNotifier # Create a new composite notifier object with the given +prefix+, and # +base_notifier+ to use for output. def initialize(prefix, base_notifier) super @notifiers = [D_NOMSG] @level_notifier = D_NOMSG end # List of notifiers in the group attr_reader :notifiers # Creates a new LeveledNotifier in the composite #notifiers group. # # The given +prefix+ will be assigned to the notifier, and +level+ will # be used as the index of the #notifiers Array. # # This method returns the newly created instance. def def_notifier(level, prefix = "") notifier = LeveledNotifier.new(self, level, prefix) @notifiers[level] = notifier notifier end # Returns the leveled notifier for this object attr_reader :level_notifier alias level level_notifier # Sets the leveled notifier for this object. # # When the given +value+ is an instance of AbstractNotifier, # #level_notifier is set to the given object. # # When an Integer is given, #level_notifier is set to the notifier at the # index +value+ in the #notifiers Array. # # If no notifier exists at the index +value+ in the #notifiers Array, an # ErrUndefinedNotifier exception is raised. # # An ErrUnrecognizedLevel exception is raised if the given +value+ is not # found in the existing #notifiers Array, or an instance of # AbstractNotifier def level_notifier=(value) case value when AbstractNotifier @level_notifier = value when Integer l = @notifiers[value] raise ErrUndefinedNotifier, value unless l @level_notifier = l else raise ErrUnrecognizedLevel, value unless l end end alias level= level_notifier= end # A leveled notifier is comparable to the composite group from # CompositeNotifier#notifiers. class LeveledNotifier < AbstractNotifier include Comparable # Create a new leveled notifier with the given +base+, and +prefix+ to # send to AbstractNotifier.new # # The given +level+ is used to compare other leveled notifiers in the # CompositeNotifier group to determine whether or not to output # notifications. def initialize(base, level, prefix) super(prefix, base) @level = level end # The current level of this notifier object attr_reader :level # Compares the level of this notifier object with the given +other+ # notifier. # # See the Comparable module for more information. def <=>(other) @level <=> other.level end # Whether to output messages to the output method, depending on the level # of this notifier object. def notify? @base_notifier.level >= self end end # NoMsgNotifier is a LeveledNotifier that's used as the default notifier # when creating a new CompositeNotifier. # # This notifier is used as the +zero+ index, or level +0+, for # CompositeNotifier#notifiers, and will not output messages of any sort. class NoMsgNotifier < LeveledNotifier # Creates a new notifier that should not be used to output messages. def initialize @base_notifier = nil @level = 0 @prefix = "" end # Ensures notifications are ignored, see AbstractNotifier#notify? for # more information. def notify? false end end D_NOMSG = NoMsgNotifier.new # :nodoc: end end PK ]D\\#gems/bundler-2.2.24/libexec/bundlernuȯ#!/usr/bin/ruby # frozen_string_literal: true load File.expand_path("../bundle", __FILE__) PK ]ʏM"gems/bundler-2.2.24/libexec/bundlenuȯ#!/usr/bin/ruby # frozen_string_literal: true # Exit cleanly from an early interrupt Signal.trap("INT") do Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler) exit 1 end base_path = File.expand_path("../lib", __dir__) if File.exist?(base_path) require_relative "../lib/bundler" else require "bundler" end # Check if an older version of bundler is installed $LOAD_PATH.each do |path| next unless path =~ %r{/bundler-0\.(\d+)} && $1.to_i < 9 err = String.new err << "Looks like you have a version of bundler that's older than 0.9.\n" err << "Please remove your old versions.\n" err << "An easy way to do this is by running `gem cleanup bundler`." abort(err) end if File.exist?(base_path) require_relative "../lib/bundler/friendly_errors" else require "bundler/friendly_errors" end Bundler.with_friendly_errors do if File.exist?(base_path) require_relative "../lib/bundler/cli" else require "bundler/cli" end # Allow any command to use --help flag to show help for that command help_flags = %w[--help -h] help_flag_used = ARGV.any? {|a| help_flags.include? a } args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV Bundler::CLI.start(args, :debug => true) end PK ]^ ^^"gems/bundler-2.2.24/lib/bundler.rbnu[# frozen_string_literal: true require_relative "bundler/vendored_fileutils" require "pathname" require "rbconfig" require_relative "bundler/errors" require_relative "bundler/environment_preserver" require_relative "bundler/plugin" require_relative "bundler/rubygems_ext" require_relative "bundler/rubygems_integration" require_relative "bundler/version" require_relative "bundler/constants" require_relative "bundler/current_ruby" require_relative "bundler/build_metadata" # Bundler provides a consistent environment for Ruby projects by # tracking and installing the exact gems and versions that are needed. # # Since Ruby 2.6, Bundler is a part of Ruby's standard library. # # Bunder is used by creating _gemfiles_ listing all the project dependencies # and (optionally) their versions and then using # # require 'bundler/setup' # # or Bundler.setup to setup environment where only specified gems and their # specified versions could be used. # # See {Bundler website}[https://bundler.io/docs.html] for extensive documentation # on gemfiles creation and Bundler usage. # # As a standard library inside project, Bundler could be used for introspection # of loaded and required modules. # module Bundler environment_preserver = EnvironmentPreserver.from_env ORIGINAL_ENV = environment_preserver.restore environment_preserver.replace_with_backup SUDO_MUTEX = Mutex.new autoload :Definition, File.expand_path("bundler/definition", __dir__) autoload :Dependency, File.expand_path("bundler/dependency", __dir__) autoload :DepProxy, File.expand_path("bundler/dep_proxy", __dir__) autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__) autoload :Dsl, File.expand_path("bundler/dsl", __dir__) autoload :EndpointSpecification, File.expand_path("bundler/endpoint_specification", __dir__) autoload :Env, File.expand_path("bundler/env", __dir__) autoload :Fetcher, File.expand_path("bundler/fetcher", __dir__) autoload :FeatureFlag, File.expand_path("bundler/feature_flag", __dir__) autoload :GemHelper, File.expand_path("bundler/gem_helper", __dir__) autoload :GemHelpers, File.expand_path("bundler/gem_helpers", __dir__) autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__) autoload :Graph, File.expand_path("bundler/graph", __dir__) autoload :Index, File.expand_path("bundler/index", __dir__) autoload :Injector, File.expand_path("bundler/injector", __dir__) autoload :Installer, File.expand_path("bundler/installer", __dir__) autoload :LazySpecification, File.expand_path("bundler/lazy_specification", __dir__) autoload :LockfileParser, File.expand_path("bundler/lockfile_parser", __dir__) autoload :MatchPlatform, File.expand_path("bundler/match_platform", __dir__) autoload :ProcessLock, File.expand_path("bundler/process_lock", __dir__) autoload :RemoteSpecification, File.expand_path("bundler/remote_specification", __dir__) autoload :Resolver, File.expand_path("bundler/resolver", __dir__) autoload :Retry, File.expand_path("bundler/retry", __dir__) autoload :RubyDsl, File.expand_path("bundler/ruby_dsl", __dir__) autoload :RubyVersion, File.expand_path("bundler/ruby_version", __dir__) autoload :Runtime, File.expand_path("bundler/runtime", __dir__) autoload :Settings, File.expand_path("bundler/settings", __dir__) autoload :SharedHelpers, File.expand_path("bundler/shared_helpers", __dir__) autoload :Source, File.expand_path("bundler/source", __dir__) autoload :SourceList, File.expand_path("bundler/source_list", __dir__) autoload :SourceMap, File.expand_path("bundler/source_map", __dir__) autoload :SpecSet, File.expand_path("bundler/spec_set", __dir__) autoload :StubSpecification, File.expand_path("bundler/stub_specification", __dir__) autoload :UI, File.expand_path("bundler/ui", __dir__) autoload :URICredentialsFilter, File.expand_path("bundler/uri_credentials_filter", __dir__) autoload :VersionRanges, File.expand_path("bundler/version_ranges", __dir__) class << self def configure @configured ||= configure_gem_home_and_path end def ui (defined?(@ui) && @ui) || (self.ui = UI::Shell.new) end def ui=(ui) Bundler.rubygems.ui = UI::RGProxy.new(ui) @ui = ui end # Returns absolute path of where gems are installed on the filesystem. def bundle_path @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root) end def configured_bundle_path @configured_bundle_path ||= settings.path.tap(&:validate!) end # Returns absolute location of where binstubs are installed to. def bin_path @bin_path ||= begin path = settings[:bin] || "bin" path = Pathname.new(path).expand_path(root).expand_path SharedHelpers.filesystem_access(path) {|p| FileUtils.mkdir_p(p) } path end end # Turns on the Bundler runtime. After +Bundler.setup+ call, all +load+ or # +require+ of the gems would be allowed only if they are part of # the Gemfile or Ruby's standard library. If the versions specified # in Gemfile, only those versions would be loaded. # # Assuming Gemfile # # gem 'first_gem', '= 1.0' # group :test do # gem 'second_gem', '= 1.0' # end # # The code using Bundler.setup works as follows: # # require 'third_gem' # allowed, required from global gems # require 'first_gem' # allowed, loads the last installed version # Bundler.setup # require 'fourth_gem' # fails with LoadError # require 'second_gem' # loads exactly version 1.0 # # +Bundler.setup+ can be called only once, all subsequent calls are no-op. # # If _groups_ list is provided, only gems from specified groups would # be allowed (gems specified outside groups belong to special +:default+ group). # # To require all gems from Gemfile (or only some groups), see Bundler.require. # def setup(*groups) # Return if all groups are already loaded return @setup if defined?(@setup) && @setup definition.validate_runtime! SharedHelpers.print_major_deprecations! if groups.empty? # Load all groups, but only once @setup = load.setup else load.setup(*groups) end end # Setups Bundler environment (see Bundler.setup) if it is not already set, # and loads all gems from groups specified. Unlike ::setup, can be called # multiple times with different groups (if they were allowed by setup). # # Assuming Gemfile # # gem 'first_gem', '= 1.0' # group :test do # gem 'second_gem', '= 1.0' # end # # The code will work as follows: # # Bundler.setup # allow all groups # Bundler.require(:default) # requires only first_gem # # ...later # Bundler.require(:test) # requires second_gem # def require(*groups) setup(*groups).require(*groups) end def load @load ||= Runtime.new(root, definition) end def environment SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", :print_caller_location => true load end # Returns an instance of Bundler::Definition for given Gemfile and lockfile # # @param unlock [Hash, Boolean, nil] Gems that have been requested # to be updated or true if all gems should be updated # @return [Bundler::Definition] def definition(unlock = nil) @definition = nil if unlock @definition ||= begin configure Definition.build(default_gemfile, default_lockfile, unlock) end end def frozen_bundle? frozen = settings[:deployment] frozen ||= settings[:frozen] frozen end def locked_gems @locked_gems ||= if defined?(@definition) && @definition definition.locked_gems elsif Bundler.default_lockfile.file? lock = Bundler.read_file(Bundler.default_lockfile) LockfileParser.new(lock) end end def most_specific_locked_platform?(platform) return false unless defined?(@definition) && @definition definition.most_specific_locked_platform == platform end def ruby_scope "#{Bundler.rubygems.ruby_engine}/#{RbConfig::CONFIG["ruby_version"]}" end def user_home @user_home ||= begin home = Bundler.rubygems.user_home bundle_home = home ? File.join(home, ".bundle") : nil warning = if home.nil? "Your home directory is not set." elsif !File.directory?(home) "`#{home}` is not a directory." elsif !File.writable?(home) && (!File.directory?(bundle_home) || !File.writable?(bundle_home)) "`#{home}` is not writable." end if warning Bundler.ui.warn "#{warning}\n" user_home = tmp_home_path Bundler.ui.warn "Bundler will use `#{user_home}' as your home directory temporarily.\n" user_home else Pathname.new(home) end end end def user_bundle_path(dir = "home") env_var, fallback = case dir when "home" ["BUNDLE_USER_HOME", proc { Pathname.new(user_home).join(".bundle") }] when "cache" ["BUNDLE_USER_CACHE", proc { user_bundle_path.join("cache") }] when "config" ["BUNDLE_USER_CONFIG", proc { user_bundle_path.join("config") }] when "plugin" ["BUNDLE_USER_PLUGIN", proc { user_bundle_path.join("plugin") }] else raise BundlerError, "Unknown user path requested: #{dir}" end # `fallback` will already be a Pathname, but Pathname.new() is # idempotent so it's OK Pathname.new(ENV.fetch(env_var, &fallback)) end def user_cache user_bundle_path("cache") end def home bundle_path.join("bundler") end def install_path home.join("gems") end def specs_path bundle_path.join("specifications") end def root @root ||= begin SharedHelpers.root rescue GemfileNotFound bundle_dir = default_bundle_dir raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir Pathname.new(File.expand_path("..", bundle_dir)) end end def app_config_path if app_config = ENV["BUNDLE_APP_CONFIG"] app_config_pathname = Pathname.new(app_config) if app_config_pathname.absolute? app_config_pathname else app_config_pathname.expand_path(root) end else root.join(".bundle") end end def app_cache(custom_path = nil) path = custom_path || root Pathname.new(path).join(settings.app_cache_path) end def tmp(name = Process.pid.to_s) Kernel.send(:require, "tmpdir") Pathname.new(Dir.mktmpdir(["bundler", name])) end def rm_rf(path) FileUtils.remove_entry_secure(path) if path && File.exist?(path) rescue ArgumentError message = < true ) unbundled_env end # @return [Hash] Environment with all bundler-related variables removed def unbundled_env env = original_env if env.key?("BUNDLER_ORIG_MANPATH") env["MANPATH"] = env["BUNDLER_ORIG_MANPATH"] end env.delete_if {|k, _| k[0, 7] == "BUNDLE_" } if env.key?("RUBYOPT") rubyopt = env["RUBYOPT"].split(" ") rubyopt.delete("-r#{File.expand_path("bundler/setup", __dir__)}") rubyopt.delete("-rbundler/setup") env["RUBYOPT"] = rubyopt.join(" ") end if env.key?("RUBYLIB") rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR) rubylib.delete(File.expand_path("..", __FILE__)) env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR) end env end # Run block with environment present before Bundler was activated def with_original_env with_env(original_env) { yield } end # @deprecated Use `with_unbundled_env` instead def with_clean_env Bundler::SharedHelpers.major_deprecation( 2, "`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \ "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`", :print_caller_location => true ) with_env(unbundled_env) { yield } end # Run block with all bundler-related variables removed def with_unbundled_env with_env(unbundled_env) { yield } end # Run subcommand with the environment present before Bundler was activated def original_system(*args) with_original_env { Kernel.system(*args) } end # @deprecated Use `unbundled_system` instead def clean_system(*args) Bundler::SharedHelpers.major_deprecation( 2, "`Bundler.clean_system` has been deprecated in favor of `Bundler.unbundled_system`. " \ "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`", :print_caller_location => true ) with_env(unbundled_env) { Kernel.system(*args) } end # Run subcommand in an environment with all bundler related variables removed def unbundled_system(*args) with_unbundled_env { Kernel.system(*args) } end # Run a `Kernel.exec` to a subcommand with the environment present before Bundler was activated def original_exec(*args) with_original_env { Kernel.exec(*args) } end # @deprecated Use `unbundled_exec` instead def clean_exec(*args) Bundler::SharedHelpers.major_deprecation( 2, "`Bundler.clean_exec` has been deprecated in favor of `Bundler.unbundled_exec`. " \ "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`", :print_caller_location => true ) with_env(unbundled_env) { Kernel.exec(*args) } end # Run a `Kernel.exec` to a subcommand in an environment with all bundler related variables removed def unbundled_exec(*args) with_env(unbundled_env) { Kernel.exec(*args) } end def local_platform return Gem::Platform::RUBY if settings[:force_ruby_platform] || Gem.platforms == [Gem::Platform::RUBY] Gem::Platform.local end def default_gemfile SharedHelpers.default_gemfile end def default_lockfile SharedHelpers.default_lockfile end def default_bundle_dir SharedHelpers.default_bundle_dir end def system_bindir # Gem.bindir doesn't always return the location that RubyGems will install # system binaries. If you put '-n foo' in your .gemrc, RubyGems will # install binstubs there instead. Unfortunately, RubyGems doesn't expose # that directory at all, so rather than parse .gemrc ourselves, we allow # the directory to be set as well, via `bundle config set --local bindir foo`. Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir end def preferred_gemfile_name Bundler.settings[:init_gems_rb] ? "gems.rb" : "Gemfile" end def use_system_gems? configured_bundle_path.use_system_gems? end def requires_sudo? return @requires_sudo if defined?(@requires_sudo_ran) sudo_present = which "sudo" if settings.allow_sudo? if sudo_present # the bundle path and subdirectories need to be writable for RubyGems # to be able to unpack and install gems without exploding path = bundle_path path = path.parent until path.exist? # bins are written to a different location on OS X bin_dir = Pathname.new(Bundler.system_bindir) bin_dir = bin_dir.parent until bin_dir.exist? # if any directory is not writable, we need sudo files = [path, bin_dir] | Dir[bundle_path.join("build_info/*").to_s] | Dir[bundle_path.join("*").to_s] unwritable_files = files.reject {|f| File.writable?(f) } sudo_needed = !unwritable_files.empty? if sudo_needed Bundler.ui.warn "Following files may not be writable, so sudo is needed:\n #{unwritable_files.map(&:to_s).sort.join("\n ")}" end end @requires_sudo_ran = true @requires_sudo = settings.allow_sudo? && sudo_present && sudo_needed end def mkdir_p(path, options = {}) if requires_sudo? && !options[:no_sudo] sudo "mkdir -p '#{path}'" unless File.exist?(path) else SharedHelpers.filesystem_access(path, :write) do |p| FileUtils.mkdir_p(p) end end end def which(executable) if File.file?(executable) && File.executable?(executable) executable elsif paths = ENV["PATH"] quote = '"'.freeze paths.split(File::PATH_SEPARATOR).find do |path| path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote) executable_path = File.expand_path(executable, path) return executable_path if File.file?(executable_path) && File.executable?(executable_path) end end end def sudo(str) SUDO_MUTEX.synchronize do prompt = "\n\n" + <<-PROMPT.gsub(/^ {6}/, "").strip + " " Your user account isn't allowed to install to the system RubyGems. You can cancel this installation and run: bundle config set --local path 'vendor/bundle' bundle install to install the gems into ./vendor/bundle/, or you can enter your password and install the bundled gems to RubyGems using sudo. Password: PROMPT unless @prompted_for_sudo ||= system(%(sudo -k -p "#{prompt}" true)) raise SudoNotPermittedError, "Bundler requires sudo access to install at the moment. " \ "Try installing again, granting Bundler sudo access when prompted, or installing into a different path." end `sudo -p "#{prompt}" #{str}` end end def read_file(file) SharedHelpers.filesystem_access(file, :read) do File.open(file, "r:UTF-8", &:read) end end def load_marshal(data) Marshal.load(data) rescue StandardError => e raise MarshalError, "#{e.class}: #{e.message}" end def load_gemspec(file, validate = false) @gemspec_cache ||= {} key = File.expand_path(file) @gemspec_cache[key] ||= load_gemspec_uncached(file, validate) # Protect against caching side-effected gemspecs by returning a # new instance each time. @gemspec_cache[key].dup if @gemspec_cache[key] end def load_gemspec_uncached(file, validate = false) path = Pathname.new(file) contents = read_file(file) spec = if contents.start_with?("---") # YAML header eval_yaml_gemspec(path, contents) else # Eval the gemspec from its parent directory, because some gemspecs # depend on "./" relative paths. SharedHelpers.chdir(path.dirname.to_s) do eval_gemspec(path, contents) end end return unless spec spec.loaded_from = path.expand_path.to_s Bundler.rubygems.validate(spec) if validate spec end def clear_gemspec_cache @gemspec_cache = {} end def git_present? return @git_present if defined?(@git_present) @git_present = Bundler.which("git") || Bundler.which("git.exe") end def feature_flag @feature_flag ||= FeatureFlag.new(VERSION) end def reset! reset_paths! Plugin.reset! reset_rubygems! end def reset_settings_and_root! @settings = nil @root = nil end def reset_paths! @bin_path = nil @bundler_major_version = nil @bundle_path = nil @configured = nil @configured_bundle_path = nil @definition = nil @load = nil @locked_gems = nil @root = nil @settings = nil @setup = nil @user_home = nil end def reset_rubygems! return unless defined?(@rubygems) && @rubygems rubygems.undo_replacements rubygems.reset @rubygems = nil end private def eval_yaml_gemspec(path, contents) require_relative "bundler/psyched_yaml" # If the YAML is invalid, Syck raises an ArgumentError, and Psych # raises a Psych::SyntaxError. See psyched_yaml.rb for more info. Gem::Specification.from_yaml(contents) rescue YamlLibrarySyntaxError, ArgumentError, Gem::EndOfYAMLException, Gem::Exception eval_gemspec(path, contents) end def eval_gemspec(path, contents) eval(contents, TOPLEVEL_BINDING.dup, path.expand_path.to_s) rescue ScriptError, StandardError => e msg = "There was an error while loading `#{path.basename}`: #{e.message}" if e.is_a?(LoadError) msg += "\nDoes it try to require a relative path? That's been removed in Ruby 1.9" end raise GemspecError, Dsl::DSLError.new(msg, path, e.backtrace, contents) end def configure_gem_home_and_path configure_gem_path configure_gem_home bundle_path end def configure_gem_path(env = ENV) blank_home = env["GEM_HOME"].nil? || env["GEM_HOME"].empty? if !use_system_gems? # this needs to be empty string to cause # PathSupport.split_gem_path to only load up the # Bundler --path setting as the GEM_PATH. env["GEM_PATH"] = "" elsif blank_home possibles = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path] paths = possibles.flatten.compact.uniq.reject(&:empty?) env["GEM_PATH"] = paths.join(File::PATH_SEPARATOR) end end def configure_gem_home Bundler::SharedHelpers.set_env "GEM_HOME", File.expand_path(bundle_path, root) Bundler.rubygems.clear_paths end def tmp_home_path Kernel.send(:require, "tmpdir") SharedHelpers.filesystem_access(Dir.tmpdir) do path = Bundler.tmp at_exit { Bundler.rm_rf(path) } path end end # @param env [Hash] def with_env(env) backup = ENV.to_hash ENV.replace(env) yield ensure ENV.replace(backup) end end end PK ]tJT T )gems/bundler-2.2.24/lib/bundler/source.rbnu[# frozen_string_literal: true module Bundler class Source autoload :Gemspec, File.expand_path("source/gemspec", __dir__) autoload :Git, File.expand_path("source/git", __dir__) autoload :Metadata, File.expand_path("source/metadata", __dir__) autoload :Path, File.expand_path("source/path", __dir__) autoload :Rubygems, File.expand_path("source/rubygems", __dir__) autoload :RubygemsAggregate, File.expand_path("source/rubygems_aggregate", __dir__) attr_accessor :dependency_names def unmet_deps specs.unmet_dependency_names end def version_message(spec) message = "#{spec.name} #{spec.version}" message += " (#{spec.platform})" if spec.platform != Gem::Platform::RUBY && !spec.platform.nil? if Bundler.locked_gems locked_spec = Bundler.locked_gems.specs.find {|s| s.name == spec.name } locked_spec_version = locked_spec.version if locked_spec if locked_spec_version && spec.version != locked_spec_version message += Bundler.ui.add_color(" (was #{locked_spec_version})", version_color(spec.version, locked_spec_version)) end end message end def can_lock?(spec) spec.source == self end def local!; end def local_only!; end def cached!; end def remote!; end def add_dependency_names(names) @dependency_names = Array(dependency_names) | Array(names) end # it's possible that gems from one source depend on gems from some # other source, so now we download gemspecs and iterate over those # dependencies, looking for gems we don't have info on yet. def double_check_for(*); end def dependency_names_to_double_check specs.dependency_names end def spec_names specs.spec_names end def include?(other) other == self end def inspect "#<#{self.class}:0x#{object_id} #{self}>" end def path? instance_of?(Bundler::Source::Path) end def extension_cache_path(spec) return unless Bundler.feature_flag.global_gem_cache? return unless source_slug = extension_cache_slug(spec) Bundler.user_cache.join( "extensions", Gem::Platform.local.to_s, Bundler.ruby_scope, source_slug, spec.full_name ) end private def version_color(spec_version, locked_spec_version) if Gem::Version.correct?(spec_version) && Gem::Version.correct?(locked_spec_version) # display yellow if there appears to be a regression earlier_version?(spec_version, locked_spec_version) ? :yellow : :green else # default to green if the versions cannot be directly compared :green end end def earlier_version?(spec_version, locked_spec_version) Gem::Version.new(spec_version) < Gem::Version.new(locked_spec_version) end def print_using_message(message) if !message.include?("(was ") && Bundler.feature_flag.suppress_install_using_messages? Bundler.ui.debug message else Bundler.ui.info message end end def extension_cache_slug(_) nil end end end PK ]${9gems/bundler-2.2.24/lib/bundler/endpoint_specification.rbnu[# frozen_string_literal: true module Bundler # used for Creating Specifications from the Gemcutter Endpoint class EndpointSpecification < Gem::Specification ILLFORMED_MESSAGE = 'Ill-formed requirement ["# e raise GemspecError, "There was an error parsing the metadata for the gem #{name} (#{version}): #{e.class}\n#{e}\nThe metadata was #{data.inspect}" end def build_dependency(name, requirements) Gem::Dependency.new(name, requirements) rescue ArgumentError => e raise unless e.message.include?(ILLFORMED_MESSAGE) puts # we shouldn't print the error message on the "fetching info" status line raise GemspecError, "Unfortunately, the gem #{name} (#{version}) has an invalid " \ "gemspec.\nPlease ask the gem author to yank the bad version to fix " \ "this issue. For more information, see http://bit.ly/syck-defaultkey." end end end PK ]١"2)2)*gems/bundler-2.2.24/lib/bundler/runtime.rbnu[# frozen_string_literal: true module Bundler class Runtime include SharedHelpers def initialize(root, definition) @root = root @definition = definition end def setup(*groups) @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen_bundle? # Has to happen first clean_load_path specs = @definition.specs_for(groups) SharedHelpers.set_bundle_environment Bundler.rubygems.replace_entrypoints(specs) # Activate the specs load_paths = specs.map do |spec| unless spec.loaded_from raise GemNotFound, "#{spec.full_name} is missing. Run `bundle install` to get it." end check_for_activated_spec!(spec) Bundler.rubygems.mark_loaded(spec) spec.load_paths.reject {|path| $LOAD_PATH.include?(path) } end.reverse.flatten Bundler.rubygems.add_to_load_path(load_paths) setup_manpath lock(:preserve_unknown_sections => true) self end def require(*groups) groups.map!(&:to_sym) groups = [:default] if groups.empty? @definition.dependencies.each do |dep| # Skip the dependency if it is not in any of the requested groups, or # not for the current platform, or doesn't match the gem constraints. next unless (dep.groups & groups).any? && dep.should_include? required_file = nil begin # Loop through all the specified autorequires for the # dependency. If there are none, use the dependency's name # as the autorequire. Array(dep.autorequire || dep.name).each do |file| # Allow `require: true` as an alias for `require: ` file = dep.name if file == true required_file = file begin Kernel.require file rescue RuntimeError => e raise e if e.is_a?(LoadError) # we handle this a little later raise Bundler::GemRequireError.new e, "There was an error while trying to load the gem '#{file}'." end end rescue LoadError => e raise if dep.autorequire || e.path != required_file if dep.autorequire.nil? && dep.name.include?("-") begin namespaced_file = dep.name.tr("-", "/") Kernel.require namespaced_file rescue LoadError => e raise if e.path != namespaced_file end end end end end def self.definition_method(meth) define_method(meth) do raise ArgumentError, "no definition when calling Runtime##{meth}" unless @definition @definition.send(meth) end end private_class_method :definition_method definition_method :requested_specs definition_method :specs definition_method :dependencies definition_method :current_dependencies definition_method :requires def lock(opts = {}) return if @definition.nothing_changed? && !@definition.unlocking? @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections]) end alias_method :gems, :specs def cache(custom_path = nil) cache_path = Bundler.app_cache(custom_path) SharedHelpers.filesystem_access(cache_path) do |p| FileUtils.mkdir_p(p) end unless File.exist?(cache_path) Bundler.ui.info "Updating files in #{Bundler.settings.app_cache_path}" specs_to_cache = Bundler.settings[:cache_all_platforms] ? @definition.resolve.materialized_for_all_platforms : specs specs_to_cache.each do |spec| next if spec.name == "bundler" next if spec.source.is_a?(Source::Gemspec) spec.source.send(:fetch_gem, spec) if Bundler.settings[:cache_all_platforms] && spec.source.respond_to?(:fetch_gem, true) spec.source.cache(spec, custom_path) if spec.source.respond_to?(:cache) end Dir[cache_path.join("*/.git")].each do |git_dir| FileUtils.rm_rf(git_dir) FileUtils.touch(File.expand_path("../.bundlecache", git_dir)) end prune_cache(cache_path) unless Bundler.settings[:no_prune] end def prune_cache(cache_path) SharedHelpers.filesystem_access(cache_path) do |p| FileUtils.mkdir_p(p) end unless File.exist?(cache_path) resolve = @definition.resolve prune_gem_cache(resolve, cache_path) prune_git_and_path_cache(resolve, cache_path) end def clean(dry_run = false) gem_bins = Dir["#{Gem.dir}/bin/*"] git_dirs = Dir["#{Gem.dir}/bundler/gems/*"] git_cache_dirs = Dir["#{Gem.dir}/cache/bundler/git/*"] gem_dirs = Dir["#{Gem.dir}/gems/*"] gem_files = Dir["#{Gem.dir}/cache/*.gem"] gemspec_files = Dir["#{Gem.dir}/specifications/*.gemspec"] extension_dirs = Dir["#{Gem.dir}/extensions/*/*/*"] + Dir["#{Gem.dir}/bundler/gems/extensions/*/*/*"] spec_gem_paths = [] # need to keep git sources around spec_git_paths = @definition.spec_git_paths spec_git_cache_dirs = [] spec_gem_executables = [] spec_cache_paths = [] spec_gemspec_paths = [] spec_extension_paths = [] Bundler.rubygems.add_default_gems_to(specs).values.each do |spec| spec_gem_paths << spec.full_gem_path # need to check here in case gems are nested like for the rails git repo md = %r{(.+bundler/gems/.+-[a-f0-9]{7,12})}.match(spec.full_gem_path) spec_git_paths << md[1] if md spec_gem_executables << spec.executables.collect do |executable| e = "#{Bundler.rubygems.gem_bindir}/#{executable}" [e, "#{e}.bat"] end spec_cache_paths << spec.cache_file spec_gemspec_paths << spec.spec_file spec_extension_paths << spec.extension_dir if spec.respond_to?(:extension_dir) spec_git_cache_dirs << spec.source.cache_path.to_s if spec.source.is_a?(Bundler::Source::Git) end spec_gem_paths.uniq! spec_gem_executables.flatten! stale_gem_bins = gem_bins - spec_gem_executables stale_git_dirs = git_dirs - spec_git_paths - ["#{Gem.dir}/bundler/gems/extensions"] stale_git_cache_dirs = git_cache_dirs - spec_git_cache_dirs stale_gem_dirs = gem_dirs - spec_gem_paths stale_gem_files = gem_files - spec_cache_paths stale_gemspec_files = gemspec_files - spec_gemspec_paths stale_extension_dirs = extension_dirs - spec_extension_paths removed_stale_gem_dirs = stale_gem_dirs.collect {|dir| remove_dir(dir, dry_run) } removed_stale_git_dirs = stale_git_dirs.collect {|dir| remove_dir(dir, dry_run) } output = removed_stale_gem_dirs + removed_stale_git_dirs unless dry_run stale_files = stale_gem_bins + stale_gem_files + stale_gemspec_files stale_files.each do |file| SharedHelpers.filesystem_access(File.dirname(file)) do |_p| FileUtils.rm(file) if File.exist?(file) end end stale_dirs = stale_git_cache_dirs + stale_extension_dirs stale_dirs.each do |stale_dir| SharedHelpers.filesystem_access(stale_dir) do |dir| FileUtils.rm_rf(dir) if File.exist?(dir) end end end output end private def prune_gem_cache(resolve, cache_path) cached = Dir["#{cache_path}/*.gem"] cached = cached.delete_if do |path| spec = Bundler.rubygems.spec_from_gem path resolve.any? do |s| s.name == spec.name && s.version == spec.version && !s.source.is_a?(Bundler::Source::Git) end end if cached.any? Bundler.ui.info "Removing outdated .gem files from #{Bundler.settings.app_cache_path}" cached.each do |path| Bundler.ui.info " * #{File.basename(path)}" File.delete(path) end end end def prune_git_and_path_cache(resolve, cache_path) cached = Dir["#{cache_path}/*/.bundlecache"] cached = cached.delete_if do |path| name = File.basename(File.dirname(path)) resolve.any? do |s| source = s.source source.respond_to?(:app_cache_dirname) && source.app_cache_dirname == name end end if cached.any? Bundler.ui.info "Removing outdated git and path gems from #{Bundler.settings.app_cache_path}" cached.each do |path| path = File.dirname(path) Bundler.ui.info " * #{File.basename(path)}" FileUtils.rm_rf(path) end end end def setup_manpath # Add man/ subdirectories from activated bundles to MANPATH for man(1) manuals = $LOAD_PATH.map do |path| man_subdir = path.sub(/lib$/, "man") man_subdir unless Dir[man_subdir + "/man?/"].empty? end.compact return if manuals.empty? Bundler::SharedHelpers.set_env "MANPATH", manuals.concat( ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR) ).uniq.join(File::PATH_SEPARATOR) end def remove_dir(dir, dry_run) full_name = Pathname.new(dir).basename.to_s parts = full_name.split("-") name = parts[0..-2].join("-") version = parts.last output = "#{name} (#{version})" if dry_run Bundler.ui.info "Would have removed #{output}" else Bundler.ui.info "Removing #{output}" FileUtils.rm_rf(dir) end output end def check_for_activated_spec!(spec) return unless activated_spec = Bundler.rubygems.loaded_specs(spec.name) return if activated_spec.version == spec.version suggestion = if Bundler.rubygems.spec_default_gem?(activated_spec) "Since #{spec.name} is a default gem, you can either remove your dependency on it" \ " or try updating to a newer version of bundler that supports #{spec.name} as a default gem." else "Prepending `bundle exec` to your command may solve this." end e = Gem::LoadError.new "You have already activated #{activated_spec.name} #{activated_spec.version}, " \ "but your Gemfile requires #{spec.name} #{spec.version}. #{suggestion}" e.name = spec.name if e.respond_to?(:requirement=) e.requirement = Gem::Requirement.new(spec.version.to_s) else e.version_requirement = Gem::Requirement.new(spec.version.to_s) end raise e end end end PK ]P5gems/bundler-2.2.24/lib/bundler/lazy_specification.rbnu[# frozen_string_literal: true require_relative "match_platform" module Bundler class LazySpecification include MatchPlatform attr_reader :name, :version, :dependencies, :platform attr_accessor :source, :remote def initialize(name, version, platform, source = nil) @name = name @version = version @dependencies = [] @platform = platform || Gem::Platform::RUBY @source = source @specification = nil end def full_name if platform == Gem::Platform::RUBY || platform.nil? "#{@name}-#{@version}" else "#{@name}-#{@version}-#{platform}" end end def ==(other) identifier == other.identifier end def eql?(other) identifier.eql?(other.identifier) end def hash identifier.hash end def satisfies?(dependency) @name == dependency.name && dependency.requirement.satisfied_by?(Gem::Version.new(@version)) end def to_lock out = String.new if platform == Gem::Platform::RUBY || platform.nil? out << " #{name} (#{version})\n" else out << " #{name} (#{version}-#{platform})\n" end dependencies.sort_by(&:to_s).uniq.each do |dep| next if dep.type == :development out << " #{dep.to_lock}\n" end out end def __materialize__ @specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name source.gemspec.tap {|s| s.source = source } else search_object = if source.is_a?(Source::Path) Dependency.new(name, version) else ruby_platform_materializes_to_ruby_platform? ? self : Dependency.new(name, version) end platform_object = Gem::Platform.new(platform) candidates = source.specs.search(search_object) same_platform_candidates = candidates.select do |spec| MatchPlatform.platforms_match?(spec.platform, platform_object) end installable_candidates = same_platform_candidates.select do |spec| !spec.is_a?(EndpointSpecification) || (spec.required_ruby_version.satisfied_by?(Gem.ruby_version) && spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)) end search = installable_candidates.last || same_platform_candidates.last search.dependencies = dependencies if search && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) search end end def respond_to?(*args) super || @specification ? @specification.respond_to?(*args) : nil end def to_s @__to_s ||= if platform == Gem::Platform::RUBY || platform.nil? "#{name} (#{version})" else "#{name} (#{version}-#{platform})" end end def identifier @__identifier ||= [name, version, platform_string] end def git_version return unless source.is_a?(Bundler::Source::Git) " #{source.revision[0..6]}" end protected def platform_string platform_string = platform.to_s platform_string == Index::RUBY ? Index::NULL : platform_string end private def to_ary nil end def method_missing(method, *args, &blk) raise "LazySpecification has not been materialized yet (calling :#{method} #{args.inspect})" unless @specification return super unless respond_to?(method) @specification.send(method, *args, &blk) end # # For backwards compatibility with existing lockfiles, if the most specific # locked platform is RUBY, we keep the previous behaviour of resolving the # best platform variant at materiliazation time. For previous bundler # versions (before 2.2.0) this was always the case (except when the lockfile # only included non-ruby platforms), but we're also keeping this behaviour # on newer bundlers unless users generate the lockfile from scratch or # explicitly add a more specific platform. # def ruby_platform_materializes_to_ruby_platform? !Bundler.most_specific_locked_platform?(Gem::Platform::RUBY) || Bundler.settings[:force_ruby_platform] end end end PK ]eo}O}O&gems/bundler-2.2.24/lib/bundler/dsl.rbnu[# frozen_string_literal: true require_relative "dependency" require_relative "ruby_dsl" module Bundler class Dsl include RubyDsl def self.evaluate(gemfile, lockfile, unlock) builder = new builder.eval_gemfile(gemfile) builder.to_definition(lockfile, unlock) end VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules platform platforms type source install_if gemfile].freeze attr_reader :gemspecs attr_accessor :dependencies def initialize @source = nil @sources = SourceList.new @git_sources = {} @dependencies = [] @groups = [] @install_conditionals = [] @optional_groups = [] @platforms = [] @env = nil @ruby_version = nil @gemspecs = [] @gemfile = nil @gemfiles = [] add_git_sources end def eval_gemfile(gemfile, contents = nil) expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile && @gemfile.parent) original_gemfile = @gemfile @gemfile = expanded_gemfile_path @gemfiles << expanded_gemfile_path contents ||= Bundler.read_file(@gemfile.to_s) instance_eval(contents.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1) rescue Exception => e # rubocop:disable Lint/RescueException message = "There was an error " \ "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ "`#{File.basename gemfile.to_s}`: #{e.message}" raise DSLError.new(message, gemfile, e.backtrace, contents) ensure @gemfile = original_gemfile end def gemspec(opts = nil) opts ||= {} path = opts[:path] || "." glob = opts[:glob] name = opts[:name] development_group = opts[:development_group] || :development expanded_path = gemfile_root.join(path) gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).map {|g| Bundler.load_gemspec(g) }.compact gemspecs.reject! {|s| s.name != name } if name Index.sort_specs(gemspecs) specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] } case specs_by_name_and_version.size when 1 specs = specs_by_name_and_version.values.first spec = specs.find {|s| s.match_platform(Bundler.local_platform) } || specs.first @gemspecs << spec gem spec.name, :name => spec.name, :path => path, :glob => glob group(development_group) do spec.development_dependencies.each do |dep| gem dep.name, *(dep.requirement.as_list + [:type => :development]) end end when 0 raise InvalidOption, "There are no gemspecs at #{expanded_path}" else raise InvalidOption, "There are multiple gemspecs at #{expanded_path}. " \ "Please use the :name option to specify which one should be used" end end def gem(name, *args) options = args.last.is_a?(Hash) ? args.pop.dup : {} options["gemfile"] = @gemfile version = args || [">= 0"] normalize_options(name, version, options) dep = Dependency.new(name, version, options) # if there's already a dependency with this name we try to prefer one if current = @dependencies.find {|d| d.name == dep.name } deleted_dep = @dependencies.delete(current) if current.type == :development unless deleted_dep if current.requirement != dep.requirement return if dep.type == :development update_prompt = "" if File.basename(@gemfile) == Injector::INJECTED_GEMS if dep.requirements_list.include?(">= 0") && !current.requirements_list.include?(">= 0") update_prompt = ". Gem already added" else update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`" update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current.requirements_list.include?(">= 0") end end raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \ "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \ "#{update_prompt}" else Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \ "You should probably keep only one of them.\n" \ "Remove any duplicate entries and specify the gem only once.\n" \ "While it's not a problem now, it could cause errors if you change the version of one of them later." end if current.source != dep.source return if dep.type == :development raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ "You specified that #{dep.name} (#{dep.requirement}) should come from " \ "#{current.source || "an unspecified source"} and #{dep.source}\n" end end end @dependencies << dep end def source(source, *args, &blk) options = args.last.is_a?(Hash) ? args.pop.dup : {} options = normalize_hash(options) source = normalize_source(source) if options.key?("type") options["type"] = options["type"].to_s unless Plugin.source?(options["type"]) raise InvalidOption, "No plugin sources available for #{options["type"]}" end unless block_given? raise InvalidOption, "You need to pass a block to #source with :type option" end source_opts = options.merge("uri" => source) with_source(@sources.add_plugin_source(options["type"], source_opts), &blk) elsif block_given? with_source(@sources.add_rubygems_source("remotes" => source), &blk) else @sources.add_global_rubygems_remote(source) end end def git_source(name, &block) unless block_given? raise InvalidOption, "You need to pass a block to #git_source" end if valid_keys.include?(name.to_s) raise InvalidOption, "You cannot use #{name} as a git source. It " \ "is a reserved key. Reserved keys are: #{valid_keys.join(", ")}" end @git_sources[name.to_s] = block end def path(path, options = {}, &blk) source_options = normalize_hash(options).merge( "path" => Pathname.new(path), "root_path" => gemfile_root, "gemspec" => gemspecs.find {|g| g.name == options["name"] } ) source_options["global"] = true unless block_given? source = @sources.add_path_source(source_options) with_source(source, &blk) end def git(uri, options = {}, &blk) unless block_given? msg = "You can no longer specify a git source by itself. Instead, \n" \ "either use the :git option on a gem, or specify the gems that \n" \ "bundler should find in the git source by passing a block to \n" \ "the git method, like: \n\n" \ " git 'git://github.com/rails/rails.git' do\n" \ " gem 'rails'\n" \ " end" raise DeprecatedError, msg end with_source(@sources.add_git_source(normalize_hash(options).merge("uri" => uri)), &blk) end def github(repo, options = {}) raise ArgumentError, "GitHub sources require a block" unless block_given? github_uri = @git_sources["github"].call(repo) git_options = normalize_hash(options).merge("uri" => github_uri) git_source = @sources.add_git_source(git_options) with_source(git_source) { yield } end def to_definition(lockfile, unlock) check_primary_source_safety Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles) end def group(*args, &blk) options = args.last.is_a?(Hash) ? args.pop.dup : {} normalize_group_options(options, args) @groups.concat args if options["optional"] optional_groups = args - @optional_groups @optional_groups.concat optional_groups end yield ensure args.each { @groups.pop } end def install_if(*args) @install_conditionals.concat args yield ensure args.each { @install_conditionals.pop } end def platforms(*platforms) @platforms.concat platforms yield ensure platforms.each { @platforms.pop } end alias_method :platform, :platforms def env(name) old = @env @env = name yield ensure @env = old end def plugin(*args) # Pass on end def method_missing(name, *args) raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" end def check_primary_source_safety check_path_source_safety check_rubygems_source_safety end private def add_git_sources git_source(:github) do |repo_name| warn_deprecated_git_source(:github, <<-'RUBY'.strip, 'Change any "reponame" :github sources to "username/reponame".') "https://github.com/#{repo_name}.git" RUBY repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") "https://github.com/#{repo_name}.git" end git_source(:gist) do |repo_name| warn_deprecated_git_source(:gist, '"https://gist.github.com/#{repo_name}.git"') "https://gist.github.com/#{repo_name}.git" end git_source(:bitbucket) do |repo_name| warn_deprecated_git_source(:bitbucket, <<-'RUBY'.strip) user_name, repo_name = repo_name.split("/") repo_name ||= user_name "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" RUBY user_name, repo_name = repo_name.split("/") repo_name ||= user_name "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" end end def with_source(source) old_source = @source if block_given? @source = source yield end source ensure @source = old_source end def normalize_hash(opts) opts.keys.each do |k| opts[k.to_s] = opts.delete(k) unless k.is_a?(String) end opts end def valid_keys @valid_keys ||= VALID_KEYS end def normalize_options(name, version, opts) if name.is_a?(Symbol) raise GemfileError, %(You need to specify gem names as Strings. Use 'gem "#{name}"' instead) end if name =~ /\s/ raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace) end raise GemfileError, %(an empty gem name is not valid) if name.empty? normalize_hash(opts) git_names = @git_sources.keys.map(&:to_s) validate_keys("gem '#{name}'", opts, valid_keys + git_names) groups = @groups.dup opts["group"] = opts.delete("groups") || opts["group"] groups.concat Array(opts.delete("group")) groups = [:default] if groups.empty? install_if = @install_conditionals.dup install_if.concat Array(opts.delete("install_if")) install_if = install_if.reduce(true) do |memo, val| memo && (val.respond_to?(:call) ? val.call : val) end platforms = @platforms.dup opts["platforms"] = opts["platform"] || opts["platforms"] platforms.concat Array(opts.delete("platforms")) platforms.map!(&:to_sym) platforms.each do |p| next if VALID_PLATFORMS.include?(p) raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}" end # Save sources passed in a key if opts.key?("source") source = normalize_source(opts["source"]) opts["source"] = @sources.add_rubygems_source("remotes" => source) end git_name = (git_names & opts.keys).last if @git_sources[git_name] opts["git"] = @git_sources[git_name].call(opts[git_name]) end %w[git path].each do |type| next unless param = opts[type] if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/ options = opts.merge("name" => name, "version" => $1) else options = opts.dup end source = send(type, param, options) {} opts["source"] = source end opts["source"] ||= @source opts["env"] ||= @env opts["platforms"] = platforms.dup opts["group"] = groups opts["should_include"] = install_if end def normalize_group_options(opts, groups) normalize_hash(opts) groups = groups.map {|group| ":#{group}" }.join(", ") validate_keys("group #{groups}", opts, %w[optional]) opts["optional"] ||= false end def validate_keys(command, opts, valid_keys) invalid_keys = opts.keys - valid_keys git_source = opts.keys & @git_sources.keys.map(&:to_s) if opts["branch"] && !(opts["git"] || opts["github"] || git_source.any?) raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch) end return true unless invalid_keys.any? message = String.new message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} " message << if invalid_keys.size > 1 "as options for #{command}, but they are invalid." else "as an option for #{command}, but it is invalid." end message << " Valid options are: #{valid_keys.join(", ")}." message << " You may be able to resolve this by upgrading Bundler to the newest version." raise InvalidOption, message end def normalize_source(source) case source when :gemcutter, :rubygems, :rubyforge Bundler::SharedHelpers.major_deprecation 2, "The source :#{source} is deprecated because HTTP " \ "requests are insecure.\nPlease change your source to 'https://" \ "rubygems.org' if possible, or 'http://rubygems.org' if not." "http://rubygems.org" when String source else raise GemfileError, "Unknown source '#{source}'" end end def check_path_source_safety return if @sources.global_path_source.nil? msg = "You can no longer specify a path source by itself. Instead, \n" \ "either use the :path option on a gem, or specify the gems that \n" \ "bundler should find in the path source by passing a block to \n" \ "the path method, like: \n\n" \ " path 'dir/containing/rails' do\n" \ " gem 'rails'\n" \ " end\n\n" SharedHelpers.major_deprecation(2, msg.strip) end def check_rubygems_source_safety return unless @sources.aggregate_global_source? if Bundler.feature_flag.bundler_3_mode? msg = "This Gemfile contains multiple primary sources. " \ "Each source after the first must include a block to indicate which gems " \ "should come from that source" raise GemfileEvalError, msg else Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple primary sources. " \ "Using `source` more than once without a block is a security risk, and " \ "may result in installing unexpected gems. To resolve this warning, use " \ "a block to indicate which gems should come from the secondary source." end end def warn_deprecated_git_source(name, replacement, additional_message = nil) additional_message &&= " #{additional_message}" replacement = if replacement.count("\n").zero? "{|repo_name| #{replacement} }" else "do |repo_name|\n#{replacement.to_s.gsub(/^/, " ")}\n end" end Bundler::SharedHelpers.major_deprecation 3, <<-EOS The :#{name} git source is deprecated, and will be removed in the future.#{additional_message} Add this code to the top of your Gemfile to ensure it continues to work: git_source(:#{name}) #{replacement} EOS end class DSLError < GemfileError # @return [String] the description that should be presented to the user. # attr_reader :description # @return [String] the path of the dsl file that raised the exception. # attr_reader :dsl_path # @return [Exception] the backtrace of the exception raised by the # evaluation of the dsl file. # attr_reader :backtrace # @param [Exception] backtrace @see backtrace # @param [String] dsl_path @see dsl_path # def initialize(description, dsl_path, backtrace, contents = nil) @status_code = $!.respond_to?(:status_code) && $!.status_code @description = description @dsl_path = dsl_path @backtrace = backtrace @contents = contents end def status_code @status_code || super end # @return [String] the contents of the DSL that cause the exception to # be raised. # def contents @contents ||= begin dsl_path && File.exist?(dsl_path) && File.read(dsl_path) end end # The message of the exception reports the content of podspec for the # line that generated the original exception. # # @example Output # # Invalid podspec at `RestKit.podspec` - undefined method # `exclude_header_search_paths=' for # # # from spec-repos/master/RestKit/0.9.3/RestKit.podspec:36 # ------------------------------------------- # # because it would break: #import # > ns.exclude_header_search_paths = 'Code/RestKit.h' # end # ------------------------------------------- # # @return [String] the message of the exception. # def to_s @to_s ||= begin trace_line, description = parse_line_number_from_description m = String.new("\n[!] ") m << description m << ". Bundler cannot continue.\n" return m unless backtrace && dsl_path && contents trace_line = backtrace.find {|l| l.include?(dsl_path.to_s) } || trace_line return m unless trace_line line_numer = trace_line.split(":")[1].to_i - 1 return m unless line_numer lines = contents.lines.to_a indent = " # " indicator = indent.tr("#", ">") first_line = line_numer.zero? last_line = (line_numer == (lines.count - 1)) m << "\n" m << "#{indent}from #{trace_line.gsub(/:in.*$/, "")}\n" m << "#{indent}-------------------------------------------\n" m << "#{indent}#{lines[line_numer - 1]}" unless first_line m << "#{indicator}#{lines[line_numer]}" m << "#{indent}#{lines[line_numer + 1]}" unless last_line m << "\n" unless m.end_with?("\n") m << "#{indent}-------------------------------------------\n" end end private def parse_line_number_from_description description = self.description if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path.to_s}):\d+)/ trace_line = Regexp.last_match[1] description = description.sub(/\n.*\n(\.\.\.)? *\^~+$/, "").sub(/#{Regexp.quote trace_line}:\s*/, "").sub("\n", " - ") end [trace_line, description] end end def gemfile_root @gemfile ||= Bundler.default_gemfile @gemfile.dirname end end end PK ]eAss-gems/bundler-2.2.24/lib/bundler/capistrano.rbnu[# frozen_string_literal: true require_relative "shared_helpers" Bundler::SharedHelpers.major_deprecation 2, "The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler" # Capistrano task for Bundler. # # Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and # Bundler will be activated after each new deployment. require_relative "deployment" require "capistrano/version" if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release >= Gem::Version.new("3.0") raise "For Capistrano 3.x integration, please use https://github.com/capistrano/bundler" end Capistrano::Configuration.instance(:must_exist).load do before "deploy:finalize_update", "bundle:install" Bundler::Deployment.define_task(self, :task, :except => { :no_release => true }) set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" } end PK ]V1gems/bundler-2.2.24/lib/bundler/match_platform.rbnu[# frozen_string_literal: true require_relative "gem_helpers" module Bundler module MatchPlatform include GemHelpers def match_platform(p) MatchPlatform.platforms_match?(platform, p) end def self.platforms_match?(gemspec_platform, local_platform) return true if gemspec_platform.nil? return true if Gem::Platform::RUBY == gemspec_platform return true if local_platform == gemspec_platform gemspec_platform = Gem::Platform.new(gemspec_platform) return true if GemHelpers.generic(gemspec_platform) === local_platform return true if gemspec_platform === local_platform false end end end PK ] .XX-gems/bundler-2.2.24/lib/bundler/definition.rbnu[# frozen_string_literal: true require_relative "lockfile_parser" module Bundler class Definition include GemHelpers attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles ) # Given a gemfile and lockfile creates a Bundler definition # # @param gemfile [Pathname] Path to Gemfile # @param lockfile [Pathname,nil] Path to Gemfile.lock # @param unlock [Hash, Boolean, nil] Gems that have been requested # to be updated or true if all gems should be updated # @return [Bundler::Definition] def self.build(gemfile, lockfile, unlock) unlock ||= {} gemfile = Pathname.new(gemfile).expand_path raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file? Dsl.evaluate(gemfile, lockfile, unlock) end # # How does the new system work? # # * Load information from Gemfile and Lockfile # * Invalidate stale locked specs # * All specs from stale source are stale # * All specs that are reachable only through a stale # dependency are stale. # * If all fresh dependencies are satisfied by the locked # specs, then we can try to resolve locally. # # @param lockfile [Pathname] Path to Gemfile.lock # @param dependencies [Array(Bundler::Dependency)] array of dependencies from Gemfile # @param sources [Bundler::SourceList] # @param unlock [Hash, Boolean, nil] Gems that have been requested # to be updated or true if all gems should be updated # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version # @param optional_groups [Array(String)] A list of optional groups def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) if [true, false].include?(unlock) @unlocking_bundler = false @unlocking = unlock else @unlocking_bundler = unlock.delete(:bundler) @unlocking = unlock.any? {|_k, v| !Array(v).empty? } end @dependencies = dependencies @sources = sources @unlock = unlock @optional_groups = optional_groups @remote = false @specs = nil @ruby_version = ruby_version @gemfiles = gemfiles @lockfile = lockfile @lockfile_contents = String.new @locked_bundler_version = nil @locked_ruby_version = nil @locked_specs_incomplete_for_platform = false @new_platform = nil if lockfile && File.exist?(lockfile) @lockfile_contents = Bundler.read_file(lockfile) @locked_gems = LockfileParser.new(@lockfile_contents) @locked_platforms = @locked_gems.platforms @platforms = @locked_platforms.dup @locked_bundler_version = @locked_gems.bundler_version @locked_ruby_version = @locked_gems.ruby_version if unlock != true @locked_deps = @locked_gems.dependencies @locked_specs = SpecSet.new(@locked_gems.specs) @locked_sources = @locked_gems.sources else @unlock = {} @locked_deps = {} @locked_specs = SpecSet.new([]) @locked_sources = [] end else @unlock = {} @platforms = [] @locked_gems = nil @locked_deps = {} @locked_specs = SpecSet.new([]) @locked_sources = [] @locked_platforms = [] end locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle? if @multisource_allowed unless sources.aggregate_global_source? msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." Bundler::SharedHelpers.major_deprecation 2, msg end @sources.merged_gem_lockfile_sections!(locked_gem_sources.first) end @unlock[:sources] ||= [] @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object @ruby_version.diff(locked_ruby_version_object) end @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version) add_current_platform unless current_ruby_platform_locked? || Bundler.frozen_bundle? converge_path_sources_to_gemspec_sources @path_changes = converge_paths @source_changes = converge_sources if @unlock[:conservative] @unlock[:gems] ||= @dependencies.map(&:name) else eager_unlock = expand_dependencies(@unlock[:gems] || [], true) @unlock[:gems] = @locked_specs.for(eager_unlock, false, false, false).map(&:name) end @dependency_changes = converge_dependencies @local_changes = converge_locals @requires = compute_requires end def gem_version_promoter @gem_version_promoter ||= begin locked_specs = if unlocking? && @locked_specs.empty? && !@lockfile_contents.empty? # Definition uses an empty set of locked_specs to indicate all gems # are unlocked, but GemVersionPromoter needs the locked_specs # for conservative comparison. Bundler::SpecSet.new(@locked_gems.specs) else @locked_specs end GemVersionPromoter.new(locked_specs, @unlock[:gems]) end end def multisource_allowed? @multisource_allowed end def resolve_only_locally! @remote = false sources.local_only! resolve end def resolve_with_cache! sources.cached! resolve end def resolve_remotely! @remote = true sources.remote! resolve end # For given dependency list returns a SpecSet with Gemspec of all the required # dependencies. # 1. The method first resolves the dependencies specified in Gemfile # 2. After that it tries and fetches gemspec of resolved dependencies # # @return [Bundler::SpecSet] def specs @specs ||= add_bundler_to(resolve.materialize(requested_dependencies)) rescue GemNotFound => e # Handle yanked gem gem_name, gem_version = extract_gem_info(e) locked_gem = @locked_specs[gem_name].last raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \ "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \ "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \ "removed in order to install." end def new_specs specs - @locked_specs end def removed_specs @locked_specs - specs end def missing_specs missing = [] resolve.materialize(requested_dependencies, missing) missing end def missing_specs? missing = missing_specs return false if missing.empty? Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}" true rescue BundlerError => e @resolve = nil @specs = nil @gem_version_promoter = nil Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})" true end def requested_specs specs_for(requested_groups) end def requested_dependencies dependencies_for(requested_groups) end def current_dependencies dependencies.select do |d| d.should_include? && !d.gem_platforms(@platforms).empty? end end def specs_for(groups) groups = requested_groups if groups.empty? deps = dependencies_for(groups) add_bundler_to(resolve.materialize(expand_dependencies(deps))) end def dependencies_for(groups) groups.map!(&:to_sym) current_dependencies.reject do |d| (d.groups & groups).empty? end end # Resolve all the dependencies specified in Gemfile. It ensures that # dependencies that have been already resolved via locked file and are fresh # are reused when resolving dependencies # # @return [SpecSet] resolved dependencies def resolve @resolve ||= begin last_resolve = converge_locked_specs if Bundler.frozen_bundle? Bundler.ui.debug "Frozen, using resolution from the lockfile" last_resolve elsif !unlocking? && nothing_changed? Bundler.ui.debug("Found no changes, using resolution from the lockfile") last_resolve else # Run a resolve against the locally available gems Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote) Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) end end end def has_rubygems_remotes? sources.rubygems_sources.any? {|s| s.remotes.any? } end def spec_git_paths sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact end def groups dependencies.map(&:groups).flatten.uniq end def lock(file, preserve_unknown_sections = false) contents = to_lock # Convert to \r\n if the existing lock has them # i.e., Windows with `git config core.autocrlf=true` contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match("\r\n") if @locked_bundler_version locked_major = @locked_bundler_version.segments.first current_major = Gem::Version.create(Bundler::VERSION).segments.first if updating_major = locked_major < current_major Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \ "after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}." end end preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler)) return if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) if Bundler.frozen_bundle? Bundler.ui.error "Cannot write a changed lockfile while frozen." return end SharedHelpers.filesystem_access(file) do |p| File.open(p, "wb") {|f| f.puts(contents) } end end def locked_bundler_version if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION) new_version = Bundler::VERSION end new_version || @locked_bundler_version || Bundler::VERSION end def locked_ruby_version return unless ruby_version if @unlock[:ruby] || !@locked_ruby_version Bundler::RubyVersion.system else @locked_ruby_version end end def locked_ruby_version_object return unless @locked_ruby_version @locked_ruby_version_object ||= begin unless version = RubyVersion.from_string(@locked_ruby_version) raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \ "#{@lockfile} could not be parsed. " \ "Try running bundle update --ruby to resolve this." end version end end def to_lock require_relative "lockfile_generator" LockfileGenerator.generate(self) end def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) msg = String.new msg << "You are trying to install in deployment mode after changing\n" \ "your Gemfile. Run `bundle install` elsewhere and add the\n" \ "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control." unless explicit_flag suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any? "bundle config unset frozen" elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? "bundle config unset deployment" end msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \ "freeze \nby running `#{suggested_command}`." end added = [] deleted = [] changed = [] new_platforms = @platforms - @locked_platforms deleted_platforms = @locked_platforms - @platforms added.concat new_platforms.map {|p| "* platform: #{p}" } deleted.concat deleted_platforms.map {|p| "* platform: #{p}" } gemfile_sources = sources.lock_sources new_sources = gemfile_sources - @locked_sources deleted_sources = @locked_sources - gemfile_sources new_deps = @dependencies - @locked_deps.values deleted_deps = @locked_deps.values - @dependencies # Check if it is possible that the source is only changed thing if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?) new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) } deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) } end if @locked_sources != gemfile_sources if new_sources.any? added.concat new_sources.map {|source| "* source: #{source}" } end if deleted_sources.any? deleted.concat deleted_sources.map {|source| "* source: #{source}" } end end added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any? if deleted_deps.any? deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } end both_sources = Hash.new {|h, k| h[k] = [] } @dependencies.each {|d| both_sources[d.name][0] = d } @locked_deps.each {|name, d| both_sources[name][1] = d.source } both_sources.each do |name, (dep, lock_source)| next if lock_source.nil? || (dep && lock_source.can_lock?(dep)) gemfile_source_name = (dep && dep.source) || "no specified source" lockfile_source_name = lock_source changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`" end reason = change_reason msg << "\n\n#{reason.split(", ").map(&:capitalize).join("\n")}" unless reason.strip.empty? msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? msg << "\n" raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed? end def validate_runtime! validate_ruby! validate_platforms! end def validate_ruby! return unless ruby_version if diff = ruby_version.diff(Bundler::RubyVersion.system) problem, expected, actual = diff msg = case problem when :engine "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}" when :version "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" when :engine_version "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" when :patchlevel if !expected.is_a?(String) "The Ruby patchlevel in your Gemfile must be a string" else "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}" end end raise RubyVersionMismatch, msg end end def validate_platforms! return if current_platform_locked? raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \ "but your local platform is #{Bundler.local_platform}. " \ "Add the current platform to the lockfile with `bundle lock --add-platform #{Bundler.local_platform}` and try again." end def add_platform(platform) @new_platform ||= !@platforms.include?(platform) @platforms |= [platform] end def remove_platform(platform) return if @platforms.delete(Gem::Platform.new(platform)) raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" end def most_specific_locked_platform @platforms.min_by do |bundle_platform| platform_specificity_match(bundle_platform, local_platform) end end attr_reader :sources private :sources def nothing_changed? !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform end def unlocking? @unlocking end private def add_bundler_to(specs) unless specs["bundler"].any? bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last specs["bundler"] = bundler end specs end def precompute_source_requirements_for_indirect_dependencies? sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? end def current_ruby_platform_locked? return false unless generic_local_platform == Gem::Platform::RUBY current_platform_locked? end def current_platform_locked? @platforms.any? do |bundle_platform| MatchPlatform.platforms_match?(bundle_platform, Bundler.local_platform) end end def add_current_platform add_platform(local_platform) end def change_reason if unlocking? unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v| if v == true k.to_s else v = Array(v) "#{k}: (#{v.join(", ")})" end end.join(", ") return "bundler is unlocking #{unlock_reason}" end [ [@source_changes, "the list of sources changed"], [@dependency_changes, "the dependencies in your gemfile changed"], [@new_platform, "you added a new platform to your gemfile"], [@path_changes, "the gemspecs for path gems changed"], [@local_changes, "the gemspecs for git local gems changed"], [@locked_specs_incomplete_for_platform, "the lockfile does not have all gems needed for the current platform"], ].select(&:first).map(&:last).join(", ") end def pretty_dep(dep, source = false) SharedHelpers.pretty_dependency(dep, source) end # Check if the specs of the given source changed # according to the locked source. def specs_changed?(source) locked = @locked_sources.find {|s| s == source } !locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source) end def dependencies_for_source_changed?(source, locked_source = source) deps_for_source = @dependencies.select {|s| s.source == source } locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source } deps_for_source.uniq.sort != locked_deps_for_source.sort end def specs_for_source_changed?(source) locked_index = Index.new locked_index.use(@locked_specs.select {|s| source.can_lock?(s) }) # order here matters, since Index#== is checking source.specs.include?(locked_index) locked_index != source.specs rescue PathError, GitError => e Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})" false end # Get all locals and override their matching sources. # Return true if any of the locals changed (for example, # they point to a new revision) or depend on new specs. def converge_locals locals = [] Bundler.settings.local_overrides.map do |k, v| spec = @dependencies.find {|s| s.name == k } source = spec && spec.source if source && source.respond_to?(:local_override!) source.unlock! if @unlock[:gems].include?(spec.name) locals << [source, source.local_override!(v)] end end sources_with_changes = locals.select do |source, changed| changed || specs_changed?(source) end.map(&:first) !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty? end def converge_paths sources.path_sources.any? do |source| specs_changed?(source) end end def converge_path_source_to_gemspec_source(source) return source unless source.instance_of?(Source::Path) gemspec_source = sources.path_sources.find {|s| s.is_a?(Source::Gemspec) && s.as_path_source == source } gemspec_source || source end def converge_path_sources_to_gemspec_sources @locked_sources.map! do |source| converge_path_source_to_gemspec_source(source) end @locked_specs.each do |spec| spec.source &&= converge_path_source_to_gemspec_source(spec.source) end @locked_deps.each do |_, dep| dep.source &&= converge_path_source_to_gemspec_source(dep.source) end end def converge_sources # Replace the sources from the Gemfile with the sources from the Gemfile.lock, # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent # source in the Gemfile.lock, use the one from the Gemfile. changes = sources.replace_sources!(@locked_sources) sources.all_sources.each do |source| # If the source is unlockable and the current command allows an unlock of # the source (for example, you are doing a `bundle update ` of a git-pinned # gem), unlock it. For git sources, this means to unlock the revision, which # will cause the `ref` used to be the most recent for the branch (or master) if # an explicit `ref` is not used. if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name) source.unlock! changes = true end end changes end def converge_dependencies frozen = Bundler.frozen_bundle? (@dependencies + @locked_deps.values).each do |dep| locked_source = @locked_deps[dep.name] # This is to make sure that if bundler is installing in deployment mode and # after locked_source and sources don't match, we still use locked_source. if frozen && !locked_source.nil? && locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist? dep.source = locked_source.source elsif dep.source dep.source = sources.get(dep.source) end end changes = false # We want to know if all match, but don't want to check all entries # This means we need to return false if any dependency doesn't match # the lock or doesn't exist in the lock. @dependencies.each do |dependency| unless locked_dep = @locked_deps[dependency.name] changes = true next end # Gem::Dependency#== matches Gem::Dependency#type. As the lockfile # doesn't carry a notion of the dependency type, if you use # add_development_dependency in a gemspec that's loaded with the gemspec # directive, the lockfile dependencies and resolved dependencies end up # with a mismatch on #type. Work around that by setting the type on the # dep from the lockfile. locked_dep.instance_variable_set(:@type, dependency.type) # We already know the name matches from the hash lookup # so we only need to check the requirement now changes ||= dependency.requirement != locked_dep.requirement end changes end # Remove elements from the locked specs that are expired. This will most # commonly happen if the Gemfile has changed since the lockfile was last # generated def converge_locked_specs deps = [] # Build a list of dependencies that are the same in the Gemfile # and Gemfile.lock. If the Gemfile modified a dependency, but # the gem in the Gemfile.lock still satisfies it, this is fine # too. @dependencies.each do |dep| locked_dep = @locked_deps[dep.name] # If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep locked_dep = nil unless locked_dep == dep if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep) deps << dep elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source) @locked_specs.each do |s| @unlock[:gems] << s.name if s.source == dep.source end dep.source.unlock! if dep.source.respond_to?(:unlock!) dep.source.specs.each {|s| @unlock[:gems] << s.name } end end converged = [] @locked_specs.each do |s| # Replace the locked dependency's source with the equivalent source from the Gemfile dep = @dependencies.find {|d| s.satisfies?(d) } s.source = (dep && dep.source) || sources.get(s.source) # Don't add a spec to the list if its source is expired. For example, # if you change a Git gem to RubyGems. next if s.source.nil? next if @unlock[:sources].include?(s.source.name) # If the spec is from a path source and it doesn't exist anymore # then we unlock it. # Path sources have special logic if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec) new_specs = begin s.source.specs rescue PathError, GitError # if we won't need the source (according to the lockfile), # don't error if the path/git source isn't available next if @locked_specs. for(requested_dependencies, false, true, false). none? {|locked_spec| locked_spec.source == s.source } raise end new_spec = new_specs[s].first # If the spec is no longer in the path source, unlock it. This # commonly happens if the version changed in the gemspec next unless new_spec s.dependencies.replace(new_spec.dependencies) end converged << s end resolve = SpecSet.new(converged) @locked_specs_incomplete_for_platform = !resolve.for(expand_dependencies(requested_dependencies & deps), true, true) resolve = SpecSet.new(resolve.for(expand_dependencies(deps, true), false, false, false).reject{|s| @unlock[:gems].include?(s.name) }) diff = nil # Now, we unlock any sources that do not have anymore gems pinned to it sources.all_sources.each do |source| next unless source.respond_to?(:unlock!) unless resolve.any? {|s| s.source == source } diff ||= @locked_specs.to_a - resolve.to_a source.unlock! if diff.any? {|s| s.source == source } end end resolve end def in_locked_deps?(dep, locked_dep) # Because the lockfile can't link a dep to a specific remote, we need to # treat sources as equivalent anytime the locked dep has all the remotes # that the Gemfile dep does. locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source) end def satisfies_locked_spec?(dep) @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) } end def metadata_dependencies @metadata_dependencies ||= begin ruby_versions = ruby_version_requirements(@ruby_version) [ Dependency.new("Ruby\0", ruby_versions), Dependency.new("RubyGems\0", Gem::VERSION), ] end end def ruby_version_requirements(ruby_version) return [] unless ruby_version if ruby_version.patchlevel [ruby_version.to_gem_version_with_patchlevel] else ruby_version.versions.map do |version| requirement = Gem::Requirement.new(version) if requirement.exact? "~> #{version}.0" else requirement end end end end def expand_dependencies(dependencies, remote = false) deps = [] dependencies.each do |dep| dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name) next unless remote || dep.current_platform? target_platforms = dep.gem_platforms(remote ? @platforms : [generic_local_platform]) deps += expand_dependency_with_platforms(dep, target_platforms) end deps end def expand_dependency_with_platforms(dep, platforms) platforms.map do |p| DepProxy.get_proxy(dep, p) end end def source_requirements # Record the specs available in each gem's source, so that those # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) source_requirements = if precompute_source_requirements_for_indirect_dependencies? { :default => sources.default_source }.merge(source_map.all_requirements) else { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements) end metadata_dependencies.each do |dep| source_requirements[dep.name] = sources.metadata_source end source_requirements[:default_bundler] = source_requirements["bundler"] || sources.default_source source_requirements["bundler"] = sources.metadata_source # needs to come last to override source_requirements end def requested_groups groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] end def lockfiles_equal?(current, proposed, preserve_unknown_sections) if preserve_unknown_sections sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version) sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current) sections_to_ignore += LockfileParser::ENVIRONMENT_VERSION_SECTIONS pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/ whitespace_cleanup = /\n{2,}/ current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip end current == proposed end def extract_gem_info(error) # This method will extract the error message like "Could not find foo-1.2.3 in any of the sources" # to an array. The first element will be the gem name (e.g. foo), the second will be the version number. error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten end def compute_requires dependencies.reduce({}) do |requires, dep| next requires unless dep.should_include? requires[dep.name] = Array(dep.autorequire || dep.name).map do |file| # Allow `require: true` as an alias for `require: ` file == true ? dep.name : file end requires end end def additional_base_requirements_for_resolve return [] unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources) dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) } @locked_gems.specs.reduce({}) do |requirements, locked_spec| name = locked_spec.name dependency = dependencies_by_name[name] next requirements if @locked_gems.dependencies[name] != dependency next requirements if dependency && dependency.source.is_a?(Source::Path) dep = Gem::Dependency.new(name, ">= #{locked_spec.version}") requirements[name] = DepProxy.get_proxy(dep, locked_spec.platform) requirements end.values end def equivalent_rubygems_remotes?(source) return false unless source.is_a?(Source::Rubygems) Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes) end def source_map @source_map ||= SourceMap.new(sources, dependencies) end end end PK ]W|%gems/bundler-2.2.24/lib/bundler/ui.rbnu[# frozen_string_literal: true module Bundler module UI autoload :RGProxy, File.expand_path("ui/rg_proxy", __dir__) autoload :Shell, File.expand_path("ui/shell", __dir__) autoload :Silent, File.expand_path("ui/silent", __dir__) end end PK ]HT9gems/bundler-2.2.24/lib/bundler/rubygems_gem_installer.rbnu[# frozen_string_literal: true require "rubygems/installer" module Bundler class RubyGemsGemInstaller < Gem::Installer def check_executable_overwrite(filename) # Bundler needs to install gems regardless of binstub overwriting end def install pre_install_checks run_pre_install_hooks spec.loaded_from = spec_file # Completely remove any previous gem files FileUtils.rm_rf gem_dir FileUtils.rm_rf spec.extension_dir FileUtils.mkdir_p gem_dir, :mode => 0o755 extract_files build_extensions write_build_info_file run_post_build_hooks generate_bin generate_plugins write_spec write_cache_file say spec.post_install_message unless spec.post_install_message.nil? run_post_install_hooks spec end def generate_plugins return unless Gem::Installer.instance_methods(false).include?(:generate_plugins) latest = Gem::Specification.stubs_for(spec.name).first return if latest && latest.version > spec.version ensure_writable_dir @plugins_dir if spec.plugins.empty? remove_plugins_for(spec, @plugins_dir) else regenerate_plugins_for(spec, @plugins_dir) end end def pre_install_checks super && validate_bundler_checksum(options[:bundler_expected_checksum]) end def build_extensions extension_cache_path = options[:bundler_extension_cache_path] return super unless extension_cache_path && extension_dir = spec.extension_dir extension_dir = Pathname.new(extension_dir) build_complete = SharedHelpers.filesystem_access(extension_cache_path.join("gem.build_complete"), :read, &:file?) if build_complete && !options[:force] SharedHelpers.filesystem_access(extension_dir.parent, &:mkpath) SharedHelpers.filesystem_access(extension_cache_path) do FileUtils.cp_r extension_cache_path, spec.extension_dir end else super if extension_dir.directory? # not made for gems without extensions SharedHelpers.filesystem_access(extension_cache_path.parent, &:mkpath) SharedHelpers.filesystem_access(extension_cache_path) do FileUtils.cp_r extension_dir, extension_cache_path end end end end private def validate_bundler_checksum(checksum) return true if Bundler.settings[:disable_checksum_validation] return true unless checksum return true unless source = @package.instance_variable_get(:@gem) return true unless source.respond_to?(:with_read_io) digest = source.with_read_io do |io| digest = SharedHelpers.digest(:SHA256).new digest << io.read(16_384) until io.eof? io.rewind send(checksum_type(checksum), digest) end unless digest == checksum raise SecurityError, <<-MESSAGE Bundler cannot continue installing #{spec.name} (#{spec.version}). The checksum for the downloaded `#{spec.full_name}.gem` does not match \ the checksum given by the server. This means the contents of the downloaded \ gem is different from what was uploaded to the server, and could be a potential security issue. To resolve this issue: 1. delete the downloaded gem located at: `#{spec.gem_dir}/#{spec.full_name}.gem` 2. run `bundle install` If you wish to continue installing the downloaded gem, and are certain it does not pose a \ security issue despite the mismatching checksum, do the following: 1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification 2. run `bundle install` (More info: The expected SHA256 checksum was #{checksum.inspect}, but the \ checksum for the downloaded gem was #{digest.inspect}.) MESSAGE end true end def checksum_type(checksum) case checksum.length when 64 then :hexdigest! when 44 then :base64digest! else raise InstallError, "The given checksum for #{spec.full_name} (#{checksum.inspect}) is not a valid SHA256 hexdigest nor base64digest" end end def hexdigest!(digest) digest.hexdigest! end def base64digest!(digest) if digest.respond_to?(:base64digest!) digest.base64digest! else [digest.digest!].pack("m0") end end end end PK ]_l__2gems/bundler-2.2.24/lib/bundler/vendored_tmpdir.rbnu[# frozen_string_literal: true module Bundler; end require_relative "vendor/tmpdir/lib/tmpdir" PK ]65gems/bundler-2.2.24/lib/bundler/lockfile_generator.rbnu[# frozen_string_literal: true module Bundler class LockfileGenerator attr_reader :definition attr_reader :out # @private def initialize(definition) @definition = definition @out = String.new end def self.generate(definition) new(definition).generate! end def generate! add_sources add_platforms add_dependencies add_locked_ruby_version add_bundled_with out end private def add_sources definition.send(:sources).lock_sources.each_with_index do |source, idx| out << "\n" unless idx.zero? # Add the source header out << source.to_lock # Find all specs for this source specs = definition.resolve.select {|s| source.can_lock?(s) } add_specs(specs) end end def add_specs(specs) # This needs to be sorted by full name so that # gems with the same name, but different platform # are ordered consistently specs.sort_by(&:full_name).each do |spec| next if spec.name == "bundler".freeze out << spec.to_lock end end def add_platforms add_section("PLATFORMS", definition.platforms) end def add_dependencies out << "\nDEPENDENCIES\n" handled = [] definition.dependencies.sort_by(&:to_s).each do |dep| next if handled.include?(dep.name) out << dep.to_lock handled << dep.name end end def add_locked_ruby_version return unless locked_ruby_version = definition.locked_ruby_version add_section("RUBY VERSION", locked_ruby_version.to_s) end def add_bundled_with add_section("BUNDLED WITH", definition.locked_bundler_version.to_s) end def add_section(name, value) out << "\n#{name}\n" case value when Array value.map(&:to_s).sort.each do |val| out << " #{val}\n" end when Hash value.to_a.sort_by {|k, _| k.to_s }.each do |key, val| out << " #{key}: #{val}\n" end when String out << " #{value}\n" else raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile" end end end end PK ]xsn}*}*)gems/bundler-2.2.24/lib/bundler/plugin.rbnu[# frozen_string_literal: true require_relative "plugin/api" module Bundler module Plugin autoload :DSL, File.expand_path("plugin/dsl", __dir__) autoload :Events, File.expand_path("plugin/events", __dir__) autoload :Index, File.expand_path("plugin/index", __dir__) autoload :Installer, File.expand_path("plugin/installer", __dir__) autoload :SourceList, File.expand_path("plugin/source_list", __dir__) class MalformattedPlugin < PluginError; end class UndefinedCommandError < PluginError; end class UnknownSourceError < PluginError; end PLUGIN_FILE_NAME = "plugins.rb".freeze module_function def reset! instance_variables.each {|i| remove_instance_variable(i) } @sources = {} @commands = {} @hooks_by_event = Hash.new {|h, k| h[k] = [] } @loaded_plugin_names = [] end reset! # Installs a new plugin by the given name # # @param [Array] names the name of plugin to be installed # @param [Hash] options various parameters as described in description. # Refer to cli/plugin for available options def install(names, options) specs = Installer.new.install(names, options) save_plugins names, specs rescue PluginError => e specs_to_delete = specs.select {|k, _v| names.include?(k) && !index.commands.values.include?(k) } specs_to_delete.each_value {|spec| Bundler.rm_rf(spec.full_gem_path) } names_list = names.map {|name| "`#{name}`" }.join(", ") Bundler.ui.error "Failed to install the following plugins: #{names_list}. The underlying error was: #{e.message}.\n #{e.backtrace.join("\n ")}" end # Uninstalls plugins by the given names # # @param [Array] names the names of plugins to be uninstalled def uninstall(names, options) if names.empty? && !options[:all] Bundler.ui.error "No plugins to uninstall. Specify at least 1 plugin to uninstall.\n"\ "Use --all option to uninstall all the installed plugins." return end names = index.installed_plugins if options[:all] if names.any? names.each do |name| if index.installed?(name) Bundler.rm_rf(index.plugin_path(name)) index.unregister_plugin(name) Bundler.ui.info "Uninstalled plugin #{name}" else Bundler.ui.error "Plugin #{name} is not installed \n" end end else Bundler.ui.info "No plugins installed" end end # List installed plugins and commands # def list installed_plugins = index.installed_plugins if installed_plugins.any? output = String.new installed_plugins.each do |plugin| output << "#{plugin}\n" output << "-----\n" index.plugin_commands(plugin).each do |command| output << " #{command}\n" end output << "\n" end else output = "No plugins installed" end Bundler.ui.info output end # Evaluates the Gemfile with a limited DSL and installs the plugins # specified by plugin method # # @param [Pathname] gemfile path # @param [Proc] block that can be evaluated for (inline) Gemfile def gemfile_install(gemfile = nil, &inline) Bundler.settings.temporary(:frozen => false, :deployment => false) do builder = DSL.new if block_given? builder.instance_eval(&inline) else builder.eval_gemfile(gemfile) end builder.check_primary_source_safety definition = builder.to_definition(nil, true) return if definition.dependencies.empty? plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p } installed_specs = Installer.new.install_definition(definition) save_plugins plugins, installed_specs, builder.inferred_plugins end rescue RuntimeError => e unless e.is_a?(GemfileError) Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}" end raise end # The index object used to store the details about the plugin def index @index ||= Index.new end # The directory root for all plugin related data # # If run in an app, points to local root, in app_config_path # Otherwise, points to global root, in Bundler.user_bundle_path("plugin") def root @root ||= if SharedHelpers.in_bundle? local_root else global_root end end def local_root Bundler.app_config_path.join("plugin") end # The global directory root for all plugin related data def global_root Bundler.user_bundle_path("plugin") end # The cache directory for plugin stuffs def cache @cache ||= root.join("cache") end # To be called via the API to register to handle a command def add_command(command, cls) @commands[command] = cls end # Checks if any plugin handles the command def command?(command) !index.command_plugin(command).nil? end # To be called from Cli class to pass the command and argument to # appropriate plugin class def exec_command(command, args) raise UndefinedCommandError, "Command `#{command}` not found" unless command? command load_plugin index.command_plugin(command) unless @commands.key? command @commands[command].new.exec(command, args) end # To be called via the API to register to handle a source plugin def add_source(source, cls) @sources[source] = cls end # Checks if any plugin declares the source def source?(name) !index.source_plugin(name.to_s).nil? end # @return [Class] that handles the source. The class includes API::Source def source(name) raise UnknownSourceError, "Source #{name} not found" unless source? name load_plugin(index.source_plugin(name)) unless @sources.key? name @sources[name] end # @param [Hash] The options that are present in the lock file # @return [API::Source] the instance of the class that handles the source # type passed in locked_opts def source_from_lock(locked_opts) src = source(locked_opts["type"]) src.new(locked_opts.merge("uri" => locked_opts["remote"])) end # To be called via the API to register a hooks and corresponding block that # will be called to handle the hook def add_hook(event, &block) unless Events.defined_event?(event) raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" end @hooks_by_event[event.to_s] << block end # Runs all the hooks that are registered for the passed event # # It passes the passed arguments and block to the block registered with # the api. # # @param [String] event def hook(event, *args, &arg_blk) return unless Bundler.feature_flag.plugins? unless Events.defined_event?(event) raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" end plugins = index.hook_plugins(event) return unless plugins.any? (plugins - @loaded_plugin_names).each {|name| load_plugin(name) } @hooks_by_event[event].each {|blk| blk.call(*args, &arg_blk) } end # currently only intended for specs # # @return [String, nil] installed path def installed?(plugin) Index.new.installed?(plugin) end # Post installation processing and registering with index # # @param [Array] plugins list to be installed # @param [Hash] specs of plugins mapped to installation path (currently they # contain all the installed specs, including plugins) # @param [Array] names of inferred source plugins that can be ignored def save_plugins(plugins, specs, optional_plugins = []) plugins.each do |name| spec = specs[name] validate_plugin! Pathname.new(spec.full_gem_path) installed = register_plugin(name, spec, optional_plugins.include?(name)) Bundler.ui.info "Installed plugin #{name}" if installed end end # Checks if the gem is good to be a plugin # # At present it only checks whether it contains plugins.rb file # # @param [Pathname] plugin_path the path plugin is installed at # @raise [MalformattedPlugin] if plugins.rb file is not found def validate_plugin!(plugin_path) plugin_file = plugin_path.join(PLUGIN_FILE_NAME) raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin." unless plugin_file.file? end # Runs the plugins.rb file in an isolated namespace, records the plugin # actions it registers for and then passes the data to index to be stored. # # @param [String] name the name of the plugin # @param [Specification] spec of installed plugin # @param [Boolean] optional_plugin, removed if there is conflict with any # other plugin (used for default source plugins) # # @raise [MalformattedPlugin] if plugins.rb raises any error def register_plugin(name, spec, optional_plugin = false) commands = @commands sources = @sources hooks = @hooks_by_event @commands = {} @sources = {} @hooks_by_event = Hash.new {|h, k| h[k] = [] } load_paths = spec.load_paths Bundler.rubygems.add_to_load_path(load_paths) path = Pathname.new spec.full_gem_path begin load path.join(PLUGIN_FILE_NAME), true rescue StandardError => e raise MalformattedPlugin, "#{e.class}: #{e.message}" end if optional_plugin && @sources.keys.any? {|s| source? s } Bundler.rm_rf(path) false else index.register_plugin(name, path.to_s, load_paths, @commands.keys, @sources.keys, @hooks_by_event.keys) true end ensure @commands = commands @sources = sources @hooks_by_event = hooks end # Executes the plugins.rb file # # @param [String] name of the plugin def load_plugin(name) return unless name && !name.empty? # Need to ensure before this that plugin root where the rest of gems # are installed to be on load path to support plugin deps. Currently not # done to avoid conflicts path = index.plugin_path(name) Bundler.rubygems.add_to_load_path(index.load_paths(name)) load path.join(PLUGIN_FILE_NAME) @loaded_plugin_names << name rescue RuntimeError => e Bundler.ui.error "Failed loading plugin #{name}: #{e.message}" raise end class << self private :load_plugin, :register_plugin, :save_plugins, :validate_plugin! end end end PK ]h&(7gems/bundler-2.2.24/lib/bundler/remote_specification.rbnu[# frozen_string_literal: true module Bundler # Represents a lazily loaded gem specification, where the full specification # is on the source server in rubygems' "quick" index. The proxy object is to # be seeded with what we're given from the source's abbreviated index - the # full specification will only be fetched when necessary. class RemoteSpecification include MatchPlatform include Comparable attr_reader :name, :version, :platform attr_writer :dependencies attr_accessor :source, :remote def initialize(name, version, platform, spec_fetcher) @name = name @version = Gem::Version.create version @platform = platform @spec_fetcher = spec_fetcher @dependencies = nil end # Needed before installs, since the arch matters then and quick # specs don't bother to include the arch in the platform string def fetch_platform @platform = _remote_specification.platform end def full_name if platform == Gem::Platform::RUBY || platform.nil? "#{@name}-#{@version}" else "#{@name}-#{@version}-#{platform}" end end # Compare this specification against another object. Using sort_obj # is compatible with Gem::Specification and other Bundler or RubyGems # objects. Otherwise, use the default Object comparison. def <=>(other) if other.respond_to?(:sort_obj) sort_obj <=> other.sort_obj else super end end # Because Rubyforge cannot be trusted to provide valid specifications # once the remote gem is downloaded, the backend specification will # be swapped out. def __swap__(spec) raise APIResponseInvalidDependenciesError unless spec.dependencies.all? {|d| d.is_a?(Gem::Dependency) } SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies) @_remote_specification = spec end # Create a delegate used for sorting. This strategy is copied from # RubyGems 2.23 and ensures that Bundler's specifications can be # compared and sorted with RubyGems' own specifications. # # @see #<=> # @see Gem::Specification#sort_obj # # @return [Array] an object you can use to compare and sort this # specification against other specifications def sort_obj [@name, @version, @platform == Gem::Platform::RUBY ? -1 : 1] end def to_s "#<#{self.class} name=#{name} version=#{version} platform=#{platform}>" end def dependencies @dependencies ||= begin deps = method_missing(:dependencies) # allow us to handle when the specs dependencies are an array of array of string # in order to delay the crash to `#__swap__` where it results in a friendlier error # see https://github.com/rubygems/bundler/issues/5797 deps = deps.map {|d| d.is_a?(Gem::Dependency) ? d : Gem::Dependency.new(*d) } deps end end def git_version return unless loaded_from && source.is_a?(Bundler::Source::Git) " #{source.revision[0..6]}" end private def to_ary nil end def _remote_specification @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @platform]) @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \ " missing from the server! Try installing with `--full-index` as a workaround.") end def method_missing(method, *args, &blk) _remote_specification.send(method, *args, &blk) end def respond_to?(method, include_all = false) super || _remote_specification.respond_to?(method, include_all) end public :respond_to? end end PK ] F2gems/bundler-2.2.24/lib/bundler/lockfile_parser.rbnu[# frozen_string_literal: true module Bundler class LockfileParser attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version BUNDLED = "BUNDLED WITH".freeze DEPENDENCIES = "DEPENDENCIES".freeze PLATFORMS = "PLATFORMS".freeze RUBY = "RUBY VERSION".freeze GIT = "GIT".freeze GEM = "GEM".freeze PATH = "PATH".freeze PLUGIN = "PLUGIN SOURCE".freeze SPECS = " specs:".freeze OPTIONS = /^ ([a-z]+): (.*)$/i.freeze SOURCE = [GIT, GEM, PATH, PLUGIN].freeze SECTIONS_BY_VERSION_INTRODUCED = { Gem::Version.create("1.0") => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze, Gem::Version.create("1.10") => [BUNDLED].freeze, Gem::Version.create("1.12") => [RUBY].freeze, Gem::Version.create("1.13") => [PLUGIN].freeze, }.freeze KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten.freeze ENVIRONMENT_VERSION_SECTIONS = [BUNDLED, RUBY].freeze def self.sections_in_lockfile(lockfile_contents) lockfile_contents.scan(/^\w[\w ]*$/).uniq end def self.unknown_sections_in_lockfile(lockfile_contents) sections_in_lockfile(lockfile_contents) - KNOWN_SECTIONS end def self.sections_to_ignore(base_version = nil) base_version &&= base_version.release base_version ||= Gem::Version.create("1.0".dup) attributes = [] SECTIONS_BY_VERSION_INTRODUCED.each do |version, introduced| next if version <= base_version attributes += introduced end attributes end def initialize(lockfile) @platforms = [] @sources = [] @dependencies = {} @state = nil @specs = {} if lockfile.match(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \ "Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock." end lockfile.split(/(?:\r?\n)+/).each do |line| if SOURCE.include?(line) @state = :source parse_source(line) elsif line == DEPENDENCIES @state = :dependency elsif line == PLATFORMS @state = :platform elsif line == RUBY @state = :ruby elsif line == BUNDLED @state = :bundled_with elsif line =~ /^[^\s]/ @state = nil elsif @state send("parse_#{@state}", line) end end @specs = @specs.values.sort_by(&:identifier) warn_for_outdated_bundler_version rescue ArgumentError => e Bundler.ui.debug(e) raise LockfileError, "Your lockfile is unreadable. Run `rm #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` " \ "and then `bundle install` to generate a new lockfile." end def warn_for_outdated_bundler_version return unless bundler_version prerelease_text = bundler_version.prerelease? ? " --pre" : "" current_version = Gem::Version.create(Bundler::VERSION) return unless current_version < bundler_version Bundler.ui.warn "Warning: the running version of Bundler (#{current_version}) is older " \ "than the version that created the lockfile (#{bundler_version}). We suggest you to " \ "upgrade to the version that created the lockfile by running `gem install " \ "bundler:#{bundler_version}#{prerelease_text}`.\n" end private TYPES = { GIT => Bundler::Source::Git, GEM => Bundler::Source::Rubygems, PATH => Bundler::Source::Path, PLUGIN => Bundler::Plugin, }.freeze def parse_source(line) case line when SPECS case @type when PATH @current_source = TYPES[@type].from_lock(@opts) @sources << @current_source when GIT @current_source = TYPES[@type].from_lock(@opts) @sources << @current_source when GEM @opts["remotes"] = Array(@opts.delete("remote")).reverse @current_source = TYPES[@type].from_lock(@opts) @sources << @current_source when PLUGIN @current_source = Plugin.source_from_lock(@opts) @sources << @current_source end when OPTIONS value = $2 value = true if value == "true" value = false if value == "false" key = $1 if @opts[key] @opts[key] = Array(@opts[key]) @opts[key] << value else @opts[key] = value end when *SOURCE @current_source = nil @opts = {} @type = line else parse_spec(line) end end space = / / NAME_VERSION = / ^(#{space}{2}|#{space}{4}|#{space}{6})(?!#{space}) # Exactly 2, 4, or 6 spaces at the start of the line (.*?) # Name (?:#{space}\(([^-]*) # Space, followed by version (?:-(.*))?\))? # Optional platform (!)? # Optional pinned marker $ # Line end /xo.freeze def parse_dependency(line) return unless line =~ NAME_VERSION spaces = $1 return unless spaces.size == 2 name = $2 version = $3 pinned = $5 version = version.split(",").map(&:strip) if version dep = Bundler::Dependency.new(name, version) if pinned && dep.name != "bundler" spec = @specs.find {|_, v| v.name == dep.name } dep.source = spec.last.source if spec # Path sources need to know what the default name / version # to use in the case that there are no gemspecs present. A fake # gemspec is created based on the version set on the dependency # TODO: Use the version from the spec instead of from the dependency if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path) dep.source.name = name dep.source.version = $1 end end @dependencies[dep.name] = dep end def parse_spec(line) return unless line =~ NAME_VERSION spaces = $1 name = $2 version = $3 platform = $4 if spaces.size == 4 version = Gem::Version.new(version) platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY @current_spec = LazySpecification.new(name, version, platform) @current_spec.source = @current_source @specs[@current_spec.identifier] = @current_spec elsif spaces.size == 6 version = version.split(",").map(&:strip) if version dep = Gem::Dependency.new(name, version) @current_spec.dependencies << dep end end def parse_platform(line) @platforms << Gem::Platform.new($1) if line =~ /^ (.*)$/ end def parse_bundled_with(line) line = line.strip return unless Gem::Version.correct?(line) @bundler_version = Gem::Version.create(line) end def parse_ruby(line) @ruby_version = line.strip end end end PK ]x9gems/bundler-2.2.24/lib/bundler/uri_credentials_filter.rbnu[# frozen_string_literal: true module Bundler module URICredentialsFilter module_function def credential_filtered_uri(uri_to_anonymize) return uri_to_anonymize if uri_to_anonymize.nil? uri = uri_to_anonymize.dup if uri.is_a?(String) return uri if File.exist?(uri) require_relative "vendored_uri" uri = Bundler::URI(uri) end if uri.userinfo # oauth authentication if uri.password == "x-oauth-basic" || uri.password == "x" # URI as string does not display with password if no user is set oauth_designation = uri.password uri.user = oauth_designation end uri.password = nil end return uri.to_s if uri_to_anonymize.is_a?(String) uri rescue Bundler::URI::InvalidURIError # uri is not canonical uri scheme uri end def credential_filtered_string(str_to_filter, uri) return str_to_filter if uri.nil? || str_to_filter.nil? str_with_no_credentials = str_to_filter.dup anonymous_uri_str = credential_filtered_uri(uri).to_s uri_str = uri.to_s if anonymous_uri_str != uri_str str_with_no_credentials = str_with_no_credentials.gsub(uri_str, anonymous_uri_str) end str_with_no_credentials end end end PK ]--1gems/bundler-2.2.24/lib/bundler/shared_helpers.rbnu[# frozen_string_literal: true require "pathname" require "rbconfig" require_relative "version" require_relative "constants" require_relative "rubygems_integration" require_relative "current_ruby" module Bundler module SharedHelpers def root gemfile = find_gemfile raise GemfileNotFound, "Could not locate Gemfile" unless gemfile Pathname.new(gemfile).tap{|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path.parent end def default_gemfile gemfile = find_gemfile raise GemfileNotFound, "Could not locate Gemfile" unless gemfile Pathname.new(gemfile).tap{|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path end def default_lockfile gemfile = default_gemfile case gemfile.basename.to_s when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked")) else Pathname.new("#{gemfile}.lock") end.tap{|x| x.untaint if RUBY_VERSION < "2.7" } end def default_bundle_dir bundle_dir = find_directory(".bundle") return nil unless bundle_dir bundle_dir = Pathname.new(bundle_dir) global_bundle_dir = Bundler.user_home.join(".bundle") return nil if bundle_dir == global_bundle_dir bundle_dir end def in_bundle? find_gemfile end def chdir(dir, &blk) Bundler.rubygems.ext_lock.synchronize do Dir.chdir dir, &blk end end def pwd Bundler.rubygems.ext_lock.synchronize do Pathname.pwd end end def with_clean_git_env(&block) keys = %w[GIT_DIR GIT_WORK_TREE] old_env = keys.inject({}) do |h, k| h.update(k => ENV[k]) end keys.each {|key| ENV.delete(key) } block.call ensure keys.each {|key| ENV[key] = old_env[key] } end def set_bundle_environment set_bundle_variables set_path set_rubyopt set_rubylib end # Rescues permissions errors raised by file system operations # (ie. Errno:EACCESS, Errno::EAGAIN) and raises more friendly errors instead. # # @param path [String] the path that the action will be attempted to # @param action [Symbol, #to_s] the type of operation that will be # performed. For example: :write, :read, :exec # # @yield path # # @raise [Bundler::PermissionError] if Errno:EACCES is raised in the # given block # @raise [Bundler::TemporaryResourceError] if Errno:EAGAIN is raised in the # given block # # @example # filesystem_access("vendor/cache", :write) do # FileUtils.mkdir_p("vendor/cache") # end # # @see {Bundler::PermissionError} def filesystem_access(path, action = :write, &block) yield(path.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }) rescue Errno::EACCES raise PermissionError.new(path, action) rescue Errno::EAGAIN raise TemporaryResourceError.new(path, action) rescue Errno::EPROTO raise VirtualProtocolError.new rescue Errno::ENOSPC raise NoSpaceOnDeviceError.new(path, action) rescue *[const_get_safely(:ENOTSUP, Errno)].compact raise OperationNotSupportedError.new(path, action) rescue Errno::EEXIST, Errno::ENOENT raise rescue SystemCallError => e raise GenericSystemCallError.new(e, "There was an error accessing `#{path}`.") end def const_get_safely(constant_name, namespace) const_in_namespace = namespace.constants.include?(constant_name.to_s) || namespace.constants.include?(constant_name.to_sym) return nil unless const_in_namespace namespace.const_get(constant_name) end def major_deprecation(major_version, message, print_caller_location: false) if print_caller_location caller_location = caller_locations(2, 2).first message = "#{message} (called at #{caller_location.path}:#{caller_location.lineno})" end bundler_major_version = Bundler.bundler_major_version if bundler_major_version > major_version require_relative "errors" raise DeprecatedError, "[REMOVED] #{message}" end return unless bundler_major_version >= major_version && prints_major_deprecations? Bundler.ui.warn("[DEPRECATED] #{message}") end def print_major_deprecations! multiple_gemfiles = search_up(".") do |dir| gemfiles = gemfile_names.select {|gf| File.file? File.expand_path(gf, dir) } next if gemfiles.empty? break gemfiles.size != 1 end return unless multiple_gemfiles message = "Multiple gemfiles (gems.rb and Gemfile) detected. " \ "Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.rb.locked." Bundler.ui.warn message end def trap(signal, override = false, &block) prior = Signal.trap(signal) do block.call prior.call unless override end end def ensure_same_dependencies(spec, old_deps, new_deps) new_deps = new_deps.reject {|d| d.type == :development } old_deps = old_deps.reject {|d| d.type == :development } without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) } new_deps.map!(&without_type) old_deps.map!(&without_type) extra_deps = new_deps - old_deps return if extra_deps.empty? Bundler.ui.debug "#{spec.full_name} from #{spec.remote} has either corrupted API or lockfile dependencies" \ " (was expecting #{old_deps.map(&:to_s)}, but the real spec has #{new_deps.map(&:to_s)})" raise APIResponseMismatchError, "Downloading #{spec.full_name} revealed dependencies not in the API or the lockfile (#{extra_deps.join(", ")})." \ "\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem." end def pretty_dependency(dep, print_source = false) msg = String.new(dep.name) msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default if dep.is_a?(Bundler::Dependency) platform_string = dep.platforms.join(", ") msg << " " << platform_string if !platform_string.empty? && platform_string != Gem::Platform::RUBY end msg << " from the `#{dep.source}` source" if print_source && dep.source msg end def md5_available? return @md5_available if defined?(@md5_available) @md5_available = begin require "openssl" ::OpenSSL::Digest.digest("MD5", "") true rescue LoadError true rescue ::OpenSSL::Digest::DigestError false end end def digest(name) require "digest" Digest(name) end def write_to_gemfile(gemfile_path, contents) filesystem_access(gemfile_path) {|g| File.open(g, "w") {|file| file.puts contents } } end private def validate_bundle_path path_separator = Bundler.rubygems.path_separator return unless Bundler.bundle_path.to_s.split(path_separator).size > 1 message = "Your bundle path contains text matching #{path_separator.inspect}, " \ "which is the path separator for your system. Bundler cannot " \ "function correctly when the Bundle path contains the " \ "system's PATH separator. Please change your " \ "bundle path to not match #{path_separator.inspect}." \ "\nYour current bundle path is '#{Bundler.bundle_path}'." raise Bundler::PathError, message end def find_gemfile given = ENV["BUNDLE_GEMFILE"] return given if given && !given.empty? find_file(*gemfile_names) end def gemfile_names ["gems.rb", "Gemfile"] end def find_file(*names) search_up(*names) do |filename| return filename if File.file?(filename) end end def find_directory(*names) search_up(*names) do |dirname| return dirname if File.directory?(dirname) end end def search_up(*names) previous = nil current = File.expand_path(SharedHelpers.pwd).tap{|x| x.untaint if RUBY_VERSION < "2.7" } until !File.directory?(current) || current == previous if ENV["BUNDLE_SPEC_RUN"] # avoid stepping above the tmp directory when testing gemspec = if ENV["GEM_COMMAND"] # for Ruby Core "lib/bundler/bundler.gemspec" else "bundler.gemspec" end # avoid stepping above the tmp directory when testing return nil if File.file?(File.join(current, gemspec)) end names.each do |name| filename = File.join(current, name) yield filename end previous = current current = File.expand_path("..", current) end end def set_env(key, value) raise ArgumentError, "new key #{key}" unless EnvironmentPreserver::BUNDLER_KEYS.include?(key) orig_key = "#{EnvironmentPreserver::BUNDLER_PREFIX}#{key}" orig = ENV[key] orig ||= EnvironmentPreserver::INTENTIONALLY_NIL ENV[orig_key] ||= orig ENV[key] = value end public :set_env def set_bundle_variables # bundler exe & lib folders have same root folder, typical gem installation exe_file = File.expand_path("../../../exe/bundle", __FILE__) # for Ruby core repository testing exe_file = File.expand_path("../../../libexec/bundle", __FILE__) unless File.exist?(exe_file) # bundler is a default gem, exe path is separate exe_file = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file) Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION end def set_path validate_bundle_path paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR) paths.unshift "#{Bundler.bundle_path}/bin" Bundler::SharedHelpers.set_env "PATH", paths.uniq.join(File::PATH_SEPARATOR) end def set_rubyopt rubyopt = [ENV["RUBYOPT"]].compact setup_require = "-r#{File.expand_path("setup", __dir__)}" return if !rubyopt.empty? && rubyopt.first =~ /#{setup_require}/ rubyopt.unshift setup_require Bundler::SharedHelpers.set_env "RUBYOPT", rubyopt.join(" ") end def set_rubylib rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR) rubylib.unshift bundler_ruby_lib unless RbConfig::CONFIG["rubylibdir"] == bundler_ruby_lib Bundler::SharedHelpers.set_env "RUBYLIB", rubylib.uniq.join(File::PATH_SEPARATOR) end def bundler_ruby_lib resolve_path File.expand_path("../..", __FILE__) end def clean_load_path bundler_lib = bundler_ruby_lib loaded_gem_paths = Bundler.rubygems.loaded_gem_paths $LOAD_PATH.reject! do |p| next if resolve_path(p).start_with?(bundler_lib) loaded_gem_paths.delete(p) end $LOAD_PATH.uniq! end def resolve_path(path) expanded = File.expand_path(path) return expanded unless File.respond_to?(:realpath) && File.exist?(expanded) File.realpath(expanded) end def prints_major_deprecations? require_relative "../bundler" return false if Bundler.settings[:silence_deprecations] require_relative "deprecate" return false if Bundler::Deprecate.skip true end extend self end end PK ]-)+gems/bundler-2.2.24/lib/bundler/ruby_dsl.rbnu[# frozen_string_literal: true module Bundler module RubyDsl def ruby(*ruby_version) options = ruby_version.last.is_a?(Hash) ? ruby_version.pop : {} ruby_version.flatten! raise GemfileError, "Please define :engine_version" if options[:engine] && options[:engine_version].nil? raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil? if options[:engine] == "ruby" && options[:engine_version] && ruby_version != Array(options[:engine_version]) raise GemfileEvalError, "ruby_version must match the :engine_version for MRI" end @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version]) end end end PK ]zrr&gems/bundler-2.2.24/lib/bundler/cli.rbnu[# frozen_string_literal: true require_relative "vendored_thor" module Bundler class CLI < Thor require_relative "cli/common" package_name "Bundler" AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze PARSEABLE_COMMANDS = %w[check config help exec platform show version].freeze COMMAND_ALIASES = { "check" => "c", "install" => "i", "plugin" => "", "list" => "ls", "exec" => ["e", "ex", "exe"], "cache" => ["package", "pack"], "version" => ["-v", "--version"], }.freeze def self.start(*) super ensure Bundler::SharedHelpers.print_major_deprecations! end def self.dispatch(*) super do |i| i.send(:print_command) i.send(:warn_on_outdated_bundler) end end def self.all_aliases @all_aliases ||= begin command_aliases = {} COMMAND_ALIASES.each do |name, aliases| Array(aliases).each do |one_alias| command_aliases[one_alias] = name end end command_aliases end end def self.aliases_for(command_name) COMMAND_ALIASES.select {|k, _| k == command_name }.invert end def initialize(*args) super custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile] if custom_gemfile && !custom_gemfile.empty? Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile) Bundler.reset_settings_and_root! end Bundler.settings.set_command_option_if_given :retry, options[:retry] current_cmd = args.last[:current_command].name auto_install if AUTO_INSTALL_CMDS.include?(current_cmd) rescue UnknownArgumentError => e raise InvalidOption, e.message ensure self.options ||= {} unprinted_warnings = Bundler.ui.unprinted_warnings Bundler.ui = UI::Shell.new(options) Bundler.ui.level = "debug" if options["verbose"] unprinted_warnings.each {|w| Bundler.ui.warn(w) } if ENV["RUBYGEMS_GEMDEPS"] && !ENV["RUBYGEMS_GEMDEPS"].empty? Bundler.ui.warn( "The RUBYGEMS_GEMDEPS environment variable is set. This enables RubyGems' " \ "experimental Gemfile mode, which may conflict with Bundler and cause unexpected errors. " \ "To remove this warning, unset RUBYGEMS_GEMDEPS.", :wrap => true ) end end check_unknown_options!(:except => [:config, :exec]) stop_on_unknown_option! :exec desc "cli_help", "Prints a summary of bundler commands", :hide => true def cli_help version Bundler.ui.info "\n" primary_commands = ["install", "update", "cache", "exec", "config", "help"] list = self.class.printable_commands(true) by_name = list.group_by {|name, _message| name.match(/^bundle (\w+)/)[1] } utilities = by_name.keys.sort - primary_commands primary_commands.map! {|name| (by_name[name] || raise("no primary command #{name}")).first } utilities.map! {|name| by_name[name].first } shell.say "Bundler commands:\n\n" shell.say " Primary commands:\n" shell.print_table(primary_commands, :indent => 4, :truncate => true) shell.say shell.say " Utilities:\n" shell.print_table(utilities, :indent => 4, :truncate => true) shell.say self.class.send(:class_options_help, shell) end default_task(Bundler.feature_flag.default_cli_command) class_option "no-color", :type => :boolean, :desc => "Disable colorization in output" class_option "retry", :type => :numeric, :aliases => "-r", :banner => "NUM", :desc => "Specify the number of times you wish to attempt network commands" class_option "verbose", :type => :boolean, :desc => "Enable verbose output mode", :aliases => "-V" def help(cli = nil) case cli when "gemfile" then command = "gemfile" when nil then command = "bundle" else command = "bundle-#{cli}" end man_path = File.expand_path("man", __dir__) man_pages = Hash[Dir.glob(File.join(man_path, "**", "*")).grep(/.*\.\d*\Z/).collect do |f| [File.basename(f, ".*"), f] end] if man_pages.include?(command) man_page = man_pages[command] if Bundler.which("man") && man_path !~ %r{^file:/.+!/META-INF/jruby.home/.+} Kernel.exec "man #{man_page}" else puts File.read("#{man_path}/#{File.basename(man_page)}.ronn") end elsif command_path = Bundler.which("bundler-#{cli}") Kernel.exec(command_path, "--help") else super end end def self.handle_no_command_error(command, has_namespace = $thor_runner) if Bundler.feature_flag.plugins? && Bundler::Plugin.command?(command) return Bundler::Plugin.exec_command(command, ARGV[1..-1]) end return super unless command_path = Bundler.which("bundler-#{command}") Kernel.exec(command_path, *ARGV[1..-1]) end desc "init [OPTIONS]", "Generates a Gemfile into the current working directory" long_desc <<-D Init generates a default Gemfile in the current working directory. When adding a Gemfile to a gem with a gemspec, the --gemspec option will automatically add each dependency listed in the gemspec file to the newly created Gemfile. D method_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile" def init require_relative "cli/init" Init.new(options.dup).run end desc "check [OPTIONS]", "Checks if the dependencies listed in Gemfile are satisfied by currently installed gems" long_desc <<-D Check searches the local machine for each of the gems requested in the Gemfile. If all gems are found, Bundler prints a success message and exits with a status of 0. If not, the first missing gem is listed and Bundler exits status 1. D method_option "dry-run", :type => :boolean, :default => false, :banner => "Lock the Gemfile" method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "path", :type => :string, :banner => "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" def check remembered_flag_deprecation("path") require_relative "cli/check" Check.new(options).run end map aliases_for("check") desc "remove [GEM [GEM ...]]", "Removes gems from the Gemfile" long_desc <<-D Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If the gem is not found, Bundler prints a error message and if gem could not be removed due to any reason Bundler will display a warning. D method_option "install", :type => :boolean, :banner => "Runs 'bundle install' after removing the gems from the Gemfile" def remove(*gems) require_relative "cli/remove" Remove.new(gems, options).run end desc "install [OPTIONS]", "Install the current environment to the system" long_desc <<-D Install will install all of the gems in the current bundle, making them available for use. In a freshly checked out repository, this command will give you the same gem versions as the last person who updated the Gemfile and ran `bundle update`. Passing [DIR] to install (e.g. vendor) will cause the unpacked gems to be installed into the [DIR] directory rather than into system gems. If the bundle has already been installed, bundler will tell you so and then exit. D method_option "binstubs", :type => :string, :lazy_default => "bin", :banner => "Generate bin stubs for bundled gems to ./bin" method_option "clean", :type => :boolean, :banner => "Run bundle clean automatically after install" method_option "deployment", :type => :boolean, :banner => "Install using defaults tuned for deployment environments" method_option "frozen", :type => :boolean, :banner => "Do not allow the Gemfile.lock to be updated after this install" method_option "full-index", :type => :boolean, :banner => "Fall back to using the single-file index of all gems" method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "jobs", :aliases => "-j", :type => :numeric, :banner => "Specify the number of jobs to run in parallel" method_option "local", :type => :boolean, :banner => "Do not attempt to fetch gems remotely and use the gem cache instead" method_option "no-cache", :type => :boolean, :banner => "Don't update the existing gem cache." method_option "redownload", :type => :boolean, :aliases => "--force", :banner => "Force downloading every gem." method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache." method_option "path", :type => :string, :banner => "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." method_option "shebang", :type => :string, :banner => "Specify a different shebang executable name than the default (usually 'ruby')" method_option "standalone", :type => :array, :lazy_default => [], :banner => "Make a bundle that can work without the Bundler runtime" method_option "system", :type => :boolean, :banner => "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application" method_option "trust-policy", :alias => "P", :type => :string, :banner => "Gem trust policy (like gem install -P). Must be one of " + Bundler.rubygems.security_policy_keys.join("|") method_option "without", :type => :array, :banner => "Exclude gems that are part of the specified named group." method_option "with", :type => :array, :banner => "Include gems that are part of the specified named group." def install SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force") %w[clean deployment frozen no-prune path shebang system without with].each do |option| remembered_flag_deprecation(option) end remembered_negative_flag_deprecation("no-deployment") require_relative "cli/install" Bundler.settings.temporary(:no_install => false) do Install.new(options.dup).run end end map aliases_for("install") desc "update [OPTIONS]", "Update the current environment" long_desc <<-D Update will install the newest versions of the gems listed in the Gemfile. Use update when you have changed the Gemfile, or if you want to get the newest possible versions of the gems in the bundle. D method_option "full-index", :type => :boolean, :banner => "Fall back to using the single-file index of all gems" method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "group", :aliases => "-g", :type => :array, :banner => "Update a specific group" method_option "jobs", :aliases => "-j", :type => :numeric, :banner => "Specify the number of jobs to run in parallel" method_option "local", :type => :boolean, :banner => "Do not attempt to fetch gems remotely and use the gem cache instead" method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." method_option "source", :type => :array, :banner => "Update a specific source (and all gems associated with it)" method_option "redownload", :type => :boolean, :aliases => "--force", :banner => "Force downloading every gem." method_option "ruby", :type => :boolean, :banner => "Update ruby specified in Gemfile.lock" method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner => "Update the locked version of bundler" method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version" method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version" method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" method_option "strict", :type => :boolean, :banner => "Do not allow any gem to be updated past latest --patch | --minor | --major" method_option "conservative", :type => :boolean, :banner => "Use bundle install conservative update behavior and do not allow shared dependencies to be updated." method_option "all", :type => :boolean, :banner => "Update everything." def update(*gems) SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force") require_relative "cli/update" Bundler.settings.temporary(:no_install => false) do Update.new(options, gems).run end end desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" long_desc <<-D Show lists the names and versions of all gems that are required by your Gemfile. Calling show with [GEM] will list the exact location of that gem on your machine. D method_option "paths", :type => :boolean, :banner => "List the paths of all gems that are required by your Gemfile." method_option "outdated", :type => :boolean, :banner => "Show verbose output including whether gems are outdated." def show(gem_name = nil) SharedHelpers.major_deprecation(2, "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement") if ARGV.include?("--outdated") require_relative "cli/show" Show.new(options, gem_name).run end desc "list", "List all gems in the bundle" method_option "name-only", :type => :boolean, :banner => "print only the gem names" method_option "only-group", :type => :array, :default => [], :banner => "print gems from a given set of groups" method_option "without-group", :type => :array, :default => [], :banner => "print all gems except from a given set of groups" method_option "paths", :type => :boolean, :banner => "print the path to each gem in the bundle" def list require_relative "cli/list" List.new(options).run end map aliases_for("list") desc "info GEM [OPTIONS]", "Show information for the given gem" method_option "path", :type => :boolean, :banner => "Print full path to gem" def info(gem_name) require_relative "cli/info" Info.new(options, gem_name).run end desc "binstubs GEM [OPTIONS]", "Install the binstubs of the listed gem" long_desc <<-D Generate binstubs for executables in [GEM]. Binstubs are put into bin, or the --binstubs directory if one has been set. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems. D method_option "force", :type => :boolean, :default => false, :banner => "Overwrite existing binstubs if they exist" method_option "path", :type => :string, :lazy_default => "bin", :banner => "Binstub destination directory (default bin)" method_option "shebang", :type => :string, :banner => "Specify a different shebang executable name than the default (usually 'ruby')" method_option "standalone", :type => :boolean, :banner => "Make binstubs that can work without the Bundler runtime" method_option "all", :type => :boolean, :banner => "Install binstubs for all gems" method_option "all-platforms", :type => :boolean, :default => false, :banner => "Install binstubs for all platforms" def binstubs(*gems) require_relative "cli/binstubs" Binstubs.new(options, gems).run end desc "add GEM VERSION", "Add gem to Gemfile and run bundle install" long_desc <<-D Adds the specified gem to Gemfile (if valid) and run 'bundle install' in one step. D method_option "version", :aliases => "-v", :type => :string method_option "group", :aliases => "-g", :type => :string method_option "source", :aliases => "-s", :type => :string method_option "git", :type => :string method_option "branch", :type => :string method_option "skip-install", :type => :boolean, :banner => "Adds gem to the Gemfile but does not install it" method_option "optimistic", :type => :boolean, :banner => "Adds optimistic declaration of version to gem" method_option "strict", :type => :boolean, :banner => "Adds strict declaration of version to gem" def add(*gems) require_relative "cli/add" Add.new(options.dup, gems).run end desc "outdated GEM [OPTIONS]", "List installed gems with newer versions available" long_desc <<-D Outdated lists the names and versions of gems that have a newer version available in the given source. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems. Prerelease gems are ignored by default. If your gems are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. For more information on patch level options (--major, --minor, --patch, --update-strict) see documentation on the same options on the update command. D method_option "group", :type => :string, :banner => "List gems from a specific group" method_option "groups", :type => :boolean, :banner => "List gems organized by groups" method_option "local", :type => :boolean, :banner => "Do not attempt to fetch gems remotely and use the gem cache instead" method_option "pre", :type => :boolean, :banner => "Check for newer pre-release gems" method_option "source", :type => :array, :banner => "Check against a specific source" strict_is_update = Bundler.feature_flag.forget_cli_options? method_option "filter-strict", :type => :boolean, :aliases => strict_is_update ? [] : %w[--strict], :banner => "Only list newer versions allowed by your Gemfile requirements" method_option "update-strict", :type => :boolean, :aliases => strict_is_update ? %w[--strict] : [], :banner => "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major" method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version" method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version" method_option "filter-major", :type => :boolean, :banner => "Only list major newer versions" method_option "filter-minor", :type => :boolean, :banner => "Only list minor newer versions" method_option "filter-patch", :type => :boolean, :banner => "Only list patch newer versions" method_option "parseable", :aliases => "--porcelain", :type => :boolean, :banner => "Use minimal formatting for more parseable output" method_option "only-explicit", :type => :boolean, :banner => "Only list gems specified in your Gemfile, not their dependencies" def outdated(*gems) require_relative "cli/outdated" Outdated.new(options, gems).run end desc "fund [OPTIONS]", "Lists information about gems seeking funding assistance" method_option "group", :aliases => "-g", :type => :array, :banner => "Fetch funding information for a specific group" def fund require_relative "cli/fund" Fund.new(options).run end desc "cache [OPTIONS]", "Locks and then caches all of the gems into vendor/cache" method_option "all", :type => :boolean, :default => Bundler.feature_flag.cache_all?, :banner => "Include all sources (including path and git)." method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one" method_option "cache-path", :type => :string, :banner => "Specify a different cache path than the default (vendor/cache)." method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "no-install", :type => :boolean, :banner => "Don't install the gems, only update the cache." method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache." method_option "path", :type => :string, :banner => "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." method_option "frozen", :type => :boolean, :banner => "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install" long_desc <<-D The cache command will copy the .gem files for every gem in the bundle into the directory ./vendor/cache. If you then check that directory into your source control repository, others who check out your source will be able to install the bundle without having to download any additional gems. D def cache SharedHelpers.major_deprecation 2, "The `--all` flag is deprecated because it relies on being " \ "remembered across bundler invocations, which bundler will no longer " \ "do in future versions. Instead please use `bundle config set cache_all true`, " \ "and stop using this flag" if ARGV.include?("--all") require_relative "cli/cache" Cache.new(options).run end map aliases_for("cache") desc "exec [OPTIONS]", "Run the command in context of the bundle" method_option :keep_file_descriptors, :type => :boolean, :default => false method_option :gemfile, :type => :string, :required => false long_desc <<-D Exec runs a command, providing it access to the gems in the bundle. While using bundle exec you can require and call the bundled gems as if they were installed into the system wide RubyGems repository. D def exec(*args) require_relative "cli/exec" Exec.new(options, args).run end map aliases_for("exec") desc "config NAME [VALUE]", "Retrieve or set a configuration value" long_desc <<-D Retrieves or sets a configuration value. If only one parameter is provided, retrieve the value. If two parameters are provided, replace the existing value with the newly provided one. By default, setting a configuration value sets it for all projects on the machine. If a global setting is superseded by local configuration, this command will show the current value, as well as any superseded values and where they were specified. D require_relative "cli/config" subcommand "config", Config desc "open GEM", "Opens the source directory of the given bundled gem" def open(name) require_relative "cli/open" Open.new(options, name).run end unless Bundler.feature_flag.bundler_3_mode? desc "console [GROUP]", "Opens an IRB session with the bundle pre-loaded" def console(group = nil) require_relative "cli/console" Console.new(options, group).run end end desc "version", "Prints the bundler's version information" def version cli_help = current_command.name == "cli_help" if cli_help || ARGV.include?("version") build_info = " (#{BuildMetadata.built_at} commit #{BuildMetadata.git_commit_sha})" end if !cli_help && Bundler.feature_flag.print_only_version_number? Bundler.ui.info "#{Bundler::VERSION}#{build_info}" else Bundler.ui.info "Bundler version #{Bundler::VERSION}#{build_info}" end end map aliases_for("version") desc "licenses", "Prints the license of all gems in the bundle" def licenses Bundler.load.specs.sort_by {|s| s.license.to_s }.reverse_each do |s| gem_name = s.name license = s.license || s.licenses if license.empty? Bundler.ui.warn "#{gem_name}: Unknown" else Bundler.ui.info "#{gem_name}: #{license}" end end end unless Bundler.feature_flag.bundler_3_mode? desc "viz [OPTIONS]", "Generates a visual dependency graph", :hide => true long_desc <<-D Viz generates a PNG file of the current Gemfile as a dependency graph. Viz requires the ruby-graphviz gem (and its dependencies). The associated gems must also be installed via 'bundle install'. D method_option :file, :type => :string, :default => "gem_graph", :aliases => "-f", :desc => "The name to use for the generated file. see format option" method_option :format, :type => :string, :default => "png", :aliases => "-F", :desc => "This is output format option. Supported format is png, jpg, svg, dot ..." method_option :requirements, :type => :boolean, :default => false, :aliases => "-R", :desc => "Set to show the version of each required dependency." method_option :version, :type => :boolean, :default => false, :aliases => "-v", :desc => "Set to show each gem version." method_option :without, :type => :array, :default => [], :aliases => "-W", :banner => "GROUP[ GROUP...]", :desc => "Exclude gems that are part of the specified named group." def viz SharedHelpers.major_deprecation 2, "The `viz` command has been moved to the `bundle-viz` gem, see https://github.com/bundler/bundler-viz" require_relative "cli/viz" Viz.new(options.dup).run end end old_gem = instance_method(:gem) desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem" method_option :exe, :type => :boolean, :default => false, :aliases => ["--bin", "-b"], :desc => "Generate a binary executable for your library." method_option :coc, :type => :boolean, :desc => "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`." method_option :edit, :type => :string, :aliases => "-e", :required => false, :banner => "EDITOR", :lazy_default => [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, :desc => "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)" method_option :ext, :type => :boolean, :default => false, :desc => "Generate the boilerplate for C extension code" method_option :git, :type => :boolean, :default => true, :desc => "Initialize a git repo inside your library." method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." method_option :rubocop, :type => :boolean, :desc => "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`." method_option :changelog, :type => :boolean, :desc => "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`." method_option :test, :type => :string, :lazy_default => Bundler.settings["gem.test"] || "", :aliases => "-t", :banner => "Use the specified test framework for your library", :desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`." method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "", :desc => "Generate CI configuration, either GitHub Actions, Travis CI, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|travis|gitlab|circle)`" method_option :github_username, :type => :string, :default => Bundler.settings["gem.github_username"], :banner => "Set your username on GitHub", :desc => "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username `." def gem(name) end commands["gem"].tap do |gem_command| def gem_command.run(instance, args = []) arity = 1 # name require_relative "cli/gem" cmd_args = args + [instance] cmd_args.unshift(instance.options) cmd = begin Gem.new(*cmd_args) rescue ArgumentError => e instance.class.handle_argument_error(self, e, args, arity) end cmd.run end end undef_method(:gem) define_method(:gem, old_gem) private :gem def self.source_root File.expand_path(File.join(File.dirname(__FILE__), "templates")) end desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", :hide => true method_option "dry-run", :type => :boolean, :default => false, :banner => "Only print out changes, do not clean gems" method_option "force", :type => :boolean, :default => false, :banner => "Forces clean even if --path is not set" def clean require_relative "cli/clean" Clean.new(options.dup).run end desc "platform [OPTIONS]", "Displays platform compatibility information" method_option "ruby", :type => :boolean, :default => false, :banner => "only display ruby related platform information" def platform require_relative "cli/platform" Platform.new(options).run end desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", :hide => true method_option "source", :type => :string, :banner => "Install gem from the given source" method_option "group", :type => :string, :banner => "Install gem into a bundler group" def inject(name, version) SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command" require_relative "cli/inject" Inject.new(options.dup, name, version).run end desc "lock", "Creates a lockfile without installing" method_option "update", :type => :array, :lazy_default => true, :banner => "ignore the existing lockfile, update all gems by default, or update list of given gems" method_option "local", :type => :boolean, :default => false, :banner => "do not attempt to fetch remote gemspecs and use the local gem cache only" method_option "print", :type => :boolean, :default => false, :banner => "print the lockfile to STDOUT instead of writing to the file system" method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "lockfile", :type => :string, :default => nil, :banner => "the path the lockfile should be written to" method_option "full-index", :type => :boolean, :default => false, :banner => "Fall back to using the single-file index of all gems" method_option "add-platform", :type => :array, :default => [], :banner => "Add a new platform to the lockfile" method_option "remove-platform", :type => :array, :default => [], :banner => "Remove a platform from the lockfile" method_option "patch", :type => :boolean, :banner => "If updating, prefer updating only to next patch version" method_option "minor", :type => :boolean, :banner => "If updating, prefer updating only to next minor version" method_option "major", :type => :boolean, :banner => "If updating, prefer updating to next major version (default)" method_option "strict", :type => :boolean, :banner => "If updating, do not allow any gem to be updated past latest --patch | --minor | --major" method_option "conservative", :type => :boolean, :banner => "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated" def lock require_relative "cli/lock" Lock.new(options).run end desc "env", "Print information about the environment Bundler is running under" def env Env.write($stdout) end desc "doctor [OPTIONS]", "Checks the bundle for common problems" long_desc <<-D Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If missing dependencies are detected, Bundler prints them and exits status 1. Otherwise, Bundler prints a success message and exits with a status of 0. D method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." def doctor require_relative "cli/doctor" Doctor.new(options).run end desc "issue", "Learn how to report an issue in Bundler" def issue require_relative "cli/issue" Issue.new.run end desc "pristine [GEMS...]", "Restores installed gems to pristine condition" long_desc <<-D Restores installed gems to pristine condition from files located in the gem cache. Gems installed from a git repository will be issued `git checkout --force`. D def pristine(*gems) require_relative "cli/pristine" Pristine.new(gems).run end if Bundler.feature_flag.plugins? require_relative "cli/plugin" desc "plugin", "Manage the bundler plugins" subcommand "plugin", Plugin end # Reformat the arguments passed to bundle that include a --help flag # into the corresponding `bundle help #{command}` call def self.reformatted_help_args(args) bundler_commands = (COMMAND_ALIASES.keys + COMMAND_ALIASES.values).flatten help_flags = %w[--help -h] exec_commands = ["exec"] + COMMAND_ALIASES["exec"] help_used = args.index {|a| help_flags.include? a } exec_used = args.index {|a| exec_commands.include? a } command = args.find {|a| bundler_commands.include? a } command = all_aliases[command] if all_aliases[command] if exec_used && help_used if exec_used + help_used == 1 %w[help exec] else args end elsif help_used args = args.dup args.delete_at(help_used) ["help", command || args].flatten.compact else args end end private # Automatically invoke `bundle install` and resume if # Bundler.settings[:auto_install] exists. This is set through config cmd # `bundle config set --global auto_install 1`. # # Note that this method `nil`s out the global Definition object, so it # should be called first, before you instantiate anything like an # `Installer` that'll keep a reference to the old one instead. def auto_install return unless Bundler.settings[:auto_install] begin Bundler.definition.specs rescue GemNotFound Bundler.ui.info "Automatically installing missing gems." Bundler.reset! invoke :install, [] Bundler.reset! end end def current_command _, _, config = @_initializer config[:current_command] end def print_command return unless Bundler.ui.debug? cmd = current_command command_name = cmd.name return if PARSEABLE_COMMANDS.include?(command_name) command = ["bundle", command_name] + args options_to_print = options.dup options_to_print.delete_if do |k, v| next unless o = cmd.options[k] o.default == v end command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip command.reject!(&:empty?) Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler::VERSION}" end def warn_on_outdated_bundler return if Bundler.settings[:disable_version_check] command_name = current_command.name return if PARSEABLE_COMMANDS.include?(command_name) return unless SharedHelpers.md5_available? latest = Fetcher::CompactIndex. new(nil, Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org")), nil). send(:compact_index_client). instance_variable_get(:@cache). dependencies("bundler"). map {|d| Gem::Version.new(d.first) }. max return unless latest current = Gem::Version.new(VERSION) return if current >= latest latest_installed = Bundler.rubygems.find_name("bundler").map(&:version).max installation = "To install the latest version, run `gem install bundler#{" --pre" if latest.prerelease?}`" if latest_installed && latest_installed > current suggestion = "To update to the most recent installed version (#{latest_installed}), run `bundle update --bundler`" suggestion = "#{installation}\n#{suggestion}" if latest_installed < latest else suggestion = installation end Bundler.ui.warn "The latest bundler is #{latest}, but you are currently running #{current}.\n#{suggestion}" rescue RuntimeError nil end def remembered_negative_flag_deprecation(name) positive_name = name.gsub(/\Ano-/, "") option = current_command.options[positive_name] flag_name = "--no-" + option.switch_name.gsub(/\A--/, "") flag_deprecation(positive_name, flag_name, option) end def remembered_flag_deprecation(name) option = current_command.options[name] flag_name = option.switch_name flag_deprecation(name, flag_name, option) end def flag_deprecation(name, flag_name, option) name_index = ARGV.find {|arg| flag_name == arg.split("=")[0] } return unless name_index value = options[name] value = value.join(" ").to_s if option.type == :array Bundler::SharedHelpers.major_deprecation 2, "The `#{flag_name}` flag is deprecated because it relies on being " \ "remembered across bundler invocations, which bundler will no longer " \ "do in future versions. Instead please use `bundle config set --local #{name.tr("-", "_")} " \ "'#{value}'`, and stop using this flag" end end end PK ]!6n n 2gems/bundler-2.2.24/lib/bundler/yaml_serializer.rbnu[# frozen_string_literal: true module Bundler # A stub yaml serializer that can handle only hashes and strings (as of now). module YAMLSerializer module_function def dump(hash) yaml = String.new("---") yaml << dump_hash(hash) end def dump_hash(hash) yaml = String.new("\n") hash.each do |k, v| yaml << k << ":" if v.is_a?(Hash) yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines elsif v.is_a?(Array) # Expected to be array of strings yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n" else yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n" end end yaml end ARRAY_REGEX = / ^ (?:[ ]*-[ ]) # '- ' before array items (['"]?) # optional opening quote (.*) # value \1 # matching closing quote $ /xo.freeze HASH_REGEX = / ^ ([ ]*) # indentations (.+) # key (?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value) [ ]? (['"]?) # optional opening quote (.*) # value \3 # matching closing quote $ /xo.freeze def load(str) res = {} stack = [res] last_hash = nil last_empty_key = nil str.split(/\r?\n/).each do |line| if match = HASH_REGEX.match(line) indent, key, quote, val = match.captures key = convert_to_backward_compatible_key(key) depth = indent.scan(/ /).length if quote.empty? && val.empty? new_hash = {} stack[depth][key] = new_hash stack[depth + 1] = new_hash last_empty_key = key last_hash = stack[depth] else stack[depth][key] = val end elsif match = ARRAY_REGEX.match(line) _, val = match.captures last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array) last_hash[last_empty_key].push(val) end end res end # for settings' keys def convert_to_backward_compatible_key(key) key = "#{key}/" if key =~ /https?:/i && key !~ %r{/\Z} key = key.gsub(".", "__") if key.include?(".") key end class << self private :dump_hash, :convert_to_backward_compatible_key end end end PK ]X33+gems/bundler-2.2.24/lib/bundler/settings.rbnu[# frozen_string_literal: true module Bundler class Settings autoload :Mirror, File.expand_path("mirror", __dir__) autoload :Mirrors, File.expand_path("mirror", __dir__) autoload :Validator, File.expand_path("settings/validator", __dir__) BOOL_KEYS = %w[ allow_deployment_source_credential_changes allow_offline_install auto_clean_without_path auto_install cache_all cache_all_platforms clean default_install_uses_path deployment disable_checksum_validation disable_exec_load disable_local_branch_check disable_local_revision_check disable_shared_gems disable_version_check force_ruby_platform forget_cli_options frozen gem.changelog gem.coc gem.mit git.allow_insecure global_gem_cache ignore_messages init_gems_rb inline no_install no_prune path_relative_to_cwd path.system plugins prefer_patch print_only_version_number setup_makes_kernel_gem_public silence_deprecations silence_root_warning suppress_install_using_messages update_requires_all_flag use_gem_version_promoter_for_major_updates ].freeze NUMBER_KEYS = %w[ jobs redirect retry ssl_verify_mode timeout ].freeze ARRAY_KEYS = %w[ with without ].freeze STRING_KEYS = %w[ bin cache_path console gem.ci gem.github_username gem.linter gem.rubocop gem.test gemfile path shebang system_bindir trust-policy ].freeze DEFAULT_CONFIG = { "BUNDLE_SILENCE_DEPRECATIONS" => false, "BUNDLE_DISABLE_VERSION_CHECK" => true, "BUNDLE_PREFER_PATCH" => false, "BUNDLE_REDIRECT" => 5, "BUNDLE_RETRY" => 3, "BUNDLE_TIMEOUT" => 10, }.freeze def initialize(root = nil) @root = root @local_config = load_config(local_config_file) @env_config = ENV.to_h.select {|key, _value| key =~ /\ABUNDLE_.+/ } @global_config = load_config(global_config_file) @temporary = {} end def [](name) key = key_for(name) value = configs.values.map {|config| config[key] }.compact.first converted_value(value, name) end def set_command_option(key, value) if Bundler.feature_flag.forget_cli_options? temporary(key => value) value else set_local(key, value) end end def set_command_option_if_given(key, value) return if value.nil? set_command_option(key, value) end def set_local(key, value) local_config_file || raise(GemfileNotFound, "Could not locate Gemfile") set_key(key, value, @local_config, local_config_file) end def temporary(update) existing = Hash[update.map {|k, _| [k, @temporary[key_for(k)]] }] update.each do |k, v| set_key(k, v, @temporary, nil) end return unless block_given? begin yield ensure existing.each {|k, v| set_key(k, v, @temporary, nil) } end end def set_global(key, value) set_key(key, value, @global_config, global_config_file) end def all keys = @temporary.keys | @global_config.keys | @local_config.keys | @env_config.keys keys.map do |key| key.sub(/^BUNDLE_/, "").gsub(/___/, "-").gsub(/__/, ".").downcase end.sort end def local_overrides repos = {} all.each do |k| repos[$'] = self[k] if k =~ /^local\./ end repos end def mirror_for(uri) if uri.is_a?(String) require_relative "vendored_uri" uri = Bundler::URI(uri) end gem_mirrors.for(uri.to_s).uri end def credentials_for(uri) self[uri.to_s] || self[uri.host] end def gem_mirrors all.inject(Mirrors.new) do |mirrors, k| mirrors.parse(k, self[k]) if k.start_with?("mirror.") mirrors end end def locations(key) key = key_for(key) configs.keys.inject({}) do |partial_locations, level| value_on_level = configs[level][key] partial_locations[level] = value_on_level unless value_on_level.nil? partial_locations end end def pretty_values_for(exposed_key) key = key_for(exposed_key) locations = [] if value = @temporary[key] locations << "Set for the current command: #{printable_value(value, exposed_key).inspect}" end if value = @local_config[key] locations << "Set for your local app (#{local_config_file}): #{printable_value(value, exposed_key).inspect}" end if value = @env_config[key] locations << "Set via #{key}: #{printable_value(value, exposed_key).inspect}" end if value = @global_config[key] locations << "Set for the current user (#{global_config_file}): #{printable_value(value, exposed_key).inspect}" end return ["You have not configured a value for `#{exposed_key}`"] if locations.empty? locations end def processor_count require "etc" Etc.nprocessors rescue StandardError 1 end # for legacy reasons, in Bundler 2, we do not respect :disable_shared_gems def path configs.each do |_level, settings| path = value_for("path", settings) path_system = value_for("path.system", settings) disabled_shared_gems = value_for("disable_shared_gems", settings) next if path.nil? && path_system.nil? && disabled_shared_gems.nil? system_path = path_system || (disabled_shared_gems == false) return Path.new(path, system_path) end Path.new(nil, false) end Path = Struct.new(:explicit_path, :system_path) do def path path = base_path path = File.join(path, Bundler.ruby_scope) unless use_system_gems? path end def use_system_gems? return true if system_path return false if explicit_path !Bundler.feature_flag.default_install_uses_path? end def base_path path = explicit_path path ||= ".bundle" unless use_system_gems? path ||= Bundler.rubygems.gem_dir path end def base_path_relative_to_pwd base_path = Pathname.new(self.base_path) expanded_base_path = base_path.expand_path(Bundler.root) relative_path = expanded_base_path.relative_path_from(Pathname.pwd) if relative_path.to_s.start_with?("..") relative_path = base_path if base_path.absolute? else relative_path = Pathname.new(File.join(".", relative_path)) end relative_path rescue ArgumentError expanded_base_path end def validate! return unless explicit_path && system_path path = Bundler.settings.pretty_values_for(:path) path.unshift(nil, "path:") unless path.empty? system_path = Bundler.settings.pretty_values_for("path.system") system_path.unshift(nil, "path.system:") unless system_path.empty? disable_shared_gems = Bundler.settings.pretty_values_for(:disable_shared_gems) disable_shared_gems.unshift(nil, "disable_shared_gems:") unless disable_shared_gems.empty? raise InvalidOption, "Using a custom path while using system gems is unsupported.\n#{path.join("\n")}\n#{system_path.join("\n")}\n#{disable_shared_gems.join("\n")}" end end def allow_sudo? key = key_for(:path) path_configured = @temporary.key?(key) || @local_config.key?(key) !path_configured end def ignore_config? ENV["BUNDLE_IGNORE_CONFIG"] end def app_cache_path @app_cache_path ||= self[:cache_path] || "vendor/cache" end def validate! all.each do |raw_key| [@local_config, @env_config, @global_config].each do |settings| value = value_for(raw_key, settings) Validator.validate!(raw_key, value, settings.dup) end end end def key_for(key) self.class.key_for(key) end private def configs { :temporary => @temporary, :local => @local_config, :env => @env_config, :global => @global_config, :default => DEFAULT_CONFIG, } end def value_for(name, config) converted_value(config[key_for(name)], name) end def parent_setting_for(name) split_specific_setting_for(name)[0] end def specific_gem_for(name) split_specific_setting_for(name)[1] end def split_specific_setting_for(name) name.split(".") end def is_bool(name) BOOL_KEYS.include?(name.to_s) || BOOL_KEYS.include?(parent_setting_for(name.to_s)) end def is_string(name) STRING_KEYS.include?(name.to_s) || name.to_s.start_with?("local.") || name.to_s.start_with?("mirror.") || name.to_s.start_with?("build.") end def to_bool(value) case value when nil, /\A(false|f|no|n|0|)\z/i, false false else true end end def is_num(key) NUMBER_KEYS.include?(key.to_s) end def is_array(key) ARRAY_KEYS.include?(key.to_s) end def is_credential(key) key == "gem.push_key" end def is_userinfo(value) value.include?(":") end def to_array(value) return [] unless value value.split(":").map(&:to_sym) end def array_to_s(array) array = Array(array) return nil if array.empty? array.join(":").tr(" ", ":") end def set_key(raw_key, value, hash, file) raw_key = raw_key.to_s value = array_to_s(value) if is_array(raw_key) key = key_for(raw_key) return if hash[key] == value hash[key] = value hash.delete(key) if value.nil? Validator.validate!(raw_key, converted_value(value, raw_key), hash) return unless file SharedHelpers.filesystem_access(file) do |p| FileUtils.mkdir_p(p.dirname) require_relative "yaml_serializer" p.open("w") {|f| f.write(YAMLSerializer.dump(hash)) } end end def converted_value(value, key) if is_array(key) to_array(value) elsif value.nil? nil elsif is_bool(key) || value == "false" to_bool(value) elsif is_num(key) value.to_i else value.to_s end end def printable_value(value, key) converted = converted_value(value, key) return converted unless converted.is_a?(String) if is_string(key) converted elsif is_credential(key) "[REDACTED]" elsif is_userinfo(converted) converted.gsub(/:.*$/, ":[REDACTED]") else converted end end def global_config_file if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty? Pathname.new(ENV["BUNDLE_CONFIG"]) elsif Bundler.rubygems.user_home && !Bundler.rubygems.user_home.empty? Pathname.new(Bundler.rubygems.user_home).join(".bundle/config") end end def local_config_file Pathname.new(@root).join("config") if @root end def load_config(config_file) return {} if !config_file || ignore_config? SharedHelpers.filesystem_access(config_file, :read) do |file| valid_file = file.exist? && !file.size.zero? return {} unless valid_file require_relative "yaml_serializer" YAMLSerializer.load(file.read).inject({}) do |config, (k, v)| new_k = k if k.include?("-") Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \ "This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \ "Please edit #{file} and replace any dashes in configuration keys with a triple underscore (`___`)." new_k = k.gsub("-", "___") end config[new_k] = v config end end end PER_URI_OPTIONS = %w[ fallback_timeout ].freeze NORMALIZE_URI_OPTIONS_PATTERN = / \A (\w+\.)? # optional prefix key (https?.*?) # URI (\.#{Regexp.union(PER_URI_OPTIONS)})? # optional suffix key \z /ix.freeze def self.key_for(key) key = normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key key = key.to_s.gsub(".", "__").gsub("-", "___").upcase "BUNDLE_#{key}" end # TODO: duplicates Rubygems#normalize_uri # TODO: is this the correct place to validate mirror URIs? def self.normalize_uri(uri) uri = uri.to_s if uri =~ NORMALIZE_URI_OPTIONS_PATTERN prefix = $1 uri = $2 suffix = $3 end uri = "#{uri}/" unless uri.end_with?("/") require_relative "vendored_uri" uri = Bundler::URI(uri) unless uri.absolute? raise ArgumentError, format("Gem sources must be absolute. You provided '%s'.", uri) end "#{prefix}#{uri}#{suffix}" end end end PK ](|{ { 5gems/bundler-2.2.24/lib/bundler/stub_specification.rbnu[# frozen_string_literal: true module Bundler class StubSpecification < RemoteSpecification def self.from_stub(stub) return stub if stub.is_a?(Bundler::StubSpecification) spec = new(stub.name, stub.version, stub.platform, nil) spec.stub = stub spec end attr_accessor :stub, :ignored def source=(source) super # Stub has no concept of source, which means that extension_dir may be wrong # This is the case for git-based gems. So, instead manually assign the extension dir return unless source.respond_to?(:extension_dir_name) path = File.join(stub.extensions_dir, source.extension_dir_name) stub.extension_dir = File.expand_path(path) end def to_yaml _remote_specification.to_yaml end # @!group Stub Delegates def manually_installed? # This is for manually installed gems which are gems that were fixed in place after a # failed installation. Once the issue was resolved, the user then manually created # the gem specification using the instructions provided by `gem help install` installed_by_version == Gem::Version.new(0) end # This is defined directly to avoid having to loading the full spec def missing_extensions? return false if default_gem? return false if extensions.empty? return false if File.exist? gem_build_complete_path return false if manually_installed? true end def activated stub.activated end def activated=(activated) stub.instance_variable_set(:@activated, activated) end def extensions stub.extensions end def gem_build_complete_path File.join(extension_dir, "gem.build_complete") end def default_gem? stub.default_gem? end def full_gem_path # deleted gems can have their stubs return nil, so in that case grab the # expired path from the full spec stub.full_gem_path || method_missing(:full_gem_path) end def full_require_paths stub.full_require_paths end def load_paths full_require_paths end def loaded_from stub.loaded_from end def matches_for_glob(glob) stub.matches_for_glob(glob) end def raw_require_paths stub.raw_require_paths end private def _remote_specification @_remote_specification ||= begin rs = stub.to_spec if rs.equal?(self) # happens when to_spec gets the spec from Gem.loaded_specs rs = Gem::Specification.load(loaded_from) Bundler.rubygems.stub_set_spec(stub, rs) end unless rs raise GemspecError, "The gemspec for #{full_name} at #{loaded_from}" \ " was missing or broken. Try running `gem pristine #{name} -v #{version}`" \ " to fix the cached spec." end rs.source = source rs end end end end PK ]e Mgems/bundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool.rbnu[require_relative 'connection_pool/version' require_relative 'connection_pool/timed_stack' # Generic connection pool class for e.g. sharing a limited number of network connections # among many threads. Note: Connections are lazily created. # # Example usage with block (faster): # # @pool = Bundler::ConnectionPool.new { Redis.new } # # @pool.with do |redis| # redis.lpop('my-list') if redis.llen('my-list') > 0 # end # # Using optional timeout override (for that single invocation) # # @pool.with(timeout: 2.0) do |redis| # redis.lpop('my-list') if redis.llen('my-list') > 0 # end # # Example usage replacing an existing connection (slower): # # $redis = Bundler::ConnectionPool.wrap { Redis.new } # # def do_work # $redis.lpop('my-list') if $redis.llen('my-list') > 0 # end # # Accepts the following options: # - :size - number of connections to pool, defaults to 5 # - :timeout - amount of time to wait for a connection if none currently available, defaults to 5 seconds # class Bundler::ConnectionPool DEFAULTS = {size: 5, timeout: 5} class Error < RuntimeError end def self.wrap(options, &block) Wrapper.new(options, &block) end def initialize(options = {}, &block) raise ArgumentError, 'Connection pool requires a block' unless block options = DEFAULTS.merge(options) @size = options.fetch(:size) @timeout = options.fetch(:timeout) @available = TimedStack.new(@size, &block) @key = :"current-#{@available.object_id}" @key_count = :"current-#{@available.object_id}-count" end if Thread.respond_to?(:handle_interrupt) # MRI def with(options = {}) Thread.handle_interrupt(Exception => :never) do conn = checkout(options) begin Thread.handle_interrupt(Exception => :immediate) do yield conn end ensure checkin end end end else # jruby 1.7.x def with(options = {}) conn = checkout(options) begin yield conn ensure checkin end end end def checkout(options = {}) if ::Thread.current[@key] ::Thread.current[@key_count]+= 1 ::Thread.current[@key] else ::Thread.current[@key_count]= 1 ::Thread.current[@key]= @available.pop(options[:timeout] || @timeout) end end def checkin if ::Thread.current[@key] if ::Thread.current[@key_count] == 1 @available.push(::Thread.current[@key]) ::Thread.current[@key]= nil else ::Thread.current[@key_count]-= 1 end else raise Bundler::ConnectionPool::Error, 'no connections are checked out' end nil end def shutdown(&block) @available.shutdown(&block) end # Size of this connection pool def size @size end # Number of pool entries available for checkout at this instant. def available @available.length end private class Wrapper < ::BasicObject METHODS = [:with, :pool_shutdown] def initialize(options = {}, &block) @pool = options.fetch(:pool) { ::Bundler::ConnectionPool.new(options, &block) } end def with(&block) @pool.with(&block) end def pool_shutdown(&block) @pool.shutdown(&block) end def pool_size @pool.size end def pool_available @pool.available end def respond_to?(id, *args) METHODS.include?(id) || with { |c| c.respond_to?(id, *args) } end def method_missing(name, *args, &block) with do |connection| connection.send(name, *args, &block) end end end end PK ]\?66Ugems/bundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rbnu[class Bundler::ConnectionPool VERSION = "2.2.2" end PK ]q.YY\gems/bundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rbnu[# Global monotonic clock from Concurrent Ruby 1.0. # Copyright (c) Jerry D'Antonio -- released under the MIT license. # Slightly modified; used with permission. # https://github.com/ruby-concurrency/concurrent-ruby require 'thread' class Bundler::ConnectionPool class_definition = Class.new do if defined?(Process::CLOCK_MONOTONIC) # @!visibility private def get_time Process.clock_gettime(Process::CLOCK_MONOTONIC) end elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' # @!visibility private def get_time java.lang.System.nanoTime() / 1_000_000_000.0 end else # @!visibility private def initialize @mutex = Mutex.new @last_time = Time.now.to_f end # @!visibility private def get_time @mutex.synchronize do now = Time.now.to_f if @last_time < now @last_time = now else # clock has moved back in time @last_time += 0.000_001 end end end end end ## # Clock that cannot be set and represents monotonic time since # some unspecified starting point. # # @!visibility private GLOBAL_MONOTONIC_CLOCK = class_definition.new private_constant :GLOBAL_MONOTONIC_CLOCK class << self ## # Returns the current time a tracked by the application monotonic clock. # # @return [Float] The current monotonic time when `since` not given else # the elapsed monotonic time between `since` and the current time def monotonic_time GLOBAL_MONOTONIC_CLOCK.get_time end end end PK ]y<22Ygems/bundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rbnu[require 'thread' require 'timeout' require_relative 'monotonic_time' ## # Raised when you attempt to retrieve a connection from a pool that has been # shut down. class Bundler::ConnectionPool::PoolShuttingDownError < RuntimeError; end ## # The TimedStack manages a pool of homogeneous connections (or any resource # you wish to manage). Connections are created lazily up to a given maximum # number. # Examples: # # ts = TimedStack.new(1) { MyConnection.new } # # # fetch a connection # conn = ts.pop # # # return a connection # ts.push conn # # conn = ts.pop # ts.pop timeout: 5 # #=> raises Timeout::Error after 5 seconds class Bundler::ConnectionPool::TimedStack attr_reader :max ## # Creates a new pool with +size+ connections that are created from the given # +block+. def initialize(size = 0, &block) @create_block = block @created = 0 @que = [] @max = size @mutex = Mutex.new @resource = ConditionVariable.new @shutdown_block = nil end ## # Returns +obj+ to the stack. +options+ is ignored in TimedStack but may be # used by subclasses that extend TimedStack. def push(obj, options = {}) @mutex.synchronize do if @shutdown_block @shutdown_block.call(obj) else store_connection obj, options end @resource.broadcast end end alias_method :<<, :push ## # Retrieves a connection from the stack. If a connection is available it is # immediately returned. If no connection is available within the given # timeout a Timeout::Error is raised. # # +:timeout+ is the only checked entry in +options+ and is preferred over # the +timeout+ argument (which will be removed in a future release). Other # options may be used by subclasses that extend TimedStack. def pop(timeout = 0.5, options = {}) options, timeout = timeout, 0.5 if Hash === timeout timeout = options.fetch :timeout, timeout deadline = Bundler::ConnectionPool.monotonic_time + timeout @mutex.synchronize do loop do raise Bundler::ConnectionPool::PoolShuttingDownError if @shutdown_block return fetch_connection(options) if connection_stored?(options) connection = try_create(options) return connection if connection to_wait = deadline - Bundler::ConnectionPool.monotonic_time raise Timeout::Error, "Waited #{timeout} sec" if to_wait <= 0 @resource.wait(@mutex, to_wait) end end end ## # Shuts down the TimedStack which prevents connections from being checked # out. The +block+ is called once for each connection on the stack. def shutdown(&block) raise ArgumentError, "shutdown must receive a block" unless block_given? @mutex.synchronize do @shutdown_block = block @resource.broadcast shutdown_connections end end ## # Returns +true+ if there are no available connections. def empty? (@created - @que.length) >= @max end ## # The number of connections available on the stack. def length @max - @created + @que.length end private ## # This is an extension point for TimedStack and is called with a mutex. # # This method must returns true if a connection is available on the stack. def connection_stored?(options = nil) !@que.empty? end ## # This is an extension point for TimedStack and is called with a mutex. # # This method must return a connection from the stack. def fetch_connection(options = nil) @que.pop end ## # This is an extension point for TimedStack and is called with a mutex. # # This method must shut down all connections on the stack. def shutdown_connections(options = nil) while connection_stored?(options) conn = fetch_connection(options) @shutdown_block.call(conn) end end ## # This is an extension point for TimedStack and is called with a mutex. # # This method must return +obj+ to the stack. def store_connection(obj, options = nil) @que.push obj end ## # This is an extension point for TimedStack and is called with a mutex. # # This method must create a connection if and only if the total number of # connections allowed has not been met. def try_create(options = nil) unless @created == @max object = @create_block.call @created += 1 object end end end PK ]홇Cgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor.rbnu[require_relative "line_editor/basic" require_relative "line_editor/readline" class Bundler::Thor module LineEditor def self.readline(prompt, options = {}) best_available.new(prompt, options).readline end def self.best_available [ Bundler::Thor::LineEditor::Readline, Bundler::Thor::LineEditor::Basic ].detect(&:available?) end end end PK ]>gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser.rbnu[require_relative "parser/argument" require_relative "parser/arguments" require_relative "parser/option" require_relative "parser/options" PK ]LuvvCgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/rake_compat.rbnu[require "rake" require "rake/dsl_definition" class Bundler::Thor # Adds a compatibility layer to your Bundler::Thor classes which allows you to use # rake package tasks. For example, to use rspec rake tasks, one can do: # # require 'bundler/vendor/thor/lib/thor/rake_compat' # require 'rspec/core/rake_task' # # class Default < Bundler::Thor # include Bundler::Thor::RakeCompat # # RSpec::Core::RakeTask.new(:spec) do |t| # t.spec_opts = ['--options', './.rspec'] # t.spec_files = FileList['spec/**/*_spec.rb'] # end # end # module RakeCompat include Rake::DSL if defined?(Rake::DSL) def self.rake_classes @rake_classes ||= [] end def self.included(base) super(base) # Hack. Make rakefile point to invoker, so rdoc task is generated properly. rakefile = File.basename(caller[0].match(/(.*):\d+/)[1]) Rake.application.instance_variable_set(:@rakefile, rakefile) rake_classes << base end end end # override task on (main), for compatibility with Rake 0.9 instance_eval do alias rake_namespace namespace def task(*) task = super if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition non_namespaced_name = task.name.split(":").last description = non_namespaced_name description << task.arg_names.map { |n| n.to_s.upcase }.join(" ") description.strip! klass.desc description, Rake.application.last_description || non_namespaced_name Rake.application.last_description = nil klass.send :define_method, non_namespaced_name do |*args| Rake::Task[task.name.to_sym].invoke(*args) end end task end def namespace(name) if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition const_name = Bundler::Thor::Util.camel_case(name.to_s).to_sym klass.const_set(const_name, Class.new(Bundler::Thor)) new_klass = klass.const_get(const_name) Bundler::Thor::RakeCompat.rake_classes << new_klass end super Bundler::Thor::RakeCompat.rake_classes.pop end end PK ]ɗc =gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/error.rbnu[class Bundler::Thor Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) # rubocop:disable Naming/ConstantName # In order to support versions of Ruby that don't have keyword # arguments, we need our own spell checker class that doesn't take key # words. Even though this code wouldn't be hit because of the check # above, it's still necessary because the interpreter would otherwise be # unable to parse the file. class NoKwargSpellChecker < DidYouMean::SpellChecker # :nodoc: def initialize(dictionary) @dictionary = dictionary end end DidYouMean::Correctable end # Bundler::Thor::Error is raised when it's caused by wrong usage of thor classes. Those # errors have their backtrace suppressed and are nicely shown to the user. # # Errors that are caused by the developer, like declaring a method which # overwrites a thor keyword, SHOULD NOT raise a Bundler::Thor::Error. This way, we # ensure that developer errors are shown with full backtrace. class Error < StandardError end # Raised when a command was not found. class UndefinedCommandError < Error class SpellChecker attr_reader :error def initialize(error) @error = error end def corrections @corrections ||= spell_checker.correct(error.command).map(&:inspect) end def spell_checker NoKwargSpellChecker.new(error.all_commands) end end attr_reader :command, :all_commands def initialize(command, all_commands, namespace) @command = command @all_commands = all_commands message = "Could not find command #{command.inspect}" message = namespace ? "#{message} in #{namespace.inspect} namespace." : "#{message}." super(message) end prepend Correctable if Correctable end UndefinedTaskError = UndefinedCommandError class AmbiguousCommandError < Error end AmbiguousTaskError = AmbiguousCommandError # Raised when a command was found, but not invoked properly. class InvocationError < Error end class UnknownArgumentError < Error class SpellChecker attr_reader :error def initialize(error) @error = error end def corrections @corrections ||= error.unknown.flat_map { |unknown| spell_checker.correct(unknown) }.uniq.map(&:inspect) end def spell_checker @spell_checker ||= NoKwargSpellChecker.new(error.switches) end end attr_reader :switches, :unknown def initialize(switches, unknown) @switches = switches @unknown = unknown super("Unknown switches #{unknown.map(&:inspect).join(', ')}") end prepend Correctable if Correctable end class RequiredArgumentMissingError < InvocationError end class MalformattedArgumentError < InvocationError end if Correctable DidYouMean::SPELL_CHECKERS.merge!( 'Bundler::Thor::UndefinedCommandError' => UndefinedCommandError::SpellChecker, 'Bundler::Thor::UnknownArgumentError' => UnknownArgumentError::SpellChecker ) end end PK ]#I`i#i#=gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/group.rbnu[require_relative "base" # Bundler::Thor has a special class called Bundler::Thor::Group. The main difference to Bundler::Thor class # is that it invokes all commands at once. It also include some methods that allows # invocations to be done at the class method, which are not available to Bundler::Thor # commands. class Bundler::Thor::Group class << self # The description for this Bundler::Thor::Group. If none is provided, but a source root # exists, tries to find the USAGE one folder above it, otherwise searches # in the superclass. # # ==== Parameters # description:: The description for this Bundler::Thor::Group. # def desc(description = nil) if description @desc = description else @desc ||= from_superclass(:desc, nil) end end # Prints help information. # # ==== Options # short:: When true, shows only usage. # def help(shell) shell.say "Usage:" shell.say " #{banner}\n" shell.say class_options_help(shell) shell.say desc if desc end # Stores invocations for this class merging with superclass values. # def invocations #:nodoc: @invocations ||= from_superclass(:invocations, {}) end # Stores invocation blocks used on invoke_from_option. # def invocation_blocks #:nodoc: @invocation_blocks ||= from_superclass(:invocation_blocks, {}) end # Invoke the given namespace or class given. It adds an instance # method that will invoke the klass and command. You can give a block to # configure how it will be invoked. # # The namespace/class given will have its options showed on the help # usage. Check invoke_from_option for more information. # def invoke(*names, &block) options = names.last.is_a?(Hash) ? names.pop : {} verbose = options.fetch(:verbose, true) names.each do |name| invocations[name] = false invocation_blocks[name] = block if block_given? class_eval <<-METHOD, __FILE__, __LINE__ + 1 def _invoke_#{name.to_s.gsub(/\W/, '_')} klass, command = self.class.prepare_for_invocation(nil, #{name.inspect}) if klass say_status :invoke, #{name.inspect}, #{verbose.inspect} block = self.class.invocation_blocks[#{name.inspect}] _invoke_for_class_method klass, command, &block else say_status :error, %(#{name.inspect} [not found]), :red end end METHOD end end # Invoke a thor class based on the value supplied by the user to the # given option named "name". A class option must be created before this # method is invoked for each name given. # # ==== Examples # # class GemGenerator < Bundler::Thor::Group # class_option :test_framework, :type => :string # invoke_from_option :test_framework # end # # ==== Boolean options # # In some cases, you want to invoke a thor class if some option is true or # false. This is automatically handled by invoke_from_option. Then the # option name is used to invoke the generator. # # ==== Preparing for invocation # # In some cases you want to customize how a specified hook is going to be # invoked. You can do that by overwriting the class method # prepare_for_invocation. The class method must necessarily return a klass # and an optional command. # # ==== Custom invocations # # You can also supply a block to customize how the option is going to be # invoked. The block receives two parameters, an instance of the current # class and the klass to be invoked. # def invoke_from_option(*names, &block) options = names.last.is_a?(Hash) ? names.pop : {} verbose = options.fetch(:verbose, :white) names.each do |name| unless class_options.key?(name) raise ArgumentError, "You have to define the option #{name.inspect} " \ "before setting invoke_from_option." end invocations[name] = true invocation_blocks[name] = block if block_given? class_eval <<-METHOD, __FILE__, __LINE__ + 1 def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')} return unless options[#{name.inspect}] value = options[#{name.inspect}] value = #{name.inspect} if TrueClass === value klass, command = self.class.prepare_for_invocation(#{name.inspect}, value) if klass say_status :invoke, value, #{verbose.inspect} block = self.class.invocation_blocks[#{name.inspect}] _invoke_for_class_method klass, command, &block else say_status :error, %(\#{value} [not found]), :red end end METHOD end end # Remove a previously added invocation. # # ==== Examples # # remove_invocation :test_framework # def remove_invocation(*names) names.each do |name| remove_command(name) remove_class_option(name) invocations.delete(name) invocation_blocks.delete(name) end end # Overwrite class options help to allow invoked generators options to be # shown recursively when invoking a generator. # def class_options_help(shell, groups = {}) #:nodoc: get_options_from_invocations(groups, class_options) do |klass| klass.send(:get_options_from_invocations, groups, class_options) end super(shell, groups) end # Get invocations array and merge options from invocations. Those # options are added to group_options hash. Options that already exists # in base_options are not added twice. # def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength invocations.each do |name, from_option| value = if from_option option = class_options[name] option.type == :boolean ? name : option.default else name end next unless value klass, _ = prepare_for_invocation(name, value) next unless klass && klass.respond_to?(:class_options) value = value.to_s human_name = value.respond_to?(:classify) ? value.classify : value group_options[human_name] ||= [] group_options[human_name] += klass.class_options.values.select do |class_option| base_options[class_option.name.to_sym].nil? && class_option.group.nil? && !group_options.values.flatten.any? { |i| i.name == class_option.name } end yield klass if block_given? end end # Returns commands ready to be printed. def printable_commands(*) item = [] item << banner item << (desc ? "# #{desc.gsub(/\s+/m, ' ')}" : "") [item] end alias_method :printable_tasks, :printable_commands def handle_argument_error(command, error, _args, arity) #:nodoc: msg = "#{basename} #{command.name} takes #{arity} argument".dup msg << "s" if arity > 1 msg << ", but it should not." raise error, msg end protected # The method responsible for dispatching given the args. def dispatch(command, given_args, given_opts, config) #:nodoc: if Bundler::Thor::HELP_MAPPINGS.include?(given_args.first) help(config[:shell]) return end args, opts = Bundler::Thor::Options.split(given_args) opts = given_opts || opts instance = new(args, opts, config) yield instance if block_given? if command instance.invoke_command(all_commands[command]) else instance.invoke_all end end # The banner for this class. You can customize it if you are invoking the # thor class by another ways which is not the Bundler::Thor::Runner. def banner "#{basename} #{self_command.formatted_usage(self, false)}" end # Represents the whole class as a command. def self_command #:nodoc: Bundler::Thor::DynamicCommand.new(namespace, class_options) end alias_method :self_task, :self_command def baseclass #:nodoc: Bundler::Thor::Group end def create_command(meth) #:nodoc: commands[meth.to_s] = Bundler::Thor::Command.new(meth, nil, nil, nil, nil) true end alias_method :create_task, :create_command end include Bundler::Thor::Base protected # Shortcut to invoke with padding and block handling. Use internally by # invoke and invoke_from_option class methods. def _invoke_for_class_method(klass, command = nil, *args, &block) #:nodoc: with_padding do if block case block.arity when 3 yield(self, klass, command) when 2 yield(self, klass) when 1 instance_exec(klass, &block) end else invoke klass, command, *args end end end end PK ]1UyXXCgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/color.rbnu[require_relative "basic" class Bundler::Thor module Shell # Inherit from Bundler::Thor::Shell::Basic and add set_color behavior. Check # Bundler::Thor::Shell::Basic to see all available methods. # class Color < Basic # Embed in a String to clear all previous ANSI sequences. CLEAR = "\e[0m" # The start of an ANSI bold sequence. BOLD = "\e[1m" # Set the terminal's foreground ANSI color to black. BLACK = "\e[30m" # Set the terminal's foreground ANSI color to red. RED = "\e[31m" # Set the terminal's foreground ANSI color to green. GREEN = "\e[32m" # Set the terminal's foreground ANSI color to yellow. YELLOW = "\e[33m" # Set the terminal's foreground ANSI color to blue. BLUE = "\e[34m" # Set the terminal's foreground ANSI color to magenta. MAGENTA = "\e[35m" # Set the terminal's foreground ANSI color to cyan. CYAN = "\e[36m" # Set the terminal's foreground ANSI color to white. WHITE = "\e[37m" # Set the terminal's background ANSI color to black. ON_BLACK = "\e[40m" # Set the terminal's background ANSI color to red. ON_RED = "\e[41m" # Set the terminal's background ANSI color to green. ON_GREEN = "\e[42m" # Set the terminal's background ANSI color to yellow. ON_YELLOW = "\e[43m" # Set the terminal's background ANSI color to blue. ON_BLUE = "\e[44m" # Set the terminal's background ANSI color to magenta. ON_MAGENTA = "\e[45m" # Set the terminal's background ANSI color to cyan. ON_CYAN = "\e[46m" # Set the terminal's background ANSI color to white. ON_WHITE = "\e[47m" # Set color by using a string or one of the defined constants. If a third # option is set to true, it also adds bold to the string. This is based # on Highline implementation and it automatically appends CLEAR to the end # of the returned String. # # Pass foreground, background and bold options to this method as # symbols. # # Example: # # set_color "Hi!", :red, :on_white, :bold # # The available colors are: # # :bold # :black # :red # :green # :yellow # :blue # :magenta # :cyan # :white # :on_black # :on_red # :on_green # :on_yellow # :on_blue # :on_magenta # :on_cyan # :on_white def set_color(string, *colors) if colors.compact.empty? || !can_display_colors? string elsif colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } ansi_colors = colors.map { |color| lookup_color(color) } "#{ansi_colors.join}#{string}#{CLEAR}" else # The old API was `set_color(color, bold=boolean)`. We # continue to support the old API because you should never # break old APIs unnecessarily :P foreground, bold = colors foreground = self.class.const_get(foreground.to_s.upcase) if foreground.is_a?(Symbol) bold = bold ? BOLD : "" "#{bold}#{foreground}#{string}#{CLEAR}" end end protected def can_display_colors? are_colors_supported? && !are_colors_disabled? end def are_colors_supported? stdout.tty? && ENV["TERM"] != "dumb" end def are_colors_disabled? !ENV['NO_COLOR'].nil? end # Overwrite show_diff to show diff with colors if Diff::LCS is # available. # def show_diff(destination, content) #:nodoc: if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil? actual = File.binread(destination).to_s.split("\n") content = content.to_s.split("\n") Diff::LCS.sdiff(actual, content).each do |diff| output_diff_line(diff) end else super end end def output_diff_line(diff) #:nodoc: case diff.action when "-" say "- #{diff.old_element.chomp}", :red, true when "+" say "+ #{diff.new_element.chomp}", :green, true when "!" say "- #{diff.old_element.chomp}", :red, true say "+ #{diff.new_element.chomp}", :green, true else say " #{diff.old_element.chomp}", nil, true end end # Check if Diff::LCS is loaded. If it is, use it to create pretty output # for diff. # def diff_lcs_loaded? #:nodoc: return true if defined?(Diff::LCS) return @diff_lcs_loaded unless @diff_lcs_loaded.nil? @diff_lcs_loaded = begin require "diff/lcs" true rescue LoadError false end end end end end PK ].Bgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/html.rbnu[require_relative "basic" class Bundler::Thor module Shell # Inherit from Bundler::Thor::Shell::Basic and add set_color behavior. Check # Bundler::Thor::Shell::Basic to see all available methods. # class HTML < Basic # The start of an HTML bold sequence. BOLD = "font-weight: bold" # Set the terminal's foreground HTML color to black. BLACK = "color: black" # Set the terminal's foreground HTML color to red. RED = "color: red" # Set the terminal's foreground HTML color to green. GREEN = "color: green" # Set the terminal's foreground HTML color to yellow. YELLOW = "color: yellow" # Set the terminal's foreground HTML color to blue. BLUE = "color: blue" # Set the terminal's foreground HTML color to magenta. MAGENTA = "color: magenta" # Set the terminal's foreground HTML color to cyan. CYAN = "color: cyan" # Set the terminal's foreground HTML color to white. WHITE = "color: white" # Set the terminal's background HTML color to black. ON_BLACK = "background-color: black" # Set the terminal's background HTML color to red. ON_RED = "background-color: red" # Set the terminal's background HTML color to green. ON_GREEN = "background-color: green" # Set the terminal's background HTML color to yellow. ON_YELLOW = "background-color: yellow" # Set the terminal's background HTML color to blue. ON_BLUE = "background-color: blue" # Set the terminal's background HTML color to magenta. ON_MAGENTA = "background-color: magenta" # Set the terminal's background HTML color to cyan. ON_CYAN = "background-color: cyan" # Set the terminal's background HTML color to white. ON_WHITE = "background-color: white" # Set color by using a string or one of the defined constants. If a third # option is set to true, it also adds bold to the string. This is based # on Highline implementation and it automatically appends CLEAR to the end # of the returned String. # def set_color(string, *colors) if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } html_colors = colors.map { |color| lookup_color(color) } "#{Bundler::Thor::Util.escape_html(string)}" else color, bold = colors html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) styles = [html_color] styles << BOLD if bold "#{Bundler::Thor::Util.escape_html(string)}" end end # Ask something to the user and receives a response. # # ==== Example # ask("What is your name?") # # TODO: Implement #ask for Bundler::Thor::Shell::HTML def ask(statement, color = nil) raise NotImplementedError, "Implement #ask for Bundler::Thor::Shell::HTML" end protected def can_display_colors? true end # Overwrite show_diff to show diff with colors if Diff::LCS is # available. # def show_diff(destination, content) #:nodoc: if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil? actual = File.binread(destination).to_s.split("\n") content = content.to_s.split("\n") Diff::LCS.sdiff(actual, content).each do |diff| output_diff_line(diff) end else super end end def output_diff_line(diff) #:nodoc: case diff.action when "-" say "- #{diff.old_element.chomp}", :red, true when "+" say "+ #{diff.new_element.chomp}", :green, true when "!" say "- #{diff.old_element.chomp}", :red, true say "+ #{diff.new_element.chomp}", :green, true else say " #{diff.old_element.chomp}", nil, true end end # Check if Diff::LCS is loaded. If it is, use it to create pretty output # for diff. # def diff_lcs_loaded? #:nodoc: return true if defined?(Diff::LCS) return @diff_lcs_loaded unless @diff_lcs_loaded.nil? @diff_lcs_loaded = begin require "diff/lcs" true rescue LoadError false end end end end end PK ]699Cgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/basic.rbnu[class Bundler::Thor module Shell class Basic DEFAULT_TERMINAL_WIDTH = 80 attr_accessor :base attr_reader :padding # Initialize base, mute and padding to nil. # def initialize #:nodoc: @base = nil @mute = false @padding = 0 @always_force = false end # Mute everything that's inside given block # def mute @mute = true yield ensure @mute = false end # Check if base is muted # def mute? @mute end # Sets the output padding, not allowing less than zero values. # def padding=(value) @padding = [0, value].max end # Sets the output padding while executing a block and resets it. # def indent(count = 1) orig_padding = padding self.padding = padding + count yield self.padding = orig_padding end # Asks something to the user and receives a response. # # If a default value is specified it will be presented to the user # and allows them to select that value with an empty response. This # option is ignored when limited answers are supplied. # # If asked to limit the correct responses, you can pass in an # array of acceptable answers. If one of those is not supplied, # they will be shown a message stating that one of those answers # must be given and re-asked the question. # # If asking for sensitive information, the :echo option can be set # to false to mask user input from $stdin. # # If the required input is a path, then set the path option to # true. This will enable tab completion for file paths relative # to the current working directory on systems that support # Readline. # # ==== Example # ask("What is your name?") # # ask("What is the planet furthest from the sun?", :default => "Pluto") # # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"]) # # ask("What is your password?", :echo => false) # # ask("Where should the file be saved?", :path => true) # def ask(statement, *args) options = args.last.is_a?(Hash) ? args.pop : {} color = args.first if options[:limited_to] ask_filtered(statement, color, options) else ask_simply(statement, color, options) end end # Say (print) something to the user. If the sentence ends with a whitespace # or tab character, a new line is not appended (print + flush). Otherwise # are passed straight to puts (behavior got from Highline). # # ==== Example # say("I know you knew that.") # def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/)) return if quiet? buffer = prepare_message(message, *color) buffer << "\n" if force_new_line && !message.to_s.end_with?("\n") stdout.print(buffer) stdout.flush end # Say a status with the given color and appends the message. Since this # method is used frequently by actions, it allows nil or false to be given # in log_status, avoiding the message from being shown. If a Symbol is # given in log_status, it's used as the color. # def say_status(status, message, log_status = true) return if quiet? || log_status == false spaces = " " * (padding + 1) color = log_status.is_a?(Symbol) ? log_status : :green status = status.to_s.rjust(12) status = set_color status, color, true if color buffer = "#{status}#{spaces}#{message}" buffer = "#{buffer}\n" unless buffer.end_with?("\n") stdout.print(buffer) stdout.flush end # Make a question the to user and returns true if the user replies "y" or # "yes". # def yes?(statement, color = nil) !!(ask(statement, color, :add_to_history => false) =~ is?(:yes)) end # Make a question the to user and returns true if the user replies "n" or # "no". # def no?(statement, color = nil) !!(ask(statement, color, :add_to_history => false) =~ is?(:no)) end # Prints values in columns # # ==== Parameters # Array[String, String, ...] # def print_in_columns(array) return if array.empty? colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2 array.each_with_index do |value, index| # Don't output trailing spaces when printing the last column if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length stdout.puts value else stdout.printf("%-#{colwidth}s", value) end end end # Prints a table. # # ==== Parameters # Array[Array[String, String, ...]] # # ==== Options # indent:: Indent the first column by indent value. # colwidth:: Force the first column to colwidth spaces wide. # def print_table(array, options = {}) # rubocop:disable MethodLength return if array.empty? formats = [] indent = options[:indent].to_i colwidth = options[:colwidth] options[:truncate] = terminal_width if options[:truncate] == true formats << "%-#{colwidth + 2}s".dup if colwidth start = colwidth ? 1 : 0 colcount = array.max { |a, b| a.size <=> b.size }.size maximas = [] start.upto(colcount - 1) do |index| maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max maximas << maxima formats << if index == colcount - 1 # Don't output 2 trailing spaces when printing the last column "%-s".dup else "%-#{maxima + 2}s".dup end end formats[0] = formats[0].insert(0, " " * indent) formats << "%s" array.each do |row| sentence = "".dup row.each_with_index do |column, index| maxima = maximas[index] f = if column.is_a?(Numeric) if index == row.size - 1 # Don't output 2 trailing spaces when printing the last column "%#{maxima}s" else "%#{maxima}s " end else formats[index] end sentence << f % column.to_s end sentence = truncate(sentence, options[:truncate]) if options[:truncate] stdout.puts sentence end end # Prints a long string, word-wrapping the text to the current width of the # terminal display. Ideal for printing heredocs. # # ==== Parameters # String # # ==== Options # indent:: Indent each line of the printed paragraph by indent value. # def print_wrapped(message, options = {}) indent = options[:indent] || 0 width = terminal_width - indent paras = message.split("\n\n") paras.map! do |unwrapped| words = unwrapped.split(" ") counter = words.first.length words.inject do |memo, word| word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n") counter = 0 if word.include? "\n" if (counter + word.length + 1) < width memo = "#{memo} #{word}" counter += (word.length + 1) else memo = "#{memo}\n#{word}" counter = word.length end memo end end.compact! paras.each do |para| para.split("\n").each do |line| stdout.puts line.insert(0, " " * indent) end stdout.puts unless para == paras.last end end # Deals with file collision and returns true if the file should be # overwritten and false otherwise. If a block is given, it uses the block # response as the content for the diff. # # ==== Parameters # destination:: the destination file to solve conflicts # block:: an optional block that returns the value to be used in diff and merge # def file_collision(destination) return true if @always_force options = block_given? ? "[Ynaqdhm]" : "[Ynaqh]" loop do answer = ask( %[Overwrite #{destination}? (enter "h" for help) #{options}], :add_to_history => false ) case answer when nil say "" return true when is?(:yes), is?(:force), "" return true when is?(:no), is?(:skip) return false when is?(:always) return @always_force = true when is?(:quit) say "Aborting..." raise SystemExit when is?(:diff) show_diff(destination, yield) if block_given? say "Retrying..." when is?(:merge) if block_given? && !merge_tool.empty? merge(destination, yield) return nil end say "Please specify merge tool to `THOR_MERGE` env." else say file_collision_help end end end # This code was copied from Rake, available under MIT-LICENSE # Copyright (c) 2003, 2004 Jim Weirich def terminal_width result = if ENV["THOR_COLUMNS"] ENV["THOR_COLUMNS"].to_i else unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH end result < 10 ? DEFAULT_TERMINAL_WIDTH : result rescue DEFAULT_TERMINAL_WIDTH end # Called if something goes wrong during the execution. This is used by Bundler::Thor # internally and should not be used inside your scripts. If something went # wrong, you can always raise an exception. If you raise a Bundler::Thor::Error, it # will be rescued and wrapped in the method below. # def error(statement) stderr.puts statement end # Apply color to the given string with optional bold. Disabled in the # Bundler::Thor::Shell::Basic class. # def set_color(string, *) #:nodoc: string end protected def prepare_message(message, *color) spaces = " " * padding spaces + set_color(message.to_s, *color) end def can_display_colors? false end def lookup_color(color) return color unless color.is_a?(Symbol) self.class.const_get(color.to_s.upcase) end def stdout $stdout end def stderr $stderr end def is?(value) #:nodoc: value = value.to_s if value.size == 1 /\A#{value}\z/i else /\A(#{value}|#{value[0, 1]})\z/i end end def file_collision_help #:nodoc: <<-HELP Y - yes, overwrite n - no, do not overwrite a - all, overwrite this and all others q - quit, abort d - diff, show the differences between the old and the new h - help, show this help m - merge, run merge tool HELP end def show_diff(destination, content) #:nodoc: diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u" require "tempfile" Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp| temp.write content temp.rewind system %(#{diff_cmd} "#{destination}" "#{temp.path}") end end def quiet? #:nodoc: mute? || (base && base.options[:quiet]) end # Calculate the dynamic width of the terminal def dynamic_width @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput) end def dynamic_width_stty `stty size 2>/dev/null`.split[1].to_i end def dynamic_width_tput `tput cols 2>/dev/null`.to_i end def unix? RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i end def truncate(string, width) as_unicode do chars = string.chars.to_a if chars.length <= width chars.join else chars[0, width - 3].join + "..." end end end if "".respond_to?(:encode) def as_unicode yield end else def as_unicode old = $KCODE $KCODE = "U" yield ensure $KCODE = old end end def ask_simply(statement, color, options) default = options[:default] message = [statement, ("(#{default})" if default), nil].uniq.join(" ") message = prepare_message(message, *color) result = Bundler::Thor::LineEditor.readline(message, options) return unless result result = result.strip if default && result == "" default else result end end def ask_filtered(statement, color, options) answer_set = options[:limited_to] case_insensitive = options.fetch(:case_insensitive, false) correct_answer = nil until correct_answer answers = answer_set.join(", ") answer = ask_simply("#{statement} [#{answers}]", color, options) correct_answer = answer_match(answer_set, answer, case_insensitive) say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer end correct_answer end def answer_match(possibilities, answer, case_insensitive) if case_insensitive possibilities.detect{ |possibility| possibility.downcase == answer.downcase } else possibilities.detect{ |possibility| possibility == answer } end end def merge(destination, content) #:nodoc: require "tempfile" Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp| temp.write content temp.rewind system %(#{merge_tool} "#{temp.path}" "#{destination}") end end def merge_tool #:nodoc: @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool end def git_merge_tool #:nodoc: `git config merge.tool`.rstrip rescue "" end end end end PK ];?gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/command.rbnu[class Bundler::Thor class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name) FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/ def initialize(name, description, long_description, usage, options = nil) super(name.to_s, description, long_description, usage, options || {}) end def initialize_copy(other) #:nodoc: super(other) self.options = other.options.dup if other.options end def hidden? false end # By default, a command invokes a method in the thor class. You can change this # implementation to create custom commands. def run(instance, args = []) arity = nil if private_method?(instance) instance.class.handle_no_command_error(name) elsif public_method?(instance) arity = instance.method(name).arity instance.__send__(name, *args) elsif local_method?(instance, :method_missing) instance.__send__(:method_missing, name.to_sym, *args) else instance.class.handle_no_command_error(name) end rescue ArgumentError => e handle_argument_error?(instance, e, caller) ? instance.class.handle_argument_error(self, e, args, arity) : (raise e) rescue NoMethodError => e handle_no_method_error?(instance, e, caller) ? instance.class.handle_no_command_error(name) : (raise e) end # Returns the formatted usage by injecting given required arguments # and required options into the given usage. def formatted_usage(klass, namespace = true, subcommand = false) if ancestor_name formatted = "#{ancestor_name} ".dup # add space elsif namespace namespace = klass.namespace formatted = "#{namespace.gsub(/^(default)/, '')}:".dup end formatted ||= "#{klass.namespace.split(':').last} ".dup if subcommand formatted ||= "".dup Array(usage).map do |specific_usage| formatted_specific_usage = formatted formatted_specific_usage += required_arguments_for(klass, specific_usage) # Add required options formatted_specific_usage += " #{required_options}" # Strip and go! formatted_specific_usage.strip end.join("\n") end protected # Add usage with required arguments def required_arguments_for(klass, usage) if klass && !klass.arguments.empty? usage.to_s.gsub(/^#{name}/) do |match| match << " " << klass.arguments.map(&:usage).compact.join(" ") end else usage.to_s end end def not_debugging?(instance) !(instance.class.respond_to?(:debugging) && instance.class.debugging) end def required_options @required_options ||= options.map { |_, o| o.usage if o.required? }.compact.sort.join(" ") end # Given a target, checks if this class name is a public method. def public_method?(instance) #:nodoc: !(instance.public_methods & [name.to_s, name.to_sym]).empty? end def private_method?(instance) !(instance.private_methods & [name.to_s, name.to_sym]).empty? end def local_method?(instance, name) methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false) !(methods & [name.to_s, name.to_sym]).empty? end def sans_backtrace(backtrace, caller) #:nodoc: saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) || (frame =~ %r{^kernel/} && RUBY_ENGINE =~ /rbx/) } saned - caller end def handle_argument_error?(instance, error, caller) not_debugging?(instance) && (error.message =~ /wrong number of arguments/ || error.message =~ /given \d*, expected \d*/) && begin saned = sans_backtrace(error.backtrace, caller) saned.empty? || saned.size == 1 end end def handle_no_method_error?(instance, error, caller) not_debugging?(instance) && error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ end end Task = Command # A command that is hidden in help messages but still invocable. class HiddenCommand < Command def hidden? true end end HiddenTask = HiddenCommand # A dynamic command that handles method missing scenarios. class DynamicCommand < Command def initialize(name, options = nil) super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options) end def run(instance, args = []) if (instance.methods & [name.to_s, name.to_sym]).empty? super else instance.class.handle_no_command_error(name) end end end DynamicTask = DynamicCommand end PK ]ᡇ++Fgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/nested_context.rbnu[class Bundler::Thor class NestedContext def initialize @depth = 0 end def enter push yield ensure pop end def entered? @depth > 0 end private def push @depth += 1 end def pop @depth -= 1 end end end PK ]_-[IIBgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/invocation.rbnu[class Bundler::Thor module Invocation def self.included(base) #:nodoc: super(base) base.extend ClassMethods end module ClassMethods # This method is responsible for receiving a name and find the proper # class and command for it. The key is an optional parameter which is # available only in class methods invocations (i.e. in Bundler::Thor::Group). def prepare_for_invocation(key, name) #:nodoc: case name when Symbol, String Bundler::Thor::Util.find_class_and_command_by_namespace(name.to_s, !key) else name end end end # Make initializer aware of invocations and the initialization args. def initialize(args = [], options = {}, config = {}, &block) #:nodoc: @_invocations = config[:invocations] || Hash.new { |h, k| h[k] = [] } @_initializer = [args, options, config] super end # Make the current command chain accessible with in a Bundler::Thor-(sub)command def current_command_chain @_invocations.values.flatten.map(&:to_sym) end # Receives a name and invokes it. The name can be a string (either "command" or # "namespace:command"), a Bundler::Thor::Command, a Class or a Bundler::Thor instance. If the # command cannot be guessed by name, it can also be supplied as second argument. # # You can also supply the arguments, options and configuration values for # the command to be invoked, if none is given, the same values used to # initialize the invoker are used to initialize the invoked. # # When no name is given, it will invoke the default command of the current class. # # ==== Examples # # class A < Bundler::Thor # def foo # invoke :bar # invoke "b:hello", ["Erik"] # end # # def bar # invoke "b:hello", ["Erik"] # end # end # # class B < Bundler::Thor # def hello(name) # puts "hello #{name}" # end # end # # You can notice that the method "foo" above invokes two commands: "bar", # which belongs to the same class and "hello" which belongs to the class B. # # By using an invocation system you ensure that a command is invoked only once. # In the example above, invoking "foo" will invoke "b:hello" just once, even # if it's invoked later by "bar" method. # # When class A invokes class B, all arguments used on A initialization are # supplied to B. This allows lazy parse of options. Let's suppose you have # some rspec commands: # # class Rspec < Bundler::Thor::Group # class_option :mock_framework, :type => :string, :default => :rr # # def invoke_mock_framework # invoke "rspec:#{options[:mock_framework]}" # end # end # # As you noticed, it invokes the given mock framework, which might have its # own options: # # class Rspec::RR < Bundler::Thor::Group # class_option :style, :type => :string, :default => :mock # end # # Since it's not rspec concern to parse mock framework options, when RR # is invoked all options are parsed again, so RR can extract only the options # that it's going to use. # # If you want Rspec::RR to be initialized with its own set of options, you # have to do that explicitly: # # invoke "rspec:rr", [], :style => :foo # # Besides giving an instance, you can also give a class to invoke: # # invoke Rspec::RR, [], :style => :foo # def invoke(name = nil, *args) if name.nil? warn "[Bundler::Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}" return invoke_all end args.unshift(nil) if args.first.is_a?(Array) || args.first.nil? command, args, opts, config = args klass, command = _retrieve_class_and_command(name, command) raise "Missing Bundler::Thor class for invoke #{name}" unless klass raise "Expected Bundler::Thor class, got #{klass}" unless klass <= Bundler::Thor::Base args, opts, config = _parse_initialization_options(args, opts, config) klass.send(:dispatch, command, args, opts, config) do |instance| instance.parent_options = options end end # Invoke the given command if the given args. def invoke_command(command, *args) #:nodoc: current = @_invocations[self.class] unless current.include?(command.name) current << command.name command.run(self, *args) end end alias_method :invoke_task, :invoke_command # Invoke all commands for the current instance. def invoke_all #:nodoc: self.class.all_commands.map { |_, command| invoke_command(command) } end # Invokes using shell padding. def invoke_with_padding(*args) with_padding { invoke(*args) } end protected # Configuration values that are shared between invocations. def _shared_configuration #:nodoc: {:invocations => @_invocations} end # This method simply retrieves the class and command to be invoked. # If the name is nil or the given name is a command in the current class, # use the given name and return self as class. Otherwise, call # prepare_for_invocation in the current class. def _retrieve_class_and_command(name, sent_command = nil) #:nodoc: if name.nil? [self.class, nil] elsif self.class.all_commands[name.to_s] [self.class, name.to_s] else klass, command = self.class.prepare_for_invocation(nil, name) [klass, command || sent_command] end end alias_method :_retrieve_class_and_task, :_retrieve_class_and_command # Initialize klass using values stored in the @_initializer. def _parse_initialization_options(args, opts, config) #:nodoc: stored_args, stored_opts, stored_config = @_initializer args ||= stored_args.dup opts ||= stored_opts.dup config ||= {} config = stored_config.merge(_shared_configuration).merge!(config) [args, opts, config] end end end PK ]5,,?gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/version.rbnu[class Bundler::Thor VERSION = "1.1.0" end PK ]8]gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rbnu[class Bundler::Thor module CoreExt #:nodoc: # A hash with indifferent access and magic predicates. # # hash = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true # # hash[:foo] #=> 'bar' # hash['foo'] #=> 'bar' # hash.foo? #=> true # class HashWithIndifferentAccess < ::Hash #:nodoc: def initialize(hash = {}) super() hash.each do |key, value| self[convert_key(key)] = value end end def [](key) super(convert_key(key)) end def []=(key, value) super(convert_key(key), value) end def delete(key) super(convert_key(key)) end def fetch(key, *args) super(convert_key(key), *args) end def key?(key) super(convert_key(key)) end def values_at(*indices) indices.map { |key| self[convert_key(key)] } end def merge(other) dup.merge!(other) end def merge!(other) other.each do |key, value| self[convert_key(key)] = value end self end def reverse_merge(other) self.class.new(other).merge(self) end def reverse_merge!(other_hash) replace(reverse_merge(other_hash)) end def replace(other_hash) super(other_hash) end # Convert to a Hash with String keys. def to_hash Hash.new(default).merge!(self) end protected def convert_key(key) key.is_a?(Symbol) ? key.to_s : key end # Magic predicates. For instance: # # options.force? # => !!options['force'] # options.shebang # => "/usr/lib/local/ruby" # options.test_framework?(:rspec) # => options[:test_framework] == :rspec # def method_missing(method, *args) method = method.to_s if method =~ /^(\w+)\?$/ if args.empty? !!self[$1] else self[$1] == args.first end else self[method] end end end end end PK ]dq=77Lgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rbnu[class Bundler::Thor module LineEditor class Readline < Basic def self.available? begin require "readline" rescue LoadError end Object.const_defined?(:Readline) end def readline if echo? ::Readline.completion_append_character = nil # rb-readline does not allow Readline.completion_proc= to receive nil. if complete = completion_proc ::Readline.completion_proc = complete end ::Readline.readline(prompt, add_to_history?) else super end end private def add_to_history? options.fetch(:add_to_history, true) end def completion_proc if use_path_completion? proc { |text| PathCompletion.new(text).matches } elsif completion_options.any? proc do |text| completion_options.select { |option| option.start_with?(text) } end end end def completion_options options.fetch(:limited_to, []) end def use_path_completion? options.fetch(:path, false) end class PathCompletion attr_reader :text private :text def initialize(text) @text = text end def matches relative_matches end private def relative_matches absolute_matches.map { |path| path.sub(base_path, "") } end def absolute_matches Dir[glob_pattern].map do |path| if File.directory?(path) "#{path}/" else path end end end def glob_pattern "#{base_path}#{text}*" end def base_path "#{Dir.pwd}/" end end end end end PK ]Yt}}Igems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rbnu[class Bundler::Thor module LineEditor class Basic attr_reader :prompt, :options def self.available? true end def initialize(prompt, options) @prompt = prompt @options = options end def readline $stdout.print(prompt) get_input end private def get_input if echo? $stdin.gets else # Lazy-load io/console since it is gem-ified as of 2.3 require "io/console" $stdin.noecho(&:gets) end end def echo? options.fetch(:echo, true) end end end end PK ]))?gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions.rbnu[require_relative "actions/create_file" require_relative "actions/create_link" require_relative "actions/directory" require_relative "actions/empty_directory" require_relative "actions/file_manipulation" require_relative "actions/inject_into_file" class Bundler::Thor module Actions attr_accessor :behavior def self.included(base) #:nodoc: super(base) base.extend ClassMethods end module ClassMethods # Hold source paths for one Bundler::Thor instance. source_paths_for_search is the # method responsible to gather source_paths from this current class, # inherited paths and the source root. # def source_paths @_source_paths ||= [] end # Stores and return the source root for this class def source_root(path = nil) @_source_root = path if path @_source_root ||= nil end # Returns the source paths in the following order: # # 1) This class source paths # 2) Source root # 3) Parents source paths # def source_paths_for_search paths = [] paths += source_paths paths << source_root if source_root paths += from_superclass(:source_paths, []) paths end # Add runtime options that help actions execution. # def add_runtime_options! class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime, :desc => "Overwrite files that already exist" class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime, :desc => "Run but do not make any changes" class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime, :desc => "Suppress status output" class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime, :desc => "Skip files that already exist" end end # Extends initializer to add more configuration options. # # ==== Configuration # behavior:: The actions default behavior. Can be :invoke or :revoke. # It also accepts :force, :skip and :pretend to set the behavior # and the respective option. # # destination_root:: The root directory needed for some actions. # def initialize(args = [], options = {}, config = {}) self.behavior = case config[:behavior].to_s when "force", "skip" _cleanup_options_and_set(options, config[:behavior]) :invoke when "revoke" :revoke else :invoke end super self.destination_root = config[:destination_root] end # Wraps an action object and call it accordingly to the thor class behavior. # def action(instance) #:nodoc: if behavior == :revoke instance.revoke! else instance.invoke! end end # Returns the root for this thor class (also aliased as destination root). # def destination_root @destination_stack.last end # Sets the root for this thor class. Relatives path are added to the # directory where the script was invoked and expanded. # def destination_root=(root) @destination_stack ||= [] @destination_stack[0] = File.expand_path(root || "") end # Returns the given path relative to the absolute root (ie, root where # the script started). # def relative_to_original_destination_root(path, remove_dot = true) root = @destination_stack[0] if path.start_with?(root) && [File::SEPARATOR, File::ALT_SEPARATOR, nil, ''].include?(path[root.size..root.size]) path = path.dup path[0...root.size] = '.' remove_dot ? (path[2..-1] || "") : path else path end end # Holds source paths in instance so they can be manipulated. # def source_paths @source_paths ||= self.class.source_paths_for_search end # Receives a file or directory and search for it in the source paths. # def find_in_source_paths(file) possible_files = [file, file + TEMPLATE_EXTNAME] relative_root = relative_to_original_destination_root(destination_root, false) source_paths.each do |source| possible_files.each do |f| source_file = File.expand_path(f, File.join(source, relative_root)) return source_file if File.exist?(source_file) end end message = "Could not find #{file.inspect} in any of your source paths. ".dup unless self.class.source_root message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. " end message << if source_paths.empty? "Currently you have no source paths." else "Your current source paths are: \n#{source_paths.join("\n")}" end raise Error, message end # Do something in the root or on a provided subfolder. If a relative path # is given it's referenced from the current root. The full path is yielded # to the block you provide. The path is set back to the previous path when # the method exits. # # ==== Parameters # dir:: the directory to move to. # config:: give :verbose => true to log and use padding. # def inside(dir = "", config = {}, &block) verbose = config.fetch(:verbose, false) pretend = options[:pretend] say_status :inside, dir, verbose shell.padding += 1 if verbose @destination_stack.push File.expand_path(dir, destination_root) # If the directory doesnt exist and we're not pretending if !File.exist?(destination_root) && !pretend require "fileutils" FileUtils.mkdir_p(destination_root) end if pretend # In pretend mode, just yield down to the block block.arity == 1 ? yield(destination_root) : yield else require "fileutils" FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield } end @destination_stack.pop shell.padding -= 1 if verbose end # Goes to the root and execute the given block. # def in_root inside(@destination_stack.first) { yield } end # Loads an external file and execute it in the instance binding. # # ==== Parameters # path:: The path to the file to execute. Can be a web address or # a relative path from the source root. # # ==== Examples # # apply "http://gist.github.com/103208" # # apply "recipes/jquery.rb" # def apply(path, config = {}) verbose = config.fetch(:verbose, true) is_uri = path =~ %r{^https?\://} path = find_in_source_paths(path) unless is_uri say_status :apply, path, verbose shell.padding += 1 if verbose contents = if is_uri require "open-uri" URI.open(path, "Accept" => "application/x-thor-template", &:read) else open(path, &:read) end instance_eval(contents, path) shell.padding -= 1 if verbose end # Executes a command returning the contents of the command. # # ==== Parameters # command:: the command to be executed. # config:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with # to append an executable to command execution. # # ==== Example # # inside('vendor') do # run('ln -s ~/edge rails') # end # def run(command, config = {}) return unless behavior == :invoke destination = relative_to_original_destination_root(destination_root, false) desc = "#{command} from #{destination.inspect}" if config[:with] desc = "#{File.basename(config[:with].to_s)} #{desc}" command = "#{config[:with]} #{command}" end say_status :run, desc, config.fetch(:verbose, true) return if options[:pretend] env_splat = [config[:env]] if config[:env] if config[:capture] require "open3" result, status = Open3.capture2e(*env_splat, command.to_s) success = status.success? else result = system(*env_splat, command.to_s) success = result end abort if !success && config.fetch(:abort_on_failure, self.class.exit_on_failure?) result end # Executes a ruby script (taking into account WIN32 platform quirks). # # ==== Parameters # command:: the command to be executed. # config:: give :verbose => false to not log the status. # def run_ruby_script(command, config = {}) return unless behavior == :invoke run command, config.merge(:with => Bundler::Thor::Util.ruby_command) end # Run a thor command. A hash of options can be given and it's converted to # switches. # # ==== Parameters # command:: the command to be invoked # args:: arguments to the command # config:: give :verbose => false to not log the status, :capture => true to hide to output. # Other options are given as parameter to Bundler::Thor. # # # ==== Examples # # thor :install, "http://gist.github.com/103208" # #=> thor install http://gist.github.com/103208 # # thor :list, :all => true, :substring => 'rails' # #=> thor list --all --substring=rails # def thor(command, *args) config = args.last.is_a?(Hash) ? args.pop : {} verbose = config.key?(:verbose) ? config.delete(:verbose) : true pretend = config.key?(:pretend) ? config.delete(:pretend) : false capture = config.key?(:capture) ? config.delete(:capture) : false args.unshift(command) args.push Bundler::Thor::Options.to_switches(config) command = args.join(" ").strip run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture end protected # Allow current root to be shared between invocations. # def _shared_configuration #:nodoc: super.merge!(:destination_root => destination_root) end def _cleanup_options_and_set(options, key) #:nodoc: case options when Array %w(--force -f --skip -s).each { |i| options.delete(i) } options << "--#{key}" when Hash [:force, :skip, "force", "skip"].each { |i| options.delete(i) } options.merge!(key => true) end end end end PK ]``<gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/base.rbnu[require_relative "command" require_relative "core_ext/hash_with_indifferent_access" require_relative "error" require_relative "invocation" require_relative "nested_context" require_relative "parser" require_relative "shell" require_relative "line_editor" require_relative "util" class Bundler::Thor autoload :Actions, File.expand_path("actions", __dir__) autoload :RakeCompat, File.expand_path("rake_compat", __dir__) autoload :Group, File.expand_path("group", __dir__) # Shortcuts for help. HELP_MAPPINGS = %w(-h -? --help -D) # Bundler::Thor methods that should not be overwritten by the user. THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root action add_file create_file in_root inside run run_ruby_script) TEMPLATE_EXTNAME = ".tt" class << self def deprecation_warning(message) #:nodoc: unless ENV['THOR_SILENCE_DEPRECATION'] warn "Deprecation warning: #{message}\n" + 'You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.' end end end module Base attr_accessor :options, :parent_options, :args # It receives arguments in an Array and two hashes, one for options and # other for configuration. # # Notice that it does not check if all required arguments were supplied. # It should be done by the parser. # # ==== Parameters # args:: An array of objects. The objects are applied to their # respective accessors declared with argument. # # options:: An options hash that will be available as self.options. # The hash given is converted to a hash with indifferent # access, magic predicates (options.skip?) and then frozen. # # config:: Configuration for this Bundler::Thor class. # def initialize(args = [], local_options = {}, config = {}) parse_options = self.class.class_options # The start method splits inbound arguments at the first argument # that looks like an option (starts with - or --). It then calls # new, passing in the two halves of the arguments Array as the # first two parameters. command_options = config.delete(:command_options) # hook for start parse_options = parse_options.merge(command_options) if command_options if local_options.is_a?(Array) array_options = local_options hash_options = {} else # Handle the case where the class was explicitly instantiated # with pre-parsed options. array_options = [] hash_options = local_options end # Let Bundler::Thor::Options parse the options first, so it can remove # declared options from the array. This will leave us with # a list of arguments that weren't declared. stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command] disable_required_check = self.class.disable_required_check? config[:current_command] opts = Bundler::Thor::Options.new(parse_options, hash_options, stop_on_unknown, disable_required_check) self.options = opts.parse(array_options) self.options = config[:class_options].merge(options) if config[:class_options] # If unknown options are disallowed, make sure that none of the # remaining arguments looks like an option. opts.check_unknown! if self.class.check_unknown_options?(config) # Add the remaining arguments from the options parser to the # arguments passed in to initialize. Then remove any positional # arguments declared using #argument (this is primarily used # by Bundler::Thor::Group). Tis will leave us with the remaining # positional arguments. to_parse = args to_parse += opts.remaining unless self.class.strict_args_position?(config) thor_args = Bundler::Thor::Arguments.new(self.class.arguments) thor_args.parse(to_parse).each { |k, v| __send__("#{k}=", v) } @args = thor_args.remaining end class << self def included(base) #:nodoc: super(base) base.extend ClassMethods base.send :include, Invocation base.send :include, Shell end # Returns the classes that inherits from Bundler::Thor or Bundler::Thor::Group. # # ==== Returns # Array[Class] # def subclasses @subclasses ||= [] end # Returns the files where the subclasses are kept. # # ==== Returns # Hash[path => Class] # def subclass_files @subclass_files ||= Hash.new { |h, k| h[k] = [] } end # Whenever a class inherits from Bundler::Thor or Bundler::Thor::Group, we should track the # class and the file on Bundler::Thor::Base. This is the method responsible for it. # def register_klass_file(klass) #:nodoc: file = caller[1].match(/(.*):\d+/)[1] Bundler::Thor::Base.subclasses << klass unless Bundler::Thor::Base.subclasses.include?(klass) file_subclasses = Bundler::Thor::Base.subclass_files[File.expand_path(file)] file_subclasses << klass unless file_subclasses.include?(klass) end end module ClassMethods def attr_reader(*) #:nodoc: no_commands { super } end def attr_writer(*) #:nodoc: no_commands { super } end def attr_accessor(*) #:nodoc: no_commands { super } end # If you want to raise an error for unknown options, call check_unknown_options! # This is disabled by default to allow dynamic invocations. def check_unknown_options! @check_unknown_options = true end def check_unknown_options #:nodoc: @check_unknown_options ||= from_superclass(:check_unknown_options, false) end def check_unknown_options?(config) #:nodoc: !!check_unknown_options end # If you want to raise an error when the default value of an option does not match # the type call check_default_type! # This will be the default; for compatibility a deprecation warning is issued if necessary. def check_default_type! @check_default_type = true end # If you want to use defaults that don't match the type of an option, # either specify `check_default_type: false` or call `allow_incompatible_default_type!` def allow_incompatible_default_type! @check_default_type = false end def check_default_type #:nodoc: @check_default_type = from_superclass(:check_default_type, nil) unless defined?(@check_default_type) @check_default_type end # If true, option parsing is suspended as soon as an unknown option or a # regular argument is encountered. All remaining arguments are passed to # the command as regular arguments. def stop_on_unknown_option?(command_name) #:nodoc: false end # If true, option set will not suspend the execution of the command when # a required option is not provided. def disable_required_check?(command_name) #:nodoc: false end # If you want only strict string args (useful when cascading thor classes), # call strict_args_position! This is disabled by default to allow dynamic # invocations. def strict_args_position! @strict_args_position = true end def strict_args_position #:nodoc: @strict_args_position ||= from_superclass(:strict_args_position, false) end def strict_args_position?(config) #:nodoc: !!strict_args_position end # Adds an argument to the class and creates an attr_accessor for it. # # Arguments are different from options in several aspects. The first one # is how they are parsed from the command line, arguments are retrieved # from position: # # thor command NAME # # Instead of: # # thor command --name=NAME # # Besides, arguments are used inside your code as an accessor (self.argument), # while options are all kept in a hash (self.options). # # Finally, arguments cannot have type :default or :boolean but can be # optional (supplying :optional => :true or :required => false), although # you cannot have a required argument after a non-required argument. If you # try it, an error is raised. # # ==== Parameters # name:: The name of the argument. # options:: Described below. # # ==== Options # :desc - Description for the argument. # :required - If the argument is required or not. # :optional - If the argument is optional or not. # :type - The type of the argument, can be :string, :hash, :array, :numeric. # :default - Default value for this argument. It cannot be required and have default values. # :banner - String to show on usage notes. # # ==== Errors # ArgumentError:: Raised if you supply a required argument after a non required one. # def argument(name, options = {}) is_thor_reserved_word?(name, :argument) no_commands { attr_accessor name } required = if options.key?(:optional) !options[:optional] elsif options.key?(:required) options[:required] else options[:default].nil? end remove_argument name if required arguments.each do |argument| next if argument.required? raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " \ "the non-required argument #{argument.human_name.inspect}." end end options[:required] = required arguments << Bundler::Thor::Argument.new(name, options) end # Returns this class arguments, looking up in the ancestors chain. # # ==== Returns # Array[Bundler::Thor::Argument] # def arguments @arguments ||= from_superclass(:arguments, []) end # Adds a bunch of options to the set of class options. # # class_options :foo => false, :bar => :required, :baz => :string # # If you prefer more detailed declaration, check class_option. # # ==== Parameters # Hash[Symbol => Object] # def class_options(options = nil) @class_options ||= from_superclass(:class_options, {}) build_options(options, @class_options) if options @class_options end # Adds an option to the set of class options # # ==== Parameters # name:: The name of the argument. # options:: Described below. # # ==== Options # :desc:: -- Description for the argument. # :required:: -- If the argument is required or not. # :default:: -- Default value for this argument. # :group:: -- The group for this options. Use by class options to output options in different levels. # :aliases:: -- Aliases for this option. Note: Bundler::Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead. # :type:: -- The type of the argument, can be :string, :hash, :array, :numeric or :boolean. # :banner:: -- String to show on usage notes. # :hide:: -- If you want to hide this option from the help. # def class_option(name, options = {}) build_option(name, options, class_options) end # Removes a previous defined argument. If :undefine is given, undefine # accessors as well. # # ==== Parameters # names:: Arguments to be removed # # ==== Examples # # remove_argument :foo # remove_argument :foo, :bar, :baz, :undefine => true # def remove_argument(*names) options = names.last.is_a?(Hash) ? names.pop : {} names.each do |name| arguments.delete_if { |a| a.name == name.to_s } undef_method name, "#{name}=" if options[:undefine] end end # Removes a previous defined class option. # # ==== Parameters # names:: Class options to be removed # # ==== Examples # # remove_class_option :foo # remove_class_option :foo, :bar, :baz # def remove_class_option(*names) names.each do |name| class_options.delete(name) end end # Defines the group. This is used when thor list is invoked so you can specify # that only commands from a pre-defined group will be shown. Defaults to standard. # # ==== Parameters # name # def group(name = nil) if name @group = name.to_s else @group ||= from_superclass(:group, "standard") end end # Returns the commands for this Bundler::Thor class. # # ==== Returns # Hash:: An ordered hash with commands names as keys and Bundler::Thor::Command # objects as values. # def commands @commands ||= Hash.new end alias_method :tasks, :commands # Returns the commands for this Bundler::Thor class and all subclasses. # # ==== Returns # Hash:: An ordered hash with commands names as keys and Bundler::Thor::Command # objects as values. # def all_commands @all_commands ||= from_superclass(:all_commands, Hash.new) @all_commands.merge!(commands) end alias_method :all_tasks, :all_commands # Removes a given command from this Bundler::Thor class. This is usually done if you # are inheriting from another class and don't want it to be available # anymore. # # By default it only remove the mapping to the command. But you can supply # :undefine => true to undefine the method from the class as well. # # ==== Parameters # name:: The name of the command to be removed # options:: You can give :undefine => true if you want commands the method # to be undefined from the class as well. # def remove_command(*names) options = names.last.is_a?(Hash) ? names.pop : {} names.each do |name| commands.delete(name.to_s) all_commands.delete(name.to_s) undef_method name if options[:undefine] end end alias_method :remove_task, :remove_command # All methods defined inside the given block are not added as commands. # # So you can do: # # class MyScript < Bundler::Thor # no_commands do # def this_is_not_a_command # end # end # end # # You can also add the method and remove it from the command list: # # class MyScript < Bundler::Thor # def this_is_not_a_command # end # remove_command :this_is_not_a_command # end # def no_commands(&block) no_commands_context.enter(&block) end alias_method :no_tasks, :no_commands def no_commands_context @no_commands_context ||= NestedContext.new end def no_commands? no_commands_context.entered? end # Sets the namespace for the Bundler::Thor or Bundler::Thor::Group class. By default the # namespace is retrieved from the class name. If your Bundler::Thor class is named # Scripts::MyScript, the help method, for example, will be called as: # # thor scripts:my_script -h # # If you change the namespace: # # namespace :my_scripts # # You change how your commands are invoked: # # thor my_scripts -h # # Finally, if you change your namespace to default: # # namespace :default # # Your commands can be invoked with a shortcut. Instead of: # # thor :my_command # def namespace(name = nil) if name @namespace = name.to_s else @namespace ||= Bundler::Thor::Util.namespace_from_thor_class(self) end end # Parses the command and options from the given args, instantiate the class # and invoke the command. This method is used when the arguments must be parsed # from an array. If you are inside Ruby and want to use a Bundler::Thor class, you # can simply initialize it: # # script = MyScript.new(args, options, config) # script.invoke(:command, first_arg, second_arg, third_arg) # def start(given_args = ARGV, config = {}) config[:shell] ||= Bundler::Thor::Base.shell.new dispatch(nil, given_args.dup, nil, config) rescue Bundler::Thor::Error => e config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message) exit(false) if exit_on_failure? rescue Errno::EPIPE # This happens if a thor command is piped to something like `head`, # which closes the pipe when it's done reading. This will also # mean that if the pipe is closed, further unnecessary # computation will not occur. exit(true) end # Allows to use private methods from parent in child classes as commands. # # ==== Parameters # names:: Method names to be used as commands # # ==== Examples # # public_command :foo # public_command :foo, :bar, :baz # def public_command(*names) names.each do |name| class_eval "def #{name}(*); super end" end end alias_method :public_task, :public_command def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc: raise UndefinedCommandError.new(command, all_commands.keys, (namespace if has_namespace)) end alias_method :handle_no_task_error, :handle_no_command_error def handle_argument_error(command, error, args, arity) #:nodoc: name = [command.ancestor_name, command.name].compact.join(" ") msg = "ERROR: \"#{basename} #{name}\" was called with ".dup msg << "no arguments" if args.empty? msg << "arguments " << args.inspect unless args.empty? msg << "\nUsage: \"#{banner(command).split("\n").join("\"\n \"")}\"" raise InvocationError, msg end # A flag that makes the process exit with status 1 if any error happens. def exit_on_failure? Bundler::Thor.deprecation_warning "Bundler::Thor exit with status 0 on errors. To keep this behavior, you must define `exit_on_failure?` in `#{self.name}`" false end protected # Prints the class options per group. If an option does not belong to # any group, it's printed as Class option. # def class_options_help(shell, groups = {}) #:nodoc: # Group options by group class_options.each do |_, value| groups[value.group] ||= [] groups[value.group] << value end # Deal with default group global_options = groups.delete(nil) || [] print_options(shell, global_options) # Print all others groups.each do |group_name, options| print_options(shell, options, group_name) end end # Receives a set of options and print them. def print_options(shell, options, group_name = nil) return if options.empty? list = [] padding = options.map { |o| o.aliases.size }.max.to_i * 4 options.each do |option| next if option.hide item = [option.usage(padding)] item.push(option.description ? "# #{option.description}" : "") list << item list << ["", "# Default: #{option.default}"] if option.show_default? list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum end shell.say(group_name ? "#{group_name} options:" : "Options:") shell.print_table(list, :indent => 2) shell.say "" end # Raises an error if the word given is a Bundler::Thor reserved word. def is_thor_reserved_word?(word, type) #:nodoc: return false unless THOR_RESERVED_WORDS.include?(word.to_s) raise "#{word.inspect} is a Bundler::Thor reserved word and cannot be defined as #{type}" end # Build an option and adds it to the given scope. # # ==== Parameters # name:: The name of the argument. # options:: Described in both class_option and method_option. # scope:: Options hash that is being built up def build_option(name, options, scope) #:nodoc: scope[name] = Bundler::Thor::Option.new(name, {:check_default_type => check_default_type}.merge!(options)) end # Receives a hash of options, parse them and add to the scope. This is a # fast way to set a bunch of options: # # build_options :foo => true, :bar => :required, :baz => :string # # ==== Parameters # Hash[Symbol => Object] def build_options(options, scope) #:nodoc: options.each do |key, value| scope[key] = Bundler::Thor::Option.parse(key, value) end end # Finds a command with the given name. If the command belongs to the current # class, just return it, otherwise dup it and add the fresh copy to the # current command hash. def find_and_refresh_command(name) #:nodoc: if commands[name.to_s] commands[name.to_s] elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition commands[name.to_s] = command.clone else raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found." end end alias_method :find_and_refresh_task, :find_and_refresh_command # Everytime someone inherits from a Bundler::Thor class, register the klass # and file into baseclass. def inherited(klass) super(klass) Bundler::Thor::Base.register_klass_file(klass) klass.instance_variable_set(:@no_commands, 0) end # Fire this callback whenever a method is added. Added methods are # tracked as commands by invoking the create_command method. def method_added(meth) super(meth) meth = meth.to_s if meth == "initialize" initialize_added return end # Return if it's not a public instance method return unless public_method_defined?(meth.to_sym) return if no_commands? || !create_command(meth) is_thor_reserved_word?(meth, :command) Bundler::Thor::Base.register_klass_file(self) end # Retrieves a value from superclass. If it reaches the baseclass, # returns default. def from_superclass(method, default = nil) if self == baseclass || !superclass.respond_to?(method, true) default else value = superclass.send(method) # Ruby implements `dup` on Object, but raises a `TypeError` # if the method is called on immediates. As a result, we # don't have a good way to check whether dup will succeed # without calling it and rescuing the TypeError. begin value.dup rescue TypeError value end end end # # The basename of the program invoking the thor class. # def basename File.basename($PROGRAM_NAME).split(" ").first end # SIGNATURE: Sets the baseclass. This is where the superclass lookup # finishes. def baseclass #:nodoc: end # SIGNATURE: Creates a new command if valid_command? is true. This method is # called when a new method is added to the class. def create_command(meth) #:nodoc: end alias_method :create_task, :create_command # SIGNATURE: Defines behavior when the initialize method is added to the # class. def initialize_added #:nodoc: end # SIGNATURE: The hook invoked by start. def dispatch(command, given_args, given_opts, config) #:nodoc: raise NotImplementedError end end end end PK ]P?% % =gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell.rbnu[require "rbconfig" class Bundler::Thor module Base class << self attr_writer :shell # Returns the shell used in all Bundler::Thor classes. If you are in a Unix platform # it will use a colored log, otherwise it will use a basic one without color. # def shell @shell ||= if ENV["THOR_SHELL"] && !ENV["THOR_SHELL"].empty? Bundler::Thor::Shell.const_get(ENV["THOR_SHELL"]) elsif RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ && !ENV["ANSICON"] Bundler::Thor::Shell::Basic else Bundler::Thor::Shell::Color end end end end module Shell SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width] attr_writer :shell autoload :Basic, File.expand_path("shell/basic", __dir__) autoload :Color, File.expand_path("shell/color", __dir__) autoload :HTML, File.expand_path("shell/html", __dir__) # Add shell to initialize config values. # # ==== Configuration # shell:: An instance of the shell to be used. # # ==== Examples # # class MyScript < Bundler::Thor # argument :first, :type => :numeric # end # # MyScript.new [1.0], { :foo => :bar }, :shell => Bundler::Thor::Shell::Basic.new # def initialize(args = [], options = {}, config = {}) super self.shell = config[:shell] shell.base ||= self if shell.respond_to?(:base) end # Holds the shell for the given Bundler::Thor instance. If no shell is given, # it gets a default shell from Bundler::Thor::Base.shell. def shell @shell ||= Bundler::Thor::Base.shell.new end # Common methods that are delegated to the shell. SHELL_DELEGATED_METHODS.each do |method| module_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{method}(*args,&block) shell.#{method}(*args,&block) end METHOD end # Yields the given block with padding. def with_padding shell.padding += 1 yield ensure shell.padding -= 1 end protected # Allow shell to be shared between invocations. # def _shared_configuration #:nodoc: super.merge!(:shell => shell) end end end PK ](_b'b'>gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/runner.rbnu[require_relative "../thor" require_relative "group" require "yaml" require "digest/md5" require "pathname" class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLength autoload :OpenURI, "open-uri" map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version def self.banner(command, all = false, subcommand = false) "thor " + command.formatted_usage(self, all, subcommand) end def self.exit_on_failure? true end # Override Bundler::Thor#help so it can give information about any class and any method. # def help(meth = nil) if meth && !respond_to?(meth) initialize_thorfiles(meth) klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth) self.class.handle_no_command_error(command, false) if klass.nil? klass.start(["-h", command].compact, :shell => shell) else super end end # If a command is not found on Bundler::Thor::Runner, method missing is invoked and # Bundler::Thor::Runner is then responsible for finding the command in all classes. # def method_missing(meth, *args) meth = meth.to_s initialize_thorfiles(meth) klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth) self.class.handle_no_command_error(command, false) if klass.nil? args.unshift(command) if command klass.start(args, :shell => shell) end desc "install NAME", "Install an optionally named Bundler::Thor file into your system commands" method_options :as => :string, :relative => :boolean, :force => :boolean def install(name) # rubocop:disable MethodLength initialize_thorfiles # If a directory name is provided as the argument, look for a 'main.thor' # command in said directory. begin if File.directory?(File.expand_path(name)) base = File.join(name, "main.thor") package = :directory contents = open(base, &:read) else base = name package = :file contents = open(name, &:read) end rescue OpenURI::HTTPError raise Error, "Error opening URI '#{name}'" rescue Errno::ENOENT raise Error, "Error opening file '#{name}'" end say "Your Thorfile contains:" say contents unless options["force"] return false if no?("Do you wish to continue [y/N]?") end as = options["as"] || begin first_line = contents.split("\n")[0] (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil end unless as basename = File.basename(name) as = ask("Please specify a name for #{name} in the system repository [#{basename}]:") as = basename if as.empty? end location = if options[:relative] || name =~ %r{^https?://} name else File.expand_path(name) end thor_yaml[as] = { :filename => Digest::MD5.hexdigest(name + as), :location => location, :namespaces => Bundler::Thor::Util.namespaces_in_content(contents, base) } save_yaml(thor_yaml) say "Storing thor file in your system repository" destination = File.join(thor_root, thor_yaml[as][:filename]) if package == :file File.open(destination, "w") { |f| f.puts contents } else require "fileutils" FileUtils.cp_r(name, destination) end thor_yaml[as][:filename] # Indicate success end desc "version", "Show Bundler::Thor version" def version require_relative "version" say "Bundler::Thor #{Bundler::Thor::VERSION}" end desc "uninstall NAME", "Uninstall a named Bundler::Thor module" def uninstall(name) raise Error, "Can't find module '#{name}'" unless thor_yaml[name] say "Uninstalling #{name}." require "fileutils" FileUtils.rm_rf(File.join(thor_root, (thor_yaml[name][:filename]).to_s)) thor_yaml.delete(name) save_yaml(thor_yaml) puts "Done." end desc "update NAME", "Update a Bundler::Thor file from its original location" def update(name) raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location] say "Updating '#{name}' from #{thor_yaml[name][:location]}" old_filename = thor_yaml[name][:filename] self.options = options.merge("as" => name) if File.directory? File.expand_path(name) require "fileutils" FileUtils.rm_rf(File.join(thor_root, old_filename)) thor_yaml.delete(old_filename) save_yaml(thor_yaml) filename = install(name) else filename = install(thor_yaml[name][:location]) end File.delete(File.join(thor_root, old_filename)) unless filename == old_filename end desc "installed", "List the installed Bundler::Thor modules and commands" method_options :internal => :boolean def installed initialize_thorfiles(nil, true) display_klasses(true, options["internal"]) end desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)" method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean def list(search = "") initialize_thorfiles search = ".*#{search}" if options["substring"] search = /^#{search}.*/i group = options[:group] || "standard" klasses = Bundler::Thor::Base.subclasses.select do |k| (options[:all] || k.group == group) && k.namespace =~ search end display_klasses(false, false, klasses) end private def thor_root Bundler::Thor::Util.thor_root end def thor_yaml @thor_yaml ||= begin yaml_file = File.join(thor_root, "thor.yml") yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file) yaml || {} end end # Save the yaml file. If none exists in thor root, creates one. # def save_yaml(yaml) yaml_file = File.join(thor_root, "thor.yml") unless File.exist?(yaml_file) require "fileutils" FileUtils.mkdir_p(thor_root) yaml_file = File.join(thor_root, "thor.yml") FileUtils.touch(yaml_file) end File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml } end # Load the Thorfiles. If relevant_to is supplied, looks for specific files # in the thor_root instead of loading them all. # # By default, it also traverses the current path until find Bundler::Thor files, as # described in thorfiles. This look up can be skipped by supplying # skip_lookup true. # def initialize_thorfiles(relevant_to = nil, skip_lookup = false) thorfiles(relevant_to, skip_lookup).each do |f| Bundler::Thor::Util.load_thorfile(f, nil, options[:debug]) unless Bundler::Thor::Base.subclass_files.keys.include?(File.expand_path(f)) end end # Finds Thorfiles by traversing from your current directory down to the root # directory of your system. If at any time we find a Bundler::Thor file, we stop. # # We also ensure that system-wide Thorfiles are loaded first, so local # Thorfiles can override them. # # ==== Example # # If we start at /Users/wycats/dev/thor ... # # 1. /Users/wycats/dev/thor # 2. /Users/wycats/dev # 3. /Users/wycats <-- we find a Thorfile here, so we stop # # Suppose we start at c:\Documents and Settings\james\dev\thor ... # # 1. c:\Documents and Settings\james\dev\thor # 2. c:\Documents and Settings\james\dev # 3. c:\Documents and Settings\james # 4. c:\Documents and Settings # 5. c:\ <-- no Thorfiles found! # def thorfiles(relevant_to = nil, skip_lookup = false) thorfiles = [] unless skip_lookup Pathname.pwd.ascend do |path| thorfiles = Bundler::Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten break unless thorfiles.empty? end end files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Bundler::Thor::Util.thor_root_glob) files += thorfiles files -= ["#{thor_root}/thor.yml"] files.map! do |file| File.directory?(file) ? File.join(file, "main.thor") : file end end # Load Thorfiles relevant to the given method. If you provide "foo:bar" it # will load all thor files in the thor.yaml that has "foo" e "foo:bar" # namespaces registered. # def thorfiles_relevant_to(meth) lookup = [meth, meth.split(":")[0...-1].join(":")] files = thor_yaml.select do |_, v| v[:namespaces] && !(v[:namespaces] & lookup).empty? end files.map { |_, v| File.join(thor_root, (v[:filename]).to_s) } end # Display information about the given klasses. If with_module is given, # it shows a table with information extracted from the yaml file. # def display_klasses(with_modules = false, show_internal = false, klasses = Bundler::Thor::Base.subclasses) klasses -= [Bundler::Thor, Bundler::Thor::Runner, Bundler::Thor::Group] unless show_internal raise Error, "No Bundler::Thor commands available" if klasses.empty? show_modules if with_modules && !thor_yaml.empty? list = Hash.new { |h, k| h[k] = [] } groups = klasses.select { |k| k.ancestors.include?(Bundler::Thor::Group) } # Get classes which inherit from Bundler::Thor (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) } # Get classes which inherit from Bundler::Thor::Base groups.map! { |k| k.printable_commands(false).first } list["root"] = groups # Order namespaces with default coming first list = list.sort { |a, b| a[0].sub(/^default/, "") <=> b[0].sub(/^default/, "") } list.each { |n, commands| display_commands(n, commands) unless commands.empty? } end def display_commands(namespace, list) #:nodoc: list.sort! { |a, b| a[0] <=> b[0] } say shell.set_color(namespace, :blue, true) say "-" * namespace.size print_table(list, :truncate => true) say end alias_method :display_tasks, :display_commands def show_modules #:nodoc: info = [] labels = %w(Modules Namespaces) info << labels info << ["-" * labels[0].size, "-" * labels[1].size] thor_yaml.each do |name, hash| info << [name, hash[:namespaces].join(", ")] end print_table info say "" end end PK ]aqEgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/option.rbnu[class Bundler::Thor class Option < Argument #:nodoc: attr_reader :aliases, :group, :lazy_default, :hide, :repeatable VALID_TYPES = [:boolean, :numeric, :hash, :array, :string] def initialize(name, options = {}) @check_default_type = options[:check_default_type] options[:required] = false unless options.key?(:required) @repeatable = options.fetch(:repeatable, false) super @lazy_default = options[:lazy_default] @group = options[:group].to_s.capitalize if options[:group] @aliases = Array(options[:aliases]) @hide = options[:hide] end # This parse quick options given as method_options. It makes several # assumptions, but you can be more specific using the option method. # # parse :foo => "bar" # #=> Option foo with default value bar # # parse [:foo, :baz] => "bar" # #=> Option foo with default value bar and alias :baz # # parse :foo => :required # #=> Required option foo without default value # # parse :foo => 2 # #=> Option foo with default value 2 and type numeric # # parse :foo => :numeric # #=> Option foo without default value and type numeric # # parse :foo => true # #=> Option foo with default value true and type boolean # # The valid types are :boolean, :numeric, :hash, :array and :string. If none # is given a default type is assumed. This default type accepts arguments as # string (--foo=value) or booleans (just --foo). # # By default all options are optional, unless :required is given. # def self.parse(key, value) if key.is_a?(Array) name, *aliases = key else name = key aliases = [] end name = name.to_s default = value type = case value when Symbol default = nil if VALID_TYPES.include?(value) value elsif required = (value == :required) # rubocop:disable AssignmentInCondition :string end when TrueClass, FalseClass :boolean when Numeric :numeric when Hash, Array, String value.class.name.downcase.to_sym end new(name.to_s, :required => required, :type => type, :default => default, :aliases => aliases) end def switch_name @switch_name ||= dasherized? ? name : dasherize(name) end def human_name @human_name ||= dasherized? ? undasherize(name) : name end def usage(padding = 0) sample = if banner && !banner.to_s.empty? "#{switch_name}=#{banner}".dup else switch_name end sample = "[#{sample}]".dup unless required? if boolean? sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.start_with?("no-") end if aliases.empty? (" " * padding) << sample else "#{aliases.join(', ')}, #{sample}" end end VALID_TYPES.each do |type| class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{type}? self.type == #{type.inspect} end RUBY end protected def validate! raise ArgumentError, "An option cannot be boolean and required." if boolean? && required? validate_default_type! end def validate_default_type! default_type = case @default when nil return when TrueClass, FalseClass required? ? :string : :boolean when Numeric :numeric when Symbol :string when Hash, Array, String @default.class.name.downcase.to_sym end expected_type = (@repeatable && @type != :hash) ? :array : @type if default_type != expected_type err = "Expected #{expected_type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})" if @check_default_type raise ArgumentError, err elsif @check_default_type == nil Bundler::Thor.deprecation_warning "#{err}.\n" + 'This will be rejected in the future unless you explicitly pass the options `check_default_type: false`' + ' or call `allow_incompatible_default_type!` in your code' end end end def dasherized? name.index("-") == 0 end def undasherize(str) str.sub(/^-{1,2}/, "") end def dasherize(str) (str.length > 1 ? "--" : "-") + str.tr("_", "-") end end end PK ]llHgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/arguments.rbnu[class Bundler::Thor class Arguments #:nodoc: # rubocop:disable ClassLength NUMERIC = /[-+]?(\d*\.\d+|\d+)/ # Receives an array of args and returns two arrays, one with arguments # and one with switches. # def self.split(args) arguments = [] args.each do |item| break if item.is_a?(String) && item =~ /^-/ arguments << item end [arguments, args[Range.new(arguments.size, -1)]] end def self.parse(*args) to_parse = args.pop new(*args).parse(to_parse) end # Takes an array of Bundler::Thor::Argument objects. # def initialize(arguments = []) @assigns = {} @non_assigned_required = [] @switches = arguments arguments.each do |argument| if !argument.default.nil? begin @assigns[argument.human_name] = argument.default.dup rescue TypeError # Compatibility shim for un-dup-able Fixnum in Ruby < 2.4 @assigns[argument.human_name] = argument.default end elsif argument.required? @non_assigned_required << argument end end end def parse(args) @pile = args.dup @switches.each do |argument| break unless peek @non_assigned_required.delete(argument) @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name) end check_requirement! @assigns end def remaining @pile end private def no_or_skip?(arg) arg =~ /^--(no|skip)-([-\w]+)$/ $2 end def last? @pile.empty? end def peek @pile.first end def shift @pile.shift end def unshift(arg) if arg.is_a?(Array) @pile = arg + @pile else @pile.unshift(arg) end end def current_is_value? peek && peek.to_s !~ /^-{1,2}\S+/ end # Runs through the argument array getting strings that contains ":" and # mark it as a hash: # # [ "name:string", "age:integer" ] # # Becomes: # # { "name" => "string", "age" => "integer" } # def parse_hash(name) return shift if peek.is_a?(Hash) hash = {} while current_is_value? && peek.include?(":") key, value = shift.split(":", 2) raise MalformattedArgumentError, "You can't specify '#{key}' more than once in option '#{name}'; got #{key}:#{hash[key]} and #{key}:#{value}" if hash.include? key hash[key] = value end hash end # Runs through the argument array getting all strings until no string is # found or a switch is found. # # ["a", "b", "c"] # # And returns it as an array: # # ["a", "b", "c"] # def parse_array(name) return shift if peek.is_a?(Array) array = [] array << shift while current_is_value? array end # Check if the peek is numeric format and return a Float or Integer. # Check if the peek is included in enum if enum is provided. # Otherwise raises an error. # def parse_numeric(name) return shift if peek.is_a?(Numeric) unless peek =~ NUMERIC && $& == peek raise MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}" end value = $&.index(".") ? shift.to_f : shift.to_i if @switches.is_a?(Hash) && switch = @switches[name] if switch.enum && !switch.enum.include?(value) raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}" end end value end # Parse string: # for --string-arg, just return the current value in the pile # for --no-string-arg, nil # Check if the peek is included in enum if enum is provided. Otherwise raises an error. # def parse_string(name) if no_or_skip?(name) nil else value = shift if @switches.is_a?(Hash) && switch = @switches[name] if switch.enum && !switch.enum.include?(value) raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}" end end value end end # Raises an error if @non_assigned_required array is not empty. # def check_requirement! return if @non_assigned_required.empty? names = @non_assigned_required.map do |o| o.respond_to?(:switch_name) ? o.switch_name : o.human_name end.join("', '") class_name = self.class.name.split("::").last.downcase raise RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'" end end end PK ]i Ggems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/argument.rbnu[class Bundler::Thor class Argument #:nodoc: VALID_TYPES = [:numeric, :hash, :array, :string] attr_reader :name, :description, :enum, :required, :type, :default, :banner alias_method :human_name, :name def initialize(name, options = {}) class_name = self.class.name.split("::").last type = options[:type] raise ArgumentError, "#{class_name} name can't be nil." if name.nil? raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type) @name = name.to_s @description = options[:desc] @required = options.key?(:required) ? options[:required] : true @type = (type || :string).to_sym @default = options[:default] @banner = options[:banner] || default_banner @enum = options[:enum] validate! # Trigger specific validations end def usage required? ? banner : "[#{banner}]" end def required? required end def show_default? case default when Array, String, Hash !default.empty? else default end end protected def validate! raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil? raise ArgumentError, "An argument cannot have an enum other than an array." if @enum && !@enum.is_a?(Array) end def valid_type?(type) self.class::VALID_TYPES.include?(type.to_sym) end def default_banner case type when :boolean nil when :string, :default human_name.upcase when :numeric "N" when :hash "key:value" when :array "one two three" end end end end PK ]$IJ;;Fgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/options.rbnu[class Bundler::Thor class Options < Arguments #:nodoc: # rubocop:disable ClassLength LONG_RE = /^(--\w+(?:-\w+)*)$/ SHORT_RE = /^(-[a-z])$/i EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i OPTS_END = "--".freeze # Receives a hash and makes it switches. def self.to_switches(options) options.map do |key, value| case value when true "--#{key}" when Array "--#{key} #{value.map(&:inspect).join(' ')}" when Hash "--#{key} #{value.map { |k, v| "#{k}:#{v}" }.join(' ')}" when nil, false nil else "--#{key} #{value.inspect}" end end.compact.join(" ") end # Takes a hash of Bundler::Thor::Option and a hash with defaults. # # If +stop_on_unknown+ is true, #parse will stop as soon as it encounters # an unknown option or a regular argument. def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false) @stop_on_unknown = stop_on_unknown @disable_required_check = disable_required_check options = hash_options.values super(options) # Add defaults defaults.each do |key, value| @assigns[key.to_s] = value @non_assigned_required.delete(hash_options[key]) end @shorts = {} @switches = {} @extra = [] @stopped_parsing_after_extra_index = nil options.each do |option| @switches[option.switch_name] = option option.aliases.each do |short| name = short.to_s.sub(/^(?!\-)/, "-") @shorts[name] ||= option.switch_name end end end def remaining @extra end def peek return super unless @parsing_options result = super if result == OPTS_END shift @parsing_options = false @stopped_parsing_after_extra_index ||= @extra.size super else result end end def parse(args) # rubocop:disable MethodLength @pile = args.dup @parsing_options = true while peek if parsing_options? match, is_switch = current_is_switch? shifted = shift if is_switch case shifted when SHORT_SQ_RE unshift($1.split("").map { |f| "-#{f}" }) next when EQ_RE, SHORT_NUM unshift($2) switch = $1 when LONG_RE, SHORT_RE switch = $1 end switch = normalize_switch(switch) option = switch_option(switch) result = parse_peek(switch, option) assign_result!(option, result) elsif @stop_on_unknown @parsing_options = false @extra << shifted @stopped_parsing_after_extra_index ||= @extra.size @extra << shift while peek break elsif match @extra << shifted @extra << shift while peek && peek !~ /^-/ else @extra << shifted end else @extra << shift end end check_requirement! unless @disable_required_check assigns = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new(@assigns) assigns.freeze assigns end def check_unknown! to_check = @stopped_parsing_after_extra_index ? @extra[0...@stopped_parsing_after_extra_index] : @extra # an unknown option starts with - or -- and has no more --'s afterward. unknown = to_check.select { |str| str =~ /^--?(?:(?!--).)*$/ } raise UnknownArgumentError.new(@switches.keys, unknown) unless unknown.empty? end protected def assign_result!(option, result) if option.repeatable && option.type == :hash (@assigns[option.human_name] ||= {}).merge!(result) elsif option.repeatable (@assigns[option.human_name] ||= []) << result else @assigns[option.human_name] = result end end # Check if the current value in peek is a registered switch. # # Two booleans are returned. The first is true if the current value # starts with a hyphen; the second is true if it is a registered switch. def current_is_switch? case peek when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM [true, switch?($1)] when SHORT_SQ_RE [true, $1.split("").any? { |f| switch?("-#{f}") }] else [false, false] end end def current_is_switch_formatted? case peek when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE true else false end end def current_is_value? peek && (!parsing_options? || super) end def switch?(arg) !switch_option(normalize_switch(arg)).nil? end def switch_option(arg) if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition @switches[arg] || @switches["--#{match}"] else @switches[arg] end end # Check if the given argument is actually a shortcut. # def normalize_switch(arg) (@shorts[arg] || arg).tr("_", "-") end def parsing_options? peek @parsing_options end # Parse boolean values which can be given as --foo=true, --foo or --no-foo. # def parse_boolean(switch) if current_is_value? if ["true", "TRUE", "t", "T", true].include?(peek) shift true elsif ["false", "FALSE", "f", "F", false].include?(peek) shift false else @switches.key?(switch) || !no_or_skip?(switch) end else @switches.key?(switch) || !no_or_skip?(switch) end end # Parse the value at the peek analyzing if it requires an input or not. # def parse_peek(switch, option) if parsing_options? && (current_is_switch_formatted? || last?) if option.boolean? # No problem for boolean types elsif no_or_skip?(switch) return nil # User set value to nil elsif option.string? && !option.required? # Return the default if there is one, else the human name return option.lazy_default || option.default || option.human_name elsif option.lazy_default return option.lazy_default else raise MalformattedArgumentError, "No value provided for option '#{switch}'" end end @non_assigned_required.delete(option) send(:"parse_#{option.type}", switch) end end end PK ]V]Pgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rbnu[require_relative "empty_directory" class Bundler::Thor module Actions # Injects the given content into a file. Different from gsub_file, this # method is reversible. # # ==== Parameters # destination:: Relative path to the destination root # data:: Data to add to the file. Can be given as a block. # config:: give :verbose => false to not log the status and the flag # for injection (:after or :before) or :force => true for # insert two or more times the same content. # # ==== Examples # # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n" # # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do # gems = ask "Which gems would you like to add?" # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n") # end # WARNINGS = { unchanged_no_flag: 'File unchanged! The supplied flag value not found!' } def insert_into_file(destination, *args, &block) data = block_given? ? block : args.shift config = args.shift || {} config[:after] = /\z/ unless config.key?(:before) || config.key?(:after) action InjectIntoFile.new(self, destination, data, config) end alias_method :inject_into_file, :insert_into_file class InjectIntoFile < EmptyDirectory #:nodoc: attr_reader :replacement, :flag, :behavior def initialize(base, destination, data, config) super(base, destination, {:verbose => true}.merge(config)) @behavior, @flag = if @config.key?(:after) [:after, @config.delete(:after)] else [:before, @config.delete(:before)] end @replacement = data.is_a?(Proc) ? data.call : data @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp) end def invoke! content = if @behavior == :after '\0' + replacement else replacement + '\0' end if exists? if replace!(/#{flag}/, content, config[:force]) say_status(:invoke) else say_status(:unchanged, warning: WARNINGS[:unchanged_no_flag], color: :red) end else unless pretend? raise Bundler::Thor::Error, "The file #{ destination } does not appear to exist" end end end def revoke! say_status :revoke regexp = if @behavior == :after content = '\1\2' /(#{flag})(.*)(#{Regexp.escape(replacement)})/m else content = '\2\3' /(#{Regexp.escape(replacement)})(.*)(#{flag})/m end replace!(regexp, content, true) end protected def say_status(behavior, warning: nil, color: nil) status = if behavior == :invoke if flag == /\A/ :prepend elsif flag == /\z/ :append else :insert end elsif warning warning else :subtract end super(status, (color || config[:verbose])) end # Adds the content to the file. # def replace!(regexp, string, force) return if pretend? content = File.read(destination) if force || !content.include?(replacement) success = content.gsub!(regexp, string) File.open(destination, "wb") { |file| file.write(content) } success end end end end end PK ]s mmKgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/create_link.rbnu[require_relative "create_file" class Bundler::Thor module Actions # Create a new file relative to the destination root from the given source. # # ==== Parameters # destination:: the relative path to the destination root. # source:: the relative path to the source root. # config:: give :verbose => false to not log the status. # :: give :symbolic => false for hard link. # # ==== Examples # # create_link "config/apache.conf", "/etc/apache.conf" # def create_link(destination, *args) config = args.last.is_a?(Hash) ? args.pop : {} source = args.first action CreateLink.new(self, destination, source, config) end alias_method :add_link, :create_link # CreateLink is a subset of CreateFile, which instead of taking a block of # data, just takes a source string from the user. # class CreateLink < CreateFile #:nodoc: attr_reader :data # Checks if the content of the file at the destination is identical to the rendered result. # # ==== Returns # Boolean:: true if it is identical, false otherwise. # def identical? source = File.expand_path(render, File.dirname(destination)) exists? && File.identical?(source, destination) end def invoke! invoke_with_conflict_check do require "fileutils" FileUtils.mkdir_p(File.dirname(destination)) # Create a symlink by default config[:symbolic] = true if config[:symbolic].nil? File.unlink(destination) if exists? if config[:symbolic] File.symlink(render, destination) else File.link(render, destination) end end given_destination end def exists? super || File.symlink?(destination) end end end end PK ],;  Igems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/directory.rbnu[require_relative "empty_directory" class Bundler::Thor module Actions # Copies recursively the files from source directory to root directory. # If any of the files finishes with .tt, it's considered to be a template # and is placed in the destination without the extension .tt. If any # empty directory is found, it's copied and all .empty_directory files are # ignored. If any file name is wrapped within % signs, the text within # the % signs will be executed as a method and replaced with the returned # value. Let's suppose a doc directory with the following files: # # doc/ # components/.empty_directory # README # rdoc.rb.tt # %app_name%.rb # # When invoked as: # # directory "doc" # # It will create a doc directory in the destination with the following # files (assuming that the `app_name` method returns the value "blog"): # # doc/ # components/ # README # rdoc.rb # blog.rb # # Encoded path note: Since Bundler::Thor internals use Object#respond_to? to check if it can # expand %something%, this `something` should be a public method in the class calling # #directory. If a method is private, Bundler::Thor stack raises PrivateMethodEncodedError. # # ==== Parameters # source:: the relative path to the source root. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # If :recursive => false, does not look for paths recursively. # If :mode => :preserve, preserve the file mode from the source. # If :exclude_pattern => /regexp/, prevents copying files that match that regexp. # # ==== Examples # # directory "doc" # directory "doc", "docs", :recursive => false # def directory(source, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first || source action Directory.new(self, source, destination || source, config, &block) end class Directory < EmptyDirectory #:nodoc: attr_reader :source def initialize(base, source, destination = nil, config = {}, &block) @source = File.expand_path(Dir[Util.escape_globs(base.find_in_source_paths(source.to_s))].first) @block = block super(base, destination, {:recursive => true}.merge(config)) end def invoke! base.empty_directory given_destination, config execute! end def revoke! execute! end protected def execute! lookup = Util.escape_globs(source) lookup = config[:recursive] ? File.join(lookup, "**") : lookup lookup = file_level_lookup(lookup) files(lookup).sort.each do |file_source| next if File.directory?(file_source) next if config[:exclude_pattern] && file_source.match(config[:exclude_pattern]) file_destination = File.join(given_destination, file_source.gsub(source, ".")) file_destination.gsub!("/./", "/") case file_source when /\.empty_directory$/ dirname = File.dirname(file_destination).gsub(%r{/\.$}, "") next if dirname == given_destination base.empty_directory(dirname, config) when /#{TEMPLATE_EXTNAME}$/ base.template(file_source, file_destination[0..-4], config, &@block) else base.copy_file(file_source, file_destination, config, &@block) end end end def file_level_lookup(previous_lookup) File.join(previous_lookup, "*") end def files(lookup) Dir.glob(lookup, File::FNM_DOTMATCH) end end end end PK ]te) ) Kgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/create_file.rbnu[require_relative "empty_directory" class Bundler::Thor module Actions # Create a new file relative to the destination root with the given data, # which is the return value of a block or a data string. # # ==== Parameters # destination:: the relative path to the destination root. # data:: the data to append to the file. # config:: give :verbose => false to not log the status. # # ==== Examples # # create_file "lib/fun_party.rb" do # hostname = ask("What is the virtual hostname I should use?") # "vhost.name = #{hostname}" # end # # create_file "config/apache.conf", "your apache config" # def create_file(destination, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} data = args.first action CreateFile.new(self, destination, block || data.to_s, config) end alias_method :add_file, :create_file # CreateFile is a subset of Template, which instead of rendering a file with # ERB, it gets the content from the user. # class CreateFile < EmptyDirectory #:nodoc: attr_reader :data def initialize(base, destination, data, config = {}) @data = data super(base, destination, config) end # Checks if the content of the file at the destination is identical to the rendered result. # # ==== Returns # Boolean:: true if it is identical, false otherwise. # def identical? exists? && File.binread(destination) == render end # Holds the content to be added to the file. # def render @render ||= if data.is_a?(Proc) data.call else data end end def invoke! invoke_with_conflict_check do require "fileutils" FileUtils.mkdir_p(File.dirname(destination)) File.open(destination, "wb") { |f| f.write render } end given_destination end protected # Now on conflict we check if the file is identical or not. # def on_conflict_behavior(&block) if identical? say_status :identical, :blue else options = base.options.merge(config) force_or_skip_or_conflict(options[:force], options[:skip], &block) end end # If force is true, run the action, otherwise check if it's not being # skipped. If both are false, show the file_collision menu, if the menu # returns true, force it, otherwise skip. # def force_or_skip_or_conflict(force, skip, &block) if force say_status :force, :yellow yield unless pretend? elsif skip say_status :skip, :yellow else say_status :conflict, :red force_or_skip_or_conflict(force_on_collision?, true, &block) end end # Shows the file collision menu to the user and gets the result. # def force_on_collision? base.shell.file_collision(destination) { render } end end end end PK ]Iq3q3Qgems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rbnu[require "erb" class Bundler::Thor module Actions # Copies the file from the relative source to the relative destination. If # the destination is not given it's assumed to be equal to the source. # # ==== Parameters # source:: the relative path to the source root. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status, and # :mode => :preserve, to preserve the file mode from the source. # # ==== Examples # # copy_file "README", "doc/README" # # copy_file "doc/README" # def copy_file(source, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first || source source = File.expand_path(find_in_source_paths(source.to_s)) resulting_destination = create_file destination, nil, config do content = File.binread(source) content = yield(content) if block content end if config[:mode] == :preserve mode = File.stat(source).mode chmod(resulting_destination, mode, config) end end # Links the file from the relative source to the relative destination. If # the destination is not given it's assumed to be equal to the source. # # ==== Parameters # source:: the relative path to the source root. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # # ==== Examples # # link_file "README", "doc/README" # # link_file "doc/README" # def link_file(source, *args) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first || source source = File.expand_path(find_in_source_paths(source.to_s)) create_link destination, source, config end # Gets the content at the given address and places it at the given relative # destination. If a block is given instead of destination, the content of # the url is yielded and used as location. # # +get+ relies on open-uri, so passing application user input would provide # a command injection attack vector. # # ==== Parameters # source:: the address of the given content. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # # ==== Examples # # get "http://gist.github.com/103208", "doc/README" # # get "http://gist.github.com/103208" do |content| # content.split("\n").first # end # def get(source, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first render = if source =~ %r{^https?\://} require "open-uri" URI.send(:open, source) { |input| input.binmode.read } else source = File.expand_path(find_in_source_paths(source.to_s)) open(source) { |input| input.binmode.read } end destination ||= if block_given? block.arity == 1 ? yield(render) : yield else File.basename(source) end create_file destination, render, config end # Gets an ERB template at the relative source, executes it and makes a copy # at the relative destination. If the destination is not given it's assumed # to be equal to the source removing .tt from the filename. # # ==== Parameters # source:: the relative path to the source root. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # # ==== Examples # # template "README", "doc/README" # # template "doc/README" # def template(source, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, "") source = File.expand_path(find_in_source_paths(source.to_s)) context = config.delete(:context) || instance_eval("binding") create_file destination, nil, config do match = ERB.version.match(/(\d+\.\d+\.\d+)/) capturable_erb = if match && match[1] >= "2.2.0" # Ruby 2.6+ CapturableERB.new(::File.binread(source), :trim_mode => "-", :eoutvar => "@output_buffer") else CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer") end content = capturable_erb.tap do |erb| erb.filename = source end.result(context) content = yield(content) if block content end end # Changes the mode of the given file or directory. # # ==== Parameters # mode:: the file mode # path:: the name of the file to change mode # config:: give :verbose => false to not log the status. # # ==== Example # # chmod "script/server", 0755 # def chmod(path, mode, config = {}) return unless behavior == :invoke path = File.expand_path(path, destination_root) say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true) unless options[:pretend] require "fileutils" FileUtils.chmod_R(mode, path) end end # Prepend text to a file. Since it depends on insert_into_file, it's reversible. # # ==== Parameters # path:: path of the file to be changed # data:: the data to prepend to the file, can be also given as a block. # config:: give :verbose => false to not log the status. # # ==== Example # # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"' # # prepend_to_file 'config/environments/test.rb' do # 'config.gem "rspec"' # end # def prepend_to_file(path, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} config[:after] = /\A/ insert_into_file(path, *(args << config), &block) end alias_method :prepend_file, :prepend_to_file # Append text to a file. Since it depends on insert_into_file, it's reversible. # # ==== Parameters # path:: path of the file to be changed # data:: the data to append to the file, can be also given as a block. # config:: give :verbose => false to not log the status. # # ==== Example # # append_to_file 'config/environments/test.rb', 'config.gem "rspec"' # # append_to_file 'config/environments/test.rb' do # 'config.gem "rspec"' # end # def append_to_file(path, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} config[:before] = /\z/ insert_into_file(path, *(args << config), &block) end alias_method :append_file, :append_to_file # Injects text right after the class definition. Since it depends on # insert_into_file, it's reversible. # # ==== Parameters # path:: path of the file to be changed # klass:: the class to be manipulated # data:: the data to append to the class, can be also given as a block. # config:: give :verbose => false to not log the status. # # ==== Examples # # inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n" # # inject_into_class "app/controllers/application_controller.rb", ApplicationController do # " filter_parameter :password\n" # end # def inject_into_class(path, klass, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} config[:after] = /class #{klass}\n|class #{klass} .*\n/ insert_into_file(path, *(args << config), &block) end # Injects text right after the module definition. Since it depends on # insert_into_file, it's reversible. # # ==== Parameters # path:: path of the file to be changed # module_name:: the module to be manipulated # data:: the data to append to the class, can be also given as a block. # config:: give :verbose => false to not log the status. # # ==== Examples # # inject_into_module "app/helpers/application_helper.rb", ApplicationHelper, " def help; 'help'; end\n" # # inject_into_module "app/helpers/application_helper.rb", ApplicationHelper do # " def help; 'help'; end\n" # end # def inject_into_module(path, module_name, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} config[:after] = /module #{module_name}\n|module #{module_name} .*\n/ insert_into_file(path, *(args << config), &block) end # Run a regular expression replacement on a file. # # ==== Parameters # path:: path of the file to be changed # flag:: the regexp or string to be replaced # replacement:: the replacement, can be also given as a block # config:: give :verbose => false to not log the status, and # :force => true, to force the replacement regardless of runner behavior. # # ==== Example # # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1' # # gsub_file 'README', /rake/, :green do |match| # match << " no more. Use thor!" # end # def gsub_file(path, flag, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} return unless behavior == :invoke || config.fetch(:force, false) path = File.expand_path(path, destination_root) say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true) unless options[:pretend] content = File.binread(path) content.gsub!(flag, *args, &block) File.open(path, "wb") { |file| file.write(content) } end end # Uncomment all lines matching a given regex. It will leave the space # which existed before the comment hash in tact but will remove any spacing # between the comment hash and the beginning of the line. # # ==== Parameters # path:: path of the file to be changed # flag:: the regexp or string used to decide which lines to uncomment # config:: give :verbose => false to not log the status. # # ==== Example # # uncomment_lines 'config/initializers/session_store.rb', /active_record/ # def uncomment_lines(path, flag, *args) flag = flag.respond_to?(:source) ? flag.source : flag gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args) end # Comment all lines matching a given regex. It will leave the space # which existed before the beginning of the line in tact and will insert # a single space after the comment hash. # # ==== Parameters # path:: path of the file to be changed # flag:: the regexp or string used to decide which lines to comment # config:: give :verbose => false to not log the status. # # ==== Example # # comment_lines 'config/initializers/session_store.rb', /cookie_store/ # def comment_lines(path, flag, *args) flag = flag.respond_to?(:source) ? flag.source : flag gsub_file(path, /^(\s*)([^#\n]*#{flag})/, '\1# \2', *args) end # Removes a file at the given location. # # ==== Parameters # path:: path of the file to be changed # config:: give :verbose => false to not log the status. # # ==== Example # # remove_file 'README' # remove_file 'app/controllers/application_controller.rb' # def remove_file(path, config = {}) return unless behavior == :invoke path = File.expand_path(path, destination_root) say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true) if !options[:pretend] && File.exist?(path) require "fileutils" ::FileUtils.rm_rf(path) end end alias_method :remove_dir, :remove_file attr_accessor :output_buffer private :output_buffer, :output_buffer= private def concat(string) @output_buffer.concat(string) end def capture(*args) with_output_buffer { yield(*args) } end def with_output_buffer(buf = "".dup) #:nodoc: raise ArgumentError, "Buffer can not be a frozen object" if buf.frozen? old_buffer = output_buffer self.output_buffer = buf yield output_buffer ensure self.output_buffer = old_buffer end # Bundler::Thor::Actions#capture depends on what kind of buffer is used in ERB. # Thus CapturableERB fixes ERB to use String buffer. class CapturableERB < ERB def set_eoutvar(compiler, eoutvar = "_erbout") compiler.put_cmd = "#{eoutvar}.concat" compiler.insert_cmd = "#{eoutvar}.concat" compiler.pre_cmd = ["#{eoutvar} = ''.dup"] compiler.post_cmd = [eoutvar] end end end end PK ]O&Ogems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rbnu[class Bundler::Thor module Actions # Creates an empty directory. # # ==== Parameters # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # # ==== Examples # # empty_directory "doc" # def empty_directory(destination, config = {}) action EmptyDirectory.new(self, destination, config) end # Class which holds create directory logic. This is the base class for # other actions like create_file and directory. # # This implementation is based in Templater actions, created by Jonas Nicklas # and Michael S. Klishin under MIT LICENSE. # class EmptyDirectory #:nodoc: attr_reader :base, :destination, :given_destination, :relative_destination, :config # Initializes given the source and destination. # # ==== Parameters # base:: A Bundler::Thor::Base instance # source:: Relative path to the source of this file # destination:: Relative path to the destination of this file # config:: give :verbose => false to not log the status. # def initialize(base, destination, config = {}) @base = base @config = {:verbose => true}.merge(config) self.destination = destination end # Checks if the destination file already exists. # # ==== Returns # Boolean:: true if the file exists, false otherwise. # def exists? ::File.exist?(destination) end def invoke! invoke_with_conflict_check do require "fileutils" ::FileUtils.mkdir_p(destination) end end def revoke! say_status :remove, :red require "fileutils" ::FileUtils.rm_rf(destination) if !pretend? && exists? given_destination end protected # Shortcut for pretend. # def pretend? base.options[:pretend] end # Sets the absolute destination value from a relative destination value. # It also stores the given and relative destination. Let's suppose our # script is being executed on "dest", it sets the destination root to # "dest". The destination, given_destination and relative_destination # are related in the following way: # # inside "bar" do # empty_directory "baz" # end # # destination #=> dest/bar/baz # relative_destination #=> bar/baz # given_destination #=> baz # def destination=(destination) return unless destination @given_destination = convert_encoded_instructions(destination.to_s) @destination = ::File.expand_path(@given_destination, base.destination_root) @relative_destination = base.relative_to_original_destination_root(@destination) end # Filenames in the encoded form are converted. If you have a file: # # %file_name%.rb # # It calls #file_name from the base and replaces %-string with the # return value (should be String) of #file_name: # # user.rb # # The method referenced can be either public or private. # def convert_encoded_instructions(filename) filename.gsub(/%(.*?)%/) do |initial_string| method = $1.strip base.respond_to?(method, true) ? base.send(method) : initial_string end end # Receives a hash of options and just execute the block if some # conditions are met. # def invoke_with_conflict_check(&block) if exists? on_conflict_behavior(&block) else yield unless pretend? say_status :create, :green end destination rescue Errno::EISDIR, Errno::EEXIST on_file_clash_behavior end def on_file_clash_behavior say_status :file_clash, :red end # What to do when the destination file already exists. # def on_conflict_behavior say_status :exist, :blue end # Shortcut to say_status shell method. # def say_status(status, color) base.shell.say_status status, relative_destination, color if config[:verbose] end end end end PK ]jU#U#<gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/util.rbnu[require "rbconfig" class Bundler::Thor module Sandbox #:nodoc: end # This module holds several utilities: # # 1) Methods to convert thor namespaces to constants and vice-versa. # # Bundler::Thor::Util.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz" # # 2) Loading thor files and sandboxing: # # Bundler::Thor::Util.load_thorfile("~/.thor/foo") # module Util class << self # Receives a namespace and search for it in the Bundler::Thor::Base subclasses. # # ==== Parameters # namespace:: The namespace to search for. # def find_by_namespace(namespace) namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/ Bundler::Thor::Base.subclasses.detect { |klass| klass.namespace == namespace } end # Receives a constant and converts it to a Bundler::Thor namespace. Since Bundler::Thor # commands can be added to a sandbox, this method is also responsible for # removing the sandbox namespace. # # This method should not be used in general because it's used to deal with # older versions of Bundler::Thor. On current versions, if you need to get the # namespace from a class, just call namespace on it. # # ==== Parameters # constant:: The constant to be converted to the thor path. # # ==== Returns # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz" # def namespace_from_thor_class(constant) constant = constant.to_s.gsub(/^Bundler::Thor::Sandbox::/, "") constant = snake_case(constant).squeeze(":") constant end # Given the contents, evaluate it inside the sandbox and returns the # namespaces defined in the sandbox. # # ==== Parameters # contents # # ==== Returns # Array[Object] # def namespaces_in_content(contents, file = __FILE__) old_constants = Bundler::Thor::Base.subclasses.dup Bundler::Thor::Base.subclasses.clear load_thorfile(file, contents) new_constants = Bundler::Thor::Base.subclasses.dup Bundler::Thor::Base.subclasses.replace(old_constants) new_constants.map!(&:namespace) new_constants.compact! new_constants end # Returns the thor classes declared inside the given class. # def thor_classes_in(klass) stringfied_constants = klass.constants.map(&:to_s) Bundler::Thor::Base.subclasses.select do |subclass| next unless subclass.name stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", "")) end end # Receives a string and convert it to snake case. SnakeCase returns snake_case. # # ==== Parameters # String # # ==== Returns # String # def snake_case(str) return str.downcase if str =~ /^[A-Z_]+$/ str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/ $+.downcase end # Receives a string and convert it to camel case. camel_case returns CamelCase. # # ==== Parameters # String # # ==== Returns # String # def camel_case(str) return str if str !~ /_/ && str =~ /[A-Z]+.*/ str.split("_").map(&:capitalize).join end # Receives a namespace and tries to retrieve a Bundler::Thor or Bundler::Thor::Group class # from it. It first searches for a class using the all the given namespace, # if it's not found, removes the highest entry and searches for the class # again. If found, returns the highest entry as the class name. # # ==== Examples # # class Foo::Bar < Bundler::Thor # def baz # end # end # # class Baz::Foo < Bundler::Thor::Group # end # # Bundler::Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default command # Bundler::Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil # Bundler::Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz" # # ==== Parameters # namespace # def find_class_and_command_by_namespace(namespace, fallback = true) if namespace.include?(":") # look for a namespaced command pieces = namespace.split(":") command = pieces.pop klass = Bundler::Thor::Util.find_by_namespace(pieces.join(":")) end unless klass # look for a Bundler::Thor::Group with the right name klass = Bundler::Thor::Util.find_by_namespace(namespace) command = nil end if !klass && fallback # try a command in the default namespace command = namespace klass = Bundler::Thor::Util.find_by_namespace("") end [klass, command] end alias_method :find_class_and_task_by_namespace, :find_class_and_command_by_namespace # Receives a path and load the thor file in the path. The file is evaluated # inside the sandbox to avoid namespacing conflicts. # def load_thorfile(path, content = nil, debug = false) content ||= File.binread(path) begin Bundler::Thor::Sandbox.class_eval(content, path) rescue StandardError => e $stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}") if debug $stderr.puts(*e.backtrace) else $stderr.puts(e.backtrace.first) end end end def user_home @@user_home ||= if ENV["HOME"] ENV["HOME"] elsif ENV["USERPROFILE"] ENV["USERPROFILE"] elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"] File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"]) elsif ENV["APPDATA"] ENV["APPDATA"] else begin File.expand_path("~") rescue if File::ALT_SEPARATOR "C:/" else "/" end end end end # Returns the root where thor files are located, depending on the OS. # def thor_root File.join(user_home, ".thor").tr('\\', "/") end # Returns the files in the thor root. On Windows thor_root will be something # like this: # # C:\Documents and Settings\james\.thor # # If we don't #gsub the \ character, Dir.glob will fail. # def thor_root_glob files = Dir["#{escape_globs(thor_root)}/*"] files.map! do |file| File.directory?(file) ? File.join(file, "main.thor") : file end end # Where to look for Bundler::Thor files. # def globs_for(path) path = escape_globs(path) ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"] end # Return the path to the ruby interpreter taking into account multiple # installations and windows extensions. # def ruby_command @ruby_command ||= begin ruby_name = RbConfig::CONFIG["ruby_install_name"] ruby = File.join(RbConfig::CONFIG["bindir"], ruby_name) ruby << RbConfig::CONFIG["EXEEXT"] # avoid using different name than ruby (on platforms supporting links) if ruby_name != "ruby" && File.respond_to?(:readlink) begin alternate_ruby = File.join(RbConfig::CONFIG["bindir"], "ruby") alternate_ruby << RbConfig::CONFIG["EXEEXT"] # ruby is a symlink if File.symlink? alternate_ruby linked_ruby = File.readlink alternate_ruby # symlink points to 'ruby_install_name' ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby end rescue NotImplementedError # rubocop:disable HandleExceptions # just ignore on windows end end # escape string in case path to ruby executable contain spaces. ruby.sub!(/.*\s.*/m, '"\&"') ruby end end # Returns a string that has had any glob characters escaped. # The glob characters are `* ? { } [ ]`. # # ==== Examples # # Bundler::Thor::Util.escape_globs('[apps]') # => '\[apps\]' # # ==== Parameters # String # # ==== Returns # String # def escape_globs(path) path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&') end # Returns a string that has had any HTML characters escaped. # # ==== Examples # # Bundler::Thor::Util.escape_html('
') # => "<div>" # # ==== Parameters # String # # ==== Returns # String # def escape_html(string) CGI.escapeHTML(string) end end end end PK ]q@q@7gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor.rbnu[require_relative "thor/base" class Bundler::Thor $thor_runner ||= false class << self # Allows for custom "Command" package naming. # # === Parameters # name # options # def package_name(name, _ = {}) @package_name = name.nil? || name == "" ? nil : name end # Sets the default command when thor is executed without an explicit command to be called. # # ==== Parameters # meth:: name of the default command # def default_command(meth = nil) if meth @default_command = meth == :none ? "help" : meth.to_s else @default_command ||= from_superclass(:default_command, "help") end end alias_method :default_task, :default_command # Registers another Bundler::Thor subclass as a command. # # ==== Parameters # klass:: Bundler::Thor subclass to register # command:: Subcommand name to use # usage:: Short usage for the subcommand # description:: Description for the subcommand def register(klass, subcommand_name, usage, description, options = {}) if klass <= Bundler::Thor::Group desc usage, description, options define_method(subcommand_name) { |*args| invoke(klass, args) } else desc usage, description, options subcommand subcommand_name, klass end end # Defines the usage and the description of the next command. # # ==== Parameters # usage # description # options # def desc(usage, description, options = {}) if options[:for] command = find_and_refresh_command(options[:for]) command.usage = usage if usage command.description = description if description else @usage = usage @desc = description @hide = options[:hide] || false end end # Defines the long description of the next command. # # ==== Parameters # long description # def long_desc(long_description, options = {}) if options[:for] command = find_and_refresh_command(options[:for]) command.long_description = long_description if long_description else @long_desc = long_description end end # Maps an input to a command. If you define: # # map "-T" => "list" # # Running: # # thor -T # # Will invoke the list command. # # ==== Parameters # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command. # def map(mappings = nil, **kw) @map ||= from_superclass(:map, {}) if mappings && !kw.empty? mappings = kw.merge!(mappings) else mappings ||= kw end if mappings mappings.each do |key, value| if key.respond_to?(:each) key.each { |subkey| @map[subkey] = value } else @map[key] = value end end end @map end # Declares the options for the next command to be declared. # # ==== Parameters # Hash[Symbol => Object]:: The hash key is the name of the option and the value # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric # or :required (string). If you give a value, the type of the value is used. # def method_options(options = nil) @method_options ||= {} build_options(options, @method_options) if options @method_options end alias_method :options, :method_options # Adds an option to the set of method options. If :for is given as option, # it allows you to change the options from a previous defined command. # # def previous_command # # magic # end # # method_option :foo => :bar, :for => :previous_command # # def next_command # # magic # end # # ==== Parameters # name:: The name of the argument. # options:: Described below. # # ==== Options # :desc - Description for the argument. # :required - If the argument is required or not. # :default - Default value for this argument. It cannot be required and have default values. # :aliases - Aliases for this option. # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean. # :banner - String to show on usage notes. # :hide - If you want to hide this option from the help. # def method_option(name, options = {}) scope = if options[:for] find_and_refresh_command(options[:for]).options else method_options end build_option(name, options, scope) end alias_method :option, :method_option # Prints help information for the given command. # # ==== Parameters # shell # command_name # def command_help(shell, command_name) meth = normalize_command_name(command_name) command = all_commands[meth] handle_no_command_error(meth) unless command shell.say "Usage:" shell.say " #{banner(command).split("\n").join("\n ")}" shell.say class_options_help(shell, nil => command.options.values) if command.long_description shell.say "Description:" shell.print_wrapped(command.long_description, :indent => 2) else shell.say command.description end end alias_method :task_help, :command_help # Prints help information for this class. # # ==== Parameters # shell # def help(shell, subcommand = false) list = printable_commands(true, subcommand) Bundler::Thor::Util.thor_classes_in(self).each do |klass| list += klass.printable_commands(false) end list.sort! { |a, b| a[0] <=> b[0] } if defined?(@package_name) && @package_name shell.say "#{@package_name} commands:" else shell.say "Commands:" end shell.print_table(list, :indent => 2, :truncate => true) shell.say class_options_help(shell) end # Returns commands ready to be printed. def printable_commands(all = true, subcommand = false) (all ? all_commands : commands).map do |_, command| next if command.hidden? item = [] item << banner(command, false, subcommand) item << (command.description ? "# #{command.description.gsub(/\s+/m, ' ')}" : "") item end.compact end alias_method :printable_tasks, :printable_commands def subcommands @subcommands ||= from_superclass(:subcommands, []) end alias_method :subtasks, :subcommands def subcommand_classes @subcommand_classes ||= {} end def subcommand(subcommand, subcommand_class) subcommands << subcommand.to_s subcommand_class.subcommand_help subcommand subcommand_classes[subcommand.to_s] = subcommand_class define_method(subcommand) do |*args| args, opts = Bundler::Thor::Arguments.split(args) invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}] invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h") invoke subcommand_class, *invoke_args end subcommand_class.commands.each do |_meth, command| command.ancestor_name = subcommand end end alias_method :subtask, :subcommand # Extend check unknown options to accept a hash of conditions. # # === Parameters # options: A hash containing :only and/or :except keys def check_unknown_options!(options = {}) @check_unknown_options ||= {} options.each do |key, value| if value @check_unknown_options[key] = Array(value) else @check_unknown_options.delete(key) end end @check_unknown_options end # Overwrite check_unknown_options? to take subcommands and options into account. def check_unknown_options?(config) #:nodoc: options = check_unknown_options return false unless options command = config[:current_command] return true unless command name = command.name if subcommands.include?(name) false elsif options[:except] !options[:except].include?(name.to_sym) elsif options[:only] options[:only].include?(name.to_sym) else true end end # Stop parsing of options as soon as an unknown option or a regular # argument is encountered. All remaining arguments are passed to the command. # This is useful if you have a command that can receive arbitrary additional # options, and where those additional options should not be handled by # Bundler::Thor. # # ==== Example # # To better understand how this is useful, let's consider a command that calls # an external command. A user may want to pass arbitrary options and # arguments to that command. The command itself also accepts some options, # which should be handled by Bundler::Thor. # # class_option "verbose", :type => :boolean # stop_on_unknown_option! :exec # check_unknown_options! :except => :exec # # desc "exec", "Run a shell command" # def exec(*args) # puts "diagnostic output" if options[:verbose] # Kernel.exec(*args) # end # # Here +exec+ can be called with +--verbose+ to get diagnostic output, # e.g.: # # $ thor exec --verbose echo foo # diagnostic output # foo # # But if +--verbose+ is given after +echo+, it is passed to +echo+ instead: # # $ thor exec echo --verbose foo # --verbose foo # # ==== Parameters # Symbol ...:: A list of commands that should be affected. def stop_on_unknown_option!(*command_names) @stop_on_unknown_option = stop_on_unknown_option | command_names end def stop_on_unknown_option?(command) #:nodoc: command && stop_on_unknown_option.include?(command.name.to_sym) end # Disable the check for required options for the given commands. # This is useful if you have a command that does not need the required options # to work, like help. # # ==== Parameters # Symbol ...:: A list of commands that should be affected. def disable_required_check!(*command_names) @disable_required_check = disable_required_check | command_names end def disable_required_check?(command) #:nodoc: command && disable_required_check.include?(command.name.to_sym) end protected def stop_on_unknown_option #:nodoc: @stop_on_unknown_option ||= [] end # help command has the required check disabled by default. def disable_required_check #:nodoc: @disable_required_check ||= [:help] end # The method responsible for dispatching given the args. def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength meth ||= retrieve_command_name(given_args) command = all_commands[normalize_command_name(meth)] if !command && config[:invoked_via_subcommand] # We're a subcommand and our first argument didn't match any of our # commands. So we put it back and call our default command. given_args.unshift(meth) command = all_commands[normalize_command_name(default_command)] end if command args, opts = Bundler::Thor::Options.split(given_args) if stop_on_unknown_option?(command) && !args.empty? # given_args starts with a non-option, so we treat everything as # ordinary arguments args.concat opts opts.clear end else args = given_args opts = nil command = dynamic_command_class.new(meth) end opts = given_opts || opts || [] config[:current_command] = command config[:command_options] = command.options instance = new(args, opts, config) yield instance if block_given? args = instance.args trailing = args[Range.new(arguments.size, -1)] instance.invoke_command(command, trailing || []) end # The banner for this class. You can customize it if you are invoking the # thor class by another ways which is not the Bundler::Thor::Runner. It receives # the command that is going to be invoked and a boolean which indicates if # the namespace should be displayed as arguments. # def banner(command, namespace = nil, subcommand = false) command.formatted_usage(self, $thor_runner, subcommand).split("\n").map do |formatted_usage| "#{basename} #{formatted_usage}" end.join("\n") end def baseclass #:nodoc: Bundler::Thor end def dynamic_command_class #:nodoc: Bundler::Thor::DynamicCommand end def create_command(meth) #:nodoc: @usage ||= nil @desc ||= nil @long_desc ||= nil @hide ||= nil if @usage && @desc base_class = @hide ? Bundler::Thor::HiddenCommand : Bundler::Thor::Command commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options) @usage, @desc, @long_desc, @method_options, @hide = nil true elsif all_commands[meth] || meth == "method_missing" true else puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " \ "Call desc if you want this method to be available as command or declare it inside a " \ "no_commands{} block. Invoked from #{caller[1].inspect}." false end end alias_method :create_task, :create_command def initialize_added #:nodoc: class_options.merge!(method_options) @method_options = nil end # Retrieve the command name from given args. def retrieve_command_name(args) #:nodoc: meth = args.first.to_s unless args.empty? args.shift if meth && (map[meth] || meth !~ /^\-/) end alias_method :retrieve_task_name, :retrieve_command_name # receives a (possibly nil) command name and returns a name that is in # the commands hash. In addition to normalizing aliases, this logic # will determine if a shortened command is an unambiguous substring of # a command or alias. # # +normalize_command_name+ also converts names like +animal-prison+ # into +animal_prison+. def normalize_command_name(meth) #:nodoc: return default_command.to_s.tr("-", "_") unless meth possibilities = find_command_possibilities(meth) raise AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]" if possibilities.size > 1 if possibilities.empty? meth ||= default_command elsif map[meth] meth = map[meth] else meth = possibilities.first end meth.to_s.tr("-", "_") # treat foo-bar as foo_bar end alias_method :normalize_task_name, :normalize_command_name # this is the logic that takes the command name passed in by the user # and determines whether it is an unambiguous substrings of a command or # alias name. def find_command_possibilities(meth) len = meth.to_s.length possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort unique_possibilities = possibilities.map { |k| map[k] || k }.uniq if possibilities.include?(meth) [meth] elsif unique_possibilities.size == 1 unique_possibilities else possibilities end end alias_method :find_task_possibilities, :find_command_possibilities def subcommand_help(cmd) desc "help [COMMAND]", "Describe subcommands or one specific subcommand" class_eval " def help(command = nil, subcommand = true); super; end " end alias_method :subtask_help, :subcommand_help end include Bundler::Thor::Base map HELP_MAPPINGS => :help desc "help [COMMAND]", "Describe available commands or one specific command" def help(command = nil, subcommand = false) if command if self.class.subcommands.include? command self.class.subcommand_classes[command].help(shell, true) else self.class.command_help(shell, command) end else self.class.help(shell, subcommand) end end end PK ]C}mmUgems/bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rbnu[require 'net/http' require_relative '../../../../uri/lib/uri' require 'cgi' # for escaping require_relative '../../../../connection_pool/lib/connection_pool' autoload :OpenSSL, 'openssl' ## # Persistent connections for Net::HTTP # # Bundler::Persistent::Net::HTTP::Persistent maintains persistent connections across all the # servers you wish to talk to. For each host:port you communicate with a # single persistent connection is created. # # Connections will be shared across threads through a connection pool to # increase reuse of connections. # # You can shut down any remaining HTTP connections when done by calling # #shutdown. # # Example: # # require 'bundler/vendor/net-http-persistent/lib/net/http/persistent' # # uri = Bundler::URI 'http://example.com/awesome/web/service' # # http = Bundler::Persistent::Net::HTTP::Persistent.new # # # perform a GET # response = http.request uri # # # or # # get = Net::HTTP::Get.new uri.request_uri # response = http.request get # # # create a POST # post_uri = uri + 'create' # post = Net::HTTP::Post.new post_uri.path # post.set_form_data 'some' => 'cool data' # # # perform the POST, the Bundler::URI is always required # response http.request post_uri, post # # Note that for GET, HEAD and other requests that do not have a body you want # to use Bundler::URI#request_uri not Bundler::URI#path. The request_uri contains the query # params which are sent in the body for other requests. # # == TLS/SSL # # TLS connections are automatically created depending upon the scheme of the # Bundler::URI. TLS connections are automatically verified against the default # certificate store for your computer. You can override this by changing # verify_mode or by specifying an alternate cert_store. # # Here are the TLS settings, see the individual methods for documentation: # # #certificate :: This client's certificate # #ca_file :: The certificate-authorities # #ca_path :: Directory with certificate-authorities # #cert_store :: An SSL certificate store # #ciphers :: List of SSl ciphers allowed # #private_key :: The client's SSL private key # #reuse_ssl_sessions :: Reuse a previously opened SSL session for a new # connection # #ssl_timeout :: Session lifetime # #ssl_version :: Which specific SSL version to use # #verify_callback :: For server certificate verification # #verify_depth :: Depth of certificate verification # #verify_mode :: How connections should be verified # # == Proxies # # A proxy can be set through #proxy= or at initialization time by providing a # second argument to ::new. The proxy may be the Bundler::URI of the proxy server or # :ENV which will consult environment variables. # # See #proxy= and #proxy_from_env for details. # # == Headers # # Headers may be specified for use in every request. #headers are appended to # any headers on the request. #override_headers replace existing headers on # the request. # # The difference between the two can be seen in setting the User-Agent. Using # http.headers['User-Agent'] = 'MyUserAgent' will send "Ruby, # MyUserAgent" while http.override_headers['User-Agent'] = # 'MyUserAgent' will send "MyUserAgent". # # == Tuning # # === Segregation # # Each Bundler::Persistent::Net::HTTP::Persistent instance has its own pool of connections. There # is no sharing with other instances (as was true in earlier versions). # # === Idle Timeout # # If a connection hasn't been used for this number of seconds it will # automatically be reset upon the next use to avoid attempting to send to a # closed connection. The default value is 5 seconds. nil means no timeout. # Set through #idle_timeout. # # Reducing this value may help avoid the "too many connection resets" error # when sending non-idempotent requests while increasing this value will cause # fewer round-trips. # # === Read Timeout # # The amount of time allowed between reading two chunks from the socket. Set # through #read_timeout # # === Max Requests # # The number of requests that should be made before opening a new connection. # Typically many keep-alive capable servers tune this to 100 or less, so the # 101st request will fail with ECONNRESET. If unset (default), this value has # no effect, if set, connections will be reset on the request after # max_requests. # # === Open Timeout # # The amount of time to wait for a connection to be opened. Set through # #open_timeout. # # === Socket Options # # Socket options may be set on newly-created connections. See #socket_options # for details. # # === Connection Termination # # If you are done using the Bundler::Persistent::Net::HTTP::Persistent instance you may shut down # all the connections in the current thread with #shutdown. This is not # recommended for normal use, it should only be used when it will be several # minutes before you make another HTTP request. # # If you are using multiple threads, call #shutdown in each thread when the # thread is done making requests. If you don't call shutdown, that's OK. # Ruby will automatically garbage collect and shutdown your HTTP connections # when the thread terminates. class Bundler::Persistent::Net::HTTP::Persistent ## # The beginning of Time EPOCH = Time.at 0 # :nodoc: ## # Is OpenSSL available? This test works with autoload HAVE_OPENSSL = defined? OpenSSL::SSL # :nodoc: ## # The default connection pool size is 1/4 the allowed open files # (ulimit -n) or 256 if your OS does not support file handle # limits (typically windows). if Process.const_defined? :RLIMIT_NOFILE open_file_limits = Process.getrlimit(Process::RLIMIT_NOFILE) # Under JRuby on Windows Process responds to `getrlimit` but returns something that does not match docs if open_file_limits.respond_to?(:first) DEFAULT_POOL_SIZE = open_file_limits.first / 4 else DEFAULT_POOL_SIZE = 256 end else DEFAULT_POOL_SIZE = 256 end ## # The version of Bundler::Persistent::Net::HTTP::Persistent you are using VERSION = '4.0.0' ## # Error class for errors raised by Bundler::Persistent::Net::HTTP::Persistent. Various # SystemCallErrors are re-raised with a human-readable message under this # class. class Error < StandardError; end ## # Use this method to detect the idle timeout of the host at +uri+. The # value returned can be used to configure #idle_timeout. +max+ controls the # maximum idle timeout to detect. # # After # # Idle timeout detection is performed by creating a connection then # performing a HEAD request in a loop until the connection terminates # waiting one additional second per loop. # # NOTE: This may not work on ruby > 1.9. def self.detect_idle_timeout uri, max = 10 uri = Bundler::URI uri unless Bundler::URI::Generic === uri uri += '/' req = Net::HTTP::Head.new uri.request_uri http = new 'net-http-persistent detect_idle_timeout' http.connection_for uri do |connection| sleep_time = 0 http = connection.http loop do response = http.request req $stderr.puts "HEAD #{uri} => #{response.code}" if $DEBUG unless Net::HTTPOK === response then raise Error, "bad response code #{response.code} detecting idle timeout" end break if sleep_time >= max sleep_time += 1 $stderr.puts "sleeping #{sleep_time}" if $DEBUG sleep sleep_time end end rescue # ignore StandardErrors, we've probably found the idle timeout. ensure return sleep_time unless $! end ## # This client's OpenSSL::X509::Certificate attr_reader :certificate ## # For Net::HTTP parity alias cert certificate ## # An SSL certificate authority. Setting this will set verify_mode to # VERIFY_PEER. attr_reader :ca_file ## # A directory of SSL certificates to be used as certificate authorities. # Setting this will set verify_mode to VERIFY_PEER. attr_reader :ca_path ## # An SSL certificate store. Setting this will override the default # certificate store. See verify_mode for more information. attr_reader :cert_store ## # The ciphers allowed for SSL connections attr_reader :ciphers ## # Sends debug_output to this IO via Net::HTTP#set_debug_output. # # Never use this method in production code, it causes a serious security # hole. attr_accessor :debug_output ## # Current connection generation attr_reader :generation # :nodoc: ## # Headers that are added to every request using Net::HTTP#add_field attr_reader :headers ## # Maps host:port to an HTTP version. This allows us to enable version # specific features. attr_reader :http_versions ## # Maximum time an unused connection can remain idle before being # automatically closed. attr_accessor :idle_timeout ## # Maximum number of requests on a connection before it is considered expired # and automatically closed. attr_accessor :max_requests ## # Number of retries to perform if a request fails. # # See also #max_retries=, Net::HTTP#max_retries=. attr_reader :max_retries ## # The value sent in the Keep-Alive header. Defaults to 30. Not needed for # HTTP/1.1 servers. # # This may not work correctly for HTTP/1.0 servers # # This method may be removed in a future version as RFC 2616 does not # require this header. attr_accessor :keep_alive ## # The name for this collection of persistent connections. attr_reader :name ## # Seconds to wait until a connection is opened. See Net::HTTP#open_timeout attr_accessor :open_timeout ## # Headers that are added to every request using Net::HTTP#[]= attr_reader :override_headers ## # This client's SSL private key attr_reader :private_key ## # For Net::HTTP parity alias key private_key ## # The URL through which requests will be proxied attr_reader :proxy_uri ## # List of host suffixes which will not be proxied attr_reader :no_proxy ## # Test-only accessor for the connection pool attr_reader :pool # :nodoc: ## # Seconds to wait until reading one block. See Net::HTTP#read_timeout attr_accessor :read_timeout ## # Seconds to wait until writing one block. See Net::HTTP#write_timeout attr_accessor :write_timeout ## # By default SSL sessions are reused to avoid extra SSL handshakes. Set # this to false if you have problems communicating with an HTTPS server # like: # # SSL_connect [...] read finished A: unexpected message (OpenSSL::SSL::SSLError) attr_accessor :reuse_ssl_sessions ## # An array of options for Socket#setsockopt. # # By default the TCP_NODELAY option is set on sockets. # # To set additional options append them to this array: # # http.socket_options << [Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1] attr_reader :socket_options ## # Current SSL connection generation attr_reader :ssl_generation # :nodoc: ## # SSL session lifetime attr_reader :ssl_timeout ## # SSL version to use. # # By default, the version will be negotiated automatically between client # and server. Ruby 1.9 and newer only. Deprecated since Ruby 2.5. attr_reader :ssl_version ## # Minimum SSL version to use, e.g. :TLS1_1 # # By default, the version will be negotiated automatically between client # and server. Ruby 2.5 and newer only. attr_reader :min_version ## # Maximum SSL version to use, e.g. :TLS1_2 # # By default, the version will be negotiated automatically between client # and server. Ruby 2.5 and newer only. attr_reader :max_version ## # Where this instance's last-use times live in the thread local variables attr_reader :timeout_key # :nodoc: ## # SSL verification callback. Used when ca_file or ca_path is set. attr_reader :verify_callback ## # Sets the depth of SSL certificate verification attr_reader :verify_depth ## # HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_PEER which verifies # the server certificate. # # If no ca_file, ca_path or cert_store is set the default system certificate # store is used. # # You can use +verify_mode+ to override any default values. attr_reader :verify_mode ## # Creates a new Bundler::Persistent::Net::HTTP::Persistent. # # Set a +name+ for fun. Your library name should be good enough, but this # otherwise has no purpose. # # +proxy+ may be set to a Bundler::URI::HTTP or :ENV to pick up proxy options from # the environment. See proxy_from_env for details. # # In order to use a Bundler::URI for the proxy you may need to do some extra work # beyond Bundler::URI parsing if the proxy requires a password: # # proxy = Bundler::URI 'http://proxy.example' # proxy.user = 'AzureDiamond' # proxy.password = 'hunter2' # # Set +pool_size+ to limit the maximum number of connections allowed. # Defaults to 1/4 the number of allowed file handles or 256 if your OS does # not support a limit on allowed file handles. You can have no more than # this many threads with active HTTP transactions. def initialize name: nil, proxy: nil, pool_size: DEFAULT_POOL_SIZE @name = name @debug_output = nil @proxy_uri = nil @no_proxy = [] @headers = {} @override_headers = {} @http_versions = {} @keep_alive = 30 @open_timeout = nil @read_timeout = nil @write_timeout = nil @idle_timeout = 5 @max_requests = nil @max_retries = 1 @socket_options = [] @ssl_generation = 0 # incremented when SSL session variables change @socket_options << [Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1] if Socket.const_defined? :TCP_NODELAY @pool = Bundler::Persistent::Net::HTTP::Persistent::Pool.new size: pool_size do |http_args| Bundler::Persistent::Net::HTTP::Persistent::Connection.new Net::HTTP, http_args, @ssl_generation end @certificate = nil @ca_file = nil @ca_path = nil @ciphers = nil @private_key = nil @ssl_timeout = nil @ssl_version = nil @min_version = nil @max_version = nil @verify_callback = nil @verify_depth = nil @verify_mode = nil @cert_store = nil @generation = 0 # incremented when proxy Bundler::URI changes if HAVE_OPENSSL then @verify_mode = OpenSSL::SSL::VERIFY_PEER @reuse_ssl_sessions = OpenSSL::SSL.const_defined? :Session end self.proxy = proxy if proxy end ## # Sets this client's OpenSSL::X509::Certificate def certificate= certificate @certificate = certificate reconnect_ssl end # For Net::HTTP parity alias cert= certificate= ## # Sets the SSL certificate authority file. def ca_file= file @ca_file = file reconnect_ssl end ## # Sets the SSL certificate authority path. def ca_path= path @ca_path = path reconnect_ssl end ## # Overrides the default SSL certificate store used for verifying # connections. def cert_store= store @cert_store = store reconnect_ssl end ## # The ciphers allowed for SSL connections def ciphers= ciphers @ciphers = ciphers reconnect_ssl end ## # Creates a new connection for +uri+ def connection_for uri use_ssl = uri.scheme.downcase == 'https' net_http_args = [uri.hostname, uri.port] # I'm unsure if uri.host or uri.hostname should be checked against # the proxy bypass list. if @proxy_uri and not proxy_bypass? uri.host, uri.port then net_http_args.concat @proxy_args else net_http_args.concat [nil, nil, nil, nil] end connection = @pool.checkout net_http_args http = connection.http connection.ressl @ssl_generation if connection.ssl_generation != @ssl_generation if not http.started? then ssl http if use_ssl start http elsif expired? connection then reset connection end http.keep_alive_timeout = @idle_timeout if @idle_timeout http.max_retries = @max_retries if http.respond_to?(:max_retries=) http.read_timeout = @read_timeout if @read_timeout http.write_timeout = @write_timeout if @write_timeout && http.respond_to?(:write_timeout=) return yield connection rescue Errno::ECONNREFUSED address = http.proxy_address || http.address port = http.proxy_port || http.port raise Error, "connection refused: #{address}:#{port}" rescue Errno::EHOSTDOWN address = http.proxy_address || http.address port = http.proxy_port || http.port raise Error, "host down: #{address}:#{port}" ensure @pool.checkin net_http_args end ## # CGI::escape wrapper def escape str CGI.escape str if str end ## # CGI::unescape wrapper def unescape str CGI.unescape str if str end ## # Returns true if the connection should be reset due to an idle timeout, or # maximum request count, false otherwise. def expired? connection return true if @max_requests && connection.requests >= @max_requests return false unless @idle_timeout return true if @idle_timeout.zero? Time.now - connection.last_use > @idle_timeout end ## # Starts the Net::HTTP +connection+ def start http http.set_debug_output @debug_output if @debug_output http.open_timeout = @open_timeout if @open_timeout http.start socket = http.instance_variable_get :@socket if socket then # for fakeweb @socket_options.each do |option| socket.io.setsockopt(*option) end end end ## # Finishes the Net::HTTP +connection+ def finish connection connection.finish connection.http.instance_variable_set :@last_communicated, nil connection.http.instance_variable_set :@ssl_session, nil unless @reuse_ssl_sessions end ## # Returns the HTTP protocol version for +uri+ def http_version uri @http_versions["#{uri.hostname}:#{uri.port}"] end ## # Adds "http://" to the String +uri+ if it is missing. def normalize_uri uri (uri =~ /^https?:/) ? uri : "http://#{uri}" end ## # Set the maximum number of retries for a request. # # Defaults to one retry. # # Set this to 0 to disable retries. def max_retries= retries retries = retries.to_int raise ArgumentError, "max_retries must be positive" if retries < 0 @max_retries = retries reconnect end ## # Sets this client's SSL private key def private_key= key @private_key = key reconnect_ssl end # For Net::HTTP parity alias key= private_key= ## # Sets the proxy server. The +proxy+ may be the Bundler::URI of the proxy server, # the symbol +:ENV+ which will read the proxy from the environment or nil to # disable use of a proxy. See #proxy_from_env for details on setting the # proxy from the environment. # # If the proxy Bundler::URI is set after requests have been made, the next request # will shut-down and re-open all connections. # # The +no_proxy+ query parameter can be used to specify hosts which shouldn't # be reached via proxy; if set it should be a comma separated list of # hostname suffixes, optionally with +:port+ appended, for example # example.com,some.host:8080. def proxy= proxy @proxy_uri = case proxy when :ENV then proxy_from_env when Bundler::URI::HTTP then proxy when nil then # ignore else raise ArgumentError, 'proxy must be :ENV or a Bundler::URI::HTTP' end @no_proxy.clear if @proxy_uri then @proxy_args = [ @proxy_uri.hostname, @proxy_uri.port, unescape(@proxy_uri.user), unescape(@proxy_uri.password), ] @proxy_connection_id = [nil, *@proxy_args].join ':' if @proxy_uri.query then @no_proxy = CGI.parse(@proxy_uri.query)['no_proxy'].join(',').downcase.split(',').map { |x| x.strip }.reject { |x| x.empty? } end end reconnect reconnect_ssl end ## # Creates a Bundler::URI for an HTTP proxy server from ENV variables. # # If +HTTP_PROXY+ is set a proxy will be returned. # # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the Bundler::URI is given the # indicated user and password unless HTTP_PROXY contains either of these in # the Bundler::URI. # # The +NO_PROXY+ ENV variable can be used to specify hosts which shouldn't # be reached via proxy; if set it should be a comma separated list of # hostname suffixes, optionally with +:port+ appended, for example # example.com,some.host:8080. When set to * no proxy will # be returned. # # For Windows users, lowercase ENV variables are preferred over uppercase ENV # variables. def proxy_from_env env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY'] return nil if env_proxy.nil? or env_proxy.empty? uri = Bundler::URI normalize_uri env_proxy env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY'] # '*' is special case for always bypass return nil if env_no_proxy == '*' if env_no_proxy then uri.query = "no_proxy=#{escape(env_no_proxy)}" end unless uri.user or uri.password then uri.user = escape ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER'] uri.password = escape ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS'] end uri end ## # Returns true when proxy should by bypassed for host. def proxy_bypass? host, port host = host.downcase host_port = [host, port].join ':' @no_proxy.each do |name| return true if host[-name.length, name.length] == name or host_port[-name.length, name.length] == name end false end ## # Forces reconnection of all HTTP connections, including TLS/SSL # connections. def reconnect @generation += 1 end ## # Forces reconnection of only TLS/SSL connections. def reconnect_ssl @ssl_generation += 1 end ## # Finishes then restarts the Net::HTTP +connection+ def reset connection http = connection.http finish connection start http rescue Errno::ECONNREFUSED e = Error.new "connection refused: #{http.address}:#{http.port}" e.set_backtrace $@ raise e rescue Errno::EHOSTDOWN e = Error.new "host down: #{http.address}:#{http.port}" e.set_backtrace $@ raise e end ## # Makes a request on +uri+. If +req+ is nil a Net::HTTP::Get is performed # against +uri+. # # If a block is passed #request behaves like Net::HTTP#request (the body of # the response will not have been read). # # +req+ must be a Net::HTTPGenericRequest subclass (see Net::HTTP for a list). def request uri, req = nil, &block uri = Bundler::URI uri req = request_setup req || uri response = nil connection_for uri do |connection| http = connection.http begin connection.requests += 1 response = http.request req, &block if req.connection_close? or (response.http_version <= '1.0' and not response.connection_keep_alive?) or response.connection_close? then finish connection end rescue Exception # make sure to close the connection when it was interrupted finish connection raise ensure connection.last_use = Time.now end end @http_versions["#{uri.hostname}:#{uri.port}"] ||= response.http_version response end ## # Creates a GET request if +req_or_uri+ is a Bundler::URI and adds headers to the # request. # # Returns the request. def request_setup req_or_uri # :nodoc: req = if req_or_uri.respond_to? 'request_uri' then Net::HTTP::Get.new req_or_uri.request_uri else req_or_uri end @headers.each do |pair| req.add_field(*pair) end @override_headers.each do |name, value| req[name] = value end unless req['Connection'] then req.add_field 'Connection', 'keep-alive' req.add_field 'Keep-Alive', @keep_alive end req end ## # Shuts down all connections # # *NOTE*: Calling shutdown for can be dangerous! # # If any thread is still using a connection it may cause an error! Call # #shutdown when you are completely done making requests! def shutdown @pool.shutdown { |http| http.finish } end ## # Enables SSL on +connection+ def ssl connection connection.use_ssl = true connection.ciphers = @ciphers if @ciphers connection.ssl_timeout = @ssl_timeout if @ssl_timeout connection.ssl_version = @ssl_version if @ssl_version connection.min_version = @min_version if @min_version connection.max_version = @max_version if @max_version connection.verify_depth = @verify_depth connection.verify_mode = @verify_mode if OpenSSL::SSL::VERIFY_PEER == OpenSSL::SSL::VERIFY_NONE and not Object.const_defined?(:I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG) then warn <<-WARNING !!!SECURITY WARNING!!! The SSL HTTP connection to: #{connection.address}:#{connection.port} !!!MAY NOT BE VERIFIED!!! On your platform your OpenSSL implementation is broken. There is no difference between the values of VERIFY_NONE and VERIFY_PEER. This means that attempting to verify the security of SSL connections may not work. This exposes you to man-in-the-middle exploits, snooping on the contents of your connection and other dangers to the security of your data. To disable this warning define the following constant at top-level in your application: I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG = nil WARNING end connection.ca_file = @ca_file if @ca_file connection.ca_path = @ca_path if @ca_path if @ca_file or @ca_path then connection.verify_mode = OpenSSL::SSL::VERIFY_PEER connection.verify_callback = @verify_callback if @verify_callback end if @certificate and @private_key then connection.cert = @certificate connection.key = @private_key end connection.cert_store = if @cert_store then @cert_store else store = OpenSSL::X509::Store.new store.set_default_paths store end end ## # SSL session lifetime def ssl_timeout= ssl_timeout @ssl_timeout = ssl_timeout reconnect_ssl end ## # SSL version to use def ssl_version= ssl_version @ssl_version = ssl_version reconnect_ssl end ## # Minimum SSL version to use def min_version= min_version @min_version = min_version reconnect_ssl end ## # maximum SSL version to use def max_version= max_version @max_version = max_version reconnect_ssl end ## # Sets the depth of SSL certificate verification def verify_depth= verify_depth @verify_depth = verify_depth reconnect_ssl end ## # Sets the HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_PEER. # # Setting this to VERIFY_NONE is a VERY BAD IDEA and should NEVER be used. # Securely transfer the correct certificate and update the default # certificate store or set the ca file instead. def verify_mode= verify_mode @verify_mode = verify_mode reconnect_ssl end ## # SSL verification callback. def verify_callback= callback @verify_callback = callback reconnect_ssl end end require_relative 'persistent/connection' require_relative 'persistent/pool' PK ]6lffggems/bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rbnu[class Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti < Bundler::ConnectionPool::TimedStack # :nodoc: ## # Returns a new hash that has arrays for keys # # Using a class method to limit the bindings referenced by the hash's # default_proc def self.hash_of_arrays # :nodoc: Hash.new { |h,k| h[k] = [] } end def initialize(size = 0, &block) super @enqueued = 0 @ques = self.class.hash_of_arrays @lru = {} @key = :"connection_args-#{object_id}" end def empty? (@created - @enqueued) >= @max end def length @max - @created + @enqueued end private def connection_stored? options = {} # :nodoc: !@ques[options[:connection_args]].empty? end def fetch_connection options = {} # :nodoc: connection_args = options[:connection_args] @enqueued -= 1 lru_update connection_args @ques[connection_args].pop end def lru_update connection_args # :nodoc: @lru.delete connection_args @lru[connection_args] = true end def shutdown_connections # :nodoc: @ques.each_key do |key| super connection_args: key end end def store_connection obj, options = {} # :nodoc: @ques[options[:connection_args]].push obj @enqueued += 1 end def try_create options = {} # :nodoc: connection_args = options[:connection_args] if @created >= @max && @enqueued >= 1 oldest, = @lru.first @lru.delete oldest @ques[oldest].pop @created -= 1 end if @created < @max @created += 1 lru_update connection_args return @create_block.call(connection_args) end end end PK ]hO8Zgems/bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rbnu[class Bundler::Persistent::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc: attr_reader :available # :nodoc: attr_reader :key # :nodoc: def initialize(options = {}, &block) super @available = Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti.new(@size, &block) @key = "current-#{@available.object_id}" end def checkin net_http_args stack = Thread.current[@key][net_http_args] ||= [] raise Bundler::ConnectionPool::Error, 'no connections are checked out' if stack.empty? conn = stack.pop if stack.empty? @available.push conn, connection_args: net_http_args Thread.current[@key].delete(net_http_args) Thread.current[@key] = nil if Thread.current[@key].empty? end nil end def checkout net_http_args stacks = Thread.current[@key] ||= {} stack = stacks[net_http_args] ||= [] if stack.empty? then conn = @available.pop connection_args: net_http_args else conn = stack.last end stack.push conn conn end def shutdown Thread.current[@key] = nil super end end require_relative 'timed_stack_multi' PK ](ц`gems/bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rbnu[## # A Net::HTTP connection wrapper that holds extra information for managing the # connection's lifetime. class Bundler::Persistent::Net::HTTP::Persistent::Connection # :nodoc: attr_accessor :http attr_accessor :last_use attr_accessor :requests attr_accessor :ssl_generation def initialize http_class, http_args, ssl_generation @http = http_class.new(*http_args) @ssl_generation = ssl_generation reset end def finish @http.finish rescue IOError ensure reset end def reset @last_use = Bundler::Persistent::Net::HTTP::Persistent::EPOCH @requests = 0 end def ressl ssl_generation @ssl_generation = ssl_generation finish end end PK ]t//Agems/bundler-2.2.24/lib/bundler/vendor/fileutils/lib/fileutils.rbnu[# frozen_string_literal: true begin require 'rbconfig' rescue LoadError # for make mjit-headers end # # = fileutils.rb # # Copyright (c) 2000-2007 Minero Aoki # # This program is free software. # You can distribute/modify this program under the same terms of ruby. # # == module Bundler::FileUtils # # Namespace for several file utility methods for copying, moving, removing, etc. # # === Module Functions # # require 'bundler/vendor/fileutils/lib/fileutils' # # Bundler::FileUtils.cd(dir, **options) # Bundler::FileUtils.cd(dir, **options) {|dir| block } # Bundler::FileUtils.pwd() # Bundler::FileUtils.mkdir(dir, **options) # Bundler::FileUtils.mkdir(list, **options) # Bundler::FileUtils.mkdir_p(dir, **options) # Bundler::FileUtils.mkdir_p(list, **options) # Bundler::FileUtils.rmdir(dir, **options) # Bundler::FileUtils.rmdir(list, **options) # Bundler::FileUtils.ln(target, link, **options) # Bundler::FileUtils.ln(targets, dir, **options) # Bundler::FileUtils.ln_s(target, link, **options) # Bundler::FileUtils.ln_s(targets, dir, **options) # Bundler::FileUtils.ln_sf(target, link, **options) # Bundler::FileUtils.cp(src, dest, **options) # Bundler::FileUtils.cp(list, dir, **options) # Bundler::FileUtils.cp_r(src, dest, **options) # Bundler::FileUtils.cp_r(list, dir, **options) # Bundler::FileUtils.mv(src, dest, **options) # Bundler::FileUtils.mv(list, dir, **options) # Bundler::FileUtils.rm(list, **options) # Bundler::FileUtils.rm_r(list, **options) # Bundler::FileUtils.rm_rf(list, **options) # Bundler::FileUtils.install(src, dest, **options) # Bundler::FileUtils.chmod(mode, list, **options) # Bundler::FileUtils.chmod_R(mode, list, **options) # Bundler::FileUtils.chown(user, group, list, **options) # Bundler::FileUtils.chown_R(user, group, list, **options) # Bundler::FileUtils.touch(list, **options) # # Possible options are: # # :force :: forced operation (rewrite files if exist, remove # directories if not empty, etc.); # :verbose :: print command to be run, in bash syntax, before # performing it; # :preserve :: preserve object's group, user and modification # time on copying; # :noop :: no changes are made (usable in combination with # :verbose which will print the command to run) # # Each method documents the options that it honours. See also ::commands, # ::options and ::options_of methods to introspect which command have which # options. # # All methods that have the concept of a "source" file or directory can take # either one file or a list of files in that argument. See the method # documentation for examples. # # There are some `low level' methods, which do not accept keyword arguments: # # Bundler::FileUtils.copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) # Bundler::FileUtils.copy_file(src, dest, preserve = false, dereference = true) # Bundler::FileUtils.copy_stream(srcstream, deststream) # Bundler::FileUtils.remove_entry(path, force = false) # Bundler::FileUtils.remove_entry_secure(path, force = false) # Bundler::FileUtils.remove_file(path, force = false) # Bundler::FileUtils.compare_file(path_a, path_b) # Bundler::FileUtils.compare_stream(stream_a, stream_b) # Bundler::FileUtils.uptodate?(file, cmp_list) # # == module Bundler::FileUtils::Verbose # # This module has all methods of Bundler::FileUtils module, but it outputs messages # before acting. This equates to passing the :verbose flag to methods # in Bundler::FileUtils. # # == module Bundler::FileUtils::NoWrite # # This module has all methods of Bundler::FileUtils module, but never changes # files/directories. This equates to passing the :noop flag to methods # in Bundler::FileUtils. # # == module Bundler::FileUtils::DryRun # # This module has all methods of Bundler::FileUtils module, but never changes # files/directories. This equates to passing the :noop and # :verbose flags to methods in Bundler::FileUtils. # module Bundler::FileUtils VERSION = "1.4.1" def self.private_module_function(name) #:nodoc: module_function name private_class_method name end # # Returns the name of the current directory. # def pwd Dir.pwd end module_function :pwd alias getwd pwd module_function :getwd # # Changes the current directory to the directory +dir+. # # If this method is called with block, resumes to the previous # working directory after the block execution has finished. # # Bundler::FileUtils.cd('/') # change directory # # Bundler::FileUtils.cd('/', verbose: true) # change directory and report it # # Bundler::FileUtils.cd('/') do # change directory # # ... # do something # end # return to original directory # def cd(dir, verbose: nil, &block) # :yield: dir fu_output_message "cd #{dir}" if verbose result = Dir.chdir(dir, &block) fu_output_message 'cd -' if verbose and block result end module_function :cd alias chdir cd module_function :chdir # # Returns true if +new+ is newer than all +old_list+. # Non-existent files are older than any file. # # Bundler::FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \ # system 'make hello.o' # def uptodate?(new, old_list) return false unless File.exist?(new) new_time = File.mtime(new) old_list.each do |old| if File.exist?(old) return false unless new_time > File.mtime(old) end end true end module_function :uptodate? def remove_trailing_slash(dir) #:nodoc: dir == '/' ? dir : dir.chomp(?/) end private_module_function :remove_trailing_slash # # Creates one or more directories. # # Bundler::FileUtils.mkdir 'test' # Bundler::FileUtils.mkdir %w(tmp data) # Bundler::FileUtils.mkdir 'notexist', noop: true # Does not really create. # Bundler::FileUtils.mkdir 'tmp', mode: 0700 # def mkdir(list, mode: nil, noop: nil, verbose: nil) list = fu_list(list) fu_output_message "mkdir #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose return if noop list.each do |dir| fu_mkdir dir, mode end end module_function :mkdir # # Creates a directory and all its parent directories. # For example, # # Bundler::FileUtils.mkdir_p '/usr/local/lib/ruby' # # causes to make following directories, if they do not exist. # # * /usr # * /usr/local # * /usr/local/lib # * /usr/local/lib/ruby # # You can pass several directories at a time in a list. # def mkdir_p(list, mode: nil, noop: nil, verbose: nil) list = fu_list(list) fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose return *list if noop list.map {|path| remove_trailing_slash(path)}.each do |path| # optimize for the most common case begin fu_mkdir path, mode next rescue SystemCallError next if File.directory?(path) end stack = [] until path == stack.last # dirname("/")=="/", dirname("C:/")=="C:/" stack.push path path = File.dirname(path) end stack.pop # root directory should exist stack.reverse_each do |dir| begin fu_mkdir dir, mode rescue SystemCallError raise unless File.directory?(dir) end end end return *list end module_function :mkdir_p alias mkpath mkdir_p alias makedirs mkdir_p module_function :mkpath module_function :makedirs def fu_mkdir(path, mode) #:nodoc: path = remove_trailing_slash(path) if mode Dir.mkdir path, mode File.chmod mode, path else Dir.mkdir path end end private_module_function :fu_mkdir # # Removes one or more directories. # # Bundler::FileUtils.rmdir 'somedir' # Bundler::FileUtils.rmdir %w(somedir anydir otherdir) # # Does not really remove directory; outputs message. # Bundler::FileUtils.rmdir 'somedir', verbose: true, noop: true # def rmdir(list, parents: nil, noop: nil, verbose: nil) list = fu_list(list) fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose return if noop list.each do |dir| Dir.rmdir(dir = remove_trailing_slash(dir)) if parents begin until (parent = File.dirname(dir)) == '.' or parent == dir dir = parent Dir.rmdir(dir) end rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT end end end end module_function :rmdir # # :call-seq: # Bundler::FileUtils.ln(target, link, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln(target, dir, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln(targets, dir, force: nil, noop: nil, verbose: nil) # # In the first form, creates a hard link +link+ which points to +target+. # If +link+ already exists, raises Errno::EEXIST. # But if the +force+ option is set, overwrites +link+. # # Bundler::FileUtils.ln 'gcc', 'cc', verbose: true # Bundler::FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs' # # In the second form, creates a link +dir/target+ pointing to +target+. # In the third form, creates several hard links in the directory +dir+, # pointing to each item in +targets+. # If +dir+ is not a directory, raises Errno::ENOTDIR. # # Bundler::FileUtils.cd '/sbin' # Bundler::FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked. # def ln(src, dest, force: nil, noop: nil, verbose: nil) fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest0(src, dest) do |s,d| remove_file d, true if force File.link s, d end end module_function :ln alias link ln module_function :link # # Hard link +src+ to +dest+. If +src+ is a directory, this method links # all its contents recursively. If +dest+ is a directory, links # +src+ to +dest/src+. # # +src+ can be a list of files. # # If +dereference_root+ is true, this method dereference tree root. # # If +remove_destination+ is true, this method removes each destination file before copy. # # Bundler::FileUtils.rm_r site_ruby + '/mylib', force: true # Bundler::FileUtils.cp_lr 'lib/', site_ruby + '/mylib' # # # Examples of linking several files to target directory. # Bundler::FileUtils.cp_lr %w(mail.rb field.rb debug/), site_ruby + '/tmail' # Bundler::FileUtils.cp_lr Dir.glob('*.rb'), '/home/aamine/lib/ruby', noop: true, verbose: true # # # If you want to link all contents of a directory instead of the # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y, # # use the following code. # Bundler::FileUtils.cp_lr 'src/.', 'dest' # cp_lr('src', 'dest') makes dest/src, but this doesn't. # def cp_lr(src, dest, noop: nil, verbose: nil, dereference_root: true, remove_destination: false) fu_output_message "cp -lr#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest(src, dest) do |s, d| link_entry s, d, dereference_root, remove_destination end end module_function :cp_lr # # :call-seq: # Bundler::FileUtils.ln_s(target, link, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln_s(target, dir, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln_s(targets, dir, force: nil, noop: nil, verbose: nil) # # In the first form, creates a symbolic link +link+ which points to +target+. # If +link+ already exists, raises Errno::EEXIST. # But if the force option is set, overwrites +link+. # # Bundler::FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby' # Bundler::FileUtils.ln_s 'verylongsourcefilename.c', 'c', force: true # # In the second form, creates a link +dir/target+ pointing to +target+. # In the third form, creates several symbolic links in the directory +dir+, # pointing to each item in +targets+. # If +dir+ is not a directory, raises Errno::ENOTDIR. # # Bundler::FileUtils.ln_s Dir.glob('/bin/*.rb'), '/home/foo/bin' # def ln_s(src, dest, force: nil, noop: nil, verbose: nil) fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest0(src, dest) do |s,d| remove_file d, true if force File.symlink s, d end end module_function :ln_s alias symlink ln_s module_function :symlink # # :call-seq: # Bundler::FileUtils.ln_sf(*args) # # Same as # # Bundler::FileUtils.ln_s(*args, force: true) # def ln_sf(src, dest, noop: nil, verbose: nil) ln_s src, dest, force: true, noop: noop, verbose: verbose end module_function :ln_sf # # Hard links a file system entry +src+ to +dest+. # If +src+ is a directory, this method links its contents recursively. # # Both of +src+ and +dest+ must be a path name. # +src+ must exist, +dest+ must not exist. # # If +dereference_root+ is true, this method dereferences the tree root. # # If +remove_destination+ is true, this method removes each destination file before copy. # def link_entry(src, dest, dereference_root = false, remove_destination = false) Entry_.new(src, nil, dereference_root).traverse do |ent| destent = Entry_.new(dest, ent.rel, false) File.unlink destent.path if remove_destination && File.file?(destent.path) ent.link destent.path end end module_function :link_entry # # Copies a file content +src+ to +dest+. If +dest+ is a directory, # copies +src+ to +dest/src+. # # If +src+ is a list of files, then +dest+ must be a directory. # # Bundler::FileUtils.cp 'eval.c', 'eval.c.org' # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6' # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', verbose: true # Bundler::FileUtils.cp 'symlink', 'dest' # copy content, "dest" is not a symlink # def cp(src, dest, preserve: nil, noop: nil, verbose: nil) fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest(src, dest) do |s, d| copy_file s, d, preserve end end module_function :cp alias copy cp module_function :copy # # Copies +src+ to +dest+. If +src+ is a directory, this method copies # all its contents recursively. If +dest+ is a directory, copies # +src+ to +dest/src+. # # +src+ can be a list of files. # # If +dereference_root+ is true, this method dereference tree root. # # If +remove_destination+ is true, this method removes each destination file before copy. # # # Installing Ruby library "mylib" under the site_ruby # Bundler::FileUtils.rm_r site_ruby + '/mylib', force: true # Bundler::FileUtils.cp_r 'lib/', site_ruby + '/mylib' # # # Examples of copying several files to target directory. # Bundler::FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail' # Bundler::FileUtils.cp_r Dir.glob('*.rb'), '/home/foo/lib/ruby', noop: true, verbose: true # # # If you want to copy all contents of a directory instead of the # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y, # # use following code. # Bundler::FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes dest/src, # # but this doesn't. # def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil, dereference_root: true, remove_destination: nil) fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest(src, dest) do |s, d| copy_entry s, d, preserve, dereference_root, remove_destination end end module_function :cp_r # # Copies a file system entry +src+ to +dest+. # If +src+ is a directory, this method copies its contents recursively. # This method preserves file types, c.f. symlink, directory... # (FIFO, device files and etc. are not supported yet) # # Both of +src+ and +dest+ must be a path name. # +src+ must exist, +dest+ must not exist. # # If +preserve+ is true, this method preserves owner, group, and # modified time. Permissions are copied regardless +preserve+. # # If +dereference_root+ is true, this method dereference tree root. # # If +remove_destination+ is true, this method removes each destination file before copy. # def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) if dereference_root src = File.realpath(src) end Entry_.new(src, nil, false).wrap_traverse(proc do |ent| destent = Entry_.new(dest, ent.rel, false) File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path)) ent.copy destent.path end, proc do |ent| destent = Entry_.new(dest, ent.rel, false) ent.copy_metadata destent.path if preserve end) end module_function :copy_entry # # Copies file contents of +src+ to +dest+. # Both of +src+ and +dest+ must be a path name. # def copy_file(src, dest, preserve = false, dereference = true) ent = Entry_.new(src, nil, dereference) ent.copy_file dest ent.copy_metadata dest if preserve end module_function :copy_file # # Copies stream +src+ to +dest+. # +src+ must respond to #read(n) and # +dest+ must respond to #write(str). # def copy_stream(src, dest) IO.copy_stream(src, dest) end module_function :copy_stream # # Moves file(s) +src+ to +dest+. If +file+ and +dest+ exist on the different # disk partition, the file is copied then the original file is removed. # # Bundler::FileUtils.mv 'badname.rb', 'goodname.rb' # Bundler::FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', force: true # no error # # Bundler::FileUtils.mv %w(junk.txt dust.txt), '/home/foo/.trash/' # Bundler::FileUtils.mv Dir.glob('test*.rb'), 'test', noop: true, verbose: true # def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest(src, dest) do |s, d| destent = Entry_.new(d, nil, true) begin if destent.exist? if destent.directory? raise Errno::EEXIST, d end end begin File.rename s, d rescue Errno::EXDEV, Errno::EPERM # move from unencrypted to encrypted dir (ext4) copy_entry s, d, true if secure remove_entry_secure s, force else remove_entry s, force end end rescue SystemCallError raise unless force end end end module_function :mv alias move mv module_function :move # # Remove file(s) specified in +list+. This method cannot remove directories. # All StandardErrors are ignored when the :force option is set. # # Bundler::FileUtils.rm %w( junk.txt dust.txt ) # Bundler::FileUtils.rm Dir.glob('*.so') # Bundler::FileUtils.rm 'NotExistFile', force: true # never raises exception # def rm(list, force: nil, noop: nil, verbose: nil) list = fu_list(list) fu_output_message "rm#{force ? ' -f' : ''} #{list.join ' '}" if verbose return if noop list.each do |path| remove_file path, force end end module_function :rm alias remove rm module_function :remove # # Equivalent to # # Bundler::FileUtils.rm(list, force: true) # def rm_f(list, noop: nil, verbose: nil) rm list, force: true, noop: noop, verbose: verbose end module_function :rm_f alias safe_unlink rm_f module_function :safe_unlink # # remove files +list+[0] +list+[1]... If +list+[n] is a directory, # removes its all contents recursively. This method ignores # StandardError when :force option is set. # # Bundler::FileUtils.rm_r Dir.glob('/tmp/*') # Bundler::FileUtils.rm_r 'some_dir', force: true # # WARNING: This method causes local vulnerability # if one of parent directories or removing directory tree are world # writable (including /tmp, whose permission is 1777), and the current # process has strong privilege such as Unix super user (root), and the # system has symbolic link. For secure removing, read the documentation # of remove_entry_secure carefully, and set :secure option to true. # Default is secure: false. # # NOTE: This method calls remove_entry_secure if :secure option is set. # See also remove_entry_secure. # def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) list = fu_list(list) fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose return if noop list.each do |path| if secure remove_entry_secure path, force else remove_entry path, force end end end module_function :rm_r # # Equivalent to # # Bundler::FileUtils.rm_r(list, force: true) # # WARNING: This method causes local vulnerability. # Read the documentation of rm_r first. # def rm_rf(list, noop: nil, verbose: nil, secure: nil) rm_r list, force: true, noop: noop, verbose: verbose, secure: secure end module_function :rm_rf alias rmtree rm_rf module_function :rmtree # # This method removes a file system entry +path+. +path+ shall be a # regular file, a directory, or something. If +path+ is a directory, # remove it recursively. This method is required to avoid TOCTTOU # (time-of-check-to-time-of-use) local security vulnerability of rm_r. # #rm_r causes security hole when: # # * Parent directory is world writable (including /tmp). # * Removing directory tree includes world writable directory. # * The system has symbolic link. # # To avoid this security hole, this method applies special preprocess. # If +path+ is a directory, this method chown(2) and chmod(2) all # removing directories. This requires the current process is the # owner of the removing whole directory tree, or is the super user (root). # # WARNING: You must ensure that *ALL* parent directories cannot be # moved by other untrusted users. For example, parent directories # should not be owned by untrusted users, and should not be world # writable except when the sticky bit set. # # WARNING: Only the owner of the removing directory tree, or Unix super # user (root) should invoke this method. Otherwise this method does not # work. # # For details of this security vulnerability, see Perl's case: # # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448 # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452 # # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100]. # def remove_entry_secure(path, force = false) unless fu_have_symlink? remove_entry path, force return end fullpath = File.expand_path(path) st = File.lstat(fullpath) unless st.directory? File.unlink fullpath return end # is a directory. parent_st = File.stat(File.dirname(fullpath)) unless parent_st.world_writable? remove_entry path, force return end unless parent_st.sticky? raise ArgumentError, "parent directory is world writable, Bundler::FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})" end # freeze tree root euid = Process.euid dot_file = fullpath + "/." begin File.open(dot_file) {|f| unless fu_stat_identical_entry?(st, f.stat) # symlink (TOC-to-TOU attack?) File.unlink fullpath return end f.chown euid, -1 f.chmod 0700 } rescue Errno::EISDIR # JRuby in non-native mode can't open files as dirs File.lstat(dot_file).tap {|fstat| unless fu_stat_identical_entry?(st, fstat) # symlink (TOC-to-TOU attack?) File.unlink fullpath return end File.chown euid, -1, dot_file File.chmod 0700, dot_file } end unless fu_stat_identical_entry?(st, File.lstat(fullpath)) # TOC-to-TOU attack? File.unlink fullpath return end # ---- tree root is frozen ---- root = Entry_.new(path) root.preorder_traverse do |ent| if ent.directory? ent.chown euid, -1 ent.chmod 0700 end end root.postorder_traverse do |ent| begin ent.remove rescue raise unless force end end rescue raise unless force end module_function :remove_entry_secure def fu_have_symlink? #:nodoc: File.symlink nil, nil rescue NotImplementedError return false rescue TypeError return true end private_module_function :fu_have_symlink? def fu_stat_identical_entry?(a, b) #:nodoc: a.dev == b.dev and a.ino == b.ino end private_module_function :fu_stat_identical_entry? # # This method removes a file system entry +path+. # +path+ might be a regular file, a directory, or something. # If +path+ is a directory, remove it recursively. # # See also remove_entry_secure. # def remove_entry(path, force = false) Entry_.new(path).postorder_traverse do |ent| begin ent.remove rescue raise unless force end end rescue raise unless force end module_function :remove_entry # # Removes a file +path+. # This method ignores StandardError if +force+ is true. # def remove_file(path, force = false) Entry_.new(path).remove_file rescue raise unless force end module_function :remove_file # # Removes a directory +dir+ and its contents recursively. # This method ignores StandardError if +force+ is true. # def remove_dir(path, force = false) remove_entry path, force # FIXME?? check if it is a directory end module_function :remove_dir # # Returns true if the contents of a file +a+ and a file +b+ are identical. # # Bundler::FileUtils.compare_file('somefile', 'somefile') #=> true # Bundler::FileUtils.compare_file('/dev/null', '/dev/urandom') #=> false # def compare_file(a, b) return false unless File.size(a) == File.size(b) File.open(a, 'rb') {|fa| File.open(b, 'rb') {|fb| return compare_stream(fa, fb) } } end module_function :compare_file alias identical? compare_file alias cmp compare_file module_function :identical? module_function :cmp # # Returns true if the contents of a stream +a+ and +b+ are identical. # def compare_stream(a, b) bsize = fu_stream_blksize(a, b) if RUBY_VERSION > "2.4" sa = String.new(capacity: bsize) sb = String.new(capacity: bsize) else sa = String.new sb = String.new end begin a.read(bsize, sa) b.read(bsize, sb) return true if sa.empty? && sb.empty? end while sa == sb false end module_function :compare_stream # # If +src+ is not same as +dest+, copies it and changes the permission # mode to +mode+. If +dest+ is a directory, destination is +dest+/+src+. # This method removes destination before copy. # # Bundler::FileUtils.install 'ruby', '/usr/local/bin/ruby', mode: 0755, verbose: true # Bundler::FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', verbose: true # def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil, noop: nil, verbose: nil) if verbose msg = +"install -c" msg << ' -p' if preserve msg << ' -m ' << mode_to_s(mode) if mode msg << " -o #{owner}" if owner msg << " -g #{group}" if group msg << ' ' << [src,dest].flatten.join(' ') fu_output_message msg end return if noop uid = fu_get_uid(owner) gid = fu_get_gid(group) fu_each_src_dest(src, dest) do |s, d| st = File.stat(s) unless File.exist?(d) and compare_file(s, d) remove_file d, true copy_file s, d File.utime st.atime, st.mtime, d if preserve File.chmod fu_mode(mode, st), d if mode File.chown uid, gid, d if uid or gid end end end module_function :install def user_mask(target) #:nodoc: target.each_char.inject(0) do |mask, chr| case chr when "u" mask | 04700 when "g" mask | 02070 when "o" mask | 01007 when "a" mask | 07777 else raise ArgumentError, "invalid `who' symbol in file mode: #{chr}" end end end private_module_function :user_mask def apply_mask(mode, user_mask, op, mode_mask) #:nodoc: case op when '=' (mode & ~user_mask) | (user_mask & mode_mask) when '+' mode | (user_mask & mode_mask) when '-' mode & ~(user_mask & mode_mask) end end private_module_function :apply_mask def symbolic_modes_to_i(mode_sym, path) #:nodoc: mode = if File::Stat === path path.mode else File.stat(path).mode end mode_sym.split(/,/).inject(mode & 07777) do |current_mode, clause| target, *actions = clause.split(/([=+-])/) raise ArgumentError, "invalid file mode: #{mode_sym}" if actions.empty? target = 'a' if target.empty? user_mask = user_mask(target) actions.each_slice(2) do |op, perm| need_apply = op == '=' mode_mask = (perm || '').each_char.inject(0) do |mask, chr| case chr when "r" mask | 0444 when "w" mask | 0222 when "x" mask | 0111 when "X" if FileTest.directory? path mask | 0111 else mask end when "s" mask | 06000 when "t" mask | 01000 when "u", "g", "o" if mask.nonzero? current_mode = apply_mask(current_mode, user_mask, op, mask) end need_apply = false copy_mask = user_mask(chr) (current_mode & copy_mask) / (copy_mask & 0111) * (user_mask & 0111) else raise ArgumentError, "invalid `perm' symbol in file mode: #{chr}" end end if mode_mask.nonzero? || need_apply current_mode = apply_mask(current_mode, user_mask, op, mode_mask) end end current_mode end end private_module_function :symbolic_modes_to_i def fu_mode(mode, path) #:nodoc: mode.is_a?(String) ? symbolic_modes_to_i(mode, path) : mode end private_module_function :fu_mode def mode_to_s(mode) #:nodoc: mode.is_a?(String) ? mode : "%o" % mode end private_module_function :mode_to_s # # Changes permission bits on the named files (in +list+) to the bit pattern # represented by +mode+. # # +mode+ is the symbolic and absolute mode can be used. # # Absolute mode is # Bundler::FileUtils.chmod 0755, 'somecommand' # Bundler::FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb) # Bundler::FileUtils.chmod 0755, '/usr/bin/ruby', verbose: true # # Symbolic mode is # Bundler::FileUtils.chmod "u=wrx,go=rx", 'somecommand' # Bundler::FileUtils.chmod "u=wr,go=rr", %w(my.rb your.rb his.rb her.rb) # Bundler::FileUtils.chmod "u=wrx,go=rx", '/usr/bin/ruby', verbose: true # # "a" :: is user, group, other mask. # "u" :: is user's mask. # "g" :: is group's mask. # "o" :: is other's mask. # "w" :: is write permission. # "r" :: is read permission. # "x" :: is execute permission. # "X" :: # is execute permission for directories only, must be used in conjunction with "+" # "s" :: is uid, gid. # "t" :: is sticky bit. # "+" :: is added to a class given the specified mode. # "-" :: Is removed from a given class given mode. # "=" :: Is the exact nature of the class will be given a specified mode. def chmod(mode, list, noop: nil, verbose: nil) list = fu_list(list) fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose return if noop list.each do |path| Entry_.new(path).chmod(fu_mode(mode, path)) end end module_function :chmod # # Changes permission bits on the named files (in +list+) # to the bit pattern represented by +mode+. # # Bundler::FileUtils.chmod_R 0700, "/tmp/app.#{$$}" # Bundler::FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}" # def chmod_R(mode, list, noop: nil, verbose: nil, force: nil) list = fu_list(list) fu_output_message sprintf('chmod -R%s %s %s', (force ? 'f' : ''), mode_to_s(mode), list.join(' ')) if verbose return if noop list.each do |root| Entry_.new(root).traverse do |ent| begin ent.chmod(fu_mode(mode, ent.path)) rescue raise unless force end end end end module_function :chmod_R # # Changes owner and group on the named files (in +list+) # to the user +user+ and the group +group+. +user+ and +group+ # may be an ID (Integer/String) or a name (String). # If +user+ or +group+ is nil, this method does not change # the attribute. # # Bundler::FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby' # Bundler::FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), verbose: true # def chown(user, group, list, noop: nil, verbose: nil) list = fu_list(list) fu_output_message sprintf('chown %s %s', (group ? "#{user}:#{group}" : user || ':'), list.join(' ')) if verbose return if noop uid = fu_get_uid(user) gid = fu_get_gid(group) list.each do |path| Entry_.new(path).chown uid, gid end end module_function :chown # # Changes owner and group on the named files (in +list+) # to the user +user+ and the group +group+ recursively. # +user+ and +group+ may be an ID (Integer/String) or # a name (String). If +user+ or +group+ is nil, this # method does not change the attribute. # # Bundler::FileUtils.chown_R 'www', 'www', '/var/www/htdocs' # Bundler::FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', verbose: true # def chown_R(user, group, list, noop: nil, verbose: nil, force: nil) list = fu_list(list) fu_output_message sprintf('chown -R%s %s %s', (force ? 'f' : ''), (group ? "#{user}:#{group}" : user || ':'), list.join(' ')) if verbose return if noop uid = fu_get_uid(user) gid = fu_get_gid(group) list.each do |root| Entry_.new(root).traverse do |ent| begin ent.chown uid, gid rescue raise unless force end end end end module_function :chown_R def fu_get_uid(user) #:nodoc: return nil unless user case user when Integer user when /\A\d+\z/ user.to_i else require 'etc' Etc.getpwnam(user) ? Etc.getpwnam(user).uid : nil end end private_module_function :fu_get_uid def fu_get_gid(group) #:nodoc: return nil unless group case group when Integer group when /\A\d+\z/ group.to_i else require 'etc' Etc.getgrnam(group) ? Etc.getgrnam(group).gid : nil end end private_module_function :fu_get_gid # # Updates modification time (mtime) and access time (atime) of file(s) in # +list+. Files are created if they don't exist. # # Bundler::FileUtils.touch 'timestamp' # Bundler::FileUtils.touch Dir.glob('*.c'); system 'make' # def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil) list = fu_list(list) t = mtime if verbose fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}" end return if noop list.each do |path| created = nocreate begin File.utime(t, t, path) rescue Errno::ENOENT raise if created File.open(path, 'a') { ; } created = true retry if t end end end module_function :touch private module StreamUtils_ private case (defined?(::RbConfig) ? ::RbConfig::CONFIG['host_os'] : ::RUBY_PLATFORM) when /mswin|mingw/ def fu_windows?; true end else def fu_windows?; false end end def fu_copy_stream0(src, dest, blksize = nil) #:nodoc: IO.copy_stream(src, dest) end def fu_stream_blksize(*streams) streams.each do |s| next unless s.respond_to?(:stat) size = fu_blksize(s.stat) return size if size end fu_default_blksize() end def fu_blksize(st) s = st.blksize return nil unless s return nil if s == 0 s end def fu_default_blksize 1024 end end include StreamUtils_ extend StreamUtils_ class Entry_ #:nodoc: internal use only include StreamUtils_ def initialize(a, b = nil, deref = false) @prefix = @rel = @path = nil if b @prefix = a @rel = b else @path = a end @deref = deref @stat = nil @lstat = nil end def inspect "\#<#{self.class} #{path()}>" end def path if @path File.path(@path) else join(@prefix, @rel) end end def prefix @prefix || @path end def rel @rel end def dereference? @deref end def exist? begin lstat true rescue Errno::ENOENT false end end def file? s = lstat! s and s.file? end def directory? s = lstat! s and s.directory? end def symlink? s = lstat! s and s.symlink? end def chardev? s = lstat! s and s.chardev? end def blockdev? s = lstat! s and s.blockdev? end def socket? s = lstat! s and s.socket? end def pipe? s = lstat! s and s.pipe? end S_IF_DOOR = 0xD000 def door? s = lstat! s and (s.mode & 0xF000 == S_IF_DOOR) end def entries opts = {} opts[:encoding] = ::Encoding::UTF_8 if fu_windows? files = if Dir.respond_to?(:children) Dir.children(path, **opts) else Dir.entries(path(), **opts) .reject {|n| n == '.' or n == '..' } end untaint = RUBY_VERSION < '2.7' files.map {|n| Entry_.new(prefix(), join(rel(), untaint ? n.untaint : n)) } end def stat return @stat if @stat if lstat() and lstat().symlink? @stat = File.stat(path()) else @stat = lstat() end @stat end def stat! return @stat if @stat if lstat! and lstat!.symlink? @stat = File.stat(path()) else @stat = lstat! end @stat rescue SystemCallError nil end def lstat if dereference? @lstat ||= File.stat(path()) else @lstat ||= File.lstat(path()) end end def lstat! lstat() rescue SystemCallError nil end def chmod(mode) if symlink? File.lchmod mode, path() if have_lchmod? else File.chmod mode, path() end end def chown(uid, gid) if symlink? File.lchown uid, gid, path() if have_lchown? else File.chown uid, gid, path() end end def link(dest) case when directory? if !File.exist?(dest) and descendant_directory?(dest, path) raise ArgumentError, "cannot link directory %s to itself %s" % [path, dest] end begin Dir.mkdir dest rescue raise unless File.directory?(dest) end else File.link path(), dest end end def copy(dest) lstat case when file? copy_file dest when directory? if !File.exist?(dest) and descendant_directory?(dest, path) raise ArgumentError, "cannot copy directory %s to itself %s" % [path, dest] end begin Dir.mkdir dest rescue raise unless File.directory?(dest) end when symlink? File.symlink File.readlink(path()), dest when chardev?, blockdev? raise "cannot handle device file" when socket? begin require 'socket' rescue LoadError raise "cannot handle socket" else raise "cannot handle socket" unless defined?(UNIXServer) end UNIXServer.new(dest).close File.chmod lstat().mode, dest when pipe? raise "cannot handle FIFO" unless File.respond_to?(:mkfifo) File.mkfifo dest, lstat().mode when door? raise "cannot handle door: #{path()}" else raise "unknown file type: #{path()}" end end def copy_file(dest) File.open(path()) do |s| File.open(dest, 'wb', s.stat.mode) do |f| IO.copy_stream(s, f) end end end def copy_metadata(path) st = lstat() if !st.symlink? File.utime st.atime, st.mtime, path end mode = st.mode begin if st.symlink? begin File.lchown st.uid, st.gid, path rescue NotImplementedError end else File.chown st.uid, st.gid, path end rescue Errno::EPERM, Errno::EACCES # clear setuid/setgid mode &= 01777 end if st.symlink? begin File.lchmod mode, path rescue NotImplementedError end else File.chmod mode, path end end def remove if directory? remove_dir1 else remove_file end end def remove_dir1 platform_support { Dir.rmdir path().chomp(?/) } end def remove_file platform_support { File.unlink path } end def platform_support return yield unless fu_windows? first_time_p = true begin yield rescue Errno::ENOENT raise rescue => err if first_time_p first_time_p = false begin File.chmod 0700, path() # Windows does not have symlink retry rescue SystemCallError end end raise err end end def preorder_traverse stack = [self] while ent = stack.pop yield ent stack.concat ent.entries.reverse if ent.directory? end end alias traverse preorder_traverse def postorder_traverse if directory? entries().each do |ent| ent.postorder_traverse do |e| yield e end end end ensure yield self end def wrap_traverse(pre, post) pre.call self if directory? entries.each do |ent| ent.wrap_traverse pre, post end end post.call self end private @@fileutils_rb_have_lchmod = nil def have_lchmod? # This is not MT-safe, but it does not matter. if @@fileutils_rb_have_lchmod == nil @@fileutils_rb_have_lchmod = check_have_lchmod? end @@fileutils_rb_have_lchmod end def check_have_lchmod? return false unless File.respond_to?(:lchmod) File.lchmod 0 return true rescue NotImplementedError return false end @@fileutils_rb_have_lchown = nil def have_lchown? # This is not MT-safe, but it does not matter. if @@fileutils_rb_have_lchown == nil @@fileutils_rb_have_lchown = check_have_lchown? end @@fileutils_rb_have_lchown end def check_have_lchown? return false unless File.respond_to?(:lchown) File.lchown nil, nil return true rescue NotImplementedError return false end def join(dir, base) return File.path(dir) if not base or base == '.' return File.path(base) if not dir or dir == '.' File.join(dir, base) end if File::ALT_SEPARATOR DIRECTORY_TERM = "(?=[/#{Regexp.quote(File::ALT_SEPARATOR)}]|\\z)" else DIRECTORY_TERM = "(?=/|\\z)" end def descendant_directory?(descendant, ascendant) if File::FNM_SYSCASE.nonzero? File.expand_path(File.dirname(descendant)).casecmp(File.expand_path(ascendant)) == 0 else File.expand_path(File.dirname(descendant)) == File.expand_path(ascendant) end end end # class Entry_ def fu_list(arg) #:nodoc: [arg].flatten.map {|path| File.path(path) } end private_module_function :fu_list def fu_each_src_dest(src, dest) #:nodoc: fu_each_src_dest0(src, dest) do |s, d| raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s, d) yield s, d end end private_module_function :fu_each_src_dest def fu_each_src_dest0(src, dest) #:nodoc: if tmp = Array.try_convert(src) tmp.each do |s| s = File.path(s) yield s, File.join(dest, File.basename(s)) end else src = File.path(src) if File.directory?(dest) yield src, File.join(dest, File.basename(src)) else yield src, File.path(dest) end end end private_module_function :fu_each_src_dest0 def fu_same?(a, b) #:nodoc: File.identical?(a, b) end private_module_function :fu_same? def fu_output_message(msg) #:nodoc: output = @fileutils_output if defined?(@fileutils_output) output ||= $stderr if defined?(@fileutils_label) msg = @fileutils_label + msg end output.puts msg end private_module_function :fu_output_message # This hash table holds command options. OPT_TABLE = {} #:nodoc: internal use only (private_instance_methods & methods(false)).inject(OPT_TABLE) {|tbl, name| (tbl[name.to_s] = instance_method(name).parameters).map! {|t, n| n if t == :key}.compact! tbl } public # # Returns an Array of names of high-level methods that accept any keyword # arguments. # # p Bundler::FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...] # def self.commands OPT_TABLE.keys end # # Returns an Array of option names. # # p Bundler::FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"] # def self.options OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s } end # # Returns true if the method +mid+ have an option +opt+. # # p Bundler::FileUtils.have_option?(:cp, :noop) #=> true # p Bundler::FileUtils.have_option?(:rm, :force) #=> true # p Bundler::FileUtils.have_option?(:rm, :preserve) #=> false # def self.have_option?(mid, opt) li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}" li.include?(opt) end # # Returns an Array of option names of the method +mid+. # # p Bundler::FileUtils.options_of(:rm) #=> ["noop", "verbose", "force"] # def self.options_of(mid) OPT_TABLE[mid.to_s].map {|sym| sym.to_s } end # # Returns an Array of methods names which have the option +opt+. # # p Bundler::FileUtils.collect_method(:preserve) #=> ["cp", "cp_r", "copy", "install"] # def self.collect_method(opt) OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) } end private LOW_METHODS = singleton_methods(false) - collect_method(:noop).map(&:intern) # :nodoc: module LowMethods # :nodoc: internal use only private def _do_nothing(*)end ::Bundler::FileUtils::LOW_METHODS.map {|name| alias_method name, :_do_nothing} end METHODS = singleton_methods() - [:private_module_function, # :nodoc: :commands, :options, :have_option?, :options_of, :collect_method] # # This module has all methods of Bundler::FileUtils module, but it outputs messages # before acting. This equates to passing the :verbose flag to # methods in Bundler::FileUtils. # module Verbose include Bundler::FileUtils names = ::Bundler::FileUtils.collect_method(:verbose) names.each do |name| module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args, **options) super(*args, **options, verbose: true) end EOS end private(*names) extend self class << self public(*::Bundler::FileUtils::METHODS) end end # # This module has all methods of Bundler::FileUtils module, but never changes # files/directories. This equates to passing the :noop flag # to methods in Bundler::FileUtils. # module NoWrite include Bundler::FileUtils include LowMethods names = ::Bundler::FileUtils.collect_method(:noop) names.each do |name| module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args, **options) super(*args, **options, noop: true) end EOS end private(*names) extend self class << self public(*::Bundler::FileUtils::METHODS) end end # # This module has all methods of Bundler::FileUtils module, but never changes # files/directories, with printing message before acting. # This equates to passing the :noop and :verbose flag # to methods in Bundler::FileUtils. # module DryRun include Bundler::FileUtils include LowMethods names = ::Bundler::FileUtils.collect_method(:noop) names.each do |name| module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args, **options) super(*args, **options, noop: true, verbose: true) end EOS end private(*names) extend self class << self public(*::Bundler::FileUtils::METHODS) end end end PK ]OU0 5gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri.rbnu[# frozen_string_literal: false # Bundler::URI is a module providing classes to handle Uniform Resource Identifiers # (RFC2396[http://tools.ietf.org/html/rfc2396]). # # == Features # # * Uniform way of handling URIs. # * Flexibility to introduce custom Bundler::URI schemes. # * Flexibility to have an alternate Bundler::URI::Parser (or just different patterns # and regexp's). # # == Basic example # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI("http://foo.com/posts?id=30&limit=5#time=1305298413") # #=> # # # uri.scheme #=> "http" # uri.host #=> "foo.com" # uri.path #=> "/posts" # uri.query #=> "id=30&limit=5" # uri.fragment #=> "time=1305298413" # # uri.to_s #=> "http://foo.com/posts?id=30&limit=5#time=1305298413" # # == Adding custom URIs # # module Bundler::URI # class RSYNC < Generic # DEFAULT_PORT = 873 # end # @@schemes['RSYNC'] = RSYNC # end # #=> Bundler::URI::RSYNC # # Bundler::URI.scheme_list # #=> {"FILE"=>Bundler::URI::File, "FTP"=>Bundler::URI::FTP, "HTTP"=>Bundler::URI::HTTP, # # "HTTPS"=>Bundler::URI::HTTPS, "LDAP"=>Bundler::URI::LDAP, "LDAPS"=>Bundler::URI::LDAPS, # # "MAILTO"=>Bundler::URI::MailTo, "RSYNC"=>Bundler::URI::RSYNC} # # uri = Bundler::URI("rsync://rsync.foo.com") # #=> # # # == RFC References # # A good place to view an RFC spec is http://www.ietf.org/rfc.html. # # Here is a list of all related RFC's: # - RFC822[http://tools.ietf.org/html/rfc822] # - RFC1738[http://tools.ietf.org/html/rfc1738] # - RFC2255[http://tools.ietf.org/html/rfc2255] # - RFC2368[http://tools.ietf.org/html/rfc2368] # - RFC2373[http://tools.ietf.org/html/rfc2373] # - RFC2396[http://tools.ietf.org/html/rfc2396] # - RFC2732[http://tools.ietf.org/html/rfc2732] # - RFC3986[http://tools.ietf.org/html/rfc3986] # # == Class tree # # - Bundler::URI::Generic (in uri/generic.rb) # - Bundler::URI::File - (in uri/file.rb) # - Bundler::URI::FTP - (in uri/ftp.rb) # - Bundler::URI::HTTP - (in uri/http.rb) # - Bundler::URI::HTTPS - (in uri/https.rb) # - Bundler::URI::LDAP - (in uri/ldap.rb) # - Bundler::URI::LDAPS - (in uri/ldaps.rb) # - Bundler::URI::MailTo - (in uri/mailto.rb) # - Bundler::URI::Parser - (in uri/common.rb) # - Bundler::URI::REGEXP - (in uri/common.rb) # - Bundler::URI::REGEXP::PATTERN - (in uri/common.rb) # - Bundler::URI::Util - (in uri/common.rb) # - Bundler::URI::Escape - (in uri/common.rb) # - Bundler::URI::Error - (in uri/common.rb) # - Bundler::URI::InvalidURIError - (in uri/common.rb) # - Bundler::URI::InvalidComponentError - (in uri/common.rb) # - Bundler::URI::BadURIError - (in uri/common.rb) # # == Copyright Info # # Author:: Akira Yamada # Documentation:: # Akira Yamada # Dmitry V. Sabanin # Vincent Batts # License:: # Copyright (c) 2001 akira yamada # You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # module Bundler::URI end require_relative 'uri/version' require_relative 'uri/common' require_relative 'uri/generic' require_relative 'uri/file' require_relative 'uri/ftp' require_relative 'uri/http' require_relative 'uri/https' require_relative 'uri/ldap' require_relative 'uri/ldaps' require_relative 'uri/mailto' PK ]M0 0 <gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/mailto.rbnu[# frozen_string_literal: false # = uri/mailto.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'generic' module Bundler::URI # # RFC6068, the mailto URL scheme. # class MailTo < Generic include REGEXP # A Default port of nil for Bundler::URI::MailTo. DEFAULT_PORT = nil # An Array of the available components for Bundler::URI::MailTo. COMPONENT = [ :scheme, :to, :headers ].freeze # :stopdoc: # "hname" and "hvalue" are encodings of an RFC 822 header name and # value, respectively. As with "to", all URL reserved characters must # be encoded. # # "#mailbox" is as specified in RFC 822 [RFC822]. This means that it # consists of zero or more comma-separated mail addresses, possibly # including "phrase" and "comment" components. Note that all URL # reserved characters in "to" must be encoded: in particular, # parentheses, commas, and the percent sign ("%"), which commonly occur # in the "mailbox" syntax. # # Within mailto URLs, the characters "?", "=", "&" are reserved. # ; RFC 6068 # hfields = "?" hfield *( "&" hfield ) # hfield = hfname "=" hfvalue # hfname = *qchar # hfvalue = *qchar # qchar = unreserved / pct-encoded / some-delims # some-delims = "!" / "$" / "'" / "(" / ")" / "*" # / "+" / "," / ";" / ":" / "@" # # ; RFC3986 # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" # pct-encoded = "%" HEXDIG HEXDIG HEADER_REGEXP = /\A(?(?:%\h\h|[!$'-.0-;@-Z_a-z~])*=(?:%\h\h|[!$'-.0-;@-Z_a-z~])*)(?:&\g)*\z/ # practical regexp for email address # https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address EMAIL_REGEXP = /\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/ # :startdoc: # # == Description # # Creates a new Bundler::URI::MailTo object from components, with syntax checking. # # Components can be provided as an Array or Hash. If an Array is used, # the components must be supplied as [to, headers]. # # If a Hash is used, the keys are the component names preceded by colons. # # The headers can be supplied as a pre-encoded string, such as # "subject=subscribe&cc=address", or as an Array of Arrays # like [['subject', 'subscribe'], ['cc', 'address']]. # # Examples: # # require 'bundler/vendor/uri/lib/uri' # # m1 = Bundler::URI::MailTo.build(['joe@example.com', 'subject=Ruby']) # m1.to_s # => "mailto:joe@example.com?subject=Ruby" # # m2 = Bundler::URI::MailTo.build(['john@example.com', [['Subject', 'Ruby'], ['Cc', 'jack@example.com']]]) # m2.to_s # => "mailto:john@example.com?Subject=Ruby&Cc=jack@example.com" # # m3 = Bundler::URI::MailTo.build({:to => 'listman@example.com', :headers => [['subject', 'subscribe']]}) # m3.to_s # => "mailto:listman@example.com?subject=subscribe" # def self.build(args) tmp = Util.make_components_hash(self, args) case tmp[:to] when Array tmp[:opaque] = tmp[:to].join(',') when String tmp[:opaque] = tmp[:to].dup else tmp[:opaque] = '' end if tmp[:headers] query = case tmp[:headers] when Array tmp[:headers].collect { |x| if x.kind_of?(Array) x[0] + '=' + x[1..-1].join else x.to_s end }.join('&') when Hash tmp[:headers].collect { |h,v| h + '=' + v }.join('&') else tmp[:headers].to_s end unless query.empty? tmp[:opaque] << '?' << query end end super(tmp) end # # == Description # # Creates a new Bundler::URI::MailTo object from generic URL components with # no syntax checking. # # This method is usually called from Bundler::URI::parse, which checks # the validity of each component. # def initialize(*arg) super(*arg) @to = nil @headers = [] # The RFC3986 parser does not normally populate opaque @opaque = "?#{@query}" if @query && !@opaque unless @opaque raise InvalidComponentError, "missing opaque part for mailto URL" end to, header = @opaque.split('?', 2) # allow semicolon as a addr-spec separator # http://support.microsoft.com/kb/820868 unless /\A(?:[^@,;]+@[^@,;]+(?:\z|[,;]))*\z/ =~ to raise InvalidComponentError, "unrecognised opaque part for mailtoURL: #{@opaque}" end if arg[10] # arg_check self.to = to self.headers = header else set_to(to) set_headers(header) end end # The primary e-mail address of the URL, as a String. attr_reader :to # E-mail headers set by the URL, as an Array of Arrays. attr_reader :headers # Checks the to +v+ component. def check_to(v) return true unless v return true if v.size == 0 v.split(/[,;]/).each do |addr| # check url safety as path-rootless if /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*\z/ !~ addr raise InvalidComponentError, "an address in 'to' is invalid as Bundler::URI #{addr.dump}" end # check addr-spec # don't s/\+/ /g addr.gsub!(/%\h\h/, Bundler::URI::TBLDECWWWCOMP_) if EMAIL_REGEXP !~ addr raise InvalidComponentError, "an address in 'to' is invalid as uri-escaped addr-spec #{addr.dump}" end end true end private :check_to # Private setter for to +v+. def set_to(v) @to = v end protected :set_to # Setter for to +v+. def to=(v) check_to(v) set_to(v) v end # Checks the headers +v+ component against either # * HEADER_REGEXP def check_headers(v) return true unless v return true if v.size == 0 if HEADER_REGEXP !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end true end private :check_headers # Private setter for headers +v+. def set_headers(v) @headers = [] if v v.split('&').each do |x| @headers << x.split(/=/, 2) end end end protected :set_headers # Setter for headers +v+. def headers=(v) check_headers(v) set_headers(v) v end # Constructs String from Bundler::URI. def to_s @scheme + ':' + if @to @to else '' end + if @headers.size > 0 '?' + @headers.collect{|x| x.join('=')}.join('&') else '' end + if @fragment '#' + @fragment else '' end end # Returns the RFC822 e-mail text equivalent of the URL, as a String. # # Example: # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("mailto:ruby-list@ruby-lang.org?Subject=subscribe&cc=myaddr") # uri.to_mailtext # # => "To: ruby-list@ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n" # def to_mailtext to = Bundler::URI.decode_www_form_component(@to) head = '' body = '' @headers.each do |x| case x[0] when 'body' body = Bundler::URI.decode_www_form_component(x[1]) when 'to' to << ', ' + Bundler::URI.decode_www_form_component(x[1]) else head << Bundler::URI.decode_www_form_component(x[0]).capitalize + ': ' + Bundler::URI.decode_www_form_component(x[1]) + "\n" end end "To: #{to} #{head} #{body} " end alias to_rfc822text to_mailtext end @@schemes['MAILTO'] = MailTo end PK ]M}:gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/file.rbnu[# frozen_string_literal: true require_relative 'generic' module Bundler::URI # # The "file" Bundler::URI is defined by RFC8089. # class File < Generic # A Default port of nil for Bundler::URI::File. DEFAULT_PORT = nil # # An Array of the available components for Bundler::URI::File. # COMPONENT = [ :scheme, :host, :path ].freeze # # == Description # # Creates a new Bundler::URI::File object from components, with syntax checking. # # The components accepted are +host+ and +path+. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the # order [host, path]. # # Examples: # # require 'bundler/vendor/uri/lib/uri' # # uri1 = Bundler::URI::File.build(['host.example.com', '/path/file.zip']) # uri1.to_s # => "file://host.example.com/path/file.zip" # # uri2 = Bundler::URI::File.build({:host => 'host.example.com', # :path => '/ruby/src'}) # uri2.to_s # => "file://host.example.com/ruby/src" # def self.build(args) tmp = Util::make_components_hash(self, args) super(tmp) end # Protected setter for the host component +v+. # # See also Bundler::URI::Generic.host=. # def set_host(v) v = "" if v.nil? || v == "localhost" @host = v end # do nothing def set_port(v) end # raise InvalidURIError def check_userinfo(user) raise Bundler::URI::InvalidURIError, "can not set userinfo for file Bundler::URI" end # raise InvalidURIError def check_user(user) raise Bundler::URI::InvalidURIError, "can not set user for file Bundler::URI" end # raise InvalidURIError def check_password(user) raise Bundler::URI::InvalidURIError, "can not set password for file Bundler::URI" end # do nothing def set_userinfo(v) end # do nothing def set_user(v) end # do nothing def set_password(v) end end @@schemes['FILE'] = File end PK ]]F֖֖=gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/generic.rbnu[# frozen_string_literal: true # = uri/generic.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'common' autoload :IPSocket, 'socket' autoload :IPAddr, 'ipaddr' module Bundler::URI # # Base class for all Bundler::URI classes. # Implements generic Bundler::URI syntax as per RFC 2396. # class Generic include Bundler::URI # # A Default port of nil for Bundler::URI::Generic. # DEFAULT_PORT = nil # # Returns default port. # def self.default_port self::DEFAULT_PORT end # # Returns default port. # def default_port self.class.default_port end # # An Array of the available components for Bundler::URI::Generic. # COMPONENT = [ :scheme, :userinfo, :host, :port, :registry, :path, :opaque, :query, :fragment ].freeze # # Components of the Bundler::URI in the order. # def self.component self::COMPONENT end USE_REGISTRY = false # :nodoc: def self.use_registry # :nodoc: self::USE_REGISTRY end # # == Synopsis # # See ::new. # # == Description # # At first, tries to create a new Bundler::URI::Generic instance using # Bundler::URI::Generic::build. But, if exception Bundler::URI::InvalidComponentError is raised, # then it does Bundler::URI::Escape.escape all Bundler::URI components and tries again. # def self.build2(args) begin return self.build(args) rescue InvalidComponentError if args.kind_of?(Array) return self.build(args.collect{|x| if x.is_a?(String) DEFAULT_PARSER.escape(x) else x end }) elsif args.kind_of?(Hash) tmp = {} args.each do |key, value| tmp[key] = if value DEFAULT_PARSER.escape(value) else value end end return self.build(tmp) end end end # # == Synopsis # # See ::new. # # == Description # # Creates a new Bundler::URI::Generic instance from components of Bundler::URI::Generic # with check. Components are: scheme, userinfo, host, port, registry, path, # opaque, query, and fragment. You can provide arguments either by an Array or a Hash. # See ::new for hash keys to use or for order of array items. # def self.build(args) if args.kind_of?(Array) && args.size == ::Bundler::URI::Generic::COMPONENT.size tmp = args.dup elsif args.kind_of?(Hash) tmp = ::Bundler::URI::Generic::COMPONENT.collect do |c| if args.include?(c) args[c] else nil end end else component = self.class.component rescue ::Bundler::URI::Generic::COMPONENT raise ArgumentError, "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})" end tmp << nil tmp << true return self.new(*tmp) end # # == Args # # +scheme+:: # Protocol scheme, i.e. 'http','ftp','mailto' and so on. # +userinfo+:: # User name and password, i.e. 'sdmitry:bla'. # +host+:: # Server host name. # +port+:: # Server port. # +registry+:: # Registry of naming authorities. # +path+:: # Path on server. # +opaque+:: # Opaque part. # +query+:: # Query data. # +fragment+:: # Part of the Bundler::URI after '#' character. # +parser+:: # Parser for internal use [Bundler::URI::DEFAULT_PARSER by default]. # +arg_check+:: # Check arguments [false by default]. # # == Description # # Creates a new Bundler::URI::Generic instance from ``generic'' components without check. # def initialize(scheme, userinfo, host, port, registry, path, opaque, query, fragment, parser = DEFAULT_PARSER, arg_check = false) @scheme = nil @user = nil @password = nil @host = nil @port = nil @path = nil @query = nil @opaque = nil @fragment = nil @parser = parser == DEFAULT_PARSER ? nil : parser if arg_check self.scheme = scheme self.userinfo = userinfo self.hostname = host self.port = port self.path = path self.query = query self.opaque = opaque self.fragment = fragment else self.set_scheme(scheme) self.set_userinfo(userinfo) self.set_host(host) self.set_port(port) self.set_path(path) self.query = query self.set_opaque(opaque) self.fragment=(fragment) end if registry raise InvalidURIError, "the scheme #{@scheme} does not accept registry part: #{registry} (or bad hostname?)" end @scheme&.freeze self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2) self.set_port(self.default_port) if self.default_port && !@port end # # Returns the scheme component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz").scheme #=> "http" # attr_reader :scheme # Returns the host component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz").host #=> "foo" # # It returns nil if no host component exists. # # Bundler::URI("mailto:foo@example.org").host #=> nil # # The component does not contain the port number. # # Bundler::URI("http://foo:8080/bar/baz").host #=> "foo" # # Since IPv6 addresses are wrapped with brackets in URIs, # this method returns IPv6 addresses wrapped with brackets. # This form is not appropriate to pass to socket methods such as TCPSocket.open. # If unwrapped host names are required, use the #hostname method. # # Bundler::URI("http://[::1]/bar/baz").host #=> "[::1]" # Bundler::URI("http://[::1]/bar/baz").hostname #=> "::1" # attr_reader :host # Returns the port component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz").port #=> 80 # Bundler::URI("http://foo:8080/bar/baz").port #=> 8080 # attr_reader :port def registry # :nodoc: nil end # Returns the path component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz").path #=> "/bar/baz" # attr_reader :path # Returns the query component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz?search=FooBar").query #=> "search=FooBar" # attr_reader :query # Returns the opaque part of the Bundler::URI. # # Bundler::URI("mailto:foo@example.org").opaque #=> "foo@example.org" # Bundler::URI("http://foo/bar/baz").opaque #=> nil # # The portion of the path that does not make use of the slash '/'. # The path typically refers to an absolute path or an opaque part. # (See RFC2396 Section 3 and 5.2.) # attr_reader :opaque # Returns the fragment component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz?search=FooBar#ponies").fragment #=> "ponies" # attr_reader :fragment # Returns the parser to be used. # # Unless a Bundler::URI::Parser is defined, DEFAULT_PARSER is used. # def parser if !defined?(@parser) || !@parser DEFAULT_PARSER else @parser || DEFAULT_PARSER end end # Replaces self by other Bundler::URI object. # def replace!(oth) if self.class != oth.class raise ArgumentError, "expected #{self.class} object" end component.each do |c| self.__send__("#{c}=", oth.__send__(c)) end end private :replace! # # Components of the Bundler::URI in the order. # def component self.class.component end # # Checks the scheme +v+ component against the Bundler::URI::Parser Regexp for :SCHEME. # def check_scheme(v) if v && parser.regexp[:SCHEME] !~ v raise InvalidComponentError, "bad component(expected scheme component): #{v}" end return true end private :check_scheme # Protected setter for the scheme component +v+. # # See also Bundler::URI::Generic.scheme=. # def set_scheme(v) @scheme = v&.downcase end protected :set_scheme # # == Args # # +v+:: # String # # == Description # # Public setter for the scheme component +v+ # (with validation). # # See also Bundler::URI::Generic.check_scheme. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.scheme = "https" # uri.to_s #=> "https://my.example.com" # def scheme=(v) check_scheme(v) set_scheme(v) v end # # Checks the +user+ and +password+. # # If +password+ is not provided, then +user+ is # split, using Bundler::URI::Generic.split_userinfo, to # pull +user+ and +password. # # See also Bundler::URI::Generic.check_user, Bundler::URI::Generic.check_password. # def check_userinfo(user, password = nil) if !password user, password = split_userinfo(user) end check_user(user) check_password(password, user) return true end private :check_userinfo # # Checks the user +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp for :USERINFO. # # Can not have a registry or opaque component defined, # with a user component defined. # def check_user(v) if @opaque raise InvalidURIError, "can not set user with opaque" end return v unless v if parser.regexp[:USERINFO] !~ v raise InvalidComponentError, "bad component(expected userinfo component or user component): #{v}" end return true end private :check_user # # Checks the password +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp for :USERINFO. # # Can not have a registry or opaque component defined, # with a user component defined. # def check_password(v, user = @user) if @opaque raise InvalidURIError, "can not set password with opaque" end return v unless v if !user raise InvalidURIError, "password component depends user component" end if parser.regexp[:USERINFO] !~ v raise InvalidComponentError, "bad password component" end return true end private :check_password # # Sets userinfo, argument is string like 'name:pass'. # def userinfo=(userinfo) if userinfo.nil? return nil end check_userinfo(*userinfo) set_userinfo(*userinfo) # returns userinfo end # # == Args # # +v+:: # String # # == Description # # Public setter for the +user+ component # (with validation). # # See also Bundler::URI::Generic.check_user. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://john:S3nsit1ve@my.example.com") # uri.user = "sam" # uri.to_s #=> "http://sam:V3ry_S3nsit1ve@my.example.com" # def user=(user) check_user(user) set_user(user) # returns user end # # == Args # # +v+:: # String # # == Description # # Public setter for the +password+ component # (with validation). # # See also Bundler::URI::Generic.check_password. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://john:S3nsit1ve@my.example.com") # uri.password = "V3ry_S3nsit1ve" # uri.to_s #=> "http://john:V3ry_S3nsit1ve@my.example.com" # def password=(password) check_password(password) set_password(password) # returns password end # Protected setter for the +user+ component, and +password+ if available # (with validation). # # See also Bundler::URI::Generic.userinfo=. # def set_userinfo(user, password = nil) unless password user, password = split_userinfo(user) end @user = user @password = password if password [@user, @password] end protected :set_userinfo # Protected setter for the user component +v+. # # See also Bundler::URI::Generic.user=. # def set_user(v) set_userinfo(v, @password) v end protected :set_user # Protected setter for the password component +v+. # # See also Bundler::URI::Generic.password=. # def set_password(v) @password = v # returns v end protected :set_password # Returns the userinfo +ui+ as [user, password] # if properly formatted as 'user:password'. def split_userinfo(ui) return nil, nil unless ui user, password = ui.split(':', 2) return user, password end private :split_userinfo # Escapes 'user:password' +v+ based on RFC 1738 section 3.1. def escape_userpass(v) parser.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/ end private :escape_userpass # Returns the userinfo, either as 'user' or 'user:password'. def userinfo if @user.nil? nil elsif @password.nil? @user else @user + ':' + @password end end # Returns the user component. def user @user end # Returns the password component. def password @password end # # Checks the host +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp for :HOST. # # Can not have a registry or opaque component defined, # with a host component defined. # def check_host(v) return v unless v if @opaque raise InvalidURIError, "can not set host with registry or opaque" elsif parser.regexp[:HOST] !~ v raise InvalidComponentError, "bad component(expected host component): #{v}" end return true end private :check_host # Protected setter for the host component +v+. # # See also Bundler::URI::Generic.host=. # def set_host(v) @host = v end protected :set_host # # == Args # # +v+:: # String # # == Description # # Public setter for the host component +v+ # (with validation). # # See also Bundler::URI::Generic.check_host. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.host = "foo.com" # uri.to_s #=> "http://foo.com" # def host=(v) check_host(v) set_host(v) v end # Extract the host part of the Bundler::URI and unwrap brackets for IPv6 addresses. # # This method is the same as Bundler::URI::Generic#host except # brackets for IPv6 (and future IP) addresses are removed. # # uri = Bundler::URI("http://[::1]/bar") # uri.hostname #=> "::1" # uri.host #=> "[::1]" # def hostname v = self.host /\A\[(.*)\]\z/ =~ v ? $1 : v end # Sets the host part of the Bundler::URI as the argument with brackets for IPv6 addresses. # # This method is the same as Bundler::URI::Generic#host= except # the argument can be a bare IPv6 address. # # uri = Bundler::URI("http://foo/bar") # uri.hostname = "::1" # uri.to_s #=> "http://[::1]/bar" # # If the argument seems to be an IPv6 address, # it is wrapped with brackets. # def hostname=(v) v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v self.host = v end # # Checks the port +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp for :PORT. # # Can not have a registry or opaque component defined, # with a port component defined. # def check_port(v) return v unless v if @opaque raise InvalidURIError, "can not set port with registry or opaque" elsif !v.kind_of?(Integer) && parser.regexp[:PORT] !~ v raise InvalidComponentError, "bad component(expected port component): #{v.inspect}" end return true end private :check_port # Protected setter for the port component +v+. # # See also Bundler::URI::Generic.port=. # def set_port(v) v = v.empty? ? nil : v.to_i unless !v || v.kind_of?(Integer) @port = v end protected :set_port # # == Args # # +v+:: # String # # == Description # # Public setter for the port component +v+ # (with validation). # # See also Bundler::URI::Generic.check_port. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.port = 8080 # uri.to_s #=> "http://my.example.com:8080" # def port=(v) check_port(v) set_port(v) port end def check_registry(v) # :nodoc: raise InvalidURIError, "can not set registry" end private :check_registry def set_registry(v) #:nodoc: raise InvalidURIError, "can not set registry" end protected :set_registry def registry=(v) raise InvalidURIError, "can not set registry" end # # Checks the path +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp # for :ABS_PATH and :REL_PATH. # # Can not have a opaque component defined, # with a path component defined. # def check_path(v) # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if v && @opaque raise InvalidURIError, "path conflicts with opaque" end # If scheme is ftp, path may be relative. # See RFC 1738 section 3.2.2, and RFC 2396. if @scheme && @scheme != "ftp" if v && v != '' && parser.regexp[:ABS_PATH] !~ v raise InvalidComponentError, "bad component(expected absolute path component): #{v}" end else if v && v != '' && parser.regexp[:ABS_PATH] !~ v && parser.regexp[:REL_PATH] !~ v raise InvalidComponentError, "bad component(expected relative path component): #{v}" end end return true end private :check_path # Protected setter for the path component +v+. # # See also Bundler::URI::Generic.path=. # def set_path(v) @path = v end protected :set_path # # == Args # # +v+:: # String # # == Description # # Public setter for the path component +v+ # (with validation). # # See also Bundler::URI::Generic.check_path. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com/pub/files") # uri.path = "/faq/" # uri.to_s #=> "http://my.example.com/faq/" # def path=(v) check_path(v) set_path(v) v end # # == Args # # +v+:: # String # # == Description # # Public setter for the query component +v+. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com/?id=25") # uri.query = "id=1" # uri.to_s #=> "http://my.example.com/?id=1" # def query=(v) return @query = nil unless v raise InvalidURIError, "query conflicts with opaque" if @opaque x = v.to_str v = x.dup if x.equal? v v.encode!(Encoding::UTF_8) rescue nil v.delete!("\t\r\n") v.force_encoding(Encoding::ASCII_8BIT) raise InvalidURIError, "invalid percent escape: #{$1}" if /(%\H\H)/n.match(v) v.gsub!(/(?!%\h\h|[!$-&(-;=?-_a-~])./n.freeze){'%%%02X' % $&.ord} v.force_encoding(Encoding::US_ASCII) @query = v end # # Checks the opaque +v+ component for RFC2396 compliance and # against the Bundler::URI::Parser Regexp for :OPAQUE. # # Can not have a host, port, user, or path component defined, # with an opaque component defined. # def check_opaque(v) return v unless v # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if @host || @port || @user || @path # userinfo = @user + ':' + @password raise InvalidURIError, "can not set opaque with host, port, userinfo or path" elsif v && parser.regexp[:OPAQUE] !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end return true end private :check_opaque # Protected setter for the opaque component +v+. # # See also Bundler::URI::Generic.opaque=. # def set_opaque(v) @opaque = v end protected :set_opaque # # == Args # # +v+:: # String # # == Description # # Public setter for the opaque component +v+ # (with validation). # # See also Bundler::URI::Generic.check_opaque. # def opaque=(v) check_opaque(v) set_opaque(v) v end # # Checks the fragment +v+ component against the Bundler::URI::Parser Regexp for :FRAGMENT. # # # == Args # # +v+:: # String # # == Description # # Public setter for the fragment component +v+ # (with validation). # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com/?id=25#time=1305212049") # uri.fragment = "time=1305212086" # uri.to_s #=> "http://my.example.com/?id=25#time=1305212086" # def fragment=(v) return @fragment = nil unless v x = v.to_str v = x.dup if x.equal? v v.encode!(Encoding::UTF_8) rescue nil v.delete!("\t\r\n") v.force_encoding(Encoding::ASCII_8BIT) v.gsub!(/(?!%\h\h|[!-~])./n){'%%%02X' % $&.ord} v.force_encoding(Encoding::US_ASCII) @fragment = v end # # Returns true if Bundler::URI is hierarchical. # # == Description # # Bundler::URI has components listed in order of decreasing significance from left to right, # see RFC3986 https://tools.ietf.org/html/rfc3986 1.2.3. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com/") # uri.hierarchical? # #=> true # uri = Bundler::URI.parse("mailto:joe@example.com") # uri.hierarchical? # #=> false # def hierarchical? if @path true else false end end # # Returns true if Bundler::URI has a scheme (e.g. http:// or https://) specified. # def absolute? if @scheme true else false end end alias absolute absolute? # # Returns true if Bundler::URI does not have a scheme (e.g. http:// or https://) specified. # def relative? !absolute? end # # Returns an Array of the path split on '/'. # def split_path(path) path.split("/", -1) end private :split_path # # Merges a base path +base+, with relative path +rel+, # returns a modified base path. # def merge_path(base, rel) # RFC2396, Section 5.2, 5) # RFC2396, Section 5.2, 6) base_path = split_path(base) rel_path = split_path(rel) # RFC2396, Section 5.2, 6), a) base_path << '' if base_path.last == '..' while i = base_path.index('..') base_path.slice!(i - 1, 2) end if (first = rel_path.first) and first.empty? base_path.clear rel_path.shift end # RFC2396, Section 5.2, 6), c) # RFC2396, Section 5.2, 6), d) rel_path.push('') if rel_path.last == '.' || rel_path.last == '..' rel_path.delete('.') # RFC2396, Section 5.2, 6), e) tmp = [] rel_path.each do |x| if x == '..' && !(tmp.empty? || tmp.last == '..') tmp.pop else tmp << x end end add_trailer_slash = !tmp.empty? if base_path.empty? base_path = [''] # keep '/' for root directory elsif add_trailer_slash base_path.pop end while x = tmp.shift if x == '..' # RFC2396, Section 4 # a .. or . in an absolute path has no special meaning base_path.pop if base_path.size > 1 else # if x == '..' # valid absolute (but abnormal) path "/../..." # else # valid absolute path # end base_path << x tmp.each {|t| base_path << t} add_trailer_slash = false break end end base_path.push('') if add_trailer_slash return base_path.join('/') end private :merge_path # # == Args # # +oth+:: # Bundler::URI or String # # == Description # # Destructive form of #merge. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.merge!("/main.rbx?page=1") # uri.to_s # => "http://my.example.com/main.rbx?page=1" # def merge!(oth) t = merge(oth) if self == t nil else replace!(t) self end end # # == Args # # +oth+:: # Bundler::URI or String # # == Description # # Merges two URIs. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.merge("/main.rbx?page=1") # # => "http://my.example.com/main.rbx?page=1" # def merge(oth) rel = parser.send(:convert_to_uri, oth) if rel.absolute? #raise BadURIError, "both Bundler::URI are absolute" if absolute? # hmm... should return oth for usability? return rel end unless self.absolute? raise BadURIError, "both Bundler::URI are relative" end base = self.dup authority = rel.userinfo || rel.host || rel.port # RFC2396, Section 5.2, 2) if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query base.fragment=(rel.fragment) if rel.fragment return base end base.query = nil base.fragment=(nil) # RFC2396, Section 5.2, 4) if !authority base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path else # RFC2396, Section 5.2, 4) base.set_path(rel.path) if rel.path end # RFC2396, Section 5.2, 7) base.set_userinfo(rel.userinfo) if rel.userinfo base.set_host(rel.host) if rel.host base.set_port(rel.port) if rel.port base.query = rel.query if rel.query base.fragment=(rel.fragment) if rel.fragment return base end # merge alias + merge # :stopdoc: def route_from_path(src, dst) case dst when src # RFC2396, Section 4.2 return '' when %r{(?:\A|/)\.\.?(?:/|\z)} # dst has abnormal absolute path, # like "/./", "/../", "/x/../", ... return dst.dup end src_path = src.scan(%r{[^/]*/}) dst_path = dst.scan(%r{[^/]*/?}) # discard same parts while !dst_path.empty? && dst_path.first == src_path.first src_path.shift dst_path.shift end tmp = dst_path.join # calculate if src_path.empty? if tmp.empty? return './' elsif dst_path.first.include?(':') # (see RFC2396 Section 5) return './' + tmp else return tmp end end return '../' * src_path.size + tmp end private :route_from_path # :startdoc: # :stopdoc: def route_from0(oth) oth = parser.send(:convert_to_uri, oth) if self.relative? raise BadURIError, "relative Bundler::URI: #{self}" end if oth.relative? raise BadURIError, "relative Bundler::URI: #{oth}" end if self.scheme != oth.scheme return self, self.dup end rel = Bundler::URI::Generic.new(nil, # it is relative Bundler::URI self.userinfo, self.host, self.port, nil, self.path, self.opaque, self.query, self.fragment, parser) if rel.userinfo != oth.userinfo || rel.host.to_s.downcase != oth.host.to_s.downcase || rel.port != oth.port if self.userinfo.nil? && self.host.nil? return self, self.dup end rel.set_port(nil) if rel.port == oth.default_port return rel, rel end rel.set_userinfo(nil) rel.set_host(nil) rel.set_port(nil) if rel.path && rel.path == oth.path rel.set_path('') rel.query = nil if rel.query == oth.query return rel, rel elsif rel.opaque && rel.opaque == oth.opaque rel.set_opaque('') rel.query = nil if rel.query == oth.query return rel, rel end # you can modify `rel', but can not `oth'. return oth, rel end private :route_from0 # :startdoc: # # == Args # # +oth+:: # Bundler::URI or String # # == Description # # Calculates relative path from oth to self. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse('http://my.example.com/main.rbx?page=1') # uri.route_from('http://my.example.com') # #=> # # def route_from(oth) # you can modify `rel', but can not `oth'. begin oth, rel = route_from0(oth) rescue raise $!.class, $!.message end if oth == rel return rel end rel.set_path(route_from_path(oth.path, self.path)) if rel.path == './' && self.query # "./?foo" -> "?foo" rel.set_path('') end return rel end alias - route_from # # == Args # # +oth+:: # Bundler::URI or String # # == Description # # Calculates relative path to oth from self. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse('http://my.example.com') # uri.route_to('http://my.example.com/main.rbx?page=1') # #=> # # def route_to(oth) parser.send(:convert_to_uri, oth).route_from(self) end # # Returns normalized Bundler::URI. # # require 'bundler/vendor/uri/lib/uri' # # Bundler::URI("HTTP://my.EXAMPLE.com").normalize # #=> # # # Normalization here means: # # * scheme and host are converted to lowercase, # * an empty path component is set to "/". # def normalize uri = dup uri.normalize! uri end # # Destructive version of #normalize. # def normalize! if path&.empty? set_path('/') end if scheme && scheme != scheme.downcase set_scheme(self.scheme.downcase) end if host && host != host.downcase set_host(self.host.downcase) end end # # Constructs String from Bundler::URI. # def to_s str = ''.dup if @scheme str << @scheme str << ':' end if @opaque str << @opaque else if @host || %w[file postgres].include?(@scheme) str << '//' end if self.userinfo str << self.userinfo str << '@' end if @host str << @host end if @port && @port != self.default_port str << ':' str << @port.to_s end str << @path if @query str << '?' str << @query end end if @fragment str << '#' str << @fragment end str end # # Compares two URIs. # def ==(oth) if self.class == oth.class self.normalize.component_ary == oth.normalize.component_ary else false end end def hash self.component_ary.hash end def eql?(oth) self.class == oth.class && parser == oth.parser && self.component_ary.eql?(oth.component_ary) end =begin --- Bundler::URI::Generic#===(oth) =end # def ===(oth) # raise NotImplementedError # end =begin =end # Returns an Array of the components defined from the COMPONENT Array. def component_ary component.collect do |x| self.send(x) end end protected :component_ary # == Args # # +components+:: # Multiple Symbol arguments defined in Bundler::URI::HTTP. # # == Description # # Selects specified components from Bundler::URI. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse('http://myuser:mypass@my.example.com/test.rbx') # uri.select(:userinfo, :host, :path) # # => ["myuser:mypass", "my.example.com", "/test.rbx"] # def select(*components) components.collect do |c| if component.include?(c) self.send(c) else raise ArgumentError, "expected of components of #{self.class} (#{self.class.component.join(', ')})" end end end def inspect "#<#{self.class} #{self}>" end # # == Args # # +v+:: # Bundler::URI or String # # == Description # # Attempts to parse other Bundler::URI +oth+, # returns [parsed_oth, self]. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.coerce("http://foo.com") # #=> [#, #] # def coerce(oth) case oth when String oth = parser.parse(oth) else super end return oth, self end # Returns a proxy Bundler::URI. # The proxy Bundler::URI is obtained from environment variables such as http_proxy, # ftp_proxy, no_proxy, etc. # If there is no proper proxy, nil is returned. # # If the optional parameter +env+ is specified, it is used instead of ENV. # # Note that capitalized variables (HTTP_PROXY, FTP_PROXY, NO_PROXY, etc.) # are examined, too. # # But http_proxy and HTTP_PROXY is treated specially under CGI environment. # It's because HTTP_PROXY may be set by Proxy: header. # So HTTP_PROXY is not used. # http_proxy is not used too if the variable is case insensitive. # CGI_HTTP_PROXY can be used instead. def find_proxy(env=ENV) raise BadURIError, "relative Bundler::URI: #{self}" if self.relative? name = self.scheme.downcase + '_proxy' proxy_uri = nil if name == 'http_proxy' && env.include?('REQUEST_METHOD') # CGI? # HTTP_PROXY conflicts with *_proxy for proxy settings and # HTTP_* for header information in CGI. # So it should be careful to use it. pairs = env.reject {|k, v| /\Ahttp_proxy\z/i !~ k } case pairs.length when 0 # no proxy setting anyway. proxy_uri = nil when 1 k, _ = pairs.shift if k == 'http_proxy' && env[k.upcase] == nil # http_proxy is safe to use because ENV is case sensitive. proxy_uri = env[name] else proxy_uri = nil end else # http_proxy is safe to use because ENV is case sensitive. proxy_uri = env.to_hash[name] end if !proxy_uri # Use CGI_HTTP_PROXY. cf. libwww-perl. proxy_uri = env["CGI_#{name.upcase}"] end elsif name == 'http_proxy' unless proxy_uri = env[name] if proxy_uri = env[name.upcase] warn 'The environment variable HTTP_PROXY is discouraged. Use http_proxy.', uplevel: 1 end end else proxy_uri = env[name] || env[name.upcase] end if proxy_uri.nil? || proxy_uri.empty? return nil end if self.hostname begin addr = IPSocket.getaddress(self.hostname) return nil if /\A127\.|\A::1\z/ =~ addr rescue SocketError end end name = 'no_proxy' if no_proxy = env[name] || env[name.upcase] return nil unless Bundler::URI::Generic.use_proxy?(self.hostname, addr, self.port, no_proxy) end Bundler::URI.parse(proxy_uri) end def self.use_proxy?(hostname, addr, port, no_proxy) # :nodoc: hostname = hostname.downcase dothostname = ".#{hostname}" no_proxy.scan(/([^:,\s]+)(?::(\d+))?/) {|p_host, p_port| if !p_port || port == p_port.to_i if p_host.start_with?('.') return false if hostname.end_with?(p_host.downcase) else return false if dothostname.end_with?(".#{p_host.downcase}") end if addr begin return false if IPAddr.new(p_host).include?(addr) rescue IPAddr::InvalidAddressError next end end end } true end end end PK ]wL{{:gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ldap.rbnu[# frozen_string_literal: false # = uri/ldap.rb # # Author:: # Takaaki Tateishi # Akira Yamada # License:: # Bundler::URI::LDAP is copyrighted free software by Takaaki Tateishi and Akira Yamada. # You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'generic' module Bundler::URI # # LDAP Bundler::URI SCHEMA (described in RFC2255). #-- # ldap:///[?[?[?[?]]]] #++ class LDAP < Generic # A Default port of 389 for Bundler::URI::LDAP. DEFAULT_PORT = 389 # An Array of the available components for Bundler::URI::LDAP. COMPONENT = [ :scheme, :host, :port, :dn, :attributes, :scope, :filter, :extensions, ].freeze # Scopes available for the starting point. # # * SCOPE_BASE - the Base DN # * SCOPE_ONE - one level under the Base DN, not including the base DN and # not including any entries under this # * SCOPE_SUB - subtrees, all entries at all levels # SCOPE = [ SCOPE_ONE = 'one', SCOPE_SUB = 'sub', SCOPE_BASE = 'base', ].freeze # # == Description # # Creates a new Bundler::URI::LDAP object from components, with syntax checking. # # The components accepted are host, port, dn, attributes, # scope, filter, and extensions. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the # order [host, port, dn, attributes, scope, filter, extensions]. # # Example: # # uri = Bundler::URI::LDAP.build({:host => 'ldap.example.com', # :dn => '/dc=example'}) # # uri = Bundler::URI::LDAP.build(["ldap.example.com", nil, # "/dc=example;dc=com", "query", nil, nil, nil]) # def self.build(args) tmp = Util::make_components_hash(self, args) if tmp[:dn] tmp[:path] = tmp[:dn] end query = [] [:extensions, :filter, :scope, :attributes].collect do |x| next if !tmp[x] && query.size == 0 query.unshift(tmp[x]) end tmp[:query] = query.join('?') return super(tmp) end # # == Description # # Creates a new Bundler::URI::LDAP object from generic Bundler::URI components as per # RFC 2396. No LDAP-specific syntax checking is performed. # # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+, # +opaque+, +query+, and +fragment+, in that order. # # Example: # # uri = Bundler::URI::LDAP.new("ldap", nil, "ldap.example.com", nil, nil, # "/dc=example;dc=com", nil, "query", nil) # # See also Bundler::URI::Generic.new. # def initialize(*arg) super(*arg) if @fragment raise InvalidURIError, 'bad LDAP URL' end parse_dn parse_query end # Private method to cleanup +dn+ from using the +path+ component attribute. def parse_dn @dn = @path[1..-1] end private :parse_dn # Private method to cleanup +attributes+, +scope+, +filter+, and +extensions+ # from using the +query+ component attribute. def parse_query @attributes = nil @scope = nil @filter = nil @extensions = nil if @query attrs, scope, filter, extensions = @query.split('?') @attributes = attrs if attrs && attrs.size > 0 @scope = scope if scope && scope.size > 0 @filter = filter if filter && filter.size > 0 @extensions = extensions if extensions && extensions.size > 0 end end private :parse_query # Private method to assemble +query+ from +attributes+, +scope+, +filter+, and +extensions+. def build_path_query @path = '/' + @dn query = [] [@extensions, @filter, @scope, @attributes].each do |x| next if !x && query.size == 0 query.unshift(x) end @query = query.join('?') end private :build_path_query # Returns dn. def dn @dn end # Private setter for dn +val+. def set_dn(val) @dn = val build_path_query @dn end protected :set_dn # Setter for dn +val+. def dn=(val) set_dn(val) val end # Returns attributes. def attributes @attributes end # Private setter for attributes +val+. def set_attributes(val) @attributes = val build_path_query @attributes end protected :set_attributes # Setter for attributes +val+. def attributes=(val) set_attributes(val) val end # Returns scope. def scope @scope end # Private setter for scope +val+. def set_scope(val) @scope = val build_path_query @scope end protected :set_scope # Setter for scope +val+. def scope=(val) set_scope(val) val end # Returns filter. def filter @filter end # Private setter for filter +val+. def set_filter(val) @filter = val build_path_query @filter end protected :set_filter # Setter for filter +val+. def filter=(val) set_filter(val) val end # Returns extensions. def extensions @extensions end # Private setter for extensions +val+. def set_extensions(val) @extensions = val build_path_query @extensions end protected :set_extensions # Setter for extensions +val+. def extensions=(val) set_extensions(val) val end # Checks if Bundler::URI has a path. # For Bundler::URI::LDAP this will return +false+. def hierarchical? false end end @@schemes['LDAP'] = LDAP end PK ]I;gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ldaps.rbnu[# frozen_string_literal: false # = uri/ldap.rb # # License:: You can redistribute it and/or modify it under the same term as Ruby. # # See Bundler::URI for general documentation # require_relative 'ldap' module Bundler::URI # The default port for LDAPS URIs is 636, and the scheme is 'ldaps:' rather # than 'ldap:'. Other than that, LDAPS URIs are identical to LDAP URIs; # see Bundler::URI::LDAP. class LDAPS < LDAP # A Default port of 636 for Bundler::URI::LDAPS DEFAULT_PORT = 636 end @@schemes['LDAPS'] = LDAPS end PK ] %%9gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ftp.rbnu[# frozen_string_literal: false # = uri/ftp.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'generic' module Bundler::URI # # FTP Bundler::URI syntax is defined by RFC1738 section 3.2. # # This class will be redesigned because of difference of implementations; # the structure of its path. draft-hoffman-ftp-uri-04 is a draft but it # is a good summary about the de facto spec. # http://tools.ietf.org/html/draft-hoffman-ftp-uri-04 # class FTP < Generic # A Default port of 21 for Bundler::URI::FTP. DEFAULT_PORT = 21 # # An Array of the available components for Bundler::URI::FTP. # COMPONENT = [ :scheme, :userinfo, :host, :port, :path, :typecode ].freeze # # Typecode is "a", "i", or "d". # # * "a" indicates a text file (the FTP command was ASCII) # * "i" indicates a binary file (FTP command IMAGE) # * "d" indicates the contents of a directory should be displayed # TYPECODE = ['a', 'i', 'd'].freeze # Typecode prefix ";type=". TYPECODE_PREFIX = ';type='.freeze def self.new2(user, password, host, port, path, typecode = nil, arg_check = true) # :nodoc: # Do not use this method! Not tested. [Bug #7301] # This methods remains just for compatibility, # Keep it undocumented until the active maintainer is assigned. typecode = nil if typecode.size == 0 if typecode && !TYPECODE.include?(typecode) raise ArgumentError, "bad typecode is specified: #{typecode}" end # do escape self.new('ftp', [user, password], host, port, nil, typecode ? path + TYPECODE_PREFIX + typecode : path, nil, nil, nil, arg_check) end # # == Description # # Creates a new Bundler::URI::FTP object from components, with syntax checking. # # The components accepted are +userinfo+, +host+, +port+, +path+, and # +typecode+. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the # order [userinfo, host, port, path, typecode]. # # If the path supplied is absolute, it will be escaped in order to # make it absolute in the Bundler::URI. # # Examples: # # require 'bundler/vendor/uri/lib/uri' # # uri1 = Bundler::URI::FTP.build(['user:password', 'ftp.example.com', nil, # '/path/file.zip', 'i']) # uri1.to_s # => "ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=i" # # uri2 = Bundler::URI::FTP.build({:host => 'ftp.example.com', # :path => 'ruby/src'}) # uri2.to_s # => "ftp://ftp.example.com/ruby/src" # def self.build(args) # Fix the incoming path to be generic URL syntax # FTP path -> URL path # foo/bar /foo/bar # /foo/bar /%2Ffoo/bar # if args.kind_of?(Array) args[3] = '/' + args[3].sub(/^\//, '%2F') else args[:path] = '/' + args[:path].sub(/^\//, '%2F') end tmp = Util::make_components_hash(self, args) if tmp[:typecode] if tmp[:typecode].size == 1 tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode] end tmp[:path] << tmp[:typecode] end return super(tmp) end # # == Description # # Creates a new Bundler::URI::FTP object from generic URL components with no # syntax checking. # # Unlike build(), this method does not escape the path component as # required by RFC1738; instead it is treated as per RFC2396. # # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+, # +opaque+, +query+, and +fragment+, in that order. # def initialize(scheme, userinfo, host, port, registry, path, opaque, query, fragment, parser = nil, arg_check = false) raise InvalidURIError unless path path = path.sub(/^\//,'') path.sub!(/^%2F/,'/') super(scheme, userinfo, host, port, registry, path, opaque, query, fragment, parser, arg_check) @typecode = nil if tmp = @path.index(TYPECODE_PREFIX) typecode = @path[tmp + TYPECODE_PREFIX.size..-1] @path = @path[0..tmp - 1] if arg_check self.typecode = typecode else self.set_typecode(typecode) end end end # typecode accessor. # # See Bundler::URI::FTP::COMPONENT. attr_reader :typecode # Validates typecode +v+, # returns +true+ or +false+. # def check_typecode(v) if TYPECODE.include?(v) return true else raise InvalidComponentError, "bad typecode(expected #{TYPECODE.join(', ')}): #{v}" end end private :check_typecode # Private setter for the typecode +v+. # # See also Bundler::URI::FTP.typecode=. # def set_typecode(v) @typecode = v end protected :set_typecode # # == Args # # +v+:: # String # # == Description # # Public setter for the typecode +v+ # (with validation). # # See also Bundler::URI::FTP.check_typecode. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("ftp://john@ftp.example.com/my_file.img") # #=> # # uri.typecode = "i" # uri # #=> # # def typecode=(typecode) check_typecode(typecode) set_typecode(typecode) typecode end def merge(oth) # :nodoc: tmp = super(oth) if self != tmp tmp.set_typecode(oth.typecode) end return tmp end # Returns the path from an FTP Bundler::URI. # # RFC 1738 specifically states that the path for an FTP Bundler::URI does not # include the / which separates the Bundler::URI path from the Bundler::URI host. Example: # # ftp://ftp.example.com/pub/ruby # # The above Bundler::URI indicates that the client should connect to # ftp.example.com then cd to pub/ruby from the initial login directory. # # If you want to cd to an absolute directory, you must include an # escaped / (%2F) in the path. Example: # # ftp://ftp.example.com/%2Fpub/ruby # # This method will then return "/pub/ruby". # def path return @path.sub(/^\//,'').sub(/^%2F/,'/') end # Private setter for the path of the Bundler::URI::FTP. def set_path(v) super("/" + v.sub(/^\//, "%2F")) end protected :set_path # Returns a String representation of the Bundler::URI::FTP. def to_s save_path = nil if @typecode save_path = @path @path = @path + TYPECODE_PREFIX + @typecode end str = super if @typecode @path = save_path end return str end end @@schemes['FTP'] = FTP end PK ]3=gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/version.rbnu[module Bundler::URI # :stopdoc: VERSION_CODE = '001000'.freeze VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze # :startdoc: end PK ]*@QQ<gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/common.rbnu[# frozen_string_literal: true #-- # = uri/common.rb # # Author:: Akira Yamada # Revision:: $Id$ # License:: # You can redistribute it and/or modify it under the same term as Ruby. # # See Bundler::URI for general documentation # require_relative "rfc2396_parser" require_relative "rfc3986_parser" module Bundler::URI REGEXP = RFC2396_REGEXP Parser = RFC2396_Parser RFC3986_PARSER = RFC3986_Parser.new # Bundler::URI::Parser.new DEFAULT_PARSER = Parser.new DEFAULT_PARSER.pattern.each_pair do |sym, str| unless REGEXP::PATTERN.const_defined?(sym) REGEXP::PATTERN.const_set(sym, str) end end DEFAULT_PARSER.regexp.each_pair do |sym, str| const_set(sym, str) end module Util # :nodoc: def make_components_hash(klass, array_hash) tmp = {} if array_hash.kind_of?(Array) && array_hash.size == klass.component.size - 1 klass.component[1..-1].each_index do |i| begin tmp[klass.component[i + 1]] = array_hash[i].clone rescue TypeError tmp[klass.component[i + 1]] = array_hash[i] end end elsif array_hash.kind_of?(Hash) array_hash.each do |key, value| begin tmp[key] = value.clone rescue TypeError tmp[key] = value end end else raise ArgumentError, "expected Array of or Hash of components of #{klass} (#{klass.component[1..-1].join(', ')})" end tmp[:scheme] = klass.to_s.sub(/\A.*::/, '').downcase return tmp end module_function :make_components_hash end # Module for escaping unsafe characters with codes. module Escape # # == Synopsis # # Bundler::URI.escape(str [, unsafe]) # # == Args # # +str+:: # String to replaces in. # +unsafe+:: # Regexp that matches all symbols that must be replaced with codes. # By default uses UNSAFE. # When this argument is a String, it represents a character set. # # == Description # # Escapes the string, replacing all unsafe characters with codes. # # This method is obsolete and should not be used. Instead, use # CGI.escape, Bundler::URI.encode_www_form or Bundler::URI.encode_www_form_component # depending on your specific use case. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # enc_uri = Bundler::URI.escape("http://example.com/?a=\11\15") # # => "http://example.com/?a=%09%0D" # # Bundler::URI.unescape(enc_uri) # # => "http://example.com/?a=\t\r" # # Bundler::URI.escape("@?@!", "!?") # # => "@%3F@%21" # def escape(*arg) warn "Bundler::URI.escape is obsolete", uplevel: 1 DEFAULT_PARSER.escape(*arg) end alias encode escape # # == Synopsis # # Bundler::URI.unescape(str) # # == Args # # +str+:: # String to unescape. # # == Description # # This method is obsolete and should not be used. Instead, use # CGI.unescape, Bundler::URI.decode_www_form or Bundler::URI.decode_www_form_component # depending on your specific use case. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # enc_uri = Bundler::URI.escape("http://example.com/?a=\11\15") # # => "http://example.com/?a=%09%0D" # # Bundler::URI.unescape(enc_uri) # # => "http://example.com/?a=\t\r" # def unescape(*arg) warn "Bundler::URI.unescape is obsolete", uplevel: 1 DEFAULT_PARSER.unescape(*arg) end alias decode unescape end # module Escape extend Escape include REGEXP @@schemes = {} # Returns a Hash of the defined schemes. def self.scheme_list @@schemes end # # Base class for all Bundler::URI exceptions. # class Error < StandardError; end # # Not a Bundler::URI. # class InvalidURIError < Error; end # # Not a Bundler::URI component. # class InvalidComponentError < Error; end # # Bundler::URI is valid, bad usage is not. # class BadURIError < Error; end # # == Synopsis # # Bundler::URI::split(uri) # # == Args # # +uri+:: # String with Bundler::URI. # # == Description # # Splits the string on following parts and returns array with result: # # * Scheme # * Userinfo # * Host # * Port # * Registry # * Path # * Opaque # * Query # * Fragment # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # Bundler::URI.split("http://www.ruby-lang.org/") # # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil] # def self.split(uri) RFC3986_PARSER.split(uri) end # # == Synopsis # # Bundler::URI::parse(uri_str) # # == Args # # +uri_str+:: # String with Bundler::URI. # # == Description # # Creates one of the Bundler::URI's subclasses instance from the string. # # == Raises # # Bundler::URI::InvalidURIError:: # Raised if Bundler::URI given is not a correct one. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://www.ruby-lang.org/") # # => # # uri.scheme # # => "http" # uri.host # # => "www.ruby-lang.org" # # It's recommended to first ::escape the provided +uri_str+ if there are any # invalid Bundler::URI characters. # def self.parse(uri) RFC3986_PARSER.parse(uri) end # # == Synopsis # # Bundler::URI::join(str[, str, ...]) # # == Args # # +str+:: # String(s) to work with, will be converted to RFC3986 URIs before merging. # # == Description # # Joins URIs. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # Bundler::URI.join("http://example.com/","main.rbx") # # => # # # Bundler::URI.join('http://example.com', 'foo') # # => # # # Bundler::URI.join('http://example.com', '/foo', '/bar') # # => # # # Bundler::URI.join('http://example.com', '/foo', 'bar') # # => # # # Bundler::URI.join('http://example.com', '/foo/', 'bar') # # => # # def self.join(*str) RFC3986_PARSER.join(*str) end # # == Synopsis # # Bundler::URI::extract(str[, schemes][,&blk]) # # == Args # # +str+:: # String to extract URIs from. # +schemes+:: # Limit Bundler::URI matching to specific schemes. # # == Description # # Extracts URIs from a string. If block given, iterates through all matched URIs. # Returns nil if block given or array with matches. # # == Usage # # require "bundler/vendor/uri/lib/uri" # # Bundler::URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.") # # => ["http://foo.example.com/bla", "mailto:test@example.com"] # def self.extract(str, schemes = nil, &block) warn "Bundler::URI.extract is obsolete", uplevel: 1 if $VERBOSE DEFAULT_PARSER.extract(str, schemes, &block) end # # == Synopsis # # Bundler::URI::regexp([match_schemes]) # # == Args # # +match_schemes+:: # Array of schemes. If given, resulting regexp matches to URIs # whose scheme is one of the match_schemes. # # == Description # # Returns a Regexp object which matches to Bundler::URI-like strings. # The Regexp object returned by this method includes arbitrary # number of capture group (parentheses). Never rely on it's number. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # # extract first Bundler::URI from html_string # html_string.slice(Bundler::URI.regexp) # # # remove ftp URIs # html_string.sub(Bundler::URI.regexp(['ftp']), '') # # # You should not rely on the number of parentheses # html_string.scan(Bundler::URI.regexp) do |*matches| # p $& # end # def self.regexp(schemes = nil) warn "Bundler::URI.regexp is obsolete", uplevel: 1 if $VERBOSE DEFAULT_PARSER.make_regexp(schemes) end TBLENCWWWCOMP_ = {} # :nodoc: 256.times do |i| TBLENCWWWCOMP_[-i.chr] = -('%%%02X' % i) end TBLENCWWWCOMP_[' '] = '+' TBLENCWWWCOMP_.freeze TBLDECWWWCOMP_ = {} # :nodoc: 256.times do |i| h, l = i>>4, i&15 TBLDECWWWCOMP_[-('%%%X%X' % [h, l])] = -i.chr TBLDECWWWCOMP_[-('%%%x%X' % [h, l])] = -i.chr TBLDECWWWCOMP_[-('%%%X%x' % [h, l])] = -i.chr TBLDECWWWCOMP_[-('%%%x%x' % [h, l])] = -i.chr end TBLDECWWWCOMP_['+'] = ' ' TBLDECWWWCOMP_.freeze # Encodes given +str+ to URL-encoded form data. # # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP # (ASCII space) to + and converts others to %XX. # # If +enc+ is given, convert +str+ to the encoding before percent encoding. # # This is an implementation of # http://www.w3.org/TR/2013/CR-html5-20130806/forms.html#url-encoded-form-data. # # See Bundler::URI.decode_www_form_component, Bundler::URI.encode_www_form. def self.encode_www_form_component(str, enc=nil) str = str.to_s.dup if str.encoding != Encoding::ASCII_8BIT if enc && enc != Encoding::ASCII_8BIT str.encode!(Encoding::UTF_8, invalid: :replace, undef: :replace) str.encode!(enc, fallback: ->(x){"&##{x.ord};"}) end str.force_encoding(Encoding::ASCII_8BIT) end str.gsub!(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_) str.force_encoding(Encoding::US_ASCII) end # Decodes given +str+ of URL-encoded form data. # # This decodes + to SP. # # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form. def self.decode_www_form_component(str, enc=Encoding::UTF_8) raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/ =~ str str.b.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc) end # Generates URL-encoded form data from given +enum+. # # This generates application/x-www-form-urlencoded data defined in HTML5 # from given an Enumerable object. # # This internally uses Bundler::URI.encode_www_form_component(str). # # This method doesn't convert the encoding of given items, so convert them # before calling this method if you want to send data as other than original # encoding or mixed encoding data. (Strings which are encoded in an HTML5 # ASCII incompatible encoding are converted to UTF-8.) # # This method doesn't handle files. When you send a file, use # multipart/form-data. # # This refers http://url.spec.whatwg.org/#concept-urlencoded-serializer # # Bundler::URI.encode_www_form([["q", "ruby"], ["lang", "en"]]) # #=> "q=ruby&lang=en" # Bundler::URI.encode_www_form("q" => "ruby", "lang" => "en") # #=> "q=ruby&lang=en" # Bundler::URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en") # #=> "q=ruby&q=perl&lang=en" # Bundler::URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]]) # #=> "q=ruby&q=perl&lang=en" # # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form. def self.encode_www_form(enum, enc=nil) enum.map do |k,v| if v.nil? encode_www_form_component(k, enc) elsif v.respond_to?(:to_ary) v.to_ary.map do |w| str = encode_www_form_component(k, enc) unless w.nil? str << '=' str << encode_www_form_component(w, enc) end end.join('&') else str = encode_www_form_component(k, enc) str << '=' str << encode_www_form_component(v, enc) end end.join('&') end # Decodes URL-encoded form data from given +str+. # # This decodes application/x-www-form-urlencoded data # and returns an array of key-value arrays. # # This refers http://url.spec.whatwg.org/#concept-urlencoded-parser, # so this supports only &-separator, and doesn't support ;-separator. # # ary = Bundler::URI.decode_www_form("a=1&a=2&b=3") # ary #=> [['a', '1'], ['a', '2'], ['b', '3']] # ary.assoc('a').last #=> '1' # ary.assoc('b').last #=> '3' # ary.rassoc('a').last #=> '2' # Hash[ary] #=> {"a"=>"2", "b"=>"3"} # # See Bundler::URI.decode_www_form_component, Bundler::URI.encode_www_form. def self.decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false) raise ArgumentError, "the input of #{self.name}.#{__method__} must be ASCII only string" unless str.ascii_only? ary = [] return ary if str.empty? enc = Encoding.find(enc) str.b.each_line(separator) do |string| string.chomp!(separator) key, sep, val = string.partition('=') if isindex if sep.empty? val = key key = +'' end isindex = false end if use__charset_ and key == '_charset_' and e = get_encoding(val) enc = e use__charset_ = false end key.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_) if val val.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_) else val = +'' end ary << [key, val] end ary.each do |k, v| k.force_encoding(enc) k.scrub! v.force_encoding(enc) v.scrub! end ary end private =begin command for WEB_ENCODINGS_ curl https://encoding.spec.whatwg.org/encodings.json| ruby -rjson -e 'H={} h={ "shift_jis"=>"Windows-31J", "euc-jp"=>"cp51932", "iso-2022-jp"=>"cp50221", "x-mac-cyrillic"=>"macCyrillic", } JSON($<.read).map{|x|x["encodings"]}.flatten.each{|x| Encoding.find(n=h.fetch(n=x["name"].downcase,n))rescue next x["labels"].each{|y|H[y]=n} } puts "{" H.each{|k,v|puts %[ #{k.dump}=>#{v.dump},]} puts "}" ' =end WEB_ENCODINGS_ = { "unicode-1-1-utf-8"=>"utf-8", "utf-8"=>"utf-8", "utf8"=>"utf-8", "866"=>"ibm866", "cp866"=>"ibm866", "csibm866"=>"ibm866", "ibm866"=>"ibm866", "csisolatin2"=>"iso-8859-2", "iso-8859-2"=>"iso-8859-2", "iso-ir-101"=>"iso-8859-2", "iso8859-2"=>"iso-8859-2", "iso88592"=>"iso-8859-2", "iso_8859-2"=>"iso-8859-2", "iso_8859-2:1987"=>"iso-8859-2", "l2"=>"iso-8859-2", "latin2"=>"iso-8859-2", "csisolatin3"=>"iso-8859-3", "iso-8859-3"=>"iso-8859-3", "iso-ir-109"=>"iso-8859-3", "iso8859-3"=>"iso-8859-3", "iso88593"=>"iso-8859-3", "iso_8859-3"=>"iso-8859-3", "iso_8859-3:1988"=>"iso-8859-3", "l3"=>"iso-8859-3", "latin3"=>"iso-8859-3", "csisolatin4"=>"iso-8859-4", "iso-8859-4"=>"iso-8859-4", "iso-ir-110"=>"iso-8859-4", "iso8859-4"=>"iso-8859-4", "iso88594"=>"iso-8859-4", "iso_8859-4"=>"iso-8859-4", "iso_8859-4:1988"=>"iso-8859-4", "l4"=>"iso-8859-4", "latin4"=>"iso-8859-4", "csisolatincyrillic"=>"iso-8859-5", "cyrillic"=>"iso-8859-5", "iso-8859-5"=>"iso-8859-5", "iso-ir-144"=>"iso-8859-5", "iso8859-5"=>"iso-8859-5", "iso88595"=>"iso-8859-5", "iso_8859-5"=>"iso-8859-5", "iso_8859-5:1988"=>"iso-8859-5", "arabic"=>"iso-8859-6", "asmo-708"=>"iso-8859-6", "csiso88596e"=>"iso-8859-6", "csiso88596i"=>"iso-8859-6", "csisolatinarabic"=>"iso-8859-6", "ecma-114"=>"iso-8859-6", "iso-8859-6"=>"iso-8859-6", "iso-8859-6-e"=>"iso-8859-6", "iso-8859-6-i"=>"iso-8859-6", "iso-ir-127"=>"iso-8859-6", "iso8859-6"=>"iso-8859-6", "iso88596"=>"iso-8859-6", "iso_8859-6"=>"iso-8859-6", "iso_8859-6:1987"=>"iso-8859-6", "csisolatingreek"=>"iso-8859-7", "ecma-118"=>"iso-8859-7", "elot_928"=>"iso-8859-7", "greek"=>"iso-8859-7", "greek8"=>"iso-8859-7", "iso-8859-7"=>"iso-8859-7", "iso-ir-126"=>"iso-8859-7", "iso8859-7"=>"iso-8859-7", "iso88597"=>"iso-8859-7", "iso_8859-7"=>"iso-8859-7", "iso_8859-7:1987"=>"iso-8859-7", "sun_eu_greek"=>"iso-8859-7", "csiso88598e"=>"iso-8859-8", "csisolatinhebrew"=>"iso-8859-8", "hebrew"=>"iso-8859-8", "iso-8859-8"=>"iso-8859-8", "iso-8859-8-e"=>"iso-8859-8", "iso-ir-138"=>"iso-8859-8", "iso8859-8"=>"iso-8859-8", "iso88598"=>"iso-8859-8", "iso_8859-8"=>"iso-8859-8", "iso_8859-8:1988"=>"iso-8859-8", "visual"=>"iso-8859-8", "csisolatin6"=>"iso-8859-10", "iso-8859-10"=>"iso-8859-10", "iso-ir-157"=>"iso-8859-10", "iso8859-10"=>"iso-8859-10", "iso885910"=>"iso-8859-10", "l6"=>"iso-8859-10", "latin6"=>"iso-8859-10", "iso-8859-13"=>"iso-8859-13", "iso8859-13"=>"iso-8859-13", "iso885913"=>"iso-8859-13", "iso-8859-14"=>"iso-8859-14", "iso8859-14"=>"iso-8859-14", "iso885914"=>"iso-8859-14", "csisolatin9"=>"iso-8859-15", "iso-8859-15"=>"iso-8859-15", "iso8859-15"=>"iso-8859-15", "iso885915"=>"iso-8859-15", "iso_8859-15"=>"iso-8859-15", "l9"=>"iso-8859-15", "iso-8859-16"=>"iso-8859-16", "cskoi8r"=>"koi8-r", "koi"=>"koi8-r", "koi8"=>"koi8-r", "koi8-r"=>"koi8-r", "koi8_r"=>"koi8-r", "koi8-ru"=>"koi8-u", "koi8-u"=>"koi8-u", "dos-874"=>"windows-874", "iso-8859-11"=>"windows-874", "iso8859-11"=>"windows-874", "iso885911"=>"windows-874", "tis-620"=>"windows-874", "windows-874"=>"windows-874", "cp1250"=>"windows-1250", "windows-1250"=>"windows-1250", "x-cp1250"=>"windows-1250", "cp1251"=>"windows-1251", "windows-1251"=>"windows-1251", "x-cp1251"=>"windows-1251", "ansi_x3.4-1968"=>"windows-1252", "ascii"=>"windows-1252", "cp1252"=>"windows-1252", "cp819"=>"windows-1252", "csisolatin1"=>"windows-1252", "ibm819"=>"windows-1252", "iso-8859-1"=>"windows-1252", "iso-ir-100"=>"windows-1252", "iso8859-1"=>"windows-1252", "iso88591"=>"windows-1252", "iso_8859-1"=>"windows-1252", "iso_8859-1:1987"=>"windows-1252", "l1"=>"windows-1252", "latin1"=>"windows-1252", "us-ascii"=>"windows-1252", "windows-1252"=>"windows-1252", "x-cp1252"=>"windows-1252", "cp1253"=>"windows-1253", "windows-1253"=>"windows-1253", "x-cp1253"=>"windows-1253", "cp1254"=>"windows-1254", "csisolatin5"=>"windows-1254", "iso-8859-9"=>"windows-1254", "iso-ir-148"=>"windows-1254", "iso8859-9"=>"windows-1254", "iso88599"=>"windows-1254", "iso_8859-9"=>"windows-1254", "iso_8859-9:1989"=>"windows-1254", "l5"=>"windows-1254", "latin5"=>"windows-1254", "windows-1254"=>"windows-1254", "x-cp1254"=>"windows-1254", "cp1255"=>"windows-1255", "windows-1255"=>"windows-1255", "x-cp1255"=>"windows-1255", "cp1256"=>"windows-1256", "windows-1256"=>"windows-1256", "x-cp1256"=>"windows-1256", "cp1257"=>"windows-1257", "windows-1257"=>"windows-1257", "x-cp1257"=>"windows-1257", "cp1258"=>"windows-1258", "windows-1258"=>"windows-1258", "x-cp1258"=>"windows-1258", "x-mac-cyrillic"=>"macCyrillic", "x-mac-ukrainian"=>"macCyrillic", "chinese"=>"gbk", "csgb2312"=>"gbk", "csiso58gb231280"=>"gbk", "gb2312"=>"gbk", "gb_2312"=>"gbk", "gb_2312-80"=>"gbk", "gbk"=>"gbk", "iso-ir-58"=>"gbk", "x-gbk"=>"gbk", "gb18030"=>"gb18030", "big5"=>"big5", "big5-hkscs"=>"big5", "cn-big5"=>"big5", "csbig5"=>"big5", "x-x-big5"=>"big5", "cseucpkdfmtjapanese"=>"cp51932", "euc-jp"=>"cp51932", "x-euc-jp"=>"cp51932", "csiso2022jp"=>"cp50221", "iso-2022-jp"=>"cp50221", "csshiftjis"=>"Windows-31J", "ms932"=>"Windows-31J", "ms_kanji"=>"Windows-31J", "shift-jis"=>"Windows-31J", "shift_jis"=>"Windows-31J", "sjis"=>"Windows-31J", "windows-31j"=>"Windows-31J", "x-sjis"=>"Windows-31J", "cseuckr"=>"euc-kr", "csksc56011987"=>"euc-kr", "euc-kr"=>"euc-kr", "iso-ir-149"=>"euc-kr", "korean"=>"euc-kr", "ks_c_5601-1987"=>"euc-kr", "ks_c_5601-1989"=>"euc-kr", "ksc5601"=>"euc-kr", "ksc_5601"=>"euc-kr", "windows-949"=>"euc-kr", "utf-16be"=>"utf-16be", "utf-16"=>"utf-16le", "utf-16le"=>"utf-16le", } # :nodoc: # :nodoc: # return encoding or nil # http://encoding.spec.whatwg.org/#concept-encoding-get def self.get_encoding(label) Encoding.find(WEB_ENCODINGS_[label.to_str.strip.downcase]) rescue nil end end # module Bundler::URI module Bundler # # Returns +uri+ converted to an Bundler::URI object. # def URI(uri) if uri.is_a?(Bundler::URI::Generic) uri elsif uri = String.try_convert(uri) Bundler::URI.parse(uri) else raise ArgumentError, "bad argument (expected Bundler::URI object or Bundler::URI string)" end end module_function :URI end PK ] :gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/http.rbnu[# frozen_string_literal: false # = uri/http.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'generic' module Bundler::URI # # The syntax of HTTP URIs is defined in RFC1738 section 3.3. # # Note that the Ruby Bundler::URI library allows HTTP URLs containing usernames and # passwords. This is not legal as per the RFC, but used to be # supported in Internet Explorer 5 and 6, before the MS04-004 security # update. See . # class HTTP < Generic # A Default port of 80 for Bundler::URI::HTTP. DEFAULT_PORT = 80 # An Array of the available components for Bundler::URI::HTTP. COMPONENT = %i[ scheme userinfo host port path query fragment ].freeze # # == Description # # Creates a new Bundler::URI::HTTP object from components, with syntax checking. # # The components accepted are userinfo, host, port, path, query, and # fragment. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the # order [userinfo, host, port, path, query, fragment]. # # Example: # # uri = Bundler::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar') # # uri = Bundler::URI::HTTP.build([nil, "www.example.com", nil, "/path", # "query", 'fragment']) # # Currently, if passed userinfo components this method generates # invalid HTTP URIs as per RFC 1738. # def self.build(args) tmp = Util.make_components_hash(self, args) super(tmp) end # # == Description # # Returns the full path for an HTTP request, as required by Net::HTTP::Get. # # If the Bundler::URI contains a query, the full path is Bundler::URI#path + '?' + Bundler::URI#query. # Otherwise, the path is simply Bundler::URI#path. # # Example: # # uri = Bundler::URI::HTTP.build(path: '/foo/bar', query: 'test=true') # uri.request_uri # => "/foo/bar?test=true" # def request_uri return unless @path url = @query ? "#@path?#@query" : @path.dup url.start_with?(?/.freeze) ? url : ?/ + url end end @@schemes['HTTP'] = HTTP end PK ]="__;gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/https.rbnu[# frozen_string_literal: false # = uri/https.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'http' module Bundler::URI # The default port for HTTPS URIs is 443, and the scheme is 'https:' rather # than 'http:'. Other than that, HTTPS URIs are identical to HTTP URIs; # see Bundler::URI::HTTP. class HTTPS < HTTP # A Default port of 443 for Bundler::URI::HTTPS DEFAULT_PORT = 443 end @@schemes['HTTPS'] = HTTPS end PK ]#TΉQQDgems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rbnu[# frozen_string_literal: false module Bundler::URI class RFC3986_Parser # :nodoc: # Bundler::URI defined in RFC3986 # this regexp is modified not to host is not empty string RFC3986_URI = /\A(?(?[A-Za-z][+\-.0-9A-Za-z]*):(?\/\/(?(?:(?(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?(?\[(?:(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{1,4}?::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?\d*))?)(?(?:\/(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?\/(?:(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g)*)?)|(?\g(?:\/\g)*)|(?))(?:\?(?[^#]*))?(?:\#(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/ RFC3986_relative_ref = /\A(?(?\/\/(?(?:(?(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?(?\[(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{1,4}?::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+)\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?\d*))?)(?(?:\/(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?\/(?:(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g)*)?)|(?(?(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g)*)|(?))(?:\?(?[^#]*))?(?:\#(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/ attr_reader :regexp def initialize @regexp = default_regexp.each_value(&:freeze).freeze end def split(uri) #:nodoc: begin uri = uri.to_str rescue NoMethodError raise InvalidURIError, "bad Bundler::URI(is not Bundler::URI?): #{uri.inspect}" end uri.ascii_only? or raise InvalidURIError, "Bundler::URI must be ascii only #{uri.dump}" if m = RFC3986_URI.match(uri) query = m["query".freeze] scheme = m["scheme".freeze] opaque = m["path-rootless".freeze] if opaque opaque << "?#{query}" if query [ scheme, nil, # userinfo nil, # host nil, # port nil, # registry nil, # path opaque, nil, # query m["fragment".freeze] ] else # normal [ scheme, m["userinfo".freeze], m["host".freeze], m["port".freeze], nil, # registry (m["path-abempty".freeze] || m["path-absolute".freeze] || m["path-empty".freeze]), nil, # opaque query, m["fragment".freeze] ] end elsif m = RFC3986_relative_ref.match(uri) [ nil, # scheme m["userinfo".freeze], m["host".freeze], m["port".freeze], nil, # registry, (m["path-abempty".freeze] || m["path-absolute".freeze] || m["path-noscheme".freeze] || m["path-empty".freeze]), nil, # opaque m["query".freeze], m["fragment".freeze] ] else raise InvalidURIError, "bad Bundler::URI(is not Bundler::URI?): #{uri.inspect}" end end def parse(uri) # :nodoc: scheme, userinfo, host, port, registry, path, opaque, query, fragment = self.split(uri) scheme_list = Bundler::URI.scheme_list if scheme && scheme_list.include?(uc = scheme.upcase) scheme_list[uc].new(scheme, userinfo, host, port, registry, path, opaque, query, fragment, self) else Generic.new(scheme, userinfo, host, port, registry, path, opaque, query, fragment, self) end end def join(*uris) # :nodoc: uris[0] = convert_to_uri(uris[0]) uris.inject :merge end @@to_s = Kernel.instance_method(:to_s) def inspect @@to_s.bind_call(self) end private def default_regexp # :nodoc: { SCHEME: /\A[A-Za-z][A-Za-z0-9+\-.]*\z/, USERINFO: /\A(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*\z/, HOST: /\A(?:(?\[(?:(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{,4}::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))\z/, ABS_PATH: /\A\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/, REL_PATH: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/, QUERY: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/, FRAGMENT: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/, OPAQUE: /\A(?:[^\/].*)?\z/, PORT: /\A[\x09\x0a\x0c\x0d ]*\d*[\x09\x0a\x0c\x0d ]*\z/, } end def convert_to_uri(uri) if uri.is_a?(Bundler::URI::Generic) uri elsif uri = String.try_convert(uri) parse(uri) else raise ArgumentError, "bad argument (expected Bundler::URI object or Bundler::URI string)" end end end # class Parser end # module Bundler::URI PK ]ٍ2G2GDgems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rbnu[# frozen_string_literal: false #-- # = uri/common.rb # # Author:: Akira Yamada # Revision:: $Id$ # License:: # You can redistribute it and/or modify it under the same term as Ruby. # # See Bundler::URI for general documentation # module Bundler::URI # # Includes Bundler::URI::REGEXP::PATTERN # module RFC2396_REGEXP # # Patterns used to parse Bundler::URI's # module PATTERN # :stopdoc: # RFC 2396 (Bundler::URI Generic Syntax) # RFC 2732 (IPv6 Literal Addresses in URL's) # RFC 2373 (IPv6 Addressing Architecture) # alpha = lowalpha | upalpha ALPHA = "a-zA-Z" # alphanum = alpha | digit ALNUM = "#{ALPHA}\\d" # hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | # "a" | "b" | "c" | "d" | "e" | "f" HEX = "a-fA-F\\d" # escaped = "%" hex hex ESCAPED = "%[#{HEX}]{2}" # mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | # "(" | ")" # unreserved = alphanum | mark UNRESERVED = "\\-_.!~*'()#{ALNUM}" # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | # "$" | "," # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | # "$" | "," | "[" | "]" (RFC 2732) RESERVED = ";/?:@&=+$,\\[\\]" # domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)" # toplabel = alpha | alpha *( alphanum | "-" ) alphanum TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)" # hostname = *( domainlabel "." ) toplabel [ "." ] HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?" # :startdoc: end # PATTERN # :startdoc: end # REGEXP # Class that parses String's into Bundler::URI's. # # It contains a Hash set of patterns and Regexp's that match and validate. # class RFC2396_Parser include RFC2396_REGEXP # # == Synopsis # # Bundler::URI::Parser.new([opts]) # # == Args # # The constructor accepts a hash as options for parser. # Keys of options are pattern names of Bundler::URI components # and values of options are pattern strings. # The constructor generates set of regexps for parsing URIs. # # You can use the following keys: # # * :ESCAPED (Bundler::URI::PATTERN::ESCAPED in default) # * :UNRESERVED (Bundler::URI::PATTERN::UNRESERVED in default) # * :DOMLABEL (Bundler::URI::PATTERN::DOMLABEL in default) # * :TOPLABEL (Bundler::URI::PATTERN::TOPLABEL in default) # * :HOSTNAME (Bundler::URI::PATTERN::HOSTNAME in default) # # == Examples # # p = Bundler::URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})") # u = p.parse("http://example.jp/%uABCD") #=> # # Bundler::URI.parse(u.to_s) #=> raises Bundler::URI::InvalidURIError # # s = "http://example.com/ABCD" # u1 = p.parse(s) #=> # # u2 = Bundler::URI.parse(s) #=> # # u1 == u2 #=> true # u1.eql?(u2) #=> false # def initialize(opts = {}) @pattern = initialize_pattern(opts) @pattern.each_value(&:freeze) @pattern.freeze @regexp = initialize_regexp(@pattern) @regexp.each_value(&:freeze) @regexp.freeze end # The Hash of patterns. # # See also Bundler::URI::Parser.initialize_pattern. attr_reader :pattern # The Hash of Regexp. # # See also Bundler::URI::Parser.initialize_regexp. attr_reader :regexp # Returns a split Bundler::URI against regexp[:ABS_URI]. def split(uri) case uri when '' # null uri when @regexp[:ABS_URI] scheme, opaque, userinfo, host, port, registry, path, query, fragment = $~[1..-1] # Bundler::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] # opaque_part = uric_no_slash *uric # abs_path = "/" path_segments # net_path = "//" authority [ abs_path ] # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] if !scheme raise InvalidURIError, "bad Bundler::URI(absolute but no scheme): #{uri}" end if !opaque && (!path && (!host && !registry)) raise InvalidURIError, "bad Bundler::URI(absolute but no path): #{uri}" end when @regexp[:REL_URI] scheme = nil opaque = nil userinfo, host, port, registry, rel_segment, abs_path, query, fragment = $~[1..-1] if rel_segment && abs_path path = rel_segment + abs_path elsif rel_segment path = rel_segment elsif abs_path path = abs_path end # Bundler::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] # net_path = "//" authority [ abs_path ] # abs_path = "/" path_segments # rel_path = rel_segment [ abs_path ] # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] else raise InvalidURIError, "bad Bundler::URI(is not Bundler::URI?): #{uri}" end path = '' if !path && !opaque # (see RFC2396 Section 5.2) ret = [ scheme, userinfo, host, port, # X registry, # X path, # Y opaque, # Y query, fragment ] return ret end # # == Args # # +uri+:: # String # # == Description # # Parses +uri+ and constructs either matching Bundler::URI scheme object # (File, FTP, HTTP, HTTPS, LDAP, LDAPS, or MailTo) or Bundler::URI::Generic. # # == Usage # # p = Bundler::URI::Parser.new # p.parse("ldap://ldap.example.com/dc=example?user=john") # #=> # # def parse(uri) scheme, userinfo, host, port, registry, path, opaque, query, fragment = self.split(uri) if scheme && Bundler::URI.scheme_list.include?(scheme.upcase) Bundler::URI.scheme_list[scheme.upcase].new(scheme, userinfo, host, port, registry, path, opaque, query, fragment, self) else Generic.new(scheme, userinfo, host, port, registry, path, opaque, query, fragment, self) end end # # == Args # # +uris+:: # an Array of Strings # # == Description # # Attempts to parse and merge a set of URIs. # def join(*uris) uris[0] = convert_to_uri(uris[0]) uris.inject :merge end # # :call-seq: # extract( str ) # extract( str, schemes ) # extract( str, schemes ) {|item| block } # # == Args # # +str+:: # String to search # +schemes+:: # Patterns to apply to +str+ # # == Description # # Attempts to parse and merge a set of URIs. # If no +block+ given, then returns the result, # else it calls +block+ for each element in result. # # See also Bundler::URI::Parser.make_regexp. # def extract(str, schemes = nil) if block_given? str.scan(make_regexp(schemes)) { yield $& } nil else result = [] str.scan(make_regexp(schemes)) { result.push $& } result end end # Returns Regexp that is default self.regexp[:ABS_URI_REF], # unless +schemes+ is provided. Then it is a Regexp.union with self.pattern[:X_ABS_URI]. def make_regexp(schemes = nil) unless schemes @regexp[:ABS_URI_REF] else /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x end end # # :call-seq: # escape( str ) # escape( str, unsafe ) # # == Args # # +str+:: # String to make safe # +unsafe+:: # Regexp to apply. Defaults to self.regexp[:UNSAFE] # # == Description # # Constructs a safe String from +str+, removing unsafe characters, # replacing them with codes. # def escape(str, unsafe = @regexp[:UNSAFE]) unless unsafe.kind_of?(Regexp) # perhaps unsafe is String object unsafe = Regexp.new("[#{Regexp.quote(unsafe)}]", false) end str.gsub(unsafe) do us = $& tmp = '' us.each_byte do |uc| tmp << sprintf('%%%02X', uc) end tmp end.force_encoding(Encoding::US_ASCII) end # # :call-seq: # unescape( str ) # unescape( str, escaped ) # # == Args # # +str+:: # String to remove escapes from # +escaped+:: # Regexp to apply. Defaults to self.regexp[:ESCAPED] # # == Description # # Removes escapes from +str+. # def unescape(str, escaped = @regexp[:ESCAPED]) enc = str.encoding enc = Encoding::UTF_8 if enc == Encoding::US_ASCII str.gsub(escaped) { [$&[1, 2]].pack('H2').force_encoding(enc) } end @@to_s = Kernel.instance_method(:to_s) def inspect @@to_s.bind_call(self) end private # Constructs the default Hash of patterns. def initialize_pattern(opts = {}) ret = {} ret[:ESCAPED] = escaped = (opts.delete(:ESCAPED) || PATTERN::ESCAPED) ret[:UNRESERVED] = unreserved = opts.delete(:UNRESERVED) || PATTERN::UNRESERVED ret[:RESERVED] = reserved = opts.delete(:RESERVED) || PATTERN::RESERVED ret[:DOMLABEL] = opts.delete(:DOMLABEL) || PATTERN::DOMLABEL ret[:TOPLABEL] = opts.delete(:TOPLABEL) || PATTERN::TOPLABEL ret[:HOSTNAME] = hostname = opts.delete(:HOSTNAME) # RFC 2396 (Bundler::URI Generic Syntax) # RFC 2732 (IPv6 Literal Addresses in URL's) # RFC 2373 (IPv6 Addressing Architecture) # uric = reserved | unreserved | escaped ret[:URIC] = uric = "(?:[#{unreserved}#{reserved}]|#{escaped})" # uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | # "&" | "=" | "+" | "$" | "," ret[:URIC_NO_SLASH] = uric_no_slash = "(?:[#{unreserved};?:@&=+$,]|#{escaped})" # query = *uric ret[:QUERY] = query = "#{uric}*" # fragment = *uric ret[:FRAGMENT] = fragment = "#{uric}*" # hostname = *( domainlabel "." ) toplabel [ "." ] # reg-name = *( unreserved / pct-encoded / sub-delims ) # RFC3986 unless hostname ret[:HOSTNAME] = hostname = "(?:[a-zA-Z0-9\\-.]|%\\h\\h)+" end # RFC 2373, APPENDIX B: # IPv6address = hexpart [ ":" IPv4address ] # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT # hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ] # hexseq = hex4 *( ":" hex4) # hex4 = 1*4HEXDIG # # XXX: This definition has a flaw. "::" + IPv4address must be # allowed too. Here is a replacement. # # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT ret[:IPV4ADDR] = ipv4addr = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}" # hex4 = 1*4HEXDIG hex4 = "[#{PATTERN::HEX}]{1,4}" # lastpart = hex4 | IPv4address lastpart = "(?:#{hex4}|#{ipv4addr})" # hexseq1 = *( hex4 ":" ) hex4 hexseq1 = "(?:#{hex4}:)*#{hex4}" # hexseq2 = *( hex4 ":" ) lastpart hexseq2 = "(?:#{hex4}:)*#{lastpart}" # IPv6address = hexseq2 | [ hexseq1 ] "::" [ hexseq2 ] ret[:IPV6ADDR] = ipv6addr = "(?:#{hexseq2}|(?:#{hexseq1})?::(?:#{hexseq2})?)" # IPv6prefix = ( hexseq1 | [ hexseq1 ] "::" [ hexseq1 ] ) "/" 1*2DIGIT # unused # ipv6reference = "[" IPv6address "]" (RFC 2732) ret[:IPV6REF] = ipv6ref = "\\[#{ipv6addr}\\]" # host = hostname | IPv4address # host = hostname | IPv4address | IPv6reference (RFC 2732) ret[:HOST] = host = "(?:#{hostname}|#{ipv4addr}|#{ipv6ref})" # port = *digit ret[:PORT] = port = '\d*' # hostport = host [ ":" port ] ret[:HOSTPORT] = hostport = "#{host}(?::#{port})?" # userinfo = *( unreserved | escaped | # ";" | ":" | "&" | "=" | "+" | "$" | "," ) ret[:USERINFO] = userinfo = "(?:[#{unreserved};:&=+$,]|#{escaped})*" # pchar = unreserved | escaped | # ":" | "@" | "&" | "=" | "+" | "$" | "," pchar = "(?:[#{unreserved}:@&=+$,]|#{escaped})" # param = *pchar param = "#{pchar}*" # segment = *pchar *( ";" param ) segment = "#{pchar}*(?:;#{param})*" # path_segments = segment *( "/" segment ) ret[:PATH_SEGMENTS] = path_segments = "#{segment}(?:/#{segment})*" # server = [ [ userinfo "@" ] hostport ] server = "(?:#{userinfo}@)?#{hostport}" # reg_name = 1*( unreserved | escaped | "$" | "," | # ";" | ":" | "@" | "&" | "=" | "+" ) ret[:REG_NAME] = reg_name = "(?:[#{unreserved}$,;:@&=+]|#{escaped})+" # authority = server | reg_name authority = "(?:#{server}|#{reg_name})" # rel_segment = 1*( unreserved | escaped | # ";" | "@" | "&" | "=" | "+" | "$" | "," ) ret[:REL_SEGMENT] = rel_segment = "(?:[#{unreserved};@&=+$,]|#{escaped})+" # scheme = alpha *( alpha | digit | "+" | "-" | "." ) ret[:SCHEME] = scheme = "[#{PATTERN::ALPHA}][\\-+.#{PATTERN::ALPHA}\\d]*" # abs_path = "/" path_segments ret[:ABS_PATH] = abs_path = "/#{path_segments}" # rel_path = rel_segment [ abs_path ] ret[:REL_PATH] = rel_path = "#{rel_segment}(?:#{abs_path})?" # net_path = "//" authority [ abs_path ] ret[:NET_PATH] = net_path = "//#{authority}(?:#{abs_path})?" # hier_part = ( net_path | abs_path ) [ "?" query ] ret[:HIER_PART] = hier_part = "(?:#{net_path}|#{abs_path})(?:\\?(?:#{query}))?" # opaque_part = uric_no_slash *uric ret[:OPAQUE_PART] = opaque_part = "#{uric_no_slash}#{uric}*" # absoluteURI = scheme ":" ( hier_part | opaque_part ) ret[:ABS_URI] = abs_uri = "#{scheme}:(?:#{hier_part}|#{opaque_part})" # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] ret[:REL_URI] = rel_uri = "(?:#{net_path}|#{abs_path}|#{rel_path})(?:\\?#{query})?" # Bundler::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] ret[:URI_REF] = "(?:#{abs_uri}|#{rel_uri})?(?:##{fragment})?" ret[:X_ABS_URI] = " (#{scheme}): (?# 1: scheme) (?: (#{opaque_part}) (?# 2: opaque) | (?:(?: //(?: (?:(?:(#{userinfo})@)? (?# 3: userinfo) (?:(#{host})(?::(\\d*))?))? (?# 4: host, 5: port) | (#{reg_name}) (?# 6: registry) ) | (?!//)) (?# XXX: '//' is the mark for hostport) (#{abs_path})? (?# 7: path) )(?:\\?(#{query}))? (?# 8: query) ) (?:\\#(#{fragment}))? (?# 9: fragment) " ret[:X_REL_URI] = " (?: (?: // (?: (?:(#{userinfo})@)? (?# 1: userinfo) (#{host})?(?::(\\d*))? (?# 2: host, 3: port) | (#{reg_name}) (?# 4: registry) ) ) | (#{rel_segment}) (?# 5: rel_segment) )? (#{abs_path})? (?# 6: abs_path) (?:\\?(#{query}))? (?# 7: query) (?:\\#(#{fragment}))? (?# 8: fragment) " ret end # Constructs the default Hash of Regexp's. def initialize_regexp(pattern) ret = {} # for Bundler::URI::split ret[:ABS_URI] = Regexp.new('\A\s*' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED) ret[:REL_URI] = Regexp.new('\A\s*' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED) # for Bundler::URI::extract ret[:URI_REF] = Regexp.new(pattern[:URI_REF]) ret[:ABS_URI_REF] = Regexp.new(pattern[:X_ABS_URI], Regexp::EXTENDED) ret[:REL_URI_REF] = Regexp.new(pattern[:X_REL_URI], Regexp::EXTENDED) # for Bundler::URI::escape/unescape ret[:ESCAPED] = Regexp.new(pattern[:ESCAPED]) ret[:UNSAFE] = Regexp.new("[^#{pattern[:UNRESERVED]}#{pattern[:RESERVED]}]") # for Generic#initialize ret[:SCHEME] = Regexp.new("\\A#{pattern[:SCHEME]}\\z") ret[:USERINFO] = Regexp.new("\\A#{pattern[:USERINFO]}\\z") ret[:HOST] = Regexp.new("\\A#{pattern[:HOST]}\\z") ret[:PORT] = Regexp.new("\\A#{pattern[:PORT]}\\z") ret[:OPAQUE] = Regexp.new("\\A#{pattern[:OPAQUE_PART]}\\z") ret[:REGISTRY] = Regexp.new("\\A#{pattern[:REG_NAME]}\\z") ret[:ABS_PATH] = Regexp.new("\\A#{pattern[:ABS_PATH]}\\z") ret[:REL_PATH] = Regexp.new("\\A#{pattern[:REL_PATH]}\\z") ret[:QUERY] = Regexp.new("\\A#{pattern[:QUERY]}\\z") ret[:FRAGMENT] = Regexp.new("\\A#{pattern[:FRAGMENT]}\\z") ret end def convert_to_uri(uri) if uri.is_a?(Bundler::URI::Generic) uri elsif uri = String.try_convert(uri) parse(uri) else raise ArgumentError, "bad argument (expected Bundler::URI object or Bundler::URI string)" end end end # class Parser end # module Bundler::URI PK ] II;gems/bundler-2.2.24/lib/bundler/vendor/tmpdir/lib/tmpdir.rbnu[# frozen_string_literal: true # # tmpdir - retrieve temporary directory path # # $Id$ # require_relative '../../fileutils/lib/fileutils' begin require 'etc.so' rescue LoadError # rescue LoadError for miniruby end class Bundler::Dir < Dir @systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp' ## # Returns the operating system's temporary file path. def self.tmpdir tmp = nil ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', @systmpdir], ['/tmp']*2, ['.']*2].each do |name, dir = ENV[name]| next if !dir dir = File.expand_path(dir) stat = File.stat(dir) rescue next case when !stat.directory? warn "#{name} is not a directory: #{dir}" when !stat.writable? warn "#{name} is not writable: #{dir}" when stat.world_writable? && !stat.sticky? warn "#{name} is world-writable: #{dir}" else tmp = dir break end end raise ArgumentError, "could not find a temporary directory" unless tmp tmp end # Bundler::Dir.mktmpdir creates a temporary directory. # # The directory is created with 0700 permission. # Application should not change the permission to make the temporary directory accessible from other users. # # The prefix and suffix of the name of the directory is specified by # the optional first argument, prefix_suffix. # - If it is not specified or nil, "d" is used as the prefix and no suffix is used. # - If it is a string, it is used as the prefix and no suffix is used. # - If it is an array, first element is used as the prefix and second element is used as a suffix. # # Bundler::Dir.mktmpdir {|dir| dir is ".../d..." } # Bundler::Dir.mktmpdir("foo") {|dir| dir is ".../foo..." } # Bundler::Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" } # # The directory is created under Bundler::Dir.tmpdir or # the optional second argument tmpdir if non-nil value is given. # # Bundler::Dir.mktmpdir {|dir| dir is "#{Bundler::Dir.tmpdir}/d..." } # Bundler::Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." } # # If a block is given, # it is yielded with the path of the directory. # The directory and its contents are removed # using Bundler::FileUtils.remove_entry before Bundler::Dir.mktmpdir returns. # The value of the block is returned. # # Bundler::Dir.mktmpdir {|dir| # # use the directory... # open("#{dir}/foo", "w") { ... } # } # # If a block is not given, # The path of the directory is returned. # In this case, Bundler::Dir.mktmpdir doesn't remove the directory. # # dir = Bundler::Dir.mktmpdir # begin # # use the directory... # open("#{dir}/foo", "w") { ... } # ensure # # remove the directory. # Bundler::FileUtils.remove_entry dir # end # def self.mktmpdir(prefix_suffix=nil, *rest, **options) base = nil path = Tmpname.create(prefix_suffix || "d", *rest, **options) {|p, _, _, d| base = d mkdir(p, 0700) } if block_given? begin yield path.dup ensure unless base stat = File.stat(File.dirname(path)) if stat.world_writable? and !stat.sticky? raise ArgumentError, "parent directory is world writable but not sticky" end end Bundler::FileUtils.remove_entry path end else path end end module Tmpname # :nodoc: module_function def tmpdir Bundler::Dir.tmpdir end UNUSABLE_CHARS = "^,-.0-9A-Z_a-z~" class << (RANDOM = Random.new) MAX = 36**6 # < 0x100000000 def next rand(MAX).to_s(36) end end private_constant :RANDOM def create(basename, tmpdir=nil, max_try: nil, **opts) origdir = tmpdir tmpdir ||= tmpdir() n = nil prefix, suffix = basename prefix = (String.try_convert(prefix) or raise ArgumentError, "unexpected prefix: #{prefix.inspect}") prefix = prefix.delete(UNUSABLE_CHARS) suffix &&= (String.try_convert(suffix) or raise ArgumentError, "unexpected suffix: #{suffix.inspect}") suffix &&= suffix.delete(UNUSABLE_CHARS) begin t = Time.now.strftime("%Y%m%d") path = "#{prefix}#{t}-#{$$}-#{RANDOM.next}"\ "#{n ? %[-#{n}] : ''}#{suffix||''}" path = File.join(tmpdir, path) yield(path, n, opts, origdir) rescue Errno::EEXIST n ||= 0 n += 1 retry if !max_try or n < max_try raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'" end path end end end PK ]lHYYAgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo.rbnu[# frozen_string_literal: true require_relative 'molinillo/gem_metadata' require_relative 'molinillo/errors' require_relative 'molinillo/resolver' require_relative 'molinillo/modules/ui' require_relative 'molinillo/modules/specification_provider' # Bundler::Molinillo is a generic dependency resolution algorithm. module Bundler::Molinillo end PK ]ԻHHYgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rbnu[# frozen_string_literal: true module Bundler::Molinillo class DependencyGraph # A vertex in a {DependencyGraph} that encapsulates a {#name} and a # {#payload} class Vertex # @return [String] the name of the vertex attr_accessor :name # @return [Object] the payload the vertex holds attr_accessor :payload # @return [Array] the explicit requirements that required # this vertex attr_reader :explicit_requirements # @return [Boolean] whether the vertex is considered a root vertex attr_accessor :root alias root? root # Initializes a vertex with the given name and payload. # @param [String] name see {#name} # @param [Object] payload see {#payload} def initialize(name, payload) @name = name.frozen? ? name : name.dup.freeze @payload = payload @explicit_requirements = [] @outgoing_edges = [] @incoming_edges = [] end # @return [Array] all of the requirements that required # this vertex def requirements (incoming_edges.map(&:requirement) + explicit_requirements).uniq end # @return [Array] the edges of {#graph} that have `self` as their # {Edge#origin} attr_accessor :outgoing_edges # @return [Array] the edges of {#graph} that have `self` as their # {Edge#destination} attr_accessor :incoming_edges # @return [Array] the vertices of {#graph} that have an edge with # `self` as their {Edge#destination} def predecessors incoming_edges.map(&:origin) end # @return [Set] the vertices of {#graph} where `self` is a # {#descendent?} def recursive_predecessors _recursive_predecessors end # @param [Set] vertices the set to add the predecessors to # @return [Set] the vertices of {#graph} where `self` is a # {#descendent?} def _recursive_predecessors(vertices = new_vertex_set) incoming_edges.each do |edge| vertex = edge.origin next unless vertices.add?(vertex) vertex._recursive_predecessors(vertices) end vertices end protected :_recursive_predecessors # @return [Array] the vertices of {#graph} that have an edge with # `self` as their {Edge#origin} def successors outgoing_edges.map(&:destination) end # @return [Set] the vertices of {#graph} where `self` is an # {#ancestor?} def recursive_successors _recursive_successors end # @param [Set] vertices the set to add the successors to # @return [Set] the vertices of {#graph} where `self` is an # {#ancestor?} def _recursive_successors(vertices = new_vertex_set) outgoing_edges.each do |edge| vertex = edge.destination next unless vertices.add?(vertex) vertex._recursive_successors(vertices) end vertices end protected :_recursive_successors # @return [String] a string suitable for debugging def inspect "#{self.class}:#{name}(#{payload.inspect})" end # @return [Boolean] whether the two vertices are equal, determined # by a recursive traversal of each {Vertex#successors} def ==(other) return true if equal?(other) shallow_eql?(other) && successors.to_set == other.successors.to_set end # @param [Vertex] other the other vertex to compare to # @return [Boolean] whether the two vertices are equal, determined # solely by {#name} and {#payload} equality def shallow_eql?(other) return true if equal?(other) other && name == other.name && payload == other.payload end alias eql? == # @return [Fixnum] a hash for the vertex based upon its {#name} def hash name.hash end # Is there a path from `self` to `other` following edges in the # dependency graph? # @return whether there is a path following edges within this {#graph} def path_to?(other) _path_to?(other) end alias descendent? path_to? # @param [Vertex] other the vertex to check if there's a path to # @param [Set] visited the vertices of {#graph} that have been visited # @return [Boolean] whether there is a path to `other` from `self` def _path_to?(other, visited = new_vertex_set) return false unless visited.add?(self) return true if equal?(other) successors.any? { |v| v._path_to?(other, visited) } end protected :_path_to? # Is there a path from `other` to `self` following edges in the # dependency graph? # @return whether there is a path following edges within this {#graph} def ancestor?(other) other.path_to?(self) end alias is_reachable_from? ancestor? def new_vertex_set require 'set' Set.new end private :new_vertex_set end end end PK ]:ʘ!fgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # @see DependencyGraph#detach_vertex_named class DetachVertexNamed < Action # @!group Action # (see Action#name) def self.action_name :add_vertex end # (see Action#up) def up(graph) return [] unless @vertex = graph.vertices.delete(name) removed_vertices = [@vertex] @vertex.outgoing_edges.each do |e| v = e.destination v.incoming_edges.delete(e) if !v.root? && v.incoming_edges.empty? removed_vertices.concat graph.detach_vertex_named(v.name) end end @vertex.incoming_edges.each do |e| v = e.origin v.outgoing_edges.delete(e) end removed_vertices end # (see Action#down) def down(graph) return unless @vertex graph.vertices[@vertex.name] = @vertex @vertex.outgoing_edges.each do |e| e.destination.incoming_edges << e end @vertex.incoming_edges.each do |e| e.origin.outgoing_edges << e end end # @!group DetachVertexNamed # @return [String] the name of the vertex to detach attr_reader :name # Initialize an action to detach a vertex from a dependency graph # @param [String] name the name of the vertex to detach def initialize(name) @name = name end end end end PK ]XAcc]gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # (see DependencyGraph#add_vertex) class AddVertex < Action # :nodoc: # @!group Action # (see Action.action_name) def self.action_name :add_vertex end # (see Action#up) def up(graph) if existing = graph.vertices[name] @existing_payload = existing.payload @existing_root = existing.root end vertex = existing || Vertex.new(name, payload) graph.vertices[vertex.name] = vertex vertex.payload ||= payload vertex.root ||= root vertex end # (see Action#down) def down(graph) if defined?(@existing_payload) vertex = graph.vertices[name] vertex.payload = @existing_payload vertex.root = @existing_root else graph.vertices.delete(name) end end # @!group AddVertex # @return [String] the name of the vertex attr_reader :name # @return [Object] the payload for the vertex attr_reader :payload # @return [Boolean] whether the vertex is root or not attr_reader :root # Initialize an action to add a vertex to a dependency graph # @param [String] name the name of the vertex # @param [Object] payload the payload for the vertex # @param [Boolean] root whether the vertex is root or not def initialize(name, payload, root) @name = name @payload = payload @root = root end end end end PK ].mVVgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # @see DependencyGraph#tag class Tag < Action # @!group Action # (see Action.action_name) def self.action_name :tag end # (see Action#up) def up(graph) end # (see Action#down) def down(graph) end # @!group Tag # @return [Object] An opaque tag attr_reader :tag # Initialize an action to tag a state of a dependency graph # @param [Object] tag an opaque tag def initialize(tag) @tag = tag end end end end PK ]@G{Ygems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rbnu[# frozen_string_literal: true module Bundler::Molinillo class DependencyGraph # An action that modifies a {DependencyGraph} that is reversible. # @abstract class Action # rubocop:disable Lint/UnusedMethodArgument # @return [Symbol] The name of the action. def self.action_name raise 'Abstract' end # Performs the action on the given graph. # @param [DependencyGraph] graph the graph to perform the action on. # @return [Void] def up(graph) raise 'Abstract' end # Reverses the action on the given graph. # @param [DependencyGraph] graph the graph to reverse the action on. # @return [Void] def down(graph) raise 'Abstract' end # @return [Action,Nil] The previous action attr_accessor :previous # @return [Action,Nil] The next action attr_accessor :next end end end PK ]5 Vgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rbnu[# frozen_string_literal: true require_relative 'add_edge_no_circular' require_relative 'add_vertex' require_relative 'delete_edge' require_relative 'detach_vertex_named' require_relative 'set_payload' require_relative 'tag' module Bundler::Molinillo class DependencyGraph # A log for dependency graph actions class Log # Initializes an empty log def initialize @current_action = @first_action = nil end # @!macro [new] action # {include:DependencyGraph#$0} # @param [Graph] graph the graph to perform the action on # @param (see DependencyGraph#$0) # @return (see DependencyGraph#$0) # @macro action def tag(graph, tag) push_action(graph, Tag.new(tag)) end # @macro action def add_vertex(graph, name, payload, root) push_action(graph, AddVertex.new(name, payload, root)) end # @macro action def detach_vertex_named(graph, name) push_action(graph, DetachVertexNamed.new(name)) end # @macro action def add_edge_no_circular(graph, origin, destination, requirement) push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement)) end # {include:DependencyGraph#delete_edge} # @param [Graph] graph the graph to perform the action on # @param [String] origin_name # @param [String] destination_name # @param [Object] requirement # @return (see DependencyGraph#delete_edge) def delete_edge(graph, origin_name, destination_name, requirement) push_action(graph, DeleteEdge.new(origin_name, destination_name, requirement)) end # @macro action def set_payload(graph, name, payload) push_action(graph, SetPayload.new(name, payload)) end # Pops the most recent action from the log and undoes the action # @param [DependencyGraph] graph # @return [Action] the action that was popped off the log def pop!(graph) return unless action = @current_action unless @current_action = action.previous @first_action = nil end action.down(graph) action end extend Enumerable # @!visibility private # Enumerates each action in the log # @yield [Action] def each return enum_for unless block_given? action = @first_action loop do break unless action yield action action = action.next end self end # @!visibility private # Enumerates each action in the log in reverse order # @yield [Action] def reverse_each return enum_for(:reverse_each) unless block_given? action = @current_action loop do break unless action yield action action = action.previous end self end # @macro action def rewind_to(graph, tag) loop do action = pop!(graph) raise "No tag #{tag.inspect} found" unless action break if action.class.action_name == :tag && action.tag == tag end end private # Adds the given action to the log, running the action # @param [DependencyGraph] graph # @param [Action] action # @return The value returned by `action.up` def push_action(graph, action) action.previous = @current_action @current_action.next = action if @current_action @current_action = action @first_action ||= action action.up(graph) end end end end PK ]D""^gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # (see DependencyGraph#delete_edge) class DeleteEdge < Action # @!group Action # (see Action.action_name) def self.action_name :delete_edge end # (see Action#up) def up(graph) edge = make_edge(graph) edge.origin.outgoing_edges.delete(edge) edge.destination.incoming_edges.delete(edge) end # (see Action#down) def down(graph) edge = make_edge(graph) edge.origin.outgoing_edges << edge edge.destination.incoming_edges << edge edge end # @!group DeleteEdge # @return [String] the name of the origin of the edge attr_reader :origin_name # @return [String] the name of the destination of the edge attr_reader :destination_name # @return [Object] the requirement that the edge represents attr_reader :requirement # @param [DependencyGraph] graph the graph to find vertices from # @return [Edge] The edge this action adds def make_edge(graph) Edge.new( graph.vertex_named(origin_name), graph.vertex_named(destination_name), requirement ) end # Initialize an action to add an edge to a dependency graph # @param [String] origin_name the name of the origin of the edge # @param [String] destination_name the name of the destination of the edge # @param [Object] requirement the requirement that the edge represents def initialize(origin_name, destination_name, requirement) @origin_name = origin_name @destination_name = destination_name @requirement = requirement end end end end PK ] ?=WW^gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # @see DependencyGraph#set_payload class SetPayload < Action # :nodoc: # @!group Action # (see Action.action_name) def self.action_name :set_payload end # (see Action#up) def up(graph) vertex = graph.vertex_named(name) @old_payload = vertex.payload vertex.payload = payload end # (see Action#down) def down(graph) graph.vertex_named(name).payload = @old_payload end # @!group SetPayload # @return [String] the name of the vertex attr_reader :name # @return [Object] the payload for the vertex attr_reader :payload # Initialize an action to add set the payload for a vertex in a dependency # graph # @param [String] name the name of the vertex # @param [Object] payload the payload for the vertex def initialize(name, payload) @name = name @payload = payload end end end end PK ]DNjooggems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # (see DependencyGraph#add_edge_no_circular) class AddEdgeNoCircular < Action # @!group Action # (see Action.action_name) def self.action_name :add_vertex end # (see Action#up) def up(graph) edge = make_edge(graph) edge.origin.outgoing_edges << edge edge.destination.incoming_edges << edge edge end # (see Action#down) def down(graph) edge = make_edge(graph) delete_first(edge.origin.outgoing_edges, edge) delete_first(edge.destination.incoming_edges, edge) end # @!group AddEdgeNoCircular # @return [String] the name of the origin of the edge attr_reader :origin # @return [String] the name of the destination of the edge attr_reader :destination # @return [Object] the requirement that the edge represents attr_reader :requirement # @param [DependencyGraph] graph the graph to find vertices from # @return [Edge] The edge this action adds def make_edge(graph) Edge.new(graph.vertex_named(origin), graph.vertex_named(destination), requirement) end # Initialize an action to add an edge to a dependency graph # @param [String] origin the name of the origin of the edge # @param [String] destination the name of the destination of the edge # @param [Object] requirement the requirement that the edge represents def initialize(origin, destination, requirement) @origin = origin @destination = destination @requirement = requirement end private def delete_first(array, item) return unless index = array.index(item) array.delete_at(index) end end end end PK ]cOu((Ggems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/state.rbnu[# frozen_string_literal: true module Bundler::Molinillo # A state that a {Resolution} can be in # @attr [String] name the name of the current requirement # @attr [Array] requirements currently unsatisfied requirements # @attr [DependencyGraph] activated the graph of activated dependencies # @attr [Object] requirement the current requirement # @attr [Object] possibilities the possibilities to satisfy the current requirement # @attr [Integer] depth the depth of the resolution # @attr [Hash] conflicts unresolved conflicts, indexed by dependency name # @attr [Array] unused_unwind_options unwinds for previous conflicts that weren't explored ResolutionState = Struct.new( :name, :requirements, :activated, :requirement, :possibilities, :depth, :conflicts, :unused_unwind_options ) class ResolutionState # Returns an empty resolution state # @return [ResolutionState] an empty state def self.empty new(nil, [], DependencyGraph.new, nil, nil, 0, {}, []) end end # A state that encapsulates a set of {#requirements} with an {Array} of # possibilities class DependencyState < ResolutionState # Removes a possibility from `self` # @return [PossibilityState] a state with a single possibility, # the possibility that was removed from `self` def pop_possibility_state PossibilityState.new( name, requirements.dup, activated, requirement, [possibilities.pop], depth + 1, conflicts.dup, unused_unwind_options.dup ).tap do |state| state.activated.tag(state) end end end # A state that encapsulates a single possibility to fulfill the given # {#requirement} class PossibilityState < ResolutionState end end PK ]U#||Hgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/errors.rbnu[# frozen_string_literal: true module Bundler::Molinillo # An error that occurred during the resolution process class ResolverError < StandardError; end # An error caused by searching for a dependency that is completely unknown, # i.e. has no versions available whatsoever. class NoSuchDependencyError < ResolverError # @return [Object] the dependency that could not be found attr_accessor :dependency # @return [Array] the specifications that depended upon {#dependency} attr_accessor :required_by # Initializes a new error with the given missing dependency. # @param [Object] dependency @see {#dependency} # @param [Array] required_by @see {#required_by} def initialize(dependency, required_by = []) @dependency = dependency @required_by = required_by.uniq super() end # The error message for the missing dependency, including the specifications # that had this dependency. def message sources = required_by.map { |r| "`#{r}`" }.join(' and ') message = "Unable to find a specification for `#{dependency}`" message += " depended upon by #{sources}" unless sources.empty? message end end # An error caused by attempting to fulfil a dependency that was circular # # @note This exception will be thrown if and only if a {Vertex} is added to a # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an # existing {DependencyGraph::Vertex} class CircularDependencyError < ResolverError # [Set] the dependencies responsible for causing the error attr_reader :dependencies # Initializes a new error with the given circular vertices. # @param [Array] vertices the vertices in the dependency # that caused the error def initialize(vertices) super "There is a circular dependency between #{vertices.map(&:name).join(' and ')}" @dependencies = vertices.map { |vertex| vertex.payload.possibilities.last }.to_set end end # An error caused by conflicts in version class VersionConflict < ResolverError # @return [{String => Resolution::Conflict}] the conflicts that caused # resolution to fail attr_reader :conflicts # @return [SpecificationProvider] the specification provider used during # resolution attr_reader :specification_provider # Initializes a new error with the given version conflicts. # @param [{String => Resolution::Conflict}] conflicts see {#conflicts} # @param [SpecificationProvider] specification_provider see {#specification_provider} def initialize(conflicts, specification_provider) pairs = [] conflicts.values.flat_map(&:requirements).each do |conflicting| conflicting.each do |source, conflict_requirements| conflict_requirements.each do |c| pairs << [c, source] end end end super "Unable to satisfy the following requirements:\n\n" \ "#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}" @conflicts = conflicts @specification_provider = specification_provider end require_relative 'delegates/specification_provider' include Delegates::SpecificationProvider # @return [String] An error message that includes requirement trees, # which is much more detailed & customizable than the default message # @param [Hash] opts the options to create a message with. # @option opts [String] :solver_name The user-facing name of the solver # @option opts [String] :possibility_type The generic name of a possibility # @option opts [Proc] :reduce_trees A proc that reduced the list of requirement trees # @option opts [Proc] :printable_requirement A proc that pretty-prints requirements # @option opts [Proc] :additional_message_for_conflict A proc that appends additional # messages for each conflict # @option opts [Proc] :version_for_spec A proc that returns the version number for a # possibility def message_with_trees(opts = {}) solver_name = opts.delete(:solver_name) { self.class.name.split('::').first } possibility_type = opts.delete(:possibility_type) { 'possibility named' } reduce_trees = opts.delete(:reduce_trees) { proc { |trees| trees.uniq.sort_by(&:to_s) } } printable_requirement = opts.delete(:printable_requirement) { proc { |req| req.to_s } } additional_message_for_conflict = opts.delete(:additional_message_for_conflict) { proc {} } version_for_spec = opts.delete(:version_for_spec) { proc(&:to_s) } incompatible_version_message_for_conflict = opts.delete(:incompatible_version_message_for_conflict) do proc do |name, _conflict| %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":) end end conflicts.sort.reduce(''.dup) do |o, (name, conflict)| o << "\n" << incompatible_version_message_for_conflict.call(name, conflict) << "\n" if conflict.locked_requirement o << %( In snapshot (#{name_for_locking_dependency_source}):\n) o << %( #{printable_requirement.call(conflict.locked_requirement)}\n) o << %(\n) end o << %( In #{name_for_explicit_dependency_source}:\n) trees = reduce_trees.call(conflict.requirement_trees) o << trees.map do |tree| t = ''.dup depth = 2 tree.each do |req| t << ' ' * depth << printable_requirement.call(req) unless tree.last == req if spec = conflict.activated_by_name[name_for(req)] t << %( was resolved to #{version_for_spec.call(spec)}, which) end t << %( depends on) end t << %(\n) depth += 1 end t end.join("\n") additional_message_for_conflict.call(o, name, conflict) o end.strip end end end PK ]~Jgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rbnu[# frozen_string_literal: true require_relative 'dependency_graph' module Bundler::Molinillo # This class encapsulates a dependency resolver. # The resolver is responsible for determining which set of dependencies to # activate, with feedback from the {#specification_provider} # # class Resolver require_relative 'resolution' # @return [SpecificationProvider] the specification provider used # in the resolution process attr_reader :specification_provider # @return [UI] the UI module used to communicate back to the user # during the resolution process attr_reader :resolver_ui # Initializes a new resolver. # @param [SpecificationProvider] specification_provider # see {#specification_provider} # @param [UI] resolver_ui # see {#resolver_ui} def initialize(specification_provider, resolver_ui) @specification_provider = specification_provider @resolver_ui = resolver_ui end # Resolves the requested dependencies into a {DependencyGraph}, # locking to the base dependency graph (if specified) # @param [Array] requested an array of 'requested' dependencies that the # {#specification_provider} can understand # @param [DependencyGraph,nil] base the base dependency graph to which # dependencies should be 'locked' def resolve(requested, base = DependencyGraph.new) Resolution.new(specification_provider, resolver_ui, requested, base). resolve end end end PK ] Rgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rbnu[# frozen_string_literal: true require 'tsort' require_relative 'dependency_graph/log' require_relative 'dependency_graph/vertex' module Bundler::Molinillo # A directed acyclic graph that is tuned to hold named dependencies class DependencyGraph include Enumerable # Enumerates through the vertices of the graph. # @return [Array] The graph's vertices. def each return vertices.values.each unless block_given? vertices.values.each { |v| yield v } end include TSort # @!visibility private alias tsort_each_node each # @!visibility private def tsort_each_child(vertex, &block) vertex.successors.each(&block) end # Topologically sorts the given vertices. # @param [Enumerable] vertices the vertices to be sorted, which must # all belong to the same graph. # @return [Array] The sorted vertices. def self.tsort(vertices) TSort.tsort( lambda { |b| vertices.each(&b) }, lambda { |v, &b| (v.successors & vertices).each(&b) } ) end # A directed edge of a {DependencyGraph} # @attr [Vertex] origin The origin of the directed edge # @attr [Vertex] destination The destination of the directed edge # @attr [Object] requirement The requirement the directed edge represents Edge = Struct.new(:origin, :destination, :requirement) # @return [{String => Vertex}] the vertices of the dependency graph, keyed # by {Vertex#name} attr_reader :vertices # @return [Log] the op log for this graph attr_reader :log # Initializes an empty dependency graph def initialize @vertices = {} @log = Log.new end # Tags the current state of the dependency as the given tag # @param [Object] tag an opaque tag for the current state of the graph # @return [Void] def tag(tag) log.tag(self, tag) end # Rewinds the graph to the state tagged as `tag` # @param [Object] tag the tag to rewind to # @return [Void] def rewind_to(tag) log.rewind_to(self, tag) end # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices} # are properly copied. # @param [DependencyGraph] other the graph to copy. def initialize_copy(other) super @vertices = {} @log = other.log.dup traverse = lambda do |new_v, old_v| return if new_v.outgoing_edges.size == old_v.outgoing_edges.size old_v.outgoing_edges.each do |edge| destination = add_vertex(edge.destination.name, edge.destination.payload) add_edge_no_circular(new_v, destination, edge.requirement) traverse.call(destination, edge.destination) end end other.vertices.each do |name, vertex| new_vertex = add_vertex(name, vertex.payload, vertex.root?) new_vertex.explicit_requirements.replace(vertex.explicit_requirements) traverse.call(new_vertex, vertex) end end # @return [String] a string suitable for debugging def inspect "#{self.class}:#{vertices.values.inspect}" end # @param [Hash] options options for dot output. # @return [String] Returns a dot format representation of the graph def to_dot(options = {}) edge_label = options.delete(:edge_label) raise ArgumentError, "Unknown options: #{options.keys}" unless options.empty? dot_vertices = [] dot_edges = [] vertices.each do |n, v| dot_vertices << " #{n} [label=\"{#{n}|#{v.payload}}\"]" v.outgoing_edges.each do |e| label = edge_label ? edge_label.call(e) : e.requirement dot_edges << " #{e.origin.name} -> #{e.destination.name} [label=#{label.to_s.dump}]" end end dot_vertices.uniq! dot_vertices.sort! dot_edges.uniq! dot_edges.sort! dot = dot_vertices.unshift('digraph G {').push('') + dot_edges.push('}') dot.join("\n") end # @param [DependencyGraph] other # @return [Boolean] whether the two dependency graphs are equal, determined # by a recursive traversal of each {#root_vertices} and its # {Vertex#successors} def ==(other) return false unless other return true if equal?(other) vertices.each do |name, vertex| other_vertex = other.vertex_named(name) return false unless other_vertex return false unless vertex.payload == other_vertex.payload return false unless other_vertex.successors.to_set == vertex.successors.to_set end end # @param [String] name # @param [Object] payload # @param [Array] parent_names # @param [Object] requirement the requirement that is requiring the child # @return [void] def add_child_vertex(name, payload, parent_names, requirement) root = !parent_names.delete(nil) { true } vertex = add_vertex(name, payload, root) vertex.explicit_requirements << requirement if root parent_names.each do |parent_name| parent_vertex = vertex_named(parent_name) add_edge(parent_vertex, vertex, requirement) end vertex end # Adds a vertex with the given name, or updates the existing one. # @param [String] name # @param [Object] payload # @return [Vertex] the vertex that was added to `self` def add_vertex(name, payload, root = false) log.add_vertex(self, name, payload, root) end # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively # removing any non-root vertices that were orphaned in the process # @param [String] name # @return [Array] the vertices which have been detached def detach_vertex_named(name) log.detach_vertex_named(self, name) end # @param [String] name # @return [Vertex,nil] the vertex with the given name def vertex_named(name) vertices[name] end # @param [String] name # @return [Vertex,nil] the root vertex with the given name def root_vertex_named(name) vertex = vertex_named(name) vertex if vertex && vertex.root? end # Adds a new {Edge} to the dependency graph # @param [Vertex] origin # @param [Vertex] destination # @param [Object] requirement the requirement that this edge represents # @return [Edge] the added edge def add_edge(origin, destination, requirement) if destination.path_to?(origin) raise CircularDependencyError.new(path(destination, origin)) end add_edge_no_circular(origin, destination, requirement) end # Deletes an {Edge} from the dependency graph # @param [Edge] edge # @return [Void] def delete_edge(edge) log.delete_edge(self, edge.origin.name, edge.destination.name, edge.requirement) end # Sets the payload of the vertex with the given name # @param [String] name the name of the vertex # @param [Object] payload the payload # @return [Void] def set_payload(name, payload) log.set_payload(self, name, payload) end private # Adds a new {Edge} to the dependency graph without checking for # circularity. # @param (see #add_edge) # @return (see #add_edge) def add_edge_no_circular(origin, destination, requirement) log.add_edge_no_circular(self, origin.name, destination.name, requirement) end # Returns the path between two vertices # @raise [ArgumentError] if there is no path between the vertices # @param [Vertex] from # @param [Vertex] to # @return [Array] the shortest path from `from` to `to` def path(from, to) distances = Hash.new(vertices.size + 1) distances[from.name] = 0 predecessors = {} each do |vertex| vertex.successors.each do |successor| if distances[successor.name] > distances[vertex.name] + 1 distances[successor.name] = distances[vertex.name] + 1 predecessors[successor] = vertex end end end path = [to] while before = predecessors[to] path << before to = before break if to == from end unless path.last.equal?(from) raise ArgumentError, "There is no path from #{from.name} to #{to.name}" end path.reverse end end end PK ]ۦ bgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rbnu[# frozen_string_literal: true module Bundler::Molinillo module Delegates # Delegates all {Bundler::Molinillo::SpecificationProvider} methods to a # `#specification_provider` property. module SpecificationProvider # (see Bundler::Molinillo::SpecificationProvider#search_for) def search_for(dependency) with_no_such_dependency_error_handling do specification_provider.search_for(dependency) end end # (see Bundler::Molinillo::SpecificationProvider#dependencies_for) def dependencies_for(specification) with_no_such_dependency_error_handling do specification_provider.dependencies_for(specification) end end # (see Bundler::Molinillo::SpecificationProvider#requirement_satisfied_by?) def requirement_satisfied_by?(requirement, activated, spec) with_no_such_dependency_error_handling do specification_provider.requirement_satisfied_by?(requirement, activated, spec) end end # (see Bundler::Molinillo::SpecificationProvider#dependencies_equal?) def dependencies_equal?(dependencies, other_dependencies) with_no_such_dependency_error_handling do specification_provider.dependencies_equal?(dependencies, other_dependencies) end end # (see Bundler::Molinillo::SpecificationProvider#name_for) def name_for(dependency) with_no_such_dependency_error_handling do specification_provider.name_for(dependency) end end # (see Bundler::Molinillo::SpecificationProvider#name_for_explicit_dependency_source) def name_for_explicit_dependency_source with_no_such_dependency_error_handling do specification_provider.name_for_explicit_dependency_source end end # (see Bundler::Molinillo::SpecificationProvider#name_for_locking_dependency_source) def name_for_locking_dependency_source with_no_such_dependency_error_handling do specification_provider.name_for_locking_dependency_source end end # (see Bundler::Molinillo::SpecificationProvider#sort_dependencies) def sort_dependencies(dependencies, activated, conflicts) with_no_such_dependency_error_handling do specification_provider.sort_dependencies(dependencies, activated, conflicts) end end # (see Bundler::Molinillo::SpecificationProvider#allow_missing?) def allow_missing?(dependency) with_no_such_dependency_error_handling do specification_provider.allow_missing?(dependency) end end private # Ensures any raised {NoSuchDependencyError} has its # {NoSuchDependencyError#required_by} set. # @yield def with_no_such_dependency_error_handling yield rescue NoSuchDependencyError => error if state vertex = activated.vertex_named(name_for(error.dependency)) error.required_by += vertex.incoming_edges.map { |e| e.origin.name } error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty? end raise end end end end PK ]9DD??\gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rbnu[# frozen_string_literal: true module Bundler::Molinillo # @!visibility private module Delegates # Delegates all {Bundler::Molinillo::ResolutionState} methods to a `#state` property. module ResolutionState # (see Bundler::Molinillo::ResolutionState#name) def name current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.name end # (see Bundler::Molinillo::ResolutionState#requirements) def requirements current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.requirements end # (see Bundler::Molinillo::ResolutionState#activated) def activated current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.activated end # (see Bundler::Molinillo::ResolutionState#requirement) def requirement current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.requirement end # (see Bundler::Molinillo::ResolutionState#possibilities) def possibilities current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.possibilities end # (see Bundler::Molinillo::ResolutionState#depth) def depth current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.depth end # (see Bundler::Molinillo::ResolutionState#conflicts) def conflicts current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.conflicts end # (see Bundler::Molinillo::ResolutionState#unused_unwind_options) def unused_unwind_options current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.unused_unwind_options end end end end PK ]+4Lgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rbnu[# frozen_string_literal: true module Bundler::Molinillo # Conveys information about the resolution process to a user. module UI # The {IO} object that should be used to print output. `STDOUT`, by default. # # @return [IO] def output STDOUT end # Called roughly every {#progress_rate}, this method should convey progress # to the user. # # @return [void] def indicate_progress output.print '.' unless debug? end # How often progress should be conveyed to the user via # {#indicate_progress}, in seconds. A third of a second, by default. # # @return [Float] def progress_rate 0.33 end # Called before resolution begins. # # @return [void] def before_resolution output.print 'Resolving dependencies...' end # Called after resolution ends (either successfully or with an error). # By default, prints a newline. # # @return [void] def after_resolution output.puts end # Conveys debug information to the user. # # @param [Integer] depth the current depth of the resolution process. # @return [void] def debug(depth = 0) if debug? debug_info = yield debug_info = debug_info.inspect unless debug_info.is_a?(String) debug_info = debug_info.split("\n").map { |s| ":#{depth.to_s.rjust 4}: #{s}" } output.puts debug_info end end # Whether or not debug messages should be printed. # By default, whether or not the `MOLINILLO_DEBUG` environment variable is # set. # # @return [Boolean] def debug? return @debug_mode if defined?(@debug_mode) @debug_mode = ENV['MOLINILLO_DEBUG'] end end end PK ]!gpt[[`gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rbnu[# frozen_string_literal: true module Bundler::Molinillo # Provides information about specifications and dependencies to the resolver, # allowing the {Resolver} class to remain generic while still providing power # and flexibility. # # This module contains the methods that users of Bundler::Molinillo must to implement, # using knowledge of their own model classes. module SpecificationProvider # Search for the specifications that match the given dependency. # The specifications in the returned array will be considered in reverse # order, so the latest version ought to be last. # @note This method should be 'pure', i.e. the return value should depend # only on the `dependency` parameter. # # @param [Object] dependency # @return [Array] the specifications that satisfy the given # `dependency`. def search_for(dependency) [] end # Returns the dependencies of `specification`. # @note This method should be 'pure', i.e. the return value should depend # only on the `specification` parameter. # # @param [Object] specification # @return [Array] the dependencies that are required by the given # `specification`. def dependencies_for(specification) [] end # Determines whether the given `requirement` is satisfied by the given # `spec`, in the context of the current `activated` dependency graph. # # @param [Object] requirement # @param [DependencyGraph] activated the current dependency graph in the # resolution process. # @param [Object] spec # @return [Boolean] whether `requirement` is satisfied by `spec` in the # context of the current `activated` dependency graph. def requirement_satisfied_by?(requirement, activated, spec) true end # Determines whether two arrays of dependencies are equal, and thus can be # grouped. # # @param [Array] dependencies # @param [Array] other_dependencies # @return [Boolean] whether `dependencies` and `other_dependencies` should # be considered equal. def dependencies_equal?(dependencies, other_dependencies) dependencies == other_dependencies end # Returns the name for the given `dependency`. # @note This method should be 'pure', i.e. the return value should depend # only on the `dependency` parameter. # # @param [Object] dependency # @return [String] the name for the given `dependency`. def name_for(dependency) dependency.to_s end # @return [String] the name of the source of explicit dependencies, i.e. # those passed to {Resolver#resolve} directly. def name_for_explicit_dependency_source 'user-specified dependency' end # @return [String] the name of the source of 'locked' dependencies, i.e. # those passed to {Resolver#resolve} directly as the `base` def name_for_locking_dependency_source 'Lockfile' end # Sort dependencies so that the ones that are easiest to resolve are first. # Easiest to resolve is (usually) defined by: # 1) Is this dependency already activated? # 2) How relaxed are the requirements? # 3) Are there any conflicts for this dependency? # 4) How many possibilities are there to satisfy this dependency? # # @param [Array] dependencies # @param [DependencyGraph] activated the current dependency graph in the # resolution process. # @param [{String => Array}] conflicts # @return [Array] a sorted copy of `dependencies`. def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| name = name_for(dependency) [ activated.vertex_named(name).payload ? 0 : 1, conflicts[name] ? 0 : 1, ] end end # Returns whether this dependency, which has no possible matching # specifications, can safely be ignored. # # @param [Object] dependency # @return [Boolean] whether this dependency can safely be skipped. def allow_missing?(dependency) false end end end PK ]=Lgems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rbnu[# frozen_string_literal: true module Bundler::Molinillo class Resolver # A specific resolution from a given {Resolver} class Resolution # A conflict that the resolution process encountered # @attr [Object] requirement the requirement that immediately led to the conflict # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict # @attr [Object, nil] existing the existing spec that was in conflict with # the {#possibility} # @attr [Object] possibility_set the set of specs that was unable to be # activated due to a conflict. # @attr [Object] locked_requirement the relevant locking requirement. # @attr [Array>] requirement_trees the different requirement # trees that led to every requirement for the conflicting name. # @attr [{String=>Object}] activated_by_name the already-activated specs. # @attr [Object] underlying_error an error that has occurred during resolution, and # will be raised at the end of it if no resolution is found. Conflict = Struct.new( :requirement, :requirements, :existing, :possibility_set, :locked_requirement, :requirement_trees, :activated_by_name, :underlying_error ) class Conflict # @return [Object] a spec that was unable to be activated due to a conflict def possibility possibility_set && possibility_set.latest_version end end # A collection of possibility states that share the same dependencies # @attr [Array] dependencies the dependencies for this set of possibilities # @attr [Array] possibilities the possibilities PossibilitySet = Struct.new(:dependencies, :possibilities) class PossibilitySet # String representation of the possibility set, for debugging def to_s "[#{possibilities.join(', ')}]" end # @return [Object] most up-to-date dependency in the possibility set def latest_version possibilities.last end end # Details of the state to unwind to when a conflict occurs, and the cause of the unwind # @attr [Integer] state_index the index of the state to unwind to # @attr [Object] state_requirement the requirement of the state we're unwinding to # @attr [Array] requirement_tree for the requirement we're relaxing # @attr [Array] conflicting_requirements the requirements that combined to cause the conflict # @attr [Array] requirement_trees for the conflict # @attr [Array] requirements_unwound_to_instead array of unwind requirements that were chosen over this unwind UnwindDetails = Struct.new( :state_index, :state_requirement, :requirement_tree, :conflicting_requirements, :requirement_trees, :requirements_unwound_to_instead ) class UnwindDetails include Comparable # We compare UnwindDetails when choosing which state to unwind to. If # two options have the same state_index we prefer the one most # removed from a requirement that caused the conflict. Both options # would unwind to the same state, but a `grandparent` option will # filter out fewer of its possibilities after doing so - where a state # is both a `parent` and a `grandparent` to requirements that have # caused a conflict this is the correct behaviour. # @param [UnwindDetail] other UnwindDetail to be compared # @return [Integer] integer specifying ordering def <=>(other) if state_index > other.state_index 1 elsif state_index == other.state_index reversed_requirement_tree_index <=> other.reversed_requirement_tree_index else -1 end end # @return [Integer] index of state requirement in reversed requirement tree # (the conflicting requirement itself will be at position 0) def reversed_requirement_tree_index @reversed_requirement_tree_index ||= if state_requirement requirement_tree.reverse.index(state_requirement) else 999_999 end end # @return [Boolean] where the requirement of the state we're unwinding # to directly caused the conflict. Note: in this case, it is # impossible for the state we're unwinding to to be a parent of # any of the other conflicting requirements (or we would have # circularity) def unwinding_to_primary_requirement? requirement_tree.last == state_requirement end # @return [Array] array of sub-dependencies to avoid when choosing a # new possibility for the state we've unwound to. Only relevant for # non-primary unwinds def sub_dependencies_to_avoid @requirements_to_avoid ||= requirement_trees.map do |tree| index = tree.index(state_requirement) tree[index + 1] if index end.compact end # @return [Array] array of all the requirements that led to the need for # this unwind def all_requirements @all_requirements ||= requirement_trees.flatten(1) end end # @return [SpecificationProvider] the provider that knows about # dependencies, requirements, specifications, versions, etc. attr_reader :specification_provider # @return [UI] the UI that knows how to communicate feedback about the # resolution process back to the user attr_reader :resolver_ui # @return [DependencyGraph] the base dependency graph to which # dependencies should be 'locked' attr_reader :base # @return [Array] the dependencies that were explicitly required attr_reader :original_requested # Initializes a new resolution. # @param [SpecificationProvider] specification_provider # see {#specification_provider} # @param [UI] resolver_ui see {#resolver_ui} # @param [Array] requested see {#original_requested} # @param [DependencyGraph] base see {#base} def initialize(specification_provider, resolver_ui, requested, base) @specification_provider = specification_provider @resolver_ui = resolver_ui @original_requested = requested @base = base @states = [] @iteration_counter = 0 @parents_of = Hash.new { |h, k| h[k] = [] } end # Resolves the {#original_requested} dependencies into a full dependency # graph # @raise [ResolverError] if successful resolution is impossible # @return [DependencyGraph] the dependency graph of successfully resolved # dependencies def resolve start_resolution while state break if !state.requirement && state.requirements.empty? indicate_progress if state.respond_to?(:pop_possibility_state) # DependencyState debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" } state.pop_possibility_state.tap do |s| if s states.push(s) activated.tag(s) end end end process_topmost_state end resolve_activated_specs ensure end_resolution end # @return [Integer] the number of resolver iterations in between calls to # {#resolver_ui}'s {UI#indicate_progress} method attr_accessor :iteration_rate private :iteration_rate # @return [Time] the time at which resolution began attr_accessor :started_at private :started_at # @return [Array] the stack of states for the resolution attr_accessor :states private :states private # Sets up the resolution process # @return [void] def start_resolution @started_at = Time.now push_initial_state debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" } resolver_ui.before_resolution end def resolve_activated_specs activated.vertices.each do |_, vertex| next unless vertex.payload latest_version = vertex.payload.possibilities.reverse_each.find do |possibility| vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) } end activated.set_payload(vertex.name, latest_version) end activated.freeze end # Ends the resolution process # @return [void] def end_resolution resolver_ui.after_resolution debug do "Finished resolution (#{@iteration_counter} steps) " \ "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})" end debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state end require_relative 'state' require_relative 'modules/specification_provider' require_relative 'delegates/resolution_state' require_relative 'delegates/specification_provider' include Bundler::Molinillo::Delegates::ResolutionState include Bundler::Molinillo::Delegates::SpecificationProvider # Processes the topmost available {RequirementState} on the stack # @return [void] def process_topmost_state if possibility attempt_to_activate else create_conflict unwind_for_conflict end rescue CircularDependencyError => underlying_error create_conflict(underlying_error) unwind_for_conflict end # @return [Object] the current possibility that the resolution is trying # to activate def possibility possibilities.last end # @return [RequirementState] the current state the resolution is # operating upon def state states.last end # Creates and pushes the initial state for the resolution, based upon the # {#requested} dependencies # @return [void] def push_initial_state graph = DependencyGraph.new.tap do |dg| original_requested.each do |requested| vertex = dg.add_vertex(name_for(requested), nil, true) vertex.explicit_requirements << requested end dg.tag(:initial_state) end push_state_for_requirements(original_requested, true, graph) end # Unwinds the states stack because a conflict has been encountered # @return [void] def unwind_for_conflict details_for_unwind = build_details_for_unwind unwind_options = unused_unwind_options debug(depth) { "Unwinding for conflict: #{requirement} to #{details_for_unwind.state_index / 2}" } conflicts.tap do |c| sliced_states = states.slice!((details_for_unwind.state_index + 1)..-1) raise_error_unless_state(c) activated.rewind_to(sliced_states.first || :initial_state) if sliced_states state.conflicts = c state.unused_unwind_options = unwind_options filter_possibilities_after_unwind(details_for_unwind) index = states.size - 1 @parents_of.each { |_, a| a.reject! { |i| i >= index } } state.unused_unwind_options.reject! { |uw| uw.state_index >= index } end end # Raises a VersionConflict error, or any underlying error, if there is no # current state # @return [void] def raise_error_unless_state(conflicts) return if state error = conflicts.values.map(&:underlying_error).compact.first raise error || VersionConflict.new(conflicts, specification_provider) end # @return [UnwindDetails] Details of the nearest index to which we could unwind def build_details_for_unwind # Get the possible unwinds for the current conflict current_conflict = conflicts[name] binding_requirements = binding_requirements_for_conflict(current_conflict) unwind_details = unwind_options_for_requirements(binding_requirements) last_detail_for_current_unwind = unwind_details.sort.last current_detail = last_detail_for_current_unwind # Look for past conflicts that could be unwound to affect the # requirement tree for the current conflict all_reqs = last_detail_for_current_unwind.all_requirements all_reqs_size = all_reqs.size relevant_unused_unwinds = unused_unwind_options.select do |alternative| diff_reqs = all_reqs - alternative.requirements_unwound_to_instead next if diff_reqs.size == all_reqs_size # Find the highest index unwind whilst looping through current_detail = alternative if alternative > current_detail alternative end # Add the current unwind options to the `unused_unwind_options` array. # The "used" option will be filtered out during `unwind_for_conflict`. state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 } # Update the requirements_unwound_to_instead on any relevant unused unwinds relevant_unused_unwinds.each do |d| (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq! end unwind_details.each do |d| (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq! end current_detail end # @param [Array] binding_requirements array of requirements that combine to create a conflict # @return [Array] array of UnwindDetails that have a chance # of resolving the passed requirements def unwind_options_for_requirements(binding_requirements) unwind_details = [] trees = [] binding_requirements.reverse_each do |r| partial_tree = [r] trees << partial_tree unwind_details << UnwindDetails.new(-1, nil, partial_tree, binding_requirements, trees, []) # If this requirement has alternative possibilities, check if any would # satisfy the other requirements that created this conflict requirement_state = find_state_for(r) if conflict_fixing_possibilities?(requirement_state, binding_requirements) unwind_details << UnwindDetails.new( states.index(requirement_state), r, partial_tree, binding_requirements, trees, [] ) end # Next, look at the parent of this requirement, and check if the requirement # could have been avoided if an alternative PossibilitySet had been chosen parent_r = parent_of(r) next if parent_r.nil? partial_tree.unshift(parent_r) requirement_state = find_state_for(parent_r) if requirement_state.possibilities.any? { |set| !set.dependencies.include?(r) } unwind_details << UnwindDetails.new( states.index(requirement_state), parent_r, partial_tree, binding_requirements, trees, [] ) end # Finally, look at the grandparent and up of this requirement, looking # for any possibilities that wouldn't create their parent requirement grandparent_r = parent_of(parent_r) until grandparent_r.nil? partial_tree.unshift(grandparent_r) requirement_state = find_state_for(grandparent_r) if requirement_state.possibilities.any? { |set| !set.dependencies.include?(parent_r) } unwind_details << UnwindDetails.new( states.index(requirement_state), grandparent_r, partial_tree, binding_requirements, trees, [] ) end parent_r = grandparent_r grandparent_r = parent_of(parent_r) end end unwind_details end # @param [DependencyState] state # @param [Array] binding_requirements array of requirements # @return [Boolean] whether or not the given state has any possibilities # that could satisfy the given requirements def conflict_fixing_possibilities?(state, binding_requirements) return false unless state state.possibilities.any? do |possibility_set| possibility_set.possibilities.any? do |poss| possibility_satisfies_requirements?(poss, binding_requirements) end end end # Filter's a state's possibilities to remove any that would not fix the # conflict we've just rewound from # @param [UnwindDetails] unwind_details details of the conflict just # unwound from # @return [void] def filter_possibilities_after_unwind(unwind_details) return unless state && !state.possibilities.empty? if unwind_details.unwinding_to_primary_requirement? filter_possibilities_for_primary_unwind(unwind_details) else filter_possibilities_for_parent_unwind(unwind_details) end end # Filter's a state's possibilities to remove any that would not satisfy # the requirements in the conflict we've just rewound from # @param [UnwindDetails] unwind_details details of the conflict just unwound from # @return [void] def filter_possibilities_for_primary_unwind(unwind_details) unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index } unwinds_to_state << unwind_details unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements) state.possibilities.reject! do |possibility_set| possibility_set.possibilities.none? do |poss| unwind_requirement_sets.any? do |requirements| possibility_satisfies_requirements?(poss, requirements) end end end end # @param [Object] possibility a single possibility # @param [Array] requirements an array of requirements # @return [Boolean] whether the possibility satisfies all of the # given requirements def possibility_satisfies_requirements?(possibility, requirements) name = name_for(possibility) activated.tag(:swap) activated.set_payload(name, possibility) if activated.vertex_named(name) satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) } activated.rewind_to(:swap) satisfied end # Filter's a state's possibilities to remove any that would (eventually) # create a requirement in the conflict we've just rewound from # @param [UnwindDetails] unwind_details details of the conflict just unwound from # @return [void] def filter_possibilities_for_parent_unwind(unwind_details) unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index } unwinds_to_state << unwind_details primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq parent_unwinds = unwinds_to_state.uniq - primary_unwinds allowed_possibility_sets = primary_unwinds.flat_map do |unwind| states[unwind.state_index].possibilities.select do |possibility_set| possibility_set.possibilities.any? do |poss| possibility_satisfies_requirements?(poss, unwind.conflicting_requirements) end end end requirements_to_avoid = parent_unwinds.flat_map(&:sub_dependencies_to_avoid) state.possibilities.reject! do |possibility_set| !allowed_possibility_sets.include?(possibility_set) && (requirements_to_avoid - possibility_set.dependencies).empty? end end # @param [Conflict] conflict # @return [Array] minimal array of requirements that would cause the passed # conflict to occur. def binding_requirements_for_conflict(conflict) return [conflict.requirement] if conflict.possibility.nil? possible_binding_requirements = conflict.requirements.values.flatten(1).uniq # When there's a `CircularDependency` error the conflicting requirement # (the one causing the circular) won't be `conflict.requirement` # (which won't be for the right state, because we won't have created it, # because it's circular). # We need to make sure we have that requirement in the conflict's list, # otherwise we won't be able to unwind properly, so we just return all # the requirements for the conflict. return possible_binding_requirements if conflict.underlying_error possibilities = search_for(conflict.requirement) # If all the requirements together don't filter out all possibilities, # then the only two requirements we need to consider are the initial one # (where the dependency's version was first chosen) and the last if binding_requirement_in_set?(nil, possible_binding_requirements, possibilities) return [conflict.requirement, requirement_for_existing_name(name_for(conflict.requirement))].compact end # Loop through the possible binding requirements, removing each one # that doesn't bind. Use a `reverse_each` as we want the earliest set of # binding requirements, and don't use `reject!` as we wish to refine the # array *on each iteration*. binding_requirements = possible_binding_requirements.dup possible_binding_requirements.reverse_each do |req| next if req == conflict.requirement unless binding_requirement_in_set?(req, binding_requirements, possibilities) binding_requirements -= [req] end end binding_requirements end # @param [Object] requirement we wish to check # @param [Array] possible_binding_requirements array of requirements # @param [Array] possibilities array of possibilities the requirements will be used to filter # @return [Boolean] whether or not the given requirement is required to filter # out all elements of the array of possibilities. def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities) possibilities.any? do |poss| possibility_satisfies_requirements?(poss, possible_binding_requirements - [requirement]) end end # @param [Object] requirement # @return [Object] the requirement that led to `requirement` being added # to the list of requirements. def parent_of(requirement) return unless requirement return unless index = @parents_of[requirement].last return unless parent_state = @states[index] parent_state.requirement end # @param [String] name # @return [Object] the requirement that led to a version of a possibility # with the given name being activated. def requirement_for_existing_name(name) return nil unless vertex = activated.vertex_named(name) return nil unless vertex.payload states.find { |s| s.name == name }.requirement end # @param [Object] requirement # @return [ResolutionState] the state whose `requirement` is the given # `requirement`. def find_state_for(requirement) return nil unless requirement states.find { |i| requirement == i.requirement } end # @param [Object] underlying_error # @return [Conflict] a {Conflict} that reflects the failure to activate # the {#possibility} in conjunction with the current {#state} def create_conflict(underlying_error = nil) vertex = activated.vertex_named(name) locked_requirement = locked_requirement_named(name) requirements = {} unless vertex.explicit_requirements.empty? requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements end requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement vertex.incoming_edges.each do |edge| (requirements[edge.origin.payload.latest_version] ||= []).unshift(edge.requirement) end activated_by_name = {} activated.each { |v| activated_by_name[v.name] = v.payload.latest_version if v.payload } conflicts[name] = Conflict.new( requirement, requirements, vertex.payload && vertex.payload.latest_version, possibility, locked_requirement, requirement_trees, activated_by_name, underlying_error ) end # @return [Array>] The different requirement # trees that led to every requirement for the current spec. def requirement_trees vertex = activated.vertex_named(name) vertex.requirements.map { |r| requirement_tree_for(r) } end # @param [Object] requirement # @return [Array] the list of requirements that led to # `requirement` being required. def requirement_tree_for(requirement) tree = [] while requirement tree.unshift(requirement) requirement = parent_of(requirement) end tree end # Indicates progress roughly once every second # @return [void] def indicate_progress @iteration_counter += 1 @progress_rate ||= resolver_ui.progress_rate if iteration_rate.nil? if Time.now - started_at >= @progress_rate self.iteration_rate = @iteration_counter end end if iteration_rate && (@iteration_counter % iteration_rate) == 0 resolver_ui.indicate_progress end end # Calls the {#resolver_ui}'s {UI#debug} method # @param [Integer] depth the depth of the {#states} stack # @param [Proc] block a block that yields a {#to_s} # @return [void] def debug(depth = 0, &block) resolver_ui.debug(depth, &block) end # Attempts to activate the current {#possibility} # @return [void] def attempt_to_activate debug(depth) { 'Attempting to activate ' + possibility.to_s } existing_vertex = activated.vertex_named(name) if existing_vertex.payload debug(depth) { "Found existing spec (#{existing_vertex.payload})" } attempt_to_filter_existing_spec(existing_vertex) else latest = possibility.latest_version possibility.possibilities.select! do |possibility| requirement_satisfied_by?(requirement, activated, possibility) end if possibility.latest_version.nil? # ensure there's a possibility for better error messages possibility.possibilities << latest if latest create_conflict unwind_for_conflict else activate_new_spec end end end # Attempts to update the existing vertex's `PossibilitySet` with a filtered version # @return [void] def attempt_to_filter_existing_spec(vertex) filtered_set = filtered_possibility_set(vertex) if !filtered_set.possibilities.empty? activated.set_payload(name, filtered_set) new_requirements = requirements.dup push_state_for_requirements(new_requirements, false) else create_conflict debug(depth) { "Unsatisfied by existing spec (#{vertex.payload})" } unwind_for_conflict end end # Generates a filtered version of the existing vertex's `PossibilitySet` using the # current state's `requirement` # @param [Object] vertex existing vertex # @return [PossibilitySet] filtered possibility set def filtered_possibility_set(vertex) PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities) end # @param [String] requirement_name the spec name to search for # @return [Object] the locked spec named `requirement_name`, if one # is found on {#base} def locked_requirement_named(requirement_name) vertex = base.vertex_named(requirement_name) vertex && vertex.payload end # Add the current {#possibility} to the dependency graph of the current # {#state} # @return [void] def activate_new_spec conflicts.delete(name) debug(depth) { "Activated #{name} at #{possibility}" } activated.set_payload(name, possibility) require_nested_dependencies_for(possibility) end # Requires the dependencies that the recently activated spec has # @param [Object] possibility_set the PossibilitySet that has just been # activated # @return [void] def require_nested_dependencies_for(possibility_set) nested_dependencies = dependencies_for(possibility_set.latest_version) debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" } nested_dependencies.each do |d| activated.add_child_vertex(name_for(d), nil, [name_for(possibility_set.latest_version)], d) parent_index = states.size - 1 parents = @parents_of[d] parents << parent_index if parents.empty? end push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?) end # Pushes a new {DependencyState} that encapsulates both existing and new # requirements # @param [Array] new_requirements # @param [Boolean] requires_sort # @param [Object] new_activated # @return [void] def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated) new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort new_requirement = nil loop do new_requirement = new_requirements.shift break if new_requirement.nil? || states.none? { |s| s.requirement == new_requirement } end new_name = new_requirement ? name_for(new_requirement) : ''.freeze possibilities = possibilities_for_requirement(new_requirement) handle_missing_or_push_dependency_state DependencyState.new( new_name, new_requirements, new_activated, new_requirement, possibilities, depth, conflicts.dup, unused_unwind_options.dup ) end # Checks a proposed requirement with any existing locked requirement # before generating an array of possibilities for it. # @param [Object] requirement the proposed requirement # @param [Object] activated # @return [Array] possibilities def possibilities_for_requirement(requirement, activated = self.activated) return [] unless requirement if locked_requirement_named(name_for(requirement)) return locked_requirement_possibility_set(requirement, activated) end group_possibilities(search_for(requirement)) end # @param [Object] requirement the proposed requirement # @param [Object] activated # @return [Array] possibility set containing only the locked requirement, if any def locked_requirement_possibility_set(requirement, activated = self.activated) all_possibilities = search_for(requirement) locked_requirement = locked_requirement_named(name_for(requirement)) # Longwinded way to build a possibilities array with either the locked # requirement or nothing in it. Required, since the API for # locked_requirement isn't guaranteed. locked_possibilities = all_possibilities.select do |possibility| requirement_satisfied_by?(locked_requirement, activated, possibility) end group_possibilities(locked_possibilities) end # Build an array of PossibilitySets, with each element representing a group of # dependency versions that all have the same sub-dependency version constraints # and are contiguous. # @param [Array] possibilities an array of possibilities # @return [Array] an array of possibility sets def group_possibilities(possibilities) possibility_sets = [] current_possibility_set = nil possibilities.reverse_each do |possibility| dependencies = dependencies_for(possibility) if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies) current_possibility_set.possibilities.unshift(possibility) else possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility])) current_possibility_set = possibility_sets.first end end possibility_sets end # Pushes a new {DependencyState}. # If the {#specification_provider} says to # {SpecificationProvider#allow_missing?} that particular requirement, and # there are no possibilities for that requirement, then `state` is not # pushed, and the vertex in {#activated} is removed, and we continue # resolving the remaining requirements. # @param [DependencyState] state # @return [void] def handle_missing_or_push_dependency_state(state) if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement) state.activated.detach_vertex_named(state.name) push_state_for_requirements(state.requirements.dup, false, state.activated) else states.push(state).tap { activated.tag(state) } end end end end end PK ]."Ngems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rbnu[# frozen_string_literal: true module Bundler::Molinillo # The version of Bundler::Molinillo. VERSION = '0.7.0'.freeze end PK ]}X,gems/bundler-2.2.24/lib/bundler/gem_tasks.rbnu[# frozen_string_literal: true require "rake/clean" CLOBBER.include "pkg" require_relative "gem_helper" Bundler::GemHelper.install_tasks PK ] D##.gems/bundler-2.2.24/lib/bundler/source/path.rbnu[# frozen_string_literal: true module Bundler class Source class Path < Source autoload :Installer, File.expand_path("path/installer", __dir__) attr_reader :path, :options, :root_path, :original_path attr_writer :name attr_accessor :version protected :original_path DEFAULT_GLOB = "{,*,*/*}.gemspec".freeze def initialize(options) @options = options.dup @glob = options["glob"] || DEFAULT_GLOB @allow_cached = false @allow_remote = false @root_path = options["root_path"] || root if options["path"] @path = Pathname.new(options["path"]) expanded_path = expand(@path) @path = if @path.relative? expanded_path.relative_path_from(root_path.expand_path) else expanded_path end end @name = options["name"] @version = options["version"] # Stores the original path. If at any point we move to the # cached directory, we still have the original path to copy from. @original_path = @path end def remote! @local_specs = nil @allow_remote = true end def cached! @local_specs = nil @allow_cached = true end def self.from_lock(options) new(options.merge("path" => options.delete("remote"))) end def to_lock out = String.new("PATH\n") out << " remote: #{lockfile_path}\n" out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB out << " specs:\n" end def to_s "source at `#{@path}`" end def hash [self.class, expanded_path, version].hash end def eql?(other) return unless other.class == self.class expanded_original_path == other.expanded_original_path && version == other.version end alias_method :==, :eql? def name File.basename(expanded_path.to_s) end def install(spec, options = {}) using_message = "Using #{version_message(spec)} from #{self}" using_message += " and installing its executables" unless spec.executables.empty? print_using_message using_message generate_bin(spec, :disable_extensions => true) nil # no post-install message end def cache(spec, custom_path = nil) app_cache_path = app_cache_path(custom_path) return unless Bundler.feature_flag.cache_all? return if expand(@original_path).to_s.index(root_path.to_s + "/") == 0 unless @original_path.exist? raise GemNotFound, "Can't cache gem #{version_message(spec)} because #{self} is missing!" end FileUtils.rm_rf(app_cache_path) FileUtils.cp_r("#{@original_path}/.", app_cache_path) FileUtils.touch(app_cache_path.join(".bundlecache")) end def local_specs(*) @local_specs ||= load_spec_files end def specs if has_app_cache? @path = app_cache_path @expanded_path = nil # Invalidate end local_specs end def app_cache_dirname name end def root Bundler.root end def expanded_original_path @expanded_original_path ||= expand(original_path) end private def expanded_path @expanded_path ||= expand(path) end def expand(somepath) if Bundler.current_ruby.jruby? # TODO: Unify when https://github.com/rubygems/bundler/issues/7598 fixed upstream and all supported jrubies include the fix somepath.expand_path(root_path).expand_path else somepath.expand_path(root_path) end rescue ArgumentError => e Bundler.ui.debug(e) raise PathError, "There was an error while trying to use the path " \ "`#{somepath}`.\nThe error message was: #{e.message}." end def lockfile_path return relative_path(original_path) if original_path.absolute? expand(original_path).relative_path_from(root) end def app_cache_path(custom_path = nil) @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) end def has_app_cache? SharedHelpers.in_bundle? && app_cache_path.exist? end def load_gemspec(file) return unless spec = Bundler.load_gemspec(file) Bundler.rubygems.set_installed_by_version(spec) spec end def validate_spec(spec) Bundler.rubygems.validate(spec) end def load_spec_files index = Index.new if File.directory?(expanded_path) # We sort depth-first since `<<` will override the earlier-found specs Gem::Util.glob_files_in_dir(@glob, expanded_path).sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file| next unless spec = load_gemspec(file) spec.source = self # Validation causes extension_dir to be calculated, which depends # on #source, so we validate here instead of load_gemspec validate_spec(spec) index << spec end if index.empty? && @name && @version index << Gem::Specification.new do |s| s.name = @name s.source = self s.version = Gem::Version.new(@version) s.platform = Gem::Platform::RUBY s.summary = "Fake gemspec for #{@name}" s.relative_loaded_from = "#{@name}.gemspec" s.authors = ["no one"] if expanded_path.join("bin").exist? executables = expanded_path.join("bin").children executables.reject! {|p| File.directory?(p) } s.executables = executables.map {|c| c.basename.to_s } end end end else message = String.new("The path `#{expanded_path}` ") message << if File.exist?(expanded_path) "is not a directory." else "does not exist." end raise PathError, message end index end def relative_path(path = self.path) if path.to_s.start_with?(root_path.to_s) return path.relative_path_from(root_path) end path end def generate_bin(spec, options = {}) gem_dir = Pathname.new(spec.full_gem_path) # Some gem authors put absolute paths in their gemspec # and we have to save them from themselves spec.files = spec.files.map do |p| next p unless p =~ /\A#{Pathname::SEPARATOR_PAT}/ next if File.directory?(p) begin Pathname.new(p).relative_path_from(gem_dir).to_s rescue ArgumentError p end end.compact installer = Path::Installer.new( spec, :env_shebang => false, :disable_extensions => options[:disable_extensions], :build_args => options[:build_args], :bundler_extension_cache_path => extension_cache_path(spec) ) installer.post_install rescue Gem::InvalidSpecificationException => e Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \ "This prevents bundler from installing bins or native extensions, but " \ "that may not affect its functionality." if !spec.extensions.empty? && !spec.email.empty? Bundler.ui.warn "If you need to use this package without installing it from a gem " \ "repository, please contact #{spec.email} and ask them " \ "to modify their .gemspec so it can work with `gem build`." end Bundler.ui.warn "The validation message from RubyGems was:\n #{e.message}" end end end end PK ]uR!xx8gems/bundler-2.2.24/lib/bundler/source/path/installer.rbnu[# frozen_string_literal: true require_relative "../../rubygems_gem_installer" module Bundler class Source class Path class Installer < Bundler::RubyGemsGemInstaller attr_reader :spec def initialize(spec, options = {}) @options = options @spec = spec @gem_dir = Bundler.rubygems.path(spec.full_gem_path) @wrappers = true @env_shebang = true @format_executable = options[:format_executable] || false @build_args = options[:build_args] || Bundler.rubygems.build_args @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin" @disable_extensions = options[:disable_extensions] if Bundler.requires_sudo? @tmp_dir = Bundler.tmp(spec.full_name).to_s @bin_dir = "#{@tmp_dir}/bin" else @bin_dir = @gem_bin_dir end end def post_install run_hooks(:pre_install) unless @disable_extensions build_extensions run_hooks(:post_build) end generate_bin unless spec.executables.empty? run_hooks(:post_install) ensure Bundler.rm_rf(@tmp_dir) if Bundler.requires_sudo? end private def generate_bin super if Bundler.requires_sudo? SharedHelpers.filesystem_access(@gem_bin_dir) do |p| Bundler.mkdir_p(p) end spec.executables.each do |exe| Bundler.sudo "cp -R #{@bin_dir}/#{exe} #{@gem_bin_dir}" end end end def run_hooks(type) hooks_meth = "#{type}_hooks" return unless Gem.respond_to?(hooks_meth) Gem.send(hooks_meth).each do |hook| result = hook.call(self) next unless result == false location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/ message = "#{type} hook#{location} failed for #{spec.full_name}" raise InstallHookError, message end end end end end end PK ].۬2gems/bundler-2.2.24/lib/bundler/source/metadata.rbnu[# frozen_string_literal: true module Bundler class Source class Metadata < Source def specs @specs ||= Index.build do |idx| idx << Gem::Specification.new("Ruby\0", RubyVersion.system.to_gem_version_with_patchlevel) idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s| s.required_rubygems_version = Gem::Requirement.default end idx << Gem::Specification.new do |s| s.name = "bundler" s.version = VERSION s.license = "MIT" s.platform = Gem::Platform::RUBY s.source = self s.authors = ["bundler team"] s.bindir = "exe" s.homepage = "https://bundler.io" s.summary = "The best way to manage your application's dependencies" s.executables = %w[bundle] # can't point to the actual gemspec or else the require paths will be wrong s.loaded_from = File.expand_path("..", __FILE__) end if local_spec = Bundler.rubygems.find_name("bundler").find {|s| s.version.to_s == VERSION } idx << local_spec end idx.each {|s| s.source = self } end end def options {} end def install(spec, _opts = {}) print_using_message "Using #{version_message(spec)}" nil end def to_s "the local ruby installation" end def ==(other) self.class == other.class end alias_method :eql?, :== def hash self.class.hash end def version_message(spec) "#{spec.name} #{spec.version}" end end end end PK ]gYGG2gems/bundler-2.2.24/lib/bundler/source/rubygems.rbnu[# frozen_string_literal: true require "rubygems/user_interaction" module Bundler class Source class Rubygems < Source autoload :Remote, File.expand_path("rubygems/remote", __dir__) # Use the API when installing less than X gems API_REQUEST_LIMIT = 500 # Ask for X gems per API request API_REQUEST_SIZE = 50 attr_reader :remotes, :caches def initialize(options = {}) @options = options @remotes = [] @dependency_names = [] @allow_remote = false @allow_cached = false @allow_local = options["allow_local"] || false @caches = [cache_path, *Bundler.rubygems.gem_cache] Array(options["remotes"]).reverse_each {|r| add_remote(r) } end def local_only! @specs = nil @allow_local = true @allow_remote = false end def local! return if @allow_local @specs = nil @allow_local = true end def remote! return if @allow_remote @specs = nil @allow_remote = true end def cached! return if @allow_cached @specs = nil @allow_cached = true end def hash @remotes.hash end def eql?(other) other.is_a?(Rubygems) && other.credless_remotes == credless_remotes end alias_method :==, :eql? def include?(o) o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty? end def multiple_remotes? @remotes.size > 1 end def can_lock?(spec) return super unless multiple_remotes? include?(spec.source) end def options { "remotes" => @remotes.map(&:to_s) } end def self.from_lock(options) new(options) end def to_lock out = String.new("GEM\n") remotes.reverse_each do |remote| out << " remote: #{suppress_configured_credentials remote}\n" end out << " specs:\n" end def to_s if remotes.empty? "locally installed gems" else remote_names = remotes.map(&:to_s).join(", ") "rubygems repository #{remote_names} or installed locally" end end alias_method :name, :to_s def specs @specs ||= begin # remote_specs usually generates a way larger Index than the other # sources, and large_idx.use small_idx is way faster than # small_idx.use large_idx. idx = @allow_remote ? remote_specs.dup : Index.new idx.use(cached_specs, :override_dupes) if @allow_cached || @allow_remote idx.use(installed_specs, :override_dupes) if @allow_local idx end end def install(spec, opts = {}) force = opts[:force] ensure_builtin_gems_cached = opts[:ensure_builtin_gems_cached] if ensure_builtin_gems_cached && builtin_gem?(spec) if !cached_path(spec) cached_built_in_gem(spec) unless spec.remote force = true else spec.loaded_from = loaded_from(spec) end end if (installed?(spec) || Plugin.installed?(spec.name)) && !force print_using_message "Using #{version_message(spec)}" return nil # no post-install message end # Download the gem to get the spec, because some specs that are returned # by rubygems.org are broken and wrong. if spec.remote # Check for this spec from other sources uris = [spec.remote.anonymized_uri] uris += remotes_for_spec(spec).map(&:anonymized_uri) uris.uniq! Installer.ambiguous_gems << [spec.name, *uris] if uris.length > 1 path = fetch_gem(spec) begin s = Bundler.rubygems.spec_from_gem(path, Bundler.settings["trust-policy"]) spec.__swap__(s) rescue StandardError Bundler.rm_rf(path) raise end end unless Bundler.settings[:no_install] message = "Installing #{version_message(spec)}" message += " with native extensions" if spec.extensions.any? Bundler.ui.confirm message path = cached_gem(spec) if requires_sudo? install_path = Bundler.tmp(spec.full_name) bin_path = install_path.join("bin") else install_path = rubygems_dir bin_path = Bundler.system_bindir end Bundler.mkdir_p bin_path, :no_sudo => true unless spec.executables.empty? || Bundler.rubygems.provides?(">= 2.7.5") require_relative "../rubygems_gem_installer" installed_spec = Bundler::RubyGemsGemInstaller.at( path, :install_dir => install_path.to_s, :bin_dir => bin_path.to_s, :ignore_dependencies => true, :wrappers => true, :env_shebang => true, :build_args => opts[:build_args], :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum, :bundler_extension_cache_path => extension_cache_path(spec) ).install spec.full_gem_path = installed_spec.full_gem_path # SUDO HAX if requires_sudo? Bundler.rubygems.repository_subdirectories.each do |name| src = File.join(install_path, name, "*") dst = File.join(rubygems_dir, name) if name == "extensions" && Dir.glob(src).any? src = File.join(src, "*/*") ext_src = Dir.glob(src).first ext_src.gsub!(src[0..-6], "") dst = File.dirname(File.join(dst, ext_src)) end SharedHelpers.filesystem_access(dst) do |p| Bundler.mkdir_p(p) end Bundler.sudo "cp -R #{src} #{dst}" if Dir[src].any? end spec.executables.each do |exe| SharedHelpers.filesystem_access(Bundler.system_bindir) do |p| Bundler.mkdir_p(p) end Bundler.sudo "cp -R #{install_path}/bin/#{exe} #{Bundler.system_bindir}/" end end installed_spec.loaded_from = loaded_from(spec) end spec.loaded_from = loaded_from(spec) spec.post_install_message ensure Bundler.rm_rf(install_path) if requires_sudo? end def cache(spec, custom_path = nil) if builtin_gem?(spec) cached_path = cached_built_in_gem(spec) else cached_path = cached_gem(spec) end raise GemNotFound, "Missing gem file '#{spec.full_name}.gem'." unless cached_path return if File.dirname(cached_path) == Bundler.app_cache.to_s Bundler.ui.info " * #{File.basename(cached_path)}" FileUtils.cp(cached_path, Bundler.app_cache(custom_path)) rescue Errno::EACCES => e Bundler.ui.debug(e) raise InstallError, e.message end def cached_built_in_gem(spec) cached_path = cached_path(spec) if cached_path.nil? remote_spec = remote_specs.search(spec).first if remote_spec cached_path = fetch_gem(remote_spec) else Bundler.ui.warn "#{spec.full_name} is built in to Ruby, and can't be cached because your Gemfile doesn't have any sources that contain it." end end cached_path end def add_remote(source) uri = normalize_uri(source) @remotes.unshift(uri) unless @remotes.include?(uri) end def equivalent_remotes?(other_remotes) other_remotes.map(&method(:remove_auth)) == @remotes.map(&method(:remove_auth)) end def spec_names if @allow_remote && dependency_api_available? remote_specs.spec_names else [] end end def unmet_deps if @allow_remote && dependency_api_available? remote_specs.unmet_dependency_names else [] end end def fetchers @fetchers ||= remotes.map do |uri| remote = Source::Rubygems::Remote.new(uri) Bundler::Fetcher.new(remote) end end def double_check_for(unmet_dependency_names) return unless @allow_remote return unless dependency_api_available? unmet_dependency_names = unmet_dependency_names.call unless unmet_dependency_names.nil? if api_fetchers.size <= 1 # can't do this when there are multiple fetchers because then we might not fetch from _all_ # of them unmet_dependency_names -= remote_specs.spec_names # avoid re-fetching things we've already gotten end return if unmet_dependency_names.empty? end Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}" fetch_names(api_fetchers, unmet_dependency_names, specs, false) end def dependency_names_to_double_check names = [] remote_specs.each do |spec| case spec when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification names.concat(spec.runtime_dependencies.map(&:name)) when RemoteSpecification # from the full index return nil else raise "unhandled spec type (#{spec.inspect})" end end names end def dependency_api_available? api_fetchers.any? end protected def credless_remotes remotes.map(&method(:suppress_configured_credentials)) end def remotes_for_spec(spec) specs.search_all(spec.name).inject([]) do |uris, s| uris << s.remote if s.remote uris end end def loaded_from(spec) "#{rubygems_dir}/specifications/#{spec.full_name}.gemspec" end def cached_gem(spec) cached_gem = cached_path(spec) unless cached_gem raise Bundler::GemNotFound, "Could not find #{spec.file_name} for installation" end cached_gem end def cached_path(spec) possibilities = @caches.map {|p| "#{p}/#{spec.file_name}" } possibilities.find {|p| File.exist?(p) } end def normalize_uri(uri) uri = uri.to_s uri = "#{uri}/" unless uri =~ %r{/$} require_relative "../vendored_uri" uri = Bundler::URI(uri) raise ArgumentError, "The source must be an absolute URI. For example:\n" \ "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(Bundler::URI::HTTP) && uri.host.nil?) uri end def suppress_configured_credentials(remote) remote_nouser = remove_auth(remote) if remote.userinfo && remote.userinfo == Bundler.settings[remote_nouser] remote_nouser else remote end end def remove_auth(remote) if remote.user || remote.password remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s else remote.to_s end end def installed_specs @installed_specs ||= Index.build do |idx| Bundler.rubygems.all_specs.reverse_each do |spec| spec.source = self if Bundler.rubygems.spec_missing_extensions?(spec, false) Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions" next end idx << spec end end end def cached_specs @cached_specs ||= begin idx = @allow_local ? installed_specs.dup : Index.new Dir["#{cache_path}/*.gem"].each do |gemfile| next if gemfile =~ /^bundler\-[\d\.]+?\.gem/ s ||= Bundler.rubygems.spec_from_gem(gemfile) s.source = self idx << s end idx end end def api_fetchers fetchers.select {|f| f.use_api && f.fetchers.first.api_fetcher? } end def remote_specs @remote_specs ||= Index.build do |idx| index_fetchers = fetchers - api_fetchers # gather lists from non-api sites fetch_names(index_fetchers, nil, idx, false) # because ensuring we have all the gems we need involves downloading # the gemspecs of those gems, if the non-api sites contain more than # about 500 gems, we treat all sites as non-api for speed. allow_api = idx.size < API_REQUEST_LIMIT && dependency_names.size < API_REQUEST_LIMIT Bundler.ui.debug "Need to query more than #{API_REQUEST_LIMIT} gems." \ " Downloading full index instead..." unless allow_api fetch_names(api_fetchers, allow_api && dependency_names, idx, false) end end def fetch_names(fetchers, dependency_names, index, override_dupes) fetchers.each do |f| if dependency_names Bundler.ui.info "Fetching gem metadata from #{URICredentialsFilter.credential_filtered_uri(f.uri)}", Bundler.ui.debug? index.use f.specs_with_retry(dependency_names, self), override_dupes Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over else Bundler.ui.info "Fetching source index from #{URICredentialsFilter.credential_filtered_uri(f.uri)}" index.use f.specs_with_retry(nil, self), override_dupes end end end def fetch_gem(spec) return false unless spec.remote spec.fetch_platform download_path = requires_sudo? ? Bundler.tmp(spec.full_name) : rubygems_dir gem_path = "#{rubygems_dir}/cache/#{spec.full_name}.gem" SharedHelpers.filesystem_access("#{download_path}/cache") do |p| FileUtils.mkdir_p(p) end download_gem(spec, download_path) if requires_sudo? SharedHelpers.filesystem_access("#{rubygems_dir}/cache") do |p| Bundler.mkdir_p(p) end Bundler.sudo "mv #{download_path}/cache/#{spec.full_name}.gem #{gem_path}" end gem_path ensure Bundler.rm_rf(download_path) if requires_sudo? end def builtin_gem?(spec) # Ruby 2.1, where all included gems have this summary return true if spec.summary =~ /is bundled with Ruby/ # Ruby 2.0, where gemspecs are stored in specifications/default/ spec.loaded_from && spec.loaded_from.include?("specifications/default/") end def installed?(spec) installed_specs[spec].any? end def requires_sudo? Bundler.requires_sudo? end def rubygems_dir Bundler.rubygems.gem_dir end def cache_path Bundler.app_cache end private # Checks if the requested spec exists in the global cache. If it does, # we copy it to the download path, and if it does not, we download it. # # @param [Specification] spec # the spec we want to download or retrieve from the cache. # # @param [String] download_path # the local directory the .gem will end up in. # def download_gem(spec, download_path) local_path = File.join(download_path, "cache/#{spec.full_name}.gem") if (cache_path = download_cache_path(spec)) && cache_path.file? SharedHelpers.filesystem_access(local_path) do FileUtils.cp(cache_path, local_path) end else uri = spec.remote.uri Bundler.ui.confirm("Fetching #{version_message(spec)}") rubygems_local_path = Bundler.rubygems.download_gem(spec, uri, download_path) # older rubygems return varying file:// variants depending on version rubygems_local_path = rubygems_local_path.gsub(/\Afile:/, "") unless Bundler.rubygems.provides?(">= 3.2.0.rc.2") rubygems_local_path = rubygems_local_path.gsub(%r{\A//}, "") if Bundler.rubygems.provides?("< 3.1.0") if rubygems_local_path != local_path SharedHelpers.filesystem_access(local_path) do FileUtils.mv(rubygems_local_path, local_path) end end cache_globally(spec, local_path) end end # Checks if the requested spec exists in the global cache. If it does # not, we create the relevant global cache subdirectory if it does not # exist and copy the spec from the local cache to the global cache. # # @param [Specification] spec # the spec we want to copy to the global cache. # # @param [String] local_cache_path # the local directory from which we want to copy the .gem. # def cache_globally(spec, local_cache_path) return unless cache_path = download_cache_path(spec) return if cache_path.exist? SharedHelpers.filesystem_access(cache_path.dirname, &:mkpath) SharedHelpers.filesystem_access(cache_path) do FileUtils.cp(local_cache_path, cache_path) end end # Returns the global cache path of the calling Rubygems::Source object. # # Note that the Source determines the path's subdirectory. We use this # subdirectory in the global cache path so that gems with the same name # -- and possibly different versions -- from different sources are saved # to their respective subdirectories and do not override one another. # # @param [Gem::Specification] specification # # @return [Pathname] The global cache path. # def download_cache_path(spec) return unless Bundler.feature_flag.global_gem_cache? return unless remote = spec.remote return unless cache_slug = remote.cache_slug Bundler.user_cache.join("gems", cache_slug, spec.file_name) end def extension_cache_slug(spec) return unless remote = spec.remote remote.cache_slug end end end end PK ]:U''9gems/bundler-2.2.24/lib/bundler/source/rubygems/remote.rbnu[# frozen_string_literal: true module Bundler class Source class Rubygems class Remote attr_reader :uri, :anonymized_uri, :original_uri def initialize(uri) orig_uri = uri uri = Bundler.settings.mirror_for(uri) @original_uri = orig_uri if orig_uri != uri fallback_auth = Bundler.settings.credentials_for(uri) @uri = apply_auth(uri, fallback_auth).freeze @anonymized_uri = remove_auth(@uri).freeze end # @return [String] A slug suitable for use as a cache key for this # remote. # def cache_slug @cache_slug ||= begin return nil unless SharedHelpers.md5_available? cache_uri = original_uri || uri host = cache_uri.to_s.start_with?("file://") ? nil : cache_uri.host uri_parts = [host, cache_uri.user, cache_uri.port, cache_uri.path] uri_digest = SharedHelpers.digest(:MD5).hexdigest(uri_parts.compact.join(".")) uri_parts[-1] = uri_digest uri_parts.compact.join(".") end end def to_s "rubygems remote at #{anonymized_uri}" end private def apply_auth(uri, auth) if auth && uri.userinfo.nil? uri = uri.dup uri.userinfo = auth end uri rescue Bundler::URI::InvalidComponentError error_message = "Please CGI escape your usernames and passwords before " \ "setting them for authentication." raise HTTPError.new(error_message) end def remove_auth(uri) if uri.userinfo uri = uri.dup uri.user = uri.password = nil end uri end end end end end PK ]ƨ'1gems/bundler-2.2.24/lib/bundler/source/gemspec.rbnu[# frozen_string_literal: true module Bundler class Source class Gemspec < Path attr_reader :gemspec def initialize(options) super @gemspec = options["gemspec"] end def as_path_source Path.new(options) end end end end PK ] E//<gems/bundler-2.2.24/lib/bundler/source/rubygems_aggregate.rbnu[# frozen_string_literal: true module Bundler class Source class RubygemsAggregate attr_reader :source_map, :sources def initialize(sources, source_map) @sources = sources @source_map = source_map @index = build_index end def specs @index end def to_s "any of the sources" end private def build_index Index.build do |idx| dependency_names = source_map.pinned_spec_names sources.all_sources.each do |source| source.dependency_names = dependency_names - source_map.pinned_spec_names(source) idx.add_source source.specs dependency_names.concat(source.unmet_deps).uniq! end double_check_for_index(idx, dependency_names) end end # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both # sources A and B. At this point, the API request will have found all the versions of Bar in source A, # but will not have found any versions of Bar from source B, which is a problem if the requested version # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for # each spec we found, we add all possible versions from all sources to the index. def double_check_for_index(idx, dependency_names) pinned_names = source_map.pinned_spec_names names = :names # do this so we only have to traverse to get dependency_names from the index once unmet_dependency_names = lambda do return names unless names == :names new_names = sources.all_sources.map(&:dependency_names_to_double_check) return names = nil if new_names.compact! names = new_names.flatten(1).concat(dependency_names) names.uniq! names -= pinned_names names end sources.all_sources.each do |source| source.double_check_for(unmet_dependency_names) end end end end end PK ]Ƌ}(}(-gems/bundler-2.2.24/lib/bundler/source/git.rbnu[# frozen_string_literal: true require_relative "../vendored_fileutils" module Bundler class Source class Git < Path autoload :GitProxy, File.expand_path("git/git_proxy", __dir__) attr_reader :uri, :ref, :branch, :options, :glob, :submodules def initialize(options) @options = options @glob = options["glob"] || DEFAULT_GLOB @allow_cached = false @allow_remote = false # Stringify options that could be set as symbols %w[ref branch tag revision].each {|k| options[k] = options[k].to_s if options[k] } @uri = options["uri"] || "" @safe_uri = URICredentialsFilter.credential_filtered_uri(@uri) @branch = options["branch"] @ref = options["ref"] || options["branch"] || options["tag"] @submodules = options["submodules"] @name = options["name"] @version = options["version"].to_s.strip.gsub("-", ".pre.") @copied = false @local = false end def self.from_lock(options) new(options.merge("uri" => options.delete("remote"))) end def to_lock out = String.new("GIT\n") out << " remote: #{@uri}\n" out << " revision: #{revision}\n" %w[ref branch tag submodules].each do |opt| out << " #{opt}: #{options[opt]}\n" if options[opt] end out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB out << " specs:\n" end def hash [self.class, uri, ref, branch, name, version, glob, submodules].hash end def eql?(other) other.is_a?(Git) && uri == other.uri && ref == other.ref && branch == other.branch && name == other.name && version == other.version && glob == other.glob && submodules == other.submodules end alias_method :==, :eql? def to_s begin at = if local? path elsif user_ref = options["ref"] if ref =~ /\A[a-z0-9]{4,}\z/i shortref_for_display(user_ref) else user_ref end elsif ref ref else git_proxy.branch end rev = " (at #{at}@#{shortref_for_display(revision)})" rescue GitError "" end "#{@safe_uri}#{rev}" end def name File.basename(@uri, ".git") end # This is the path which is going to contain a specific # checkout of the git repository. When using local git # repos, this is set to the local repo. def install_path @install_path ||= begin git_scope = "#{base_name}-#{shortref_for_path(revision)}" path = Bundler.install_path.join(git_scope) if !path.exist? && Bundler.requires_sudo? Bundler.user_bundle_path.join(Bundler.ruby_scope).join(git_scope) else path end end end alias_method :path, :install_path def extension_dir_name "#{base_name}-#{shortref_for_path(revision)}" end def unlock! git_proxy.revision = nil options["revision"] = nil @unlocked = true end def local_override!(path) return false if local? original_path = path path = Pathname.new(path) path = path.expand_path(Bundler.root) unless path.relative? unless options["branch"] || Bundler.settings[:disable_local_branch_check] raise GitError, "Cannot use local override for #{name} at #{path} because " \ ":branch is not specified in Gemfile. Specify a branch or run " \ "`bundle config unset local.#{override_for(original_path)}` to remove the local override" end unless path.exist? raise GitError, "Cannot use local override for #{name} because #{path} " \ "does not exist. Run `bundle config unset local.#{override_for(original_path)}` to remove the local override" end set_local!(path) # Create a new git proxy without the cached revision # so the Gemfile.lock always picks up the new revision. @git_proxy = GitProxy.new(path, uri, ref) if git_proxy.branch != options["branch"] && !Bundler.settings[:disable_local_branch_check] raise GitError, "Local override for #{name} at #{path} is using branch " \ "#{git_proxy.branch} but Gemfile specifies #{options["branch"]}" end changed = cached_revision && cached_revision != git_proxy.revision if !Bundler.settings[:disable_local_revision_check] && changed && !@unlocked && !git_proxy.contains?(cached_revision) raise GitError, "The Gemfile lock is pointing to revision #{shortref_for_display(cached_revision)} " \ "but the current branch in your local override for #{name} does not contain such commit. " \ "Please make sure your branch is up to date." end changed end def specs(*) set_local!(app_cache_path) if has_app_cache? && !local? if requires_checkout? && !@copied fetch git_proxy.copy_to(install_path, submodules) serialize_gemspecs_in(install_path) @copied = true end local_specs end def install(spec, options = {}) force = options[:force] print_using_message "Using #{version_message(spec)} from #{self}" if (requires_checkout? && !@copied) || force Bundler.ui.debug " * Checking out revision: #{ref}" git_proxy.copy_to(install_path, submodules) serialize_gemspecs_in(install_path) @copied = true end generate_bin_options = { :disable_extensions => !Bundler.rubygems.spec_missing_extensions?(spec), :build_args => options[:build_args] } generate_bin(spec, generate_bin_options) requires_checkout? ? spec.post_install_message : nil end def cache(spec, custom_path = nil) app_cache_path = app_cache_path(custom_path) return unless Bundler.feature_flag.cache_all? return if path == app_cache_path cached! FileUtils.rm_rf(app_cache_path) git_proxy.checkout if requires_checkout? git_proxy.copy_to(app_cache_path, @submodules) serialize_gemspecs_in(app_cache_path) end def load_spec_files super rescue PathError => e Bundler.ui.trace e raise GitError, "#{self} is not yet checked out. Run `bundle install` first." end # This is the path which is going to contain a cache # of the git repository. When using the same git repository # across different projects, this cache will be shared. # When using local git repos, this is set to the local repo. def cache_path @cache_path ||= begin if Bundler.requires_sudo? || Bundler.feature_flag.global_gem_cache? Bundler.user_cache else Bundler.bundle_path.join("cache", "bundler") end.join("git", git_scope) end end def app_cache_dirname "#{base_name}-#{shortref_for_path(cached_revision || revision)}" end def revision git_proxy.revision end def allow_git_ops? @allow_remote || @allow_cached end def local? @local end private def serialize_gemspecs_in(destination) destination = destination.expand_path(Bundler.root) if destination.relative? Dir["#{destination}/#{@glob}"].each do |spec_path| # Evaluate gemspecs and cache the result. Gemspecs # in git might require git or other dependencies. # The gemspecs we cache should already be evaluated. spec = Bundler.load_gemspec(spec_path) next unless spec Bundler.rubygems.set_installed_by_version(spec) Bundler.rubygems.validate(spec) File.open(spec_path, "wb") {|file| file.write(spec.to_ruby) } end end def set_local!(path) @local = true @local_specs = @git_proxy = nil @cache_path = @install_path = path end def has_app_cache? cached_revision && super end def requires_checkout? allow_git_ops? && !local? && !cached_revision_checked_out? end def cached_revision_checked_out? cached_revision && cached_revision == revision && install_path.exist? end def base_name File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)?(//\w*/)?(\w*/)*}, ""), ".git") end def shortref_for_display(ref) ref[0..6] end def shortref_for_path(ref) ref[0..11] end def uri_hash if uri =~ %r{^\w+://(\w+@)?} # Downcase the domain component of the URI # and strip off a trailing slash, if one is present input = Bundler::URI.parse(uri).normalize.to_s.sub(%r{/$}, "") else # If there is no URI scheme, assume it is an ssh/git URI input = uri end SharedHelpers.digest(:SHA1).hexdigest(input) end def cached_revision options["revision"] end def cached? cache_path.exist? end def git_proxy @git_proxy ||= GitProxy.new(cache_path, uri, ref, cached_revision, self) end def fetch git_proxy.checkout rescue GitError => e raise unless Bundler.feature_flag.allow_offline_install? Bundler.ui.warn "Using cached git data because of network errors:\n#{e}" end # no-op, since we validate when re-serializing the gemspec def validate_spec(_spec); end def load_gemspec(file) stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent) stub.full_gem_path = Pathname.new(file).dirname.expand_path(root).to_s.tap{|x| x.untaint if RUBY_VERSION < "2.7" } StubSpecification.from_stub(stub) end def git_scope "#{base_name}-#{uri_hash}" end def extension_cache_slug(_) extension_dir_name end def override_for(path) Bundler.settings.local_overrides.key(path) end end end end PK ])g@##7gems/bundler-2.2.24/lib/bundler/source/git/git_proxy.rbnu[# frozen_string_literal: true require "shellwords" module Bundler class Source class Git class GitNotInstalledError < GitError def initialize msg = String.new msg << "You need to install git to be able to use gems from git repositories. " msg << "For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git" super msg end end class GitNotAllowedError < GitError def initialize(command) msg = String.new msg << "Bundler is trying to run `#{command}` at runtime. You probably need to run `bundle install`. However, " msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md " msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}" super msg end end class GitCommandError < GitError attr_reader :command def initialize(command, path, extra_info = nil) @command = command msg = String.new msg << "Git error: command `#{command}` in directory #{path} has failed." msg << "\n#{extra_info}" if extra_info msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if path.exist? super msg end end class MissingGitRevisionError < GitCommandError def initialize(command, destination_path, ref, repo) msg = "Revision #{ref} does not exist in the repository #{repo}. Maybe you misspelled it?" super command, destination_path, msg end end # The GitProxy is responsible to interact with git repositories. # All actions required by the Git source is encapsulated in this # object. class GitProxy attr_accessor :path, :uri, :ref attr_writer :revision def initialize(path, uri, ref, revision = nil, git = nil) @path = path @uri = uri @ref = ref @revision = revision @git = git raise GitNotInstalledError.new if allow? && !Bundler.git_present? end def revision @revision ||= find_local_revision end def branch @branch ||= allowed_with_path do git("rev-parse", "--abbrev-ref", "HEAD", :dir => path).strip end end def contains?(commit) allowed_with_path do result, status = git_null("branch", "--contains", commit, :dir => path) status.success? && result =~ /^\* (.*)$/ end end def version git("--version").match(/(git version\s*)?((\.?\d+)+).*/)[2] end def full_version git("--version").sub("git version", "").strip end def checkout return if path.exist? && has_revision_cached? extra_ref = "#{ref}:#{ref}" if ref && ref.start_with?("refs/") Bundler.ui.info "Fetching #{URICredentialsFilter.credential_filtered_uri(uri)}" configured_uri = configured_uri_for(uri).to_s unless path.exist? SharedHelpers.filesystem_access(path.dirname) do |p| FileUtils.mkdir_p(p) end git_retry "clone", configured_uri, path.to_s, "--bare", "--no-hardlinks", "--quiet" return unless extra_ref end with_path do git_retry(*["fetch", "--force", "--quiet", "--tags", configured_uri, "refs/heads/*:refs/heads/*", extra_ref].compact, :dir => path) end end def copy_to(destination, submodules = false) # method 1 unless File.exist?(destination.join(".git")) begin SharedHelpers.filesystem_access(destination.dirname) do |p| FileUtils.mkdir_p(p) end SharedHelpers.filesystem_access(destination) do |p| FileUtils.rm_rf(p) end git_retry "clone", "--no-checkout", "--quiet", path.to_s, destination.to_s File.chmod(((File.stat(destination).mode | 0o777) & ~File.umask), destination) rescue Errno::EEXIST => e file_path = e.message[%r{.*?((?:[a-zA-Z]:)?/.*)}, 1] raise GitError, "Bundler could not install a gem because it needs to " \ "create a directory, but a file exists - #{file_path}. Please delete " \ "this file and try again." end end # method 2 git_retry "fetch", "--force", "--quiet", "--tags", path.to_s, :dir => destination begin git "reset", "--hard", @revision, :dir => destination rescue GitCommandError => e raise MissingGitRevisionError.new(e.command, destination, @revision, URICredentialsFilter.credential_filtered_uri(uri)) end if submodules git_retry "submodule", "update", "--init", "--recursive", :dir => destination elsif Gem::Version.create(version) >= Gem::Version.create("2.9.0") inner_command = "git -C $toplevel submodule deinit --force $sm_path" git_retry "submodule", "foreach", "--quiet", inner_command, :dir => destination end end private def git_null(*command, dir: nil) check_allowed(command) out, status = SharedHelpers.with_clean_git_env do capture_and_ignore_stderr(*capture3_args_for(command, dir)) end [URICredentialsFilter.credential_filtered_string(out, uri), status] end def git_retry(*command, dir: nil) command_with_no_credentials = check_allowed(command) Bundler::Retry.new("`#{command_with_no_credentials}` at #{dir || SharedHelpers.pwd}").attempts do git(*command, :dir => dir) end end def git(*command, dir: nil) command_with_no_credentials = check_allowed(command) out, status = SharedHelpers.with_clean_git_env do capture_and_filter_stderr(*capture3_args_for(command, dir)) end filtered_out = URICredentialsFilter.credential_filtered_string(out, uri) raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, filtered_out) unless status.success? filtered_out end def has_revision_cached? return unless @revision with_path { git("cat-file", "-e", @revision, :dir => path) } true rescue GitError false end def remove_cache FileUtils.rm_rf(path) end def find_local_revision allowed_with_path do git("rev-parse", "--verify", ref || "HEAD", :dir => path).strip end rescue GitCommandError => e raise MissingGitRevisionError.new(e.command, path, ref, URICredentialsFilter.credential_filtered_uri(uri)) end # Adds credentials to the URI as Fetcher#configured_uri_for does def configured_uri_for(uri) if /https?:/ =~ uri remote = Bundler::URI(uri) config_auth = Bundler.settings[remote.to_s] || Bundler.settings[remote.host] remote.userinfo ||= config_auth remote.to_s else uri end end def allow? @git ? @git.allow_git_ops? : true end def with_path(&blk) checkout unless path.exist? blk.call end def allowed_with_path return with_path { yield } if allow? raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application" end def check_allowed(command) command_with_no_credentials = URICredentialsFilter.credential_filtered_string("git #{command.shelljoin}", uri) raise GitNotAllowedError.new(command_with_no_credentials) unless allow? command_with_no_credentials end def capture_and_filter_stderr(*cmd) require "open3" return_value, captured_err, status = Open3.capture3(*cmd) Bundler.ui.warn URICredentialsFilter.credential_filtered_string(captured_err, uri) unless captured_err.empty? [return_value, status] end def capture_and_ignore_stderr(*cmd) require "open3" return_value, _, status = Open3.capture3(*cmd) [return_value, status] end def capture3_args_for(cmd, dir) return ["git", *cmd] unless dir if Bundler.feature_flag.bundler_3_mode? || supports_minus_c? ["git", "-C", dir.to_s, *cmd] else ["git", *cmd, { :chdir => dir.to_s }] end end def supports_minus_c? @supports_minus_c ||= Gem::Version.new(version) >= Gem::Version.new("1.8.5") end end end end end PK ]ƣZ+gems/bundler-2.2.24/lib/bundler/spec_set.rbnu[# frozen_string_literal: true require "tsort" module Bundler class SpecSet include Enumerable include TSort def initialize(specs) @specs = specs end def for(dependencies, check = false, match_current_platform = false, raise_on_missing = true) handled = [] deps = dependencies.dup specs = [] loop do break unless dep = deps.shift next if handled.any?{|d| d.name == dep.name && (match_current_platform || d.__platform == dep.__platform) } || dep.name == "bundler" handled << dep specs_for_dep = spec_for_dependency(dep, match_current_platform) if specs_for_dep.any? specs += specs_for_dep specs_for_dep.first.dependencies.each do |d| next if d.type == :development d = DepProxy.get_proxy(d, dep.__platform) unless match_current_platform deps << d end elsif check return false elsif raise_on_missing others = lookup[dep.name] if match_current_platform message = "Unable to find a spec satisfying #{dep} in the set. Perhaps the lockfile is corrupted?" message += " Found #{others.join(", ")} that did not match the current platform." if others && !others.empty? raise GemNotFound, message end end if spec = lookup["bundler"].first specs << spec end check ? true : specs end def [](key) key = key.name if key.respond_to?(:name) lookup[key].reverse end def []=(key, value) @specs << value @lookup = nil @sorted = nil end def sort! self end def to_a sorted.dup end def to_hash lookup.dup end def materialize(deps, missing_specs = nil) materialized = self.for(deps, false, true, !missing_specs) materialized.group_by(&:source).each do |source, specs| next unless specs.any?{|s| s.is_a?(LazySpecification) } source.local! names = -> { specs.map(&:name).uniq } source.double_check_for(names) end materialized.map! do |s| next s unless s.is_a?(LazySpecification) spec = s.__materialize__ unless spec unless missing_specs raise GemNotFound, "Could not find #{s.full_name} in any of the sources" end missing_specs << s end spec end SpecSet.new(missing_specs ? materialized.compact : materialized) end # Materialize for all the specs in the spec set, regardless of what platform they're for # This is in contrast to how for does platform filtering (and specifically different from how `materialize` calls `for` only for the current platform) # @return [Array] def materialized_for_all_platforms @specs.group_by(&:source).each do |source, specs| next unless specs.any?{|s| s.is_a?(LazySpecification) } source.local! source.remote! names = -> { specs.map(&:name).uniq } source.double_check_for(names) end @specs.map do |s| next s unless s.is_a?(LazySpecification) spec = s.__materialize__ raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec spec end end def merge(set) arr = sorted.dup set.each do |set_spec| full_name = set_spec.full_name next if arr.any? {|spec| spec.full_name == full_name } arr << set_spec end SpecSet.new(arr) end def find_by_name_and_platform(name, platform) @specs.detect {|spec| spec.name == name && spec.match_platform(platform) } end def what_required(spec) unless req = find {|s| s.dependencies.any? {|d| d.type == :runtime && d.name == spec.name } } return [spec] end what_required(req) << spec end def <<(spec) @specs << spec end def length @specs.length end def size @specs.size end def empty? @specs.empty? end def each(&b) sorted.each(&b) end private def sorted rake = @specs.find {|s| s.name == "rake" } begin @sorted ||= ([rake] + tsort).compact.uniq rescue TSort::Cyclic => error cgems = extract_circular_gems(error) raise CyclicDependencyError, "Your bundle requires gems that depend" \ " on each other, creating an infinite loop. Please remove either" \ " gem '#{cgems[1]}' or gem '#{cgems[0]}' and try again." end end def extract_circular_gems(error) error.message.scan(/@name="(.*?)"/).flatten end def lookup @lookup ||= begin lookup = Hash.new {|h, k| h[k] = [] } Index.sort_specs(@specs).reverse_each do |s| lookup[s.name] << s end lookup end end def tsort_each_node # MUST sort by name for backwards compatibility @specs.sort_by(&:name).each {|s| yield s } end def spec_for_dependency(dep, match_current_platform) specs_for_platforms = lookup[dep.name] if match_current_platform GemHelpers.select_best_platform_match(specs_for_platforms.select{|s| Gem::Platform.match_spec?(s) }, Bundler.local_platform) else GemHelpers.select_best_platform_match(specs_for_platforms, dep.__platform) end end def tsort_each_child(s) s.dependencies.sort_by(&:name).each do |d| next if d.type == :development lookup[d.name].each {|s2| yield s2 } end end end end PK ]4f++7gems/bundler-2.2.24/lib/bundler/gem_version_promoter.rbnu[# frozen_string_literal: true module Bundler # This class contains all of the logic for determining the next version of a # Gem to update to based on the requested level (patch, minor, major). # Primarily designed to work with Resolver which will provide it the list of # available dependency versions as found in its index, before returning it to # to the resolution engine to select the best version. class GemVersionPromoter DEBUG = ENV["BUNDLER_DEBUG_RESOLVER"] || ENV["DEBUG_RESOLVER"] attr_reader :level, :locked_specs, :unlock_gems # By default, strict is false, meaning every available version of a gem # is returned from sort_versions. The order gives preference to the # requested level (:patch, :minor, :major) but in complicated requirement # cases some gems will by necessity by promoted past the requested level, # or even reverted to older versions. # # If strict is set to true, the results from sort_versions will be # truncated, eliminating any version outside the current level scope. # This can lead to unexpected outcomes or even VersionConflict exceptions # that report a version of a gem not existing for versions that indeed do # existing in the referenced source. attr_accessor :strict attr_accessor :prerelease_specified # Given a list of locked_specs and a list of gems to unlock creates a # GemVersionPromoter instance. # # @param locked_specs [SpecSet] All current locked specs. Unlike Definition # where this list is empty if all gems are being updated, this should # always be populated for all gems so this class can properly function. # @param unlock_gems [String] List of gem names being unlocked. If empty, # all gems will be considered unlocked. # @return [GemVersionPromoter] def initialize(locked_specs = SpecSet.new([]), unlock_gems = []) @level = :major @strict = false @locked_specs = locked_specs @unlock_gems = unlock_gems @sort_versions = {} @prerelease_specified = {} end # @param value [Symbol] One of three Symbols: :major, :minor or :patch. def level=(value) v = case value when String, Symbol value.to_sym end raise ArgumentError, "Unexpected level #{v}. Must be :major, :minor or :patch" unless [:major, :minor, :patch].include?(v) @level = v end # Given a Dependency and an Array of SpecGroups of available versions for a # gem, this method will return the Array of SpecGroups sorted (and possibly # truncated if strict is true) in an order to give preference to the current # level (:major, :minor or :patch) when resolution is deciding what versions # best resolve all dependencies in the bundle. # @param dep [Dependency] The Dependency of the gem. # @param spec_groups [SpecGroup] An array of SpecGroups for the same gem # named in the @dep param. # @return [SpecGroup] A new instance of the SpecGroup Array sorted and # possibly filtered. def sort_versions(dep, spec_groups) before_result = "before sort_versions: #{debug_format_result(dep, spec_groups).inspect}" if DEBUG @sort_versions[dep] ||= begin gem_name = dep.name # An Array per version returned, different entries for different platforms. # We only need the version here so it's ok to hard code this to the first instance. locked_spec = locked_specs[gem_name].first if strict filter_dep_specs(spec_groups, locked_spec) else sort_dep_specs(spec_groups, locked_spec) end.tap do |specs| if DEBUG puts before_result puts " after sort_versions: #{debug_format_result(dep, specs).inspect}" end end end end # @return [bool] Convenience method for testing value of level variable. def major? level == :major end # @return [bool] Convenience method for testing value of level variable. def minor? level == :minor end private def filter_dep_specs(spec_groups, locked_spec) res = spec_groups.select do |spec_group| if locked_spec && !major? gsv = spec_group.version lsv = locked_spec.version must_match = minor? ? [0] : [0, 1] matches = must_match.map {|idx| gsv.segments[idx] == lsv.segments[idx] } matches.uniq == [true] ? (gsv >= lsv) : false else true end end sort_dep_specs(res, locked_spec) end def sort_dep_specs(spec_groups, locked_spec) return spec_groups unless locked_spec @gem_name = locked_spec.name @locked_version = locked_spec.version result = spec_groups.sort do |a, b| @a_ver = a.version @b_ver = b.version unless @prerelease_specified[@gem_name] a_pre = @a_ver.prerelease? b_pre = @b_ver.prerelease? next -1 if a_pre && !b_pre next 1 if b_pre && !a_pre end if major? @a_ver <=> @b_ver elsif either_version_older_than_locked @a_ver <=> @b_ver elsif segments_do_not_match(:major) @b_ver <=> @a_ver elsif !minor? && segments_do_not_match(:minor) @b_ver <=> @a_ver else @a_ver <=> @b_ver end end post_sort(result) end def either_version_older_than_locked @a_ver < @locked_version || @b_ver < @locked_version end def segments_do_not_match(level) index = [:major, :minor].index(level) @a_ver.segments[index] != @b_ver.segments[index] end def unlocking_gem? unlock_gems.empty? || unlock_gems.include?(@gem_name) end # Specific version moves can't always reliably be done during sorting # as not all elements are compared against each other. def post_sort(result) # default :major behavior in Bundler does not do this return result if major? if unlocking_gem? result else move_version_to_end(result, @locked_version) end end def move_version_to_end(result, version) move, keep = result.partition {|s| s.version.to_s == version.to_s } keep.concat(move) end def debug_format_result(dep, spec_groups) a = [dep.to_s, spec_groups.map {|sg| [sg.version, sg.dependencies_for_activated_platforms.map {|dp| [dp.name, dp.requirement.to_s] }] }] last_map = a.last.map {|sg_data| [sg_data.first.version, sg_data.last.map {|aa| aa.join(" ") }] } [a.first, last_map, level, strict ? :strict : :not_strict] end end end PK ]Tee5gems/bundler-2.2.24/lib/bundler/vendored_molinillo.rbnu[# frozen_string_literal: true module Bundler; end require_relative "vendor/molinillo/lib/molinillo" PK ]z]EE7gems/bundler-2.2.24/lib/bundler/rubygems_integration.rbnu[# frozen_string_literal: true require "rubygems" unless defined?(Gem) module Bundler class RubygemsIntegration if defined?(Gem::Ext::Builder::CHDIR_MONITOR) EXT_LOCK = Gem::Ext::Builder::CHDIR_MONITOR else require "monitor" EXT_LOCK = Monitor.new end def self.version @version ||= Gem::Version.new(Gem::VERSION) end def self.provides?(req_str) Gem::Requirement.new(req_str).satisfied_by?(version) end def initialize @replaced_methods = {} backport_ext_builder_monitor end def version self.class.version end def provides?(req_str) self.class.provides?(req_str) end def build_args Gem::Command.build_args end def build_args=(args) Gem::Command.build_args = args end def loaded_specs(name) Gem.loaded_specs[name] end def add_to_load_path(paths) return Gem.add_to_load_path(*paths) if Gem.respond_to?(:add_to_load_path) if insert_index = Gem.load_path_insert_index # Gem directories must come after -I and ENV['RUBYLIB'] $LOAD_PATH.insert(insert_index, *paths) else # We are probably testing in core, -I and RUBYLIB don't apply $LOAD_PATH.unshift(*paths) end end def mark_loaded(spec) if spec.respond_to?(:activated=) current = Gem.loaded_specs[spec.name] current.activated = false if current spec.activated = true end Gem.loaded_specs[spec.name] = spec end def validate(spec) Bundler.ui.silence { spec.validate(false) } rescue Gem::InvalidSpecificationException => e error_message = "The gemspec at #{spec.loaded_from} is not valid. Please fix this gemspec.\n" \ "The validation error was '#{e.message}'\n" raise Gem::InvalidSpecificationException.new(error_message) rescue Errno::ENOENT nil end def set_installed_by_version(spec, installed_by_version = Gem::VERSION) return unless spec.respond_to?(:installed_by_version=) spec.installed_by_version = Gem::Version.create(installed_by_version) end def spec_missing_extensions?(spec, default = true) return spec.missing_extensions? if spec.respond_to?(:missing_extensions?) return false if spec_default_gem?(spec) return false if spec.extensions.empty? default end def spec_default_gem?(spec) spec.respond_to?(:default_gem?) && spec.default_gem? end def spec_matches_for_glob(spec, glob) return spec.matches_for_glob(glob) if spec.respond_to?(:matches_for_glob) spec.load_paths.map do |lp| Dir["#{lp}/#{glob}#{suffix_pattern}"] end.flatten(1) end def stub_set_spec(stub, spec) stub.instance_variable_set(:@spec, spec) end def path(obj) obj.to_s end def configuration require_relative "psyched_yaml" Gem.configuration rescue Gem::SystemExitException, LoadError => e Bundler.ui.error "#{e.class}: #{e.message}" Bundler.ui.trace e raise rescue YamlLibrarySyntaxError => e raise YamlSyntaxError.new(e, "Your RubyGems configuration, which is " \ "usually located in ~/.gemrc, contains invalid YAML syntax.") end def ruby_engine Gem.ruby_engine end def read_binary(path) Gem.read_binary(path) end def inflate(obj) Gem::Util.inflate(obj) end def correct_for_windows_path(path) if Gem::Util.respond_to?(:correct_for_windows_path) Gem::Util.correct_for_windows_path(path) elsif path[0].chr == "/" && path[1].chr =~ /[a-z]/i && path[2].chr == ":" path[1..-1] else path end end def sources=(val) # Gem.configuration creates a new Gem::ConfigFile, which by default will read ~/.gemrc # If that file exists, its settings (including sources) will overwrite the values we # are about to set here. In order to avoid that, we force memoizing the config file now. configuration Gem.sources = val end def sources Gem.sources end def gem_dir Gem.dir end def gem_bindir Gem.bindir end def user_home Gem.user_home end def gem_path Gem.path end def reset Gem::Specification.reset end def post_reset_hooks Gem.post_reset_hooks end def suffix_pattern Gem.suffix_pattern end def gem_cache gem_path.map {|p| File.expand_path("cache", p) } end def spec_cache_dirs @spec_cache_dirs ||= begin dirs = gem_path.map {|dir| File.join(dir, "specifications") } dirs << Gem.spec_cache_dir if Gem.respond_to?(:spec_cache_dir) # Not in RubyGems 2.0.3 or earlier dirs.uniq.select {|dir| File.directory? dir } end end def marshal_spec_dir Gem::MARSHAL_SPEC_DIR end def clear_paths Gem.clear_paths end def bin_path(gem, bin, ver) Gem.bin_path(gem, bin, ver) end def loaded_gem_paths loaded_gem_paths = Gem.loaded_specs.map {|_, s| s.full_require_paths } loaded_gem_paths.flatten end def load_plugins Gem.load_plugins if Gem.respond_to?(:load_plugins) end def load_plugin_files(files) Gem.load_plugin_files(files) if Gem.respond_to?(:load_plugin_files) end def load_env_plugins Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins) end def ui=(obj) Gem::DefaultUserInteraction.ui = obj end def ext_lock EXT_LOCK end def with_build_args(args) ext_lock.synchronize do old_args = build_args begin self.build_args = args yield ensure self.build_args = old_args end end end def spec_from_gem(path, policy = nil) require "rubygems/security" require_relative "psyched_yaml" gem_from_path(path, security_policies[policy]).spec rescue Exception, Gem::Exception, Gem::Security::Exception => e # rubocop:disable Lint/RescueException if e.is_a?(Gem::Security::Exception) || e.message =~ /unknown trust policy|unsigned gem/i || e.message =~ /couldn't verify (meta)?data signature/i raise SecurityError, "The gem #{File.basename(path, ".gem")} can't be installed because " \ "the security policy didn't allow it, with the message: #{e.message}" else raise e end end def build_gem(gem_dir, spec) build(spec) end def security_policy_keys %w[High Medium Low AlmostNo No].map {|level| "#{level}Security" } end def security_policies @security_policies ||= begin require "rubygems/security" Gem::Security::Policies rescue LoadError, NameError {} end end def reverse_rubygems_kernel_mixin # Disable rubygems' gem activation system kernel = (class << ::Kernel; self; end) [kernel, ::Kernel].each do |k| if k.private_method_defined?(:gem_original_require) redefine_method(k, :require, k.instance_method(:gem_original_require)) end end end def replace_gem(specs, specs_by_name) reverse_rubygems_kernel_mixin executables = nil kernel = (class << ::Kernel; self; end) [kernel, ::Kernel].each do |kernel_class| redefine_method(kernel_class, :gem) do |dep, *reqs| if executables && executables.include?(File.basename(caller.first.split(":").first)) break end reqs.pop if reqs.last.is_a?(Hash) unless dep.respond_to?(:name) && dep.respond_to?(:requirement) dep = Gem::Dependency.new(dep, reqs) end if spec = specs_by_name[dep.name] return true if dep.matches_spec?(spec) end message = if spec.nil? target_file = begin Bundler.default_gemfile.basename rescue GemfileNotFound "inline Gemfile" end "#{dep.name} is not part of the bundle." \ " Add it to your #{target_file}." else "can't activate #{dep}, already activated #{spec.full_name}. " \ "Make sure all dependencies are added to Gemfile." end e = Gem::LoadError.new(message) e.name = dep.name if e.respond_to?(:requirement=) e.requirement = dep.requirement elsif e.respond_to?(:version_requirement=) e.version_requirement = dep.requirement end raise e end # backwards compatibility shim, see https://github.com/rubygems/bundler/issues/5102 kernel_class.send(:public, :gem) if Bundler.feature_flag.setup_makes_kernel_gem_public? end end # Used to make bin stubs that are not created by bundler work # under bundler. The new Gem.bin_path only considers gems in # +specs+ def replace_bin_path(specs_by_name) gem_class = (class << Gem; self; end) redefine_method(gem_class, :find_spec_for_exe) do |gem_name, *args| exec_name = args.first raise ArgumentError, "you must supply exec_name" unless exec_name spec_with_name = specs_by_name[gem_name] matching_specs_by_exec_name = specs_by_name.values.select {|s| s.executables.include?(exec_name) } spec = matching_specs_by_exec_name.delete(spec_with_name) unless spec || !matching_specs_by_exec_name.empty? message = "can't find executable #{exec_name} for gem #{gem_name}" if spec_with_name.nil? message += ". #{gem_name} is not currently included in the bundle, " \ "perhaps you meant to add it to your #{Bundler.default_gemfile.basename}?" end raise Gem::Exception, message end unless spec spec = matching_specs_by_exec_name.shift warn \ "Bundler is using a binstub that was created for a different gem (#{spec.name}).\n" \ "You should run `bundle binstub #{gem_name}` " \ "to work around a system/bundle conflict." end unless matching_specs_by_exec_name.empty? conflicting_names = matching_specs_by_exec_name.map(&:name).join(", ") warn \ "The `#{exec_name}` executable in the `#{spec.name}` gem is being loaded, but it's also present in other gems (#{conflicting_names}).\n" \ "If you meant to run the executable for another gem, make sure you use a project specific binstub (`bundle binstub `).\n" \ "If you plan to use multiple conflicting executables, generate binstubs for them and disambiguate their names." end spec end redefine_method(gem_class, :activate_bin_path) do |name, *args| exec_name = args.first return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle" # Copy of Rubygems activate_bin_path impl requirement = args.last spec = find_spec_for_exe name, exec_name, [requirement] gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name) gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name) File.exist?(gem_bin) ? gem_bin : gem_from_path_bin end redefine_method(gem_class, :bin_path) do |name, *args| exec_name = args.first return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle" spec = find_spec_for_exe(name, *args) exec_name ||= spec.default_executable gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name) gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name) File.exist?(gem_bin) ? gem_bin : gem_from_path_bin end end # Replace or hook into RubyGems to provide a bundlerized view # of the world. def replace_entrypoints(specs) specs_by_name = add_default_gems_to(specs) replace_gem(specs, specs_by_name) stub_rubygems(specs) replace_bin_path(specs_by_name) Gem.clear_paths end # Add default gems not already present in specs, and return them as a hash. def add_default_gems_to(specs) specs_by_name = specs.reduce({}) do |h, s| h[s.name] = s h end Bundler.rubygems.default_stubs.each do |stub| default_spec = stub.to_spec default_spec_name = default_spec.name next if specs_by_name.key?(default_spec_name) specs << default_spec specs_by_name[default_spec_name] = default_spec end specs_by_name end def undo_replacements @replaced_methods.each do |(sym, klass), method| redefine_method(klass, sym, method) end if Binding.public_method_defined?(:source_location) post_reset_hooks.reject! {|proc| proc.binding.source_location[0] == __FILE__ } else post_reset_hooks.reject! {|proc| proc.binding.eval("__FILE__") == __FILE__ } end @replaced_methods.clear end def redefine_method(klass, method, unbound_method = nil, &block) visibility = method_visibility(klass, method) begin if (instance_method = klass.instance_method(method)) && method != :initialize # doing this to ensure we also get private methods klass.send(:remove_method, method) end rescue NameError # method isn't defined nil end @replaced_methods[[method, klass]] = instance_method if unbound_method klass.send(:define_method, method, unbound_method) klass.send(visibility, method) elsif block klass.send(:define_method, method, &block) klass.send(visibility, method) end end def method_visibility(klass, method) if klass.private_method_defined?(method) :private elsif klass.protected_method_defined?(method) :protected else :public end end def stub_rubygems(specs) Gem::Specification.all = specs Gem.post_reset do Gem::Specification.all = specs end redefine_method((class << Gem; self; end), :finish_resolve) do |*| [] end end def plain_specs Gem::Specification._all end def plain_specs=(specs) Gem::Specification.all = specs end def fetch_specs(remote, name) path = remote.uri.to_s + "#{name}.#{Gem.marshal_version}.gz" fetcher = gem_remote_fetcher fetcher.headers = { "X-Gemfile-Source" => remote.original_uri.to_s } if remote.original_uri string = fetcher.fetch_path(path) Bundler.load_marshal(string) rescue Gem::RemoteFetcher::FetchError => e # it's okay for prerelease to fail raise e unless name == "prerelease_specs" end def fetch_all_remote_specs(remote) specs = fetch_specs(remote, "specs") pres = fetch_specs(remote, "prerelease_specs") || [] specs.concat(pres) end def download_gem(spec, uri, path) uri = Bundler.settings.mirror_for(uri) fetcher = gem_remote_fetcher fetcher.headers = { "X-Gemfile-Source" => spec.remote.original_uri.to_s } if spec.remote.original_uri Bundler::Retry.new("download gem from #{uri}").attempts do fetcher.download(spec, uri, path) end rescue Gem::RemoteFetcher::FetchError => e raise Bundler::HTTPError, "Could not download gem from #{uri} due to underlying error <#{e.message}>" end def gem_remote_fetcher require "rubygems/remote_fetcher" proxy = configuration[:http_proxy] Gem::RemoteFetcher.new(proxy) end def gem_from_path(path, policy = nil) require "rubygems/package" p = Gem::Package.new(path) p.security_policy = policy if policy p end def build(spec, skip_validation = false) require "rubygems/package" Gem::Package.build(spec, skip_validation) end def repository_subdirectories Gem::REPOSITORY_SUBDIRECTORIES end def install_with_build_args(args) yield end def path_separator Gem.path_separator end def all_specs Gem::Specification.stubs.map do |stub| StubSpecification.from_stub(stub) end end def backport_ext_builder_monitor # So we can avoid requiring "rubygems/ext" in its entirety Gem.module_eval <<-RUBY, __FILE__, __LINE__ + 1 module Ext end RUBY require "rubygems/ext/builder" Gem::Ext::Builder.class_eval do unless const_defined?(:CHDIR_MONITOR) const_set(:CHDIR_MONITOR, EXT_LOCK) end remove_const(:CHDIR_MUTEX) if const_defined?(:CHDIR_MUTEX) const_set(:CHDIR_MUTEX, const_get(:CHDIR_MONITOR)) end end def find_name(name) Gem::Specification.stubs_for(name).map(&:to_spec) end if Gem::Specification.respond_to?(:default_stubs) def default_stubs Gem::Specification.default_stubs("*.gemspec") end else def default_stubs Gem::Specification.send(:default_stubs, "*.gemspec") end end def use_gemdeps(gemfile) ENV["BUNDLE_GEMFILE"] ||= File.expand_path(gemfile) require_relative "gemdeps" runtime = Bundler.setup activated_spec_names = runtime.requested_specs.map(&:to_spec).sort_by(&:name) [Gemdeps.new(runtime), activated_spec_names] end end def self.rubygems @rubygems ||= RubygemsIntegration.new end end PK ] X6*gems/bundler-2.2.24/lib/bundler/version.rbnu[# frozen_string_literal: false module Bundler VERSION = "2.2.24".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i end end PK ]#/gems/bundler-2.2.24/lib/bundler/current_ruby.rbnu[# frozen_string_literal: true module Bundler # Returns current version of Ruby # # @return [CurrentRuby] Current version of Ruby def self.current_ruby @current_ruby ||= CurrentRuby.new end class CurrentRuby KNOWN_MINOR_VERSIONS = %w[ 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 3.0 ].freeze KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze KNOWN_PLATFORMS = %w[ jruby maglev mingw mri mswin mswin64 rbx ruby truffleruby x64_mingw ].freeze def ruby? return true if Bundler::GemHelpers.generic_local_platform == Gem::Platform::RUBY !mswin? && (RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby") end def mri? !mswin? && RUBY_ENGINE == "ruby" end def rbx? ruby? && RUBY_ENGINE == "rbx" end def jruby? RUBY_ENGINE == "jruby" end def maglev? RUBY_ENGINE == "maglev" end def truffleruby? RUBY_ENGINE == "truffleruby" end def mswin? Gem.win_platform? end def mswin64? Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64" end def mingw? Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64" end def x64_mingw? Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64" end (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version| trimmed_version = version.tr(".", "") define_method(:"on_#{trimmed_version}?") do RUBY_VERSION.start_with?("#{version}.") end KNOWN_PLATFORMS.each do |platform| define_method(:"#{platform}_#{trimmed_version}?") do send(:"#{platform}?") && send(:"on_#{trimmed_version}?") end end end end end PK ])PY\\6gems/bundler-2.2.24/lib/bundler/similarity_detector.rbnu[# frozen_string_literal: true module Bundler class SimilarityDetector SimilarityScore = Struct.new(:string, :distance) # initialize with an array of words to be matched against def initialize(corpus) @corpus = corpus end # return an array of words similar to 'word' from the corpus def similar_words(word, limit = 3) words_by_similarity = @corpus.map {|w| SimilarityScore.new(w, levenshtein_distance(word, w)) } words_by_similarity.select {|s| s.distance <= limit }.sort_by(&:distance).map(&:string) end # return the result of 'similar_words', concatenated into a list # (eg "a, b, or c") def similar_word_list(word, limit = 3) words = similar_words(word, limit) if words.length == 1 words[0] elsif words.length > 1 [words[0..-2].join(", "), words[-1]].join(" or ") end end protected # https://www.informit.com/articles/article.aspx?p=683059&seqNum=36 def levenshtein_distance(this, that, ins = 2, del = 2, sub = 1) # ins, del, sub are weighted costs return nil if this.nil? return nil if that.nil? dm = [] # distance matrix # Initialize first row values dm[0] = (0..this.length).collect {|i| i * ins } fill = [0] * (this.length - 1) # Initialize first column values (1..that.length).each do |i| dm[i] = [i * del, fill.flatten] end # populate matrix (1..that.length).each do |i| (1..this.length).each do |j| # critical comparison dm[i][j] = [ dm[i - 1][j - 1] + (this[j - 1] == that[i - 1] ? 0 : sub), dm[i][j - 1] + ins, dm[i - 1][j] + del, ].min end end # The last value in matrix is the Levenshtein distance between the strings dm[that.length][this.length] end end end PK ]6e$ll,gems/bundler-2.2.24/lib/bundler/deprecate.rbnu[# frozen_string_literal: true begin require "rubygems/deprecate" rescue LoadError # it's fine if it doesn't exist on the current RubyGems... nil end module Bundler # If Bundler::Deprecate is an autoload constant, we need to define it if defined?(Bundler::Deprecate) && !autoload?(:Deprecate) # nothing to do! elsif defined? ::Deprecate Deprecate = ::Deprecate elsif defined? Gem::Deprecate Deprecate = Gem::Deprecate else class Deprecate end end unless Deprecate.respond_to?(:skip_during) def Deprecate.skip_during original = skip self.skip = true yield ensure self.skip = original end end unless Deprecate.respond_to?(:skip) def Deprecate.skip @skip ||= false end end unless Deprecate.respond_to?(:skip=) def Deprecate.skip=(skip) @skip = skip end end end PK ]|YY/gems/bundler-2.2.24/lib/bundler/vendored_uri.rbnu[# frozen_string_literal: true module Bundler; end require_relative "vendor/uri/lib/uri" PK ]یYY7gems/bundler-2.2.24/lib/bundler/compact_index_client.rbnu[# frozen_string_literal: true require "pathname" require "set" module Bundler class CompactIndexClient DEBUG_MUTEX = Mutex.new def self.debug return unless ENV["DEBUG_COMPACT_INDEX"] DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") } end class Error < StandardError; end require_relative "compact_index_client/cache" require_relative "compact_index_client/updater" attr_reader :directory def initialize(directory, fetcher) @directory = Pathname.new(directory) @updater = Updater.new(fetcher) @cache = Cache.new(@directory) @endpoints = Set.new @info_checksums_by_name = {} @parsed_checksums = false @mutex = Mutex.new end def execution_mode=(block) Bundler::CompactIndexClient.debug { "execution_mode=" } @endpoints = Set.new @execution_mode = block end # @return [Lambda] A lambda that takes an array of inputs and a block, and # maps the inputs with the block in parallel. # def execution_mode @execution_mode || sequentially end def sequential_execution_mode! self.execution_mode = sequentially end def sequentially @sequentially ||= lambda do |inputs, &blk| inputs.map(&blk) end end def names Bundler::CompactIndexClient.debug { "/names" } update(@cache.names_path, "names") @cache.names end def versions Bundler::CompactIndexClient.debug { "/versions" } update(@cache.versions_path, "versions") versions, @info_checksums_by_name = @cache.versions versions end def dependencies(names) Bundler::CompactIndexClient.debug { "dependencies(#{names})" } execution_mode.call(names) do |name| update_info(name) @cache.dependencies(name).map {|d| d.unshift(name) } end.flatten(1) end def spec(name, version, platform = nil) Bundler::CompactIndexClient.debug { "spec(name = #{name}, version = #{version}, platform = #{platform})" } update_info(name) @cache.specific_dependency(name, version, platform) end def update_and_parse_checksums! Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" } return @info_checksums_by_name if @parsed_checksums update(@cache.versions_path, "versions") @info_checksums_by_name = @cache.checksums @parsed_checksums = true end private def update(local_path, remote_path) Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" } unless synchronize { @endpoints.add?(remote_path) } Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" } return end @updater.update(local_path, url(remote_path)) end def update_info(name) Bundler::CompactIndexClient.debug { "update_info(#{name})" } path = @cache.info_path(name) checksum = @updater.checksum_for_file(path) unless existing = @info_checksums_by_name[name] Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" } return end if checksum == existing Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" } return end Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" } update(path, "info/#{name}") end def url(path) path end def synchronize @mutex.synchronize { yield } end end end PK ]j[] ] )gems/bundler-2.2.24/lib/bundler/worker.rbnu[# frozen_string_literal: true module Bundler class Worker POISON = Object.new class WrappedException < StandardError attr_reader :exception def initialize(exn) @exception = exn end end # @return [String] the name of the worker attr_reader :name # Creates a worker pool of specified size # # @param size [Integer] Size of pool # @param name [String] name the name of the worker # @param func [Proc] job to run in inside the worker pool def initialize(size, name, func) @name = name @request_queue = Queue.new @response_queue = Queue.new @func = func @size = size @threads = nil SharedHelpers.trap("INT") { abort_threads } end # Enqueue a request to be executed in the worker pool # # @param obj [String] mostly it is name of spec that should be downloaded def enq(obj) create_threads unless @threads @request_queue.enq obj end # Retrieves results of job function being executed in worker pool def deq result = @response_queue.deq raise result.exception if result.is_a?(WrappedException) result end def stop stop_threads end private def process_queue(i) loop do obj = @request_queue.deq break if obj.equal? POISON @response_queue.enq apply_func(obj, i) end end def apply_func(obj, i) @func.call(obj, i) rescue Exception => e # rubocop:disable Lint/RescueException WrappedException.new(e) end # Stop the worker threads by sending a poison object down the request queue # so as worker threads after retrieving it, shut themselves down def stop_threads return unless @threads @threads.each { @request_queue.enq POISON } @threads.each(&:join) @threads = nil end def abort_threads return unless @threads Bundler.ui.debug("\n#{caller.join("\n")}") @threads.each(&:exit) exit 1 end def create_threads creation_errors = [] @threads = Array.new(@size) do |i| begin Thread.start { process_queue(i) }.tap do |thread| thread.name = "#{name} Worker ##{i}" if thread.respond_to?(:name=) end rescue ThreadError => e creation_errors << e nil end end.compact return if creation_errors.empty? message = "Failed to create threads for the #{name} worker: #{creation_errors.map(&:to_s).uniq.join(", ")}" raise ThreadCreationError, message if @threads.empty? Bundler.ui.info message end end end PK ]<, , 5gems/bundler-2.2.24/lib/bundler/settings/validator.rbnu[# frozen_string_literal: true module Bundler class Settings class Validator class Rule attr_reader :description def initialize(keys, description, &validate) @keys = keys @description = description @validate = validate end def validate!(key, value, settings) instance_exec(key, value, settings, &@validate) end def fail!(key, value, *reasons) reasons.unshift @description raise InvalidOption, "Setting `#{key}` to #{value.inspect} failed:\n#{reasons.map {|r| " - #{r}" }.join("\n")}" end def set(settings, key, value, *reasons) hash_key = k(key) return if settings[hash_key] == value reasons.unshift @description Bundler.ui.info "Setting `#{key}` to #{value.inspect}, since #{reasons.join(", ")}" if value.nil? settings.delete(hash_key) else settings[hash_key] = value end end def k(key) Bundler.settings.key_for(key) end end def self.rules @rules ||= Hash.new {|h, k| h[k] = [] } end private_class_method :rules def self.rule(keys, description, &blk) rule = Rule.new(keys, description, &blk) keys.each {|k| rules[k] << rule } end private_class_method :rule def self.validate!(key, value, settings) rules_to_validate = rules[key] rules_to_validate.each {|rule| rule.validate!(key, value, settings) } end rule %w[path path.system], "path and path.system are mutually exclusive" do |key, value, settings| if key == "path" && value set(settings, "path.system", nil) elsif key == "path.system" && value set(settings, :path, nil) end end rule %w[with without], "a group cannot be in both `with` & `without` simultaneously" do |key, value, settings| with = settings.fetch(k(:with), "").split(":").map(&:to_sym) without = settings.fetch(k(:without), "").split(":").map(&:to_sym) other_key = key == "with" ? :without : :with other_setting = key == "with" ? without : with conflicting = with & without if conflicting.any? fail!(key, value, "`#{other_key}` is current set to #{other_setting.inspect}", "the `#{conflicting.join("`, `")}` groups conflict") end end rule %w[path], "relative paths are expanded relative to the current working directory" do |key, value, settings| next if value.nil? path = Pathname.new(value) next if !path.relative? || !Bundler.feature_flag.path_relative_to_cwd? path = path.expand_path root = begin Bundler.root rescue GemfileNotFound Pathname.pwd.expand_path end path = begin path.relative_path_from(root) rescue ArgumentError path end set(settings, key, path.to_s) end end end end PK ]h =gems/bundler-2.2.24/lib/bundler/compact_index_client/cache.rbnu[# frozen_string_literal: true require_relative "gem_parser" module Bundler class CompactIndexClient class Cache attr_reader :directory def initialize(directory) @directory = Pathname.new(directory).expand_path info_roots.each do |dir| SharedHelpers.filesystem_access(dir) do FileUtils.mkdir_p(dir) end end end def names lines(names_path) end def names_path directory.join("names") end def versions versions_by_name = Hash.new {|hash, key| hash[key] = [] } info_checksums_by_name = {} lines(versions_path).each do |line| name, versions_string, info_checksum = line.split(" ", 3) info_checksums_by_name[name] = info_checksum || "" versions_string.split(",").each do |version| if version.start_with?("-") version = version[1..-1].split("-", 2).unshift(name) versions_by_name[name].delete(version) else version = version.split("-", 2).unshift(name) versions_by_name[name] << version end end end [versions_by_name, info_checksums_by_name] end def versions_path directory.join("versions") end def checksums checksums = {} lines(versions_path).each do |line| name, _, checksum = line.split(" ", 3) checksums[name] = checksum end checksums end def dependencies(name) lines(info_path(name)).map do |line| parse_gem(line) end end def info_path(name) name = name.to_s if name =~ /[^a-z0-9_-]/ name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}" info_roots.last.join(name) else info_roots.first.join(name) end end def specific_dependency(name, version, platform) pattern = [version, platform].compact.join("-") return nil if pattern.empty? gem_lines = info_path(name).read gem_line = gem_lines[/^#{Regexp.escape(pattern)}\b.*/, 0] gem_line ? parse_gem(gem_line) : nil end private def lines(path) return [] unless path.file? lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n") header = lines.index("---") header ? lines[header + 1..-1] : lines end def parse_gem(line) @dependency_parser ||= GemParser.new @dependency_parser.parse(line) end def info_roots [ directory.join("info"), directory.join("info-special-characters"), ] end end end end PK ]CXjBgems/bundler-2.2.24/lib/bundler/compact_index_client/gem_parser.rbnu[# frozen_string_literal: true module Bundler class CompactIndexClient if defined?(Gem::Resolver::APISet::GemParser) GemParser = Gem::Resolver::APISet::GemParser else class GemParser def parse(line) version_and_platform, rest = line.split(" ", 2) version, platform = version_and_platform.split("-", 2) dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : [] requirements = requirements ? requirements.map {|d| parse_dependency(d) } : [] [version, platform, dependencies, requirements] end private def parse_dependency(string) dependency = string.split(":") dependency[-1] = dependency[-1].split("&") if dependency.size > 1 dependency end end end end end PK ]q cc?gems/bundler-2.2.24/lib/bundler/compact_index_client/updater.rbnu[# frozen_string_literal: true require_relative "../vendored_fileutils" module Bundler class CompactIndexClient class Updater class MisMatchedChecksumError < Error def initialize(path, server_checksum, local_checksum) @path = path @server_checksum = server_checksum @local_checksum = local_checksum end def message "The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \ "(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})." end end def initialize(fetcher) @fetcher = fetcher require_relative "../vendored_tmpdir" end def update(local_path, remote_path, retrying = nil) headers = {} Bundler::Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir| local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename) # first try to fetch any new bytes on the existing file if retrying.nil? && local_path.file? SharedHelpers.filesystem_access(local_temp_path) do FileUtils.cp local_path, local_temp_path end headers["If-None-Match"] = etag_for(local_temp_path) headers["Range"] = if local_temp_path.size.nonzero? # Subtract a byte to ensure the range won't be empty. # Avoids 416 (Range Not Satisfiable) responses. "bytes=#{local_temp_path.size - 1}-" else "bytes=#{local_temp_path.size}-" end end response = @fetcher.call(remote_path, headers) return nil if response.is_a?(Net::HTTPNotModified) content = response.body etag = (response["ETag"] || "").gsub(%r{\AW/}, "") correct_response = SharedHelpers.filesystem_access(local_temp_path) do if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero? local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) } etag_for(local_temp_path) == etag else local_temp_path.open("wb") {|f| f << content } etag.length.zero? || etag_for(local_temp_path) == etag end end if correct_response SharedHelpers.filesystem_access(local_path) do FileUtils.mv(local_temp_path, local_path) end return nil end if retrying raise MisMatchedChecksumError.new(remote_path, etag, etag_for(local_temp_path)) end update(local_path, remote_path, :retrying) end rescue Errno::EACCES raise Bundler::PermissionError, "Bundler does not have write access to create a temp directory " \ "within #{Dir.tmpdir}. Bundler must have write access to your " \ "systems temp directory to function properly. " rescue Zlib::GzipFile::Error raise Bundler::HTTPError end def etag_for(path) sum = checksum_for_file(path) sum ? %("#{sum}") : nil end def slice_body(body, range) body.byteslice(range) end def checksum_for_file(path) return nil unless path.file? # This must use File.read instead of Digest.file().hexdigest # because we need to preserve \n line endings on windows when calculating # the checksum SharedHelpers.filesystem_access(path, :read) do SharedHelpers.digest(:MD5).hexdigest(File.read(path)) end end end end end PK ]Hu""(gems/bundler-2.2.24/lib/bundler/setup.rbnu[# frozen_string_literal: true require_relative "shared_helpers" if Bundler::SharedHelpers.in_bundle? require_relative "../bundler" if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"] begin Bundler.ui.silence { Bundler.setup } rescue Bundler::BundlerError => e Bundler.ui.warn "\e[31m#{e.message}\e[0m" Bundler.ui.warn e.backtrace.join("\n") if ENV["DEBUG"] if e.is_a?(Bundler::GemNotFound) Bundler.ui.warn "\e[33mRun `bundle install` to install missing gems.\e[0m" end exit e.status_code end else Bundler.ui.silence { Bundler.setup } end # We might be in the middle of shelling out to rubygems # (RUBYOPT=-rbundler/setup), so we need to give rubygems the opportunity of # not being silent. Gem::DefaultUserInteraction.ui = nil end PK ]hFF/gems/bundler-2.2.24/lib/bundler/psyched_yaml.rbnu[# frozen_string_literal: true # Psych could be in the stdlib # but it's too late if Syck is already loaded begin require "psych" unless defined?(Syck) rescue LoadError # Apparently Psych wasn't available. Oh well. end # At least load the YAML stdlib, whatever that may be require "yaml" unless defined?(YAML.dump) module Bundler # On encountering invalid YAML, # Psych raises Psych::SyntaxError if defined?(::Psych::SyntaxError) YamlLibrarySyntaxError = ::Psych::SyntaxError else # Syck raises ArgumentError YamlLibrarySyntaxError = ::ArgumentError end end PK ]hc8gems/bundler-2.2.24/lib/bundler/environment_preserver.rbnu[# frozen_string_literal: true module Bundler class EnvironmentPreserver INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL".freeze BUNDLER_KEYS = %w[ BUNDLE_BIN_PATH BUNDLE_GEMFILE BUNDLER_VERSION GEM_HOME GEM_PATH MANPATH PATH RB_USER_INSTALL RUBYLIB RUBYOPT ].map(&:freeze).freeze BUNDLER_PREFIX = "BUNDLER_ORIG_".freeze def self.from_env new(env_to_hash(ENV), BUNDLER_KEYS) end def self.env_to_hash(env) to_hash = env.to_hash return to_hash unless Gem.win_platform? to_hash.each_with_object({}) {|(k,v), a| a[k.upcase] = v } end # @param env [Hash] # @param keys [Array] def initialize(env, keys) @original = env @keys = keys @prefix = BUNDLER_PREFIX end # Replaces `ENV` with the bundler environment variables backed up def replace_with_backup ENV.replace(backup) unless Gem.win_platform? # Fallback logic for Windows below to workaround # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all # supported rubies include the fix for that. ENV.clear backup.each {|k, v| ENV[k] = v } end # @return [Hash] def backup env = @original.clone @keys.each do |key| value = env[key] if !value.nil? && !value.empty? env[@prefix + key] ||= value elsif value.nil? env[@prefix + key] ||= INTENTIONALLY_NIL end end env end # @return [Hash] def restore env = @original.clone @keys.each do |key| value_original = env[@prefix + key] next if value_original.nil? || value_original.empty? if value_original == INTENTIONALLY_NIL env.delete(key) else env[key] = value_original end env.delete(@prefix + key) end env end end end PK ]I~] <gems/bundler-2.2.24/lib/bundler/templates/Executable.bundlernu[#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> # frozen_string_literal: true # # This file was generated by Bundler. # # The application '<%= executable %>' is installed as part of a gem, and # this file is here to facilitate running it. # require "rubygems" m = Module.new do module_function def invoked_as_script? File.expand_path($0) == File.expand_path(__FILE__) end def env_var_version ENV["BUNDLER_VERSION"] end def cli_arg_version return unless invoked_as_script? # don't want to hijack other binstubs return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` bundler_version = nil update_index = nil ARGV.each_with_index do |a, i| if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN bundler_version = a end next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ bundler_version = $1 update_index = i end bundler_version end def gemfile gemfile = ENV["BUNDLE_GEMFILE"] return gemfile if gemfile && !gemfile.empty? File.expand_path("../<%= relative_gemfile_path %>", __FILE__) end def lockfile lockfile = case File.basename(gemfile) when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) else "#{gemfile}.lock" end File.expand_path(lockfile) end def lockfile_version return unless File.file?(lockfile) lockfile_contents = File.read(lockfile) return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ Regexp.last_match(1) end def bundler_version @bundler_version ||= env_var_version || cli_arg_version || lockfile_version end def bundler_requirement return "#{Gem::Requirement.default}.a" unless bundler_version bundler_gem_version = Gem::Version.new(bundler_version) requirement = bundler_gem_version.approximate_recommendation return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") requirement += ".a" if bundler_gem_version.prerelease? requirement end def load_bundler! ENV["BUNDLE_GEMFILE"] ||= gemfile activate_bundler end def activate_bundler gem_error = activation_error_handling do gem "bundler", bundler_requirement end return if gem_error.nil? require_error = activation_error_handling do require "bundler/version" end return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" exit 42 end def activation_error_handling yield nil rescue StandardError, LoadError => e e end end m.load_bundler! if m.invoked_as_script? load Gem.bin_path("<%= spec.name %>", "<%= executable %>") end PK ]MGgems/bundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/newgem.c.ttnu[#include "<%= config[:underscored_name] %>.h" VALUE rb_m<%= config[:constant_array].join %>; void Init_<%= config[:underscored_name] %>(void) { rb_m<%= config[:constant_array].join %> = rb_define_module(<%= config[:constant_name].inspect %>); } PK ]?Ggems/bundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/newgem.h.ttnu[#ifndef <%= config[:underscored_name].upcase %>_H #define <%= config[:underscored_name].upcase %>_H 1 #include "ruby.h" #endif /* <%= config[:underscored_name].upcase %>_H */ PK ]95ffIgems/bundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/extconf.rb.ttnu[# frozen_string_literal: true require "mkmf" create_makefile(<%= config[:makefile_path].inspect %>) PK ]7##Bgems/bundler-2.2.24/lib/bundler/templates/newgem/newgem.gemspec.ttnu[# frozen_string_literal: true require_relative "lib/<%=config[:namespaced_path]%>/version" Gem::Specification.new do |spec| spec.name = <%= config[:name].inspect %> spec.version = <%= config[:constant_name] %>::VERSION spec.authors = [<%= config[:author].inspect %>] spec.email = [<%= config[:email].inspect %>] spec.summary = "TODO: Write a short summary, because RubyGems requires one." spec.description = "TODO: Write a longer description or delete this line." spec.homepage = "TODO: Put your gem's website or public repo URL here." <%- if config[:mit] -%> spec.license = "MIT" <%- end -%> spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>" spec.metadata["allowed_push_host"] = "TODO: Set to 'https://mygemserver.com'" spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the RubyGem that have been added into git. spec.files = Dir.chdir(File.expand_path(__dir__)) do `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) } end spec.bindir = "exe" spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] <%- if config[:ext] -%> spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"] <%- end -%> # Uncomment to register a new dependency of your gem # spec.add_dependency "example-gem", "~> 1.0" # For more information and examples about making a new gem, checkout our # guide at: https://bundler.io/guides/creating_gem.html end PK ]!5c| | =gems/bundler-2.2.24/lib/bundler/templates/newgem/README.md.ttnu[# <%= config[:constant_name] %> Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/<%= config[:namespaced_path] %>`. To experiment with that code, run `bin/console` for an interactive prompt. TODO: Delete this and the text above, and describe your gem ## Installation Add this line to your application's Gemfile: ```ruby gem '<%= config[:name] %>' ``` And then execute: $ bundle install Or install it yourself as: $ gem install <%= config[:name] %> ## Usage TODO: Write usage instructions here ## Development After checking out the repo, run `bin/setup` to install dependencies.<% if config[:test] %> Then, run `rake <%= config[:test].sub('mini', '').sub('rspec', 'spec') %>` to run the tests.<% end %> You can also run `bin/console` for an interactive prompt that will allow you to experiment.<% if config[:bin] %> Run `bundle exec <%= config[:name] %>` to use the gem in this directory, ignoring other installed copies of this gem.<% end %> To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). <% if config[:git] -%> ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md).<% end %> <% end -%> <% if config[:mit] -%> ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). <% end -%> <% if config[:git] && config[:coc] -%> ## Code of Conduct Everyone interacting in the <%= config[:constant_name] %> project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md). <% end -%> PK ]+<gems/bundler-2.2.24/lib/bundler/templates/newgem/Rakefile.ttnu[# frozen_string_literal: true require "bundler/gem_tasks" <% default_task_names = [config[:test_task]].compact -%> <% case config[:test] -%> <% when "minitest", "test-unit" -%> require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList["test/**/*_test.rb"] end <% when "rspec" -%> require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) <% end -%> <% if config[:rubocop] -%> <% default_task_names << :rubocop -%> require "rubocop/rake_task" RuboCop::RakeTask.new <% end -%> <% if config[:ext] -%> <% default_task_names.unshift(:clobber, :compile) -%> require "rake/extensiontask" task build: :compile Rake::ExtensionTask.new("<%= config[:underscored_name] %>") do |ext| ext.lib_dir = "lib/<%= config[:namespaced_path] %>" end <% end -%> <% if default_task_names.size == 1 -%> task default: <%= default_task_names.first.inspect %> <% else -%> task default: %i[<%= default_task_names.join(" ") %>] <% end -%> PK ]~~>gems/bundler-2.2.24/lib/bundler/templates/newgem/travis.yml.ttnu[--- language: ruby cache: bundler rvm: - <%= RUBY_VERSION %> before_install: gem install bundler -v <%= Bundler::VERSION %> PK ]Ҧ+Ggems/bundler-2.2.24/lib/bundler/templates/newgem/spec/spec_helper.rb.ttnu[# frozen_string_literal: true require "<%= config[:namespaced_path] %>" RSpec.configure do |config| # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = ".rspec_status" # Disable RSpec exposing methods globally on `Module` and `main` config.disable_monkey_patching! config.expect_with :rspec do |c| c.syntax = :expect end end PK ]32 Ggems/bundler-2.2.24/lib/bundler/templates/newgem/spec/newgem_spec.rb.ttnu[# frozen_string_literal: true RSpec.describe <%= config[:constant_name] %> do it "has a version number" do expect(<%= config[:constant_name] %>::VERSION).not_to be nil end it "does something useful" do expect(false).to eq(true) end end PK ]rə;gems/bundler-2.2.24/lib/bundler/templates/newgem/Gemfile.ttnu[# frozen_string_literal: true source "https://rubygems.org" # Specify your gem's dependencies in <%= config[:name] %>.gemspec gemspec gem "rake", "~> 13.0" <%- if config[:ext] -%> gem "rake-compiler" <%- end -%> <%- if config[:test] -%> gem "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>" <%- end -%> <%- if config[:rubocop] -%> gem "rubocop", "~> <%= config[:rubocop_version] %>" <%- end -%> PK ]z??>gems/bundler-2.2.24/lib/bundler/templates/newgem/exe/newgem.ttnu[#!/usr/bin/env ruby require "<%= config[:namespaced_path] %>" PK ]lq559gems/bundler-2.2.24/lib/bundler/templates/newgem/rspec.ttnu[--format documentation --color --require spec_helper PK ]G>JQgems/bundler-2.2.24/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.ttnu[# frozen_string_literal: true $LOAD_PATH.unshift File.expand_path("../lib", __dir__) require "<%= config[:namespaced_path] %>" require "test-unit" PK ]q{33Qgems/bundler-2.2.24/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.ttnu[# frozen_string_literal: true require "test_helper" class <%= config[:constant_name] %>Test < Test::Unit::TestCase test "VERSION" do assert do ::<%= config[:constant_name] %>.const_defined?(:VERSION) end end test "something useful" do assert_equal("expected", "actual") end end PK ]M-nPgems/bundler-2.2.24/lib/bundler/templates/newgem/test/minitest/test_helper.rb.ttnu[# frozen_string_literal: true $LOAD_PATH.unshift File.expand_path("../lib", __dir__) require "<%= config[:namespaced_path] %>" require "minitest/autorun" PK ]-Pgems/bundler-2.2.24/lib/bundler/templates/newgem/test/minitest/newgem_test.rb.ttnu[# frozen_string_literal: true require "test_helper" class <%= config[:constant_name] %>Test < Minitest::Test def test_that_it_has_a_version_number refute_nil ::<%= config[:constant_name] %>::VERSION end def test_it_does_something_useful assert false end end PK ]/++?gems/bundler-2.2.24/lib/bundler/templates/newgem/rubocop.yml.ttnu[AllCops: TargetRubyVersion: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %> Style/StringLiterals: Enabled: true EnforcedStyle: double_quotes Style/StringLiteralsInInterpolation: Enabled: true EnforcedStyle: double_quotes Layout/LineLength: Max: 120 PK ]v@@Mgems/bundler-2.2.24/lib/bundler/templates/newgem/github/workflows/main.yml.ttnu[name: Ruby on: [push,pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: <%= RUBY_VERSION %> bundler-cache: true - name: Run the default task run: bundle exec rake PK ]g2=gems/bundler-2.2.24/lib/bundler/templates/newgem/gitignore.ttnu[/.bundle/ /.yardoc /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ <%- if config[:ext] -%> *.bundle *.so *.o *.a mkmf.log <%- end -%> <%- if config[:test] == "rspec" -%> # rspec failure tracking .rspec_status <%- end -%> PK ]44.Agems/bundler-2.2.24/lib/bundler/templates/newgem/gitlab-ci.yml.ttnu[image: ruby:<%= RUBY_VERSION %> before_script: - gem install bundler -v <%= Bundler::VERSION %> - bundle install example_job: script: - bundle exec rake PK ]!5PP@gems/bundler-2.2.24/lib/bundler/templates/newgem/CHANGELOG.md.ttnu[## [Unreleased] ## [0.1.0] - <%= Time.now.strftime('%F') %> - Initial release PK ]QQ?gems/bundler-2.2.24/lib/bundler/templates/newgem/LICENSE.txt.ttnu[The MIT License (MIT) Copyright (c) <%= Time.now.year %> <%= config[:author] %> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK ]_ccFgems/bundler-2.2.24/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.ttnu[# Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at <%= config[:email] %>. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. PK ]eە?gems/bundler-2.2.24/lib/bundler/templates/newgem/bin/console.ttnu[#!/usr/bin/env ruby # frozen_string_literal: true require "bundler/setup" require "<%= config[:namespaced_path] %>" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start(__FILE__) PK ]=gems/bundler-2.2.24/lib/bundler/templates/newgem/bin/setup.ttnu[#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install # Do any other automated setup that you need to do here PK ]^6)g&&Ggems/bundler-2.2.24/lib/bundler/templates/newgem/circleci/config.yml.ttnu[version: 2.1 jobs: build: docker: - image: ruby:<%= RUBY_VERSION %> steps: - checkout - run: name: Run the default task command: | gem install bundler -v <%= Bundler::VERSION %> bundle install bundle exec rake PK ]Igems/bundler-2.2.24/lib/bundler/templates/newgem/lib/newgem/version.rb.ttnu[# frozen_string_literal: true <%- config[:constant_array].each_with_index do |c, i| -%> <%= " " * i %>module <%= c %> <%- end -%> <%= " " * config[:constant_array].size %>VERSION = "0.1.0" <%- (config[:constant_array].size-1).downto(0) do |i| -%> <%= " " * i %>end <%- end -%> PK ]Br==Agems/bundler-2.2.24/lib/bundler/templates/newgem/lib/newgem.rb.ttnu[# frozen_string_literal: true require_relative "<%= File.basename(config[:namespaced_path]) %>/version" <%- if config[:ext] -%> require_relative "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>" <%- end -%> <%- config[:constant_array].each_with_index do |c, i| -%> <%= " " * i %>module <%= c %> <%- end -%> <%= " " * config[:constant_array].size %>class Error < StandardError; end <%= " " * config[:constant_array].size %># Your code goes here... <%- (config[:constant_array].size-1).downto(0) do |i| -%> <%= " " * i %>end <%- end -%> PK ]”}Ñ4gems/bundler-2.2.24/lib/bundler/templates/Executablenu[#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> # frozen_string_literal: true # # This file was generated by Bundler. # # The application '<%= executable %>' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../<%= relative_gemfile_path %>", Pathname.new(__FILE__).realpath) bundle_binstub = File.expand_path("../bundle", __FILE__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") end end require "rubygems" require "bundler/setup" load Gem.bin_path("<%= spec.name %>", "<%= executable %>") PK ]t1gems/bundler-2.2.24/lib/bundler/templates/Gemfilenu[# frozen_string_literal: true source "https://rubygems.org" git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } # gem "rails" PK ]{?gems/bundler-2.2.24/lib/bundler/templates/Executable.standalonenu[#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> # # This file was generated by Bundler. # # The application '<%= executable %>' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" path = Pathname.new(__FILE__) $:.unshift File.expand_path "../<%= standalone_path %>", path.realpath require "bundler/setup" load File.expand_path "../<%= executable_path %>", path.realpath PK ]Ba71gems/bundler-2.2.24/lib/bundler/templates/gems.rbnu[# frozen_string_literal: true # A sample gems.rb source "https://rubygems.org" git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } # gem "rails" PK ]9rQ' ' )gems/bundler-2.2.24/lib/bundler/inline.rbnu[# frozen_string_literal: true # Allows for declaring a Gemfile inline in a ruby script, optionally installing # any gems that aren't already installed on the user's system. # # @note Every gem that is specified in this 'Gemfile' will be `require`d, as if # the user had manually called `Bundler.require`. To avoid a requested gem # being automatically required, add the `:require => false` option to the # `gem` dependency declaration. # # @param install [Boolean] whether gems that aren't already installed on the # user's system should be installed. # Defaults to `false`. # # @param gemfile [Proc] a block that is evaluated as a `Gemfile`. # # @example Using an inline Gemfile # # #!/usr/bin/env ruby # # require 'bundler/inline' # # gemfile do # source 'https://rubygems.org' # gem 'json', require: false # gem 'nap', require: 'rest' # gem 'cocoapods', '~> 0.34.1' # end # # puts Pod::VERSION # => "0.34.4" # def gemfile(install = false, options = {}, &gemfile) require_relative "../bundler" opts = options.dup ui = opts.delete(:ui) { Bundler::UI::Shell.new } ui.level = "silent" if opts.delete(:quiet) raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty? begin old_root = Bundler.method(:root) bundler_module = class << Bundler; self; end bundler_module.send(:remove_method, :root) def Bundler.root Bundler::SharedHelpers.pwd.expand_path end old_gemfile = ENV["BUNDLE_GEMFILE"] Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile" Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? builder = Bundler::Dsl.new builder.instance_eval(&gemfile) builder.check_primary_source_safety Bundler.settings.temporary(:deployment => false, :frozen => false) do definition = builder.to_definition(nil, true) def definition.lock(*); end definition.validate_runtime! Bundler.ui = install ? ui : Bundler::UI::Silent.new if install || definition.missing_specs? Bundler.settings.temporary(:inline => true) do installer = Bundler::Installer.install(Bundler.root, definition, :system => true) installer.post_install_messages.each do |name, message| Bundler.ui.info "Post-install message from #{name}:\n#{message}" end end end runtime = Bundler::Runtime.new(nil, definition) runtime.setup.require end ensure if bundler_module bundler_module.send(:remove_method, :root) bundler_module.send(:define_method, :root, old_root) end if old_gemfile ENV["BUNDLE_GEMFILE"] = old_gemfile else ENV["BUNDLE_GEMFILE"] = "" end end end PK ]4%%+gems/bundler-2.2.24/lib/bundler/injector.rbnu[# frozen_string_literal: true module Bundler class Injector INJECTED_GEMS = "injected gems".freeze def self.inject(new_deps, options = {}) injector = new(new_deps, options) injector.inject(Bundler.default_gemfile, Bundler.default_lockfile) end def self.remove(gems, options = {}) injector = new(gems, options) injector.remove(Bundler.default_gemfile, Bundler.default_lockfile) end def initialize(deps, options = {}) @deps = deps @options = options end # @param [Pathname] gemfile_path The Gemfile in which to inject the new dependency. # @param [Pathname] lockfile_path The lockfile in which to inject the new dependency. # @return [Array] def inject(gemfile_path, lockfile_path) if Bundler.frozen_bundle? # ensure the lock and Gemfile are synced Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true) end # temporarily unfreeze Bundler.settings.temporary(:deployment => false, :frozen => false) do # evaluate the Gemfile we have now builder = Dsl.new builder.eval_gemfile(gemfile_path) # don't inject any gems that are already in the Gemfile @deps -= builder.dependencies # add new deps to the end of the in-memory Gemfile # Set conservative versioning to false because # we want to let the resolver resolve the version first builder.eval_gemfile(INJECTED_GEMS, build_gem_lines(false)) if @deps.any? # resolve to see if the new deps broke anything @definition = builder.to_definition(lockfile_path, {}) @definition.resolve_remotely! # since nothing broke, we can add those gems to the gemfile append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any? # since we resolved successfully, write out the lockfile @definition.lock(Bundler.default_lockfile) # invalidate the cached Bundler.definition Bundler.reset_paths! # return an array of the deps that we added @deps end end # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. # @param [Pathname] lockfile_path The lockfile from which to remove dependencies. # @return [Array] def remove(gemfile_path, lockfile_path) # remove gems from each gemfiles we have Bundler.definition.gemfiles.each do |path| deps = remove_deps(path) show_warning("No gems were removed from the gemfile.") if deps.empty? deps.each {|dep| Bundler.ui.confirm "#{SharedHelpers.pretty_dependency(dep, false)} was removed." } end end private def conservative_version(spec) version = spec.version return ">= 0" if version.nil? segments = version.segments seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2 prerelease_suffix = version.to_s.gsub(version.release.to_s, "") if version.prerelease? "#{version_prefix}#{segments[0..seg_end_index].join(".")}#{prerelease_suffix}" end def version_prefix if @options[:strict] "= " elsif @options[:optimistic] ">= " else "~> " end end def build_gem_lines(conservative_versioning) @deps.map do |d| name = d.name.dump requirement = if conservative_versioning ", \"#{conservative_version(@definition.specs[d.name][0])}\"" else ", #{d.requirement.as_list.map(&:dump).join(", ")}" end if d.groups != Array(:default) group = d.groups.size == 1 ? ", :group => #{d.groups.first.inspect}" : ", :groups => #{d.groups.inspect}" end source = ", :source => \"#{d.source}\"" unless d.source.nil? git = ", :git => \"#{d.git}\"" unless d.git.nil? branch = ", :branch => \"#{d.branch}\"" unless d.branch.nil? %(gem #{name}#{requirement}#{group}#{source}#{git}#{branch}) end.join("\n") end def append_to(gemfile_path, new_gem_lines) gemfile_path.open("a") do |f| f.puts f.puts new_gem_lines end end # evaluates a gemfile to remove the specified gem # from it. def remove_deps(gemfile_path) initial_gemfile = File.readlines(gemfile_path) Bundler.ui.info "Removing gems from #{gemfile_path}" # evaluate the Gemfile we have builder = Dsl.new builder.eval_gemfile(gemfile_path) removed_deps = remove_gems_from_dependencies(builder, @deps, gemfile_path) # abort the operation if no gems were removed # no need to operate on gemfile further return [] if removed_deps.empty? cleaned_gemfile = remove_gems_from_gemfile(@deps, gemfile_path) SharedHelpers.write_to_gemfile(gemfile_path, cleaned_gemfile) # check for errors # including extra gems being removed # or some gems not being removed # and return the actual removed deps cross_check_for_errors(gemfile_path, builder.dependencies, removed_deps, initial_gemfile) end # @param [Dsl] builder Dsl object of current Gemfile. # @param [Array] gems Array of names of gems to be removed. # @param [Pathname] gemfile_path Path of the Gemfile. # @return [Array] Array of removed dependencies. def remove_gems_from_dependencies(builder, gems, gemfile_path) removed_deps = [] gems.each do |gem_name| deleted_dep = builder.dependencies.find {|d| d.name == gem_name } if deleted_dep.nil? raise GemfileError, "`#{gem_name}` is not specified in #{gemfile_path} so it could not be removed." end builder.dependencies.delete(deleted_dep) removed_deps << deleted_dep end removed_deps end # @param [Array] gems Array of names of gems to be removed. # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. def remove_gems_from_gemfile(gems, gemfile_path) patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2\)/ new_gemfile = [] multiline_removal = false File.readlines(gemfile_path).each do |line| match_data = line.match(patterns) if match_data && is_not_within_comment?(line, match_data) multiline_removal = line.rstrip.end_with?(",") # skip lines which match the regex next end # skip followup lines until line does not end with ',' new_gemfile << line unless multiline_removal multiline_removal = line.rstrip.end_with?(",") if multiline_removal end # remove line \n and append them with other strings new_gemfile.each_with_index do |_line, index| if new_gemfile[index + 1] == "\n" new_gemfile[index] += new_gemfile[index + 1] new_gemfile.delete_at(index + 1) end end %w[group source env install_if].each {|block| remove_nested_blocks(new_gemfile, block) } new_gemfile.join.chomp end # @param [String] line Individual line of gemfile content. # @param [MatchData] match_data Data about Regex match. def is_not_within_comment?(line, match_data) match_start_index = match_data.offset(0).first !line[0..match_start_index].include?("#") end # @param [Array] gemfile Array of gemfile contents. # @param [String] block_name Name of block name to look for. def remove_nested_blocks(gemfile, block_name) nested_blocks = 0 # count number of nested blocks gemfile.each_with_index {|line, index| nested_blocks += 1 if !gemfile[index + 1].nil? && gemfile[index + 1].include?(block_name) && line.include?(block_name) } while nested_blocks >= 0 nested_blocks -= 1 gemfile.each_with_index do |line, index| next unless !line.nil? && line.strip.start_with?(block_name) if gemfile[index + 1] =~ /^\s*end\s*$/ gemfile[index] = nil gemfile[index + 1] = nil end end gemfile.compact! end end # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. # @param [Array] original_deps Array of original dependencies. # @param [Array] removed_deps Array of removed dependencies. # @param [Array] initial_gemfile Contents of original Gemfile before any operation. def cross_check_for_errors(gemfile_path, original_deps, removed_deps, initial_gemfile) # evaluate the new gemfile to look for any failure cases builder = Dsl.new builder.eval_gemfile(gemfile_path) # record gems which were removed but not requested extra_removed_gems = original_deps - builder.dependencies # if some extra gems were removed then raise error # and revert Gemfile to original unless extra_removed_gems.empty? SharedHelpers.write_to_gemfile(gemfile_path, initial_gemfile.join) raise InvalidOption, "Gems could not be removed. #{extra_removed_gems.join(", ")} would also have been removed. Bundler cannot continue." end # record gems which could not be removed due to some reasons errored_deps = builder.dependencies.select {|d| d.gemfile == gemfile_path } & removed_deps.select {|d| d.gemfile == gemfile_path } show_warning "#{errored_deps.map(&:name).join(", ")} could not be removed." unless errored_deps.empty? # return actual removed dependencies removed_deps - errored_deps end def show_warning(message) Bundler.ui.info Bundler.ui.add_color(message, :yellow) end end end PK ] G,gems/bundler-2.2.24/lib/bundler/dep_proxy.rbnu[# frozen_string_literal: true module Bundler class DepProxy attr_reader :__platform, :dep @proxies = {} def self.get_proxy(dep, platform) @proxies[[dep, platform]] ||= new(dep, platform).freeze end def initialize(dep, platform) @dep = dep @__platform = platform end private_class_method :new alias_method :eql?, :== def type @dep.type end def name @dep.name end def requirement @dep.requirement end def to_s s = name.dup s << " (#{requirement})" unless requirement == Gem::Requirement.default s << " #{__platform}" unless __platform == Gem::Platform::RUBY s end def dup raise NoMethodError.new("DepProxy cannot be duplicated") end def clone raise NoMethodError.new("DepProxy cannot be cloned") end private def method_missing(*args, &blk) @dep.send(*args, &blk) end end end PK ]\'gems/bundler-2.2.24/lib/bundler/vlad.rbnu[# frozen_string_literal: true require_relative "shared_helpers" Bundler::SharedHelpers.major_deprecation 2, "The Bundler task for Vlad" # Vlad task for Bundler. # # Add "require 'bundler/vlad'" in your Vlad deploy.rb, and # include the vlad:bundle:install task in your vlad:deploy task. require_relative "deployment" include Rake::DSL if defined? Rake::DSL namespace :vlad do Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, :roles => :app) end PK ]oJ)gems/bundler-2.2.24/lib/bundler/errors.rbnu[# frozen_string_literal: true module Bundler class BundlerError < StandardError def self.status_code(code) define_method(:status_code) { code } if match = BundlerError.all_errors.find {|_k, v| v == code } error, _ = match raise ArgumentError, "Trying to register #{self} for status code #{code} but #{error} is already registered" end BundlerError.all_errors[self] = code end def self.all_errors @all_errors ||= {} end end class GemfileError < BundlerError; status_code(4); end class InstallError < BundlerError; status_code(5); end # Internal error, should be rescued class VersionConflict < BundlerError attr_reader :conflicts def initialize(conflicts, msg = nil) super(msg) @conflicts = conflicts end status_code(6) end class GemNotFound < BundlerError; status_code(7); end class InstallHookError < BundlerError; status_code(8); end class GemfileNotFound < BundlerError; status_code(10); end class GitError < BundlerError; status_code(11); end class DeprecatedError < BundlerError; status_code(12); end class PathError < BundlerError; status_code(13); end class GemspecError < BundlerError; status_code(14); end class InvalidOption < BundlerError; status_code(15); end class ProductionError < BundlerError; status_code(16); end class HTTPError < BundlerError status_code(17) def filter_uri(uri) URICredentialsFilter.credential_filtered_uri(uri) end end class RubyVersionMismatch < BundlerError; status_code(18); end class SecurityError < BundlerError; status_code(19); end class LockfileError < BundlerError; status_code(20); end class CyclicDependencyError < BundlerError; status_code(21); end class GemfileLockNotFound < BundlerError; status_code(22); end class PluginError < BundlerError; status_code(29); end class SudoNotPermittedError < BundlerError; status_code(30); end class ThreadCreationError < BundlerError; status_code(33); end class APIResponseMismatchError < BundlerError; status_code(34); end class APIResponseInvalidDependenciesError < BundlerError; status_code(35); end class GemfileEvalError < GemfileError; end class MarshalError < StandardError; end class PermissionError < BundlerError def initialize(path, permission_type = :write) @path = path @permission_type = permission_type end def action case @permission_type when :read then "read from" when :write then "write to" when :executable, :exec then "execute" else @permission_type.to_s end end def message "There was an error while trying to #{action} `#{@path}`. " \ "It is likely that you need to grant #{@permission_type} permissions " \ "for that path." end status_code(23) end class GemRequireError < BundlerError attr_reader :orig_exception def initialize(orig_exception, msg) full_message = msg + "\nGem Load Error is: #{orig_exception.message}\n"\ "Backtrace for gem load error is:\n"\ "#{orig_exception.backtrace.join("\n")}\n"\ "Bundler Error Backtrace:\n" super(full_message) @orig_exception = orig_exception end status_code(24) end class YamlSyntaxError < BundlerError attr_reader :orig_exception def initialize(orig_exception, msg) super(msg) @orig_exception = orig_exception end status_code(25) end class TemporaryResourceError < PermissionError def message "There was an error while trying to #{action} `#{@path}`. " \ "Some resource was temporarily unavailable. It's suggested that you try" \ "the operation again." end status_code(26) end class VirtualProtocolError < BundlerError def message "There was an error relating to virtualization and file access." \ "It is likely that you need to grant access to or mount some file system correctly." end status_code(27) end class OperationNotSupportedError < PermissionError def message "Attempting to #{action} `#{@path}` is unsupported by your OS." end status_code(28) end class NoSpaceOnDeviceError < PermissionError def message "There was an error while trying to #{action} `#{@path}`. " \ "There was insufficient space remaining on the device." end status_code(31) end class GenericSystemCallError < BundlerError attr_reader :underlying_error def initialize(underlying_error, message) @underlying_error = underlying_error super("#{message}\nThe underlying system error is #{@underlying_error.class}: #{@underlying_error}") end status_code(32) end end PK ]Ǵ0gems/bundler-2.2.24/lib/bundler/vendored_thor.rbnu[# frozen_string_literal: true module Bundler def self.require_thor_actions require_relative "vendor/thor/lib/thor/actions" end end require_relative "vendor/thor/lib/thor" PK ]p2Ǥ,gems/bundler-2.2.24/lib/bundler/constants.rbnu[# frozen_string_literal: true module Bundler WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/ FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/ NULL = WINDOWS ? "NUL" : "/dev/null" end PK ]88.gems/bundler-2.2.24/lib/bundler/cli/console.rbnu[# frozen_string_literal: true module Bundler class CLI::Console attr_reader :options, :group def initialize(options, group) @options = options @group = group end def run Bundler::SharedHelpers.major_deprecation 2, "bundle console will be replaced " \ "by `bin/console` generated by `bundle gem `" group ? Bundler.require(:default, *group.split(" ").map!(&:to_sym)) : Bundler.require ARGV.clear console = get_console(Bundler.settings[:console] || "irb") console.start end def get_console(name) require name get_constant(name) rescue LoadError Bundler.ui.error "Couldn't load console #{name}, falling back to irb" require "irb" get_constant("irb") end def get_constant(name) const_name = { "pry" => :Pry, "ripl" => :Ripl, "irb" => :IRB, }[name] Object.const_get(const_name) rescue NameError Bundler.ui.error "Could not find constant #{const_name}" exit 1 end end end PK ],gems/bundler-2.2.24/lib/bundler/cli/check.rbnu[# frozen_string_literal: true module Bundler class CLI::Check attr_reader :options def initialize(options) @options = options end def run Bundler.settings.set_command_option_if_given :path, options[:path] definition = Bundler.definition definition.validate_runtime! begin definition.resolve_only_locally! not_installed = definition.missing_specs rescue GemNotFound, VersionConflict Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies." Bundler.ui.warn "Install missing gems with `bundle install`." exit 1 end if not_installed.any? Bundler.ui.error "The following gems are missing" not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" } Bundler.ui.warn "Install missing gems with `bundle install`" exit 1 elsif !Bundler.default_lockfile.file? && Bundler.frozen_bundle? Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present" exit 1 else Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"] Bundler.ui.info "The Gemfile's dependencies are satisfied" end end end end PK ]j+gems/bundler-2.2.24/lib/bundler/cli/show.rbnu[# frozen_string_literal: true module Bundler class CLI::Show attr_reader :options, :gem_name, :latest_specs def initialize(options, gem_name) @options = options @gem_name = gem_name @verbose = options[:verbose] || options[:outdated] @latest_specs = fetch_latest_specs if @verbose end def run Bundler.ui.silence do Bundler.definition.validate_runtime! Bundler.load.lock end if gem_name if gem_name == "bundler" path = File.expand_path("../../../..", __FILE__) else spec = Bundler::CLI::Common.select_spec(gem_name, :regex_match) return unless spec path = spec.full_gem_path unless File.directory?(path) return Bundler.ui.warn "The gem #{gem_name} has been deleted. It was installed at: #{path}" end end return Bundler.ui.info(path) end if options[:paths] Bundler.load.specs.sort_by(&:name).map do |s| Bundler.ui.info s.full_gem_path end else Bundler.ui.info "Gems included by the bundle:" Bundler.load.specs.sort_by(&:name).each do |s| desc = " * #{s.name} (#{s.version}#{s.git_version})" if @verbose latest = latest_specs.find {|l| l.name == s.name } Bundler.ui.info <<-END.gsub(/^ +/, "") #{desc} \tSummary: #{s.summary || "No description available."} \tHomepage: #{s.homepage || "No website available."} \tStatus: #{outdated?(s, latest) ? "Outdated - #{s.version} < #{latest.version}" : "Up to date"} END else Bundler.ui.info desc end end end end private def fetch_latest_specs definition = Bundler.definition(true) if options[:outdated] Bundler.ui.info "Fetching remote specs for outdated check...\n\n" Bundler.ui.silence { definition.resolve_remotely! } else definition.resolve_with_cache! end Bundler.reset! definition.specs end def outdated?(current, latest) return false unless latest Gem::Version.new(current.version) < Gem::Version.new(latest.version) end end end PK ]`K+gems/bundler-2.2.24/lib/bundler/cli/lock.rbnu[# frozen_string_literal: true module Bundler class CLI::Lock attr_reader :options def initialize(options) @options = options end def run unless Bundler.default_gemfile Bundler.ui.error "Unable to find a Gemfile to lock" exit 1 end print = options[:print] ui = Bundler.ui Bundler.ui = UI::Silent.new if print Bundler::Fetcher.disable_endpoint = options["full-index"] update = options[:update] conservative = options[:conservative] if update.is_a?(Array) # unlocking specific gems Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update) update = { :gems => update, :conservative => conservative } elsif update update = { :conservative => conservative } if conservative end definition = Bundler.definition(update) Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update] options["remove-platform"].each do |platform| definition.remove_platform(platform) end options["add-platform"].each do |platform_string| platform = Gem::Platform.new(platform_string) if platform.to_s == "unknown" Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \ "and adding it will likely lead to resolution errors" end definition.add_platform(platform) end if definition.platforms.empty? raise InvalidOption, "Removing all platforms from the bundle is not allowed" end definition.resolve_remotely! unless options[:local] if print puts definition.to_lock else file = options[:lockfile] file = file ? File.expand_path(file) : Bundler.default_lockfile puts "Writing lockfile to #{file}" definition.lock(file) end Bundler.ui = ui end end end PK ])``,gems/bundler-2.2.24/lib/bundler/cli/clean.rbnu[# frozen_string_literal: true module Bundler class CLI::Clean attr_reader :options def initialize(options) @options = options end def run require_path_or_force unless options[:"dry-run"] Bundler.load.clean(options[:"dry-run"]) end protected def require_path_or_force return unless Bundler.use_system_gems? && !options[:force] raise InvalidOption, "Cleaning all the gems on your system is dangerous! " \ "If you're sure you want to remove every system gem not in this " \ "bundle, run `bundle clean --force`." end end end PK ]m/Ċ+gems/bundler-2.2.24/lib/bundler/cli/init.rbnu[# frozen_string_literal: true module Bundler class CLI::Init attr_reader :options def initialize(options) @options = options end def run if File.exist?(gemfile) Bundler.ui.error "#{gemfile} already exists at #{File.expand_path(gemfile)}" exit 1 end unless File.writable?(Dir.pwd) Bundler.ui.error "Can not create #{gemfile} as the current directory is not writable." exit 1 end if options[:gemspec] gemspec = File.expand_path(options[:gemspec]) unless File.exist?(gemspec) Bundler.ui.error "Gem specification #{gemspec} doesn't exist" exit 1 end spec = Bundler.load_gemspec_uncached(gemspec) File.open(gemfile, "wb") do |file| file << "# Generated from #{gemspec}\n" file << spec.to_gemfile end else FileUtils.cp(File.expand_path("../../templates/#{gemfile}", __FILE__), gemfile) end puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}" end private def gemfile @gemfile ||= Bundler.preferred_gemfile_name end end end PK ]Ak-gems/bundler-2.2.24/lib/bundler/cli/plugin.rbnu[# frozen_string_literal: true require_relative "../vendored_thor" module Bundler class CLI::Plugin < Thor desc "install PLUGINS", "Install the plugin from the source" long_desc <<-D Install plugins either from the rubygems source provided (with --source option) or from a git source provided with --git (for remote repos) or --local_git (for local repos). If no sources are provided, it uses Gem.sources D method_option "source", :type => :string, :default => nil, :banner => "URL of the RubyGems source to fetch the plugin from" method_option "version", :type => :string, :default => nil, :banner => "The version of the plugin to fetch" method_option "git", :type => :string, :default => nil, :banner => "URL of the git repo to fetch from" method_option "local_git", :type => :string, :default => nil, :banner => "Path of the local git repo to fetch from" method_option "branch", :type => :string, :default => nil, :banner => "The git branch to checkout" method_option "ref", :type => :string, :default => nil, :banner => "The git revision to check out" def install(*plugins) Bundler::Plugin.install(plugins, options) end desc "uninstall PLUGINS", "Uninstall the plugins" long_desc <<-D Uninstall given list of plugins. To uninstall all the plugins, use -all option. D method_option "all", :type => :boolean, :default => nil, :banner => "Uninstall all the installed plugins. If no plugin is installed, then it does nothing." def uninstall(*plugins) Bundler::Plugin.uninstall(plugins, options) end desc "list", "List the installed plugins and available commands" def list Bundler::Plugin.list end end end PK ]N  +gems/bundler-2.2.24/lib/bundler/cli/exec.rbnu[# frozen_string_literal: true require_relative "../current_ruby" module Bundler class CLI::Exec attr_reader :options, :args, :cmd TRAPPED_SIGNALS = %w[INT].freeze def initialize(options, args) @options = options @cmd = args.shift @args = args if !Bundler.current_ruby.jruby? @args << { :close_others => !options.keep_file_descriptors? } elsif options.keep_file_descriptors? Bundler.ui.warn "Ruby version #{RUBY_VERSION} defaults to keeping non-standard file descriptors on Kernel#exec." end end def run validate_cmd! SharedHelpers.set_bundle_environment if bin_path = Bundler.which(cmd) if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path) return kernel_load(bin_path, *args) end kernel_exec(bin_path, *args) else # exec using the given command kernel_exec(cmd, *args) end end private def validate_cmd! return unless cmd.nil? Bundler.ui.error "bundler: exec needs a command to run" exit 128 end def kernel_exec(*args) Kernel.exec(*args) rescue Errno::EACCES, Errno::ENOEXEC Bundler.ui.error "bundler: not executable: #{cmd}" exit 126 rescue Errno::ENOENT Bundler.ui.error "bundler: command not found: #{cmd}" Bundler.ui.warn "Install missing gem executables with `bundle install`" exit 127 end def kernel_load(file, *args) args.pop if args.last.is_a?(Hash) ARGV.replace(args) $0 = file Process.setproctitle(process_title(file, args)) if Process.respond_to?(:setproctitle) require_relative "../setup" TRAPPED_SIGNALS.each {|s| trap(s, "DEFAULT") } Kernel.load(file) rescue SystemExit, SignalException raise rescue Exception # rubocop:disable Lint/RescueException Bundler.ui.error "bundler: failed to load command: #{cmd} (#{file})" Bundler::FriendlyErrors.disable! raise end def process_title(file, args) "#{file} #{args.join(" ")}".strip end def ruby_shebang?(file) possibilities = [ "#!/usr/bin/env ruby\n", "#!/usr/bin/env jruby\n", "#!/usr/bin/env truffleruby\n", "#!#{Gem.ruby}\n", ] if File.zero?(file) Bundler.ui.warn "#{file} is empty" return false end first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) } possibilities.any? {|shebang| first_line.start_with?(shebang) } end end end PK ]|jj,gems/bundler-2.2.24/lib/bundler/cli/cache.rbnu[# frozen_string_literal: true module Bundler class CLI::Cache attr_reader :options def initialize(options) @options = options end def run Bundler.ui.level = "error" if options[:quiet] Bundler.settings.set_command_option_if_given :path, options[:path] Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"] setup_cache_all install # TODO: move cache contents here now that all bundles are locked custom_path = Bundler.settings[:path] if options[:path] Bundler.settings.temporary(:cache_all_platforms => options["all-platforms"]) do Bundler.load.cache(custom_path) end end private def install require_relative "install" options = self.options.dup options["local"] = false if Bundler.settings[:cache_all_platforms] options["no-cache"] = true Bundler::CLI::Install.new(options).run end def setup_cache_all all = options.fetch(:all, Bundler.feature_flag.cache_all? || nil) Bundler.settings.set_command_option_if_given :cache_all, all end end end PK ]%4/gems/bundler-2.2.24/lib/bundler/cli/platform.rbnu[# frozen_string_literal: true module Bundler class CLI::Platform attr_reader :options def initialize(options) @options = options end def run platforms, ruby_version = Bundler.ui.silence do locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string [Bundler.definition.platforms.map {|p| "* #{p}" }, locked_ruby_version || gemfile_ruby_version] end output = [] if options[:ruby] if ruby_version output << ruby_version else output << "No ruby version specified" end else output << "Your platform is: #{RUBY_PLATFORM}" output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}" if ruby_version output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}" begin Bundler.definition.validate_runtime! output << "Your current platform satisfies the Ruby version requirement." rescue RubyVersionMismatch => e output << e.message end else output << "Your Gemfile does not specify a Ruby version requirement." end end Bundler.ui.info output.join("\n\n") end end end PK ]22*gems/bundler-2.2.24/lib/bundler/cli/gem.rbnu[# frozen_string_literal: true require "pathname" module Bundler class CLI Bundler.require_thor_actions include Thor::Actions end class CLI::Gem TEST_FRAMEWORK_VERSIONS = { "rspec" => "3.0", "minitest" => "5.0", "test-unit" => "3.0", }.freeze attr_reader :options, :gem_name, :thor, :name, :target def initialize(options, gem_name, thor) @options = options @gem_name = resolve_name(gem_name) @thor = thor thor.behavior = :invoke thor.destination_root = nil @name = @gem_name @target = SharedHelpers.pwd.join(gem_name) validate_ext_name if options[:ext] end def run Bundler.ui.confirm "Creating gem '#{name}'..." underscored_name = name.tr("-", "_") namespaced_path = name.tr("-", "/") constant_name = name.gsub(/-[_-]*(?![_-]|$)/) { "::" }.gsub(/([_-]+|(::)|^)(.|$)/) { $2.to_s + $3.upcase } constant_array = constant_name.split("::") use_git = Bundler.git_present? && options[:git] git_author_name = use_git ? `git config user.name`.chomp : "" git_username = use_git ? `git config github.user`.chomp : "" git_user_email = use_git ? `git config user.email`.chomp : "" github_username = if options[:github_username].nil? git_username elsif options[:github_username] == false "" else options[:github_username] end config = { :name => name, :underscored_name => underscored_name, :namespaced_path => namespaced_path, :makefile_path => "#{underscored_name}/#{underscored_name}", :constant_name => constant_name, :constant_array => constant_array, :author => git_author_name.empty? ? "TODO: Write your name" : git_author_name, :email => git_user_email.empty? ? "TODO: Write your email address" : git_user_email, :test => options[:test], :ext => options[:ext], :exe => options[:exe], :bundler_version => bundler_dependency_version, :git => use_git, :github_username => github_username.empty? ? "[USERNAME]" : github_username, :required_ruby_version => Gem.ruby_version < Gem::Version.new("2.4.a") ? "2.3.0" : "2.4.0", } ensure_safe_gem_name(name, constant_array) templates = { "#{Bundler.preferred_gemfile_name}.tt" => Bundler.preferred_gemfile_name, "lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb", "lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb", "newgem.gemspec.tt" => "#{name}.gemspec", "Rakefile.tt" => "Rakefile", "README.md.tt" => "README.md", "bin/console.tt" => "bin/console", "bin/setup.tt" => "bin/setup", } executables = %w[ bin/console bin/setup ] templates.merge!("gitignore.tt" => ".gitignore") if use_git if test_framework = ask_and_set_test_framework config[:test] = test_framework config[:test_framework_version] = TEST_FRAMEWORK_VERSIONS[test_framework] case test_framework when "rspec" templates.merge!( "rspec.tt" => ".rspec", "spec/spec_helper.rb.tt" => "spec/spec_helper.rb", "spec/newgem_spec.rb.tt" => "spec/#{namespaced_path}_spec.rb" ) config[:test_task] = :spec when "minitest" templates.merge!( "test/minitest/test_helper.rb.tt" => "test/test_helper.rb", "test/minitest/newgem_test.rb.tt" => "test/#{namespaced_path}_test.rb" ) config[:test_task] = :test when "test-unit" templates.merge!( "test/test-unit/test_helper.rb.tt" => "test/test_helper.rb", "test/test-unit/newgem_test.rb.tt" => "test/#{namespaced_path}_test.rb" ) config[:test_task] = :test end end config[:ci] = ask_and_set_ci case config[:ci] when "github" templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml") when "travis" templates.merge!("travis.yml.tt" => ".travis.yml") when "gitlab" templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml") when "circle" templates.merge!("circleci/config.yml.tt" => ".circleci/config.yml") end if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?", "This means that any other developer or company will be legally allowed to use your code " \ "for free as long as they admit you created it. You can read more about the MIT license " \ "at https://choosealicense.com/licenses/mit.") config[:mit] = true Bundler.ui.info "MIT License enabled in config" templates.merge!("LICENSE.txt.tt" => "LICENSE.txt") end if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?", "Codes of conduct can increase contributions to your project by contributors who " \ "prefer collaborative, safe spaces. You can read more about the code of conduct at " \ "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \ "of enforcing it, so be sure that you are prepared to do that. Be sure that your email " \ "address is specified as a contact in the generated code of conduct so that people know " \ "who to contact in case of a violation. For suggestions about " \ "how to enforce codes of conduct, see https://bit.ly/coc-enforcement.") config[:coc] = true Bundler.ui.info "Code of conduct enabled in config" templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") end if ask_and_set(:changelog, "Do you want to include a changelog?", "A changelog is a file which contains a curated, chronologically ordered list of notable " \ "changes for each version of a project. To make it easier for users and contributors to" \ " see precisely what notable changes have been made between each release (or version) of" \ " the project. Whether consumers or developers, the end users of software are" \ " human beings who care about what's in the software. When the software changes, people " \ "want to know why and how. see https://keepachangelog.com") config[:changelog] = true Bundler.ui.info "Changelog enabled in config" templates.merge!("CHANGELOG.md.tt" => "CHANGELOG.md") end if ask_and_set(:rubocop, "Do you want to add rubocop as a dependency for gems you generate?", "RuboCop is a static code analyzer that has out-of-the-box rules for many " \ "of the guidelines in the community style guide. " \ "For more information, see the RuboCop docs (https://docs.rubocop.org/en/stable/) " \ "and the Ruby Style Guides (https://github.com/rubocop-hq/ruby-style-guide).") config[:rubocop] = true config[:rubocop_version] = Gem.ruby_version < Gem::Version.new("2.4.a") ? "0.81.0" : "1.7" Bundler.ui.info "RuboCop enabled in config" templates.merge!("rubocop.yml.tt" => ".rubocop.yml") end templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe] if options[:ext] templates.merge!( "ext/newgem/extconf.rb.tt" => "ext/#{name}/extconf.rb", "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", "ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c" ) end if File.exist?(target) && !File.directory?(target) Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`." exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError] end if use_git Bundler.ui.info "Initializing git repo in #{target}" `git init #{target}` config[:git_default_branch] = File.read("#{target}/.git/HEAD").split("/").last.chomp end templates.each do |src, dst| destination = target.join(dst) thor.template("newgem/#{src}", destination, config) end executables.each do |file| path = target.join(file) executable = (path.stat.mode | 0o111) path.chmod(executable) end if use_git Dir.chdir(target) do `git add .` end end # Open gemspec in editor open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit] Bundler.ui.info "Gem '#{name}' was successfully created. " \ "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html" end private def resolve_name(name) SharedHelpers.pwd.join(name).basename.to_s end def ask_and_set(key, header, message) choice = options[key] choice = Bundler.settings["gem.#{key}"] if choice.nil? if choice.nil? Bundler.ui.confirm header choice = Bundler.ui.yes? "#{message} y/(n):" Bundler.settings.set_global("gem.#{key}", choice) end choice end def validate_ext_name return unless gem_name.index("-") Bundler.ui.error "You have specified a gem name which does not conform to the \n" \ "naming guidelines for C extensions. For more information, \n" \ "see the 'Extension Naming' section at the following URL:\n" \ "https://guides.rubygems.org/gems-with-extensions/\n" exit 1 end def ask_and_set_test_framework test_framework = options[:test] || Bundler.settings["gem.test"] if test_framework.to_s.empty? Bundler.ui.confirm "Do you want to generate tests with your gem?" Bundler.ui.info hint_text("test") result = Bundler.ui.ask "Enter a test framework. rspec/minitest/test-unit/(none):" if result =~ /rspec|minitest|test-unit/ test_framework = result else test_framework = false end end if Bundler.settings["gem.test"].nil? Bundler.settings.set_global("gem.test", test_framework) end if options[:test] == Bundler.settings["gem.test"] Bundler.ui.info "#{options[:test]} is already configured, ignoring --test flag." end test_framework end def hint_text(setting) if Bundler.settings["gem.#{setting}"] == false "Your choice will only be applied to this gem." else "Future `bundle gem` calls will use your choice. " \ "This setting can be changed anytime with `bundle config gem.#{setting}`." end end def ask_and_set_ci ci_template = options[:ci] || Bundler.settings["gem.ci"] if ci_template.to_s.empty? Bundler.ui.confirm "Do you want to set up continuous integration for your gem? " \ "Supported services:\n" \ "* CircleCI: https://circleci.com/\n" \ "* GitHub Actions: https://github.com/features/actions\n" \ "* GitLab CI: https://docs.gitlab.com/ee/ci/\n" \ "* Travis CI: https://travis-ci.org/\n" \ "\n" Bundler.ui.info hint_text("ci") result = Bundler.ui.ask "Enter a CI service. github/travis/gitlab/circle/(none):" if result =~ /github|travis|gitlab|circle/ ci_template = result else ci_template = false end end if Bundler.settings["gem.ci"].nil? Bundler.settings.set_global("gem.ci", ci_template) end if options[:ci] == Bundler.settings["gem.ci"] Bundler.ui.info "#{options[:ci]} is already configured, ignoring --ci flag." end ci_template end def bundler_dependency_version v = Gem::Version.new(Bundler::VERSION) req = v.segments[0..1] req << "a" if v.prerelease? req.join(".") end def ensure_safe_gem_name(name, constant_array) if name =~ /^\d/ Bundler.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers." exit 1 end constant_name = constant_array.join("::") existing_constant = constant_array.inject(Object) do |c, s| defined = begin c.const_defined?(s) rescue NameError Bundler.ui.error "Invalid gem name #{name} -- `#{constant_name}` is an invalid constant name" exit 1 end (defined && c.const_get(s)) || break end return unless existing_constant Bundler.ui.error "Invalid gem name #{name} constant #{constant_name} is already in use. Please choose another gem name." exit 1 end def open_editor(editor, file) thor.run(%(#{editor} "#{file}")) end end end PK ]lqOww-gems/bundler-2.2.24/lib/bundler/cli/inject.rbnu[# frozen_string_literal: true module Bundler class CLI::Inject attr_reader :options, :name, :version, :group, :source, :gems def initialize(options, name, version) @options = options @name = name @version = version || last_version_number @group = options[:group].split(",") unless options[:group].nil? @source = options[:source] @gems = [] end def run # The required arguments allow Thor to give useful feedback when the arguments # are incorrect. This adds those first two arguments onto the list as a whole. gems.unshift(source).unshift(group).unshift(version).unshift(name) # Build an array of Dependency objects out of the arguments deps = [] # when `inject` support addition of more than one gem, then this loop will # help. Currently this loop is running once. gems.each_slice(4) do |gem_name, gem_version, gem_group, gem_source| ops = Gem::Requirement::OPS.map {|key, _val| key } has_op = ops.any? {|op| gem_version.start_with? op } gem_version = "~> #{gem_version}" unless has_op deps << Bundler::Dependency.new(gem_name, gem_version, "group" => gem_group, "source" => gem_source) end added = Injector.inject(deps, options) if added.any? Bundler.ui.confirm "Added to Gemfile:" Bundler.ui.confirm(added.map do |d| name = "'#{d.name}'" requirement = ", '#{d.requirement}'" group = ", :group => #{d.groups.inspect}" if d.groups != Array(:default) source = ", :source => '#{d.source}'" unless d.source.nil? %(gem #{name}#{requirement}#{group}#{source}) end.join("\n")) else Bundler.ui.confirm "All gems were already present in the Gemfile" end end private def last_version_number definition = Bundler.definition(true) definition.resolve_remotely! specs = definition.index[name].sort_by(&:version) unless options[:pre] specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } end spec = specs.last spec.version.to_s end end end PK ];.>>*gems/bundler-2.2.24/lib/bundler/cli/viz.rbnu[# frozen_string_literal: true module Bundler class CLI::Viz attr_reader :options, :gem_name def initialize(options) @options = options end def run # make sure we get the right `graphviz`. There is also a `graphviz` # gem we're not built to support gem "ruby-graphviz" require "graphviz" options[:without] = options[:without].join(":").tr(" ", ":").split(":") output_file = File.expand_path(options[:file]) graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format], options[:without]) graph.viz rescue LoadError => e Bundler.ui.error e.inspect Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" Bundler.ui.warn "`gem install ruby-graphviz`" rescue StandardError => e raise unless e.message =~ /GraphViz not installed or dot not in PATH/ Bundler.ui.error e.message Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`." end end end PK ]V9+gems/bundler-2.2.24/lib/bundler/cli/fund.rbnu[# frozen_string_literal: true module Bundler class CLI::Fund attr_reader :options def initialize(options) @options = options end def run Bundler.definition.validate_runtime! groups = Array(options[:group]).map(&:to_sym) deps = if groups.any? Bundler.definition.dependencies_for(groups) else Bundler.definition.current_dependencies end fund_info = deps.each_with_object([]) do |dep, arr| spec = Bundler.definition.specs[dep.name].first if spec.metadata.key?("funding_uri") arr << "* #{spec.name} (#{spec.version})\n Funding: #{spec.metadata["funding_uri"]}" end end if fund_info.empty? Bundler.ui.info "None of the installed gems you directly depend on are looking for funding." else Bundler.ui.info fund_info.join("\n") end end end end PK ]-gems/bundler-2.2.24/lib/bundler/cli/common.rbnu[# frozen_string_literal: true module Bundler module CLI::Common def self.output_post_install_messages(messages) return if Bundler.settings["ignore_messages"] messages.to_a.each do |name, msg| print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"] end end def self.print_post_install_message(name, msg) Bundler.ui.confirm "Post-install message from #{name}:" Bundler.ui.info msg end def self.output_fund_metadata_summary definition = Bundler.definition current_dependencies = definition.requested_dependencies current_specs = definition.specs count = current_dependencies.count {|dep| current_specs[dep.name].first.metadata.key?("funding_uri") } return if count.zero? intro = count > 1 ? "#{count} installed gems you directly depend on are" : "#{count} installed gem you directly depend on is" message = "#{intro} looking for funding.\n Run `bundle fund` for details" Bundler.ui.info message end def self.output_without_groups_message(command) return if Bundler.settings[:without].empty? Bundler.ui.confirm without_groups_message(command) end def self.without_groups_message(command) command_in_past_tense = command == :install ? "installed" : "updated" groups = Bundler.settings[:without] "Gems in the #{verbalize_groups(groups)} were not #{command_in_past_tense}." end def self.verbalize_groups(groups) groups.map!{|g| "'#{g}'" } group_list = [groups[0...-1].join(", "), groups[-1..-1]]. reject {|s| s.to_s.empty? }.join(" and ") group_str = groups.size == 1 ? "group" : "groups" "#{group_str} #{group_list}" end def self.select_spec(name, regex_match = nil) specs = [] regexp = Regexp.new(name) if regex_match Bundler.definition.specs.each do |spec| return spec if spec.name == name specs << spec if regexp && spec.name =~ regexp end case specs.count when 0 dep_in_other_group = Bundler.definition.current_dependencies.find {|dep|dep.name == name } if dep_in_other_group raise GemNotFound, "Could not find gem '#{name}', because it's in the #{verbalize_groups(dep_in_other_group.groups)}, configured to be ignored." else raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) end when 1 specs.first else ask_for_spec_from(specs) end rescue RegexpError raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) end def self.ask_for_spec_from(specs) specs.each_with_index do |spec, index| Bundler.ui.info "#{index.succ} : #{spec.name}", true end Bundler.ui.info "0 : - exit -", true num = Bundler.ui.ask("> ").to_i num > 0 ? specs[num - 1] : nil end def self.gem_not_found_message(missing_gem_name, alternatives) require_relative "../similarity_detector" message = "Could not find gem '#{missing_gem_name}'." alternate_names = alternatives.map {|a| a.respond_to?(:name) ? a.name : a } suggestions = SimilarityDetector.new(alternate_names).similar_word_list(missing_gem_name) message += "\nDid you mean #{suggestions}?" if suggestions message end def self.ensure_all_gems_in_lockfile!(names, locked_gems = Bundler.locked_gems) return unless locked_gems locked_names = locked_gems.specs.map(&:name).uniq names.-(locked_names).each do |g| raise GemNotFound, gem_not_found_message(g, locked_names) end end def self.configure_gem_version_promoter(definition, options) patch_level = patch_level_options(options) patch_level << :patch if patch_level.empty? && Bundler.settings[:prefer_patch] raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1 definition.gem_version_promoter.tap do |gvp| gvp.level = patch_level.first || :major gvp.strict = options[:strict] || options["update-strict"] || options["filter-strict"] end end def self.patch_level_options(options) [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) } end def self.clean_after_install? clean = Bundler.settings[:clean] return clean unless clean.nil? clean ||= Bundler.feature_flag.auto_clean_without_path? && Bundler.settings[:path].nil? clean &&= !Bundler.use_system_gems? clean end end end PK ]RR+gems/bundler-2.2.24/lib/bundler/cli/list.rbnu[# frozen_string_literal: true module Bundler class CLI::List def initialize(options) @options = options @without_group = options["without-group"].map(&:to_sym) @only_group = options["only-group"].map(&:to_sym) end def run raise InvalidOption, "The `--only-group` and `--without-group` options cannot be used together" if @only_group.any? && @without_group.any? raise InvalidOption, "The `--name-only` and `--paths` options cannot be used together" if @options["name-only"] && @options[:paths] specs = if @only_group.any? || @without_group.any? filtered_specs_by_groups else Bundler.load.specs end.reject {|s| s.name == "bundler" }.sort_by(&:name) return Bundler.ui.info "No gems in the Gemfile" if specs.empty? return specs.each {|s| Bundler.ui.info s.name } if @options["name-only"] return specs.each {|s| Bundler.ui.info s.full_gem_path } if @options["paths"] Bundler.ui.info "Gems included by the bundle:" specs.each {|s| Bundler.ui.info " * #{s.name} (#{s.version}#{s.git_version})" } Bundler.ui.info "Use `bundle info` to print more detailed information about a gem" end private def verify_group_exists(groups) (@without_group + @only_group).each do |group| raise InvalidOption, "`#{group}` group could not be found." unless groups.include?(group) end end def filtered_specs_by_groups definition = Bundler.definition groups = definition.groups verify_group_exists(groups) show_groups = if @without_group.any? groups.reject {|g| @without_group.include?(g) } elsif @only_group.any? groups.select {|g| @only_group.include?(g) } else groups end.map(&:to_sym) definition.specs_for(show_groups) end end end PK ]+gems/bundler-2.2.24/lib/bundler/cli/open.rbnu[# frozen_string_literal: true require "shellwords" module Bundler class CLI::Open attr_reader :options, :name def initialize(options, name) @options = options @name = name end def run editor = [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? } return Bundler.ui.info("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR") unless editor return unless spec = Bundler::CLI::Common.select_spec(name, :regex_match) if spec.default_gem? Bundler.ui.info "Unable to open #{name} because it's a default gem, so the directory it would normally be installed to does not exist." else path = spec.full_gem_path Dir.chdir(path) do command = Shellwords.split(editor) + [path] Bundler.with_original_env do system(*command) end || Bundler.ui.info("Could not run '#{command.join(" ")}'") end end end end end PK ]lww-gems/bundler-2.2.24/lib/bundler/cli/remove.rbnu[# frozen_string_literal: true module Bundler class CLI::Remove def initialize(gems, options) @gems = gems @options = options end def run raise InvalidOption, "Please specify gems to remove." if @gems.empty? Injector.remove(@gems, {}) Installer.install(Bundler.root, Bundler.definition) if @options["install"] end end end PK ] -gems/bundler-2.2.24/lib/bundler/cli/doctor.rbnu[# frozen_string_literal: true require "rbconfig" module Bundler class CLI::Doctor DARWIN_REGEX = /\s+(.+) \(compatibility /.freeze LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/.freeze attr_reader :options def initialize(options) @options = options end def otool_available? Bundler.which("otool") end def ldd_available? Bundler.which("ldd") end def dylibs_darwin(path) output = `/usr/bin/otool -L "#{path}"`.chomp dylibs = output.split("\n")[1..-1].map {|l| l.match(DARWIN_REGEX).captures[0] }.uniq # ignore @rpath and friends dylibs.reject {|dylib| dylib.start_with? "@" } end def dylibs_ldd(path) output = `/usr/bin/ldd "#{path}"`.chomp output.split("\n").map do |l| match = l.match(LDD_REGEX) next if match.nil? match.captures[0] end.compact end def dylibs(path) case RbConfig::CONFIG["host_os"] when /darwin/ return [] unless otool_available? dylibs_darwin(path) when /(linux|solaris|bsd)/ return [] unless ldd_available? dylibs_ldd(path) else # Windows, etc. Bundler.ui.warn("Dynamic library check not supported on this platform.") [] end end def bundles_for_gem(spec) Dir.glob("#{spec.full_gem_path}/**/*.bundle") end def check! require_relative "check" Bundler::CLI::Check.new({}).run end def run Bundler.ui.level = "error" if options[:quiet] Bundler.settings.validate! check! definition = Bundler.definition broken_links = {} definition.specs.each do |spec| bundles_for_gem(spec).each do |bundle| bad_paths = dylibs(bundle).select {|f| !File.exist?(f) } if bad_paths.any? broken_links[spec] ||= [] broken_links[spec].concat(bad_paths) end end end permissions_valid = check_home_permissions if broken_links.any? message = "The following gems are missing OS dependencies:" broken_links.map do |spec, paths| paths.uniq.map do |path| "\n * #{spec.name}: #{path}" end end.flatten.sort.each {|m| message += m } raise ProductionError, message elsif !permissions_valid Bundler.ui.info "No issues found with the installed bundle" end end private def check_home_permissions require "find" files_not_readable_or_writable = [] files_not_rw_and_owned_by_different_user = [] files_not_owned_by_current_user_but_still_rw = [] broken_symlinks = [] Find.find(Bundler.bundle_path.to_s).each do |f| if !File.exist?(f) broken_symlinks << f elsif !File.writable?(f) || !File.readable?(f) if File.stat(f).uid != Process.uid files_not_rw_and_owned_by_different_user << f else files_not_readable_or_writable << f end elsif File.stat(f).uid != Process.uid files_not_owned_by_current_user_but_still_rw << f end end ok = true if broken_symlinks.any? Bundler.ui.warn "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{broken_symlinks.join("\n - ")}" ok = false end if files_not_owned_by_current_user_but_still_rw.any? Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ "user, but are still readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" ok = false end if files_not_rw_and_owned_by_different_user.any? Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ "user, and are not readable/writable. These files are:\n - #{files_not_rw_and_owned_by_different_user.join("\n - ")}" ok = false end if files_not_readable_or_writable.any? Bundler.ui.warn "Files exist in the Bundler home that are not " \ "readable/writable by the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" ok = false end ok end end end PK ],-gems/bundler-2.2.24/lib/bundler/cli/update.rbnu[# frozen_string_literal: true module Bundler class CLI::Update attr_reader :options, :gems def initialize(options, gems) @options = options @gems = gems end def run Bundler.ui.level = "error" if options[:quiet] Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? sources = Array(options[:source]) groups = Array(options[:group]).map(&:to_sym) full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !options[:bundler] if full_update && !options[:all] if Bundler.feature_flag.update_requires_all_flag? raise InvalidOption, "To update everything, pass the `--all` flag." end SharedHelpers.major_deprecation 3, "Pass --all to `bundle update` to update everything" elsif !full_update && options[:all] raise InvalidOption, "Cannot specify --all along with specific options." end conservative = options[:conservative] if full_update if conservative Bundler.definition(:conservative => conservative) else Bundler.definition(true) end else unless Bundler.default_lockfile.exist? raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \ "Run `bundle install` to update and install the bundled gems." end Bundler::CLI::Common.ensure_all_gems_in_lockfile!(gems) if groups.any? deps = Bundler.definition.dependencies.select {|d| (d.groups & groups).any? } gems.concat(deps.map(&:name)) end Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby], :conservative => conservative, :bundler => options[:bundler]) end Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) Bundler::Fetcher.disable_endpoint = options["full-index"] opts = options.dup opts["update"] = true opts["local"] = options[:local] Bundler.settings.set_command_option_if_given :jobs, opts["jobs"] Bundler.definition.validate_runtime! if locked_gems = Bundler.definition.locked_gems previous_locked_info = locked_gems.specs.reduce({}) do |h, s| h[s.name] = { :spec => s, :version => s.version, :source => s.source.to_s } h end end installer = Installer.install Bundler.root, Bundler.definition, opts Bundler.load.cache if Bundler.app_cache.exist? if CLI::Common.clean_after_install? require_relative "clean" Bundler::CLI::Clean.new(options).run end if locked_gems gems.each do |name| locked_info = previous_locked_info[name] next unless locked_info locked_spec = locked_info[:spec] new_spec = Bundler.definition.specs[name].first unless new_spec unless locked_spec.match_platform(Bundler.local_platform) Bundler.ui.warn "Bundler attempted to update #{name} but it was not considered because it is for a different platform from the current one" end next end locked_source = locked_info[:source] new_source = new_spec.source.to_s next if locked_source != new_source new_version = new_spec.version locked_version = locked_info[:version] if new_version < locked_version Bundler.ui.warn "Note: #{name} version regressed from #{locked_version} to #{new_version}" elsif new_version == locked_version Bundler.ui.warn "Bundler attempted to update #{name} but its version stayed the same" end end end Bundler.ui.confirm "Bundle updated!" Bundler::CLI::Common.output_without_groups_message(:update) Bundler::CLI::Common.output_post_install_messages installer.post_install_messages Bundler::CLI::Common.output_fund_metadata_summary end end end PK ]="$"$/gems/bundler-2.2.24/lib/bundler/cli/outdated.rbnu[# frozen_string_literal: true module Bundler class CLI::Outdated attr_reader :options, :gems, :options_include_groups, :filter_options_patch, :sources, :strict attr_accessor :outdated_gems def initialize(options, gems) @options = options @gems = gems @sources = Array(options[:source]) @filter_options_patch = options.keys & %w[filter-major filter-minor filter-patch] @outdated_gems = [] @options_include_groups = [:group, :groups].any? do |v| options.keys.include?(v.to_s) end # the patch level options imply strict is also true. It wouldn't make # sense otherwise. @strict = options["filter-strict"] || Bundler::CLI::Common.patch_level_options(options).any? end def run check_for_deployment_mode! gems.each do |gem_name| Bundler::CLI::Common.select_spec(gem_name) end Bundler.definition.validate_runtime! current_specs = Bundler.ui.silence { Bundler.definition.resolve } current_dependencies = Bundler.ui.silence do Bundler.load.dependencies.map {|dep| [dep.name, dep] }.to_h end definition = if gems.empty? && sources.empty? # We're doing a full update Bundler.definition(true) else Bundler.definition(:gems => gems, :sources => sources) end Bundler::CLI::Common.configure_gem_version_promoter( Bundler.definition, options ) definition_resolution = proc do options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely! end if options[:parseable] Bundler.ui.silence(&definition_resolution) else definition_resolution.call end Bundler.ui.info "" # Loop through the current specs gemfile_specs, dependency_specs = current_specs.partition do |spec| current_dependencies.key? spec.name end specs = if options["only-explicit"] gemfile_specs else gemfile_specs + dependency_specs end specs.sort_by(&:name).uniq(&:name).each do |current_spec| next unless gems.empty? || gems.include?(current_spec.name) active_spec = retrieve_active_spec(definition, current_spec) next unless active_spec next unless filter_options_patch.empty? || update_present_via_semver_portions(current_spec, active_spec, options) gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version) next unless gem_outdated || (current_spec.git_version != active_spec.git_version) dependency = current_dependencies[current_spec.name] groups = "" if dependency && !options[:parseable] groups = dependency.groups.join(", ") end outdated_gems << { :active_spec => active_spec, :current_spec => current_spec, :dependency => dependency, :groups => groups, } end if outdated_gems.empty? unless options[:parseable] Bundler.ui.info(nothing_outdated_message) end else if options_include_groups relevant_outdated_gems = outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems| contains_group = groups.split(", ").include?(options[:group]) next unless options[:groups] || contains_group gems end.compact if options[:parseable] relevant_outdated_gems.each do |gems| print_gems(gems) end else print_gems_table(relevant_outdated_gems) end elsif options[:parseable] print_gems(outdated_gems) else print_gems_table(outdated_gems) end exit 1 end end private def groups_text(group_text, groups) "#{group_text}#{groups.split(",").size > 1 ? "s" : ""} \"#{groups}\"" end def nothing_outdated_message if filter_options_patch.any? display = filter_options_patch.map do |o| o.sub("filter-", "") end.join(" or ") "No #{display} updates to display.\n" else "Bundle up to date!\n" end end def retrieve_active_spec(definition, current_spec) active_spec = definition.resolve.find_by_name_and_platform(current_spec.name, current_spec.platform) return unless active_spec return active_spec if strict active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } end active_specs.last end def print_gems(gems_list) gems_list.each do |gem| print_gem( gem[:current_spec], gem[:active_spec], gem[:dependency], gem[:groups], ) end end def print_gems_table(gems_list) data = gems_list.map do |gem| gem_column_for( gem[:current_spec], gem[:active_spec], gem[:dependency], gem[:groups], ) end print_indented([table_header] + data) end def print_gem(current_spec, active_spec, dependency, groups) spec_version = "#{active_spec.version}#{active_spec.git_version}" spec_version += " (from #{active_spec.loaded_from})" if Bundler.ui.debug? && active_spec.loaded_from current_version = "#{current_spec.version}#{current_spec.git_version}" if dependency && dependency.specific? dependency_version = %(, requested #{dependency.requirement}) end spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \ "installed #{current_version}#{dependency_version})" output_message = if options[:parseable] spec_outdated_info.to_s elsif options_include_groups || groups.empty? " * #{spec_outdated_info}" else " * #{spec_outdated_info} in #{groups_text("group", groups)}" end Bundler.ui.info output_message.rstrip end def gem_column_for(current_spec, active_spec, dependency, groups) current_version = "#{current_spec.version}#{current_spec.git_version}" spec_version = "#{active_spec.version}#{active_spec.git_version}" dependency = dependency.requirement if dependency ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s] ret_val << active_spec.loaded_from.to_s if Bundler.ui.debug? ret_val end def check_for_deployment_mode! return unless Bundler.frozen_bundle? suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any? "bundle config unset frozen" elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? "bundle config unset deployment" end raise ProductionError, "You are trying to check outdated gems in " \ "deployment mode. Run `bundle outdated` elsewhere.\n" \ "\nIf this is a development machine, remove the " \ "#{Bundler.default_gemfile} freeze" \ "\nby running `#{suggested_command}`." end def update_present_via_semver_portions(current_spec, active_spec, options) current_major = current_spec.version.segments.first active_major = active_spec.version.segments.first update_present = false update_present = active_major > current_major if options["filter-major"] if !update_present && (options["filter-minor"] || options["filter-patch"]) && current_major == active_major current_minor = get_version_semver_portion_value(current_spec, 1) active_minor = get_version_semver_portion_value(active_spec, 1) update_present = active_minor > current_minor if options["filter-minor"] if !update_present && options["filter-patch"] && current_minor == active_minor current_patch = get_version_semver_portion_value(current_spec, 2) active_patch = get_version_semver_portion_value(active_spec, 2) update_present = active_patch > current_patch end end update_present end def get_version_semver_portion_value(spec, version_portion_index) version_section = spec.version.segments[version_portion_index, 1] version_section.to_a[0].to_i end def print_indented(matrix) header = matrix[0] data = matrix[1..-1] column_sizes = Array.new(header.size) do |index| matrix.max_by {|row| row[index].length }[index].length end Bundler.ui.info justify(header, column_sizes) data.sort_by! {|row| row[0] } data.each do |row| Bundler.ui.info justify(row, column_sizes) end end def table_header header = ["Gem", "Current", "Latest", "Requested", "Groups"] header << "Path" if Bundler.ui.debug? header end def justify(row, sizes) row.each_with_index.map do |element, index| element.ljust(sizes[index]) end.join(" ").strip + "\n" end end end PK ]w#w#.gems/bundler-2.2.24/lib/bundler/cli/install.rbnu[# frozen_string_literal: true module Bundler class CLI::Install attr_reader :options def initialize(options) @options = options end def run Bundler.ui.level = "error" if options[:quiet] warn_if_root Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD # Disable color in deployment mode Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment] check_for_options_conflicts check_trust_policy if options[:deployment] || options[:frozen] || Bundler.frozen_bundle? unless Bundler.default_lockfile.exist? flag = "--deployment flag" if options[:deployment] flag ||= "--frozen flag" if options[:frozen] flag ||= "deployment setting" raise ProductionError, "The #{flag} requires a #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}. Please make " \ "sure you have checked your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} into version control " \ "before deploying." end options[:local] = true if Bundler.app_cache.exist? Bundler.settings.set_command_option :deployment, true if options[:deployment] Bundler.settings.set_command_option :frozen, true if options[:frozen] end # When install is called with --no-deployment, disable deployment mode if options[:deployment] == false Bundler.settings.set_command_option :frozen, nil options[:system] = true end normalize_settings Bundler::Fetcher.disable_endpoint = options["full-index"] if options["binstubs"] Bundler::SharedHelpers.major_deprecation 2, "The --binstubs option will be removed in favor of `bundle binstubs --all`" end Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? definition = Bundler.definition definition.validate_runtime! installer = Installer.install(Bundler.root, definition, options) Bundler.settings.temporary(:cache_all_platforms => options[:local] ? false : Bundler.settings[:cache_all_platforms]) do Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle? end Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}." Bundler::CLI::Common.output_without_groups_message(:install) if Bundler.use_system_gems? Bundler.ui.confirm "Use `bundle info [gemname]` to see where a bundled gem is installed." else relative_path = Bundler.configured_bundle_path.base_path_relative_to_pwd Bundler.ui.confirm "Bundled gems are installed into `#{relative_path}`" end Bundler::CLI::Common.output_post_install_messages installer.post_install_messages warn_ambiguous_gems if CLI::Common.clean_after_install? require_relative "clean" Bundler::CLI::Clean.new(options).run end Bundler::CLI::Common.output_fund_metadata_summary rescue GemNotFound, VersionConflict => e if options[:local] && Bundler.app_cache.exist? Bundler.ui.warn "Some gems seem to be missing from your #{Bundler.settings.app_cache_path} directory." end unless Bundler.definition.has_rubygems_remotes? Bundler.ui.warn <<-WARN, :wrap => true Your Gemfile has no gem server sources. If you need gems that are \ not already on your machine, add a line like this to your Gemfile: source 'https://rubygems.org' WARN end raise e rescue Gem::InvalidSpecificationException => e Bundler.ui.warn "You have one or more invalid gemspecs that need to be fixed." raise e end private def warn_if_root return if Bundler.settings[:silence_root_warning] || Gem.win_platform? || !Process.uid.zero? Bundler.ui.warn "Don't run Bundler as root. Bundler can ask for sudo " \ "if it is needed, and installing your bundle as root will break this " \ "application for all non-root users on this machine.", :wrap => true end def dependencies_count_for(definition) count = definition.dependencies.count "#{count} Gemfile #{count == 1 ? "dependency" : "dependencies"}" end def gems_installed_for(definition) count = definition.specs.count "#{count} #{count == 1 ? "gem" : "gems"} now installed" end def check_for_group_conflicts_in_cli_options conflicting_groups = Array(options[:without]) & Array(options[:with]) return if conflicting_groups.empty? raise InvalidOption, "You can't list a group in both with and without." \ " The offending groups are: #{conflicting_groups.join(", ")}." end def check_for_options_conflicts if (options[:path] || options[:deployment]) && options[:system] error_message = String.new error_message << "You have specified both --path as well as --system. Please choose only one option.\n" if options[:path] error_message << "You have specified both --deployment as well as --system. Please choose only one option.\n" if options[:deployment] raise InvalidOption.new(error_message) end end def check_trust_policy trust_policy = options["trust-policy"] unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy) raise InvalidOption, "RubyGems doesn't know about trust policy '#{trust_policy}'. " \ "The known policies are: #{Bundler.rubygems.security_policies.keys.join(", ")}." end Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy end def normalize_groups options[:with] &&= options[:with].join(":").tr(" ", ":").split(":") options[:without] &&= options[:without].join(":").tr(" ", ":").split(":") check_for_group_conflicts_in_cli_options Bundler.settings.set_command_option :with, nil if options[:with] == [] Bundler.settings.set_command_option :without, nil if options[:without] == [] with = options.fetch(:with, []) with |= Bundler.settings[:with].map(&:to_s) with -= options[:without] if options[:without] without = options.fetch(:without, []) without |= Bundler.settings[:without].map(&:to_s) without -= options[:with] if options[:with] options[:with] = with options[:without] = without unless Bundler.settings[:without] == options[:without] && Bundler.settings[:with] == options[:with] # need to nil them out first to get around validation for backwards compatibility Bundler.settings.set_command_option :without, nil Bundler.settings.set_command_option :with, nil Bundler.settings.set_command_option :without, options[:without] - options[:with] Bundler.settings.set_command_option :with, options[:with] end end def normalize_settings Bundler.settings.set_command_option :path, nil if options[:system] Bundler.settings.temporary(:path_relative_to_cwd => false) do Bundler.settings.set_command_option :path, "vendor/bundle" if Bundler.settings[:deployment] && Bundler.settings[:path].nil? end Bundler.settings.set_command_option_if_given :path, options[:path] Bundler.settings.temporary(:path_relative_to_cwd => false) do Bundler.settings.set_command_option :path, "bundle" if options["standalone"] && Bundler.settings[:path].nil? end bin_option = options["binstubs"] bin_option = nil if bin_option && bin_option.empty? Bundler.settings.set_command_option :bin, bin_option if options["binstubs"] Bundler.settings.set_command_option_if_given :shebang, options["shebang"] Bundler.settings.set_command_option_if_given :jobs, options["jobs"] Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"] Bundler.settings.set_command_option_if_given :no_install, options["no-install"] Bundler.settings.set_command_option_if_given :clean, options["clean"] normalize_groups options[:force] = options[:redownload] end def warn_ambiguous_gems # TODO: remove this when we drop Bundler 1.x support Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris| Bundler.ui.warn "Warning: the gem '#{name}' was found in multiple sources." Bundler.ui.warn "Installed from: #{installed_from_uri}" Bundler.ui.warn "Also found in:" also_found_in_uris.each {|uri| Bundler.ui.warn " * #{uri}" } Bundler.ui.warn "You should add a source requirement to restrict this gem to your preferred source." Bundler.ui.warn "For example:" Bundler.ui.warn " gem '#{name}', :source => '#{installed_from_uri}'" Bundler.ui.warn "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again." end end end end PK ]3LT/gems/bundler-2.2.24/lib/bundler/cli/pristine.rbnu[# frozen_string_literal: true module Bundler class CLI::Pristine def initialize(gems) @gems = gems end def run CLI::Common.ensure_all_gems_in_lockfile!(@gems) definition = Bundler.definition definition.validate_runtime! installer = Bundler::Installer.new(Bundler.root, definition) Bundler.load.specs.each do |spec| next if spec.name == "bundler" # Source::Rubygems doesn't install bundler next if !@gems.empty? && !@gems.include?(spec.name) gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})" gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY case source = spec.source when Source::Rubygems cached_gem = spec.cache_file unless File.exist?(cached_gem) Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.") next end FileUtils.rm_rf spec.full_gem_path when Source::Git if source.local? Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is locally overridden.") next end source.remote! if extension_cache_path = source.extension_cache_path(spec) FileUtils.rm_rf extension_cache_path end FileUtils.rm_rf spec.extension_dir FileUtils.rm_rf spec.full_gem_path else Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") next end Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec end end end end PK ]Ʊe}}-gems/bundler-2.2.24/lib/bundler/cli/config.rbnu[# frozen_string_literal: true module Bundler class CLI::Config < Thor class_option :parseable, :type => :boolean, :banner => "Use minimal formatting for more parseable output" def self.scope_options method_option :global, :type => :boolean, :banner => "Only change the global config" method_option :local, :type => :boolean, :banner => "Only change the local config" end private_class_method :scope_options desc "base NAME [VALUE]", "The Bundler 1 config interface", :hide => true scope_options method_option :delete, :type => :boolean, :banner => "delete" def base(name = nil, *value) new_args = if ARGV.size == 1 ["config", "list"] elsif ARGV.include?("--delete") ARGV.map {|arg| arg == "--delete" ? "unset" : arg } elsif ARGV.include?("--global") || ARGV.include?("--local") || ARGV.size == 3 ["config", "set", *ARGV[1..-1]] else ["config", "get", ARGV[1]] end SharedHelpers.major_deprecation 3, "Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle #{new_args.join(" ")}` instead." Base.new(options, name, value, self).run end desc "list", "List out all configured settings" def list Base.new(options, nil, nil, self).run end desc "get NAME", "Returns the value for the given key" def get(name) Base.new(options, name, nil, self).run end desc "set NAME VALUE", "Sets the given value for the given key" scope_options def set(name, value, *value_) Base.new(options, name, value_.unshift(value), self).run end desc "unset NAME", "Unsets the value for the given key" scope_options def unset(name) options[:delete] = true Base.new(options, name, nil, self).run end default_task :base class Base attr_reader :name, :value, :options, :scope, :thor def initialize(options, name, value, thor) @options = options @name = name value = Array(value) @value = value.empty? ? nil : value.join(" ") @thor = thor validate_scope! end def run unless name warn_unused_scope "Ignoring --#{scope}" confirm_all return end if options[:delete] if !explicit_scope? || scope != "global" Bundler.settings.set_local(name, nil) end if !explicit_scope? || scope != "local" Bundler.settings.set_global(name, nil) end return end if value.nil? warn_unused_scope "Ignoring --#{scope} since no value to set was given" if options[:parseable] if value = Bundler.settings[name] Bundler.ui.info("#{name}=#{value}") end return end confirm(name) return end Bundler.ui.info(message) if message Bundler.settings.send("set_#{scope}", name, new_value) end def confirm_all if @options[:parseable] thor.with_padding do Bundler.settings.all.each do |setting| val = Bundler.settings[setting] Bundler.ui.info "#{setting}=#{val}" end end else Bundler.ui.confirm "Settings are listed in order of priority. The top value will be used.\n" Bundler.settings.all.each do |setting| Bundler.ui.confirm setting show_pretty_values_for(setting) Bundler.ui.confirm "" end end end def confirm(name) Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used" show_pretty_values_for(name) end def new_value pathname = Pathname.new(value) if name.start_with?("local.") && pathname.directory? pathname.expand_path.to_s else value end end def message locations = Bundler.settings.locations(name) if @options[:parseable] "#{name}=#{new_value}" if new_value elsif scope == "global" if !locations[:local].nil? "Your application has set #{name} to #{locations[:local].inspect}. " \ "This will override the global value you are currently setting" elsif locations[:env] "You have a bundler environment variable for #{name} set to " \ "#{locations[:env].inspect}. This will take precedence over the global value you are setting" elsif !locations[:global].nil? && locations[:global] != value "You are replacing the current global value of #{name}, which is currently " \ "#{locations[:global].inspect}" end elsif scope == "local" && !locations[:local].nil? && locations[:local] != value "You are replacing the current local value of #{name}, which is currently " \ "#{locations[:local].inspect}" end end def show_pretty_values_for(setting) thor.with_padding do Bundler.settings.pretty_values_for(setting).each do |line| Bundler.ui.info line end end end def explicit_scope? @explicit_scope end def warn_unused_scope(msg) return unless explicit_scope? return if options[:parseable] Bundler.ui.warn(msg) end def validate_scope! @explicit_scope = true scopes = %w[global local].select {|s| options[s] } case scopes.size when 0 @scope = "global" @explicit_scope = false when 1 @scope = scopes.first else raise InvalidOption, "The options #{scopes.join " and "} were specified. Please only use one of the switches at a time." end end end end end PK ]RL*gems/bundler-2.2.24/lib/bundler/cli/add.rbnu[# frozen_string_literal: true module Bundler class CLI::Add attr_reader :gems, :options, :version def initialize(options, gems) @gems = gems @options = options @options[:group] = options[:group].split(",").map(&:strip) unless options[:group].nil? @version = options[:version].split(",").map(&:strip) unless options[:version].nil? end def run validate_options! inject_dependencies perform_bundle_install unless options["skip-install"] end private def perform_bundle_install Installer.install(Bundler.root, Bundler.definition) Bundler.load.cache if Bundler.app_cache.exist? end def inject_dependencies dependencies = gems.map {|g| Bundler::Dependency.new(g, version, options) } Injector.inject(dependencies, :conservative_versioning => options[:version].nil?, # Perform conservative versioning only when version is not specified :optimistic => options[:optimistic], :strict => options[:strict]) end def validate_options! raise InvalidOption, "You can not specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic] # raise error when no gems are specified raise InvalidOption, "Please specify gems to add." if gems.empty? version.to_a.each do |v| raise InvalidOption, "Invalid gem requirement pattern '#{v}'" unless Gem::Requirement::PATTERN =~ v.to_s end end end end PK ]u),gems/bundler-2.2.24/lib/bundler/cli/issue.rbnu[# frozen_string_literal: true require "rbconfig" module Bundler class CLI::Issue def run Bundler.ui.info <<-EOS.gsub(/^ {8}/, "") Did you find an issue with Bundler? Before filing a new issue, be sure to check out these resources: 1. Check out our troubleshooting guide for quick fixes to common issues: https://github.com/rubygems/rubygems/blob/master/bundler/doc/TROUBLESHOOTING.md 2. Instructions for common Bundler uses can be found on the documentation site: https://bundler.io/ 3. Information about each Bundler command can be found in the Bundler man pages: https://bundler.io/man/bundle.1.html Hopefully the troubleshooting steps above resolved your problem! If things still aren't working the way you expect them to, please let us know so that we can diagnose and help fix the problem you're having. Please view the Filing Issues guide for more information: https://github.com/rubygems/rubygems/blob/master/bundler/doc/contributing/ISSUES.md EOS Bundler.ui.info Bundler::Env.report Bundler.ui.info "\n## Bundle Doctor" doctor end def doctor require_relative "doctor" Bundler::CLI::Doctor.new({}).run end end end PK ]"G/gems/bundler-2.2.24/lib/bundler/cli/binstubs.rbnu[# frozen_string_literal: true module Bundler class CLI::Binstubs attr_reader :options, :gems def initialize(options, gems) @options = options @gems = gems end def run Bundler.definition.validate_runtime! path_option = options["path"] path_option = nil if path_option && path_option.empty? Bundler.settings.set_command_option :bin, path_option if options["path"] Bundler.settings.set_command_option_if_given :shebang, options["shebang"] installer = Installer.new(Bundler.root, Bundler.definition) installer_opts = { :force => options[:force], :binstubs_cmd => true, :all_platforms => options["all-platforms"], } if options[:all] raise InvalidOption, "Cannot specify --all with specific gems" unless gems.empty? @gems = Bundler.definition.specs.map(&:name) installer_opts.delete(:binstubs_cmd) elsif gems.empty? Bundler.ui.error "`bundle binstubs` needs at least one gem to run." exit 1 end gems.each do |gem_name| spec = Bundler.definition.specs.find {|s| s.name == gem_name } unless spec raise GemNotFound, Bundler::CLI::Common.gem_not_found_message( gem_name, Bundler.definition.specs ) end if options[:standalone] next Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") if gem_name == "bundler" Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do installer.generate_standalone_bundler_executable_stubs(spec, installer_opts) end else installer.generate_bundler_executable_stubs(spec, installer_opts) end end end end end PK ]W{ { +gems/bundler-2.2.24/lib/bundler/cli/info.rbnu[# frozen_string_literal: true module Bundler class CLI::Info attr_reader :gem_name, :options def initialize(options, gem_name) @options = options @gem_name = gem_name end def run Bundler.ui.silence do Bundler.definition.validate_runtime! Bundler.load.lock end spec = spec_for_gem(gem_name) if spec return print_gem_path(spec) if @options[:path] print_gem_info(spec) end end private def spec_for_gem(gem_name) spec = Bundler.definition.specs.find {|s| s.name == gem_name } spec || default_gem_spec(gem_name) || Bundler::CLI::Common.select_spec(gem_name, :regex_match) end def default_gem_spec(gem_name) return unless Gem::Specification.respond_to?(:find_all_by_name) gem_spec = Gem::Specification.find_all_by_name(gem_name).last return gem_spec if gem_spec && gem_spec.respond_to?(:default_gem?) && gem_spec.default_gem? end def spec_not_found(gem_name) raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(gem_name, Bundler.definition.dependencies) end def print_gem_path(spec) if spec.name == "bundler" path = File.expand_path("../../../..", __FILE__) else path = spec.full_gem_path unless File.directory?(path) return Bundler.ui.warn "The gem #{gem_name} has been deleted. It was installed at: #{path}" end end Bundler.ui.info path end def print_gem_info(spec) metadata = spec.metadata gem_info = String.new gem_info << " * #{spec.name} (#{spec.version}#{spec.git_version})\n" gem_info << "\tSummary: #{spec.summary}\n" if spec.summary gem_info << "\tHomepage: #{spec.homepage}\n" if spec.homepage gem_info << "\tDocumentation: #{metadata["documentation_uri"]}\n" if metadata.key?("documentation_uri") gem_info << "\tSource Code: #{metadata["source_code_uri"]}\n" if metadata.key?("source_code_uri") gem_info << "\tFunding: #{metadata["funding_uri"]}\n" if metadata.key?("funding_uri") gem_info << "\tWiki: #{metadata["wiki_uri"]}\n" if metadata.key?("wiki_uri") gem_info << "\tChangelog: #{metadata["changelog_uri"]}\n" if metadata.key?("changelog_uri") gem_info << "\tBug Tracker: #{metadata["bug_tracker_uri"]}\n" if metadata.key?("bug_tracker_uri") gem_info << "\tMailing List: #{metadata["mailing_list_uri"]}\n" if metadata.key?("mailing_list_uri") gem_info << "\tPath: #{spec.full_gem_path}\n" gem_info << "\tDefault Gem: yes" if spec.respond_to?(:default_gem?) && spec.default_gem? Bundler.ui.info gem_info end end end PK ]?z-gems/bundler-2.2.24/lib/bundler/gem_helper.rbnu[# frozen_string_literal: true require_relative "../bundler" require "shellwords" module Bundler class GemHelper include Rake::DSL if defined? Rake::DSL class << self # set when install'd. attr_accessor :instance def install_tasks(opts = {}) new(opts[:dir], opts[:name]).install end def tag_prefix=(prefix) instance.tag_prefix = prefix end def gemspec(&block) gemspec = instance.gemspec block.call(gemspec) if block gemspec end end attr_reader :spec_path, :base, :gemspec attr_writer :tag_prefix def initialize(base = nil, name = nil) @base = File.expand_path(base || SharedHelpers.pwd) gemspecs = name ? [File.join(@base, "#{name}.gemspec")] : Gem::Util.glob_files_in_dir("{,*}.gemspec", @base) raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1 @spec_path = gemspecs.first @gemspec = Bundler.load_gemspec(@spec_path) @tag_prefix = "" end def install built_gem_path = nil desc "Build #{name}-#{version}.gem into the pkg directory." task "build" do built_gem_path = build_gem end desc "Generate SHA512 checksum if #{name}-#{version}.gem into the checksums directory." task "build:checksum" => "build" do build_checksum(built_gem_path) end desc "Build and install #{name}-#{version}.gem into system gems." task "install" => "build" do install_gem(built_gem_path) end desc "Build and install #{name}-#{version}.gem into system gems without network access." task "install:local" => "build" do install_gem(built_gem_path, :local) end desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to #{gem_push_host}\n" \ "To prevent publishing in RubyGems use `gem_push=no rake release`" task "release", [:remote] => ["build", "release:guard_clean", "release:source_control_push", "release:rubygem_push"] do end task "release:guard_clean" do guard_clean end task "release:source_control_push", [:remote] do |_, args| tag_version { git_push(args[:remote]) } unless already_tagged? end task "release:rubygem_push" do rubygem_push(built_gem_path) if gem_push? end GemHelper.instance = self end def build_gem file_name = nil sh([*gem_command, "build", "-V", spec_path]) do file_name = File.basename(built_gem_path) SharedHelpers.filesystem_access(File.join(base, "pkg")) {|p| FileUtils.mkdir_p(p) } FileUtils.mv(built_gem_path, "pkg") Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}." end File.join(base, "pkg", file_name) end def install_gem(built_gem_path = nil, local = false) built_gem_path ||= build_gem cmd = [*gem_command, "install", built_gem_path.to_s] cmd << "--local" if local _, status = sh_with_status(cmd) unless status.success? raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" end Bundler.ui.confirm "#{name} (#{version}) installed." end def build_checksum(built_gem_path = nil) built_gem_path ||= build_gem SharedHelpers.filesystem_access(File.join(base, "checksums")) {|p| FileUtils.mkdir_p(p) } file_name = "#{File.basename(built_gem_path)}.sha512" require "digest/sha2" checksum = Digest::SHA512.new.hexdigest(built_gem_path.to_s) target = File.join(base, "checksums", file_name) File.write(target, checksum) Bundler.ui.confirm "#{name} #{version} checksum written to checksums/#{file_name}." end protected def rubygem_push(path) cmd = [*gem_command, "push", path] cmd << "--key" << gem_key if gem_key cmd << "--host" << allowed_push_host if allowed_push_host sh_with_input(cmd) Bundler.ui.confirm "Pushed #{name} #{version} to #{gem_push_host}" end def built_gem_path Gem::Util.glob_files_in_dir("#{name}-*.gem", base).sort_by {|f| File.mtime(f) }.last end def git_push(remote = nil) remote ||= default_remote perform_git_push "#{remote} refs/heads/#{current_branch}" perform_git_push "#{remote} refs/tags/#{version_tag}" Bundler.ui.confirm "Pushed git commits and release tag." end def default_remote remote_for_branch, status = sh_with_status(%W[git config --get branch.#{current_branch}.remote]) return "origin" unless status.success? remote_for_branch.strip end def current_branch # We can replace this with `git branch --show-current` once we drop support for git < 2.22.0 sh(%w[git rev-parse --abbrev-ref HEAD]).gsub(%r{\Aheads/}, "").strip end def allowed_push_host @gemspec.metadata["allowed_push_host"] if @gemspec.respond_to?(:metadata) end def gem_push_host env_rubygems_host = ENV["RUBYGEMS_HOST"] env_rubygems_host = nil if env_rubygems_host && env_rubygems_host.empty? allowed_push_host || env_rubygems_host || "rubygems.org" end def perform_git_push(options = "") cmd = "git push #{options}" out, status = sh_with_status(cmd.shellsplit) return if status.success? raise "Couldn't git push. `#{cmd}' failed with the following output:\n\n#{out}\n" end def already_tagged? return false unless sh(%w[git tag]).split(/\n/).include?(version_tag) Bundler.ui.confirm "Tag #{version_tag} has already been created." true end def guard_clean clean? && committed? || raise("There are files that need to be committed first.") end def clean? sh_with_status(%w[git diff --exit-code])[1].success? end def committed? sh_with_status(%w[git diff-index --quiet --cached HEAD])[1].success? end def tag_version sh %W[git tag -m Version\ #{version} #{version_tag}] Bundler.ui.confirm "Tagged #{version_tag}." yield if block_given? rescue RuntimeError Bundler.ui.error "Untagging #{version_tag} due to error." sh_with_status %W[git tag -d #{version_tag}] raise end def version gemspec.version end def version_tag "#{@tag_prefix}v#{version}" end def name gemspec.name end def sh_with_input(cmd) Bundler.ui.debug(cmd) SharedHelpers.chdir(base) do abort unless Kernel.system(*cmd) end end def sh(cmd, &block) out, status = sh_with_status(cmd, &block) unless status.success? cmd = cmd.shelljoin if cmd.respond_to?(:shelljoin) raise(out.empty? ? "Running `#{cmd}` failed. Run this command directly for more detailed output." : out) end out end def sh_with_status(cmd, &block) Bundler.ui.debug(cmd) SharedHelpers.chdir(base) do outbuf = IO.popen(cmd, :err => [:child, :out], &:read) status = $? block.call(outbuf) if status.success? && block [outbuf, status] end end def gem_key Bundler.settings["gem.push_key"].to_s.downcase if Bundler.settings["gem.push_key"] end def gem_push? !%w[n no nil false off 0].include?(ENV["gem_push"].to_s.downcase) end def gem_command ENV["GEM_COMMAND"]&.shellsplit || ["gem"] end end end PK ]`f<<+gems/bundler-2.2.24/lib/bundler/resolver.rbnu[# frozen_string_literal: true module Bundler class Resolver require_relative "vendored_molinillo" require_relative "resolver/spec_group" include GemHelpers # Figures out the best possible configuration of gems that satisfies # the list of passed dependencies and any child dependencies without # causing any gem activation errors. # # ==== Parameters # *dependencies:: The list of dependencies to resolve # # ==== Returns # ,nil:: If the list of dependencies can be resolved, a # collection of gemspecs is returned. Otherwise, nil is returned. def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) base = SpecSet.new(base) unless base.is_a?(SpecSet) resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) result = resolver.start(requirements) SpecSet.new(SpecSet.new(result).for(requirements.reject{|dep| dep.name.end_with?("\0") })) end def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) @source_requirements = source_requirements @base = base @resolver = Molinillo::Resolver.new(self, self) @search_for = {} @base_dg = Molinillo::DependencyGraph.new aggregate_global_source = @source_requirements[:default].is_a?(Source::RubygemsAggregate) @base.each do |ls| dep = Dependency.new(ls.name, ls.version) ls.source = source_for(ls.name) unless aggregate_global_source @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true) end additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } @platforms = platforms.reject {|p| p != Gem::Platform::RUBY && (platforms - [p]).any? {|pl| generic(pl) == p } } @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY] @gem_version_promoter = gem_version_promoter @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? end def start(requirements) @gem_version_promoter.prerelease_specified = @prerelease_specified = {} requirements.each {|dep| @prerelease_specified[dep.name] ||= dep.prerelease? } verify_gemfile_dependencies_are_found!(requirements) dg = @resolver.resolve(requirements, @base_dg) dg. map(&:payload). reject {|sg| sg.name.end_with?("\0") }. map(&:to_specs). flatten rescue Molinillo::VersionConflict => e message = version_conflict_message(e) raise VersionConflict.new(e.conflicts.keys.uniq, message) rescue Molinillo::CircularDependencyError => e names = e.dependencies.sort_by(&:name).map {|d| "gem '#{d.name}'" } raise CyclicDependencyError, "Your bundle requires gems that depend" \ " on each other, creating an infinite loop. Please remove" \ " #{names.count > 1 ? "either " : ""}#{names.join(" or ")}" \ " and try again." end include Molinillo::UI # Conveys debug information to the user. # # @param [Integer] depth the current depth of the resolution process. # @return [void] def debug(depth = 0) return unless debug? debug_info = yield debug_info = debug_info.inspect unless debug_info.is_a?(String) puts debug_info.split("\n").map {|s| depth == 0 ? "BUNDLER: #{s}" : "BUNDLER(#{depth}): #{s}" } end def debug? return @debug_mode if defined?(@debug_mode) @debug_mode = ENV["BUNDLER_DEBUG_RESOLVER"] || ENV["BUNDLER_DEBUG_RESOLVER_TREE"] || ENV["DEBUG_RESOLVER"] || ENV["DEBUG_RESOLVER_TREE"] || false end def before_resolution Bundler.ui.info "Resolving dependencies...", debug? end def after_resolution Bundler.ui.info "" end def indicate_progress Bundler.ui.info ".", false unless debug? end include Molinillo::SpecificationProvider def dependencies_for(specification) specification.dependencies_for_activated_platforms end def search_for(dependency_proxy) platform = dependency_proxy.__platform dependency = dependency_proxy.dep name = dependency.name @search_for[dependency_proxy] ||= begin results = results_for(dependency, @base[name]) if vertex = @base_dg.vertex_named(name) locked_requirement = vertex.payload.requirement end if !@prerelease_specified[name] && (!@use_gvp || locked_requirement.nil?) # Move prereleases to the beginning of the list, so they're considered # last during resolution. pre, results = results.partition {|spec| spec.version.prerelease? } results = pre + results end spec_groups = if results.any? nested = [] results.each do |spec| version, specs = nested.last if version == spec.version specs << spec else nested << [spec.version, [spec]] end end nested.reduce([]) do |groups, (version, specs)| next groups if locked_requirement && !locked_requirement.satisfied_by?(version) specs_by_platform = Hash.new do |current_specs, current_platform| current_specs[current_platform] = select_best_platform_match(specs, current_platform) end spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY) groups << spec_group_ruby if spec_group_ruby next groups if @resolving_only_for_ruby spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform) groups << spec_group if spec_group groups end else [] end # GVP handles major itself, but it's still a bit risky to trust it with it # until we get it settled with new behavior. For 2.x it can take over all cases. if !@use_gvp spec_groups else @gem_version_promoter.sort_versions(dependency, spec_groups) end end end def index_for(dependency) source_for(dependency.name).specs end def source_for(name) @source_requirements[name] || @source_requirements[:default] end def results_for(dependency, base) index_for(dependency).search(dependency, base) end def name_for(dependency) dependency.name end def name_for_explicit_dependency_source Bundler.default_gemfile.basename.to_s rescue StandardError "Gemfile" end def name_for_locking_dependency_source Bundler.default_lockfile.basename.to_s rescue StandardError "Gemfile.lock" end def requirement_satisfied_by?(requirement, activated, spec) requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec) end def dependencies_equal?(dependencies, other_dependencies) dependencies.map(&:dep) == other_dependencies.map(&:dep) end def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| name = name_for(dependency) vertex = activated.vertex_named(name) [ @base_dg.vertex_named(name) ? 0 : 1, vertex.payload ? 0 : 1, vertex.root? ? 0 : 1, amount_constrained(dependency), conflicts[name] ? 0 : 1, vertex.payload ? 0 : search_for(dependency).count, self.class.platform_sort_key(dependency.__platform), ] end end def self.platform_sort_key(platform) # Prefer specific platform to not specific platform return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform ["00", *platform.to_a.map {|part| part || "" }] end private # returns an integer \in (-\infty, 0] # a number closer to 0 means the dependency is less constraining # # dependencies w/ 0 or 1 possibilities (ignoring version requirements) # are given very negative values, so they _always_ sort first, # before dependencies that are unconstrained def amount_constrained(dependency) @amount_constrained ||= {} @amount_constrained[dependency.name] ||= begin if (base = @base[dependency.name]) && !base.empty? dependency.requirement.satisfied_by?(base.first.version) ? 0 : 1 else all = index_for(dependency).search(dependency.name).size if all <= 1 all - 1_000_000 else search = search_for(dependency) search = @prerelease_specified[dependency.name] ? search.count : search.count {|s| !s.version.prerelease? } search - all end end end end def verify_gemfile_dependencies_are_found!(requirements) requirements.each do |requirement| name = requirement.name next if name == "bundler" next unless search_for(requirement).empty? cache_message = begin " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist? rescue GemfileNotFound nil end if (base = @base[name]) && !base.empty? version = base.first.version message = "You have requested:\n" \ " #{name} #{requirement.requirement}\n\n" \ "The bundle currently has #{name} locked at #{version}.\n" \ "Try running `bundle update #{name}`\n\n" \ "If you are updating multiple gems in your Gemfile at once,\n" \ "try passing them all to `bundle update`" elsif source = @source_requirements[name] specs = source.specs.search(name) versions_with_platforms = specs.map {|s| [s.version, s.platform] } message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n") message << if versions_with_platforms.any? "The source contains the following versions of '#{name}': #{formatted_versions_with_platforms(versions_with_platforms)}" else "The source does not contain any versions of '#{name}'" end else message = "Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in any of the gem sources " \ "listed in your Gemfile#{cache_message}." end raise GemNotFound, message end end def formatted_versions_with_platforms(versions_with_platforms) version_platform_strs = versions_with_platforms.map do |vwp| version = vwp.first platform = vwp.last version_platform_str = String.new(version.to_s) version_platform_str << " #{platform}" unless platform.nil? || platform == Gem::Platform::RUBY version_platform_str end version_platform_strs.join(", ") end def version_conflict_message(e) # only show essential conflicts, if possible conflicts = e.conflicts.dup if conflicts["bundler"] conflicts.replace("bundler" => conflicts["bundler"]) else conflicts.delete_if do |_name, conflict| deps = conflict.requirement_trees.map(&:last).flatten(1) !Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement))) end end e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty? solver_name = "Bundler" possibility_type = "gem" e.message_with_trees( :solver_name => solver_name, :possibility_type => possibility_type, :reduce_trees => lambda do |trees| # called first, because we want to reduce the amount of work required to find maximal empty sets trees = trees.uniq {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } } # bail out if tree size is too big for Array#combination to make any sense return trees if trees.size > 15 maximal = 1.upto(trees.size).map do |size| trees.map(&:last).flatten(1).combination(size).to_a end.flatten(1).select do |deps| Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement))) end.min_by(&:size) trees.reject! {|t| !maximal.include?(t.last) } if maximal trees.sort_by {|t| t.reverse.map(&:name) } end, :printable_requirement => lambda {|req| SharedHelpers.pretty_dependency(req) }, :additional_message_for_conflict => lambda do |o, name, conflict| if name == "bundler" o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION})) conflict_dependency = conflict.requirement conflict_requirement = conflict_dependency.requirement other_bundler_required = !conflict_requirement.satisfied_by?(Gem::Version.new(Bundler::VERSION)) if other_bundler_required o << "\n\n" candidate_specs = source_for(:default_bundler).specs.search(conflict_dependency) if candidate_specs.any? target_version = candidate_specs.last.version new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ") o << "Your bundle requires a different version of Bundler than the one you're running.\n" o << "Install the necessary version with `gem install bundler:#{target_version}` and rerun bundler using `#{new_command}`\n" else o << "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n" end end elsif conflict.locked_requirement o << "\n" o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n) o << %(the gems in your Gemfile, which may resolve the conflict.\n) elsif !conflict.existing o << "\n" relevant_source = conflict.requirement.source || source_for(name) metadata_requirement = name.end_with?("\0") o << "Could not find gem '" unless metadata_requirement o << SharedHelpers.pretty_dependency(conflict.requirement) o << "'" unless metadata_requirement if conflict.requirement_trees.first.size > 1 o << ", which is required by " o << "gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}'," end o << " " o << if metadata_requirement "is not available in #{relevant_source}" else "in #{relevant_source}.\n" end end end, :version_for_spec => lambda {|spec| spec.version }, :incompatible_version_message_for_conflict => lambda do |name, _conflict| if name.end_with?("\0") %(#{solver_name} found conflicting requirements for the #{name} version:) else %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":) end end ) end end end PK ]ω~%%-gems/bundler-2.2.24/lib/bundler/dependency.rbnu[# frozen_string_literal: true require "rubygems/dependency" require_relative "shared_helpers" require_relative "rubygems_ext" module Bundler class Dependency < Gem::Dependency attr_reader :autorequire attr_reader :groups, :platforms, :gemfile, :git, :branch PLATFORM_MAP = { :ruby => Gem::Platform::RUBY, :ruby_18 => Gem::Platform::RUBY, :ruby_19 => Gem::Platform::RUBY, :ruby_20 => Gem::Platform::RUBY, :ruby_21 => Gem::Platform::RUBY, :ruby_22 => Gem::Platform::RUBY, :ruby_23 => Gem::Platform::RUBY, :ruby_24 => Gem::Platform::RUBY, :ruby_25 => Gem::Platform::RUBY, :ruby_26 => Gem::Platform::RUBY, :mri => Gem::Platform::RUBY, :mri_18 => Gem::Platform::RUBY, :mri_19 => Gem::Platform::RUBY, :mri_20 => Gem::Platform::RUBY, :mri_21 => Gem::Platform::RUBY, :mri_22 => Gem::Platform::RUBY, :mri_23 => Gem::Platform::RUBY, :mri_24 => Gem::Platform::RUBY, :mri_25 => Gem::Platform::RUBY, :mri_26 => Gem::Platform::RUBY, :rbx => Gem::Platform::RUBY, :truffleruby => Gem::Platform::RUBY, :jruby => Gem::Platform::JAVA, :jruby_18 => Gem::Platform::JAVA, :jruby_19 => Gem::Platform::JAVA, :mswin => Gem::Platform::MSWIN, :mswin_18 => Gem::Platform::MSWIN, :mswin_19 => Gem::Platform::MSWIN, :mswin_20 => Gem::Platform::MSWIN, :mswin_21 => Gem::Platform::MSWIN, :mswin_22 => Gem::Platform::MSWIN, :mswin_23 => Gem::Platform::MSWIN, :mswin_24 => Gem::Platform::MSWIN, :mswin_25 => Gem::Platform::MSWIN, :mswin_26 => Gem::Platform::MSWIN, :mswin64 => Gem::Platform::MSWIN64, :mswin64_19 => Gem::Platform::MSWIN64, :mswin64_20 => Gem::Platform::MSWIN64, :mswin64_21 => Gem::Platform::MSWIN64, :mswin64_22 => Gem::Platform::MSWIN64, :mswin64_23 => Gem::Platform::MSWIN64, :mswin64_24 => Gem::Platform::MSWIN64, :mswin64_25 => Gem::Platform::MSWIN64, :mswin64_26 => Gem::Platform::MSWIN64, :mingw => Gem::Platform::MINGW, :mingw_18 => Gem::Platform::MINGW, :mingw_19 => Gem::Platform::MINGW, :mingw_20 => Gem::Platform::MINGW, :mingw_21 => Gem::Platform::MINGW, :mingw_22 => Gem::Platform::MINGW, :mingw_23 => Gem::Platform::MINGW, :mingw_24 => Gem::Platform::MINGW, :mingw_25 => Gem::Platform::MINGW, :mingw_26 => Gem::Platform::MINGW, :x64_mingw => Gem::Platform::X64_MINGW, :x64_mingw_20 => Gem::Platform::X64_MINGW, :x64_mingw_21 => Gem::Platform::X64_MINGW, :x64_mingw_22 => Gem::Platform::X64_MINGW, :x64_mingw_23 => Gem::Platform::X64_MINGW, :x64_mingw_24 => Gem::Platform::X64_MINGW, :x64_mingw_25 => Gem::Platform::X64_MINGW, :x64_mingw_26 => Gem::Platform::X64_MINGW, }.freeze def initialize(name, version, options = {}, &blk) type = options["type"] || :runtime super(name, version, type) @autorequire = nil @groups = Array(options["group"] || :default).map(&:to_sym) @source = options["source"] @git = options["git"] @branch = options["branch"] @platforms = Array(options["platforms"]) @env = options["env"] @should_include = options.fetch("should_include", true) @gemfile = options["gemfile"] @autorequire = Array(options["require"] || []) if options.key?("require") end # Returns the platforms this dependency is valid for, in the same order as # passed in the `valid_platforms` parameter def gem_platforms(valid_platforms) return valid_platforms if @platforms.empty? valid_generic_platforms = valid_platforms.map {|p| [p, GemHelpers.generic(p)] }.to_h @gem_platforms ||= expanded_platforms.compact.uniq filtered_generic_platforms = valid_generic_platforms.values & @gem_platforms valid_generic_platforms.select {|_, v| filtered_generic_platforms.include?(v) }.keys end def expanded_platforms @platforms.map {|pl| PLATFORM_MAP[pl] } end def should_include? @should_include && current_env? && current_platform? end def current_env? return true unless @env if @env.is_a?(Hash) @env.all? do |key, val| ENV[key.to_s] && (val.is_a?(String) ? ENV[key.to_s] == val : ENV[key.to_s] =~ val) end else ENV[@env.to_s] end end def current_platform? return true if @platforms.empty? @platforms.any? do |p| Bundler.current_ruby.send("#{p}?") end end def to_lock out = super out << "!" if source out << "\n" end def specific? super rescue NoMethodError requirement != ">= 0" end end end PK ]N˾/gems/bundler-2.2.24/lib/bundler/process_lock.rbnu[# frozen_string_literal: true module Bundler class ProcessLock def self.lock(bundle_path = Bundler.bundle_path) lock_file_path = File.join(bundle_path, "bundler.lock") has_lock = false File.open(lock_file_path, "w") do |f| f.flock(File::LOCK_EX) has_lock = true yield f.flock(File::LOCK_UN) end rescue Errno::EACCES, Errno::ENOLCK, *[SharedHelpers.const_get_safely(:ENOTSUP, Errno)].compact # In the case the user does not have access to # create the lock file or is using NFS where # locks are not available we skip locking. yield ensure FileUtils.rm_f(lock_file_path) if has_lock end end end PK ]h -gems/bundler-2.2.24/lib/bundler/deployment.rbnu[# frozen_string_literal: true require_relative "shared_helpers" Bundler::SharedHelpers.major_deprecation 2, "Bundler no longer integrates with " \ "Capistrano, but Capistrano provides its own integration with " \ "Bundler via the capistrano-bundler gem. Use it instead." module Bundler class Deployment def self.define_task(context, task_method = :task, opts = {}) if defined?(Capistrano) && context.is_a?(Capistrano::Configuration) context_name = "capistrano" role_default = "{:except => {:no_release => true}}" error_type = ::Capistrano::CommandError else context_name = "vlad" role_default = "[:app]" error_type = ::Rake::CommandFailedError end roles = context.fetch(:bundle_roles, false) opts[:roles] = roles if roles context.send :namespace, :bundle do send :desc, <<-DESC Install the current Bundler environment. By default, gems will be \ installed to the shared/bundle path. Gems in the development and \ test group will not be installed. The install command is executed \ with the --deployment and --quiet flags. If the bundle cmd cannot \ be found then you can override the bundle_cmd variable to specify \ which one it should use. The base path to the app is fetched from \ the :latest_release variable. Set it for custom deploy layouts. You can override any of these defaults by setting the variables shown below. N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \ in your deploy.rb file. set :bundle_gemfile, "Gemfile" set :bundle_dir, File.join(fetch(:shared_path), 'bundle') set :bundle_flags, "--deployment --quiet" set :bundle_without, [:development, :test] set :bundle_with, [:mysql] set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle" set :bundle_roles, #{role_default} # e.g. [:app, :batch] DESC send task_method, :install, opts do bundle_cmd = context.fetch(:bundle_cmd, "bundle") bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet") bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), "bundle")) bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile") bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact bundle_with = [*context.fetch(:bundle_with, [])].compact app_path = context.fetch(:latest_release) if app_path.to_s.empty? raise error_type.new("Cannot detect current release path - make sure you have deployed at least once.") end args = ["--gemfile #{File.join(app_path, bundle_gemfile)}"] args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty? args << bundle_flags.to_s args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty? args << "--with #{bundle_with.join(" ")}" unless bundle_with.empty? run "cd #{app_path} && #{bundle_cmd} install #{args.join(" ")}" end end end end end PK ]aXeXX2gems/bundler-2.2.24/lib/bundler/friendly_errors.rbnu[# frozen_string_literal: true require_relative "vendored_thor" module Bundler module FriendlyErrors module_function def enable! @disabled = false end def disabled? @disabled end def disable! @disabled = true end def log_error(error) case error when YamlSyntaxError Bundler.ui.error error.message Bundler.ui.trace error.orig_exception when Dsl::DSLError, GemspecError Bundler.ui.error error.message when GemRequireError Bundler.ui.error error.message Bundler.ui.trace error.orig_exception when BundlerError Bundler.ui.error error.message, :wrap => true Bundler.ui.trace error when Thor::Error Bundler.ui.error error.message when LoadError raise error unless error.message =~ /cannot load such file -- openssl|openssl.so|libcrypto.so/ Bundler.ui.error "\nCould not load OpenSSL. #{error.class}: #{error}\n#{error.backtrace.join("\n ")}" when Interrupt Bundler.ui.error "\nQuitting..." Bundler.ui.trace error when Gem::InvalidSpecificationException Bundler.ui.error error.message, :wrap => true when SystemExit when *[defined?(Java::JavaLang::OutOfMemoryError) && Java::JavaLang::OutOfMemoryError].compact Bundler.ui.error "\nYour JVM has run out of memory, and Bundler cannot continue. " \ "You can decrease the amount of memory Bundler needs by removing gems from your Gemfile, " \ "especially large gems. (Gems can be as large as hundreds of megabytes, and Bundler has to read those files!). " \ "Alternatively, you can increase the amount of memory the JVM is able to use by running Bundler with jruby -J-Xmx1024m -S bundle (JRuby defaults to 500MB)." else request_issue_report_for(error) end end def exit_status(error) case error when BundlerError then error.status_code when Thor::Error then 15 when SystemExit then error.status else 1 end end def request_issue_report_for(e) Bundler.ui.error <<-EOS.gsub(/^ {8}/, ""), nil, nil --- ERROR REPORT TEMPLATE ------------------------------------------------------- # Error Report ## Questions Please fill out answers to these questions, it'll help us figure out why things are going wrong. - **What did you do?** I ran the command `#{$PROGRAM_NAME} #{ARGV.join(" ")}` - **What did you expect to happen?** I expected Bundler to... - **What happened instead?** Instead, what happened was... - **Have you tried any solutions posted on similar issues in our issue tracker, stack overflow, or google?** I tried... - **Have you read our issues document, https://github.com/rubygems/rubygems/blob/master/bundler/doc/contributing/ISSUES.md?** ... ## Backtrace ``` #{e.class}: #{e.message} #{e.backtrace && e.backtrace.join("\n ").chomp} ``` #{Bundler::Env.report} --- TEMPLATE END ---------------------------------------------------------------- EOS Bundler.ui.error "Unfortunately, an unexpected error occurred, and Bundler cannot continue." Bundler.ui.error <<-EOS.gsub(/^ {8}/, ""), nil, :yellow First, try this link to see if there are any existing issue reports for this error: #{issues_url(e)} If there aren't any reports for this error yet, please copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at: https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md EOS end def issues_url(exception) message = exception.message.lines.first.tr(":", " ").chomp message = message.split("-").first if exception.is_a?(Errno) require "cgi" "https://github.com/rubygems/rubygems/search?q=" \ "#{CGI.escape(message)}&type=Issues" end end def self.with_friendly_errors FriendlyErrors.enable! yield rescue SignalException raise rescue Exception => e # rubocop:disable Lint/RescueException raise if FriendlyErrors.disabled? FriendlyErrors.log_error(e) exit FriendlyErrors.exit_status(e) end end PK ]^cc.gems/bundler-2.2.24/lib/bundler/gem_helpers.rbnu[# frozen_string_literal: true module Bundler module GemHelpers GENERIC_CACHE = { Gem::Platform::RUBY => Gem::Platform::RUBY } # rubocop:disable Style/MutableConstant GENERICS = [ [Gem::Platform.new("java"), Gem::Platform.new("java")], [Gem::Platform.new("mswin32"), Gem::Platform.new("mswin32")], [Gem::Platform.new("mswin64"), Gem::Platform.new("mswin64")], [Gem::Platform.new("universal-mingw32"), Gem::Platform.new("universal-mingw32")], [Gem::Platform.new("x64-mingw32"), Gem::Platform.new("x64-mingw32")], [Gem::Platform.new("x86_64-mingw32"), Gem::Platform.new("x64-mingw32")], [Gem::Platform.new("mingw32"), Gem::Platform.new("x86-mingw32")], ].freeze def generic(p) GENERIC_CACHE[p] ||= begin _, found = GENERICS.find do |match, _generic| p.os == match.os && (!match.cpu || p.cpu == match.cpu) end found || Gem::Platform::RUBY end end module_function :generic def generic_local_platform generic(local_platform) end module_function :generic_local_platform def local_platform Bundler.local_platform end module_function :local_platform def platform_specificity_match(spec_platform, user_platform) spec_platform = Gem::Platform.new(spec_platform) PlatformMatch.specificity_score(spec_platform, user_platform) end module_function :platform_specificity_match def select_best_platform_match(specs, platform) matching = specs.select {|spec| spec.match_platform(platform) } exact = matching.select {|spec| spec.platform == platform } return exact if exact.any? sorted_matching = matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) } exemplary_spec = sorted_matching.first sorted_matching.take_while{|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) } end module_function :select_best_platform_match class PlatformMatch def self.specificity_score(spec_platform, user_platform) return -1 if spec_platform == user_platform return 1_000_000 if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY os_match(spec_platform, user_platform) + cpu_match(spec_platform, user_platform) * 10 + platform_version_match(spec_platform, user_platform) * 100 end def self.os_match(spec_platform, user_platform) if spec_platform.os == user_platform.os 0 else 1 end end def self.cpu_match(spec_platform, user_platform) if spec_platform.cpu == user_platform.cpu 0 elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm") 0 elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal" 1 else 2 end end def self.platform_version_match(spec_platform, user_platform) if spec_platform.version == user_platform.version 0 elsif spec_platform.version.nil? 1 else 2 end end end def same_specificity(platform, spec, exemplary_spec) platform_specificity_match(spec.platform, platform) == platform_specificity_match(exemplary_spec.platform, platform) end module_function :same_specificity def same_deps(spec, exemplary_spec) same_runtime_deps = spec.dependencies.sort == exemplary_spec.dependencies.sort return same_runtime_deps unless spec.is_a?(Gem::Specification) && exemplary_spec.is_a?(Gem::Specification) same_metadata_deps = spec.required_ruby_version == exemplary_spec.required_ruby_version && spec.required_rubygems_version == exemplary_spec.required_rubygems_version same_runtime_deps && same_metadata_deps end module_function :same_deps end end PK ]a! :gems/bundler-2.2.24/lib/bundler/installer/gem_installer.rbnu[# frozen_string_literal: true require "shellwords" module Bundler class GemInstaller attr_reader :spec, :standalone, :worker, :force, :installer def initialize(spec, installer, standalone = false, worker = 0, force = false) @spec = spec @installer = installer @standalone = standalone @worker = worker @force = force end def install_from_spec post_install_message = spec_settings ? install_with_settings : install Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}" generate_executable_stubs return true, post_install_message rescue Bundler::InstallHookError, Bundler::SecurityError, Bundler::APIResponseMismatchError raise rescue Errno::ENOSPC return false, out_of_space_message rescue Bundler::BundlerError, Gem::InstallError, Bundler::APIResponseInvalidDependenciesError => e return false, specific_failure_message(e) end private def specific_failure_message(e) message = "#{e.class}: #{e.message}\n" message += " " + e.backtrace.join("\n ") + "\n\n" if Bundler.ui.debug? message = message.lines.first + Bundler.ui.add_color(message.lines.drop(1).join, :clear) message + Bundler.ui.add_color(failure_message, :red) end def failure_message return install_error_message if spec.source.options["git"] "#{install_error_message}\n#{gem_install_message}" end def install_error_message "An error occurred while installing #{spec.name} (#{spec.version}), and Bundler cannot continue." end def gem_install_message source = spec.source return unless source.respond_to?(:remotes) if source.remotes.size == 1 "Make sure that `gem install #{spec.name} -v '#{spec.version}' --source '#{source.remotes.first}'` succeeds before bundling." else "Make sure that `gem install #{spec.name} -v '#{spec.version}'` succeeds before bundling." end end def spec_settings # Fetch the build settings, if there are any if settings = Bundler.settings["build.#{spec.name}"] Shellwords.shellsplit(settings) end end def install spec.source.install(spec, :force => force, :ensure_builtin_gems_cached => standalone, :build_args => Array(spec_settings)) end def install_with_settings # Build arguments are global, so this is mutexed Bundler.rubygems.install_with_build_args([spec_settings]) { install } end def out_of_space_message "#{install_error_message}\nYour disk is out of space. Free some space to be able to install your bundle." end def generate_executable_stubs return if Bundler.feature_flag.forget_cli_options? return if Bundler.settings[:inline] if Bundler.settings[:bin] && standalone installer.generate_standalone_bundler_executable_stubs(spec) elsif Bundler.settings[:bin] installer.generate_bundler_executable_stubs(spec, :force => true) end end end end PK ]y?gems/bundler-2.2.24/lib/bundler/installer/parallel_installer.rbnu[# frozen_string_literal: true require_relative "../worker" require_relative "gem_installer" module Bundler class ParallelInstaller class SpecInstallation attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error def initialize(spec) @spec = spec @name = spec.name @full_name = spec.full_name @state = :none @post_install_message = "" @error = nil end def installed? state == :installed end def enqueued? state == :enqueued end def failed? state == :failed end def ready_to_enqueue? state == :none end def has_post_install_message? !post_install_message.empty? end def ignorable_dependency?(dep) dep.type == :development || dep.name == @name end # Checks installed dependencies against spec's dependencies to make # sure needed dependencies have been installed. def dependencies_installed?(all_specs) installed_specs = all_specs.select(&:installed?).map(&:name) dependencies.all? {|d| installed_specs.include? d.name } end # Represents only the non-development dependencies, the ones that are # itself and are in the total list. def dependencies @dependencies ||= all_dependencies.reject {|dep| ignorable_dependency? dep } end def missing_lockfile_dependencies(all_spec_names) dependencies.reject {|dep| all_spec_names.include? dep.name } end # Represents all dependencies def all_dependencies @spec.dependencies end def to_s "#<#{self.class} #{full_name} (#{state})>" end end def self.call(*args) new(*args).call end attr_reader :size def initialize(installer, all_specs, size, standalone, force) @installer = installer @size = size @standalone = standalone @force = force @specs = all_specs.map {|s| SpecInstallation.new(s) } @spec_set = all_specs @rake = @specs.find {|s| s.name == "rake" } end def call check_for_corrupt_lockfile if @rake do_install(@rake, 0) Gem::Specification.reset end if @size > 1 install_with_worker else install_serially end check_for_unmet_dependencies handle_error if failed_specs.any? @specs ensure worker_pool && worker_pool.stop end def check_for_unmet_dependencies unmet_dependencies = @specs.map do |s| [ s, s.dependencies.reject {|dep| @specs.any? {|spec| dep.matches_spec?(spec.spec) } }, ] end.reject {|a| a.last.empty? } return if unmet_dependencies.empty? warning = [] warning << "Your lockfile doesn't include a valid resolution." warning << "You can fix this by regenerating your lockfile or trying to manually editing the bad locked gems to a version that satisfies all dependencies." warning << "The unmet dependencies are:" unmet_dependencies.each do |spec, unmet_spec_dependencies| unmet_spec_dependencies.each do |unmet_spec_dependency| warning << "* #{unmet_spec_dependency}, depended upon #{spec.full_name}, unsatisfied by #{@specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) }.full_name}" end end Bundler.ui.warn(warning.join("\n")) end def check_for_corrupt_lockfile missing_dependencies = @specs.map do |s| [ s, s.missing_lockfile_dependencies(@specs.map(&:name)), ] end.reject {|a| a.last.empty? } return if missing_dependencies.empty? warning = [] warning << "Your lockfile was created by an old Bundler that left some things out." if @size != 1 warning << "Because of the missing DEPENDENCIES, we can only install gems one at a time, instead of installing #{@size} at a time." @size = 1 end warning << "You can fix this by adding the missing gems to your Gemfile, running bundle install, and then removing the gems from your Gemfile." warning << "The missing gems are:" missing_dependencies.each do |spec, missing| warning << "* #{missing.map(&:name).join(", ")} depended upon by #{spec.name}" end Bundler.ui.warn(warning.join("\n")) end private def failed_specs @specs.select(&:failed?) end def install_with_worker enqueue_specs process_specs until finished_installing? end def install_serially until finished_installing? raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?) spec_install.state = :enqueued do_install(spec_install, 0) end end def worker_pool @worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda {|spec_install, worker_num| do_install(spec_install, worker_num) } end def do_install(spec_install, worker_num) Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install) gem_installer = Bundler::GemInstaller.new( spec_install.spec, @installer, @standalone, worker_num, @force ) success, message = gem_installer.install_from_spec if success spec_install.state = :installed spec_install.post_install_message = message unless message.nil? else spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}" spec_install.state = :failed end Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL, spec_install) spec_install end # Dequeue a spec and save its post-install message and then enqueue the # remaining specs. # Some specs might've had to wait til this spec was installed to be # processed so the call to `enqueue_specs` is important after every # dequeue. def process_specs worker_pool.deq enqueue_specs end def finished_installing? @specs.all? do |spec| return true if spec.failed? spec.installed? end end def handle_error errors = failed_specs.map(&:error) if exception = errors.find {|e| e.is_a?(Bundler::BundlerError) } raise exception end raise Bundler::InstallError, errors.join("\n\n") end def require_tree_for_spec(spec) tree = @spec_set.what_required(spec) t = String.new("In #{File.basename(SharedHelpers.default_gemfile)}:\n") tree.each_with_index do |s, depth| t << " " * depth.succ << s.name unless tree.last == s t << %( was resolved to #{s.version}, which depends on) end t << %(\n) end t end # Keys in the remains hash represent uninstalled gems specs. # We enqueue all gem specs that do not have any dependencies. # Later we call this lambda again to install specs that depended on # previously installed specifications. We continue until all specs # are installed. def enqueue_specs @specs.select(&:ready_to_enqueue?).each do |spec| if spec.dependencies_installed? @specs spec.state = :enqueued worker_pool.enq spec end end end end end PK ]{sEjj7gems/bundler-2.2.24/lib/bundler/installer/standalone.rbnu[# frozen_string_literal: true module Bundler class Standalone def initialize(groups, definition) @specs = definition.specs_for(groups) end def generate SharedHelpers.filesystem_access(bundler_path) do |p| FileUtils.mkdir_p(p) end File.open File.join(bundler_path, "setup.rb"), "w" do |file| file.puts "require 'rbconfig'" file.puts "ruby_engine = RUBY_ENGINE" file.puts "ruby_version = RbConfig::CONFIG[\"ruby_version\"]" file.puts "path = File.expand_path('..', __FILE__)" file.puts reverse_rubygems_kernel_mixin paths.each do |path| file.puts %($:.unshift File.expand_path("\#{path}/#{path}")) end end end private def paths @specs.map do |spec| next if spec.name == "bundler" Array(spec.require_paths).map do |path| gem_path(path, spec).sub(version_dir, '#{ruby_engine}/#{ruby_version}') # This is a static string intentionally. It's interpolated at a later time. end end.flatten end def version_dir "#{Bundler::RubyVersion.system.engine}/#{RbConfig::CONFIG["ruby_version"]}" end def bundler_path Bundler.root.join(Bundler.settings[:path], "bundler") end def gem_path(path, spec) full_path = Pathname.new(path).absolute? ? path : File.join(spec.full_gem_path, path) Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s rescue TypeError error_message = "#{spec.name} #{spec.version} has an invalid gemspec" raise Gem::InvalidSpecificationException.new(error_message) end def reverse_rubygems_kernel_mixin <<~END kernel = (class << ::Kernel; self; end) [kernel, ::Kernel].each do |k| if k.private_method_defined?(:gem_original_require) private_require = k.private_method_defined?(:require) k.send(:remove_method, :require) k.send(:define_method, :require, k.instance_method(:gem_original_require)) k.send(:private, :require) if private_require end end END end end end PK ]3dMM3gems/bundler-2.2.24/lib/bundler/man/bundle-remove.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-REMOVE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile . .SH "SYNOPSIS" \fBbundle remove [GEM [GEM \.\.\.]] [\-\-install]\fR . .SH "DESCRIPTION" Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid\. If a gem cannot be removed, a warning is printed\. If a gem is already absent from the Gemfile, and error is raised\. . .SH "OPTIONS" . .TP \fB\-\-install\fR Runs \fBbundle install\fR after the given gems have been removed from the Gemfile, which ensures that both the lockfile and the installed gems on disk are also updated to remove the given gem(s)\. . .P Example: . .P bundle remove rails . .P bundle remove rails rack . .P bundle remove rails rack \-\-install PK ])&LYY7gems/bundler-2.2.24/lib/bundler/man/bundle-check.1.ronnnu[bundle-check(1) -- Verifies if dependencies are satisfied by installed gems =========================================================================== ## SYNOPSIS `bundle check` [--dry-run] [--gemfile=FILE] [--path=PATH] ## DESCRIPTION `check` searches the local machine for each of the gems requested in the Gemfile. If all gems are found, Bundler prints a success message and exits with a status of 0. If not, the first missing gem is listed and Bundler exits status 1. ## OPTIONS * `--dry-run`: Locks the [`Gemfile(5)`][Gemfile(5)] before running the command. * `--gemfile`: Use the specified gemfile instead of the [`Gemfile(5)`][Gemfile(5)]. * `--path`: Specify a different path than the system default (`$BUNDLE_PATH` or `$GEM_HOME`). Bundler will remember this value for future installs on this machine. PK ](V5gems/bundler-2.2.24/lib/bundler/man/bundle-viz.1.ronnnu[bundle-viz(1) -- Generates a visual dependency graph for your Gemfile ===================================================================== ## SYNOPSIS `bundle viz` [--file=FILE] [--format=FORMAT] [--requirements] [--version] [--without=GROUP GROUP] ## DESCRIPTION `viz` generates a PNG file of the current `Gemfile(5)` as a dependency graph. `viz` requires the ruby-graphviz gem (and its dependencies). The associated gems must also be installed via [`bundle install(1)`](bundle-install.1.html). ## OPTIONS * `--file`, `-f`: The name to use for the generated file. See `--format` option * `--format`, `-F`: This is output format option. Supported format is png, jpg, svg, dot ... * `--requirements`, `-R`: Set to show the version of each required dependency. * `--version`, `-v`: Set to show each gem version. * `--without`, `-W`: Exclude gems that are part of the specified named group. PK ];76763gems/bundler-2.2.24/lib/bundler/man/bundle-update.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-UPDATE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions . .SH "SYNOPSIS" \fBbundle update\fR \fI*gems\fR [\-\-all] [\-\-group=NAME] [\-\-source=NAME] [\-\-local] [\-\-ruby] [\-\-bundler[=VERSION]] [\-\-full\-index] [\-\-jobs=JOBS] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-redownload] [\-\-strict] [\-\-conservative] . .SH "DESCRIPTION" Update the gems specified (all gems, if \fB\-\-all\fR flag is used), ignoring the previously installed gems specified in the \fBGemfile\.lock\fR\. In general, you should use bundle install(1) \fIbundle\-install\.1\.html\fR to install the same exact gems and versions across machines\. . .P You would use \fBbundle update\fR to explicitly update the version of a gem\. . .SH "OPTIONS" . .TP \fB\-\-all\fR Update all gems specified in Gemfile\. . .TP \fB\-\-group=\fR, \fB\-g=[]\fR Only update the gems in the specified group\. For instance, you can update all gems in the development group with \fBbundle update \-\-group development\fR\. You can also call \fBbundle update rails \-\-group test\fR to update the rails gem and all gems in the test group, for example\. . .TP \fB\-\-source=\fR The name of a \fB:git\fR or \fB:path\fR source used in the Gemfile(5)\. For instance, with a \fB:git\fR source of \fBhttp://github\.com/rails/rails\.git\fR, you would call \fBbundle update \-\-source rails\fR . .TP \fB\-\-local\fR Do not attempt to fetch gems remotely and use the gem cache instead\. . .TP \fB\-\-ruby\fR Update the locked version of Ruby to the current version of Ruby\. . .TP \fB\-\-bundler\fR Update the locked version of bundler to the invoked bundler version\. . .TP \fB\-\-full\-index\fR Fall back to using the single\-file index of all gems\. . .TP \fB\-\-jobs=[]\fR, \fB\-j[]\fR Specify the number of jobs to run in parallel\. The default is \fB1\fR\. . .TP \fB\-\-retry=[]\fR Retry failed network or git requests for \fInumber\fR times\. . .TP \fB\-\-quiet\fR Only output warnings and errors\. . .TP \fB\-\-redownload\fR Force downloading every gem\. . .TP \fB\-\-patch\fR Prefer updating only to next patch version\. . .TP \fB\-\-minor\fR Prefer updating only to next minor version\. . .TP \fB\-\-major\fR Prefer updating to next major version (default)\. . .TP \fB\-\-strict\fR Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\. . .TP \fB\-\-conservative\fR Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\. . .SH "UPDATING ALL GEMS" If you run \fBbundle update \-\-all\fR, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. . .P Consider the following Gemfile(5): . .IP "" 4 . .nf source "https://rubygems\.org" gem "rails", "3\.0\.0\.rc" gem "nokogiri" . .fi . .IP "" 0 . .P When you run bundle install(1) \fIbundle\-install\.1\.html\fR the first time, bundler will resolve all of the dependencies, all the way down, and install what you need: . .IP "" 4 . .nf Fetching gem metadata from https://rubygems\.org/\.\.\.\.\.\.\.\.\. Resolving dependencies\.\.\. Installing builder 2\.1\.2 Installing abstract 1\.0\.0 Installing rack 1\.2\.8 Using bundler 1\.7\.6 Installing rake 10\.4\.0 Installing polyglot 0\.3\.5 Installing mime\-types 1\.25\.1 Installing i18n 0\.4\.2 Installing mini_portile 0\.6\.1 Installing tzinfo 0\.3\.42 Installing rack\-mount 0\.6\.14 Installing rack\-test 0\.5\.7 Installing treetop 1\.4\.15 Installing thor 0\.14\.6 Installing activesupport 3\.0\.0\.rc Installing erubis 2\.6\.6 Installing activemodel 3\.0\.0\.rc Installing arel 0\.4\.0 Installing mail 2\.2\.20 Installing activeresource 3\.0\.0\.rc Installing actionpack 3\.0\.0\.rc Installing activerecord 3\.0\.0\.rc Installing actionmailer 3\.0\.0\.rc Installing railties 3\.0\.0\.rc Installing rails 3\.0\.0\.rc Installing nokogiri 1\.6\.5 Bundle complete! 2 Gemfile dependencies, 26 gems total\. Use `bundle show [gemname]` to see where a bundled gem is installed\. . .fi . .IP "" 0 . .P As you can see, even though you have two gems in the Gemfile(5), your application needs 26 different gems in order to run\. Bundler remembers the exact versions it installed in \fBGemfile\.lock\fR\. The next time you run bundle install(1) \fIbundle\-install\.1\.html\fR, bundler skips the dependency resolution and installs the same gems as it installed last time\. . .P After checking in the \fBGemfile\.lock\fR into version control and cloning it on another machine, running bundle install(1) \fIbundle\-install\.1\.html\fR will \fIstill\fR install the gems that you installed last time\. You don\'t need to worry that a new release of \fBerubis\fR or \fBmail\fR changes the gems you use\. . .P However, from time to time, you might want to update the gems you are using to the newest versions that still match the gems in your Gemfile(5)\. . .P To do this, run \fBbundle update \-\-all\fR, which will ignore the \fBGemfile\.lock\fR, and resolve all the dependencies again\. Keep in mind that this process can result in a significantly different set of the 25 gems, based on the requirements of new gems that the gem authors released since the last time you ran \fBbundle update \-\-all\fR\. . .SH "UPDATING A LIST OF GEMS" Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. . .P For instance, in the scenario above, imagine that \fBnokogiri\fR releases version \fB1\.4\.4\fR, and you want to update it \fIwithout\fR updating Rails and all of its dependencies\. To do this, run \fBbundle update nokogiri\fR\. . .P Bundler will update \fBnokogiri\fR and any of its dependencies, but leave alone Rails and its dependencies\. . .SH "OVERLAPPING DEPENDENCIES" Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same second\-level dependency\. For instance, consider the case of \fBthin\fR and \fBrack\-perftools\-profiler\fR\. . .IP "" 4 . .nf source "https://rubygems\.org" gem "thin" gem "rack\-perftools\-profiler" . .fi . .IP "" 0 . .P The \fBthin\fR gem depends on \fBrack >= 1\.0\fR, while \fBrack\-perftools\-profiler\fR depends on \fBrack ~> 1\.0\fR\. If you run bundle install, you get: . .IP "" 4 . .nf Fetching source index for https://rubygems\.org/ Installing daemons (1\.1\.0) Installing eventmachine (0\.12\.10) with native extensions Installing open4 (1\.0\.1) Installing perftools\.rb (0\.4\.7) with native extensions Installing rack (1\.2\.1) Installing rack\-perftools_profiler (0\.0\.2) Installing thin (1\.2\.7) with native extensions Using bundler (1\.0\.0\.rc\.3) . .fi . .IP "" 0 . .P In this case, the two gems have their own set of dependencies, but they share \fBrack\fR in common\. If you run \fBbundle update thin\fR, bundler will update \fBdaemons\fR, \fBeventmachine\fR and \fBrack\fR, which are dependencies of \fBthin\fR, but not \fBopen4\fR or \fBperftools\.rb\fR, which are dependencies of \fBrack\-perftools_profiler\fR\. Note that \fBbundle update thin\fR will update \fBrack\fR even though it\'s \fIalso\fR a dependency of \fBrack\-perftools_profiler\fR\. . .P In short, by default, when you update a gem using \fBbundle update\fR, bundler will update all dependencies of that gem, including those that are also dependencies of another gem\. . .P To prevent updating indirect dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR: . .P In this scenario, updating the \fBthin\fR version manually in the Gemfile(5), and then running bundle install(1) \fIbundle\-install\.1\.html\fR will only update \fBdaemons\fR and \fBeventmachine\fR, but not \fBrack\fR\. For more information, see the \fBCONSERVATIVE UPDATING\fR section of bundle install(1) \fIbundle\-install\.1\.html\fR\. . .P Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent indirect dependencies from being updated\. . .SH "PATCH LEVEL OPTIONS" Version 1\.14 introduced 4 patch\-level options that will influence how gem versions are resolved\. One of the following options can be used: \fB\-\-patch\fR, \fB\-\-minor\fR or \fB\-\-major\fR\. \fB\-\-strict\fR can be added to further influence resolution\. . .TP \fB\-\-patch\fR Prefer updating only to next patch version\. . .TP \fB\-\-minor\fR Prefer updating only to next minor version\. . .TP \fB\-\-major\fR Prefer updating to next major version (default)\. . .TP \fB\-\-strict\fR Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\. . .P When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don\'t satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order\. . .P Providing one of the patch level options (e\.g\. \fB\-\-patch\fR) changes the sort order of the satisfying versions, causing Bundler to consider the latest \fB\-\-patch\fR or \fB\-\-minor\fR version available before other versions\. Note that versions outside the stated patch level could still be resolved to if necessary to find a suitable dependency graph\. . .P For example, if gem \'foo\' is locked at 1\.0\.2, with no gem requirement defined in the Gemfile, and versions 1\.0\.3, 1\.0\.4, 1\.1\.0, 1\.1\.1, 2\.0\.0 all exist, the default order of preference by default (\fB\-\-major\fR) will be "2\.0\.0, 1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\. . .P If the \fB\-\-patch\fR option is used, the order of preference will change to "1\.0\.4, 1\.0\.3, 1\.0\.2, 1\.1\.1, 1\.1\.0, 2\.0\.0"\. . .P If the \fB\-\-minor\fR option is used, the order of preference will change to "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2, 2\.0\.0"\. . .P Combining the \fB\-\-strict\fR option with any of the patch level options will remove any versions beyond the scope of the patch level option, to ensure that no gem is updated that far\. . .P To continue the previous example, if both \fB\-\-patch\fR and \fB\-\-strict\fR options are used, the available versions for resolution would be "1\.0\.4, 1\.0\.3, 1\.0\.2"\. If \fB\-\-minor\fR and \fB\-\-strict\fR are used, it would be "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\. . .P Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available\. If the gem requirement for \fBfoo\fR in the Gemfile is \'~> 1\.0\', that will accomplish the same thing as providing the \fB\-\-minor\fR and \fB\-\-strict\fR options\. . .SH "PATCH LEVEL EXAMPLES" Given the following gem specifications: . .IP "" 4 . .nf foo 1\.4\.3, requires: ~> bar 2\.0 foo 1\.4\.4, requires: ~> bar 2\.0 foo 1\.4\.5, requires: ~> bar 2\.1 foo 1\.5\.0, requires: ~> bar 2\.1 foo 1\.5\.1, requires: ~> bar 3\.0 bar with versions 2\.0\.3, 2\.0\.4, 2\.1\.0, 2\.1\.1, 3\.0\.0 . .fi . .IP "" 0 . .P Gemfile: . .IP "" 4 . .nf gem \'foo\' . .fi . .IP "" 0 . .P Gemfile\.lock: . .IP "" 4 . .nf foo (1\.4\.3) bar (~> 2\.0) bar (2\.0\.3) . .fi . .IP "" 0 . .P Cases: . .IP "" 4 . .nf # Command Line Result \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- 1 bundle update \-\-patch \'foo 1\.4\.5\', \'bar 2\.1\.1\' 2 bundle update \-\-patch foo \'foo 1\.4\.5\', \'bar 2\.1\.1\' 3 bundle update \-\-minor \'foo 1\.5\.1\', \'bar 3\.0\.0\' 4 bundle update \-\-minor \-\-strict \'foo 1\.5\.0\', \'bar 2\.1\.1\' 5 bundle update \-\-patch \-\-strict \'foo 1\.4\.4\', \'bar 2\.0\.4\' . .fi . .IP "" 0 . .P In case 1, bar is upgraded to 2\.1\.1, a minor version increase, because the dependency from foo 1\.4\.5 required it\. . .P In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it\'s not a declared dependency in the Gemfile\. . .P In case 3, bar goes up a whole major release, because a minor increase is preferred now for foo, and when it goes to 1\.5\.1, it requires 3\.0\.0 of bar\. . .P In case 4, foo is preferred up to a minor version, but 1\.5\.1 won\'t work because the \-\-strict flag removes bar 3\.0\.0 from consideration since it\'s a major increment\. . .P In case 5, both foo and bar have any minor or major increments removed from consideration because of the \-\-strict flag, so the most they can move is up to 1\.4\.4 and 2\.0\.4\. . .SH "RECOMMENDED WORKFLOW" In general, when working with an application managed with bundler, you should use the following workflow: . .IP "\(bu" 4 After you create your Gemfile(5) for the first time, run . .IP $ bundle install . .IP "\(bu" 4 Check the resulting \fBGemfile\.lock\fR into version control . .IP $ git add Gemfile\.lock . .IP "\(bu" 4 When checking out this repository on another development machine, run . .IP $ bundle install . .IP "\(bu" 4 When checking out this repository on a deployment machine, run . .IP $ bundle install \-\-deployment . .IP "\(bu" 4 After changing the Gemfile(5) to reflect a new or update dependency, run . .IP $ bundle install . .IP "\(bu" 4 Make sure to check the updated \fBGemfile\.lock\fR into version control . .IP $ git add Gemfile\.lock . .IP "\(bu" 4 If bundle install(1) \fIbundle\-install\.1\.html\fR reports a conflict, manually update the specific gems that you changed in the Gemfile(5) . .IP $ bundle update rails thin . .IP "\(bu" 4 If you want to update all the gems to the latest possible versions that still match the gems listed in the Gemfile(5), run . .IP $ bundle update \-\-all . .IP "" 0 PK ]MM0gems/bundler-2.2.24/lib/bundler/man/bundle-viz.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-VIZ" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile . .SH "SYNOPSIS" \fBbundle viz\fR [\-\-file=FILE] [\-\-format=FORMAT] [\-\-requirements] [\-\-version] [\-\-without=GROUP GROUP] . .SH "DESCRIPTION" \fBviz\fR generates a PNG file of the current \fBGemfile(5)\fR as a dependency graph\. \fBviz\fR requires the ruby\-graphviz gem (and its dependencies)\. . .P The associated gems must also be installed via \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR\. . .SH "OPTIONS" . .TP \fB\-\-file\fR, \fB\-f\fR The name to use for the generated file\. See \fB\-\-format\fR option . .TP \fB\-\-format\fR, \fB\-F\fR This is output format option\. Supported format is png, jpg, svg, dot \.\.\. . .TP \fB\-\-requirements\fR, \fB\-R\fR Set to show the version of each required dependency\. . .TP \fB\-\-version\fR, \fB\-v\fR Set to show each gem version\. . .TP \fB\-\-without\fR, \fB\-W\fR Exclude gems that are part of the specified named group\. PK ]l47gems/bundler-2.2.24/lib/bundler/man/bundle-clean.1.ronnnu[bundle-clean(1) -- Cleans up unused gems in your bundler directory ================================================================== ## SYNOPSIS `bundle clean` [--dry-run] [--force] ## DESCRIPTION This command will remove all unused gems in your bundler directory. This is useful when you have made many changes to your gem dependencies. ## OPTIONS * `--dry-run`: Print the changes, but do not clean the unused gems. * `--force`: Force a clean even if `--path` is not set. PK ]k  7gems/bundler-2.2.24/lib/bundler/man/bundle-cache.1.ronnnu[bundle-cache(1) -- Package your needed `.gem` files into your application =========================================================================== ## SYNOPSIS `bundle cache` ## DESCRIPTION Copy all of the `.gem` files needed to run the application into the `vendor/cache` directory. In the future, when running [bundle install(1)][bundle-install], use the gems in the cache in preference to the ones on `rubygems.org`. ## GIT AND PATH GEMS The `bundle cache` command can also package `:git` and `:path` dependencies besides .gem files. This needs to be explicitly enabled via the `--all` option. Once used, the `--all` option will be remembered. ## SUPPORT FOR MULTIPLE PLATFORMS When using gems that have different packages for different platforms, Bundler supports caching of gems for other platforms where the Gemfile has been resolved (i.e. present in the lockfile) in `vendor/cache`. This needs to be enabled via the `--all-platforms` option. This setting will be remembered in your local bundler configuration. ## REMOTE FETCHING By default, if you run `bundle install(1)`](bundle-install.1.html) after running [bundle cache(1)](bundle-cache.1.html), bundler will still connect to `rubygems.org` to check whether a platform-specific gem exists for any of the gems in `vendor/cache`. For instance, consider this Gemfile(5): source "https://rubygems.org" gem "nokogiri" If you run `bundle cache` under C Ruby, bundler will retrieve the version of `nokogiri` for the `"ruby"` platform. If you deploy to JRuby and run `bundle install`, bundler is forced to check to see whether a `"java"` platformed `nokogiri` exists. Even though the `nokogiri` gem for the Ruby platform is _technically_ acceptable on JRuby, it has a C extension that does not run on JRuby. As a result, bundler will, by default, still connect to `rubygems.org` to check whether it has a version of one of your gems more specific to your platform. This problem is also not limited to the `"java"` platform. A similar (common) problem can happen when developing on Windows and deploying to Linux, or even when developing on OSX and deploying to Linux. If you know for sure that the gems packaged in `vendor/cache` are appropriate for the platform you are on, you can run `bundle install --local` to skip checking for more appropriate gems, and use the ones in `vendor/cache`. One way to be sure that you have the right platformed versions of all your gems is to run `bundle cache` on an identical machine and check in the gems. For instance, you can run `bundle cache` on an identical staging box during your staging process, and check in the `vendor/cache` before deploying to production. By default, [bundle cache(1)](bundle-cache.1.html) fetches and also installs the gems to the default location. To package the dependencies to `vendor/cache` without installing them to the local install location, you can run `bundle cache --no-install`. PK ]&0gems/bundler-2.2.24/lib/bundler/man/bundle-add.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-ADD" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install . .SH "SYNOPSIS" \fBbundle add\fR \fIGEM_NAME\fR [\-\-group=GROUP] [\-\-version=VERSION] [\-\-source=SOURCE] [\-\-git=GIT] [\-\-branch=BRANCH] [\-\-skip\-install] [\-\-strict] [\-\-optimistic] . .SH "DESCRIPTION" Adds the named gem to the Gemfile and run \fBbundle install\fR\. \fBbundle install\fR can be avoided by using the flag \fB\-\-skip\-install\fR\. . .P Example: . .P bundle add rails . .P bundle add rails \-\-version "< 3\.0, > 1\.1" . .P bundle add rails \-\-version "~> 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development" . .P bundle add rails \-\-skip\-install . .P bundle add rails \-\-group "development, test" . .SH "OPTIONS" . .TP \fB\-\-version\fR, \fB\-v\fR Specify version requirements(s) for the added gem\. . .TP \fB\-\-group\fR, \fB\-g\fR Specify the group(s) for the added gem\. Multiple groups should be separated by commas\. . .TP \fB\-\-source\fR, , \fB\-s\fR Specify the source for the added gem\. . .TP \fB\-\-git\fR Specify the git source for the added gem\. . .TP \fB\-\-branch\fR Specify the git branch for the added gem\. . .TP \fB\-\-skip\-install\fR Adds the gem to the Gemfile but does not install it\. . .TP \fB\-\-optimistic\fR Adds optimistic declaration of version . .TP \fB\-\-strict\fR Adds strict declaration of version PK ]H1gems/bundler-2.2.24/lib/bundler/man/bundle-show.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-SHOW" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem . .SH "SYNOPSIS" \fBbundle show\fR [GEM] [\-\-paths] . .SH "DESCRIPTION" Without the [GEM] option, \fBshow\fR will print a list of the names and versions of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by name\. . .P Calling show with [GEM] will list the exact location of that gem on your machine\. . .SH "OPTIONS" . .TP \fB\-\-paths\fR List the paths of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by gem name\. PK ]B5UU8gems/bundler-2.2.24/lib/bundler/man/bundle-inject.1.ronnnu[bundle-inject(1) -- Add named gem(s) with version requirements to Gemfile ========================================================================= ## SYNOPSIS `bundle inject` [GEM] [VERSION] ## DESCRIPTION Adds the named gem(s) with their version requirements to the resolved [`Gemfile(5)`][Gemfile(5)]. This command will add the gem to both your [`Gemfile(5)`][Gemfile(5)] and Gemfile.lock if it isn't listed yet. Example: bundle install bundle inject 'rack' '> 0' This will inject the 'rack' gem with a version greater than 0 in your [`Gemfile(5)`][Gemfile(5)] and Gemfile.lock PK ]$3gems/bundler-2.2.24/lib/bundler/man/bundle-doctor.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-DOCTOR" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems . .SH "SYNOPSIS" \fBbundle doctor\fR [\-\-quiet] [\-\-gemfile=GEMFILE] . .SH "DESCRIPTION" Checks your Gemfile and gem environment for common problems\. If issues are detected, Bundler prints them and exits status 1\. Otherwise, Bundler prints a success message and exits status 0\. . .P Examples of common problems caught by bundle\-doctor include: . .IP "\(bu" 4 Invalid Bundler settings . .IP "\(bu" 4 Mismatched Ruby versions . .IP "\(bu" 4 Mismatched platforms . .IP "\(bu" 4 Uninstalled gems . .IP "\(bu" 4 Missing dependencies . .IP "" 0 . .SH "OPTIONS" . .TP \fB\-\-quiet\fR Only output warnings and errors\. . .TP \fB\-\-gemfile=\fR The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project\'s root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\. PK ]9IG 6gems/bundler-2.2.24/lib/bundler/man/bundle-lock.1.ronnnu[bundle-lock(1) -- Creates / Updates a lockfile without installing ================================================================= ## SYNOPSIS `bundle lock` [--update] [--local] [--print] [--lockfile=PATH] [--full-index] [--add-platform] [--remove-platform] [--patch] [--minor] [--major] [--strict] [--conservative] ## DESCRIPTION Lock the gems specified in Gemfile. ## OPTIONS * `--update=<*gems>`: Ignores the existing lockfile. Resolve then updates lockfile. Taking a list of gems or updating all gems if no list is given. * `--local`: Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the gems already present in Rubygems' cache or in `vendor/cache`. Note that if a appropriate platform-specific gem exists on `rubygems.org` it will not be found. * `--print`: Prints the lockfile to STDOUT instead of writing to the file system. * `--lockfile=`: The path where the lockfile should be written to. * `--full-index`: Fall back to using the single-file index of all gems. * `--add-platform`: Add a new platform to the lockfile, re-resolving for the addition of that platform. * `--remove-platform`: Remove a platform from the lockfile. * `--patch`: If updating, prefer updating only to next patch version. * `--minor`: If updating, prefer updating only to next minor version. * `--major`: If updating, prefer updating to next major version (default). * `--strict`: If updating, do not allow any gem to be updated past latest --patch | --minor | --major. * `--conservative`: If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated. ## UPDATING ALL GEMS If you run `bundle lock` with `--update` option without list of gems, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources. ## UPDATING A LIST OF GEMS Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the `Gemfile.lock`. For instance, you only want to update `nokogiri`, run `bundle lock --update nokogiri`. Bundler will update `nokogiri` and any of its dependencies, but leave the rest of the gems that you specified locked to the versions in the `Gemfile.lock`. ## SUPPORTING OTHER PLATFORMS If you want your bundle to support platforms other than the one you're running locally, you can run `bundle lock --add-platform PLATFORM` to add PLATFORM to the lockfile, force bundler to re-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform-specific gems on. For a full explanation of gem platforms, see `gem help platform`. ## PATCH LEVEL OPTIONS See [bundle update(1)](bundle-update.1.html) for details. PK ]Iߚ :gems/bundler-2.2.24/lib/bundler/man/bundle-outdated.1.ronnnu[bundle-outdated(1) -- List installed gems with newer versions available ======================================================================= ## SYNOPSIS `bundle outdated` [GEM] [--local] [--pre] [--source] [--strict] [--parseable | --porcelain] [--group=GROUP] [--groups] [--update-strict] [--patch|--minor|--major] [--filter-major] [--filter-minor] [--filter-patch] [--only-explicit] ## DESCRIPTION Outdated lists the names and versions of gems that have a newer version available in the given source. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems. Prerelease gems are ignored by default. If your gems are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. ## OPTIONS * `--local`: Do not attempt to fetch gems remotely and use the gem cache instead. * `--pre`: Check for newer pre-release gems. * `--source`: Check against a specific source. * `--strict`: Only list newer versions allowed by your Gemfile requirements. * `--parseable`, `--porcelain`: Use minimal formatting for more parseable output. * `--group`: List gems from a specific group. * `--groups`: List gems organized by groups. * `--update-strict`: Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor| --major. * `--minor`: Prefer updating only to next minor version. * `--major`: Prefer updating to next major version (default). * `--patch`: Prefer updating only to next patch version. * `--filter-major`: Only list major newer versions. * `--filter-minor`: Only list minor newer versions. * `--filter-patch`: Only list patch newer versions. * `--only-explicit`: Only list gems specified in your Gemfile, not their dependencies. ## PATCH LEVEL OPTIONS See [bundle update(1)](bundle-update.1.html) for details. One difference between the patch level options in `bundle update` and here is the `--strict` option. `--strict` was already an option on outdated before the patch level options were added. `--strict` wasn't altered, and the `--update-strict` option on `outdated` reflects what `--strict` does on `bundle update`. ## FILTERING OUTPUT The 3 filtering options do not affect the resolution of versions, merely what versions are shown in the output. If the regular output shows the following: * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test" * hashie (newest 3.4.6, installed 1.2.0, requested = 1.2.0) in groups "default" * headless (newest 2.3.1, installed 2.2.3) in groups "test" `--filter-major` would only show: * hashie (newest 3.4.6, installed 1.2.0, requested = 1.2.0) in groups "default" `--filter-minor` would only show: * headless (newest 2.3.1, installed 2.2.3) in groups "test" `--filter-patch` would only show: * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test" Filter options can be combined. `--filter-minor` and `--filter-patch` would show: * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test" * headless (newest 2.3.1, installed 2.2.3) in groups "test" Combining all three `filter` options would be the same result as providing none of them. PK ]1~:gems/bundler-2.2.24/lib/bundler/man/bundle-binstubs.1.ronnnu[bundle-binstubs(1) -- Install the binstubs of the listed gems ============================================================= ## SYNOPSIS `bundle binstubs` [--force] [--path PATH] [--standalone] ## DESCRIPTION Binstubs are scripts that wrap around executables. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into `bin/`. Binstubs are a shortcut-or alternative- to always using `bundle exec`. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application. For example, if you run `bundle binstubs rspec-core`, Bundler will create the file `bin/rspec`. That file will contain enough code to load Bundler, tell it to load the bundled gems, and then run rspec. This command generates binstubs for executables in `GEM_NAME`. Binstubs are put into `bin`, or the `--path` directory if one has been set. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems. ## OPTIONS * `--force`: Overwrite existing binstubs if they exist. * `--path`: The location to install the specified binstubs to. This defaults to `bin`. * `--standalone`: Makes binstubs that can work without depending on Rubygems or Bundler at runtime. * `--shebang`: Specify a different shebang executable name than the default (default 'ruby') * `--all`: Create binstubs for all gems in the bundle. PK ]UM 2gems/bundler-2.2.24/lib/bundler/man/bundle-cache.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-CACHE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application . .SH "SYNOPSIS" \fBbundle cache\fR . .SH "DESCRIPTION" Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running [bundle install(1)][bundle\-install], use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\. . .SH "GIT AND PATH GEMS" The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This needs to be explicitly enabled via the \fB\-\-all\fR option\. Once used, the \fB\-\-all\fR option will be remembered\. . .SH "SUPPORT FOR MULTIPLE PLATFORMS" When using gems that have different packages for different platforms, Bundler supports caching of gems for other platforms where the Gemfile has been resolved (i\.e\. present in the lockfile) in \fBvendor/cache\fR\. This needs to be enabled via the \fB\-\-all\-platforms\fR option\. This setting will be remembered in your local bundler configuration\. . .SH "REMOTE FETCHING" By default, if you run \fBbundle install(1)\fR](bundle\-install\.1\.html) after running bundle cache(1) \fIbundle\-cache\.1\.html\fR, bundler will still connect to \fBrubygems\.org\fR to check whether a platform\-specific gem exists for any of the gems in \fBvendor/cache\fR\. . .P For instance, consider this Gemfile(5): . .IP "" 4 . .nf source "https://rubygems\.org" gem "nokogiri" . .fi . .IP "" 0 . .P If you run \fBbundle cache\fR under C Ruby, bundler will retrieve the version of \fBnokogiri\fR for the \fB"ruby"\fR platform\. If you deploy to JRuby and run \fBbundle install\fR, bundler is forced to check to see whether a \fB"java"\fR platformed \fBnokogiri\fR exists\. . .P Even though the \fBnokogiri\fR gem for the Ruby platform is \fItechnically\fR acceptable on JRuby, it has a C extension that does not run on JRuby\. As a result, bundler will, by default, still connect to \fBrubygems\.org\fR to check whether it has a version of one of your gems more specific to your platform\. . .P This problem is also not limited to the \fB"java"\fR platform\. A similar (common) problem can happen when developing on Windows and deploying to Linux, or even when developing on OSX and deploying to Linux\. . .P If you know for sure that the gems packaged in \fBvendor/cache\fR are appropriate for the platform you are on, you can run \fBbundle install \-\-local\fR to skip checking for more appropriate gems, and use the ones in \fBvendor/cache\fR\. . .P One way to be sure that you have the right platformed versions of all your gems is to run \fBbundle cache\fR on an identical machine and check in the gems\. For instance, you can run \fBbundle cache\fR on an identical staging box during your staging process, and check in the \fBvendor/cache\fR before deploying to production\. . .P By default, bundle cache(1) \fIbundle\-cache\.1\.html\fR fetches and also installs the gems to the default location\. To package the dependencies to \fBvendor/cache\fR without installing them to the local install location, you can run \fBbundle cache \-\-no\-install\fR\. PK ]5gems/bundler-2.2.24/lib/bundler/man/bundle-outdated.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-OUTDATED" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available . .SH "SYNOPSIS" \fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-update\-strict] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit] . .SH "DESCRIPTION" Outdated lists the names and versions of gems that have a newer version available in the given source\. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems\. Prerelease gems are ignored by default\. If your gems are up to date, Bundler will exit with a status of 0\. Otherwise, it will exit 1\. . .SH "OPTIONS" . .TP \fB\-\-local\fR Do not attempt to fetch gems remotely and use the gem cache instead\. . .TP \fB\-\-pre\fR Check for newer pre\-release gems\. . .TP \fB\-\-source\fR Check against a specific source\. . .TP \fB\-\-strict\fR Only list newer versions allowed by your Gemfile requirements\. . .TP \fB\-\-parseable\fR, \fB\-\-porcelain\fR Use minimal formatting for more parseable output\. . .TP \fB\-\-group\fR List gems from a specific group\. . .TP \fB\-\-groups\fR List gems organized by groups\. . .TP \fB\-\-update\-strict\fR Strict conservative resolution, do not allow any gem to be updated past latest \-\-patch | \-\-minor| \-\-major\. . .TP \fB\-\-minor\fR Prefer updating only to next minor version\. . .TP \fB\-\-major\fR Prefer updating to next major version (default)\. . .TP \fB\-\-patch\fR Prefer updating only to next patch version\. . .TP \fB\-\-filter\-major\fR Only list major newer versions\. . .TP \fB\-\-filter\-minor\fR Only list minor newer versions\. . .TP \fB\-\-filter\-patch\fR Only list patch newer versions\. . .TP \fB\-\-only\-explicit\fR Only list gems specified in your Gemfile, not their dependencies\. . .SH "PATCH LEVEL OPTIONS" See bundle update(1) \fIbundle\-update\.1\.html\fR for details\. . .P One difference between the patch level options in \fBbundle update\fR and here is the \fB\-\-strict\fR option\. \fB\-\-strict\fR was already an option on outdated before the patch level options were added\. \fB\-\-strict\fR wasn\'t altered, and the \fB\-\-update\-strict\fR option on \fBoutdated\fR reflects what \fB\-\-strict\fR does on \fBbundle update\fR\. . .SH "FILTERING OUTPUT" The 3 filtering options do not affect the resolution of versions, merely what versions are shown in the output\. . .P If the regular output shows the following: . .IP "" 4 . .nf * faker (newest 1\.6\.6, installed 1\.6\.5, requested ~> 1\.4) in groups "development, test" * hashie (newest 3\.4\.6, installed 1\.2\.0, requested = 1\.2\.0) in groups "default" * headless (newest 2\.3\.1, installed 2\.2\.3) in groups "test" . .fi . .IP "" 0 . .P \fB\-\-filter\-major\fR would only show: . .IP "" 4 . .nf * hashie (newest 3\.4\.6, installed 1\.2\.0, requested = 1\.2\.0) in groups "default" . .fi . .IP "" 0 . .P \fB\-\-filter\-minor\fR would only show: . .IP "" 4 . .nf * headless (newest 2\.3\.1, installed 2\.2\.3) in groups "test" . .fi . .IP "" 0 . .P \fB\-\-filter\-patch\fR would only show: . .IP "" 4 . .nf * faker (newest 1\.6\.6, installed 1\.6\.5, requested ~> 1\.4) in groups "development, test" . .fi . .IP "" 0 . .P Filter options can be combined\. \fB\-\-filter\-minor\fR and \fB\-\-filter\-patch\fR would show: . .IP "" 4 . .nf * faker (newest 1\.6\.6, installed 1\.6\.5, requested ~> 1\.4) in groups "development, test" * headless (newest 2\.3\.1, installed 2\.2\.3) in groups "test" . .fi . .IP "" 0 . .P Combining all three \fBfilter\fR options would be the same result as providing none of them\. PK ]N-,gems/bundler-2.2.24/lib/bundler/man/bundle.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management . .SH "SYNOPSIS" \fBbundle\fR COMMAND [\-\-no\-color] [\-\-verbose] [ARGS] . .SH "DESCRIPTION" Bundler manages an \fBapplication\'s dependencies\fR through its entire life across many machines systematically and repeatably\. . .P See the bundler website \fIhttps://bundler\.io\fR for information on getting started, and Gemfile(5) for more information on the \fBGemfile\fR format\. . .SH "OPTIONS" . .TP \fB\-\-no\-color\fR Print all output without color . .TP \fB\-\-retry\fR, \fB\-r\fR Specify the number of times you wish to attempt network commands . .TP \fB\-\-verbose\fR, \fB\-V\fR Print out additional logging information . .SH "BUNDLE COMMANDS" We divide \fBbundle\fR subcommands into primary commands and utilities: . .SH "PRIMARY COMMANDS" . .TP \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR Install the gems specified by the \fBGemfile\fR or \fBGemfile\.lock\fR . .TP \fBbundle update(1)\fR \fIbundle\-update\.1\.html\fR Update dependencies to their latest versions . .TP \fBbundle package(1)\fR \fIbundle\-package\.1\.html\fR Package the \.gem files required by your application into the \fBvendor/cache\fR directory . .TP \fBbundle exec(1)\fR \fIbundle\-exec\.1\.html\fR Execute a script in the current bundle . .TP \fBbundle config(1)\fR \fIbundle\-config\.1\.html\fR Specify and read configuration options for Bundler . .TP \fBbundle help(1)\fR Display detailed help for each subcommand . .SH "UTILITIES" . .TP \fBbundle add(1)\fR \fIbundle\-add\.1\.html\fR Add the named gem to the Gemfile and run \fBbundle install\fR . .TP \fBbundle binstubs(1)\fR \fIbundle\-binstubs\.1\.html\fR Generate binstubs for executables in a gem . .TP \fBbundle check(1)\fR \fIbundle\-check\.1\.html\fR Determine whether the requirements for your application are installed and available to Bundler . .TP \fBbundle show(1)\fR \fIbundle\-show\.1\.html\fR Show the source location of a particular gem in the bundle . .TP \fBbundle outdated(1)\fR \fIbundle\-outdated\.1\.html\fR Show all of the outdated gems in the current bundle . .TP \fBbundle console(1)\fR Start an IRB session in the current bundle . .TP \fBbundle open(1)\fR \fIbundle\-open\.1\.html\fR Open an installed gem in the editor . .TP \fBbundle lock(1)\fR \fIbundle\-lock\.1\.html\fR Generate a lockfile for your dependencies . .TP \fBbundle viz(1)\fR \fIbundle\-viz\.1\.html\fR Generate a visual representation of your dependencies . .TP \fBbundle init(1)\fR \fIbundle\-init\.1\.html\fR Generate a simple \fBGemfile\fR, placed in the current directory . .TP \fBbundle gem(1)\fR \fIbundle\-gem\.1\.html\fR Create a simple gem, suitable for development with Bundler . .TP \fBbundle platform(1)\fR \fIbundle\-platform\.1\.html\fR Display platform compatibility information . .TP \fBbundle clean(1)\fR \fIbundle\-clean\.1\.html\fR Clean up unused gems in your Bundler directory . .TP \fBbundle doctor(1)\fR \fIbundle\-doctor\.1\.html\fR Display warnings about common problems . .TP \fBbundle remove(1)\fR \fIbundle\-remove\.1\.html\fR Removes gems from the Gemfile . .SH "PLUGINS" When running a command that isn\'t listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named \fBbundler\-\fR and execute it, passing down any extra arguments to it\. . .SH "OBSOLETE" These commands are obsolete and should no longer be used: . .IP "\(bu" 4 \fBbundle cache(1)\fR . .IP "\(bu" 4 \fBbundle show(1)\fR . .IP "" 0 PK ]|)$J$J8gems/bundler-2.2.24/lib/bundler/man/bundle-config.1.ronnnu[bundle-config(1) -- Set bundler configuration options ===================================================== ## SYNOPSIS `bundle config` [list|get|set|unset] [ []] ## DESCRIPTION This command allows you to interact with Bundler's configuration system. Bundler loads configuration settings in this order: 1. Local config (`/.bundle/config` or `$BUNDLE_APP_CONFIG/config`) 2. Environmental variables (`ENV`) 3. Global config (`~/.bundle/config`) 4. Bundler default config Executing `bundle config list` with will print a list of all bundler configuration for the current bundle, and where that configuration was set. Executing `bundle config get ` will print the value of that configuration setting, and where it was set. Executing `bundle config set ` will set that configuration to the value specified for all bundles executed as the current user. The configuration will be stored in `~/.bundle/config`. If already is set, will be overridden and user will be warned. Executing `bundle config set --global ` works the same as above. Executing `bundle config set --local ` will set that configuration in the directory for the local application. The configuration will be stored in `/.bundle/config`. If `BUNDLE_APP_CONFIG` is set, the configuration will be stored in `$BUNDLE_APP_CONFIG/config`. Executing `bundle config unset ` will delete the configuration in both local and global sources. Executing `bundle config unset --global ` will delete the configuration only from the user configuration. Executing `bundle config unset --local ` will delete the configuration only from the local application. Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will cause it to ignore all configuration. ## REMEMBERING OPTIONS Flags passed to `bundle install` or the Bundler runtime, such as `--path foo` or `--without production`, are remembered between commands and saved to your local application's configuration (normally, `./.bundle/config`). However, this will be changed in bundler 3, so it's better not to rely on this behavior. If these options must be remembered, it's better to set them using `bundle config` (e.g., `bundle config set --local path foo`). The options that can be configured are: * `bin`: Creates a directory (defaults to `~/bin`) and place any executables from the gem there. These executables run in Bundler's context. If used, you might add this directory to your environment's `PATH` variable. For instance, if the `rails` gem comes with a `rails` executable, this flag will create a `bin/rails` executable that ensures that all referred dependencies will be resolved using the bundled gems. * `deployment`: In deployment mode, Bundler will 'roll-out' the bundle for `production` use. Please check carefully if you want to have this option enabled in `development` or `test` environments. * `path`: The location to install the specified gems to. This defaults to Rubygems' setting. Bundler shares this location with Rubygems, `gem install ...` will have gem installed there, too. Therefore, gems installed without a `--path ...` setting will show up by calling `gem list`. Accordingly, gems installed to other locations will not get listed. * `without`: A space-separated list of groups referencing gems to skip during installation. * `with`: A space-separated list of groups referencing gems to include during installation. ## BUILD OPTIONS You can use `bundle config` to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem. A very common example, the `mysql` gem, requires Snow Leopard users to pass configuration flags to `gem install` to specify where to find the `mysql_config` executable. gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config Since the specific location of that executable can change from machine to machine, you can specify these flags on a per-machine basis. bundle config set --global build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config After running this command, every time bundler needs to install the `mysql` gem, it will pass along the flags you specified. ## CONFIGURATION KEYS Configuration keys in bundler have two forms: the canonical form and the environment variable form. For instance, passing the `--without` flag to [bundle install(1)](bundle-install.1.html) prevents Bundler from installing certain groups specified in the Gemfile(5). Bundler persists this value in `app/.bundle/config` so that calls to `Bundler.setup` do not try to find gems from the `Gemfile` that you didn't install. Additionally, subsequent calls to [bundle install(1)](bundle-install.1.html) remember this setting and skip those groups. The canonical form of this configuration is `"without"`. To convert the canonical form to the environment variable form, capitalize it, and prepend `BUNDLE_`. The environment variable form of `"without"` is `BUNDLE_WITHOUT`. Any periods in the configuration keys must be replaced with two underscores when setting it via environment variables. The configuration key `local.rack` becomes the environment variable `BUNDLE_LOCAL__RACK`. ## LIST OF AVAILABLE KEYS The following is a list of all configuration keys and their purpose. You can learn more about their operation in [bundle install(1)](bundle-install.1.html). * `allow_deployment_source_credential_changes` (`BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES`): When in deployment mode, allow changing the credentials to a gem's source. Ex: `https://some.host.com/gems/path/` -> `https://user_name:password@some.host.com/gems/path` * `allow_offline_install` (`BUNDLE_ALLOW_OFFLINE_INSTALL`): Allow Bundler to use cached data when installing without network access. * `auto_clean_without_path` (`BUNDLE_AUTO_CLEAN_WITHOUT_PATH`): Automatically run `bundle clean` after installing when an explicit `path` has not been set and Bundler is not installing into the system gems. * `auto_install` (`BUNDLE_AUTO_INSTALL`): Automatically run `bundle install` when gems are missing. * `bin` (`BUNDLE_BIN`): Install executables from gems in the bundle to the specified directory. Defaults to `false`. * `cache_all` (`BUNDLE_CACHE_ALL`): Cache all gems, including path and git gems. This needs to be explicitly configured on bundler 1 and bundler 2, but will be the default on bundler 3. * `cache_all_platforms` (`BUNDLE_CACHE_ALL_PLATFORMS`): Cache gems for all platforms. * `cache_path` (`BUNDLE_CACHE_PATH`): The directory that bundler will place cached gems in when running bundle package, and that bundler will look in when installing gems. Defaults to `vendor/cache`. * `clean` (`BUNDLE_CLEAN`): Whether Bundler should run `bundle clean` automatically after `bundle install`. * `console` (`BUNDLE_CONSOLE`): The console that `bundle console` starts. Defaults to `irb`. * `default_install_uses_path` (`BUNDLE_DEFAULT_INSTALL_USES_PATH`): Whether a `bundle install` without an explicit `--path` argument defaults to installing gems in `.bundle`. * `deployment` (`BUNDLE_DEPLOYMENT`): Disallow changes to the `Gemfile`. When the `Gemfile` is changed and the lockfile has not been updated, running Bundler commands will be blocked. * `disable_checksum_validation` (`BUNDLE_DISABLE_CHECKSUM_VALIDATION`): Allow installing gems even if they do not match the checksum provided by RubyGems. * `disable_exec_load` (`BUNDLE_DISABLE_EXEC_LOAD`): Stop Bundler from using `load` to launch an executable in-process in `bundle exec`. * `disable_local_branch_check` (`BUNDLE_DISABLE_LOCAL_BRANCH_CHECK`): Allow Bundler to use a local git override without a branch specified in the Gemfile. * `disable_local_revision_check` (`BUNDLE_DISABLE_LOCAL_REVISION_CHECK`): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository. * `disable_shared_gems` (`BUNDLE_DISABLE_SHARED_GEMS`): Stop Bundler from accessing gems installed to RubyGems' normal location. * `disable_version_check` (`BUNDLE_DISABLE_VERSION_CHECK`): Stop Bundler from checking if a newer Bundler version is available on rubygems.org. * `force_ruby_platform` (`BUNDLE_FORCE_RUBY_PLATFORM`): Ignore the current machine's platform and install only `ruby` platform gems. As a result, gems with native extensions will be compiled from source. * `frozen` (`BUNDLE_FROZEN`): Disallow changes to the `Gemfile`. When the `Gemfile` is changed and the lockfile has not been updated, running Bundler commands will be blocked. Defaults to `true` when `--deployment` is used. * `gem.github_username` (`BUNDLE_GEM__GITHUB_USERNAME`): Sets a GitHub username or organization to be used in `README` file when you create a new gem via `bundle gem` command. It can be overridden by passing an explicit `--github-username` flag to `bundle gem`. * `gem.push_key` (`BUNDLE_GEM__PUSH_KEY`): Sets the `--key` parameter for `gem push` when using the `rake release` command with a private gemstash server. * `gemfile` (`BUNDLE_GEMFILE`): The name of the file that bundler should use as the `Gemfile`. This location of this file also sets the root of the project, which is used to resolve relative paths in the `Gemfile`, among other things. By default, bundler will search up from the current working directory until it finds a `Gemfile`. * `global_gem_cache` (`BUNDLE_GLOBAL_GEM_CACHE`): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation. * `ignore_messages` (`BUNDLE_IGNORE_MESSAGES`): When set, no post install messages will be printed. To silence a single gem, use dot notation like `ignore_messages.httparty true`. * `init_gems_rb` (`BUNDLE_INIT_GEMS_RB`): Generate a `gems.rb` instead of a `Gemfile` when running `bundle init`. * `jobs` (`BUNDLE_JOBS`): The number of gems Bundler can install in parallel. Defaults to 1 on Windows, and to the the number of processors on other platforms. * `no_install` (`BUNDLE_NO_INSTALL`): Whether `bundle package` should skip installing gems. * `no_prune` (`BUNDLE_NO_PRUNE`): Whether Bundler should leave outdated gems unpruned when caching. * `path` (`BUNDLE_PATH`): The location on disk where all gems in your bundle will be located regardless of `$GEM_HOME` or `$GEM_PATH` values. Bundle gems not found in this location will be installed by `bundle install`. Defaults to `Gem.dir`. When --deployment is used, defaults to vendor/bundle. * `path.system` (`BUNDLE_PATH__SYSTEM`): Whether Bundler will install gems into the default system path (`Gem.dir`). * `path_relative_to_cwd` (`BUNDLE_PATH_RELATIVE_TO_CWD`) Makes `--path` relative to the CWD instead of the `Gemfile`. * `plugins` (`BUNDLE_PLUGINS`): Enable Bundler's experimental plugin system. * `prefer_patch` (BUNDLE_PREFER_PATCH): Prefer updating only to next patch version during updates. Makes `bundle update` calls equivalent to `bundler update --patch`. * `print_only_version_number` (`BUNDLE_PRINT_ONLY_VERSION_NUMBER`): Print only version number from `bundler --version`. * `redirect` (`BUNDLE_REDIRECT`): The number of redirects allowed for network requests. Defaults to `5`. * `retry` (`BUNDLE_RETRY`): The number of times to retry failed network requests. Defaults to `3`. * `setup_makes_kernel_gem_public` (`BUNDLE_SETUP_MAKES_KERNEL_GEM_PUBLIC`): Have `Bundler.setup` make the `Kernel#gem` method public, even though RubyGems declares it as private. * `shebang` (`BUNDLE_SHEBANG`): The program name that should be invoked for generated binstubs. Defaults to the ruby install name used to generate the binstub. * `silence_deprecations` (`BUNDLE_SILENCE_DEPRECATIONS`): Whether Bundler should silence deprecation warnings for behavior that will be changed in the next major version. * `silence_root_warning` (`BUNDLE_SILENCE_ROOT_WARNING`): Silence the warning Bundler prints when installing gems as root. * `ssl_ca_cert` (`BUNDLE_SSL_CA_CERT`): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format. * `ssl_client_cert` (`BUNDLE_SSL_CLIENT_CERT`): Path to a designated file containing a X.509 client certificate and key in PEM format. * `ssl_verify_mode` (`BUNDLE_SSL_VERIFY_MODE`): The SSL verification mode Bundler uses when making HTTPS requests. Defaults to verify peer. * `suppress_install_using_messages` (`BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES`): Avoid printing `Using ...` messages during installation when the version of a gem has not changed. * `system_bindir` (`BUNDLE_SYSTEM_BINDIR`): The location where RubyGems installs binstubs. Defaults to `Gem.bindir`. * `timeout` (`BUNDLE_TIMEOUT`): The seconds allowed before timing out for network requests. Defaults to `10`. * `update_requires_all_flag` (`BUNDLE_UPDATE_REQUIRES_ALL_FLAG`): Require passing `--all` to `bundle update` when everything should be updated, and disallow passing no options to `bundle update`. * `user_agent` (`BUNDLE_USER_AGENT`): The custom user agent fragment Bundler includes in API requests. * `with` (`BUNDLE_WITH`): A `:`-separated list of groups whose gems bundler should install. * `without` (`BUNDLE_WITHOUT`): A `:`-separated list of groups whose gems bundler should not install. In general, you should set these settings per-application by using the applicable flag to the [bundle install(1)](bundle-install.1.html) or [bundle package(1)](bundle-package.1.html) command. You can set them globally either via environment variables or `bundle config`, whichever is preferable for your setup. If you use both, environment variables will take preference over global settings. ## LOCAL GIT REPOS Bundler also allows you to work against a git repository locally instead of using the remote version. This can be achieved by setting up a local override: bundle config set --local local.GEM_NAME /path/to/local/git/repository For example, in order to use a local Rack repository, a developer could call: bundle config set --local local.rack ~/Work/git/rack Now instead of checking out the remote git repository, the local override will be used. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler. This means a commit in the local git repo will update the revision in the `Gemfile.lock` to the local git repo revision. This requires the same attention as git submodules. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine. You'll also need to CGI escape your usernames and passwords as well. Bundler does many checks to ensure a developer won't work with invalid references. Particularly, we force a developer to specify a branch in the `Gemfile` in order to use this feature. If the branch specified in the `Gemfile` and the current branch in the local git repository do not match, Bundler will abort. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch. Finally, Bundler also ensures that the current revision in the `Gemfile.lock` exists in the local git repository. By doing this, Bundler forces you to fetch the latest changes in the remotes. ## MIRRORS OF GEM SOURCES Bundler supports overriding gem sources with mirrors. This allows you to configure rubygems.org as the gem source in your Gemfile while still using your mirror to fetch gems. bundle config set --global mirror.SOURCE_URL MIRROR_URL For example, to use a mirror of rubygems.org hosted at rubygems-mirror.org: bundle config set --global mirror.http://rubygems.org http://rubygems-mirror.org Each mirror also provides a fallback timeout setting. If the mirror does not respond within the fallback timeout, Bundler will try to use the original server instead of the mirror. bundle config set --global mirror.SOURCE_URL.fallback_timeout TIMEOUT For example, to fall back to rubygems.org after 3 seconds: bundle config set --global mirror.https://rubygems.org.fallback_timeout 3 The default fallback timeout is 0.1 seconds, but the setting can currently only accept whole seconds (for example, 1, 15, or 30). ## CREDENTIALS FOR GEM SOURCES Bundler allows you to configure credentials for any gem source, which allows you to avoid putting secrets into your Gemfile. bundle config set --global SOURCE_HOSTNAME USERNAME:PASSWORD For example, to save the credentials of user `claudette` for the gem source at `gems.longerous.com`, you would run: bundle config set --global gems.longerous.com claudette:s00pers3krit Or you can set the credentials as an environment variable like this: export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit" For gems with a git source with HTTP(S) URL you can specify credentials like so: bundle config set --global https://github.com/rubygems/rubygems.git username:password Or you can set the credentials as an environment variable like so: export BUNDLE_GITHUB__COM=username:password This is especially useful for private repositories on hosts such as Github, where you can use personal OAuth tokens: export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x-oauth-basic Note that any configured credentials will be redacted by informative commands such as `bundle config list` or `bundle config get`, unless you use the `--parseable` flag. This is to avoid unintentially leaking credentials when copy-pasting bundler output. Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations: * Any `-` characters in a host name are mapped to a triple dash (`___`) in the corresponding enviroment variable. * Any `.` characters in a host name are mapped to a double dash (`__`) in the corresponding environment variable. This means that if you have a gem server named `my.gem-host.com`, you'll need to use the `BUNDLE_MY__GEM___HOST__COM` variable to configure credentials for it through ENV. ## CONFIGURE BUNDLER DIRECTORIES Bundler's home, config, cache and plugin directories are able to be configured through environment variables. The default location for Bundler's home directory is `~/.bundle`, which all directories inherit from by default. The following outlines the available environment variables and their default values BUNDLE_USER_HOME : $HOME/.bundle BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin PK ]ms s 1gems/bundler-2.2.24/lib/bundler/man/bundle-lock.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-LOCK" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing . .SH "SYNOPSIS" \fBbundle lock\fR [\-\-update] [\-\-local] [\-\-print] [\-\-lockfile=PATH] [\-\-full\-index] [\-\-add\-platform] [\-\-remove\-platform] [\-\-patch] [\-\-minor] [\-\-major] [\-\-strict] [\-\-conservative] . .SH "DESCRIPTION" Lock the gems specified in Gemfile\. . .SH "OPTIONS" . .TP \fB\-\-update=<*gems>\fR Ignores the existing lockfile\. Resolve then updates lockfile\. Taking a list of gems or updating all gems if no list is given\. . .TP \fB\-\-local\fR Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. . .TP \fB\-\-print\fR Prints the lockfile to STDOUT instead of writing to the file system\. . .TP \fB\-\-lockfile=\fR The path where the lockfile should be written to\. . .TP \fB\-\-full\-index\fR Fall back to using the single\-file index of all gems\. . .TP \fB\-\-add\-platform\fR Add a new platform to the lockfile, re\-resolving for the addition of that platform\. . .TP \fB\-\-remove\-platform\fR Remove a platform from the lockfile\. . .TP \fB\-\-patch\fR If updating, prefer updating only to next patch version\. . .TP \fB\-\-minor\fR If updating, prefer updating only to next minor version\. . .TP \fB\-\-major\fR If updating, prefer updating to next major version (default)\. . .TP \fB\-\-strict\fR If updating, do not allow any gem to be updated past latest \-\-patch | \-\-minor | \-\-major\. . .TP \fB\-\-conservative\fR If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated\. . .SH "UPDATING ALL GEMS" If you run \fBbundle lock\fR with \fB\-\-update\fR option without list of gems, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. . .SH "UPDATING A LIST OF GEMS" Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. . .P For instance, you only want to update \fBnokogiri\fR, run \fBbundle lock \-\-update nokogiri\fR\. . .P Bundler will update \fBnokogiri\fR and any of its dependencies, but leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. . .SH "SUPPORTING OTHER PLATFORMS" If you want your bundle to support platforms other than the one you\'re running locally, you can run \fBbundle lock \-\-add\-platform PLATFORM\fR to add PLATFORM to the lockfile, force bundler to re\-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform\-specific gems on\. . .P For a full explanation of gem platforms, see \fBgem help platform\fR\. . .SH "PATCH LEVEL OPTIONS" See bundle update(1) \fIbundle\-update\.1\.html\fR for details\. PK ]m2gems/bundler-2.2.24/lib/bundler/man/bundle-check.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-CHECK" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems . .SH "SYNOPSIS" \fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE] [\-\-path=PATH] . .SH "DESCRIPTION" \fBcheck\fR searches the local machine for each of the gems requested in the Gemfile\. If all gems are found, Bundler prints a success message and exits with a status of 0\. . .P If not, the first missing gem is listed and Bundler exits status 1\. . .SH "OPTIONS" . .TP \fB\-\-dry\-run\fR Locks the [\fBGemfile(5)\fR][Gemfile(5)] before running the command\. . .TP \fB\-\-gemfile\fR Use the specified gemfile instead of the [\fBGemfile(5)\fR][Gemfile(5)]\. . .TP \fB\-\-path\fR Specify a different path than the system default (\fB$BUNDLE_PATH\fR or \fB$GEM_HOME\fR)\. Bundler will remember this value for future installs on this machine\. PK ]\'iTT6gems/bundler-2.2.24/lib/bundler/man/bundle-show.1.ronnnu[bundle-show(1) -- Shows all the gems in your bundle, or the path to a gem ========================================================================= ## SYNOPSIS `bundle show` [GEM] [--paths] ## DESCRIPTION Without the [GEM] option, `show` will print a list of the names and versions of all gems that are required by your [`Gemfile(5)`][Gemfile(5)], sorted by name. Calling show with [GEM] will list the exact location of that gem on your machine. ## OPTIONS * `--paths`: List the paths of all gems that are required by your [`Gemfile(5)`][Gemfile(5)], sorted by gem name. PK ]˱[y8gems/bundler-2.2.24/lib/bundler/man/bundle-remove.1.ronnnu[bundle-remove(1) -- Removes gems from the Gemfile =========================================================================== ## SYNOPSIS `bundle remove [GEM [GEM ...]] [--install]` ## DESCRIPTION Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If a gem cannot be removed, a warning is printed. If a gem is already absent from the Gemfile, and error is raised. ## OPTIONS * `--install`: Runs `bundle install` after the given gems have been removed from the Gemfile, which ensures that both the lockfile and the installed gems on disk are also updated to remove the given gem(s). Example: bundle remove rails bundle remove rails rack bundle remove rails rack --install PK ]h6gems/bundler-2.2.24/lib/bundler/man/bundle-init.1.ronnnu[bundle-init(1) -- Generates a Gemfile into the current working directory ======================================================================== ## SYNOPSIS `bundle init` [--gemspec=FILE] ## DESCRIPTION Init generates a default [`Gemfile(5)`][Gemfile(5)] in the current working directory. When adding a [`Gemfile(5)`][Gemfile(5)] to a gem with a gemspec, the `--gemspec` option will automatically add each dependency listed in the gemspec file to the newly created [`Gemfile(5)`][Gemfile(5)]. ## OPTIONS * `--gemspec`: Use the specified .gemspec to create the [`Gemfile(5)`][Gemfile(5)] ## FILES Included in the default [`Gemfile(5)`][Gemfile(5)] generated is the line `# frozen_string_literal: true`. This is a magic comment supported for the first time in Ruby 2.3. The presence of this line results in all string literals in the file being implicitly frozen. ## SEE ALSO [Gemfile(5)](https://bundler.io/man/gemfile.5.html) PK ]+B+B9gems/bundler-2.2.24/lib/bundler/man/bundle-install.1.ronnnu[bundle-install(1) -- Install the dependencies specified in your Gemfile ======================================================================= ## SYNOPSIS `bundle install` [--binstubs[=DIRECTORY]] [--clean] [--deployment] [--frozen] [--full-index] [--gemfile=GEMFILE] [--jobs=NUMBER] [--local] [--no-cache] [--no-prune] [--path PATH] [--quiet] [--redownload] [--retry=NUMBER] [--shebang] [--standalone[=GROUP[ GROUP...]]] [--system] [--trust-policy=POLICY] [--with=GROUP[ GROUP...]] [--without=GROUP[ GROUP...]] ## DESCRIPTION Install the gems specified in your Gemfile(5). If this is the first time you run bundle install (and a `Gemfile.lock` does not exist), Bundler will fetch all remote sources, resolve dependencies and install all needed gems. If a `Gemfile.lock` does exist, and you have not updated your Gemfile(5), Bundler will fetch all remote sources, but use the dependencies specified in the `Gemfile.lock` instead of resolving dependencies. If a `Gemfile.lock` does exist, and you have updated your Gemfile(5), Bundler will use the dependencies in the `Gemfile.lock` for all gems that you did not update, but will re-resolve the dependencies of gems that you did update. You can find more information about this update process below under [CONSERVATIVE UPDATING][]. ## OPTIONS The `--clean`, `--deployment`, `--frozen`, `--no-prune`, `--path`, `--shebang`, `--system`, `--without` and `--with` options are deprecated because they only make sense if they are applied to every subsequent `bundle install` run automatically and that requires `bundler` to silently remember them. Since `bundler` will no longer remember CLI flags in future versions, `bundle config` (see bundle-config(1)) should be used to apply them permanently. * `--binstubs[=]`: Binstubs are scripts that wrap around executables. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it in `bin/`. This lets you link the binstub inside of an application to the exact gem version the application needs. Creates a directory (defaults to `~/bin`) and places any executables from the gem there. These executables run in Bundler's context. If used, you might add this directory to your environment's `PATH` variable. For instance, if the `rails` gem comes with a `rails` executable, this flag will create a `bin/rails` executable that ensures that all referred dependencies will be resolved using the bundled gems. * `--clean`: On finishing the installation Bundler is going to remove any gems not present in the current Gemfile(5). Don't worry, gems currently in use will not be removed. This option is deprecated in favor of the `clean` setting. * `--deployment`: In [deployment mode][DEPLOYMENT MODE], Bundler will 'roll-out' the bundle for production or CI use. Please check carefully if you want to have this option enabled in your development environment. This option is deprecated in favor of the `deployment` setting. * `--redownload`: Force download every gem, even if the required versions are already available locally. * `--frozen`: Do not allow the Gemfile.lock to be updated after this install. Exits non-zero if there are going to be changes to the Gemfile.lock. This option is deprecated in favor of the `frozen` setting. * `--full-index`: Bundler will not call Rubygems' API endpoint (default) but download and cache a (currently big) index file of all gems. Performance can be improved for large bundles that seldom change by enabling this option. * `--gemfile=`: The location of the Gemfile(5) which Bundler should use. This defaults to a Gemfile(5) in the current working directory. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find `Gemfile.lock` and `vendor/cache` relative to this location. * `--jobs=[]`, `-j[]`: The maximum number of parallel download and install jobs. The default is `1`. * `--local`: Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the gems already present in Rubygems' cache or in `vendor/cache`. Note that if an appropriate platform-specific gem exists on `rubygems.org` it will not be found. * `--no-cache`: Do not update the cache in `vendor/cache` with the newly bundled gems. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install. * `--no-prune`: Don't remove stale gems from the cache when the installation finishes. This option is deprecated in favor of the `no_prune` setting. * `--path=`: The location to install the specified gems to. This defaults to Rubygems' setting. Bundler shares this location with Rubygems, `gem install ...` will have gem installed there, too. Therefore, gems installed without a `--path ...` setting will show up by calling `gem list`. Accordingly, gems installed to other locations will not get listed. This option is deprecated in favor of the `path` setting. * `--quiet`: Do not print progress information to the standard output. Instead, Bundler will exit using a status code (`$?`). * `--retry=[]`: Retry failed network or git requests for times. * `--shebang=`: Uses the specified ruby executable (usually `ruby`) to execute the scripts created with `--binstubs`. In addition, if you use `--binstubs` together with `--shebang jruby` these executables will be changed to execute `jruby` instead. This option is deprecated in favor of the `shebang` setting. * `--standalone[=]`: Makes a bundle that can work without depending on Rubygems or Bundler at runtime. A space separated list of groups to install has to be specified. Bundler creates a directory named `bundle` and installs the bundle there. It also generates a `bundle/bundler/setup.rb` file to replace Bundler's own setup in the manner required. Using this option implicitly sets `path`, which is a [remembered option][REMEMBERED OPTIONS]. * `--system`: Installs the gems specified in the bundle to the system's Rubygems location. This overrides any previous configuration of `--path`. This option is deprecated in favor of the `system` setting. * `--trust-policy=[]`: Apply the Rubygems security policy , where policy is one of `HighSecurity`, `MediumSecurity`, `LowSecurity`, `AlmostNoSecurity`, or `NoSecurity`. For more details, please see the Rubygems signing documentation linked below in [SEE ALSO][]. * `--with=`: A space-separated list of groups referencing gems to install. If an optional group is given it is installed. If a group is given that is in the remembered list of groups given to --without, it is removed from that list. This option is deprecated in favor of the `with` setting. * `--without=`: A space-separated list of groups referencing gems to skip during installation. If a group is given that is in the remembered list of groups given to --with, it is removed from that list. This option is deprecated in favor of the `without` setting. ## DEPLOYMENT MODE Bundler's defaults are optimized for development. To switch to defaults optimized for deployment and for CI, use the `--deployment` flag. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified. 1. A `Gemfile.lock` is required. To ensure that the same versions of the gems you developed with and tested with are also used in deployments, a `Gemfile.lock` is required. This is mainly to ensure that you remember to check your `Gemfile.lock` into version control. 2. The `Gemfile.lock` must be up to date In development, you can modify your Gemfile(5) and re-run `bundle install` to [conservatively update][CONSERVATIVE UPDATING] your `Gemfile.lock` snapshot. In deployment, your `Gemfile.lock` should be up-to-date with changes made in your Gemfile(5). 3. Gems are installed to `vendor/bundle` not your default system location In development, it's convenient to share the gems used in your application with other applications and other scripts that run on the system. In deployment, isolation is a more important default. In addition, the user deploying the application may not have permission to install gems to the system, or the web server may not have permission to read them. As a result, `bundle install --deployment` installs gems to the `vendor/bundle` directory in the application. This may be overridden using the `--path` option. ## SUDO USAGE By default, Bundler installs gems to the same location as `gem install`. In some cases, that location may not be writable by your Unix user. In that case, Bundler will stage everything in a temporary directory, then ask you for your `sudo` password in order to copy the gems into their system location. From your perspective, this is identical to installing the gems directly into the system. You should never use `sudo bundle install`. This is because several other steps in `bundle install` must be performed as the current user: * Updating your `Gemfile.lock` * Updating your `vendor/cache`, if necessary * Checking out private git repositories using your user's SSH keys Of these three, the first two could theoretically be performed by `chown`ing the resulting files to `$SUDO_USER`. The third, however, can only be performed by invoking the `git` command as the current user. Therefore, git gems are downloaded and installed into `~/.bundle` rather than $GEM_HOME or $BUNDLE_PATH. As a result, you should run `bundle install` as the current user, and Bundler will ask for your password if it is needed to put the gems into their final location. ## INSTALLING GROUPS By default, `bundle install` will install all gems in all groups in your Gemfile(5), except those declared for a different platform. However, you can explicitly tell Bundler to skip installing certain groups with the `--without` option. This option takes a space-separated list of groups. While the `--without` option will skip _installing_ the gems in the specified groups, it will still _download_ those gems and use them to resolve the dependencies of every gem in your Gemfile(5). This is so that installing a different set of groups on another machine (such as a production server) will not change the gems and versions that you have already developed and tested against. `Bundler offers a rock-solid guarantee that the third-party code you are running in development and testing is also the third-party code you are running in production. You can choose to exclude some of that code in different environments, but you will never be caught flat-footed by different versions of third-party code being used in different environments.` For a simple illustration, consider the following Gemfile(5): source 'https://rubygems.org' gem 'sinatra' group :production do gem 'rack-perftools-profiler' end In this case, `sinatra` depends on any version of Rack (`>= 1.0`), while `rack-perftools-profiler` depends on 1.x (`~> 1.0`). When you run `bundle install --without production` in development, we look at the dependencies of `rack-perftools-profiler` as well. That way, you do not spend all your time developing against Rack 2.0, using new APIs unavailable in Rack 1.x, only to have Bundler switch to Rack 1.2 when the `production` group _is_ used. This should not cause any problems in practice, because we do not attempt to `install` the gems in the excluded groups, and only evaluate as part of the dependency resolution process. This also means that you cannot include different versions of the same gem in different groups, because doing so would result in different sets of dependencies used in development and production. Because of the vagaries of the dependency resolution process, this usually affects more than the gems you list in your Gemfile(5), and can (surprisingly) radically change the gems you are using. ## THE GEMFILE.LOCK When you run `bundle install`, Bundler will persist the full names and versions of all gems that you used (including dependencies of the gems specified in the Gemfile(5)) into a file called `Gemfile.lock`. Bundler uses this file in all subsequent calls to `bundle install`, which guarantees that you always use the same exact code, even as your application moves across machines. Because of the way dependency resolution works, even a seemingly small change (for instance, an update to a point-release of a dependency of a gem in your Gemfile(5)) can result in radically different gems being needed to satisfy all dependencies. As a result, you `SHOULD` check your `Gemfile.lock` into version control, in both applications and gems. If you do not, every machine that checks out your repository (including your production server) will resolve all dependencies again, which will result in different versions of third-party code being used if `any` of the gems in the Gemfile(5) or any of their dependencies have been updated. When Bundler first shipped, the `Gemfile.lock` was included in the `.gitignore` file included with generated gems. Over time, however, it became clear that this practice forces the pain of broken dependencies onto new contributors, while leaving existing contributors potentially unaware of the problem. Since `bundle install` is usually the first step towards a contribution, the pain of broken dependencies would discourage new contributors from contributing. As a result, we have revised our guidance for gem authors to now recommend checking in the lock for gems. ## CONSERVATIVE UPDATING When you make a change to the Gemfile(5) and then run `bundle install`, Bundler will update only the gems that you modified. In other words, if a gem that you `did not modify` worked before you called `bundle install`, it will continue to use the exact same versions of all dependencies as it used before the update. Let's take a look at an example. Here's your original Gemfile(5): source 'https://rubygems.org' gem 'actionpack', '2.3.8' gem 'activemerchant' In this case, both `actionpack` and `activemerchant` depend on `activesupport`. The `actionpack` gem depends on `activesupport 2.3.8` and `rack ~> 1.1.0`, while the `activemerchant` gem depends on `activesupport >= 2.3.2`, `braintree >= 2.0.0`, and `builder >= 2.0.0`. When the dependencies are first resolved, Bundler will select `activesupport 2.3.8`, which satisfies the requirements of both gems in your Gemfile(5). Next, you modify your Gemfile(5) to: source 'https://rubygems.org' gem 'actionpack', '3.0.0.rc' gem 'activemerchant' The `actionpack 3.0.0.rc` gem has a number of new dependencies, and updates the `activesupport` dependency to `= 3.0.0.rc` and the `rack` dependency to `~> 1.2.1`. When you run `bundle install`, Bundler notices that you changed the `actionpack` gem, but not the `activemerchant` gem. It evaluates the gems currently being used to satisfy its requirements: * `activesupport 2.3.8`: also used to satisfy a dependency in `activemerchant`, which is not being updated * `rack ~> 1.1.0`: not currently being used to satisfy another dependency Because you did not explicitly ask to update `activemerchant`, you would not expect it to suddenly stop working after updating `actionpack`. However, satisfying the new `activesupport 3.0.0.rc` dependency of actionpack requires updating one of its dependencies. Even though `activemerchant` declares a very loose dependency that theoretically matches `activesupport 3.0.0.rc`, Bundler treats gems in your Gemfile(5) that have not changed as an atomic unit together with their dependencies. In this case, the `activemerchant` dependency is treated as `activemerchant 1.7.1 + activesupport 2.3.8`, so `bundle install` will report that it cannot update `actionpack`. To explicitly update `actionpack`, including its dependencies which other gems in the Gemfile(5) still depend on, run `bundle update actionpack` (see `bundle update(1)`). `Summary`: In general, after making a change to the Gemfile(5) , you should first try to run `bundle install`, which will guarantee that no other gem in the Gemfile(5) is impacted by the change. If that does not work, run [bundle update(1)](bundle-update.1.html). ## SEE ALSO * [Gem install docs](http://guides.rubygems.org/rubygems-basics/#installing-gems) * [Rubygems signing docs](http://guides.rubygems.org/security/) PK ]^ ;ff1gems/bundler-2.2.24/lib/bundler/man/bundle-exec.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-EXEC" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle . .SH "SYNOPSIS" \fBbundle exec\fR [\-\-keep\-file\-descriptors] \fIcommand\fR . .SH "DESCRIPTION" This command executes the command, making all gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] available to \fBrequire\fR in Ruby programs\. . .P Essentially, if you would normally have run something like \fBrspec spec/my_spec\.rb\fR, and you want to use the gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] and installed via bundle install(1) \fIbundle\-install\.1\.html\fR, you should run \fBbundle exec rspec spec/my_spec\.rb\fR\. . .P Note that \fBbundle exec\fR does not require that an executable is available on your shell\'s \fB$PATH\fR\. . .SH "OPTIONS" . .TP \fB\-\-keep\-file\-descriptors\fR Exec in Ruby 2\.0 began discarding non\-standard file descriptors\. When this flag is passed, exec will revert to the 1\.9 behaviour of passing all file descriptors to the new process\. . .SH "BUNDLE INSTALL \-\-BINSTUBS" If you use the \fB\-\-binstubs\fR flag in bundle install(1) \fIbundle\-install\.1\.html\fR, Bundler will automatically create a directory (which defaults to \fBapp_root/bin\fR) containing all of the executables available from gems in the bundle\. . .P After using \fB\-\-binstubs\fR, \fBbin/rspec spec/my_spec\.rb\fR is identical to \fBbundle exec rspec spec/my_spec\.rb\fR\. . .SH "ENVIRONMENT MODIFICATIONS" \fBbundle exec\fR makes a number of changes to the shell environment, then executes the command you specify in full\. . .IP "\(bu" 4 make sure that it\'s still possible to shell out to \fBbundle\fR from inside a command invoked by \fBbundle exec\fR (using \fB$BUNDLE_BIN_PATH\fR) . .IP "\(bu" 4 put the directory containing executables (like \fBrails\fR, \fBrspec\fR, \fBrackup\fR) for your bundle on \fB$PATH\fR . .IP "\(bu" 4 make sure that if bundler is invoked in the subshell, it uses the same \fBGemfile\fR (by setting \fBBUNDLE_GEMFILE\fR) . .IP "\(bu" 4 add \fB\-rbundler/setup\fR to \fB$RUBYOPT\fR, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle . .IP "" 0 . .P It also modifies Rubygems: . .IP "\(bu" 4 disallow loading additional gems not in the bundle . .IP "\(bu" 4 modify the \fBgem\fR method to be a no\-op if a gem matching the requirements is in the bundle, and to raise a \fBGem::LoadError\fR if it\'s not . .IP "\(bu" 4 Define \fBGem\.refresh\fR to be a no\-op, since the source index is always frozen when using bundler, and to prevent gems from the system leaking into the environment . .IP "\(bu" 4 Override \fBGem\.bin_path\fR to use the gems in the bundle, making system executables work . .IP "\(bu" 4 Add all gems in the bundle into Gem\.loaded_specs . .IP "" 0 . .P Finally, \fBbundle exec\fR also implicitly modifies \fBGemfile\.lock\fR if the lockfile and the Gemfile do not match\. Bundler needs the Gemfile to determine things such as a gem\'s groups, \fBautorequire\fR, and platforms, etc\., and that information isn\'t stored in the lockfile\. The Gemfile and lockfile must be synced in order to \fBbundle exec\fR successfully, so \fBbundle exec\fR updates the lockfile beforehand\. . .SS "Loading" By default, when attempting to \fBbundle exec\fR to a file with a ruby shebang, Bundler will \fBKernel\.load\fR that file instead of using \fBKernel\.exec\fR\. For the vast majority of cases, this is a performance improvement\. In a rare few cases, this could cause some subtle side\-effects (such as dependence on the exact contents of \fB$0\fR or \fB__FILE__\fR) and the optimization can be disabled by enabling the \fBdisable_exec_load\fR setting\. . .SS "Shelling out" Any Ruby code that opens a subshell (like \fBsystem\fR, backticks, or \fB%x{}\fR) will automatically use the current Bundler environment\. If you need to shell out to a Ruby command that is not part of your current bundle, use the \fBwith_clean_env\fR method with a block\. Any subshells created inside the block will be given the environment present before Bundler was activated\. For example, Homebrew commands run Ruby, but don\'t work inside a bundle: . .IP "" 4 . .nf Bundler\.with_clean_env do `brew install wget` end . .fi . .IP "" 0 . .P Using \fBwith_clean_env\fR is also necessary if you are shelling out to a different bundle\. Any Bundler commands run in a subshell will inherit the current Gemfile, so commands that need to run in the context of a different bundle also need to use \fBwith_clean_env\fR\. . .IP "" 4 . .nf Bundler\.with_clean_env do Dir\.chdir "/other/bundler/project" do `bundle exec \./script` end end . .fi . .IP "" 0 . .P Bundler provides convenience helpers that wrap \fBsystem\fR and \fBexec\fR, and they can be used like this: . .IP "" 4 . .nf Bundler\.clean_system(\'brew install wget\') Bundler\.clean_exec(\'brew install wget\') . .fi . .IP "" 0 . .SH "RUBYGEMS PLUGINS" At present, the Rubygems plugin system requires all files named \fBrubygems_plugin\.rb\fR on the load path of \fIany\fR installed gem when any Ruby code requires \fBrubygems\.rb\fR\. This includes executables installed into the system, like \fBrails\fR, \fBrackup\fR, and \fBrspec\fR\. . .P Since Rubygems plugins can contain arbitrary Ruby code, they commonly end up activating themselves or their dependencies\. . .P For instance, the \fBgemcutter 0\.5\fR gem depended on \fBjson_pure\fR\. If you had that version of gemcutter installed (even if you \fIalso\fR had a newer version without this problem), Rubygems would activate \fBgemcutter 0\.5\fR and \fBjson_pure \fR\. . .P If your Gemfile(5) also contained \fBjson_pure\fR (or a gem with a dependency on \fBjson_pure\fR), the latest version on your system might conflict with the version in your Gemfile(5), or the snapshot version in your \fBGemfile\.lock\fR\. . .P If this happens, bundler will say: . .IP "" 4 . .nf You have already activated json_pure 1\.4\.6 but your Gemfile requires json_pure 1\.4\.3\. Consider using bundle exec\. . .fi . .IP "" 0 . .P In this situation, you almost certainly want to remove the underlying gem with the problematic gem plugin\. In general, the authors of these plugins (in this case, the \fBgemcutter\fR gem) have released newer versions that are more careful in their plugins\. . .P You can find a list of all the gems containing gem plugins by running . .IP "" 4 . .nf ruby \-rrubygems \-e "puts Gem\.find_files(\'rubygems_plugin\.rb\')" . .fi . .IP "" 0 . .P At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren\'t using (\fBgem uninstall gem_name\fR)\. PK ]qq6gems/bundler-2.2.24/lib/bundler/man/bundle-info.1.ronnnu[bundle-info(1) -- Show information for the given gem in your bundle ========================================================================= ## SYNOPSIS `bundle info` [GEM] [--path] ## DESCRIPTION Print the basic information about the provided GEM such as homepage, version, path and summary. ## OPTIONS * `--path`: Print the path of the given gem PK ]Ag885gems/bundler-2.2.24/lib/bundler/man/bundle-platform.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-PLATFORM" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information . .SH "SYNOPSIS" \fBbundle platform\fR [\-\-ruby] . .SH "DESCRIPTION" \fBplatform\fR will display information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\. . .P For instance, using this Gemfile(5): . .IP "" 4 . .nf source "https://rubygems\.org" ruby "1\.9\.3" gem "rack" . .fi . .IP "" 0 . .P If you run \fBbundle platform\fR on Ruby 1\.9\.3, it will display the following output: . .IP "" 4 . .nf Your platform is: x86_64\-linux Your app has gems that work on these platforms: * ruby Your Gemfile specifies a Ruby version requirement: * ruby 1\.9\.3 Your current platform satisfies the Ruby version requirement\. . .fi . .IP "" 0 . .P \fBplatform\fR will list all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It will also let you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn\'t match the running Ruby VM, it will tell you what part does not\. . .SH "OPTIONS" . .TP \fB\-\-ruby\fR It will display the ruby directive information, so you don\'t have to parse it from the Gemfile(5)\. PK ]QdUU-gems/bundler-2.2.24/lib/bundler/man/gemfile.5nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "GEMFILE" "5" "June 2021" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs . .SH "SYNOPSIS" A \fBGemfile\fR describes the gem dependencies required to execute associated Ruby code\. . .P Place the \fBGemfile\fR in the root of the directory containing the associated code\. For instance, in a Rails application, place the \fBGemfile\fR in the same directory as the \fBRakefile\fR\. . .SH "SYNTAX" A \fBGemfile\fR is evaluated as Ruby code, in a context which makes available a number of methods used to describe the gem requirements\. . .SH "GLOBAL SOURCES" At the top of the \fBGemfile\fR, add a line for the \fBRubygems\fR source that contains the gems listed in the \fBGemfile\fR\. . .IP "" 4 . .nf source "https://rubygems\.org" . .fi . .IP "" 0 . .P It is possible, but not recommended as of Bundler 1\.7, to add multiple global \fBsource\fR lines\. Each of these \fBsource\fRs \fBMUST\fR be a valid Rubygems repository\. . .P Sources are checked for gems following the heuristics described in \fISOURCE PRIORITY\fR\. If a gem is found in more than one global source, Bundler will print a warning after installing the gem indicating which source was used, and listing the other sources where the gem is available\. A specific source can be selected for gems that need to use a non\-standard repository, suppressing this warning, by using the \fI\fB:source\fR option\fR or a \fI\fBsource\fR block\fR\. . .SS "CREDENTIALS" Some gem sources require a username and password\. Use bundle config(1) \fIbundle\-config\.1\.html\fR to set the username and password for any of the sources that need it\. The command must be run once on each computer that will install the Gemfile, but this keeps the credentials from being stored in plain text in version control\. . .IP "" 4 . .nf bundle config gems\.example\.com user:password . .fi . .IP "" 0 . .P For some sources, like a company Gemfury account, it may be easier to include the credentials in the Gemfile as part of the source URL\. . .IP "" 4 . .nf source "https://user:password@gems\.example\.com" . .fi . .IP "" 0 . .P Credentials in the source URL will take precedence over credentials set using \fBconfig\fR\. . .SH "RUBY" If your application requires a specific Ruby version or engine, specify your requirements using the \fBruby\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\. . .SS "VERSION (required)" The version of Ruby that your application requires\. If your application requires an alternate Ruby engine, such as JRuby, Rubinius or TruffleRuby, this should be the Ruby version that the engine is compatible with\. . .IP "" 4 . .nf ruby "1\.9\.3" . .fi . .IP "" 0 . .SS "ENGINE" Each application \fImay\fR specify a Ruby engine\. If an engine is specified, an engine version \fImust\fR also be specified\. . .P What exactly is an Engine? \- A Ruby engine is an implementation of the Ruby language\. . .IP "\(bu" 4 For background: the reference or original implementation of the Ruby programming language is called Matz\'s Ruby Interpreter \fIhttps://en\.wikipedia\.org/wiki/Ruby_MRI\fR, or MRI for short\. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz\. MRI is also known as CRuby, because it is written in C\. MRI is the most widely used Ruby engine\. . .IP "\(bu" 4 Other implementations \fIhttps://www\.ruby\-lang\.org/en/about/\fR of Ruby exist\. Some of the more well\-known implementations include Rubinius \fIhttps://rubinius\.com/\fR, and JRuby \fIhttp://jruby\.org/\fR\. Rubinius is an alternative implementation of Ruby written in Ruby\. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine\. . .IP "" 0 . .SS "ENGINE VERSION" Each application \fImay\fR specify a Ruby engine version\. If an engine version is specified, an engine \fImust\fR also be specified\. If the engine is "ruby" the engine version specified \fImust\fR match the Ruby version\. . .IP "" 4 . .nf ruby "1\.8\.7", :engine => "jruby", :engine_version => "1\.6\.7" . .fi . .IP "" 0 . .SS "PATCHLEVEL" Each application \fImay\fR specify a Ruby patchlevel\. . .IP "" 4 . .nf ruby "2\.0\.0", :patchlevel => "247" . .fi . .IP "" 0 . .SH "GEMS" Specify gem requirements using the \fBgem\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\. . .SS "NAME (required)" For each gem requirement, list a single \fIgem\fR line\. . .IP "" 4 . .nf gem "nokogiri" . .fi . .IP "" 0 . .SS "VERSION" Each \fIgem\fR \fBMAY\fR have one or more version specifiers\. . .IP "" 4 . .nf gem "nokogiri", ">= 1\.4\.2" gem "RedCloth", ">= 4\.1\.0", "< 4\.2\.0" . .fi . .IP "" 0 . .SS "REQUIRE AS" Each \fIgem\fR \fBMAY\fR specify files that should be used when autorequiring via \fBBundler\.require\fR\. You may pass an array with multiple files or \fBtrue\fR if the file you want \fBrequired\fR has the same name as \fIgem\fR or \fBfalse\fR to prevent any file from being autorequired\. . .IP "" 4 . .nf gem "redis", :require => ["redis/connection/hiredis", "redis"] gem "webmock", :require => false gem "byebug", :require => true . .fi . .IP "" 0 . .P The argument defaults to the name of the gem\. For example, these are identical: . .IP "" 4 . .nf gem "nokogiri" gem "nokogiri", :require => "nokogiri" gem "nokogiri", :require => true . .fi . .IP "" 0 . .SS "GROUPS" Each \fIgem\fR \fBMAY\fR specify membership in one or more groups\. Any \fIgem\fR that does not specify membership in any group is placed in the \fBdefault\fR group\. . .IP "" 4 . .nf gem "rspec", :group => :test gem "wirble", :groups => [:development, :test] . .fi . .IP "" 0 . .P The Bundler runtime allows its two main methods, \fBBundler\.setup\fR and \fBBundler\.require\fR, to limit their impact to particular groups\. . .IP "" 4 . .nf # setup adds gems to Ruby\'s load path Bundler\.setup # defaults to all groups require "bundler/setup" # same as Bundler\.setup Bundler\.setup(:default) # only set up the _default_ group Bundler\.setup(:test) # only set up the _test_ group (but `not` _default_) Bundler\.setup(:default, :test) # set up the _default_ and _test_ groups, but no others # require requires all of the gems in the specified groups Bundler\.require # defaults to the _default_ group Bundler\.require(:default) # identical Bundler\.require(:default, :test) # requires the _default_ and _test_ groups Bundler\.require(:test) # requires the _test_ group . .fi . .IP "" 0 . .P The Bundler CLI allows you to specify a list of groups whose gems \fBbundle install\fR should not install with the \fBwithout\fR configuration\. . .P To specify multiple groups to ignore, specify a list of groups separated by spaces\. . .IP "" 4 . .nf bundle config set \-\-local without test bundle config set \-\-local without development test . .fi . .IP "" 0 . .P Also, calling \fBBundler\.setup\fR with no parameters, or calling \fBrequire "bundler/setup"\fR will setup all groups except for the ones you excluded via \fB\-\-without\fR (since they are not available)\. . .P Note that on \fBbundle install\fR, bundler downloads and evaluates all gems, in order to create a single canonical list of all of the required gems and their dependencies\. This means that you cannot list different versions of the same gems in different groups\. For more details, see Understanding Bundler \fIhttps://bundler\.io/rationale\.html\fR\. . .SS "PLATFORMS" If a gem should only be used in a particular platform or set of platforms, you can specify them\. Platforms are essentially identical to groups, except that you do not need to use the \fB\-\-without\fR install\-time flag to exclude groups of gems for other platforms\. . .P There are a number of \fBGemfile\fR platforms: . .TP \fBruby\fR C Ruby (MRI), Rubinius or TruffleRuby, but \fBNOT\fR Windows . .TP \fBmri\fR Same as \fIruby\fR, but only C Ruby (MRI) . .TP \fBmingw\fR Windows 32 bit \'mingw32\' platform (aka RubyInstaller) . .TP \fBx64_mingw\fR Windows 64 bit \'mingw32\' platform (aka RubyInstaller x64) . .TP \fBrbx\fR Rubinius . .TP \fBjruby\fR JRuby . .TP \fBtruffleruby\fR TruffleRuby . .TP \fBmswin\fR Windows . .P You can restrict further by platform and version for all platforms \fIexcept\fR for \fBrbx\fR, \fBjruby\fR, \fBtruffleruby\fR and \fBmswin\fR\. . .P To specify a version in addition to a platform, append the version number without the delimiter to the platform\. For example, to specify that a gem should only be used on platforms with Ruby 2\.3, use: . .IP "" 4 . .nf ruby_23 . .fi . .IP "" 0 . .P The full list of platforms and supported versions includes: . .TP \fBruby\fR 1\.8, 1\.9, 2\.0, 2\.1, 2\.2, 2\.3, 2\.4, 2\.5, 2\.6 . .TP \fBmri\fR 1\.8, 1\.9, 2\.0, 2\.1, 2\.2, 2\.3, 2\.4, 2\.5, 2\.6 . .TP \fBmingw\fR 1\.8, 1\.9, 2\.0, 2\.1, 2\.2, 2\.3, 2\.4, 2\.5, 2\.6 . .TP \fBx64_mingw\fR 2\.0, 2\.1, 2\.2, 2\.3, 2\.4, 2\.5, 2\.6 . .P As with groups, you can specify one or more platforms: . .IP "" 4 . .nf gem "weakling", :platforms => :jruby gem "ruby\-debug", :platforms => :mri_18 gem "nokogiri", :platforms => [:mri_18, :jruby] . .fi . .IP "" 0 . .P All operations involving groups (\fBbundle install\fR \fIbundle\-install\.1\.html\fR, \fBBundler\.setup\fR, \fBBundler\.require\fR) behave exactly the same as if any groups not matching the current platform were explicitly excluded\. . .SS "SOURCE" You can select an alternate Rubygems repository for a gem using the \':source\' option\. . .IP "" 4 . .nf gem "some_internal_gem", :source => "https://gems\.example\.com" . .fi . .IP "" 0 . .P This forces the gem to be loaded from this source and ignores any global sources declared at the top level of the file\. If the gem does not exist in this source, it will not be installed\. . .P Bundler will search for child dependencies of this gem by first looking in the source selected for the parent, but if they are not found there, it will fall back on global sources using the ordering described in \fISOURCE PRIORITY\fR\. . .P Selecting a specific source repository this way also suppresses the ambiguous gem warning described above in \fIGLOBAL SOURCES (#source)\fR\. . .P Using the \fB:source\fR option for an individual gem will also make that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when adding gems with explicit sources, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources\. . .SS "GIT" If necessary, you can specify that a gem is located at a particular git repository using the \fB:git\fR parameter\. The repository can be accessed via several protocols: . .TP \fBHTTP(S)\fR gem "rails", :git => "https://github\.com/rails/rails\.git" . .TP \fBSSH\fR gem "rails", :git => "git@github\.com:rails/rails\.git" . .TP \fBgit\fR gem "rails", :git => "git://github\.com/rails/rails\.git" . .P If using SSH, the user that you use to run \fBbundle install\fR \fBMUST\fR have the appropriate keys available in their \fB$HOME/\.ssh\fR\. . .P \fBNOTE\fR: \fBhttp://\fR and \fBgit://\fR URLs should be avoided if at all possible\. These protocols are unauthenticated, so a man\-in\-the\-middle attacker can deliver malicious code and compromise your system\. HTTPS and SSH are strongly preferred\. . .P The \fBgroup\fR, \fBplatforms\fR, and \fBrequire\fR options are available and behave exactly the same as they would for a normal gem\. . .P A git repository \fBSHOULD\fR have at least one file, at the root of the directory containing the gem, with the extension \fB\.gemspec\fR\. This file \fBMUST\fR contain a valid gem specification, as expected by the \fBgem build\fR command\. . .P If a git repository does not have a \fB\.gemspec\fR, bundler will attempt to create one, but it will not contain any dependencies, executables, or C extension compilation instructions\. As a result, it may fail to properly integrate into your application\. . .P If a git repository does have a \fB\.gemspec\fR for the gem you attached it to, a version specifier, if provided, means that the git repository is only valid if the \fB\.gemspec\fR specifies a version matching the version specifier\. If not, bundler will print a warning\. . .IP "" 4 . .nf gem "rails", "2\.3\.8", :git => "https://github\.com/rails/rails\.git" # bundle install will fail, because the \.gemspec in the rails # repository\'s master branch specifies version 3\.0\.0 . .fi . .IP "" 0 . .P If a git repository does \fBnot\fR have a \fB\.gemspec\fR for the gem you attached it to, a version specifier \fBMUST\fR be provided\. Bundler will use this version in the simple \fB\.gemspec\fR it creates\. . .P Git repositories support a number of additional options\. . .TP \fBbranch\fR, \fBtag\fR, and \fBref\fR You \fBMUST\fR only specify at most one of these options\. The default is \fB:branch => "master"\fR\. For example: . .IP gem "rails", :git => "https://github\.com/rails/rails\.git", :branch => "5\-0\-stable" . .IP gem "rails", :git => "https://github\.com/rails/rails\.git", :tag => "v5\.0\.0" . .IP gem "rails", :git => "https://github\.com/rails/rails\.git", :ref => "4aded" . .TP \fBsubmodules\fR For reference, a git submodule \fIhttps://git\-scm\.com/book/en/v2/Git\-Tools\-Submodules\fR lets you have another git repository within a subfolder of your repository\. Specify \fB:submodules => true\fR to cause bundler to expand any submodules included in the git repository . .P If a git repository contains multiple \fB\.gemspecs\fR, each \fB\.gemspec\fR represents a gem located at the same place in the file system as the \fB\.gemspec\fR\. . .IP "" 4 . .nf |~rails [git root] | |\-rails\.gemspec [rails gem located here] |~actionpack | |\-actionpack\.gemspec [actionpack gem located here] |~activesupport | |\-activesupport\.gemspec [activesupport gem located here] |\.\.\. . .fi . .IP "" 0 . .P To install a gem located in a git repository, bundler changes to the directory containing the gemspec, runs \fBgem build name\.gemspec\fR and then installs the resulting gem\. The \fBgem build\fR command, which comes standard with Rubygems, evaluates the \fB\.gemspec\fR in the context of the directory in which it is located\. . .SS "GIT SOURCE" A custom git source can be defined via the \fBgit_source\fR method\. Provide the source\'s name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address: . .IP "" 4 . .nf git_source(:stash){ |repo_name| "https://stash\.corp\.acme\.pl/#{repo_name}\.git" } gem \'rails\', :stash => \'forks/rails\' . .fi . .IP "" 0 . .P In addition, if you wish to choose a specific branch: . .IP "" 4 . .nf gem "rails", :stash => "forks/rails", :branch => "branch_name" . .fi . .IP "" 0 . .SS "GITHUB" \fBNOTE\fR: This shorthand should be avoided until Bundler 2\.0, since it currently expands to an insecure \fBgit://\fR URL\. This allows a man\-in\-the\-middle attacker to compromise your system\. . .P If the git repository you want to use is hosted on GitHub and is public, you can use the :github shorthand to specify the github username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\. . .IP "" 4 . .nf gem "rails", :github => "rails/rails" gem "rails", :github => "rails" . .fi . .IP "" 0 . .P Are both equivalent to . .IP "" 4 . .nf gem "rails", :git => "git://github\.com/rails/rails\.git" . .fi . .IP "" 0 . .P Since the \fBgithub\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. . .SS "GIST" If the git repository you want to use is hosted as a Github Gist and is public, you can use the :gist shorthand to specify the gist identifier (without the trailing "\.git")\. . .IP "" 4 . .nf gem "the_hatch", :gist => "4815162342" . .fi . .IP "" 0 . .P Is equivalent to: . .IP "" 4 . .nf gem "the_hatch", :git => "https://gist\.github\.com/4815162342\.git" . .fi . .IP "" 0 . .P Since the \fBgist\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. . .SS "BITBUCKET" If the git repository you want to use is hosted on Bitbucket and is public, you can use the :bitbucket shorthand to specify the bitbucket username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\. . .IP "" 4 . .nf gem "rails", :bitbucket => "rails/rails" gem "rails", :bitbucket => "rails" . .fi . .IP "" 0 . .P Are both equivalent to . .IP "" 4 . .nf gem "rails", :git => "https://rails@bitbucket\.org/rails/rails\.git" . .fi . .IP "" 0 . .P Since the \fBbitbucket\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. . .SS "PATH" You can specify that a gem is located in a particular location on the file system\. Relative paths are resolved relative to the directory containing the \fBGemfile\fR\. . .P Similar to the semantics of the \fB:git\fR option, the \fB:path\fR option requires that the directory in question either contains a \fB\.gemspec\fR for the gem, or that you specify an explicit version that bundler should use\. . .P Unlike \fB:git\fR, bundler does not compile C extensions for gems specified as paths\. . .IP "" 4 . .nf gem "rails", :path => "vendor/rails" . .fi . .IP "" 0 . .P If you would like to use multiple local gems directly from the filesystem, you can set a global \fBpath\fR option to the path containing the gem\'s files\. This will automatically load gemspec files from subdirectories\. . .IP "" 4 . .nf path \'components\' do gem \'admin_ui\' gem \'public_ui\' end . .fi . .IP "" 0 . .SH "BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS" The \fB:source\fR, \fB:git\fR, \fB:path\fR, \fB:group\fR, and \fB:platforms\fR options may be applied to a group of gems by using block form\. . .IP "" 4 . .nf source "https://gems\.example\.com" do gem "some_internal_gem" gem "another_internal_gem" end git "https://github\.com/rails/rails\.git" do gem "activesupport" gem "actionpack" end platforms :ruby do gem "ruby\-debug" gem "sqlite3" end group :development, :optional => true do gem "wirble" gem "faker" end . .fi . .IP "" 0 . .P In the case of the group block form the :optional option can be given to prevent a group from being installed unless listed in the \fB\-\-with\fR option given to the \fBbundle install\fR command\. . .P In the case of the \fBgit\fR block form, the \fB:ref\fR, \fB:branch\fR, \fB:tag\fR, and \fB:submodules\fR options may be passed to the \fBgit\fR method, and all gems in the block will inherit those options\. . .P The presence of a \fBsource\fR block in a Gemfile also makes that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when defining source blocks, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources, either via source blocks or \fB:source\fR directives on individual gems\. . .SH "INSTALL_IF" The \fBinstall_if\fR method allows gems to be installed based on a proc or lambda\. This is especially useful for optional gems that can only be used if certain software is installed or some other conditions are met\. . .IP "" 4 . .nf install_if \-> { RUBY_PLATFORM =~ /darwin/ } do gem "pasteboard" end . .fi . .IP "" 0 . .SH "GEMSPEC" The \fB\.gemspec\fR \fIhttp://guides\.rubygems\.org/specification\-reference/\fR file is where you provide metadata about your gem to Rubygems\. Some required Gemspec attributes include the name, description, and homepage of your gem\. This is also where you specify the dependencies your gem needs to run\. . .P If you wish to use Bundler to help install dependencies for a gem while it is being developed, use the \fBgemspec\fR method to pull in the dependencies listed in the \fB\.gemspec\fR file\. . .P The \fBgemspec\fR method adds any runtime dependencies as gem requirements in the default group\. It also adds development dependencies as gem requirements in the \fBdevelopment\fR group\. Finally, it adds a gem requirement on your project (\fB:path => \'\.\'\fR)\. In conjunction with \fBBundler\.setup\fR, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths\. . .P The \fBgemspec\fR method supports optional \fB:path\fR, \fB:glob\fR, \fB:name\fR, and \fB:development_group\fR options, which control where bundler looks for the \fB\.gemspec\fR, the glob it uses to look for the gemspec (defaults to: "{,\fI,\fR/*}\.gemspec"), what named \fB\.gemspec\fR it uses (if more than one is present), and which group development dependencies are included in\. . .P When a \fBgemspec\fR dependency encounters version conflicts during resolution, the local version under development will always be selected \-\- even if there are remote versions that better match other requirements for the \fBgemspec\fR gem\. . .SH "SOURCE PRIORITY" When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order: . .IP "1." 4 The source explicitly attached to the gem (using \fB:source\fR, \fB:path\fR, or \fB:git\fR) . .IP "2." 4 For implicit gems (dependencies of explicit gems), any source, git, or path repository declared on the parent\. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from \fBrubygems\.org\fR . .IP "3." 4 The sources specified via global \fBsource\fR lines, searching each source in your \fBGemfile\fR from last added to first added\. . .IP "" 0 PK ]n½1gems/bundler-2.2.24/lib/bundler/man/bundle-info.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-INFO" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle . .SH "SYNOPSIS" \fBbundle info\fR [GEM] [\-\-path] . .SH "DESCRIPTION" Print the basic information about the provided GEM such as homepage, version, path and summary\. . .SH "OPTIONS" . .TP \fB\-\-path\fR Print the path of the given gem PK ]6H8gems/bundler-2.2.24/lib/bundler/man/bundle-doctor.1.ronnnu[bundle-doctor(1) -- Checks the bundle for common problems ========================================================= ## SYNOPSIS `bundle doctor` [--quiet] [--gemfile=GEMFILE] ## DESCRIPTION Checks your Gemfile and gem environment for common problems. If issues are detected, Bundler prints them and exits status 1. Otherwise, Bundler prints a success message and exits status 0. Examples of common problems caught by bundle-doctor include: * Invalid Bundler settings * Mismatched Ruby versions * Mismatched platforms * Uninstalled gems * Missing dependencies ## OPTIONS * `--quiet`: Only output warnings and errors. * `--gemfile=`: The location of the Gemfile(5) which Bundler should use. This defaults to a Gemfile(5) in the current working directory. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find `Gemfile.lock` and `vendor/cache` relative to this location. PK ]8XX2gems/bundler-2.2.24/lib/bundler/man/bundle-clean.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-CLEAN" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory . .SH "SYNOPSIS" \fBbundle clean\fR [\-\-dry\-run] [\-\-force] . .SH "DESCRIPTION" This command will remove all unused gems in your bundler directory\. This is useful when you have made many changes to your gem dependencies\. . .SH "OPTIONS" . .TP \fB\-\-dry\-run\fR Print the changes, but do not clean the unused gems\. . .TP \fB\-\-force\fR Force a clean even if \fB\-\-path\fR is not set\. PK ]Y|LL5gems/bundler-2.2.24/lib/bundler/man/bundle-binstubs.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-BINSTUBS" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems . .SH "SYNOPSIS" \fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-path PATH] [\-\-standalone] . .SH "DESCRIPTION" Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into \fBbin/\fR\. Binstubs are a shortcut\-or alternative\- to always using \fBbundle exec\fR\. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application\. . .P For example, if you run \fBbundle binstubs rspec\-core\fR, Bundler will create the file \fBbin/rspec\fR\. That file will contain enough code to load Bundler, tell it to load the bundled gems, and then run rspec\. . .P This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the \fB\-\-path\fR directory if one has been set\. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems\. . .SH "OPTIONS" . .TP \fB\-\-force\fR Overwrite existing binstubs if they exist\. . .TP \fB\-\-path\fR The location to install the specified binstubs to\. This defaults to \fBbin\fR\. . .TP \fB\-\-standalone\fR Makes binstubs that can work without depending on Rubygems or Bundler at runtime\. . .TP \fB\-\-shebang\fR Specify a different shebang executable name than the default (default \'ruby\') . .TP \fB\-\-all\fR Create binstubs for all gems in the bundle\. PK ]V#6gems/bundler-2.2.24/lib/bundler/man/bundle-list.1.ronnnu[bundle-list(1) -- List all the gems in the bundle ========================================================================= ## SYNOPSIS `bundle list` [--name-only] [--paths] [--without-group=GROUP[ GROUP...]] [--only-group=GROUP[ GROUP...]] ## DESCRIPTION Prints a list of all the gems in the bundle including their version. Example: bundle list --name-only bundle list --paths bundle list --without-group test bundle list --only-group dev bundle list --only-group dev test --paths ## OPTIONS * `--name-only`: Print only the name of each gem. * `--paths`: Print the path to each gem in the bundle. * `--without-group=`: A space-separated list of groups of gems to skip during printing. * `--only-group=`: A space-separated list of groups of gems to print. PK ]#s:gems/bundler-2.2.24/lib/bundler/man/bundle-pristine.1.ronnnu[bundle-pristine(1) -- Restores installed gems to their pristine condition =========================================================================== ## SYNOPSIS `bundle pristine` ## DESCRIPTION `pristine` restores the installed gems in the bundle to their pristine condition using the local gem cache from RubyGems. For git gems, a forced checkout will be performed. For further explanation, `bundle pristine` ignores unpacked files on disk. In other words, this command utilizes the local `.gem` cache or the gem's git repository as if one were installing from scratch. Note: the Bundler gem cannot be restored to its original state with `pristine`. One also cannot use `bundle pristine` on gems with a 'path' option in the Gemfile, because bundler has no original copy it can restore from. When is it practical to use `bundle pristine`? It comes in handy when a developer is debugging a gem. `bundle pristine` is a great way to get rid of experimental changes to a gem that one may not want. Why use `bundle pristine` over `gem pristine --all`? Both commands are very similar. For context: `bundle pristine`, without arguments, cleans all gems from the lockfile. Meanwhile, `gem pristine --all` cleans all installed gems for that Ruby version. If a developer forgets which gems in their project they might have been debugging, the Rubygems `gem pristine [GEMNAME]` command may be inconvenient. One can avoid waiting for `gem pristine --all`, and instead run `bundle pristine`. PK ]C..5gems/bundler-2.2.24/lib/bundler/man/bundle-gem.1.ronnnu[bundle-gem(1) -- Generate a project skeleton for creating a rubygem ==================================================================== ## SYNOPSIS `bundle gem` [OPTIONS] ## DESCRIPTION Generates a directory named `GEM_NAME` with a `Rakefile`, `GEM_NAME.gemspec`, and other supporting files and directories that can be used to develop a rubygem with that name. Run `rake -T` in the resulting project for a list of Rake tasks that can be used to test and publish the gem to rubygems.org. The generated project skeleton can be customized with OPTIONS, as explained below. Note that these options can also be specified via Bundler's global configuration file using the following names: * `gem.coc` * `gem.mit` * `gem.test` ## OPTIONS * `--exe` or `-b` or `--bin`: Specify that Bundler should create a binary executable (as `exe/GEM_NAME`) in the generated rubygem project. This binary will also be added to the `GEM_NAME.gemspec` manifest. This behavior is disabled by default. * `--no-exe`: Do not create a binary (overrides `--exe` specified in the global config). * `--coc`: Add a `CODE_OF_CONDUCT.md` file to the root of the generated project. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future `bundle gem` use. * `--no-coc`: Do not create a `CODE_OF_CONDUCT.md` (overrides `--coc` specified in the global config). * `--ext`: Add boilerplate for C extension code to the generated project. This behavior is disabled by default. * `--no-ext`: Do not add C extension code (overrides `--ext` specified in the global config). * `--mit`: Add an MIT license to a `LICENSE.txt` file in the root of the generated project. Your name from the global git config is used for the copyright statement. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future `bundle gem` use. * `--no-mit`: Do not create a `LICENSE.txt` (overrides `--mit` specified in the global config). * `-t`, `--test=minitest`, `--test=rspec`, `--test=test-unit`: Specify the test framework that Bundler should use when generating the project. Acceptable values are `minitest`, `rspec` and `test-unit`. The `GEM_NAME.gemspec` will be configured and a skeleton test/spec directory will be created based on this option. Given no option is specified: When Bundler is configured to generate tests, this defaults to Bundler's global config setting `gem.test`. When Bundler is configured to not generate tests, an interactive prompt will be displayed and the answer will be used for the current rubygem project. When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future `bundle gem` use. * `--ci`, `--ci=github`, `--ci=travis`, `--ci=gitlab`, `--ci=circle`: Specify the continuous integration service that Bundler should use when generating the project. Acceptable values are `github`, `travis`, `gitlab` and `circle`. A configuration file will be generated in the project directory. Given no option is specified: When Bundler is configured to generate CI files, this defaults to Bundler's global config setting `gem.ci`. When Bundler is configured to not generate CI files, an interactive prompt will be displayed and the answer will be used for the current rubygem project. When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future `bundle gem` use. * `-e`, `--edit[=EDITOR]`: Open the resulting GEM_NAME.gemspec in EDITOR, or the default editor if not specified. The default is `$BUNDLER_EDITOR`, `$VISUAL`, or `$EDITOR`. ## SEE ALSO * [bundle config(1)](bundle-config.1.html) PK ]^-0gems/bundler-2.2.24/lib/bundler/man/bundle-gem.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-GEM" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem . .SH "SYNOPSIS" \fBbundle gem\fR \fIGEM_NAME\fR \fIOPTIONS\fR . .SH "DESCRIPTION" Generates a directory named \fBGEM_NAME\fR with a \fBRakefile\fR, \fBGEM_NAME\.gemspec\fR, and other supporting files and directories that can be used to develop a rubygem with that name\. . .P Run \fBrake \-T\fR in the resulting project for a list of Rake tasks that can be used to test and publish the gem to rubygems\.org\. . .P The generated project skeleton can be customized with OPTIONS, as explained below\. Note that these options can also be specified via Bundler\'s global configuration file using the following names: . .IP "\(bu" 4 \fBgem\.coc\fR . .IP "\(bu" 4 \fBgem\.mit\fR . .IP "\(bu" 4 \fBgem\.test\fR . .IP "" 0 . .SH "OPTIONS" . .TP \fB\-\-exe\fR or \fB\-b\fR or \fB\-\-bin\fR Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\. . .TP \fB\-\-no\-exe\fR Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\. . .TP \fB\-\-coc\fR Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . .TP \fB\-\-no\-coc\fR Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\. . .TP \fB\-\-ext\fR Add boilerplate for C extension code to the generated project\. This behavior is disabled by default\. . .TP \fB\-\-no\-ext\fR Do not add C extension code (overrides \fB\-\-ext\fR specified in the global config)\. . .TP \fB\-\-mit\fR Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . .TP \fB\-\-no\-mit\fR Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\. . .TP \fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified: . .IP When Bundler is configured to generate tests, this defaults to Bundler\'s global config setting \fBgem\.test\fR\. . .IP When Bundler is configured to not generate tests, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. . .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . .TP \fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=travis\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBtravis\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified: . .IP When Bundler is configured to generate CI files, this defaults to Bundler\'s global config setting \fBgem\.ci\fR\. . .IP When Bundler is configured to not generate CI files, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. . .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . .TP \fB\-e\fR, \fB\-\-edit[=EDITOR]\fR Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\. . .SH "SEE ALSO" . .IP "\(bu" 4 bundle config(1) \fIbundle\-config\.1\.html\fR . .IP "" 0 PK ]56gems/bundler-2.2.24/lib/bundler/man/bundle-open.1.ronnnu[bundle-open(1) -- Opens the source directory for a gem in your bundle ===================================================================== ## SYNOPSIS `bundle open` [GEM] ## DESCRIPTION Opens the source directory of the provided GEM in your editor. For this to work the `EDITOR` or `BUNDLER_EDITOR` environment variable has to be set. Example: bundle open 'rack' Will open the source directory for the 'rack' gem in your bundle. PK ]P~||6gems/bundler-2.2.24/lib/bundler/man/bundle-exec.1.ronnnu[bundle-exec(1) -- Execute a command in the context of the bundle ================================================================ ## SYNOPSIS `bundle exec` [--keep-file-descriptors] ## DESCRIPTION This command executes the command, making all gems specified in the [`Gemfile(5)`][Gemfile(5)] available to `require` in Ruby programs. Essentially, if you would normally have run something like `rspec spec/my_spec.rb`, and you want to use the gems specified in the [`Gemfile(5)`][Gemfile(5)] and installed via [bundle install(1)](bundle-install.1.html), you should run `bundle exec rspec spec/my_spec.rb`. Note that `bundle exec` does not require that an executable is available on your shell's `$PATH`. ## OPTIONS * `--keep-file-descriptors`: Exec in Ruby 2.0 began discarding non-standard file descriptors. When this flag is passed, exec will revert to the 1.9 behaviour of passing all file descriptors to the new process. ## BUNDLE INSTALL --BINSTUBS If you use the `--binstubs` flag in [bundle install(1)](bundle-install.1.html), Bundler will automatically create a directory (which defaults to `app_root/bin`) containing all of the executables available from gems in the bundle. After using `--binstubs`, `bin/rspec spec/my_spec.rb` is identical to `bundle exec rspec spec/my_spec.rb`. ## ENVIRONMENT MODIFICATIONS `bundle exec` makes a number of changes to the shell environment, then executes the command you specify in full. * make sure that it's still possible to shell out to `bundle` from inside a command invoked by `bundle exec` (using `$BUNDLE_BIN_PATH`) * put the directory containing executables (like `rails`, `rspec`, `rackup`) for your bundle on `$PATH` * make sure that if bundler is invoked in the subshell, it uses the same `Gemfile` (by setting `BUNDLE_GEMFILE`) * add `-rbundler/setup` to `$RUBYOPT`, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle It also modifies Rubygems: * disallow loading additional gems not in the bundle * modify the `gem` method to be a no-op if a gem matching the requirements is in the bundle, and to raise a `Gem::LoadError` if it's not * Define `Gem.refresh` to be a no-op, since the source index is always frozen when using bundler, and to prevent gems from the system leaking into the environment * Override `Gem.bin_path` to use the gems in the bundle, making system executables work * Add all gems in the bundle into Gem.loaded_specs Finally, `bundle exec` also implicitly modifies `Gemfile.lock` if the lockfile and the Gemfile do not match. Bundler needs the Gemfile to determine things such as a gem's groups, `autorequire`, and platforms, etc., and that information isn't stored in the lockfile. The Gemfile and lockfile must be synced in order to `bundle exec` successfully, so `bundle exec` updates the lockfile beforehand. ### Loading By default, when attempting to `bundle exec` to a file with a ruby shebang, Bundler will `Kernel.load` that file instead of using `Kernel.exec`. For the vast majority of cases, this is a performance improvement. In a rare few cases, this could cause some subtle side-effects (such as dependence on the exact contents of `$0` or `__FILE__`) and the optimization can be disabled by enabling the `disable_exec_load` setting. ### Shelling out Any Ruby code that opens a subshell (like `system`, backticks, or `%x{}`) will automatically use the current Bundler environment. If you need to shell out to a Ruby command that is not part of your current bundle, use the `with_clean_env` method with a block. Any subshells created inside the block will be given the environment present before Bundler was activated. For example, Homebrew commands run Ruby, but don't work inside a bundle: Bundler.with_clean_env do `brew install wget` end Using `with_clean_env` is also necessary if you are shelling out to a different bundle. Any Bundler commands run in a subshell will inherit the current Gemfile, so commands that need to run in the context of a different bundle also need to use `with_clean_env`. Bundler.with_clean_env do Dir.chdir "/other/bundler/project" do `bundle exec ./script` end end Bundler provides convenience helpers that wrap `system` and `exec`, and they can be used like this: Bundler.clean_system('brew install wget') Bundler.clean_exec('brew install wget') ## RUBYGEMS PLUGINS At present, the Rubygems plugin system requires all files named `rubygems_plugin.rb` on the load path of _any_ installed gem when any Ruby code requires `rubygems.rb`. This includes executables installed into the system, like `rails`, `rackup`, and `rspec`. Since Rubygems plugins can contain arbitrary Ruby code, they commonly end up activating themselves or their dependencies. For instance, the `gemcutter 0.5` gem depended on `json_pure`. If you had that version of gemcutter installed (even if you _also_ had a newer version without this problem), Rubygems would activate `gemcutter 0.5` and `json_pure `. If your Gemfile(5) also contained `json_pure` (or a gem with a dependency on `json_pure`), the latest version on your system might conflict with the version in your Gemfile(5), or the snapshot version in your `Gemfile.lock`. If this happens, bundler will say: You have already activated json_pure 1.4.6 but your Gemfile requires json_pure 1.4.3. Consider using bundle exec. In this situation, you almost certainly want to remove the underlying gem with the problematic gem plugin. In general, the authors of these plugins (in this case, the `gemcutter` gem) have released newer versions that are more careful in their plugins. You can find a list of all the gems containing gem plugins by running ruby -rrubygems -e "puts Gem.find_files('rubygems_plugin.rb')" At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren't using (`gem uninstall gem_name`). PK ]w,w118gems/bundler-2.2.24/lib/bundler/man/bundle-update.1.ronnnu[bundle-update(1) -- Update your gems to the latest available versions ===================================================================== ## SYNOPSIS `bundle update` <*gems> [--all] [--group=NAME] [--source=NAME] [--local] [--ruby] [--bundler[=VERSION]] [--full-index] [--jobs=JOBS] [--quiet] [--patch|--minor|--major] [--redownload] [--strict] [--conservative] ## DESCRIPTION Update the gems specified (all gems, if `--all` flag is used), ignoring the previously installed gems specified in the `Gemfile.lock`. In general, you should use [bundle install(1)](bundle-install.1.html) to install the same exact gems and versions across machines. You would use `bundle update` to explicitly update the version of a gem. ## OPTIONS * `--all`: Update all gems specified in Gemfile. * `--group=`, `-g=[]`: Only update the gems in the specified group. For instance, you can update all gems in the development group with `bundle update --group development`. You can also call `bundle update rails --group test` to update the rails gem and all gems in the test group, for example. * `--source=`: The name of a `:git` or `:path` source used in the Gemfile(5). For instance, with a `:git` source of `http://github.com/rails/rails.git`, you would call `bundle update --source rails` * `--local`: Do not attempt to fetch gems remotely and use the gem cache instead. * `--ruby`: Update the locked version of Ruby to the current version of Ruby. * `--bundler`: Update the locked version of bundler to the invoked bundler version. * `--full-index`: Fall back to using the single-file index of all gems. * `--jobs=[]`, `-j[]`: Specify the number of jobs to run in parallel. The default is `1`. * `--retry=[]`: Retry failed network or git requests for times. * `--quiet`: Only output warnings and errors. * `--redownload`: Force downloading every gem. * `--patch`: Prefer updating only to next patch version. * `--minor`: Prefer updating only to next minor version. * `--major`: Prefer updating to next major version (default). * `--strict`: Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. * `--conservative`: Use bundle install conservative update behavior and do not allow indirect dependencies to be updated. ## UPDATING ALL GEMS If you run `bundle update --all`, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources. Consider the following Gemfile(5): source "https://rubygems.org" gem "rails", "3.0.0.rc" gem "nokogiri" When you run [bundle install(1)](bundle-install.1.html) the first time, bundler will resolve all of the dependencies, all the way down, and install what you need: Fetching gem metadata from https://rubygems.org/......... Resolving dependencies... Installing builder 2.1.2 Installing abstract 1.0.0 Installing rack 1.2.8 Using bundler 1.7.6 Installing rake 10.4.0 Installing polyglot 0.3.5 Installing mime-types 1.25.1 Installing i18n 0.4.2 Installing mini_portile 0.6.1 Installing tzinfo 0.3.42 Installing rack-mount 0.6.14 Installing rack-test 0.5.7 Installing treetop 1.4.15 Installing thor 0.14.6 Installing activesupport 3.0.0.rc Installing erubis 2.6.6 Installing activemodel 3.0.0.rc Installing arel 0.4.0 Installing mail 2.2.20 Installing activeresource 3.0.0.rc Installing actionpack 3.0.0.rc Installing activerecord 3.0.0.rc Installing actionmailer 3.0.0.rc Installing railties 3.0.0.rc Installing rails 3.0.0.rc Installing nokogiri 1.6.5 Bundle complete! 2 Gemfile dependencies, 26 gems total. Use `bundle show [gemname]` to see where a bundled gem is installed. As you can see, even though you have two gems in the Gemfile(5), your application needs 26 different gems in order to run. Bundler remembers the exact versions it installed in `Gemfile.lock`. The next time you run [bundle install(1)](bundle-install.1.html), bundler skips the dependency resolution and installs the same gems as it installed last time. After checking in the `Gemfile.lock` into version control and cloning it on another machine, running [bundle install(1)](bundle-install.1.html) will _still_ install the gems that you installed last time. You don't need to worry that a new release of `erubis` or `mail` changes the gems you use. However, from time to time, you might want to update the gems you are using to the newest versions that still match the gems in your Gemfile(5). To do this, run `bundle update --all`, which will ignore the `Gemfile.lock`, and resolve all the dependencies again. Keep in mind that this process can result in a significantly different set of the 25 gems, based on the requirements of new gems that the gem authors released since the last time you ran `bundle update --all`. ## UPDATING A LIST OF GEMS Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the `Gemfile.lock`. For instance, in the scenario above, imagine that `nokogiri` releases version `1.4.4`, and you want to update it _without_ updating Rails and all of its dependencies. To do this, run `bundle update nokogiri`. Bundler will update `nokogiri` and any of its dependencies, but leave alone Rails and its dependencies. ## OVERLAPPING DEPENDENCIES Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same second-level dependency. For instance, consider the case of `thin` and `rack-perftools-profiler`. source "https://rubygems.org" gem "thin" gem "rack-perftools-profiler" The `thin` gem depends on `rack >= 1.0`, while `rack-perftools-profiler` depends on `rack ~> 1.0`. If you run bundle install, you get: Fetching source index for https://rubygems.org/ Installing daemons (1.1.0) Installing eventmachine (0.12.10) with native extensions Installing open4 (1.0.1) Installing perftools.rb (0.4.7) with native extensions Installing rack (1.2.1) Installing rack-perftools_profiler (0.0.2) Installing thin (1.2.7) with native extensions Using bundler (1.0.0.rc.3) In this case, the two gems have their own set of dependencies, but they share `rack` in common. If you run `bundle update thin`, bundler will update `daemons`, `eventmachine` and `rack`, which are dependencies of `thin`, but not `open4` or `perftools.rb`, which are dependencies of `rack-perftools_profiler`. Note that `bundle update thin` will update `rack` even though it's _also_ a dependency of `rack-perftools_profiler`. In short, by default, when you update a gem using `bundle update`, bundler will update all dependencies of that gem, including those that are also dependencies of another gem. To prevent updating indirect dependencies, prior to version 1.14 the only option was the `CONSERVATIVE UPDATING` behavior in [bundle install(1)](bundle-install.1.html): In this scenario, updating the `thin` version manually in the Gemfile(5), and then running [bundle install(1)](bundle-install.1.html) will only update `daemons` and `eventmachine`, but not `rack`. For more information, see the `CONSERVATIVE UPDATING` section of [bundle install(1)](bundle-install.1.html). Starting with 1.14, specifying the `--conservative` option will also prevent indirect dependencies from being updated. ## PATCH LEVEL OPTIONS Version 1.14 introduced 4 patch-level options that will influence how gem versions are resolved. One of the following options can be used: `--patch`, `--minor` or `--major`. `--strict` can be added to further influence resolution. * `--patch`: Prefer updating only to next patch version. * `--minor`: Prefer updating only to next minor version. * `--major`: Prefer updating to next major version (default). * `--strict`: Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don't satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order. Providing one of the patch level options (e.g. `--patch`) changes the sort order of the satisfying versions, causing Bundler to consider the latest `--patch` or `--minor` version available before other versions. Note that versions outside the stated patch level could still be resolved to if necessary to find a suitable dependency graph. For example, if gem 'foo' is locked at 1.0.2, with no gem requirement defined in the Gemfile, and versions 1.0.3, 1.0.4, 1.1.0, 1.1.1, 2.0.0 all exist, the default order of preference by default (`--major`) will be "2.0.0, 1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". If the `--patch` option is used, the order of preference will change to "1.0.4, 1.0.3, 1.0.2, 1.1.1, 1.1.0, 2.0.0". If the `--minor` option is used, the order of preference will change to "1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2, 2.0.0". Combining the `--strict` option with any of the patch level options will remove any versions beyond the scope of the patch level option, to ensure that no gem is updated that far. To continue the previous example, if both `--patch` and `--strict` options are used, the available versions for resolution would be "1.0.4, 1.0.3, 1.0.2". If `--minor` and `--strict` are used, it would be "1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available. If the gem requirement for `foo` in the Gemfile is '~> 1.0', that will accomplish the same thing as providing the `--minor` and `--strict` options. ## PATCH LEVEL EXAMPLES Given the following gem specifications: foo 1.4.3, requires: ~> bar 2.0 foo 1.4.4, requires: ~> bar 2.0 foo 1.4.5, requires: ~> bar 2.1 foo 1.5.0, requires: ~> bar 2.1 foo 1.5.1, requires: ~> bar 3.0 bar with versions 2.0.3, 2.0.4, 2.1.0, 2.1.1, 3.0.0 Gemfile: gem 'foo' Gemfile.lock: foo (1.4.3) bar (~> 2.0) bar (2.0.3) Cases: # Command Line Result ------------------------------------------------------------ 1 bundle update --patch 'foo 1.4.5', 'bar 2.1.1' 2 bundle update --patch foo 'foo 1.4.5', 'bar 2.1.1' 3 bundle update --minor 'foo 1.5.1', 'bar 3.0.0' 4 bundle update --minor --strict 'foo 1.5.0', 'bar 2.1.1' 5 bundle update --patch --strict 'foo 1.4.4', 'bar 2.0.4' In case 1, bar is upgraded to 2.1.1, a minor version increase, because the dependency from foo 1.4.5 required it. In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it's not a declared dependency in the Gemfile. In case 3, bar goes up a whole major release, because a minor increase is preferred now for foo, and when it goes to 1.5.1, it requires 3.0.0 of bar. In case 4, foo is preferred up to a minor version, but 1.5.1 won't work because the --strict flag removes bar 3.0.0 from consideration since it's a major increment. In case 5, both foo and bar have any minor or major increments removed from consideration because of the --strict flag, so the most they can move is up to 1.4.4 and 2.0.4. ## RECOMMENDED WORKFLOW In general, when working with an application managed with bundler, you should use the following workflow: * After you create your Gemfile(5) for the first time, run $ bundle install * Check the resulting `Gemfile.lock` into version control $ git add Gemfile.lock * When checking out this repository on another development machine, run $ bundle install * When checking out this repository on a deployment machine, run $ bundle install --deployment * After changing the Gemfile(5) to reflect a new or update dependency, run $ bundle install * Make sure to check the updated `Gemfile.lock` into version control $ git add Gemfile.lock * If [bundle install(1)](bundle-install.1.html) reports a conflict, manually update the specific gems that you changed in the Gemfile(5) $ bundle update rails thin * If you want to update all the gems to the latest possible versions that still match the gems listed in the Gemfile(5), run $ bundle update --all PK ]|=3gems/bundler-2.2.24/lib/bundler/man/bundle-inject.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-INJECT" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile . .SH "SYNOPSIS" \fBbundle inject\fR [GEM] [VERSION] . .SH "DESCRIPTION" Adds the named gem(s) with their version requirements to the resolved [\fBGemfile(5)\fR][Gemfile(5)]\. . .P This command will add the gem to both your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock if it isn\'t listed yet\. . .P Example: . .IP "" 4 . .nf bundle install bundle inject \'rack\' \'> 0\' . .fi . .IP "" 0 . .P This will inject the \'rack\' gem with a version greater than 0 in your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock PK ],1gems/bundler-2.2.24/lib/bundler/man/bundle-list.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-LIST" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle . .SH "SYNOPSIS" \fBbundle list\fR [\-\-name\-only] [\-\-paths] [\-\-without\-group=GROUP[ GROUP\.\.\.]] [\-\-only\-group=GROUP[ GROUP\.\.\.]] . .SH "DESCRIPTION" Prints a list of all the gems in the bundle including their version\. . .P Example: . .P bundle list \-\-name\-only . .P bundle list \-\-paths . .P bundle list \-\-without\-group test . .P bundle list \-\-only\-group dev . .P bundle list \-\-only\-group dev test \-\-paths . .SH "OPTIONS" . .TP \fB\-\-name\-only\fR Print only the name of each gem\. . .TP \fB\-\-paths\fR Print the path to each gem in the bundle\. . .TP \fB\-\-without\-group=\fR A space\-separated list of groups of gems to skip during printing\. . .TP \fB\-\-only\-group=\fR A space\-separated list of groups of gems to print\. PK ]8EDFDF4gems/bundler-2.2.24/lib/bundler/man/bundle-install.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-INSTALL" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile . .SH "SYNOPSIS" \fBbundle install\fR [\-\-binstubs[=DIRECTORY]] [\-\-clean] [\-\-deployment] [\-\-frozen] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-no\-cache] [\-\-no\-prune] [\-\-path PATH] [\-\-quiet] [\-\-redownload] [\-\-retry=NUMBER] [\-\-shebang] [\-\-standalone[=GROUP[ GROUP\.\.\.]]] [\-\-system] [\-\-trust\-policy=POLICY] [\-\-with=GROUP[ GROUP\.\.\.]] [\-\-without=GROUP[ GROUP\.\.\.]] . .SH "DESCRIPTION" Install the gems specified in your Gemfile(5)\. If this is the first time you run bundle install (and a \fBGemfile\.lock\fR does not exist), Bundler will fetch all remote sources, resolve dependencies and install all needed gems\. . .P If a \fBGemfile\.lock\fR does exist, and you have not updated your Gemfile(5), Bundler will fetch all remote sources, but use the dependencies specified in the \fBGemfile\.lock\fR instead of resolving dependencies\. . .P If a \fBGemfile\.lock\fR does exist, and you have updated your Gemfile(5), Bundler will use the dependencies in the \fBGemfile\.lock\fR for all gems that you did not update, but will re\-resolve the dependencies of gems that you did update\. You can find more information about this update process below under \fICONSERVATIVE UPDATING\fR\. . .SH "OPTIONS" The \fB\-\-clean\fR, \fB\-\-deployment\fR, \fB\-\-frozen\fR, \fB\-\-no\-prune\fR, \fB\-\-path\fR, \fB\-\-shebang\fR, \fB\-\-system\fR, \fB\-\-without\fR and \fB\-\-with\fR options are deprecated because they only make sense if they are applied to every subsequent \fBbundle install\fR run automatically and that requires \fBbundler\fR to silently remember them\. Since \fBbundler\fR will no longer remember CLI flags in future versions, \fBbundle config\fR (see bundle\-config(1)) should be used to apply them permanently\. . .TP \fB\-\-binstubs[=]\fR Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it in \fBbin/\fR\. This lets you link the binstub inside of an application to the exact gem version the application needs\. . .IP Creates a directory (defaults to \fB~/bin\fR) and places any executables from the gem there\. These executables run in Bundler\'s context\. If used, you might add this directory to your environment\'s \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\. . .TP \fB\-\-clean\fR On finishing the installation Bundler is going to remove any gems not present in the current Gemfile(5)\. Don\'t worry, gems currently in use will not be removed\. . .IP This option is deprecated in favor of the \fBclean\fR setting\. . .TP \fB\-\-deployment\fR In \fIdeployment mode\fR, Bundler will \'roll\-out\' the bundle for production or CI use\. Please check carefully if you want to have this option enabled in your development environment\. . .IP This option is deprecated in favor of the \fBdeployment\fR setting\. . .TP \fB\-\-redownload\fR Force download every gem, even if the required versions are already available locally\. . .TP \fB\-\-frozen\fR Do not allow the Gemfile\.lock to be updated after this install\. Exits non\-zero if there are going to be changes to the Gemfile\.lock\. . .IP This option is deprecated in favor of the \fBfrozen\fR setting\. . .TP \fB\-\-full\-index\fR Bundler will not call Rubygems\' API endpoint (default) but download and cache a (currently big) index file of all gems\. Performance can be improved for large bundles that seldom change by enabling this option\. . .TP \fB\-\-gemfile=\fR The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project\'s root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\. . .TP \fB\-\-jobs=[]\fR, \fB\-j[]\fR The maximum number of parallel download and install jobs\. The default is \fB1\fR\. . .TP \fB\-\-local\fR Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. . .TP \fB\-\-no\-cache\fR Do not update the cache in \fBvendor/cache\fR with the newly bundled gems\. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install\. . .TP \fB\-\-no\-prune\fR Don\'t remove stale gems from the cache when the installation finishes\. . .IP This option is deprecated in favor of the \fBno_prune\fR setting\. . .TP \fB\-\-path=\fR The location to install the specified gems to\. This defaults to Rubygems\' setting\. Bundler shares this location with Rubygems, \fBgem install \.\.\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \.\.\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\. . .IP This option is deprecated in favor of the \fBpath\fR setting\. . .TP \fB\-\-quiet\fR Do not print progress information to the standard output\. Instead, Bundler will exit using a status code (\fB$?\fR)\. . .TP \fB\-\-retry=[]\fR Retry failed network or git requests for \fInumber\fR times\. . .TP \fB\-\-shebang=\fR Uses the specified ruby executable (usually \fBruby\fR) to execute the scripts created with \fB\-\-binstubs\fR\. In addition, if you use \fB\-\-binstubs\fR together with \fB\-\-shebang jruby\fR these executables will be changed to execute \fBjruby\fR instead\. . .IP This option is deprecated in favor of the \fBshebang\fR setting\. . .TP \fB\-\-standalone[=]\fR Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install has to be specified\. Bundler creates a directory named \fBbundle\fR and installs the bundle there\. It also generates a \fBbundle/bundler/setup\.rb\fR file to replace Bundler\'s own setup in the manner required\. Using this option implicitly sets \fBpath\fR, which is a [remembered option][REMEMBERED OPTIONS]\. . .TP \fB\-\-system\fR Installs the gems specified in the bundle to the system\'s Rubygems location\. This overrides any previous configuration of \fB\-\-path\fR\. . .IP This option is deprecated in favor of the \fBsystem\fR setting\. . .TP \fB\-\-trust\-policy=[]\fR Apply the Rubygems security policy \fIpolicy\fR, where policy is one of \fBHighSecurity\fR, \fBMediumSecurity\fR, \fBLowSecurity\fR, \fBAlmostNoSecurity\fR, or \fBNoSecurity\fR\. For more details, please see the Rubygems signing documentation linked below in \fISEE ALSO\fR\. . .TP \fB\-\-with=\fR A space\-separated list of groups referencing gems to install\. If an optional group is given it is installed\. If a group is given that is in the remembered list of groups given to \-\-without, it is removed from that list\. . .IP This option is deprecated in favor of the \fBwith\fR setting\. . .TP \fB\-\-without=\fR A space\-separated list of groups referencing gems to skip during installation\. If a group is given that is in the remembered list of groups given to \-\-with, it is removed from that list\. . .IP This option is deprecated in favor of the \fBwithout\fR setting\. . .SH "DEPLOYMENT MODE" Bundler\'s defaults are optimized for development\. To switch to defaults optimized for deployment and for CI, use the \fB\-\-deployment\fR flag\. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified\. . .IP "1." 4 A \fBGemfile\.lock\fR is required\. . .IP To ensure that the same versions of the gems you developed with and tested with are also used in deployments, a \fBGemfile\.lock\fR is required\. . .IP This is mainly to ensure that you remember to check your \fBGemfile\.lock\fR into version control\. . .IP "2." 4 The \fBGemfile\.lock\fR must be up to date . .IP In development, you can modify your Gemfile(5) and re\-run \fBbundle install\fR to \fIconservatively update\fR your \fBGemfile\.lock\fR snapshot\. . .IP In deployment, your \fBGemfile\.lock\fR should be up\-to\-date with changes made in your Gemfile(5)\. . .IP "3." 4 Gems are installed to \fBvendor/bundle\fR not your default system location . .IP In development, it\'s convenient to share the gems used in your application with other applications and other scripts that run on the system\. . .IP In deployment, isolation is a more important default\. In addition, the user deploying the application may not have permission to install gems to the system, or the web server may not have permission to read them\. . .IP As a result, \fBbundle install \-\-deployment\fR installs gems to the \fBvendor/bundle\fR directory in the application\. This may be overridden using the \fB\-\-path\fR option\. . .IP "" 0 . .SH "SUDO USAGE" By default, Bundler installs gems to the same location as \fBgem install\fR\. . .P In some cases, that location may not be writable by your Unix user\. In that case, Bundler will stage everything in a temporary directory, then ask you for your \fBsudo\fR password in order to copy the gems into their system location\. . .P From your perspective, this is identical to installing the gems directly into the system\. . .P You should never use \fBsudo bundle install\fR\. This is because several other steps in \fBbundle install\fR must be performed as the current user: . .IP "\(bu" 4 Updating your \fBGemfile\.lock\fR . .IP "\(bu" 4 Updating your \fBvendor/cache\fR, if necessary . .IP "\(bu" 4 Checking out private git repositories using your user\'s SSH keys . .IP "" 0 . .P Of these three, the first two could theoretically be performed by \fBchown\fRing the resulting files to \fB$SUDO_USER\fR\. The third, however, can only be performed by invoking the \fBgit\fR command as the current user\. Therefore, git gems are downloaded and installed into \fB~/\.bundle\fR rather than $GEM_HOME or $BUNDLE_PATH\. . .P As a result, you should run \fBbundle install\fR as the current user, and Bundler will ask for your password if it is needed to put the gems into their final location\. . .SH "INSTALLING GROUPS" By default, \fBbundle install\fR will install all gems in all groups in your Gemfile(5), except those declared for a different platform\. . .P However, you can explicitly tell Bundler to skip installing certain groups with the \fB\-\-without\fR option\. This option takes a space\-separated list of groups\. . .P While the \fB\-\-without\fR option will skip \fIinstalling\fR the gems in the specified groups, it will still \fIdownload\fR those gems and use them to resolve the dependencies of every gem in your Gemfile(5)\. . .P This is so that installing a different set of groups on another machine (such as a production server) will not change the gems and versions that you have already developed and tested against\. . .P \fBBundler offers a rock\-solid guarantee that the third\-party code you are running in development and testing is also the third\-party code you are running in production\. You can choose to exclude some of that code in different environments, but you will never be caught flat\-footed by different versions of third\-party code being used in different environments\.\fR . .P For a simple illustration, consider the following Gemfile(5): . .IP "" 4 . .nf source \'https://rubygems\.org\' gem \'sinatra\' group :production do gem \'rack\-perftools\-profiler\' end . .fi . .IP "" 0 . .P In this case, \fBsinatra\fR depends on any version of Rack (\fB>= 1\.0\fR), while \fBrack\-perftools\-profiler\fR depends on 1\.x (\fB~> 1\.0\fR)\. . .P When you run \fBbundle install \-\-without production\fR in development, we look at the dependencies of \fBrack\-perftools\-profiler\fR as well\. That way, you do not spend all your time developing against Rack 2\.0, using new APIs unavailable in Rack 1\.x, only to have Bundler switch to Rack 1\.2 when the \fBproduction\fR group \fIis\fR used\. . .P This should not cause any problems in practice, because we do not attempt to \fBinstall\fR the gems in the excluded groups, and only evaluate as part of the dependency resolution process\. . .P This also means that you cannot include different versions of the same gem in different groups, because doing so would result in different sets of dependencies used in development and production\. Because of the vagaries of the dependency resolution process, this usually affects more than the gems you list in your Gemfile(5), and can (surprisingly) radically change the gems you are using\. . .SH "THE GEMFILE\.LOCK" When you run \fBbundle install\fR, Bundler will persist the full names and versions of all gems that you used (including dependencies of the gems specified in the Gemfile(5)) into a file called \fBGemfile\.lock\fR\. . .P Bundler uses this file in all subsequent calls to \fBbundle install\fR, which guarantees that you always use the same exact code, even as your application moves across machines\. . .P Because of the way dependency resolution works, even a seemingly small change (for instance, an update to a point\-release of a dependency of a gem in your Gemfile(5)) can result in radically different gems being needed to satisfy all dependencies\. . .P As a result, you \fBSHOULD\fR check your \fBGemfile\.lock\fR into version control, in both applications and gems\. If you do not, every machine that checks out your repository (including your production server) will resolve all dependencies again, which will result in different versions of third\-party code being used if \fBany\fR of the gems in the Gemfile(5) or any of their dependencies have been updated\. . .P When Bundler first shipped, the \fBGemfile\.lock\fR was included in the \fB\.gitignore\fR file included with generated gems\. Over time, however, it became clear that this practice forces the pain of broken dependencies onto new contributors, while leaving existing contributors potentially unaware of the problem\. Since \fBbundle install\fR is usually the first step towards a contribution, the pain of broken dependencies would discourage new contributors from contributing\. As a result, we have revised our guidance for gem authors to now recommend checking in the lock for gems\. . .SH "CONSERVATIVE UPDATING" When you make a change to the Gemfile(5) and then run \fBbundle install\fR, Bundler will update only the gems that you modified\. . .P In other words, if a gem that you \fBdid not modify\fR worked before you called \fBbundle install\fR, it will continue to use the exact same versions of all dependencies as it used before the update\. . .P Let\'s take a look at an example\. Here\'s your original Gemfile(5): . .IP "" 4 . .nf source \'https://rubygems\.org\' gem \'actionpack\', \'2\.3\.8\' gem \'activemerchant\' . .fi . .IP "" 0 . .P In this case, both \fBactionpack\fR and \fBactivemerchant\fR depend on \fBactivesupport\fR\. The \fBactionpack\fR gem depends on \fBactivesupport 2\.3\.8\fR and \fBrack ~> 1\.1\.0\fR, while the \fBactivemerchant\fR gem depends on \fBactivesupport >= 2\.3\.2\fR, \fBbraintree >= 2\.0\.0\fR, and \fBbuilder >= 2\.0\.0\fR\. . .P When the dependencies are first resolved, Bundler will select \fBactivesupport 2\.3\.8\fR, which satisfies the requirements of both gems in your Gemfile(5)\. . .P Next, you modify your Gemfile(5) to: . .IP "" 4 . .nf source \'https://rubygems\.org\' gem \'actionpack\', \'3\.0\.0\.rc\' gem \'activemerchant\' . .fi . .IP "" 0 . .P The \fBactionpack 3\.0\.0\.rc\fR gem has a number of new dependencies, and updates the \fBactivesupport\fR dependency to \fB= 3\.0\.0\.rc\fR and the \fBrack\fR dependency to \fB~> 1\.2\.1\fR\. . .P When you run \fBbundle install\fR, Bundler notices that you changed the \fBactionpack\fR gem, but not the \fBactivemerchant\fR gem\. It evaluates the gems currently being used to satisfy its requirements: . .TP \fBactivesupport 2\.3\.8\fR also used to satisfy a dependency in \fBactivemerchant\fR, which is not being updated . .TP \fBrack ~> 1\.1\.0\fR not currently being used to satisfy another dependency . .P Because you did not explicitly ask to update \fBactivemerchant\fR, you would not expect it to suddenly stop working after updating \fBactionpack\fR\. However, satisfying the new \fBactivesupport 3\.0\.0\.rc\fR dependency of actionpack requires updating one of its dependencies\. . .P Even though \fBactivemerchant\fR declares a very loose dependency that theoretically matches \fBactivesupport 3\.0\.0\.rc\fR, Bundler treats gems in your Gemfile(5) that have not changed as an atomic unit together with their dependencies\. In this case, the \fBactivemerchant\fR dependency is treated as \fBactivemerchant 1\.7\.1 + activesupport 2\.3\.8\fR, so \fBbundle install\fR will report that it cannot update \fBactionpack\fR\. . .P To explicitly update \fBactionpack\fR, including its dependencies which other gems in the Gemfile(5) still depend on, run \fBbundle update actionpack\fR (see \fBbundle update(1)\fR)\. . .P \fBSummary\fR: In general, after making a change to the Gemfile(5) , you should first try to run \fBbundle install\fR, which will guarantee that no other gem in the Gemfile(5) is impacted by the change\. If that does not work, run bundle update(1) \fIbundle\-update\.1\.html\fR\. . .SH "SEE ALSO" . .IP "\(bu" 4 Gem install docs \fIhttp://guides\.rubygems\.org/rubygems\-basics/#installing\-gems\fR . .IP "\(bu" 4 Rubygems signing docs \fIhttp://guides\.rubygems\.org/security/\fR . .IP "" 0 PK ]-N-N2gems/bundler-2.2.24/lib/bundler/man/gemfile.5.ronnnu[Gemfile(5) -- A format for describing gem dependencies for Ruby programs ======================================================================== ## SYNOPSIS A `Gemfile` describes the gem dependencies required to execute associated Ruby code. Place the `Gemfile` in the root of the directory containing the associated code. For instance, in a Rails application, place the `Gemfile` in the same directory as the `Rakefile`. ## SYNTAX A `Gemfile` is evaluated as Ruby code, in a context which makes available a number of methods used to describe the gem requirements. ## GLOBAL SOURCES At the top of the `Gemfile`, add a line for the `Rubygems` source that contains the gems listed in the `Gemfile`. source "https://rubygems.org" It is possible, but not recommended as of Bundler 1.7, to add multiple global `source` lines. Each of these `source`s `MUST` be a valid Rubygems repository. Sources are checked for gems following the heuristics described in [SOURCE PRIORITY][]. If a gem is found in more than one global source, Bundler will print a warning after installing the gem indicating which source was used, and listing the other sources where the gem is available. A specific source can be selected for gems that need to use a non-standard repository, suppressing this warning, by using the [`:source` option](#SOURCE) or a [`source` block](#BLOCK-FORM-OF-SOURCE-GIT-PATH-GROUP-and-PLATFORMS). ### CREDENTIALS Some gem sources require a username and password. Use [bundle config(1)](bundle-config.1.html) to set the username and password for any of the sources that need it. The command must be run once on each computer that will install the Gemfile, but this keeps the credentials from being stored in plain text in version control. bundle config gems.example.com user:password For some sources, like a company Gemfury account, it may be easier to include the credentials in the Gemfile as part of the source URL. source "https://user:password@gems.example.com" Credentials in the source URL will take precedence over credentials set using `config`. ## RUBY If your application requires a specific Ruby version or engine, specify your requirements using the `ruby` method, with the following arguments. All parameters are `OPTIONAL` unless otherwise specified. ### VERSION (required) The version of Ruby that your application requires. If your application requires an alternate Ruby engine, such as JRuby, Rubinius or TruffleRuby, this should be the Ruby version that the engine is compatible with. ruby "1.9.3" ### ENGINE Each application _may_ specify a Ruby engine. If an engine is specified, an engine version _must_ also be specified. What exactly is an Engine? - A Ruby engine is an implementation of the Ruby language. - For background: the reference or original implementation of the Ruby programming language is called [Matz's Ruby Interpreter](https://en.wikipedia.org/wiki/Ruby_MRI), or MRI for short. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz. MRI is also known as CRuby, because it is written in C. MRI is the most widely used Ruby engine. - [Other implementations](https://www.ruby-lang.org/en/about/) of Ruby exist. Some of the more well-known implementations include [Rubinius](https://rubinius.com/), and [JRuby](http://jruby.org/). Rubinius is an alternative implementation of Ruby written in Ruby. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine. ### ENGINE VERSION Each application _may_ specify a Ruby engine version. If an engine version is specified, an engine _must_ also be specified. If the engine is "ruby" the engine version specified _must_ match the Ruby version. ruby "1.8.7", :engine => "jruby", :engine_version => "1.6.7" ### PATCHLEVEL Each application _may_ specify a Ruby patchlevel. ruby "2.0.0", :patchlevel => "247" ## GEMS Specify gem requirements using the `gem` method, with the following arguments. All parameters are `OPTIONAL` unless otherwise specified. ### NAME (required) For each gem requirement, list a single _gem_ line. gem "nokogiri" ### VERSION Each _gem_ `MAY` have one or more version specifiers. gem "nokogiri", ">= 1.4.2" gem "RedCloth", ">= 4.1.0", "< 4.2.0" ### REQUIRE AS Each _gem_ `MAY` specify files that should be used when autorequiring via `Bundler.require`. You may pass an array with multiple files or `true` if the file you want `required` has the same name as _gem_ or `false` to prevent any file from being autorequired. gem "redis", :require => ["redis/connection/hiredis", "redis"] gem "webmock", :require => false gem "byebug", :require => true The argument defaults to the name of the gem. For example, these are identical: gem "nokogiri" gem "nokogiri", :require => "nokogiri" gem "nokogiri", :require => true ### GROUPS Each _gem_ `MAY` specify membership in one or more groups. Any _gem_ that does not specify membership in any group is placed in the `default` group. gem "rspec", :group => :test gem "wirble", :groups => [:development, :test] The Bundler runtime allows its two main methods, `Bundler.setup` and `Bundler.require`, to limit their impact to particular groups. # setup adds gems to Ruby's load path Bundler.setup # defaults to all groups require "bundler/setup" # same as Bundler.setup Bundler.setup(:default) # only set up the _default_ group Bundler.setup(:test) # only set up the _test_ group (but `not` _default_) Bundler.setup(:default, :test) # set up the _default_ and _test_ groups, but no others # require requires all of the gems in the specified groups Bundler.require # defaults to the _default_ group Bundler.require(:default) # identical Bundler.require(:default, :test) # requires the _default_ and _test_ groups Bundler.require(:test) # requires the _test_ group The Bundler CLI allows you to specify a list of groups whose gems `bundle install` should not install with the `without` configuration. To specify multiple groups to ignore, specify a list of groups separated by spaces. bundle config set --local without test bundle config set --local without development test Also, calling `Bundler.setup` with no parameters, or calling `require "bundler/setup"` will setup all groups except for the ones you excluded via `--without` (since they are not available). Note that on `bundle install`, bundler downloads and evaluates all gems, in order to create a single canonical list of all of the required gems and their dependencies. This means that you cannot list different versions of the same gems in different groups. For more details, see [Understanding Bundler](https://bundler.io/rationale.html). ### PLATFORMS If a gem should only be used in a particular platform or set of platforms, you can specify them. Platforms are essentially identical to groups, except that you do not need to use the `--without` install-time flag to exclude groups of gems for other platforms. There are a number of `Gemfile` platforms: * `ruby`: C Ruby (MRI), Rubinius or TruffleRuby, but `NOT` Windows * `mri`: Same as _ruby_, but only C Ruby (MRI) * `mingw`: Windows 32 bit 'mingw32' platform (aka RubyInstaller) * `x64_mingw`: Windows 64 bit 'mingw32' platform (aka RubyInstaller x64) * `rbx`: Rubinius * `jruby`: JRuby * `truffleruby`: TruffleRuby * `mswin`: Windows You can restrict further by platform and version for all platforms *except* for `rbx`, `jruby`, `truffleruby` and `mswin`. To specify a version in addition to a platform, append the version number without the delimiter to the platform. For example, to specify that a gem should only be used on platforms with Ruby 2.3, use: ruby_23 The full list of platforms and supported versions includes: * `ruby`: 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 * `mri`: 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 * `mingw`: 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 * `x64_mingw`: 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 As with groups, you can specify one or more platforms: gem "weakling", :platforms => :jruby gem "ruby-debug", :platforms => :mri_18 gem "nokogiri", :platforms => [:mri_18, :jruby] All operations involving groups ([`bundle install`](bundle-install.1.html), `Bundler.setup`, `Bundler.require`) behave exactly the same as if any groups not matching the current platform were explicitly excluded. ### SOURCE You can select an alternate Rubygems repository for a gem using the ':source' option. gem "some_internal_gem", :source => "https://gems.example.com" This forces the gem to be loaded from this source and ignores any global sources declared at the top level of the file. If the gem does not exist in this source, it will not be installed. Bundler will search for child dependencies of this gem by first looking in the source selected for the parent, but if they are not found there, it will fall back on global sources using the ordering described in [SOURCE PRIORITY][]. Selecting a specific source repository this way also suppresses the ambiguous gem warning described above in [GLOBAL SOURCES (#source)](#GLOBAL-SOURCES). Using the `:source` option for an individual gem will also make that source available as a possible global source for any other gems which do not specify explicit sources. Thus, when adding gems with explicit sources, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources. ### GIT If necessary, you can specify that a gem is located at a particular git repository using the `:git` parameter. The repository can be accessed via several protocols: * `HTTP(S)`: gem "rails", :git => "https://github.com/rails/rails.git" * `SSH`: gem "rails", :git => "git@github.com:rails/rails.git" * `git`: gem "rails", :git => "git://github.com/rails/rails.git" If using SSH, the user that you use to run `bundle install` `MUST` have the appropriate keys available in their `$HOME/.ssh`. `NOTE`: `http://` and `git://` URLs should be avoided if at all possible. These protocols are unauthenticated, so a man-in-the-middle attacker can deliver malicious code and compromise your system. HTTPS and SSH are strongly preferred. The `group`, `platforms`, and `require` options are available and behave exactly the same as they would for a normal gem. A git repository `SHOULD` have at least one file, at the root of the directory containing the gem, with the extension `.gemspec`. This file `MUST` contain a valid gem specification, as expected by the `gem build` command. If a git repository does not have a `.gemspec`, bundler will attempt to create one, but it will not contain any dependencies, executables, or C extension compilation instructions. As a result, it may fail to properly integrate into your application. If a git repository does have a `.gemspec` for the gem you attached it to, a version specifier, if provided, means that the git repository is only valid if the `.gemspec` specifies a version matching the version specifier. If not, bundler will print a warning. gem "rails", "2.3.8", :git => "https://github.com/rails/rails.git" # bundle install will fail, because the .gemspec in the rails # repository's master branch specifies version 3.0.0 If a git repository does `not` have a `.gemspec` for the gem you attached it to, a version specifier `MUST` be provided. Bundler will use this version in the simple `.gemspec` it creates. Git repositories support a number of additional options. * `branch`, `tag`, and `ref`: You `MUST` only specify at most one of these options. The default is `:branch => "master"`. For example: gem "rails", :git => "https://github.com/rails/rails.git", :branch => "5-0-stable" gem "rails", :git => "https://github.com/rails/rails.git", :tag => "v5.0.0" gem "rails", :git => "https://github.com/rails/rails.git", :ref => "4aded" * `submodules`: For reference, a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) lets you have another git repository within a subfolder of your repository. Specify `:submodules => true` to cause bundler to expand any submodules included in the git repository If a git repository contains multiple `.gemspecs`, each `.gemspec` represents a gem located at the same place in the file system as the `.gemspec`. |~rails [git root] | |-rails.gemspec [rails gem located here] |~actionpack | |-actionpack.gemspec [actionpack gem located here] |~activesupport | |-activesupport.gemspec [activesupport gem located here] |... To install a gem located in a git repository, bundler changes to the directory containing the gemspec, runs `gem build name.gemspec` and then installs the resulting gem. The `gem build` command, which comes standard with Rubygems, evaluates the `.gemspec` in the context of the directory in which it is located. ### GIT SOURCE A custom git source can be defined via the `git_source` method. Provide the source's name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address: git_source(:stash){ |repo_name| "https://stash.corp.acme.pl/#{repo_name}.git" } gem 'rails', :stash => 'forks/rails' In addition, if you wish to choose a specific branch: gem "rails", :stash => "forks/rails", :branch => "branch_name" ### GITHUB `NOTE`: This shorthand should be avoided until Bundler 2.0, since it currently expands to an insecure `git://` URL. This allows a man-in-the-middle attacker to compromise your system. If the git repository you want to use is hosted on GitHub and is public, you can use the :github shorthand to specify the github username and repository name (without the trailing ".git"), separated by a slash. If both the username and repository name are the same, you can omit one. gem "rails", :github => "rails/rails" gem "rails", :github => "rails" Are both equivalent to gem "rails", :git => "git://github.com/rails/rails.git" Since the `github` method is a specialization of `git_source`, it accepts a `:branch` named argument. ### GIST If the git repository you want to use is hosted as a Github Gist and is public, you can use the :gist shorthand to specify the gist identifier (without the trailing ".git"). gem "the_hatch", :gist => "4815162342" Is equivalent to: gem "the_hatch", :git => "https://gist.github.com/4815162342.git" Since the `gist` method is a specialization of `git_source`, it accepts a `:branch` named argument. ### BITBUCKET If the git repository you want to use is hosted on Bitbucket and is public, you can use the :bitbucket shorthand to specify the bitbucket username and repository name (without the trailing ".git"), separated by a slash. If both the username and repository name are the same, you can omit one. gem "rails", :bitbucket => "rails/rails" gem "rails", :bitbucket => "rails" Are both equivalent to gem "rails", :git => "https://rails@bitbucket.org/rails/rails.git" Since the `bitbucket` method is a specialization of `git_source`, it accepts a `:branch` named argument. ### PATH You can specify that a gem is located in a particular location on the file system. Relative paths are resolved relative to the directory containing the `Gemfile`. Similar to the semantics of the `:git` option, the `:path` option requires that the directory in question either contains a `.gemspec` for the gem, or that you specify an explicit version that bundler should use. Unlike `:git`, bundler does not compile C extensions for gems specified as paths. gem "rails", :path => "vendor/rails" If you would like to use multiple local gems directly from the filesystem, you can set a global `path` option to the path containing the gem's files. This will automatically load gemspec files from subdirectories. path 'components' do gem 'admin_ui' gem 'public_ui' end ## BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS The `:source`, `:git`, `:path`, `:group`, and `:platforms` options may be applied to a group of gems by using block form. source "https://gems.example.com" do gem "some_internal_gem" gem "another_internal_gem" end git "https://github.com/rails/rails.git" do gem "activesupport" gem "actionpack" end platforms :ruby do gem "ruby-debug" gem "sqlite3" end group :development, :optional => true do gem "wirble" gem "faker" end In the case of the group block form the :optional option can be given to prevent a group from being installed unless listed in the `--with` option given to the `bundle install` command. In the case of the `git` block form, the `:ref`, `:branch`, `:tag`, and `:submodules` options may be passed to the `git` method, and all gems in the block will inherit those options. The presence of a `source` block in a Gemfile also makes that source available as a possible global source for any other gems which do not specify explicit sources. Thus, when defining source blocks, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources, either via source blocks or `:source` directives on individual gems. ## INSTALL_IF The `install_if` method allows gems to be installed based on a proc or lambda. This is especially useful for optional gems that can only be used if certain software is installed or some other conditions are met. install_if -> { RUBY_PLATFORM =~ /darwin/ } do gem "pasteboard" end ## GEMSPEC The [`.gemspec`](http://guides.rubygems.org/specification-reference/) file is where you provide metadata about your gem to Rubygems. Some required Gemspec attributes include the name, description, and homepage of your gem. This is also where you specify the dependencies your gem needs to run. If you wish to use Bundler to help install dependencies for a gem while it is being developed, use the `gemspec` method to pull in the dependencies listed in the `.gemspec` file. The `gemspec` method adds any runtime dependencies as gem requirements in the default group. It also adds development dependencies as gem requirements in the `development` group. Finally, it adds a gem requirement on your project (`:path => '.'`). In conjunction with `Bundler.setup`, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths. The `gemspec` method supports optional `:path`, `:glob`, `:name`, and `:development_group` options, which control where bundler looks for the `.gemspec`, the glob it uses to look for the gemspec (defaults to: "{,*,*/*}.gemspec"), what named `.gemspec` it uses (if more than one is present), and which group development dependencies are included in. When a `gemspec` dependency encounters version conflicts during resolution, the local version under development will always be selected -- even if there are remote versions that better match other requirements for the `gemspec` gem. ## SOURCE PRIORITY When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order: 1. The source explicitly attached to the gem (using `:source`, `:path`, or `:git`) 2. For implicit gems (dependencies of explicit gems), any source, git, or path repository declared on the parent. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from `rubygems.org` 3. The sources specified via global `source` lines, searching each source in your `Gemfile` from last added to first added. PK ]>^gH H 1gems/bundler-2.2.24/lib/bundler/man/bundle.1.ronnnu[bundle(1) -- Ruby Dependency Management ======================================= ## SYNOPSIS `bundle` COMMAND [--no-color] [--verbose] [ARGS] ## DESCRIPTION Bundler manages an `application's dependencies` through its entire life across many machines systematically and repeatably. See [the bundler website](https://bundler.io) for information on getting started, and Gemfile(5) for more information on the `Gemfile` format. ## OPTIONS * `--no-color`: Print all output without color * `--retry`, `-r`: Specify the number of times you wish to attempt network commands * `--verbose`, `-V`: Print out additional logging information ## BUNDLE COMMANDS We divide `bundle` subcommands into primary commands and utilities: ## PRIMARY COMMANDS * [`bundle install(1)`](bundle-install.1.html): Install the gems specified by the `Gemfile` or `Gemfile.lock` * [`bundle update(1)`](bundle-update.1.html): Update dependencies to their latest versions * [`bundle package(1)`](bundle-package.1.html): Package the .gem files required by your application into the `vendor/cache` directory * [`bundle exec(1)`](bundle-exec.1.html): Execute a script in the current bundle * [`bundle config(1)`](bundle-config.1.html): Specify and read configuration options for Bundler * `bundle help(1)`: Display detailed help for each subcommand ## UTILITIES * [`bundle add(1)`](bundle-add.1.html): Add the named gem to the Gemfile and run `bundle install` * [`bundle binstubs(1)`](bundle-binstubs.1.html): Generate binstubs for executables in a gem * [`bundle check(1)`](bundle-check.1.html): Determine whether the requirements for your application are installed and available to Bundler * [`bundle show(1)`](bundle-show.1.html): Show the source location of a particular gem in the bundle * [`bundle outdated(1)`](bundle-outdated.1.html): Show all of the outdated gems in the current bundle * `bundle console(1)`: Start an IRB session in the current bundle * [`bundle open(1)`](bundle-open.1.html): Open an installed gem in the editor * [`bundle lock(1)`](bundle-lock.1.html): Generate a lockfile for your dependencies * [`bundle viz(1)`](bundle-viz.1.html): Generate a visual representation of your dependencies * [`bundle init(1)`](bundle-init.1.html): Generate a simple `Gemfile`, placed in the current directory * [`bundle gem(1)`](bundle-gem.1.html): Create a simple gem, suitable for development with Bundler * [`bundle platform(1)`](bundle-platform.1.html): Display platform compatibility information * [`bundle clean(1)`](bundle-clean.1.html): Clean up unused gems in your Bundler directory * [`bundle doctor(1)`](bundle-doctor.1.html): Display warnings about common problems * [`bundle remove(1)`](bundle-remove.1.html): Removes gems from the Gemfile ## PLUGINS When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named `bundler-` and execute it, passing down any extra arguments to it. ## OBSOLETE These commands are obsolete and should no longer be used: * `bundle cache(1)` * `bundle show(1)` PK ]2P331gems/bundler-2.2.24/lib/bundler/man/bundle-init.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-INIT" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory . .SH "SYNOPSIS" \fBbundle init\fR [\-\-gemspec=FILE] . .SH "DESCRIPTION" Init generates a default [\fBGemfile(5)\fR][Gemfile(5)] in the current working directory\. When adding a [\fBGemfile(5)\fR][Gemfile(5)] to a gem with a gemspec, the \fB\-\-gemspec\fR option will automatically add each dependency listed in the gemspec file to the newly created [\fBGemfile(5)\fR][Gemfile(5)]\. . .SH "OPTIONS" . .TP \fB\-\-gemspec\fR Use the specified \.gemspec to create the [\fBGemfile(5)\fR][Gemfile(5)] . .SH "FILES" Included in the default [\fBGemfile(5)\fR][Gemfile(5)] generated is the line \fB# frozen_string_literal: true\fR\. This is a magic comment supported for the first time in Ruby 2\.3\. The presence of this line results in all string literals in the file being implicitly frozen\. . .SH "SEE ALSO" Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR PK ]ߕ}}:gems/bundler-2.2.24/lib/bundler/man/bundle-platform.1.ronnnu[bundle-platform(1) -- Displays platform compatibility information ================================================================= ## SYNOPSIS `bundle platform` [--ruby] ## DESCRIPTION `platform` will display information from your Gemfile, Gemfile.lock, and Ruby VM about your platform. For instance, using this Gemfile(5): source "https://rubygems.org" ruby "1.9.3" gem "rack" If you run `bundle platform` on Ruby 1.9.3, it will display the following output: Your platform is: x86_64-linux Your app has gems that work on these platforms: * ruby Your Gemfile specifies a Ruby version requirement: * ruby 1.9.3 Your current platform satisfies the Ruby version requirement. `platform` will list all the platforms in your `Gemfile.lock` as well as the `ruby` directive if applicable from your Gemfile(5). It will also let you know if the `ruby` directive requirement has been met. If `ruby` directive doesn't match the running Ruby VM, it will tell you what part does not. ## OPTIONS * `--ruby`: It will display the ruby directive information, so you don't have to parse it from the Gemfile(5). PK ]j5gems/bundler-2.2.24/lib/bundler/man/bundle-pristine.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-PRISTINE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition . .SH "SYNOPSIS" \fBbundle pristine\fR . .SH "DESCRIPTION" \fBpristine\fR restores the installed gems in the bundle to their pristine condition using the local gem cache from RubyGems\. For git gems, a forced checkout will be performed\. . .P For further explanation, \fBbundle pristine\fR ignores unpacked files on disk\. In other words, this command utilizes the local \fB\.gem\fR cache or the gem\'s git repository as if one were installing from scratch\. . .P Note: the Bundler gem cannot be restored to its original state with \fBpristine\fR\. One also cannot use \fBbundle pristine\fR on gems with a \'path\' option in the Gemfile, because bundler has no original copy it can restore from\. . .P When is it practical to use \fBbundle pristine\fR? . .P It comes in handy when a developer is debugging a gem\. \fBbundle pristine\fR is a great way to get rid of experimental changes to a gem that one may not want\. . .P Why use \fBbundle pristine\fR over \fBgem pristine \-\-all\fR? . .P Both commands are very similar\. For context: \fBbundle pristine\fR, without arguments, cleans all gems from the lockfile\. Meanwhile, \fBgem pristine \-\-all\fR cleans all installed gems for that Ruby version\. . .P If a developer forgets which gems in their project they might have been debugging, the Rubygems \fBgem pristine [GEMNAME]\fR command may be inconvenient\. One can avoid waiting for \fBgem pristine \-\-all\fR, and instead run \fBbundle pristine\fR\. PK ]'uw^5gems/bundler-2.2.24/lib/bundler/man/bundle-add.1.ronnnu[bundle-add(1) -- Add gem to the Gemfile and run bundle install ================================================================ ## SYNOPSIS `bundle add` [--group=GROUP] [--version=VERSION] [--source=SOURCE] [--git=GIT] [--branch=BRANCH] [--skip-install] [--strict] [--optimistic] ## DESCRIPTION Adds the named gem to the Gemfile and run `bundle install`. `bundle install` can be avoided by using the flag `--skip-install`. Example: bundle add rails bundle add rails --version "< 3.0, > 1.1" bundle add rails --version "~> 5.0.0" --source "https://gems.example.com" --group "development" bundle add rails --skip-install bundle add rails --group "development, test" ## OPTIONS * `--version`, `-v`: Specify version requirements(s) for the added gem. * `--group`, `-g`: Specify the group(s) for the added gem. Multiple groups should be separated by commas. * `--source`, , `-s`: Specify the source for the added gem. * `--git`: Specify the git source for the added gem. * `--branch`: Specify the git branch for the added gem. * `--skip-install`: Adds the gem to the Gemfile but does not install it. * `--optimistic`: Adds optimistic declaration of version * `--strict`: Adds strict declaration of version PK ]?OAA1gems/bundler-2.2.24/lib/bundler/man/bundle-open.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-OPEN" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle . .SH "SYNOPSIS" \fBbundle open\fR [GEM] . .SH "DESCRIPTION" Opens the source directory of the provided GEM in your editor\. . .P For this to work the \fBEDITOR\fR or \fBBUNDLER_EDITOR\fR environment variable has to be set\. . .P Example: . .IP "" 4 . .nf bundle open \'rack\' . .fi . .IP "" 0 . .P Will open the source directory for the \'rack\' gem in your bundle\. PK ]"&YxSS3gems/bundler-2.2.24/lib/bundler/man/bundle-config.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-CONFIG" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options . .SH "SYNOPSIS" \fBbundle config\fR [list|get|set|unset] [\fIname\fR [\fIvalue\fR]] . .SH "DESCRIPTION" This command allows you to interact with Bundler\'s configuration system\. . .P Bundler loads configuration settings in this order: . .IP "1." 4 Local config (\fB/\.bundle/config\fR or \fB$BUNDLE_APP_CONFIG/config\fR) . .IP "2." 4 Environmental variables (\fBENV\fR) . .IP "3." 4 Global config (\fB~/\.bundle/config\fR) . .IP "4." 4 Bundler default config . .IP "" 0 . .P Executing \fBbundle config list\fR with will print a list of all bundler configuration for the current bundle, and where that configuration was set\. . .P Executing \fBbundle config get \fR will print the value of that configuration setting, and where it was set\. . .P Executing \fBbundle config set \fR will set that configuration to the value specified for all bundles executed as the current user\. The configuration will be stored in \fB~/\.bundle/config\fR\. If \fIname\fR already is set, \fIname\fR will be overridden and user will be warned\. . .P Executing \fBbundle config set \-\-global \fR works the same as above\. . .P Executing \fBbundle config set \-\-local \fR will set that configuration in the directory for the local application\. The configuration will be stored in \fB/\.bundle/config\fR\. If \fBBUNDLE_APP_CONFIG\fR is set, the configuration will be stored in \fB$BUNDLE_APP_CONFIG/config\fR\. . .P Executing \fBbundle config unset \fR will delete the configuration in both local and global sources\. . .P Executing \fBbundle config unset \-\-global \fR will delete the configuration only from the user configuration\. . .P Executing \fBbundle config unset \-\-local \fR will delete the configuration only from the local application\. . .P Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. . .SH "REMEMBERING OPTIONS" Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application\'s configuration (normally, \fB\./\.bundle/config\fR)\. . .P However, this will be changed in bundler 3, so it\'s better not to rely on this behavior\. If these options must be remembered, it\'s better to set them using \fBbundle config\fR (e\.g\., \fBbundle config set \-\-local path foo\fR)\. . .P The options that can be configured are: . .TP \fBbin\fR Creates a directory (defaults to \fB~/bin\fR) and place any executables from the gem there\. These executables run in Bundler\'s context\. If used, you might add this directory to your environment\'s \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\. . .TP \fBdeployment\fR In deployment mode, Bundler will \'roll\-out\' the bundle for \fBproduction\fR use\. Please check carefully if you want to have this option enabled in \fBdevelopment\fR or \fBtest\fR environments\. . .TP \fBpath\fR The location to install the specified gems to\. This defaults to Rubygems\' setting\. Bundler shares this location with Rubygems, \fBgem install \.\.\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \.\.\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\. . .TP \fBwithout\fR A space\-separated list of groups referencing gems to skip during installation\. . .TP \fBwith\fR A space\-separated list of groups referencing gems to include during installation\. . .SH "BUILD OPTIONS" You can use \fBbundle config\fR to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem\. . .P A very common example, the \fBmysql\fR gem, requires Snow Leopard users to pass configuration flags to \fBgem install\fR to specify where to find the \fBmysql_config\fR executable\. . .IP "" 4 . .nf gem install mysql \-\- \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config . .fi . .IP "" 0 . .P Since the specific location of that executable can change from machine to machine, you can specify these flags on a per\-machine basis\. . .IP "" 4 . .nf bundle config set \-\-global build\.mysql \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config . .fi . .IP "" 0 . .P After running this command, every time bundler needs to install the \fBmysql\fR gem, it will pass along the flags you specified\. . .SH "CONFIGURATION KEYS" Configuration keys in bundler have two forms: the canonical form and the environment variable form\. . .P For instance, passing the \fB\-\-without\fR flag to bundle install(1) \fIbundle\-install\.1\.html\fR prevents Bundler from installing certain groups specified in the Gemfile(5)\. Bundler persists this value in \fBapp/\.bundle/config\fR so that calls to \fBBundler\.setup\fR do not try to find gems from the \fBGemfile\fR that you didn\'t install\. Additionally, subsequent calls to bundle install(1) \fIbundle\-install\.1\.html\fR remember this setting and skip those groups\. . .P The canonical form of this configuration is \fB"without"\fR\. To convert the canonical form to the environment variable form, capitalize it, and prepend \fBBUNDLE_\fR\. The environment variable form of \fB"without"\fR is \fBBUNDLE_WITHOUT\fR\. . .P Any periods in the configuration keys must be replaced with two underscores when setting it via environment variables\. The configuration key \fBlocal\.rack\fR becomes the environment variable \fBBUNDLE_LOCAL__RACK\fR\. . .SH "LIST OF AVAILABLE KEYS" The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\. . .IP "\(bu" 4 \fBallow_deployment_source_credential_changes\fR (\fBBUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES\fR): When in deployment mode, allow changing the credentials to a gem\'s source\. Ex: \fBhttps://some\.host\.com/gems/path/\fR \-> \fBhttps://user_name:password@some\.host\.com/gems/path\fR . .IP "\(bu" 4 \fBallow_offline_install\fR (\fBBUNDLE_ALLOW_OFFLINE_INSTALL\fR): Allow Bundler to use cached data when installing without network access\. . .IP "\(bu" 4 \fBauto_clean_without_path\fR (\fBBUNDLE_AUTO_CLEAN_WITHOUT_PATH\fR): Automatically run \fBbundle clean\fR after installing when an explicit \fBpath\fR has not been set and Bundler is not installing into the system gems\. . .IP "\(bu" 4 \fBauto_install\fR (\fBBUNDLE_AUTO_INSTALL\fR): Automatically run \fBbundle install\fR when gems are missing\. . .IP "\(bu" 4 \fBbin\fR (\fBBUNDLE_BIN\fR): Install executables from gems in the bundle to the specified directory\. Defaults to \fBfalse\fR\. . .IP "\(bu" 4 \fBcache_all\fR (\fBBUNDLE_CACHE_ALL\fR): Cache all gems, including path and git gems\. This needs to be explicitly configured on bundler 1 and bundler 2, but will be the default on bundler 3\. . .IP "\(bu" 4 \fBcache_all_platforms\fR (\fBBUNDLE_CACHE_ALL_PLATFORMS\fR): Cache gems for all platforms\. . .IP "\(bu" 4 \fBcache_path\fR (\fBBUNDLE_CACHE_PATH\fR): The directory that bundler will place cached gems in when running \fBbundle package\fR, and that bundler will look in when installing gems\. Defaults to \fBvendor/cache\fR\. . .IP "\(bu" 4 \fBclean\fR (\fBBUNDLE_CLEAN\fR): Whether Bundler should run \fBbundle clean\fR automatically after \fBbundle install\fR\. . .IP "\(bu" 4 \fBconsole\fR (\fBBUNDLE_CONSOLE\fR): The console that \fBbundle console\fR starts\. Defaults to \fBirb\fR\. . .IP "\(bu" 4 \fBdefault_install_uses_path\fR (\fBBUNDLE_DEFAULT_INSTALL_USES_PATH\fR): Whether a \fBbundle install\fR without an explicit \fB\-\-path\fR argument defaults to installing gems in \fB\.bundle\fR\. . .IP "\(bu" 4 \fBdeployment\fR (\fBBUNDLE_DEPLOYMENT\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\. . .IP "\(bu" 4 \fBdisable_checksum_validation\fR (\fBBUNDLE_DISABLE_CHECKSUM_VALIDATION\fR): Allow installing gems even if they do not match the checksum provided by RubyGems\. . .IP "\(bu" 4 \fBdisable_exec_load\fR (\fBBUNDLE_DISABLE_EXEC_LOAD\fR): Stop Bundler from using \fBload\fR to launch an executable in\-process in \fBbundle exec\fR\. . .IP "\(bu" 4 \fBdisable_local_branch_check\fR (\fBBUNDLE_DISABLE_LOCAL_BRANCH_CHECK\fR): Allow Bundler to use a local git override without a branch specified in the Gemfile\. . .IP "\(bu" 4 \fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\. . .IP "\(bu" 4 \fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems\' normal location\. . .IP "\(bu" 4 \fBdisable_version_check\fR (\fBBUNDLE_DISABLE_VERSION_CHECK\fR): Stop Bundler from checking if a newer Bundler version is available on rubygems\.org\. . .IP "\(bu" 4 \fBforce_ruby_platform\fR (\fBBUNDLE_FORCE_RUBY_PLATFORM\fR): Ignore the current machine\'s platform and install only \fBruby\fR platform gems\. As a result, gems with native extensions will be compiled from source\. . .IP "\(bu" 4 \fBfrozen\fR (\fBBUNDLE_FROZEN\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\. Defaults to \fBtrue\fR when \fB\-\-deployment\fR is used\. . .IP "\(bu" 4 \fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in \fBREADME\fR file when you create a new gem via \fBbundle gem\fR command\. It can be overridden by passing an explicit \fB\-\-github\-username\fR flag to \fBbundle gem\fR\. . .IP "\(bu" 4 \fBgem\.push_key\fR (\fBBUNDLE_GEM__PUSH_KEY\fR): Sets the \fB\-\-key\fR parameter for \fBgem push\fR when using the \fBrake release\fR command with a private gemstash server\. . .IP "\(bu" 4 \fBgemfile\fR (\fBBUNDLE_GEMFILE\fR): The name of the file that bundler should use as the \fBGemfile\fR\. This location of this file also sets the root of the project, which is used to resolve relative paths in the \fBGemfile\fR, among other things\. By default, bundler will search up from the current working directory until it finds a \fBGemfile\fR\. . .IP "\(bu" 4 \fBglobal_gem_cache\fR (\fBBUNDLE_GLOBAL_GEM_CACHE\fR): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation\. . .IP "\(bu" 4 \fBignore_messages\fR (\fBBUNDLE_IGNORE_MESSAGES\fR): When set, no post install messages will be printed\. To silence a single gem, use dot notation like \fBignore_messages\.httparty true\fR\. . .IP "\(bu" 4 \fBinit_gems_rb\fR (\fBBUNDLE_INIT_GEMS_RB\fR): Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\. . .IP "\(bu" 4 \fBjobs\fR (\fBBUNDLE_JOBS\fR): The number of gems Bundler can install in parallel\. Defaults to 1 on Windows, and to the the number of processors on other platforms\. . .IP "\(bu" 4 \fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR): Whether \fBbundle package\fR should skip installing gems\. . .IP "\(bu" 4 \fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR): Whether Bundler should leave outdated gems unpruned when caching\. . .IP "\(bu" 4 \fBpath\fR (\fBBUNDLE_PATH\fR): The location on disk where all gems in your bundle will be located regardless of \fB$GEM_HOME\fR or \fB$GEM_PATH\fR values\. Bundle gems not found in this location will be installed by \fBbundle install\fR\. Defaults to \fBGem\.dir\fR\. When \-\-deployment is used, defaults to vendor/bundle\. . .IP "\(bu" 4 \fBpath\.system\fR (\fBBUNDLE_PATH__SYSTEM\fR): Whether Bundler will install gems into the default system path (\fBGem\.dir\fR)\. . .IP "\(bu" 4 \fBpath_relative_to_cwd\fR (\fBBUNDLE_PATH_RELATIVE_TO_CWD\fR) Makes \fB\-\-path\fR relative to the CWD instead of the \fBGemfile\fR\. . .IP "\(bu" 4 \fBplugins\fR (\fBBUNDLE_PLUGINS\fR): Enable Bundler\'s experimental plugin system\. . .IP "\(bu" 4 \fBprefer_patch\fR (BUNDLE_PREFER_PATCH): Prefer updating only to next patch version during updates\. Makes \fBbundle update\fR calls equivalent to \fBbundler update \-\-patch\fR\. . .IP "\(bu" 4 \fBprint_only_version_number\fR (\fBBUNDLE_PRINT_ONLY_VERSION_NUMBER\fR): Print only version number from \fBbundler \-\-version\fR\. . .IP "\(bu" 4 \fBredirect\fR (\fBBUNDLE_REDIRECT\fR): The number of redirects allowed for network requests\. Defaults to \fB5\fR\. . .IP "\(bu" 4 \fBretry\fR (\fBBUNDLE_RETRY\fR): The number of times to retry failed network requests\. Defaults to \fB3\fR\. . .IP "\(bu" 4 \fBsetup_makes_kernel_gem_public\fR (\fBBUNDLE_SETUP_MAKES_KERNEL_GEM_PUBLIC\fR): Have \fBBundler\.setup\fR make the \fBKernel#gem\fR method public, even though RubyGems declares it as private\. . .IP "\(bu" 4 \fBshebang\fR (\fBBUNDLE_SHEBANG\fR): The program name that should be invoked for generated binstubs\. Defaults to the ruby install name used to generate the binstub\. . .IP "\(bu" 4 \fBsilence_deprecations\fR (\fBBUNDLE_SILENCE_DEPRECATIONS\fR): Whether Bundler should silence deprecation warnings for behavior that will be changed in the next major version\. . .IP "\(bu" 4 \fBsilence_root_warning\fR (\fBBUNDLE_SILENCE_ROOT_WARNING\fR): Silence the warning Bundler prints when installing gems as root\. . .IP "\(bu" 4 \fBssl_ca_cert\fR (\fBBUNDLE_SSL_CA_CERT\fR): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format\. . .IP "\(bu" 4 \fBssl_client_cert\fR (\fBBUNDLE_SSL_CLIENT_CERT\fR): Path to a designated file containing a X\.509 client certificate and key in PEM format\. . .IP "\(bu" 4 \fBssl_verify_mode\fR (\fBBUNDLE_SSL_VERIFY_MODE\fR): The SSL verification mode Bundler uses when making HTTPS requests\. Defaults to verify peer\. . .IP "\(bu" 4 \fBsuppress_install_using_messages\fR (\fBBUNDLE_SUPPRESS_INSTALL_USING_MESSAGES\fR): Avoid printing \fBUsing \.\.\.\fR messages during installation when the version of a gem has not changed\. . .IP "\(bu" 4 \fBsystem_bindir\fR (\fBBUNDLE_SYSTEM_BINDIR\fR): The location where RubyGems installs binstubs\. Defaults to \fBGem\.bindir\fR\. . .IP "\(bu" 4 \fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\. . .IP "\(bu" 4 \fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\. . .IP "\(bu" 4 \fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR): The custom user agent fragment Bundler includes in API requests\. . .IP "\(bu" 4 \fBwith\fR (\fBBUNDLE_WITH\fR): A \fB:\fR\-separated list of groups whose gems bundler should install\. . .IP "\(bu" 4 \fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A \fB:\fR\-separated list of groups whose gems bundler should not install\. . .IP "" 0 . .P In general, you should set these settings per\-application by using the applicable flag to the bundle install(1) \fIbundle\-install\.1\.html\fR or bundle package(1) \fIbundle\-package\.1\.html\fR command\. . .P You can set them globally either via environment variables or \fBbundle config\fR, whichever is preferable for your setup\. If you use both, environment variables will take preference over global settings\. . .SH "LOCAL GIT REPOS" Bundler also allows you to work against a git repository locally instead of using the remote version\. This can be achieved by setting up a local override: . .IP "" 4 . .nf bundle config set \-\-local local\.GEM_NAME /path/to/local/git/repository . .fi . .IP "" 0 . .P For example, in order to use a local Rack repository, a developer could call: . .IP "" 4 . .nf bundle config set \-\-local local\.rack ~/Work/git/rack . .fi . .IP "" 0 . .P Now instead of checking out the remote git repository, the local override will be used\. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler\. This means a commit in the local git repo will update the revision in the \fBGemfile\.lock\fR to the local git repo revision\. This requires the same attention as git submodules\. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine\. You\'ll also need to CGI escape your usernames and passwords as well\. . .P Bundler does many checks to ensure a developer won\'t work with invalid references\. Particularly, we force a developer to specify a branch in the \fBGemfile\fR in order to use this feature\. If the branch specified in the \fBGemfile\fR and the current branch in the local git repository do not match, Bundler will abort\. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch\. . .P Finally, Bundler also ensures that the current revision in the \fBGemfile\.lock\fR exists in the local git repository\. By doing this, Bundler forces you to fetch the latest changes in the remotes\. . .SH "MIRRORS OF GEM SOURCES" Bundler supports overriding gem sources with mirrors\. This allows you to configure rubygems\.org as the gem source in your Gemfile while still using your mirror to fetch gems\. . .IP "" 4 . .nf bundle config set \-\-global mirror\.SOURCE_URL MIRROR_URL . .fi . .IP "" 0 . .P For example, to use a mirror of rubygems\.org hosted at rubygems\-mirror\.org: . .IP "" 4 . .nf bundle config set \-\-global mirror\.http://rubygems\.org http://rubygems\-mirror\.org . .fi . .IP "" 0 . .P Each mirror also provides a fallback timeout setting\. If the mirror does not respond within the fallback timeout, Bundler will try to use the original server instead of the mirror\. . .IP "" 4 . .nf bundle config set \-\-global mirror\.SOURCE_URL\.fallback_timeout TIMEOUT . .fi . .IP "" 0 . .P For example, to fall back to rubygems\.org after 3 seconds: . .IP "" 4 . .nf bundle config set \-\-global mirror\.https://rubygems\.org\.fallback_timeout 3 . .fi . .IP "" 0 . .P The default fallback timeout is 0\.1 seconds, but the setting can currently only accept whole seconds (for example, 1, 15, or 30)\. . .SH "CREDENTIALS FOR GEM SOURCES" Bundler allows you to configure credentials for any gem source, which allows you to avoid putting secrets into your Gemfile\. . .IP "" 4 . .nf bundle config set \-\-global SOURCE_HOSTNAME USERNAME:PASSWORD . .fi . .IP "" 0 . .P For example, to save the credentials of user \fBclaudette\fR for the gem source at \fBgems\.longerous\.com\fR, you would run: . .IP "" 4 . .nf bundle config set \-\-global gems\.longerous\.com claudette:s00pers3krit . .fi . .IP "" 0 . .P Or you can set the credentials as an environment variable like this: . .IP "" 4 . .nf export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit" . .fi . .IP "" 0 . .P For gems with a git source with HTTP(S) URL you can specify credentials like so: . .IP "" 4 . .nf bundle config set \-\-global https://github\.com/rubygems/rubygems\.git username:password . .fi . .IP "" 0 . .P Or you can set the credentials as an environment variable like so: . .IP "" 4 . .nf export BUNDLE_GITHUB__COM=username:password . .fi . .IP "" 0 . .P This is especially useful for private repositories on hosts such as Github, where you can use personal OAuth tokens: . .IP "" 4 . .nf export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x\-oauth\-basic . .fi . .IP "" 0 . .P Note that any configured credentials will be redacted by informative commands such as \fBbundle config list\fR or \fBbundle config get\fR, unless you use the \fB\-\-parseable\fR flag\. This is to avoid unintentially leaking credentials when copy\-pasting bundler output\. . .P Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations: . .IP "\(bu" 4 Any \fB\-\fR characters in a host name are mapped to a triple dash (\fB___\fR) in the corresponding enviroment variable\. . .IP "\(bu" 4 Any \fB\.\fR characters in a host name are mapped to a double dash (\fB__\fR) in the corresponding environment variable\. . .IP "" 0 . .P This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you\'ll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\. . .SH "CONFIGURE BUNDLER DIRECTORIES" Bundler\'s home, config, cache and plugin directories are able to be configured through environment variables\. The default location for Bundler\'s home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values . .IP "" 4 . .nf BUNDLE_USER_HOME : $HOME/\.bundle BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin . .fi . .IP "" 0 PK ]uw-w-,gems/bundler-2.2.24/lib/bundler/installer.rbnu[# frozen_string_literal: true require "rubygems/dependency_installer" require_relative "worker" require_relative "installer/parallel_installer" require_relative "installer/standalone" require_relative "installer/gem_installer" module Bundler class Installer class << self attr_accessor :ambiguous_gems Installer.ambiguous_gems = [] end attr_reader :post_install_messages # Begins the installation process for Bundler. # For more information see the #run method on this class. def self.install(root, definition, options = {}) installer = new(root, definition) Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL_ALL, definition.dependencies) installer.run(options) Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL_ALL, definition.dependencies) installer end def initialize(root, definition) @root = root @definition = definition @post_install_messages = {} end # Runs the install procedures for a specific Gemfile. # # Firstly, this method will check to see if `Bundler.bundle_path` exists # and if not then Bundler will create the directory. This is usually the same # location as RubyGems which typically is the `~/.gem` directory # unless other specified. # # Secondly, it checks if Bundler has been configured to be "frozen". # Frozen ensures that the Gemfile and the Gemfile.lock file are matching. # This stops a situation where a developer may update the Gemfile but may not run # `bundle install`, which leads to the Gemfile.lock file not being correctly updated. # If this file is not correctly updated then any other developer running # `bundle install` will potentially not install the correct gems. # # Thirdly, Bundler checks if there are any dependencies specified in the Gemfile. # If there are no dependencies specified then Bundler returns a warning message stating # so and this method returns. # # Fourthly, Bundler checks if the Gemfile.lock exists, and if so # then proceeds to set up a definition based on the Gemfile and the Gemfile.lock. # During this step Bundler will also download information about any new gems # that are not in the Gemfile.lock and resolve any dependencies if needed. # # Fifthly, Bundler resolves the dependencies either through a cache of gems or by remote. # This then leads into the gems being installed, along with stubs for their executables, # but only if the --binstubs option has been passed or Bundler.options[:bin] has been set # earlier. # # Sixthly, a new Gemfile.lock is created from the installed gems to ensure that the next time # that a user runs `bundle install` they will receive any updates from this process. # # Finally, if the user has specified the standalone flag, Bundler will generate the needed # require paths and save them in a `setup.rb` file. See `bundle standalone --help` for more # information. def run(options) create_bundle_path ProcessLock.lock do if Bundler.frozen_bundle? @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment]) end if @definition.dependencies.empty? Bundler.ui.warn "The Gemfile specifies no dependencies" lock return end if resolve_if_needed(options) ensure_specs_are_compatible! load_plugins options.delete(:jobs) else options[:jobs] = 1 # to avoid the overhead of Bundler::Worker end install(options) Gem::Specification.reset # invalidate gem specification cache so that installed gems are immediately available lock unless Bundler.frozen_bundle? Standalone.new(options[:standalone], @definition).generate if options[:standalone] end end def generate_bundler_executable_stubs(spec, options = {}) if options[:binstubs_cmd] && spec.executables.empty? options = {} spec.runtime_dependencies.each do |dep| bins = @definition.specs[dep].first.executables options[dep.name] = bins unless bins.empty? end if options.any? Bundler.ui.warn "#{spec.name} has no executables, but you may want " \ "one from a gem it depends on." options.each {|name, bins| Bundler.ui.warn " #{name} has: #{bins.join(", ")}" } else Bundler.ui.warn "There are no executables for the gem #{spec.name}." end return end # double-assignment to avoid warnings about variables that will be used by ERB bin_path = Bundler.bin_path bin_path = bin_path relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path) relative_gemfile_path = relative_gemfile_path ruby_command = Thor::Util.ruby_command ruby_command = ruby_command template_path = File.expand_path("../templates/Executable", __FILE__) if spec.name == "bundler" template_path += ".bundler" spec.executables = %(bundle) end template = File.read(template_path) exists = [] spec.executables.each do |executable| binstub_path = "#{bin_path}/#{executable}" if File.exist?(binstub_path) && !options[:force] exists << executable next end mode = Gem.win_platform? ? "wb:UTF-8" : "w" require "erb" content = if RUBY_VERSION >= "2.6" ERB.new(template, :trim_mode => "-").result(binding) else ERB.new(template, nil, "-").result(binding) end File.write(binstub_path, content, :mode => mode, :perm => 0o777 & ~File.umask) if Gem.win_platform? || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{binstub_path}.cmd", prefix + content, :mode => mode) end end if options[:binstubs_cmd] && exists.any? case exists.size when 1 Bundler.ui.warn "Skipped #{exists[0]} since it already exists." when 2 Bundler.ui.warn "Skipped #{exists.join(" and ")} since they already exist." else items = exists[0...-1].empty? ? nil : exists[0...-1].join(", ") skipped = [items, exists[-1]].compact.join(" and ") Bundler.ui.warn "Skipped #{skipped} since they already exist." end Bundler.ui.warn "If you want to overwrite skipped stubs, use --force." end end def generate_standalone_bundler_executable_stubs(spec, options = {}) # double-assignment to avoid warnings about variables that will be used by ERB bin_path = Bundler.bin_path unless path = Bundler.settings[:path] raise "Can't standalone without an explicit path set" end standalone_path = Bundler.root.join(path).relative_path_from(bin_path) standalone_path = standalone_path template = File.read(File.expand_path("../templates/Executable.standalone", __FILE__)) ruby_command = Thor::Util.ruby_command ruby_command = ruby_command spec.executables.each do |executable| next if executable == "bundle" executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) executable_path = executable_path mode = Gem.win_platform? ? "wb:UTF-8" : "w" require "erb" content = if RUBY_VERSION >= "2.6" ERB.new(template, :trim_mode => "-").result(binding) else ERB.new(template, nil, "-").result(binding) end File.write("#{bin_path}/#{executable}", content, :mode => mode, :perm => 0o755) if Gem.win_platform? || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{bin_path}/#{executable}.cmd", prefix + content, :mode => mode) end end end private # the order that the resolver provides is significant, since # dependencies might affect the installation of a gem. # that said, it's a rare situation (other than rake), and parallel # installation is SO MUCH FASTER. so we let people opt in. def install(options) force = options["force"] jobs = installation_parallelization(options) install_in_parallel jobs, options[:standalone], force end def installation_parallelization(options) if jobs = options.delete(:jobs) return jobs end if jobs = Bundler.settings[:jobs] return jobs end # Parallelization has some issues on Windows, so it's not yet the default return 1 if Gem.win_platform? Bundler.settings.processor_count end def load_plugins Bundler.rubygems.load_plugins requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) } path_plugin_files = requested_path_gems.map do |spec| begin Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}") rescue TypeError error_message = "#{spec.name} #{spec.version} has an invalid gemspec" raise Gem::InvalidSpecificationException, error_message end end.flatten Bundler.rubygems.load_plugin_files(path_plugin_files) Bundler.rubygems.load_env_plugins end def ensure_specs_are_compatible! system_ruby = Bundler::RubyVersion.system rubygems_version = Gem::Version.create(Gem::VERSION) @definition.specs.each do |spec| if required_ruby_version = spec.required_ruby_version unless required_ruby_version.satisfied_by?(system_ruby.gem_version) raise InstallError, "#{spec.full_name} requires ruby version #{required_ruby_version}, " \ "which is incompatible with the current version, #{system_ruby}" end end next unless required_rubygems_version = spec.required_rubygems_version unless required_rubygems_version.satisfied_by?(rubygems_version) raise InstallError, "#{spec.full_name} requires rubygems version #{required_rubygems_version}, " \ "which is incompatible with the current version, #{rubygems_version}" end end end def install_in_parallel(size, standalone, force = false) spec_installations = ParallelInstaller.call(self, @definition.specs, size, standalone, force) spec_installations.each do |installation| post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message? end end def create_bundle_path SharedHelpers.filesystem_access(Bundler.bundle_path.to_s) do |p| Bundler.mkdir_p(p) end unless Bundler.bundle_path.exist? rescue Errno::EEXIST raise PathError, "Could not install to path `#{Bundler.bundle_path}` " \ "because a file already exists at that path. Either remove or rename the file so the directory can be created." end # returns whether or not a re-resolve was needed def resolve_if_needed(options) if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file? return false if @definition.nothing_changed? && !@definition.missing_specs? end options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely! true end def lock(opts = {}) @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections]) end end end PK ]Vw8gems/bundler-2.2.24/lib/bundler/fetcher/compact_index.rbnu[# frozen_string_literal: true require_relative "base" require_relative "../worker" module Bundler autoload :CompactIndexClient, File.expand_path("../compact_index_client", __dir__) class Fetcher class CompactIndex < Base def self.compact_index_request(method_name) method = instance_method(method_name) undef_method(method_name) define_method(method_name) do |*args, &blk| begin method.bind(self).call(*args, &blk) rescue NetworkDownError, CompactIndexClient::Updater::MisMatchedChecksumError => e raise HTTPError, e.message rescue AuthenticationRequiredError # Fail since we got a 401 from the server. raise rescue HTTPError => e Bundler.ui.trace(e) nil end end end def specs(gem_names) specs_for_names(gem_names) end compact_index_request :specs def specs_for_names(gem_names) gem_info = [] complete_gems = [] remaining_gems = gem_names.dup until remaining_gems.empty? log_specs "Looking up gems #{remaining_gems.inspect}" deps = begin parallel_compact_index_client.dependencies(remaining_gems) rescue TooManyRequestsError @bundle_worker.stop if @bundle_worker @bundle_worker = nil # reset it. Not sure if necessary serial_compact_index_client.dependencies(remaining_gems) end next_gems = deps.map {|d| d[3].map(&:first).flatten(1) }.flatten(1).uniq deps.each {|dep| gem_info << dep } complete_gems.concat(deps.map(&:first)).uniq! remaining_gems = next_gems - complete_gems end @bundle_worker.stop if @bundle_worker @bundle_worker = nil # reset it. Not sure if necessary gem_info end def fetch_spec(spec) spec -= [nil, "ruby", ""] contents = compact_index_client.spec(*spec) return nil if contents.nil? contents.unshift(spec.first) contents[3].map! {|d| Gem::Dependency.new(*d) } EndpointSpecification.new(*contents) end compact_index_request :fetch_spec def available? return nil unless SharedHelpers.md5_available? user_home = Bundler.user_home return nil unless user_home.directory? && user_home.writable? # Read info file checksums out of /versions, so we can know if gems are up to date fetch_uri.scheme != "file" && compact_index_client.update_and_parse_checksums! rescue CompactIndexClient::Updater::MisMatchedChecksumError => e Bundler.ui.debug(e.message) nil end compact_index_request :available? def api_fetcher? true end private def compact_index_client @compact_index_client ||= SharedHelpers.filesystem_access(cache_path) do CompactIndexClient.new(cache_path, client_fetcher) end end def parallel_compact_index_client compact_index_client.execution_mode = lambda do |inputs, &blk| func = lambda {|object, _index| blk.call(object) } worker = bundle_worker(func) inputs.each {|input| worker.enq(input) } inputs.map { worker.deq } end compact_index_client end def serial_compact_index_client compact_index_client.sequential_execution_mode! compact_index_client end def bundle_worker(func = nil) @bundle_worker ||= begin worker_name = "Compact Index (#{display_uri.host})" Bundler::Worker.new(Bundler.settings.processor_count, worker_name, func) end @bundle_worker.tap do |worker| worker.instance_variable_set(:@func, func) if func end end def cache_path Bundler.user_cache.join("compact_index", remote.cache_slug) end def client_fetcher ClientFetcher.new(self, Bundler.ui) end ClientFetcher = Struct.new(:fetcher, :ui) do def call(path, headers) fetcher.downloader.fetch(fetcher.fetch_uri + path, headers) rescue NetworkDownError => e raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"] ui.warn "Using the cached data for the new index because of a network error: #{e}" Net::HTTPNotModified.new(nil, nil, nil) end end end end end PK ]L;8 5gems/bundler-2.2.24/lib/bundler/fetcher/dependency.rbnu[# frozen_string_literal: true require_relative "base" require "cgi" module Bundler class Fetcher class Dependency < Base def available? @available ||= fetch_uri.scheme != "file" && downloader.fetch(dependency_api_uri) rescue NetworkDownError => e raise HTTPError, e.message rescue AuthenticationRequiredError # Fail since we got a 401 from the server. raise rescue HTTPError false end def api_fetcher? true end def specs(gem_names, full_dependency_list = [], last_spec_list = []) query_list = gem_names.uniq - full_dependency_list log_specs "Query List: #{query_list.inspect}" return last_spec_list if query_list.empty? spec_list, deps_list = Bundler::Retry.new("dependency api", FAIL_ERRORS).attempts do dependency_specs(query_list) end returned_gems = spec_list.map(&:first).uniq specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list) rescue MarshalError Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over Bundler.ui.debug "could not fetch from the dependency API, trying the full index" nil rescue HTTPError, GemspecError Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over Bundler.ui.debug "could not fetch from the dependency API\nit's suggested to retry using the full index via `bundle install --full-index`" nil end def dependency_specs(gem_names) Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(",")}" gem_list = unmarshalled_dep_gems(gem_names) get_formatted_specs_and_deps(gem_list) end def unmarshalled_dep_gems(gem_names) gem_list = [] gem_names.each_slice(Source::Rubygems::API_REQUEST_SIZE) do |names| marshalled_deps = downloader.fetch(dependency_api_uri(names)).body gem_list.concat(Bundler.load_marshal(marshalled_deps)) end gem_list end def get_formatted_specs_and_deps(gem_list) deps_list = [] spec_list = [] gem_list.each do |s| deps_list.concat(s[:dependencies].map(&:first)) deps = s[:dependencies].map {|n, d| [n, d.split(", ")] } spec_list.push([s[:name], s[:number], s[:platform], deps]) end [spec_list, deps_list] end def dependency_api_uri(gem_names = []) uri = fetch_uri + "api/v1/dependencies" uri.query = "gems=#{CGI.escape(gem_names.sort.join(","))}" if gem_names.any? uri end end end end PK ]/gems/bundler-2.2.24/lib/bundler/fetcher/base.rbnu[# frozen_string_literal: true module Bundler class Fetcher class Base attr_reader :downloader attr_reader :display_uri attr_reader :remote def initialize(downloader, remote, display_uri) raise "Abstract class" if self.class == Base @downloader = downloader @remote = remote @display_uri = display_uri end def remote_uri @remote.uri end def fetch_uri @fetch_uri ||= begin if remote_uri.host == "rubygems.org" uri = remote_uri.dup uri.host = "index.rubygems.org" uri else remote_uri end end end def available? true end def api_fetcher? false end private def log_specs(debug_msg) if Bundler.ui.debug? Bundler.ui.debug debug_msg else Bundler.ui.info ".", false end end end end end PK ],dd0gems/bundler-2.2.24/lib/bundler/fetcher/index.rbnu[# frozen_string_literal: true require_relative "base" module Bundler class Fetcher class Index < Base def specs(_gem_names) Bundler.rubygems.fetch_all_remote_specs(remote) rescue Gem::RemoteFetcher::FetchError => e case e.message when /certificate verify failed/ raise CertificateFailureError.new(display_uri) when /401/ raise BadAuthenticationError, remote_uri if remote_uri.userinfo raise AuthenticationRequiredError, remote_uri when /403/ raise BadAuthenticationError, remote_uri if remote_uri.userinfo raise AuthenticationRequiredError, remote_uri else raise HTTPError, "Could not fetch specs from #{display_uri} due to underlying error <#{e.message}>" end end def fetch_spec(spec) spec -= [nil, "ruby", ""] spec_file_name = "#{spec.join "-"}.gemspec" uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") if uri.scheme == "file" path = Bundler.rubygems.correct_for_windows_path(uri.path) Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(path)) elsif cached_spec_path = gemspec_cached_path(spec_file_name) Bundler.load_gemspec(cached_spec_path) else Bundler.load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) end rescue MarshalError raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ "Your network or your gem server is probably having issues right now." end private # cached gem specification path, if one exists def gemspec_cached_path(spec_file_name) paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } paths.find {|path| File.file? path } end end end end PK ]]Y Y 5gems/bundler-2.2.24/lib/bundler/fetcher/downloader.rbnu[# frozen_string_literal: true module Bundler class Fetcher class Downloader attr_reader :connection attr_reader :redirect_limit def initialize(connection, redirect_limit) @connection = connection @redirect_limit = redirect_limit end def fetch(uri, headers = {}, counter = 0) raise HTTPError, "Too many redirects" if counter >= redirect_limit filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) response = request(uri, headers) Bundler.ui.debug("HTTP #{response.code} #{response.message} #{filtered_uri}") case response when Net::HTTPSuccess, Net::HTTPNotModified response when Net::HTTPRedirection new_uri = Bundler::URI.parse(response["location"]) if new_uri.host == uri.host new_uri.user = uri.user new_uri.password = uri.password end fetch(new_uri, headers, counter + 1) when Net::HTTPRequestedRangeNotSatisfiable new_headers = headers.dup new_headers.delete("Range") new_headers["Accept-Encoding"] = "gzip" fetch(uri, new_headers) when Net::HTTPRequestEntityTooLarge raise FallbackError, response.body when Net::HTTPTooManyRequests raise TooManyRequestsError, response.body when Net::HTTPUnauthorized raise BadAuthenticationError, uri.host if uri.userinfo raise AuthenticationRequiredError, uri.host when Net::HTTPNotFound raise FallbackError, "Net::HTTPNotFound: #{filtered_uri}" else raise HTTPError, "#{response.class}#{": #{response.body}" unless response.body.empty?}" end end def request(uri, headers) validate_uri_scheme!(uri) filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) Bundler.ui.debug "HTTP GET #{filtered_uri}" req = Net::HTTP::Get.new uri.request_uri, headers if uri.user user = CGI.unescape(uri.user) password = uri.password ? CGI.unescape(uri.password) : nil req.basic_auth(user, password) end connection.request(uri, req) rescue NoMethodError => e raise unless ["undefined method", "use_ssl="].all? {|snippet| e.message.include? snippet } raise LoadError.new("cannot load such file -- openssl") rescue OpenSSL::SSL::SSLError raise CertificateFailureError.new(uri) rescue *HTTP_ERRORS => e Bundler.ui.trace e if e.is_a?(SocketError) || e.message =~ /host down:/ raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \ "connection and try again." else raise HTTPError, "Network error while fetching #{filtered_uri}" \ " (#{e})" end end private def validate_uri_scheme!(uri) return if uri.scheme =~ /\Ahttps?\z/ raise InvalidOption, "The request uri `#{uri}` has an invalid scheme (`#{uri.scheme}`). " \ "Did you mean `http` or `https`?" end end end end PK ]+(gems/bundler-2.2.24/lib/bundler/index.rbnu[# frozen_string_literal: true module Bundler class Index include Enumerable def self.build i = new yield i i end attr_reader :specs, :all_specs, :sources protected :specs, :all_specs RUBY = "ruby".freeze NULL = "\0".freeze def initialize @sources = [] @cache = {} @specs = Hash.new {|h, k| h[k] = {} } @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH } end def initialize_copy(o) @sources = o.sources.dup @cache = {} @specs = Hash.new {|h, k| h[k] = {} } @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH } o.specs.each do |name, hash| @specs[name] = hash.dup end o.all_specs.each do |name, array| @all_specs[name] = array.dup end end def inspect "#<#{self.class}:0x#{object_id} sources=#{sources.map(&:inspect)} specs.size=#{specs.size}>" end def empty? each { return false } true end def search_all(name) all_matches = local_search(name) + @all_specs[name] @sources.each do |source| all_matches.concat(source.search_all(name)) end all_matches end # Search this index's specs, and any source indexes that this index knows # about, returning all of the results. def search(query, base = nil) sort_specs(unsorted_search(query, base)) end def unsorted_search(query, base) results = local_search(query, base) seen = results.map(&:full_name).uniq unless @sources.empty? @sources.each do |source| source.unsorted_search(query, base).each do |spec| next if seen.include?(spec.full_name) seen << spec.full_name results << spec end end results end protected :unsorted_search def self.sort_specs(specs) specs.sort_by do |s| platform_string = s.platform.to_s [s.version, platform_string == RUBY ? NULL : platform_string] end end def sort_specs(specs) self.class.sort_specs(specs) end def local_search(query, base = nil) case query when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query) when String then specs_by_name(query) when Gem::Dependency then search_by_dependency(query, base) when DepProxy then search_by_dependency(query.dep, base) else raise "You can't search for a #{query.inspect}." end end alias_method :[], :search def <<(spec) @specs[spec.name][spec.full_name] = spec spec end def each(&blk) return enum_for(:each) unless blk specs.values.each do |spec_sets| spec_sets.values.each(&blk) end sources.each {|s| s.each(&blk) } self end def spec_names names = specs.keys + sources.map(&:spec_names) names.uniq! names end def unmet_dependency_names dependency_names.select do |name| search(name).empty? end end def dependency_names names = [] each do |spec| spec.dependencies.each do |dep| next if dep.type == :development names << dep.name end end names.uniq end def use(other, override_dupes = false) return unless other other.each do |s| if (dupes = search_by_spec(s)) && !dupes.empty? # safe to << since it's a new array when it has contents @all_specs[s.name] = dupes << s next unless override_dupes end self << s end self end def size @sources.inject(@specs.size) do |size, source| size += source.size end end # Whether all the specs in self are in other # TODO: rename to #include? def ==(other) all? do |spec| other_spec = other[spec].first other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source end end def dependencies_eql?(spec, other_spec) deps = spec.dependencies.select {|d| d.type != :development } other_deps = other_spec.dependencies.select {|d| d.type != :development } deps.sort == other_deps.sort end def add_source(index) raise ArgumentError, "Source must be an index, not #{index.class}" unless index.is_a?(Index) @sources << index @sources.uniq! # need to use uniq! here instead of checking for the item before adding end private def specs_by_name(name) @specs[name].values end def search_by_dependency(dependency, base = nil) @cache[base || false] ||= {} @cache[base || false][dependency] ||= begin specs = specs_by_name(dependency.name) specs += base if base found = specs.select do |spec| next true if spec.source.is_a?(Source::Gemspec) if base # allow all platforms when searching from a lockfile dependency.matches_spec?(spec) else dependency.matches_spec?(spec) && Gem::Platform.match_spec?(spec) end end found end end EMPTY_SEARCH = [].freeze def search_by_spec(spec) spec = @specs[spec.name][spec.full_name] spec ? [spec] : EMPTY_SEARCH end end end PK ]PCm/gems/bundler-2.2.24/lib/bundler/ruby_version.rbnu[# frozen_string_literal: true module Bundler class RubyVersion attr_reader :versions, :patchlevel, :engine, :engine_versions, :gem_version, :engine_gem_version def initialize(versions, patchlevel, engine, engine_version) # The parameters to this method must satisfy the # following constraints, which are verified in # the DSL: # # * If an engine is specified, an engine version # must also be specified # * If an engine version is specified, an engine # must also be specified # * If the engine is "ruby", the engine version # must not be specified, or the engine version # specified must match the version. @versions = Array(versions).map do |v| op, v = Gem::Requirement.parse(v) op == "=" ? v.to_s : "#{op} #{v}" end @gem_version = Gem::Requirement.create(@versions.first).requirements.first.last @input_engine = engine && engine.to_s @engine = engine && engine.to_s || "ruby" @engine_versions = (engine_version && Array(engine_version)) || @versions @engine_gem_version = Gem::Requirement.create(@engine_versions.first).requirements.first.last @patchlevel = patchlevel end def to_s(versions = self.versions) output = String.new("ruby #{versions_string(versions)}") output << "p#{patchlevel}" if patchlevel output << " (#{engine} #{versions_string(engine_versions)})" unless engine == "ruby" output end # @private PATTERN = / ruby\s ([\d.]+) # ruby version (?:p(-?\d+))? # optional patchlevel (?:\s\((\S+)\s(.+)\))? # optional engine info /xo.freeze # Returns a RubyVersion from the given string. # @param [String] the version string to match. # @return [RubyVersion,Nil] The version if the string is a valid RubyVersion # description, and nil otherwise. def self.from_string(string) new($1, $2, $3, $4) if string =~ PATTERN end def single_version_string to_s(gem_version) end def ==(other) versions == other.versions && engine == other.engine && engine_versions == other.engine_versions && patchlevel == other.patchlevel end def host @host ||= [ RbConfig::CONFIG["host_cpu"], RbConfig::CONFIG["host_vendor"], RbConfig::CONFIG["host_os"], ].join("-") end # Returns a tuple of these things: # [diff, this, other] # The priority of attributes are # 1. engine # 2. ruby_version # 3. engine_version def diff(other) raise ArgumentError, "Can only diff with a RubyVersion, not a #{other.class}" unless other.is_a?(RubyVersion) if engine != other.engine && @input_engine [:engine, engine, other.engine] elsif versions.empty? || !matches?(versions, other.gem_version) [:version, versions_string(versions), versions_string(other.versions)] elsif @input_engine && !matches?(engine_versions, other.engine_gem_version) [:engine_version, versions_string(engine_versions), versions_string(other.engine_versions)] elsif patchlevel && (!patchlevel.is_a?(String) || !other.patchlevel.is_a?(String) || !matches?(patchlevel, other.patchlevel)) [:patchlevel, patchlevel, other.patchlevel] end end def versions_string(versions) Array(versions).join(", ") end def self.system ruby_engine = RUBY_ENGINE.dup ruby_version = ENV.fetch("BUNDLER_SPEC_RUBY_VERSION") { RUBY_VERSION }.dup ruby_engine_version = RUBY_ENGINE_VERSION.dup patchlevel = RUBY_PATCHLEVEL.to_s @ruby_version ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version) end def to_gem_version_with_patchlevel @gem_version_with_patch ||= begin Gem::Version.create("#{@gem_version}.#{@patchlevel}") rescue ArgumentError @gem_version end end def exact? return @exact if defined?(@exact) @exact = versions.all? {|v| Gem::Requirement.create(v).exact? } end private def matches?(requirements, version) # Handles RUBY_PATCHLEVEL of -1 for instances like ruby-head return requirements == version if requirements.to_s == "-1" || version.to_s == "-1" Array(requirements).all? do |requirement| Gem::Requirement.create(requirement).satisfied_by?(Gem::Version.create(version)) end end end end PK ]ؤ-""-gems/bundler-2.2.24/lib/bundler/source_map.rbnu[# frozen_string_literal: true module Bundler class SourceMap attr_reader :sources, :dependencies def initialize(sources, dependencies) @sources = sources @dependencies = dependencies end def pinned_spec_names(skip = nil) direct_requirements.reject {|_, source| source == skip }.keys end def all_requirements requirements = direct_requirements.dup unmet_deps = sources.non_default_explicit_sources.map do |source| (source.spec_names - pinned_spec_names).each do |indirect_dependency_name| previous_source = requirements[indirect_dependency_name] if previous_source.nil? requirements[indirect_dependency_name] = source else no_ambiguous_sources = Bundler.feature_flag.bundler_3_mode? msg = ["The gem '#{indirect_dependency_name}' was found in multiple relevant sources."] msg.concat [previous_source, source].map {|s| " * #{s}" }.sort msg << "You #{no_ambiguous_sources ? :must : :should} add this gem to the source block for the source you wish it to be installed from." msg = msg.join("\n") raise SecurityError, msg if no_ambiguous_sources Bundler.ui.warn "Warning: #{msg}" end end source.unmet_deps end sources.default_source.add_dependency_names(unmet_deps.flatten - requirements.keys) requirements end def direct_requirements @direct_requirements ||= begin requirements = {} default = sources.default_source dependencies.each do |dep| dep_source = dep.source || default dep_source.add_dependency_names(dep.name) requirements[dep.name] = dep_source end requirements end end end end PK ]0/gems/bundler-2.2.24/lib/bundler/rubygems_ext.rbnu[# frozen_string_literal: true require "pathname" require "rubygems/specification" # Possible use in Gem::Specification#source below and require # shouldn't be deferred. require "rubygems/source" require_relative "match_platform" module Gem class Specification attr_accessor :remote, :location, :relative_loaded_from remove_method :source attr_writer :source def source (defined?(@source) && @source) || Gem::Source::Installed.new end alias_method :rg_full_gem_path, :full_gem_path alias_method :rg_loaded_from, :loaded_from def full_gem_path # this cannot check source.is_a?(Bundler::Plugin::API::Source) # because that _could_ trip the autoload, and if there are unresolved # gems at that time, this method could be called inside another require, # thus raising with that constant being undefined. Better to check a method if source.respond_to?(:path) || (source.respond_to?(:bundler_plugin_api_source?) && source.bundler_plugin_api_source?) Pathname.new(loaded_from).dirname.expand_path(source.root).to_s.tap{|x| x.untaint if RUBY_VERSION < "2.7" } else rg_full_gem_path end end def loaded_from if relative_loaded_from source.path.join(relative_loaded_from).to_s else rg_loaded_from end end def load_paths full_require_paths end alias_method :rg_extension_dir, :extension_dir def extension_dir @bundler_extension_dir ||= if source.respond_to?(:extension_dir_name) unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-") File.expand_path(File.join(extensions_dir, unique_extension_dir)) else rg_extension_dir end end remove_method :gem_dir if instance_methods(false).include?(:gem_dir) def gem_dir full_gem_path end def groups @groups ||= [] end def git_version return unless loaded_from && source.is_a?(Bundler::Source::Git) " #{source.revision[0..6]}" end def to_gemfile(path = nil) gemfile = String.new("source 'https://rubygems.org'\n") gemfile << dependencies_to_gemfile(nondevelopment_dependencies) unless development_dependencies.empty? gemfile << "\n" gemfile << dependencies_to_gemfile(development_dependencies, :development) end gemfile end def nondevelopment_dependencies dependencies - development_dependencies end private def dependencies_to_gemfile(dependencies, group = nil) gemfile = String.new if dependencies.any? gemfile << "group :#{group} do\n" if group dependencies.each do |dependency| gemfile << " " if group gemfile << %(gem "#{dependency.name}") req = dependency.requirements_list.first gemfile << %(, "#{req}") if req gemfile << "\n" end gemfile << "end\n" if group end gemfile end end class Dependency attr_accessor :source, :groups alias_method :eql?, :== def encode_with(coder) to_yaml_properties.each do |ivar| coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar) end end def to_yaml_properties instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) } end def to_lock out = String.new(" #{name}") unless requirement.none? reqs = requirement.requirements.map {|o, v| "#{o} #{v}" }.sort.reverse out << " (#{reqs.join(", ")})" end out end end # comparison is done order independently since rubygems 3.2.0.rc.2 unless Gem::Requirement.new("> 1", "< 2") == Gem::Requirement.new("< 2", "> 1") class Requirement module OrderIndependentComparison def ==(other) return unless Gem::Requirement === other if _requirements_sorted? && other._requirements_sorted? super else _with_sorted_requirements == other._with_sorted_requirements end end protected def _requirements_sorted? return @_are_requirements_sorted if defined?(@_are_requirements_sorted) strings = as_list @_are_requirements_sorted = strings == strings.sort end def _with_sorted_requirements @_with_sorted_requirements ||= _requirements_sorted? ? self : self.class.new(as_list.sort) end end prepend OrderIndependentComparison end end if Gem::Requirement.new("~> 2.0").hash == Gem::Requirement.new("~> 2.0.0").hash class Requirement module CorrectHashForLambdaOperator def hash if requirements.any? {|r| r.first == "~>" } requirements.map {|r| r.first == "~>" ? [r[0], r[1].to_s] : r }.sort.hash else super end end end prepend CorrectHashForLambdaOperator end end require "rubygems/platform" class Platform JAVA = Gem::Platform.new("java") unless defined?(JAVA) MSWIN = Gem::Platform.new("mswin32") unless defined?(MSWIN) MSWIN64 = Gem::Platform.new("mswin64") unless defined?(MSWIN64) MINGW = Gem::Platform.new("x86-mingw32") unless defined?(MINGW) X64_MINGW = Gem::Platform.new("x64-mingw32") unless defined?(X64_MINGW) end Platform.singleton_class.module_eval do unless Platform.singleton_methods.include?(:match_spec?) def match_spec?(spec) match_gem?(spec.platform, spec.name) end def match_gem?(platform, gem_name) match_platforms?(platform, Gem.platforms) end private def match_platforms?(platform, platforms) platforms.any? do |local_platform| platform.nil? || local_platform == platform || (local_platform != Gem::Platform::RUBY && local_platform =~ platform) end end end end require "rubygems/util" Util.singleton_class.module_eval do if Util.singleton_methods.include?(:glob_files_in_dir) # since 3.0.0.beta.2 remove_method :glob_files_in_dir end def glob_files_in_dir(glob, base_path) if RUBY_VERSION >= "2.5" Dir.glob(glob, :base => base_path).map! {|f| File.expand_path(f, base_path) } else Dir.glob(File.join(base_path.to_s.gsub(/[\[\]]/, '\\\\\\&'), glob)).map! {|f| File.expand_path(f) } end end end end module Gem class Specification include ::Bundler::MatchPlatform end end PK ]i *  &gems/bundler-2.2.24/lib/bundler/env.rbnu[# frozen_string_literal: true require_relative "rubygems_integration" require_relative "source/git/git_proxy" module Bundler class Env def self.write(io) io.write report end def self.report(options = {}) print_gemfile = options.delete(:print_gemfile) { true } print_gemspecs = options.delete(:print_gemspecs) { true } out = String.new append_formatted_table("Environment", environment, out) append_formatted_table("Bundler Build Metadata", BuildMetadata.to_h, out) unless Bundler.settings.all.empty? out << "\n## Bundler settings\n\n```\n" Bundler.settings.all.each do |setting| out << setting << "\n" Bundler.settings.pretty_values_for(setting).each do |line| out << " " << line << "\n" end end out << "```\n" end return out unless SharedHelpers.in_bundle? if print_gemfile gemfiles = [Bundler.default_gemfile] begin gemfiles = Bundler.definition.gemfiles rescue GemfileNotFound nil end out << "\n## Gemfile\n" gemfiles.each do |gemfile| out << "\n### #{Pathname.new(gemfile).relative_path_from(SharedHelpers.pwd)}\n\n" out << "```ruby\n" << read_file(gemfile).chomp << "\n```\n" end out << "\n### #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}\n\n" out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n" end if print_gemspecs dsl = Dsl.new.tap {|d| d.eval_gemfile(Bundler.default_gemfile) } out << "\n## Gemspecs\n" unless dsl.gemspecs.empty? dsl.gemspecs.each do |gs| out << "\n### #{File.basename(gs.loaded_from)}" out << "\n\n```ruby\n" << read_file(gs.loaded_from).chomp << "\n```\n" end end out end def self.read_file(filename) Bundler.read_file(filename.to_s).strip rescue Errno::ENOENT "" rescue RuntimeError => e "#{e.class}: #{e.message}" end def self.ruby_version str = String.new(RUBY_VERSION) str << "p#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL str << " (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{RUBY_PLATFORM}]" end def self.git_version Bundler::Source::Git::GitProxy.new(nil, nil, nil).full_version rescue Bundler::Source::Git::GitNotInstalledError "not installed" end def self.version_of(script) return "not installed" unless Bundler.which(script) `#{script} --version`.chomp end def self.chruby_version return "not installed" unless Bundler.which("chruby-exec") `chruby-exec -- chruby --version`. sub(/.*^chruby: (#{Gem::Version::VERSION_PATTERN}).*/m, '\1') end def self.environment out = [] out << ["Bundler", Bundler::VERSION] out << [" Platforms", Gem.platforms.join(", ")] out << ["Ruby", ruby_version] out << [" Full Path", Gem.ruby] out << [" Config Dir", Pathname.new(Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE).dirname] out << ["RubyGems", Gem::VERSION] out << [" Gem Home", Gem.dir] out << [" Gem Path", Gem.path.join(File::PATH_SEPARATOR)] out << [" User Home", Gem.user_home] out << [" User Path", Gem.user_dir] out << [" Bin Dir", Gem.bindir] if defined?(OpenSSL::SSL) out << ["OpenSSL"] out << [" Compiled", OpenSSL::OPENSSL_VERSION] if defined?(OpenSSL::OPENSSL_VERSION) out << [" Loaded", OpenSSL::OPENSSL_LIBRARY_VERSION] if defined?(OpenSSL::OPENSSL_LIBRARY_VERSION) out << [" Cert File", OpenSSL::X509::DEFAULT_CERT_FILE] if defined?(OpenSSL::X509::DEFAULT_CERT_FILE) out << [" Cert Dir", OpenSSL::X509::DEFAULT_CERT_DIR] if defined?(OpenSSL::X509::DEFAULT_CERT_DIR) end out << ["Tools"] out << [" Git", git_version] out << [" RVM", ENV.fetch("rvm_version") { version_of("rvm") }] out << [" rbenv", version_of("rbenv")] out << [" chruby", chruby_version] %w[rubygems-bundler open_gem].each do |name| specs = Bundler.rubygems.find_name(name) out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty? end if (exe = caller.last.split(":").first) && exe =~ %r{(exe|bin)/bundler?\z} shebang = File.read(exe).lines.first shebang.sub!(/^#!\s*/, "") unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby") out << ["Gem.ruby", Gem.ruby] out << ["bundle #!", shebang] end end out end def self.append_formatted_table(title, pairs, out) return if pairs.empty? out << "\n" unless out.empty? out << "## #{title}\n\n```\n" ljust = pairs.map {|k, _v| k.to_s.length }.max pairs.each do |k, v| out << "#{k.to_s.ljust(ljust)} #{v}\n" end out << "```\n" end private_class_method :read_file, :ruby_version, :git_version, :append_formatted_table, :version_of, :chruby_version end end PK ]Piy@ @ 6gems/bundler-2.2.24/lib/bundler/resolver/spec_group.rbnu[# frozen_string_literal: true module Bundler class Resolver class SpecGroup attr_accessor :name, :version, :source attr_accessor :activated_platforms def self.create_for(specs, all_platforms, specific_platform) specific_platform_specs = specs[specific_platform] return unless specific_platform_specs.any? platforms = all_platforms.select {|p| specs[p].any? } new(specific_platform_specs.first, specs, platforms) end def initialize(exemplary_spec, specs, relevant_platforms) @exemplary_spec = exemplary_spec @name = exemplary_spec.name @version = exemplary_spec.version @source = exemplary_spec.source @activated_platforms = relevant_platforms @dependencies = Hash.new do |dependencies, platforms| dependencies[platforms] = dependencies_for(platforms) end @specs = specs end def to_specs activated_platforms.map do |p| specs = @specs[p] next unless specs.any? specs.map do |s| lazy_spec = LazySpecification.new(name, version, s.platform, source) lazy_spec.dependencies.replace s.dependencies lazy_spec end end.flatten.compact.uniq end def to_s activated_platforms_string = sorted_activated_platforms.join(", ") "#{name} (#{version}) (#{activated_platforms_string})" end def dependencies_for_activated_platforms @dependencies[activated_platforms] end def ==(other) return unless other.is_a?(SpecGroup) name == other.name && version == other.version && sorted_activated_platforms == other.sorted_activated_platforms && source == other.source end def eql?(other) return unless other.is_a?(SpecGroup) name.eql?(other.name) && version.eql?(other.version) && sorted_activated_platforms.eql?(other.sorted_activated_platforms) && source.eql?(other.source) end def hash name.hash ^ version.hash ^ sorted_activated_platforms.hash ^ source.hash end protected def sorted_activated_platforms activated_platforms.sort_by(&:to_s) end private def dependencies_for(platforms) platforms.map do |platform| __dependencies(platform) + metadata_dependencies(platform) end.flatten end def __dependencies(platform) dependencies = [] @specs[platform].first.dependencies.each do |dep| next if dep.type == :development dependencies << DepProxy.get_proxy(dep, platform) end dependencies end def metadata_dependencies(platform) spec = @specs[platform].first return [] unless spec.is_a?(Gem::Specification) dependencies = [] if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none? dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform) end if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none? dependencies << DepProxy.get_proxy(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform) end dependencies end end end end PK ]B$hHH)gems/bundler-2.2.24/lib/bundler/mirror.rbnu[# frozen_string_literal: true require "socket" module Bundler class Settings # Class used to build the mirror set and then find a mirror for a given URI # # @param prober [Prober object, nil] by default a TCPSocketProbe, this object # will be used to probe the mirror address to validate that the mirror replies. class Mirrors def initialize(prober = nil) @all = Mirror.new @prober = prober || TCPSocketProbe.new @mirrors = {} end # Returns a mirror for the given uri. # # Depending on the uri having a valid mirror or not, it may be a # mirror that points to the provided uri def for(uri) if @all.validate!(@prober).valid? @all else fetch_valid_mirror_for(Settings.normalize_uri(uri)) end end def each @mirrors.each do |k, v| yield k, v.uri.to_s end end def parse(key, value) config = MirrorConfig.new(key, value) mirror = if config.all? @all else @mirrors[config.uri] ||= Mirror.new end config.update_mirror(mirror) end private def fetch_valid_mirror_for(uri) downcased = uri.to_s.downcase mirror = @mirrors[downcased] || @mirrors[Bundler::URI(downcased).host] || Mirror.new(uri) mirror.validate!(@prober) mirror = Mirror.new(uri) unless mirror.valid? mirror end end # A mirror # # Contains both the uri that should be used as a mirror and the # fallback timeout which will be used for probing if the mirror # replies on time or not. class Mirror DEFAULT_FALLBACK_TIMEOUT = 0.1 attr_reader :uri, :fallback_timeout def initialize(uri = nil, fallback_timeout = 0) self.uri = uri self.fallback_timeout = fallback_timeout @valid = nil end def uri=(uri) @uri = if uri.nil? nil else Bundler::URI(uri.to_s) end @valid = nil end def fallback_timeout=(timeout) case timeout when true, "true" @fallback_timeout = DEFAULT_FALLBACK_TIMEOUT when false, "false" @fallback_timeout = 0 else @fallback_timeout = timeout.to_i end @valid = nil end def ==(other) !other.nil? && uri == other.uri && fallback_timeout == other.fallback_timeout end def valid? return false if @uri.nil? return @valid unless @valid.nil? false end def validate!(probe = nil) @valid = false if uri.nil? if @valid.nil? @valid = fallback_timeout == 0 || (probe || TCPSocketProbe.new).replies?(self) end self end end # Class used to parse one configuration line # # Gets the configuration line and the value. # This object provides a `update_mirror` method # used to setup the given mirror value. class MirrorConfig attr_accessor :uri, :value def initialize(config_line, value) uri, fallback = config_line.match(%r{\Amirror\.(all|.+?)(\.fallback_timeout)?\/?\z}).captures @fallback = !fallback.nil? @all = false if uri == "all" @all = true else @uri = Bundler::URI(uri).absolute? ? Settings.normalize_uri(uri) : uri end @value = value end def all? @all end def update_mirror(mirror) if @fallback mirror.fallback_timeout = @value else mirror.uri = Settings.normalize_uri(@value) end end end # Class used for probing TCP availability for a given mirror. class TCPSocketProbe def replies?(mirror) MirrorSockets.new(mirror).any? do |socket, address, timeout| begin socket.connect_nonblock(address) rescue Errno::EINPROGRESS wait_for_writtable_socket(socket, address, timeout) rescue RuntimeError # Connection failed somehow, again false end end end private def wait_for_writtable_socket(socket, address, timeout) if IO.select(nil, [socket], nil, timeout) probe_writtable_socket(socket, address) else # TCP Handshake timed out, or there is something dropping packets false end end def probe_writtable_socket(socket, address) socket.connect_nonblock(address) rescue Errno::EISCONN true rescue StandardError # Connection failed false end end end # Class used to build the list of sockets that correspond to # a given mirror. # # One mirror may correspond to many different addresses, both # because of it having many dns entries or because # the network interface is both ipv4 and ipv5 class MirrorSockets def initialize(mirror) @timeout = mirror.fallback_timeout @addresses = Socket.getaddrinfo(mirror.uri.host, mirror.uri.port).map do |address| SocketAddress.new(address[0], address[3], address[1]) end end def any? @addresses.any? do |address| socket = Socket.new(Socket.const_get(address.type), Socket::SOCK_STREAM, 0) socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) value = yield socket, address.to_socket_address, @timeout socket.close unless socket.closed? value end end end # Socket address builder. # # Given a socket type, a host and a port, # provides a method to build sockaddr string class SocketAddress attr_reader :type, :host, :port def initialize(type, host, port) @type = type @host = host @port = port end def to_socket_address Socket.pack_sockaddr_in(@port, @host) end end end PK ]"x-gems/bundler-2.2.24/lib/bundler/plugin/dsl.rbnu[# frozen_string_literal: true module Bundler module Plugin # Dsl to parse the Gemfile looking for plugins to install class DSL < Bundler::Dsl class PluginGemfileError < PluginError; end alias_method :_gem, :gem # To use for plugin installation as gem # So that we don't have to override all there methods to dummy ones # explicitly. # They will be handled by method_missing [:gemspec, :gem, :install_if, :platforms, :env].each {|m| undef_method m } # This lists the plugins that was added automatically and not specified by # the user. # # When we encounter :type attribute with a source block, we add a plugin # by name bundler-source- to list of plugins to be installed. # # These plugins are optional and are not installed when there is conflict # with any other plugin. attr_reader :inferred_plugins def initialize super @sources = Plugin::SourceList.new @inferred_plugins = [] # The source plugins inferred from :type end def plugin(name, *args) _gem(name, *args) end def method_missing(name, *args) raise PluginGemfileError, "Undefined local variable or method `#{name}' for Gemfile" unless Bundler::Dsl.method_defined? name end def source(source, *args, &blk) options = args.last.is_a?(Hash) ? args.pop.dup : {} options = normalize_hash(options) return super unless options.key?("type") plugin_name = "bundler-source-#{options["type"]}" return if @dependencies.any? {|d| d.name == plugin_name } plugin(plugin_name) @inferred_plugins << plugin_name end end end end PK ]ӃnDD0gems/bundler-2.2.24/lib/bundler/plugin/events.rbnu[# frozen_string_literal: true module Bundler module Plugin module Events def self.define(const, event) const = const.to_sym.freeze if const_defined?(const) && const_get(const) != event raise ArgumentError, "Attempting to reassign #{const} to a different value" end const_set(const, event) unless const_defined?(const) @events ||= {} @events[event] = const end private_class_method :define def self.reset @events.each_value do |const| remove_const(const) end @events = nil end private_class_method :reset # Check if an event has been defined # @param event [String] An event to check # @return [Boolean] A boolean indicating if the event has been defined def self.defined_event?(event) @events ||= {} @events.key?(event) end # @!parse # A hook called before each individual gem is installed # Includes a Bundler::ParallelInstaller::SpecInstallation. # No state, error, post_install_message will be present as nothing has installed yet # GEM_BEFORE_INSTALL = "before-install" define :GEM_BEFORE_INSTALL, "before-install" # @!parse # A hook called after each individual gem is installed # Includes a Bundler::ParallelInstaller::SpecInstallation. # - If state is failed, an error will be present. # - If state is success, a post_install_message may be present. # GEM_AFTER_INSTALL = "after-install" define :GEM_AFTER_INSTALL, "after-install" # @!parse # A hook called before any gems install # Includes an Array of Bundler::Dependency objects # GEM_BEFORE_INSTALL_ALL = "before-install-all" define :GEM_BEFORE_INSTALL_ALL, "before-install-all" # @!parse # A hook called after any gems install # Includes an Array of Bundler::Dependency objects # GEM_AFTER_INSTALL_ALL = "after-install-all" define :GEM_AFTER_INSTALL_ALL, "after-install-all" end end end PK ]6P P -gems/bundler-2.2.24/lib/bundler/plugin/api.rbnu[# frozen_string_literal: true module Bundler # This is the interfacing class represents the API that we intend to provide # the plugins to use. # # For plugins to be independent of the Bundler internals they shall limit their # interactions to methods of this class only. This will save them from breaking # when some internal change. # # Currently we are delegating the methods defined in Bundler class to # itself. So, this class acts as a buffer. # # If there is some change in the Bundler class that is incompatible to its # previous behavior or if otherwise desired, we can reimplement(or implement) # the method to preserve compatibility. # # To use this, either the class can inherit this class or use it directly. # For example of both types of use, refer the file `spec/plugins/command.rb` # # To use it without inheriting, you will have to create an object of this # to use the functions (except for declaration functions like command, source, # and hooks). module Plugin class API autoload :Source, File.expand_path("api/source", __dir__) # The plugins should declare that they handle a command through this helper. # # @param [String] command being handled by them # @param [Class] (optional) class that handles the command. If not # provided, the `self` class will be used. def self.command(command, cls = self) Plugin.add_command command, cls end # The plugins should declare that they provide a installation source # through this helper. # # @param [String] the source type they provide # @param [Class] (optional) class that handles the source. If not # provided, the `self` class will be used. def self.source(source, cls = self) cls.send :include, Bundler::Plugin::API::Source Plugin.add_source source, cls end def self.hook(event, &block) Plugin.add_hook(event, &block) end # The cache dir to be used by the plugins for storage # # @return [Pathname] path of the cache dir def cache_dir Plugin.cache.join("plugins") end # A tmp dir to be used by plugins # Accepts names that get concatenated as suffix # # @return [Pathname] object for the new directory created def tmp(*names) Bundler.tmp(["plugin", *names].join("-")) end def method_missing(name, *args, &blk) return Bundler.send(name, *args, &blk) if Bundler.respond_to?(name) return SharedHelpers.send(name, *args, &blk) if SharedHelpers.respond_to?(name) super end def respond_to_missing?(name, include_private = false) SharedHelpers.respond_to?(name, include_private) || Bundler.respond_to?(name, include_private) || super end end end end PK ] g..4gems/bundler-2.2.24/lib/bundler/plugin/api/source.rbnu[# frozen_string_literal: true module Bundler module Plugin class API # This class provides the base to build source plugins # All the method here are required to build a source plugin (except # `uri_hash`, `gem_install_dir`; they are helpers). # # Defaults for methods, where ever possible are provided which is # expected to work. But, all source plugins have to override # `fetch_gemspec_files` and `install`. Defaults are also not provided for # `remote!`, `cache!` and `unlock!`. # # The defaults shall work for most situations but nevertheless they can # be (preferably should be) overridden as per the plugins' needs safely # (as long as they behave as expected). # On overriding `initialize` you should call super first. # # If required plugin should override `hash`, `==` and `eql?` methods to be # able to match objects representing same sources, but may be created in # different situation (like form gemfile and lockfile). The default ones # checks only for class and uri, but elaborate source plugins may need # more comparisons (e.g. git checking on branch or tag). # # @!attribute [r] uri # @return [String] the remote specified with `source` block in Gemfile # # @!attribute [r] options # @return [String] options passed during initialization (either from # lockfile or Gemfile) # # @!attribute [r] name # @return [String] name that can be used to uniquely identify a source # # @!attribute [rw] dependency_names # @return [Array] Names of dependencies that the source should # try to resolve. It is not necessary to use this list internally. This # is present to be compatible with `Definition` and is used by # rubygems source. module Source attr_reader :uri, :options, :name attr_accessor :dependency_names def initialize(opts) @options = opts @dependency_names = [] @uri = opts["uri"] @type = opts["type"] @name = opts["name"] || "#{@type} at #{@uri}" end # This is used by the default `spec` method to constructs the # Specification objects for the gems and versions that can be installed # by this source plugin. # # Note: If the spec method is overridden, this function is not necessary # # @return [Array] paths of the gemspec files for gems that can # be installed def fetch_gemspec_files [] end # Options to be saved in the lockfile so that the source plugin is able # to check out same version of gem later. # # There options are passed when the source plugin is created from the # lock file. # # @return [Hash] def options_to_lock {} end # Install the gem specified by the spec at appropriate path. # `install_path` provides a sufficient default, if the source can only # satisfy one gem, but is not binding. # # @return [String] post installation message (if any) def install(spec, opts) raise MalformattedPlugin, "Source plugins need to override the install method." end # It builds extensions, generates bins and installs them for the spec # provided. # # It depends on `spec.loaded_from` to get full_gem_path. The source # plugins should set that. # # It should be called in `install` after the plugin is done placing the # gem at correct install location. # # It also runs Gem hooks `pre_install`, `post_build` and `post_install` # # Note: Do not override if you don't know what you are doing. def post_install(spec, disable_exts = false) opts = { :env_shebang => false, :disable_extensions => disable_exts } installer = Bundler::Source::Path::Installer.new(spec, opts) installer.post_install end # A default installation path to install a single gem. If the source # servers multiple gems, it's not of much use and the source should one # of its own. def install_path @install_path ||= begin base_name = File.basename(Bundler::URI.parse(uri).normalize.path) gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") end end # Parses the gemspec files to find the specs for the gems that can be # satisfied by the source. # # Few important points to keep in mind: # - If the gems are not installed then it shall return specs for all # the gems it can satisfy # - If gem is installed (that is to be detected by the plugin itself) # then it shall return at least the specs that are installed. # - The `loaded_from` for each of the specs shall be correct (it is # used to find the load path) # # @return [Bundler::Index] index containing the specs def specs files = fetch_gemspec_files Bundler::Index.build do |index| files.each do |file| next unless spec = Bundler.load_gemspec(file) Bundler.rubygems.set_installed_by_version(spec) spec.source = self Bundler.rubygems.validate(spec) index << spec end end end # Set internal representation to fetch the gems/specs locally. # # When this is called, the source should try to fetch the specs and # install from the local system. def local! end # Set internal representation to fetch the gems/specs from remote. # # When this is called, the source should try to fetch the specs and # install from remote path. def remote! end # Set internal representation to fetch the gems/specs from app cache. # # When this is called, the source should try to fetch the specs and # install from the path provided by `app_cache_path`. def cached! end # This is called to update the spec and installation. # # If the source plugin is loaded from lockfile or otherwise, it shall # refresh the cache/specs (e.g. git sources can make a fresh clone). def unlock! end # Name of directory where plugin the is expected to cache the gems when # #cache is called. # # Also this name is matched against the directories in cache for pruning # # This is used by `app_cache_path` def app_cache_dirname base_name = File.basename(Bundler::URI.parse(uri).normalize.path) "#{base_name}-#{uri_hash}" end # This method is called while caching to save copy of the gems that the # source can resolve to path provided by `app_cache_app`so that they can # be reinstalled from the cache without querying the remote (i.e. an # alternative to remote) # # This is stored with the app and source plugins should try to provide # specs and install only from this cache when `cached!` is called. # # This cache is different from the internal caching that can be done # at sub paths of `cache_path` (from API). This can be though as caching # by bundler. def cache(spec, custom_path = nil) new_cache_path = app_cache_path(custom_path) FileUtils.rm_rf(new_cache_path) FileUtils.cp_r(install_path, new_cache_path) FileUtils.touch(app_cache_path.join(".bundlecache")) end # This shall check if two source object represent the same source. # # The comparison shall take place only on the attribute that can be # inferred from the options passed from Gemfile and not on attributes # that are used to pin down the gem to specific version (e.g. Git # sources should compare on branch and tag but not on commit hash) # # The sources objects are constructed from Gemfile as well as from # lockfile. To converge the sources, it is necessary that they match. # # The same applies for `eql?` and `hash` def ==(other) other.is_a?(self.class) && uri == other.uri end # When overriding `eql?` please preserve the behaviour as mentioned in # docstring for `==` method. alias_method :eql?, :== # When overriding `hash` please preserve the behaviour as mentioned in # docstring for `==` method, i.e. two methods equal by above comparison # should have same hash. def hash [self.class, uri].hash end # A helper method, not necessary if not used internally. def installed? File.directory?(install_path) end # The full path where the plugin should cache the gem so that it can be # installed latter. # # Note: Do not override if you don't know what you are doing. def app_cache_path(custom_path = nil) @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) end # Used by definition. # # Note: Do not override if you don't know what you are doing. def unmet_deps specs.unmet_dependency_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def spec_names specs.spec_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def add_dependency_names(names) @dependencies |= Array(names) end # Note: Do not override if you don't know what you are doing. def can_lock?(spec) spec.source == self end # Generates the content to be entered into the lockfile. # Saves type and remote and also calls to `options_to_lock`. # # Plugin should use `options_to_lock` to save information in lockfile # and not override this. # # Note: Do not override if you don't know what you are doing. def to_lock out = String.new("#{LockfileParser::PLUGIN}\n") out << " remote: #{@uri}\n" out << " type: #{@type}\n" options_to_lock.each do |opt, value| out << " #{opt}: #{value}\n" end out << " specs:\n" end def to_s "plugin source for #{@type} with uri #{@uri}" end # Note: Do not override if you don't know what you are doing. def include?(other) other == self end def uri_hash SharedHelpers.digest(:SHA1).hexdigest(uri) end # Note: Do not override if you don't know what you are doing. def gem_install_dir Bundler.install_path end # It is used to obtain the full_gem_path. # # spec's loaded_from path is expanded against this to get full_gem_path # # Note: Do not override if you don't know what you are doing. def root Bundler.root end # @private # Returns true def bundler_plugin_api_source? true end # @private # This API on source might not be stable, and for now we expect plugins # to download all specs in `#specs`, so we implement the method for # compatibility purposes and leave it undocumented (and don't support) # overriding it) def double_check_for(*); end end end end end PK ]A<gems/bundler-2.2.24/lib/bundler/plugin/installer/rubygems.rbnu[# frozen_string_literal: true module Bundler module Plugin class Installer class Rubygems < Bundler::Source::Rubygems def version_message(spec) "#{spec.name} #{spec.version}" end private def requires_sudo? false # Will change on implementation of project level plugins end def rubygems_dir Plugin.root end def cache_path Plugin.cache end end end end end PK ]ߛ"Maa7gems/bundler-2.2.24/lib/bundler/plugin/installer/git.rbnu[# frozen_string_literal: true module Bundler module Plugin class Installer class Git < Bundler::Source::Git def cache_path @cache_path ||= begin git_scope = "#{base_name}-#{uri_hash}" Plugin.cache.join("bundler", "git", git_scope) end end def install_path @install_path ||= begin git_scope = "#{base_name}-#{shortref_for_path(revision)}" Plugin.root.join("bundler", "gems", git_scope) end end def version_message(spec) "#{spec.name} #{spec.version}" end def root Plugin.root end def generate_bin(spec, disable_extensions = false) # Need to find a way without code duplication # For now, we can ignore this end end end end end PK ]{׳ 3gems/bundler-2.2.24/lib/bundler/plugin/installer.rbnu[# frozen_string_literal: true module Bundler # Handles the installation of plugin in appropriate directories. # # This class is supposed to be wrapper over the existing gem installation infra # but currently it itself handles everything as the Source's subclasses (e.g. Source::RubyGems) # are heavily dependent on the Gemfile. module Plugin class Installer autoload :Rubygems, File.expand_path("installer/rubygems", __dir__) autoload :Git, File.expand_path("installer/git", __dir__) def install(names, options) check_sources_consistency!(options) version = options[:version] || [">= 0"] if options[:git] install_git(names, version, options) elsif options[:local_git] install_local_git(names, version, options) else sources = options[:source] || Bundler.rubygems.sources install_rubygems(names, version, sources) end end # Installs the plugin from Definition object created by limited parsing of # Gemfile searching for plugins to be installed # # @param [Definition] definition object # @return [Hash] map of names to their specs they are installed with def install_definition(definition) def definition.lock(*); end definition.resolve_remotely! specs = definition.specs install_from_specs specs end private def check_sources_consistency!(options) if options.key?(:git) && options.key?(:local_git) raise InvalidOption, "Remote and local plugin git sources can't be both specified" end end def install_git(names, version, options) uri = options.delete(:git) options["uri"] = uri install_all_sources(names, version, options, options[:source]) end def install_local_git(names, version, options) uri = options.delete(:local_git) options["uri"] = uri install_all_sources(names, version, options, options[:source]) end # Installs the plugin from rubygems source and returns the path where the # plugin was installed # # @param [String] name of the plugin gem to search in the source # @param [Array] version of the gem to install # @param [String, Array] source(s) to resolve the gem # # @return [Hash] map of names to the specs of plugins installed def install_rubygems(names, version, sources) install_all_sources(names, version, nil, sources) end def install_all_sources(names, version, git_source_options, rubygems_source) source_list = SourceList.new source_list.add_git_source(git_source_options) if git_source_options Array(rubygems_source).each {|remote| source_list.add_global_rubygems_remote(remote) } if rubygems_source deps = names.map {|name| Dependency.new name, version } definition = Definition.new(nil, deps, source_list, true) install_definition(definition) end # Installs the plugins and deps from the provided specs and returns map of # gems to their paths # # @param specs to install # # @return [Hash] map of names to the specs def install_from_specs(specs) paths = {} specs.each do |spec| spec.source.install spec paths[spec.name] = spec end paths end end end end PK ]./gems/bundler-2.2.24/lib/bundler/plugin/index.rbnu[# frozen_string_literal: true module Bundler # Manages which plugins are installed and their sources. This also is supposed to map # which plugin does what (currently the features are not implemented so this class is # now a stub class). module Plugin class Index class CommandConflict < PluginError def initialize(plugin, commands) msg = "Command(s) `#{commands.join("`, `")}` declared by #{plugin} are already registered." super msg end end class SourceConflict < PluginError def initialize(plugin, sources) msg = "Source(s) `#{sources.join("`, `")}` declared by #{plugin} are already registered." super msg end end attr_reader :commands def initialize @plugin_paths = {} @commands = {} @sources = {} @hooks = {} @load_paths = {} begin load_index(global_index_file, true) rescue GenericSystemCallError # no need to fail when on a read-only FS, for example nil end load_index(local_index_file) if SharedHelpers.in_bundle? end # This function is to be called when a new plugin is installed. This # function shall add the functions of the plugin to existing maps and also # the name to source location. # # @param [String] name of the plugin to be registered # @param [String] path where the plugin is installed # @param [Array] load_paths for the plugin # @param [Array] commands that are handled by the plugin # @param [Array] sources that are handled by the plugin def register_plugin(name, path, load_paths, commands, sources, hooks) old_commands = @commands.dup common = commands & @commands.keys raise CommandConflict.new(name, common) unless common.empty? commands.each {|c| @commands[c] = name } common = sources & @sources.keys raise SourceConflict.new(name, common) unless common.empty? sources.each {|k| @sources[k] = name } hooks.each do |event| event_hooks = (@hooks[event] ||= []) << name event_hooks.uniq! end @plugin_paths[name] = path @load_paths[name] = load_paths save_index rescue StandardError @commands = old_commands raise end def unregister_plugin(name) @commands.delete_if {|_, v| v == name } @sources.delete_if {|_, v| v == name } @hooks.each do |hook, names| names.delete(name) @hooks.delete(hook) if names.empty? end @plugin_paths.delete(name) @load_paths.delete(name) save_index end # Path of default index file def index_file Plugin.root.join("index") end # Path where the global index file is stored def global_index_file Plugin.global_root.join("index") end # Path where the local index file is stored def local_index_file Plugin.local_root.join("index") end def plugin_path(name) Pathname.new @plugin_paths[name] end def load_paths(name) @load_paths[name] end # Fetch the name of plugin handling the command def command_plugin(command) @commands[command] end def installed?(name) @plugin_paths[name] end def installed_plugins @plugin_paths.keys end def plugin_commands(plugin) @commands.find_all {|_, n| n == plugin }.map(&:first) end def source?(source) @sources.key? source end def source_plugin(name) @sources[name] end # Returns the list of plugin names handling the passed event def hook_plugins(event) @hooks[event] || [] end private # Reads the index file from the directory and initializes the instance # variables. # # It skips the sources if the second param is true # @param [Pathname] index file path # @param [Boolean] is the index file global index def load_index(index_file, global = false) SharedHelpers.filesystem_access(index_file, :read) do |index_f| valid_file = index_f && index_f.exist? && !index_f.size.zero? break unless valid_file data = index_f.read require_relative "../yaml_serializer" index = YAMLSerializer.load(data) @commands.merge!(index["commands"]) @hooks.merge!(index["hooks"]) @load_paths.merge!(index["load_paths"]) @plugin_paths.merge!(index["plugin_paths"]) @sources.merge!(index["sources"]) unless global end end # Should be called when any of the instance variables change. Stores the # instance variables in YAML format. (The instance variables are supposed # to be only String key value pairs) def save_index index = { "commands" => @commands, "hooks" => @hooks, "load_paths" => @load_paths, "plugin_paths" => @plugin_paths, "sources" => @sources, } require_relative "../yaml_serializer" SharedHelpers.filesystem_access(index_file) do |index_f| FileUtils.mkdir_p(index_f.dirname) File.open(index_f, "w") {|f| f.puts YAMLSerializer.dump(index) } end end end end end PK ]ΦAA5gems/bundler-2.2.24/lib/bundler/plugin/source_list.rbnu[# frozen_string_literal: true module Bundler # SourceList object to be used while parsing the Gemfile, setting the # approptiate options to be used with Source classes for plugin installation module Plugin class SourceList < Bundler::SourceList def add_git_source(options = {}) add_source_to_list Plugin::Installer::Git.new(options), git_sources end def add_rubygems_source(options = {}) add_source_to_list Plugin::Installer::Rubygems.new(options), @rubygems_sources end def all_sources path_sources + git_sources + rubygems_sources + [metadata_source] end def default_source git_sources.first || global_rubygems_source end private def rubygems_aggregate_class Plugin::Installer::Rubygems end end end end PK ]wz,,*gems/bundler-2.2.24/lib/bundler/fetcher.rbnu[# frozen_string_literal: true require_relative "vendored_persistent" require "cgi" require "securerandom" require "zlib" require "rubygems/request" module Bundler # Handles all the fetching with the rubygems server class Fetcher autoload :CompactIndex, File.expand_path("fetcher/compact_index", __dir__) autoload :Downloader, File.expand_path("fetcher/downloader", __dir__) autoload :Dependency, File.expand_path("fetcher/dependency", __dir__) autoload :Index, File.expand_path("fetcher/index", __dir__) # This error is raised when it looks like the network is down class NetworkDownError < HTTPError; end # This error is raised if we should rate limit our requests to the API class TooManyRequestsError < HTTPError; end # This error is raised if the API returns a 413 (only printed in verbose) class FallbackError < HTTPError; end # This is the error raised if OpenSSL fails the cert verification class CertificateFailureError < HTTPError def initialize(remote_uri) remote_uri = filter_uri(remote_uri) super "Could not verify the SSL certificate for #{remote_uri}.\nThere" \ " is a chance you are experiencing a man-in-the-middle attack, but" \ " most likely your system doesn't have the CA certificates needed" \ " for verification. For information about OpenSSL certificates, see" \ " http://bit.ly/ruby-ssl. To connect without using SSL, edit your Gemfile" \ " sources and change 'https' to 'http'." end end # This is the error raised when a source is HTTPS and OpenSSL didn't load class SSLError < HTTPError def initialize(msg = nil) super msg || "Could not load OpenSSL.\n" \ "You must recompile Ruby with OpenSSL support or change the sources in your " \ "Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL " \ "using RVM are available at rvm.io/packages/openssl." end end # This error is raised if HTTP authentication is required, but not provided. class AuthenticationRequiredError < HTTPError def initialize(remote_uri) remote_uri = filter_uri(remote_uri) super "Authentication is required for #{remote_uri}.\n" \ "Please supply credentials for this source. You can do this by running:\n" \ "`bundle config set --global #{remote_uri} username:password`\n" \ "or by storing the credentials in the `#{Settings.key_for(remote_uri)}` environment variable" end end # This error is raised if HTTP authentication is provided, but incorrect. class BadAuthenticationError < HTTPError def initialize(remote_uri) remote_uri = filter_uri(remote_uri) super "Bad username or password for #{remote_uri}.\n" \ "Please double-check your credentials and correct them." end end # Exceptions classes that should bypass retry attempts. If your password didn't work the # first time, it's not going to the third time. NET_ERRORS = [:HTTPBadGateway, :HTTPBadRequest, :HTTPFailedDependency, :HTTPForbidden, :HTTPInsufficientStorage, :HTTPMethodNotAllowed, :HTTPMovedPermanently, :HTTPNoContent, :HTTPNotFound, :HTTPNotImplemented, :HTTPPreconditionFailed, :HTTPRequestEntityTooLarge, :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity, :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze FAIL_ERRORS = begin fail_errors = [AuthenticationRequiredError, BadAuthenticationError, FallbackError] fail_errors << Gem::Requirement::BadRequirementError if defined?(Gem::Requirement::BadRequirementError) fail_errors.concat(NET_ERRORS.map {|e| SharedHelpers.const_get_safely(e, Net) }.compact) end.freeze class << self attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries end self.redirect_limit = Bundler.settings[:redirect] # How many redirects to allow in one request self.api_timeout = Bundler.settings[:timeout] # How long to wait for each API call self.max_retries = Bundler.settings[:retry] # How many retries for the API call def initialize(remote) @remote = remote Socket.do_not_reverse_lookup = true connection # create persistent connection end def uri @remote.anonymized_uri end # fetch a gem specification def fetch_spec(spec) spec -= [nil, "ruby", ""] spec_file_name = "#{spec.join "-"}.gemspec" uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") if uri.scheme == "file" path = Bundler.rubygems.correct_for_windows_path(uri.path) Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(path)) elsif cached_spec_path = gemspec_cached_path(spec_file_name) Bundler.load_gemspec(cached_spec_path) else Bundler.load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) end rescue MarshalError raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ "Your network or your gem server is probably having issues right now." end # return the specs in the bundler format as an index with retries def specs_with_retry(gem_names, source) Bundler::Retry.new("fetcher", FAIL_ERRORS).attempts do specs(gem_names, source) end end # return the specs in the bundler format as an index def specs(gem_names, source) old = Bundler.rubygems.sources index = Bundler::Index.new if Bundler::Fetcher.disable_endpoint @use_api = false specs = fetchers.last.specs(gem_names) else specs = [] fetchers.shift until fetchers.first.available? || fetchers.empty? fetchers.dup.each do |f| break unless f.api_fetcher? && !gem_names || !specs = f.specs(gem_names) fetchers.delete(f) end @use_api = false if fetchers.none?(&:api_fetcher?) end specs.each do |name, version, platform, dependencies, metadata| spec = if dependencies EndpointSpecification.new(name, version, platform, dependencies, metadata) else RemoteSpecification.new(name, version, platform, self) end spec.source = source spec.remote = @remote index << spec end index rescue CertificateFailureError Bundler.ui.info "" if gem_names && use_api # newline after dots raise ensure Bundler.rubygems.sources = old end def use_api return @use_api if defined?(@use_api) fetchers.shift until fetchers.first.available? @use_api = if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint false else fetchers.first.api_fetcher? end end def user_agent @user_agent ||= begin ruby = Bundler::RubyVersion.system agent = String.new("bundler/#{Bundler::VERSION}") agent << " rubygems/#{Gem::VERSION}" agent << " ruby/#{ruby.versions_string(ruby.versions)}" agent << " (#{ruby.host})" agent << " command/#{ARGV.first}" if ruby.engine != "ruby" # engine_version raises on unknown engines engine_version = begin ruby.engine_versions rescue RuntimeError "???" end agent << " #{ruby.engine}/#{ruby.versions_string(engine_version)}" end agent << " options/#{Bundler.settings.all.join(",")}" agent << " ci/#{cis.join(",")}" if cis.any? # add a random ID so we can consolidate runs server-side agent << " " << SecureRandom.hex(8) # add any user agent strings set in the config extra_ua = Bundler.settings[:user_agent] agent << " " << extra_ua if extra_ua agent end end def fetchers @fetchers ||= FETCHERS.map {|f| f.new(downloader, @remote, uri) } end def http_proxy return unless uri = connection.proxy_uri uri.to_s end def inspect "#<#{self.class}:0x#{object_id} uri=#{uri}>" end private FETCHERS = [CompactIndex, Dependency, Index].freeze def cis env_cis = { "TRAVIS" => "travis", "CIRCLECI" => "circle", "SEMAPHORE" => "semaphore", "JENKINS_URL" => "jenkins", "BUILDBOX" => "buildbox", "GO_SERVER_URL" => "go", "SNAP_CI" => "snap", "GITLAB_CI" => "gitlab", "CI_NAME" => ENV["CI_NAME"], "CI" => "ci", } env_cis.find_all {|env, _| ENV[env] }.map {|_, ci| ci } end def connection @connection ||= begin needs_ssl = remote_uri.scheme == "https" || Bundler.settings[:ssl_verify_mode] || Bundler.settings[:ssl_client_cert] raise SSLError if needs_ssl && !defined?(OpenSSL::SSL) con = PersistentHTTP.new :name => "bundler", :proxy => :ENV if gem_proxy = Bundler.rubygems.configuration[:http_proxy] con.proxy = Bundler::URI.parse(gem_proxy) if gem_proxy != :no_proxy end if remote_uri.scheme == "https" con.verify_mode = (Bundler.settings[:ssl_verify_mode] || OpenSSL::SSL::VERIFY_PEER) con.cert_store = bundler_cert_store end ssl_client_cert = Bundler.settings[:ssl_client_cert] || (Bundler.rubygems.configuration.ssl_client_cert if Bundler.rubygems.configuration.respond_to?(:ssl_client_cert)) if ssl_client_cert pem = File.read(ssl_client_cert) con.cert = OpenSSL::X509::Certificate.new(pem) con.key = OpenSSL::PKey::RSA.new(pem) end con.read_timeout = Fetcher.api_timeout con.open_timeout = Fetcher.api_timeout con.override_headers["User-Agent"] = user_agent con.override_headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri con end end # cached gem specification path, if one exists def gemspec_cached_path(spec_file_name) paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } paths = paths.select {|path| File.file? path } paths.first end HTTP_ERRORS = [ Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH, Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, PersistentHTTP::Error, Zlib::BufError, Errno::EHOSTUNREACH ].freeze def bundler_cert_store store = OpenSSL::X509::Store.new ssl_ca_cert = Bundler.settings[:ssl_ca_cert] || (Bundler.rubygems.configuration.ssl_ca_cert if Bundler.rubygems.configuration.respond_to?(:ssl_ca_cert)) if ssl_ca_cert if File.directory? ssl_ca_cert store.add_path ssl_ca_cert else store.add_file ssl_ca_cert end else store.set_default_paths Gem::Request.get_cert_files.each {|c| store.add_file c } end store end private def remote_uri @remote.uri end def downloader @downloader ||= Downloader.new(connection, self.class.redirect_limit) end end end PK ]•n.gems/bundler-2.2.24/lib/bundler/source_list.rbnu[# frozen_string_literal: true module Bundler class SourceList attr_reader :path_sources, :git_sources, :plugin_sources, :global_path_source, :metadata_source def global_rubygems_source @global_rubygems_source ||= rubygems_aggregate_class.new("allow_local" => true) end def initialize @path_sources = [] @git_sources = [] @plugin_sources = [] @global_rubygems_source = nil @global_path_source = nil @rubygems_sources = [] @metadata_source = Source::Metadata.new @merged_gem_lockfile_sections = false end def merged_gem_lockfile_sections? @merged_gem_lockfile_sections end def merged_gem_lockfile_sections!(replacement_source) @merged_gem_lockfile_sections = true @global_rubygems_source = replacement_source end def aggregate_global_source? global_rubygems_source.multiple_remotes? end def add_path_source(options = {}) if options["gemspec"] add_source_to_list Source::Gemspec.new(options), path_sources else path_source = add_source_to_list Source::Path.new(options), path_sources @global_path_source ||= path_source if options["global"] path_source end end def add_git_source(options = {}) add_source_to_list(Source::Git.new(options), git_sources).tap do |source| warn_on_git_protocol(source) end end def add_rubygems_source(options = {}) new_source = Source::Rubygems.new(options) return @global_rubygems_source if @global_rubygems_source == new_source add_source_to_list new_source, @rubygems_sources end def add_plugin_source(source, options = {}) add_source_to_list Plugin.source(source).new(options), @plugin_sources end def add_global_rubygems_remote(uri) global_rubygems_source.add_remote(uri) global_rubygems_source end def default_source global_path_source || global_rubygems_source end def rubygems_sources non_global_rubygems_sources + [global_rubygems_source] end def non_global_rubygems_sources @rubygems_sources end def rubygems_remotes rubygems_sources.map(&:remotes).flatten.uniq end def all_sources path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source] end def non_default_explicit_sources all_sources - [default_source, metadata_source] end def get(source) source_list_for(source).find {|s| equal_source?(source, s) || equivalent_source?(source, s) } end def lock_sources lock_other_sources + lock_rubygems_sources end def lock_other_sources (path_sources + git_sources + plugin_sources).sort_by(&:to_s) end def lock_rubygems_sources if merged_gem_lockfile_sections? [combine_rubygems_sources] else rubygems_sources.sort_by(&:to_s) end end # Returns true if there are changes def replace_sources!(replacement_sources) return false if replacement_sources.empty? @path_sources, @git_sources, @plugin_sources = map_sources(replacement_sources) different_sources?(lock_sources, replacement_sources) end # Returns true if there are changes def expired_sources?(replacement_sources) return false if replacement_sources.empty? lock_sources = dup_with_replaced_sources(replacement_sources).lock_sources different_sources?(lock_sources, replacement_sources) end def local_only! all_sources.each(&:local_only!) end def cached! all_sources.each(&:cached!) end def remote! all_sources.each(&:remote!) end private def dup_with_replaced_sources(replacement_sources) new_source_list = dup new_source_list.replace_sources!(replacement_sources) new_source_list end def map_sources(replacement_sources) [path_sources, git_sources, plugin_sources].map do |sources| sources.map do |source| replacement_sources.find {|s| s == source } || source end end end def different_sources?(lock_sources, replacement_sources) !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources) end def rubygems_aggregate_class Source::Rubygems end def add_source_to_list(source, list) list.unshift(source).uniq! source end def source_list_for(source) case source when Source::Git then git_sources when Source::Path then path_sources when Source::Rubygems then rubygems_sources when Plugin::API::Source then plugin_sources else raise ArgumentError, "Invalid source: #{source.inspect}" end end def combine_rubygems_sources Source::Rubygems.new("remotes" => rubygems_remotes) end def warn_on_git_protocol(source) return if Bundler.settings["git.allow_insecure"] if source.uri =~ /^git\:/ Bundler.ui.warn "The git source `#{source.uri}` uses the `git` protocol, " \ "which transmits data without encryption. Disable this warning with " \ "`bundle config set --local git.allow_insecure true`, or switch to the `https` " \ "protocol to keep your data secure." end end def equal_sources?(lock_sources, replacement_sources) lock_sources.sort_by(&:to_s) == replacement_sources.sort_by(&:to_s) end def equal_source?(source, other_source) return source.include?(other_source) if source.is_a?(Source::Rubygems) && other_source.is_a?(Source::Rubygems) && !merged_gem_lockfile_sections? source == other_source end def equivalent_source?(source, other_source) return false unless Bundler.settings[:allow_deployment_source_credential_changes] && source.is_a?(Source::Rubygems) equivalent_rubygems_sources?([source], [other_source]) end def equivalent_sources?(lock_sources, replacement_sources) return false unless Bundler.settings[:allow_deployment_source_credential_changes] lock_rubygems_sources, lock_other_sources = lock_sources.partition {|s| s.is_a?(Source::Rubygems) } replacement_rubygems_sources, replacement_other_sources = replacement_sources.partition {|s| s.is_a?(Source::Rubygems) } equivalent_rubygems_sources?(lock_rubygems_sources, replacement_rubygems_sources) && equal_sources?(lock_other_sources, replacement_other_sources) end def equivalent_rubygems_sources?(lock_sources, replacement_sources) actual_remotes = replacement_sources.map(&:remotes).flatten.uniq lock_sources.all? {|s| s.equivalent_remotes?(actual_remotes) } end end end PK ]wj51gems/bundler-2.2.24/lib/bundler/build_metadata.rbnu[# frozen_string_literal: true module Bundler # Represents metadata from when the Bundler gem was built. module BuildMetadata # begin ivars @release = false # end ivars # A hash representation of the build metadata. def self.to_h { "Built At" => built_at, "Git SHA" => git_commit_sha, "Released Version" => release?, } end # A string representing the date the bundler gem was built. def self.built_at @built_at ||= Time.now.utc.strftime("%Y-%m-%d").freeze end # The SHA for the git commit the bundler gem was built from. def self.git_commit_sha return @git_commit_sha if instance_variable_defined? :@git_commit_sha # If Bundler has been installed without its .git directory and without a # commit instance variable then we can't determine its commits SHA. git_dir = File.join(File.expand_path("../../../..", __FILE__), ".git") if File.directory?(git_dir) return @git_commit_sha = Dir.chdir(git_dir) { `git rev-parse --short HEAD`.strip.freeze } end @git_commit_sha ||= "unknown" end # Whether this is an official release build of Bundler. def self.release? @release end end end PK ][56gems/bundler-2.2.24/lib/bundler/vendored_persistent.rbnu[# frozen_string_literal: true module Bundler module Persistent module Net module HTTP end end end end require_relative "vendor/net-http-persistent/lib/net/http/persistent" module Bundler class PersistentHTTP < Persistent::Net::HTTP::Persistent def connection_for(uri) super(uri) do |connection| result = yield connection warn_old_tls_version_rubygems_connection(uri, connection) result end end def warn_old_tls_version_rubygems_connection(uri, connection) return unless connection.http.use_ssl? return unless (uri.host || "").end_with?("rubygems.org") socket = connection.instance_variable_get(:@socket) return unless socket socket_io = socket.io return unless socket_io.respond_to?(:ssl_version) ssl_version = socket_io.ssl_version case ssl_version when /TLSv([\d\.]+)/ version = Gem::Version.new($1) if version < Gem::Version.new("1.2") Bundler.ui.warn \ "Warning: Your Ruby version is compiled against a copy of OpenSSL that is very old. " \ "Starting in January 2018, RubyGems.org will refuse connection requests from these " \ "very old versions of OpenSSL. If you will need to continue installing gems after " \ "January 2018, please follow this guide to upgrade: http://ruby.to/tls-outdated.", :wrap => true end end end end end PK ][  ,gems/bundler-2.2.24/lib/bundler/ui/silent.rbnu[# frozen_string_literal: true module Bundler module UI class Silent attr_writer :shell def initialize @warnings = [] end def add_color(string, color) string end def info(message, newline = nil) end def confirm(message, newline = nil) end def warn(message, newline = nil) @warnings |= [message] end def error(message, newline = nil) end def debug(message, newline = nil) end def debug? false end def quiet? false end def ask(message) end def yes?(msg) raise "Cannot ask yes? with a silent shell" end def no? raise "Cannot ask no? with a silent shell" end def level=(name) end def level(name = nil) end def trace(message, newline = nil, force = false) end def silence yield end def unprinted_warnings @warnings end end end end PK ]K66.gems/bundler-2.2.24/lib/bundler/ui/rg_proxy.rbnu[# frozen_string_literal: true require_relative "../ui" require "rubygems/user_interaction" module Bundler module UI class RGProxy < ::Gem::SilentUI def initialize(ui) @ui = ui super() end def say(message) @ui && @ui.debug(message) end end end end PK ]Xȷr r +gems/bundler-2.2.24/lib/bundler/ui/shell.rbnu[# frozen_string_literal: true require_relative "../vendored_thor" module Bundler module UI class Shell LEVELS = %w[silent error warn confirm info debug].freeze attr_writer :shell def initialize(options = {}) Thor::Base.shell = options["no-color"] ? Thor::Shell::Basic : nil @shell = Thor::Base.shell.new @level = ENV["DEBUG"] ? "debug" : "info" @warning_history = [] end def add_color(string, *color) @shell.set_color(string, *color) end def info(msg, newline = nil) tell_me(msg, nil, newline) if level("info") end def confirm(msg, newline = nil) tell_me(msg, :green, newline) if level("confirm") end def warn(msg, newline = nil, color = :yellow) return unless level("warn") return if @warning_history.include? msg @warning_history << msg tell_err(msg, color, newline) end def error(msg, newline = nil, color = :red) return unless level("error") tell_err(msg, color, newline) end def debug(msg, newline = nil) tell_me(msg, nil, newline) if debug? end def debug? level("debug") end def quiet? level("quiet") end def ask(msg) @shell.ask(msg) end def yes?(msg) @shell.yes?(msg) end def no? @shell.no?(msg) end def level=(level) raise ArgumentError unless LEVELS.include?(level.to_s) @level = level.to_s end def level(name = nil) return @level unless name unless index = LEVELS.index(name) raise "#{name.inspect} is not a valid level" end index <= LEVELS.index(@level) end def trace(e, newline = nil, force = false) return unless debug? || force msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n ")}" tell_me(msg, nil, newline) end def silence(&blk) with_level("silent", &blk) end def unprinted_warnings [] end private # valimism def tell_me(msg, color = nil, newline = nil) msg = word_wrap(msg) if newline.is_a?(Hash) && newline[:wrap] if newline.nil? @shell.say(msg, color) else @shell.say(msg, color, newline) end end def tell_err(message, color = nil, newline = nil) return if @shell.send(:stderr).closed? newline ||= message.to_s !~ /( |\t)\Z/ message = word_wrap(message) if newline.is_a?(Hash) && newline[:wrap] color = nil if color && !$stderr.tty? buffer = @shell.send(:prepare_message, message, *color) buffer << "\n" if newline && !message.to_s.end_with?("\n") @shell.send(:stderr).print(buffer) @shell.send(:stderr).flush end def strip_leading_spaces(text) spaces = text[/\A\s+/, 0] spaces ? text.gsub(/#{spaces}/, "") : text end def word_wrap(text, line_width = @shell.terminal_width) strip_leading_spaces(text).split("\n").collect do |line| line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line end * "\n" end def with_level(level) original = @level @level = level yield ensure @level = original end end end end PK ]unuu(gems/bundler-2.2.24/lib/bundler/retry.rbnu[# frozen_string_literal: true module Bundler # General purpose class for retrying code that may fail class Retry attr_accessor :name, :total_runs, :current_run class << self def default_attempts default_retries + 1 end alias_method :attempts, :default_attempts def default_retries Bundler.settings[:retry] end end def initialize(name, exceptions = nil, retries = self.class.default_retries) @name = name @retries = retries @exceptions = Array(exceptions) || [] @total_runs = @retries + 1 # will run once, then upto attempts.times end def attempt(&block) @current_run = 0 @failed = false @error = nil run(&block) while keep_trying? @result end alias_method :attempts, :attempt private def run(&block) @failed = false @current_run += 1 @result = block.call rescue StandardError => e fail_attempt(e) end def fail_attempt(e) @failed = true if last_attempt? || @exceptions.any? {|k| e.is_a?(k) } Bundler.ui.info "" unless Bundler.ui.debug? raise e end return true unless name Bundler.ui.info "" unless Bundler.ui.debug? # Add new line in case dots preceded this Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", Bundler.ui.debug? end def keep_trying? return true if current_run.zero? return false if last_attempt? return true if @failed end def last_attempt? current_run >= total_runs end end end PK ]0ee5gems/bundler-2.2.24/lib/bundler/vendored_fileutils.rbnu[# frozen_string_literal: true module Bundler; end require_relative "vendor/fileutils/lib/fileutils" PK ]'/gems/bundler-2.2.24/lib/bundler/feature_flag.rbnu[# frozen_string_literal: true module Bundler class FeatureFlag def self.settings_flag(flag, &default) unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s) raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key" end settings_method("#{flag}?", flag, &default) end private_class_method :settings_flag def self.settings_option(key, &default) settings_method(key, key, &default) end private_class_method :settings_option def self.settings_method(name, key, &default) define_method(name) do value = Bundler.settings[key] value = instance_eval(&default) if value.nil? value end end private_class_method :settings_method (1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } } settings_flag(:allow_offline_install) { bundler_3_mode? } settings_flag(:auto_clean_without_path) { bundler_3_mode? } settings_flag(:cache_all) { bundler_3_mode? } settings_flag(:default_install_uses_path) { bundler_3_mode? } settings_flag(:forget_cli_options) { bundler_3_mode? } settings_flag(:global_gem_cache) { bundler_3_mode? } settings_flag(:path_relative_to_cwd) { bundler_3_mode? } settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") } settings_flag(:print_only_version_number) { bundler_3_mode? } settings_flag(:setup_makes_kernel_gem_public) { !bundler_3_mode? } settings_flag(:suppress_install_using_messages) { bundler_3_mode? } settings_flag(:update_requires_all_flag) { bundler_4_mode? } settings_flag(:use_gem_version_promoter_for_major_updates) { bundler_3_mode? } settings_option(:default_cli_command) { bundler_3_mode? ? :cli_help : :install } def initialize(bundler_version) @bundler_version = Gem::Version.create(bundler_version) end def major_version @bundler_version.segments.first end private :major_version end end PK ]O ɧ*gems/bundler-2.2.24/lib/bundler/gemdeps.rbnu[# frozen_string_literal: true module Bundler class Gemdeps def initialize(runtime) @runtime = runtime end def requested_specs @runtime.requested_specs end def specs @runtime.specs end def dependencies @runtime.dependencies end def current_dependencies @runtime.current_dependencies end def requires @runtime.requires end end end PK ]-L001gems/bundler-2.2.24/lib/bundler/version_ranges.rbnu[# frozen_string_literal: true module Bundler module VersionRanges NEq = Struct.new(:version) ReqR = Struct.new(:left, :right) class ReqR Endpoint = Struct.new(:version, :inclusive) do def <=>(other) if version.equal?(INFINITY) return 0 if other.version.equal?(INFINITY) return 1 elsif other.version.equal?(INFINITY) return -1 end comp = version <=> other.version return comp unless comp.zero? if inclusive && !other.inclusive 1 elsif !inclusive && other.inclusive -1 else 0 end end end def to_s "#{left.inclusive ? "[" : "("}#{left.version}, #{right.version}#{right.inclusive ? "]" : ")"}" end INFINITY = begin inf = Object.new def inf.to_s "∞" end def inf.<=>(other) return 0 if other.equal?(self) 1 end inf.freeze end ZERO = Gem::Version.new("0.a") def cover?(v) return false if left.inclusive && left.version > v return false if !left.inclusive && left.version >= v if right.version != INFINITY return false if right.inclusive && right.version < v return false if !right.inclusive && right.version <= v end true end def empty? left.version == right.version && !(left.inclusive && right.inclusive) end def single? left.version == right.version end def <=>(other) return -1 if other.equal?(INFINITY) comp = left <=> other.left return comp unless comp.zero? right <=> other.right end UNIVERSAL = ReqR.new(ReqR::Endpoint.new(Gem::Version.new("0.a"), true), ReqR::Endpoint.new(ReqR::INFINITY, false)).freeze end def self.for_many(requirements) requirements = requirements.map(&:requirements).flatten(1).map {|r| r.join(" ") } requirements << ">= 0.a" if requirements.empty? requirement = Gem::Requirement.new(requirements) self.for(requirement) end def self.for(requirement) ranges = requirement.requirements.map do |op, v| case op when "=" then ReqR.new(ReqR::Endpoint.new(v, true), ReqR::Endpoint.new(v, true)) when "!=" then NEq.new(v) when ">=" then ReqR.new(ReqR::Endpoint.new(v, true), ReqR::Endpoint.new(ReqR::INFINITY, false)) when ">" then ReqR.new(ReqR::Endpoint.new(v, false), ReqR::Endpoint.new(ReqR::INFINITY, false)) when "<" then ReqR.new(ReqR::Endpoint.new(ReqR::ZERO, true), ReqR::Endpoint.new(v, false)) when "<=" then ReqR.new(ReqR::Endpoint.new(ReqR::ZERO, true), ReqR::Endpoint.new(v, true)) when "~>" then ReqR.new(ReqR::Endpoint.new(v, true), ReqR::Endpoint.new(v.bump, false)) else raise "unknown version op #{op} in requirement #{requirement}" end end.uniq ranges, neqs = ranges.partition {|r| !r.is_a?(NEq) } [ranges.sort, neqs.map(&:version)] end def self.empty?(ranges, neqs) !ranges.reduce(ReqR::UNIVERSAL) do |last_range, curr_range| next false unless last_range next false if curr_range.single? && neqs.include?(curr_range.left.version) next curr_range if last_range.right.version == ReqR::INFINITY case last_range.right.version <=> curr_range.left.version # higher when 1 then next ReqR.new(curr_range.left, last_range.right) # equal when 0 if last_range.right.inclusive && curr_range.left.inclusive && !neqs.include?(curr_range.left.version) ReqR.new(curr_range.left, [curr_range.right, last_range.right].max) end # lower when -1 then next false end end end end end PK ]3,(gems/bundler-2.2.24/lib/bundler/graph.rbnu[# frozen_string_literal: true require "set" module Bundler class Graph GRAPH_NAME = :Gemfile def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png", without = []) @env = env @output_file = output_file @show_version = show_version @show_requirements = show_requirements @output_format = output_format @without_groups = without.map(&:to_sym) @groups = [] @relations = Hash.new {|h, k| h[k] = Set.new } @node_options = {} @edge_options = {} _populate_relations end attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format def viz GraphVizClient.new(self).run end private def _populate_relations parent_dependencies = _groups.values.to_set.flatten loop do break if parent_dependencies.empty? tmp = Set.new parent_dependencies.each do |dependency| child_dependencies = spec_for_dependency(dependency).runtime_dependencies.to_set @relations[dependency.name] += child_dependencies.map(&:name).to_set tmp += child_dependencies @node_options[dependency.name] = _make_label(dependency, :node) child_dependencies.each do |c_dependency| @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge) end end parent_dependencies = tmp end end def _groups relations = Hash.new {|h, k| h[k] = Set.new } @env.current_dependencies.each do |dependency| dependency.groups.each do |group| next if @without_groups.include?(group) relations[group.to_s].add(dependency) @relations[group.to_s].add(dependency.name) @node_options[group.to_s] ||= _make_label(group, :node) @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge) end end @groups = relations.keys relations end def _make_label(symbol_or_string_or_dependency, element_type) case element_type.to_sym when :node if symbol_or_string_or_dependency.is_a?(Gem::Dependency) label = symbol_or_string_or_dependency.name.dup label << "\n#{spec_for_dependency(symbol_or_string_or_dependency).version}" if @show_version else label = symbol_or_string_or_dependency.to_s end when :edge label = nil if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements tmp = symbol_or_string_or_dependency.requirements_list.join(", ") label = tmp if tmp != ">= 0" end else raise ArgumentError, "2nd argument is invalid" end label.nil? ? {} : { :label => label } end def spec_for_dependency(dependency) @env.requested_specs.find {|s| s.name == dependency.name } end class GraphVizClient def initialize(graph_instance) @graph_name = graph_instance.class::GRAPH_NAME @groups = graph_instance.groups @relations = graph_instance.relations @node_options = graph_instance.node_options @edge_options = graph_instance.edge_options @output_file = graph_instance.output_file @output_format = graph_instance.output_format end def g @g ||= ::GraphViz.digraph(@graph_name, :concentrate => true, :normalize => true, :nodesep => 0.55) do |g| g.edge[:weight] = 2 g.edge[:fontname] = g.node[:fontname] = "Arial, Helvetica, SansSerif" g.edge[:fontsize] = 12 end end def run @groups.each do |group| g.add_nodes( group, { :style => "filled", :fillcolor => "#B9B9D5", :shape => "box3d", :fontsize => 16, }.merge(@node_options[group]) ) end @relations.each do |parent, children| children.each do |child| if @groups.include?(parent) g.add_nodes(child, { :style => "filled", :fillcolor => "#B9B9D5" }.merge(@node_options[child])) g.add_edges(parent, child, { :constraint => false }.merge(@edge_options["#{parent}_#{child}"])) else g.add_nodes(child, @node_options[child]) g.add_edges(parent, child, @edge_options["#{parent}_#{child}"]) end end end if @output_format.to_s == "debug" $stdout.puts g.output :none => String Bundler.ui.info "debugging bundle viz..." else begin g.output @output_format.to_sym => "#{@output_file}.#{@output_format}" Bundler.ui.info "#{@output_file}.#{@output_format}" rescue ArgumentError => e warn "Unsupported output format. See Ruby-Graphviz/lib/graphviz/constants.rb" raise e end end end end end end PK ]YE[hgems/rdoc-6.2.1.1/exe/rdocnuȯ#!/usr/bin/ruby # # RDoc: Documentation tool for source code # (see lib/rdoc/rdoc.rb for more information) # # Copyright (c) 2003 Dave Thomas # Released under the same terms as Ruby begin gem 'rdoc' rescue NameError => e # --disable-gems raise unless e.name == :gem rescue Gem::LoadError end require 'rdoc/rdoc' begin r = RDoc::RDoc.new r.document ARGV rescue Errno::ENOSPC $stderr.puts 'Ran out of space creating documentation' $stderr.puts $stderr.puts 'Please free up some space and try again' rescue SystemExit raise rescue Exception => e if $DEBUG_RDOC then $stderr.puts e.message $stderr.puts "#{e.backtrace.join "\n\t"}" $stderr.puts elsif Interrupt === e then $stderr.puts $stderr.puts 'Interrupted' else $stderr.puts "uh-oh! RDoc had a problem:" $stderr.puts e.message $stderr.puts $stderr.puts "run with --debug for full backtrace" end exit 1 end PK ]ֳsgems/rdoc-6.2.1.1/exe/rinuȯ#!/usr/bin/ruby begin gem 'rdoc' rescue NameError => e # --disable-gems raise unless e.name == :gem rescue Gem::LoadError end require 'rdoc/ri/driver' RDoc::RI::Driver.run ARGV PK ]u`x`x%gems/rdoc-6.2.1.1/lib/rdoc/context.rbnu[# frozen_string_literal: true require 'cgi' ## # A Context is something that can hold modules, classes, methods, attributes, # aliases, requires, and includes. Classes, modules, and files are all # Contexts. class RDoc::Context < RDoc::CodeObject include Comparable ## # Types of methods TYPES = %w[class instance] ## # If a context has these titles it will be sorted in this order. TOMDOC_TITLES = [nil, 'Public', 'Internal', 'Deprecated'] # :nodoc: TOMDOC_TITLES_SORT = TOMDOC_TITLES.sort_by { |title| title.to_s } # :nodoc: ## # Class/module aliases attr_reader :aliases ## # All attr* methods attr_reader :attributes ## # Block params to be used in the next MethodAttr parsed under this context attr_accessor :block_params ## # Constants defined attr_reader :constants ## # Sets the current documentation section of documentation attr_writer :current_section ## # Files this context is found in attr_reader :in_files ## # Modules this context includes attr_reader :includes ## # Modules this context is extended with attr_reader :extends ## # Methods defined in this context attr_reader :method_list ## # Name of this class excluding namespace. See also full_name attr_reader :name ## # Files this context requires attr_reader :requires ## # Use this section for the next method, attribute or constant added. attr_accessor :temporary_section ## # Hash old_name => [aliases], for aliases # that haven't (yet) been resolved to a method/attribute. # (Not to be confused with the aliases of the context.) attr_accessor :unmatched_alias_lists ## # Aliases that could not be resolved. attr_reader :external_aliases ## # Current visibility of this context attr_accessor :visibility ## # Current visibility of this line attr_writer :current_line_visibility ## # Hash of registered methods. Attributes are also registered here, # twice if they are RW. attr_reader :methods_hash ## # Params to be used in the next MethodAttr parsed under this context attr_accessor :params ## # Hash of registered constants. attr_reader :constants_hash ## # Creates an unnamed empty context with public current visibility def initialize super @in_files = [] @name ||= "unknown" @parent = nil @visibility = :public @current_section = Section.new self, nil, nil @sections = { nil => @current_section } @temporary_section = nil @classes = {} @modules = {} initialize_methods_etc end ## # Sets the defaults for methods and so-forth def initialize_methods_etc @method_list = [] @attributes = [] @aliases = [] @requires = [] @includes = [] @extends = [] @constants = [] @external_aliases = [] @current_line_visibility = nil # This Hash maps a method name to a list of unmatched aliases (aliases of # a method not yet encountered). @unmatched_alias_lists = {} @methods_hash = {} @constants_hash = {} @params = nil @store ||= nil end ## # Contexts are sorted by full_name def <=>(other) return nil unless RDoc::CodeObject === other full_name <=> other.full_name end ## # Adds an item of type +klass+ with the given +name+ and +comment+ to the # context. # # Currently only RDoc::Extend and RDoc::Include are supported. def add klass, name, comment if RDoc::Extend == klass then ext = RDoc::Extend.new name, comment add_extend ext elsif RDoc::Include == klass then incl = RDoc::Include.new name, comment add_include incl else raise NotImplementedError, "adding a #{klass} is not implemented" end end ## # Adds +an_alias+ that is automatically resolved def add_alias an_alias return an_alias unless @document_self method_attr = find_method(an_alias.old_name, an_alias.singleton) || find_attribute(an_alias.old_name, an_alias.singleton) if method_attr then method_attr.add_alias an_alias, self else add_to @external_aliases, an_alias unmatched_alias_list = @unmatched_alias_lists[an_alias.pretty_old_name] ||= [] unmatched_alias_list.push an_alias end an_alias end ## # Adds +attribute+ if not already there. If it is (as method(s) or attribute), # updates the comment if it was empty. # # The attribute is registered only if it defines a new method. # For instance, attr_reader :foo will not be registered # if method +foo+ exists, but attr_accessor :foo will be registered # if method +foo+ exists, but foo= does not. def add_attribute attribute return attribute unless @document_self # mainly to check for redefinition of an attribute as a method # TODO find a policy for 'attr_reader :foo' + 'def foo=()' register = false key = nil if attribute.rw.index 'R' then key = attribute.pretty_name known = @methods_hash[key] if known then known.comment = attribute.comment if known.comment.empty? elsif registered = @methods_hash[attribute.pretty_name + '='] and RDoc::Attr === registered then registered.rw = 'RW' else @methods_hash[key] = attribute register = true end end if attribute.rw.index 'W' then key = attribute.pretty_name + '=' known = @methods_hash[key] if known then known.comment = attribute.comment if known.comment.empty? elsif registered = @methods_hash[attribute.pretty_name] and RDoc::Attr === registered then registered.rw = 'RW' else @methods_hash[key] = attribute register = true end end if register then attribute.visibility = @visibility add_to @attributes, attribute resolve_aliases attribute end attribute end ## # Adds a class named +given_name+ with +superclass+. # # Both +given_name+ and +superclass+ may contain '::', and are # interpreted relative to the +self+ context. This allows handling correctly # examples like these: # class RDoc::Gauntlet < Gauntlet # module Mod # class Object # implies < ::Object # class SubObject < Object # this is _not_ ::Object # # Given class Container::Item RDoc assumes +Container+ is a module # unless it later sees class Container. +add_class+ automatically # upgrades +given_name+ to a class in this case. def add_class class_type, given_name, superclass = '::Object' # superclass +nil+ is passed by the C parser in the following cases: # - registering Object in 1.8 (correct) # - registering BasicObject in 1.9 (correct) # - registering RubyVM in 1.9 in iseq.c (incorrect: < Object in vm.c) # # If we later find a superclass for a registered class with a nil # superclass, we must honor it. # find the name & enclosing context if given_name =~ /^:+(\w+)$/ then full_name = $1 enclosing = top_level name = full_name.split(/:+/).last else full_name = child_name given_name if full_name =~ /^(.+)::(\w+)$/ then name = $2 ename = $1 enclosing = @store.classes_hash[ename] || @store.modules_hash[ename] # HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming) unless enclosing then # try the given name at top level (will work for the above example) enclosing = @store.classes_hash[given_name] || @store.modules_hash[given_name] return enclosing if enclosing # not found: create the parent(s) names = ename.split('::') enclosing = self names.each do |n| enclosing = enclosing.classes_hash[n] || enclosing.modules_hash[n] || enclosing.add_module(RDoc::NormalModule, n) end end else name = full_name enclosing = self end end # fix up superclass if full_name == 'BasicObject' then superclass = nil elsif full_name == 'Object' then superclass = '::BasicObject' end # find the superclass full name if superclass then if superclass =~ /^:+/ then superclass = $' #' else if superclass =~ /^(\w+):+(.+)$/ then suffix = $2 mod = find_module_named($1) superclass = mod.full_name + '::' + suffix if mod else mod = find_module_named(superclass) superclass = mod.full_name if mod end end # did we believe it was a module? mod = @store.modules_hash.delete superclass upgrade_to_class mod, RDoc::NormalClass, mod.parent if mod # e.g., Object < Object superclass = nil if superclass == full_name end klass = @store.classes_hash[full_name] if klass then # if TopLevel, it may not be registered in the classes: enclosing.classes_hash[name] = klass # update the superclass if needed if superclass then existing = klass.superclass existing = existing.full_name unless existing.is_a?(String) if existing if existing.nil? || (existing == 'Object' && superclass != 'Object') then klass.superclass = superclass end end else # this is a new class mod = @store.modules_hash.delete full_name if mod then klass = upgrade_to_class mod, RDoc::NormalClass, enclosing klass.superclass = superclass unless superclass.nil? else klass = class_type.new name, superclass enclosing.add_class_or_module(klass, enclosing.classes_hash, @store.classes_hash) end end klass.parent = self klass end ## # Adds the class or module +mod+ to the modules or # classes Hash +self_hash+, and to +all_hash+ (either # TopLevel::modules_hash or TopLevel::classes_hash), # unless #done_documenting is +true+. Sets the #parent of +mod+ # to +self+, and its #section to #current_section. Returns +mod+. def add_class_or_module mod, self_hash, all_hash mod.section = current_section # TODO declaring context? something is # wrong here... mod.parent = self mod.full_name = nil mod.store = @store unless @done_documenting then self_hash[mod.name] = mod # this must be done AFTER adding mod to its parent, so that the full # name is correct: all_hash[mod.full_name] = mod if @store.unmatched_constant_alias[mod.full_name] then to, file = @store.unmatched_constant_alias[mod.full_name] add_module_alias mod, mod.name, to, file end end mod end ## # Adds +constant+ if not already there. If it is, updates the comment, # value and/or is_alias_for of the known constant if they were empty/nil. def add_constant constant return constant unless @document_self # HACK: avoid duplicate 'PI' & 'E' in math.c (1.8.7 source code) # (this is a #ifdef: should be handled by the C parser) known = @constants_hash[constant.name] if known then known.comment = constant.comment if known.comment.empty? known.value = constant.value if known.value.nil? or known.value.strip.empty? known.is_alias_for ||= constant.is_alias_for else @constants_hash[constant.name] = constant add_to @constants, constant end constant end ## # Adds included module +include+ which should be an RDoc::Include def add_include include add_to @includes, include include end ## # Adds extension module +ext+ which should be an RDoc::Extend def add_extend ext add_to @extends, ext ext end ## # Adds +method+ if not already there. If it is (as method or attribute), # updates the comment if it was empty. def add_method method return method unless @document_self # HACK: avoid duplicate 'new' in io.c & struct.c (1.8.7 source code) key = method.pretty_name known = @methods_hash[key] if known then if @store then # otherwise we are loading known.comment = method.comment if known.comment.empty? previously = ", previously in #{known.file}" unless method.file == known.file @store.rdoc.options.warn \ "Duplicate method #{known.full_name} in #{method.file}#{previously}" end else @methods_hash[key] = method if @current_line_visibility method.visibility, @current_line_visibility = @current_line_visibility, nil else method.visibility = @visibility end add_to @method_list, method resolve_aliases method end method end ## # Adds a module named +name+. If RDoc already knows +name+ is a class then # that class is returned instead. See also #add_class. def add_module(class_type, name) mod = @classes[name] || @modules[name] return mod if mod full_name = child_name name mod = @store.modules_hash[full_name] || class_type.new(name) add_class_or_module mod, @modules, @store.modules_hash end ## # Adds a module by +RDoc::NormalModule+ instance. See also #add_module. def add_module_by_normal_module(mod) add_class_or_module mod, @modules, @store.modules_hash end ## # Adds an alias from +from+ (a class or module) to +name+ which was defined # in +file+. def add_module_alias from, from_name, to, file return from if @done_documenting to_full_name = child_name to.name # if we already know this name, don't register an alias: # see the metaprogramming in lib/active_support/basic_object.rb, # where we already know BasicObject is a class when we find # BasicObject = BlankSlate return from if @store.find_class_or_module to_full_name unless from @store.unmatched_constant_alias[child_name(from_name)] = [to, file] return to end new_to = from.dup new_to.name = to.name new_to.full_name = nil if new_to.module? then @store.modules_hash[to_full_name] = new_to @modules[to.name] = new_to else @store.classes_hash[to_full_name] = new_to @classes[to.name] = new_to end # Registers a constant for this alias. The constant value and comment # will be updated later, when the Ruby parser adds the constant const = RDoc::Constant.new to.name, nil, new_to.comment const.record_location file const.is_alias_for = from add_constant const new_to end ## # Adds +require+ to this context's top level def add_require(require) return require unless @document_self if RDoc::TopLevel === self then add_to @requires, require else parent.add_require require end end ## # Returns a section with +title+, creating it if it doesn't already exist. # +comment+ will be appended to the section's comment. # # A section with a +title+ of +nil+ will return the default section. # # See also RDoc::Context::Section def add_section title, comment = nil if section = @sections[title] then section.add_comment comment if comment else section = Section.new self, title, comment @sections[title] = section end section end ## # Adds +thing+ to the collection +array+ def add_to array, thing array << thing if @document_self thing.parent = self thing.store = @store if @store thing.section = current_section end ## # Is there any content? # # This means any of: comment, aliases, methods, attributes, external # aliases, require, constant. # # Includes and extends are also checked unless includes == false. def any_content(includes = true) @any_content ||= !( @comment.empty? && @method_list.empty? && @attributes.empty? && @aliases.empty? && @external_aliases.empty? && @requires.empty? && @constants.empty? ) @any_content || (includes && !(@includes + @extends).empty? ) end ## # Creates the full name for a child with +name+ def child_name name if name =~ /^:+/ $' #' elsif RDoc::TopLevel === self then name else "#{self.full_name}::#{name}" end end ## # Class attributes def class_attributes @class_attributes ||= attributes.select { |a| a.singleton } end ## # Class methods def class_method_list @class_method_list ||= method_list.select { |a| a.singleton } end ## # Array of classes in this context def classes @classes.values end ## # All classes and modules in this namespace def classes_and_modules classes + modules end ## # Hash of classes keyed by class name def classes_hash @classes end ## # The current documentation section that new items will be added to. If # temporary_section is available it will be used. def current_section if section = @temporary_section then @temporary_section = nil else section = @current_section end section end ## # Is part of this thing was defined in +file+? def defined_in?(file) @in_files.include?(file) end def display(method_attr) # :nodoc: if method_attr.is_a? RDoc::Attr "#{method_attr.definition} #{method_attr.pretty_name}" else "method #{method_attr.pretty_name}" end end ## # Iterator for ancestors for duck-typing. Does nothing. See # RDoc::ClassModule#each_ancestor. # # This method exists to make it easy to work with Context subclasses that # aren't part of RDoc. def each_ancestor # :nodoc: end ## # Iterator for attributes def each_attribute # :yields: attribute @attributes.each { |a| yield a } end ## # Iterator for classes and modules def each_classmodule(&block) # :yields: module classes_and_modules.sort.each(&block) end ## # Iterator for constants def each_constant # :yields: constant @constants.each {|c| yield c} end ## # Iterator for included modules def each_include # :yields: include @includes.each do |i| yield i end end ## # Iterator for extension modules def each_extend # :yields: extend @extends.each do |e| yield e end end ## # Iterator for methods def each_method # :yields: method return enum_for __method__ unless block_given? @method_list.sort.each { |m| yield m } end ## # Iterator for each section's contents sorted by title. The +section+, the # section's +constants+ and the sections +attributes+ are yielded. The # +constants+ and +attributes+ collections are sorted. # # To retrieve methods in a section use #methods_by_type with the optional # +section+ parameter. # # NOTE: Do not edit collections yielded by this method def each_section # :yields: section, constants, attributes return enum_for __method__ unless block_given? constants = @constants.group_by do |constant| constant.section end attributes = @attributes.group_by do |attribute| attribute.section end constants.default = [] attributes.default = [] sort_sections.each do |section| yield section, constants[section].select(&:display?).sort, attributes[section].select(&:display?).sort end end ## # Finds an attribute +name+ with singleton value +singleton+. def find_attribute(name, singleton) name = $1 if name =~ /^(.*)=$/ @attributes.find { |a| a.name == name && a.singleton == singleton } end ## # Finds an attribute with +name+ in this context def find_attribute_named(name) case name when /\A#/ then find_attribute name[1..-1], false when /\A::/ then find_attribute name[2..-1], true else @attributes.find { |a| a.name == name } end end ## # Finds a class method with +name+ in this context def find_class_method_named(name) @method_list.find { |meth| meth.singleton && meth.name == name } end ## # Finds a constant with +name+ in this context def find_constant_named(name) @constants.find do |m| m.name == name || m.full_name == name end end ## # Find a module at a higher scope def find_enclosing_module_named(name) parent && parent.find_module_named(name) end ## # Finds an external alias +name+ with singleton value +singleton+. def find_external_alias(name, singleton) @external_aliases.find { |m| m.name == name && m.singleton == singleton } end ## # Finds an external alias with +name+ in this context def find_external_alias_named(name) case name when /\A#/ then find_external_alias name[1..-1], false when /\A::/ then find_external_alias name[2..-1], true else @external_aliases.find { |a| a.name == name } end end ## # Finds a file with +name+ in this context def find_file_named name @store.find_file_named name end ## # Finds an instance method with +name+ in this context def find_instance_method_named(name) @method_list.find { |meth| !meth.singleton && meth.name == name } end ## # Finds a method, constant, attribute, external alias, module or file # named +symbol+ in this context. def find_local_symbol(symbol) find_method_named(symbol) or find_constant_named(symbol) or find_attribute_named(symbol) or find_external_alias_named(symbol) or find_module_named(symbol) or find_file_named(symbol) end ## # Finds a method named +name+ with singleton value +singleton+. def find_method(name, singleton) @method_list.find { |m| if m.singleton m.name == name && m.singleton == singleton else m.name == name && !m.singleton && !singleton end } end ## # Finds a instance or module method with +name+ in this context def find_method_named(name) case name when /\A#/ then find_method name[1..-1], false when /\A::/ then find_method name[2..-1], true else @method_list.find { |meth| meth.name == name } end end ## # Find a module with +name+ using ruby's scoping rules def find_module_named(name) res = @modules[name] || @classes[name] return res if res return self if self.name == name find_enclosing_module_named name end ## # Look up +symbol+, first as a module, then as a local symbol. def find_symbol(symbol) find_symbol_module(symbol) || find_local_symbol(symbol) end ## # Look up a module named +symbol+. def find_symbol_module(symbol) result = nil # look for a class or module 'symbol' case symbol when /^::/ then result = @store.find_class_or_module symbol when /^(\w+):+(.+)$/ suffix = $2 top = $1 searched = self while searched do mod = searched.find_module_named(top) break unless mod result = @store.find_class_or_module "#{mod.full_name}::#{suffix}" break if result || searched.is_a?(RDoc::TopLevel) searched = searched.parent end else searched = self while searched do result = searched.find_module_named(symbol) break if result || searched.is_a?(RDoc::TopLevel) searched = searched.parent end end result end ## # The full name for this context. This method is overridden by subclasses. def full_name '(unknown)' end ## # Does this context and its methods and constants all have documentation? # # (Yes, fully documented doesn't mean everything.) def fully_documented? documented? and attributes.all? { |a| a.documented? } and method_list.all? { |m| m.documented? } and constants.all? { |c| c.documented? } end ## # URL for this with a +prefix+ def http_url(prefix) path = name_for_path path = path.gsub(/<<\s*(\w*)/, 'from-\1') if path =~ /<'class' or # 'instance') and visibility (+:public+, +:protected+, +:private+). # # If +section+ is provided only methods in that RDoc::Context::Section will # be returned. def methods_by_type section = nil methods = {} TYPES.each do |type| visibilities = {} RDoc::VISIBILITIES.each do |vis| visibilities[vis] = [] end methods[type] = visibilities end each_method do |method| next if section and not method.section == section methods[method.type][method.visibility] << method end methods end ## # Yields AnyMethod and Attr entries matching the list of names in +methods+. def methods_matching(methods, singleton = false, &block) (@method_list + @attributes).each do |m| yield m if methods.include?(m.name) and m.singleton == singleton end each_ancestor do |parent| parent.methods_matching(methods, singleton, &block) end end ## # Array of modules in this context def modules @modules.values end ## # Hash of modules keyed by module name def modules_hash @modules end ## # Name to use to generate the url. # #full_name by default. def name_for_path full_name end ## # Changes the visibility for new methods to +visibility+ def ongoing_visibility=(visibility) @visibility = visibility end ## # Record +top_level+ as a file +self+ is in. def record_location(top_level) @in_files << top_level unless @in_files.include?(top_level) end ## # Should we remove this context from the documentation? # # The answer is yes if: # * #received_nodoc is +true+ # * #any_content is +false+ (not counting includes) # * All #includes are modules (not a string), and their module has # #remove_from_documentation? == true # * All classes and modules have #remove_from_documentation? == true def remove_from_documentation? @remove_from_documentation ||= @received_nodoc && !any_content(false) && @includes.all? { |i| !i.module.is_a?(String) && i.module.remove_from_documentation? } && classes_and_modules.all? { |cm| cm.remove_from_documentation? } end ## # Removes methods and attributes with a visibility less than +min_visibility+. #-- # TODO mark the visibility of attributes in the template (if not public?) def remove_invisible min_visibility return if [:private, :nodoc].include? min_visibility remove_invisible_in @method_list, min_visibility remove_invisible_in @attributes, min_visibility remove_invisible_in @constants, min_visibility end ## # Only called when min_visibility == :public or :private def remove_invisible_in array, min_visibility # :nodoc: if min_visibility == :public then array.reject! { |e| e.visibility != :public and not e.force_documentation } else array.reject! { |e| e.visibility == :private and not e.force_documentation } end end ## # Tries to resolve unmatched aliases when a method or attribute has just # been added. def resolve_aliases added # resolve any pending unmatched aliases key = added.pretty_name unmatched_alias_list = @unmatched_alias_lists[key] return unless unmatched_alias_list unmatched_alias_list.each do |unmatched_alias| added.add_alias unmatched_alias, self @external_aliases.delete unmatched_alias end @unmatched_alias_lists.delete key end ## # Returns RDoc::Context::Section objects referenced in this context for use # in a table of contents. def section_contents used_sections = {} each_method do |method| next unless method.display? used_sections[method.section] = true end # order found sections sections = sort_sections.select do |section| used_sections[section] end # only the default section is used return [] if sections.length == 1 and not sections.first.title sections end ## # Sections in this context def sections @sections.values end def sections_hash # :nodoc: @sections end ## # Sets the current section to a section with +title+. See also #add_section def set_current_section title, comment @current_section = add_section title, comment end ## # Given an array +methods+ of method names, set the visibility of each to # +visibility+ def set_visibility_for(methods, visibility, singleton = false) methods_matching methods, singleton do |m| m.visibility = visibility end end ## # Given an array +names+ of constants, set the visibility of each constant to # +visibility+ def set_constant_visibility_for(names, visibility) names.each do |name| constant = @constants_hash[name] or next constant.visibility = visibility end end ## # Sorts sections alphabetically (default) or in TomDoc fashion (none, # Public, Internal, Deprecated) def sort_sections titles = @sections.map { |title, _| title } if titles.length > 1 and TOMDOC_TITLES_SORT == (titles | TOMDOC_TITLES).sort_by { |title| title.to_s } then @sections.values_at(*TOMDOC_TITLES).compact else @sections.sort_by { |title, _| title.to_s }.map { |_, section| section } end end def to_s # :nodoc: "#{self.class.name} #{self.full_name}" end ## # Return the TopLevel that owns us #-- # FIXME we can be 'owned' by several TopLevel (see #record_location & # #in_files) def top_level return @top_level if defined? @top_level @top_level = self @top_level = @top_level.parent until RDoc::TopLevel === @top_level @top_level end ## # Upgrades NormalModule +mod+ in +enclosing+ to a +class_type+ def upgrade_to_class mod, class_type, enclosing enclosing.modules_hash.delete mod.name klass = RDoc::ClassModule.from_module class_type, mod klass.store = @store # if it was there, then we keep it even if done_documenting @store.classes_hash[mod.full_name] = klass enclosing.classes_hash[mod.name] = klass klass end autoload :Section, 'rdoc/context/section' end PK ]FvEE gems/rdoc-6.2.1.1/lib/rdoc/rd.rbnu[# frozen_string_literal: true ## # RDoc::RD implements the RD format from the rdtool gem. # # To choose RD as your only default format see # RDoc::Options@Saved+Options for instructions on setting up a # .doc_options file to store your project default. # # == LICENSE # # The grammar that produces RDoc::RD::BlockParser and RDoc::RD::InlineParser # is included in RDoc under the Ruby License. # # You can find the original source for rdtool at # https://github.com/uwabami/rdtool/ # # You can use, re-distribute or change these files under Ruby's License or GPL. # # 1. You may make and give away verbatim copies of the source form of the # software without restriction, provided that you duplicate all of the # original copyright notices and associated disclaimers. # # 2. You may modify your copy of the software in any way, provided that # you do at least ONE of the following: # # a. place your modifications in the Public Domain or otherwise # make them Freely Available, such as by posting said # modifications to Usenet or an equivalent medium, or by allowing # the author to include your modifications in the software. # # b. use the modified software only within your corporation or # organization. # # c. give non-standard binaries non-standard names, with # instructions on where to get the original software distribution. # # d. make other distribution arrangements with the author. # # 3. You may distribute the software in object code or binary form, # provided that you do at least ONE of the following: # # a. distribute the binaries and library files of the software, # together with instructions (in the manual page or equivalent) # on where to get the original distribution. # # b. accompany the distribution with the machine-readable source of # the software. # # c. give non-standard binaries non-standard names, with # instructions on where to get the original software distribution. # # d. make other distribution arrangements with the author. # # 4. You may modify and include the part of the software into any other # software (possibly commercial). But some files in the distribution # are not written by the author, so that they are not under these terms. # # For the list of those files and their copying conditions, see the # file LEGAL. # # 5. The scripts and library files supplied as input to or produced as # output from the software do not automatically fall under the # copyright of the software, but belong to whomever generated them, # and may be sold commercially, and may be aggregated with this # software. # # 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE. class RDoc::RD ## # Parses +rd+ source and returns an RDoc::Markup::Document. If the # =begin or =end lines are missing they will be added. def self.parse rd rd = rd.lines.to_a if rd.find { |i| /\S/ === i } and !rd.find{|i| /^=begin\b/ === i } then rd.unshift("=begin\n").push("=end\n") end parser = RDoc::RD::BlockParser.new document = parser.parse rd # isn't this always true? document.parts.shift if RDoc::Markup::BlankLine === document.parts.first document.parts.pop if RDoc::Markup::BlankLine === document.parts.last document end autoload :BlockParser, 'rdoc/rd/block_parser' autoload :InlineParser, 'rdoc/rd/inline_parser' autoload :Inline, 'rdoc/rd/inline' end PK ]533$gems/rdoc-6.2.1.1/lib/rdoc/parser.rbnu[# -*- coding: us-ascii -*- # frozen_string_literal: true ## # A parser is simple a class that subclasses RDoc::Parser and implements #scan # to fill in an RDoc::TopLevel with parsed data. # # The initialize method takes an RDoc::TopLevel to fill with parsed content, # the name of the file to be parsed, the content of the file, an RDoc::Options # object and an RDoc::Stats object to inform the user of parsed items. The # scan method is then called to parse the file and must return the # RDoc::TopLevel object. By calling super these items will be set for you. # # In order to be used by RDoc the parser needs to register the file extensions # it can parse. Use ::parse_files_matching to register extensions. # # require 'rdoc' # # class RDoc::Parser::Xyz < RDoc::Parser # parse_files_matching /\.xyz$/ # # def initialize top_level, file_name, content, options, stats # super # # # extra initialization if needed # end # # def scan # # parse file and fill in @top_level # end # end class RDoc::Parser @parsers = [] class << self ## # An Array of arrays that maps file extension (or name) regular # expressions to parser classes that will parse matching filenames. # # Use parse_files_matching to register a parser's file extensions. attr_reader :parsers end ## # The name of the file being parsed attr_reader :file_name ## # Alias an extension to another extension. After this call, files ending # "new_ext" will be parsed using the same parser as "old_ext" def self.alias_extension(old_ext, new_ext) old_ext = old_ext.sub(/^\.(.*)/, '\1') new_ext = new_ext.sub(/^\.(.*)/, '\1') parser = can_parse_by_name "xxx.#{old_ext}" return false unless parser RDoc::Parser.parsers.unshift [/\.#{new_ext}$/, parser] true end ## # Determines if the file is a "binary" file which basically means it has # content that an RDoc parser shouldn't try to consume. def self.binary?(file) return false if file =~ /\.(rdoc|txt)$/ s = File.read(file, 1024) or return false return true if s[0, 2] == Marshal.dump('')[0, 2] or s.index("\x00") mode = 'r:utf-8' # default source encoding has been chagened to utf-8 s.sub!(/\A#!.*\n/, '') # assume shebang line isn't longer than 1024. encoding = s[/^\s*\#\s*(?:-\*-\s*)?(?:en)?coding:\s*([^\s;]+?)(?:-\*-|[\s;])/, 1] mode = "rb:#{encoding}" if encoding s = File.open(file, mode) {|f| f.gets(nil, 1024)} not s.valid_encoding? end ## # Checks if +file+ is a zip file in disguise. Signatures from # http://www.garykessler.net/library/file_sigs.html def self.zip? file zip_signature = File.read file, 4 zip_signature == "PK\x03\x04" or zip_signature == "PK\x05\x06" or zip_signature == "PK\x07\x08" rescue false end ## # Return a parser that can handle a particular extension def self.can_parse file_name parser = can_parse_by_name file_name # HACK Selenium hides a jar file using a .txt extension return if parser == RDoc::Parser::Simple and zip? file_name parser end ## # Returns a parser that can handle the extension for +file_name+. This does # not depend upon the file being readable. def self.can_parse_by_name file_name _, parser = RDoc::Parser.parsers.find { |regexp,| regexp =~ file_name } # The default parser must not parse binary files ext_name = File.extname file_name return parser if ext_name.empty? if parser == RDoc::Parser::Simple and ext_name !~ /txt|rdoc/ then case check_modeline file_name when nil, 'rdoc' then # continue else return nil end end parser rescue Errno::EACCES end ## # Returns the file type from the modeline in +file_name+ def self.check_modeline file_name line = File.open file_name do |io| io.gets end /-\*-\s*(.*?\S)\s*-\*-/ =~ line return nil unless type = $1 if /;/ =~ type then return nil unless /(?:\s|\A)mode:\s*([^\s;]+)/i =~ type type = $1 end return nil if /coding:/i =~ type type.downcase rescue ArgumentError rescue Encoding::InvalidByteSequenceError # invalid byte sequence end ## # Finds and instantiates the correct parser for the given +file_name+ and # +content+. def self.for top_level, file_name, content, options, stats return if binary? file_name parser = use_markup content unless parser then parse_name = file_name # If no extension, look for shebang if file_name !~ /\.\w+$/ && content =~ %r{\A#!(.+)} then shebang = $1 case shebang when %r{env\s+ruby}, %r{/ruby} parse_name = 'dummy.rb' end end parser = can_parse parse_name end return unless parser content = remove_modeline content parser.new top_level, file_name, content, options, stats rescue SystemCallError nil end ## # Record which file types this parser can understand. # # It is ok to call this multiple times. def self.parse_files_matching(regexp) RDoc::Parser.parsers.unshift [regexp, self] end ## # Removes an emacs-style modeline from the first line of the document def self.remove_modeline content content.sub(/\A.*-\*-\s*(.*?\S)\s*-\*-.*\r?\n/, '') end ## # If there is a markup: parser_name comment at the front of the # file, use it to determine the parser. For example: # # # markup: rdoc # # Class comment can go here # # class C # end # # The comment should appear as the first line of the +content+. # # If the content contains a shebang or editor modeline the comment may # appear on the second or third line. # # Any comment style may be used to hide the markup comment. def self.use_markup content markup = content.lines.first(3).grep(/markup:\s+(\w+)/) { $1 }.first return unless markup # TODO Ruby should be returned only when the filename is correct return RDoc::Parser::Ruby if %w[tomdoc markdown].include? markup markup = Regexp.escape markup _, selected = RDoc::Parser.parsers.find do |_, parser| /^#{markup}$/i =~ parser.name.sub(/.*:/, '') end selected end ## # Creates a new Parser storing +top_level+, +file_name+, +content+, # +options+ and +stats+ in instance variables. In +@preprocess+ an # RDoc::Markup::PreProcess object is created which allows processing of # directives. def initialize top_level, file_name, content, options, stats @top_level = top_level @top_level.parser = self.class @store = @top_level.store @file_name = file_name @content = content @options = options @stats = stats @preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include @preprocess.options = @options end autoload :RubyTools, 'rdoc/parser/ruby_tools' autoload :Text, 'rdoc/parser/text' end # simple must come first in order to show up last in the parsers list require 'rdoc/parser/simple' require 'rdoc/parser/c' require 'rdoc/parser/changelog' require 'rdoc/parser/markdown' require 'rdoc/parser/rd' require 'rdoc/parser/ruby' PK ]m|`"gems/rdoc-6.2.1.1/lib/rdoc/i18n.rbnu[# frozen_string_literal: true ## # This module provides i18n related features. module RDoc::I18n autoload :Locale, 'rdoc/i18n/locale' require 'rdoc/i18n/text' end PK ]H"--'gems/rdoc-6.2.1.1/lib/rdoc/top_level.rbnu[# frozen_string_literal: true ## # A TopLevel context is a representation of the contents of a single file class RDoc::TopLevel < RDoc::Context MARSHAL_VERSION = 0 # :nodoc: ## # This TopLevel's File::Stat struct attr_accessor :file_stat ## # Relative name of this file attr_accessor :relative_name ## # Absolute name of this file attr_accessor :absolute_name ## # All the classes or modules that were declared in # this file. These are assigned to either +#classes_hash+ # or +#modules_hash+ once we know what they really are. attr_reader :classes_or_modules attr_accessor :diagram # :nodoc: ## # The parser class that processed this file attr_reader :parser ## # Creates a new TopLevel for the file at +absolute_name+. If documentation # is being generated outside the source dir +relative_name+ is relative to # the source directory. def initialize absolute_name, relative_name = absolute_name super() @name = nil @absolute_name = absolute_name @relative_name = relative_name @file_stat = File.stat(absolute_name) rescue nil # HACK for testing @diagram = nil @parser = nil @classes_or_modules = [] end def parser=(val) @parser = val @store.update_parser_of_file(absolute_name, val) if @store @parser end ## # An RDoc::TopLevel is equal to another with the same relative_name def == other self.class === other and @relative_name == other.relative_name end alias eql? == ## # Adds +an_alias+ to +Object+ instead of +self+. def add_alias(an_alias) object_class.record_location self return an_alias unless @document_self object_class.add_alias an_alias end ## # Adds +constant+ to +Object+ instead of +self+. def add_constant constant object_class.record_location self return constant unless @document_self object_class.add_constant constant end ## # Adds +include+ to +Object+ instead of +self+. def add_include(include) object_class.record_location self return include unless @document_self object_class.add_include include end ## # Adds +method+ to +Object+ instead of +self+. def add_method(method) object_class.record_location self return method unless @document_self object_class.add_method method end ## # Adds class or module +mod+. Used in the building phase # by the Ruby parser. def add_to_classes_or_modules mod @classes_or_modules << mod end ## # Base name of this file def base_name File.basename @relative_name end alias name base_name ## # Only a TopLevel that contains text file) will be displayed. See also # RDoc::CodeObject#display? def display? text? and super end ## # See RDoc::TopLevel::find_class_or_module #-- # TODO Why do we search through all classes/modules found, not just the # ones of this instance? def find_class_or_module name @store.find_class_or_module name end ## # Finds a class or module named +symbol+ def find_local_symbol(symbol) find_class_or_module(symbol) || super end ## # Finds a module or class with +name+ def find_module_named(name) find_class_or_module(name) end ## # Returns the relative name of this file def full_name @relative_name end ## # An RDoc::TopLevel has the same hash as another with the same # relative_name def hash @relative_name.hash end ## # URL for this with a +prefix+ def http_url(prefix) path = [prefix, @relative_name.tr('.', '_')] File.join(*path.compact) + '.html' end def inspect # :nodoc: "#<%s:0x%x %p modules: %p classes: %p>" % [ self.class, object_id, base_name, @modules.map { |n,m| m }, @classes.map { |n,c| c } ] end ## # Time this file was last modified, if known def last_modified @file_stat ? file_stat.mtime : nil end ## # Dumps this TopLevel for use by ri. See also #marshal_load def marshal_dump [ MARSHAL_VERSION, @relative_name, @parser, parse(@comment), ] end ## # Loads this TopLevel from +array+. def marshal_load array # :nodoc: initialize array[1] @parser = array[2] @comment = array[3] @file_stat = nil end ## # Returns the NormalClass "Object", creating it if not found. # # Records +self+ as a location in "Object". def object_class @object_class ||= begin oc = @store.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object') oc.record_location self oc end end ## # Base name of this file without the extension def page_name basename = File.basename @relative_name basename =~ /\.(rb|rdoc|txt|md)$/i $` || basename end ## # Path to this file for use with HTML generator output. def path http_url @store.rdoc.generator.file_dir end def pretty_print q # :nodoc: q.group 2, "[#{self.class}: ", "]" do q.text "base name: #{base_name.inspect}" q.breakable items = @modules.map { |n,m| m } items.concat @modules.map { |n,c| c } q.seplist items do |mod| q.pp mod end end end ## # Search record used by RDoc::Generator::JsonIndex def search_record return unless @parser < RDoc::Parser::Text [ page_name, '', page_name, '', path, '', snippet(@comment), ] end ## # Is this TopLevel from a text file instead of a source code file? def text? @parser and @parser.include? RDoc::Parser::Text end def to_s # :nodoc: "file #{full_name}" end end PK ]󈗢+gems/rdoc-6.2.1.1/lib/rdoc/normal_module.rbnu[# frozen_string_literal: true ## # A normal module, like NormalClass class RDoc::NormalModule < RDoc::ClassModule def aref_prefix # :nodoc: 'module' end def inspect # :nodoc: "#<%s:0x%x module %s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [ self.class, object_id, full_name, @includes, @extends, @attributes, @method_list, @aliases ] end ## # The definition of this module, module MyModuleName def definition "module #{full_name}" end ## # This is a module, returns true def module? true end def pretty_print q # :nodoc: q.group 2, "[module #{full_name}: ", "]" do q.breakable q.text "includes:" q.breakable q.seplist @includes do |inc| q.pp inc end q.breakable q.breakable q.text "constants:" q.breakable q.seplist @constants do |const| q.pp const end q.text "attributes:" q.breakable q.seplist @attributes do |attr| q.pp attr end q.breakable q.text "methods:" q.breakable q.seplist @method_list do |meth| q.pp meth end q.breakable q.text "aliases:" q.breakable q.seplist @aliases do |aliaz| q.pp aliaz end q.breakable q.text "comment:" q.breakable q.pp comment end end ## # Modules don't have one, raises NoMethodError def superclass raise NoMethodError, "#{full_name} is a module" end end PK ]|y*gems/rdoc-6.2.1.1/lib/rdoc/single_class.rbnu[# frozen_string_literal: true ## # A singleton class class RDoc::SingleClass < RDoc::ClassModule ## # Adds the superclass to the included modules. def ancestors superclass ? super + [superclass] : super end def aref_prefix # :nodoc: 'sclass' end ## # The definition of this singleton class, class << MyClassName def definition "class << #{full_name}" end end PK ]Ԣ&&(gems/rdoc-6.2.1.1/lib/rdoc/any_method.rbnu[# frozen_string_literal: true ## # AnyMethod is the base class for objects representing methods class RDoc::AnyMethod < RDoc::MethodAttr ## # 2:: # RDoc 4 # Added calls_super # Added parent name and class # Added section title # 3:: # RDoc 4.1 # Added is_alias_for MARSHAL_VERSION = 3 # :nodoc: ## # Don't rename \#initialize to \::new attr_accessor :dont_rename_initialize ## # The C function that implements this method (if it was defined in a C file) attr_accessor :c_function ## # Different ways to call this method attr_reader :call_seq ## # Parameters for this method attr_accessor :params ## # If true this method uses +super+ to call a superclass version attr_accessor :calls_super include RDoc::TokenStream ## # Creates a new AnyMethod with a token stream +text+ and +name+ def initialize text, name super @c_function = nil @dont_rename_initialize = false @token_stream = nil @calls_super = false @superclass_method = nil end ## # Adds +an_alias+ as an alias for this method in +context+. def add_alias an_alias, context = nil method = self.class.new an_alias.text, an_alias.new_name method.record_location an_alias.file method.singleton = self.singleton method.params = self.params method.visibility = self.visibility method.comment = an_alias.comment method.is_alias_for = self @aliases << method context.add_method method if context method end ## # Prefix for +aref+ is 'method'. def aref_prefix 'method' end ## # The call_seq or the param_seq with method name, if there is no call_seq. # # Use this for displaying a method's argument lists. def arglists if @call_seq then @call_seq elsif @params then "#{name}#{param_seq}" end end ## # Sets the different ways you can call this method. If an empty +call_seq+ # is given nil is assumed. # # See also #param_seq def call_seq= call_seq return if call_seq.empty? @call_seq = call_seq end ## # Loads is_alias_for from the internal name. Returns nil if the alias # cannot be found. def is_alias_for # :nodoc: case @is_alias_for when RDoc::MethodAttr then @is_alias_for when Array then return nil unless @store klass_name, singleton, method_name = @is_alias_for return nil unless klass = @store.find_class_or_module(klass_name) @is_alias_for = klass.find_method method_name, singleton end end ## # Dumps this AnyMethod for use by ri. See also #marshal_load def marshal_dump aliases = @aliases.map do |a| [a.name, parse(a.comment)] end is_alias_for = [ @is_alias_for.parent.full_name, @is_alias_for.singleton, @is_alias_for.name ] if @is_alias_for [ MARSHAL_VERSION, @name, full_name, @singleton, @visibility, parse(@comment), @call_seq, @block_params, aliases, @params, @file.relative_name, @calls_super, @parent.name, @parent.class, @section.title, is_alias_for, ] end ## # Loads this AnyMethod from +array+. For a loaded AnyMethod the following # methods will return cached values: # # * #full_name # * #parent_name def marshal_load array initialize_visibility @dont_rename_initialize = nil @token_stream = nil @aliases = [] @parent = nil @parent_name = nil @parent_class = nil @section = nil @file = nil version = array[0] @name = array[1] @full_name = array[2] @singleton = array[3] @visibility = array[4] @comment = array[5] @call_seq = array[6] @block_params = array[7] # 8 handled below @params = array[9] # 10 handled below @calls_super = array[11] @parent_name = array[12] @parent_title = array[13] @section_title = array[14] @is_alias_for = array[15] array[8].each do |new_name, comment| add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton) end @parent_name ||= if @full_name =~ /#/ then $` else name = @full_name.split('::') name.pop name.join '::' end @file = RDoc::TopLevel.new array[10] if version > 0 end ## # Method name # # If the method has no assigned name, it extracts it from #call_seq. def name return @name if @name @name = @call_seq[/^.*?\.(\w+)/, 1] || @call_seq[/^.*?(\w+)/, 1] || @call_seq if @call_seq end ## # A list of this method's method and yield parameters. +call-seq+ params # are preferred over parsed method and block params. def param_list if @call_seq then params = @call_seq.split("\n").last params = params.sub(/.*?\((.*)\)/, '\1') params = params.sub(/(\{|do)\s*\|([^|]*)\|.*/, ',\2') elsif @params then params = @params.sub(/\((.*)\)/, '\1') params << ",#{@block_params}" if @block_params elsif @block_params then params = @block_params else return [] end if @block_params then # If this method has explicit block parameters, remove any explicit # &block params = params.sub(/,?\s*&\w+/, '') else params = params.sub(/\&(\w+)/, '\1') end params = params.gsub(/\s+/, '').split(',').reject(&:empty?) params.map { |param| param.sub(/=.*/, '') } end ## # Pretty parameter list for this method. If the method's parameters were # given by +call-seq+ it is preferred over the parsed values. def param_seq if @call_seq then params = @call_seq.split("\n").last params = params.sub(/[^( ]+/, '') params = params.sub(/(\|[^|]+\|)\s*\.\.\.\s*(end|\})/, '\1 \2') elsif @params then params = @params.gsub(/\s*\#.*/, '') params = params.tr_s("\n ", " ") params = "(#{params})" unless params[0] == ?( else params = '' end if @block_params then # If this method has explicit block parameters, remove any explicit # &block params = params.sub(/,?\s*&\w+/, '') block = @block_params.tr_s("\n ", " ") if block[0] == ?( block = block.sub(/^\(/, '').sub(/\)/, '') end params << " { |#{block}| ... }" end params end ## # Sets the store for this method and its referenced code objects. def store= store super @file = @store.add_file @file.full_name if @file end ## # For methods that +super+, find the superclass method that would be called. def superclass_method return unless @calls_super return @superclass_method if @superclass_method parent.each_ancestor do |ancestor| if method = ancestor.method_list.find { |m| m.name == @name } then @superclass_method = method break end end @superclass_method end end PK ]c7%gems/rdoc-6.2.1.1/lib/rdoc/comment.rbnu[# frozen_string_literal: true ## # A comment holds the text comment for a RDoc::CodeObject and provides a # unified way of cleaning it up and parsing it into an RDoc::Markup::Document. # # Each comment may have a different markup format set by #format=. By default # 'rdoc' is used. The :markup: directive tells RDoc which format to use. # # See RDoc::Markup@Other+directives for instructions on adding an alternate # format. class RDoc::Comment include RDoc::Text ## # The format of this comment. Defaults to RDoc::Markup attr_reader :format ## # The RDoc::TopLevel this comment was found in attr_accessor :location ## # Line where this Comment was written attr_accessor :line ## # For duck-typing when merging classes at load time alias file location # :nodoc: ## # The text for this comment attr_reader :text ## # Alias for text alias to_s text ## # Overrides the content returned by #parse. Use when there is no #text # source for this comment attr_writer :document ## # Creates a new comment with +text+ that is found in the RDoc::TopLevel # +location+. def initialize text = nil, location = nil, language = nil @location = location @text = text.nil? ? nil : text.dup @language = language @document = nil @format = 'rdoc' @normalized = false end ## #-- # TODO deep copy @document def initialize_copy copy # :nodoc: @text = copy.text.dup end def == other # :nodoc: self.class === other and other.text == @text and other.location == @location end ## # Look for a 'call-seq' in the comment to override the normal parameter # handling. The :call-seq: is indented from the baseline. All lines of the # same indentation level and prefix are consumed. # # For example, all of the following will be used as the :call-seq: # # # :call-seq: # # ARGF.readlines(sep=$/) -> array # # ARGF.readlines(limit) -> array # # ARGF.readlines(sep, limit) -> array # # # # ARGF.to_a(sep=$/) -> array # # ARGF.to_a(limit) -> array # # ARGF.to_a(sep, limit) -> array def extract_call_seq method # we must handle situations like the above followed by an unindented first # comment. The difficulty is to make sure not to match lines starting # with ARGF at the same indent, but that are after the first description # paragraph. if @text =~ /^\s*:?call-seq:(.*?(?:\S).*?)^\s*$/m then all_start, all_stop = $~.offset(0) seq_start, seq_stop = $~.offset(1) # we get the following lines that start with the leading word at the # same indent, even if they have blank lines before if $1 =~ /(^\s*\n)+^(\s*\w+)/m then leading = $2 # ' * ARGF' in the example above re = %r% \A( (^\s*\n)+ (^#{Regexp.escape leading}.*?\n)+ )+ ^\s*$ %xm if @text[seq_stop..-1] =~ re then all_stop = seq_stop + $~.offset(0).last seq_stop = seq_stop + $~.offset(1).last end end seq = @text[seq_start..seq_stop] seq.gsub!(/^\s*(\S|\n)/m, '\1') @text.slice! all_start...all_stop method.call_seq = seq.chomp else regexp = /^\s*:?call-seq:(.*?)(^\s*$|\z)/m if regexp =~ @text then @text = @text.sub(regexp, '') seq = $1 seq.gsub!(/^\s*/, '') method.call_seq = seq end end method end ## # A comment is empty if its text String is empty. def empty? @text.empty? end ## # HACK dubious def encode! encoding # TODO: Remove this condition after Ruby 2.2 EOL if RUBY_VERSION < '2.3.0' @text = @text.force_encoding encoding else @text = String.new @text, encoding: encoding end self end ## # Sets the format of this comment and resets any parsed document def format= format @format = format @document = nil end def inspect # :nodoc: location = @location ? @location.relative_name : '(unknown)' "#<%s:%x %s %p>" % [self.class, object_id, location, @text] end ## # Normalizes the text. See RDoc::Text#normalize_comment for details def normalize return self unless @text return self if @normalized # TODO eliminate duplicate normalization @text = normalize_comment @text @normalized = true self end ## # Was this text normalized? def normalized? # :nodoc: @normalized end ## # Parses the comment into an RDoc::Markup::Document. The parsed document is # cached until the text is changed. def parse return @document if @document @document = super @text, @format @document.file = @location @document end ## # Removes private sections from this comment. Private sections are flush to # the comment marker and start with -- and end with ++. # For C-style comments, a private marker may not start at the opening of the # comment. # # /* # *-- # * private # *++ # * public # */ def remove_private # Workaround for gsub encoding for Ruby 1.9.2 and earlier empty = '' empty = RDoc::Encoding.change_encoding empty, @text.encoding @text = @text.gsub(%r%^\s*([#*]?)--.*?^\s*(\1)\+\+\n?%m, empty) @text = @text.sub(%r%^\s*[#*]?--.*%m, '') end ## # Replaces this comment's text with +text+ and resets the parsed document. # # An error is raised if the comment contains a document but no text. def text= text raise RDoc::Error, 'replacing document-only comment is not allowed' if @text.nil? and @document @document = nil @text = text.nil? ? nil : text.dup end ## # Returns true if this comment is in TomDoc format. def tomdoc? @format == 'tomdoc' end end PK ]VU} } +gems/rdoc-6.2.1.1/lib/rdoc/known_classes.rbnu[# frozen_string_literal: true module RDoc ## # Ruby's built-in classes, modules and exceptions KNOWN_CLASSES = { "rb_cArray" => "Array", "rb_cBasicObject" => "BasicObject", "rb_cBignum" => "Bignum", "rb_cClass" => "Class", "rb_cData" => "Data", "rb_cDir" => "Dir", "rb_cEncoding" => "Encoding", "rb_cFalseClass" => "FalseClass", "rb_cFile" => "File", "rb_cFixnum" => "Fixnum", "rb_cFloat" => "Float", "rb_cHash" => "Hash", "rb_cIO" => "IO", "rb_cInteger" => "Integer", "rb_cModule" => "Module", "rb_cNilClass" => "NilClass", "rb_cNumeric" => "Numeric", "rb_cObject" => "Object", "rb_cProc" => "Proc", "rb_cRange" => "Range", "rb_cRegexp" => "Regexp", "rb_cRubyVM" => "RubyVM", "rb_cSocket" => "Socket", "rb_cString" => "String", "rb_cStruct" => "Struct", "rb_cSymbol" => "Symbol", "rb_cThread" => "Thread", "rb_cTime" => "Time", "rb_cTrueClass" => "TrueClass", "rb_eArgError" => "ArgError", "rb_eEOFError" => "EOFError", "rb_eException" => "Exception", "rb_eFatal" => "fatal", "rb_eFloatDomainError" => "FloatDomainError", "rb_eIOError" => "IOError", "rb_eIndexError" => "IndexError", "rb_eInterrupt" => "Interrupt", "rb_eLoadError" => "LoadError", "rb_eNameError" => "NameError", "rb_eNoMemError" => "NoMemError", "rb_eNotImpError" => "NotImpError", "rb_eRangeError" => "RangeError", "rb_eRuntimeError" => "RuntimeError", "rb_eScriptError" => "ScriptError", "rb_eSecurityError" => "SecurityError", "rb_eSignal" => "SignalException", "rb_eStandardError" => "StandardError", "rb_eSyntaxError" => "SyntaxError", "rb_eSystemCallError" => "SystemCallError", "rb_eSystemExit" => "SystemExit", "rb_eTypeError" => "TypeError", "rb_eZeroDivError" => "ZeroDivError", "rb_mComparable" => "Comparable", "rb_mEnumerable" => "Enumerable", "rb_mErrno" => "Errno", "rb_mFConst" => "File::Constants", "rb_mFileTest" => "FileTest", "rb_mGC" => "GC", "rb_mKernel" => "Kernel", "rb_mMath" => "Math", "rb_mProcess" => "Process" } end PK ]HLf*q0q0%gems/rdoc-6.2.1.1/lib/rdoc/servlet.rbnu[# frozen_string_literal: true require 'rdoc' require 'erb' require 'time' require 'json' require 'webrick' ## # This is a WEBrick servlet that allows you to browse ri documentation. # # You can show documentation through either `ri --server` or, with RubyGems # 2.0 or newer, `gem server`. For ri, the server runs on port 8214 by # default. For RubyGems the server runs on port 8808 by default. # # You can use this servlet in your own project by mounting it on a WEBrick # server: # # require 'webrick' # # server = WEBrick::HTTPServer.new Port: 8000 # # server.mount '/', RDoc::Servlet # # If you want to mount the servlet some other place than the root, provide the # base path when mounting: # # server.mount '/rdoc', RDoc::Servlet, '/rdoc' class RDoc::Servlet < WEBrick::HTTPServlet::AbstractServlet @server_stores = Hash.new { |hash, server| hash[server] = {} } @cache = Hash.new { |hash, store| hash[store] = {} } ## # Maps an asset type to its path on the filesystem attr_reader :asset_dirs ## # An RDoc::Options instance used for rendering options attr_reader :options ## # Creates an instance of this servlet that shares cached data between # requests. def self.get_instance server, *options # :nodoc: stores = @server_stores[server] new server, stores, @cache, *options end ## # Creates a new WEBrick servlet. # # Use +mount_path+ when mounting the servlet somewhere other than /. # # Use +extra_doc_dirs+ for additional documentation directories. # # +server+ is provided automatically by WEBrick when mounting. +stores+ and # +cache+ are provided automatically by the servlet. def initialize server, stores, cache, mount_path = nil, extra_doc_dirs = [] super server @cache = cache @mount_path = mount_path @extra_doc_dirs = extra_doc_dirs @stores = stores @options = RDoc::Options.new @options.op_dir = '.' darkfish_dir = nil # HACK dup $LOAD_PATH.each do |path| darkfish_dir = File.join path, 'rdoc/generator/template/darkfish/' next unless File.directory? darkfish_dir @options.template_dir = darkfish_dir break end @asset_dirs = { :darkfish => darkfish_dir, :json_index => File.expand_path('../generator/template/json_index/', __FILE__), } end ## # Serves the asset at the path in +req+ for +generator_name+ via +res+. def asset generator_name, req, res asset_dir = @asset_dirs[generator_name] asset_path = File.join asset_dir, req.path if_modified_since req, res, asset_path res.body = File.read asset_path res.content_type = case req.path when /\.css\z/ then 'text/css' when /\.js\z/ then 'application/javascript' else 'application/octet-stream' end end ## # GET request entry point. Fills in +res+ for the path, etc. in +req+. def do_GET req, res req.path.sub!(/\A#{Regexp.escape @mount_path}/, '') if @mount_path case req.path when '/' then root req, res when '/js/darkfish.js', '/js/jquery.js', '/js/search.js', %r%^/css/%, %r%^/images/%, %r%^/fonts/% then asset :darkfish, req, res when '/js/navigation.js', '/js/searcher.js' then asset :json_index, req, res when '/js/search_index.js' then root_search req, res else show_documentation req, res end rescue WEBrick::HTTPStatus::NotFound => e generator = generator_for RDoc::Store.new not_found generator, req, res, e.message rescue WEBrick::HTTPStatus::Status raise rescue => e error e, req, res end ## # Fills in +res+ with the class, module or page for +req+ from +store+. # # +path+ is relative to the mount_path and is used to determine the class, # module or page name (/RDoc/Servlet.html becomes RDoc::Servlet). # +generator+ is used to create the page. def documentation_page store, generator, path, req, res text_name = path.chomp '.html' name = text_name.gsub '/', '::' if klass = store.find_class_or_module(name) then res.body = generator.generate_class klass elsif page = store.find_text_page(name.sub(/_([^_]*)\z/, '.\1')) then res.body = generator.generate_page page elsif page = store.find_text_page(text_name.sub(/_([^_]*)\z/, '.\1')) then res.body = generator.generate_page page else not_found generator, req, res end end ## # Creates the JSON search index on +res+ for the given +store+. +generator+ # must respond to \#json_index to build. +req+ is ignored. def documentation_search store, generator, req, res json_index = @cache[store].fetch :json_index do @cache[store][:json_index] = JSON.dump generator.json_index.build_index end res.content_type = 'application/javascript' res.body = "var search_data = #{json_index}" end ## # Returns the RDoc::Store and path relative to +mount_path+ for # documentation at +path+. def documentation_source path _, source_name, path = path.split '/', 3 store = @stores[source_name] return store, path if store store = store_for source_name store.load_all @stores[source_name] = store return store, path end ## # Generates an error page for the +exception+ while handling +req+ on +res+. def error exception, req, res backtrace = exception.backtrace.join "\n" res.content_type = 'text/html' res.status = 500 res.body = <<-BODY Error - #{ERB::Util.html_escape exception.class}

Error

While processing #{ERB::Util.html_escape req.request_uri} the RDoc (#{ERB::Util.html_escape RDoc::VERSION}) server has encountered a #{ERB::Util.html_escape exception.class} exception:

#{ERB::Util.html_escape exception.message}

Please report this to the RDoc issues tracker. Please include the RDoc version, the URI above and exception class, message and backtrace. If you're viewing a gem's documentation, include the gem name and version. If you're viewing Ruby's documentation, include the version of ruby.

Backtrace:

#{ERB::Util.html_escape backtrace}
BODY end ## # Instantiates a Darkfish generator for +store+ def generator_for store generator = RDoc::Generator::Darkfish.new store, @options generator.file_output = false generator.asset_rel_path = '..' rdoc = RDoc::RDoc.new rdoc.store = store rdoc.generator = generator rdoc.options = @options @options.main_page = store.main @options.title = store.title generator end ## # Handles the If-Modified-Since HTTP header on +req+ for +path+. If the # file has not been modified a Not Modified response is returned. If the # file has been modified a Last-Modified header is added to +res+. def if_modified_since req, res, path = nil last_modified = File.stat(path).mtime if path res['last-modified'] = last_modified.httpdate return unless ims = req['if-modified-since'] ims = Time.parse ims unless ims < last_modified then res.body = '' raise WEBrick::HTTPStatus::NotModified end end ## # Returns an Array of installed documentation. # # Each entry contains the documentation name (gem name, 'Ruby # Documentation', etc.), the path relative to the mount point, whether the # documentation exists, the type of documentation (See RDoc::RI::Paths#each) # and the filesystem to the RDoc::Store for the documentation. def installed_docs extra_counter = 0 ri_paths.map do |path, type| store = RDoc::Store.new path, type exists = File.exist? store.cache_path case type when :gem then gem_path = path[%r%/([^/]*)/ri$%, 1] [gem_path, "#{gem_path}/", exists, type, path] when :system then ['Ruby Documentation', 'ruby/', exists, type, path] when :site then ['Site Documentation', 'site/', exists, type, path] when :home then ['Home Documentation', 'home/', exists, type, path] when :extra then extra_counter += 1 store.load_cache if exists title = store.title || "Extra Documentation" [title, "extra-#{extra_counter}/", exists, type, path] end end end ## # Returns a 404 page built by +generator+ for +req+ on +res+. def not_found generator, req, res, message = nil message ||= "The page #{ERB::Util.h req.path} was not found" res.body = generator.generate_servlet_not_found message res.status = 404 end ## # Enumerates the ri paths. See RDoc::RI::Paths#each def ri_paths &block RDoc::RI::Paths.each true, true, true, :all, *@extra_doc_dirs, &block #TODO: pass extra_dirs end ## # Generates the root page on +res+. +req+ is ignored. def root req, res generator = RDoc::Generator::Darkfish.new nil, @options res.body = generator.generate_servlet_root installed_docs res.content_type = 'text/html' end ## # Generates a search index for the root page on +res+. +req+ is ignored. def root_search req, res search_index = [] info = [] installed_docs.map do |name, href, exists, type, path| next unless exists search_index << name case type when :gem gemspec = path.gsub(%r%/doc/([^/]*?)/ri$%, '/specifications/\1.gemspec') spec = Gem::Specification.load gemspec path = spec.full_name comment = spec.summary when :system then path = 'ruby' comment = 'Documentation for the Ruby standard library' when :site then path = 'site' comment = 'Documentation for non-gem libraries' when :home then path = 'home' comment = 'Documentation from your home directory' when :extra comment = name end info << [name, '', path, '', comment] end index = { :index => { :searchIndex => search_index, :longSearchIndex => search_index, :info => info, } } res.body = "var search_data = #{JSON.dump index};" res.content_type = 'application/javascript' end ## # Displays documentation for +req+ on +res+, whether that be HTML or some # asset. def show_documentation req, res store, path = documentation_source req.path if_modified_since req, res, store.cache_path generator = generator_for store case path when nil, '', 'index.html' then res.body = generator.generate_index when 'table_of_contents.html' then res.body = generator.generate_table_of_contents when 'js/search_index.js' then documentation_search store, generator, req, res else documentation_page store, generator, path, req, res end ensure res.content_type ||= 'text/html' end ## # Returns an RDoc::Store for the given +source_name+ ('ruby' or a gem name). def store_for source_name case source_name when 'home' then RDoc::Store.new RDoc::RI::Paths.home_dir, :home when 'ruby' then RDoc::Store.new RDoc::RI::Paths.system_dir, :system when 'site' then RDoc::Store.new RDoc::RI::Paths.site_dir, :site when /\Aextra-(\d+)\z/ then index = $1.to_i - 1 ri_dir = installed_docs[index][4] RDoc::Store.new ri_dir, :extra else ri_dir, type = ri_paths.find do |dir, dir_type| next unless dir_type == :gem source_name == dir[%r%/([^/]*)/ri$%, 1] end raise WEBrick::HTTPStatus::NotFound, "Could not find gem \"#{ERB::Util.html_escape(source_name)}\". Are you sure you installed it?" unless ri_dir store = RDoc::Store.new ri_dir, type return store if File.exist? store.cache_path raise WEBrick::HTTPStatus::NotFound, "Could not find documentation for \"#{ERB::Util.html_escape(source_name)}\". Please run `gem rdoc --ri gem_name`" end end end PK ]58)gems/rdoc-6.2.1.1/lib/rdoc/erb_partial.rbnu[# frozen_string_literal: true ## # Allows an ERB template to be rendered in the context (binding) of an # existing ERB template evaluation. class RDoc::ERBPartial < ERB ## # Overrides +compiler+ startup to set the +eoutvar+ to an empty string only # if it isn't already set. def set_eoutvar compiler, eoutvar = '_erbout' super compiler.pre_cmd = ["#{eoutvar} ||= ''"] end end PK ]p-}}#gems/rdoc-6.2.1.1/lib/rdoc/alias.rbnu[# frozen_string_literal: true ## # Represent an alias, which is an old_name/new_name pair associated with a # particular context #-- # TODO implement Alias as a proxy to a method/attribute, inheriting from # MethodAttr class RDoc::Alias < RDoc::CodeObject ## # Aliased method's name attr_reader :new_name alias name new_name ## # Aliasee method's name attr_reader :old_name ## # Is this an alias declared in a singleton context? attr_accessor :singleton ## # Source file token stream attr_reader :text ## # Creates a new Alias with a token stream of +text+ that aliases +old_name+ # to +new_name+, has +comment+ and is a +singleton+ context. def initialize(text, old_name, new_name, comment, singleton = false) super() @text = text @singleton = singleton @old_name = old_name @new_name = new_name self.comment = comment end ## # Order by #singleton then #new_name def <=>(other) [@singleton ? 0 : 1, new_name] <=> [other.singleton ? 0 : 1, other.new_name] end ## # HTML fragment reference for this alias def aref type = singleton ? 'c' : 'i' "#alias-#{type}-#{html_name}" end ## # Full old name including namespace def full_old_name @full_name || "#{parent.name}#{pretty_old_name}" end ## # HTML id-friendly version of +#new_name+. def html_name CGI.escape(@new_name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '') end def inspect # :nodoc: parent_name = parent ? parent.name : '(unknown)' "#<%s:0x%x %s.alias_method %s, %s>" % [ self.class, object_id, parent_name, @old_name, @new_name, ] end ## # '::' for the alias of a singleton method/attribute, '#' for instance-level. def name_prefix singleton ? '::' : '#' end ## # Old name with prefix '::' or '#'. def pretty_old_name "#{singleton ? '::' : '#'}#{@old_name}" end ## # New name with prefix '::' or '#'. def pretty_new_name "#{singleton ? '::' : '#'}#{@new_name}" end alias pretty_name pretty_new_name def to_s # :nodoc: "alias: #{self.new_name} -> #{self.pretty_old_name} in: #{parent}" end end PK ]epC0)gems/rdoc-6.2.1.1/lib/rdoc/meta_method.rbnu[# frozen_string_literal: true ## # MetaMethod represents a meta-programmed method class RDoc::MetaMethod < RDoc::AnyMethod end PK ]/%gems/rdoc-6.2.1.1/lib/rdoc/include.rbnu[# frozen_string_literal: true ## # A Module included in a class with \#include # # RDoc::Include.new 'Enumerable', 'comment ...' class RDoc::Include < RDoc::Mixin end PK ]oc#gems/rdoc-6.2.1.1/lib/rdoc/erbio.rbnu[# frozen_string_literal: true require 'erb' ## # A subclass of ERB that writes directly to an IO. Credit to Aaron Patterson # and Masatoshi SEKI. # # To use: # # erbio = RDoc::ERBIO.new '<%= "hello world" %>', nil, nil # # File.open 'hello.txt', 'w' do |io| # erbio.result binding # end # # Note that binding must enclose the io you wish to output on. class RDoc::ERBIO < ERB ## # Defaults +eoutvar+ to 'io', otherwise is identical to ERB's initialize def initialize str, safe_level = nil, trim_mode = nil, eoutvar = 'io' if RUBY_VERSION >= '2.6' super(str, trim_mode: trim_mode, eoutvar: eoutvar) else super end end ## # Instructs +compiler+ how to write to +io_variable+ def set_eoutvar compiler, io_variable compiler.put_cmd = "#{io_variable}.write" compiler.insert_cmd = "#{io_variable}.write" compiler.pre_cmd = [] compiler.post_cmd = [] end end PK ]&“%gems/rdoc-6.2.1.1/lib/rdoc/require.rbnu[# frozen_string_literal: true ## # A file loaded by \#require class RDoc::Require < RDoc::CodeObject ## # Name of the required file attr_accessor :name ## # Creates a new Require that loads +name+ with +comment+ def initialize(name, comment) super() @name = name.gsub(/'|"/, "") #' @top_level = nil self.comment = comment end def inspect # :nodoc: "#<%s:0x%x require '%s' in %s>" % [ self.class, object_id, @name, parent_file_name, ] end def to_s # :nodoc: "require #{name} in: #{parent}" end ## # The RDoc::TopLevel corresponding to this require, or +nil+ if not found. def top_level @top_level ||= begin tl = RDoc::TopLevel.all_files_hash[name + '.rb'] if tl.nil? and RDoc::TopLevel.all_files.first.full_name =~ %r(^lib/) then # second chance tl = RDoc::TopLevel.all_files_hash['lib/' + name + '.rb'] end tl end end end PK ]W,*gems/rdoc-6.2.1.1/lib/rdoc/normal_class.rbnu[# frozen_string_literal: true ## # A normal class, neither singleton nor anonymous class RDoc::NormalClass < RDoc::ClassModule ## # The ancestors of this class including modules. Unlike Module#ancestors, # this class is not included in the result. The result will contain both # RDoc::ClassModules and Strings. def ancestors if String === superclass then super << superclass elsif superclass then ancestors = super ancestors << superclass ancestors.concat superclass.ancestors else super end end def aref_prefix # :nodoc: 'class' end ## # The definition of this class, class MyClassName def definition "class #{full_name}" end def direct_ancestors superclass ? super + [superclass] : super end def inspect # :nodoc: superclass = @superclass ? " < #{@superclass}" : nil "<%s:0x%x class %s%s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [ self.class, object_id, full_name, superclass, @includes, @extends, @attributes, @method_list, @aliases ] end def to_s # :nodoc: display = "#{self.class.name} #{self.full_name}" if superclass display += ' < ' + (superclass.is_a?(String) ? superclass : superclass.full_name) end display += ' -> ' + is_alias_for.to_s if is_alias_for display end def pretty_print q # :nodoc: superclass = @superclass ? " < #{@superclass}" : nil q.group 2, "[class #{full_name}#{superclass} ", "]" do q.breakable q.text "includes:" q.breakable q.seplist @includes do |inc| q.pp inc end q.breakable q.text "constants:" q.breakable q.seplist @constants do |const| q.pp const end q.breakable q.text "attributes:" q.breakable q.seplist @attributes do |attr| q.pp attr end q.breakable q.text "methods:" q.breakable q.seplist @method_list do |meth| q.pp meth end q.breakable q.text "aliases:" q.breakable q.seplist @aliases do |aliaz| q.pp aliaz end q.breakable q.text "comment:" q.breakable q.pp comment end end end PK ]- % %)gems/rdoc-6.2.1.1/lib/rdoc/code_object.rbnu[# frozen_string_literal: true ## # Base class for the RDoc code tree. # # We contain the common stuff for contexts (which are containers) and other # elements (methods, attributes and so on) # # Here's the tree of the CodeObject subclasses: # # * RDoc::Context # * RDoc::TopLevel # * RDoc::ClassModule # * RDoc::AnonClass (never used so far) # * RDoc::NormalClass # * RDoc::NormalModule # * RDoc::SingleClass # * RDoc::MethodAttr # * RDoc::Attr # * RDoc::AnyMethod # * RDoc::GhostMethod # * RDoc::MetaMethod # * RDoc::Alias # * RDoc::Constant # * RDoc::Mixin # * RDoc::Require # * RDoc::Include class RDoc::CodeObject include RDoc::Text ## # Our comment attr_reader :comment ## # Do we document our children? attr_reader :document_children ## # Do we document ourselves? attr_reader :document_self ## # Are we done documenting (ie, did we come across a :enddoc:)? attr_reader :done_documenting ## # Which file this code object was defined in attr_reader :file ## # Force documentation of this CodeObject attr_reader :force_documentation ## # Line in #file where this CodeObject was defined attr_accessor :line ## # Hash of arbitrary metadata for this CodeObject attr_reader :metadata ## # Sets the parent CodeObject attr_writer :parent ## # Did we ever receive a +:nodoc:+ directive? attr_reader :received_nodoc ## # Set the section this CodeObject is in attr_writer :section ## # The RDoc::Store for this object. attr_reader :store ## # We are the model of the code, but we know that at some point we will be # worked on by viewers. By implementing the Viewable protocol, viewers can # associated themselves with these objects. attr_accessor :viewer ## # Creates a new CodeObject that will document itself and its children def initialize @metadata = {} @comment = '' @parent = nil @parent_name = nil # for loading @parent_class = nil # for loading @section = nil @section_title = nil # for loading @file = nil @full_name = nil @store = nil @track_visibility = true initialize_visibility end ## # Initializes state for visibility of this CodeObject and its children. def initialize_visibility # :nodoc: @document_children = true @document_self = true @done_documenting = false @force_documentation = false @received_nodoc = false @ignored = false @suppressed = false @track_visibility = true end ## # Replaces our comment with +comment+, unless it is empty. def comment=(comment) @comment = case comment when NilClass then '' when RDoc::Markup::Document then comment when RDoc::Comment then comment.normalize else if comment and not comment.empty? then normalize_comment comment else # HACK correct fix is to have #initialize create @comment # with the correct encoding if String === @comment and @comment.empty? then @comment = RDoc::Encoding.change_encoding @comment, comment.encoding end @comment end end end ## # Should this CodeObject be displayed in output? # # A code object should be displayed if: # # * The item didn't have a nodoc or wasn't in a container that had nodoc # * The item wasn't ignored # * The item has documentation and was not suppressed def display? @document_self and not @ignored and (documented? or not @suppressed) end ## # Enables or disables documentation of this CodeObject's children unless it # has been turned off by :enddoc: def document_children=(document_children) return unless @track_visibility @document_children = document_children unless @done_documenting end ## # Enables or disables documentation of this CodeObject unless it has been # turned off by :enddoc:. If the argument is +nil+ it means the # documentation is turned off by +:nodoc:+. def document_self=(document_self) return unless @track_visibility return if @done_documenting @document_self = document_self @received_nodoc = true if document_self.nil? end ## # Does this object have a comment with content or is #received_nodoc true? def documented? @received_nodoc or !@comment.empty? end ## # Turns documentation on/off, and turns on/off #document_self # and #document_children. # # Once documentation has been turned off (by +:enddoc:+), # the object will refuse to turn #document_self or # #document_children on, so +:doc:+ and +:start_doc:+ directives # will have no effect in the current file. def done_documenting=(value) return unless @track_visibility @done_documenting = value @document_self = !value @document_children = @document_self end ## # Yields each parent of this CodeObject. See also # RDoc::ClassModule#each_ancestor def each_parent code_object = self while code_object = code_object.parent do yield code_object end self end ## # File name where this CodeObject was found. # # See also RDoc::Context#in_files def file_name return unless @file @file.absolute_name end ## # Force the documentation of this object unless documentation # has been turned off by :enddoc: #-- # HACK untested, was assigning to an ivar def force_documentation=(value) @force_documentation = value unless @done_documenting end ## # Sets the full_name overriding any computed full name. # # Set to +nil+ to clear RDoc's cached value def full_name= full_name @full_name = full_name end ## # Use this to ignore a CodeObject and all its children until found again # (#record_location is called). An ignored item will not be displayed in # documentation. # # See github issue #55 # # The ignored status is temporary in order to allow implementation details # to be hidden. At the end of processing a file RDoc allows all classes # and modules to add new documentation to previously created classes. # # If a class was ignored (via stopdoc) then reopened later with additional # documentation it should be displayed. If a class was ignored and never # reopened it should not be displayed. The ignore flag allows this to # occur. def ignore return unless @track_visibility @ignored = true stop_doc end ## # Has this class been ignored? # # See also #ignore def ignored? @ignored end ## # The options instance from the store this CodeObject is attached to, or a # default options instance if the CodeObject is not attached. # # This is used by Text#snippet def options if @store and @store.rdoc then @store.rdoc.options else RDoc::Options.new end end ## # Our parent CodeObject. The parent may be missing for classes loaded from # legacy RI data stores. def parent return @parent if @parent return nil unless @parent_name if @parent_class == RDoc::TopLevel then @parent = @store.add_file @parent_name else @parent = @store.find_class_or_module @parent_name return @parent if @parent begin @parent = @store.load_class @parent_name rescue RDoc::Store::MissingFileError nil end end end ## # File name of our parent def parent_file_name @parent ? @parent.base_name : '(unknown)' end ## # Name of our parent def parent_name @parent ? @parent.full_name : '(unknown)' end ## # Records the RDoc::TopLevel (file) where this code object was defined def record_location top_level @ignored = false @suppressed = false @file = top_level end ## # The section this CodeObject is in. Sections allow grouping of constants, # attributes and methods inside a class or module. def section return @section if @section @section = parent.add_section @section_title if parent end ## # Enable capture of documentation unless documentation has been # turned off by :enddoc: def start_doc return if @done_documenting @document_self = true @document_children = true @ignored = false @suppressed = false end ## # Disable capture of documentation def stop_doc return unless @track_visibility @document_self = false @document_children = false end ## # Sets the +store+ that contains this CodeObject def store= store @store = store return unless @track_visibility if :nodoc == options.visibility then initialize_visibility @track_visibility = false end end ## # Use this to suppress a CodeObject and all its children until the next file # it is seen in or documentation is discovered. A suppressed item with # documentation will be displayed while an ignored item with documentation # may not be displayed. def suppress return unless @track_visibility @suppressed = true stop_doc end ## # Has this class been suppressed? # # See also #suppress def suppressed? @suppressed end end PK ]#SpSp$gems/rdoc-6.2.1.1/lib/rdoc/markup.rbnu[# frozen_string_literal: true ## # RDoc::Markup parses plain text documents and attempts to decompose them into # their constituent parts. Some of these parts are high-level: paragraphs, # chunks of verbatim text, list entries and the like. Other parts happen at # the character level: a piece of bold text, a word in code font. This markup # is similar in spirit to that used on WikiWiki webs, where folks create web # pages using a simple set of formatting rules. # # RDoc::Markup and other markup formats do no output formatting, this is # handled by the RDoc::Markup::Formatter subclasses. # # = Supported Formats # # Besides the RDoc::Markup format, the following formats are built in to RDoc: # # markdown:: # The markdown format as described by # http://daringfireball.net/projects/markdown/. See RDoc::Markdown for # details on the parser and supported extensions. # rd:: # The rdtool format. See RDoc::RD for details on the parser and format. # tomdoc:: # The TomDoc format as described by http://tomdoc.org/. See RDoc::TomDoc # for details on the parser and supported extensions. # # You can choose a markup format using the following methods: # # per project:: # If you build your documentation with rake use RDoc::Task#markup. # # If you build your documentation by hand run: # # rdoc --markup your_favorite_format --write-options # # and commit .rdoc_options and ship it with your packaged gem. # per file:: # At the top of the file use the :markup: directive to set the # default format for the rest of the file. # per comment:: # Use the :markup: directive at the top of a comment you want # to write in a different format. # # = RDoc::Markup # # RDoc::Markup is extensible at runtime: you can add \new markup elements to # be recognized in the documents that RDoc::Markup parses. # # RDoc::Markup is intended to be the basis for a family of tools which share # the common requirement that simple, plain-text should be rendered in a # variety of different output formats and media. It is envisaged that # RDoc::Markup could be the basis for formatting RDoc style comment blocks, # Wiki entries, and online FAQs. # # == Synopsis # # This code converts +input_string+ to HTML. The conversion takes place in # the +convert+ method, so you can use the same RDoc::Markup converter to # convert multiple input strings. # # require 'rdoc' # # h = RDoc::Markup::ToHtml.new(RDoc::Options.new) # # puts h.convert(input_string) # # You can extend the RDoc::Markup parser to recognize new markup # sequences, and to add regexp handling. Here we make WikiWords significant to # the parser, and also make the sequences {word} and \text... signify # strike-through text. We then subclass the HTML output class to deal # with these: # # require 'rdoc' # # class WikiHtml < RDoc::Markup::ToHtml # def handle_regexp_WIKIWORD(target) # "" + target.text + "" # end # end # # markup = RDoc::Markup.new # markup.add_word_pair("{", "}", :STRIKE) # markup.add_html("no", :STRIKE) # # markup.add_regexp_handling(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # wh = WikiHtml.new RDoc::Options.new, markup # wh.add_tag(:STRIKE, "", "") # # puts "#{wh.convert ARGF.read}" # # == Encoding # # Where Encoding support is available, RDoc will automatically convert all # documents to the same output encoding. The output encoding can be set via # RDoc::Options#encoding and defaults to Encoding.default_external. # # = \RDoc Markup Reference # # == Block Markup # # === Paragraphs and Verbatim # # The markup engine looks for a document's natural left margin. This is # used as the initial margin for the document. # # Consecutive lines starting at this margin are considered to be a # paragraph. Empty lines separate paragraphs. # # Any line that starts to the right of the current margin is treated # as verbatim text. This is useful for code listings: # # 3.times { puts "Ruby" } # # In verbatim text, two or more blank lines are collapsed into one, # and trailing blank lines are removed: # # This is the first line # # # This is the second non-blank line, # after 2 blank lines in the source markup. # # # There were two trailing blank lines right above this paragraph, that # have been removed. In addition, the verbatim text has been shifted # left, so the amount of indentation of verbatim text is unimportant. # # For HTML output RDoc makes a small effort to determine if a verbatim section # contains Ruby source code. If so, the verbatim block will be marked up as # HTML. Triggers include "def", "class", "module", "require", the "hash # rocket"# (=>) or a block call with a parameter. # # === Headers # # A line starting with an equal sign (=) is treated as a # heading. Level one headings have one equals sign, level two headings # have two, and so on until level six, which is the maximum # (seven hyphens or more result in a level six heading). # # For example, the above header was obtained with: # # === Headers # # In HTML output headers have an id matching their name. The above example's # HTML is: # #

Headers

# # If a heading is inside a method body the id will be prefixed with the # method's id. If the above header where in the documentation for a method # such as: # # ## # # This method does fun things # # # # = Example # # # # Example of fun things goes here ... # # def do_fun_things # end # # The header's id would be: # #

Example

# # The label can be linked-to using SomeClass@Headers. See # {Links}[RDoc::Markup@Links] for further details. # # === Rules # # A line starting with three or more hyphens (at the current indent) # generates a horizontal rule. # # --- # # produces: # # --- # # === Simple Lists # # If a paragraph starts with a "*", "-", "." or ".", # then it is taken to be the start of a list. The margin is increased to be # the first non-space following the list start flag. Subsequent lines # should be indented to this new margin until the list ends. For example: # # * this is a list with three paragraphs in # the first item. This is the first paragraph. # # And this is the second paragraph. # # 1. This is an indented, numbered list. # 2. This is the second item in that list # # This is the third conventional paragraph in the # first list item. # # * This is the second item in the original list # # produces: # # * this is a list with three paragraphs in # the first item. This is the first paragraph. # # And this is the second paragraph. # # 1. This is an indented, numbered list. # 2. This is the second item in that list # # This is the third conventional paragraph in the # first list item. # # * This is the second item in the original list # # === Labeled Lists # # You can also construct labeled lists, sometimes called description # or definition lists. Do this by putting the label in square brackets # and indenting the list body: # # [cat] a small furry mammal # that seems to sleep a lot # # [ant] a little insect that is known # to enjoy picnics # # produces: # # [cat] a small furry mammal # that seems to sleep a lot # # [ant] a little insect that is known # to enjoy picnics # # If you want the list bodies to line up to the left of the labels, # use two colons: # # cat:: a small furry mammal # that seems to sleep a lot # # ant:: a little insect that is known # to enjoy picnics # # produces: # # cat:: a small furry mammal # that seems to sleep a lot # # ant:: a little insect that is known # to enjoy picnics # # Notice that blank lines right after the label are ignored in labeled lists: # # [one] # # definition 1 # # [two] # # definition 2 # # produces the same output as # # [one] definition 1 # [two] definition 2 # # # === Lists and Verbatim # # If you want to introduce a verbatim section right after a list, it has to be # less indented than the list item bodies, but more indented than the list # label, letter, digit or bullet. For instance: # # * point 1 # # * point 2, first paragraph # # point 2, second paragraph # verbatim text inside point 2 # point 2, third paragraph # verbatim text outside of the list (the list is therefore closed) # regular paragraph after the list # # produces: # # * point 1 # # * point 2, first paragraph # # point 2, second paragraph # verbatim text inside point 2 # point 2, third paragraph # verbatim text outside of the list (the list is therefore closed) # regular paragraph after the list # # == Text Markup # # === Bold, Italic, Typewriter Text # # You can use markup within text (except verbatim) to change the # appearance of parts of that text. Out of the box, RDoc::Markup # supports word-based and general markup. # # Word-based markup uses flag characters around individual words: # # \*_word_\*:: displays _word_ in a *bold* font # \__word_\_:: displays _word_ in an _emphasized_ font # \+_word_\+:: displays _word_ in a +code+ font # # General markup affects text between a start delimiter and an end # delimiter. Not surprisingly, these delimiters look like HTML markup. # # \_text_:: displays _text_ in a *bold* font # \_text_:: displays _text_ in an _emphasized_ font # (alternate tag: \) # \_text_\:: displays _text_ in a +code+ font # (alternate tag: \) # # Unlike conventional Wiki markup, general markup can cross line # boundaries. You can turn off the interpretation of markup by # preceding the first character with a backslash (see Escaping # Text Markup, below). # # === Links # # Links to starting with +http:+, +https:+, +mailto:+, +ftp:+ or +www.+ # are recognized. An HTTP url that references an external image is converted # into an inline image element. # # Classes and methods will be automatically linked to their definition. For # example, RDoc::Markup will link to this documentation. By default # methods will only be automatically linked if they contain an _ (all # methods can be automatically linked through the --hyperlink-all # command line option). # # Single-word methods can be linked by using the # character for # instance methods or :: for class methods. For example, # #convert links to #convert. A class or method may be combined like # RDoc::Markup#convert. # # A heading inside the documentation can be linked by following the class # or method by an @ then the heading name. # RDoc::Markup@Links will link to this section like this: # RDoc::Markup@Links. Spaces in headings with multiple words must be escaped # with + like RDoc::Markup@Escaping+Text+Markup. # Punctuation and other special characters must be escaped like CGI.escape. # # The @ can also be used to link to sections. If a section and a # heading share the same name the section is preferred for the link. # # Links can also be of the form label[url], in which case +label+ is # used in the displayed text, and +url+ is used as the target. If +label+ # contains multiple words, put it in braces: {multi word label}[url]. # The +url+ may be an +http:+-type link or a cross-reference to a class, # module or method with a label. # # Links with the rdoc-image: scheme will create an image tag for # HTML output. Only fully-qualified URLs are supported. # # Links with the rdoc-ref: scheme will link to the referenced class, # module, method, file, etc. If the referenced item is does not exist # no link will be generated and rdoc-ref: will be removed from the # resulting text. # # Links starting with rdoc-label:label_name will link to the # +label_name+. You can create a label for the current link (for # bidirectional links) by supplying a name for the current link like # rdoc-label:label-other:label-mine. # # Links starting with +link:+ refer to local files whose path is relative to # the --op directory. Use rdoc-ref: instead of # link: to link to files generated by RDoc as the link target may # be different across RDoc generators. # # Example links: # # https://github.com/ruby/rdoc # mailto:user@example.com # {RDoc Documentation}[http://rdoc.rubyforge.org] # {RDoc Markup}[rdoc-ref:RDoc::Markup] # # === Escaping Text Markup # # Text markup can be escaped with a backslash, as in \, which was obtained # with \\. Except in verbatim sections and between \ tags, # to produce a backslash you have to double it unless it is followed by a # space, tab or newline. Otherwise, the HTML formatter will discard it, as it # is used to escape potential links: # # * The \ must be doubled if not followed by white space: \\. # * But not in \ tags: in a Regexp, \S matches non-space. # * This is a link to {ruby-lang}[www.ruby-lang.org]. # * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org]. # * This will not be linked to \RDoc::RDoc#document # # generates: # # * The \ must be doubled if not followed by white space: \\. # * But not in \ tags: in a Regexp, \S matches non-space. # * This is a link to {ruby-lang}[www.ruby-lang.org] # * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org] # * This will not be linked to \RDoc::RDoc#document # # Inside \ tags, more precisely, leading backslashes are removed only if # followed by a markup character (<*_+), a backslash, or a known link # reference (a known class or method). So in the example above, the backslash # of \S would be removed if there was a class or module named +S+ in # the current context. # # This behavior is inherited from RDoc version 1, and has been kept for # compatibility with existing RDoc documentation. # # === Conversion of characters # # HTML will convert two/three dashes to an em-dash. Other common characters are # converted as well: # # em-dash:: -- or --- # ellipsis:: ... # # single quotes:: 'text' or `text' # double quotes:: "text" or ``text'' # # copyright:: (c) # registered trademark:: (r) # # produces: # # em-dash:: -- or --- # ellipsis:: ... # # single quotes:: 'text' or `text' # double quotes:: "text" or ``text'' # # copyright:: (c) # registered trademark:: (r) # # # == Documenting Source Code # # Comment blocks can be written fairly naturally, either using # on # successive lines of the comment, or by including the comment in # a =begin/=end block. If you use the latter form, # the =begin line _must_ be flagged with an +rdoc+ tag: # # =begin rdoc # Documentation to be processed by RDoc. # # ... # =end # # RDoc stops processing comments if it finds a comment line starting # with -- right after the # character (otherwise, # it will be treated as a rule if it has three dashes or more). # This can be used to separate external from internal comments, # or to stop a comment being associated with a method, class, or module. # Commenting can be turned back on with a line that starts with ++. # # ## # # Extract the age and calculate the date-of-birth. # #-- # # FIXME: fails if the birthday falls on February 29th # #++ # # The DOB is returned as a Time object. # # def get_dob(person) # # ... # end # # Names of classes, files, and any method names containing an underscore or # preceded by a hash character are automatically linked from comment text to # their description. This linking works inside the current class or module, # and with ancestor methods (in included modules or in the superclass). # # Method parameter lists are extracted and displayed with the method # description. If a method calls +yield+, then the parameters passed to yield # will also be displayed: # # def fred # ... # yield line, address # # This will get documented as: # # fred() { |line, address| ... } # # You can override this using a comment containing ':yields: ...' immediately # after the method definition # # def fred # :yields: index, position # # ... # # yield line, address # # which will get documented as # # fred() { |index, position| ... } # # +:yields:+ is an example of a documentation directive. These appear # immediately after the start of the document element they are modifying. # # RDoc automatically cross-references words with underscores or camel-case. # To suppress cross-references, prefix the word with a \ character. To # include special characters like "\n", you'll need to use # two \ characters in normal text, but only one in \ text: # # "\\n" or "\n" # # produces: # # "\\n" or "\n" # # == Directives # # Directives are keywords surrounded by ":" characters. # # === Controlling what is documented # # [+:nodoc:+ / :nodoc: all] # This directive prevents documentation for the element from # being generated. For classes and modules, methods, aliases, # constants, and attributes directly within the affected class or # module also will be omitted. By default, though, modules and # classes within that class or module _will_ be documented. This is # turned off by adding the +all+ modifier. # # module MyModule # :nodoc: # class Input # end # end # # module OtherModule # :nodoc: all # class Output # end # end # # In the above code, only class MyModule::Input will be documented. # # The +:nodoc:+ directive, like +:enddoc:+, +:stopdoc:+ and +:startdoc:+ # presented below, is local to the current file: if you do not want to # document a module that appears in several files, specify +:nodoc:+ on each # appearance, at least once per file. # # [+:stopdoc:+ / +:startdoc:+] # Stop and start adding new documentation elements to the current container. # For example, if a class has a number of constants that you don't want to # document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the # last. If you don't specify a +:startdoc:+ by the end of the container, # disables documentation for the rest of the current file. # # [+:doc:+] # Forces a method or attribute to be documented even if it wouldn't be # otherwise. Useful if, for example, you want to include documentation of a # particular private method. # # [+:enddoc:+] # Document nothing further at the current level: directives +:startdoc:+ and # +:doc:+ that appear after this will not be honored for the current container # (file, class or module), in the current file. # # [+:notnew:+ / +:not_new:+ / +:not-new:+ ] # Only applicable to the +initialize+ instance method. Normally RDoc # assumes that the documentation and parameters for +initialize+ are # actually for the +new+ method, and so fakes out a +new+ for the class. # The +:notnew:+ directive stops this. Remember that +initialize+ is private, # so you won't see the documentation unless you use the +-a+ command line # option. # # === Method arguments # # [+:arg:+ or +:args:+ _parameters_] # Overrides the default argument handling with exactly these parameters. # # ## # # :args: a, b # # def some_method(*a) # end # # [+:yield:+ or +:yields:+ _parameters_] # Overrides the default yield discovery with these parameters. # # ## # # :yields: key, value # # def each_thing &block # @things.each(&block) # end # # [+:call-seq:+] # Lines up to the next blank line or lines with a common prefix in the # comment are treated as the method's calling sequence, overriding the # default parsing of method parameters and yield arguments. # # Multiple lines may be used. # # # :call-seq: # # ARGF.readlines(sep=$/) -> array # # ARGF.readlines(limit) -> array # # ARGF.readlines(sep, limit) -> array # # # # ARGF.to_a(sep=$/) -> array # # ARGF.to_a(limit) -> array # # ARGF.to_a(sep, limit) -> array # # # # The remaining lines are documentation ... # # === Sections # # Sections allow you to group methods in a class into sensible containers. If # you use the sections 'Public', 'Internal' and 'Deprecated' (the three # allowed method statuses from TomDoc) the sections will be displayed in that # order placing the most useful methods at the top. Otherwise, sections will # be displayed in alphabetical order. # # [+:category:+ _section_] # Adds this item to the named +section+ overriding the current section. Use # this to group methods by section in RDoc output while maintaining a # sensible ordering (like alphabetical). # # # :category: Utility Methods # # # # CGI escapes +text+ # # def convert_string text # CGI.escapeHTML text # end # # An empty category will place the item in the default category: # # # :category: # # # # This method is in the default category # # def some_method # # ... # end # # Unlike the :section: directive, :category: is not sticky. The category # only applies to the item immediately following the comment. # # Use the :section: directive to provide introductory text for a section of # documentation. # # [+:section:+ _title_] # Provides section introductory text in RDoc output. The title following # +:section:+ is used as the section name and the remainder of the comment # containing the section is used as introductory text. A section's comment # block must be separated from following comment blocks. Use an empty title # to switch to the default section. # # The :section: directive is sticky, so subsequent methods, aliases, # attributes, and classes will be contained in this section until the # section is changed. The :category: directive will override the :section: # directive. # # A :section: comment block may have one or more lines before the :section: # directive. These will be removed, and any identical lines at the end of # the block are also removed. This allows you to add visual cues to the # section. # # Example: # # # ---------------------------------------- # # :section: My Section # # This is the section that I wrote. # # See it glisten in the noon-day sun. # # ---------------------------------------- # # ## # # Comment for some_method # # def some_method # # ... # end # # === Other directives # # [+:markup:+ _type_] # Overrides the default markup type for this comment with the specified # markup type. For Ruby files, if the first comment contains this directive # it is applied automatically to all comments in the file. # # Unless you are converting between markup formats you should use a # .rdoc_options file to specify the default documentation # format for your entire project. See RDoc::Options@Saved+Options for # instructions. # # At the top of a file the +:markup:+ directive applies to the entire file: # # # coding: UTF-8 # # :markup: TomDoc # # # TomDoc comment here ... # # class MyClass # # ... # # For just one comment: # # # ... # end # # # :markup: RDoc # # # # This is a comment in RDoc markup format ... # # def some_method # # ... # # See Markup@CONTRIBUTING for instructions on adding a new markup format. # # [+:include:+ _filename_] # Include the contents of the named file at this point. This directive # must appear alone on one line, possibly preceded by spaces. In this # position, it can be escaped with a \ in front of the first colon. # # The file will be searched for in the directories listed by the +--include+ # option, or in the current directory by default. The contents of the file # will be shifted to have the same indentation as the ':' at the start of # the +:include:+ directive. # # [+:title:+ _text_] # Sets the title for the document. Equivalent to the --title # command line parameter. (The command line parameter overrides any :title: # directive in the source). # # [+:main:+ _name_] # Equivalent to the --main command line parameter. # #-- # Original Author:: Dave Thomas, dave@pragmaticprogrammer.com # License:: Ruby license class RDoc::Markup ## # An AttributeManager which handles inline markup. attr_reader :attribute_manager ## # Parses +str+ into an RDoc::Markup::Document. def self.parse str RDoc::Markup::Parser.parse str rescue RDoc::Markup::Parser::Error => e $stderr.puts <<-EOF While parsing markup, RDoc encountered a #{e.class}: #{e} \tfrom #{e.backtrace.join "\n\tfrom "} ---8<--- #{text} ---8<--- RDoc #{RDoc::VERSION} Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} #{RUBY_RELEASE_DATE} Please file a bug report with the above information at: https://github.com/ruby/rdoc/issues EOF raise end ## # Take a block of text and use various heuristics to determine its # structure (paragraphs, lists, and so on). Invoke an event handler as we # identify significant chunks. def initialize attribute_manager = nil @attribute_manager = attribute_manager || RDoc::Markup::AttributeManager.new @output = nil end ## # Add to the sequences used to add formatting to an individual word (such # as *bold*). Matching entries will generate attributes that the output # formatters can recognize by their +name+. def add_word_pair(start, stop, name) @attribute_manager.add_word_pair(start, stop, name) end ## # Add to the sequences recognized as general markup. def add_html(tag, name) @attribute_manager.add_html(tag, name) end ## # Add to other inline sequences. For example, we could add WikiWords using # something like: # # parser.add_regexp_handling(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # Each wiki word will be presented to the output formatter. def add_regexp_handling(pattern, name) @attribute_manager.add_regexp_handling(pattern, name) end ## # We take +input+, parse it if necessary, then invoke the output +formatter+ # using a Visitor to render the result. def convert input, formatter document = case input when RDoc::Markup::Document then input else RDoc::Markup::Parser.parse input end document.accept formatter end autoload :Parser, 'rdoc/markup/parser' autoload :PreProcess, 'rdoc/markup/pre_process' # Inline markup classes autoload :AttrChanger, 'rdoc/markup/attr_changer' autoload :AttrSpan, 'rdoc/markup/attr_span' autoload :Attributes, 'rdoc/markup/attributes' autoload :AttributeManager, 'rdoc/markup/attribute_manager' autoload :RegexpHandling, 'rdoc/markup/regexp_handling' # RDoc::Markup AST autoload :BlankLine, 'rdoc/markup/blank_line' autoload :BlockQuote, 'rdoc/markup/block_quote' autoload :Document, 'rdoc/markup/document' autoload :HardBreak, 'rdoc/markup/hard_break' autoload :Heading, 'rdoc/markup/heading' autoload :Include, 'rdoc/markup/include' autoload :IndentedParagraph, 'rdoc/markup/indented_paragraph' autoload :List, 'rdoc/markup/list' autoload :ListItem, 'rdoc/markup/list_item' autoload :Paragraph, 'rdoc/markup/paragraph' autoload :Raw, 'rdoc/markup/raw' autoload :Rule, 'rdoc/markup/rule' autoload :Verbatim, 'rdoc/markup/verbatim' # Formatters autoload :Formatter, 'rdoc/markup/formatter' autoload :ToAnsi, 'rdoc/markup/to_ansi' autoload :ToBs, 'rdoc/markup/to_bs' autoload :ToHtml, 'rdoc/markup/to_html' autoload :ToHtmlCrossref, 'rdoc/markup/to_html_crossref' autoload :ToHtmlSnippet, 'rdoc/markup/to_html_snippet' autoload :ToLabel, 'rdoc/markup/to_label' autoload :ToMarkdown, 'rdoc/markup/to_markdown' autoload :ToRdoc, 'rdoc/markup/to_rdoc' autoload :ToTableOfContents, 'rdoc/markup/to_table_of_contents' autoload :ToTest, 'rdoc/markup/to_test' autoload :ToTtOnly, 'rdoc/markup/to_tt_only' end PK ]ʘw  /gems/rdoc-6.2.1.1/lib/rdoc/markup/to_tt_only.rbnu[# frozen_string_literal: true ## # Extracts sections of text enclosed in plus, tt or code. Used to discover # undocumented parameters. class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter ## # Stack of list types attr_reader :list_type ## # Output accumulator attr_reader :res ## # Creates a new tt-only formatter. def initialize markup = nil super nil, markup add_tag :TT, nil, nil end ## # Adds tts from +block_quote+ to the output def accept_block_quote block_quote tt_sections block_quote.text end ## # Pops the list type for +list+ from #list_type def accept_list_end list @list_type.pop end ## # Pushes the list type for +list+ onto #list_type def accept_list_start list @list_type << list.type end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start list_item case @list_type.last when :NOTE, :LABEL then Array(list_item.label).map do |label| tt_sections label end.flatten end end ## # Adds +paragraph+ to the output def accept_paragraph paragraph tt_sections(paragraph.text) end ## # Does nothing to +markup_item+ because it doesn't have any user-built # content def do_nothing markup_item end alias accept_blank_line do_nothing # :nodoc: alias accept_heading do_nothing # :nodoc: alias accept_list_item_end do_nothing # :nodoc: alias accept_raw do_nothing # :nodoc: alias accept_rule do_nothing # :nodoc: alias accept_verbatim do_nothing # :nodoc: ## # Extracts tt sections from +text+ def tt_sections text flow = @am.flow text.dup flow.each do |item| case item when String then @res << item if in_tt? when RDoc::Markup::AttrChanger then off_tags res, item on_tags res, item when RDoc::Markup::RegexpHandling then @res << convert_regexp_handling(item) if in_tt? # TODO can this happen? else raise "Unknown flow element: #{item.inspect}" end end res end ## # Returns an Array of items that were wrapped in plus, tt or code. def end_accepting @res.compact end ## # Prepares the visitor for gathering tt sections def start_accepting @res = [] @list_type = [] end end PK ][nA##-gems/rdoc-6.2.1.1/lib/rdoc/markup/verbatim.rbnu[# frozen_string_literal: true ## # A section of verbatim text class RDoc::Markup::Verbatim < RDoc::Markup::Raw ## # Format of this verbatim section attr_accessor :format def initialize *parts # :nodoc: super @format = nil end def == other # :nodoc: super and @format == other.format end ## # Calls #accept_verbatim on +visitor+ def accept visitor visitor.accept_verbatim self end ## # Collapses 3+ newlines into two newlines def normalize parts = [] newlines = 0 @parts.each do |part| case part when /^\s*\n/ then newlines += 1 parts << part if newlines == 1 else newlines = 0 parts << part end end parts.pop if parts.last =~ /\A\r?\n\z/ @parts = parts end def pretty_print q # :nodoc: self.class.name =~ /.*::(\w{1,4})/i q.group 2, "[#{$1.downcase}: ", ']' do if @format then q.text "format: #{@format}" q.breakable end q.seplist @parts do |part| q.pp part end end end ## # Is this verbatim section Ruby code? def ruby? @format ||= nil # TODO for older ri data, switch the tree to marshal_dump @format == :ruby end ## # The text of the section def text @parts.join end end PK ]eM4gems/rdoc-6.2.1.1/lib/rdoc/markup/to_html_snippet.rbnu[# frozen_string_literal: true ## # Outputs RDoc markup as paragraphs with inline markup only. class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml ## # After this many characters the input will be cut off. attr_reader :character_limit ## # The number of characters seen so far. attr_reader :characters # :nodoc: ## # The attribute bitmask attr_reader :mask ## # After this many paragraphs the input will be cut off. attr_reader :paragraph_limit ## # Count of paragraphs found attr_reader :paragraphs ## # Creates a new ToHtmlSnippet formatter that will cut off the input on the # next word boundary after the given number of +characters+ or +paragraphs+ # of text have been encountered. def initialize options, characters = 100, paragraphs = 3, markup = nil super options, markup @character_limit = characters @paragraph_limit = paragraphs @characters = 0 @mask = 0 @paragraphs = 0 @markup.add_regexp_handling RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF end ## # Adds +heading+ to the output as a paragraph def accept_heading heading @res << "

#{to_html heading.text}\n" add_paragraph end ## # Raw sections are untrusted and ignored alias accept_raw ignore ## # Rules are ignored alias accept_rule ignore def accept_paragraph paragraph para = @in_list_entry.last || "

" text = paragraph.text @hard_break @res << "#{para}#{to_html text}\n" add_paragraph end ## # Finishes consumption of +list_item+ def accept_list_item_end list_item end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start list_item @res << list_item_start(list_item, @list.last) end ## # Prepares the visitor for consuming +list+ def accept_list_start list @list << list.type @res << html_list_name(list.type, true) @in_list_entry.push '' end ## # Adds +verbatim+ to the output def accept_verbatim verbatim throw :done if @characters >= @character_limit input = verbatim.text.rstrip text = truncate input text << ' ...' unless text == input super RDoc::Markup::Verbatim.new text add_paragraph end ## # Prepares the visitor for HTML snippet generation def start_accepting super @characters = 0 end ## # Removes escaping from the cross-references in +target+ def handle_regexp_CROSSREF target target.text.sub(/\A\\/, '') end ## # +target+ is a
def handle_regexp_HARD_BREAK target @characters -= 4 '
' end ## # Lists are paragraphs, but notes and labels have a separator def list_item_start list_item, list_type throw :done if @characters >= @character_limit case list_type when :BULLET, :LALPHA, :NUMBER, :UALPHA then "

" when :LABEL, :NOTE then labels = Array(list_item.label).map do |label| to_html label end.join ', ' labels << " — " unless labels.empty? start = "

#{labels}" @characters += 1 # try to include the label start else raise RDoc::Error, "Invalid list type: #{list_type.inspect}" end end ## # Returns just the text of +link+, +url+ is only used to determine the link # type. def gen_url url, text if url =~ /^rdoc-label:([^:]*)(?::(.*))?/ then type = "link" elsif url =~ /([A-Za-z]+):(.*)/ then type = $1 else type = "http" end if (type == "http" or type == "https" or type == "link") and url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then '' else text.sub(%r%^#{type}:/*%, '') end end ## # In snippets, there are no lists def html_list_name list_type, open_tag '' end ## # Throws +:done+ when paragraph_limit paragraphs have been encountered def add_paragraph @paragraphs += 1 throw :done if @paragraphs >= @paragraph_limit end ## # Marks up +content+ def convert content catch :done do return super end end_accepting end ## # Converts flow items +flow+ def convert_flow flow throw :done if @characters >= @character_limit res = [] @mask = 0 flow.each do |item| case item when RDoc::Markup::AttrChanger then off_tags res, item on_tags res, item when String then text = convert_string item res << truncate(text) when RDoc::Markup::RegexpHandling then text = convert_regexp_handling item res << truncate(text) else raise "Unknown flow element: #{item.inspect}" end if @characters >= @character_limit then off_tags res, RDoc::Markup::AttrChanger.new(0, @mask) break end end res << ' ...' if @characters >= @character_limit res.join end ## # Maintains a bitmask to allow HTML elements to be closed properly. See # RDoc::Markup::Formatter. def on_tags res, item @mask ^= item.turn_on super end ## # Maintains a bitmask to allow HTML elements to be closed properly. See # RDoc::Markup::Formatter. def off_tags res, item @mask ^= item.turn_off super end ## # Truncates +text+ at the end of the first word after the character_limit. def truncate text length = text.length characters = @characters @characters += length return text if @characters < @character_limit remaining = @character_limit - characters text =~ /\A(.{#{remaining},}?)(\s|$)/m # TODO word-break instead of \s? $1 end end PK ]N_0gems/rdoc-6.2.1.1/lib/rdoc/markup/block_quote.rbnu[# frozen_string_literal: true ## # A quoted section which contains markup items. class RDoc::Markup::BlockQuote < RDoc::Markup::Raw ## # Calls #accept_block_quote on +visitor+ def accept visitor visitor.accept_block_quote self end end PK ]tԇ/gems/rdoc-6.2.1.1/lib/rdoc/markup/blank_line.rbnu[# frozen_string_literal: true ## # An empty line. This class is a singleton. class RDoc::Markup::BlankLine @instance = new ## # RDoc::Markup::BlankLine is a singleton def self.new @instance end ## # Calls #accept_blank_line on +visitor+ def accept visitor visitor.accept_blank_line self end def pretty_print q # :nodoc: q.text 'blankline' end end PK ]<88+gems/rdoc-6.2.1.1/lib/rdoc/markup/parser.rbnu[# frozen_string_literal: true require 'strscan' ## # A recursive-descent parser for RDoc markup. # # The parser tokenizes an input string then parses the tokens into a Document. # Documents can be converted into output formats by writing a visitor like # RDoc::Markup::ToHTML. # # The parser only handles the block-level constructs Paragraph, List, # ListItem, Heading, Verbatim, BlankLine, Rule and BlockQuote. # Inline markup such as \+blah\+ is handled separately by # RDoc::Markup::AttributeManager. # # To see what markup the Parser implements read RDoc. To see how to use # RDoc markup to format text in your program read RDoc::Markup. class RDoc::Markup::Parser include RDoc::Text ## # List token types LIST_TOKENS = [ :BULLET, :LABEL, :LALPHA, :NOTE, :NUMBER, :UALPHA, ] ## # Parser error subclass class Error < RuntimeError; end ## # Raised when the parser is unable to handle the given markup class ParseError < Error; end ## # Enables display of debugging information attr_accessor :debug ## # Token accessor attr_reader :tokens ## # Parses +str+ into a Document. # # Use RDoc::Markup#parse instead of this method. def self.parse str parser = new parser.tokenize str doc = RDoc::Markup::Document.new parser.parse doc end ## # Returns a token stream for +str+, for testing def self.tokenize str parser = new parser.tokenize str parser.tokens end ## # Creates a new Parser. See also ::parse def initialize @binary_input = nil @current_token = nil @debug = false @s = nil @tokens = [] end ## # Builds a Heading of +level+ def build_heading level type, text, = get text = case type when :TEXT then skip :NEWLINE text else unget '' end RDoc::Markup::Heading.new level, text end ## # Builds a List flush to +margin+ def build_list margin p :list_start => margin if @debug list = RDoc::Markup::List.new label = nil until @tokens.empty? do type, data, column, = get case type when *LIST_TOKENS then if column < margin || (list.type && list.type != type) then unget break end list.type = type peek_type, _, column, = peek_token case type when :NOTE, :LABEL then label = [] unless label if peek_type == :NEWLINE then # description not on the same line as LABEL/NOTE # skip the trailing newline & any blank lines below while peek_type == :NEWLINE get peek_type, _, column, = peek_token end # we may be: # - at end of stream # - at a column < margin: # [text] # blah blah blah # - at the same column, but with a different type of list item # [text] # * blah blah # - at the same column, with the same type of list item # [one] # [two] # In all cases, we have an empty description. # In the last case only, we continue. if peek_type.nil? || column < margin then empty = true elsif column == margin then case peek_type when type empty = :continue when *LIST_TOKENS empty = true else empty = false end else empty = false end if empty then label << data next if empty == :continue break end end else data = nil end if label then data = label << data label = nil end list_item = RDoc::Markup::ListItem.new data parse list_item, column list << list_item else unget break end end p :list_end => margin if @debug if list.empty? then return nil unless label return nil unless [:LABEL, :NOTE].include? list.type list_item = RDoc::Markup::ListItem.new label, RDoc::Markup::BlankLine.new list << list_item end list end ## # Builds a Paragraph that is flush to +margin+ def build_paragraph margin p :paragraph_start => margin if @debug paragraph = RDoc::Markup::Paragraph.new until @tokens.empty? do type, data, column, = get if type == :TEXT and column == margin then paragraph << data break if peek_token.first == :BREAK data << ' ' if skip :NEWLINE else unget break end end paragraph.parts.last.sub!(/ \z/, '') # cleanup p :paragraph_end => margin if @debug paragraph end ## # Builds a Verbatim that is indented from +margin+. # # The verbatim block is shifted left (the least indented lines start in # column 0). Each part of the verbatim is one line of text, always # terminated by a newline. Blank lines always consist of a single newline # character, and there is never a single newline at the end of the verbatim. def build_verbatim margin p :verbatim_begin => margin if @debug verbatim = RDoc::Markup::Verbatim.new min_indent = nil generate_leading_spaces = true line = ''.dup until @tokens.empty? do type, data, column, = get if type == :NEWLINE then line << data verbatim << line line = ''.dup generate_leading_spaces = true next end if column <= margin unget break end if generate_leading_spaces then indent = column - margin line << ' ' * indent min_indent = indent if min_indent.nil? || indent < min_indent generate_leading_spaces = false end case type when :HEADER then line << '=' * data _, _, peek_column, = peek_token peek_column ||= column + data indent = peek_column - column - data line << ' ' * indent when :RULE then width = 2 + data line << '-' * width _, _, peek_column, = peek_token peek_column ||= column + width indent = peek_column - column - width line << ' ' * indent when :BREAK, :TEXT then line << data else # *LIST_TOKENS list_marker = case type when :BULLET then data when :LABEL then "[#{data}]" when :NOTE then "#{data}::" else # :LALPHA, :NUMBER, :UALPHA "#{data}." end line << list_marker peek_type, _, peek_column = peek_token unless peek_type == :NEWLINE then peek_column ||= column + list_marker.length indent = peek_column - column - list_marker.length line << ' ' * indent end end end verbatim << line << "\n" unless line.empty? verbatim.parts.each { |p| p.slice!(0, min_indent) unless p == "\n" } if min_indent > 0 verbatim.normalize p :verbatim_end => margin if @debug verbatim end ## # Pulls the next token from the stream. def get @current_token = @tokens.shift p :get => @current_token if @debug @current_token end ## # Parses the tokens into an array of RDoc::Markup::XXX objects, # and appends them to the passed +parent+ RDoc::Markup::YYY object. # # Exits at the end of the token stream, or when it encounters a token # in a column less than +indent+ (unless it is a NEWLINE). # # Returns +parent+. def parse parent, indent = 0 p :parse_start => indent if @debug until @tokens.empty? do type, data, column, = get case type when :BREAK then parent << RDoc::Markup::BlankLine.new skip :NEWLINE, false next when :NEWLINE then # trailing newlines are skipped below, so this is a blank line parent << RDoc::Markup::BlankLine.new skip :NEWLINE, false next end # indentation change: break or verbatim if column < indent then unget break elsif column > indent then unget parent << build_verbatim(indent) next end # indentation is the same case type when :HEADER then parent << build_heading(data) when :RULE then parent << RDoc::Markup::Rule.new(data) skip :NEWLINE when :TEXT then unget parse_text parent, indent when :BLOCKQUOTE then type, _, column = get if type == :NEWLINE type, _, column = get end unget if type bq = RDoc::Markup::BlockQuote.new p :blockquote_start => [data, column] if @debug parse bq, column p :blockquote_end => indent if @debug parent << bq when *LIST_TOKENS then unget parent << build_list(indent) else type, data, column, line = @current_token raise ParseError, "Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}" end end p :parse_end => indent if @debug parent end ## # Small hook that is overridden by RDoc::TomDoc def parse_text parent, indent # :nodoc: parent << build_paragraph(indent) end ## # Returns the next token on the stream without modifying the stream def peek_token token = @tokens.first || [] p :peek => token if @debug token end ## # A simple wrapper of StringScanner that is aware of the current column and lineno class MyStringScanner def initialize(input) @line = @column = 0 @s = StringScanner.new input end def scan(re) ret = @s.scan(re) @column += ret.length if ret ret end def unscan(s) @s.pos -= s.bytesize @column -= s.length end def pos [@column, @line] end def newline! @column = 0 @line += 1 end def eos? @s.eos? end def matched @s.matched end def [](i) @s[i] end end ## # Creates the StringScanner def setup_scanner input @s = MyStringScanner.new input end ## # Skips the next token if its type is +token_type+. # # Optionally raises an error if the next token is not of the expected type. def skip token_type, error = true type, = get return unless type # end of stream return @current_token if token_type == type unget raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if error end ## # Turns text +input+ into a stream of tokens def tokenize input setup_scanner input until @s.eos? do pos = @s.pos # leading spaces will be reflected by the column of the next token # the only thing we loose are trailing spaces at the end of the file next if @s.scan(/ +/) # note: after BULLET, LABEL, etc., # indent will be the column of the next non-newline token @tokens << case # [CR]LF => :NEWLINE when @s.scan(/\r?\n/) then token = [:NEWLINE, @s.matched, *pos] @s.newline! token # === text => :HEADER then :TEXT when @s.scan(/(=+)(\s*)/) then level = @s[1].length header = [:HEADER, level, *pos] if @s[2] =~ /^\r?\n/ then @s.unscan(@s[2]) header else pos = @s.pos @s.scan(/.*/) @tokens << header [:TEXT, @s.matched.sub(/\r$/, ''), *pos] end # --- (at least 3) and nothing else on the line => :RULE when @s.scan(/(-{3,}) *\r?$/) then [:RULE, @s[1].length - 2, *pos] # * or - followed by white space and text => :BULLET when @s.scan(/([*-]) +(\S)/) then @s.unscan(@s[2]) [:BULLET, @s[1], *pos] # A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER when @s.scan(/([a-z]|\d+)\. +(\S)/i) then # FIXME if tab(s), the column will be wrong # either support tabs everywhere by first expanding them to # spaces, or assume that they will have been replaced # before (and provide a check for that at least in debug # mode) list_label = @s[1] @s.unscan(@s[2]) list_type = case list_label when /[a-z]/ then :LALPHA when /[A-Z]/ then :UALPHA when /\d/ then :NUMBER else raise ParseError, "BUG token #{list_label}" end [list_type, list_label, *pos] # [text] followed by spaces or end of line => :LABEL when @s.scan(/\[(.*?)\]( +|\r?$)/) then [:LABEL, @s[1], *pos] # text:: followed by spaces or end of line => :NOTE when @s.scan(/(.*?)::( +|\r?$)/) then [:NOTE, @s[1], *pos] # >>> followed by end of line => :BLOCKQUOTE when @s.scan(/>>> *(\w+)?$/) then [:BLOCKQUOTE, @s[1], *pos] # anything else: :TEXT else @s.scan(/(.*?)( )?\r?$/) token = [:TEXT, @s[1], *pos] if @s[2] then @tokens << token [:BREAK, @s[2], pos[0] + @s[1].length, pos[1]] else token end end end self end ## # Returns the current token to the token stream def unget token = @current_token p :unget => token if @debug raise Error, 'too many #ungets' if token == @tokens.first @tokens.unshift token if token end end PK ]V,gems/rdoc-6.2.1.1/lib/rdoc/markup/to_test.rbnu[# frozen_string_literal: true ## # This Markup outputter is used for testing purposes. class RDoc::Markup::ToTest < RDoc::Markup::Formatter # :stopdoc: ## # :section: Visitor def start_accepting @res = [] @list = [] end def end_accepting @res end def accept_paragraph(paragraph) @res << convert_flow(@am.flow(paragraph.text)) end def accept_raw raw @res << raw.parts.join end def accept_verbatim(verbatim) @res << verbatim.text.gsub(/^(\S)/, ' \1') end def accept_list_start(list) @list << case list.type when :BULLET then '*' when :NUMBER then '1' else list.type end end def accept_list_end(list) @list.pop end def accept_list_item_start(list_item) @res << "#{' ' * (@list.size - 1)}#{@list.last}: " end def accept_list_item_end(list_item) end def accept_blank_line(blank_line) @res << "\n" end def accept_heading(heading) @res << "#{'=' * heading.level} #{heading.text}" end def accept_rule(rule) @res << '-' * rule.weight end # :startdoc: end PK ]fQ`66,gems/rdoc-6.2.1.1/lib/rdoc/markup/to_ansi.rbnu[# frozen_string_literal: true ## # Outputs RDoc markup with vibrant ANSI color! class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc ## # Creates a new ToAnsi visitor that is ready to output vibrant ANSI color! def initialize markup = nil super @headings.clear @headings[1] = ["\e[1;32m", "\e[m"] # bold @headings[2] = ["\e[4;32m", "\e[m"] # underline @headings[3] = ["\e[32m", "\e[m"] # just green end ## # Maps attributes to ANSI sequences def init_tags add_tag :BOLD, "\e[1m", "\e[m" add_tag :TT, "\e[7m", "\e[m" add_tag :EM, "\e[4m", "\e[m" end ## # Overrides indent width to ensure output lines up correctly. def accept_list_item_end list_item width = case @list_type.last when :BULLET then 2 when :NOTE, :LABEL then if @prefix then @res << @prefix.strip @prefix = nil end @res << "\n" unless res.length == 1 2 else bullet = @list_index.last.to_s @list_index[-1] = @list_index.last.succ bullet.length + 2 end @indent -= width end ## # Adds coloring to note and label list items def accept_list_item_start list_item bullet = case @list_type.last when :BULLET then '*' when :NOTE, :LABEL then labels = Array(list_item.label).map do |label| attributes(label).strip end.join "\n" labels << ":\n" unless labels.empty? labels else @list_index.last.to_s + '.' end case @list_type.last when :NOTE, :LABEL then @indent += 2 @prefix = bullet + (' ' * @indent) else @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1) width = bullet.gsub(/\e\[[\d;]*m/, '').length + 1 @indent += width end end ## # Starts accepting with a reset screen def start_accepting super @res = ["\e[0m"] end end PK ]d.gems/rdoc-6.2.1.1/lib/rdoc/markup/paragraph.rbnu[# frozen_string_literal: true ## # A Paragraph of text class RDoc::Markup::Paragraph < RDoc::Markup::Raw ## # Calls #accept_paragraph on +visitor+ def accept visitor visitor.accept_paragraph self end ## # Joins the raw paragraph text and converts inline HardBreaks to the # +hard_break+ text. def text hard_break = '' @parts.map do |part| if RDoc::Markup::HardBreak === part then hard_break else part end end.join end end PK ]$$5gems/rdoc-6.2.1.1/lib/rdoc/markup/to_html_crossref.rbnu[# frozen_string_literal: true ## # Subclass of the RDoc::Markup::ToHtml class that supports looking up method # names, classes, etc to create links. RDoc::CrossReference is used to # generate those links based on the current context. class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml # :stopdoc: ALL_CROSSREF_REGEXP = RDoc::CrossReference::ALL_CROSSREF_REGEXP CLASS_REGEXP_STR = RDoc::CrossReference::CLASS_REGEXP_STR CROSSREF_REGEXP = RDoc::CrossReference::CROSSREF_REGEXP METHOD_REGEXP_STR = RDoc::CrossReference::METHOD_REGEXP_STR # :startdoc: ## # RDoc::CodeObject for generating references attr_accessor :context ## # Should we show '#' characters on method references? attr_accessor :show_hash ## # Creates a new crossref resolver that generates links relative to +context+ # which lives at +from_path+ in the generated files. '#' characters on # references are removed unless +show_hash+ is true. Only method names # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true. def initialize(options, from_path, context, markup = nil) raise ArgumentError, 'from_path cannot be nil' if from_path.nil? super options, markup @context = context @from_path = from_path @hyperlink_all = @options.hyperlink_all @show_hash = @options.show_hash crossref_re = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP @markup.add_regexp_handling crossref_re, :CROSSREF @cross_reference = RDoc::CrossReference.new @context end ## # Creates a link to the reference +name+ if the name exists. If +text+ is # given it is used as the link text, otherwise +name+ is used. def cross_reference name, text = nil, code = true lookup = name name = name[1..-1] unless @show_hash if name[0, 1] == '#' if name =~ /(.*[^#:])@/ text ||= "#{CGI.unescape $'} at #{$1}" code = false else text ||= name end link lookup, text, code end ## # We're invoked when any text matches the CROSSREF pattern. If we find the # corresponding reference, generate a link. If the name we're looking for # contains no punctuation, we look for it up the module/class chain. For # example, ToHtml is found, even without the RDoc::Markup:: prefix, # because we look for it in module Markup first. def handle_regexp_CROSSREF(target) name = target.text return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails unless @hyperlink_all then # This ensures that words entirely consisting of lowercase letters will # not have cross-references generated (to suppress lots of erroneous # cross-references to "new" in text, for instance) return name if name =~ /\A[a-z]*\z/ end cross_reference name end ## # Handles rdoc-ref: scheme links and allows RDoc::Markup::ToHtml to # handle other schemes. def handle_regexp_HYPERLINK target return cross_reference $' if target.text =~ /\Ardoc-ref:/ super end ## # +target+ is an rdoc-schemed link that will be converted into a hyperlink. # For the rdoc-ref scheme the cross-reference will be looked up and the # given name will be used. # # All other contents are handled by # {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_regexp_RDOCLINK] def handle_regexp_RDOCLINK target url = target.text case url when /\Ardoc-ref:/ then cross_reference $' else super end end ## # Generates links for rdoc-ref: scheme URLs and allows # RDoc::Markup::ToHtml to handle other schemes. def gen_url url, text return super unless url =~ /\Ardoc-ref:/ name = $' cross_reference name, text, name == text end ## # Creates an HTML link to +name+ with the given +text+. def link name, text, code = true if name =~ /(.*[^#:])@/ then name = $1 label = $' end ref = @cross_reference.resolve name, text case ref when String then ref else path = ref.as_href @from_path if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref) text = "#{text}" end if path =~ /#/ then path << "-label-#{label}" elsif ref.sections and ref.sections.any? { |section| label == section.title } then path << "##{label}" else if ref.respond_to?(:aref) path << "##{ref.aref}-label-#{label}" else path << "#label-#{label}" end end if label "#{text}" end end end PK ]Q,gems/rdoc-6.2.1.1/lib/rdoc/markup/to_rdoc.rbnu[# frozen_string_literal: true ## # Outputs RDoc markup as RDoc markup! (mostly) class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter ## # Current indent amount for output in characters attr_accessor :indent ## # Output width in characters attr_accessor :width ## # Stack of current list indexes for alphabetic and numeric lists attr_reader :list_index ## # Stack of list types attr_reader :list_type ## # Stack of list widths for indentation attr_reader :list_width ## # Prefix for the next list item. See #use_prefix attr_reader :prefix ## # Output accumulator attr_reader :res ## # Creates a new formatter that will output (mostly) \RDoc markup def initialize markup = nil super nil, markup @markup.add_regexp_handling(/\\\S/, :SUPPRESSED_CROSSREF) @width = 78 init_tags @headings = {} @headings.default = [] @headings[1] = ['= ', ''] @headings[2] = ['== ', ''] @headings[3] = ['=== ', ''] @headings[4] = ['==== ', ''] @headings[5] = ['===== ', ''] @headings[6] = ['====== ', ''] @hard_break = "\n" end ## # Maps attributes to HTML sequences def init_tags add_tag :BOLD, "", "" add_tag :TT, "", "" add_tag :EM, "", "" end ## # Adds +blank_line+ to the output def accept_blank_line blank_line @res << "\n" end ## # Adds +paragraph+ to the output def accept_block_quote block_quote @indent += 2 block_quote.parts.each do |part| @prefix = '> ' part.accept self end @indent -= 2 end ## # Adds +heading+ to the output def accept_heading heading use_prefix or @res << ' ' * @indent @res << @headings[heading.level][0] @res << attributes(heading.text) @res << @headings[heading.level][1] @res << "\n" end ## # Finishes consumption of +list+ def accept_list_end list @list_index.pop @list_type.pop @list_width.pop end ## # Finishes consumption of +list_item+ def accept_list_item_end list_item width = case @list_type.last when :BULLET then 2 when :NOTE, :LABEL then if @prefix then @res << @prefix.strip @prefix = nil end @res << "\n" 2 else bullet = @list_index.last.to_s @list_index[-1] = @list_index.last.succ bullet.length + 2 end @indent -= width end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start list_item type = @list_type.last case type when :NOTE, :LABEL then bullets = Array(list_item.label).map do |label| attributes(label).strip end.join "\n" bullets << ":\n" unless bullets.empty? @prefix = ' ' * @indent @indent += 2 @prefix << bullets + (' ' * @indent) else bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1) width = bullet.length + 1 @indent += width end end ## # Prepares the visitor for consuming +list+ def accept_list_start list case list.type when :BULLET then @list_index << nil @list_width << 1 when :LABEL, :NOTE then @list_index << nil @list_width << 2 when :LALPHA then @list_index << 'a' @list_width << list.items.length.to_s.length when :NUMBER then @list_index << 1 @list_width << list.items.length.to_s.length when :UALPHA then @list_index << 'A' @list_width << list.items.length.to_s.length else raise RDoc::Error, "invalid list type #{list.type}" end @list_type << list.type end ## # Adds +paragraph+ to the output def accept_paragraph paragraph text = paragraph.text @hard_break wrap attributes text end ## # Adds +paragraph+ to the output def accept_indented_paragraph paragraph @indent += paragraph.indent text = paragraph.text @hard_break wrap attributes text @indent -= paragraph.indent end ## # Adds +raw+ to the output def accept_raw raw @res << raw.parts.join("\n") end ## # Adds +rule+ to the output def accept_rule rule use_prefix or @res << ' ' * @indent @res << '-' * (@width - @indent) @res << "\n" end ## # Outputs +verbatim+ indented 2 columns def accept_verbatim verbatim indent = ' ' * (@indent + 2) verbatim.parts.each do |part| @res << indent unless part == "\n" @res << part end @res << "\n" end ## # Applies attribute-specific markup to +text+ using RDoc::AttributeManager def attributes text flow = @am.flow text.dup convert_flow flow end ## # Returns the generated output def end_accepting @res.join end ## # Removes preceding \\ from the suppressed crossref +target+ def handle_regexp_SUPPRESSED_CROSSREF target text = target.text text = text.sub('\\', '') unless in_tt? text end ## # Adds a newline to the output def handle_regexp_HARD_BREAK target "\n" end ## # Prepares the visitor for text generation def start_accepting @res = [""] @indent = 0 @prefix = nil @list_index = [] @list_type = [] @list_width = [] end ## # Adds the stored #prefix to the output and clears it. Lists generate a # prefix for later consumption. def use_prefix prefix, @prefix = @prefix, nil @res << prefix if prefix prefix end ## # Wraps +text+ to #width def wrap text return unless text && !text.empty? text_len = @width - @indent text_len = 20 if text_len < 20 re = /^(.{0,#{text_len}})[ \n]/ next_prefix = ' ' * @indent prefix = @prefix || next_prefix @prefix = nil @res << prefix while text.length > text_len if text =~ re then @res << $1 text.slice!(0, $&.length) else @res << text.slice!(0, text_len) end @res << "\n" << next_prefix end if text.empty? then @res.pop @res.pop else @res << text @res << "\n" end end end PK ]C"==,gems/rdoc-6.2.1.1/lib/rdoc/markup/include.rbnu[# frozen_string_literal: true ## # A file included at generation time. Objects of this class are created by # RDoc::RD for an extension-less include. # # This implementation in incomplete. class RDoc::Markup::Include ## # The filename to be included, without extension attr_reader :file ## # Directories to search for #file attr_reader :include_path ## # Creates a new include that will import +file+ from +include_path+ def initialize file, include_path @file = file @include_path = include_path end def == other # :nodoc: self.class === other and @file == other.file and @include_path == other.include_path end def pretty_print q # :nodoc: q.group 2, '[incl ', ']' do q.text file q.breakable q.text 'from ' q.pp include_path end end end PK ]-Ǘ.gems/rdoc-6.2.1.1/lib/rdoc/markup/formatter.rbnu[# frozen_string_literal: true ## # Base class for RDoc markup formatters # # Formatters are a visitor that converts an RDoc::Markup tree (from a comment) # into some kind of output. RDoc ships with formatters for converting back to # rdoc, ANSI text, HTML, a Table of Contents and other formats. # # If you'd like to write your own Formatter use # RDoc::Markup::FormatterTestCase. If you're writing a text-output formatter # use RDoc::Markup::TextFormatterTestCase which provides extra test cases. class RDoc::Markup::Formatter ## # Tag for inline markup containing a +bit+ for the bitmask and the +on+ and # +off+ triggers. InlineTag = Struct.new(:bit, :on, :off) ## # Converts a target url to one that is relative to a given path def self.gen_relative_url path, target from = File.dirname path to, to_file = File.split target from = from.split "/" to = to.split "/" from.delete '.' to.delete '.' while from.size > 0 and to.size > 0 and from[0] == to[0] do from.shift to.shift end from.fill ".." from.concat to from << to_file File.join(*from) end ## # Creates a new Formatter def initialize options, markup = nil @options = options @markup = markup || RDoc::Markup.new @am = @markup.attribute_manager @am.add_regexp_handling(/
/, :HARD_BREAK) @attributes = @am.attributes @attr_tags = [] @in_tt = 0 @tt_bit = @attributes.bitmap_for :TT @hard_break = '' @from_path = '.' end ## # Adds +document+ to the output def accept_document document document.parts.each do |item| case item when RDoc::Markup::Document then # HACK accept_document item else item.accept self end end end ## # Adds a regexp handling for links of the form rdoc-...: def add_regexp_handling_RDOCLINK @markup.add_regexp_handling(/rdoc-[a-z]+:[^\s\]]+/, :RDOCLINK) end ## # Adds a regexp handling for links of the form {}[] and # [] def add_regexp_handling_TIDYLINK @markup.add_regexp_handling(/(?: \{.*?\} | # multi-word label \b[^\s{}]+? # single-word label ) \[\S+?\] # link target /x, :TIDYLINK) end ## # Add a new set of tags for an attribute. We allow separate start and end # tags for flexibility def add_tag(name, start, stop) attr = @attributes.bitmap_for name @attr_tags << InlineTag.new(attr, start, stop) end ## # Allows +tag+ to be decorated with additional information. def annotate(tag) tag end ## # Marks up +content+ def convert content @markup.convert content, self end ## # Converts flow items +flow+ def convert_flow(flow) res = [] flow.each do |item| case item when String then res << convert_string(item) when RDoc::Markup::AttrChanger then off_tags res, item on_tags res, item when RDoc::Markup::RegexpHandling then res << convert_regexp_handling(item) else raise "Unknown flow element: #{item.inspect}" end end res.join end ## # Converts added regexp handlings. See RDoc::Markup#add_regexp_handling def convert_regexp_handling target return target.text if in_tt? handled = false @attributes.each_name_of target.type do |name| method_name = "handle_regexp_#{name}" if respond_to? method_name then target.text = send method_name, target handled = true end end unless handled then target_name = @attributes.as_string target.type raise RDoc::Error, "Unhandled regexp handling #{target_name}: #{target}" end target.text end ## # Converts a string to be fancier if desired def convert_string string string end ## # Use ignore in your subclass to ignore the content of a node. # # ## # # We don't support raw nodes in ToNoRaw # # alias accept_raw ignore def ignore *node end ## # Are we currently inside tt tags? def in_tt? @in_tt > 0 end ## # Turns on tags for +item+ on +res+ def on_tags res, item attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 then res << annotate(tag.on) @in_tt += 1 if tt? tag end end end ## # Turns off tags for +item+ on +res+ def off_tags res, item attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 then @in_tt -= 1 if tt? tag res << annotate(tag.off) end end end ## # Extracts and a scheme, url and an anchor id from +url+ and returns them. def parse_url url case url when /^rdoc-label:([^:]*)(?::(.*))?/ then scheme = 'link' path = "##{$1}" id = " id=\"#{$2}\"" if $2 when /([A-Za-z]+):(.*)/ then scheme = $1.downcase path = $2 when /^#/ then else scheme = 'http' path = url url = url end if scheme == 'link' then url = if path[0, 1] == '#' then # is this meaningful? path else self.class.gen_relative_url @from_path, path end end [scheme, url, id] end ## # Is +tag+ a tt tag? def tt? tag tag.bit == @tt_bit end end PK ]|4gems/rdoc-6.2.1.1/lib/rdoc/markup/regexp_handling.rbnu[# frozen_string_literal: true ## # Hold details of a regexp handling sequence class RDoc::Markup::RegexpHandling ## # Regexp handling type attr_reader :type ## # Regexp handling text attr_accessor :text ## # Creates a new regexp handling sequence of +type+ with +text+ def initialize(type, text) @type, @text = type, text end ## # Regexp handlings are equal when the have the same text and type def ==(o) self.text == o.text && self.type == o.type end def inspect # :nodoc: "#" % [ object_id, @type, text.dump] end def to_s # :nodoc: "RegexpHandling: type=#{type} text=#{text.dump}" end end PK ]ߦo1gems/rdoc-6.2.1.1/lib/rdoc/markup/attr_changer.rbnu[# frozen_string_literal: true class RDoc::Markup AttrChanger = Struct.new :turn_on, :turn_off # :nodoc: end ## # An AttrChanger records a change in attributes. It contains a bitmap of the # attributes to turn on, and a bitmap of those to turn off. class RDoc::Markup::AttrChanger def to_s # :nodoc: "Attr: +#{turn_on}/-#{turn_off}" end def inspect # :nodoc: '+%d/-%d' % [turn_on, turn_off] end end PK ]|"",gems/rdoc-6.2.1.1/lib/rdoc/markup/to_html.rbnu[# frozen_string_literal: true require 'cgi' ## # Outputs RDoc markup as HTML. class RDoc::Markup::ToHtml < RDoc::Markup::Formatter include RDoc::Text # :section: Utilities ## # Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags LIST_TYPE_TO_HTML = { :BULLET => ['

    ', '
'], :LABEL => ['
', '
'], :LALPHA => ['
    ', '
'], :NOTE => ['
', '
'], :NUMBER => ['
    ', '
'], :UALPHA => ['
    ', '
'], } attr_reader :res # :nodoc: attr_reader :in_list_entry # :nodoc: attr_reader :list # :nodoc: ## # The RDoc::CodeObject HTML is being generated for. This is used to # generate namespaced URI fragments attr_accessor :code_object ## # Path to this document for relative links attr_accessor :from_path # :section: ## # Creates a new formatter that will output HTML def initialize options, markup = nil super @code_object = nil @from_path = '' @in_list_entry = nil @list = nil @th = nil @hard_break = "
\n" # external links @markup.add_regexp_handling(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/, :HYPERLINK) add_regexp_handling_RDOCLINK add_regexp_handling_TIDYLINK init_tags end # :section: Regexp Handling # # These methods are used by regexp handling markup added by RDoc::Markup#add_regexp_handling. def handle_RDOCLINK url # :nodoc: case url when /^rdoc-ref:/ $' when /^rdoc-label:/ text = $' text = case text when /\Alabel-/ then $' when /\Afootmark-/ then $' when /\Afoottext-/ then $' else text end gen_url url, text when /^rdoc-image:/ "" else url =~ /\Ardoc-[a-z]+:/ $' end end ## # +target+ is a
def handle_regexp_HARD_BREAK target '
' end ## # +target+ is a potential link. The following schemes are handled: # # mailto::: # Inserted as-is. # http::: # Links are checked to see if they reference an image. If so, that image # gets inserted using an tag. Otherwise a conventional # is used. # link::: # Reference to a local file relative to the output directory. def handle_regexp_HYPERLINK(target) url = target.text gen_url url, url end ## # +target+ is an rdoc-schemed link that will be converted into a hyperlink. # # For the +rdoc-ref+ scheme the named reference will be returned without # creating a link. # # For the +rdoc-label+ scheme the footnote and label prefixes are stripped # when creating a link. All other contents will be linked verbatim. def handle_regexp_RDOCLINK target handle_RDOCLINK target.text end ## # This +target+ is a link where the label is different from the URL # label[url] or {long label}[url] def handle_regexp_TIDYLINK(target) text = target.text return text unless text =~ /^\{(.*)\}\[(.*?)\]$/ or text =~ /^(\S+)\[(.*?)\]$/ label = $1 url = $2 label = handle_RDOCLINK label if /^rdoc-image:/ =~ label gen_url url, label end # :section: Visitor # # These methods implement the HTML visitor. ## # Prepares the visitor for HTML generation def start_accepting @res = [] @in_list_entry = [] @list = [] end ## # Returns the generated output def end_accepting @res.join end ## # Adds +block_quote+ to the output def accept_block_quote block_quote @res << "\n
" block_quote.parts.each do |part| part.accept self end @res << "
\n" end ## # Adds +paragraph+ to the output def accept_paragraph paragraph @res << "\n

" text = paragraph.text @hard_break text = text.gsub(/\r?\n/, ' ') @res << to_html(text) @res << "

\n" end ## # Adds +verbatim+ to the output def accept_verbatim verbatim text = verbatim.text.rstrip klass = nil content = if verbatim.ruby? or parseable? text then begin tokens = RDoc::Parser::RipperStateLex.parse text klass = ' class="ruby"' result = RDoc::TokenStream.to_html tokens result = result + "\n" unless "\n" == result[-1] result rescue CGI.escapeHTML text end else CGI.escapeHTML text end if @options.pipe then @res << "\n
#{CGI.escapeHTML text}\n
\n" else @res << "\n#{content}\n" end end ## # Adds +rule+ to the output def accept_rule rule @res << "
\n" end ## # Prepares the visitor for consuming +list+ def accept_list_start(list) @list << list.type @res << html_list_name(list.type, true) @in_list_entry.push false end ## # Finishes consumption of +list+ def accept_list_end(list) @list.pop if tag = @in_list_entry.pop @res << tag end @res << html_list_name(list.type, false) << "\n" end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start(list_item) if tag = @in_list_entry.last @res << tag end @res << list_item_start(list_item, @list.last) end ## # Finishes consumption of +list_item+ def accept_list_item_end(list_item) @in_list_entry[-1] = list_end_for(@list.last) end ## # Adds +blank_line+ to the output def accept_blank_line(blank_line) # @res << annotate("

") << "\n" end ## # Adds +heading+ to the output. The headings greater than 6 are trimmed to # level 6. def accept_heading heading level = [6, heading.level].min label = heading.label @code_object @res << if @options.output_decoration "\n" else "\n" end @res << to_html(heading.text) unless @options.pipe then @res << "" @res << " " end @res << "\n" end ## # Adds +raw+ to the output def accept_raw raw @res << raw.parts.join("\n") end # :section: Utilities ## # CGI-escapes +text+ def convert_string(text) CGI.escapeHTML text end ## # Generate a link to +url+ with content +text+. Handles the special cases # for img: and link: described under handle_regexp_HYPERLINK def gen_url url, text scheme, url, id = parse_url url if %w[http https link].include?(scheme) and url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then "" else text = text.sub %r%^#{scheme}:/*%i, '' text = text.sub %r%^[*\^](\d+)$%, '\1' link = "#{text}" link = "#{link}" if /"foot/ =~ id link end end ## # Determines the HTML list element for +list_type+ and +open_tag+ def html_list_name(list_type, open_tag) tags = LIST_TYPE_TO_HTML[list_type] raise RDoc::Error, "Invalid list type: #{list_type.inspect}" unless tags tags[open_tag ? 0 : 1] end ## # Maps attributes to HTML tags def init_tags add_tag :BOLD, "", "" add_tag :TT, "", "" add_tag :EM, "", "" end ## # Returns the HTML tag for +list_type+, possible using a label from # +list_item+ def list_item_start(list_item, list_type) case list_type when :BULLET, :LALPHA, :NUMBER, :UALPHA then "

  • " when :LABEL, :NOTE then Array(list_item.label).map do |label| "
    #{to_html label}\n" end.join << "
    " else raise RDoc::Error, "Invalid list type: #{list_type.inspect}" end end ## # Returns the HTML end-tag for +list_type+ def list_end_for(list_type) case list_type when :BULLET, :LALPHA, :NUMBER, :UALPHA then "
  • " when :LABEL, :NOTE then "" else raise RDoc::Error, "Invalid list type: #{list_type.inspect}" end end ## # Returns true if text is valid ruby syntax def parseable? text verbose, $VERBOSE = $VERBOSE, nil eval("BEGIN {return true}\n#{text}") rescue SyntaxError false ensure $VERBOSE = verbose end ## # Converts +item+ to HTML using RDoc::Text#to_html def to_html item super convert_flow @am.flow item end end PK ]FVV-gems/rdoc-6.2.1.1/lib/rdoc/markup/to_label.rbnu[# frozen_string_literal: true require 'cgi' ## # Creates HTML-safe labels suitable for use in id attributes. Tidylinks are # converted to their link part and cross-reference links have the suppression # marks removed (\\SomeClass is converted to SomeClass). class RDoc::Markup::ToLabel < RDoc::Markup::Formatter attr_reader :res # :nodoc: ## # Creates a new formatter that will output HTML-safe labels def initialize markup = nil super nil, markup @markup.add_regexp_handling RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF @markup.add_regexp_handling(/(((\{.*?\})|\b\S+?)\[\S+?\])/, :TIDYLINK) add_tag :BOLD, '', '' add_tag :TT, '', '' add_tag :EM, '', '' @res = [] end ## # Converts +text+ to an HTML-safe label def convert text label = convert_flow @am.flow text CGI.escape(label).gsub('%', '-').sub(/^-/, '') end ## # Converts the CROSSREF +target+ to plain text, removing the suppression # marker, if any def handle_regexp_CROSSREF target text = target.text text.sub(/^\\/, '') end ## # Converts the TIDYLINK +target+ to just the text part def handle_regexp_TIDYLINK target text = target.text return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/ $1 end alias accept_blank_line ignore alias accept_block_quote ignore alias accept_heading ignore alias accept_list_end ignore alias accept_list_item_end ignore alias accept_list_item_start ignore alias accept_list_start ignore alias accept_paragraph ignore alias accept_raw ignore alias accept_rule ignore alias accept_verbatim ignore alias end_accepting ignore alias handle_regexp_HARD_BREAK ignore alias start_accepting ignore end PK ]<.gems/rdoc-6.2.1.1/lib/rdoc/markup/attr_span.rbnu[# frozen_string_literal: true ## # An array of attributes which parallels the characters in a string. class RDoc::Markup::AttrSpan ## # Creates a new AttrSpan for +length+ characters def initialize(length) @attrs = Array.new(length, 0) end ## # Toggles +bits+ from +start+ to +length+ def set_attrs(start, length, bits) for i in start ... (start+length) @attrs[i] |= bits end end ## # Accesses flags for character +n+ def [](n) @attrs[n] end end PK ]ua1*gems/rdoc-6.2.1.1/lib/rdoc/markup/to_bs.rbnu[# frozen_string_literal: true ## # Outputs RDoc markup with hot backspace action! You will probably need a # pager to use this output format. # # This formatter won't work on 1.8.6 because it lacks String#chars. class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc ## # Returns a new ToBs that is ready for hot backspace action! def initialize markup = nil super @in_b = false @in_em = false end ## # Sets a flag that is picked up by #annotate to do the right thing in # #convert_string def init_tags add_tag :BOLD, '+b', '-b' add_tag :EM, '+_', '-_' add_tag :TT, '' , '' # we need in_tt information maintained end ## # Makes heading text bold. def accept_heading heading use_prefix or @res << ' ' * @indent @res << @headings[heading.level][0] @in_b = true @res << attributes(heading.text) @in_b = false @res << @headings[heading.level][1] @res << "\n" end ## # Turns on or off regexp handling for +convert_string+ def annotate tag case tag when '+b' then @in_b = true when '-b' then @in_b = false when '+_' then @in_em = true when '-_' then @in_em = false end '' end ## # Calls convert_string on the result of convert_regexp_handling def convert_regexp_handling target convert_string super end ## # Adds bold or underline mixed with backspaces def convert_string string return string unless @in_b or @in_em chars = if @in_b then string.chars.map do |char| "#{char}\b#{char}" end elsif @in_em then string.chars.map do |char| "_\b#{char}" end end chars.join end end PK ]y /gems/rdoc-6.2.1.1/lib/rdoc/markup/hard_break.rbnu[# frozen_string_literal: true ## # A hard-break in the middle of a paragraph. class RDoc::Markup::HardBreak @instance = new ## # RDoc::Markup::HardBreak is a singleton def self.new @instance end ## # Calls #accept_hard_break on +visitor+ def accept visitor visitor.accept_hard_break self end def == other # :nodoc: self.class === other end def pretty_print q # :nodoc: q.text "[break]" end end PK ] 7>?9gems/rdoc-6.2.1.1/lib/rdoc/markup/to_table_of_contents.rbnu[# frozen_string_literal: true ## # Extracts just the RDoc::Markup::Heading elements from a # RDoc::Markup::Document to help build a table of contents class RDoc::Markup::ToTableOfContents < RDoc::Markup::Formatter @to_toc = nil ## # Singleton for table-of-contents generation def self.to_toc @to_toc ||= new end ## # Output accumulator attr_reader :res ## # Omits headings with a level less than the given level. attr_accessor :omit_headings_below def initialize # :nodoc: super nil @omit_headings_below = nil end ## # Adds +document+ to the output, using its heading cutoff if present def accept_document document @omit_headings_below = document.omit_headings_below super end ## # Adds +heading+ to the table of contents def accept_heading heading @res << heading unless suppressed? heading end ## # Returns the table of contents def end_accepting @res end ## # Prepares the visitor for text generation def start_accepting @omit_headings_below = nil @res = [] end ## # Returns true if +heading+ is below the display threshold def suppressed? heading return false unless @omit_headings_below heading.level > @omit_headings_below end # :stopdoc: alias accept_block_quote ignore alias accept_raw ignore alias accept_rule ignore alias accept_blank_line ignore alias accept_paragraph ignore alias accept_verbatim ignore alias accept_list_end ignore alias accept_list_item_start ignore alias accept_list_item_end ignore alias accept_list_end_bullet ignore alias accept_list_start ignore # :startdoc: end PK ]f !r r 6gems/rdoc-6.2.1.1/lib/rdoc/markup/attribute_manager.rbnu[# frozen_string_literal: true ## # Manages changes of attributes in a block of text class RDoc::Markup::AttributeManager ## # The NUL character NULL = "\000".freeze #-- # We work by substituting non-printing characters in to the text. For now # I'm assuming that I can substitute a character in the range 0..8 for a 7 # bit character without damaging the encoded string, but this might be # optimistic #++ A_PROTECT = 004 # :nodoc: ## # Special mask character to prevent inline markup handling PROTECT_ATTR = A_PROTECT.chr # :nodoc: ## # The attributes enabled for this markup object. attr_reader :attributes ## # This maps delimiters that occur around words (such as *bold* or +tt+) # where the start and end delimiters and the same. This lets us optimize # the regexp attr_reader :matching_word_pairs ## # And this is used when the delimiters aren't the same. In this case the # hash maps a pattern to the attribute character attr_reader :word_pair_map ## # This maps HTML tags to the corresponding attribute char attr_reader :html_tags ## # A \ in front of a character that would normally be processed turns off # processing. We do this by turning \< into <#{PROTECT} attr_reader :protectable ## # And this maps _regexp handling_ sequences to a name. A regexp handling # sequence is something like a WikiWord attr_reader :regexp_handlings ## # Creates a new attribute manager that understands bold, emphasized and # teletype text. def initialize @html_tags = {} @matching_word_pairs = {} @protectable = %w[<] @regexp_handlings = [] @word_pair_map = {} @attributes = RDoc::Markup::Attributes.new add_word_pair "*", "*", :BOLD add_word_pair "_", "_", :EM add_word_pair "+", "+", :TT add_html "em", :EM add_html "i", :EM add_html "b", :BOLD add_html "tt", :TT add_html "code", :TT end ## # Return an attribute object with the given turn_on and turn_off bits set def attribute(turn_on, turn_off) RDoc::Markup::AttrChanger.new turn_on, turn_off end ## # Changes the current attribute from +current+ to +new+ def change_attribute current, new diff = current ^ new attribute(new & diff, current & diff) end ## # Used by the tests to change attributes by name from +current_set+ to # +new_set+ def changed_attribute_by_name current_set, new_set current = new = 0 current_set.each do |name| current |= @attributes.bitmap_for(name) end new_set.each do |name| new |= @attributes.bitmap_for(name) end change_attribute(current, new) end ## # Copies +start_pos+ to +end_pos+ from the current string def copy_string(start_pos, end_pos) res = @str[start_pos...end_pos] res.gsub!(/\000/, '') res end ## # Map attributes like textto the sequence # \001\002\001\003, where is a per-attribute specific # character def convert_attrs(str, attrs) # first do matching ones tags = @matching_word_pairs.keys.join("") re = /(^|\W)([#{tags}])([#\\]?[\w:.\/-]+?\S?)\2(\W|$)/ 1 while str.gsub!(re) do attr = @matching_word_pairs[$2] attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr) $1 + NULL * $2.length + $3 + NULL * $2.length + $4 end # then non-matching unless @word_pair_map.empty? then @word_pair_map.each do |regexp, attr| str.gsub!(regexp) { attrs.set_attrs($`.length + $1.length, $2.length, attr) NULL * $1.length + $2 + NULL * $3.length } end end end ## # Converts HTML tags to RDoc attributes def convert_html(str, attrs) tags = @html_tags.keys.join '|' 1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) { attr = @html_tags[$1.downcase] html_length = $1.length + 2 seq = NULL * html_length attrs.set_attrs($`.length + html_length, $2.length, attr) seq + $2 + seq + NULL } end ## # Converts regexp handling sequences to RDoc attributes def convert_regexp_handlings str, attrs @regexp_handlings.each do |regexp, attribute| str.scan(regexp) do capture = $~.size == 1 ? 0 : 1 s, e = $~.offset capture attrs.set_attrs s, e - s, attribute | @attributes.regexp_handling end end end ## # Escapes regexp handling sequences of text to prevent conversion to RDoc def mask_protected_sequences # protect __send__, __FILE__, etc. @str.gsub!(/__([a-z]+)__/i, "_#{PROTECT_ATTR}_#{PROTECT_ATTR}\\1_#{PROTECT_ATTR}_#{PROTECT_ATTR}") @str.gsub!(/(\A|[^\\])\\([#{Regexp.escape @protectable.join}])/m, "\\1\\2#{PROTECT_ATTR}") @str.gsub!(/\\(\\[#{Regexp.escape @protectable.join}])/m, "\\1") end ## # Unescapes regexp handling sequences of text def unmask_protected_sequences @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000") end ## # Adds a markup class with +name+ for words wrapped in the +start+ and # +stop+ character. To make words wrapped with "*" bold: # # am.add_word_pair '*', '*', :BOLD def add_word_pair(start, stop, name) raise ArgumentError, "Word flags may not start with '<'" if start[0,1] == '<' bitmap = @attributes.bitmap_for name if start == stop then @matching_word_pairs[start] = bitmap else pattern = /(#{Regexp.escape start})(\S+)(#{Regexp.escape stop})/ @word_pair_map[pattern] = bitmap end @protectable << start[0,1] @protectable.uniq! end ## # Adds a markup class with +name+ for words surrounded by HTML tag +tag+. # To process emphasis tags: # # am.add_html 'em', :EM def add_html(tag, name) @html_tags[tag.downcase] = @attributes.bitmap_for name end ## # Adds a regexp handling for +pattern+ with +name+. A simple URL handler # would be: # # @am.add_regexp_handling(/((https?:)\S+\w)/, :HYPERLINK) def add_regexp_handling pattern, name @regexp_handlings << [pattern, @attributes.bitmap_for(name)] end ## # Processes +str+ converting attributes, HTML and regexp handlings def flow str @str = str.dup mask_protected_sequences @attrs = RDoc::Markup::AttrSpan.new @str.length convert_attrs @str, @attrs convert_html @str, @attrs convert_regexp_handlings @str, @attrs unmask_protected_sequences split_into_flow end ## # Debug method that prints a string along with its attributes def display_attributes puts puts @str.tr(NULL, "!") bit = 1 16.times do |bno| line = "" @str.length.times do |i| if (@attrs[i] & bit) == 0 line << " " else if bno.zero? line << "S" else line << ("%d" % (bno+1)) end end end puts(line) unless line =~ /^ *$/ bit <<= 1 end end ## # Splits the string into chunks by attribute change def split_into_flow res = [] current_attr = 0 str_len = @str.length # skip leading invisible text i = 0 i += 1 while i < str_len and @str[i].chr == "\0" start_pos = i # then scan the string, chunking it on attribute changes while i < str_len new_attr = @attrs[i] if new_attr != current_attr if i > start_pos res << copy_string(start_pos, i) start_pos = i end res << change_attribute(current_attr, new_attr) current_attr = new_attr if (current_attr & @attributes.regexp_handling) != 0 then i += 1 while i < str_len and (@attrs[i] & @attributes.regexp_handling) != 0 res << RDoc::Markup::RegexpHandling.new(current_attr, copy_string(start_pos, i)) start_pos = i next end end # move on, skipping any invisible characters begin i += 1 end while i < str_len and @str[i].chr == "\0" end # tidy up trailing text if start_pos < str_len res << copy_string(start_pos, str_len) end # and reset to all attributes off res << change_attribute(current_attr, 0) if current_attr != 0 res end end PK ]6WG!G!0gems/rdoc-6.2.1.1/lib/rdoc/markup/pre_process.rbnu[# frozen_string_literal: true ## # Handle common directives that can occur in a block of text: # # \:include: filename # # Directives can be escaped by preceding them with a backslash. # # RDoc plugin authors can register additional directives to be handled by # using RDoc::Markup::PreProcess::register. # # Any directive that is not built-in to RDoc (including those registered via # plugins) will be stored in the metadata hash on the CodeObject the comment # is attached to. See RDoc::Markup@Directives for the list of built-in # directives. class RDoc::Markup::PreProcess ## # An RDoc::Options instance that will be filled in with overrides from # directives attr_accessor :options ## # Adds a post-process handler for directives. The handler will be called # with the result RDoc::Comment (or text String) and the code object for the # comment (if any). def self.post_process &block @post_processors << block end ## # Registered post-processors def self.post_processors @post_processors end ## # Registers +directive+ as one handled by RDoc. If a block is given the # directive will be replaced by the result of the block, otherwise the # directive will be removed from the processed text. # # The block will be called with the directive name and the directive # parameter: # # RDoc::Markup::PreProcess.register 'my-directive' do |directive, param| # # replace text, etc. # end def self.register directive, &block @registered[directive] = block end ## # Registered directives def self.registered @registered end ## # Clears all registered directives and post-processors def self.reset @post_processors = [] @registered = {} end reset ## # Creates a new pre-processor for +input_file_name+ that will look for # included files in +include_path+ def initialize(input_file_name, include_path) @input_file_name = input_file_name @include_path = include_path @options = nil end ## # Look for directives in the given +text+. # # Options that we don't handle are yielded. If the block returns false the # directive is restored to the text. If the block returns nil or no block # was given the directive is handled according to the registered directives. # If a String was returned the directive is replaced with the string. # # If no matching directive was registered the directive is restored to the # text. # # If +code_object+ is given and the directive is unknown then the # directive's parameter is set as metadata on the +code_object+. See # RDoc::CodeObject#metadata for details. def handle text, code_object = nil, &block if RDoc::Comment === text then comment = text text = text.text end # regexp helper (square brackets for optional) # $1 $2 $3 $4 $5 # [prefix][\]:directive:[spaces][param]newline text = text.gsub(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?(\r?\n|$)/) do # skip something like ':toto::' next $& if $4.empty? and $5 and $5[0, 1] == ':' # skip if escaped next "#$1:#$3:#$4#$5\n" unless $2.empty? # This is not in handle_directive because I didn't want to pass another # argument into it if comment and $3 == 'markup' then next "#{$1.strip}\n" unless $5 comment.format = $5.downcase next "#{$1.strip}\n" end handle_directive $1, $3, $5, code_object, text.encoding, &block end if comment then comment.text = text else comment = text end self.class.post_processors.each do |handler| handler.call comment, code_object end text end ## # Performs the actions described by +directive+ and its parameter +param+. # # +code_object+ is used for directives that operate on a class or module. # +prefix+ is used to ensure the replacement for handled directives is # correct. +encoding+ is used for the include directive. # # For a list of directives in RDoc see RDoc::Markup. #-- # When 1.8.7 support is ditched prefix can be defaulted to '' def handle_directive prefix, directive, param, code_object = nil, encoding = nil blankline = "#{prefix.strip}\n" directive = directive.downcase case directive when 'arg', 'args' then return "#{prefix}:#{directive}: #{param}\n" unless code_object && code_object.kind_of?(RDoc::AnyMethod) code_object.params = param blankline when 'category' then if RDoc::Context === code_object then section = code_object.add_section param code_object.temporary_section = section end blankline # ignore category if we're not on an RDoc::Context when 'doc' then return blankline unless code_object code_object.document_self = true code_object.force_documentation = true blankline when 'enddoc' then return blankline unless code_object code_object.done_documenting = true blankline when 'include' then filename = param.split.first include_file filename, prefix, encoding when 'main' then @options.main_page = param if @options.respond_to? :main_page blankline when 'nodoc' then return blankline unless code_object code_object.document_self = nil # notify nodoc code_object.document_children = param !~ /all/i blankline when 'notnew', 'not_new', 'not-new' then return blankline unless RDoc::AnyMethod === code_object code_object.dont_rename_initialize = true blankline when 'startdoc' then return blankline unless code_object code_object.start_doc code_object.force_documentation = true blankline when 'stopdoc' then return blankline unless code_object code_object.stop_doc blankline when 'title' then @options.default_title = param if @options.respond_to? :default_title= blankline when 'yield', 'yields' then return blankline unless code_object # remove parameter &block code_object.params = code_object.params.sub(/,?\s*&\w+/, '') if code_object.params code_object.block_params = param blankline else result = yield directive, param if block_given? case result when nil then code_object.metadata[directive] = param if code_object if RDoc::Markup::PreProcess.registered.include? directive then handler = RDoc::Markup::PreProcess.registered[directive] result = handler.call directive, param if handler else result = "#{prefix}:#{directive}: #{param}\n" end when false then result = "#{prefix}:#{directive}: #{param}\n" end result end end ## # Handles the :include: _filename_ directive. # # If the first line of the included file starts with '#', and contains # an encoding information in the form 'coding:' or 'coding=', it is # removed. # # If all lines in the included file start with a '#', this leading '#' # is removed before inclusion. The included content is indented like # the :include: directive. #-- # so all content will be verbatim because of the likely space after '#'? # TODO shift left the whole file content in that case # TODO comment stop/start #-- and #++ in included file must be processed here def include_file name, indent, encoding full_name = find_include_file name unless full_name then warn "Couldn't find file to include '#{name}' from #{@input_file_name}" return '' end content = RDoc::Encoding.read_file full_name, encoding, true content = RDoc::Encoding.remove_magic_comment content # strip magic comment content = content.sub(/\A# .*coding[=:].*$/, '').lstrip # strip leading '#'s, but only if all lines start with them if content =~ /^[^#]/ then content.gsub(/^/, indent) else content.gsub(/^#?/, indent) end end ## # Look for the given file in the directory containing the current file, # and then in each of the directories specified in the RDOC_INCLUDE path def find_include_file(name) to_search = [File.dirname(@input_file_name)].concat @include_path to_search.each do |dir| full_name = File.join(dir, name) stat = File.stat(full_name) rescue next return full_name if stat.readable? end nil end end PK ]ھ/gems/rdoc-6.2.1.1/lib/rdoc/markup/attributes.rbnu[# frozen_string_literal: true ## # We manage a set of attributes. Each attribute has a symbol name and a bit # value. class RDoc::Markup::Attributes ## # The regexp handling attribute type. See RDoc::Markup#add_regexp_handling attr_reader :regexp_handling ## # Creates a new attributes set. def initialize @regexp_handling = 1 @name_to_bitmap = [ [:_REGEXP_HANDLING_, @regexp_handling], ] @next_bitmap = @regexp_handling << 1 end ## # Returns a unique bit for +name+ def bitmap_for name bitmap = @name_to_bitmap.assoc name unless bitmap then bitmap = @next_bitmap @next_bitmap <<= 1 @name_to_bitmap << [name, bitmap] else bitmap = bitmap.last end bitmap end ## # Returns a string representation of +bitmap+ def as_string bitmap return 'none' if bitmap.zero? res = [] @name_to_bitmap.each do |name, bit| res << name if (bitmap & bit) != 0 end res.join ',' end ## # yields each attribute name in +bitmap+ def each_name_of bitmap return enum_for __method__, bitmap unless block_given? @name_to_bitmap.each do |name, bit| next if bit == @regexp_handling yield name.to_s if (bitmap & bit) != 0 end end end PK ]6%Vee8gems/rdoc-6.2.1.1/lib/rdoc/markup/to_joined_paragraph.rbnu[# frozen_string_literal: true ## # Joins the parts of an RDoc::Markup::Paragraph into a single String. # # This allows for easier maintenance and testing of Markdown support. # # This formatter only works on Paragraph instances. Attempting to process # other markup syntax items will not work. class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter def initialize # :nodoc: super nil end def start_accepting # :nodoc: end def end_accepting # :nodoc: end ## # Converts the parts of +paragraph+ to a single entry. def accept_paragraph paragraph parts = paragraph.parts.chunk do |part| String === part end.map do |string, chunk| string ? chunk.join.rstrip : chunk end.flatten paragraph.parts.replace parts end alias accept_block_quote ignore alias accept_heading ignore alias accept_list_end ignore alias accept_list_item_end ignore alias accept_list_item_start ignore alias accept_list_start ignore alias accept_raw ignore alias accept_rule ignore alias accept_verbatim ignore end PK ]ԄEE)gems/rdoc-6.2.1.1/lib/rdoc/markup/list.rbnu[# frozen_string_literal: true ## # A List is a homogeneous set of ListItems. # # The supported list types include: # # :BULLET:: # An unordered list # :LABEL:: # An unordered definition list, but using an alternate RDoc::Markup syntax # :LALPHA:: # An ordered list using increasing lowercase English letters # :NOTE:: # An unordered definition list # :NUMBER:: # An ordered list using increasing Arabic numerals # :UALPHA:: # An ordered list using increasing uppercase English letters # # Definition lists behave like HTML definition lists. Each list item can # describe multiple terms. See RDoc::Markup::ListItem for how labels and # definition are stored as list items. class RDoc::Markup::List ## # The list's type attr_accessor :type ## # Items in the list attr_reader :items ## # Creates a new list of +type+ with +items+. Valid list types are: # +:BULLET+, +:LABEL+, +:LALPHA+, +:NOTE+, +:NUMBER+, +:UALPHA+ def initialize type = nil, *items @type = type @items = [] @items.concat items end ## # Appends +item+ to the list def << item @items << item end def == other # :nodoc: self.class == other.class and @type == other.type and @items == other.items end ## # Runs this list and all its #items through +visitor+ def accept visitor visitor.accept_list_start self @items.each do |item| item.accept visitor end visitor.accept_list_end self end ## # Is the list empty? def empty? @items.empty? end ## # Returns the last item in the list def last @items.last end def pretty_print q # :nodoc: q.group 2, "[list: #{@type} ", ']' do q.seplist @items do |item| q.pp item end end end ## # Appends +items+ to the list def push *items @items.concat items end end PK ]fcr.gems/rdoc-6.2.1.1/lib/rdoc/markup/list_item.rbnu[# frozen_string_literal: true ## # An item within a List that contains paragraphs, headings, etc. # # For BULLET, NUMBER, LALPHA and UALPHA lists, the label will always be nil. # For NOTE and LABEL lists, the list label may contain: # # * a single String for a single label # * an Array of Strings for a list item with multiple terms # * nil for an extra description attached to a previously labeled list item class RDoc::Markup::ListItem ## # The label for the ListItem attr_accessor :label ## # Parts of the ListItem attr_reader :parts ## # Creates a new ListItem with an optional +label+ containing +parts+ def initialize label = nil, *parts @label = label @parts = [] @parts.concat parts end ## # Appends +part+ to the ListItem def << part @parts << part end def == other # :nodoc: self.class == other.class and @label == other.label and @parts == other.parts end ## # Runs this list item and all its #parts through +visitor+ def accept visitor visitor.accept_list_item_start self @parts.each do |part| part.accept visitor end visitor.accept_list_item_end self end ## # Is the ListItem empty? def empty? @parts.empty? end ## # Length of parts in the ListItem def length @parts.length end def pretty_print q # :nodoc: q.group 2, '[item: ', ']' do case @label when Array then q.pp @label q.text ';' q.breakable when String then q.pp @label q.text ';' q.breakable end q.seplist @parts do |part| q.pp part end end end ## # Adds +parts+ to the ListItem def push *parts @parts.concat parts end end PK ]Т7gems/rdoc-6.2.1.1/lib/rdoc/markup/indented_paragraph.rbnu[# frozen_string_literal: true ## # An Indented Paragraph of text class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw ## # The indent in number of spaces attr_reader :indent ## # Creates a new IndentedParagraph containing +parts+ indented with +indent+ # spaces def initialize indent, *parts @indent = indent super(*parts) end def == other # :nodoc: super and indent == other.indent end ## # Calls #accept_indented_paragraph on +visitor+ def accept visitor visitor.accept_indented_paragraph self end ## # Joins the raw paragraph text and converts inline HardBreaks to the # +hard_break+ text followed by the indent. def text hard_break = nil @parts.map do |part| if RDoc::Markup::HardBreak === part then '%1$s%3$*2$s' % [hard_break, @indent, ' '] if hard_break else part end end.join end end PK ];;)gems/rdoc-6.2.1.1/lib/rdoc/markup/rule.rbnu[# frozen_string_literal: true ## # A horizontal rule with a weight class RDoc::Markup::Rule < Struct.new :weight ## # Calls #accept_rule on +visitor+ def accept visitor visitor.accept_rule self end def pretty_print q # :nodoc: q.group 2, '[rule:', ']' do q.pp weight end end end PK ]M(gems/rdoc-6.2.1.1/lib/rdoc/markup/raw.rbnu[# frozen_string_literal: true ## # A section of text that is added to the output document as-is class RDoc::Markup::Raw ## # The component parts of the list attr_reader :parts ## # Creates a new Raw containing +parts+ def initialize *parts @parts = [] @parts.concat parts end ## # Appends +text+ def << text @parts << text end def == other # :nodoc: self.class == other.class and @parts == other.parts end ## # Calls #accept_raw+ on +visitor+ def accept visitor visitor.accept_raw self end ## # Appends +other+'s parts def merge other @parts.concat other.parts end def pretty_print q # :nodoc: self.class.name =~ /.*::(\w{1,4})/i q.group 2, "[#{$1.downcase}: ", ']' do q.seplist @parts do |part| q.pp part end end end ## # Appends +texts+ onto this Paragraph def push *texts self.parts.concat texts end ## # The raw text def text @parts.join ' ' end end PK ]p,gems/rdoc-6.2.1.1/lib/rdoc/markup/heading.rbnu[# frozen_string_literal: true ## # A heading with a level (1-6) and text RDoc::Markup::Heading = Struct.new :level, :text do @to_html = nil @to_label = nil ## # A singleton RDoc::Markup::ToLabel formatter for headings. def self.to_label @to_label ||= RDoc::Markup::ToLabel.new end ## # A singleton plain HTML formatter for headings. Used for creating labels # for the Table of Contents def self.to_html return @to_html if @to_html markup = RDoc::Markup.new markup.add_regexp_handling RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF @to_html = RDoc::Markup::ToHtml.new nil def @to_html.handle_regexp_CROSSREF target target.text.sub(/^\\/, '') end @to_html end ## # Calls #accept_heading on +visitor+ def accept visitor visitor.accept_heading self end ## # An HTML-safe anchor reference for this header. def aref "label-#{self.class.to_label.convert text.dup}" end ## # Creates a fully-qualified label which will include the label from # +context+. This helps keep ids unique in HTML. def label context = nil label = aref label = [context.aref, label].compact.join '-' if context and context.respond_to? :aref label end ## # HTML markup of the text of this label without the surrounding header # element. def plain_html self.class.to_html.to_html(text.dup) end def pretty_print q # :nodoc: q.group 2, "[head: #{level} ", ']' do q.pp text end end end PK ]WY -gems/rdoc-6.2.1.1/lib/rdoc/markup/document.rbnu[# frozen_string_literal: true ## # A Document containing lists, headings, paragraphs, etc. class RDoc::Markup::Document include Enumerable ## # The file this document was created from. See also # RDoc::ClassModule#add_comment attr_reader :file ## # If a heading is below the given level it will be omitted from the # table_of_contents attr_accessor :omit_headings_below ## # The parts of the Document attr_reader :parts ## # Creates a new Document with +parts+ def initialize *parts @parts = [] @parts.concat parts @file = nil @omit_headings_from_table_of_contents_below = nil end ## # Appends +part+ to the document def << part case part when RDoc::Markup::Document then unless part.empty? then parts.concat part.parts parts << RDoc::Markup::BlankLine.new end when String then raise ArgumentError, "expected RDoc::Markup::Document and friends, got String" unless part.empty? else parts << part end end def == other # :nodoc: self.class == other.class and @file == other.file and @parts == other.parts end ## # Runs this document and all its #items through +visitor+ def accept visitor visitor.start_accepting visitor.accept_document self visitor.end_accepting end ## # Concatenates the given +parts+ onto the document def concat parts self.parts.concat parts end ## # Enumerator for the parts of this document def each &block @parts.each(&block) end ## # Does this document have no parts? def empty? @parts.empty? or (@parts.length == 1 and merged? and @parts.first.empty?) end ## # The file this Document was created from. def file= location @file = case location when RDoc::TopLevel then location.relative_name else location end end ## # When this is a collection of documents (#file is not set and this document # contains only other documents as its direct children) #merge replaces # documents in this class with documents from +other+ when the file matches # and adds documents from +other+ when the files do not. # # The information in +other+ is preferred over the receiver def merge other if empty? then @parts = other.parts return self end other.parts.each do |other_part| self.parts.delete_if do |self_part| self_part.file and self_part.file == other_part.file end self.parts << other_part end self end ## # Does this Document contain other Documents? def merged? RDoc::Markup::Document === @parts.first end def pretty_print q # :nodoc: start = @file ? "[doc (#{@file}): " : '[doc: ' q.group 2, start, ']' do q.seplist @parts do |part| q.pp part end end end ## # Appends +parts+ to the document def push *parts self.parts.concat parts end ## # Returns an Array of headings in the document. # # Require 'rdoc/markup/formatter' before calling this method. def table_of_contents accept RDoc::Markup::ToTableOfContents.to_toc end end PK ] t{ll0gems/rdoc-6.2.1.1/lib/rdoc/markup/to_markdown.rbnu[# frozen_string_literal: true # :markup: markdown ## # Outputs parsed markup as Markdown class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc ## # Creates a new formatter that will output Markdown format text def initialize markup = nil super @headings[1] = ['# ', ''] @headings[2] = ['## ', ''] @headings[3] = ['### ', ''] @headings[4] = ['#### ', ''] @headings[5] = ['##### ', ''] @headings[6] = ['###### ', ''] add_regexp_handling_RDOCLINK add_regexp_handling_TIDYLINK @hard_break = " \n" end ## # Maps attributes to HTML sequences def init_tags add_tag :BOLD, '**', '**' add_tag :EM, '*', '*' add_tag :TT, '`', '`' end ## # Adds a newline to the output def handle_regexp_HARD_BREAK target " \n" end ## # Finishes consumption of `list` def accept_list_end list @res << "\n" super end ## # Finishes consumption of `list_item` def accept_list_item_end list_item width = case @list_type.last when :BULLET then 4 when :NOTE, :LABEL then use_prefix 4 else @list_index[-1] = @list_index.last.succ 4 end @indent -= width end ## # Prepares the visitor for consuming `list_item` def accept_list_item_start list_item type = @list_type.last case type when :NOTE, :LABEL then bullets = Array(list_item.label).map do |label| attributes(label).strip end.join "\n" bullets << "\n:" @prefix = ' ' * @indent @indent += 4 @prefix << bullets + (' ' * (@indent - 1)) else bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' @prefix = (' ' * @indent) + bullet.ljust(4) @indent += 4 end end ## # Prepares the visitor for consuming `list` def accept_list_start list case list.type when :BULLET, :LABEL, :NOTE then @list_index << nil when :LALPHA, :NUMBER, :UALPHA then @list_index << 1 else raise RDoc::Error, "invalid list type #{list.type}" end @list_width << 4 @list_type << list.type end ## # Adds `rule` to the output def accept_rule rule use_prefix or @res << ' ' * @indent @res << '-' * 3 @res << "\n" end ## # Outputs `verbatim` indented 4 columns def accept_verbatim verbatim indent = ' ' * (@indent + 4) verbatim.parts.each do |part| @res << indent unless part == "\n" @res << part end @res << "\n" end ## # Creates a Markdown-style URL from +url+ with +text+. def gen_url url, text scheme, url, = parse_url url "[#{text.sub(%r{^#{scheme}:/*}i, '')}](#{url})" end ## # Handles rdoc- type links for footnotes. def handle_rdoc_link url case url when /^rdoc-ref:/ then $' when /^rdoc-label:footmark-(\d+)/ then "[^#{$1}]:" when /^rdoc-label:foottext-(\d+)/ then "[^#{$1}]" when /^rdoc-label:label-/ then gen_url url, $' when /^rdoc-image:/ then "![](#{$'})" when /^rdoc-[a-z]+:/ then $' end end ## # Converts the RDoc markup tidylink into a Markdown.style link. def handle_regexp_TIDYLINK target text = target.text return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/ label = $1 url = $2 if url =~ /^rdoc-label:foot/ then handle_rdoc_link url else gen_url url, label end end ## # Converts the rdoc-...: links into a Markdown.style links. def handle_regexp_RDOCLINK target handle_rdoc_link target.text end end PK ]Vnrr*gems/rdoc-6.2.1.1/lib/rdoc/ri/formatter.rbnu[# frozen_string_literal: true ## # For RubyGems backwards compatibility module RDoc::RI::Formatter # :nodoc: end PK ] qh&gems/rdoc-6.2.1.1/lib/rdoc/ri/paths.rbnu[# frozen_string_literal: true require 'rdoc/rdoc' ## # The directories where ri data lives. Paths can be enumerated via ::each, or # queried individually via ::system_dir, ::site_dir, ::home_dir and ::gem_dir. module RDoc::RI::Paths #:stopdoc: require 'rbconfig' version = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] BASE = if RbConfig::CONFIG.key? 'ridir' then File.join RbConfig::CONFIG['ridir'], version else File.join RbConfig::CONFIG['datadir'], 'ri', version end homedir = begin File.expand_path('~') rescue ArgumentError end homedir ||= ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH'] # for 1.8 compatibility HOMEDIR = if homedir then File.join homedir, ".rdoc" end #:startdoc: ## # Iterates over each selected path yielding the directory and type. # # Yielded types: # :system:: Where Ruby's ri data is stored. Yielded when +system+ is # true # :site:: Where ri for installed libraries are stored. Yielded when # +site+ is true. Normally no ri data is stored here. # :home:: ~/.rdoc. Yielded when +home+ is true. # :gem:: ri data for an installed gem. Yielded when +gems+ is true. # :extra:: ri data directory from the command line. Yielded for each # entry in +extra_dirs+ def self.each system = true, site = true, home = true, gems = :latest, *extra_dirs # :yields: directory, type return enum_for __method__, system, site, home, gems, *extra_dirs unless block_given? extra_dirs.each do |dir| yield dir, :extra end yield system_dir, :system if system yield site_dir, :site if site yield home_dir, :home if home and HOMEDIR gemdirs(gems).each do |dir| yield dir, :gem end if gems nil end ## # The ri directory for the gem with +gem_name+. def self.gem_dir name, version req = Gem::Requirement.new "= #{version}" spec = Gem::Specification.find_by_name name, req File.join spec.doc_dir, 'ri' end ## # The latest installed gems' ri directories. +filter+ can be :all or # :latest. # # A +filter+ :all includes all versions of gems and includes gems without # ri documentation. def self.gemdirs filter = :latest ri_paths = {} all = Gem::Specification.map do |spec| [File.join(spec.doc_dir, 'ri'), spec.name, spec.version] end if filter == :all then gemdirs = [] all.group_by do |_, name, _| name end.sort_by do |group, _| group end.map do |group, items| items.sort_by do |_, _, version| version end.reverse_each do |dir,| gemdirs << dir end end return gemdirs end all.each do |dir, name, ver| next unless File.exist? dir if ri_paths[name].nil? or ver > ri_paths[name].first then ri_paths[name] = [ver, name, dir] end end ri_paths.sort_by { |_, (_, name, _)| name }.map { |k, v| v.last } rescue LoadError [] end ## # The location of the rdoc data in the user's home directory. # # Like ::system, ri data in the user's home directory is rare and predates # libraries distributed via RubyGems. ri data is rarely generated into this # directory. def self.home_dir HOMEDIR end ## # Returns existing directories from the selected documentation directories # as an Array. # # See also ::each def self.path(system = true, site = true, home = true, gems = :latest, *extra_dirs) path = raw_path system, site, home, gems, *extra_dirs path.select { |directory| File.directory? directory } end ## # Returns selected documentation directories including nonexistent # directories. # # See also ::each def self.raw_path(system, site, home, gems, *extra_dirs) path = [] each(system, site, home, gems, *extra_dirs) do |dir, type| path << dir end path.compact end ## # The location of ri data installed into the site dir. # # Historically this was available for documentation installed by Ruby # libraries predating RubyGems. It is unlikely to contain any content for # modern Ruby installations. def self.site_dir File.join BASE, 'site' end ## # The location of the built-in ri data. # # This data is built automatically when `make` is run when Ruby is # installed. If you did not install Ruby by hand you may need to install # the documentation yourself. Please consult the documentation for your # package manager or Ruby installer for details. You can also use the # rdoc-data gem to install system ri data for common versions of Ruby. def self.system_dir File.join BASE, 'system' end end PK ]tUU&gems/rdoc-6.2.1.1/lib/rdoc/ri/store.rbnu[# frozen_string_literal: true module RDoc::RI Store = RDoc::Store # :nodoc: end PK ]L!66%gems/rdoc-6.2.1.1/lib/rdoc/ri/task.rbnu[# frozen_string_literal: true begin gem 'rdoc' rescue Gem::LoadError end unless defined?(RDoc) require 'rdoc/task' ## # RDoc::RI::Task creates ri data in ./.rdoc for your project. # # It contains the following tasks: # # [ri] # Build ri data # # [clobber_ri] # Delete ri data files. This target is automatically added to the main # clobber target. # # [reri] # Rebuild the ri data from scratch even if they are not out of date. # # Simple example: # # require 'rdoc/ri/task' # # RDoc::RI::Task.new do |ri| # ri.main = 'README.rdoc' # ri.rdoc_files.include 'README.rdoc', 'lib/**/*.rb' # end # # For further configuration details see RDoc::Task. class RDoc::RI::Task < RDoc::Task DEFAULT_NAMES = { # :nodoc: :clobber_rdoc => :clobber_ri, :rdoc => :ri, :rerdoc => :reri, } ## # Create an ri task with the given name. See RDoc::Task for documentation on # setting names. def initialize name = DEFAULT_NAMES # :yield: self super end def clobber_task_description # :nodoc: "Remove RI data files" end ## # Sets default task values def defaults super @rdoc_dir = '.rdoc' end def rdoc_task_description # :nodoc: 'Build RI data files' end def rerdoc_task_description # :nodoc: 'Rebuild RI data files' end end PK ]yy'gems/rdoc-6.2.1.1/lib/rdoc/ri/driver.rbnu[# frozen_string_literal: true require 'abbrev' require 'optparse' begin require 'readline' rescue LoadError end begin require 'win32console' rescue LoadError end require 'rdoc' ## # For RubyGems backwards compatibility require 'rdoc/ri/formatter' ## # The RI driver implements the command-line ri tool. # # The driver supports: # * loading RI data from: # * Ruby's standard library # * RubyGems # * ~/.rdoc # * A user-supplied directory # * Paging output (uses RI_PAGER environment variable, PAGER environment # variable or the less, more and pager programs) # * Interactive mode with tab-completion # * Abbreviated names (ri Zl shows Zlib documentation) # * Colorized output # * Merging output from multiple RI data sources class RDoc::RI::Driver ## # Base Driver error class class Error < RDoc::RI::Error; end ## # Raised when a name isn't found in the ri data stores class NotFoundError < Error def initialize(klass, suggestions = nil) # :nodoc: @klass = klass @suggestions = suggestions end ## # Name that wasn't found def name @klass end def message # :nodoc: str = "Nothing known about #{@klass}" if @suggestions and !@suggestions.empty? str += "\nDid you mean? #{@suggestions.join("\n ")}" end str end end ## # Show all method documentation following a class or module attr_accessor :show_all ## # An RDoc::RI::Store for each entry in the RI path attr_accessor :stores ## # Controls the user of the pager vs $stdout attr_accessor :use_stdout ## # Default options for ri def self.default_options options = {} options[:interactive] = false options[:profile] = false options[:show_all] = false options[:use_stdout] = !$stdout.tty? options[:width] = 72 # By default all standard paths are used. options[:use_system] = true options[:use_site] = true options[:use_home] = true options[:use_gems] = true options[:extra_doc_dirs] = [] return options end ## # Dump +data_path+ using pp def self.dump data_path require 'pp' File.open data_path, 'rb' do |io| pp Marshal.load(io.read) end end ## # Parses +argv+ and returns a Hash of options def self.process_args argv options = default_options opts = OptionParser.new do |opt| opt.accept File do |file,| File.readable?(file) and not File.directory?(file) and file end opt.program_name = File.basename $0 opt.version = RDoc::VERSION opt.release = nil opt.summary_indent = ' ' * 4 opt.banner = <<-EOT Usage: #{opt.program_name} [options] [name ...] Where name can be: Class | Module | Module::Class Class::method | Class#method | Class.method | method gem_name: | gem_name:README | gem_name:History All class names may be abbreviated to their minimum unambiguous form. If a name is ambiguous, all valid options will be listed. A '.' matches either class or instance methods, while #method matches only instance and ::method matches only class methods. README and other files may be displayed by prefixing them with the gem name they're contained in. If the gem name is followed by a ':' all files in the gem will be shown. The file name extension may be omitted where it is unambiguous. For example: #{opt.program_name} Fil #{opt.program_name} File #{opt.program_name} File.new #{opt.program_name} zip #{opt.program_name} rdoc:README Note that shell quoting or escaping may be required for method names containing punctuation: #{opt.program_name} 'Array.[]' #{opt.program_name} compact\\! To see the default directories #{opt.program_name} will search, run: #{opt.program_name} --list-doc-dirs Specifying the --system, --site, --home, --gems, or --doc-dir options will limit ri to searching only the specified directories. ri options may be set in the RI environment variable. The ri pager can be set with the RI_PAGER environment variable or the PAGER environment variable. EOT opt.separator nil opt.separator "Options:" opt.separator nil opt.on("--[no-]interactive", "-i", "In interactive mode you can repeatedly", "look up methods with autocomplete.") do |interactive| options[:interactive] = interactive end opt.separator nil opt.on("--[no-]all", "-a", "Show all documentation for a class or", "module.") do |show_all| options[:show_all] = show_all end opt.separator nil opt.on("--[no-]list", "-l", "List classes ri knows about.") do |list| options[:list] = list end opt.separator nil opt.on("--[no-]pager", "Send output to a pager,", "rather than directly to stdout.") do |use_pager| options[:use_stdout] = !use_pager end opt.separator nil opt.on("-T", "Synonym for --no-pager.") do options[:use_stdout] = true end opt.separator nil opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger, "Set the width of the output.") do |width| options[:width] = width end opt.separator nil opt.on("--server[=PORT]", Integer, "Run RDoc server on the given port.", "The default port is 8214.") do |port| options[:server] = port || 8214 end opt.separator nil formatters = RDoc::Markup.constants.grep(/^To[A-Z][a-z]+$/).sort formatters = formatters.sort.map do |formatter| formatter.to_s.sub('To', '').downcase end formatters -= %w[html label test] # remove useless output formats opt.on("--format=NAME", "-f", "Use the selected formatter. The default", "formatter is bs for paged output and ansi", "otherwise. Valid formatters are:", "#{formatters.join(', ')}.", formatters) do |value| options[:formatter] = RDoc::Markup.const_get "To#{value.capitalize}" end opt.separator nil opt.on("--help", "-h", "Show help and exit.") do puts opts exit end opt.separator nil opt.on("--version", "-v", "Output version information and exit.") do puts "#{opts.program_name} #{opts.version}" exit end opt.separator nil opt.separator "Data source options:" opt.separator nil opt.on("--[no-]list-doc-dirs", "List the directories from which ri will", "source documentation on stdout and exit.") do |list_doc_dirs| options[:list_doc_dirs] = list_doc_dirs end opt.separator nil opt.on("--doc-dir=DIRNAME", "-d", Array, "List of directories from which to source", "documentation in addition to the standard", "directories. May be repeated.") do |value| value.each do |dir| unless File.directory? dir then raise OptionParser::InvalidArgument, "#{dir} is not a directory" end options[:extra_doc_dirs] << File.expand_path(dir) end end opt.separator nil opt.on("--no-standard-docs", "Do not include documentation from", "the Ruby standard library, site_lib,", "installed gems, or ~/.rdoc.", "Use with --doc-dir.") do options[:use_system] = false options[:use_site] = false options[:use_gems] = false options[:use_home] = false end opt.separator nil opt.on("--[no-]system", "Include documentation from Ruby's", "standard library. Defaults to true.") do |value| options[:use_system] = value end opt.separator nil opt.on("--[no-]site", "Include documentation from libraries", "installed in site_lib.", "Defaults to true.") do |value| options[:use_site] = value end opt.separator nil opt.on("--[no-]gems", "Include documentation from RubyGems.", "Defaults to true.") do |value| options[:use_gems] = value end opt.separator nil opt.on("--[no-]home", "Include documentation stored in ~/.rdoc.", "Defaults to true.") do |value| options[:use_home] = value end opt.separator nil opt.separator "Debug options:" opt.separator nil opt.on("--[no-]profile", "Run with the ruby profiler.") do |value| options[:profile] = value end opt.separator nil opt.on("--dump=CACHE", File, "Dump data from an ri cache or data file.") do |value| options[:dump_path] = value end end argv = ENV['RI'].to_s.split.concat argv opts.parse! argv options[:names] = argv options[:use_stdout] ||= !$stdout.tty? options[:use_stdout] ||= options[:interactive] options[:width] ||= 72 options rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e puts opts puts puts e exit 1 end ## # Runs the ri command line executable using +argv+ def self.run argv = ARGV options = process_args argv if options[:dump_path] then dump options[:dump_path] return end ri = new options ri.run end ## # Creates a new driver using +initial_options+ from ::process_args def initialize initial_options = {} @paging = false @classes = nil options = self.class.default_options.update(initial_options) @formatter_klass = options[:formatter] require 'profile' if options[:profile] @names = options[:names] @list = options[:list] @doc_dirs = [] @stores = [] RDoc::RI::Paths.each(options[:use_system], options[:use_site], options[:use_home], options[:use_gems], *options[:extra_doc_dirs]) do |path, type| @doc_dirs << path store = RDoc::RI::Store.new path, type store.load_cache @stores << store end @list_doc_dirs = options[:list_doc_dirs] @interactive = options[:interactive] @server = options[:server] @use_stdout = options[:use_stdout] @show_all = options[:show_all] @width = options[:width] # pager process for jruby @jruby_pager_process = nil end ## # Adds paths for undocumented classes +also_in+ to +out+ def add_also_in out, also_in return if also_in.empty? out << RDoc::Markup::Rule.new(1) out << RDoc::Markup::Paragraph.new("Also found in:") paths = RDoc::Markup::Verbatim.new also_in.each do |store| paths.parts.push store.friendly_path, "\n" end out << paths end ## # Adds a class header to +out+ for class +name+ which is described in # +classes+. def add_class out, name, classes heading = if classes.all? { |klass| klass.module? } then name else superclass = classes.map do |klass| klass.superclass unless klass.module? end.compact.shift || 'Object' superclass = superclass.full_name unless String === superclass "#{name} < #{superclass}" end out << RDoc::Markup::Heading.new(1, heading) out << RDoc::Markup::BlankLine.new end ## # Adds "(from ...)" to +out+ for +store+ def add_from out, store out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})") end ## # Adds +extends+ to +out+ def add_extends out, extends add_extension_modules out, 'Extended by', extends end ## # Adds a list of +extensions+ to this module of the given +type+ to +out+. # add_includes and add_extends call this, so you should use those directly. def add_extension_modules out, type, extensions return if extensions.empty? out << RDoc::Markup::Rule.new(1) out << RDoc::Markup::Heading.new(1, "#{type}:") extensions.each do |modules, store| if modules.length == 1 then add_extension_modules_single out, store, modules.first else add_extension_modules_multiple out, store, modules end end end ## # Renders multiple included +modules+ from +store+ to +out+. def add_extension_modules_multiple out, store, modules # :nodoc: out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})") wout, with = modules.partition { |incl| incl.comment.empty? } out << RDoc::Markup::BlankLine.new unless with.empty? with.each do |incl| out << RDoc::Markup::Paragraph.new(incl.name) out << RDoc::Markup::BlankLine.new out << incl.comment end unless wout.empty? then verb = RDoc::Markup::Verbatim.new wout.each do |incl| verb.push incl.name, "\n" end out << verb end end ## # Adds a single extension module +include+ from +store+ to +out+ def add_extension_modules_single out, store, include # :nodoc: name = include.name path = store.friendly_path out << RDoc::Markup::Paragraph.new("#{name} (from #{path})") if include.comment then out << RDoc::Markup::BlankLine.new out << include.comment end end ## # Adds +includes+ to +out+ def add_includes out, includes add_extension_modules out, 'Includes', includes end ## # Looks up the method +name+ and adds it to +out+ def add_method out, name filtered = lookup_method name method_out = method_document name, filtered out.concat method_out.parts end ## # Adds documentation for all methods in +klass+ to +out+ def add_method_documentation out, klass klass.method_list.each do |method| begin add_method out, method.full_name rescue NotFoundError next end end end ## # Adds a list of +methods+ to +out+ with a heading of +name+ def add_method_list out, methods, name return if methods.empty? out << RDoc::Markup::Heading.new(1, "#{name}:") out << RDoc::Markup::BlankLine.new if @use_stdout and !@interactive then out.concat methods.map { |method| RDoc::Markup::Verbatim.new method } else out << RDoc::Markup::IndentedParagraph.new(2, methods.join(', ')) end out << RDoc::Markup::BlankLine.new end ## # Returns ancestor classes of +klass+ def ancestors_of klass ancestors = [] unexamined = [klass] seen = [] loop do break if unexamined.empty? current = unexamined.shift seen << current stores = classes[current] break unless stores and not stores.empty? klasses = stores.map do |store| store.ancestors[current] end.flatten.uniq klasses = klasses - seen ancestors.concat klasses unexamined.concat klasses end ancestors.reverse end ## # For RubyGems backwards compatibility def class_cache # :nodoc: end ## # Builds a RDoc::Markup::Document from +found+, +klasess+ and +includes+ def class_document name, found, klasses, includes, extends also_in = [] out = RDoc::Markup::Document.new add_class out, name, klasses add_includes out, includes add_extends out, extends found.each do |store, klass| render_class out, store, klass, also_in end add_also_in out, also_in out end ## # Adds the class +comment+ to +out+. def class_document_comment out, comment # :nodoc: unless comment.empty? then out << RDoc::Markup::Rule.new(1) if comment.merged? then parts = comment.parts parts = parts.zip [RDoc::Markup::BlankLine.new] * parts.length parts.flatten! parts.pop out.concat parts else out << comment end end end ## # Adds the constants from +klass+ to the Document +out+. def class_document_constants out, klass # :nodoc: return if klass.constants.empty? out << RDoc::Markup::Heading.new(1, "Constants:") out << RDoc::Markup::BlankLine.new list = RDoc::Markup::List.new :NOTE constants = klass.constants.sort_by { |constant| constant.name } list.items.concat constants.map { |constant| parts = constant.comment.parts if constant.comment parts << RDoc::Markup::Paragraph.new('[not documented]') if parts.empty? RDoc::Markup::ListItem.new(constant.name, *parts) } out << list out << RDoc::Markup::BlankLine.new end ## # Hash mapping a known class or module to the stores it can be loaded from def classes return @classes if @classes @classes = {} @stores.each do |store| store.cache[:modules].each do |mod| # using default block causes searched-for modules to be added @classes[mod] ||= [] @classes[mod] << store end end @classes end ## # Returns the stores wherein +name+ is found along with the classes, # extends and includes that match it def classes_and_includes_and_extends_for name klasses = [] extends = [] includes = [] found = @stores.map do |store| begin klass = store.load_class name klasses << klass extends << [klass.extends, store] if klass.extends includes << [klass.includes, store] if klass.includes [store, klass] rescue RDoc::Store::MissingFileError end end.compact extends.reject! do |modules,| modules.empty? end includes.reject! do |modules,| modules.empty? end [found, klasses, includes, extends] end ## # Completes +name+ based on the caches. For Readline def complete name completions = [] klass, selector, method = parse_name name complete_klass name, klass, selector, method, completions complete_method name, klass, selector, completions completions.sort.uniq end def complete_klass name, klass, selector, method, completions # :nodoc: klasses = classes.keys # may need to include Foo when given Foo:: klass_name = method ? name : klass if name !~ /#|\./ then completions.replace klasses.grep(/^#{Regexp.escape klass_name}[^:]*$/) completions.concat klasses.grep(/^#{Regexp.escape name}[^:]*$/) if name =~ /::$/ completions << klass if classes.key? klass # to complete a method name elsif selector then completions << klass if classes.key? klass elsif classes.key? klass_name then completions << klass_name end end def complete_method name, klass, selector, completions # :nodoc: if completions.include? klass and name =~ /#|\.|::/ then methods = list_methods_matching name if not methods.empty? then # remove Foo if given Foo:: and a method was found completions.delete klass elsif selector then # replace Foo with Foo:: as given completions.delete klass completions << "#{klass}#{selector}" end completions.concat methods end end ## # Converts +document+ to text and writes it to the pager def display document page do |io| f = formatter(io) f.width = @width if @width and f.respond_to?(:width) text = document.accept f io.write text end end ## # Outputs formatted RI data for class +name+. Groups undocumented classes def display_class name return if name =~ /#|\./ found, klasses, includes, extends = classes_and_includes_and_extends_for name return if found.empty? out = class_document name, found, klasses, includes, extends display out end ## # Outputs formatted RI data for method +name+ def display_method name out = RDoc::Markup::Document.new add_method out, name display out end ## # Outputs formatted RI data for the class or method +name+. # # Returns true if +name+ was found, false if it was not an alternative could # be guessed, raises an error if +name+ couldn't be guessed. def display_name name if name =~ /\w:(\w|$)/ then display_page name return true end return true if display_class name display_method name if name =~ /::|#|\./ true rescue NotFoundError matches = list_methods_matching name if name =~ /::|#|\./ matches = classes.keys.grep(/^#{Regexp.escape name}/) if matches.empty? raise if matches.empty? page do |io| io.puts "#{name} not found, maybe you meant:" io.puts io.puts matches.sort.join("\n") end false end ## # Displays each name in +name+ def display_names names names.each do |name| name = expand_name name display_name name end end ## # Outputs formatted RI data for page +name+. def display_page name store_name, page_name = name.split ':', 2 store = @stores.find { |s| s.source == store_name } return display_page_list store if page_name.empty? pages = store.cache[:pages] unless pages.include? page_name then found_names = pages.select do |n| n =~ /#{Regexp.escape page_name}\.[^.]+$/ end if found_names.length.zero? then return display_page_list store, pages elsif found_names.length > 1 then return display_page_list store, found_names, page_name end page_name = found_names.first end page = store.load_page page_name display page.comment end ## # Outputs a formatted RI page list for the pages in +store+. def display_page_list store, pages = store.cache[:pages], search = nil out = RDoc::Markup::Document.new title = if search then "#{search} pages" else 'Pages' end out << RDoc::Markup::Heading.new(1, "#{title} in #{store.friendly_path}") out << RDoc::Markup::BlankLine.new list = RDoc::Markup::List.new(:BULLET) pages.each do |page| list << RDoc::Markup::Paragraph.new(page) end out << list display out end def check_did_you_mean # :nodoc: if defined? DidYouMean::SpellChecker true else begin require 'did_you_mean' if defined? DidYouMean::SpellChecker true else false end rescue LoadError false end end end ## # Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da" # will be expanded to Zlib::DataError. def expand_class klass class_names = classes.keys ary = class_names.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z")) if ary.length != 1 && ary.first != klass if check_did_you_mean suggestions = DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass) raise NotFoundError.new(klass, suggestions) else raise NotFoundError, klass end end ary.first end ## # Expands the class portion of +name+ into a fully-qualified class. See # #expand_class. def expand_name name klass, selector, method = parse_name name return [selector, method].join if klass.empty? case selector when ':' then [find_store(klass), selector, method] else [expand_class(klass), selector, method] end.join end ## # Filters the methods in +found+ trying to find a match for +name+. def filter_methods found, name regexp = name_regexp name filtered = found.find_all do |store, methods| methods.any? { |method| method.full_name =~ regexp } end return filtered unless filtered.empty? found end ## # Yields items matching +name+ including the store they were found in, the # class being searched for, the class they were found in (an ancestor) the # types of methods to look up (from #method_type), and the method name being # searched for def find_methods name klass, selector, method = parse_name name types = method_type selector klasses = nil ambiguous = klass.empty? if ambiguous then klasses = classes.keys else klasses = ancestors_of klass klasses.unshift klass end methods = [] klasses.each do |ancestor| ancestors = classes[ancestor] next unless ancestors klass = ancestor if ambiguous ancestors.each do |store| methods << [store, klass, ancestor, types, method] end end methods = methods.sort_by do |_, k, a, _, m| [k, a, m].compact end methods.each do |item| yield(*item) # :yields: store, klass, ancestor, types, method end self end ## # Finds the given +pager+ for jruby. Returns an IO if +pager+ was found. # # Returns false if +pager+ does not exist. # # Returns nil if the jruby JVM doesn't support ProcessBuilder redirection # (1.6 and older). def find_pager_jruby pager require 'java' require 'shellwords' return nil unless java.lang.ProcessBuilder.constants.include? :Redirect pager = Shellwords.split pager pb = java.lang.ProcessBuilder.new(*pager) pb = pb.redirect_output java.lang.ProcessBuilder::Redirect::INHERIT @jruby_pager_process = pb.start input = @jruby_pager_process.output_stream io = input.to_io io.sync = true io rescue java.io.IOException false end ## # Finds a store that matches +name+ which can be the name of a gem, "ruby", # "home" or "site". # # See also RDoc::Store#source def find_store name @stores.each do |store| source = store.source return source if source == name return source if store.type == :gem and source =~ /^#{Regexp.escape name}-\d/ end raise RDoc::RI::Driver::NotFoundError, name end ## # Creates a new RDoc::Markup::Formatter. If a formatter is given with -f, # use it. If we're outputting to a pager, use bs, otherwise ansi. def formatter(io) if @formatter_klass then @formatter_klass.new elsif paging? or !io.tty? then RDoc::Markup::ToBs.new else RDoc::Markup::ToAnsi.new end end ## # Runs ri interactively using Readline if it is available. def interactive puts "\nEnter the method name you want to look up." if defined? Readline then Readline.completion_proc = method :complete puts "You can use tab to autocomplete." end puts "Enter a blank line to exit.\n\n" loop do name = if defined? Readline then Readline.readline ">> " else print ">> " $stdin.gets end return if name.nil? or name.empty? begin display_name expand_name(name.strip) rescue NotFoundError => e puts e.message end end rescue Interrupt exit end ## # Is +file+ in ENV['PATH']? def in_path? file return true if file =~ %r%\A/% and File.exist? file ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path| File.exist? File.join(path, file) end end ## # Lists classes known to ri starting with +names+. If +names+ is empty all # known classes are shown. def list_known_classes names = [] classes = [] stores.each do |store| classes << store.module_names end classes = classes.flatten.uniq.sort unless names.empty? then filter = Regexp.union names.map { |name| /^#{name}/ } classes = classes.grep filter end page do |io| if paging? or io.tty? then if names.empty? then io.puts "Classes and Modules known to ri:" else io.puts "Classes and Modules starting with #{names.join ', '}:" end io.puts end io.puts classes.join("\n") end end ## # Returns an Array of methods matching +name+ def list_methods_matching name found = [] find_methods name do |store, klass, ancestor, types, method| if types == :instance or types == :both then methods = store.instance_methods[ancestor] if methods then matches = methods.grep(/^#{Regexp.escape method.to_s}/) matches = matches.map do |match| "#{klass}##{match}" end found.concat matches end end if types == :class or types == :both then methods = store.class_methods[ancestor] next unless methods matches = methods.grep(/^#{Regexp.escape method.to_s}/) matches = matches.map do |match| "#{klass}::#{match}" end found.concat matches end end found.uniq end ## # Loads RI data for method +name+ on +klass+ from +store+. +type+ and # +cache+ indicate if it is a class or instance method. def load_method store, cache, klass, type, name methods = store.send(cache)[klass] return unless methods method = methods.find do |method_name| method_name == name end return unless method store.load_method klass, "#{type}#{method}" rescue RDoc::Store::MissingFileError => e comment = RDoc::Comment.new("missing documentation at #{e.file}").parse method = RDoc::AnyMethod.new nil, name method.comment = comment method end ## # Returns an Array of RI data for methods matching +name+ def load_methods_matching name found = [] find_methods name do |store, klass, ancestor, types, method| methods = [] methods << load_method(store, :class_methods, ancestor, '::', method) if [:class, :both].include? types methods << load_method(store, :instance_methods, ancestor, '#', method) if [:instance, :both].include? types found << [store, methods.compact] end found.reject do |path, methods| methods.empty? end end ## # Returns a filtered list of methods matching +name+ def lookup_method name found = load_methods_matching name if found.empty? if check_did_you_mean methods = [] _, _, method_name = parse_name name find_methods name do |store, klass, ancestor, types, method| methods.push(*store.class_methods[klass]) if [:class, :both].include? types methods.push(*store.instance_methods[klass]) if [:instance, :both].include? types end methods = methods.uniq suggestions = DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name) raise NotFoundError.new(name, suggestions) else raise NotFoundError, name end end filter_methods found, name end ## # Builds a RDoc::Markup::Document from +found+, +klasses+ and +includes+ def method_document name, filtered out = RDoc::Markup::Document.new out << RDoc::Markup::Heading.new(1, name) out << RDoc::Markup::BlankLine.new filtered.each do |store, methods| methods.each do |method| render_method out, store, method, name end end out end ## # Returns the type of method (:both, :instance, :class) for +selector+ def method_type selector case selector when '.', nil then :both when '#' then :instance else :class end end ## # Returns a regular expression for +name+ that will match an # RDoc::AnyMethod's name. def name_regexp name klass, type, name = parse_name name case type when '#', '::' then /^#{klass}#{type}#{Regexp.escape name}$/ else /^#{klass}(#|::)#{Regexp.escape name}$/ end end ## # Paginates output through a pager program. def page if pager = setup_pager then begin yield pager ensure pager.close @jruby_pager_process.wait_for if @jruby_pager_process end else yield $stdout end rescue Errno::EPIPE ensure @paging = false end ## # Are we using a pager? def paging? @paging end ## # Extracts the class, selector and method name parts from +name+ like # Foo::Bar#baz. # # NOTE: Given Foo::Bar, Bar is considered a class even though it may be a # method def parse_name name parts = name.split(/(::?|#|\.)/) if parts.length == 1 then if parts.first =~ /^[a-z]|^([%&*+\/<>^`|~-]|\+@|-@|<<|<=>?|===?|=>|=~|>>|\[\]=?|~@)$/ then type = '.' meth = parts.pop else type = nil meth = nil end elsif parts.length == 2 or parts.last =~ /::|#|\./ then type = parts.pop meth = nil elsif parts[1] == ':' then klass = parts.shift type = parts.shift meth = parts.join elsif parts[-2] != '::' or parts.last !~ /^[A-Z]/ then meth = parts.pop type = parts.pop end klass ||= parts.join [klass, type, meth] end ## # Renders the +klass+ from +store+ to +out+. If the klass has no # documentable items the class is added to +also_in+ instead. def render_class out, store, klass, also_in # :nodoc: comment = klass.comment # TODO the store's cache should always return an empty Array class_methods = store.class_methods[klass.full_name] || [] instance_methods = store.instance_methods[klass.full_name] || [] attributes = store.attributes[klass.full_name] || [] if comment.empty? and instance_methods.empty? and class_methods.empty? then also_in << store return end add_from out, store class_document_comment out, comment if class_methods or instance_methods or not klass.constants.empty? then out << RDoc::Markup::Rule.new(1) end class_document_constants out, klass add_method_list out, class_methods, 'Class methods' add_method_list out, instance_methods, 'Instance methods' add_method_list out, attributes, 'Attributes' add_method_documentation out, klass if @show_all end def render_method out, store, method, name # :nodoc: out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})") unless name =~ /^#{Regexp.escape method.parent_name}/ then out << RDoc::Markup::Heading.new(3, "Implementation from #{method.parent_name}") end out << RDoc::Markup::Rule.new(1) render_method_arguments out, method.arglists render_method_superclass out, method if method.is_alias_for al = method.is_alias_for alias_for = store.load_method al.parent_name, "#{al.name_prefix}#{al.name}" render_method_comment out, method, alias_for else render_method_comment out, method end end def render_method_arguments out, arglists # :nodoc: return unless arglists arglists = arglists.chomp.split "\n" arglists = arglists.map { |line| line + "\n" } out << RDoc::Markup::Verbatim.new(*arglists) out << RDoc::Markup::Rule.new(1) end def render_method_comment out, method, alias_for = nil# :nodoc: if alias_for unless method.comment.nil? or method.comment.empty? out << RDoc::Markup::BlankLine.new out << method.comment end out << RDoc::Markup::BlankLine.new out << RDoc::Markup::Paragraph.new("(This method is an alias for #{alias_for.full_name}.)") out << RDoc::Markup::BlankLine.new out << alias_for.comment out << RDoc::Markup::BlankLine.new else out << RDoc::Markup::BlankLine.new out << method.comment out << RDoc::Markup::BlankLine.new end end def render_method_superclass out, method # :nodoc: return unless method.respond_to?(:superclass_method) and method.superclass_method out << RDoc::Markup::BlankLine.new out << RDoc::Markup::Heading.new(4, "(Uses superclass method #{method.superclass_method})") out << RDoc::Markup::Rule.new(1) end ## # Looks up and displays ri data according to the options given. def run if @list_doc_dirs then puts @doc_dirs elsif @list then list_known_classes @names elsif @server then start_server elsif @interactive or @names.empty? then interactive else display_names @names end rescue NotFoundError => e abort e.message end ## # Sets up a pager program to pass output through. Tries the RI_PAGER and # PAGER environment variables followed by pager, less then more. def setup_pager return if @use_stdout jruby = RUBY_ENGINE == 'jruby' pagers = [ENV['RI_PAGER'], ENV['PAGER'], 'pager', 'less', 'more'] pagers.compact.uniq.each do |pager| next unless pager pager_cmd = pager.split.first next unless in_path? pager_cmd if jruby then case io = find_pager_jruby(pager) when nil then break when false then next else io end else io = IO.popen(pager, 'w') rescue next end next if $? and $?.pid == io.pid and $?.exited? # pager didn't work @paging = true return io end @use_stdout = true nil end ## # Starts a WEBrick server for ri. def start_server require 'webrick' server = WEBrick::HTTPServer.new :Port => @server extra_doc_dirs = @stores.map {|s| s.type == :extra ? s.path : nil}.compact server.mount '/', RDoc::Servlet, nil, extra_doc_dirs trap 'INT' do server.shutdown end trap 'TERM' do server.shutdown end server.start end end PK ]y&gems/rdoc-6.2.1.1/lib/rdoc/encoding.rbnu[# coding: US-ASCII # frozen_string_literal: true ## # This class is a wrapper around File IO and Encoding that helps RDoc load # files and convert them to the correct encoding. module RDoc::Encoding HEADER_REGEXP = /^ (?: \A\#!.*\n | ^\#\s+frozen[-_]string[-_]literal[=:].+\n | ^\#[^\n]+\b(?:en)?coding[=:]\s*(?[^\s;]+).*\n | <\?xml[^?]*encoding=(?["'])(?.*?)\k.*\n )+ /xi # :nodoc: ## # Reads the contents of +filename+ and handles any encoding directives in # the file. # # The content will be converted to the +encoding+. If the file cannot be # converted a warning will be printed and nil will be returned. # # If +force_transcode+ is true the document will be transcoded and any # unknown character in the target encoding will be replaced with '?' def self.read_file filename, encoding, force_transcode = false content = File.open filename, "rb" do |f| f.read end content.gsub!("\r\n", "\n") if RUBY_PLATFORM =~ /mswin|mingw/ utf8 = content.sub!(/\A\xef\xbb\xbf/, '') enc = RDoc::Encoding.detect_encoding content content = RDoc::Encoding.change_encoding content, enc if enc begin encoding ||= Encoding.default_external orig_encoding = content.encoding if not orig_encoding.ascii_compatible? then content = content.encode encoding elsif utf8 then content = RDoc::Encoding.change_encoding content, Encoding::UTF_8 content = content.encode encoding else # assume the content is in our output encoding content = RDoc::Encoding.change_encoding content, encoding end unless content.valid_encoding? then # revert and try to transcode content = RDoc::Encoding.change_encoding content, orig_encoding content = content.encode encoding end unless content.valid_encoding? then warn "unable to convert #{filename} to #{encoding}, skipping" content = nil end rescue Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError => e if force_transcode then content = RDoc::Encoding.change_encoding content, orig_encoding content = content.encode(encoding, :invalid => :replace, :undef => :replace, :replace => '?') return content else warn "unable to convert #{e.message} for #{filename}, skipping" return nil end end content rescue ArgumentError => e raise unless e.message =~ /unknown encoding name - (.*)/ warn "unknown encoding name \"#{$1}\" for #{filename}, skipping" nil rescue Errno::EISDIR, Errno::ENOENT nil end def self.remove_frozen_string_literal string string =~ /\A(?:#!.*\n)?(.*\n)/ first_line = $1 if first_line =~ /\A# +frozen[-_]string[-_]literal[=:].+$/i string = string.sub first_line, '' end string end ## # Detects the encoding of +string+ based on the magic comment def self.detect_encoding string result = HEADER_REGEXP.match string name = result && result[:name] name ? Encoding.find(name) : nil end ## # Removes magic comments and shebang def self.remove_magic_comment string string.sub HEADER_REGEXP do |s| s.gsub(/[^\n]/, '') end end ## # Changes encoding based on +encoding+ without converting and returns new # string def self.change_encoding text, encoding if text.kind_of? RDoc::Comment text.encode! encoding else # TODO: Remove this condition after Ruby 2.2 EOL if RUBY_VERSION < '2.3.0' text.force_encoding encoding else String.new text, encoding: encoding end end end end PK ]$gems/rdoc-6.2.1.1/lib/rdoc/extend.rbnu[# frozen_string_literal: true ## # A Module extension to a class with \#extend # # RDoc::Extend.new 'Enumerable', 'comment ...' class RDoc::Extend < RDoc::Mixin end PK ] =MM%gems/rdoc-6.2.1.1/lib/rdoc/version.rbnu[module RDoc ## # RDoc version you are using VERSION = '6.2.1.1' end PK ]g**gems/rdoc-6.2.1.1/lib/rdoc/code_objects.rbnu[# frozen_string_literal: true # This file was used to load all the RDoc::CodeObject subclasses at once. Now # autoload handles this. require 'rdoc' PK ]bb]]&gems/rdoc-6.2.1.1/lib/rdoc/constant.rbnu[# frozen_string_literal: true ## # A constant class RDoc::Constant < RDoc::CodeObject MARSHAL_VERSION = 0 # :nodoc: ## # Sets the module or class this is constant is an alias for. attr_writer :is_alias_for ## # The constant's name attr_accessor :name ## # The constant's value attr_accessor :value ## # The constant's visibility attr_accessor :visibility ## # Creates a new constant with +name+, +value+ and +comment+ def initialize(name, value, comment) super() @name = name @value = value @is_alias_for = nil @visibility = :public self.comment = comment end ## # Constants are ordered by name def <=> other return unless self.class === other [parent_name, name] <=> [other.parent_name, other.name] end ## # Constants are equal when their #parent and #name is the same def == other self.class == other.class and @parent == other.parent and @name == other.name end ## # A constant is documented if it has a comment, or is an alias # for a documented class or module. def documented? return true if super return false unless @is_alias_for case @is_alias_for when String then found = @store.find_class_or_module @is_alias_for return false unless found @is_alias_for = found end @is_alias_for.documented? end ## # Full constant name including namespace def full_name @full_name ||= "#{parent_name}::#{@name}" end ## # The module or class this constant is an alias for def is_alias_for case @is_alias_for when String then found = @store.find_class_or_module @is_alias_for @is_alias_for = found if found @is_alias_for else @is_alias_for end end def inspect # :nodoc: "#<%s:0x%x %s::%s>" % [ self.class, object_id, parent_name, @name, ] end ## # Dumps this Constant for use by ri. See also #marshal_load def marshal_dump alias_name = case found = is_alias_for when RDoc::CodeObject then found.full_name else found end [ MARSHAL_VERSION, @name, full_name, @visibility, alias_name, parse(@comment), @file.relative_name, parent.name, parent.class, section.title, ] end ## # Loads this Constant from +array+. For a loaded Constant the following # methods will return cached values: # # * #full_name # * #parent_name def marshal_load array initialize array[1], nil, array[5] @full_name = array[2] @visibility = array[3] || :public @is_alias_for = array[4] # 5 handled above # 6 handled below @parent_name = array[7] @parent_class = array[8] @section_title = array[9] @file = RDoc::TopLevel.new array[6] end ## # Path to this constant for use with HTML generator output. def path "#{@parent.path}##{@name}" end def pretty_print q # :nodoc: q.group 2, "[#{self.class.name} #{full_name}", "]" do unless comment.empty? then q.breakable q.text "comment:" q.breakable q.pp @comment end end end ## # Sets the store for this class or module and its contained code objects. def store= store super @file = @store.add_file @file.full_name if @file end def to_s # :nodoc: parent_name = parent ? parent.full_name : '(unknown)' if is_alias_for "constant #{parent_name}::#@name -> #{is_alias_for}" else "constant #{parent_name}::#@name" end end end PK ]I#$#$)gems/rdoc-6.2.1.1/lib/rdoc/method_attr.rbnu[# frozen_string_literal: true ## # Abstract class representing either a method or an attribute. class RDoc::MethodAttr < RDoc::CodeObject include Comparable ## # Name of this method/attribute. attr_accessor :name ## # public, protected, private attr_accessor :visibility ## # Is this a singleton method/attribute? attr_accessor :singleton ## # Source file token stream attr_reader :text ## # Array of other names for this method/attribute attr_reader :aliases ## # The method/attribute we're aliasing attr_accessor :is_alias_for #-- # The attributes below are for AnyMethod only. # They are left here for the time being to # allow ri to operate. # TODO modify ri to avoid calling these on attributes. #++ ## # Parameters yielded by the called block attr_reader :block_params ## # Parameters for this method attr_accessor :params ## # Different ways to call this method attr_accessor :call_seq ## # The call_seq or the param_seq with method name, if there is no call_seq. attr_reader :arglists ## # Pretty parameter list for this method attr_reader :param_seq ## # Creates a new MethodAttr from token stream +text+ and method or attribute # name +name+. # # Usually this is called by super from a subclass. def initialize text, name super() @text = text @name = name @aliases = [] @is_alias_for = nil @parent_name = nil @singleton = nil @visibility = :public @see = false @arglists = nil @block_params = nil @call_seq = nil @param_seq = nil @params = nil end ## # Resets cached data for the object so it can be rebuilt by accessor methods def initialize_copy other # :nodoc: @full_name = nil end def initialize_visibility # :nodoc: super @see = nil end ## # Order by #singleton then #name def <=>(other) return unless other.respond_to?(:singleton) && other.respond_to?(:name) [ @singleton ? 0 : 1, name] <=> [other.singleton ? 0 : 1, other.name] end def == other # :nodoc: equal?(other) or self.class == other.class and full_name == other.full_name end ## # A method/attribute is documented if any of the following is true: # - it was marked with :nodoc:; # - it has a comment; # - it is an alias for a documented method; # - it has a +#see+ method that is documented. def documented? super or (is_alias_for and is_alias_for.documented?) or (see and see.documented?) end ## # A method/attribute to look at, # in particular if this method/attribute has no documentation. # # It can be a method/attribute of the superclass or of an included module, # including the Kernel module, which is always appended to the included # modules. # # Returns +nil+ if there is no such method/attribute. # The +#is_alias_for+ method/attribute, if any, is not included. # # Templates may generate a "see also ..." if this method/attribute # has documentation, and "see ..." if it does not. def see @see = find_see if @see == false @see end ## # Sets the store for this class or module and its contained code objects. def store= store super @file = @store.add_file @file.full_name if @file end def find_see # :nodoc: return nil if singleton || is_alias_for # look for the method other = find_method_or_attribute name return other if other # if it is a setter, look for a getter return nil unless name =~ /[a-z_]=$/i # avoid == or === return find_method_or_attribute name[0..-2] end def find_method_or_attribute name # :nodoc: return nil unless parent.respond_to? :ancestors searched = parent.ancestors kernel = @store.modules_hash['Kernel'] searched << kernel if kernel && parent != kernel && !searched.include?(kernel) searched.each do |ancestor| next if String === ancestor next if parent == ancestor other = ancestor.find_method_named('#' + name) || ancestor.find_attribute_named(name) return other if other end nil end ## # Abstract method. Contexts in their building phase call this # to register a new alias for this known method/attribute. # # - creates a new AnyMethod/Attribute named an_alias.new_name; # - adds +self+ as an alias for the new method or attribute # - adds the method or attribute to #aliases # - adds the method or attribute to +context+. def add_alias(an_alias, context) raise NotImplementedError end ## # HTML fragment reference for this method def aref type = singleton ? 'c' : 'i' # % characters are not allowed in html names => dash instead "#{aref_prefix}-#{type}-#{html_name}" end ## # Prefix for +aref+, defined by subclasses. def aref_prefix raise NotImplementedError end ## # Attempts to sanitize the content passed by the Ruby parser: # remove outer parentheses, etc. def block_params=(value) # 'yield.to_s' or 'assert yield, msg' return @block_params = '' if value =~ /^[\.,]/ # remove trailing 'if/unless ...' return @block_params = '' if value =~ /^(if|unless)\s/ value = $1.strip if value =~ /^(.+)\s(if|unless)\s/ # outer parentheses value = $1 if value =~ /^\s*\((.*)\)\s*$/ value = value.strip # proc/lambda return @block_params = $1 if value =~ /^(proc|lambda)(\s*\{|\sdo)/ # surrounding +...+ or [...] value = $1.strip if value =~ /^\+(.*)\+$/ value = $1.strip if value =~ /^\[(.*)\]$/ return @block_params = '' if value.empty? # global variable return @block_params = 'str' if value =~ /^\$[&0-9]$/ # wipe out array/hash indices value.gsub!(/(\w)\[[^\[]+\]/, '\1') # remove @ from class/instance variables value.gsub!(/@@?([a-z0-9_]+)/, '\1') # method calls => method name value.gsub!(/([A-Z:a-z0-9_]+)\.([a-z0-9_]+)(\s*\(\s*[a-z0-9_.,\s]*\s*\)\s*)?/) do case $2 when 'to_s' then $1 when 'const_get' then 'const' when 'new' then $1.split('::').last. # ClassName => class_name gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). gsub(/([a-z\d])([A-Z])/,'\1_\2'). downcase else $2 end end # class prefixes value.gsub!(/[A-Za-z0-9_:]+::/, '') # simple expressions value = $1 if value =~ /^([a-z0-9_]+)\s*[-*+\/]/ @block_params = value.strip end ## # HTML id-friendly method/attribute name def html_name require 'cgi' CGI.escape(@name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '') end ## # Full method/attribute name including namespace def full_name @full_name ||= "#{parent_name}#{pretty_name}" end def inspect # :nodoc: alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil visibility = self.visibility visibility = "forced #{visibility}" if force_documentation "#<%s:0x%x %s (%s)%s>" % [ self.class, object_id, full_name, visibility, alias_for, ] end ## # '::' for a class method/attribute, '#' for an instance method. def name_prefix @singleton ? '::' : '#' end ## # Name for output to HTML. For class methods the full name with a "." is # used like +SomeClass.method_name+. For instance methods the class name is # used if +context+ does not match the parent. # # This is to help prevent people from using :: to call class methods. def output_name context return "#{name_prefix}#{@name}" if context == parent "#{parent_name}#{@singleton ? '.' : '#'}#{@name}" end ## # Method/attribute name with class/instance indicator def pretty_name "#{name_prefix}#{@name}" end ## # Type of method/attribute (class or instance) def type singleton ? 'class' : 'instance' end ## # Path to this method for use with HTML generator output. def path "#{@parent.path}##{aref}" end ## # Name of our parent with special handling for un-marshaled methods def parent_name @parent_name || super end def pretty_print q # :nodoc: alias_for = if @is_alias_for.respond_to? :name then "alias for #{@is_alias_for.name}" elsif Array === @is_alias_for then "alias for #{@is_alias_for.last}" end q.group 2, "[#{self.class.name} #{full_name} #{visibility}", "]" do if alias_for then q.breakable q.text alias_for end if text then q.breakable q.text "text:" q.breakable q.pp @text end unless comment.empty? then q.breakable q.text "comment:" q.breakable q.pp @comment end end end ## # Used by RDoc::Generator::JsonIndex to create a record for the search # engine. def search_record [ @name, full_name, @name, @parent.full_name, path, params, snippet(@comment), ] end def to_s # :nodoc: if @is_alias_for "#{self.class.name}: #{full_name} -> #{is_alias_for}" else "#{self.class.name}: #{full_name}" end end end PK ]OG!!/gems/rdoc-6.2.1.1/lib/rdoc/markdown/entities.rbnu[# frozen_string_literal: true ## # HTML entity name map for RDoc::Markdown RDoc::Markdown::HTML_ENTITIES = { "AElig" => [0x000C6], "AMP" => [0x00026], "Aacute" => [0x000C1], "Abreve" => [0x00102], "Acirc" => [0x000C2], "Acy" => [0x00410], "Afr" => [0x1D504], "Agrave" => [0x000C0], "Alpha" => [0x00391], "Amacr" => [0x00100], "And" => [0x02A53], "Aogon" => [0x00104], "Aopf" => [0x1D538], "ApplyFunction" => [0x02061], "Aring" => [0x000C5], "Ascr" => [0x1D49C], "Assign" => [0x02254], "Atilde" => [0x000C3], "Auml" => [0x000C4], "Backslash" => [0x02216], "Barv" => [0x02AE7], "Barwed" => [0x02306], "Bcy" => [0x00411], "Because" => [0x02235], "Bernoullis" => [0x0212C], "Beta" => [0x00392], "Bfr" => [0x1D505], "Bopf" => [0x1D539], "Breve" => [0x002D8], "Bscr" => [0x0212C], "Bumpeq" => [0x0224E], "CHcy" => [0x00427], "COPY" => [0x000A9], "Cacute" => [0x00106], "Cap" => [0x022D2], "CapitalDifferentialD" => [0x02145], "Cayleys" => [0x0212D], "Ccaron" => [0x0010C], "Ccedil" => [0x000C7], "Ccirc" => [0x00108], "Cconint" => [0x02230], "Cdot" => [0x0010A], "Cedilla" => [0x000B8], "CenterDot" => [0x000B7], "Cfr" => [0x0212D], "Chi" => [0x003A7], "CircleDot" => [0x02299], "CircleMinus" => [0x02296], "CirclePlus" => [0x02295], "CircleTimes" => [0x02297], "ClockwiseContourIntegral" => [0x02232], "CloseCurlyDoubleQuote" => [0x0201D], "CloseCurlyQuote" => [0x02019], "Colon" => [0x02237], "Colone" => [0x02A74], "Congruent" => [0x02261], "Conint" => [0x0222F], "ContourIntegral" => [0x0222E], "Copf" => [0x02102], "Coproduct" => [0x02210], "CounterClockwiseContourIntegral" => [0x02233], "Cross" => [0x02A2F], "Cscr" => [0x1D49E], "Cup" => [0x022D3], "CupCap" => [0x0224D], "DD" => [0x02145], "DDotrahd" => [0x02911], "DJcy" => [0x00402], "DScy" => [0x00405], "DZcy" => [0x0040F], "Dagger" => [0x02021], "Darr" => [0x021A1], "Dashv" => [0x02AE4], "Dcaron" => [0x0010E], "Dcy" => [0x00414], "Del" => [0x02207], "Delta" => [0x00394], "Dfr" => [0x1D507], "DiacriticalAcute" => [0x000B4], "DiacriticalDot" => [0x002D9], "DiacriticalDoubleAcute" => [0x002DD], "DiacriticalGrave" => [0x00060], "DiacriticalTilde" => [0x002DC], "Diamond" => [0x022C4], "DifferentialD" => [0x02146], "Dopf" => [0x1D53B], "Dot" => [0x000A8], "DotDot" => [0x020DC], "DotEqual" => [0x02250], "DoubleContourIntegral" => [0x0222F], "DoubleDot" => [0x000A8], "DoubleDownArrow" => [0x021D3], "DoubleLeftArrow" => [0x021D0], "DoubleLeftRightArrow" => [0x021D4], "DoubleLeftTee" => [0x02AE4], "DoubleLongLeftArrow" => [0x027F8], "DoubleLongLeftRightArrow" => [0x027FA], "DoubleLongRightArrow" => [0x027F9], "DoubleRightArrow" => [0x021D2], "DoubleRightTee" => [0x022A8], "DoubleUpArrow" => [0x021D1], "DoubleUpDownArrow" => [0x021D5], "DoubleVerticalBar" => [0x02225], "DownArrow" => [0x02193], "DownArrowBar" => [0x02913], "DownArrowUpArrow" => [0x021F5], "DownBreve" => [0x00311], "DownLeftRightVector" => [0x02950], "DownLeftTeeVector" => [0x0295E], "DownLeftVector" => [0x021BD], "DownLeftVectorBar" => [0x02956], "DownRightTeeVector" => [0x0295F], "DownRightVector" => [0x021C1], "DownRightVectorBar" => [0x02957], "DownTee" => [0x022A4], "DownTeeArrow" => [0x021A7], "Downarrow" => [0x021D3], "Dscr" => [0x1D49F], "Dstrok" => [0x00110], "ENG" => [0x0014A], "ETH" => [0x000D0], "Eacute" => [0x000C9], "Ecaron" => [0x0011A], "Ecirc" => [0x000CA], "Ecy" => [0x0042D], "Edot" => [0x00116], "Efr" => [0x1D508], "Egrave" => [0x000C8], "Element" => [0x02208], "Emacr" => [0x00112], "EmptySmallSquare" => [0x025FB], "EmptyVerySmallSquare" => [0x025AB], "Eogon" => [0x00118], "Eopf" => [0x1D53C], "Epsilon" => [0x00395], "Equal" => [0x02A75], "EqualTilde" => [0x02242], "Equilibrium" => [0x021CC], "Escr" => [0x02130], "Esim" => [0x02A73], "Eta" => [0x00397], "Euml" => [0x000CB], "Exists" => [0x02203], "ExponentialE" => [0x02147], "Fcy" => [0x00424], "Ffr" => [0x1D509], "FilledSmallSquare" => [0x025FC], "FilledVerySmallSquare" => [0x025AA], "Fopf" => [0x1D53D], "ForAll" => [0x02200], "Fouriertrf" => [0x02131], "Fscr" => [0x02131], "GJcy" => [0x00403], "GT" => [0x0003E], "Gamma" => [0x00393], "Gammad" => [0x003DC], "Gbreve" => [0x0011E], "Gcedil" => [0x00122], "Gcirc" => [0x0011C], "Gcy" => [0x00413], "Gdot" => [0x00120], "Gfr" => [0x1D50A], "Gg" => [0x022D9], "Gopf" => [0x1D53E], "GreaterEqual" => [0x02265], "GreaterEqualLess" => [0x022DB], "GreaterFullEqual" => [0x02267], "GreaterGreater" => [0x02AA2], "GreaterLess" => [0x02277], "GreaterSlantEqual" => [0x02A7E], "GreaterTilde" => [0x02273], "Gscr" => [0x1D4A2], "Gt" => [0x0226B], "HARDcy" => [0x0042A], "Hacek" => [0x002C7], "Hat" => [0x0005E], "Hcirc" => [0x00124], "Hfr" => [0x0210C], "HilbertSpace" => [0x0210B], "Hopf" => [0x0210D], "HorizontalLine" => [0x02500], "Hscr" => [0x0210B], "Hstrok" => [0x00126], "HumpDownHump" => [0x0224E], "HumpEqual" => [0x0224F], "IEcy" => [0x00415], "IJlig" => [0x00132], "IOcy" => [0x00401], "Iacute" => [0x000CD], "Icirc" => [0x000CE], "Icy" => [0x00418], "Idot" => [0x00130], "Ifr" => [0x02111], "Igrave" => [0x000CC], "Im" => [0x02111], "Imacr" => [0x0012A], "ImaginaryI" => [0x02148], "Implies" => [0x021D2], "Int" => [0x0222C], "Integral" => [0x0222B], "Intersection" => [0x022C2], "InvisibleComma" => [0x02063], "InvisibleTimes" => [0x02062], "Iogon" => [0x0012E], "Iopf" => [0x1D540], "Iota" => [0x00399], "Iscr" => [0x02110], "Itilde" => [0x00128], "Iukcy" => [0x00406], "Iuml" => [0x000CF], "Jcirc" => [0x00134], "Jcy" => [0x00419], "Jfr" => [0x1D50D], "Jopf" => [0x1D541], "Jscr" => [0x1D4A5], "Jsercy" => [0x00408], "Jukcy" => [0x00404], "KHcy" => [0x00425], "KJcy" => [0x0040C], "Kappa" => [0x0039A], "Kcedil" => [0x00136], "Kcy" => [0x0041A], "Kfr" => [0x1D50E], "Kopf" => [0x1D542], "Kscr" => [0x1D4A6], "LJcy" => [0x00409], "LT" => [0x0003C], "Lacute" => [0x00139], "Lambda" => [0x0039B], "Lang" => [0x027EA], "Laplacetrf" => [0x02112], "Larr" => [0x0219E], "Lcaron" => [0x0013D], "Lcedil" => [0x0013B], "Lcy" => [0x0041B], "LeftAngleBracket" => [0x027E8], "LeftArrow" => [0x02190], "LeftArrowBar" => [0x021E4], "LeftArrowRightArrow" => [0x021C6], "LeftCeiling" => [0x02308], "LeftDoubleBracket" => [0x027E6], "LeftDownTeeVector" => [0x02961], "LeftDownVector" => [0x021C3], "LeftDownVectorBar" => [0x02959], "LeftFloor" => [0x0230A], "LeftRightArrow" => [0x02194], "LeftRightVector" => [0x0294E], "LeftTee" => [0x022A3], "LeftTeeArrow" => [0x021A4], "LeftTeeVector" => [0x0295A], "LeftTriangle" => [0x022B2], "LeftTriangleBar" => [0x029CF], "LeftTriangleEqual" => [0x022B4], "LeftUpDownVector" => [0x02951], "LeftUpTeeVector" => [0x02960], "LeftUpVector" => [0x021BF], "LeftUpVectorBar" => [0x02958], "LeftVector" => [0x021BC], "LeftVectorBar" => [0x02952], "Leftarrow" => [0x021D0], "Leftrightarrow" => [0x021D4], "LessEqualGreater" => [0x022DA], "LessFullEqual" => [0x02266], "LessGreater" => [0x02276], "LessLess" => [0x02AA1], "LessSlantEqual" => [0x02A7D], "LessTilde" => [0x02272], "Lfr" => [0x1D50F], "Ll" => [0x022D8], "Lleftarrow" => [0x021DA], "Lmidot" => [0x0013F], "LongLeftArrow" => [0x027F5], "LongLeftRightArrow" => [0x027F7], "LongRightArrow" => [0x027F6], "Longleftarrow" => [0x027F8], "Longleftrightarrow" => [0x027FA], "Longrightarrow" => [0x027F9], "Lopf" => [0x1D543], "LowerLeftArrow" => [0x02199], "LowerRightArrow" => [0x02198], "Lscr" => [0x02112], "Lsh" => [0x021B0], "Lstrok" => [0x00141], "Lt" => [0x0226A], "Map" => [0x02905], "Mcy" => [0x0041C], "MediumSpace" => [0x0205F], "Mellintrf" => [0x02133], "Mfr" => [0x1D510], "MinusPlus" => [0x02213], "Mopf" => [0x1D544], "Mscr" => [0x02133], "Mu" => [0x0039C], "NJcy" => [0x0040A], "Nacute" => [0x00143], "Ncaron" => [0x00147], "Ncedil" => [0x00145], "Ncy" => [0x0041D], "NegativeMediumSpace" => [0x0200B], "NegativeThickSpace" => [0x0200B], "NegativeThinSpace" => [0x0200B], "NegativeVeryThinSpace" => [0x0200B], "NestedGreaterGreater" => [0x0226B], "NestedLessLess" => [0x0226A], "NewLine" => [0x0000A], "Nfr" => [0x1D511], "NoBreak" => [0x02060], "NonBreakingSpace" => [0x000A0], "Nopf" => [0x02115], "Not" => [0x02AEC], "NotCongruent" => [0x02262], "NotCupCap" => [0x0226D], "NotDoubleVerticalBar" => [0x02226], "NotElement" => [0x02209], "NotEqual" => [0x02260], "NotEqualTilde" => [0x02242, 0x00338], "NotExists" => [0x02204], "NotGreater" => [0x0226F], "NotGreaterEqual" => [0x02271], "NotGreaterFullEqual" => [0x02267, 0x00338], "NotGreaterGreater" => [0x0226B, 0x00338], "NotGreaterLess" => [0x02279], "NotGreaterSlantEqual" => [0x02A7E, 0x00338], "NotGreaterTilde" => [0x02275], "NotHumpDownHump" => [0x0224E, 0x00338], "NotHumpEqual" => [0x0224F, 0x00338], "NotLeftTriangle" => [0x022EA], "NotLeftTriangleBar" => [0x029CF, 0x00338], "NotLeftTriangleEqual" => [0x022EC], "NotLess" => [0x0226E], "NotLessEqual" => [0x02270], "NotLessGreater" => [0x02278], "NotLessLess" => [0x0226A, 0x00338], "NotLessSlantEqual" => [0x02A7D, 0x00338], "NotLessTilde" => [0x02274], "NotNestedGreaterGreater" => [0x02AA2, 0x00338], "NotNestedLessLess" => [0x02AA1, 0x00338], "NotPrecedes" => [0x02280], "NotPrecedesEqual" => [0x02AAF, 0x00338], "NotPrecedesSlantEqual" => [0x022E0], "NotReverseElement" => [0x0220C], "NotRightTriangle" => [0x022EB], "NotRightTriangleBar" => [0x029D0, 0x00338], "NotRightTriangleEqual" => [0x022ED], "NotSquareSubset" => [0x0228F, 0x00338], "NotSquareSubsetEqual" => [0x022E2], "NotSquareSuperset" => [0x02290, 0x00338], "NotSquareSupersetEqual" => [0x022E3], "NotSubset" => [0x02282, 0x020D2], "NotSubsetEqual" => [0x02288], "NotSucceeds" => [0x02281], "NotSucceedsEqual" => [0x02AB0, 0x00338], "NotSucceedsSlantEqual" => [0x022E1], "NotSucceedsTilde" => [0x0227F, 0x00338], "NotSuperset" => [0x02283, 0x020D2], "NotSupersetEqual" => [0x02289], "NotTilde" => [0x02241], "NotTildeEqual" => [0x02244], "NotTildeFullEqual" => [0x02247], "NotTildeTilde" => [0x02249], "NotVerticalBar" => [0x02224], "Nscr" => [0x1D4A9], "Ntilde" => [0x000D1], "Nu" => [0x0039D], "OElig" => [0x00152], "Oacute" => [0x000D3], "Ocirc" => [0x000D4], "Ocy" => [0x0041E], "Odblac" => [0x00150], "Ofr" => [0x1D512], "Ograve" => [0x000D2], "Omacr" => [0x0014C], "Omega" => [0x003A9], "Omicron" => [0x0039F], "Oopf" => [0x1D546], "OpenCurlyDoubleQuote" => [0x0201C], "OpenCurlyQuote" => [0x02018], "Or" => [0x02A54], "Oscr" => [0x1D4AA], "Oslash" => [0x000D8], "Otilde" => [0x000D5], "Otimes" => [0x02A37], "Ouml" => [0x000D6], "OverBar" => [0x0203E], "OverBrace" => [0x023DE], "OverBracket" => [0x023B4], "OverParenthesis" => [0x023DC], "PartialD" => [0x02202], "Pcy" => [0x0041F], "Pfr" => [0x1D513], "Phi" => [0x003A6], "Pi" => [0x003A0], "PlusMinus" => [0x000B1], "Poincareplane" => [0x0210C], "Popf" => [0x02119], "Pr" => [0x02ABB], "Precedes" => [0x0227A], "PrecedesEqual" => [0x02AAF], "PrecedesSlantEqual" => [0x0227C], "PrecedesTilde" => [0x0227E], "Prime" => [0x02033], "Product" => [0x0220F], "Proportion" => [0x02237], "Proportional" => [0x0221D], "Pscr" => [0x1D4AB], "Psi" => [0x003A8], "QUOT" => [0x00022], "Qfr" => [0x1D514], "Qopf" => [0x0211A], "Qscr" => [0x1D4AC], "RBarr" => [0x02910], "REG" => [0x000AE], "Racute" => [0x00154], "Rang" => [0x027EB], "Rarr" => [0x021A0], "Rarrtl" => [0x02916], "Rcaron" => [0x00158], "Rcedil" => [0x00156], "Rcy" => [0x00420], "Re" => [0x0211C], "ReverseElement" => [0x0220B], "ReverseEquilibrium" => [0x021CB], "ReverseUpEquilibrium" => [0x0296F], "Rfr" => [0x0211C], "Rho" => [0x003A1], "RightAngleBracket" => [0x027E9], "RightArrow" => [0x02192], "RightArrowBar" => [0x021E5], "RightArrowLeftArrow" => [0x021C4], "RightCeiling" => [0x02309], "RightDoubleBracket" => [0x027E7], "RightDownTeeVector" => [0x0295D], "RightDownVector" => [0x021C2], "RightDownVectorBar" => [0x02955], "RightFloor" => [0x0230B], "RightTee" => [0x022A2], "RightTeeArrow" => [0x021A6], "RightTeeVector" => [0x0295B], "RightTriangle" => [0x022B3], "RightTriangleBar" => [0x029D0], "RightTriangleEqual" => [0x022B5], "RightUpDownVector" => [0x0294F], "RightUpTeeVector" => [0x0295C], "RightUpVector" => [0x021BE], "RightUpVectorBar" => [0x02954], "RightVector" => [0x021C0], "RightVectorBar" => [0x02953], "Rightarrow" => [0x021D2], "Ropf" => [0x0211D], "RoundImplies" => [0x02970], "Rrightarrow" => [0x021DB], "Rscr" => [0x0211B], "Rsh" => [0x021B1], "RuleDelayed" => [0x029F4], "SHCHcy" => [0x00429], "SHcy" => [0x00428], "SOFTcy" => [0x0042C], "Sacute" => [0x0015A], "Sc" => [0x02ABC], "Scaron" => [0x00160], "Scedil" => [0x0015E], "Scirc" => [0x0015C], "Scy" => [0x00421], "Sfr" => [0x1D516], "ShortDownArrow" => [0x02193], "ShortLeftArrow" => [0x02190], "ShortRightArrow" => [0x02192], "ShortUpArrow" => [0x02191], "Sigma" => [0x003A3], "SmallCircle" => [0x02218], "Sopf" => [0x1D54A], "Sqrt" => [0x0221A], "Square" => [0x025A1], "SquareIntersection" => [0x02293], "SquareSubset" => [0x0228F], "SquareSubsetEqual" => [0x02291], "SquareSuperset" => [0x02290], "SquareSupersetEqual" => [0x02292], "SquareUnion" => [0x02294], "Sscr" => [0x1D4AE], "Star" => [0x022C6], "Sub" => [0x022D0], "Subset" => [0x022D0], "SubsetEqual" => [0x02286], "Succeeds" => [0x0227B], "SucceedsEqual" => [0x02AB0], "SucceedsSlantEqual" => [0x0227D], "SucceedsTilde" => [0x0227F], "SuchThat" => [0x0220B], "Sum" => [0x02211], "Sup" => [0x022D1], "Superset" => [0x02283], "SupersetEqual" => [0x02287], "Supset" => [0x022D1], "THORN" => [0x000DE], "TRADE" => [0x02122], "TSHcy" => [0x0040B], "TScy" => [0x00426], "Tab" => [0x00009], "Tau" => [0x003A4], "Tcaron" => [0x00164], "Tcedil" => [0x00162], "Tcy" => [0x00422], "Tfr" => [0x1D517], "Therefore" => [0x02234], "Theta" => [0x00398], "ThickSpace" => [0x0205F, 0x0200A], "ThinSpace" => [0x02009], "Tilde" => [0x0223C], "TildeEqual" => [0x02243], "TildeFullEqual" => [0x02245], "TildeTilde" => [0x02248], "Topf" => [0x1D54B], "TripleDot" => [0x020DB], "Tscr" => [0x1D4AF], "Tstrok" => [0x00166], "Uacute" => [0x000DA], "Uarr" => [0x0219F], "Uarrocir" => [0x02949], "Ubrcy" => [0x0040E], "Ubreve" => [0x0016C], "Ucirc" => [0x000DB], "Ucy" => [0x00423], "Udblac" => [0x00170], "Ufr" => [0x1D518], "Ugrave" => [0x000D9], "Umacr" => [0x0016A], "UnderBar" => [0x0005F], "UnderBrace" => [0x023DF], "UnderBracket" => [0x023B5], "UnderParenthesis" => [0x023DD], "Union" => [0x022C3], "UnionPlus" => [0x0228E], "Uogon" => [0x00172], "Uopf" => [0x1D54C], "UpArrow" => [0x02191], "UpArrowBar" => [0x02912], "UpArrowDownArrow" => [0x021C5], "UpDownArrow" => [0x02195], "UpEquilibrium" => [0x0296E], "UpTee" => [0x022A5], "UpTeeArrow" => [0x021A5], "Uparrow" => [0x021D1], "Updownarrow" => [0x021D5], "UpperLeftArrow" => [0x02196], "UpperRightArrow" => [0x02197], "Upsi" => [0x003D2], "Upsilon" => [0x003A5], "Uring" => [0x0016E], "Uscr" => [0x1D4B0], "Utilde" => [0x00168], "Uuml" => [0x000DC], "VDash" => [0x022AB], "Vbar" => [0x02AEB], "Vcy" => [0x00412], "Vdash" => [0x022A9], "Vdashl" => [0x02AE6], "Vee" => [0x022C1], "Verbar" => [0x02016], "Vert" => [0x02016], "VerticalBar" => [0x02223], "VerticalLine" => [0x0007C], "VerticalSeparator" => [0x02758], "VerticalTilde" => [0x02240], "VeryThinSpace" => [0x0200A], "Vfr" => [0x1D519], "Vopf" => [0x1D54D], "Vscr" => [0x1D4B1], "Vvdash" => [0x022AA], "Wcirc" => [0x00174], "Wedge" => [0x022C0], "Wfr" => [0x1D51A], "Wopf" => [0x1D54E], "Wscr" => [0x1D4B2], "Xfr" => [0x1D51B], "Xi" => [0x0039E], "Xopf" => [0x1D54F], "Xscr" => [0x1D4B3], "YAcy" => [0x0042F], "YIcy" => [0x00407], "YUcy" => [0x0042E], "Yacute" => [0x000DD], "Ycirc" => [0x00176], "Ycy" => [0x0042B], "Yfr" => [0x1D51C], "Yopf" => [0x1D550], "Yscr" => [0x1D4B4], "Yuml" => [0x00178], "ZHcy" => [0x00416], "Zacute" => [0x00179], "Zcaron" => [0x0017D], "Zcy" => [0x00417], "Zdot" => [0x0017B], "ZeroWidthSpace" => [0x0200B], "Zeta" => [0x00396], "Zfr" => [0x02128], "Zopf" => [0x02124], "Zscr" => [0x1D4B5], "aacute" => [0x000E1], "abreve" => [0x00103], "ac" => [0x0223E], "acE" => [0x0223E, 0x00333], "acd" => [0x0223F], "acirc" => [0x000E2], "acute" => [0x000B4], "acy" => [0x00430], "aelig" => [0x000E6], "af" => [0x02061], "afr" => [0x1D51E], "agrave" => [0x000E0], "alefsym" => [0x02135], "aleph" => [0x02135], "alpha" => [0x003B1], "amacr" => [0x00101], "amalg" => [0x02A3F], "amp" => [0x00026], "and" => [0x02227], "andand" => [0x02A55], "andd" => [0x02A5C], "andslope" => [0x02A58], "andv" => [0x02A5A], "ang" => [0x02220], "ange" => [0x029A4], "angle" => [0x02220], "angmsd" => [0x02221], "angmsdaa" => [0x029A8], "angmsdab" => [0x029A9], "angmsdac" => [0x029AA], "angmsdad" => [0x029AB], "angmsdae" => [0x029AC], "angmsdaf" => [0x029AD], "angmsdag" => [0x029AE], "angmsdah" => [0x029AF], "angrt" => [0x0221F], "angrtvb" => [0x022BE], "angrtvbd" => [0x0299D], "angsph" => [0x02222], "angst" => [0x000C5], "angzarr" => [0x0237C], "aogon" => [0x00105], "aopf" => [0x1D552], "ap" => [0x02248], "apE" => [0x02A70], "apacir" => [0x02A6F], "ape" => [0x0224A], "apid" => [0x0224B], "apos" => [0x00027], "approx" => [0x02248], "approxeq" => [0x0224A], "aring" => [0x000E5], "ascr" => [0x1D4B6], "ast" => [0x0002A], "asymp" => [0x02248], "asympeq" => [0x0224D], "atilde" => [0x000E3], "auml" => [0x000E4], "awconint" => [0x02233], "awint" => [0x02A11], "bNot" => [0x02AED], "backcong" => [0x0224C], "backepsilon" => [0x003F6], "backprime" => [0x02035], "backsim" => [0x0223D], "backsimeq" => [0x022CD], "barvee" => [0x022BD], "barwed" => [0x02305], "barwedge" => [0x02305], "bbrk" => [0x023B5], "bbrktbrk" => [0x023B6], "bcong" => [0x0224C], "bcy" => [0x00431], "bdquo" => [0x0201E], "becaus" => [0x02235], "because" => [0x02235], "bemptyv" => [0x029B0], "bepsi" => [0x003F6], "bernou" => [0x0212C], "beta" => [0x003B2], "beth" => [0x02136], "between" => [0x0226C], "bfr" => [0x1D51F], "bigcap" => [0x022C2], "bigcirc" => [0x025EF], "bigcup" => [0x022C3], "bigodot" => [0x02A00], "bigoplus" => [0x02A01], "bigotimes" => [0x02A02], "bigsqcup" => [0x02A06], "bigstar" => [0x02605], "bigtriangledown" => [0x025BD], "bigtriangleup" => [0x025B3], "biguplus" => [0x02A04], "bigvee" => [0x022C1], "bigwedge" => [0x022C0], "bkarow" => [0x0290D], "blacklozenge" => [0x029EB], "blacksquare" => [0x025AA], "blacktriangle" => [0x025B4], "blacktriangledown" => [0x025BE], "blacktriangleleft" => [0x025C2], "blacktriangleright" => [0x025B8], "blank" => [0x02423], "blk12" => [0x02592], "blk14" => [0x02591], "blk34" => [0x02593], "block" => [0x02588], "bne" => [0x0003D, 0x020E5], "bnequiv" => [0x02261, 0x020E5], "bnot" => [0x02310], "bopf" => [0x1D553], "bot" => [0x022A5], "bottom" => [0x022A5], "bowtie" => [0x022C8], "boxDL" => [0x02557], "boxDR" => [0x02554], "boxDl" => [0x02556], "boxDr" => [0x02553], "boxH" => [0x02550], "boxHD" => [0x02566], "boxHU" => [0x02569], "boxHd" => [0x02564], "boxHu" => [0x02567], "boxUL" => [0x0255D], "boxUR" => [0x0255A], "boxUl" => [0x0255C], "boxUr" => [0x02559], "boxV" => [0x02551], "boxVH" => [0x0256C], "boxVL" => [0x02563], "boxVR" => [0x02560], "boxVh" => [0x0256B], "boxVl" => [0x02562], "boxVr" => [0x0255F], "boxbox" => [0x029C9], "boxdL" => [0x02555], "boxdR" => [0x02552], "boxdl" => [0x02510], "boxdr" => [0x0250C], "boxh" => [0x02500], "boxhD" => [0x02565], "boxhU" => [0x02568], "boxhd" => [0x0252C], "boxhu" => [0x02534], "boxminus" => [0x0229F], "boxplus" => [0x0229E], "boxtimes" => [0x022A0], "boxuL" => [0x0255B], "boxuR" => [0x02558], "boxul" => [0x02518], "boxur" => [0x02514], "boxv" => [0x02502], "boxvH" => [0x0256A], "boxvL" => [0x02561], "boxvR" => [0x0255E], "boxvh" => [0x0253C], "boxvl" => [0x02524], "boxvr" => [0x0251C], "bprime" => [0x02035], "breve" => [0x002D8], "brvbar" => [0x000A6], "bscr" => [0x1D4B7], "bsemi" => [0x0204F], "bsim" => [0x0223D], "bsime" => [0x022CD], "bsol" => [0x0005C], "bsolb" => [0x029C5], "bsolhsub" => [0x027C8], "bull" => [0x02022], "bullet" => [0x02022], "bump" => [0x0224E], "bumpE" => [0x02AAE], "bumpe" => [0x0224F], "bumpeq" => [0x0224F], "cacute" => [0x00107], "cap" => [0x02229], "capand" => [0x02A44], "capbrcup" => [0x02A49], "capcap" => [0x02A4B], "capcup" => [0x02A47], "capdot" => [0x02A40], "caps" => [0x02229, 0x0FE00], "caret" => [0x02041], "caron" => [0x002C7], "ccaps" => [0x02A4D], "ccaron" => [0x0010D], "ccedil" => [0x000E7], "ccirc" => [0x00109], "ccups" => [0x02A4C], "ccupssm" => [0x02A50], "cdot" => [0x0010B], "cedil" => [0x000B8], "cemptyv" => [0x029B2], "cent" => [0x000A2], "centerdot" => [0x000B7], "cfr" => [0x1D520], "chcy" => [0x00447], "check" => [0x02713], "checkmark" => [0x02713], "chi" => [0x003C7], "cir" => [0x025CB], "cirE" => [0x029C3], "circ" => [0x002C6], "circeq" => [0x02257], "circlearrowleft" => [0x021BA], "circlearrowright" => [0x021BB], "circledR" => [0x000AE], "circledS" => [0x024C8], "circledast" => [0x0229B], "circledcirc" => [0x0229A], "circleddash" => [0x0229D], "cire" => [0x02257], "cirfnint" => [0x02A10], "cirmid" => [0x02AEF], "cirscir" => [0x029C2], "clubs" => [0x02663], "clubsuit" => [0x02663], "colon" => [0x0003A], "colone" => [0x02254], "coloneq" => [0x02254], "comma" => [0x0002C], "commat" => [0x00040], "comp" => [0x02201], "compfn" => [0x02218], "complement" => [0x02201], "complexes" => [0x02102], "cong" => [0x02245], "congdot" => [0x02A6D], "conint" => [0x0222E], "copf" => [0x1D554], "coprod" => [0x02210], "copy" => [0x000A9], "copysr" => [0x02117], "crarr" => [0x021B5], "cross" => [0x02717], "cscr" => [0x1D4B8], "csub" => [0x02ACF], "csube" => [0x02AD1], "csup" => [0x02AD0], "csupe" => [0x02AD2], "ctdot" => [0x022EF], "cudarrl" => [0x02938], "cudarrr" => [0x02935], "cuepr" => [0x022DE], "cuesc" => [0x022DF], "cularr" => [0x021B6], "cularrp" => [0x0293D], "cup" => [0x0222A], "cupbrcap" => [0x02A48], "cupcap" => [0x02A46], "cupcup" => [0x02A4A], "cupdot" => [0x0228D], "cupor" => [0x02A45], "cups" => [0x0222A, 0x0FE00], "curarr" => [0x021B7], "curarrm" => [0x0293C], "curlyeqprec" => [0x022DE], "curlyeqsucc" => [0x022DF], "curlyvee" => [0x022CE], "curlywedge" => [0x022CF], "curren" => [0x000A4], "curvearrowleft" => [0x021B6], "curvearrowright" => [0x021B7], "cuvee" => [0x022CE], "cuwed" => [0x022CF], "cwconint" => [0x02232], "cwint" => [0x02231], "cylcty" => [0x0232D], "dArr" => [0x021D3], "dHar" => [0x02965], "dagger" => [0x02020], "daleth" => [0x02138], "darr" => [0x02193], "dash" => [0x02010], "dashv" => [0x022A3], "dbkarow" => [0x0290F], "dblac" => [0x002DD], "dcaron" => [0x0010F], "dcy" => [0x00434], "dd" => [0x02146], "ddagger" => [0x02021], "ddarr" => [0x021CA], "ddotseq" => [0x02A77], "deg" => [0x000B0], "delta" => [0x003B4], "demptyv" => [0x029B1], "dfisht" => [0x0297F], "dfr" => [0x1D521], "dharl" => [0x021C3], "dharr" => [0x021C2], "diam" => [0x022C4], "diamond" => [0x022C4], "diamondsuit" => [0x02666], "diams" => [0x02666], "die" => [0x000A8], "digamma" => [0x003DD], "disin" => [0x022F2], "div" => [0x000F7], "divide" => [0x000F7], "divideontimes" => [0x022C7], "divonx" => [0x022C7], "djcy" => [0x00452], "dlcorn" => [0x0231E], "dlcrop" => [0x0230D], "dollar" => [0x00024], "dopf" => [0x1D555], "dot" => [0x002D9], "doteq" => [0x02250], "doteqdot" => [0x02251], "dotminus" => [0x02238], "dotplus" => [0x02214], "dotsquare" => [0x022A1], "doublebarwedge" => [0x02306], "downarrow" => [0x02193], "downdownarrows" => [0x021CA], "downharpoonleft" => [0x021C3], "downharpoonright" => [0x021C2], "drbkarow" => [0x02910], "drcorn" => [0x0231F], "drcrop" => [0x0230C], "dscr" => [0x1D4B9], "dscy" => [0x00455], "dsol" => [0x029F6], "dstrok" => [0x00111], "dtdot" => [0x022F1], "dtri" => [0x025BF], "dtrif" => [0x025BE], "duarr" => [0x021F5], "duhar" => [0x0296F], "dwangle" => [0x029A6], "dzcy" => [0x0045F], "dzigrarr" => [0x027FF], "eDDot" => [0x02A77], "eDot" => [0x02251], "eacute" => [0x000E9], "easter" => [0x02A6E], "ecaron" => [0x0011B], "ecir" => [0x02256], "ecirc" => [0x000EA], "ecolon" => [0x02255], "ecy" => [0x0044D], "edot" => [0x00117], "ee" => [0x02147], "efDot" => [0x02252], "efr" => [0x1D522], "eg" => [0x02A9A], "egrave" => [0x000E8], "egs" => [0x02A96], "egsdot" => [0x02A98], "el" => [0x02A99], "elinters" => [0x023E7], "ell" => [0x02113], "els" => [0x02A95], "elsdot" => [0x02A97], "emacr" => [0x00113], "empty" => [0x02205], "emptyset" => [0x02205], "emptyv" => [0x02205], "emsp" => [0x02003], "emsp13" => [0x02004], "emsp14" => [0x02005], "eng" => [0x0014B], "ensp" => [0x02002], "eogon" => [0x00119], "eopf" => [0x1D556], "epar" => [0x022D5], "eparsl" => [0x029E3], "eplus" => [0x02A71], "epsi" => [0x003B5], "epsilon" => [0x003B5], "epsiv" => [0x003F5], "eqcirc" => [0x02256], "eqcolon" => [0x02255], "eqsim" => [0x02242], "eqslantgtr" => [0x02A96], "eqslantless" => [0x02A95], "equals" => [0x0003D], "equest" => [0x0225F], "equiv" => [0x02261], "equivDD" => [0x02A78], "eqvparsl" => [0x029E5], "erDot" => [0x02253], "erarr" => [0x02971], "escr" => [0x0212F], "esdot" => [0x02250], "esim" => [0x02242], "eta" => [0x003B7], "eth" => [0x000F0], "euml" => [0x000EB], "euro" => [0x020AC], "excl" => [0x00021], "exist" => [0x02203], "expectation" => [0x02130], "exponentiale" => [0x02147], "fallingdotseq" => [0x02252], "fcy" => [0x00444], "female" => [0x02640], "ffilig" => [0x0FB03], "fflig" => [0x0FB00], "ffllig" => [0x0FB04], "ffr" => [0x1D523], "filig" => [0x0FB01], "fjlig" => [0x00066, 0x0006A], "flat" => [0x0266D], "fllig" => [0x0FB02], "fltns" => [0x025B1], "fnof" => [0x00192], "fopf" => [0x1D557], "forall" => [0x02200], "fork" => [0x022D4], "forkv" => [0x02AD9], "fpartint" => [0x02A0D], "frac12" => [0x000BD], "frac13" => [0x02153], "frac14" => [0x000BC], "frac15" => [0x02155], "frac16" => [0x02159], "frac18" => [0x0215B], "frac23" => [0x02154], "frac25" => [0x02156], "frac34" => [0x000BE], "frac35" => [0x02157], "frac38" => [0x0215C], "frac45" => [0x02158], "frac56" => [0x0215A], "frac58" => [0x0215D], "frac78" => [0x0215E], "frasl" => [0x02044], "frown" => [0x02322], "fscr" => [0x1D4BB], "gE" => [0x02267], "gEl" => [0x02A8C], "gacute" => [0x001F5], "gamma" => [0x003B3], "gammad" => [0x003DD], "gap" => [0x02A86], "gbreve" => [0x0011F], "gcirc" => [0x0011D], "gcy" => [0x00433], "gdot" => [0x00121], "ge" => [0x02265], "gel" => [0x022DB], "geq" => [0x02265], "geqq" => [0x02267], "geqslant" => [0x02A7E], "ges" => [0x02A7E], "gescc" => [0x02AA9], "gesdot" => [0x02A80], "gesdoto" => [0x02A82], "gesdotol" => [0x02A84], "gesl" => [0x022DB, 0x0FE00], "gesles" => [0x02A94], "gfr" => [0x1D524], "gg" => [0x0226B], "ggg" => [0x022D9], "gimel" => [0x02137], "gjcy" => [0x00453], "gl" => [0x02277], "glE" => [0x02A92], "gla" => [0x02AA5], "glj" => [0x02AA4], "gnE" => [0x02269], "gnap" => [0x02A8A], "gnapprox" => [0x02A8A], "gne" => [0x02A88], "gneq" => [0x02A88], "gneqq" => [0x02269], "gnsim" => [0x022E7], "gopf" => [0x1D558], "grave" => [0x00060], "gscr" => [0x0210A], "gsim" => [0x02273], "gsime" => [0x02A8E], "gsiml" => [0x02A90], "gt" => [0x0003E], "gtcc" => [0x02AA7], "gtcir" => [0x02A7A], "gtdot" => [0x022D7], "gtlPar" => [0x02995], "gtquest" => [0x02A7C], "gtrapprox" => [0x02A86], "gtrarr" => [0x02978], "gtrdot" => [0x022D7], "gtreqless" => [0x022DB], "gtreqqless" => [0x02A8C], "gtrless" => [0x02277], "gtrsim" => [0x02273], "gvertneqq" => [0x02269, 0x0FE00], "gvnE" => [0x02269, 0x0FE00], "hArr" => [0x021D4], "hairsp" => [0x0200A], "half" => [0x000BD], "hamilt" => [0x0210B], "hardcy" => [0x0044A], "harr" => [0x02194], "harrcir" => [0x02948], "harrw" => [0x021AD], "hbar" => [0x0210F], "hcirc" => [0x00125], "hearts" => [0x02665], "heartsuit" => [0x02665], "hellip" => [0x02026], "hercon" => [0x022B9], "hfr" => [0x1D525], "hksearow" => [0x02925], "hkswarow" => [0x02926], "hoarr" => [0x021FF], "homtht" => [0x0223B], "hookleftarrow" => [0x021A9], "hookrightarrow" => [0x021AA], "hopf" => [0x1D559], "horbar" => [0x02015], "hscr" => [0x1D4BD], "hslash" => [0x0210F], "hstrok" => [0x00127], "hybull" => [0x02043], "hyphen" => [0x02010], "iacute" => [0x000ED], "ic" => [0x02063], "icirc" => [0x000EE], "icy" => [0x00438], "iecy" => [0x00435], "iexcl" => [0x000A1], "iff" => [0x021D4], "ifr" => [0x1D526], "igrave" => [0x000EC], "ii" => [0x02148], "iiiint" => [0x02A0C], "iiint" => [0x0222D], "iinfin" => [0x029DC], "iiota" => [0x02129], "ijlig" => [0x00133], "imacr" => [0x0012B], "image" => [0x02111], "imagline" => [0x02110], "imagpart" => [0x02111], "imath" => [0x00131], "imof" => [0x022B7], "imped" => [0x001B5], "in" => [0x02208], "incare" => [0x02105], "infin" => [0x0221E], "infintie" => [0x029DD], "inodot" => [0x00131], "int" => [0x0222B], "intcal" => [0x022BA], "integers" => [0x02124], "intercal" => [0x022BA], "intlarhk" => [0x02A17], "intprod" => [0x02A3C], "iocy" => [0x00451], "iogon" => [0x0012F], "iopf" => [0x1D55A], "iota" => [0x003B9], "iprod" => [0x02A3C], "iquest" => [0x000BF], "iscr" => [0x1D4BE], "isin" => [0x02208], "isinE" => [0x022F9], "isindot" => [0x022F5], "isins" => [0x022F4], "isinsv" => [0x022F3], "isinv" => [0x02208], "it" => [0x02062], "itilde" => [0x00129], "iukcy" => [0x00456], "iuml" => [0x000EF], "jcirc" => [0x00135], "jcy" => [0x00439], "jfr" => [0x1D527], "jmath" => [0x00237], "jopf" => [0x1D55B], "jscr" => [0x1D4BF], "jsercy" => [0x00458], "jukcy" => [0x00454], "kappa" => [0x003BA], "kappav" => [0x003F0], "kcedil" => [0x00137], "kcy" => [0x0043A], "kfr" => [0x1D528], "kgreen" => [0x00138], "khcy" => [0x00445], "kjcy" => [0x0045C], "kopf" => [0x1D55C], "kscr" => [0x1D4C0], "lAarr" => [0x021DA], "lArr" => [0x021D0], "lAtail" => [0x0291B], "lBarr" => [0x0290E], "lE" => [0x02266], "lEg" => [0x02A8B], "lHar" => [0x02962], "lacute" => [0x0013A], "laemptyv" => [0x029B4], "lagran" => [0x02112], "lambda" => [0x003BB], "lang" => [0x027E8], "langd" => [0x02991], "langle" => [0x027E8], "lap" => [0x02A85], "laquo" => [0x000AB], "larr" => [0x02190], "larrb" => [0x021E4], "larrbfs" => [0x0291F], "larrfs" => [0x0291D], "larrhk" => [0x021A9], "larrlp" => [0x021AB], "larrpl" => [0x02939], "larrsim" => [0x02973], "larrtl" => [0x021A2], "lat" => [0x02AAB], "latail" => [0x02919], "late" => [0x02AAD], "lates" => [0x02AAD, 0x0FE00], "lbarr" => [0x0290C], "lbbrk" => [0x02772], "lbrace" => [0x0007B], "lbrack" => [0x0005B], "lbrke" => [0x0298B], "lbrksld" => [0x0298F], "lbrkslu" => [0x0298D], "lcaron" => [0x0013E], "lcedil" => [0x0013C], "lceil" => [0x02308], "lcub" => [0x0007B], "lcy" => [0x0043B], "ldca" => [0x02936], "ldquo" => [0x0201C], "ldquor" => [0x0201E], "ldrdhar" => [0x02967], "ldrushar" => [0x0294B], "ldsh" => [0x021B2], "le" => [0x02264], "leftarrow" => [0x02190], "leftarrowtail" => [0x021A2], "leftharpoondown" => [0x021BD], "leftharpoonup" => [0x021BC], "leftleftarrows" => [0x021C7], "leftrightarrow" => [0x02194], "leftrightarrows" => [0x021C6], "leftrightharpoons" => [0x021CB], "leftrightsquigarrow" => [0x021AD], "leftthreetimes" => [0x022CB], "leg" => [0x022DA], "leq" => [0x02264], "leqq" => [0x02266], "leqslant" => [0x02A7D], "les" => [0x02A7D], "lescc" => [0x02AA8], "lesdot" => [0x02A7F], "lesdoto" => [0x02A81], "lesdotor" => [0x02A83], "lesg" => [0x022DA, 0x0FE00], "lesges" => [0x02A93], "lessapprox" => [0x02A85], "lessdot" => [0x022D6], "lesseqgtr" => [0x022DA], "lesseqqgtr" => [0x02A8B], "lessgtr" => [0x02276], "lesssim" => [0x02272], "lfisht" => [0x0297C], "lfloor" => [0x0230A], "lfr" => [0x1D529], "lg" => [0x02276], "lgE" => [0x02A91], "lhard" => [0x021BD], "lharu" => [0x021BC], "lharul" => [0x0296A], "lhblk" => [0x02584], "ljcy" => [0x00459], "ll" => [0x0226A], "llarr" => [0x021C7], "llcorner" => [0x0231E], "llhard" => [0x0296B], "lltri" => [0x025FA], "lmidot" => [0x00140], "lmoust" => [0x023B0], "lmoustache" => [0x023B0], "lnE" => [0x02268], "lnap" => [0x02A89], "lnapprox" => [0x02A89], "lne" => [0x02A87], "lneq" => [0x02A87], "lneqq" => [0x02268], "lnsim" => [0x022E6], "loang" => [0x027EC], "loarr" => [0x021FD], "lobrk" => [0x027E6], "longleftarrow" => [0x027F5], "longleftrightarrow" => [0x027F7], "longmapsto" => [0x027FC], "longrightarrow" => [0x027F6], "looparrowleft" => [0x021AB], "looparrowright" => [0x021AC], "lopar" => [0x02985], "lopf" => [0x1D55D], "loplus" => [0x02A2D], "lotimes" => [0x02A34], "lowast" => [0x02217], "lowbar" => [0x0005F], "loz" => [0x025CA], "lozenge" => [0x025CA], "lozf" => [0x029EB], "lpar" => [0x00028], "lparlt" => [0x02993], "lrarr" => [0x021C6], "lrcorner" => [0x0231F], "lrhar" => [0x021CB], "lrhard" => [0x0296D], "lrm" => [0x0200E], "lrtri" => [0x022BF], "lsaquo" => [0x02039], "lscr" => [0x1D4C1], "lsh" => [0x021B0], "lsim" => [0x02272], "lsime" => [0x02A8D], "lsimg" => [0x02A8F], "lsqb" => [0x0005B], "lsquo" => [0x02018], "lsquor" => [0x0201A], "lstrok" => [0x00142], "lt" => [0x0003C], "ltcc" => [0x02AA6], "ltcir" => [0x02A79], "ltdot" => [0x022D6], "lthree" => [0x022CB], "ltimes" => [0x022C9], "ltlarr" => [0x02976], "ltquest" => [0x02A7B], "ltrPar" => [0x02996], "ltri" => [0x025C3], "ltrie" => [0x022B4], "ltrif" => [0x025C2], "lurdshar" => [0x0294A], "luruhar" => [0x02966], "lvertneqq" => [0x02268, 0x0FE00], "lvnE" => [0x02268, 0x0FE00], "mDDot" => [0x0223A], "macr" => [0x000AF], "male" => [0x02642], "malt" => [0x02720], "maltese" => [0x02720], "map" => [0x021A6], "mapsto" => [0x021A6], "mapstodown" => [0x021A7], "mapstoleft" => [0x021A4], "mapstoup" => [0x021A5], "marker" => [0x025AE], "mcomma" => [0x02A29], "mcy" => [0x0043C], "mdash" => [0x02014], "measuredangle" => [0x02221], "mfr" => [0x1D52A], "mho" => [0x02127], "micro" => [0x000B5], "mid" => [0x02223], "midast" => [0x0002A], "midcir" => [0x02AF0], "middot" => [0x000B7], "minus" => [0x02212], "minusb" => [0x0229F], "minusd" => [0x02238], "minusdu" => [0x02A2A], "mlcp" => [0x02ADB], "mldr" => [0x02026], "mnplus" => [0x02213], "models" => [0x022A7], "mopf" => [0x1D55E], "mp" => [0x02213], "mscr" => [0x1D4C2], "mstpos" => [0x0223E], "mu" => [0x003BC], "multimap" => [0x022B8], "mumap" => [0x022B8], "nGg" => [0x022D9, 0x00338], "nGt" => [0x0226B, 0x020D2], "nGtv" => [0x0226B, 0x00338], "nLeftarrow" => [0x021CD], "nLeftrightarrow" => [0x021CE], "nLl" => [0x022D8, 0x00338], "nLt" => [0x0226A, 0x020D2], "nLtv" => [0x0226A, 0x00338], "nRightarrow" => [0x021CF], "nVDash" => [0x022AF], "nVdash" => [0x022AE], "nabla" => [0x02207], "nacute" => [0x00144], "nang" => [0x02220, 0x020D2], "nap" => [0x02249], "napE" => [0x02A70, 0x00338], "napid" => [0x0224B, 0x00338], "napos" => [0x00149], "napprox" => [0x02249], "natur" => [0x0266E], "natural" => [0x0266E], "naturals" => [0x02115], "nbsp" => [0x000A0], "nbump" => [0x0224E, 0x00338], "nbumpe" => [0x0224F, 0x00338], "ncap" => [0x02A43], "ncaron" => [0x00148], "ncedil" => [0x00146], "ncong" => [0x02247], "ncongdot" => [0x02A6D, 0x00338], "ncup" => [0x02A42], "ncy" => [0x0043D], "ndash" => [0x02013], "ne" => [0x02260], "neArr" => [0x021D7], "nearhk" => [0x02924], "nearr" => [0x02197], "nearrow" => [0x02197], "nedot" => [0x02250, 0x00338], "nequiv" => [0x02262], "nesear" => [0x02928], "nesim" => [0x02242, 0x00338], "nexist" => [0x02204], "nexists" => [0x02204], "nfr" => [0x1D52B], "ngE" => [0x02267, 0x00338], "nge" => [0x02271], "ngeq" => [0x02271], "ngeqq" => [0x02267, 0x00338], "ngeqslant" => [0x02A7E, 0x00338], "nges" => [0x02A7E, 0x00338], "ngsim" => [0x02275], "ngt" => [0x0226F], "ngtr" => [0x0226F], "nhArr" => [0x021CE], "nharr" => [0x021AE], "nhpar" => [0x02AF2], "ni" => [0x0220B], "nis" => [0x022FC], "nisd" => [0x022FA], "niv" => [0x0220B], "njcy" => [0x0045A], "nlArr" => [0x021CD], "nlE" => [0x02266, 0x00338], "nlarr" => [0x0219A], "nldr" => [0x02025], "nle" => [0x02270], "nleftarrow" => [0x0219A], "nleftrightarrow" => [0x021AE], "nleq" => [0x02270], "nleqq" => [0x02266, 0x00338], "nleqslant" => [0x02A7D, 0x00338], "nles" => [0x02A7D, 0x00338], "nless" => [0x0226E], "nlsim" => [0x02274], "nlt" => [0x0226E], "nltri" => [0x022EA], "nltrie" => [0x022EC], "nmid" => [0x02224], "nopf" => [0x1D55F], "not" => [0x000AC], "notin" => [0x02209], "notinE" => [0x022F9, 0x00338], "notindot" => [0x022F5, 0x00338], "notinva" => [0x02209], "notinvb" => [0x022F7], "notinvc" => [0x022F6], "notni" => [0x0220C], "notniva" => [0x0220C], "notnivb" => [0x022FE], "notnivc" => [0x022FD], "npar" => [0x02226], "nparallel" => [0x02226], "nparsl" => [0x02AFD, 0x020E5], "npart" => [0x02202, 0x00338], "npolint" => [0x02A14], "npr" => [0x02280], "nprcue" => [0x022E0], "npre" => [0x02AAF, 0x00338], "nprec" => [0x02280], "npreceq" => [0x02AAF, 0x00338], "nrArr" => [0x021CF], "nrarr" => [0x0219B], "nrarrc" => [0x02933, 0x00338], "nrarrw" => [0x0219D, 0x00338], "nrightarrow" => [0x0219B], "nrtri" => [0x022EB], "nrtrie" => [0x022ED], "nsc" => [0x02281], "nsccue" => [0x022E1], "nsce" => [0x02AB0, 0x00338], "nscr" => [0x1D4C3], "nshortmid" => [0x02224], "nshortparallel" => [0x02226], "nsim" => [0x02241], "nsime" => [0x02244], "nsimeq" => [0x02244], "nsmid" => [0x02224], "nspar" => [0x02226], "nsqsube" => [0x022E2], "nsqsupe" => [0x022E3], "nsub" => [0x02284], "nsubE" => [0x02AC5, 0x00338], "nsube" => [0x02288], "nsubset" => [0x02282, 0x020D2], "nsubseteq" => [0x02288], "nsubseteqq" => [0x02AC5, 0x00338], "nsucc" => [0x02281], "nsucceq" => [0x02AB0, 0x00338], "nsup" => [0x02285], "nsupE" => [0x02AC6, 0x00338], "nsupe" => [0x02289], "nsupset" => [0x02283, 0x020D2], "nsupseteq" => [0x02289], "nsupseteqq" => [0x02AC6, 0x00338], "ntgl" => [0x02279], "ntilde" => [0x000F1], "ntlg" => [0x02278], "ntriangleleft" => [0x022EA], "ntrianglelefteq" => [0x022EC], "ntriangleright" => [0x022EB], "ntrianglerighteq" => [0x022ED], "nu" => [0x003BD], "num" => [0x00023], "numero" => [0x02116], "numsp" => [0x02007], "nvDash" => [0x022AD], "nvHarr" => [0x02904], "nvap" => [0x0224D, 0x020D2], "nvdash" => [0x022AC], "nvge" => [0x02265, 0x020D2], "nvgt" => [0x0003E, 0x020D2], "nvinfin" => [0x029DE], "nvlArr" => [0x02902], "nvle" => [0x02264, 0x020D2], "nvlt" => [0x0003C, 0x020D2], "nvltrie" => [0x022B4, 0x020D2], "nvrArr" => [0x02903], "nvrtrie" => [0x022B5, 0x020D2], "nvsim" => [0x0223C, 0x020D2], "nwArr" => [0x021D6], "nwarhk" => [0x02923], "nwarr" => [0x02196], "nwarrow" => [0x02196], "nwnear" => [0x02927], "oS" => [0x024C8], "oacute" => [0x000F3], "oast" => [0x0229B], "ocir" => [0x0229A], "ocirc" => [0x000F4], "ocy" => [0x0043E], "odash" => [0x0229D], "odblac" => [0x00151], "odiv" => [0x02A38], "odot" => [0x02299], "odsold" => [0x029BC], "oelig" => [0x00153], "ofcir" => [0x029BF], "ofr" => [0x1D52C], "ogon" => [0x002DB], "ograve" => [0x000F2], "ogt" => [0x029C1], "ohbar" => [0x029B5], "ohm" => [0x003A9], "oint" => [0x0222E], "olarr" => [0x021BA], "olcir" => [0x029BE], "olcross" => [0x029BB], "oline" => [0x0203E], "olt" => [0x029C0], "omacr" => [0x0014D], "omega" => [0x003C9], "omicron" => [0x003BF], "omid" => [0x029B6], "ominus" => [0x02296], "oopf" => [0x1D560], "opar" => [0x029B7], "operp" => [0x029B9], "oplus" => [0x02295], "or" => [0x02228], "orarr" => [0x021BB], "ord" => [0x02A5D], "order" => [0x02134], "orderof" => [0x02134], "ordf" => [0x000AA], "ordm" => [0x000BA], "origof" => [0x022B6], "oror" => [0x02A56], "orslope" => [0x02A57], "orv" => [0x02A5B], "oscr" => [0x02134], "oslash" => [0x000F8], "osol" => [0x02298], "otilde" => [0x000F5], "otimes" => [0x02297], "otimesas" => [0x02A36], "ouml" => [0x000F6], "ovbar" => [0x0233D], "par" => [0x02225], "para" => [0x000B6], "parallel" => [0x02225], "parsim" => [0x02AF3], "parsl" => [0x02AFD], "part" => [0x02202], "pcy" => [0x0043F], "percnt" => [0x00025], "period" => [0x0002E], "permil" => [0x02030], "perp" => [0x022A5], "pertenk" => [0x02031], "pfr" => [0x1D52D], "phi" => [0x003C6], "phiv" => [0x003D5], "phmmat" => [0x02133], "phone" => [0x0260E], "pi" => [0x003C0], "pitchfork" => [0x022D4], "piv" => [0x003D6], "planck" => [0x0210F], "planckh" => [0x0210E], "plankv" => [0x0210F], "plus" => [0x0002B], "plusacir" => [0x02A23], "plusb" => [0x0229E], "pluscir" => [0x02A22], "plusdo" => [0x02214], "plusdu" => [0x02A25], "pluse" => [0x02A72], "plusmn" => [0x000B1], "plussim" => [0x02A26], "plustwo" => [0x02A27], "pm" => [0x000B1], "pointint" => [0x02A15], "popf" => [0x1D561], "pound" => [0x000A3], "pr" => [0x0227A], "prE" => [0x02AB3], "prap" => [0x02AB7], "prcue" => [0x0227C], "pre" => [0x02AAF], "prec" => [0x0227A], "precapprox" => [0x02AB7], "preccurlyeq" => [0x0227C], "preceq" => [0x02AAF], "precnapprox" => [0x02AB9], "precneqq" => [0x02AB5], "precnsim" => [0x022E8], "precsim" => [0x0227E], "prime" => [0x02032], "primes" => [0x02119], "prnE" => [0x02AB5], "prnap" => [0x02AB9], "prnsim" => [0x022E8], "prod" => [0x0220F], "profalar" => [0x0232E], "profline" => [0x02312], "profsurf" => [0x02313], "prop" => [0x0221D], "propto" => [0x0221D], "prsim" => [0x0227E], "prurel" => [0x022B0], "pscr" => [0x1D4C5], "psi" => [0x003C8], "puncsp" => [0x02008], "qfr" => [0x1D52E], "qint" => [0x02A0C], "qopf" => [0x1D562], "qprime" => [0x02057], "qscr" => [0x1D4C6], "quaternions" => [0x0210D], "quatint" => [0x02A16], "quest" => [0x0003F], "questeq" => [0x0225F], "quot" => [0x00022], "rAarr" => [0x021DB], "rArr" => [0x021D2], "rAtail" => [0x0291C], "rBarr" => [0x0290F], "rHar" => [0x02964], "race" => [0x0223D, 0x00331], "racute" => [0x00155], "radic" => [0x0221A], "raemptyv" => [0x029B3], "rang" => [0x027E9], "rangd" => [0x02992], "range" => [0x029A5], "rangle" => [0x027E9], "raquo" => [0x000BB], "rarr" => [0x02192], "rarrap" => [0x02975], "rarrb" => [0x021E5], "rarrbfs" => [0x02920], "rarrc" => [0x02933], "rarrfs" => [0x0291E], "rarrhk" => [0x021AA], "rarrlp" => [0x021AC], "rarrpl" => [0x02945], "rarrsim" => [0x02974], "rarrtl" => [0x021A3], "rarrw" => [0x0219D], "ratail" => [0x0291A], "ratio" => [0x02236], "rationals" => [0x0211A], "rbarr" => [0x0290D], "rbbrk" => [0x02773], "rbrace" => [0x0007D], "rbrack" => [0x0005D], "rbrke" => [0x0298C], "rbrksld" => [0x0298E], "rbrkslu" => [0x02990], "rcaron" => [0x00159], "rcedil" => [0x00157], "rceil" => [0x02309], "rcub" => [0x0007D], "rcy" => [0x00440], "rdca" => [0x02937], "rdldhar" => [0x02969], "rdquo" => [0x0201D], "rdquor" => [0x0201D], "rdsh" => [0x021B3], "real" => [0x0211C], "realine" => [0x0211B], "realpart" => [0x0211C], "reals" => [0x0211D], "rect" => [0x025AD], "reg" => [0x000AE], "rfisht" => [0x0297D], "rfloor" => [0x0230B], "rfr" => [0x1D52F], "rhard" => [0x021C1], "rharu" => [0x021C0], "rharul" => [0x0296C], "rho" => [0x003C1], "rhov" => [0x003F1], "rightarrow" => [0x02192], "rightarrowtail" => [0x021A3], "rightharpoondown" => [0x021C1], "rightharpoonup" => [0x021C0], "rightleftarrows" => [0x021C4], "rightleftharpoons" => [0x021CC], "rightrightarrows" => [0x021C9], "rightsquigarrow" => [0x0219D], "rightthreetimes" => [0x022CC], "ring" => [0x002DA], "risingdotseq" => [0x02253], "rlarr" => [0x021C4], "rlhar" => [0x021CC], "rlm" => [0x0200F], "rmoust" => [0x023B1], "rmoustache" => [0x023B1], "rnmid" => [0x02AEE], "roang" => [0x027ED], "roarr" => [0x021FE], "robrk" => [0x027E7], "ropar" => [0x02986], "ropf" => [0x1D563], "roplus" => [0x02A2E], "rotimes" => [0x02A35], "rpar" => [0x00029], "rpargt" => [0x02994], "rppolint" => [0x02A12], "rrarr" => [0x021C9], "rsaquo" => [0x0203A], "rscr" => [0x1D4C7], "rsh" => [0x021B1], "rsqb" => [0x0005D], "rsquo" => [0x02019], "rsquor" => [0x02019], "rthree" => [0x022CC], "rtimes" => [0x022CA], "rtri" => [0x025B9], "rtrie" => [0x022B5], "rtrif" => [0x025B8], "rtriltri" => [0x029CE], "ruluhar" => [0x02968], "rx" => [0x0211E], "sacute" => [0x0015B], "sbquo" => [0x0201A], "sc" => [0x0227B], "scE" => [0x02AB4], "scap" => [0x02AB8], "scaron" => [0x00161], "sccue" => [0x0227D], "sce" => [0x02AB0], "scedil" => [0x0015F], "scirc" => [0x0015D], "scnE" => [0x02AB6], "scnap" => [0x02ABA], "scnsim" => [0x022E9], "scpolint" => [0x02A13], "scsim" => [0x0227F], "scy" => [0x00441], "sdot" => [0x022C5], "sdotb" => [0x022A1], "sdote" => [0x02A66], "seArr" => [0x021D8], "searhk" => [0x02925], "searr" => [0x02198], "searrow" => [0x02198], "sect" => [0x000A7], "semi" => [0x0003B], "seswar" => [0x02929], "setminus" => [0x02216], "setmn" => [0x02216], "sext" => [0x02736], "sfr" => [0x1D530], "sfrown" => [0x02322], "sharp" => [0x0266F], "shchcy" => [0x00449], "shcy" => [0x00448], "shortmid" => [0x02223], "shortparallel" => [0x02225], "shy" => [0x000AD], "sigma" => [0x003C3], "sigmaf" => [0x003C2], "sigmav" => [0x003C2], "sim" => [0x0223C], "simdot" => [0x02A6A], "sime" => [0x02243], "simeq" => [0x02243], "simg" => [0x02A9E], "simgE" => [0x02AA0], "siml" => [0x02A9D], "simlE" => [0x02A9F], "simne" => [0x02246], "simplus" => [0x02A24], "simrarr" => [0x02972], "slarr" => [0x02190], "smallsetminus" => [0x02216], "smashp" => [0x02A33], "smeparsl" => [0x029E4], "smid" => [0x02223], "smile" => [0x02323], "smt" => [0x02AAA], "smte" => [0x02AAC], "smtes" => [0x02AAC, 0x0FE00], "softcy" => [0x0044C], "sol" => [0x0002F], "solb" => [0x029C4], "solbar" => [0x0233F], "sopf" => [0x1D564], "spades" => [0x02660], "spadesuit" => [0x02660], "spar" => [0x02225], "sqcap" => [0x02293], "sqcaps" => [0x02293, 0x0FE00], "sqcup" => [0x02294], "sqcups" => [0x02294, 0x0FE00], "sqsub" => [0x0228F], "sqsube" => [0x02291], "sqsubset" => [0x0228F], "sqsubseteq" => [0x02291], "sqsup" => [0x02290], "sqsupe" => [0x02292], "sqsupset" => [0x02290], "sqsupseteq" => [0x02292], "squ" => [0x025A1], "square" => [0x025A1], "squarf" => [0x025AA], "squf" => [0x025AA], "srarr" => [0x02192], "sscr" => [0x1D4C8], "ssetmn" => [0x02216], "ssmile" => [0x02323], "sstarf" => [0x022C6], "star" => [0x02606], "starf" => [0x02605], "straightepsilon" => [0x003F5], "straightphi" => [0x003D5], "strns" => [0x000AF], "sub" => [0x02282], "subE" => [0x02AC5], "subdot" => [0x02ABD], "sube" => [0x02286], "subedot" => [0x02AC3], "submult" => [0x02AC1], "subnE" => [0x02ACB], "subne" => [0x0228A], "subplus" => [0x02ABF], "subrarr" => [0x02979], "subset" => [0x02282], "subseteq" => [0x02286], "subseteqq" => [0x02AC5], "subsetneq" => [0x0228A], "subsetneqq" => [0x02ACB], "subsim" => [0x02AC7], "subsub" => [0x02AD5], "subsup" => [0x02AD3], "succ" => [0x0227B], "succapprox" => [0x02AB8], "succcurlyeq" => [0x0227D], "succeq" => [0x02AB0], "succnapprox" => [0x02ABA], "succneqq" => [0x02AB6], "succnsim" => [0x022E9], "succsim" => [0x0227F], "sum" => [0x02211], "sung" => [0x0266A], "sup" => [0x02283], "sup1" => [0x000B9], "sup2" => [0x000B2], "sup3" => [0x000B3], "supE" => [0x02AC6], "supdot" => [0x02ABE], "supdsub" => [0x02AD8], "supe" => [0x02287], "supedot" => [0x02AC4], "suphsol" => [0x027C9], "suphsub" => [0x02AD7], "suplarr" => [0x0297B], "supmult" => [0x02AC2], "supnE" => [0x02ACC], "supne" => [0x0228B], "supplus" => [0x02AC0], "supset" => [0x02283], "supseteq" => [0x02287], "supseteqq" => [0x02AC6], "supsetneq" => [0x0228B], "supsetneqq" => [0x02ACC], "supsim" => [0x02AC8], "supsub" => [0x02AD4], "supsup" => [0x02AD6], "swArr" => [0x021D9], "swarhk" => [0x02926], "swarr" => [0x02199], "swarrow" => [0x02199], "swnwar" => [0x0292A], "szlig" => [0x000DF], "target" => [0x02316], "tau" => [0x003C4], "tbrk" => [0x023B4], "tcaron" => [0x00165], "tcedil" => [0x00163], "tcy" => [0x00442], "tdot" => [0x020DB], "telrec" => [0x02315], "tfr" => [0x1D531], "there4" => [0x02234], "therefore" => [0x02234], "theta" => [0x003B8], "thetasym" => [0x003D1], "thetav" => [0x003D1], "thickapprox" => [0x02248], "thicksim" => [0x0223C], "thinsp" => [0x02009], "thkap" => [0x02248], "thksim" => [0x0223C], "thorn" => [0x000FE], "tilde" => [0x002DC], "times" => [0x000D7], "timesb" => [0x022A0], "timesbar" => [0x02A31], "timesd" => [0x02A30], "tint" => [0x0222D], "toea" => [0x02928], "top" => [0x022A4], "topbot" => [0x02336], "topcir" => [0x02AF1], "topf" => [0x1D565], "topfork" => [0x02ADA], "tosa" => [0x02929], "tprime" => [0x02034], "trade" => [0x02122], "triangle" => [0x025B5], "triangledown" => [0x025BF], "triangleleft" => [0x025C3], "trianglelefteq" => [0x022B4], "triangleq" => [0x0225C], "triangleright" => [0x025B9], "trianglerighteq" => [0x022B5], "tridot" => [0x025EC], "trie" => [0x0225C], "triminus" => [0x02A3A], "triplus" => [0x02A39], "trisb" => [0x029CD], "tritime" => [0x02A3B], "trpezium" => [0x023E2], "tscr" => [0x1D4C9], "tscy" => [0x00446], "tshcy" => [0x0045B], "tstrok" => [0x00167], "twixt" => [0x0226C], "twoheadleftarrow" => [0x0219E], "twoheadrightarrow" => [0x021A0], "uArr" => [0x021D1], "uHar" => [0x02963], "uacute" => [0x000FA], "uarr" => [0x02191], "ubrcy" => [0x0045E], "ubreve" => [0x0016D], "ucirc" => [0x000FB], "ucy" => [0x00443], "udarr" => [0x021C5], "udblac" => [0x00171], "udhar" => [0x0296E], "ufisht" => [0x0297E], "ufr" => [0x1D532], "ugrave" => [0x000F9], "uharl" => [0x021BF], "uharr" => [0x021BE], "uhblk" => [0x02580], "ulcorn" => [0x0231C], "ulcorner" => [0x0231C], "ulcrop" => [0x0230F], "ultri" => [0x025F8], "umacr" => [0x0016B], "uml" => [0x000A8], "uogon" => [0x00173], "uopf" => [0x1D566], "uparrow" => [0x02191], "updownarrow" => [0x02195], "upharpoonleft" => [0x021BF], "upharpoonright" => [0x021BE], "uplus" => [0x0228E], "upsi" => [0x003C5], "upsih" => [0x003D2], "upsilon" => [0x003C5], "upuparrows" => [0x021C8], "urcorn" => [0x0231D], "urcorner" => [0x0231D], "urcrop" => [0x0230E], "uring" => [0x0016F], "urtri" => [0x025F9], "uscr" => [0x1D4CA], "utdot" => [0x022F0], "utilde" => [0x00169], "utri" => [0x025B5], "utrif" => [0x025B4], "uuarr" => [0x021C8], "uuml" => [0x000FC], "uwangle" => [0x029A7], "vArr" => [0x021D5], "vBar" => [0x02AE8], "vBarv" => [0x02AE9], "vDash" => [0x022A8], "vangrt" => [0x0299C], "varepsilon" => [0x003F5], "varkappa" => [0x003F0], "varnothing" => [0x02205], "varphi" => [0x003D5], "varpi" => [0x003D6], "varpropto" => [0x0221D], "varr" => [0x02195], "varrho" => [0x003F1], "varsigma" => [0x003C2], "varsubsetneq" => [0x0228A, 0x0FE00], "varsubsetneqq" => [0x02ACB, 0x0FE00], "varsupsetneq" => [0x0228B, 0x0FE00], "varsupsetneqq" => [0x02ACC, 0x0FE00], "vartheta" => [0x003D1], "vartriangleleft" => [0x022B2], "vartriangleright" => [0x022B3], "vcy" => [0x00432], "vdash" => [0x022A2], "vee" => [0x02228], "veebar" => [0x022BB], "veeeq" => [0x0225A], "vellip" => [0x022EE], "verbar" => [0x0007C], "vert" => [0x0007C], "vfr" => [0x1D533], "vltri" => [0x022B2], "vnsub" => [0x02282, 0x020D2], "vnsup" => [0x02283, 0x020D2], "vopf" => [0x1D567], "vprop" => [0x0221D], "vrtri" => [0x022B3], "vscr" => [0x1D4CB], "vsubnE" => [0x02ACB, 0x0FE00], "vsubne" => [0x0228A, 0x0FE00], "vsupnE" => [0x02ACC, 0x0FE00], "vsupne" => [0x0228B, 0x0FE00], "vzigzag" => [0x0299A], "wcirc" => [0x00175], "wedbar" => [0x02A5F], "wedge" => [0x02227], "wedgeq" => [0x02259], "weierp" => [0x02118], "wfr" => [0x1D534], "wopf" => [0x1D568], "wp" => [0x02118], "wr" => [0x02240], "wreath" => [0x02240], "wscr" => [0x1D4CC], "xcap" => [0x022C2], "xcirc" => [0x025EF], "xcup" => [0x022C3], "xdtri" => [0x025BD], "xfr" => [0x1D535], "xhArr" => [0x027FA], "xharr" => [0x027F7], "xi" => [0x003BE], "xlArr" => [0x027F8], "xlarr" => [0x027F5], "xmap" => [0x027FC], "xnis" => [0x022FB], "xodot" => [0x02A00], "xopf" => [0x1D569], "xoplus" => [0x02A01], "xotime" => [0x02A02], "xrArr" => [0x027F9], "xrarr" => [0x027F6], "xscr" => [0x1D4CD], "xsqcup" => [0x02A06], "xuplus" => [0x02A04], "xutri" => [0x025B3], "xvee" => [0x022C1], "xwedge" => [0x022C0], "yacute" => [0x000FD], "yacy" => [0x0044F], "ycirc" => [0x00177], "ycy" => [0x0044B], "yen" => [0x000A5], "yfr" => [0x1D536], "yicy" => [0x00457], "yopf" => [0x1D56A], "yscr" => [0x1D4CE], "yucy" => [0x0044E], "yuml" => [0x000FF], "zacute" => [0x0017A], "zcaron" => [0x0017E], "zcy" => [0x00437], "zdot" => [0x0017C], "zeetrf" => [0x02128], "zeta" => [0x003B6], "zfr" => [0x1D537], "zhcy" => [0x00436], "zigrarr" => [0x021DD], "zopf" => [0x1D56B], "zscr" => [0x1D4CF], "zwj" => [0x0200D], "zwnj" => [0x0200C], } PK ]LRh$h$/gems/rdoc-6.2.1.1/lib/rdoc/markdown/literals.rbnu[# coding: UTF-8 # frozen_string_literal: true # :markup: markdown ## #-- # This set of literals is for Ruby 1.9 regular expressions and gives full # unicode support. # # Unlike peg-markdown, this set of literals recognizes Unicode alphanumeric # characters, newlines and spaces. class RDoc::Markdown::Literals # :stopdoc: # This is distinct from setup_parser so that a standalone parser # can redefine #initialize and still have access to the proper # parser setup code. def initialize(str, debug=false) setup_parser(str, debug) end # Prepares for parsing +str+. If you define a custom initialize you must # call this method before #parse def setup_parser(str, debug=false) set_string str, 0 @memoizations = Hash.new { |h,k| h[k] = {} } @result = nil @failed_rule = nil @failing_rule_offset = -1 setup_foreign_grammar end attr_reader :string attr_reader :failing_rule_offset attr_accessor :result, :pos def current_column(target=pos) if c = string.rindex("\n", target-1) return target - c - 1 end target + 1 end def current_line(target=pos) cur_offset = 0 cur_line = 0 string.each_line do |line| cur_line += 1 cur_offset += line.size return cur_line if cur_offset >= target end -1 end def lines lines = [] string.each_line { |l| lines << l } lines end def get_text(start) @string[start..@pos-1] end # Sets the string and current parsing position for the parser. def set_string string, pos @string = string @string_size = string ? string.size : 0 @pos = pos end def show_pos width = 10 if @pos < width "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")" else "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")" end end def failure_info l = current_line @failing_rule_offset c = current_column @failing_rule_offset if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'" else "line #{l}, column #{c}: failed rule '#{@failed_rule}'" end end def failure_caret l = current_line @failing_rule_offset c = current_column @failing_rule_offset line = lines[l-1] "#{line}\n#{' ' * (c - 1)}^" end def failure_character l = current_line @failing_rule_offset c = current_column @failing_rule_offset lines[l-1][c-1, 1] end def failure_oneline l = current_line @failing_rule_offset c = current_column @failing_rule_offset char = lines[l-1][c-1, 1] if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'" else "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'" end end class ParseError < RuntimeError end def raise_error raise ParseError, failure_oneline end def show_error(io=STDOUT) error_pos = @failing_rule_offset line_no = current_line(error_pos) col_no = current_column(error_pos) io.puts "On line #{line_no}, column #{col_no}:" if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')" else io.puts "Failed to match rule '#{@failed_rule}'" end io.puts "Got: #{string[error_pos,1].inspect}" line = lines[line_no-1] io.puts "=> #{line}" io.print(" " * (col_no + 3)) io.puts "^" end def set_failed_rule(name) if @pos > @failing_rule_offset @failed_rule = name @failing_rule_offset = @pos end end attr_reader :failed_rule def match_string(str) len = str.size if @string[pos,len] == str @pos += len return str end return nil end def scan(reg) if m = reg.match(@string[@pos..-1]) width = m.end(0) @pos += width return true end return nil end if "".respond_to? :ord def get_byte if @pos >= @string_size return nil end s = @string[@pos].ord @pos += 1 s end else def get_byte if @pos >= @string_size return nil end s = @string[@pos] @pos += 1 s end end def parse(rule=nil) # We invoke the rules indirectly via apply # instead of by just calling them as methods because # if the rules use left recursion, apply needs to # manage that. if !rule apply(:_root) else method = rule.gsub("-","_hyphen_") apply :"_#{method}" end end class MemoEntry def initialize(ans, pos) @ans = ans @pos = pos @result = nil @set = false @left_rec = false end attr_reader :ans, :pos, :result, :set attr_accessor :left_rec def move!(ans, pos, result) @ans = ans @pos = pos @result = result @set = true @left_rec = false end end def external_invoke(other, rule, *args) old_pos = @pos old_string = @string set_string other.string, other.pos begin if val = __send__(rule, *args) other.pos = @pos other.result = @result else other.set_failed_rule "#{self.class}##{rule}" end val ensure set_string old_string, old_pos end end def apply_with_args(rule, *args) memo_key = [rule, args] if m = @memoizations[memo_key][@pos] @pos = m.pos if !m.set m.left_rec = true return nil end @result = m.result return m.ans else m = MemoEntry.new(nil, @pos) @memoizations[memo_key][@pos] = m start_pos = @pos ans = __send__ rule, *args lr = m.left_rec m.move! ans, @pos, @result # Don't bother trying to grow the left recursion # if it's failing straight away (thus there is no seed) if ans and lr return grow_lr(rule, args, start_pos, m) else return ans end end end def apply(rule) if m = @memoizations[rule][@pos] @pos = m.pos if !m.set m.left_rec = true return nil end @result = m.result return m.ans else m = MemoEntry.new(nil, @pos) @memoizations[rule][@pos] = m start_pos = @pos ans = __send__ rule lr = m.left_rec m.move! ans, @pos, @result # Don't bother trying to grow the left recursion # if it's failing straight away (thus there is no seed) if ans and lr return grow_lr(rule, nil, start_pos, m) else return ans end end end def grow_lr(rule, args, start_pos, m) while true @pos = start_pos @result = m.result if args ans = __send__ rule, *args else ans = __send__ rule end return nil unless ans break if @pos <= m.pos m.move! ans, @pos, @result end @result = m.result @pos = m.pos return m.ans end class RuleInfo def initialize(name, rendered) @name = name @rendered = rendered end attr_reader :name, :rendered end def self.rule_info(name, rendered) RuleInfo.new(name, rendered) end # :startdoc: # :stopdoc: def setup_foreign_grammar; end # Alphanumeric = /\p{Word}/ def _Alphanumeric _tmp = scan(/\A(?-mix:\p{Word})/) set_failed_rule :_Alphanumeric unless _tmp return _tmp end # AlphanumericAscii = /[A-Za-z0-9]/ def _AlphanumericAscii _tmp = scan(/\A(?-mix:[A-Za-z0-9])/) set_failed_rule :_AlphanumericAscii unless _tmp return _tmp end # BOM = "uFEFF" def _BOM _tmp = match_string("uFEFF") set_failed_rule :_BOM unless _tmp return _tmp end # Newline = /\n|\r\n?|\p{Zl}|\p{Zp}/ def _Newline _tmp = scan(/\A(?-mix:\n|\r\n?|\p{Zl}|\p{Zp})/) set_failed_rule :_Newline unless _tmp return _tmp end # NonAlphanumeric = /\p{^Word}/ def _NonAlphanumeric _tmp = scan(/\A(?-mix:\p{^Word})/) set_failed_rule :_NonAlphanumeric unless _tmp return _tmp end # Spacechar = /\t|\p{Zs}/ def _Spacechar _tmp = scan(/\A(?-mix:\t|\p{Zs})/) set_failed_rule :_Spacechar unless _tmp return _tmp end Rules = {} Rules[:_Alphanumeric] = rule_info("Alphanumeric", "/\\p{Word}/") Rules[:_AlphanumericAscii] = rule_info("AlphanumericAscii", "/[A-Za-z0-9]/") Rules[:_BOM] = rule_info("BOM", "\"uFEFF\"") Rules[:_Newline] = rule_info("Newline", "/\\n|\\r\\n?|\\p{Zl}|\\p{Zp}/") Rules[:_NonAlphanumeric] = rule_info("NonAlphanumeric", "/\\p{^Word}/") Rules[:_Spacechar] = rule_info("Spacechar", "/\\t|\\p{Zs}/") # :startdoc: end PK ]FMYY#gems/rdoc-6.2.1.1/lib/rdoc/store.rbnu[# frozen_string_literal: true require 'fileutils' ## # A set of rdoc data for a single project (gem, path, etc.). # # The store manages reading and writing ri data for a project and maintains a # cache of methods, classes and ancestors in the store. # # The store maintains a #cache of its contents for faster lookup. After # adding items to the store it must be flushed using #save_cache. The cache # contains the following structures: # # @cache = { # :ancestors => {}, # class name => ancestor names # :attributes => {}, # class name => attributes # :class_methods => {}, # class name => class methods # :instance_methods => {}, # class name => instance methods # :modules => [], # classes and modules in this store # :pages => [], # page names # } #-- # TODO need to prune classes class RDoc::Store ## # Errors raised from loading or saving the store class Error < RDoc::Error end ## # Raised when a stored file for a class, module, page or method is missing. class MissingFileError < Error ## # The store the file should exist in attr_reader :store ## # The file the #name should be saved as attr_reader :file ## # The name of the object the #file would be loaded from attr_reader :name ## # Creates a new MissingFileError for the missing +file+ for the given # +name+ that should have been in the +store+. def initialize store, file, name @store = store @file = file @name = name end def message # :nodoc: "store at #{@store.path} missing file #{@file} for #{@name}" end end ## # Stores the name of the C variable a class belongs to. This helps wire up # classes defined from C across files. attr_reader :c_enclosure_classes # :nodoc: attr_reader :c_enclosure_names # :nodoc: ## # Maps C variables to class or module names for each parsed C file. attr_reader :c_class_variables ## # Maps C variables to singleton class names for each parsed C file. attr_reader :c_singleton_class_variables ## # If true this Store will not write any files attr_accessor :dry_run ## # Path this store reads or writes attr_accessor :path ## # The RDoc::RDoc driver for this parse tree. This allows classes consulting # the documentation tree to access user-set options, for example. attr_accessor :rdoc ## # Type of ri datastore this was loaded from. See RDoc::RI::Driver, # RDoc::RI::Paths. attr_accessor :type ## # The contents of the Store attr_reader :cache ## # The encoding of the contents in the Store attr_accessor :encoding ## # The lazy constants alias will be discovered in passing attr_reader :unmatched_constant_alias ## # Creates a new Store of +type+ that will load or save to +path+ def initialize path = nil, type = nil @dry_run = false @encoding = nil @path = path @rdoc = nil @type = type @cache = { :ancestors => {}, :attributes => {}, :class_methods => {}, :c_class_variables => {}, :c_singleton_class_variables => {}, :encoding => @encoding, :instance_methods => {}, :main => nil, :modules => [], :pages => [], :title => nil, } @classes_hash = {} @modules_hash = {} @files_hash = {} @text_files_hash = {} @c_enclosure_classes = {} @c_enclosure_names = {} @c_class_variables = {} @c_singleton_class_variables = {} @unique_classes = nil @unique_modules = nil @unmatched_constant_alias = {} end ## # Adds +module+ as an enclosure (namespace) for the given +variable+ for C # files. def add_c_enclosure variable, namespace @c_enclosure_classes[variable] = namespace end ## # Adds C variables from an RDoc::Parser::C def add_c_variables c_parser filename = c_parser.top_level.relative_name @c_class_variables[filename] = make_variable_map c_parser.classes @c_singleton_class_variables[filename] = c_parser.singleton_classes end ## # Adds the file with +name+ as an RDoc::TopLevel to the store. Returns the # created RDoc::TopLevel. def add_file absolute_name, relative_name: absolute_name, parser: nil unless top_level = @files_hash[relative_name] then top_level = RDoc::TopLevel.new absolute_name, relative_name top_level.parser = parser if parser top_level.store = self @files_hash[relative_name] = top_level @text_files_hash[relative_name] = top_level if top_level.text? end top_level end def update_parser_of_file(absolute_name, parser) if top_level = @files_hash[absolute_name] then @text_files_hash[absolute_name] = top_level if top_level.text? end end ## # Returns all classes discovered by RDoc def all_classes @classes_hash.values end ## # Returns all classes and modules discovered by RDoc def all_classes_and_modules @classes_hash.values + @modules_hash.values end ## # All TopLevels known to RDoc def all_files @files_hash.values end ## # Returns all modules discovered by RDoc def all_modules modules_hash.values end ## # Ancestors cache accessor. Maps a klass name to an Array of its ancestors # in this store. If Foo in this store inherits from Object, Kernel won't be # listed (it will be included from ruby's ri store). def ancestors @cache[:ancestors] end ## # Attributes cache accessor. Maps a class to an Array of its attributes. def attributes @cache[:attributes] end ## # Path to the cache file def cache_path File.join @path, 'cache.ri' end ## # Path to the ri data for +klass_name+ def class_file klass_name name = klass_name.split('::').last File.join class_path(klass_name), "cdesc-#{name}.ri" end ## # Class methods cache accessor. Maps a class to an Array of its class # methods (not full name). def class_methods @cache[:class_methods] end ## # Path where data for +klass_name+ will be stored (methods or class data) def class_path klass_name File.join @path, *klass_name.split('::') end ## # Hash of all classes known to RDoc def classes_hash @classes_hash end ## # Removes empty items and ensures item in each collection are unique and # sorted def clean_cache_collection collection # :nodoc: collection.each do |name, item| if item.empty? then collection.delete name else # HACK mongrel-1.1.5 documents its files twice item.uniq! item.sort! end end end ## # Prepares the RDoc code object tree for use by a generator. # # It finds unique classes/modules defined, and replaces classes/modules that # are aliases for another one by a copy with RDoc::ClassModule#is_alias_for # set. # # It updates the RDoc::ClassModule#constant_aliases attribute of "real" # classes or modules. # # It also completely removes the classes and modules that should be removed # from the documentation and the methods that have a visibility below # +min_visibility+, which is the --visibility option. # # See also RDoc::Context#remove_from_documentation? def complete min_visibility fix_basic_object_inheritance # cache included modules before they are removed from the documentation all_classes_and_modules.each { |cm| cm.ancestors } unless min_visibility == :nodoc then remove_nodoc @classes_hash remove_nodoc @modules_hash end @unique_classes = find_unique @classes_hash @unique_modules = find_unique @modules_hash unique_classes_and_modules.each do |cm| cm.complete min_visibility end @files_hash.each_key do |file_name| tl = @files_hash[file_name] unless tl.text? then tl.modules_hash.clear tl.classes_hash.clear tl.classes_or_modules.each do |cm| name = cm.full_name if cm.type == 'class' then tl.classes_hash[name] = cm if @classes_hash[name] else tl.modules_hash[name] = cm if @modules_hash[name] end end end end end ## # Hash of all files known to RDoc def files_hash @files_hash end ## # Finds the enclosure (namespace) for the given C +variable+. def find_c_enclosure variable @c_enclosure_classes.fetch variable do break unless name = @c_enclosure_names[variable] mod = find_class_or_module name unless mod then loaded_mod = load_class_data name file = loaded_mod.in_files.first return unless file # legacy data source file.store = self mod = file.add_module RDoc::NormalModule, name end @c_enclosure_classes[variable] = mod end end ## # Finds the class with +name+ in all discovered classes def find_class_named name @classes_hash[name] end ## # Finds the class with +name+ starting in namespace +from+ def find_class_named_from name, from from = find_class_named from unless RDoc::Context === from until RDoc::TopLevel === from do return nil unless from klass = from.find_class_named name return klass if klass from = from.parent end find_class_named name end ## # Finds the class or module with +name+ def find_class_or_module name name = $' if name =~ /^::/ @classes_hash[name] || @modules_hash[name] end ## # Finds the file with +name+ in all discovered files def find_file_named name @files_hash[name] end ## # Finds the module with +name+ in all discovered modules def find_module_named name @modules_hash[name] end ## # Returns the RDoc::TopLevel that is a text file and has the given # +file_name+ def find_text_page file_name @text_files_hash.each_value.find do |file| file.full_name == file_name end end ## # Finds unique classes/modules defined in +all_hash+, # and returns them as an array. Performs the alias # updates in +all_hash+: see ::complete. #-- # TODO aliases should be registered by Context#add_module_alias def find_unique all_hash unique = [] all_hash.each_pair do |full_name, cm| unique << cm if full_name == cm.full_name end unique end ## # Fixes the erroneous BasicObject < Object in 1.9. # # Because we assumed all classes without a stated superclass # inherit from Object, we have the above wrong inheritance. # # We fix BasicObject right away if we are running in a Ruby # version >= 1.9. def fix_basic_object_inheritance basic = classes_hash['BasicObject'] return unless basic basic.superclass = nil end ## # Friendly rendition of #path def friendly_path case type when :gem then parent = File.expand_path '..', @path "gem #{File.basename parent}" when :home then '~/.rdoc' when :site then 'ruby site' when :system then 'ruby core' else @path end end def inspect # :nodoc: "#<%s:0x%x %s %p>" % [self.class, object_id, @path, module_names.sort] end ## # Instance methods cache accessor. Maps a class to an Array of its # instance methods (not full name). def instance_methods @cache[:instance_methods] end ## # Loads all items from this store into memory. This recreates a # documentation tree for use by a generator def load_all load_cache module_names.each do |module_name| mod = find_class_or_module(module_name) || load_class(module_name) # load method documentation since the loaded class/module does not have # it loaded_methods = mod.method_list.map do |method| load_method module_name, method.full_name end mod.method_list.replace loaded_methods loaded_attributes = mod.attributes.map do |attribute| load_method module_name, attribute.full_name end mod.attributes.replace loaded_attributes end all_classes_and_modules.each do |mod| descendent_re = /^#{mod.full_name}::[^:]+$/ module_names.each do |name| next unless name =~ descendent_re descendent = find_class_or_module name case descendent when RDoc::NormalClass then mod.classes_hash[name] = descendent when RDoc::NormalModule then mod.modules_hash[name] = descendent end end end @cache[:pages].each do |page_name| page = load_page page_name @files_hash[page_name] = page @text_files_hash[page_name] = page if page.text? end end ## # Loads cache file for this store def load_cache #orig_enc = @encoding File.open cache_path, 'rb' do |io| @cache = Marshal.load io.read end load_enc = @cache[:encoding] # TODO this feature will be time-consuming to add: # a) Encodings may be incompatible but transcodeable # b) Need to warn in the appropriate spots, wherever they may be # c) Need to handle cross-cache differences in encodings # d) Need to warn when generating into a cache with different encodings # #if orig_enc and load_enc != orig_enc then # warn "Cached encoding #{load_enc} is incompatible with #{orig_enc}\n" \ # "from #{path}/cache.ri" unless # Encoding.compatible? orig_enc, load_enc #end @encoding = load_enc unless @encoding @cache[:pages] ||= [] @cache[:main] ||= nil @cache[:c_class_variables] ||= {} @cache[:c_singleton_class_variables] ||= {} @cache[:c_class_variables].each do |_, map| map.each do |variable, name| @c_enclosure_names[variable] = name end end @cache rescue Errno::ENOENT end ## # Loads ri data for +klass_name+ and hooks it up to this store. def load_class klass_name obj = load_class_data klass_name obj.store = self case obj when RDoc::NormalClass then @classes_hash[klass_name] = obj when RDoc::SingleClass then @classes_hash[klass_name] = obj when RDoc::NormalModule then @modules_hash[klass_name] = obj end end ## # Loads ri data for +klass_name+ def load_class_data klass_name file = class_file klass_name File.open file, 'rb' do |io| Marshal.load io.read end rescue Errno::ENOENT => e error = MissingFileError.new(self, file, klass_name) error.set_backtrace e.backtrace raise error end ## # Loads ri data for +method_name+ in +klass_name+ def load_method klass_name, method_name file = method_file klass_name, method_name File.open file, 'rb' do |io| obj = Marshal.load io.read obj.store = self obj.parent = find_class_or_module(klass_name) || load_class(klass_name) unless obj.parent obj end rescue Errno::ENOENT => e error = MissingFileError.new(self, file, klass_name + method_name) error.set_backtrace e.backtrace raise error end ## # Loads ri data for +page_name+ def load_page page_name file = page_file page_name File.open file, 'rb' do |io| obj = Marshal.load io.read obj.store = self obj end rescue Errno::ENOENT => e error = MissingFileError.new(self, file, page_name) error.set_backtrace e.backtrace raise error end ## # Gets the main page for this RDoc store. This page is used as the root of # the RDoc server. def main @cache[:main] end ## # Sets the main page for this RDoc store. def main= page @cache[:main] = page end ## # Converts the variable => ClassModule map +variables+ from a C parser into # a variable => class name map. def make_variable_map variables map = {} variables.each { |variable, class_module| map[variable] = class_module.full_name } map end ## # Path to the ri data for +method_name+ in +klass_name+ def method_file klass_name, method_name method_name = method_name.split('::').last method_name =~ /#(.*)/ method_type = $1 ? 'i' : 'c' method_name = $1 if $1 method_name = method_name.gsub(/\W/) { "%%%02x" % $&[0].ord } File.join class_path(klass_name), "#{method_name}-#{method_type}.ri" end ## # Modules cache accessor. An Array of all the module (and class) names in # the store. def module_names @cache[:modules] end ## # Hash of all modules known to RDoc def modules_hash @modules_hash end ## # Returns the RDoc::TopLevel that is a text file and has the given +name+ def page name @text_files_hash.each_value.find do |file| file.page_name == name end end ## # Path to the ri data for +page_name+ def page_file page_name file_name = File.basename(page_name).gsub('.', '_') File.join @path, File.dirname(page_name), "page-#{file_name}.ri" end ## # Removes from +all_hash+ the contexts that are nodoc or have no content. # # See RDoc::Context#remove_from_documentation? def remove_nodoc all_hash all_hash.keys.each do |name| context = all_hash[name] all_hash.delete(name) if context.remove_from_documentation? end end ## # Saves all entries in the store def save load_cache all_classes_and_modules.each do |klass| save_class klass klass.each_method do |method| save_method klass, method end klass.each_attribute do |attribute| save_method klass, attribute end end all_files.each do |file| save_page file end save_cache end ## # Writes the cache file for this store def save_cache clean_cache_collection @cache[:ancestors] clean_cache_collection @cache[:attributes] clean_cache_collection @cache[:class_methods] clean_cache_collection @cache[:instance_methods] @cache[:modules].uniq! @cache[:modules].sort! @cache[:pages].uniq! @cache[:pages].sort! @cache[:encoding] = @encoding # this gets set twice due to assert_cache @cache[:c_class_variables].merge! @c_class_variables @cache[:c_singleton_class_variables].merge! @c_singleton_class_variables return if @dry_run File.open cache_path, 'wb' do |io| Marshal.dump @cache, io end end ## # Writes the ri data for +klass+ (or module) def save_class klass full_name = klass.full_name FileUtils.mkdir_p class_path(full_name) unless @dry_run @cache[:modules] << full_name path = class_file full_name begin disk_klass = load_class full_name klass = disk_klass.merge klass rescue MissingFileError end # BasicObject has no ancestors ancestors = klass.direct_ancestors.compact.map do |ancestor| # HACK for classes we don't know about (class X < RuntimeError) String === ancestor ? ancestor : ancestor.full_name end @cache[:ancestors][full_name] ||= [] @cache[:ancestors][full_name].concat ancestors attribute_definitions = klass.attributes.map do |attribute| "#{attribute.definition} #{attribute.name}" end unless attribute_definitions.empty? then @cache[:attributes][full_name] ||= [] @cache[:attributes][full_name].concat attribute_definitions end to_delete = [] unless klass.method_list.empty? then @cache[:class_methods][full_name] ||= [] @cache[:instance_methods][full_name] ||= [] class_methods, instance_methods = klass.method_list.partition { |meth| meth.singleton } class_methods = class_methods. map { |method| method.name } instance_methods = instance_methods.map { |method| method.name } attribute_names = klass.attributes.map { |attr| attr.name } old = @cache[:class_methods][full_name] - class_methods to_delete.concat old.map { |method| method_file full_name, "#{full_name}::#{method}" } old = @cache[:instance_methods][full_name] - instance_methods - attribute_names to_delete.concat old.map { |method| method_file full_name, "#{full_name}##{method}" } @cache[:class_methods][full_name] = class_methods @cache[:instance_methods][full_name] = instance_methods end return if @dry_run FileUtils.rm_f to_delete File.open path, 'wb' do |io| Marshal.dump klass, io end end ## # Writes the ri data for +method+ on +klass+ def save_method klass, method full_name = klass.full_name FileUtils.mkdir_p class_path(full_name) unless @dry_run cache = if method.singleton then @cache[:class_methods] else @cache[:instance_methods] end cache[full_name] ||= [] cache[full_name] << method.name return if @dry_run File.open method_file(full_name, method.full_name), 'wb' do |io| Marshal.dump method, io end end ## # Writes the ri data for +page+ def save_page page return unless page.text? path = page_file page.full_name FileUtils.mkdir_p File.dirname(path) unless @dry_run cache[:pages] ||= [] cache[:pages] << page.full_name return if @dry_run File.open path, 'wb' do |io| Marshal.dump page, io end end ## # Source of the contents of this store. # # For a store from a gem the source is the gem name. For a store from the # home directory the source is "home". For system ri store (the standard # library documentation) the source is"ruby". For a store from the site # ri directory the store is "site". For other stores the source is the # #path. def source case type when :gem then File.basename File.expand_path '..', @path when :home then 'home' when :site then 'site' when :system then 'ruby' else @path end end ## # Gets the title for this RDoc store. This is used as the title in each # page on the RDoc server def title @cache[:title] end ## # Sets the title page for this RDoc store. def title= title @cache[:title] = title end ## # Returns the unique classes discovered by RDoc. # # ::complete must have been called prior to using this method. def unique_classes @unique_classes end ## # Returns the unique classes and modules discovered by RDoc. # ::complete must have been called prior to using this method. def unique_classes_and_modules @unique_classes + @unique_modules end ## # Returns the unique modules discovered by RDoc. # ::complete must have been called prior to using this method. def unique_modules @unique_modules end end PK ]]'gems/rdoc-6.2.1.1/lib/rdoc/rd/inline.rbnu[# frozen_string_literal: true ## # Inline keeps track of markup and labels to create proper links. class RDoc::RD::Inline ## # The text of the reference attr_reader :reference ## # The markup of this reference in RDoc format attr_reader :rdoc ## # Creates a new Inline for +rdoc+ and +reference+. # # +rdoc+ may be another Inline or a String. If +reference+ is not given it # will use the text from +rdoc+. def self.new rdoc, reference = rdoc if self === rdoc and reference.equal? rdoc then rdoc else super end end ## # Initializes the Inline with +rdoc+ and +inline+ def initialize rdoc, reference # :not-new: @reference = reference.equal?(rdoc) ? reference.dup : reference # unpack @reference = @reference.reference if self.class === @reference @rdoc = rdoc end def == other # :nodoc: self.class === other and @reference == other.reference and @rdoc == other.rdoc end ## # Appends +more+ to this inline. +more+ may be a String or another Inline. def append more case more when String then @reference += more @rdoc += more when RDoc::RD::Inline then @reference += more.reference @rdoc += more.rdoc else raise "unknown thingy #{more}" end self end def inspect # :nodoc: "(inline: #{self})" end alias to_s rdoc # :nodoc: end PK ]kXX-gems/rdoc-6.2.1.1/lib/rdoc/rd/block_parser.rbnu[# frozen_string_literal: true # # DO NOT MODIFY!!!! # This file is automatically generated by Racc 1.4.16 # from Racc grammar file "". # require 'racc/parser.rb' class RDoc::RD ## # RD format parser for headings, paragraphs, lists, verbatim sections that # exist as blocks. class BlockParser < Racc::Parser # :stopdoc: TMPFILE = ["rdtmp", $$, 0] MARK_TO_LEVEL = { '=' => 1, '==' => 2, '===' => 3, '====' => 4, '+' => 5, '++' => 6, } # :startdoc: ## # Footnotes for this document attr_reader :footnotes ## # Labels for items in this document attr_reader :labels ## # Path to find included files in attr_accessor :include_path ## # Creates a new RDoc::RD::BlockParser. Use #parse to parse an rd-format # document. def initialize @inline_parser = RDoc::RD::InlineParser.new self @include_path = [] # for testing @footnotes = [] @labels = {} end ## # Parses +src+ and returns an RDoc::Markup::Document. def parse src @src = src @src.push false @footnotes = [] @labels = {} # @i: index(line no.) of src @i = 0 # stack for current indentation @indent_stack = [] # how indented. @current_indent = @indent_stack.join("") # RDoc::RD::BlockParser for tmp src @subparser = nil # which part is in now @in_part = nil @part_content = [] @in_verbatim = false @yydebug = true document = do_parse unless @footnotes.empty? then blankline = document.parts.pop document.parts << RDoc::Markup::Rule.new(1) document.parts.concat @footnotes document.parts.push blankline end document end ## # Returns the next token from the document def next_token # :nodoc: # preprocessing # if it is not in RD part # => method while @in_part != "rd" line = @src[@i] @i += 1 # next line case line # src end when false return [false, false] # RD part begin when /^=begin\s*(?:\bRD\b.*)?\s*$/ if @in_part # if in non-RD part @part_content.push(line) else @in_part = "rd" return [:WHITELINE, "=begin\n"] # <= for textblockand end # non-RD part begin when /^=begin\s+(\w+)/ part = $1 if @in_part # if in non-RD part @part_content.push(line) else @in_part = part if @tree.filter[part] # if filter exists # p "BEGIN_PART: #{@in_part}" # DEBUG end # non-RD part end when /^=end/ if @in_part # if in non-RD part # p "END_PART: #{@in_part}" # DEBUG # make Part-in object part = RDoc::RD::Part.new(@part_content.join(""), @tree, "r") @part_content.clear # call filter, part_out is output(Part object) part_out = @tree.filter[@in_part].call(part) if @tree.filter[@in_part].mode == :rd # if output is RD formatted subtree = parse_subtree(part_out.to_a) else # if output is target formatted basename = TMPFILE.join('.') TMPFILE[-1] += 1 tmpfile = open(@tree.tmp_dir + "/" + basename + ".#{@in_part}", "w") tmpfile.print(part_out) tmpfile.close subtree = parse_subtree(["=begin\n", "<<< #{basename}\n", "=end\n"]) end @in_part = nil return [:SUBTREE, subtree] end else if @in_part # if in non-RD part @part_content.push(line) end end end @current_indent = @indent_stack.join("") line = @src[@i] case line when false if_current_indent_equal("") do [false, false] end when /^=end/ if_current_indent_equal("") do @in_part = nil [:WHITELINE, "=end"] # MUST CHANGE?? end when /^\s*$/ @i += 1 # next line return [:WHITELINE, ':WHITELINE'] when /^\#/ # comment line @i += 1 # next line self.next_token() when /^(={1,4})(?!=)\s*(?=\S)/, /^(\+{1,2})(?!\+)\s*(?=\S)/ rest = $' # ' rest.strip! mark = $1 if_current_indent_equal("") do return [:HEADLINE, [MARK_TO_LEVEL[mark], rest]] end when /^<<<\s*(\S+)/ file = $1 if_current_indent_equal("") do suffix = file[-3 .. -1] if suffix == ".rd" or suffix == ".rb" subtree = parse_subtree(get_included(file)) [:SUBTREE, subtree] else [:INCLUDE, file] end end when /^(\s*)\*(\s*)/ rest = $' # ' newIndent = $2 if_current_indent_equal($1) do if @in_verbatim [:STRINGLINE, line] else @indent_stack.push("\s" + newIndent) [:ITEMLISTLINE, rest] end end when /^(\s*)(\(\d+\))(\s*)/ rest = $' # ' mark = $2 newIndent = $3 if_current_indent_equal($1) do if @in_verbatim [:STRINGLINE, line] else @indent_stack.push("\s" * mark.size + newIndent) [:ENUMLISTLINE, rest] end end when /^(\s*):(\s*)/ rest = $' # ' newIndent = $2 if_current_indent_equal($1) do if @in_verbatim [:STRINGLINE, line] else @indent_stack.push("\s#{$2}") [:DESCLISTLINE, rest] end end when /^(\s*)---(?!-|\s*$)/ indent = $1 rest = $' /\s*/ === rest term = $' new_indent = $& if_current_indent_equal(indent) do if @in_verbatim [:STRINGLINE, line] else @indent_stack.push("\s\s\s" + new_indent) [:METHODLISTLINE, term] end end when /^(\s*)/ if_current_indent_equal($1) do [:STRINGLINE, line] end else raise "[BUG] parsing error may occurred." end end ## # Yields to the given block if +indent+ matches the current indent, otherwise # an indentation token is processed. def if_current_indent_equal(indent) indent = indent.sub(/\t/, "\s" * 8) if @current_indent == indent @i += 1 # next line yield elsif indent.index(@current_indent) == 0 @indent_stack.push(indent[@current_indent.size .. -1]) [:INDENT, ":INDENT"] else @indent_stack.pop [:DEDENT, ":DEDENT"] end end private :if_current_indent_equal ## # Cuts off excess whitespace in +src+ def cut_off(src) ret = [] whiteline_buf = [] line = src.shift /^\s*/ =~ line indent = Regexp.quote($&) ret.push($') while line = src.shift if /^(\s*)$/ =~ line whiteline_buf.push(line) elsif /^#{indent}/ =~ line unless whiteline_buf.empty? ret.concat(whiteline_buf) whiteline_buf.clear end ret.push($') else raise "[BUG]: probably Parser Error while cutting off.\n" end end ret end private :cut_off def set_term_to_element(parent, term) # parent.set_term_under_document_struct(term, @tree.document_struct) parent.set_term_without_document_struct(term) end private :set_term_to_element ## # Raises a ParseError when invalid formatting is found def on_error(et, ev, _values) prv, cur, nxt = format_line_num(@i, @i+1, @i+2) raise ParseError, <|#{@src[@i].chomp} #{nxt} |#{@src[@i+1].chomp} Msg end ## # Current line number def line_index @i end ## # Parses subtree +src+ def parse_subtree src @subparser ||= RDoc::RD::BlockParser.new @subparser.parse src end private :parse_subtree ## # Retrieves the content for +file+ from the include_path def get_included(file) included = [] @include_path.each do |dir| file_name = File.join dir, file if File.exist? file_name then included = IO.readlines file_name break end end included end private :get_included ## # Formats line numbers +line_numbers+ prettily def format_line_num(*line_numbers) width = line_numbers.collect{|i| i.to_s.length }.max line_numbers.collect{|i| sprintf("%#{width}d", i) } end private :format_line_num ## # Retrieves the content of +values+ as a single String def content values values.map { |value| value.content }.join end ## # Creates a paragraph for +value+ def paragraph value content = cut_off(value).join(' ').rstrip contents = @inline_parser.parse content RDoc::Markup::Paragraph.new(*contents) end ## # Adds footnote +content+ to the document def add_footnote content index = @footnotes.length / 2 + 1 footmark_link = "{^#{index}}[rdoc-label:footmark-#{index}:foottext-#{index}]" @footnotes << RDoc::Markup::Paragraph.new(footmark_link, ' ', *content) @footnotes << RDoc::Markup::BlankLine.new index end ## # Adds label +label+ to the document def add_label label @labels[label] = true label end # :stopdoc: ##### State transition tables begin ### racc_action_table = [ 34, 35, 30, 33, 40, 34, 35, 30, 33, 40, 65, 34, 35, 30, 33, 14, 73, 36, 38, 34, 15, 88, 34, 35, 30, 33, 14, 9, 10, 11, 12, 15, 34, 35, 30, 33, 14, 9, 10, 11, 12, 15, 34, 35, 30, 33, 35, 47, 30, 54, 33, 15, 34, 35, 30, 33, 54, 47, 14, 14, 59, 15, 34, 35, 30, 33, 14, 73, 67, 76, 77, 15, 34, 35, 30, 33, 14, 73, 54, 81, 38, 15, 34, 35, 30, 33, 14, 73, 38, 40, 83, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, 61, 63, nil, 15, 14, 62, 60, 61, 63, 79, 61, 63, 62, 87, nil, 62, 34, 35, 30, 33 ] racc_action_check = [ 41, 41, 41, 41, 41, 15, 15, 15, 15, 15, 41, 86, 86, 86, 86, 86, 86, 1, 13, 22, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 24, 24, 24, 24, 25, 24, 28, 30, 31, 24, 27, 27, 27, 27, 33, 27, 34, 35, 36, 27, 45, 45, 45, 45, 45, 45, 44, 49, 51, 45, 46, 46, 46, 46, 46, 46, 54, 56, 57, 46, 47, 47, 47, 47, 47, 47, 58, 62, 66, 47, 68, 68, 68, 68, 68, 68, nil, nil, nil, 68, 74, 74, 74, 74, 74, 74, nil, nil, nil, 74, 75, 75, 75, 75, 75, 75, nil, nil, nil, 75, 78, 78, 78, 78, 78, 78, nil, nil, nil, 78, 79, 79, 79, 79, 79, 79, nil, nil, nil, 79, 85, 85, 85, 85, 85, 85, 39, 39, nil, 85, 52, 39, 39, 82, 82, 52, 64, 64, 82, 82, nil, 64, 20, 20, 20, 20 ] racc_action_pointer = [ 19, 17, 29, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 11, nil, 2, nil, nil, nil, nil, 161, nil, 16, nil, 39, 42, nil, 49, 43, nil, 41, 44, nil, 48, 51, 52, 60, nil, nil, 141, nil, -3, nil, nil, 55, 59, 69, 79, nil, 56, nil, 57, 145, nil, 70, nil, 66, 73, 81, nil, nil, nil, 82, nil, 151, nil, 77, nil, 89, nil, nil, nil, nil, nil, 99, 109, nil, nil, 119, 129, nil, nil, 148, nil, nil, 139, 8, nil, nil ] racc_action_default = [ -2, -73, -1, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -16, -73, -23, -24, -25, -26, -27, -31, -32, -34, -72, -36, -38, -72, -40, -42, -59, -44, -46, -59, -63, -65, -73, -3, -15, -73, -22, -73, -30, -33, -73, -69, -70, -71, -37, -73, -41, -73, -51, -58, -61, -45, -73, -62, -64, 89, -17, -19, -73, -21, -18, -28, -73, -35, -66, -53, -54, -55, -56, -57, -67, -68, -39, -43, -49, -73, -60, -47, -73, -29, -52, -48, -73, -20, -50 ] racc_goto_table = [ 4, 39, 4, 68, 74, 75, 5, 6, 5, 6, 44, 42, 51, 49, 3, 56, 37, 57, 58, 1, 2, 66, 84, 41, 43, 48, 50, 64, 84, 84, 45, 46, 42, 45, 46, 55, 85, 86, 80, 84, 84, nil, nil, nil, nil, nil, nil, nil, 82, nil, nil, nil, 78 ] racc_goto_check = [ 4, 10, 4, 31, 31, 31, 5, 6, 5, 6, 21, 12, 27, 21, 3, 27, 3, 9, 9, 1, 2, 11, 32, 17, 19, 23, 26, 10, 32, 32, 5, 6, 12, 5, 6, 29, 31, 31, 33, 32, 32, nil, nil, nil, nil, nil, nil, nil, 10, nil, nil, nil, 4 ] racc_goto_pointer = [ nil, 19, 20, 14, 0, 6, 7, nil, nil, -17, -14, -20, -9, nil, nil, nil, nil, 8, nil, 2, nil, -14, nil, 0, nil, nil, -2, -18, nil, 4, nil, -42, -46, -16 ] racc_goto_default = [ nil, nil, nil, nil, 70, 71, 72, 7, 8, 13, nil, nil, 21, 16, 17, 18, 19, 20, 22, 23, 24, nil, 25, 26, 27, 28, 29, nil, 31, 32, 52, nil, 69, 53 ] racc_reduce_table = [ 0, 0, :racc_error, 1, 15, :_reduce_1, 0, 15, :_reduce_2, 2, 16, :_reduce_3, 1, 16, :_reduce_4, 1, 17, :_reduce_5, 1, 17, :_reduce_6, 1, 17, :_reduce_none, 1, 17, :_reduce_8, 1, 17, :_reduce_9, 1, 17, :_reduce_10, 1, 17, :_reduce_11, 1, 21, :_reduce_12, 1, 22, :_reduce_13, 1, 18, :_reduce_14, 2, 23, :_reduce_15, 1, 23, :_reduce_16, 3, 19, :_reduce_17, 1, 25, :_reduce_18, 2, 24, :_reduce_19, 4, 24, :_reduce_20, 2, 24, :_reduce_21, 1, 24, :_reduce_22, 1, 26, :_reduce_none, 1, 26, :_reduce_none, 1, 26, :_reduce_none, 1, 26, :_reduce_none, 1, 20, :_reduce_27, 3, 20, :_reduce_28, 4, 20, :_reduce_29, 2, 31, :_reduce_30, 1, 31, :_reduce_31, 1, 27, :_reduce_32, 2, 32, :_reduce_33, 1, 32, :_reduce_34, 3, 33, :_reduce_35, 1, 28, :_reduce_36, 2, 36, :_reduce_37, 1, 36, :_reduce_38, 3, 37, :_reduce_39, 1, 29, :_reduce_40, 2, 39, :_reduce_41, 1, 39, :_reduce_42, 3, 40, :_reduce_43, 1, 30, :_reduce_44, 2, 42, :_reduce_45, 1, 42, :_reduce_46, 3, 43, :_reduce_47, 3, 41, :_reduce_48, 2, 41, :_reduce_49, 4, 41, :_reduce_50, 1, 41, :_reduce_51, 2, 45, :_reduce_52, 1, 45, :_reduce_none, 1, 46, :_reduce_54, 1, 46, :_reduce_55, 1, 46, :_reduce_none, 1, 46, :_reduce_57, 1, 44, :_reduce_none, 0, 44, :_reduce_none, 2, 47, :_reduce_none, 1, 47, :_reduce_none, 2, 34, :_reduce_62, 1, 34, :_reduce_63, 2, 38, :_reduce_64, 1, 38, :_reduce_65, 2, 35, :_reduce_66, 2, 35, :_reduce_67, 2, 35, :_reduce_68, 1, 35, :_reduce_69, 1, 35, :_reduce_none, 1, 35, :_reduce_71, 0, 35, :_reduce_72 ] racc_reduce_n = 73 racc_shift_n = 89 racc_token_table = { false => 0, :error => 1, :DUMMY => 2, :ITEMLISTLINE => 3, :ENUMLISTLINE => 4, :DESCLISTLINE => 5, :METHODLISTLINE => 6, :STRINGLINE => 7, :WHITELINE => 8, :SUBTREE => 9, :HEADLINE => 10, :INCLUDE => 11, :INDENT => 12, :DEDENT => 13 } racc_nt_base = 14 racc_use_result_var = true Racc_arg = [ racc_action_table, racc_action_check, racc_action_default, racc_action_pointer, racc_goto_table, racc_goto_check, racc_goto_default, racc_goto_pointer, racc_nt_base, racc_reduce_table, racc_token_table, racc_shift_n, racc_reduce_n, racc_use_result_var ] Racc_token_to_s_table = [ "$end", "error", "DUMMY", "ITEMLISTLINE", "ENUMLISTLINE", "DESCLISTLINE", "METHODLISTLINE", "STRINGLINE", "WHITELINE", "SUBTREE", "HEADLINE", "INCLUDE", "INDENT", "DEDENT", "$start", "document", "blocks", "block", "textblock", "verbatim", "lists", "headline", "include", "textblockcontent", "verbatimcontent", "verbatim_after_lists", "list", "itemlist", "enumlist", "desclist", "methodlist", "lists2", "itemlistitems", "itemlistitem", "first_textblock_in_itemlist", "other_blocks_in_list", "enumlistitems", "enumlistitem", "first_textblock_in_enumlist", "desclistitems", "desclistitem", "description_part", "methodlistitems", "methodlistitem", "whitelines", "blocks_in_list", "block_in_list", "whitelines2" ] Racc_debug_parser = false ##### State transition tables end ##### # reduce 0 omitted def _reduce_1(val, _values, result) result = RDoc::Markup::Document.new(*val[0]) result end def _reduce_2(val, _values, result) raise ParseError, "file empty" result end def _reduce_3(val, _values, result) result = val[0].concat val[1] result end def _reduce_4(val, _values, result) result = val[0] result end def _reduce_5(val, _values, result) result = val result end def _reduce_6(val, _values, result) result = val result end # reduce 7 omitted def _reduce_8(val, _values, result) result = val result end def _reduce_9(val, _values, result) result = val result end def _reduce_10(val, _values, result) result = [RDoc::Markup::BlankLine.new] result end def _reduce_11(val, _values, result) result = val[0].parts result end def _reduce_12(val, _values, result) # val[0] is like [level, title] title = @inline_parser.parse(val[0][1]) result = RDoc::Markup::Heading.new(val[0][0], title) result end def _reduce_13(val, _values, result) result = RDoc::Markup::Include.new val[0], @include_path result end def _reduce_14(val, _values, result) # val[0] is Array of String result = paragraph val[0] result end def _reduce_15(val, _values, result) result << val[1].rstrip result end def _reduce_16(val, _values, result) result = [val[0].rstrip] result end def _reduce_17(val, _values, result) # val[1] is Array of String content = cut_off val[1] result = RDoc::Markup::Verbatim.new(*content) # imform to lexer. @in_verbatim = false result end def _reduce_18(val, _values, result) # val[0] is Array of String content = cut_off val[0] result = RDoc::Markup::Verbatim.new(*content) # imform to lexer. @in_verbatim = false result end def _reduce_19(val, _values, result) result << val[1] result end def _reduce_20(val, _values, result) result.concat val[2] result end def _reduce_21(val, _values, result) result << "\n" result end def _reduce_22(val, _values, result) result = val # inform to lexer. @in_verbatim = true result end # reduce 23 omitted # reduce 24 omitted # reduce 25 omitted # reduce 26 omitted def _reduce_27(val, _values, result) result = val[0] result end def _reduce_28(val, _values, result) result = val[1] result end def _reduce_29(val, _values, result) result = val[1].push(val[2]) result end def _reduce_30(val, _values, result) result = val[0] << val[1] result end def _reduce_31(val, _values, result) result = [val[0]] result end def _reduce_32(val, _values, result) result = RDoc::Markup::List.new :BULLET, *val[0] result end def _reduce_33(val, _values, result) result.push(val[1]) result end def _reduce_34(val, _values, result) result = val result end def _reduce_35(val, _values, result) result = RDoc::Markup::ListItem.new nil, val[0], *val[1] result end def _reduce_36(val, _values, result) result = RDoc::Markup::List.new :NUMBER, *val[0] result end def _reduce_37(val, _values, result) result.push(val[1]) result end def _reduce_38(val, _values, result) result = val result end def _reduce_39(val, _values, result) result = RDoc::Markup::ListItem.new nil, val[0], *val[1] result end def _reduce_40(val, _values, result) result = RDoc::Markup::List.new :NOTE, *val[0] result end def _reduce_41(val, _values, result) result.push(val[1]) result end def _reduce_42(val, _values, result) result = val result end def _reduce_43(val, _values, result) term = @inline_parser.parse val[0].strip result = RDoc::Markup::ListItem.new term, *val[1] result end def _reduce_44(val, _values, result) result = RDoc::Markup::List.new :LABEL, *val[0] result end def _reduce_45(val, _values, result) result.push(val[1]) result end def _reduce_46(val, _values, result) result = val result end def _reduce_47(val, _values, result) result = RDoc::Markup::ListItem.new "#{val[0].strip}", *val[1] result end def _reduce_48(val, _values, result) result = [val[1]].concat(val[2]) result end def _reduce_49(val, _values, result) result = [val[1]] result end def _reduce_50(val, _values, result) result = val[2] result end def _reduce_51(val, _values, result) result = [] result end def _reduce_52(val, _values, result) result.concat val[1] result end # reduce 53 omitted def _reduce_54(val, _values, result) result = val result end def _reduce_55(val, _values, result) result = val result end # reduce 56 omitted def _reduce_57(val, _values, result) result = [] result end # reduce 58 omitted # reduce 59 omitted # reduce 60 omitted # reduce 61 omitted def _reduce_62(val, _values, result) result = paragraph [val[0]].concat(val[1]) result end def _reduce_63(val, _values, result) result = paragraph [val[0]] result end def _reduce_64(val, _values, result) result = paragraph [val[0]].concat(val[1]) result end def _reduce_65(val, _values, result) result = paragraph [val[0]] result end def _reduce_66(val, _values, result) result = [val[0]].concat(val[1]) result end def _reduce_67(val, _values, result) result.concat val[1] result end def _reduce_68(val, _values, result) result = val[1] result end def _reduce_69(val, _values, result) result = val result end # reduce 70 omitted def _reduce_71(val, _values, result) result = [] result end def _reduce_72(val, _values, result) result = [] result end def _reduce_none(val, _values, result) val[0] end end # class BlockParser end PK ]M<}}.gems/rdoc-6.2.1.1/lib/rdoc/rd/inline_parser.rbnu[# frozen_string_literal: true # # DO NOT MODIFY!!!! # This file is automatically generated by Racc 1.4.16 # from Racc grammar file "". # require 'racc/parser.rb' require 'strscan' class RDoc::RD ## # RD format parser for inline markup such as emphasis, links, footnotes, etc. class InlineParser < Racc::Parser # :stopdoc: EM_OPEN = '((*' EM_OPEN_RE = /\A#{Regexp.quote(EM_OPEN)}/ EM_CLOSE = '*))' EM_CLOSE_RE = /\A#{Regexp.quote(EM_CLOSE)}/ CODE_OPEN = '(({' CODE_OPEN_RE = /\A#{Regexp.quote(CODE_OPEN)}/ CODE_CLOSE = '}))' CODE_CLOSE_RE = /\A#{Regexp.quote(CODE_CLOSE)}/ VAR_OPEN = '((|' VAR_OPEN_RE = /\A#{Regexp.quote(VAR_OPEN)}/ VAR_CLOSE = '|))' VAR_CLOSE_RE = /\A#{Regexp.quote(VAR_CLOSE)}/ KBD_OPEN = '((%' KBD_OPEN_RE = /\A#{Regexp.quote(KBD_OPEN)}/ KBD_CLOSE = '%))' KBD_CLOSE_RE = /\A#{Regexp.quote(KBD_CLOSE)}/ INDEX_OPEN = '((:' INDEX_OPEN_RE = /\A#{Regexp.quote(INDEX_OPEN)}/ INDEX_CLOSE = ':))' INDEX_CLOSE_RE = /\A#{Regexp.quote(INDEX_CLOSE)}/ REF_OPEN = '((<' REF_OPEN_RE = /\A#{Regexp.quote(REF_OPEN)}/ REF_CLOSE = '>))' REF_CLOSE_RE = /\A#{Regexp.quote(REF_CLOSE)}/ FOOTNOTE_OPEN = '((-' FOOTNOTE_OPEN_RE = /\A#{Regexp.quote(FOOTNOTE_OPEN)}/ FOOTNOTE_CLOSE = '-))' FOOTNOTE_CLOSE_RE = /\A#{Regexp.quote(FOOTNOTE_CLOSE)}/ VERB_OPEN = "(('" VERB_OPEN_RE = /\A#{Regexp.quote(VERB_OPEN)}/ VERB_CLOSE = "'))" VERB_CLOSE_RE = /\A#{Regexp.quote(VERB_CLOSE)}/ BAR = "|" BAR_RE = /\A#{Regexp.quote(BAR)}/ QUOTE = '"' QUOTE_RE = /\A#{Regexp.quote(QUOTE)}/ SLASH = "/" SLASH_RE = /\A#{Regexp.quote(SLASH)}/ BACK_SLASH = "\\" BACK_SLASH_RE = /\A#{Regexp.quote(BACK_SLASH)}/ URL = "URL:" URL_RE = /\A#{Regexp.quote(URL)}/ other_re_mode = Regexp::EXTENDED other_re_mode |= Regexp::MULTILINE OTHER_RE = Regexp.new( "\\A.+?(?=#{Regexp.quote(EM_OPEN)}|#{Regexp.quote(EM_CLOSE)}| #{Regexp.quote(CODE_OPEN)}|#{Regexp.quote(CODE_CLOSE)}| #{Regexp.quote(VAR_OPEN)}|#{Regexp.quote(VAR_CLOSE)}| #{Regexp.quote(KBD_OPEN)}|#{Regexp.quote(KBD_CLOSE)}| #{Regexp.quote(INDEX_OPEN)}|#{Regexp.quote(INDEX_CLOSE)}| #{Regexp.quote(REF_OPEN)}|#{Regexp.quote(REF_CLOSE)}| #{Regexp.quote(FOOTNOTE_OPEN)}|#{Regexp.quote(FOOTNOTE_CLOSE)}| #{Regexp.quote(VERB_OPEN)}|#{Regexp.quote(VERB_CLOSE)}| #{Regexp.quote(BAR)}| #{Regexp.quote(QUOTE)}| #{Regexp.quote(SLASH)}| #{Regexp.quote(BACK_SLASH)}| #{Regexp.quote(URL)})", other_re_mode) # :startdoc: ## # Creates a new parser for inline markup in the rd format. The +block_parser+ # is used to for footnotes and labels in the inline text. def initialize block_parser @block_parser = block_parser end ## # Parses the +inline+ text from RD format into RDoc format. def parse inline @inline = inline @src = StringScanner.new inline @pre = "".dup @yydebug = true do_parse.to_s end ## # Returns the next token from the inline text def next_token return [false, false] if @src.eos? # p @src.rest if @yydebug if ret = @src.scan(EM_OPEN_RE) @pre << ret [:EM_OPEN, ret] elsif ret = @src.scan(EM_CLOSE_RE) @pre << ret [:EM_CLOSE, ret] elsif ret = @src.scan(CODE_OPEN_RE) @pre << ret [:CODE_OPEN, ret] elsif ret = @src.scan(CODE_CLOSE_RE) @pre << ret [:CODE_CLOSE, ret] elsif ret = @src.scan(VAR_OPEN_RE) @pre << ret [:VAR_OPEN, ret] elsif ret = @src.scan(VAR_CLOSE_RE) @pre << ret [:VAR_CLOSE, ret] elsif ret = @src.scan(KBD_OPEN_RE) @pre << ret [:KBD_OPEN, ret] elsif ret = @src.scan(KBD_CLOSE_RE) @pre << ret [:KBD_CLOSE, ret] elsif ret = @src.scan(INDEX_OPEN_RE) @pre << ret [:INDEX_OPEN, ret] elsif ret = @src.scan(INDEX_CLOSE_RE) @pre << ret [:INDEX_CLOSE, ret] elsif ret = @src.scan(REF_OPEN_RE) @pre << ret [:REF_OPEN, ret] elsif ret = @src.scan(REF_CLOSE_RE) @pre << ret [:REF_CLOSE, ret] elsif ret = @src.scan(FOOTNOTE_OPEN_RE) @pre << ret [:FOOTNOTE_OPEN, ret] elsif ret = @src.scan(FOOTNOTE_CLOSE_RE) @pre << ret [:FOOTNOTE_CLOSE, ret] elsif ret = @src.scan(VERB_OPEN_RE) @pre << ret [:VERB_OPEN, ret] elsif ret = @src.scan(VERB_CLOSE_RE) @pre << ret [:VERB_CLOSE, ret] elsif ret = @src.scan(BAR_RE) @pre << ret [:BAR, ret] elsif ret = @src.scan(QUOTE_RE) @pre << ret [:QUOTE, ret] elsif ret = @src.scan(SLASH_RE) @pre << ret [:SLASH, ret] elsif ret = @src.scan(BACK_SLASH_RE) @pre << ret [:BACK_SLASH, ret] elsif ret = @src.scan(URL_RE) @pre << ret [:URL, ret] elsif ret = @src.scan(OTHER_RE) @pre << ret [:OTHER, ret] else ret = @src.rest @pre << ret @src.terminate [:OTHER, ret] end end ## # Raises a ParseError when invalid formatting is found def on_error(et, ev, values) lines_of_rest = @src.rest.lines.to_a.length prev_words = prev_words_on_error(ev) at = 4 + prev_words.length message = <<-MSG RD syntax error: line #{@block_parser.line_index - lines_of_rest}: ...#{prev_words} #{(ev||'')} #{next_words_on_error()} ... MSG message << " " * at + "^" * (ev ? ev.length : 0) + "\n" raise ParseError, message end ## # Returns words before the error def prev_words_on_error(ev) pre = @pre if ev and /#{Regexp.quote(ev)}$/ =~ pre pre = $` end last_line(pre) end ## # Returns the last line of +src+ def last_line(src) if n = src.rindex("\n") src[(n+1) .. -1] else src end end private :last_line ## # Returns words following an error def next_words_on_error if n = @src.rest.index("\n") @src.rest[0 .. (n-1)] else @src.rest end end ## # Creates a new RDoc::RD::Inline for the +rdoc+ markup and the raw +reference+ def inline rdoc, reference = rdoc RDoc::RD::Inline.new rdoc, reference end # :stopdoc: ##### State transition tables begin ### racc_action_table = [ 104, 103, 102, 100, 101, 99, 115, 116, 117, 29, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 84, 118, 119, 63, 64, 65, 61, 81, 62, 76, 78, 79, 85, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 80, 149, 63, 64, 65, 153, 81, 62, 76, 78, 79, 86, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 80, 152, 104, 103, 102, 100, 101, 99, 115, 116, 117, 87, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 88, 118, 119, 104, 103, 102, 100, 101, 99, 115, 116, 117, 89, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 96, 118, 119, 104, 103, 102, 100, 101, 99, 115, 116, 117, 124, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 137, 118, 119, 22, 23, 24, 25, 26, 21, 18, 19, 176, 177, 13, 148, 14, 154, 15, 137, 16, 161, 17, 164, 173, 20, 22, 23, 24, 25, 26, 21, 18, 19, 175, 177, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 42, nil, 20, 54, 38, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 63, 64, 65, 61, 81, 62, 76, 78, 79, nil, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 80, 122, nil, nil, 54, nil, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 135, 136, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 135, 136, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 135, 136, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 95, nil, 20, 54, 91, 53, 55, 56, 57, 145, nil, nil, 54, 133, 53, 55, 56, 57, 158, nil, nil, 54, nil, 53, 55, 56, 57, 165, 135, 136, 54, 133, 53, 55, 56, 57, 145, nil, nil, 54, 133, 53, 55, 56, 57, 172, 135, 136, 54, 133, 53, 55, 56, 57, 174, 135, 136, 54, 133, 53, 55, 56, 57, 178, 135, 136, 54, 133, 53, 55, 56, 57, 135, 136, 54, 133, 53, 55, 56, 57, 135, 136, 54, 133, 53, 55, 56, 57, 135, 136, 54, 133, 53, 55, 56, 57, 22, 23, 24, 25, 26, 21 ] racc_action_check = [ 38, 38, 38, 38, 38, 38, 38, 38, 38, 1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 29, 38, 38, 59, 59, 59, 59, 59, 59, 59, 59, 59, 31, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 61, 61, 61, 61, 61, 61, 61, 32, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 91, 91, 91, 91, 91, 91, 91, 91, 91, 33, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 34, 91, 91, 97, 97, 97, 97, 97, 97, 97, 97, 97, 35, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 37, 97, 97, 155, 155, 155, 155, 155, 155, 155, 155, 155, 41, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 43, 155, 155, 0, 0, 0, 0, 0, 0, 0, 0, 165, 165, 0, 58, 0, 90, 0, 94, 0, 100, 0, 125, 162, 0, 2, 2, 2, 2, 2, 2, 2, 2, 164, 172, 2, nil, 2, nil, 2, nil, 2, nil, 2, nil, nil, 2, 13, 13, 13, 13, 13, 13, 13, 13, nil, nil, 13, nil, 13, nil, 13, nil, 13, nil, 13, nil, nil, 13, 14, 14, 14, 14, 14, 14, 14, 14, nil, nil, 14, nil, 14, nil, 14, nil, 14, nil, 14, nil, nil, 14, 15, 15, 15, 15, 15, 15, 15, 15, nil, nil, 15, nil, 15, nil, 15, nil, 15, nil, 15, nil, nil, 15, 16, 16, 16, 16, 16, 16, 16, 16, nil, nil, 16, nil, 16, nil, 16, nil, 16, nil, 16, nil, nil, 16, 17, 17, 17, 17, 17, 17, 17, 17, nil, nil, 17, nil, 17, nil, 17, nil, 17, nil, 17, 18, nil, 17, 18, 18, 18, 18, 18, 18, nil, 18, nil, 18, nil, 18, nil, 18, nil, 18, nil, nil, 18, 19, 19, 19, 19, 19, 19, 19, 19, nil, nil, 19, nil, 19, nil, 19, nil, 19, nil, 19, nil, nil, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, nil, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 39, nil, nil, 39, nil, 39, 39, 39, 39, nil, 39, nil, 39, nil, 39, nil, 39, nil, 39, 44, nil, 39, 44, 44, 44, 44, 44, 44, nil, 44, nil, 44, nil, 44, nil, 44, nil, 44, 45, nil, 44, 45, 45, 45, 45, 45, 45, nil, 45, nil, 45, nil, 45, nil, 45, nil, 45, 138, nil, 45, 138, 138, 138, 138, 138, 138, nil, 138, nil, 138, nil, 138, nil, 138, nil, 138, 146, nil, 138, 146, 146, 146, 146, 146, 146, nil, 146, nil, 146, nil, 146, nil, 146, nil, 146, nil, nil, 146, 42, 42, 42, 42, 42, 42, 42, 42, nil, 42, nil, 42, nil, 42, nil, 42, nil, 42, nil, nil, 42, 122, 122, 122, 122, 122, 122, 122, 122, nil, 122, nil, 122, nil, 122, nil, 122, nil, 122, nil, nil, 122, 127, 127, 127, 127, 127, 127, 127, 127, nil, 127, nil, 127, nil, 127, nil, 127, nil, 127, 36, nil, 127, 36, 36, 36, 36, 36, 36, 52, nil, nil, 52, 52, 52, 52, 52, 52, 92, nil, nil, 92, nil, 92, 92, 92, 92, 126, 126, 126, 126, 126, 126, 126, 126, 126, 142, nil, nil, 142, 142, 142, 142, 142, 142, 159, 159, 159, 159, 159, 159, 159, 159, 159, 163, 163, 163, 163, 163, 163, 163, 163, 163, 171, 171, 171, 171, 171, 171, 171, 171, 171, 95, 95, 95, 95, 95, 95, 95, 95, 158, 158, 158, 158, 158, 158, 158, 158, 168, 168, 168, 168, 168, 168, 168, 168, 27, 27, 27, 27, 27, 27 ] racc_action_pointer = [ 135, 9, 157, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 179, 201, 223, 245, 267, 286, 308, 330, nil, nil, nil, nil, nil, nil, 606, nil, 20, nil, 18, 39, 60, 69, 79, 510, 89, -3, 352, nil, 120, 449, 130, 371, 390, nil, nil, nil, nil, nil, nil, 519, nil, nil, nil, nil, nil, 138, 20, nil, 43, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 128, 66, 528, nil, 148, 581, nil, 89, nil, nil, 149, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 470, nil, nil, 154, 537, 491, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 409, nil, nil, nil, 546, nil, nil, nil, 428, nil, nil, nil, nil, nil, nil, nil, nil, 112, nil, nil, 589, 555, nil, nil, 155, 564, 164, 142, nil, nil, 597, nil, nil, 573, 164, nil, nil, nil, nil, nil, nil ] racc_action_default = [ -138, -138, -1, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -138, -138, -138, -138, -138, -138, -138, -138, -103, -104, -105, -106, -107, -108, -111, -110, -138, -2, -138, -138, -138, -138, -138, -138, -138, -138, -27, -26, -35, -138, -58, -41, -40, -47, -48, -49, -50, -51, -52, -63, -66, -67, -68, -69, -70, -138, -138, -112, -138, -116, -117, -118, -119, -120, -121, -122, -123, -124, -125, -126, -127, -128, -129, -130, -131, -132, -133, -134, -135, -137, -109, 179, -13, -14, -15, -16, -17, -138, -138, -23, -22, -33, -138, -19, -24, -79, -80, -138, -82, -83, -84, -85, -86, -87, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, -100, -25, -35, -138, -58, -28, -138, -59, -42, -46, -55, -56, -65, -71, -72, -75, -76, -77, -31, -38, -44, -53, -54, -57, -61, -73, -74, -39, -62, -101, -102, -136, -113, -114, -115, -18, -20, -21, -33, -138, -138, -78, -81, -138, -59, -36, -37, -64, -45, -59, -43, -60, -138, -34, -36, -37, -29, -30, -32, -34 ] racc_goto_table = [ 126, 44, 125, 43, 144, 144, 160, 93, 97, 52, 166, 82, 144, 40, 41, 39, 138, 146, 169, 30, 36, 94, 44, 1, 123, 129, 169, 52, 90, 37, 52, 167, 147, 92, 120, 121, 31, 32, 33, 34, 35, 170, 58, 166, 59, 83, 170, 166, 151, nil, 150, nil, 166, 159, 4, 166, 4, nil, nil, nil, nil, 155, nil, 156, 160, nil, nil, 4, 4, 4, 4, 4, nil, 4, 5, nil, 5, 157, nil, nil, 163, nil, 162, 52, nil, 168, nil, 5, 5, 5, 5, 5, nil, 5, nil, nil, nil, nil, 144, nil, nil, nil, 144, nil, nil, 129, 144, 144, nil, 6, 129, 6, nil, nil, nil, nil, 171, 7, nil, 7, nil, nil, 6, 6, 6, 6, 6, 8, 6, 8, 7, 7, 7, 7, 7, 11, 7, 11, nil, nil, 8, 8, 8, 8, 8, nil, 8, nil, 11, 11, 11, 11, 11, nil, 11 ] racc_goto_check = [ 22, 24, 21, 23, 36, 36, 37, 18, 16, 34, 35, 41, 36, 19, 20, 17, 25, 25, 28, 3, 13, 23, 24, 1, 23, 24, 28, 34, 14, 15, 34, 29, 32, 17, 19, 20, 1, 1, 1, 1, 1, 33, 1, 35, 38, 39, 33, 35, 42, nil, 41, nil, 35, 22, 4, 35, 4, nil, nil, nil, nil, 16, nil, 18, 37, nil, nil, 4, 4, 4, 4, 4, nil, 4, 5, nil, 5, 23, nil, nil, 22, nil, 21, 34, nil, 22, nil, 5, 5, 5, 5, 5, nil, 5, nil, nil, nil, nil, 36, nil, nil, nil, 36, nil, nil, 24, 36, 36, nil, 6, 24, 6, nil, nil, nil, nil, 22, 7, nil, 7, nil, nil, 6, 6, 6, 6, 6, 8, 6, 8, 7, 7, 7, 7, 7, 11, 7, 11, nil, nil, 8, 8, 8, 8, 8, nil, 8, nil, 11, 11, 11, 11, 11, nil, 11 ] racc_goto_pointer = [ nil, 23, nil, 17, 54, 74, 109, 117, 127, nil, nil, 135, nil, 2, -8, 11, -30, -3, -29, -5, -4, -40, -42, -15, -17, -28, nil, nil, -120, -96, nil, nil, -20, -101, -9, -116, -40, -91, 24, 18, nil, -9, -13 ] racc_goto_default = [ nil, nil, 2, 3, 46, 47, 48, 49, 50, 9, 10, 51, 12, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 140, nil, 45, 127, 139, 128, 141, 130, 142, 143, 132, 131, 134, 98, nil, 28, 27, nil, 60 ] racc_reduce_table = [ 0, 0, :racc_error, 1, 27, :_reduce_none, 2, 28, :_reduce_2, 1, 28, :_reduce_3, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 3, 30, :_reduce_13, 3, 31, :_reduce_14, 3, 32, :_reduce_15, 3, 33, :_reduce_16, 3, 34, :_reduce_17, 4, 35, :_reduce_18, 3, 35, :_reduce_19, 2, 40, :_reduce_20, 2, 40, :_reduce_21, 1, 40, :_reduce_22, 1, 40, :_reduce_23, 2, 41, :_reduce_24, 2, 41, :_reduce_25, 1, 41, :_reduce_26, 1, 41, :_reduce_27, 2, 39, :_reduce_none, 4, 39, :_reduce_29, 4, 39, :_reduce_30, 2, 43, :_reduce_31, 4, 43, :_reduce_32, 1, 44, :_reduce_33, 3, 44, :_reduce_34, 1, 45, :_reduce_none, 3, 45, :_reduce_36, 3, 45, :_reduce_37, 2, 46, :_reduce_38, 2, 46, :_reduce_39, 1, 46, :_reduce_40, 1, 46, :_reduce_41, 1, 47, :_reduce_none, 2, 51, :_reduce_43, 1, 51, :_reduce_44, 2, 53, :_reduce_45, 1, 53, :_reduce_46, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 54, :_reduce_none, 1, 54, :_reduce_none, 1, 55, :_reduce_none, 1, 55, :_reduce_none, 1, 56, :_reduce_57, 1, 52, :_reduce_58, 1, 57, :_reduce_59, 2, 58, :_reduce_60, 1, 58, :_reduce_none, 2, 49, :_reduce_62, 1, 49, :_reduce_none, 2, 48, :_reduce_64, 1, 48, :_reduce_none, 1, 60, :_reduce_none, 1, 60, :_reduce_none, 1, 60, :_reduce_none, 1, 60, :_reduce_none, 1, 60, :_reduce_none, 1, 62, :_reduce_none, 1, 62, :_reduce_none, 1, 59, :_reduce_none, 1, 59, :_reduce_none, 1, 61, :_reduce_none, 1, 61, :_reduce_none, 1, 61, :_reduce_none, 2, 42, :_reduce_78, 1, 42, :_reduce_none, 1, 63, :_reduce_none, 2, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 3, 36, :_reduce_101, 3, 37, :_reduce_102, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 2, 66, :_reduce_109, 1, 66, :_reduce_none, 1, 38, :_reduce_111, 1, 67, :_reduce_none, 2, 67, :_reduce_113, 2, 67, :_reduce_114, 2, 67, :_reduce_115, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 2, 64, :_reduce_136, 1, 64, :_reduce_none ] racc_reduce_n = 138 racc_shift_n = 179 racc_token_table = { false => 0, :error => 1, :EX_LOW => 2, :QUOTE => 3, :BAR => 4, :SLASH => 5, :BACK_SLASH => 6, :URL => 7, :OTHER => 8, :REF_OPEN => 9, :FOOTNOTE_OPEN => 10, :FOOTNOTE_CLOSE => 11, :EX_HIGH => 12, :EM_OPEN => 13, :EM_CLOSE => 14, :CODE_OPEN => 15, :CODE_CLOSE => 16, :VAR_OPEN => 17, :VAR_CLOSE => 18, :KBD_OPEN => 19, :KBD_CLOSE => 20, :INDEX_OPEN => 21, :INDEX_CLOSE => 22, :REF_CLOSE => 23, :VERB_OPEN => 24, :VERB_CLOSE => 25 } racc_nt_base = 26 racc_use_result_var = true Racc_arg = [ racc_action_table, racc_action_check, racc_action_default, racc_action_pointer, racc_goto_table, racc_goto_check, racc_goto_default, racc_goto_pointer, racc_nt_base, racc_reduce_table, racc_token_table, racc_shift_n, racc_reduce_n, racc_use_result_var ] Racc_token_to_s_table = [ "$end", "error", "EX_LOW", "QUOTE", "BAR", "SLASH", "BACK_SLASH", "URL", "OTHER", "REF_OPEN", "FOOTNOTE_OPEN", "FOOTNOTE_CLOSE", "EX_HIGH", "EM_OPEN", "EM_CLOSE", "CODE_OPEN", "CODE_CLOSE", "VAR_OPEN", "VAR_CLOSE", "KBD_OPEN", "KBD_CLOSE", "INDEX_OPEN", "INDEX_CLOSE", "REF_CLOSE", "VERB_OPEN", "VERB_CLOSE", "$start", "content", "elements", "element", "emphasis", "code", "var", "keyboard", "index", "reference", "footnote", "verb", "normal_str_ele", "substitute", "ref_label", "ref_label2", "ref_url_strings", "filename", "element_label", "element_label2", "ref_subst_content", "ref_subst_content_q", "ref_subst_strings_q", "ref_subst_strings_first", "ref_subst_ele2", "ref_subst_eles", "ref_subst_str_ele_first", "ref_subst_eles_q", "ref_subst_ele", "ref_subst_ele_q", "ref_subst_str_ele", "ref_subst_str_ele_q", "ref_subst_strings", "ref_subst_string3", "ref_subst_string", "ref_subst_string_q", "ref_subst_string2", "ref_url_string", "verb_strings", "normal_string", "normal_strings", "verb_string", "verb_normal_string" ] Racc_debug_parser = false ##### State transition tables end ##### # reduce 0 omitted # reduce 1 omitted def _reduce_2(val, _values, result) result.append val[1] result end def _reduce_3(val, _values, result) result = val[0] result end # reduce 4 omitted # reduce 5 omitted # reduce 6 omitted # reduce 7 omitted # reduce 8 omitted # reduce 9 omitted # reduce 10 omitted # reduce 11 omitted # reduce 12 omitted def _reduce_13(val, _values, result) content = val[1] result = inline "#{content}", content result end def _reduce_14(val, _values, result) content = val[1] result = inline "#{content}", content result end def _reduce_15(val, _values, result) content = val[1] result = inline "+#{content}+", content result end def _reduce_16(val, _values, result) content = val[1] result = inline "#{content}", content result end def _reduce_17(val, _values, result) label = val[1] @block_parser.add_label label.reference result = "#{label}" result end def _reduce_18(val, _values, result) result = "{#{val[1]}}[#{val[2].join}]" result end def _reduce_19(val, _values, result) scheme, inline = val[1] result = "{#{inline}}[#{scheme}#{inline.reference}]" result end def _reduce_20(val, _values, result) result = [nil, inline(val[1])] result end def _reduce_21(val, _values, result) result = [ 'rdoc-label:', inline("#{val[0].reference}/#{val[1].reference}") ] result end def _reduce_22(val, _values, result) result = ['rdoc-label:', val[0].reference] result end def _reduce_23(val, _values, result) result = ['rdoc-label:', "#{val[0].reference}/"] result end def _reduce_24(val, _values, result) result = [nil, inline(val[1])] result end def _reduce_25(val, _values, result) result = [ 'rdoc-label:', inline("#{val[0].reference}/#{val[1].reference}") ] result end def _reduce_26(val, _values, result) result = ['rdoc-label:', val[0]] result end def _reduce_27(val, _values, result) ref = val[0].reference result = ['rdoc-label:', inline(ref, "#{ref}/")] result end # reduce 28 omitted def _reduce_29(val, _values, result) result = val[1] result end def _reduce_30(val, _values, result) result = val[1] result end def _reduce_31(val, _values, result) result = inline val[0] result end def _reduce_32(val, _values, result) result = inline "\"#{val[1]}\"" result end def _reduce_33(val, _values, result) result = inline val[0] result end def _reduce_34(val, _values, result) result = inline "\"#{val[1]}\"" result end # reduce 35 omitted def _reduce_36(val, _values, result) result = val[1] result end def _reduce_37(val, _values, result) result = inline val[1] result end def _reduce_38(val, _values, result) result = val[0].append val[1] result end def _reduce_39(val, _values, result) result = val[0].append val[1] result end def _reduce_40(val, _values, result) result = val[0] result end def _reduce_41(val, _values, result) result = inline val[0] result end # reduce 42 omitted def _reduce_43(val, _values, result) result = val[0].append val[1] result end def _reduce_44(val, _values, result) result = inline val[0] result end def _reduce_45(val, _values, result) result = val[0].append val[1] result end def _reduce_46(val, _values, result) result = val[0] result end # reduce 47 omitted # reduce 48 omitted # reduce 49 omitted # reduce 50 omitted # reduce 51 omitted # reduce 52 omitted # reduce 53 omitted # reduce 54 omitted # reduce 55 omitted # reduce 56 omitted def _reduce_57(val, _values, result) result = val[0] result end def _reduce_58(val, _values, result) result = inline val[0] result end def _reduce_59(val, _values, result) result = inline val[0] result end def _reduce_60(val, _values, result) result << val[1] result end # reduce 61 omitted def _reduce_62(val, _values, result) result << val[1] result end # reduce 63 omitted def _reduce_64(val, _values, result) result << val[1] result end # reduce 65 omitted # reduce 66 omitted # reduce 67 omitted # reduce 68 omitted # reduce 69 omitted # reduce 70 omitted # reduce 71 omitted # reduce 72 omitted # reduce 73 omitted # reduce 74 omitted # reduce 75 omitted # reduce 76 omitted # reduce 77 omitted def _reduce_78(val, _values, result) result << val[1] result end # reduce 79 omitted # reduce 80 omitted # reduce 81 omitted # reduce 82 omitted # reduce 83 omitted # reduce 84 omitted # reduce 85 omitted # reduce 86 omitted # reduce 87 omitted # reduce 88 omitted # reduce 89 omitted # reduce 90 omitted # reduce 91 omitted # reduce 92 omitted # reduce 93 omitted # reduce 94 omitted # reduce 95 omitted # reduce 96 omitted # reduce 97 omitted # reduce 98 omitted # reduce 99 omitted # reduce 100 omitted def _reduce_101(val, _values, result) index = @block_parser.add_footnote val[1].rdoc result = "{*#{index}}[rdoc-label:foottext-#{index}:footmark-#{index}]" result end def _reduce_102(val, _values, result) result = inline "#{val[1]}", val[1] result end # reduce 103 omitted # reduce 104 omitted # reduce 105 omitted # reduce 106 omitted # reduce 107 omitted # reduce 108 omitted def _reduce_109(val, _values, result) result << val[1] result end # reduce 110 omitted def _reduce_111(val, _values, result) result = inline val[0] result end # reduce 112 omitted def _reduce_113(val, _values, result) result = val[1] result end def _reduce_114(val, _values, result) result = val[1] result end def _reduce_115(val, _values, result) result = val[1] result end # reduce 116 omitted # reduce 117 omitted # reduce 118 omitted # reduce 119 omitted # reduce 120 omitted # reduce 121 omitted # reduce 122 omitted # reduce 123 omitted # reduce 124 omitted # reduce 125 omitted # reduce 126 omitted # reduce 127 omitted # reduce 128 omitted # reduce 129 omitted # reduce 130 omitted # reduce 131 omitted # reduce 132 omitted # reduce 133 omitted # reduce 134 omitted # reduce 135 omitted def _reduce_136(val, _values, result) result << val[1] result end # reduce 137 omitted def _reduce_none(val, _values, result) val[0] end end # class InlineParser end PK ]x"gems/rdoc-6.2.1.1/lib/rdoc/task.rbnu[# frozen_string_literal: true #-- # Copyright (c) 2003, 2004 Jim Weirich, 2009 Eric Hodel # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ begin gem 'rdoc' rescue Gem::LoadError end unless defined?(RDoc) begin gem 'rake' rescue Gem::LoadError end unless defined?(Rake) require 'rdoc' require 'rake' require 'rake/tasklib' ## # RDoc::Task creates the following rake tasks to generate and clean up RDoc # output: # # [rdoc] # Main task for this RDoc task. # # [clobber_rdoc] # Delete all the rdoc files. This target is automatically added to the main # clobber target. # # [rerdoc] # Rebuild the rdoc files from scratch, even if they are not out of date. # # Simple Example: # # require 'rdoc/task' # # RDoc::Task.new do |rdoc| # rdoc.main = "README.rdoc" # rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb") # end # # The +rdoc+ object passed to the block is an RDoc::Task object. See the # attributes list for the RDoc::Task class for available customization options. # # == Specifying different task names # # You may wish to give the task a different name, such as if you are # generating two sets of documentation. For instance, if you want to have a # development set of documentation including private methods: # # require 'rdoc/task' # # RDoc::Task.new :rdoc_dev do |rdoc| # rdoc.main = "README.doc" # rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb") # rdoc.options << "--all" # end # # The tasks would then be named :rdoc_dev, # :clobber_rdoc_dev, and :rerdoc_dev. # # If you wish to have completely different task names, then pass a Hash as # first argument. With the :rdoc, :clobber_rdoc and # :rerdoc options, you can customize the task names to your liking. # # For example: # # require 'rdoc/task' # # RDoc::Task.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean", # :rerdoc => "rdoc:force") # # This will create the tasks :rdoc, :rdoc:clean and # :rdoc:force. class RDoc::Task < Rake::TaskLib ## # Name of the main, top level task. (default is :rdoc) attr_accessor :name ## # Comment markup format. rdoc, rd and tomdoc are supported. (default is # 'rdoc') attr_accessor :markup ## # Name of directory to receive the html output files. (default is "html") attr_accessor :rdoc_dir ## # Title of RDoc documentation. (defaults to rdoc's default) attr_accessor :title ## # Name of file to be used as the main, top level file of the RDoc. (default # is none) attr_accessor :main ## # Name of template to be used by rdoc. (defaults to rdoc's default) attr_accessor :template ## # Name of format generator (--format) used by rdoc. (defaults to # rdoc's default) attr_accessor :generator ## # List of files to be included in the rdoc generation. (default is []) attr_accessor :rdoc_files ## # Additional list of options to be passed rdoc. (default is []) attr_accessor :options ## # Whether to run the rdoc process as an external shell (default is false) attr_accessor :external ## # Create an RDoc task with the given name. See the RDoc::Task class overview # for documentation. def initialize name = :rdoc # :yield: self defaults check_names name @name = name yield self if block_given? define end ## # Ensures that +names+ only includes names for the :rdoc, :clobber_rdoc and # :rerdoc. If other names are given an ArgumentError is raised. def check_names names return unless Hash === names invalid_options = names.keys.map { |k| k.to_sym } - [:rdoc, :clobber_rdoc, :rerdoc] unless invalid_options.empty? then raise ArgumentError, "invalid options: #{invalid_options.join ', '}" end end ## # Task description for the clobber rdoc task or its renamed equivalent def clobber_task_description "Remove RDoc HTML files" end ## # Sets default task values def defaults @name = :rdoc @rdoc_files = Rake::FileList.new @rdoc_dir = 'html' @main = nil @title = nil @template = nil @generator = nil @options = [] end ## # All source is inline now. This method is deprecated def inline_source # :nodoc: warn "RDoc::Task#inline_source is deprecated" true end ## # All source is inline now. This method is deprecated def inline_source=(value) # :nodoc: warn "RDoc::Task#inline_source is deprecated" end ## # Create the tasks defined by this task lib. def define desc rdoc_task_description task rdoc_task_name desc rerdoc_task_description task rerdoc_task_name => [clobber_task_name, rdoc_task_name] desc clobber_task_description task clobber_task_name do rm_r @rdoc_dir rescue nil end task :clobber => [clobber_task_name] directory @rdoc_dir rdoc_target_deps = [ @rdoc_files, Rake.application.rakefile ].flatten.compact task rdoc_task_name => [rdoc_target] file rdoc_target => rdoc_target_deps do @before_running_rdoc.call if @before_running_rdoc args = option_list + @rdoc_files $stderr.puts "rdoc #{args.join ' '}" if Rake.application.options.trace RDoc::RDoc.new.document args end self end ## # List of options that will be supplied to RDoc def option_list result = @options.dup result << "-o" << @rdoc_dir result << "--main" << main if main result << "--markup" << markup if markup result << "--title" << title if title result << "-T" << template if template result << '-f' << generator if generator result end ## # The block passed to this method will be called just before running the # RDoc generator. It is allowed to modify RDoc::Task attributes inside the # block. def before_running_rdoc(&block) @before_running_rdoc = block end ## # Task description for the rdoc task or its renamed equivalent def rdoc_task_description 'Build RDoc HTML files' end ## # Task description for the rerdoc task or its renamed description def rerdoc_task_description "Rebuild RDoc HTML files" end private def rdoc_target "#{rdoc_dir}/created.rid" end def rdoc_task_name case name when Hash then (name[:rdoc] || "rdoc").to_s else name.to_s end end def clobber_task_name case name when Hash then (name[:clobber_rdoc] || "clobber_rdoc").to_s else "clobber_#{name}" end end def rerdoc_task_name case name when Hash then (name[:rerdoc] || "rerdoc").to_s else "re#{name}" end end end # :stopdoc: module Rake ## # For backwards compatibility RDocTask = RDoc::Task end # :startdoc: PK ]刊--'gems/rdoc-6.2.1.1/lib/rdoc/generator.rbnu[# frozen_string_literal: true ## # RDoc uses generators to turn parsed source code in the form of an # RDoc::CodeObject tree into some form of output. RDoc comes with the HTML # generator RDoc::Generator::Darkfish and an ri data generator # RDoc::Generator::RI. # # == Registering a Generator # # Generators are registered by calling RDoc::RDoc.add_generator with the class # of the generator: # # class My::Awesome::Generator # RDoc::RDoc.add_generator self # end # # == Adding Options to +rdoc+ # # Before option processing in +rdoc+, RDoc::Options will call ::setup_options # on the generator class with an RDoc::Options instance. The generator can # use RDoc::Options#option_parser to add command-line options to the +rdoc+ # tool. See RDoc::Options@Custom+Options for an example and see OptionParser # for details on how to add options. # # You can extend the RDoc::Options instance with additional accessors for your # generator. # # == Generator Instantiation # # After parsing, RDoc::RDoc will instantiate a generator by calling # #initialize with an RDoc::Store instance and an RDoc::Options instance. # # The RDoc::Store instance holds documentation for parsed source code. In # RDoc 3 and earlier the RDoc::TopLevel class held this data. When upgrading # a generator from RDoc 3 and earlier you should only need to replace # RDoc::TopLevel with the store instance. # # RDoc will then call #generate on the generator instance. You can use the # various methods on RDoc::Store and in the RDoc::CodeObject tree to create # your desired output format. module RDoc::Generator autoload :Markup, 'rdoc/generator/markup' autoload :Darkfish, 'rdoc/generator/darkfish' autoload :JsonIndex, 'rdoc/generator/json_index' autoload :RI, 'rdoc/generator/ri' autoload :POT, 'rdoc/generator/pot' end PK ]Ȅ(gems/rdoc-6.2.1.1/lib/rdoc/anon_class.rbnu[# frozen_string_literal: true ## # An anonymous class like: # # c = Class.new do end # # AnonClass is currently not used. class RDoc::AnonClass < RDoc::ClassModule end PK ]  #gems/rdoc-6.2.1.1/lib/rdoc/mixin.rbnu[# frozen_string_literal: true ## # A Mixin adds features from a module into another context. RDoc::Include and # RDoc::Extend are both mixins. class RDoc::Mixin < RDoc::CodeObject ## # Name of included module attr_accessor :name ## # Creates a new Mixin for +name+ with +comment+ def initialize(name, comment) super() @name = name self.comment = comment @module = nil # cache for module if found end ## # Mixins are sorted by name def <=> other return unless self.class === other name <=> other.name end def == other # :nodoc: self.class === other and @name == other.name end alias eql? == # :nodoc: ## # Full name based on #module def full_name m = self.module RDoc::ClassModule === m ? m.full_name : @name end def hash # :nodoc: [@name, self.module].hash end def inspect # :nodoc: "#<%s:0x%x %s.%s %s>" % [ self.class, object_id, parent_name, self.class.name.downcase, @name, ] end ## # Attempts to locate the included module object. Returns the name if not # known. # # The scoping rules of Ruby to resolve the name of an included module are: # - first look into the children of the current context; # - if not found, look into the children of included modules, # in reverse inclusion order; # - if still not found, go up the hierarchy of names. # # This method has O(n!) behavior when the module calling # include is referencing nonexistent modules. Avoid calling #module until # after all the files are parsed. This behavior is due to ruby's constant # lookup behavior. # # As of the beginning of October, 2011, no gem includes nonexistent modules. def module return @module if @module # search the current context return @name unless parent full_name = parent.child_name(@name) @module = @store.modules_hash[full_name] return @module if @module return @name if @name =~ /^::/ # search the includes before this one, in reverse order searched = parent.includes.take_while { |i| i != self }.reverse searched.each do |i| inc = i.module next if String === inc full_name = inc.child_name(@name) @module = @store.modules_hash[full_name] return @module if @module end # go up the hierarchy of names up = parent.parent while up full_name = up.child_name(@name) @module = @store.modules_hash[full_name] return @module if @module up = up.parent end @name end ## # Sets the store for this class or module and its contained code objects. def store= store super @file = @store.add_file @file.full_name if @file end def to_s # :nodoc: "#{self.class.name.downcase} #@name in: #{parent}" end end PK ]s-gems/rdoc-6.2.1.1/lib/rdoc/context/section.rbnu[# frozen_string_literal: true ## # A section of documentation like: # # # :section: The title # # The body # # Sections can be referenced multiple times and will be collapsed into a # single section. class RDoc::Context::Section include RDoc::Text MARSHAL_VERSION = 0 # :nodoc: ## # Section comment attr_reader :comment ## # Section comments attr_reader :comments ## # Context this Section lives in attr_reader :parent ## # Section title attr_reader :title @@sequence = "SEC00000" ## # Creates a new section with +title+ and +comment+ def initialize parent, title, comment @parent = parent @title = title ? title.strip : title @@sequence = @@sequence.succ @sequence = @@sequence.dup @comments = [] add_comment comment end ## # Sections are equal when they have the same #title def == other self.class === other and @title == other.title end alias eql? == ## # Adds +comment+ to this section def add_comment comment comment = extract_comment comment return if comment.empty? case comment when RDoc::Comment then @comments << comment when RDoc::Markup::Document then @comments.concat comment.parts when Array then @comments.concat comment else raise TypeError, "unknown comment type: #{comment.inspect}" end end ## # Anchor reference for linking to this section def aref title = @title || '[untitled]' CGI.escape(title).gsub('%', '-').sub(/^-/, '') end ## # Extracts the comment for this section from the original comment block. # If the first line contains :section:, strip it and use the rest. # Otherwise remove lines up to the line containing :section:, and look # for those lines again at the end and remove them. This lets us write # # # :section: The title # # The body def extract_comment comment case comment when Array then comment.map do |c| extract_comment c end when nil RDoc::Comment.new '' when RDoc::Comment then if comment.text =~ /^#[ \t]*:section:.*\n/ then start = $` rest = $' comment.text = if start.empty? then rest else rest.sub(/#{start.chomp}\Z/, '') end end comment when RDoc::Markup::Document then comment else raise TypeError, "unknown comment #{comment.inspect}" end end def inspect # :nodoc: "#<%s:0x%x %p>" % [self.class, object_id, title] end def hash # :nodoc: @title.hash end ## # The files comments in this section come from def in_files return [] if @comments.empty? case @comments when Array then @comments.map do |comment| comment.file end when RDoc::Markup::Document then @comment.parts.map do |document| document.file end else raise RDoc::Error, "BUG: unknown comment class #{@comments.class}" end end ## # Serializes this Section. The title and parsed comment are saved, but not # the section parent which must be restored manually. def marshal_dump [ MARSHAL_VERSION, @title, parse, ] end ## # De-serializes this Section. The section parent must be restored manually. def marshal_load array @parent = nil @title = array[1] @comments = array[2] end ## # Parses +comment_location+ into an RDoc::Markup::Document composed of # multiple RDoc::Markup::Documents with their file set. def parse case @comments when String then super when Array then docs = @comments.map do |comment, location| doc = super comment doc.file = location if location doc end RDoc::Markup::Document.new(*docs) when RDoc::Comment then doc = super @comments.text, comments.format doc.file = @comments.location doc when RDoc::Markup::Document then return @comments else raise ArgumentError, "unknown comment class #{comments.class}" end end ## # The section's title, or 'Top Section' if the title is nil. # # This is used by the table of contents template so the name is silly. def plain_html @title || 'Top Section' end ## # Removes a comment from this section if it is from the same file as # +comment+ def remove_comment comment return if @comments.empty? case @comments when Array then @comments.delete_if do |my_comment| my_comment.file == comment.file end when RDoc::Markup::Document then @comments.parts.delete_if do |document| document.file == comment.file.name end else raise RDoc::Error, "BUG: unknown comment class #{@comments.class}" end end ## # Section sequence number (deprecated) def sequence warn "RDoc::Context::Section#sequence is deprecated, use #aref" @sequence end end PK ]e3 *gems/rdoc-6.2.1.1/lib/rdoc/token_stream.rbnu[# frozen_string_literal: true ## # A TokenStream is a list of tokens, gathered during the parse of some entity # (say a method). Entities populate these streams by being registered with the # lexer. Any class can collect tokens by including TokenStream. From the # outside, you use such an object by calling the start_collecting_tokens # method, followed by calls to add_token and pop_token. module RDoc::TokenStream ## # Converts +token_stream+ to HTML wrapping various tokens with # elements. Some tokens types are wrapped in spans # with the given class names. Other token types are not wrapped in spans. def self.to_html token_stream starting_title = false token_stream.map do |t| next unless t style = case t[:kind] when :on_const then 'ruby-constant' when :on_kw then 'ruby-keyword' when :on_ivar then 'ruby-ivar' when :on_cvar then 'ruby-identifier' when :on_gvar then 'ruby-identifier' when '=' != t[:text] && :on_op then 'ruby-operator' when :on_tlambda then 'ruby-operator' when :on_ident then 'ruby-identifier' when :on_label then 'ruby-value' when :on_backref, :on_dstring then 'ruby-node' when :on_comment then 'ruby-comment' when :on_embdoc then 'ruby-comment' when :on_regexp then 'ruby-regexp' when :on_tstring then 'ruby-string' when :on_int, :on_float, :on_rational, :on_imaginary, :on_heredoc, :on_symbol, :on_CHAR then 'ruby-value' when :on_heredoc_beg, :on_heredoc_end then 'ruby-identifier' end comment_with_nl = false if :on_comment == t[:kind] or :on_embdoc == t[:kind] or :on_heredoc_end == t[:kind] comment_with_nl = true if "\n" == t[:text][-1] text = t[:text].rstrip else text = t[:text] end if :on_ident == t[:kind] && starting_title starting_title = false style = 'ruby-identifier ruby-title' end if :on_kw == t[:kind] and 'def' == t[:text] starting_title = true end text = CGI.escapeHTML text if style then "#{text}#{"\n" if comment_with_nl}" else text end end.join end ## # Adds +tokens+ to the collected tokens def add_tokens(tokens) @token_stream.concat(tokens) end ## # Adds one +token+ to the collected tokens def add_token(token) @token_stream.push(token) end ## # Starts collecting tokens def collect_tokens @token_stream = [] end alias start_collecting_tokens collect_tokens ## # Remove the last token from the collected tokens def pop_token @token_stream.pop end ## # Current token stream def token_stream @token_stream end ## # Returns a string representation of the token stream def tokens_to_s token_stream.compact.map { |token| token[:text] }.join '' end end PK ]vTDODO*gems/rdoc-6.2.1.1/lib/rdoc/class_module.rbnu[# frozen_string_literal: true ## # ClassModule is the base class for objects representing either a class or a # module. class RDoc::ClassModule < RDoc::Context ## # 1:: # RDoc 3.7 # * Added visibility, singleton and file to attributes # * Added file to constants # * Added file to includes # * Added file to methods # 2:: # RDoc 3.13 # * Added extends # 3:: # RDoc 4.0 # * Added sections # * Added in_files # * Added parent name # * Complete Constant dump MARSHAL_VERSION = 3 # :nodoc: ## # Constants that are aliases for this class or module attr_accessor :constant_aliases ## # Comment and the location it came from. Use #add_comment to add comments attr_accessor :comment_location attr_accessor :diagram # :nodoc: ## # Class or module this constant is an alias for attr_accessor :is_alias_for ## # Return a RDoc::ClassModule of class +class_type+ that is a copy # of module +module+. Used to promote modules to classes. #-- # TODO move to RDoc::NormalClass (I think) def self.from_module class_type, mod klass = class_type.new mod.name mod.comment_location.each do |comment, location| klass.add_comment comment, location end klass.parent = mod.parent klass.section = mod.section klass.viewer = mod.viewer klass.attributes.concat mod.attributes klass.method_list.concat mod.method_list klass.aliases.concat mod.aliases klass.external_aliases.concat mod.external_aliases klass.constants.concat mod.constants klass.includes.concat mod.includes klass.extends.concat mod.extends klass.methods_hash.update mod.methods_hash klass.constants_hash.update mod.constants_hash klass.current_section = mod.current_section klass.in_files.concat mod.in_files klass.sections.concat mod.sections klass.unmatched_alias_lists = mod.unmatched_alias_lists klass.current_section = mod.current_section klass.visibility = mod.visibility klass.classes_hash.update mod.classes_hash klass.modules_hash.update mod.modules_hash klass.metadata.update mod.metadata klass.document_self = mod.received_nodoc ? nil : mod.document_self klass.document_children = mod.document_children klass.force_documentation = mod.force_documentation klass.done_documenting = mod.done_documenting # update the parent of all children (klass.attributes + klass.method_list + klass.aliases + klass.external_aliases + klass.constants + klass.includes + klass.extends + klass.classes + klass.modules).each do |obj| obj.parent = klass obj.full_name = nil end klass end ## # Creates a new ClassModule with +name+ with optional +superclass+ # # This is a constructor for subclasses, and must never be called directly. def initialize(name, superclass = nil) @constant_aliases = [] @diagram = nil @is_alias_for = nil @name = name @superclass = superclass @comment_location = [] # [[comment, location]] super() end ## # Adds +comment+ to this ClassModule's list of comments at +location+. This # method is preferred over #comment= since it allows ri data to be updated # across multiple runs. def add_comment comment, location return unless document_self original = comment comment = case comment when RDoc::Comment then comment.normalize else normalize_comment comment end if location.parser == RDoc::Parser::C @comment_location.delete_if { |(_, l)| l == location } end @comment_location << [comment, location] self.comment = original end def add_things my_things, other_things # :nodoc: other_things.each do |group, things| my_things[group].each { |thing| yield false, thing } if my_things.include? group things.each do |thing| yield true, thing end end end ## # Ancestors list for this ClassModule: the list of included modules # (classes will add their superclass if any). # # Returns the included classes or modules, not the includes # themselves. The returned values are either String or # RDoc::NormalModule instances (see RDoc::Include#module). # # The values are returned in reverse order of their inclusion, # which is the order suitable for searching methods/attributes # in the ancestors. The superclass, if any, comes last. def ancestors includes.map { |i| i.module }.reverse end def aref_prefix # :nodoc: raise NotImplementedError, "missing aref_prefix for #{self.class}" end ## # HTML fragment reference for this module or class. See # RDoc::NormalClass#aref and RDoc::NormalModule#aref def aref "#{aref_prefix}-#{full_name}" end ## # Ancestors of this class or module only alias direct_ancestors ancestors ## # Clears the comment. Used by the Ruby parser. def clear_comment @comment = '' end ## # This method is deprecated, use #add_comment instead. # # Appends +comment+ to the current comment, but separated by a rule. Works # more like +=. def comment= comment # :nodoc: comment = case comment when RDoc::Comment then comment.normalize else normalize_comment comment end comment = "#{@comment.to_s}\n---\n#{comment.to_s}" unless @comment.empty? super comment end ## # Prepares this ClassModule for use by a generator. # # See RDoc::Store#complete def complete min_visibility update_aliases remove_nodoc_children update_includes remove_invisible min_visibility end ## # Does this ClassModule or any of its methods have document_self set? def document_self_or_methods document_self || method_list.any?{ |m| m.document_self } end ## # Does this class or module have a comment with content or is # #received_nodoc true? def documented? return true if @received_nodoc return false if @comment_location.empty? @comment_location.any? { |comment, _| not comment.empty? } end ## # Iterates the ancestors of this class or module for which an # RDoc::ClassModule exists. def each_ancestor # :yields: module return enum_for __method__ unless block_given? ancestors.each do |mod| next if String === mod next if self == mod yield mod end end ## # Looks for a symbol in the #ancestors. See Context#find_local_symbol. def find_ancestor_local_symbol symbol each_ancestor do |m| res = m.find_local_symbol(symbol) return res if res end nil end ## # Finds a class or module with +name+ in this namespace or its descendants def find_class_named name return self if full_name == name return self if @name == name @classes.values.find do |klass| next if klass == self klass.find_class_named name end end ## # Return the fully qualified name of this class or module def full_name @full_name ||= if RDoc::ClassModule === parent then "#{parent.full_name}::#{@name}" else @name end end ## # TODO: filter included items by #display? def marshal_dump # :nodoc: attrs = attributes.sort.map do |attr| next unless attr.display? [ attr.name, attr.rw, attr.visibility, attr.singleton, attr.file_name, ] end.compact method_types = methods_by_type.map do |type, visibilities| visibilities = visibilities.map do |visibility, methods| method_names = methods.map do |method| next unless method.display? [method.name, method.file_name] end.compact [visibility, method_names.uniq] end [type, visibilities] end [ MARSHAL_VERSION, @name, full_name, @superclass, parse(@comment_location), attrs, constants.select { |constant| constant.display? }, includes.map do |incl| next unless incl.display? [incl.name, parse(incl.comment), incl.file_name] end.compact, method_types, extends.map do |ext| next unless ext.display? [ext.name, parse(ext.comment), ext.file_name] end.compact, @sections.values, @in_files.map do |tl| tl.relative_name end, parent.full_name, parent.class, ] end def marshal_load array # :nodoc: initialize_visibility initialize_methods_etc @current_section = nil @document_self = true @done_documenting = false @parent = nil @temporary_section = nil @visibility = nil @classes = {} @modules = {} @name = array[1] @full_name = array[2] @superclass = array[3] @comment = array[4] @comment_location = if RDoc::Markup::Document === @comment.parts.first then @comment else RDoc::Markup::Document.new @comment end array[5].each do |name, rw, visibility, singleton, file| singleton ||= false visibility ||= :public attr = RDoc::Attr.new nil, name, rw, nil, singleton add_attribute attr attr.visibility = visibility attr.record_location RDoc::TopLevel.new file end array[6].each do |constant, comment, file| case constant when RDoc::Constant then add_constant constant else constant = add_constant RDoc::Constant.new(constant, nil, comment) constant.record_location RDoc::TopLevel.new file end end array[7].each do |name, comment, file| incl = add_include RDoc::Include.new(name, comment) incl.record_location RDoc::TopLevel.new file end array[8].each do |type, visibilities| visibilities.each do |visibility, methods| @visibility = visibility methods.each do |name, file| method = RDoc::AnyMethod.new nil, name method.singleton = true if type == 'class' method.record_location RDoc::TopLevel.new file add_method method end end end array[9].each do |name, comment, file| ext = add_extend RDoc::Extend.new(name, comment) ext.record_location RDoc::TopLevel.new file end if array[9] # Support Marshal version 1 sections = (array[10] || []).map do |section| [section.title, section] end @sections = Hash[*sections.flatten] @current_section = add_section nil @in_files = [] (array[11] || []).each do |filename| record_location RDoc::TopLevel.new filename end @parent_name = array[12] @parent_class = array[13] end ## # Merges +class_module+ into this ClassModule. # # The data in +class_module+ is preferred over the receiver. def merge class_module @parent = class_module.parent @parent_name = class_module.parent_name other_document = parse class_module.comment_location if other_document then document = parse @comment_location document = document.merge other_document @comment = @comment_location = document end cm = class_module other_files = cm.in_files merge_collections attributes, cm.attributes, other_files do |add, attr| if add then add_attribute attr else @attributes.delete attr @methods_hash.delete attr.pretty_name end end merge_collections constants, cm.constants, other_files do |add, const| if add then add_constant const else @constants.delete const @constants_hash.delete const.name end end merge_collections includes, cm.includes, other_files do |add, incl| if add then add_include incl else @includes.delete incl end end @includes.uniq! # clean up merge_collections extends, cm.extends, other_files do |add, ext| if add then add_extend ext else @extends.delete ext end end @extends.uniq! # clean up merge_collections method_list, cm.method_list, other_files do |add, meth| if add then add_method meth else @method_list.delete meth @methods_hash.delete meth.pretty_name end end merge_sections cm self end ## # Merges collection +mine+ with +other+ preferring other. +other_files+ is # used to help determine which items should be deleted. # # Yields whether the item should be added or removed (true or false) and the # item to be added or removed. # # merge_collections things, other.things, other.in_files do |add, thing| # if add then # # add the thing # else # # remove the thing # end # end def merge_collections mine, other, other_files, &block # :nodoc: my_things = mine. group_by { |thing| thing.file } other_things = other.group_by { |thing| thing.file } remove_things my_things, other_files, &block add_things my_things, other_things, &block end ## # Merges the comments in this ClassModule with the comments in the other # ClassModule +cm+. def merge_sections cm # :nodoc: my_sections = sections.group_by { |section| section.title } other_sections = cm.sections.group_by { |section| section.title } other_files = cm.in_files remove_things my_sections, other_files do |_, section| @sections.delete section.title end other_sections.each do |group, sections| if my_sections.include? group my_sections[group].each do |my_section| other_section = cm.sections_hash[group] my_comments = my_section.comments other_comments = other_section.comments other_files = other_section.in_files merge_collections my_comments, other_comments, other_files do |add, comment| if add then my_section.add_comment comment else my_section.remove_comment comment end end end else sections.each do |section| add_section group, section.comments end end end end ## # Does this object represent a module? def module? false end ## # Allows overriding the initial name. # # Used for modules and classes that are constant aliases. def name= new_name @name = new_name end ## # Parses +comment_location+ into an RDoc::Markup::Document composed of # multiple RDoc::Markup::Documents with their file set. def parse comment_location case comment_location when String then super when Array then docs = comment_location.map do |comment, location| doc = super comment doc.file = location doc end RDoc::Markup::Document.new(*docs) when RDoc::Comment then doc = super comment_location.text, comment_location.format doc.file = comment_location.location doc when RDoc::Markup::Document then return comment_location else raise ArgumentError, "unknown comment class #{comment_location.class}" end end ## # Path to this class or module for use with HTML generator output. def path http_url @store.rdoc.generator.class_dir end ## # Name to use to generate the url: # modules and classes that are aliases for another # module or class return the name of the latter. def name_for_path is_alias_for ? is_alias_for.full_name : full_name end ## # Returns the classes and modules that are not constants # aliasing another class or module. For use by formatters # only (caches its result). def non_aliases @non_aliases ||= classes_and_modules.reject { |cm| cm.is_alias_for } end ## # Updates the child modules or classes of class/module +parent+ by # deleting the ones that have been removed from the documentation. # # +parent_hash+ is either parent.modules_hash or # parent.classes_hash and +all_hash+ is ::all_modules_hash or # ::all_classes_hash. def remove_nodoc_children prefix = self.full_name + '::' modules_hash.each_key do |name| full_name = prefix + name modules_hash.delete name unless @store.modules_hash[full_name] end classes_hash.each_key do |name| full_name = prefix + name classes_hash.delete name unless @store.classes_hash[full_name] end end def remove_things my_things, other_files # :nodoc: my_things.delete_if do |file, things| next false unless other_files.include? file things.each do |thing| yield false, thing end true end end ## # Search record used by RDoc::Generator::JsonIndex def search_record [ name, full_name, full_name, '', path, '', snippet(@comment_location), ] end ## # Sets the store for this class or module and its contained code objects. def store= store super @attributes .each do |attr| attr.store = store end @constants .each do |const| const.store = store end @includes .each do |incl| incl.store = store end @extends .each do |ext| ext.store = store end @method_list.each do |meth| meth.store = store end end ## # Get the superclass of this class. Attempts to retrieve the superclass # object, returns the name if it is not known. def superclass @store.find_class_named(@superclass) || @superclass end ## # Set the superclass of this class to +superclass+ def superclass=(superclass) raise NoMethodError, "#{full_name} is a module" if module? @superclass = superclass end def to_s # :nodoc: if is_alias_for then "#{self.class.name} #{self.full_name} -> #{is_alias_for}" else super end end ## # 'module' or 'class' def type module? ? 'module' : 'class' end ## # Updates the child modules & classes by replacing the ones that are # aliases through a constant. # # The aliased module/class is replaced in the children and in # RDoc::Store#modules_hash or RDoc::Store#classes_hash # by a copy that has RDoc::ClassModule#is_alias_for set to # the aliased module/class, and this copy is added to #aliases # of the aliased module/class. # # Formatters can use the #non_aliases method to retrieve children that # are not aliases, for instance to list the namespace content, since # the aliased modules are included in the constants of the class/module, # that are listed separately. def update_aliases constants.each do |const| next unless cm = const.is_alias_for cm_alias = cm.dup cm_alias.name = const.name # Don't move top-level aliases under Object, they look ugly there unless RDoc::TopLevel === cm_alias.parent then cm_alias.parent = self cm_alias.full_name = nil # force update for new parent end cm_alias.aliases.clear cm_alias.is_alias_for = cm if cm.module? then @store.modules_hash[cm_alias.full_name] = cm_alias modules_hash[const.name] = cm_alias else @store.classes_hash[cm_alias.full_name] = cm_alias classes_hash[const.name] = cm_alias end cm.aliases << cm_alias end end ## # Deletes from #includes those whose module has been removed from the # documentation. #-- # FIXME: includes are not reliably removed, see _possible_bug test case def update_includes includes.reject! do |include| mod = include.module !(String === mod) && @store.modules_hash[mod.full_name].nil? end includes.uniq! end ## # Deletes from #extends those whose module has been removed from the # documentation. #-- # FIXME: like update_includes, extends are not reliably removed def update_extends extends.reject! do |ext| mod = ext.module !(String === mod) && @store.modules_hash[mod.full_name].nil? end extends.uniq! end end PK ]V*6*6"gems/rdoc-6.2.1.1/lib/rdoc/rdoc.rbnu[# frozen_string_literal: true require 'rdoc' require 'find' require 'fileutils' require 'pathname' require 'time' ## # This is the driver for generating RDoc output. It handles file parsing and # generation of output. # # To use this class to generate RDoc output via the API, the recommended way # is: # # rdoc = RDoc::RDoc.new # options = rdoc.load_options # returns an RDoc::Options instance # # set extra options # rdoc.document options # # You can also generate output like the +rdoc+ executable: # # rdoc = RDoc::RDoc.new # rdoc.document argv # # Where +argv+ is an array of strings, each corresponding to an argument you'd # give rdoc on the command line. See rdoc --help for details. class RDoc::RDoc @current = nil ## # This is the list of supported output generators GENERATORS = {} ## # Generator instance used for creating output attr_accessor :generator ## # Hash of files and their last modified times. attr_reader :last_modified ## # RDoc options attr_accessor :options ## # Accessor for statistics. Available after each call to parse_files attr_reader :stats ## # The current documentation store attr_reader :store ## # Add +klass+ that can generate output after parsing def self.add_generator(klass) name = klass.name.sub(/^RDoc::Generator::/, '').downcase GENERATORS[name] = klass end ## # Active RDoc::RDoc instance def self.current @current end ## # Sets the active RDoc::RDoc instance def self.current= rdoc @current = rdoc end ## # Creates a new RDoc::RDoc instance. Call #document to parse files and # generate documentation. def initialize @current = nil @generator = nil @last_modified = {} @old_siginfo = nil @options = nil @stats = nil @store = nil end ## # Report an error message and exit def error(msg) raise RDoc::Error, msg end ## # Gathers a set of parseable files from the files and directories listed in # +files+. def gather_files files files = ["."] if files.empty? file_list = normalized_file_list files, true, @options.exclude file_list = file_list.uniq file_list = remove_unparseable file_list file_list.sort end ## # Turns RDoc from stdin into HTML def handle_pipe @html = RDoc::Markup::ToHtml.new @options parser = RDoc::Text::MARKUP_FORMAT[@options.markup] document = parser.parse $stdin.read out = @html.convert document $stdout.write out end ## # Installs a siginfo handler that prints the current filename. def install_siginfo_handler return unless Signal.list.include? 'INFO' @old_siginfo = trap 'INFO' do puts @current if @current end end ## # Loads options from .rdoc_options if the file exists, otherwise creates a # new RDoc::Options instance. def load_options options_file = File.expand_path '.rdoc_options' return RDoc::Options.new unless File.exist? options_file RDoc.load_yaml begin options = YAML.load_file '.rdoc_options' rescue Psych::SyntaxError end raise RDoc::Error, "#{options_file} is not a valid rdoc options file" unless RDoc::Options === options options end ## # Create an output dir if it doesn't exist. If it does exist, but doesn't # contain the flag file created.rid then we refuse to use it, as # we may clobber some manually generated documentation def setup_output_dir(dir, force) flag_file = output_flag_file dir last = {} if @options.dry_run then # do nothing elsif File.exist? dir then error "#{dir} exists and is not a directory" unless File.directory? dir begin File.open flag_file do |io| unless force then Time.parse io.gets io.each do |line| file, time = line.split "\t", 2 time = Time.parse(time) rescue next last[file] = time end end end rescue SystemCallError, TypeError error <<-ERROR Directory #{dir} already exists, but it looks like it isn't an RDoc directory. Because RDoc doesn't want to risk destroying any of your existing files, you'll need to specify a different output directory name (using the --op
    option) ERROR end unless @options.force_output else FileUtils.mkdir_p dir FileUtils.touch flag_file end last end ## # Sets the current documentation tree to +store+ and sets the store's rdoc # driver to this instance. def store= store @store = store @store.rdoc = self end ## # Update the flag file in an output directory. def update_output_dir(op_dir, time, last = {}) return if @options.dry_run or not @options.update_output_dir unless ENV['SOURCE_DATE_EPOCH'].nil? time = Time.at(ENV['SOURCE_DATE_EPOCH'].to_i).gmtime end File.open output_flag_file(op_dir), "w" do |f| f.puts time.rfc2822 last.each do |n, t| f.puts "#{n}\t#{t.rfc2822}" end end end ## # Return the path name of the flag file in an output directory. def output_flag_file(op_dir) File.join op_dir, "created.rid" end ## # The .document file contains a list of file and directory name patterns, # representing candidates for documentation. It may also contain comments # (starting with '#') def parse_dot_doc_file in_dir, filename # read and strip comments patterns = File.read(filename).gsub(/#.*/, '') result = [] patterns.split.each do |patt| candidates = Dir.glob(File.join(in_dir, patt)) result.concat normalized_file_list(candidates, false, @options.exclude) end result end ## # Given a list of files and directories, create a list of all the Ruby # files they contain. # # If +force_doc+ is true we always add the given files, if false, only # add files that we guarantee we can parse. It is true when looking at # files given on the command line, false when recursing through # subdirectories. # # The effect of this is that if you want a file with a non-standard # extension parsed, you must name it explicitly. def normalized_file_list(relative_files, force_doc = false, exclude_pattern = nil) file_list = [] relative_files.each do |rel_file_name| next if rel_file_name.end_with? 'created.rid' next if exclude_pattern && exclude_pattern =~ rel_file_name stat = File.stat rel_file_name rescue next case type = stat.ftype when "file" then next if last_modified = @last_modified[rel_file_name] and stat.mtime.to_i <= last_modified.to_i if force_doc or RDoc::Parser.can_parse(rel_file_name) then file_list << rel_file_name.sub(/^\.\//, '') @last_modified[rel_file_name] = stat.mtime end when "directory" then next if rel_file_name == "CVS" || rel_file_name == ".svn" created_rid = File.join rel_file_name, "created.rid" next if File.file? created_rid dot_doc = File.join rel_file_name, RDoc::DOT_DOC_FILENAME if File.file? dot_doc then file_list << parse_dot_doc_file(rel_file_name, dot_doc) else file_list << list_files_in_directory(rel_file_name) end else warn "rdoc can't parse the #{type} #{rel_file_name}" end end file_list.flatten end ## # Return a list of the files to be processed in a directory. We know that # this directory doesn't have a .document file, so we're looking for real # files. However we may well contain subdirectories which must be tested # for .document files. def list_files_in_directory dir files = Dir.glob File.join(dir, "*") normalized_file_list files, false, @options.exclude end ## # Parses +filename+ and returns an RDoc::TopLevel def parse_file filename encoding = @options.encoding filename = filename.encode encoding @stats.add_file filename return if RDoc::Parser.binary? filename content = RDoc::Encoding.read_file filename, encoding return unless content filename_path = Pathname(filename).expand_path begin relative_path = filename_path.relative_path_from @options.root rescue ArgumentError relative_path = filename_path end if @options.page_dir and relative_path.to_s.start_with? @options.page_dir.to_s then relative_path = relative_path.relative_path_from @options.page_dir end top_level = @store.add_file filename, relative_name: relative_path.to_s parser = RDoc::Parser.for top_level, filename, content, @options, @stats return unless parser parser.scan # restart documentation for the classes & modules found top_level.classes_or_modules.each do |cm| cm.done_documenting = false end top_level rescue Errno::EACCES => e $stderr.puts <<-EOF Unable to read #{filename}, #{e.message} Please check the permissions for this file. Perhaps you do not have access to it or perhaps the original author's permissions are to restrictive. If the this is not your library please report a bug to the author. EOF rescue => e $stderr.puts <<-EOF Before reporting this, could you check that the file you're documenting has proper syntax: #{Gem.ruby} -c #{filename} RDoc is not a full Ruby parser and will fail when fed invalid ruby programs. The internal error was: \t(#{e.class}) #{e.message} EOF $stderr.puts e.backtrace.join("\n\t") if $DEBUG_RDOC raise e nil end ## # Parse each file on the command line, recursively entering directories. def parse_files files file_list = gather_files files @stats = RDoc::Stats.new @store, file_list.length, @options.verbosity return [] if file_list.empty? original_options = @options.dup @stats.begin_adding file_info = file_list.map do |filename| @current = filename parse_file filename end.compact @stats.done_adding @options = original_options file_info end ## # Removes file extensions known to be unparseable from +files+ and TAGS # files for emacs and vim. def remove_unparseable files files.reject do |file| file =~ /\.(?:class|eps|erb|scpt\.txt|svg|ttf|yml)$/i or (file =~ /tags$/i and File.open(file, 'rb') { |io| io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/ }) end end ## # Generates documentation or a coverage report depending upon the settings # in +options+. # # +options+ can be either an RDoc::Options instance or an array of strings # equivalent to the strings that would be passed on the command line like # %w[-q -o doc -t My\ Doc\ Title]. #document will automatically # call RDoc::Options#finish if an options instance was given. # # For a list of options, see either RDoc::Options or rdoc --help. # # By default, output will be stored in a directory called "doc" below the # current directory, so make sure you're somewhere writable before invoking. def document options self.store = RDoc::Store.new if RDoc::Options === options then @options = options @options.finish else @options = load_options @options.parse options end if @options.pipe then handle_pipe exit end unless @options.coverage_report then @last_modified = setup_output_dir @options.op_dir, @options.force_update end @store.encoding = @options.encoding @store.dry_run = @options.dry_run @store.main = @options.main_page @store.title = @options.title @store.path = @options.op_dir @start_time = Time.now @store.load_cache file_info = parse_files @options.files @options.default_title = "RDoc Documentation" @store.complete @options.visibility @stats.coverage_level = @options.coverage_report if @options.coverage_report then puts puts @stats.report.accept RDoc::Markup::ToRdoc.new elsif file_info.empty? then $stderr.puts "\nNo newer files." unless @options.quiet else gen_klass = @options.generator @generator = gen_klass.new @store, @options generate end if @stats and (@options.coverage_report or not @options.quiet) then puts puts @stats.summary.accept RDoc::Markup::ToRdoc.new end exit @stats.fully_documented? if @options.coverage_report end ## # Generates documentation for +file_info+ (from #parse_files) into the # output dir using the generator selected # by the RDoc options def generate if @options.dry_run then # do nothing @generator.generate else Dir.chdir @options.op_dir do unless @options.quiet then $stderr.puts "\nGenerating #{@generator.class.name.sub(/^.*::/, '')} format into #{Dir.pwd}..." end @generator.generate update_output_dir '.', @start_time, @last_modified end end end ## # Removes a siginfo handler and replaces the previous def remove_siginfo_handler return unless Signal.list.key? 'INFO' handler = @old_siginfo || 'DEFAULT' trap 'INFO', handler end end begin require 'rubygems' rdoc_extensions = Gem.find_files 'rdoc/discover' rdoc_extensions.each do |extension| begin load extension rescue => e warn "error loading #{extension.inspect}: #{e.message} (#{e.class})" warn "\t#{e.backtrace.join "\n\t"}" if $DEBUG end end rescue LoadError end # require built-in generators after discovery in case they've been replaced require 'rdoc/generator/darkfish' require 'rdoc/generator/ri' require 'rdoc/generator/pot' PK ]v}+gems/rdoc-6.2.1.1/lib/rdoc/rubygems_hook.rbnu[# frozen_string_literal: true require 'rubygems/user_interaction' require 'fileutils' require 'rdoc' ## # Gem::RDoc provides methods to generate RDoc and ri data for installed gems # upon gem installation. # # This file is automatically required by RubyGems 1.9 and newer. class RDoc::RubygemsHook include Gem::UserInteraction extend Gem::UserInteraction @rdoc_version = nil @specs = [] ## # Force installation of documentation? attr_accessor :force ## # Generate rdoc? attr_accessor :generate_rdoc ## # Generate ri data? attr_accessor :generate_ri class << self ## # Loaded version of RDoc. Set by ::load_rdoc attr_reader :rdoc_version end ## # Post installs hook that generates documentation for each specification in # +specs+ def self.generation_hook installer, specs start = Time.now types = installer.document generate_rdoc = types.include? 'rdoc' generate_ri = types.include? 'ri' specs.each do |spec| new(spec, generate_rdoc, generate_ri).generate end return unless generate_rdoc or generate_ri duration = (Time.now - start).to_i names = specs.map(&:name).join ', ' say "Done installing documentation for #{names} after #{duration} seconds" end ## # Loads the RDoc generator def self.load_rdoc return if @rdoc_version require 'rdoc/rdoc' @rdoc_version = Gem::Version.new ::RDoc::VERSION end ## # Creates a new documentation generator for +spec+. RDoc and ri data # generation can be enabled or disabled through +generate_rdoc+ and # +generate_ri+ respectively. # # Only +generate_ri+ is enabled by default. def initialize spec, generate_rdoc = false, generate_ri = true @doc_dir = spec.doc_dir @force = false @rdoc = nil @spec = spec @generate_rdoc = generate_rdoc @generate_ri = generate_ri @rdoc_dir = spec.doc_dir 'rdoc' @ri_dir = spec.doc_dir 'ri' end ## # Removes legacy rdoc arguments from +args+ #-- # TODO move to RDoc::Options def delete_legacy_args args args.delete '--inline-source' args.delete '--promiscuous' args.delete '-p' args.delete '--one-file' end ## # Generates documentation using the named +generator+ ("darkfish" or "ri") # and following the given +options+. # # Documentation will be generated into +destination+ def document generator, options, destination generator_name = generator options = options.dup options.exclude ||= [] # TODO maybe move to RDoc::Options#finish options.setup_generator generator options.op_dir = destination options.finish generator = options.generator.new @rdoc.store, options @rdoc.options = options @rdoc.generator = generator say "Installing #{generator_name} documentation for #{@spec.full_name}" FileUtils.mkdir_p options.op_dir Dir.chdir options.op_dir do begin @rdoc.class.current = @rdoc @rdoc.generator.generate ensure @rdoc.class.current = nil end end end ## # Generates RDoc and ri data def generate return if @spec.default_gem? return unless @generate_ri or @generate_rdoc setup options = nil args = @spec.rdoc_options args.concat @spec.source_paths args.concat @spec.extra_rdoc_files case config_args = Gem.configuration[:rdoc] when String then args = args.concat config_args.split when Array then args = args.concat config_args end delete_legacy_args args Dir.chdir @spec.full_gem_path do options = ::RDoc::Options.new options.default_title = "#{@spec.full_name} Documentation" options.parse args end options.quiet = !Gem.configuration.really_verbose @rdoc = new_rdoc @rdoc.options = options store = RDoc::Store.new store.encoding = options.encoding store.dry_run = options.dry_run store.main = options.main_page store.title = options.title @rdoc.store = store say "Parsing documentation for #{@spec.full_name}" Dir.chdir @spec.full_gem_path do @rdoc.parse_files options.files end document 'ri', options, @ri_dir if @generate_ri and (@force or not File.exist? @ri_dir) document 'darkfish', options, @rdoc_dir if @generate_rdoc and (@force or not File.exist? @rdoc_dir) end ## # #new_rdoc creates a new RDoc instance. This method is provided only to # make testing easier. def new_rdoc # :nodoc: ::RDoc::RDoc.new end ## # Is rdoc documentation installed? def rdoc_installed? File.exist? @rdoc_dir end ## # Removes generated RDoc and ri data def remove base_dir = @spec.base_dir raise Gem::FilePermissionError, base_dir unless File.writable? base_dir FileUtils.rm_rf @rdoc_dir FileUtils.rm_rf @ri_dir end ## # Is ri data installed? def ri_installed? File.exist? @ri_dir end ## # Prepares the spec for documentation generation def setup self.class.load_rdoc raise Gem::FilePermissionError, @doc_dir if File.exist?(@doc_dir) and not File.writable?(@doc_dir) FileUtils.mkdir_p @doc_dir unless File.exist? @doc_dir end end PK ]ʥ9e%gems/rdoc-6.2.1.1/lib/rdoc/tom_doc.rbnu[# frozen_string_literal: true # :markup: tomdoc # A parser for TomDoc based on TomDoc 1.0.0-rc1 (02adef9b5a) # # The TomDoc specification can be found at: # # http://tomdoc.org # # The latest version of the TomDoc specification can be found at: # # https://github.com/mojombo/tomdoc/blob/master/tomdoc.md # # To choose TomDoc as your only default format see RDoc::Options@Saved+Options # for instructions on setting up a .rdoc_options file to store # your project default. # # There are a few differences between this parser and the specification. A # best-effort was made to follow the specification as closely as possible but # some choices to deviate were made. # # A future version of RDoc will warn when a MUST or MUST NOT is violated and # may warn when a SHOULD or SHOULD NOT is violated. RDoc will always try # to emit documentation even if given invalid TomDoc. # # Here are some implementation choices this parser currently makes: # # This parser allows rdoc-style inline markup but you should not depended on # it. # # This parser allows a space between the comment and the method body. # # This parser does not require the default value to be described for an # optional argument. # # This parser does not examine the order of sections. An Examples section may # precede the Arguments section. # # This class is documented in TomDoc format. Since this is a subclass of the # RDoc markup parser there isn't much to see here, unfortunately. class RDoc::TomDoc < RDoc::Markup::Parser # Internal: Token accessor attr_reader :tokens # Internal: Adds a post-processor which sets the RDoc section based on the # comment's status. # # Returns nothing. def self.add_post_processor # :nodoc: RDoc::Markup::PreProcess.post_process do |comment, code_object| next unless code_object and RDoc::Comment === comment and comment.format == 'tomdoc' comment.text.gsub!(/(\A\s*# )(Public|Internal|Deprecated):\s+/) do section = code_object.add_section $2 code_object.temporary_section = section $1 end end end add_post_processor # Public: Parses TomDoc from text # # text - A String containing TomDoc-format text. # # Examples # # RDoc::TomDoc.parse <<-TOMDOC # This method does some things # # Returns nothing. # TOMDOC # # => # # # Returns an RDoc::Markup::Document representing the TomDoc format. def self.parse text parser = new parser.tokenize text doc = RDoc::Markup::Document.new parser.parse doc doc end # Internal: Extracts the Signature section's method signature # # comment - An RDoc::Comment that will be parsed and have the signature # extracted # # Returns a String containing the signature and nil if not def self.signature comment return unless comment.tomdoc? document = comment.parse signature = nil found_heading = false found_signature = false document.parts.delete_if do |part| next false if found_signature found_heading ||= RDoc::Markup::Heading === part && part.text == 'Signature' next false unless found_heading next true if RDoc::Markup::BlankLine === part if RDoc::Markup::Verbatim === part then signature = part found_signature = true end end signature and signature.text end # Public: Creates a new TomDoc parser. See also RDoc::Markup::parse def initialize super @section = nil @seen_returns = false end # Internal: Builds a heading from the token stream # # level - The level of heading to create # # Returns an RDoc::Markup::Heading def build_heading level heading = super @section = heading.text heading end # Internal: Builds a verbatim from the token stream. A verbatim in the # Examples section will be marked as in Ruby format. # # margin - The indentation from the margin for lines that belong to this # verbatim section. # # Returns an RDoc::Markup::Verbatim def build_verbatim margin verbatim = super verbatim.format = :ruby if @section == 'Examples' verbatim end # Internal: Builds a paragraph from the token stream # # margin - Unused # # Returns an RDoc::Markup::Paragraph. def build_paragraph margin p :paragraph_start => margin if @debug paragraph = RDoc::Markup::Paragraph.new until @tokens.empty? do type, data, = get case type when :TEXT then @section = 'Returns' if data =~ /\A(Returns|Raises)/ paragraph << data when :NEWLINE then if :TEXT == peek_token[0] then # Lines beginning with 'Raises' in the Returns section should not be # treated as multiline text if 'Returns' == @section and peek_token[1].start_with?('Raises') then break else paragraph << ' ' end else break end else unget break end end p :paragraph_end => margin if @debug paragraph end ## # Detects a section change to "Returns" and adds a heading def parse_text parent, indent # :nodoc: paragraph = build_paragraph indent if false == @seen_returns and 'Returns' == @section then @seen_returns = true parent << RDoc::Markup::Heading.new(3, 'Returns') parent << RDoc::Markup::BlankLine.new end parent << paragraph end # Internal: Turns text into an Array of tokens # # text - A String containing TomDoc-format text. # # Returns self. def tokenize text text = text.sub(/\A(Public|Internal|Deprecated):\s+/, '') setup_scanner text until @s.eos? do pos = @s.pos # leading spaces will be reflected by the column of the next token # the only thing we loose are trailing spaces at the end of the file next if @s.scan(/ +/) @tokens << case when @s.scan(/\r?\n/) then token = [:NEWLINE, @s.matched, *pos] @s.newline! token when @s.scan(/(Examples|Signature)$/) then @tokens << [:HEADER, 3, *pos] [:TEXT, @s[1], *pos] when @s.scan(/([:\w][\w\[\]]*)[ ]+- /) then [:NOTE, @s[1], *pos] else @s.scan(/.*/) [:TEXT, @s.matched.sub(/\r$/, ''), *pos] end end self end end PK ] [>  "gems/rdoc-6.2.1.1/lib/rdoc/attr.rbnu[# frozen_string_literal: true ## # An attribute created by \#attr, \#attr_reader, \#attr_writer or # \#attr_accessor class RDoc::Attr < RDoc::MethodAttr ## # 3:: # RDoc 4 # Added parent name and class # Added section title MARSHAL_VERSION = 3 # :nodoc: ## # Is the attribute readable ('R'), writable ('W') or both ('RW')? attr_accessor :rw ## # Creates a new Attr with body +text+, +name+, read/write status +rw+ and # +comment+. +singleton+ marks this as a class attribute. def initialize(text, name, rw, comment, singleton = false) super text, name @rw = rw @singleton = singleton self.comment = comment end ## # Attributes are equal when their names, singleton and rw are identical def == other self.class == other.class and self.name == other.name and self.rw == other.rw and self.singleton == other.singleton end ## # Add +an_alias+ as an attribute in +context+. def add_alias(an_alias, context) new_attr = self.class.new(self.text, an_alias.new_name, self.rw, self.comment, self.singleton) new_attr.record_location an_alias.file new_attr.visibility = self.visibility new_attr.is_alias_for = self @aliases << new_attr context.add_attribute new_attr new_attr end ## # The #aref prefix for attributes def aref_prefix 'attribute' end ## # Attributes never call super. See RDoc::AnyMethod#calls_super # # An RDoc::Attr can show up in the method list in some situations (see # Gem::ConfigFile) def calls_super # :nodoc: false end ## # Returns attr_reader, attr_writer or attr_accessor as appropriate. def definition case @rw when 'RW' then 'attr_accessor' when 'R' then 'attr_reader' when 'W' then 'attr_writer' end end def inspect # :nodoc: alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil visibility = self.visibility visibility = "forced #{visibility}" if force_documentation "#<%s:0x%x %s %s (%s)%s>" % [ self.class, object_id, full_name, rw, visibility, alias_for, ] end ## # Dumps this Attr for use by ri. See also #marshal_load def marshal_dump [ MARSHAL_VERSION, @name, full_name, @rw, @visibility, parse(@comment), singleton, @file.relative_name, @parent.full_name, @parent.class, @section.title ] end ## # Loads this Attr from +array+. For a loaded Attr the following # methods will return cached values: # # * #full_name # * #parent_name def marshal_load array initialize_visibility @aliases = [] @parent = nil @parent_name = nil @parent_class = nil @section = nil @file = nil version = array[0] @name = array[1] @full_name = array[2] @rw = array[3] @visibility = array[4] @comment = array[5] @singleton = array[6] || false # MARSHAL_VERSION == 0 # 7 handled below @parent_name = array[8] @parent_class = array[9] @section_title = array[10] @file = RDoc::TopLevel.new array[7] if version > 1 @parent_name ||= @full_name.split('#', 2).first end def pretty_print q # :nodoc: q.group 2, "[#{self.class.name} #{full_name} #{rw} #{visibility}", "]" do unless comment.empty? then q.breakable q.text "comment:" q.breakable q.pp @comment end end end def to_s # :nodoc: "#{definition} #{name} in: #{parent}" end ## # Attributes do not have token streams. # # An RDoc::Attr can show up in the method list in some situations (see # Gem::ConfigFile) def token_stream # :nodoc: end end PK ]KzVf f )gems/rdoc-6.2.1.1/lib/rdoc/i18n/locale.rbnu[# frozen_string_literal: true ## # A message container for a locale. # # This object provides the following two features: # # * Loads translated messages from .po file. # * Translates a message into the locale. class RDoc::I18n::Locale @@locales = {} # :nodoc: class << self ## # Returns the locale object for +locale_name+. def [](locale_name) @@locales[locale_name] ||= new(locale_name) end ## # Sets the locale object for +locale_name+. # # Normally, this method is not used. This method is useful for # testing. def []=(locale_name, locale) @@locales[locale_name] = locale end end ## # The name of the locale. It uses IETF language tag format # +[language[_territory][.codeset][@modifier]]+. # # See also {BCP 47 - Tags for Identifying # Languages}[http://tools.ietf.org/rfc/bcp/bcp47.txt]. attr_reader :name ## # Creates a new locale object for +name+ locale. +name+ must # follow IETF language tag format. def initialize(name) @name = name @messages = {} end ## # Loads translation messages from +locale_directory+/+@name+/rdoc.po # or +locale_directory+/+@name+.po. The former has high priority. # # This method requires gettext gem for parsing .po file. If you # don't have gettext gem, this method doesn't load .po file. This # method warns and returns +false+. # # Returns +true+ if succeeded, +false+ otherwise. def load(locale_directory) return false if @name.nil? po_file_candidates = [ File.join(locale_directory, @name, 'rdoc.po'), File.join(locale_directory, "#{@name}.po"), ] po_file = po_file_candidates.find do |po_file_candidate| File.exist?(po_file_candidate) end return false unless po_file begin require 'gettext/po_parser' require 'gettext/mo' rescue LoadError warn('Need gettext gem for i18n feature:') warn(' gem install gettext') return false end po_parser = GetText::POParser.new messages = GetText::MO.new po_parser.report_warning = false po_parser.parse_file(po_file, messages) @messages.merge!(messages) true end ## # Translates the +message+ into locale. If there is no translation # messages for +message+ in locale, +message+ itself is returned. def translate(message) @messages[message] || message end end PK ]S2 'gems/rdoc-6.2.1.1/lib/rdoc/i18n/text.rbnu[# frozen_string_literal: true ## # An i18n supported text. # # This object provides the following two features: # # * Extracts translation messages from wrapped raw text. # * Translates wrapped raw text in specified locale. # # Wrapped raw text is one of String, RDoc::Comment or Array of them. class RDoc::I18n::Text ## # Creates a new i18n supported text for +raw+ text. def initialize(raw) @raw = raw end ## # Extracts translation target messages and yields each message. # # Each yielded message is a Hash. It consists of the followings: # # :type :: :paragraph # :paragraph :: String (The translation target message itself.) # :line_no :: Integer (The line number of the :paragraph is started.) # # The above content may be added in the future. def extract_messages parse do |part| case part[:type] when :empty_line # ignore when :paragraph yield(part) end end end # Translates raw text into +locale+. def translate(locale) translated_text = '' parse do |part| case part[:type] when :paragraph translated_text += locale.translate(part[:paragraph]) when :empty_line translated_text += part[:line] else raise "should not reach here: unexpected type: #{type}" end end translated_text end private def parse(&block) paragraph = '' paragraph_start_line = 0 line_no = 0 each_line(@raw) do |line| line_no += 1 case line when /\A\s*\z/ if paragraph.empty? emit_empty_line_event(line, line_no, &block) else paragraph += line emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) paragraph = '' end else paragraph_start_line = line_no if paragraph.empty? paragraph += line end end unless paragraph.empty? emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) end end def each_line(raw, &block) case raw when RDoc::Comment raw.text.each_line(&block) when Array raw.each do |comment, location| each_line(comment, &block) end else raw.each_line(&block) end end def emit_empty_line_event(line, line_no) part = { :type => :empty_line, :line => line, :line_no => line_no, } yield(part) end def emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) paragraph_part = { :type => :paragraph, :line_no => paragraph_start_line, } match_data = /(\s*)\z/.match(paragraph) if match_data paragraph_part[:paragraph] = match_data.pre_match yield(paragraph_part) emit_empty_line_event(match_data[1], line_no, &block) else paragraph_part[:paragraph] = paragraph yield(paragraph_part) end end end PK ]>"gems/rdoc-6.2.1.1/lib/rdoc/text.rbnu[# frozen_string_literal: true ## # For RDoc::Text#to_html require 'strscan' ## # Methods for manipulating comment text module RDoc::Text attr_accessor :language ## # Maps markup formats to classes that can parse them. If the format is # unknown, "rdoc" format is used. MARKUP_FORMAT = { 'markdown' => RDoc::Markdown, 'rdoc' => RDoc::Markup, 'rd' => RDoc::RD, 'tomdoc' => RDoc::TomDoc, } MARKUP_FORMAT.default = RDoc::Markup ## # Maps an encoding to a Hash of characters properly transcoded for that # encoding. # # See also encode_fallback. TO_HTML_CHARACTERS = Hash.new do |h, encoding| h[encoding] = { :close_dquote => encode_fallback('”', encoding, '"'), :close_squote => encode_fallback('’', encoding, '\''), :copyright => encode_fallback('©', encoding, '(c)'), :ellipsis => encode_fallback('…', encoding, '...'), :em_dash => encode_fallback('—', encoding, '---'), :en_dash => encode_fallback('–', encoding, '--'), :open_dquote => encode_fallback('“', encoding, '"'), :open_squote => encode_fallback('‘', encoding, '\''), :trademark => encode_fallback('®', encoding, '(r)'), } end ## # Transcodes +character+ to +encoding+ with a +fallback+ character. def self.encode_fallback character, encoding, fallback character.encode(encoding, :fallback => { character => fallback }, :undef => :replace, :replace => fallback) end ## # Expands tab characters in +text+ to eight spaces def expand_tabs text expanded = [] text.each_line do |line| nil while line.gsub!(/(?:\G|\r)((?:.{8})*?)([^\t\r\n]{0,7})\t/) do r = "#{$1}#{$2}#{' ' * (8 - $2.size)}" r = RDoc::Encoding.change_encoding r, text.encoding r end expanded << line end expanded.join end ## # Flush +text+ left based on the shortest line def flush_left text indent = 9999 text.each_line do |line| line_indent = line =~ /\S/ || 9999 indent = line_indent if indent > line_indent end empty = '' empty = RDoc::Encoding.change_encoding empty, text.encoding text.gsub(/^ {0,#{indent}}/, empty) end ## # Convert a string in markup format into HTML. # # Requires the including class to implement #formatter def markup text if @store.rdoc.options locale = @store.rdoc.options.locale else locale = nil end if locale i18n_text = RDoc::I18n::Text.new(text) text = i18n_text.translate(locale) end parse(text).accept formatter end ## # Strips hashes, expands tabs then flushes +text+ to the left def normalize_comment text return text if text.empty? case language when :ruby text = strip_hashes text when :c text = strip_stars text end text = expand_tabs text text = flush_left text text = strip_newlines text text end ## # Normalizes +text+ then builds a RDoc::Markup::Document from it def parse text, format = 'rdoc' return text if RDoc::Markup::Document === text return text.parse if RDoc::Comment === text text = normalize_comment text # TODO remove, should not be necessary return RDoc::Markup::Document.new if text =~ /\A\n*\z/ MARKUP_FORMAT[format].parse text end ## # The first +limit+ characters of +text+ as HTML def snippet text, limit = 100 document = parse text RDoc::Markup::ToHtmlSnippet.new(options, limit).convert document end ## # Strips leading # characters from +text+ def strip_hashes text return text if text =~ /^(?>\s*)[^\#]/ empty = '' empty = RDoc::Encoding.change_encoding empty, text.encoding text.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }.gsub(/^\s+$/, empty) end ## # Strips leading and trailing \n characters from +text+ def strip_newlines text text.gsub(/\A\n*(.*?)\n*\z/m) do $1 end # block preserves String encoding end ## # Strips /* */ style comments def strip_stars text return text unless text =~ %r%/\*.*\*/%m encoding = text.encoding text = text.gsub %r%Document-method:\s+[\w:.#=!?|^&<>~+\-/*\%@`\[\]]+%, '' space = ' ' space = RDoc::Encoding.change_encoding space, encoding if encoding text.sub! %r%/\*+% do space * $&.length end text.sub! %r%\*+/% do space * $&.length end text.gsub! %r%^[ \t]*\*%m do space * $&.length end empty = '' empty = RDoc::Encoding.change_encoding empty, encoding if encoding text.gsub(/^\s+$/, empty) end ## # Converts ampersand, dashes, ellipsis, quotes, copyright and registered # trademark symbols in +text+ to properly encoded characters. def to_html text html = (''.encode text.encoding).dup encoded = RDoc::Text::TO_HTML_CHARACTERS[text.encoding] s = StringScanner.new text insquotes = false indquotes = false after_word = nil until s.eos? do case when s.scan(/<(tt|code)>.*?<\/\1>/) then # skip contents of tt html << s.matched.gsub('\\\\', '\\') when s.scan(/<(tt|code)>.*?/) then warn "mismatched <#{s[1]}> tag" # TODO signal file/line html << s.matched when s.scan(/<[^>]+\/?s*>/) then # skip HTML tags html << s.matched when s.scan(/\\(\S)/) then # unhandled suppressed crossref html << s[1] after_word = nil when s.scan(/\.\.\.(\.?)/) then html << s[1] << encoded[:ellipsis] after_word = nil when s.scan(/\(c\)/) then html << encoded[:copyright] after_word = nil when s.scan(/\(r\)/) then html << encoded[:trademark] after_word = nil when s.scan(/---/) then html << encoded[:em_dash] after_word = nil when s.scan(/--/) then html << encoded[:en_dash] after_word = nil when s.scan(/"|"/) then html << encoded[indquotes ? :close_dquote : :open_dquote] indquotes = !indquotes after_word = nil when s.scan(/``/) then # backtick double quote html << encoded[:open_dquote] after_word = nil when s.scan(/''/) then # tick double quote html << encoded[:close_dquote] after_word = nil when s.scan(/'/) then # single quote if insquotes html << encoded[:close_squote] insquotes = false elsif after_word # Mary's dog, my parents' house: do not start paired quotes html << encoded[:close_squote] else html << encoded[:open_squote] insquotes = true end after_word = nil else # advance to the next potentially significant character match = s.scan(/.+?(?=[<\\.("'`&-])/) #" if match then html << match after_word = match =~ /\w$/ else html << s.rest break end end end html end ## # Wraps +txt+ to +line_len+ def wrap(txt, line_len = 76) res = [] sp = 0 ep = txt.length while sp < ep # scan back for a space p = sp + line_len - 1 if p >= ep p = ep else while p > sp and txt[p] != ?\s p -= 1 end if p <= sp p = sp + line_len while p < ep and txt[p] != ?\s p += 1 end end end res << txt[sp...p] << "\n" sp = p sp += 1 while sp < ep and txt[sp] == ?\s end res.join.strip end end PK ]at))#gems/rdoc-6.2.1.1/lib/rdoc/stats.rbnu[# frozen_string_literal: true ## # RDoc statistics collector which prints a summary and report of a project's # documentation totals. class RDoc::Stats include RDoc::Text ## # Output level for the coverage report attr_reader :coverage_level ## # Count of files parsed during parsing attr_reader :files_so_far ## # Total number of files found attr_reader :num_files ## # Creates a new Stats that will have +num_files+. +verbosity+ defaults to 1 # which will create an RDoc::Stats::Normal outputter. def initialize store, num_files, verbosity = 1 @num_files = num_files @store = store @coverage_level = 0 @doc_items = nil @files_so_far = 0 @fully_documented = false @num_params = 0 @percent_doc = nil @start = Time.now @undoc_params = 0 @display = case verbosity when 0 then Quiet.new num_files when 1 then Normal.new num_files else Verbose.new num_files end end ## # Records the parsing of an alias +as+. def add_alias as @display.print_alias as end ## # Records the parsing of an attribute +attribute+ def add_attribute attribute @display.print_attribute attribute end ## # Records the parsing of a class +klass+ def add_class klass @display.print_class klass end ## # Records the parsing of +constant+ def add_constant constant @display.print_constant constant end ## # Records the parsing of +file+ def add_file(file) @files_so_far += 1 @display.print_file @files_so_far, file end ## # Records the parsing of +method+ def add_method(method) @display.print_method method end ## # Records the parsing of a module +mod+ def add_module(mod) @display.print_module mod end ## # Call this to mark the beginning of parsing for display purposes def begin_adding @display.begin_adding end ## # Calculates documentation totals and percentages for classes, modules, # constants, attributes and methods. def calculate return if @doc_items ucm = @store.unique_classes_and_modules classes = @store.unique_classes.reject { |cm| cm.full_name == 'Object' } constants = [] ucm.each { |cm| constants.concat cm.constants } methods = [] ucm.each { |cm| methods.concat cm.method_list } attributes = [] ucm.each { |cm| attributes.concat cm.attributes } @num_attributes, @undoc_attributes = doc_stats attributes @num_classes, @undoc_classes = doc_stats classes @num_constants, @undoc_constants = doc_stats constants @num_methods, @undoc_methods = doc_stats methods @num_modules, @undoc_modules = doc_stats @store.unique_modules @num_items = @num_attributes + @num_classes + @num_constants + @num_methods + @num_modules + @num_params @undoc_items = @undoc_attributes + @undoc_classes + @undoc_constants + @undoc_methods + @undoc_modules + @undoc_params @doc_items = @num_items - @undoc_items end ## # Sets coverage report level. Accepted values are: # # false or nil:: No report # 0:: Classes, modules, constants, attributes, methods # 1:: Level 0 + method parameters def coverage_level= level level = -1 unless level @coverage_level = level end ## # Returns the length and number of undocumented items in +collection+. def doc_stats collection visible = collection.select { |item| item.display? } [visible.length, visible.count { |item| not item.documented? }] end ## # Call this to mark the end of parsing for display purposes def done_adding @display.done_adding end ## # The documentation status of this project. +true+ when 100%, +false+ when # less than 100% and +nil+ when unknown. # # Set by calling #calculate def fully_documented? @fully_documented end ## # A report that says you did a great job! def great_job report = RDoc::Markup::Document.new report << RDoc::Markup::Paragraph.new('100% documentation!') report << RDoc::Markup::Paragraph.new('Great Job!') report end ## # Calculates the percentage of items documented. def percent_doc return @percent_doc if @percent_doc @fully_documented = (@num_items - @doc_items) == 0 @percent_doc = @doc_items.to_f / @num_items * 100 if @num_items.nonzero? @percent_doc ||= 0 @percent_doc end ## # Returns a report on which items are not documented def report if @coverage_level > 0 then extend RDoc::Text end if @coverage_level.zero? then calculate return great_job if @num_items == @doc_items end ucm = @store.unique_classes_and_modules report = RDoc::Markup::Document.new report << RDoc::Markup::Paragraph.new('The following items are not documented:') report << RDoc::Markup::BlankLine.new ucm.sort.each do |cm| body = report_class_module(cm) { [ report_constants(cm), report_attributes(cm), report_methods(cm), ].compact } report << body if body end if @coverage_level > 0 then calculate return great_job if @num_items == @doc_items end report end ## # Returns a report on undocumented attributes in ClassModule +cm+ def report_attributes cm return if cm.attributes.empty? report = [] cm.each_attribute do |attr| next if attr.documented? line = attr.line ? ":#{attr.line}" : nil report << " #{attr.definition} :#{attr.name} # in file #{attr.file.full_name}#{line}\n" report << "\n" end report end ## # Returns a report on undocumented items in ClassModule +cm+ def report_class_module cm return if cm.fully_documented? and @coverage_level.zero? return unless cm.display? report = RDoc::Markup::Document.new if cm.in_files.empty? then report << RDoc::Markup::Paragraph.new("#{cm.definition} is referenced but empty.") report << RDoc::Markup::Paragraph.new("It probably came from another project. I'm sorry I'm holding it against you.") return report elsif cm.documented? then documented = true klass = RDoc::Markup::Verbatim.new("#{cm.definition} # is documented\n") else report << RDoc::Markup::Paragraph.new('In files:') list = RDoc::Markup::List.new :BULLET cm.in_files.each do |file| para = RDoc::Markup::Paragraph.new file.full_name list << RDoc::Markup::ListItem.new(nil, para) end report << list report << RDoc::Markup::BlankLine.new klass = RDoc::Markup::Verbatim.new("#{cm.definition}\n") end klass << "\n" body = yield.flatten # HACK remove #flatten if body.empty? then return if documented klass.parts.pop else klass.parts.concat body end klass << "end\n" report << klass report end ## # Returns a report on undocumented constants in ClassModule +cm+ def report_constants cm return if cm.constants.empty? report = [] cm.each_constant do |constant| # TODO constant aliases are listed in the summary but not reported # figure out what to do here next if constant.documented? || constant.is_alias_for line = constant.line ? ":#{constant.line}" : line report << " # in file #{constant.file.full_name}#{line}\n" report << " #{constant.name} = nil\n" report << "\n" end report end ## # Returns a report on undocumented methods in ClassModule +cm+ def report_methods cm return if cm.method_list.empty? report = [] cm.each_method do |method| next if method.documented? and @coverage_level.zero? if @coverage_level > 0 then params, undoc = undoc_params method @num_params += params unless undoc.empty? then @undoc_params += undoc.length undoc = undoc.map do |param| "+#{param}+" end param_report = " # #{undoc.join ', '} is not documented\n" end end next if method.documented? and not param_report line = method.line ? ":#{method.line}" : nil scope = method.singleton ? 'self.' : nil report << " # in file #{method.file.full_name}#{line}\n" report << param_report if param_report report << " def #{scope}#{method.name}#{method.params}; end\n" report << "\n" end report end ## # Returns a summary of the collected statistics. def summary calculate num_width = [@num_files, @num_items].max.to_s.length undoc_width = [ @undoc_attributes, @undoc_classes, @undoc_constants, @undoc_items, @undoc_methods, @undoc_modules, @undoc_params, ].max.to_s.length report = RDoc::Markup::Verbatim.new report << "Files: %*d\n" % [num_width, @num_files] report << "\n" report << "Classes: %*d (%*d undocumented)\n" % [ num_width, @num_classes, undoc_width, @undoc_classes] report << "Modules: %*d (%*d undocumented)\n" % [ num_width, @num_modules, undoc_width, @undoc_modules] report << "Constants: %*d (%*d undocumented)\n" % [ num_width, @num_constants, undoc_width, @undoc_constants] report << "Attributes: %*d (%*d undocumented)\n" % [ num_width, @num_attributes, undoc_width, @undoc_attributes] report << "Methods: %*d (%*d undocumented)\n" % [ num_width, @num_methods, undoc_width, @undoc_methods] report << "Parameters: %*d (%*d undocumented)\n" % [ num_width, @num_params, undoc_width, @undoc_params] if @coverage_level > 0 report << "\n" report << "Total: %*d (%*d undocumented)\n" % [ num_width, @num_items, undoc_width, @undoc_items] report << "%6.2f%% documented\n" % percent_doc report << "\n" report << "Elapsed: %0.1fs\n" % (Time.now - @start) RDoc::Markup::Document.new report end ## # Determines which parameters in +method+ were not documented. Returns a # total parameter count and an Array of undocumented methods. def undoc_params method @formatter ||= RDoc::Markup::ToTtOnly.new params = method.param_list params = params.map { |param| param.gsub(/^\*\*?/, '') } return 0, [] if params.empty? document = parse method.comment tts = document.accept @formatter undoc = params - tts [params.length, undoc] end autoload :Quiet, 'rdoc/stats/quiet' autoload :Normal, 'rdoc/stats/normal' autoload :Verbose, 'rdoc/stats/verbose' end PK ] )gems/rdoc-6.2.1.1/lib/rdoc/parser/ruby.rbnu[# frozen_string_literal: true ## # This file contains stuff stolen outright from: # # rtags.rb - # ruby-lex.rb - ruby lexcal analyzer # ruby-token.rb - ruby tokens # by Keiju ISHITSUKA (Nippon Rational Inc.) # ## # Extracts code elements from a source file returning a TopLevel object # containing the constituent file elements. # # This file is based on rtags # # RubyParser understands how to document: # * classes # * modules # * methods # * constants # * aliases # * private, public, protected # * private_class_function, public_class_function # * private_constant, public_constant # * module_function # * attr, attr_reader, attr_writer, attr_accessor # * extra accessors given on the command line # * metaprogrammed methods # * require # * include # # == Method Arguments # #-- # NOTE: I don't think this works, needs tests, remove the paragraph following # this block when known to work # # The parser extracts the arguments from the method definition. You can # override this with a custom argument definition using the :args: directive: # # ## # # This method tries over and over until it is tired # # def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try # puts thing_to_try # go_go_go thing_to_try, tries - 1 # end # # If you have a more-complex set of overrides you can use the :call-seq: # directive: #++ # # The parser extracts the arguments from the method definition. You can # override this with a custom argument definition using the :call-seq: # directive: # # ## # # This method can be called with a range or an offset and length # # # # :call-seq: # # my_method(Range) # # my_method(offset, length) # # def my_method(*args) # end # # The parser extracts +yield+ expressions from method bodies to gather the # yielded argument names. If your method manually calls a block instead of # yielding or you want to override the discovered argument names use # the :yields: directive: # # ## # # My method is awesome # # def my_method(&block) # :yields: happy, times # block.call 1, 2 # end # # == Metaprogrammed Methods # # To pick up a metaprogrammed method, the parser looks for a comment starting # with '##' before an identifier: # # ## # # This is a meta-programmed method! # # add_my_method :meta_method, :arg1, :arg2 # # The parser looks at the token after the identifier to determine the name, in # this example, :meta_method. If a name cannot be found, a warning is printed # and 'unknown is used. # # You can force the name of a method using the :method: directive: # # ## # # :method: some_method! # # By default, meta-methods are instance methods. To indicate that a method is # a singleton method instead use the :singleton-method: directive: # # ## # # :singleton-method: # # You can also use the :singleton-method: directive with a name: # # ## # # :singleton-method: some_method! # # You can define arguments for metaprogrammed methods via either the # :call-seq:, :arg: or :args: directives. # # Additionally you can mark a method as an attribute by # using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like # for :method:, the name is optional. # # ## # # :attr_reader: my_attr_name # # == Hidden methods and attributes # # You can provide documentation for methods that don't appear using # the :method:, :singleton-method: and :attr: directives: # # ## # # :attr_writer: ghost_writer # # There is an attribute here, but you can't see it! # # ## # # :method: ghost_method # # There is a method here, but you can't see it! # # ## # # this is a comment for a regular method # # def regular_method() end # # Note that by default, the :method: directive will be ignored if there is a # standard rdocable item following it. require 'ripper' require_relative 'ripper_state_lex' class RDoc::Parser::Ruby < RDoc::Parser parse_files_matching(/\.rbw?$/) include RDoc::TokenStream include RDoc::Parser::RubyTools ## # RDoc::NormalClass type NORMAL = "::" ## # RDoc::SingleClass type SINGLE = "<<" ## # Creates a new Ruby parser. def initialize(top_level, file_name, content, options, stats) super if /\t/ =~ content then tab_width = @options.tab_width content = content.split(/\n/).map do |line| 1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width) } && $~ line end.join("\n") end @size = 0 @token_listeners = nil content = RDoc::Encoding.remove_magic_comment content @scanner = RDoc::Parser::RipperStateLex.parse(content) @content = content @scanner_point = 0 @prev_seek = nil @markup = @options.markup @track_visibility = :nodoc != @options.visibility @encoding = @options.encoding reset end def tk_nl?(tk) :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind] end ## # Retrieves the read token stream and replaces +pattern+ with +replacement+ # using gsub. If the result is only a ";" returns an empty string. def get_tkread_clean pattern, replacement # :nodoc: read = get_tkread.gsub(pattern, replacement).strip return '' if read == ';' read end ## # Extracts the visibility information for the visibility token +tk+ # and +single+ class type identifier. # # Returns the visibility type (a string), the visibility (a symbol) and # +singleton+ if the methods following should be converted to singleton # methods. def get_visibility_information tk, single # :nodoc: vis_type = tk[:text] singleton = single == SINGLE vis = case vis_type when 'private' then :private when 'protected' then :protected when 'public' then :public when 'private_class_method' then singleton = true :private when 'public_class_method' then singleton = true :public when 'module_function' then singleton = true :public else raise RDoc::Error, "Invalid visibility: #{tk.name}" end return vis_type, vis, singleton end ## # Look for the first comment in a file that isn't a shebang line. def collect_first_comment skip_tkspace comment = ''.dup comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding first_line = true first_comment_tk_kind = nil line_no = nil tk = get_tk while tk && (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) comment_body = retrieve_comment_body(tk) if first_line and comment_body =~ /\A#!/ then skip_tkspace tk = get_tk elsif first_line and comment_body =~ /\A#\s*-\*-/ then first_line = false skip_tkspace tk = get_tk else break if first_comment_tk_kind and not first_comment_tk_kind === tk[:kind] first_comment_tk_kind = tk[:kind] line_no = tk[:line_no] if first_line first_line = false comment << comment_body tk = get_tk if :on_nl === tk then skip_tkspace_without_nl tk = get_tk end end end unget_tk tk new_comment comment, line_no end ## # Consumes trailing whitespace from the token stream def consume_trailing_spaces # :nodoc: skip_tkspace_without_nl end ## # Creates a new attribute in +container+ with +name+. def create_attr container, single, name, rw, comment # :nodoc: att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE record_location att container.add_attribute att @stats.add_attribute att att end ## # Creates a module alias in +container+ at +rhs_name+ (or at the top-level # for "::") with the name from +constant+. def create_module_alias container, constant, rhs_name # :nodoc: mod = if rhs_name =~ /^::/ then @store.find_class_or_module rhs_name else container.find_module_named rhs_name end container.add_module_alias mod, rhs_name, constant, @top_level end ## # Aborts with +msg+ def error(msg) msg = make_message msg abort msg end ## # Looks for a true or false token. def get_bool skip_tkspace tk = get_tk if :on_kw == tk[:kind] && 'true' == tk[:text] true elsif :on_kw == tk[:kind] && ('false' == tk[:text] || 'nil' == tk[:text]) false else unget_tk tk true end end ## # Look for the name of a class of module (optionally with a leading :: or # with :: separated named) and return the ultimate name, the associated # container, and the given name (with the ::). def get_class_or_module container, ignore_constants = false skip_tkspace name_t = get_tk given_name = ''.dup # class ::A -> A is in the top level if :on_op == name_t[:kind] and '::' == name_t[:text] then # bug name_t = get_tk container = @top_level given_name << '::' end skip_tkspace_without_nl given_name << name_t[:text] is_self = name_t[:kind] == :on_op && name_t[:text] == '<<' new_modules = [] while !is_self && (tk = peek_tk) and :on_op == tk[:kind] and '::' == tk[:text] do prev_container = container container = container.find_module_named name_t[:text] container ||= if ignore_constants then c = RDoc::NormalModule.new name_t[:text] c.store = @store new_modules << [prev_container, c] c else c = prev_container.add_module RDoc::NormalModule, name_t[:text] c.ignore unless prev_container.document_children @top_level.add_to_classes_or_modules c c end record_location container get_tk skip_tkspace if :on_lparen == peek_tk[:kind] # ProcObjectInConstant::() parse_method_or_yield_parameters break end name_t = get_tk unless :on_const == name_t[:kind] || :on_ident == name_t[:kind] raise RDoc::Error, "Invalid class or module definition: #{given_name}" end if prev_container == container and !ignore_constants given_name = name_t[:text] else given_name << '::' + name_t[:text] end end skip_tkspace_without_nl return [container, name_t, given_name, new_modules] end ## # Return a superclass, which can be either a constant of an expression def get_class_specification tk = peek_tk if tk.nil? return '' elsif :on_kw == tk[:kind] && 'self' == tk[:text] return 'self' elsif :on_gvar == tk[:kind] return '' end res = get_constant skip_tkspace_without_nl get_tkread # empty out read buffer tk = get_tk return res unless tk case tk[:kind] when :on_nl, :on_comment, :on_embdoc, :on_semicolon then unget_tk(tk) return res end res += parse_call_parameters(tk) res end ## # Parse a constant, which might be qualified by one or more class or module # names def get_constant res = "" skip_tkspace_without_nl tk = get_tk while tk && ((:on_op == tk[:kind] && '::' == tk[:text]) || :on_const == tk[:kind]) do res += tk[:text] tk = get_tk end unget_tk(tk) res end ## # Get an included module that may be surrounded by parens def get_included_module_with_optional_parens skip_tkspace_without_nl get_tkread tk = get_tk end_token = get_end_token tk return '' unless end_token nest = 0 continue = false only_constant = true while tk != nil do is_element_of_constant = false case tk[:kind] when :on_semicolon then break if nest == 0 when :on_lbracket then nest += 1 when :on_rbracket then nest -= 1 when :on_lbrace then nest += 1 when :on_rbrace then nest -= 1 if nest <= 0 # we might have a.each { |i| yield i } unget_tk(tk) if nest < 0 break end when :on_lparen then nest += 1 when end_token[:kind] then if end_token[:kind] == :on_rparen nest -= 1 break if nest <= 0 else break if nest <= 0 end when :on_rparen then nest -= 1 when :on_comment, :on_embdoc then @read.pop if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and (!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then break if !continue and nest <= 0 end when :on_comma then continue = true when :on_ident then continue = false if continue when :on_kw then case tk[:text] when 'def', 'do', 'case', 'for', 'begin', 'class', 'module' nest += 1 when 'if', 'unless', 'while', 'until', 'rescue' # postfix if/unless/while/until/rescue must be EXPR_LABEL nest += 1 unless (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0 when 'end' nest -= 1 break if nest == 0 end when :on_const then is_element_of_constant = true when :on_op then is_element_of_constant = true if '::' == tk[:text] end only_constant = false unless is_element_of_constant tk = get_tk end if only_constant get_tkread_clean(/\s+/, ' ') else '' end end ## # Little hack going on here. In the statement: # # f = 2*(1+yield) # # We see the RPAREN as the next token, so we need to exit early. This still # won't catch all cases (such as "a = yield + 1" def get_end_token tk # :nodoc: case tk[:kind] when :on_lparen token = RDoc::Parser::RipperStateLex::Token.new token[:kind] = :on_rparen token[:text] = ')' token when :on_rparen nil else token = RDoc::Parser::RipperStateLex::Token.new token[:kind] = :on_nl token[:text] = "\n" token end end ## # Retrieves the method container for a singleton method. def get_method_container container, name_t # :nodoc: prev_container = container container = container.find_module_named(name_t[:text]) unless container then constant = prev_container.constants.find do |const| const.name == name_t[:text] end if constant then parse_method_dummy prev_container return end end unless container then # TODO seems broken, should starting at Object in @store obj = name_t[:text].split("::").inject(Object) do |state, item| state.const_get(item) end rescue nil type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule unless [Class, Module].include?(obj.class) then warn("Couldn't find #{name_t[:text]}. Assuming it's a module") end if type == RDoc::NormalClass then sclass = obj.superclass ? obj.superclass.name : nil container = prev_container.add_class type, name_t[:text], sclass else container = prev_container.add_module type, name_t[:text] end record_location container end container end ## # Extracts a name or symbol from the token stream. def get_symbol_or_name tk = get_tk case tk[:kind] when :on_symbol then text = tk[:text].sub(/^:/, '') next_tk = peek_tk if next_tk && :on_op == next_tk[:kind] && '=' == next_tk[:text] then get_tk text << '=' end text when :on_ident, :on_const, :on_gvar, :on_cvar, :on_ivar, :on_op, :on_kw then tk[:text] when :on_tstring, :on_dstring then tk[:text][1..-2] else raise RDoc::Error, "Name or symbol expected (got #{tk})" end end ## # Marks containers between +container+ and +ancestor+ as ignored def suppress_parents container, ancestor # :nodoc: while container and container != ancestor do container.suppress unless container.documented? container = container.parent end end ## # Look for directives in a normal comment block: # # # :stopdoc: # # Don't display comment from this point forward # # This routine modifies its +comment+ parameter. def look_for_directives_in container, comment @preprocess.handle comment, container do |directive, param| case directive when 'method', 'singleton-method', 'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then false # handled elsewhere when 'section' then break unless container.kind_of?(RDoc::Context) container.set_current_section param, comment.dup comment.text = '' break end end comment.remove_private end ## # Adds useful info about the parser to +message+ def make_message message prefix = "#{@file_name}:".dup tk = peek_tk prefix << "#{tk[:line_no]}:#{tk[:char_no]}:" if tk "#{prefix} #{message}" end ## # Creates a comment with the correct format def new_comment comment, line_no = nil c = RDoc::Comment.new comment, @top_level, :ruby c.line = line_no c.format = @markup c end ## # Creates an RDoc::Attr for the name following +tk+, setting the comment to # +comment+. def parse_attr(context, single, tk, comment) line_no = tk[:line_no] args = parse_symbol_arg 1 if args.size > 0 then name = args[0] rw = "R" skip_tkspace_without_nl tk = get_tk if :on_comma == tk[:kind] then rw = "RW" if get_bool else unget_tk tk end att = create_attr context, single, name, rw, comment att.line = line_no read_documentation_modifiers att, RDoc::ATTR_MODIFIERS else warn "'attr' ignored - looks like a variable" end end ## # Creates an RDoc::Attr for each attribute listed after +tk+, setting the # comment for each to +comment+. def parse_attr_accessor(context, single, tk, comment) line_no = tk[:line_no] args = parse_symbol_arg rw = "?" tmp = RDoc::CodeObject.new read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS # TODO In most other places we let the context keep track of document_self # and add found items appropriately but here we do not. I'm not sure why. return if @track_visibility and not tmp.document_self case tk[:text] when "attr_reader" then rw = "R" when "attr_writer" then rw = "W" when "attr_accessor" then rw = "RW" else rw = '?' end for name in args att = create_attr context, single, name, rw, comment att.line = line_no end end ## # Parses an +alias+ in +context+ with +comment+ def parse_alias(context, single, tk, comment) line_no = tk[:line_no] skip_tkspace if :on_lparen === peek_tk[:kind] then get_tk skip_tkspace end new_name = get_symbol_or_name skip_tkspace if :on_comma === peek_tk[:kind] then get_tk skip_tkspace end begin old_name = get_symbol_or_name rescue RDoc::Error return end al = RDoc::Alias.new(get_tkread, old_name, new_name, comment, single == SINGLE) record_location al al.line = line_no read_documentation_modifiers al, RDoc::ATTR_MODIFIERS context.add_alias al @stats.add_alias al al end ## # Extracts call parameters from the token stream. def parse_call_parameters(tk) end_token = case tk[:kind] when :on_lparen :on_rparen when :on_rparen return "" else :on_nl end nest = 0 loop do break if tk.nil? case tk[:kind] when :on_semicolon break when :on_lparen nest += 1 when end_token if end_token == :on_rparen nest -= 1 break if RDoc::Parser::RipperStateLex.end?(tk) and nest <= 0 else break if RDoc::Parser::RipperStateLex.end?(tk) end when :on_comment, :on_embdoc unget_tk(tk) break when :on_op if tk[:text] =~ /^(.{1,2})?=$/ unget_tk(tk) break end end tk = get_tk end get_tkread_clean "\n", " " end ## # Parses a class in +context+ with +comment+ def parse_class container, single, tk, comment line_no = tk[:line_no] declaration_context = container container, name_t, given_name, = get_class_or_module container if name_t[:kind] == :on_const cls = parse_class_regular container, declaration_context, single, name_t, given_name, comment elsif name_t[:kind] == :on_op && name_t[:text] == '<<' case name = get_class_specification when 'self', container.name read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS parse_statements container, SINGLE return # don't update line else cls = parse_class_singleton container, name, comment end else warn "Expected class name or '<<'. Got #{name_t[:kind]}: #{name_t[:text].inspect}" return end cls.line = line_no # after end modifiers read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS cls end ## # Parses and creates a regular class def parse_class_regular container, declaration_context, single, # :nodoc: name_t, given_name, comment superclass = '::Object' if given_name =~ /^::/ then declaration_context = @top_level given_name = $' end tk = peek_tk if tk[:kind] == :on_op && tk[:text] == '<' then get_tk skip_tkspace superclass = get_class_specification superclass = '(unknown)' if superclass.empty? end cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass cls = declaration_context.add_class cls_type, given_name, superclass cls.ignore unless container.document_children read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS record_location cls cls.add_comment comment, @top_level @top_level.add_to_classes_or_modules cls @stats.add_class cls suppress_parents container, declaration_context unless cls.document_self parse_statements cls cls end ## # Parses a singleton class in +container+ with the given +name+ and # +comment+. def parse_class_singleton container, name, comment # :nodoc: other = @store.find_class_named name unless other then if name =~ /^::/ then name = $' container = @top_level end other = container.add_module RDoc::NormalModule, name record_location other # class << $gvar other.ignore if name.empty? other.add_comment comment, @top_level end # notify :nodoc: all if not a constant-named class/module # (and remove any comment) unless name =~ /\A(::)?[A-Z]/ then other.document_self = nil other.document_children = false other.clear_comment end @top_level.add_to_classes_or_modules other @stats.add_class other read_documentation_modifiers other, RDoc::CLASS_MODIFIERS parse_statements(other, SINGLE) other end ## # Parses a constant in +context+ with +comment+. If +ignore_constants+ is # true, no found constants will be added to RDoc. def parse_constant container, tk, comment, ignore_constants = false line_no = tk[:line_no] name = tk[:text] skip_tkspace_without_nl return unless name =~ /^\w+$/ new_modules = [] if :on_op == peek_tk[:kind] && '::' == peek_tk[:text] then unget_tk tk container, name_t, _, new_modules = get_class_or_module container, true name = name_t[:text] end is_array_or_hash = false if peek_tk && :on_lbracket == peek_tk[:kind] get_tk nest = 1 while bracket_tk = get_tk case bracket_tk[:kind] when :on_lbracket nest += 1 when :on_rbracket nest -= 1 break if nest == 0 end end skip_tkspace_without_nl is_array_or_hash = true end unless peek_tk && :on_op == peek_tk[:kind] && '=' == peek_tk[:text] then return false end get_tk unless ignore_constants new_modules.each do |prev_c, new_module| prev_c.add_module_by_normal_module new_module new_module.ignore unless prev_c.document_children @top_level.add_to_classes_or_modules new_module end end value = '' con = RDoc::Constant.new name, value, comment body = parse_constant_body container, con, is_array_or_hash return unless body con.value = body record_location con con.line = line_no read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS return if is_array_or_hash @stats.add_constant con container.add_constant con true end def parse_constant_body container, constant, is_array_or_hash # :nodoc: nest = 0 rhs_name = ''.dup get_tkread tk = get_tk body = nil loop do break if tk.nil? if :on_semicolon == tk[:kind] then break if nest <= 0 elsif [:on_tlambeg, :on_lparen, :on_lbrace, :on_lbracket].include?(tk[:kind]) then nest += 1 elsif (:on_kw == tk[:kind] && 'def' == tk[:text]) then nest += 1 elsif (:on_kw == tk[:kind] && %w{do if unless case begin}.include?(tk[:text])) then if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0 nest += 1 end elsif [:on_rparen, :on_rbrace, :on_rbracket].include?(tk[:kind]) || (:on_kw == tk[:kind] && 'end' == tk[:text]) then nest -= 1 elsif (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) then unget_tk tk if nest <= 0 and RDoc::Parser::RipperStateLex.end?(tk) then body = get_tkread_clean(/^[ \t]+/, '') read_documentation_modifiers constant, RDoc::CONSTANT_MODIFIERS break else read_documentation_modifiers constant, RDoc::CONSTANT_MODIFIERS end elsif :on_const == tk[:kind] then rhs_name << tk[:text] next_tk = peek_tk if nest <= 0 and (next_tk.nil? || :on_nl == next_tk[:kind]) then create_module_alias container, constant, rhs_name unless is_array_or_hash break end elsif :on_nl == tk[:kind] then if nest <= 0 and RDoc::Parser::RipperStateLex.end?(tk) then unget_tk tk break end elsif :on_op == tk[:kind] && '::' == tk[:text] rhs_name << '::' end tk = get_tk end body ? body : get_tkread_clean(/^[ \t]+/, '') end ## # Generates an RDoc::Method or RDoc::Attr from +comment+ by looking for # :method: or :attr: directives in +comment+. def parse_comment container, tk, comment return parse_comment_tomdoc container, tk, comment if @markup == 'tomdoc' column = tk[:char_no] line_no = comment.line.nil? ? tk[:line_no] : comment.line comment.text = comment.text.sub(/(^# +:?)(singleton-)(method:)/, '\1\3') singleton = !!$~ co = if (comment.text = comment.text.sub(/^# +:?method: *(\S*).*?\n/i, '')) && !!$~ then line_no += $`.count("\n") parse_comment_ghost container, comment.text, $1, column, line_no, comment elsif (comment.text = comment.text.sub(/# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '')) && !!$~ then parse_comment_attr container, $1, $3, comment end if co then co.singleton = singleton co.line = line_no end true end ## # Parse a comment that is describing an attribute in +container+ with the # given +name+ and +comment+. def parse_comment_attr container, type, name, comment # :nodoc: return if name.empty? rw = case type when 'attr_reader' then 'R' when 'attr_writer' then 'W' else 'RW' end create_attr container, NORMAL, name, rw, comment end def parse_comment_ghost container, text, name, column, line_no, # :nodoc: comment name = nil if name.empty? meth = RDoc::GhostMethod.new get_tkread, name record_location meth meth.start_collecting_tokens indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column) position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment) position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}" newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n") meth.add_tokens [position_comment, newline, indent] meth.params = if text.sub!(/^#\s+:?args?:\s*(.*?)\s*$/i, '') then $1 else '' end comment.normalize comment.extract_call_seq meth return unless meth.name container.add_method meth meth.comment = comment @stats.add_method meth meth end ## # Creates an RDoc::Method on +container+ from +comment+ if there is a # Signature section in the comment def parse_comment_tomdoc container, tk, comment return unless signature = RDoc::TomDoc.signature(comment) column = tk[:char_no] line_no = tk[:line_no] name, = signature.split %r%[ \(]%, 2 meth = RDoc::GhostMethod.new get_tkread, name record_location meth meth.line = line_no meth.start_collecting_tokens indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column) position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment) position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}" newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n") meth.add_tokens [position_comment, newline, indent] meth.call_seq = signature comment.normalize return unless meth.name container.add_method meth meth.comment = comment @stats.add_method meth end ## # Parses an +include+ or +extend+, indicated by the +klass+ and adds it to # +container+ # with +comment+ def parse_extend_or_include klass, container, comment # :nodoc: loop do skip_tkspace_comment name = get_included_module_with_optional_parens unless name.empty? then obj = container.add klass, name, comment record_location obj end return if peek_tk.nil? || :on_comma != peek_tk[:kind] get_tk end end ## # Parses identifiers that can create new methods or change visibility. # # Returns true if the comment was not consumed. def parse_identifier container, single, tk, comment # :nodoc: case tk[:text] when 'private', 'protected', 'public', 'private_class_method', 'public_class_method', 'module_function' then parse_visibility container, single, tk return true when 'private_constant', 'public_constant' parse_constant_visibility container, single, tk return true when 'attr' then parse_attr container, single, tk, comment when /^attr_(reader|writer|accessor)$/ then parse_attr_accessor container, single, tk, comment when 'alias_method' then parse_alias container, single, tk, comment when 'require', 'include' then # ignore else if comment.text =~ /\A#\#$/ then case comment.text when /^# +:?attr(_reader|_writer|_accessor)?:/ then parse_meta_attr container, single, tk, comment else method = parse_meta_method container, single, tk, comment method.params = container.params if container.params method.block_params = container.block_params if container.block_params end end end false end ## # Parses a meta-programmed attribute and creates an RDoc::Attr. # # To create foo and bar attributes on class C with comment "My attributes": # # class C # # ## # # :attr: # # # # My attributes # # my_attr :foo, :bar # # end # # To create a foo attribute on class C with comment "My attribute": # # class C # # ## # # :attr: foo # # # # My attribute # # my_attr :foo, :bar # # end def parse_meta_attr(context, single, tk, comment) args = parse_symbol_arg rw = "?" # If nodoc is given, don't document any of them tmp = RDoc::CodeObject.new read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS regexp = /^# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i if regexp =~ comment.text then comment.text = comment.text.sub(regexp, '') rw = case $1 when 'attr_reader' then 'R' when 'attr_writer' then 'W' else 'RW' end name = $3 unless $3.empty? end if name then att = create_attr context, single, name, rw, comment else args.each do |attr_name| att = create_attr context, single, attr_name, rw, comment end end att end ## # Parses a meta-programmed method def parse_meta_method(container, single, tk, comment) column = tk[:char_no] line_no = tk[:line_no] start_collecting_tokens add_token tk add_token_listener self skip_tkspace_without_nl comment.text = comment.text.sub(/(^# +:?)(singleton-)(method:)/, '\1\3') singleton = !!$~ name = parse_meta_method_name comment, tk return unless name meth = RDoc::MetaMethod.new get_tkread, name record_location meth meth.line = line_no meth.singleton = singleton remove_token_listener self meth.start_collecting_tokens indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column) position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment) position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}" newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n") meth.add_tokens [position_comment, newline, indent] meth.add_tokens @token_stream parse_meta_method_params container, single, meth, tk, comment meth.comment = comment @stats.add_method meth meth end ## # Parses the name of a metaprogrammed method. +comment+ is used to # determine the name while +tk+ is used in an error message if the name # cannot be determined. def parse_meta_method_name comment, tk # :nodoc: if comment.text.sub!(/^# +:?method: *(\S*).*?\n/i, '') then return $1 unless $1.empty? end name_t = get_tk if :on_symbol == name_t[:kind] then name_t[:text][1..-1] elsif :on_tstring == name_t[:kind] then name_t[:text][1..-2] elsif :on_op == name_t[:kind] && '=' == name_t[:text] then # ignore remove_token_listener self nil else warn "unknown name token #{name_t.inspect} for meta-method '#{tk[:text]}'" 'unknown' end end ## # Parses the parameters and block for a meta-programmed method. def parse_meta_method_params container, single, meth, tk, comment # :nodoc: token_listener meth do meth.params = '' look_for_directives_in meth, comment comment.normalize comment.extract_call_seq meth container.add_method meth last_tk = tk while tk = get_tk do if :on_semicolon == tk[:kind] then break elsif :on_nl == tk[:kind] then break unless last_tk and :on_comma == last_tk[:kind] elsif :on_sp == tk[:kind] then # expression continues elsif :on_kw == tk[:kind] && 'do' == tk[:text] then parse_statements container, single, meth break else last_tk = tk end end end end ## # Parses a normal method defined by +def+ def parse_method(container, single, tk, comment) singleton = nil added_container = false name = nil column = tk[:char_no] line_no = tk[:line_no] start_collecting_tokens add_token tk token_listener self do prev_container = container name, container, singleton = parse_method_name container added_container = container != prev_container end return unless name meth = RDoc::AnyMethod.new get_tkread, name look_for_directives_in meth, comment meth.singleton = single == SINGLE ? true : singleton record_location meth meth.line = line_no meth.start_collecting_tokens indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column) token = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment) token[:text] = "# File #{@top_level.relative_name}, line #{line_no}" newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n") meth.add_tokens [token, newline, indent] meth.add_tokens @token_stream parse_method_params_and_body container, single, meth, added_container comment.normalize comment.extract_call_seq meth meth.comment = comment # after end modifiers read_documentation_modifiers meth, RDoc::METHOD_MODIFIERS @stats.add_method meth end ## # Parses the parameters and body of +meth+ def parse_method_params_and_body container, single, meth, added_container token_listener meth do parse_method_parameters meth if meth.document_self or not @track_visibility then container.add_method meth elsif added_container then container.document_self = false end # Having now read the method parameters and documentation modifiers, we # now know whether we have to rename #initialize to ::new if meth.name == "initialize" && !meth.singleton then if meth.dont_rename_initialize then meth.visibility = :protected else meth.singleton = true meth.name = "new" meth.visibility = :public end end parse_statements container, single, meth end end ## # Parses a method that needs to be ignored. def parse_method_dummy container dummy = RDoc::Context.new dummy.parent = container dummy.store = container.store skip_method dummy end ## # Parses the name of a method in +container+. # # Returns the method name, the container it is in (for def Foo.name) and if # it is a singleton or regular method. def parse_method_name container # :nodoc: skip_tkspace name_t = get_tk back_tk = skip_tkspace_without_nl singleton = false dot = get_tk if dot[:kind] == :on_period || (dot[:kind] == :on_op && dot[:text] == '::') then singleton = true name, container = parse_method_name_singleton container, name_t else unget_tk dot back_tk.reverse_each do |token| unget_tk token end name = parse_method_name_regular container, name_t end return name, container, singleton end ## # For the given +container+ and initial name token +name_t+ the method name # is parsed from the token stream for a regular method. def parse_method_name_regular container, name_t # :nodoc: if :on_op == name_t[:kind] && (%w{* & [] []= <<}.include?(name_t[:text])) then name_t[:text] else unless [:on_kw, :on_const, :on_ident].include?(name_t[:kind]) then warn "expected method name token, . or ::, got #{name_t.inspect}" skip_method container return end name_t[:text] end end ## # For the given +container+ and initial name token +name_t+ the method name # and the new +container+ (if necessary) are parsed from the token stream # for a singleton method. def parse_method_name_singleton container, name_t # :nodoc: skip_tkspace name_t2 = get_tk if (:on_kw == name_t[:kind] && 'self' == name_t[:text]) || (:on_op == name_t[:kind] && '%' == name_t[:text]) then # NOTE: work around '[' being consumed early if :on_lbracket == name_t2[:kind] get_tk name = '[]' else name = name_t2[:text] end elsif :on_const == name_t[:kind] then name = name_t2[:text] container = get_method_container container, name_t return unless container name elsif :on_ident == name_t[:kind] || :on_ivar == name_t[:kind] || :on_gvar == name_t[:kind] then parse_method_dummy container name = nil elsif (:on_kw == name_t[:kind]) && ('true' == name_t[:text] || 'false' == name_t[:text] || 'nil' == name_t[:text]) then klass_name = "#{name_t[:text].capitalize}Class" container = @store.find_class_named klass_name container ||= @top_level.add_class RDoc::NormalClass, klass_name name = name_t2[:text] else warn "unexpected method name token #{name_t.inspect}" # break skip_method container name = nil end return name, container end ## # Extracts +yield+ parameters from +method+ def parse_method_or_yield_parameters(method = nil, modifiers = RDoc::METHOD_MODIFIERS) skip_tkspace_without_nl tk = get_tk end_token = get_end_token tk return '' unless end_token nest = 0 continue = false while tk != nil do case tk[:kind] when :on_semicolon then break if nest == 0 when :on_lbracket then nest += 1 when :on_rbracket then nest -= 1 when :on_lbrace then nest += 1 when :on_rbrace then nest -= 1 if nest <= 0 # we might have a.each { |i| yield i } unget_tk(tk) if nest < 0 break end when :on_lparen then nest += 1 when end_token[:kind] then if end_token[:kind] == :on_rparen nest -= 1 break if nest <= 0 else break end when :on_rparen then nest -= 1 when :on_comment, :on_embdoc then @read.pop if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and (!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then if method && method.block_params.nil? then unget_tk tk read_documentation_modifiers method, modifiers end break if !continue and nest <= 0 end when :on_comma then continue = true when :on_ident then continue = false if continue end tk = get_tk end get_tkread_clean(/\s+/, ' ') end ## # Capture the method's parameters. Along the way, look for a comment # containing: # # # yields: .... # # and add this as the block_params for the method def parse_method_parameters method res = parse_method_or_yield_parameters method res = "(#{res})" unless res =~ /\A\(/ method.params = res unless method.params return if method.block_params skip_tkspace_without_nl read_documentation_modifiers method, RDoc::METHOD_MODIFIERS end ## # Parses an RDoc::NormalModule in +container+ with +comment+ def parse_module container, single, tk, comment container, name_t, = get_class_or_module container name = name_t[:text] mod = container.add_module RDoc::NormalModule, name mod.ignore unless container.document_children record_location mod read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS mod.add_comment comment, @top_level parse_statements mod # after end modifiers read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS @stats.add_module mod end ## # Parses an RDoc::Require in +context+ containing +comment+ def parse_require(context, comment) skip_tkspace_comment tk = get_tk if :on_lparen == tk[:kind] then skip_tkspace_comment tk = get_tk end name = tk[:text][1..-2] if :on_tstring == tk[:kind] if name then @top_level.add_require RDoc::Require.new(name, comment) else unget_tk tk end end ## # Parses a rescue def parse_rescue skip_tkspace_without_nl while tk = get_tk case tk[:kind] when :on_nl, :on_semicolon, :on_comment then break when :on_comma then skip_tkspace_without_nl get_tk if :on_nl == peek_tk[:kind] end skip_tkspace_without_nl end end ## # Retrieve comment body without =begin/=end def retrieve_comment_body(tk) if :on_embdoc == tk[:kind] tk[:text].gsub(/\A=begin.*\n/, '').gsub(/=end\n?\z/, '') else tk[:text] end end ## # The core of the Ruby parser. def parse_statements(container, single = NORMAL, current_method = nil, comment = new_comment('')) raise 'no' unless RDoc::Comment === comment comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding nest = 1 save_visibility = container.visibility non_comment_seen = true while tk = get_tk do keep_comment = false try_parse_comment = false non_comment_seen = true unless (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) case tk[:kind] when :on_nl, :on_ignored_nl, :on_comment, :on_embdoc then if :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind] skip_tkspace tk = get_tk else past_tokens = @read.size > 1 ? @read[0..-2] : [] nl_position = 0 past_tokens.reverse.each_with_index do |read_tk, i| if read_tk =~ /^\n$/ then nl_position = (past_tokens.size - 1) - i break elsif read_tk =~ /^#.*\n$/ then nl_position = ((past_tokens.size - 1) - i) + 1 break end end comment_only_line = past_tokens[nl_position..-1].all?{ |c| c =~ /^\s+$/ } unless comment_only_line then tk = get_tk end end if tk and (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) then if non_comment_seen then # Look for RDoc in a comment about to be thrown away non_comment_seen = parse_comment container, tk, comment unless comment.empty? comment = '' comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding end line_no = nil while tk and (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) do comment_body = retrieve_comment_body(tk) line_no = tk[:line_no] if comment.empty? comment += comment_body comment << "\n" unless comment_body =~ /\n\z/ if comment_body.size > 1 && comment_body =~ /\n\z/ then skip_tkspace_without_nl # leading spaces end tk = get_tk end comment = new_comment comment, line_no unless comment.empty? then look_for_directives_in container, comment if container.done_documenting then throw :eof if RDoc::TopLevel === container container.ongoing_visibility = save_visibility end end keep_comment = true else non_comment_seen = true end unget_tk tk keep_comment = true container.current_line_visibility = nil when :on_kw then case tk[:text] when 'class' then parse_class container, single, tk, comment when 'module' then parse_module container, single, tk, comment when 'def' then parse_method container, single, tk, comment when 'alias' then parse_alias container, single, tk, comment unless current_method when 'yield' then if current_method.nil? then warn "Warning: yield outside of method" if container.document_self else parse_yield container, single, tk, current_method end when 'until', 'while' then if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0 nest += 1 skip_optional_do_after_expression end # Until and While can have a 'do', which shouldn't increase the nesting. # We can't solve the general case, but we can handle most occurrences by # ignoring a do at the end of a line. # 'for' is trickier when 'for' then nest += 1 skip_for_variable skip_optional_do_after_expression when 'case', 'do', 'if', 'unless', 'begin' then if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0 nest += 1 end when 'super' then current_method.calls_super = true if current_method when 'rescue' then parse_rescue when 'end' then nest -= 1 if nest == 0 then container.ongoing_visibility = save_visibility parse_comment container, tk, comment unless comment.empty? return end end when :on_const then unless parse_constant container, tk, comment, current_method then try_parse_comment = true end when :on_ident then if nest == 1 and current_method.nil? then keep_comment = parse_identifier container, single, tk, comment end case tk[:text] when "require" then parse_require container, comment when "include" then parse_extend_or_include RDoc::Include, container, comment when "extend" then parse_extend_or_include RDoc::Extend, container, comment end else try_parse_comment = nest == 1 end if try_parse_comment then non_comment_seen = parse_comment container, tk, comment unless comment.empty? keep_comment = false end unless keep_comment then comment = new_comment '' comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding container.params = nil container.block_params = nil end consume_trailing_spaces end container.params = nil container.block_params = nil end ## # Parse up to +no+ symbol arguments def parse_symbol_arg(no = nil) skip_tkspace_comment tk = get_tk if tk[:kind] == :on_lparen parse_symbol_arg_paren no else parse_symbol_arg_space no, tk end end ## # Parses up to +no+ symbol arguments surrounded by () and places them in # +args+. def parse_symbol_arg_paren no # :nodoc: args = [] loop do skip_tkspace_comment if tk1 = parse_symbol_in_arg args.push tk1 break if no and args.size >= no end skip_tkspace_comment case (tk2 = get_tk)[:kind] when :on_rparen break when :on_comma else warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC break end end args end ## # Parses up to +no+ symbol arguments separated by spaces and places them in # +args+. def parse_symbol_arg_space no, tk # :nodoc: args = [] unget_tk tk if tk = parse_symbol_in_arg args.push tk return args if no and args.size >= no end loop do skip_tkspace_without_nl tk1 = get_tk if tk1.nil? || :on_comma != tk1[:kind] then unget_tk tk1 break end skip_tkspace_comment if tk = parse_symbol_in_arg args.push tk break if no and args.size >= no end end args end ## # Returns symbol text from the next token def parse_symbol_in_arg tk = get_tk if :on_symbol == tk[:kind] then tk[:text].sub(/^:/, '') elsif :on_tstring == tk[:kind] then tk[:text][1..-2] elsif :on_dstring == tk[:kind] or :on_ident == tk[:kind] then nil # ignore else warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC nil end end ## # Parses statements in the top-level +container+ def parse_top_level_statements container comment = collect_first_comment look_for_directives_in container, comment throw :eof if container.done_documenting @markup = comment.format # HACK move if to RDoc::Context#comment= container.comment = comment if container.document_self unless comment.empty? parse_statements container, NORMAL, nil, comment end ## # Determines the visibility in +container+ from +tk+ def parse_visibility(container, single, tk) vis_type, vis, singleton = get_visibility_information tk, single skip_tkspace_comment false ptk = peek_tk # Ryan Davis suggested the extension to ignore modifiers, because he # often writes # # protected unless $TESTING # if [:on_nl, :on_semicolon].include?(ptk[:kind]) || (:on_kw == ptk[:kind] && (['if', 'unless'].include?(ptk[:text]))) then container.ongoing_visibility = vis elsif :on_kw == ptk[:kind] && 'def' == ptk[:text] container.current_line_visibility = vis else update_visibility container, vis_type, vis, singleton end end ## # Parses a Module#private_constant or Module#public_constant call from +tk+. def parse_constant_visibility(container, single, tk) args = parse_symbol_arg case tk[:text] when 'private_constant' vis = :private when 'public_constant' vis = :public else raise RDoc::Error, 'Unreachable' end container.set_constant_visibility_for args, vis end ## # Determines the block parameter for +context+ def parse_yield(context, single, tk, method) return if method.block_params get_tkread method.block_params = parse_method_or_yield_parameters end ## # Directives are modifier comments that can appear after class, module, or # method names. For example: # # def fred # :yields: a, b # # or: # # class MyClass # :nodoc: # # We return the directive name and any parameters as a two element array if # the name is in +allowed+. A directive can be found anywhere up to the end # of the current line. def read_directive allowed tokens = [] while tk = get_tk do tokens << tk if :on_nl == tk[:kind] or (:on_kw == tk[:kind] && 'def' == tk[:text]) then return elsif :on_comment == tk[:kind] or :on_embdoc == tk[:kind] then return unless tk[:text] =~ /\s*:?([\w-]+):\s*(.*)/ directive = $1.downcase return [directive, $2] if allowed.include? directive return end end ensure unless tokens.length == 1 and (:on_comment == tokens.first[:kind] or :on_embdoc == tokens.first[:kind]) then tokens.reverse_each do |token| unget_tk token end end end ## # Handles directives following the definition for +context+ (any # RDoc::CodeObject) if the directives are +allowed+ at this point. # # See also RDoc::Markup::PreProcess#handle_directive def read_documentation_modifiers context, allowed skip_tkspace_without_nl directive, value = read_directive allowed return unless directive @preprocess.handle_directive '', directive, value, context do |dir, param| if %w[notnew not_new not-new].include? dir then context.dont_rename_initialize = true true end end end ## # Records the location of this +container+ in the file for this parser and # adds it to the list of classes and modules in the file. def record_location container # :nodoc: case container when RDoc::ClassModule then @top_level.add_to_classes_or_modules container end container.record_location @top_level end ## # Scans this Ruby file for Ruby constructs def scan reset catch :eof do begin parse_top_level_statements @top_level rescue StandardError => e if @content.include?('<%') and @content.include?('%>') then # Maybe, this is ERB. $stderr.puts "\033[2KRDoc detects ERB file. Skips it for compatibility:" $stderr.puts @file_name return end if @scanner_point >= @scanner.size now_line_no = @scanner[@scanner.size - 1][:line_no] else now_line_no = peek_tk[:line_no] end first_tk_index = @scanner.find_index { |tk| tk[:line_no] == now_line_no } last_tk_index = @scanner.find_index { |tk| tk[:line_no] == now_line_no + 1 } last_tk_index = last_tk_index ? last_tk_index - 1 : @scanner.size - 1 code = @scanner[first_tk_index..last_tk_index].map{ |t| t[:text] }.join $stderr.puts <<-EOF #{self.class} failure around line #{now_line_no} of #{@file_name} EOF unless code.empty? then $stderr.puts code $stderr.puts end raise e end end @top_level end ## # while, until, and for have an optional do def skip_optional_do_after_expression skip_tkspace_without_nl tk = get_tk b_nest = 0 nest = 0 loop do break unless tk case tk[:kind] when :on_semicolon, :on_nl, :on_ignored_nl then break if b_nest.zero? when :on_lparen then nest += 1 when :on_rparen then nest -= 1 when :on_kw then case tk[:text] when 'begin' b_nest += 1 when 'end' b_nest -= 1 when 'do' break if nest.zero? end when :on_comment, :on_embdoc then if b_nest.zero? and "\n" == tk[:text][-1] then break end end tk = get_tk end skip_tkspace_without_nl get_tk if peek_tk && :on_kw == peek_tk[:kind] && 'do' == peek_tk[:text] end ## # skip the var [in] part of a 'for' statement def skip_for_variable skip_tkspace_without_nl get_tk skip_tkspace_without_nl tk = get_tk unget_tk(tk) unless :on_kw == tk[:kind] and 'in' == tk[:text] end ## # Skips the next method in +container+ def skip_method container meth = RDoc::AnyMethod.new "", "anon" parse_method_parameters meth parse_statements container, false, meth end ## # Skip spaces until a comment is found def skip_tkspace_comment(skip_nl = true) loop do skip_nl ? skip_tkspace : skip_tkspace_without_nl next_tk = peek_tk return if next_tk.nil? || (:on_comment != next_tk[:kind] and :on_embdoc != next_tk[:kind]) get_tk end end ## # Updates visibility in +container+ from +vis_type+ and +vis+. def update_visibility container, vis_type, vis, singleton # :nodoc: new_methods = [] case vis_type when 'module_function' then args = parse_symbol_arg container.set_visibility_for args, :private, false container.methods_matching args do |m| s_m = m.dup record_location s_m s_m.singleton = true new_methods << s_m end when 'public_class_method', 'private_class_method' then args = parse_symbol_arg container.methods_matching args, true do |m| if m.parent != container then m = m.dup record_location m new_methods << m end m.visibility = vis end else args = parse_symbol_arg container.set_visibility_for args, vis, singleton end new_methods.each do |method| case method when RDoc::AnyMethod then container.add_method method when RDoc::Attr then container.add_attribute method end method.visibility = vis end end ## # Prints +message+ to +$stderr+ unless we're being quiet def warn message @options.warn make_message message end end PK ]:ܶ'gems/rdoc-6.2.1.1/lib/rdoc/parser/rd.rbnu[# frozen_string_literal: true ## # Parse a RD format file. The parsed RDoc::Markup::Document is attached as a # file comment. class RDoc::Parser::RD < RDoc::Parser include RDoc::Parser::Text parse_files_matching(/\.rd(?:\.[^.]+)?$/) ## # Creates an rd-format TopLevel for the given file. def scan comment = RDoc::Comment.new @content, @top_level comment.format = 'rd' @top_level.comment = comment end end PK ]Og.gems/rdoc-6.2.1.1/lib/rdoc/parser/changelog.rbnu[# frozen_string_literal: true require 'time' ## # A ChangeLog file parser. # # This parser converts a ChangeLog into an RDoc::Markup::Document. When # viewed as HTML a ChangeLog page will have an entry for each day's entries in # the sidebar table of contents. # # This parser is meant to parse the MRI ChangeLog, but can be used to parse any # {GNU style Change # Log}[http://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html]. class RDoc::Parser::ChangeLog < RDoc::Parser include RDoc::Parser::Text parse_files_matching(/(\/|\\|\A)ChangeLog[^\/\\]*\z/) ## # Attaches the +continuation+ of the previous line to the +entry_body+. # # Continued function listings are joined together as a single entry. # Continued descriptions are joined to make a single paragraph. def continue_entry_body entry_body, continuation return unless last = entry_body.last if last =~ /\)\s*\z/ and continuation =~ /\A\(/ then last.sub!(/\)\s*\z/, ',') continuation = continuation.sub(/\A\(/, '') end if last =~ /\s\z/ then last << continuation else last << ' ' + continuation end end ## # Creates an RDoc::Markup::Document given the +groups+ of ChangeLog entries. def create_document groups doc = RDoc::Markup::Document.new doc.omit_headings_below = 2 doc.file = @top_level doc << RDoc::Markup::Heading.new(1, File.basename(@file_name)) doc << RDoc::Markup::BlankLine.new groups.sort_by do |day,| day end.reverse_each do |day, entries| doc << RDoc::Markup::Heading.new(2, day.dup) doc << RDoc::Markup::BlankLine.new doc.concat create_entries entries end doc end ## # Returns a list of ChangeLog entries an RDoc::Markup nodes for the given # +entries+. def create_entries entries out = [] entries.each do |entry, items| out << RDoc::Markup::Heading.new(3, entry) out << RDoc::Markup::BlankLine.new out << create_items(items) end out end ## # Returns an RDoc::Markup::List containing the given +items+ in the # ChangeLog def create_items items list = RDoc::Markup::List.new :NOTE items.each do |item| item =~ /\A(.*?(?:\([^)]+\))?):\s*/ title = $1 body = $' paragraph = RDoc::Markup::Paragraph.new body list_item = RDoc::Markup::ListItem.new title, paragraph list << list_item end list end ## # Groups +entries+ by date. def group_entries entries @time_cache ||= {} entries.group_by do |title, _| begin time = @time_cache[title] (time || Time.parse(title)).strftime '%Y-%m-%d' rescue NoMethodError, ArgumentError time, = title.split ' ', 2 Time.parse(time).strftime '%Y-%m-%d' end end end ## # Parses the entries in the ChangeLog. # # Returns an Array of each ChangeLog entry in order of parsing. # # A ChangeLog entry is an Array containing the ChangeLog title (date and # committer) and an Array of ChangeLog items (file and function changed with # description). # # An example result would be: # # [ 'Tue Dec 4 08:33:46 2012 Eric Hodel ', # [ 'README.EXT: Converted to RDoc format', # 'README.EXT.ja: ditto']] def parse_entries @time_cache ||= {} entries = [] entry_name = nil entry_body = [] @content.each_line do |line| case line when /^\s*$/ then next when /^\w.*/ then entries << [entry_name, entry_body] if entry_name entry_name = $& begin time = Time.parse entry_name @time_cache[entry_name] = time # HACK Ruby 1.8 does not raise ArgumentError for Time.parse "Other" entry_name = nil unless entry_name =~ /#{time.year}/ rescue NoMethodError # HACK Ruby 2.1.2 and earlier raises NoMethodError if time part is absent entry_name.split ' ', 2 rescue ArgumentError if /out of range/ =~ $!.message Time.parse(entry_name.split(' ', 2)[0]) rescue entry_name = nil else entry_name = nil end end entry_body = [] when /^(\t| {8})?\*\s*(.*)/ then # "\t* file.c (func): ..." entry_body << $2.dup when /^(\t| {8})?\s*(\(.*)/ then # "\t(func): ..." entry = $2 if entry_body.last =~ /:/ then entry_body << entry.dup else continue_entry_body entry_body, entry end when /^(\t| {8})?\s*(.*)/ then continue_entry_body entry_body, $2 end end entries << [entry_name, entry_body] if entry_name entries.reject! do |(entry,_)| entry == nil end entries end ## # Converts the ChangeLog into an RDoc::Markup::Document def scan @time_cache = {} entries = parse_entries grouped_entries = group_entries entries doc = create_document grouped_entries @top_level.comment = doc @top_level end end PK ]4QՆ /gems/rdoc-6.2.1.1/lib/rdoc/parser/ruby_tools.rbnu[# frozen_string_literal: true ## # Collection of methods for writing parsers module RDoc::Parser::RubyTools ## # Adds a token listener +obj+, but you should probably use token_listener def add_token_listener(obj) @token_listeners ||= [] @token_listeners << obj end ## # Fetches the next token from the scanner def get_tk tk = nil if @tokens.empty? then if @scanner_point >= @scanner.size return nil else tk = @scanner[@scanner_point] @scanner_point += 1 @read.push tk[:text] end else @read.push @unget_read.shift tk = @tokens.shift end if tk == nil || :on___end__ == tk[:kind] tk = nil end return nil unless tk # inform any listeners of our shiny new token @token_listeners.each do |obj| obj.add_token(tk) end if @token_listeners tk end ## # Reads and returns all tokens up to one of +tokens+. Leaves the matched # token in the token list. def get_tk_until(*tokens) read = [] loop do tk = get_tk case tk when *tokens then unget_tk tk break end read << tk end read end ## # Retrieves a String representation of the read tokens def get_tkread read = @read.join("") @read = [] read end ## # Peek equivalent for get_tkread def peek_read @read.join('') end ## # Peek at the next token, but don't remove it from the stream def peek_tk unget_tk(tk = get_tk) tk end ## # Removes the token listener +obj+ def remove_token_listener(obj) @token_listeners.delete(obj) end ## # Resets the tools def reset @read = [] @tokens = [] @unget_read = [] @nest = 0 @scanner_point = 0 end ## # Skips whitespace tokens including newlines def skip_tkspace tokens = [] while (tk = get_tk) and (:on_sp == tk[:kind] or :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind]) do tokens.push(tk) end unget_tk(tk) tokens end ## # Skips whitespace tokens excluding newlines def skip_tkspace_without_nl tokens = [] while (tk = get_tk) and :on_sp == tk[:kind] do tokens.push(tk) end unget_tk(tk) tokens end ## # Has +obj+ listen to tokens def token_listener(obj) add_token_listener obj yield ensure remove_token_listener obj end ## # Returns +tk+ to the scanner def unget_tk(tk) @tokens.unshift tk @unget_read.unshift @read.pop # Remove this token from any listeners @token_listeners.each do |obj| obj.pop_token end if @token_listeners nil end end PK ]9GG&gems/rdoc-6.2.1.1/lib/rdoc/parser/c.rbnu[# frozen_string_literal: true require 'tsort' ## # RDoc::Parser::C attempts to parse C extension files. It looks for # the standard patterns that you find in extensions: +rb_define_class+, # +rb_define_method+ and so on. It tries to find the corresponding # C source for the methods and extract comments, but if we fail # we don't worry too much. # # The comments associated with a Ruby method are extracted from the C # comment block associated with the routine that _implements_ that # method, that is to say the method whose name is given in the # +rb_define_method+ call. For example, you might write: # # /* # * Returns a new array that is a one-dimensional flattening of this # * array (recursively). That is, for every element that is an array, # * extract its elements into the new array. # * # * s = [ 1, 2, 3 ] #=> [1, 2, 3] # * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] # * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] # * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # */ # static VALUE # rb_ary_flatten(VALUE ary) # { # ary = rb_obj_dup(ary); # rb_ary_flatten_bang(ary); # return ary; # } # # ... # # void # Init_Array(void) # { # ... # rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0); # # Here RDoc will determine from the +rb_define_method+ line that there's a # method called "flatten" in class Array, and will look for the implementation # in the method +rb_ary_flatten+. It will then use the comment from that # method in the HTML output. This method must be in the same source file # as the +rb_define_method+. # # The comment blocks may include special directives: # # [Document-class: +name+] # Documentation for the named class. # # [Document-module: +name+] # Documentation for the named module. # # [Document-const: +name+] # Documentation for the named +rb_define_const+. # # Constant values can be supplied on the first line of the comment like so: # # /* 300: The highest possible score in bowling */ # rb_define_const(cFoo, "PERFECT", INT2FIX(300)); # # The value can contain internal colons so long as they are escaped with a \ # # [Document-global: +name+] # Documentation for the named +rb_define_global_const+ # # [Document-variable: +name+] # Documentation for the named +rb_define_variable+ # # [Document-method\: +method_name+] # Documentation for the named method. Use this when the method name is # unambiguous. # # [Document-method\: ClassName::method_name] # Documentation for a singleton method in the given class. Use this when # the method name alone is ambiguous. # # [Document-method\: ClassName#method_name] # Documentation for a instance method in the given class. Use this when the # method name alone is ambiguous. # # [Document-attr: +name+] # Documentation for the named attribute. # # [call-seq: text up to an empty line] # Because C source doesn't give descriptive names to Ruby-level parameters, # you need to document the calling sequence explicitly # # In addition, RDoc assumes by default that the C method implementing a # Ruby function is in the same source file as the rb_define_method call. # If this isn't the case, add the comment: # # rb_define_method(....); // in filename # # As an example, we might have an extension that defines multiple classes # in its Init_xxx method. We could document them using # # /* # * Document-class: MyClass # * # * Encapsulate the writing and reading of the configuration # * file. ... # */ # # /* # * Document-method: read_value # * # * call-seq: # * cfg.read_value(key) -> value # * cfg.read_value(key} { |key| } -> value # * # * Return the value corresponding to +key+ from the configuration. # * In the second form, if the key isn't found, invoke the # * block and return its value. # */ class RDoc::Parser::C < RDoc::Parser parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/) include RDoc::Text ## # Maps C variable names to names of Ruby classes or modules attr_reader :classes ## # C file the parser is parsing attr_accessor :content ## # Dependencies from a missing enclosing class to the classes in # missing_dependencies that depend upon it. attr_reader :enclosure_dependencies ## # Maps C variable names to names of Ruby classes (and singleton classes) attr_reader :known_classes ## # Classes found while parsing the C file that were not yet registered due to # a missing enclosing class. These are processed by do_missing attr_reader :missing_dependencies ## # Maps C variable names to names of Ruby singleton classes attr_reader :singleton_classes ## # The TopLevel items in the parsed file belong to attr_reader :top_level ## # Prepares for parsing a C file. See RDoc::Parser#initialize for details on # the arguments. def initialize top_level, file_name, content, options, stats super @known_classes = RDoc::KNOWN_CLASSES.dup @content = handle_tab_width handle_ifdefs_in @content @file_dir = File.dirname @file_name @classes = load_variable_map :c_class_variables @singleton_classes = load_variable_map :c_singleton_class_variables # class_variable => { function => [method, ...] } @methods = Hash.new { |h, f| h[f] = Hash.new { |i, m| i[m] = [] } } # missing variable => [handle_class_module arguments] @missing_dependencies = {} # missing enclosure variable => [dependent handle_class_module arguments] @enclosure_dependencies = Hash.new { |h, k| h[k] = [] } @enclosure_dependencies.instance_variable_set :@missing_dependencies, @missing_dependencies @enclosure_dependencies.extend TSort def @enclosure_dependencies.tsort_each_node &block each_key(&block) rescue TSort::Cyclic => e cycle_vars = e.message.scan(/"(.*?)"/).flatten cycle = cycle_vars.sort.map do |var_name| delete var_name var_name, type, mod_name, = @missing_dependencies[var_name] "#{type} #{mod_name} (#{var_name})" end.join ', ' warn "Unable to create #{cycle} due to a cyclic class or module creation" retry end def @enclosure_dependencies.tsort_each_child node, &block fetch(node, []).each(&block) end end ## # Removes duplicate call-seq entries for methods using the same # implementation. def deduplicate_call_seq @methods.each do |var_name, functions| class_name = @known_classes[var_name] next unless class_name class_obj = find_class var_name, class_name functions.each_value do |method_names| next if method_names.length == 1 method_names.each do |method_name| deduplicate_method_name class_obj, method_name end end end end ## # If two ruby methods share a C implementation (and comment) this # deduplicates the examples in the call_seq for the method to reduce # confusion in the output. def deduplicate_method_name class_obj, method_name # :nodoc: return unless method = class_obj.method_list.find { |m| m.name == method_name } return unless call_seq = method.call_seq method_name = method_name[0, 1] if method_name =~ /\A\[/ entries = call_seq.split "\n" matching = entries.select do |entry| entry =~ /^\w*\.?#{Regexp.escape method_name}/ or entry =~ /\s#{Regexp.escape method_name}\s/ end method.call_seq = matching.join "\n" end ## # Scans #content for rb_define_alias def do_aliases @content.scan(/rb_define_alias\s*\( \s*(\w+), \s*"(.+?)", \s*"(.+?)" \s*\)/xm) do |var_name, new_name, old_name| class_name = @known_classes[var_name] unless class_name then @options.warn "Enclosing class or module %p for alias %s %s is not known" % [ var_name, new_name, old_name] next end class_obj = find_class var_name, class_name al = RDoc::Alias.new '', old_name, new_name, '' al.singleton = @singleton_classes.key? var_name comment = find_alias_comment var_name, new_name, old_name comment.normalize al.comment = comment al.record_location @top_level class_obj.add_alias al @stats.add_alias al end end ## # Scans #content for rb_attr and rb_define_attr def do_attrs @content.scan(/rb_attr\s*\( \s*(\w+), \s*([\w"()]+), \s*([01]), \s*([01]), \s*\w+\);/xm) do |var_name, attr_name, read, write| handle_attr var_name, attr_name, read, write end @content.scan(%r%rb_define_attr\( \s*([\w\.]+), \s*"([^"]+)", \s*(\d+), \s*(\d+)\s*\); %xm) do |var_name, attr_name, read, write| handle_attr var_name, attr_name, read, write end end ## # Scans #content for boot_defclass def do_boot_defclass @content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do |var_name, class_name, parent| parent = nil if parent == "0" handle_class_module(var_name, :class, class_name, parent, nil) end end ## # Scans #content for rb_define_class, boot_defclass, rb_define_class_under # and rb_singleton_class def do_classes_and_modules do_boot_defclass if @file_name == "class.c" @content.scan( %r( (?[\w\.]+)\s* = \s*rb_(?: define_(?: class(?: # rb_define_class(class_name_1, parent_name_1) \s*\( \s*"(?\w+)", \s*(?\w+)\s* \) | _under\s*\( # rb_define_class_under(class_under, class_name2, parent_name2...) \s* (?\w+), \s* "(?\w+)", \s* (?: (?[\w\*\s\(\)\.\->]+) | rb_path2class\("(?[\w:]+)"\) ) \s*\) ) | module(?: # rb_define_module(module_name_1) \s*\( \s*"(?\w+)"\s* \) | _under\s*\( # rb_define_module_under(module_under, module_name_1) \s*(?\w+), \s*"(?\w+)" \s*\) ) ) | struct_define_without_accessor\s*\( # rb_struct_define_without_accessor(class_name_3, parent_name_3, ...) \s*"(?\w+)", \s*(?\w+), \s*\w+, # Allocation function (?:\s*"\w+",)* # Attributes \s*NULL \) | singleton_class\s*\( # rb_singleton_class(target_class_name) \s*(?\w+) \) ) )mx ) do class_name = $~[:class_name_1] type = :class if class_name # rb_define_class(class_name_1, parent_name_1) parent_name = $~[:parent_name_1] #under = nil else class_name = $~[:class_name_2] if class_name # rb_define_class_under(class_under, class_name2, parent_name2...) parent_name = $~[:parent_name_2] || $~[:path] under = $~[:class_under] else class_name = $~[:class_name_3] if class_name # rb_struct_define_without_accessor(class_name_3, parent_name_3, ...) parent_name = $~[:parent_name_3] #under = nil else type = :module class_name = $~[:module_name_1] #parent_name = nil if class_name # rb_define_module(module_name_1) #under = nil else class_name = $~[:module_name_2] if class_name # rb_define_module_under(module_under, module_name_1) under = $~[:module_under] else # rb_singleton_class(target_class_name) target_class_name = $~[:target_class_name] handle_singleton $~[:var_name], target_class_name next end end end end end handle_class_module($~[:var_name], type, class_name, parent_name, under) end end ## # Scans #content for rb_define_variable, rb_define_readonly_variable, # rb_define_const and rb_define_global_const def do_constants @content.scan(%r%\Wrb_define_ ( variable | readonly_variable | const | global_const ) \s*\( (?:\s*(\w+),)? \s*"(\w+)", \s*(.*?)\s*\)\s*; %xm) do |type, var_name, const_name, definition| var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel" handle_constants type, var_name, const_name, definition end @content.scan(%r% \Wrb_curses_define_const \s*\( \s* (\w+) \s* \) \s*;%xm) do |consts| const = consts.first handle_constants 'const', 'mCurses', const, "UINT2NUM(#{const})" end @content.scan(%r% \Wrb_file_const \s*\( \s* "([^"]+)", \s* (.*?) \s* \) \s*;%xm) do |name, value| handle_constants 'const', 'rb_mFConst', name, value end end ## # Scans #content for rb_include_module def do_includes @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m| next unless cls = @classes[c] m = @known_classes[m] || m comment = RDoc::Comment.new '', @top_level, :c incl = cls.add_include RDoc::Include.new(m, comment) incl.record_location @top_level end end ## # Scans #content for rb_define_method, rb_define_singleton_method, # rb_define_module_function, rb_define_private_method, # rb_define_global_function and define_filetest_function def do_methods @content.scan(%r%rb_define_ ( singleton_method | method | module_function | private_method ) \s*\(\s*([\w\.]+), \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\(|\(METHOD\))?(\w+)\)?, \s*(-?\w+)\s*\) (?:;\s*/[*/]\s+in\s+(\w+?\.(?:cpp|c|y)))? %xm) do |type, var_name, meth_name, function, param_count, source_file| # Ignore top-object and weird struct.c dynamic stuff next if var_name == "ruby_top_self" next if var_name == "nstr" var_name = "rb_cObject" if var_name == "rb_mKernel" handle_method(type, var_name, meth_name, function, param_count, source_file) end @content.scan(%r%rb_define_global_function\s*\( \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\) (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))? %xm) do |meth_name, function, param_count, source_file| handle_method("method", "rb_mKernel", meth_name, function, param_count, source_file) end @content.scan(/define_filetest_function\s*\( \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\)/xm) do |meth_name, function, param_count| handle_method("method", "rb_mFileTest", meth_name, function, param_count) handle_method("singleton_method", "rb_cFile", meth_name, function, param_count) end end ## # Creates classes and module that were missing were defined due to the file # order being different than the declaration order. def do_missing return if @missing_dependencies.empty? @enclosure_dependencies.tsort.each do |in_module| arguments = @missing_dependencies.delete in_module next unless arguments # dependency on existing class handle_class_module(*arguments) end end ## # Finds the comment for an alias on +class_name+ from +new_name+ to # +old_name+ def find_alias_comment class_name, new_name, old_name content =~ %r%((?>/\*.*?\*/\s+)) rb_define_alias\(\s*#{Regexp.escape class_name}\s*, \s*"#{Regexp.escape new_name}"\s*, \s*"#{Regexp.escape old_name}"\s*\);%xm RDoc::Comment.new($1 || '', @top_level, :c) end ## # Finds a comment for rb_define_attr, rb_attr or Document-attr. # # +var_name+ is the C class variable the attribute is defined on. # +attr_name+ is the attribute's name. # # +read+ and +write+ are the read/write flags ('1' or '0'). Either both or # neither must be provided. def find_attr_comment var_name, attr_name, read = nil, write = nil attr_name = Regexp.escape attr_name rw = if read and write then /\s*#{read}\s*,\s*#{write}\s*/xm else /.*?/m end comment = if @content =~ %r%((?>/\*.*?\*/\s+)) rb_define_attr\((?:\s*#{var_name},)?\s* "#{attr_name}"\s*, #{rw}\)\s*;%xm then $1 elsif @content =~ %r%((?>/\*.*?\*/\s+)) rb_attr\(\s*#{var_name}\s*, \s*#{attr_name}\s*, #{rw},.*?\)\s*;%xm then $1 elsif @content =~ %r%(/\*.*?(?:\s*\*\s*)?) Document-attr:\s#{attr_name}\s*?\n ((?>(.|\n)*?\*/))%x then "#{$1}\n#{$2}" else '' end RDoc::Comment.new comment, @top_level, :c end ## # Generate a Ruby-method table def gen_body_table file_content table = {} file_content.scan(%r{ ((?>/\*.*?\*/\s*)?) ((?:(?:\w+)\s+)? (?:intern\s+)?VALUE\s+(\w+) \s*(?:\([^)]*\))(?:[^;]|$)) | ((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+(\w+)\s+(\w+)) | ^\s*\#\s*define\s+(\w+)\s+(\w+) }xm) do case when $1 table[$3] = [:func_def, $1, $2, $~.offset(2)] if !table[$3] || table[$3][0] != :func_def when $4 table[$6] = [:macro_def, $4, $5, $~.offset(5), $7] if !table[$6] || table[$6][0] == :macro_alias when $8 table[$8] ||= [:macro_alias, $9] end end table end ## # Find the C code corresponding to a Ruby method def find_body class_name, meth_name, meth_obj, file_content, quiet = false if file_content @body_table ||= {} @body_table[file_content] ||= gen_body_table file_content type, *args = @body_table[file_content][meth_name] end case type when :func_def comment = RDoc::Comment.new args[0], @top_level, :c body = args[1] offset, = args[2] comment.remove_private if comment # try to find the whole body body = $& if /#{Regexp.escape body}[^(]*?\{.*?^\}/m =~ file_content # The comment block may have been overridden with a 'Document-method' # block. This happens in the interpreter when multiple methods are # vectored through to the same C method but those methods are logically # distinct (for example Kernel.hash and Kernel.object_id share the same # implementation override_comment = find_override_comment class_name, meth_obj comment = override_comment if override_comment comment.normalize find_modifiers comment, meth_obj if comment #meth_obj.params = params meth_obj.start_collecting_tokens tk = { :line_no => 1, :char_no => 1, :text => body } meth_obj.add_token tk meth_obj.comment = comment meth_obj.line = file_content[0, offset].count("\n") + 1 body when :macro_def comment = RDoc::Comment.new args[0], @top_level, :c body = args[1] offset, = args[2] find_body class_name, args[3], meth_obj, file_content, true comment.normalize find_modifiers comment, meth_obj meth_obj.start_collecting_tokens tk = { :line_no => 1, :char_no => 1, :text => body } meth_obj.add_token tk meth_obj.comment = comment meth_obj.line = file_content[0, offset].count("\n") + 1 body when :macro_alias # with no comment we hope the aliased definition has it and use it's # definition body = find_body(class_name, args[0], meth_obj, file_content, true) return body if body @options.warn "No definition for #{meth_name}" false else # No body, but might still have an override comment comment = find_override_comment class_name, meth_obj if comment then comment.normalize find_modifiers comment, meth_obj meth_obj.comment = comment '' else @options.warn "No definition for #{meth_name}" false end end end ## # Finds a RDoc::NormalClass or RDoc::NormalModule for +raw_name+ def find_class(raw_name, name) unless @classes[raw_name] if raw_name =~ /^rb_m/ container = @top_level.add_module RDoc::NormalModule, name else container = @top_level.add_class RDoc::NormalClass, name end container.record_location @top_level @classes[raw_name] = container end @classes[raw_name] end ## # Look for class or module documentation above Init_+class_name+(void), # in a Document-class +class_name+ (or module) comment or above an # rb_define_class (or module). If a comment is supplied above a matching # Init_ and a rb_define_class the Init_ comment is used. # # /* # * This is a comment for Foo # */ # Init_Foo(void) { # VALUE cFoo = rb_define_class("Foo", rb_cObject); # } # # /* # * Document-class: Foo # * This is a comment for Foo # */ # Init_foo(void) { # VALUE cFoo = rb_define_class("Foo", rb_cObject); # } # # /* # * This is a comment for Foo # */ # VALUE cFoo = rb_define_class("Foo", rb_cObject); def find_class_comment class_name, class_mod comment = nil if @content =~ %r% ((?>/\*.*?\*/\s+)) (static\s+)? void\s+ Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)%xmi then comment = $1.sub(%r%Document-(?:class|module):\s+#{class_name}%, '') elsif @content =~ %r%Document-(?:class|module):\s+#{class_name}\s*? (?:<\s+[:,\w]+)?\n((?>.*?\*/))%xm then comment = "/*\n#{$1}" elsif @content =~ %r%((?>/\*.*?\*/\s+)) ([\w\.\s]+\s* = \s+)?rb_define_(class|module)[\t (]*?"(#{class_name})"%xm then comment = $1 elsif @content =~ %r%((?>/\*.*?\*/\s+)) ([\w\. \t]+ = \s+)?rb_define_(class|module)_under[\t\w, (]*?"(#{class_name.split('::').last})"%xm then comment = $1 else comment = '' end comment = RDoc::Comment.new comment, @top_level, :c comment.normalize look_for_directives_in class_mod, comment class_mod.add_comment comment, @top_level end ## # Generate a const table def gen_const_table file_content table = {} @content.scan(%r{ ((?>^\s*/\*.*?\*/\s+)) rb_define_(\w+)\((?:\s*(?:\w+),)?\s* "(\w+)"\s*, .*?\)\s*; | Document-(?:const|global|variable):\s ((?:\w+::)*\w+) \s*?\n((?>.*?\*/)) }mxi) do case when $1 then table[[$2, $3]] = $1 when $4 then table[$4] = "/*\n" + $5 end end table end ## # Finds a comment matching +type+ and +const_name+ either above the # comment or in the matching Document- section. def find_const_comment(type, const_name, class_name = nil) @const_table ||= {} @const_table[@content] ||= gen_const_table @content table = @const_table[@content] comment = table[[type, const_name]] || (class_name && table[class_name + "::" + const_name]) || table[const_name] || '' RDoc::Comment.new comment, @top_level, :c end ## # Handles modifiers in +comment+ and updates +meth_obj+ as appropriate. def find_modifiers comment, meth_obj comment.normalize comment.extract_call_seq meth_obj look_for_directives_in meth_obj, comment end ## # Finds a Document-method override for +meth_obj+ on +class_name+ def find_override_comment class_name, meth_obj name = Regexp.escape meth_obj.name prefix = Regexp.escape meth_obj.name_prefix comment = if @content =~ %r%Document-method: \s+#{class_name}#{prefix}#{name} \s*?\n((?>.*?\*/))%xm then "/*#{$1}" elsif @content =~ %r%Document-method: \s#{name}\s*?\n((?>.*?\*/))%xm then "/*#{$1}" end return unless comment RDoc::Comment.new comment, @top_level, :c end ## # Creates a new RDoc::Attr +attr_name+ on class +var_name+ that is either # +read+, +write+ or both def handle_attr(var_name, attr_name, read, write) rw = '' rw += 'R' if '1' == read rw += 'W' if '1' == write class_name = @known_classes[var_name] return unless class_name class_obj = find_class var_name, class_name return unless class_obj comment = find_attr_comment var_name, attr_name comment.normalize name = attr_name.gsub(/rb_intern(?:_const)?\("([^"]+)"\)/, '\1') attr = RDoc::Attr.new '', name, rw, comment attr.record_location @top_level class_obj.add_attribute attr @stats.add_attribute attr end ## # Creates a new RDoc::NormalClass or RDoc::NormalModule based on +type+ # named +class_name+ in +parent+ which was assigned to the C +var_name+. def handle_class_module(var_name, type, class_name, parent, in_module) parent_name = @known_classes[parent] || parent if in_module then enclosure = @classes[in_module] || @store.find_c_enclosure(in_module) if enclosure.nil? and enclosure = @known_classes[in_module] then enc_type = /^rb_m/ =~ in_module ? :module : :class handle_class_module in_module, enc_type, enclosure, nil, nil enclosure = @classes[in_module] end unless enclosure then @enclosure_dependencies[in_module] << var_name @missing_dependencies[var_name] = [var_name, type, class_name, parent, in_module] return end else enclosure = @top_level end if type == :class then full_name = if RDoc::ClassModule === enclosure then enclosure.full_name + "::#{class_name}" else class_name end if @content =~ %r%Document-class:\s+#{full_name}\s*<\s+([:,\w]+)% then parent_name = $1 end cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name else cm = enclosure.add_module RDoc::NormalModule, class_name end cm.record_location enclosure.top_level find_class_comment cm.full_name, cm case cm when RDoc::NormalClass @stats.add_class cm when RDoc::NormalModule @stats.add_module cm end @classes[var_name] = cm @known_classes[var_name] = cm.full_name @store.add_c_enclosure var_name, cm end ## # Adds constants. By providing some_value: at the start of the comment you # can override the C value of the comment to give a friendly definition. # # /* 300: The perfect score in bowling */ # rb_define_const(cFoo, "PERFECT", INT2FIX(300)); # # Will override INT2FIX(300) with the value +300+ in the output # RDoc. Values may include quotes and escaped colons (\:). def handle_constants(type, var_name, const_name, definition) class_name = @known_classes[var_name] return unless class_name class_obj = find_class var_name, class_name unless class_obj then @options.warn 'Enclosing class or module %p is not known' % [const_name] return end comment = find_const_comment type, const_name, class_name comment.normalize # In the case of rb_define_const, the definition and comment are in # "/* definition: comment */" form. The literal ':' and '\' characters # can be escaped with a backslash. if type.downcase == 'const' then no_match, new_definition, new_comment = comment.text.split(/(\A.*):/) if no_match and no_match.empty? then if new_definition.empty? then # Default to literal C definition new_definition = definition else new_definition = new_definition.gsub("\:", ":") new_definition = new_definition.gsub("\\", '\\') end new_definition.sub!(/\A(\s+)/, '') new_comment = "#{$1}#{new_comment.lstrip}" new_comment = RDoc::Comment.new new_comment, @top_level, :c con = RDoc::Constant.new const_name, new_definition, new_comment else con = RDoc::Constant.new const_name, definition, comment end else con = RDoc::Constant.new const_name, definition, comment end con.record_location @top_level @stats.add_constant con class_obj.add_constant con end ## # Removes #ifdefs that would otherwise confuse us def handle_ifdefs_in(body) body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1') end ## # Adds an RDoc::AnyMethod +meth_name+ defined on a class or module assigned # to +var_name+. +type+ is the type of method definition function used. # +singleton_method+ and +module_function+ create a singleton method. def handle_method(type, var_name, meth_name, function, param_count, source_file = nil) class_name = @known_classes[var_name] singleton = @singleton_classes.key? var_name @methods[var_name][function] << meth_name return unless class_name class_obj = find_class var_name, class_name if class_obj then if meth_name == 'initialize' then meth_name = 'new' singleton = true type = 'method' # force public end meth_obj = RDoc::AnyMethod.new '', meth_name meth_obj.c_function = function meth_obj.singleton = singleton || %w[singleton_method module_function].include?(type) p_count = Integer(param_count) rescue -1 if source_file then file_name = File.join @file_dir, source_file if File.exist? file_name then file_content = File.read file_name else @options.warn "unknown source #{source_file} for #{meth_name} in #{@file_name}" end else file_content = @content end body = find_body class_name, function, meth_obj, file_content if body and meth_obj.document_self then meth_obj.params = if p_count < -1 then # -2 is Array '(*args)' elsif p_count == -1 then # argc, argv rb_scan_args body else "(#{(1..p_count).map { |i| "p#{i}" }.join ', '})" end meth_obj.record_location @top_level class_obj.add_method meth_obj @stats.add_method meth_obj meth_obj.visibility = :private if 'private_method' == type end end end ## # Registers a singleton class +sclass_var+ as a singleton of +class_var+ def handle_singleton sclass_var, class_var class_name = @known_classes[class_var] @known_classes[sclass_var] = class_name @singleton_classes[sclass_var] = class_name end ## # Normalizes tabs in +body+ def handle_tab_width(body) if /\t/ =~ body tab_width = @options.tab_width body.split(/\n/).map do |line| 1 while line.gsub!(/\t+/) do ' ' * (tab_width * $&.length - $`.length % tab_width) end && $~ line end.join "\n" else body end end ## # Loads the variable map with the given +name+ from the RDoc::Store, if # present. def load_variable_map map_name return {} unless files = @store.cache[map_name] return {} unless name_map = files[@file_name] class_map = {} name_map.each do |variable, name| next unless mod = @store.find_class_or_module(name) class_map[variable] = if map_name == :c_class_variables then mod else name end @known_classes[variable] = name end class_map end ## # Look for directives in a normal comment block: # # /* # * :title: My Awesome Project # */ # # This method modifies the +comment+ def look_for_directives_in context, comment @preprocess.handle comment, context do |directive, param| case directive when 'main' then @options.main_page = param '' when 'title' then @options.default_title = param if @options.respond_to? :default_title= '' end end comment end ## # Extracts parameters from the +method_body+ and returns a method # parameter string. Follows 1.9.3dev's scan-arg-spec, see README.EXT def rb_scan_args method_body method_body =~ /rb_scan_args\((.*?)\)/m return '(*args)' unless $1 $1.split(/,/)[2] =~ /"(.*?)"/ # format argument format = $1.split(//) lead = opt = trail = 0 if format.first =~ /\d/ then lead = $&.to_i format.shift if format.first =~ /\d/ then opt = $&.to_i format.shift if format.first =~ /\d/ then trail = $&.to_i format.shift block_arg = true end end end if format.first == '*' and not block_arg then var = true format.shift if format.first =~ /\d/ then trail = $&.to_i format.shift end end if format.first == ':' then hash = true format.shift end if format.first == '&' then block = true format.shift end # if the format string is not empty there's a bug in the C code, ignore it args = [] position = 1 (1...(position + lead)).each do |index| args << "p#{index}" end position += lead (position...(position + opt)).each do |index| args << "p#{index} = v#{index}" end position += opt if var then args << '*args' position += 1 end (position...(position + trail)).each do |index| args << "p#{index}" end position += trail if hash then args << "p#{position} = {}" end args << '&block' if block "(#{args.join ', '})" end ## # Removes lines that are commented out that might otherwise get picked up # when scanning for classes and methods def remove_commented_out_lines @content = @content.gsub(%r%//.*rb_define_%, '//') end ## # Extracts the classes, modules, methods, attributes, constants and aliases # from a C file and returns an RDoc::TopLevel for this file def scan remove_commented_out_lines do_classes_and_modules do_missing do_constants do_methods do_includes do_aliases do_attrs deduplicate_call_seq @store.add_c_variables self @top_level end end PK ]U+gems/rdoc-6.2.1.1/lib/rdoc/parser/simple.rbnu[# frozen_string_literal: true ## # Parse a non-source file. We basically take the whole thing as one big # comment. class RDoc::Parser::Simple < RDoc::Parser include RDoc::Parser::Text parse_files_matching(//) attr_reader :content # :nodoc: ## # Prepare to parse a plain file def initialize(top_level, file_name, content, options, stats) super preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include @content = preprocess.handle @content, @top_level end ## # Extract the file contents and attach them to the TopLevel as a comment def scan comment = remove_coding_comment @content comment = remove_private_comment comment comment = RDoc::Comment.new comment, @top_level @top_level.comment = comment @top_level end ## # Removes the encoding magic comment from +text+ def remove_coding_comment text text.sub(/\A# .*coding[=:].*$/, '') end ## # Removes private comments. # # Unlike RDoc::Comment#remove_private this implementation only looks for two # dashes at the beginning of the line. Three or more dashes are considered # to be a rule and ignored. def remove_private_comment comment # Workaround for gsub encoding for Ruby 1.9.2 and earlier empty = '' empty = RDoc::Encoding.change_encoding empty, comment.encoding comment = comment.gsub(%r%^--\n.*?^\+\+\n?%m, empty) comment.sub(%r%^--\n.*%m, empty) end end PK ]733)gems/rdoc-6.2.1.1/lib/rdoc/parser/text.rbnu[# frozen_string_literal: true ## # Indicates this parser is text and doesn't contain code constructs. # # Include this module in a RDoc::Parser subclass to make it show up as a file, # not as part of a class or module. #-- # This is not named File to avoid overriding ::File module RDoc::Parser::Text end PK ]_A-gems/rdoc-6.2.1.1/lib/rdoc/parser/markdown.rbnu[# frozen_string_literal: true ## # Parse a Markdown format file. The parsed RDoc::Markup::Document is attached # as a file comment. class RDoc::Parser::Markdown < RDoc::Parser include RDoc::Parser::Text parse_files_matching(/\.(md|markdown)(?:\.[^.]+)?$/) ## # Creates an Markdown-format TopLevel for the given file. def scan comment = RDoc::Comment.new @content, @top_level comment.format = 'markdown' @top_level.comment = comment end end PK ] />>5gems/rdoc-6.2.1.1/lib/rdoc/parser/ripper_state_lex.rbnu[# frozen_string_literal: true require 'ripper' class RDoc::Parser::RipperStateLex # TODO: Remove this constants after Ruby 2.4 EOL RIPPER_HAS_LEX_STATE = Ripper::Filter.method_defined?(:state) Token = Struct.new(:line_no, :char_no, :kind, :text, :state) EXPR_NONE = 0 EXPR_BEG = 1 EXPR_END = 2 EXPR_ENDARG = 4 EXPR_ENDFN = 8 EXPR_ARG = 16 EXPR_CMDARG = 32 EXPR_MID = 64 EXPR_FNAME = 128 EXPR_DOT = 256 EXPR_CLASS = 512 EXPR_LABEL = 1024 EXPR_LABELED = 2048 EXPR_FITEM = 4096 EXPR_VALUE = EXPR_BEG EXPR_BEG_ANY = (EXPR_BEG | EXPR_MID | EXPR_CLASS) EXPR_ARG_ANY = (EXPR_ARG | EXPR_CMDARG) EXPR_END_ANY = (EXPR_END | EXPR_ENDARG | EXPR_ENDFN) class InnerStateLex < Ripper::Filter attr_accessor :lex_state def initialize(code) @lex_state = EXPR_BEG @in_fname = false @continue = false reset super(code) end def reset @command_start = false @cmd_state = @command_start end def on_nl(tok, data) case @lex_state when EXPR_FNAME, EXPR_DOT @continue = true else @continue = false @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0 end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_ignored_nl(tok, data) case @lex_state when EXPR_FNAME, EXPR_DOT @continue = true else @continue = false @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0 end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_op(tok, data) case tok when '&', '|', '!', '!=', '!~' case @lex_state when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end when '<<' # TODO next token? case @lex_state when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end when '?' @lex_state = EXPR_BEG when '&&', '||', '+=', '-=', '*=', '**=', '&=', '|=', '^=', '<<=', '>>=', '||=', '&&=' @lex_state = EXPR_BEG when '::' case @lex_state when EXPR_ARG, EXPR_CMDARG @lex_state = EXPR_DOT when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end else case @lex_state when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_kw(tok, data) case tok when 'class' @lex_state = EXPR_CLASS @in_fname = true when 'def' @lex_state = EXPR_FNAME @continue = true @in_fname = true when 'if', 'unless', 'while', 'until' if ((EXPR_MID | EXPR_END | EXPR_ENDARG | EXPR_ENDFN | EXPR_ARG | EXPR_CMDARG) & @lex_state) != 0 # postfix if @lex_state = EXPR_BEG | EXPR_LABEL else @lex_state = EXPR_BEG end when 'begin', 'case', 'when' @lex_state = EXPR_BEG when 'return', 'break' @lex_state = EXPR_MID else if @lex_state == EXPR_FNAME @lex_state = EXPR_END else @lex_state = EXPR_END end end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_tstring_beg(tok, data) @lex_state = EXPR_BEG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_tstring_end(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_CHAR(tok, data) @lex_state = EXPR_END data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_period(tok, data) @lex_state = EXPR_DOT data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_int(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_float(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_rational(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_imaginary(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_symbeg(tok, data) @lex_state = EXPR_FNAME @continue = true @in_fname = true data << Token.new(lineno, column, __method__, tok, @lex_state) end private def on_variables(event, tok, data) if @in_fname @lex_state = EXPR_ENDFN @in_fname = false @continue = false elsif @continue case @lex_state when EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_ENDFN @continue = false end else @lex_state = EXPR_CMDARG end data << Token.new(lineno, column, event, tok, @lex_state) end def on_ident(tok, data) on_variables(__method__, tok, data) end def on_ivar(tok, data) @lex_state = EXPR_END on_variables(__method__, tok, data) end def on_cvar(tok, data) @lex_state = EXPR_END on_variables(__method__, tok, data) end def on_gvar(tok, data) @lex_state = EXPR_END on_variables(__method__, tok, data) end def on_backref(tok, data) @lex_state = EXPR_END on_variables(__method__, tok, data) end def on_lparen(tok, data) @lex_state = EXPR_LABEL | EXPR_BEG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_rparen(tok, data) @lex_state = EXPR_ENDFN data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_lbrace(tok, data) @lex_state = EXPR_LABEL | EXPR_BEG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_rbrace(tok, data) @lex_state = EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_lbracket(tok, data) @lex_state = EXPR_LABEL | EXPR_BEG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_rbracket(tok, data) @lex_state = EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_const(tok, data) case @lex_state when EXPR_FNAME @lex_state = EXPR_ENDFN when EXPR_CLASS, EXPR_CMDARG, EXPR_MID @lex_state = EXPR_ARG else @lex_state = EXPR_CMDARG end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_sp(tok, data) data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_comma(tok, data) @lex_state = EXPR_BEG | EXPR_LABEL if (EXPR_ARG_ANY & @lex_state) != 0 data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_comment(tok, data) @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0 data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_ignored_sp(tok, data) @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0 data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_heredoc_beg(tok, data) data << Token.new(lineno, column, __method__, tok, @lex_state) @lex_state = EXPR_END data end def on_heredoc_end(tok, data) data << Token.new(lineno, column, __method__, tok, @lex_state) @lex_state = EXPR_BEG data end def on_default(event, tok, data) reset data << Token.new(lineno, column, event, tok, @lex_state) end end unless RIPPER_HAS_LEX_STATE class InnerStateLex < Ripper::Filter def initialize(code) super(code) end def on_default(event, tok, data) data << Token.new(lineno, column, event, tok, state) end end if RIPPER_HAS_LEX_STATE def get_squashed_tk if @buf.empty? tk = @tokens.shift else tk = @buf.shift end return nil if tk.nil? case tk[:kind] when :on_symbeg then tk = get_symbol_tk(tk) when :on_tstring_beg then tk = get_string_tk(tk) when :on_backtick then if (tk[:state] & (EXPR_FNAME | EXPR_ENDFN)) != 0 @inner_lex.lex_state = EXPR_ARG unless RIPPER_HAS_LEX_STATE tk[:kind] = :on_ident tk[:state] = Ripper::Lexer.const_defined?(:State) ? Ripper::Lexer::State.new(EXPR_ARG) : EXPR_ARG else tk = get_string_tk(tk) end when :on_regexp_beg then tk = get_regexp_tk(tk) when :on_embdoc_beg then tk = get_embdoc_tk(tk) when :on_heredoc_beg then @heredoc_queue << retrieve_heredoc_info(tk) @inner_lex.lex_state = EXPR_END unless RIPPER_HAS_LEX_STATE when :on_nl, :on_ignored_nl, :on_comment, :on_heredoc_end then if !@heredoc_queue.empty? get_heredoc_tk(*@heredoc_queue.shift) elsif tk[:text].nil? # :on_ignored_nl sometimes gives nil tk[:text] = '' end when :on_words_beg then tk = get_words_tk(tk) when :on_qwords_beg then tk = get_words_tk(tk) when :on_symbols_beg then tk = get_words_tk(tk) when :on_qsymbols_beg then tk = get_words_tk(tk) when :on_op then if '&.' == tk[:text] tk[:kind] = :on_period else tk = get_op_tk(tk) end end tk end private def get_symbol_tk(tk) is_symbol = true symbol_tk = Token.new(tk.line_no, tk.char_no, :on_symbol) if ":'" == tk[:text] or ':"' == tk[:text] tk1 = get_string_tk(tk) symbol_tk[:text] = tk1[:text] symbol_tk[:state] = tk1[:state] else case (tk1 = get_squashed_tk)[:kind] when :on_ident symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_tstring_content symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = get_squashed_tk[:state] # skip :on_tstring_end when :on_tstring_end symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_op symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_ivar symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_cvar symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_gvar symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_const symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_kw symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] else is_symbol = false tk = tk1 end end if is_symbol tk = symbol_tk end tk end private def get_string_tk(tk) string = tk[:text] state = nil kind = :on_tstring loop do inner_str_tk = get_squashed_tk if inner_str_tk.nil? break elsif :on_tstring_end == inner_str_tk[:kind] string = string + inner_str_tk[:text] state = inner_str_tk[:state] break elsif :on_label_end == inner_str_tk[:kind] string = string + inner_str_tk[:text] state = inner_str_tk[:state] kind = :on_symbol break else string = string + inner_str_tk[:text] if :on_embexpr_beg == inner_str_tk[:kind] then kind = :on_dstring if :on_tstring == kind end end end Token.new(tk.line_no, tk.char_no, kind, string, state) end private def get_regexp_tk(tk) string = tk[:text] state = nil loop do inner_str_tk = get_squashed_tk if inner_str_tk.nil? break elsif :on_regexp_end == inner_str_tk[:kind] string = string + inner_str_tk[:text] state = inner_str_tk[:state] break else string = string + inner_str_tk[:text] end end Token.new(tk.line_no, tk.char_no, :on_regexp, string, state) end private def get_embdoc_tk(tk) string = tk[:text] until :on_embdoc_end == (embdoc_tk = get_squashed_tk)[:kind] do string = string + embdoc_tk[:text] end string = string + embdoc_tk[:text] Token.new(tk.line_no, tk.char_no, :on_embdoc, string, embdoc_tk.state) end private def get_heredoc_tk(heredoc_name, indent) string = '' start_tk = nil prev_tk = nil until heredoc_end?(heredoc_name, indent, tk = @tokens.shift) do start_tk = tk unless start_tk if (prev_tk.nil? or "\n" == prev_tk[:text][-1]) and 0 != tk[:char_no] string = string + (' ' * tk[:char_no]) end string = string + tk[:text] prev_tk = tk end start_tk = tk unless start_tk prev_tk = tk unless prev_tk @buf.unshift tk # closing heredoc heredoc_tk = Token.new(start_tk.line_no, start_tk.char_no, :on_heredoc, string, prev_tk.state) @buf.unshift heredoc_tk end private def retrieve_heredoc_info(tk) name = tk[:text].gsub(/\A<<[-~]?(['"`]?)(.+)\1\z/, '\2') indent = tk[:text] =~ /\A<<[-~]/ [name, indent] end private def heredoc_end?(name, indent, tk) result = false if :on_heredoc_end == tk[:kind] then tk_name = tk[:text].chomp tk_name.lstrip! if indent if name == tk_name result = true end end result end private def get_words_tk(tk) string = '' start_token = tk[:text] start_quote = tk[:text].rstrip[-1] line_no = tk[:line_no] char_no = tk[:char_no] state = tk[:state] end_quote = case start_quote when ?( then ?) when ?[ then ?] when ?{ then ?} when ?< then ?> else start_quote end end_token = nil loop do tk = get_squashed_tk if tk.nil? end_token = end_quote break elsif :on_tstring_content == tk[:kind] then string += tk[:text] elsif :on_words_sep == tk[:kind] or :on_tstring_end == tk[:kind] then if end_quote == tk[:text].strip then end_token = tk[:text] break else string += tk[:text] end else string += tk[:text] end end text = "#{start_token}#{string}#{end_token}" Token.new(line_no, char_no, :on_dstring, text, state) end private def get_op_tk(tk) redefinable_operators = %w[! != !~ % & * ** + +@ - -@ / < << <= <=> == === =~ > >= >> [] []= ^ ` | ~] if redefinable_operators.include?(tk[:text]) and tk[:state] == EXPR_ARG then @inner_lex.lex_state = EXPR_ARG unless RIPPER_HAS_LEX_STATE tk[:state] = Ripper::Lexer.const_defined?(:State) ? Ripper::Lexer::State.new(EXPR_ARG) : EXPR_ARG tk[:kind] = :on_ident elsif tk[:text] =~ /^[-+]$/ then tk_ahead = get_squashed_tk case tk_ahead[:kind] when :on_int, :on_float, :on_rational, :on_imaginary then tk[:text] += tk_ahead[:text] tk[:kind] = tk_ahead[:kind] tk[:state] = tk_ahead[:state] when :on_heredoc_beg, :on_tstring, :on_dstring # frozen/non-frozen string literal tk[:text] += tk_ahead[:text] tk[:kind] = tk_ahead[:kind] tk[:state] = tk_ahead[:state] else @buf.unshift tk_ahead end end tk end def initialize(code) @buf = [] @heredoc_queue = [] @inner_lex = InnerStateLex.new(code) @tokens = @inner_lex.parse([]) end def self.parse(code) lex = self.new(code) tokens = [] begin while tk = lex.get_squashed_tk tokens.push tk end rescue StopIteration end tokens end def self.end?(token) (token[:state] & EXPR_END) end end PK ]mh fEE&gems/rdoc-6.2.1.1/lib/rdoc/markdown.rbnu[# coding: UTF-8 # frozen_string_literal: true # :markup: markdown ## # RDoc::Markdown as described by the [markdown syntax][syntax]. # # To choose Markdown as your only default format see # RDoc::Options@Saved+Options for instructions on setting up a `.doc_options` # file to store your project default. # # ## Usage # # Here is a brief example of using this parse to read a markdown file by hand. # # data = File.read("README.md") # formatter = RDoc::Markup::ToHtml.new(RDoc::Options.new, nil) # html = RDoc::Markdown.parse(data).accept(formatter) # # # do something with html # # ## Extensions # # The following markdown extensions are supported by the parser, but not all # are used in RDoc output by default. # # ### RDoc # # The RDoc Markdown parser has the following built-in behaviors that cannot be # disabled. # # Underscores embedded in words are never interpreted as emphasis. (While the # [markdown dingus][dingus] emphasizes in-word underscores, neither the # Markdown syntax nor MarkdownTest mention this behavior.) # # For HTML output, RDoc always auto-links bare URLs. # # ### Break on Newline # # The break_on_newline extension converts all newlines into hard line breaks # as in [Github Flavored Markdown][GFM]. This extension is disabled by # default. # # ### CSS # # The #css extension enables CSS blocks to be included in the output, but they # are not used for any built-in RDoc output format. This extension is disabled # by default. # # Example: # # # # ### Definition Lists # # The definition_lists extension allows definition lists using the [PHP # Markdown Extra syntax][PHPE], but only one label and definition are supported # at this time. This extension is enabled by default. # # Example: # # ``` # cat # : A small furry mammal # that seems to sleep a lot # # ant # : A little insect that is known # to enjoy picnics # # ``` # # Produces: # # cat # : A small furry mammal # that seems to sleep a lot # # ant # : A little insect that is known # to enjoy picnics # # ### Strike # # Example: # # ``` # This is ~~striked~~. # ``` # # Produces: # # This is ~~striked~~. # # ### Github # # The #github extension enables a partial set of [Github Flavored Markdown] # [GFM]. This extension is enabled by default. # # Supported github extensions include: # # #### Fenced code blocks # # Use ` ``` ` around a block of code instead of indenting it four spaces. # # #### Syntax highlighting # # Use ` ``` ruby ` as the start of a code fence to add syntax highlighting. # (Currently only `ruby` syntax is supported). # # ### HTML # # Enables raw HTML to be included in the output. This extension is enabled by # default. # # Example: # # # ... #
    # # ### Notes # # The #notes extension enables footnote support. This extension is enabled by # default. # # Example: # # Here is some text[^1] including an inline footnote ^[for short footnotes] # # ... # # [^1]: With the footnote text down at the bottom # # Produces: # # Here is some text[^1] including an inline footnote ^[for short footnotes] # # [^1]: With the footnote text down at the bottom # # ## Limitations # # * Link titles are not used # * Footnotes are collapsed into a single paragraph # # ## Author # # This markdown parser is a port to kpeg from [peg-markdown][pegmarkdown] by # John MacFarlane. # # It is used under the MIT license: # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # The port to kpeg was performed by Eric Hodel and Evan Phoenix # # [dingus]: http://daringfireball.net/projects/markdown/dingus # [GFM]: http://github.github.com/github-flavored-markdown/ # [pegmarkdown]: https://github.com/jgm/peg-markdown # [PHPE]: http://michelf.com/projects/php-markdown/extra/#def-list # [syntax]: http://daringfireball.net/projects/markdown/syntax #-- # Last updated to jgm/peg-markdown commit 8f8fc22ef0 class RDoc::Markdown # :stopdoc: # This is distinct from setup_parser so that a standalone parser # can redefine #initialize and still have access to the proper # parser setup code. def initialize(str, debug=false) setup_parser(str, debug) end # Prepares for parsing +str+. If you define a custom initialize you must # call this method before #parse def setup_parser(str, debug=false) set_string str, 0 @memoizations = Hash.new { |h,k| h[k] = {} } @result = nil @failed_rule = nil @failing_rule_offset = -1 setup_foreign_grammar end attr_reader :string attr_reader :failing_rule_offset attr_accessor :result, :pos def current_column(target=pos) if c = string.rindex("\n", target-1) return target - c - 1 end target + 1 end def current_line(target=pos) cur_offset = 0 cur_line = 0 string.each_line do |line| cur_line += 1 cur_offset += line.size return cur_line if cur_offset >= target end -1 end def lines lines = [] string.each_line { |l| lines << l } lines end def get_text(start) @string[start..@pos-1] end # Sets the string and current parsing position for the parser. def set_string string, pos @string = string @string_size = string ? string.size : 0 @pos = pos end def show_pos width = 10 if @pos < width "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")" else "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")" end end def failure_info l = current_line @failing_rule_offset c = current_column @failing_rule_offset if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'" else "line #{l}, column #{c}: failed rule '#{@failed_rule}'" end end def failure_caret l = current_line @failing_rule_offset c = current_column @failing_rule_offset line = lines[l-1] "#{line}\n#{' ' * (c - 1)}^" end def failure_character l = current_line @failing_rule_offset c = current_column @failing_rule_offset lines[l-1][c-1, 1] end def failure_oneline l = current_line @failing_rule_offset c = current_column @failing_rule_offset char = lines[l-1][c-1, 1] if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'" else "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'" end end class ParseError < RuntimeError end def raise_error raise ParseError, failure_oneline end def show_error(io=STDOUT) error_pos = @failing_rule_offset line_no = current_line(error_pos) col_no = current_column(error_pos) io.puts "On line #{line_no}, column #{col_no}:" if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')" else io.puts "Failed to match rule '#{@failed_rule}'" end io.puts "Got: #{string[error_pos,1].inspect}" line = lines[line_no-1] io.puts "=> #{line}" io.print(" " * (col_no + 3)) io.puts "^" end def set_failed_rule(name) if @pos > @failing_rule_offset @failed_rule = name @failing_rule_offset = @pos end end attr_reader :failed_rule def match_string(str) len = str.size if @string[pos,len] == str @pos += len return str end return nil end def scan(reg) if m = reg.match(@string[@pos..-1]) width = m.end(0) @pos += width return true end return nil end if "".respond_to? :ord def get_byte if @pos >= @string_size return nil end s = @string[@pos].ord @pos += 1 s end else def get_byte if @pos >= @string_size return nil end s = @string[@pos] @pos += 1 s end end def parse(rule=nil) # We invoke the rules indirectly via apply # instead of by just calling them as methods because # if the rules use left recursion, apply needs to # manage that. if !rule apply(:_root) else method = rule.gsub("-","_hyphen_") apply :"_#{method}" end end class MemoEntry def initialize(ans, pos) @ans = ans @pos = pos @result = nil @set = false @left_rec = false end attr_reader :ans, :pos, :result, :set attr_accessor :left_rec def move!(ans, pos, result) @ans = ans @pos = pos @result = result @set = true @left_rec = false end end def external_invoke(other, rule, *args) old_pos = @pos old_string = @string set_string other.string, other.pos begin if val = __send__(rule, *args) other.pos = @pos other.result = @result else other.set_failed_rule "#{self.class}##{rule}" end val ensure set_string old_string, old_pos end end def apply_with_args(rule, *args) memo_key = [rule, args] if m = @memoizations[memo_key][@pos] @pos = m.pos if !m.set m.left_rec = true return nil end @result = m.result return m.ans else m = MemoEntry.new(nil, @pos) @memoizations[memo_key][@pos] = m start_pos = @pos ans = __send__ rule, *args lr = m.left_rec m.move! ans, @pos, @result # Don't bother trying to grow the left recursion # if it's failing straight away (thus there is no seed) if ans and lr return grow_lr(rule, args, start_pos, m) else return ans end end end def apply(rule) if m = @memoizations[rule][@pos] @pos = m.pos if !m.set m.left_rec = true return nil end @result = m.result return m.ans else m = MemoEntry.new(nil, @pos) @memoizations[rule][@pos] = m start_pos = @pos ans = __send__ rule lr = m.left_rec m.move! ans, @pos, @result # Don't bother trying to grow the left recursion # if it's failing straight away (thus there is no seed) if ans and lr return grow_lr(rule, nil, start_pos, m) else return ans end end end def grow_lr(rule, args, start_pos, m) while true @pos = start_pos @result = m.result if args ans = __send__ rule, *args else ans = __send__ rule end return nil unless ans break if @pos <= m.pos m.move! ans, @pos, @result end @result = m.result @pos = m.pos return m.ans end class RuleInfo def initialize(name, rendered) @name = name @rendered = rendered end attr_reader :name, :rendered end def self.rule_info(name, rendered) RuleInfo.new(name, rendered) end # :startdoc: require 'rdoc' require 'rdoc/markup/to_joined_paragraph' require 'rdoc/markdown/entities' require 'rdoc/markdown/literals' ## # Supported extensions EXTENSIONS = [] ## # Extensions enabled by default DEFAULT_EXTENSIONS = [ :definition_lists, :github, :html, :notes, :strike, ] # :section: Extensions ## # Creates extension methods for the `name` extension to enable and disable # the extension and to query if they are active. def self.extension name EXTENSIONS << name define_method "#{name}?" do extension? name end define_method "#{name}=" do |enable| extension name, enable end end ## # Converts all newlines into hard breaks extension :break_on_newline ## # Allow style blocks extension :css ## # Allow PHP Markdown Extras style definition lists extension :definition_lists ## # Allow Github Flavored Markdown extension :github ## # Allow HTML extension :html ## # Enables the notes extension extension :notes ## # Enables the strike extension extension :strike # :section: ## # Parses the `markdown` document into an RDoc::Document using the default # extensions. def self.parse markdown parser = new parser.parse markdown end # TODO remove when kpeg 0.10 is released alias orig_initialize initialize # :nodoc: ## # Creates a new markdown parser that enables the given +extensions+. def initialize extensions = DEFAULT_EXTENSIONS, debug = false @debug = debug @formatter = RDoc::Markup::ToJoinedParagraph.new @extensions = extensions @references = nil @unlinked_references = nil @footnotes = nil @note_order = nil end ## # Wraps `text` in emphasis for rdoc inline formatting def emphasis text if text =~ /\A[a-z\d.\/]+\z/i then "_#{text}_" else "#{text}" end end ## # :category: Extensions # # Is the extension `name` enabled? def extension? name @extensions.include? name end ## # :category: Extensions # # Enables or disables the extension with `name` def extension name, enable if enable then @extensions |= [name] else @extensions -= [name] end end ## # Parses `text` in a clone of this parser. This is used for handling nested # lists the same way as markdown_parser. def inner_parse text # :nodoc: parser = clone parser.setup_parser text, @debug parser.peg_parse doc = parser.result doc.accept @formatter doc.parts end ## # Finds a link reference for `label` and creates a new link to it with # `content` as the link text. If `label` was not encountered in the # reference-gathering parser pass the label and content are reconstructed # with the linking `text` (usually whitespace). def link_to content, label = content, text = nil raise ParseError, 'enable notes extension' if content.start_with? '^' and label.equal? content if ref = @references[label] then "{#{content}}[#{ref}]" elsif label.equal? content then "[#{content}]#{text}" else "[#{content}]#{text}[#{label}]" end end ## # Creates an RDoc::Markup::ListItem by parsing the `unparsed` content from # the first parsing pass. def list_item_from unparsed parsed = inner_parse unparsed.join RDoc::Markup::ListItem.new nil, *parsed end ## # Stores `label` as a note and fills in previously unknown note references. def note label #foottext = "rdoc-label:foottext-#{label}:footmark-#{label}" #ref.replace foottext if ref = @unlinked_notes.delete(label) @notes[label] = foottext #"{^1}[rdoc-label:footmark-#{label}:foottext-#{label}] " end ## # Creates a new link for the footnote `reference` and adds the reference to # the note order list for proper display at the end of the document. def note_for ref @note_order << ref label = @note_order.length "{*#{label}}[rdoc-label:foottext-#{label}:footmark-#{label}]" end ## # The internal kpeg parse method alias peg_parse parse # :nodoc: ## # Creates an RDoc::Markup::Paragraph from `parts` and including # extension-specific behavior def paragraph parts parts = parts.map do |part| if "\n" == part then RDoc::Markup::HardBreak.new else part end end if break_on_newline? RDoc::Markup::Paragraph.new(*parts) end ## # Parses `markdown` into an RDoc::Document def parse markdown @references = {} @unlinked_references = {} markdown += "\n\n" setup_parser markdown, @debug peg_parse 'References' if notes? then @footnotes = {} setup_parser markdown, @debug peg_parse 'Notes' # using note_order on the first pass would be a bug @note_order = [] end setup_parser markdown, @debug peg_parse doc = result if notes? and not @footnotes.empty? then doc << RDoc::Markup::Rule.new(1) @note_order.each_with_index do |ref, index| label = index + 1 note = @footnotes[ref] link = "{^#{label}}[rdoc-label:footmark-#{label}:foottext-#{label}] " note.parts.unshift link doc << note end end doc.accept @formatter doc end ## # Stores `label` as a reference to `link` and fills in previously unknown # link references. def reference label, link if ref = @unlinked_references.delete(label) then ref.replace link end @references[label] = link end ## # Wraps `text` in strong markup for rdoc inline formatting def strong text if text =~ /\A[a-z\d.\/-]+\z/i then "*#{text}*" else "#{text}" end end ## # Wraps `text` in strike markup for rdoc inline formatting def strike text if text =~ /\A[a-z\d.\/-]+\z/i then "~#{text}~" else "#{text}" end end # :stopdoc: def setup_foreign_grammar @_grammar_literals = RDoc::Markdown::Literals.new(nil) end # root = Doc def _root _tmp = apply(:_Doc) set_failed_rule :_root unless _tmp return _tmp end # Doc = BOM? Block*:a { RDoc::Markup::Document.new(*a.compact) } def _Doc _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_BOM) unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save break end _ary = [] while true _tmp = apply(:_Block) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Document.new(*a.compact) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Doc unless _tmp return _tmp end # Block = @BlankLine* (BlockQuote | Verbatim | CodeFence | Note | Reference | HorizontalRule | Heading | OrderedList | BulletList | DefinitionList | HtmlBlock | StyleBlock | Para | Plain) def _Block _save = self.pos while true # sequence while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _save2 = self.pos while true # choice _tmp = apply(:_BlockQuote) break if _tmp self.pos = _save2 _tmp = apply(:_Verbatim) break if _tmp self.pos = _save2 _tmp = apply(:_CodeFence) break if _tmp self.pos = _save2 _tmp = apply(:_Note) break if _tmp self.pos = _save2 _tmp = apply(:_Reference) break if _tmp self.pos = _save2 _tmp = apply(:_HorizontalRule) break if _tmp self.pos = _save2 _tmp = apply(:_Heading) break if _tmp self.pos = _save2 _tmp = apply(:_OrderedList) break if _tmp self.pos = _save2 _tmp = apply(:_BulletList) break if _tmp self.pos = _save2 _tmp = apply(:_DefinitionList) break if _tmp self.pos = _save2 _tmp = apply(:_HtmlBlock) break if _tmp self.pos = _save2 _tmp = apply(:_StyleBlock) break if _tmp self.pos = _save2 _tmp = apply(:_Para) break if _tmp self.pos = _save2 _tmp = apply(:_Plain) break if _tmp self.pos = _save2 break end # end choice unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Block unless _tmp return _tmp end # Para = @NonindentSpace Inlines:a @BlankLine+ { paragraph a } def _Para _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _tmp = apply(:_Inlines) a = @result unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; paragraph a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Para unless _tmp return _tmp end # Plain = Inlines:a { paragraph a } def _Plain _save = self.pos while true # sequence _tmp = apply(:_Inlines) a = @result unless _tmp self.pos = _save break end @result = begin; paragraph a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Plain unless _tmp return _tmp end # AtxInline = !@Newline !(@Sp /#*/ @Sp @Newline) Inline def _AtxInline _save = self.pos while true # sequence _save1 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save3 break end _tmp = scan(/\A(?-mix:#*)/) unless _tmp self.pos = _save3 break end _tmp = _Sp() unless _tmp self.pos = _save3 break end _tmp = _Newline() unless _tmp self.pos = _save3 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _tmp = apply(:_Inline) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AtxInline unless _tmp return _tmp end # AtxStart = < /\#{1,6}/ > { text.length } def _AtxStart _save = self.pos while true # sequence _text_start = self.pos _tmp = scan(/\A(?-mix:\#{1,6})/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text.length ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AtxStart unless _tmp return _tmp end # AtxHeading = AtxStart:s @Sp AtxInline+:a (@Sp /#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) } def _AtxHeading _save = self.pos while true # sequence _tmp = apply(:_AtxStart) s = @result unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _save1 = self.pos _ary = [] _tmp = apply(:_AtxInline) if _tmp _ary << @result while true _tmp = apply(:_AtxInline) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save3 break end _tmp = scan(/\A(?-mix:#*)/) unless _tmp self.pos = _save3 break end _tmp = _Sp() unless _tmp self.pos = _save3 end break end # end sequence unless _tmp _tmp = true self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Heading.new(s, a.join) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AtxHeading unless _tmp return _tmp end # SetextHeading = (SetextHeading1 | SetextHeading2) def _SetextHeading _save = self.pos while true # choice _tmp = apply(:_SetextHeading1) break if _tmp self.pos = _save _tmp = apply(:_SetextHeading2) break if _tmp self.pos = _save break end # end choice set_failed_rule :_SetextHeading unless _tmp return _tmp end # SetextBottom1 = /={1,}/ @Newline def _SetextBottom1 _save = self.pos while true # sequence _tmp = scan(/\A(?-mix:={1,})/) unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_SetextBottom1 unless _tmp return _tmp end # SetextBottom2 = /-{1,}/ @Newline def _SetextBottom2 _save = self.pos while true # sequence _tmp = scan(/\A(?-mix:-{1,})/) unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_SetextBottom2 unless _tmp return _tmp end # SetextHeading1 = &(@RawLine SetextBottom1) @StartList:a (!@Endline Inline:b { a << b })+ @Sp @Newline SetextBottom1 { RDoc::Markup::Heading.new(1, a.join) } def _SetextHeading1 _save = self.pos while true # sequence _save1 = self.pos _save2 = self.pos while true # sequence _tmp = _RawLine() unless _tmp self.pos = _save2 break end _tmp = apply(:_SetextBottom1) unless _tmp self.pos = _save2 end break end # end sequence self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save3 = self.pos _save4 = self.pos while true # sequence _save5 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence if _tmp while true _save6 = self.pos while true # sequence _save7 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save3 end unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _tmp = apply(:_SetextBottom1) unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Heading.new(1, a.join) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_SetextHeading1 unless _tmp return _tmp end # SetextHeading2 = &(@RawLine SetextBottom2) @StartList:a (!@Endline Inline:b { a << b })+ @Sp @Newline SetextBottom2 { RDoc::Markup::Heading.new(2, a.join) } def _SetextHeading2 _save = self.pos while true # sequence _save1 = self.pos _save2 = self.pos while true # sequence _tmp = _RawLine() unless _tmp self.pos = _save2 break end _tmp = apply(:_SetextBottom2) unless _tmp self.pos = _save2 end break end # end sequence self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save3 = self.pos _save4 = self.pos while true # sequence _save5 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence if _tmp while true _save6 = self.pos while true # sequence _save7 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save3 end unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _tmp = apply(:_SetextBottom2) unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Heading.new(2, a.join) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_SetextHeading2 unless _tmp return _tmp end # Heading = (SetextHeading | AtxHeading) def _Heading _save = self.pos while true # choice _tmp = apply(:_SetextHeading) break if _tmp self.pos = _save _tmp = apply(:_AtxHeading) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Heading unless _tmp return _tmp end # BlockQuote = BlockQuoteRaw:a { RDoc::Markup::BlockQuote.new(*a) } def _BlockQuote _save = self.pos while true # sequence _tmp = apply(:_BlockQuoteRaw) a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::BlockQuote.new(*a) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_BlockQuote unless _tmp return _tmp end # BlockQuoteRaw = @StartList:a (">" " "? Line:l { a << l } (!">" !@BlankLine Line:c { a << c })* (@BlankLine:n { a << n })*)+ { inner_parse a.join } def _BlockQuoteRaw _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos while true # sequence _tmp = match_string(">") unless _tmp self.pos = _save2 break end _save3 = self.pos _tmp = match_string(" ") unless _tmp _tmp = true self.pos = _save3 end unless _tmp self.pos = _save2 break end _tmp = apply(:_Line) l = @result unless _tmp self.pos = _save2 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save2 break end while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _save7 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save5 break end _tmp = apply(:_Line) c = @result unless _tmp self.pos = _save5 break end @result = begin; a << c ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save2 break end while true _save9 = self.pos while true # sequence _tmp = _BlankLine() n = @result unless _tmp self.pos = _save9 break end @result = begin; a << n ; end _tmp = true unless _tmp self.pos = _save9 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence if _tmp while true _save10 = self.pos while true # sequence _tmp = match_string(">") unless _tmp self.pos = _save10 break end _save11 = self.pos _tmp = match_string(" ") unless _tmp _tmp = true self.pos = _save11 end unless _tmp self.pos = _save10 break end _tmp = apply(:_Line) l = @result unless _tmp self.pos = _save10 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save10 break end while true _save13 = self.pos while true # sequence _save14 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save14 unless _tmp self.pos = _save13 break end _save15 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save15 unless _tmp self.pos = _save13 break end _tmp = apply(:_Line) c = @result unless _tmp self.pos = _save13 break end @result = begin; a << c ; end _tmp = true unless _tmp self.pos = _save13 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save10 break end while true _save17 = self.pos while true # sequence _tmp = _BlankLine() n = @result unless _tmp self.pos = _save17 break end @result = begin; a << n ; end _tmp = true unless _tmp self.pos = _save17 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save10 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; inner_parse a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_BlockQuoteRaw unless _tmp return _tmp end # NonblankIndentedLine = !@BlankLine IndentedLine def _NonblankIndentedLine _save = self.pos while true # sequence _save1 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_IndentedLine) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_NonblankIndentedLine unless _tmp return _tmp end # VerbatimChunk = @BlankLine*:a NonblankIndentedLine+:b { a.concat b } def _VerbatimChunk _save = self.pos while true # sequence _ary = [] while true _tmp = _BlankLine() _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary a = @result unless _tmp self.pos = _save break end _save2 = self.pos _ary = [] _tmp = apply(:_NonblankIndentedLine) if _tmp _ary << @result while true _tmp = apply(:_NonblankIndentedLine) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save2 end b = @result unless _tmp self.pos = _save break end @result = begin; a.concat b ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_VerbatimChunk unless _tmp return _tmp end # Verbatim = VerbatimChunk+:a { RDoc::Markup::Verbatim.new(*a.flatten) } def _Verbatim _save = self.pos while true # sequence _save1 = self.pos _ary = [] _tmp = apply(:_VerbatimChunk) if _tmp _ary << @result while true _tmp = apply(:_VerbatimChunk) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Verbatim.new(*a.flatten) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Verbatim unless _tmp return _tmp end # HorizontalRule = @NonindentSpace ("*" @Sp "*" @Sp "*" (@Sp "*")* | "-" @Sp "-" @Sp "-" (@Sp "-")* | "_" @Sp "_" @Sp "_" (@Sp "_")*) @Sp @Newline @BlankLine+ { RDoc::Markup::Rule.new 1 } def _HorizontalRule _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _save2 = self.pos while true # sequence _tmp = match_string("*") unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 break end _tmp = match_string("*") unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 break end _tmp = match_string("*") unless _tmp self.pos = _save2 break end while true _save4 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save4 break end _tmp = match_string("*") unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save1 _save5 = self.pos while true # sequence _tmp = match_string("-") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = match_string("-") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = match_string("-") unless _tmp self.pos = _save5 break end while true _save7 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save7 break end _tmp = match_string("-") unless _tmp self.pos = _save7 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save1 _save8 = self.pos while true # sequence _tmp = match_string("_") unless _tmp self.pos = _save8 break end _tmp = _Sp() unless _tmp self.pos = _save8 break end _tmp = match_string("_") unless _tmp self.pos = _save8 break end _tmp = _Sp() unless _tmp self.pos = _save8 break end _tmp = match_string("_") unless _tmp self.pos = _save8 break end while true _save10 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save10 break end _tmp = match_string("_") unless _tmp self.pos = _save10 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save8 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _save11 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save11 end unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Rule.new 1 ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HorizontalRule unless _tmp return _tmp end # Bullet = !HorizontalRule @NonindentSpace /[+*-]/ @Spacechar+ def _Bullet _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_HorizontalRule) _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _tmp = scan(/\A(?-mix:[+*-])/) unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _Spacechar() if _tmp while true _tmp = _Spacechar() break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Bullet unless _tmp return _tmp end # BulletList = &Bullet (ListTight | ListLoose):a { RDoc::Markup::List.new(:BULLET, *a) } def _BulletList _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_Bullet) self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos while true # choice _tmp = apply(:_ListTight) break if _tmp self.pos = _save2 _tmp = apply(:_ListLoose) break if _tmp self.pos = _save2 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::List.new(:BULLET, *a) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_BulletList unless _tmp return _tmp end # ListTight = ListItemTight+:a @BlankLine* !(Bullet | Enumerator) { a } def _ListTight _save = self.pos while true # sequence _save1 = self.pos _ary = [] _tmp = apply(:_ListItemTight) if _tmp _ary << @result while true _tmp = apply(:_ListItemTight) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end a = @result unless _tmp self.pos = _save break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _save3 = self.pos _save4 = self.pos while true # choice _tmp = apply(:_Bullet) break if _tmp self.pos = _save4 _tmp = apply(:_Enumerator) break if _tmp self.pos = _save4 break end # end choice _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListTight unless _tmp return _tmp end # ListLoose = @StartList:a (ListItem:b @BlankLine* { a << b })+ { a } def _ListLoose _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos while true # sequence _tmp = apply(:_ListItem) b = @result unless _tmp self.pos = _save2 break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save2 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence if _tmp while true _save4 = self.pos while true # sequence _tmp = apply(:_ListItem) b = @result unless _tmp self.pos = _save4 break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListLoose unless _tmp return _tmp end # ListItem = (Bullet | Enumerator) @StartList:a ListBlock:b { a << b } (ListContinuationBlock:c { a.push(*c) })* { list_item_from a } def _ListItem _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_Bullet) break if _tmp self.pos = _save1 _tmp = apply(:_Enumerator) break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _tmp = apply(:_ListBlock) b = @result unless _tmp self.pos = _save break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save break end while true _save3 = self.pos while true # sequence _tmp = apply(:_ListContinuationBlock) c = @result unless _tmp self.pos = _save3 break end @result = begin; a.push(*c) ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; list_item_from a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListItem unless _tmp return _tmp end # ListItemTight = (Bullet | Enumerator) ListBlock:a (!@BlankLine ListContinuationBlock:b { a.push(*b) })* !ListContinuationBlock { list_item_from a } def _ListItemTight _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_Bullet) break if _tmp self.pos = _save1 _tmp = apply(:_Enumerator) break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_ListBlock) a = @result unless _tmp self.pos = _save break end while true _save3 = self.pos while true # sequence _save4 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_ListContinuationBlock) b = @result unless _tmp self.pos = _save3 break end @result = begin; a.push(*b) ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _save5 = self.pos _tmp = apply(:_ListContinuationBlock) _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save break end @result = begin; list_item_from a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListItemTight unless _tmp return _tmp end # ListBlock = !@BlankLine Line:a ListBlockLine*:c { [a, *c] } def _ListBlock _save = self.pos while true # sequence _save1 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_Line) a = @result unless _tmp self.pos = _save break end _ary = [] while true _tmp = apply(:_ListBlockLine) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary c = @result unless _tmp self.pos = _save break end @result = begin; [a, *c] ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListBlock unless _tmp return _tmp end # ListContinuationBlock = @StartList:a @BlankLine* { a << "\n" } (Indent ListBlock:b { a.concat b })+ { a } def _ListContinuationBlock _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; a << "\n" ; end _tmp = true unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _tmp = apply(:_Indent) unless _tmp self.pos = _save3 break end _tmp = apply(:_ListBlock) b = @result unless _tmp self.pos = _save3 break end @result = begin; a.concat b ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save4 = self.pos while true # sequence _tmp = apply(:_Indent) unless _tmp self.pos = _save4 break end _tmp = apply(:_ListBlock) b = @result unless _tmp self.pos = _save4 break end @result = begin; a.concat b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListContinuationBlock unless _tmp return _tmp end # Enumerator = @NonindentSpace [0-9]+ "." @Spacechar+ def _Enumerator _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos _tmp = get_byte if _tmp unless _tmp >= 48 and _tmp <= 57 self.pos = _save2 _tmp = nil end end if _tmp while true _save3 = self.pos _tmp = get_byte if _tmp unless _tmp >= 48 and _tmp <= 57 self.pos = _save3 _tmp = nil end end break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end _tmp = match_string(".") unless _tmp self.pos = _save break end _save4 = self.pos _tmp = _Spacechar() if _tmp while true _tmp = _Spacechar() break unless _tmp end _tmp = true else self.pos = _save4 end unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Enumerator unless _tmp return _tmp end # OrderedList = &Enumerator (ListTight | ListLoose):a { RDoc::Markup::List.new(:NUMBER, *a) } def _OrderedList _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_Enumerator) self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos while true # choice _tmp = apply(:_ListTight) break if _tmp self.pos = _save2 _tmp = apply(:_ListLoose) break if _tmp self.pos = _save2 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::List.new(:NUMBER, *a) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_OrderedList unless _tmp return _tmp end # ListBlockLine = !@BlankLine !(Indent? (Bullet | Enumerator)) !HorizontalRule OptionallyIndentedLine def _ListBlockLine _save = self.pos while true # sequence _save1 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_Indent) unless _tmp _tmp = true self.pos = _save4 end unless _tmp self.pos = _save3 break end _save5 = self.pos while true # choice _tmp = apply(:_Bullet) break if _tmp self.pos = _save5 _tmp = apply(:_Enumerator) break if _tmp self.pos = _save5 break end # end choice unless _tmp self.pos = _save3 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _save6 = self.pos _tmp = apply(:_HorizontalRule) _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save break end _tmp = apply(:_OptionallyIndentedLine) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListBlockLine unless _tmp return _tmp end # HtmlOpenAnchor = "<" Spnl ("a" | "A") Spnl HtmlAttribute* ">" def _HtmlOpenAnchor _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("a") break if _tmp self.pos = _save1 _tmp = match_string("A") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlOpenAnchor unless _tmp return _tmp end # HtmlCloseAnchor = "<" Spnl "/" ("a" | "A") Spnl ">" def _HtmlCloseAnchor _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("a") break if _tmp self.pos = _save1 _tmp = match_string("A") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlCloseAnchor unless _tmp return _tmp end # HtmlAnchor = HtmlOpenAnchor (HtmlAnchor | !HtmlCloseAnchor .)* HtmlCloseAnchor def _HtmlAnchor _save = self.pos while true # sequence _tmp = apply(:_HtmlOpenAnchor) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlAnchor) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlCloseAnchor) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlCloseAnchor) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlAnchor unless _tmp return _tmp end # HtmlBlockOpenAddress = "<" Spnl ("address" | "ADDRESS") Spnl HtmlAttribute* ">" def _HtmlBlockOpenAddress _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("address") break if _tmp self.pos = _save1 _tmp = match_string("ADDRESS") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenAddress unless _tmp return _tmp end # HtmlBlockCloseAddress = "<" Spnl "/" ("address" | "ADDRESS") Spnl ">" def _HtmlBlockCloseAddress _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("address") break if _tmp self.pos = _save1 _tmp = match_string("ADDRESS") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseAddress unless _tmp return _tmp end # HtmlBlockAddress = HtmlBlockOpenAddress (HtmlBlockAddress | !HtmlBlockCloseAddress .)* HtmlBlockCloseAddress def _HtmlBlockAddress _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenAddress) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockAddress) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseAddress) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseAddress) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockAddress unless _tmp return _tmp end # HtmlBlockOpenBlockquote = "<" Spnl ("blockquote" | "BLOCKQUOTE") Spnl HtmlAttribute* ">" def _HtmlBlockOpenBlockquote _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("blockquote") break if _tmp self.pos = _save1 _tmp = match_string("BLOCKQUOTE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenBlockquote unless _tmp return _tmp end # HtmlBlockCloseBlockquote = "<" Spnl "/" ("blockquote" | "BLOCKQUOTE") Spnl ">" def _HtmlBlockCloseBlockquote _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("blockquote") break if _tmp self.pos = _save1 _tmp = match_string("BLOCKQUOTE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseBlockquote unless _tmp return _tmp end # HtmlBlockBlockquote = HtmlBlockOpenBlockquote (HtmlBlockBlockquote | !HtmlBlockCloseBlockquote .)* HtmlBlockCloseBlockquote def _HtmlBlockBlockquote _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenBlockquote) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockBlockquote) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseBlockquote) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseBlockquote) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockBlockquote unless _tmp return _tmp end # HtmlBlockOpenCenter = "<" Spnl ("center" | "CENTER") Spnl HtmlAttribute* ">" def _HtmlBlockOpenCenter _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("center") break if _tmp self.pos = _save1 _tmp = match_string("CENTER") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenCenter unless _tmp return _tmp end # HtmlBlockCloseCenter = "<" Spnl "/" ("center" | "CENTER") Spnl ">" def _HtmlBlockCloseCenter _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("center") break if _tmp self.pos = _save1 _tmp = match_string("CENTER") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseCenter unless _tmp return _tmp end # HtmlBlockCenter = HtmlBlockOpenCenter (HtmlBlockCenter | !HtmlBlockCloseCenter .)* HtmlBlockCloseCenter def _HtmlBlockCenter _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenCenter) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockCenter) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseCenter) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseCenter) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCenter unless _tmp return _tmp end # HtmlBlockOpenDir = "<" Spnl ("dir" | "DIR") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDir _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dir") break if _tmp self.pos = _save1 _tmp = match_string("DIR") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDir unless _tmp return _tmp end # HtmlBlockCloseDir = "<" Spnl "/" ("dir" | "DIR") Spnl ">" def _HtmlBlockCloseDir _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dir") break if _tmp self.pos = _save1 _tmp = match_string("DIR") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDir unless _tmp return _tmp end # HtmlBlockDir = HtmlBlockOpenDir (HtmlBlockDir | !HtmlBlockCloseDir .)* HtmlBlockCloseDir def _HtmlBlockDir _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDir) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDir) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDir) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDir) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDir unless _tmp return _tmp end # HtmlBlockOpenDiv = "<" Spnl ("div" | "DIV") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDiv _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("div") break if _tmp self.pos = _save1 _tmp = match_string("DIV") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDiv unless _tmp return _tmp end # HtmlBlockCloseDiv = "<" Spnl "/" ("div" | "DIV") Spnl ">" def _HtmlBlockCloseDiv _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("div") break if _tmp self.pos = _save1 _tmp = match_string("DIV") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDiv unless _tmp return _tmp end # HtmlBlockDiv = HtmlBlockOpenDiv (HtmlBlockDiv | !HtmlBlockCloseDiv .)* HtmlBlockCloseDiv def _HtmlBlockDiv _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDiv) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDiv) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDiv) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDiv) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDiv unless _tmp return _tmp end # HtmlBlockOpenDl = "<" Spnl ("dl" | "DL") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dl") break if _tmp self.pos = _save1 _tmp = match_string("DL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDl unless _tmp return _tmp end # HtmlBlockCloseDl = "<" Spnl "/" ("dl" | "DL") Spnl ">" def _HtmlBlockCloseDl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dl") break if _tmp self.pos = _save1 _tmp = match_string("DL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDl unless _tmp return _tmp end # HtmlBlockDl = HtmlBlockOpenDl (HtmlBlockDl | !HtmlBlockCloseDl .)* HtmlBlockCloseDl def _HtmlBlockDl _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDl) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDl) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDl) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDl) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDl unless _tmp return _tmp end # HtmlBlockOpenFieldset = "<" Spnl ("fieldset" | "FIELDSET") Spnl HtmlAttribute* ">" def _HtmlBlockOpenFieldset _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("fieldset") break if _tmp self.pos = _save1 _tmp = match_string("FIELDSET") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenFieldset unless _tmp return _tmp end # HtmlBlockCloseFieldset = "<" Spnl "/" ("fieldset" | "FIELDSET") Spnl ">" def _HtmlBlockCloseFieldset _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("fieldset") break if _tmp self.pos = _save1 _tmp = match_string("FIELDSET") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseFieldset unless _tmp return _tmp end # HtmlBlockFieldset = HtmlBlockOpenFieldset (HtmlBlockFieldset | !HtmlBlockCloseFieldset .)* HtmlBlockCloseFieldset def _HtmlBlockFieldset _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenFieldset) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockFieldset) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseFieldset) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseFieldset) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockFieldset unless _tmp return _tmp end # HtmlBlockOpenForm = "<" Spnl ("form" | "FORM") Spnl HtmlAttribute* ">" def _HtmlBlockOpenForm _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("form") break if _tmp self.pos = _save1 _tmp = match_string("FORM") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenForm unless _tmp return _tmp end # HtmlBlockCloseForm = "<" Spnl "/" ("form" | "FORM") Spnl ">" def _HtmlBlockCloseForm _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("form") break if _tmp self.pos = _save1 _tmp = match_string("FORM") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseForm unless _tmp return _tmp end # HtmlBlockForm = HtmlBlockOpenForm (HtmlBlockForm | !HtmlBlockCloseForm .)* HtmlBlockCloseForm def _HtmlBlockForm _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenForm) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockForm) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseForm) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseForm) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockForm unless _tmp return _tmp end # HtmlBlockOpenH1 = "<" Spnl ("h1" | "H1") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH1 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h1") break if _tmp self.pos = _save1 _tmp = match_string("H1") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH1 unless _tmp return _tmp end # HtmlBlockCloseH1 = "<" Spnl "/" ("h1" | "H1") Spnl ">" def _HtmlBlockCloseH1 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h1") break if _tmp self.pos = _save1 _tmp = match_string("H1") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH1 unless _tmp return _tmp end # HtmlBlockH1 = HtmlBlockOpenH1 (HtmlBlockH1 | !HtmlBlockCloseH1 .)* HtmlBlockCloseH1 def _HtmlBlockH1 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH1) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH1) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH1) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH1) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH1 unless _tmp return _tmp end # HtmlBlockOpenH2 = "<" Spnl ("h2" | "H2") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH2 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h2") break if _tmp self.pos = _save1 _tmp = match_string("H2") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH2 unless _tmp return _tmp end # HtmlBlockCloseH2 = "<" Spnl "/" ("h2" | "H2") Spnl ">" def _HtmlBlockCloseH2 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h2") break if _tmp self.pos = _save1 _tmp = match_string("H2") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH2 unless _tmp return _tmp end # HtmlBlockH2 = HtmlBlockOpenH2 (HtmlBlockH2 | !HtmlBlockCloseH2 .)* HtmlBlockCloseH2 def _HtmlBlockH2 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH2) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH2) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH2) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH2) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH2 unless _tmp return _tmp end # HtmlBlockOpenH3 = "<" Spnl ("h3" | "H3") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH3 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h3") break if _tmp self.pos = _save1 _tmp = match_string("H3") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH3 unless _tmp return _tmp end # HtmlBlockCloseH3 = "<" Spnl "/" ("h3" | "H3") Spnl ">" def _HtmlBlockCloseH3 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h3") break if _tmp self.pos = _save1 _tmp = match_string("H3") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH3 unless _tmp return _tmp end # HtmlBlockH3 = HtmlBlockOpenH3 (HtmlBlockH3 | !HtmlBlockCloseH3 .)* HtmlBlockCloseH3 def _HtmlBlockH3 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH3) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH3) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH3) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH3) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH3 unless _tmp return _tmp end # HtmlBlockOpenH4 = "<" Spnl ("h4" | "H4") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH4 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h4") break if _tmp self.pos = _save1 _tmp = match_string("H4") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH4 unless _tmp return _tmp end # HtmlBlockCloseH4 = "<" Spnl "/" ("h4" | "H4") Spnl ">" def _HtmlBlockCloseH4 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h4") break if _tmp self.pos = _save1 _tmp = match_string("H4") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH4 unless _tmp return _tmp end # HtmlBlockH4 = HtmlBlockOpenH4 (HtmlBlockH4 | !HtmlBlockCloseH4 .)* HtmlBlockCloseH4 def _HtmlBlockH4 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH4) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH4) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH4) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH4) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH4 unless _tmp return _tmp end # HtmlBlockOpenH5 = "<" Spnl ("h5" | "H5") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH5 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h5") break if _tmp self.pos = _save1 _tmp = match_string("H5") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH5 unless _tmp return _tmp end # HtmlBlockCloseH5 = "<" Spnl "/" ("h5" | "H5") Spnl ">" def _HtmlBlockCloseH5 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h5") break if _tmp self.pos = _save1 _tmp = match_string("H5") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH5 unless _tmp return _tmp end # HtmlBlockH5 = HtmlBlockOpenH5 (HtmlBlockH5 | !HtmlBlockCloseH5 .)* HtmlBlockCloseH5 def _HtmlBlockH5 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH5) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH5) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH5) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH5) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH5 unless _tmp return _tmp end # HtmlBlockOpenH6 = "<" Spnl ("h6" | "H6") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH6 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h6") break if _tmp self.pos = _save1 _tmp = match_string("H6") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH6 unless _tmp return _tmp end # HtmlBlockCloseH6 = "<" Spnl "/" ("h6" | "H6") Spnl ">" def _HtmlBlockCloseH6 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h6") break if _tmp self.pos = _save1 _tmp = match_string("H6") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH6 unless _tmp return _tmp end # HtmlBlockH6 = HtmlBlockOpenH6 (HtmlBlockH6 | !HtmlBlockCloseH6 .)* HtmlBlockCloseH6 def _HtmlBlockH6 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH6) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH6) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH6) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH6) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH6 unless _tmp return _tmp end # HtmlBlockOpenMenu = "<" Spnl ("menu" | "MENU") Spnl HtmlAttribute* ">" def _HtmlBlockOpenMenu _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("menu") break if _tmp self.pos = _save1 _tmp = match_string("MENU") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenMenu unless _tmp return _tmp end # HtmlBlockCloseMenu = "<" Spnl "/" ("menu" | "MENU") Spnl ">" def _HtmlBlockCloseMenu _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("menu") break if _tmp self.pos = _save1 _tmp = match_string("MENU") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseMenu unless _tmp return _tmp end # HtmlBlockMenu = HtmlBlockOpenMenu (HtmlBlockMenu | !HtmlBlockCloseMenu .)* HtmlBlockCloseMenu def _HtmlBlockMenu _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenMenu) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockMenu) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseMenu) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseMenu) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockMenu unless _tmp return _tmp end # HtmlBlockOpenNoframes = "<" Spnl ("noframes" | "NOFRAMES") Spnl HtmlAttribute* ">" def _HtmlBlockOpenNoframes _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("noframes") break if _tmp self.pos = _save1 _tmp = match_string("NOFRAMES") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenNoframes unless _tmp return _tmp end # HtmlBlockCloseNoframes = "<" Spnl "/" ("noframes" | "NOFRAMES") Spnl ">" def _HtmlBlockCloseNoframes _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("noframes") break if _tmp self.pos = _save1 _tmp = match_string("NOFRAMES") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseNoframes unless _tmp return _tmp end # HtmlBlockNoframes = HtmlBlockOpenNoframes (HtmlBlockNoframes | !HtmlBlockCloseNoframes .)* HtmlBlockCloseNoframes def _HtmlBlockNoframes _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenNoframes) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockNoframes) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseNoframes) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseNoframes) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockNoframes unless _tmp return _tmp end # HtmlBlockOpenNoscript = "<" Spnl ("noscript" | "NOSCRIPT") Spnl HtmlAttribute* ">" def _HtmlBlockOpenNoscript _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("noscript") break if _tmp self.pos = _save1 _tmp = match_string("NOSCRIPT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenNoscript unless _tmp return _tmp end # HtmlBlockCloseNoscript = "<" Spnl "/" ("noscript" | "NOSCRIPT") Spnl ">" def _HtmlBlockCloseNoscript _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("noscript") break if _tmp self.pos = _save1 _tmp = match_string("NOSCRIPT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseNoscript unless _tmp return _tmp end # HtmlBlockNoscript = HtmlBlockOpenNoscript (HtmlBlockNoscript | !HtmlBlockCloseNoscript .)* HtmlBlockCloseNoscript def _HtmlBlockNoscript _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenNoscript) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockNoscript) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseNoscript) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseNoscript) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockNoscript unless _tmp return _tmp end # HtmlBlockOpenOl = "<" Spnl ("ol" | "OL") Spnl HtmlAttribute* ">" def _HtmlBlockOpenOl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("ol") break if _tmp self.pos = _save1 _tmp = match_string("OL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenOl unless _tmp return _tmp end # HtmlBlockCloseOl = "<" Spnl "/" ("ol" | "OL") Spnl ">" def _HtmlBlockCloseOl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("ol") break if _tmp self.pos = _save1 _tmp = match_string("OL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseOl unless _tmp return _tmp end # HtmlBlockOl = HtmlBlockOpenOl (HtmlBlockOl | !HtmlBlockCloseOl .)* HtmlBlockCloseOl def _HtmlBlockOl _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenOl) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockOl) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseOl) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseOl) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOl unless _tmp return _tmp end # HtmlBlockOpenP = "<" Spnl ("p" | "P") Spnl HtmlAttribute* ">" def _HtmlBlockOpenP _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("p") break if _tmp self.pos = _save1 _tmp = match_string("P") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenP unless _tmp return _tmp end # HtmlBlockCloseP = "<" Spnl "/" ("p" | "P") Spnl ">" def _HtmlBlockCloseP _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("p") break if _tmp self.pos = _save1 _tmp = match_string("P") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseP unless _tmp return _tmp end # HtmlBlockP = HtmlBlockOpenP (HtmlBlockP | !HtmlBlockCloseP .)* HtmlBlockCloseP def _HtmlBlockP _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenP) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockP) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseP) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseP) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockP unless _tmp return _tmp end # HtmlBlockOpenPre = "<" Spnl ("pre" | "PRE") Spnl HtmlAttribute* ">" def _HtmlBlockOpenPre _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("pre") break if _tmp self.pos = _save1 _tmp = match_string("PRE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenPre unless _tmp return _tmp end # HtmlBlockClosePre = "<" Spnl "/" ("pre" | "PRE") Spnl ">" def _HtmlBlockClosePre _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("pre") break if _tmp self.pos = _save1 _tmp = match_string("PRE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockClosePre unless _tmp return _tmp end # HtmlBlockPre = HtmlBlockOpenPre (HtmlBlockPre | !HtmlBlockClosePre .)* HtmlBlockClosePre def _HtmlBlockPre _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenPre) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockPre) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockClosePre) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockClosePre) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockPre unless _tmp return _tmp end # HtmlBlockOpenTable = "<" Spnl ("table" | "TABLE") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTable _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("table") break if _tmp self.pos = _save1 _tmp = match_string("TABLE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTable unless _tmp return _tmp end # HtmlBlockCloseTable = "<" Spnl "/" ("table" | "TABLE") Spnl ">" def _HtmlBlockCloseTable _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("table") break if _tmp self.pos = _save1 _tmp = match_string("TABLE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTable unless _tmp return _tmp end # HtmlBlockTable = HtmlBlockOpenTable (HtmlBlockTable | !HtmlBlockCloseTable .)* HtmlBlockCloseTable def _HtmlBlockTable _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTable) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTable) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTable) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTable) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTable unless _tmp return _tmp end # HtmlBlockOpenUl = "<" Spnl ("ul" | "UL") Spnl HtmlAttribute* ">" def _HtmlBlockOpenUl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("ul") break if _tmp self.pos = _save1 _tmp = match_string("UL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenUl unless _tmp return _tmp end # HtmlBlockCloseUl = "<" Spnl "/" ("ul" | "UL") Spnl ">" def _HtmlBlockCloseUl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("ul") break if _tmp self.pos = _save1 _tmp = match_string("UL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseUl unless _tmp return _tmp end # HtmlBlockUl = HtmlBlockOpenUl (HtmlBlockUl | !HtmlBlockCloseUl .)* HtmlBlockCloseUl def _HtmlBlockUl _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenUl) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockUl) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseUl) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseUl) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockUl unless _tmp return _tmp end # HtmlBlockOpenDd = "<" Spnl ("dd" | "DD") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDd _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dd") break if _tmp self.pos = _save1 _tmp = match_string("DD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDd unless _tmp return _tmp end # HtmlBlockCloseDd = "<" Spnl "/" ("dd" | "DD") Spnl ">" def _HtmlBlockCloseDd _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dd") break if _tmp self.pos = _save1 _tmp = match_string("DD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDd unless _tmp return _tmp end # HtmlBlockDd = HtmlBlockOpenDd (HtmlBlockDd | !HtmlBlockCloseDd .)* HtmlBlockCloseDd def _HtmlBlockDd _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDd) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDd) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDd) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDd) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDd unless _tmp return _tmp end # HtmlBlockOpenDt = "<" Spnl ("dt" | "DT") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDt _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dt") break if _tmp self.pos = _save1 _tmp = match_string("DT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDt unless _tmp return _tmp end # HtmlBlockCloseDt = "<" Spnl "/" ("dt" | "DT") Spnl ">" def _HtmlBlockCloseDt _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dt") break if _tmp self.pos = _save1 _tmp = match_string("DT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDt unless _tmp return _tmp end # HtmlBlockDt = HtmlBlockOpenDt (HtmlBlockDt | !HtmlBlockCloseDt .)* HtmlBlockCloseDt def _HtmlBlockDt _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDt) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDt) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDt) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDt) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDt unless _tmp return _tmp end # HtmlBlockOpenFrameset = "<" Spnl ("frameset" | "FRAMESET") Spnl HtmlAttribute* ">" def _HtmlBlockOpenFrameset _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("frameset") break if _tmp self.pos = _save1 _tmp = match_string("FRAMESET") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenFrameset unless _tmp return _tmp end # HtmlBlockCloseFrameset = "<" Spnl "/" ("frameset" | "FRAMESET") Spnl ">" def _HtmlBlockCloseFrameset _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("frameset") break if _tmp self.pos = _save1 _tmp = match_string("FRAMESET") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseFrameset unless _tmp return _tmp end # HtmlBlockFrameset = HtmlBlockOpenFrameset (HtmlBlockFrameset | !HtmlBlockCloseFrameset .)* HtmlBlockCloseFrameset def _HtmlBlockFrameset _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenFrameset) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockFrameset) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseFrameset) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseFrameset) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockFrameset unless _tmp return _tmp end # HtmlBlockOpenLi = "<" Spnl ("li" | "LI") Spnl HtmlAttribute* ">" def _HtmlBlockOpenLi _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("li") break if _tmp self.pos = _save1 _tmp = match_string("LI") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenLi unless _tmp return _tmp end # HtmlBlockCloseLi = "<" Spnl "/" ("li" | "LI") Spnl ">" def _HtmlBlockCloseLi _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("li") break if _tmp self.pos = _save1 _tmp = match_string("LI") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseLi unless _tmp return _tmp end # HtmlBlockLi = HtmlBlockOpenLi (HtmlBlockLi | !HtmlBlockCloseLi .)* HtmlBlockCloseLi def _HtmlBlockLi _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenLi) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockLi) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseLi) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseLi) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockLi unless _tmp return _tmp end # HtmlBlockOpenTbody = "<" Spnl ("tbody" | "TBODY") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTbody _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tbody") break if _tmp self.pos = _save1 _tmp = match_string("TBODY") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTbody unless _tmp return _tmp end # HtmlBlockCloseTbody = "<" Spnl "/" ("tbody" | "TBODY") Spnl ">" def _HtmlBlockCloseTbody _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tbody") break if _tmp self.pos = _save1 _tmp = match_string("TBODY") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTbody unless _tmp return _tmp end # HtmlBlockTbody = HtmlBlockOpenTbody (HtmlBlockTbody | !HtmlBlockCloseTbody .)* HtmlBlockCloseTbody def _HtmlBlockTbody _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTbody) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTbody) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTbody) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTbody) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTbody unless _tmp return _tmp end # HtmlBlockOpenTd = "<" Spnl ("td" | "TD") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTd _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("td") break if _tmp self.pos = _save1 _tmp = match_string("TD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTd unless _tmp return _tmp end # HtmlBlockCloseTd = "<" Spnl "/" ("td" | "TD") Spnl ">" def _HtmlBlockCloseTd _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("td") break if _tmp self.pos = _save1 _tmp = match_string("TD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTd unless _tmp return _tmp end # HtmlBlockTd = HtmlBlockOpenTd (HtmlBlockTd | !HtmlBlockCloseTd .)* HtmlBlockCloseTd def _HtmlBlockTd _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTd) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTd) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTd) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTd) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTd unless _tmp return _tmp end # HtmlBlockOpenTfoot = "<" Spnl ("tfoot" | "TFOOT") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTfoot _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tfoot") break if _tmp self.pos = _save1 _tmp = match_string("TFOOT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTfoot unless _tmp return _tmp end # HtmlBlockCloseTfoot = "<" Spnl "/" ("tfoot" | "TFOOT") Spnl ">" def _HtmlBlockCloseTfoot _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tfoot") break if _tmp self.pos = _save1 _tmp = match_string("TFOOT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTfoot unless _tmp return _tmp end # HtmlBlockTfoot = HtmlBlockOpenTfoot (HtmlBlockTfoot | !HtmlBlockCloseTfoot .)* HtmlBlockCloseTfoot def _HtmlBlockTfoot _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTfoot) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTfoot) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTfoot) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTfoot) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTfoot unless _tmp return _tmp end # HtmlBlockOpenTh = "<" Spnl ("th" | "TH") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTh _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("th") break if _tmp self.pos = _save1 _tmp = match_string("TH") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTh unless _tmp return _tmp end # HtmlBlockCloseTh = "<" Spnl "/" ("th" | "TH") Spnl ">" def _HtmlBlockCloseTh _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("th") break if _tmp self.pos = _save1 _tmp = match_string("TH") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTh unless _tmp return _tmp end # HtmlBlockTh = HtmlBlockOpenTh (HtmlBlockTh | !HtmlBlockCloseTh .)* HtmlBlockCloseTh def _HtmlBlockTh _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTh) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTh) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTh) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTh) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTh unless _tmp return _tmp end # HtmlBlockOpenThead = "<" Spnl ("thead" | "THEAD") Spnl HtmlAttribute* ">" def _HtmlBlockOpenThead _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("thead") break if _tmp self.pos = _save1 _tmp = match_string("THEAD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenThead unless _tmp return _tmp end # HtmlBlockCloseThead = "<" Spnl "/" ("thead" | "THEAD") Spnl ">" def _HtmlBlockCloseThead _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("thead") break if _tmp self.pos = _save1 _tmp = match_string("THEAD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseThead unless _tmp return _tmp end # HtmlBlockThead = HtmlBlockOpenThead (HtmlBlockThead | !HtmlBlockCloseThead .)* HtmlBlockCloseThead def _HtmlBlockThead _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenThead) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockThead) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseThead) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseThead) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockThead unless _tmp return _tmp end # HtmlBlockOpenTr = "<" Spnl ("tr" | "TR") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTr _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tr") break if _tmp self.pos = _save1 _tmp = match_string("TR") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTr unless _tmp return _tmp end # HtmlBlockCloseTr = "<" Spnl "/" ("tr" | "TR") Spnl ">" def _HtmlBlockCloseTr _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tr") break if _tmp self.pos = _save1 _tmp = match_string("TR") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTr unless _tmp return _tmp end # HtmlBlockTr = HtmlBlockOpenTr (HtmlBlockTr | !HtmlBlockCloseTr .)* HtmlBlockCloseTr def _HtmlBlockTr _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTr) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTr) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTr) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTr) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTr unless _tmp return _tmp end # HtmlBlockOpenScript = "<" Spnl ("script" | "SCRIPT") Spnl HtmlAttribute* ">" def _HtmlBlockOpenScript _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("script") break if _tmp self.pos = _save1 _tmp = match_string("SCRIPT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenScript unless _tmp return _tmp end # HtmlBlockCloseScript = "<" Spnl "/" ("script" | "SCRIPT") Spnl ">" def _HtmlBlockCloseScript _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("script") break if _tmp self.pos = _save1 _tmp = match_string("SCRIPT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseScript unless _tmp return _tmp end # HtmlBlockScript = HtmlBlockOpenScript (!HtmlBlockCloseScript .)* HtmlBlockCloseScript def _HtmlBlockScript _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenScript) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _tmp = apply(:_HtmlBlockCloseScript) _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseScript) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockScript unless _tmp return _tmp end # HtmlBlockOpenHead = "<" Spnl ("head" | "HEAD") Spnl HtmlAttribute* ">" def _HtmlBlockOpenHead _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("head") break if _tmp self.pos = _save1 _tmp = match_string("HEAD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenHead unless _tmp return _tmp end # HtmlBlockCloseHead = "<" Spnl "/" ("head" | "HEAD") Spnl ">" def _HtmlBlockCloseHead _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("head") break if _tmp self.pos = _save1 _tmp = match_string("HEAD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseHead unless _tmp return _tmp end # HtmlBlockHead = HtmlBlockOpenHead (!HtmlBlockCloseHead .)* HtmlBlockCloseHead def _HtmlBlockHead _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenHead) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _tmp = apply(:_HtmlBlockCloseHead) _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseHead) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockHead unless _tmp return _tmp end # HtmlBlockInTags = (HtmlAnchor | HtmlBlockAddress | HtmlBlockBlockquote | HtmlBlockCenter | HtmlBlockDir | HtmlBlockDiv | HtmlBlockDl | HtmlBlockFieldset | HtmlBlockForm | HtmlBlockH1 | HtmlBlockH2 | HtmlBlockH3 | HtmlBlockH4 | HtmlBlockH5 | HtmlBlockH6 | HtmlBlockMenu | HtmlBlockNoframes | HtmlBlockNoscript | HtmlBlockOl | HtmlBlockP | HtmlBlockPre | HtmlBlockTable | HtmlBlockUl | HtmlBlockDd | HtmlBlockDt | HtmlBlockFrameset | HtmlBlockLi | HtmlBlockTbody | HtmlBlockTd | HtmlBlockTfoot | HtmlBlockTh | HtmlBlockThead | HtmlBlockTr | HtmlBlockScript | HtmlBlockHead) def _HtmlBlockInTags _save = self.pos while true # choice _tmp = apply(:_HtmlAnchor) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockAddress) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockBlockquote) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockCenter) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDir) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDiv) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDl) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockFieldset) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockForm) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH1) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH2) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH3) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH4) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH5) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH6) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockMenu) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockNoframes) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockNoscript) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockOl) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockP) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockPre) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTable) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockUl) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDd) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDt) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockFrameset) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockLi) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTbody) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTd) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTfoot) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTh) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockThead) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTr) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockScript) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockHead) break if _tmp self.pos = _save break end # end choice set_failed_rule :_HtmlBlockInTags unless _tmp return _tmp end # HtmlBlock = < (HtmlBlockInTags | HtmlComment | HtmlBlockSelfClosing | HtmlUnclosed) > @BlankLine+ { if html? then RDoc::Markup::Raw.new text end } def _HtmlBlock _save = self.pos while true # sequence _text_start = self.pos _save1 = self.pos while true # choice _tmp = apply(:_HtmlBlockInTags) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlComment) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlBlockSelfClosing) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlUnclosed) break if _tmp self.pos = _save1 break end # end choice if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end @result = begin; if html? then RDoc::Markup::Raw.new text end ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlock unless _tmp return _tmp end # HtmlUnclosed = "<" Spnl HtmlUnclosedType Spnl HtmlAttribute* Spnl ">" def _HtmlUnclosed _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = apply(:_HtmlUnclosedType) unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlUnclosed unless _tmp return _tmp end # HtmlUnclosedType = ("HR" | "hr") def _HtmlUnclosedType _save = self.pos while true # choice _tmp = match_string("HR") break if _tmp self.pos = _save _tmp = match_string("hr") break if _tmp self.pos = _save break end # end choice set_failed_rule :_HtmlUnclosedType unless _tmp return _tmp end # HtmlBlockSelfClosing = "<" Spnl HtmlBlockType Spnl HtmlAttribute* "/" Spnl ">" def _HtmlBlockSelfClosing _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockType) unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockSelfClosing unless _tmp return _tmp end # HtmlBlockType = ("ADDRESS" | "BLOCKQUOTE" | "CENTER" | "DD" | "DIR" | "DIV" | "DL" | "DT" | "FIELDSET" | "FORM" | "FRAMESET" | "H1" | "H2" | "H3" | "H4" | "H5" | "H6" | "HR" | "ISINDEX" | "LI" | "MENU" | "NOFRAMES" | "NOSCRIPT" | "OL" | "P" | "PRE" | "SCRIPT" | "TABLE" | "TBODY" | "TD" | "TFOOT" | "TH" | "THEAD" | "TR" | "UL" | "address" | "blockquote" | "center" | "dd" | "dir" | "div" | "dl" | "dt" | "fieldset" | "form" | "frameset" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "hr" | "isindex" | "li" | "menu" | "noframes" | "noscript" | "ol" | "p" | "pre" | "script" | "table" | "tbody" | "td" | "tfoot" | "th" | "thead" | "tr" | "ul") def _HtmlBlockType _save = self.pos while true # choice _tmp = match_string("ADDRESS") break if _tmp self.pos = _save _tmp = match_string("BLOCKQUOTE") break if _tmp self.pos = _save _tmp = match_string("CENTER") break if _tmp self.pos = _save _tmp = match_string("DD") break if _tmp self.pos = _save _tmp = match_string("DIR") break if _tmp self.pos = _save _tmp = match_string("DIV") break if _tmp self.pos = _save _tmp = match_string("DL") break if _tmp self.pos = _save _tmp = match_string("DT") break if _tmp self.pos = _save _tmp = match_string("FIELDSET") break if _tmp self.pos = _save _tmp = match_string("FORM") break if _tmp self.pos = _save _tmp = match_string("FRAMESET") break if _tmp self.pos = _save _tmp = match_string("H1") break if _tmp self.pos = _save _tmp = match_string("H2") break if _tmp self.pos = _save _tmp = match_string("H3") break if _tmp self.pos = _save _tmp = match_string("H4") break if _tmp self.pos = _save _tmp = match_string("H5") break if _tmp self.pos = _save _tmp = match_string("H6") break if _tmp self.pos = _save _tmp = match_string("HR") break if _tmp self.pos = _save _tmp = match_string("ISINDEX") break if _tmp self.pos = _save _tmp = match_string("LI") break if _tmp self.pos = _save _tmp = match_string("MENU") break if _tmp self.pos = _save _tmp = match_string("NOFRAMES") break if _tmp self.pos = _save _tmp = match_string("NOSCRIPT") break if _tmp self.pos = _save _tmp = match_string("OL") break if _tmp self.pos = _save _tmp = match_string("P") break if _tmp self.pos = _save _tmp = match_string("PRE") break if _tmp self.pos = _save _tmp = match_string("SCRIPT") break if _tmp self.pos = _save _tmp = match_string("TABLE") break if _tmp self.pos = _save _tmp = match_string("TBODY") break if _tmp self.pos = _save _tmp = match_string("TD") break if _tmp self.pos = _save _tmp = match_string("TFOOT") break if _tmp self.pos = _save _tmp = match_string("TH") break if _tmp self.pos = _save _tmp = match_string("THEAD") break if _tmp self.pos = _save _tmp = match_string("TR") break if _tmp self.pos = _save _tmp = match_string("UL") break if _tmp self.pos = _save _tmp = match_string("address") break if _tmp self.pos = _save _tmp = match_string("blockquote") break if _tmp self.pos = _save _tmp = match_string("center") break if _tmp self.pos = _save _tmp = match_string("dd") break if _tmp self.pos = _save _tmp = match_string("dir") break if _tmp self.pos = _save _tmp = match_string("div") break if _tmp self.pos = _save _tmp = match_string("dl") break if _tmp self.pos = _save _tmp = match_string("dt") break if _tmp self.pos = _save _tmp = match_string("fieldset") break if _tmp self.pos = _save _tmp = match_string("form") break if _tmp self.pos = _save _tmp = match_string("frameset") break if _tmp self.pos = _save _tmp = match_string("h1") break if _tmp self.pos = _save _tmp = match_string("h2") break if _tmp self.pos = _save _tmp = match_string("h3") break if _tmp self.pos = _save _tmp = match_string("h4") break if _tmp self.pos = _save _tmp = match_string("h5") break if _tmp self.pos = _save _tmp = match_string("h6") break if _tmp self.pos = _save _tmp = match_string("hr") break if _tmp self.pos = _save _tmp = match_string("isindex") break if _tmp self.pos = _save _tmp = match_string("li") break if _tmp self.pos = _save _tmp = match_string("menu") break if _tmp self.pos = _save _tmp = match_string("noframes") break if _tmp self.pos = _save _tmp = match_string("noscript") break if _tmp self.pos = _save _tmp = match_string("ol") break if _tmp self.pos = _save _tmp = match_string("p") break if _tmp self.pos = _save _tmp = match_string("pre") break if _tmp self.pos = _save _tmp = match_string("script") break if _tmp self.pos = _save _tmp = match_string("table") break if _tmp self.pos = _save _tmp = match_string("tbody") break if _tmp self.pos = _save _tmp = match_string("td") break if _tmp self.pos = _save _tmp = match_string("tfoot") break if _tmp self.pos = _save _tmp = match_string("th") break if _tmp self.pos = _save _tmp = match_string("thead") break if _tmp self.pos = _save _tmp = match_string("tr") break if _tmp self.pos = _save _tmp = match_string("ul") break if _tmp self.pos = _save break end # end choice set_failed_rule :_HtmlBlockType unless _tmp return _tmp end # StyleOpen = "<" Spnl ("style" | "STYLE") Spnl HtmlAttribute* ">" def _StyleOpen _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("style") break if _tmp self.pos = _save1 _tmp = match_string("STYLE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StyleOpen unless _tmp return _tmp end # StyleClose = "<" Spnl "/" ("style" | "STYLE") Spnl ">" def _StyleClose _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("style") break if _tmp self.pos = _save1 _tmp = match_string("STYLE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StyleClose unless _tmp return _tmp end # InStyleTags = StyleOpen (!StyleClose .)* StyleClose def _InStyleTags _save = self.pos while true # sequence _tmp = apply(:_StyleOpen) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _tmp = apply(:_StyleClose) _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_StyleClose) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_InStyleTags unless _tmp return _tmp end # StyleBlock = < InStyleTags > @BlankLine* { if css? then RDoc::Markup::Raw.new text end } def _StyleBlock _save = self.pos while true # sequence _text_start = self.pos _tmp = apply(:_InStyleTags) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; if css? then RDoc::Markup::Raw.new text end ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StyleBlock unless _tmp return _tmp end # Inlines = (!@Endline Inline:i { i } | @Endline:c &Inline { c })+:chunks @Endline? { chunks } def _Inlines _save = self.pos while true # sequence _save1 = self.pos _ary = [] _save2 = self.pos while true # choice _save3 = self.pos while true # sequence _save4 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_Inline) i = @result unless _tmp self.pos = _save3 break end @result = begin; i ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 _save5 = self.pos while true # sequence _tmp = _Endline() c = @result unless _tmp self.pos = _save5 break end _save6 = self.pos _tmp = apply(:_Inline) self.pos = _save6 unless _tmp self.pos = _save5 break end @result = begin; c ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice if _tmp _ary << @result while true _save7 = self.pos while true # choice _save8 = self.pos while true # sequence _save9 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Inline) i = @result unless _tmp self.pos = _save8 break end @result = begin; i ; end _tmp = true unless _tmp self.pos = _save8 end break end # end sequence break if _tmp self.pos = _save7 _save10 = self.pos while true # sequence _tmp = _Endline() c = @result unless _tmp self.pos = _save10 break end _save11 = self.pos _tmp = apply(:_Inline) self.pos = _save11 unless _tmp self.pos = _save10 break end @result = begin; c ; end _tmp = true unless _tmp self.pos = _save10 end break end # end sequence break if _tmp self.pos = _save7 break end # end choice _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end chunks = @result unless _tmp self.pos = _save break end _save12 = self.pos _tmp = _Endline() unless _tmp _tmp = true self.pos = _save12 end unless _tmp self.pos = _save break end @result = begin; chunks ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Inlines unless _tmp return _tmp end # Inline = (Str | @Endline | UlOrStarLine | @Space | Strong | Emph | Strike | Image | Link | NoteReference | InlineNote | Code | RawHtml | Entity | EscapedChar | Symbol) def _Inline _save = self.pos while true # choice _tmp = apply(:_Str) break if _tmp self.pos = _save _tmp = _Endline() break if _tmp self.pos = _save _tmp = apply(:_UlOrStarLine) break if _tmp self.pos = _save _tmp = _Space() break if _tmp self.pos = _save _tmp = apply(:_Strong) break if _tmp self.pos = _save _tmp = apply(:_Emph) break if _tmp self.pos = _save _tmp = apply(:_Strike) break if _tmp self.pos = _save _tmp = apply(:_Image) break if _tmp self.pos = _save _tmp = apply(:_Link) break if _tmp self.pos = _save _tmp = apply(:_NoteReference) break if _tmp self.pos = _save _tmp = apply(:_InlineNote) break if _tmp self.pos = _save _tmp = apply(:_Code) break if _tmp self.pos = _save _tmp = apply(:_RawHtml) break if _tmp self.pos = _save _tmp = apply(:_Entity) break if _tmp self.pos = _save _tmp = apply(:_EscapedChar) break if _tmp self.pos = _save _tmp = apply(:_Symbol) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Inline unless _tmp return _tmp end # Space = @Spacechar+ { " " } def _Space _save = self.pos while true # sequence _save1 = self.pos _tmp = _Spacechar() if _tmp while true _tmp = _Spacechar() break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; " " ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Space unless _tmp return _tmp end # Str = @StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { a } def _Str _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _text_start = self.pos _save1 = self.pos _tmp = _NormalChar() if _tmp while true _tmp = _NormalChar() break unless _tmp end _tmp = true else self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; a = text ; end _tmp = true unless _tmp self.pos = _save break end while true _save3 = self.pos while true # sequence _tmp = apply(:_StrChunk) c = @result unless _tmp self.pos = _save3 break end @result = begin; a << c ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Str unless _tmp return _tmp end # StrChunk = < (@NormalChar | /_+/ &Alphanumeric)+ > { text } def _StrChunk _save = self.pos while true # sequence _text_start = self.pos _save1 = self.pos _save2 = self.pos while true # choice _tmp = _NormalChar() break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _tmp = scan(/\A(?-mix:_+)/) unless _tmp self.pos = _save3 break end _save4 = self.pos _tmp = apply(:_Alphanumeric) self.pos = _save4 unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice if _tmp while true _save5 = self.pos while true # choice _tmp = _NormalChar() break if _tmp self.pos = _save5 _save6 = self.pos while true # sequence _tmp = scan(/\A(?-mix:_+)/) unless _tmp self.pos = _save6 break end _save7 = self.pos _tmp = apply(:_Alphanumeric) self.pos = _save7 unless _tmp self.pos = _save6 end break end # end sequence break if _tmp self.pos = _save5 break end # end choice break unless _tmp end _tmp = true else self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StrChunk unless _tmp return _tmp end # EscapedChar = "\\" !@Newline < /[:\\`|*_{}\[\]()#+.!><-]/ > { text } def _EscapedChar _save = self.pos while true # sequence _tmp = match_string("\\") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _text_start = self.pos _tmp = scan(/\A(?-mix:[:\\`|*_{}\[\]()#+.!><-])/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_EscapedChar unless _tmp return _tmp end # Entity = (HexEntity | DecEntity | CharEntity):a { a } def _Entity _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_HexEntity) break if _tmp self.pos = _save1 _tmp = apply(:_DecEntity) break if _tmp self.pos = _save1 _tmp = apply(:_CharEntity) break if _tmp self.pos = _save1 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Entity unless _tmp return _tmp end # Endline = (@LineBreak | @TerminalEndline | @NormalEndline) def _Endline _save = self.pos while true # choice _tmp = _LineBreak() break if _tmp self.pos = _save _tmp = _TerminalEndline() break if _tmp self.pos = _save _tmp = _NormalEndline() break if _tmp self.pos = _save break end # end choice set_failed_rule :_Endline unless _tmp return _tmp end # NormalEndline = @Sp @Newline !@BlankLine !">" !AtxStart !(Line /={1,}|-{1,}/ @Newline) { "\n" } def _NormalEndline _save = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _save3 = self.pos _tmp = apply(:_AtxStart) _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save break end _save4 = self.pos _save5 = self.pos while true # sequence _tmp = apply(:_Line) unless _tmp self.pos = _save5 break end _tmp = scan(/\A(?-mix:={1,}|-{1,})/) unless _tmp self.pos = _save5 break end _tmp = _Newline() unless _tmp self.pos = _save5 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save break end @result = begin; "\n" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_NormalEndline unless _tmp return _tmp end # TerminalEndline = @Sp @Newline @Eof def _TerminalEndline _save = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _tmp = _Eof() unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_TerminalEndline unless _tmp return _tmp end # LineBreak = " " @NormalEndline { RDoc::Markup::HardBreak.new } def _LineBreak _save = self.pos while true # sequence _tmp = match_string(" ") unless _tmp self.pos = _save break end _tmp = _NormalEndline() unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::HardBreak.new ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_LineBreak unless _tmp return _tmp end # Symbol = < @SpecialChar > { text } def _Symbol _save = self.pos while true # sequence _text_start = self.pos _tmp = _SpecialChar() if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Symbol unless _tmp return _tmp end # UlOrStarLine = (UlLine | StarLine):a { a } def _UlOrStarLine _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_UlLine) break if _tmp self.pos = _save1 _tmp = apply(:_StarLine) break if _tmp self.pos = _save1 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_UlOrStarLine unless _tmp return _tmp end # StarLine = (< /\*{4,}/ > { text } | < @Spacechar /\*+/ &@Spacechar > { text }) def _StarLine _save = self.pos while true # choice _save1 = self.pos while true # sequence _text_start = self.pos _tmp = scan(/\A(?-mix:\*{4,})/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save1 break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save1 end break end # end sequence break if _tmp self.pos = _save _save2 = self.pos while true # sequence _text_start = self.pos _save3 = self.pos while true # sequence _tmp = _Spacechar() unless _tmp self.pos = _save3 break end _tmp = scan(/\A(?-mix:\*+)/) unless _tmp self.pos = _save3 break end _save4 = self.pos _tmp = _Spacechar() self.pos = _save4 unless _tmp self.pos = _save3 end break end # end sequence if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save2 break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save break end # end choice set_failed_rule :_StarLine unless _tmp return _tmp end # UlLine = (< /_{4,}/ > { text } | < @Spacechar /_+/ &@Spacechar > { text }) def _UlLine _save = self.pos while true # choice _save1 = self.pos while true # sequence _text_start = self.pos _tmp = scan(/\A(?-mix:_{4,})/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save1 break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save1 end break end # end sequence break if _tmp self.pos = _save _save2 = self.pos while true # sequence _text_start = self.pos _save3 = self.pos while true # sequence _tmp = _Spacechar() unless _tmp self.pos = _save3 break end _tmp = scan(/\A(?-mix:_+)/) unless _tmp self.pos = _save3 break end _save4 = self.pos _tmp = _Spacechar() self.pos = _save4 unless _tmp self.pos = _save3 end break end # end sequence if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save2 break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save break end # end choice set_failed_rule :_UlLine unless _tmp return _tmp end # Emph = (EmphStar | EmphUl) def _Emph _save = self.pos while true # choice _tmp = apply(:_EmphStar) break if _tmp self.pos = _save _tmp = apply(:_EmphUl) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Emph unless _tmp return _tmp end # Whitespace = (@Spacechar | @Newline) def _Whitespace _save = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save _tmp = _Newline() break if _tmp self.pos = _save break end # end choice set_failed_rule :_Whitespace unless _tmp return _tmp end # EmphStar = "*" !@Whitespace @StartList:a (!"*" Inline:b { a << b } | StrongStar:b { a << b })+ "*" { emphasis a.join } def _EmphStar _save = self.pos while true # sequence _tmp = match_string("*") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # choice _save4 = self.pos while true # sequence _save5 = self.pos _tmp = match_string("*") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break if _tmp self.pos = _save3 _save6 = self.pos while true # sequence _tmp = apply(:_StrongStar) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break if _tmp self.pos = _save3 break end # end choice if _tmp while true _save7 = self.pos while true # choice _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string("*") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save8 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save8 end break end # end sequence break if _tmp self.pos = _save7 _save10 = self.pos while true # sequence _tmp = apply(:_StrongStar) b = @result unless _tmp self.pos = _save10 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save10 end break end # end sequence break if _tmp self.pos = _save7 break end # end choice break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("*") unless _tmp self.pos = _save break end @result = begin; emphasis a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_EmphStar unless _tmp return _tmp end # EmphUl = "_" !@Whitespace @StartList:a (!"_" Inline:b { a << b } | StrongUl:b { a << b })+ "_" { emphasis a.join } def _EmphUl _save = self.pos while true # sequence _tmp = match_string("_") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # choice _save4 = self.pos while true # sequence _save5 = self.pos _tmp = match_string("_") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break if _tmp self.pos = _save3 _save6 = self.pos while true # sequence _tmp = apply(:_StrongUl) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break if _tmp self.pos = _save3 break end # end choice if _tmp while true _save7 = self.pos while true # choice _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string("_") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save8 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save8 end break end # end sequence break if _tmp self.pos = _save7 _save10 = self.pos while true # sequence _tmp = apply(:_StrongUl) b = @result unless _tmp self.pos = _save10 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save10 end break end # end sequence break if _tmp self.pos = _save7 break end # end choice break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("_") unless _tmp self.pos = _save break end @result = begin; emphasis a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_EmphUl unless _tmp return _tmp end # Strong = (StrongStar | StrongUl) def _Strong _save = self.pos while true # choice _tmp = apply(:_StrongStar) break if _tmp self.pos = _save _tmp = apply(:_StrongUl) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Strong unless _tmp return _tmp end # StrongStar = "**" !@Whitespace @StartList:a (!"**" Inline:b { a << b })+ "**" { strong a.join } def _StrongStar _save = self.pos while true # sequence _tmp = match_string("**") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("**") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save3 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = match_string("**") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save5 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("**") unless _tmp self.pos = _save break end @result = begin; strong a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StrongStar unless _tmp return _tmp end # StrongUl = "__" !@Whitespace @StartList:a (!"__" Inline:b { a << b })+ "__" { strong a.join } def _StrongUl _save = self.pos while true # sequence _tmp = match_string("__") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("__") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save3 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = match_string("__") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save5 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("__") unless _tmp self.pos = _save break end @result = begin; strong a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StrongUl unless _tmp return _tmp end # Strike = &{ strike? } "~~" !@Whitespace @StartList:a (!"~~" Inline:b { a << b })+ "~~" { strike a.join } def _Strike _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; strike? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = match_string("~~") unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save3 = self.pos _save4 = self.pos while true # sequence _save5 = self.pos _tmp = match_string("~~") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence if _tmp while true _save6 = self.pos while true # sequence _save7 = self.pos _tmp = match_string("~~") _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save3 end unless _tmp self.pos = _save break end _tmp = match_string("~~") unless _tmp self.pos = _save break end @result = begin; strike a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Strike unless _tmp return _tmp end # Image = "!" (ExplicitLink | ReferenceLink):a { "rdoc-image:#{a[/\[(.*)\]/, 1]}" } def _Image _save = self.pos while true # sequence _tmp = match_string("!") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = apply(:_ExplicitLink) break if _tmp self.pos = _save1 _tmp = apply(:_ReferenceLink) break if _tmp self.pos = _save1 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; "rdoc-image:#{a[/\[(.*)\]/, 1]}" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Image unless _tmp return _tmp end # Link = (ExplicitLink | ReferenceLink | AutoLink) def _Link _save = self.pos while true # choice _tmp = apply(:_ExplicitLink) break if _tmp self.pos = _save _tmp = apply(:_ReferenceLink) break if _tmp self.pos = _save _tmp = apply(:_AutoLink) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Link unless _tmp return _tmp end # ReferenceLink = (ReferenceLinkDouble | ReferenceLinkSingle) def _ReferenceLink _save = self.pos while true # choice _tmp = apply(:_ReferenceLinkDouble) break if _tmp self.pos = _save _tmp = apply(:_ReferenceLinkSingle) break if _tmp self.pos = _save break end # end choice set_failed_rule :_ReferenceLink unless _tmp return _tmp end # ReferenceLinkDouble = Label:content < Spnl > !"[]" Label:label { link_to content, label, text } def _ReferenceLinkDouble _save = self.pos while true # sequence _tmp = apply(:_Label) content = @result unless _tmp self.pos = _save break end _text_start = self.pos _tmp = apply(:_Spnl) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("[]") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_Label) label = @result unless _tmp self.pos = _save break end @result = begin; link_to content, label, text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ReferenceLinkDouble unless _tmp return _tmp end # ReferenceLinkSingle = Label:content < (Spnl "[]")? > { link_to content, content, text } def _ReferenceLinkSingle _save = self.pos while true # sequence _tmp = apply(:_Label) content = @result unless _tmp self.pos = _save break end _text_start = self.pos _save1 = self.pos _save2 = self.pos while true # sequence _tmp = apply(:_Spnl) unless _tmp self.pos = _save2 break end _tmp = match_string("[]") unless _tmp self.pos = _save2 end break end # end sequence unless _tmp _tmp = true self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; link_to content, content, text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ReferenceLinkSingle unless _tmp return _tmp end # ExplicitLink = Label:l "(" @Sp Source:s Spnl Title @Sp ")" { "{#{l}}[#{s}]" } def _ExplicitLink _save = self.pos while true # sequence _tmp = apply(:_Label) l = @result unless _tmp self.pos = _save break end _tmp = match_string("(") unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = apply(:_Source) s = @result unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = apply(:_Title) unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = match_string(")") unless _tmp self.pos = _save break end @result = begin; "{#{l}}[#{s}]" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ExplicitLink unless _tmp return _tmp end # Source = ("<" < SourceContents > ">" | < SourceContents >) { text } def _Source _save = self.pos while true # sequence _save1 = self.pos while true # choice _save2 = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save2 break end _text_start = self.pos _tmp = apply(:_SourceContents) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save2 break end _tmp = match_string(">") unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save1 _text_start = self.pos _tmp = apply(:_SourceContents) if _tmp text = get_text(_text_start) end break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Source unless _tmp return _tmp end # SourceContents = ((!"(" !")" !">" Nonspacechar)+ | "(" SourceContents ")")* def _SourceContents while true _save1 = self.pos while true # choice _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("(") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _save5 = self.pos _tmp = match_string(")") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save3 break end _save6 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save3 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save7 = self.pos while true # sequence _save8 = self.pos _tmp = match_string("(") _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save7 break end _save9 = self.pos _tmp = match_string(")") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save7 break end _save10 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save10 unless _tmp self.pos = _save7 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save7 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end break if _tmp self.pos = _save1 _save11 = self.pos while true # sequence _tmp = match_string("(") unless _tmp self.pos = _save11 break end _tmp = apply(:_SourceContents) unless _tmp self.pos = _save11 break end _tmp = match_string(")") unless _tmp self.pos = _save11 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice break unless _tmp end _tmp = true set_failed_rule :_SourceContents unless _tmp return _tmp end # Title = (TitleSingle | TitleDouble | ""):a { a } def _Title _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_TitleSingle) break if _tmp self.pos = _save1 _tmp = apply(:_TitleDouble) break if _tmp self.pos = _save1 _tmp = match_string("") break if _tmp self.pos = _save1 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Title unless _tmp return _tmp end # TitleSingle = "'" (!("'" @Sp (")" | @Newline)) .)* "'" def _TitleSingle _save = self.pos while true # sequence _tmp = match_string("'") unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # sequence _tmp = match_string("'") unless _tmp self.pos = _save4 break end _tmp = _Sp() unless _tmp self.pos = _save4 break end _save5 = self.pos while true # choice _tmp = match_string(")") break if _tmp self.pos = _save5 _tmp = _Newline() break if _tmp self.pos = _save5 break end # end choice unless _tmp self.pos = _save4 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("'") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_TitleSingle unless _tmp return _tmp end # TitleDouble = "\"" (!("\"" @Sp (")" | @Newline)) .)* "\"" def _TitleDouble _save = self.pos while true # sequence _tmp = match_string("\"") unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # sequence _tmp = match_string("\"") unless _tmp self.pos = _save4 break end _tmp = _Sp() unless _tmp self.pos = _save4 break end _save5 = self.pos while true # choice _tmp = match_string(")") break if _tmp self.pos = _save5 _tmp = _Newline() break if _tmp self.pos = _save5 break end # end choice unless _tmp self.pos = _save4 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("\"") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_TitleDouble unless _tmp return _tmp end # AutoLink = (AutoLinkUrl | AutoLinkEmail) def _AutoLink _save = self.pos while true # choice _tmp = apply(:_AutoLinkUrl) break if _tmp self.pos = _save _tmp = apply(:_AutoLinkEmail) break if _tmp self.pos = _save break end # end choice set_failed_rule :_AutoLink unless _tmp return _tmp end # AutoLinkUrl = "<" < /[A-Za-z]+/ "://" (!@Newline !">" .)+ > ">" { text } def _AutoLinkUrl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _text_start = self.pos _save1 = self.pos while true # sequence _tmp = scan(/\A(?-mix:[A-Za-z]+)/) unless _tmp self.pos = _save1 break end _tmp = match_string("://") unless _tmp self.pos = _save1 break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _save5 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save6 = self.pos while true # sequence _save7 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _save8 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save6 break end _tmp = get_byte unless _tmp self.pos = _save6 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save1 end break end # end sequence if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AutoLinkUrl unless _tmp return _tmp end # AutoLinkEmail = "<" "mailto:"? < /[\w+.\/!%~$-]+/i "@" (!@Newline !">" .)+ > ">" { "mailto:#{text}" } def _AutoLinkEmail _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("mailto:") unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save break end _text_start = self.pos _save2 = self.pos while true # sequence _tmp = scan(/\A(?i-mx:[\w+.\/!%~$-]+)/) unless _tmp self.pos = _save2 break end _tmp = match_string("@") unless _tmp self.pos = _save2 break end _save3 = self.pos _save4 = self.pos while true # sequence _save5 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _save6 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save4 break end _tmp = get_byte unless _tmp self.pos = _save4 end break end # end sequence if _tmp while true _save7 = self.pos while true # sequence _save8 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save7 break end _save9 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save7 break end _tmp = get_byte unless _tmp self.pos = _save7 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save3 end unless _tmp self.pos = _save2 end break end # end sequence if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save break end @result = begin; "mailto:#{text}" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AutoLinkEmail unless _tmp return _tmp end # Reference = @NonindentSpace !"[]" Label:label ":" Spnl RefSrc:link RefTitle @BlankLine+ { # TODO use title reference label, link nil } def _Reference _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("[]") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_Label) label = @result unless _tmp self.pos = _save break end _tmp = match_string(":") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = apply(:_RefSrc) link = @result unless _tmp self.pos = _save break end _tmp = apply(:_RefTitle) unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end @result = begin; # TODO use title reference label, link nil ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Reference unless _tmp return _tmp end # Label = "[" (!"^" &{ notes? } | &. &{ !notes? }) @StartList:a (!"]" Inline:l { a << l })* "]" { a.join.gsub(/\s+/, ' ') } def _Label _save = self.pos while true # sequence _tmp = match_string("[") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _save2 = self.pos while true # sequence _save3 = self.pos _tmp = match_string("^") _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _save4 = self.pos _tmp = begin; notes? ; end self.pos = _save4 unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save1 _save5 = self.pos while true # sequence _save6 = self.pos _tmp = get_byte self.pos = _save6 unless _tmp self.pos = _save5 break end _save7 = self.pos _tmp = begin; !notes? ; end self.pos = _save7 unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end while true _save9 = self.pos while true # sequence _save10 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save10 unless _tmp self.pos = _save9 break end _tmp = apply(:_Inline) l = @result unless _tmp self.pos = _save9 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save9 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("]") unless _tmp self.pos = _save break end @result = begin; a.join.gsub(/\s+/, ' ') ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Label unless _tmp return _tmp end # RefSrc = < Nonspacechar+ > { text } def _RefSrc _save = self.pos while true # sequence _text_start = self.pos _save1 = self.pos _tmp = apply(:_Nonspacechar) if _tmp while true _tmp = apply(:_Nonspacechar) break unless _tmp end _tmp = true else self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RefSrc unless _tmp return _tmp end # RefTitle = (RefTitleSingle | RefTitleDouble | RefTitleParens | EmptyTitle) def _RefTitle _save = self.pos while true # choice _tmp = apply(:_RefTitleSingle) break if _tmp self.pos = _save _tmp = apply(:_RefTitleDouble) break if _tmp self.pos = _save _tmp = apply(:_RefTitleParens) break if _tmp self.pos = _save _tmp = apply(:_EmptyTitle) break if _tmp self.pos = _save break end # end choice set_failed_rule :_RefTitle unless _tmp return _tmp end # EmptyTitle = "" def _EmptyTitle _tmp = match_string("") set_failed_rule :_EmptyTitle unless _tmp return _tmp end # RefTitleSingle = Spnl "'" < (!("'" @Sp @Newline | @Newline) .)* > "'" { text } def _RefTitleSingle _save = self.pos while true # sequence _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("'") unless _tmp self.pos = _save break end _text_start = self.pos while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # choice _save5 = self.pos while true # sequence _tmp = match_string("'") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = _Newline() unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save4 _tmp = _Newline() break if _tmp self.pos = _save4 break end # end choice _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string("'") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RefTitleSingle unless _tmp return _tmp end # RefTitleDouble = Spnl "\"" < (!("\"" @Sp @Newline | @Newline) .)* > "\"" { text } def _RefTitleDouble _save = self.pos while true # sequence _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("\"") unless _tmp self.pos = _save break end _text_start = self.pos while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # choice _save5 = self.pos while true # sequence _tmp = match_string("\"") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = _Newline() unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save4 _tmp = _Newline() break if _tmp self.pos = _save4 break end # end choice _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string("\"") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RefTitleDouble unless _tmp return _tmp end # RefTitleParens = Spnl "(" < (!(")" @Sp @Newline | @Newline) .)* > ")" { text } def _RefTitleParens _save = self.pos while true # sequence _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("(") unless _tmp self.pos = _save break end _text_start = self.pos while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # choice _save5 = self.pos while true # sequence _tmp = match_string(")") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = _Newline() unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save4 _tmp = _Newline() break if _tmp self.pos = _save4 break end # end choice _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(")") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RefTitleParens unless _tmp return _tmp end # References = (Reference | SkipBlock)* def _References while true _save1 = self.pos while true # choice _tmp = apply(:_Reference) break if _tmp self.pos = _save1 _tmp = apply(:_SkipBlock) break if _tmp self.pos = _save1 break end # end choice break unless _tmp end _tmp = true set_failed_rule :_References unless _tmp return _tmp end # Ticks1 = "`" !"`" def _Ticks1 _save = self.pos while true # sequence _tmp = match_string("`") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks1 unless _tmp return _tmp end # Ticks2 = "``" !"`" def _Ticks2 _save = self.pos while true # sequence _tmp = match_string("``") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks2 unless _tmp return _tmp end # Ticks3 = "```" !"`" def _Ticks3 _save = self.pos while true # sequence _tmp = match_string("```") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks3 unless _tmp return _tmp end # Ticks4 = "````" !"`" def _Ticks4 _save = self.pos while true # sequence _tmp = match_string("````") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks4 unless _tmp return _tmp end # Ticks5 = "`````" !"`" def _Ticks5 _save = self.pos while true # sequence _tmp = match_string("`````") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks5 unless _tmp return _tmp end # Code = (Ticks1 @Sp < ((!"`" Nonspacechar)+ | !Ticks1 /`+/ | !(@Sp Ticks1) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks1 | Ticks2 @Sp < ((!"`" Nonspacechar)+ | !Ticks2 /`+/ | !(@Sp Ticks2) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks2 | Ticks3 @Sp < ((!"`" Nonspacechar)+ | !Ticks3 /`+/ | !(@Sp Ticks3) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks3 | Ticks4 @Sp < ((!"`" Nonspacechar)+ | !Ticks4 /`+/ | !(@Sp Ticks4) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks4 | Ticks5 @Sp < ((!"`" Nonspacechar)+ | !Ticks5 /`+/ | !(@Sp Ticks5) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks5) { "#{text}" } def _Code _save = self.pos while true # sequence _save1 = self.pos while true # choice _save2 = self.pos while true # sequence _tmp = apply(:_Ticks1) unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 break end _text_start = self.pos _save3 = self.pos _save4 = self.pos while true # choice _save5 = self.pos _save6 = self.pos while true # sequence _save7 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save6 end break end # end sequence if _tmp while true _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save8 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save5 end break if _tmp self.pos = _save4 _save10 = self.pos while true # sequence _save11 = self.pos _tmp = apply(:_Ticks1) _tmp = _tmp ? nil : true self.pos = _save11 unless _tmp self.pos = _save10 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save10 end break end # end sequence break if _tmp self.pos = _save4 _save12 = self.pos while true # sequence _save13 = self.pos _save14 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save14 break end _tmp = apply(:_Ticks1) unless _tmp self.pos = _save14 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save13 unless _tmp self.pos = _save12 break end _save15 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save15 _save16 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save16 break end _save17 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save17 unless _tmp self.pos = _save16 end break end # end sequence break if _tmp self.pos = _save15 break end # end choice unless _tmp self.pos = _save12 end break end # end sequence break if _tmp self.pos = _save4 break end # end choice if _tmp while true _save18 = self.pos while true # choice _save19 = self.pos _save20 = self.pos while true # sequence _save21 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save21 unless _tmp self.pos = _save20 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save20 end break end # end sequence if _tmp while true _save22 = self.pos while true # sequence _save23 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save23 unless _tmp self.pos = _save22 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save22 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save19 end break if _tmp self.pos = _save18 _save24 = self.pos while true # sequence _save25 = self.pos _tmp = apply(:_Ticks1) _tmp = _tmp ? nil : true self.pos = _save25 unless _tmp self.pos = _save24 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save24 end break end # end sequence break if _tmp self.pos = _save18 _save26 = self.pos while true # sequence _save27 = self.pos _save28 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save28 break end _tmp = apply(:_Ticks1) unless _tmp self.pos = _save28 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save27 unless _tmp self.pos = _save26 break end _save29 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save29 _save30 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save30 break end _save31 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save31 unless _tmp self.pos = _save30 end break end # end sequence break if _tmp self.pos = _save29 break end # end choice unless _tmp self.pos = _save26 end break end # end sequence break if _tmp self.pos = _save18 break end # end choice break unless _tmp end _tmp = true else self.pos = _save3 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 break end _tmp = apply(:_Ticks1) unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save1 _save32 = self.pos while true # sequence _tmp = apply(:_Ticks2) unless _tmp self.pos = _save32 break end _tmp = _Sp() unless _tmp self.pos = _save32 break end _text_start = self.pos _save33 = self.pos _save34 = self.pos while true # choice _save35 = self.pos _save36 = self.pos while true # sequence _save37 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save37 unless _tmp self.pos = _save36 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save36 end break end # end sequence if _tmp while true _save38 = self.pos while true # sequence _save39 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save39 unless _tmp self.pos = _save38 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save38 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save35 end break if _tmp self.pos = _save34 _save40 = self.pos while true # sequence _save41 = self.pos _tmp = apply(:_Ticks2) _tmp = _tmp ? nil : true self.pos = _save41 unless _tmp self.pos = _save40 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save40 end break end # end sequence break if _tmp self.pos = _save34 _save42 = self.pos while true # sequence _save43 = self.pos _save44 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save44 break end _tmp = apply(:_Ticks2) unless _tmp self.pos = _save44 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save43 unless _tmp self.pos = _save42 break end _save45 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save45 _save46 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save46 break end _save47 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save47 unless _tmp self.pos = _save46 end break end # end sequence break if _tmp self.pos = _save45 break end # end choice unless _tmp self.pos = _save42 end break end # end sequence break if _tmp self.pos = _save34 break end # end choice if _tmp while true _save48 = self.pos while true # choice _save49 = self.pos _save50 = self.pos while true # sequence _save51 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save51 unless _tmp self.pos = _save50 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save50 end break end # end sequence if _tmp while true _save52 = self.pos while true # sequence _save53 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save53 unless _tmp self.pos = _save52 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save52 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save49 end break if _tmp self.pos = _save48 _save54 = self.pos while true # sequence _save55 = self.pos _tmp = apply(:_Ticks2) _tmp = _tmp ? nil : true self.pos = _save55 unless _tmp self.pos = _save54 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save54 end break end # end sequence break if _tmp self.pos = _save48 _save56 = self.pos while true # sequence _save57 = self.pos _save58 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save58 break end _tmp = apply(:_Ticks2) unless _tmp self.pos = _save58 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save57 unless _tmp self.pos = _save56 break end _save59 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save59 _save60 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save60 break end _save61 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save61 unless _tmp self.pos = _save60 end break end # end sequence break if _tmp self.pos = _save59 break end # end choice unless _tmp self.pos = _save56 end break end # end sequence break if _tmp self.pos = _save48 break end # end choice break unless _tmp end _tmp = true else self.pos = _save33 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save32 break end _tmp = _Sp() unless _tmp self.pos = _save32 break end _tmp = apply(:_Ticks2) unless _tmp self.pos = _save32 end break end # end sequence break if _tmp self.pos = _save1 _save62 = self.pos while true # sequence _tmp = apply(:_Ticks3) unless _tmp self.pos = _save62 break end _tmp = _Sp() unless _tmp self.pos = _save62 break end _text_start = self.pos _save63 = self.pos _save64 = self.pos while true # choice _save65 = self.pos _save66 = self.pos while true # sequence _save67 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save67 unless _tmp self.pos = _save66 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save66 end break end # end sequence if _tmp while true _save68 = self.pos while true # sequence _save69 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save69 unless _tmp self.pos = _save68 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save68 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save65 end break if _tmp self.pos = _save64 _save70 = self.pos while true # sequence _save71 = self.pos _tmp = apply(:_Ticks3) _tmp = _tmp ? nil : true self.pos = _save71 unless _tmp self.pos = _save70 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save70 end break end # end sequence break if _tmp self.pos = _save64 _save72 = self.pos while true # sequence _save73 = self.pos _save74 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save74 break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save74 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save73 unless _tmp self.pos = _save72 break end _save75 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save75 _save76 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save76 break end _save77 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save77 unless _tmp self.pos = _save76 end break end # end sequence break if _tmp self.pos = _save75 break end # end choice unless _tmp self.pos = _save72 end break end # end sequence break if _tmp self.pos = _save64 break end # end choice if _tmp while true _save78 = self.pos while true # choice _save79 = self.pos _save80 = self.pos while true # sequence _save81 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save81 unless _tmp self.pos = _save80 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save80 end break end # end sequence if _tmp while true _save82 = self.pos while true # sequence _save83 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save83 unless _tmp self.pos = _save82 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save82 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save79 end break if _tmp self.pos = _save78 _save84 = self.pos while true # sequence _save85 = self.pos _tmp = apply(:_Ticks3) _tmp = _tmp ? nil : true self.pos = _save85 unless _tmp self.pos = _save84 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save84 end break end # end sequence break if _tmp self.pos = _save78 _save86 = self.pos while true # sequence _save87 = self.pos _save88 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save88 break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save88 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save87 unless _tmp self.pos = _save86 break end _save89 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save89 _save90 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save90 break end _save91 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save91 unless _tmp self.pos = _save90 end break end # end sequence break if _tmp self.pos = _save89 break end # end choice unless _tmp self.pos = _save86 end break end # end sequence break if _tmp self.pos = _save78 break end # end choice break unless _tmp end _tmp = true else self.pos = _save63 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save62 break end _tmp = _Sp() unless _tmp self.pos = _save62 break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save62 end break end # end sequence break if _tmp self.pos = _save1 _save92 = self.pos while true # sequence _tmp = apply(:_Ticks4) unless _tmp self.pos = _save92 break end _tmp = _Sp() unless _tmp self.pos = _save92 break end _text_start = self.pos _save93 = self.pos _save94 = self.pos while true # choice _save95 = self.pos _save96 = self.pos while true # sequence _save97 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save97 unless _tmp self.pos = _save96 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save96 end break end # end sequence if _tmp while true _save98 = self.pos while true # sequence _save99 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save99 unless _tmp self.pos = _save98 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save98 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save95 end break if _tmp self.pos = _save94 _save100 = self.pos while true # sequence _save101 = self.pos _tmp = apply(:_Ticks4) _tmp = _tmp ? nil : true self.pos = _save101 unless _tmp self.pos = _save100 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save100 end break end # end sequence break if _tmp self.pos = _save94 _save102 = self.pos while true # sequence _save103 = self.pos _save104 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save104 break end _tmp = apply(:_Ticks4) unless _tmp self.pos = _save104 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save103 unless _tmp self.pos = _save102 break end _save105 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save105 _save106 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save106 break end _save107 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save107 unless _tmp self.pos = _save106 end break end # end sequence break if _tmp self.pos = _save105 break end # end choice unless _tmp self.pos = _save102 end break end # end sequence break if _tmp self.pos = _save94 break end # end choice if _tmp while true _save108 = self.pos while true # choice _save109 = self.pos _save110 = self.pos while true # sequence _save111 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save111 unless _tmp self.pos = _save110 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save110 end break end # end sequence if _tmp while true _save112 = self.pos while true # sequence _save113 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save113 unless _tmp self.pos = _save112 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save112 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save109 end break if _tmp self.pos = _save108 _save114 = self.pos while true # sequence _save115 = self.pos _tmp = apply(:_Ticks4) _tmp = _tmp ? nil : true self.pos = _save115 unless _tmp self.pos = _save114 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save114 end break end # end sequence break if _tmp self.pos = _save108 _save116 = self.pos while true # sequence _save117 = self.pos _save118 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save118 break end _tmp = apply(:_Ticks4) unless _tmp self.pos = _save118 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save117 unless _tmp self.pos = _save116 break end _save119 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save119 _save120 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save120 break end _save121 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save121 unless _tmp self.pos = _save120 end break end # end sequence break if _tmp self.pos = _save119 break end # end choice unless _tmp self.pos = _save116 end break end # end sequence break if _tmp self.pos = _save108 break end # end choice break unless _tmp end _tmp = true else self.pos = _save93 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save92 break end _tmp = _Sp() unless _tmp self.pos = _save92 break end _tmp = apply(:_Ticks4) unless _tmp self.pos = _save92 end break end # end sequence break if _tmp self.pos = _save1 _save122 = self.pos while true # sequence _tmp = apply(:_Ticks5) unless _tmp self.pos = _save122 break end _tmp = _Sp() unless _tmp self.pos = _save122 break end _text_start = self.pos _save123 = self.pos _save124 = self.pos while true # choice _save125 = self.pos _save126 = self.pos while true # sequence _save127 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save127 unless _tmp self.pos = _save126 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save126 end break end # end sequence if _tmp while true _save128 = self.pos while true # sequence _save129 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save129 unless _tmp self.pos = _save128 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save128 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save125 end break if _tmp self.pos = _save124 _save130 = self.pos while true # sequence _save131 = self.pos _tmp = apply(:_Ticks5) _tmp = _tmp ? nil : true self.pos = _save131 unless _tmp self.pos = _save130 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save130 end break end # end sequence break if _tmp self.pos = _save124 _save132 = self.pos while true # sequence _save133 = self.pos _save134 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save134 break end _tmp = apply(:_Ticks5) unless _tmp self.pos = _save134 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save133 unless _tmp self.pos = _save132 break end _save135 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save135 _save136 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save136 break end _save137 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save137 unless _tmp self.pos = _save136 end break end # end sequence break if _tmp self.pos = _save135 break end # end choice unless _tmp self.pos = _save132 end break end # end sequence break if _tmp self.pos = _save124 break end # end choice if _tmp while true _save138 = self.pos while true # choice _save139 = self.pos _save140 = self.pos while true # sequence _save141 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save141 unless _tmp self.pos = _save140 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save140 end break end # end sequence if _tmp while true _save142 = self.pos while true # sequence _save143 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save143 unless _tmp self.pos = _save142 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save142 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save139 end break if _tmp self.pos = _save138 _save144 = self.pos while true # sequence _save145 = self.pos _tmp = apply(:_Ticks5) _tmp = _tmp ? nil : true self.pos = _save145 unless _tmp self.pos = _save144 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save144 end break end # end sequence break if _tmp self.pos = _save138 _save146 = self.pos while true # sequence _save147 = self.pos _save148 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save148 break end _tmp = apply(:_Ticks5) unless _tmp self.pos = _save148 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save147 unless _tmp self.pos = _save146 break end _save149 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save149 _save150 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save150 break end _save151 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save151 unless _tmp self.pos = _save150 end break end # end sequence break if _tmp self.pos = _save149 break end # end choice unless _tmp self.pos = _save146 end break end # end sequence break if _tmp self.pos = _save138 break end # end choice break unless _tmp end _tmp = true else self.pos = _save123 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save122 break end _tmp = _Sp() unless _tmp self.pos = _save122 break end _tmp = apply(:_Ticks5) unless _tmp self.pos = _save122 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end @result = begin; "#{text}" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Code unless _tmp return _tmp end # RawHtml = < (HtmlComment | HtmlBlockScript | HtmlTag) > { if html? then text else '' end } def _RawHtml _save = self.pos while true # sequence _text_start = self.pos _save1 = self.pos while true # choice _tmp = apply(:_HtmlComment) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlBlockScript) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlTag) break if _tmp self.pos = _save1 break end # end choice if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; if html? then text else '' end ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RawHtml unless _tmp return _tmp end # BlankLine = @Sp @Newline { "\n" } def _BlankLine _save = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end @result = begin; "\n" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_BlankLine unless _tmp return _tmp end # Quoted = ("\"" (!"\"" .)* "\"" | "'" (!"'" .)* "'") def _Quoted _save = self.pos while true # choice _save1 = self.pos while true # sequence _tmp = match_string("\"") unless _tmp self.pos = _save1 break end while true _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("\"") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save1 break end _tmp = match_string("\"") unless _tmp self.pos = _save1 end break end # end sequence break if _tmp self.pos = _save _save5 = self.pos while true # sequence _tmp = match_string("'") unless _tmp self.pos = _save5 break end while true _save7 = self.pos while true # sequence _save8 = self.pos _tmp = match_string("'") _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save7 break end _tmp = get_byte unless _tmp self.pos = _save7 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save5 break end _tmp = match_string("'") unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save break end # end choice set_failed_rule :_Quoted unless _tmp return _tmp end # HtmlAttribute = (AlphanumericAscii | "-")+ Spnl ("=" Spnl (Quoted | (!">" Nonspacechar)+))? Spnl def _HtmlAttribute _save = self.pos while true # sequence _save1 = self.pos _save2 = self.pos while true # choice _tmp = apply(:_AlphanumericAscii) break if _tmp self.pos = _save2 _tmp = match_string("-") break if _tmp self.pos = _save2 break end # end choice if _tmp while true _save3 = self.pos while true # choice _tmp = apply(:_AlphanumericAscii) break if _tmp self.pos = _save3 _tmp = match_string("-") break if _tmp self.pos = _save3 break end # end choice break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save4 = self.pos _save5 = self.pos while true # sequence _tmp = match_string("=") unless _tmp self.pos = _save5 break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save5 break end _save6 = self.pos while true # choice _tmp = apply(:_Quoted) break if _tmp self.pos = _save6 _save7 = self.pos _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save8 end break end # end sequence if _tmp while true _save10 = self.pos while true # sequence _save11 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save11 unless _tmp self.pos = _save10 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save10 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save7 end break if _tmp self.pos = _save6 break end # end choice unless _tmp self.pos = _save5 end break end # end sequence unless _tmp _tmp = true self.pos = _save4 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlAttribute unless _tmp return _tmp end # HtmlComment = "" .)* "-->" def _HtmlComment _save = self.pos while true # sequence _tmp = match_string("") _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("-->") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlComment unless _tmp return _tmp end # HtmlTag = "<" Spnl "/"? AlphanumericAscii+ Spnl HtmlAttribute* "/"? Spnl ">" def _HtmlTag _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("/") unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save break end _save2 = self.pos _tmp = apply(:_AlphanumericAscii) if _tmp while true _tmp = apply(:_AlphanumericAscii) break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _save4 = self.pos _tmp = match_string("/") unless _tmp _tmp = true self.pos = _save4 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlTag unless _tmp return _tmp end # Eof = !. def _Eof _save = self.pos _tmp = get_byte _tmp = _tmp ? nil : true self.pos = _save set_failed_rule :_Eof unless _tmp return _tmp end # Nonspacechar = !@Spacechar !@Newline . def _Nonspacechar _save = self.pos while true # sequence _save1 = self.pos _tmp = _Spacechar() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _tmp = get_byte unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Nonspacechar unless _tmp return _tmp end # Sp = @Spacechar* def _Sp while true _tmp = _Spacechar() break unless _tmp end _tmp = true set_failed_rule :_Sp unless _tmp return _tmp end # Spnl = @Sp (@Newline @Sp)? def _Spnl _save = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 end break end # end sequence unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Spnl unless _tmp return _tmp end # SpecialChar = (/[~*_`&\[\]()= 48 and _tmp <= 57 self.pos = _save _tmp = nil end end set_failed_rule :_Digit unless _tmp return _tmp end # Alphanumeric = %literals.Alphanumeric def _Alphanumeric _tmp = @_grammar_literals.external_invoke(self, :_Alphanumeric) set_failed_rule :_Alphanumeric unless _tmp return _tmp end # AlphanumericAscii = %literals.AlphanumericAscii def _AlphanumericAscii _tmp = @_grammar_literals.external_invoke(self, :_AlphanumericAscii) set_failed_rule :_AlphanumericAscii unless _tmp return _tmp end # BOM = %literals.BOM def _BOM _tmp = @_grammar_literals.external_invoke(self, :_BOM) set_failed_rule :_BOM unless _tmp return _tmp end # Newline = %literals.Newline def _Newline _tmp = @_grammar_literals.external_invoke(self, :_Newline) set_failed_rule :_Newline unless _tmp return _tmp end # Spacechar = %literals.Spacechar def _Spacechar _tmp = @_grammar_literals.external_invoke(self, :_Spacechar) set_failed_rule :_Spacechar unless _tmp return _tmp end # HexEntity = /&#x/i < /[0-9a-fA-F]+/ > ";" { [text.to_i(16)].pack 'U' } def _HexEntity _save = self.pos while true # sequence _tmp = scan(/\A(?i-mx:&#x)/) unless _tmp self.pos = _save break end _text_start = self.pos _tmp = scan(/\A(?-mix:[0-9a-fA-F]+)/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(";") unless _tmp self.pos = _save break end @result = begin; [text.to_i(16)].pack 'U' ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HexEntity unless _tmp return _tmp end # DecEntity = "&#" < /[0-9]+/ > ";" { [text.to_i].pack 'U' } def _DecEntity _save = self.pos while true # sequence _tmp = match_string("&#") unless _tmp self.pos = _save break end _text_start = self.pos _tmp = scan(/\A(?-mix:[0-9]+)/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(";") unless _tmp self.pos = _save break end @result = begin; [text.to_i].pack 'U' ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DecEntity unless _tmp return _tmp end # CharEntity = "&" < /[A-Za-z0-9]+/ > ";" { if entity = HTML_ENTITIES[text] then entity.pack 'U*' else "&#{text};" end } def _CharEntity _save = self.pos while true # sequence _tmp = match_string("&") unless _tmp self.pos = _save break end _text_start = self.pos _tmp = scan(/\A(?-mix:[A-Za-z0-9]+)/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(";") unless _tmp self.pos = _save break end @result = begin; if entity = HTML_ENTITIES[text] then entity.pack 'U*' else "&#{text};" end ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_CharEntity unless _tmp return _tmp end # NonindentSpace = / {0,3}/ def _NonindentSpace _tmp = scan(/\A(?-mix: {0,3})/) set_failed_rule :_NonindentSpace unless _tmp return _tmp end # Indent = /\t| / def _Indent _tmp = scan(/\A(?-mix:\t| )/) set_failed_rule :_Indent unless _tmp return _tmp end # IndentedLine = Indent Line def _IndentedLine _save = self.pos while true # sequence _tmp = apply(:_Indent) unless _tmp self.pos = _save break end _tmp = apply(:_Line) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_IndentedLine unless _tmp return _tmp end # OptionallyIndentedLine = Indent? Line def _OptionallyIndentedLine _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_Indent) unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save break end _tmp = apply(:_Line) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_OptionallyIndentedLine unless _tmp return _tmp end # StartList = &. { [] } def _StartList _save = self.pos while true # sequence _save1 = self.pos _tmp = get_byte self.pos = _save1 unless _tmp self.pos = _save break end @result = begin; [] ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StartList unless _tmp return _tmp end # Line = @RawLine:a { a } def _Line _save = self.pos while true # sequence _tmp = _RawLine() a = @result unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Line unless _tmp return _tmp end # RawLine = (< (!"\r" !"\n" .)* @Newline > | < .+ > @Eof) { text } def _RawLine _save = self.pos while true # sequence _save1 = self.pos while true # choice _text_start = self.pos _save2 = self.pos while true # sequence while true _save4 = self.pos while true # sequence _save5 = self.pos _tmp = match_string("\r") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _save6 = self.pos _tmp = match_string("\n") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save4 break end _tmp = get_byte unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save2 break end _tmp = _Newline() unless _tmp self.pos = _save2 end break end # end sequence if _tmp text = get_text(_text_start) end break if _tmp self.pos = _save1 _save7 = self.pos while true # sequence _text_start = self.pos _save8 = self.pos _tmp = get_byte if _tmp while true _tmp = get_byte break unless _tmp end _tmp = true else self.pos = _save8 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save7 break end _tmp = _Eof() unless _tmp self.pos = _save7 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RawLine unless _tmp return _tmp end # SkipBlock = (HtmlBlock | (!"#" !SetextBottom1 !SetextBottom2 !@BlankLine @RawLine)+ @BlankLine* | @BlankLine+ | @RawLine) def _SkipBlock _save = self.pos while true # choice _tmp = apply(:_HtmlBlock) break if _tmp self.pos = _save _save1 = self.pos while true # sequence _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("#") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _save5 = self.pos _tmp = apply(:_SetextBottom1) _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save3 break end _save6 = self.pos _tmp = apply(:_SetextBottom2) _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save3 break end _save7 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save3 break end _tmp = _RawLine() unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string("#") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _save10 = self.pos _tmp = apply(:_SetextBottom1) _tmp = _tmp ? nil : true self.pos = _save10 unless _tmp self.pos = _save8 break end _save11 = self.pos _tmp = apply(:_SetextBottom2) _tmp = _tmp ? nil : true self.pos = _save11 unless _tmp self.pos = _save8 break end _save12 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save12 unless _tmp self.pos = _save8 break end _tmp = _RawLine() unless _tmp self.pos = _save8 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save1 break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save1 end break end # end sequence break if _tmp self.pos = _save _save14 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save14 end break if _tmp self.pos = _save _tmp = _RawLine() break if _tmp self.pos = _save break end # end choice set_failed_rule :_SkipBlock unless _tmp return _tmp end # ExtendedSpecialChar = &{ notes? } "^" def _ExtendedSpecialChar _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; notes? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = match_string("^") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ExtendedSpecialChar unless _tmp return _tmp end # NoteReference = &{ notes? } RawNoteReference:ref { note_for ref } def _NoteReference _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; notes? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_RawNoteReference) ref = @result unless _tmp self.pos = _save break end @result = begin; note_for ref ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_NoteReference unless _tmp return _tmp end # RawNoteReference = "[^" < (!@Newline !"]" .)+ > "]" { text } def _RawNoteReference _save = self.pos while true # sequence _tmp = match_string("[^") unless _tmp self.pos = _save break end _text_start = self.pos _save1 = self.pos _save2 = self.pos while true # sequence _save3 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _save4 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence if _tmp while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _save7 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save5 break end _tmp = get_byte unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string("]") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RawNoteReference unless _tmp return _tmp end # Note = &{ notes? } @NonindentSpace RawNoteReference:ref ":" @Sp @StartList:a RawNoteBlock:i { a.concat i } (&Indent RawNoteBlock:i { a.concat i })* { @footnotes[ref] = paragraph a nil } def _Note _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; notes? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _tmp = apply(:_RawNoteReference) ref = @result unless _tmp self.pos = _save break end _tmp = match_string(":") unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _tmp = apply(:_RawNoteBlock) i = @result unless _tmp self.pos = _save break end @result = begin; a.concat i ; end _tmp = true unless _tmp self.pos = _save break end while true _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_Indent) self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_RawNoteBlock) i = @result unless _tmp self.pos = _save3 break end @result = begin; a.concat i ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; @footnotes[ref] = paragraph a nil ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Note unless _tmp return _tmp end # InlineNote = &{ notes? } "^[" @StartList:a (!"]" Inline:l { a << l })+ "]" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref } def _InlineNote _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; notes? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = match_string("^[") unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_Inline) l = @result unless _tmp self.pos = _save3 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _tmp = apply(:_Inline) l = @result unless _tmp self.pos = _save5 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("]") unless _tmp self.pos = _save break end @result = begin; ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_InlineNote unless _tmp return _tmp end # Notes = (Note | SkipBlock)* def _Notes while true _save1 = self.pos while true # choice _tmp = apply(:_Note) break if _tmp self.pos = _save1 _tmp = apply(:_SkipBlock) break if _tmp self.pos = _save1 break end # end choice break unless _tmp end _tmp = true set_failed_rule :_Notes unless _tmp return _tmp end # RawNoteBlock = @StartList:a (!@BlankLine OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a } def _RawNoteBlock _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos while true # sequence _save3 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = apply(:_OptionallyIndentedLine) l = @result unless _tmp self.pos = _save2 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence if _tmp while true _save4 = self.pos while true # sequence _save5 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_OptionallyIndentedLine) l = @result unless _tmp self.pos = _save4 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end _text_start = self.pos while true _tmp = _BlankLine() break unless _tmp end _tmp = true if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; a << text ; end _tmp = true unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RawNoteBlock unless _tmp return _tmp end # CodeFence = &{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!"`" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim } def _CodeFence _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; github? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save3 break end _tmp = apply(:_StrChunk) format = @result unless _tmp self.pos = _save3 end break end # end sequence unless _tmp _tmp = true self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _text_start = self.pos _save4 = self.pos _save5 = self.pos while true # choice _save6 = self.pos _save7 = self.pos while true # sequence _save8 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save7 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save7 end break end # end sequence if _tmp while true _save9 = self.pos while true # sequence _save10 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save10 unless _tmp self.pos = _save9 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save9 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save6 end break if _tmp self.pos = _save5 _save11 = self.pos while true # sequence _save12 = self.pos _tmp = apply(:_Ticks3) _tmp = _tmp ? nil : true self.pos = _save12 unless _tmp self.pos = _save11 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save11 end break end # end sequence break if _tmp self.pos = _save5 _tmp = apply(:_Spacechar) break if _tmp self.pos = _save5 _tmp = _Newline() break if _tmp self.pos = _save5 break end # end choice if _tmp while true _save13 = self.pos while true # choice _save14 = self.pos _save15 = self.pos while true # sequence _save16 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save16 unless _tmp self.pos = _save15 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save15 end break end # end sequence if _tmp while true _save17 = self.pos while true # sequence _save18 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save18 unless _tmp self.pos = _save17 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save17 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save14 end break if _tmp self.pos = _save13 _save19 = self.pos while true # sequence _save20 = self.pos _tmp = apply(:_Ticks3) _tmp = _tmp ? nil : true self.pos = _save20 unless _tmp self.pos = _save19 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save19 end break end # end sequence break if _tmp self.pos = _save13 _tmp = apply(:_Spacechar) break if _tmp self.pos = _save13 _tmp = _Newline() break if _tmp self.pos = _save13 break end # end choice break unless _tmp end _tmp = true else self.pos = _save4 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end while true _tmp = _Newline() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_CodeFence unless _tmp return _tmp end # DefinitionList = &{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten } def _DefinitionList _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; definition_lists? ; end self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _ary = [] _tmp = apply(:_DefinitionListItem) if _tmp _ary << @result while true _tmp = apply(:_DefinitionListItem) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save2 end list = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::List.new :NOTE, *list.flatten ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DefinitionList unless _tmp return _tmp end # DefinitionListItem = DefinitionListLabel+:label DefinitionListDefinition+:defns { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items } def _DefinitionListItem _save = self.pos while true # sequence _save1 = self.pos _ary = [] _tmp = apply(:_DefinitionListLabel) if _tmp _ary << @result while true _tmp = apply(:_DefinitionListLabel) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end label = @result unless _tmp self.pos = _save break end _save2 = self.pos _ary = [] _tmp = apply(:_DefinitionListDefinition) if _tmp _ary << @result while true _tmp = apply(:_DefinitionListDefinition) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save2 end defns = @result unless _tmp self.pos = _save break end @result = begin; list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DefinitionListItem unless _tmp return _tmp end # DefinitionListLabel = StrChunk:label @Sp @Newline { label } def _DefinitionListLabel _save = self.pos while true # sequence _tmp = apply(:_StrChunk) label = @result unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end @result = begin; label ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DefinitionListLabel unless _tmp return _tmp end # DefinitionListDefinition = @NonindentSpace ":" @Space Inlines:a @BlankLine+ { paragraph a } def _DefinitionListDefinition _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _tmp = match_string(":") unless _tmp self.pos = _save break end _tmp = _Space() unless _tmp self.pos = _save break end _tmp = apply(:_Inlines) a = @result unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; paragraph a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DefinitionListDefinition unless _tmp return _tmp end Rules = {} Rules[:_root] = rule_info("root", "Doc") Rules[:_Doc] = rule_info("Doc", "BOM? Block*:a { RDoc::Markup::Document.new(*a.compact) }") Rules[:_Block] = rule_info("Block", "@BlankLine* (BlockQuote | Verbatim | CodeFence | Note | Reference | HorizontalRule | Heading | OrderedList | BulletList | DefinitionList | HtmlBlock | StyleBlock | Para | Plain)") Rules[:_Para] = rule_info("Para", "@NonindentSpace Inlines:a @BlankLine+ { paragraph a }") Rules[:_Plain] = rule_info("Plain", "Inlines:a { paragraph a }") Rules[:_AtxInline] = rule_info("AtxInline", "!@Newline !(@Sp /\#*/ @Sp @Newline) Inline") Rules[:_AtxStart] = rule_info("AtxStart", "< /\\\#{1,6}/ > { text.length }") Rules[:_AtxHeading] = rule_info("AtxHeading", "AtxStart:s @Sp AtxInline+:a (@Sp /\#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) }") Rules[:_SetextHeading] = rule_info("SetextHeading", "(SetextHeading1 | SetextHeading2)") Rules[:_SetextBottom1] = rule_info("SetextBottom1", "/={1,}/ @Newline") Rules[:_SetextBottom2] = rule_info("SetextBottom2", "/-{1,}/ @Newline") Rules[:_SetextHeading1] = rule_info("SetextHeading1", "&(@RawLine SetextBottom1) @StartList:a (!@Endline Inline:b { a << b })+ @Sp @Newline SetextBottom1 { RDoc::Markup::Heading.new(1, a.join) }") Rules[:_SetextHeading2] = rule_info("SetextHeading2", "&(@RawLine SetextBottom2) @StartList:a (!@Endline Inline:b { a << b })+ @Sp @Newline SetextBottom2 { RDoc::Markup::Heading.new(2, a.join) }") Rules[:_Heading] = rule_info("Heading", "(SetextHeading | AtxHeading)") Rules[:_BlockQuote] = rule_info("BlockQuote", "BlockQuoteRaw:a { RDoc::Markup::BlockQuote.new(*a) }") Rules[:_BlockQuoteRaw] = rule_info("BlockQuoteRaw", "@StartList:a (\">\" \" \"? Line:l { a << l } (!\">\" !@BlankLine Line:c { a << c })* (@BlankLine:n { a << n })*)+ { inner_parse a.join }") Rules[:_NonblankIndentedLine] = rule_info("NonblankIndentedLine", "!@BlankLine IndentedLine") Rules[:_VerbatimChunk] = rule_info("VerbatimChunk", "@BlankLine*:a NonblankIndentedLine+:b { a.concat b }") Rules[:_Verbatim] = rule_info("Verbatim", "VerbatimChunk+:a { RDoc::Markup::Verbatim.new(*a.flatten) }") Rules[:_HorizontalRule] = rule_info("HorizontalRule", "@NonindentSpace (\"*\" @Sp \"*\" @Sp \"*\" (@Sp \"*\")* | \"-\" @Sp \"-\" @Sp \"-\" (@Sp \"-\")* | \"_\" @Sp \"_\" @Sp \"_\" (@Sp \"_\")*) @Sp @Newline @BlankLine+ { RDoc::Markup::Rule.new 1 }") Rules[:_Bullet] = rule_info("Bullet", "!HorizontalRule @NonindentSpace /[+*-]/ @Spacechar+") Rules[:_BulletList] = rule_info("BulletList", "&Bullet (ListTight | ListLoose):a { RDoc::Markup::List.new(:BULLET, *a) }") Rules[:_ListTight] = rule_info("ListTight", "ListItemTight+:a @BlankLine* !(Bullet | Enumerator) { a }") Rules[:_ListLoose] = rule_info("ListLoose", "@StartList:a (ListItem:b @BlankLine* { a << b })+ { a }") Rules[:_ListItem] = rule_info("ListItem", "(Bullet | Enumerator) @StartList:a ListBlock:b { a << b } (ListContinuationBlock:c { a.push(*c) })* { list_item_from a }") Rules[:_ListItemTight] = rule_info("ListItemTight", "(Bullet | Enumerator) ListBlock:a (!@BlankLine ListContinuationBlock:b { a.push(*b) })* !ListContinuationBlock { list_item_from a }") Rules[:_ListBlock] = rule_info("ListBlock", "!@BlankLine Line:a ListBlockLine*:c { [a, *c] }") Rules[:_ListContinuationBlock] = rule_info("ListContinuationBlock", "@StartList:a @BlankLine* { a << \"\\n\" } (Indent ListBlock:b { a.concat b })+ { a }") Rules[:_Enumerator] = rule_info("Enumerator", "@NonindentSpace [0-9]+ \".\" @Spacechar+") Rules[:_OrderedList] = rule_info("OrderedList", "&Enumerator (ListTight | ListLoose):a { RDoc::Markup::List.new(:NUMBER, *a) }") Rules[:_ListBlockLine] = rule_info("ListBlockLine", "!@BlankLine !(Indent? (Bullet | Enumerator)) !HorizontalRule OptionallyIndentedLine") Rules[:_HtmlOpenAnchor] = rule_info("HtmlOpenAnchor", "\"<\" Spnl (\"a\" | \"A\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlCloseAnchor] = rule_info("HtmlCloseAnchor", "\"<\" Spnl \"/\" (\"a\" | \"A\") Spnl \">\"") Rules[:_HtmlAnchor] = rule_info("HtmlAnchor", "HtmlOpenAnchor (HtmlAnchor | !HtmlCloseAnchor .)* HtmlCloseAnchor") Rules[:_HtmlBlockOpenAddress] = rule_info("HtmlBlockOpenAddress", "\"<\" Spnl (\"address\" | \"ADDRESS\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseAddress] = rule_info("HtmlBlockCloseAddress", "\"<\" Spnl \"/\" (\"address\" | \"ADDRESS\") Spnl \">\"") Rules[:_HtmlBlockAddress] = rule_info("HtmlBlockAddress", "HtmlBlockOpenAddress (HtmlBlockAddress | !HtmlBlockCloseAddress .)* HtmlBlockCloseAddress") Rules[:_HtmlBlockOpenBlockquote] = rule_info("HtmlBlockOpenBlockquote", "\"<\" Spnl (\"blockquote\" | \"BLOCKQUOTE\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseBlockquote] = rule_info("HtmlBlockCloseBlockquote", "\"<\" Spnl \"/\" (\"blockquote\" | \"BLOCKQUOTE\") Spnl \">\"") Rules[:_HtmlBlockBlockquote] = rule_info("HtmlBlockBlockquote", "HtmlBlockOpenBlockquote (HtmlBlockBlockquote | !HtmlBlockCloseBlockquote .)* HtmlBlockCloseBlockquote") Rules[:_HtmlBlockOpenCenter] = rule_info("HtmlBlockOpenCenter", "\"<\" Spnl (\"center\" | \"CENTER\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseCenter] = rule_info("HtmlBlockCloseCenter", "\"<\" Spnl \"/\" (\"center\" | \"CENTER\") Spnl \">\"") Rules[:_HtmlBlockCenter] = rule_info("HtmlBlockCenter", "HtmlBlockOpenCenter (HtmlBlockCenter | !HtmlBlockCloseCenter .)* HtmlBlockCloseCenter") Rules[:_HtmlBlockOpenDir] = rule_info("HtmlBlockOpenDir", "\"<\" Spnl (\"dir\" | \"DIR\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDir] = rule_info("HtmlBlockCloseDir", "\"<\" Spnl \"/\" (\"dir\" | \"DIR\") Spnl \">\"") Rules[:_HtmlBlockDir] = rule_info("HtmlBlockDir", "HtmlBlockOpenDir (HtmlBlockDir | !HtmlBlockCloseDir .)* HtmlBlockCloseDir") Rules[:_HtmlBlockOpenDiv] = rule_info("HtmlBlockOpenDiv", "\"<\" Spnl (\"div\" | \"DIV\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDiv] = rule_info("HtmlBlockCloseDiv", "\"<\" Spnl \"/\" (\"div\" | \"DIV\") Spnl \">\"") Rules[:_HtmlBlockDiv] = rule_info("HtmlBlockDiv", "HtmlBlockOpenDiv (HtmlBlockDiv | !HtmlBlockCloseDiv .)* HtmlBlockCloseDiv") Rules[:_HtmlBlockOpenDl] = rule_info("HtmlBlockOpenDl", "\"<\" Spnl (\"dl\" | \"DL\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDl] = rule_info("HtmlBlockCloseDl", "\"<\" Spnl \"/\" (\"dl\" | \"DL\") Spnl \">\"") Rules[:_HtmlBlockDl] = rule_info("HtmlBlockDl", "HtmlBlockOpenDl (HtmlBlockDl | !HtmlBlockCloseDl .)* HtmlBlockCloseDl") Rules[:_HtmlBlockOpenFieldset] = rule_info("HtmlBlockOpenFieldset", "\"<\" Spnl (\"fieldset\" | \"FIELDSET\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseFieldset] = rule_info("HtmlBlockCloseFieldset", "\"<\" Spnl \"/\" (\"fieldset\" | \"FIELDSET\") Spnl \">\"") Rules[:_HtmlBlockFieldset] = rule_info("HtmlBlockFieldset", "HtmlBlockOpenFieldset (HtmlBlockFieldset | !HtmlBlockCloseFieldset .)* HtmlBlockCloseFieldset") Rules[:_HtmlBlockOpenForm] = rule_info("HtmlBlockOpenForm", "\"<\" Spnl (\"form\" | \"FORM\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseForm] = rule_info("HtmlBlockCloseForm", "\"<\" Spnl \"/\" (\"form\" | \"FORM\") Spnl \">\"") Rules[:_HtmlBlockForm] = rule_info("HtmlBlockForm", "HtmlBlockOpenForm (HtmlBlockForm | !HtmlBlockCloseForm .)* HtmlBlockCloseForm") Rules[:_HtmlBlockOpenH1] = rule_info("HtmlBlockOpenH1", "\"<\" Spnl (\"h1\" | \"H1\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH1] = rule_info("HtmlBlockCloseH1", "\"<\" Spnl \"/\" (\"h1\" | \"H1\") Spnl \">\"") Rules[:_HtmlBlockH1] = rule_info("HtmlBlockH1", "HtmlBlockOpenH1 (HtmlBlockH1 | !HtmlBlockCloseH1 .)* HtmlBlockCloseH1") Rules[:_HtmlBlockOpenH2] = rule_info("HtmlBlockOpenH2", "\"<\" Spnl (\"h2\" | \"H2\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH2] = rule_info("HtmlBlockCloseH2", "\"<\" Spnl \"/\" (\"h2\" | \"H2\") Spnl \">\"") Rules[:_HtmlBlockH2] = rule_info("HtmlBlockH2", "HtmlBlockOpenH2 (HtmlBlockH2 | !HtmlBlockCloseH2 .)* HtmlBlockCloseH2") Rules[:_HtmlBlockOpenH3] = rule_info("HtmlBlockOpenH3", "\"<\" Spnl (\"h3\" | \"H3\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH3] = rule_info("HtmlBlockCloseH3", "\"<\" Spnl \"/\" (\"h3\" | \"H3\") Spnl \">\"") Rules[:_HtmlBlockH3] = rule_info("HtmlBlockH3", "HtmlBlockOpenH3 (HtmlBlockH3 | !HtmlBlockCloseH3 .)* HtmlBlockCloseH3") Rules[:_HtmlBlockOpenH4] = rule_info("HtmlBlockOpenH4", "\"<\" Spnl (\"h4\" | \"H4\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH4] = rule_info("HtmlBlockCloseH4", "\"<\" Spnl \"/\" (\"h4\" | \"H4\") Spnl \">\"") Rules[:_HtmlBlockH4] = rule_info("HtmlBlockH4", "HtmlBlockOpenH4 (HtmlBlockH4 | !HtmlBlockCloseH4 .)* HtmlBlockCloseH4") Rules[:_HtmlBlockOpenH5] = rule_info("HtmlBlockOpenH5", "\"<\" Spnl (\"h5\" | \"H5\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH5] = rule_info("HtmlBlockCloseH5", "\"<\" Spnl \"/\" (\"h5\" | \"H5\") Spnl \">\"") Rules[:_HtmlBlockH5] = rule_info("HtmlBlockH5", "HtmlBlockOpenH5 (HtmlBlockH5 | !HtmlBlockCloseH5 .)* HtmlBlockCloseH5") Rules[:_HtmlBlockOpenH6] = rule_info("HtmlBlockOpenH6", "\"<\" Spnl (\"h6\" | \"H6\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH6] = rule_info("HtmlBlockCloseH6", "\"<\" Spnl \"/\" (\"h6\" | \"H6\") Spnl \">\"") Rules[:_HtmlBlockH6] = rule_info("HtmlBlockH6", "HtmlBlockOpenH6 (HtmlBlockH6 | !HtmlBlockCloseH6 .)* HtmlBlockCloseH6") Rules[:_HtmlBlockOpenMenu] = rule_info("HtmlBlockOpenMenu", "\"<\" Spnl (\"menu\" | \"MENU\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseMenu] = rule_info("HtmlBlockCloseMenu", "\"<\" Spnl \"/\" (\"menu\" | \"MENU\") Spnl \">\"") Rules[:_HtmlBlockMenu] = rule_info("HtmlBlockMenu", "HtmlBlockOpenMenu (HtmlBlockMenu | !HtmlBlockCloseMenu .)* HtmlBlockCloseMenu") Rules[:_HtmlBlockOpenNoframes] = rule_info("HtmlBlockOpenNoframes", "\"<\" Spnl (\"noframes\" | \"NOFRAMES\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseNoframes] = rule_info("HtmlBlockCloseNoframes", "\"<\" Spnl \"/\" (\"noframes\" | \"NOFRAMES\") Spnl \">\"") Rules[:_HtmlBlockNoframes] = rule_info("HtmlBlockNoframes", "HtmlBlockOpenNoframes (HtmlBlockNoframes | !HtmlBlockCloseNoframes .)* HtmlBlockCloseNoframes") Rules[:_HtmlBlockOpenNoscript] = rule_info("HtmlBlockOpenNoscript", "\"<\" Spnl (\"noscript\" | \"NOSCRIPT\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseNoscript] = rule_info("HtmlBlockCloseNoscript", "\"<\" Spnl \"/\" (\"noscript\" | \"NOSCRIPT\") Spnl \">\"") Rules[:_HtmlBlockNoscript] = rule_info("HtmlBlockNoscript", "HtmlBlockOpenNoscript (HtmlBlockNoscript | !HtmlBlockCloseNoscript .)* HtmlBlockCloseNoscript") Rules[:_HtmlBlockOpenOl] = rule_info("HtmlBlockOpenOl", "\"<\" Spnl (\"ol\" | \"OL\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseOl] = rule_info("HtmlBlockCloseOl", "\"<\" Spnl \"/\" (\"ol\" | \"OL\") Spnl \">\"") Rules[:_HtmlBlockOl] = rule_info("HtmlBlockOl", "HtmlBlockOpenOl (HtmlBlockOl | !HtmlBlockCloseOl .)* HtmlBlockCloseOl") Rules[:_HtmlBlockOpenP] = rule_info("HtmlBlockOpenP", "\"<\" Spnl (\"p\" | \"P\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseP] = rule_info("HtmlBlockCloseP", "\"<\" Spnl \"/\" (\"p\" | \"P\") Spnl \">\"") Rules[:_HtmlBlockP] = rule_info("HtmlBlockP", "HtmlBlockOpenP (HtmlBlockP | !HtmlBlockCloseP .)* HtmlBlockCloseP") Rules[:_HtmlBlockOpenPre] = rule_info("HtmlBlockOpenPre", "\"<\" Spnl (\"pre\" | \"PRE\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockClosePre] = rule_info("HtmlBlockClosePre", "\"<\" Spnl \"/\" (\"pre\" | \"PRE\") Spnl \">\"") Rules[:_HtmlBlockPre] = rule_info("HtmlBlockPre", "HtmlBlockOpenPre (HtmlBlockPre | !HtmlBlockClosePre .)* HtmlBlockClosePre") Rules[:_HtmlBlockOpenTable] = rule_info("HtmlBlockOpenTable", "\"<\" Spnl (\"table\" | \"TABLE\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTable] = rule_info("HtmlBlockCloseTable", "\"<\" Spnl \"/\" (\"table\" | \"TABLE\") Spnl \">\"") Rules[:_HtmlBlockTable] = rule_info("HtmlBlockTable", "HtmlBlockOpenTable (HtmlBlockTable | !HtmlBlockCloseTable .)* HtmlBlockCloseTable") Rules[:_HtmlBlockOpenUl] = rule_info("HtmlBlockOpenUl", "\"<\" Spnl (\"ul\" | \"UL\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseUl] = rule_info("HtmlBlockCloseUl", "\"<\" Spnl \"/\" (\"ul\" | \"UL\") Spnl \">\"") Rules[:_HtmlBlockUl] = rule_info("HtmlBlockUl", "HtmlBlockOpenUl (HtmlBlockUl | !HtmlBlockCloseUl .)* HtmlBlockCloseUl") Rules[:_HtmlBlockOpenDd] = rule_info("HtmlBlockOpenDd", "\"<\" Spnl (\"dd\" | \"DD\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDd] = rule_info("HtmlBlockCloseDd", "\"<\" Spnl \"/\" (\"dd\" | \"DD\") Spnl \">\"") Rules[:_HtmlBlockDd] = rule_info("HtmlBlockDd", "HtmlBlockOpenDd (HtmlBlockDd | !HtmlBlockCloseDd .)* HtmlBlockCloseDd") Rules[:_HtmlBlockOpenDt] = rule_info("HtmlBlockOpenDt", "\"<\" Spnl (\"dt\" | \"DT\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDt] = rule_info("HtmlBlockCloseDt", "\"<\" Spnl \"/\" (\"dt\" | \"DT\") Spnl \">\"") Rules[:_HtmlBlockDt] = rule_info("HtmlBlockDt", "HtmlBlockOpenDt (HtmlBlockDt | !HtmlBlockCloseDt .)* HtmlBlockCloseDt") Rules[:_HtmlBlockOpenFrameset] = rule_info("HtmlBlockOpenFrameset", "\"<\" Spnl (\"frameset\" | \"FRAMESET\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseFrameset] = rule_info("HtmlBlockCloseFrameset", "\"<\" Spnl \"/\" (\"frameset\" | \"FRAMESET\") Spnl \">\"") Rules[:_HtmlBlockFrameset] = rule_info("HtmlBlockFrameset", "HtmlBlockOpenFrameset (HtmlBlockFrameset | !HtmlBlockCloseFrameset .)* HtmlBlockCloseFrameset") Rules[:_HtmlBlockOpenLi] = rule_info("HtmlBlockOpenLi", "\"<\" Spnl (\"li\" | \"LI\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseLi] = rule_info("HtmlBlockCloseLi", "\"<\" Spnl \"/\" (\"li\" | \"LI\") Spnl \">\"") Rules[:_HtmlBlockLi] = rule_info("HtmlBlockLi", "HtmlBlockOpenLi (HtmlBlockLi | !HtmlBlockCloseLi .)* HtmlBlockCloseLi") Rules[:_HtmlBlockOpenTbody] = rule_info("HtmlBlockOpenTbody", "\"<\" Spnl (\"tbody\" | \"TBODY\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTbody] = rule_info("HtmlBlockCloseTbody", "\"<\" Spnl \"/\" (\"tbody\" | \"TBODY\") Spnl \">\"") Rules[:_HtmlBlockTbody] = rule_info("HtmlBlockTbody", "HtmlBlockOpenTbody (HtmlBlockTbody | !HtmlBlockCloseTbody .)* HtmlBlockCloseTbody") Rules[:_HtmlBlockOpenTd] = rule_info("HtmlBlockOpenTd", "\"<\" Spnl (\"td\" | \"TD\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTd] = rule_info("HtmlBlockCloseTd", "\"<\" Spnl \"/\" (\"td\" | \"TD\") Spnl \">\"") Rules[:_HtmlBlockTd] = rule_info("HtmlBlockTd", "HtmlBlockOpenTd (HtmlBlockTd | !HtmlBlockCloseTd .)* HtmlBlockCloseTd") Rules[:_HtmlBlockOpenTfoot] = rule_info("HtmlBlockOpenTfoot", "\"<\" Spnl (\"tfoot\" | \"TFOOT\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTfoot] = rule_info("HtmlBlockCloseTfoot", "\"<\" Spnl \"/\" (\"tfoot\" | \"TFOOT\") Spnl \">\"") Rules[:_HtmlBlockTfoot] = rule_info("HtmlBlockTfoot", "HtmlBlockOpenTfoot (HtmlBlockTfoot | !HtmlBlockCloseTfoot .)* HtmlBlockCloseTfoot") Rules[:_HtmlBlockOpenTh] = rule_info("HtmlBlockOpenTh", "\"<\" Spnl (\"th\" | \"TH\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTh] = rule_info("HtmlBlockCloseTh", "\"<\" Spnl \"/\" (\"th\" | \"TH\") Spnl \">\"") Rules[:_HtmlBlockTh] = rule_info("HtmlBlockTh", "HtmlBlockOpenTh (HtmlBlockTh | !HtmlBlockCloseTh .)* HtmlBlockCloseTh") Rules[:_HtmlBlockOpenThead] = rule_info("HtmlBlockOpenThead", "\"<\" Spnl (\"thead\" | \"THEAD\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseThead] = rule_info("HtmlBlockCloseThead", "\"<\" Spnl \"/\" (\"thead\" | \"THEAD\") Spnl \">\"") Rules[:_HtmlBlockThead] = rule_info("HtmlBlockThead", "HtmlBlockOpenThead (HtmlBlockThead | !HtmlBlockCloseThead .)* HtmlBlockCloseThead") Rules[:_HtmlBlockOpenTr] = rule_info("HtmlBlockOpenTr", "\"<\" Spnl (\"tr\" | \"TR\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTr] = rule_info("HtmlBlockCloseTr", "\"<\" Spnl \"/\" (\"tr\" | \"TR\") Spnl \">\"") Rules[:_HtmlBlockTr] = rule_info("HtmlBlockTr", "HtmlBlockOpenTr (HtmlBlockTr | !HtmlBlockCloseTr .)* HtmlBlockCloseTr") Rules[:_HtmlBlockOpenScript] = rule_info("HtmlBlockOpenScript", "\"<\" Spnl (\"script\" | \"SCRIPT\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseScript] = rule_info("HtmlBlockCloseScript", "\"<\" Spnl \"/\" (\"script\" | \"SCRIPT\") Spnl \">\"") Rules[:_HtmlBlockScript] = rule_info("HtmlBlockScript", "HtmlBlockOpenScript (!HtmlBlockCloseScript .)* HtmlBlockCloseScript") Rules[:_HtmlBlockOpenHead] = rule_info("HtmlBlockOpenHead", "\"<\" Spnl (\"head\" | \"HEAD\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseHead] = rule_info("HtmlBlockCloseHead", "\"<\" Spnl \"/\" (\"head\" | \"HEAD\") Spnl \">\"") Rules[:_HtmlBlockHead] = rule_info("HtmlBlockHead", "HtmlBlockOpenHead (!HtmlBlockCloseHead .)* HtmlBlockCloseHead") Rules[:_HtmlBlockInTags] = rule_info("HtmlBlockInTags", "(HtmlAnchor | HtmlBlockAddress | HtmlBlockBlockquote | HtmlBlockCenter | HtmlBlockDir | HtmlBlockDiv | HtmlBlockDl | HtmlBlockFieldset | HtmlBlockForm | HtmlBlockH1 | HtmlBlockH2 | HtmlBlockH3 | HtmlBlockH4 | HtmlBlockH5 | HtmlBlockH6 | HtmlBlockMenu | HtmlBlockNoframes | HtmlBlockNoscript | HtmlBlockOl | HtmlBlockP | HtmlBlockPre | HtmlBlockTable | HtmlBlockUl | HtmlBlockDd | HtmlBlockDt | HtmlBlockFrameset | HtmlBlockLi | HtmlBlockTbody | HtmlBlockTd | HtmlBlockTfoot | HtmlBlockTh | HtmlBlockThead | HtmlBlockTr | HtmlBlockScript | HtmlBlockHead)") Rules[:_HtmlBlock] = rule_info("HtmlBlock", "< (HtmlBlockInTags | HtmlComment | HtmlBlockSelfClosing | HtmlUnclosed) > @BlankLine+ { if html? then RDoc::Markup::Raw.new text end }") Rules[:_HtmlUnclosed] = rule_info("HtmlUnclosed", "\"<\" Spnl HtmlUnclosedType Spnl HtmlAttribute* Spnl \">\"") Rules[:_HtmlUnclosedType] = rule_info("HtmlUnclosedType", "(\"HR\" | \"hr\")") Rules[:_HtmlBlockSelfClosing] = rule_info("HtmlBlockSelfClosing", "\"<\" Spnl HtmlBlockType Spnl HtmlAttribute* \"/\" Spnl \">\"") Rules[:_HtmlBlockType] = rule_info("HtmlBlockType", "(\"ADDRESS\" | \"BLOCKQUOTE\" | \"CENTER\" | \"DD\" | \"DIR\" | \"DIV\" | \"DL\" | \"DT\" | \"FIELDSET\" | \"FORM\" | \"FRAMESET\" | \"H1\" | \"H2\" | \"H3\" | \"H4\" | \"H5\" | \"H6\" | \"HR\" | \"ISINDEX\" | \"LI\" | \"MENU\" | \"NOFRAMES\" | \"NOSCRIPT\" | \"OL\" | \"P\" | \"PRE\" | \"SCRIPT\" | \"TABLE\" | \"TBODY\" | \"TD\" | \"TFOOT\" | \"TH\" | \"THEAD\" | \"TR\" | \"UL\" | \"address\" | \"blockquote\" | \"center\" | \"dd\" | \"dir\" | \"div\" | \"dl\" | \"dt\" | \"fieldset\" | \"form\" | \"frameset\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"hr\" | \"isindex\" | \"li\" | \"menu\" | \"noframes\" | \"noscript\" | \"ol\" | \"p\" | \"pre\" | \"script\" | \"table\" | \"tbody\" | \"td\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"ul\")") Rules[:_StyleOpen] = rule_info("StyleOpen", "\"<\" Spnl (\"style\" | \"STYLE\") Spnl HtmlAttribute* \">\"") Rules[:_StyleClose] = rule_info("StyleClose", "\"<\" Spnl \"/\" (\"style\" | \"STYLE\") Spnl \">\"") Rules[:_InStyleTags] = rule_info("InStyleTags", "StyleOpen (!StyleClose .)* StyleClose") Rules[:_StyleBlock] = rule_info("StyleBlock", "< InStyleTags > @BlankLine* { if css? then RDoc::Markup::Raw.new text end }") Rules[:_Inlines] = rule_info("Inlines", "(!@Endline Inline:i { i } | @Endline:c &Inline { c })+:chunks @Endline? { chunks }") Rules[:_Inline] = rule_info("Inline", "(Str | @Endline | UlOrStarLine | @Space | Strong | Emph | Strike | Image | Link | NoteReference | InlineNote | Code | RawHtml | Entity | EscapedChar | Symbol)") Rules[:_Space] = rule_info("Space", "@Spacechar+ { \" \" }") Rules[:_Str] = rule_info("Str", "@StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { a }") Rules[:_StrChunk] = rule_info("StrChunk", "< (@NormalChar | /_+/ &Alphanumeric)+ > { text }") Rules[:_EscapedChar] = rule_info("EscapedChar", "\"\\\\\" !@Newline < /[:\\\\`|*_{}\\[\\]()\#+.!><-]/ > { text }") Rules[:_Entity] = rule_info("Entity", "(HexEntity | DecEntity | CharEntity):a { a }") Rules[:_Endline] = rule_info("Endline", "(@LineBreak | @TerminalEndline | @NormalEndline)") Rules[:_NormalEndline] = rule_info("NormalEndline", "@Sp @Newline !@BlankLine !\">\" !AtxStart !(Line /={1,}|-{1,}/ @Newline) { \"\\n\" }") Rules[:_TerminalEndline] = rule_info("TerminalEndline", "@Sp @Newline @Eof") Rules[:_LineBreak] = rule_info("LineBreak", "\" \" @NormalEndline { RDoc::Markup::HardBreak.new }") Rules[:_Symbol] = rule_info("Symbol", "< @SpecialChar > { text }") Rules[:_UlOrStarLine] = rule_info("UlOrStarLine", "(UlLine | StarLine):a { a }") Rules[:_StarLine] = rule_info("StarLine", "(< /\\*{4,}/ > { text } | < @Spacechar /\\*+/ &@Spacechar > { text })") Rules[:_UlLine] = rule_info("UlLine", "(< /_{4,}/ > { text } | < @Spacechar /_+/ &@Spacechar > { text })") Rules[:_Emph] = rule_info("Emph", "(EmphStar | EmphUl)") Rules[:_Whitespace] = rule_info("Whitespace", "(@Spacechar | @Newline)") Rules[:_EmphStar] = rule_info("EmphStar", "\"*\" !@Whitespace @StartList:a (!\"*\" Inline:b { a << b } | StrongStar:b { a << b })+ \"*\" { emphasis a.join }") Rules[:_EmphUl] = rule_info("EmphUl", "\"_\" !@Whitespace @StartList:a (!\"_\" Inline:b { a << b } | StrongUl:b { a << b })+ \"_\" { emphasis a.join }") Rules[:_Strong] = rule_info("Strong", "(StrongStar | StrongUl)") Rules[:_StrongStar] = rule_info("StrongStar", "\"**\" !@Whitespace @StartList:a (!\"**\" Inline:b { a << b })+ \"**\" { strong a.join }") Rules[:_StrongUl] = rule_info("StrongUl", "\"__\" !@Whitespace @StartList:a (!\"__\" Inline:b { a << b })+ \"__\" { strong a.join }") Rules[:_Strike] = rule_info("Strike", "&{ strike? } \"~~\" !@Whitespace @StartList:a (!\"~~\" Inline:b { a << b })+ \"~~\" { strike a.join }") Rules[:_Image] = rule_info("Image", "\"!\" (ExplicitLink | ReferenceLink):a { \"rdoc-image:\#{a[/\\[(.*)\\]/, 1]}\" }") Rules[:_Link] = rule_info("Link", "(ExplicitLink | ReferenceLink | AutoLink)") Rules[:_ReferenceLink] = rule_info("ReferenceLink", "(ReferenceLinkDouble | ReferenceLinkSingle)") Rules[:_ReferenceLinkDouble] = rule_info("ReferenceLinkDouble", "Label:content < Spnl > !\"[]\" Label:label { link_to content, label, text }") Rules[:_ReferenceLinkSingle] = rule_info("ReferenceLinkSingle", "Label:content < (Spnl \"[]\")? > { link_to content, content, text }") Rules[:_ExplicitLink] = rule_info("ExplicitLink", "Label:l \"(\" @Sp Source:s Spnl Title @Sp \")\" { \"{\#{l}}[\#{s}]\" }") Rules[:_Source] = rule_info("Source", "(\"<\" < SourceContents > \">\" | < SourceContents >) { text }") Rules[:_SourceContents] = rule_info("SourceContents", "((!\"(\" !\")\" !\">\" Nonspacechar)+ | \"(\" SourceContents \")\")*") Rules[:_Title] = rule_info("Title", "(TitleSingle | TitleDouble | \"\"):a { a }") Rules[:_TitleSingle] = rule_info("TitleSingle", "\"'\" (!(\"'\" @Sp (\")\" | @Newline)) .)* \"'\"") Rules[:_TitleDouble] = rule_info("TitleDouble", "\"\\\"\" (!(\"\\\"\" @Sp (\")\" | @Newline)) .)* \"\\\"\"") Rules[:_AutoLink] = rule_info("AutoLink", "(AutoLinkUrl | AutoLinkEmail)") Rules[:_AutoLinkUrl] = rule_info("AutoLinkUrl", "\"<\" < /[A-Za-z]+/ \"://\" (!@Newline !\">\" .)+ > \">\" { text }") Rules[:_AutoLinkEmail] = rule_info("AutoLinkEmail", "\"<\" \"mailto:\"? < /[\\w+.\\/!%~$-]+/i \"@\" (!@Newline !\">\" .)+ > \">\" { \"mailto:\#{text}\" }") Rules[:_Reference] = rule_info("Reference", "@NonindentSpace !\"[]\" Label:label \":\" Spnl RefSrc:link RefTitle @BlankLine+ { \# TODO use title reference label, link nil }") Rules[:_Label] = rule_info("Label", "\"[\" (!\"^\" &{ notes? } | &. &{ !notes? }) @StartList:a (!\"]\" Inline:l { a << l })* \"]\" { a.join.gsub(/\\s+/, ' ') }") Rules[:_RefSrc] = rule_info("RefSrc", "< Nonspacechar+ > { text }") Rules[:_RefTitle] = rule_info("RefTitle", "(RefTitleSingle | RefTitleDouble | RefTitleParens | EmptyTitle)") Rules[:_EmptyTitle] = rule_info("EmptyTitle", "\"\"") Rules[:_RefTitleSingle] = rule_info("RefTitleSingle", "Spnl \"'\" < (!(\"'\" @Sp @Newline | @Newline) .)* > \"'\" { text }") Rules[:_RefTitleDouble] = rule_info("RefTitleDouble", "Spnl \"\\\"\" < (!(\"\\\"\" @Sp @Newline | @Newline) .)* > \"\\\"\" { text }") Rules[:_RefTitleParens] = rule_info("RefTitleParens", "Spnl \"(\" < (!(\")\" @Sp @Newline | @Newline) .)* > \")\" { text }") Rules[:_References] = rule_info("References", "(Reference | SkipBlock)*") Rules[:_Ticks1] = rule_info("Ticks1", "\"`\" !\"`\"") Rules[:_Ticks2] = rule_info("Ticks2", "\"``\" !\"`\"") Rules[:_Ticks3] = rule_info("Ticks3", "\"```\" !\"`\"") Rules[:_Ticks4] = rule_info("Ticks4", "\"````\" !\"`\"") Rules[:_Ticks5] = rule_info("Ticks5", "\"`````\" !\"`\"") Rules[:_Code] = rule_info("Code", "(Ticks1 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks1 /`+/ | !(@Sp Ticks1) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks1 | Ticks2 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks2 /`+/ | !(@Sp Ticks2) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks2 | Ticks3 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | !(@Sp Ticks3) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks3 | Ticks4 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks4 /`+/ | !(@Sp Ticks4) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks4 | Ticks5 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks5 /`+/ | !(@Sp Ticks5) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks5) { \"\#{text}\" }") Rules[:_RawHtml] = rule_info("RawHtml", "< (HtmlComment | HtmlBlockScript | HtmlTag) > { if html? then text else '' end }") Rules[:_BlankLine] = rule_info("BlankLine", "@Sp @Newline { \"\\n\" }") Rules[:_Quoted] = rule_info("Quoted", "(\"\\\"\" (!\"\\\"\" .)* \"\\\"\" | \"'\" (!\"'\" .)* \"'\")") Rules[:_HtmlAttribute] = rule_info("HtmlAttribute", "(AlphanumericAscii | \"-\")+ Spnl (\"=\" Spnl (Quoted | (!\">\" Nonspacechar)+))? Spnl") Rules[:_HtmlComment] = rule_info("HtmlComment", "\"\" .)* \"-->\"") Rules[:_HtmlTag] = rule_info("HtmlTag", "\"<\" Spnl \"/\"? AlphanumericAscii+ Spnl HtmlAttribute* \"/\"? Spnl \">\"") Rules[:_Eof] = rule_info("Eof", "!.") Rules[:_Nonspacechar] = rule_info("Nonspacechar", "!@Spacechar !@Newline .") Rules[:_Sp] = rule_info("Sp", "@Spacechar*") Rules[:_Spnl] = rule_info("Spnl", "@Sp (@Newline @Sp)?") Rules[:_SpecialChar] = rule_info("SpecialChar", "(/[~*_`&\\[\\]() \";\" { [text.to_i(16)].pack 'U' }") Rules[:_DecEntity] = rule_info("DecEntity", "\"&\#\" < /[0-9]+/ > \";\" { [text.to_i].pack 'U' }") Rules[:_CharEntity] = rule_info("CharEntity", "\"&\" < /[A-Za-z0-9]+/ > \";\" { if entity = HTML_ENTITIES[text] then entity.pack 'U*' else \"&\#{text};\" end }") Rules[:_NonindentSpace] = rule_info("NonindentSpace", "/ {0,3}/") Rules[:_Indent] = rule_info("Indent", "/\\t| /") Rules[:_IndentedLine] = rule_info("IndentedLine", "Indent Line") Rules[:_OptionallyIndentedLine] = rule_info("OptionallyIndentedLine", "Indent? Line") Rules[:_StartList] = rule_info("StartList", "&. { [] }") Rules[:_Line] = rule_info("Line", "@RawLine:a { a }") Rules[:_RawLine] = rule_info("RawLine", "(< (!\"\\r\" !\"\\n\" .)* @Newline > | < .+ > @Eof) { text }") Rules[:_SkipBlock] = rule_info("SkipBlock", "(HtmlBlock | (!\"\#\" !SetextBottom1 !SetextBottom2 !@BlankLine @RawLine)+ @BlankLine* | @BlankLine+ | @RawLine)") Rules[:_ExtendedSpecialChar] = rule_info("ExtendedSpecialChar", "&{ notes? } \"^\"") Rules[:_NoteReference] = rule_info("NoteReference", "&{ notes? } RawNoteReference:ref { note_for ref }") Rules[:_RawNoteReference] = rule_info("RawNoteReference", "\"[^\" < (!@Newline !\"]\" .)+ > \"]\" { text }") Rules[:_Note] = rule_info("Note", "&{ notes? } @NonindentSpace RawNoteReference:ref \":\" @Sp @StartList:a RawNoteBlock:i { a.concat i } (&Indent RawNoteBlock:i { a.concat i })* { @footnotes[ref] = paragraph a nil }") Rules[:_InlineNote] = rule_info("InlineNote", "&{ notes? } \"^[\" @StartList:a (!\"]\" Inline:l { a << l })+ \"]\" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref }") Rules[:_Notes] = rule_info("Notes", "(Note | SkipBlock)*") Rules[:_RawNoteBlock] = rule_info("RawNoteBlock", "@StartList:a (!@BlankLine OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a }") Rules[:_CodeFence] = rule_info("CodeFence", "&{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim }") Rules[:_DefinitionList] = rule_info("DefinitionList", "&{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten }") Rules[:_DefinitionListItem] = rule_info("DefinitionListItem", "DefinitionListLabel+:label DefinitionListDefinition+:defns { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items }") Rules[:_DefinitionListLabel] = rule_info("DefinitionListLabel", "StrChunk:label @Sp @Newline { label }") Rules[:_DefinitionListDefinition] = rule_info("DefinitionListDefinition", "@NonindentSpace \":\" @Space Inlines:a @BlankLine+ { paragraph a }") # :startdoc: end PK ]WnYY gems/rdoc-6.2.1.1/lib/rdoc/ri.rbnu[# frozen_string_literal: true require 'rdoc' ## # Namespace for the ri command line tool's implementation. # # See ri --help for details. module RDoc::RI ## # Base RI error class class Error < RDoc::Error; end autoload :Driver, 'rdoc/ri/driver' autoload :Paths, 'rdoc/ri/paths' autoload :Store, 'rdoc/ri/store' end PK ]+Zq{q{%gems/rdoc-6.2.1.1/lib/rdoc/options.rbnu[# frozen_string_literal: true require 'optparse' require 'pathname' ## # RDoc::Options handles the parsing and storage of options # # == Saved Options # # You can save some options like the markup format in the # .rdoc_options file in your gem. The easiest way to do this is: # # rdoc --markup tomdoc --write-options # # Which will automatically create the file and fill it with the options you # specified. # # The following options will not be saved since they interfere with the user's # preferences or with the normal operation of RDoc: # # * +--coverage-report+ # * +--dry-run+ # * +--encoding+ # * +--force-update+ # * +--format+ # * +--pipe+ # * +--quiet+ # * +--template+ # * +--verbose+ # # == Custom Options # # Generators can hook into RDoc::Options to add generator-specific command # line options. # # When --format is encountered in ARGV, RDoc calls ::setup_options on # the generator class to add extra options to the option parser. Options for # custom generators must occur after --format. rdoc --help # will list options for all installed generators. # # Example: # # class RDoc::Generator::Spellcheck # RDoc::RDoc.add_generator self # # def self.setup_options rdoc_options # op = rdoc_options.option_parser # # op.on('--spell-dictionary DICTIONARY', # RDoc::Options::Path) do |dictionary| # rdoc_options.spell_dictionary = dictionary # end # end # end # # Of course, RDoc::Options does not respond to +spell_dictionary+ by default # so you will need to add it: # # class RDoc::Options # # ## # # The spell dictionary used by the spell-checking plugin. # # attr_accessor :spell_dictionary # # end # # == Option Validators # # OptionParser validators will validate and cast user input values. In # addition to the validators that ship with OptionParser (String, Integer, # Float, TrueClass, FalseClass, Array, Regexp, Date, Time, URI, etc.), # RDoc::Options adds Path, PathArray and Template. class RDoc::Options ## # The deprecated options. DEPRECATED = { '--accessor' => 'support discontinued', '--diagram' => 'support discontinued', '--help-output' => 'support discontinued', '--image-format' => 'was an option for --diagram', '--inline-source' => 'source code is now always inlined', '--merge' => 'ri now always merges class information', '--one-file' => 'support discontinued', '--op-name' => 'support discontinued', '--opname' => 'support discontinued', '--promiscuous' => 'files always only document their content', '--ri-system' => 'Ruby installers use other techniques', } ## # RDoc options ignored (or handled specially) by --write-options SPECIAL = %w[ coverage_report dry_run encoding files force_output force_update generator generator_name generator_options generators op_dir option_parser pipe rdoc_include root static_path stylesheet_url template template_dir update_output_dir verbosity write_options ] ## # Option validator for OptionParser that matches a directory that exists on # the filesystem. Directory = Object.new ## # Option validator for OptionParser that matches a file or directory that # exists on the filesystem. Path = Object.new ## # Option validator for OptionParser that matches a comma-separated list of # files or directories that exist on the filesystem. PathArray = Object.new ## # Option validator for OptionParser that matches a template directory for an # installed generator that lives in # "rdoc/generator/template/#{template_name}" Template = Object.new ## # Character-set for HTML output. #encoding is preferred over #charset attr_accessor :charset ## # If true, RDoc will not write any files. attr_accessor :dry_run ## # The output encoding. All input files will be transcoded to this encoding. # # The default encoding is UTF-8. This is set via --encoding. attr_accessor :encoding ## # Files matching this pattern will be excluded attr_writer :exclude ## # The list of files to be processed attr_accessor :files ## # Create the output even if the output directory does not look # like an rdoc output directory attr_accessor :force_output ## # Scan newer sources than the flag file if true. attr_accessor :force_update ## # Formatter to mark up text with attr_accessor :formatter ## # Description of the output generator (set with the --format option) attr_accessor :generator ## # For #== attr_reader :generator_name # :nodoc: ## # Loaded generator options. Used to prevent --help from loading the same # options multiple times. attr_accessor :generator_options ## # Old rdoc behavior: hyperlink all words that match a method name, # even if not preceded by '#' or '::' attr_accessor :hyperlink_all ## # Include line numbers in the source code attr_accessor :line_numbers ## # The output locale. attr_accessor :locale ## # The directory where locale data live. attr_accessor :locale_dir ## # Name of the file, class or module to display in the initial index page (if # not specified the first file we encounter is used) attr_accessor :main_page ## # The default markup format. The default is 'rdoc'. 'markdown', 'tomdoc' # and 'rd' are also built-in. attr_accessor :markup ## # If true, only report on undocumented files attr_accessor :coverage_report ## # The name of the output directory attr_accessor :op_dir ## # The OptionParser for this instance attr_accessor :option_parser ## # Output heading decorations? attr_accessor :output_decoration ## # Directory where guides, FAQ, and other pages not associated with a class # live. You may leave this unset if these are at the root of your project. attr_accessor :page_dir ## # Is RDoc in pipe mode? attr_accessor :pipe ## # Array of directories to search for files to satisfy an :include: attr_accessor :rdoc_include ## # Root of the source documentation will be generated for. Set this when # building documentation outside the source directory. Defaults to the # current directory. attr_accessor :root ## # Include the '#' at the front of hyperlinked instance method names attr_accessor :show_hash ## # Directory to copy static files from attr_accessor :static_path ## # The number of columns in a tab attr_accessor :tab_width ## # Template to be used when generating output attr_accessor :template ## # Directory the template lives in attr_accessor :template_dir ## # Additional template stylesheets attr_accessor :template_stylesheets ## # Documentation title attr_accessor :title ## # Should RDoc update the timestamps in the output dir? attr_accessor :update_output_dir ## # Verbosity, zero means quiet attr_accessor :verbosity ## # URL of web cvs frontend attr_accessor :webcvs ## # Minimum visibility of a documented method. One of +:public+, +:protected+, # +:private+ or +:nodoc+. # # The +:nodoc+ visibility ignores all directives related to visibility. The # other visibilities may be overridden on a per-method basis with the :doc: # directive. attr_reader :visibility def initialize # :nodoc: init_ivars end def init_ivars # :nodoc: @dry_run = false @exclude = %w[ ~\z \.orig\z \.rej\z \.bak\z \.gemspec\z ] @files = nil @force_output = false @force_update = true @generator = nil @generator_name = nil @generator_options = [] @generators = RDoc::RDoc::GENERATORS @hyperlink_all = false @line_numbers = false @locale = nil @locale_name = nil @locale_dir = 'locale' @main_page = nil @markup = 'rdoc' @coverage_report = false @op_dir = nil @page_dir = nil @pipe = false @output_decoration = true @rdoc_include = [] @root = Pathname(Dir.pwd) @show_hash = false @static_path = [] @stylesheet_url = nil # TODO remove in RDoc 4 @tab_width = 8 @template = nil @template_dir = nil @template_stylesheets = [] @title = nil @update_output_dir = true @verbosity = 1 @visibility = :protected @webcvs = nil @write_options = false @encoding = Encoding::UTF_8 @charset = @encoding.name end def init_with map # :nodoc: init_ivars encoding = map['encoding'] @encoding = encoding ? Encoding.find(encoding) : encoding @charset = map['charset'] @exclude = map['exclude'] @generator_name = map['generator_name'] @hyperlink_all = map['hyperlink_all'] @line_numbers = map['line_numbers'] @locale_name = map['locale_name'] @locale_dir = map['locale_dir'] @main_page = map['main_page'] @markup = map['markup'] @op_dir = map['op_dir'] @show_hash = map['show_hash'] @tab_width = map['tab_width'] @template_dir = map['template_dir'] @title = map['title'] @visibility = map['visibility'] @webcvs = map['webcvs'] @rdoc_include = sanitize_path map['rdoc_include'] @static_path = sanitize_path map['static_path'] end def yaml_initialize tag, map # :nodoc: init_with map end def == other # :nodoc: self.class === other and @encoding == other.encoding and @generator_name == other.generator_name and @hyperlink_all == other.hyperlink_all and @line_numbers == other.line_numbers and @locale == other.locale and @locale_dir == other.locale_dir and @main_page == other.main_page and @markup == other.markup and @op_dir == other.op_dir and @rdoc_include == other.rdoc_include and @show_hash == other.show_hash and @static_path == other.static_path and @tab_width == other.tab_width and @template == other.template and @title == other.title and @visibility == other.visibility and @webcvs == other.webcvs end ## # Check that the files on the command line exist def check_files @files.delete_if do |file| if File.exist? file then if File.readable? file then false else warn "file '#{file}' not readable" true end else warn "file '#{file}' not found" true end end end ## # Ensure only one generator is loaded def check_generator if @generator then raise OptionParser::InvalidOption, "generator already set to #{@generator_name}" end end ## # Set the title, but only if not already set. Used to set the title # from a source file, so that a title set from the command line # will have the priority. def default_title=(string) @title ||= string end ## # For dumping YAML def encode_with coder # :nodoc: encoding = @encoding ? @encoding.name : nil coder.add 'encoding', encoding coder.add 'static_path', sanitize_path(@static_path) coder.add 'rdoc_include', sanitize_path(@rdoc_include) ivars = instance_variables.map { |ivar| ivar.to_s[1..-1] } ivars -= SPECIAL ivars.sort.each do |ivar| coder.add ivar, instance_variable_get("@#{ivar}") end end ## # Create a regexp for #exclude def exclude if @exclude.nil? or Regexp === @exclude then # done, #finish is being re-run @exclude elsif @exclude.empty? then nil else Regexp.new(@exclude.join("|")) end end ## # Completes any unfinished option setup business such as filtering for # existent files, creating a regexp for #exclude and setting a default # #template. def finish @op_dir ||= 'doc' @rdoc_include << "." if @rdoc_include.empty? root = @root.to_s @rdoc_include << root unless @rdoc_include.include?(root) @exclude = self.exclude finish_page_dir check_files # If no template was specified, use the default template for the output # formatter unless @template then @template = @generator_name @template_dir = template_dir_for @template end if @locale_name @locale = RDoc::I18n::Locale[@locale_name] @locale.load(@locale_dir) else @locale = nil end self end ## # Fixes the page_dir to be relative to the root_dir and adds the page_dir to # the files list. def finish_page_dir return unless @page_dir @files << @page_dir.to_s page_dir = nil begin page_dir = @page_dir.expand_path.relative_path_from @root rescue ArgumentError # On Windows, sometimes crosses different drive letters. page_dir = @page_dir.expand_path end @page_dir = page_dir end ## # Returns a properly-space list of generators and their descriptions. def generator_descriptions lengths = [] generators = RDoc::RDoc::GENERATORS.map do |name, generator| lengths << name.length description = generator::DESCRIPTION if generator.const_defined? :DESCRIPTION [name, description] end longest = lengths.max generators.sort.map do |name, description| if description then " %-*s - %s" % [longest, name, description] else " #{name}" end end.join "\n" end ## # Parses command line options. def parse argv ignore_invalid = true argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT'] opts = OptionParser.new do |opt| @option_parser = opt opt.program_name = File.basename $0 opt.version = RDoc::VERSION opt.release = nil opt.summary_indent = ' ' * 4 opt.banner = <<-EOF Usage: #{opt.program_name} [options] [names...] Files are parsed, and the information they contain collected, before any output is produced. This allows cross references between all files to be resolved. If a name is a directory, it is traversed. If no names are specified, all Ruby files in the current directory (and subdirectories) are processed. How RDoc generates output depends on the output formatter being used, and on the options you give. Options can be specified via the RDOCOPT environment variable, which functions similar to the RUBYOPT environment variable for ruby. $ export RDOCOPT="--show-hash" will make rdoc show hashes in method links by default. Command-line options always will override those in RDOCOPT. Available formatters: #{generator_descriptions} RDoc understands the following file formats: EOF parsers = Hash.new { |h,parser| h[parser] = [] } RDoc::Parser.parsers.each do |regexp, parser| parsers[parser.name.sub('RDoc::Parser::', '')] << regexp.source end parsers.sort.each do |parser, regexp| opt.banner += " - #{parser}: #{regexp.join ', '}\n" end opt.banner += " - TomDoc: Only in ruby files\n" opt.banner += "\n The following options are deprecated:\n\n" name_length = DEPRECATED.keys.sort_by { |k| k.length }.last.length DEPRECATED.sort_by { |k,| k }.each do |name, reason| opt.banner += " %*1$2$s %3$s\n" % [-name_length, name, reason] end opt.accept Template do |template| template_dir = template_dir_for template unless template_dir then $stderr.puts "could not find template #{template}" nil else [template, template_dir] end end opt.accept Directory do |directory| directory = File.expand_path directory raise OptionParser::InvalidArgument unless File.directory? directory directory end opt.accept Path do |path| path = File.expand_path path raise OptionParser::InvalidArgument unless File.exist? path path end opt.accept PathArray do |paths,| paths = if paths then paths.split(',').map { |d| d unless d.empty? } end paths.map do |path| path = File.expand_path path raise OptionParser::InvalidArgument unless File.exist? path path end end opt.separator nil opt.separator "Parsing options:" opt.separator nil opt.on("--encoding=ENCODING", "-e", Encoding.list.map { |e| e.name }, "Specifies the output encoding. All files", "read will be converted to this encoding.", "The default encoding is UTF-8.", "--encoding is preferred over --charset") do |value| @encoding = Encoding.find value @charset = @encoding.name # may not be valid value end opt.separator nil opt.on("--locale=NAME", "Specifies the output locale.") do |value| @locale_name = value end opt.on("--locale-data-dir=DIR", "Specifies the directory where locale data live.") do |value| @locale_dir = value end opt.separator nil opt.on("--all", "-a", "Synonym for --visibility=private.") do |value| @visibility = :private end opt.separator nil opt.on("--exclude=PATTERN", "-x", Regexp, "Do not process files or directories", "matching PATTERN.") do |value| @exclude << value end opt.separator nil opt.on("--extension=NEW=OLD", "-E", "Treat files ending with .new as if they", "ended with .old. Using '-E cgi=rb' will", "cause xxx.cgi to be parsed as a Ruby file.") do |value| new, old = value.split(/=/, 2) unless new and old then raise OptionParser::InvalidArgument, "Invalid parameter to '-E'" end unless RDoc::Parser.alias_extension old, new then raise OptionParser::InvalidArgument, "Unknown extension .#{old} to -E" end end opt.separator nil opt.on("--[no-]force-update", "-U", "Forces rdoc to scan all sources even if", "newer than the flag file.") do |value| @force_update = value end opt.separator nil opt.on("--pipe", "-p", "Convert RDoc on stdin to HTML") do @pipe = true end opt.separator nil opt.on("--tab-width=WIDTH", "-w", Integer, "Set the width of tab characters.") do |value| raise OptionParser::InvalidArgument, "#{value} is an invalid tab width" if value <= 0 @tab_width = value end opt.separator nil opt.on("--visibility=VISIBILITY", "-V", RDoc::VISIBILITIES + [:nodoc], "Minimum visibility to document a method.", "One of 'public', 'protected' (the default),", "'private' or 'nodoc' (show everything)") do |value| @visibility = value end opt.separator nil markup_formats = RDoc::Text::MARKUP_FORMAT.keys.sort opt.on("--markup=MARKUP", markup_formats, "The markup format for the named files.", "The default is rdoc. Valid values are:", markup_formats.join(', ')) do |value| @markup = value end opt.separator nil opt.on("--root=ROOT", Directory, "Root of the source tree documentation", "will be generated for. Set this when", "building documentation outside the", "source directory. Default is the", "current directory.") do |root| @root = Pathname(root) end opt.separator nil opt.on("--page-dir=DIR", Directory, "Directory where guides, your FAQ or", "other pages not associated with a class", "live. Set this when you don't store", "such files at your project root.", "NOTE: Do not use the same file name in", "the page dir and the root of your project") do |page_dir| @page_dir = Pathname(page_dir) end opt.separator nil opt.separator "Common generator options:" opt.separator nil opt.on("--force-output", "-O", "Forces rdoc to write the output files,", "even if the output directory exists", "and does not seem to have been created", "by rdoc.") do |value| @force_output = value end opt.separator nil generator_text = @generators.keys.map { |name| " #{name}" }.sort opt.on("-f", "--fmt=FORMAT", "--format=FORMAT", @generators.keys, "Set the output formatter. One of:", *generator_text) do |value| check_generator @generator_name = value.downcase setup_generator end opt.separator nil opt.on("--include=DIRECTORIES", "-i", PathArray, "Set (or add to) the list of directories to", "be searched when satisfying :include:", "requests. Can be used more than once.") do |value| @rdoc_include.concat value.map { |dir| dir.strip } end opt.separator nil opt.on("--[no-]coverage-report=[LEVEL]", "--[no-]dcov", "-C", Integer, "Prints a report on undocumented items.", "Does not generate files.") do |value| value = 0 if value.nil? # Integer converts -C to nil @coverage_report = value @force_update = true if value end opt.separator nil opt.on("--output=DIR", "--op", "-o", "Set the output directory.") do |value| @op_dir = value end opt.separator nil opt.on("-d", "Deprecated --diagram option.", "Prevents firing debug mode", "with legacy invocation.") do |value| end opt.separator nil opt.separator 'HTML generator options:' opt.separator nil opt.on("--charset=CHARSET", "-c", "Specifies the output HTML character-set.", "Use --encoding instead of --charset if", "available.") do |value| @charset = value end opt.separator nil opt.on("--hyperlink-all", "-A", "Generate hyperlinks for all words that", "correspond to known methods, even if they", "do not start with '#' or '::' (legacy", "behavior).") do |value| @hyperlink_all = value end opt.separator nil opt.on("--main=NAME", "-m", "NAME will be the initial page displayed.") do |value| @main_page = value end opt.separator nil opt.on("--[no-]line-numbers", "-N", "Include line numbers in the source code.", "By default, only the number of the first", "line is displayed, in a leading comment.") do |value| @line_numbers = value end opt.separator nil opt.on("--show-hash", "-H", "A name of the form #name in a comment is a", "possible hyperlink to an instance method", "name. When displayed, the '#' is removed", "unless this option is specified.") do |value| @show_hash = value end opt.separator nil opt.on("--template=NAME", "-T", Template, "Set the template used when generating", "output. The default depends on the", "formatter used.") do |(template, template_dir)| @template = template @template_dir = template_dir end opt.separator nil opt.on("--template-stylesheets=FILES", PathArray, "Set (or add to) the list of files to", "include with the html template.") do |value| @template_stylesheets << value end opt.separator nil opt.on("--title=TITLE", "-t", "Set TITLE as the title for HTML output.") do |value| @title = value end opt.separator nil opt.on("--copy-files=PATH", Path, "Specify a file or directory to copy static", "files from.", "If a file is given it will be copied into", "the output dir. If a directory is given the", "entire directory will be copied.", "You can use this multiple times") do |value| @static_path << value end opt.separator nil opt.on("--webcvs=URL", "-W", "Specify a URL for linking to a web frontend", "to CVS. If the URL contains a '\%s', the", "name of the current file will be", "substituted; if the URL doesn't contain a", "'\%s', the filename will be appended to it.") do |value| @webcvs = value end opt.separator nil opt.separator "ri generator options:" opt.separator nil opt.on("--ri", "-r", "Generate output for use by `ri`. The files", "are stored in the '.rdoc' directory under", "your home directory unless overridden by a", "subsequent --op parameter, so no special", "privileges are needed.") do |value| check_generator @generator_name = "ri" @op_dir ||= RDoc::RI::Paths::HOMEDIR setup_generator end opt.separator nil opt.on("--ri-site", "-R", "Generate output for use by `ri`. The files", "are stored in a site-wide directory,", "making them accessible to others, so", "special privileges are needed.") do |value| check_generator @generator_name = "ri" @op_dir = RDoc::RI::Paths.site_dir setup_generator end opt.separator nil opt.separator "Generic options:" opt.separator nil opt.on("--write-options", "Write .rdoc_options to the current", "directory with the given options. Not all", "options will be used. See RDoc::Options", "for details.") do |value| @write_options = true end opt.separator nil opt.on("--[no-]dry-run", "Don't write any files") do |value| @dry_run = value end opt.separator nil opt.on("-D", "--[no-]debug", "Displays lots on internal stuff.") do |value| $DEBUG_RDOC = value end opt.separator nil opt.on("--[no-]ignore-invalid", "Ignore invalid options and continue", "(default true).") do |value| ignore_invalid = value end opt.separator nil opt.on("--quiet", "-q", "Don't show progress as we parse.") do |value| @verbosity = 0 end opt.separator nil opt.on("--verbose", "-V", "Display extra progress as RDoc parses") do |value| @verbosity = 2 end opt.separator nil opt.on("--version", "-v", "print the version") do puts opt.version exit end opt.separator nil opt.on("--help", "-h", "Display this help") do RDoc::RDoc::GENERATORS.each_key do |generator| setup_generator generator end puts opt.help exit end opt.separator nil end setup_generator 'darkfish' if argv.grep(/\A(-f|--fmt|--format|-r|-R|--ri|--ri-site)\b/).empty? deprecated = [] invalid = [] begin opts.parse! argv rescue OptionParser::ParseError => e if DEPRECATED[e.args.first] then deprecated << e.args.first elsif %w[--format --ri -r --ri-site -R].include? e.args.first then raise else invalid << e.args.join(' ') end retry end unless @generator then @generator = RDoc::Generator::Darkfish @generator_name = 'darkfish' end if @pipe and not argv.empty? then @pipe = false invalid << '-p (with files)' end unless quiet then deprecated.each do |opt| $stderr.puts 'option ' + opt + ' is deprecated: ' + DEPRECATED[opt] end end unless invalid.empty? then invalid = "invalid options: #{invalid.join ', '}" if ignore_invalid then unless quiet then $stderr.puts invalid $stderr.puts '(invalid options are ignored)' end else unless quiet then $stderr.puts opts end $stderr.puts invalid exit 1 end end @files = argv.dup finish if @write_options then write_options exit end self end ## # Don't display progress as we process the files def quiet @verbosity.zero? end ## # Set quietness to +bool+ def quiet= bool @verbosity = bool ? 0 : 1 end ## # Removes directories from +path+ that are outside the current directory def sanitize_path path require 'pathname' dot = Pathname.new('.').expand_path path.reject do |item| path = Pathname.new(item).expand_path is_reject = nil relative = nil begin relative = path.relative_path_from(dot).to_s rescue ArgumentError # On Windows, sometimes crosses different drive letters. is_reject = true else is_reject = relative.start_with? '..' end is_reject end end ## # Set up an output generator for the named +generator_name+. # # If the found generator responds to :setup_options it will be called with # the options instance. This allows generators to add custom options or set # default options. def setup_generator generator_name = @generator_name @generator = @generators[generator_name] unless @generator then raise OptionParser::InvalidArgument, "Invalid output formatter #{generator_name}" end return if @generator_options.include? @generator @generator_name = generator_name @generator_options << @generator if @generator.respond_to? :setup_options then @option_parser ||= OptionParser.new @generator.setup_options self end end ## # Finds the template dir for +template+ def template_dir_for template template_path = File.join 'rdoc', 'generator', 'template', template $LOAD_PATH.map do |path| File.join File.expand_path(path), template_path end.find do |dir| File.directory? dir end end # Sets the minimum visibility of a documented method. # # Accepts +:public+, +:protected+, +:private+, +:nodoc+, or +:all+. # # When +:all+ is passed, visibility is set to +:private+, similarly to # RDOCOPT="--all", see #visibility for more information. def visibility= visibility case visibility when :all @visibility = :private else @visibility = visibility end end ## # Displays a warning using Kernel#warn if we're being verbose def warn message super message if @verbosity > 1 end ## # Writes the YAML file .rdoc_options to the current directory containing the # parsed options. def write_options RDoc.load_yaml File.open '.rdoc_options', 'w' do |io| io.set_encoding Encoding::UTF_8 YAML.dump self, io end end end PK ]R5*gems/rdoc-6.2.1.1/lib/rdoc/ghost_method.rbnu[# frozen_string_literal: true ## # GhostMethod represents a method referenced only by a comment class RDoc::GhostMethod < RDoc::AnyMethod end PK ]#@@)gems/rdoc-6.2.1.1/lib/rdoc/stats/quiet.rbnu[# frozen_string_literal: true ## # Stats printer that prints nothing class RDoc::Stats::Quiet ## # Creates a new Quiet that will print nothing def initialize num_files @num_files = num_files end ## # Prints a message at the beginning of parsing def begin_adding(*) end ## # Prints when an alias is added def print_alias(*) end ## # Prints when an attribute is added def print_attribute(*) end ## # Prints when a class is added def print_class(*) end ## # Prints when a constant is added def print_constant(*) end ## # Prints when a file is added def print_file(*) end ## # Prints when a method is added def print_method(*) end ## # Prints when a module is added def print_module(*) end ## # Prints when RDoc is done def done_adding(*) end end PK ] +gems/rdoc-6.2.1.1/lib/rdoc/stats/verbose.rbnu[# frozen_string_literal: true ## # Stats printer that prints everything documented, including the documented # status class RDoc::Stats::Verbose < RDoc::Stats::Normal ## # Returns a marker for RDoc::CodeObject +co+ being undocumented def nodoc co " (undocumented)" unless co.documented? end def print_alias as # :nodoc: puts " alias #{as.new_name} #{as.old_name}#{nodoc as}" end def print_attribute attribute # :nodoc: puts " #{attribute.definition} #{attribute.name}#{nodoc attribute}" end def print_class(klass) # :nodoc: puts " class #{klass.full_name}#{nodoc klass}" end def print_constant(constant) # :nodoc: puts " #{constant.name}#{nodoc constant}" end def print_file(files_so_far, file) # :nodoc: super puts end def print_method(method) # :nodoc: puts " #{method.singleton ? '::' : '#'}#{method.name}#{nodoc method}" end def print_module(mod) # :nodoc: puts " module #{mod.full_name}#{nodoc mod}" end end PK ]9)-$00*gems/rdoc-6.2.1.1/lib/rdoc/stats/normal.rbnu[# frozen_string_literal: true begin require 'io/console/size' rescue LoadError # for JRuby require 'io/console' end ## # Stats printer that prints just the files being documented with a progress # bar class RDoc::Stats::Normal < RDoc::Stats::Quiet def begin_adding # :nodoc: puts "Parsing sources..." @last_width = 0 end ## # Prints a file with a progress bar def print_file files_so_far, filename progress_bar = sprintf("%3d%% [%2d/%2d] ", 100 * files_so_far / @num_files, files_so_far, @num_files) if $stdout.tty? # Print a progress bar, but make sure it fits on a single line. Filename # will be truncated if necessary. size = IO.respond_to?(:console_size) ? IO.console_size : IO.console.winsize terminal_width = size[1].to_i.nonzero? || 80 max_filename_size = (terminal_width - progress_bar.size) - 1 if filename.size > max_filename_size then # Turn "some_long_filename.rb" to "...ong_filename.rb" filename = filename[(filename.size - max_filename_size) .. -1] filename[0..2] = "..." end # Clean the line with whitespaces so that leftover output from the # previous line doesn't show up. $stdout.print("\r\e[K") if @last_width && @last_width > 0 @last_width = progress_bar.size + filename.size term = "\r" else term = "\n" end $stdout.print(progress_bar, filename, term) $stdout.flush end def done_adding # :nodoc: puts end end PK ]+<ߐ<<Ngems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtmlnu[<% unless klass.sections.length == 1 then %> <% end %> PK ]JiMgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtmlnu[<% unless klass.extends.empty? then %> <% end %> PK ] NNNNgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtmlnu[

    Not Found

    <%= message %>

    PK ] yBgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_head.rhtmlnu[ <%= h @title %> <% if @options.template_stylesheets.flatten.any? then %> <% @options.template_stylesheets.flatten.each do |stylesheet| %> <% end %> <% end %> PK ]C..Bgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/class.rhtmlnu[

    <%= klass.type %> <%= klass.full_name %>

    <%= klass.description %>
    <% klass.each_section do |section, constants, attributes| %>
    <% if section.title then %>

    <%= section.title %>

    ↑ top
    <% end %> <% if section.comment then %>
    <%= section.description %>
    <% end %> <% unless constants.empty? then %>

    Constants

    <% constants.each do |const| %>
    <%= const.name %> <% if const.comment then %>
    <%= const.description.strip %> <% else %>
    (Not documented) <% end %> <% end %>
    <% end %> <% unless attributes.empty? then %>

    Attributes

    <% attributes.each do |attrib| %>
    <%= h attrib.name %>[<%= attrib.rw %>]
    <% if attrib.comment then %> <%= attrib.description.strip %> <% else %>

    (Not documented) <% end %>

    <% end %>
    <% end %> <% klass.methods_by_type(section).each do |type, visibilities| next if visibilities.empty? visibilities.each do |visibility, methods| next if methods.empty? %>

    <%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods

    <% methods.each do |method| %>
    "> <% if method.call_seq then %> <% method.call_seq.strip.split("\n").each_with_index do |call_seq, i| %>
    <%= h(call_seq.strip. gsub( /^\w+\./m, '')). gsub(/(.*)[-=]>/, '\1→') %> <% if i == 0 and method.token_stream then %> click to toggle source <% end %>
    <% end %> <% else %>
    <%= h method.name %><%= h method.param_seq %> <% if method.token_stream then %> click to toggle source <% end %>
    <% end %>
    <% if method.comment then %> <%= method.description.strip %> <% else %>

    (Not documented) <% end %> <% if method.calls_super then %>

    Calls superclass method <%= method.superclass_method ? method.formatter.link(method.superclass_method.full_name, method.superclass_method.full_name) : nil %>
    <% end %> <% if method.token_stream then %>
    <%= method.markup_code %>
    <% end %>
    <% unless method.aliases.empty? then %>
    Also aliased as: <%= method.aliases.map do |aka| if aka.parent then # HACK lib/rexml/encodings %{#{h aka.name}} else h aka.name end end.join ", " %>
    <% end %> <% if method.is_alias_for then %> <% end %>
    <% end %>
    <% end end %>
    <% end %>
    PK ]3^^Dgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_footer.rhtmlnu[ PK ]13 3 Egems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/js/darkfish.jsnu[/** * * Darkfish Page Functions * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $ * * Author: Michael Granger * */ /* Provide console simulation for firebug-less environments */ /* if (!("console" in window) || !("firebug" in console)) { var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; window.console = {}; for (var i = 0; i < names.length; ++i) window.console[names[i]] = function() {}; }; */ function showSource( e ) { var target = e.target; while (!target.classList.contains('method-detail')) { target = target.parentNode; } if (typeof target !== "undefined" && target !== null) { target = target.querySelector('.method-source-code'); } if (typeof target !== "undefined" && target !== null) { target.classList.toggle('active-menu') } }; function hookSourceViews() { document.querySelectorAll('.method-heading').forEach(function (codeObject) { codeObject.addEventListener('click', showSource); }); }; function hookSearch() { var input = document.querySelector('#search-field'); var result = document.querySelector('#search-results'); result.classList.remove("initially-hidden"); var search_section = document.querySelector('#search-section'); search_section.classList.remove("initially-hidden"); var search = new Search(search_data, input, result); search.renderItem = function(result) { var li = document.createElement('li'); var html = ''; // TODO add relative path to

    <%=h exception.class %> at <%=h path %>

    <% if exception.respond_to?(:detailed_message) %>

    <%=h exception.detailed_message(highlight: false) %>

    <% else %>

    <%=h exception.message %>

    <% end %>
    Ruby <% if first = frames.first %> <%=h first.filename %>: in <%=h first.function %>, line <%=h frames.first.lineno %> <% else %> unknown location <% end %>
    Web <%=h req.request_method %> <%=h(req.host + path)%>

    Jump to:

    Traceback (innermost first)

      <% frames.each { |frame| %>
    • <%=h frame.filename %>: in <%=h frame.function %> <% if frame.context_line %>
      <% if frame.pre_context %>
        <% frame.pre_context.each { |line| %>
      1. <%=h line %>
      2. <% } %>
      <% end %>
      1. <%=h frame.context_line %>...
      <% if frame.post_context %>
        <% frame.post_context.each { |line| %>
      1. <%=h line %>
      2. <% } %>
      <% end %>
      <% end %>
    • <% } %>

    Request information

    GET

    <% if req.GET and not req.GET.empty? %> <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> <% } %>
    Variable Value
    <%=h key %>
    <%=h val.inspect %>
    <% else %>

    No GET data.

    <% end %>

    POST

    <% if ((req.POST and not req.POST.empty?) rescue (no_post_data = "Invalid POST data"; nil)) %> <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> <% } %>
    Variable Value
    <%=h key %>
    <%=h val.inspect %>
    <% else %>

    <%= no_post_data || "No POST data" %>.

    <% end %> <% unless req.cookies.empty? %> <% req.cookies.each { |key, val| %> <% } %>
    Variable Value
    <%=h key %>
    <%=h val.inspect %>
    <% else %>

    No cookie data.

    <% end %>

    Rack ENV

    <% env.sort_by { |k, v| k.to_s }.each { |key, val| %> <% } %>
    Variable Value
    <%=h key %>
    <%=h val.inspect %>

    You're seeing this error because you use Rack::ShowExceptions.

    HTML # :startdoc: end end PK ][J$gems/rack-3.0.8/lib/rack/deflater.rbnu[# frozen_string_literal: true require "zlib" require "time" # for Time.httpdate require_relative 'constants' require_relative 'utils' require_relative 'request' require_relative 'body_proxy' module Rack # This middleware enables content encoding of http responses, # usually for purposes of compression. # # Currently supported encodings: # # * gzip # * identity (no transformation) # # This middleware automatically detects when encoding is supported # and allowed. For example no encoding is made when a cache # directive of 'no-transform' is present, when the response status # code is one that doesn't allow an entity body, or when the body # is empty. # # Note that despite the name, Deflater does not support the +deflate+ # encoding. class Deflater # Creates Rack::Deflater middleware. Options: # # :if :: a lambda enabling / disabling deflation based on returned boolean value # (e.g use Rack::Deflater, :if => lambda { |*, body| sum=0; body.each { |i| sum += i.length }; sum > 512 }). # However, be aware that calling `body.each` inside the block will break cases where `body.each` is not idempotent, # such as when it is an +IO+ instance. # :include :: a list of content types that should be compressed. By default, all content types are compressed. # :sync :: determines if the stream is going to be flushed after every chunk. Flushing after every chunk reduces # latency for time-sensitive streaming applications, but hurts compression and throughput. # Defaults to +true+. def initialize(app, options = {}) @app = app @condition = options[:if] @compressible_types = options[:include] @sync = options.fetch(:sync, true) end def call(env) status, headers, body = response = @app.call(env) unless should_deflate?(env, status, headers, body) return response end request = Request.new(env) encoding = Utils.select_best_encoding(%w(gzip identity), request.accept_encoding) # Set the Vary HTTP header. vary = headers["vary"].to_s.split(",").map(&:strip) unless vary.include?("*") || vary.any?{|v| v.downcase == 'accept-encoding'} headers["vary"] = vary.push("Accept-Encoding").join(",") end case encoding when "gzip" headers['content-encoding'] = "gzip" headers.delete(CONTENT_LENGTH) mtime = headers["last-modified"] mtime = Time.httpdate(mtime).to_i if mtime response[2] = GzipStream.new(body, mtime, @sync) response when "identity" response else # when nil # Only possible encoding values here are 'gzip', 'identity', and nil message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." bp = Rack::BodyProxy.new([message]) { body.close if body.respond_to?(:close) } [406, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => message.length.to_s }, bp] end end # Body class used for gzip encoded responses. class GzipStream BUFFER_LENGTH = 128 * 1_024 # Initialize the gzip stream. Arguments: # body :: Response body to compress with gzip # mtime :: The modification time of the body, used to set the # modification time in the gzip header. # sync :: Whether to flush each gzip chunk as soon as it is ready. def initialize(body, mtime, sync) @body = body @mtime = mtime @sync = sync end # Yield gzip compressed strings to the given block. def each(&block) @writer = block gzip = ::Zlib::GzipWriter.new(self) gzip.mtime = @mtime if @mtime # @body.each is equivalent to @body.gets (slow) if @body.is_a? ::File # XXX: Should probably be ::IO while part = @body.read(BUFFER_LENGTH) gzip.write(part) gzip.flush if @sync end else @body.each { |part| # Skip empty strings, as they would result in no output, # and flushing empty parts would raise Zlib::BufError. next if part.empty? gzip.write(part) gzip.flush if @sync } end ensure gzip.finish end # Call the block passed to #each with the gzipped data. def write(data) @writer.call(data) end # Close the original body if possible. def close @body.close if @body.respond_to?(:close) end end private # Whether the body should be compressed. def should_deflate?(env, status, headers, body) # Skip compressing empty entity body responses and responses with # no-transform set. if Utils::STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) || /\bno-transform\b/.match?(headers[CACHE_CONTROL].to_s) || headers['content-encoding']&.!~(/\bidentity\b/) return false end # Skip if @compressible_types are given and does not include request's content type return false if @compressible_types && !(headers.has_key?(CONTENT_TYPE) && @compressible_types.include?(headers[CONTENT_TYPE][/[^;]*/])) # Skip if @condition lambda is given and evaluates to false return false if @condition && !@condition.call(env, status, headers, body) # No point in compressing empty body, also handles usage with # Rack::Sendfile. return false if headers[CONTENT_LENGTH] == '0' true end end end PK ]>== gems/rack-3.0.8/lib/rack/lock.rbnu[# frozen_string_literal: true require_relative 'body_proxy' module Rack # Rack::Lock locks every request inside a mutex, so that every request # will effectively be executed synchronously. class Lock def initialize(app, mutex = Mutex.new) @app, @mutex = app, mutex end def call(env) @mutex.lock begin response = @app.call(env) returned = response << BodyProxy.new(response.pop) { unlock } ensure unlock unless returned end end private def unlock @mutex.unlock end end end PK ]/{{(gems/rack-3.0.8/lib/rack/mock_request.rbnu[# frozen_string_literal: true require 'uri' require 'stringio' require_relative 'constants' require_relative 'mock_response' module Rack # Rack::MockRequest helps testing your Rack application without # actually using HTTP. # # After performing a request on a URL with get/post/put/patch/delete, it # returns a MockResponse with useful helper methods for effective # testing. # # You can pass a hash with additional configuration to the # get/post/put/patch/delete. # :input:: A String or IO-like to be used as rack.input. # :fatal:: Raise a FatalWarning if the app writes to rack.errors. # :lint:: If true, wrap the application in a Rack::Lint. class MockRequest class FatalWarning < RuntimeError end class FatalWarner def puts(warning) raise FatalWarning, warning end def write(warning) raise FatalWarning, warning end def flush end def string "" end end DEFAULT_ENV = { RACK_INPUT => StringIO.new, RACK_ERRORS => StringIO.new, }.freeze def initialize(app) @app = app end # Make a GET request and return a MockResponse. See #request. def get(uri, opts = {}) request(GET, uri, opts) end # Make a POST request and return a MockResponse. See #request. def post(uri, opts = {}) request(POST, uri, opts) end # Make a PUT request and return a MockResponse. See #request. def put(uri, opts = {}) request(PUT, uri, opts) end # Make a PATCH request and return a MockResponse. See #request. def patch(uri, opts = {}) request(PATCH, uri, opts) end # Make a DELETE request and return a MockResponse. See #request. def delete(uri, opts = {}) request(DELETE, uri, opts) end # Make a HEAD request and return a MockResponse. See #request. def head(uri, opts = {}) request(HEAD, uri, opts) end # Make an OPTIONS request and return a MockResponse. See #request. def options(uri, opts = {}) request(OPTIONS, uri, opts) end # Make a request using the given request method for the given # uri to the rack application and return a MockResponse. # Options given are passed to MockRequest.env_for. def request(method = GET, uri = "", opts = {}) env = self.class.env_for(uri, opts.merge(method: method)) if opts[:lint] app = Rack::Lint.new(@app) else app = @app end errors = env[RACK_ERRORS] status, headers, body = app.call(env) MockResponse.new(status, headers, body, errors) ensure body.close if body.respond_to?(:close) end # For historical reasons, we're pinning to RFC 2396. # URI::Parser = URI::RFC2396_Parser def self.parse_uri_rfc2396(uri) @parser ||= URI::Parser.new @parser.parse(uri) end # Return the Rack environment used for a request to +uri+. # All options that are strings are added to the returned environment. # Options: # :fatal :: Whether to raise an exception if request outputs to rack.errors # :input :: The rack.input to set # :http_version :: The SERVER_PROTOCOL to set # :method :: The HTTP request method to use # :params :: The params to use # :script_name :: The SCRIPT_NAME to set def self.env_for(uri = "", opts = {}) uri = parse_uri_rfc2396(uri) uri.path = "/#{uri.path}" unless uri.path[0] == ?/ env = DEFAULT_ENV.dup env[REQUEST_METHOD] = (opts[:method] ? opts[:method].to_s.upcase : GET).b env[SERVER_NAME] = (uri.host || "example.org").b env[SERVER_PORT] = (uri.port ? uri.port.to_s : "80").b env[SERVER_PROTOCOL] = opts[:http_version] || 'HTTP/1.1' env[QUERY_STRING] = (uri.query.to_s).b env[PATH_INFO] = (uri.path).b env[RACK_URL_SCHEME] = (uri.scheme || "http").b env[HTTPS] = (env[RACK_URL_SCHEME] == "https" ? "on" : "off").b env[SCRIPT_NAME] = opts[:script_name] || "" if opts[:fatal] env[RACK_ERRORS] = FatalWarner.new else env[RACK_ERRORS] = StringIO.new end if params = opts[:params] if env[REQUEST_METHOD] == GET params = Utils.parse_nested_query(params) if params.is_a?(String) params.update(Utils.parse_nested_query(env[QUERY_STRING])) env[QUERY_STRING] = Utils.build_nested_query(params) elsif !opts.has_key?(:input) opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" if params.is_a?(Hash) if data = Rack::Multipart.build_multipart(params) opts[:input] = data opts["CONTENT_LENGTH"] ||= data.length.to_s opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Rack::Multipart::MULTIPART_BOUNDARY}" else opts[:input] = Utils.build_nested_query(params) end else opts[:input] = params end end end opts[:input] ||= String.new if String === opts[:input] rack_input = StringIO.new(opts[:input]) else rack_input = opts[:input] end rack_input.set_encoding(Encoding::BINARY) env[RACK_INPUT] = rack_input env["CONTENT_LENGTH"] ||= env[RACK_INPUT].size.to_s if env[RACK_INPUT].respond_to?(:size) opts.each { |field, value| env[field] = value if String === field } env end end end PK ]gG&gems/rack-3.0.8/lib/rack/media_type.rbnu[# frozen_string_literal: true module Rack # Rack::MediaType parse media type and parameters out of content_type string class MediaType SPLIT_PATTERN = %r{\s*[;,]\s*} class << self # The media type (type/subtype) portion of the CONTENT_TYPE header # without any media type parameters. e.g., when CONTENT_TYPE is # "text/plain;charset=utf-8", the media-type is "text/plain". # # For more information on the use of media types in HTTP, see: # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 def type(content_type) return nil unless content_type content_type.split(SPLIT_PATTERN, 2).first.tap(&:downcase!) end # The media type parameters provided in CONTENT_TYPE as a Hash, or # an empty Hash if no CONTENT_TYPE or media-type parameters were # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", # this method responds with the following Hash: # { 'charset' => 'utf-8' } def params(content_type) return {} if content_type.nil? content_type.split(SPLIT_PATTERN)[1..-1].each_with_object({}) do |s, hsh| k, v = s.split('=', 2) hsh[k.tap(&:downcase!)] = strip_doublequotes(v) end end private def strip_doublequotes(str) (str.start_with?('"') && str.end_with?('"')) ? str[1..-2] : str end end end end PK ]/gems/rack-3.0.8/lib/rack/auth/digest/request.rbnu[require_relative '../digest' PK ]+gems/rack-3.0.8/lib/rack/auth/digest/md5.rbnu[require_relative '../digest' PK ]-gems/rack-3.0.8/lib/rack/auth/digest/nonce.rbnu[require_relative '../digest' PK ].gems/rack-3.0.8/lib/rack/auth/digest/params.rbnu[require_relative '../digest' PK ],UU1gems/rack-3.0.8/lib/rack/auth/abstract/request.rbnu[# frozen_string_literal: true require_relative '../../request' module Rack module Auth class AbstractRequest def initialize(env) @env = env end def request @request ||= Request.new(@env) end def provided? !authorization_key.nil? && valid? end def valid? !@env[authorization_key].nil? end def parts @parts ||= @env[authorization_key].split(' ', 2) end def scheme @scheme ||= parts.first&.downcase end def params @params ||= parts.last end private AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'] def authorization_key @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) } end end end end PK ]lGRR1gems/rack-3.0.8/lib/rack/auth/abstract/handler.rbnu[# frozen_string_literal: true require_relative '../../constants' module Rack module Auth # Rack::Auth::AbstractHandler implements common authentication functionality. # # +realm+ should be set for all handlers. class AbstractHandler attr_accessor :realm def initialize(app, realm = nil, &authenticator) @app, @realm, @authenticator = app, realm, authenticator end private def unauthorized(www_authenticate = challenge) return [ 401, { CONTENT_TYPE => 'text/plain', CONTENT_LENGTH => '0', 'www-authenticate' => www_authenticate.to_s }, [] ] end def bad_request return [ 400, { CONTENT_TYPE => 'text/plain', CONTENT_LENGTH => '0' }, [] ] end end end end PK ]&gems/rack-3.0.8/lib/rack/auth/basic.rbnu[# frozen_string_literal: true require_relative 'abstract/handler' require_relative 'abstract/request' require 'base64' module Rack module Auth # Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617. # # Initialize with the Rack application that you want protecting, # and a block that checks if a username and password pair are valid. class Basic < AbstractHandler def call(env) auth = Basic::Request.new(env) return unauthorized unless auth.provided? return bad_request unless auth.basic? if valid?(auth) env['REMOTE_USER'] = auth.username return @app.call(env) end unauthorized end private def challenge 'Basic realm="%s"' % realm end def valid?(auth) @authenticator.call(*auth.credentials) end class Request < Auth::AbstractRequest def basic? "basic" == scheme && credentials.length == 2 end def credentials @credentials ||= Base64.decode64(params).split(':', 2) end def username credentials.first end end end end end PK ]  'gems/rack-3.0.8/lib/rack/auth/digest.rbnu[# frozen_string_literal: true require_relative 'abstract/handler' require_relative 'abstract/request' require 'digest/md5' require 'base64' module Rack warn "Rack::Auth::Digest is deprecated and will be removed in Rack 3.1", uplevel: 1 module Auth module Digest # Rack::Auth::Digest::Nonce is the default nonce generator for the # Rack::Auth::Digest::MD5 authentication handler. # # +private_key+ needs to set to a constant string. # # +time_limit+ can be optionally set to an integer (number of seconds), # to limit the validity of the generated nonces. class Nonce class << self attr_accessor :private_key, :time_limit end def self.parse(string) new(*Base64.decode64(string).split(' ', 2)) end def initialize(timestamp = Time.now, given_digest = nil) @timestamp, @given_digest = timestamp.to_i, given_digest end def to_s Base64.encode64("#{@timestamp} #{digest}").strip end def digest ::Digest::MD5.hexdigest("#{@timestamp}:#{self.class.private_key}") end def valid? digest == @given_digest end def stale? !self.class.time_limit.nil? && (Time.now.to_i - @timestamp) > self.class.time_limit end def fresh? !stale? end end class Params < Hash def self.parse(str) Params[*split_header_value(str).map do |param| k, v = param.split('=', 2) [k, dequote(v)] end.flatten] end def self.dequote(str) # From WEBrick::HTTPUtils ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup ret.gsub!(/\\(.)/, "\\1") ret end def self.split_header_value(str) str.scan(/\w+\=(?:"[^\"]+"|[^,]+)/n) end def initialize super() yield self if block_given? end def [](k) super k.to_s end def []=(k, v) super k.to_s, v.to_s end UNQUOTED = ['nc', 'stale'] def to_s map do |k, v| "#{k}=#{(UNQUOTED.include?(k) ? v.to_s : quote(v))}" end.join(', ') end def quote(str) # From WEBrick::HTTPUtils '"' + str.gsub(/[\\\"]/o, "\\\1") + '"' end end class Request < Auth::AbstractRequest def method @env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] || @env[REQUEST_METHOD] end def digest? "digest" == scheme end def correct_uri? request.fullpath == uri end def nonce @nonce ||= Nonce.parse(params['nonce']) end def params @params ||= Params.parse(parts.last) end def respond_to?(sym, *) super or params.has_key? sym.to_s end def method_missing(sym, *args) return super unless params.has_key?(key = sym.to_s) return params[key] if args.size == 0 raise ArgumentError, "wrong number of arguments (#{args.size} for 0)" end end # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of # HTTP Digest Authentication, as per RFC 2617. # # Initialize with the [Rack] application that you want protecting, # and a block that looks up a plaintext password for a given username. # # +opaque+ needs to be set to a constant base64/hexadecimal string. # class MD5 < AbstractHandler attr_accessor :opaque attr_writer :passwords_hashed def initialize(app, realm = nil, opaque = nil, &authenticator) @passwords_hashed = nil if opaque.nil? and realm.respond_to? :values_at realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed end super(app, realm, &authenticator) @opaque = opaque end def passwords_hashed? !!@passwords_hashed end def call(env) auth = Request.new(env) unless auth.provided? return unauthorized end if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth) return bad_request end if valid?(auth) if auth.nonce.stale? return unauthorized(challenge(stale: true)) else env['REMOTE_USER'] = auth.username return @app.call(env) end end unauthorized end private QOP = 'auth' def params(hash = {}) Params.new do |params| params['realm'] = realm params['nonce'] = Nonce.new.to_s params['opaque'] = H(opaque) params['qop'] = QOP hash.each { |k, v| params[k] = v } end end def challenge(hash = {}) "Digest #{params(hash)}" end def valid?(auth) valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) end def valid_qop?(auth) QOP == auth.qop end def valid_opaque?(auth) H(opaque) == auth.opaque end def valid_nonce?(auth) auth.nonce.valid? end def valid_digest?(auth) pw = @authenticator.call(auth.username) pw && Rack::Utils.secure_compare(digest(auth, pw), auth.response) end def md5(data) ::Digest::MD5.hexdigest(data) end alias :H :md5 def KD(secret, data) H "#{secret}:#{data}" end def A1(auth, password) "#{auth.username}:#{auth.realm}:#{password}" end def A2(auth) "#{auth.method}:#{auth.uri}" end def digest(auth, password) password_hash = passwords_hashed? ? password : H(A1(auth, password)) KD password_hash, "#{auth.nonce}:#{auth.nc}:#{auth.cnonce}:#{QOP}:#{H A2(auth)}" end end end end end PK ]>Sf?"?"#gems/rack-3.0.8/lib/rack/builder.rbnu[# frozen_string_literal: true require_relative 'urlmap' module Rack # Rack::Builder provides a domain-specific language (DSL) to construct Rack # applications. It is primarily used to parse +config.ru+ files which # instantiate several middleware and a final application which are hosted # by a Rack-compatible web server. # # Example: # # app = Rack::Builder.new do # use Rack::CommonLogger # map "/ok" do # run lambda { |env| [200, {'content-type' => 'text/plain'}, ['OK']] } # end # end # # run app # # Or # # app = Rack::Builder.app do # use Rack::CommonLogger # run lambda { |env| [200, {'content-type' => 'text/plain'}, ['OK']] } # end # # run app # # +use+ adds middleware to the stack, +run+ dispatches to an application. # You can use +map+ to construct a Rack::URLMap in a convenient way. class Builder # https://stackoverflow.com/questions/2223882/whats-the-difference-between-utf-8-and-utf-8-without-bom UTF_8_BOM = '\xef\xbb\xbf' # Parse the given config file to get a Rack application. # # If the config file ends in +.ru+, it is treated as a # rackup file and the contents will be treated as if # specified inside a Rack::Builder block. # # If the config file does not end in +.ru+, it is # required and Rack will use the basename of the file # to guess which constant will be the Rack application to run. # # Examples: # # Rack::Builder.parse_file('config.ru') # # Rack application built using Rack::Builder.new # # Rack::Builder.parse_file('app.rb') # # requires app.rb, which can be anywhere in Ruby's # # load path. After requiring, assumes App constant # # contains Rack application # # Rack::Builder.parse_file('./my_app.rb') # # requires ./my_app.rb, which should be in the # # process's current directory. After requiring, # # assumes MyApp constant contains Rack application def self.parse_file(path) if path.end_with?('.ru') return self.load_file(path) else require path return Object.const_get(::File.basename(path, '.rb').split('_').map(&:capitalize).join('')) end end # Load the given file as a rackup file, treating the # contents as if specified inside a Rack::Builder block. # # Ignores content in the file after +__END__+, so that # use of +__END__+ will not result in a syntax error. # # Example config.ru file: # # $ cat config.ru # # use Rack::ContentLength # require './app.rb' # run App def self.load_file(path) config = ::File.read(path) config.slice!(/\A#{UTF_8_BOM}/) if config.encoding == Encoding::UTF_8 if config[/^#\\(.*)/] fail "Parsing options from the first comment line is no longer supported: #{path}" end config.sub!(/^__END__\n.*\Z/m, '') return new_from_string(config, path) end # Evaluate the given +builder_script+ string in the context of # a Rack::Builder block, returning a Rack application. def self.new_from_string(builder_script, file = "(rackup)") # We want to build a variant of TOPLEVEL_BINDING with self as a Rack::Builder instance. # We cannot use instance_eval(String) as that would resolve constants differently. binding, builder = TOPLEVEL_BINDING.eval('Rack::Builder.new.instance_eval { [binding, self] }') eval builder_script, binding, file return builder.to_app end # Initialize a new Rack::Builder instance. +default_app+ specifies the # default application if +run+ is not called later. If a block # is given, it is evaluated in the context of the instance. def initialize(default_app = nil, &block) @use = [] @map = nil @run = default_app @warmup = nil @freeze_app = false instance_eval(&block) if block_given? end # Create a new Rack::Builder instance and return the Rack application # generated from it. def self.app(default_app = nil, &block) self.new(default_app, &block).to_app end # Specifies middleware to use in a stack. # # class Middleware # def initialize(app) # @app = app # end # # def call(env) # env["rack.some_header"] = "setting an example" # @app.call(env) # end # end # # use Middleware # run lambda { |env| [200, { "content-type" => "text/plain" }, ["OK"]] } # # All requests through to this application will first be processed by the middleware class. # The +call+ method in this example sets an additional environment key which then can be # referenced in the application if required. def use(middleware, *args, &block) if @map mapping, @map = @map, nil @use << proc { |app| generate_map(app, mapping) } end @use << proc { |app| middleware.new(app, *args, &block) } end # :nocov: ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true) # :nocov: # Takes a block or argument that is an object that responds to #call and # returns a Rack response. # # You can use a block: # # run do |env| # [200, { "content-type" => "text/plain" }, ["Hello World!"]] # end # # You can also provide a lambda: # # run lambda { |env| [200, { "content-type" => "text/plain" }, ["OK"]] } # # You can also provide a class instance: # # class Heartbeat # def call(env) # [200, { "content-type" => "text/plain" }, ["OK"]] # end # end # # run Heartbeat.new # def run(app = nil, &block) raise ArgumentError, "Both app and block given!" if app && block_given? @run = app || block end # Takes a lambda or block that is used to warm-up the application. This block is called # before the Rack application is returned by to_app. # # warmup do |app| # client = Rack::MockRequest.new(app) # client.get('/') # end # # use SomeMiddleware # run MyApp def warmup(prc = nil, &block) @warmup = prc || block end # Creates a route within the application. Routes under the mapped path will be sent to # the Rack application specified by run inside the block. Other requests will be sent to the # default application specified by run outside the block. # # class App # def call(env) # [200, {'content-type' => 'text/plain'}, ["Hello World"]] # end # end # # class Heartbeat # def call(env) # [200, { "content-type" => "text/plain" }, ["OK"]] # end # end # # app = Rack::Builder.app do # map '/heartbeat' do # run Heartbeat.new # end # run App.new # end # # run app # # The +use+ method can also be used inside the block to specify middleware to run under a specific path: # # app = Rack::Builder.app do # map '/heartbeat' do # use Middleware # run Heartbeat.new # end # run App.new # end # # This example includes a piece of middleware which will run before +/heartbeat+ requests hit +Heartbeat+. # # Note that providing a +path+ of +/+ will ignore any default application given in a +run+ statement # outside the block. def map(path, &block) @map ||= {} @map[path] = block end # Freeze the app (set using run) and all middleware instances when building the application # in to_app. def freeze_app @freeze_app = true end # Return the Rack application generated by this instance. def to_app app = @map ? generate_map(@run, @map) : @run fail "missing run or map statement" unless app app.freeze if @freeze_app app = @use.reverse.inject(app) { |a, e| e[a].tap { |x| x.freeze if @freeze_app } } @warmup.call(app) if @warmup app end # Call the Rack application generated by this builder instance. Note that # this rebuilds the Rack application and runs the warmup code (if any) # every time it is called, so it should not be used if performance is important. def call(env) to_app.call(env) end private # Generate a URLMap instance by generating new Rack applications for each # map block in this instance. def generate_map(default_app, mapping) mapped = default_app ? { '/' => default_app } : {} mapping.each { |r, b| mapped[r] = self.class.new(default_app, &b).to_app } URLMap.new(mapped) end end end PK ]O~%gems/rack-3.0.8/lib/rack/recursive.rbnu[# frozen_string_literal: true require 'uri' require_relative 'constants' module Rack # Rack::ForwardRequest gets caught by Rack::Recursive and redirects # the current request to the app at +url+. # # raise ForwardRequest.new("/not-found") # class ForwardRequest < Exception attr_reader :url, :env def initialize(url, env = {}) @url = URI(url) @env = env @env[PATH_INFO] = @url.path @env[QUERY_STRING] = @url.query if @url.query @env[HTTP_HOST] = @url.host if @url.host @env[HTTP_PORT] = @url.port if @url.port @env[RACK_URL_SCHEME] = @url.scheme if @url.scheme super "forwarding to #{url}" end end # Rack::Recursive allows applications called down the chain to # include data from other applications (by using # rack['rack.recursive.include'][...] or raise a # ForwardRequest to redirect internally. class Recursive def initialize(app) @app = app end def call(env) dup._call(env) end def _call(env) @script_name = env[SCRIPT_NAME] @app.call(env.merge(RACK_RECURSIVE_INCLUDE => method(:include))) rescue ForwardRequest => req call(env.merge(req.env)) end def include(env, path) unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ || path[@script_name.size].nil?) raise ArgumentError, "can only include below #{@script_name}, not #{path}" end env = env.merge(PATH_INFO => path, SCRIPT_NAME => @script_name, REQUEST_METHOD => GET, "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", RACK_INPUT => StringIO.new("")) @app.call(env) end end end PK ]ӎ cTcT!gems/rack-3.0.8/lib/rack/utils.rbnu[# -*- encoding: binary -*- # frozen_string_literal: true require 'uri' require 'fileutils' require 'set' require 'tempfile' require 'time' require_relative 'query_parser' require_relative 'mime' require_relative 'headers' require_relative 'constants' module Rack # Rack::Utils contains a grab-bag of useful methods for writing web # applications adopted from all kinds of Ruby libraries. module Utils ParameterTypeError = QueryParser::ParameterTypeError InvalidParameterError = QueryParser::InvalidParameterError ParamsTooDeepError = QueryParser::ParamsTooDeepError DEFAULT_SEP = QueryParser::DEFAULT_SEP COMMON_SEP = QueryParser::COMMON_SEP KeySpaceConstrainedParams = QueryParser::Params class << self attr_accessor :default_query_parser end # The default amount of nesting to allowed by hash parameters. # This helps prevent a rogue client from triggering a possible stack overflow # when parsing parameters. self.default_query_parser = QueryParser.make_default(32) module_function # URI escapes. (CGI style space to +) def escape(s) URI.encode_www_form_component(s) end # Like URI escaping, but with %20 instead of +. Strictly speaking this is # true URI escaping. def escape_path(s) ::URI::DEFAULT_PARSER.escape s end # Unescapes the **path** component of a URI. See Rack::Utils.unescape for # unescaping query parameters or form components. def unescape_path(s) ::URI::DEFAULT_PARSER.unescape s end # Unescapes a URI escaped string with +encoding+. +encoding+ will be the # target encoding of the string returned, and it defaults to UTF-8 def unescape(s, encoding = Encoding::UTF_8) URI.decode_www_form_component(s, encoding) end class << self attr_accessor :multipart_total_part_limit attr_accessor :multipart_file_limit # multipart_part_limit is the original name of multipart_file_limit, but # the limit only counts parts with filenames. alias multipart_part_limit multipart_file_limit alias multipart_part_limit= multipart_file_limit= end # The maximum number of file parts a request can contain. Accepting too # many parts can lead to the server running out of file handles. # Set to `0` for no limit. self.multipart_file_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || ENV['RACK_MULTIPART_FILE_LIMIT'] || 128).to_i # The maximum total number of parts a request can contain. Accepting too # many can lead to excessive memory use and parsing time. self.multipart_total_part_limit = (ENV['RACK_MULTIPART_TOTAL_PART_LIMIT'] || 4096).to_i def self.param_depth_limit default_query_parser.param_depth_limit end def self.param_depth_limit=(v) self.default_query_parser = self.default_query_parser.new_depth_limit(v) end def self.key_space_limit warn("`Rack::Utils.key_space_limit` is deprecated as this value no longer has an effect. It will be removed in Rack 3.1", uplevel: 1) 65536 end def self.key_space_limit=(v) warn("`Rack::Utils.key_space_limit=` is deprecated and no longer has an effect. It will be removed in Rack 3.1", uplevel: 1) end if defined?(Process::CLOCK_MONOTONIC) def clock_time Process.clock_gettime(Process::CLOCK_MONOTONIC) end else # :nocov: def clock_time Time.now.to_f end # :nocov: end def parse_query(qs, d = nil, &unescaper) Rack::Utils.default_query_parser.parse_query(qs, d, &unescaper) end def parse_nested_query(qs, d = nil) Rack::Utils.default_query_parser.parse_nested_query(qs, d) end def build_query(params) params.map { |k, v| if v.class == Array build_query(v.map { |x| [k, x] }) else v.nil? ? escape(k) : "#{escape(k)}=#{escape(v)}" end }.join("&") end def build_nested_query(value, prefix = nil) case value when Array value.map { |v| build_nested_query(v, "#{prefix}[]") }.join("&") when Hash value.map { |k, v| build_nested_query(v, prefix ? "#{prefix}[#{k}]" : k) }.delete_if(&:empty?).join('&') when nil escape(prefix) else raise ArgumentError, "value must be a Hash" if prefix.nil? "#{escape(prefix)}=#{escape(value)}" end end def q_values(q_value_header) q_value_header.to_s.split(/\s*,\s*/).map do |part| value, parameters = part.split(/\s*;\s*/, 2) quality = 1.0 if parameters && (md = /\Aq=([\d.]+)/.match(parameters)) quality = md[1].to_f end [value, quality] end end def forwarded_values(forwarded_header) return nil unless forwarded_header forwarded_header = forwarded_header.to_s.gsub("\n", ";") forwarded_header.split(/\s*;\s*/).each_with_object({}) do |field, values| field.split(/\s*,\s*/).each do |pair| return nil unless pair =~ /\A\s*(by|for|host|proto)\s*=\s*"?([^"]+)"?\s*\Z/i (values[$1.downcase.to_sym] ||= []) << $2 end end end module_function :forwarded_values # Return best accept value to use, based on the algorithm # in RFC 2616 Section 14. If there are multiple best # matches (same specificity and quality), the value returned # is arbitrary. def best_q_match(q_value_header, available_mimes) values = q_values(q_value_header) matches = values.map do |req_mime, quality| match = available_mimes.find { |am| Rack::Mime.match?(am, req_mime) } next unless match [match, quality] end.compact.sort_by do |match, quality| (match.split('/', 2).count('*') * -10) + quality end.last matches&.first end ESCAPE_HTML = { "&" => "&", "<" => "<", ">" => ">", "'" => "'", '"' => """, "/" => "/" } ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys) # Escape ampersands, brackets and quotes to their HTML/XML entities. def escape_html(string) string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] } end def select_best_encoding(available_encodings, accept_encoding) # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html expanded_accept_encoding = [] accept_encoding.each do |m, q| preference = available_encodings.index(m) || available_encodings.size if m == "*" (available_encodings - accept_encoding.map(&:first)).each do |m2| expanded_accept_encoding << [m2, q, preference] end else expanded_accept_encoding << [m, q, preference] end end encoding_candidates = expanded_accept_encoding .sort_by { |_, q, p| [-q, p] } .map!(&:first) unless encoding_candidates.include?("identity") encoding_candidates.push("identity") end expanded_accept_encoding.each do |m, q| encoding_candidates.delete(m) if q == 0.0 end (encoding_candidates & available_encodings)[0] end # :call-seq: # parse_cookies_header(value) -> hash # # Parse cookies from the provided header +value+ according to RFC6265. The # syntax for cookie headers only supports semicolons. Returns a map of # cookie +key+ to cookie +value+. # # parse_cookies_header('myname=myvalue; max-age=0') # # => {"myname"=>"myvalue", "max-age"=>"0"} # def parse_cookies_header(value) return {} unless value value.split(/; */n).each_with_object({}) do |cookie, cookies| next if cookie.empty? key, value = cookie.split('=', 2) cookies[key] = (unescape(value) rescue value) unless cookies.key?(key) end end def add_cookie_to_header(header, key, value) warn("add_cookie_to_header is deprecated and will be removed in Rack 3.1", uplevel: 1) case header when nil, '' return set_cookie_header(key, value) when String [header, set_cookie_header(key, value)] when Array header + [set_cookie_header(key, value)] else raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}" end end # :call-seq: # parse_cookies(env) -> hash # # Parse cookies from the provided request environment using # parse_cookies_header. Returns a map of cookie +key+ to cookie +value+. # # parse_cookies({'HTTP_COOKIE' => 'myname=myvalue'}) # # => {'myname' => 'myvalue'} # def parse_cookies(env) parse_cookies_header env[HTTP_COOKIE] end # :call-seq: # set_cookie_header(key, value) -> encoded string # # Generate an encoded string using the provided +key+ and +value+ suitable # for the +set-cookie+ header according to RFC6265. The +value+ may be an # instance of either +String+ or +Hash+. # # If the cookie +value+ is an instance of +Hash+, it considers the following # cookie attribute keys: +domain+, +max_age+, +expires+ (must be instance # of +Time+), +secure+, +http_only+, +same_site+ and +value+. For more # details about the interpretation of these fields, consult # [RFC6265 Section 5.2](https://datatracker.ietf.org/doc/html/rfc6265#section-5.2). # # An extra cookie attribute +escape_key+ can be provided to control whether # or not the cookie key is URL encoded. If explicitly set to +false+, the # cookie key name will not be url encoded (escaped). The default is +true+. # # set_cookie_header("myname", "myvalue") # # => "myname=myvalue" # # set_cookie_header("myname", {value: "myvalue", max_age: 10}) # # => "myname=myvalue; max-age=10" # def set_cookie_header(key, value) case value when Hash key = escape(key) unless value[:escape_key] == false domain = "; domain=#{value[:domain]}" if value[:domain] path = "; path=#{value[:path]}" if value[:path] max_age = "; max-age=#{value[:max_age]}" if value[:max_age] expires = "; expires=#{value[:expires].httpdate}" if value[:expires] secure = "; secure" if value[:secure] httponly = "; httponly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only]) same_site = case value[:same_site] when false, nil nil when :none, 'None', :None '; SameSite=None' when :lax, 'Lax', :Lax '; SameSite=Lax' when true, :strict, 'Strict', :Strict '; SameSite=Strict' else raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}" end value = value[:value] else key = escape(key) end value = [value] unless Array === value return "#{key}=#{value.map { |v| escape v }.join('&')}#{domain}" \ "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}" end # :call-seq: # set_cookie_header!(headers, key, value) -> header value # # Append a cookie in the specified headers with the given cookie +key+ and # +value+ using set_cookie_header. # # If the headers already contains a +set-cookie+ key, it will be converted # to an +Array+ if not already, and appended to. def set_cookie_header!(headers, key, value) if header = headers[SET_COOKIE] if header.is_a?(Array) header << set_cookie_header(key, value) else headers[SET_COOKIE] = [header, set_cookie_header(key, value)] end else headers[SET_COOKIE] = set_cookie_header(key, value) end end # :call-seq: # delete_set_cookie_header(key, value = {}) -> encoded string # # Generate an encoded string based on the given +key+ and +value+ using # set_cookie_header for the purpose of causing the specified cookie to be # deleted. The +value+ may be an instance of +Hash+ and can include # attributes as outlined by set_cookie_header. The encoded cookie will have # a +max_age+ of 0 seconds, an +expires+ date in the past and an empty # +value+. When used with the +set-cookie+ header, it will cause the client # to *remove* any matching cookie. # # delete_set_cookie_header("myname") # # => "myname=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT" # def delete_set_cookie_header(key, value = {}) set_cookie_header(key, value.merge(max_age: '0', expires: Time.at(0), value: '')) end def make_delete_cookie_header(header, key, value) warn("make_delete_cookie_header is deprecated and will be removed in Rack 3.1, use delete_set_cookie_header! instead", uplevel: 1) delete_set_cookie_header!(header, key, value) end def delete_cookie_header!(headers, key, value = {}) headers[SET_COOKIE] = delete_set_cookie_header!(headers[SET_COOKIE], key, value) return nil end def add_remove_cookie_to_header(header, key, value = {}) warn("add_remove_cookie_to_header is deprecated and will be removed in Rack 3.1, use delete_set_cookie_header! instead", uplevel: 1) delete_set_cookie_header!(header, key, value) end # :call-seq: # delete_set_cookie_header!(header, key, value = {}) -> header value # # Set an expired cookie in the specified headers with the given cookie # +key+ and +value+ using delete_set_cookie_header. This causes # the client to immediately delete the specified cookie. # # delete_set_cookie_header!(nil, "mycookie") # # => "mycookie=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT" # # If the header is non-nil, it will be modified in place. # # header = [] # delete_set_cookie_header!(header, "mycookie") # # => ["mycookie=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"] # header # # => ["mycookie=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"] # def delete_set_cookie_header!(header, key, value = {}) if header header = Array(header) header << delete_set_cookie_header(key, value) else header = delete_set_cookie_header(key, value) end return header end def rfc2822(time) time.rfc2822 end # Parses the "Range:" header, if present, into an array of Range objects. # Returns nil if the header is missing or syntactically invalid. # Returns an empty array if none of the ranges are satisfiable. def byte_ranges(env, size) get_byte_ranges env['HTTP_RANGE'], size end def get_byte_ranges(http_range, size) # See return nil unless http_range && http_range =~ /bytes=([^;]+)/ ranges = [] $1.split(/,\s*/).each do |range_spec| return nil unless range_spec.include?('-') range = range_spec.split('-') r0, r1 = range[0], range[1] if r0.nil? || r0.empty? return nil if r1.nil? # suffix-byte-range-spec, represents trailing suffix of file r0 = size - r1.to_i r0 = 0 if r0 < 0 r1 = size - 1 else r0 = r0.to_i if r1.nil? r1 = size - 1 else r1 = r1.to_i return nil if r1 < r0 # backwards range is syntactically invalid r1 = size - 1 if r1 >= size end end ranges << (r0..r1) if r0 <= r1 end ranges end # :nocov: if defined?(OpenSSL.fixed_length_secure_compare) # Constant time string comparison. # # NOTE: the values compared should be of fixed length, such as strings # that have already been processed by HMAC. This should not be used # on variable length plaintext strings because it could leak length info # via timing attacks. def secure_compare(a, b) return false unless a.bytesize == b.bytesize OpenSSL.fixed_length_secure_compare(a, b) end # :nocov: else def secure_compare(a, b) return false unless a.bytesize == b.bytesize l = a.unpack("C*") r, i = 0, -1 b.each_byte { |v| r |= v ^ l[i += 1] } r == 0 end end # Context allows the use of a compatible middleware at different points # in a request handling stack. A compatible middleware must define # #context which should take the arguments env and app. The first of which # would be the request environment. The second of which would be the rack # application that the request would be forwarded to. class Context attr_reader :for, :app def initialize(app_f, app_r) raise 'running context does not respond to #context' unless app_f.respond_to? :context @for, @app = app_f, app_r end def call(env) @for.context(env, @app) end def recontext(app) self.class.new(@for, app) end def context(env, app = @app) recontext(app).call(env) end end # A wrapper around Headers # header when set. # # @api private class HeaderHash < Hash # :nodoc: def self.[](headers) warn "Rack::Utils::HeaderHash is deprecated and will be removed in Rack 3.1, switch to Rack::Headers", uplevel: 1 if headers.is_a?(Headers) && !headers.frozen? return headers end new_headers = Headers.new headers.each{|k,v| new_headers[k] = v} new_headers end def self.new(hash = {}) warn "Rack::Utils::HeaderHash is deprecated and will be removed in Rack 3.1, switch to Rack::Headers", uplevel: 1 headers = Headers.new hash.each{|k,v| headers[k] = v} headers end def self.allocate raise TypeError, "cannot allocate HeaderHash" end end # Every standard HTTP code mapped to the appropriate message. # Generated with: # curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \ # ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \ # puts "#{m[1]} => \x27#{m[2].strip}\x27,"' HTTP_STATUS_CODES = { 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 103 => 'Early Hints', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 208 => 'Already Reported', 226 => 'IM Used', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => '(Unused)', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Payload Too Large', 414 => 'URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Range Not Satisfiable', 417 => 'Expectation Failed', 421 => 'Misdirected Request', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Too Early', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable for Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 509 => 'Bandwidth Limit Exceeded', 510 => 'Not Extended', 511 => 'Network Authentication Required' } # Responses with HTTP status codes that should not have an entity body STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])] SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message| [message.downcase.gsub(/\s|-|'/, '_').to_sym, code] }.flatten] def status_code(status) if status.is_a?(Symbol) SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" } else status.to_i end end PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact) def clean_path_info(path_info) parts = path_info.split PATH_SEPS clean = [] parts.each do |part| next if part.empty? || part == '.' part == '..' ? clean.pop : clean << part end clean_path = clean.join(::File::SEPARATOR) clean_path.prepend("/") if parts.empty? || parts.first.empty? clean_path end NULL_BYTE = "\0" def valid_path?(path) path.valid_encoding? && !path.include?(NULL_BYTE) end end end PK ]&44,gems/rack-3.0.8/lib/rack/multipart/parser.rbnu[# frozen_string_literal: true require 'strscan' require_relative '../utils' module Rack module Multipart class MultipartPartLimitError < Errno::EMFILE; end class MultipartTotalPartLimitError < StandardError; end # Use specific error class when parsing multipart request # that ends early. class EmptyContentError < ::EOFError; end # Base class for multipart exceptions that do not subclass from # other exception classes for backwards compatibility. class Error < StandardError; end EOL = "\r\n" MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/ CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/ BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:[^:]*;\s*name=(#{VALUE})/ni MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni # Updated definitions from RFC 2231 ATTRIBUTE_CHAR = %r{[^ \x00-\x1f\x7f)(><@,;:\\"/\[\]?='*%]} ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/ SECTION = /\*[0-9]+/ REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/ REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/ EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/ EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/ EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/ EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/ EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/ EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/ EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/ DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/ RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i class Parser BUFSIZE = 1_048_576 TEXT_PLAIN = "text/plain" TEMPFILE_FACTORY = lambda { |filename, content_type| Tempfile.new(["RackMultipart", ::File.extname(filename.gsub("\0", '%00'))]) } class BoundedIO # :nodoc: def initialize(io, content_length) @io = io @content_length = content_length @cursor = 0 end def read(size, outbuf = nil) return if @cursor >= @content_length left = @content_length - @cursor str = if left < size @io.read left, outbuf else @io.read size, outbuf end if str @cursor += str.bytesize else # Raise an error for mismatching content-length and actual contents raise EOFError, "bad content body" end str end end MultipartInfo = Struct.new :params, :tmp_files EMPTY = MultipartInfo.new(nil, []) def self.parse_boundary(content_type) return unless content_type data = content_type.match(MULTIPART) return unless data data[1] end def self.parse(io, content_length, content_type, tmpfile, bufsize, qp) return EMPTY if 0 == content_length boundary = parse_boundary content_type return EMPTY unless boundary if boundary.length > 70 # RFC 1521 Section 7.2.1 imposes a 70 character maximum for the boundary. # Most clients use no more than 55 characters. raise Error, "multipart boundary size too large (#{boundary.length} characters)" end io = BoundedIO.new(io, content_length) if content_length parser = new(boundary, tmpfile, bufsize, qp) parser.parse(io) parser.result end class Collector class MimePart < Struct.new(:body, :head, :filename, :content_type, :name) def get_data data = body if filename == "" # filename is blank which means no file has been selected return elsif filename body.rewind if body.respond_to?(:rewind) # Take the basename of the upload's original filename. # This handles the full Windows paths given by Internet Explorer # (and perhaps other broken user agents) without affecting # those which give the lone filename. fn = filename.split(/[\/\\]/).last data = { filename: fn, type: content_type, name: name, tempfile: body, head: head } end yield data end end class BufferPart < MimePart def file?; false; end def close; end end class TempfilePart < MimePart def file?; true; end def close; body.close; end end include Enumerable def initialize(tempfile) @tempfile = tempfile @mime_parts = [] @open_files = 0 end def each @mime_parts.each { |part| yield part } end def on_mime_head(mime_index, head, filename, content_type, name) if filename body = @tempfile.call(filename, content_type) body.binmode if body.respond_to?(:binmode) klass = TempfilePart @open_files += 1 else body = String.new klass = BufferPart end @mime_parts[mime_index] = klass.new(body, head, filename, content_type, name) check_part_limits end def on_mime_body(mime_index, content) @mime_parts[mime_index].body << content end def on_mime_finish(mime_index) end private def check_part_limits file_limit = Utils.multipart_file_limit part_limit = Utils.multipart_total_part_limit if file_limit && file_limit > 0 if @open_files >= file_limit @mime_parts.each(&:close) raise MultipartPartLimitError, 'Maximum file multiparts in content reached' end end if part_limit && part_limit > 0 if @mime_parts.size >= part_limit @mime_parts.each(&:close) raise MultipartTotalPartLimitError, 'Maximum total multiparts in content reached' end end end end attr_reader :state def initialize(boundary, tempfile, bufsize, query_parser) @query_parser = query_parser @params = query_parser.make_params @bufsize = bufsize @state = :FAST_FORWARD @mime_index = 0 @collector = Collector.new tempfile @sbuf = StringScanner.new("".dup) @body_regex = /(?:#{EOL}|\A)--#{Regexp.quote(boundary)}(?:#{EOL}|--)/m @rx_max_size = boundary.bytesize + 6 # (\r\n-- at start, either \r\n or -- at finish) @head_regex = /(.*?#{EOL})#{EOL}/m end def parse(io) outbuf = String.new read_data(io, outbuf) loop do status = case @state when :FAST_FORWARD handle_fast_forward when :CONSUME_TOKEN handle_consume_token when :MIME_HEAD handle_mime_head when :MIME_BODY handle_mime_body else # when :DONE return end read_data(io, outbuf) if status == :want_read end end def result @collector.each do |part| part.get_data do |data| tag_multipart_encoding(part.filename, part.content_type, part.name, data) @query_parser.normalize_params(@params, part.name, data) end end MultipartInfo.new @params.to_params_hash, @collector.find_all(&:file?).map(&:body) end private def dequote(str) # From WEBrick::HTTPUtils ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup ret.gsub!(/\\(.)/, "\\1") ret end def read_data(io, outbuf) content = io.read(@bufsize, outbuf) handle_empty_content!(content) @sbuf.concat(content) end # This handles the initial parser state. We read until we find the starting # boundary, then we can transition to the next state. If we find the ending # boundary, this is an invalid multipart upload, but keep scanning for opening # boundary in that case. If no boundary found, we need to keep reading data # and retry. It's highly unlikely the initial read will not consume the # boundary. The client would have to deliberately craft a response # with the opening boundary beyond the buffer size for that to happen. def handle_fast_forward while true case consume_boundary when :BOUNDARY # found opening boundary, transition to next state @state = :MIME_HEAD return when :END_BOUNDARY # invalid multipart upload, but retry for opening boundary else # no boundary found, keep reading data return :want_read end end end def handle_consume_token tok = consume_boundary # break if we're at the end of a buffer, but not if it is the end of a field @state = if tok == :END_BOUNDARY || (@sbuf.eos? && tok != :BOUNDARY) :DONE else :MIME_HEAD end end def handle_mime_head if @sbuf.scan_until(@head_regex) head = @sbuf[1] content_type = head[MULTIPART_CONTENT_TYPE, 1] if name = head[MULTIPART_CONTENT_DISPOSITION, 1] name = dequote(name) else name = head[MULTIPART_CONTENT_ID, 1] end filename = get_filename(head) if name.nil? || name.empty? name = filename || "#{content_type || TEXT_PLAIN}[]".dup end @collector.on_mime_head @mime_index, head, filename, content_type, name @state = :MIME_BODY else :want_read end end def handle_mime_body if (body_with_boundary = @sbuf.check_until(@body_regex)) # check but do not advance the pointer yet body = body_with_boundary.sub(/#{@body_regex}\z/m, '') # remove the boundary from the string @collector.on_mime_body @mime_index, body @sbuf.pos += body.length + 2 # skip \r\n after the content @state = :CONSUME_TOKEN @mime_index += 1 else # Save what we have so far if @rx_max_size < @sbuf.rest_size delta = @sbuf.rest_size - @rx_max_size @collector.on_mime_body @mime_index, @sbuf.peek(delta) @sbuf.pos += delta @sbuf.string = @sbuf.rest end :want_read end end # Scan until the we find the start or end of the boundary. # If we find it, return the appropriate symbol for the start or # end of the boundary. If we don't find the start or end of the # boundary, clear the buffer and return nil. def consume_boundary if read_buffer = @sbuf.scan_until(@body_regex) read_buffer.end_with?(EOL) ? :BOUNDARY : :END_BOUNDARY else @sbuf.terminate nil end end def get_filename(head) filename = nil case head when RFC2183 params = Hash[*head.scan(DISPPARM).flat_map(&:compact)] if filename = params['filename*'] encoding, _, filename = filename.split("'", 3) elsif filename = params['filename'] filename = $1 if filename =~ /^"(.*)"$/ end when BROKEN filename = $1 filename = $1 if filename =~ /^"(.*)"$/ end return unless filename if filename.scan(/%.?.?/).all? { |s| /%[0-9a-fA-F]{2}/.match?(s) } filename = Utils.unescape_path(filename) end filename.scrub! if filename !~ /\\[^\\"]/ filename = filename.gsub(/\\(.)/, '\1') end if encoding filename.force_encoding ::Encoding.find(encoding) end filename end CHARSET = "charset" deprecate_constant :CHARSET def tag_multipart_encoding(filename, content_type, name, body) name = name.to_s encoding = Encoding::UTF_8 name.force_encoding(encoding) return if filename if content_type list = content_type.split(';') type_subtype = list.first type_subtype.strip! if TEXT_PLAIN == type_subtype rest = list.drop 1 rest.each do |param| k, v = param.split('=', 2) k.strip! v.strip! v = v[1..-2] if v.start_with?('"') && v.end_with?('"') if k == "charset" encoding = begin Encoding.find v rescue ArgumentError Encoding::BINARY end end end end end name.force_encoding(encoding) body.force_encoding(encoding) end def handle_empty_content!(content) if content.nil? || content.empty? raise EmptyContentError end end end end end PK ]l /gems/rack-3.0.8/lib/rack/multipart/generator.rbnu[# frozen_string_literal: true require_relative 'uploaded_file' module Rack module Multipart class Generator def initialize(params, first = true) @params, @first = params, first if @first && !@params.is_a?(Hash) raise ArgumentError, "value must be a Hash" end end def dump return nil if @first && !multipart? return flattened_params unless @first flattened_params.map do |name, file| if file.respond_to?(:original_filename) if file.path ::File.open(file.path, 'rb') do |f| f.set_encoding(Encoding::BINARY) content_for_tempfile(f, file, name) end else content_for_tempfile(file, file, name) end else content_for_other(file, name) end end.join << "--#{MULTIPART_BOUNDARY}--\r" end private def multipart? query = lambda { |value| case value when Array value.any?(&query) when Hash value.values.any?(&query) when Rack::Multipart::UploadedFile true end } @params.values.any?(&query) end def flattened_params @flattened_params ||= begin h = Hash.new @params.each do |key, value| k = @first ? key.to_s : "[#{key}]" case value when Array value.map { |v| Multipart.build_multipart(v, false).each { |subkey, subvalue| h["#{k}[]#{subkey}"] = subvalue } } when Hash Multipart.build_multipart(value, false).each { |subkey, subvalue| h[k + subkey] = subvalue } else h[k] = value end end h end end def content_for_tempfile(io, file, name) length = ::File.stat(file.path).size if file.path filename = "; filename=\"#{Utils.escape_path(file.original_filename)}\"" <<-EOF --#{MULTIPART_BOUNDARY}\r content-disposition: form-data; name="#{name}"#{filename}\r content-type: #{file.content_type}\r #{"content-length: #{length}\r\n" if length}\r #{io.read}\r EOF end def content_for_other(file, name) <<-EOF --#{MULTIPART_BOUNDARY}\r content-disposition: form-data; name="#{name}"\r \r #{file}\r EOF end end end end PK ]N$$3gems/rack-3.0.8/lib/rack/multipart/uploaded_file.rbnu[# frozen_string_literal: true require 'tempfile' require 'fileutils' module Rack module Multipart class UploadedFile # The filename, *not* including the path, of the "uploaded" file attr_reader :original_filename # The content type of the "uploaded" file attr_accessor :content_type def initialize(filepath = nil, ct = "text/plain", bin = false, path: filepath, content_type: ct, binary: bin, filename: nil, io: nil) if io @tempfile = io @original_filename = filename else raise "#{path} file does not exist" unless ::File.exist?(path) @original_filename = filename || ::File.basename(path) @tempfile = Tempfile.new([@original_filename, ::File.extname(path)], encoding: Encoding::BINARY) @tempfile.binmode if binary FileUtils.copy_file(path, @tempfile.path) end @content_type = content_type end def path @tempfile.path if @tempfile.respond_to?(:path) end alias_method :local_path, :path def respond_to?(*args) super or @tempfile.respond_to?(*args) end def method_missing(method_name, *args, &block) #:nodoc: @tempfile.__send__(method_name, *args, &block) end end end end PK ] Cx x )gems/rack-3.0.8/lib/rack/common_logger.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' require_relative 'body_proxy' require_relative 'request' module Rack # Rack::CommonLogger forwards every request to the given +app+, and # logs a line in the # {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common] # to the configured logger. class CommonLogger # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common # # lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 - # # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % # # The actual format is slightly different than the above due to the # separation of SCRIPT_NAME and PATH_INFO, and because the elapsed # time in seconds is included at the end. FORMAT = %{%s - %s [%s] "%s %s%s%s %s" %d %s %0.4f\n} # +logger+ can be any object that supports the +write+ or +<<+ methods, # which includes the standard library Logger. These methods are called # with a single string argument, the log message. # If +logger+ is nil, CommonLogger will fall back env['rack.errors']. def initialize(app, logger = nil) @app = app @logger = logger end # Log all requests in common_log format after a response has been # returned. Note that if the app raises an exception, the request # will not be logged, so if exception handling middleware are used, # they should be loaded after this middleware. Additionally, because # the logging happens after the request body has been fully sent, any # exceptions raised during the sending of the response body will # cause the request not to be logged. def call(env) began_at = Utils.clock_time status, headers, body = response = @app.call(env) response[2] = BodyProxy.new(body) { log(env, status, headers, began_at) } response end private # Log the request to the configured logger. def log(env, status, response_headers, began_at) request = Rack::Request.new(env) length = extract_content_length(response_headers) msg = sprintf(FORMAT, request.ip || "-", request.get_header("REMOTE_USER") || "-", Time.now.strftime("%d/%b/%Y:%H:%M:%S %z"), request.request_method, request.script_name, request.path_info, request.query_string.empty? ? "" : "?#{request.query_string}", request.get_header(SERVER_PROTOCOL), status.to_s[0..3], length, Utils.clock_time - began_at) msg.gsub!(/[^[:print:]\n]/) { |c| sprintf("\\x%x", c.ord) } logger = @logger || request.get_header(RACK_ERRORS) # Standard library logger doesn't support write but it supports << which actually # calls to write on the log device without formatting if logger.respond_to?(:write) logger.write(msg) else logger << msg end end # Attempt to determine the content length for the response to # include it in the logged data. def extract_content_length(headers) value = headers[CONTENT_LENGTH] !value || value.to_s == '0' ? '-' : value end end end PK ]YYd  +gems/rack-3.0.8/lib/rack/tempfile_reaper.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'body_proxy' module Rack # Middleware tracks and cleans Tempfiles created throughout a request (i.e. Rack::Multipart) # Ideas/strategy based on posts by Eric Wong and Charles Oliver Nutter # https://groups.google.com/forum/#!searchin/rack-devel/temp/rack-devel/brK8eh-MByw/sw61oJJCGRMJ class TempfileReaper def initialize(app) @app = app end def call(env) env[RACK_TEMPFILES] ||= [] begin _, _, body = response = @app.call(env) rescue Exception env[RACK_TEMPFILES]&.each(&:close!) raise end response[2] = BodyProxy.new(body) do env[RACK_TEMPFILES]&.each(&:close!) end response end end end PK ]Kbx  $gems/rack-3.0.8/lib/rack/reloader.rbnu[# frozen_string_literal: true # Copyright (C) 2009-2018 Michael Fellinger # Rack::Reloader is subject to the terms of an MIT-style license. # See MIT-LICENSE or https://opensource.org/licenses/MIT. require 'pathname' module Rack # High performant source reloader # # This class acts as Rack middleware. # # What makes it especially suited for use in a production environment is that # any file will only be checked once and there will only be made one system # call stat(2). # # Please note that this will not reload files in the background, it does so # only when actively called. # # It is performing a check/reload cycle at the start of every request, but # also respects a cool down time, during which nothing will be done. class Reloader def initialize(app, cooldown = 10, backend = Stat) @app = app @cooldown = cooldown @last = (Time.now - cooldown) @cache = {} @mtimes = {} @reload_mutex = Mutex.new extend backend end def call(env) if @cooldown and Time.now > @last + @cooldown if Thread.list.size > 1 @reload_mutex.synchronize{ reload! } else reload! end @last = Time.now end @app.call(env) end def reload!(stderr = $stderr) rotation do |file, mtime| previous_mtime = @mtimes[file] ||= mtime safe_load(file, mtime, stderr) if mtime > previous_mtime end end # A safe Kernel::load, issuing the hooks depending on the results def safe_load(file, mtime, stderr = $stderr) load(file) stderr.puts "#{self.class}: reloaded `#{file}'" file rescue LoadError, SyntaxError => ex stderr.puts ex ensure @mtimes[file] = mtime end module Stat def rotation files = [$0, *$LOADED_FEATURES].uniq paths = ['./', *$LOAD_PATH].uniq files.map{|file| next if /\.(so|bundle)$/.match?(file) # cannot reload compiled files found, stat = figure_path(file, paths) next unless found && stat && mtime = stat.mtime @cache[file] = found yield(found, mtime) }.compact end # Takes a relative or absolute +file+ name, a couple possible +paths+ that # the +file+ might reside in. Returns the full path and File::Stat for the # path. def figure_path(file, paths) found = @cache[file] found = file if !found and Pathname.new(file).absolute? found, stat = safe_stat(found) return found, stat if found paths.find do |possible_path| path = ::File.join(possible_path, file) found, stat = safe_stat(path) return ::File.expand_path(found), stat if found end return false, false end def safe_stat(file) return unless file stat = ::File.stat(file) return file, stat if stat.file? rescue Errno::ENOENT, Errno::ENOTDIR, Errno::ESRCH @cache.delete(file) and false end end end end PK ]&{!{!(gems/rack-3.0.8/lib/rack/query_parser.rbnu[# frozen_string_literal: true require 'uri' module Rack class QueryParser DEFAULT_SEP = /[&] */n COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n } # ParameterTypeError is the error that is raised when incoming structural # parameters (parsed by parse_nested_query) contain conflicting types. class ParameterTypeError < TypeError; end # InvalidParameterError is the error that is raised when incoming structural # parameters (parsed by parse_nested_query) contain invalid format or byte # sequence. class InvalidParameterError < ArgumentError; end # ParamsTooDeepError is the error that is raised when params are recursively # nested over the specified limit. class ParamsTooDeepError < RangeError; end def self.make_default(_key_space_limit=(not_deprecated = true; nil), param_depth_limit) unless not_deprecated warn("`first argument `key_space limit` is deprecated and no longer has an effect. Please call with only one argument, which will be required in a future version of Rack", uplevel: 1) end new Params, param_depth_limit end attr_reader :param_depth_limit def initialize(params_class, _key_space_limit=(not_deprecated = true; nil), param_depth_limit) unless not_deprecated warn("`second argument `key_space limit` is deprecated and no longer has an effect. Please call with only two arguments, which will be required in a future version of Rack", uplevel: 1) end @params_class = params_class @param_depth_limit = param_depth_limit end # Stolen from Mongrel, with some small modifications: # Parses a query string by breaking it up at the '&'. You can also use this # to parse cookies by changing the characters used in the second parameter # (which defaults to '&'). def parse_query(qs, separator = nil, &unescaper) unescaper ||= method(:unescape) params = make_params (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p| next if p.empty? k, v = p.split('=', 2).map!(&unescaper) if cur = params[k] if cur.class == Array params[k] << v else params[k] = [cur, v] end else params[k] = v end end return params.to_h end # parse_nested_query expands a query string into structural types. Supported # types are Arrays, Hashes and basic value types. It is possible to supply # query strings with parameters of conflicting types, in this case a # ParameterTypeError is raised. Users are encouraged to return a 400 in this # case. def parse_nested_query(qs, separator = nil) params = make_params unless qs.nil? || qs.empty? (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p| k, v = p.split('=', 2).map! { |s| unescape(s) } _normalize_params(params, k, v, 0) end end return params.to_h rescue ArgumentError => e raise InvalidParameterError, e.message, e.backtrace end # normalize_params recursively expands parameters into structural types. If # the structural types represented by two different parameter names are in # conflict, a ParameterTypeError is raised. The depth argument is deprecated # and should no longer be used, it is kept for backwards compatibility with # earlier versions of rack. def normalize_params(params, name, v, _depth=nil) _normalize_params(params, name, v, 0) end private def _normalize_params(params, name, v, depth) raise ParamsTooDeepError if depth >= param_depth_limit if !name # nil name, treat same as empty string (required by tests) k = after = '' elsif depth == 0 # Start of parsing, don't treat [] or [ at start of string specially if start = name.index('[', 1) # Start of parameter nesting, use part before brackets as key k = name[0, start] after = name[start, name.length] else # Plain parameter with no nesting k = name after = '' end elsif name.start_with?('[]') # Array nesting k = '[]' after = name[2, name.length] elsif name.start_with?('[') && (start = name.index(']', 1)) # Hash nesting, use the part inside brackets as the key k = name[1, start-1] after = name[start+1, name.length] else # Probably malformed input, nested but not starting with [ # treat full name as key for backwards compatibility. k = name after = '' end return if k.empty? if after == '' if k == '[]' && depth != 0 return [v] else params[k] = v end elsif after == "[" params[name] = v elsif after == "[]" params[k] ||= [] raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) params[k] << v elsif after.start_with?('[]') # Recognize x[][y] (hash inside array) parameters unless after[2] == '[' && after.end_with?(']') && (child_key = after[3, after.length-4]) && !child_key.empty? && !child_key.index('[') && !child_key.index(']') # Handle other nested array parameters child_key = after[2, after.length] end params[k] ||= [] raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key) _normalize_params(params[k].last, child_key, v, depth + 1) else params[k] << _normalize_params(make_params, child_key, v, depth + 1) end else params[k] ||= make_params raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k]) params[k] = _normalize_params(params[k], after, v, depth + 1) end params end def make_params @params_class.new end def new_depth_limit(param_depth_limit) self.class.new @params_class, param_depth_limit end private def params_hash_type?(obj) obj.kind_of?(@params_class) end def params_hash_has_key?(hash, key) return false if /\[\]/.match?(key) key.split(/[\[\]]+/).inject(hash) do |h, part| next h if part == '' return false unless params_hash_type?(h) && h.key?(part) h[part] end true end def unescape(string, encoding = Encoding::UTF_8) URI.decode_www_form_component(string, encoding) end class Params def initialize @size = 0 @params = {} end def [](key) @params[key] end def []=(key, value) @params[key] = value end def key?(key) @params.key?(key) end # Recursively unwraps nested `Params` objects and constructs an object # of the same shape, but using the objects' internal representations # (Ruby hashes) in place of the objects. The result is a hash consisting # purely of Ruby primitives. # # Mutation warning! # # 1. This method mutates the internal representation of the `Params` # objects in order to save object allocations. # # 2. The value you get back is a reference to the internal hash # representation, not a copy. # # 3. Because the `Params` object's internal representation is mutable # through the `#[]=` method, it is not thread safe. The result of # getting the hash representation while another thread is adding a # key to it is non-deterministic. # def to_h @params.each do |key, value| case value when self # Handle circular references gracefully. @params[key] = @params when Params @params[key] = value.to_h when Array value.map! { |v| v.kind_of?(Params) ? v.to_h : v } else # Ignore anything that is not a `Params` object or # a collection that can contain one. end end @params end alias_method :to_params_hash, :to_h end end end PK ]U``"%gems/rack-3.0.8/lib/rack/multipart.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' require_relative 'multipart/parser' require_relative 'multipart/generator' module Rack # A multipart form data parser, adapted from IOWA. # # Usually, Rack::Request#POST takes care of calling this. module Multipart MULTIPART_BOUNDARY = "AaB03x" class << self def parse_multipart(env, params = Rack::Utils.default_query_parser) io = env[RACK_INPUT] if content_length = env['CONTENT_LENGTH'] content_length = content_length.to_i end content_type = env['CONTENT_TYPE'] tempfile = env[RACK_MULTIPART_TEMPFILE_FACTORY] || Parser::TEMPFILE_FACTORY bufsize = env[RACK_MULTIPART_BUFFER_SIZE] || Parser::BUFSIZE info = Parser.parse(io, content_length, content_type, tempfile, bufsize, params) env[RACK_TEMPFILES] = info.tmp_files return info.params end def extract_multipart(request, params = Rack::Utils.default_query_parser) parse_multipart(request.env) end def build_multipart(params, first = true) Generator.new(params, first).dump end end end end PK ]|Х!gems/rack-3.0.8/lib/rack/files.rbnu[# frozen_string_literal: true require 'time' require_relative 'constants' require_relative 'head' require_relative 'utils' require_relative 'request' require_relative 'mime' module Rack # Rack::Files serves files below the +root+ directory given, according to the # path info of the Rack request. # e.g. when Rack::Files.new("/etc") is used, you can access 'passwd' file # as http://localhost:9292/passwd # # Handlers can detect if bodies are a Rack::Files, and use mechanisms # like sendfile on the +path+. class Files ALLOWED_VERBS = %w[GET HEAD OPTIONS] ALLOW_HEADER = ALLOWED_VERBS.join(', ') MULTIPART_BOUNDARY = 'AaB03x' attr_reader :root def initialize(root, headers = {}, default_mime = 'text/plain') @root = (::File.expand_path(root) if root) @headers = headers @default_mime = default_mime @head = Rack::Head.new(lambda { |env| get env }) end def call(env) # HEAD requests drop the response body, including 4xx error messages. @head.call env end def get(env) request = Rack::Request.new env unless ALLOWED_VERBS.include? request.request_method return fail(405, "Method Not Allowed", { 'allow' => ALLOW_HEADER }) end path_info = Utils.unescape_path request.path_info return fail(400, "Bad Request") unless Utils.valid_path?(path_info) clean_path_info = Utils.clean_path_info(path_info) path = ::File.join(@root, clean_path_info) available = begin ::File.file?(path) && ::File.readable?(path) rescue SystemCallError # Not sure in what conditions this exception can occur, but this # is a safe way to handle such an error. # :nocov: false # :nocov: end if available serving(request, path) else fail(404, "File not found: #{path_info}") end end def serving(request, path) if request.options? return [200, { 'allow' => ALLOW_HEADER, CONTENT_LENGTH => '0' }, []] end last_modified = ::File.mtime(path).httpdate return [304, {}, []] if request.get_header('HTTP_IF_MODIFIED_SINCE') == last_modified headers = { "last-modified" => last_modified } mime_type = mime_type path, @default_mime headers[CONTENT_TYPE] = mime_type if mime_type # Set custom headers headers.merge!(@headers) if @headers status = 200 size = filesize path ranges = Rack::Utils.get_byte_ranges(request.get_header('HTTP_RANGE'), size) if ranges.nil? # No ranges: ranges = [0..size - 1] elsif ranges.empty? # Unsatisfiable. Return error, and file size: response = fail(416, "Byte range unsatisfiable") response[1]["content-range"] = "bytes */#{size}" return response else # Partial content partial_content = true if ranges.size == 1 range = ranges[0] headers["content-range"] = "bytes #{range.begin}-#{range.end}/#{size}" else headers[CONTENT_TYPE] = "multipart/byteranges; boundary=#{MULTIPART_BOUNDARY}" end status = 206 body = BaseIterator.new(path, ranges, mime_type: mime_type, size: size) size = body.bytesize end headers[CONTENT_LENGTH] = size.to_s if request.head? body = [] elsif !partial_content body = Iterator.new(path, ranges, mime_type: mime_type, size: size) end [status, headers, body] end class BaseIterator attr_reader :path, :ranges, :options def initialize(path, ranges, options) @path = path @ranges = ranges @options = options end def each ::File.open(path, "rb") do |file| ranges.each do |range| yield multipart_heading(range) if multipart? each_range_part(file, range) do |part| yield part end end yield "\r\n--#{MULTIPART_BOUNDARY}--\r\n" if multipart? end end def bytesize size = ranges.inject(0) do |sum, range| sum += multipart_heading(range).bytesize if multipart? sum += range.size end size += "\r\n--#{MULTIPART_BOUNDARY}--\r\n".bytesize if multipart? size end def close; end private def multipart? ranges.size > 1 end def multipart_heading(range) <<-EOF \r --#{MULTIPART_BOUNDARY}\r content-type: #{options[:mime_type]}\r content-range: bytes #{range.begin}-#{range.end}/#{options[:size]}\r \r EOF end def each_range_part(file, range) file.seek(range.begin) remaining_len = range.end - range.begin + 1 while remaining_len > 0 part = file.read([8192, remaining_len].min) break unless part remaining_len -= part.length yield part end end end class Iterator < BaseIterator alias :to_path :path end private def fail(status, body, headers = {}) body += "\n" [ status, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => body.size.to_s, "x-cascade" => "pass" }.merge!(headers), [body] ] end # The MIME type for the contents of the file located at @path def mime_type(path, default_mime) Mime.mime_type(::File.extname(path), default_mime) end def filesize(path) # We check via File::size? whether this file provides size info # via stat (e.g. /proc files often don't), otherwise we have to # figure it out by reading the whole file into memory. ::File.size?(path) || ::File.read(path).bytesize end end end PK ]44"gems/rack-3.0.8/lib/rack/events.rbnu[# frozen_string_literal: true require_relative 'body_proxy' require_relative 'request' require_relative 'response' module Rack ### This middleware provides hooks to certain places in the request / # response lifecycle. This is so that middleware that don't need to filter # the response data can safely leave it alone and not have to send messages # down the traditional "rack stack". # # The events are: # # * on_start(request, response) # # This event is sent at the start of the request, before the next # middleware in the chain is called. This method is called with a request # object, and a response object. Right now, the response object is always # nil, but in the future it may actually be a real response object. # # * on_commit(request, response) # # The response has been committed. The application has returned, but the # response has not been sent to the webserver yet. This method is always # called with a request object and the response object. The response # object is constructed from the rack triple that the application returned. # Changes may still be made to the response object at this point. # # * on_send(request, response) # # The webserver has started iterating over the response body and presumably # has started sending data over the wire. This method is always called with # a request object and the response object. The response object is # constructed from the rack triple that the application returned. Changes # SHOULD NOT be made to the response object as the webserver has already # started sending data. Any mutations will likely result in an exception. # # * on_finish(request, response) # # The webserver has closed the response, and all data has been written to # the response socket. The request and response object should both be # read-only at this point. The body MAY NOT be available on the response # object as it may have been flushed to the socket. # # * on_error(request, response, error) # # An exception has occurred in the application or an `on_commit` event. # This method will get the request, the response (if available) and the # exception that was raised. # # ## Order # # `on_start` is called on the handlers in the order that they were passed to # the constructor. `on_commit`, on_send`, `on_finish`, and `on_error` are # called in the reverse order. `on_finish` handlers are called inside an # `ensure` block, so they are guaranteed to be called even if something # raises an exception. If something raises an exception in a `on_finish` # method, then nothing is guaranteed. class Events module Abstract def on_start(req, res) end def on_commit(req, res) end def on_send(req, res) end def on_finish(req, res) end def on_error(req, res, e) end end class EventedBodyProxy < Rack::BodyProxy # :nodoc: attr_reader :request, :response def initialize(body, request, response, handlers, &block) super(body, &block) @request = request @response = response @handlers = handlers end def each @handlers.reverse_each { |handler| handler.on_send request, response } super end end class BufferedResponse < Rack::Response::Raw # :nodoc: attr_reader :body def initialize(status, headers, body) super(status, headers) @body = body end def to_a; [status, headers, body]; end end def initialize(app, handlers) @app = app @handlers = handlers end def call(env) request = make_request env on_start request, nil begin status, headers, body = @app.call request.env response = make_response status, headers, body on_commit request, response rescue StandardError => e on_error request, response, e on_finish request, response raise end body = EventedBodyProxy.new(body, request, response, @handlers) do on_finish request, response end [response.status, response.headers, body] end private def on_error(request, response, e) @handlers.reverse_each { |handler| handler.on_error request, response, e } end def on_commit(request, response) @handlers.reverse_each { |handler| handler.on_commit request, response } end def on_start(request, response) @handlers.each { |handler| handler.on_start request, nil } end def on_finish(request, response) @handlers.reverse_each { |handler| handler.on_finish request, response } end def make_request(env) Rack::Request.new env end def make_response(status, headers, body) BufferedResponse.new status, headers, body end end end PK ]A%gems/rack-3.0.8/lib/rack/directory.rbnu[# frozen_string_literal: true require 'time' require_relative 'constants' require_relative 'utils' require_relative 'head' require_relative 'mime' require_relative 'files' module Rack # Rack::Directory serves entries below the +root+ given, according to the # path info of the Rack request. If a directory is found, the file's contents # will be presented in an html based index. If a file is found, the env will # be passed to the specified +app+. # # If +app+ is not specified, a Rack::Files of the same +root+ will be used. class Directory DIR_FILE = "%s%s%s%s\n" DIR_PAGE_HEADER = <<-PAGE %s

    %s


    PAGE DIR_PAGE_FOOTER = <<-PAGE
    Name Size Type Last Modified

    PAGE # Body class for directory entries, showing an index page with links # to each file. class DirectoryBody < Struct.new(:root, :path, :files) # Yield strings for each part of the directory entry def each show_path = Utils.escape_html(path.sub(/^#{root}/, '')) yield(DIR_PAGE_HEADER % [ show_path, show_path ]) unless path.chomp('/') == root yield(DIR_FILE % DIR_FILE_escape(files.call('..'))) end Dir.foreach(path) do |basename| next if basename.start_with?('.') next unless f = files.call(basename) yield(DIR_FILE % DIR_FILE_escape(f)) end yield(DIR_PAGE_FOOTER) end private # Escape each element in the array of html strings. def DIR_FILE_escape(htmls) htmls.map { |e| Utils.escape_html(e) } end end # The root of the directory hierarchy. Only requests for files and # directories inside of the root directory are supported. attr_reader :root # Set the root directory and application for serving files. def initialize(root, app = nil) @root = ::File.expand_path(root) @app = app || Files.new(@root) @head = Head.new(method(:get)) end def call(env) # strip body if this is a HEAD call @head.call env end # Internals of request handling. Similar to call but does # not remove body for HEAD requests. def get(env) script_name = env[SCRIPT_NAME] path_info = Utils.unescape_path(env[PATH_INFO]) if client_error_response = check_bad_request(path_info) || check_forbidden(path_info) client_error_response else path = ::File.join(@root, path_info) list_path(env, path, path_info, script_name) end end # Rack response to use for requests with invalid paths, or nil if path is valid. def check_bad_request(path_info) return if Utils.valid_path?(path_info) body = "Bad Request\n" [400, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => body.bytesize.to_s, "x-cascade" => "pass" }, [body]] end # Rack response to use for requests with paths outside the root, or nil if path is inside the root. def check_forbidden(path_info) return unless path_info.include? ".." return if ::File.expand_path(::File.join(@root, path_info)).start_with?(@root) body = "Forbidden\n" [403, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => body.bytesize.to_s, "x-cascade" => "pass" }, [body]] end # Rack response to use for directories under the root. def list_directory(path_info, path, script_name) url_head = (script_name.split('/') + path_info.split('/')).map do |part| Utils.escape_path part end # Globbing not safe as path could contain glob metacharacters body = DirectoryBody.new(@root, path, ->(basename) do stat = stat(::File.join(path, basename)) next unless stat url = ::File.join(*url_head + [Utils.escape_path(basename)]) mtime = stat.mtime.httpdate if stat.directory? type = 'directory' size = '-' url << '/' if basename == '..' basename = 'Parent Directory' else basename << '/' end else type = Mime.mime_type(::File.extname(basename)) size = filesize_format(stat.size) end [ url, basename, size, type, mtime ] end) [ 200, { CONTENT_TYPE => 'text/html; charset=utf-8' }, body ] end # File::Stat for the given path, but return nil for missing/bad entries. def stat(path) ::File.stat(path) rescue Errno::ENOENT, Errno::ELOOP return nil end # Rack response to use for files and directories under the root. # Unreadable and non-file, non-directory entries will get a 404 response. def list_path(env, path, path_info, script_name) if (stat = stat(path)) && stat.readable? return @app.call(env) if stat.file? return list_directory(path_info, path, script_name) if stat.directory? end entity_not_found(path_info) end # Rack response to use for unreadable and non-file, non-directory entries. def entity_not_found(path_info) body = "Entity not found: #{path_info}\n" [404, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => body.bytesize.to_s, "x-cascade" => "pass" }, [body]] end # Stolen from Ramaze FILESIZE_FORMAT = [ ['%.1fT', 1 << 40], ['%.1fG', 1 << 30], ['%.1fM', 1 << 20], ['%.1fK', 1 << 10], ] # Provide human readable file sizes def filesize_format(int) FILESIZE_FORMAT.each do |format, size| return format % (int.to_f / size) if int >= size end "#{int}B" end end end PK ]iZ&&*gems/rack-3.0.8/lib/rack/content_length.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' module Rack # Sets the content-length header on responses that do not specify # a content-length or transfer-encoding header. Note that this # does not fix responses that have an invalid content-length # header specified. class ContentLength include Rack::Utils def initialize(app) @app = app end def call(env) status, headers, body = response = @app.call(env) if !STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) && !headers[CONTENT_LENGTH] && !headers[TRANSFER_ENCODING] && body.respond_to?(:to_ary) response[2] = body = body.to_ary headers[CONTENT_LENGTH] = body.sum(&:bytesize).to_s end response end end end PK ]ɸHO#gems/rack-3.0.8/lib/rack/version.rbnu[# frozen_string_literal: true # Copyright (C) 2007-2019 Leah Neukirchen # # Rack is freely distributable under the terms of an MIT-style license. # See MIT-LICENSE or https://opensource.org/licenses/MIT. # The Rack main module, serving as a namespace for all core Rack # modules and classes. # # All modules meant for use in your application are autoloaded here, # so it should be enough just to require 'rack' in your code. module Rack # The Rack protocol version number implemented. VERSION = [1, 3].freeze deprecate_constant :VERSION VERSION_STRING = "1.3".freeze deprecate_constant :VERSION_STRING # The Rack protocol version number implemented. def self.version warn "Rack.version is deprecated and will be removed in Rack 3.1!", uplevel: 1 VERSION end RELEASE = "3.0.8" # Return the Rack release as a dotted string. def self.release RELEASE end end PK ]R  )gems/rack-3.0.8/lib/rack/mock_response.rbnu[# frozen_string_literal: true require 'cgi/cookie' require 'time' require_relative 'response' module Rack # Rack::MockResponse provides useful helpers for testing your apps. # Usually, you don't create the MockResponse on your own, but use # MockRequest. class MockResponse < Rack::Response class << self alias [] new end # Headers attr_reader :original_headers, :cookies # Errors attr_accessor :errors def initialize(status, headers, body, errors = nil) @original_headers = headers if errors @errors = errors.string if errors.respond_to?(:string) else @errors = "" end super(body, status, headers) @cookies = parse_cookies_from_header buffered_body! end def =~(other) body =~ other end def match(other) body.match other end def body return @buffered_body if defined?(@buffered_body) # FIXME: apparently users of MockResponse expect the return value of # MockResponse#body to be a string. However, the real response object # returns the body as a list. # # See spec_showstatus.rb: # # should "not replace existing messages" do # ... # res.body.should == "foo!" # end buffer = @buffered_body = String.new @body.each do |chunk| buffer << chunk end return buffer end def empty? [201, 204, 304].include? status end def cookie(name) cookies.fetch(name, nil) end private def parse_cookies_from_header cookies = Hash.new if headers.has_key? 'set-cookie' set_cookie_header = headers.fetch('set-cookie') Array(set_cookie_header).each do |header_value| header_value.split("\n").each do |cookie| cookie_name, cookie_filling = cookie.split('=', 2) cookie_attributes = identify_cookie_attributes cookie_filling parsed_cookie = CGI::Cookie.new( 'name' => cookie_name.strip, 'value' => cookie_attributes.fetch('value'), 'path' => cookie_attributes.fetch('path', nil), 'domain' => cookie_attributes.fetch('domain', nil), 'expires' => cookie_attributes.fetch('expires', nil), 'secure' => cookie_attributes.fetch('secure', false) ) cookies.store(cookie_name, parsed_cookie) end end end cookies end def identify_cookie_attributes(cookie_filling) cookie_bits = cookie_filling.split(';') cookie_attributes = Hash.new cookie_attributes.store('value', cookie_bits[0].strip) cookie_bits.drop(1).each do |bit| if bit.include? '=' cookie_attribute, attribute_value = bit.split('=', 2) cookie_attributes.store(cookie_attribute.strip.downcase, attribute_value.strip) end if bit.include? 'secure' cookie_attributes.store('secure', true) end end if cookie_attributes.key? 'max-age' cookie_attributes.store('expires', Time.now + cookie_attributes['max-age'].to_i) elsif cookie_attributes.key? 'expires' cookie_attributes.store('expires', Time.httpdate(cookie_attributes['expires'])) end cookie_attributes end end end PK ]Y488$gems/rack-3.0.8/lib/rack/sendfile.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' require_relative 'body_proxy' module Rack # = Sendfile # # The Sendfile middleware intercepts responses whose body is being # served from a file and replaces it with a server specific x-sendfile # header. The web server is then responsible for writing the file contents # to the client. This can dramatically reduce the amount of work required # by the Ruby backend and takes advantage of the web server's optimized file # delivery code. # # In order to take advantage of this middleware, the response body must # respond to +to_path+ and the request must include an x-sendfile-type # header. Rack::Files and other components implement +to_path+ so there's # rarely anything you need to do in your application. The x-sendfile-type # header is typically set in your web servers configuration. The following # sections attempt to document # # === Nginx # # Nginx supports the x-accel-redirect header. This is similar to x-sendfile # but requires parts of the filesystem to be mapped into a private URL # hierarchy. # # The following example shows the Nginx configuration required to create # a private "/files/" area, enable x-accel-redirect, and pass the special # x-sendfile-type and x-accel-mapping headers to the backend: # # location ~ /files/(.*) { # internal; # alias /var/www/$1; # } # # location / { # proxy_redirect off; # # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # # proxy_set_header x-sendfile-type x-accel-redirect; # proxy_set_header x-accel-mapping /var/www/=/files/; # # proxy_pass http://127.0.0.1:8080/; # } # # Note that the x-sendfile-type header must be set exactly as shown above. # The x-accel-mapping header should specify the location on the file system, # followed by an equals sign (=), followed name of the private URL pattern # that it maps to. The middleware performs a simple substitution on the # resulting path. # # See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile # # === lighttpd # # Lighttpd has supported some variation of the x-sendfile header for some # time, although only recent version support x-sendfile in a reverse proxy # configuration. # # $HTTP["host"] == "example.com" { # proxy-core.protocol = "http" # proxy-core.balancer = "round-robin" # proxy-core.backends = ( # "127.0.0.1:8000", # "127.0.0.1:8001", # ... # ) # # proxy-core.allow-x-sendfile = "enable" # proxy-core.rewrite-request = ( # "x-sendfile-type" => (".*" => "x-sendfile") # ) # } # # See Also: http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModProxyCore # # === Apache # # x-sendfile is supported under Apache 2.x using a separate module: # # https://tn123.org/mod_xsendfile/ # # Once the module is compiled and installed, you can enable it using # XSendFile config directive: # # RequestHeader Set x-sendfile-type x-sendfile # ProxyPassReverse / http://localhost:8001/ # XSendFile on # # === Mapping parameter # # The third parameter allows for an overriding extension of the # x-accel-mapping header. Mappings should be provided in tuples of internal to # external. The internal values may contain regular expression syntax, they # will be matched with case indifference. class Sendfile def initialize(app, variation = nil, mappings = []) @app = app @variation = variation @mappings = mappings.map do |internal, external| [/^#{internal}/i, external] end end def call(env) _, headers, body = response = @app.call(env) if body.respond_to?(:to_path) case type = variation(env) when /x-accel-redirect/i path = ::File.expand_path(body.to_path) if url = map_accel_path(env, path) headers[CONTENT_LENGTH] = '0' # '?' must be percent-encoded because it is not query string but a part of path headers[type.downcase] = ::Rack::Utils.escape_path(url).gsub('?', '%3F') obody = body response[2] = Rack::BodyProxy.new([]) do obody.close if obody.respond_to?(:close) end else env[RACK_ERRORS].puts "x-accel-mapping header missing" end when /x-sendfile|x-lighttpd-send-file/i path = ::File.expand_path(body.to_path) headers[CONTENT_LENGTH] = '0' headers[type.downcase] = path obody = body response[2] = Rack::BodyProxy.new([]) do obody.close if obody.respond_to?(:close) end when '', nil else env[RACK_ERRORS].puts "Unknown x-sendfile variation: '#{type}'.\n" end end response end private def variation(env) @variation || env['sendfile.type'] || env['HTTP_X_SENDFILE_TYPE'] end def map_accel_path(env, path) if mapping = @mappings.find { |internal, _| internal =~ path } path.sub(*mapping) elsif mapping = env['HTTP_X_ACCEL_MAPPING'] mapping.split(',').map(&:strip).each do |m| internal, external = m.split('=', 2).map(&:strip) new_path = path.sub(/^#{internal}/i, external) return new_path unless path == new_path end path end end end end PK ]dP"gems/rack-3.0.8/lib/rack/logger.rbnu[# frozen_string_literal: true require 'logger' require_relative 'constants' module Rack # Sets up rack.logger to write to rack.errors stream class Logger def initialize(app, level = ::Logger::INFO) @app, @level = app, level end def call(env) logger = ::Logger.new(env[RACK_ERRORS]) logger.level = @level env[RACK_LOGGER] = logger @app.call(env) end end end PK ]M}Y?? gems/rack-3.0.8/lib/rack/mock.rbnu[# frozen_string_literal: true require_relative 'mock_request' PK ]K?33&gems/rack-3.0.8/lib/rack/body_proxy.rbnu[# frozen_string_literal: true module Rack # Proxy for response bodies allowing calling a block when # the response body is closed (after the response has been fully # sent to the client). class BodyProxy # Set the response body to wrap, and the block to call when the # response has been fully sent. def initialize(body, &block) @body = body @block = block @closed = false end # Return whether the wrapped body responds to the method. def respond_to_missing?(method_name, include_all = false) super or @body.respond_to?(method_name, include_all) end # If not already closed, close the wrapped body and # then call the block the proxy was initialized with. def close return if @closed @closed = true begin @body.close if @body.respond_to?(:close) ensure @block.call end end # Whether the proxy is closed. The proxy starts as not closed, # and becomes closed on the first call to close. def closed? @closed end # Delegate missing methods to the wrapped body. def method_missing(method_name, *args, &block) @body.__send__(method_name, *args, &block) end # :nocov: ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true) # :nocov: end end PK ]ю "gems/rack-3.0.8/lib/rack/static.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'files' require_relative 'mime' module Rack # The Rack::Static middleware intercepts requests for static files # (javascript files, images, stylesheets, etc) based on the url prefixes or # route mappings passed in the options, and serves them using a Rack::Files # object. This allows a Rack stack to serve both static and dynamic content. # # Examples: # # Serve all requests beginning with /media from the "media" folder located # in the current directory (ie media/*): # # use Rack::Static, :urls => ["/media"] # # Same as previous, but instead of returning 404 for missing files under # /media, call the next middleware: # # use Rack::Static, :urls => ["/media"], :cascade => true # # Serve all requests beginning with /css or /images from the folder "public" # in the current directory (ie public/css/* and public/images/*): # # use Rack::Static, :urls => ["/css", "/images"], :root => "public" # # Serve all requests to / with "index.html" from the folder "public" in the # current directory (ie public/index.html): # # use Rack::Static, :urls => {"/" => 'index.html'}, :root => 'public' # # Serve all requests normally from the folder "public" in the current # directory but uses index.html as default route for "/" # # use Rack::Static, :urls => [""], :root => 'public', :index => # 'index.html' # # Set custom HTTP Headers for based on rules: # # use Rack::Static, :root => 'public', # :header_rules => [ # [rule, {header_field => content, header_field => content}], # [rule, {header_field => content}] # ] # # Rules for selecting files: # # 1) All files # Provide the :all symbol # :all => Matches every file # # 2) Folders # Provide the folder path as a string # '/folder' or '/folder/subfolder' => Matches files in a certain folder # # 3) File Extensions # Provide the file extensions as an array # ['css', 'js'] or %w(css js) => Matches files ending in .css or .js # # 4) Regular Expressions / Regexp # Provide a regular expression # %r{\.(?:css|js)\z} => Matches files ending in .css or .js # /\.(?:eot|ttf|otf|woff2|woff|svg)\z/ => Matches files ending in # the most common web font formats (.eot, .ttf, .otf, .woff2, .woff, .svg) # Note: This Regexp is available as a shortcut, using the :fonts rule # # 5) Font Shortcut # Provide the :fonts symbol # :fonts => Uses the Regexp rule stated right above to match all common web font endings # # Rule Ordering: # Rules are applied in the order that they are provided. # List rather general rules above special ones. # # Complete example use case including HTTP header rules: # # use Rack::Static, :root => 'public', # :header_rules => [ # # Cache all static files in public caches (e.g. Rack::Cache) # # as well as in the browser # [:all, {'cache-control' => 'public, max-age=31536000'}], # # # Provide web fonts with cross-origin access-control-headers # # Firefox requires this when serving assets using a Content Delivery Network # [:fonts, {'access-control-allow-origin' => '*'}] # ] # class Static def initialize(app, options = {}) @app = app @urls = options[:urls] || ["/favicon.ico"] @index = options[:index] @gzip = options[:gzip] @cascade = options[:cascade] root = options[:root] || Dir.pwd # HTTP Headers @header_rules = options[:header_rules] || [] # Allow for legacy :cache_control option while prioritizing global header_rules setting @header_rules.unshift([:all, { CACHE_CONTROL => options[:cache_control] }]) if options[:cache_control] @file_server = Rack::Files.new(root) end def add_index_root?(path) @index && route_file(path) && path.end_with?('/') end def overwrite_file_path(path) @urls.kind_of?(Hash) && @urls.key?(path) || add_index_root?(path) end def route_file(path) @urls.kind_of?(Array) && @urls.any? { |url| path.index(url) == 0 } end def can_serve(path) route_file(path) || overwrite_file_path(path) end def call(env) path = env[PATH_INFO] if can_serve(path) if overwrite_file_path(path) env[PATH_INFO] = (add_index_root?(path) ? path + @index : @urls[path]) elsif @gzip && env['HTTP_ACCEPT_ENCODING'] && /\bgzip\b/.match?(env['HTTP_ACCEPT_ENCODING']) path = env[PATH_INFO] env[PATH_INFO] += '.gz' response = @file_server.call(env) env[PATH_INFO] = path if response[0] == 404 response = nil elsif response[0] == 304 # Do nothing, leave headers as is else response[1][CONTENT_TYPE] = Mime.mime_type(::File.extname(path), 'text/plain') response[1]['content-encoding'] = 'gzip' end end path = env[PATH_INFO] response ||= @file_server.call(env) if @cascade && response[0] == 404 return @app.call(env) end headers = response[1] applicable_rules(path).each do |rule, new_headers| new_headers.each { |field, content| headers[field] = content } end response else @app.call(env) end end # Convert HTTP header rules to HTTP headers def applicable_rules(path) @header_rules.find_all do |rule, new_headers| case rule when :all true when :fonts /\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path) when String path = ::Rack::Utils.unescape(path) path.start_with?(rule) || path.start_with?('/' + rule) when Array /\.(#{rule.join('|')})\z/.match?(path) when Regexp rule.match?(path) else false end end end end end PK ]VMVww gems/rack-3.0.8/lib/rack/etag.rbnu[# frozen_string_literal: true require 'digest/sha2' require_relative 'constants' require_relative 'utils' module Rack # Automatically sets the etag header on all String bodies. # # The etag header is skipped if etag or last-modified headers are sent or if # a sendfile body (body.responds_to :to_path) is given (since such cases # should be handled by apache/nginx). # # On initialization, you can pass two parameters: a cache-control directive # used when etag is absent and a directive when it is present. The first # defaults to nil, while the second defaults to "max-age=0, private, must-revalidate" class ETag ETAG_STRING = Rack::ETAG DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate" def initialize(app, no_cache_control = nil, cache_control = DEFAULT_CACHE_CONTROL) @app = app @cache_control = cache_control @no_cache_control = no_cache_control end def call(env) status, headers, body = response = @app.call(env) if etag_status?(status) && body.respond_to?(:to_ary) && !skip_caching?(headers) body = body.to_ary digest = digest_body(body) headers[ETAG_STRING] = %(W/"#{digest}") if digest end unless headers[CACHE_CONTROL] if digest headers[CACHE_CONTROL] = @cache_control if @cache_control else headers[CACHE_CONTROL] = @no_cache_control if @no_cache_control end end response end private def etag_status?(status) status == 200 || status == 201 end def skip_caching?(headers) headers.key?(ETAG_STRING) || headers.key?('last-modified') end def digest_body(body) digest = nil body.each do |part| (digest ||= Digest::SHA256.new) << part unless part.empty? end digest && digest.hexdigest.byteslice(0,32) end end end PK ];~ ~ ,gems/rack-3.0.8/lib/rack/rewindable_input.rbnu[# -*- encoding: binary -*- # frozen_string_literal: true require 'tempfile' require_relative 'constants' module Rack # Class which can make any IO object rewindable, including non-rewindable ones. It does # this by buffering the data into a tempfile, which is rewindable. # # Don't forget to call #close when you're done. This frees up temporary resources that # RewindableInput uses, though it does *not* close the original IO object. class RewindableInput # Makes rack.input rewindable, for compatibility with applications and middleware # designed for earlier versions of Rack (where rack.input was required to be # rewindable). class Middleware def initialize(app) @app = app end def call(env) env[RACK_INPUT] = RewindableInput.new(env[RACK_INPUT]) @app.call(env) end end def initialize(io) @io = io @rewindable_io = nil @unlinked = false end def gets make_rewindable unless @rewindable_io @rewindable_io.gets end def read(*args) make_rewindable unless @rewindable_io @rewindable_io.read(*args) end def each(&block) make_rewindable unless @rewindable_io @rewindable_io.each(&block) end def rewind make_rewindable unless @rewindable_io @rewindable_io.rewind end def size make_rewindable unless @rewindable_io @rewindable_io.size end # Closes this RewindableInput object without closing the originally # wrapped IO object. Cleans up any temporary resources that this RewindableInput # has created. # # This method may be called multiple times. It does nothing on subsequent calls. def close if @rewindable_io if @unlinked @rewindable_io.close else @rewindable_io.close! end @rewindable_io = nil end end private def make_rewindable # Buffer all data into a tempfile. Since this tempfile is private to this # RewindableInput object, we chmod it so that nobody else can read or write # it. On POSIX filesystems we also unlink the file so that it doesn't # even have a file entry on the filesystem anymore, though we can still # access it because we have the file handle open. @rewindable_io = Tempfile.new('RackRewindableInput') @rewindable_io.chmod(0000) @rewindable_io.set_encoding(Encoding::BINARY) @rewindable_io.binmode # :nocov: if filesystem_has_posix_semantics? raise 'Unlink failed. IO closed.' if @rewindable_io.closed? @unlinked = true end # :nocov: buffer = "".dup while @io.read(1024 * 4, buffer) entire_buffer_written_out = false while !entire_buffer_written_out written = @rewindable_io.write(buffer) entire_buffer_written_out = written == buffer.bytesize if !entire_buffer_written_out buffer.slice!(0 .. written - 1) end end end @rewindable_io.rewind end def filesystem_has_posix_semantics? RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ end end end PK ]$**$gems/rack-3.0.8/lib/rack/response.rbnu[# frozen_string_literal: true require 'time' require_relative 'constants' require_relative 'utils' require_relative 'media_type' require_relative 'headers' module Rack # Rack::Response provides a convenient interface to create a Rack # response. # # It allows setting of headers and cookies, and provides useful # defaults (an OK response with empty headers and body). # # You can use Response#write to iteratively generate your response, # but note that this is buffered by Rack::Response until you call # +finish+. +finish+ however can take a block inside which calls to # +write+ are synchronous with the Rack response. # # Your application's +call+ should end returning Response#finish. class Response def self.[](status, headers, body) self.new(body, status, headers) end CHUNKED = 'chunked' STATUS_WITH_NO_ENTITY_BODY = Utils::STATUS_WITH_NO_ENTITY_BODY attr_accessor :length, :status, :body attr_reader :headers # Deprecated, use headers instead. def header warn 'Rack::Response#header is deprecated and will be removed in Rack 3.1', uplevel: 1 headers end # Initialize the response object with the specified +body+, +status+ # and +headers+. # # If the +body+ is +nil+, construct an empty response object with internal # buffering. # # If the +body+ responds to +to_str+, assume it's a string-like object and # construct a buffered response object containing using that string as the # initial contents of the buffer. # # Otherwise it is expected +body+ conforms to the normal requirements of a # Rack response body, typically implementing one of +each+ (enumerable # body) or +call+ (streaming body). # # The +status+ defaults to +200+ which is the "OK" HTTP status code. You # can provide any other valid status code. # # The +headers+ must be a +Hash+ of key-value header pairs which conform to # the Rack specification for response headers. The key must be a +String+ # instance and the value can be either a +String+ or +Array+ instance. def initialize(body = nil, status = 200, headers = {}) @status = status.to_i unless headers.is_a?(Hash) warn "Providing non-hash headers to Rack::Response is deprecated and will be removed in Rack 3.1", uplevel: 1 end @headers = Headers.new # Convert headers input to a plain hash with lowercase keys. headers.each do |k, v| @headers[k] = v end @writer = self.method(:append) @block = nil # Keep track of whether we have expanded the user supplied body. if body.nil? @body = [] @buffered = true @length = 0 elsif body.respond_to?(:to_str) @body = [body] @buffered = true @length = body.to_str.bytesize else @body = body @buffered = nil # undetermined as of yet. @length = 0 end yield self if block_given? end def redirect(target, status = 302) self.status = status self.location = target end def chunked? CHUNKED == get_header(TRANSFER_ENCODING) end def no_entity_body? # The response body is an enumerable body and it is not allowed to have an entity body. @body.respond_to?(:each) && STATUS_WITH_NO_ENTITY_BODY[@status] end # Generate a response array consistent with the requirements of the SPEC. # @return [Array] a 3-tuple suitable of `[status, headers, body]` # which is suitable to be returned from the middleware `#call(env)` method. def finish(&block) if no_entity_body? delete_header CONTENT_TYPE delete_header CONTENT_LENGTH close return [@status, @headers, []] else if block_given? @block = block return [@status, @headers, self] else return [@status, @headers, @body] end end end alias to_a finish # For *response def each(&callback) @body.each(&callback) @buffered = true if @block @writer = callback @block.call(self) end end # Append to body and update content-length. # # NOTE: Do not mix #write and direct #body access! # def write(chunk) buffered_body! @writer.call(chunk.to_s) end def close @body.close if @body.respond_to?(:close) end def empty? @block == nil && @body.empty? end def has_header?(key) raise ArgumentError unless key.is_a?(String) @headers.key?(key) end def get_header(key) raise ArgumentError unless key.is_a?(String) @headers[key] end def set_header(key, value) raise ArgumentError unless key.is_a?(String) @headers[key] = value end def delete_header(key) raise ArgumentError unless key.is_a?(String) @headers.delete key end alias :[] :get_header alias :[]= :set_header module Helpers def invalid?; status < 100 || status >= 600; end def informational?; status >= 100 && status < 200; end def successful?; status >= 200 && status < 300; end def redirection?; status >= 300 && status < 400; end def client_error?; status >= 400 && status < 500; end def server_error?; status >= 500 && status < 600; end def ok?; status == 200; end def created?; status == 201; end def accepted?; status == 202; end def no_content?; status == 204; end def moved_permanently?; status == 301; end def bad_request?; status == 400; end def unauthorized?; status == 401; end def forbidden?; status == 403; end def not_found?; status == 404; end def method_not_allowed?; status == 405; end def not_acceptable?; status == 406; end def request_timeout?; status == 408; end def precondition_failed?; status == 412; end def unprocessable?; status == 422; end def redirect?; [301, 302, 303, 307, 308].include? status; end def include?(header) has_header?(header) end # Add a header that may have multiple values. # # Example: # response.add_header 'vary', 'accept-encoding' # response.add_header 'vary', 'cookie' # # assert_equal 'accept-encoding,cookie', response.get_header('vary') # # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 def add_header(key, value) raise ArgumentError unless key.is_a?(String) if value.nil? return get_header(key) end value = value.to_s if header = get_header(key) if header.is_a?(Array) header << value else set_header(key, [header, value]) end else set_header(key, value) end end # Get the content type of the response. def content_type get_header CONTENT_TYPE end # Set the content type of the response. def content_type=(content_type) set_header CONTENT_TYPE, content_type end def media_type MediaType.type(content_type) end def media_type_params MediaType.params(content_type) end def content_length cl = get_header CONTENT_LENGTH cl ? cl.to_i : cl end def location get_header "location" end def location=(location) set_header "location", location end def set_cookie(key, value) add_header SET_COOKIE, Utils.set_cookie_header(key, value) end def delete_cookie(key, value = {}) set_header(SET_COOKIE, Utils.delete_set_cookie_header!( get_header(SET_COOKIE), key, value ) ) end def set_cookie_header get_header SET_COOKIE end def set_cookie_header=(value) set_header SET_COOKIE, value end def cache_control get_header CACHE_CONTROL end def cache_control=(value) set_header CACHE_CONTROL, value end # Specifies that the content shouldn't be cached. Overrides `cache!` if already called. def do_not_cache! set_header CACHE_CONTROL, "no-cache, must-revalidate" set_header EXPIRES, Time.now.httpdate end # Specify that the content should be cached. # @param duration [Integer] The number of seconds until the cache expires. # @option directive [String] The cache control directive, one of "public", "private", "no-cache" or "no-store". def cache!(duration = 3600, directive: "public") unless headers[CACHE_CONTROL] =~ /no-cache/ set_header CACHE_CONTROL, "#{directive}, max-age=#{duration}" set_header EXPIRES, (Time.now + duration).httpdate end end def etag get_header ETAG end def etag=(value) set_header ETAG, value end protected def buffered_body! if @buffered.nil? if @body.is_a?(Array) # The user supplied body was an array: @body = @body.compact @body.each do |part| @length += part.to_s.bytesize end elsif @body.respond_to?(:each) # Turn the user supplied body into a buffered array: body = @body @body = Array.new body.each do |part| @writer.call(part.to_s) end body.close if body.respond_to?(:close) @buffered = true else @buffered = false end end return @buffered end def append(chunk) @body << chunk unless chunked? @length += chunk.bytesize set_header(CONTENT_LENGTH, @length.to_s) end return chunk end end include Helpers class Raw include Helpers attr_reader :headers attr_accessor :status def initialize(status, headers) @status = status @headers = headers end def has_header?(key) headers.key?(key) end def get_header(key) headers[key] end def set_header(key, value) headers[key] = value end def delete_header(key) headers.delete(key) end end end end PK ]3+gems/rack-3.0.8/lib/rack/method_override.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'request' require_relative 'utils' module Rack class MethodOverride HTTP_METHODS = %w[GET HEAD PUT POST DELETE OPTIONS PATCH LINK UNLINK] METHOD_OVERRIDE_PARAM_KEY = "_method" HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE" ALLOWED_METHODS = %w[POST] def initialize(app) @app = app end def call(env) if allowed_methods.include?(env[REQUEST_METHOD]) method = method_override(env) if HTTP_METHODS.include?(method) env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] = env[REQUEST_METHOD] env[REQUEST_METHOD] = method end end @app.call(env) end def method_override(env) req = Request.new(env) method = method_override_param(req) || env[HTTP_METHOD_OVERRIDE_HEADER] begin method.to_s.upcase rescue ArgumentError env[RACK_ERRORS].puts "Invalid string for method" end end private def allowed_methods ALLOWED_METHODS end def method_override_param(req) req.POST[METHOD_OVERRIDE_PARAM_KEY] if req.form_data? || req.parseable_data? rescue Utils::InvalidParameterError, Utils::ParameterTypeError, QueryParser::ParamsTooDeepError req.get_header(RACK_ERRORS).puts "Invalid or incomplete POST params" rescue EOFError req.get_header(RACK_ERRORS).puts "Bad request content body" end end end PK ]@j %gems/rack-3.0.8/lib/rack/constants.rbnu[# frozen_string_literal: true module Rack # Request env keys HTTP_HOST = 'HTTP_HOST' HTTP_PORT = 'HTTP_PORT' HTTPS = 'HTTPS' PATH_INFO = 'PATH_INFO' REQUEST_METHOD = 'REQUEST_METHOD' REQUEST_PATH = 'REQUEST_PATH' SCRIPT_NAME = 'SCRIPT_NAME' QUERY_STRING = 'QUERY_STRING' SERVER_PROTOCOL = 'SERVER_PROTOCOL' SERVER_NAME = 'SERVER_NAME' SERVER_PORT = 'SERVER_PORT' HTTP_COOKIE = 'HTTP_COOKIE' # Response Header Keys CACHE_CONTROL = 'cache-control' CONTENT_LENGTH = 'content-length' CONTENT_TYPE = 'content-type' ETAG = 'etag' EXPIRES = 'expires' SET_COOKIE = 'set-cookie' TRANSFER_ENCODING = 'transfer-encoding' # HTTP method verbs GET = 'GET' POST = 'POST' PUT = 'PUT' PATCH = 'PATCH' DELETE = 'DELETE' HEAD = 'HEAD' OPTIONS = 'OPTIONS' LINK = 'LINK' UNLINK = 'UNLINK' TRACE = 'TRACE' # Rack environment variables RACK_VERSION = 'rack.version' RACK_TEMPFILES = 'rack.tempfiles' RACK_ERRORS = 'rack.errors' RACK_LOGGER = 'rack.logger' RACK_INPUT = 'rack.input' RACK_SESSION = 'rack.session' RACK_SESSION_OPTIONS = 'rack.session.options' RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail' RACK_URL_SCHEME = 'rack.url_scheme' RACK_HIJACK = 'rack.hijack' RACK_IS_HIJACK = 'rack.hijack?' RACK_RECURSIVE_INCLUDE = 'rack.recursive.include' RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size' RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory' RACK_RESPONSE_FINISHED = 'rack.response_finished' RACK_REQUEST_FORM_INPUT = 'rack.request.form_input' RACK_REQUEST_FORM_HASH = 'rack.request.form_hash' RACK_REQUEST_FORM_VARS = 'rack.request.form_vars' RACK_REQUEST_FORM_ERROR = 'rack.request.form_error' RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash' RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string' RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash' RACK_REQUEST_QUERY_STRING = 'rack.request.query_string' RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method' end PK ]Oi #gems/rack-3.0.8/lib/rack/headers.rbnu[module Rack # Rack::Headers is a Hash subclass that downcases all keys. It's designed # to be used by rack applications that don't implement the Rack 3 SPEC # (by using non-lowercase response header keys), automatically handling # the downcasing of keys. class Headers < Hash def self.[](*items) if items.length % 2 != 0 if items.length == 1 && items.first.is_a?(Hash) new.merge!(items.first) else raise ArgumentError, "odd number of arguments for Rack::Headers" end else hash = new loop do break if items.length == 0 key = items.shift value = items.shift hash[key] = value end hash end end def [](key) super(downcase_key(key)) end def []=(key, value) super(key.downcase.freeze, value) end alias store []= def assoc(key) super(downcase_key(key)) end def compare_by_identity raise TypeError, "Rack::Headers cannot compare by identity, use regular Hash" end def delete(key) super(downcase_key(key)) end def dig(key, *a) super(downcase_key(key), *a) end def fetch(key, *default, &block) key = downcase_key(key) super end def fetch_values(*a) super(*a.map!{|key| downcase_key(key)}) end def has_key?(key) super(downcase_key(key)) end alias include? has_key? alias key? has_key? alias member? has_key? def invert hash = self.class.new each{|key, value| hash[value] = key} hash end def merge(hash, &block) dup.merge!(hash, &block) end def reject(&block) hash = dup hash.reject!(&block) hash end def replace(hash) clear update(hash) end def select(&block) hash = dup hash.select!(&block) hash end def to_proc lambda{|x| self[x]} end def transform_values(&block) dup.transform_values!(&block) end def update(hash, &block) hash.each do |key, value| self[key] = if block_given? && include?(key) block.call(key, self[key], value) else value end end self end alias merge! update def values_at(*keys) keys.map{|key| self[key]} end # :nocov: if RUBY_VERSION >= '2.5' # :nocov: def slice(*a) h = self.class.new a.each{|k| h[k] = self[k] if has_key?(k)} h end def transform_keys(&block) dup.transform_keys!(&block) end def transform_keys! hash = self.class.new each do |k, v| hash[yield k] = v end replace(hash) end end # :nocov: if RUBY_VERSION >= '3.0' # :nocov: def except(*a) super(*a.map!{|key| downcase_key(key)}) end end private def downcase_key(key) key.is_a?(String) ? key.downcase : key end end end PK ]ѝo   gems/rack-3.0.8/lib/rack/head.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'body_proxy' module Rack # Rack::Head returns an empty body for all HEAD requests. It leaves # all other requests unchanged. class Head def initialize(app) @app = app end def call(env) _, _, body = response = @app.call(env) if env[REQUEST_METHOD] == HEAD response[2] = Rack::BodyProxy.new([]) do body.close if body.respond_to? :close end end response end end end PK ]՝[[ gems/rack-3.0.8/lib/rack/lint.rbnuȯ# frozen_string_literal: true require 'forwardable' require_relative 'constants' require_relative 'utils' module Rack # Rack::Lint validates your application and the requests and # responses according to the Rack spec. class Lint def initialize(app) @app = app end # :stopdoc: class LintError < RuntimeError; end # AUTHORS: n.b. The trailing whitespace between paragraphs is important and # should not be removed. The whitespace creates paragraphs in the RDoc # output. # ## This specification aims to formalize the Rack protocol. You ## can (and should) use Rack::Lint to enforce it. ## ## When you develop middleware, be sure to add a Lint before and ## after to catch all mistakes. ## ## = Rack applications ## ## A Rack application is a Ruby object (not a class) that ## responds to +call+. def call(env = nil) Wrapper.new(@app, env).response end class Wrapper def initialize(app, env) @app = app @env = env @response = nil @head_request = false @status = nil @headers = nil @body = nil @invoked = nil @content_length = nil @closed = false @size = 0 end def response ## It takes exactly one argument, the *environment* raise LintError, "No env given" unless @env check_environment(@env) @env[RACK_INPUT] = InputWrapper.new(@env[RACK_INPUT]) @env[RACK_ERRORS] = ErrorWrapper.new(@env[RACK_ERRORS]) ## and returns a non-frozen Array of exactly three values: @response = @app.call(@env) raise LintError, "response is not an Array, but #{@response.class}" unless @response.kind_of? Array raise LintError, "response is frozen" if @response.frozen? raise LintError, "response array has #{@response.size} elements instead of 3" unless @response.size == 3 @status, @headers, @body = @response ## The *status*, check_status(@status) ## the *headers*, check_headers(@headers) hijack_proc = check_hijack_response(@headers, @env) if hijack_proc @headers[RACK_HIJACK] = hijack_proc end ## and the *body*. check_content_type(@status, @headers) check_content_length(@status, @headers) @head_request = @env[REQUEST_METHOD] == HEAD @lint = (@env['rack.lint'] ||= []) << self if (@env['rack.lint.body_iteration'] ||= 0) > 0 raise LintError, "Middleware must not call #each directly" end return [@status, @headers, self] end ## ## == The Environment ## def check_environment(env) ## The environment must be an unfrozen instance of Hash that includes ## CGI-like headers. The Rack application is free to modify the ## environment. raise LintError, "env #{env.inspect} is not a Hash, but #{env.class}" unless env.kind_of? Hash raise LintError, "env should not be frozen, but is" if env.frozen? ## ## The environment is required to include these variables ## (adopted from {PEP 333}[https://peps.python.org/pep-0333/]), except when they'd be empty, but see ## below. ## REQUEST_METHOD:: The HTTP request method, such as ## "GET" or "POST". This cannot ever ## be an empty string, and so is ## always required. ## SCRIPT_NAME:: The initial portion of the request ## URL's "path" that corresponds to the ## application object, so that the ## application knows its virtual ## "location". This may be an empty ## string, if the application corresponds ## to the "root" of the server. ## PATH_INFO:: The remainder of the request URL's ## "path", designating the virtual ## "location" of the request's target ## within the application. This may be an ## empty string, if the request URL targets ## the application root and does not have a ## trailing slash. This value may be ## percent-encoded when originating from ## a URL. ## QUERY_STRING:: The portion of the request URL that ## follows the ?, if any. May be ## empty, but is always required! ## SERVER_NAME:: When combined with SCRIPT_NAME and ## PATH_INFO, these variables can be ## used to complete the URL. Note, however, ## that HTTP_HOST, if present, ## should be used in preference to ## SERVER_NAME for reconstructing ## the request URL. ## SERVER_NAME can never be an empty ## string, and so is always required. ## SERVER_PORT:: An optional +Integer+ which is the port the ## server is running on. Should be specified if ## the server is running on a non-standard port. ## SERVER_PROTOCOL:: A string representing the HTTP version used ## for the request. ## HTTP_ Variables:: Variables corresponding to the ## client-supplied HTTP request ## headers (i.e., variables whose ## names begin with HTTP_). The ## presence or absence of these ## variables should correspond with ## the presence or absence of the ## appropriate HTTP header in the ## request. See ## {RFC3875 section 4.1.18}[https://tools.ietf.org/html/rfc3875#section-4.1.18] ## for specific behavior. ## In addition to this, the Rack environment must include these ## Rack-specific variables: ## rack.url_scheme:: +http+ or +https+, depending on the ## request URL. ## rack.input:: See below, the input stream. ## rack.errors:: See below, the error stream. ## rack.hijack?:: See below, if present and true, indicates ## that the server supports partial hijacking. ## rack.hijack:: See below, if present, an object responding ## to +call+ that is used to perform a full ## hijack. ## Additional environment specifications have approved to ## standardized middleware APIs. None of these are required to ## be implemented by the server. ## rack.session:: A hash-like interface for storing ## request session data. ## The store must implement: if session = env[RACK_SESSION] ## store(key, value) (aliased as []=); unless session.respond_to?(:store) && session.respond_to?(:[]=) raise LintError, "session #{session.inspect} must respond to store and []=" end ## fetch(key, default = nil) (aliased as []); unless session.respond_to?(:fetch) && session.respond_to?(:[]) raise LintError, "session #{session.inspect} must respond to fetch and []" end ## delete(key); unless session.respond_to?(:delete) raise LintError, "session #{session.inspect} must respond to delete" end ## clear; unless session.respond_to?(:clear) raise LintError, "session #{session.inspect} must respond to clear" end ## to_hash (returning unfrozen Hash instance); unless session.respond_to?(:to_hash) && session.to_hash.kind_of?(Hash) && !session.to_hash.frozen? raise LintError, "session #{session.inspect} must respond to to_hash and return unfrozen Hash instance" end end ## rack.logger:: A common object interface for logging messages. ## The object must implement: if logger = env[RACK_LOGGER] ## info(message, &block) unless logger.respond_to?(:info) raise LintError, "logger #{logger.inspect} must respond to info" end ## debug(message, &block) unless logger.respond_to?(:debug) raise LintError, "logger #{logger.inspect} must respond to debug" end ## warn(message, &block) unless logger.respond_to?(:warn) raise LintError, "logger #{logger.inspect} must respond to warn" end ## error(message, &block) unless logger.respond_to?(:error) raise LintError, "logger #{logger.inspect} must respond to error" end ## fatal(message, &block) unless logger.respond_to?(:fatal) raise LintError, "logger #{logger.inspect} must respond to fatal" end end ## rack.multipart.buffer_size:: An Integer hint to the multipart parser as to what chunk size to use for reads and writes. if bufsize = env[RACK_MULTIPART_BUFFER_SIZE] unless bufsize.is_a?(Integer) && bufsize > 0 raise LintError, "rack.multipart.buffer_size must be an Integer > 0 if specified" end end ## rack.multipart.tempfile_factory:: An object responding to #call with two arguments, the filename and content_type given for the multipart form field, and returning an IO-like object that responds to #<< and optionally #rewind. This factory will be used to instantiate the tempfile for each multipart form file upload field, rather than the default class of Tempfile. if tempfile_factory = env[RACK_MULTIPART_TEMPFILE_FACTORY] raise LintError, "rack.multipart.tempfile_factory must respond to #call" unless tempfile_factory.respond_to?(:call) env[RACK_MULTIPART_TEMPFILE_FACTORY] = lambda do |filename, content_type| io = tempfile_factory.call(filename, content_type) raise LintError, "rack.multipart.tempfile_factory return value must respond to #<<" unless io.respond_to?(:<<) io end end ## The server or the application can store their own data in the ## environment, too. The keys must contain at least one dot, ## and should be prefixed uniquely. The prefix rack. ## is reserved for use with the Rack core distribution and other ## accepted specifications and must not be used otherwise. ## %w[REQUEST_METHOD SERVER_NAME QUERY_STRING SERVER_PROTOCOL rack.input rack.errors].each { |header| raise LintError, "env missing required key #{header}" unless env.include? header } ## The SERVER_PORT must be an Integer if set. server_port = env["SERVER_PORT"] unless server_port.nil? || (Integer(server_port) rescue false) raise LintError, "env[SERVER_PORT] is not an Integer" end ## The SERVER_NAME must be a valid authority as defined by RFC7540. unless (URI.parse("http://#{env[SERVER_NAME]}/") rescue false) raise LintError, "#{env[SERVER_NAME]} must be a valid authority" end ## The HTTP_HOST must be a valid authority as defined by RFC7540. unless (URI.parse("http://#{env[HTTP_HOST]}/") rescue false) raise LintError, "#{env[HTTP_HOST]} must be a valid authority" end ## The SERVER_PROTOCOL must match the regexp HTTP/\d(\.\d)?. server_protocol = env['SERVER_PROTOCOL'] unless %r{HTTP/\d(\.\d)?}.match?(server_protocol) raise LintError, "env[SERVER_PROTOCOL] does not match HTTP/\\d(\\.\\d)?" end ## If the HTTP_VERSION is present, it must equal the SERVER_PROTOCOL. if env['HTTP_VERSION'] && env['HTTP_VERSION'] != server_protocol raise LintError, "env[HTTP_VERSION] does not equal env[SERVER_PROTOCOL]" end ## The environment must not contain the keys ## HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH ## (use the versions without HTTP_). %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header| if env.include? header raise LintError, "env contains #{header}, must use #{header[5..-1]}" end } ## The CGI keys (named without a period) must have String values. ## If the string values for CGI keys contain non-ASCII characters, ## they should use ASCII-8BIT encoding. env.each { |key, value| next if key.include? "." # Skip extensions unless value.kind_of? String raise LintError, "env variable #{key} has non-string value #{value.inspect}" end next if value.encoding == Encoding::ASCII_8BIT unless value.b !~ /[\x80-\xff]/n raise LintError, "env variable #{key} has value containing non-ASCII characters and has non-ASCII-8BIT encoding #{value.inspect} encoding: #{value.encoding}" end } ## There are the following restrictions: ## * rack.url_scheme must either be +http+ or +https+. unless %w[http https].include?(env[RACK_URL_SCHEME]) raise LintError, "rack.url_scheme unknown: #{env[RACK_URL_SCHEME].inspect}" end ## * There must be a valid input stream in rack.input. check_input env[RACK_INPUT] ## * There must be a valid error stream in rack.errors. check_error env[RACK_ERRORS] ## * There may be a valid hijack callback in rack.hijack check_hijack env ## * The REQUEST_METHOD must be a valid token. unless env[REQUEST_METHOD] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/ raise LintError, "REQUEST_METHOD unknown: #{env[REQUEST_METHOD].dump}" end ## * The SCRIPT_NAME, if non-empty, must start with / if env.include?(SCRIPT_NAME) && env[SCRIPT_NAME] != "" && env[SCRIPT_NAME] !~ /\A\// raise LintError, "SCRIPT_NAME must start with /" end ## * The PATH_INFO, if non-empty, must start with / if env.include?(PATH_INFO) && env[PATH_INFO] != "" && env[PATH_INFO] !~ /\A\// raise LintError, "PATH_INFO must start with /" end ## * The CONTENT_LENGTH, if given, must consist of digits only. if env.include?("CONTENT_LENGTH") && env["CONTENT_LENGTH"] !~ /\A\d+\z/ raise LintError, "Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}" end ## * One of SCRIPT_NAME or PATH_INFO must be ## set. PATH_INFO should be / if ## SCRIPT_NAME is empty. unless env[SCRIPT_NAME] || env[PATH_INFO] raise LintError, "One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)" end ## SCRIPT_NAME never should be /, but instead be empty. unless env[SCRIPT_NAME] != "/" raise LintError, "SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'" end ## rack.response_finished:: An array of callables run by the server after the response has been ## processed. This would typically be invoked after sending the response to the client, but it could also be ## invoked if an error occurs while generating the response or sending the response; in that case, the error ## argument will be a subclass of +Exception+. ## The callables are invoked with +env, status, headers, error+ arguments and should not raise any ## exceptions. They should be invoked in reverse order of registration. if callables = env[RACK_RESPONSE_FINISHED] raise LintError, "rack.response_finished must be an array of callable objects" unless callables.is_a?(Array) callables.each do |callable| raise LintError, "rack.response_finished values must respond to call(env, status, headers, error)" unless callable.respond_to?(:call) end end end ## ## === The Input Stream ## ## The input stream is an IO-like object which contains the raw HTTP ## POST data. def check_input(input) ## When applicable, its external encoding must be "ASCII-8BIT" and it ## must be opened in binary mode, for Ruby 1.9 compatibility. if input.respond_to?(:external_encoding) && input.external_encoding != Encoding::ASCII_8BIT raise LintError, "rack.input #{input} does not have ASCII-8BIT as its external encoding" end if input.respond_to?(:binmode?) && !input.binmode? raise LintError, "rack.input #{input} is not opened in binary mode" end ## The input stream must respond to +gets+, +each+, and +read+. [:gets, :each, :read].each { |method| unless input.respond_to? method raise LintError, "rack.input #{input} does not respond to ##{method}" end } end class InputWrapper def initialize(input) @input = input end ## * +gets+ must be called without arguments and return a string, ## or +nil+ on EOF. def gets(*args) raise LintError, "rack.input#gets called with arguments" unless args.size == 0 v = @input.gets unless v.nil? or v.kind_of? String raise LintError, "rack.input#gets didn't return a String" end v end ## * +read+ behaves like IO#read. ## Its signature is read([length, [buffer]]). ## ## If given, +length+ must be a non-negative Integer (>= 0) or +nil+, ## and +buffer+ must be a String and may not be nil. ## ## If +length+ is given and not nil, then this method reads at most ## +length+ bytes from the input stream. ## ## If +length+ is not given or nil, then this method reads ## all data until EOF. ## ## When EOF is reached, this method returns nil if +length+ is given ## and not nil, or "" if +length+ is not given or is nil. ## ## If +buffer+ is given, then the read data will be placed ## into +buffer+ instead of a newly created String object. def read(*args) unless args.size <= 2 raise LintError, "rack.input#read called with too many arguments" end if args.size >= 1 unless args.first.kind_of?(Integer) || args.first.nil? raise LintError, "rack.input#read called with non-integer and non-nil length" end unless args.first.nil? || args.first >= 0 raise LintError, "rack.input#read called with a negative length" end end if args.size >= 2 unless args[1].kind_of?(String) raise LintError, "rack.input#read called with non-String buffer" end end v = @input.read(*args) unless v.nil? or v.kind_of? String raise LintError, "rack.input#read didn't return nil or a String" end if args[0].nil? unless !v.nil? raise LintError, "rack.input#read(nil) returned nil on EOF" end end v end ## * +each+ must be called without arguments and only yield Strings. def each(*args) raise LintError, "rack.input#each called with arguments" unless args.size == 0 @input.each { |line| unless line.kind_of? String raise LintError, "rack.input#each didn't yield a String" end yield line } end ## * +close+ can be called on the input stream to indicate that the ## any remaining input is not needed. def close(*args) @input.close(*args) end end ## ## === The Error Stream ## def check_error(error) ## The error stream must respond to +puts+, +write+ and +flush+. [:puts, :write, :flush].each { |method| unless error.respond_to? method raise LintError, "rack.error #{error} does not respond to ##{method}" end } end class ErrorWrapper def initialize(error) @error = error end ## * +puts+ must be called with a single argument that responds to +to_s+. def puts(str) @error.puts str end ## * +write+ must be called with a single argument that is a String. def write(str) raise LintError, "rack.errors#write not called with a String" unless str.kind_of? String @error.write str end ## * +flush+ must be called without arguments and must be called ## in order to make the error appear for sure. def flush @error.flush end ## * +close+ must never be called on the error stream. def close(*args) raise LintError, "rack.errors#close must not be called" end end ## ## === Hijacking ## ## The hijacking interfaces provides a means for an application to take ## control of the HTTP connection. There are two distinct hijack ## interfaces: full hijacking where the application takes over the raw ## connection, and partial hijacking where the application takes over ## just the response body stream. In both cases, the application is ## responsible for closing the hijacked stream. ## ## Full hijacking only works with HTTP/1. Partial hijacking is functionally ## equivalent to streaming bodies, and is still optionally supported for ## backwards compatibility with older Rack versions. ## ## ==== Full Hijack ## ## Full hijack is used to completely take over an HTTP/1 connection. It ## occurs before any headers are written and causes the request to ## ignores any response generated by the application. ## ## It is intended to be used when applications need access to raw HTTP/1 ## connection. ## def check_hijack(env) ## If +rack.hijack+ is present in +env+, it must respond to +call+ if original_hijack = env[RACK_HIJACK] raise LintError, "rack.hijack must respond to call" unless original_hijack.respond_to?(:call) env[RACK_HIJACK] = proc do io = original_hijack.call ## and return an +IO+ instance which can be used to read and write ## to the underlying connection using HTTP/1 semantics and ## formatting. raise LintError, "rack.hijack must return an IO instance" unless io.is_a?(IO) io end end end ## ## ==== Partial Hijack ## ## Partial hijack is used for bi-directional streaming of the request and ## response body. It occurs after the status and headers are written by ## the server and causes the server to ignore the Body of the response. ## ## It is intended to be used when applications need bi-directional ## streaming. ## def check_hijack_response(headers, env) ## If +rack.hijack?+ is present in +env+ and truthy, if env[RACK_IS_HIJACK] ## an application may set the special response header +rack.hijack+ if original_hijack = headers[RACK_HIJACK] ## to an object that responds to +call+, unless original_hijack.respond_to?(:call) raise LintError, 'rack.hijack header must respond to #call' end ## accepting a +stream+ argument. return proc do |io| original_hijack.call StreamWrapper.new(io) end end ## ## After the response status and headers have been sent, this hijack ## callback will be invoked with a +stream+ argument which follows the ## same interface as outlined in "Streaming Body". Servers must ## ignore the +body+ part of the response tuple when the ## +rack.hijack+ response header is present. Using an empty +Array+ ## instance is recommended. else ## ## The special response header +rack.hijack+ must only be set ## if the request +env+ has a truthy +rack.hijack?+. if headers.key?(RACK_HIJACK) raise LintError, 'rack.hijack header must not be present if server does not support hijacking' end end nil end ## == The Response ## ## === The Status ## def check_status(status) ## This is an HTTP status. It must be an Integer greater than or equal to ## 100. unless status.is_a?(Integer) && status >= 100 raise LintError, "Status must be an Integer >=100" end end ## ## === The Headers ## def check_headers(headers) ## The headers must be a unfrozen Hash. unless headers.kind_of?(Hash) raise LintError, "headers object should be a hash, but isn't (got #{headers.class} as headers)" end if headers.frozen? raise LintError, "headers object should not be frozen, but is" end headers.each do |key, value| ## The header keys must be Strings. unless key.kind_of? String raise LintError, "header key must be a string, was #{key.class}" end ## Special headers starting "rack." are for communicating with the ## server, and must not be sent back to the client. next if key.start_with?("rack.") ## The header must not contain a +Status+ key. raise LintError, "header must not contain status" if key == "status" ## Header keys must conform to RFC7230 token specification, i.e. cannot ## contain non-printable ASCII, DQUOTE or "(),/:;<=>?@[\]{}". raise LintError, "invalid header name: #{key}" if key =~ /[\(\),\/:;<=>\?@\[\\\]{}[:cntrl:]]/ ## Header keys must not contain uppercase ASCII characters (A-Z). raise LintError, "uppercase character in header name: #{key}" if key =~ /[A-Z]/ ## Header values must be either a String instance, if value.kind_of?(String) check_header_value(key, value) elsif value.kind_of?(Array) ## or an Array of String instances, value.each{|value| check_header_value(key, value)} else raise LintError, "a header value must be a String or Array of Strings, but the value of '#{key}' is a #{value.class}" end end end def check_header_value(key, value) ## such that each String instance must not contain characters below 037. if value =~ /[\000-\037]/ raise LintError, "invalid header value #{key}: #{value.inspect}" end end ## ## === The content-type ## def check_content_type(status, headers) headers.each { |key, value| ## There must not be a content-type header key when the +Status+ is 1xx, ## 204, or 304. if key == "content-type" if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key? status.to_i raise LintError, "content-type header found in #{status} response, not allowed" end return end } end ## ## === The content-length ## def check_content_length(status, headers) headers.each { |key, value| if key == 'content-length' ## There must not be a content-length header key when the ## +Status+ is 1xx, 204, or 304. if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key? status.to_i raise LintError, "content-length header found in #{status} response, not allowed" end @content_length = value end } end def verify_content_length(size) if @head_request unless size == 0 raise LintError, "Response body was given for HEAD request, but should be empty" end elsif @content_length unless @content_length == size.to_s raise LintError, "content-length header was #{@content_length}, but should be #{size}" end end end ## ## === The Body ## ## The Body is typically an +Array+ of +String+ instances, an enumerable ## that yields +String+ instances, a +Proc+ instance, or a File-like ## object. ## ## The Body must respond to +each+ or +call+. It may optionally respond ## to +to_path+ or +to_ary+. A Body that responds to +each+ is considered ## to be an Enumerable Body. A Body that responds to +call+ is considered ## to be a Streaming Body. ## ## A Body that responds to both +each+ and +call+ must be treated as an ## Enumerable Body, not a Streaming Body. If it responds to +each+, you ## must call +each+ and not +call+. If the Body doesn't respond to ## +each+, then you can assume it responds to +call+. ## ## The Body must either be consumed or returned. The Body is consumed by ## optionally calling either +each+ or +call+. ## Then, if the Body responds to +close+, it must be called to release ## any resources associated with the generation of the body. ## In other words, +close+ must always be called at least once; typically ## after the web server has sent the response to the client, but also in ## cases where the Rack application makes internal/virtual requests and ## discards the response. ## def close ## ## After calling +close+, the Body is considered closed and should not ## be consumed again. @closed = true ## If the original Body is replaced by a new Body, the new Body must ## also consume the original Body by calling +close+ if possible. @body.close if @body.respond_to?(:close) index = @lint.index(self) unless @env['rack.lint'][0..index].all? {|lint| lint.instance_variable_get(:@closed)} raise LintError, "Body has not been closed" end end def verify_to_path ## ## If the Body responds to +to_path+, it must return a +String+ ## path for the local file system whose contents are identical ## to that produced by calling +each+; this may be used by the ## server as an alternative, possibly more efficient way to ## transport the response. The +to_path+ method does not consume ## the body. if @body.respond_to?(:to_path) unless ::File.exist? @body.to_path raise LintError, "The file identified by body.to_path does not exist" end end end ## ## ==== Enumerable Body ## def each ## The Enumerable Body must respond to +each+. raise LintError, "Enumerable Body must respond to each" unless @body.respond_to?(:each) ## It must only be called once. raise LintError, "Response body must only be invoked once (#{@invoked})" unless @invoked.nil? ## It must not be called after being closed. raise LintError, "Response body is already closed" if @closed @invoked = :each @body.each do |chunk| ## and must only yield String values. unless chunk.kind_of? String raise LintError, "Body yielded non-string value #{chunk.inspect}" end ## ## The Body itself should not be an instance of String, as this will ## break in Ruby 1.9. ## ## Middleware must not call +each+ directly on the Body. ## Instead, middleware can return a new Body that calls +each+ on the ## original Body, yielding at least once per iteration. if @lint[0] == self @env['rack.lint.body_iteration'] += 1 else if (@env['rack.lint.body_iteration'] -= 1) > 0 raise LintError, "New body must yield at least once per iteration of old body" end end @size += chunk.bytesize yield chunk end verify_content_length(@size) verify_to_path end BODY_METHODS = {to_ary: true, each: true, call: true, to_path: true} def to_path @body.to_path end def respond_to?(name, *) if BODY_METHODS.key?(name) @body.respond_to?(name) else super end end ## ## If the Body responds to +to_ary+, it must return an +Array+ whose ## contents are identical to that produced by calling +each+. ## Middleware may call +to_ary+ directly on the Body and return a new ## Body in its place. In other words, middleware can only process the ## Body directly if it responds to +to_ary+. If the Body responds to both ## +to_ary+ and +close+, its implementation of +to_ary+ must call ## +close+. def to_ary @body.to_ary.tap do |content| unless content == @body.enum_for.to_a raise LintError, "#to_ary not identical to contents produced by calling #each" end end ensure close end ## ## ==== Streaming Body ## def call(stream) ## The Streaming Body must respond to +call+. raise LintError, "Streaming Body must respond to call" unless @body.respond_to?(:call) ## It must only be called once. raise LintError, "Response body must only be invoked once (#{@invoked})" unless @invoked.nil? ## It must not be called after being closed. raise LintError, "Response body is already closed" if @closed @invoked = :call ## It takes a +stream+ argument. ## ## The +stream+ argument must implement: ## read, write, <<, flush, close, close_read, close_write, closed? ## @body.call(StreamWrapper.new(stream)) end class StreamWrapper extend Forwardable ## The semantics of these IO methods must be a best effort match to ## those of a normal Ruby IO or Socket object, using standard arguments ## and raising standard exceptions. Servers are encouraged to simply ## pass on real IO objects, although it is recognized that this approach ## is not directly compatible with HTTP/2. REQUIRED_METHODS = [ :read, :write, :<<, :flush, :close, :close_read, :close_write, :closed? ] def_delegators :@stream, *REQUIRED_METHODS def initialize(stream) @stream = stream REQUIRED_METHODS.each do |method_name| raise LintError, "Stream must respond to #{method_name}" unless stream.respond_to?(method_name) end end end # :startdoc: end end end ## ## == Thanks ## Some parts of this specification are adopted from {PEP 333 – Python Web Server Gateway Interface v1.0}[https://peps.python.org/pep-0333/] ## I'd like to thank everyone involved in that effort. PK ]|| +gems/rack-3.0.8/lib/rack/conditional_get.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' require_relative 'body_proxy' module Rack # Middleware that enables conditional GET using if-none-match and # if-modified-since. The application should set either or both of the # last-modified or etag response headers according to RFC 2616. When # either of the conditions is met, the response body is set to be zero # length and the response status is set to 304 Not Modified. # # Applications that defer response body generation until the body's each # message is received will avoid response body generation completely when # a conditional GET matches. # # Adapted from Michael Klishin's Merb implementation: # https://github.com/wycats/merb/blob/master/merb-core/lib/merb-core/rack/middleware/conditional_get.rb class ConditionalGet def initialize(app) @app = app end # Return empty 304 response if the response has not been # modified since the last request. def call(env) case env[REQUEST_METHOD] when "GET", "HEAD" status, headers, body = response = @app.call(env) if status == 200 && fresh?(env, headers) response[0] = 304 headers.delete(CONTENT_TYPE) headers.delete(CONTENT_LENGTH) response[2] = Rack::BodyProxy.new([]) do body.close if body.respond_to?(:close) end end response else @app.call(env) end end private # Return whether the response has not been modified since the # last request. def fresh?(env, headers) # if-none-match has priority over if-modified-since per RFC 7232 if none_match = env['HTTP_IF_NONE_MATCH'] etag_matches?(none_match, headers) elsif (modified_since = env['HTTP_IF_MODIFIED_SINCE']) && (modified_since = to_rfc2822(modified_since)) modified_since?(modified_since, headers) end end # Whether the etag response header matches the if-none-match request header. # If so, the request has not been modified. def etag_matches?(none_match, headers) headers[ETAG] == none_match end # Whether the last-modified response header matches the if-modified-since # request header. If so, the request has not been modified. def modified_since?(modified_since, headers) last_modified = to_rfc2822(headers['last-modified']) and modified_since >= last_modified end # Return a Time object for the given string (which should be in RFC2822 # format), or nil if the string cannot be parsed. def to_rfc2822(since) # shortest possible valid date is the obsolete: 1 Nov 97 09:55 A # anything shorter is invalid, this avoids exceptions for common cases # most common being the empty string if since && since.length >= 16 # NOTE: there is no trivial way to write this in a non exception way # _rfc2822 returns a hash but is not that usable Time.rfc2822(since) rescue nil end end end end PK ]N4q(gems/rack-3.0.8/lib/rack/content_type.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' module Rack # Sets the content-type header on responses which don't have one. # # Builder Usage: # use Rack::ContentType, "text/plain" # # When no content type argument is provided, "text/html" is the # default. class ContentType include Rack::Utils def initialize(app, content_type = "text/html") @app = app @content_type = content_type end def call(env) status, headers, _ = response = @app.call(env) unless STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) headers[CONTENT_TYPE] ||= @content_type end response end end end PK ]dNN'gems/rack-3.0.8/lib/rack/show_status.rbnu[# frozen_string_literal: true require 'erb' require_relative 'constants' require_relative 'utils' require_relative 'request' require_relative 'body_proxy' module Rack # Rack::ShowStatus catches all empty responses and replaces them # with a site explaining the error. # # Additional details can be put into rack.showstatus.detail # and will be shown as HTML. If such details exist, the error page # is always rendered, even if the reply was not empty. class ShowStatus def initialize(app) @app = app @template = ERB.new(TEMPLATE) end def call(env) status, headers, body = response = @app.call(env) empty = headers[CONTENT_LENGTH].to_i <= 0 # client or server error, or explicit message if (status.to_i >= 400 && empty) || env[RACK_SHOWSTATUS_DETAIL] # This double assignment is to prevent an "unused variable" warning. # Yes, it is dumb, but I don't like Ruby yelling at me. req = req = Rack::Request.new(env) message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s # This double assignment is to prevent an "unused variable" warning. # Yes, it is dumb, but I don't like Ruby yelling at me. detail = detail = env[RACK_SHOWSTATUS_DETAIL] || message html = @template.result(binding) size = html.bytesize response[2] = Rack::BodyProxy.new([html]) do body.close if body.respond_to?(:close) end headers[CONTENT_TYPE] = "text/html" headers[CONTENT_LENGTH] = size.to_s end response end def h(obj) # :nodoc: case obj when String Utils.escape_html(obj) else Utils.escape_html(obj.inspect) end end # :stopdoc: # adapted from Django # Copyright (c) Django Software Foundation and individual contributors. # Used under the modified BSD license: # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 TEMPLATE = <<'HTML' <%=h message %> at <%=h req.script_name + req.path_info %>

    <%=h message %> (<%= status.to_i %>)

    Request Method: <%=h req.request_method %>
    Request URL: <%=h req.url %>

    <%=h detail %>

    You're seeing this error because you use Rack::ShowStatus.

    HTML # :startdoc: end end PK ]?6/ gems/rack-3.0.8/lib/rack/mime.rbnu[# frozen_string_literal: true module Rack module Mime # Returns String with mime type if found, otherwise use +fallback+. # +ext+ should be filename extension in the '.ext' format that # File.extname(file) returns. # +fallback+ may be any object # # Also see the documentation for MIME_TYPES # # Usage: # Rack::Mime.mime_type('.foo') # # This is a shortcut for: # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream') def mime_type(ext, fallback = 'application/octet-stream') MIME_TYPES.fetch(ext.to_s.downcase, fallback) end module_function :mime_type # Returns true if the given value is a mime match for the given mime match # specification, false otherwise. # # Rack::Mime.match?('text/html', 'text/*') => true # Rack::Mime.match?('text/plain', '*') => true # Rack::Mime.match?('text/html', 'application/json') => false def match?(value, matcher) v1, v2 = value.split('/', 2) m1, m2 = matcher.split('/', 2) (m1 == '*' || v1 == m1) && (m2.nil? || m2 == '*' || m2 == v2) end module_function :match? # List of most common mime-types, selected various sources # according to their usefulness in a webserving scope for Ruby # users. # # To amend this list with your local mime.types list you can use: # # require 'webrick/httputils' # list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types') # Rack::Mime::MIME_TYPES.merge!(list) # # N.B. On Ubuntu the mime.types file does not include the leading period, so # users may need to modify the data before merging into the hash. MIME_TYPES = { ".123" => "application/vnd.lotus-1-2-3", ".3dml" => "text/vnd.in3d.3dml", ".3g2" => "video/3gpp2", ".3gp" => "video/3gpp", ".a" => "application/octet-stream", ".acc" => "application/vnd.americandynamics.acc", ".ace" => "application/x-ace-compressed", ".acu" => "application/vnd.acucobol", ".aep" => "application/vnd.audiograph", ".afp" => "application/vnd.ibm.modcap", ".ai" => "application/postscript", ".aif" => "audio/x-aiff", ".aiff" => "audio/x-aiff", ".ami" => "application/vnd.amiga.ami", ".apng" => "image/apng", ".appcache" => "text/cache-manifest", ".apr" => "application/vnd.lotus-approach", ".asc" => "application/pgp-signature", ".asf" => "video/x-ms-asf", ".asm" => "text/x-asm", ".aso" => "application/vnd.accpac.simply.aso", ".asx" => "video/x-ms-asf", ".atc" => "application/vnd.acucorp", ".atom" => "application/atom+xml", ".atomcat" => "application/atomcat+xml", ".atomsvc" => "application/atomsvc+xml", ".atx" => "application/vnd.antix.game-component", ".au" => "audio/basic", ".avi" => "video/x-msvideo", ".avif" => "image/avif", ".bat" => "application/x-msdownload", ".bcpio" => "application/x-bcpio", ".bdm" => "application/vnd.syncml.dm+wbxml", ".bh2" => "application/vnd.fujitsu.oasysprs", ".bin" => "application/octet-stream", ".bmi" => "application/vnd.bmi", ".bmp" => "image/bmp", ".box" => "application/vnd.previewsystems.box", ".btif" => "image/prs.btif", ".bz" => "application/x-bzip", ".bz2" => "application/x-bzip2", ".c" => "text/x-c", ".c4g" => "application/vnd.clonk.c4group", ".cab" => "application/vnd.ms-cab-compressed", ".cc" => "text/x-c", ".ccxml" => "application/ccxml+xml", ".cdbcmsg" => "application/vnd.contact.cmsg", ".cdkey" => "application/vnd.mediastation.cdkey", ".cdx" => "chemical/x-cdx", ".cdxml" => "application/vnd.chemdraw+xml", ".cdy" => "application/vnd.cinderella", ".cer" => "application/pkix-cert", ".cgm" => "image/cgm", ".chat" => "application/x-chat", ".chm" => "application/vnd.ms-htmlhelp", ".chrt" => "application/vnd.kde.kchart", ".cif" => "chemical/x-cif", ".cii" => "application/vnd.anser-web-certificate-issue-initiation", ".cil" => "application/vnd.ms-artgalry", ".cla" => "application/vnd.claymore", ".class" => "application/octet-stream", ".clkk" => "application/vnd.crick.clicker.keyboard", ".clkp" => "application/vnd.crick.clicker.palette", ".clkt" => "application/vnd.crick.clicker.template", ".clkw" => "application/vnd.crick.clicker.wordbank", ".clkx" => "application/vnd.crick.clicker", ".clp" => "application/x-msclip", ".cmc" => "application/vnd.cosmocaller", ".cmdf" => "chemical/x-cmdf", ".cml" => "chemical/x-cml", ".cmp" => "application/vnd.yellowriver-custom-menu", ".cmx" => "image/x-cmx", ".com" => "application/x-msdownload", ".conf" => "text/plain", ".cpio" => "application/x-cpio", ".cpp" => "text/x-c", ".cpt" => "application/mac-compactpro", ".crd" => "application/x-mscardfile", ".crl" => "application/pkix-crl", ".crt" => "application/x-x509-ca-cert", ".csh" => "application/x-csh", ".csml" => "chemical/x-csml", ".csp" => "application/vnd.commonspace", ".css" => "text/css", ".csv" => "text/csv", ".curl" => "application/vnd.curl", ".cww" => "application/prs.cww", ".cxx" => "text/x-c", ".daf" => "application/vnd.mobius.daf", ".davmount" => "application/davmount+xml", ".dcr" => "application/x-director", ".dd2" => "application/vnd.oma.dd2+xml", ".ddd" => "application/vnd.fujixerox.ddd", ".deb" => "application/x-debian-package", ".der" => "application/x-x509-ca-cert", ".dfac" => "application/vnd.dreamfactory", ".diff" => "text/x-diff", ".dis" => "application/vnd.mobius.dis", ".djv" => "image/vnd.djvu", ".djvu" => "image/vnd.djvu", ".dll" => "application/x-msdownload", ".dmg" => "application/octet-stream", ".dna" => "application/vnd.dna", ".doc" => "application/msword", ".docm" => "application/vnd.ms-word.document.macroEnabled.12", ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".dot" => "application/msword", ".dotm" => "application/vnd.ms-word.template.macroEnabled.12", ".dotx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template", ".dp" => "application/vnd.osgi.dp", ".dpg" => "application/vnd.dpgraph", ".dsc" => "text/prs.lines.tag", ".dtd" => "application/xml-dtd", ".dts" => "audio/vnd.dts", ".dtshd" => "audio/vnd.dts.hd", ".dv" => "video/x-dv", ".dvi" => "application/x-dvi", ".dwf" => "model/vnd.dwf", ".dwg" => "image/vnd.dwg", ".dxf" => "image/vnd.dxf", ".dxp" => "application/vnd.spotfire.dxp", ".ear" => "application/java-archive", ".ecelp4800" => "audio/vnd.nuera.ecelp4800", ".ecelp7470" => "audio/vnd.nuera.ecelp7470", ".ecelp9600" => "audio/vnd.nuera.ecelp9600", ".ecma" => "application/ecmascript", ".edm" => "application/vnd.novadigm.edm", ".edx" => "application/vnd.novadigm.edx", ".efif" => "application/vnd.picsel", ".ei6" => "application/vnd.pg.osasli", ".eml" => "message/rfc822", ".eol" => "audio/vnd.digital-winds", ".eot" => "application/vnd.ms-fontobject", ".eps" => "application/postscript", ".es3" => "application/vnd.eszigno3+xml", ".esf" => "application/vnd.epson.esf", ".etx" => "text/x-setext", ".exe" => "application/x-msdownload", ".ext" => "application/vnd.novadigm.ext", ".ez" => "application/andrew-inset", ".ez2" => "application/vnd.ezpix-album", ".ez3" => "application/vnd.ezpix-package", ".f" => "text/x-fortran", ".f77" => "text/x-fortran", ".f90" => "text/x-fortran", ".fbs" => "image/vnd.fastbidsheet", ".fdf" => "application/vnd.fdf", ".fe_launch" => "application/vnd.denovo.fcselayout-link", ".fg5" => "application/vnd.fujitsu.oasysgp", ".fli" => "video/x-fli", ".flif" => "image/flif", ".flo" => "application/vnd.micrografx.flo", ".flv" => "video/x-flv", ".flw" => "application/vnd.kde.kivio", ".flx" => "text/vnd.fmi.flexstor", ".fly" => "text/vnd.fly", ".fm" => "application/vnd.framemaker", ".fnc" => "application/vnd.frogans.fnc", ".for" => "text/x-fortran", ".fpx" => "image/vnd.fpx", ".fsc" => "application/vnd.fsc.weblaunch", ".fst" => "image/vnd.fst", ".ftc" => "application/vnd.fluxtime.clip", ".fti" => "application/vnd.anser-web-funds-transfer-initiation", ".fvt" => "video/vnd.fvt", ".fzs" => "application/vnd.fuzzysheet", ".g3" => "image/g3fax", ".gac" => "application/vnd.groove-account", ".gdl" => "model/vnd.gdl", ".gem" => "application/octet-stream", ".gemspec" => "text/x-script.ruby", ".ghf" => "application/vnd.groove-help", ".gif" => "image/gif", ".gim" => "application/vnd.groove-identity-message", ".gmx" => "application/vnd.gmx", ".gph" => "application/vnd.flographit", ".gqf" => "application/vnd.grafeq", ".gram" => "application/srgs", ".grv" => "application/vnd.groove-injector", ".grxml" => "application/srgs+xml", ".gtar" => "application/x-gtar", ".gtm" => "application/vnd.groove-tool-message", ".gtw" => "model/vnd.gtw", ".gv" => "text/vnd.graphviz", ".gz" => "application/x-gzip", ".h" => "text/x-c", ".h261" => "video/h261", ".h263" => "video/h263", ".h264" => "video/h264", ".hbci" => "application/vnd.hbci", ".hdf" => "application/x-hdf", ".heic" => "image/heic", ".heics" => "image/heic-sequence", ".heif" => "image/heif", ".heifs" => "image/heif-sequence", ".hh" => "text/x-c", ".hlp" => "application/winhlp", ".hpgl" => "application/vnd.hp-hpgl", ".hpid" => "application/vnd.hp-hpid", ".hps" => "application/vnd.hp-hps", ".hqx" => "application/mac-binhex40", ".htc" => "text/x-component", ".htke" => "application/vnd.kenameaapp", ".htm" => "text/html", ".html" => "text/html", ".hvd" => "application/vnd.yamaha.hv-dic", ".hvp" => "application/vnd.yamaha.hv-voice", ".hvs" => "application/vnd.yamaha.hv-script", ".icc" => "application/vnd.iccprofile", ".ice" => "x-conference/x-cooltalk", ".ico" => "image/vnd.microsoft.icon", ".ics" => "text/calendar", ".ief" => "image/ief", ".ifb" => "text/calendar", ".ifm" => "application/vnd.shana.informed.formdata", ".igl" => "application/vnd.igloader", ".igs" => "model/iges", ".igx" => "application/vnd.micrografx.igx", ".iif" => "application/vnd.shana.informed.interchange", ".imp" => "application/vnd.accpac.simply.imp", ".ims" => "application/vnd.ms-ims", ".ipk" => "application/vnd.shana.informed.package", ".irm" => "application/vnd.ibm.rights-management", ".irp" => "application/vnd.irepository.package+xml", ".iso" => "application/octet-stream", ".itp" => "application/vnd.shana.informed.formtemplate", ".ivp" => "application/vnd.immervision-ivp", ".ivu" => "application/vnd.immervision-ivu", ".jad" => "text/vnd.sun.j2me.app-descriptor", ".jam" => "application/vnd.jam", ".jar" => "application/java-archive", ".java" => "text/x-java-source", ".jisp" => "application/vnd.jisp", ".jlt" => "application/vnd.hp-jlyt", ".jnlp" => "application/x-java-jnlp-file", ".joda" => "application/vnd.joost.joda-archive", ".jp2" => "image/jp2", ".jpeg" => "image/jpeg", ".jpg" => "image/jpeg", ".jpgv" => "video/jpeg", ".jpm" => "video/jpm", ".js" => "application/javascript", ".json" => "application/json", ".karbon" => "application/vnd.kde.karbon", ".kfo" => "application/vnd.kde.kformula", ".kia" => "application/vnd.kidspiration", ".kml" => "application/vnd.google-earth.kml+xml", ".kmz" => "application/vnd.google-earth.kmz", ".kne" => "application/vnd.kinar", ".kon" => "application/vnd.kde.kontour", ".kpr" => "application/vnd.kde.kpresenter", ".ksp" => "application/vnd.kde.kspread", ".ktz" => "application/vnd.kahootz", ".kwd" => "application/vnd.kde.kword", ".latex" => "application/x-latex", ".lbd" => "application/vnd.llamagraphics.life-balance.desktop", ".lbe" => "application/vnd.llamagraphics.life-balance.exchange+xml", ".les" => "application/vnd.hhe.lesson-player", ".link66" => "application/vnd.route66.link66+xml", ".log" => "text/plain", ".lostxml" => "application/lost+xml", ".lrm" => "application/vnd.ms-lrm", ".ltf" => "application/vnd.frogans.ltf", ".lvp" => "audio/vnd.lucent.voice", ".lwp" => "application/vnd.lotus-wordpro", ".m3u" => "audio/x-mpegurl", ".m3u8" => "application/x-mpegurl", ".m4a" => "audio/mp4a-latm", ".m4v" => "video/mp4", ".ma" => "application/mathematica", ".mag" => "application/vnd.ecowin.chart", ".man" => "text/troff", ".manifest" => "text/cache-manifest", ".mathml" => "application/mathml+xml", ".mbk" => "application/vnd.mobius.mbk", ".mbox" => "application/mbox", ".mc1" => "application/vnd.medcalcdata", ".mcd" => "application/vnd.mcd", ".mdb" => "application/x-msaccess", ".mdi" => "image/vnd.ms-modi", ".mdoc" => "text/troff", ".me" => "text/troff", ".mfm" => "application/vnd.mfmp", ".mgz" => "application/vnd.proteus.magazine", ".mid" => "audio/midi", ".midi" => "audio/midi", ".mif" => "application/vnd.mif", ".mime" => "message/rfc822", ".mj2" => "video/mj2", ".mlp" => "application/vnd.dolby.mlp", ".mmd" => "application/vnd.chipnuts.karaoke-mmd", ".mmf" => "application/vnd.smaf", ".mml" => "application/mathml+xml", ".mmr" => "image/vnd.fujixerox.edmics-mmr", ".mng" => "video/x-mng", ".mny" => "application/x-msmoney", ".mov" => "video/quicktime", ".movie" => "video/x-sgi-movie", ".mp3" => "audio/mpeg", ".mp4" => "video/mp4", ".mp4a" => "audio/mp4", ".mp4s" => "application/mp4", ".mp4v" => "video/mp4", ".mpc" => "application/vnd.mophun.certificate", ".mpd" => "application/dash+xml", ".mpeg" => "video/mpeg", ".mpg" => "video/mpeg", ".mpga" => "audio/mpeg", ".mpkg" => "application/vnd.apple.installer+xml", ".mpm" => "application/vnd.blueice.multipass", ".mpn" => "application/vnd.mophun.application", ".mpp" => "application/vnd.ms-project", ".mpy" => "application/vnd.ibm.minipay", ".mqy" => "application/vnd.mobius.mqy", ".mrc" => "application/marc", ".ms" => "text/troff", ".mscml" => "application/mediaservercontrol+xml", ".mseq" => "application/vnd.mseq", ".msf" => "application/vnd.epson.msf", ".msh" => "model/mesh", ".msi" => "application/x-msdownload", ".msl" => "application/vnd.mobius.msl", ".msty" => "application/vnd.muvee.style", ".mts" => "model/vnd.mts", ".mus" => "application/vnd.musician", ".mvb" => "application/x-msmediaview", ".mwf" => "application/vnd.mfer", ".mxf" => "application/mxf", ".mxl" => "application/vnd.recordare.musicxml", ".mxml" => "application/xv+xml", ".mxs" => "application/vnd.triscape.mxs", ".mxu" => "video/vnd.mpegurl", ".n" => "application/vnd.nokia.n-gage.symbian.install", ".nc" => "application/x-netcdf", ".ngdat" => "application/vnd.nokia.n-gage.data", ".nlu" => "application/vnd.neurolanguage.nlu", ".nml" => "application/vnd.enliven", ".nnd" => "application/vnd.noblenet-directory", ".nns" => "application/vnd.noblenet-sealer", ".nnw" => "application/vnd.noblenet-web", ".npx" => "image/vnd.net-fpx", ".nsf" => "application/vnd.lotus-notes", ".oa2" => "application/vnd.fujitsu.oasys2", ".oa3" => "application/vnd.fujitsu.oasys3", ".oas" => "application/vnd.fujitsu.oasys", ".obd" => "application/x-msbinder", ".oda" => "application/oda", ".odc" => "application/vnd.oasis.opendocument.chart", ".odf" => "application/vnd.oasis.opendocument.formula", ".odg" => "application/vnd.oasis.opendocument.graphics", ".odi" => "application/vnd.oasis.opendocument.image", ".odp" => "application/vnd.oasis.opendocument.presentation", ".ods" => "application/vnd.oasis.opendocument.spreadsheet", ".odt" => "application/vnd.oasis.opendocument.text", ".oga" => "audio/ogg", ".ogg" => "application/ogg", ".ogv" => "video/ogg", ".ogx" => "application/ogg", ".org" => "application/vnd.lotus-organizer", ".otc" => "application/vnd.oasis.opendocument.chart-template", ".otf" => "application/vnd.oasis.opendocument.formula-template", ".otg" => "application/vnd.oasis.opendocument.graphics-template", ".oth" => "application/vnd.oasis.opendocument.text-web", ".oti" => "application/vnd.oasis.opendocument.image-template", ".otm" => "application/vnd.oasis.opendocument.text-master", ".ots" => "application/vnd.oasis.opendocument.spreadsheet-template", ".ott" => "application/vnd.oasis.opendocument.text-template", ".oxt" => "application/vnd.openofficeorg.extension", ".p" => "text/x-pascal", ".p10" => "application/pkcs10", ".p12" => "application/x-pkcs12", ".p7b" => "application/x-pkcs7-certificates", ".p7m" => "application/pkcs7-mime", ".p7r" => "application/x-pkcs7-certreqresp", ".p7s" => "application/pkcs7-signature", ".pas" => "text/x-pascal", ".pbd" => "application/vnd.powerbuilder6", ".pbm" => "image/x-portable-bitmap", ".pcl" => "application/vnd.hp-pcl", ".pclxl" => "application/vnd.hp-pclxl", ".pcx" => "image/x-pcx", ".pdb" => "chemical/x-pdb", ".pdf" => "application/pdf", ".pem" => "application/x-x509-ca-cert", ".pfr" => "application/font-tdpfr", ".pgm" => "image/x-portable-graymap", ".pgn" => "application/x-chess-pgn", ".pgp" => "application/pgp-encrypted", ".pic" => "image/x-pict", ".pict" => "image/pict", ".pkg" => "application/octet-stream", ".pki" => "application/pkixcmp", ".pkipath" => "application/pkix-pkipath", ".pl" => "text/x-script.perl", ".plb" => "application/vnd.3gpp.pic-bw-large", ".plc" => "application/vnd.mobius.plc", ".plf" => "application/vnd.pocketlearn", ".pls" => "application/pls+xml", ".pm" => "text/x-script.perl-module", ".pml" => "application/vnd.ctc-posml", ".png" => "image/png", ".pnm" => "image/x-portable-anymap", ".pntg" => "image/x-macpaint", ".portpkg" => "application/vnd.macports.portpkg", ".pot" => "application/vnd.ms-powerpoint", ".potm" => "application/vnd.ms-powerpoint.template.macroEnabled.12", ".potx" => "application/vnd.openxmlformats-officedocument.presentationml.template", ".ppa" => "application/vnd.ms-powerpoint", ".ppam" => "application/vnd.ms-powerpoint.addin.macroEnabled.12", ".ppd" => "application/vnd.cups-ppd", ".ppm" => "image/x-portable-pixmap", ".pps" => "application/vnd.ms-powerpoint", ".ppsm" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", ".ppsx" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow", ".ppt" => "application/vnd.ms-powerpoint", ".pptm" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12", ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", ".prc" => "application/vnd.palm", ".pre" => "application/vnd.lotus-freelance", ".prf" => "application/pics-rules", ".ps" => "application/postscript", ".psb" => "application/vnd.3gpp.pic-bw-small", ".psd" => "image/vnd.adobe.photoshop", ".ptid" => "application/vnd.pvi.ptid1", ".pub" => "application/x-mspublisher", ".pvb" => "application/vnd.3gpp.pic-bw-var", ".pwn" => "application/vnd.3m.post-it-notes", ".py" => "text/x-script.python", ".pya" => "audio/vnd.ms-playready.media.pya", ".pyv" => "video/vnd.ms-playready.media.pyv", ".qam" => "application/vnd.epson.quickanime", ".qbo" => "application/vnd.intu.qbo", ".qfx" => "application/vnd.intu.qfx", ".qps" => "application/vnd.publishare-delta-tree", ".qt" => "video/quicktime", ".qtif" => "image/x-quicktime", ".qxd" => "application/vnd.quark.quarkxpress", ".ra" => "audio/x-pn-realaudio", ".rake" => "text/x-script.ruby", ".ram" => "audio/x-pn-realaudio", ".rar" => "application/x-rar-compressed", ".ras" => "image/x-cmu-raster", ".rb" => "text/x-script.ruby", ".rcprofile" => "application/vnd.ipunplugged.rcprofile", ".rdf" => "application/rdf+xml", ".rdz" => "application/vnd.data-vision.rdz", ".rep" => "application/vnd.businessobjects", ".rgb" => "image/x-rgb", ".rif" => "application/reginfo+xml", ".rl" => "application/resource-lists+xml", ".rlc" => "image/vnd.fujixerox.edmics-rlc", ".rld" => "application/resource-lists-diff+xml", ".rm" => "application/vnd.rn-realmedia", ".rmp" => "audio/x-pn-realaudio-plugin", ".rms" => "application/vnd.jcp.javame.midlet-rms", ".rnc" => "application/relax-ng-compact-syntax", ".roff" => "text/troff", ".rpm" => "application/x-redhat-package-manager", ".rpss" => "application/vnd.nokia.radio-presets", ".rpst" => "application/vnd.nokia.radio-preset", ".rq" => "application/sparql-query", ".rs" => "application/rls-services+xml", ".rsd" => "application/rsd+xml", ".rss" => "application/rss+xml", ".rtf" => "application/rtf", ".rtx" => "text/richtext", ".ru" => "text/x-script.ruby", ".s" => "text/x-asm", ".saf" => "application/vnd.yamaha.smaf-audio", ".sbml" => "application/sbml+xml", ".sc" => "application/vnd.ibm.secure-container", ".scd" => "application/x-msschedule", ".scm" => "application/vnd.lotus-screencam", ".scq" => "application/scvp-cv-request", ".scs" => "application/scvp-cv-response", ".sdkm" => "application/vnd.solent.sdkm+xml", ".sdp" => "application/sdp", ".see" => "application/vnd.seemail", ".sema" => "application/vnd.sema", ".semd" => "application/vnd.semd", ".semf" => "application/vnd.semf", ".setpay" => "application/set-payment-initiation", ".setreg" => "application/set-registration-initiation", ".sfd" => "application/vnd.hydrostatix.sof-data", ".sfs" => "application/vnd.spotfire.sfs", ".sgm" => "text/sgml", ".sgml" => "text/sgml", ".sh" => "application/x-sh", ".shar" => "application/x-shar", ".shf" => "application/shf+xml", ".sig" => "application/pgp-signature", ".sit" => "application/x-stuffit", ".sitx" => "application/x-stuffitx", ".skp" => "application/vnd.koan", ".slt" => "application/vnd.epson.salt", ".smi" => "application/smil+xml", ".snd" => "audio/basic", ".so" => "application/octet-stream", ".spf" => "application/vnd.yamaha.smaf-phrase", ".spl" => "application/x-futuresplash", ".spot" => "text/vnd.in3d.spot", ".spp" => "application/scvp-vp-response", ".spq" => "application/scvp-vp-request", ".src" => "application/x-wais-source", ".srt" => "text/srt", ".srx" => "application/sparql-results+xml", ".sse" => "application/vnd.kodak-descriptor", ".ssf" => "application/vnd.epson.ssf", ".ssml" => "application/ssml+xml", ".stf" => "application/vnd.wt.stf", ".stk" => "application/hyperstudio", ".str" => "application/vnd.pg.format", ".sus" => "application/vnd.sus-calendar", ".sv4cpio" => "application/x-sv4cpio", ".sv4crc" => "application/x-sv4crc", ".svd" => "application/vnd.svd", ".svg" => "image/svg+xml", ".svgz" => "image/svg+xml", ".swf" => "application/x-shockwave-flash", ".swi" => "application/vnd.arastra.swi", ".t" => "text/troff", ".tao" => "application/vnd.tao.intent-module-archive", ".tar" => "application/x-tar", ".tbz" => "application/x-bzip-compressed-tar", ".tcap" => "application/vnd.3gpp2.tcap", ".tcl" => "application/x-tcl", ".tex" => "application/x-tex", ".texi" => "application/x-texinfo", ".texinfo" => "application/x-texinfo", ".text" => "text/plain", ".tif" => "image/tiff", ".tiff" => "image/tiff", ".tmo" => "application/vnd.tmobile-livetv", ".torrent" => "application/x-bittorrent", ".tpl" => "application/vnd.groove-tool-template", ".tpt" => "application/vnd.trid.tpt", ".tr" => "text/troff", ".tra" => "application/vnd.trueapp", ".trm" => "application/x-msterminal", ".ts" => "video/mp2t", ".tsv" => "text/tab-separated-values", ".ttf" => "application/octet-stream", ".twd" => "application/vnd.simtech-mindmapper", ".txd" => "application/vnd.genomatix.tuxedo", ".txf" => "application/vnd.mobius.txf", ".txt" => "text/plain", ".ufd" => "application/vnd.ufdl", ".umj" => "application/vnd.umajin", ".unityweb" => "application/vnd.unity", ".uoml" => "application/vnd.uoml+xml", ".uri" => "text/uri-list", ".ustar" => "application/x-ustar", ".utz" => "application/vnd.uiq.theme", ".uu" => "text/x-uuencode", ".vcd" => "application/x-cdlink", ".vcf" => "text/x-vcard", ".vcg" => "application/vnd.groove-vcard", ".vcs" => "text/x-vcalendar", ".vcx" => "application/vnd.vcx", ".vis" => "application/vnd.visionary", ".viv" => "video/vnd.vivo", ".vrml" => "model/vrml", ".vsd" => "application/vnd.visio", ".vsf" => "application/vnd.vsf", ".vtt" => "text/vtt", ".vtu" => "model/vnd.vtu", ".vxml" => "application/voicexml+xml", ".war" => "application/java-archive", ".wasm" => "application/wasm", ".wav" => "audio/x-wav", ".wax" => "audio/x-ms-wax", ".wbmp" => "image/vnd.wap.wbmp", ".wbs" => "application/vnd.criticaltools.wbs+xml", ".wbxml" => "application/vnd.wap.wbxml", ".webm" => "video/webm", ".webp" => "image/webp", ".wm" => "video/x-ms-wm", ".wma" => "audio/x-ms-wma", ".wmd" => "application/x-ms-wmd", ".wmf" => "application/x-msmetafile", ".wml" => "text/vnd.wap.wml", ".wmlc" => "application/vnd.wap.wmlc", ".wmls" => "text/vnd.wap.wmlscript", ".wmlsc" => "application/vnd.wap.wmlscriptc", ".wmv" => "video/x-ms-wmv", ".wmx" => "video/x-ms-wmx", ".wmz" => "application/x-ms-wmz", ".woff" => "application/font-woff", ".woff2" => "application/font-woff2", ".wpd" => "application/vnd.wordperfect", ".wpl" => "application/vnd.ms-wpl", ".wps" => "application/vnd.ms-works", ".wqd" => "application/vnd.wqd", ".wri" => "application/x-mswrite", ".wrl" => "model/vrml", ".wsdl" => "application/wsdl+xml", ".wspolicy" => "application/wspolicy+xml", ".wtb" => "application/vnd.webturbo", ".wvx" => "video/x-ms-wvx", ".x3d" => "application/vnd.hzn-3d-crossword", ".xar" => "application/vnd.xara", ".xbd" => "application/vnd.fujixerox.docuworks.binder", ".xbm" => "image/x-xbitmap", ".xdm" => "application/vnd.syncml.dm+xml", ".xdp" => "application/vnd.adobe.xdp+xml", ".xdw" => "application/vnd.fujixerox.docuworks", ".xenc" => "application/xenc+xml", ".xer" => "application/patch-ops-error+xml", ".xfdf" => "application/vnd.adobe.xfdf", ".xfdl" => "application/vnd.xfdl", ".xhtml" => "application/xhtml+xml", ".xif" => "image/vnd.xiff", ".xla" => "application/vnd.ms-excel", ".xlam" => "application/vnd.ms-excel.addin.macroEnabled.12", ".xls" => "application/vnd.ms-excel", ".xlsb" => "application/vnd.ms-excel.sheet.binary.macroEnabled.12", ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".xlsm" => "application/vnd.ms-excel.sheet.macroEnabled.12", ".xlt" => "application/vnd.ms-excel", ".xltx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template", ".xml" => "application/xml", ".xo" => "application/vnd.olpc-sugar", ".xop" => "application/xop+xml", ".xpm" => "image/x-xpixmap", ".xpr" => "application/vnd.is-xpr", ".xps" => "application/vnd.ms-xpsdocument", ".xpw" => "application/vnd.intercon.formnet", ".xsl" => "application/xml", ".xslt" => "application/xslt+xml", ".xsm" => "application/vnd.syncml+xml", ".xspf" => "application/xspf+xml", ".xul" => "application/vnd.mozilla.xul+xml", ".xwd" => "image/x-xwindowdump", ".xyz" => "chemical/x-xyz", ".yaml" => "text/yaml", ".yml" => "text/yaml", ".zaz" => "application/vnd.zzazz.deck+xml", ".zip" => "application/zip", ".zmm" => "application/vnd.handheld-entertainment+xml", } end end PK ]i\"gems/rack-3.0.8/lib/rack/config.rbnu[# frozen_string_literal: true module Rack # Rack::Config modifies the environment using the block given during # initialization. # # Example: # use Rack::Config do |env| # env['my-key'] = 'some-value' # end class Config def initialize(app, &block) @app = app @block = block end def call(env) @block.call(env) @app.call(env) end end end PK ]Y  #gems/rack-3.0.8/lib/rack/cascade.rbnu[# frozen_string_literal: true require_relative 'constants' module Rack # Rack::Cascade tries a request on several apps, and returns the # first response that is not 404 or 405 (or in a list of configured # status codes). If all applications tried return one of the configured # status codes, return the last response. class Cascade # deprecated, no longer used NotFound = [404, { CONTENT_TYPE => "text/plain" }, []] # An array of applications to try in order. attr_reader :apps # Set the apps to send requests to, and what statuses result in # cascading. Arguments: # # apps: An enumerable of rack applications. # cascade_for: The statuses to use cascading for. If a response is received # from an app, the next app is tried. def initialize(apps, cascade_for = [404, 405]) @apps = [] apps.each { |app| add app } @cascade_for = {} [*cascade_for].each { |status| @cascade_for[status] = true } end # Call each app in order. If the responses uses a status that requires # cascading, try the next app. If all responses require cascading, # return the response from the last app. def call(env) return [404, { CONTENT_TYPE => "text/plain" }, []] if @apps.empty? result = nil last_body = nil @apps.each do |app| # The SPEC says that the body must be closed after it has been iterated # by the server, or if it is replaced by a middleware action. Cascade # replaces the body each time a cascade happens. It is assumed that nil # does not respond to close, otherwise the previous application body # will be closed. The final application body will not be closed, as it # will be passed to the server as a result. last_body.close if last_body.respond_to? :close result = app.call(env) return result unless @cascade_for.include?(result[0].to_i) last_body = result[2] end result end # Append an app to the list of apps to cascade. This app will # be tried last. def add(app) @apps << app end # Whether the given app is one of the apps to cascade to. def include?(app) @apps.include?(app) end alias_method :<<, :add end end PK ]_l'gems/rack-3.0.8/lib/rack/null_logger.rbnu[# frozen_string_literal: true require_relative 'constants' module Rack class NullLogger def initialize(app) @app = app end def call(env) env[RACK_LOGGER] = self @app.call(env) end def info(progname = nil, &block); end def debug(progname = nil, &block); end def warn(progname = nil, &block); end def error(progname = nil, &block); end def fatal(progname = nil, &block); end def unknown(progname = nil, &block); end def info? ; end def debug? ; end def warn? ; end def error? ; end def fatal? ; end def debug! ; end def error! ; end def fatal! ; end def info! ; end def warn! ; end def level ; end def progname ; end def datetime_format ; end def formatter ; end def sev_threshold ; end def level=(level); end def progname=(progname); end def datetime_format=(datetime_format); end def formatter=(formatter); end def sev_threshold=(sev_threshold); end def close ; end def add(severity, message = nil, progname = nil, &block); end def log(severity, message = nil, progname = nil, &block); end def <<(msg); end def reopen(logdev = nil); end end end PK ]/gems/ruby-lsapi-5.5/ext/lsapi/.sitearchdir.timenu[PK ]Y//(gems/ruby-lsapi-5.5/ext/lsapi/lsapilib.hnu[/* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _LSAPILIB_H_ #define _LSAPILIB_H_ #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif #include "lsapidef.h" #include #include #include struct LSAPI_key_value_pair { char * pKey; char * pValue; int keyLen; int valLen; }; struct lsapi_child_status; #define LSAPI_MAX_RESP_HEADERS 1000 typedef struct lsapi_request { int m_fdListen; int m_fd; long m_lLastActive; long m_lReqBegin; char * m_pReqBuf; int m_reqBufSize; char * m_pRespBuf; char * m_pRespBufEnd; char * m_pRespBufPos; char * m_pRespHeaderBuf; char * m_pRespHeaderBufEnd; char * m_pRespHeaderBufPos; struct lsapi_child_status * child_status; struct iovec * m_pIovec; struct iovec * m_pIovecEnd; struct iovec * m_pIovecCur; struct iovec * m_pIovecToWrite; struct lsapi_packet_header * m_respPktHeaderEnd; struct lsapi_req_header * m_pHeader; struct LSAPI_key_value_pair * m_pEnvList; struct LSAPI_key_value_pair * m_pSpecialEnvList; int m_envListSize; int m_specialEnvListSize; struct lsapi_http_header_index * m_pHeaderIndex; struct lsapi_header_offset * m_pUnknownHeader; char * m_pScriptFile; char * m_pScriptName; char * m_pQueryString; char * m_pHttpHeader; char * m_pRequestMethod; int m_totalLen; int m_reqState; off_t m_reqBodyLen; off_t m_reqBodyRead; int m_bufProcessed; int m_bufRead; struct lsapi_packet_header m_respPktHeader[5]; struct lsapi_resp_header m_respHeader; short m_respHeaderLen[LSAPI_MAX_RESP_HEADERS]; void * m_pAppData; }LSAPI_Request; extern LSAPI_Request g_req; /* return: >0 continue, ==0 stop, -1 failed */ typedef int (*LSAPI_CB_EnvHandler )( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ); int LSAPI_Init(void); void LSAPI_Stop(void); int LSAPI_Is_Listen_r( LSAPI_Request * pReq); int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ); int LSAPI_Accept_r( LSAPI_Request * pReq ); void LSAPI_Reset_r( LSAPI_Request * pReq ); int LSAPI_Finish_r( LSAPI_Request * pReq ); int LSAPI_Release_r( LSAPI_Request * pReq ); char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ); int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ); ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t len ); int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ); int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF ); int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ); ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len ); ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size ); ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len ); int LSAPI_Flush_r( LSAPI_Request * pReq ); int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len ); int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName, const char * pHeaderValue ); int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders, const char * pBody, int bodyLen ); static inline int LSAPI_SetRespStatus_r( LSAPI_Request * pReq, int code ) { if ( !pReq ) return -1; pReq->m_respHeader.m_respInfo.m_status = code; return 0; } static inline int LSAPI_SetAppData_r( LSAPI_Request * pReq, void * data ) { if ( !pReq ) return -1; pReq->m_pAppData = data; return 0; } static inline void * LSAPI_GetAppData_r( LSAPI_Request * pReq ) { if ( !pReq ) return NULL; return pReq->m_pAppData; } static inline char * LSAPI_GetQueryString_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pQueryString; return NULL; } static inline char * LSAPI_GetScriptFileName_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pScriptFile; return NULL; } static inline char * LSAPI_GetScriptName_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pScriptName; return NULL; } static inline char * LSAPI_GetRequestMethod_r( LSAPI_Request * pReq) { if ( pReq ) return pReq->m_pRequestMethod; return NULL; } static inline off_t LSAPI_GetReqBodyLen_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_reqBodyLen; return -1; } static inline off_t LSAPI_GetReqBodyRemain_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_reqBodyLen - pReq->m_reqBodyRead; return -1; } int LSAPI_End_Response_r(LSAPI_Request * pReq); int LSAPI_Is_Listen(void); static inline int LSAPI_Accept( void ) { return LSAPI_Accept_r( &g_req ); } static inline int LSAPI_Finish(void) { return LSAPI_Finish_r( &g_req ); } static inline char * LSAPI_GetHeader( int headerIndex ) { return LSAPI_GetHeader_r( &g_req, headerIndex ); } static inline int LSAPI_ForeachHeader( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachHeader_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachOrgHeader( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachOrgHeader_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachEnv( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachEnv_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachSpecialEnv( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachSpecialEnv_r( &g_req, fn, arg ); } static inline char * LSAPI_GetEnv( const char * name ) { return LSAPI_GetEnv_r( &g_req, name ); } static inline char * LSAPI_GetQueryString(void) { return LSAPI_GetQueryString_r( &g_req ); } static inline char * LSAPI_GetScriptFileName(void) { return LSAPI_GetScriptFileName_r( &g_req ); } static inline char * LSAPI_GetScriptName(void) { return LSAPI_GetScriptName_r( &g_req ); } static inline char * LSAPI_GetRequestMethod(void) { return LSAPI_GetRequestMethod_r( &g_req ); } static inline off_t LSAPI_GetReqBodyLen(void) { return LSAPI_GetReqBodyLen_r( &g_req ); } static inline off_t LSAPI_GetReqBodyRemain(void) { return LSAPI_GetReqBodyRemain_r( &g_req ); } static inline ssize_t LSAPI_ReadReqBody( char * pBuf, size_t len ) { return LSAPI_ReadReqBody_r( &g_req, pBuf, len ); } static inline int LSAPI_ReqBodyGetChar(void) { return LSAPI_ReqBodyGetChar_r( &g_req ); } static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF ) { return LSAPI_ReqBodyGetLine_r( &g_req, pBuf, len, getLF ); } static inline int LSAPI_FinalizeRespHeaders(void) { return LSAPI_FinalizeRespHeaders_r( &g_req ); } static inline ssize_t LSAPI_Write( const char * pBuf, ssize_t len ) { return LSAPI_Write_r( &g_req, pBuf, len ); } static inline ssize_t LSAPI_sendfile( int fdIn, off_t* off, size_t size ) { return LSAPI_sendfile_r(&g_req, fdIn, off, size ); } static inline ssize_t LSAPI_Write_Stderr( const char * pBuf, ssize_t len ) { return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); } static inline int LSAPI_Flush(void) { return LSAPI_Flush_r( &g_req ); } static inline int LSAPI_AppendRespHeader( char * pBuf, int len ) { return LSAPI_AppendRespHeader_r( &g_req, pBuf, len ); } static inline int LSAPI_SetRespStatus( int code ) { return LSAPI_SetRespStatus_r( &g_req, code ); } static inline int LSAPI_ErrResponse( int code, const char ** pRespHeaders, const char * pBody, int bodyLen ) { return LSAPI_ErrResponse_r( &g_req, code, pRespHeaders, pBody, bodyLen ); } static inline int LSAPI_End_Response(void) { return LSAPI_End_Response_r( &g_req ); } int LSAPI_IsRunning(void); int LSAPI_CreateListenSock( const char * pBind, int backlog ); typedef int (*fn_select_t)( int, fd_set *, fd_set *, fd_set *, struct timeval * ); int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ); void LSAPI_Set_Server_fd( int fd ); int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ); void LSAPI_No_Check_ppid(void); void LSAPI_Set_Max_Reqs( int reqs ); void LSAPI_Set_Max_Idle( int secs ); void LSAPI_Set_Max_Children( int maxChildren ); void LSAPI_Set_Max_Idle_Children( int maxIdleChld ); void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ); void LSAPI_Set_Max_Process_Time( int secs ); int LSAPI_Init_Env_Parameters( fn_select_t fp ); void LSAPI_Set_Slow_Req_Msecs( int msecs ); int LSAPI_Get_Slow_Req_Msecs(void); int LSAPI_is_suEXEC_Daemon(void); int LSAPI_Set_Restored_Parent_Pid(int pid); typedef void (*LSAPI_On_Timer_pf)(int *forked_child_pid); void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf); int LSAPI_Inc_Req_Processed(int cnt); int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq); int LSAPI_Postfork_Child(LSAPI_Request * pReq); int LSAPI_Postfork_Parent(LSAPI_Request * pReq); #define LSAPI_LOG_LEVEL_BITS 0xff #define LSAPI_LOG_FLAG_NONE 0 #define LSAPI_LOG_FLAG_DEBUG 1 #define LSAPI_LOG_FLAG_INFO 2 #define LSAPI_LOG_FLAG_NOTICE 3 #define LSAPI_LOG_FLAG_WARN 4 #define LSAPI_LOG_FLAG_ERROR 5 #define LSAPI_LOG_FLAG_CRIT 6 #define LSAPI_LOG_FLAG_FATAL 7 #define LSAPI_LOG_TIMESTAMP_BITS (0xff00) #define LSAPI_LOG_TIMESTAMP_FULL (0x100) #define LSAPI_LOG_TIMESTAMP_HMS (0x200) #define LSAPI_LOG_TIMESTAMP_STDERR (0x400) #define LSAPI_LOG_PID (0x10000) void LSAPI_Log(int flag, const char * fmt, ...) #if __GNUC__ __attribute__((format(printf, 2, 3))) #endif ; #if defined (c_plusplus) || defined (__cplusplus) } #endif #endif PK ]7Zw(gems/ruby-lsapi-5.5/ext/lsapi/extconf.rbnu[require 'mkmf' dir_config( 'lsapi' ) if ( have_library( "socket" )) have_library( "nsl" ) end if RUBY_VERSION =~ /1.9/ then $CPPFLAGS += " -DRUBY_19" end if RUBY_VERSION =~ /2/ then $CPPFLAGS += " -DRUBY_2" end create_makefile( "lsapi" ) PK ].ZZ&gems/ruby-lsapi-5.5/ext/lsapi/lsruby.cnu[ #include "ruby.h" #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 #include "util.h" #else #include #include #endif #include "lsapilib.h" #include #include #include #include #include #include #include #include #include #ifndef RUBY_API_VERSION_CODE #define RUBY_API_VERSION_CODE (RUBY_API_VERSION_MAJOR*10000+RUBY_API_VERSION_MINOR*100+RUBY_API_VERSION_TEENY) #endif /* RUBY_EXTERN VALUE ruby_errinfo; */ RUBY_EXTERN VALUE rb_stdin; RUBY_EXTERN VALUE rb_stdout; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 RUBY_EXTERN VALUE rb_defout; #endif static VALUE orig_stdin; static VALUE orig_stdout; static VALUE orig_stderr; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 static VALUE orig_defout; #endif static VALUE orig_env; static VALUE env_copy; static VALUE lsapi_env; static int MAX_BODYBUF_LENGTH = (10 * 1024 * 1024); /* static VALUE lsapi_objrefs; */ typedef struct lsapi_data { LSAPI_Request * req; VALUE env; ssize_t (* fn_write)( LSAPI_Request *, const char * , size_t ); }lsapi_data; static VALUE cLSAPI; static VALUE s_req = Qnil; static lsapi_data * s_req_data; static VALUE s_req_stderr = Qnil; static lsapi_data * s_stderr_data; static pid_t s_pid = 0; typedef struct lsapi_body { char *bodyBuf; //we put small one into memory, otherwise, into a memory mapping file, and we still use the bodyBuf to access this mapping int bodyLen; //expected length got form content-length int bodyCurrentLen; //current length by read() readBodyToReqBuf int curPos; }lsapi_body; static lsapi_body s_body; static char sTempFile[1024] = {0}; /* * static void lsapi_ruby_setenv(const char *name, const char *value) * { * if (!name) return; * * if (value && *value) * ruby_setenv(name, value); * else * ruby_unsetenv(name); } * * */ static void lsapi_mark( lsapi_data * data ) { rb_gc_mark( data->env ); } /* * static void lsapi_free_data( lsapi_data * data ) * { * free( data ); } * * */ static int add_env_rails( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { char * p; int len; /* Fixup some environment variables for rails */ switch( *pKey ) { case 'Q': if ( strcmp( pKey, "QUERY_STRING" ) == 0 ) { if ( !*pValue ) return 1; } break; case 'R': if (( *(pKey+8) == 'U' )&&( strcmp( pKey, "REQUEST_URI" ) == 0 )) { p = strchr( pValue, '?' ); if ( p ) { len = valLen - ( p - pValue ) - 1; /* * valLen = p - pValue; *p++ = 0; */ } else { p = (char *)pValue + valLen; len = 0; } rb_hash_aset( lsapi_env,rb_tainted_str_new("PATH_INFO", 9), rb_tainted_str_new(pValue, p - pValue)); rb_hash_aset( lsapi_env,rb_tainted_str_new("REQUEST_PATH", 12), rb_tainted_str_new(pValue, p - pValue)); if ( *p == '?' ) ++p; rb_hash_aset( lsapi_env,rb_tainted_str_new("QUERY_STRING", 12), rb_tainted_str_new(p, len)); } break; case 'S': if ( strcmp( pKey, "SCRIPT_NAME" ) == 0 ) { pValue = "/"; valLen = 1; } break; case 'P': if ( strcmp( pKey, "PATH_INFO" ) == 0 ) return 1; default: break; } /* lsapi_ruby_setenv(pKey, pValue ); */ rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen), rb_tainted_str_new(pValue, valLen)); return 1; } static int add_env_no_fix( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen), rb_tainted_str_new(pValue, valLen)); return 1; } typedef int (*fn_add_env)( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ); fn_add_env s_fn_add_env = add_env_no_fix; static void clear_env() { /* rb_funcall( lsapi_env, rb_intern( "clear" ), 0 ); */ rb_funcall( lsapi_env, rb_intern( "replace" ), 1, env_copy ); } static void setup_cgi_env( lsapi_data * data ) { clear_env(); LSAPI_ForeachHeader_r( data->req, s_fn_add_env, data ); LSAPI_ForeachEnv_r( data->req, s_fn_add_env, data ); } static VALUE lsapi_s_accept( VALUE self ) { int pid; if ( LSAPI_Prefork_Accept_r( &g_req ) == -1 ) return Qnil; else { if (s_body.bodyBuf != NULL) free (s_body.bodyBuf); s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; pid = getpid(); if ( pid != s_pid ) { s_pid = pid; rb_funcall( Qnil, rb_intern( "srand" ), 0 ); } setup_cgi_env( s_req_data ); return s_req; } } static VALUE lsapi_s_accept_new_conn(VALUE self) { if (LSAPI_Accept_Before_Fork(&g_req) == -1 ) return Qnil; else return s_req; } static VALUE lsapi_s_postfork_child(VALUE self) { LSAPI_Postfork_Child(&g_req); return s_req; } static VALUE lsapi_s_postfork_parent(VALUE self) { LSAPI_Postfork_Parent(&g_req); return s_req; } /* * static int chdir_file( const char * pFile ) * { * char * p = strrchr( pFile, '/' ); * int ret; * if ( !p ) * return -1; *p = 0; ret = chdir( pFile ); *p = '/'; return ret; } */ static VALUE lsapi_eval_string_wrap(VALUE self, VALUE str) { #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4) { Check_Type(str, T_STRING); } else #endif { SafeStringValue(str); } return rb_eval_string_wrap(StringValuePtr(str), NULL); } static VALUE lsapi_process( VALUE self ) { /* lsapi_data *data; const char * pScriptPath; Data_Get_Struct(self,lsapi_data, data); pScriptPath = LSAPI_GetScriptFileName_r( data->req ); */ /* * if ( chdir_file( pScriptPath ) == -1 ) * { * lsapi_send_error( 404 ); * } * rb_load_file( pScriptPath ); */ return Qnil; } static VALUE lsapi_putc(VALUE self, VALUE c) { char ch = NUM2CHR(c); lsapi_data *data; Data_Get_Struct(self,lsapi_data, data); if ( (*data->fn_write)( data->req, &ch, 1 ) == 1 ) return c; else return INT2NUM( EOF ); } static VALUE lsapi_write( VALUE self, VALUE str ) { lsapi_data *data; int len; Data_Get_Struct(self,lsapi_data, data); /* len = LSAPI_Write_r( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); */ if (TYPE(str) != T_STRING) str = rb_obj_as_string(str); len = (*data->fn_write)( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); return INT2NUM( len ); } static VALUE lsapi_print( int argc, VALUE *argv, VALUE out ) { int i; VALUE line; /* if no argument given, print `$_' */ if (argc == 0) { argc = 1; line = rb_lastline_get(); argv = &line; } for (i = 0; i0) { lsapi_write(out, rb_output_fs); } switch (TYPE(argv[i])) { case T_NIL: lsapi_write(out, rb_str_new2("nil")); break; default: lsapi_write(out, argv[i]); break; } } if (!NIL_P(rb_output_rs)) { lsapi_write(out, rb_output_rs); } return Qnil; } static VALUE lsapi_printf(int argc, VALUE *argv, VALUE out) { lsapi_write(out, rb_f_sprintf(argc, argv)); return Qnil; } static VALUE lsapi_puts _((int, VALUE*, VALUE)); #if RUBY_API_VERSION_CODE >= 10900 static VALUE lsapi_puts_ary(VALUE ary, VALUE out, int recur ) { VALUE tmp; long i; if (recur) { tmp = rb_str_new2("[...]"); rb_io_puts(1, &tmp, out); return Qnil; } for (i=0; i= 10900 rb_exec_recursive(lsapi_puts_ary, argv[i], out); #else rb_protect_inspect(lsapi_puts_ary, argv[i], out); #endif continue; default: line = argv[i]; break; } line = rb_obj_as_string(line); lsapi_write(out, line); if (*( RSTRING_PTR(line) + RSTRING_LEN(line) - 1 ) != '\n') { lsapi_write(out, rb_default_rs); } } return Qnil; } static VALUE lsapi_addstr(VALUE out, VALUE str) { lsapi_write(out, str); return out; } static VALUE lsapi_flush( VALUE self ) { /* * lsapi_data *data; * Data_Get_Struct(self,lsapi_data, data); */ LSAPI_Flush_r( &g_req ); return Qnil; } static VALUE lsapi_getc( VALUE self ) { int ch; /* * lsapi_data *data; * Data_Get_Struct(self,lsapi_data, data); */ #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif ch = LSAPI_ReqBodyGetChar_r( &g_req ); if ( ch == EOF ) return Qnil; return INT2NUM( ch ); } static inline int isBodyWriteToFile() { return ((s_body.bodyLen >= MAX_BODYBUF_LENGTH)? (1): (0)); } //create a temp file and open it, if failed, fd = -1 static inline int createTempFile() { int fd = -1; char *sfn = strdup(sTempFile); if ((fd = mkstemp(sfn)) == -1) { fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); } else unlink(sfn); free(sfn); return fd; } //return 1 if error occured! //if already created, always OK (0) static int createBodyBuf() { int fd = -1; if (s_body.bodyLen == -1) { s_body.bodyLen = LSAPI_GetReqBodyLen_r(&g_req); //Error if get a zeor length, should not happen if (s_body.bodyLen < 0) { //Wrong bode length will be treated as 0 s_body.bodyLen = 0; } if (s_body.bodyLen > 0) { if (isBodyWriteToFile()) { //create file mapping fd = createTempFile(); if (fd == -1) { return 1; } if (ftruncate(fd, s_body.bodyLen) == 0) { perror("ftruncate() failed. \n"); close(fd); return 1; } s_body.bodyBuf = mmap(NULL, s_body.bodyLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (s_body.bodyBuf == MAP_FAILED) { perror("File mapping failed. \n"); close(fd); return 1; } close(fd); //close since needn't it anymore } else { s_body.bodyBuf = (char *)calloc(s_body.bodyLen, sizeof(char)); if (s_body.bodyBuf == NULL) { perror("Memory calloc error"); return 1; } } } } return 0; } static inline int isAllBodyRead() { return (s_body.bodyCurrentLen < s_body.bodyLen)? 0 : 1; } static inline int isEofBodyBuf() { return (s_body.curPos < s_body.bodyLen) ? 0 : 1; } //try to read length as times pagesize (such as 8KB * N) static int readBodyBuf(const int needRead) { const int blockSize = 8192; char *buff = s_body.bodyBuf + s_body.bodyCurrentLen; int nRead; int readMore = (needRead + blockSize -1) / blockSize * blockSize; int remain = LSAPI_GetReqBodyRemain_r( &g_req ); //Only when not enough left, needReadChange will be changed!!! if (remain < readMore) readMore = remain; if ( readMore <= 0 ) return 0; nRead = LSAPI_ReadReqBody_r(&g_req, buff, readMore); if ( nRead > 0 ) s_body.bodyCurrentLen += nRead; return nRead; } static VALUE lsapi_gets( VALUE self ) { VALUE str; const int blkSize = 4096; int n; char *p = NULL; #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif if (createBodyBuf() == 1) { return Qnil; } //comment: while((p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1)) == NULL) { if (isAllBodyRead() == 1) break; //read one page and check, then reply readBodyBuf(blkSize); } p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1); if (p != NULL) n = p - s_body.bodyBuf - s_body.curPos + 1; else n = s_body.bodyCurrentLen - s_body.curPos; str = rb_str_buf_new( n ); #if RUBY_API_VERSION_CODE < 20700 OBJ_TAINT(str); #endif if (n > 0) { rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n ); s_body.curPos += n; } return str; } static VALUE lsapi_read(int argc, VALUE *argv, VALUE self) { VALUE str; int n; int needRead; int nRead; #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif if (createBodyBuf() == 1) { return Qnil; } //we need to consider these 4 cases: //1, need all data since argc == 0, we may have all data 2, or not //3, need a length of data (argv >= 1), we may have enough data already read, 4, or not if (argc == 0) n = s_body.bodyLen - s_body.curPos; else { n = NUM2INT(argv[0]); //request that length from currentpos if (n < 0) return Qnil; if (n > s_body.bodyLen - s_body.curPos) n = s_body.bodyLen - s_body.curPos; } needRead = s_body.curPos + n - s_body.bodyCurrentLen; if (needRead < 0) needRead = 0; str = rb_str_buf_new( n ); #if RUBY_API_VERSION_CODE < 20700 OBJ_TAINT(str); #endif if (n == 0) return str; //copy already have part first if (n - needRead != 0) { rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n - needRead); s_body.curPos += (n - needRead); } if (needRead > 0) { //try to read needRead, but may be less (changed) when read the end of the data nRead = readBodyBuf(needRead); if (nRead > 0) { n = ((nRead < needRead) ? nRead : needRead); rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n ); s_body.curPos += n; } } return str; } static VALUE lsapi_rewind(VALUE self) { s_body.curPos = 0; return self; } static VALUE lsapi_each(VALUE self) { VALUE str; lsapi_rewind(self); while(isEofBodyBuf() != 1) { str = lsapi_gets(self); rb_yield(str); } return self; } static VALUE lsapi_eof(VALUE self) { return (LSAPI_GetReqBodyRemain_r( &g_req ) <= 0) ? Qtrue : Qfalse; } static VALUE lsapi_binmode(VALUE self) { return self; } static VALUE lsapi_isatty(VALUE self) { return Qfalse; } static VALUE lsapi_sync(VALUE self) { return Qfalse; } static VALUE lsapi_setsync(VALUE self,VALUE sync) { return Qfalse; } static VALUE lsapi_close(VALUE self) { LSAPI_Flush_r( &g_req ); if (isBodyWriteToFile()) { //msync(s_body.bodyBuf, s_body.bodyLen, MS_SYNC); //sleep(5); munmap(s_body.bodyBuf, s_body.bodyLen); } else free(s_body.bodyBuf); s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; //Should the temp be deleted here?! return Qnil; } static VALUE lsapi_reopen( int argc, VALUE *argv, VALUE self) { VALUE orig_verbose; if ( self == s_req_stderr ) { /* constant silence hack */ orig_verbose = (VALUE)ruby_verbose; ruby_verbose = Qnil; rb_define_global_const("STDERR", orig_stderr); ruby_verbose = (VALUE)orig_verbose; return rb_funcall2( orig_stderr, rb_intern( "reopen" ), argc, argv ); } return self; } static void readMaxBodyBufLength() { int n; const char *p = getenv( "LSAPI_MAX_BODYBUF_LENGTH" ); if ( p ) { n = atoi( p ); if (n > 0) { if (strstr(p, "M") || strstr(p, "m")) MAX_BODYBUF_LENGTH = n * 1024 * 1024; else if (strstr(p, "K") || strstr(p, "k")) MAX_BODYBUF_LENGTH = n * 1024; else MAX_BODYBUF_LENGTH = n; } } } static void readTempFileTemplate() { const char *p = getenv( "LSAPI_TEMPFILE" ); if (p == NULL || strlen(p) > 1024 - 7) p = "/tmp/lsapi.XXXXXX"; strcpy(sTempFile, p); if (strlen(p) <= 6 || strcmp(p + (strlen(p) - 6), "XXXXXX") != 0) strcat(sTempFile, ".XXXXXX"); } static void initBodyBuf() { s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; } void Init_lsapi() { VALUE orig_verbose; char * p; int prefork = 0; LSAPI_Init(); initBodyBuf(); readMaxBodyBufLength(); readTempFileTemplate(); p = getenv("LSAPI_CHILDREN"); if (p && atoi(p) > 1) prefork = 1; #ifdef rb_thread_select LSAPI_Init_Env_Parameters( rb_thread_select ); #else LSAPI_Init_Env_Parameters( select ); #endif s_pid = getpid(); p = getenv( "RACK_ROOT" ); if ( p ) { if ( chdir( p ) == -1 ) perror( "chdir()" ); } if ( p || getenv( "RACK_ENV" ) ) s_fn_add_env = add_env_rails; orig_stdin = rb_stdin; orig_stdout = rb_stdout; orig_stderr = rb_stderr; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 orig_defout = rb_defout; #endif orig_env = rb_const_get( rb_cObject, rb_intern("ENV") ); env_copy = rb_funcall( orig_env, rb_intern( "to_hash" ), 0 ); /* tell the garbage collector it is a global variable, do not recycle it. */ rb_global_variable(&env_copy); rb_hash_aset( env_copy,rb_tainted_str_new("GATEWAY_Irewindable_input.rbNTERFACE", 17), rb_tainted_str_new("CGI/1.2", 7)); rb_define_global_function("eval_string_wrap", lsapi_eval_string_wrap, 1); cLSAPI = rb_define_class("LSAPI", rb_cObject); rb_define_singleton_method(cLSAPI, "accept", lsapi_s_accept, 0); if (prefork) { rb_define_singleton_method(cLSAPI, "accept_new_connection", lsapi_s_accept_new_conn, 0); rb_define_singleton_method(cLSAPI, "postfork_child", lsapi_s_postfork_child, 0); rb_define_singleton_method(cLSAPI, "postfork_parent", lsapi_s_postfork_parent, 0); } rb_define_method(cLSAPI, "process", lsapi_process, 0 ); /* rb_define_method(cLSAPI, "initialize", lsapi_initialize, 0); */ rb_define_method(cLSAPI, "putc", lsapi_putc, 1); rb_define_method(cLSAPI, "write", lsapi_write, 1); rb_define_method(cLSAPI, "print", lsapi_print, -1); rb_define_method(cLSAPI, "printf", lsapi_printf, -1); rb_define_method(cLSAPI, "puts", lsapi_puts, -1); rb_define_method(cLSAPI, "<<", lsapi_addstr, 1); rb_define_method(cLSAPI, "flush", lsapi_flush, 0); rb_define_method(cLSAPI, "getc", lsapi_getc, 0); /* rb_define_method(cLSAPI, "ungetc", lsapi_ungetc, 1); */ rb_define_method(cLSAPI, "gets", lsapi_gets, 0); //TEST: adding readline function to make irb happy? /*rb_define_method(cLSAPI, "readline", lsapi_gets, 0); */ rb_define_method(cLSAPI, "read", lsapi_read, -1); rb_define_method(cLSAPI, "rewind", lsapi_rewind, 0); rb_define_method(cLSAPI, "each", lsapi_each, 0); rb_define_method(cLSAPI, "eof", lsapi_eof, 0); rb_define_method(cLSAPI, "eof?", lsapi_eof, 0); rb_define_method(cLSAPI, "close", lsapi_close, 0); /* rb_define_method(cLSAPI, "closed?", lsapi_closed, 0); */ rb_define_method(cLSAPI, "binmode", lsapi_binmode, 0); rb_define_method(cLSAPI, "isatty", lsapi_isatty, 0); rb_define_method(cLSAPI, "tty?", lsapi_isatty, 0); rb_define_method(cLSAPI, "sync", lsapi_sync, 0); rb_define_method(cLSAPI, "sync=", lsapi_setsync, 1); rb_define_method(cLSAPI, "reopen", lsapi_reopen, -1 ); s_req = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_req_data ); s_req_data->req = &g_req; s_req_data->fn_write = LSAPI_Write_r; rb_stdin = rb_stdout = s_req; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 rb_defout = s_req; #endif rb_global_variable(&s_req ); s_req_stderr = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_stderr_data ); s_stderr_data->req = &g_req; s_stderr_data->fn_write = LSAPI_Write_Stderr_r; rb_stderr = s_req_stderr; rb_global_variable(&s_req_stderr ); /* constant silence hack */ orig_verbose = (VALUE)ruby_verbose; ruby_verbose = Qnil; lsapi_env = rb_hash_new(); clear_env(); /* redefine ENV using a hash table, should be faster than char **environment */ rb_define_global_const("ENV", lsapi_env); rb_define_global_const("STDERR", rb_stderr); ruby_verbose = (VALUE)orig_verbose; return; } PK ]W q,,(gems/ruby-lsapi-5.5/ext/lsapi/lsapidef.hnu[/* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _LSAPIDEF_H_ #define _LSAPIDEF_H_ #include #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif enum { H_ACCEPT = 0, H_ACC_CHARSET, H_ACC_ENCODING, H_ACC_LANG, H_AUTHORIZATION, H_CONNECTION, H_CONTENT_TYPE, H_CONTENT_LENGTH, H_COOKIE, H_COOKIE2, H_HOST, H_PRAGMA, H_REFERER, H_USERAGENT, H_CACHE_CTRL, H_IF_MODIFIED_SINCE, H_IF_MATCH, H_IF_NO_MATCH, H_IF_RANGE, H_IF_UNMOD_SINCE, H_KEEP_ALIVE, H_RANGE, H_X_FORWARDED_FOR, H_VIA, H_TRANSFER_ENCODING }; #define LSAPI_SOCK_FILENO 0 #define LSAPI_VERSION_B0 'L' #define LSAPI_VERSION_B1 'S' /* Values for m_flag in lsapi_packet_header */ #define LSAPI_ENDIAN_LITTLE 0 #define LSAPI_ENDIAN_BIG 1 #define LSAPI_ENDIAN_BIT 1 #if defined(__i386__)||defined( __x86_64 )||defined( __x86_64__ ) #define LSAPI_ENDIAN LSAPI_ENDIAN_LITTLE #else #define LSAPI_ENDIAN LSAPI_ENDIAN_BIG #endif /* Values for m_type in lsapi_packet_header */ #define LSAPI_BEGIN_REQUEST 1 #define LSAPI_ABORT_REQUEST 2 #define LSAPI_RESP_HEADER 3 #define LSAPI_RESP_STREAM 4 #define LSAPI_RESP_END 5 #define LSAPI_STDERR_STREAM 6 #define LSAPI_REQ_RECEIVED 7 #define LSAPI_CONN_CLOSE 8 #define LSAPI_INTERNAL_ERROR 9 #define LSAPI_MAX_HEADER_LEN 65535 #define LSAPI_MAX_DATA_PACKET_LEN 16384 #define LSAPI_RESP_HTTP_HEADER_MAX 32768 #define LSAPI_PACKET_HEADER_LEN 8 struct lsapi_packet_header { char m_versionB0; /* LSAPI protocol version */ char m_versionB1; char m_type; char m_flag; union { int32_t m_iLen; /* include this header */ char m_bytes[4]; }m_packetLen; }; /* LSAPI request header packet 1. struct lsapi_req_header 2. struct lsapi_http_header_index 3. lsapi_header_offset * unknownHeaders 4. org http request header 5. request body if available */ struct lsapi_req_header { struct lsapi_packet_header m_pktHeader; int32_t m_httpHeaderLen; int32_t m_reqBodyLen; int32_t m_scriptFileOff; /* path to the script file. */ int32_t m_scriptNameOff; /* decrypted URI, without pathinfo, */ int32_t m_queryStringOff; /* Query string inside env */ int32_t m_requestMethodOff; int32_t m_cntUnknownHeaders; int32_t m_cntEnv; int32_t m_cntSpecialEnv; } ; struct lsapi_http_header_index { uint16_t m_headerLen[H_TRANSFER_ENCODING+1]; int32_t m_headerOff[H_TRANSFER_ENCODING+1]; } ; struct lsapi_header_offset { int32_t nameOff; int32_t nameLen; int32_t valueOff; int32_t valueLen; } ; struct lsapi_resp_info { int32_t m_cntHeaders; int32_t m_status; }; struct lsapi_resp_header { struct lsapi_packet_header m_pktHeader; struct lsapi_resp_info m_respInfo; }; #if defined (c_plusplus) || defined (__cplusplus) } #endif #endif PK ](((gems/ruby-lsapi-5.5/ext/lsapi/lsapilib.onu[ELF>@@=< 02/3.4-5ff.ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=DÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH=1tIH=HcH5HH[ÉD1?H=HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHtHHtHHtH{@Ht1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDHu48u uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=HcB$HH@H,H9rZf.HH9vGH3LuHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L=L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$)H8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L LfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH L$DIH Ic LEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcUff.AWAVAUATUSHXHt$ HT$dH%(H$H1HIH1E1L-HL%HHHcHcT4t/HHAAtIL{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eHthILM)MUI9t HtDL+t$HL[]A\A]A^A_DM@@M)(IHt$HLHk8f.HAVLAUIATIUSHu\H߉AD${LǃLSHu0{L[L]A\A]A^[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIHLc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAMt$PHLIFID$PA:I|$PMD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHAI\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1HL$Aߺu#DHuDo߻D HDeOAkDH}An}NHtff.USHdH%(H$1HHu/HH$dH3%(uHĘ[]@1H=tAUATA'USH'DNuDH@AHHHHtH-ƉljUDk HDcEufH H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0ALJt` A1LHcIHIGAo IuID%D-B(AA1IcH4IILI 9HqH= IJDB(9xHqH= XIJB($AD$IKAzHL$;MbfoLt$ LAoL$AT$Ml$)$ LLHL$LHLLH$ID$H$I3L$H1H D$$Dl$EDDl$H=IHIDMH=t"LDLŃP|$Et$A9uHt$DŃ5$A?D5t AH5LHtHHf)#AH51H@H51LH 1HIH51H51D%DD$H=IHtZEW7E1111H=H51E|$M2;|$E1H5LuI}Ń1H5LKfD=-ED$AIFH51HH)H5H11H5L 1H5LA#LH H1H5Laff.AVAUATUSHdH%(H$1D$ HH ;1Ll$Ld$Lt$ Hkl{ul;LLD$CHHt@HHt{1f|$=u|H4tH舴Hd1H$dH3 %(u}HĠ[]A\A]A^D {H5Hfы{LA;ff.AWAVAUATUSHD=dH%(H$1ExHH-H};DH-Ht 1HEDEH$L|$PDcA:E1AfD EDEtHHt @fLH1HIcDHD$PHD$XA ?)ѺHH D9#11A|$MHD9#HHt @D9#AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$LH$LHHD$@AHLDŽ$hH$H$LHHD$0PH$LHHD$8+H$`L HHD$(H$ LHHD$HADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%EHHt H=1IL9t<1ձL5EDu EME1VHLH1HHc}}LD$LHD$PHD$X ?)ѺH1H T`1 8Ht$(1ҿ x=_5tHHt @f,D9# DCHHt@HHtDc1DN ={H5HHHt*HHB(@HHt@HH@8B-DAD9M==H HtDHHt A9HHtD҉T$$DE ~:E~5T$$AAAuDE UM D9vHAHtDH51D$0 H=T$fD}蠩C1mH|$IH|$HT$Ht$161E Mt AMgMg{E1CHt$1ҿH=f;>fDD$$0d T$$WH=T$T$fDD#AfDRDEBHH29{H5H{wH=H=0MAH… H{HH=Ht$1ҿHL=HHHtH11L=AGHHt{1蝦D-EuHHt!E9~;t Ht$@1ҿL$Ht$01ҿHt$H1ҿHt$81ҿHt$(1ҿ kHLSH$$L$H=%,H=QHHt*fC1CD$CCT$HC(HC fD=ff.@H,LSLSLSLS GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realignAnonymous mmap() failedlocalhost%02d:%02d:%02d [%s] [UID:%d][%d] %.*syesnosystem()%s, errno: %d (%s) /dev/nulllibpthread.sopthread_atforkHTTP_[UID:%d][%d] %s:%s: %s LSAPI: jail() failure./etc/Can't set signalsaccept() failedLSAPI_STDERR_LOGPHP_LSAPI_MAX_REQUESTSLSAPI_MAX_REQSLSAPI_KEEP_LISTENLSAPI_AVOID_FORKLSAPI_ACCEPT_NOTIFYLSAPI_SLOW_REQ_MSECSLSAPI_ALLOW_CORE_DUMPLSAPI_MAX_IDLEPHP_LSAPI_CHILDRENLSAPI_CHILDRENLSAPI_EXTRA_CHILDRENLSAPI_MAX_IDLE_CHILDRENLSAPI_PGRP_MAX_IDLELSAPI_MAX_PROCESS_TIMELSAPI_PPID_NO_CHECKLSAPI_MAX_BUSY_WORKERLSAPI_DUMP_DEBUG_INFOnobodyLSAPI_DEFAULT_UIDLSAPI_DEFAULT_GIDLSAPI_SECRETLSAPI_LVE_ENABLELVE_ENABLEliblve.so.0lve_is_availablelve_instance_initlve_destroylve_enterlve_leavejailLSAPI_PHP_LSAPI_PHPRC=packetLen < 0 packetLen > %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGINFONOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveRangeX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

    Resource Limit Is Reached

    The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
              ^ d/4-//// %-/Ga '9 (_intG )@/G G @ @ G @ G     G  `@ A C $E (J 0NL8PX@[+H\+X]+hj$xp4G- - N1 ooGGXa&& E18: ;1?A B C1GOI JK1 OQ RS TU1ac Ed EC^&e&g1 Y[ E]ah 1l5no 1tfv Ew x@ Cp3&5&<&Db_rtL&VO&i&p&y5G1$ +& ( * 0 { f|HCIRT Cv&"7&$ R  E+v"&T.1 4 c G@4HH//-Gldy"m - 911; CmGFy<d(eGfI@I@IEIE"1 36 |7 |8 |9 | : |(; |0< |8= |@@ |HA |PB |XD `F hHpItJ xM9NNO Q Y [ \ ] ^ E_ `b g+J  G J J  G4'  < ' ' '   T h4I ' T X@!      !!"! ! ! ""F " E" #!X@$  i0%9"# # # 4  G  "&4 &6 &7  < |"0'1 '3 |'4 |'6 '7 '8 |'9 | ': |(jtm8(, ( ( ( (  ( (((( ( ((0|< G'), ') ')'), ') ')H*! B@,H      !"#$%&'()*+,-./0123456789:;<<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'-$|'-2 '-7 '-; .U.m.4/"/*/!B@/) !)./23\^bgl00/{C/&/ &/ -&/ =-G=GMG"/h/ 4M'/h'/h"// ///-GK/,/ ///M/K0050708090: 0; F 0<0= | 0>( ,"n11 1 GkB@2,     C2q&2s9&2t"2k2m 2n 2o 2p 2u",22 2 92 9 2 92 92 92 92 9 2 9$2 9("222 4G9G"22 92 92 92 9 "2G2 92 9"2o2"2"/" / 1 | 2 | 3  4 k : < = ? @ B| C  E|( F|0 G|8 I|@ J|H K|P L!VX O ` P h Q p R x T'\ V'b W'h X'h Y' Z' \'n ]'t _| `| a| b| c| d e f g h iL k'zL m'G(L n'8L oE "0pVr s uhvwxz{ |(vGa=G q' s w9   EM X9    $EM x7=RH H"XOYbufP =Q YinRG-G?]!NB@j~            9     H  H  H  |      l "G * ^GN G t N  t G M>CQ L L @  J l E m  9    9#!  9 9 #! @! !9Z! #!  g!F!9! ! |'  ! m!        # # *"G&%" K "  K@ V#          ( 0 8M " z# V# @      #  -     H! x$2cnt!U$2pid'U  : YO%2buf'#!U#in>74r"4TsUs]4U T 4UsT  [5m4UsT 5UsT ,5UsT Q5UsT v5UsT 5U ʳY5U YU ;W6%;O";#;Y2x6k%2w~}׳6U2T~QwY7U 9Y,7U YK7U Yj7U Y7U Y7U ;Y7U Y7U <ytY,8U YK8U G<Yw8U ;Y8U ;Y8U <Y8U Q;Y'9U YF9U ^9Us<Y9U Y9U Q;{X9TvQ | $0.MX] ":!p], _ ":3:=GE `: E- G % :!p%) %2| %= ' :len( end) |:=G ;i pw!)p7 2;env ! )del! D TD ( ;*$U(;**U(<*'U(G<*&U(v<*$U(<*"U( <*U( =   H  -5+fd ret    ~ Et;=   5 >__d U| $ &585> 8! O EOOOOw PyPz%P{2P|?P~LPYPfPsPPPPtPtPuPvNPP p?P>QT?Q?U  y @y!y 9C@7@Ä*UvT|Q@T7@U}C AUAT|Qt7"AU}CGAU?T|QtClAU2T|QtCAU:T|QtCAU3T|Qt3AU OAU0KQ BU|[%BUV3KBT}Q0R0XtC|BU:TtQ0BU T BU [WVBUu7BUthCUtTAtDCU0TtQtLtCU2TtQCU  CU CU  DU 8DU tiDU2TtQ03DU0T0Q DT0LCDUATtQ0CEU?TtQ0C8EU3TtQ0C\EU2TtQ0CEU:TtQ0EU QU  ?yj"FQy-?y+Qy+y #/ y+y #  yy*T Q8ly 9G~y+y yy*T Q8zqQGUsOhGU03GU|TvQ0R0X[WGU|GU|T0Q HU LGHUs?Ãsx_HUsHUs?ÃsqpHUsOHU0M M M .5+ O 4 P 4Q }R E} S retT  V z#EactX ~;I   5I__d ;1J  #JU T7VJU|CJUATvQ 7JU|CJU?TvQ CJU2TvQ CKU:TvQ C@KU3TvQ 3[KU OrKU0KQKU}[KUV3KT|Q0R0XC LUAT Q0C2LU?T Q0C[LU3T Q0CLU2T Q0CLU:T Q0LU T LU [W )MU HMU gMU VMUu> @N > +5+5N C 4OU0L pO  *5+  y6 GOy!y@ 7NÄ 9O*UsTwQ@3OU0T0Q OT0LQ: Q : @z# ; 95+act=  =  = % = / >  >  ?  @ retA pidB  C 4 D 4 E  F E H  I FP   FQ__d )  D/ 1T+ : 6R  ,        %RU T   F lY  *  5 =X~ret pfd YSYUUTsZqYUsTv88 Z 8 ' 8 @ : Zp; | < |res=  = , > ? ZG -[  6[  Gret fd  D  ZT1Q0ZUsT2Q1[UsT1Q2RDX4?[UsTvQ} ][UsT|L,[Uv 8 [  /5+  B!len LF[ch )   ^  05+  C  ,   len ;\ch ;\ch 57]  U|  x]TTQ~  ]T}Qv]UvU} t^* 25+U- Ä F^  05+#fn !#arg ,E@p_QTRQt Fp_ t )5+#fnu !#argu ,E@p_QTRQ6a s` a 6h#nb #fnb (#argb 3E d #hrete qX} b  ,5+#fn !#arg ,Ei len! " |ret# $ ;Zb7 Z}p8 | 9 | : | ;  < &t < -t5(achK % O Fa__cO 9 ̋F 1b݋r}U~T}#X|3bUv3$|"T v2$}"X|$_d /5+#fn!#arg,Ei len  |ret  _d~5c |  &t -tEdUwQ R E=dUwT| $ &Q R 3QdXvA"pd=G d2v1'U2v27T|'f (5+ ; #h #h['ff$Ff$9fSf^fNkfelfwfffffUffUff9RU|Ts3$"RU|q|f q-5+ q@is t |)p | |  &t -t)ch) )__c8< -g </5+ <B!len<O >  ?p@ A - B -retC iovDg E  gGh $5+ret n .ph6$)CP]qTshhUshUs?Ãs^(iNi*'5+U "\  -Ä -j +5+ 5#offBj N "\ jÄg5jUs*RjT~Q8Z^yjTTQQRR^8 - k (5+ ;!lenH "\  p! " - # - $ - %  - l .5+ ;| Hlen -    l$UvQ|-o ʊlۊ@U~TvQsln -5+ :| G THlen -  -  |  |  |p |  >n#nTQsTQsmo no% ooU~jUT:Qs]mo -5++moo%ooUs o .5+  len -|Sp*+5+U 5off yJqp y&5+(nYp n%5+-`t}$qKzq K*5+h-qUsgEqUseqUs?Ãs^Us-r -%5+hqUsgqUsqpqUs^Ft %5+=X~ElenF ~~ ?yPsQy-?y+Qy+y / y+y   yy*T Q8zqhsUssT0sT|Q}sT0xsUssUv?ÃsqptUs8tT6Q1R~X4 yt*(5+Ut@FtU %w (5+#fd2  `Tu}$q  uvT Y' >vk%'w~~׳/vUvT~Q~ HveY'U T2ʳvU vUsT vUvT1wU0wT0( Sw2cb;*UD Tx EۄwU=T ۄxU:T ;xUIT1WxU2T1t{xU T0xU T1T A y A%5+lenC D 4/y!fd4) 6 /y?yG+^y!fd+,s y!fd5 y!fd 7y!fd.!pktN\ *z *5+ 4   |  | Wz 65+ D z D.5+uidF gidG H I J#h K#hiL 1 >{ 1.5+ 2|!len2 2+| 26 4 5>{-N{G { '5+!uid3L!gid>@ Prv pw! { 6 | +5+#uid7L#pwL!ret  Tw3o|UQTs|U T Q|Xs}|UvT Q0 $} ,5+!uid8L) ret  r} -5+r} } }G}=G#4}6{  {,5+ {? {R} ":_n~ i~ ~$zUvT Q1R X rf~U|Tv*~U2DrJ [ J%stLSfdM ) zrc+   )uid  -5+  i ) &t -t7 O 35+i F2bp|) &t -t7v /5+pb7 )Hp |b6t Y t4h tB*u! Q u#| w#h x xh!fdh j=XlenkF R ف R<ف SH S+ U#hh> >>\ >L)bF62 G 235+ 2=p4 |vTv$ Ă $+5+!n$5p&  05+ :  | i!fd 2i < Gret  n  -!fd' 2E!len?ret -7 у 35+ !fdret 6 U#fd# +val UsT3Q0@UUT47wф wJ\ x&!lenx0tR :A  A A2EsaC~CWUvT0Qs7oUsCUvTsQ0:8 υ2sig8!U:3 2sig3 Uu (7   .mUs@U T QURTvvwxfmt'PVbuf Tvyp |z Eap  u5VtvEuVtm u{iևzU|T Q1R X \i/XzU|T Q1R X õuUsT0ϵUsTu +۵T1Q}Ru\i-zUsTdQ1R X Yv3$" izUsTdQ1R X  > [[OT1Q X|rW  :5+ D.|ʊ|."-" "E"%.k|6kkk.\|`\\.>E>E>>.'E̋'E''.EG.8 18.did d<P.A]__sA]__nAAP.%|Ռ%%|sz' 8n n8i i8 B  BS.)s))PW11W"m"m,moooo-o ʊۊ@U~TvQ|,aq$ÃSу G$% L8Us+ $Ã, )6CP]UvQ|,Ot  OfT0,YYYYY}YYY}Y}YYG g)U|TsQ N ʑ)UvT|Ql  UsT0Q: ` T}q ̋ ݋ Uv 6\ SG) U|T:51U|T )OU}T]AzU}T0Q}R}NU|[U},UUUUQUQVV[UC ה$UUUUVVNVV+VU T|QgU TvQ3VUu,flEfggg,g9gDgQg^gkgxgf< ggf%g,g9gDgQg^gkgxg e6)CP]qTwQ2R} Z ÄgU~U~?Ã~*7U2T~,9= ::п `:b :}:r::_:: , 2sUwT 9 %ɌUsT|Q јTvQ0 3:g 6E:R:HGeY'UsT AQ UsڙUvT2LUvU2T1}U0T Qs9 ]  :% :}U0T QU,jjjjjjjjjkQk j jjjjjjjjkk S $Ä? cUTQvg{UsgUs^,[[[[}[ [$[$[>[,[>[3g[U|- TvQs,Y8YYYYYYYQYY@tUUTT,{X!#XXX-{X XXX՞U@T1[UU,x xxx oO/ʊ  ۊ@UsTvQ| xA hxxx߁1V۠O  o@iš%8ʊۊ@U}T|Qv yn yyzz~zA %Aˁ+5R %5ˁvT v $ &33$A %Aˁ+5R %5ˁvT v $ &33$  wODO X]%j v v[ v v v6 v vȦ v-vS K$% >#)&+v %O23@ v  v ڨ$ v $-v $*z1 ԩ"?o363A* @ 'n* A * A B1B( 1 : ; 9 I8 41B11 4: ;9 I 1RBUX YW  : ;9 IB 4: ;9 IB : ;9 I I: ; 9 I4: ;9 I1RBX YW .?<n: ; 9 4: ;9 I4: ;9 IBI41 U.: ;9 'I : ; 9 I!I/ .?: ;9 'I@B4: ; 9 I41 : ;9 I8 .?<n: ;9 I!: ;9 I" : ; 9 #: ;9 IB$1% & : ; 9 I'4: ; 9 I?<(.?: ;9 '@B) *: ;9 I+1RBX YW ,.1@B-1RBUX YW ..?: ; 9 'I 4/$ > 0(1 : ; 9 2: ;9 I34&I5 6.: ;9 'I@B7.: ;9 ' 8.?: ;9 'I 9'I:.: ;9 '@B; U<7I=!I/> 1?1B@B1A.?<n: ; B> I: ; 9 C : ; 9 D.?: ;9 'I@BE4: ;9 IF G5IH4: ;9 I?<I : ; I8 J<K : ;9 L : ; 9 I8M: ;9 IN 1UO 1PQ41 R'S1X YW T.?: ;9 '@BU 1UV4: ; 9 IW.: ; 9 'I X> I: ; 9 Y : ; 9 I8 ZB1[1UX YW \1RBX Y W ]: ; 9 I^% _$ > ` a : ; 9 b : ; 9 Ic'd&eIf : ; g: ; 9 h!i(j : ; 9 k : ; 9 l4G: ; 9 m'InB1o.?: ;9 'I@Bp4: ;9 I qrBs.: ;9 'I t.: ;9 ' u.: ;9 I v.?: ; 9 '@Bw: ; 9 IBx: ; 9 IBy4: ; 9 IBz4: ; 9 IB{1RBUX Y W |4: ; 9 I}1UX YW ~.?<n.?<n: ;9 6ddqd T)TuPPP(PPsPPKP[P"R+RRJQ^Q5Q5<v <Q{ PTt _X ~XX[TiT2TAXX[P[aQxT4T@PP{P{t XRr t;# $  %!r"p;# $  %!r"u?[gRSRbRHRQRR {RTKTiQX%vXvzr TiTTQq Ru .Q2QHQ+Q4QQoQQ;QQXP iR~Rv FRFW{ _Rz QK$KU$KKVKKUKIKTIKKSKK|hKKTK.KP.KPKQpKuKQuK}K?p K$KQ$KLKUpK}KU3KFK q 3KFK03KFKUQKpK8QKpK0QKpK\pKyK 7p yK}KQpK~K0pK}KUKK@KKUKKSKKVKKXKK0KKSKK|hJlJUlJJ]JJUJJ]JJUJJUJ0JT0JJSJJTJJTJJSJJTJJs@JJSJJSJJQJJ^JJQJJQJJ^JJ^7JTJPWJZJp?ZJaJPaJtJ\tJJPJJ_lJJUJJ | v"|JJ_|JJSJJTJJT|JJUJJ | v"JJ@JJSJJTJJs@JJ}JJ ~ JJQJJ\JJu`IIUII\IIUII\`IITIIT`IIQIIVIIvxIIVIIV`IIRII^IIRII^`IIXII]IIXII]dIITdIIUP@c@Uc@CVCrDUrDEVE.EU.EeEVeElFUlF;GV;GTIU@@P@@P@@P@APA0AS0ACAPVAiAP}AAPAAPAAPABP$B7BPKB^BPrBBPBBPBBPrDDSDDPDEPEEPEESlFFPDDsp"1DDP@@P@@PjApAPAAPAA0AAPBBPDDPDD0.E4EP:EQEP~@A0A!AP$AC\rDDPDD\DD0DD\DE0EE\lFF\FF0FH\H@I\EITI\@@P@@PAAPAAS5ACAP[AiAPAAPAAPBBP)B7BPPB^BPwBBPBBPBBPFGP"G,GP'CQCPE#EP HQHPFFPG!GP;GPGPPGTGUTGGVHHVHHQHHVI;IVEITIVFFPG!GPDGPGPPGTGUTGGVHHVHHQHHVI;IVEITIVWGpGPpGGSHHSI%IS%I6IP6I@ISEITISDGWG0DGPGPPGTGUTGWGV`GeG}eGpGQpGqG}`GpGPpGqGSGG@GG GGS]CtCP{C}C0G HP H HPfCtCPHHPHIS]>,?0,?C?]p;u<0<<P<=]=>]>,?0,?C?]p;u<0u<`=}=>}>>T>>}>,?0,?,?},?C?0p;u<0u<@=V@=V=PV==V==P=>V>>V>,?0,?0?V>?C?0p;`=S=:?S<< s $ &<<U=>0Z>c>0c>{>^{>>~>>~~>>~: ;U ;/;S/;0;U;;P99U9:S::U::S::U9S:\::S::@::6::W::4:: ::H4U4U U $$6U404^^ $^$6040000T9r0? $0404_\_\mm_ $_$60404K\KV\V\ $V$60SS 6S]] 6]USUSUST.V.T  wS  P ' S' W v(d r Pr x S     p`# p`# <$ c ~`# <$d x ~`# <$ vv" P c ^d x ^  \  0  P  S89P8:9QP+ PQQ + Q # 0 # 0 # P  U s U ) P) > S> k Pk n Sn r Pr s S 7L7UL77U 7H7TH7w7Vw7x7Tx77VM7Z7Px77P55U56V6?6U?66V66U66V66U56T6?6T?6F6TF66\66T66T66\66T66P66P66\T6g6Pg66S66UF66]66n2(3U(34\44U223T23(4V(404T044T223Q234]44Q63Y3PY3c3pc3t3Pt3~3^33p33P33S34P4,4,4h4L3p3Qp3~3R33Q33R3 4T 4 4tp 44T414^4(4V(404T0414T404|I4R4QR4S4VI4R4TR4S4]I4R4|_(l(Pl(v(u_(v(3_(l(ul(v(P''U''U''U''T''Q''T''T''Q''R''Q''QP''U''U''UP''T''Q''T''TP''Q''R''Q''Q0`U`SSU0`T`^TT0`Q`VQVQQ0`R`]R]RRD\~1$~"3$U"T $ &33$U"\~1$~"3$U"T $ &33$U"\`iP{P0%%U%&S&&}&+'U+'9'}9'@'U@'E'U0%%T%&_&9'}9'@'T@'E'}0%%Q%9'|9'@'Q@'E'|%%V%%vb%%0%%p 9'@'0%%Q&&Q%%P&&Pb%%0%%^%%~%&^&'}+'9'}9'@'0c&u&}u&&]&&}&&}&&]+'9'}K&&_+'9'_c&&S+'9'SK&X&V_&u&Vu&&}&&t&&T&&}#+'9'V%'\+'9'\&&P&'}+'9'}&&V&&v8$8&2$p"&& v8$8&2$p"c&c&5c&c& c&c&^#|$U|$$U$$U$ %U %%U%$%U#w#Tw#$S$$T$%S%%T%$%T#w#Qw#$V$$Q$%V% %Q %%V%%Q%$%Q##P##p$$0$$0$$^$%^<#w#0##r ##t %%0##Q$$q$!$qpI$Y$RY$m$q %%qp$$P$$P$%P<#w#0w##\##|#,$\,$_$|_$$\$%\ %%\%%0$!$T3$m$T %%T%%q`$!$X>$B$RB$$X %%X#$P %%P#$Y %%Y !U!7!S7!p!wp!{!{!!U!!S!*"w*""U""w !T uF!q!S!!S!!s""S""P""P{!!|I"o"|o""P{!!VD""V""v""V{!!_I""_{!!}D"d"}{!!]""]{!!^""^o""q2$u"""q2$u"o""v8$8&2$u"""v8$8&2$u"""v8$8&2$u"((U(=)S=)>)U>)Q)UQ)b)Sb))U()0) )P!)&) &)<)P>))0(( uu@()Q>)Q) uu@b)|) uu@()P( )s ))T))s()s()Pt u T p p# p`# tp# Q P 4 T2D2UD22S22~~22U22S22~~22U22U2D2TD22V22T22T22T22V22T22T2D2QD22]22Q22Q22Q22]22Q22Q2D2RD22\22R22R22R22\22R22R2)2u)22^22U#22^22U#22uU2Z2|Z2u2PU2u24U2u2^`U< ]< H UH b ]b k U`T< VH b V`Q5 SH [ S[ ^ sp^ b SP}q $ &}} $ &P\H b PP0< \H b \P\V 0 SH H S 0 VH H V 0 ^H H ^ PH b P  S  V  ^ZUZ^UH^H\UQTQ]TH]H\TZQZHQH\QZRZ\RH\H\RlSHS?ZSZ_H_HRSP\QTQZ]ZVUVVUHVH\TT__PPSS__UVU(4^(3 p $ &37 s $ &USUSUUSss $ &0yTyTMYQYn t2$x"#4nyRU)S)*UUPU0//U/0S0 0U 0#0S#0)0U./U/[/S[/\/U\/a/Ua/o/So/u/UWWUWXSXXUXYSYYUYPYSPYUYUY#YsY#YsY#YsY0Y Y#Ys U S"U"rSrU'T'V"]V]_P_rVrTdlP3  303}@3}S?LPL}\V]d2]d 3JP,2,U2,h,Vh,k,Uk,,V,<,T<,j,\j,k,Tk,,\,G,QG,,Q-,H,0H,L,Pk,,P,,R+:+U:++\++U++\+:+T:++^++T++^+:+Q:+V+SV++Q++P++p $  $-(q++ q++  U uh U T T q Rq w Rw y Ry R q Zw Z 0  [  p * X- q [q 0 0 T t  u|#- 4 T4 7 pD W T^ b tb q u|#q 00 C UC n Sn p Up w S0 G TG o Vo w TH _ P_ i sp u P U S U S U U S T V T V T V P P P0_U_VUV07T7\T\@JUJrVrvQvwU@UTUcScvRvwT@UV}U}V.U.VU@T|]|}T}.].5T5]v\S} S R.:v:\S\S P}Pv  \c c c\SWRWXuSWQWX]SWs} }d}S dUS.  (s U  S  U  S $ U$ * U Q$ * Q P ) P) * u t $ & P  \  \ T  V  V  ^  ^ P ] $ P \ V ^G P P U V U VU T _ T _T Q \ Q \Q R ^ R z^zRR P S %P%XSXdPdS R ] ]R U SS(S T VT9V 4}4]}*\kPS(P(QS*S04^0QTPThSsS'<'<S',},<\l\UvFQSs0s0s}Q | Q|V\dUdU}P_U_/0/LPLn__UdSPnSSPSdnPPQQRX))U)*^**U**U**U**U))T)*~**T**~**T**~))Q))w)*Q**Q**Q**Q**Q))Q))w)*Q))T)*~))U)*^**S)*~*`*_`*v*v**_&*f*Qf****}x**Qj**]**P{**P**]{**2{**w{**~{**P**]{**2D*T*qT*j*PD*j*6D*j*\,-U--V-T.UT..V..Q..U..U..V..U..V..U,- T.q. .. .. .. ,-W--ST.q.S..S..S..S,-U-{-V{--ST.q.S..U..V..S..V,V-0V-h-U..0r--P..P- - - -W{--_--\{--S{-- -.S*.T.S..S--P--V*.;.P;.T.V..P..V-- A--Sq..V..Q..U000U01S11U11S11U11S000T0111T1111T1111T11000Q00V01Q11Q11V11Q11V00V01Q11Q11V01111101S11S11S00]0 1T 11x1b1Tn11T11T01V11V000F1^F1R1rpR11^11^0-1_-151x511_11_0b1Yq11Y11Y11Y00R11R11 @00400T11V1111_45U5%5U%5/5U/55\55U55\55U45T5%5T%5F5TF55V55T55V55T45Q5%5Q%5P5QP55Q55Q55S55s55}%55S55}55S55P55st"%575P75F5st"1F5f5vs"1K5`5T`5b5tpb5f5Tq55Sq55Vq55|7 7U 77U77U7 7T 77T77T77U78U88U88U77T78V88T88V88T88V77Q78]88Q88]88Q88]77Q78]88Q88]88]77T78V88T88V88V77U7^8\88\K LU LWL_WLLULP_P$PU$POW_OWTWUTWW_LLP,LWL\LL\,LWLVLLV,LWLSLLS=LGLPLLP,L=L\,L=LV,L=LSLP_OPOW_TWW_qMMPLPSOPDUS\UOWSTWWSLL1LLPLLQ8MqMV8MqM\.MqM]NMXMPqMMP8MNMV8MNM\8MNM]MPSOP,RS\UUSV0VSW/WSMP_OP,R_\UU_V0V_W/W_MM p1OPQ p1MP\OP,R\\UU\V0V\W/W\MNVMNMNMNVMNMNMNPNONVNONNON!NONV!NON!NON8NONPyOO_RiR_RDU_\UV_5VV_4WOW_TWW_yOO#R,R#\UhU#yO{O0{OOPOOpOOPOOROPQ_OPQPOPkPpOPQpSPkPQkPyPp kPQp oPyPQyPPpyPQp}PPQPPpPPpPQp PPpPPpPQp PPpPPpPQpPPQPPpPPp PQp PPp!PPp$PQp$ PPp%PPp(PQp(PPQPPp)QEQPEQIQp"Q'Qp1$q""Q.Qp1$q"3QEQQ3QEQQ6QEQRiQQPQQppQRPpQRQQQPQQppQQPQRppQQRQQRQQRQQR\UU_iUUPvRRVvRR_RRPRU_UV_5VV_4WOW_TWW_RDS\DSGSPGSSwST\UU\UU0UU\RKS]KSSPSS~ST]UU]TUPRU0UV05VV04WOW0TWW0R SZ SSzhUUzhUU0 SSZUUZRRpRSXUUX_SS__SSz|_SSRSS~_SSz_SSzSS\SS}pSS@SS SS]TT0UV05VV0VV04WJW0TWW0WW0T T~UUP8VXV\VVVTT_UV_5VV_VV_4WJW_TWW_WW_^TpTPyTTPTTPTTPUUPUVVAVXVPiVVPVVPVVPVVVVVP4WIWPWWPWWVT2TP2TT]UUP5V@VP@VXV]XVzV0VV]VV]VVPTWW] TT_UU_XVzV_VV_TWW_ T3T 3T;TPTWgWPhWW_UUHUU0UU U4UU4UU4UUDU U4UPJP P$PU$PJP_.PJPP,d       9>ACFQxx| *)SX 05:@nOh"'3"'3TY}O[]dRV] 0 P P  0 P P {!!!"""{!!""`"h"p""""`"h"""%'0'9'.&5&B&G&c&c&_(e(l(v(((() )))* **`*f*{**D*D*I*Q*;+>+c+n+q++,,,-X.x.....,,- --.0.X...0111110000U2U2`2j2D3c3k3~333334%4,41464<4I4S455+5555q5w5{55777 8 888888s:}:::s:}:::::::::O<T<<<<<=>`>>@@@@BQC E0EFH HXHHHI;IEITIFGHHI;IEITIDGGHHI;IEITIQCChEpFH HXHHHIhEEXHHHIEpFHHdIdIxII_JJJJ|J|JJJJJJJJJJJJJJJpKpKuKwKyK~KKKKKKKKK,LWLLL0LWLLLWL\LL POPiSiSUUUUOWTWWMPOP,R\UUV5VW4WyOyOOOOP\PaPdPhPkP\PaPdPhPkPrPvPyPrPvPyPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQQQQQQQQQQQQQQQQQQQQQQQRiSiSUUV5VV4W@WEWOWTW`WcWWUSeSiSiSiSSSSUS_S_SeSiSiSiSSSSiSqSSSSSTTUV8VV4W@WEWOWTW`WcWWTTTTUUUV8VV4W@WEWOWTW`WcWW T;TUUTW`WcWW T;TTW`WcWWUUUUUDUYYYYY0YYYZ ZUZaZZZ@[]^_`_`8`` aHaaa0bstruct_FILE.hFILE.hstdio.hsys_errlist.hresource.hstruct_iovec.hsocket.hsocket_type.hsockaddr.htime.hpwd.hstruct_tm.htime.hunistd.hctype.hconfname.hgetopt_core.hstdint-uintn.hin.hnetdb.hun.hlsapidef.hstring.hresource.hdlfcn.hsocket.herrno.hselect2.hsched.hmman.hsendfile.huio.hstrings.hinet.hwait.hprctl.hgrp.h KK.K5J/I#KK1 0 z zJ Z " OJJ = ...v <K gfJ.T2KxJ.n=@<YDw<<=:/;<;/u;=IK=H</փ-K-=>:X-=;=0:/;=I<//sf=H</[G-K-=18=;=0:X;=-/I=;/?Gf-K-=I<-=;=-/e=-/t0//-</-</-</-<///-<///-J=t=Y-</ȑ-</J>Xtu-=ttu;/K-=-/X-/t;/gK-=Y-=;=J;=/K-=-/X;/u-=ttu-=K;</f;=;/fu-=t.V>,>t;=/.K-=-/t-=-//-/-X.I</t.W=-/0,0,<.W=-/t/t;=;/H ># K# = l Z< < h u$I$K="IY<IJ =$J$<=;"<J = vXF.L L = /d f.L u /O7@p$tik<=<>V L a$f mX Xm< .>m<X N1+ pk " kJJ k.XX"~K k  [ X O(kX  < kX  b>= E<>:<Y<; = vk<q R< !l   l<lz/ f X< Kffkv ~*~ X$ rJ~ # .?f h ~~<  .<1 ~) < ~t)X ~<= jtt        Z-JJXft X L!s gf  fF J Y Y :"foXXXJlt0 hd/ L. XN6g J yi< X$   Z  4tKK  ;:|". < Z IY6t(f+K"JMX"X< mJ< & AJX0J XXXV$J)I!4f<9X!Jh  .$r.XX`KJ Jt5<uY"J q<% 3$x.`XYBW[$g   F x \ *2. F^ \t;:j KK-uYIX Ki+JJK2KKu\/ u  u  (tX |  x(9?JL6J9xX<u1tu6,XJK,@g L,K /sJK u XQy  X KEW \ g x. < %  /s u Z ptt  /t.X  o tK !f J/ kt Zs gY  Z Y g Y  #!xwJKxJK K!JK sJ  s< ! KJ9J!JK!s  f K =J YYt YYt YYJ YY<xK t<YL ,<W ue [A<v v .KXe#!CJ;Cg K E dX ` x DNK$ JG MY<," g <    =  &> t u X   Y r< f Kr  < r rJ huJL |   fX.X  ]u u<   Z = = y<kJK,&J"Irt &s=r< !rff  "yJD!IK L%; K%H K KKK.7 .XB#I1u#J Q  F Z  KNJ U  X  hJ.$ .Xhr / X L*~Jf-S. LKI u YZ .HJ K Y)%fX80JJ )X%<XX$%4HJL<0YBL=;B=Vv<)/Mt z0<6u  zt/  L4K"vI4H =" @"F %#K%W Yz Q*uJf  uJ K mJJ .I  <vJ uMF =0J u) Y%#K,K"9 =& =X YsJY FX:JJ Z L N*<xX<JX>tJ e < 7/t  L4K xH4 = K *vJfJ  uJ  Y.W mJt mX K t Km \x JYKWiX<JJz NS =;0WX Y)? K  LeJf<Ki*_8tK )^ ~tf<_K z.` ztf< XKJZfv*=gJ Z AK=%, =%H KM, tY,Lho!(fot(= -K l X|K<x < o.K Ms f sf tJt    Z 93JJM _< . jy 93JJ Kw ' K"f/ s XM X X mXL  f   yr rX' =P Yr J:h6t YGu  uf>= . f  K  ^tj  !tJ<   jF % =%H K  Z7)K LK)8 K! K 2%o = K%: K2 GK  _X#< ]< <& Y ZX [f<Ȃ _Xy q   KK&,N>:hZs"  [sf  "Ui Xi g Y .. - sX ... K fh00< =  h+< Y  u<   Y Jz   . L+< g  /.  L g J JK*X.X v6= Y; u/ Xl f? lJXY lf"Kl "K8G8=P.4XK%      J.Jp<J*<X v6= Y;. / Xl f lJXY"=8G8= I/..c<<jBz<  sX&`" f [Z M   L  Y 0 U= =Y K ^f 4I gYK$/ fY L y^ /K-%]  K+/X>0XX<uj Yv Xg Y IgZ$Hv&L<X(.= /.u.Z .fJOwX(WuO=.ft"<*w  <K t Y /?N&tuKK  h g G] t Y t YtM   t  Y IgYJvYY g r Y >v t YK, <Y ._ho<x }KYWJtbXK X 9    ft "u ; <u WY rXu WY X"0", XX LXJ<f?JfjK t Y*=K t ,=K t 0=K t .=K t Y,=KgjKK 2K zt/ Y Z  c    Zc  cf  Zc <<   a,<  Zci  Zc x    Zc w X     c       Yc  v    Yc  v    Zc  w    Yc  v  Z [    Zc   g     Yb  f }r       g {  g1J }  <1-u-).K.X UJ.< Z .)J KIK XxK +zz< O=>;g< 0:>< Y6 2 _< < Z    \_<   _X<   _ @ /        J       f :v ZYw Yu    Zv  .X t   tXI/ /    u ~ft  Zr> Z J  z  X/X < zX   tX /  `ggWK>X u ~X~ }XYX |X |<Y ^  X ./ XR XUJ Y   h.eX> tYvtYK   M U -/](tq $~Zv <Qyt/Z t   t Z*(t N   bX J| < y  !#J Y  Z+KZ)=1K- M< <Y v.u. }Jt ZY< gJ f"<  /  np < }2NX)     ~ |X}Y"Xg![qg!p'Y>tYK&CXK%.ZY&i fYp<x u   Zv X w ~9}5Xl t.Z7j.+"<g7/W5K/I Mu_Kg\K _SC_THREAD_SPORADIC_SERVERpthread_atfork_functotalLSAPI_Set_Max_Process_Timelsapi_parent_dead__fxstatparseContentLenFromHeaderugidLen_SC_2_SW_DEVm_pScriptFileLSAPI_Stopsi_addr_lsb_unused2_SC_TIMERSm_iReqCounter_fileno_SC_SHELL_SC_MEMORY_PROTECTION_SC_SCHAR_MAX__pathtm_secH_AUTHORIZATION_SC_THREAD_SAFE_FUNCTIONS_SC_UCHAR_MAXmax_lenfreeaddrinfogid_tverifyHeader_SC_C_LANG_SUPPORTm_pIovecEndstrcpy__uint8_tIPPROTO_TPpw_uidwaitpidHTTP_HEADER_LEN_SC_TTY_NAME_MAX_SC_PASS_MAXLSAPI_ErrResponse_rsi_uidm_bytes_SC_2_PBS_TRACKfp_lve_destroym_pHeader_IO_buf_end__RLIM_NLIMITS_SC_SELECT_shortbufrlimitsockaddr_insa_family_tSOCK_DCCP_SC_BC_STRING_MAX_ISpunctis_enough_free_meminet_addr_SC_TRACE_INHERITinit_lve_exnewSizem_tmStartliblvesetgroups_SC_SEMAPHORES_SC_EQUIV_CLASS_MAXread__environ_sigpollsa_datauint16_t__builtin_memmoveai_protocol_valuem_pChildrenStatusCurIPPROTO_UDPoverflow_arg_areatime_tsin_zero_SC_DEVICE_SPECIFICin_port_t_flagsachMD5_SC_THREAD_THREADS_MAXerror_msg_SC_LEVEL3_CACHE_SIZE_SC_TRACEreg_save_areacalloc_archm_respPktHeaderg_running__off_t_addr_bndlsapi_cleanupachHeaderNamest_size_SC_THREAD_PROCESS_SHAREDallocateBuf_SC_JOB_CONTROLgetppidtm_isdstswapIntEndianlsapi_check_child_statussignal_locks_max_idle_secslsapi_set_nblockenvirons_schedule_notifysetUID_LVE_SC_NL_NMAX__RLIMIT_NPROCRLIMIT_DATApServeratoluint32_tinitgroups_SC_POLLm_pHttpHeader_SC_V6_ILP32_OFF32_SC_TRACE_SYS_MAXm_pScriptName__builtin_va_listst_blksizeRLIMIT_NOFILEm_pEnvList_SC_BASE_sigchldLSAPI_Set_Max_Idle_Childrenint32_t_SC_LONG_BITfixEndianLSAPI_GetEnv_r_upper__fmtsa_familym_specialEnvListSizepw_passwd_SC_CLOCK_SELECTIONmasklsapi_resp_infosigaction__RLIMIT_RTTIME_SC_V7_LPBIG_OFFBIGbodyLeftfcntllastTime_SC_AIO_LISTIO_MAXLSAPI_Init_Prefork_ServerpErr1pErr2st_gidm_cntHeaderss_notify_scheduledm_envListSizeacceptinggettimeofdaypBufai_addrm_iAvoidForks_secret_timerlsapi_MD5Context__syscall_slong_t__builtin_memset_SC_FILE_SYSTEMsa_restorerm_pChildrenStatusEnd_IO_write_endtype_SC_SCHAR_MIN_SC_LINE_MAXLSAPI_SetRespStatus_rlsapi_MD5_CTX__resst_nlinks_addr_SC_TZNAME_MAX__va_list_tag_syscallst_ctimnameLen__builtin___snprintf_chkLSAPI_Postfork_Child_SC_2_VERSIONfree_SC_2_PBS_CHECKPOINTIPPROTO_MPLS__sigset_tm_requestMethodOffm_tmWaitBeginreadSecretreadReq__tznameatoig_initedgetaddrinfovalLens_acklsapi_jailLVE__d0_SC_LEVEL4_CACHE_ASSOClsapi_MD5Final_SC_NL_LANGMAXdoAddrInfo__stack_chk_failmemcpy_killcurSizeRLIMIT_STACKIPPROTO_IPIPdlopenbacklogsin_family_SC_LEVEL1_ICACHE_ASSOCpIovrlim_maxm_iKillSentm_fdListen_SC_AIO_PRIO_DELTA_MAXvalidateHeadersst_atimm_statusm_reqBodyLensig_numoptargSOCK_RAWsnprintfold_int_SC_2_C_BINDs_enable_lve__clock_tparseRequestIPPROTO_RAWstrdupbufLen_SC_PRIORITY_SCHEDULING_SC_SS_REPL_MAXsys_errlistsival_ptrpStderrLogsetpgid__uid_tdaylightsi_stimeoptoptLSAPI_ReqBodyGetChar_rpKeysun_family__uint16_t_SC_FSYNCsin_portgetpeernameLSAPI_is_suEXEC_DaemonLSAPI_Is_Listen_rLSAPI_End_Response_r_SC_FILE_ATTRIBUTESsetreuidserverAddr_SC_NZEROm_pQueryString__gnuc_va_list_SC_2_C_DEV_chainpContentLen_call_addrEnvForeachnewfdm_iServerMaxIdleSOCK_NONBLOCKusleepSOCK_RDM_SC_SYMLOOP_MAXsockaddr_un_ISblankunsigned charIPPROTO_MAX_SC_MQ_OPEN_MAXSOCK_DGRAMm_tmReqBegin__fd_mask__blkcnt_tlsapi_enterLVE__builtin_calloc_IO_lock_tLSAPI_Is_ListenIPPROTO_COMPLSAPI_key_value_pairlsapi_check_pathLSAPI_ForeachHeader_rpHeaderName_SC_SEM_NSEMS_MAX_SC_USHRT_MAXLSAPI_FinalizeRespHeaders_r__read_alias__fdelt_chkshouldFixEndianpBody_SC_STREAM_MAX_SC_ASYNCHRONOUS_IOserverMaxIdle__open_alias_SC_READER_WRITER_LOCKS_SC_CPUTIME__getcwd_alias_SC_2_PBS_LOCATE_SC_DEVICE_IOsa_flagspVecgeteuid_SC_SIGNALS__ctype_b_loc_SC_V7_ILP32_OFFBIGstatusoff_tchild_statuss_notified_pids_max_reqsH_X_FORWARDED_FORs_pid_dump_debug_info_ISalpha__fprintf_chktm_zone__mode_tm_queryStringOff_SC_V7_LP64_OFF64_SC_NPROCESSORS_CONF__RLIMIT_SIGPENDINGfdInlsapi_changeUGidtv_usec_SC_XOPEN_XCU_VERSIONold_childold_termLSAPI_sendfile_rlsapi_lve_erroraccept_SC_MEMLOCKallocateRespHeaderBuf_ISprintsched_yieldpMessages_liblvepValueH_CONTENT_LENGTHm_tmLastCheckPoint__vfprintf_chk_ISalnum_SC_SEM_VALUE_MAXs_req_processedstrtollopen_SC_XOPEN_XPG2_SC_XOPEN_XPG3_SC_XOPEN_XPG4LSAPI_STATE_CONNECTED_IO_write_ptr_SC_REALTIME_SIGNALSsystemlsapi_packet_headerIPPROTO_ENCAP_ISspacelsapi_suexec_authgetLFg_prefork_serverva_list__suseconds_treqsexitLSAPI_CreateListenSock2__rlim_ts_ignore_pid__RLIMIT_MEMLOCKpCurpHeaderValue__sizesizes_slow_req_msecslsapi_init_children_statusgetuidFILEH_COOKIELSAPI_ParseSockAddrdlsympthread_lib_SC_PII_INTERNET_DGRAM_SC_SINGLE_PROCESSbyteReversedump_debug_infoLSAPI_Accept_Before_Fork_SC_SHRT_MAX_ISxdigit_SC_RAW_SOCKETSfp_lve_enterLSAPI_AppendRespHeader_rsize_tH_CONNECTIONLSAPI_GetHeader_r_SC_MULTI_PROCESSs_stderr_log_pathm_statefp_lve_instance_init_SC_BC_BASE_MAXH_CONTENT_TYPELSAPI_STATE_ACCEPTING_SC_RTSIG_MAX_SC_NETWORKINGachCmdH_ACCEPT_SC_GETGR_R_SIZE_MAXperrorcompareValueLocation_SC_THREAD_ATTR_STACKADDR_SC_LEVEL2_CACHE_ASSOC_SC_IOV_MAX_SC_TRACE_EVENT_NAME_MAX_SC_PII_INTERNETIPPROTO_IGMPpServerAddrlsapi_acceptlsapi_initLVE_IO_save_baseLSAPI_Release_riovecold_usr1maxIdleChldsocklen_tm_iMaxChildren_SC_2_UPEai_canonnameIPPROTO_IPV6_SC_DELAYTIMER_MAXpw_dirsa_mask__sigval_tLSAPI_Set_Extra_Childrens_restored_ppidsin6_flowinfototalLenm_pid_SC_SYSTEM_DATABASElsapi_prefork_server_acceptm_pIovecToWritecodem_respHeaderLen_wide_dataH_IF_MATCHai_family__nlink_tsi_addrst_inost_modeLSAPI_IsRunning_SC_T_IOV_MAXCGI_HEADER_LENIPPROTO_DCCP__in6_usysconfGNU C17 8.5.0 20210514 (Red Hat 8.5.0-18) -mtune=generic -m64 -march=x86-64 -g -O2 -fPIC -fexceptions -fstack-protector-strong -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection=full -fplugin=gcc-annobinGetHeaderVarH_ACC_CHARSET__stream_SC_XOPEN_STREAMSm_iMaxIdleChildrensendfile_IScntrlm_reqBufSizelsapi_child_statusprctlallocateEnvList_ISupperpStatuserr_nosival_intsi_codem_pReqBufwait_timestrcasecmpH_IF_UNMOD_SINCEpw_name_SC_TRACE_USER_EVENT_MAX__socklen_tsend_notification_pktlsapi_requestpKeyEndcurTimefprintflsapi_writev__ssize_t__srclsapi_closepChrootH_IF_RANGEtimespecnameOff__u6_addr8strerror__RLIMIT_RSSavoidForkm_packetLenLSAPI_ReadReqBody_rIPPROTO_MPTCP_SC_2_FORT_RUNbindfp_lve_leave__valin6_addr_SC_ADVISORY_INFOpacketLen__timezone__ctype_toupper_locsin6_addr_SC_TIMER_MAXpBufCur_SC_THREADSunset_lsapi_envs__sighandler_t_SC_USER_GROUPS_RLSAPI_Set_Server_fdLSAPI_CreateListenSock__RLIMIT_LOCKSm_respPktHeaderEndLSAPI_On_Timer_pfLSAPI_Set_Max_Reqs_SC_UINT_MAXst_uids_conn_close_pktLSAPI_Postfork_ParentpEndpktTypelsapilib.cset_skip_write_SC_TRACE_NAME_MAX_lowers_busy_workers_SC_THREAD_DESTRUCTOR_ITERATIONSm_flagmemsetlevelstderrm_pHeaderIndexnameidle_SC_CHILD_MAXlsapi_reopen_stderr2_IO_save_endtm_min__nptrLSAPI_InitLSAPI_Request_SC_V6_LP64_OFF64flag_SC_NGROUPS_MAXm_bufProcessedfixHeaderIndexEndianstdoutfp_offsetlsapi_MD5TransformLSAPI_Write_Stderr_r__time_t_SC_THREAD_ROBUST_PRIO_INHERITgp_offset_padLSAPI_ForeachOrgHeader_rsigaddsetLSAPI_Inc_Req_Processedm_httpHeaderLendyingrealpathtm_yday_SC_SSIZE_MAX_SC_PII_OSI_CLTS_SC_SYSTEM_DATABASE_RmsecspAuth_SC_LEVEL1_DCACHE_SIZEkeyLenextraChildrenLSAPI_Flush_rshort unsigned intrlim_cursigned charLSAPI_Reset_rs_lveold_ppidLSAPI_CB_EnvHandler_valueLen__blksize_t_SC_STREAMSSOCK_STREAMdigestpBufEnd_SC_PAGESIZE_SC_THREAD_PRIORITY_SCHEDULINGcountsi_pidIPPROTO_MTPs_stop_SC_CHARCLASS_NAME_MAXlsapi_header_offsetstrchrvfprintfsetgid_boundstm_wday__off64_t__fd__lenachBuf_sigsys_IO_read_base_SC_XBS5_ILP32_OFFBIGsend_req_received_notification_offsetIPPROTO_EGPLSAPI_reset_server_statesockaddrsigset_ts_defaultGids_keep_listenersecsm_cntUnknownHeadersreadfdsai_addrlenlongsopterr_SC_DEVICE_SPECIFIC_RLSAPI_Set_Restored_Parent_Pidpw_gecos_modem_iExtraChildrenLSAPI_No_Check_ppid_SC_PIPE_IO_write_base_SC_XOPEN_CRYPTvalueLenm_respInfotz_dsttime_SC_PHYS_PAGESlsapi_enable_core_dumpH_CACHE_CTRLH_COOKIE2_SC_ATEXIT_MAX__desttm_monclose_SC_SHRT_MIN_SC_FIFObitstimeH_USERAGENTs_min_avail_pages_SC_USER_GROUPSm_lLastActiveLSAPI_ForeachEnv_rlong intSOCK_PACKETsa_sigactionnotify_req_received_SC_XBS5_ILP32_OFF32dumps_worker_status_IO_marker__builtin_strncpys_ppidtm_yearlimitmax_children_SC_2_PBS_MESSAGEm_pRespBufEndtimevalorig_masktmCur_SC_XOPEN_REALTIME_THREADSfp_lve_is_availablepAddrs_defaultUidm_pChildrenStatus__fds_bits_SC_SPIN_LOCKSLSAPI_Set_Server_Max_Idle_Secswritem_bufRead_SC_SPORADIC_SERVERlsapi_close_connectionuint8_t_SC_LEVEL1_DCACHE_LINESIZE__sigaction_handlerlsapi_signal_SC_PRIORITIZED_IOin_addrSOCK_SEQPACKET__pid_t_IO_codecvt_SC_GETPW_R_SIZE_MAXpUgidheadershints_SC_XOPEN_VERSIONH_RANGE_SC_BC_SCALE_MAX_SC_2_C_VERSIONdup2strtolg_reqlong doubleparseEnvai_socktype_SC_THREAD_KEYS_MAXiov_len_SC_LEVEL4_CACHE_LINESIZEfd_setlsapi_MD5Init_SC_NL_TEXTMAXnonblocklong unsigned intlsapi_req_header_SC_LOGIN_NAME_MAXfind_child_statusIPPROTO_PIM_SC_XBS5_LP64_OFF64_SC_SPAWNmaxChildrennewlensi_statussigemptyset_pkeym_headerOff__RLIMIT_OFILEHTTP_HEADERS_SC_2_PBSs_proc_group_timer_cbpw_gid__errno_location_SC_XBS5_LPBIG_OFFBIG_SC_WORD_BITchar_SC_2_PBS_ACCOUNTINGm_pSpecialEnvListsin6_scope_idstdin_SC_AIO_MAX__oflag_SC_2_CHAR_TERMresolved_path_SC_LEVEL1_ICACHE_LINESIZE_IO_buf_baseai_flagsrealloc_SC_XOPEN_SHM__dev_t_SC_XOPEN_ENH_I18Nold_quitRLIMIT_CPU__glibc_reserved_IO_read_end_SC_ULONG_MAX_SC_TYPED_MEMORY_OBJECTS_SC_TIMEOUTS_SC_LEVEL2_CACHE_SIZEfinal_SC_XOPEN_UNIXm_pRespBufPos_IO_FILEin_addr_tm_fdH_HOST_IO_wide_datacookiestrlentzname_sifields_SC_LEVEL2_CACHE_LINESIZE__u6_addr16s_pidIPPROTO_AHLSAPI_ReqBodyGetLine_rtm_hoursetsidFlush_RespBuf_r_SC_THREAD_STACK_MINisPipe_SC_PII_OSI_Mm_respHeaders_global_counterRLIMIT_AS_SC_NL_MSGMAXsi_signom_pAppData__RLIMIT_MSGQUEUEachAddrm_inProcess_SC_THREAD_ROBUST_PRIO_PROTECT_ISgraph_lsapi_prefork_servertm_mdaypIntegerlsapi_siguser1__pad0_SC_BC_DIM_MAX__pad5_SC_LEVEL1_DCACHE_ASSOCmallocs_dump_debug_infos_avail_pages__u6_addr32_headerInfom_typesi_errnofinish_closelistensigno_SC_XOPEN_REALTIME_markersLSAPI_InitRequest_SC_SAVED_IDSpBindm_scriptFileOff_SC_INT_MAXsi_bands_log_level_namess_skip_writeH_VIAmemccpy_codecvtforkIPPROTO_ESPm_pRespHeaderBufEnd_SC_TRACE_LOGgetpwnamtimeout_SC_THREAD_PRIO_PROTECTg_fnSelectRLIMIT_FSIZE__builtin_memcpyst_rdevlsapi_http_header_indexpEnv_SC_OPEN_MAXst_devssize_tdlerrorheaderIndex_SC_UIO_MAXIOVLSAPI_Logm_pRespHeaderBuf__int32_tH_PRAGMA__uint32_tqsortpSecretFile__RLIMIT_NLIMITS__daylightIPPROTO_RSVPstrncpyH_REFERERIPPROTO_UDPLITESOCK_CLOEXECLSAPI_Set_Slow_Req_MsecsLSAPI_Prefork_Accept_r_sys_siglisthandler_SC_CHAR_MAXLSAPI_Get_ppid_ISlowerpEnvEndsigprocmaskm_pUnknownHeadergetpwuidm_reqState_SC_PII_XTIpRespHeadersleftkill/builddir/build/BUILD/opt/alt/ruby27/share/gems/gems/ruby-lsapi-5.5/ext/lsapim_pRespBufm_iCurChildrensocketLSAPI_Write_r_SC_PII_OSI_COTSm_totalLenpasswdm_pIovecs_stderr_is_pipefstat__snprintf_chk_SC_PII_SOCKET__gid_tlsapi_sigpipe_SC_V6_LPBIG_OFFBIG_SC_MQ_PRIO_MAXgetcwdH_TRANSFER_ENCODINGH_IF_MODIFIED_SINCE__bsxai_nexts_enable_core_dump_SC_TRACE_EVENT_FILTERnodelaysin6_family__resolved_freeres_buf_sigfaultm_iChildrenMaxIdleTime_SC_THREAD_CPUTIMEsi_utimetv_sec_SC_VERSIONm_cntSpecialEnv_SC_C_LANG_SUPPORT_Rlong long unsigned intmemmovesa_handlersin_addr_cur_columnlsapi_load_lve_libtoWriteuid_t_SC_PIIsi_fd_SC_MAPPED_FILES_SC_LEVEL4_CACHE_SIZEIPPROTO_BEETPHfp_lve_jail_SC_2_FORT_DEVIPPROTO_IPm_pRespHeaderBufPosst_blockslsapi_initSuEXEC__bswap_16getpid__buf_SC_2_LOCALEDEFm_cntEnvlocaltime_r_SC_LEVEL1_ICACHE_SIZEreadBodyToReqBuftm_gmtoffIPPROTO_PUP_namesigval_IO_backup_baseH_KEEP_ALIVE_IO_read_ptr_SC_CHAR_BITLSAPI_Register_Pgrp_Timer_Callbackmd5ctx__socket_type__nbytes_nameLengetenv_freeres_list__aps_max_busy_workersIPPROTO_ETHERNETH_IF_NO_MATCHpEnvListrlim_tlsapi_readsun_pathtimezoneCGI_HEADERSsi_overrun__bswap_32pReq_SC_INT_MINlsapi_MD5Update_SC_RE_DUP_MAX_SC_PII_INTERNET_STREAMachBodyachPeerheader_SC_THREAD_ATTR_STACKSIZEfull_path_old_offset_SC_SIGQUEUE_MAXsiginfo_t_SC_FD_MGMTexpect_connected_SC_SYNCHRONIZED_IOLSAPI_STATE_IDLEvalueOffsighandler_t_SC_V7_ILP32_OFF32skipunlinksend_conn_close_notificationoptinds_accept_notifywritevH_ACC_LANG_SC_EXPR_NEST_MAX_SC_LEVEL3_CACHE_LINESIZElong long intm_pktHeaderin6addr_loopbackports_accepting_workersIPPROTO_IDP_flags2lsapi_prefork_serverallocateIovec_SC_MESSAGE_PASSING__ch_SC_REGEX_VERSIONm_iLenLSAPI_Set_Max_Children__d1setuidtv_nsecm_scriptNameOfflsapi_perror_SC_FILE_LOCKING_SC_AVPHYS_PAGES_SC_MB_LEN_MAXpHeader_ISdigitsockaddr_in6IPPROTO_SCTP_SC_PII_OSI_SC_ARG_MAX__ino_tsetsockopt_SC_MEMLOCK_RANGELSAPI_Finish_r_SC_SHARED_MEMORY_OBJECTSlsapi_resp_headersys_nerrin6addr_anym_pRequestMethodachError_SC_CHAR_MIN__realpath_chkiov_basem_lReqBegins_uids_total_pagespw_shell__namem_versionB0m_versionB1IPPROTO_GRE_SC_XOPEN_LEGACY_SC_NL_ARGMAXRLIMIT_COREsi_tidtobekilled_SC_THREAD_PRIO_INHERIT_SC_LEVEL3_CACHE_ASSOC_SC_NPROCESSORS_ONLNm_headerLenexpect_acceptingm_pIovecCurfdListenLSAPI_Init_Env_Parametersaddr_len_SC_HOST_NAME_MAXIPPROTO_TCPLSAPI_AppendRespHeader2_r_SC_COLL_WEIGHTS_MAX_SC_MONOTONIC_CLOCK__rlimit_resourcem_reqBodyReadLSAPI_Set_Max_Idle_SC_CLK_TCKLSAPI_ForeachSpecialEnv_rlsapi_buildPacketHeaderLSAPI_perror_r_SC_NL_SETMAXunsigned int_SC_BARRIERSbodyLenpBeginLSAPI_Accept_rwait_secslsapi_reopen_stderrstrcmpst_mtim__statbuf__RLIMIT_NICEfn_select_tshort intlsapi_notify_pidsi_sigvalsetrlimit_vtable_offsetaddrinfo_SC_IPV6mmapIPPROTO_ICMPlsapi_sigchild_SC_REGEXPlsapi_schedule_notifyLSAPI_Get_Slow_Req_Msecs_SC_V6_ILP32_OFFBIGstatmemchrtz_minuteswestsys_siglistH_ACC_ENCODINGsin6_portm_iMaxReqProcessTime__RLIMIT_RTPRIOGCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-18)GNUzRx 0D LXsEIB E(A0z (A BBBI A (D BBBA  @YGJB B(A0A80F(B DBb0BFC G  AABK Hk(\GADJ n AAA 4UAGK R CAG L JCG AG] AJ t C KFLBBE A(H0H (D BBBD  (D BBBA PXvFB A(D0D (A BBBB L(A BBBA$aAAD XAAHBBB B(A0A8D@N 8C0A(B BBBH $ OAf Q C E H@HYBBB A(D0J 0A(A BBBF xFEA C(G   (A ABBD M I c A  E M A k E E E E H V HFBB B(A0A8D`` 8A0A(B BBBD lT+BBB B(A0D8JYHPC Mi 8A0A(B BBBE LTMDd6BBB B(A0A8DP 8A0A(B BBBG  8J0H(G DBBK $,7EFF IIOTh|  4FAA G>  AABG EO D  A  (Y<JEDXS l]Ph H XAHlFBB B(A0A8LP 8A0A(B BBBH < FBB A(A0 (D BBBI i`0FBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH L$FBB A(A0H Q D 0A(A BBBH LFBB B(A0A8G 8A0A(B BBBF 4FHF\$pnCXJLlFBB B(A0A8DA 8A0A(B BBBA `BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0L BMD GL  AABA < =BAA G L@I@U  AABG $ TWEHG ag H SH FBB B(A0A8DPS 8D0A(B BBBF TX bIE D(C0P (F BBBM Q(H BBBAH FBB B(A0A8DP 8A0A(B BBBA T CBA A(G0` (A ABBD  (C ABBA J8T -FBD D(D@T (A ABBB  ( lECGF AAI L !cBG A(D0 (A ABBE XD0 4 ZH 10\ pFAA G@7  AABF  @LsL FBB B(A0A8G 8A0A(B BBBG   $ 8 L ` t     <  FBA K(G (A ABBG <FEE D(D0M (C BBBB X(HlFBH E(A0E8I@ 8A0A(B BBBE (FED ABH BBB B(A0A8G 8A0A(B BBBJ D0FBB A(A0G 0A(A BBBF Lx FBB B(A0A8G  8A0A(B BBBA    1 -  E2a~345.IWul -- "0s-Je s z )Y)2L0Yz+ k + w 0 Gw : X Ui s  s    x 5 P _ s(0x *  * # N0 al |  O& - =h9Y9 @ $@O e` rU+66 %  7 6S wm w   l      4 f   x    ]  '  ; ]\ m{ m     *+ *L k    \ \" k C k b    "   " $%@ `d0$%UE'xdE'''''D(m())* *+7+F+c,~, 0,.,=.u/*7u/[)0})011224C4k55667!7G7k78d X 8 8+8S:9y:9q9P q9: #h 3 (B:g0;0;H?   @  H?'^?GR^?tk?k????,?V?~???@,@T@z @+@+@?@?@;K@WK@TI ) p h d ` P H @# 80 X6TIYIzIJJJJ K(K?WTK \(b $o(|WUYUYZd Zd>qdiqdd!#$&()+2345671828F"KO(pRP [oy#)/5;AG8MXSY_ekqw+}=Nbw*@V %]+o17=CpIO@U[Tahgtms8yp6&(P,-./0) >Mcmy 1   " / 9 @C R a h v      @7      ! !'! #S!3!8!C!RK!@ Q!X!^!` p!p!Y!J!!0S!]!l!!!` "p i" %","@"#$Y"_"0%u"P'F"'F"'"(")l""""# #.#/1#00?#2P#Y#2s#z#4#5-#####7# 7l#7! $$$!$85$8ZN$@91a$9pv$:@$$0;$$$$P?$`? $p?%?%?:%?V%?u%@ % @ %0@%@@ %P@ %%%%&&& &`I4&I(B&JR&Ka&j&q&{&&&&&W&`Y &&&`d&d '.annobin_lsapilib.c.annobin_lsapilib.c_end.annobin_lsapilib.c.hot.annobin_lsapilib.c_end.hot.annobin_lsapilib.c.unlikely.annobin_lsapilib.c_end.unlikely.annobin_lsapilib.c.startup.annobin_lsapilib.c_end.startup.annobin_lsapilib.c.exit.annobin_lsapilib.c_end.exit.annobin_lsapi_sigpipe.start.annobin_lsapi_sigpipe.endlsapi_sigpipe.annobin_lsapi_siguser1.start.annobin_lsapi_siguser1.endlsapi_siguser1g_running.annobin_compareValueLocation.start.annobin_compareValueLocation.end.annobin_EnvForeach.start.annobin_EnvForeach.endEnvForeach.annobin_lsapi_cleanup.start.annobin_lsapi_cleanup.endlsapi_cleanups_stop.annobin_set_skip_write.start.annobin_set_skip_write.ends_skip_write.annobin_lsapi_MD5Transform.start.annobin_lsapi_MD5Transform.endlsapi_MD5Transform.annobin_lsapi_signal.start.annobin_lsapi_signal.endlsapi_signal.annobin_find_child_status.start.annobin_find_child_status.endfind_child_statusg_prefork_server.annobin_allocateRespHeaderBuf.start.annobin_allocateRespHeaderBuf.endallocateRespHeaderBuf.annobin_lsapi_set_nblock.start.annobin_lsapi_set_nblock.endlsapi_set_nblock.annobin_lsapi_accept.start.annobin_lsapi_accept.endlsapi_accept.annobin_parseEnv.start.annobin_parseEnv.endparseEnv.annobin_lsapi_init_children_status.start.annobin_lsapi_init_children_status.endlsapi_init_children_statuss_busy_workerss_accepting_workerss_avail_pagess_global_counter.annobin_readBodyToReqBuf.part.2.start.annobin_readBodyToReqBuf.part.2.endreadBodyToReqBuf.part.2.annobin_lsapi_close_connection.isra.4.start.annobin_lsapi_close_connection.isra.4.endlsapi_close_connection.isra.4s_worker_status.annobin_lsapi_writev.part.6.start.annobin_lsapi_writev.part.6.endlsapi_writev.part.6.annobin_lsapi_parent_dead.start.annobin_lsapi_parent_dead.endlsapi_parent_deads_ppids_restored_ppid.annobin_LSAPI_ParseSockAddr.part.13.start.annobin_LSAPI_ParseSockAddr.part.13.endLSAPI_ParseSockAddr.part.13.annobin_LSAPI_Log.start.annobin_LSAPI_Log.ends_stderr_is_pipes_log_level_namess_pid.annobin_lsapi_sigchild.start.annobin_lsapi_sigchild.endlsapi_sigchilds_pid_dump_debug_infos_ignore_pid.annobin_dump_debug_info.start.annobin_dump_debug_info.end.annobin_lsapi_check_child_status.start.annobin_lsapi_check_child_status.endlsapi_check_child_statuss_max_idle_secss_dump_debug_info.annobin_lsapi_perror.start.annobin_lsapi_perror.end.annobin_LSAPI_is_suEXEC_Daemon.start.annobin_LSAPI_is_suEXEC_Daemon.ends_uids_secret.annobin_LSAPI_Stop.start.annobin_LSAPI_Stop.end.annobin_LSAPI_IsRunning.start.annobin_LSAPI_IsRunning.end.annobin_LSAPI_Register_Pgrp_Timer_Callback.start.annobin_LSAPI_Register_Pgrp_Timer_Callback.ends_proc_group_timer_cb.annobin_LSAPI_InitRequest.start.annobin_LSAPI_InitRequest.end.annobin_LSAPI_Init.start.annobin_LSAPI_Init.endg_initedpthread_atfork_func.annobin_LSAPI_Is_Listen_r.start.annobin_LSAPI_Is_Listen_r.end.annobin_LSAPI_Is_Listen.start.annobin_LSAPI_Is_Listen.end.annobin_LSAPI_Reset_r.start.annobin_LSAPI_Reset_r.end.annobin_LSAPI_Release_r.start.annobin_LSAPI_Release_r.end.annobin_LSAPI_GetHeader_r.start.annobin_LSAPI_GetHeader_r.end.annobin_LSAPI_ReqBodyGetChar_r.start.annobin_LSAPI_ReqBodyGetChar_r.end.annobin_LSAPI_ReqBodyGetLine_r.start.annobin_LSAPI_ReqBodyGetLine_r.end.annobin_LSAPI_ReadReqBody_r.start.annobin_LSAPI_ReadReqBody_r.end.annobin_Flush_RespBuf_r.start.annobin_Flush_RespBuf_r.end.annobin_LSAPI_GetEnv_r.start.annobin_LSAPI_GetEnv_r.endCGI_HEADERS.annobin_LSAPI_ForeachOrgHeader_r.start.annobin_LSAPI_ForeachOrgHeader_r.endHTTP_HEADERSHTTP_HEADER_LEN.annobin_LSAPI_ForeachHeader_r.start.annobin_LSAPI_ForeachHeader_r.endCGI_HEADER_LEN.annobin_LSAPI_ForeachEnv_r.start.annobin_LSAPI_ForeachEnv_r.end.annobin_LSAPI_ForeachSpecialEnv_r.start.annobin_LSAPI_ForeachSpecialEnv_r.end.annobin_LSAPI_FinalizeRespHeaders_r.start.annobin_LSAPI_FinalizeRespHeaders_r.end.annobin_LSAPI_Flush_r.start.annobin_LSAPI_Flush_r.end.annobin_LSAPI_Write_Stderr_r.start.annobin_LSAPI_Write_Stderr_r.ends_stderr_log_path.annobin_LSAPI_perror_r.start.annobin_LSAPI_perror_r.endLSAPI_perror_r.annobin_lsapi_jailLVE.start.annobin_lsapi_jailLVE.endlsapi_jailLVEfp_lve_jail.annobin_lsapi_reopen_stderr.start.annobin_lsapi_reopen_stderr.endlsapi_reopen_stderr.annobin_LSAPI_Finish_r.start.annobin_LSAPI_Finish_r.endfinish_close.annobin_LSAPI_End_Response_r.start.annobin_LSAPI_End_Response_r.end.annobin_LSAPI_Write_r.start.annobin_LSAPI_Write_r.end.annobin_LSAPI_sendfile_r.start.annobin_LSAPI_sendfile_r.end.annobin_LSAPI_AppendRespHeader2_r.start.annobin_LSAPI_AppendRespHeader2_r.end.annobin_LSAPI_AppendRespHeader_r.start.annobin_LSAPI_AppendRespHeader_r.end.annobin_LSAPI_CreateListenSock2.start.annobin_LSAPI_CreateListenSock2.end.annobin_LSAPI_ParseSockAddr.start.annobin_LSAPI_ParseSockAddr.end.annobin_LSAPI_CreateListenSock.start.annobin_LSAPI_CreateListenSock.end.annobin_LSAPI_Init_Prefork_Server.start.annobin_LSAPI_Init_Prefork_Server.ends_max_busy_workersg_fnSelects_total_pages.annobin_LSAPI_Set_Server_fd.start.annobin_LSAPI_Set_Server_fd.end.annobin_LSAPI_reset_server_state.start.annobin_LSAPI_reset_server_state.end.annobin_is_enough_free_mem.start.annobin_is_enough_free_mem.ends_min_avail_pages.annobin_LSAPI_Postfork_Child.start.annobin_LSAPI_Postfork_Child.ends_req_processeds_keep_listeners_notified_pid.annobin_LSAPI_Postfork_Parent.start.annobin_LSAPI_Postfork_Parent.end.annobin_LSAPI_Accept_Before_Fork.start.annobin_LSAPI_Accept_Before_Fork.endold_childold_termold_intold_usr1old_quit.annobin_LSAPI_Set_Max_Reqs.start.annobin_LSAPI_Set_Max_Reqs.ends_max_reqs.annobin_LSAPI_Set_Max_Idle.start.annobin_LSAPI_Set_Max_Idle.end.annobin_LSAPI_Set_Max_Children.start.annobin_LSAPI_Set_Max_Children.end.annobin_LSAPI_Set_Extra_Children.start.annobin_LSAPI_Set_Extra_Children.end.annobin_LSAPI_Set_Max_Process_Time.start.annobin_LSAPI_Set_Max_Process_Time.end.annobin_LSAPI_Set_Max_Idle_Children.start.annobin_LSAPI_Set_Max_Idle_Children.end.annobin_LSAPI_Set_Server_Max_Idle_Secs.start.annobin_LSAPI_Set_Server_Max_Idle_Secs.end.annobin_LSAPI_Set_Slow_Req_Msecs.start.annobin_LSAPI_Set_Slow_Req_Msecs.ends_slow_req_msecs.annobin_LSAPI_Get_Slow_Req_Msecs.start.annobin_LSAPI_Get_Slow_Req_Msecs.end.annobin_LSAPI_No_Check_ppid.start.annobin_LSAPI_No_Check_ppid.end.annobin_LSAPI_Get_ppid.start.annobin_LSAPI_Get_ppid.end.annobin_LSAPI_Init_Env_Parameters.start.annobin_LSAPI_Init_Env_Parameters.ends_accept_notifys_enable_core_dumps_defaultUids_defaultGids_enable_lves_liblvefp_lve_is_availablefp_lve_instance_initfp_lve_enters_lve.annobin_LSAPI_ErrResponse_r.start.annobin_LSAPI_ErrResponse_r.end.annobin_lsapi_MD5Init.start.annobin_lsapi_MD5Init.end.annobin_lsapi_MD5Update.start.annobin_lsapi_MD5Update.end.annobin_lsapi_MD5Final.start.annobin_lsapi_MD5Final.end.annobin_readReq.start.annobin_readReq.endreadReqs_ackachBody.7025headers.7024.annobin_LSAPI_Accept_r.start.annobin_LSAPI_Accept_r.end.annobin_LSAPI_Prefork_Accept_r.start.annobin_LSAPI_Prefork_Accept_r.ends_conn_close_pkt.annobin_LSAPI_Set_Restored_Parent_Pid.start.annobin_LSAPI_Set_Restored_Parent_Pid.end.annobin_LSAPI_Inc_Req_Processed.start.annobin_LSAPI_Inc_Req_Processed.end.LC0.LC1.LC4.LC5.LC6.LC3.LC2.LC7.LC8.LC9.LC10.LC11.LC12.LC13.LC14.LC15.LC16.LC17.LC18.LC19.LC20.LC21.LC22.LC23.LC24.LC25.LC26.LC27.LC31.LC32.LC30.LC29.LC33.LC34.LC36.LC37.LC38.LC39.LC40.LC41.LC42.LC44.LC45.LC46.LC47.LC48.LC49.LC50.LC51.LC59.LC69.LC70.LC71.LC43.LC35.LC61.LC62.LC63.LC64.LC65.LC66.LC67.LC68.LC52.LC53.LC54.LC60.LC58.LC57.LC55.LC56.LC87.LC76.LC77.LC78.LC72.LC79.LC80.LC86.LC74.LC84.LC83.LC73.LC75.LC82.LC81.LC85.LC92.LC91.LC88.LC90.LC89.text.group.text.hot.group.text.unlikely.group.text.startup.group.text.exit.groupcompareValueLocationset_skip_write_GLOBAL_OFFSET_TABLE_sigactionsigemptyset__stack_chk_failreallocfcntlsetsockoptmmapmemsetsetsidread__errno_locationwritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkstrdupLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamenvirondlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectd \D   h o    2 9 H $O ,T g -o    h C M X h c z  h  h h a 8g.J5*T/0 *1%>Kw235R4Y5`6v\  "X 3/8M7`io89p3:?K_;<Rf=h{d h t8~KW>`i{h*$?*/?@GNw*"  ( h !A`!!!a"j#<q#\p$*}$$*$ %%%&A'((Y)))b***7+A+N+BW+_+}+C++++D,,{,D,,E,,h -n---F----.8.?.N.Y.~.G...H./*/ L/T/i/// /0_1111Q2v22/33-4O4|5N6h66666666I7W7777` 7` 77888#8-828<8G8T {8889'9G9$Q9L f9T 99999999999p:*:#:<:d G:Z:` d:h::::#:::: ;!;H;;;;;;|;;<<<<,<9<V<x<t<\ <<<$< :=S=e=o=}=|====<====>/>I6>@> F>w> > >>J>?K ??L#?D?Y?f?w?????@&@6@F@_@M@@@N@@@O@@@d @P@A'AQ,A@AFA%MARRAfAmAtASyAAhATAAAAAUAAAVA BBBW B4B;BBBXGB[BbBiBYnBBBBZBBB[BBB` B\BBBBhC` C\C]#C2Cd?CdEC`TC^YCqCwC\ChC*ChC_C`CazD` DDL D DbDDcE%E`1ENEUE*\EpEduEELEeEEDEE\EfEEgE<EEhEEiF4 FFjF%F,,FTGFkLFSFTXF_FPFFFFFlFFFdGm GG(G`/Gn4GQGmGG|GGGGdG`HoHH\"Hd,H`6H`DH\ZHXyHLHpHHHH<HTHHhHHDHXIh IIq+Ir7IAIKIsIIIIJJzK9LDLOLh JMUMdMh M4NOtOPuP*P.RhDR%JR$]R#}RRdR`RvSwmS|S!S"S"S# T$TT/T4GT+uT%T&T'TlThTTMTUU|*U$1UGUxSUeU}U(UyUUzUUdU`U$UTU)V{V V|,V=V%eV%V}V*V~V[VdV`V$VWW+W9WPWYWyWWW WWXh BXUXhXX$XXh XY$ YGYQYxYYYYYYYYh #Zh 3Z?ZeZ ZZZp[[[[[\C\\\t\\ \\\$] ^]u]]]]^^4^d B^$X^$]^s^^^^^_d __c +_D_c__ _ _ __I__ ` `%`\`k`-|`.```.``` a,aJ5abaqa` aa` aaaaaaabbh 3bK8bGbXb.gbpbvb{bbbbbbpb*bbbd bc` ch$cCcTcecvcccccc#ccLccd dd9dKdVdfdldd, s|2J +$,PX---D-Lpx 08)dl)))+ $,+ P+ Xw + w w  w   s D Ls ps x s   x  x 0x 8* dx l* *  *   $ ,PX99 9 D 9L p x       0 8 6d l 6 6 w 6 w w $ w, P X         D L p x     ]  ]0 ]8 md ]l m m  m   $,PX****DLpx\\\k \ k 0k 8 dk l  " ""$%$",$%P$%XE'$%E'E''E''''D'L'p'x('(()( )0)8*d)l**+*++,$+,,P,X.,..u/.u/u/)0Du/L)0p)0x1)01121 20284d2l4454556$5,6P6X767777778D7L8p8x8888:98 :90:98q9d:9lq9q9:q9::0;$:,0;P0;XH?0;H?H?^?H?^?^?k?D^?Lk?pk?x?k????? ?0?8?d?l??????@$?,@P@X@@@@+@@+@+@?@D+@L?@p?@xK@?@K@K@TIK@ TI0TI8IdTIlIIJIJJJ$ J, JP JX K J K K W K W!W!UYD!WL!UYp!UYx!Zd!UY!Zd!Zd!qd"Zd "qd0"qd8"dd"qdl"d % & ' (]CC C(X 01CC3C9C> CE(CJ0CP8CU@C[HCbPCqXC`ChCpCxCCCCCCCCCCCC+C4CHCSCYCiCm C(C0C8C@CHCPCXC`ChCpC!xC+C7CDCTCgC~CCCCCCCC  $ $c $,) #0 $8 < $C $ 7J $$Q $V $d $7n $ z $9+ $L+ $! $& $ $e- $@4 $ $ $q $  $# $' " $Q. $: $!M $MY $ e $Gq $ $% $ $w $", $ $4 $i $ $ $( $/  $8 $ $  $  $e, $v9 $o.F $3T $U8a $*n ${ $ $ $( $j $( $* $ $  $/ $  $j7  $ $&5 $A $rM $/b $ $F  $ $!0 $ $  $ $ $ $s5 $.1 $7( $5 $B $7Y $f $s $8% $f. $  $ $ $y $N% $ $ $ $)( $/? $ L $Y $Qp $| $  $ $9 $2. $M $: $c( $v) $ $( $', $18 $^ $.j $! $ $Z# $ $ $$ $+ $p8 $2 $.. $*: $^F $W"S $o.` $Dn $z  $" $$ $  $ $ $ $ $ $< $J'( $5 $E0B $&O $B\ $ i $v $E $d& $I $> $(0 $ $) $  $ $'3 $1 $. $7 $o, $9 $F $,*S $|` $0m $%.z $) $W $ $ $ $! $# $i' $ $&& $2 $> $4Z $ f $6x $&~ $* $ $. $g5 $ $ $`% $K( $t $g $ $ $w( $|7 $8 $ $i+ $U $0 $y $ $  $\, $49 $d$G $wS $0e $ek $b q $ w $ } $# $ $! $+ $ $ $ $ $V $1 $a8 $ ( $ -5 $B $O $\ $%i $N v $ $5 $ $+ $' $( $! $" $ $g $ $0 $= $ I $z+U $,a $'m $ y $1 $C $44 $ $6 $i $* $ $ $ $) $ $X $ $ ${# $ 2 $  $/ $  $S4 $ $R3 $$ $t4* $10 $&6 $ < $B $R H $-N $v.T $Z $E` $f $)l $1r $Ux $~ $) $# $ $V6 $* $2 $f $e1 $ $  $  $  $W/ $ $ $/ $/ $d, $V- $ $(4 $ $d $+ $ $t1 $  $-& $}, $(2 $8 $k> $5D $rJ $#P $$V $\ $b $P$h $(n $t $z $1 $ $5 $y* $ $ $5 $  $3 $! $ $# $L $-' $  $& $& $+& $ $ $ $X $g $v $R0  $, $4 $) $I1" $f( $%. $34 $ : $o@ $ F $XL $\R $)!X $O^ $d $&j $1p $Y5v $ | $U( $h $6 $$ $! $P $% $% $H5 $) $o" $ $7 $0 $ $. $ $ $S. $  $ $  $1 $6!  $  $Y  $3 $$ $k6* $0 $6 $S< $B $"H $8N $k3T $Z $0` $%f $ #l $r $'x $~ $' $& $g! $ $|% $% $ $7" $  $  $Y $$  $ $A8 $R ${- $6 $2 $- $ $Z* $/ $b  $I& $ $) $?#  $'& $, $'2 $8 $5> $2D $&/J $ P $l$V $7\ $sb $F2h $Jn $t $z $p  $ $} $ $ $  $ $( $  $2 $  $  $7# $^ $ $S' $# $9 $f/? $7E $ K $; Q $06W $] $0c $i $3o $u ${ $ $+ $<5 $:* $' $ $  $ $F  $ $ $' $W)N $[ $n $4z $2 $ $W  $  $. $ $4 $. $8 $  $K $&- $7; $q&I $W $D$e $ys $  $ $ $- $#  $  $1 $i $  $|8 $2 $% $" $ ( $. $4 $ : $b'@ $C+F $+L $I!R $ X $-^ $d $0j $kp $v $80| $# $ $* $- $}3 $ $ $$5 $05 $o) $ $ $$ $2  $H- $ : $)G $3T $a $Q n ${ $/ $. $* $5 $T% $ $ $ $02 $  $- $q: $ H $4U $2b $ r $/$w $  $  $ $ $  $ $  $]' $w! $4 $ $A $," $I"/ $<'< $(+I $F*V $q/c $kp $'-} $ $5 $W $ $? $% $% $ $ $ $?,  $ $& $ 3 $@ $4M $-Z $Y,g $ t $6 $y $# $W $-( $l $l( $N $! $ $  $( $" $/ $d < $m I $ $D $)$ $/ $7+ $O $i $?! $ $2 $ $/ $N $! $  $gl $ $"1: $GP $']f $s| $h  $7) $ $; $* $ $,5 $3BK $:(X0a $0nd w $ $0- $Z`  $5X  $U!P  $I)( # $09 $%Fx_ $"1l  $ $o%@ $` $) $92 $- p $5 l( $"6 h? $M dV $ d `m $ r $  X $ P $" H $ @ $0*! $8!8[! $! $K/!0! $2!)! $K! $~! $x!(! $ !(" $/" +" $)9"B" $c)P" $0^" $0l" $z" $C" $*"" $(" $]'" $" $] " $," $" $ # $<.# $8# $,# $":# $H# $0W# $/3d# $r# # $## $"## $## $l## $&## $ $@ $ $b$"$ $b0$9$ $CF$ $0R$dy$ $0 $`d$ $&$ $ $ $$$ 1$ - % % j % ~$% R3% 7% pF% hJ% @V% $ ^%Ku% $q% % % X% P% $% % % ( % " %3K%3K% s % q %  &  &  &  &QK$&QKA&  E&  N&  R&  [& 8 _& 6 i&pKs& " & _ & [ &  &  &  &  &~K&K& "`&  &  &  &  & M & K 'K ' "' r !' p *'  .'  7'  ;'  A'QK_'K' $U1'J'  '  '  '  ' h ' \ '  '  ' "@ ( ( (dJD(|JN( "p_( c( l( p( y( @}( <(J(J(J( "( ( ( ( ) )  )J/)J9) "J) $N)  W) d[) bd) h) m)J{)J) $$)I) $') $ ) $ *`I"* $D1.* 2* 7* $gC* G* L* $p,X* \\* Ra* $m* q* v* $'7* <* 4*dI* "* * * * *I*I*I+IB+ $5N+P@p+ t+ + + + + + + + $+ + +pF+ $$"+F ,@,@3, 7, <,@Y,@c, " t, 6x, 4},@,A,A, ], Y,A,5A,5A- - -DA:-[AD-[Aa- e- j-jA-A-A- - -A-A-A- - .A!.B+.BH. )L. 'Q.Bn.)Bx.)B. N. L.8B.PB.PB. s. q._B/wB/wB// 3/ 8/BU/B_/B|/ / /B/B/B/ / /B/B/ " 0 " 0  0 0 E 0 ?)0 " 60 :0 C0FM0Fj0 rn0 ps0F0G0G0 0 0"G0DG0 " 0 0 1 " 1 1 r 1DG*1DGG1 K1 T1 AX1 ;]1UG1`G1`G1 1 1 1 1qG1G1G 2 2 2 A2 ?%2 o)2 m.2GE2U2Gm2H2H2;I2]2F2C]2G3Co 38G3C&3'C73CVG3QCQ3 "@ ^3 "@ g3 k3 t3fC~3fC3 3 3uC3hE3 " 3H3  3 3H 4H#4I84yEM4C^4Ey4C4E4E4 " 4 " 4 Z4 V4E4C4E4C5E#5C-5FH5CR5"Fm5Cw5PF5]5\F5H5]C5C5 H5C5C5C6C*6 .6 760DL6 P6 \6Ff6F6 4 6 2 6F6F6F6@6C7@7@#7C-7@B7C+L7@a7C=k70A7CN7VA7Cb7qA7}A7Cw7A7C7A8A8A#8C-8AB8CL8BY8$Bn8Cx8?B8KB8C8fB8rB8C8B8B8C8B 9B9C*(9B=9C@G9D_9Dl9D9C9E9C95E9RE9`E9EI9 $O7: $14: $ F: $1S: $ a: $ ~: $'': $]: $;&: $/; $w3; $,?;@@R; $n Z;0@m; $(8y; @; $+;@; $; $";?; $; $B;? < $k< $5!<?8< $H< $P<?g< $w< $3<p?< $%%< $6<`?< $< $<P?< $/= \ = X = $+=`Y-= $D19=  ==  M= !!Q= !b= !f= !k= $E7w= ="{= /"= $= $q*= "= $ = $3=aZ= "= "=iZ >(_ > $,> #0> #:>@[D> "U> ($Y> $b> ($f> $o> $s> $x> "> %> %> 0&> &> 5'> +'> '> '> (> '> I)> /))? "A?]Z? W*^? S*c?]u?`_? *? *?_?_?_?c? "? +? +? "@c@ " @ +$@ +-@ +1@ +:@  ,>@ ,H@cR@co@ 1,s@ /,|@ W,@ U,@ },@ {,@c@c@E[@t[@[ A[#A[HA[mA"\AG\A\A` A\A\A\B\&Bb]LBy]YB]}B_B]B_B@`BS`B``Bo`C`EC`RC`_C`C`C]CaC9aCCCaC](CaCaD]D$J>2Ju;?J;WJ;wJJ;J;JJ<J@J!< KK=<7KAK<RK` \K<sK<K<K<K>=KW=Ks=K L=$L3L=ML\L=vL@L=LL:>L]LD>L>L> M> MC*M??MCIM'?^M]hM5?MH?M $@M:M $D1M 2M  2M ;M $*M a2M _2M;N%;N $N95N $D1AN 2EN 2JN $*"VN 3ZN 3cN:mN " ~N *3N (3N " N:N " N O3N M3N u3N s3N 3N 3N:N "P N 3N 3O 3O 3O 4O 4O:'O:HO9UO9bO9oO:OO::O:O:O:O $;O $O $D1 P $lP $&&P $ 3P $b@P $bMP $kZP $E7P $(P $*P $P $q*P $P $_"P $ P $3Q $Q $Q@91Q $n9QLQ $TQkQ $i"wQ G4{Q 94Q $Q 4Q 4Q $z5Q o5Q c5Q $XQ 6Q 5Q $Q 6Q 6Q $Q ^7Q X7Q $VQ 7Q 7QCR]P&RO=R[R]eR|RR R]RR $3RR $R 8R 7S $i"S 8S 8S $b,S6SSS 8WS 8`S  9dS  9mS 69qS 29vSS]S S3S<SdS]pTm&T>TUTjTCRtTT $T T $T y9T o9T $T 9T 9T $*"T :T :T U U ;$U ;-U B;1U @;:U j;>U f;CU dU UX Us UCU $7U $U $^U $1V $5V $kV $ ,V $!;V $CV8ZV $fV ;jV ;oV $V{V ;V ;V $$VV $V ;V ;V $VV *<V $<V V W u< W s<W <W <"W <&W <-W $5WLW $\W $#hW W $5W <W <W .=W "=W $.W $1W Xl 0Xs NX $VX8|X $DX $*"X $X $X 7X $)X =X =X $O X =X =Y $v Y X>#Y T>5YM7TY[7rY7Y $Y $)Y $"Y $(Y $VY $#Y $ Y $3Z $9"Z59Z $EZ >IZ >NZ $O ZZ J?^Z :?oZ @sZ ?Z P@Z J@Z $dZ $6Z @Z @ZR6Zl6Z6[6@[6^[6k[6x[6[6[ $[ $D1[ $[ $1%[ $<6 \2"\ $D1.\ @2\ @7\ $C\ /AG\ 'AL\ $}X\ A\\ Aa\ $m\ Aq\ Av\ $ \ LB\ FB\ B\ B\ "P \ B\ B\ " \ (C\ $C\3\ $1%\ dC] ^C]4]4)] " :] C>] CG] CK] CT] +DX] )D]]14}]I4] " ] TD] PD] D] D] D] D]S4]33]3^ $?^'&^ $D19^_(C^ "P^ DT^ D]^ )Ea^ 'Ej^ QEn^ MEu^ $6^'^ $D1^ E^ E^ E^ E^ KF^ CF^'^ $!^P'_ $D1"_ F&_ F6_ G:_ FK_ kGO_ cGT_'q_ $ }_0_ $*_ G_ G_ 6H_ .H_ H_ H_ 5I_ )I_ $V_ I_ I` J ` J`{ ` $ ,`0%C` $D1O` JS` Jc` Kg` Kx` L|` L` lL` hL` L` L` $` L` L` 9M` 5M` $` }M` oM` "@` $ a &Na Na $ !a N%a N*a $"6a N:a N?a $Ka 4OOa &OTa $x`a Oda Oia $Vua Pya P~ax&a cPa aPa&a $a Pa Pa&ac&a "pb Pb Pb Qb P(b /Q,b -Q2b&[b%bE'b $ b#b $D1b ^Qb RQb Qb Qb Rb }Rc JSc >Sc Sc S!c $-c NT1c BTBc TFc TKc $Wc 5U[c #U`c $#rc#c $ c Uc Uc $c cVc [Vc $xc Vc Vc $Vc Vc Vc$cd$4d>d$Rd$%qd $}d d $}d d $D1d EWd 3Wd $d  Xd  Xd $/7 e 4Xe 0Xe $V$e "`;e "`De rXHe lXQe XUe X^e "ke Xoe Xxe RY|e JYe Ye Ye Ye Ye *Ze &Ze dZe `Ze "e Ze Ze "e Ze Zee"e!fd!(f $:f $D1Gf $_f $xf $ f $"f $f $xf $Vf $f $f $D1g $ g $1-g $VEg $"Rg $yg $z g $g(g $D1g e[g Y[g [g [g o\g g\g(h "h \h \(h ],h ]5h h]9h f]>h "Lh ]Ph ]Zh)qh(h!)h])h $'hp h $D1h $3h ]h ]h $Q i T^ i R^i i " *i y^.i w^7i ^;i ^Di ^Hi ^Oi $u[i2ri $D1~i ^i ^i $.i _i _i y`i i`i $i 7ai 'ai $3i ai aiU2i " i bi bj b j bj bj bjU26jz2Sj2zj2j $,j $D1j $j $3j $Vj $Q j $.k $"k $Y2!k $-k`Dk $D1Pk cTk  cYk $ek cik cnk $Q zk c~k ck ddk Xdk $/k  ek ekk "k nek jek ek ekl l "l e!l e*l f.l f7l Af;l =f@l "Il {fMl wfVl `l }l fl fl fl fl fl fl l! l $'ll $D1m *gm  g m $m gm gm $Q *m h.m h3m $?m thCm jhTm hXm h]m $},im (imm  irm $x~m im im $cm im im $xm jm jm jm jmm " m km km Tkm Pkm kn kn$nCn(Mn(jn knn ksn(n ln kn4nn $ nn $D1n Tln Hloo+o l/o l4oNo mRo mWono $/o $D1o $o $o0o $D1o $+o ;mo 7mo zmo tmp $Lp(p $D14p m8p m=pJpWpdp&rp $zpp $D1p #np npp "p qnp onp np np $D p/q $D1 q nq nq/.q/Fq/fq!0{q $e4q.q $D1q Doq 8oq#/qP/qX/qm/ r $67rW,r $D18r os(QsWisXsFXsXsXsXsXtXtKY9tUYGt $2 St`jt $D1zt $ tpttt $)tt $D1t Eqt ;qt qu qu $ u Mru Kru(u "9u rr=u prFu rJu rYu3cu "@tu rxu ru ru ru "@u  su  su<uuu Esu Csu v0vCv]Mv "^v jsbv hskv sov stvdvCovvv=vOwmw&w $_0.wTw $`wsw ${ww $9ww "w $w sw swwwwx x~ vB~ vK~ vO~ vY~+~C~;+~E+~[+~c+~+~+~+ $ $ $r 6 $]+\ ${ $. $  $D1 $ $x $V $ $D14 $xA $VP $s^ $D1w $ $( $;$ ̀ $0؀ w܀ w $ jw fw $/7 $V w w $+,& x*  x/ $; Sx? GxD $ P xT xZ $(x $1 $g $0 $& $́ $ $x $3 $[ $&0 = $D1I yM yR $^ Fzb @zq zu zzH $D3 $D1ł $ׂ $D1 $ $ $: $#* $7 $Q $},p $1 $ $ #ă $D1҃ $W $2  , z0 z5 $$A {E {V &|Z  |_  $6 $3 $S҄ $ ܄ $n#0 $) w| o| $+ | |5`Xp $(Ѕ $m-؅ $P $3@, $8 E}< =}A $M }Q }VVnwC[ $+@ $dʆ ~Ά  ~ކ ~ ~ \ H $ 6 0.0eo "P     ܀ ڀ̇]ۇcc   / - W U$NC"YBvOS " ~ z ˆ ˈ ψ ԈX # , G0 E9 n= lBjC2~ "    ĉ ȉ ͉C8 " "#  , P0 N5)KCF\iw $s $D1 $g $- $/ $ˊ $>܊ $( $/ $0 $+ $! $Q* $-7 $H $!T $Qa $r $!~ $f3 $- $. $! $Q $-͋ $ ދ $! $Q $- $ $ $, $0? $2P $\ $j $ $ $^ $5 $.֌ $ $2 $  $2 $A-( $(5 $r7I $SZ $f $#&t $91 $- $/ $- ύ Ӎ t܍   H B "    ' @+ <0 "09 |= vF P m Džq Ņz ~     Ŏ0 @ @  6 4!G 9Q Lw Vw v c Y ߆ Ն [ Q ه ͇ŏ mɏ aҏ ֏  e+5 "`BPgy [ S   & Đ Ȑ    X R''$ ( 1 ʋ5 ȋ> B G<lv " , * S Q z vϑFّ "  Nx "1 ٌ5 ׌> B K (O $Yc "Pt ex a   ͍ ˍ "˒ ϒ ؒ ܒ  k (C2P{9ؓ Cܓ ? " "$ ( |1 V5 J> B ؏K vO pX "e i r v {z”ؔ)      ?# 1T)^){  ޒ 5 1 q m)  ɕ ԓ͕ ̓֕ <ڕ 4   Ô {* " * . 7 ";  D HH FQ nU lZ " h l u Εy ̕~*D* "p Ö ̖ 0Ж .ٖ Vݖ T)**8*J,e i y|, "  y     "̗ MЗ Gٗ ݗ - "@ ԙ ҙ   -7{-A{-^ #b k ^o \t{-  -r-Ҙ].ߘ..- "p  # "p, 0 9-C-` d m q v---<.ۙC.R..%]X;x.Ex.b ٛf ӛkx..]8.00ך 1ۚ % ɜ   "0, "= 0A (J N W [ ` "i Bm 6v ɟz ş    {   J D0ƛ "ܛ    11 " + / 8 /< -A1dc1|114 `Ü R̜  М ٜ ݜ  " / # 5# ' 1>5J FN @Sg5lq5v "P      ޥ5ǝ7   ] W7=7X \ e i r v 7 " ? 5   3 -7֞8'868@88(KC G |P <T :b,Ll "} c _   ת Ӫ "   0L0Lݟ I G n l  =L!HL4L> " O S X " a e n 2r *{LL    LѠ ۬ՠ ٬8M8M   % #! J% H*@M? qC mL@MV@Ms w  έ ̭  NMYMʡMԡ "     "    ^ T'M1MN ϯR ͯ[ _ h l qMMM D B i gȢ ̢ ѢM  MNN< ް@ ܰI M V +Z )_Ny!N!N S Q x v  !Nԣ ȱأ Ʊݣ8NyO " " ' "0 4 = A JO_ @c >l ep c|OPOP  OP Ť ΤOPؤ "0 Գ ҳ "0   "  kP! "p2 G6 E; "pD nH lQ U `yPj "{   "  ߴ  P "ĥ Cȥ Aͥ "֥ jڥ h  P "`   "` ޵# ܵ, 0 ;PE "V +Z )_ "h Rl Pu {y wP "   " ۶ ٶ ¦ ͦPצ "` ( & "` O M v tP "- 1 6 "? ÷C L P ]Q{Q ' #"Q a _ç ǧ Ч3Qڧ3Q  3Q ݸ ۸ " .bQC +G %P xT v]Qg "x |  " ۹ ׹  Q "0¨ "0Ш :Ԩ 8ߨQ "p "p _ ]Q" "0 "> B P\UZ\Uw { \U κ ̺iUUթpNN P)C30VQC6[/Wu]vRvR   ê ȪvRݪ = ;R R "' j+ `0 "9 = ٻF J ~S W ` (d m q z  ~  E ?_S "p    ɫ ߾ͫ ۾֫ ګ  C = "S " " & / 3 < @ FS^SSSǬTѬ "`       6 ( "  ( *, 5U? "U Y b "t xx rhWhW  hW­W 3T&hW=]RU\UuVV] TϮ\TyTTT6UNAV[iVhVCVVCɯVJWC W"C3T@T[CeUrU]8U]pİUΰU     6 4U ". d2 b;UE " R V _UiU  UU   ñ ȱ5Uٱ(P CTWU2C< WVC&m Pw P * ( T P P ò Ȳ.P߲TW $ $ $. $g $~' $~' $7 $7 $"$ $"$( $S, $4 $b8 $bA $>E $[M $#!Q $#!Z $0^ $0g $h*k $h*s $w $ $m $m $H $H $ $ $* $* $ $ $ ³ $ ˳ $0)ϳ $0)س $ ܳ $ $% $% $ $ $h $h $ $  $ $ $/" $/+ $"/ $"8 $B%< $B%D $H $P $D!T $D!\ $` $i $&m $&u $3,y $3, $5* $5* $' $' $ $ $, $, $G- $ $ô $̴ $4д $4ٴ $7ݴ $7 $ $ $H4 $H4 $, $, $" $" $ $! $)% $)- $^21 $^2: $7> $7F $W+J $W+S $c7W $c7_ $/c $/k $Z8o $Z8w $z&{ $z& $$ $$ $( $( $ $ $ $ĵ $ȵ $е $/Ե $/ܵ $ $ $ $ $2 $2 $+ $" $  $* $<" $<* $. $6 $: $B $ F $ O $eS $e\ $` $h $l $t $-x $ $4 $4 $$* $$* $J $J $J $ $ $ $K $Kȶ $a̶ $aԶ $P,ض $P, $ $ $ $ $3 $3 $ $T+'-(- 38]QCp(sCovC]C",C2C85CF ʿI(   4H \00L`0     \ 0  $L@ X0@Xl`p,@\0p` p 4 #0%8P'L'`'t()+P , , . / 00\ 2 2 4X 5 7  7 7$ 88 8L @9` 9 : 0; P? `?( p?< ?P ?d ?x ? @  @ 0@ @@ P@`I\IpJKK4W|`Y`dd.symtab.strtab.shstrtab.rela.text.data.bss.rela.gnu.build.attributes.text.hot.rela.gnu.build.attributes.hot.text.unlikely.rela.gnu.build.attributes.unlikely.text.startup.rela.gnu.build.attributes.startup.text.exit.rela.gnu.build.attributes.exit.rodata.str1.1.rodata.str1.8.rodata.rela.data.rel.local.rela.data.rel.rela.data.rel.ro.local.rela.debug_info.debug_abbrev.rela.debug_loc.rela.debug_aranges.debug_ranges.rela.debug_line.debug_str.comment.text.hot.zzz.text.unlikely.zzz.text.startup.zzz.text.exit.zzz.note.GNU-stack.note.gnu.property.rela.eh_frame.groupP@:PT:Pl:P:P: d@@A@G:&`ep ,n 6nt"1@ : LT[TV@P0: u((@0:@0:ЖЖ@0:22/"D /`8 *@:D?@:S N@p:kf@(\:!wa-i@ :$/0@0:& 0`lJR@H:)0}807.eeueLe eeeeee.h FA@((:8x4; ('PWPK ]]z.##&gems/ruby-lsapi-5.5/ext/lsapi/Makefilenu[ SHELL = /bin/sh # V=0 quiet, V=1 verbose. other values don't work. V = 1 Q1 = $(V:1=) Q = $(Q1:0=@) ECHO1 = $(V:1=@ :) ECHO = $(ECHO1:0=@ echo) NULLCMD = : #### Start of system configuration section. #### srcdir = . topdir = /opt/alt/ruby27/include hdrdir = $(topdir) arch_hdrdir = /opt/alt/ruby27/include PATH_SEPARATOR = : VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby prefix = $(DESTDIR)/opt/alt/ruby27 rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) rubyarchprefix = $(DESTDIR)/opt/alt/ruby27/lib64/ruby rubylibprefix = $(exec_prefix)/share/ruby exec_prefix = $(DESTDIR)/opt/alt/ruby27 vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby rubyarchhdrdir = $(DESTDIR)/opt/alt/ruby27/include vendorhdrdir = $(rubyhdrdir)/vendor_ruby sitehdrdir = $(rubyhdrdir)/site_ruby rubyhdrdir = $(DESTDIR)/opt/alt/ruby27/include rubygemsdir = $(DESTDIR)/opt/alt/ruby27/share/rubygems vendorarchdir = $(DESTDIR)/opt/alt/ruby27/lib64/ruby/vendor_ruby vendorlibdir = $(vendordir) vendordir = $(DESTDIR)/opt/alt/ruby27/share/ruby/vendor_ruby sitearchdir = $(DESTDIR)./.gem.20230713-1832549-9v9h3w sitelibdir = $(DESTDIR)./.gem.20230713-1832549-9v9h3w sitedir = $(DESTDIR)/opt/alt/ruby27/share/ruby/site_ruby rubyarchdir = $(rubyarchprefix) rubylibdir = $(rubylibprefix) sitearchincludedir = $(includedir)/$(sitearch) archincludedir = $(includedir)/$(arch) sitearchlibdir = $(libdir)/$(sitearch) archlibdir = $(DESTDIR)/opt/alt/ruby27/lib64 ridir = $(datarootdir)/$(RI_BASE_NAME) mandir = $(DESTDIR)/opt/alt/ruby27/share/man localedir = $(datarootdir)/locale libdir = $(exec_prefix)/lib64 psdir = $(docdir) pdfdir = $(docdir) dvidir = $(docdir) htmldir = $(docdir) infodir = $(DESTDIR)/opt/alt/ruby27/share/info docdir = $(datarootdir)/doc/$(PACKAGE) oldincludedir = $(DESTDIR)/usr/include includedir = $(DESTDIR)/opt/alt/ruby27/include localstatedir = $(DESTDIR)/var sharedstatedir = $(DESTDIR)/var/lib sysconfdir = $(DESTDIR)/etc datadir = $(DESTDIR)/opt/alt/ruby27/share datarootdir = $(prefix)/share libexecdir = $(DESTDIR)/opt/alt/ruby27/libexec sbindir = $(DESTDIR)/opt/alt/ruby27/sbin bindir = $(exec_prefix)/bin archdir = $(rubyarchdir) CC_WRAPPER = CC = gcc CXX = g++ LIBRUBY = $(LIBRUBY_SO) LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a LIBRUBYARG_SHARED = -Wl,-rpath,$(archlibdir) -L$(archlibdir) -l$(RUBY_SO_NAME) LIBRUBYARG_STATIC = -Wl,-rpath,$(archlibdir) -L$(archlibdir) -l$(RUBY_SO_NAME)-static $(MAINLIBS) empty = OUTFLAG = -o $(empty) COUTFLAG = -o $(empty) CSRCFLAG = $(empty) RUBY_EXTCONF_H = cflags = $(optflags) $(debugflags) $(warnflags) cxxflags = optflags = -O3 debugflags = -ggdb3 warnflags = -Wall -Wextra -Wdeprecated-declarations -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable cppflags = CCDLFLAGS = -fPIC CFLAGS = $(CCDLFLAGS) -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection $(ARCH_FLAG) INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) DEFS = CPPFLAGS = $(DEFS) $(cppflags) -DRUBY_2 CXXFLAGS = $(CCDLFLAGS) -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection $(ARCH_FLAG) ldflags = -L. -L/opt/alt/ruby27/lib64 -Wl,-rpath=/opt/alt/ruby27/lib64 -fstack-protector-strong -rdynamic -Wl,-export-dynamic dldflags = -L/opt/alt/ruby27/lib64 -Wl,-rpath=/opt/alt/ruby27/lib64 ARCH_FLAG = -m64 DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) LDSHARED = $(CC) -shared LDSHAREDXX = $(CXX) -shared AR = ar EXEEXT = RUBY_INSTALL_NAME = $(RUBY_BASE_NAME) RUBY_SO_NAME = ruby RUBYW_INSTALL_NAME = RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version_dir_name) RUBYW_BASE_NAME = rubyw RUBY_BASE_NAME = ruby arch = x86_64-linux sitearch = $(arch) ruby_version = 2.7.0 ruby = $(bindir)/$(RUBY_BASE_NAME) RUBY = $(ruby) BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME) ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h RM = rm -f RM_RF = $(RUBY) -run -e rm -- -rf RMDIRS = rmdir --ignore-fail-on-non-empty -p MAKEDIRS = /usr/bin/mkdir -p INSTALL = /usr/bin/install -c INSTALL_PROG = $(INSTALL) -m 0755 INSTALL_DATA = $(INSTALL) -m 644 COPY = cp TOUCH = exit > #### End of system configuration section. #### preload = libpath = . $(archlibdir) LIBPATH = -L. -L$(archlibdir) -Wl,-rpath,$(archlibdir) DEFFILE = CLEANFILES = mkmf.log DISTCLEANFILES = DISTCLEANDIRS = extout = extout_prefix = target_prefix = LOCAL_LIBS = LIBS = $(LIBRUBYARG_SHARED) -lm -lc ORIG_SRCS = lsapilib.c lsruby.c SRCS = $(ORIG_SRCS) OBJS = lsapilib.o lsruby.o HDRS = $(srcdir)/lsapidef.h $(srcdir)/lsapilib.h LOCAL_HDRS = TARGET = lsapi TARGET_NAME = lsapi TARGET_ENTRY = Init_$(TARGET_NAME) DLLIB = $(TARGET).so EXTSTATIC = STATIC_LIB = TIMESTAMP_DIR = . BINDIR = $(bindir) RUBYCOMMONDIR = $(sitedir)$(target_prefix) RUBYLIBDIR = $(sitelibdir)$(target_prefix) RUBYARCHDIR = $(sitearchdir)$(target_prefix) HDRDIR = $(rubyhdrdir)/ruby$(target_prefix) ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix) TARGET_SO_DIR = TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) CLEANLIBS = $(TARGET_SO) CLEANOBJS = *.o *.bak all: $(DLLIB) static: $(STATIC_LIB) .PHONY: all install static install-so install-rb .PHONY: clean clean-so clean-static clean-rb clean-static:: clean-rb-default:: clean-rb:: clean-so:: clean: clean-so clean-static clean-rb-default clean-rb -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time distclean-rb-default:: distclean-rb:: distclean-so:: distclean-static:: distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true realclean: distclean install: install-so install-rb install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.time $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) clean-static:: -$(Q)$(RM) $(STATIC_LIB) install-rb: pre-install-rb do-install-rb install-rb-default install-rb-default: pre-install-rb-default do-install-rb-default pre-install-rb: Makefile pre-install-rb-default: Makefile do-install-rb: do-install-rb-default: pre-install-rb-default: @$(NULLCMD) $(TIMESTAMP_DIR)/.sitearchdir.time: $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) $(Q) $(TOUCH) $@ site-install: site-install-so site-install-rb site-install-so: install-so site-install-rb: install-rb .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S .cc.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cc.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .mm.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .mm.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .cxx.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cxx.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .cpp.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cpp.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .c.o: $(ECHO) compiling $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .c.S: $(ECHO) translating $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .m.o: $(ECHO) compiling $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .m.S: $(ECHO) translating $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< $(TARGET_SO): $(OBJS) Makefile $(ECHO) linking shared-object $(DLLIB) -$(Q)$(RM) $(@) $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) $(OBJS): $(HDRS) $(ruby_headers) PK ] 3O8aa(gems/ruby-lsapi-5.5/ext/lsapi/lsapilib.cnu[//#define LSAPI_DEBUG /* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lsapilib.h" #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #include #endif #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #include #endif #include #ifndef uint32 #define uint32 uint32_t #endif struct lsapi_MD5Context { uint32 buf[4]; uint32 bits[2]; unsigned char in[64]; }; void lsapi_MD5Init(struct lsapi_MD5Context *context); void lsapi_MD5Update(struct lsapi_MD5Context *context, unsigned char const *buf, unsigned len); void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *context); /* * This is needed to make RSAREF happy on some MS-DOS compilers. */ typedef struct lsapi_MD5Context lsapi_MD5_CTX; #define LSAPI_ST_REQ_HEADER 1 #define LSAPI_ST_REQ_BODY 2 #define LSAPI_ST_RESP_HEADER 4 #define LSAPI_ST_RESP_BODY 8 #define LSAPI_ST_BACKGROUND 16 #define LSAPI_RESP_BUF_SIZE 8192 #define LSAPI_INIT_RESP_HEADER_LEN 4096 enum { LSAPI_STATE_IDLE, LSAPI_STATE_CONNECTED, LSAPI_STATE_ACCEPTING, }; typedef struct lsapi_child_status { int m_pid; long m_tmStart; volatile short m_iKillSent; volatile char m_inProcess; volatile char m_state; volatile int m_iReqCounter; volatile long m_tmWaitBegin; volatile long m_tmReqBegin; volatile long m_tmLastCheckPoint; } lsapi_child_status; static lsapi_child_status * s_worker_status = NULL; static int g_inited = 0; static int g_running = 1; static int s_ppid; static int s_restored_ppid = 0; static int s_pid = 0; static int s_slow_req_msecs = 0; static int s_keep_listener = 1; static int s_dump_debug_info = 0; static int s_pid_dump_debug_info = 0; static int s_req_processed = 0; static int s_skip_write = 0; static int (*pthread_atfork_func)(void (*prepare)(void), void (*parent)(void), void (*child)(void)) = NULL; static int *s_busy_workers = NULL; static int *s_accepting_workers = NULL; static int *s_global_counter = &s_req_processed; static int s_max_busy_workers = -1; static char *s_stderr_log_path = NULL; static int s_stderr_is_pipe = 0; static int s_ignore_pid = -1; static size_t s_total_pages = 1; static size_t s_min_avail_pages = 256 * 1024; static size_t *s_avail_pages = &s_total_pages; LSAPI_Request g_req = { .m_fdListen = -1, .m_fd = -1 }; static char s_secret[24]; static LSAPI_On_Timer_pf s_proc_group_timer_cb = NULL; void Flush_RespBuf_r( LSAPI_Request * pReq ); static int lsapi_reopen_stderr(const char *p); static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] = { "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHORIZATION", "HTTP_CONNECTION", "CONTENT_TYPE", "CONTENT_LENGTH", "HTTP_COOKIE", "HTTP_COOKIE2", "HTTP_HOST", "HTTP_PRAGMA", "HTTP_REFERER", "HTTP_USER_AGENT", "HTTP_CACHE_CONTROL", "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH", "HTTP_IF_NONE_MATCH", "HTTP_IF_RANGE", "HTTP_IF_UNMODIFIED_SINCE", "HTTP_KEEP_ALIVE", "HTTP_RANGE", "HTTP_X_FORWARDED_FOR", "HTTP_VIA", "HTTP_TRANSFER_ENCODING" }; static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] = { 11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18, 22, 13, 18, 13, 24, 15, 10, 20, 8, 22 }; static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] = { "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Authorization", "Connection", "Content-Type", "Content-Length", "Cookie", "Cookie2", "Host", "Pragma", "Referer", "User-Agent", "Cache-Control", "If-Modified-Since", "If-Match", "If-None-Match", "If-Range", "If-Unmodified-Since", "Keep-Alive", "Range", "X-Forwarded-For", "Via", "Transfer-Encoding" }; static int HTTP_HEADER_LEN[H_TRANSFER_ENCODING+1] = { 6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, //user-agent 13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17 }; static const char *s_log_level_names[8] = { "", "DEBUG","INFO", "NOTICE", "WARN", "ERROR", "CRIT", "FATAL" }; void LSAPI_Log(int flag, const char * fmt, ...) { char buf[1024]; char *p = buf; if ((flag & LSAPI_LOG_TIMESTAMP_BITS) && !(s_stderr_is_pipe)) { struct timeval tv; struct tm tm; gettimeofday(&tv, NULL); localtime_r(&tv.tv_sec, &tm); if (flag & LSAPI_LOG_TIMESTAMP_FULL) { p += snprintf(p, 1024, "%04d-%02d-%02d %02d:%02d:%02d.%06d ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)tv.tv_usec); } else if (flag & LSAPI_LOG_TIMESTAMP_HMS) { p += snprintf(p, 1024, "%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec); } } int level = flag & LSAPI_LOG_LEVEL_BITS; if (level && level <= LSAPI_LOG_FLAG_FATAL) { p += snprintf(p, 100, "[%s] ", s_log_level_names[level]); } if (flag & LSAPI_LOG_PID) { p += snprintf(p, 100, "[UID:%d][%d] ", getuid(), s_pid); } if (p > buf) fprintf(stderr, "%.*s", (int)(p - buf), buf); va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #ifdef LSAPI_DEBUG #define DBGLOG_FLAG (LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_FLAG_DEBUG|LSAPI_LOG_PID) #define lsapi_dbg(...) LSAPI_Log(DBGLOG_FLAG, __VA_ARGS__) #else #define lsapi_dbg(...) #endif #define lsapi_log(...) LSAPI_Log(LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_PID, __VA_ARGS__) void lsapi_perror(const char * pMessage, int err_no) { lsapi_log("%s, errno: %d (%s)\n", pMessage, err_no, strerror(err_no)); } static int lsapi_parent_dead() { // Return non-zero if the parent is dead. 0 if still alive. if (!s_ppid) { // not checking, so not dead return(0); } if (s_restored_ppid) { if (kill(s_restored_ppid,0) == -1) { if (errno == EPERM) { return(0); // no permission, but it's still there. } return(1); // Dead } return(0); // it worked, so it's not dead } return(s_ppid != getppid()); } static void lsapi_sigpipe( int sig ) { } static void lsapi_siguser1( int sig ) { g_running = 0; } #ifndef sighandler_t typedef void (*sighandler_t)(int); #endif static void lsapi_signal(int signo, sighandler_t handler) { struct sigaction sa; sigaction(signo, NULL, &sa); if (sa.sa_handler == SIG_DFL) { sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; sigaction(signo, &sa, NULL); } } static int s_enable_core_dump = 0; static void lsapi_enable_core_dump(void) { #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) int mib[2]; size_t len; #if !defined(__OpenBSD__) len = 2; if ( sysctlnametomib("kern.sugid_coredump", mib, &len) == 0 ) { len = sizeof(s_enable_core_dump); if (sysctl(mib, 2, NULL, 0, &s_enable_core_dump, len) == -1) perror( "sysctl: Failed to set 'kern.sugid_coredump', " "core dump may not be available!"); } #else int set = 3; len = sizeof(set); mib[0] = CTL_KERN; mib[1] = KERN_NOSUIDCOREDUMP; if (sysctl(mib, 2, NULL, 0, &set, len) == 0) { s_enable_core_dump = 1; } #endif #endif #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if (prctl(PR_SET_DUMPABLE, s_enable_core_dump,0,0,0) == -1) perror( "prctl: Failed to set dumpable, " "core dump may not be available!"); #endif } static inline void lsapi_buildPacketHeader( struct lsapi_packet_header * pHeader, char type, int len ) { pHeader->m_versionB0 = LSAPI_VERSION_B0; /* LSAPI protocol version */ pHeader->m_versionB1 = LSAPI_VERSION_B1; pHeader->m_type = type; pHeader->m_flag = LSAPI_ENDIAN; pHeader->m_packetLen.m_iLen = len; } static int lsapi_set_nblock( int fd, int nonblock ) { int val = fcntl( fd, F_GETFL, 0 ); if ( nonblock ) { if (!( val & O_NONBLOCK )) { return fcntl( fd, F_SETFL, val | O_NONBLOCK ); } } else { if ( val & O_NONBLOCK ) { return fcntl( fd, F_SETFL, val &(~O_NONBLOCK) ); } } return 0; } static int lsapi_close( int fd ) { int ret; while( 1 ) { ret = close( fd ); if (( ret == -1 )&&( errno == EINTR )&&(g_running)) continue; return ret; } } static void lsapi_close_connection(LSAPI_Request *pReq) { if (pReq->m_fd == -1) return; lsapi_close(pReq->m_fd); pReq->m_fd = -1; if (s_busy_workers) __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST); if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_IDLE, __ATOMIC_SEQ_CST); } static inline ssize_t lsapi_read( int fd, void * pBuf, size_t len ) { ssize_t ret; while( 1 ) { ret = read( fd, (char *)pBuf, len ); if (( ret == -1 )&&( errno == EINTR )&&(g_running)) continue; return ret; } } /* static int lsapi_write( int fd, const void * pBuf, int len ) { int ret; const char * pCur; const char * pEnd; if ( len == 0 ) return 0; pCur = (const char *)pBuf; pEnd = pCur + len; while( g_running && (pCur < pEnd) ) { ret = write( fd, pCur, pEnd - pCur ); if ( ret >= 0) pCur += ret; else if (( ret == -1 )&&( errno != EINTR )) return ret; } return pCur - (const char *)pBuf; } */ static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen ) { int ret; int left = totalLen; int n = count; if (s_skip_write) return totalLen; while(( left > 0 )&&g_running ) { ret = writev( fd, *pVec, n ); if ( ret > 0 ) { left -= ret; if (( left <= 0)||( !g_running )) return totalLen - left; while( ret > 0 ) { if ( (*pVec)->iov_len <= (unsigned int )ret ) { ret -= (*pVec)->iov_len; ++(*pVec); } else { (*pVec)->iov_base = (char *)(*pVec)->iov_base + ret; (*pVec)->iov_len -= ret; break; } } } else if ( ret == -1 ) { if ( errno == EAGAIN ) { if ( totalLen - left > 0 ) return totalLen - left; else return -1; } else if ( errno != EINTR ) return ret; } } return totalLen - left; } /* static int getTotalLen( struct iovec * pVec, int count ) { struct iovec * pEnd = pVec + count; int total = 0; while( pVec < pEnd ) { total += pVec->iov_len; ++pVec; } return total; } */ static inline int allocateBuf( LSAPI_Request * pReq, int size ) { char * pBuf = (char *)realloc( pReq->m_pReqBuf, size ); if ( pBuf ) { pReq->m_pReqBuf = pBuf; pReq->m_reqBufSize = size; pReq->m_pHeader = (struct lsapi_req_header *)pReq->m_pReqBuf; return 0; } return -1; } static int allocateIovec( LSAPI_Request * pReq, int n ) { struct iovec * p = (struct iovec *)realloc( pReq->m_pIovec, sizeof(struct iovec) * n ); if ( !p ) return -1; pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec ); pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec ); pReq->m_pIovec = p; pReq->m_pIovecEnd = p + n; return 0; } static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size ) { char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size ); if ( !p ) return -1; pReq->m_pRespHeaderBufPos = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf ); pReq->m_pRespHeaderBuf = p; pReq->m_pRespHeaderBufEnd = p + size; return 0; } static inline int verifyHeader( struct lsapi_packet_header * pHeader, char pktType ) { if (( LSAPI_VERSION_B0 != pHeader->m_versionB0 )|| ( LSAPI_VERSION_B1 != pHeader->m_versionB1 )|| ( pktType != pHeader->m_type )) return -1; if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT )) { register char b; b = pHeader->m_packetLen.m_bytes[0]; pHeader->m_packetLen.m_bytes[0] = pHeader->m_packetLen.m_bytes[3]; pHeader->m_packetLen.m_bytes[3] = b; b = pHeader->m_packetLen.m_bytes[1]; pHeader->m_packetLen.m_bytes[1] = pHeader->m_packetLen.m_bytes[2]; pHeader->m_packetLen.m_bytes[2] = b; } return pHeader->m_packetLen.m_iLen; } static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList, int *curSize, int newSize ) { struct LSAPI_key_value_pair * pBuf; if ( *curSize >= newSize ) return 0; if ( newSize > 8192 ) return -1; pBuf = (struct LSAPI_key_value_pair *)realloc( *pEnvList, newSize * sizeof(struct LSAPI_key_value_pair) ); if ( pBuf ) { *pEnvList = pBuf; *curSize = newSize; return 0; } else return -1; } static inline int isPipe( int fd ) { char achPeer[128]; socklen_t len = 128; if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&& ( errno == ENOTCONN )) return 0; else return 1; } static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count, char **pBegin, char * pEnd ) { struct LSAPI_key_value_pair * pEnvEnd; int keyLen = 0, valLen = 0; if ( count > 8192 ) return -1; pEnvEnd = pEnvList + count; while( pEnvList != pEnvEnd ) { if ( pEnd - *pBegin < 4 ) return -1; keyLen = *((unsigned char *)((*pBegin)++)); keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++)); valLen = *((unsigned char *)((*pBegin)++)); valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++)); if ( *pBegin + keyLen + valLen > pEnd ) return -1; if (( !keyLen )||( !valLen )) return -1; pEnvList->pKey = *pBegin; *pBegin += keyLen; pEnvList->pValue = *pBegin; *pBegin += valLen; pEnvList->keyLen = keyLen - 1; pEnvList->valLen = valLen - 1; ++pEnvList; } if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 ) return -1; *pBegin += 4; return 0; } static inline void swapIntEndian( int * pInteger ) { char * p = (char *)pInteger; register char b; b = p[0]; p[0] = p[3]; p[3] = b; b = p[1]; p[1] = p[2]; p[2] = b; } static inline void fixEndian( LSAPI_Request * pReq ) { struct lsapi_req_header *p= pReq->m_pHeader; swapIntEndian( &p->m_httpHeaderLen ); swapIntEndian( &p->m_reqBodyLen ); swapIntEndian( &p->m_scriptFileOff ); swapIntEndian( &p->m_scriptNameOff ); swapIntEndian( &p->m_queryStringOff ); swapIntEndian( &p->m_requestMethodOff ); swapIntEndian( &p->m_cntUnknownHeaders ); swapIntEndian( &p->m_cntEnv ); swapIntEndian( &p->m_cntSpecialEnv ); } static void fixHeaderIndexEndian( LSAPI_Request * pReq ) { int i; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { register char b; char * p = (char *)(&pReq->m_pHeaderIndex->m_headerLen[i]); b = p[0]; p[0] = p[1]; p[1] = b; swapIntEndian( &pReq->m_pHeaderIndex->m_headerOff[i] ); } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { swapIntEndian( &pCur->nameOff ); swapIntEndian( &pCur->nameLen ); swapIntEndian( &pCur->valueOff ); swapIntEndian( &pCur->valueLen ); ++pCur; } } } static int validateHeaders( LSAPI_Request * pReq ) { int totalLen = pReq->m_pHeader->m_httpHeaderLen; int i; for(i = 0; i < H_TRANSFER_ENCODING; ++i) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { if (pReq->m_pHeaderIndex->m_headerOff[i] > totalLen || pReq->m_pHeaderIndex->m_headerLen[i] + pReq->m_pHeaderIndex->m_headerOff[i] > totalLen) return -1; } } if (pReq->m_pHeader->m_cntUnknownHeaders > 0) { struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { if (pCur->nameOff > totalLen || pCur->nameOff + pCur->nameLen > totalLen || pCur->valueOff > totalLen || pCur->valueOff + pCur->valueLen > totalLen) return -1; ++pCur; } } return 0; } static uid_t s_uid = 0; static uid_t s_defaultUid; //web server need set this static gid_t s_defaultGid; #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #define LSAPI_LVE_DISABLED 0 #define LSAPI_LVE_ENABLED 1 #define LSAPI_CAGEFS_ENABLED 2 #define LSAPI_CAGEFS_NO_SUEXEC 3 struct liblve; static int s_enable_lve = LSAPI_LVE_DISABLED; static struct liblve * s_lve = NULL; static void *s_liblve; static int (*fp_lve_is_available)(void) = NULL; static int (*fp_lve_instance_init)(struct liblve *) = NULL; static int (*fp_lve_destroy)(struct liblve *) = NULL; static int (*fp_lve_enter)(struct liblve *, uint32_t, int32_t, int32_t, uint32_t *) = NULL; static int (*fp_lve_leave)(struct liblve *, uint32_t *) = NULL; static int (*fp_lve_jail)( struct passwd *, char *) = NULL; static int lsapi_load_lve_lib(void) { s_liblve = dlopen("liblve.so.0", RTLD_NOW | RTLD_GLOBAL); if (s_liblve) { fp_lve_is_available = dlsym(s_liblve, "lve_is_available"); if (dlerror() == NULL) { if ( !(*fp_lve_is_available)() ) { int uid = getuid(); if ( uid ) { if (setreuid( s_uid, uid )) {}; if ( !(*fp_lve_is_available)() ) s_enable_lve = 0; if (setreuid( uid, s_uid )) {}; } } } } else { s_enable_lve = LSAPI_LVE_DISABLED; } return (s_liblve)? 0 : -1; } static int init_lve_ex(void) { int rc; if ( !s_liblve ) return -1; fp_lve_instance_init = dlsym(s_liblve, "lve_instance_init"); fp_lve_destroy = dlsym(s_liblve, "lve_destroy"); fp_lve_enter = dlsym(s_liblve, "lve_enter"); fp_lve_leave = dlsym(s_liblve, "lve_leave"); if ( s_enable_lve >= LSAPI_CAGEFS_ENABLED ) fp_lve_jail = dlsym(s_liblve, "jail" ); if ( s_lve == NULL ) { rc = (*fp_lve_instance_init)(NULL); s_lve = malloc(rc); } rc = (*fp_lve_instance_init)(s_lve); if (rc != 0) { perror( "LSAPI: Unable to initialize LVE" ); free( s_lve ); s_lve = NULL; return -1; } return 0; } #endif static int readSecret( const char * pSecretFile ) { struct stat st; int fd = open( pSecretFile, O_RDONLY , 0600 ); if ( fd == -1 ) { lsapi_log("LSAPI: failed to open secret file: %s!\n", pSecretFile ); return -1; } if ( fstat( fd, &st ) == -1 ) { lsapi_log("LSAPI: failed to check state of file: %s!\n", pSecretFile ); close( fd ); return -1; } /* if ( st.st_uid != s_uid ) { lsapi_log("LSAPI: file owner check failure: %s!\n", pSecretFile ); close( fd ); return -1; } */ if ( st.st_mode & 0077 ) { lsapi_log("LSAPI: file permission check failure: %s\n", pSecretFile ); close( fd ); return -1; } if ( read( fd, s_secret, 16 ) < 16 ) { lsapi_log("LSAPI: failed to read secret from secret file: %s\n", pSecretFile ); close( fd ); return -1; } close( fd ); return 0; } int LSAPI_is_suEXEC_Daemon(void) { if (( !s_uid )&&( s_secret[0] )) return 1; else return 0; } static int LSAPI_perror_r( LSAPI_Request * pReq, const char * pErr1, const char *pErr2 ) { char achError[4096]; int n = snprintf(achError, sizeof(achError), "[UID:%d][%d] %s:%s: %s\n", getuid(), getpid(), pErr1, (pErr2)?pErr2:"", strerror(errno)); if (n > (int)sizeof(achError)) n = sizeof(achError); if ( pReq ) LSAPI_Write_Stderr_r( pReq, achError, n ); else if (write( STDERR_FILENO, achError, n )) {}; return 0; } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) static int lsapi_lve_error( LSAPI_Request * pReq ) { static const char * headers[] = { "Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0", "Pragma: no-cache", "Retry-After: 60", "Content-Type: text/html", NULL }; static const char achBody[] = "\n" "\n508 Resource Limit Is Reached\n" "\n" "

    Resource Limit Is Reached

    \n" "The website is temporarily unable to service your request as it exceeded resource limit.\n" "Please try again later.\n" "
    \n" "\n"; LSAPI_ErrResponse_r( pReq, 508, headers, achBody, sizeof( achBody ) - 1 ); return 0; } static int lsapi_enterLVE( LSAPI_Request * pReq, uid_t uid ) { if ( s_lve && uid ) //root user should not do that { uint32_t cookie; int ret = -1; ret = (*fp_lve_enter)(s_lve, uid, -1, -1, &cookie); if ( ret < 0 ) { //lsapi_log("enter LVE (%d) : result: %d !\n", uid, ret ); LSAPI_perror_r(pReq, "LSAPI: lve_enter() failure, reached resource limit.", NULL ); lsapi_lve_error( pReq ); return -1; } } return 0; } static int lsapi_jailLVE( LSAPI_Request * pReq, uid_t uid, struct passwd * pw ) { int ret = 0; char error_msg[1024] = ""; ret = (*fp_lve_jail)( pw, error_msg ); if ( ret < 0 ) { lsapi_log("LSAPI: LVE jail(%d) result: %d, error: %s !\n", uid, ret, error_msg ); LSAPI_perror_r( pReq, "LSAPI: jail() failure.", NULL ); return -1; } return ret; } static int lsapi_initLVE(void) { const char * pEnv; if ( (pEnv = getenv( "LSAPI_LVE_ENABLE" ))!= NULL ) { s_enable_lve = atol( pEnv ); pEnv = NULL; } else if ( (pEnv = getenv( "LVE_ENABLE" ))!= NULL ) { s_enable_lve = atol( pEnv ); pEnv = NULL; } if ( s_enable_lve && !s_uid ) { lsapi_load_lve_lib(); if ( s_enable_lve ) { return init_lve_ex(); } } return 0; } #endif static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * pChroot) { int rv; struct passwd * pw; pw = getpwuid( uid ); #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if ( s_lve ) { if( lsapi_enterLVE( pReq, uid ) == -1 ) return -1; if ( pw && fp_lve_jail) { rv = lsapi_jailLVE( pReq, uid, pw ); if ( rv == -1 ) return -1; if (( rv == 1 )&&(s_enable_lve == LSAPI_CAGEFS_NO_SUEXEC )) //this mode only use cageFS, does not use suEXEC { uid = s_defaultUid; gid = s_defaultGid; pw = getpwuid( uid ); } } } #endif //if ( !uid || !gid ) //do not allow root //{ // return -1; //} #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) if ( s_enable_core_dump ) lsapi_enable_core_dump(); #endif rv = setgid(gid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setgid()", NULL); return -1; } if ( pw && (pw->pw_gid == gid )) { rv = initgroups( pw->pw_name, gid ); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: initgroups()", NULL); return -1; } } else { rv = setgroups(1, &gid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setgroups()", NULL); } } if ( pChroot ) { rv = chroot( pChroot ); if ( rv == -1 ) { LSAPI_perror_r(pReq, "LSAPI: chroot()", NULL); return -1; } } rv = setuid(uid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setuid()", NULL); return -1; } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if ( s_enable_core_dump ) lsapi_enable_core_dump(); #endif return 0; } static int lsapi_suexec_auth( LSAPI_Request *pReq, char * pAuth, int len, char * pUgid, int ugidLen ) { lsapi_MD5_CTX md5ctx; unsigned char achMD5[16]; if ( len < 32 ) return -1; memmove( achMD5, pAuth + 16, 16 ); memmove( pAuth + 16, s_secret, 16 ); lsapi_MD5Init( &md5ctx ); lsapi_MD5Update( &md5ctx, (unsigned char *)pAuth, 32 ); lsapi_MD5Update( &md5ctx, (unsigned char *)pUgid, 8 ); lsapi_MD5Final( (unsigned char *)pAuth + 16, &md5ctx); if ( memcmp( achMD5, pAuth + 16, 16 ) == 0 ) return 0; return 1; } static int lsapi_changeUGid( LSAPI_Request * pReq ) { int uid = s_defaultUid; int gid = s_defaultGid; const char *pStderrLog; const char *pChroot = NULL; struct LSAPI_key_value_pair * pEnv; struct LSAPI_key_value_pair * pAuth; int i; if ( s_uid ) return 0; //with special ID 0x00 //authenticate the suEXEC request; //first one should be MD5( nonce + lscgid secret ) //remember to clear the secret after verification //it should be set at the end of special env i = pReq->m_pHeader->m_cntSpecialEnv - 1; if ( i >= 0 ) { pEnv = pReq->m_pSpecialEnvList + i; if (( *pEnv->pKey == '\000' )&& ( strcmp( pEnv->pKey+1, "SUEXEC_AUTH" ) == 0 )) { --pReq->m_pHeader->m_cntSpecialEnv; pAuth = pEnv--; if (( *pEnv->pKey == '\000' )&& ( strcmp( pEnv->pKey+1, "SUEXEC_UGID" ) == 0 )) { --pReq->m_pHeader->m_cntSpecialEnv; uid = *(uint32_t *)pEnv->pValue; gid = *(((uint32_t *)pEnv->pValue) + 1 ); //lsapi_log("LSAPI: SUEXEC_UGID set UID: %d, GID: %d\n", uid, gid ); } else { lsapi_log("LSAPI: missing SUEXEC_UGID env, use default user!\n" ); pEnv = NULL; } if ( pEnv&& lsapi_suexec_auth( pReq, pAuth->pValue, pAuth->valLen, pEnv->pValue, pEnv->valLen ) == 0 ) { //read UID, GID from specialEnv } else { //authentication error lsapi_log("LSAPI: SUEXEC_AUTH authentication failed, use default user!\n" ); uid = 0; } } else { //lsapi_log("LSAPI: no SUEXEC_AUTH env, use default user!\n" ); } } if ( !uid ) { uid = s_defaultUid; gid = s_defaultGid; } //change uid if ( setUID_LVE( pReq, uid, gid, pChroot ) == -1 ) { return -1; } s_uid = uid; if ( pReq->m_fdListen != -1 ) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } pStderrLog = LSAPI_GetEnv_r( pReq, "LSAPI_STDERR_LOG"); if (pStderrLog) lsapi_reopen_stderr(pStderrLog); return 0; } static int parseContentLenFromHeader(LSAPI_Request * pReq) { const char * pContentLen = LSAPI_GetHeader_r( pReq, H_CONTENT_LENGTH ); if ( pContentLen ) pReq->m_reqBodyLen = strtoll( pContentLen, NULL, 10 ); return 0; } static int parseRequest( LSAPI_Request * pReq, int totalLen ) { int shouldFixEndian; char * pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header ); char * pEnd = pReq->m_pReqBuf + totalLen; shouldFixEndian = ( LSAPI_ENDIAN != ( pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) ); if ( shouldFixEndian ) { fixEndian( pReq ); } if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&& allocateEnvList( &pReq->m_pSpecialEnvList, &pReq->m_specialEnvListSize, pReq->m_pHeader->m_cntSpecialEnv ) == -1 ) return -1; if ( (pReq->m_envListSize < pReq->m_pHeader->m_cntEnv )&& allocateEnvList( &pReq->m_pEnvList, &pReq->m_envListSize, pReq->m_pHeader->m_cntEnv ) == -1 ) return -1; if ( parseEnv( pReq->m_pSpecialEnvList, pReq->m_pHeader->m_cntSpecialEnv, &pBegin, pEnd ) == -1 ) return -1; if ( parseEnv( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, &pBegin, pEnd ) == -1 ) return -1; if (pReq->m_pHeader->m_scriptFileOff < 0 || pReq->m_pHeader->m_scriptFileOff >= totalLen || pReq->m_pHeader->m_scriptNameOff < 0 || pReq->m_pHeader->m_scriptNameOff >= totalLen || pReq->m_pHeader->m_queryStringOff < 0 || pReq->m_pHeader->m_queryStringOff >= totalLen || pReq->m_pHeader->m_requestMethodOff < 0 || pReq->m_pHeader->m_requestMethodOff >= totalLen) { lsapi_log("Bad request header - ERROR#1\n"); return -1; } pReq->m_pScriptFile = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptFileOff; pReq->m_pScriptName = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff; pReq->m_pQueryString = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff; pReq->m_pRequestMethod = pReq->m_pReqBuf + pReq->m_pHeader->m_requestMethodOff; pBegin = pReq->m_pReqBuf + (( pBegin - pReq->m_pReqBuf + 7 ) & (~0x7)); pReq->m_pHeaderIndex = ( struct lsapi_http_header_index * )pBegin; pBegin += sizeof( struct lsapi_http_header_index ); pReq->m_pUnknownHeader = (struct lsapi_header_offset *)pBegin; pBegin += sizeof( struct lsapi_header_offset) * pReq->m_pHeader->m_cntUnknownHeaders; pReq->m_pHttpHeader = pBegin; pBegin += pReq->m_pHeader->m_httpHeaderLen; if ( pBegin != pEnd ) { lsapi_log("Request header does match total size, total: %d, " "real: %ld\n", totalLen, pBegin - pReq->m_pReqBuf ); return -1; } if ( shouldFixEndian ) { fixHeaderIndexEndian( pReq ); } if (validateHeaders(pReq) == -1) { lsapi_log("Bad request header - ERROR#2\n"); return -1; } pReq->m_reqBodyLen = pReq->m_pHeader->m_reqBodyLen; if ( pReq->m_reqBodyLen == -2 ) { parseContentLenFromHeader(pReq); } return 0; } //OPTIMIZATION static char s_accept_notify = 0; static char s_schedule_notify = 0; static char s_notify_scheduled = 0; static char s_notified_pid = 0; static struct lsapi_packet_header s_ack = {'L', 'S', LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; static struct lsapi_packet_header s_conn_close_pkt = {'L', 'S', LSAPI_CONN_CLOSE, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; static inline int send_notification_pkt( int fd, struct lsapi_packet_header *pkt ) { if ( write( fd, pkt, LSAPI_PACKET_HEADER_LEN ) < LSAPI_PACKET_HEADER_LEN ) return -1; return 0; } static inline int send_req_received_notification( int fd ) { return send_notification_pkt(fd, &s_ack); } static inline int send_conn_close_notification( int fd ) { return send_notification_pkt(fd, &s_conn_close_pkt); } //static void lsapi_sigalarm( int sig ) //{ // if ( s_notify_scheduled ) // { // s_notify_scheduled = 0; // if ( g_req.m_fd != -1 ) // write_req_received_notification( g_req.m_fd ); // } //} static inline int lsapi_schedule_notify(void) { if ( !s_notify_scheduled ) { alarm( 2 ); s_notify_scheduled = 1; } return 0; } static inline int notify_req_received( int fd ) { if ( s_schedule_notify ) return lsapi_schedule_notify(); return send_req_received_notification( fd ); } static inline int lsapi_notify_pid( int fd ) { char achBuf[16]; lsapi_buildPacketHeader( (struct lsapi_packet_header *)achBuf, LSAPI_STDERR_STREAM, 8 + LSAPI_PACKET_HEADER_LEN ); memmove( &achBuf[8], "\0PID", 4 ); *((int *)&achBuf[12]) = getpid(); if ( write( fd, achBuf, 16 ) < 16 ) return -1; return 0; } static int readReq( LSAPI_Request * pReq ) { int len; int packetLen; if ( !pReq ) return -1; if ( pReq->m_reqBufSize < 8192 ) { if ( allocateBuf( pReq, 8192 ) == -1 ) return -1; } while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN ) { len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize ); if ( len <= 0 ) return -1; pReq->m_bufRead += len; } pReq->m_reqState = LSAPI_ST_REQ_HEADER; packetLen = verifyHeader( &pReq->m_pHeader->m_pktHeader, LSAPI_BEGIN_REQUEST ); if ( packetLen < 0 ) { lsapi_log("packetLen < 0\n"); return -1; } if ( packetLen > LSAPI_MAX_HEADER_LEN ) { lsapi_log("packetLen > %d\n", LSAPI_MAX_HEADER_LEN ); return -1; } if ( packetLen + 1024 > pReq->m_reqBufSize ) { if ( allocateBuf( pReq, packetLen + 1024 ) == -1 ) return -1; } while( packetLen > pReq->m_bufRead ) { len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, packetLen - pReq->m_bufRead ); if ( len <= 0 ) return -1; pReq->m_bufRead += len; } if ( parseRequest( pReq, packetLen ) < 0 ) { lsapi_log("ParseRequest error\n"); return -1; } pReq->m_reqState = LSAPI_ST_REQ_BODY | LSAPI_ST_RESP_HEADER; if ( !s_uid ) { if ( lsapi_changeUGid( pReq ) ) return -1; memset(s_secret, 0, sizeof(s_secret)); } pReq->m_bufProcessed = packetLen; //OPTIMIZATION if ( !s_accept_notify && !s_notified_pid ) return notify_req_received( pReq->m_fd ); else { s_notified_pid = 0; return 0; } } int LSAPI_Init(void) { if ( !g_inited ) { s_uid = geteuid(); s_secret[0] = 0; lsapi_signal(SIGPIPE, lsapi_sigpipe); lsapi_signal(SIGUSR1, lsapi_siguser1); #if defined(SIGXFSZ) && defined(SIG_IGN) signal(SIGXFSZ, SIG_IGN); #endif /* let STDOUT function as STDERR, just in case writing to STDOUT directly */ dup2( 2, 1 ); if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 ) return -1; g_inited = 1; s_ppid = getppid(); void *pthread_lib = dlopen("libpthread.so", RTLD_LAZY); if (pthread_lib) pthread_atfork_func = dlsym(pthread_lib, "pthread_atfork"); } return 0; } void LSAPI_Stop(void) { g_running = 0; } int LSAPI_IsRunning(void) { return g_running; } void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf cb) { s_proc_group_timer_cb = cb; } int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ) { int newfd; if ( !pReq ) return -1; memset( pReq, 0, sizeof( LSAPI_Request ) ); if ( allocateIovec( pReq, 16 ) == -1 ) return -1; pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE ); if ( !pReq->m_pRespBuf ) return -1; pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5]; if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 ) return -1; if ( fd == STDIN_FILENO ) { fd = dup( fd ); newfd = open( "/dev/null", O_RDWR ); dup2( newfd, STDIN_FILENO ); } if ( isPipe( fd ) ) { pReq->m_fdListen = -1; pReq->m_fd = fd; } else { pReq->m_fdListen = fd; pReq->m_fd = -1; lsapi_set_nblock( fd, 1 ); } return 0; } int LSAPI_Is_Listen( void ) { return LSAPI_Is_Listen_r( &g_req ); } int LSAPI_Is_Listen_r( LSAPI_Request * pReq) { return pReq->m_fdListen != -1; } int LSAPI_Accept_r( LSAPI_Request * pReq ) { char achPeer[128]; socklen_t len; int nodelay = 1; if ( !pReq ) return -1; if ( LSAPI_Finish_r( pReq ) == -1 ) return -1; lsapi_set_nblock( pReq->m_fdListen , 0 ); while( g_running ) { if ( pReq->m_fd == -1 ) { if ( pReq->m_fdListen != -1) { len = sizeof( achPeer ); pReq->m_fd = accept( pReq->m_fdListen, (struct sockaddr *)&achPeer, &len ); if ( pReq->m_fd == -1 ) { if (( errno == EINTR )||( errno == EAGAIN)) continue; else return -1; } else { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd , 0 ); if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); } //init_conn_key( pReq->m_fd ); //OPTIMIZATION if ( s_accept_notify ) if ( notify_req_received( pReq->m_fd ) == -1 ) return -1; } } else return -1; } if ( !readReq( pReq ) ) break; //abort(); lsapi_close_connection(pReq); LSAPI_Reset_r( pReq ); } return 0; } static struct lsapi_packet_header finish_close[2] = { {'L', 'S', LSAPI_RESP_END, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }, {'L', 'S', LSAPI_CONN_CLOSE, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} } }; int LSAPI_Finish_r( LSAPI_Request * pReq ) { /* finish req body */ if ( !pReq ) return -1; if (pReq->m_reqState) { if ( pReq->m_fd != -1 ) { if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } pReq->m_pIovecCur->iov_base = (void *)finish_close; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; LSAPI_Flush_r( pReq ); } LSAPI_Reset_r( pReq ); } return 0; } int LSAPI_End_Response_r(LSAPI_Request * pReq) { if (!pReq) return -1; if (pReq->m_reqState & LSAPI_ST_BACKGROUND) return 0; if (pReq->m_reqState) { if ( pReq->m_fd != -1 ) { if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { if ( pReq->m_pRespHeaderBufPos <= pReq->m_pRespHeaderBuf ) return 0; LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } pReq->m_pIovecCur->iov_base = (void *)finish_close; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN << 1; pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN << 1; ++pReq->m_pIovecCur; LSAPI_Flush_r( pReq ); lsapi_close_connection(pReq); } pReq->m_reqState |= LSAPI_ST_BACKGROUND; } return 0; } void LSAPI_Reset_r( LSAPI_Request * pReq ) { pReq->m_pRespBufPos = pReq->m_pRespBuf; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; pReq->m_pRespHeaderBufPos = pReq->m_pRespHeaderBuf; memset( &pReq->m_pHeaderIndex, 0, (char *)(pReq->m_respHeaderLen) - (char *)&pReq->m_pHeaderIndex ); } int LSAPI_Release_r( LSAPI_Request * pReq ) { if ( pReq->m_pReqBuf ) free( pReq->m_pReqBuf ); if ( pReq->m_pSpecialEnvList ) free( pReq->m_pSpecialEnvList ); if ( pReq->m_pEnvList ) free( pReq->m_pEnvList ); if ( pReq->m_pRespHeaderBuf ) free( pReq->m_pRespHeaderBuf ); return 0; } char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ) { int off; if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) ) return NULL; off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ]; if ( !off ) return NULL; if ( *(pReq->m_pHttpHeader + off + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) ) { *( pReq->m_pHttpHeader + off + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0; } return pReq->m_pHttpHeader + off; } static int readBodyToReqBuf( LSAPI_Request * pReq ) { off_t bodyLeft; ssize_t len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len > 0 ) return len; pReq->m_bufRead = pReq->m_bufProcessed = pReq->m_pHeader->m_pktHeader.m_packetLen.m_iLen; bodyLeft = pReq->m_reqBodyLen - pReq->m_reqBodyRead; len = pReq->m_reqBufSize - pReq->m_bufRead; if ( len < 0 ) return -1; if ( len > bodyLeft ) len = bodyLeft; len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, len ); if ( len > 0 ) pReq->m_bufRead += len; return len; } int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ) { if (!pReq || (pReq->m_fd ==-1) ) return EOF; if ( pReq->m_bufProcessed >= pReq->m_bufRead ) { if ( readBodyToReqBuf( pReq ) <= 0 ) return EOF; } ++pReq->m_reqBodyRead; return (unsigned char)*(pReq->m_pReqBuf + pReq->m_bufProcessed++); } int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF ) { ssize_t len; ssize_t left; char * pBufEnd = pBuf + bufLen - 1; char * pBufCur = pBuf; char * pCur; char * p; if (!pReq || pReq->m_fd == -1 || !pBuf || !getLF) return -1; *getLF = 0; while( (left = pBufEnd - pBufCur ) > 0 ) { len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len <= 0 ) { if ( (len = readBodyToReqBuf( pReq )) <= 0 ) { *getLF = 1; break; } } if ( len > left ) len = left; pCur = pReq->m_pReqBuf + pReq->m_bufProcessed; p = memchr( pCur, '\n', len ); if ( p ) len = p - pCur + 1; memmove( pBufCur, pCur, len ); pBufCur += len; pReq->m_bufProcessed += len; pReq->m_reqBodyRead += len; if ( p ) { *getLF = 1; break; } } *pBufCur = 0; return pBufCur - pBuf; } ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen ) { ssize_t len; off_t total; /* char *pOldBuf = pBuf; */ if (!pReq || pReq->m_fd == -1 || !pBuf || (ssize_t)bufLen < 0) return -1; total = pReq->m_reqBodyLen - pReq->m_reqBodyRead; if ( total <= 0 ) return 0; if ( total < (ssize_t)bufLen ) bufLen = total; total = 0; len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len > 0 ) { if ( len > (ssize_t)bufLen ) len = bufLen; memmove( pBuf, pReq->m_pReqBuf + pReq->m_bufProcessed, len ); pReq->m_bufProcessed += len; total += len; pBuf += len; bufLen -= len; } while( bufLen > 0 ) { len = lsapi_read( pReq->m_fd, pBuf, bufLen ); if ( len > 0 ) { total += len; pBuf += len; bufLen -= len; } else if ( len <= 0 ) { if ( !total) return -1; break; } } pReq->m_reqBodyRead += total; return total; } ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len ) { struct lsapi_packet_header * pHeader; const char * pEnd; const char * p; ssize_t bufLen; ssize_t toWrite; ssize_t packetLen; int skip = 0; if (!pReq || !pBuf) return -1; if (pReq->m_reqState & LSAPI_ST_BACKGROUND) return len; if (pReq->m_fd == -1) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); /* if ( *pBuf == '\r' ) { ++skip; } if ( *pBuf == '\n' ) { ++skip; } */ } pReq->m_reqState |= LSAPI_ST_RESP_BODY; if ( ((ssize_t)len - skip) < pReq->m_pRespBufEnd - pReq->m_pRespBufPos ) { memmove( pReq->m_pRespBufPos, pBuf + skip, len - skip ); pReq->m_pRespBufPos += len - skip; return len; } pHeader = pReq->m_respPktHeader; p = pBuf + skip; pEnd = pBuf + len; bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; while( ( toWrite = pEnd - p ) > 0 ) { packetLen = toWrite + bufLen; if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { packetLen = LSAPI_MAX_DATA_PACKET_LEN; toWrite = packetLen - bufLen; } lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, packetLen + LSAPI_PACKET_HEADER_LEN ); pReq->m_totalLen += packetLen + LSAPI_PACKET_HEADER_LEN; pReq->m_pIovecCur->iov_base = (void *)pHeader; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; ++pHeader; if ( bufLen > 0 ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; pReq->m_pIovecCur->iov_len = bufLen; pReq->m_pRespBufPos = pReq->m_pRespBuf; ++pReq->m_pIovecCur; bufLen = 0; } pReq->m_pIovecCur->iov_base = (void *)p; pReq->m_pIovecCur->iov_len = toWrite; ++pReq->m_pIovecCur; p += toWrite; if ( pHeader >= pReq->m_respPktHeaderEnd - 1) { if ( LSAPI_Flush_r( pReq ) == -1 ) return -1; pHeader = pReq->m_respPktHeader; } } if ( pHeader != pReq->m_respPktHeader ) if ( LSAPI_Flush_r( pReq ) == -1 ) return -1; return p - pBuf; } #if defined(__FreeBSD__ ) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t written; ret = sendfile( fdIn, fdOut, *off, size, NULL, &written, 0 ); if ( written > 0 ) { ret = written; *off += ret; } return ret; } #endif #if defined(__OpenBSD__) || defined(__NetBSD__) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t written = 0; const size_t bufsiz = 16384; unsigned char in[bufsiz] = {0}; if (lseek(fdIn, *off, SEEK_SET) == -1) { return -1; } while (size > 0) { size_t tor = size > sizeof(in) ? sizeof(in) : size; ssize_t c = read(fdIn, in, tor); if (c <= 0) { goto end; } ssize_t w = write(fdOut, in, c); if (w > 0) written += w; if (w != c) { goto end; } size -= c; } end: *off += written; return 0; } #endif #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t len = size; ret = sendfile( fdIn, fdOut, *off, &len, NULL, 0 ); if (( ret == 0 )&&( len > 0 )) { ret = len; *off += len; } return ret; } #endif #if defined(sun) || defined(__sun) #include ssize_t gsendfile( int fdOut, int fdIn, off_t *off, size_t size ) { int n = 0 ; sendfilevec_t vec[1]; vec[n].sfv_fd = fdIn; vec[n].sfv_flag = 0; vec[n].sfv_off = *off; vec[n].sfv_len = size; ++n; size_t written; ssize_t ret = sendfilev( fdOut, vec, n, &written ); if (( !ret )||( errno == EAGAIN )) ret = written; if ( ret > 0 ) *off += ret; return ret; } #endif #if defined(linux) || defined(__linux) || defined(__linux__) || \ defined(__gnu_linux__) #include #define gsendfile sendfile #endif #if defined(HPUX) ssize_t gsendfile( int fdOut, int fdIn, off_t * off, size_t size ) { return sendfile( fdOut, fdIn, off, size, NULL, 0 ); } #endif ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size ) { struct lsapi_packet_header * pHeader = pReq->m_respPktHeader; if ( !pReq || (pReq->m_fd == -1) || fdIn == -1 ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } pReq->m_reqState |= LSAPI_ST_RESP_BODY; LSAPI_Flush_r(pReq); lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, size + LSAPI_PACKET_HEADER_LEN ); if (write(pReq->m_fd, (const char *) pHeader, LSAPI_PACKET_HEADER_LEN ) != LSAPI_PACKET_HEADER_LEN) return -1; return gsendfile( pReq->m_fd, fdIn, off, size ); } void Flush_RespBuf_r( LSAPI_Request * pReq ) { struct lsapi_packet_header * pHeader = pReq->m_respPktHeader; int bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; pReq->m_reqState |= LSAPI_ST_RESP_BODY; lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, bufLen + LSAPI_PACKET_HEADER_LEN ); pReq->m_totalLen += bufLen + LSAPI_PACKET_HEADER_LEN; pReq->m_pIovecCur->iov_base = (void *)pHeader; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; ++pHeader; if ( bufLen > 0 ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; pReq->m_pIovecCur->iov_len = bufLen; pReq->m_pRespBufPos = pReq->m_pRespBuf; ++pReq->m_pIovecCur; bufLen = 0; } } int LSAPI_Flush_r( LSAPI_Request * pReq ) { int ret = 0; int n; if ( !pReq ) return -1; n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf )) return 0; if ( pReq->m_fd == -1 ) { pReq->m_pRespBufPos = pReq->m_pRespBuf; pReq->m_totalLen = 0; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; return -1; } if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; if ( n > 0 ) { ret = lsapi_writev( pReq->m_fd, &pReq->m_pIovecToWrite, n, pReq->m_totalLen ); if ( ret < pReq->m_totalLen ) { lsapi_close_connection(pReq); ret = -1; } pReq->m_totalLen = 0; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; } return ret; } ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len ) { struct lsapi_packet_header header; const char * pEnd; const char * p; ssize_t packetLen; ssize_t totalLen; int ret; struct iovec iov[2]; struct iovec *pIov; if ( !pReq ) return -1; if (s_stderr_log_path || pReq->m_fd == -1 || pReq->m_fd == pReq->m_fdListen) return write( 2, pBuf, len ); if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { LSAPI_Flush_r( pReq ); } p = pBuf; pEnd = pBuf + len; while( ( packetLen = pEnd - p ) > 0 ) { if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { packetLen = LSAPI_MAX_DATA_PACKET_LEN; } lsapi_buildPacketHeader( &header, LSAPI_STDERR_STREAM, packetLen + LSAPI_PACKET_HEADER_LEN ); totalLen = packetLen + LSAPI_PACKET_HEADER_LEN; iov[0].iov_base = (void *)&header; iov[0].iov_len = LSAPI_PACKET_HEADER_LEN; iov[1].iov_base = (void *)p; iov[1].iov_len = packetLen; p += packetLen; pIov = iov; ret = lsapi_writev( pReq->m_fd, &pIov, 2, totalLen ); if ( ret < totalLen ) { lsapi_close_connection(pReq); ret = -1; } } return p - pBuf; } static char * GetHeaderVar( LSAPI_Request * pReq, const char * name ) { int i; char * pValue; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { if ( strcmp( name, CGI_HEADERS[i] ) == 0 ) { pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; if ( *(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) != '\0') { *(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) = '\0'; } return pValue; } } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { const char *p; char *pKey; char *pKeyEnd; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; pKeyEnd = pKey + keyLen; p = &name[5]; while(( pKey < pKeyEnd )&&( *p )) { char ch = toupper( *pKey ); if ((ch != *p )||(( *p == '_' )&&( ch != '-'))) break; ++p; ++pKey; } if (( pKey == pKeyEnd )&& (!*p )) { pValue = pReq->m_pHttpHeader + pCur->valueOff; if ( *(pValue + pCur->valueLen) != '\0') { *(pValue + pCur->valueLen) = '\0'; } return pValue; } ++pCur; } } return NULL; } char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ) { struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList; struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv; if ( !pReq || !name ) return NULL; if ( strncmp( name, "HTTP_", 5 ) == 0 ) { return GetHeaderVar( pReq, name ); } while( pBegin < pEnd ) { if ( strcmp( name, pBegin->pKey ) == 0 ) return pBegin->pValue; ++pBegin; } return NULL; } struct _headerInfo { const char * _name; int _nameLen; const char * _value; int _valueLen; }; int compareValueLocation(const void * v1, const void *v2 ) { return ((const struct _headerInfo *)v1)->_value - ((const struct _headerInfo *)v2)->_value; } int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { int i; int len = 0; char * pValue; int ret; int count = 0; struct _headerInfo headers[512]; if ( !pReq || !fn ) return -1; if ( !pReq->m_pHeaderIndex ) return 0; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { len = pReq->m_pHeaderIndex->m_headerLen[i]; pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; *(pValue + len ) = 0; headers[count]._name = HTTP_HEADERS[i]; headers[count]._nameLen = HTTP_HEADER_LEN[i]; headers[count]._value = pValue; headers[count]._valueLen = len; ++count; //ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i], // pValue, len, arg ); //if ( ret <= 0 ) // return ret; } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { char *pKey; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; *(pKey + keyLen ) = 0; pValue = pReq->m_pHttpHeader + pCur->valueOff; *(pValue + pCur->valueLen ) = 0; headers[count]._name = pKey; headers[count]._nameLen = keyLen; headers[count]._value = pValue; headers[count]._valueLen = pCur->valueLen; ++count; if ( count == 512 ) break; //ret = (*fn)( pKey, keyLen, // pValue, pCur->valueLen, arg ); //if ( ret <= 0 ) // return ret; ++pCur; } } qsort( headers, count, sizeof( struct _headerInfo ), compareValueLocation ); for( i = 0; i < count; ++i ) { ret = (*fn)( headers[i]._name, headers[i]._nameLen, headers[i]._value, headers[i]._valueLen, arg ); if ( ret <= 0 ) return ret; } return count; } int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { int i; int len = 0; char * pValue; int ret; int count = 0; if ( !pReq || !fn ) return -1; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { len = pReq->m_pHeaderIndex->m_headerLen[i]; pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; *(pValue + len ) = 0; ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i], pValue, len, arg ); ++count; if ( ret <= 0 ) return ret; } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { char achHeaderName[256]; char *p; char *pKey; char *pKeyEnd ; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; if ( keyLen > 250 ) keyLen = 250; pKeyEnd = pKey + keyLen; memcpy( achHeaderName, "HTTP_", 5 ); p = &achHeaderName[5]; while( pKey < pKeyEnd ) { char ch = *pKey++; if ( ch == '-' ) *p++ = '_'; else *p++ = toupper( ch ); } *p = 0; keyLen += 5; pValue = pReq->m_pHttpHeader + pCur->valueOff; *(pValue + pCur->valueLen ) = 0; ret = (*fn)( achHeaderName, keyLen, pValue, pCur->valueLen, arg ); if ( ret <= 0 ) return ret; ++pCur; } } return count + pReq->m_pHeader->m_cntUnknownHeaders; } static int EnvForeach( struct LSAPI_key_value_pair * pEnv, int n, LSAPI_CB_EnvHandler fn, void * arg ) { struct LSAPI_key_value_pair * pEnd = pEnv + n; int ret; if ( !pEnv || !fn ) return -1; while( pEnv < pEnd ) { ret = (*fn)( pEnv->pKey, pEnv->keyLen, pEnv->pValue, pEnv->valLen, arg ); if ( ret <= 0 ) return ret; ++pEnv; } return n; } int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { if ( !pReq || !fn ) return -1; if ( pReq->m_pHeader->m_cntEnv > 0 ) { return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, fn, arg ); } return 0; } int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { if ( !pReq || !fn ) return -1; if ( pReq->m_pHeader->m_cntSpecialEnv > 0 ) { return EnvForeach( pReq->m_pSpecialEnvList, pReq->m_pHeader->m_cntSpecialEnv, fn, arg ); } return 0; } int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ) { if ( !pReq || !pReq->m_pIovec ) return -1; if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) ) return 0; pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER; if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf; pReq->m_pIovecCur->iov_len = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf; pReq->m_totalLen += pReq->m_pIovecCur->iov_len; ++pReq->m_pIovecCur; } pReq->m_pIovec->iov_len = sizeof( struct lsapi_resp_header) + pReq->m_respHeader.m_respInfo.m_cntHeaders * sizeof( short ); pReq->m_totalLen += pReq->m_pIovec->iov_len; lsapi_buildPacketHeader( &pReq->m_respHeader.m_pktHeader, LSAPI_RESP_HEADER, pReq->m_totalLen ); pReq->m_pIovec->iov_base = (void *)&pReq->m_respHeader; pReq->m_pIovecToWrite = pReq->m_pIovec; return 0; } int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName, const char * pHeaderValue ) { int nameLen, valLen, len; if ( !pReq || !pHeaderName || !pHeaderValue ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) return -1; if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) return -1; nameLen = strlen( pHeaderName ); valLen = strlen( pHeaderValue ); if ( nameLen == 0 ) return -1; while( nameLen > 0 ) { char ch = *(pHeaderName + nameLen - 1 ); if (( ch == '\n' )||( ch == '\r' )) --nameLen; else break; } if ( nameLen <= 0 ) return 0; while( valLen > 0 ) { char ch = *(pHeaderValue + valLen - 1 ); if (( ch == '\n' )||( ch == '\r' )) --valLen; else break; } len = nameLen + valLen + 1; if ( len > LSAPI_RESP_HTTP_HEADER_MAX ) return -1; if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) { int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf; newlen -= newlen % 4096; if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) return -1; } memmove( pReq->m_pRespHeaderBufPos, pHeaderName, nameLen ); pReq->m_pRespHeaderBufPos += nameLen; *pReq->m_pRespHeaderBufPos++ = ':'; memmove( pReq->m_pRespHeaderBufPos, pHeaderValue, valLen ); pReq->m_pRespHeaderBufPos += valLen; *pReq->m_pRespHeaderBufPos++ = 0; ++len; /* add one byte padding for \0 */ pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len; ++pReq->m_respHeader.m_respInfo.m_cntHeaders; return 0; } int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len ) { if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) return -1; if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) return -1; while( len > 0 ) { char ch = *(pBuf + len - 1 ); if (( ch == '\n' )||( ch == '\r' )) --len; else break; } if ( len <= 0 ) return 0; if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) { int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf; newlen -= newlen % 4096; if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) return -1; } memmove( pReq->m_pRespHeaderBufPos, pBuf, len ); pReq->m_pRespHeaderBufPos += len; *pReq->m_pRespHeaderBufPos++ = 0; ++len; /* add one byte padding for \0 */ pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len; ++pReq->m_respHeader.m_respInfo.m_cntHeaders; return 0; } int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog ) { int ret; int fd; int flag = 1; int addr_len; switch( pServerAddr->sa_family ) { case AF_INET: addr_len = 16; break; case AF_INET6: addr_len = sizeof( struct sockaddr_in6 ); break; case AF_UNIX: addr_len = sizeof( struct sockaddr_un ); unlink( ((struct sockaddr_un *)pServerAddr)->sun_path ); break; default: return -1; } fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 ); if ( fd == -1 ) return -1; fcntl( fd, F_SETFD, FD_CLOEXEC ); if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char *)( &flag ), sizeof(flag)) == 0) { ret = bind( fd, pServerAddr, addr_len ); if ( !ret ) { ret = listen( fd, backlog ); if ( !ret ) return fd; } } ret = errno; close(fd); errno = ret; return -1; } int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr ) { char achAddr[256]; char * p = achAddr; char * pEnd; struct addrinfo *res, hints; int doAddrInfo = 0; int port; if ( !pBind ) return -1; while( isspace( *pBind ) ) ++pBind; strncpy(achAddr, pBind, 255); achAddr[255] = 0; switch( *p ) { case '/': pAddr->sa_family = AF_UNIX; strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p, sizeof(((struct sockaddr_un *)pAddr)->sun_path) ); return 0; case '[': pAddr->sa_family = AF_INET6; ++p; pEnd = strchr( p, ']' ); if ( !pEnd ) return -1; *pEnd++ = 0; if ( *p == '*' ) { strcpy( achAddr, "::" ); p = achAddr; } doAddrInfo = 1; break; default: pAddr->sa_family = AF_INET; pEnd = strchr( p, ':' ); if ( !pEnd ) return -1; *pEnd++ = 0; doAddrInfo = 0; if ( *p == '*' ) { ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY); } else if (!strcasecmp( p, "localhost" ) ) ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK ); else { #ifdef HAVE_INET_PTON if (!inet_pton(AF_INET, p, &((struct sockaddr_in *)pAddr)->sin_addr)) #else ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p ); if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST) #endif { doAddrInfo = 1; } } break; } if ( *pEnd == ':' ) ++pEnd; port = atoi( pEnd ); if (( port <= 0 )||( port > 65535 )) return -1; if ( doAddrInfo ) { memset(&hints, 0, sizeof(hints)); hints.ai_family = pAddr->sa_family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if ( getaddrinfo(p, NULL, &hints, &res) ) { return -1; } memcpy(pAddr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); } if ( pAddr->sa_family == AF_INET ) ((struct sockaddr_in *)pAddr)->sin_port = htons( port ); else ((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port ); return 0; } int LSAPI_CreateListenSock( const char * pBind, int backlog ) { char serverAddr[128]; int ret; int fd = -1; ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr ); if ( !ret ) { fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog ); } return fd; } static fn_select_t g_fnSelect = select; typedef struct _lsapi_prefork_server { int m_fd; int m_iMaxChildren; int m_iExtraChildren; int m_iCurChildren; int m_iMaxIdleChildren; int m_iServerMaxIdle; int m_iChildrenMaxIdleTime; int m_iMaxReqProcessTime; int m_iAvoidFork; lsapi_child_status * m_pChildrenStatus; lsapi_child_status * m_pChildrenStatusCur; lsapi_child_status * m_pChildrenStatusEnd; }lsapi_prefork_server; static lsapi_prefork_server * g_prefork_server = NULL; int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ) { if ( g_prefork_server ) return 0; if ( max_children <= 1 ) return -1; if ( max_children >= 10000) max_children = 10000; if (s_max_busy_workers == 0) s_max_busy_workers = max_children / 2 + 1; g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) ); if ( !g_prefork_server ) return -1; memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) ); if ( fp != NULL ) g_fnSelect = fp; s_ppid = getppid(); s_pid = getpid(); setpgid( s_pid, s_pid ); #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) s_total_pages = sysconf(_SC_PHYS_PAGES); #endif g_prefork_server->m_iAvoidFork = avoidFork; g_prefork_server->m_iMaxChildren = max_children; g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ; g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3); if ( g_prefork_server->m_iMaxIdleChildren == 0 ) g_prefork_server->m_iMaxIdleChildren = 1; g_prefork_server->m_iChildrenMaxIdleTime = 300; g_prefork_server->m_iMaxReqProcessTime = 3600; setsid(); return 0; } void LSAPI_Set_Server_fd( int fd ) { if( g_prefork_server ) g_prefork_server->m_fd = fd; } static int lsapi_accept( int fdListen ) { int fd; int nodelay = 1; socklen_t len; char achPeer[128]; len = sizeof( achPeer ); fd = accept( fdListen, (struct sockaddr *)&achPeer, &len ); if ( fd != -1 ) { if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); } //OPTIMIZATION //if ( s_accept_notify ) // notify_req_received( fd ); } return fd; } static unsigned int s_max_reqs = UINT_MAX; static int s_max_idle_secs = 300; static int s_stop; static void lsapi_cleanup(int signal) { s_stop = signal; } static lsapi_child_status * find_child_status( int pid ) { lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd; while( pStatus < pEnd ) { if ( pStatus->m_pid == pid ) { if (pid == 0) { memset(pStatus, 0, sizeof( *pStatus ) ); pStatus->m_pid = -1; } if ( pStatus + 1 > g_prefork_server->m_pChildrenStatusCur ) g_prefork_server->m_pChildrenStatusCur = pStatus + 1; return pStatus; } ++pStatus; } return NULL; } void LSAPI_reset_server_state( void ) { /* Reset child status */ g_prefork_server->m_iCurChildren = 0; lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd; while( pStatus < pEnd ) { pStatus->m_pid = 0; ++pStatus; } if (s_busy_workers) __atomic_store_n(s_busy_workers, 0, __ATOMIC_SEQ_CST); if (s_accepting_workers) __atomic_store_n(s_accepting_workers, 0, __ATOMIC_SEQ_CST); } static void lsapi_sigchild( int signal ) { int status, pid; char expect_connected = LSAPI_STATE_CONNECTED; char expect_accepting = LSAPI_STATE_ACCEPTING; lsapi_child_status * child_status; if (g_prefork_server == NULL) return; while( 1 ) { pid = waitpid( -1, &status, WNOHANG|WUNTRACED ); if ( pid <= 0 ) { break; } if ( WIFSIGNALED( status )) { int sig_num = WTERMSIG( status ); #ifdef WCOREDUMP const char * dump = WCOREDUMP( status ) ? "yes" : "no"; #else const char * dump = "unknown"; #endif lsapi_log("Child process with pid: %d was killed by signal: " "%d, core dumped: %s\n", pid, sig_num, dump ); } if ( pid == s_pid_dump_debug_info ) { pid = 0; continue; } if ( pid == s_ignore_pid ) { pid = 0; s_ignore_pid = -1; continue; } child_status = find_child_status( pid ); if ( child_status ) { if (__atomic_compare_exchange_n(&child_status->m_state, &expect_connected, LSAPI_STATE_IDLE, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { if (s_busy_workers) __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST); } else if (__atomic_compare_exchange_n(&child_status->m_state, &expect_accepting, LSAPI_STATE_IDLE, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { if (s_accepting_workers) __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST); } child_status->m_pid = 0; --g_prefork_server->m_iCurChildren; } } while(( g_prefork_server->m_pChildrenStatusCur > g_prefork_server->m_pChildrenStatus ) &&( g_prefork_server->m_pChildrenStatusCur[-1].m_pid == 0 )) --g_prefork_server->m_pChildrenStatusCur; } static int lsapi_init_children_status(void) { char * pBuf; int size = 4096; int max_children; if (g_prefork_server->m_pChildrenStatus) return 0; max_children = g_prefork_server->m_iMaxChildren + g_prefork_server->m_iExtraChildren; size = max_children * sizeof( lsapi_child_status ) * 2 + 3 * sizeof(int); size = (size + 4095) / 4096 * 4096; pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0 ); if ( pBuf == MAP_FAILED ) { perror( "Anonymous mmap() failed" ); return -1; } memset( pBuf, 0, size ); g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf; g_prefork_server->m_pChildrenStatusCur = (lsapi_child_status *)pBuf; g_prefork_server->m_pChildrenStatusEnd = (lsapi_child_status *)pBuf + max_children; s_busy_workers = (int *)g_prefork_server->m_pChildrenStatusEnd; s_accepting_workers = s_busy_workers + 1; s_global_counter = s_accepting_workers + 1; s_avail_pages = (size_t *)(s_global_counter + 1); setsid(); return 0; } static void dump_debug_info( lsapi_child_status * pStatus, long tmCur ) { char achCmd[1024]; if ( s_pid_dump_debug_info ) { if ( kill( s_pid_dump_debug_info, 0 ) == 0 ) return; } lsapi_log("Possible runaway process, UID: %d, PPID: %d, PID: %d, " "reqCount: %d, process time: %ld, checkpoint time: %ld, start " "time: %ld\n", getuid(), getppid(), pStatus->m_pid, pStatus->m_iReqCounter, tmCur - pStatus->m_tmReqBegin, tmCur - pStatus->m_tmLastCheckPoint, tmCur - pStatus->m_tmStart ); s_pid_dump_debug_info = fork(); if (s_pid_dump_debug_info == 0) { snprintf( achCmd, 1024, "gdb --batch -ex \"attach %d\" -ex \"set height 0\" " "-ex \"bt\" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2", pStatus->m_pid, pStatus->m_pid ); if ( system( achCmd ) == -1 ) perror( "system()" ); exit( 0 ); } } static void lsapi_check_child_status( long tmCur ) { int idle = 0; int tobekilled; int dying = 0; int count = 0; lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusCur; while( pStatus < pEnd ) { tobekilled = 0; if ( pStatus->m_pid != 0 && pStatus->m_pid != -1) { ++count; if ( !pStatus->m_inProcess ) { if (g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren || idle > g_prefork_server->m_iMaxIdleChildren) { ++pStatus->m_iKillSent; //tobekilled = SIGUSR1; } else { if (s_max_idle_secs> 0 && tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5) { ++pStatus->m_iKillSent; //tobekilled = SIGUSR1; } } if (!pStatus->m_iKillSent) ++idle; } else { if (tmCur - pStatus->m_tmReqBegin > g_prefork_server->m_iMaxReqProcessTime) { if ((pStatus->m_iKillSent % 5) == 0 && s_dump_debug_info) dump_debug_info( pStatus, tmCur ); if ( pStatus->m_iKillSent > 5 ) { tobekilled = SIGKILL; lsapi_log("Force killing runaway process PID: %d" " with SIGKILL\n", pStatus->m_pid ); } else { tobekilled = SIGTERM; lsapi_log("Killing runaway process PID: %d with " "SIGTERM\n", pStatus->m_pid ); } } } if ( tobekilled ) { if (( kill( pStatus->m_pid, tobekilled ) == -1 ) && ( errno == ESRCH )) { pStatus->m_pid = 0; --count; } else { ++pStatus->m_iKillSent; ++dying; } } } ++pStatus; } if ( abs( g_prefork_server->m_iCurChildren - count ) > 1 ) { lsapi_log("Children tracking is wrong: Cur Children: %d," " count: %d, idle: %d, dying: %d\n", g_prefork_server->m_iCurChildren, count, idle, dying ); } } //static int lsapi_all_children_must_die(void) //{ // int maxWait; // int sec =0; // g_prefork_server->m_iMaxReqProcessTime = 10; // g_prefork_server->m_iMaxIdleChildren = -1; // maxWait = 15; // // while( g_prefork_server->m_iCurChildren && (sec < maxWait) ) // { // lsapi_check_child_status(time(NULL)); // sleep( 1 ); // sec++; // } // if ( g_prefork_server->m_iCurChildren != 0 ) // kill( -getpgrp(), SIGKILL ); // return 0; //} void set_skip_write(void) { s_skip_write = 1; } int is_enough_free_mem(void) { #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) //minimum 1GB or 10% available free memory return (*s_avail_pages > s_min_avail_pages || (*s_avail_pages * 10) / s_total_pages > 0); #endif return 1; } static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Request * pReq ) { struct sigaction act, old_term, old_quit, old_int, old_usr1, old_child; lsapi_child_status * child_status; int wait_secs = 0; int ret = 0; int pid; time_t lastTime = 0; time_t curTime = 0; fd_set readfds; struct timeval timeout; sigset_t mask; sigset_t orig_mask; lsapi_init_children_status(); act.sa_flags = 0; act.sa_handler = lsapi_sigchild; sigemptyset(&(act.sa_mask)); if( sigaction( SIGCHLD, &act, &old_child ) ) { perror( "Can't set signal handler for SIGCHILD" ); return -1; } /* Set up handler to kill children upon exit */ act.sa_flags = 0; act.sa_handler = lsapi_cleanup; sigemptyset(&(act.sa_mask)); if( sigaction( SIGTERM, &act, &old_term ) || sigaction( SIGINT, &act, &old_int ) || sigaction( SIGUSR1, &act, &old_usr1 ) || sigaction( SIGQUIT, &act, &old_quit )) { perror( "Can't set signals" ); return -1; } while( !s_stop ) { if (s_proc_group_timer_cb != NULL) { s_proc_group_timer_cb(&s_ignore_pid); } curTime = time( NULL ); if (curTime != lastTime ) { lastTime = curTime; if (lsapi_parent_dead()) break; lsapi_check_child_status(curTime ); if (pServer->m_iServerMaxIdle) { if ( pServer->m_iCurChildren <= 0 ) { ++wait_secs; if ( wait_secs > pServer->m_iServerMaxIdle ) return -1; } else wait_secs = 0; } } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) *s_avail_pages = sysconf(_SC_AVPHYS_PAGES); // lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n", // s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages); #endif FD_ZERO( &readfds ); FD_SET( pServer->m_fd, &readfds ); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout); if (ret == 1 ) { int accepting = 0; if (s_accepting_workers) accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST); if (pServer->m_iCurChildren > 0 && accepting > 0) { usleep(400); while(accepting-- > 0) sched_yield(); continue; } } else if ( ret == -1 ) { if ( errno == EINTR ) continue; /* perror( "select()" ); */ break; } else { continue; } if (pServer->m_iCurChildren >= pServer->m_iMaxChildren + pServer->m_iExtraChildren) { lsapi_log("Reached max children process limit: %d, extra: %d," " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n", pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren, s_busy_workers ? *s_busy_workers : -1 ); usleep( 100000 ); continue; } pReq->m_fd = lsapi_accept( pServer->m_fd ); if ( pReq->m_fd != -1 ) { wait_secs = 0; child_status = find_child_status( 0 ); sigemptyset( &mask ); sigaddset( &mask, SIGCHLD ); if ( sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0 ) { perror( "sigprocmask(SIG_BLOCK) to block SIGCHLD" ); } pid = fork(); if ( !pid ) { setsid(); if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK in child" ); g_prefork_server = NULL; s_ppid = getppid(); s_pid = getpid(); s_req_processed = 0; s_proc_group_timer_cb = NULL; s_worker_status = child_status; if (pthread_atfork_func) (*pthread_atfork_func)(NULL, NULL, set_skip_write); __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd, 0 ); //keep it open if busy_count is used. if (!s_keep_listener && s_busy_workers && *s_busy_workers > (pServer->m_iMaxChildren >> 1)) s_keep_listener = 1; if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem()) && pReq->m_fdListen != -1 ) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } /* don't catch our signals */ sigaction( SIGCHLD, &old_child, 0 ); sigaction( SIGTERM, &old_term, 0 ); sigaction( SIGQUIT, &old_quit, 0 ); sigaction( SIGINT, &old_int, 0 ); sigaction( SIGUSR1, &old_usr1, 0 ); //init_conn_key( pReq->m_fd ); lsapi_notify_pid( pReq->m_fd ); s_notified_pid = 1; //if ( s_accept_notify ) // return notify_req_received( pReq->m_fd ); return 0; } else if ( pid == -1 ) { lsapi_perror("fork() failed, please increase process limit", errno); if (child_status) child_status->m_pid = 0; } else { ++pServer->m_iCurChildren; if ( child_status ) { child_status->m_pid = pid; child_status->m_tmWaitBegin = curTime; child_status->m_tmStart = curTime; } } close( pReq->m_fd ); pReq->m_fd = -1; if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK" ); } else { if (( errno == EINTR )||( errno == EAGAIN)) continue; lsapi_perror("accept() failed", errno); return -1; } } sigaction( SIGUSR1, &old_usr1, 0 ); //kill( -getpgrp(), SIGUSR1 ); //lsapi_all_children_must_die(); /* Sorry, children ;-) */ return -1; } static struct sigaction old_term, old_quit, old_int, old_usr1, old_child; int LSAPI_Postfork_Child(LSAPI_Request * pReq) { int max_children = g_prefork_server->m_iMaxChildren; s_pid = getpid(); __atomic_store_n(&pReq->child_status->m_pid, s_pid, __ATOMIC_SEQ_CST); s_worker_status = pReq->child_status; setsid(); g_prefork_server = NULL; s_ppid = getppid(); s_req_processed = 0; s_proc_group_timer_cb = NULL; if (pthread_atfork_func) (*pthread_atfork_func)(NULL, NULL, set_skip_write); __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd, 0 ); //keep it open if busy_count is used. if (!s_keep_listener && s_busy_workers && *s_busy_workers > (max_children >> 1)) s_keep_listener = 1; if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem()) && pReq->m_fdListen != -1 ) { close(pReq->m_fdListen); pReq->m_fdListen = -1; } //init_conn_key( pReq->m_fd ); lsapi_notify_pid(pReq->m_fd); s_notified_pid = 1; //if ( s_accept_notify ) // return notify_req_received( pReq->m_fd ); return 0; } int LSAPI_Postfork_Parent(LSAPI_Request * pReq) { ++g_prefork_server->m_iCurChildren; if (pReq->child_status) { time_t curTime = time( NULL ); pReq->child_status->m_tmWaitBegin = curTime; pReq->child_status->m_tmStart = curTime; } close(pReq->m_fd); pReq->m_fd = -1; return 0; } int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq) { time_t lastTime = 0; time_t curTime = 0; fd_set readfds; struct timeval timeout; int wait_secs = 0; int ret = 0; lsapi_prefork_server * pServer = g_prefork_server; struct sigaction act; lsapi_init_children_status(); act.sa_flags = 0; act.sa_handler = lsapi_sigchild; sigemptyset(&(act.sa_mask)); if (sigaction(SIGCHLD, &act, &old_child)) { perror( "Can't set signal handler for SIGCHILD" ); return -1; } /* Set up handler to kill children upon exit */ act.sa_flags = 0; act.sa_handler = lsapi_cleanup; sigemptyset(&(act.sa_mask)); if (sigaction(SIGTERM, &act, &old_term) || sigaction(SIGINT, &act, &old_int ) || sigaction(SIGUSR1, &act, &old_usr1) || sigaction(SIGQUIT, &act, &old_quit)) { perror( "Can't set signals" ); return -1; } s_stop = 0; pReq->m_reqState = 0; while(!s_stop) { if (s_proc_group_timer_cb != NULL) { s_proc_group_timer_cb(&s_ignore_pid); } curTime = time(NULL); if (curTime != lastTime) { lastTime = curTime; if (lsapi_parent_dead()) break; lsapi_check_child_status(curTime); if (pServer->m_iServerMaxIdle) { if (pServer->m_iCurChildren <= 0) { ++wait_secs; if ( wait_secs > pServer->m_iServerMaxIdle ) return -1; } else wait_secs = 0; } } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) *s_avail_pages = sysconf(_SC_AVPHYS_PAGES); // lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n", // s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages); #endif FD_ZERO(&readfds); FD_SET(pServer->m_fd, &readfds); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout); if (ret == 1 ) { int accepting = 0; if (s_accepting_workers) accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST); if (pServer->m_iCurChildren > 0 && accepting > 0) { usleep( 400); while(accepting-- > 0) sched_yield(); continue; } } else if (ret == -1) { if (errno == EINTR) continue; /* perror( "select()" ); */ break; } else { continue; } if (pServer->m_iCurChildren >= pServer->m_iMaxChildren + pServer->m_iExtraChildren) { lsapi_log("Reached max children process limit: %d, extra: %d," " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n", pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren, s_busy_workers ? *s_busy_workers : -1); usleep(100000); continue; } pReq->m_fd = lsapi_accept(pServer->m_fd); if (pReq->m_fd != -1) { wait_secs = 0; pReq->child_status = find_child_status(0); ret = 0; break; } else { if ((errno == EINTR) || (errno == EAGAIN)) continue; lsapi_perror("accept() failed", errno); ret = -1; break; } } sigaction(SIGCHLD, &old_child, 0); sigaction(SIGTERM, &old_term, 0); sigaction(SIGQUIT, &old_quit, 0); sigaction(SIGINT, &old_int, 0); sigaction(SIGUSR1, &old_usr1, 0); return ret; } int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ) { int fd; int ret; int wait_secs; fd_set readfds; struct timeval timeout; if (s_skip_write) return -1; LSAPI_Finish_r( pReq ); if ( g_prefork_server ) { if ( g_prefork_server->m_fd != -1 ) if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 ) return -1; } else if (s_req_processed > 0 && s_max_busy_workers > 0 && s_busy_workers) { ret = __atomic_load_n(s_busy_workers, __ATOMIC_SEQ_CST); if (ret >= s_max_busy_workers) { send_conn_close_notification(pReq->m_fd); lsapi_close_connection(pReq); } } if ( (unsigned int)s_req_processed > s_max_reqs ) return -1; if ( s_worker_status ) { s_worker_status->m_tmWaitBegin = time( NULL ); } while( g_running ) { if ( pReq->m_fd != -1 ) { fd = pReq->m_fd; } else if ( pReq->m_fdListen != -1 ) fd = pReq->m_fdListen; else { break; } wait_secs = 0; while( 1 ) { if ( !g_running ) return -1; if (s_req_processed && s_worker_status && s_worker_status->m_iKillSent) return -1; FD_ZERO( &readfds ); FD_SET( fd, &readfds ); timeout.tv_sec = 1; timeout.tv_usec = 0; if (fd == pReq->m_fdListen) { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_ACCEPTING, __ATOMIC_SEQ_CST); if (s_accepting_workers) __atomic_fetch_add(s_accepting_workers, 1, __ATOMIC_SEQ_CST); } ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout); if (fd == pReq->m_fdListen) { if (s_accepting_workers) __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST); if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_IDLE, __ATOMIC_SEQ_CST); } if ( ret == 0 ) { if ( s_worker_status ) { s_worker_status->m_inProcess = 0; if (fd == pReq->m_fdListen) { if (s_keep_listener == 0 || !is_enough_free_mem()) return -1; if (s_keep_listener == 1) { int wait_time = 10; if (s_busy_workers) wait_time += *s_busy_workers * 10; if (s_accepting_workers) wait_time >>= (*s_accepting_workers); if (wait_secs >= wait_time) return -1; } } } ++wait_secs; if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs )) return -1; if ( lsapi_parent_dead() ) return -1; } else if ( ret == -1 ) { if ( errno == EINTR ) continue; else return -1; } else if ( ret >= 1 ) { if (s_req_processed && s_worker_status && s_worker_status->m_iKillSent) return -1; if ( fd == pReq->m_fdListen ) { pReq->m_fd = lsapi_accept( pReq->m_fdListen ); if ( pReq->m_fd != -1 ) { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST); fd = pReq->m_fd; lsapi_set_nblock( fd, 0 ); //init_conn_key( pReq->m_fd ); if (!s_keep_listener) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } if ( s_accept_notify ) if ( notify_req_received( pReq->m_fd ) == -1 ) return -1; } else { if (( errno == EINTR )||( errno == EAGAIN)) continue; lsapi_perror( "lsapi_accept() error", errno ); return -1; } } else break; } } if ( !readReq( pReq ) ) { if ( s_worker_status ) { s_worker_status->m_iKillSent = 0; s_worker_status->m_inProcess = 1; ++s_worker_status->m_iReqCounter; s_worker_status->m_tmReqBegin = s_worker_status->m_tmLastCheckPoint = time(NULL); } ++s_req_processed; return 0; } lsapi_close_connection(pReq); LSAPI_Reset_r( pReq ); } return -1; } void LSAPI_Set_Max_Reqs( int reqs ) { s_max_reqs = reqs - 1; } void LSAPI_Set_Max_Idle( int secs ) { s_max_idle_secs = secs; } void LSAPI_Set_Max_Children( int maxChildren ) { if ( g_prefork_server ) g_prefork_server->m_iMaxChildren = maxChildren; } void LSAPI_Set_Extra_Children( int extraChildren ) { if (( g_prefork_server )&&( extraChildren >= 0 )) g_prefork_server->m_iExtraChildren = extraChildren; } void LSAPI_Set_Max_Process_Time( int secs ) { if (( g_prefork_server )&&( secs > 0 )) g_prefork_server->m_iMaxReqProcessTime = secs; } void LSAPI_Set_Max_Idle_Children( int maxIdleChld ) { if (( g_prefork_server )&&( maxIdleChld > 0 )) g_prefork_server->m_iMaxIdleChildren = maxIdleChld; } void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ) { if ( g_prefork_server ) g_prefork_server->m_iServerMaxIdle = serverMaxIdle; } void LSAPI_Set_Slow_Req_Msecs( int msecs ) { s_slow_req_msecs = msecs; } int LSAPI_Get_Slow_Req_Msecs(void) { return s_slow_req_msecs; } void LSAPI_No_Check_ppid(void) { s_ppid = 0; } int LSAPI_Get_ppid(void) { return(s_ppid); } #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #include #else extern char ** environ; #endif static void unset_lsapi_envs(void) { char **env; #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) env = *_NSGetEnviron(); #else env = environ; #endif while( env != NULL && *env != NULL ) { if (!strncmp(*env, "LSAPI_", 6) || !strncmp( *env, "PHP_LSAPI_", 10 ) || (!strncmp( *env, "PHPRC=", 6 )&&(!s_uid))) { char ** del = env; do *del = del[1]; while( *del++ ); } else ++env; } } static int lsapi_initSuEXEC(void) { int i; struct passwd * pw; s_defaultUid = 0; s_defaultGid = 0; if ( s_uid == 0 ) { const char * p = getenv( "LSAPI_DEFAULT_UID" ); if ( p ) { i = atoi( p ); if ( i > 0 ) s_defaultUid = i; } p = getenv( "LSAPI_DEFAULT_GID" ); if ( p ) { i = atoi( p ); if ( i > 0 ) s_defaultGid = i; } p = getenv( "LSAPI_SECRET" ); if (( !p )||( readSecret(p) == -1 )) return -1; if ( g_prefork_server ) { if ( g_prefork_server->m_iMaxChildren < 100 ) g_prefork_server->m_iMaxChildren = 100; if ( g_prefork_server->m_iExtraChildren < 1000 ) g_prefork_server->m_iExtraChildren = 1000; } } if ( !s_defaultUid || !s_defaultGid ) { pw = getpwnam( "nobody" ); if ( pw ) { if ( !s_defaultUid ) s_defaultUid = pw->pw_uid; if ( !s_defaultGid ) s_defaultGid = pw->pw_gid; } else { if ( !s_defaultUid ) s_defaultUid = 10000; if ( !s_defaultGid ) s_defaultGid = 10000; } } return 0; } static int lsapi_check_path(const char *p, char *final, int max_len) { char resolved_path[PATH_MAX+1]; int len = 0; char *end; if (*p != '/') { if (getcwd(final, max_len) == NULL) return -1; len = strlen(final); *(final + len) = '/'; ++len; } end = memccpy(&final[len], p, '\0', PATH_MAX - len); if (!end) { errno = EINVAL; return -1; } p = final; if (realpath(p, resolved_path) == NULL && errno != ENOENT && errno != EACCES) return -1; if (strncmp(resolved_path, "/etc/", 5) == 0) { errno = EPERM; return -1; } return 0; } static int lsapi_reopen_stderr2(const char *full_path) { int newfd = open(full_path, O_WRONLY | O_CREAT | O_APPEND, 0644); if (newfd == -1) { LSAPI_perror_r(NULL, "Failed to open custom stderr log", full_path); return -1; } if (newfd != 2) { dup2(newfd, 2); close(newfd); dup2(2, 1); } if (s_stderr_log_path && full_path != s_stderr_log_path) { free(s_stderr_log_path); s_stderr_log_path = NULL; } s_stderr_log_path = strdup(full_path); return 0; } static int lsapi_reopen_stderr(const char *p) { char full_path[PATH_MAX]; if (s_uid == 0) return -1; if (lsapi_check_path(p, full_path, PATH_MAX) == -1) { LSAPI_perror_r(NULL, "Invalid custom stderr log path", p); return -1; } return lsapi_reopen_stderr2(full_path); } int LSAPI_Init_Env_Parameters( fn_select_t fp ) { const char *p; char ch; int n; int avoidFork = 0; p = getenv("LSAPI_STDERR_LOG"); if (p) { lsapi_reopen_stderr(p); } if (!s_stderr_log_path) s_stderr_is_pipe = isPipe(STDERR_FILENO); p = getenv( "PHP_LSAPI_MAX_REQUESTS" ); if ( !p ) p = getenv( "LSAPI_MAX_REQS" ); if ( p ) { n = atoi( p ); if ( n > 0 ) LSAPI_Set_Max_Reqs( n ); } p = getenv( "LSAPI_KEEP_LISTEN" ); if ( p ) { n = atoi( p ); s_keep_listener = n; } p = getenv( "LSAPI_AVOID_FORK" ); if ( p ) { avoidFork = atoi( p ); if (avoidFork) { s_keep_listener = 2; ch = *(p + strlen(p) - 1); if ( ch == 'G' || ch == 'g' ) avoidFork *= 1024 * 1024 * 1024; else if ( ch == 'M' || ch == 'm' ) avoidFork *= 1024 * 1024; if (avoidFork >= 1024 * 10240) s_min_avail_pages = avoidFork / 4096; } } p = getenv( "LSAPI_ACCEPT_NOTIFY" ); if ( p ) { s_accept_notify = atoi( p ); } p = getenv( "LSAPI_SLOW_REQ_MSECS" ); if ( p ) { n = atoi( p ); LSAPI_Set_Slow_Req_Msecs( n ); } #if defined( RLIMIT_CORE ) p = getenv( "LSAPI_ALLOW_CORE_DUMP" ); if ( !p ) { struct rlimit limit = { 0, 0 }; setrlimit( RLIMIT_CORE, &limit ); } else s_enable_core_dump = 1; #endif p = getenv( "LSAPI_MAX_IDLE" ); if ( p ) { n = atoi( p ); LSAPI_Set_Max_Idle( n ); } if ( LSAPI_Is_Listen() ) { n = 0; p = getenv( "PHP_LSAPI_CHILDREN" ); if ( !p ) p = getenv( "LSAPI_CHILDREN" ); if ( p ) n = atoi( p ); if ( n > 1 ) { LSAPI_Init_Prefork_Server( n, fp, avoidFork != 0 ); LSAPI_Set_Server_fd( g_req.m_fdListen ); } p = getenv( "LSAPI_EXTRA_CHILDREN" ); if ( p ) LSAPI_Set_Extra_Children( atoi( p ) ); p = getenv( "LSAPI_MAX_IDLE_CHILDREN" ); if ( p ) LSAPI_Set_Max_Idle_Children( atoi( p ) ); p = getenv( "LSAPI_PGRP_MAX_IDLE" ); if ( p ) { LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) ); } p = getenv( "LSAPI_MAX_PROCESS_TIME" ); if ( p ) LSAPI_Set_Max_Process_Time( atoi( p ) ); if ( getenv( "LSAPI_PPID_NO_CHECK" ) ) { LSAPI_No_Check_ppid(); } p = getenv("LSAPI_MAX_BUSY_WORKER"); if (p) { n = atoi(p); s_max_busy_workers = n; if (n >= 0) LSAPI_No_Check_ppid(); } p = getenv( "LSAPI_DUMP_DEBUG_INFO" ); if ( p ) s_dump_debug_info = atoi( p ); if ( lsapi_initSuEXEC() == -1 ) return -1; #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) lsapi_initLVE(); #endif } unset_lsapi_envs(); return 0; } int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders, const char * pBody, int bodyLen ) { LSAPI_SetRespStatus_r( pReq, code ); if ( pRespHeaders ) { while( *pRespHeaders ) { LSAPI_AppendRespHeader_r( pReq, *pRespHeaders, strlen( *pRespHeaders ) ); ++pRespHeaders; } } if ( pBody &&( bodyLen > 0 )) { LSAPI_Write_r( pReq, pBody, bodyLen ); } LSAPI_Finish_r( pReq ); return 0; } static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]); /* * Note: this code is harmless on little-endian machines. */ static void byteReverse(unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void lsapi_MD5Init(struct lsapi_MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void lsapi_MD5Update(struct lsapi_MD5Context *ctx, unsigned char const *buf, unsigned len) { register uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memmove(p, buf, len); return; } memmove(p, buf, t); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memmove(ctx->in, buf, 64); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memmove(ctx->in, buf, len); } /* * Final wrap-up - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *ctx) { unsigned int count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1]; lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memmove(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } int LSAPI_Set_Restored_Parent_Pid(int pid) { int old_ppid = s_ppid; s_restored_ppid = pid; return old_ppid; } int LSAPI_Inc_Req_Processed(int cnt) { return __atomic_add_fetch(s_global_counter, cnt, __ATOMIC_SEQ_CST); } PK ]Mr33&gems/ruby-lsapi-5.5/ext/lsapi/lsapi.sonuȯELF>S@P,@8 @ P P !P ! h h !h !888$$ Std PtdpppQtdRtdP P !P !GNU}C5@/㤈fC H‚3@(L`qCSlP*fRn}'3qѮl>&Sɶ ܮʼnSO`[is|&߱RD/y7řkՊ eY&09=By:%/=ejOzJ6'l#mNULCB1{!\$O#W23S=apbU06aD7jp#7ĴDIΊ=\4yݾCEкQuo rSѮIo|q%h6 󝵛 ' =qX[ uw  f ) ysOQ    [- F ! k & !d  2TRT s G + g }n >7   -z kH  ".%  " "$7x v4 A  A 9 4, 2 F"`\ E"  T r `G  |F pD   K 5 ti~ P 0z! b p. 8! ] @Z\ e n  v 1 p Y ` o@   Prl yj U P| 0- q]   n pY n  5 Po `w$ }l! s U T E @u qS m7 mT @(   Г  {F @qJ p @! |I   p  !b 0g ` P@, '! l 6 0n  ` @!__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizecompareValueLocationset_skip_writesigactionsigemptyset__stack_chk_failreallocfcntlacceptsetsockoptmmapmemsetsetsidread__errno_locationclosewritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemexitlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidsignalg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamdlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectrb_tainted_str_newrb_hash_asetrb_funcallvrb_intern2rb_gc_markmunmaprb_check_typerb_obj_as_stringrb_f_sprintfs_fn_add_envrb_string_valuerb_string_value_ptrrb_eval_string_wraprb_ruby_verbose_ptrrb_define_global_construby_strdupmkstempftruncaterb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_str_new_staticrb_exec_recursiverb_default_rsrb_output_fsrb_output_rsrb_lastline_getInit_lsapichdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocrb_stdoutrb_stdinrb_hash_new__memcpy_chkrb_define_global_functionrb_define_methodrb_define_singleton_methodlibruby.so.2.7libm.so.6libc.so.6__environ_edata__bss_start_endGLIBC_2.14GLIBC_2.15GLIBC_2.4GLIBC_2.3.4GLIBC_2.2.5GLIBC_2.3/opt/alt/ruby27/lib64 1 < ii G ti Q ui ] ii i P !PTX !T` !` ! ! ! !A ! ! !# !) !. !4 !; !J !Z !j !x ! ! ! ! ! ! !( !0 !8 !@ !H !P !X ! ` !!h !p !,x !< !@ !R !^ !r ! ! ! ! ! ! ! ! ! !  ! !' !: !Q( !_0 !r8 !@ !H !P !X !` !!!!!!!!$#!8!X!`!h!p!x!!!!!2!!<!H!J!R!V!V!W!!!m!{!!! !(!0!8!@!H!P!X!`!h!p! x! ! ! ! !!!!!!!!!!!!!!!!! !(!0!8!@!H!P!X! `!"h!#p!x!$!%!&!!'!(!!)!!!!*!+!,!-!!!!!.!/ !0(!0!18!@!H!3P!4X!5`!6h!7p!8x!9!;!=!>!?!@!!A!B!C!D!E!F!!G!!I!K!L!M!N !O(!0!P8!Q@!H!SP!X!T`!Uh!Xp!Yx!Z![!\!]!^!!_!`!!a!b!c!d!e!f!g!h!i!!j!k !l(!0!8!n@!oH!pP!qX!r`!h!sp!tx!u!w!x!y!z!|!!}!~!!!!!!!!!!!! !(!0!8!@!H!P!HH1 HtH5r %s hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhq% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% DH= H H9tH Ht H=i H5b H)HHH?HHtH HtfD=% u+UH=ʻ Ht H=. d ]wff.N ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=^ D ÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH=o 1XtIɲ tH=` -HcH5`HEHf [ÉD1?H= `HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHt:HHt)HHtH{@Ht 1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDjHu48u @ uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=\HcB$HH@H,H9rZf.HH9vGH3LluHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L={ L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$){H8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L LgfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH  L$DIH Ic LEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcUL{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eHmthILM)MUI9t HItDL+t$HL[]A\A]A^A_DM@@M)(KIHt$HLHk8f.HAVLAUIATIUSHu\H߉{AD${LǃLSHu0{L[L]A\A]A^k[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIH Lc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAMt$PHLIFID$PA:I|$P}MD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHAPI\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1HL$Aߺؿu#DH'uD o߻D HZDeOAkDH}An}NcHtff.USHdH%(H$1HHu/HH$dH3%(uHĘ[]Կ@1H= tAUATA'USH 'DNuD H@AHH HHtH- t iƉlj JUDk H DcEuD蟹jf.H=j>H=F 11H\$HCX= f= DH Htxff.H HtxxHe Ht~xHE Ht~xH% Htxff.= D D Ð DAUATUHH=0=SH8dH%(H$(1mHtH H= H=<FHE1 H边H=<Ht 1H薹x H=<HHt 1HmIAąWE1H=<Ht 1H<ߌ H=<蚳HtHǺ 1菳H=<sH H=<THtHǺ 1иYH=p< H1 H蘸OH=V<HtHǺ 1oH=D<̲HtHǺ 1H1H=5<襲HtHǺ 1!H="<~HtHǺ 1òH=<WHt]H=<AHt 1H轷 _H=;Ht 1H菷Ջ Dn ` R EH=;H=2 u P% 5 H=;蓱H 1H  …t Hw HHHHD L;L ;L;C HLt@HֹL€D t%HtAHHt9HLuHfDHJHHJHuHHu1ۉH$(dH3%(H8[]A\A]fD H趲D1 sAHc讲L%w HH a裮Åt= @R u \ 5b `HH5=uHH5y=1u HH5=Fff.AVIAUEATIUHSHt4Hu!(fDHH褭HLwH]HuMtEL[1]A\A]A^ÐIcLLH#EgHGHHܺvT2HGAWAVAAUIATUHoSH1HGO@ƉWDW?t;AĉDHH|@D)A9rhAGt4LLDHL9A?vWEfAIIIH޺@HH@ HLL9uA?DLHH[]A\A]A^A_ܱIATLfUHSFH?LHz?)ƒw=t19rLHfCAD$AD$ ID$071)2HCHLHCP?o H{1HMHHCPH)KXH[]A\ff.fAWAVAUATUSHdH%(H$1Ht^ IAfMcg IoA_@LHCHuMX8u =~ uٽH$dH3 %( HĨ[]A\A]A^A_f~AAuIALJf8LS|xr@tPHf@HPXN MgA;G ZA9~uEo)HHcIHLD2Hu$G85} uAMgA9ID$,HD$HcIIDhAh(A9}A /HcIH4@HeHAIIh$A9}A HcIH4@HHAIIHl$p(ILHIILp$hMIc@o9gIcP[9SIcpG9?IcH39+IHHHHIHT$IIc@ H)IHHIHHHIHIIcHIHHHD$I9E1DL4t9dfH "H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0:| ALJt`{ { A{ 1LHcϩIHIGAo IuID%{ D-{ B(AA1IcH4IILI 9HqH=, IJDB(9xHqH=, XIJB($AD$IKAzHL$;Mbfo{ Lt$ LAoL$AT$Ml$)$踪 LL8HL$LH#LLH$ID$H$I3L$H1H D$$Dl$EDDl$H=Dz IHIDz MH=y t"LDLŃP|$臨Et$A9uHt$螤D=Ń5y $A?D5y t @AH5(L*HtHHy f)gy #AH5k 1KH@H5J*1YLH 1H菤IH5421H5Y21D%x x DD$4H=x IHtZEW7E1111H=e2H5)1耨E|$迦M2;|$藦E1H5)LuI}觧Ń1H5a)LKfD=w -w w ED$AIFH5(1覧HH)H5h0H1聧1H5(L 1H50LA#LH c2Hr 解1H5(Laff.AVAUATUSHdH%(H$1D$ HH ;1Ll$Ld$Lt$ HklRr {ul;LLD$CHv Ht@HDv Ht{1f|$=u u|H4tH舴H`q d1H$dH3 %(u}HĠ[]A\A]A^D賜 {H5 h \Hfы{LA; ff.AWAVAUATUSHD=Du dH%(H$1ExH@H-yt H}u ;>g DH-u Ht 1aHEDp EH$L|$PDcA:E1AfD Ep EDt EtHt Ht @fLH1HIc臝DHD$PHD$XA ?)ѺHH D9#11A|$MHo D9#Ht Ht @D9#f AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$L̞H$LHHD$@迚AHLDŽ$hH$腞H$LHHD$0xPH$LHHD$8S+H$`L HHD$(.H$ LHHD$H ADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%q EHq Ht H=m 1蔞IL9t<1ձL5EDu EME1VFHm LH1HHc}՚}LD$LHD$PHD$X ?)ѺH1H T`1Vm  '8Ht$(1ҿ 轘x=_5p tHq Ht @f,D9# DCHp Ht@Hp HtDc1DN 0l =o {H5b HH1p Ht*Hap HB(@HAp Ht@Ho H@˖8B-DAD9M=bk 譟=Fk Ho HtDH`o Ht A9HAo HtD҉T$$DE ~:E~5WT$$A˙A輙AuDE UM D9vHn AHtDH5Z&1ƞD$藕0 H=? gT$fD}蠩C1mH|$IH|$HT$Ht$1萔61E Mt AMgMg{E1cCHt$1ҿ;H=d(Gf;)>fDD$$菔0d T$$WH=ST$WT$fDD#AfD^m RDh EBH+m H29h {H5u_ ДH{wH=&f̓H=='0讖MAH… H{HLh H=:Ht$1ҿ贒Hk bl L=bl Hl H%l 'l Hk HtH\X 11L='l AGHk Ht{1蝦D-~g EuHk Ht!E9~Zg Xk ;t Ht$@1ҿL$ Ht$01ҿHt$H1ҿHt$81ҿ֒Ht$(1ҿ ŒkHLSH$&$ޒL$踒Yj j H=/"J%˚,H=$"QHj Ht*fC1CD$CCT$HC(HC tj fD=nj lj ff.@H%f f.ffDn Hff.HV HH+HHODH1f1fATIHUSHcxHcLHjH=n HH[]A\ff.HH5ui dH%(HD$1Hm H$Ht-H=m HHD$dH3%(u&H@H= &跘HH i ffDHSHH=QU 謏HfHH=1U 茏Hc5l ;5d H=l |6Hl Hl l HfD蛎f?IH=T HH+9M1~+HHcHc5il H5Vl 聐~Sl Hfff.@HH=QT |tHHHDHff.UHSH H6Hm t]uaHHHtT؃tJ tEHH؉уu5HM u@HHpH}HH[]HD@HuHߎHMH tHPHpfSHCH[ff.SHSHH[ÐHH=!S LHmb HHH=S \HMb HHH=R 輑tH#b HHUSHH=R :H=ej HtKHPj HLj Jj 腍9Gj t H5e 8j Ht[11ҿ}1H$j ?H-Q H;HHu艔HuH;HjH[a HH[]fH="HHme SHH\$Ht$HH-1HH[ff.fAWAVAUAATIUSHHJfDmH{HfKHu{Ht -gN OkHU{Hu-JN 2HHAnonymous mmap() failedlocalhost%02d:%02d:%02d [%s] [UID:%d][%d] %.*syesnosystem()%s, errno: %d (%s) /dev/nulllibpthread.sopthread_atforkHTTP_[UID:%d][%d] %s:%s: %s LSAPI: jail() failure./etc/Can't set signalsaccept() failedLSAPI_STDERR_LOGPHP_LSAPI_MAX_REQUESTSLSAPI_MAX_REQSLSAPI_KEEP_LISTENLSAPI_AVOID_FORKLSAPI_ACCEPT_NOTIFYLSAPI_SLOW_REQ_MSECSLSAPI_ALLOW_CORE_DUMPLSAPI_MAX_IDLEPHP_LSAPI_CHILDRENLSAPI_EXTRA_CHILDRENLSAPI_MAX_IDLE_CHILDRENLSAPI_PGRP_MAX_IDLELSAPI_MAX_PROCESS_TIMELSAPI_PPID_NO_CHECKLSAPI_MAX_BUSY_WORKERLSAPI_DUMP_DEBUG_INFOnobodyLSAPI_DEFAULT_UIDLSAPI_DEFAULT_GIDLSAPI_SECRETLSAPI_LVE_ENABLEliblve.so.0lve_is_availablelve_instance_initlve_destroylve_enterlve_leavejailPHP_LSAPI_PHPRC=packetLen < 0 packetLen > %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGNOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

    Resource Limit Is Reached

    The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
              replacesrandQUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMESTDERRreopenftruncate() failed. File mapping failed. Memory calloc error[...]nilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXRACK_ROOTchdir()to_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXX;{ \f(q@rTrh r|rrr z8zl {p{{p|},p~| DЀl0,x0P px P$ `8 pL Ў` | P `@ ВT  @X l p p  0| xDЪX0lp @ P4`H\p 0@P<л|TPPp,@Th| p  8@X0Pp0P `d P$8d0zRx $X FJ w?:*3$"Db \mpmm LmsEIB E(A0z (A BBBI A (D BBBA m m@mYGJB B(A0A80F(B DBb0TtBFC G  AABK   AABG xEO D  A @$ T hY|hJEDS ]Ph H XAH$lFBB B(A0A8LP 8A0A(B BBBH <H FBB A(A0 (D BBBI \i`ptFBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH L0$FBB A(A0H Q D 0A(A BBBH L$FBB B(A0A8G 8A0A(B BBBF tFFX$nCXJLlFBB B(A0A8DA 8A0A(B BBBA `( ܏BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0 xBMD GL  AABA < =BAA G L@I@U  AABG $ TWEHG ( \ag H SHL FBB B(A0A8DPS 8D0A(B BBBF T lbIE D(C0P (F BBBM Q(H BBBAH FBB B(A0A8DP 8A0A(B BBBA T< xCBA A(G0` (A ABBD  (C ABBA J8 @-FBD D(D@T (A ABBB  4( @lECGF AAI L !cBG A(D0 (A ABBE XD0` dt pZ 10 pFAA G@7  AABF  $@LsL HFBB B(A0A8G 8A0A(B BBBG < P  d x  ( 4 @ L  H  D@ << FBA K(G (A ABBG <X FEE D(D0M (C BBBB L(HhFBH E(A0E8I@ 8A0A(B BBBE ( FED ABH$ BBB B(A0A8G 8A0A(B BBBJ DpDFBB A(A0G 0A(A BBBF L FBB B(A0A8G  8A0A(B BBBA \h4p Hl\x+p(BFGA kFBzD O E   HU gHQ G <haydT2HW I I(tEDL ] CAJ dELhEYl HWt HW|-Hd( EAD  DAJ LX3ED hAHlxFBB E(D0C8GPm 8F0A(B BBBG ,LZAD J ABL 4oAD  AAK pP \ 4FDA D(F0` (D ABBB j (D ABBE l(G DBBDBBI B(A0A8D@8D0A(B BBBl*HP H I|UKI8FBA D(D@ (A ABBE @(TEDG0 AAI H$PFBB A(A0 (F BBBH {(F BBB@(OFBB A(D0D@  0A(A BBBJ 84KFBA A(D0 (A ABBE GNUPTT` !A#).4;JZjx !,<@R^r ':Q_r   s h> P !X !o` !.8&p o%oo"$oDh !>>>>>>?? ?0?@?P?`?p?????????@@ @0@@@P@`@p@@@@@@@@@AA A0A@APA`ApAAAAAAAAABB B0B@BPB`BpBBBBBBBBBCC C0C@CPC`CpCCCCCCCCCDD D0D@DPD`DpDDDDDDDDDEE E0E@EPE`EpEEEEEEEEEFF F0F@FPF`FpFFFFFFFFFGG G0G@GPG`GpGGGGGGGGGHH H0H@HPH`HpHHHHHHHHHII,LSLSLSLS!$#!GA$3a1h> GA$3p1067`TGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1067GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY`T GA+GLIBCXX_ASSERTIONSlsapi.so-5.5-1.el8.x86_64.debugܣ7zXZִF!t/wZ]?Eh=ڊ2NI ͕  (<φ5+#Su-a?'L<nr)>!T:Iw'a;W2aI;bq]]bkQpQ DGymYE{E:C m4b_3fw@(]|simko:.4tܰ0!TL=k(#fHJuSX]1;#ewpZvPzfWh&9\JXW.\O)ĮW)Ê\iSkts ԇ*?`ʳP6eHtR p*rH`FR¹JIY=k06j{  c~82vAOIʝ/`m}~t7zP=>9x.xc_" [t#j`t8BMtze01_0㶚h/ݜJh7?Dj!"B56JJv}aJI⦬w7}N+)a^Jgi~v0&SSMpfIC7\&ߥ?xphDBO"FP1>") xSdr}hT/mGkS-~lX. gg7J|`n6Ͻ0s(d\bg;3qe{MiJ/X:ФOv`bʟDSregj#72?|#xFl{(yܪ+2TQjPr(RRΔLeR4S M/.Pԙg+|wOL,ZmQI}B,zo-7y+G ӺKx& !N Bp^+wwOΒ|7fhNu9ʖ/]8V`M-}Z>.Eed^TϒOC@=zJˏ 5,c{K1Obڡ8.&)aT?S}[@G$گ`'9BjU(Ch}uU$LfQt=&DL.C1!UymLH壄69anCuTȎ:Շ֌r&Q`Wpj؂#@?F~|2tAi)>hڷ ѫ%lќar I?2ak<^%eq҂z10oz,F3\X+E$:G }|kKݵKTnG`E:}jIQrGRlX?^pיFHh&Y3YF \[LA-b6xKGvu'8F*R+29Ħ]EMO2LI\<]FMTwMiA.#:`)\|D <{ l$,HlѲ%z؃kUn0.;5[.N /%5>GtX k똞 );4.éZ ݢ?цuinIX1HAsuW#*JW:! w9͔oZZr $ΓAMY5r@ՀM1yhB 7K''SSE50OJpzӱuF4*3 .+C8 _X"ZúEULBm C]Af\{$6p.͸ViR# }&~[@7U6:SS.~Q#Mf-PȗjaUfp5r8A(, D7< ѱgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``p( 0 8o"$"$Eo%%pT8&8&p^B..hh>h>c>> n I I wSSK}} p ppXXL P !P X !X ` !`  h !h X!X!X`!` @!@ 'a@\#$"#+1PK ].c|&gems/ruby-lsapi-5.5/ext/lsapi/lsruby.onu[ELF>@@98 ,.+/*0)1fDHff.HHH+HHODH1f1fATIHUSHcHcLHH=HH[]A\ff.HH5dH%(HD$1HH$Ht-H=HHD$dH3%(u&H@H=HHfDHHH=HfHH=Hc5;5H=|6HHHfDf?IH=HH+9M1~+HHcHc5H5~Hfff.@HH=tHHHDHff.UHSH HHm t]uaHHHtT؃tJ tEHH؉уu5HM u@HHpH}HH[]HD@HuHHMH tHPHpfSHCH[ff.SHHH[ÐHH=HHHH=HHHH=tHHHUSHH=H=HtHH9t H5Ht[11ҿ1H?H-H;HHuHuH;HHHH[]fH=HHSHH\$Ht$HH1HH[ff.fAWAVAUAATIUSHHJfDmHHfKHHt -OkHHu-2 GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realignreplacesrand/QUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMESTDERRreopen%s: %s ftruncate() failed. File mapping failed. Memory calloc error [...]nilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXLSAPI_CHILDRENRACK_ROOTchdir()ENVto_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXXF 9%I'P(int)@ 9 1 3 6  7  8  9 : ( ; 0 < 8 = @ @ H A P B X D` Fh Hp It J x MP NW O Q Y [ \ ] ^ G _ - ` b  +  9  9 ? M     UJ U   U a}^q!$2 7 ;  f9:IDg9@4 @b     I  @`  @ @ @x@v#w :xF@@  :@5   Z :len ptr aux5Zary  9(as@2 W$Flen aux%2ptr&F'Wary( F 9(as)(sA tu L v L w G L !GA "L ::::::::::::::::::::::::::::::::::::::::::::::::: : : : : ::::::::::::::::::: :!:":#:%:&:':(:*:,:,:,(:G:H:I:J:K::  9 7 89:;<=>#@,     $q=%s%t k m n  o  p  u ,  =                $  ( D D  T4 T 9 d 9                "= " 4 6 7  /k 1 2  3  4 & : < = ? @ B C E( F0 G8 I@ JH KP L!X O` Ph Qp Rx T' V' W' X' Y' Z' \' ]' _ ` a b c d e f g h i'k''m'('n'8'oG    G  -=)d = 9 j(9qks)?!!!!!G-.P  W  c  9 c A W   F*WTQQ  )4?JU`Akv$  !{$$% $% 4% D 4 9 D 9 T 9 o  Too I 9  9@+":+#:,$: ,(: ,*: ,,: ,.  2-req4-env5: 6)!!!-7Q,9: ,;: ,< ,>: +?,@~  By D E F GH7,Jy  (9,K  .  /-K$0/ :1p0 01 23S*K 4C5U 5T320T6T$0T23TK 4C5U 5T74C5Q05R02`0 :4C5TH5Q 5R|20:4C5TH5Q 5R|7 %38-%59:;%:F%8,: :;>:4C5Us5T05Q:<CY5U <Cw5Us5TM<C5Us5Tm<C5Us5TK4C5Us5Tk8%69:!%8:!^;:;:4C5U 5Ts5Qv5R =9# ;9;9<C5U 4C5Us8,:9;>:4C5T05Q:>D<C@5U >D>!D<Cy5U >.D>;D<HD5U <UD5U 5T7<UD5U 5TA<bD5Q}??5U 5T 5Q1<oD^5U ?5T 5Q 5R0?5T 5Q 5R0?5T 5Q 5R1? 5T 5Q 5R1?@ 5T 5Q 5R ?n 5T 5Q 5R ? 5T 5Q 5R ? 5T 5Q 5R1? 5T 5Q 5R0?#!5T 5Q 5R0?P!5T 5Q 5R0?~!5T 5Q 5R ?!5T 5Q 5R0?!5T 5Q 5R0?"5T 5Q 5R0?2"5T 5Q 5R0?_"5T 5Q 5R0?"5T 5Q 5R0?"5T 5Q 5R0?"5T 5Q 5R0?#5T 5Q 5R0?@#5T 5Q 5R1?n#5T 5Q 5R <HD#5U <HD#5U >|D>|D>D>_4<D#5U <D$5U >|D?X$5T 5Q 5R0?$5T 5Q 5R0?$5T 5Q 5R0<D$5U 4C5U  F$@%$A& B -%CpB R%Cn  Cp D:%E E-E9:6 :F3*K G:g4&H :Iw+ >D>D>DG:v&J":UJ-:TK:&E:D:&E!:G:&J":UG:+C'J:UL8 M8G:Ua(H:1str :=a( ';s(7+ 8)S(;*9N*:+*N8*:C*<>D(O*s>,+>DD:(E!:Gr:4)HrHr*Hr6:1strt :1nu 0v 0w 89 w);9>D>D>,+<D)5Us $ &<O*)5U|< E)5U}5Qs $ &4 E5U}5Q| $ &DC:O*EC :CstrE :6FCnG CpH G. a+H."P0 01 02 03 64 884+M8>EQ)Q$R K+Cfd Rw+Cfd Csfn QG:2+H :1ch >"EG:%,H!:>DG:,Sout!:Sstr,:4/5Us5TTD:,EE*Tout6:Ci 6 :De:2-Tarye#:Toute.:Ee7Ctmpg :Cih G\:-H\H\,Sout\8:<.E-5UU5TT4/5UsG8:O/H8H8,Sout88:1i: 3; :@8$9Jv.;69<;E.5U~5T3</.5Uv</.5Uv</.5Uv</.5Uv>HE>UEU,:0H,!:Sstr,-:0.1len/ 890/;94^E5Uv5T<8$92 /;694kE5UsG :K1H :Sc +:Vch" W0#8D9"0;V9W9f;9<D05Us>D89$$1;94^E5Uv5T<?=15TW5Q1>UEG: ~1J#:UX:3 2Y+:Zstr7:<xE15Us<E15Us4E5T0X: P2Y,:>EX: 2Y+:>EX:-2Y,:>EX:E4Y$:[pid 23\ + $\ 23, K 4C5U 5T54C5U85Q05R0]E4 4;R4>_4<E45Qs4E5Qs>E>D>!D^ _4_)` z52 5a,'5`a24,K 4C5U 5T74C5Q15Rw>UE F'5 95X B6Y)Y3YHYTZarg#G<UD55UQ5T R $ &<UD55U|5Ts $ &4bD5QvXd ?8Yd(Yd2YdGYdSZarge"G[pg blenh <UD65U|5T~<UD65Us5Tv $ &<bD75Q|<E.75U|5T?<UDN75U|5T<UDr75U 5T9<bD75Qw<UD75U|5T<UD75U 5T<<bD75Qw<UD85U5T}<UD*85U 5T<4bD5Q}cZ 8YZ&dEe8_?e8_<D8Ta:f !:D9Ta$:Dy$9Tay:D?D9Tobj?:Dab9Txa:D:9Tx:EECDG9Tobj:D9Tx:g:__g\,:_\_\hiL:Eigdw:_d!_d<ija(:ks(Uj&:k&UjR%;;d%;q%;~%N%WR%;~%;q%;d%9:%l%;4C5U 5T6>|D>|D<D;5U >|DmC5QU5RTj,+>n>+=83<M8Iw+8,+ >9:>+8K+=9:]+:i+8L: =;i:;]:4F5T15Q 5Rs<F4=5U <FL=5Us<)Fd=5Us<D|=5Us>6F>BF4D5Us<OF=5Uv5Ts<\F=5U05Ts5Q35R15Xv5Y0<hF>5Uv<D3>5U <hFK>5Uv<Dj>5U 4hF5Uv<uF>5T14D5U j)?:*N+*:8*:C*;*I+X <O*B?5U <Fu?5U|"5Tv5Q 5R1<D?5Uv4 E5U|5Qvj)* @;*N*o+*N8*pC*>,+m>O*Uj,8B;,;,; -q-@:&-89p@;9=b9r@;9;9;t94F5Us88rWA;8988 AA;84F5Us=,'eB;,; -;,r'q-@N&-<;EA5U 5T54F5U15Tw5Qv<F*B5U15Tw5Qv>UEj,PC;,;,;,N,N,s,nCM,M,M,9:,:,8$9B;69<FC5U 5Qs>kE</;C5Us5T~</SC5Us4;E5U|5T34/5Usttetutwvw/tmp/lsapi.XXXXXXvw .XXXXXXtu{tnttt tttt7ttt0t t  uuL t3 ttttt$u utttxtRttVtWtcttt}uut^utuZ u Dt t9 u% tt u9ta ttqw lsruby.ctttYt% : ; 9 I$ >  $ > &I I7I I !I/  : ; 9  : ; 9 I8 : ; 9 <4: ; 9 I?<!4: ;9 I?<: ; 9 I> I: ;9 ( (((   : ;9  : ;9 I8  : ;9  : ;9 I : ;9  : ;9 I8  : ;9 I : ;9 I 8 '!I": ;9 I#> I: ; 9 $ : ; 9 % : ; 9 I& : ; 9 ' : ; 9 I8(!I/)'I* : ;9 +4: ; 9 I,4: ; 9 I- : ; 9 I8 .4: ; 9 I?/.?: ;9 @B04: ;9 IB14: ;9 IB2 U34: ;9 I415B64: ;9 I71RB UX YW 81RB UX YW 9 U:41B;1B<1=1RB X YW >1?@!I/ A.: ;9 B.: ;9 C4: ;9 ID.: ;9 'I E: ;9 IF G.: ;9 'I@BH: ;9 IBI1RB X YW J: ;9 IK.: ;9 'IL1RB X YW M1N41O1BP4: ;9 IQ.: ;9 I R.: ;9 I S: ;9 IBT: ;9 IU.: ;9 'I@BV4: ;9 IW1RB UX YW X.: ; 9 'I@BY: ; 9 IBZ: ; 9 IB[4: ; 9 IB\4: ; 9 IB]1RB UX Y W ^.: ; 9 ' _: ; 9 I`.: ; 9 @Ba4: ; 9 I b4: ; 9 I c.: ; 9 '@BdB1e.: ; 9 'I f.?: ;9 '<g.?: ; 9 'I 4h.?: ;9 'I ij.1@Bk1l 1UmB1n41 o41p41 q41r s1UX YW t.?<n: ;9 u.?<n: ; 9 v.?<n: ; w6x.?<nOVOTpqPPqP0uVT0V0T0?0T0?0nPP PPSSPS,8P8HSHcTSSH\TpSH\ Tp vv vPUU U  S  P U U  S  P S  S      0  0 U S D UD g Sg u Uu  S U S U T V D TD a Va u Tu  V T V T Q Q P  ] + P+ C ]C D P ] S  SW u P \ v| v| $0 $+(  v $0 $+( ? v $0 $+( v $0 $+(  P PL V Uu | U U u@aUN $ &"^a $ &"O^PNQ^aQpUUPPpUU`lUlqSqrP`lTlrTUUTTQSQPUwwUw1PT]wTTWPQpVpwQwQV{0S8=S0 s $ &3$}") s $ &3$}"UVWUTS,AS&V,WV+PUVS,9S0 U V U V0 S TS S T S PP S TS S S S S U VU3UTUUUUU U!U!UkPP0000SU\UTSTQQRRXX@USSSS@TVTTVTVT_V@Q\3Q3\JQJ_\@{R{]R]RG]G^ R Z]Z_^@XX3X3XJXJ_X7PPP_JTPT__`hUhmU`USQUS`TVRTV`QQQQVRTVSQUS\\rV * Vg q  q V@Y YiPiV * V* 4 P4 VRVPVyS* q SN q U Z pZ ^ UR n Pn \ PD } S  P6 > P * U U T UT S U S U  U T TT V T V T  V T QT Q Q  QT ] } ] ]T _ S Sd  d  r  rd l Sl  S Sv  S S U  U Q  Q T  V1U1.U.:U:PU1T1.T.=T=PT1Q1SQ.S.AQACSCPQ10UP^P.^1_UU,8U 8U/09szsz@ @r0 g < K N _ L W x  X _ l  v  P 08_0cXH\\cXpv@` 0@ $@LnW /opt/alt/ruby27/include/ruby/usr/include/bits/usr/include/usr/lib/gcc/x86_64-redhat-linux/8/include/usr/include/bits/types/usr/include/sys/usr/include/netinetlsruby.clsapilib.hruby.hstdio2.hstdlib.hstring_fortified.hstddef.htypes.hstruct_FILE.hFILE.hstdio.hsys_errlist.htypes.hstdint-intn.hstdint-uintn.hunistd.hgetopt_core.hmath.hintern.hversion.hlsapidef.htime.hstruct_iovec.herrno.hsockaddr.hsocket.hin.hsignal.hstring.hmman.hutil.h  JK?K| #t>iK>KK{KY;./*X **}( // RX} t     0Yf q\:>X. t" u t/u* uZ ^  %gfu Z3 X }t }< tXX uKt  .t.  X  f. f *8u t  X    o.@5< t-< ti JJ [X -JiX O  L( ff-X< n9= t; K1 tQJ/f J L 2  =t<UMtUX&<< ` 0z X .    =Yl  qX[wt Z " h   m grtX  h fY:g< KXfKY sbXtv  SY|X |X<   L/$ eX< z < zt yt5Y|X |.X z  Z rh Y   *xp*suqwZ7Mt -uDXZ;467954644584236:8648: "u{ wt JvI ;tZvpJuI==[X=XvXuv0X>f~z t gz t ` X p((* uv #G< Y(%[$ rb_mWaitWritable_sys_errlistm_pScriptFileRUBY_Qnilrb_eNoMemError_unused2_filenorb_cMethodrb_obj_wb_unprotectrb_eSyntaxErrorm_cntUnknownHeadersH_AUTHORIZATIONsockaddr_isoblockSizem_pIovecEndstrcpym_pRespBufPosRUBY_FL_EXIVAR__uint8_tdmarkRUBY_DATA_FUNCm_pktHeaderrb_eIOErrorm_bytesm_pHeaderrb_data_object_get_shortbufsockaddr_inrb_cFilerb_eSignalunlinklsapi_dataRUBY_T_ARRAYrb_eKeyErroradd_env_rails__environlsapi_addstrsa_datauint16_tm_totalLensin_zeroRUBY_FL_UNTRUSTEDrb_eZeroDivErrorin_port_t_flagslsapi_getscallocm_respPktHeader__off_tcreateTempFiledfreeRUBY_T_IMEMOrb_global_variable_lockROBJECT_EMBED_LEN_MAXRUBY_T_UNDEFrb_cStringrb_eEOFErroratoim_pHttpHeaderLSAPI_GetReqBodyRemain_rm_pScriptNamerb_mKernelm_pEnvListrb_output_fsint32_t__fmtsa_familym_specialEnvListSizerb_cModulesockaddr_ns__u6_addr8RUBY_T_FALSEruby_robject_flagsrb_cIntegerRUBY_T_FILE_IO_write_endm_iLensockaddrrb_cTrueClasss_addrRUBY_FL_USER0RUBY_FL_USER1RUBY_FL_USER2RUBY_FL_USER3RUBY_FL_USER4RUBY_FL_USER5RUBY_FL_USER6RUBY_FL_USER7RUBY_FL_USER8RUBY_FL_USER9nameLenLSAPI_Postfork_Childfreerb_fsm_requestMethodOffRUBY_T_COMPLEXdata_struct_objrb_eEncCompatErrorruby_special_constsvalLenRSTRING_EMBED_LEN_SHIFT__stack_chk_failruby_rarray_flagsruby_descriptionsin_familyRStringm_fdListenMAX_BODYBUF_LENGTHlsapi_bodym_statusm_reqBodyLenrb_eNameErroroptargneedReadrb_eRegexpErrorrb_cBasicObjectRUBY_T_STRUCTrb_cRationalrb_cFloatrb_cClassrb_cStatsys_errlistin_addr_tbasicRUBY_QtrueLSAPI_ReqBodyGetChar_rpKey__uint16_tsin_portRUBY_T_STRINGrb_cContrb_cFalseClassm_flagRARRAY_EMBED_LEN_SHIFTreadMaxBodyBufLengthm_pQueryString_chainRUBY_T_MODULErb_eArgErrorrb_eInterruptrecurrb_funcallvRUBY_FL_SINGLETONsockaddr_ununsigned charcapanReadm_cntSpecialEnv_IO_lock_tRUBY_T_ZOMBIEfloatLSAPI_key_value_pairLSAPI_ForeachHeader_rrb_stderrlsapi_eachm_cntHeadersrb_str_catbodyBufRARRAY_EMBED_LEN_MAXRUBY_T_FIXNUMrb_eSecurityErrorisEofBodyBuflsapi_processlsapi_flushRARRAY_EMBED_FLAGROBJECT_EMBEDoff_tchild_statusRUBY_SYMBOL_FLAGrb_mComparableH_X_FORWARDED_FOR__fprintf_chkm_queryStringOffRUBY_FLONUM_FLAGrb_stdoutruby_rstring_flagsH_CONTENT_LENGTHrb_cTimeruby_engine_IO_write_ptrrb_output_rsROBJECT_ENUM_ENDlsapi_packet_headerLSAPI_ReadReqBody_rrb_eFatallsapi_http_header_indexrb_funcall_argcsTempFilerb_funcall_argsclosesharedlsapi_printfRUBY_T_OBJECTFILEH_COOKIEs_fn_add_envmunmapRSTRING_EMBED_LEN_MAXbodyCurrentLenLSAPI_Accept_Before_Forkrb_cNumerics_req_stderrrb_cHashsize_trb_array_const_ptrH_CONNECTIONrb_rsuint8_tH_CONTENT_TYPERArraylsapi_markm_headerLenRUBY_ELTS_SHAREDperrorlsapi_envruby_release_daterb_cDirsetup_cgi_env_IO_save_baseioveclsapi_eofrb_array_const_ptr_transientenvironlsapi_child_statusreadTempFileTemplatesockaddr_x25rb_eLoadErrorsin6_flowinfom_pIovecToWriteorig_stderrm_respHeaderLen_wide_dataH_IF_MATCHRUBY_FL_PROMOTED0RUBY_FL_PROMOTED1__in6_uGNU C17 8.5.0 20210514 (Red Hat 8.5.0-18) -mtune=generic -m64 -march=x86-64 -g -O2 -fPIC -fexceptions -fstack-protector-strong -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection=full -fplugin=gcc-annobinH_ACC_CHARSETruby_versionorig_stdout__streamsigngamruby_copyrightm_reqBufSizerb_eExceptionrb_yieldadd_env_no_fixRUBY_T_FLOATRUBY_T_CLASSrb_cDataftruncateruby_fl_typelsapi_requestrb_cComplexfprintfrb_check_typeRUBY_T_HASHsyncRUBY_T_NODEchdir__ssize_t__srcrb_mErrnolsapi_closeH_IF_RANGEnameOffruby_api_versionstrerrorsa_family_tm_packetLenreadMoreRUBY_FL_WB_PROTECTEDin6_addrisBodyWriteToFilelinesin6_addrrb_mWaitReadablelsapi_setsyncm_respPktHeaderEndRUBY_FL_TAINTLSAPI_Postfork_Parentfn_add_envlsapi_printrb_eSystemCallErrorrb_intern2stderrm_pHeaderIndexprogram_invocation_short_namerb_cUnboundMethodrb_f_sprintf_IO_save_endrb_const_get__nptrLSAPI_InitLSAPI_Requestrb_eScriptErrorrb_tainted_str_newfn_writelsapi_syncm_bufProcessedstdoutreadBodyBufoptoptlsapi_reopenrb_mGCrb_eIndexErrorm_httpHeaderLencurPosH_IF_NO_MATCHlsapi_s_acceptpreforkRUBY_T_DATAbuffssizetypekeyLenRUBY_FL_DUPPED__builtin_strchrLSAPI_Flush_rshort unsigned intsigned charrb_array_lentz_dsttimefilenamelsruby.clsapi_header_offset__off64_tsockaddr_eon_IO_read_base_offsetm_pIovecrb_string_value_ptrrb_eFloatDomainError_IO_buf_endm_respInfoopterrlsapi_puts_ary_modeblkSize_IO_write_basevalueLenInit_lsapirb_eStandardErrorrb_cSymbolrb_argv0H_CACHE_CTRLH_COOKIE2__destrb_cMatchrb_cEncodinglsapi_isattyH_USERAGENTRARRAY_EMBED_LEN_MASKLSAPI_ForeachEnv_rlong intRUBY_T_NONErb_mProcessrb_mFileTestremain_IO_markerrb_cEnumeratorm_pRespBufEnd__builtin___memcpy_chkrb_io_putslsapi_s_postfork_childrb_define_global_constrb_obj_as_stringm_bufReadin_addruint32_tsockaddr_in6__pid_t_IO_codecvtrb_funcall_nargsH_RANGERDatastrtolg_reqlong doublerb_cRangeiov_lenlsapi_resp_inforb_cObjectlong unsigned intlsapi_req_headerRVALUE_EMBED_LEN_MAXrb_gc_markinitBodyBufruby_strdupm_headerOffrb_eNotImpError__errno_locationlsapi_s_postfork_parentcharsockaddr_inarpm_pSpecialEnvListsin6_scope_idrb_cIORSTRING_ENUM_ENDstdinsin_addrRUBY_T_BIGNUM_IO_buf_baseRSTRING_NOEMBEDRUBY_T_RATIONALRUBY_FL_PROMOTEDs_bodyrb_eTypeErrorRBasicrb_eNoMethodError_IO_read_endRUBY_T_ICLASSrb_num2intcLSAPIRUBY_SPECIAL_SHIFT_IO_FILEH_IF_UNMOD_SINCEm_fdRUBY_T_SYMBOLH_HOSTrb_num2char_inline_IO_wide_datastrlen__u6_addr16s_pidselfrb_eSystemExitisAllBodyReadm_respHeaderrb_cThreadRUBY_FL_SEEN_OBJ_IDm_envListSizem_pAppDataruby_platformsockaddr_ax25RSTRING_FSTRrb_eThreadError__pad5rb_str_new_staticshared_root__u6_addr32rb_cNilClassm_type_markersrb_stdinrb_eStopIterationm_scriptFileOffRUBY_FL_USHIFTklassrb_define_classH_VIA_codecvtm_pRespHeaderBufEndH_PRAGMARUBY_FL_FINALIZErb_cRandomdoublemkstemplsapi_putcargcssize_tstrcatlsapi_writelsapi_putsorig_stdinRUBY_FIXNUM_FLAGargvRARRAY_ENUM_ENDrb_eRuntimeErrorm_pRespHeaderBuf__int32_trb_cProc__uint32_tRUBY_IMMEDIATE_MASKrb_hash_asetdataH_REFERERrb_cStructLSAPI_Prefork_Accept_rheap_sys_siglistRARRAY_TRANSIENT_FLAGm_pUnknownHeaderrb_typem_reqStateRUBY_T_NILRUBY_T_MOVEDrb_eSysStackError/builddir/build/BUILD/opt/alt/ruby27/share/gems/gems/ruby-lsapi-5.5/ext/lsapim_pRespBufrb_num2int_inlineprogram_invocation_namerb_cArrayrb_eEncodingErrorrb_ruby_verbose_ptrrb_cBindingrb_intern_id_cacheH_TRANSFER_ENCODINGH_IF_MODIFIED_SINCErb_ary_detransientRUBY_FL_USER10RUBY_FL_USER11RUBY_FL_USER12RUBY_FL_USER13RUBY_FL_USER14RUBY_FL_USER15RUBY_FL_USER16RUBY_FL_USER17RUBY_FL_USER18RUBY_FL_USER19_freeres_bufRUBY_T_MATCHlong long unsigned intpid_t_cur_columnlsapi_rewinds_reqrb_eRangeErrorm_pRespHeaderBufPoss_stderr_datarb_eval_string_wrapgetpidm_cntEnvRUBY_T_MASKrb_lastline_getcreateBodyBuf_IO_backup_baseH_KEEP_ALIVE__memcpy_chk_IO_read_ptrrb_eMathDomainErrorrb_fix2intLSAPI_GetReqBodyLen_rrb_gc_writebarrier_unprotectrb_exec_recursivegetenv_freeres_listrb_eLocalJumpError_sys_nerrlsapi_readtimezonepReqlsapi_getcrb_hash_newclear_envrb_cRegexplsapi_binmode_old_offsetstrchrm_pReqBufrb_cNameErrorMesgvalueOffoptindH_ACC_LANGlong long intin6addr_loopback_flags2VALUErb_mMathRUBY_T_TRUEmemmemsin6_familysockaddr_atruby_value_typem_scriptNameOffH_ACCEPTm_lLastActiverb_eNoMatchingPatternErrorlsapi_resp_headersys_nerrin6addr_anym_pRequestMethods_req_dataiov_basem_lReqBeginruby_rvalue_flagsm_versionB0m_versionB1rb_str_buf_newRUBY_FLONUM_MASKruby_patchlevelRUBY_T_REGEXPm_pIovecCurLSAPI_Init_Env_Parametersorig_envm_reqBodyReadRUBY_Qundeflsapi_s_accept_new_connrb_eFrozenErrorsockaddr_dlRSTRING_EMBED_LEN_MASKRUBY_FL_FREEZEunsigned intbodyLensockaddr_ipxrb_default_rsshort intrb_string_value_vtable_offsetpValueenv_copymmaporig_verboserb_data_object_zallocrb_mEnumerableRUBY_Qfalseflagstz_minuteswestsys_siglistH_ACC_ENCODINGsin6_portlsapi_eval_string_wrapGCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-18)GNUzRx  0D+Xl(BFGA kFBzD O E  HUgHQ G $ayd<2HW I I(\EDL ] CAJ ELEY HW HW-Hd(EAD  DAJ 43ED hAHTFBB E(D0C8GPm 8F0A(B BBBG ,ZAD J ABL 4oAD  AAK pP \4FDA D(F0` (D ABBB j (D ABBE l(G DBBDhBBI B(A0A8D@8D0A(B BBB*HP H IUKI8FBA D(D@ (A ABBE ((<EDG0 AAI HhPFBB A(A0 (F BBBH {(F BBB@OFBB A(D0D@  0A(A BBBJ 8KFBA A(D0 (A ABBE   - )  ?.Yt/01 5 C _"y @"[0+[h` h)wCpPwmB pZz# < xEZ_mw` mpg0aIaUaop2WWr`r1KX   #J o-  X  ` 3D3[3x_@_`  3 N\ @f   4      '  *2  L  d  Uo     '   '   ' 0 2  L Pd Po P  PO          h "$%'./0123-4# ( - @2 )7 < 3A F K LP SU [ ba Zg xm s y           $ * f n s y             ! ' - 3 9 ? E 1K GQ VW ] c i u    ()*+,       # . < C H \ s        $7G[ov-&18A^i|K $*4?L_o   .annobin_lsruby.c.annobin_lsruby.c_end.annobin_lsruby.c.hot.annobin_lsruby.c_end.hot.annobin_lsruby.c.unlikely.annobin_lsruby.c_end.unlikely.annobin_lsruby.c.startup.annobin_lsruby.c_end.startup.annobin_lsruby.c.exit.annobin_lsruby.c_end.exit.annobin_lsapi_process.start.annobin_lsapi_process.endlsapi_process.annobin_lsapi_rewind.start.annobin_lsapi_rewind.endlsapi_rewinds_body.annobin_lsapi_eof.start.annobin_lsapi_eof.endlsapi_eof.annobin_lsapi_binmode.start.annobin_lsapi_binmode.endlsapi_binmode.annobin_lsapi_isatty.start.annobin_lsapi_isatty.endlsapi_isatty.annobin_lsapi_setsync.start.annobin_lsapi_setsync.endlsapi_setsync.annobin_add_env_no_fix.start.annobin_add_env_no_fix.endadd_env_no_fixlsapi_env.annobin_clear_env.start.annobin_clear_env.endclear_envrb_intern_id_cache.15416env_copy.annobin_lsapi_mark.start.annobin_lsapi_mark.endlsapi_mark.annobin_lsapi_flush.start.annobin_lsapi_flush.endlsapi_flush.annobin_lsapi_close.start.annobin_lsapi_close.endlsapi_closeMAX_BODYBUF_LENGTH.annobin_readBodyBuf.start.annobin_readBodyBuf.endreadBodyBuf.annobin_lsapi_getc.start.annobin_lsapi_getc.endlsapi_getc.annobin_lsapi_write.start.annobin_lsapi_write.endlsapi_write.annobin_lsapi_addstr.start.annobin_lsapi_addstr.endlsapi_addstr.annobin_lsapi_printf.start.annobin_lsapi_printf.endlsapi_printf.annobin_lsapi_s_postfork_parent.start.annobin_lsapi_s_postfork_parent.endlsapi_s_postfork_parents_req.annobin_lsapi_s_postfork_child.start.annobin_lsapi_s_postfork_child.endlsapi_s_postfork_child.annobin_lsapi_s_accept_new_conn.start.annobin_lsapi_s_accept_new_conn.endlsapi_s_accept_new_conn.annobin_lsapi_s_accept.start.annobin_lsapi_s_accept.endlsapi_s_accepts_pidrb_intern_id_cache.15429s_req_data.annobin_lsapi_eval_string_wrap.start.annobin_lsapi_eval_string_wrap.endlsapi_eval_string_wrap.annobin_add_env_rails.start.annobin_add_env_rails.endadd_env_rails.annobin_lsapi_reopen.start.annobin_lsapi_reopen.endlsapi_reopens_req_stderrorig_stderrrb_intern_id_cache.15593.annobin_createBodyBuf.start.annobin_createBodyBuf.endcreateBodyBufsTempFile.annobin_lsapi_read.start.annobin_lsapi_read.endlsapi_read.annobin_lsapi_gets.part.2.start.annobin_lsapi_gets.part.2.endlsapi_gets.part.2.annobin_lsapi_gets.start.annobin_lsapi_gets.endlsapi_gets.annobin_lsapi_each.start.annobin_lsapi_each.endlsapi_each.annobin_lsapi_puts_ary.start.annobin_lsapi_puts_ary.endlsapi_puts_ary.annobin_lsapi_sync.start.annobin_lsapi_sync.endlsapi_sync.annobin_lsapi_putc.start.annobin_lsapi_putc.endlsapi_putc.annobin_lsapi_puts.start.annobin_lsapi_puts.endlsapi_puts.annobin_lsapi_print.start.annobin_lsapi_print.endlsapi_print.annobin_Init_lsapi.start.annobin_Init_lsapi.endrb_intern_id_cache.15609rb_intern_id_cache.15614orig_envcLSAPI.LC0.LC1.LC7.LC5.LC4.LC6.LC3.LC2.LC8.LC9.LC13.LC11.LC10.LC12.LC14.LC15.LC16.LC17.LC18.LC55.LC20.LC21.LC25.LC26.LC27.LC28.LC29.LC33.LC34.LC35.LC36.LC37.LC38.LC39.LC40.LC41.LC42.LC43.LC44.LC45.LC46.LC47.LC48.LC49.LC50.LC51.LC52.LC53.LC23.LC19.LC30.LC31.LC32.LC24.LC22.LC54.text.group.text.hot.group.text.unlikely.group.text.startup.group.text.exit.group_GLOBAL_OFFSET_TABLE_g_reqrb_tainted_str_newrb_hash_asetrb_funcallvrb_intern2__stack_chk_failrb_gc_markLSAPI_Flush_rmunmapfreeLSAPI_ReadReqBody_rLSAPI_ReqBodyGetChar_rrb_check_typerb_obj_as_stringrb_f_sprintfLSAPI_Postfork_ParentLSAPI_Postfork_ChildLSAPI_Accept_Before_ForkLSAPI_Prefork_Accept_rgetpids_fn_add_envLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rrb_string_valuerb_string_value_ptrrb_eval_string_wrapstrchrrb_ruby_verbose_ptrrb_define_global_construby_strdupmkstempunlinkftruncatemmapcallocperror__errno_locationstrerror__fprintf_chkrb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_str_new_staticrb_exec_recursiverb_default_rsrb_output_fsrb_output_rsrb_lastline_getInit_lsapiLSAPI_InitgetenvstrtolstrlenselectLSAPI_Init_Env_Parameterschdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocLSAPI_Write_rrb_stdoutrb_stdinLSAPI_Write_Stderr_rrb_hash_new__memcpy_chkrb_define_global_functionrb_define_methodrb_define_singleton_methodH7*ltl@EOV{**D <8DH*?HF<KUH{*=****"7<AH8XD^HgmTv|T\*)~l0\hq|lllAg  C* D6 C<HSfnuD  <  <  @     1 8 G Q *[ c t y     D L H  L <( . LS ] Lc Dy  L <  L < D H  L2 K Y Lc <k q L D H  D Lh           &v*3**@* "8DH#$ %#5%QXL_<fm#$*&'T#(**)** +|,3t:t?,KP\dktv5-d7d6d6d6&d9>6EdX]6ddw|6d6d6d6d6d 6d%*61dAF6Md]b6idy~6d6d6d6d6d 6d$)60dCH6O*Vdj.q*x*/\*0*1,d.*2, 3l"l).8=Bg<l4y<d7d7d7 %/6|HMWch {#  i  $, P X" ""["[[hD[Lhphxwhwww 08dlZZZm$Z,mPmXmaDLapaxaW W0W8rdWlrrr$,PX     D  L p x 3  3 3 _ 3 _0 _8 d _l        $  ,  P  X            D  L  p  x     '   ' 0 ' 8  d ' l   P  P P $P,PX       ) . D < C L S Z _ m r B~   j B  P i ~   ' >4 'A N [ h u o  h j   N    2 L  5+ 08 E R _ l y E  G  X  B  ' 3 ? [ g +s       q   :  +     " `) r.  ; W j p v ,|  (    U k 3 s  X   K  V 7      c      & l, 2 8 > _D J KP RV \ >c x v L|    V   &          + 9 G U  ! * *3 9< HE WN fW u` j q x  %     y  4       # o, @ ,M  z B     " A   ) = ,J  z   }  % Y3 IS ` m fz y        s  # d0 e = J W d mq b~  ;    V J   "  g' 4 A oN [ h Xu     K %    k N    + 8 E R _ l y   |   0 6 , Z    }" / j< I V uc h p }      k    # / ; SG 'S &_ k  S     ^  y      M N 5    >   x u  u * % 1 '> & K X e r | 7   ' |  C    5 7 X * 7 $e r  c     s   { @  * f7 =D AQ ~^ l z J  \     >    9   H# =0 = EJ W d /q ~ } : 5           |' t4 A (N 2\ j x H 3       @ [L -X +d q +~  ' a   V  7 M' 4 R C` n | v    n   U    [   2   a   U ab u        k Hx& 3p< UIR }y  } dh  ` .  " /X8 hE R _ l 7z h @ @    V  # A' ;, [8 < A `J X aQr1  p     d F B  )10 % 1 5 ~:nP`a `j v z `  P P      @ <;P1Z x    vH    ' 7+ 30pA@cvlv    )19v 0  "q71AN[p1z CxT1 hz$11@U1$_p1*}1f1n0 #1s  B$ 1y1 PA aR 1_ o  1   1 `  1 p !1!p$!5!1B! Q!b!1o! !.!1!!J!1! !f!1!0""1$"03"D"1Q"`"q"1~"`""1"p""1"p""1# #-%#12#A#LR#1S_#`o#########2#1$A$1L$F,$=$11J$Y$j$1Gw$$ $1V$$l$1$$1% t % % F .% S% e% r% % % V% %% %% % % %% &&'&5& A&X& g& w& & & (& & z&`& &  &0 ' '4('4D' P' g' s' ?w' 9' ' ' ' ' ' ' ' ' ' @' ' ( @( :( 6"( z&( v+( E( T( b( t( ( 5( ( ( ( ( ( ( ( ( h( d( ( ) 7) / ) ) ) !) 1-) ` 1) \ :)L C) T) X) ])W j)} x) ) ) ), ) * * ,* P* \*s* * * * * o* ) * % * 1* * * C* * * ** +O+ + -+ ZL+ Jx+ j+ N+p+ + + + 7 + 3 ++ +p, , q , m ,&, 2,`U, Y, j, n, s,m, , , , |,  - 3- ?-V- b- : f- 6 k- w- w {- s - - --- -P- -  -  . . \ . R #. '. 6. R:. J?. |S.\. m. q. w....8.U.// /2/ >/ B/ S/ ZW/ T\/ Ih/ l/ }/ / // / / /// / @/ </A0 00 '0 30 ~70 vF0 J0 ^0 Ij0 Fn0 Dw0P 0 0 o0 i0 0 00 0 0 0 0 0 `1 1  1 %1 >1 L1 X1o1 1 11 1 01 ,1 k1 i11#1- 2 Q2/2 :2 >2 C2Q2 \2s2 ~2 2 22 22 2 2 22 L22 3 I 3 E3 3 #3 0,3 p 73 ;3 @3 L3 dW3 [3 `3 pi3 v3331333 3 63 433 44&+4E84kF4 S4 I`4 eg4~4 4 p 4 4 d4 @4 44I414 5Z-5 < 85O5 =Z5 _^5 Yc5 ~n5 r5 w5 A5 5 5 5 >5 :5 {5 w5556 6@46 =?6 C6 H6 ~S6 ?W6 -\6 Ag6 k6 p6 {6 6 6 y6 m6 6 66674/7`O7ud71)s77771377881+8@8 G8`^8 Ii8 lm8 hr8m8 8 I8 8 I8 K 8 8  9 %9 E9 c9 a9 9 |9 99 I9 9 9 : :  : -: ?: M: ^: j: %|::p:`: : : +: !: :  ;; ; #; ,; 0; 9; =; ~B; K; O; X; a;r;1S;;;;1L;;; <<8<.A<.Z<@c< Pp< Py< '}< <@< < < < < < <N < < f< d< < <_ =1Z=L+=@5=WM=je=r}=5 =< =g ===> *>1b4># L>} a>1xk> >>>1> > > > > > E> A> }? { ? ? *? C?6 g?1v?O ?o ? ? ? ? ? @ ,@ 0@ 9@ =@ vF@  J@  [@ y _@ q h@ q@ p@ @ @d @d @ !@ !@ Y!@ U!@ !@ !@l @l @  A !A !A Av 'A 8A ! ... end There is no need to change the way that how CGI environment variables are being accessed in your scripts. You can find some examples under examples/ folder. Ruby Script Runner ^^^^^^^^^^^^^^^^^^ If you don't want to change your existing Ruby CGI code, you can use our Ruby script runner under scripts/ folder. You need to configure lsruby_runner.rb as a LSAPI application, then add a script handler for "rb" suffix. Rails dispatcher ^^^^^^^^^^^^^^^^ With Ruby LSAPI, we proudly provide a optimum platform for Rails application deployment. Ruby LSAPI has the following advantages over other solutions. * Easy configuration, deploy a Rails application only take a few clicks with our Rails easy configuration * Fast startup, the expensive Rails framework initialization only takes place once when multiple processes need to be started * Resource efficience, ruby processes can be started on demand, idle process will be stop. To use LSAPI with Ruby on Rails, please check out our toturial http://www.litespeedtech.com/support/wiki/doku.php There are a few environment variables that can be tweaked to tune ruby LSAPI process. * LSAPI_CHILDREN (default: 0) LSAPI_CHILDREN controls the maximum number of children processes can be started by the first ruby process started by web server. When set to <=1, the first ruby process will handle request by itself, without starting any child process. When LSAPI_CHILDREN is >1, the LSAPI application is stared in "Self Managed Mode", which will start children processes based on demand. With Rails easy configuration, LSAPI_CHILDREN is set to the value of "Max Connections" by web server, no need to set it explicitly. Usually, there is no need to set value of LSAPI_CHILDREN over 100 in most server environment. * LSAPI_AVOID_FORK (default: 0) LSAPI_AVOID_FORK specifies the policy of the internal process manager in "Self Managed Mode". When set to 0, the internal process manager will stop and start children process on demand to save system resource. This is preferred in a shared hosting environment. When set to 1, the internal process manager will try to avoid freqently stopping and starting children process. This might be preferred in a dedicate hosting environment. * LSAPI_EXTRA_CHILDREN (default: 1/3 of LSAPI_CHILDREN or 0) LSAPI_EXTRA_CHILDREN controls the maximum number of extra children processes can be started when some or all existing children processes are in malfunctioning state. Total number of children processes will be reduced to LSAPI_CHILDREN level as soon as service is back to normal. When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is 0. * LSAPI_MAX_REQS (default value: 10000) LSAPI_MAX_REQS specifies the maximum number of requests each child process will handle before it exits automatically. This parameter can help reducing memory usage when there are memory leaks in the application. * LSAPI_MAX_IDLE (default value: 300 seconds) In Self Managed Mode, LSAPI_MAX_IDLE controls how long a idle child process will wait for a new request before exit. This option help releasing system resources taken by idle processes. * LSAPI_MAX_IDLE_CHILDREN (default value: 1/3 of LSAPI_CHILDREN or LSAPI_CHILDREN) In Self Managed Mode, LSAI_MAX_IDLE_CHILDREN controls how many idle children processes are allowed. Excessive idle children processes will be killed by the parent process. When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is LSAPI_CHILDREN. * LSAPI_MAX_PROCESS_TIME (default value: 300 seconds) In Self Managed Mode, LSAPI_MAX_PROCESS_TIME controls the maximum processing time allowed when processing a request. If a child process can not finish processing of a request in the given time period, it will be killed by the parent process. This option can help getting rid of dead or runaway child process. * LSAPI_PGRP_MAX_IDLE (default value: FOREVER ) In Self Managed Mode, LSAPI_PGRP_MAX_IDLE controls how long the parent process will wait before exiting when there is no child process. This option help releasing system resources taken by an idle parent process. * LSAPI_PPID_NO_CHECK By default a LSAPI application check the existence of its parent process and exits automatically if the parent process died. This is to reduce orphan process when web server is restarted. However, it is desireable to disable this feature, such as when a LSAPI process was started manually from command line. LSAPI_PPID_NO_CHECK should be set when you want to disable the checking of existence of parent process. License ------- LSAPI library code is under BSD license LSAPI ruby extension code is under Ruby license * (()) (Japanese) * (()) (English) Copyright --------- Copyright (C) 2006 Lite Speed Technologies Inc. PK ]j2(gems/ruby-lsapi-5.5/rails/dispatch.lsapinuȯ#!/opt/alt/ruby27/bin/ruby if GC.respond_to?(:copy_on_write_friendly=) GC.copy_on_write_friendly = true end require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) # If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: # "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired require "dispatcher" require "lsapi" while LSAPI.accept != nil Dispatcher.dispatch end PK ]MM,gems/ruby-lsapi-5.5/scripts/lsruby_runner.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' class CodeCache def [](filename) mtime = File.mtime( filename ) entry = @cache[filename]; if entry != nil return entry end code = compile(filename) #entry = CodeEntry.new( filename, mtime, code ) @cache[filename] = code return code end private def initialize @cache = {} end def compile(filename) open(filename) do |f| s = f.read s.untaint binding = eval_string_wrap("binding") return eval(format("Proc.new {\n%s\n}", s), binding, filename, 0) end end end $count = 0; $cache = CodeCache.new while true $req = LSAPI.accept break if $req == nil filename = ENV['SCRIPT_FILENAME'] filename.untaint filename =~ %r{^(\/.*?)\/*([^\/]+)$} path = $1 Dir.chdir( path ) #load( filename, true ) code = $cache[filename] code.call end class CodeEntry public :path, :name, :mtime, :opcode def initizlize( filename, mtime, opcode ) filename =~ %r{^(\/.*?)\/*([^\/]+)$} @path = $1 @name = $2 @mtime = mtime @opcode = opcode end end PK ]##BBgems/ruby-lsapi-5.5/setup.rbnu[# # setup.rb # # Copyright (c) 2000-2005 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU LGPL, Lesser General Public License version 2.1. # unless Enumerable.method_defined?(:map) # Ruby 1.4.6 module Enumerable alias map collect end end unless File.respond_to?(:read) # Ruby 1.6 def File.read(fname) open(fname) {|f| return f.read } end end unless Errno.const_defined?(:ENOTEMPTY) # Windows? module Errno class ENOTEMPTY # We do not raise this exception, implementation is not needed. end end end def File.binread(fname) open(fname, 'rb') {|f| return f.read } end # for corrupted Windows' stat(2) def File.dir?(path) File.directory?((path[-1,1] == '/') ? path : path + '/') end class ConfigTable include Enumerable def initialize(rbconfig) @rbconfig = rbconfig @items = [] @table = {} # options @install_prefix = nil @config_opt = nil @verbose = true @no_harm = false end attr_accessor :install_prefix attr_accessor :config_opt attr_writer :verbose def verbose? @verbose end attr_writer :no_harm def no_harm? @no_harm end def [](key) lookup(key).resolve(self) end def []=(key, val) lookup(key).set val end def names @items.map {|i| i.name } end def each(&block) @items.each(&block) end def key?(name) @table.key?(name) end def lookup(name) @table[name] or setup_rb_error "no such config item: #{name}" end def add(item) @items.push item @table[item.name] = item end def remove(name) item = lookup(name) @items.delete_if {|i| i.name == name } @table.delete_if {|name, i| i.name == name } item end def load_script(path, inst = nil) if File.file?(path) MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path end end def savefile '.config' end def load_savefile begin File.foreach(savefile()) do |line| k, v = *line.split(/=/, 2) self[k] = v.strip end rescue Errno::ENOENT setup_rb_error $!.message + "\n#{File.basename($0)} config first" end end def save @items.each {|i| i.value } File.open(savefile(), 'w') {|f| @items.each do |i| f.printf "%s=%s\n", i.name, i.value if i.value? and i.value end } end def load_standard_entries standard_entries(@rbconfig).each do |ent| add ent end end def standard_entries(rbconfig) c = rbconfig rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) major = c['MAJOR'].to_i minor = c['MINOR'].to_i teeny = c['TEENY'].to_i version = "#{major}.#{minor}" # ruby ver. >= 1.4.4? newpath_p = ((major >= 2) or ((major == 1) and ((minor >= 5) or ((minor == 4) and (teeny >= 4))))) if c['rubylibdir'] # V > 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = c['rubylibdir'] librubyverarch = c['archdir'] siteruby = c['sitedir'] siterubyver = c['sitelibdir'] siterubyverarch = c['sitearchdir'] elsif newpath_p # 1.4.4 <= V <= 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = c['sitedir'] siterubyver = "$siteruby/#{version}" siterubyverarch = "$siterubyver/#{c['arch']}" else # V < 1.4.4 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" siterubyver = siteruby siterubyverarch = "$siterubyver/#{c['arch']}" end parameterize = lambda {|path| path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') } if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } makeprog = arg.sub(/'/, '').split(/=/, 2)[1] else makeprog = 'make' end [ ExecItem.new('installdirs', 'std/site/home', 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ {|val, table| case val when 'std' table['rbdir'] = '$librubyver' table['sodir'] = '$librubyverarch' when 'site' table['rbdir'] = '$siterubyver' table['sodir'] = '$siterubyverarch' when 'home' setup_rb_error '$HOME was not set' unless ENV['HOME'] table['prefix'] = ENV['HOME'] table['rbdir'] = '$libdir/ruby' table['sodir'] = '$libdir/ruby' end }, PathItem.new('prefix', 'path', c['prefix'], 'path prefix of target environment'), PathItem.new('bindir', 'path', parameterize.call(c['bindir']), 'the directory for commands'), PathItem.new('libdir', 'path', parameterize.call(c['libdir']), 'the directory for libraries'), PathItem.new('datadir', 'path', parameterize.call(c['datadir']), 'the directory for shared data'), PathItem.new('mandir', 'path', parameterize.call(c['mandir']), 'the directory for man pages'), PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), 'the directory for system configuration files'), PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), 'the directory for local state data'), PathItem.new('libruby', 'path', libruby, 'the directory for ruby libraries'), PathItem.new('librubyver', 'path', librubyver, 'the directory for standard ruby libraries'), PathItem.new('librubyverarch', 'path', librubyverarch, 'the directory for standard ruby extensions'), PathItem.new('siteruby', 'path', siteruby, 'the directory for version-independent aux ruby libraries'), PathItem.new('siterubyver', 'path', siterubyver, 'the directory for aux ruby libraries'), PathItem.new('siterubyverarch', 'path', siterubyverarch, 'the directory for aux ruby binaries'), PathItem.new('rbdir', 'path', '$siterubyver', 'the directory for ruby scripts'), PathItem.new('sodir', 'path', '$siterubyverarch', 'the directory for ruby extentions'), PathItem.new('rubypath', 'path', rubypath, 'the path to set to #! line'), ProgramItem.new('rubyprog', 'name', rubypath, 'the ruby program using for installation'), ProgramItem.new('makeprog', 'name', makeprog, 'the make program to compile ruby extentions'), SelectItem.new('shebang', 'all/ruby/never', 'ruby', 'shebang line (#!) editing mode'), BoolItem.new('without-ext', 'yes/no', 'no', 'does not compile/install ruby extentions') ] end private :standard_entries def load_multipackage_entries multipackage_entries().each do |ent| add ent end end def multipackage_entries [ PackageSelectionItem.new('with', 'name,name...', '', 'ALL', 'package names that you want to install'), PackageSelectionItem.new('without', 'name,name...', '', 'NONE', 'package names that you do not want to install') ] end private :multipackage_entries ALIASES = { 'std-ruby' => 'librubyver', 'stdruby' => 'librubyver', 'rubylibdir' => 'librubyver', 'archdir' => 'librubyverarch', 'site-ruby-common' => 'siteruby', # For backward compatibility 'site-ruby' => 'siterubyver', # For backward compatibility 'bin-dir' => 'bindir', 'bin-dir' => 'bindir', 'rb-dir' => 'rbdir', 'so-dir' => 'sodir', 'data-dir' => 'datadir', 'ruby-path' => 'rubypath', 'ruby-prog' => 'rubyprog', 'ruby' => 'rubyprog', 'make-prog' => 'makeprog', 'make' => 'makeprog' } def fixup ALIASES.each do |ali, name| @table[ali] = @table[name] end @items.freeze @table.freeze @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ end def parse_opt(opt) m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" m.to_a[1,2] end def dllext @rbconfig['DLEXT'] end def value_config?(name) lookup(name).value? end class Item def initialize(name, template, default, desc) @name = name.freeze @template = template @value = default @default = default @description = desc end attr_reader :name attr_reader :description attr_accessor :default alias help_default default def help_opt "--#{@name}=#{@template}" end def value? true end def value @value end def resolve(table) @value.gsub(%r<\$([^/]+)>) { table[$1] } end def set(val) @value = check(val) end private def check(val) setup_rb_error "config: --#{name} requires argument" unless val val end end class BoolItem < Item def config_type 'bool' end def help_opt "--#{@name}" end private def check(val) return 'yes' unless val case val when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' else setup_rb_error "config: --#{@name} accepts only yes/no for argument" end end end class PathItem < Item def config_type 'path' end private def check(path) setup_rb_error "config: --#{@name} requires argument" unless path path[0,1] == '$' ? path : File.expand_path(path) end end class ProgramItem < Item def config_type 'program' end end class SelectItem < Item def initialize(name, selection, default, desc) super @ok = selection.split('/') end def config_type 'select' end private def check(val) unless @ok.include?(val.strip) setup_rb_error "config: use --#{@name}=#{@template} (#{val})" end val.strip end end class ExecItem < Item def initialize(name, selection, desc, &block) super name, selection, nil, desc @ok = selection.split('/') @action = block end def config_type 'exec' end def value? false end def resolve(table) setup_rb_error "$#{name()} wrongly used as option value" end undef set def evaluate(val, table) v = val.strip.downcase unless @ok.include?(v) setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" end @action.call v, table end end class PackageSelectionItem < Item def initialize(name, template, default, help_default, desc) super name, template, default, desc @help_default = help_default end attr_reader :help_default def config_type 'package' end private def check(val) unless File.dir?("packages/#{val}") setup_rb_error "config: no such package: #{val}" end val end end class MetaConfigEnvironment def initialize(config, installer) @config = config @installer = installer end def config_names @config.names end def config?(name) @config.key?(name) end def bool_config?(name) @config.lookup(name).config_type == 'bool' end def path_config?(name) @config.lookup(name).config_type == 'path' end def value_config?(name) @config.lookup(name).config_type != 'exec' end def add_config(item) @config.add item end def add_bool_config(name, default, desc) @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) end def add_path_config(name, default, desc) @config.add PathItem.new(name, 'path', default, desc) end def set_config_default(name, default) @config.lookup(name).default = default end def remove_config(name) @config.remove(name) end # For only multipackage def packages raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer @installer.packages end # For only multipackage def declare_packages(list) raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer @installer.packages = list end end end # class ConfigTable # This module requires: #verbose?, #no_harm? module FileOperations def mkdir_p(dirname, prefix = nil) dirname = prefix + File.expand_path(dirname) if prefix $stderr.puts "mkdir -p #{dirname}" if verbose? return if no_harm? # Does not check '/', it's too abnormal. dirs = File.expand_path(dirname).split(%r<(?=/)>) if /\A[a-z]:\z/i =~ dirs[0] disk = dirs.shift dirs[0] = disk + dirs[0] end dirs.each_index do |idx| path = dirs[0..idx].join('') Dir.mkdir path unless File.dir?(path) end end def rm_f(path) $stderr.puts "rm -f #{path}" if verbose? return if no_harm? force_remove_file path end def rm_rf(path) $stderr.puts "rm -rf #{path}" if verbose? return if no_harm? remove_tree path end def remove_tree(path) if File.symlink?(path) remove_file path elsif File.dir?(path) remove_tree0 path else force_remove_file path end end def remove_tree0(path) Dir.foreach(path) do |ent| next if ent == '.' next if ent == '..' entpath = "#{path}/#{ent}" if File.symlink?(entpath) remove_file entpath elsif File.dir?(entpath) remove_tree0 entpath else force_remove_file entpath end end begin Dir.rmdir path rescue Errno::ENOTEMPTY # directory may not be empty end end def move_file(src, dest) force_remove_file dest begin File.rename src, dest rescue File.open(dest, 'wb') {|f| f.write File.binread(src) } File.chmod File.stat(src).mode, dest File.unlink src end end def force_remove_file(path) begin remove_file path rescue end end def remove_file(path) File.chmod 0777, path File.unlink path end def install(from, dest, mode, prefix = nil) $stderr.puts "install #{from} #{dest}" if verbose? return if no_harm? realdest = prefix ? prefix + File.expand_path(dest) : dest realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) str = File.binread(from) if diff?(str, realdest) verbose_off { rm_f realdest if File.exist?(realdest) } File.open(realdest, 'wb') {|f| f.write str } File.chmod mode, realdest File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| if prefix f.puts realdest.sub(prefix, '') else f.puts realdest end } end end def diff?(new_content, path) return true unless File.exist?(path) new_content != File.binread(path) end def command(*args) $stderr.puts args.join(' ') if verbose? system(*args) or raise RuntimeError, "system(#{args.map{|a| a.inspect }.join(' ')}) failed" end def ruby(*args) command config('rubyprog'), *args end def make(task = nil) command(*[config('makeprog'), task].compact) end def extdir?(dir) File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") end def files_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.file?("#{dir}/#{ent}") } } end DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) def directories_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT } end end # This module requires: #srcdir_root, #objdir_root, #relpath module HookScriptAPI def get_config(key) @config[key] end alias config get_config # obsolete: use metaconfig to change configuration def set_config(key, val) @config[key] = val end # # srcdir/objdir (works only in the package directory) # def curr_srcdir "#{srcdir_root()}/#{relpath()}" end def curr_objdir "#{objdir_root()}/#{relpath()}" end def srcfile(path) "#{curr_srcdir()}/#{path}" end def srcexist?(path) File.exist?(srcfile(path)) end def srcdirectory?(path) File.dir?(srcfile(path)) end def srcfile?(path) File.file?(srcfile(path)) end def srcentries(path = '.') Dir.open("#{curr_srcdir()}/#{path}") {|d| return d.to_a - %w(. ..) } end def srcfiles(path = '.') srcentries(path).select {|fname| File.file?(File.join(curr_srcdir(), path, fname)) } end def srcdirectories(path = '.') srcentries(path).select {|fname| File.dir?(File.join(curr_srcdir(), path, fname)) } end end class ToplevelInstaller Version = '3.4.1' Copyright = 'Copyright (c) 2000-2005 Minero Aoki' TASKS = [ [ 'all', 'do config, setup, then install' ], [ 'config', 'saves your configurations' ], [ 'show', 'shows current configuration' ], [ 'setup', 'compiles ruby extentions and others' ], [ 'install', 'installs files' ], [ 'test', 'run all tests in test/' ], [ 'clean', "does `make clean' for each extention" ], [ 'distclean',"does `make distclean' for each extention" ] ] def ToplevelInstaller.invoke config = ConfigTable.new(load_rbconfig()) config.load_standard_entries config.load_multipackage_entries if multipackage? config.fixup klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) klass.new(File.dirname($0), config).invoke end def ToplevelInstaller.multipackage? File.dir?(File.dirname($0) + '/packages') end def ToplevelInstaller.load_rbconfig if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } ARGV.delete(arg) load File.expand_path(arg.split(/=/, 2)[1]) $".push 'rbconfig.rb' else require 'rbconfig' end ::Config::CONFIG end def initialize(ardir_root, config) @ardir = File.expand_path(ardir_root) @config = config # cache @valid_task_re = nil end def config(key) @config[key] end def inspect "#<#{self.class} #{__id__()}>" end def invoke run_metaconfigs case task = parsearg_global() when nil, 'all' parsearg_config init_installers exec_config exec_setup exec_install else case task when 'config', 'test' ; when 'clean', 'distclean' @config.load_savefile if File.exist?(@config.savefile) else @config.load_savefile end __send__ "parsearg_#{task}" init_installers __send__ "exec_#{task}" end end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig" end def init_installers @installer = Installer.new(@config, @ardir, File.expand_path('.')) end # # Hook Script API bases # def srcdir_root @ardir end def objdir_root '.' end def relpath '.' end # # Option Parsing # def parsearg_global while arg = ARGV.shift case arg when /\A\w+\z/ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) return arg when '-q', '--quiet' @config.verbose = false when '--verbose' @config.verbose = true when '--help' print_usage $stdout exit 0 when '--version' puts "#{File.basename($0)} version #{Version}" exit 0 when '--copyright' puts Copyright exit 0 else setup_rb_error "unknown global option '#{arg}'" end end nil end def valid_task?(t) valid_task_re() =~ t end def valid_task_re @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ end def parsearg_no_options unless ARGV.empty? task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" end end alias parsearg_show parsearg_no_options alias parsearg_setup parsearg_no_options alias parsearg_test parsearg_no_options alias parsearg_clean parsearg_no_options alias parsearg_distclean parsearg_no_options def parsearg_config evalopt = [] set = [] @config.config_opt = [] while i = ARGV.shift if /\A--?\z/ =~ i @config.config_opt = ARGV.dup break end name, value = *@config.parse_opt(i) if @config.value_config?(name) @config[name] = value else evalopt.push [name, value] end set.push name end evalopt.each do |name, value| @config.lookup(name).evaluate value, @config end # Check if configuration is valid set.each do |n| @config[n] if @config.value_config?(n) end end def parsearg_install @config.no_harm = false @config.install_prefix = '' while a = ARGV.shift case a when '--no-harm' @config.no_harm = true when /\A--prefix=/ path = a.split(/=/, 2)[1] path = File.expand_path(path) unless path[0,1] == '/' @config.install_prefix = path else setup_rb_error "install: unknown option #{a}" end end end def print_usage(out) out.puts 'Typical Installation Procedure:' out.puts " $ ruby #{File.basename $0} config" out.puts " $ ruby #{File.basename $0} setup" out.puts " # ruby #{File.basename $0} install (may require root privilege)" out.puts out.puts 'Detailed Usage:' out.puts " ruby #{File.basename $0} " out.puts " ruby #{File.basename $0} [] []" fmt = " %-24s %s\n" out.puts out.puts 'Global options:' out.printf fmt, '-q,--quiet', 'suppress message outputs' out.printf fmt, ' --verbose', 'output messages verbosely' out.printf fmt, ' --help', 'print this message' out.printf fmt, ' --version', 'print version and quit' out.printf fmt, ' --copyright', 'print copyright and quit' out.puts out.puts 'Tasks:' TASKS.each do |name, desc| out.printf fmt, name, desc end fmt = " %-24s %s [%s]\n" out.puts out.puts 'Options for CONFIG or ALL:' @config.each do |item| out.printf fmt, item.help_opt, item.description, item.help_default end out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" out.puts out.puts 'Options for INSTALL:' out.printf fmt, '--no-harm', 'only display what to do if given', 'off' out.printf fmt, '--prefix=path', 'install path prefix', '' out.puts end # # Task Handlers # def exec_config @installer.exec_config @config.save # must be final end def exec_setup @installer.exec_setup end def exec_install @installer.exec_install end def exec_test @installer.exec_test end def exec_show @config.each do |i| printf "%-20s %s\n", i.name, i.value if i.value? end end def exec_clean @installer.exec_clean end def exec_distclean @installer.exec_distclean end end # class ToplevelInstaller class ToplevelInstallerMulti < ToplevelInstaller include FileOperations def initialize(ardir_root, config) super @packages = directories_of("#{@ardir}/packages") raise 'no package exists' if @packages.empty? @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig", self @packages.each do |name| @config.load_script "#{@ardir}/packages/#{name}/metaconfig" end end attr_reader :packages def packages=(list) raise 'package list is empty' if list.empty? list.each do |name| raise "directory packages/#{name} does not exist"\ unless File.dir?("#{@ardir}/packages/#{name}") end @packages = list end def init_installers @installers = {} @packages.each do |pack| @installers[pack] = Installer.new(@config, "#{@ardir}/packages/#{pack}", "packages/#{pack}") end with = extract_selection(config('with')) without = extract_selection(config('without')) @selected = @installers.keys.select {|name| (with.empty? or with.include?(name)) \ and not without.include?(name) } end def extract_selection(list) a = list.split(/,/) a.each do |name| setup_rb_error "no such package: #{name}" unless @installers.key?(name) end a end def print_usage(f) super f.puts 'Inluded packages:' f.puts ' ' + @packages.sort.join(' ') f.puts end # # Task Handlers # def exec_config run_hook 'pre-config' each_selected_installers {|inst| inst.exec_config } run_hook 'post-config' @config.save # must be final end def exec_setup run_hook 'pre-setup' each_selected_installers {|inst| inst.exec_setup } run_hook 'post-setup' end def exec_install run_hook 'pre-install' each_selected_installers {|inst| inst.exec_install } run_hook 'post-install' end def exec_test run_hook 'pre-test' each_selected_installers {|inst| inst.exec_test } run_hook 'post-test' end def exec_clean rm_f @config.savefile run_hook 'pre-clean' each_selected_installers {|inst| inst.exec_clean } run_hook 'post-clean' end def exec_distclean rm_f @config.savefile run_hook 'pre-distclean' each_selected_installers {|inst| inst.exec_distclean } run_hook 'post-distclean' end # # lib # def each_selected_installers Dir.mkdir 'packages' unless File.dir?('packages') @selected.each do |pack| $stderr.puts "Processing the package `#{pack}' ..." if verbose? Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") Dir.chdir "packages/#{pack}" yield @installers[pack] Dir.chdir '../..' end end def run_hook(id) @root_installer.run_hook id end # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end end # class ToplevelInstallerMulti class Installer FILETYPES = %w( bin lib ext data conf man ) include FileOperations include HookScriptAPI def initialize(config, srcroot, objroot) @config = config @srcdir = File.expand_path(srcroot) @objdir = File.expand_path(objroot) @currdir = '.' end def inspect "#<#{self.class} #{File.basename(@srcdir)}>" end def noop(rel) end # # Hook Script API base methods # def srcdir_root @srcdir end def objdir_root @objdir end def relpath @currdir end # # Config Access # # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end def verbose_off begin save, @config.verbose = @config.verbose?, false yield ensure @config.verbose = save end end # # TASK config # def exec_config exec_task_traverse 'config' end alias config_dir_bin noop alias config_dir_lib noop def config_dir_ext(rel) extconf if extdir?(curr_srcdir()) end alias config_dir_data noop alias config_dir_conf noop alias config_dir_man noop def extconf ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt end # # TASK setup # def exec_setup exec_task_traverse 'setup' end def setup_dir_bin(rel) files_of(curr_srcdir()).each do |fname| update_shebang_line "#{curr_srcdir()}/#{fname}" end end alias setup_dir_lib noop def setup_dir_ext(rel) make if extdir?(curr_srcdir()) end alias setup_dir_data noop alias setup_dir_conf noop alias setup_dir_man noop def update_shebang_line(path) return if no_harm? return if config('shebang') == 'never' old = Shebang.load(path) if old $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 new = new_shebang(old) return if new.to_s == old.to_s else return unless config('shebang') == 'all' new = Shebang.new(config('rubypath')) end $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? open_atomic_writer(path) {|output| File.open(path, 'rb') {|f| f.gets if old # discard output.puts new.to_s output.print f.read } } end def new_shebang(old) if /\Aruby/ =~ File.basename(old.cmd) Shebang.new(config('rubypath'), old.args) elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' Shebang.new(config('rubypath'), old.args[1..-1]) else return old unless config('shebang') == 'all' Shebang.new(config('rubypath')) end end def open_atomic_writer(path, &block) tmpfile = File.basename(path) + '.tmp' begin File.open(tmpfile, 'wb', &block) File.rename tmpfile, File.basename(path) ensure File.unlink tmpfile if File.exist?(tmpfile) end end class Shebang def Shebang.load(path) line = nil File.open(path) {|f| line = f.gets } return nil unless /\A#!/ =~ line parse(line) end def Shebang.parse(line) cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') new(cmd, args) end def initialize(cmd, args = []) @cmd = cmd @args = args end attr_reader :cmd attr_reader :args def to_s "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") end end # # TASK install # def exec_install rm_f 'InstalledFiles' exec_task_traverse 'install' end def install_dir_bin(rel) install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 end def install_dir_lib(rel) install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 end def install_dir_ext(rel) return unless extdir?(curr_srcdir()) install_files rubyextentions('.'), "#{config('sodir')}/#{File.dirname(rel)}", 0555 end def install_dir_data(rel) install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 end def install_dir_conf(rel) # FIXME: should not remove current config files # (rename previous file to .old/.org) install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 end def install_dir_man(rel) install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 end def install_files(list, dest, mode) mkdir_p dest, @config.install_prefix list.each do |fname| install fname, dest, mode, @config.install_prefix end end def libfiles glob_reject(%w(*.y *.output), targetfiles()) end def rubyextentions(dir) ents = glob_select("*.#{@config.dllext}", targetfiles()) if ents.empty? setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" end ents end def targetfiles mapdir(existfiles() - hookfiles()) end def mapdir(ents) ents.map {|ent| if File.exist?(ent) then ent # objdir else "#{curr_srcdir()}/#{ent}" # srcdir end } end # picked up many entries from cvs-1.11.1/src/ignore.c JUNK_FILES = %w( core RCSLOG tags TAGS .make.state .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$ *.org *.in .* ) def existfiles glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) end def hookfiles %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| %w( config setup install clean ).map {|t| sprintf(fmt, t) } }.flatten end def glob_select(pat, ents) re = globs2re([pat]) ents.select {|ent| re =~ ent } end def glob_reject(pats, ents) re = globs2re(pats) ents.reject {|ent| re =~ ent } end GLOB2REGEX = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' } def globs2re(pats) /\A(?:#{ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') })\z/ end # # TASK test # TESTDIR = 'test' def exec_test unless File.directory?('test') $stderr.puts 'no test in this package' if verbose? return end $stderr.puts 'Running tests...' if verbose? begin require 'test/unit' rescue LoadError setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' end runner = Test::Unit::AutoRunner.new(true) runner.to_run << TESTDIR runner.run end # # TASK clean # def exec_clean exec_task_traverse 'clean' rm_f @config.savefile rm_f 'InstalledFiles' end alias clean_dir_bin noop alias clean_dir_lib noop alias clean_dir_data noop alias clean_dir_conf noop alias clean_dir_man noop def clean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'clean' if File.file?('Makefile') end # # TASK distclean # def exec_distclean exec_task_traverse 'distclean' rm_f @config.savefile rm_f 'InstalledFiles' end alias distclean_dir_bin noop alias distclean_dir_lib noop def distclean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'distclean' if File.file?('Makefile') end alias distclean_dir_data noop alias distclean_dir_conf noop alias distclean_dir_man noop # # Traversing # def exec_task_traverse(task) run_hook "pre-#{task}" FILETYPES.each do |type| if type == 'ext' and config('without-ext') == 'yes' $stderr.puts 'skipping ext/* by user option' if verbose? next end traverse task, type, "#{task}_dir_#{type}" end run_hook "post-#{task}" end def traverse(task, rel, mid) dive_into(rel) { run_hook "pre-#{task}" __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') directories_of(curr_srcdir()).each do |d| traverse task, "#{rel}/#{d}", mid end run_hook "post-#{task}" } end def dive_into(rel) return unless File.dir?("#{@srcdir}/#{rel}") dir = File.basename(rel) Dir.mkdir dir unless File.dir?(dir) prevdir = Dir.pwd Dir.chdir dir $stderr.puts '---> ' + rel if verbose? @currdir = rel yield Dir.chdir prevdir $stderr.puts '<--- ' + rel if verbose? @currdir = File.dirname(rel) end def run_hook(id) path = [ "#{curr_srcdir()}/#{id}", "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } return unless path begin instance_eval File.read(path), path, 1 rescue raise if $DEBUG setup_rb_error "hook #{path} failed:\n" + $!.message end end end # class Installer class SetupError < StandardError; end def setup_rb_error(msg) raise SetupError, msg end if $0 == __FILE__ begin ToplevelInstaller.invoke rescue SetupError raise if $DEBUG $stderr.puts $!.message $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." exit 1 end end PK ]*  )gems/ruby-lsapi-5.5/examples/testlsapi.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' $count = 0; while LSAPI.accept != nil print "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\nHello World! \##{$count}
    \r\n" ENV.each_pair {|key, value| print "#{key} is #{value}
    \r\n" } $count = $count + 1 end PK ].gems/ruby-lsapi-5.5/examples/lsapi_with_cgi.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' require 'cgi' while LSAPI.accept != nil cgi = CGI.new name = cgi['name'] puts cgi.header puts "Hello #{name}!
    " if name puts "You are from #{cgi.remote_addr}
    " end PK ]!gems/minitest-5.13.0/Manifest.txtnu[.autotest History.rdoc Manifest.txt README.rdoc Rakefile design_rationale.rb lib/hoe/minitest.rb lib/minitest.rb lib/minitest/assertions.rb lib/minitest/autorun.rb lib/minitest/benchmark.rb lib/minitest/expectations.rb lib/minitest/hell.rb lib/minitest/mock.rb lib/minitest/parallel.rb lib/minitest/pride.rb lib/minitest/pride_plugin.rb lib/minitest/spec.rb lib/minitest/test.rb lib/minitest/unit.rb test/minitest/metametameta.rb test/minitest/test_minitest_assertions.rb test/minitest/test_minitest_benchmark.rb test/minitest/test_minitest_mock.rb test/minitest/test_minitest_reporter.rb test/minitest/test_minitest_spec.rb test/minitest/test_minitest_test.rb PK ]S`gems/minitest-5.13.0/Rakefilenu[# -*- ruby -*- require "rubygems" require "hoe" Hoe.plugin :seattlerb Hoe.plugin :rdoc Hoe.spec "minitest" do developer "Ryan Davis", "ryand-ruby@zenspider.com" license "MIT" require_ruby_version "~> 2.2" end desc "Find missing expectations" task :specs do $:.unshift "lib" require "minitest/test" require "minitest/spec" pos_prefix, neg_prefix = "must", "wont" skip_re = /^(must|wont)$|wont_(throw)|must_(block|not?_|nothing|raise$)/x dont_flip_re = /(must|wont)_(include|respond_to)/ map = { /(must_throw)s/ => '\1', /(?!not)_same/ => "_be_same_as", /_in_/ => "_be_within_", /_operator/ => "_be", /_includes/ => "_include", /(must|wont)_(.*_of|nil|silent|empty)/ => '\1_be_\2', /must_raises/ => "must_raise", } expectations = Minitest::Expectations.public_instance_methods.map(&:to_s) assertions = Minitest::Assertions.public_instance_methods.map(&:to_s) assertions.sort.each do |assertion| expectation = case assertion when /^assert/ then assertion.sub(/^assert/, pos_prefix.to_s) when /^refute/ then assertion.sub(/^refute/, neg_prefix.to_s) end next unless expectation next if expectation =~ skip_re regexp, replacement = map.find { |re, _| expectation =~ re } expectation.sub! regexp, replacement if replacement next if expectations.include? expectation args = [assertion, expectation].map(&:to_sym).map(&:inspect) args << :reverse if expectation =~ dont_flip_re puts puts "##" puts "# :method: #{expectation}" puts "# See Minitest::Assertions##{assertion}" puts puts "infect_an_assertion #{args.join ", "}" end end task :bugs do sh "for f in bug*.rb ; do echo $f; echo; #{Gem.ruby} -Ilib $f && rm $f ; done" end # vim: syntax=Ruby PK ]9(  =gems/minitest-5.13.0/test/minitest/test_minitest_benchmark.rbnu[require "minitest/autorun" require "minitest/benchmark" ## # Used to verify data: # http://www.wolframalpha.com/examples/RegressionAnalysis.html class TestMinitestBenchmark < Minitest::Test def test_cls_bench_exp assert_equal [2, 4, 8, 16, 32], Minitest::Benchmark.bench_exp(2, 32, 2) end def test_cls_bench_linear assert_equal [2, 4, 6, 8, 10], Minitest::Benchmark.bench_linear(2, 10, 2) end def test_cls_runnable_methods assert_equal [], Minitest::Benchmark.runnable_methods c = Class.new(Minitest::Benchmark) do def bench_blah end end assert_equal ["bench_blah"], c.runnable_methods end def test_cls_bench_range assert_equal [1, 10, 100, 1_000, 10_000], Minitest::Benchmark.bench_range end def test_fit_exponential_clean x = [1.0, 2.0, 3.0, 4.0, 5.0] y = x.map { |n| 1.1 * Math.exp(2.1 * n) } assert_fit :exponential, x, y, 1.0, 1.1, 2.1 end def test_fit_exponential_noisy x = [1.0, 1.9, 2.6, 3.4, 5.0] y = [12, 10, 8.2, 6.9, 5.9] # verified with Numbers and R assert_fit :exponential, x, y, 0.95, 13.81148, -0.1820 end def test_fit_logarithmic_clean x = [1.0, 2.0, 3.0, 4.0, 5.0] y = x.map { |n| 1.1 + 2.1 * Math.log(n) } assert_fit :logarithmic, x, y, 1.0, 1.1, 2.1 end def test_fit_logarithmic_noisy x = [1.0, 2.0, 3.0, 4.0, 5.0] # Generated with # y = x.map { |n| jitter = 0.999 + 0.002 * rand; (Math.log(n) ) * jitter } y = [0.0, 0.6935, 1.0995, 1.3873, 1.6097] assert_fit :logarithmic, x, y, 0.95, 0, 1 end def test_fit_constant_clean x = (1..5).to_a y = [5.0, 5.0, 5.0, 5.0, 5.0] assert_fit :linear, x, y, nil, 5.0, 0 end def test_fit_constant_noisy x = (1..5).to_a y = [1.0, 1.2, 1.0, 0.8, 1.0] # verified in numbers and R assert_fit :linear, x, y, nil, 1.12, -0.04 end def test_fit_linear_clean # y = m * x + b where m = 2.2, b = 3.1 x = (1..5).to_a y = x.map { |n| 2.2 * n + 3.1 } assert_fit :linear, x, y, 1.0, 3.1, 2.2 end def test_fit_linear_noisy x = [ 60, 61, 62, 63, 65] y = [3.1, 3.6, 3.8, 4.0, 4.1] # verified in numbers and R assert_fit :linear, x, y, 0.8315, -7.9635, 0.1878 end def test_fit_power_clean # y = A x ** B, where B = b and A = e ** a # if, A = 1, B = 2, then x = [1.0, 2.0, 3.0, 4.0, 5.0] y = [1.0, 4.0, 9.0, 16.0, 25.0] assert_fit :power, x, y, 1.0, 1.0, 2.0 end def test_fit_power_noisy # from www.engr.uidaho.edu/thompson/courses/ME330/lecture/least_squares.html x = [10, 12, 15, 17, 20, 22, 25, 27, 30, 32, 35] y = [95, 105, 125, 141, 173, 200, 253, 298, 385, 459, 602] # verified in numbers assert_fit :power, x, y, 0.90, 2.6217, 1.4556 # income to % of households below income amount # http://library.wolfram.com/infocenter/Conferences/6461/PowerLaws.nb x = [15_000, 25_000, 35_000, 50_000, 75_000, 100_000] y = [0.154, 0.283, 0.402, 0.55, 0.733, 0.843] # verified in numbers assert_fit :power, x, y, 0.96, 3.119e-5, 0.8959 end def assert_fit msg, x, y, fit, exp_a, exp_b bench = Minitest::Benchmark.new :blah a, b, rr = bench.send "fit_#{msg}", x, y assert_operator rr, :>=, fit if fit assert_in_delta exp_a, a assert_in_delta exp_b, b end end describe "my class Bench" do klass = self it "should provide bench methods" do klass.must_respond_to :bench end end PK ]+ɃɃ>gems/minitest-5.13.0/test/minitest/test_minitest_assertions.rbnu[# encoding: UTF-8 require "minitest/autorun" if defined? Encoding then e = Encoding.default_external if e != Encoding::UTF_8 then warn "" warn "" warn "NOTE: External encoding #{e} is not UTF-8. Tests WILL fail." warn " Run tests with `RUBYOPT=-Eutf-8 rake` to avoid errors." warn "" warn "" end end SomeError = Class.new Exception unless defined? MyModule then module MyModule; end class AnError < StandardError; include MyModule; end end class TestMinitestAssertions < Minitest::Test # do not call parallelize_me! - teardown accesses @tc._assertions # which is not threadsafe. Nearly every method in here is an # assertion test so it isn't worth splitting it out further. RUBY18 = !defined? Encoding class DummyTest include Minitest::Assertions # include Minitest::Reportable # TODO: why do I really need this? attr_accessor :assertions, :failure def initialize self.assertions = 0 self.failure = nil end end def setup super Minitest::Test.reset @tc = DummyTest.new @zomg = "zomg ponies!" # TODO: const @assertion_count = 1 end def teardown assert_equal(@assertion_count, @tc.assertions, "expected #{@assertion_count} assertions to be fired during the test, not #{@tc.assertions}") end def assert_deprecated name dep = /DEPRECATED: #{name}. From #{__FILE__}:\d+(?::.*)?/ dep = "" if $-w.nil? assert_output nil, dep do yield end end def assert_triggered expected, klass = Minitest::Assertion e = assert_raises klass do yield end msg = e.message.sub(/(---Backtrace---).*/m, '\1') msg.gsub!(/\(oid=[-0-9]+\)/, "(oid=N)") msg.gsub!(/(\d\.\d{6})\d+/, '\1xxx') # normalize: ruby version, impl, platform assert_msg = Regexp === expected ? :assert_match : :assert_equal self.send assert_msg, expected, msg end def clean s s.gsub(/^ {6,10}/, "") end def non_verbose orig_verbose = $VERBOSE $VERBOSE = false yield ensure $VERBOSE = orig_verbose end def test_assert @assertion_count = 2 @tc.assert_equal true, @tc.assert(true), "returns true on success" end def test_assert__triggered assert_triggered "Expected false to be truthy." do @tc.assert false end end def test_assert__triggered_message assert_triggered @zomg do @tc.assert false, @zomg end end def test_assert__triggered_lambda assert_triggered "whoops" do @tc.assert false, lambda { "whoops" } end end def test_assert_empty @assertion_count = 2 @tc.assert_empty [] end def test_assert_empty_triggered @assertion_count = 2 assert_triggered "Expected [1] to be empty." do @tc.assert_empty [1] end end def test_assert_equal @tc.assert_equal 1, 1 end def test_assert_equal_different_collection_array_hex_invisible object1 = Object.new object2 = Object.new msg = "No visible difference in the Array#inspect output. You should look at the implementation of #== on Array or its members. [#]".gsub(/^ +/, "") assert_triggered msg do @tc.assert_equal [object1], [object2] end end def test_assert_equal_different_collection_hash_hex_invisible h1, h2 = {}, {} h1[1] = Object.new h2[1] = Object.new msg = "No visible difference in the Hash#inspect output. You should look at the implementation of #== on Hash or its members. {1=>#}".gsub(/^ +/, "") assert_triggered msg do @tc.assert_equal h1, h2 end end def test_assert_equal_different_diff_deactivated without_diff do assert_triggered util_msg("haha" * 10, "blah" * 10) do o1 = "haha" * 10 o2 = "blah" * 10 @tc.assert_equal o1, o2 end end end def test_assert_equal_different_message assert_triggered "whoops.\nExpected: 1\n Actual: 2" do @tc.assert_equal 1, 2, message { "whoops" } end end def test_assert_equal_different_lambda assert_triggered "whoops.\nExpected: 1\n Actual: 2" do @tc.assert_equal 1, 2, lambda { "whoops" } end end def test_assert_equal_different_hex c = Class.new do def initialize s; @name = s; end end o1 = c.new "a" o2 = c.new "b" msg = clean <<-EOS --- expected +++ actual @@ -1 +1 @@ -#<#:0xXXXXXX @name=\"a\"> +#<#:0xXXXXXX @name=\"b\"> EOS assert_triggered msg do @tc.assert_equal o1, o2 end end def test_assert_equal_different_hex_invisible o1 = Object.new o2 = Object.new msg = "No visible difference in the Object#inspect output. You should look at the implementation of #== on Object or its members. #".gsub(/^ +/, "") assert_triggered msg do @tc.assert_equal o1, o2 end end def test_assert_equal_different_long msg = "--- expected +++ actual @@ -1 +1 @@ -\"hahahahahahahahahahahahahahahahahahahaha\" +\"blahblahblahblahblahblahblahblahblahblah\" ".gsub(/^ +/, "") assert_triggered msg do o1 = "haha" * 10 o2 = "blah" * 10 @tc.assert_equal o1, o2 end end def test_assert_equal_different_long_invisible msg = "No visible difference in the String#inspect output. You should look at the implementation of #== on String or its members. \"blahblahblahblahblahblahblahblahblahblah\"".gsub(/^ +/, "") assert_triggered msg do o1 = "blah" * 10 o2 = "blah" * 10 def o1.== _ false end @tc.assert_equal o1, o2 end end def test_assert_equal_different_long_msg msg = "message. --- expected +++ actual @@ -1 +1 @@ -\"hahahahahahahahahahahahahahahahahahahaha\" +\"blahblahblahblahblahblahblahblahblahblah\" ".gsub(/^ +/, "") assert_triggered msg do o1 = "haha" * 10 o2 = "blah" * 10 @tc.assert_equal o1, o2, "message" end end def test_assert_equal_different_short assert_triggered util_msg(1, 2) do @tc.assert_equal 1, 2 end end def test_assert_equal_different_short_msg assert_triggered util_msg(1, 2, "message") do @tc.assert_equal 1, 2, "message" end end def test_assert_equal_different_short_multiline msg = "--- expected\n+++ actual\n@@ -1,2 +1,2 @@\n \"a\n-b\"\n+c\"\n" assert_triggered msg do @tc.assert_equal "a\nb", "a\nc" end end def test_assert_equal_does_not_allow_lhs_nil if Minitest::VERSION =~ /^6/ then warn "Time to strip the MT5 test" @assertion_count += 1 assert_triggered(/Use assert_nil if expecting nil/) do @tc.assert_equal nil, nil end else err_re = /Use assert_nil if expecting nil from .*test_minitest_\w+.rb/ err_re = "" if $-w.nil? assert_output "", err_re do @tc.assert_equal nil, nil end end end def test_assert_equal_does_not_allow_lhs_nil_triggered assert_triggered "Expected: nil\n Actual: false" do @tc.assert_equal nil, false end end def test_assert_equal_string_bug791 exp = <<-'EOF'.gsub(/^ {10}/, "") # note single quotes --- expected +++ actual @@ -1,2 +1 @@ -"\\n -" +"\\\" EOF exp = "Expected: \"\\\\n\"\n Actual: \"\\\\\"" assert_triggered exp do @tc.assert_equal "\\n", "\\" end end def test_assert_equal_string_both_escaped_unescaped_newlines msg = <<-EOM.gsub(/^ {10}/, "") --- expected +++ actual @@ -1,2 +1 @@ -\"A\\n -B\" +\"A\\n\\\\nB\" EOM assert_triggered msg do exp = "A\\nB" act = "A\n\\nB" @tc.assert_equal exp, act end end def test_assert_equal_string_encodings msg = <<-EOM.gsub(/^ {10}/, "") --- expected +++ actual @@ -1,3 +1,3 @@ -# encoding: UTF-8 -# valid: false +# encoding: ASCII-8BIT +# valid: true "bad-utf8-\\xF1.txt" EOM assert_triggered msg do x = "bad-utf8-\xF1.txt" y = x.dup.force_encoding "binary" # TODO: switch to .b when 1.9 dropped @tc.assert_equal x, y end end unless RUBY18 def test_assert_equal_string_encodings_both_different msg = <<-EOM.gsub(/^ {10}/, "") --- expected +++ actual @@ -1,3 +1,3 @@ -# encoding: US-ASCII -# valid: false +# encoding: ASCII-8BIT +# valid: true "bad-utf8-\\xF1.txt" EOM assert_triggered msg do x = "bad-utf8-\xF1.txt".force_encoding "ASCII" y = x.dup.force_encoding "binary" # TODO: switch to .b when 1.9 dropped @tc.assert_equal x, y end end unless RUBY18 def test_assert_equal_unescape_newlines msg = <<-'EOM'.gsub(/^ {10}/, "") # NOTE single quotes on heredoc --- expected +++ actual @@ -1,2 +1,2 @@ -"hello +"hello\n world" EOM assert_triggered msg do exp = "hello\nworld" act = 'hello\nworld' # notice single quotes @tc.assert_equal exp, act end end def test_assert_in_delta @tc.assert_in_delta 0.0, 1.0 / 1000, 0.1 end def test_assert_in_delta_triggered x = "1.0e-06" assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}." do @tc.assert_in_delta 0.0, 1.0 / 1000, 0.000001 end end def test_assert_in_epsilon @assertion_count = 10 @tc.assert_in_epsilon 10_000, 9991 @tc.assert_in_epsilon 9991, 10_000 @tc.assert_in_epsilon 1.0, 1.001 @tc.assert_in_epsilon 1.001, 1.0 @tc.assert_in_epsilon 10_000, 9999.1, 0.0001 @tc.assert_in_epsilon 9999.1, 10_000, 0.0001 @tc.assert_in_epsilon 1.0, 1.0001, 0.0001 @tc.assert_in_epsilon 1.0001, 1.0, 0.0001 @tc.assert_in_epsilon(-1, -1) @tc.assert_in_epsilon(-10_000, -9991) end def test_assert_in_epsilon_triggered assert_triggered "Expected |10000 - 9990| (10) to be <= 9.99." do @tc.assert_in_epsilon 10_000, 9990 end end def test_assert_in_epsilon_triggered_negative_case x = (RUBY18 and not maglev?) ? "0.1" : "0.100000xxx" y = "0.1" assert_triggered "Expected |-1.1 - -1| (#{x}) to be <= #{y}." do @tc.assert_in_epsilon(-1.1, -1, 0.1) end end def test_assert_includes @assertion_count = 2 @tc.assert_includes [true], true end def test_assert_includes_triggered @assertion_count = 3 e = @tc.assert_raises Minitest::Assertion do @tc.assert_includes [true], false end expected = "Expected [true] to include false." assert_equal expected, e.message end def test_assert_instance_of @tc.assert_instance_of String, "blah" end def test_assert_instance_of_triggered assert_triggered 'Expected "blah" to be an instance of Array, not String.' do @tc.assert_instance_of Array, "blah" end end def test_assert_kind_of @tc.assert_kind_of String, "blah" end def test_assert_kind_of_triggered assert_triggered 'Expected "blah" to be a kind of Array, not String.' do @tc.assert_kind_of Array, "blah" end end def test_assert_match @assertion_count = 2 @tc.assert_match(/\w+/, "blah blah blah") end def test_assert_match_matchee_to_str @assertion_count = 2 obj = Object.new def obj.to_str; "blah" end @tc.assert_match "blah", obj end def test_assert_match_matcher_object @assertion_count = 2 pattern = Object.new def pattern.=~ _; true end @tc.assert_match pattern, 5 end def test_assert_match_object_triggered @assertion_count = 2 pattern = Object.new def pattern.=~ _; false end def pattern.inspect; "[Object]" end assert_triggered "Expected [Object] to match 5." do @tc.assert_match pattern, 5 end end def test_assert_match_triggered @assertion_count = 2 assert_triggered 'Expected /\d+/ to match "blah blah blah".' do @tc.assert_match(/\d+/, "blah blah blah") end end def test_assert_nil @tc.assert_nil nil end def test_assert_nil_triggered assert_triggered "Expected 42 to be nil." do @tc.assert_nil 42 end end def test_assert_operator @tc.assert_operator 2, :>, 1 end def test_assert_operator_bad_object bad = Object.new def bad.== _; true end @tc.assert_operator bad, :equal?, bad end def test_assert_operator_triggered assert_triggered "Expected 2 to be < 1." do @tc.assert_operator 2, :<, 1 end end def test_assert_output_both @assertion_count = 2 @tc.assert_output "yay", "blah" do print "yay" $stderr.print "blah" end end def test_assert_output_both_regexps @assertion_count = 4 @tc.assert_output(/y.y/, /bl.h/) do print "yay" $stderr.print "blah" end end def test_assert_output_err @tc.assert_output nil, "blah" do $stderr.print "blah" end end def test_assert_output_neither @assertion_count = 0 @tc.assert_output do # do nothing end end def test_assert_output_out @tc.assert_output "blah" do print "blah" end end def test_assert_output_triggered_both assert_triggered util_msg("blah", "blah blah", "In stderr") do @tc.assert_output "yay", "blah" do print "boo" $stderr.print "blah blah" end end end def test_assert_output_triggered_err assert_triggered util_msg("blah", "blah blah", "In stderr") do @tc.assert_output nil, "blah" do $stderr.print "blah blah" end end end def test_assert_output_triggered_out assert_triggered util_msg("blah", "blah blah", "In stdout") do @tc.assert_output "blah" do print "blah blah" end end end def test_assert_output_without_block assert_triggered "assert_output requires a block to capture output." do @tc.assert_output "blah" end end def test_assert_predicate @tc.assert_predicate "", :empty? end def test_assert_predicate_triggered assert_triggered 'Expected "blah" to be empty?.' do @tc.assert_predicate "blah", :empty? end end def test_assert_raises @tc.assert_raises RuntimeError do raise "blah" end end def test_assert_raises_default @tc.assert_raises do raise StandardError, "blah" end end def test_assert_raises_default_triggered e = assert_raises Minitest::Assertion do @tc.assert_raises do raise SomeError, "blah" end end expected = clean <<-EOM.chomp [StandardError] exception expected, not Class: Message: <\"blah\"> ---Backtrace--- FILE:LINE:in \`test_assert_raises_default_triggered\' --------------- EOM actual = e.message.gsub(/^.+:\d+/, "FILE:LINE") actual.gsub!(/block \(\d+ levels\) in /, "") if RUBY_VERSION >= "1.9.0" assert_equal expected, actual end def test_assert_raises_exit @tc.assert_raises SystemExit do exit 1 end end def test_assert_raises_module @tc.assert_raises MyModule do raise AnError end end def test_assert_raises_signals @tc.assert_raises SignalException do raise SignalException, :INT end end ## # *sigh* This is quite an odd scenario, but it is from real (albeit # ugly) test code in ruby-core: # http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=29259 def test_assert_raises_skip @assertion_count = 0 assert_triggered "skipped", Minitest::Skip do @tc.assert_raises ArgumentError do begin raise "blah" rescue skip "skipped" end end end end def test_assert_raises_subclass @tc.assert_raises StandardError do raise AnError end end def test_assert_raises_subclass_triggered e = assert_raises Minitest::Assertion do @tc.assert_raises SomeError do raise AnError, "some message" end end expected = clean <<-EOM [SomeError] exception expected, not Class: Message: <\"some message\"> ---Backtrace--- FILE:LINE:in \`test_assert_raises_subclass_triggered\' --------------- EOM actual = e.message.gsub(/^.+:\d+/, "FILE:LINE") actual.gsub!(/block \(\d+ levels\) in /, "") if RUBY_VERSION >= "1.9.0" assert_equal expected.chomp, actual end def test_assert_raises_triggered_different e = assert_raises Minitest::Assertion do @tc.assert_raises RuntimeError do raise SyntaxError, "icky" end end expected = clean <<-EOM.chomp [RuntimeError] exception expected, not Class: Message: <\"icky\"> ---Backtrace--- FILE:LINE:in \`test_assert_raises_triggered_different\' --------------- EOM actual = e.message.gsub(/^.+:\d+/, "FILE:LINE") actual.gsub!(/block \(\d+ levels\) in /, "") if RUBY_VERSION >= "1.9.0" assert_equal expected, actual end def test_assert_raises_triggered_different_msg e = assert_raises Minitest::Assertion do @tc.assert_raises RuntimeError, "XXX" do raise SyntaxError, "icky" end end expected = clean <<-EOM XXX. [RuntimeError] exception expected, not Class: Message: <\"icky\"> ---Backtrace--- FILE:LINE:in \`test_assert_raises_triggered_different_msg\' --------------- EOM actual = e.message.gsub(/^.+:\d+/, "FILE:LINE") actual.gsub!(/block \(\d+ levels\) in /, "") if RUBY_VERSION >= "1.9.0" assert_equal expected.chomp, actual end def test_assert_raises_triggered_none e = assert_raises Minitest::Assertion do @tc.assert_raises Minitest::Assertion do # do nothing end end expected = "Minitest::Assertion expected but nothing was raised." assert_equal expected, e.message end def test_assert_raises_triggered_none_msg e = assert_raises Minitest::Assertion do @tc.assert_raises Minitest::Assertion, "XXX" do # do nothing end end expected = "XXX.\nMinitest::Assertion expected but nothing was raised." assert_equal expected, e.message end def test_assert_raises_without_block assert_triggered "assert_raises requires a block to capture errors." do @tc.assert_raises StandardError end end def test_assert_respond_to @tc.assert_respond_to "blah", :empty? end def test_assert_respond_to_triggered assert_triggered 'Expected "blah" (String) to respond to #rawr!.' do @tc.assert_respond_to "blah", :rawr! end end def test_assert_same @assertion_count = 3 o = "blah" @tc.assert_same 1, 1 @tc.assert_same :blah, :blah @tc.assert_same o, o end def test_assert_same_triggered @assertion_count = 2 assert_triggered "Expected 2 (oid=N) to be the same as 1 (oid=N)." do @tc.assert_same 1, 2 end s1 = "blah" s2 = "blah" assert_triggered 'Expected "blah" (oid=N) to be the same as "blah" (oid=N).' do @tc.assert_same s1, s2 end end def test_assert_send assert_deprecated :assert_send do @tc.assert_send [1, :<, 2] end end def test_assert_send_bad assert_deprecated :assert_send do assert_triggered "Expected 1.>(*[2]) to return true." do @tc.assert_send [1, :>, 2] end end end def test_assert_silent @assertion_count = 2 @tc.assert_silent do # do nothing end end def test_assert_silent_triggered_err assert_triggered util_msg("", "blah blah", "In stderr") do @tc.assert_silent do $stderr.print "blah blah" end end end def test_assert_silent_triggered_out @assertion_count = 2 assert_triggered util_msg("", "blah blah", "In stdout") do @tc.assert_silent do print "blah blah" end end end def test_assert_throws @tc.assert_throws :blah do throw :blah end end def test_assert_throws_argument_exception @tc.assert_raises ArgumentError do @tc.assert_throws :blah do raise ArgumentError end end end def test_assert_throws_different assert_triggered "Expected :blah to have been thrown, not :not_blah." do @tc.assert_throws :blah do throw :not_blah end end end def test_assert_throws_name_error @tc.assert_raises NameError do @tc.assert_throws :blah do raise NameError end end end def test_assert_throws_unthrown assert_triggered "Expected :blah to have been thrown." do @tc.assert_throws :blah do # do nothing end end end def test_assert_path_exists @tc.assert_path_exists __FILE__ end def test_assert_path_exists_triggered assert_triggered "Expected path 'blah' to exist." do @tc.assert_path_exists "blah" end end def test_capture_io @assertion_count = 0 non_verbose do out, err = capture_io do puts "hi" $stderr.puts "bye!" end assert_equal "hi\n", out assert_equal "bye!\n", err end end def test_capture_subprocess_io @assertion_count = 0 non_verbose do out, err = capture_subprocess_io do system("echo hi") system("echo bye! 1>&2") end assert_equal "hi\n", out assert_equal "bye!", err.strip end end def test_class_asserts_match_refutes @assertion_count = 0 methods = Minitest::Assertions.public_instance_methods methods.map!(&:to_s) if Symbol === methods.first # These don't have corresponding refutes _on purpose_. They're # useless and will never be added, so don't bother. ignores = %w[assert_output assert_raises assert_send assert_silent assert_throws assert_mock] # These are test/unit methods. I'm not actually sure why they're still here ignores += %w[assert_no_match assert_not_equal assert_not_nil assert_not_same assert_nothing_raised assert_nothing_thrown assert_raise] asserts = methods.grep(/^assert/).sort - ignores refutes = methods.grep(/^refute/).sort - ignores assert_empty refutes.map { |n| n.sub(/^refute/, "assert") } - asserts assert_empty asserts.map { |n| n.sub(/^assert/, "refute") } - refutes end def test_delta_consistency @assertion_count = 2 @tc.assert_in_delta 0, 1, 1 assert_triggered "Expected |0 - 1| (1) to not be <= 1." do @tc.refute_in_delta 0, 1, 1 end end def test_epsilon_consistency @assertion_count = 2 @tc.assert_in_epsilon 1.0, 1.001 msg = "Expected |1.0 - 1.001| (0.000999xxx) to not be <= 0.001." assert_triggered msg do @tc.refute_in_epsilon 1.0, 1.001 end end def test_fail_after t = Time.now y, m, d = t.year, t.month, t.day assert_silent do @tc.fail_after y, m, d+1, "remove the deprecations" end assert_triggered "remove the deprecations" do @tc.fail_after y, m, d, "remove the deprecations" end end def test_flunk assert_triggered "Epic Fail!" do @tc.flunk end end def test_flunk_message assert_triggered @zomg do @tc.flunk @zomg end end def test_pass @tc.pass end def test_refute @assertion_count = 2 @tc.assert_equal false, @tc.refute(false), "returns false on success" end def test_refute_empty @assertion_count = 2 @tc.refute_empty [1] end def test_refute_empty_triggered @assertion_count = 2 assert_triggered "Expected [] to not be empty." do @tc.refute_empty [] end end def test_refute_equal @tc.refute_equal "blah", "yay" end def test_refute_equal_triggered assert_triggered 'Expected "blah" to not be equal to "blah".' do @tc.refute_equal "blah", "blah" end end def test_refute_in_delta @tc.refute_in_delta 0.0, 1.0 / 1000, 0.000001 end def test_refute_in_delta_triggered x = "0.1" assert_triggered "Expected |0.0 - 0.001| (0.001) to not be <= #{x}." do @tc.refute_in_delta 0.0, 1.0 / 1000, 0.1 end end def test_refute_in_epsilon @tc.refute_in_epsilon 10_000, 9990-1 end def test_refute_in_epsilon_triggered assert_triggered "Expected |10000 - 9990| (10) to not be <= 10.0." do @tc.refute_in_epsilon 10_000, 9990 flunk end end def test_refute_includes @assertion_count = 2 @tc.refute_includes [true], false end def test_refute_includes_triggered @assertion_count = 3 e = @tc.assert_raises Minitest::Assertion do @tc.refute_includes [true], true end expected = "Expected [true] to not include true." assert_equal expected, e.message end def test_refute_instance_of @tc.refute_instance_of Array, "blah" end def test_refute_instance_of_triggered assert_triggered 'Expected "blah" to not be an instance of String.' do @tc.refute_instance_of String, "blah" end end def test_refute_kind_of @tc.refute_kind_of Array, "blah" end def test_refute_kind_of_triggered assert_triggered 'Expected "blah" to not be a kind of String.' do @tc.refute_kind_of String, "blah" end end def test_refute_match @assertion_count = 2 @tc.refute_match(/\d+/, "blah blah blah") end def test_refute_match_matcher_object @assertion_count = 2 pattern = Object.new def pattern.=~ _; false end @tc.refute_match pattern, 5 end def test_refute_match_object_triggered @assertion_count = 2 pattern = Object.new def pattern.=~ _; true end def pattern.inspect; "[Object]" end assert_triggered "Expected [Object] to not match 5." do @tc.refute_match pattern, 5 end end def test_refute_match_triggered @assertion_count = 2 assert_triggered 'Expected /\w+/ to not match "blah blah blah".' do @tc.refute_match(/\w+/, "blah blah blah") end end def test_refute_nil @tc.refute_nil 42 end def test_refute_nil_triggered assert_triggered "Expected nil to not be nil." do @tc.refute_nil nil end end def test_refute_operator @tc.refute_operator 2, :<, 1 end def test_refute_operator_bad_object bad = Object.new def bad.== _; true end @tc.refute_operator true, :equal?, bad end def test_refute_operator_triggered assert_triggered "Expected 2 to not be > 1." do @tc.refute_operator 2, :>, 1 end end def test_refute_predicate @tc.refute_predicate "42", :empty? end def test_refute_predicate_triggered assert_triggered 'Expected "" to not be empty?.' do @tc.refute_predicate "", :empty? end end def test_refute_respond_to @tc.refute_respond_to "blah", :rawr! end def test_refute_respond_to_triggered assert_triggered 'Expected "blah" to not respond to empty?.' do @tc.refute_respond_to "blah", :empty? end end def test_refute_same @tc.refute_same 1, 2 end def test_refute_same_triggered assert_triggered "Expected 1 (oid=N) to not be the same as 1 (oid=N)." do @tc.refute_same 1, 1 end end def test_refute_path_exists @tc.refute_path_exists "blah" end def test_refute_path_exists_triggered assert_triggered "Expected path '#{__FILE__}' to not exist." do @tc.refute_path_exists __FILE__ end end def test_skip @assertion_count = 0 assert_triggered "haha!", Minitest::Skip do @tc.skip "haha!" end end def test_skip_until @assertion_count = 0 t = Time.now y, m, d = t.year, t.month, t.day assert_output "", /Stale skip_until \"not yet\" at .*?:\d+$/ do @tc.skip_until y, m, d, "not yet" end assert_triggered "not ready yet", Minitest::Skip do @tc.skip_until y, m, d+1, "not ready yet" end end def util_msg exp, act, msg = nil s = "Expected: #{exp.inspect}\n Actual: #{act.inspect}" s = "#{msg}.\n#{s}" if msg s end def without_diff old_diff = Minitest::Assertions.diff Minitest::Assertions.diff = nil yield ensure Minitest::Assertions.diff = old_diff end end class TestMinitestAssertionHelpers < Minitest::Test def assert_mu_pp exp, input, raw = false act = mu_pp input if String === input && !raw then assert_equal "\"#{exp}\"", act else assert_equal exp, act end end def assert_mu_pp_for_diff exp, input, raw = false act = mu_pp_for_diff input if String === input && !raw then assert_equal "\"#{exp}\"", act else assert_equal exp, act end end def test_diff_equal msg = "No visible difference in the String#inspect output. You should look at the implementation of #== on String or its members. \"blahblahblahblahblahblahblahblahblahblah\"".gsub(/^ +/, "") o1 = "blah" * 10 o2 = "blah" * 10 def o1.== _ false end assert_equal msg, diff(o1, o2) end def test_diff_str_mixed msg = <<-'EOM'.gsub(/^ {10}/, "") # NOTE single quotes on heredoc --- expected +++ actual @@ -1 +1 @@ -"A\\n\nB" +"A\n\\nB" EOM exp = "A\\n\nB" act = "A\n\\nB" assert_equal msg, diff(exp, act) end def test_diff_str_multiline msg = <<-'EOM'.gsub(/^ {10}/, "") # NOTE single quotes on heredoc --- expected +++ actual @@ -1,2 +1,2 @@ "A -B" +C" EOM exp = "A\nB" act = "A\nC" assert_equal msg, diff(exp, act) end def test_diff_str_simple msg = <<-'EOM'.gsub(/^ {10}/, "").chomp # NOTE single quotes on heredoc Expected: "A" Actual: "B" EOM exp = "A" act = "B" assert_equal msg, diff(exp, act) end def test_message assert_equal "blah2.", message { "blah2" }.call assert_equal "blah2.", message("") { "blah2" }.call assert_equal "blah1.\nblah2.", message(:blah1) { "blah2" }.call assert_equal "blah1.\nblah2.", message("blah1") { "blah2" }.call message = proc { "blah1" } assert_equal "blah1.\nblah2.", message(message) { "blah2" }.call message = message { "blah1" } assert_equal "blah1.\nblah2.", message(message) { "blah2" }.call end def test_message_deferred var = nil msg = message { var = "blah" } assert_nil var msg.call assert_equal "blah", var end def test_mu_pp assert_mu_pp 42.inspect, 42 assert_mu_pp %w[a b c].inspect, %w[a b c] assert_mu_pp "A B", "A B" assert_mu_pp "A\\nB", "A\nB" assert_mu_pp "A\\\\nB", 'A\nB' # notice single quotes end def test_mu_pp_for_diff assert_mu_pp_for_diff "#", Object.new assert_mu_pp_for_diff "A B", "A B" assert_mu_pp_for_diff [1, 2, 3].inspect, [1, 2, 3] assert_mu_pp_for_diff "A\nB", "A\nB" end def test_mu_pp_for_diff_str_bad_encoding str = "\666".force_encoding Encoding::UTF_8 exp = "# encoding: UTF-8\n# valid: false\n\"\\xB6\"" assert_mu_pp_for_diff exp, str, :raw end def test_mu_pp_for_diff_str_bad_encoding_both str = "\666A\\n\nB".force_encoding Encoding::UTF_8 exp = "# encoding: UTF-8\n# valid: false\n\"\\xB6A\\\\n\\nB\"" assert_mu_pp_for_diff exp, str, :raw end def test_mu_pp_for_diff_str_encoding str = "A\nB".b exp = "# encoding: ASCII-8BIT\n# valid: true\n\"A\nB\"" assert_mu_pp_for_diff exp, str, :raw end def test_mu_pp_for_diff_str_encoding_both str = "A\\n\nB".b exp = "# encoding: ASCII-8BIT\n# valid: true\n\"A\\\\n\\nB\"" assert_mu_pp_for_diff exp, str, :raw end def test_mu_pp_for_diff_str_nerd assert_mu_pp_for_diff "A\\nB\\\\nC", "A\nB\\nC" assert_mu_pp_for_diff "\\nB\\\\nC", "\nB\\nC" assert_mu_pp_for_diff "\\nB\\\\n", "\nB\\n" assert_mu_pp_for_diff "\\n\\\\n", "\n\\n" assert_mu_pp_for_diff "\\\\n\\n", "\\n\n" assert_mu_pp_for_diff "\\\\nB\\n", "\\nB\n" assert_mu_pp_for_diff "\\\\nB\\nC", "\\nB\nC" assert_mu_pp_for_diff "A\\\\n\\nB", "A\\n\nB" assert_mu_pp_for_diff "A\\n\\\\nB", "A\n\\nB" assert_mu_pp_for_diff "\\\\n\\n", "\\n\n" assert_mu_pp_for_diff "\\n\\\\n", "\n\\n" end def test_mu_pp_for_diff_str_normal assert_mu_pp_for_diff "", "" assert_mu_pp_for_diff "A\\n\n", "A\\n" assert_mu_pp_for_diff "A\\n\nB", "A\\nB" assert_mu_pp_for_diff "A\n", "A\n" assert_mu_pp_for_diff "A\nB", "A\nB" assert_mu_pp_for_diff "\\n\n", "\\n" assert_mu_pp_for_diff "\n", "\n" assert_mu_pp_for_diff "\\n\nA", "\\nA" assert_mu_pp_for_diff "\nA", "\nA" end def test_mu_pp_str_bad_encoding str = "\666".force_encoding Encoding::UTF_8 exp = "# encoding: UTF-8\n# valid: false\n\"\\xB6\"" assert_mu_pp exp, str, :raw end def test_mu_pp_str_encoding str = "A\nB".b exp = "# encoding: ASCII-8BIT\n# valid: true\n\"A\\nB\"" assert_mu_pp exp, str, :raw end def test_mu_pp_str_immutable printer = Class.new { extend Minitest::Assertions } str = "test".freeze assert_equal '"test"', printer.mu_pp(str) end end PK ]`#*ii<gems/minitest-5.13.0/test/minitest/test_minitest_reporter.rbnu[require "minitest/autorun" require "minitest/metametameta" class Runnable def woot assert true end end class TestMinitestReporter < MetaMetaMetaTestCase attr_accessor :r, :io def new_composite_reporter reporter = Minitest::CompositeReporter.new reporter << Minitest::SummaryReporter.new(self.io) reporter << Minitest::ProgressReporter.new(self.io) def reporter.first reporters.first end def reporter.results first.results end def reporter.count first.count end def reporter.assertions first.assertions end reporter end def setup self.io = StringIO.new("") self.r = new_composite_reporter end def error_test unless defined? @et then @et = Minitest::Test.new(:woot) @et.failures << Minitest::UnexpectedError.new(begin raise "no" rescue => e e end) @et = Minitest::Result.from @et end @et end def fail_test unless defined? @ft then @ft = Minitest::Test.new(:woot) @ft.failures << begin raise Minitest::Assertion, "boo" rescue Minitest::Assertion => e e end @ft = Minitest::Result.from @ft end @ft end def passing_test @pt ||= Minitest::Result.from Minitest::Test.new(:woot) end def skip_test unless defined? @st then @st = Minitest::Test.new(:woot) @st.failures << begin raise Minitest::Skip rescue Minitest::Assertion => e e end @st = Minitest::Result.from @st end @st end def test_to_s r.record passing_test r.record fail_test assert_match "woot", r.first.to_s end def test_passed_eh_empty assert_predicate r, :passed? end def test_passed_eh_failure r.results << fail_test refute_predicate r, :passed? end SKIP_MSG = "\n\nYou have skipped tests. Run with --verbose for details." def test_passed_eh_error r.start r.results << error_test refute_predicate r, :passed? r.report refute_match SKIP_MSG, io.string end def test_passed_eh_skipped r.start r.results << skip_test assert r.passed? restore_env do r.report end assert_match SKIP_MSG, io.string end def test_passed_eh_skipped_verbose r.first.options[:verbose] = true r.start r.results << skip_test assert r.passed? r.report refute_match SKIP_MSG, io.string end def test_start r.start exp = "Run options: \n\n# Running:\n\n" assert_equal exp, io.string end def test_record_pass r.record passing_test assert_equal ".", io.string assert_empty r.results assert_equal 1, r.count assert_equal 0, r.assertions end def test_record_fail fail_test = self.fail_test r.record fail_test assert_equal "F", io.string assert_equal [fail_test], r.results assert_equal 1, r.count assert_equal 0, r.assertions end def test_record_error error_test = self.error_test r.record error_test assert_equal "E", io.string assert_equal [error_test], r.results assert_equal 1, r.count assert_equal 0, r.assertions end def test_record_skip skip_test = self.skip_test r.record skip_test assert_equal "S", io.string assert_equal [skip_test], r.results assert_equal 1, r.count assert_equal 0, r.assertions end def test_report_empty r.start r.report exp = clean <<-EOM Run options: # Running: Finished in 0.00 0 runs, 0 assertions, 0 failures, 0 errors, 0 skips EOM assert_equal exp, normalize_output(io.string) end def test_report_passing r.start r.record passing_test r.report exp = clean <<-EOM Run options: # Running: . Finished in 0.00 1 runs, 0 assertions, 0 failures, 0 errors, 0 skips EOM assert_equal exp, normalize_output(io.string) end def test_report_failure r.start r.record fail_test r.report exp = clean <<-EOM Run options: # Running: F Finished in 0.00 1) Failure: Minitest::Test#woot [FILE:LINE]: boo 1 runs, 0 assertions, 1 failures, 0 errors, 0 skips EOM assert_equal exp, normalize_output(io.string) end def test_report_error r.start r.record error_test r.report exp = clean <<-EOM Run options: # Running: E Finished in 0.00 1) Error: Minitest::Test#woot: RuntimeError: no FILE:LINE:in `error_test' FILE:LINE:in `test_report_error' 1 runs, 0 assertions, 0 failures, 1 errors, 0 skips EOM assert_equal exp, normalize_output(io.string) end def test_report_skipped r.start r.record skip_test restore_env do r.report end exp = clean <<-EOM Run options: # Running: S Finished in 0.00 1 runs, 0 assertions, 0 failures, 0 errors, 1 skips You have skipped tests. Run with --verbose for details. EOM assert_equal exp, normalize_output(io.string) end end PK ]m1i\i\8gems/minitest-5.13.0/test/minitest/test_minitest_test.rbnu[# encoding: UTF-8 require "pathname" require "minitest/metametameta" if defined? Encoding then e = Encoding.default_external if e != Encoding::UTF_8 then warn "" warn "" warn "NOTE: External encoding #{e} is not UTF-8. Tests WILL fail." warn " Run tests with `RUBYOPT=-Eutf-8 rake` to avoid errors." warn "" warn "" end end class Minitest::Runnable def whatever # faked for testing assert true end end class TestMinitestUnit < MetaMetaMetaTestCase parallelize_me! pwd = Pathname.new File.expand_path Dir.pwd basedir = Pathname.new(File.expand_path "lib/minitest") + "mini" basedir = basedir.relative_path_from(pwd).to_s MINITEST_BASE_DIR = basedir[/\A\./] ? basedir : "./#{basedir}" BT_MIDDLE = ["#{MINITEST_BASE_DIR}/test.rb:161:in `each'", "#{MINITEST_BASE_DIR}/test.rb:158:in `each'", "#{MINITEST_BASE_DIR}/test.rb:139:in `run'", "#{MINITEST_BASE_DIR}/test.rb:106:in `run'"] def test_filter_backtrace # this is a semi-lame mix of relative paths. # I cheated by making the autotest parts not have ./ bt = (["lib/autotest.rb:571:in `add_exception'", "test/test_autotest.rb:62:in `test_add_exception'", "#{MINITEST_BASE_DIR}/test.rb:165:in `__send__'"] + BT_MIDDLE + ["#{MINITEST_BASE_DIR}/test.rb:29", "test/test_autotest.rb:422"]) bt = util_expand_bt bt ex = ["lib/autotest.rb:571:in `add_exception'", "test/test_autotest.rb:62:in `test_add_exception'"] ex = util_expand_bt ex fu = Minitest.filter_backtrace(bt) assert_equal ex, fu end def test_filter_backtrace_all_unit bt = (["#{MINITEST_BASE_DIR}/test.rb:165:in `__send__'"] + BT_MIDDLE + ["#{MINITEST_BASE_DIR}/test.rb:29"]) ex = bt.clone fu = Minitest.filter_backtrace(bt) assert_equal ex, fu end def test_filter_backtrace_unit_starts bt = (["#{MINITEST_BASE_DIR}/test.rb:165:in `__send__'"] + BT_MIDDLE + ["#{MINITEST_BASE_DIR}/mini/test.rb:29", "-e:1"]) bt = util_expand_bt bt ex = ["-e:1"] fu = Minitest.filter_backtrace bt assert_equal ex, fu end # def test_default_runner_is_minitest_unit # assert_instance_of Minitest::Unit, Minitest::Unit.runner # end def test_infectious_binary_encoding @tu = Class.new FakeNamedTest do def test_this_is_not_ascii_assertion assert_equal "ЁЁЁ", "ёёё" end def test_this_is_non_ascii_failure_message fail 'ЁЁЁ'.force_encoding('ASCII-8BIT') end end expected = clean <<-EOM EF Finished in 0.00 1) Error: FakeNamedTestXX#test_this_is_non_ascii_failure_message: RuntimeError: ЁЁЁ FILE:LINE:in `test_this_is_non_ascii_failure_message' 2) Failure: FakeNamedTestXX#test_this_is_not_ascii_assertion [FILE:LINE]: Expected: \"ЁЁЁ\" Actual: \"ёёё\" 2 runs, 1 assertions, 1 failures, 1 errors, 0 skips EOM assert_report expected end def test_passed_eh_teardown_good test_class = Class.new FakeNamedTest do def teardown; assert true; end def test_omg; assert true; end end test = test_class.new :test_omg test.run refute_predicate test, :error? assert_predicate test, :passed? refute_predicate test, :skipped? end def test_passed_eh_teardown_skipped test_class = Class.new FakeNamedTest do def teardown; assert true; end def test_omg; skip "bork"; end end test = test_class.new :test_omg test.run refute_predicate test, :error? refute_predicate test, :passed? assert_predicate test, :skipped? end def test_passed_eh_teardown_flunked test_class = Class.new FakeNamedTest do def teardown; flunk; end def test_omg; assert true; end end test = test_class.new :test_omg test.run refute_predicate test, :error? refute_predicate test, :passed? refute_predicate test, :skipped? end def util_expand_bt bt if RUBY_VERSION >= "1.9.0" then bt.map { |f| (f =~ /^\./) ? File.expand_path(f) : f } else bt end end end class TestMinitestUnitInherited < MetaMetaMetaTestCase def with_overridden_include Class.class_eval do def inherited_with_hacks _klass throw :inherited_hook end alias inherited_without_hacks inherited alias inherited inherited_with_hacks alias IGNORE_ME! inherited # 1.8 bug. god I love venture bros end yield ensure Class.class_eval do alias inherited inherited_without_hacks undef_method :inherited_with_hacks undef_method :inherited_without_hacks end refute_respond_to Class, :inherited_with_hacks refute_respond_to Class, :inherited_without_hacks end def test_inherited_hook_plays_nice_with_others with_overridden_include do assert_throws :inherited_hook do Class.new FakeNamedTest end end end end class TestMinitestRunner < MetaMetaMetaTestCase # do not parallelize this suite... it just can't handle it. def test_class_runnables @assertion_count = 0 tc = Class.new(Minitest::Test) assert_equal 1, Minitest::Test.runnables.size assert_equal [tc], Minitest::Test.runnables end def test_run_test @tu = Class.new FakeNamedTest do attr_reader :foo def run @foo = "hi mom!" r = super @foo = "okay" r end def test_something assert_equal "hi mom!", foo end end expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected end def test_run_error @tu = Class.new FakeNamedTest do def test_something assert true end def test_error raise "unhandled exception" end end expected = clean <<-EOM E. Finished in 0.00 1) Error: FakeNamedTestXX#test_error: RuntimeError: unhandled exception FILE:LINE:in \`test_error\' 2 runs, 1 assertions, 0 failures, 1 errors, 0 skips EOM assert_report expected end def test_run_error_teardown @tu = Class.new FakeNamedTest do def test_something assert true end def teardown raise "unhandled exception" end end expected = clean <<-EOM E Finished in 0.00 1) Error: FakeNamedTestXX#test_something: RuntimeError: unhandled exception FILE:LINE:in \`teardown\' 1 runs, 1 assertions, 0 failures, 1 errors, 0 skips EOM assert_report expected end def test_run_failing setup_basic_tu expected = clean <<-EOM F. Finished in 0.00 1) Failure: FakeNamedTestXX#test_failure [FILE:LINE]: Expected false to be truthy. 2 runs, 2 assertions, 1 failures, 0 errors, 0 skips EOM assert_report expected end def setup_basic_tu @tu = Class.new FakeNamedTest do def test_something assert true end def test_failure assert false end end end def test_run_failing_filtered setup_basic_tu expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected, %w[--name /some|thing/ --seed 42] end def assert_filtering filter, name, expected, a = false args = %W[--#{filter} #{name} --seed 42] alpha = Class.new FakeNamedTest do define_method :test_something do assert a end end Object.const_set(:Alpha, alpha) beta = Class.new FakeNamedTest do define_method :test_something do assert true end end Object.const_set(:Beta, beta) @tus = [alpha, beta] assert_report expected, args ensure Object.send :remove_const, :Alpha Object.send :remove_const, :Beta end def test_run_filtered_including_suite_name expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "name", "/Beta#test_something/", expected end def test_run_filtered_including_suite_name_string expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "name", "Beta#test_something", expected end def test_run_filtered_string_method_only expected = clean <<-EOM .. Finished in 0.00 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "name", "test_something", expected, :pass end def test_run_failing_excluded setup_basic_tu expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected, %w[--exclude /failure/ --seed 42] end def test_run_filtered_excluding_suite_name expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "exclude", "/Alpha#test_something/", expected end def test_run_filtered_excluding_suite_name_string expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "exclude", "Alpha#test_something", expected end def test_run_filtered_excluding_string_method_only expected = clean <<-EOM Finished in 0.00 0 runs, 0 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "exclude", "test_something", expected, :pass end def test_run_passing @tu = Class.new FakeNamedTest do def test_something assert true end end expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected end def test_run_skip @tu = Class.new FakeNamedTest do def test_something assert true end def test_skip skip "not yet" end end expected = clean <<-EOM S. Finished in 0.00 2 runs, 1 assertions, 0 failures, 0 errors, 1 skips You have skipped tests. Run with --verbose for details. EOM restore_env do assert_report expected end end def test_run_skip_verbose @tu = Class.new FakeNamedTest do def test_something assert true end def test_skip skip "not yet" end end expected = clean <<-EOM FakeNamedTestXX#test_skip = 0.00 s = S FakeNamedTestXX#test_something = 0.00 s = . Finished in 0.00 1) Skipped: FakeNamedTestXX#test_skip [FILE:LINE]: not yet 2 runs, 1 assertions, 0 failures, 0 errors, 1 skips EOM assert_report expected, %w[--seed 42 --verbose] end def test_run_with_other_runner @tu = Class.new FakeNamedTest do def self.run reporter, options = {} @reporter = reporter before_my_suite super end def self.name; "wacky!" end def self.before_my_suite @reporter.io.puts "Running #{self.name} tests" @@foo = 1 end def test_something assert_equal 1, @@foo end def test_something_else assert_equal 1, @@foo end end expected = clean <<-EOM Running wacky! tests .. Finished in 0.00 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected end require "monitor" class Latch def initialize count = 1 @count = count @lock = Monitor.new @cv = @lock.new_cond end def release @lock.synchronize do @count -= 1 if @count > 0 @cv.broadcast if @count == 0 end end def await @lock.synchronize { @cv.wait_while { @count > 0 } } end end def test_run_parallel test_count = 2 test_latch = Latch.new test_count wait_latch = Latch.new test_count main_latch = Latch.new thread = Thread.new { Thread.current.abort_on_exception = true # This latch waits until both test latches have been released. Both # latches can't be released unless done in separate threads because # `main_latch` keeps the test method from finishing. test_latch.await main_latch.release } @tu = Class.new FakeNamedTest do parallelize_me! test_count.times do |i| define_method :"test_wait_on_main_thread_#{i}" do test_latch.release # This latch blocks until the "main thread" releases it. The main # thread can't release this latch until both test latches have # been released. This forces the latches to be released in separate # threads. main_latch.await assert true end end end expected = clean <<-EOM .. Finished in 0.00 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips EOM assert_report(expected) do |reporter| reporter.extend(Module.new { define_method("record") do |result| super(result) wait_latch.release end define_method("report") do wait_latch.await super() end }) end assert thread.join end end class TestMinitestUnitOrder < MetaMetaMetaTestCase # do not parallelize this suite... it just can't handle it. def test_before_setup call_order = [] @tu = Class.new FakeNamedTest do define_method :setup do super() call_order << :setup end define_method :before_setup do call_order << :before_setup end def test_omg; assert true; end end run_tu_with_fresh_reporter expected = [:before_setup, :setup] assert_equal expected, call_order end def test_after_teardown call_order = [] @tu = Class.new FakeNamedTest do define_method :teardown do super() call_order << :teardown end define_method :after_teardown do call_order << :after_teardown end def test_omg; assert true; end end run_tu_with_fresh_reporter expected = [:teardown, :after_teardown] assert_equal expected, call_order end def test_all_teardowns_are_guaranteed_to_run call_order = [] @tu = Class.new FakeNamedTest do define_method :after_teardown do super() call_order << :after_teardown raise end define_method :teardown do super() call_order << :teardown raise end define_method :before_teardown do super() call_order << :before_teardown raise end def test_omg; assert true; end end run_tu_with_fresh_reporter expected = [:before_teardown, :teardown, :after_teardown] assert_equal expected, call_order end def test_setup_and_teardown_survive_inheritance call_order = [] @tu = Class.new FakeNamedTest do define_method :setup do call_order << :setup_method end define_method :teardown do call_order << :teardown_method end define_method :test_something do call_order << :test end end run_tu_with_fresh_reporter @tu = Class.new @tu run_tu_with_fresh_reporter # Once for the parent class, once for the child expected = [:setup_method, :test, :teardown_method] * 2 assert_equal expected, call_order end end class TestMinitestRunnable < Minitest::Test def setup_marshal klass tc = klass.new "whatever" tc.assertions = 42 tc.failures << "a failure" yield tc if block_given? def tc.setup @blah = "blah" end tc.setup @tc = Minitest::Result.from tc end def assert_marshal expected_ivars new_tc = Marshal.load Marshal.dump @tc ivars = new_tc.instance_variables.map(&:to_s).sort assert_equal expected_ivars, ivars assert_equal "whatever", new_tc.name assert_equal 42, new_tc.assertions assert_equal ["a failure"], new_tc.failures yield new_tc if block_given? end def test_marshal setup_marshal Minitest::Runnable assert_marshal %w[@NAME @assertions @failures @klass @source_location @time] end def test_spec_marshal klass = describe("whatever") { it("passes") { assert true } } rm = klass.runnable_methods.first # Run the test @tc = klass.new(rm).run assert_kind_of Minitest::Result, @tc # Pass it over the wire over_the_wire = Marshal.load Marshal.dump @tc assert_equal @tc.time, over_the_wire.time assert_equal @tc.name, over_the_wire.name assert_equal @tc.assertions, over_the_wire.assertions assert_equal @tc.failures, over_the_wire.failures assert_equal @tc.klass, over_the_wire.klass end end class TestMinitestTest < TestMinitestRunnable def test_dup setup_marshal Minitest::Test do |tc| tc.time = 3.14 end assert_marshal %w[@NAME @assertions @failures @klass @source_location @time] do |new_tc| assert_in_epsilon 3.14, new_tc.time end end end class TestMinitestUnitTestCase < Minitest::Test # do not call parallelize_me! - teardown accesses @tc._assertions # which is not threadsafe. Nearly every method in here is an # assertion test so it isn't worth splitting it out further. RUBY18 = !defined? Encoding def setup super Minitest::Test.reset @tc = Minitest::Test.new "fake tc" @zomg = "zomg ponies!" @assertion_count = 1 end def teardown assert_equal(@assertion_count, @tc.assertions, "expected #{@assertion_count} assertions to be fired during the test, not #{@tc.assertions}") if @tc.passed? end def non_verbose orig_verbose = $VERBOSE $VERBOSE = false yield ensure $VERBOSE = orig_verbose end def test_runnable_methods_random @assertion_count = 0 sample_test_case = Class.new FakeNamedTest do def self.test_order; :random; end def test_test1; assert "does not matter" end def test_test2; assert "does not matter" end def test_test3; assert "does not matter" end end srand 42 expected = %w[test_test2 test_test1 test_test3] assert_equal expected, sample_test_case.runnable_methods end def test_runnable_methods_sorted @assertion_count = 0 sample_test_case = Class.new FakeNamedTest do def self.test_order; :sorted end def test_test3; assert "does not matter" end def test_test2; assert "does not matter" end def test_test1; assert "does not matter" end end expected = %w[test_test1 test_test2 test_test3] assert_equal expected, sample_test_case.runnable_methods end def test_i_suck_and_my_tests_are_order_dependent_bang_sets_test_order_alpha @assertion_count = 0 shitty_test_case = Class.new FakeNamedTest shitty_test_case.i_suck_and_my_tests_are_order_dependent! assert_equal :alpha, shitty_test_case.test_order end def test_i_suck_and_my_tests_are_order_dependent_bang_does_not_warn @assertion_count = 0 shitty_test_case = Class.new FakeNamedTest def shitty_test_case.test_order; :lol end assert_silent do shitty_test_case.i_suck_and_my_tests_are_order_dependent! end end def test_autorun_does_not_affect_fork_success_status @assertion_count = 0 skip "windows doesn't have skip" unless Process.respond_to?(:fork) Process.waitpid(fork {}) assert_equal true, $?.success? end def test_autorun_does_not_affect_fork_exit_status @assertion_count = 0 skip "windows doesn't have skip" unless Process.respond_to?(:fork) Process.waitpid(fork { exit 42 }) assert_equal 42, $?.exitstatus end end class TestMinitestGuard < Minitest::Test parallelize_me! def test_mri_eh assert self.class.mri? "ruby blah" assert self.mri? "ruby blah" end def test_jruby_eh assert self.class.jruby? "java" assert self.jruby? "java" end def test_rubinius_eh assert_output "", /DEPRECATED/ do assert self.class.rubinius? "rbx" end assert_output "", /DEPRECATED/ do assert self.rubinius? "rbx" end end def test_maglev_eh assert_output "", /DEPRECATED/ do assert self.class.maglev? "maglev" end assert_output "", /DEPRECATED/ do assert self.maglev? "maglev" end end def test_osx_eh assert self.class.osx? "darwin" assert self.osx? "darwin" end def test_windows_eh assert self.class.windows? "mswin" assert self.windows? "mswin" end end class TestMinitestUnitRecording < MetaMetaMetaTestCase # do not parallelize this suite... it just can't handle it. def assert_run_record *expected, &block @tu = Class.new FakeNamedTest, &block run_tu_with_fresh_reporter recorded = first_reporter.results.map(&:failures).flatten.map { |f| f.error.class } assert_equal expected, recorded end def test_run_with_bogus_reporter # https://github.com/seattlerb/minitest/issues/659 # TODO: remove test for minitest 6 @tu = Class.new FakeNamedTest do def test_method assert true end end bogus_reporter = Class.new do # doesn't subclass AbstractReporter def start; @success = false; end # def prerecord klass, name; end # doesn't define full API def record result; @success = true; end def report; end def passed?; end def results; end def success?; @success; end end.new self.reporter = Minitest::CompositeReporter.new reporter << bogus_reporter Minitest::Runnable.runnables.delete @tu @tu.run reporter, {} assert_predicate bogus_reporter, :success? end def test_record_passing assert_run_record do def test_method assert true end end end def test_record_failing assert_run_record Minitest::Assertion do def test_method assert false end end end def test_record_error assert_run_record RuntimeError do def test_method raise "unhandled exception" end end end def test_record_error_teardown assert_run_record RuntimeError do def test_method assert true end def teardown raise "unhandled exception" end end end def test_record_error_in_test_and_teardown assert_run_record AnError, RuntimeError do def test_method raise AnError end def teardown raise "unhandled exception" end end end def test_to_s_error_in_test_and_teardown @tu = Class.new FakeNamedTest do def test_method raise AnError end def teardown raise "unhandled exception" end end run_tu_with_fresh_reporter exp = clean " Error: FakeNamedTestXX#test_method: AnError: AnError FILE:LINE:in `test_method' Error: FakeNamedTestXX#test_method: RuntimeError: unhandled exception FILE:LINE:in `teardown' " assert_equal exp.strip, normalize_output(first_reporter.results.first.to_s).strip end def test_record_skip assert_run_record Minitest::Skip do def test_method skip "not yet" end end end end PK ]lJlJ8gems/minitest-5.13.0/test/minitest/test_minitest_mock.rbnu[require "minitest/autorun" class TestMinitestMock < Minitest::Test parallelize_me! def setup @mock = Minitest::Mock.new.expect(:foo, nil) @mock.expect(:meaning_of_life, 42) end def test_create_stub_method assert_nil @mock.foo end def test_allow_return_value_specification assert_equal 42, @mock.meaning_of_life end def test_blow_up_if_not_called @mock.foo util_verify_bad "expected meaning_of_life() => 42" end def test_not_blow_up_if_everything_called @mock.foo @mock.meaning_of_life assert_mock @mock end def test_allow_expectations_to_be_added_after_creation @mock.expect(:bar, true) assert @mock.bar end def test_not_verify_if_new_expected_method_is_not_called @mock.foo @mock.meaning_of_life @mock.expect(:bar, true) util_verify_bad "expected bar() => true" end def test_blow_up_on_wrong_number_of_arguments @mock.foo @mock.meaning_of_life @mock.expect(:sum, 3, [1, 2]) e = assert_raises ArgumentError do @mock.sum end assert_equal "mocked method :sum expects 2 arguments, got 0", e.message end def test_return_mock_does_not_raise retval = Minitest::Mock.new mock = Minitest::Mock.new mock.expect(:foo, retval) mock.foo assert_mock mock end def test_mock_args_does_not_raise arg = Minitest::Mock.new mock = Minitest::Mock.new mock.expect(:foo, nil, [arg]) mock.foo(arg) assert_mock mock end def test_set_expectation_on_special_methods mock = Minitest::Mock.new mock.expect :object_id, "received object_id" assert_equal "received object_id", mock.object_id mock.expect :respond_to_missing?, "received respond_to_missing?" assert_equal "received respond_to_missing?", mock.respond_to_missing? mock.expect :===, "received ===" assert_equal "received ===", mock.=== mock.expect :inspect, "received inspect" assert_equal "received inspect", mock.inspect mock.expect :to_s, "received to_s" assert_equal "received to_s", mock.to_s mock.expect :public_send, "received public_send" assert_equal "received public_send", mock.public_send mock.expect :send, "received send" assert_equal "received send", mock.send assert_mock mock end def test_expectations_can_be_satisfied_via_send @mock.send :foo @mock.send :meaning_of_life assert_mock @mock end def test_expectations_can_be_satisfied_via_public_send skip "Doesn't run on 1.8" if RUBY_VERSION < "1.9" @mock.public_send :foo @mock.public_send :meaning_of_life assert_mock @mock end def test_blow_up_on_wrong_arguments @mock.foo @mock.meaning_of_life @mock.expect(:sum, 3, [1, 2]) e = assert_raises MockExpectationError do @mock.sum(2, 4) end exp = "mocked method :sum called with unexpected arguments [2, 4]" assert_equal exp, e.message end def test_expect_with_non_array_args e = assert_raises ArgumentError do @mock.expect :blah, 3, false end assert_equal "args must be an array", e.message end def test_respond_appropriately assert @mock.respond_to?(:foo) assert @mock.respond_to?(:foo, true) assert @mock.respond_to?("foo") assert !@mock.respond_to?(:bar) end def test_no_method_error_on_unexpected_methods e = assert_raises NoMethodError do @mock.bar end expected = "unmocked method :bar, expected one of [:foo, :meaning_of_life]" assert_equal expected, e.message end def test_assign_per_mock_return_values a = Minitest::Mock.new b = Minitest::Mock.new a.expect(:foo, :a) b.expect(:foo, :b) assert_equal :a, a.foo assert_equal :b, b.foo end def test_do_not_create_stub_method_on_new_mocks a = Minitest::Mock.new a.expect(:foo, :a) assert !Minitest::Mock.new.respond_to?(:foo) end def test_mock_is_a_blank_slate @mock.expect :kind_of?, true, [String] @mock.expect :==, true, [1] assert @mock.kind_of?(String), "didn't mock :kind_of\?" assert @mock == 1, "didn't mock :==" end def test_verify_allows_called_args_to_be_loosely_specified mock = Minitest::Mock.new mock.expect :loose_expectation, true, [Integer] mock.loose_expectation 1 assert_mock mock end def test_verify_raises_with_strict_args mock = Minitest::Mock.new mock.expect :strict_expectation, true, [2] e = assert_raises MockExpectationError do mock.strict_expectation 1 end exp = "mocked method :strict_expectation called with unexpected arguments [1]" assert_equal exp, e.message end def test_method_missing_empty mock = Minitest::Mock.new mock.expect :a, nil mock.a e = assert_raises MockExpectationError do mock.a end assert_equal "No more expects available for :a: []", e.message end def test_same_method_expects_are_verified_when_all_called mock = Minitest::Mock.new mock.expect :foo, nil, [:bar] mock.expect :foo, nil, [:baz] mock.foo :bar mock.foo :baz assert_mock mock end def test_same_method_expects_blow_up_when_not_all_called mock = Minitest::Mock.new mock.expect :foo, nil, [:bar] mock.expect :foo, nil, [:baz] mock.foo :bar e = assert_raises(MockExpectationError) { mock.verify } exp = "expected foo(:baz) => nil, got [foo(:bar) => nil]" assert_equal exp, e.message end def test_same_method_expects_with_same_args_blow_up_when_not_all_called mock = Minitest::Mock.new mock.expect :foo, nil, [:bar] mock.expect :foo, nil, [:bar] mock.foo :bar e = assert_raises(MockExpectationError) { mock.verify } exp = "expected foo(:bar) => nil, got [foo(:bar) => nil]" assert_equal exp, e.message end def test_verify_passes_when_mock_block_returns_true mock = Minitest::Mock.new mock.expect :foo, nil do true end mock.foo assert_mock mock end def test_mock_block_is_passed_function_params arg1, arg2, arg3 = :bar, [1, 2, 3], { :a => "a" } mock = Minitest::Mock.new mock.expect :foo, nil do |a1, a2, a3| a1 == arg1 && a2 == arg2 && a3 == arg3 end mock.foo arg1, arg2, arg3 assert_mock mock end def test_mock_block_is_passed_function_block mock = Minitest::Mock.new block = proc { "bar" } mock.expect :foo, nil do |arg, &blk| arg == "foo" && blk == block end mock.foo "foo", &block assert_mock mock end def test_verify_fails_when_mock_block_returns_false mock = Minitest::Mock.new mock.expect :foo, nil do false end e = assert_raises(MockExpectationError) { mock.foo } exp = "mocked method :foo failed block w/ []" assert_equal exp, e.message end def test_mock_block_throws_if_args_passed mock = Minitest::Mock.new e = assert_raises(ArgumentError) do mock.expect :foo, nil, [:a, :b, :c] do true end end exp = "args ignored when block given" assert_equal exp, e.message end def test_mock_returns_retval_when_called_with_block mock = Minitest::Mock.new mock.expect(:foo, 32) do true end rs = mock.foo assert_equal rs, 32 end def util_verify_bad exp e = assert_raises MockExpectationError do @mock.verify end assert_equal exp, e.message end def test_mock_called_via_send mock = Minitest::Mock.new mock.expect(:foo, true) mock.send :foo assert_mock mock end def test_mock_called_via___send__ mock = Minitest::Mock.new mock.expect(:foo, true) mock.__send__ :foo assert_mock mock end def test_mock_called_via_send_with_args mock = Minitest::Mock.new mock.expect(:foo, true, [1, 2, 3]) mock.send(:foo, 1, 2, 3) assert_mock mock end end require "minitest/metametameta" class TestMinitestStub < Minitest::Test # Do not parallelize since we're calling stub on class methods def setup super Minitest::Test.reset @tc = Minitest::Test.new "fake tc" @assertion_count = 1 end def teardown super assert_equal @assertion_count, @tc.assertions if self.passed? end class Time def self.now 24 end end def assert_stub val_or_callable @assertion_count += 1 t = Time.now.to_i Time.stub :now, val_or_callable do @tc.assert_equal 42, Time.now end @tc.assert_operator Time.now.to_i, :>=, t end def test_stub_private_module_method @assertion_count += 1 t0 = Time.now self.stub :sleep, nil do @tc.assert_nil sleep(10) end @tc.assert_operator Time.now - t0, :<=, 1 end def test_stub_private_module_method_indirect @assertion_count += 1 fail_clapper = Class.new do def fail_clap raise :clap end end.new fail_clapper.stub :raise, nil do |safe_clapper| @tc.assert_equal :clap, safe_clapper.fail_clap # either form works @tc.assert_equal :clap, fail_clapper.fail_clap # yay closures end end def test_stub_public_module_method Math.stub :log10, :stubbed do @tc.assert_equal :stubbed, Math.log10(1000) end end def test_stub_value assert_stub 42 end def test_stub_block assert_stub lambda { 42 } end def test_stub_block_args @assertion_count += 1 t = Time.now.to_i Time.stub :now, lambda { |n| n * 2 } do @tc.assert_equal 42, Time.now(21) end @tc.assert_operator Time.now.to_i, :>=, t end def test_stub_callable obj = Object.new def obj.call 42 end assert_stub obj end def test_stub_yield_self obj = "foo" val = obj.stub :to_s, "bar" do |s| s.to_s end @tc.assert_equal "bar", val end def test_dynamic_method @assertion_count = 2 dynamic = Class.new do def self.respond_to? meth meth == :found end def self.method_missing meth, *args, &block if meth == :found false else super end end end val = dynamic.stub(:found, true) do |s| s.found end @tc.assert_equal true, val @tc.assert_equal false, dynamic.found end def test_stub_NameError e = @tc.assert_raises NameError do Time.stub :nope_nope_nope, 42 do # do nothing end end exp = /undefined method `nope_nope_nope' for( class)? `#{self.class}::Time'/ assert_match exp, e.message end def test_mock_with_yield mock = Minitest::Mock.new mock.expect(:write, true) do true end rs = nil File.stub :open, true, mock do File.open "foo.txt", "r" do |f| rs = f.write end end @tc.assert_equal true, rs end alias test_stub_value__old test_stub_value # TODO: remove/rename ## Permutation Sets: # [:value, :lambda] # [:*, :block, :block_call] # [:**, :block_args] # # Where: # # :value = a normal value # :lambda = callable or lambda # :* = no block # :block = normal block # :block_call = :lambda invokes the block (N/A for :value) # :** = no args # :args = args passed to stub ## Permutations # [:call, :*, :**] =>5 callable+block FIX: CALL BOTH (bug) # [:call, :*, :**] =>6 callable # [:lambda, :*, :**] => lambda result # [:lambda, :*, :args] => lambda result NO ARGS # [:lambda, :block, :**] =>5 lambda result FIX: CALL BOTH (bug) # [:lambda, :block, :**] =>6 lambda result # [:lambda, :block, :args] =>5 lambda result FIX: CALL BOTH (bug) # [:lambda, :block, :args] =>6 lambda result # [:lambda, :block, :args] =>7 raise ArgumentError # [:lambda, :block_call, :**] =>5 lambda FIX: BUG!-not passed block to lambda # [:lambda, :block_call, :**] =>6 lambda+block result # [:lambda, :block_call, :args] =>5 lambda FIX: BUG!-not passed block to lambda # [:lambda, :block_call, :args] =>6 lambda+block result # [:value, :*, :**] => value # [:value, :*, :args] => value, ignore args # [:value, :block, :**] =>5 value, call block # [:value, :block, :**] =>6 value # [:value, :block, :args] =>5 value, call block w/ args # [:value, :block, :args] =>6 value, call block w/ args, deprecated # [:value, :block, :args] =>7 raise ArgumentError # [:value, :block_call, :**] => N/A # [:value, :block_call, :args] => N/A class Bar def call puts "hi" end end class Foo def self.blocking yield end end class Thingy def self.identity arg arg end end def test_stub_callable_block_5 # from tenderlove @assertion_count += 1 Foo.stub5 :blocking, Bar.new do @tc.assert_output "hi\n", "" do Foo.blocking do @tc.flunk "shouldn't ever hit this" end end end end def test_stub_callable_block_6 # from tenderlove skip_stub6 @assertion_count += 1 Foo.stub6 :blocking, Bar.new do @tc.assert_output "hi\n", "" do Foo.blocking do @tc.flunk "shouldn't ever hit this" end end end end def test_stub_lambda Thread.stub :new, lambda { 21+21 } do @tc.assert_equal 42, Thread.new end end def test_stub_lambda_args Thread.stub :new, lambda { 21+21 }, :wtf do @tc.assert_equal 42, Thread.new end end def test_stub_lambda_block_5 Thread.stub5 :new, lambda { 21+21 } do result = Thread.new do @tc.flunk "shouldn't ever hit this" end @tc.assert_equal 42, result end end def test_stub_lambda_block_6 skip_stub6 Thread.stub6 :new, lambda { 21+21 } do result = Thread.new do @tc.flunk "shouldn't ever hit this" end @tc.assert_equal 42, result end end def test_stub_lambda_block_args_5 @assertion_count += 1 Thingy.stub5 :identity, lambda { |y| @tc.assert_equal :nope, y; 21+21 }, :WTF? do result = Thingy.identity :nope do |x| @tc.flunk "shouldn't reach this" end @tc.assert_equal 42, result end end def test_stub_lambda_block_args_6 skip_stub6 @assertion_count += 1 Thingy.stub6 :identity, lambda { |y| @tc.assert_equal :nope, y; 21+21 }, :WTF? do result = Thingy.identity :nope do |x| @tc.flunk "shouldn't reach this" end @tc.assert_equal 42, result end end def test_stub_lambda_block_args_6_2 skip_stub6 @tc.assert_raises ArgumentError do Thingy.stub6_2 :identity, lambda { |y| :__not_run__ }, :WTF? do # doesn't matter end end end def test_stub_lambda_block_call_5 @assertion_count += 1 rs = nil io = StringIO.new "", "w" File.stub5 :open, lambda { |p, m, &blk| blk and blk.call io } do File.open "foo.txt", "r" do |f| rs = f && f.write("woot") end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_lambda_block_call_6 skip_stub6 @assertion_count += 1 rs = nil io = StringIO.new "", "w" File.stub6 :open, lambda { |p, m, &blk| blk.call io } do File.open "foo.txt", "r" do |f| rs = f.write("woot") end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_lambda_block_call_args_5 @assertion_count += 1 rs = nil io = StringIO.new "", "w" File.stub5(:open, lambda { |p, m, &blk| blk and blk.call io }, :WTF?) do File.open "foo.txt", "r" do |f| rs = f.write("woot") end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_lambda_block_call_args_6 skip_stub6 @assertion_count += 1 rs = nil io = StringIO.new "", "w" File.stub6(:open, lambda { |p, m, &blk| blk.call io }, :WTF?) do File.open "foo.txt", "r" do |f| rs = f.write("woot") end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_lambda_block_call_args_6_2 skip_stub6 @assertion_count += 2 rs = nil io = StringIO.new "", "w" @tc.assert_raises ArgumentError do File.stub6_2(:open, lambda { |p, m, &blk| blk.call io }, :WTF?) do File.open "foo.txt", "r" do |f| rs = f.write("woot") end end end @tc.assert_nil rs @tc.assert_equal "", io.string end def test_stub_value Thread.stub :new, 42 do result = Thread.new @tc.assert_equal 42, result end end def test_stub_value_args Thread.stub :new, 42, :WTF? do result = Thread.new @tc.assert_equal 42, result end end def test_stub_value_block_5 @assertion_count += 1 Thread.stub5 :new, 42 do result = Thread.new do @tc.assert true end @tc.assert_equal 42, result end end def test_stub_value_block_6 skip_stub6 Thread.stub6 :new, 42 do result = Thread.new do @tc.flunk "shouldn't hit this" end @tc.assert_equal 42, result end end def test_stub_value_block_args_5 @assertion_count += 2 rs = nil io = StringIO.new "", "w" File.stub5 :open, :value, io do result = File.open "foo.txt", "r" do |f| rs = f.write("woot") end @tc.assert_equal :value, result end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_value_block_args_5__break_if_not_passed e = @tc.assert_raises NoMethodError do File.stub5 :open, :return_value do # intentionally bad setup w/ no args File.open "foo.txt", "r" do |f| f.write "woot" end end end exp = "undefined method `write' for nil:NilClass" assert_equal exp, e.message end def test_stub_value_block_args_6 skip_stub6 @assertion_count += 2 rs = nil io = StringIO.new "", "w" assert_deprecated do File.stub6 :open, :value, io do result = File.open "foo.txt", "r" do |f| rs = f.write("woot") end @tc.assert_equal :value, result end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_value_block_args_6_2 skip_stub6 @assertion_count += 2 rs = nil io = StringIO.new "", "w" @tc.assert_raises ArgumentError do File.stub6_2 :open, :value, io do result = File.open "foo.txt", "r" do |f| @tc.flunk "shouldn't hit this" end @tc.assert_equal :value, result end end @tc.assert_nil rs @tc.assert_equal "", io.string end def assert_deprecated re = /deprecated/ assert_output "", re do yield end end def skip_stub6 skip "not yet" unless STUB6 end end STUB6 = ENV["STUB6"] if STUB6 then require "minitest/mock6" if STUB6 else class Object alias stub5 stub alias stub6 stub end end PK ]O 2gems/minitest-5.13.0/test/minitest/metametameta.rbnu[require "tempfile" require "stringio" require "minitest/autorun" class Minitest::Test def clean s s.gsub(/^ {6}/, "") end end class FakeNamedTest < Minitest::Test @@count = 0 def self.name @fake_name ||= begin @@count += 1 "FakeNamedTest%02d" % @@count end end end module MyModule; end class AnError < StandardError; include MyModule; end class MetaMetaMetaTestCase < Minitest::Test attr_accessor :reporter, :output, :tu def with_stderr err old = $stderr $stderr = err yield ensure $stderr = old end def run_tu_with_fresh_reporter flags = %w[--seed 42] options = Minitest.process_args flags @output = StringIO.new("".encode('UTF-8')) self.reporter = Minitest::CompositeReporter.new reporter << Minitest::SummaryReporter.new(@output, options) reporter << Minitest::ProgressReporter.new(@output, options) with_stderr @output do reporter.start yield(reporter) if block_given? @tus ||= [@tu] @tus.each do |tu| Minitest::Runnable.runnables.delete tu tu.run reporter, options end reporter.report end end def first_reporter reporter.reporters.first end def assert_report expected, flags = %w[--seed 42], &block header = clean <<-EOM Run options: #{flags.map { |s| s =~ /\|/ ? s.inspect : s }.join " "} # Running: EOM run_tu_with_fresh_reporter flags, &block output = normalize_output @output.string.dup assert_equal header + expected, output end def normalize_output output output.sub!(/Finished in .*/, "Finished in 0.00") output.sub!(/Loaded suite .*/, "Loaded suite blah") output.gsub!(/FakeNamedTest\d+/, "FakeNamedTestXX") output.gsub!(/ = \d+.\d\d s = /, " = 0.00 s = ") output.gsub!(/0x[A-Fa-f0-9]+/, "0xXXX") output.gsub!(/ +$/, "") if windows? then output.gsub!(/\[(?:[A-Za-z]:)?[^\]:]+:\d+\]/, "[FILE:LINE]") output.gsub!(/^(\s+)(?:[A-Za-z]:)?[^:]+:\d+:in/, '\1FILE:LINE:in') else output.gsub!(/\[[^\]:]+:\d+\]/, "[FILE:LINE]") output.gsub!(/^(\s+)[^:]+:\d+:in/, '\1FILE:LINE:in') end output.gsub!(/( at )[^:]+:\d+/, '\1[FILE:LINE]') output end def restore_env old_value = ENV["MT_NO_SKIP_MSG"] ENV.delete "MT_NO_SKIP_MSG" yield ensure ENV["MT_NO_SKIP_MSG"] = old_value end def setup super srand 42 Minitest::Test.reset @tu = nil end end PK ]8*k*k8gems/minitest-5.13.0/test/minitest/test_minitest_spec.rbnu[# encoding: utf-8 require "minitest/metametameta" require "stringio" class MiniSpecA < Minitest::Spec; end class MiniSpecB < Minitest::Test; extend Minitest::Spec::DSL; end class MiniSpecC < MiniSpecB; end class NamedExampleA < MiniSpecA; end class NamedExampleB < MiniSpecB; end class NamedExampleC < MiniSpecC; end class ExampleA; end class ExampleB < ExampleA; end describe Minitest::Spec do # helps to deal with 2.4 deprecation of Fixnum for Integer Int = 1.class # do not parallelize this suite... it just can"t handle it. def assert_triggered expected = "blah", klass = Minitest::Assertion @assertion_count += 1 e = assert_raises(klass) do yield end msg = e.message.sub(/(---Backtrace---).*/m, '\1') msg.gsub!(/\(oid=[-0-9]+\)/, "(oid=N)") msg.gsub!(/(\d\.\d{6})\d+/, '\1xxx') # normalize: ruby version, impl, platform msg.gsub!(/:0x[Xa-fA-F0-9]{4,}[ @].+?>/, ":0xXXXXXX@PATH>") if expected @assertion_count += 1 case expected when String then assert_equal expected, msg when Regexp then @assertion_count += 1 assert_match expected, msg else flunk "Unknown: #{expected.inspect}" end end end before do @assertion_count = 4 end after do _(self.assertions).must_equal @assertion_count if passed? and not skipped? end it "needs to be able to catch a Minitest::Assertion exception" do @assertion_count = 1 assert_triggered "Expected 1 to not be equal to 1." do _(1).wont_equal 1 end end it "needs to check for file existence" do @assertion_count = 3 _(_(__FILE__).path_must_exist).must_equal true assert_triggered "Expected path 'blah' to exist." do _("blah").path_must_exist end end it "needs to check for file non-existence" do @assertion_count = 3 _(_("blah").path_wont_exist).must_equal false assert_triggered "Expected path '#{__FILE__}' to not exist." do _(__FILE__).path_wont_exist end end it "needs to be sensible about must_include order" do @assertion_count += 3 # must_include is 2 assertions _(_([1, 2, 3]).must_include(2)).must_equal true assert_triggered "Expected [1, 2, 3] to include 5." do _([1, 2, 3]).must_include 5 end assert_triggered "msg.\nExpected [1, 2, 3] to include 5." do _([1, 2, 3]).must_include 5, "msg" end end it "needs to be sensible about wont_include order" do @assertion_count += 3 # wont_include is 2 assertions _(_([1, 2, 3]).wont_include(5)).must_equal false assert_triggered "Expected [1, 2, 3] to not include 2." do _([1, 2, 3]).wont_include 2 end assert_triggered "msg.\nExpected [1, 2, 3] to not include 2." do _([1, 2, 3]).wont_include 2, "msg" end end it "needs to catch an expected exception" do @assertion_count = 2 expect { raise "blah" }.must_raise RuntimeError expect { raise Minitest::Assertion }.must_raise Minitest::Assertion end it "needs to catch an unexpected exception" do @assertion_count -= 2 # no positive msg = <<-EOM.gsub(/^ {6}/, "").chomp [RuntimeError] exception expected, not Class: Message: <"woot"> ---Backtrace--- EOM assert_triggered msg do expect { raise StandardError, "woot" }.must_raise RuntimeError end assert_triggered "msg.\n#{msg}" do expect { raise StandardError, "woot" }.must_raise RuntimeError, "msg" end end it "needs to ensure silence" do @assertion_count -= 1 # no msg @assertion_count += 2 # assert_output is 2 assertions _(expect {}.must_be_silent).must_equal true assert_triggered "In stdout.\nExpected: \"\"\n Actual: \"xxx\"" do expect { print "xxx" }.must_be_silent end end it "needs to have all methods named well" do skip "N/A" if ENV["MT_NO_EXPECTATIONS"] @assertion_count = 2 methods = Minitest::Expectations.public_instance_methods.grep(/must|wont/) methods.map!(&:to_s) if Symbol === methods.first musts, wonts = methods.sort.partition { |m| m =~ /must/ } expected_musts = %w[must_be must_be_close_to must_be_empty must_be_instance_of must_be_kind_of must_be_nil must_be_same_as must_be_silent must_be_within_delta must_be_within_epsilon must_equal must_include must_match must_output must_raise must_respond_to must_throw path_must_exist] bad = %w[not raise throw send output be_silent] expected_wonts = expected_musts.map { |m| m.sub(/must/, "wont") }.sort expected_wonts.reject! { |m| m =~ /wont_#{Regexp.union(*bad)}/ } _(musts).must_equal expected_musts _(wonts).must_equal expected_wonts end it "needs to raise if an expected exception is not raised" do @assertion_count -= 2 # no positive test assert_triggered "RuntimeError expected but nothing was raised." do expect { 42 }.must_raise RuntimeError end assert_triggered "msg.\nRuntimeError expected but nothing was raised." do expect { 42 }.must_raise RuntimeError, "msg" end end it "needs to verify binary messages" do _(_(42).wont_be(:<, 24)).must_equal false assert_triggered "Expected 24 to not be < 42." do _(24).wont_be :<, 42 end assert_triggered "msg.\nExpected 24 to not be < 42." do _(24).wont_be :<, 42, "msg" end end it "needs to verify emptyness" do @assertion_count += 3 # empty is 2 assertions _(_([]).must_be_empty).must_equal true assert_triggered "Expected [42] to be empty." do _([42]).must_be_empty end assert_triggered "msg.\nExpected [42] to be empty." do _([42]).must_be_empty "msg" end end it "needs to verify equality" do @assertion_count += 1 _(_(6 * 7).must_equal(42)).must_equal true assert_triggered "Expected: 42\n Actual: 54" do _(6 * 9).must_equal 42 end assert_triggered "msg.\nExpected: 42\n Actual: 54" do _(6 * 9).must_equal 42, "msg" end assert_triggered(/^-42\n\+#\n/) do _(proc { 42 }).must_equal 42 # proc isn't called, so expectation fails end end it "needs to warn on equality with nil" do @assertion_count += 1 # extra test out, err = capture_io do _(_(nil).must_equal(nil)).must_equal true end exp = "DEPRECATED: Use assert_nil if expecting nil from #{__FILE__}:#{__LINE__-3}. " \ "This will fail in Minitest 6.\n" exp = "" if $-w.nil? assert_empty out assert_equal exp, err end it "needs to verify floats outside a delta" do @assertion_count += 1 # extra test _(_(24).wont_be_close_to(42)).must_equal false assert_triggered "Expected |42 - 42.0| (0.0) to not be <= 0.001." do _(6 * 7.0).wont_be_close_to 42 end x = "1.0e-05" assert_triggered "Expected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_close_to 42, 0.00001 end assert_triggered "msg.\nExpected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_close_to 42, 0.00001, "msg" end end it "needs to verify floats outside an epsilon" do @assertion_count += 1 # extra test _(_(24).wont_be_within_epsilon(42)).must_equal false x = "0.042" assert_triggered "Expected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_within_epsilon 42 end x = "0.00042" assert_triggered "Expected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_within_epsilon 42, 0.00001 end assert_triggered "msg.\nExpected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_within_epsilon 42, 0.00001, "msg" end end it "needs to verify floats within a delta" do @assertion_count += 1 # extra test _(_(6.0 * 7).must_be_close_to(42.0)).must_equal true assert_triggered "Expected |0.0 - 0.01| (0.01) to be <= 0.001." do _(1.0 / 100).must_be_close_to 0.0 end x = "1.0e-06" assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}." do _(1.0 / 1000).must_be_close_to 0.0, 0.000001 end assert_triggered "msg.\nExpected |0.0 - 0.001| (0.001) to be <= #{x}." do _(1.0 / 1000).must_be_close_to 0.0, 0.000001, "msg" end end it "needs to verify floats within an epsilon" do @assertion_count += 1 # extra test _(_(6.0 * 7).must_be_within_epsilon(42.0)).must_equal true assert_triggered "Expected |0.0 - 0.01| (0.01) to be <= 0.0." do _(1.0 / 100).must_be_within_epsilon 0.0 end assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= 0.0." do _(1.0 / 1000).must_be_within_epsilon 0.0, 0.000001 end assert_triggered "msg.\nExpected |0.0 - 0.001| (0.001) to be <= 0.0." do _(1.0 / 1000).must_be_within_epsilon 0.0, 0.000001, "msg" end end it "needs to verify identity" do _(_(1).must_be_same_as(1)).must_equal true assert_triggered "Expected 1 (oid=N) to be the same as 2 (oid=N)." do _(1).must_be_same_as 2 end assert_triggered "msg.\nExpected 1 (oid=N) to be the same as 2 (oid=N)." do _(1).must_be_same_as 2, "msg" end end it "needs to verify inequality" do @assertion_count += 2 _(_(42).wont_equal(6 * 9)).must_equal false _(_(proc {}).wont_equal(42)).must_equal false assert_triggered "Expected 1 to not be equal to 1." do _(1).wont_equal 1 end assert_triggered "msg.\nExpected 1 to not be equal to 1." do _(1).wont_equal 1, "msg" end end it "needs to verify instances of a class" do _(_(42).wont_be_instance_of(String)).must_equal false assert_triggered "Expected 42 to not be a kind of #{Int.name}." do _(42).wont_be_kind_of Int end assert_triggered "msg.\nExpected 42 to not be an instance of #{Int.name}." do _(42).wont_be_instance_of Int, "msg" end end it "needs to verify kinds of a class" do @assertion_count += 2 _(_(42).wont_be_kind_of(String)).must_equal false _(_(proc {}).wont_be_kind_of(String)).must_equal false assert_triggered "Expected 42 to not be a kind of #{Int.name}." do _(42).wont_be_kind_of Int end assert_triggered "msg.\nExpected 42 to not be a kind of #{Int.name}." do _(42).wont_be_kind_of Int, "msg" end end it "needs to verify kinds of objects" do @assertion_count += 3 # extra test _(_(6 * 7).must_be_kind_of(Int)).must_equal true _(_(6 * 7).must_be_kind_of(Numeric)).must_equal true assert_triggered "Expected 42 to be a kind of String, not #{Int.name}." do _(6 * 7).must_be_kind_of String end assert_triggered "msg.\nExpected 42 to be a kind of String, not #{Int.name}." do _(6 * 7).must_be_kind_of String, "msg" end exp = "Expected # to be a kind of String, not Proc." assert_triggered exp do _(proc {}).must_be_kind_of String end end it "needs to verify mismatch" do @assertion_count += 3 # match is 2 _(_("blah").wont_match(/\d+/)).must_equal false assert_triggered "Expected /\\w+/ to not match \"blah\"." do _("blah").wont_match(/\w+/) end assert_triggered "msg.\nExpected /\\w+/ to not match \"blah\"." do _("blah").wont_match(/\w+/, "msg") end end it "needs to verify nil" do _(_(nil).must_be_nil).must_equal true assert_triggered "Expected 42 to be nil." do _(42).must_be_nil end assert_triggered "msg.\nExpected 42 to be nil." do _(42).must_be_nil "msg" end end it "needs to verify non-emptyness" do @assertion_count += 3 # empty is 2 assertions _(_(["some item"]).wont_be_empty).must_equal false assert_triggered "Expected [] to not be empty." do _([]).wont_be_empty end assert_triggered "msg.\nExpected [] to not be empty." do _([]).wont_be_empty "msg" end end it "needs to verify non-identity" do _(_(1).wont_be_same_as(2)).must_equal false assert_triggered "Expected 1 (oid=N) to not be the same as 1 (oid=N)." do _(1).wont_be_same_as 1 end assert_triggered "msg.\nExpected 1 (oid=N) to not be the same as 1 (oid=N)." do _(1).wont_be_same_as 1, "msg" end end it "needs to verify non-nil" do _(_(42).wont_be_nil).must_equal false assert_triggered "Expected nil to not be nil." do _(nil).wont_be_nil end assert_triggered "msg.\nExpected nil to not be nil." do _(nil).wont_be_nil "msg" end end it "needs to verify objects not responding to a message" do _(_("").wont_respond_to(:woot!)).must_equal false assert_triggered "Expected \"\" to not respond to to_s." do _("").wont_respond_to :to_s end assert_triggered "msg.\nExpected \"\" to not respond to to_s." do _("").wont_respond_to :to_s, "msg" end end it "needs to verify output in stderr" do @assertion_count -= 1 # no msg _(expect { $stderr.print "blah" }.must_output(nil, "blah")).must_equal true assert_triggered "In stderr.\nExpected: \"blah\"\n Actual: \"xxx\"" do expect { $stderr.print "xxx" }.must_output(nil, "blah") end end it "needs to verify output in stdout" do @assertion_count -= 1 # no msg _(expect { print "blah" }.must_output("blah")).must_equal true assert_triggered "In stdout.\nExpected: \"blah\"\n Actual: \"xxx\"" do expect { print "xxx" }.must_output("blah") end end it "needs to verify regexp matches" do @assertion_count += 3 # must_match is 2 assertions _(_("blah").must_match(/\w+/)).must_equal true assert_triggered "Expected /\\d+/ to match \"blah\"." do _("blah").must_match(/\d+/) end assert_triggered "msg.\nExpected /\\d+/ to match \"blah\"." do _("blah").must_match(/\d+/, "msg") end end describe "expect" do before do @assertion_count -= 3 end it "can use expect" do _(1 + 1).must_equal 2 end it "can use expect with a lambda" do _ { raise "blah" }.must_raise RuntimeError end it "can use expect in a thread" do Thread.new { _(1 + 1).must_equal 2 }.join end it "can NOT use must_equal in a thread. It must use expect in a thread" do skip "N/A" if ENV["MT_NO_EXPECTATIONS"] assert_raises RuntimeError do capture_io do Thread.new { (1 + 1).must_equal 2 }.join end end end it "fails gracefully when expectation used outside of `it`" do skip "N/A" if ENV["MT_NO_EXPECTATIONS"] @assertion_count += 1 e = assert_raises RuntimeError do capture_io do Thread.new { # forces ctx to be nil describe("woot") do (1 + 1).must_equal 2 end }.join end end assert_equal "Calling #must_equal outside of test.", e.message end it "deprecates expectation used without _" do skip "N/A" if ENV["MT_NO_EXPECTATIONS"] @assertion_count += 3 exp = /DEPRECATED: global use of must_equal from/ assert_output "", exp do (1 + 1).must_equal 2 end end end it "needs to verify throw" do @assertion_count += 2 # 2 extra tests _(expect { throw :blah }.must_throw(:blah)).must_equal true assert_triggered "Expected :blah to have been thrown." do expect {}.must_throw :blah end assert_triggered "Expected :blah to have been thrown, not :xxx." do expect { throw :xxx }.must_throw :blah end assert_triggered "msg.\nExpected :blah to have been thrown." do expect {}.must_throw :blah, "msg" end assert_triggered "msg.\nExpected :blah to have been thrown, not :xxx." do expect { throw :xxx }.must_throw :blah, "msg" end end it "needs to verify types of objects" do _(_(6 * 7).must_be_instance_of(Int)).must_equal true exp = "Expected 42 to be an instance of String, not #{Int.name}." assert_triggered exp do _(6 * 7).must_be_instance_of String end assert_triggered "msg.\n#{exp}" do _(6 * 7).must_be_instance_of String, "msg" end end it "needs to verify using any (negative) predicate" do @assertion_count -= 1 # doesn"t take a message _(_("blah").wont_be(:empty?)).must_equal false assert_triggered "Expected \"\" to not be empty?." do _("").wont_be :empty? end end it "needs to verify using any binary operator" do @assertion_count -= 1 # no msg _(_(41).must_be(:<, 42)).must_equal true assert_triggered "Expected 42 to be < 41." do _(42).must_be(:<, 41) end end it "needs to verify using any predicate" do @assertion_count -= 1 # no msg _(_("").must_be(:empty?)).must_equal true assert_triggered "Expected \"blah\" to be empty?." do _("blah").must_be :empty? end end it "needs to verify using respond_to" do _(_(42).must_respond_to(:+)).must_equal true assert_triggered "Expected 42 (#{Int.name}) to respond to #clear." do _(42).must_respond_to :clear end assert_triggered "msg.\nExpected 42 (#{Int.name}) to respond to #clear." do _(42).must_respond_to :clear, "msg" end end end describe Minitest::Spec, :let do i_suck_and_my_tests_are_order_dependent! def _count $let_count ||= 0 end let :count do $let_count += 1 $let_count end it "is evaluated once per example" do _(_count).must_equal 0 _(count).must_equal 1 _(count).must_equal 1 _(_count).must_equal 1 end it "is REALLY evaluated once per example" do _(_count).must_equal 1 _(count).must_equal 2 _(count).must_equal 2 _(_count).must_equal 2 end it 'raises an error if the name begins with "test"' do expect { self.class.let(:test_value) { true } }.must_raise ArgumentError end it "raises an error if the name shadows a normal instance method" do expect { self.class.let(:message) { true } }.must_raise ArgumentError end it "doesn't raise an error if it is just another let" do v = proc do describe :outer do let(:bar) describe :inner do let(:bar) end end :good end.call _(v).must_equal :good end it "procs come after dont_flip" do p = proc {} assert_respond_to p, :call _(p).must_respond_to :call end end describe Minitest::Spec, :subject do attr_reader :subject_evaluation_count subject do @subject_evaluation_count ||= 0 @subject_evaluation_count += 1 @subject_evaluation_count end it "is evaluated once per example" do _(subject).must_equal 1 _(subject).must_equal 1 _(subject_evaluation_count).must_equal 1 end end class TestMetaStatic < Minitest::Test def test_children Minitest::Spec.children.clear # prevents parallel run y = z = nil x = describe "top-level thingy" do y = describe "first thingy" do end it "top-level-it" do end z = describe "second thingy" do end end assert_equal [x], Minitest::Spec.children assert_equal [y, z], x.children assert_equal [], y.children assert_equal [], z.children end def test_it_wont_remove_existing_child_test_methods Minitest::Spec.children.clear # prevents parallel run inner = nil outer = describe "outer" do inner = describe "inner" do it do assert true end end it do assert true end end assert_equal 1, outer.public_instance_methods.grep(/^test_/).count assert_equal 1, inner.public_instance_methods.grep(/^test_/).count end def test_it_wont_add_test_methods_to_children Minitest::Spec.children.clear # prevents parallel run inner = nil outer = describe "outer" do inner = describe "inner" do end it do assert true end end assert_equal 1, outer.public_instance_methods.grep(/^test_/).count assert_equal 0, inner.public_instance_methods.grep(/^test_/).count end end class TestMeta < MetaMetaMetaTestCase # do not call parallelize_me! here because specs use register_spec_type globally def util_structure y = z = nil before_list = [] after_list = [] x = describe "top-level thingy" do before { before_list << 1 } after { after_list << 1 } it "top-level-it" do end y = describe "inner thingy" do before { before_list << 2 } after { after_list << 2 } it "inner-it" do end z = describe "very inner thingy" do before { before_list << 3 } after { after_list << 3 } it "inner-it" do end it { } # ignore me specify { } # anonymous it end end end return x, y, z, before_list, after_list end def test_register_spec_type original_types = Minitest::Spec::TYPES.dup assert_includes Minitest::Spec::TYPES, [//, Minitest::Spec] Minitest::Spec.register_spec_type(/woot/, TestMeta) p = lambda do |_| true end Minitest::Spec.register_spec_type TestMeta, &p keys = Minitest::Spec::TYPES.map(&:first) assert_includes keys, /woot/ assert_includes keys, p ensure Minitest::Spec::TYPES.replace original_types end def test_spec_type original_types = Minitest::Spec::TYPES.dup Minitest::Spec.register_spec_type(/A$/, MiniSpecA) Minitest::Spec.register_spec_type MiniSpecB do |desc| desc.superclass == ExampleA end Minitest::Spec.register_spec_type MiniSpecC do |_desc, *addl| addl.include? :woot end assert_equal MiniSpecA, Minitest::Spec.spec_type(ExampleA) assert_equal MiniSpecB, Minitest::Spec.spec_type(ExampleB) assert_equal MiniSpecC, Minitest::Spec.spec_type(ExampleB, :woot) ensure Minitest::Spec::TYPES.replace original_types end def test_bug_dsl_expectations spec_class = Class.new MiniSpecB do it "should work" do _(0).must_equal 0 end end test_name = spec_class.instance_methods.sort.grep(/test/).first spec = spec_class.new test_name result = spec.run assert spec.passed? assert result.passed? assert_equal 1, result.assertions end def test_name spec_a = describe ExampleA do; end spec_b = describe ExampleB, :random_method do; end spec_c = describe ExampleB, :random_method, :addl_context do; end assert_equal "ExampleA", spec_a.name assert_equal "ExampleB::random_method", spec_b.name assert_equal "ExampleB::random_method::addl_context", spec_c.name end def test_name2 assert_equal "NamedExampleA", NamedExampleA.name assert_equal "NamedExampleB", NamedExampleB.name assert_equal "NamedExampleC", NamedExampleC.name spec_a = describe ExampleA do; end spec_b = describe ExampleB, :random_method do; end assert_equal "ExampleA", spec_a.name assert_equal "ExampleB::random_method", spec_b.name end def test_structure x, y, z, * = util_structure assert_equal "top-level thingy", x.to_s assert_equal "top-level thingy::inner thingy", y.to_s assert_equal "top-level thingy::inner thingy::very inner thingy", z.to_s assert_equal "top-level thingy", x.desc assert_equal "inner thingy", y.desc assert_equal "very inner thingy", z.desc top_methods = %w[setup teardown test_0001_top-level-it] inner_methods1 = %w[setup teardown test_0001_inner-it] inner_methods2 = inner_methods1 + %w[test_0002_anonymous test_0003_anonymous] assert_equal top_methods, x.instance_methods(false).sort.map(&:to_s) assert_equal inner_methods1, y.instance_methods(false).sort.map(&:to_s) assert_equal inner_methods2, z.instance_methods(false).sort.map(&:to_s) end def test_structure_postfix_it z = nil y = describe "outer" do # NOT here, below the inner-describe! # it "inner-it" do end z = describe "inner" do it "inner-it" do end end # defined AFTER inner describe means we'll try to wipe out the inner-it it "inner-it" do end end assert_equal %w[test_0001_inner-it], y.instance_methods(false).map(&:to_s) assert_equal %w[test_0001_inner-it], z.instance_methods(false).map(&:to_s) end def test_setup_teardown_behavior _, _, z, before_list, after_list = util_structure @tu = z run_tu_with_fresh_reporter size = z.runnable_methods.size assert_equal [1, 2, 3] * size, before_list assert_equal [3, 2, 1] * size, after_list end def test_describe_first_structure x1 = x2 = y = z = nil x = describe "top-level thingy" do y = describe "first thingy" do end x1 = it "top level it" do end x2 = it "не латинские &いった α, β, γ, δ, ε hello!!! world" do end z = describe "second thingy" do end end test_methods = ["test_0001_top level it", "test_0002_не латинские &いった α, β, γ, δ, ε hello!!! world", ].sort assert_equal test_methods, [x1, x2] assert_equal test_methods, x.instance_methods.grep(/^test/).map(&:to_s).sort assert_equal [], y.instance_methods.grep(/^test/) assert_equal [], z.instance_methods.grep(/^test/) end def test_structure_subclasses z = nil x = Class.new Minitest::Spec do def xyz; end end y = Class.new x do z = describe("inner") { } end assert_respond_to x.new(nil), "xyz" assert_respond_to y.new(nil), "xyz" assert_respond_to z.new(nil), "xyz" end end class TestSpecInTestCase < MetaMetaMetaTestCase def setup super Thread.current[:current_spec] = self @tc = self @assertion_count = 2 end def assert_triggered expected, klass = Minitest::Assertion @assertion_count += 1 e = assert_raises klass do yield end msg = e.message.sub(/(---Backtrace---).*/m, "\1") msg.gsub!(/\(oid=[-0-9]+\)/, "(oid=N)") assert_equal expected, msg end def teardown msg = "expected #{@assertion_count} assertions, not #{@tc.assertions}" assert_equal @assertion_count, @tc.assertions, msg end def test_expectation @tc.assert_equal true, _(1).must_equal(1) end def test_expectation_triggered assert_triggered "Expected: 2\n Actual: 1" do _(1).must_equal 2 end end include Minitest::Spec::DSL::InstanceMethods def test_expectation_with_a_message assert_triggered "woot.\nExpected: 2\n Actual: 1" do _(1).must_equal 2, "woot" end end end class ValueMonadTest < Minitest::Test attr_accessor :struct def setup @struct = { :_ => "a", :value => "b", :expect => "c" } def @struct.method_missing k # think openstruct self[k] end end def test_value_monad_method assert_equal "a", struct._ end def test_value_monad_value_alias assert_equal "b", struct.value end def test_value_monad_expect_alias assert_equal "c", struct.expect end end PK ]ފ`o`o gems/minitest-5.13.0/README.rdocnu[= minitest/{test,spec,mock,benchmark} home :: https://github.com/seattlerb/minitest bugs :: https://github.com/seattlerb/minitest/issues rdoc :: http://docs.seattlerb.org/minitest vim :: https://github.com/sunaku/vim-ruby-minitest emacs:: https://github.com/arthurnn/minitest-emacs == DESCRIPTION: minitest provides a complete suite of testing facilities supporting TDD, BDD, mocking, and benchmarking. "I had a class with Jim Weirich on testing last week and we were allowed to choose our testing frameworks. Kirk Haines and I were paired up and we cracked open the code for a few test frameworks... I MUST say that minitest is *very* readable / understandable compared to the 'other two' options we looked at. Nicely done and thank you for helping us keep our mental sanity." -- Wayne E. Seguin minitest/test is a small and incredibly fast unit testing framework. It provides a rich set of assertions to make your tests clean and readable. minitest/spec is a functionally complete spec engine. It hooks onto minitest/test and seamlessly bridges test assertions over to spec expectations. minitest/benchmark is an awesome way to assert the performance of your algorithms in a repeatable manner. Now you can assert that your newb co-worker doesn't replace your linear algorithm with an exponential one! minitest/mock by Steven Baker, is a beautifully tiny mock (and stub) object framework. minitest/pride shows pride in testing and adds coloring to your test output. I guess it is an example of how to write IO pipes too. :P minitest/test is meant to have a clean implementation for language implementors that need a minimal set of methods to bootstrap a working test suite. For example, there is no magic involved for test-case discovery. "Again, I can't praise enough the idea of a testing/specing framework that I can actually read in full in one sitting!" -- Piotr Szotkowski Comparing to rspec: rspec is a testing DSL. minitest is ruby. -- Adam Hawkins, "Bow Before MiniTest" minitest doesn't reinvent anything that ruby already provides, like: classes, modules, inheritance, methods. This means you only have to learn ruby to use minitest and all of your regular OO practices like extract-method refactorings still apply. == FEATURES/PROBLEMS: * minitest/autorun - the easy and explicit way to run all your tests. * minitest/test - a very fast, simple, and clean test system. * minitest/spec - a very fast, simple, and clean spec system. * minitest/mock - a simple and clean mock/stub system. * minitest/benchmark - an awesome way to assert your algorithm's performance. * minitest/pride - show your pride in testing! * Incredibly small and fast runner, but no bells and whistles. * Written by squishy human beings. Software can never be perfect. We will all eventually die. == RATIONALE: See design_rationale.rb to see how specs and tests work in minitest. == SYNOPSIS: Given that you'd like to test the following class: class Meme def i_can_has_cheezburger? "OHAI!" end def will_it_blend? "YES!" end end === Unit tests Define your tests as methods beginning with +test_+. require "minitest/autorun" class TestMeme < Minitest::Test def setup @meme = Meme.new end def test_that_kitty_can_eat assert_equal "OHAI!", @meme.i_can_has_cheezburger? end def test_that_it_will_not_blend refute_match /^no/i, @meme.will_it_blend? end def test_that_will_be_skipped skip "test this later" end end === Specs require "minitest/autorun" describe Meme do before do @meme = Meme.new end describe "when asked about cheeseburgers" do it "must respond positively" do _(@meme.i_can_has_cheezburger?).must_equal "OHAI!" end end describe "when asked about blending possibilities" do it "won't say no" do _(@meme.will_it_blend?).wont_match /^no/i end end end For matchers support check out: * https://github.com/wojtekmach/minitest-matchers * https://github.com/rmm5t/minitest-matchers_vaccine === Benchmarks Add benchmarks to your tests. # optionally run benchmarks, good for CI-only work! require "minitest/benchmark" if ENV["BENCH"] class TestMeme < Minitest::Benchmark # Override self.bench_range or default range is [1, 10, 100, 1_000, 10_000] def bench_my_algorithm assert_performance_linear 0.9999 do |n| # n is a range value @obj.my_algorithm(n) end end end Or add them to your specs. If you make benchmarks optional, you'll need to wrap your benchmarks in a conditional since the methods won't be defined. In minitest 5, the describe name needs to match /Bench(mark)?$/. describe "Meme Benchmark" do if ENV["BENCH"] then bench_performance_linear "my_algorithm", 0.9999 do |n| 100.times do @obj.my_algorithm(n) end end end end outputs something like: # Running benchmarks: TestBlah 100 1000 10000 bench_my_algorithm 0.006167 0.079279 0.786993 bench_other_algorithm 0.061679 0.792797 7.869932 Output is tab-delimited to make it easy to paste into a spreadsheet. === Mocks Mocks and stubs defined using terminology by Fowler & Meszaros at http://www.martinfowler.com/bliki/TestDouble.html: "Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting." class MemeAsker def initialize(meme) @meme = meme end def ask(question) method = question.tr(" ", "_") + "?" @meme.__send__(method) end end require "minitest/autorun" describe MemeAsker, :ask do describe "when passed an unpunctuated question" do it "should invoke the appropriate predicate method on the meme" do @meme = Minitest::Mock.new @meme_asker = MemeAsker.new @meme @meme.expect :will_it_blend?, :return_value @meme_asker.ask "will it blend" @meme.verify end end end ==== Multi-threading and Mocks Minitest mocks do not support multi-threading. If it works, fine, if it doesn't you can use regular ruby patterns and facilities like local variables. Here's an example of asserting that code inside a thread is run: def test_called_inside_thread called = false pr = Proc.new { called = true } thread = Thread.new(&pr) thread.join assert called, "proc not called" end === Stubs Mocks and stubs are defined using terminology by Fowler & Meszaros at http://www.martinfowler.com/bliki/TestDouble.html: "Stubs provide canned answers to calls made during the test". Minitest's stub method overrides a single method for the duration of the block. def test_stale_eh obj_under_test = Something.new refute obj_under_test.stale? Time.stub :now, Time.at(0) do # stub goes away once the block is done assert obj_under_test.stale? end end A note on stubbing: In order to stub a method, the method must actually exist prior to stubbing. Use a singleton method to create a new non-existing method: def obj_under_test.fake_method ... end === Running Your Tests Ideally, you'll use a rake task to run your tests, either piecemeal or all at once. Both rake and rails ship with rake tasks for running your tests. BUT! You don't have to: % ruby -Ilib:test test/minitest/test_minitest_test.rb Run options: --seed 37685 # Running: ...................................................................... (etc) Finished in 0.107130s, 1446.8403 runs/s, 2959.0217 assertions/s. 155 runs, 317 assertions, 0 failures, 0 errors, 0 skips There are runtime options available, both from minitest itself, and also provided via plugins. To see them, simply run with +--help+: % ruby -Ilib:test test/minitest/test_minitest_test.rb --help minitest options: -h, --help Display this help. -s, --seed SEED Sets random seed. Also via env. Eg: SEED=n rake -v, --verbose Verbose. Show progress processing files. -n, --name PATTERN Filter run on /regexp/ or string. -e, --exclude PATTERN Exclude /regexp/ or string from run. Known extensions: pride, autotest -p, --pride Pride. Show your testing pride! -a, --autotest Connect to autotest server. You can set up a rake task to run all your tests by adding this to your Rakefile: require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList["test/**/test_*.rb"] end task :default => :test == Writing Extensions To define a plugin, add a file named minitest/XXX_plugin.rb to your project/gem. That file must be discoverable via ruby's LOAD_PATH (via rubygems or otherwise). Minitest will find and require that file using Gem.find_files. It will then try to call +plugin_XXX_init+ during startup. The option processor will also try to call +plugin_XXX_options+ passing the OptionParser instance and the current options hash. This lets you register your own command-line options. Here's a totally bogus example: # minitest/bogus_plugin.rb: module Minitest def self.plugin_bogus_options(opts, options) opts.on "--myci", "Report results to my CI" do options[:myci] = true options[:myci_addr] = get_myci_addr options[:myci_port] = get_myci_port end end def self.plugin_bogus_init(options) self.reporter << MyCI.new(options) if options[:myci] end end === Adding custom reporters Minitest uses composite reporter to output test results using multiple reporter instances. You can add new reporters to the composite during the init_plugins phase. As we saw in +plugin_bogus_init+ above, you simply add your reporter instance to the composite via <<. +AbstractReporter+ defines the API for reporters. You may subclass it and override any method you want to achieve your desired behavior. start :: Called when the run has started. record :: Called for each result, passed or otherwise. report :: Called at the end of the run. passed? :: Called to see if you detected any problems. Using our example above, here is how we might implement MyCI: # minitest/bogus_plugin.rb module Minitest class MyCI < AbstractReporter attr_accessor :results, :addr, :port def initialize options self.results = [] self.addr = options[:myci_addr] self.port = options[:myci_port] end def record result self.results << result end def report CI.connect(addr, port).send_results self.results end end # code from above... end == FAQ === How to test SimpleDelegates? The following implementation and test: class Worker < SimpleDelegator def work end end describe Worker do before do @worker = Worker.new(Object.new) end it "must respond to work" do _(@worker).must_respond_to :work end end outputs a failure: 1) Failure: Worker#test_0001_must respond to work [bug11.rb:16]: Expected # (Object) to respond to #work. Worker is a SimpleDelegate which in 1.9+ is a subclass of BasicObject. Expectations are put on Object (one level down) so the Worker (SimpleDelegate) hits +method_missing+ and delegates down to the +Object.new+ instance. That object doesn't respond to work so the test fails. You can bypass SimpleDelegate#method_missing by extending the worker with Minitest::Expectations. You can either do that in your setup at the instance level, like: before do @worker = Worker.new(Object.new) @worker.extend Minitest::Expectations end or you can extend the Worker class (within the test file!), like: class Worker include ::Minitest::Expectations end === How to share code across test classes? Use a module. That's exactly what they're for: module UsefulStuff def useful_method # ... end end describe Blah do include UsefulStuff def test_whatever # useful_method available here end end Remember, +describe+ simply creates test classes. It's just ruby at the end of the day and all your normal Good Ruby Rules (tm) apply. If you want to extend your test using setup/teardown via a module, just make sure you ALWAYS call super. before/after automatically call super for you, so make sure you don't do it twice. === How to run code before a group of tests? Use a constant with begin...end like this: describe Blah do SETUP = begin # ... this runs once when describe Blah starts end # ... end This can be useful for expensive initializations or sharing state. Remember, this is just ruby code, so you need to make sure this technique and sharing state doesn't interfere with your tests. === Why am I seeing uninitialized constant MiniTest::Test (NameError)? Are you running the test with Bundler (e.g. via bundle exec )? If so, in order to require minitest, you must first add the gem 'minitest' to your Gemfile and run +bundle+. Once it's installed, you should be able to require minitest and run your tests. == Prominent Projects using Minitest: * arel * journey * mime-types * nokogiri * rails (active_support et al) * rake * rdoc * ...and of course, everything from seattle.rb... == Developing Minitest: Minitest requires {Hoe}[https://rubygems.org/gems/hoe]. === Minitest's own tests require UTF-8 external encoding. This is a common problem in Windows, where the default external Encoding is often CP850, but can affect any platform. Minitest can run test suites using any Encoding, but to run Minitest's own tests you must have a default external Encoding of UTF-8. If your encoding is wrong, you'll see errors like: --- expected +++ actual @@ -1,2 +1,3 @@ # encoding: UTF-8 -"Expected /\\w+/ to not match \"blah blah blah\"." +"Expected /\\w+/ to not match # encoding: UTF-8 +\"blah blah blah\"." To check your current encoding, run: ruby -e 'puts Encoding.default_external' If your output is something other than UTF-8, you can set the RUBYOPTS env variable to a value of '-Eutf-8'. Something like: RUBYOPT='-Eutf-8' ruby -e 'puts Encoding.default_external' Check your OS/shell documentation for the precise syntax (the above will not work on a basic Windows CMD prompt, look for the SET command). Once you've got it successfully outputing UTF-8, use the same setting when running rake in Minitest. === Minitest's own tests require GNU (or similar) diff. This is also a problem primarily affecting Windows developers. PowerShell has a command called diff, but it is not suitable for use with Minitest. If you see failures like either of these, you are probably missing diff tool: 4) Failure: TestMinitestUnitTestCase#test_assert_equal_different_long [D:/ruby/seattlerb/minitest/test/minitest/test_minitest_test.rb:936]: Expected: "--- expected\n+++ actual\n@@ -1 +1 @@\n-\"hahahahahahahahahahahahahahahahahahahaha\"\n+\"blahblahblahblahblahblahblahblahblahblah\"\n" Actual: "Expected: \"hahahahahahahahahahahahahahahahahahahaha\"\n Actual: \"blahblahblahblahblahblahblahblahblahblah\"" 5) Failure: TestMinitestUnitTestCase#test_assert_equal_different_collection_hash_hex_invisible [D:/ruby/seattlerb/minitest/test/minitest/test_minitest_test.rb:845]: Expected: "No visible difference in the Hash#inspect output.\nYou should look at the implementation of #== on Hash or its members.\n {1=>#}" Actual: "Expected: {1=>#}\n Actual: {1=>#}" If you use Cygwin or MSYS2 or similar there are packages that include a GNU diff for Windows. If you don't, you can download GNU diffutils from http://gnuwin32.sourceforge.net/packages/diffutils.htm (make sure to add it to your PATH). You can make sure it's installed and path is configured properly with: diff.exe -v There are multiple lines of output, the first should be something like: diff (GNU diffutils) 2.8.1 If you are using PowerShell make sure you run diff.exe, not just diff, which will invoke the PowerShell built in function. == Known Extensions: capybara_minitest_spec :: Bridge between Capybara RSpec matchers and Minitest::Spec expectations (e.g. page.must_have_content("Title")). color_pound_spec_reporter :: Test names print Ruby Object types in color with your Minitest Spec style tests. minispec-metadata :: Metadata for describe/it blocks & CLI tag filter. E.g. it "requires JS driver", js: true do & ruby test.rb --tag js runs tests tagged :js. minispec-rails :: Minimal support to use Spec style in Rails 5+. mini-apivore :: for swagger based automated API testing. minitest-around :: Around block for minitest. An alternative to setup/teardown dance. minitest-assert_errors :: Adds Minitest assertions to test for errors raised or not raised by Minitest itself. minitest-autotest :: autotest is a continuous testing facility meant to be used during development. minitest-bacon :: minitest-bacon extends minitest with bacon-like functionality. minitest-bang :: Adds support for RSpec-style let! to immediately invoke let statements before each test. minitest-bisect :: Helps you isolate and debug random test failures. minitest-blink1_reporter :: Display test results with a Blink1. minitest-capistrano :: Assertions and expectations for testing Capistrano recipes. minitest-capybara :: Capybara matchers support for minitest unit and spec. minitest-chef-handler :: Run Minitest suites as Chef report handlers minitest-ci :: CI reporter plugin for Minitest. minitest-context :: Defines contexts for code reuse in Minitest specs that share common expectations. minitest-debugger :: Wraps assert so failed assertions drop into the ruby debugger. minitest-display :: Patches Minitest to allow for an easily configurable output. minitest-documentation :: Minimal documentation format inspired by rspec's. minitest-doc_reporter :: Detailed output inspired by rspec's documentation format. minitest-emoji :: Print out emoji for your test passes, fails, and skips. minitest-english :: Semantically symmetric aliases for assertions and expectations. minitest-excludes :: Clean API for excluding certain tests you don't want to run under certain conditions. minitest-fail-fast :: Reimplements RSpec's "fail fast" feature minitest-filecontent :: Support unit tests with expectation results in files. Differing results will be stored again in files. minitest-filesystem :: Adds assertion and expectation to help testing filesystem contents. minitest-firemock :: Makes your Minitest mocks more resilient. minitest-focus :: Focus on one test at a time. minitest-gcstats :: A minitest plugin that adds a report of the top tests by number of objects allocated. minitest-global_expectations:: Support minitest expectation methods for all objects minitest-great_expectations :: Generally useful additions to minitest's assertions and expectations. minitest-growl :: Test notifier for minitest via growl. minitest-happy :: GLOBALLY ACTIVATE MINITEST PRIDE! RAWR! minitest-have_tag :: Adds Minitest assertions to test for the existence of HTML tags, including contents, within a provided string. minitest-hooks :: Around and before_all/after_all/around_all hooks minitest-hyper :: Pretty, single-page HTML reports for your Minitest runs minitest-implicit-subject :: Implicit declaration of the test subject. minitest-instrument :: Instrument ActiveSupport::Notifications when test method is executed. minitest-instrument-db :: Store information about speed of test execution provided by minitest-instrument in database. minitest-junit :: JUnit-style XML reporter for minitest. minitest-keyword :: Use Minitest assertions with keyword arguments. minitest-libnotify :: Test notifier for minitest via libnotify. minitest-line :: Run test at line number. minitest-logger :: Define assert_log and enable minitest to test log messages. Supports Logger and Log4r::Logger. minitest-macruby :: Provides extensions to minitest for macruby UI testing. minitest-matchers :: Adds support for RSpec-style matchers to minitest. minitest-matchers_vaccine :: Adds assertions that adhere to the matcher spec, but without any expectation infections. minitest-metadata :: Annotate tests with metadata (key-value). minitest-mock_expectations :: Provides method call assertions for minitest. minitest-mongoid :: Mongoid assertion matchers for Minitest. minitest-must_not :: Provides must_not as an alias for wont in Minitest. minitest-optional_retry :: Automatically retry failed test to help with flakiness. minitest-osx :: Reporter for the Mac OS X notification center. minitest-parallel_fork :: Fork-based parallelization minitest-parallel-db :: Run tests in parallel with a single database. minitest-power_assert :: PowerAssert for Minitest. minitest-predicates :: Adds support for .predicate? methods. minitest-profile :: List the 10 slowest tests in your suite. minitest-rails :: Minitest integration for Rails 3.x. minitest-rails-capybara :: Capybara integration for Minitest::Rails. minitest-reporters :: Create customizable Minitest output formats. minitest-rg :: Colored red/green output for Minitest. minitest-rspec_mocks :: Use RSpec Mocks with Minitest. minitest-server :: minitest-server provides a client/server setup with your minitest process, allowing your test run to send its results directly to a handler. minitest-sequel :: Minitest assertions to speed-up development and testing of Ruby Sequel database setups. minitest-shared_description :: Support for shared specs and shared spec subclasses minitest-should_syntax :: RSpec-style x.should == y assertions for Minitest. minitest-shouldify :: Adding all manner of shoulds to Minitest (bad idea) minitest-snail :: Print a list of tests that take too long minitest-spec-context :: Provides rspec-ish context method to Minitest::Spec. minitest-spec-expect :: Expect syntax for Minitest::Spec (e.g. expect(sequences).to_include :celery_man). minitest-spec-magic :: Minitest::Spec extensions for Rails and beyond. minitest-spec-rails :: Drop in Minitest::Spec superclass for ActiveSupport::TestCase. minitest-sprint :: Runs (Get it? It's fast!) your tests and makes it easier to rerun individual failures. minitest-stately :: Find leaking state between tests minitest-stub_any_instance :: Stub any instance of a method on the given class for the duration of a block. minitest-stub-const :: Stub constants for the duration of a block. minitest-tags :: Add tags for minitest. minitest-unordered :: Adds a new assertion to minitest for checking the contents of a collection, ignoring element order. minitest-vcr :: Automatic cassette managment with Minitest::Spec and VCR. minitest_owrapper :: Get tests results as a TestResult object. minitest_should :: Shoulda style syntax for minitest test::unit. minitest_tu_shim :: Bridges between test/unit and minitest. mongoid-minitest :: Minitest matchers for Mongoid. mutant-minitest :: Minitest integration for mutant. pry-rescue :: A pry plugin w/ minitest support. See pry-rescue/minitest.rb. rspec2minitest :: Easily translate any RSpec matchers to Minitest assertions and expectations. == Unknown Extensions: Authors... Please send me a pull request with a description of your minitest extension. * assay-minitest * detroit-minitest * em-minitest-spec * flexmock-minitest * guard-minitest * guard-minitest-decisiv * minitest-activemodel * minitest-ar-assertions * minitest-capybara-unit * minitest-colorer * minitest-deluxe * minitest-extra-assertions * minitest-rails-shoulda * minitest-spec * minitest-spec-should * minitest-sugar * spork-minitest == Minitest related goods * minitest/pride fabric: http://www.spoonflower.com/fabric/3928730-again-by-katie_allen == REQUIREMENTS: * Ruby 2.3+. No magic is involved. I hope. == INSTALL: sudo gem install minitest On 1.9, you already have it. To get newer candy you can still install the gem, and then requiring "minitest/autorun" should automatically pull it in. If not, you'll need to do it yourself: gem "minitest" # ensures you"re using the gem, and not the built-in MT require "minitest/autorun" # ... usual testing stuffs ... DO NOTE: There is a serious problem with the way that ruby 1.9/2.0 packages their own gems. They install a gem specification file, but don't install the gem contents in the gem path. This messes up Gem.find_files and many other things (gem which, gem contents, etc). Just install minitest as a gem for real and you'll be happier. == LICENSE: (The MIT License) Copyright (c) Ryan Davis, seattle.rb Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK ].`.`$gems/minitest-5.13.0/lib/minitest.rbnu[require "optparse" require "thread" require "mutex_m" require "minitest/parallel" require "stringio" ## # :include: README.rdoc module Minitest VERSION = "5.13.0" # :nodoc: ENCS = "".respond_to? :encoding # :nodoc: @@installed_at_exit ||= false @@after_run = [] @extensions = [] mc = (class << self; self; end) ## # Parallel test executor mc.send :attr_accessor, :parallel_executor warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"] n_threads = (ENV["MT_CPU"] || ENV["N"] || 2).to_i self.parallel_executor = Parallel::Executor.new n_threads ## # Filter object for backtraces. mc.send :attr_accessor, :backtrace_filter ## # Reporter object to be used for all runs. # # NOTE: This accessor is only available during setup, not during runs. mc.send :attr_accessor, :reporter ## # Names of known extension plugins. mc.send :attr_accessor, :extensions ## # The signal to use for dumping information to STDERR. Defaults to "INFO". mc.send :attr_accessor, :info_signal self.info_signal = "INFO" ## # Registers Minitest to run at process exit def self.autorun at_exit { next if $! and not ($!.kind_of? SystemExit and $!.success?) exit_code = nil pid = Process.pid at_exit { next if Process.pid != pid @@after_run.reverse_each(&:call) exit exit_code || false } exit_code = Minitest.run ARGV } unless @@installed_at_exit @@installed_at_exit = true end ## # A simple hook allowing you to run a block of code after everything # is done running. Eg: # # Minitest.after_run { p $debugging_info } def self.after_run &block @@after_run << block end def self.init_plugins options # :nodoc: self.extensions.each do |name| msg = "plugin_#{name}_init" send msg, options if self.respond_to? msg end end def self.load_plugins # :nodoc: return unless self.extensions.empty? seen = {} require "rubygems" unless defined? Gem Gem.find_files("minitest/*_plugin.rb").each do |plugin_path| name = File.basename plugin_path, "_plugin.rb" next if seen[name] seen[name] = true require plugin_path self.extensions << name end end ## # This is the top-level run method. Everything starts from here. It # tells each Runnable sub-class to run, and each of those are # responsible for doing whatever they do. # # The overall structure of a run looks like this: # # Minitest.autorun # Minitest.run(args) # Minitest.__run(reporter, options) # Runnable.runnables.each # runnable.run(reporter, options) # self.runnable_methods.each # self.run_one_method(self, runnable_method, reporter) # Minitest.run_one_method(klass, runnable_method) # klass.new(runnable_method).run def self.run args = [] self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"] options = process_args args reporter = CompositeReporter.new reporter << SummaryReporter.new(options[:io], options) reporter << ProgressReporter.new(options[:io], options) self.reporter = reporter # this makes it available to plugins self.init_plugins options self.reporter = nil # runnables shouldn't depend on the reporter, ever self.parallel_executor.start if parallel_executor.respond_to?(:start) reporter.start begin __run reporter, options rescue Interrupt warn "Interrupted. Exiting..." end self.parallel_executor.shutdown reporter.report reporter.passed? end ## # Internal run method. Responsible for telling all Runnable # sub-classes to run. def self.__run reporter, options suites = Runnable.runnables.reject { |s| s.runnable_methods.empty? }.shuffle parallel, serial = suites.partition { |s| s.test_order == :parallel } # If we run the parallel tests before the serial tests, the parallel tests # could run in parallel with the serial tests. This would be bad because # the serial tests won't lock around Reporter#record. Run the serial tests # first, so that after they complete, the parallel tests will lock when # recording results. serial.map { |suite| suite.run reporter, options } + parallel.map { |suite| suite.run reporter, options } end def self.process_args args = [] # :nodoc: options = { :io => $stdout, } orig_args = args.dup OptionParser.new do |opts| opts.banner = "minitest options:" opts.version = Minitest::VERSION opts.on "-h", "--help", "Display this help." do puts opts exit end opts.on "--no-plugins", "Bypass minitest plugin auto-loading (or set $MT_NO_PLUGINS)." desc = "Sets random seed. Also via env. Eg: SEED=n rake" opts.on "-s", "--seed SEED", Integer, desc do |m| options[:seed] = m.to_i end opts.on "-v", "--verbose", "Verbose. Show progress processing files." do options[:verbose] = true end opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a| options[:filter] = a end opts.on "-e", "--exclude PATTERN", "Exclude /regexp/ or string from run." do |a| options[:exclude] = a end unless extensions.empty? opts.separator "" opts.separator "Known extensions: #{extensions.join(", ")}" extensions.each do |meth| msg = "plugin_#{meth}_options" send msg, opts, options if self.respond_to?(msg) end end begin opts.parse! args rescue OptionParser::InvalidOption => e puts puts e puts puts opts exit 1 end orig_args -= args end unless options[:seed] then srand options[:seed] = (ENV["SEED"] || srand).to_i % 0xFFFF orig_args << "--seed" << options[:seed].to_s end srand options[:seed] options[:args] = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " " options end def self.filter_backtrace bt # :nodoc: backtrace_filter.filter bt end ## # Represents anything "runnable", like Test, Spec, Benchmark, or # whatever you can dream up. # # Subclasses of this are automatically registered and available in # Runnable.runnables. class Runnable ## # Number of assertions executed in this run. attr_accessor :assertions ## # An assertion raised during the run, if any. attr_accessor :failures ## # The time it took to run. attr_accessor :time def time_it # :nodoc: t0 = Minitest.clock_time yield ensure self.time = Minitest.clock_time - t0 end ## # Name of the run. def name @NAME end ## # Set the name of the run. def name= o @NAME = o end ## # Returns all instance methods matching the pattern +re+. def self.methods_matching re public_instance_methods(true).grep(re).map(&:to_s) end def self.reset # :nodoc: @@runnables = [] end reset ## # Responsible for running all runnable methods in a given class, # each in its own instance. Each instance is passed to the # reporter to record. def self.run reporter, options = {} filter = options[:filter] || "/./" filter = Regexp.new $1 if filter.is_a?(String) && filter =~ %r%/(.*)/% filtered_methods = self.runnable_methods.find_all { |m| filter === m || filter === "#{self}##{m}" } exclude = options[:exclude] exclude = Regexp.new $1 if exclude =~ %r%/(.*)/% filtered_methods.delete_if { |m| exclude === m || exclude === "#{self}##{m}" } return if filtered_methods.empty? with_info_handler reporter do filtered_methods.each do |method_name| run_one_method self, method_name, reporter end end end ## # Runs a single method and has the reporter record the result. # This was considered internal API but is factored out of run so # that subclasses can specialize the running of an individual # test. See Minitest::ParallelTest::ClassMethods for an example. def self.run_one_method klass, method_name, reporter reporter.prerecord klass, method_name reporter.record Minitest.run_one_method(klass, method_name) end def self.with_info_handler reporter, &block # :nodoc: handler = lambda do unless reporter.passed? then warn "Current results:" warn "" warn reporter.reporters.first warn "" end end on_signal ::Minitest.info_signal, handler, &block end SIGNALS = Signal.list # :nodoc: def self.on_signal name, action # :nodoc: supported = SIGNALS[name] old_trap = trap name do old_trap.call if old_trap.respond_to? :call action.call end if supported yield ensure trap name, old_trap if supported end ## # Each subclass of Runnable is responsible for overriding this # method to return all runnable methods. See #methods_matching. def self.runnable_methods raise NotImplementedError, "subclass responsibility" end ## # Returns all subclasses of Runnable. def self.runnables @@runnables end @@marshal_dump_warned = false def marshal_dump # :nodoc: unless @@marshal_dump_warned then warn ["Minitest::Runnable#marshal_dump is deprecated.", "You might be violating internals. From", caller.first].join " " @@marshal_dump_warned = true end [self.name, self.failures, self.assertions, self.time] end def marshal_load ary # :nodoc: self.name, self.failures, self.assertions, self.time = ary end def failure # :nodoc: self.failures.first end def initialize name # :nodoc: self.name = name self.failures = [] self.assertions = 0 end ## # Runs a single method. Needs to return self. def run raise NotImplementedError, "subclass responsibility" end ## # Did this run pass? # # Note: skipped runs are not considered passing, but they don't # cause the process to exit non-zero. def passed? raise NotImplementedError, "subclass responsibility" end ## # Returns a single character string to print based on the result # of the run. One of ".", "F", # "E" or "S". def result_code raise NotImplementedError, "subclass responsibility" end ## # Was this run skipped? See #passed? for more information. def skipped? raise NotImplementedError, "subclass responsibility" end end ## # Shared code for anything that can get passed to a Reporter. See # Minitest::Test & Minitest::Result. module Reportable ## # Did this run pass? # # Note: skipped runs are not considered passing, but they don't # cause the process to exit non-zero. def passed? not self.failure end ## # The location identifier of this test. Depends on a method # existing called class_name. def location loc = " [#{self.failure.location}]" unless passed? or error? "#{self.class_name}##{self.name}#{loc}" end def class_name # :nodoc: raise NotImplementedError, "subclass responsibility" end ## # Returns ".", "F", or "E" based on the result of the run. def result_code self.failure and self.failure.result_code or "." end ## # Was this run skipped? def skipped? self.failure and Skip === self.failure end ## # Did this run error? def error? self.failures.any? { |f| UnexpectedError === f } end end ## # This represents a test result in a clean way that can be # marshalled over a wire. Tests can do anything they want to the # test instance and can create conditions that cause Marshal.dump to # blow up. By using Result.from(a_test) you can be reasonably sure # that the test result can be marshalled. class Result < Runnable include Minitest::Reportable undef_method :marshal_dump undef_method :marshal_load ## # The class name of the test result. attr_accessor :klass ## # The location of the test method. attr_accessor :source_location ## # Create a new test result from a Runnable instance. def self.from runnable o = runnable r = self.new o.name r.klass = o.class.name r.assertions = o.assertions r.failures = o.failures.dup r.time = o.time r.source_location = o.method(o.name).source_location rescue ["unknown", -1] r end def class_name # :nodoc: self.klass # for Minitest::Reportable end def to_s # :nodoc: return location if passed? and not skipped? failures.map { |failure| "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n" }.join "\n" end end ## # Defines the API for Reporters. Subclass this and override whatever # you want. Go nuts. class AbstractReporter include Mutex_m ## # Starts reporting on the run. def start end ## # About to start running a test. This allows a reporter to show # that it is starting or that we are in the middle of a test run. def prerecord klass, name end ## # Output and record the result of the test. Call # {result#result_code}[rdoc-ref:Runnable#result_code] to get the # result character string. Stores the result of the run if the run # did not pass. def record result end ## # Outputs the summary of the run. def report end ## # Did this run pass? def passed? true end end class Reporter < AbstractReporter # :nodoc: ## # The IO used to report. attr_accessor :io ## # Command-line options for this run. attr_accessor :options def initialize io = $stdout, options = {} # :nodoc: super() self.io = io self.options = options end end ## # A very simple reporter that prints the "dots" during the run. # # This is added to the top-level CompositeReporter at the start of # the run. If you want to change the output of minitest via a # plugin, pull this out of the composite and replace it with your # own. class ProgressReporter < Reporter def prerecord klass, name #:nodoc: if options[:verbose] then io.print "%s#%s = " % [klass.name, name] io.flush end end def record result # :nodoc: io.print "%.2f s = " % [result.time] if options[:verbose] io.print result.result_code io.puts if options[:verbose] end end ## # A reporter that gathers statistics about a test run. Does not do # any IO because meant to be used as a parent class for a reporter # that does. # # If you want to create an entirely different type of output (eg, # CI, HTML, etc), this is the place to start. # # Example: # # class JenkinsCIReporter < StatisticsReporter # def report # super # Needed to calculate some statistics # # print " 30 characters. # 3. or: Strings are equal to each other (but maybe different encodings?). # 4. and: we found a diff executable. def things_to_diff exp, act expect = mu_pp_for_diff exp butwas = mu_pp_for_diff act e1, e2 = expect.include?("\n"), expect.include?("\\n") b1, b2 = butwas.include?("\n"), butwas.include?("\\n") need_to_diff = (e1 ^ e2 || b1 ^ b2 || expect.size > 30 || butwas.size > 30 || expect == butwas) && Minitest::Assertions.diff need_to_diff && [expect, butwas] end ## # This returns a human-readable version of +obj+. By default # #inspect is called. You can override this to use #pretty_inspect # if you want. # # See Minitest::Test.make_my_diffs_pretty! def mu_pp obj s = obj.inspect if defined? Encoding then s = s.encode Encoding.default_external if String === obj && (obj.encoding != Encoding.default_external || !obj.valid_encoding?) then enc = "# encoding: #{obj.encoding}" val = "# valid: #{obj.valid_encoding?}" s = "#{enc}\n#{val}\n#{s}" end end s end ## # This returns a diff-able more human-readable version of +obj+. # This differs from the regular mu_pp because it expands escaped # newlines and makes hex-values (like object_ids) generic. This # uses mu_pp to do the first pass and then cleans it up. def mu_pp_for_diff obj str = mu_pp obj # both '\n' & '\\n' (_after_ mu_pp (aka inspect)) single = !!str.match(/(?exp == act
    printing the difference between # the two, if possible. # # If there is no visible difference but the assertion fails, you # should suspect that your #== is buggy, or your inspect output is # missing crucial details. For nicer structural diffing, set # Minitest::Test.make_my_diffs_pretty! # # For floats use assert_in_delta. # # See also: Minitest::Assertions.diff def assert_equal exp, act, msg = nil msg = message(msg, E) { diff exp, act } result = assert exp == act, msg if nil == exp then if Minitest::VERSION =~ /^6/ then refute_nil exp, "Use assert_nil if expecting nil." else where = Minitest.filter_backtrace(caller).first where = where.split(/:in /, 2).first # clean up noise warn "DEPRECATED: Use assert_nil if expecting nil from #{where}. This will fail in Minitest 6." end end result end ## # For comparing Floats. Fails unless +exp+ and +act+ are within +delta+ # of each other. # # assert_in_delta Math::PI, (22.0 / 7.0), 0.01 def assert_in_delta exp, act, delta = 0.001, msg = nil n = (exp - act).abs msg = message(msg) { "Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}" } assert delta >= n, msg end ## # For comparing Floats. Fails unless +exp+ and +act+ have a relative # error less than +epsilon+. def assert_in_epsilon exp, act, epsilon = 0.001, msg = nil assert_in_delta exp, act, [exp.abs, act.abs].min * epsilon, msg end ## # Fails unless +collection+ includes +obj+. def assert_includes collection, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" } assert_respond_to collection, :include? assert collection.include?(obj), msg end ## # Fails unless +obj+ is an instance of +cls+. def assert_instance_of cls, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}" } assert obj.instance_of?(cls), msg end ## # Fails unless +obj+ is a kind of +cls+. def assert_kind_of cls, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" } assert obj.kind_of?(cls), msg end ## # Fails unless +matcher+ =~ +obj+. def assert_match matcher, obj, msg = nil msg = message(msg) { "Expected #{mu_pp matcher} to match #{mu_pp obj}" } assert_respond_to matcher, :"=~" matcher = Regexp.new Regexp.escape matcher if String === matcher assert matcher =~ obj, msg end ## # Fails unless +obj+ is nil def assert_nil obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" } assert obj.nil?, msg end ## # For testing with binary operators. Eg: # # assert_operator 5, :<=, 4 def assert_operator o1, op, o2 = UNDEFINED, msg = nil return assert_predicate o1, op, msg if UNDEFINED == o2 msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" } assert o1.__send__(op, o2), msg end ## # Fails if stdout or stderr do not output the expected results. # Pass in nil if you don't care about that streams output. Pass in # "" if you require it to be silent. Pass in a regexp if you want # to pattern match. # # assert_output(/hey/) { method_with_output } # # NOTE: this uses #capture_io, not #capture_subprocess_io. # # See also: #assert_silent def assert_output stdout = nil, stderr = nil flunk "assert_output requires a block to capture output." unless block_given? out, err = capture_io do yield end err_msg = Regexp === stderr ? :assert_match : :assert_equal if stderr out_msg = Regexp === stdout ? :assert_match : :assert_equal if stdout y = send err_msg, stderr, err, "In stderr" if err_msg x = send out_msg, stdout, out, "In stdout" if out_msg (!stdout || x) && (!stderr || y) end ## # Fails unless +path+ exists. def assert_path_exists path, msg = nil msg = message(msg) { "Expected path '#{path}' to exist" } assert File.exist?(path), msg end ## # For testing with predicates. Eg: # # assert_predicate str, :empty? # # This is really meant for specs and is front-ended by assert_operator: # # str.must_be :empty? def assert_predicate o1, op, msg = nil msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op}" } assert o1.__send__(op), msg end ## # Fails unless the block raises one of +exp+. Returns the # exception matched so you can check the message, attributes, etc. # # +exp+ takes an optional message on the end to help explain # failures and defaults to StandardError if no exception class is # passed. Eg: # # assert_raises(CustomError) { method_with_custom_error } # # With custom error message: # # assert_raises(CustomError, 'This should have raised CustomError') { method_with_custom_error } # # Using the returned object: # # error = assert_raises(CustomError) do # raise CustomError, 'This is really bad' # end # # assert_equal 'This is really bad', error.message def assert_raises *exp flunk "assert_raises requires a block to capture errors." unless block_given? msg = "#{exp.pop}.\n" if String === exp.last exp << StandardError if exp.empty? begin yield rescue *exp => e pass # count assertion return e rescue Minitest::Skip, Minitest::Assertion # don't count assertion raise rescue SignalException, SystemExit raise rescue Exception => e flunk proc { exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not") } end exp = exp.first if exp.size == 1 flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised." end ## # Fails unless +obj+ responds to +meth+. def assert_respond_to obj, meth, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}" } assert obj.respond_to?(meth), msg end ## # Fails unless +exp+ and +act+ are #equal? def assert_same exp, act, msg = nil msg = message(msg) { data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id] "Expected %s (oid=%d) to be the same as %s (oid=%d)" % data } assert exp.equal?(act), msg end ## # +send_ary+ is a receiver, message and arguments. # # Fails unless the call returns a true value def assert_send send_ary, m = nil where = Minitest.filter_backtrace(caller).first where = where.split(/:in /, 2).first # clean up noise warn "DEPRECATED: assert_send. From #{where}" recv, msg, *args = send_ary m = message(m) { "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" } assert recv.__send__(msg, *args), m end ## # Fails if the block outputs anything to stderr or stdout. # # See also: #assert_output def assert_silent assert_output "", "" do yield end end ## # Fails unless the block throws +sym+ def assert_throws sym, msg = nil default = "Expected #{mu_pp(sym)} to have been thrown" caught = true catch(sym) do begin yield rescue ThreadError => e # wtf?!? 1.8 + threads == suck default += ", not \:#{e.message[/uncaught throw \`(\w+?)\'/, 1]}" rescue ArgumentError => e # 1.9 exception raise e unless e.message.include?("uncaught throw") default += ", not #{e.message.split(/ /).last}" rescue NameError => e # 1.8 exception raise e unless e.name == sym default += ", not #{e.name.inspect}" end caught = false end assert caught, message(msg) { default } end ## # Captures $stdout and $stderr into strings: # # out, err = capture_io do # puts "Some info" # warn "You did a bad thing" # end # # assert_match %r%info%, out # assert_match %r%bad%, err # # NOTE: For efficiency, this method uses StringIO and does not # capture IO for subprocesses. Use #capture_subprocess_io for # that. def capture_io _synchronize do begin captured_stdout, captured_stderr = StringIO.new, StringIO.new orig_stdout, orig_stderr = $stdout, $stderr $stdout, $stderr = captured_stdout, captured_stderr yield return captured_stdout.string, captured_stderr.string ensure $stdout = orig_stdout $stderr = orig_stderr end end end ## # Captures $stdout and $stderr into strings, using Tempfile to # ensure that subprocess IO is captured as well. # # out, err = capture_subprocess_io do # system "echo Some info" # system "echo You did a bad thing 1>&2" # end # # assert_match %r%info%, out # assert_match %r%bad%, err # # NOTE: This method is approximately 10x slower than #capture_io so # only use it when you need to test the output of a subprocess. def capture_subprocess_io _synchronize do begin require "tempfile" captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err") orig_stdout, orig_stderr = $stdout.dup, $stderr.dup $stdout.reopen captured_stdout $stderr.reopen captured_stderr yield $stdout.rewind $stderr.rewind return captured_stdout.read, captured_stderr.read ensure captured_stdout.unlink captured_stderr.unlink $stdout.reopen orig_stdout $stderr.reopen orig_stderr end end end ## # Returns details for exception +e+ def exception_details e, msg [ "#{msg}", "Class: <#{e.class}>", "Message: <#{e.message.inspect}>", "---Backtrace---", "#{Minitest.filter_backtrace(e.backtrace).join("\n")}", "---------------", ].join "\n" end ## # Fails after a given date (in the local time zone). This allows # you to put time-bombs in your tests if you need to keep # something around until a later date lest you forget about it. def fail_after y,m,d,msg flunk msg if Time.now > Time.local(y, m, d) end ## # Fails with +msg+. def flunk msg = nil msg ||= "Epic Fail!" assert false, msg end ## # Returns a proc that will output +msg+ along with the default message. def message msg = nil, ending = nil, &default proc { msg = msg.call.chomp(".") if Proc === msg custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty? "#{custom_message}#{default.call}#{ending || "."}" } end ## # used for counting assertions def pass _msg = nil assert true end ## # Fails if +test+ is truthy. def refute test, msg = nil msg ||= message { "Expected #{mu_pp(test)} to not be truthy" } not assert !test, msg end ## # Fails if +obj+ is empty. def refute_empty obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not be empty" } assert_respond_to obj, :empty? refute obj.empty?, msg end ## # Fails if exp == act. # # For floats use refute_in_delta. def refute_equal exp, act, msg = nil msg = message(msg) { "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}" } refute exp == act, msg end ## # For comparing Floats. Fails if +exp+ is within +delta+ of +act+. # # refute_in_delta Math::PI, (22.0 / 7.0) def refute_in_delta exp, act, delta = 0.001, msg = nil n = (exp - act).abs msg = message(msg) { "Expected |#{exp} - #{act}| (#{n}) to not be <= #{delta}" } refute delta >= n, msg end ## # For comparing Floats. Fails if +exp+ and +act+ have a relative error # less than +epsilon+. def refute_in_epsilon a, b, epsilon = 0.001, msg = nil refute_in_delta a, b, a * epsilon, msg end ## # Fails if +collection+ includes +obj+. def refute_includes collection, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}" } assert_respond_to collection, :include? refute collection.include?(obj), msg end ## # Fails if +obj+ is an instance of +cls+. def refute_instance_of cls, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not be an instance of #{cls}" } refute obj.instance_of?(cls), msg end ## # Fails if +obj+ is a kind of +cls+. def refute_kind_of cls, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" } refute obj.kind_of?(cls), msg end ## # Fails if +matcher+ =~ +obj+. def refute_match matcher, obj, msg = nil msg = message(msg) { "Expected #{mu_pp matcher} to not match #{mu_pp obj}" } assert_respond_to matcher, :"=~" matcher = Regexp.new Regexp.escape matcher if String === matcher refute matcher =~ obj, msg end ## # Fails if +obj+ is nil. def refute_nil obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" } refute obj.nil?, msg end ## # Fails if +o1+ is not +op+ +o2+. Eg: # # refute_operator 1, :>, 2 #=> pass # refute_operator 1, :<, 2 #=> fail def refute_operator o1, op, o2 = UNDEFINED, msg = nil return refute_predicate o1, op, msg if UNDEFINED == o2 msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}" } refute o1.__send__(op, o2), msg end ## # Fails if +path+ exists. def refute_path_exists path, msg = nil msg = message(msg) { "Expected path '#{path}' to not exist" } refute File.exist?(path), msg end ## # For testing with predicates. # # refute_predicate str, :empty? # # This is really meant for specs and is front-ended by refute_operator: # # str.wont_be :empty? def refute_predicate o1, op, msg = nil msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op}" } refute o1.__send__(op), msg end ## # Fails if +obj+ responds to the message +meth+. def refute_respond_to obj, meth, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" } refute obj.respond_to?(meth), msg end ## # Fails if +exp+ is the same (by object identity) as +act+. def refute_same exp, act, msg = nil msg = message(msg) { data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id] "Expected %s (oid=%d) to not be the same as %s (oid=%d)" % data } refute exp.equal?(act), msg end ## # Skips the current run. If run in verbose-mode, the skipped run # gets listed at the end of the run but doesn't cause a failure # exit code. def skip msg = nil, bt = caller msg ||= "Skipped, no message given" @skip = true raise Minitest::Skip, msg, bt end ## # Skips the current run until a given date (in the local time # zone). This allows you to put some fixes on hold until a later # date, but still holds you accountable and prevents you from # forgetting it. def skip_until y,m,d,msg skip msg if Time.now < Time.local(y, m, d) where = caller.first.split(/:/, 3).first(2).join ":" warn "Stale skip_until %p at %s" % [msg, where] end ## # Was this testcase skipped? Meant for #teardown. def skipped? defined?(@skip) and @skip end end end PK ]+**)gems/minitest-5.13.0/lib/minitest/test.rbnu[require "minitest" unless defined? Minitest::Runnable module Minitest ## # Subclass Test to create your own tests. Typically you'll want a # Test subclass per implementation class. # # See Minitest::Assertions class Test < Runnable require "minitest/assertions" include Minitest::Assertions include Minitest::Reportable def class_name # :nodoc: self.class.name # for Minitest::Reportable end PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, SystemExit] # :nodoc: # :stopdoc: class << self; attr_accessor :io_lock; end self.io_lock = Mutex.new # :startdoc: ## # Call this at the top of your tests when you absolutely # positively need to have ordered tests. In doing so, you're # admitting that you suck and your tests are weak. def self.i_suck_and_my_tests_are_order_dependent! class << self undef_method :test_order if method_defined? :test_order define_method :test_order do :alpha end end end ## # Make diffs for this Test use #pretty_inspect so that diff # in assert_equal can have more details. NOTE: this is much slower # than the regular inspect but much more usable for complex # objects. def self.make_my_diffs_pretty! require "pp" define_method :mu_pp, &:pretty_inspect end ## # Call this at the top of your tests when you want to run your # tests in parallel. In doing so, you're admitting that you rule # and your tests are awesome. def self.parallelize_me! include Minitest::Parallel::Test extend Minitest::Parallel::Test::ClassMethods end ## # Returns all instance methods starting with "test_". Based on # #test_order, the methods are either sorted, randomized # (default), or run in parallel. def self.runnable_methods methods = methods_matching(/^test_/) case self.test_order when :random, :parallel then max = methods.size methods.sort.sort_by { rand max } when :alpha, :sorted then methods.sort else raise "Unknown test_order: #{self.test_order.inspect}" end end ## # Defines the order to run tests (:random by default). Override # this or use a convenience method to change it for your tests. def self.test_order :random end TEARDOWN_METHODS = %w[ before_teardown teardown after_teardown ] # :nodoc: ## # Runs a single test with setup/teardown hooks. def run with_info_handler do time_it do capture_exceptions do before_setup; setup; after_setup self.send self.name end TEARDOWN_METHODS.each do |hook| capture_exceptions do self.send hook end end end end Result.from self # per contract end ## # Provides before/after hooks for setup and teardown. These are # meant for library writers, NOT for regular test authors. See # #before_setup for an example. module LifecycleHooks ## # Runs before every test, before setup. This hook is meant for # libraries to extend minitest. It is not meant to be used by # test developers. # # As a simplistic example: # # module MyMinitestPlugin # def before_setup # super # # ... stuff to do before setup is run # end # # def after_setup # # ... stuff to do after setup is run # super # end # # def before_teardown # super # # ... stuff to do before teardown is run # end # # def after_teardown # # ... stuff to do after teardown is run # super # end # end # # class MiniTest::Test # include MyMinitestPlugin # end def before_setup; end ## # Runs before every test. Use this to set up before each test # run. def setup; end ## # Runs before every test, after setup. This hook is meant for # libraries to extend minitest. It is not meant to be used by # test developers. # # See #before_setup for an example. def after_setup; end ## # Runs after every test, before teardown. This hook is meant for # libraries to extend minitest. It is not meant to be used by # test developers. # # See #before_setup for an example. def before_teardown; end ## # Runs after every test. Use this to clean up after each test # run. def teardown; end ## # Runs after every test, after teardown. This hook is meant for # libraries to extend minitest. It is not meant to be used by # test developers. # # See #before_setup for an example. def after_teardown; end end # LifecycleHooks def capture_exceptions # :nodoc: yield rescue *PASSTHROUGH_EXCEPTIONS raise rescue Assertion => e self.failures << e rescue Exception => e self.failures << UnexpectedError.new(e) end def with_info_handler &block # :nodoc: t0 = Minitest.clock_time handler = lambda do warn "\nCurrent: %s#%s %.2fs" % [self.class, self.name, Minitest.clock_time - t0] end self.class.on_signal ::Minitest.info_signal, handler, &block end include LifecycleHooks include Guard extend Guard end # Test end require "minitest/unit" unless defined?(MiniTest) # compatibility layer only PK ] 00.gems/minitest-5.13.0/lib/minitest/benchmark.rbnu[require "minitest/test" require "minitest/spec" module Minitest ## # Subclass Benchmark to create your own benchmark runs. Methods # starting with "bench_" get executed on a per-class. # # See Minitest::Assertions class Benchmark < Test def self.io # :nodoc: @io end def io # :nodoc: self.class.io end def self.run reporter, options = {} # :nodoc: @io = reporter.io super end def self.runnable_methods # :nodoc: methods_matching(/^bench_/) end ## # Returns a set of ranges stepped exponentially from +min+ to # +max+ by powers of +base+. Eg: # # bench_exp(2, 16, 2) # => [2, 4, 8, 16] def self.bench_exp min, max, base = 10 min = (Math.log10(min) / Math.log10(base)).to_i max = (Math.log10(max) / Math.log10(base)).to_i (min..max).map { |m| base ** m }.to_a end ## # Returns a set of ranges stepped linearly from +min+ to +max+ by # +step+. Eg: # # bench_linear(20, 40, 10) # => [20, 30, 40] def self.bench_linear min, max, step = 10 (min..max).step(step).to_a rescue LocalJumpError # 1.8.6 r = []; (min..max).step(step) { |n| r << n }; r end ## # Specifies the ranges used for benchmarking for that class. # Defaults to exponential growth from 1 to 10k by powers of 10. # Override if you need different ranges for your benchmarks. # # See also: ::bench_exp and ::bench_linear. def self.bench_range bench_exp 1, 10_000 end ## # Runs the given +work+, gathering the times of each run. Range # and times are then passed to a given +validation+ proc. Outputs # the benchmark name and times in tab-separated format, making it # easy to paste into a spreadsheet for graphing or further # analysis. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # validation = proc { |x, y| ... } # assert_performance validation do |n| # @obj.algorithm(n) # end # end def assert_performance validation, &work range = self.class.bench_range io.print "#{self.name}" times = [] range.each do |x| GC.start t0 = Minitest.clock_time instance_exec(x, &work) t = Minitest.clock_time - t0 io.print "\t%9.6f" % t times << t end io.puts validation[range, times] end ## # Runs the given +work+ and asserts that the times gathered fit to # match a constant rate (eg, linear slope == 0) within a given # +threshold+. Note: because we're testing for a slope of 0, R^2 # is not a good determining factor for the fit, so the threshold # is applied against the slope itself. As such, you probably want # to tighten it from the default. # # See https://www.graphpad.com/guides/prism/8/curve-fitting/reg_intepretingnonlinr2.htm # for more details. # # Fit is calculated by #fit_linear. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_constant 0.9999 do |n| # @obj.algorithm(n) # end # end def assert_performance_constant threshold = 0.99, &work validation = proc do |range, times| a, b, rr = fit_linear range, times assert_in_delta 0, b, 1 - threshold [a, b, rr] end assert_performance validation, &work end ## # Runs the given +work+ and asserts that the times gathered fit to # match a exponential curve within a given error +threshold+. # # Fit is calculated by #fit_exponential. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_exponential 0.9999 do |n| # @obj.algorithm(n) # end # end def assert_performance_exponential threshold = 0.99, &work assert_performance validation_for_fit(:exponential, threshold), &work end ## # Runs the given +work+ and asserts that the times gathered fit to # match a logarithmic curve within a given error +threshold+. # # Fit is calculated by #fit_logarithmic. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_logarithmic 0.9999 do |n| # @obj.algorithm(n) # end # end def assert_performance_logarithmic threshold = 0.99, &work assert_performance validation_for_fit(:logarithmic, threshold), &work end ## # Runs the given +work+ and asserts that the times gathered fit to # match a straight line within a given error +threshold+. # # Fit is calculated by #fit_linear. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_linear 0.9999 do |n| # @obj.algorithm(n) # end # end def assert_performance_linear threshold = 0.99, &work assert_performance validation_for_fit(:linear, threshold), &work end ## # Runs the given +work+ and asserts that the times gathered curve # fit to match a power curve within a given error +threshold+. # # Fit is calculated by #fit_power. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_power 0.9999 do |x| # @obj.algorithm # end # end def assert_performance_power threshold = 0.99, &work assert_performance validation_for_fit(:power, threshold), &work end ## # Takes an array of x/y pairs and calculates the general R^2 value. # # See: http://en.wikipedia.org/wiki/Coefficient_of_determination def fit_error xys y_bar = sigma(xys) { |_, y| y } / xys.size.to_f ss_tot = sigma(xys) { |_, y| (y - y_bar) ** 2 } ss_err = sigma(xys) { |x, y| (yield(x) - y) ** 2 } 1 - (ss_err / ss_tot) end ## # To fit a functional form: y = ae^(bx). # # Takes x and y values and returns [a, b, r^2]. # # See: http://mathworld.wolfram.com/LeastSquaresFittingExponential.html def fit_exponential xs, ys n = xs.size xys = xs.zip(ys) sxlny = sigma(xys) { |x, y| x * Math.log(y) } slny = sigma(xys) { |_, y| Math.log(y) } sx2 = sigma(xys) { |x, _| x * x } sx = sigma xs c = n * sx2 - sx ** 2 a = (slny * sx2 - sx * sxlny) / c b = ( n * sxlny - sx * slny ) / c return Math.exp(a), b, fit_error(xys) { |x| Math.exp(a + b * x) } end ## # To fit a functional form: y = a + b*ln(x). # # Takes x and y values and returns [a, b, r^2]. # # See: http://mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html def fit_logarithmic xs, ys n = xs.size xys = xs.zip(ys) slnx2 = sigma(xys) { |x, _| Math.log(x) ** 2 } slnx = sigma(xys) { |x, _| Math.log(x) } sylnx = sigma(xys) { |x, y| y * Math.log(x) } sy = sigma(xys) { |_, y| y } c = n * slnx2 - slnx ** 2 b = ( n * sylnx - sy * slnx ) / c a = (sy - b * slnx) / n return a, b, fit_error(xys) { |x| a + b * Math.log(x) } end ## # Fits the functional form: a + bx. # # Takes x and y values and returns [a, b, r^2]. # # See: http://mathworld.wolfram.com/LeastSquaresFitting.html def fit_linear xs, ys n = xs.size xys = xs.zip(ys) sx = sigma xs sy = sigma ys sx2 = sigma(xs) { |x| x ** 2 } sxy = sigma(xys) { |x, y| x * y } c = n * sx2 - sx**2 a = (sy * sx2 - sx * sxy) / c b = ( n * sxy - sx * sy ) / c return a, b, fit_error(xys) { |x| a + b * x } end ## # To fit a functional form: y = ax^b. # # Takes x and y values and returns [a, b, r^2]. # # See: http://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html def fit_power xs, ys n = xs.size xys = xs.zip(ys) slnxlny = sigma(xys) { |x, y| Math.log(x) * Math.log(y) } slnx = sigma(xs) { |x | Math.log(x) } slny = sigma(ys) { | y| Math.log(y) } slnx2 = sigma(xs) { |x | Math.log(x) ** 2 } b = (n * slnxlny - slnx * slny) / (n * slnx2 - slnx ** 2) a = (slny - b * slnx) / n return Math.exp(a), b, fit_error(xys) { |x| (Math.exp(a) * (x ** b)) } end ## # Enumerates over +enum+ mapping +block+ if given, returning the # sum of the result. Eg: # # sigma([1, 2, 3]) # => 1 + 2 + 3 => 6 # sigma([1, 2, 3]) { |n| n ** 2 } # => 1 + 4 + 9 => 14 def sigma enum, &block enum = enum.map(&block) if block enum.inject { |sum, n| sum + n } end ## # Returns a proc that calls the specified fit method and asserts # that the error is within a tolerable threshold. def validation_for_fit msg, threshold proc do |range, times| a, b, rr = send "fit_#{msg}", range, times assert_operator rr, :>=, threshold [a, b, rr] end end end end module Minitest ## # The spec version of Minitest::Benchmark. class BenchSpec < Benchmark extend Minitest::Spec::DSL ## # This is used to define a new benchmark method. You usually don't # use this directly and is intended for those needing to write new # performance curve fits (eg: you need a specific polynomial fit). # # See ::bench_performance_linear for an example of how to use this. def self.bench name, &block define_method "bench_#{name.gsub(/\W+/, "_")}", &block end ## # Specifies the ranges used for benchmarking for that class. # # bench_range do # bench_exp(2, 16, 2) # end # # See Minitest::Benchmark#bench_range for more details. def self.bench_range &block return super unless block meta = (class << self; self; end) meta.send :define_method, "bench_range", &block end ## # Create a benchmark that verifies that the performance is linear. # # describe "my class Bench" do # bench_performance_linear "fast_algorithm", 0.9999 do |n| # @obj.fast_algorithm(n) # end # end def self.bench_performance_linear name, threshold = 0.99, &work bench name do assert_performance_linear threshold, &work end end ## # Create a benchmark that verifies that the performance is constant. # # describe "my class Bench" do # bench_performance_constant "zoom_algorithm!" do |n| # @obj.zoom_algorithm!(n) # end # end def self.bench_performance_constant name, threshold = 0.99, &work bench name do assert_performance_constant threshold, &work end end ## # Create a benchmark that verifies that the performance is exponential. # # describe "my class Bench" do # bench_performance_exponential "algorithm" do |n| # @obj.algorithm(n) # end # end def self.bench_performance_exponential name, threshold = 0.99, &work bench name do assert_performance_exponential threshold, &work end end ## # Create a benchmark that verifies that the performance is logarithmic. # # describe "my class Bench" do # bench_performance_logarithmic "algorithm" do |n| # @obj.algorithm(n) # end # end def self.bench_performance_logarithmic name, threshold = 0.99, &work bench name do assert_performance_logarithmic threshold, &work end end ## # Create a benchmark that verifies that the performance is power. # # describe "my class Bench" do # bench_performance_power "algorithm" do |n| # @obj.algorithm(n) # end # end def self.bench_performance_power name, threshold = 0.99, &work bench name do assert_performance_power threshold, &work end end end Minitest::Spec.register_spec_type(/Bench(mark)?$/, Minitest::BenchSpec) end PK ]y)gems/minitest-5.13.0/lib/minitest/unit.rbnu[# :stopdoc: unless defined?(Minitest) then # all of this crap is just to avoid circular requires and is only # needed if a user requires "minitest/unit" directly instead of # "minitest/autorun", so we also warn from = caller.reject { |s| s =~ /rubygems/ }.join("\n ") warn "Warning: you should require 'minitest/autorun' instead." warn %(Warning: or add 'gem "minitest"' before 'require "minitest/autorun"') warn "From:\n #{from}" module Minitest; end MiniTest = Minitest # prevents minitest.rb from requiring back to us require "minitest" end MiniTest = Minitest unless defined?(MiniTest) module Minitest class Unit VERSION = Minitest::VERSION class TestCase < Minitest::Test def self.inherited klass # :nodoc: from = caller.first warn "MiniTest::Unit::TestCase is now Minitest::Test. From #{from}" super end end def self.autorun # :nodoc: from = caller.first warn "MiniTest::Unit.autorun is now Minitest.autorun. From #{from}" Minitest.autorun end def self.after_tests &b # :nodoc: from = caller.first warn "MiniTest::Unit.after_tests is now Minitest.after_run. From #{from}" Minitest.after_run(&b) end end end # :startdoc: PK ]/w[NN)gems/minitest-5.13.0/lib/minitest/mock.rbnu[class MockExpectationError < StandardError; end # :nodoc: module Minitest # :nodoc: ## # A simple and clean mock object framework. # # All mock objects are an instance of Mock class Mock alias :__respond_to? :respond_to? overridden_methods = %w[ === class inspect instance_eval instance_variables object_id public_send respond_to_missing? send to_s ] instance_methods.each do |m| undef_method m unless overridden_methods.include?(m.to_s) || m =~ /^__/ end overridden_methods.map(&:to_sym).each do |method_id| define_method method_id do |*args, &b| if @expected_calls.key? method_id then method_missing(method_id, *args, &b) else super(*args, &b) end end end def initialize delegator = nil # :nodoc: @delegator = delegator @expected_calls = Hash.new { |calls, name| calls[name] = [] } @actual_calls = Hash.new { |calls, name| calls[name] = [] } end ## # Expect that method +name+ is called, optionally with +args+ or a # +blk+, and returns +retval+. # # @mock.expect(:meaning_of_life, 42) # @mock.meaning_of_life # => 42 # # @mock.expect(:do_something_with, true, [some_obj, true]) # @mock.do_something_with(some_obj, true) # => true # # @mock.expect(:do_something_else, true) do |a1, a2| # a1 == "buggs" && a2 == :bunny # end # # +args+ is compared to the expected args using case equality (ie, the # '===' operator), allowing for less specific expectations. # # @mock.expect(:uses_any_string, true, [String]) # @mock.uses_any_string("foo") # => true # @mock.verify # => true # # @mock.expect(:uses_one_string, true, ["foo"]) # @mock.uses_one_string("bar") # => raises MockExpectationError # # If a method will be called multiple times, specify a new expect for each one. # They will be used in the order you define them. # # @mock.expect(:ordinal_increment, 'first') # @mock.expect(:ordinal_increment, 'second') # # @mock.ordinal_increment # => 'first' # @mock.ordinal_increment # => 'second' # @mock.ordinal_increment # => raises MockExpectationError "No more expects available for :ordinal_increment" # def expect name, retval, args = [], &blk name = name.to_sym if block_given? raise ArgumentError, "args ignored when block given" unless args.empty? @expected_calls[name] << { :retval => retval, :block => blk } else raise ArgumentError, "args must be an array" unless Array === args @expected_calls[name] << { :retval => retval, :args => args } end self end def __call name, data # :nodoc: case data when Hash then "#{name}(#{data[:args].inspect[1..-2]}) => #{data[:retval].inspect}" else data.map { |d| __call name, d }.join ", " end end ## # Verify that all methods were called as expected. Raises # +MockExpectationError+ if the mock object was not called as # expected. def verify @expected_calls.each do |name, expected| actual = @actual_calls.fetch(name, nil) raise MockExpectationError, "expected #{__call name, expected[0]}" unless actual raise MockExpectationError, "expected #{__call name, expected[actual.size]}, got [#{__call name, actual}]" if actual.size < expected.size end true end def method_missing sym, *args, &block # :nodoc: unless @expected_calls.key?(sym) then if @delegator && @delegator.respond_to?(sym) return @delegator.public_send(sym, *args, &block) else raise NoMethodError, "unmocked method %p, expected one of %p" % [sym, @expected_calls.keys.sort_by(&:to_s)] end end index = @actual_calls[sym].length expected_call = @expected_calls[sym][index] unless expected_call then raise MockExpectationError, "No more expects available for %p: %p" % [sym, args] end expected_args, retval, val_block = expected_call.values_at(:args, :retval, :block) if val_block then # keep "verify" happy @actual_calls[sym] << expected_call raise MockExpectationError, "mocked method %p failed block w/ %p" % [sym, args] unless val_block.call(*args, &block) return retval end if expected_args.size != args.size then raise ArgumentError, "mocked method %p expects %d arguments, got %d" % [sym, expected_args.size, args.size] end zipped_args = expected_args.zip(args) fully_matched = zipped_args.all? { |mod, a| mod === a or mod == a } unless fully_matched then raise MockExpectationError, "mocked method %p called with unexpected arguments %p" % [sym, args] end @actual_calls[sym] << { :retval => retval, :args => zipped_args.map! { |mod, a| mod === a ? mod : a }, } retval end def respond_to? sym, include_private = false # :nodoc: return true if @expected_calls.key? sym.to_sym return true if @delegator && @delegator.respond_to?(sym, include_private) __respond_to?(sym, include_private) end end end module Minitest::Assertions ## # Assert that the mock verifies correctly. def assert_mock mock assert mock.verify end end ## # Object extensions for Minitest::Mock. class Object ## # Add a temporary stubbed method replacing +name+ for the duration # of the +block+. If +val_or_callable+ responds to #call, then it # returns the result of calling it, otherwise returns the value # as-is. If stubbed method yields a block, +block_args+ will be # passed along. Cleans up the stub at the end of the +block+. The # method +name+ must exist before stubbing. # # def test_stale_eh # obj_under_test = Something.new # refute obj_under_test.stale? # # Time.stub :now, Time.at(0) do # assert obj_under_test.stale? # end # end # def stub name, val_or_callable, *block_args new_name = "__minitest_stub__#{name}" metaclass = class << self; self; end if respond_to? name and not methods.map(&:to_s).include? name.to_s then metaclass.send :define_method, name do |*args| super(*args) end end metaclass.send :alias_method, new_name, name metaclass.send :define_method, name do |*args, &blk| if val_or_callable.respond_to? :call then val_or_callable.call(*args, &blk) else blk.call(*block_args) if blk val_or_callable end end yield self ensure metaclass.send :undef_method, name metaclass.send :alias_method, name, new_name metaclass.send :undef_method, new_name end end PK ]_cGG-gems/minitest-5.13.0/lib/minitest/parallel.rbnu[module Minitest module Parallel #:nodoc: ## # The engine used to run multiple tests in parallel. class Executor ## # The size of the pool of workers. attr_reader :size ## # Create a parallel test executor of with +size+ workers. def initialize size @size = size @queue = Queue.new @pool = nil end ## # Start the executor def start @pool = size.times.map { Thread.new(@queue) do |queue| Thread.current.abort_on_exception = true while (job = queue.pop) klass, method, reporter = job reporter.synchronize { reporter.prerecord klass, method } result = Minitest.run_one_method klass, method reporter.synchronize { reporter.record result } end end } end ## # Add a job to the queue def << work; @queue << work; end ## # Shuts down the pool of workers by signalling them to quit and # waiting for them all to finish what they're currently working # on. def shutdown size.times { @queue << nil } @pool.each(&:join) end end module Test # :nodoc: def _synchronize; Minitest::Test.io_lock.synchronize { yield }; end # :nodoc: module ClassMethods # :nodoc: def run_one_method klass, method_name, reporter Minitest.parallel_executor << [klass, method_name, reporter] end def test_order :parallel end end end end end PK ]oz)gems/minitest-5.13.0/lib/minitest/hell.rbnu[require "minitest/parallel" class Minitest::Test parallelize_me! end begin require "minitest/proveit" rescue LoadError warn "NOTE: `gem install minitest-proveit` for even more hellish tests" end PK ]9M M 1gems/minitest-5.13.0/lib/minitest/pride_plugin.rbnu[require "minitest" module Minitest def self.plugin_pride_options opts, _options # :nodoc: opts.on "-p", "--pride", "Pride. Show your testing pride!" do PrideIO.pride! end end def self.plugin_pride_init options # :nodoc: if PrideIO.pride? then klass = ENV["TERM"] =~ /^xterm|-256color$/ ? PrideLOL : PrideIO io = klass.new options[:io] self.reporter.reporters.grep(Minitest::Reporter).each do |rep| rep.io = io if rep.io.tty? end end end ## # Show your testing pride! class PrideIO ## # Activate the pride plugin. Called from both -p option and minitest/pride def self.pride! @pride = true end ## # Are we showing our testing pride? def self.pride? @pride ||= false end # Start an escape sequence ESC = "\e[" # End the escape sequence NND = "#{ESC}0m" # The IO we're going to pipe through. attr_reader :io def initialize io # :nodoc: @io = io # stolen from /System/Library/Perl/5.10.0/Term/ANSIColor.pm # also reference http://en.wikipedia.org/wiki/ANSI_escape_code @colors ||= (31..36).to_a @size = @colors.size @index = 0 end ## # Wrap print to colorize the output. def print o case o when "." then io.print pride o when "E", "F" then io.print "#{ESC}41m#{ESC}37m#{o}#{NND}" when "S" then io.print pride o else io.print o end end def puts *o # :nodoc: o.map! { |s| s.to_s.sub(/Finished/) { @index = 0 "Fabulous run".split(//).map { |c| pride(c) }.join } } io.puts(*o) end ## # Color a string. def pride string string = "*" if string == "." c = @colors[@index % @size] @index += 1 "#{ESC}#{c}m#{string}#{NND}" end def method_missing msg, *args # :nodoc: io.send(msg, *args) end end ## # If you thought the PrideIO was colorful... # # (Inspired by lolcat, but with clean math) class PrideLOL < PrideIO PI_3 = Math::PI / 3 # :nodoc: def initialize io # :nodoc: # walk red, green, and blue around a circle separated by equal thirds. # # To visualize, type this into wolfram-alpha: # # plot (3*sin(x)+3), (3*sin(x+2*pi/3)+3), (3*sin(x+4*pi/3)+3) # 6 has wide pretty gradients. 3 == lolcat, about half the width @colors = (0...(6 * 7)).map { |n| n *= 1.0 / 6 r = (3 * Math.sin(n ) + 3).to_i g = (3 * Math.sin(n + 2 * PI_3) + 3).to_i b = (3 * Math.sin(n + 4 * PI_3) + 3).to_i # Then we take rgb and encode them in a single number using base 6. # For some mysterious reason, we add 16... to clear the bottom 4 bits? # Yes... they're ugly. 36 * r + 6 * g + b + 16 } super end ## # Make the string even more colorful. Damnit. def pride string c = @colors[@index % @size] @index += 1 "#{ESC}38;5;#{c}m#{string}#{NND}" end end end PK ]T1gems/minitest-5.13.0/lib/minitest/expectations.rbnu[## # It's where you hide your "assertions". # # Please note, because of the way that expectations are implemented, # all expectations (eg must_equal) are dependent upon a thread local # variable +:current_spec+. If your specs rely on mixing threads into # the specs themselves, you're better off using assertions or the new # _(value) wrapper. For example: # # it "should still work in threads" do # my_threaded_thingy do # (1+1).must_equal 2 # bad # assert_equal 2, 1+1 # good # _(1 + 1).must_equal 2 # good # value(1 + 1).must_equal 2 # good, also #expect # end # end module Minitest::Expectations ## # See Minitest::Assertions#assert_empty. # # collection.must_be_empty # # :method: must_be_empty infect_an_assertion :assert_empty, :must_be_empty, :unary ## # See Minitest::Assertions#assert_equal # # a.must_equal b # # :method: must_equal infect_an_assertion :assert_equal, :must_equal ## # See Minitest::Assertions#assert_in_delta # # n.must_be_close_to m [, delta] # # :method: must_be_close_to infect_an_assertion :assert_in_delta, :must_be_close_to alias :must_be_within_delta :must_be_close_to # :nodoc: ## # See Minitest::Assertions#assert_in_epsilon # # n.must_be_within_epsilon m [, epsilon] # # :method: must_be_within_epsilon infect_an_assertion :assert_in_epsilon, :must_be_within_epsilon ## # See Minitest::Assertions#assert_includes # # collection.must_include obj # # :method: must_include infect_an_assertion :assert_includes, :must_include, :reverse ## # See Minitest::Assertions#assert_instance_of # # obj.must_be_instance_of klass # # :method: must_be_instance_of infect_an_assertion :assert_instance_of, :must_be_instance_of ## # See Minitest::Assertions#assert_kind_of # # obj.must_be_kind_of mod # # :method: must_be_kind_of infect_an_assertion :assert_kind_of, :must_be_kind_of ## # See Minitest::Assertions#assert_match # # a.must_match b # # :method: must_match infect_an_assertion :assert_match, :must_match ## # See Minitest::Assertions#assert_nil # # obj.must_be_nil # # :method: must_be_nil infect_an_assertion :assert_nil, :must_be_nil, :unary ## # See Minitest::Assertions#assert_operator # # n.must_be :<=, 42 # # This can also do predicates: # # str.must_be :empty? # # :method: must_be infect_an_assertion :assert_operator, :must_be, :reverse ## # See Minitest::Assertions#assert_output # # proc { ... }.must_output out_or_nil [, err] # # :method: must_output infect_an_assertion :assert_output, :must_output, :block ## # See Minitest::Assertions#assert_raises # # proc { ... }.must_raise exception # # :method: must_raise infect_an_assertion :assert_raises, :must_raise, :block ## # See Minitest::Assertions#assert_respond_to # # obj.must_respond_to msg # # :method: must_respond_to infect_an_assertion :assert_respond_to, :must_respond_to, :reverse ## # See Minitest::Assertions#assert_same # # a.must_be_same_as b # # :method: must_be_same_as infect_an_assertion :assert_same, :must_be_same_as ## # See Minitest::Assertions#assert_silent # # proc { ... }.must_be_silent # # :method: must_be_silent infect_an_assertion :assert_silent, :must_be_silent, :block ## # See Minitest::Assertions#assert_throws # # proc { ... }.must_throw sym # # :method: must_throw infect_an_assertion :assert_throws, :must_throw, :block ## # See Minitest::Assertions#assert_path_exists # # _(some_path).path_must_exist # # :method: path_must_exist infect_an_assertion :assert_path_exists, :path_must_exist, :unary ## # See Minitest::Assertions#refute_path_exists # # _(some_path).path_wont_exist # # :method: path_wont_exist infect_an_assertion :refute_path_exists, :path_wont_exist, :unary ## # See Minitest::Assertions#refute_empty # # collection.wont_be_empty # # :method: wont_be_empty infect_an_assertion :refute_empty, :wont_be_empty, :unary ## # See Minitest::Assertions#refute_equal # # a.wont_equal b # # :method: wont_equal infect_an_assertion :refute_equal, :wont_equal ## # See Minitest::Assertions#refute_in_delta # # n.wont_be_close_to m [, delta] # # :method: wont_be_close_to infect_an_assertion :refute_in_delta, :wont_be_close_to alias :wont_be_within_delta :wont_be_close_to # :nodoc: ## # See Minitest::Assertions#refute_in_epsilon # # n.wont_be_within_epsilon m [, epsilon] # # :method: wont_be_within_epsilon infect_an_assertion :refute_in_epsilon, :wont_be_within_epsilon ## # See Minitest::Assertions#refute_includes # # collection.wont_include obj # # :method: wont_include infect_an_assertion :refute_includes, :wont_include, :reverse ## # See Minitest::Assertions#refute_instance_of # # obj.wont_be_instance_of klass # # :method: wont_be_instance_of infect_an_assertion :refute_instance_of, :wont_be_instance_of ## # See Minitest::Assertions#refute_kind_of # # obj.wont_be_kind_of mod # # :method: wont_be_kind_of infect_an_assertion :refute_kind_of, :wont_be_kind_of ## # See Minitest::Assertions#refute_match # # a.wont_match b # # :method: wont_match infect_an_assertion :refute_match, :wont_match ## # See Minitest::Assertions#refute_nil # # obj.wont_be_nil # # :method: wont_be_nil infect_an_assertion :refute_nil, :wont_be_nil, :unary ## # See Minitest::Assertions#refute_operator # # n.wont_be :<=, 42 # # This can also do predicates: # # str.wont_be :empty? # # :method: wont_be infect_an_assertion :refute_operator, :wont_be, :reverse ## # See Minitest::Assertions#refute_respond_to # # obj.wont_respond_to msg # # :method: wont_respond_to infect_an_assertion :refute_respond_to, :wont_respond_to, :reverse ## # See Minitest::Assertions#refute_same # # a.wont_be_same_as b # # :method: wont_be_same_as infect_an_assertion :refute_same, :wont_be_same_as end PK ]I,gems/minitest-5.13.0/lib/minitest/autorun.rbnu[begin require "rubygems" gem "minitest" rescue Gem::LoadError # do nothing end require "minitest" require "minitest/spec" require "minitest/mock" require "minitest/hell" if ENV["MT_HELL"] Minitest.autorun PK ]^ѿ##)gems/minitest-5.13.0/lib/minitest/spec.rbnu[require "minitest/test" class Module # :nodoc: def infect_an_assertion meth, new_name, dont_flip = false # :nodoc: block = dont_flip == :block dont_flip = false if block # warn "%-22p -> %p %p" % [meth, new_name, dont_flip] self.class_eval <<-EOM, __FILE__, __LINE__ + 1 def #{new_name} *args where = Minitest.filter_backtrace(caller).first where = where.split(/:in /, 2).first # clean up noise warn "DEPRECATED: global use of #{new_name} from #\{where}. Use _(obj).#{new_name} instead. This will fail in Minitest 6." Minitest::Expectation.new(self, Minitest::Spec.current).#{new_name}(*args) end EOM Minitest::Expectation.class_eval <<-EOM, __FILE__, __LINE__ + 1 def #{new_name} *args raise "Calling ##{new_name} outside of test." unless ctx case when #{!!dont_flip} then ctx.#{meth}(target, *args) when #{block} && Proc === target then ctx.#{meth}(*args, &target) else ctx.#{meth}(args.first, target, *args[1..-1]) end end EOM end end Minitest::Expectation = Struct.new :target, :ctx # :nodoc: ## # Kernel extensions for minitest module Kernel ## # Describe a series of expectations for a given target +desc+. # # Defines a test class subclassing from either Minitest::Spec or # from the surrounding describe's class. The surrounding class may # subclass Minitest::Spec manually in order to easily share code: # # class MySpec < Minitest::Spec # # ... shared code ... # end # # class TestStuff < MySpec # it "does stuff" do # # shared code available here # end # describe "inner stuff" do # it "still does stuff" do # # ...and here # end # end # end # # For more information on getting started with writing specs, see: # # http://www.rubyinside.com/a-minitestspec-tutorial-elegant-spec-style-testing-that-comes-with-ruby-5354.html # # For some suggestions on how to improve your specs, try: # # http://betterspecs.org # # but do note that several items there are debatable or specific to # rspec. # # For more information about expectations, see Minitest::Expectations. def describe desc, *additional_desc, &block # :doc: stack = Minitest::Spec.describe_stack name = [stack.last, desc, *additional_desc].compact.join("::") sclas = stack.last || if Class === self && kind_of?(Minitest::Spec::DSL) then self else Minitest::Spec.spec_type desc, *additional_desc end cls = sclas.create name, desc stack.push cls cls.class_eval(&block) stack.pop cls end private :describe end ## # Minitest::Spec -- The faster, better, less-magical spec framework! # # For a list of expectations, see Minitest::Expectations. class Minitest::Spec < Minitest::Test def self.current # :nodoc: Thread.current[:current_spec] end def initialize name # :nodoc: super Thread.current[:current_spec] = self end ## # Oh look! A Minitest::Spec::DSL module! Eat your heart out DHH. module DSL ## # Contains pairs of matchers and Spec classes to be used to # calculate the superclass of a top-level describe. This allows for # automatically customizable spec types. # # See: register_spec_type and spec_type TYPES = [[//, Minitest::Spec]] ## # Register a new type of spec that matches the spec's description. # This method can take either a Regexp and a spec class or a spec # class and a block that takes the description and returns true if # it matches. # # Eg: # # register_spec_type(/Controller$/, Minitest::Spec::Rails) # # or: # # register_spec_type(Minitest::Spec::RailsModel) do |desc| # desc.superclass == ActiveRecord::Base # end def register_spec_type *args, &block if block then matcher, klass = block, args.first else matcher, klass = *args end TYPES.unshift [matcher, klass] end ## # Figure out the spec class to use based on a spec's description. Eg: # # spec_type("BlahController") # => Minitest::Spec::Rails def spec_type desc, *additional TYPES.find { |matcher, _klass| if matcher.respond_to? :call then matcher.call desc, *additional else matcher === desc.to_s end }.last end def describe_stack # :nodoc: Thread.current[:describe_stack] ||= [] end def children # :nodoc: @children ||= [] end def nuke_test_methods! # :nodoc: self.public_instance_methods.grep(/^test_/).each do |name| self.send :undef_method, name end end ## # Define a 'before' action. Inherits the way normal methods should. # # NOTE: +type+ is ignored and is only there to make porting easier. # # Equivalent to Minitest::Test#setup. def before _type = nil, &block define_method :setup do super() self.instance_eval(&block) end end ## # Define an 'after' action. Inherits the way normal methods should. # # NOTE: +type+ is ignored and is only there to make porting easier. # # Equivalent to Minitest::Test#teardown. def after _type = nil, &block define_method :teardown do self.instance_eval(&block) super() end end ## # Define an expectation with name +desc+. Name gets morphed to a # proper test method name. For some freakish reason, people who # write specs don't like class inheritance, so this goes way out of # its way to make sure that expectations aren't inherited. # # This is also aliased to #specify and doesn't require a +desc+ arg. # # Hint: If you _do_ want inheritance, use minitest/test. You can mix # and match between assertions and expectations as much as you want. def it desc = "anonymous", &block block ||= proc { skip "(no tests defined)" } @specs ||= 0 @specs += 1 name = "test_%04d_%s" % [ @specs, desc ] undef_klasses = self.children.reject { |c| c.public_method_defined? name } define_method name, &block undef_klasses.each do |undef_klass| undef_klass.send :undef_method, name end name end ## # Essentially, define an accessor for +name+ with +block+. # # Why use let instead of def? I honestly don't know. def let name, &block name = name.to_s pre, post = "let '#{name}' cannot ", ". Please use another name." methods = Minitest::Spec.instance_methods.map(&:to_s) - %w[subject] raise ArgumentError, "#{pre}begin with 'test'#{post}" if name =~ /\Atest/ raise ArgumentError, "#{pre}override a method in Minitest::Spec#{post}" if methods.include? name define_method name do @_memoized ||= {} @_memoized.fetch(name) { |k| @_memoized[k] = instance_eval(&block) } end end ## # Another lazy man's accessor generator. Made even more lazy by # setting the name for you to +subject+. def subject &block let :subject, &block end def create name, desc # :nodoc: cls = Class.new(self) do @name = name @desc = desc nuke_test_methods! end children << cls cls end def name # :nodoc: defined?(@name) ? @name : super end def to_s # :nodoc: name # Can't alias due to 1.8.7, not sure why end attr_reader :desc # :nodoc: alias :specify :it ## # Rdoc... why are you so dumb? module InstanceMethods ## # Takes a value or a block and returns a value monad that has # all of Expectations methods available to it. # # _(1 + 1).must_equal 2 # # And for blocks: # # _ { 1 + "1" }.must_raise TypeError # # This method of expectation-based testing is preferable to # straight-expectation methods (on Object) because it stores its # test context, bypassing our hacky use of thread-local variables. # # NOTE: At some point, the methods on Object will be deprecated # and then removed. # # It is also aliased to #value and #expect for your aesthetic # pleasure: # # _(1 + 1).must_equal 2 # value(1 + 1).must_equal 2 # expect(1 + 1).must_equal 2 def _ value = nil, &block Minitest::Expectation.new block || value, self end alias value _ alias expect _ def before_setup # :nodoc: super Thread.current[:current_spec] = self end end def self.extended obj # :nodoc: obj.send :include, InstanceMethods end end extend DSL TYPES = DSL::TYPES # :nodoc: end require "minitest/expectations" class Object # :nodoc: include Minitest::Expectations unless ENV["MT_NO_EXPECTATIONS"] end PK ]Lj)p(gems/minitest-5.13.0/lib/hoe/minitest.rbnu[# :stopdoc: class Hoe end module Hoe::Minitest def minitest? self.name == "minitest" end def initialize_minitest unless minitest? then dir = "../../minitest/dev/lib" Hoe.add_include_dirs dir if File.directory? dir end gem "minitest" require "minitest" version = Minitest::VERSION.split(/\./).first(2).join(".") dependency "minitest", "~> #{version}", :development unless minitest? or ENV["MT_NO_ISOLATE"] end def define_minitest_tasks self.testlib = :minitest # make sure we use the gemmed minitest on 1.9 self.test_prelude = 'gem "minitest"' unless minitest? or ENV["MT_NO_ISOLATE"] end end PK ]\!gems/minitest-5.13.0/History.rdocnu[=== 5.13.0 / 2019-10-29 * 9 minor enhancements: * Added Minitest::Guard#osx? * Added examples to documentation for assert_raises. (lxxxvi) * Added expectations #path_must_exist and #path_wont_exist. Not thrilled with the names. * Added fail_after(year, month, day, msg) to allow time-bombing after a deadline. * Added skip_until(year, month, day, msg) to allow deferring until a deadline. * Deprecated Minitest::Guard#maglev? * Deprecated Minitest::Guard#rubinius? * Finally added assert_path_exists and refute_path_exists. (deivid-rodriguez) * Refactored and pulled Assertions#things_to_diff out of #diff. (BurdetteLamar) * 3 bug fixes: * Fix autorun bug that affects fork exit status in tests. (dylanahsmith/jhawthorn) * Improved documentation for _/value/expect, especially for blocks. (svoop) * Support new Proc#to_s format. (ko1) === 5.12.2 / 2019-09-28 * 1 bug fix: * After chatting w/ @y-yagi and others, decided to lower support to include ruby 2.2. === 5.12.1 / 2019-09-28 * 1 minor enhancement: * Added documentation for Reporter classes. (sshaw) * 3 bug fixes: * Avoid using 'match?' to support older ruby versions. (y-yagi) * Fixed broken link to reference on goodness-of-fit testing. (havenwood) * Update requirements in readme and Rakefile/hoe spec. === 5.12.0 / 2019-09-22 * 8 minor enhancements: * Added a descriptive error if assert_output or assert_raises called without a block. (okuramasafumi) * Changed mu_pp_for_diff to make having both \n and \\n easier to debug. * Deprecated $N for specifying number of parallel test runners. Use MT_CPU. * Deprecated use of global expectations. To be removed from MT6. * Extended Assertions#mu_pp to encoding validity output for strings to improve diffs. * Extended Assertions#mu_pp to output encoding and validity if invalid to improve diffs. * Extended Assertions#mu_pp_for_diff to make escaped newlines more obvious in diffs. * Fail gracefully when expectation used outside of `it`. * 3 bug fixes: * Check `option[:filter]` klass before match. Fixes 2.6 warning. (y-yagi) * Fixed Assertions#diff from recalculating if set to nil * Fixed spec section of readme to not use deprecated global expectations. (CheezItMan) === 5.11.3 / 2018-01-26 * 1 bug fix: * Pushed #error? up to Reportable module. (composerinteralia) === 5.11.2 / 2018-01-25 * 1 minor enhancement: * Reversed Test < Result. Back to < Runnable and using Reportable for shared code. * 2 bug fixes: * Fixed Result#location for instances of Test. (alexisbernard) * Fixed deprecation message for Runnable#marshal_dump. (y-yagi) === 5.11.1 / 2018-01-02 * 1 bug fix: * Fixed Result (a superclass of Test) overriding Runnable's name accessors. (y-yagi, MSP-Greg) === 5.11.0 / 2018-01-01 * 2 major enhancements: * Added Minitest::Result and Minitest::Result.from(runnable). * Changed Minitest::Test to subclass Result and refactored methods up. * 7 minor enhancements: * Added --no-plugins and MT_NO_PLUGINS to bypass MT plugin autoloading. Helps with bad actors installed globally. * Added bench_performance_{logarithmic,power} for spec-style benchmarks. (rickhull) * Added deprecation warning for Runnable#marshal_dump. * Minitest.run_one_method now checks for instance of Result, not exact same class. * Minitest::Test.run returns a Result version of self, not self. * ProgressReporter#prerecord now explicitly prints klass.name. Allows for fakers. * 4 bug fixes: * Object.stub no longer calls the passed block if stubbed with a callable. * Object.stub now passes blocks down to the callable result. * Pushed Minitest::Test#time & #time_it up to Runnable. * Test nil equality directly in assert_equal. Fixes #679. (voxik) === 5.11.0b1 / 2017-12-20 * 2 major enhancements: * Added Minitest::Result and Minitest::Result.from(runnable). * Changed Minitest::Test to subclass Result and refactored methods up. * 6 minor enhancements: * Added --no-plugins and MT_NO_PLUGINS to bypass MT plugin autoloading. Helps with bad actors installed globally. * Added bench_performance_{logarithmic,power} for spec-style benchmarks. (rickhull) * Minitest.run_one_method now checks for instance of Result, not exact same class. * Minitest::Test.run returns a Result version of self, not self. * ProgressReporter#prerecord now explicitly prints klass.name. Allows for fakers. * Removed Runnable.marshal_dump/load. * 4 bug fixes: * Object.stub no longer calls the passed block if stubbed with a callable. * Object.stub now passes blocks down to the callable result. * Pushed Minitest::Test#time & #time_it up to Runnable. * Test nil equality directly in assert_equal. Fixes #679. (voxik) === 5.10.3 / 2017-07-21 * 1 minor enhancement: * Extended documentation for Mock#expect for multiple calls to mock object. (insti) * 2 bug fixes: * Finished off missing doco. * Fixed verbose output on parallelize_me! classes. (chanks) === 5.10.2 / 2017-05-09 * 1 minor enhancement: * Added suggestion in minitest/hell to install minitest/proveit. * 7 bug fixes: * Expand MT6 to Minitest 6. (xaviershay) * Fixed location of assert_send deprecation. (rab) * Fixed location of nil assert_equal deprecation to work with expectations. (jeremyevans) * Fixed minitest/hell to use parallelize_me! (azul) * Made deprecation use warn so -W0 will silence it. * Workaround for rdoc nodoc generation bug that totally f'd up minitest doco. (Paxa) * Write aggregated_results directly to the IO object to avoid mixed encoding errors. (tenderlove) === 5.10.1 / 2016-12-01 * 1 bug fix: * Added a hack/kludge to deal with missing #prerecord on reporters that aren't properly subclassing AbstractReporter (I'm looking at you minitest-reporters) === 5.10.0 / 2016-11-30 * 1 major enhancement: * Deprecated ruby 1.8, 1.9, possibly 2.0, assert_send, & old MiniTest namespace. * 3 minor enhancements: * Warn if assert_equal expects a nil. This will fail in minitest 6+. (tenderlove) * Added AbstractReporter#prerecord and extended ProgressReporter and CompositeReporter to use it. * Minor optimization: remove runnables with no runnable methods before run. * 3 bug fixes: * Fix assert_throw rescuing any NameError and ArgumentError. (waldyr) * Clean up (most of the) last remaining vestiges of minitest/unit. * 2.4: removed deprecation warnings when referring to Fixnum. === 5.9.1 / 2016-09-25 * 2 bug fixes: * Re-release to refresh gem certificate signing. ugh. * Fixed hoe/minitest to not augment load path if we're actually testing minitest. === 5.9.0 / 2016-05-16 * 8 minor enhancements: * Added Minitest.info_signal accessors to customize signal for test run info. (nate) * Added assert_mock to make it more clear that you're testing w/ them. * Added negative filter by test name. (utilum) * Added warning to README that 1.8 and 1.9 support will be dropped in minitest 6. * Automatically activate minitest/hell if $MT_HELL is defined. * Improved default error messages for assert and refute. (bhenderson) * minitest/hell now tries to require minitest/proveit * mu_pp for strings prints out non-standard encodings to improve assert_equal diffs. * 1 bug fix: * Removed Interrupt from PASSTHROUGH_EXCEPTIONS (already handled). (waldyr) === 5.8.5 / 2016-09-25 * 2 bug fixes: * Re-release to refresh gem certificate signing. ugh. * Fixed hoe/minitest to not augment load path if we're actually testing minitest. === 5.8.4 / 2016-01-21 * 1 bug fix: * Allow Minitest::Assertion to pass through assert_raises so inner failures are dealt with first. === 5.8.3 / 2015-11-17 * 1 minor enhancement: * Added extra note about mocks and threads to readme. (zamith) * 1 bug fix: * Fixed bug in Mock#verify. (pithub/zamith) === 5.8.2 / 2015-10-26 * 1 bug fix: * Fixed using parallelize_me! and capture_io (or any locking io). (arlt/tenderlove) === 5.8.1 / 2015-09-23 * 1 minor enhancement: * Refactor assert_raises to be cleaner and to pass SystemExit and SignalException. (bhenderson) === 5.8.0 / 2015-08-06 * 2 minor enhancements: * Add optional delegation mechanism to extend object with a mock. (zamith) * Return early if there are no filtered methods. (jeremyevans) * 1 bug fix: * Don't extend io with pride if io is not a tty. (toy) === 5.7.0 / 2015-05-27 * 1 major enhancement: * assert_raises now matches subclasses of the expected exception types. (jeremyevans) * 3 minor enhancements: * Added :block type for minitest/spec's #infect_an_assertion. (jeremyevans) * Inline verification error messages in minitest/mock for GC performance. (zamith) * assert_raises defaults to RuntimeError if not specified. (jeremyevans) * 4 bug fixes: * Added 'class' to minitest/mock's overridden_methods list. (zamith) * Added file/line to infect_an_assertion's class_eval call. (jeremyevans) * Cleared UnexpectedError's mesg w/ generic string. * Fixed non-proc-oriented expectations when used on proc target. (jeremyevans) === 5.6.1 / 2015-04-27 * 2 bug fixes: * Added Minitest.clock_time and switched all Time.now to it. (tenderlove) * Moved Minitest::Expectations#_ into Minitest::Spec::DSL. === 5.6.0 / 2015-04-13 * 4 major enhancements: * Added Minitest::Expectation value monad. * Added Minitest::Expectations#_ that returns an Expectation. Aliased to value. * All expectations are added to Minitest::Expectation. * At some point, the methods on Object will be deprecated and then removed. * 4 minor enhancements: * Added a note about bundle exec pitfall in ruby 2.2+. (searls) * Lazily start the parallel executor. (tenderlove) * Make mocks more debugger-friendly (edward) * Print out the current test run on interrupt. (riffraff) * 3 bug fixes: * Fix failing test under Windows. (kimhmadsen) * Record mocked calls before they happen so mocks can raise exceptions easier (tho I'm not a fan). (corecode) * Tried to clarify mocks vs stubs terminology better. (kkirsche) === 5.5.1 / 2015-01-09 * 1 bug fix: * Fixed doco problems. (zzak) === 5.5.0 / 2014-12-12 // mri 2.2.0 (as a real gem) * 1 minor enhancement: * Allow seed to be given via ENV for rake test loader sadness: eg rake SEED=42. === 5.4.3 / 2014-11-11 * 2 bug fixes: * Clarified requirements for ruby are now 1.8.7 or better. * Force encode error output in case mal-encoded exception is raised. (jasonrclark) === 5.4.2 / 2014-09-26 * 2 minor enhancements: * Extract teardown method list. * Thanks to minitest-gcstats got a 5-10% speedup via reduced GC! === 5.4.1 / 2014-08-28 * 1 bug fix: * Fixed specs hidden by nesting/ordering bug (blowmage/apotonick) === 5.4.0 / 2014-07-07 * 2 minor enhancements: * Kernel#describe extended to splat additional_desc. * Spec#spec_type extended to take a splat of additional items, passed to matcher procs. * 1 bug fix: * minitest/spec should require minitest/test, not minitest/unit. (doudou) === 5.3.5 / 2014-06-17 * 1 minor enhancement: * Spit and polish (mostly spit). === 5.3.4 / 2014-05-15 * 1 minor enhancement: * Test classes are randomized before running. (judofyr) === 5.3.3 / 2014-04-14 * 1 bug fix: * Fixed using expectations w/ DSL in Test class w/o describe. (blowmage+others) === 5.3.2 / 2014-04-02 * 1 bug fix: * Fixed doco on Assertions.assertions. (xaviershay) === 5.3.1 / 2014-03-14 * 1 minor enhancement: * Modified verbage on bad 'let' names to be more helpful. (Archytaus) * 1 bug fix: * Fixed 2 cases still using MiniTest. (mikesea) === 5.3.0 / 2014-02-25 * 1 minor enhancement: * Mocked methods can take a block to verify state. Seattle.rb 12 bday present from ernie! Thanks!! === 5.2.3 / 2014-02-10 * 1 bug fix: * Fixed Spec#let check to allow overriding of other lets. (mvz) === 5.2.2 / 2014-01-22 * 1 minor enhancement: * Spec#let raises ArgumentError if you override _any_ instance method (except subject). (rynr) * 1 bug fix: * Fixed up benchmark spec doco and added a test to demonstrate. (bhenderson) === 5.2.1 / 2014-01-07 * 1 bug fix: * Properly deal with horrible mix of runtime load errors + other at_exit handlers. (dougo/chqr) === 5.2.0 / 2013-12-13 * 1 minor enhancement: * Change expectations to allow calling most on procs (but not calling the proc). (bhenderson+others) === 5.1.0 / 2013-12-05 * 1 minor enhancement: * Use a Queue for scheduling parallel tests. (tenderlove) * 1 bug fix: * Fixed misspelling in doco. (amatsuda) === 5.0.8 / 2013-09-20 * 1 bug fix: * Fixed siginfo handler by rearranging reporters and fixing to_s. (tenderlove) === 5.0.7 / 2013-09-05 * 2 minor enhancements: * Added clarification about the use of thread local variables in expectations. (jemc) * Added extra message about skipped tests, if any. Disable globally with $MT_NO_SKIP_MSG. * 2 bug fixes: * Only require minitest, not minitest/autorun in pride_plugin. (judofyr) * Require rubygems in load_plugins in case you're not using minitest/autorun. === 5.0.6 / 2013-06-28 * 3 minor enhancements: * Allow stub to pass args to blocks. (swindsor) * Improved warning message about minitest/autorun to address 1.9's minitest/autorun. * Made minitest/test require minitest as needed. For lib writers. (erikh) * 1 bug fix: * Fixed missing require in minitest/test. (erikh) === 4.7.5 / 2013-06-21 // mri 2.1.1 * 2 bug fixes: * Fix Spec#describe_stack to be thread local. * Fix multithreaded test failures by defining Time local to mock test namespace === 5.0.5 / 2013-06-20 * 6 bug fixes: * DOH! Fixed the rest of the new casing on Minitest. (splattael) * Fixed typo on minitest/mock rdoc. (mrgilman/guiceolin) * Make Spec::DSL.describe_stack thread local to avoid failing on my own tests. * Make a fake Time.now local to the tests so they won't interfere with real reporter timings. * Make everything mockable by wrapping all 'special' methods in a smarter wrapper. (bestie) * Raise ArgumentError if let name starts with 'test'. (johnmaxwell) === 5.0.4 / 2013-06-07 * 5 minor enhancements: * Added AbstractReporter, defining required Reporter API to quack properly. * Added doco for writing reporters. * Refactored Reporter into ProgressReporter and SummaryReporter. (idea: phiggins, code:me+scotch) * Refactored SummaryReporter pushing up to StatisticsReporter. (phiggins) * Removed Reporter#run_and_report... cleaner, but doesn't "fit" in the API. === 5.0.3 / 2013-05-29 * 4 minor enhancements: * Added Runnable.with_info_handler and Runnable.on_signal. * Moved io.sync restore to Reporter#run_and_report. * Refactored inner loop of Reporter#report to #to_s. Callable for status updates. * Restored MT4's mid-run report (^t). (tenderlove). === 5.0.2 / 2013-05-20 * 3 bug fixes: * Gem.find_files is smarter than I remember... cause I wrote it that way. *sigh* I'm getting old. * Pride wasn't doing puts through its #io. (tmiller/tenderlove) * Replaced Runnable#dup and Test#dup with marshal_dump/load. Too many problems cropping up on untested rails code. (tenderlove/rubys) === 5.0.1 / 2013-05-14 * 2 bug fixes: * Documented Assertions' need for @assertions to be defined by the includer. * Only load one plugin version per name. Tries for latest. === 5.0.0 / 2013-05-10 Oh god... here we go... Minitest 5: * 4 deaths in the family: * MiniTest.runner is dead. No more manager objects. * MiniTest::Unit#record is dead. Use a Reporter instance instead. * MiniTest::Unit._run_* is dead. Runnable things are responsible for their own runs. * MiniTest::Unit.output is dead. No more centralized IO. * 12 major (oft incompatible) changes: * Renamed MiniTest to Minitest. Your pinkies will thank me. (aliased to MiniTest) * Removed MiniTest::Unit entirely. No more manager objects. * Added Minitest::Runnable. Everything minitest can run subclasses this. * Renamed MiniTest::Unit::TestCase to Minitest::Test (subclassing Runnable). * Added Minitest::Benchmark. * Your benchmarks need to move to their own subclass. * Benchmarks using the spec DSL have to have "Bench" somewhere in their describe. * MiniTest::Unit.after_tests moved to Minitest.after_tests * MiniTest::Unit.autorun is now Minitest.autorun. Just require minitest/autorun pls. * Removed ParallelEach#grep since it isn't used anywhere. * Renamed Runnable#__name__ to Runnable#name (but uses @NAME internally). * Runnable#run needs to return self. Allows for swapping of results as needed. * 8 minor moves: * Moved Assertions module to minitest/assertions.rb * Moved Expectations module to minitest/expectations.rb * Moved Test to minitest/test.rb * Moved everything else in minitest/unit.rb to minitest.rb * minitest/unit.rb is now just a small (user-test only) compatibility layer. * Moved most of minitest/pride into minitest/pride_plugin. * minitest/pride now just activates pride. * Moved ParallelEach under Minitest. * 9 additions: * Added a plugin system that can extend command-line options. * Added Minitest.extensions. * Added Minitest.reporter (only available during startup). * Added Minitest.run(args). This is the very top of any Minitest run. * Added Minitest::Reporter. Everything minitest can report goes through here. * Minitest.reporter is a composite so you can add your own. * Added Minitest::CompositeReporter. Much easier to extend with your own reporters. * Added UnexpectedError, an Assertion subclass, to wrap up errors. * Minitest::Test#run is now freakin' beautiful. 47 -> 17 loc * 11 other: * Removed Object.infect_with_assertions (it was already dead code). * Runnables are responsible for knowing their result_code (eg "." or "F"). * Minitest.autorun now returns boolean, not exit code. * Added FAQ entry for extending via modules. (phiggins) * Implement Runnable#dup to cleanse state back to test results. Helps with serialization. pair:tenderlove * Moved ParallelEach under Minitest. * Runnable#run needs to return self. Allows for swapping of results as needed. * Minitest.init_plugins passes down options. * Minitest.load_plugins only loads once. * Fixed minitest/pride to work with rake test loader again. (tmiller) * Added count/size to ParallelEach to fix use w/in stdlib's test/unit. :( (btaitelb) * 5 voodoo: * Removed mutex from minitest.rb (phiggins) * Removed mutex from test.rb (phiggins) * Removed Minitest::Reporter.synchronize (phiggins) * Removed Minitest::Test.synchronize (phiggins) * Upon loading minitest/parallel_each, record, capture_io and capture_subprocess_io are doped with synchronization code. (phiggins) === 4.7.4 / 2013-05-01 This is probably the last release of the 4.x series. It will be merged to ruby and will be put into maintenance mode there. I'm not set in stone on this, but at this point further development of minitest (5+) will be gem-only. It is just too hard to work w/in ruby-core w/ test-unit compatibility holding minitest development back. * 2 minor enhancements: * Added count/size to ParallelEach to fix use w/in stdlib's test/unit. :( (btaitelb) * Allow disabling of info_signal handler in runner. (erikh) === 4.7.3 / 2013-04-20 * 1 bug fix: * Reverted stubbing of module methods change. Stub the user, not the impl. (ab9/tyabe) === 4.7.2 / 2013-04-18 * 2 bug fixes: * Fixed inconsistency in refute_in_delta/epsilon. I double negatived my logic. (nettsundere) * Fixed stubbing of module methods (eg Kernel#sleep). (steveklabnik) === 4.7.1 / 2013-04-09 * 1 minor enhancement: * Added FAQ section to README * 1 bug fix: * Fixed bug where guard runs tests bypassing minitest/autorun and an ivar isn't set right. (darrencauthon) === 4.7.0 / 2013-03-18 * 1 major enhancement: * Refactored MiniTest::Spec into MiniTest::Spec::DSL. * 1 bug fix: * Removed $DEBUG handler that detected when test/unit and minitest were both loaded. (tenderlove) === 4.6.2 / 2013-02-27 * 1 minor enhancement: * Change error output to match Class#method, making it easier to use -n filter. === 4.6.1 / 2013-02-14 * 1 bug fix: * Fixed an option processing bug caused by test/unit's irresponsibly convoluted code. (floehopper) === 4.6.0 / 2013-02-07 * 3 major enhancements: * Removed ::reset_setup_teardown_hooks * Removed the long deprecated assert_block * Removed the long deprecated lifecycle hooks: add_(setup|teardown)_hook * 1 minor enhancement: * Allow filtering tests by suite name as well as test name. (lazyatom) * 2 bug fixes: * Made hex handling (eg object_ids) in mu_pp_for_diff more specific. (maxim) * nodoc top-level module. (zzak) === 4.5.0 / 2013-01-22 * 1 major enhancement: * Rearranged minitest/unit.rb so NO parallelization code is loaded/used until you opt-in. * 4 minor enhancements: * Added TestCase#skipped? for teardown guards * Added maglev? guard * Document that record can be sent twice if teardown fails or errors (randycoulman) * Errors in teardown are now recorded. (randycoulman) * 3 bug fixes: * Added hacks and skips to get clean test runs on maglev * Modified float tests for maglev float output differences. Not sure this is right. Not sure I care. * Test for existance of diff.exe instead of assuming they have devkit. (blowmage/Cumbayah) === 4.4.0 / 2013-01-07 * 3 minor enhancements: * Added fit_logarithic and assert_performance_logarithmic. (ktheory) * Merge processed options so others can mess with defaults. (tenderlove) * TestCase#message can now take another proc to defer custom message cost. (ordinaryzelig/bhenderson) * 1 bug fix: * TestCase#passed? now true if test is skipped. (qanhd) === 4.3.3 / 2012-12-06 * 1 bug fix: * Updated information about stubbing. (daviddavis) === 4.3.2 / 2012-11-27 // mri 2.0.0 * 1 minor enhancement: * Improved assert_equals error message to point you at #== of member objects. (kcurtin) === 4.3.1 / 2012-11-23 * 1 bug fix: * Moved test_children to serial testcase to prevent random failures. === 4.3.0 / 2012-11-17 * 4 minor enhancements: * Allow #autorun to run even if loaded with other test libs that call exit. (sunaku) * Do not include Expectations in Object if $MT_NO_EXPECTATIONS is set (experimental?) * Gave some much needed love to assert_raises. * Mock#expect can take a block to custom-validate args. (gmoothart) === 4.2.0 / 2012-11-02 * 4 major enhancements: * Added minitest/hell - run all your tests through the ringer! * Added support for :parallel test_order to run test cases in parallel. * Removed last_error and refactored runner code to be threadsafe. * _run_suites now runs suites in parallel if they opt-in. * 4 minor enhancements: * Added TestCase#synchronize * Added TestCase.make_my_diffs_pretty! * Added TestCase.parallelize_me! * Lock on capture_io for thread safety (tenderlove) === 4.1.0 / 2012-10-05 * 2 minor enhancements: * Added skip example to readme. (dissolved) * Extracted backtrace filter to object. (tenderlove) * 1 bug fix: * OMG I'm so dumb. Fixed access to deprecated hook class methods. I hate ruby modules. (route) === 4.0.0 / 2012-09-28 * 1 major enhancement: * The names of a privately-used undocumented constants are Super Important™. * 1 minor enhancement: * Support stubbing methods that would be handled via method_missing. (jhsu) * 3 bug fixes: * Add include_private param to MiniTest::Mock#respond_to? (rf-) * Fixed use of minitest/pride with --help. (zw963) * Made 'No visible difference.' message more clear. (ckrailo) === 3.5.0 / 2012-09-21 * 1 minor enhancement: * Added #capture_subprocess_io. (route) === 3.4.0 / 2012-09-05 * 2 minor enhancements: * assert_output can now take regexps for expected values. (suggested by stomar) * Clarified that ruby 1.9/2.0's phony gems cause serious confusion for rubygems. === 3.3.0 / 2012-07-26 * 1 major enhancement: * Deprecated add_(setup|teardown)_hook in favor of (before|after)_(setup|teardown) [2013-01-01] * 4 minor enhancements: * Refactored deprecated hook system into a module. * Refactored lifecycle hooks into a module. * Removed after_setup/before_teardown + run_X_hooks from Spec. * Spec#before/after now do a simple define_method and call super. DUR. * 2 bug fixes: * Fixed #passed? when used against a test that called flunk. (floehopper) * Fixed rdoc bug preventing doco for some expectations. (stomar). === 3.2.0 / 2012-06-26 * 1 minor enhancement: * Stubs now yield self. (peterhellberg) * 1 bug fix: * Fixed verbose test that only fails when run in verbose mode. mmmm irony. === 3.1.0 / 2012-06-13 * 2 minor enhancements: * Removed LONG deprecated Unit.out accessor * Removed generated method name munging from minitest/spec. (ordinaryzelig/tenderlove) === 3.0.1 / 2012-05-24 * 1 bug fix: * I'm a dumbass and refactored into Mock#call. Renamed to #__call so you can mock #call. (mschuerig) === 3.0.0 / 2012-05-08 * 3 major enhancements: * Added Object#stub (in minitest/mock.rb). * Mock#expect mocks are used in the order they're given. * Mock#verify now strictly compares against expect calls. * 3 minor enhancements: * Added caller to deprecation message. * Mock error messages are much prettier. * Removed String check for RHS of assert/refute_match. This lets #to_str work properly. * 1 bug fix: * Support drive letter on Windows. Patch provided from MRI by Usaku NAKAMURA. (ayumin) === 2.12.1 / 2012-04-10 * 1 minor enhancement: * Added ruby releases to History.txt to make it easier to see what you're missing * 1 bug fix: * Rolled my own deprecate msg to allow MT to work with rubygems < 1.7 === 2.12.0 / 2012-04-03 * 4 minor enhancements: * ::it returns test method name (wojtekmach) * Added #record method to runner so runner subclasses can cleanly gather data. * Added Minitest alias for MiniTest because even I forget. * Deprecated assert_block!! Yay!!! * 1 bug fix: * Fixed warning in i_suck_and_my_tests_are_order_dependent! (phiggins) === 2.11.4 / 2012-03-20 * 2 minor enhancements: * Updated known extensions * You got your unicode in my tests! You got your tests in my unicode! (fl00r) * 1 bug fix: * Fixed MiniTest::Mock example in the readme. (conradwt) === 2.11.3 / 2012-02-29 * 2 bug fixes: * Clarified that assert_raises returns the exception for further testing * Fixed assert_in_epsilon when both args are negative. (tamc) === 2.11.2 / 2012-02-14 * 1 minor enhancement: * Display failures/errors on SIGINFO. (tenderlove) * 1 bug fix: * Fixed MiniTest::Unit.after_tests for Ruby 1.9.3. (ysbaddaden) === 2.11.1 / 2012-02-01 * 3 bug fixes: * Improved description for --name argument. (drd) * Ensure Mock#expect's expected args is an Array. (mperham) * Ensure Mock#verify verifies multiple expects of the same method. (chastell) === 2.11.0 / 2012-01-25 * 2 minor enhancements: * Added before / after hooks for setup and teardown. (tenderlove) * Pushed run_setup_hooks down to Spec. (tenderlove) === 2.10.1 / 2012-01-17 * 1 bug fix: * Fixed stupid 1.9 path handling grumble grumble. (graaff) === 2.10.0 / 2011-12-20 * 3 minor enhancements: * Added specs for must/wont be_empty/respond_to/be_kind_of and others. * Added tests for assert/refute predicate. * Split minitest/excludes.rb out to its own gem. * 1 bug fix: * Fixed must_be_empty and wont_be_empty argument handling. (mrsimo) === 2.9.1 / 2011-12-13 * 4 minor enhancements: * Added a ton of tests on spec error message output. * Cleaned up consistency of msg handling on unary expectations. * Improved error messages on assert/refute_in_delta. * infect_an_assertion no longer checks arity and better handles args. * 1 bug fix: * Fixed error message on specs when 2+ args and custom message provided. (chastell) === 2.9.0 / 2011-12-07 * 4 minor enhancements: * Added TestCase.exclude and load_excludes for programmatic filtering of tests. * Added guard methods so you can cleanly skip based on platform/impl * Holy crap! 100% doco! `rdoc -C` ftw * Switch assert_output to test stderr before stdout to possibly improve debugging === 2.8.1 / 2011-11-17 * 1 bug fix: * Ugh. 1.9's test/unit violates my internals. Added const_missing. === 2.8.0 / 2011-11-08 * 2 minor enhancements: * Add a method so that code can be run around a particular test case (tenderlove) * Turn off backtrace filtering if we're running inside a ruby checkout. (drbrain) * 2 bug fixes: * Fixed 2 typos and 2 doc glitches. (splattael) * Remove unused block arguments to avoid creating Proc objects. (k-tsj) === 2.7.0 / 2011-10-25 * 2 minor enhancements: * Include failed values in the expected arg output in MockExpectationError. (nono) * Make minitest/pride work with other 256 color capable terms. (sunaku) * 2 bug fixes: * Clarified the documentation of minitest/benchmark (eregon) * Fixed using expectations in regular unit tests. (sunaku) === 2.6.2 / 2011-10-19 * 1 minor enhancement: * Added link to vim bundle. (sunaku) * 2 bug fixes: * Force gem activation in hoe minitest plugin * Support RUBY_VERSION='2.0.0' (nagachika) === 2.6.1 / 2011-09-27 * 2 bug fixes: * Alias Spec.name from Spec.to_s so it works when @name is nil (nathany) * Fixed assert and refute_operator where second object has a bad == method. === 2.6.0 / 2011-09-13 * 2 minor enhancements: * Added specify alias for it and made desc optional. * Spec#must_be and #wont_be can be used with predicates (metaskills) * 1 bug fix: * Fixed Mock.respond_to?(var) to work with strings. (holli) === 2.5.1 / 2011-08-27 // ruby 1.9.3: p0, p125, p34579 * 2 minor enhancements: * Added gem activation for minitest in minitest/autoload to help out 1.9 users * Extended Spec.register_spec_type to allow for procs instead of just regexps. === 2.5.0 / 2011-08-18 * 4 minor enhancements: * Added 2 more arguments against rspec: let & subject in 9 loc! (emmanuel/luis) * Added TestCase.i_suck_and_my_tests_are_order_dependent! * Extended describe to take an optional method name (2 line change!). (emmanuel) * Refactored and extended minitest/pride to do full 256 color support. (lolcat) * 1 bug fix: * Doc fixes. (chastell) === 2.4.0 / 2011-08-09 * 4 minor enhancements: * Added simple examples for all expectations. * Improved Mock error output when args mismatch. * Moved all expectations from Object to MiniTest::Expectations. * infect_with_assertions has been removed due to excessive clever * 4 bug fixes: * Fix Assertions#mu_pp to deal with immutable encoded strings. (ferrous26) * Fix minitest/pride for MacRuby (ferrous26) * Made error output less fancy so it is more readable * Mock shouldn't undef === and inspect. (dgraham) === 2.3.1 / 2011-06-22 * 1 bug fix: * Fixed minitest hoe plugin to be a spermy dep and not depend on itself. === 2.3.0 / 2011-06-15 * 5 minor enhancements: * Add setup and teardown hooks to MiniTest::TestCase. (phiggins) * Added nicer error messages for MiniTest::Mock. (phiggins) * Allow for less specific expected arguments in Mock. (bhenderson/phiggins) * Made MiniTest::Mock a blank slate. (phiggins) * Refactored minitest/spec to use the hooks instead of define_inheritable_method. (phiggins) * 2 bug fixes: * Fixed TestCase's inherited hook. (dchelimsky/phiggins/jamis, the 'good' neighbor) * MiniTest::Assertions#refute_empty should use mu_pp in the default message. (whatthejeff) === 2.2.2 / 2011-06-01 * 2 bug fixes: * Got rid of the trailing period in message for assert_equal. (tenderlove) * Windows needs more flushing. (Akio Tajima) === 2.2.1 / 2011-05-31 * 1 bug fix: * My _ONE_ non-rubygems-using minitest user goes to Seattle.rb! === 2.2.0 / 2011-05-29 * 6 minor enhancements: * assert_equal (and must_equal) now tries to diff output where it makes sense. * Added Assertions#diff(exp, act) to be used by assert_equal. * Added Assertions#mu_pp_for_diff * Added Assertions.diff and diff= * Moved minitest hoe-plugin from hoe-seattlerb. (erikh) * Skipped tests only output details in verbose mode. (tenderlove+zenspider=xoxo) === 2.1.0 / 2011-04-11 * 5 minor enhancements: * Added MiniTest::Spec.register_spec_type(matcher, klass) and spec_type(desc) * Added ability for specs to share code via subclassing of Spec. (metaskills) * Clarified (or tried to) bench_performance_linear's use of threshold. * MiniTest::Unit.runner=(runner) provides an easy way of creating custom test runners for specialized needs. (justinweiss) * Reverse order of inheritance in teardowns of specs. (deepfryed) * 3 bug fixes: * FINALLY fixed problems of inheriting specs in describe/it/describe scenario. (MGPalmer) * Fixed a new warning in 1.9.3. * Fixed assert_block's message handling. (nobu) === 2.0.2 / 2010-12-24 * 1 minor enhancement: * Completed doco on minitest/benchmark for specs. * 1 bug fix: * Benchmarks in specs that didn't call bench_range would die. (zzak). === 2.0.1 / 2010-12-15 * 4 minor enhancements: * Do not filter backtrace if $DEBUG * Exit autorun via nested at_exit handler, in case other libs call exit * Make options accesor lazy. * Split printing of test name and its time. (nurse) * 1 bug fix: * Fix bug when ^T is hit before runner start === 2.0.0 / 2010-11-11 * 3 major enhancements: * Added minitest/benchmark! Assert your performance! YAY! * Refactored runner to allow for more extensibility. See minitest/benchmark. * This makes the runner backwards incompatible in some ways! * 9 minor enhancements: * Added MiniTest::Unit.after_tests { ... } * Improved output by adding test rates and a more sortable verbose format * Improved readme based on feedback from others * Added io method to TestCase. If used, it'll supplant '.EF' output. * Refactored IO in MiniTest::Unit. * Refactored _run_anything to _run_suite to make it easier to wrap (ngauthier) * Spec class names are now the unmunged descriptions (btakita) * YAY for not having redundant rdoc/readmes! * Help output is now generated from the flags you passed straight up. * 4 bug fixes: * Fixed scoping issue on minitest/mock (srbaker/prosperity) * Fixed some of the assertion default messages * Fixes autorun when on windows with ruby install on different drive (larsch) * Fixed rdoc output bug in spec.rb === 1.7.2 / 2010-09-23 * 3 bug fixes: * Fixed doco for expectations and Spec. * Fixed test_capture_io on 1.9.3+ (sora_h) * assert_raises now lets MiniTest::Skip through. (shyouhei) === 1.7.1 / 2010-09-01 * 1 bug fix: * 1.9.2 fixes for spec tests === 1.7.0 / 2010-07-15 * 5 minor enhancements: * Added assert_output (mapped to must_output). * Added assert_silent (mapped to must_be_silent). * Added examples to readme (Mike Dalessio) * Added options output at the top of the run, for fatal run debugging (tenderlove) * Spec's describe method returns created class === 1.6.0 / 2010-03-27 // ruby 1.9.2-p290 * 10 minor enhancements: * Added --seed argument so you can reproduce a random order for debugging. * Added documentation for assertions * Added more rdoc and tons of :nodoc: * Added output to give you all the options you need to reproduce that run. * Added proper argument parsing to minitest. * Added unique serial # to spec names so order can be preserved (needs tests). (phrogz) * Empty 'it' fails with default msg. (phrogz) * Remove previous method on expect to remove 1.9 warnings * Spec#it is now order-proof wrt subclasses/nested describes. * assert_same error message now reports in decimal, eg: oid=123. (mattkent) * 2 bug fixes: * Fixed message on refute_same to be consistent with assert_same. * Fixed method randomization to be stable for testing. === 1.5.0 / 2010-01-06 * 4 minor enhancements: * Added ability to specify what assertions should have their args flipped. * Don't flip arguments on *include and *respond_to assertions. * Refactored Module.infect_an_assertion from Module.infect_with_assertions. * before/after :all now bitches and acts like :each * 3 bug fixes: * Nested describes now map to nested test classes to avoid namespace collision. * Using undef_method instead of remove_method to clean out inherited specs. * assert_raises was ignoring passed in message. === 1.4.2 / 2009-06-25 * 1 bug fix: * Fixed info handler for systems that don't have siginfo. === 1.4.1 / 2009-06-23 * 1 major enhancement: * Handle ^C and other fatal exceptions by failing * 1 minor enhancement: * Added something to catch mixed use of test/unit and minitest if $DEBUG * 1 bug fix: * Added SIGINFO handler for finding slow tests without verbose === 1.4.0 / 2009-06-18 * 5 minor enhancement: * Added clarification doco. * Added specs and mocks to autorun. * Changed spec test class creation to be non-destructive. * Updated rakefile for new hoe capabilities. * describes are nestable (via subclass). before/after/def inherits, specs don't. * 3 bug fixes: * Fixed location on must/wont. * Switched to __name__ to avoid common ivar name. * Fixed indentation in test file (1.9). === 1.3.1 / 2009-01-20 // ruby 1.9.1-p431 * 1 minor enhancement: * Added miniunit/autorun.rb as replacement for test/unit.rb's autorun. * 16 bug fixes: * 1.9 test fixes. * Bug fixes from nobu and akira for really odd scenarios. They run ruby funny. * Fixed (assert|refute)_match's argument order. * Fixed LocalJumpError in autorun if exception thrown before at_exit. * Fixed assert_in_delta (should be >=, not >). * Fixed assert_raises to match Modules. * Fixed capture_io to not dup IOs. * Fixed indentation of capture_io for ruby 1.9 warning. * Fixed location to deal better with custom assertions and load paths. (Yuki) * Fixed order of (must|wont)_include in MiniTest::Spec. * Fixed skip's backtrace. * Got arg order wrong in *_match in tests, message wrong as a result. * Made describe private. For some reason I thought that an attribute of Kernel. * Removed disable_autorun method, added autorun.rb instead. * assert_match escapes if passed string for pattern. * instance_of? is different from ===, use instance_of. === 1.3.0 / 2008-10-09 * 2 major enhancements: * renamed to minitest and pulled out test/unit compatibility. * mini/test.rb is now minitest/unit.rb, everything else maps directly. * 12 minor enhancements: * assert_match now checks that act can call =~ and converts exp to a regexp only if needed. * Added assert_send... seems useless to me tho. * message now forces to string... ruby-core likes to pass classes and arrays :( * Added -v handling and switched to @verbose from $DEBUG. * Verbose output now includes test class name and adds a sortable running time! * Switched message generation into procs for message deferment. * Added skip and renamed fail to flunk. * Improved output failure messages for assert_instance_of, assert_kind_of * Improved output for assert_respond_to, assert_same. * at_exit now exits false instead of errors+failures. * Made the tests happier and more readable imhfo. * Switched index(s) == 0 to rindex(s, 0) on nobu's suggestion. Faster. * 5 bug fixes: * 1.9: Added encoding normalization in mu_pp. * 1.9: Fixed backtrace filtering (BTs are expanded now) * Added back exception_details to assert_raises. DOH. * Fixed shadowed variable in mock.rb * Fixed stupid muscle memory message bug in assert_send. === 1.2.1 / 2008-06-10 * 7 minor enhancements: * Added deprecations everywhere in test/unit. * Added test_order to TestCase. :random on mini, :sorted on test/unit (for now). * Big cleanup in test/unit for rails. Thanks Jeremy Kemper! * Minor readability cleanup. * Pushed setup/run/teardown down to testcase allowing specialized testcases. * Removed pp. Tests run 2x faster. :/ * Renamed deprecation methods and moved to test/unit/deprecate.rb. === 1.2.0 / 2008-06-09 * 2 major enhancements: * Added Mini::Spec. * Added Mini::Mock. Thanks Steven Baker!! * 23 minor enhancements: * Added bin/use_miniunit to make it easy to test out miniunit. * Added -n filtering, thanks to Phil Hagelberg! * Added args argument to #run, takes ARGV from at_exit. * Added test name output if $DEBUG. * Added a refute (was deny) for every assert. * Added capture_io and a bunch of nice assertions from zentest. * Added deprecation mechanism for assert_no/not methods to test/unit/assertions. * Added pp output when available. * Added tests for all assertions. Pretty much maxed out coverage. * Added tests to verify consistency and good naming. * Aliased and deprecated all ugly assertions. * Cleaned out test/unit. Moved autorun there. * Code cleanup to make extensions easier. Thanks Chad! * Got spec args reversed in all but a couple assertions. Much more readable. * Improved error messages across the board. Adds your message to the default. * Moved into Mini namespace, renamed to Mini::Test and Mini::Spec. * Pulled the assertions into their own module... * Removed as much code as I could while still maintaining full functionality. * Moved filter_backtrace into MiniTest. * Removed MiniTest::Unit::run. Unnecessary. * Removed location_of_failure. Unnecessary. * Rewrote test/unit's filter_backtrace. Flog from 37.0 to 18.1 * Removed assert_send. Google says it is never used. * Renamed MiniTest::Unit.autotest to #run. * Renamed deny to refute. * Rewrote some ugly/confusing default assertion messages. * assert_in_delta now defaults to 0.001 precision. Makes specs prettier. * 9 bug fixes: * Fixed assert_raises to raise outside of the inner-begin/rescue. * Fixed for ruby 1.9 and rubinius. * No longer exits 0 if exception in code PRE-test run causes early exit. * Removed implementors method list from mini/test.rb - too stale. * assert_nothing_raised takes a class as an arg. wtf? STUPID * ".EF" output is now unbuffered. * Bunch of changes to get working with rails... UGH. * Added stupid hacks to deal with rails not requiring their dependencies. * Now bitch loudly if someone defines one of my classes instead of requiring. * Fixed infect method to work better on 1.9. * Fixed all shadowed variable warnings in 1.9. === 1.1.0 / 2007-11-08 * 4 major enhancements: * Finished writing all missing assertions. * Output matches original test/unit. * Documented every method needed by language implementor. * Fully switched over to self-testing setup. * 2 minor enhancements: * Added deny (assert ! test), our favorite extension to test/unit. * Added .autotest and fairly complete unit tests. (thanks Chad for help here) === 1.0.0 / 2006-10-30 * 1 major enhancement * Birthday! PK ]5~~(gems/minitest-5.13.0/design_rationale.rbnu[# Specs: # Equivalent Unit Tests: ############################################################################### describe Thingy do # class TestThingy < Minitest::Test before do # def setup do_some_setup # super end # do_some_setup # end it "should do the first thing" do # 1.must_equal 1 # def test_first_thing end # assert_equal 1, 1 # end describe SubThingy do # end before do # do_more_setup # class TestSubThingy < TestThingy end # def setup # super it "should do the second thing" do # do_more_setup 2.must_equal 2 # end end # end # def test_second_thing end # assert_equal 2, 2 # end # end ############################################################################### # runs 2 specs # runs 3 tests ############################################################################### # The specs generate: class ThingySpec < Minitest::Spec def setup super do_some_setup end def test_should_do_the_first_thing assert_equal 1, 1 end end class SubThingySpec < ThingySpec def setup super do_more_setup end # because only setup/teardown is inherited, not specs remove_method :test_should_do_the_first_thing def test_should_do_the_second_thing assert_equal 2, 2 end end PK ]:n&5&5gems/test-unit-3.3.4/PSFLnu[This is the official license for the Python 2.5 release: A. HISTORY OF THE SOFTWARE ========================== Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands as a successor of a language called ABC. Guido remains Python's principal author, although it includes many contributions from others. In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) in Reston, Virginia where he released several versions of the software. In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations (now Zope Corporation, see http://www.zope.com). In 2001, the Python Software Foundation (PSF, see http://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation is a sponsoring member of the PSF. All Python releases are Open Source (see http://www.opensource.org for the Open Source Definition). Historically, most, but not all, Python releases have also been GPL-compatible; the table below summarizes the various releases. Release Derived Year Owner GPL- from compatible? (1) 0.9.0 thru 1.2 1991-1995 CWI yes 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes 1.6 1.5.2 2000 CNRI no 2.0 1.6 2000 BeOpen.com no 1.6.1 1.6 2001 CNRI yes (2) 2.1 2.0+1.6.1 2001 PSF no 2.0.1 2.0+1.6.1 2001 PSF yes 2.1.1 2.1+2.0.1 2001 PSF yes 2.2 2.1.1 2001 PSF yes 2.1.2 2.1.1 2002 PSF yes 2.1.3 2.1.2 2002 PSF yes 2.2.1 2.2 2002 PSF yes 2.2.2 2.2.1 2002 PSF yes 2.2.3 2.2.2 2003 PSF yes 2.3 2.2.2 2002-2003 PSF yes 2.3.1 2.3 2002-2003 PSF yes 2.3.2 2.3.1 2002-2003 PSF yes 2.3.3 2.3.2 2002-2003 PSF yes 2.3.4 2.3.3 2004 PSF yes 2.3.5 2.3.4 2005 PSF yes 2.4 2.3 2004 PSF yes 2.4.1 2.4 2005 PSF yes 2.4.2 2.4.1 2005 PSF yes 2.4.3 2.4.2 2006 PSF yes 2.5 2.4 2006 PSF yes Footnotes: (1) GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't. (2) According to Richard Stallman, 1.6.1 is not GPL-compatible, because its license has a choice of law clause. According to CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 is "not incompatible" with the GPL. Thanks to the many outside volunteers who have worked under Guido's direction to make these releases possible. B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON =============================================================== PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python. 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 ------------------------------------------- BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization ("Licensee") accessing and otherwise using this software in source or binary form and its associated documentation ("the Software"). 2. Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee. 3. BeOpen is making the Software available to Licensee on an "AS IS" basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 5. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the "BeOpen Python" logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page. 7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement. CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 --------------------------------------- 1. This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 ("CNRI"), and the Individual or Organization ("Licensee") accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) 1995-2001 Corporation for National Research Initiatives; All Rights Reserved" are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): "Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the Internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the Internet using the following URL: http://hdl.handle.net/1895.22/1013". 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1. 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By clicking on the "ACCEPT" button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement. ACCEPT CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 -------------------------------------------------- Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. PK ]FNFFgems/test-unit-3.3.4/GPLnu[ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. PK ]~""gems/test-unit-3.3.4/Rakefilenu[# -*- ruby -*- # # Copyright (C) 2008-2017 Kouhei Sutou # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Encoding.default_internal = "UTF-8" if defined?(Encoding.default_internal) # TODO: Remove me when we drop Ruby 1.9 support. unless "".respond_to?(:b) class String def b dup.force_encoding("ASCII-8BIT") end end end require "erb" require "yaml" require "rubygems" require "rake/clean" require "yard" require "bundler/gem_helper" require "packnga" task :default => :test base_dir = File.dirname(__FILE__) html_base_dir = File.join(base_dir, "doc", "html") helper = Bundler::GemHelper.new(base_dir) def helper.version_tag version end helper.install spec = helper.gemspec document_task = Packnga::DocumentTask.new(spec) do |task| task.original_language = "en" task.translate_languages = ["ja"] end Packnga::ReleaseTask.new(spec) do |task| test_unit_github_io_dir_candidates = [ "../../www/test-unit.github.io", ] test_unit_github_io_dir = test_unit_github_io_dir_candidates.find do |dir| File.directory?(dir) end task.index_html_dir = test_unit_github_io_dir end def rake(*arguments) ruby($0, *arguments) end namespace :html do desc "Publish HTML to Web site." task :publish do # FIXME Do nothing for now #rsync_to_rubyforge(spec, "#{html_base_dir}/", "") end end task :test do ruby("test/run-test.rb") end PK ]s  -gems/test-unit-3.3.4/test/util/test-output.rbnu[require 'test/unit' class TestUnitOutput < Test::Unit::TestCase def test_capture_output assert_equal(["stdout\n", "stderr\n"], capture_output do puts("stdout") warn("stderr") end) end end PK ]cʪ6gems/test-unit-3.3.4/test/util/test_backtracefilter.rbnu[require 'test/unit' require 'test/unit/util/backtracefilter' module Test::Unit::Util class TestBacktraceFilter < Test::Unit::TestCase include BacktraceFilter def test_filter_backtrace backtrace = [%q{C:\some\old\path/test/unit/assertions.rb:44:in 'assert'}, %q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}, %q{C:\some\old\path/test/unit/testcase.rb:44:in 'send'}, %q{C:\some\old\path\test\unit\testcase.rb:44:in 'run'}, %q{C:\some\old\path\test\unit.rb:44:in 'run'}, %q{tc_thing.rb:3}] assert_equal(backtrace[1..2], filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Should filter out all TestUnit-specific lines") backtrace = [%q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}, %q{tc_thing.rb:3}] assert_equal(backtrace, filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Shouldn't filter too much") backtrace = [%q{C:\some\old\path/test/unit/assertions.rb:44:in 'assert'}, %q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}, %q{tc_thing.rb:3}] assert_equal(backtrace[1..3], filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Should filter out all TestUnit-specific lines") backtrace = [%q{C:\some\old\path/test/unit/assertions.rb:44:in 'assert'}, %q{C:\some\old\path/test/unit/testcase.rb:44:in 'send'}, %q{C:\some\old\path\test\unit\testcase.rb:44:in 'run'}, %q{C:\some\old\path\test\unit.rb:44:in 'run'}] assert_equal(backtrace, filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Should filter out all TestUnit-specific lines") end def test_nil_backtrace assert_equal(["No backtrace"], filter_backtrace(nil)) end def test_power_assert_backtrace omit('test for power_assert') unless defined?(PowerAssert) blk = Proc.new {caller.find {|i| /power_assert.*in \`start\'/ =~ i}} PowerAssert.start(blk) do |pa| backtrace = [pa.yield, %q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}] assert_equal(backtrace[1..2], filter_backtrace(backtrace)) end end end end PK ]`+O1gems/test-unit-3.3.4/test/util/test_observable.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/observable' module Test module Unit module Util class TC_Observable < TestCase class TF_Observable include Observable end def setup @observable = TF_Observable.new end def test_simple_observation assert_raises(ArgumentError, "add_listener should throw an exception if no callback is supplied") do @observable.add_listener(:property, "a") end heard = false callback = proc { heard = true } assert_equal("a", @observable.add_listener(:property, "a", &callback), "add_listener should return the listener that was added") count = 0 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(1, count, "notify_listeners should have returned the number of listeners that were notified") assert(heard, "Should have heard the property changed") heard = false assert_equal(callback, @observable.remove_listener(:property, "a"), "remove_listener should return the callback") count = 1 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(0, count, "notify_listeners should have returned the number of listeners that were notified") assert(!heard, "Should not have heard the property change") end def test_value_observation value = nil @observable.add_listener(:property, "a") do |passed_value| value = passed_value end count = 0 @observable.instance_eval do count = notify_listeners(:property, "stuff") end assert_equal(1, count, "Should have update the correct number of listeners") assert_equal("stuff", value, "Should have received the value as an argument to the listener") end def test_multiple_value_observation values = [] @observable.add_listener(:property, "a") do |first_value, second_value| values = [first_value, second_value] end count = 0 @observable.instance_eval do count = notify_listeners(:property, "stuff", "more stuff") end assert_equal(1, count, "Should have update the correct number of listeners") assert_equal(["stuff", "more stuff"], values, "Should have received the value as an argument to the listener") end def test_add_remove_with_default_listener assert_raises(ArgumentError, "add_listener should throw an exception if no callback is supplied") do @observable.add_listener(:property) end heard = false callback = proc { heard = true } assert_equal(callback, @observable.add_listener(:property, &callback), "add_listener should return the listener that was added") count = 0 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(1, count, "notify_listeners should have returned the number of listeners that were notified") assert(heard, "Should have heard the property changed") heard = false assert_equal(callback, @observable.remove_listener(:property, callback), "remove_listener should return the callback") count = 1 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(0, count, "notify_listeners should have returned the number of listeners that were notified") assert(!heard, "Should not have heard the property change") end end end end end PK ]2gems/test-unit-3.3.4/test/util/test_procwrapper.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/util/procwrapper' module Test module Unit module Util class TC_ProcWrapper < TestCase def munge_proc(&a_proc) return a_proc end def setup @original = proc {} @munged = munge_proc(&@original) @wrapped_original = ProcWrapper.new(@original) @wrapped_munged = ProcWrapper.new(@munged) end def test_wrapping assert_same(@original, @wrapped_original.to_proc, "The wrapper should return what was wrapped") end def test_hashing assert_equal(@wrapped_original.hash, @wrapped_munged.hash, "The original and munged should have the same hash when wrapped") assert_equal(@wrapped_original, @wrapped_munged, "The wrappers should be equivalent") a_hash = {@wrapped_original => @original} assert(a_hash[@wrapped_original], "Should be able to access the wrapper in the hash") assert_equal(a_hash[@wrapped_original], @original, "Should be able to access the wrapper in the hash") end end end end end PK ]^&1:gems/test-unit-3.3.4/test/util/test-method-owner-finder.rbnu[require 'test/unit' require 'test/unit/util/method-owner-finder' class TestUnitMethodOwnerFinder < Test::Unit::TestCase def test_find assert_equal(Exception, find(RuntimeError.new, :inspect)) assert_equal(Exception, find(Exception.new, :inspect)) anonymous_class = Class.new do end assert_equal(Kernel, find(anonymous_class.new, :inspect)) anonymous_parent_class = Class.new do def inspect super + " by anonymous parent class" end end anonymous_sub_class = Class.new(anonymous_parent_class) do end assert_equal(anonymous_parent_class, find(anonymous_sub_class.new, :inspect)) anonymous_module = Module.new do def inspect super + " by anonymous module" end end anonymous_include_class = Class.new do include anonymous_module end assert_equal(anonymous_module, find(anonymous_include_class.new, :inspect)) end private def find(object, method_name) Test::Unit::Util::MethodOwnerFinder.find(object, method_name) end end PK ]z}J J -gems/test-unit-3.3.4/test/test-test-result.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/testcase' require 'test/unit/testresult' module Test module Unit class TC_TestResult < TestCase def setup @my_result = TestResult.new @my_result.add_assertion() @failure = "failure" @my_result.add_failure(@failure) @error = "error" @my_result.add_error(@error) end def test_result_changed_notification called1 = false @my_result.add_listener(TestResult::CHANGED) do |result| assert_equal(@my_result, result) called1 = true end @my_result.add_assertion assert_true(called1) called1, called2 = false, false @my_result.add_listener(TestResult::CHANGED) do |result| assert_equal(@my_result, result) called2 = true end @my_result.add_assertion assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_failure("") assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_error("") assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_run assert_equal([true, true], [called1, called2]) end def test_fault_notification called1 = false fault = "fault" @my_result.add_listener(TestResult::FAULT) do |passed_fault| assert_equal(fault, passed_fault) called1 = true end @my_result.add_assertion assert_false(called1) @my_result.add_failure(fault) assert_true(called1) called1, called2 = false, false @my_result.add_listener(TestResult::FAULT) do |passed_fault| assert_equal(fault, passed_fault) called2 = true end @my_result.add_assertion assert_equal([false, false], [called1, called2]) called1, called2 = false, false @my_result.add_failure(fault) assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_error(fault) assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_run assert_equal([false, false], [called1, called2]) end def test_passed? result = TestResult.new assert_true(result.passed?) result.add_assertion assert_true(result.passed?) result.add_run assert_true(result.passed?) result.add_failure("") assert_false(result.passed?) result = TestResult.new result.add_error("") assert_false(result.passed?) end def test_faults assert_equal([@failure, @error], @my_result.faults) notification = "notification" @my_result.add_notification(notification) assert_equal([@failure, @error, notification], @my_result.faults) end end end end PK ]( DD-gems/test-unit-3.3.4/test/fixtures/header.tsvnu[label expected target empty string true "" plain string false hello PK ]DD-gems/test-unit-3.3.4/test/fixtures/header.csvnu[label,expected,target empty string,true,"" plain string,false,hello PK ]cm..0gems/test-unit-3.3.4/test/fixtures/no-header.csvnu[empty string,true,"" plain string,false,hello PK ]? "..0gems/test-unit-3.3.4/test/fixtures/no-header.tsvnu[empty string true "" plain string false hello PK ]_CC3gems/test-unit-3.3.4/test/fixtures/header-label.csvnu[label,expected,label upper case,HELLO,HELLO lower case,Hello,hello PK ]*CC3gems/test-unit-3.3.4/test/fixtures/header-label.tsvnu[label expected label upper case HELLO HELLO lower case Hello hello PK ]:bOO+gems/test-unit-3.3.4/test/fixtures/plus.csvnu[label,expected,augend,addend positive positive,4,3,1 positive negative,-1,1,-2 PK ]D.gems/test-unit-3.3.4/test/test-notification.rbnu[require 'test/unit' require 'testunit-test-util' class TestUnitNotification < Test::Unit::TestCase include TestUnitTestUtil class TestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end def test_notify notify("1st notify") notify("2nd notify. Reach here.") end end def test_notify result = _run_test("test_notify") assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, " \ "0 omissions, 2 notifications", result.to_s) assert_fault_messages(["1st notify", "2nd notify. Reach here."], result.notifications) end private def _run_test(name) super(TestCase, name) end end PK ]\҃P  *gems/test-unit-3.3.4/test/test-priority.rbnu[require 'test/unit' class TestUnitPriority < Test::Unit::TestCase class TestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end priority :must def test_must assert(true) end def test_must_inherited assert(true) end priority :important def test_important assert(true) end def test_important_inherited assert(true) end priority :high def test_high assert(true) end def test_high_inherited assert(true) end priority :normal def test_normal assert(true) end def test_normal_inherited assert(true) end priority :low def test_low assert(true) end def test_low_inherited assert(true) end priority :never def test_never assert(true) end def test_never_inherited assert(true) end end def test_priority_must assert_priority("must", 1.0, 0.0001) end def test_priority_important assert_priority("important", 0.9, 0.09) end def test_priority_high assert_priority("high", 0.70, 0.1) end def test_priority_normal assert_priority("normal", 0.5, 0.1) end def test_priority_low assert_priority("low", 0.25, 0.1) end def test_priority_never assert_priority("never", 0.0, 0.0001) end def assert_priority(priority, expected, delta) assert_need_to_run("test_#{priority}", expected, delta) assert_need_to_run("test_#{priority}_inherited", expected, delta) end def assert_need_to_run(test_name, expected, delta) test = TestCase.new(test_name) n = 1000 n_need_to_run = 0 n.times do |i| n_need_to_run += 1 if Test::Unit::Priority::Checker.need_to_run?(test) end assert_in_delta(expected, n_need_to_run.to_f / n, delta) end class TestClassName < self def test_colon assert_escaped_name("Test_colon__colon_Priority", "Test::Priority") end def test_space assert_escaped_name("test_priority", "test priority") end def test_slash assert_escaped_name("test_priority", "test/priority") end def test_back_slash assert_escaped_name("test_priority", "test\/priority") end def test_question assert_escaped_name("#question.predicate", "#question?") end def test_exclamation assert_escaped_name("#exclamation.destructive", "#exclamation!") end def test_equal assert_escaped_name("#equal.equal", "#equal=") end def assert_escaped_name(expected, class_name) checker = Checker.new(nil) escaped_class_name = checker.send(:escape_class_name, class_name) assert_equal(expected, escaped_class_name) end end class TestFileName < self class SpecialNameTestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end def test_question? end def test_exclamation! end def test_equal= end test "have space" do end end def test_question assert_escaped_name("test_colon__#question.predicate_case", "test: #question? case") end def test_exclamation assert_escaped_name("test_colon__#exclamation.destructive_case", "test: #exclamation! case") end def test_equal assert_escaped_name("test_colon__#equal.equal_case", "test: #equal= case") end def assert_escaped_name(expected, test_method_name) checker = Checker.new(SpecialNameTestCase.new(test_method_name)) passed_file = checker.send(:passed_file) method_name_component = File.basename(File.dirname(passed_file)) assert_equal(expected, method_name_component) end end end PK ]52'gems/test-unit-3.3.4/test/test-error.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' module Test module Unit class TC_Error < TestCase TF_Exception = Struct.new('TF_Exception', :message, :backtrace) def test_display ex = TF_Exception.new("message1\nmessage2", ['line1', 'line2']) e = Error.new("name", ex) assert_equal("name: #{TF_Exception.name}: message1", e.short_display) assert_equal(< :accessor}, test_for_accessor_category.attributes) test_for_bug_1234 = TestStack.new("test_bug_1234") assert_equal({"bug" => 1234}, test_for_bug_1234.attributes) test_no_attributes = TestStack.new("test_no_attributes") assert_equal({}, test_no_attributes.attributes) end def test_callback changed_attributes = [] observer = Proc.new do |test_case, key, old_value, value, method_name| changed_attributes << [test_case, key, old_value, value, method_name] end test_case = Class.new(TestStack) do register_attribute_observer(:bug, &observer) attribute("bug", 9876, "test_bug_1234") attribute(:description, "Test for peek", "test_peek") attribute(:bug, 29, "test_peek") end assert_equal([ [test_case, "bug", 1234, 9876, "test_bug_1234"], [test_case, "bug", nil, 29, "test_peek"], ], changed_attributes) end def test_attributes_with_prepended_module omit("Module#prepend is needed") unless Module.respond_to?(:prepend, true) test_case = Class.new(TestStack) do prepend Module.new end assert_equal({ "category" => :accessor, }, test_case.attributes("test_peek")) end class TestDescription < self def test_decoration_style test_case = Class.new(TestStack) do description "Test for push" def test_push end end test_push = test_case.new("test_push") assert_equal({"description" => "Test for push"}, test_push.attributes) end def test_explicit_test_name_style test_case = Class.new(TestStack) do def test_push end description "Test for push", :test_push end test_push = test_case.new("test_push") assert_equal({"description" => "Test for push"}, test_push.attributes) end end end PK ]d)gems/test-unit-3.3.4/test/test-pending.rbnu[require 'test/unit' require 'testunit-test-util' class TestUnitPending < Test::Unit::TestCase include TestUnitTestUtil class TestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end def test_pend pend("1st pend") pend("2nd pend. Should not be reached here.") assert(true, "Should not be reached here too.") end def test_pend_with_failure_in_block pend("Wait a minute") do raise "Not implemented yet" end assert(true, "Reached here.") end def test_pend_with_no_failure_in_block pend("Wait a minute") do "Nothing raised" end assert(true, "Not reached here.") end end def test_pend test = nil result = _run_test("test_pend") {|t| test = t} assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 1 pendings, " \ "0 omissions, 0 notifications", result.to_s) assert_fault_messages(["1st pend"], result.pendings) assert_true(test.interrupted?) end def test_pend_with_failure_in_block test = nil result = _run_test("test_pend_with_failure_in_block") {|t| test = t} assert_equal("1 tests, 1 assertions, 0 failures, 0 errors, 1 pendings, " \ "0 omissions, 0 notifications", result.to_s) assert_fault_messages(["Wait a minute"], result.pendings) assert_false(test.interrupted?) end def test_pend_with_no_failure_in_block test = nil result = _run_test("test_pend_with_no_failure_in_block") {|t| test = t} assert_equal("1 tests, 1 assertions, 1 failures, 0 errors, 0 pendings, " \ "0 omissions, 0 notifications", result.to_s) assert_fault_messages(["Pending block should not be passed: Wait a minute."], result.failures) assert_true(test.interrupted?) end private def _run_test(name, &block) super(TestCase, name, &block) end end PK ]ad  4gems/test-unit-3.3.4/test/test-test-suite-creator.rbnu[require "test/unit" module Test module Unit class TestTestSuiteCreator < TestCase def collect_test_names(test_case) creator = TestSuiteCreator.new(test_case) creator.send(:collect_test_names) end class TestStandalone < self def setup @test_case = Class.new(TestCase) do def test_in_test_case end end end def test_collect_test_names assert_equal(["test_in_test_case"], collect_test_names(@test_case)) end end class TestInherited < self def setup @parent_test_case = Class.new(TestCase) do def test_in_parent end end @child_test_case = Class.new(@parent_test_case) do def test_in_child end end end def test_collect_test_names assert_equal(["test_in_child"], collect_test_names(@child_test_case)) end end class TestModule < self def setup test_module = Module.new do def test_in_module end end @test_case = Class.new(TestCase) do include test_module def test_in_test_case end end end def test_collect_test_names assert_equal(["test_in_module", "test_in_test_case"].sort, collect_test_names(@test_case).sort) end end class TestInheritedModule < self def setup parent_test_module = Module.new do def test_in_module_in_parent end end child_test_module = Module.new do def test_in_module_in_child end end @parent_test_case = Class.new(TestCase) do include parent_test_module def test_in_parent end end @child_test_case = Class.new(@parent_test_case) do include child_test_module def test_in_child end end end def test_collect_test_names assert_equal(["test_in_child", "test_in_module_in_child"].sort, collect_test_names(@child_test_case).sort) end end end end end PK ]sEv v .gems/test-unit-3.3.4/test/test-color-scheme.rbnu[class TestUnitColorScheme < Test::Unit::TestCase def test_register inverted_scheme_spec = { "success" => {:name => "red"}, "failure" => {:name => "green"}, } Test::Unit::ColorScheme["inverted"] = inverted_scheme_spec assert_equal({ "success" => color("red"), "failure" => color("green"), }, Test::Unit::ColorScheme["inverted"].to_hash) end def test_new_with_colors scheme = Test::Unit::ColorScheme.new(:success => color("blue"), "failure" => color("green", :underline => true)) assert_equal({ "success" => color("blue"), "failure" => color("green", :underline => true), }, scheme.to_hash) end def test_new_with_spec scheme = Test::Unit::ColorScheme.new(:success => { :name => "blue", :bold => true }, "failure" => {:name => "green"}) assert_equal({ "success" => color("blue", :bold => true), "failure" => color("green"), }, scheme.to_hash) end private def color(name, options={}) Test::Unit::Color.new(name, options) end class TestFor8Colors < self def setup @original_term, ENV["TERM"] = ENV["TERM"], nil @original_color_term, ENV["COLORTERM"] = ENV["COLORTERM"], nil ENV["TERM"] = "xterm" end def teardown ENV["TERM"] = @original_term ENV["COLORTERM"] = @original_color_term end def test_default expected_schema_keys = [ "pass", "pass-marker", "failure", "failure-marker", "pending", "pending-marker", "omission", "omission-marker", "notification", "notification-marker", "error", "error-marker", "case", "suite", "diff-inserted-tag", "diff-deleted-tag", "diff-difference-tag", "diff-inserted", "diff-deleted", ] assert_equal(expected_schema_keys.sort, Test::Unit::ColorScheme.default.to_hash.keys.sort) end end end PK ]7C6gems/test-unit-3.3.4/test/collector/test-descendant.rbnu[require 'test/unit' require 'test/unit/collector/descendant' class TestUnitCollectorDescendant < Test::Unit::TestCase def setup @previous_descendants = Test::Unit::TestCase::DESCENDANTS.dup Test::Unit::TestCase::DESCENDANTS.clear end def teardown Test::Unit::TestCase::DESCENDANTS.replace(@previous_descendants) end private def assert_collect(expected, *collect_args) collector = Test::Unit::Collector::Descendant.new yield(collector) if block_given? assert_equal(expected, collector.send(:collect, *collect_args)) end def default_name Test::Unit::Collector::Descendant::NAME end def empty_suite(name=nil) Test::Unit::TestSuite.new(name || default_name) end class TestCollect < self def setup super @test_case1 = Class.new(Test::Unit::TestCase) do self.test_order = :alphabetic def self.name "test-case1" end def test_1 end def test_2 end end @test_case2 = Class.new(Test::Unit::TestCase) do self.test_order = :alphabetic def self.name "test-case2" end def test_0 end end @no_test_case = Class.new do def self.name "no-test-case" end def test_4 end end end def test_basic assert_collect(full_suite("name"), "name") assert_collect(full_suite("name"), "name") do |collector| collector.filter = [] end end def test_filtered assert_collect(empty_suite) do |collector| collector.filter = Proc.new {false} end assert_collect(full_suite) do |collector| collector.filter = Proc.new {true} end assert_collect(full_suite) do |collector| collector.filter = Proc.new {nil} end assert_collect(empty_suite) do |collector| collector.filter = [Proc.new {false}, Proc.new {true}] end assert_collect(empty_suite) do |collector| collector.filter = [Proc.new {true}, Proc.new {false}] end assert_collect(empty_suite) do |collector| collector.filter = [Proc.new {nil}, Proc.new {false}] end assert_collect(full_suite) do |collector| collector.filter = [Proc.new {nil}, Proc.new {true}] end expected = empty_suite suite1 = Test::Unit::TestSuite.new(@test_case1.name) suite1 << @test_case1.new("test_1") suite2 = Test::Unit::TestSuite.new(@test_case2.name) suite2 << @test_case2.new("test_0") expected << suite1 << suite2 assert_collect(expected) do |collector| collector.filter = Proc.new do |test| ['test_1', 'test_0'].include?(test.method_name) end end suite1 = Test::Unit::TestSuite.new(@test_case1.name) suite1 << @test_case1.new("test_1") suite2 = Test::Unit::TestSuite.new(@test_case2.name) suite2 << @test_case2.new("test_0") assert_collect(empty_suite) do |collector| filters = [Proc.new {|test| test.method_name == 'test_1' ? true : nil}, Proc.new {|test| test.method_name == 'test_0' ? true : nil}, Proc.new {false}] collector.filter = filters end end private def full_suite(name=nil) sub_suite1 = Test::Unit::TestSuite.new(@test_case1.name) sub_suite1 << @test_case1.new('test_1') sub_suite1 << @test_case1.new('test_2') sub_suite2 = Test::Unit::TestSuite.new(@test_case2.name) sub_suite2 << @test_case2.new('test_0') suite = empty_suite(name) suite << sub_suite1 suite << sub_suite2 suite end end class TestModule < self def test_included_in_child tests = Module.new do def test_in_module end end parent_test_case = Class.new(Test::Unit::TestCase) do class << self def name "Parent" end end end child_test_case = Class.new(parent_test_case) do include tests class << self def name "Child" end end end child_suite = Test::Unit::TestSuite.new(child_test_case.name) child_suite << child_test_case.new("test_in_module") parent_suite = Test::Unit::TestSuite.new(parent_test_case.name) parent_suite << child_suite suite = empty_suite("all") suite << parent_suite assert_collect(suite, "all") end end end PK ]a660gems/test-unit-3.3.4/test/collector/test-load.rbnu[require 'tmpdir' require 'pathname' require 'test/unit' require 'test/unit/collector/load' class TestUnitCollectorLoad < Test::Unit::TestCase def setup @previous_descendants = Test::Unit::TestCase::DESCENDANTS.dup Test::Unit::TestCase::DESCENDANTS.clear @temporary_test_cases_module_name = "TempTestCases" ::Object.const_set(@temporary_test_cases_module_name, Module.new) @test_dir = Pathname(Dir.tmpdir) + "test-unit" @extra_test_dir = Pathname(Dir.tmpdir) + "test-unit-extra" ensure_clean_directory(@test_dir) ensure_clean_directory(@extra_test_dir) end setup def setup_top_level_test_cases @test_case1_base_name = "test_case1.rb" @test_case1 = @test_dir + @test_case1_base_name @test_case2 = @test_dir + "test_case2.rb" @no_load_test_case3 = @test_dir + "case3.rb" @test_case1.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class TestCase1 < Test::Unit::TestCase def test1_1 end def test1_2 end end end EOT end @test_case2.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class TestCase2 < Test::Unit::TestCase def test2 end end end EOT end @no_load_test_case3.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class NoLoadTestCase3 < Test::Unit::TestCase def test3 end end end EOT end end setup def setup_sub_level_test_cases @sub_test_dir = @test_dir + "sub" @sub_test_dir.mkpath @sub_test_case1 = @sub_test_dir + @test_case1_base_name @sub_test_case4 = @sub_test_dir + "test_case4.rb" @no_load_sub_test_case5 = @sub_test_dir + "case5.rb" @sub_test_case6 = @sub_test_dir + "test_case6.rb" @sub_test_case1.open("w") do |test_case| test_case.puts(<<-TEST_CASE) module #{@temporary_test_cases_module_name} class SubTestCase1 < Test::Unit::TestCase def test1_1 end def test1_2 end end end TEST_CASE end @sub_test_case4.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubTestCase4 < Test::Unit::TestCase def test4_1 end def test4_2 end end end EOT end @no_load_sub_test_case5.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class NoLoadSubTestCase5 < Test::Unit::TestCase def test5_1 end def test5_2 end end end EOT end @sub_test_case6.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubTestCase6 < Test::Unit::TestCase def test6 end end end EOT end end setup def setup_sub_level_test_cases2 @sub2_test_dir = @test_dir + "sub2" @sub2_test_dir.mkpath @no_load_sub2_test_case7 = @sub2_test_dir + "case7.rb" @sub2_test_case8 = @sub2_test_dir + "test_case8.rb" @sub2_test_case9 = @sub2_test_dir + "test_case9.rb" @no_load_sub2_test_case7.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class NoLoadSub2TestCase7 < Test::Unit::TestCase def test7_1 end def test7_2 end end end EOT end @sub2_test_case8.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class Sub2TestCase8 < Test::Unit::TestCase def test8_1 end def test8_2 end end end EOT end @sub2_test_case9.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class Sub2TestCase9 < Test::Unit::TestCase def test9 end end end EOT end end setup def setup_svn_test_cases @svn_test_dir = @test_dir + ".svn" @svn_test_dir.mkpath @svn_test_case10 = @svn_test_dir + "test_case10.rb" @svn_test_case10.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SvnTestCase10 < Test::Unit::TestCase def test7 end end end EOT end end setup def setup_sub_cvs_test_cases @sub_cvs_test_dir = @sub_test_dir + "CVS" @sub_cvs_test_dir.mkpath @sub_cvs_test_case11 = @sub_cvs_test_dir + "test_case11.rb" @sub_cvs_test_case11.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubCVSTestCase11 < Test::Unit::TestCase def test11 end end end EOT end end setup def setup_sub_git_test_cases @sub_git_test_dir = @sub_test_dir + ".git" @sub_git_test_dir.mkpath @sub_git_test_case11 = @sub_git_test_dir + "test_case11.rb" @sub_git_test_case11.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubGitTestCase11 < Test::Unit::TestCase def test11 end end end EOT end end setup def setup_extra_top_level_test_cases @test_cases12 = @extra_test_dir + "test_cases12.rb" @test_cases12.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class TestCase121 < Test::Unit::TestCase def test121_1 end def test121_2 end end class TestCase122 < Test::Unit::TestCase def test122_1 end def test122_2 end end end EOT end end setup def setup_sub_level_extra_test_cases @sub_extra_test_dir = @extra_test_dir + "sub" @sub_extra_test_dir.mkpath @cases13_test = @sub_extra_test_dir + "13cases_test.rb" @cases13_test.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubTestCase13 < Test::Unit::TestCase def test13_1 end def test13_2 end end end EOT end end def teardown @test_dir.rmtree if @test_dir.exist? ::Object.send(:remove_const, @temporary_test_cases_module_name) Test::Unit::TestCase::DESCENDANTS.replace(@previous_descendants) end def test_simple_collect assert_collect([:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("SubTestCase4")}, [:test, {:name => "test4_1"}], [:test, {:name => "test4_2"}]], [:suite, {:name => _test_case_name("SubTestCase6")}, [:test, {:name => "test6"}]]], @sub_test_dir.to_s) end def test_simple_collect_test_suffix assert_collect([:suite, {:name => @extra_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("TestCase121")}, [:test, {:name => "test121_1"}], [:test, {:name => "test121_2"}]], [:suite, {:name => _test_case_name("TestCase122")}, [:test, {:name => "test122_1"}], [:test, {:name => "test122_2"}]], [:suite, {:name => @sub_extra_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase13")}, [:test, {:name => "test13_1"}], [:test, {:name => "test13_2"}]]]], @extra_test_dir.to_s) end def test_multilevel_collect assert_collect([:suite, {:name => "."}, [:suite, {:name => _test_case_name("TestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("TestCase2")}, [:test, {:name => "test2"}]], [:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("SubTestCase4")}, [:test, {:name => "test4_1"}], [:test, {:name => "test4_2"}]], [:suite, {:name => _test_case_name("SubTestCase6")}, [:test, {:name => "test6"}]]], [:suite, {:name => @sub2_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("Sub2TestCase8")}, [:test, {:name => "test8_1"}], [:test, {:name => "test8_2"}]], [:suite, {:name => _test_case_name("Sub2TestCase9")}, [:test, {:name => "test9"}]]]]) end def test_collect_file assert_collect([:suite, {:name => _test_case_name("TestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], @test_case1.to_s) end def test_collect_file_no_pattern_match_file_name assert_collect([:suite, {:name => _test_case_name("NoLoadSubTestCase5")}, [:test, {:name => "test5_1"}], [:test, {:name => "test5_2"}]], @no_load_sub_test_case5.to_s) end def test_collect_file_test_cases assert_collect([:suite, {:name => "[#{@test_cases12}]"}, [:suite, {:name => _test_case_name("TestCase121")}, [:test, {:name => "test121_1"}], [:test, {:name => "test121_2"}]], [:suite, {:name => _test_case_name("TestCase122")}, [:test, {:name => "test122_1"}], [:test, {:name => "test122_2"}]]], @test_cases12.to_s) end def test_collect_files assert_collect([:suite, {:name => "[#{@test_case1}, #{@test_case2}]"}, [:suite, {:name => _test_case_name("TestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("TestCase2")}, [:test, {:name => "test2"}]]], @test_case1.to_s, @test_case2.to_s) end def test_nil_pattern assert_collect([:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("NoLoadSubTestCase5")}, [:test, {:name => "test5_1"}], [:test, {:name => "test5_2"}]], [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("SubTestCase4")}, [:test, {:name => "test4_1"}], [:test, {:name => "test4_2"}]], [:suite, {:name => _test_case_name("SubTestCase6")}, [:test, {:name => "test6"}]]], @sub_test_dir.to_s) do |collector| collector.patterns.clear end end def test_filtering assert_collect([:suite, {:name => "."}, [:suite, {:name => _test_case_name("TestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]]]]) do |collector| collector.filter = Proc.new do |test| !/\Atest1/.match(test.method_name).nil? end end end def test_collect_multi test_dirs = [@sub_test_dir.to_s, @sub2_test_dir.to_s] assert_collect([:suite, {:name => "[#{test_dirs.join(', ')}]"}, [:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("SubTestCase4")}, [:test, {:name => "test4_1"}], [:test, {:name => "test4_2"}]], [:suite, {:name => _test_case_name("SubTestCase6")}, [:test, {:name => "test6"}]]], [:suite, {:name => @sub2_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("Sub2TestCase8")}, [:test, {:name => "test8_1"}], [:test, {:name => "test8_2"}]], [:suite, {:name => _test_case_name("Sub2TestCase9")}, [:test, {:name => "test9"}]]]], *test_dirs) end private def assert_collect(expected, *collect_args) keep_required_files do Dir.chdir(@test_dir.to_s) do collector = Test::Unit::Collector::Load.new yield(collector) if block_given? actual = inspect_test_object(collector.send(:collect, *collect_args)) assert_equal(expected, actual) end end end def ensure_clean_directory(directory) directory.rmtree if directory.exist? directory.mkpath end def keep_required_files required_files = $".dup yield ensure $".replace(required_files) end def _test_case_name(test_case_class_name) "#{@temporary_test_cases_module_name}::#{test_case_class_name}" end def inspect_test_object(test_object) return nil if test_object.nil? case test_object when Test::Unit::TestSuite sub_tests = test_object.tests.collect do |test| inspect_test_object(test) end.sort_by do |type, attributes, *children| attributes[:name] end [:suite, {:name => test_object.name}, *sub_tests] when Test::Unit::TestCase [:test, {:name => test_object.method_name}] else raise "unexpected test object: #{test_object.inspect}" end end end PK ])**/gems/test-unit-3.3.4/test/collector/test_dir.rbnu[require 'test/unit' require 'test/unit/collector/dir' require 'pp' module Test module Unit module Collector class TestDir < TestCase class FileSystem class Directory def initialize(name, fs, parent=self, &block) @name = name @fs = fs @parent = parent @contents = {'.' => self, '..' => parent} instance_eval(&block) if(block) end def file(name, contents) @contents[name] = contents end def dir(name, &block) @contents[name] = self.class.new(name, @fs, self, &block) end def entries @contents.keys end def directory?(name) return true if(name.nil? || name.empty?) return false unless(@contents.include?(name)) @contents[name].kind_of?(self.class) end def file?(name) return false unless(@contents.include?(name)) !directory?(name) end def exist?(name) @contents.include?(name) end def [](name) raise Errno::ENOENT, name unless(@contents.include?(name)) @contents[name] end def path_to(name=nil) if(!name) @parent.path_to(@name) elsif(@parent == self) @fs.join('/', name) else @fs.join(@parent.path_to(@name), name) end end end class ObjectSpace def initialize @objects = [] end def each_object(klass, &block) @objects.find_all{|o| o.kind_of?(klass)}.each(&block) end def <<(object) @objects << object end end attr_reader :object_space def initialize(&block) @root = Directory.new('/', self, &block) @pwd = @root @object_space = ObjectSpace.new @required = [] end def entries(dir) e = find(dir) require_directory(dir) e.entries end def directory?(name) return true if (base = basename(name)) == '/' e = find(dirname(name)) return false unless(e) e.directory?(base) end def find(path) if(/\A\// =~ path) thing = @root else thing = @pwd end path.scan(/[^\/]+/) do |e| break thing = false unless(thing.kind_of?(Directory)) thing = thing[e] end thing end def dirname(name) if (name = name.tr_s('/', '/')) == '/' name else name[%r"\A.+(?=/[^/]+/?\z)|\A/"] || "." end end def basename(name) name[%r"(\A/|[^/]+)/*\z", 1] end def split(name) [dirname(name), basename(name)] end def join(*parts) parts.join('/').gsub(%r{/+}, '/') end def file?(name) e = find(dirname(name)) return false unless(e) e.file?(basename(name)) end def pwd @pwd.path_to end def chdir(to) e = find(to) require_directory(to) @pwd = e end def expand_path(path, base = nil) until /\A\// =~ path base ||= pwd path = join(base, path) base = nil end path.gsub!(%r"(?:/\.)+(?=/)", '') nil while path.sub!(%r"/(?!\.\./)[^/]+/\.\.(?=/)", '') path.sub!(%r"\A(?:/\.\.)+(?=/)", '') path.sub!(%r"(?:\A(/)|/)\.\.?\z", '\1') path end def require_directory(path) raise Errno::ENOTDIR, path unless(directory?(path)) end def require(file) return false if(@required.include?(file)) begin e = find(file) rescue Errno::ENOENT => e if(/\.rb\Z/ =~ file) raise LoadError, file end e = find(file + '.rb') end @required << file @object_space << e true rescue Errno::ENOENT raise LoadError, file end end def test_dir inner_dir = nil dirs = FileSystem::Directory.new('/', nil) do file 'a', nil inner_dir = dir 'b' end assert_equal(inner_dir, dirs['b']) end def test_fs fs = FileSystem.new do file 'a', nil dir 'b' end assert_equal(['.', '..', 'a', 'b'].sort, fs.entries('/').sort) assert(fs.directory?('/')) assert(!fs.directory?('/a')) assert(!fs.directory?('/bogus')) assert(fs.file?('/a')) assert(!fs.file?('/')) assert(!fs.file?('/bogus')) assert(fs.directory?('/b')) assert(fs.file?('a')) assert(fs.directory?('b')) end def test_fs_sub fs = FileSystem.new do dir 'a' do file 'b', nil dir 'c' do file 'd', nil end end end assert(fs.file?('/a/b')) assert(!fs.file?('/a/b/c/d')) assert(fs.file?('/a/c/d')) end def test_fs_pwd fs = FileSystem.new do file 'a', nil dir 'b' do file 'c', nil dir 'd' do file 'e', nil end end end assert_equal('/', fs.pwd) assert_raises(Errno::ENOENT) do fs.chdir('bogus') end assert_raises(Errno::ENOTDIR) do fs.chdir('a') end fs.chdir('b') assert_equal('/b', fs.pwd) fs.chdir('d') assert_equal('/b/d', fs.pwd) fs.chdir('..') assert_equal('/b', fs.pwd) fs.chdir('..') assert_equal('/', fs.pwd) end def test_fs_entries fs = FileSystem.new do file 'a', nil dir 'b' do file 'c', nil file 'd', nil end file 'e', nil dir 'f' do file 'g', nil dir 'h' do file 'i', nil end end end assert_equal(['.', '..', 'a', 'b', 'e', 'f'], fs.entries('/').sort) assert_equal(['.', '..', 'a', 'b', 'e', 'f'], fs.entries('.').sort) assert_equal(['.', '..', 'a', 'b', 'e', 'f'], fs.entries('b/..').sort) assert_equal(['.', '..', 'c', 'd'], fs.entries('b').sort) assert_raises(Errno::ENOENT) do fs.entries('z') end assert_raises(Errno::ENOTDIR) do fs.entries('a') end fs.chdir('f') assert_equal(['.', '..', 'i'], fs.entries('h').sort) end class TestClass1 end class TestClass2 end def test_fs_require fs = FileSystem.new do file 'test_class1.rb', TestClass1 dir 'dir' do file 'test_class2.rb', TestClass2 end end c = [] fs.object_space.each_object(Class) do |o| c << o end assert_equal([], c) assert_raises(LoadError) do fs.require('bogus') end assert(fs.require('test_class1.rb')) assert(!fs.require('test_class1.rb')) c = [] fs.object_space.each_object(Class) do |o| c << o end assert_equal([TestClass1], c) fs.require('dir/test_class2') c = [] fs.object_space.each_object(Class) do |o| c << o end assert_equal([TestClass1, TestClass2], c) c = [] fs.object_space.each_object(Time) do |o| c << o end assert_equal([], c) end def setup @t1 = t1 = create_test(1) @t2 = t2 = create_test(2) @t3 = t3 = create_test(3) @t4 = t4 = create_test(4) @t5 = t5 = create_test(5) @t6 = t6 = create_test(6) fs = FileSystem.new do file 'test_1.rb', t1 file 'test_2.rb', t2 dir 'd1' do file 'test_3.rb', t3 end file 't4.rb', t4 dir 'd2' do file 'test_5', t5 file 'test_6.rb', Time end file 't6.rb', t6 end fs.require('t6') @c = Dir.new(fs, fs, fs.object_space, fs) end def create_test(name) t = Class.new(TestCase) t.class_eval <<-EOC self.test_order = :alphabetic def self.name "T\#{#{name}}" end def test_#{name}a end def test_#{name}b end EOC t end def test_simple_collect expected = TestSuite.new('d1') expected << (@t3.suite) assert_equal(expected, @c.collect('d1')) end def test_multilevel_collect expected = TestSuite.new('.') expected << @t1.suite << @t2.suite expected << (TestSuite.new('d1') << @t3.suite) assert_equal(expected, @c.collect) end def test_collect_file expected = TestSuite.new('test_1.rb') expected << @t1.suite assert_equal(expected, @c.collect('test_1.rb')) expected = TestSuite.new('t4.rb') expected << @t4.suite assert_equal(expected, @c.collect('t4.rb')) end def test_nil_pattern expected = TestSuite.new('d2') expected << @t5.suite @c.pattern.clear assert_equal(expected, @c.collect('d2')) end def test_filtering expected = TestSuite.new('.') expected << @t1.suite @c.filter = proc{|t| t.method_name == 'test_1a' || t.method_name == 'test_1b'} assert_equal(expected, @c.collect) end def test_collect_multi expected = TestSuite.new('[d1, d2]') expected << (TestSuite.new('d1') << @t3.suite) expected << (TestSuite.new('d2') << @t5.suite) @c.pattern.replace([/\btest_/]) assert_equal(expected, @c.collect('d1', 'd2')) end end end end end PK ]2\ 7gems/test-unit-3.3.4/test/collector/test_objectspace.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/collector/objectspace' module Test module Unit module Collector class TC_ObjectSpace < TestCase def setup @tc1 = Class.new(TestCase) do self.test_order = :alphabetic def self.name "tc_1" end def test_1 end def test_2 end end @tc2 = Class.new(TestCase) do self.test_order = :alphabetic def self.name "tc_2" end def test_0 end end @no_tc = Class.new do def test_4 end end @object_space = {Class => [@tc1, @tc2, @no_tc], String => ['']} def @object_space.each_object(type) self[type].each{|item| yield(item) } end @c = ObjectSpace.new(@object_space) end def full_suite(name=ObjectSpace::NAME) expected = TestSuite.new(name) expected << (TestSuite.new(@tc1.name) << @tc1.new('test_1') << @tc1.new('test_2')) expected << (TestSuite.new(@tc2.name) << @tc2.new('test_0')) end def empty_suite TestSuite.new(ObjectSpace::NAME) end def test_basic_collection assert_equal(full_suite("name"), @c.collect("name")) @c.filter = [] assert_equal(full_suite("name"), @c.collect("name")) end def test_filtered_collection @c.filter = proc{false} assert_equal(empty_suite, @c.collect) @c.filter = proc{true} assert_equal(full_suite, @c.collect) @c.filter = proc{nil} assert_equal(full_suite, @c.collect) @c.filter = [proc{false}, proc{true}] assert_equal(empty_suite, @c.collect) @c.filter = [proc{true}, proc{false}] assert_equal(empty_suite, @c.collect) @c.filter = [proc{nil}, proc{false}] assert_equal(empty_suite, @c.collect) @c.filter = [proc{nil}, proc{true}] assert_equal(full_suite, @c.collect) expected = TestSuite.new(ObjectSpace::NAME) expected << (TestSuite.new(@tc1.name) << @tc1.new('test_1')) expected << (TestSuite.new(@tc2.name) << @tc2.new('test_0')) @c.filter = proc{|test| ['test_1', 'test_0'].include?(test.method_name)} assert_equal(expected, @c.collect) expected = TestSuite.new(ObjectSpace::NAME) TestSuite.new(@tc1.name) << @tc1.new('test_1') TestSuite.new(@tc2.name) << @tc2.new('test_0') @c.filter = [proc{|t| t.method_name == 'test_1' ? true : nil}, proc{|t| t.method_name == 'test_0' ? true : nil}, proc{false}] assert_equal(empty_suite, @c.collect) end end end end end PK ]ӪU,gems/test-unit-3.3.4/test/test-test-suite.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' module Test module Unit class TestTestSuite < TestCase def setup @testcase1 = Class.new(TestCase) do def test_succeed1 assert_block { true } end def test_fail assert_block { false } end end @testcase2 = Class.new(TestCase) do def test_succeed2 assert_block { true } end def test_error raise end end end def test_add s = TestSuite.new assert_equal(s, s << self.class.new("test_add")) end def test_delete s = TestSuite.new t1 = self.class.new("test_delete") s << t1 t2 = self.class.new("test_add") s << t2 assert_equal(t1, s.delete(t1)) assert_nil(s.delete(t1)) assert_equal(TestSuite.new << t2, s) end def test_delete_tests suite = TestSuite.new test1 = self.class.new("test_delete_1") suite << test1 test2 = self.class.new("test_delete_2") suite << test2 test3 = self.class.new("test_add") suite << test3 suite.delete_tests([test1, test2]) assert_equal(1, suite.size) assert_equal(TestSuite.new << test3, suite) end def test_size suite = TestSuite.new suite2 = TestSuite.new suite2 << self.class.new("test_size") suite << suite2 suite << self.class.new("test_size") assert_equal(2, suite.size, "The count should be correct") end def test_run progress = [] @testcase1.test_order = :alphabetic suite = @testcase1.suite tests = suite.tests.dup result = TestResult.new suite.run(result) { |*values| progress << values } assert_equal(2, result.run_count, "Should have had four test runs") assert_equal(1, result.failure_count, "Should have had one test failure") assert_equal(0, result.error_count, "Should have had one test error") assert_equal([[TestSuite::STARTED, suite.name], [TestSuite::STARTED_OBJECT, suite], [TestCase::STARTED, "test_fail(#{suite.name})"], [TestCase::STARTED_OBJECT, tests[0]], [TestCase::FINISHED, "test_fail(#{suite.name})"], [TestCase::FINISHED_OBJECT, tests[0]], [TestCase::STARTED, "test_succeed1(#{suite.name})"], [TestCase::STARTED_OBJECT, tests[1]], [TestCase::FINISHED, "test_succeed1(#{suite.name})"], [TestCase::FINISHED_OBJECT, tests[1]], [TestSuite::FINISHED, suite.name], [TestSuite::FINISHED_OBJECT, suite]], progress, "Should have had the correct progress") suite = TestSuite.new suite << @testcase1.suite suite << @testcase2.suite result = TestResult.new progress = [] suite.run(result) { |*values| progress << values } assert_equal(4, result.run_count, "Should have had four test runs") assert_equal(1, result.failure_count, "Should have had one test failure") assert_equal(1, result.error_count, "Should have had one test error") assert_equal(28, progress.size, "Should have had the correct number of progress calls") end def test_empty? assert(TestSuite.new.empty?, "A new test suite should be empty?") assert(!@testcase2.suite.empty?, "A test suite with tests should not be empty") end def test_equality suite1 = TestSuite.new suite2 = TestSuite.new assert_equal(suite1, suite2) assert_equal(suite2, suite1) suite1 = TestSuite.new('name') assert_not_equal(suite1, suite2) assert_not_equal(suite2, suite1) suite2 = TestSuite.new('name') assert_equal(suite1, suite2) assert_equal(suite2, suite1) suite1 << 'test' assert_not_equal(suite1, suite2) assert_not_equal(suite2, suite1) suite2 << 'test' assert_equal(suite1, suite2) assert_equal(suite2, suite1) suite2 = Object.new class << suite2 def name 'name' end def tests ['test'] end end assert_not_equal(suite1, suite2) assert_not_equal(suite2, suite1) assert_not_equal(suite1, Object.new) assert_not_equal(Object.new, suite1) end end end end PK ]U_m77)gems/test-unit-3.3.4/test/test-failure.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/failure' module Test::Unit class TestFailure < TestCase def test_display f = Failure.new("name", [%q{location:1 in 'l'}], "message1\nmessage2") assert_equal("name: message1", f.short_display) assert_equal(< # # License: Ruby's require "test-unit" require "test/unit/fault-location-detector" require "testunit-test-util" class TestFaultLocationDetector < Test::Unit::TestCase include TestUnitTestUtil def setup @fetcher = Test::Unit::CodeSnippetFetcher.new end private def run_test_case(test_case) suite = test_case.suite result = Test::Unit::TestResult.new suite.run(result) {} result.faults[0] end def assert_detect(fault, target_line_number) detector = Test::Unit::FaultLocationDetector.new(fault, @fetcher) expected_backtrace_entries_until_detected = [] fault.location.each do |backtrace_entry| expected_backtrace_entries_until_detected << backtrace_entry _, line_number, = detector.split_backtrace_entry(backtrace_entry) break if target_line_number == line_number end actual_backtrace_entries_until_detected = [] fault.location.each do |backtrace_entry| actual_backtrace_entries_until_detected << backtrace_entry break if detector.target?(backtrace_entry) end assert_equal(expected_backtrace_entries_until_detected, actual_backtrace_entries_until_detected) end module AlwaysFailAssertion private def assert_always_failed assert_true(false) end end class TestSourceLocation < self setup def setup_check_source_location unless lambda {}.respond_to?(:source_location) omit("Need Proc#source_location") end end def test_detected target_line_number = nil test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion test "failed" do target_line_number = __LINE__; assert_always_failed end end fault = run_test_case(test_case) assert_detect(fault, target_line_number) end class TestOneLine < self def test_brace target_line_number = nil test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion test("failed") {target_line_number = __LINE__; assert_always_failed} def other_method # body end end fault = run_test_case(test_case) assert_detect(fault, target_line_number) end def test_do_end target_line_number = nil test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion test "failed" do target_line_number = __LINE__; assert_always_failed; end def other_method # body end end fault = run_test_case(test_case) assert_detect(fault, target_line_number) end end end class TestMethodName < self def test_detected test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion class << self def target_line_number @@target_line_number end def target_line_number=(line_number) @@target_line_number = line_number end end def test_failed self.class.target_line_number = __LINE__; assert_always_failed end end fault = run_test_case(test_case) assert_detect(fault, test_case.target_line_number) end end class TestInBlock < self def test_in_block test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion class << self def target_line_number @@target_line_number end def target_line_number=(line_number) @@target_line_number = line_number end end def run_yield yield end def test_failed run_yield do self.class.target_line_number = __LINE__; assert_always_failed end end end fault = run_test_case(test_case) assert_detect(fault, test_case.target_line_number) end end end PK ]G-44&gems/test-unit-3.3.4/test/test-data.rbnu[require "testunit-test-util" class TestData < Test::Unit::TestCase class Calc def initialize end def plus(augend, addend) augend + addend end end class TestCalc < Test::Unit::TestCase @@testing = false class << self def testing=(testing) @@testing = testing end end def valid? @@testing end def setup @calc = Calc.new end class TestDataSet < TestCalc data("positive positive" => {:expected => 4, :augend => 3, :addend => 1}, "positive negative" => {:expected => -1, :augend => 1, :addend => -2}) def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end end class TestNData < TestCalc data("positive positive", {:expected => 4, :augend => 3, :addend => 1}) data("positive negative", {:expected => -1, :augend => 1, :addend => -2}) def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end end class TestDynamicDataSet < TestCalc DATA_PROC = lambda do data_set = {} data_set["positive positive"] = { :expected => 3, :augend => 1, :addend => 2 } data_set["positive negative"] = { :expected => -1, :augend => 1, :addend => -2 } data_set end data(&DATA_PROC) def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end end class TestLoadDataSet < TestCalc extend TestUnitTestUtil load_data(fixture_file_path("plus.csv")) def test_plus(data) assert_equal(data["expected"], @calc.plus(data["augend"], data["addend"])) end end class TestSuperclass < TestCalc data("positive positive" => {:expected => 4, :augend => 3, :addend => 1}, "positive negative" => {:expected => -1, :augend => 1, :addend => -2}) def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end class TestNormalTestInSubclass < self def test_plus assert_equal(2, @calc.plus(1, 1)) end end end class TestMethod < TestCalc def data_test_plus { "positive positive" => {:expected => 4, :augend => 3, :addend => 1}, "positive negative" => {:expected => -1, :augend => 1, :addend => -2}, } end def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end end class TestPatterns < TestCalc data(:x, [-1, 1, 0]) data(:y, [-100, 100]) data(:z, ["a", "b", "c"]) def test_use_data(data) end end class TestPatternsKeep < TestCalc data(:x, [-1, 1, 0], keep: true) data(:y, [-100, 100]) data(:z, ["a", "b", "c"], keep: true) def test_use_data(data) end def test_use_data_keep(data) end end class TestPatternsGroup < TestCalc data(:a, [-1, 1, 0], group: 1) data(:b, [:a, :b], group: 1) data(:x, [2, 9], group: :z) data(:y, ["a", "b", "c"], group: :z) def test_use_data(data) end end end def setup TestCalc.testing = true end def teardown TestCalc.testing = false end def test_data_no_arguments_without_block assert_raise(ArgumentError) do self.class.data end end data("data set", { :test_case => TestCalc::TestDataSet, :data_sets => [ { "positive positive" => { :expected => 4, :augend => 3, :addend => 1, }, "positive negative" => { :expected => -1, :augend => 1, :addend => -2, }, }, ], }) data("n-data", { :test_case => TestCalc::TestNData, :data_sets => [ { "positive positive" => { :expected => 4, :augend => 3, :addend => 1, }, }, { "positive negative" => { :expected => -1, :augend => 1, :addend => -2, }, }, ], }) data("dynamic-data-set", { :test_case => TestCalc::TestDynamicDataSet, :data_sets => [TestCalc::TestDynamicDataSet::DATA_PROC], }) data("load-data-set", { :test_case => TestCalc::TestLoadDataSet, :data_sets => [ { "positive positive" => { "expected" => 4, "augend" => 3, "addend" => 1, }, }, { "positive negative" => { "expected" => -1, "augend" => 1, "addend" => -2, }, }, ], }) def test_data(data) test_plus = data[:test_case].new("test_plus") data_sets = Test::Unit::DataSets.new data[:data_sets].each do |data_set| data_sets.add(data_set) end assert_equal(data_sets, test_plus[:data]) end def test_data_patterns test = TestCalc::TestPatterns.new("test_use_data") data_sets = Test::Unit::DataSets.new data_sets << [:x, [-1, 1, 0]] data_sets << [:y, [-100, 100]] data_sets << [:z, ["a", "b", "c"]] assert_equal(data_sets, test[:data]) end def test_data_patterns_keep test = TestCalc::TestPatternsKeep.new("test_use_data_keep") data_sets = Test::Unit::DataSets.new data_sets.add([:x, [-1, 1, 0]], {keep: true}) data_sets.add([:z, ["a", "b", "c"]], {keep: true}) assert_equal(data_sets, test[:data]) end data("data set" => TestCalc::TestDataSet, "n-data" => TestCalc::TestNData, "dynamic-data-set" => TestCalc::TestDynamicDataSet, "load-data-set" => TestCalc::TestLoadDataSet) def test_suite(test_case) suite = test_case.suite assert_equal(["test_plus[positive negative](#{test_case.name})", "test_plus[positive positive](#{test_case.name})"], suite.tests.collect {|test| test.name}.sort) end def test_suite_patterns test_case = TestCalc::TestPatterns suite = test_case.suite assert_equal([ "test_use_data[x: -1, y: -100, z: \"a\"](#{test_case.name})", "test_use_data[x: -1, y: -100, z: \"b\"](#{test_case.name})", "test_use_data[x: -1, y: -100, z: \"c\"](#{test_case.name})", "test_use_data[x: -1, y: 100, z: \"a\"](#{test_case.name})", "test_use_data[x: -1, y: 100, z: \"b\"](#{test_case.name})", "test_use_data[x: -1, y: 100, z: \"c\"](#{test_case.name})", "test_use_data[x: 0, y: -100, z: \"a\"](#{test_case.name})", "test_use_data[x: 0, y: -100, z: \"b\"](#{test_case.name})", "test_use_data[x: 0, y: -100, z: \"c\"](#{test_case.name})", "test_use_data[x: 0, y: 100, z: \"a\"](#{test_case.name})", "test_use_data[x: 0, y: 100, z: \"b\"](#{test_case.name})", "test_use_data[x: 0, y: 100, z: \"c\"](#{test_case.name})", "test_use_data[x: 1, y: -100, z: \"a\"](#{test_case.name})", "test_use_data[x: 1, y: -100, z: \"b\"](#{test_case.name})", "test_use_data[x: 1, y: -100, z: \"c\"](#{test_case.name})", "test_use_data[x: 1, y: 100, z: \"a\"](#{test_case.name})", "test_use_data[x: 1, y: 100, z: \"b\"](#{test_case.name})", "test_use_data[x: 1, y: 100, z: \"c\"](#{test_case.name})", ], suite.tests.collect {|test| test.name}.sort) end def test_suite_patterns_group test_case = TestCalc::TestPatternsGroup suite = test_case.suite assert_equal([ "test_use_data[group: 1, a: -1, b: :a](#{test_case.name})", "test_use_data[group: 1, a: -1, b: :b](#{test_case.name})", "test_use_data[group: 1, a: 0, b: :a](#{test_case.name})", "test_use_data[group: 1, a: 0, b: :b](#{test_case.name})", "test_use_data[group: 1, a: 1, b: :a](#{test_case.name})", "test_use_data[group: 1, a: 1, b: :b](#{test_case.name})", "test_use_data[group: :z, x: 2, y: \"a\"](#{test_case.name})", "test_use_data[group: :z, x: 2, y: \"b\"](#{test_case.name})", "test_use_data[group: :z, x: 2, y: \"c\"](#{test_case.name})", "test_use_data[group: :z, x: 9, y: \"a\"](#{test_case.name})", "test_use_data[group: :z, x: 9, y: \"b\"](#{test_case.name})", "test_use_data[group: :z, x: 9, y: \"c\"](#{test_case.name})", ], suite.tests.collect {|test| test.name}.sort) end data("data set" => TestCalc::TestDataSet, "n-data" => TestCalc::TestNData, "dynamic-data-set" => TestCalc::TestDynamicDataSet, "load-data-set" => TestCalc::TestLoadDataSet, "superclass" => TestCalc::TestSuperclass, "method" => TestCalc::TestMethod) def test_run(test_case) result = _run_test(test_case) assert_equal("2 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, " \ "0 omissions, 0 notifications", result.to_s) end def test_run_normal_test_in_subclass result = _run_test(TestCalc::TestSuperclass::TestNormalTestInSubclass) assert_equal("1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, " \ "0 omissions, 0 notifications", result.to_s) end data("data set" => TestCalc::TestDataSet, "n-data" => TestCalc::TestNData, "dynamic-data-set" => TestCalc::TestDynamicDataSet, "load-data-set" => TestCalc::TestLoadDataSet) def test_equal(test_case) suite = test_case.suite positive_positive_test = suite.tests.find do |test| test.data_label == "positive positive" end suite.tests.delete(positive_positive_test) assert_equal(["test_plus[positive negative](#{test_case.name})"], suite.tests.collect {|test| test.name}.sort) end data("true" => {:expected => true, :target => "true"}, "false" => {:expected => false, :target => "false"}, "integer" => {:expected => 1, :target => "1"}, "float" => {:expected => 1.5, :target => "1.5"}, "string" => {:expected => "hello", :target => "hello"}) def test_normalize_value(data) loader = Test::Unit::Data::ClassMethods::Loader.new(self) assert_equal(data[:expected], loader.__send__(:normalize_value, data[:target])) end def _run_test(test_case) result = Test::Unit::TestResult.new test = test_case.suite yield(test) if block_given? test.run(result) {} result end class TestLoadData < Test::Unit::TestCase include TestUnitTestUtil def test_invalid_csv_file_name garbage = "X" file_name = "data.csv#{garbage}" assert_raise(ArgumentError, "unsupported file format: <#{file_name}>") do self.class.load_data(file_name) end end class TestFileFormat < self def setup self.class.current_attribute(:data).clear end class TestHeader < self data("csv" => "header.csv", "tsv" => "header.tsv") def test_normal(file_name) self.class.load_data(fixture_file_path(file_name)) data_sets = Test::Unit::DataSets.new data_sets << { "empty string" => { "expected" => true, "target" => "" } } data_sets << { "plain string" => { "expected" => false, "target" => "hello" } } assert_equal(data_sets, self.class.current_attribute(:data)[:value]) end data("csv" => "header-label.csv", "tsv" => "header-label.tsv") def test_label(file_name) self.class.load_data(fixture_file_path(file_name)) data_sets = Test::Unit::DataSets.new data_sets << { "upper case" => { "expected" => "HELLO", "label" => "HELLO" } } data_sets << { "lower case" => { "expected" => "Hello", "label" => "hello" } } assert_equal(data_sets, self.class.current_attribute(:data)[:value]) end end data("csv" => "no-header.csv", "tsv" => "no-header.tsv") def test_without_header(file_name) self.class.load_data(fixture_file_path(file_name)) data_sets = Test::Unit::DataSets.new data_sets << {"empty string" => [true, ""]} data_sets << {"plain string" => [false, "hello"]} assert_equal(data_sets, self.class.current_attribute(:data)[:value]) end end end end PK ]J  .gems/test-unit-3.3.4/test/test-code-snippet.rbnu[# coding: utf-8 require "test-unit" require "testunit-test-util" class TestCodeSnippet < Test::Unit::TestCase include TestUnitTestUtil class TestJRuby < self def test_error_inside_jruby jruby_only_test backtrace = backtrace_from_jruby no_rb_entries = backtrace.find_all do |(file, _, _)| File.extname(file) != ".rb" end fetcher = Test::Unit::CodeSnippetFetcher.new snippets = no_rb_entries.collect do |(file, line, _)| fetcher.fetch(file, line) end assert_equal([[]] * no_rb_entries.size, snippets) end private def backtrace_from_jruby begin java.util.Vector.new(-1) rescue Exception $@.collect do |entry| entry.split(/:/, 3) end else flunk("failed to raise an exception from JRuby.") end end end class TestDefaultExternal < self def suppress_warning verbose = $VERBOSE begin $VERBOSE = false yield ensure $VERBOSE = verbose end end def setup suppress_warning do @default_external = Encoding.default_external end @fetcher = Test::Unit::CodeSnippetFetcher.new end def teardown suppress_warning do Encoding.default_external = @default_external end end def test_windows_31j source = Tempfile.new(["test-code-snippet", ".rb"]) source.puts(<<-SOURCE) puts("あいうえお") SOURCE source.flush suppress_warning do Encoding.default_external = "Windows-31J" end assert_equal([ [1, "puts(\"あいうえお\")", {:target_line? => false}], ], @fetcher.fetch(source.path, 0)) end end end PK ]w22'gems/test-unit-3.3.4/test/test-color.rbnu[class TestUnitColor < Test::Unit::TestCase def test_color_escape_sequence assert_escape_sequence(["31"], color("red")) assert_escape_sequence(["32", "1"], color("green", :bold => true)) assert_escape_sequence(["0"], color("reset")) assert_escape_sequence(["45"], color("magenta", :background => true)) end def test_mix_color_escape_sequence assert_escape_sequence(["34", "1"], mix_color([color("blue"), color("none", :bold => true)])) assert_escape_sequence(["34", "1", "4"], mix_color([color("blue"), color("none", :bold => true)]) + color("none", :underline => true)) assert_escape_sequence(["34", "1", "4"], color("blue") + color("none", :bold => true) + color("none", :underline => true)) end def test_equal red = color("red") red_bold = color("red", :bold => true) assert_operator(red, :==, red) assert_not_equal(red, nil) assert_equal(red, color("red")) assert_not_equal(red, red_bold) end private def color(name, options={}) Test::Unit::Color.new(name, options) end def mix_color(colors) Test::Unit::MixColor.new(colors) end def assert_escape_sequence(expected, color) assert_equal(expected, color.sequence) assert_match(/\e\[(?:\d+;)*\d+m/, color.escape_sequence) assert_equal(expected, color.escape_sequence[2..-2].split(";")) end end PK ]20~,/gems/test-unit-3.3.4/test/testunit-test-util.rbnu[require "tempfile" module TestUnitTestUtil private def jruby? RUBY_PLATFORM == "java" end def jruby_only_test if jruby? require "java" else omit("test for JRuby") end end def assert_fault_messages(expected, faults) assert_equal(expected, faults.collect {|fault| fault.message}) end def _run_test(test_case, name) result = Test::Unit::TestResult.new test = test_case.new(name) yield(test) if block_given? test.run(result) {} result end def fixture_file_path(file_name) base_dir = File.dirname(__FILE__) File.join(base_dir, "fixtures", file_name) end end PK ]:QQ+gems/test-unit-3.3.4/test/test-test-case.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2008-2014 Kouhei Sutou # Copyright:: Copyright (c) 2011 Haruka Yoshihara # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott # License:: Ruby license. require 'test/unit' module Test module Unit class TestTestCase < TestCase self.test_order = :random def test_creation test_case = Class.new(TestCase) do def test_with_arguments(arg1, arg2) end end test = test_case.new(:test_with_arguments) check("Should have caught an invalid test when there are arguments", !test.valid?) test = test_case.new(:non_existent_test) check("Should have caught an invalid test when the method does not exist", !test.valid?) end def setup @tc_failure_error = Class.new(TestCase) do def test_failure assert_block("failure") do false end end def test_error 1 / 0 end def test_nested_failure nested end def nested assert_block("nested") do false end end def return_passed? return passed? end end def @tc_failure_error.name "TC_FailureError" end end def jruby_backtrace_entry?(entry) entry.start_with?("org/jruby/") end def rubinius_backtrace_entry?(entry) entry.start_with?("kernel/") end def normalize_location(location) filtered_location = location.reject do |entry| jruby_backtrace_entry?(entry) or rubinius_backtrace_entry?(entry) end filtered_location.collect do |entry| entry.sub(/:\d+:/, ":0:") end end def test_add_failed_assertion test_case = @tc_failure_error.new(:test_failure) assert do test_case.passed? end result = TestResult.new faults = [] result.add_listener(TestResult::FAULT) do |fault| faults << fault end progress = [] test_case.run(result) do |*arguments| progress << arguments end fault_details = faults.collect do |fault| { :class => fault.class, :message => fault.message, :test_name => fault.test_name, :location => normalize_location(fault.location), } end assert_equal([ { :class => Failure, :message => "failure", :test_name => "test_failure(TC_FailureError)", :location => [ "#{__FILE__}:0:in `test_failure'", "#{__FILE__}:0:in `#{__method__}'", ], }, ], fault_details) assert do not test_case.passed? end assert_equal([ [TestCase::STARTED, test_case.name], [TestCase::STARTED_OBJECT, test_case], [TestCase::FINISHED, test_case.name], [TestCase::FINISHED_OBJECT, test_case], ], progress) end def test_add_failure_nested test_case = @tc_failure_error.new(:test_nested_failure) assert do test_case.passed? end result = TestResult.new faults = [] result.add_listener(TestResult::FAULT) do |fault| faults << fault end test_case.run(result) do end fault_details = faults.collect do |fault| { :class => fault.class, :message => fault.message, :test_name => fault.test_name, :location => normalize_location(fault.location), } end assert_equal([ { :class => Failure, :message => "nested", :test_name => "test_nested_failure(TC_FailureError)", :location => [ "#{__FILE__}:0:in `nested'", "#{__FILE__}:0:in `test_nested_failure'", "#{__FILE__}:0:in `#{__method__}'", ], }, ], fault_details) assert do not test_case.passed? end end def jruby? defined?(JRUBY_VERSION) end def rubinius? false # TODO end def cruby? (not jruby?) and (not rubinius?) end def test_add_error test_case = @tc_failure_error.new(:test_error) assert do test_case.passed? end result = TestResult.new faults = [] result.add_listener(TestResult::FAULT) do |fault| faults << fault end test_case.run(result) do end fault_details = faults.collect do |fault| { :class => fault.class, :message => fault.message, :test_name => fault.test_name, :location => normalize_location(fault.location), } end location = [] location << "#{__FILE__}:0:in `/'" if cruby? location << "#{__FILE__}:0:in `test_error'" location << "#{__FILE__}:0:in `#{__method__}'" assert_equal([ { :class => Error, :message => "ZeroDivisionError: divided by 0", :test_name => "test_error(TC_FailureError)", :location => location, }, ], fault_details) assert do not test_case.passed? end end def test_no_tests suite = TestCase.suite check("Should have a test suite", suite.instance_of?(TestSuite)) check("Should have one test", suite.size == 1) check("Should have the default test", suite.tests.first.name == "default_test(Test::Unit::TestCase)") result = TestResult.new suite.run(result) {} check("Should have had one test run", result.run_count == 1) check("Should have had one test failure", result.failure_count == 1) check("Should have had no errors", result.error_count == 0) end def test_suite tc = Class.new(TestCase) do def test_succeed assert_block {true} end def test_fail assert_block {false} end def test_error 1/0 end def dont_run assert_block {true} end def test_dont_run(argument) assert_block {true} end def test assert_block {true} end end suite = tc.suite check("Should have a test suite", suite.instance_of?(TestSuite)) check("Should have three tests", suite.size == 3) result = TestResult.new suite.run(result) {} check("Should have had three test runs", result.run_count == 3) check("Should have had one test failure", result.failure_count == 1) check("Should have had one test error", result.error_count == 1) end def test_setup_teardown tc = Class.new(TestCase) do attr_reader(:setup_called, :teardown_called) def initialize(test) super(test) @setup_called = false @teardown_called = false end def setup @setup_called = true end def teardown @teardown_called = true end def test_succeed assert_block {true} end def test_fail assert_block {false} end def test_error raise "Error!" end end result = TestResult.new test = tc.new(:test_succeed) test.run(result) {} check("Should have called setup the correct number of times", test.setup_called) check("Should have called teardown the correct number of times", test.teardown_called) test = tc.new(:test_fail) test.run(result) {} check("Should have called setup the correct number of times", test.setup_called) check("Should have called teardown the correct number of times", test.teardown_called) test = tc.new(:test_error) test.run(result) {} check("Should have called setup the correct number of times", test.setup_called) check("Should have called teardown the correct number of times", test.teardown_called) check("Should have had two test runs", result.run_count == 3) check("Should have had a test failure", result.failure_count == 1) check("Should have had a test error", result.error_count == 1) end def test_assertion_failed_not_called tc = Class.new(TestCase) do def test_thing raise AssertionFailedError.new end end suite = tc.suite check("Should have one test", suite.size == 1) result = TestResult.new suite.run(result) {} check("Should have had one test run", result.run_count == 1) check("Should have had one assertion failure", result.failure_count == 1) check("Should not have any assertion errors but had #{result.error_count}", result.error_count == 0) end def test_equality tc1 = Class.new(TestCase) do def test_1 end def test_2 end end tc2 = Class.new(TestCase) do def test_1 end end test1 = tc1.new('test_1') test2 = tc1.new('test_1') check("Should be equal", test1 == test2) check("Should be equal", test2 == test1) test1 = tc1.new('test_2') check("Should not be equal", test1 != test2) check("Should not be equal", test2 != test1) test2 = tc1.new('test_2') check("Should be equal", test1 == test2) check("Should be equal", test2 == test1) test1 = tc1.new('test_1') test2 = tc2.new('test_1') check("Should not be equal", test1 != test2) check("Should not be equal", test2 != test1) check("Should not be equal", test1 != Object.new) check("Should not be equal", Object.new != test1) end def test_re_raise_exception test_case = Class.new(TestCase) do def test_raise_interrupt raise Interrupt, "from test" end end test = test_case.new("test_raise_interrupt") begin test.run(TestResult.new) {} check("Should not be reached", false) rescue Exception check("Interrupt exception should be re-raised", $!.class == Interrupt) end end def test_timeout_error test_case = Class.new(TestCase) do def test_raise_timeout_error require "timeout" raise Timeout::Error end end test_suite = test_case.suite result = TestResult.new begin test_suite.run(result) {} check("Timeout::Error should be handled as error", result.error_count == 1) rescue Exception check("Timeout::Error should not be passed through: #{$!}", false) end end def test_interrupted test_case = Class.new(TestCase) do def test_fail flunk end def test_nothing end end failed_test = test_case.new(:test_fail) failed_test.run(TestResult.new) {} check("Should be interrupted", failed_test.interrupted?) success_test = test_case.new(:test_nothing) success_test.run(TestResult.new) {} check("Should not be interrupted", !success_test.interrupted?) end def test_inherited_test_should_be_ignored test_case = Class.new(TestCase) do def test_nothing end end sub_test_case = Class.new(test_case) do def test_fail flunk end end test = test_case.new("test_nothing") assert_predicate(test, :valid?) test = sub_test_case.new("test_fail") assert_predicate(test, :valid?) test = sub_test_case.new("test_nothing") assert_not_predicate(test, :valid?) end def test_mixin_test_should_not_be_ignored test_module = Module.new do def test_nothing end end test_case = Class.new(Test::Unit::TestCase) do include test_module def test_fail flunk end end assert_nothing_thrown do test_case.new("test_nothing") end assert_nothing_thrown do test_case.new("test_fail") end end def test_defined_order test_case = Class.new(Test::Unit::TestCase) do def test_z end def test_1 end def test_a end end test_case.test_order = :defined assert_equal(["test_z", "test_1", "test_a"], test_case.suite.tests.collect {|test| test.method_name}) end def test_declarative_style test_case = Class.new(Test::Unit::TestCase) do test "declarative style test definition" do end test "include parenthesis" do end test "1 + 2 = 3" do end end test_case.test_order = :defined assert_equal(["test: declarative style test definition", "test: include parenthesis", "test: 1 + 2 = 3"], test_case.suite.tests.collect {|test| test.method_name}) assert_equal(["declarative style test definition", "include parenthesis", "1 + 2 = 3"], test_case.suite.tests.collect {|test| test.description}) end def test_test_mark test_case = Class.new(Test::Unit::TestCase) do test def my_test_method end end test_case.test_order = :defined assert_equal(["my_test_method"], test_case.suite.tests.collect {|test| test.method_name}) end def test_redefine_method test_case = Class.new(Test::Unit::TestCase) do self.test_order = :alphabetic def test_name end alias_method :test_name2, :test_name def test_name end end suite = test_case.suite assert_equal(["test_name", "test_name2"], suite.tests.collect {|test| test.method_name}) result = TestResult.new suite.run(result) {} assert_equal("2 tests, 0 assertions, 0 failures, " + "0 errors, 0 pendings, 0 omissions, 1 notifications", result.summary) end def test_data_driven_test test_case = Class.new(TestCase) do def test_with_data(data) end end test = test_case.new("test_with_data") assert_not_predicate(test, :valid?) test.assign_test_data("label1", :test_data1) assert_predicate(test, :valid?) end def test_data_driven_test_without_parameter test_case = Class.new(TestCase) do data("label" => "value") def test_without_parameter assert_equal("value", data) end end suite = test_case.suite assert_equal(["test_without_parameter"], suite.tests.collect {|test| test.method_name}) result = TestResult.new suite.run(result) {} assert_equal("1 tests, 1 assertions, 0 failures, " + "0 errors, 0 pendings, 0 omissions, 0 notifications", result.summary) end private def check(message, passed) add_assertion raise AssertionFailedError.new(message) unless passed end class TestTestDefined < self class TestNoQuery < self def test_no_test test_case = Class.new(TestCase) do end assert_false(test_case.test_defined?({})) end def test_have_def_style_test test_case = Class.new(TestCase) do def test_nothing end end assert_true(test_case.test_defined?({})) end def test_have_method_style_test test_case = Class.new(TestCase) do test "nothing" do end end assert_true(test_case.test_defined?({})) end end class TestPath < self class TestDefStyle < self def test_base_name test_case = Class.new(TestCase) do def test_nothing end end base_name = File.basename(__FILE__) assert_true(test_case.test_defined?(:path => base_name)) end def test_absolute_path test_case = Class.new(TestCase) do def test_nothing end end assert_true(test_case.test_defined?(:path => __FILE__)) end def test_not_match test_case = Class.new(TestCase) do def test_nothing end end assert_false(test_case.test_defined?(:path => "nonexistent.rb")) end end class TestMethodStyle < self def test_base_name test_case = Class.new(TestCase) do test "nothing" do end end base_name = File.basename(__FILE__) assert_true(test_case.test_defined?(:path => base_name)) end def test_absolute_path test_case = Class.new(TestCase) do test "nothing" do end end assert_true(test_case.test_defined?(:path => __FILE__)) end def test_not_match test_case = Class.new(TestCase) do test "nothing" do end end assert_false(test_case.test_defined?(:path => "nonexistent.rb")) end end end class TestLine < self class TestDefStyle < self def test_before line_before = nil test_case = Class.new(TestCase) do line_before = __LINE__ def test_nothing end end assert_false(test_case.test_defined?(:line => line_before)) end def test_def line_def = nil test_case = Class.new(TestCase) do line_def = __LINE__; def test_nothing end end assert_true(test_case.test_defined?(:line => line_def)) end def test_after line_after = nil test_case = Class.new(TestCase) do def test_nothing end line_after = __LINE__ end assert_true(test_case.test_defined?(:line => line_after)) end def test_child child_test_case = nil line_child = nil parent_test_case = Class.new(TestCase) do test "parent" do end child_test_case = Class.new(self) do line_child = __LINE__; test "child" do end end end assert_equal([ false, true, ], [ parent_test_case.test_defined?(:line => line_child), child_test_case.test_defined?(:line => line_child), ]) end end class TestMethodStyle < self def test_before line_before = nil test_case = Class.new(TestCase) do line_before = __LINE__ test "nothing" do end end assert_false(test_case.test_defined?(:line => line_before)) end def test_method line_method = nil test_case = Class.new(TestCase) do line_method = __LINE__; test "nothing" do end end assert_true(test_case.test_defined?(:line => line_method)) end def test_after line_after = nil test_case = Class.new(TestCase) do test "nothing" do end line_after = __LINE__ end assert_true(test_case.test_defined?(:line => line_after)) end def test_child child_test_case = nil line_child = nil parent_test_case = Class.new(TestCase) do test "parent" do end child_test_case = Class.new(self) do line_child = __LINE__; test "child" do end end end assert_equal([ false, true, ], [ parent_test_case.test_defined?(:line => line_child), child_test_case.test_defined?(:line => line_child), ]) end def test_with_setup line = nil test_case = Class.new(TestCase) do setup do end line = __LINE__; test "with setup" do end end assert do test_case.test_defined?(:line => line, :method_name => "test: with setup") end end end end class TestMethodName < self class TestDefStyle < self def test_match test_case = Class.new(TestCase) do def test_nothing end end query = {:method_name => "test_nothing"} assert_true(test_case.test_defined?(query)) end def test_not_match test_case = Class.new(TestCase) do def test_nothing end end query = {:method_name => "test_nonexistent"} assert_false(test_case.test_defined?(query)) end end class TestMethodStyle < self def test_match test_case = Class.new(TestCase) do test "nothing" do end end query = {:method_name => "test: nothing"} assert_true(test_case.test_defined?(query)) end def test_not_match test_case = Class.new(TestCase) do test "nothing" do end end query = {:method_name => "test: nonexistent"} assert_false(test_case.test_defined?(query)) end end end class TestCombine < self class TestDefStyle < self def test_line_middle line_middle = nil test_case = Class.new(TestCase) do def test_before end line_middle = __LINE__ def test_after end end query = { :path => __FILE__, :line => line_middle, :method_name => "test_before", } assert_true(test_case.test_defined?(query)) end def test_line_after_def line_after_def = nil test_case = Class.new(TestCase) do def test_before end line_after_def = __LINE__; def test_after end end query = { :path => __FILE__, :line => line_after_def, :method_name => "test_before", } assert_false(test_case.test_defined?(query)) end end class TestMethodStyle < self def test_line_middle line_middle = nil test_case = Class.new(TestCase) do test "before" do end line_middle = __LINE__ test "after" do end end query = { :path => __FILE__, :line => line_middle, :method_name => "test: before", } assert_true(test_case.test_defined?(query)) end def test_line_after_method line_after_method = nil test_case = Class.new(TestCase) do test "before" do end line_after_method = __LINE__; test "after" do end end query = { :path => __FILE__, :line => line_after_method, :method_name => "test: before", } assert_false(test_case.test_defined?(query)) end end end end class TestSubTestCase < self class TestName < self def test_anonymous test_case = Class.new(TestCase) sub_test_case = test_case.sub_test_case("sub test case") do end assert_equal("sub test case", sub_test_case.name) end def test_named test_case = Class.new(TestCase) def test_case.name "ParentTestCase" end sub_test_case = test_case.sub_test_case("sub test case") do end assert_equal("ParentTestCase::sub test case", sub_test_case.name) end end def test_suite test_case = Class.new(TestCase) sub_test_case = test_case.sub_test_case("sub test case") do def test_nothing end end test_method_names = sub_test_case.suite.tests.collect do |test| test.method_name end assert_equal(["test_nothing"], test_method_names) end def test_duplicated_name test_case = Class.new(TestCase) do def test_nothing end end sub_test_case = test_case.sub_test_case("sub test case") do def test_nothing end end test_method_names = test_case.suite.tests.collect do |test| test.method_name end sub_test_method_names = sub_test_case.suite.tests.collect do |test| test.method_name end assert_equal([ ["test_nothing"], ["test_nothing"], ], [ test_method_names, sub_test_method_names, ]) end end class TestStartupShutdown < self class TestOrder < self module CallLogger def called @@called ||= [] end end def call_order(test_case) test_case.called.clear test_suite = test_case.suite test_suite.run(TestResult.new) {} test_case.called end class TestNoInheritance < self def setup @test_case = Class.new(TestCase) do extend CallLogger class << self def startup called << :startup end def shutdown called << :shutdown end end def setup self.class.called << :setup end def teardown self.class.called << :teardown end def test1 end def test2 end end end def test_call_order assert_equal([ :startup, :setup, :teardown, :setup, :teardown, :shutdown, ], call_order(@test_case)) end end class TestInheritance < self def setup @original_descendants = TestCase::DESCENDANTS.dup TestCase::DESCENDANTS.clear @parent_test_case = Class.new(TestCase) do extend CallLogger self.test_order = :alphabetic class << self def startup called << :startup_parent end def shutdown called << :shutdown_parent end end def setup self.class.called << :setup_parent end def teardown self.class.called << :teardown_parent end def test1_parent self.class.called << :test1_parent end def test2_parent self.class.called << :test2_parent end end @child_test_case = Class.new(@parent_test_case) do class << self def startup called << :startup_child end def shutdown called << :shutdown_child end end def setup self.class.called << :setup_child end def teardown self.class.called << :teardown_child end def test1_child self.class.called << :test1_child end def test2_child self.class.called << :test2_child end end end def teardown TestCase::DESCENDANTS.replace(@original_descendants) end def test_call_order collector = Collector::Descendant.new test_suite = collector.collect test_suite.run(TestResult.new) {} called = @parent_test_case.called assert_equal([ :startup_parent, :setup_parent, :test1_parent, :teardown_parent, :setup_parent, :test2_parent, :teardown_parent, :startup_child, :setup_child, :test1_child, :teardown_child, :setup_child, :test2_child, :teardown_child, :shutdown_child, :shutdown_parent, ], called) end end end class TestError < self def run_test_case(test_case) test_suite = test_case.suite result = TestResult.new test_suite.run(result) {} result end def error_count(test_case) run_test_case(test_case).error_count end def test_on_startup test_case = Class.new(TestCase) do class << self def startup raise "from startup" end end def test_nothing end end assert_equal(1, error_count(test_case)) end def test_pass_through_on_startup test_case = Class.new(TestCase) do class << self def startup raise Interrupt, "from startup" end end def test_nothing end end assert_raise(Interrupt) do run_test_case(test_case) end end def test_on_shutdown test_case = Class.new(TestCase) do class << self def shutdown raise "from shutdown" end end def test_nothing end end assert_equal(1, error_count(test_case)) end def test_pass_through_on_shutdown test_case = Class.new(TestCase) do class << self def shutdown raise Interrupt, "from shutdown" end end def test_nothing end end assert_raise(Interrupt) do run_test_case(test_case) end end def test_pass_through_in_test test_case = Class.new(TestCase) do @called = [] class << self def called @called end def startup @called << :startup end def shutdown @called << :shutdown end end def test_error raise Interrupt, "from test" end end assert_raise(Interrupt) do run_test_case(test_case) end assert_equal([:startup, :shutdown], test_case.called) end class TestName < self def test_no_data test_case = Class.new(TestCase) do class << self def name "TestCase" end end def test_nothing end end test = test_case.new("test_nothing") assert_equal("test_nothing(TestCase)", test.name) end def test_data test_case = Class.new(TestCase) do class << self def name "TestCase" end end def test_nothing end end test = test_case.new("test_nothing") test.assign_test_data("(nil)", nil) assert_equal("test_nothing[(nil)](TestCase)", test.name) end end class TestLocalName < self def test_no_data test_case = Class.new(TestCase) do class << self def name "TestCase" end end def test_nothing end end test = test_case.new("test_nothing") assert_equal("test_nothing", test.local_name) end def test_data test_case = Class.new(TestCase) do class << self def name "TestCase" end end def test_nothing end end test = test_case.new("test_nothing") test.assign_test_data("(nil)", nil) assert_equal("test_nothing[(nil)]", test.local_name) end end end end end end end PK ])N,gems/test-unit-3.3.4/test/test-assertions.rbnu[# -*- coding: utf-8 -*- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # Copyright (c) 2009-2014 Kouhei Sutou. All rights reserved. # License:: Ruby license. require 'test/unit' require "testunit-test-util" module Test module Unit module AssertionCheckable include TestUnitTestUtil private def check(value, message="") add_assertion raise AssertionFailedError.new(message) unless value end def check_assertions(expect_fail, options={}) expected_message = options[:expected_message] actual_message_normalizer = options[:actual_message_normalizer] return_value_expected = options[:return_value_expected] @actual_assertion_count = 0 failed = true actual_message = nil @catch_assertions = true return_value = nil begin return_value = yield failed = false rescue AssertionFailedError => error return_value = error actual_message = error.message end @catch_assertions = false if expect_fail message = "Should have failed, but didn't" else message = "Should not have failed, but did with message\n" + "<#{actual_message}>" end check(expect_fail == failed, message) message = "Should have made one assertion but made\n" + "<#{@actual_assertion_count}>" check(1 == @actual_assertion_count, message) if expect_fail if actual_message_normalizer actual_message = actual_message_normalizer.call(actual_message) end case expected_message when String check(expected_message == actual_message, "Should have the correct message.\n" + "<#{expected_message.inspect}> expected but was\n" + "<#{actual_message.inspect}>") when Regexp check(expected_message =~ actual_message, "The message should match correctly.\n" + " expected to match\n" + "<#{actual_message.inspect}>") else check(false, "Incorrect expected message type in assert_nothing_failed") end else case return_value_expected when :dont_care # do nothing when true check(!return_value.nil?, "Should return a value") else check(return_value.nil?, "Should not return a value but returned <#{return_value}>") end end return_value end def check_nothing_fails(return_value_expected=false, &proc) check_assertions(false, {:expected_message => nil, :return_value_expected => return_value_expected}, &proc) end def check_fail(expected_message, options={}, &proc) check_assertions(true, options.merge(:expected_message => expected_message), &proc) end def check_fail_exception(expected_message, options={}, &proc) normalizer = lambda do |actual_message| actual_message.gsub(/(^[^:\n]+:\d+:.+\n?)+\z/, "") end check_assertions(true, options.merge(:expected_message => expected_message, :actual_message_normalizer => normalizer), &proc) end def inspect_tag(tag) tag.inspect end def add_failure(message, location=caller, options=nil) unless @catch_assertions super end end def add_assertion if @catch_assertions @actual_assertion_count += 1 else super end end end class TestAssertions < TestCase include AssertionCheckable class TestAssertBlock < self def test_pass_without_message check_nothing_fails { assert_block {true} } end def test_pass_with_message check_nothing_fails { assert_block("successful assert_block") {true} } end def test_failure_without_message check_fail("assert_block failed.") { assert_block {false} } end def test_failure_with_message check_fail("failed assert_block") { assert_block("failed assert_block") {false} } end end class TestAssertEqual < self class TestSuccess < self def test_without_message check_nothing_fails { assert_equal("string1", "string1") } end def test_with_message check_nothing_fails { assert_equal("string1", "string1", "successful assert_equal") } end end class TestFailure < self def test_without_message message = <<-EOM.chomp <"string1"> expected but was <"string2">. diff: - string1 ? ^ + string2 ? ^ EOM check_fail(message) { assert_equal("string1", "string2") } end def test_with_message message = <<-EOM.chomp failed assert_equal. <"string1"> expected but was <"string2">. diff: - string1 ? ^ + string2 ? ^ EOM check_fail(message) { assert_equal("string1", "string2", "failed assert_equal") } end def test_with_message_proc message = <<-EOM.chomp failed assert_equal. <"string1"> expected but was <"string2">. diff: - string1 ? ^ + string2 ? ^ EOM check_fail(message) do assert_equal("string1", "string2", lambda {"failed assert_equal"}) end end end class TestSystemMessage < self def test_different_type message = <<-EOM.chomp <"111111"> expected but was <111111>. diff: - "111111" ? - - + 111111 EOM check_fail(message) do assert_equal("111111", 111111) end end def test_long_line expected = ["0123456789", "1123456789", "2123456789", "3123456789", "4123456789", "5123456789", "6123456789", "7123456789", "8123456789"].join actual = ["0000000000", "1123456789", "2123456789", "3123456789", "4123456789", "5123456789", "6123456789", "7123456789", "8123456789"].join message = <<-EOM.chomp <"#{expected}"> expected but was <"#{actual}">. diff: - #{expected} ? ^^^^^^^^^ + #{actual} ? ^^^^^^^^^ folded diff: - 012345678911234567892123456789312345678941234567895123456789612345678971234567 ? ^^^^^^^^^ + 000000000011234567892123456789312345678941234567895123456789612345678971234567 ? ^^^^^^^^^ 898123456789 EOM check_fail(message) do assert_equal(expected, actual) end end def test_too_small_difference message = <<-EOM.chomp <1> expected but was <2>. EOM check_fail(message) do assert_equal(1, 2) end end def test_same_inspected_objects same_inspected_class = Class.new do def inspect "inspected" end end object1 = same_inspected_class.new object2 = same_inspected_class.new message = <<-EOM.chomp expected but was . EOM check_fail(message) do assert_equal(object1, object2) end end def test_multi_lines_result message = <<-EOM.chomp <#{AssertionMessage.convert("a\nb")}> expected but was <#{AssertionMessage.convert("x")}>. diff: + x - a - b EOM check_fail(message) do assert_equal("a\nb", "x") end end def test_large_string message = <<-EOM.chomp <#{AssertionMessage.convert("a\n" + "x" * 997)}> expected but was <#{AssertionMessage.convert("x")}>. diff: + x - a - #{"x" * 997} folded diff: + x - a #{(["- " + ("x" * 78)] * 12).join("\n")} - #{"x" * 61} EOM check_fail(message) do assert_equal("a\n" + "x" * 997, "x") end message = <<-EOM.chomp <#{AssertionMessage.convert("a\n" + "x" * 998)}> expected but was <#{AssertionMessage.convert("x")}>. EOM check_fail(message) do assert_equal("a\n" + "x" * 998, "x") end end def test_max_diff_target_string_size key = "TEST_UNIT_MAX_DIFF_TARGET_STRING_SIZE" before_value = ENV[key] ENV[key] = "100" begin message = <<-EOM.chomp <#{AssertionMessage.convert("a\n" + "x" * 97)}> expected but was <#{AssertionMessage.convert("x")}>. diff: + x - a - #{"x" * 97} folded diff: + x - a #{(["- " + ("x" * 78)]).join("\n")} - #{"x" * 19} EOM check_fail(message) do assert_equal("a\n" + "x" * 97, "x") end message = <<-EOM.chomp <#{AssertionMessage.convert("a\n" + "x" * 98)}> expected but was <#{AssertionMessage.convert("x")}>. EOM check_fail(message) do assert_equal("a\n" + "x" * 98, "x") end ensure ENV[key] = before_value end end def test_different_encoding utf8_string = "こんにちは" unless utf8_string.respond_to?(:force_encoding) omit("encoding test is for Ruby >= 1.9") end ascii_8bit_string = utf8_string.dup.force_encoding("ascii-8bit") message = <<-EOM.chomp <#{utf8_string.inspect}>("UTF-8") expected but was <#{ascii_8bit_string.inspect}>("ASCII-8BIT"). EOM check_fail(message) do assert_equal(utf8_string, ascii_8bit_string) end end def test_different_hash designers = { "Ruby" => "Matz", "Lisp" => "John McCarthy", } categories = { "LL" => ["Ruby", "Python"], "Heavy" => ["C", "C++"], } message = <<-EOM.chomp <{"Lisp"=>"John McCarthy", "Ruby"=>"Matz"}> expected but was <{"Heavy"=>["C", "C++"], "LL"=>["Ruby", "Python"]}>. EOM check_fail(message) do assert_equal(designers, categories) end end def test_recursive_hash alice = {"name" => "Alice"} bob = {"name" => "Bob"} alice["followers"] = [bob] bob["followers"] = [alice] message = <<-EOM.chomp <{"followers"=>[{"followers"=>[{...}], "name"=>"Bob"}], "name"=>"Alice"}> expected but was <{"followers"=>[{"followers"=>[{...}], "name"=>"Alice"}], "name"=>"Bob"}>. diff: - {"followers"=>[{"followers"=>[{...}], "name"=>"Bob"}], "name"=>"Alice"} ? ----------------- + {"followers"=>[{"followers"=>[{...}], "name"=>"Alice"}], "name"=>"Bob"} ? +++++++++++++++++ EOM check_fail(message) do assert_equal(alice, bob) end end def test_numeric numeric_family_class = Class.new(Numeric) do def inspect "inspect is called" end def to_s "to_s is called" end end numeric = numeric_family_class.new message = <<-MESSAGE.chomp expected but was <"must be failed">. MESSAGE check_fail(message) do assert_equal(numeric, "must be failed") end end end end def test_assert_raise_success return_value = nil check_nothing_fails(true) do return_value = assert_raise(RuntimeError) do raise "Error" end end check(return_value.kind_of?(Exception), "Should have returned the exception " + "from a successful assert_raise") check(return_value.message == "Error", "Should have returned the correct exception " + "from a successful assert_raise") check_nothing_fails(true) do assert_raise(ArgumentError, "successful assert_raise") do raise ArgumentError.new("Error") end end check_nothing_fails(true) do assert_raise(RuntimeError) do raise "Error" end end check_nothing_fails(true) do assert_raise(RuntimeError, "successful assert_raise") do raise "Error" end end check_nothing_fails(true) do assert_raise do raise Exception, "Any exception" end end end def test_assert_raise_fail check_fail(" exception was expected but none was thrown.") do assert_raise(RuntimeError) do 1 + 1 end end message = <<-EOM.chomp failed assert_raise. exception expected but was )>. EOM check_fail_exception(message) do assert_raise(ArgumentError, "failed assert_raise") do raise "Error" end end message = <<-EOM must be a subclass of Exception, an object of Exception subclasses or a Module. EOM check_fail(message.chomp) do assert_nothing_raised(Object) do 1 + 1 end end end def test_assert_raise_module exceptions = [ArgumentError, TypeError] modules = [Math, Comparable] rescues = exceptions + modules exceptions.each do |exc| return_value = nil check_nothing_fails(true) do return_value = assert_raise(*rescues) do raise exc, "Error" end end check(return_value.instance_of?(exc), "Should have returned #{exc} but was #{return_value.class}") check(return_value.message == "Error", "Should have returned the correct exception " + "from a successful assert_raise") end modules.each do |mod| return_value = nil check_nothing_fails(true) do return_value = assert_raise(*rescues) do raise Exception.new("Error").extend(mod) end end check(mod === return_value, "Should have returned #{mod}") check(return_value.message == "Error", "Should have returned the correct exception " + "from a successful assert_raise") end check_fail("<[ArgumentError, TypeError, Math, Comparable]> exception " + "was expected but none was thrown.") do assert_raise(*rescues) do 1 + 1 end end message = <<-EOM.chomp failed assert_raise. <[ArgumentError, TypeError]> exception expected but was )>. EOM check_fail_exception(message) do assert_raise(ArgumentError, TypeError, "failed assert_raise") do raise "Error" end end end def test_assert_raise_instance return_value = nil check_nothing_fails(true) do return_value = assert_raise(RuntimeError.new("Error")) do raise "Error" end end check(return_value.kind_of?(Exception), "Should have returned the exception " + "from a successful assert_raise") check(return_value.message == "Error", "Should have returned the correct exception " + "from a successful assert_raise") message = <<-EOM.chomp )> exception expected but was )>. diff: - RuntimeError() ? ^^^ + RuntimeError() ? ^^^^^ EOM check_fail_exception(message) do return_value = assert_raise(RuntimeError.new("XXX")) do raise "Error" end end different_error_class = Class.new(StandardError) message = <<-EOM.chomp <#{different_error_class.inspect}()> exception expected but was )>. EOM check_fail_exception(message) do assert_raise(different_error_class.new("Error")) do raise "Error" end end different_error = different_error_class.new("Error") def different_error.inspect "DifferentError: \"Error\"" end message = <<-EOM.chomp exception expected but was )>. EOM check_fail_exception(message) do assert_raise(different_error) do raise "Error" end end check_nothing_fails(true) do assert_raise(different_error_class.new("Error"), RuntimeError.new("Error"), RuntimeError.new("XXX")) do raise "Error" end end end def test_assert_raise_jruby omit("For JRuby") unless Object.const_defined?(:Java) exception = Java::JavaLang::StringIndexOutOfBoundsException return_value = nil check_nothing_fails(true) do return_value = assert_raise(exception) do Java::JavaLang::String.new("abc").char_at(4) end end check(return_value.instance_of?(exception), "Should have returned #{exception} but was #{return_value.class}") end def test_assert_instance_of check_nothing_fails { assert_instance_of(String, "string") } check_nothing_fails { assert_instance_of(String, "string", "successful assert_instance_of") } check_nothing_fails { assert_instance_of(String, "string", "successful assert_instance_of") } check_fail(%Q{<"string"> was expected to be instance_of?\n but was\n.}) { assert_instance_of(Hash, "string") } check_fail(%Q{failed assert_instance_of.\n<"string"> was expected to be instance_of?\n but was\n.}) { assert_instance_of(Hash, "string", "failed assert_instance_of") } check_nothing_fails do assert_instance_of([Class, NilClass], Array) end check_fail(%Q{<"string"> was expected to be instance_of?\n[, ] but was\n.}) do assert_instance_of([Class, NilClass], "string") end check_fail(%Q{ was expected to be instance_of?\n[, ] but was\n.}) do assert_instance_of([Module, NilClass], Array) end end def test_assert_not_instance_of check_nothing_fails { assert_not_instance_of(NilClass, "string") } check_nothing_fails { assert_not_instance_of(NilClass, "string", "successful assert_instance_of") } check_fail(%Q{<"string"> was expected to not be instance_of?\n but was.}) { assert_not_instance_of(String, "string") } check_fail(%Q{failed assert.\n<"string"> was expected to not be instance_of?\n but was.}) { assert_not_instance_of(String, "string", "failed assert") } check_nothing_fails do assert_not_instance_of([Module, NilClass], Array) end check_fail(%Q{ was expected to not be instance_of?\n[, ] but was.}) do assert_not_instance_of([Class, NilClass], Array) end check_fail(%Q{<"str"> was expected to not be instance_of?\n[, ] but was.}) do assert_not_instance_of([Numeric, String], 'str') end end def test_assert_nil check_nothing_fails { assert_nil(nil) } check_nothing_fails { assert_nil(nil, "successful assert_nil") } check_nothing_fails { assert_nil(nil, "successful assert_nil") } check_fail(%Q{<"string"> was expected to be nil.}) { assert_nil("string") } check_fail(%Q{failed assert_nil.\n<"string"> was expected to be nil.}) { assert_nil("string", "failed assert_nil") } end def test_assert_not_nil check_nothing_fails{assert_not_nil(false)} check_nothing_fails{assert_not_nil(false, "message")} check_fail(" was expected to not be nil."){assert_not_nil(nil)} check_fail("message.\n was expected to not be nil.") {assert_not_nil(nil, "message")} end def test_assert_kind_of check_nothing_fails { assert_kind_of(Module, Array) } check_nothing_fails { assert_kind_of(Object, "string", "successful assert_kind_of") } check_nothing_fails { assert_kind_of(String, "string", "successful assert_kind_of") } check_nothing_fails { assert_kind_of(Comparable, 1) } check_fail(%Q{<"string"> was expected to be kind_of?\n but was\n.}) { assert_kind_of(Class, "string") } check_fail(%Q{failed assert_kind_of.\n<"string"> was expected to be kind_of?\n but was\n.}) { assert_kind_of(Class, "string", "failed assert_kind_of") } check_nothing_fails do assert_kind_of([Class, NilClass], Array) end check_fail(%Q{<"string"> was expected to be kind_of?\n[, ] but was\n.}) do assert_kind_of([Class, NilClass], "string") end end def test_assert_not_kind_of check_nothing_fails { assert_not_kind_of(Class, 42) } check_nothing_fails { assert_not_kind_of(Symbol, "string", "successful assert_not_kind_of") } check_nothing_fails { assert_not_kind_of(Integer, 1.1) } check_fail(%Q{<1> was expected to not be kind_of?\n but was.}) { assert_not_kind_of(Integer, 1) } check_fail(%Q{failed assert_not_kind_of.\n<"string"> was expected to not be kind_of?\n but was.}) { assert_not_kind_of(String, "string", "failed assert_not_kind_of") } check_nothing_fails do assert_not_kind_of([String, NilClass], 100) end check_fail(%Q{ was expected to not be kind_of?\n[, ] but was.}) do assert_not_kind_of([Class, NilClass], Array) end end def test_assert_match check_nothing_fails { assert_match(/strin./, "string") } check_nothing_fails { assert_match("strin", "string") } check_nothing_fails { assert_match(/strin./, "string", "successful assert_match") } check_nothing_fails { assert_match(/strin./, "string", "successful assert_match") } check_fail(%Q{ was expected to be =~\n<"string">.}) { assert_match(/slin./, "string") } check_fail(%Q{ was expected to be =~\n<"string">.}) { assert_match("strin.", "string") } check_fail(%Q{failed assert_match.\n was expected to be =~\n<"string">.}) { assert_match(/slin./, "string", "failed assert_match") } end def test_assert_same thing = "thing" check_nothing_fails { assert_same(thing, thing) } check_nothing_fails { assert_same(thing, thing, "successful assert_same") } check_nothing_fails { assert_same(thing, thing, "successful assert_same") } thing2 = thing.dup check_fail(%Q{<"thing">\nwith id <#{thing.__id__}> was expected to be equal? to\n<"thing">\nwith id <#{thing2.__id__}>.}) { assert_same(thing, thing2) } check_fail(%Q{failed assert_same.\n<"thing">\nwith id <#{thing.__id__}> was expected to be equal? to\n<"thing">\nwith id <#{thing2.__id__}>.}) { assert_same(thing, thing2, "failed assert_same") } end def test_assert_nothing_raised check_nothing_fails(:dont_care) { assert_nothing_raised { 1 + 1 } } check_nothing_fails(:dont_care) { assert_nothing_raised("successful assert_nothing_raised") { 1 + 1 } } check_nothing_fails(:dont_care) { assert_nothing_raised("successful assert_nothing_raised") { 1 + 1 } } check_nothing_fails(:dont_care) { begin assert_nothing_raised(RuntimeError, StandardError, Comparable, "successful assert_nothing_raised") { raise ZeroDivisionError.new("ArgumentError") } rescue ZeroDivisionError end } expected_message = " must be a subclass of Exception, " + "an object of Exception subclasses or a Module." check_fail(expected_message) { assert_nothing_raised(Object) { 1 + 1 } } expected_message = <<-EOM.chomp Exception raised: RuntimeError() EOM check_fail_exception(expected_message) { assert_nothing_raised { raise "Error" } } expected_message = <<-EOM.chomp failed assert_nothing_raised. Exception raised: RuntimeError() EOM check_fail_exception(expected_message) { assert_nothing_raised("failed assert_nothing_raised") { raise "Error" } } expected_message = <<-EOM.chomp Exception raised: RuntimeError() EOM check_fail_exception(expected_message) { assert_nothing_raised(StandardError, RuntimeError) { raise "Error" } } check_fail("Failure.") do assert_nothing_raised do flunk("Failure") end end end def test_flunk check_fail("Flunked.") { flunk } check_fail("flunk message.") { flunk("flunk message") } end def test_assert_not_same thing = "thing" thing2 = thing.dup check_nothing_fails { assert_not_same(thing, thing2) } check_nothing_fails { assert_not_same(thing, thing2, "message") } check_fail(%Q{<"thing">\nwith id <#{thing.__id__}> was expected to not be equal? to\n<"thing">\nwith id <#{thing.__id__}>.}) { assert_not_same(thing, thing) } check_fail(%Q{message.\n<"thing">\nwith id <#{thing.__id__}> was expected to not be equal? to\n<"thing">\nwith id <#{thing.__id__}>.}) { assert_not_same(thing, thing, "message") } end def test_assert_not_equal check_nothing_fails { assert_not_equal("string1", "string2") } check_nothing_fails { assert_not_equal("string1", "string2", "message") } check_fail(%Q{<"string"> was expected to be != to\n<"string">.}) { assert_not_equal("string", "string") } check_fail(%Q{message.\n<"string"> was expected to be != to\n<"string">.}) { assert_not_equal("string", "string", "message") } end def test_assert_not_match_pass check_nothing_fails do assert_not_match(/sling/, "string") end end def test_assert_not_match_pass_with_message check_nothing_fails do assert_not_match(/sling/, "string", "message") end end def test_assert_not_match_fail_not_regexp check_fail(" in assert_not_match(, ...) " + "should be a Regexp.\n" + "<\"asdf\"> was expected to be instance_of?\n" + " but was\n" + ".") do assert_not_match("asdf", "asdf") end end def test_assert_not_match_fail_match check_fail(" was expected to not match\n" + "<\"string\">.") do assert_not_match(/string/, "string") end end def test_assert_not_match_fail_match_with_message check_fail("message.\n" + " was expected to not match\n" + "<\"string\">.") do assert_not_match(/string/, "string", "message") end end def test_assert_no_match check_nothing_fails{assert_no_match(/sling/, "string")} check_nothing_fails{assert_no_match(/sling/, "string", "message")} check_fail(%Q{The first argument to assert_no_match should be a Regexp.\n<"asdf"> was expected to be instance_of?\n but was\n.}) do assert_no_match("asdf", "asdf") end check_fail(%Q{ was expected to not match\n<"string">.}) do assert_no_match(/string/, "string") end check_fail(%Q{message.\n was expected to not match\n<"string">.}) do assert_no_match(/string/, "string", "message") end end def test_assert_throw check_nothing_fails do assert_throw(:thing, "message") do throw :thing end end tag = :thing2 check_fail("message.\n" + "<:thing> was expected to be thrown but\n" + "<#{inspect_tag(tag)}> was thrown.") do assert_throw(:thing, "message") do throw :thing2 end end check_fail("message.\n" + "<:thing> should have been thrown.") do assert_throw(:thing, "message") do 1 + 1 end end end def test_assert_nothing_thrown check_nothing_fails do assert_nothing_thrown("message") do 1 + 1 end end tag = :thing inspected = inspect_tag(tag) check_fail("message.\n" + "<#{inspected}> was thrown when nothing was expected.") do assert_nothing_thrown("message") do throw tag end end end def test_assert_operator check_nothing_fails { assert_operator("thing", :==, "thing", "message") } check_fail(%Q{<0.15>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to?(:to_str).}) do assert_operator("thing", 0.15, "thing") end check_fail(%Q{message.\n<"thing1"> was expected to be\n==\n<"thing2">.}) { assert_operator("thing1", :==, "thing2", "message") } end def test_assert_not_operator check_nothing_fails { assert_not_operator("thing", :==, "Thing", "message") } check_fail(%Q{<42>\ngiven as the operator for #assert_not_operator must be a Symbol or #respond_to?(:to_str).}) do assert_not_operator("thing", 42, "message") end check_fail(%Q{message.\n<0> was expected to not be\n==\n<0.0>.}) { assert_not_operator(0, :==, 0.0, "message") } end def test_assert_respond_to check_nothing_fails { assert_respond_to("thing", :to_s, "message") } check_nothing_fails { assert_respond_to("thing", "to_s", "message") } check_fail("<0.15>.kind_of?(Symbol) or\n" + "<0.15>.respond_to?(:to_str) expected") { assert_respond_to("thing", 0.15) } check_fail("message.\n" + "<:symbol>.respond_to?(:nonexistence) expected\n" + "(Class: )") { assert_respond_to(:symbol, :nonexistence, "message") } end def test_assert_not_respond_to_pass_symbol check_nothing_fails do assert_not_respond_to("thing", :nonexistent, "message") end end def test_assert_not_respond_to_pass_string check_nothing_fails do assert_not_respond_to("thing", :nonexistent, "message") end end def test_assert_not_respond_to_fail_number check_fail("<0.15>.kind_of?(Symbol) or\n" + "<0.15>.respond_to?(:to_str) expected") do assert_respond_to("thing", 0.15) end end def tset_assert_not_respond_to_fail_existence check_fail("message.\n" + "!<:symbol>.respond_to?(:to_s) expected\n" + "(Class: )") do assert_respond_to(:symbol, :to_s, "message") end end def test_assert_send object = Object.new class << object private def return_argument(argument, bogus) return argument end end check_nothing_fails do assert_send([object, :return_argument, true, "bogus"], "message") end inspected_object = AssertionMessage.convert(object) expected_message = <<-EOM message. <#{inspected_object}> was expected to respond to with a true value but was . EOM check_fail(expected_message.chomp) do assert_send([object, :return_argument, false, "bogus"], "message") end end def test_condition_invariant object = Object.new def object.inspect @changed = true end def object.==(other) @changed ||= false return (!@changed) end check_nothing_fails do assert_equal(object, object, "message") end end def test_assert_boolean check_nothing_fails do assert_boolean(true) end check_nothing_fails do assert_boolean(false) end check_fail(" or expected but was\n<1>") do assert_boolean(1) end check_fail(" or expected but was\n") do assert_boolean(nil) end check_fail("message.\n or expected but was\n<\"XXX\">") do assert_boolean("XXX", "message") end end def test_assert_true check_nothing_fails do assert_true(true) end check_fail(" expected but was\n") do assert_true(false) end check_fail(" expected but was\n<1>") do assert_true(1) end exception = check_fail("message.\n expected but was\n") do assert_true(nil, "message") end assert_equal("message", exception.user_message) end def test_assert_false check_nothing_fails do assert_false(false) end check_fail(" expected but was\n") do assert_false(true) end check_fail(" expected but was\n") do assert_false(nil) end check_fail("message.\n expected but was\n<:false>") do assert_false(:false, "message") end end def test_assert_compare check_nothing_fails do assert_compare(1.4, "<", 10.0) end check_nothing_fails do assert_compare(2, "<=", 2) end check_nothing_fails do assert_compare(14, ">=", 10.0) end check_nothing_fails do assert_compare(14, ">", 13.9) end expected_message = <<-EOM <15> < <10> should be true <15> was expected to be less than <10>. EOM check_fail(expected_message.chomp) do assert_compare(15, "<", 10) end expected_message = <<-EOM <15> <= <10> should be true <15> was expected to be less than or equal to <10>. EOM check_fail(expected_message.chomp) do assert_compare(15, "<=", 10) end expected_message = <<-EOM <10> > <15> should be true <10> was expected to be greater than <15>. EOM check_fail(expected_message.chomp) do assert_compare(10, ">", 15) end expected_message = <<-EOM <10> >= <15> should be true <10> was expected to be greater than or equal to <15>. EOM check_fail(expected_message.chomp) do assert_compare(10, ">=", 15) end end def test_assert_fail_assertion check_nothing_fails do assert_fail_assertion do flunk end end check_fail("Failed assertion was expected.") do assert_fail_assertion do end end end def test_assert_raise_message check_nothing_fails do assert_raise_message("Raise!") do raise "Raise!" end end check_nothing_fails do assert_raise_message("Raise!") do raise Exception, "Raise!" end end check_nothing_fails do assert_raise_message(/raise/i) do raise "Raise!" end end expected_message = <<-EOM <"Expected message"> exception message expected but was <"Actual message">. EOM check_fail(expected_message.chomp) do assert_raise_message("Expected message") do raise "Actual message" end end expected_message = <<-EOM <"Expected message"> exception message was expected but none was thrown. EOM check_fail(expected_message.chomp) do assert_raise_message("Expected message") do end end end def test_assert_raise_kind_of check_nothing_fails(true) do assert_raise_kind_of(SystemCallError) do raise Errno::EACCES end end expected_message = <<-EOM.chomp family exception expected but was )>. EOM check_fail_exception(expected_message) do assert_raise_kind_of(SystemCallError) do raise RuntimeError, "XXX" end end end def test_assert_const_defined check_nothing_fails do assert_const_defined(Test, :Unit) end check_nothing_fails do assert_const_defined(Test, "Unit") end check_fail(".const_defined?(<:Nonexistence>) expected.") do assert_const_defined(Test, :Nonexistence) end end def test_assert_not_const_defined check_nothing_fails do assert_not_const_defined(Test, :Nonexistence) end check_fail("!.const_defined?(<:Unit>) expected.") do assert_not_const_defined(Test, :Unit) end check_fail("!.const_defined?(<\"Unit\">) expected.") do assert_not_const_defined(Test, "Unit") end end def test_assert_predicate check_nothing_fails do assert_predicate([], :empty?) end check_fail("<[1]>.empty? is true value expected but was\n") do assert_predicate([1], :empty?) end check_fail("<[1]>.respond_to?(:nonexistent?) expected\n" + "(Class: )") do assert_predicate([1], :nonexistent?) end end def test_assert_not_predicate check_nothing_fails do assert_not_predicate([1], :empty?) end check_fail("<[]>.empty? is false value expected but was\n") do assert_not_predicate([], :empty?) end check_fail("<[]>.respond_to?(:nonexistent?) expected\n" + "(Class: )") do assert_not_predicate([], :nonexistent?) end end def test_assert_alias_method object = Object.new class << object def original_method end alias_method :alias_method, :original_method def other end end check_nothing_fails do assert_alias_method(object, :alias_method, :original_method) end check_nothing_fails do assert_alias_method(object, :original_method, :alias_method) end check_fail("<#{object.method(:other).inspect}> is alias of\n" + "<#{object.method(:original_method).inspect}> expected") do assert_alias_method(object, :other, :original_method) end inspected_object = AssertionMessage.convert(object) check_fail("<#{inspected_object}>.nonexistent doesn't exist\n" + "(Class: )") do assert_alias_method(object, :nonexistent, :original_method) end check_fail("<#{inspected_object}>.nonexistent doesn't exist\n" + "(Class: )") do assert_alias_method(object, :alias_method, :nonexistent) end end def test_assert_path_exist check_nothing_fails do assert_path_exist(__FILE__) end nonexistent_file = __FILE__ + ".nonexistent" check_fail("<#{nonexistent_file.inspect}> was expected to exist") do assert_path_exist(nonexistent_file) end end def test_assert_path_not_exist nonexistent_file = __FILE__ + ".nonexistent" check_nothing_fails do assert_path_not_exist(nonexistent_file) end check_fail("<#{__FILE__.inspect}> was expected to not exist") do assert_path_not_exist(__FILE__) end end end class TestAssert < TestCase include AssertionCheckable def test_pass check_nothing_fails do assert(true) end end def test_pass_neither_false_or_nil check_nothing_fails do assert("a") end end def test_pass_with_message check_nothing_fails do assert(true, "successful assert") end end def test_pass_block check_nothing_fails do assert do true end end end def test_fail_nil check_fail(" is not true.") do assert(nil) end end def test_fail_false check_fail(" is not true.") do assert(false) end end def test_fail_false_with_message check_fail("failed assert.\n" + " is not true.") do assert(false, "failed assert") end end def test_fail_with_assertion_message check_fail("user message.\n" + "placeholder <:in> message") do assert(false, build_message("user message", "placeholder message", :in)) end end def test_fail_block check_fail(//) do assert do 0.odd? end end end def test_error_invalid_message_true check_fail("assertion message must be String, Proc or " + "Test::Unit::Assertions::AssertionMessage: " + "()") do begin assert(true, true) rescue ArgumentError raise AssertionFailedError, $!.message end end end def test_error_wrong_number_of_arguments check_fail("wrong number of arguments (0 for 1..2)") do begin assert rescue ArgumentError raise AssertionFailedError, $!.message end end end class TestBlock < self def test_with_message if defined?(PowerAssert) system_message = <<-MESSAGE.chomp 1.to_s == "2" | | | false "1" MESSAGE else system_message = " is not true." end check_fail("user message.\n#{system_message}") do assert("user message") do 1.to_s == "2" end end end end end class TestRefute < TestCase include AssertionCheckable class TestPass < self def test_nil check_nothing_fails do refute(nil) end end def test_false check_nothing_fails do refute(false) end end def test_with_message check_nothing_fails do refute(nil, "successful refute") end end end class TestFailure < self def test_true check_fail(" is neither nil or false.") do refute(true) end end def test_with_message check_fail("failed refute.\n" + " is neither nil or false.") do refute(true, "failed refute") end end def test_fail_with_assertion_message check_fail("user message.\n" + "placeholder <:in> message") do refute(true, build_message("user message", "placeholder message", :in)) end end def test_error_invalid_message_true check_fail("assertion message must be String, Proc or " + "Test::Unit::Assertions::AssertionMessage: " + "()") do begin refute(true, false) rescue ArgumentError raise AssertionFailedError, $!.message end end end end end class TestAssertInDelta < TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_in_delta(1.4, 1.4, 0) end end def test_pass_without_delta check_nothing_fails do assert_in_delta(1.401, 1.402) end end def test_pass_with_message check_nothing_fails do assert_in_delta(0.5, 0.4, 0.1, "message") end end def test_pass_float_like_object check_nothing_fails do float_thing = Object.new def float_thing.to_f 0.2 end assert_in_delta(0.1, float_thing, 0.1) end end def test_pass_string_expected check_nothing_fails do assert_in_delta("0.5", 0.4, 0.1) end end def test_fail_with_message check_fail("message.\n" + "<0.5> -/+ <0.05> was expected to include\n" + "<0.4>.\n" + "\n" + "Relation:\n" + "<<0.4> < <0.5>-<0.05>[0.45] <= <0.5>+<0.05>[0.55]>") do assert_in_delta(0.5, 0.4, 0.05, "message") end end def test_fail_because_not_float_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The arguments must respond to to_f; " + "the first float did not.\n" + "<#{inspected_object}>.respond_to?(:to_f) expected\n" + "(Class: )") do assert_in_delta(object, 0.4, 0.1) end end def test_fail_because_negaitve_delta check_fail("The delta should not be negative.\n" + "<-0.1> was expected to be\n>=\n<0.0>.") do assert_in_delta(0.5, 0.4, -0.1, "message") end end def test_fail_without_delta check_fail("<1.402> -/+ <0.001> was expected to include\n" + "<1.404>.\n" + "\n" + "Relation:\n" + "<" + "<1.402>-<0.001>[#{1.402 - 0.001}] <= " + "<1.402>+<0.001>[#{1.402 + 0.001}] < " + "<1.404>" + ">") do assert_in_delta(1.402, 1.404) end end end class TestAssertNotInDelta < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_in_delta(1.42, 1.44, 0.01) end end def test_pass_without_delta check_nothing_fails do assert_not_in_delta(1.402, 1.404) end end def test_pass_with_message check_nothing_fails do assert_not_in_delta(0.5, 0.4, 0.09, "message") end end def test_pass_float_like_object check_nothing_fails do float_thing = Object.new def float_thing.to_f 0.2 end assert_not_in_delta(0.1, float_thing, 0.09) end end def test_pass_string_epxected check_nothing_fails do assert_not_in_delta("0.5", 0.4, 0.09) end end def test_fail check_fail("<1.4> -/+ <0.11> was expected to not include\n" + "<1.5>.\n" + "\n" + "Relation:\n" + "<" + "<1.4>-<0.11>[#{1.4 - 0.11}] <= " + "<1.5> <= " + "<1.4>+<0.11>[#{1.4 + 0.11}]" + ">") do assert_not_in_delta(1.4, 1.5, 0.11) end end def test_fail_without_delta check_fail("<1.402> -/+ <0.001> was expected to not include\n" + "<1.4021>.\n" + "\n" + "Relation:\n" + "<" + "<1.402>-<0.001>[#{1.402 - 0.001}] <= " + "<1.4021> <= " + "<1.402>+<0.001>[#{1.402 + 0.001}]" + ">") do assert_not_in_delta(1.402, 1.4021) end end def test_fail_with_message check_fail("message.\n" + "<0.5> -/+ <0.11> was expected to not include\n" + "<0.4>.\n" + "\n" + "Relation:\n" + "<" + "<0.5>-<0.11>[0.39] <= " + "<0.4> <= " + "<0.5>+<0.11>[0.61]" + ">") do assert_not_in_delta(0.5, 0.4, 0.11, "message") end end def test_fail_because_not_float_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The arguments must respond to to_f; " + "the first float did not.\n" + "<#{inspected_object}>.respond_to?(:to_f) expected\n" + "(Class: )") do assert_not_in_delta(object, 0.4, 0.1) end end def test_fail_because_negaitve_delta check_fail("The delta should not be negative.\n" + "<-0.11> was expected to be\n>=\n<0.0>.") do assert_not_in_delta(0.5, 0.4, -0.11, "message") end end end class TestAssertInEpsilon < TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_in_epsilon(10000, 9000, 0.1) end end def test_pass_without_epsilon check_nothing_fails do assert_in_epsilon(10000, 9991) end end def test_pass_with_message check_nothing_fails do assert_in_epsilon(10000, 9000, 0.1, "message") end end def test_pass_float_like_object check_nothing_fails do float_thing = Object.new def float_thing.to_f 9000.0 end assert_in_epsilon(10000, float_thing, 0.1) end end def test_pass_string_expected check_nothing_fails do assert_in_epsilon("10000", 9000, 0.1) end end def test_pass_zero_expected check_nothing_fails do assert_in_epsilon(0, 0.00000001) end end def test_pass_minus_expected check_nothing_fails do assert_in_epsilon(-1, -1) end end def test_fail_with_message check_fail("message.\n" + "<10000> -/+ (<10000> * <0.1>)[1000.0] " + "was expected to include\n" + "<8999>.\n" + "\n" + "Relation:\n" + "<" + "<8999> < " + "<10000>-(<10000>*<0.1>)[9000.0] <= " + "<10000>+(<10000>*<0.1>)[11000.0]" + ">") do assert_in_epsilon(10000, 8999, 0.1, "message") end end def test_fail_because_not_float_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The arguments must respond to to_f; " + "the first float did not.\n" + "<#{inspected_object}>.respond_to?(:to_f) expected\n" + "(Class: )") do assert_in_epsilon(object, 9000, 0.1) end end def test_fail_because_negaitve_epsilon check_fail("The epsilon should not be negative.\n" + "<-0.1> was expected to be\n>=\n<0.0>.") do assert_in_epsilon(10000, 9000, -0.1, "message") end end def test_fail_without_epsilon check_fail("<10000> -/+ (<10000> * <0.001>)[10.0] " + "was expected to include\n" + "<10011>.\n" + "\n" + "Relation:\n" + "<" + "<10000>-(<10000>*<0.001>)[9990.0] <= " + "<10000>+(<10000>*<0.001>)[10010.0] < " + "<10011>" + ">") do assert_in_epsilon(10000, 10011) end end end class TestAssertNotInEpsilon < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_in_epsilon(10000, 8999, 0.1) end end def test_pass_without_epsilon check_nothing_fails do assert_not_in_epsilon(10000, 9989) end end def test_pass_with_message check_nothing_fails do assert_not_in_epsilon(10000, 8999, 0.1, "message") end end def test_pass_float_like_object check_nothing_fails do float_thing = Object.new def float_thing.to_f 8999.0 end assert_not_in_epsilon(10000, float_thing, 0.1) end end def test_pass_string_epxected check_nothing_fails do assert_not_in_epsilon("10000", 8999, 0.1) end end def test_fail check_fail("<10000> -/+ (<10000> * <0.1>)[1000.0] " + "was expected to not include\n" + "<9000>.\n" + "\n" + "Relation:\n" + "<" + "<10000>-(<10000>*<0.1>)[9000.0] <= " + "<9000> <= " + "<10000>+(<10000>*<0.1>)[11000.0]" + ">") do assert_not_in_epsilon(10000, 9000, 0.1) end end def test_fail_without_epsilon check_fail("<10000> -/+ (<10000> * <0.001>)[10.0] " + "was expected to not include\n" + "<9990>.\n" + "\n" + "Relation:\n" + "<" + "<10000>-(<10000>*<0.001>)[9990.0] <= " + "<9990> <= " + "<10000>+(<10000>*<0.001>)[10010.0]" + ">") do assert_not_in_epsilon(10000, 9990) end end def test_fail_with_message check_fail("message.\n" + "<10000> -/+ (<10000> * <0.1>)[1000.0] " + "was expected to not include\n" + "<9000>.\n" + "\n" + "Relation:\n" + "<" + "<10000>-(<10000>*<0.1>)[9000.0] <= " + "<9000> <= " + "<10000>+(<10000>*<0.1>)[11000.0]" + ">") do assert_not_in_epsilon(10000, 9000, 0.1, "message") end end def test_fail_because_not_float_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The arguments must respond to to_f; " + "the first float did not.\n" + "<#{inspected_object}>.respond_to?(:to_f) expected\n" + "(Class: )") do assert_not_in_epsilon(object, 9000, 0.1) end end def test_fail_because_negaitve_epsilon check_fail("The epsilon should not be negative.\n" + "<-0.1> was expected to be\n>=\n<0.0>.") do assert_not_in_epsilon(10000, 9000, -0.1, "message") end end end class TestAssertInclude < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_include([1, 2, 3], 1) end end def test_pass_with_message check_nothing_fails do assert_include([1, 2, 3], 1, "message") end end def test_fail check_fail("<[1, 2, 3]> was expected to include\n" + "<4>.") do assert_include([1, 2, 3], 4) end end def test_fail_with_message check_fail("message.\n" + "<[1, 2, 3]> was expected to include\n" + "<4>.") do assert_include([1, 2, 3], 4, "message") end end def test_fail_because_not_collection_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The collection must respond to :include?.\n" + "<#{inspected_object}>.respond_to?(:include?) expected\n" + "(Class: )") do assert_include(object, 1) end end end class TestAssertNotInclude < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_include([1, 2, 3], 5) end end def test_pass_with_message check_nothing_fails do assert_not_include([1, 2, 3], 5, "message") end end def test_fail check_fail("<[1, 2, 3]> was expected to not include\n" + "<2>.") do assert_not_include([1, 2, 3], 2) end end def test_fail_with_message check_fail("message.\n" + "<[1, 2, 3]> was expected to not include\n" + "<2>.") do assert_not_include([1, 2, 3], 2, "message") end end def test_fail_because_not_collection_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The collection must respond to :include?.\n" + "<#{inspected_object}>.respond_to?(:include?) expected\n" + "(Class: )") do assert_not_include(object, 1) end end end class TestAssertEmpty < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_empty([]) end end def test_pass_with_message check_nothing_fails do assert_empty([], "message") end end def test_fail check_fail("<[1]> was expected to be empty.") do assert_empty([1]) end end def test_fail_with_message check_fail("message.\n" + "<[1]> was expected to be empty.") do assert_empty([1], "message") end end def test_fail_because_no_empty_method object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The object must respond to :empty?.\n" + "<#{inspected_object}>.respond_to?(:empty?) expected\n" + "(Class: )") do assert_empty(object) end end end class TestAssertNotEmpty < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_empty([1]) end end def test_pass_with_message check_nothing_fails do assert_not_empty([1], "message") end end def test_fail check_fail("<[]> was expected to not be empty.") do assert_not_empty([]) end end def test_fail_with_message check_fail("message.\n" + "<[]> was expected to not be empty.") do assert_not_empty([], "message") end end def test_fail_because_no_empty_method object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The object must respond to :empty?.\n" + "<#{inspected_object}>.respond_to?(:empty?) expected\n" + "(Class: )") do assert_not_empty(object) end end end class TestAssertNotSend < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_send([[1, 2], :member?, 4], "message") end end def test_fail expected_message = <<-EOM message. <[1, 2]> was expected to respond to with not a true value but was . EOM check_fail(expected_message.chomp) do assert_not_send([[1, 2], :member?, 2], "message") end end end class TestTemplate < Test::Unit::TestCase def test_incompatible_encoding_by_diff need_encoding assert_raise(AssertionFailedError) do assert_equal("UTF-8の日本語\n" * 3, ("Shift_JISの日本語\n" * 3).force_encoding("ASCII-8BIT")) end end private def need_encoding omit("need Encoding") unless Object.const_defined?(:Encoding) end end end end PK ]kVV)gems/test-unit-3.3.4/test/test-fixture.rbnu[class TestUnitFixture < Test::Unit::TestCase module EmptyModule end class TestSetup < self def test_without_option expected_setup_calls = [:setup, :custom_setup_method0, :custom_setup_callback0, :custom_setup_method1, :custom_setup_callback1, :custom_setup_method3, :custom_setup_callback3] test_case = assert_setup(expected_setup_calls, []) assert_inherited_setup(expected_setup_calls, test_case) assert_inherited_setup([:setup], nil) assert_called_fixtures(expected_setup_calls, test_case) end def test_with_before_option expected_setup_calls = [:custom_setup_callback3, :custom_setup_method3, :custom_setup_method0, :custom_setup_callback0, :custom_setup_method1, :custom_setup_callback1, :setup] test_case = assert_setup(expected_setup_calls, [[{:before => :append}], [{:before => :append}], [{:before => :prepend}], [{:before => :prepend}]]) assert_inherited_setup(expected_setup_calls, test_case) assert_inherited_setup([:setup], nil) assert_called_fixtures(expected_setup_calls, test_case) end def test_with_after_option expected_setup_calls = [:setup, :custom_setup_callback3, :custom_setup_method3, :custom_setup_method0, :custom_setup_callback0, :custom_setup_method1, :custom_setup_callback1] test_case = assert_setup(expected_setup_calls, [[{:after => :append}], [{:after => :append}], [{:after => :prepend}], [{:after => :prepend}]]) assert_inherited_setup(expected_setup_calls, test_case) assert_inherited_setup([:setup], nil) assert_called_fixtures(expected_setup_calls, test_case) end def test_with_invalid_option assert_invalid_setup_option(:unknown => true) assert_invalid_setup_option(:before => :unknown) assert_invalid_setup_option(:after => :unknown) end def test_with_option_to_inherited expected_setup_calls = [:setup] test_case = assert_setup(expected_setup_calls, nil) assert_inherited_setup([:setup, :custom_setup_method0, :custom_setup_callback0, :custom_setup_method1, :custom_setup_callback1, :custom_setup_method3, :custom_setup_callback3], test_case, []) assert_inherited_setup([:setup], nil) assert_called_fixtures(expected_setup_calls, test_case) end private def assert_setup_customizable(expected, parent, options) test_case = Class.new(parent || Test::Unit::TestCase) do yield(self, :before) if block_given? def called_ids @called_ids ||= [] end def called(id) called_ids << id end def setup called(:setup) end setup(*(options[0] || [])) if options def custom_setup_method0 called(:custom_setup_method0) end if options setup(*(options[0] || [])) do called(:custom_setup_callback0) end end def custom_setup_method1 called(:custom_setup_method1) end setup(*[:custom_setup_method1, *(options[1] || [])]) if options if options setup(*(options[1] || [])) do called(:custom_setup_callback1) end end setup(*(options[2] || [])) if options def custom_setup_method2 called(:custom_setup_method2) end unregister_setup(:custom_setup_method2) if options if options callback = lambda do called(:custom_setup_callback2) end setup(*(options[2] || []), &callback) unregister_setup(callback) end setup(*(options[3] || [])) if options def custom_setup_method3 called(:custom_setup_method3) end if options setup(*(options[3] || [])) do called(:custom_setup_callback3) end end def test_nothing end yield(self, :after) if block_given? end assert_called_fixtures(expected, test_case) test_case end def assert_setup(expected, options) _test_case = assert_setup_customizable(expected, nil, options) assert_setup_customizable(expected, nil, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end _test_case end def assert_inherited_setup(expected, parent, options=nil) _test_case = assert_setup_customizable(expected, parent, options) assert_setup_customizable(expected, parent, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end _test_case end def assert_invalid_setup_option(option) assert_invalid_option(:setup, option) end end class TestCleanup < self def test_without_option expected_cleanup_calls = [:custom_cleanup_callback3, :custom_cleanup_method3, :custom_cleanup_callback1, :custom_cleanup_method1, :custom_cleanup_callback0, :custom_cleanup_method0, :cleanup] test_case = assert_cleanup(expected_cleanup_calls, []) assert_inherited_cleanup(expected_cleanup_calls, test_case) assert_inherited_cleanup([:cleanup], nil) assert_called_fixtures(expected_cleanup_calls, test_case) end def test_with_before_option expected_cleanup_calls = [:custom_cleanup_callback3, :custom_cleanup_method3, :custom_cleanup_method0, :custom_cleanup_callback0, :custom_cleanup_method1, :custom_cleanup_callback1, :cleanup] test_case = assert_cleanup(expected_cleanup_calls, [[{:before => :append}], [{:before => :append}], [{:before => :prepend}], [{:before => :prepend}]]) assert_inherited_cleanup(expected_cleanup_calls, test_case) assert_inherited_cleanup([:cleanup], nil) assert_called_fixtures(expected_cleanup_calls, test_case) end def test_with_after_option expected_cleanup_calls = [:cleanup, :custom_cleanup_callback3, :custom_cleanup_method3, :custom_cleanup_method0, :custom_cleanup_callback0, :custom_cleanup_method1, :custom_cleanup_callback1] test_case = assert_cleanup(expected_cleanup_calls, [[{:after => :append}], [{:after => :append}], [{:after => :prepend}], [{:after => :prepend}]]) assert_inherited_cleanup(expected_cleanup_calls, test_case) assert_inherited_cleanup([:cleanup], nil) assert_called_fixtures(expected_cleanup_calls, test_case) end def test_with_invalid_option assert_invalid_cleanup_option(:unknown => true) assert_invalid_cleanup_option(:before => :unknown) assert_invalid_cleanup_option(:after => :unknown) end def test_with_option_to_inherited expected_cleanup_calls = [:cleanup] test_case = assert_cleanup(expected_cleanup_calls, nil) assert_inherited_cleanup([:custom_cleanup_callback3, :custom_cleanup_method3, :custom_cleanup_callback1, :custom_cleanup_method1, :custom_cleanup_callback0, :custom_cleanup_method0, :cleanup], test_case, []) assert_inherited_cleanup([:cleanup], nil) assert_called_fixtures(expected_cleanup_calls, test_case) end def test_with_exception test_case = Class.new(Test::Unit::TestCase) do def called_ids @called_ids ||= [] end def called(id) called_ids << id end def cleanup called(:cleanup) raise "cleanup" end cleanup def custom_cleanup_method0 called(:custom_cleanup_method0) raise "custom_cleanup_method0" end cleanup do called(:custom_cleanup_callback0) raise "custom_cleanup_callback0" end cleanup def custom_cleanup_method1 called(:custom_cleanup_method1) raise "custom_cleanup_method1" end cleanup do called(:custom_cleanup_callback1) raise "custom_cleanup_callback1" end def test_nothing end end assert_called_fixtures([:custom_cleanup_callback1], test_case) end private def assert_cleanup_customizable(expected, parent, options) test_case = Class.new(parent || Test::Unit::TestCase) do yield(self, :before) if block_given? def called_ids @called_ids ||= [] end def called(id) called_ids << id end def cleanup called(:cleanup) end cleanup(*(options[0] || [])) if options def custom_cleanup_method0 called(:custom_cleanup_method0) end if options cleanup(*(options[0] || [])) do called(:custom_cleanup_callback0) end end def custom_cleanup_method1 called(:custom_cleanup_method1) end cleanup(*[:custom_cleanup_method1, *(options[1] || [])]) if options if options cleanup(*(options[1] || [])) do called(:custom_cleanup_callback1) end end cleanup(*(options[2] || [])) if options def custom_cleanup_method2 called(:custom_cleanup_method2) end unregister_cleanup(:custom_cleanup_method2) if options if options callback = lambda do called(:custom_cleanup_callback2) end cleanup(*(options[2] || []), &callback) unregister_cleanup(callback) end cleanup(*(options[3] || [])) if options def custom_cleanup_method3 called(:custom_cleanup_method3) end if options cleanup(*(options[3] || [])) do called(:custom_cleanup_callback3) end end def test_nothing end yield(self, :after) if block_given? end assert_called_fixtures(expected, test_case) test_case end def assert_cleanup(expected, options) assert_cleanup_customizable(expected, nil, options) assert_cleanup_customizable(expected, nil, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end end def assert_inherited_cleanup(expected, parent, options=nil) assert_cleanup_customizable(expected, parent, options) assert_cleanup_customizable(expected, parent, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end end def assert_invalid_cleanup_option(option) assert_invalid_option(:cleanup, option) end end class TestTeardown < self def test_without_option expected_teardown_calls = [:custom_teardown_callback3, :custom_teardown_method3, :custom_teardown_callback1, :custom_teardown_method1, :custom_teardown_callback0, :custom_teardown_method0, :teardown] test_case = assert_teardown(expected_teardown_calls, []) assert_inherited_teardown(expected_teardown_calls, test_case) assert_inherited_teardown([:teardown], nil) assert_called_fixtures(expected_teardown_calls, test_case) end def test_with_before_option expected_teardown_calls = [:custom_teardown_callback3, :custom_teardown_method3, :custom_teardown_method0, :custom_teardown_callback0, :custom_teardown_method1, :custom_teardown_callback1, :teardown] test_case = assert_teardown(expected_teardown_calls, [[{:before => :append}], [{:before => :append}], [{:before => :prepend}], [{:before => :prepend}]]) assert_inherited_teardown(expected_teardown_calls, test_case) assert_inherited_teardown([:teardown], nil) assert_called_fixtures(expected_teardown_calls, test_case) end def test_with_after_option expected_teardown_calls = [:teardown, :custom_teardown_callback3, :custom_teardown_method3, :custom_teardown_method0, :custom_teardown_callback0, :custom_teardown_method1, :custom_teardown_callback1] test_case = assert_teardown(expected_teardown_calls, [[{:after => :append}], [{:after => :append}], [{:after => :prepend}], [{:after => :prepend}]]) assert_inherited_teardown(expected_teardown_calls, test_case) assert_inherited_teardown([:teardown], nil) assert_called_fixtures(expected_teardown_calls, test_case) end def test_with_invalid_option assert_invalid_teardown_option(:unknown => true) assert_invalid_teardown_option(:before => :unknown) assert_invalid_teardown_option(:after => :unknown) end def test_with_option_to_inherited expected_teardown_calls = [:teardown] test_case = assert_teardown(expected_teardown_calls, nil) assert_inherited_teardown([:custom_teardown_callback3, :custom_teardown_method3, :custom_teardown_callback1, :custom_teardown_method1, :custom_teardown_callback0, :custom_teardown_method0, :teardown], test_case, []) assert_inherited_teardown([:teardown], nil) assert_called_fixtures(expected_teardown_calls, test_case) end def test_with_exception test_case = Class.new(Test::Unit::TestCase) do def called_ids @called_ids ||= [] end def called(id) called_ids << id end def teardown called(:teardown) raise "teardown" end teardown def custom_teardown_method0 called(:custom_teardown_method0) raise "custom_teardown_method0" end teardown do called(:custom_teardown_callback0) raise "custom_teardown_callback0" end teardown def custom_teardown_method1 called(:custom_teardown_method1) raise "custom_teardown_method1" end teardown do called(:custom_teardown_callback1) raise "custom_teardown_callback1" end def test_nothing end end assert_called_fixtures([:custom_teardown_callback1, :custom_teardown_method1, :custom_teardown_callback0, :custom_teardown_method0, :teardown], test_case) end def test_nested called = [] parent_test_case = Class.new(Test::Unit::TestCase) do teardown do called << :parent end end child_test_case = Class.new(parent_test_case) do teardown do called << :child end def test_nothing end end run_test_nothing(child_test_case) assert_equal([:child, :parent], called) end def test_setup_with_block test_case = Class.new(Test::Unit::TestCase) do def called_ids @called_ids ||= [] end def called(id) called_ids << id end setup def setup1 called(:setup1) begin yield called(:setup1_after_yield) ensure called(:setup1_teardown) end end setup def setup2 called(:setup2) begin yield called(:setup2_after_yield) ensure called(:setup2_teardown) end end def teardown called(:teardown) end def test_nothing called(:test) flunk called(:test_after_failure) end end assert_called_fixtures([ :setup1, :setup2, :test, :setup2_teardown, :setup1_teardown, :teardown, ], test_case) end private def assert_teardown_customizable(expected, parent, options) test_case = Class.new(parent || Test::Unit::TestCase) do yield(self, :before) if block_given? def called_ids @called_ids ||= [] end def called(id) called_ids << id end def teardown called(:teardown) end teardown(*(options[0] || [])) if options def custom_teardown_method0 called(:custom_teardown_method0) end if options teardown(*(options[0] || [])) do called(:custom_teardown_callback0) end end def custom_teardown_method1 called(:custom_teardown_method1) end teardown(*[:custom_teardown_method1, *(options[1] || [])]) if options if options teardown(*(options[1] || [])) do called(:custom_teardown_callback1) end end teardown(*(options[2] || [])) if options def custom_teardown_method2 called(:custom_teardown_method2) end unregister_teardown(:custom_teardown_method2) if options if options callback = lambda do called(:custom_teardown_callback2) end teardown(*(options[2] || []), &callback) unregister_teardown(callback) end teardown(*(options[3] || [])) if options def custom_teardown_method3 called(:custom_teardown_method3) end if options teardown(*(options[3] || [])) do called(:custom_teardown_callback3) end end def test_nothing end yield(self, :after) if block_given? end assert_called_fixtures(expected, test_case) test_case end def assert_teardown(expected, options) assert_teardown_customizable(expected, nil, options) assert_teardown_customizable(expected, nil, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end end def assert_inherited_teardown(expected, parent, options=nil) assert_teardown_customizable(expected, parent, options) assert_teardown_customizable(expected, parent, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end end def assert_invalid_teardown_option(option) assert_invalid_option(:teardown, option) end end private def run_test_nothing(test_case) test = test_case.new("test_nothing") test.run(Test::Unit::TestResult.new) {} test end def assert_called_fixtures(expected, test_case) test = run_test_nothing(test_case) assert_equal(expected, test.called_ids) end def assert_invalid_option(fixture_type, option) exception = assert_raise(ArgumentError) do Class.new(Test::Unit::TestCase) do def test_nothing end send(fixture_type, option) def fixture end end end assert_equal("must be {:before => :prepend}, {:before => :append}, " + "{:after => :prepend} or {:after => :append}" + ": #{option.inspect}", exception.message) end end PK ]?"= = *gems/test-unit-3.3.4/test/test-omission.rbnu[require 'test/unit' require 'testunit-test-util' class TestUnitOmission < Test::Unit::TestCase include TestUnitTestUtil class TestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end def test_omit omit("1st omit") omit("2nd omit. Should not be reached here.") assert(true, "Should not be reached here too.") end def test_omit_with_condition omit_if(false, "Never omit.") omit_unless(true, "Never omit too.") omit_if(true, "Should omit.") omit("The last omit. Should not be reached here.") end def test_omit_with_block omit("Omit block") do flunk("Should not be reached here.") end assert(true, "Should be reached here.") end def test_omit_with_block_and_condition omit_if(false, "Never omit.") do assert(true, "Should be reached here.") end omit_if(true, "Should omit.") do flunk("Never reached here.") end assert(true, "Should be reached here too.") end end def test_omit result = _run_test("test_omit") assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, " \ "1 omissions, 0 notifications", result.to_s) assert_fault_messages(["1st omit"], result.omissions) end def test_omit_with_condition result = _run_test("test_omit_with_condition") assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, " \ "1 omissions, 0 notifications", result.to_s) assert_fault_messages(["Should omit."], result.omissions) end def test_omit_with_block result = _run_test("test_omit_with_block") assert_equal("1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, " \ "1 omissions, 0 notifications", result.to_s) assert_fault_messages(["Omit block"], result.omissions) end def test_omit_with_condition_and_block result = _run_test("test_omit_with_block_and_condition") assert_equal("1 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, " \ "1 omissions, 0 notifications", result.to_s) assert_fault_messages(["Should omit."], result.omissions) end private def _run_test(name) super(TestCase, name) end end PK ]q$G;H;H&gems/test-unit-3.3.4/test/test-diff.rbnu[class TestUnitDiff < Test::Unit::TestCase def test_binary_search_ranges assert_found_binary_search_ranges(5, [1..2, 4..5, 7..9]) assert_not_found_binary_search_ranges(3, [1..2, 4..5, 7..9]) end def test_to_indexes assert_to_indexes({"abc def" => [0, 2], "abc" => [1]}, ["abc def", "abc", "abc def"]) assert_to_indexes({?a => [0, 3], ?b => [1], ?c => [2], ?d => [4]}, "abcad") assert_to_indexes({ ?1 => [0, 35], ?t => [2, 5, 16], ?e => [3, 14, 31, 38], ?s => [4, 6, 12, 13, 20, 32, 44], ?, => [7, 21, 33], ?0 => [9, 23], ?a => [11, 26], ?r => [15, 30], ?i => [17, 27, 41], ?o => [18], ?n => [19, 39, 42], ?f => [25], ?l => [28], ?u => [29], ?p => [37], ?d => [40], ?g => [43], }, "1 tests, 0 assertions, 0 failures, 1 pendings") do |x| x == " "[0] end end def test_longest_match assert_longest_match([0, 1, 3], %w(b c d), %w(a b c d x y z), 0, 2, 0, 7) assert_longest_match([1, 2, 2], %w(b c d), %w(a b c d x y z), 1, 2, 0, 6) assert_longest_match([0, 0, 0], %w(a b), %w(c), 0, 1, 0, 0) assert_longest_match([1, 0, 2], %w(q a b x c d), %w(a b y c d f), 0, 5, 0, 5) assert_longest_match([4, 3, 2], %w(q a b x c d), %w(a b y c d f), 3, 5, 2, 5) assert_longest_match([1, 0, 2], "qabxcd", "abycdf", 0, 5, 0, 5) assert_longest_match([0, 0, 1], "efg", "eg", 0, 2, 0, 1) assert_longest_match([2, 1, 1], "efg", "eg", 1, 2, 1, 1) end def test_longest_match_with_junk_predicate assert_longest_match([0, 4, 5], " abcd", "abcd abcd", 0, 4, 0, 8) assert_longest_match([1, 0, 4], " abcd", "abcd abcd", 0, 4, 0, 8) do |x| x == ' '[0] end end def test_matches assert_matches([[0, 0, 2], [3, 2, 2]], %w(a b x c d), %w(a b c d)) assert_matches([[1, 0, 2], [4, 3, 2]], %w(q a b x c d), %w(a b y c d f)) assert_matches([[1, 0, 2], [4, 3, 2]], "qabxcd", "abycdf") assert_matches([[0, 0, 1], [2, 1, 1]], "efg", "eg") end def test_matches_with_junk_predicate assert_matches([[0, 0, 23], [24, 24, 11], [36, 36, 9]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") assert_matches([[0, 0, 1], [1, 1, 8], [9, 9, 1], [10, 10, 13], [24, 24, 11], [36, 36, 9]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") do |x| x == " "[0] end end def test_blocks assert_blocks([[0, 0, 2], [3, 2, 2], [5, 4, 0]], %w(a b x c d), %w(a b c d)) assert_blocks([[1, 0, 2], [4, 3, 2], [6, 6, 0]], %w(q a b x c d), %w(a b y c d f)) assert_blocks([[1, 0, 2], [4, 3, 2], [6, 6, 0]], "qabxcd", "abycdf") assert_blocks([[0, 0, 1], [2, 1, 1], [3, 2, 0]], "efg", "eg") end def test_blocks_with_junk_predicate assert_blocks([[0, 0, 23], [24, 24, 11], [36, 36, 9], [45, 45, 0]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") do |x| x == " "[0] end end def test_operations assert_operations([], %w(), %w()) assert_operations([[:delete, 0, 1, 0, 0], [:equal, 1, 3, 0, 2], [:replace, 3, 4, 2, 3], [:equal, 4, 6, 3, 5], [:insert, 6, 6, 5, 6]], %w(q a b x c d), %w(a b y c d f)) assert_operations([[:delete, 0, 1, 0, 0], [:equal, 1, 3, 0, 2], [:replace, 3, 4, 2, 3], [:equal, 4, 6, 3, 5], [:insert, 6, 6, 5, 6]], "qabxcd", "abycdf") assert_operations([[:equal, 0, 23, 0, 23], [:replace, 23, 24, 23, 24], [:equal, 24, 35, 24, 35], [:replace, 35, 36, 35, 36], [:equal, 36, 45, 36, 45]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") assert_operations([[:equal, 0, 23, 0, 23], [:replace, 23, 24, 23, 24], [:equal, 24, 35, 24, 35], [:replace, 35, 36, 35, 36], [:equal, 36, 45, 36, 45]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") do |x| x == " "[0] end end def test_grouped_operations assert_grouped_operations([[[:equal, 0, 0, 0, 0]]], %w(), %w()) assert_grouped_operations([[[:equal, 0, 3, 0, 3]]], %w(a b c), %w(a b c)) assert_grouped_operations([[[:equal, 0, 1, 0, 1], [:replace, 1, 2, 1, 2], [:equal, 2, 5, 2, 5]], [[:equal, 8, 11, 8, 11], [:replace, 11, 12, 11, 12], [:equal, 12, 13, 12, 13], [:delete, 13, 16, 13, 13], [:equal, 16, 17, 13, 14], [:replace, 17, 18, 14, 15], [:equal, 18, 20, 15, 17]]], %w(1 2 3 4 5 6 7 8 9 a b c d e f g h i j k), %w(1 i 3 4 5 6 7 8 9 a b cX d h iX j k)) end def test_ratio assert_ratio(0.75, "abcd", "bcde") assert_ratio(0.80, "efg", "eg") end def test_1_length_readable_diff differ = Test::Unit::Diff::ReadableDiffer.new(["0"], ["1"]) def differ.cut_off_ratio 0 end def differ.default_ratio 0 end assert_equal("- 0\n" + "? ^\n" + "+ 1\n" + "? ^", differ.diff.join("\n")) end def test_same_contents_readable_diff assert_readable_diff(" aaa", ["aaa"], ["aaa"]) assert_readable_diff(" aaa\n" \ " bbb", ["aaa", "bbb"], ["aaa", "bbb"]) end def test_deleted_readable_diff assert_readable_diff(" aaa\n" \ "- bbb", ["aaa", "bbb"], ["aaa"]) assert_readable_diff(" aaa\n" \ "- bbb\n" \ "- ccc\n" \ "- ddd", ["aaa", "bbb", "ccc", "ddd"], ["aaa"]) end def test_inserted_readable_diff assert_readable_diff(" aaa\n" \ "+ bbb\n" \ "+ ccc\n" \ "+ ddd", ["aaa"], ["aaa", "bbb", "ccc", "ddd"]) end def test_replace_readable_diff assert_readable_diff(" aaa\n" \ "- bbb\n" \ "+ BbB\n" \ " ccc\n" \ "- ddd\n" \ "- efg\n" \ "? -\n" \ "+ eg", ["aaa", "bbb", "ccc", "ddd", "efg"], ["aaa", "BbB", "ccc", "eg"]) assert_readable_diff("- abcd xyz abc\n" \ "? -\n" \ "+ abcd abcd xyz abc\n" \ "? +++++", [" abcd xyz abc"], ["abcd abcd xyz abc"]) end def test_difference_readable_diff assert_readable_diff("- 1 tests, 0 assertions, 1 failures, 0 pendings\n" \ "? ^ ^\n" \ "+ 1 tests, 0 assertions, 0 failures, 1 pendings\n" \ "? ^ ^", ["1 tests, 0 assertions, 1 failures, 0 pendings"], ["1 tests, 0 assertions, 0 failures, 1 pendings"]) end def test_complex_readable_diff assert_readable_diff(" aaa\n" \ "- bbb\n" \ "- ccc\n" \ "+ \n" \ "+ # \n" \ " ddd", ["aaa", "bbb", "ccc", "ddd"], ["aaa", "", " # ", "ddd"]) assert_readable_diff("- one1\n" \ "? ^\n" \ "+ ore1\n" \ "? ^\n" \ "- two2\n" \ "- three3\n" \ "? - -\n" \ "+ tree\n" \ "+ emu", ["one1", "two2", "three3"], ["ore1", "tree", "emu"]) end def test_empty_readable_diff assert_readable_diff("", [""], [""]) end def test_unified_diff assert_unified_diff("", ["one", "two", "three"], ["one", "two", "three"], "content 1", "content 2") assert_unified_diff("--- Original Sat Jan 26 23:30:50 1991\n" \ "+++ Current Fri Jun 06 10:20:52 2003\n" \ "@@ -1,4 +1,4 @@\n" \ "+zero\n" \ " one\n" \ "-two\n" \ "-three\n" \ "+tree\n" \ " four", ["one", "two", "three", "four"], ["zero", "one", "tree", "four"], "Original Sat Jan 26 23:30:50 1991", "Current Fri Jun 06 10:20:52 2003", :show_context => false) from = File.read(__FILE__).split(/\n/) to = from.dup target_line = __LINE__ to[target_line - 1, 1] = [] context = " def test_unified_diff" summary = "@@ -#{target_line - 3},7 +#{target_line - 3},6 @@ #{context}" assert_unified_diff((["--- revision 10", "+++ revision 11", summary] + from[target_line - 4, 3].collect {|line| " #{line}"} + ["-#{from[target_line - 1]}"] + from[target_line, 3].collect {|line| " #{line}"} ).join("\n"), from, to, "revision 10", "revision 11") end def test_empty_unified_diff assert_unified_diff("", [""], [""], "From", "To") assert_unified_diff("", [], [], "From", "To") end def test_diff_lines assert_diff_lines(["- ddd", "- efg", "? -", "+ eg"], ["aaa", "bbb", "ccc", "ddd", "efg"], ["aaa", "BbB", "ccc", "eg"], 3, 5, 3, 4) end def test_diff_line assert_diff_line(["- abcDefghiJkl", "? ^ ^ ^", "+ abcdefGhijkl", "? ^ ^ ^"], "abcDefghiJkl", "abcdefGhijkl") assert_diff_line(["- bcDefghiJklx", "? ^ ^ ^ -", "+ abcdefGhijkl", "? + ^ ^ ^"], "bcDefghiJklx", "abcdefGhijkl") end def test_empty_diff_line assert_diff_line(["- ", "+ "], "", "") end def test_format_diff_point assert_format_diff_point(["- \tabcDefghiJkl", "? \t ^ ^ ^", "+ \t\tabcdefGhijkl", "? \t ^ ^ ^"], "\tabcDefghiJkl", "\t\tabcdefGhijkl", " ^ ^ ^ ", "+ ^ ^ ^ ") assert_format_diff_point(["- efg", "? ^", "+ eg"], "efg", "eg", " ^", "") end def test_interesting_line from = ["class X", " def find(x=0)", " body", " end", "end"] to = ["def xxx", " raise 'not call me'", "end"] assert_interesting_line(" def find(x=0)", from, to, 2, 1) assert_interesting_line("def xxx", from, to, 2, 0) assert_interesting_line("class X", from, to, 0, 0) end private def assert_found_binary_search_ranges(numeric, ranges) assert_true(Test::Unit::Diff::UTF8Line.send(:binary_search_ranges, numeric, ranges)) end def assert_not_found_binary_search_ranges(numeric, ranges) assert_false(Test::Unit::Diff::UTF8Line.send(:binary_search_ranges, numeric, ranges)) end def assert_to_indexes(expected, to, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new([""], to, &junk_predicate) assert_equal(expected, matcher.instance_variable_get("@to_indexes")) end def assert_find_best_match_position(expected, from, to, from_start, from_end, to_start, to_end, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.send(:find_best_match_position, from_start, from_end, to_start, to_end)) end def assert_longest_match(expected, from, to, from_start, from_end, to_start, to_end, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.longest_match(from_start, from_end, to_start, to_end)) end def assert_matches(expected, from, to, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.send(:matches)) end def assert_blocks(expected, from, to, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.blocks) end def assert_operations(expected, from, to, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.operations) end def assert_grouped_operations(expected, from, to) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to) assert_equal(expected, matcher.grouped_operations) end def assert_ratio(expected, from, to) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to) assert_in_delta(expected, 0.001, matcher.ratio) end def assert_readable_diff(expected, from, to) assert_equal(expected, Test::Unit::Diff.readable(from.join("\n"), to.join("\n"))) end def assert_unified_diff(expected, from, to, from_label, to_label, options={}) options = options.merge(:from_label => from_label, :to_label => to_label) assert_equal(expected, Test::Unit::Diff.unified(from.join("\n"), to.join("\n"), options)) end def assert_diff_lines(expected, from, to, from_start, from_end, to_start, to_end) differ = Test::Unit::Diff::ReadableDiffer.new(from, to) result = [] differ.instance_variable_set("@result", result) differ.send(:diff_lines, from_start, from_end, to_start, to_end) assert_equal(expected, result) end def assert_diff_line(expected, from_line, to_line) differ = Test::Unit::Diff::ReadableDiffer.new([""], [""]) result = [] differ.instance_variable_set("@result", result) differ.send(:diff_line, from_line, to_line) assert_equal(expected, result) end def assert_format_diff_point(expected, from_line, to_line, from_tags, to_tags) differ = Test::Unit::Diff::ReadableDiffer.new([""], [""]) result = [] differ.instance_variable_set("@result", result) differ.send(:format_diff_point, from_line, to_line, from_tags, to_tags) assert_equal(expected, result) end def assert_interesting_line(expected, from, to, from_start, to_start) differ = Test::Unit::Diff::UnifiedDiffer.new(from, to) assert_equal(expected, differ.send(:find_interesting_line, from_start, to_start, :define_line?)) end end PK ]X_3gems/test-unit-3.3.4/test/test-attribute-matcher.rbnu[require 'test/unit' require 'testunit-test-util' class TestAttributeMatcher < Test::Unit::TestCase include TestUnitTestUtil def setup @test = {} @matcher = Test::Unit::AttributeMatcher.new(@test) end def test_nonexistent assert_false(@matcher.match?("nonexistent")) end def test_existent @test[:existent] = true assert_true(@matcher.match?("existent")) end def test_and @test[:slow] = true @test[:important] = true assert_true(@matcher.match?("important and slow")) end def test_complex @test[:tags] = [:slow, :web] @test[:bug] = "2929" assert_true(@matcher.match?("tags.include?(:web) or bug == '29'")) end def test_exception assert_raise(NoMethodError) do @matcher.match?("nonexistent > 100") end end end PK ]Fill%gems/test-unit-3.3.4/test/run-test.rbnu[#!/usr/bin/env ruby $VERBOSE = true $KCODE = "utf8" unless "".respond_to?(:encoding) base_dir = File.expand_path(File.join(File.dirname(__FILE__), "..")) lib_dir = File.join(base_dir, "lib") test_dir = File.join(base_dir, "test") $LOAD_PATH.unshift(lib_dir) require 'test/unit' test_unit_notify_base_dir = File.join(base_dir, "..", "test-unit-notify") test_unit_notify_base_dir = File.expand_path(test_unit_notify_base_dir) if File.exist?(test_unit_notify_base_dir) $LOAD_PATH.unshift(File.join(test_unit_notify_base_dir, "lib")) require 'test/unit/notify' end exit Test::Unit::AutoRunner.run(true, test_dir) PK ]7w004gems/test-unit-3.3.4/test/ui/test_testrunmediator.rbnu[require 'test/unit/ui/testrunnermediator' class TestUnitUIMediator < Test::Unit::TestCase def test_run_suite_with_interrupt_exception test_case = Class.new(Test::Unit::TestCase) do def test_raise_interrupt raise Interrupt, "from test" end end mediator = Test::Unit::UI::TestRunnerMediator.new(test_case.suite) finished = false mediator.add_listener(Test::Unit::UI::TestRunnerMediator::FINISHED) do finished = true end assert_raise(Interrupt) do mediator.run end assert(finished) end end PK ]f*k gems/test-unit-3.3.4/README.mdnu[# test-unit [![](https://badge.fury.io/rb/test-unit.svg)](http://badge.fury.io/rb/test-unit) [![](https://travis-ci.org/test-unit/test-unit.svg?branch=master)](https://travis-ci.org/test-unit/test-unit) * http://test-unit.github.io/ * https://github.com/test-unit/test-unit ## Description An xUnit family unit testing framework for Ruby. test-unit (Test::Unit) is unit testing framework for Ruby, based on xUnit principles. These were originally designed by Kent Beck, creator of extreme programming software development methodology, for Smalltalk's SUnit. It allows writing tests, checking results and automated testing in Ruby. ## Features * test-unit 1.2.3 is the original test-unit, taken straight from the ruby distribution. It is being distributed as a gem to allow tool builders to use it as a stand-alone package. (The test framework in ruby is going to radically change very soon). * test-unit will be improved actively and may break compatiblity with test-unit 1.2.3. (We will not hope it if it isn't needed.) * Some features exist as separated gems like GUI test runner. (Tk, GTK+ and Fox) test-unit-full gem package provides for installing all test-unit related gems easily. ## How To * [How To](https://github.com/test-unit/test-unit/blob/master/doc/text/how-to.md) (link for GitHub) * {file:doc/text/how-to.md How To} (link for YARD) ## Install
    % sudo gem install test-unit
    
    If you want to use full test-unit features:
    % sudo gem install test-unit-full
    
    ## License (The Ruby License) This software is distributed under the same terms as ruby. Exception: * lib/test/unit/diff.rb is a triple license of the Ruby license, PSF license and LGPLv2.1 or later. * lib/test-unit.rb is a dual license of the Ruby license and LGPLv2.1 or later. ## Authors ### Active * Kouhei Sutou: The current maintainer * Haruka Yoshihara: Data driven test supports. ### Inactive * Nathaniel Talbott: The original author * Ryan Davis: The second maintainer ### Images * Mayu & Co.: kinotan icons ## Thanks * Daniel Berger: Suggestions and bug reports. * Designing Patterns: Suggestions. * Erik Hollensbe: Suggestions and bug reports. * Bill Lear: A suggestion. * Diego Pettenò: A bug report. * Angelo Lakra: A bug report. * Mike Pomraning: A bug report. * David MARCHALAND: Suggestions and bug reports. * Andrew Grimm: A bug report. * Champak Ch: A bug report. * Florian Frank: A bug report. * grafi-tt: Bug fixes and reports. * Jeremy Stephens: A bug report. * Hans de Graaff: Bug reports. * James Mead: A bug report. * Marc Seeger (Acquia): A bug report. * boutil: A bug report. * Vladislav Rassokhin: A bug report. PK ]>X"Vgggems/test-unit-3.3.4/LGPLnu[ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! PK ]vm gems/test-unit-3.3.4/COPYINGnu[test-unit is copyrighted free software by Kouhei Sutou , Ryan Davis and Nathaniel Talbott . You can redistribute it and/or modify it under either the terms of the GPL version 2 (see the file GPL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Exceptions ---------- * lib/test/unit/diff.rb: This license, PSF license and/or LGPLv2.1 or later * lib/test-unit.rb: This license and/or LGPLv2.1 or later PK ]oc)gems/test-unit-3.3.4/sample/test_adder.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require_relative 'adder' class TestAdder < Test::Unit::TestCase def setup @adder = Adder.new(5) end def test_add assert_equal(7, @adder.add(2), "Should have added correctly") end def teardown @adder = nil end end PK ]c: $gems/test-unit-3.3.4/sample/adder.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. class Adder def initialize(number) @number = number end def add(number) @number + number end end PK ]d@.gems/test-unit-3.3.4/sample/test_subtracter.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require_relative 'subtracter' class TestSubtracter < Test::Unit::TestCase def setup @subtracter = Subtracter.new(5) end def test_subtract assert_equal(3, @subtracter.subtract(2), "Should have subtracted correctly") end def teardown @subtracter = nil end end PK ]/jj(gems/test-unit-3.3.4/sample/test_user.rbnu[# nested test case example. require 'test/unit' class UserTest < Test::Unit::TestCase def setup @user = "me" end def test_full_name assert_equal("me", @user) end class ProfileTest < UserTest setup def setup_profile @user += ": profile" end def test_has_profile assert_match(/: profile/, @user) end end end PK ]Z)gems/test-unit-3.3.4/sample/subtracter.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. class Subtracter def initialize(number) @number = number end def subtract(number) @number - number end end PK ]$yӱ'gems/test-unit-3.3.4/doc/text/how-to.mdnu[# How To ## Run all tests To make it easy to run all your tests, you can add a `run_test.rb` script to your `test` directory. A simple example might look like: base_dir = File.expand_path(File.join(File.dirname(__FILE__), "..")) lib_dir = File.join(base_dir, "lib") test_dir = File.join(base_dir, "test") $LOAD_PATH.unshift(lib_dir) require 'test/unit' exit Test::Unit::AutoRunner.run(true, test_dir) Then it's easy to run tests via the command line with, $ ruby test/run_test.rb ## Change test runner via the command line The output format can be changed via the command line with the `--runner` option. Simply tack it to the end: ruby test/run_test.rb --runner tap ## Configure test-unit per-project Test::Unit reads `test-unit.yml` or `.test-unit.yml` in the current working directory as Test::Unit's configuration file. It can contain the following settings: * color scheme definitions * test runner to be used * test runner options * test collector to be used Except color scheme definitions, all of them can be specified by command line option. Here are sample color scheme definitions: color_schemes: inverted: success: name: red bold: true failure: name: green bold: true other_scheme: ... Here are the syntax of color scheme definitions: color_schemes: SCHEME_NAME: EVENT_NAME: name: COLOR_NAME intensity: BOOLEAN bold: BOOLEAN italic: BOOLEAN underline: BOOLEAN ... ... | Definition | Description | |-------------|------------------------------| | SCHEME_NAME | the name of the color scheme | | EVENT_NAME | success, failure, pending, omission, notification, error | | COLOR_NAME | black, red, green, yellow, blue, magenta, cyan, white | | BOOLEAN | true or false | You can use the above 'inverted' color scheme with the following configuration: runner: console console_options: color_scheme: inverted color_schemes: inverted: success: name: red bold: true failure: name: green bold: true PK ]@J?%gems/test-unit-3.3.4/doc/text/news.mdnu[# News ## 3.3.4 - 2019-09-30 {#version-3-3-4} ### Improvements * Converted markup format to Markdown from RDoc. [GitHub#164][Patch by OGAWA KenIchi] * test: Stopped to depend on `Time#inspect` format. [GitHub#165][Reported by Benoit Daloze] ### Thanks * OGAWA KenIchi * Benoit Daloze ## 3.3.3 - 2019-05-10 {#version-3-3-3} ### Fixed * Fixed a bug that priority mode with test case name that uses special characters such as `?` can't be used on Windows. ## 3.3.2 - 2019-04-11 {#version-3-3-2} ### Fixes * Fixed a bug that `Test::Unit::Collector::Load` doesn't load test files under sub directories when these files have the same base name as test files in upper directories. [Reported by Kenta Murata] ### Thanks * Kenta Murata ## 3.3.1 - 2019-03-27 {#version-3-3-1} ### Improvements * Added support for `Test::Unit::AssertionFailedError#user_message` for not only `assert_equal` and `assert_raise` but also all assertions. [GitHub#162][Reported by xgraffm] ### Thanks * xgraffm ## 3.3.0 - 2019-01-23 {#version-3-3-0} ### Improvements * Added support for auto test run when all tests are defined in modules. * Added support for defining methods to test case class in multiple threads. [GitHub#159][Reported by Charles Oliver Nutter] * Suppressed warnings on Ruby 2.5. [GitHub#160][Reported by Daniel Berger] * Suppressed warnings on Ruby 2.7. ### Fixes * Fixed a code snippet fetch failure when source code isn't UTF-8 and the default external encoding is set to not UTF-8. [GitHub#161][Reported by masa kunikata] ### Thanks * Charles Oliver Nutter * Daniel Berger * masa kunikata ## 3.2.9 - 2018-12-01 {#version-3-2-9} ### Improvements * Added support for data generation by method. `data_#{test_name}` is called to generate data for `test_name` test. * Added support for data matrix generation. Example: ```ruby data(:a, [0, 1, 2]) data(:b, [:x, :y]) def test_data(data) end ``` This example generates the following data matrix: * label: `"a: 0, b: :x"`, data: `{a: 0, b: :x}` * label: `"a: 0, b: :y"`, data: `{a: 0, b: :y}` * label: `"a: 1, b: :x"`, data: `{a: 1, b: :x}` * label: `"a: 1, b: :y"`, data: `{a: 1, b: :y}` * label: `"a: 2, b: :x"`, data: `{a: 2, b: :x}` * label: `"a: 2, b: :y"`, data: `{a: 2, b: :y}` * Added `Test::Unit::TestCase#data` that returns the current data. * Added support for using test method that doesn't have no parameters as data driven test. Example: ```ruby data("label", :value) def test_data # Available since this release p data # :value end ``` * Added support for `:keep` option to `Test::Unit::TestCase.data`. * Added support for `:group` option to `Test::Unit::TestCase.data`. It's useful to generate multiple data matrix groups. ```ruby # Group1 data(:a, [0, 1, 2], group: :g1) data(:b, [:x, :y], group: :g1) # Group2 data(:a, [:x, :y], group: :g2) data(:c, [-1, -2], group: :g2) def test_data(data) end ``` This example generates the following data matrix: * label: `"group: :g1, a: 0, b: :x"`, data: `{a: 0, b: :x}` * label: `"group: :g1, a: 0, b: :y"`, data: `{a: 0, b: :y}` * label: `"group: :g1, a: 1, b: :x"`, data: `{a: 1, b: :x}` * label: `"group: :g1, a: 1, b: :y"`, data: `{a: 1, b: :y}` * label: `"group: :g1, a: 2, b: :x"`, data: `{a: 2, b: :x}` * label: `"group: :g1, a: 2, b: :y"`, data: `{a: 2, b: :y}` * label: `"group: :g2, a: :x, b: -1"`, data: `{a: :x, b: -1}` * label: `"group: :g2, a: :x, b: -2"`, data: `{a: :x, b: -2}` * label: `"group: :g2, a: :y, b: -1"`, data: `{a: :y, b: -1}` * label: `"group: :g2, a: :y, b: -2"`, data: `{a: :y, b: -2}` ## 3.2.8 - 2018-05-13 {#version-3-2-8} ### Improvements * [UI][console]: Changed to put code snippet before backtrace on reverse mode. ## 3.2.7 - 2017-12-12 {#version-3-2-7} ### Improvements * Added source code link to gemspec. [GitHub#157][Patch by Grey Baker] * Changed to use SVG image for badges in README. [GitHub#158][Patch by Olle Jonsson] * [UI][console]: Added `--reverse-output` option to output fault details in reverse like Ruby 2.5. It's enabled by default only for tty output. ### Fixes * Fixed a typo. [GitHub#156][Patch by masa kunikata] * [UI][console]: Fixed a bug that broken align in verbose mode. ### Thanks * masa kunikata * Grey Baker * Olle Jonsson ## 3.2.6 - 2017-09-21 {#version-3-2-6} ### Improvements * Changed test file require failure to error from omission. [GitHub#154][Patch by naofumi-fujii] ### Thanks * naofumi-fujii ## 3.2.5 - 2017-06-24 {#version-3-2-5} ### Improvements * Supported `--enable-frozen-string-literal` `ruby` option. [GitHub#149][Reported by Pat Allan] ### Thanks * Pat Allan ## 3.2.4 - 2017-05-23 {#version-3-2-4} ### Improvements * Updated tests for Ruby 2.4. [GitHUb#136][Patch by Kazuki Tsujimoto] * Supported power\_assert 1.0.0. [GitHub#137][Patch by Kazuki Tsujimoto] * Added the getting started document. [GitHub#139][GitHub#141][Patch by Hiroyuki Sato] * Added the document for `attribute`. [GitHub#143][Patch by Fumiaki MATSUSHIMA] * Improved a link for GitHub. [GitHub#144][Patch by rochefort] * Updated `.travis.yml`. [GitHub#145][Patch by Jun Aruga] ### Fixes * Fixed a contributor name. [GitHub#131][Patch by Akira Matsuda] * Fixed typos in document. [GitHub#132][Patch by Akira Matsuda] * Fixed typos in document. [GitHub#134][Patch by Yuji Yaginuma] * Fixed a bug that data label with "(" isn't supported. [GitHub#135][Reported by Kazuki Tsujimoto] * Fixed assertion message in English. [GitHub#133][Reported by Khalil Fazal] * Fixed a typo in typo fix. [GitHub#138][Patch by kami] * Fixed a bug that target location finder may return wrong location. [GitHub#146][Patch by Yuki Ito] * Fixed a bug that `--no-show-detail-immediately` raises an error. [GitHub#147][Reported by MSP-Greg] ### Thanks * Akira Matsuda * Yuji Yaginuma * Kazuki Tsujimoto * Khalil Fazal * kami * Hiroyuki Sato * Fumiaki MATSUSHIMA * rochefort * Jun Aruga * Yuki Ito * MSP-Greg ## 3.2.3 - 2016-11-25 {#version-3-2-3} ### Fixes * Fixed a bug that `--order` isn't applied. [GitHub#129][Reported by Vít Ondruch] ### Thanks * Vít Ondruch ## 3.2.2 - 2016-11-02 {#version-3-2-2} ### Improvements * Improved Travis CI configuration. [GitHub#123][Patch by Ryunosuke Sato] * Supported Java native exception. [GitHub#126][Reported by Bob Saveland] ### Fixes * doc: Fixed markup. [GitHub#127][Patch by Tomohiro Hashidate] * Fixed a bug that `--location=LINE` may not detect a test when fixtures are defined before any tests: 1 class MyTestCase < Test::Unit::TestCase 2 setup do 3 end 4 5 test "xxx" do 6 end 7 end `--location=5` couldn't find the `xxx` test. [Reported by Ryota Sasabe] ### Thanks * Ryunosuke Sato * Tomohiro Hashidate * Bob Saveland * Ryota Sasabe ## 3.2.1 - 2016-07-19 {#version-3-2-1} ### Improvements * Clarified lib/test/unit/diff.rb license. It's a triple license of the Ruby license, PSF license and LGPLv2.1 or later. [Reported by Luisa Pace] * Reported norification when data driven test doesn't have parameter. [GitHub#122][Reported by Satoshi "Moris" Tagomori] ### Thanks * Luisa Pace * Satoshi "Moris" Tagomori ## 3.2.0 - 2016-06-12 {#version-3-2-0} ### Improvements * Supported rxvt family terminals as color available terminals. [GitHub#121][Reported by Ippei Kishida] ### Thanks * Ippei Kishida ## 3.1.9 - 2016-05-20 {#version-3-1-9} ### Fixes * Fixed conflict with test-unit-power_assert. [GitHub#120][Patch by Kazuki Tsujimoto] * Fixed a bug that path in `$LOAD_PATH` may be removed. ### Thanks * Kazuki Tsujimoto ## 3.1.8 - 2016-03-19 {#version-3-1-8} ### Improvements * Added `--stop-on-failure` command line option. With this option, running test suite is stopped immediately when one test is failed or an error is raised in one test. ## 3.1.7 - 2016-01-17 {#version-3-1-7} ### Fixes * Added a missing require. ## 3.1.6 - 2016-01-17 {#version-3-1-6} It's a Ruby on Rails integration improvement release. ### Improvements * Filtered backtrace of power\_assert. [GitHub#114] * Improved performance to retrieve test defined location. * Improved performance to run fixtures in a test. * Supported running a test by `yield` in `setup`: Before: def setup @file = File.open("x") end def teardown @file.close end After: def setup File.open("x") do |file| @file = file yield end end * Added `--default-test-path` option that specifies the default path that has tests. * Made auto runner registration more lazily. Auto runner isn't registered automatically until user defines a test. In the previous releases, auto runner is registered automatically when user defines a test case. * Supported specifying a test by location in command line. For example, the following command line runs a test that is defined in /tmp/test_a.rb at line 10: % ruby -r test-unit -e run_test /tmp/test_a.rb:10 ### Fixes * Fixed a bug that test isn't ran. The test has the same name as data driven test that is defined in parent test case. [GitHub#115] ## 3.1.5 - 2015-10-09 {#version-3-1-5} It's a Rack integration improvement release. ### Improvements * Renamed experimental top-level `run` method to `run_test` method because `run` is conflicted with Rack. [GitHub#32][GitHub:basecamp/pow#303] [Reported by Yevhen Viktorov] ### Thanks * Yevhen Viktorov ## 3.1.4 - 2015-09-26 {#version-3-1-4} It's a minor improvement release. ### Improvements * Updated sample code. [GitHub#109][Patch by takiy33] * Updated .travis.yml. [GitHub#110][Patch by takiy33] * document: Added table header in how to document. [GitHub#111][Patch by takiy33] * Removed duplicated code. [GitHub#112][Patch by takiy33] * Removed needless encoding conversion in fetching code snippet. [GitHub#113][Patch by NARUSE, Yui] ### Thanks * takiy33 * NARUSE, Yui ## 3.1.3 - 2015-07-26 {#version-3-1-3} It's a bug fix release. ### Improvements * Removed unused `TODO` file. [GitHub#108][Patch by takiy33] ### Fixes * `--location`: Fixed a bug that `--location LINE` doesn't work when test script is specified as relative path. [Reported by TOMITA Masahiro] The following doesn't work: % ruby ./test.rb --location 10 The following works: % ruby test.rb --location 10 ### Thanks * takiy33 * TOMITA Masahiro ## 3.1.2 - 2015-06-09 {#version-3-1-2} It's command line option improvements fix release. ### Improvements * `--location`: Made path match rule more strict. [Suggested by kimura wataru] * Before: * If test defined path ends with the specified path, the test is matched. * After: * If base name of test defined path equals to the specified path, the test is matched. * If relative path of test defined path equals to the specified path, the test is matched. * If the specified path is absolute path and test defined path equals to the specified path, the test is matched. * `--pattern`: If the option is specified, the default patterns aren't used. In the earlier versions, both the default patterns and the specified patterns are used. [Suggested by kimura wataru] ### Thanks * kimura wataru ## 3.1.1 - 2015-05-29 {#version-3-1-1} It's a bug fix release. ### Fixes * Fixed a bug that `--location` detects tests not only in sub test case but also parent test case. [GitHub#105][Reported by wanabe] ### Thanks * wanabe ## 3.1.0 - 2015-05-28 {#version-3-1-0} It's a bug fix release. ### Improvements * [ui][console] Removed needless new line. ### Fixes * Fixed a bug that priority mode can't be used on Windows. [GitHub#95][Reported by Daniel Berger] * Fixed a homepage URL RubyGems spec. [GitHub#96][Patch by Masayoshi Takahashi] supported.) [GitHub#89][Patch by Aaron Stone] * Fixed a bug that shutdown hook isn't called when pass throw exception such as `Interrupt` is raised. [GitHub#98][Reported by jeremiahishere.] * Fixed typos in documents. [GitHub#100][Reported by scivola] [GitHub#102][GitHub#103][Patch by Masafumi Yokoyama] * Fixed a bug that the same name test isn't executed in sub test case. [GitHub#104][Reported by wanabe] ### Thanks * Daniel Berger * Masayoshi Takahashi * jeremiahishere * scivola * Masafumi Yokoyama * wanabe ## 3.0.9 - 2014-12-31 {#version-3-0-9} It's a release that improves colors. ### Improvements * Added a work around for Ruby 1.8. (Note: Ruby 1.8 isn't supported.) [GitHub#89][Patch by Aaron Stone] * Supported colorized output on Windows. [GitHub#90][Patch by usa] * Improved colorized output. http://www.a-k-r.org/d/2014-12.html#a2014_12_27_1 [Suggested by Tanaka Akira] ### Thanks * Aaron Stone * usa * Tanaka Akira ## 3.0.8 - 2014-12-12 {#version-3-0-8} It's a release that supports Ruby 2.2.0 preview2. ### Improvements * Added a link for YARD in README. [GitHub:test-unit.github.io#2][Reported by sunnyone] * Added description about "/PATTERN/" style value in auto runner usage. [GitHub#86][Suggested by sunnyone] * Supported Ruby 2.2.0 preview2 in `assert_throw` and `assert_nothing_thrown`. ### Fixes * Fixed a bug that error report is failed when source encoding and locale encoding are different. [GitHub#87][Reported by scivola] ### Thanks * sunnyone * scivola ## 3.0.7 - 2014-11-14 {#version-3-0-7} It's a minor update release. ### Fixes * Fixed a bug that teardown blocks aren't called with sub class to parent class order. [GitHub#85][Reported by TOMITA Masahiro] ### Thanks * TOMITA Masahiro ## 3.0.6 - 2014-11-09 {#version-3-0-6} It's a minor update release. ### Improvements * Improved code snippet location. [GitHub#84][Patch by Yuki Kurihara] ### Thanks * Yuki Kurihara ## 3.0.5 - 2014-11-08 {#version-3-0-5} It's a minor update release. ### Fixes * Fixed a bug that startup/shutdown of parent test case isn't called when the test case includes one or more modules. [GitHub#83][Reported by Chadderton Odwazny] ### Thanks * Chadderton Odwazny ## 3.0.4 - 2014-11-01 {#version-3-0-4} It's a minor update release. ### Improvements * Stopped to remove JRuby and Rubinius internal backtrace entries from backtrace on failure/error. [GitHub#82][Patch by Charles Oliver Nutter] ### Thanks * Charles Oliver Nutter ## 3.0.3 - 2014-10-29 {#version-3-0-3} It's a minor update release. ### Improvements * Improved `Test::Unit::TestCase.test` performance. 100 times faster. * Supported `Proc` for user message. [Sugested by Nobuyoshi Nakada] ### Fixes * Fixed markup in document. [GitHub#81][Patch by Masafumi Yokoyama] ### Thanks * Masafumi Yokoyama * Nobuyoshi Nakada ## 3.0.2 - 2014-10-15 {#version-3-0-2} It's a minor update release. ### Improvements * Supported broken `==` implementation. `==` implementation should be fixed but it's not work of test-unit. :< [GitHub#71][Reported by Emily] * [UI][console]: Accepted no message failure. [GitHub#66][Reported by Brian Tatnall] * Updated gem description. [GitHub#74][Patch by Vít Ondruch] * Updated GPL text. [GitHub#78][Patch by Vít Ondruch] ### Fixes * Removed needless executable bit from README file. [GitHub#79][Patch by Vít Ondruch] ### Thanks * Emily * Brian Tatnall * Vít Ondruch ## 3.0.1 - 2014-08-05 {#version-3-0-1} It's a minor update release. ### Improvements * Improved Ruby 1.8.7 support. Note that we don't support Ruby 1.8.7 actively. We just support if its support is painless. [GitHub#71][Patch by estolfo] ### Thanks * estolfo ## 3.0.0 - 2014-08-03 {#version-3-0-0} It's Power Assert supported release! ### Improvements * Improved Rubinius support. [Ryo Onodera] * Updated RR repository link. [GitHub#56][Patch by Kenichi Kamiya] * Added some minitest compatible assertions. We don't recommend using these assertions. They are just for migrating from minitest. [GitHub#57][Patch by Karol Bucek] * {Test::Unit::Assertions#refute} * {Test::Unit::Assertions#refute_predicate} * {Test::Unit::Assertions#refute_empty} * {Test::Unit::Assertions#assert_not_includes} * {Test::Unit::Assertions#refute_includes} * {Test::Unit::Assertions#assert_not_instance_of} * {Test::Unit::Assertions#refute_instance_of} * {Test::Unit::Assertions#assert_not_kind_of} * {Test::Unit::Assertions#refute_kind_of} * {Test::Unit::Assertions#assert_not_operator} * {Test::Unit::Assertions#refute_operator} * Improved code readability. [Suggested by Kenichi Kamiya] * Made license field in RubyGems parseable. [GitHub#60][Patch by Michael Grosser] * Improved test case match feature by `--testcase` and `--ignore-testcase` options. They also checks parent class names. * Made inspected representation of Numeric objects especially BigDecimal more readable. [GitHub#64][Reported by Byron Appelt] * Added badges for Traivs CI and RubyGems. [GitHub#65][Patch by Byron Appelt] * Supported Power Assert. You can use Power Assert with {Test::Unit::Assertions#assert} with block. See method document for details. We recommend using Power Assert for predicate method checks. For example, we recommend Power Assert rather than {Test::Unit::Assertions#assert_true}, {Test::Unit::Assertions#assert_predicate} and so on. We don't recommend using Power Assert for equality check assertion. {Test::Unit::Assertions#assert_equal} should be used for the case. [Kazuki Tsujimoto] ### Fixes * Fixed a bug that test case defined by block has wrong location. [GitHub#58][Patch by Narihiro Nakamura] * Fixed a bug that test methods defined in included modules in super-class are also collected. [GitHub#62][GitHub#63][Patch by Karol Bucek] ### Thanks * Ryo Onodera * Kenichi Kamiya * Karol Bucek * Narihiro Nakamura * Michael Grosser * Byron Appelt * Kazuki Tsujimoto ## 2.5.5 - 2013-05-18 {#version-2-5-5} It's Ruby 2.0.0 supported release! ### Improvements * Supported Ruby 2.0.0. [GitHub#54] [Reported by mtasaka] * Accepted screen-256color TERM as 256 colors available environment. [GitHub#55] [Reported by Tom Miller] ### Fixes * Fixed a typo in document. [GitHub#53] [Patch by Baptiste Fontaine] * Fixed a bug in {Test::Unit::Assertions#assert_in_epsilon}. It doesn't work as expected if expected value is negative value. [Ruby Bug #8317] [Reported by Nobuhiro IMAI] ### Thanks * Baptiste Fontaine * mtasaka * Tom Miller * Nobuhiro IMAI ## 2.5.4 - 2013-01-23 {#version-2-5-4} It's a bug fix release. ### Improvements * Added documents for data driven test functionality. * Added TSV support for data driven test functionality. * Support tag inspection on JRuby. ### Fixes * Fixed a bug. It is too slow to filter tests when there are many tests. [GitHub#46] * Accept anonymous test suite. [GitHub:#49] [Reported by Matthew Rudy Jacobs] ### Thanks * Matthew Rudy Jacobs ## 2.5.3 - 2012-11-28 {#version-2-5-3} It's a release for minitest compatibility and bug fix. ### Improvements * Supported diff in invalid encoding. * Added some assersion methods just for minitest compatibility. Added methods are assert_includes(), refute_*() and refute(). If you are test-unit user, please don't use them. [GitHub#40] [Suggested by Michael Grosser] * Added --attribute option to select target tests by attribute. [test-unit-users-en:00098] [Suggested by Piotr Nestorow] ### Fixes * Allowed use of test for inheritance in ActionController::TestCase. [GitHub#42] [Patch by David Rasch] * Ensured evaluating at_exit block in top level. In IRB context, exit() specifies irb_exit(). [test-unit-users-en:00089] [Reported by Daniel Berger] * Fixed a bug that decoration style description is ignored. "decoration style description" are using description method above "def test_name" or with Symbol specifying test_name. [GitHub#45] [Reported by Piotr Nestorow] ### Thanks * Michael Grosser * David Rasch * Daniel Berger * Piotr Nestorow ## 2.5.2 - 2012-08-29 {#version-2-5-2} It's an improvement release for tmtms. `--location` is a similar feature to `--line_number` in RSpec. `sub_test_case` is a similar feature to `context` in shoulda-context and RSpec. ### Improvements * Cleaned up tests. [GitHub#34] [Patch by Michael Grosser] * Added missing background color for 8 color environment. * Added workaround for NetBeans. [GitHub#38] [Reported by Marc Cooper] * Added `--location` command line option that selects target tests by test defined location. * Created sub test suite for each subclassed test case. * [ui][console] Supported nested test suites. * Added {Test::Unit.at_start} and {Test::Unit.at_exit} hooks that are run before/after all tests are run. [Good hook name is suggested by kdmsnr] * Improved code snippet target on failure. Test method is always used for code snippet target. [GitHub#39] [Suggested by Michael Grosser] * Added {Test::Unit::TestCase.sub_test_case} that creates sub test case. The sub test case name isn't limited Ruby's constant name rule. You can specify the sub test case name in free form. ### Thanks * Michael Grosser * Marc Cooper * kdmsnr ## 2.5.1 - 2012-07-05 {#version-2-5-1} It's a bug fix release. ### Improvements * Supported installing from GitHub. [GitHub#29] [Suggested by Michael Grosser] * Supported ActiveSupport::TestCase. [GitHub#30] [Reported by Michael Grosser] * [ui][console] Improved multiline falut message display. ### Fixes * [ui][console] Fixed a bug that expected and actual values are empty. [GitHub#31][GitHub#33] [Reported by Kendall Buchanan][Reported by Mathieu Martin] [Hinted by Michael Grosser] * Fixed a bug that .gemspec can't be loaded on LANG=C. [RubyForge#29595] [Reported by Jean-Denis Koeck] ### Thanks * Michael Grosser * Kendall Buchanan * Mathieu Martin * Jean-Denis Koeck ## 2.5.0 - 2012-06-06 {#version-2-5-0} It's a bug fix release. ### Fixes * Fixed a backward incompatibility of `TestUnitMediator#run_suite` introduced in 2.4.9. [GitHub#28] [Reported by Vladislav Rassokhin] ### Thanks * Vladislav Rassokhin ## 2.4.9 - 2012-06-03 {#version-2-4-9} It's a bug fix release. ### Improvements * `Test::Unit.run?` -> `Test::Unit::AutoRunner.need_auto_run?`. `Test::Unit.run?` is marked as deprecated but it is still available. * [experimental] Added top level "run" method for `"ruby -rtest-unit -e run test/test_*.rb"`. Is this API OK or dirty? * Made failure output more readable on no color mode. * Supported showing ASCII-8BIT diff in failure message. * [ui][console] Supported `ENV["TERM"] == "xterm-256color"` as color available terminal. [GitHub#26] [Reported by Michael Grosser] * [ui][console] Supported "-256color" suffix `ENV["TERM"]` terminal as 256 color supported terminal. ### Fixes * Fixed a bug that `--workdir` doesn't work. * Consumed processed command line parameters in `ARGV` as `--help` says. [RubyForge#29554] [Reported by Bob Saveland] * Added missing `require "test/unit/diff"`. [GitHub#25] [Reported by Stephan Kulow] ### Thanks * Bob Saveland * Stephan Kulow * Michael Grosser ## 2.4.8 - 2012-3-6 {#version-2-4-8} It's a bug fix release. ### Improvements * Delayed at_exit registration until Test::Unit is used. [GitHub:#21] [Reported by Jason Lunn] * Added workaround for test-spec. [GitHub:#22] [Reported by Cédric Boutillier] ### Fixes * Fixed an error on code snippet display on JRuby. [GitHub:#19][GitHub:#20] [Reported by Jørgen P. Tjernø][Patch by Junegunn Choi] ### Thanks * Jørgen P. Tjernø * Junegunn Choi * Jason Lunn ## 2.4.7 - 2012-2-10 {#version-2-4-7} It's a code snippet improvement release. ### Improvements * Supported code snippet display on all faults. ## 2.4.6 - 2012-2-9 {#version-2-4-6} It's a TAP runner separated release. ### Improvements * Moved TAP runner to test-unit-runner-tap gem from test-unit gem. * Supported code snippet display on failure. ## 2.4.5 - 2012-1-16 {#version-2-4-5} It's a failure message readability improvement release. ### Improvements * Removed needless information from exception inspected text on failure. It's for easy to read. * Supported custom inspector. ## 2.4.4 - 2012-1-2 {#version-2-4-4} It's a Rails integration improved release. ### Improvements * [ui][console] Don't break progress display when a test is failed. * [ui][console] Added markers betwen a failure detail message in progress to improve visibility. * [travis] Dropped Ruby 1.8.6 as a test target. [GitHub:#13] [Patch by Josh Kalderimis] * Supported expected value == 0 case in assert_in_epsilon. [RubyForge#29485] [Reported by Syver Enstad] * Supported a block style setup/teardown/cleanup. ### Thanks * Josh Kalderimis * Syver Enstad ## 2.4.3 - 2011-12-11 {#version-2-4-3} ### Improvements * Improved SimpleCov integration by stopping to modify `ARGV` in auto runner. [GitHub:#12] [Reported by Nikos Dimitrakopoulos] * Improved JRuby integration by removing JRuby internal backtrace. ### Thanks * Nikos Dimitrakopoulos ## 2.4.2 - 2011-11-26 {#version-2-4-2} ### Improvements * `--name` supported data label. ## 2.4.1 - 2011-11-09 ### Improvements * Accepted AssertionMessage as assertion's user message. It is used in assert_select in actionpack. [Reported by David Heath] ### Fixes * Fixed test failure on LANG=C. #11 [Reported by boutil] * Suppress warnings on Ruby 1.9.2. ### Thanks * boutil * David Heath ## 2.4.0 - 2011-09-18 ### Improvements * Supported Travis CI. #5 [Suggested by James Mead] * Added Gemfile. #6 [Suggested by James Mead] * [ui][console] Supported notification in show-detail-immediately. * [ui][console] enable --show-detail-immediately by default. * [ui] Added --max-diff-target-string-size option. * [ui][console] Supported 256 colors. ### Fixes * Added missing fixture file. #7 [Reported by grafi-tt] * [ui][console] Added missing the last newline for progress level. * Supported correct backtrace for redefined notification. * Don't handle Timeout::Error as pass through exception on Ruby 1.8. #8 [Reported by Marc Seeger (Acquia)] ### Thanks * James Mead * grafi-tt * Marc Seeger (Acquia) ## 2.3.2 - 2011-08-15 A bug fix release. ### Improvements * [ui][console] Added some newlines to improve readability. ### Fixes * [ui][console] Worked --verbose again. * Re-supported Ruby 1.8.6. [Reported by James Mead] ### Thanks * James Mead ## 2.3.1 - 2011-08-06 {#version-2-3-1} Output improvement release! ### Improvements * [ui][console] Outputs omissions and notifications in short. * [ui][console] Added "important-only" verbose level. * Intelligence diff supports recursive references. * [rubyforge #29325] Supported Ruby Enterprise Edition. [Reported by Hans de Graaff] * [rubyforge #29326] Supported JRuby. [Reported by Hans de Graaff] * Added --show-detail-immediately option that shows fault details when a fault is occurred. ### Fixes * [pull request #1] Fixed a problem that load collector can't load a test file on Ruby 1.9. [Patch by grafi-tt] * [issue #3] Fixed a problem that implicit method name override by declarative style test definition. [Reported by Jeremy Stephens] ### Thanks * grafi-tt * Jeremy Stephens * Hans de Graaff ## 2.3.0 / 2011-04-17 * 13 enhancements * improve Hash key sorting for diff. * [#28928] support any characters in declarative style description. [Daniel Berger] * add Error#location and make #backtrace deprecated. * make TestCase#passed? public. * add result finished and pass assertion notifications. * add TestSuite#passed? public. * add XML test runner. * add --output-file-descriptor option. * measure elapsed time for each test. * add --collector option. * support test driven test. [Haruka Yoshihara] * add cleanup hook it runs between after test and before teardown. * support recursive collection sort for diff. * Thanks * Daniel Berger * Haruka Yoshihara ## 2.2.0 / 2011-02-14 * 22 enhancements * [#28808] accept String as delta for assert_in_delta. [Daniel Berger] * [test-unit-users-en:00035] make GC-able finished tests. [Daniel Berger] * use also COLUMNS environment variable to guess terminal width. * make delta for assert_in_delta optional. [Nobuyoshi Nakada] * add assert_not_respond_to. [Nobuyoshi Nakada] * add assert_not_match. assert_no_match is deprecated. [Nobuyoshi Nakada] * add assert_not_in_delta. [Nobuyoshi Nakada] * add assert_in_epsilon. [Nobuyoshi Nakada] * add assert_not_in_epsilon. [Nobuyoshi Nakada] * add assert_include. [Nobuyoshi Nakada] * add assert_not_include. [Nobuyoshi Nakada] * add assert_empty. [Nobuyoshi Nakada] * add assert_not_empty. [Nobuyoshi Nakada] * notify require failed paths. * validate message value for assert. * show throughputs at the last. * support not ASCII compatible string diff. * support colorized diff on encoding different string. * normalize entry order of Hash for readable diff. * add --ignore-name option. * add --ignore-testcase option. * add assert_not_send. * Thanks * Daniel Berger * Nobuyoshi Nakada ## 2.1.2 / 2010-11-25 * 1 enhancement * support auto runner prepare hook. ## 2.1.1 / 2010-07-29 * 1 bug fix * [test-unit-users-en:00026] re-work tap runner. [Daniel Berger] * Thanks * Daniel Berger === 2.1.0 / 2010-07-17 * 1 bug fix * [#28267] global config file ignored [Daniel Berger] * Thanks * Daniel Berger ## 2.0.8 / 2010-06-02 * 5 major enchancements * collect *_test.rb and *-test.rb files as test files. * [#28181] improve assert_in_delta message. [Suggested by David MARCHALAND] * show string encoding in assert_equal failure message if they are different. * change default color scheme: * success: green back + white * failure: red back + white * add capture_output. * 2 bug fixes * fix a bug that console runner on verbose mode causes an error for long test name (>= 61). * [#28093] Autorunner ignores all files in a directory named test by default [Reported by Florian Frank] * Thanks * Florian Frank * David MARCHALAND ## 2.0.7 / 2010-03-09 * 4 major enhancements * detect redefined test methods. * [INTERFACE IMCOMPATIBLE] multiple --name and --testcase options narrow down targets instead of adding targets. * [#27764] accept custom test_order for each test case. [Suggested by David MARCHALAND] * [#27790] ignore omitted tests from 'n% passed' report. [Suggested by Daniel Berger] * 2 minor enchancements * [#27832] ignore .git directory. [Suggested by Daniel Berger] * [#27792] require 'fileutils' and 'tmpdir' lazily for non-priority mode users. [Suggested by David MARCHALAND] * 2 bug fixes * [#27892] modify processed arguments array destructively. [Reported by Bob Saveland] * work without HOME environment variable. [Reported by Champak Ch] * Thanks * David MARCHALAND * Daniel Berger * Bob Saveland * Champak Ch ## 2.0.6 / 2010-01-09 * 3 major enhancements * [#27380] Declarative syntax? [Daniel Berger] support declarative syntax: test "test description in natural language" do ... end * support test description: description "test description in natural language" def test_my_test ... end * make max diff target string size customizable by TEST_UNIT_MAX_DIFF_TARGET_STRING_SIZE environment variable. * 2 bug fixes * [#27374] omit_if unexpected behavior [David MARCHALAND] * fix a bug that tests in sub directories aren't load with --basedir. [Daniel Berger] * Thanks * David MARCHALAND * Daniel Berger ## 2.0.5 / 2009-10-18 * 1 bug fixes * [#27314] fix diff may raise an exception. [Erik Hollensbe] * Thanks * Erik Hollensbe ## 2.0.4 / 2009-10-17 * 4 major enhancements * use ~/.test-unit.yml as global configuration file. * add TAP runner. (--runner tap) * support colorized diff: http://test-unit.github.io/color-diff.png * add Test::Unit::AutoRunner.default_runner= to specify default test runner. * 4 minor enhancements * improve verbose mode output format. (use indent) * support `NOT_PASS_THROUGH_EXCEPTIONS`. * support arguments option in `#{runner}_options`. * TC_ -> Test in sample test case name. * 1 bug fixes * [#27195] test-unit-2.0.3 + ruby-1.9.1 cannot properly test DelegateClass subclasses [Mike Pomraning] * Thanks * Mike Pomraning ## 2.0.3 / 2009-07-19 * 6 major enhancements * add assert_predicate. * add assert_not_predicate. * [#24210] assert_kind_of supports an array of classes or modules. [Daniel Berger] * assert_instance_of supports an array of classes or modules. * add --default-priority option. * [#26627] add --order option. [Daniel Berger] * 4 minor enhancements * use yellow foreground + black background for error. * don't show diff for long string. * accept "*term-color" TERM environment as colorizable terminal. (e.g. Apple's Terminal) * [#26268] add a workaround for test-spec's after_all. [Angelo Lakra] * 1 bug fix * [#23586] re-support ruby 1.9.1. [Diego Pettenò] * Thanks * Diego Pettenò * Daniel Berger * Angelo Lakra ## 2.0.2 / 2008-12-21 * 2 major enhancements * re-support ruby 1.8.5. * improve exception object comparison. * 3 bug fixes * [#22723]: collector fails on anonymous classes * [#22986]: Test names with '?' blow up on Windows * [#22988]: don't create .test-result on non-priority mode. * Thanks * Erik Hollensbe * Daniel Berger * Bill Lear ## 2.0.1 / 2008-11-09 * 19 major enhancements * support ruby 1.9.1. * add run_test method to be extensible. * improve priority-mode auto off. * improve startup/shutdown RDoc. [Daniel Berger] * add assert_compare. [#20851] [Designing Patterns] * add assert_fail_assertion. [#20851] [Designing Patterns] * add assert_raise_message. [#20851] [Designing Patterns] * support folded diff. * add assert_raise_kind_of. [Daniel Berger] * ingore inherited test for nested test case. * add assert_const_defined. * add assert_not_const_defined. * support assert_raise with an exception object. * support assert_raise with no arguments that asserts any exception is raised. [#22602] [Daniel Berger] * support folded dot progress. * add --progress-row-max option. * support color scheme customize. * support configuration file. (YAML) * recognize test-XXX.rb files as test files not only test_XXX.rb * Thanks * Daniel Berger * Designing Patterns ## 2.0.0 / 2008-06-18 * 15 major enhancements * support startup/shutdown. (test case level setup/teardown) * support multiple setup/teardown. * support pending. * support omission. * support notification. * support colorize. * support diff. * support test attribute. * add assert_boolean. * add assert_true. * add assert_false. * add --priority-mode option. * don't use ObjectSpace to collect test cases. * make more customizable. (additional options, exception handling and so on) * improve Emacs integration. * 4 major changes * remove GTK+1 support. * split GTK+ runner as another gem. * split FOX runner as another gem. * split Tk runner as another gem. ## 1.2.3 / 2008-02-25 * 1 major enhancement * Birthday (as a gem)! PK ]p0gems/test-unit-3.3.4/doc/text/getting-started.mdnu[## 1. First step of the `test-unit` Let's getting start `test-unit`. This document creates an example gem package called `sample` with the `test-unit` testing framework. ## 2. Install bundler and test-unit. * First, install the `bundler` gem for generating gem template. * Second, install the `test-unit` itself. ~~~ !!!plain gem install bundler gem install test-unit ~~~ The `gem list` command output installed packages. You will find the following lines. ~~~ !!!plain gem list ... bundler (1.14.6) ... test-unit (3.2.3) ~~~ ## 3. Create gem template. Next, create a gem template using `bundler` command. This command generates package skeleton with a testing framework. However, this command can't generate test templates for `test-unit`. So, First create gem template with the `minitest` testing framework. (It's similar to `unit-test`). After that, replace some files for `test-unit`. The `bundle gem -t minitest sample` command will generate the following files. ~~~ !!!plain . |-- Gemfile |-- README.md |-- Rakefile |-- bin | |-- console | `-- setup |-- lib | |-- sample | | `-- version.rb | `-- sample.rb |-- sample.gemspec # <- Modify `-- test |-- sample_test.rb # <- Modify `-- test_helper.rb # <- Modify ~~~ ## 4. Edit files for `test-unit` ### 4.1. Edit gemspec Edit `sample.gemspec` like the below. Replace `minitest` line to `test-unit`. Before ~~~ !!!ruby spec.add_development_dependency "minitest", "~> 5.0" ~~~ After ~~~ !!!ruby spec.add_development_dependency "test-unit", "~> 3.2.3" ~~~ ### 4.2. Edit `test/test_helper.rb` Next, edit the `test/test_helper.rb` file. Before ~~~ !!!ruby $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'sample' require 'minitest/autorun' # <-- Modify this line. ~~~ After ~~~ !!!ruby $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'sample' require 'test/unit' # <-- After modification. ~~~ ### 4.3 Rakefile (No edit) This file doesn't need to modify. The output is the below. ~~~ !!!ruby require "bundler/gem_tasks" require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList['test/**/*_test.rb'] end task :default => :test ~~~ ### 4.4 Edit `test/sample_test.rb` The bundler generate the file `test/sample_test.rb`. This file originally templates for `minitest`. Let's modify this file for `test-unit` before ~~~ !!!ruby require 'test_helper' class SampleTest < Minitest::Test # <- Modify here def test_that_it_has_a_version_number refute_nil ::Sample::VERSION end def test_it_does_something_useful assert false end end ~~~ After ~~~ !!!ruby require 'test_helper' class SampleTest < Test::Unit::TestCase # <- After modification def test_that_it_has_a_version_number refute_nil ::Sample::VERSION end def test_it_does_something_useful assert false end end ~~~ ## 5. Execute test. The `rake test` command execute test scenarios in the `test` directory. Now it tries to two tests. One will success the other one fails. ~~~ !!!plain rake test Loaded suite /path/to/ruby/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/rake_test_loader Started F ================================================================================ Failure: is not true. test_it_does_something_useful(SampleTest) /path/to/sample/test/sample_test.rb:9:in `test_it_does_something_useful' 6: end 7: 8: def test_it_does_something_useful => 9: assert false 10: end 11: end ================================================================================ . Finished in 0.011521 seconds. -------------------------------------------------------------------------------- 2 tests, 2 assertions, 1 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 50% passed -------------------------------------------------------------------------------- 173.60 tests/s, 173.60 assertions/s rake aborted! Command failed with status (1) Tasks: TOP => test (See full trace by running task with --trace) ~~~ ## 6. Create original tests. Let's create your original tests with the following rules. * Create a test file in the `test` directory. * The file needs suffix `xxx_test.rb`. * You can put test file into the subdirectory like `test/sub`. Example directory layout. ~~~ !!!plain test |-- sample_test.rb |-- sub | `-- sample2_test.rb `-- test_helper.rb ~~~ Example test file in the sub directory. ~~~ !!!ruby require 'test_helper' module Sub class Sample2Test < Test::Unit::TestCase def test_that_it_has_a_version_number refute_nil ::Sample::VERSION end def test_it_does_something_useful assert false end end end ~~~ ## 7. For more inforomation Let's read the official document. * [test-unit](http://test-unit.github.io/index.html) PK ]w:gems/test-unit-3.3.4/lib/test/unit/code-snippet-fetcher.rbnu[module Test module Unit class CodeSnippetFetcher def initialize @sources = {} end def fetch(path, line, options={}) n_context_line = options[:n_context_line] || 3 lines = source(path) return [] if lines.nil? min_line = [line - n_context_line, 1].max max_line = [line + n_context_line, lines.length].min window = min_line..max_line window.collect do |n| attributes = {:target_line? => (n == line)} [n, lines[n - 1].chomp, attributes] end end def source(path) @sources[path] ||= read_source(path) end private def read_source(path) return nil unless File.exist?(path) lines = [] File.open(path, "rb") do |file| first_line = file.gets break if first_line.nil? encoding = detect_encoding(first_line) || Encoding::UTF_8 first_line.force_encoding(encoding) file.set_encoding(encoding) lines << first_line lines.concat(file.readlines) end lines end def detect_encoding(first_line) return nil unless first_line.respond_to?(:ascii_only?) return nil unless first_line.ascii_only? if /\b(?:en)?coding[:=]\s*([a-z\d_-]+)/i =~ first_line begin Encoding.find($1) rescue ArgumentError nil end else nil end end end end end PK ]C9 9 5gems/test-unit-3.3.4/lib/test/unit/util/observable.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/procwrapper' module Test module Unit module Util # This is a utility class that allows anything mixing # it in to notify a set of listeners about interesting # events. module Observable # We use this for defaults since nil might mean something NOTHING = "NOTHING/#{__id__}" # Adds the passed proc as a listener on the # channel indicated by channel_name. listener_key # is used to remove the listener later; if none is # specified, the proc itself is used. # # Whatever is used as the listener_key is # returned, making it very easy to use the proc # itself as the listener_key: # # listener = add_listener("Channel") { ... } # remove_listener("Channel", listener) def add_listener(channel_name, listener_key=NOTHING, &listener) # :yields: value unless(block_given?) raise ArgumentError.new("No callback was passed as a listener") end key = listener_key if (listener_key == NOTHING) listener_key = listener key = ProcWrapper.new(listener) end channels[channel_name] ||= {} channels[channel_name][key] = listener return listener_key end # Removes the listener indicated by listener_key # from the channel indicated by # channel_name. Returns the registered proc, or # nil if none was found. def remove_listener(channel_name, listener_key) channel = channels[channel_name] return nil unless (channel) key = listener_key if (listener_key.instance_of?(Proc)) key = ProcWrapper.new(listener_key) end if (channel.has_key?(key)) return channel.delete(key) end return nil end # Calls all the procs registered on the channel # indicated by channel_name. If value is # specified, it is passed in to the procs, # otherwise they are called with no arguments. # #-- # # Perhaps this should be private? Would it ever # make sense for an external class to call this # method directly? def notify_listeners(channel_name, *arguments) channel = channels[channel_name] return 0 unless (channel) listeners = channel.values listeners.each { |listener| listener.call(*arguments) } return listeners.size end private def channels @channels ||= {} return @channels end end end end end PK ]̭1gems/test-unit-3.3.4/lib/test/unit/util/output.rbnu[module Test module Unit module Util module Output ## # Returns output for standard output and standard # error as string. # # Example: # # capture_output do # puts("stdout") # warn("stderr") # end # -> ["stdout\n", "stderr\n"] def capture_output require 'stringio' output = StringIO.new error = StringIO.new stdout_save, stderr_save = $stdout, $stderr $stdout, $stderr = output, error begin yield [output.string, error.string] ensure $stdout, $stderr = stdout_save, stderr_save end end end end end end PK ]S<>gems/test-unit-3.3.4/lib/test/unit/util/method-owner-finder.rbnu[module Test module Unit module Util module MethodOwnerFinder module_function def find(object, method_name) method = object.method(method_name) return method.owner if method.respond_to?(:owner) if /\((.+?)\)\#/ =~ method.to_s owner_name = $1 if /\A#\MM6gems/test-unit-3.3.4/lib/test/unit/util/procwrapper.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit module Util # Allows the storage of a Proc passed through '&' in a # hash. # # Note: this may be inefficient, since the hash being # used is not necessarily very good. In Observable, # efficiency is not too important, since the hash is # only accessed when adding and removing listeners, # not when notifying. class ProcWrapper # Creates a new wrapper for a_proc. def initialize(a_proc) @a_proc = a_proc @hash = a_proc.inspect.sub(/^(#<#{a_proc.class}:)/){''}.sub(/(>)$/){''}.hex end def hash return @hash end def ==(other) case(other) when ProcWrapper return @a_proc == other.to_proc else return super end end alias :eql? :== def to_proc return @a_proc end end end end end PK ]00:gems/test-unit-3.3.4/lib/test/unit/util/backtracefilter.rbnu[begin require 'power_assert' rescue LoadError, SyntaxError end module Test module Unit module Util module BacktraceFilter TESTUNIT_FILE_SEPARATORS = %r{[\\/:]} TESTUNIT_PREFIX = __FILE__.split(TESTUNIT_FILE_SEPARATORS)[0..-3] TESTUNIT_RB_FILE = /\.rb\Z/ POWERASSERT_PREFIX = defined?(::PowerAssert) ? ::PowerAssert.method(:start).source_location[0].split(TESTUNIT_FILE_SEPARATORS)[0..-2] : nil module_function def filter_backtrace(backtrace, prefix=nil) return ["No backtrace"] unless backtrace return backtrace if ENV["TEST_UNIT_ALL_BACKTRACE"] if prefix split_prefixes = [prefix.split(TESTUNIT_FILE_SEPARATORS)] else split_prefixes = [TESTUNIT_PREFIX, POWERASSERT_PREFIX].compact end test_unit_internal_p = lambda do |entry| components = entry.split(TESTUNIT_FILE_SEPARATORS) split_prefixes.any? do |split_prefix| split_entry = components[0, split_prefix.size] next false unless split_entry[0..-2] == split_prefix[0..-2] split_entry[-1].sub(TESTUNIT_RB_FILE, '') == split_prefix[-1] end end in_user_code = false new_backtrace = backtrace.reverse.reject do |entry| if test_unit_internal_p.call(entry) in_user_code = true true else not in_user_code end end.reverse if new_backtrace.empty? new_backtrace = backtrace.reject do |entry| test_unit_internal_p.call(entry) end new_backtrace = backtrace if new_backtrace.empty? end new_backtrace end end end end end PK ]9'ee*gems/test-unit-3.3.4/lib/test/unit/diff.rbnu[# port of Python's difflib. # # Copyright (c) 2001-2008 Python Software Foundation; All Rights Reserved # Copyright (c) 2008-2011 Kouhei Sutou; All Rights Reserved # # It is free software, and is distributed under the Ruby license, the # PSF license and/or LGPLv2.1 or later. See the COPYING file, the PSFL # file and the LGPL file. module Test module Unit module Diff class SequenceMatcher def initialize(from, to, &junk_predicate) @from = from @to = to @junk_predicate = junk_predicate update_to_indexes end def longest_match(from_start, from_end, to_start, to_end) best_info = find_best_match_position(from_start, from_end, to_start, to_end) unless @junks.empty? args = [from_start, from_end, to_start, to_end] best_info = adjust_best_info_with_junk_predicate(false, best_info, *args) best_info = adjust_best_info_with_junk_predicate(true, best_info, *args) end best_info end def blocks @blocks ||= compute_blocks end def operations @operations ||= compute_operations end def grouped_operations(context_size=nil) context_size ||= 3 _operations = operations.dup _operations = [[:equal, 0, 0, 0, 0]] if _operations.empty? expand_edge_equal_operations!(_operations, context_size) group_window = context_size * 2 groups = [] group = [] _operations.each do |tag, from_start, from_end, to_start, to_end| if tag == :equal and from_end - from_start > group_window group << [tag, from_start, [from_end, from_start + context_size].min, to_start, [to_end, to_start + context_size].min] groups << group group = [] from_start = [from_start, from_end - context_size].max to_start = [to_start, to_end - context_size].max end group << [tag, from_start, from_end, to_start, to_end] end groups << group unless group.empty? groups end def ratio @ratio ||= compute_ratio end private def update_to_indexes @to_indexes = {} @junks = {} if @to.is_a?(String) each = " "[0].is_a?(Integer) ? :each_byte : :each_char else each = :each end i = 0 @to.__send__(each) do |item| @to_indexes[item] ||= [] @to_indexes[item] << i i += 1 end return if @junk_predicate.nil? @to_indexes = @to_indexes.reject do |key, value| junk = @junk_predicate.call(key) @junks[key] = true if junk junk end end def find_best_match_position(from_start, from_end, to_start, to_end) best_from, best_to, best_size = from_start, to_start, 0 sizes = {} from_start.upto(from_end) do |from_index| _sizes = {} (@to_indexes[@from[from_index]] || []).each do |to_index| next if to_index < to_start break if to_index > to_end size = _sizes[to_index] = (sizes[to_index - 1] || 0) + 1 if size > best_size best_from = from_index - size + 1 best_to = to_index - size + 1 best_size = size end end sizes = _sizes end [best_from, best_to, best_size] end def adjust_best_info_with_junk_predicate(should_junk, best_info, from_start, from_end, to_start, to_end) best_from, best_to, best_size = best_info while best_from > from_start and best_to > to_start and (should_junk ? @junks.has_key?(@to[best_to - 1]) : !@junks.has_key?(@to[best_to - 1])) and @from[best_from - 1] == @to[best_to - 1] best_from -= 1 best_to -= 1 best_size += 1 end while best_from + best_size < from_end and best_to + best_size < to_end and (should_junk ? @junks.has_key?(@to[best_to + best_size]) : !@junks.has_key?(@to[best_to + best_size])) and @from[best_from + best_size] == @to[best_to + best_size] best_size += 1 end [best_from, best_to, best_size] end def matches @matches ||= compute_matches end def compute_matches matches = [] queue = [[0, @from.size, 0, @to.size]] until queue.empty? from_start, from_end, to_start, to_end = queue.pop match = longest_match(from_start, from_end - 1, to_start, to_end - 1) match_from_index, match_to_index, size = match unless size.zero? if from_start < match_from_index and to_start < match_to_index queue.push([from_start, match_from_index, to_start, match_to_index]) end matches << match if match_from_index + size < from_end and match_to_index + size < to_end queue.push([match_from_index + size, from_end, match_to_index + size, to_end]) end end end matches.sort_by do |(from_index, _, _)| from_index end end def compute_blocks blocks = [] current_from_index = current_to_index = current_size = 0 matches.each do |from_index, to_index, size| if current_from_index + current_size == from_index and current_to_index + current_size == to_index current_size += size else unless current_size.zero? blocks << [current_from_index, current_to_index, current_size] end current_from_index = from_index current_to_index = to_index current_size = size end end unless current_size.zero? blocks << [current_from_index, current_to_index, current_size] end blocks << [@from.size, @to.size, 0] blocks end def compute_operations from_index = to_index = 0 operations = [] blocks.each do |match_from_index, match_to_index, size| tag = determine_tag(from_index, to_index, match_from_index, match_to_index) if tag != :equal operations << [tag, from_index, match_from_index, to_index, match_to_index] end from_index, to_index = match_from_index + size, match_to_index + size if size > 0 operations << [:equal, match_from_index, from_index, match_to_index, to_index] end end operations end def compute_ratio matches = blocks.inject(0) {|result, block| result + block[-1]} length = @from.length + @to.length if length.zero? 1.0 else 2.0 * matches / length end end def determine_tag(from_index, to_index, match_from_index, match_to_index) if from_index < match_from_index and to_index < match_to_index :replace elsif from_index < match_from_index :delete elsif to_index < match_to_index :insert else :equal end end def expand_edge_equal_operations!(_operations, context_size) tag, from_start, from_end, to_start, to_end = _operations[0] if tag == :equal _operations[0] = [tag, [from_start, from_end - context_size].max, from_end, [to_start, to_end - context_size].max, to_end] end tag, from_start, from_end, to_start, to_end = _operations[-1] if tag == :equal _operations[-1] = [tag, from_start, [from_end, from_start + context_size].min, to_start, [to_end, to_start + context_size].min] end end end class Differ def initialize(from, to) @from = from @to = to end private def tag(mark, contents) contents.collect {|content| mark + content} end end class UTF8Line class << self # from http://unicode.org/reports/tr11/ WIDE_CHARACTERS = [0x1100..0x1159, 0x115F..0x115F, 0x2329..0x232A, 0x2E80..0x2E99, 0x2E9B..0x2EF3, 0x2F00..0x2FD5, 0x2FF0..0x2FFB, 0x3000..0x303E, 0x3041..0x3096, 0x3099..0x30FF, 0x3105..0x312D, 0x3131..0x318E, 0x3190..0x31B7, 0x31C0..0x31E3, 0x31F0..0x321E, 0x3220..0x3243, 0x3250..0x32FE, 0x3300..0x4DB5, 0x4E00..0x9FC3, 0xA000..0xA48C, 0xA490..0xA4C6, 0xAC00..0xD7A3, 0xF900..0xFA2D, 0xFA30..0xFA6A, 0xFA70..0xFAD9, 0xFE10..0xFE19, 0xFE30..0xFE52, 0xFE54..0xFE66, 0xFE68..0xFE6B, 0xFF01..0xFF60, 0xFFE0..0xFFE6, 0x20000..0x2FFFD, 0x30000..0x3FFFD, ] AMBIGUOUS = [0x00A1..0x00A1, 0x00A4..0x00A4, 0x00A7..0x00A8, 0x00AA..0x00AA, 0x00AD..0x00AE, 0x00B0..0x00B4, 0x00B6..0x00BA, 0x00BC..0x00BF, 0x00C6..0x00C6, 0x00D0..0x00D0, 0x00D7..0x00D8, 0x00DE..0x00E1, 0x00E6..0x00E6, 0x00E8..0x00EA, 0x00EC..0x00ED, 0x00F0..0x00F0, 0x00F2..0x00F3, 0x00F7..0x00FA, 0x00FC..0x00FC, 0x00FE..0x00FE, 0x0101..0x0101, 0x0111..0x0111, 0x0113..0x0113, 0x011B..0x011B, 0x0126..0x0127, 0x012B..0x012B, 0x0131..0x0133, 0x0138..0x0138, 0x013F..0x0142, 0x0144..0x0144, 0x0148..0x014B, 0x014D..0x014D, 0x0152..0x0153, 0x0166..0x0167, 0x016B..0x016B, 0x01CE..0x01CE, 0x01D0..0x01D0, 0x01D2..0x01D2, 0x01D4..0x01D4, 0x01D6..0x01D6, 0x01D8..0x01D8, 0x01DA..0x01DA, 0x01DC..0x01DC, 0x0251..0x0251, 0x0261..0x0261, 0x02C4..0x02C4, 0x02C7..0x02C7, 0x02C9..0x02CB, 0x02CD..0x02CD, 0x02D0..0x02D0, 0x02D8..0x02DB, 0x02DD..0x02DD, 0x02DF..0x02DF, 0x0300..0x036F, 0x0391..0x03A1, 0x03A3..0x03A9, 0x03B1..0x03C1, 0x03C3..0x03C9, 0x0401..0x0401, 0x0410..0x044F, 0x0451..0x0451, 0x2010..0x2010, 0x2013..0x2016, 0x2018..0x2019, 0x201C..0x201D, 0x2020..0x2022, 0x2024..0x2027, 0x2030..0x2030, 0x2032..0x2033, 0x2035..0x2035, 0x203B..0x203B, 0x203E..0x203E, 0x2074..0x2074, 0x207F..0x207F, 0x2081..0x2084, 0x20AC..0x20AC, 0x2103..0x2103, 0x2105..0x2105, 0x2109..0x2109, 0x2113..0x2113, 0x2116..0x2116, 0x2121..0x2122, 0x2126..0x2126, 0x212B..0x212B, 0x2153..0x2154, 0x215B..0x215E, 0x2160..0x216B, 0x2170..0x2179, 0x2190..0x2199, 0x21B8..0x21B9, 0x21D2..0x21D2, 0x21D4..0x21D4, 0x21E7..0x21E7, 0x2200..0x2200, 0x2202..0x2203, 0x2207..0x2208, 0x220B..0x220B, 0x220F..0x220F, 0x2211..0x2211, 0x2215..0x2215, 0x221A..0x221A, 0x221D..0x2220, 0x2223..0x2223, 0x2225..0x2225, 0x2227..0x222C, 0x222E..0x222E, 0x2234..0x2237, 0x223C..0x223D, 0x2248..0x2248, 0x224C..0x224C, 0x2252..0x2252, 0x2260..0x2261, 0x2264..0x2267, 0x226A..0x226B, 0x226E..0x226F, 0x2282..0x2283, 0x2286..0x2287, 0x2295..0x2295, 0x2299..0x2299, 0x22A5..0x22A5, 0x22BF..0x22BF, 0x2312..0x2312, 0x2460..0x24E9, 0x24EB..0x254B, 0x2550..0x2573, 0x2580..0x258F, 0x2592..0x2595, 0x25A0..0x25A1, 0x25A3..0x25A9, 0x25B2..0x25B3, 0x25B6..0x25B7, 0x25BC..0x25BD, 0x25C0..0x25C1, 0x25C6..0x25C8, 0x25CB..0x25CB, 0x25CE..0x25D1, 0x25E2..0x25E5, 0x25EF..0x25EF, 0x2605..0x2606, 0x2609..0x2609, 0x260E..0x260F, 0x2614..0x2615, 0x261C..0x261C, 0x261E..0x261E, 0x2640..0x2640, 0x2642..0x2642, 0x2660..0x2661, 0x2663..0x2665, 0x2667..0x266A, 0x266C..0x266D, 0x266F..0x266F, 0x273D..0x273D, 0x2776..0x277F, 0xE000..0xF8FF, 0xFE00..0xFE0F, 0xFFFD..0xFFFD, 0xE0100..0xE01EF, 0xF0000..0xFFFFD, 0x100000..0x10FFFD, ] def wide_character?(character) binary_search_ranges(character, WIDE_CHARACTERS) or binary_search_ranges(character, AMBIGUOUS) end private def binary_search_ranges(character, ranges) if ranges.size.zero? false elsif ranges.size == 1 ranges[0].include?(character) else half = ranges.size / 2 range = ranges[half] if range.include?(character) true elsif character < range.begin binary_search_ranges(character, ranges[0...half]) else binary_search_ranges(character, ranges[(half + 1)..-1]) end end end end def initialize(line) @line = line @characters = @line.unpack("U*") end def [](*args) result = @characters[*args] if result.respond_to?(:pack) result.pack("U*") else result end end def each(&block) @characters.each(&block) end def size @characters.size end def to_s @line end def compute_width(start, _end) width = 0 start.upto(_end - 1) do |i| if self.class.wide_character?(@characters[i]) width += 2 else width += 1 end end width end end class ReadableDiffer < Differ def diff(options={}) @result = [] operations.each do |tag, from_start, from_end, to_start, to_end| case tag when :replace diff_lines(from_start, from_end, to_start, to_end) when :delete tag_deleted(@from[from_start...from_end]) when :insert tag_inserted(@to[to_start...to_end]) when :equal tag_equal(@from[from_start...from_end]) else raise "unknown tag: #{tag}" end end @result end private def operations @operations ||= nil if @operations.nil? matcher = SequenceMatcher.new(@from, @to) @operations = matcher.operations end @operations end def default_ratio 0.74 end def cut_off_ratio 0.75 end def tag(mark, contents) contents.each do |content| @result << (mark + content) end end def tag_deleted(contents) tag("- ", contents) end def tag_inserted(contents) tag("+ ", contents) end def tag_equal(contents) tag(" ", contents) end def tag_difference(contents) tag("? ", contents) end def find_diff_line_info(from_start, from_end, to_start, to_end) best_ratio = default_ratio from_equal_index = to_equal_index = nil from_best_index = to_best_index = nil to_start.upto(to_end - 1) do |to_index| from_start.upto(from_end - 1) do |from_index| if @from[from_index] == @to[to_index] from_equal_index ||= from_index to_equal_index ||= to_index next end matcher = SequenceMatcher.new(@from[from_index], @to[to_index], &method(:space_character?)) if matcher.ratio > best_ratio best_ratio = matcher.ratio from_best_index = from_index to_best_index = to_index end end end [best_ratio, from_equal_index, to_equal_index, from_best_index, to_best_index] end def diff_lines(from_start, from_end, to_start, to_end) info = find_diff_line_info(from_start, from_end, to_start, to_end) best_ratio, from_equal_index, to_equal_index, *info = info from_best_index, to_best_index = info from_best_index ||= from_start to_best_index ||= to_start if best_ratio < cut_off_ratio if from_equal_index.nil? if to_end - to_start < from_end - from_start tag_inserted(@to[to_start...to_end]) tag_deleted(@from[from_start...from_end]) else tag_deleted(@from[from_start...from_end]) tag_inserted(@to[to_start...to_end]) end return end from_best_index = from_equal_index to_best_index = to_equal_index best_ratio = 1.0 end _diff_lines(from_start, from_best_index, to_start, to_best_index) diff_line(@from[from_best_index], @to[to_best_index]) _diff_lines(from_best_index + 1, from_end, to_best_index + 1, to_end) end def _diff_lines(from_start, from_end, to_start, to_end) if from_start < from_end if to_start < to_end diff_lines(from_start, from_end, to_start, to_end) else tag_deleted(@from[from_start...from_end]) end else tag_inserted(@to[to_start...to_end]) end end def line_operations(from_line, to_line) if !from_line.respond_to?(:force_encoding) and $KCODE == "UTF8" from_line = UTF8Line.new(from_line) to_line = UTF8Line.new(to_line) end matcher = SequenceMatcher.new(from_line, to_line, &method(:space_character?)) [from_line, to_line, matcher.operations] end def compute_width(line, start, _end) if line.respond_to?(:encoding) and Encoding.compatible?(Encoding::UTF_8, line.encoding) utf8_line = line[start..._end].encode(Encoding::UTF_8) width = 0 utf8_line.each_codepoint do |unicode_codepoint| if UTF8Line.wide_character?(unicode_codepoint) width += 2 else width += 1 end end width elsif line.is_a?(UTF8Line) line.compute_width(start, _end) else _end - start end end def diff_line(from_line, to_line) from_tags = "" to_tags = "" from_line, to_line, _operations = line_operations(from_line, to_line) _operations.each do |tag, from_start, from_end, to_start, to_end| from_width = compute_width(from_line, from_start, from_end) to_width = compute_width(to_line, to_start, to_end) case tag when :replace from_tags += "^" * from_width to_tags += "^" * to_width when :delete from_tags += "-" * from_width when :insert to_tags += "+" * to_width when :equal from_tags += " " * from_width to_tags += " " * to_width else raise "unknown tag: #{tag}" end end format_diff_point(from_line, to_line, from_tags, to_tags) end def format_diff_point(from_line, to_line, from_tags, to_tags) common = [n_leading_characters(from_line, ?\t), n_leading_characters(to_line, ?\t)].min common = [common, n_leading_characters(from_tags[0, common], " "[0])].min from_tags = from_tags[common..-1].rstrip to_tags = to_tags[common..-1].rstrip tag_deleted([from_line]) unless from_tags.empty? tag_difference(["#{"\t" * common}#{from_tags}"]) end tag_inserted([to_line]) unless to_tags.empty? tag_difference(["#{"\t" * common}#{to_tags}"]) end end def n_leading_characters(string, character) n = 0 while string[n] == character n += 1 end n end def space_character?(character) [" "[0], "\t"[0]].include?(character) end end class UnifiedDiffer < Differ def diff(options={}) groups = SequenceMatcher.new(@from, @to).grouped_operations return [] if groups.empty? return [] if same_content?(groups) show_context = options[:show_context] show_context = true if show_context.nil? result = ["--- #{options[:from_label]}".rstrip, "+++ #{options[:to_label]}".rstrip] groups.each do |operations| result << format_summary(operations, show_context) operations.each do |args| operation_tag, from_start, from_end, to_start, to_end = args case operation_tag when :replace result.concat(tag("-", @from[from_start...from_end])) result.concat(tag("+", @to[to_start...to_end])) when :delete result.concat(tag("-", @from[from_start...from_end])) when :insert result.concat(tag("+", @to[to_start...to_end])) when :equal result.concat(tag(" ", @from[from_start...from_end])) end end end result end private def same_content?(groups) return false if groups.size != 1 group = groups[0] return false if group.size != 1 tag, from_start, from_end, to_start, to_end = group[0] tag == :equal and [from_start, from_end] == [to_start, to_end] end def format_summary(operations, show_context) _, first_from_start, _, first_to_start, _ = operations[0] _, _, last_from_end, _, last_to_end = operations[-1] summary = "@@ -%d,%d +%d,%d @@" % [first_from_start + 1, last_from_end - first_from_start, first_to_start + 1, last_to_end - first_to_start,] if show_context interesting_line = find_interesting_line(first_from_start, first_to_start, :define_line?) summary << " #{interesting_line}" if interesting_line end summary end def find_interesting_line(from_start, to_start, predicate) from_index = from_start to_index = to_start while from_index >= 0 or to_index >= 0 [@from[from_index], @to[to_index]].each do |line| return line if line and __send__(predicate, line) end from_index -= 1 to_index -= 1 end nil end def define_line?(line) /\A(?:[_a-zA-Z$]|\s*(?:class|module|def)\b)/ =~ line end end module_function def need_fold?(diff) /^[-+].{79}/ =~ diff end def fold(string) string.split(/\r?\n/).collect do |line| line.gsub(/(.{78})/, "\\1\n") end.join("\n") end def folded_readable(from, to, options={}) readable(fold(from), fold(to), options) end def readable(from, to, options={}) diff(ReadableDiffer, from, to, options) end def unified(from, to, options={}) diff(UnifiedDiffer, from, to, options) end def diff(differ_class, from, to, options={}) if from.respond_to?(:valid_encoding?) and not from.valid_encoding? from = from.dup.force_encoding("ASCII-8BIT") end if to.respond_to?(:valid_encoding?) and not to.valid_encoding? to = to.dup.force_encoding("ASCII-8BIT") end differ = differ_class.new(from.split(/\r?\n/), to.split(/\r?\n/)) lines = differ.diff(options) if Object.const_defined?(:EncodingError) begin lines.join("\n") rescue EncodingError lines.collect {|line| line.force_encoding("ASCII-8BIT")}.join("\n") end else lines.join("\n") end end end end end PK ]*6r +gems/test-unit-3.3.4/lib/test/unit/color.rbnu[module Test module Unit class Color class Error < StandardError end class ParseError < Error end class << self def parse_256_color(string) case string when /\A([0-5])([0-5])([0-5])\z/ red, green, blue = $1, $2, $3 red.to_i * 36 + green.to_i * 6 + blue.to_i + 16 else message = "must be 'RGB' format and R, G and B " + "are in 0-5: #{string.inspect}" raise ParseError, message end end end NAMES = ["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"] attr_reader :name def initialize(name, options={}) @name = name if options.has_key?(:foreground) if options[:foreground].nil? @background = false else @background = !options[:foreground] end else @background = options[:background] end @intensity = options[:intensity] @bold = options[:bold] @italic = options[:italic] @underline = options[:underline] end def foreground? not background? end def background? @background end def intensity? @intensity end def bold? @bold end def italic? @italic end def underline? @underline end def ==(other) self.class === other and [name, background?, intensity?, bold?, italic?, underline?] == [other.name, other.background?, other.intensity?, other.bold?, other.italic?, other.underline?] end def sequence sequence = [] if @name == "none" elsif @name == "reset" sequence << "0" else if NAMES.include?(@name) color_parameter = foreground? ? 3 : 4 color_parameter += 6 if intensity? color = NAMES.index(@name) sequence << "#{color_parameter}#{color}" else sequence << (foreground? ? "38" : "48") sequence << "5" sequence << self.class.parse_256_color(@name).to_s end end sequence << "1" if bold? sequence << "3" if italic? sequence << "4" if underline? sequence end def escape_sequence "\e[#{sequence.join(';')}m" end def +(other) MixColor.new([self, other]) end end class MixColor attr_reader :colors def initialize(colors) @colors = colors end def sequence @colors.inject([]) do |result, color| result + color.sequence end end def escape_sequence "\e[#{sequence.join(';')}m" end def +(other) self.class.new([self, other]) end def ==(other) self.class === other and colors == other.colors end end end end PK ]U<l /gems/test-unit-3.3.4/lib/test/unit/data-sets.rbnu[module Test module Unit class DataSets def initialize @variables = [] @procs = [] @value_sets = [] end def add(data_set, options=nil) options ||= {} if data_set.respond_to?(:call) @procs << [data_set, options] elsif data_set.is_a?(Array) @variables << [data_set, options] else @value_sets << [data_set, options] end end def <<(data_set) add(data_set) end def keep new_data_sets = self.class.new all_data_sets = Enumerator.new do |yielder| block = lambda do |(data_set, options)| yielder << [data_set, options] end @procs.each(&block) @variables.each(&block) @value_sets.each(&block) end all_data_sets.each do |data_set, options| next if options.nil? next unless options[:keep] new_data_sets.add(data_set, options) end new_data_sets end def each variables = @variables value_sets = @value_sets @procs.each do |proc, options| data_set = proc.call case data_set when Array variables += [[data_set, options]] else value_sets += [[data_set, options]] end end value_sets.each do |values, _options| values.each do |label, data| yield(label, data) end end each_pattern(variables) do |label, data| yield(label, data) end end def ==(other) @variables == other.instance_variable_get(:@variables) and @procs == other.instance_variable_get(:@procs) and @value_sets == other.instance_variable_get(:@value_sets) end def eql?(other) self == other end def hash [@variables, @procs, @value_sets].hash end private def each_pattern(variables) grouped_variables = variables.group_by do |_, options| options[:group] end grouped_variables.each do |group, group_variables| each_raw_pattern(group_variables) do |cell| label = String.new label << "group: #{group.inspect}" unless group.nil? data = {} cell.each do |variable, pattern| label << ", " unless label.empty? label << "#{variable}: #{pattern.inspect}" data[variable] = pattern end yield(label, data) end end end def each_raw_pattern(variables, &block) return if variables.empty? sorted_variables = variables.sort_by do |(variable, _), _| variable end all_patterns = sorted_variables.collect do |(variable, patterns), _| patterns.collect do |pattern| [variable, pattern] end end all_patterns[0].product(*all_patterns[1..-1], &block) end end end end PK ]q((0gems/test-unit-3.3.4/lib/test/unit/assertions.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # Copyright (c) 2009-2013 Kouhei Sutou. All rights reserved. # License:: Ruby license. require 'test/unit/assertion-failed-error' require 'test/unit/util/backtracefilter' require 'test/unit/util/method-owner-finder' require 'test/unit/diff' begin require 'power_assert' rescue LoadError, SyntaxError end module Test module Unit ## # Test::Unit::Assertions contains the standard Test::Unit assertions. # Assertions is included in Test::Unit::TestCase. # # To include it in your own code and use its functionality, you simply # need to rescue Test::Unit::AssertionFailedError. Additionally you may # override add_assertion to get notified whenever an assertion is made. # # Notes: # # * The message to each assertion, if given, will be propagated with the # failure. # * It is easy to add your own assertions based on assert_block(). # # @example Example Custom Assertion # # def deny(boolean, message=nil) # message = build_message(message, ' is not false or nil.', boolean) # assert_block(message) do # not boolean # end # end module Assertions ## # The assertion upon which all other assertions are based. Passes if the # block yields true. # # @example # assert_block "Couldn't do the thing" do # do_the_thing # end def assert_block(message="assert_block failed.") _wrap_assertion do if (! yield) options = {} if message.respond_to?(:user_message) options[:user_message] = message.user_message end raise AssertionFailedError.new(message.to_s, options) end end end # @private NOT_SPECIFIED = Object.new # @overload assert(object, message=nil) # # Asserts that `object` is not false nor nil. # # Normally, you don't need to use this assertion. Use more # specific assertions such as #assert_equal and # #assert_include. # # @example Pass patterns # assert(true) # => pass # assert([1, 2].include?(1)) # => pass # # @example Failure patterns # assert(nil) # => failure # assert(false) # => failure # assert([1, 2].include?(5)) # => failure # # @param [Object] object The check target. # @param [String] message The additional user message. It is # showed when the assertion is failed. # @return [void] # # @overload assert(message=nil) {} # # Asserts that the givens block returns not false nor nil. # # This style uses Power Assert. It means that you can see each # object values in method chains on failure. See the following # example about Power Assert. # # @example Power Assert # coins = [1, 5, 50] # target_coin = 10 # assert do # coins.include?(target_coin) # end # # => # # coins.include?(target_coin) # # | | | # # | | 10 # # | false # # [1, 5, 50] # # We recommend you to use Power Assert for predicate method # checks rather than existing assertions such as # #assert_include and #assert_predicate. Power Assert shows # useful message for debugging. # # We don't recommend you use Power Assert for equality # check. You should use #assert_equal for the case. Because # #assert_equal shows more useful message for debugging. # # @example Pass patterns # assert {true} # => pass # assert {[1, 2].include?(1)} # => pass # # @example Failure patterns # assert {nil} # => failure # assert {false} # => failure # assert {[1, 2].include?(5)} # => failure # # @param [String] message The additional user message. It is # showed when the assertion is failed. # @yield [] Given no parameters to the block. # @yieldreturn [Object] The checked object. # @return [void] def assert(object=NOT_SPECIFIED, message=nil, &block) _wrap_assertion do have_object = !NOT_SPECIFIED.equal?(object) if block message = object if have_object if defined?(PowerAssert) PowerAssert.start(block, :assertion_method => __callee__) do |pa| pa_message = AssertionMessage.delayed_literal(&pa.message_proc) assertion_message = build_message(message, "?", pa_message) assert_block(assertion_message) do pa.yield end end else assert(yield, message) end else unless have_object raise ArgumentError, "wrong number of arguments (0 for 1..2)" end assertion_message = nil case message when nil, String, Proc when AssertionMessage assertion_message = message else error_message = "assertion message must be String, Proc or " error_message += "#{AssertionMessage}: " error_message += "<#{message.inspect}>(<#{message.class}>)" raise ArgumentError, error_message, filter_backtrace(caller) end assertion_message ||= build_message(message, " is not true.", object) assert_block(assertion_message) do object end end end end # Asserts that `object` is false or nil. # # @note Just for minitest compatibility. :< # # @param [Object] object The object to be asserted. # @return [void] # # @example Pass patterns # refute(false) # => pass # refute(nil) # => pass # # @example Failure patterns # refute(true) # => failure # refute("string") # => failure # # @since 2.5.3 def refute(object, message=nil) _wrap_assertion do assertion_message = nil case message when nil, String, Proc when AssertionMessage assertion_message = message else error_message = "assertion message must be String, Proc or " error_message += "#{AssertionMessage}: " error_message += "<#{message.inspect}>(<#{message.class}>)" raise ArgumentError, error_message, filter_backtrace(caller) end assert_block("refute should not be called with a block.") do !block_given? end assertion_message ||= build_message(message, " is neither nil or false.", object) assert_block(assertion_message) do not object end end end ## # Passes if `expected` == `actual`. # # Note that the ordering of arguments is important, since a helpful # error message is generated when this one fails that tells you the # values of expected and actual. # # @example # assert_equal 'MY STRING', 'my string'.upcase def assert_equal(expected, actual, message=nil) diff = AssertionMessage.delayed_diff(expected, actual) if expected.respond_to?(:encoding) and actual.respond_to?(:encoding) and expected.encoding != actual.encoding format = <(?) expected but was (?).? EOT full_message = build_message(message, format, expected, expected.encoding.name, actual, actual.encoding.name, diff) else full_message = build_message(message, < expected but was .? EOT end begin assert_block(full_message) { expected == actual } rescue AssertionFailedError => failure _set_failed_information(failure, expected, actual) raise failure # For JRuby. :< end end ## # Passes if the block raises one of the expected # exceptions. When an expected exception is an Exception # object, passes if expected_exception == actual_exception. # # @example # assert_raise(RuntimeError, LoadError) do # raise 'Boom!!!' # end # -> pass # # assert_raise do # raise Exception, 'Any exception should be raised!!!' # end # -> pass # # assert_raise(RuntimeError.new("XXX")) {raise "XXX"} # -> pass # assert_raise(MyError.new("XXX")) {raise "XXX"} # -> fail # assert_raise(RuntimeError.new("ZZZ")) {raise "XXX"} # -> fail def assert_raise(*args, &block) assert_expected_exception = Proc.new do |*_args| message, assert_exception_helper, actual_exception = _args expected = assert_exception_helper.expected_exceptions diff = AssertionMessage.delayed_diff(expected, actual_exception) full_message = build_message(message, " exception expected but was\n.?", expected, actual_exception, diff) begin assert_block(full_message) do expected == [] or assert_exception_helper.expected?(actual_exception) end rescue AssertionFailedError => failure _set_failed_information(failure, expected, actual_exception) raise failure # For JRuby. :< end end _assert_raise(assert_expected_exception, *args, &block) end # Just for minitest compatibility. :< alias_method :assert_raises, :assert_raise ## # Passes if the block raises one of the given # exceptions or sub exceptions of the given exceptions. # # @example # assert_raise_kind_of(SystemCallError) do # raise Errno::EACCES # end def assert_raise_kind_of(*args, &block) assert_expected_exception = Proc.new do |*_args| message, assert_exception_helper, actual_exception = _args expected = assert_exception_helper.expected_exceptions full_message = build_message(message, " family exception expected " + "but was\n.", expected, actual_exception) assert_block(full_message) do assert_exception_helper.expected?(actual_exception, :kind_of?) end end _assert_raise(assert_expected_exception, *args, &block) end ## # Passes if `object`.instance_of?(`klass`). When `klass` is # an array of classes, it passes if any class # satisfies +object.instance_of?(class). # # @example # assert_instance_of(String, 'foo') # -> pass # assert_instance_of([Fixnum, NilClass], 100) # -> pass # assert_instance_of([Numeric, NilClass], 100) # -> fail def assert_instance_of(klass, object, message=nil) _wrap_assertion do if klass.is_a?(Array) klasses = klass else klasses = [klass] end assert_block("The first parameter to assert_instance_of should be " + "a Class or an Array of Class.") do klasses.all? {|k| k.is_a?(Class)} end klass_message = AssertionMessage.maybe_container(klass) do |value| "<#{value}>" end full_message = build_message(message, < was expected to be instance_of\\? ? but was . EOT assert_block(full_message) do klasses.any? {|k| object.instance_of?(k)} end end end ## # Passes if `object`.instance_of?(`klass`) does not hold. # When `klass` is an array of classes, it passes if no class # satisfies +object.instance_of?(class). # # @example # assert_not_instance_of(String, 100) # -> pass # assert_not_instance_of([Fixnum, NilClass], '100') # -> pass # assert_not_instance_of([Numeric, NilClass], 100) # -> fail # # @since 3.0.0 def assert_not_instance_of(klass, object, message=nil) _wrap_assertion do if klass.is_a?(Array) klasses = klass else klasses = [klass] end assert_block("The first parameter to assert_not_instance_of should be " + "a Class or an Array of Class.") do klasses.all? {|k| k.is_a?(Class)} end klass_message = AssertionMessage.maybe_container(klass) do |value| "<#{value}>" end full_message = build_message(message, " was expected to not be instance_of\\?\n" + "? but was.", object, klass_message) assert_block(full_message) do klasses.none? {|k| object.instance_of?(k)} end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_instance_of, :assert_not_instance_of ## # Passes if `object` is nil. # # @example # assert_nil [1, 2].uniq! def assert_nil(object, message=nil) full_message = build_message(message, < was expected to be nil. EOT assert_block(full_message) { object.nil? } end ## # Passes if `object`.kind_of?(`klass`). When `klass` is # an array of classes or modules, it passes if any # class or module satisfies +object.kind_of?(class_or_module). # # @example # assert_kind_of(Object, 'foo') # -> pass # assert_kind_of([Fixnum, NilClass], 100) # -> pass # assert_kind_of([Fixnum, NilClass], "string") # -> fail def assert_kind_of(klass, object, message=nil) _wrap_assertion do if klass.is_a?(Array) klasses = klass else klasses = [klass] end assert_block("The first parameter to assert_kind_of should be " + "a kind_of Module or an Array of a kind_of Module.") do klasses.all? {|k| k.kind_of?(Module)} end klass_message = AssertionMessage.maybe_container(klass) do |value| "<#{value}>" end full_message = build_message(message, " was expected to be kind_of\\?\n" + "? but was\n" + ".", object, klass_message, object.class) assert_block(full_message) do klasses.any? {|k| object.kind_of?(k)} end end end ## # Passes if `object`.kind_of?(`klass`) does not hold. # When `klass` is an array of classes or modules, it passes only if all # classes (and modules) do not satisfy +object.kind_of?(class_or_module). # # @example # assert_not_kind_of(Fixnum, 'foo') # -> pass # assert_not_kind_of([Fixnum, NilClass], '0') # -> pass # assert_not_kind_of([Fixnum, NilClass], 100) # -> fail # # @since 3.0.0 def assert_not_kind_of(klass, object, message=nil) _wrap_assertion do if klass.is_a?(Array) klasses = klass else klasses = [klass] end assert_block("The first parameter to assert_not_kind_of should be " + "a kind_of Module or an Array of a kind_of Module.") do klasses.all? {|k| k.kind_of?(Module)} end klass_message = AssertionMessage.maybe_container(klass) do |value| "<#{value}>" end full_message = build_message(message, " was expected to not be kind_of\\?\n" + "? but was.", object, klass_message) assert_block(full_message) do klasses.none? {|k| object.kind_of?(k)} end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_kind_of, :assert_not_kind_of ## # Passes if `object` .respond_to? `method` # # @example # assert_respond_to 'bugbear', :slice def assert_respond_to(object, method, message=nil) _wrap_assertion do full_message = build_message(message, ".kind_of\\?(Symbol) or\n" + ".respond_to\\?(:to_str) expected", method, method) assert_block(full_message) do method.kind_of?(Symbol) or method.respond_to?(:to_str) end full_message = build_message(message, ".respond_to\\?(?) expected\n" + "(Class: )", object, method, object.class) assert_block(full_message) {object.respond_to?(method)} end end ## # Passes if `object` does not .respond_to? `method`. # # @example # assert_not_respond_to('bugbear', :nonexistence) # -> pass # assert_not_respond_to('bugbear', :size) # -> fail def assert_not_respond_to(object, method, message=nil) _wrap_assertion do full_message = build_message(message, ".kind_of\\?(Symbol) or\n" + ".respond_to\\?(:to_str) expected", method, method) assert_block(full_message) do method.kind_of?(Symbol) or method.respond_to?(:to_str) end full_message = build_message(message, "!.respond_to\\?(?) expected\n" + "(Class: )", object, method, object.class) assert_block(full_message) {!object.respond_to?(method)} end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_respond_to, :assert_not_respond_to ## # Passes if `pattern` =~ `string`. # # @example # assert_match(/\d+/, 'five, 6, seven') def assert_match(pattern, string, message=nil) _wrap_assertion do pattern = case(pattern) when String Regexp.new(Regexp.escape(pattern)) else pattern end full_message = build_message(message, " was expected to be =~\n.", pattern, string) assert_block(full_message) { pattern =~ string } end end ## # Passes if `actual` .equal? `expected` (i.e. they are the same # instance). # # @example # o = Object.new # assert_same o, o def assert_same(expected, actual, message=nil) full_message = build_message(message, < with id was expected to be equal\\? to with id . EOT assert_block(full_message) { actual.equal?(expected) } end ## # Compares the `object1` with `object2` using `operator`. # # Passes if object1.__send__(operator, object2) is true. # # @example # assert_operator 5, :>=, 4 def assert_operator(object1, operator, object2, message=nil) _wrap_assertion do full_message = build_message(nil, "\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator) assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)} full_message = build_message(message, < was expected to be ? . EOT assert_block(full_message) { object1.__send__(operator, object2) } end end ## # Compares the `object1` with `object2` using `operator`. # # Passes if object1.__send__(operator, object2) is not true. # # @example # assert_not_operator(5, :<, 4) # => pass # assert_not_operator(5, :>, 4) # => fail # # @since 3.0.0 def assert_not_operator(object1, operator, object2, message=nil) _wrap_assertion do full_message = build_message(nil, "\ngiven as the operator for #assert_not_operator must be a Symbol or #respond_to\\?(:to_str).", operator) assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)} full_message = build_message(message, < was expected to not be ? . EOT assert_block(full_message) { ! object1.__send__(operator, object2) } end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_operator, :assert_not_operator ## # Passes if block does not raise an exception. # # @example # assert_nothing_raised do # [1, 2].uniq # end def assert_nothing_raised(*args) _wrap_assertion do if args.last.is_a?(String) message = args.pop else message = "" end assert_exception_helper = AssertExceptionHelper.new(self, args) begin yield rescue Exception => e if ((args.empty? && !e.instance_of?(AssertionFailedError)) || assert_exception_helper.expected?(e)) failure_message = build_message(message, "Exception raised:\n?", e) assert_block(failure_message) {false} else raise end end end end ## # Flunk always fails. # # @example # flunk 'Not done testing yet.' def flunk(message="Flunked") assert_block(build_message(message)){false} end ## # Passes if ! `actual` .equal? `expected` # # @example # assert_not_same Object.new, Object.new def assert_not_same(expected, actual, message=nil) full_message = build_message(message, < with id was expected to not be equal\\? to with id . EOT assert_block(full_message) { !actual.equal?(expected) } end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_same, :assert_not_same ## # Passes if `expected` != `actual` # # @example # assert_not_equal 'some string', 5 def assert_not_equal(expected, actual, message=nil) full_message = build_message(message, " was expected to be != to\n.", expected, actual) assert_block(full_message) { expected != actual } end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_equal, :assert_not_equal ## # Passes if ! `object` .nil? # # @example # assert_not_nil '1 two 3'.sub!(/two/, '2') def assert_not_nil(object, message=nil) full_message = build_message(message, " was expected to not be nil.", object) assert_block(full_message){!object.nil?} end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_nil, :assert_not_nil ## # Passes if `regexp` !~ `string` # # @example # assert_not_match(/two/, 'one 2 three') # -> pass # assert_not_match(/three/, 'one 2 three') # -> fail def assert_not_match(regexp, string, message=nil) _wrap_assertion do assert_instance_of(Regexp, regexp, " in assert_not_match(, ...) " + "should be a Regexp.") full_message = build_message(message, " was expected to not match\n.", regexp, string) assert_block(full_message) { regexp !~ string } end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_match, :assert_not_match ## # Deprecated. Use #assert_not_match instead. # # Passes if `regexp` !~ `string` # # @example # assert_no_match(/two/, 'one 2 three') # -> pass # assert_no_match(/three/, 'one 2 three') # -> fail def assert_no_match(regexp, string, message="") _wrap_assertion do assert_instance_of(Regexp, regexp, "The first argument to assert_no_match " + "should be a Regexp.") assert_not_match(regexp, string, message) end end # @private class ThrowTagExtractor @@have_uncaught_throw_error = const_defined?(:UncaughtThrowError) UncaughtThrowPatterns = { NameError => /^uncaught throw `(.+)'$/, ArgumentError => /^uncaught throw (`.+'|.+)$/, ThreadError => /^uncaught throw `(.+)' in thread /, } def initialize(error) @error = error end def extract_tag tag = nil if @@have_uncaught_throw_error return nil unless @error.is_a?(UncaughtThrowError) tag = @error.tag else pattern = UncaughtThrowPatterns[@error.class] return nil if pattern.nil? return nil unless pattern =~ @error.message tag = $1 end normalize_tag(tag) end private def normalize_tag(tag) case tag when /\A:/ tag[1..-1].intern when /\A`(.+)'\z/ $1.intern when String tag.intern else tag end end end ## # Passes if the block throws `expected_object` # # @example # assert_throw(:done) do # throw(:done) # end def assert_throw(expected_object, message=nil, &proc) _wrap_assertion do begin catch([]) {} rescue TypeError assert_instance_of(Symbol, expected_object, "assert_throws expects the symbol that should be thrown for its first argument") end assert_block("Should have passed a block to assert_throw.") do block_given? end caught = true begin catch(expected_object) do proc.call caught = false end full_message = build_message(message, " should have been thrown.", expected_object) assert_block(full_message) {caught} rescue => error extractor = ThrowTagExtractor.new(error) tag = extractor.extract_tag raise if tag.nil? full_message = build_message(message, " was expected to be thrown but\n" + " was thrown.", expected_object, tag) flunk(full_message) end end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :assert_throws, :assert_throw ## # Passes if block does not throw anything. # # @example # assert_nothing_thrown do # [1, 2].uniq # end def assert_nothing_thrown(message=nil, &proc) _wrap_assertion do assert(block_given?, "Should have passed a block to assert_nothing_thrown") begin proc.call rescue => error extractor = ThrowTagExtractor.new(error) tag = extractor.extract_tag raise if tag.nil? full_message = build_message(message, " was thrown when nothing was expected", tag) flunk(full_message) end assert(true, "Expected nothing to be thrown") end end ## # Passes if `expected_float` and `actual_float` are equal # within `delta` tolerance. # # @example # assert_in_delta 0.05, (50000.0 / 10**6), 0.00001 def assert_in_delta(expected_float, actual_float, delta=0.001, message="") _wrap_assertion do _assert_in_delta_validate_arguments(expected_float, actual_float, delta) full_message = _assert_in_delta_message(expected_float, actual_float, delta, message) assert_block(full_message) do (expected_float.to_f - actual_float.to_f).abs <= delta.to_f end end end ## # Passes if `expected_float` and `actual_float` are # not equal within `delta` tolerance. # # @example # assert_not_in_delta(0.05, (50000.0 / 10**6), 0.00002) # -> pass # assert_not_in_delta(0.05, (50000.0 / 10**6), 0.00001) # -> fail def assert_not_in_delta(expected_float, actual_float, delta=0.001, message="") _wrap_assertion do _assert_in_delta_validate_arguments(expected_float, actual_float, delta) full_message = _assert_in_delta_message(expected_float, actual_float, delta, message, :negative_assertion => true) assert_block(full_message) do (expected_float.to_f - actual_float.to_f).abs > delta.to_f end end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_in_delta, :assert_not_in_delta private def _assert_in_delta_validate_arguments(expected_float, actual_float, delta) { expected_float => "first float", actual_float => "second float", delta => "delta" }.each do |float, name| assert_respond_to(float, :to_f, "The arguments must respond to to_f; " + "the #{name} did not") end delta = delta.to_f assert_operator(delta, :>=, 0.0, "The delta should not be negative") end def _assert_in_delta_message(expected_float, actual_float, delta, message, options={}) if options[:negative_assertion] format = <<-EOT -/+ was expected to not include . EOT else format = <<-EOT -/+ was expected to include . EOT end arguments = [expected_float, delta, actual_float] normalized_expected = expected_float.to_f normalized_actual = actual_float.to_f normalized_delta = delta.to_f relation_format = nil relation_arguments = nil if normalized_actual < normalized_expected - normalized_delta relation_format = "< < -[?] <= +[?]>" relation_arguments = [actual_float, expected_float, delta, normalized_expected - normalized_delta, expected_float, delta, normalized_expected + normalized_delta] elsif normalized_actual <= normalized_expected + normalized_delta relation_format = "<-[?] <= <= +[?]>" relation_arguments = [expected_float, delta, normalized_expected - normalized_delta, actual_float, expected_float, delta, normalized_expected + normalized_delta] else relation_format = "<-[?] <= +[?] < >" relation_arguments = [expected_float, delta, normalized_expected - normalized_delta, expected_float, delta, normalized_expected + normalized_delta, actual_float] end if relation_format format += <<-EOT Relation: #{relation_format} EOT arguments.concat(relation_arguments) end build_message(message, format, *arguments) end public ## # Passes if `expected_float` and `actual_float` are equal # within `epsilon` relative error of `expected_float`. # # @example # assert_in_epsilon(10000.0, 9900.0, 0.1) # -> pass # assert_in_epsilon(10000.0, 9899.0, 0.1) # -> fail def assert_in_epsilon(expected_float, actual_float, epsilon=0.001, message="") _wrap_assertion do _assert_in_epsilon_validate_arguments(expected_float, actual_float, epsilon) full_message = _assert_in_epsilon_message(expected_float, actual_float, epsilon, message) assert_block(full_message) do normalized_expected_float = expected_float.to_f if normalized_expected_float.zero? delta = epsilon.to_f ** 2 else delta = normalized_expected_float * epsilon.to_f end delta = delta.abs (normalized_expected_float - actual_float.to_f).abs <= delta end end end ## # Passes if `expected_float` and `actual_float` are # not equal within `epsilon` relative error of # `expected_float`. # # @example # assert_not_in_epsilon(10000.0, 9900.0, 0.1) # -> fail # assert_not_in_epsilon(10000.0, 9899.0, 0.1) # -> pass def assert_not_in_epsilon(expected_float, actual_float, epsilon=0.001, message="") _wrap_assertion do _assert_in_epsilon_validate_arguments(expected_float, actual_float, epsilon) full_message = _assert_in_epsilon_message(expected_float, actual_float, epsilon, message, :negative_assertion => true) assert_block(full_message) do normalized_expected_float = expected_float.to_f delta = normalized_expected_float * epsilon.to_f (normalized_expected_float - actual_float.to_f).abs > delta end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_in_epsilon, :assert_not_in_epsilon private def _assert_in_epsilon_validate_arguments(expected_float, actual_float, epsilon) { expected_float => "first float", actual_float => "second float", epsilon => "epsilon" }.each do |float, name| assert_respond_to(float, :to_f, "The arguments must respond to to_f; " + "the #{name} did not") end epsilon = epsilon.to_f assert_operator(epsilon, :>=, 0.0, "The epsilon should not be negative") end def _assert_in_epsilon_message(expected_float, actual_float, epsilon, message, options={}) normalized_expected = expected_float.to_f normalized_actual = actual_float.to_f normalized_epsilon = epsilon.to_f delta = normalized_expected * normalized_epsilon if options[:negative_assertion] format = <<-EOT -/+ ( * )[?] was expected to not include . EOT else format = <<-EOT -/+ ( * )[?] was expected to include . EOT end arguments = [expected_float, expected_float, epsilon, delta, actual_float] relation_format = nil relation_arguments = nil if normalized_actual < normalized_expected - delta relation_format = "< < -(*)[?] <= +(*)[?]>" relation_arguments = [actual_float, expected_float, expected_float, epsilon, normalized_expected - delta, expected_float, expected_float, epsilon, normalized_expected + delta] elsif normalized_actual <= normalized_expected + delta relation_format = "<-(*)[?] <= <= +(*)[?]>" relation_arguments = [expected_float, expected_float, epsilon, normalized_expected - delta, actual_float, expected_float, expected_float, epsilon, normalized_expected + delta] else relation_format = "<-(*)[?] <= +(*)[?] < >" relation_arguments = [expected_float, expected_float, epsilon, normalized_expected - delta, expected_float, expected_float, epsilon, normalized_expected + delta, actual_float] end if relation_format format += <<-EOT Relation: #{relation_format} EOT arguments.concat(relation_arguments) end build_message(message, format, *arguments) end public ## # Passes if the method send returns a true value. # # `send_array` is composed of: # * A receiver # * A method # * Arguments to the method # # @example # assert_send([[1, 2], :member?, 1]) # -> pass # assert_send([[1, 2], :member?, 4]) # -> fail def assert_send(send_array, message=nil) _wrap_assertion do assert_instance_of(Array, send_array, "assert_send requires an array " + "of send information") assert_operator(send_array.size, :>=, 2, "assert_send requires at least a receiver " + "and a message name") format = < was expected to respond to with a true value but was . EOT receiver, message_name, *arguments = send_array result = nil full_message = build_message(message, format, receiver, AssertionMessage.literal(message_name.to_s), arguments, AssertionMessage.delayed_literal {result}) assert_block(full_message) do result = receiver.__send__(message_name, *arguments) result end end end ## # Passes if the method send doesn't return a true value. # # `send_array` is composed of: # * A receiver # * A method # * Arguments to the method # # @example # assert_not_send([[1, 2], :member?, 1]) # -> fail # assert_not_send([[1, 2], :member?, 4]) # -> pass def assert_not_send(send_array, message=nil) _wrap_assertion do assert_instance_of(Array, send_array, "assert_not_send requires an array " + "of send information") assert_operator(send_array.size, :>=, 2, "assert_not_send requires at least a receiver " + "and a message name") format = < was expected to respond to with not a true value but was . EOT receiver, message_name, *arguments = send_array result = nil full_message = build_message(message, format, receiver, AssertionMessage.literal(message_name.to_s), arguments, AssertionMessage.delayed_literal {result}) assert_block(full_message) do result = receiver.__send__(message_name, *arguments) not result end end end ## # Passes if `actual` is a boolean value. # # @example # assert_boolean(true) # -> pass # assert_boolean(nil) # -> fail def assert_boolean(actual, message=nil) _wrap_assertion do assert_block(build_message(message, " or expected but was\n", actual)) do [true, false].include?(actual) end end end ## # Passes if `actual` is true. # # @example # assert_true(true) # -> pass # assert_true(:true) # -> fail def assert_true(actual, message=nil) _wrap_assertion do assert_block(build_message(message, " expected but was\n", actual)) do actual == true end end end ## # Passes if `actual` is false. # # @example # assert_false(false) # -> pass # assert_false(nil) # -> fail def assert_false(actual, message=nil) _wrap_assertion do assert_block(build_message(message, " expected but was\n", actual)) do actual == false end end end ## # Passes if expression "`expected` `operator` # `actual`" is true. # # @example # assert_compare(1, "<", 10) # -> pass # assert_compare(1, ">=", 10) # -> fail def assert_compare(expected, operator, actual, message=nil) _wrap_assertion do assert_send([["<", "<=", ">", ">="], :include?, operator.to_s]) case operator.to_s when "<" operator_description = "less than" when "<=" operator_description = "less than or equal to" when ">" operator_description = "greater than" when ">=" operator_description = "greater than or equal to" end template = <<-EOT #{operator} should be true was expected to be #{operator_description} . EOT full_message = build_message(message, template, expected, actual, expected, actual) assert_block(full_message) do expected.__send__(operator, actual) end end end ## # Passes if assertion is failed in block. # # @example # assert_fail_assertion {assert_equal("A", "B")} # -> pass # assert_fail_assertion {assert_equal("A", "A")} # -> fail def assert_fail_assertion(message=nil) _wrap_assertion do full_message = build_message(message, "Failed assertion was expected.") assert_block(full_message) do begin yield false rescue AssertionFailedError true end end end end ## # Passes if an exception is raised in block and its # message is `expected`. # # @example # assert_raise_message("exception") {raise "exception"} # -> pass # assert_raise_message(/exc/i) {raise "exception"} # -> pass # assert_raise_message("exception") {raise "EXCEPTION"} # -> fail # assert_raise_message("exception") {} # -> fail def assert_raise_message(expected, message=nil) _wrap_assertion do full_message = build_message(message, " exception message was expected " + "but none was thrown.", expected) exception = nil assert_block(full_message) do begin yield false rescue Exception => exception true end end actual = exception.message diff = AssertionMessage.delayed_diff(expected, actual) full_message = build_message(message, " exception message expected but was\n" + ".?", expected, actual, diff) assert_block(full_message) do if expected.is_a?(Regexp) expected =~ actual else expected == actual end end end end ## # Passes if `object`.const_defined?(`constant_name`) # # @example # assert_const_defined(Test, :Unit) # -> pass # assert_const_defined(Object, :Nonexistent) # -> fail def assert_const_defined(object, constant_name, message=nil) _wrap_assertion do full_message = build_message(message, ".const_defined\\?() expected.", object, constant_name) assert_block(full_message) do object.const_defined?(constant_name) end end end ## # Passes if !`object`.const_defined?(`constant_name`) # # @example # assert_not_const_defined(Object, :Nonexistent) # -> pass # assert_not_const_defined(Test, :Unit) # -> fail def assert_not_const_defined(object, constant_name, message=nil) _wrap_assertion do full_message = build_message(message, "!.const_defined\\?() expected.", object, constant_name) assert_block(full_message) do !object.const_defined?(constant_name) end end end ## # Passes if `object`.`predicate` is _true_. # # @example # assert_predicate([], :empty?) # -> pass # assert_predicate([1], :empty?) # -> fail def assert_predicate(object, predicate, message=nil) _wrap_assertion do assert_respond_to(object, predicate, message) actual = object.__send__(predicate) full_message = build_message(message, ".? is true value expected but was\n" + "", object, AssertionMessage.literal(predicate), actual) assert_block(full_message) do actual end end end ## # Passes if `object`.`predicate` is not _true_. # # @example # assert_not_predicate([1], :empty?) # -> pass # assert_not_predicate([], :empty?) # -> fail def assert_not_predicate(object, predicate, message=nil) _wrap_assertion do assert_respond_to(object, predicate, message) actual = object.__send__(predicate) full_message = build_message(message, ".? is false value expected but was\n" + "", object, AssertionMessage.literal(predicate), actual) assert_block(full_message) do not actual end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_predicate, :assert_not_predicate ## # Passes if `object`#`alias_name` is an alias method of # `object`#`original_name`. # # @example # assert_alias_method([], :length, :size) # -> pass # assert_alias_method([], :size, :length) # -> pass # assert_alias_method([], :each, :size) # -> fail def assert_alias_method(object, alias_name, original_name, message=nil) _wrap_assertion do find_method_failure_message = Proc.new do |method_name| build_message(message, ".? doesn't exist\n" + "(Class: )", object, AssertionMessage.literal(method_name), object.class) end alias_method = original_method = nil assert_block(find_method_failure_message.call(alias_name)) do begin alias_method = object.method(alias_name) true rescue NameError false end end assert_block(find_method_failure_message.call(original_name)) do begin original_method = object.method(original_name) true rescue NameError false end end full_message = build_message(message, " is alias of\n" + " expected", alias_method, original_method) assert_block(full_message) do alias_method == original_method end end end ## # Passes if `path` exists. # # @example # assert_path_exist("/tmp") # -> pass # assert_path_exist("/bin/sh") # -> pass # assert_path_exist("/nonexistent") # -> fail def assert_path_exist(path, message=nil) _wrap_assertion do failure_message = build_message(message, " was expected to exist", path) assert_block(failure_message) do File.exist?(path) end end end ## # Passes if `path` doesn't exist. # # @example # assert_path_not_exist("/nonexistent") # -> pass # assert_path_not_exist("/tmp") # -> fail # assert_path_not_exist("/bin/sh") # -> fail def assert_path_not_exist(path, message=nil) _wrap_assertion do failure_message = build_message(message, " was expected to not exist", path) assert_block(failure_message) do not File.exist?(path) end end end ## # Passes if `collection` includes `object`. # # @example # assert_include([1, 10], 1) # -> pass # assert_include(1..10, 5) # -> pass # assert_include([1, 10], 5) # -> fail # assert_include(1..10, 20) # -> fail def assert_include(collection, object, message=nil) _wrap_assertion do assert_respond_to(collection, :include?, "The collection must respond to :include?.") full_message = build_message(message, " was expected to include\n.", collection, object) assert_block(full_message) do collection.include?(object) end end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :assert_includes, :assert_include ## # Passes if `collection` doesn't include `object`. # # @example # assert_not_include([1, 10], 5) # -> pass # assert_not_include(1..10, 20) # -> pass # assert_not_include([1, 10], 1) # -> fail # assert_not_include(1..10, 5) # -> fail def assert_not_include(collection, object, message=nil) _wrap_assertion do assert_respond_to(collection, :include?, "The collection must respond to :include?.") full_message = build_message(message, " was expected to not include\n.", collection, object) assert_block(full_message) do not collection.include?(object) end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :assert_not_includes, :assert_not_include # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_includes, :assert_not_include ## # Passes if `object` is empty. # # @example # assert_empty("") # -> pass # assert_empty([]) # -> pass # assert_empty({}) # -> pass # assert_empty(" ") # -> fail # assert_empty([nil]) # -> fail # assert_empty({1 => 2}) # -> fail def assert_empty(object, message=nil) _wrap_assertion do assert_respond_to(object, :empty?, "The object must respond to :empty?.") full_message = build_message(message, " was expected to be empty.", object) assert_block(full_message) do object.empty? end end end ## # Passes if `object` is not empty. # # @example # assert_not_empty(" ") # -> pass # assert_not_empty([nil]) # -> pass # assert_not_empty({1 => 2}) # -> pass # assert_not_empty("") # -> fail # assert_not_empty([]) # -> fail # assert_not_empty({}) # -> fail def assert_not_empty(object, message=nil) _wrap_assertion do assert_respond_to(object, :empty?, "The object must respond to :empty?.") full_message = build_message(message, " was expected to not be empty.", object) assert_block(full_message) do not object.empty? end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_empty, :assert_not_empty ## # Builds a failure message. `user_message` is added before the # `template` and `arguments` replaces the '?'s positionally in # the template. def build_message(user_message, template=nil, *arguments) template &&= template.chomp return AssertionMessage.new(user_message, template, arguments) end private def _wrap_assertion(&block) @_assertion_wrapped ||= false if @_assertion_wrapped block.call else @_assertion_wrapped = true begin add_assertion block.call ensure @_assertion_wrapped = false end end end public # Called whenever an assertion is made. Define this in classes # that include Test::Unit::Assertions to record assertion # counts. # # This is a public API for developers who extend test-unit. # # @return [void] def add_assertion end ## # Select whether or not to use the pretty-printer. If this option is set # to false before any assertions are made, pp.rb will not be required. def self.use_pp=(value) AssertionMessage.use_pp = value end private def _assert_raise(assert_expected_exception, *args, &block) _wrap_assertion do if args.last.is_a?(String) message = args.pop else message = "" end assert_exception_helper = AssertExceptionHelper.new(self, args) expected = assert_exception_helper.expected_exceptions actual_exception = nil full_message = build_message(message, " exception was expected " + "but none was thrown.", expected) assert_block(full_message) do begin yield false rescue Exception => actual_exception true end end assert_expected_exception.call(message, assert_exception_helper, actual_exception) actual_exception end end def _set_failed_information(failure, expected, actual) failure.expected = expected failure.actual = actual failure.inspected_expected = AssertionMessage.convert(expected) failure.inspected_actual = AssertionMessage.convert(actual) end class AssertionMessage @use_pp = true class << self attr_accessor :use_pp def literal(value) Literal.new(value) end def delayed_literal(&block) DelayedLiteral.new(block) end def maybe_container(value, &formatter) MaybeContainer.new(value, &formatter) end MAX_DIFF_TARGET_STRING_SIZE = 1000 def max_diff_target_string_size return @@max_diff_target_string_size if @@max_diff_target_string_size size = ENV["TEST_UNIT_MAX_DIFF_TARGET_STRING_SIZE"] if size begin size = Integer(size) rescue ArgumentError size = nil end end size || MAX_DIFF_TARGET_STRING_SIZE end @@max_diff_target_string_size = nil def max_diff_target_string_size=(size) @@max_diff_target_string_size = size end def diff_target_string?(string) if string.respond_to?(:bytesize) string.bytesize < max_diff_target_string_size else string.size < max_diff_target_string_size end end def ensure_diffable_string(string) if string.respond_to?(:encoding) and !string.encoding.ascii_compatible? string = string.dup.force_encoding("ASCII-8BIT") end string end def prepare_for_diff(from, to) if !from.is_a?(String) or !to.is_a?(String) from = convert(from) to = convert(to) end if diff_target_string?(from) and diff_target_string?(to) from = ensure_diffable_string(from) to = ensure_diffable_string(to) [from, to] else [nil, nil] end end def delayed_diff(from, to) delayed_literal do from, to = prepare_for_diff(from, to) diff = "" if from.nil? or to.nil? diff ||= Diff.readable(from, to) if /^[-+]/ !~ diff diff = "" elsif /^[ ?]/ =~ diff or /(?:.*\n){2,}/ =~ diff diff = "\n\ndiff:\n#{diff}" else diff = "" end if Diff.need_fold?(diff) folded_diff = Diff.folded_readable(from, to) diff += "\n\nfolded diff:\n#{folded_diff}" end diff end end def convert(object) if object.is_a?(Exception) object = AssertExceptionHelper::WrappedException.new(object) end inspector = Inspector.new(object) if use_pp begin require "pp" unless defined?(PP) begin return PP.pp(inspector, String.new).chomp rescue NameError end rescue LoadError self.use_pp = false end end inspector.inspect end end class Inspector include Comparable class << self def cached_new(object, inspected_objects) inspected_objects[object.object_id] ||= new(object, inspected_objects) end @@inspector_classes = [] def inspector_classes @@inspector_classes end def register_inspector_class(inspector_class) @@inspector_classes << inspector_class end def unregister_inspector_class(inspector_class) @@inspector_classes.delete(inspector_class) end end attr_reader :object def initialize(object, inspected_objects={}) @inspected_objects = inspected_objects @object = object @inspected_objects[@object.object_id] = self @inspect_target = inspect_target end alias_method :native_inspect, :inspect def inspect @inspect_target.inspect end def pretty_print(q) @inspect_target.pretty_print(q) end def pretty_print_cycle(q) @inspect_target.pretty_print_cycle(q) end def <=>(other) if other.is_a?(self.class) @object <=> other.object else @object <=> other end end private def inspect_target self.class.inspector_classes.each do |inspector_class| if inspector_class.target?(@object) return inspector_class.new(@object, @inspected_objects) end end @object end end class NumericInspector Inspector.register_inspector_class(self) class << self def target?(object) object.is_a?(Numeric) end end def initialize(numeric, inspected_objects) @inspected_objects = inspected_objects @numeric = numeric end def inspect @numeric.to_s end def pretty_print(q) q.text(@numeric.to_s) end def pretty_print_cycle(q) q.text(@numeric.to_s) end end class HashInspector Inspector.register_inspector_class(self) class << self def target?(object) object.is_a?(Hash) or ENV.equal?(object) end end def initialize(hash, inspected_objects) @inspected_objects = inspected_objects @hash = {} hash.each do |key, value| key = Inspector.cached_new(key, @inspected_objects) value = Inspector.cached_new(value, @inspected_objects) @hash[key] = value end end def inspect @hash.inspect end def pretty_print(q) q.group(1, '{', '}') do q.seplist(self, nil, :each_pair) do |k, v| q.group do q.pp(k) q.text('=>') q.group(1) do q.breakable('') q.pp(v) end end end end end def pretty_print_cycle(q) @hash.pretty_print_cycle(q) end def each_pair keys = @hash.keys begin keys = keys.sort # FIXME: more cleverly rescue ArgumentError end keys.each do |key| yield(key, @hash[key]) end end end class ArrayInspector Inspector.register_inspector_class(self) class << self def target?(object) object.is_a?(Array) end end def initialize(array, inspected_objects) @inspected_objects = inspected_objects @array = array.collect do |element| Inspector.cached_new(element, @inspected_objects) end end def inspect @array.inspect end def pretty_print(q) q.group(1, '[', ']') do q.seplist(self) do |v| q.pp(v) end end end def pretty_print_cycle(q) @array.pretty_print_cycle(q) end def each(&block) @array.each(&block) end end class Literal def initialize(value) @value = value end def inspect @value.to_s end end class DelayedLiteral def initialize(value) @value = value end def inspect @value.call.to_s end end class MaybeContainer def initialize(value, &formatter) @value = value @formatter = formatter end def inspect if @value.is_a?(Array) values = @value.collect do |value| @formatter.call(AssertionMessage.convert(value)) end "[#{values.join(', ')}]" else @formatter.call(AssertionMessage.convert(@value)) end end end class Template def self.create(string) parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : []) self.new(parts) end attr_reader :count def initialize(parts) @parts = parts @count = parts.find_all{|e| e == '?'}.size end def result(parameters) raise "The number of parameters does not match the number of substitutions." if(parameters.size != count) params = parameters.dup expanded_template = "" @parts.each do |part| if part == '?' param = params.shift if Object.const_defined?(:Encoding) expanded_template += concatenatable(param, expanded_template.encoding) else expanded_template += param end else expanded_template += part.gsub(/\\\?/m, '?') end end expanded_template end private def concatenatable(text, encoding) if Encoding.compatible?(text, encoding) text else text.dup.force_encoding(encoding) end end end include Util::BacktraceFilter def initialize(user_message, template_string, parameters) @user_message = user_message @template_string = template_string @parameters = parameters end def convert(object) self.class.convert(object) end def template @template ||= Template.create(@template_string) end def user_message return nil unless @user_message message = @user_message message = message.call if message.respond_to?(:call) message.to_s end def to_s message_parts = [] head = user_message if head and not head.empty? message_parts << add_period(head) end tail = template.result(@parameters.collect{|e| convert(e)}) message_parts << tail unless(tail.empty?) message_parts.join("\n") end private def add_period(string) (string =~ /\.\Z/ ? string : string + '.') end end class AssertExceptionHelper class WrappedException attr_reader :exception def initialize(exception) @exception = exception end def inspect if default_inspect? "#{@exception.class.inspect}(<#{@exception.message}>)" else @exception.inspect end end def method_missing(name, *args, &block) @exception.__send__(name, *args, &block) end private def default_inspect? inspect_method = @exception.method(:inspect) if inspect_method.respond_to?(:owner) and inspect_method.owner == Exception true else default_inspect_method = Exception.instance_method(:inspect) default_inspect_method.bind(@exception).call == @exception.inspect end end end def initialize(test_case, expected_exceptions) @test_case = test_case @expected_exceptions = expected_exceptions @expected_classes, @expected_modules, @expected_objects = split_expected_exceptions(expected_exceptions) end def expected_exceptions exceptions = @expected_exceptions.collect do |exception| if exception.is_a?(Exception) WrappedException.new(exception) else exception end end if exceptions.size == 1 exceptions[0] else exceptions end end def expected?(actual_exception, equality=nil) equality ||= :instance_of? expected_class?(actual_exception, equality) or expected_module?(actual_exception) or expected_object?(actual_exception) end private def split_expected_exceptions(expected_exceptions) exception_modules = [] exception_objects = [] exception_classes = [] expected_exceptions.each do |exception_type| if exception_type.instance_of?(Module) exception_modules << exception_type elsif exception_object?(exception_type) exception_objects << exception_type elsif exception_class?(exception_type) exception_classes << exception_type else full_message = @test_case.__send__(:build_message, nil, " must be " + "a subclass of Exception, " + "an object of Exception subclasses " + "or a Module", exception_type) @test_case.flunk(full_message) end end [exception_classes, exception_modules, exception_objects] end def exception_object?(exception_type) return true if exception_type.is_a?(Exception) if Object.const_defined?(:Java) return true if exception_type.is_a?(Java::JavaLang::Throwable) end false end def exception_class?(exception_type) return true if exception_type <= Exception if Object.const_defined?(:Java) return true if exception_type <= Java::JavaLang::Throwable end false end def expected_class?(actual_exception, equality) @expected_classes.any? do |expected_class| actual_exception.__send__(equality, expected_class) end end def expected_module?(actual_exception) @expected_modules.any? do |expected_module| actual_exception.is_a?(expected_module) end end def expected_object?(actual_exception) @expected_objects.any? do |expected_object| expected_object == actual_exception or fallback_exception_object_equal(expected_object, actual_exception) end end def fallback_exception_object_equal(expected_object, actual_exception) owner = Util::MethodOwnerFinder.find(expected_object, :==) if owner == Kernel or owner == Exception expected_object.class == actual_exception.class and expected_object.message == actual_exception.message else false end end end # :startdoc: end end end PK ] 0gems/test-unit-3.3.4/lib/test/unit/testresult.rbnu[#-- # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/observable' require 'test/unit/failure' require 'test/unit/error' require 'test/unit/omission' require 'test/unit/pending' require 'test/unit/notification' module Test module Unit module NullResultContainerInitializer private def initialize_containers end end # Collects Test::Unit::Failure and Test::Unit::Error so that # they can be displayed to the user. To this end, observers # can be added to it, allowing the dynamic updating of, say, a # UI. class TestResult include Util::Observable include NullResultContainerInitializer include TestResultFailureSupport include TestResultErrorSupport include TestResultPendingSupport include TestResultOmissionSupport include TestResultNotificationSupport FINISHED = name + "::FINISHED" CHANGED = name + "::CHANGED" PASS_ASSERTION = name + "::PASS_ASSERTION" FAULT = name + "::FAULT" attr_reader :run_count, :pass_count, :assertion_count, :faults attr_accessor :stop_tag # Constructs a new, empty TestResult. def initialize @run_count, @pass_count, @assertion_count = 0, 0, 0 @summary_generators = [] @problem_checkers = [] @faults = [] @stop_tag = nil initialize_containers end # Records a test run. def add_run @run_count += 1 notify_listeners(FINISHED, self) notify_changed end def add_pass @pass_count += 1 end # Records an individual assertion. def add_assertion @assertion_count += 1 notify_listeners(PASS_ASSERTION, self) notify_changed end # Returns a string contain the recorded runs, assertions, # failures and errors in this TestResult. def summary ["#{run_count} tests", "#{assertion_count} assertions", *@summary_generators.collect {|generator| __send__(generator)}].join(", ") end # Returnes a string that shows result status. def status if passed? if pending_count > 0 "pending" elsif omission_count > 0 "omission" elsif notification_count > 0 "notification" else "pass" end elsif error_count > 0 "error" elsif failure_count > 0 "failure" end end def stop throw @stop_tag end def to_s summary end # Returns whether or not this TestResult represents # successful completion. def passed? @problem_checkers.all? {|checker| not __send__(checker)} end def pass_percentage n_tests = @run_count - omission_count if n_tests.zero? 0 else 100.0 * (@pass_count / n_tests.to_f) end end private def notify_changed notify_listeners(CHANGED, self) end def notify_fault(fault) @faults << fault notify_listeners(FAULT, fault) end end end end PK ]Uį-gems/test-unit-3.3.4/lib/test/unit/pending.rbnu[require 'test/unit/util/backtracefilter' module Test module Unit class Pending include Util::BacktraceFilter attr_reader :test_name, :location, :message attr_reader :method_name SINGLE_CHARACTER = 'P' LABEL = "Pending" # Creates a new Pending with the given location and # message. def initialize(test_name, location, message, options={}) @test_name = test_name @location = location @message = message @method_name = options[:method_name] end # Returns a single character representation of a pending. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns a brief version of the error description. def short_display "#{@test_name}: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace = filter_backtrace(location).join("\n") "#{label}: #{@message}\n#{@test_name}\n#{backtrace}" end # Overridden to return long_display. def to_s long_display end def critical? true end end class PendedError < StandardError end module TestCasePendingSupport class << self def included(base) base.class_eval do include PendingHandler end end end # Marks the test or part of the test is pending. # # Example: # # def test_pending # pend # # Not reached here # end # # def test_pending_with_here # pend do # # Ran here # # Fails if the block doesn't raise any error. # # Because it means the block is passed unexpectedly. # end # # Reached here # end def pend(message=nil, &block) message ||= "pended." if block_given? pending = nil begin yield rescue Exception pending = Pending.new(name, filter_backtrace(caller), message, :method_name => @method_name) add_pending(pending) end unless pending flunk("Pending block should not be passed: #{message}") end else raise PendedError.new(message) end end private def add_pending(pending) problem_occurred current_result.add_pending(pending) end end module PendingHandler class << self def included(base) base.exception_handler(:handle_pended_error) end end private def handle_pended_error(exception) return false unless exception.is_a?(PendedError) pending = Pending.new(name, filter_backtrace(exception.backtrace), exception.message, :method_name => @method_name) add_pending(pending) true end end module TestResultPendingSupport attr_reader :pendings # Records a Test::Unit::Pending. def add_pending(pending) @pendings << pending notify_fault(pending) notify_changed end # Returns the number of pendings this TestResult has # recorded. def pending_count @pendings.size end private def initialize_containers super @pendings = [] @summary_generators << :pending_summary end def pending_summary "#{pending_count} pendings" end end end end PK ]Dddd.gems/test-unit-3.3.4/lib/test/unit/omission.rbnu[require 'test/unit/util/backtracefilter' module Test module Unit class Omission include Util::BacktraceFilter attr_reader :test_name, :location, :message attr_reader :method_name SINGLE_CHARACTER = 'O' LABEL = "Omission" # Creates a new Omission with the given location and # message. def initialize(test_name, location, message, options={}) @test_name = test_name @location = location @message = message @method_name = options[:method_name] end # Returns a single character representation of a omission. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns a brief version of the error description. def short_display "#{@test_name}: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace = filter_backtrace(location).join("\n") "#{label}: #{@message}\n#{@test_name}\n#{backtrace}" end # Overridden to return long_display. def to_s long_display end def critical? true end end class OmittedError < StandardError end module TestCaseOmissionSupport class << self def included(base) base.class_eval do include OmissionHandler end end end # Omit the test or part of the test. # # Example: # # def test_omission # omit # # Not reached here # end # # def test_omission_with_here # omit do # # Not ran here # end # # Reached here # end def omit(message=nil, &block) message ||= "omitted." if block_given? omission = Omission.new(name, filter_backtrace(caller), message, :method_name => @method_name) add_omission(omission) else raise OmittedError.new(message) end end # Omit the test or part of the test if _condition_ is # true. # # Example: # # def test_omission # omit_if("".empty?) # # Not reached here # end # # def test_omission_with_here # omit_if(true) do # # Not ran here # end # omit_if(false) do # # Reached here # end # # Reached here too # end def omit_if(condition, *args, &block) if condition omit(*args, &block) else block.call if block end end # Omit the test or part of the test if _condition_ is # not true. # # Example: # # def test_omission # omit_unless("string".empty?) # # Not reached here # end # # def test_omission_with_here # omit_unless(true) do # # Reached here # end # omit_unless(false) do # # Not ran here # end # # Reached here too # end def omit_unless(condition, *args, &block) if condition block.call if block else omit(*args, &block) end end private def add_omission(omission) current_result.add_omission(omission) end end module OmissionHandler class << self def included(base) base.exception_handler(:handle_omitted_error) end end private def handle_omitted_error(exception) return false unless exception.is_a?(OmittedError) omission = Omission.new(name, filter_backtrace(exception.backtrace), exception.message, :method_name => @method_name) add_omission(omission) true end end module TestResultOmissionSupport attr_reader :omissions # Records a Test::Unit::Omission. def add_omission(omission) @omissions << omission notify_fault(omission) notify_changed end # Returns the number of omissions this TestResult has # recorded. def omission_count @omissions.size end private def initialize_containers super @omissions = [] @summary_generators << :omission_summary end def omission_summary "#{omission_count} omissions" end end end end PK ]soo+gems/test-unit-3.3.4/lib/test/unit/error.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/backtracefilter' module Test module Unit # Encapsulates an error in a test. Created by # Test::Unit::TestCase when it rescues an exception thrown # during the processing of a test. class Error include Util::BacktraceFilter attr_reader :test_name, :exception attr_reader :method_name SINGLE_CHARACTER = 'E' LABEL = "Error" # Creates a new Error with the given test_name and # exception. def initialize(test_name, exception, options={}) @test_name = test_name @exception = exception @method_name = options[:method_name] end # Returns a single character representation of an error. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns the message associated with the error. def message "#{@exception.class.name}: #{@exception.message}" end # Returns a brief version of the error description. def short_display "#@test_name: #{message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace_display = location.join("\n ") "#{label}:\n#@test_name:\n#{message}\n #{backtrace_display}" end def location @location ||= filter_backtrace(@exception.backtrace) end alias_method :backtrace, :location # Deprecated # Overridden to return long_display. def to_s long_display end def critical? true end end module ErrorHandler class << self def included(base) base.exception_handler(:handle_all_exception) end end NOT_PASS_THROUGH_EXCEPTIONS = [] NOT_PASS_THROUGH_EXCEPTION_NAMES = ["Timeout::Error"] PASS_THROUGH_EXCEPTIONS = [ NoMemoryError, SignalException, Interrupt, SystemExit, ] PASS_THROUGH_EXCEPTION_NAMES = [] private def handle_all_exception(exception) return false if pass_through_exception?(exception) problem_occurred add_error(exception) true end def pass_through_exception?(exception) case exception when *NOT_PASS_THROUGH_EXCEPTIONS return false end case exception.class.name when *NOT_PASS_THROUGH_EXCEPTION_NAMES return false end case exception when *PASS_THROUGH_EXCEPTIONS return true end case exception.class.name when *PASS_THROUGH_EXCEPTION_NAMES return true end false end def add_error(exception) error = Error.new(name, exception, :method_name => @method_name) current_result.add_error(error) end end module TestResultErrorSupport attr_reader :errors # Records a Test::Unit::Error. def add_error(error) @errors << error notify_fault(error) notify_changed end # Returns the number of errors this TestResult has # recorded. def error_count @errors.size end def error_occurred? not @errors.empty? end private def initialize_containers super @errors = [] @summary_generators << :error_summary @problem_checkers << :error_occurred? end def error_summary "#{error_count} errors" end end end end PK ] /44/gems/test-unit-3.3.4/lib/test/unit/testsuite.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # Copyright:: Copyright (c) 2008-2011 Kouhei Sutou. All rights reserved. # License:: Ruby license. require 'test/unit/error' module Test module Unit # A collection of tests which can be #run. # # Note: It is easy to confuse a TestSuite instance with # something that has a static suite method; I know because _I_ # have trouble keeping them straight. Think of something that # has a suite method as simply providing a way to get a # meaningful TestSuite instance. class TestSuite attr_reader :name, :tests, :test_case, :start_time, :elapsed_time # Test suite that has higher priority is ran prior to # test suites that have lower priority. attr_accessor :priority STARTED = name + "::STARTED" STARTED_OBJECT = name + "::STARTED::OBJECT" FINISHED = name + "::FINISHED" FINISHED_OBJECT = name + "::FINISHED::OBJECT" # Creates a new TestSuite with the given name. def initialize(name="Unnamed TestSuite", test_case=nil) @name = name @tests = [] @test_case = test_case @n_tests = 0 @priority = 0 @start_time = nil @elapsed_time = nil @passed = true end # Runs the tests and/or suites contained in this # TestSuite. def run(result, &progress_block) @start_time = Time.now yield(STARTED, name) yield(STARTED_OBJECT, self) run_startup(result) while test = @tests.shift @n_tests += test.size run_test(test, result, &progress_block) @passed = false unless test.passed? end ensure begin run_shutdown(result) ensure @elapsed_time = Time.now - @start_time yield(FINISHED, name) yield(FINISHED_OBJECT, self) end end # Adds the test to the suite. def <<(test) @tests << test self end def delete(test) @tests.delete(test) end def delete_tests(tests) @tests -= tests end # Retuns the rolled up number of tests in this suite; # i.e. if the suite contains other suites, it counts the # tests within those suites, not the suites themselves. def size total_size = @n_tests @tests.each { |test| total_size += test.size } total_size end def empty? size.zero? end # Overridden to return the name given the suite at # creation. def to_s @name end # It's handy to be able to compare TestSuite instances. def ==(other) return false unless(other.kind_of?(self.class)) return false unless(@name == other.name) @tests == other.tests end def passed? @passed end private def run_startup(result) return if @test_case.nil? or !@test_case.respond_to?(:startup) begin @test_case.startup rescue Exception raise unless handle_exception($!, result) end end def run_test(test, result) finished_is_yielded = false finished_object_is_yielded = false previous_event_name = nil test.run(result) do |event_name, *args| case previous_event_name when Test::Unit::TestCase::STARTED if event_name != Test::Unit::TestCase::STARTED_OBJECT yield(Test::Unit::TestCase::STARTED_OBJECT, test) end when Test::Unit::TestCase::FINISHED if event_name != Test::Unit::TestCase::FINISHED_OBJECT yield(Test::Unit::TestCase::FINISHED_OBJECT, test) end finished_object_is_yielded = true end case event_name when Test::Unit::TestCase::STARTED finished_is_yielded = false finished_object_is_yielded = false when Test::Unit::TestCase::FINISHED finished_is_yielded = true end previous_event_name = event_name yield(event_name, *args) end if finished_is_yielded and not finished_object_is_yielded yield(Test::Unit::TestCase::FINISHED_OBJECT, test) end end def run_shutdown(result) return if @test_case.nil? or !@test_case.respond_to?(:shutdown) begin @test_case.shutdown rescue Exception raise unless handle_exception($!, result) end end def handle_exception(exception, result) case exception when *ErrorHandler::PASS_THROUGH_EXCEPTIONS false else result.add_error(Error.new(@test_case.name, exception)) @passed = false true end end end end end PK ]/gems/test-unit-3.3.4/lib/test/unit/attribute.rbnu[module Test module Unit module Attribute class StringifyKeyHash < Hash class << self def stringify(object) object.to_s end end def key?(key) super(self.class.stringify(key)) end def [](key) super(self.class.stringify(key)) end def []=(key, value) super(self.class.stringify(key), value) end end class << self def included(base) base.extend(BaseClassMethods) base.extend(ClassMethods) end end module BaseClassMethods def attributes_table {} end end module ClassMethods def method_added(name) super return unless defined?(@current_attributes) attributes = {} kept_attributes = StringifyKeyHash.new @current_attributes.each do |attribute_name, attribute| attributes[attribute_name] = attribute[:value] if attribute[:keep] keep_hook = attribute[:keep_hook] attribute = keep_hook.call(attribute) if keep_hook kept_attributes[attribute_name] = attribute end end set_attributes(name, attributes) @current_attributes = kept_attributes end # Set an attribute to test methods. # # @overload attribute(name, value) # @example # attribute :speed, :slow # def test_my_slow_method # self[:speed] # => :slow # end # # @param [Object] name the attribute name # @param [Object] value the attribute value # @return [void] # # @overload attribute(name, value, *method_names) # @example # def test_my_slow_method1 # self[:speed] # => :slow # end # # attribute :speed, :slow, :test_my_slow_method1, :test_my_slow_method2 # # def test_my_slow_method2 # self[:speed] # => :slow # end # # @param [Object] name the attribute name # @param [Object] value the attribute value # @param [Array] method_names the test method names set the attribute # @return [void] # # @overload attribute(name, value, options) # @example # attribute :speed, :slow, keep: true # def test_my_slow_method1 # self[:speed] # => :slow # end # # def test_my_slow_method2 # self[:speed] # => :slow # end # # @param [Object] name the attribute name # @param [Object] value the attribute value # @option options [Boolean] :keep whether or not to set attribute to following test methods # @return [void] # # @overload attribute(name, value, options, *method_names) # @example # def test_my_slow_method1 # self[:speed] # => :slow # end # # # There are no valid options for now. # attribute :speed, :slow, {}, :test_my_slow_method1 # # def test_my_slow_method2 # self[:speed] # => nil # end # # @param [Object] name the attribute name # @param [Object] value the attribute value # @param [Hash] options ignored # @param [Array] method_names the test method names set the attribute # @return [void] def attribute(name, value, options={}, *method_names) unless options.is_a?(Hash) method_names << options options = {} end if method_names.empty? current_attributes[name] = options.merge(:value => value) else method_names.each do |method_name| set_attributes(method_name, {name => value}) end end end def current_attributes @current_attributes ||= StringifyKeyHash.new end def current_attribute(name) current_attributes[name] || StringifyKeyHash.new end def attributes_table @attributes_table ||= StringifyKeyHash.new super.merge(@attributes_table) end def set_attributes(method_name, new_attributes) return if new_attributes.empty? @attributes_table ||= StringifyKeyHash.new @attributes_table[method_name] ||= StringifyKeyHash.new current_attributes = @attributes_table[method_name] new_attributes.each do |key, value| observers = attribute_observers(key) || [] observers.each do |observer| observer.call(self, StringifyKeyHash.stringify(key), (attributes(method_name) || {})[key], value, method_name) end current_attributes[key] = value end end def attributes(method_name) attributes = attributes_table[method_name] ancestors.each do |ancestor| next if ancestor == self if ancestor.is_a?(Class) and ancestor < Test::Unit::Attribute parent_attributes = ancestor.attributes(method_name) if attributes attributes = (parent_attributes || {}).merge(attributes) else attributes = parent_attributes end break end end attributes || StringifyKeyHash.new end def find_attribute(method_name, name, options={}) recursive_p = options[:recursive] recursive_p = true if recursive_p.nil? @attributes_table ||= StringifyKeyHash.new if @attributes_table.key?(method_name) attributes = @attributes_table[method_name] if attributes.key?(name) return attributes[name] end end return nil unless recursive_p return nil if self == TestCase @cached_parent_test_case ||= ancestors.find do |ancestor| ancestor != self and ancestor.is_a?(Class) and ancestor < Test::Unit::Attribute end @cached_parent_test_case.find_attribute(method_name, name, options) end @@attribute_observers = StringifyKeyHash.new def register_attribute_observer(attribute_name, observer=nil, &block) observer ||= Proc.new(&block) @@attribute_observers[attribute_name] ||= [] @@attribute_observers[attribute_name] << observer end def attribute_observers(attribute_name) @@attribute_observers[attribute_name] end end def attributes self.class.attributes(@method_name) || StringifyKeyHash.new end def [](name) self.class.find_attribute(@method_name, name) end end end end PK ] ,E.gems/test-unit-3.3.4/lib/test/unit/priority.rbnu[require "fileutils" module Test module Unit module Priority class << self def included(base) base.extend(ClassMethods) base.class_eval do setup :priority_setup, :before => :prepend teardown :priority_teardown, :after => :append end end @@enabled = false def enabled? @@enabled end def enable require "fileutils" require "tmpdir" @@enabled = true end def disable @@enabled = false end @@default = :normal def default @@default || :normal end def default=(default) @@default = default end def available_values Checker.available_priorities end end class Checker class << self def have_priority?(name) singleton_class = (class << self; self; end) singleton_class.method_defined?(priority_check_method_name(name)) end def need_to_run?(test) priority = test[:priority] || Priority.default if have_priority?(priority) __send__(priority_check_method_name(priority), test) else true end end def available_priorities methods(false).collect do |name| /\Arun_priority_(.+)\?\z/ =~ name.to_s $1 end.compact end def run_priority_must?(test) true end def run_priority_important?(test) rand > 0.1 end def run_priority_high?(test) rand > 0.3 end def run_priority_normal?(test) rand > 0.5 end def run_priority_low?(test) rand > 0.75 end def run_priority_never?(test) false end private def priority_check_method_name(priority_name) "run_priority_#{priority_name}?" end end attr_reader :test def initialize(test) @test = test end def setup FileUtils.rm_f(passed_file) end def teardown if @test.__send__(:passed?) FileUtils.touch(passed_file) else FileUtils.rm_f(passed_file) end end def need_to_run? !previous_test_success? or self.class.need_to_run?(@test) end private def previous_test_success? File.exist?(passed_file) end def result_dir components = [ ".test-result", escape_class_name(@test.class.name || "AnonymousTestCase"), escaped_method_name, ] parent_directories = [File.dirname($0), Dir.pwd] if Process.respond_to?(:uid) parent_directories << File.join(Dir.tmpdir, Process.uid.to_s) end parent_directories.each do |parent_directory| dir = File.expand_path(File.join(parent_directory, *components)) begin FileUtils.mkdir_p(dir) return dir rescue Errno::EACCES end end raise Errno::EACCES, parent_directories.join(", ") end def passed_file File.join(result_dir, "passed") end def escape_class_name(class_name) escape_name(class_name) end def escaped_method_name escape_name(@test.method_name.to_s) end def escape_name(name) name.gsub(/(?:[: \/!?=])/) do |matched| case matched when ":" "_colon_" when " ", "/" "_" when "!" ".destructive" when "?" ".predicate" when "=" ".equal" end end end end module ClassMethods def priority(name, *tests) unless Checker.have_priority?(name) raise ArgumentError, "unknown priority: #{name}" end attribute(:priority, name, {:keep => true}, *tests) end end def priority_setup return unless Priority.enabled? Checker.new(self).setup end def priority_teardown return unless Priority.enabled? Checker.new(self).teardown end end end end PK ]R!\c\c.gems/test-unit-3.3.4/lib/test/unit/testcase.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: # * Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # * Copyright (c) 2008-2012 Kouhei Sutou # License:: Ruby license. require 'test/unit/attribute' require 'test/unit/fixture' require 'test/unit/exception-handler' require 'test/unit/assertions' require 'test/unit/failure' require 'test/unit/error' require 'test/unit/pending' require 'test/unit/omission' require 'test/unit/notification' require 'test/unit/priority' require 'test/unit/data' require 'test/unit/testsuite' require 'test/unit/test-suite-creator' require 'test/unit/assertion-failed-error' require 'test/unit/auto-runner-loader' require 'test/unit/util/backtracefilter' require 'test/unit/util/output' require 'test/unit/util/method-owner-finder' module Test module Unit # Ties everything together. If you subclass and add your own # test methods, it takes care of making them into tests and # wrapping those tests into a suite. It also does the # nitty-gritty of actually running an individual test and # collecting its results into a Test::Unit::TestResult object. # # You can run two hooks before/after a TestCase run. # # Example: # # class TestMyClass < Test::Unit::TestCase # class << self # def startup # ... # end # # def shutdown # ... # end # end # # def setup # ... # end # # def cleanup # ... # end # # def teardown # ... # end # # def test_my_method1 # ... # end # # def test_my_method2 # ... # end # end # # Here is a call order: # # 1. startup # 1. setup # 1. test_my_method1 # 1. cleanup # 1. teardown # 1. setup # 1. test_my_method2 # 1. cleanup # 1. teardown # 1. shutdown # # You can set an attribute to each test. # # Example: # # class TestMyClass < Test::Unit::TestCase # attribute :speed, :fast # def test_my_fast_method # # You can get the attribute via `self[]` # self[:speed] # => :fast # ... # end # # attribute :speed, :slow # def test_my_slow_method # self[:speed] # => :slow # ... # end # end class TestCase include Attribute include Fixture include ExceptionHandler include ErrorHandler include FailureHandler include TestCasePendingSupport include TestCaseOmissionSupport include TestCaseNotificationSupport include Priority include Data include Assertions include Util::BacktraceFilter include Util::Output STARTED = name + "::STARTED" # :nodoc: FINISHED = name + "::FINISHED" # :nodoc: STARTED_OBJECT = name + "::STARTED::OBJECT" # :nodoc: FINISHED_OBJECT = name + "::FINISHED::OBJECT" # :nodoc: DESCENDANTS = [] # :nodoc: AVAILABLE_ORDERS = [:alphabetic, :random, :defined] # :nodoc: class << self def inherited(sub_class) # :nodoc: DESCENDANTS << sub_class super end def include(*modules, &block) # :nodoc: super modules.each do |mod| mod.public_instance_methods(false).each do |method_name| AutoRunnerLoader.check(self, method_name.to_s) end end end @@added_method_names = {} def method_added(name) # :nodoc: super added_method_names = (@@added_method_names[self] ||= {}) stringified_name = name.to_s if added_method_names.key?(stringified_name) attribute(:redefined, {:backtrace => caller}, {}, stringified_name) end source_location = find_attribute(stringified_name, :source_location) if source_location path, line = source_location elsif respond_to?(:caller_locations, true) location = caller_locations(1, 1)[0] path = location.absolute_path || location.path line = location.lineno else # TODO: Remove me when Ruby 1.9 support is dropped path, line, = caller[0].split(/:(\d+)/, 2) line = line.to_i if line end location = { :method_name => stringified_name, :path => File.expand_path(path), :line => line, } add_method_location(location) added_method_names[stringified_name] = true AutoRunnerLoader.check(self, stringified_name) end def added_method_names # :nodoc: (@@added_method_names[self] ||= {}).keys end # Rolls up all of the test* methods in the fixture into # one suite, creating a new instance of the fixture for # each method. def suite suite_creator = TestSuiteCreator.new(self) suite_creator.create end # Called before every test case runs. Can be used # to set up fixture information used in test case # scope. # # Here is an example test case: # # class TestMyClass < Test::Unit::TestCase # class << self # def startup # ... # end # end # # def setup # ... # end # # def test_my_class1 # ... # end # # def test_my_class2 # ... # end # end # # Here is a call order: # # * startup # * setup # * test_my_class1 (or test_my_class2) # * setup # * test_my_class2 (or test_my_class1) # # Note that you should not assume test order. Tests # should be worked in any order. def startup end # Called after every test case runs. Can be used to tear # down fixture information used in test case scope. # # Here is an example test case: # # class TestMyClass < Test::Unit::TestCase # class << self # def shutdown # ... # end # end # # def teardown # ... # end # # def test_my_class1 # ... # end # # def test_my_class2 # ... # end # end # # Here is a call order: # # * test_my_class1 (or test_my_class2) # * teardown # * test_my_class2 (or test_my_class1) # * teardown # * shutdown # # Note that you should not assume test order. Tests # should be worked in any order. def shutdown end @@test_orders = {} # Returns the current test order. This returns # `:alphabetic` by default. def test_order ancestors.each do |ancestor| order = @@test_orders[ancestor] return order if order end AVAILABLE_ORDERS.first end # Sets the current test order. # # Here are the available _order_: # # :alphabetic # : Default. Tests are sorted in alphabetic order. # # :random # : Tests are sorted in random order. # # :defined # : Tests are sorted in defined order. def test_order=(order) @@test_orders[self] = order end # Defines a test in declarative syntax or marks # following method as a test method. # # In declarative syntax usage, the following two # test definitions are the almost same: # # description "register user" # def test_register_user # ... # end # # test "register user" do # ... # end # # In test method mark usage, the "my_test_method" is # treated as a test method: # # test # def my_test_method # assert_equal("call me", ...) # end def test(*test_description_or_targets, &block) if block_given? test_description = test_description_or_targets.first if test_description.nil? raise ArgumentError, "test description is missing" end n_arguments = test_description_or_targets.size if n_arguments > 1 message = "wrong number of arguments (#{n_arguments} for 1)" raise ArgumentError, message end method_name = "test: #{test_description}" description(test_description, method_name) attribute(:test, true, {}, method_name) if block.respond_to?(:source_location) attribute(:source_location, block.source_location, {}, method_name) end define_method(method_name, &block) else targets = test_description_or_targets attribute(:test, true, {}, *targets) targets.each do |target| AutoRunnerLoader.check(self, target) end end end # Describes a test. # # The following example associates "register a # normal user" description with "test_register" # test. # # description "register a normal user" # def test_register # ... # end def description(value, target=nil) targets = [target].compact attribute(:description, value, {}, *targets) end # Defines a sub test case. # # This is a syntax sugar. The both of the following codes are # the same in meaning: # # Standard: # # class TestParent < Test::Unit::TestCase # class TestChild < self # def test_in_child # end # end # end # # Syntax sugar: # # class TestParent < Test::Unit::TestCase # sub_test_case("TestChild") do # def test_in_child # end # end # end # # The difference of them are the following: # # * Test case created by {sub_test_case} is an anonymous class. # So you can't refer the test case by name. # * The class name of class style must follow # constant naming rule in Ruby. But the name of test case # created by {sub_test_case} doesn't need to follow the rule. # For example, you can use a space in name such as "child test". # # @param name [String] The name of newly created sub test case. # @yield # The block is evaluated under the newly created sub test # case class context. # @return [Test::Unit::TestCase] Created sub test case class. def sub_test_case(name, &block) parent_test_case = self sub_test_case = Class.new(self) do singleton_class = class << self; self; end singleton_class.__send__(:define_method, :name) do [parent_test_case.name, name].compact.join("::") end end sub_test_case.class_eval(&block) sub_test_case end # Checks whether a test that is matched the query is # defined. # # @option query [String] :path (nil) # the path where a test is defined in. # @option query [Numeric] :line (nil) # the line number where a test is defined at. # @option query [String] :method_name (nil) # the method name for a test. def test_defined?(query) locations = find_locations(query) not locations.empty? end def find_locations(query) query_path = query[:path] query_line = query[:line] query_method_name = query[:method_name] available_locations = target_method_locations(query_path) if query_line available_locations = available_locations.sort_by do |location| -location[:line] end available_location = available_locations.find do |location| query_line >= location[:line] end return [] if available_location.nil? return [] if available_location[:test_case] != self available_locations = [available_location] end if query_method_name available_location = available_locations.find do |location| location[:test_case] == self and query_method_name == location[:method_name] end return [] if available_location.nil? available_locations = [available_location] end available_locations end private # @private @@method_locations = {} # @private @@method_location_mutex = Mutex.new # @private def method_locations @@method_locations[self] ||= [] end # @private def add_method_location(location) @@method_location_mutex.synchronize do method_locations << location end end # @private def target_method_locations(path) @@method_location_mutex.synchronize do if path.nil? self_location = method_locations.first path = self_location[:path] if self_location end return [] if path.nil? target_locations = [] @@method_locations.each do |test_case, locations| locations.each do |location| absolete_path = File.expand_path(path) location_path = location[:path] location_basename = File.basename(location_path) if location_path == absolete_path or location_basename == path target_locations << location.merge(:test_case => test_case) end end end target_locations end end end attr_reader :method_name # Creates a new instance of the fixture for running the # test represented by test_method_name. def initialize(test_method_name) @method_name = test_method_name @internal_data = InternalData.new end # Assigns test data to the test. It is used in internal. def assign_test_data(label, data) # :nodoc: @internal_data.assign_test_data(label, data) end # Returns the test is valid test. It is used in internal. def valid? # :nodoc: return false unless respond_to?(@method_name) test_method = method(@method_name) unless @internal_data.have_test_data? return false unless test_method.arity <= 0 end owner = Util::MethodOwnerFinder.find(self, @method_name) if owner.class != Module and self.class != owner return false end true end # Runs the individual test method represented by this # instance of the fixture, collecting statistics, failures # and errors in result. def run(result) begin @_result = result @internal_data.test_started yield(STARTED, name) yield(STARTED_OBJECT, self) processed_exception_in_setup = false begin catch do |tag| run_setup do begin run_test run_cleanup add_pass rescue Exception @internal_data.interrupted unless handle_exception($!) processed_exception_in_setup = true raise end throw(tag) end end end rescue Exception if processed_exception_in_setup raise else @internal_data.interrupted raise unless handle_exception($!) end ensure begin run_teardown rescue Exception raise unless handle_exception($!) end end @internal_data.test_finished result.add_run yield(FINISHED, name) yield(FINISHED_OBJECT, self) ensure # @_result = nil # For test-spec's after_all :< end end # Called before every test method runs. Can be used # to set up fixture information. # # You can add additional setup tasks by the following # code: # # class TestMyClass < Test::Unit::TestCase # def setup # ... # end # # setup # def my_setup1 # ... # end # # setup do # ... # setup callback1 # end # # setup # def my_setup2 # ... # end # # setup do # ... # setup callback2 # end # # def test_my_class # ... # end # end # # Here is a call order: # # * setup # * my_setup1 # * setup callback1 # * my_setup2 # * setup callback2 # * test_my_class def setup end # Called after every test method runs but the test # method isn't marked as 'passed'. Can be used to # clean up and/or verify tested condition. # e.g. Can be used to verify mock. # # You can add additional cleanup tasks by the following # code: # # class TestMyClass < Test::Unit::TestCase # def cleanup # ... # end # # cleanup # def my_cleanup1 # ... # end # # cleanup do # ... # cleanup callback1 # end # # cleanup # def my_cleanup2 # ... # end # # cleanup do # ... # cleanup callback2 # end # # def test_my_class # ... # end # end # # Here is a call order: # # * test_my_class # * cleanup callback2 # * my_cleanup2 # * cleanup callback1 # * my_cleanup1 # * cleanup def cleanup end # Called after every test method runs. Can be used to tear # down fixture information. # # You can add additional teardown tasks by the following # code: # # class TestMyClass < Test::Unit::TestCase # def teardown # ... # end # # teardown # def my_teardown1 # ... # end # # teardown do # ... # teardown callback1 # end # # teardown # def my_teardown2 # ... # end # # teardown do # ... # teardown callback2 # end # # def test_my_class # ... # end # end # # Here is a call order: # # * test_my_class # * teardown callback2 # * my_teardown2 # * teardown callback1 # * my_teardown1 # * teardown def teardown end def default_test flunk("No tests were specified") end def size 1 end # Returns a label of test data for the test. If the # test isn't associated with any test data, it returns # `nil`. def data_label @internal_data.test_data_label end # Returns test data for the test. If the test isn't associated # with any test data, it returns `nil`. def data @internal_data.test_data end # Returns a human-readable name for the specific test that # this instance of TestCase represents. def name "#{local_name}(#{self.class.name})" end # Returns a human-readable name for the specific test that this # instance of TestCase represents. # # `#local_name` doesn't include class name. `#name` includes # class name. def local_name if @internal_data.have_test_data? "#{@method_name}[#{data_label}]" else @method_name.to_s end end # Returns a description for the test. A description # will be associated by Test::Unit::TestCase.test or # Test::Unit::TestCase.description. # # Returns a name for the test for no description test. def description self[:description] || name end # Overridden to return #name. def to_s name end # It's handy to be able to compare TestCase instances. def ==(other) return false unless other.kind_of?(self.class) return false unless @method_name == other.method_name return false unless data_label == other.data_label self.class == other.class end # Returns a Time at the test was started. def start_time @internal_data.start_time end # Returns elapsed time for the test was ran. def elapsed_time @internal_data.elapsed_time end # Returns whether the test is interrupted. def interrupted? @internal_data.interrupted? end # Returns whether this individual test passed or # not. Primarily for use in teardown so that artifacts # can be left behind if the test fails. def passed? @internal_data.passed? end # Notify that a problem is occurred in the test. It means that # the test is a failed test. If any failed tests exist in test # suites, the test process exits with failure exit status. # # This is a public API for developers who extend test-unit. # # @return [void] def problem_occurred @internal_data.problem_occurred end # Notify that the test is passed. Normally, it is not needed # because #run calls it automatically. If you want to override # #run, it is not a good idea. Please contact test-unit # developers. We will help you without your custom #run. For # example, we may add a new hook in #run. # # This is a public API for developers who extend test-unit. # # @return [void] def add_pass current_result.add_pass end private def current_result @_result end def run_test signature = "#{self.class}\##{@method_name}" redefined_info = self[:redefined] if redefined_info notify("<#{signature}> was redefined", :backtrace => redefined_info[:backtrace]) end if @internal_data.have_test_data? test_method = method(@method_name) arity = test_method.arity if arity.zero? __send__(@method_name) else __send__(@method_name, @internal_data.test_data) end else __send__(@method_name) end end def handle_exception(exception) self.class.exception_handlers.each do |handler| if handler.respond_to?(:call) handled = handler.call(self, exception) else handled = __send__(handler, exception) end return true if handled end false end def add_assertion current_result.add_assertion end class InternalData attr_reader :start_time, :elapsed_time attr_reader :test_data_label, :test_data def initialize @start_time = nil @elapsed_time = nil @passed = true @interrupted = false @test_data_label = nil @test_data = nil end def passed? @passed end def interrupted? @interrupted end def assign_test_data(label, data) @test_data_label = label @test_data = data end def have_test_data? not @test_data_label.nil? end def test_started @start_time = Time.now end def test_finished @elapsed_time = Time.now - @start_time end def problem_occurred @passed = false end def interrupted @interrupted = true end end end end end PK ]<gems/test-unit-3.3.4/lib/test/unit/assertion-failed-error.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # Thrown by Test::Unit::Assertions when an assertion fails. class AssertionFailedError < StandardError attr_accessor :expected, :actual, :user_message attr_accessor :inspected_expected, :inspected_actual def initialize(message=nil, options=nil) options ||= {} @expected = options[:expected] @actual = options[:actual] @inspected_expected = options[:inspected_expected] @inspected_actual = options[:inspected_actual] @user_message = options[:user_message] super(message) end end end end PK ]\c3x x 2gems/test-unit-3.3.4/lib/test/unit/notification.rbnu[require 'test/unit/util/backtracefilter' module Test module Unit class Notification include Util::BacktraceFilter attr_reader :test_name, :location, :message attr_reader :method_name SINGLE_CHARACTER = 'N' LABEL = "Notification" # Creates a new Notification with the given location and # message. def initialize(test_name, location, message, options={}) @test_name = test_name @location = location @message = message @method_name = options[:method_name] end # Returns a single character representation of a notification. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns a brief version of the error description. def short_display "#{@test_name}: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace = filter_backtrace(location).join("\n") "#{label}: #{@message}\n#{@test_name}\n#{backtrace}" end # Overridden to return long_display. def to_s long_display end def critical? false end end class NotifiedError < StandardError end module TestCaseNotificationSupport class << self def included(base) base.class_eval do include NotificationHandler end end end # Notify some information. # # Example: # # def test_notification # notify("I'm here!") # # Reached here # notify("Special!") if special_case? # # Reached here too # end # # options: # # :backtrace override backtrace. def notify(message, options={}, &block) backtrace = filter_backtrace(options[:backtrace] || caller) notification = Notification.new(name, backtrace, message, :method_name => @method_name) add_notification(notification) end private def add_notification(notification) current_result.add_notification(notification) end end module NotificationHandler class << self def included(base) base.exception_handler(:handle_notified_error) end end private def handle_notified_error(exception) return false unless exception.is_a?(NotifiedError) notification = Notification.new(name, filter_backtrace(exception.backtrace), exception.message) add_notification(notification) true end end module TestResultNotificationSupport attr_reader :notifications # Records a Test::Unit::Notification. def add_notification(notification) @notifications << notification notify_fault(notification) notify_changed end # Returns the number of notifications this TestResult has # recorded. def notification_count @notifications.size end private def initialize_containers super @notifications = [] @summary_generators << :notification_summary end def notification_summary "#{notification_count} notifications" end end end end PK ](::-gems/test-unit-3.3.4/lib/test/unit/version.rbnu[module Test module Unit VERSION = "3.3.4" end end PK ]FJ:AA0gems/test-unit-3.3.4/lib/test/unit/autorunner.rbnu[require "English" require "test/unit/color-scheme" require "test/unit/priority" require "test/unit/attribute-matcher" require "test/unit/testcase" require "optparse" module Test module Unit class AutoRunner RUNNERS = {} COLLECTORS = {} ADDITIONAL_OPTIONS = [] PREPARE_HOOKS = [] class << self def register_runner(id, runner_builder=nil, &block) runner_builder ||= Proc.new(&block) RUNNERS[id] = runner_builder RUNNERS[id.to_s] = runner_builder end def runner(id) RUNNERS[id.to_s] end @@default_runner = nil def default_runner runner(@@default_runner) end def default_runner=(id) @@default_runner = id end def register_collector(id, collector_builder=nil, &block) collector_builder ||= Proc.new(&block) COLLECTORS[id] = collector_builder COLLECTORS[id.to_s] = collector_builder end def collector(id) COLLECTORS[id.to_s] end def register_color_scheme(id, scheme) ColorScheme[id] = scheme end def setup_option(option_builder=nil, &block) option_builder ||= Proc.new(&block) ADDITIONAL_OPTIONS << option_builder end def prepare(hook=nil, &block) hook ||= Proc.new(&block) PREPARE_HOOKS << hook end def run(force_standalone=false, default_dir=nil, argv=ARGV, &block) r = new(force_standalone || standalone?, &block) r.base = default_dir r.prepare r.process_args(argv) r.run end def standalone? return false unless("-e" == $0) ObjectSpace.each_object(Class) do |klass| return false if(klass < TestCase) end true end @@need_auto_run = true def need_auto_run? @@need_auto_run end def need_auto_run=(need) @@need_auto_run = need end end register_collector(:descendant) do |auto_runner| require "test/unit/collector/descendant" collector = Collector::Descendant.new collector.filter = auto_runner.filters collector.collect($0.sub(/\.rb\Z/, "")) end register_collector(:load) do |auto_runner| require "test/unit/collector/load" collector = Collector::Load.new unless auto_runner.pattern.empty? collector.patterns.replace(auto_runner.pattern) end unless auto_runner.exclude.empty? collector.excludes.replace(auto_runner.exclude) end collector.base = auto_runner.base collector.default_test_paths = auto_runner.default_test_paths collector.filter = auto_runner.filters collector.collect(*auto_runner.to_run) end # JUST TEST! # register_collector(:xml) do |auto_runner| # require "test/unit/collector/xml" # collector = Collector::XML.new # collector.filter = auto_runner.filters # collector.collect(auto_runner.to_run[0]) # end # deprecated register_collector(:object_space) do |auto_runner| require "test/unit/collector/objectspace" c = Collector::ObjectSpace.new c.filter = auto_runner.filters c.collect($0.sub(/\.rb\Z/, "")) end # deprecated register_collector(:dir) do |auto_runner| require "test/unit/collector/dir" c = Collector::Dir.new c.filter = auto_runner.filters unless auto_runner.pattern.empty? c.pattern.replace(auto_runner.pattern) end unless auto_runner.exclude.empty? c.exclude.replace(auto_runner.exclude) end c.base = auto_runner.base $:.push(auto_runner.base) if auto_runner.base c.collect(*(auto_runner.to_run.empty? ? ["."] : auto_runner.to_run)) end attr_reader :suite, :runner_options attr_accessor :filters, :to_run attr_accessor :default_test_paths attr_accessor :pattern, :exclude, :base, :workdir attr_accessor :color_scheme, :listeners attr_writer :stop_on_failure attr_writer :runner, :collector def initialize(standalone) @standalone = standalone @runner = default_runner @collector = default_collector @filters = [] @to_run = [] @default_test_paths = [] @color_scheme = ColorScheme.default @runner_options = {} @default_arguments = [] @workdir = nil @listeners = [] @stop_on_failure = false config_file = "test-unit.yml" if File.exist?(config_file) load_config(config_file) else load_global_config end yield(self) if block_given? end def stop_on_failure? @stop_on_failure end def prepare PREPARE_HOOKS.each do |handler| handler.call(self) end end def process_args(args=ARGV) begin args.unshift(*@default_arguments) options.order!(args) {|arg| add_test_path(arg)} rescue OptionParser::ParseError => e puts e puts options exit(false) end not @to_run.empty? end def options @options ||= OptionParser.new do |o| o.banner = "Test::Unit automatic runner." o.banner += "\nUsage: #{$0} [options] [-- untouched arguments]" o.on("-r", "--runner=RUNNER", RUNNERS, "Use the given RUNNER.", "(" + keyword_display(RUNNERS) + ")") do |r| @runner = r end o.on("--collector=COLLECTOR", COLLECTORS, "Use the given COLLECTOR.", "(" + keyword_display(COLLECTORS) + ")") do |collector| @collector = collector end if (@standalone) o.on("-b", "--basedir=DIR", "Base directory of test suites.") do |b| @base = b end o.on("-w", "--workdir=DIR", "Working directory to run tests.") do |w| @workdir = w end o.on("--default-test-path=PATH", "Add PATH to the default test paths.", "The PATH is used when user doesn't specify any test path.", "You can specify this option multiple times.") do |path| @default_test_paths << path end o.on("-a", "--add=TORUN", Array, "Add TORUN to the list of things to run;", "can be a file or a directory.") do |paths| paths.each do |path| add_test_path(path) end end @pattern = [] o.on("-p", "--pattern=PATTERN", Regexp, "Match files to collect against PATTERN.") do |e| @pattern << e end @exclude = [] o.on("-x", "--exclude=PATTERN", Regexp, "Ignore files to collect against PATTERN.") do |e| @exclude << e end end o.on("-n", "--name=NAME", String, "Runs tests matching NAME.", "Use '/PATTERN/' for NAME to use regular expression.") do |name| name = (%r{\A/(.*)/\Z} =~ name ? Regexp.new($1) : name) @filters << lambda do |test| return true if name === test.method_name return true if name === test.local_name false end end o.on("--ignore-name=NAME", String, "Ignores tests matching NAME.", "Use '/PATTERN/' for NAME to use regular expression.") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) case n when Regexp @filters << proc {|t| n =~ t.method_name ? false : true} else @filters << proc {|t| n != t.method_name} end end o.on("-t", "--testcase=TESTCASE", String, "Runs tests in TestCases matching TESTCASE.", "Use '/PATTERN/' for TESTCASE to use regular expression.") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) @filters << lambda do |test| match_test_case_name(test, n) end end o.on("--ignore-testcase=TESTCASE", String, "Ignores tests in TestCases matching TESTCASE.", "Use '/PATTERN/' for TESTCASE to use regular expression.") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) @filters << lambda do |test| not match_test_case_name(test, n) end end o.on("--location=LOCATION", String, "Runs tests that defined in LOCATION.", "LOCATION is one of PATH:LINE, PATH or LINE") do |location| if /\A\d+\z/ =~ location path = nil line = location.to_i else path, line, = location.split(/:(\d+)/, 2) line = line.to_i unless line.nil? end add_location_filter(path, line) end o.on("--attribute=EXPRESSION", String, "Runs tests that matches EXPRESSION.", "EXPRESSION is evaluated as Ruby's expression.", "Test attribute name can be used with no receiver in EXPRESSION.", "EXPRESSION examples:", " !slow", " tag == 'important' and !slow") do |expression| @filters << lambda do |test| matcher = AttributeMatcher.new(test) matcher.match?(expression) end end priority_filter = Proc.new do |test| if @filters == [priority_filter] Priority::Checker.new(test).need_to_run? else nil end end o.on("--[no-]priority-mode", "Runs some tests based on their priority.") do |priority_mode| if priority_mode Priority.enable @filters |= [priority_filter] else Priority.disable @filters -= [priority_filter] end end o.on("--default-priority=PRIORITY", Priority.available_values, "Uses PRIORITY as default priority", "(#{keyword_display(Priority.available_values)})") do |priority| Priority.default = priority end o.on("-I", "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]", "Appends directory list to $LOAD_PATH.") do |dirs| $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR)) end color_schemes = ColorScheme.all o.on("--color-scheme=SCHEME", color_schemes, "Use SCHEME as color scheme.", "(#{keyword_display(color_schemes)})") do |scheme| @color_scheme = scheme end o.on("--config=FILE", "Use YAML fomat FILE content as configuration file.") do |file| load_config(file) end o.on("--order=ORDER", TestCase::AVAILABLE_ORDERS, "Run tests in a test case in ORDER order.", "(#{keyword_display(TestCase::AVAILABLE_ORDERS)})") do |order| TestCase.test_order = order end assertion_message_class = Test::Unit::Assertions::AssertionMessage o.on("--max-diff-target-string-size=SIZE", Integer, "Shows diff if both expected result string size and " + "actual result string size are " + "less than or equal SIZE in bytes.", "(#{assertion_message_class.max_diff_target_string_size})") do |size| assertion_message_class.max_diff_target_string_size = size end o.on("--[no-]stop-on-failure", "Stops immediately on the first non success test", "(#{@stop_on_failure})") do |boolean| @stop_on_failure = boolean end ADDITIONAL_OPTIONS.each do |option_builder| option_builder.call(self, o) end o.on("--", "Stop processing options so that the", "remaining options will be passed to the", "test."){o.terminate} o.on("-h", "--help", "Display this help."){puts o; exit} o.on_tail o.on_tail("Deprecated options:") o.on_tail("--console", "Console runner (use --runner).") do warn("Deprecated option (--console).") @runner = self.class.runner(:console) end if RUNNERS[:fox] o.on_tail("--fox", "Fox runner (use --runner).") do warn("Deprecated option (--fox).") @runner = self.class.runner(:fox) end end o.on_tail end end def keyword_display(keywords) keywords = keywords.collect do |keyword, _| keyword.to_s end.uniq.sort i = 0 keywords.collect do |keyword| if (i > 0 and keyword[0] == keywords[i - 1][0]) or ((i < keywords.size - 1) and (keyword[0] == keywords[i + 1][0])) n = 2 else n = 1 end i += 1 keyword.sub(/^(.{#{n}})([A-Za-z]+)(?=\w*$)/, '\\1[\\2]') end.join(", ") end def run self.class.need_auto_run = false suite = @collector[self] return false if suite.nil? return true if suite.empty? runner = @runner[self] return false if runner.nil? @runner_options[:color_scheme] ||= @color_scheme @runner_options[:listeners] ||= [] @runner_options[:listeners].concat(@listeners) if @stop_on_failure @runner_options[:listeners] << StopOnFailureListener.new end change_work_directory do runner.run(suite, @runner_options).passed? end end def load_config(file) require "yaml" config = YAML.load(File.read(file)) runner_name = config["runner"] @runner = self.class.runner(runner_name) || @runner @collector = self.class.collector(config["collector"]) || @collector (config["color_schemes"] || {}).each do |name, options| ColorScheme[name] = options end runner_options = {} (config["#{runner_name}_options"] || {}).each do |key, value| key = key.to_sym value = ColorScheme[value] if key == :color_scheme if key == :arguments @default_arguments.concat(value.split) else runner_options[key.to_sym] = value end end @runner_options = @runner_options.merge(runner_options) end private def default_runner runner = self.class.default_runner if ENV["EMACS"] == "t" runner ||= self.class.runner(:emacs) else runner ||= self.class.runner(:console) end runner end def default_collector self.class.collector(@standalone ? :load : :descendant) end def global_config_file File.expand_path("~/.test-unit.yml") rescue ArgumentError nil end def load_global_config file = global_config_file load_config(file) if file and File.exist?(file) end def change_work_directory(&block) if @workdir Dir.chdir(@workdir, &block) else yield end end def match_test_case_name(test, pattern) test.class.ancestors.each do |test_class| break if test_class == TestCase return true if pattern === test_class.name end false end def add_test_path(path) if /:(\d+)\z/ =~ path line = $1.to_i path = $PREMATCH add_location_filter(path, line) end @to_run << path end def add_location_filter(path, line) @filters << lambda do |test| test.class.test_defined?(:path => path, :line => line, :method_name => test.method_name) end end class StopOnFailureListener def attach_to_mediator(mediator) mediator.add_listener(TestResult::FINISHED) do |result| result.stop unless result.passed? end end end end end end require "test/unit/runner/console" require "test/unit/runner/emacs" require "test/unit/runner/xml" PK ]n$$-gems/test-unit-3.3.4/lib/test/unit/fixture.rbnu[module Test module Unit module Fixture class << self def included(base) base.extend(ClassMethods) [:setup, :cleanup, :teardown].each do |type| observer = lambda do |test_case, _, _, value, callback| if value.nil? test_case.fixture[type].unregister(callback) else test_case.fixture[type].register(callback, value) end end base.register_attribute_observer(type, &observer) end end end class Fixture attr_reader :setup attr_reader :cleanup attr_reader :teardown def initialize(test_case) @test_case = test_case @setup = HookPoint.new(@test_case, :setup, :after => :append) @cleanup = HookPoint.new(@test_case, :cleanup, :before => :prepend) @teardown = HookPoint.new(@test_case, :teardown, :before => :prepend) @cached_before_callbacks = {} @cached_after_callbacks = {} end def [](type) case type when :setup @setup when :cleanup @cleanup when :teardown @teardown end end def before_callbacks(type) @cached_before_callbacks[type] ||= collect_before_callbacks(type) end def after_callbacks(type) @cached_after_callbacks[type] ||= collect_after_callbacks(type) end private def target_test_cases @cached_target_test_cases ||= collect_target_test_cases end def collect_before_callbacks(type) prepend_callbacks = [] append_callbacks = [] target_test_cases.each do |ancestor| prepend_callbacks << ancestor.fixture[type].before_prepend_callbacks append_callbacks << ancestor.fixture[type].before_append_callbacks end merge_callbacks(prepend_callbacks, append_callbacks) end def collect_after_callbacks(type) prepend_callbacks = [] append_callbacks = [] target_test_cases.each do |ancestor| prepend_callbacks << ancestor.fixture[type].after_prepend_callbacks append_callbacks << ancestor.fixture[type].after_append_callbacks end merge_callbacks(prepend_callbacks, append_callbacks) end def collect_target_test_cases ancestors = @test_case.ancestors base_index = ancestors.index(::Test::Unit::Fixture) interested_ancestors = ancestors[0, base_index].find_all do |ancestor| ancestor.is_a?(Class) end interested_ancestors.reverse end def merge_callbacks(prepend_callbacks, append_callbacks) all_callbacks = [] prepend_callbacks.reverse_each do |callbacks| all_callbacks.concat(callbacks) end append_callbacks.each do |callbacks| all_callbacks.concat(callbacks) end all_callbacks end end class HookPoint def initialize(test_case, type, default_options) @test_case = test_case @type = type @default_options = default_options @before_prepend_callbacks = [] @before_append_callbacks = [] @after_prepend_callbacks = [] @after_append_callbacks = [] @unregistered_callbacks = [] end def register(method_name_or_callback, options=nil) options ||= {} unless valid_register_options?(options) message = "must be {:before => :prepend}, " + "{:before => :append}, {:after => :prepend} or " + "{:after => :append}: #{options.inspect}" raise ArgumentError, message end if options.empty? options = @default_options end before_how = options[:before] after_how = options[:after] if method_name_or_callback.respond_to?(:call) callback = method_name_or_callback method_name = callback_method_name(callback) @test_case.attribute(:source_location, callback.source_location, method_name) @test_case.__send__(:define_method, method_name, &callback) else method_name = method_name_or_callback end add_callback(method_name, before_how, after_how) end def unregister(method_name_or_callback) if method_name_or_callback.respond_to?(:call) callback = method_name_or_callback method_name = callback_method_name(callback) else method_name = method_name_or_callback end @unregistered_callbacks << method_name end def before_prepend_callbacks @before_prepend_callbacks - @unregistered_callbacks end def before_append_callbacks @before_append_callbacks - @unregistered_callbacks end def after_prepend_callbacks @after_prepend_callbacks - @unregistered_callbacks end def after_append_callbacks @after_append_callbacks - @unregistered_callbacks end private def valid_register_options?(options) return true if options.empty? return false if options.size > 1 key = options.keys.first [:before, :after].include?(key) and [:prepend, :append].include?(options[key]) end def callback_method_name(callback) "#{@type}_#{callback.object_id}" end def add_callback(method_name_or_callback, before_how, after_how) case before_how when :prepend @before_prepend_callbacks = [method_name_or_callback] | @before_prepend_callbacks when :append @before_append_callbacks |= [method_name_or_callback] else case after_how when :prepend @after_prepend_callbacks = [method_name_or_callback] | @after_prepend_callbacks when :append @after_append_callbacks |= [method_name_or_callback] end end end end module ClassMethods def fixture @fixture ||= Fixture.new(self) end def setup(*method_names, &callback) register_fixture(:setup, *method_names, &callback) end def unregister_setup(*method_names_or_callbacks) unregister_fixture(:setup, *method_names_or_callbacks) end def cleanup(*method_names, &callback) register_fixture(:cleanup, *method_names, &callback) end def unregister_cleanup(*method_names_or_callbacks) unregister_fixture(:cleanup, *method_names_or_callbacks) end def teardown(*method_names, &callback) register_fixture(:teardown, *method_names, &callback) end def unregister_teardown(*method_names_or_callbacks) unregister_fixture(:teardown, *method_names_or_callbacks) end private def register_fixture(fixture, *method_names, &callback) options = {} options = method_names.pop if method_names.last.is_a?(Hash) callbacks = method_names callbacks << callback if callback attribute(fixture, options, *callbacks) end def unregister_fixture(fixture, *method_names_or_callbacks) attribute(fixture, nil, *method_names_or_callbacks) end end private def run_fixture(type, options={}, &block) fixtures = [ self.class.fixture.before_callbacks(type), type, self.class.fixture.after_callbacks(type), ].flatten if block runner = create_fixtures_runner(fixtures, options, &block) runner.call else fixtures.each do |method_name| run_fixture_callback(method_name, options) end end end def create_fixtures_runner(fixtures, options, &block) if fixtures.empty? block else last_fixture = fixtures.pop create_fixtures_runner(fixtures, options) do block_is_called = false run_fixture_callback(last_fixture, options) do block_is_called = true block.call end block.call unless block_is_called end end end def run_fixture_callback(method_name, options, &block) return unless respond_to?(method_name, true) begin __send__(method_name, &block) rescue Exception raise unless options[:handle_exception] raise unless handle_exception($!) end end def run_setup(&block) run_fixture(:setup, &block) end def run_cleanup run_fixture(:cleanup) end def run_teardown run_fixture(:teardown, :handle_exception => true) end end end end PK ]l 4gems/test-unit-3.3.4/lib/test/unit/runner/console.rbnu[# Copyright (C) 2008-2017 Kouhei Sutou # # License: Ruby OR LGPL-2.1+ # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA module Test module Unit AutoRunner.register_runner(:console) do |auto_runner| require 'test/unit/ui/console/testrunner' Test::Unit::UI::Console::TestRunner end AutoRunner.setup_option do |auto_runner, opts| require 'test/unit/ui/console/outputlevel' output_levels = [ ["silent", UI::Console::OutputLevel::SILENT], ["progress", UI::Console::OutputLevel::PROGRESS_ONLY], ["important-only", UI::Console::OutputLevel::IMPORTANT_FAULTS_ONLY], ["normal", UI::Console::OutputLevel::NORMAL], ["verbose", UI::Console::OutputLevel::VERBOSE], ] opts.on('-v', '--verbose=[LEVEL]', output_levels, "Set the output level (default is verbose).", "(#{auto_runner.keyword_display(output_levels)})") do |level| level ||= output_levels.assoc("verbose")[1] auto_runner.runner_options[:output_level] = level end use_color_options = [ [:auto, :auto], ["-", false], ["no", false], ["false", false], ["+", true], ["yes", true], ["true", true], ] opts.on("--[no-]use-color=[auto]", use_color_options, "Uses color output", "(default is auto)") do |use_color| case use_color when nil use_color = true when :auto use_color = nil end auto_runner.runner_options[:use_color] = use_color end opts.on("--progress-row-max=MAX", Integer, "Uses MAX as max terminal width for progress mark", "(default is auto)") do |max| auto_runner.runner_options[:progress_row_max] = max end opts.on("--no-show-detail-immediately", "Shows not passed test details immediately.", "(default is yes)") do |boolean| auto_runner.runner_options[:show_detail_immediately] = boolean end opts.on("--[no-]reverse-output", "Shows fault details in reverse.", "(default is yes for tty output, no otherwise)") do |boolean| auto_runner.runner_options[:reverse_output] = boolean end end end end PK ]qo0gems/test-unit-3.3.4/lib/test/unit/runner/xml.rbnu[module Test module Unit AutoRunner.register_runner(:xml) do |auto_runner| require 'test/unit/ui/xml/testrunner' Test::Unit::UI::XML::TestRunner end AutoRunner.setup_option do |auto_runner, opts| opts.on("--output-file-descriptor=FD", Integer, "Outputs to file descriptor FD") do |fd| auto_runner.runner_options[:output_file_descriptor] = fd end end end end PK ]l2gems/test-unit-3.3.4/lib/test/unit/runner/emacs.rbnu[module Test module Unit AutoRunner.register_runner(:emacs) do |auto_runner| require 'test/unit/ui/emacs/testrunner' Test::Unit::UI::Emacs::TestRunner end end end PK ] {:x => 1, :y => "a"} # # => {:x => 1, :y => "b"} # # => {:x => 2, :y => "a"} # # => {:x => 2, :y => "b"} # # => {:x => 3, :y => "a"} # # => {:x => 3, :y => "b"} # end # # Generates test matrix from variable and patterns pairs. # # @overload data(data_set, options={}) # @param [Hash] data_set specify test data as a Hash that # key is test label and value is test data. # @param [Hash] options specify options. # @option options [Boolean] :keep whether or not to use # this data in the following test methods # # @example data(data_set) # data("empty string" => [true, ""], # "plain string" => [false, "hello"]) # def test_empty?(data) # expected, target = data # assert_equal(expected, target.empty?) # end # # @overload data(options={}, &block) # @param [Hash] options specify options. # @option options [Boolean] :keep whether or not to use # this data in the following test methods # @yieldreturn [Hash] return test data set # as a Hash that key is test label and value is test data. # # @example data(&block) # data do # data_set = {} # data_set["empty string"] = [true, ""] # data_set["plain string"] = [false, "hello"] # data_set # end # def test_empty?(data) # expected, target = data # assert_equal(expected, target.empty?) # end # # @overload data(options={}, &block) # @param [Hash] options specify options. # @option options [Boolean] :keep whether or not to use # this data in the following test methods # @yieldreturn [Array] return test data set # as an Array of variable and patterns. # # @example data(&block) # data do # patterns = 3.times.to_a # [:x, patterns] # end # data do # patterns = [] # character = "a" # 2.times.each do # patterns << character # character = character.succ # end # [:y, patterns] # end # def test_patterns(data) # # 3 * 2 times executed # # 3: the number of patterns of :x # # 2: the number of patterns of :y # p data # # => {:x => 0, :y => "a"} # # => {:x => 0, :y => "b"} # # => {:x => 1, :y => "a"} # # => {:x => 1, :y => "b"} # # => {:x => 2, :y => "a"} # # => {:x => 2, :y => "b"} # end # # Generates test matrix from variable and patterns pairs. # def data(*arguments, &block) options = nil n_arguments = arguments.size case n_arguments when 0 raise ArgumentError, "no block is given" unless block_given? data_set = block when 1 if block_given? data_set = block options = arguments[1] else data_set = arguments[0] end when 2 case arguments[0] when String data_set = {arguments[0] => arguments[1]} when Hash data_set = arguments[0] options = arguments[1] else variable = arguments[0] patterns = arguments[1] data_set = [variable, patterns] end when 3 case arguments[0] when String data_set = {arguments[0] => arguments[1]} options = arguments[2] else variable = arguments[0] patterns = arguments[1] data_set = [variable, patterns] options = arguments[2] end else message = "wrong number arguments(#{n_arguments} for 0..3)" raise ArgumentError, message end options ||= {} data_sets = current_attribute(:data)[:value] || DataSets.new data_sets.add(data_set, options) if options[:keep] keep_hook = lambda do |attr| attr.merge(value: attr[:value].keep) end options = options.merge(keep_hook: keep_hook) end attribute(:data, data_sets, options) end # This method provides Data-Driven-Test functionality. # # Load test data from the file. This is shorthand to load # test data from file. If you want to load complex file, you # can use {#data} with block. # # @param [String] file_name full path to test data file. # File format is automatically detected from filename extension. # @raise [ArgumentError] if `file_name` is not supported file format. # @see Loader#load # # @example Load data from CSV file # load_data("/path/to/test-data.csv") # def test_empty?(data) # assert_equal(data["expected"], data["target"].empty?) # end # def load_data(file_name) loader = Loader.new(self) loader.load(file_name) end class Loader # @api private def initialize(test_case) @test_case = test_case end # Load data from file. # # @param [String] file_name full path to test data file. # File format is automatically detected from filename extension. # @raise [ArgumentError] if `file_name` is not supported file format. # @see #load_csv # @see #load_tsv # @api private def load(file_name) case File.extname(file_name).downcase when ".csv" load_csv(file_name) when ".tsv" load_tsv(file_name) else raise ArgumentError, "unsupported file format: <#{file_name}>" end end # Load data from CSV file. # # There are 2 types of CSV file as following examples. # First, there is a header on first row and it's first column is "label". # Another, there is no header in the file. # # @example Load data from CSV file with header # # test-data.csv: # # label,expected,target # # empty string,true,"" # # plain string,false,hello # # # load_data("/path/to/test-data.csv") # def test_empty?(data) # assert_equal(data["expected"], data["target"].empty?) # end # # @example Load data from CSV file without header # # test-data-without-header.csv: # # empty string,true,"" # # plain string,false,hello # # # load_data("/path/to/test-data-without-header.csv") # def test_empty?(data) # expected, target = data # assert_equal(expected, target.empty?) # end # # @api private def load_csv(file_name) require 'csv' first_row = true header = nil CSV.foreach(file_name) do |row| if first_row first_row = false if row.first == "label" header = row[1..-1] next end end set_test_data(header, row) end end # Load data from TSV file. # # There are 2 types of TSV file as following examples. # First, there is a header on first row and it's first column is "label". # Another, there is no header in the file. # # @example Load data from TSV file with header # # test-data.tsv: # # label expected target # # empty string true "" # # plain string false hello # # # load_data("/path/to/test-data.tsv") # def test_empty?(data) # assert_equal(data["expected"], data["target"].empty?) # end # # @example Load data from TSV file without header # # test-data-without-header.tsv: # # empty string true "" # # plain string false hello # # # load_data("/path/to/test-data-without-header.tsv") # def test_empty?(data) # expected, target = data # assert_equal(expected, target.empty?) # end # # @api private def load_tsv(file_name) require "csv" if CSV.const_defined?(:VERSION) first_row = true header = nil CSV.foreach(file_name, :col_sep => "\t") do |row| if first_row first_row = false if row.first == "label" header = row[1..-1] next end end set_test_data(header, row) end else # for old CSV library first_row = true header = nil CSV.open(file_name, "r", "\t") do |row| if first_row first_row = false if row.first == "label" header = row[1..-1] next end end set_test_data(header, row) end end end private def normalize_value(value) return true if value == "true" return false if value == "false" begin Integer(value) rescue ArgumentError begin Float(value) rescue ArgumentError value end end end def set_test_data(header, row) label = row.shift if header data = {} header.each_with_index do |key, i| data[key] = normalize_value(row[i]) end else data = row.collect do |cell| normalize_value(cell) end end @test_case.data(label, data) end end end end end end PK ]z|{{8gems/test-unit-3.3.4/lib/test/unit/auto-runner-loader.rbnu[require "test/unit/test-suite-creator" module Test module Unit module AutoRunnerLoader @loaded = false class << self def check(test_case, method_name) return if @loaded return unless TestSuiteCreator.test_method?(test_case, method_name) require "test/unit" @loaded = true end end end end end PK ]xpp:gems/test-unit-3.3.4/lib/test/unit/collector/descendant.rbnu[require 'test/unit/collector' module Test module Unit module Collector class Descendant include Collector NAME = 'collected from the subclasses of TestCase' def collect(name=NAME) suite = TestSuite.new(name) add_test_cases(suite, TestCase::DESCENDANTS) suite end end end end end PK ]W"DD3gems/test-unit-3.3.4/lib/test/unit/collector/xml.rbnu[#-- # # Author:: Kouhei Sutou # Copyright:: # * Copyright (c) 2011 Kouhei Sutou # License:: Ruby license. # just test!!! don't use it yet!!! require 'test/unit/collector' require 'rexml/document' require 'rexml/streamlistener' module Test module Unit module Collector class XML include Collector def collect(xml_log_path) listener = Listener.new File.open(xml_log_path) do |xml_log| parser = REXML::Parsers::StreamParser.new(xml_log, listener) parser.parse end suite = TestSuite.new("tests in #{xml_log_path}") suites = listener.test_suites sort(suites).each {|s| add_suite(suite, s)} suite end class Listener include REXML::StreamListener attr_reader :test_suites def initialize @ns_stack = [{"xml" => :xml}] @tag_stack = [["", :root]] @text_stack = [''] @state_stack = [:root] @values = {} @test_suites = [] end def tag_start(name, attributes) @text_stack.push('') ns = @ns_stack.last.dup attrs = {} attributes.each do |n, v| if /\Axmlns(?:\z|:)/ =~ n ns[$POSTMATCH] = v else attrs[n] = v end end @ns_stack.push(ns) _parent_tag = parent_tag prefix, local = split_name(name) uri = _ns(ns, prefix) @tag_stack.push([uri, local]) state = next_state(@state_stack.last, uri, local) @state_stack.push(state) @values = {} case state when :test_suite, :test_case # do nothing when :test @n_pass_assertions = 0 if _parent_tag == "start-test" when :backtrace @backtrace = [] @values_backup = @values end end def tag_end(name) state = @state_stack.pop text = @text_stack.pop uri, local = @tag_stack.pop no_action_states = [:root, :stream] case state when *no_action_states # do nothing when :test_suite test_suite_end when :complete_test_case @test_suites.last << @test_case.suite when :test_case test_case_end when :result @result = @values when :test test_end when :pass_assertion @n_pass_assertions += 1 when :backtrace @values = @values_backup @values["backtrace"] = @backtrace when :entry file = @values['file'] line = @values['line'] info = @values['info'] @backtrace << "#{file}:#{line}: #{info}" @values = {} else local = normalize_local(local) @values[local] = text end @ns_stack.pop end def text(data) @text_stack.last << data end private def _ns(ns, prefix) ns.fetch(prefix, "") end NAME_SPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/ def split_name(name) name =~ NAME_SPLIT [$1 || '', $2] end STATE_TABLE = { :root => [:stream], :stream => [:ready_test_suite, :start_test_suite, :ready_test_case, :start_test_case, :start_test, :pass_assertion, :test_result, :complete_test, :complete_test_case, :complete_test_suite, :success], :ready_test_suite => [:n_tests], :start_test_suite => [:test_suite], :ready_test_case => [:test_case, :n_tests], :start_test_case => [:test_case], :start_test => [:test], :pass_assertion => [:test], :complete_test => [:test, :success], :complete_test_case => [:test_case, :elapsed, :success], :complete_test_suite => [:test_suite, :success], :test_suite => [:start_time, :elapsed], :test_case => [:name, :start_time, :elapsed], :test => [:name, :start_time, :elapsed], :test_result => [:test, :result], :result => [:test_case, :test, :status, :backtrace, :detail], :backtrace => [:entry], :entry => [:file, :line, :info], } def next_state(current_state, uri, local) local = normalize_local(local) valid_elements = STATE_TABLE[current_state] if valid_elements.nil? raise "unexpected element: #{current_path}" end next_state = local.to_sym unless valid_elements.include?(next_state) raise "unexpected element: #{current_path}" end next_state end def current_path locals = @tag_stack.collect do |uri, local| local end ["", *locals].join("/") end def normalize_local(local) local.gsub(/-/, "_") end def parent_tag @tag_stack.last[1] end def test_suite_end return unless parent_tag == "start-test-suite" suite = TestSuite.new ["start_time", "elapsed_time", "n_tests"].each do |key| if @values.has_key?(key) suite.instance_variable_set("@#{key}", @values[key]) end end @test_suites << suite end def test_case_end return unless parent_tag == "start-test-case" name = @values["name"] @test_case = Class.new(TestCase) do define_method(:name) do name end end end def test_end return unless parent_tag == "complete-test" name = @values["name"] n_pass_assertions = @n_pass_assertions result = @result @test_case.module_eval do test define_method(name) do n_pass_assertions.times do add_assertion end case result["status"] when "omission" add_omission(Omission.new(name, result["backtrace"], result["detail"])) end end end end end end end end end PK ]> 4gems/test-unit-3.3.4/lib/test/unit/collector/load.rbnu[require 'pathname' require 'test/unit/testsuite' require 'test/unit/collector' module Test module Unit module Collector class Load include Collector attr_reader :patterns, :excludes, :base attr_reader :default_test_paths def initialize super @system_excludes = [/~\z/, /\A\.\#/] @system_directory_excludes = [/\A(?:CVS|\.svn|\.git)\z/] @patterns = [/\Atest[_\-].+\.rb\z/m, /[_\-]test\.rb\z/] @excludes = [] @base = nil @default_test_paths = [] @require_failed_infos = [] end def base=(base) base = Pathname(base) unless base.nil? @base = base end def default_test_paths=(paths) @default_test_paths = paths.collect do |path| Pathname(path) end end def collect(*froms) add_load_path(@base) do froms = @default_test_paths if froms.empty? froms = ["."] if froms.empty? test_suites = [] already_gathered = find_test_cases froms.each do |from| from = resolve_path(from) if from.directory? test_suite = collect_recursive(from, already_gathered) test_suites << test_suite unless test_suite.tests.empty? else collect_file(from, test_suites, already_gathered) end end add_require_failed_test_suite(test_suites) if test_suites.size > 1 test_suite = TestSuite.new("[#{froms.join(', ')}]") sort(test_suites).each do |sub_test_suite| test_suite << sub_test_suite end else test_suite = test_suites.first end test_suite end end def find_test_cases(ignore=[]) test_cases = [] TestCase::DESCENDANTS.each do |test_case| test_cases << test_case unless ignore.include?(test_case) end ignore.concat(test_cases) test_cases end private def collect_recursive(path, already_gathered) sub_test_suites = [] if path.directory? directories, files = path.children.partition do |child| child.directory? end files.each do |child| next if excluded_file?(child.basename.to_s) collect_file(child, sub_test_suites, already_gathered) end directories.each do |child| next if excluded_directory?(child.basename.to_s) sub_test_suite = collect_recursive(child, already_gathered) sub_test_suites << sub_test_suite unless sub_test_suite.empty? end else unless excluded_file?(path.basename.to_s) collect_file(path, sub_test_suites, already_gathered) end end test_suite = TestSuite.new(path.basename.to_s) sort(sub_test_suites).each do |sub_test_suite| test_suite << sub_test_suite end test_suite end def collect_file(path, test_suites, already_gathered) @program_file ||= File.expand_path($0) expanded_path = path.expand_path return if @program_file == expanded_path.to_s add_load_path(expanded_path.dirname) do begin require(expanded_path.to_s) rescue LoadError @require_failed_infos << {:path => expanded_path, :exception => $!} end add_test_cases(test_suites, find_test_cases(already_gathered)) end end def resolve_path(path) if @base @base + path else Pathname(path) end end def add_load_path(path) return yield if path.nil? path = path.to_s begin $LOAD_PATH.unshift(path) yield ensure index = $LOAD_PATH.index(path) $LOAD_PATH.delete_at(index) if index end end def excluded_directory?(base) @system_directory_excludes.any? {|pattern| pattern =~ base} end def excluded_file?(base) return true if @system_excludes.any? {|pattern| pattern =~ base} patterns = @patterns || [] unless patterns.empty? return true unless patterns.any? {|pattern| pattern =~ base} end excludes = @excludes || [] unless excludes.empty? return true if excludes.any? {|pattern| pattern =~ base} end false end def add_require_failed_test_suite(test_suites) return if @require_failed_infos.empty? require_failed_infos = @require_failed_infos require_failed_errors = Class.new(Test::Unit::TestCase) require_failed_errors.class_eval do class << self def name "RequireFailedErrors" end end require_failed_infos.each do |info| path = info[:path] normalized_path = path.to_s.gsub(/[^a-z0-9\_]+/i, '_') normalized_path = normalized_path.gsub(/\A_+/, '') exception = info[:exception] define_method("test_require_#{normalized_path}") do raise(exception.class, "failed to load <#{path}>: #{exception.message}", exception.backtrace) end end def priority 100 end end add_suite(test_suites, require_failed_errors.suite) end end end end end PK ]Q$ 3gems/test-unit-3.3.4/lib/test/unit/collector/dir.rbnu[require 'test/unit/testsuite' require 'test/unit/collector' module Test module Unit module Collector class Dir include Collector attr_reader :pattern, :exclude attr_accessor :base def initialize(dir=::Dir, file=::File, object_space=::ObjectSpace, req=nil) super() @dir = dir @file = file @object_space = object_space @req = req @pattern = [/\btest_.*\.rb\Z/m] @exclude = [] @base = nil end def collect(*from) basedir = @base $:.push(basedir) if basedir if(from.empty?) recursive_collect('.', find_test_cases) elsif(from.size == 1) recursive_collect(from.first, find_test_cases) else suites = [] from.each do |f| suite = recursive_collect(f, find_test_cases) suites << suite unless(suite.tests.empty?) end suite = TestSuite.new("[#{from.join(', ')}]") sort(suites).each{|s| suite << s} suite end ensure $:.delete_at($:.rindex(basedir)) if basedir end def find_test_cases(ignore=[]) cases = [] @object_space.each_object(Class) do |c| cases << c if(c < TestCase && !ignore.include?(c)) end ignore.concat(cases) cases end def recursive_collect(name, already_gathered) sub_suites = [] path = realdir(name) if @file.directory?(path) dir_name = name unless name == '.' @dir.entries(path).each do |e| next if(e == '.' || e == '..') e_name = dir_name ? @file.join(dir_name, e) : e if @file.directory?(realdir(e_name)) next if /\A(?:CVS|\.svn|\.git)\z/ =~ e sub_suite = recursive_collect(e_name, already_gathered) sub_suites << sub_suite unless(sub_suite.empty?) else next if /~\z/ =~ e_name or /\A\.\#/ =~ e if @pattern and !@pattern.empty? next unless @pattern.any? {|pat| pat =~ e_name} end if @exclude and !@exclude.empty? next if @exclude.any? {|pat| pat =~ e_name} end collect_file(e_name, sub_suites, already_gathered) end end else collect_file(name, sub_suites, already_gathered) end suite = TestSuite.new(@file.basename(name)) sort(sub_suites).each{|s| suite << s} suite end def collect_file(name, suites, already_gathered) dir = @file.dirname(@file.expand_path(name, @base)) $:.unshift(dir) if(@req) @req.require(name) else require(name) end find_test_cases(already_gathered).each{|t| add_suite(suites, t.suite)} ensure $:.delete_at($:.rindex(dir)) if(dir) end def realdir(path) if @base @file.join(@base, path) else path end end end end end end PK ]>;gems/test-unit-3.3.4/lib/test/unit/collector/objectspace.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/collector' module Test module Unit module Collector class ObjectSpace include Collector NAME = 'collected from the ObjectSpace' def initialize(source=::ObjectSpace) super() @source = source end def collect(name=NAME) suite = TestSuite.new(name) sub_suites = [] @source.each_object(Class) do |klass| if(Test::Unit::TestCase > klass) add_suite(sub_suites, klass.suite) end end sort(sub_suites).each{|s| suite << s} suite end end end end end PK ]], =gems/test-unit-3.3.4/lib/test/unit/fault-location-detector.rbnu[# Copyright (C) 2012 Kouhei Sutou # # License: Ruby's require "English" module Test module Unit class FaultLocationDetector def initialize(fault, code_snippet_fetcher) @fault = fault @code_snippet_fetcher = code_snippet_fetcher extract_fault_information end def split_backtrace_entry(entry) match_data = /\A(.+):(\d+)(?::(.*))?\z/.match(entry) return nil if match_data.nil? file, line_number, context = match_data.to_a[1..-1] line_number = line_number.to_i if /\Ain `(.+?)'/ =~ context method_name = $1 if /\Ablock (?:\(.+?\) )?in / =~ method_name method_name = $POSTMATCH end else method_name = nil end [file, line_number, context, method_name] end def target?(backtrace_entry) file, line_number, context, method_name = split_backtrace_entry(backtrace_entry) _ = context return false if file.nil? if @fault_source_location target_source_location?(file, line_number, method_name) elsif @fault_method_name target_method?(method_name) else true end end private def target_source_location?(file, line_number, method_name) fault_file, fault_line_number = @fault_source_location return false unless file.end_with?(fault_file) return false if line_number < fault_line_number lines = @code_snippet_fetcher.source(file) return false if lines.nil? base_indent_level = nil fault_line_number.step(lines.size) do |current_line_number| line = lines[current_line_number - 1] current_indent_level = guess_indent_level(line) base_indent_level ||= current_indent_level return true if current_line_number == line_number if current_line_number == fault_line_number break if /(?:\send|\})\s*$/ =~ line else break if current_indent_level == base_indent_level end end false end def target_method?(method_name) @fault_method_name == method_name end def guess_indent_level(line) if /\A(\s*)/ =~ line $1.sub(/\t/, " " * 8).count(" ") else 0 end end def extract_fault_information if @fault.respond_to?(:source_location) @fault_source_location = @fault.source_location else @fault_source_location = nil end if @fault.respond_to?(:method_name) @fault_method_name = @fault.method_name else @fault_method_name = nil end end end end end PK ]j V 7gems/test-unit-3.3.4/lib/test/unit/exception-handler.rbnu[module Test module Unit module ExceptionHandler @@exception_handlers = [] class << self def exception_handlers @@exception_handlers end def included(base) base.extend(ClassMethods) observer = Proc.new do |test_case, _, _, value, method_name| if value @@exception_handlers.unshift(method_name) else @@exception_handlers.delete(method_name) end end base.register_attribute_observer(:exception_handler, &observer) end end module ClassMethods def exception_handlers ExceptionHandler.exception_handlers end # @overload exception_handler(method_name) # Add an exception handler method. # # @param method_name [Symbol] # The method name that handles exception raised in tests. # @return [void] # # @overload exception_handler(&callback) # Add an exception handler. # # @yield [test, exception] # Gives the test and the exception. # @yieldparam test [Test::Unit::TestCase] # The test where the exception is raised. # @yieldparam exception [Exception] # The exception that is raised in running the test. # @yieldreturn [Boolean] # Whether the handler handles the exception or not. # The handler must return _true_ if the handler handles # test exception, _false_ otherwise. # @return [void] # # This is a public API for developers who extend test-unit. def exception_handler(*method_name_or_handlers, &block) if block_given? exception_handlers.unshift(block) else method_name_or_handlers.each do |method_name_or_handler| if method_name_or_handler.respond_to?(:call) handler = method_name_or_handler exception_handlers.unshift(handler) else method_name = method_name_or_handler attribute(:exception_handler, true, {}, method_name) end end end end def unregister_exception_handler(*method_name_or_handlers) method_name_or_handlers.each do |method_name_or_handler| if method_name_or_handler.respond_to?(:call) handler = method_name_or_handler exception_handlers.delete(handler) else method_name = method_name_or_handler attribute(:exception_handler, false, {}, method_name) end end end end end end end PK ]"zz2gems/test-unit-3.3.4/lib/test/unit/color-scheme.rbnu[require 'test/unit/color' module Test module Unit class ColorScheme include Enumerable class << self def default if available_colors == 256 default_for_256_colors else default_for_8_colors end end @@default_for_8_colors = nil def default_for_8_colors @@default_for_8_colors ||= new("pass" => Color.new("green", :background => true) + Color.new("white", :bold => true), "pass-marker" => Color.new("green", :bold => true), "failure" => Color.new("red", :background => true) + Color.new("white", :bold => true), "failure-marker" => Color.new("red"), "pending" => Color.new("magenta", :background => true) + Color.new("white", :bold => true), "pending-marker" => Color.new("magenta"), "omission" => Color.new("blue", :background => true) + Color.new("white", :bold => true), "omission-marker" => Color.new("blue"), "notification" => Color.new("cyan", :background => true) + Color.new("white", :bold => true), "notification-marker" => Color.new("cyan"), "error" => Color.new("black", :background => true) + Color.new("yellow", :bold => true), "error-marker" => Color.new("yellow"), "case" => Color.new("blue", :background => true) + Color.new("white", :bold => true), "suite" => Color.new("green", :background => true) + Color.new("white", :bold => true), "diff-inserted-tag" => Color.new("red", :background => true) + Color.new("black", :bold => true), "diff-deleted-tag" => Color.new("green", :background => true) + Color.new("black", :bold => true), "diff-difference-tag" => Color.new("cyan", :background => true) + Color.new("white", :bold => true), "diff-inserted" => Color.new("red", :background => true) + Color.new("white", :bold => true), "diff-deleted" => Color.new("green", :background => true) + Color.new("white", :bold => true)) end @@default_for_256_colors = nil def default_for_256_colors @@default_for_256_colors ||= new("pass" => Color.new("030", :background => true) + Color.new("555", :bold => true), "pass-marker" => Color.new("050", :bold => true), "failure" => Color.new("300", :background => true) + Color.new("555", :bold => true), "failure-marker" => Color.new("500"), "pending" => Color.new("303", :background => true) + Color.new("555", :bold => true), "pending-marker" => Color.new("303"), "omission" => Color.new("001", :background => true) + Color.new("555", :bold => true), "omission-marker" => Color.new("001"), "notification" => Color.new("011", :background => true) + Color.new("555", :bold => true), "notification-marker" => Color.new("011"), "error" => Color.new("000", :background => true) + Color.new("550", :bold => true), "error-marker" => Color.new("550"), "case" => Color.new("220", :background => true) + Color.new("555", :bold => true), "suite" => Color.new("110", :background => true) + Color.new("555", :bold => true), "diff-inserted-tag" => Color.new("500", :background => true) + Color.new("000", :bold => true), "diff-deleted-tag" => Color.new("050", :background => true) + Color.new("000", :bold => true), "diff-difference-tag" => Color.new("005", :background => true) + Color.new("555", :bold => true), "diff-inserted" => Color.new("300", :background => true) + Color.new("555", :bold => true), "diff-deleted" => Color.new("030", :background => true) + Color.new("555", :bold => true)) end @@schemes = {} def all @@schemes.merge("default" => default) end def [](id) @@schemes[id.to_s] end def []=(id, scheme_or_spec) if scheme_or_spec.is_a?(self) scheme = scheme_or_spec else scheme = new(scheme_or_spec) end @@schemes[id.to_s] = scheme end def available_colors guess_available_colors_from_vte_version_env || guess_available_colors_from_colorterm_env || guess_available_colors_from_term_env || 8 end private def guess_available_colors_from_vte_version_env vte_version = ENV["VTE_VERSION"] return nil if vte_version.nil? major = 0 minor = 13 micro = 0 packed_version = major * 10000 + minor * 100 + micro if vte_version.to_i >= packed_version 256 else 8 end end def guess_available_colors_from_colorterm_env case ENV["COLORTERM"] when "gnome-terminal", "xfce4-terminal" 256 else nil end end def guess_available_colors_from_term_env case ENV["TERM"] when /-256color\z/ 256 else nil end end end def initialize(scheme_spec) @scheme = {} scheme_spec.each do |key, color_spec| self[key] = color_spec end end def [](name) @scheme[name.to_s] end def []=(name, color_spec) @scheme[name.to_s] = make_color(color_spec) end def each(&block) @scheme.each(&block) end def to_hash hash = {} @scheme.each do |key, color| hash[key] = color end hash end private def make_color(color_spec) if color_spec.is_a?(Color) or color_spec.is_a?(MixColor) color_spec else color_name = nil normalized_color_spec = {} color_spec.each do |key, value| key = key.to_sym if key == :name color_name = value else normalized_color_spec[key] = value end end Color.new(color_name, normalized_color_spec) end end end end end PK ]= = 8gems/test-unit-3.3.4/lib/test/unit/test-suite-creator.rbnu[#-- # # Author:: Kouhei Sutou # Copyright:: # * Copyright (c) 2011 Kouhei Sutou # License:: Ruby license. require "test/unit/data-sets" module Test module Unit class TestSuiteCreator # :nodoc: class << self def test_method?(test_case, method_name) /\Atest./ =~ method_name.to_s or test_case.find_attribute(method_name, :test) end end def initialize(test_case) @test_case = test_case end def create suite = TestSuite.new(@test_case.name, @test_case) collect_test_names.each do |test_name| data_sets = extract_data_sets(test_name) if data_sets data_sets.each do |label, data| append_test(suite, test_name) do |test| test.assign_test_data(label, data) end end else append_test(suite, test_name) end end append_test(suite, "default_test") if suite.empty? suite end private def extract_data_sets(test_name) data_sets = @test_case.find_attribute(test_name, :data, :recursive => false) data_method_name = "data_#{test_name}" test = @test_case.new(test_name) if test.respond_to?(data_method_name) data_method = test.method(data_method_name) if data_method.arity <= 0 data_sets ||= DataSets.new data_sets << data_method end end data_sets end def append_test(suite, test_name) test = @test_case.new(test_name) yield(test) if block_given? suite << test if test.valid? end def collect_test_names methods = @test_case.public_instance_methods(true) super_test_case = @test_case.superclass methods -= super_test_case.public_instance_methods(true) methods |= @test_case.public_instance_methods(false) method_names = methods.collect(&:to_s) test_names = method_names.find_all do |method_name| self.class.test_method?(@test_case, method_name) end __send__("sort_test_names_in_#{@test_case.test_order}_order", test_names) end def sort_test_names_in_alphabetic_order(test_names) test_names.sort end def sort_test_names_in_random_order(test_names) test_names.sort_by {rand(test_names.size)} end def sort_test_names_in_defined_order(test_names) added_method_names = @test_case.added_method_names test_names.sort do |test1, test2| test1_defined_order = added_method_names.index(test1) test2_defined_order = added_method_names.index(test2) if test1_defined_order and test2_defined_order test1_defined_order <=> test2_defined_order elsif test1_defined_order 1 elsif test2_defined_order -1 else test1 <=> test2 end end end end end end PK ]H~XX-gems/test-unit-3.3.4/lib/test/unit/failure.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # Encapsulates a test failure. Created by Test::Unit::TestCase # when an assertion fails. class Failure attr_reader :test_name, :location, :message attr_reader :method_name, :source_location attr_reader :expected, :actual, :user_message attr_reader :inspected_expected, :inspected_actual SINGLE_CHARACTER = 'F' LABEL = "Failure" # Creates a new Failure with the given location and # message. def initialize(test_name, location, message, options={}) @test_name = test_name @location = location @message = message @method_name = options[:method_name] @source_location = options[:source_location] @expected = options[:expected] @actual = options[:actual] @inspected_expected = options[:inspected_expected] @inspected_actual = options[:inspected_actual] @user_message = options[:user_message] end # Returns a single character representation of a failure. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns a brief version of the error description. def short_display "#@test_name: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display if location.size == 1 location_display = location[0].sub(/\A(.+:\d+).*/, ' [\\1]') else location_display = "\n [#{location.join("\n ")}]" end "#{label}:\n#@test_name#{location_display}:\n#@message" end # Overridden to return long_display. def to_s long_display end def critical? true end def diff @diff ||= compute_diff end private def compute_diff Assertions::AssertionMessage.delayed_diff(@expected, @actual).inspect end end module FailureHandler class << self def included(base) base.exception_handler(:handle_assertion_failed_error) end end # Report a failure. # # This is a public API for developers who extend test-unit. # # @param message [String] The description about the failure. # @param backtrace [Array] The backtrace for the failure. # @option options [Object] :expected # The expected value of the assertion. # @option options [Object] :actual # The actual value of the assertion. # @option options [String] :inspected_expected # The inspected expected value of the assertion. # It is used for diff between expected and actual of the failure. # @option options [String] :inspected_actual # The inspected actual value of the assertion. # It is used for diff between expected and actual of the failure. # @option options [String] :user_message # The message of the assertion from user. # @option options [String] :method_name (@method_name) # The method name of the test. # @option options [Array] :source_location # The location where the test is defined. It is the same # format as Proc#source_location. That is, it's an array of # path and and line number where the test definition is # started. # @return [void] def add_failure(message, backtrace, options={}) default_options = { :method_name => @method_name, :source_location => self[:source_location], } failure = Failure.new(name, filter_backtrace(backtrace), message, default_options.merge(options)) current_result.add_failure(failure) end private def handle_assertion_failed_error(exception) return false unless exception.is_a?(AssertionFailedError) problem_occurred add_failure(exception.message, exception.backtrace, :expected => exception.expected, :actual => exception.actual, :inspected_expected => exception.inspected_expected, :inspected_actual => exception.inspected_actual, :user_message => exception.user_message) true end end module TestResultFailureSupport attr_reader :failures # Records a Test::Unit::Failure. def add_failure(failure) @failures << failure notify_fault(failure) notify_changed end # Returns the number of failures this TestResult has # recorded. def failure_count @failures.size end def failure_occurred? not @failures.empty? end private def initialize_containers super @failures = [] @summary_generators << :failure_summary @problem_checkers << :failure_occurred? end def failure_summary "#{failure_count} failures" end end end end PK ]xZZ9gems/test-unit-3.3.4/lib/test/unit/ui/emacs/testrunner.rbnu[require 'test/unit/ui/console/testrunner' module Test module Unit module UI module Emacs class TestRunner < Console::TestRunner private def output_setup_end end def output_started end def format_fault(fault) return super unless fault.respond_to?(:label) format_method_name = "format_fault_#{fault.label.downcase}" if respond_to?(format_method_name, true) __send__(format_method_name, fault) else super end end def format_fault_failure(failure) if failure.location.size == 1 location = failure.location[0] location_display = location.sub(/\A(.+:\d+).*/, ' [\\1]') else location_display = "\n" + failure.location.join("\n") end result = "#{failure.label}:\n" result += "#{failure.test_name}#{location_display}:\n" result += failure.message result end def format_fault_error(error) result = "#{error.label}:\n" result += "#{error.test_name}:\n" result += "#{error.message}\n" result += error.backtrace.join("\n") result end end end end end end PK ]u$$<gems/test-unit-3.3.4/lib/test/unit/ui/testrunnerutilities.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit module UI # Provides some utilities common to most, if not all, # TestRunners. # #-- # # Perhaps there ought to be a TestRunner superclass? There # seems to be a decent amount of shared code between test # runners. module TestRunnerUtilities # Creates a new TestRunner and runs the suite. def run(suite, options={}) return new(suite, options).start end # Takes care of the ARGV parsing and suite # determination necessary for running one of the # TestRunners from the command line. def start_command_line_test if ARGV.empty? puts "You should supply the name of a test suite file to the runner" exit end require ARGV[0].gsub(/.+::/, '') new(eval(ARGV[0])).start end end end end end PK ]d7gems/test-unit-3.3.4/lib/test/unit/ui/xml/testrunner.rbnu[#-- # # Author:: Kouhei Sutou # Copyright:: # * Copyright (c) 2011 Kouhei Sutou # License:: Ruby license. require 'erb' require 'time' require 'test/unit/ui/testrunner' require 'test/unit/ui/testrunnermediator' module Test module Unit module UI module XML # Runs a Test::Unit::TestSuite and outputs XML. class TestRunner < UI::TestRunner include ERB::Util # Creates a new TestRunner for running the passed # suite. :output option specifies where runner # output should go to; defaults to STDOUT. def initialize(suite, options={}) super @output = @options[:output] || STDOUT if @options[:output_file_descriptor] @output = IO.new(@options[:output_file_descriptor], "w") end @already_outputted = false @indent = 0 @top_level = true @current_test = nil @current_test_suite = nil @already_outputted = false end private def attach_to_mediator @mediator.add_listener(TestResult::PASS_ASSERTION, &method(:result_pass_assertion)) @mediator.add_listener(TestResult::FAULT, &method(:result_fault)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) @mediator.add_listener(TestCase::STARTED_OBJECT, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED_OBJECT, &method(:test_finished)) @mediator.add_listener(TestSuite::STARTED_OBJECT, &method(:test_suite_started)) @mediator.add_listener(TestSuite::FINISHED_OBJECT, &method(:test_suite_finished)) end def result_pass_assertion(result) open_tag("pass-assertion") do output_test(@current_test) end end def result_fault(fault) open_tag("test-result") do open_tag("result") do output_test_suite(@current_test_suite) output_test(@current_test) open_tag("backtrace") do fault.location.each do |entry| file, line, info = entry.split(/:/, 3) open_tag("entry") do add_content("file", file) add_content("line", line) add_content("info", info) end end end if fault.respond_to?(:expected) add_content("expected", fault.expected) end if fault.respond_to?(:actual) add_content("actual", fault.actual) end add_content("detail", fault.message) add_content("status", fault.label.downcase) end end @already_outputted = true if fault.critical? end def started(result) @result = result output_started end def output_started open_tag("stream") end def finished(elapsed_time) add_content("success", @result.passed?) close_tag("stream") end def test_started(test) @already_outputted = false @current_test = test open_tag("start-test") do output_test(test) end end def test_finished(test) unless @already_outputted open_tag("test-result") do output_test(test) open_tag("result") do output_test_suite(@current_test_suite) output_test(test) add_content("status", "success") end end end open_tag("complete-test") do output_test(test) add_content("success", test.passed?) end @current_test = nil end def test_suite_started(suite) @current_test_suite = suite if suite.test_case.nil? open_tag("ready-test-suite") do add_content("n-tests", suite.size) end open_tag("start-test-suite") do output_test_suite(suite) end else open_tag("ready-test-case") do output_test_suite(suite) add_content("n-tests", suite.size) end open_tag("start-test-case") do output_test_suite(suite) end end end def test_suite_finished(suite) if suite.test_case.nil? open_tag("complete-test-suite") do output_test_suite(suite) add_content("success", suite.passed?) end else open_tag("complete-test-case") do output_test_suite(suite) add_content("success", suite.passed?) end end @current_test_suite = nil end def indent " " * @indent end def open_tag(name) @output.puts("#{indent}<#{name}>") @indent += 2 if block_given? yield close_tag(name) end end def add_content(name, content) return if content.nil? case content when Time content = content.iso8601 end @output.puts("#{indent}<#{name}>#{h(content)}") end def close_tag(name) @indent -= 2 @output.puts("#{indent}") end def output_test(test) open_tag("test") do add_content("name", test.method_name) add_content("start-time", test.start_time) add_content("elapsed", test.elapsed_time) end end def output_test_suite(test_suite) test_case = test_suite.test_case if test_case.nil? open_tag("test-suite") do add_content("name", test_suite.name) add_content("start-time", test_suite.start_time) add_content("elapsed", test_suite.elapsed_time) end else open_tag("test-case") do add_content("name", test_suite.name) add_content("start-time", test_suite.start_time) add_content("elapsed", test_suite.elapsed_time) end end end end end end end end PK ]l~<gems/test-unit-3.3.4/lib/test/unit/ui/console/outputlevel.rbnu[module Test module Unit module UI module Console module OutputLevel SILENT = 0 PROGRESS_ONLY = 1 IMPORTANT_FAULTS_ONLY = 2 NORMAL = 3 VERBOSE = 4 end end end end end PK ]!=(__;gems/test-unit-3.3.4/lib/test/unit/ui/console/testrunner.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: # * Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # * Copyright (c) 2008-2017 Kouhei Sutou # License:: Ruby license. begin require 'io/console' rescue LoadError end require 'test/unit/color-scheme' require 'test/unit/code-snippet-fetcher' require 'test/unit/fault-location-detector' require 'test/unit/diff' require 'test/unit/ui/testrunner' require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/console/outputlevel' module Test module Unit module UI module Console # Runs a Test::Unit::TestSuite on the console. class TestRunner < UI::TestRunner include OutputLevel # Creates a new TestRunner for running the passed # suite. If quiet_mode is true, the output while # running is limited to progress dots, errors and # failures, and the final result. io specifies # where runner output should go to; defaults to # STDOUT. def initialize(suite, options={}) super @output_level = @options[:output_level] || NORMAL @output = @options[:output] || STDOUT @use_color = @options[:use_color] @use_color = guess_color_availability if @use_color.nil? @color_scheme = @options[:color_scheme] || ColorScheme.default @reset_color = Color.new("reset") @progress_row = 0 @progress_row_max = @options[:progress_row_max] @progress_row_max ||= guess_progress_row_max @show_detail_immediately = @options[:show_detail_immediately] @show_detail_immediately = true if @show_detail_immediately.nil? @reverse_output = @options[:reverse_output] @reverse_output = @output.tty? if @reverse_output.nil? @already_outputted = false @indent = 0 @top_level = true @current_output_level = NORMAL @faults = [] @code_snippet_fetcher = CodeSnippetFetcher.new @test_suites = [] end private def change_output_level(level) old_output_level = @current_output_level @current_output_level = level yield @current_output_level = old_output_level end def setup_mediator super output_setup_end end def output_setup_end suite_name = @suite.to_s suite_name = @suite.name if @suite.kind_of?(Module) output("Loaded suite #{suite_name}") end def attach_to_mediator @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) @mediator.add_listener(TestCase::STARTED_OBJECT, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED_OBJECT, &method(:test_finished)) @mediator.add_listener(TestSuite::STARTED_OBJECT, &method(:test_suite_started)) @mediator.add_listener(TestSuite::FINISHED_OBJECT, &method(:test_suite_finished)) end def add_fault(fault) @faults << fault output_progress(fault.single_character_display, fault_marker_color(fault)) output_progress_in_detail(fault) if @show_detail_immediately @already_outputted = true if fault.critical? end def started(result) @result = result output_started end def output_started output("Started") end def finished(elapsed_time) unless @show_detail_immediately nl if output?(NORMAL) and !output?(VERBOSE) output_faults end nl(PROGRESS_ONLY) change_output_level(IMPORTANT_FAULTS_ONLY) do output_statistics(elapsed_time) end end def output_faults categorized_faults = categorize_faults change_output_level(IMPORTANT_FAULTS_ONLY) do output_faults_in_detail(categorized_faults[:need_detail_faults]) end output_faults_in_short("Omissions", Omission, categorized_faults[:omissions]) output_faults_in_short("Notifications", Notification, categorized_faults[:notifications]) end def max_digit(max_number) (Math.log10(max_number) + 1).truncate end def output_faults_in_detail(faults) return if faults.nil? digit = max_digit(faults.size) faults.each_with_index do |fault, index| nl output_single("%#{digit}d) " % (index + 1)) output_fault_in_detail(fault) end end def output_faults_in_short(label, fault_class, faults) return if faults.nil? digit = max_digit(faults.size) nl output_single(label, fault_class_color(fault_class)) output(":") faults.each_with_index do |fault, index| output_single("%#{digit}d) " % (index + 1)) output_fault_in_short(fault) end end def categorize_faults faults = {} @faults.each do |fault| category = categorize_fault(fault) faults[category] ||= [] faults[category] << fault end faults end def categorize_fault(fault) case fault when Omission :omissions when Notification :notifications else :need_detail_faults end end def output_fault_in_detail(fault) if fault.is_a?(Failure) and fault.inspected_expected and fault.inspected_actual if @reverse_output output_fault_backtrace(fault) output_failure_message(fault) output_single("#{fault.label}: ") output(fault.test_name, fault_color(fault)) else output_single("#{fault.label}: ") output(fault.test_name, fault_color(fault)) output_fault_backtrace(fault) output_failure_message(fault) end else if @reverse_output output_fault_backtrace(fault) output_single("#{fault.label}: ") output_single(fault.test_name, fault_color(fault)) output_fault_message(fault) else output_single("#{fault.label}: ") output_single(fault.test_name, fault_color(fault)) output_fault_message(fault) output_fault_backtrace(fault) end end end def output_fault_message(fault) message = fault.message return if message.nil? if message.include?("\n") output(":") message.each_line do |line| output(" #{line.chomp}") end else output(": #{message}") end end def output_fault_backtrace(fault) detector = FaultLocationDetector.new(fault, @code_snippet_fetcher) backtrace = fault.location # workaround for test-spec. :< # see also GitHub:#22 backtrace ||= [] code_snippet_backtrace_index = nil code_snippet_lines = nil backtrace.each_with_index do |entry, i| next unless detector.target?(entry) file, line_number, = detector.split_backtrace_entry(entry) lines = fetch_code_snippet(file, line_number) unless lines.empty? code_snippet_backtrace_index = i code_snippet_lines = lines break end end if @reverse_output backtrace.each_with_index.reverse_each do |entry, i| if i == code_snippet_backtrace_index output_code_snippet(code_snippet_lines, fault_color(fault)) end output(entry) end else backtrace.each_with_index do |entry, i| output(entry) if i == code_snippet_backtrace_index output_code_snippet(code_snippet_lines, fault_color(fault)) end end end end def fetch_code_snippet(file, line_number) @code_snippet_fetcher.fetch(file, line_number) end def output_code_snippet(lines, target_line_color=nil) max_n = lines.collect {|n, line, attributes| n}.max digits = (Math.log10(max_n) + 1).truncate lines.each do |n, line, attributes| if attributes[:target_line?] line_color = target_line_color current_line_mark = "=>" else line_color = nil current_line_mark = "" end output(" %2s %*d: %s" % [current_line_mark, digits, n, line], line_color) end end def output_failure_message(failure) if failure.expected.respond_to?(:encoding) and failure.actual.respond_to?(:encoding) and failure.expected.encoding != failure.actual.encoding need_encoding = true else need_encoding = false end output(failure.user_message) if failure.user_message output_single("<") output_single(failure.inspected_expected, color("pass")) output_single(">") if need_encoding output_single("(") output_single(failure.expected.encoding.name, color("pass")) output_single(")") end output(" expected but was") output_single("<") output_single(failure.inspected_actual, color("failure")) output_single(">") if need_encoding output_single("(") output_single(failure.actual.encoding.name, color("failure")) output_single(")") end output("") from, to = prepare_for_diff(failure.expected, failure.actual) if from and to if need_encoding unless from.valid_encoding? from = from.dup.force_encoding("ASCII-8BIT") end unless to.valid_encoding? to = to.dup.force_encoding("ASCII-8BIT") end end from_lines = from.split(/\r?\n/) to_lines = to.split(/\r?\n/) if need_encoding from_lines << "" to_lines << "" from_lines << "Encoding: #{failure.expected.encoding.name}" to_lines << "Encoding: #{failure.actual.encoding.name}" end differ = ColorizedReadableDiffer.new(from_lines, to_lines, self) if differ.need_diff? output("") output("diff:") differ.diff end end end def output_fault_in_short(fault) if @reverse_output output(fault.location.first) output_single("#{fault.label}: ") output_single(fault.message, fault_color(fault)) output(" [#{fault.test_name}]") else output_single("#{fault.label}: ") output_single(fault.message, fault_color(fault)) output(" [#{fault.test_name}]") output(fault.location.first) end end def format_fault(fault) fault.long_display end def output_statistics(elapsed_time) output("Finished in #{elapsed_time} seconds.") output_summary_marker output(@result) output("%g%% passed" % @result.pass_percentage) unless elapsed_time.zero? output_summary_marker test_throughput = @result.run_count / elapsed_time assertion_throughput = @result.assertion_count / elapsed_time throughput = [ "%.2f tests/s" % test_throughput, "%.2f assertions/s" % assertion_throughput, ] output(throughput.join(", ")) end end def output_summary_marker if @progress_row_max > 0 output("-" * @progress_row_max, summary_marker_color) else nl end end def test_started(test) return unless output?(VERBOSE) tab_width = 8 name = test.local_name separator = ":" left_used = indent.size + name.size + separator.size right_space = tab_width * 2 left_space = @progress_row_max - right_space if (left_used % tab_width).zero? left_space -= left_used n_tabs = 0 else left_space -= ((left_used / tab_width) + 1) * tab_width n_tabs = 1 end n_tabs += [left_space, 0].max / tab_width tab_stop = "\t" * n_tabs output_single("#{indent}#{name}#{separator}#{tab_stop}", nil, VERBOSE) @test_start = Time.now end def test_finished(test) unless @already_outputted output_progress(".", color("pass-marker")) end @already_outputted = false return unless output?(VERBOSE) output(": (%f)" % (Time.now - @test_start), nil, VERBOSE) end def suite_name(prefix, suite) name = suite.name if name.nil? "(anonymous)" else name.sub(/\A#{Regexp.escape(prefix)}/, "") end end def test_suite_started(suite) last_test_suite = @test_suites.last @test_suites << suite if @top_level @top_level = false return end output_single(indent, nil, VERBOSE) if suite.test_case.nil? _color = color("suite") else _color = color("case") end prefix = "#{last_test_suite.name}::" output_single(suite_name(prefix, suite), _color, VERBOSE) output(": ", nil, VERBOSE) @indent += 2 end def test_suite_finished(suite) @indent -= 2 @test_suites.pop end def indent if output?(VERBOSE) " " * @indent else "" end end def nl(level=nil) output("", nil, level) end def output(something, color=nil, level=nil) return unless output?(level) output_single(something, color, level) @output.puts end def output_single(something, color=nil, level=nil) return false unless output?(level) if @use_color and color something = "%s%s%s" % [color.escape_sequence, something, @reset_color.escape_sequence] end @output.write(something) @output.flush true end def output_progress(mark, color=nil) if output_single(mark, color, PROGRESS_ONLY) return unless @progress_row_max > 0 @progress_row += mark.size if @progress_row >= @progress_row_max nl unless @output_level == VERBOSE @progress_row = 0 end end end def output_progress_in_detail_marker(fault) if @progress_row_max > 0 output("=" * @progress_row_max) else nl end end def output_progress_in_detail(fault) return if @output_level == SILENT nl output_progress_in_detail_marker(fault) if categorize_fault(fault) == :need_detail_faults output_fault_in_detail(fault) else output_fault_in_short(fault) end output_progress_in_detail_marker(fault) @progress_row = 0 end def output?(level) (level || @current_output_level) <= @output_level end def color(name) _color = @color_scheme[name] _color ||= @color_scheme["success"] if name == "pass" _color ||= ColorScheme.default[name] _color end def fault_class_color_name(fault_class) fault_class.name.split(/::/).last.downcase end def fault_class_color(fault_class) color(fault_class_color_name(fault_class)) end def fault_color(fault) fault_class_color(fault.class) end def fault_marker_color(fault) color("#{fault_class_color_name(fault.class)}-marker") end def summary_marker_color color("#{@result.status}-marker") end def guess_color_availability return false unless @output.tty? return true if windows? and ruby_2_0_or_later? case ENV["TERM"] when /(?:term|screen)(?:-(?:256)?color)?\z/ true when /\Arxvt/ true else return true if ENV["EMACS"] == "t" false end end def windows? /mswin|mingw/ === RUBY_PLATFORM end def ruby_2_0_or_later? RUBY_VERSION >= "2.0.0" end def guess_progress_row_max term_width = guess_term_width if term_width.zero? if ENV["EMACS"] == "t" -1 else 79 end else term_width end end def guess_term_width guess_term_width_from_io || guess_term_width_from_env || 0 end def guess_term_width_from_io if @output.respond_to?(:winsize) begin @output.winsize[1] rescue SystemCallError nil end else nil end end def guess_term_width_from_env env = ENV["COLUMNS"] || ENV["TERM_WIDTH"] return nil if env.nil? begin Integer(env) rescue ArgumentError nil end end end class ColorizedReadableDiffer < Diff::ReadableDiffer def initialize(from, to, runner) @runner = runner super(from, to) end def need_diff?(options={}) return false if one_line_all_change? operations.each do |tag,| return true if [:replace, :equal].include?(tag) end false end private def one_line_all_change? return false if operations.size != 1 tag, from_start, from_end, to_start, to_end = operations.first return false if tag != :replace return false if [from_start, from_end] != [0, 1] return false if [from_start, from_end] != [to_start, to_end] _, _, _line_operations = line_operations(@from.first, @to.first) _line_operations.size == 1 end def output_single(something, color=nil) @runner.__send__(:output_single, something, color) end def output(something, color=nil) @runner.__send__(:output, something, color) end def color(name) @runner.__send__(:color, name) end def cut_off_ratio 0 end def default_ratio 0 end def tag(mark, color_name, contents) _color = color(color_name) contents.each do |content| output_single(mark, _color) output_single(" ") output(content) end end def tag_deleted(contents) tag("-", "diff-deleted-tag", contents) end def tag_inserted(contents) tag("+", "diff-inserted-tag", contents) end def tag_equal(contents) tag(" ", "normal", contents) end def tag_difference(contents) tag("?", "diff-difference-tag", contents) end def diff_line(from_line, to_line) to_operations = [] from_line, to_line, _operations = line_operations(from_line, to_line) no_replace = true _operations.each do |tag,| if tag == :replace no_replace = false break end end output_single("?", color("diff-difference-tag")) output_single(" ") _operations.each do |tag, from_start, from_end, to_start, to_end| from_width = compute_width(from_line, from_start, from_end) to_width = compute_width(to_line, to_start, to_end) case tag when :replace output_single(from_line[from_start...from_end], color("diff-deleted")) if (from_width < to_width) output_single(" " * (to_width - from_width)) end to_operations << Proc.new do output_single(to_line[to_start...to_end], color("diff-inserted")) if (to_width < from_width) output_single(" " * (from_width - to_width)) end end when :delete output_single(from_line[from_start...from_end], color("diff-deleted")) unless no_replace to_operations << Proc.new {output_single(" " * from_width)} end when :insert if no_replace output_single(to_line[to_start...to_end], color("diff-inserted")) else output_single(" " * to_width) to_operations << Proc.new do output_single(to_line[to_start...to_end], color("diff-inserted")) end end when :equal output_single(from_line[from_start...from_end]) unless no_replace to_operations << Proc.new {output_single(" " * to_width)} end else raise "unknown tag: #{tag}" end end output("") unless to_operations.empty? output_single("?", color("diff-difference-tag")) output_single(" ") to_operations.each do |operation| operation.call end output("") end end end end end end end PK ]޸3gems/test-unit-3.3.4/lib/test/unit/ui/testrunner.rbnu[require 'test/unit/ui/testrunnerutilities' module Test module Unit module UI class TestRunner extend TestRunnerUtilities attr_reader :listeners def initialize(suite, options={}) if suite.respond_to?(:suite) @suite = suite.suite else @suite = suite end @options = options @listeners = @options[:listeners] || [] end # Begins the test run. def start setup_mediator attach_to_mediator attach_listeners start_mediator end private def setup_mediator @mediator = TestRunnerMediator.new(@suite) end def attach_listeners @listeners.each do |listener| listener.attach_to_mediator(@mediator) end end def start_mediator @mediator.run end def diff_target_string?(string) Assertions::AssertionMessage.diff_target_string?(string) end def prepare_for_diff(from, to) Assertions::AssertionMessage.prepare_for_diff(from, to) end end end end end PK ]N N ;gems/test-unit-3.3.4/lib/test/unit/ui/testrunnermediator.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/observable' require 'test/unit/testresult' module Test module Unit module UI # Provides an interface to write any given UI against, # hopefully making it easy to write new UIs. class TestRunnerMediator RESET = name + "::RESET" STARTED = name + "::STARTED" FINISHED = name + "::FINISHED" include Util::Observable # Creates a new TestRunnerMediator initialized to run # the passed suite. def initialize(suite) @suite = suite end # Runs the suite the TestRunnerMediator was created # with. def run AutoRunner.need_auto_run = false result = create_result Test::Unit.run_at_start_hooks start_time = Time.now begin catch do |stop_tag| result.stop_tag = stop_tag with_listener(result) do notify_listeners(RESET, @suite.size) notify_listeners(STARTED, result) run_suite(result) end end ensure elapsed_time = Time.now - start_time notify_listeners(FINISHED, elapsed_time) end Test::Unit.run_at_exit_hooks result end # Just for backward compatibility for NetBeans. # NetBeans should not use monkey patching. NetBeans # should use runner change public API. # # See GitHub#38 # https://github.com/test-unit/test-unit/issues/38 def run_suite(result=nil) if result.nil? run else @suite.run(result) do |channel, value| notify_listeners(channel, value) end end end private # A factory method to create the result the mediator # should run with. Can be overridden by subclasses if # one wants to use a different result. def create_result TestResult.new end def measure_time begin_time = Time.now yield Time.now - begin_time end def with_listener(result) finished_listener = result.add_listener(TestResult::FINISHED) do |*args| notify_listeners(TestResult::FINISHED, *args) end changed_listener = result.add_listener(TestResult::CHANGED) do |*args| notify_listeners(TestResult::CHANGED, *args) end pass_assertion_listener = result.add_listener(TestResult::PASS_ASSERTION) do |*args| notify_listeners(TestResult::PASS_ASSERTION, *args) end fault_listener = result.add_listener(TestResult::FAULT) do |*args| notify_listeners(TestResult::FAULT, *args) end begin yield ensure result.remove_listener(TestResult::FAULT, fault_listener) result.remove_listener(TestResult::CHANGED, changed_listener) result.remove_listener(TestResult::FINISHED, finished_listener) result.remove_listener(TestResult::PASS_ASSERTION, pass_assertion_listener) end end end end end end PK ]KE::/gems/test-unit-3.3.4/lib/test/unit/collector.rbnu[module Test module Unit module Collector def initialize @filters = [] end def filter=(filters) @filters = case(filters) when Proc [filters] when Array filters end end def add_suite(destination, suite) to_delete = suite.tests.find_all do |test| test.is_a?(TestCase) and !include?(test) end suite.delete_tests(to_delete) destination << suite unless suite.empty? end def add_test_cases(suite, test_cases) children_map = {} test_cases.each do |test_case| ancestor_classes = test_case.ancestors.find_all do |ancestor| ancestor.is_a?(Class) end parent = ancestor_classes[1] children_map[parent] ||= [] children_map[parent] << test_case end root_test_cases = children_map.keys - test_cases root_test_cases.each do |root_test_case| add_test_case(suite, root_test_case, children_map) end end def include?(test) return true if(@filters.empty?) @filters.each do |filter| return false if filter[test] == false end true end def sort(suites) suites.sort_by do |suite| [suite.priority, suite.name || suite.to_s] end end private def add_test_case(suite, test_case, children_map) children = children_map[test_case] return if children.nil? sub_suites = [] children.each do |child| sub_suite = child.suite add_test_case(sub_suite, child, children_map) add_suite(sub_suites, sub_suite) end sort(sub_suites).each do |sub_suite| suite << sub_suite end end end end end PK ]Vݯ7gems/test-unit-3.3.4/lib/test/unit/attribute-matcher.rbnu[module Test module Unit class AttributeMatcher def initialize(test) @test = test end def match?(expression) matched = instance_eval(expression) if matched.nil? false else matched end end def method_missing(name, *args) if args.empty? @test[name] else super end end end end end PK ]-K@K@%gems/test-unit-3.3.4/lib/test/unit.rbnu[require 'test/unit/testcase' require 'test/unit/autorunner' module Test # :nodoc: # # # Test::Unit - Ruby Unit Testing Framework # # ## Introduction # # Unit testing is making waves all over the place, largely due to the # fact that it is a core practice of XP. While XP is great, unit testing # has been around for a long time and has always been a good idea. One # of the keys to good unit testing, though, is not just writing tests, # but having tests. What's the difference? Well, if you just _write_ a # test and throw it away, you have no guarantee that something won't # change later which breaks your code. If, on the other hand, you _have_ # tests (obviously you have to write them first), and run them as often # as possible, you slowly build up a wall of things that cannot break # without you immediately knowing about it. This is when unit testing # hits its peak usefulness. # # Enter Test::Unit, a framework for unit testing in Ruby, helping you to # design, debug and evaluate your code by making it easy to write and # have tests for it. # # # ## Notes # # Test::Unit has grown out of and superceded Lapidary. # # # ## Feedback # # I like (and do my best to practice) XP, so I value early releases, # user feedback, and clean, simple, expressive code. There is always # room for improvement in everything I do, and Test::Unit is no # exception. Please, let me know what you think of Test::Unit as it # stands, and what you'd like to see expanded/changed/improved/etc. If # you find a bug, let me know ASAP; one good way to let me know what the # bug is is to submit a new test that catches it :-) Also, I'd love to # hear about any successes you have with Test::Unit, and any # documentation you might add will be greatly appreciated. My contact # info is below. # # # ## Contact Information # # A lot of discussion happens about Ruby in general on the ruby-talk # mailing list (http://www.ruby-lang.org/en/ml.html), and you can ask # any questions you might have there. I monitor the list, as do many # other helpful Rubyists, and you're sure to get a quick answer. Of # course, you're also welcome to email me (Nathaniel Talbott) directly # at mailto:testunit@talbott.ws, and I'll do my best to help you out. # # # ## Credits # # I'd like to thank... # # Matz, for a great language! # # Masaki Suketa, for his work on RubyUnit, which filled a vital need in # the Ruby world for a very long time. I'm also grateful for his help in # polishing Test::Unit and getting the RubyUnit compatibility layer # right. His graciousness in allowing Test::Unit to supercede RubyUnit # continues to be a challenge to me to be more willing to defer my own # rights. # # Ken McKinlay, for his interest and work on unit testing, and for his # willingness to dialog about it. He was also a great help in pointing # out some of the holes in the RubyUnit compatibility layer. # # Dave Thomas, for the original idea that led to the extremely simple # "require 'test/unit'", plus his code to improve it even more by # allowing the selection of tests from the command-line. Also, without # RDoc, the documentation for Test::Unit would stink a lot more than it # does now. # # Everyone who's helped out with bug reports, feature ideas, # encouragement to continue, etc. It's a real privilege to be a part of # the Ruby community. # # The guys at RoleModel Software, for putting up with me repeating, "But # this would be so much easier in Ruby!" whenever we're coding in Java. # # My Creator, for giving me life, and giving it more abundantly. # # # ## License # # Test::Unit is copyright (c) 2000-2003 Nathaniel Talbott. It is free # software, and is distributed under the Ruby license. See the COPYING # file. # # Exception: lib/test/unit/diff.rb is copyright (c) # 2008-2010 Kouhei Sutou and 2001-2008 Python Software # Foundation. It is free software, and is distributed # under the Ruby license and/or the PSF license. See the # COPYING file and PSFL file. # # ## Warranty # # This software is provided "as is" and without any express or # implied warranties, including, without limitation, the implied # warranties of merchantibility and fitness for a particular # purpose. # # # ## Author # # Nathaniel Talbott. # Copyright (c) 2000-2003, Nathaniel Talbott # # ---- # # # Usage # # The general idea behind unit testing is that you write a _test_ # _method_ that makes certain _assertions_ about your code, working # against a _test_ _fixture_. A bunch of these _test_ _methods_ are # bundled up into a _test_ _suite_ and can be run any time the # developer wants. The results of a run are gathered in a _test_ # _result_ and displayed to the user through some UI. So, lets break # this down and see how Test::Unit provides each of these necessary # pieces. # # # ## Assertions # # These are the heart of the framework. Think of an assertion as a # statement of expected outcome, i.e. "I assert that x should be equal # to y". If, when the assertion is executed, it turns out to be # correct, nothing happens, and life is good. If, on the other hand, # your assertion turns out to be false, an error is propagated with # pertinent information so that you can go back and make your # assertion succeed, and, once again, life is good. For an explanation # of the current assertions, see Test::Unit::Assertions. # # # ## Test Method & Test Fixture # # Obviously, these assertions have to be called within a context that # knows about them and can do something meaningful with their # pass/fail value. Also, it's handy to collect a bunch of related # tests, each test represented by a method, into a common test class # that knows how to run them. The tests will be in a separate class # from the code they're testing for a couple of reasons. First of all, # it allows your code to stay uncluttered with test code, making it # easier to maintain. Second, it allows the tests to be stripped out # for deployment, since they're really there for you, the developer, # and your users don't need them. Third, and most importantly, it # allows you to set up a common test fixture for your tests to run # against. # # What's a test fixture? Well, tests do not live in a vacuum; rather, # they're run against the code they are testing. Often, a collection # of tests will run against a common set of data, also called a # fixture. If they're all bundled into the same test class, they can # all share the setting up and tearing down of that data, eliminating # unnecessary duplication and making it much easier to add related # tests. # # Test::Unit::TestCase wraps up a collection of test methods together # and allows you to easily set up and tear down the same test fixture # for each test. This is done by overriding #setup and/or #teardown, # which will be called before and after each test method that is # run. The TestCase also knows how to collect the results of your # assertions into a Test::Unit::TestResult, which can then be reported # back to you... but I'm getting ahead of myself. To write a test, # follow these steps: # # * Make sure Test::Unit is in your library path. # * require 'test/unit' in your test script. # * Create a class that subclasses Test::Unit::TestCase. # * Add a method that begins with "test" to your class. # * Make assertions in your test method. # * Optionally define #setup and/or #teardown to set up and/or tear # down your common test fixture. # * You can now run your test as you would any other Ruby # script... try it and see! # # A really simple test might look like this (#setup and #teardown are # commented out to indicate that they are completely optional): # # require 'test/unit' # # class MyTest < Test::Unit::TestCase # # def setup # # end # # # def teardown # # end # # def test_fail # assert(false, 'Assertion was false.') # end # end # # # ## Test Runners # # So, now you have this great test class, but you still # need a way to run it and view any failures that occur # during the run. There are some test runner; console test # runner, GTK+ test runner and so on. The console test # runner is automatically invoked for you if you require # 'test/unit' and simply run the file. To use another # runner simply set default test runner ID to # Test::Unit::AutoRunner: # # require 'test/unit' # Test::Unit::AutoRunner.default_runner = "gtk2" # # ## Test Suite # # As more and more unit tests accumulate for a given project, it # becomes a real drag running them one at a time, and it also # introduces the potential to overlook a failing test because you # forget to run it. Suddenly it becomes very handy that the # TestRunners can take any object that returns a Test::Unit::TestSuite # in response to a suite method. The TestSuite can, in turn, contain # other TestSuites or individual tests (typically created by a # TestCase). In other words, you can easily wrap up a group of # TestCases and TestSuites. # # Test::Unit does a little bit more for you, by wrapping # these up automatically when you require # 'test/unit'. What does this mean? It means you could # write the above test case like this instead: # # require 'test/unit' # require 'test_myfirsttests' # require 'test_moretestsbyme' # require 'test_anothersetoftests' # # Test::Unit is smart enough to find all the test cases existing in # the ObjectSpace and wrap them up into a suite for you. It then runs # the dynamic suite using the console TestRunner. # # # ## Configuration file # # Test::Unit reads 'test-unit.yml' in the current working # directory as Test::Unit's configuration file. It can # contain the following configurations: # # * color scheme definitions # * test runner to be used # * test runner options # * test collector to be used # # Except color scheme definitions, all of them are # specified by command line option. # # Here are sample color scheme definitions: # # color_schemes: # inverted: # success: # name: red # bold: true # failure: # name: green # bold: true # other_scheme: # ... # # Here are the syntax of color scheme definitions: # # color_schemes: # SCHEME_NAME: # EVENT_NAME: # name: COLOR_NAME # intensity: BOOLEAN # bold: BOOLEAN # italic: BOOLEAN # underline: BOOLEAN # ... # ... # # SCHEME_NAME # : the name of the color scheme # # EVENT_NAME # : one of [success, failure, pending, omission, notification, error] # # COLOR_NAME # : one of [black, red, green, yellow, blue, magenta, cyan, white] # # BOOLEAN # : true or false # # You can use the above 'inverted' color scheme with the # following configuration: # # runner: console # console_options: # color_scheme: inverted # color_schemes: # inverted: # success: # name: red # bold: true # failure: # name: green # bold: true # # ## Questions? # # I'd really like to get feedback from all levels of Ruby # practitioners about typos, grammatical errors, unclear statements, # missing points, etc., in this document (or any other). # module Unit class << self # Set true when Test::Unit has run. If set to true Test::Unit # will not automatically run at exit. # # @deprecated Use Test::Unit::AutoRunner.need_auto_run= instead. def run=(have_run) AutoRunner.need_auto_run = (not have_run) end # Already tests have run? # # @deprecated Use Test::Unit::AutoRunner.need_auto_run? instead. def run? not AutoRunner.need_auto_run? end # @api private @@at_start_hooks = [] # Regsiter a hook that is run before running tests. # To register multiple hooks, call this method multiple times. # # Here is an example test case: # # Test::Unit.at_start do # # ... # end # # class TestMyClass1 < Test::Unit::TestCase # class << self # def startup # # ... # end # end # # def setup # # ... # end # # def test_my_class1 # # ... # end # # def test_my_class2 # # ... # end # end # # class TestMyClass2 < Test::Unit::TestCase # class << self # def startup # # ... # end # end # # def setup # # ... # end # # def test_my_class1 # # ... # end # # def test_my_class2 # # ... # end # end # # Here is a call order: # # * at_start # * TestMyClass1.startup # * TestMyClass1#setup # * TestMyClass1#test_my_class1 # * TestMyClass1#setup # * TestMyClass1#test_my_class2 # * TestMyClass2#setup # * TestMyClass2#test_my_class1 # * TestMyClass2#setup # * TestMyClass2#test_my_class2 # # @example # Test::Unit.at_start do # puts "Start!" # end # # @yield A block that is run before running tests. # @yieldreturn [void] # @return [void] # # @since 2.5.2 def at_start(&hook) @@at_start_hooks << hook end # @api private def run_at_start_hooks @@at_start_hooks.each do |hook| hook.call end end # @api private @@at_exit_hooks = [] # Regsiter a hook that is run after running tests. # To register multiple hooks, call this method multiple times. # # Here is an example test case: # # Test::Unit.at_exit do # # ... # end # # class TestMyClass1 < Test::Unit::TestCase # class << self # def shutdown # # ... # end # end # # def teardown # # ... # end # # def test_my_class1 # # ... # end # # def test_my_class2 # # ... # end # end # # class TestMyClass2 < Test::Unit::TestCase # class << self # def shutdown # # ... # end # end # # def teardown # # ... # end # # def test_my_class1 # # ... # end # # def test_my_class2 # # ... # end # end # # Here is a call order: # # * TestMyClass1#test_my_class1 # * TestMyClass1#teardown # * TestMyClass1#test_my_class2 # * TestMyClass1#teardown # * TestMyClass1.shutdown # * TestMyClass2#test_my_class1 # * TestMyClass2#teardown # * TestMyClass2#test_my_class2 # * TestMyClass2#teardown # * TestMyClass2.shutdown # * at_exit # # @example # Test::Unit.at_exit do # puts "Exit!" # end # # @yield A block that is run after running tests. # @yieldreturn [void] # @return [void] # # @since 2.5.2 def at_exit(&hook) @@at_exit_hooks << hook end # @api private def run_at_exit_hooks @@at_exit_hooks.each do |hook| hook.call end end end end end Module.new do at_exit do if $!.nil? and Test::Unit::AutoRunner.need_auto_run? exit Test::Unit::AutoRunner.run end end end PK ] O%gems/test-unit-3.3.4/lib/test-unit.rbnu[# Copyright (C) 2012-2015 Kouhei Sutou # # License: Ruby's or LGPLv2.1 or later # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA module Test module Unit autoload :TestCase, "test/unit/testcase" autoload :AutoRunner, "test/unit/autorunner" end end unless respond_to?(:run_test, true) # experimental. It is for "ruby -rtest-unit -e run_test test/test_*.rb". # Is this API OK or dirty? def run_test self.class.send(:undef_method, :run_test) require "test/unit" end end PK ]gems/json-2.3.0/lib/json.rbnu[#frozen_string_literal: false require 'json/common' ## # = JavaScript Object Notation (JSON) # # JSON is a lightweight data-interchange format. It is easy for us # humans to read and write. Plus, equally simple for machines to generate or parse. # JSON is completely language agnostic, making it the ideal interchange format. # # Built on two universally available structures: # 1. A collection of name/value pairs. Often referred to as an _object_, hash table, record, struct, keyed list, or associative array. # 2. An ordered list of values. More commonly called an _array_, vector, sequence or list. # # To read more about JSON visit: http://json.org # # == Parsing JSON # # To parse a JSON string received by another application or generated within # your existing application: # # require 'json' # # my_hash = JSON.parse('{"hello": "goodbye"}') # puts my_hash["hello"] => "goodbye" # # Notice the extra quotes '' around the hash notation. Ruby expects # the argument to be a string and can't convert objects like a hash or array. # # Ruby converts your string into a hash # # == Generating JSON # # Creating a JSON string for communication or serialization is # just as simple. # # require 'json' # # my_hash = {:hello => "goodbye"} # puts JSON.generate(my_hash) => "{\"hello\":\"goodbye\"}" # # Or an alternative way: # # require 'json' # puts {:hello => "goodbye"}.to_json => "{\"hello\":\"goodbye\"}" # # JSON.generate only allows objects or arrays to be converted # to JSON syntax. to_json, however, accepts many Ruby classes # even though it acts only as a method for serialization: # # require 'json' # # 1.to_json => "1" # module JSON require 'json/version' begin require 'json/ext' rescue LoadError require 'json/pure' end end PK ]oaa*gems/json-2.3.0/lib/json/add/bigdecimal.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end defined?(::BigDecimal) or require 'bigdecimal' class BigDecimal # Import a JSON Marshalled object. # # method used for JSON marshalling support. def self.json_create(object) BigDecimal._load object['b'] end # Marshal the object to JSON. # # method used for JSON marshalling support. def as_json(*) { JSON.create_id => self.class.name, 'b' => _dump, } end # return the JSON value def to_json(*args) as_json.to_json(*args) end end PK ]&a\\$gems/json-2.3.0/lib/json/add/core.rbnu[#frozen_string_literal: false # This file requires the implementations of ruby core's custom objects for # serialisation/deserialisation. require 'json/add/date' require 'json/add/date_time' require 'json/add/exception' require 'json/add/range' require 'json/add/regexp' require 'json/add/struct' require 'json/add/symbol' require 'json/add/time' PK ]@9%&gems/json-2.3.0/lib/json/add/regexp.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Regexp # Deserializes JSON string by constructing new Regexp object with source # s (Regexp or String) and options o serialized by # to_json def self.json_create(object) new(object['s'], object['o']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'o' => options, 's' => source, } end # Stores class name (Regexp) with options o and source s # (Regexp or String) as JSON string def to_json(*args) as_json.to_json(*args) end end PK ]ff&gems/json-2.3.0/lib/json/add/symbol.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Symbol # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 's' => to_s, } end # Stores class name (Symbol) with String representation of Symbol as a JSON string. def to_json(*a) as_json.to_json(*a) end # Deserializes JSON string by converting the string value stored in the object to a Symbol def self.json_create(o) o['s'].to_sym end end PK ]m'gems/json-2.3.0/lib/json/add/ostruct.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end require 'ostruct' class OpenStruct # Deserializes JSON string by constructing new Struct object with values # t serialized by to_json. def self.json_create(object) new(object['t'] || object[:t]) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) klass = self.class.name klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!" { JSON.create_id => klass, 't' => table, } end # Stores class name (OpenStruct) with this struct's values t as a # JSON string. def to_json(*args) as_json.to_json(*args) end end PK ]V(gems/json-2.3.0/lib/json/add/rational.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end defined?(::Rational) or require 'rational' class Rational # Deserializes JSON string by converting numerator value n, # denominator value d, to a Rational object. def self.json_create(object) Rational(object['n'], object['d']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'n' => numerator, 'd' => denominator, } end # Stores class name (Rational) along with numerator value n and denominator value d as JSON string def to_json(*args) as_json.to_json(*args) end end PK ]&'gems/json-2.3.0/lib/json/add/complex.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end defined?(::Complex) or require 'complex' class Complex # Deserializes JSON string by converting Real value r, imaginary # value i, to a Complex object. def self.json_create(object) Complex(object['r'], object['i']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'r' => real, 'i' => imag, } end # Stores class name (Complex) along with real value r and imaginary value i as JSON string def to_json(*args) as_json.to_json(*args) end end PK ]k)gems/json-2.3.0/lib/json/add/exception.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Exception # Deserializes JSON string by constructing new Exception object with message # m and backtrace b serialized with to_json def self.json_create(object) result = new(object['m']) result.set_backtrace object['b'] result end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'm' => message, 'b' => backtrace, } end # Stores class name (Exception) with message m and backtrace array # b as JSON string def to_json(*args) as_json.to_json(*args) end end PK ]!!#gems/json-2.3.0/lib/json/add/set.rbnu[unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end defined?(::Set) or require 'set' class Set # Import a JSON Marshalled object. # # method used for JSON marshalling support. def self.json_create(object) new object['a'] end # Marshal the object to JSON. # # method used for JSON marshalling support. def as_json(*) { JSON.create_id => self.class.name, 'a' => to_a, } end # return the JSON value def to_json(*args) as_json.to_json(*args) end end PK ]J$gems/json-2.3.0/lib/json/add/time.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Time # Deserializes JSON string by converting time since epoch to Time def self.json_create(object) if usec = object.delete('u') # used to be tv_usec -> tv_nsec object['n'] = usec * 1000 end if method_defined?(:tv_nsec) at(object['s'], Rational(object['n'], 1000)) else at(object['s'], object['n'] / 1000) end end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) nanoseconds = [ tv_usec * 1000 ] respond_to?(:tv_nsec) and nanoseconds << tv_nsec nanoseconds = nanoseconds.max { JSON.create_id => self.class.name, 's' => tv_sec, 'n' => nanoseconds, } end # Stores class name (Time) with number of seconds since epoch and number of # microseconds for Time as JSON string def to_json(*args) as_json.to_json(*args) end end PK ]mqq$gems/json-2.3.0/lib/json/add/date.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end require 'date' class Date # Deserializes JSON string by converting Julian year y, month # m, day d and Day of Calendar Reform sg to Date. def self.json_create(object) civil(*object.values_at('y', 'm', 'd', 'sg')) end alias start sg unless method_defined?(:start) # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'y' => year, 'm' => month, 'd' => day, 'sg' => start, } end # Stores class name (Date) with Julian year y, month m, day # d and Day of Calendar Reform sg as JSON string def to_json(*args) as_json.to_json(*args) end end PK ]1+Ǔ00)gems/json-2.3.0/lib/json/add/date_time.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end require 'date' class DateTime # Deserializes JSON string by converting year y, month m, # day d, hour H, minute M, second S, # offset of and Day of Calendar Reform sg to DateTime. def self.json_create(object) args = object.values_at('y', 'm', 'd', 'H', 'M', 'S') of_a, of_b = object['of'].split('/') if of_b and of_b != '0' args << Rational(of_a.to_i, of_b.to_i) else args << of_a end args << object['sg'] civil(*args) end alias start sg unless method_defined?(:start) # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'y' => year, 'm' => month, 'd' => day, 'H' => hour, 'M' => min, 'S' => sec, 'of' => offset.to_s, 'sg' => start, } end # Stores class name (DateTime) with Julian year y, month m, # day d, hour H, minute M, second S, # offset of and Day of Calendar Reform sg as JSON string def to_json(*args) as_json.to_json(*args) end end PK ]a%gems/json-2.3.0/lib/json/add/range.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Range # Deserializes JSON string by constructing new Range object with arguments # a serialized by to_json. def self.json_create(object) new(*object['a']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'a' => [ first, last, exclude_end? ] } end # Stores class name (Range) with JSON array of arguments a which # include first (integer), last (integer), and # exclude_end? (boolean) as JSON string. def to_json(*args) as_json.to_json(*args) end end PK ]%&gems/json-2.3.0/lib/json/add/struct.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Struct # Deserializes JSON string by constructing new Struct object with values # v serialized by to_json. def self.json_create(object) new(*object['v']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) klass = self.class.name klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!" { JSON.create_id => klass, 'v' => values, } end # Stores class name (Struct) with Struct values v as a JSON string. # Only named structs are supported. def to_json(*args) as_json.to_json(*args) end end PK ]Ht..#gems/json-2.3.0/lib/json/version.rbnu[# frozen_string_literal: false module JSON # JSON version VERSION = '2.3.0' VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc: VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc: VERSION_MINOR = VERSION_ARRAY[1] # :nodoc: VERSION_BUILD = VERSION_ARRAY[2] # :nodoc: end PK ];;"gems/json-2.3.0/lib/json/common.rbnu[#frozen_string_literal: false require 'json/version' require 'json/generic_object' module JSON class << self # If _object_ is string-like, parse the string and return the parsed # result as a Ruby data structure. Otherwise generate a JSON text from the # Ruby data structure object and return it. # # The _opts_ argument is passed through to generate/parse respectively. # See generate and parse for their documentation. def [](object, opts = {}) if object.respond_to? :to_str JSON.parse(object.to_str, opts) else JSON.generate(object, opts) end end # Returns the JSON parser class that is used by JSON. This is either # JSON::Ext::Parser or JSON::Pure::Parser. attr_reader :parser # Set the JSON parser class _parser_ to be used by JSON. def parser=(parser) # :nodoc: @parser = parser remove_const :Parser if const_defined?(:Parser, false) const_set :Parser, parser end # Return the constant located at _path_. The format of _path_ has to be # either ::A::B::C or A::B::C. In any case, A has to be located at the top # level (absolute namespace path?). If there doesn't exist a constant at # the given path, an ArgumentError is raised. def deep_const_get(path) # :nodoc: path.to_s.split(/::/).inject(Object) do |p, c| case when c.empty? then p when p.const_defined?(c, true) then p.const_get(c) else begin p.const_missing(c) rescue NameError => e raise ArgumentError, "can't get const #{path}: #{e}" end end end end # Set the module _generator_ to be used by JSON. def generator=(generator) # :nodoc: old, $VERBOSE = $VERBOSE, nil @generator = generator generator_methods = generator::GeneratorMethods for const in generator_methods.constants klass = deep_const_get(const) modul = generator_methods.const_get(const) klass.class_eval do instance_methods(false).each do |m| m.to_s == 'to_json' and remove_method m end include modul end end self.state = generator::State const_set :State, self.state const_set :SAFE_STATE_PROTOTYPE, State.new const_set :FAST_STATE_PROTOTYPE, State.new( :indent => '', :space => '', :object_nl => "", :array_nl => "", :max_nesting => false ) const_set :PRETTY_STATE_PROTOTYPE, State.new( :indent => ' ', :space => ' ', :object_nl => "\n", :array_nl => "\n" ) ensure $VERBOSE = old end # Returns the JSON generator module that is used by JSON. This is # either JSON::Ext::Generator or JSON::Pure::Generator. attr_reader :generator # Returns the JSON generator state class that is used by JSON. This is # either JSON::Ext::Generator::State or JSON::Pure::Generator::State. attr_accessor :state # This is create identifier, which is used to decide if the _json_create_ # hook of a class should be called. It defaults to 'json_class'. attr_accessor :create_id end self.create_id = 'json_class' NaN = 0.0/0 Infinity = 1.0/0 MinusInfinity = -Infinity # The base exception for JSON errors. class JSONError < StandardError def self.wrap(exception) obj = new("Wrapped(#{exception.class}): #{exception.message.inspect}") obj.set_backtrace exception.backtrace obj end end # This exception is raised if a parser error occurs. class ParserError < JSONError; end # This exception is raised if the nesting of parsed data structures is too # deep. class NestingError < ParserError; end # :stopdoc: class CircularDatastructure < NestingError; end # :startdoc: # This exception is raised if a generator or unparser error occurs. class GeneratorError < JSONError; end # For backwards compatibility UnparserError = GeneratorError # This exception is raised if the required unicode support is missing on the # system. Usually this means that the iconv library is not installed. class MissingUnicodeSupport < JSONError; end module_function # Parse the JSON document _source_ into a Ruby data structure and return it. # # _opts_ can have the following # keys: # * *max_nesting*: The maximum depth of nesting allowed in the parsed data # structures. Disable depth checking with :max_nesting => false. It # defaults to 100. # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in # defiance of RFC 7159 to be parsed by the Parser. This option defaults # to false. # * *symbolize_names*: If set to true, returns symbols for the names # (keys) in a JSON object. Otherwise strings are returned. Strings are # the default. # * *create_additions*: If set to false, the Parser doesn't create # additions even if a matching class and create_id was found. This option # defaults to false. # * *object_class*: Defaults to Hash # * *array_class*: Defaults to Array def parse(source, opts = {}) Parser.new(source, **(opts||{})).parse end # Parse the JSON document _source_ into a Ruby data structure and return it. # The bang version of the parse method defaults to the more dangerous values # for the _opts_ hash, so be sure only to parse trusted _source_ documents. # # _opts_ can have the following keys: # * *max_nesting*: The maximum depth of nesting allowed in the parsed data # structures. Enable depth checking with :max_nesting => anInteger. The # parse! methods defaults to not doing max depth checking: This can be # dangerous if someone wants to fill up your stack. # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in # defiance of RFC 7159 to be parsed by the Parser. This option defaults # to true. # * *create_additions*: If set to false, the Parser doesn't create # additions even if a matching class and create_id was found. This option # defaults to false. def parse!(source, opts = {}) opts = { :max_nesting => false, :allow_nan => true }.merge(opts) Parser.new(source, **(opts||{})).parse end # Generate a JSON document from the Ruby data structure _obj_ and return # it. _state_ is * a JSON::State object, # * or a Hash like object (responding to to_hash), # * an object convertible into a hash by a to_h method, # that is used as or to configure a State object. # # It defaults to a state object, that creates the shortest possible JSON text # in one line, checks for circular data structures and doesn't allow NaN, # Infinity, and -Infinity. # # A _state_ hash can have the following keys: # * *indent*: a string used to indent levels (default: ''), # * *space*: a string that is put after, a : or , delimiter (default: ''), # * *space_before*: a string that is put before a : pair delimiter (default: ''), # * *object_nl*: a string that is put at the end of a JSON object (default: ''), # * *array_nl*: a string that is put at the end of a JSON array (default: ''), # * *allow_nan*: true if NaN, Infinity, and -Infinity should be # generated, otherwise an exception is thrown if these values are # encountered. This options defaults to false. # * *max_nesting*: The maximum depth of nesting allowed in the data # structures from which JSON is to be generated. Disable depth checking # with :max_nesting => false, it defaults to 100. # # See also the fast_generate for the fastest creation method with the least # amount of sanity checks, and the pretty_generate method for some # defaults for pretty output. def generate(obj, opts = nil) if State === opts state, opts = opts, nil else state = SAFE_STATE_PROTOTYPE.dup end if opts if opts.respond_to? :to_hash opts = opts.to_hash elsif opts.respond_to? :to_h opts = opts.to_h else raise TypeError, "can't convert #{opts.class} into Hash" end state = state.configure(opts) end state.generate(obj) end # :stopdoc: # I want to deprecate these later, so I'll first be silent about them, and # later delete them. alias unparse generate module_function :unparse # :startdoc: # Generate a JSON document from the Ruby data structure _obj_ and return it. # This method disables the checks for circles in Ruby objects. # # *WARNING*: Be careful not to pass any Ruby data structures with circles as # _obj_ argument because this will cause JSON to go into an infinite loop. def fast_generate(obj, opts = nil) if State === opts state, opts = opts, nil else state = FAST_STATE_PROTOTYPE.dup end if opts if opts.respond_to? :to_hash opts = opts.to_hash elsif opts.respond_to? :to_h opts = opts.to_h else raise TypeError, "can't convert #{opts.class} into Hash" end state.configure(opts) end state.generate(obj) end # :stopdoc: # I want to deprecate these later, so I'll first be silent about them, and later delete them. alias fast_unparse fast_generate module_function :fast_unparse # :startdoc: # Generate a JSON document from the Ruby data structure _obj_ and return it. # The returned document is a prettier form of the document returned by # #unparse. # # The _opts_ argument can be used to configure the generator. See the # generate method for a more detailed explanation. def pretty_generate(obj, opts = nil) if State === opts state, opts = opts, nil else state = PRETTY_STATE_PROTOTYPE.dup end if opts if opts.respond_to? :to_hash opts = opts.to_hash elsif opts.respond_to? :to_h opts = opts.to_h else raise TypeError, "can't convert #{opts.class} into Hash" end state.configure(opts) end state.generate(obj) end # :stopdoc: # I want to deprecate these later, so I'll first be silent about them, and later delete them. alias pretty_unparse pretty_generate module_function :pretty_unparse # :startdoc: class << self # The global default options for the JSON.load method: # :max_nesting: false # :allow_nan: true # :allow_blank: true attr_accessor :load_default_options end self.load_default_options = { :max_nesting => false, :allow_nan => true, :allow_blank => true, :create_additions => true, } # Load a ruby data structure from a JSON _source_ and return it. A source can # either be a string-like object, an IO-like object, or an object responding # to the read method. If _proc_ was given, it will be called with any nested # Ruby object as an argument recursively in depth first order. To modify the # default options pass in the optional _options_ argument as well. # # BEWARE: This method is meant to serialise data from trusted user input, # like from your own database server or clients under your control, it could # be dangerous to allow untrusted users to pass JSON sources into it. The # default options for the parser can be changed via the load_default_options # method. # # This method is part of the implementation of the load/dump interface of # Marshal and YAML. def load(source, proc = nil, options = {}) opts = load_default_options.merge options if source.respond_to? :to_str source = source.to_str elsif source.respond_to? :to_io source = source.to_io.read elsif source.respond_to?(:read) source = source.read end if opts[:allow_blank] && (source.nil? || source.empty?) source = 'null' end result = parse(source, opts) recurse_proc(result, &proc) if proc result end # Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_ def recurse_proc(result, &proc) case result when Array result.each { |x| recurse_proc x, &proc } proc.call result when Hash result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc } proc.call result else proc.call result end end alias restore load module_function :restore class << self # The global default options for the JSON.dump method: # :max_nesting: false # :allow_nan: true # :allow_blank: true attr_accessor :dump_default_options end self.dump_default_options = { :max_nesting => false, :allow_nan => true, } # Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns # the result. # # If anIO (an IO-like object or an object that responds to the write method) # was given, the resulting JSON is written to it. # # If the number of nested arrays or objects exceeds _limit_, an ArgumentError # exception is raised. This argument is similar (but not exactly the # same!) to the _limit_ argument in Marshal.dump. # # The default options for the generator can be changed via the # dump_default_options method. # # This method is part of the implementation of the load/dump interface of # Marshal and YAML. def dump(obj, anIO = nil, limit = nil) if anIO and limit.nil? anIO = anIO.to_io if anIO.respond_to?(:to_io) unless anIO.respond_to?(:write) limit = anIO anIO = nil end end opts = JSON.dump_default_options opts = opts.merge(:max_nesting => limit) if limit result = generate(obj, opts) if anIO anIO.write result anIO else result end rescue JSON::NestingError raise ArgumentError, "exceed depth limit" end # Encodes string using Ruby's _String.encode_ def self.iconv(to, from, string) string.encode(to, from) end end module ::Kernel private # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in # one line. def j(*objs) objs.each do |obj| puts JSON::generate(obj, :allow_nan => true, :max_nesting => false) end nil end # Outputs _objs_ to STDOUT as JSON strings in a pretty format, with # indentation and over many lines. def jj(*objs) objs.each do |obj| puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false) end nil end # If _object_ is string-like, parse the string and return the parsed result as # a Ruby data structure. Otherwise, generate a JSON text from the Ruby data # structure object and return it. # # The _opts_ argument is passed through to generate/parse respectively. See # generate and parse for their documentation. def JSON(object, *args) if object.respond_to? :to_str JSON.parse(object.to_str, args.first) else JSON.generate(object, args.first) end end end # Extends any Class to include _json_creatable?_ method. class ::Class # Returns true if this class can be used to create an instance # from a serialised JSON string. The class has to implement a class # method _json_create_ that expects a hash as first parameter. The hash # should include the required data. def json_creatable? respond_to?(:json_create) end end PK ]1zgems/json-2.3.0/lib/json/ext.rbnu[require 'json/common' module JSON # This module holds all the modules/classes that implement JSON's # functionality as C extensions. module Ext require 'json/ext/parser' require 'json/ext/generator' $DEBUG and warn "Using Ext extension for JSON." JSON.parser = Parser JSON.generator = Generator end JSON_LOADED = true unless defined?(::JSON::JSON_LOADED) end PK ]E”*gems/json-2.3.0/lib/json/generic_object.rbnu[#frozen_string_literal: false require 'ostruct' module JSON class GenericObject < OpenStruct class << self alias [] new def json_creatable? @json_creatable end attr_writer :json_creatable def json_create(data) data = data.dup data.delete JSON.create_id self[data] end def from_hash(object) case when object.respond_to?(:to_hash) result = new object.to_hash.each do |key, value| result[key] = from_hash(value) end result when object.respond_to?(:to_ary) object.to_ary.map { |a| from_hash(a) } else object end end def load(source, proc = nil, opts = {}) result = ::JSON.load(source, proc, opts.merge(:object_class => self)) result.nil? ? new : result end def dump(obj, *args) ::JSON.dump(obj, *args) end end self.json_creatable = false def to_hash table end def [](name) __send__(name) end unless method_defined?(:[]) def []=(name, value) __send__("#{name}=", value) end unless method_defined?(:[]=) def |(other) self.class[other.to_hash.merge(to_hash)] end def as_json(*) { JSON.create_id => self.class.name }.merge to_hash end def to_json(*a) as_json.to_json(*a) end end end PK ]%Bqqgems/power_assert-1.1.7/LEGALnu[LEGAL NOTICE INFORMATION ------------------------ All the files in this distribution are written by the author. PK ]Vgems/power_assert-1.1.7/Gemfilenu[source "http://rubygems.org" gemspec # https://github.com/redmine/redmine/blob/3.0.4/Gemfile#L101 local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local") if File.exist?(local_gemfile) eval_gemfile local_gemfile end PK ]X gems/power_assert-1.1.7/Rakefilenu[require "bundler/gem_tasks" require "rake/testtask" task :default => :test Rake::TestTask.new(:test) do |t| # helper(simplecov) must be required before loading power_assert helper_path = File.realpath("test/test_helper.rb") t.ruby_opts = ["-w", "-r#{helper_path}"] t.test_files = FileList["test/**/*_test.rb"].exclude do |i| begin next false unless defined?(RubyVM) RubyVM::InstructionSequence.compile(File.read(i)) false rescue SyntaxError true end end end # ruby/ruby:test/pathname/test_pathname.rb def has_symlink? begin File.symlink("", "") rescue NotImplementedError, Errno::EACCES return false rescue Errno::ENOENT end return true end SYMLINK_DIRS = ["lib", "test"] task :before_script do if ENV["TEST_SYMLINK"] == "yes" and has_symlink? SYMLINK_DIRS.each do |d| File.rename(d, ".#{d}") File.symlink(".#{d}", d) end end end task :after_script do SYMLINK_DIRS.each do |d| if File.symlink?(d) and File.directory?(".#{d}") File.unlink(d) File.rename(".#{d}", d) end unless File.directory?(d) raise "#{d} should be directory" end end end desc "Run the benchmark suite" task :benchmark do Dir.glob("benchmark/bm_*.rb").each do |f| load(f) end end PK ]*Dgems/power_assert-1.1.7/BSDLnu[Copyright (C) 2014 Kazuki Tsujimoto Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PK ]|m# # #gems/power_assert-1.1.7/README.rdocnu[= power_assert == About Power Assert for Ruby. Power Assert shows each value of variables and method calls in the expression. It is useful for testing, providing which value wasn't correct when the condition is not satisfied. Failure: assert { 3.times.to_a.include?(3) } | | | | | false | [0, 1, 2] # == Related Projects In general, you don't need to use this library directly. Use following test frameworks or extensions instead. * {test-unit}[https://github.com/test-unit/test-unit](>= 3.0.0) * {Document}[http://test-unit.github.io/test-unit/en/Test/Unit/Assertions.html#assert-instance_method] * {minitest-power_assert}[https://github.com/hsbt/minitest-power_assert] * {rspec-power_assert}[https://github.com/joker1007/rspec-power_assert] * {pry-power_assert}[https://github.com/yui-knk/pry-power_assert] * {pry-byebug-power_assert}[https://github.com/k-tsj/pry-byebug-power_assert] * {power_p}[https://github.com/k-tsj/power_p] == Requirement * CRuby 2.0.0 or later == Reference * {Power Assert in Ruby (at RubyKaigi 2014) // Speaker Deck}[https://speakerdeck.com/k_tsj/power-assert-in-ruby] == Known Limitations * Expressions must be put in one line. Expressions with folded long lines produce nothing report, e.g.: assert do # reported func(foo: 0123456789, bar: "abcdefg") end assert do # won't be reported func(foo: 0123456789, bar: "abcdefg") end * Expressions must have one or more method call. Expressions with no method call produce nothing report, e.g.: val = false assert do # reported val == true end assert do # won't be reported val end * Returned values from accessor methods, method missing, or "super" produce nothing report, e.g: class Foo attr_accessor :val end foo = Foo.new foo.val = false assert do # reported (only the value of "foo" and the literal "true") foo.val == true end assert do # won't be reported foo.val end * Expressions should not have conditional branches. Expressions with such conditional codes may produce nothing report, e.g.: condition = true expected = false actual = true assert do # this will fail but nothing reported condition ? expected == actual : expected == actual end == Travis Build Status {}[http://travis-ci.org/k-tsj/power_assert] PK ] b gems/power_assert-1.1.7/COPYINGnu[Copyright (C) 2014 Kazuki Tsujimoto You can redistribute it and/or modify it under either the terms of the 2-clause BSDL (see the file BSDL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. PK ]mޮ ,gems/power_assert-1.1.7/power_assert.gemspecnu[# -*- encoding: utf-8 -*- # stub: power_assert 1.1.7 ruby lib Gem::Specification.new do |s| s.name = "power_assert".freeze s.version = "1.1.7" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kazuki Tsujimoto".freeze] s.bindir = "exe".freeze s.date = "2020-03-22" s.description = "Power Assert for Ruby. Power Assert shows each value of variables and method calls in the expression. It is useful for testing, providing which value wasn't correct when the condition is not satisfied.".freeze s.email = ["kazuki@callcc.net".freeze] s.extra_rdoc_files = ["README.rdoc".freeze] s.files = [".gitignore".freeze, ".travis.yml".freeze, "BSDL".freeze, "COPYING".freeze, "Gemfile".freeze, "LEGAL".freeze, "README.rdoc".freeze, "Rakefile".freeze, "bin/console".freeze, "bin/setup".freeze, "lib/power_assert.rb".freeze, "lib/power_assert/colorize.rb".freeze, "lib/power_assert/configuration.rb".freeze, "lib/power_assert/context.rb".freeze, "lib/power_assert/enable_tracepoint_events.rb".freeze, "lib/power_assert/inspector.rb".freeze, "lib/power_assert/parser.rb".freeze, "lib/power_assert/version.rb".freeze, "power_assert.gemspec".freeze] s.homepage = "https://github.com/k-tsj/power_assert".freeze s.licenses = ["2-clause BSDL".freeze, "Ruby's".freeze] s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] s.rubygems_version = "3.3.5".freeze s.summary = "Power Assert for Ruby".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]t/;JJ!gems/power_assert-1.1.7/bin/setupnu[#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install PK ]9\#gems/power_assert-1.1.7/bin/consolenu[#!/usr/bin/env ruby require 'bundler/setup' require 'power_assert' begin require 'pry' Pry rescue LoadError require 'irb' IRB end.start PK ]»13gems/power_assert-1.1.7/lib/power_assert/context.rbnu[require 'power_assert/configuration' require 'power_assert/enable_tracepoint_events' require 'power_assert/inspector' require 'power_assert/parser' module PowerAssert class Context Value = Struct.new(:name, :value, :lineno, :column, :display_offset) def initialize(base_caller_length) @fired = false @target_thread = Thread.current method_id_set = nil @return_values = [] trace_alias_method = PowerAssert.configuration._trace_alias_method @trace_return = TracePoint.new(:return, :c_return) do |tp| begin unless method_id_set next unless Thread.current == @target_thread method_id_set = @parser.method_id_set end method_id = SUPPORT_ALIAS_METHOD ? tp.callee_id : trace_alias_method && tp.event == :return ? tp.binding.eval('::Kernel.__callee__') : tp.method_id next if ! method_id_set[method_id] next if tp.event == :c_return and not (@parser.lineno == tp.lineno and @parser.path == tp.path) locs = PowerAssert.app_caller_locations diff = locs.length - base_caller_length if (tp.event == :c_return && diff == 1 || tp.event == :return && diff <= 2) and Thread.current == @target_thread idx = -(base_caller_length + 1) if @parser.path == locs[idx].path and @parser.lineno == locs[idx].lineno val = PowerAssert.configuration.lazy_inspection ? tp.return_value : InspectedValue.new(SafeInspectable.new(tp.return_value).inspect) @return_values << Value[method_id.to_s, val, locs[idx].lineno, nil] end end rescue Exception => e warn "power_assert: [BUG] Failed to trace: #{e.class}: #{e.message}" if e.respond_to?(:full_message) warn e.full_message.gsub(/^/, 'power_assert: ') end end end end def message raise 'call #yield or #enable at first' unless fired? @message ||= build_assertion_message(@parser, @return_values).freeze end def message_proc -> { message } end private def fired? @fired end def build_assertion_message(parser, return_values) if PowerAssert.configuration._colorize_message line = Pry::Code.new(parser.line).highlighted else line = parser.line end path = detect_path(parser, return_values) return line unless path c2d = column2display_offset(parser.line) return_values, methods_in_path = find_all_identified_calls(return_values, path) return_values.zip(methods_in_path) do |i, j| unless i.name == j.name warn "power_assert: [BUG] Failed to get column: #{i.name}" return line end i.display_offset = c2d[j.column] end refs_in_path = path.find_all {|i| i.type == :ref } ref_values = refs_in_path.map {|i| Value[i.name, parser.binding.eval(i.name), parser.lineno, i.column, c2d[i.column]] } vals = (return_values + ref_values).find_all(&:display_offset).sort_by(&:display_offset).reverse return line if vals.empty? fmt = (0..vals[0].display_offset).map do |i| if vals.find {|v| v.display_offset == i } "%<#{i}>s" else line[i] == "\t" ? "\t" : ' ' end end.join lines = [] lines << line.chomp lines << sprintf(fmt, vals.each_with_object({}) {|v, h| h[v.display_offset.to_s.to_sym] = '|' }).chomp vals.each do |i| inspected_val = SafeInspectable.new(Formatter.new(i.value, i.display_offset)).inspect inspected_val.each_line do |l| map_to = vals.each_with_object({}) do |j, h| h[j.display_offset.to_s.to_sym] = [l, '|', ' '][i.display_offset <=> j.display_offset] end lines << encoding_safe_rstrip(sprintf(fmt, map_to)) end end lines.join("\n") end def detect_path(parser, return_values) return parser.call_paths.flatten.uniq if parser.method_id_set.empty? all_paths = parser.call_paths return_value_names = return_values.map(&:name) uniq_calls = uniq_calls(all_paths) uniq_call = return_value_names.find {|i| uniq_calls.include?(i) } detected_paths = all_paths.find_all do |path| method_names = path.find_all {|ident| ident.type == :method }.map(&:name) break [path] if uniq_call and method_names.include?(uniq_call) return_value_names == method_names end return nil unless detected_paths.length == 1 detected_paths[0] end def uniq_calls(paths) all_calls = enum_count_by(paths.map {|path| path.find_all {|ident| ident.type == :method }.map(&:name).uniq }.flatten) {|i| i } all_calls.find_all {|_, call_count| call_count == 1 }.map {|name, _| name } end def find_all_identified_calls(return_values, path) return_value_num_of_calls = enum_count_by(return_values, &:name) path_num_of_calls = enum_count_by(path.find_all {|ident| ident.type == :method }, &:name) identified_calls = return_value_num_of_calls.find_all {|name, num| path_num_of_calls[name] == num }.map(&:first) [ return_values.find_all {|val| identified_calls.include?(val.name) }, path.find_all {|ident| ident.type == :method and identified_calls.include?(ident.name) } ] end def enum_count_by(enum, &blk) Hash[enum.group_by(&blk).map{|k, v| [k, v.length] }] end def encoding_safe_rstrip(str) str.rstrip rescue ArgumentError, Encoding::CompatibilityError enc = str.encoding if enc.ascii_compatible? str.b.rstrip.force_encoding(enc) else str end end def column2display_offset(str) display_offset = 0 str.each_char.with_object([]) do |c, r| c.bytesize.times do r << display_offset end display_offset += c.ascii_only? ? 1 : 2 # FIXME end end end private_constant :Context class BlockContext < Context def initialize(assertion_proc_or_source, assertion_method, source_binding) super(0) if assertion_proc_or_source.respond_to?(:to_proc) @assertion_proc = assertion_proc_or_source.to_proc line = nil else @assertion_proc = source_binding.eval "Proc.new {#{assertion_proc_or_source}}" line = assertion_proc_or_source end @parser = Parser::DUMMY @trace_call = TracePoint.new(:call, :c_call) do if PowerAssert.app_context? and Thread.current == @target_thread @trace_call.disable locs = PowerAssert.app_caller_locations path = locs.last.path lineno = locs.last.lineno if File.exist?(path) line ||= File.open(path) {|fp| fp.each_line.drop(lineno - 1).first } end if line @parser = Parser.new(line, path, lineno, @assertion_proc.binding, assertion_method.to_s, @assertion_proc) end end end end def yield @fired = true invoke_yield(&@assertion_proc) end private def invoke_yield @trace_return.enable do @trace_call.enable do yield end end end end private_constant :BlockContext class TraceContext < Context def initialize(binding) target_frame, *base = PowerAssert.app_caller_locations super(base.length) path = target_frame.path lineno = target_frame.lineno if File.exist?(path) line = File.open(path) {|fp| fp.each_line.drop(lineno - 1).first } @parser = Parser.new(line, path, lineno, binding) else @parser = Parser::DUMMY end end def enable @fired = true @trace_return.enable end def disable @trace_return.disable end def enabled? @trace_return.enabled? end end private_constant :TraceContext end PK ]g^2gems/power_assert-1.1.7/lib/power_assert/parser.rbnu[require 'ripper' module PowerAssert class Parser Ident = Struct.new(:type, :name, :column) attr_reader :line, :path, :lineno, :binding def initialize(line, path, lineno, binding, assertion_method_name = nil, assertion_proc = nil) @line = line @line_for_parsing = (valid_syntax?(line) ? line : slice_expression(line)).b @path = path @lineno = lineno @binding = binding @proc_local_variables = binding.eval('local_variables').map(&:to_s) @assertion_method_name = assertion_method_name @assertion_proc = assertion_proc end def idents @idents ||= extract_idents(Ripper.sexp(@line_for_parsing)) end def call_paths collect_paths(idents).uniq end def method_id_set methods = idents.flatten.find_all {|i| i.type == :method } @method_id_set ||= methods.map(&:name).map(&:to_sym).each_with_object({}) {|i, h| h[i] = true } end private def valid_syntax?(str) return true unless defined?(RubyVM) begin verbose, $VERBOSE = $VERBOSE, nil RubyVM::InstructionSequence.compile(str) true rescue SyntaxError false ensure $VERBOSE = verbose end end def slice_expression(str) str = str.chomp str.sub!(/\A\s*(?:if|unless|elsif|case|while|until) /) {|i| ' ' * i.length } str.sub!(/\A\s*(?:\}|\]|end)?\./) {|i| ' ' * i.length } str.sub!(/[\{\.\\]\z/, '') str.sub!(/(?:&&|\|\|)\z/, '') str.sub!(/ (?:do|and|or)\z/, '') str end class Branch < Array end AND_OR_OPS = %i(and or && ||) # # Returns idents as graph structure. # # +--c--b--+ # extract_idents(Ripper.sexp('a&.b(c).d')) #=> a--+ +--d # +--------+ # def extract_idents(sexp) tag, * = sexp case tag when :arg_paren, :assoc_splat, :fcall, :hash, :method_add_block, :string_literal, :return extract_idents(sexp[1]) when :assign, :massign extract_idents(sexp[2]) when :opassign _, _, (_, op_name, (_, op_column)), s0 = sexp extract_idents(s0) + [Ident[:method, op_name.sub(/=\z/, ''), op_column]] when :dyna_symbol if sexp[1][0].kind_of?(Symbol) # sexp[1] can be [:string_content, [..]] while parsing { "a": 1 } extract_idents(sexp[1]) else sexp[1].flat_map {|s| extract_idents(s) } end when :assoclist_from_args, :bare_assoc_hash, :paren, :string_embexpr, :regexp_literal, :xstring_literal sexp[1].flat_map {|s| extract_idents(s) } when :command [sexp[2], sexp[1]].flat_map {|s| extract_idents(s) } when :assoc_new, :dot2, :dot3, :string_content sexp[1..-1].flat_map {|s| extract_idents(s) } when :unary handle_columnless_ident([], sexp[1], extract_idents(sexp[2])) when :binary op = sexp[2] if AND_OR_OPS.include?(op) extract_idents(sexp[1]) + [Branch[extract_idents(sexp[3]), []]] else handle_columnless_ident(extract_idents(sexp[1]), op, extract_idents(sexp[3])) end when :call _, recv, (op_sym, op_name, _), method = sexp with_safe_op = ((op_sym == :@op and op_name == '&.') or op_sym == :"&.") if method == :call handle_columnless_ident(extract_idents(recv), :call, [], with_safe_op) else extract_idents(recv) + (with_safe_op ? [Branch[extract_idents(method), []]] : extract_idents(method)) end when :array sexp[1] ? sexp[1].flat_map {|s| extract_idents(s) } : [] when :command_call [sexp[1], sexp[4], sexp[3]].flat_map {|s| extract_idents(s) } when :aref handle_columnless_ident(extract_idents(sexp[1]), :[], extract_idents(sexp[2])) when :method_add_arg idents = extract_idents(sexp[1]) if idents.empty? # idents may be empty(e.g. ->{}.()) extract_idents(sexp[2]) else if idents[-1].kind_of?(Branch) and idents[-1][1].empty? # Safe navigation operator is used. See :call clause also. idents[0..-2] + [Branch[extract_idents(sexp[2]) + idents[-1][0], []]] else idents[0..-2] + extract_idents(sexp[2]) + [idents[-1]] end end when :args_add_block _, (tag, ss0, *ss1), _ = sexp if tag == :args_add_star (ss0 + ss1).flat_map {|s| extract_idents(s) } else sexp[1].flat_map {|s| extract_idents(s) } end when :vcall _, (tag, name, (_, column)) = sexp if tag == :@ident [Ident[@proc_local_variables.include?(name) ? :ref : :method, name, column]] else [] end when :program _, ((tag0, (tag1, (tag2, (tag3, mname, _)), _), (tag4, _, ss))) = sexp if tag0 == :method_add_block and tag1 == :method_add_arg and tag2 == :fcall and (tag3 == :@ident or tag3 == :@const) and mname == @assertion_method_name and (tag4 == :brace_block or tag4 == :do_block) ss.flat_map {|s| extract_idents(s) } else _, (s0, *) = sexp extract_idents(s0) end when :ifop _, s0, s1, s2 = sexp [*extract_idents(s0), Branch[extract_idents(s1), extract_idents(s2)]] when :if, :unless _, s0, ss0, (_, ss1) = sexp [*extract_idents(s0), Branch[ss0.flat_map {|s| extract_idents(s) }, ss1 ? ss1.flat_map {|s| extract_idents(s) } : []]] when :if_mod, :unless_mod _, s0, s1 = sexp [*extract_idents(s0), Branch[extract_idents(s1), []]] when :var_ref, :var_field _, (tag, ref_name, (_, column)) = sexp case tag when :@kw if ref_name == 'self' [Ident[:ref, 'self', column]] else [] end when :@ident, :@const, :@cvar, :@ivar, :@gvar [Ident[:ref, ref_name, column]] else [] end when :@ident, :@const, :@op _, method_name, (_, column) = sexp [Ident[:method, method_name, column]] else [] end end def str_indices(str, re, offset, limit) idx = str.index(re, offset) if idx and idx <= limit [idx, *str_indices(str, re, idx + 1, limit)] else [] end end MID2SRCTXT = { :[] => '[', :+@ => '+', :-@ => '-', :call => '(' } def handle_columnless_ident(left_idents, mid, right_idents, with_safe_op = false) left_max = left_idents.flatten.max_by(&:column) right_min = right_idents.flatten.min_by(&:column) bg = left_max ? left_max.column + left_max.name.length : 0 ed = right_min ? right_min.column - 1 : @line_for_parsing.length - 1 mname = mid.to_s srctxt = MID2SRCTXT[mid] || mname re = / #{'\b' if /\A\w/ =~ srctxt} #{Regexp.escape(srctxt)} #{'\b' if /\w\z/ =~ srctxt} /x indices = str_indices(@line_for_parsing, re, bg, ed) if indices.length == 1 or !(right_idents.empty? and left_idents.empty?) ident = Ident[:method, mname, right_idents.empty? ? indices.first : indices.last] left_idents + right_idents + (with_safe_op ? [Branch[[ident], []]] : [ident]) else left_idents + right_idents end end def collect_paths(idents, prefixes = [[]], index = 0) if index < idents.length node = idents[index] if node.kind_of?(Branch) prefixes = node.flat_map {|n| collect_paths(n, prefixes, 0) } else prefixes = prefixes.map {|prefix| prefix + [node] } end collect_paths(idents, prefixes, index + 1) else prefixes end end class DummyParser < Parser def initialize super('', nil, nil, TOPLEVEL_BINDING) end def idents [] end def call_paths [] end end DUMMY = DummyParser.new end private_constant :Parser end PK ]S/++3gems/power_assert-1.1.7/lib/power_assert/version.rbnu[module PowerAssert VERSION = "1.1.7" end PK ]!4gems/power_assert-1.1.7/lib/power_assert/colorize.rbnu[warn 'power_assert/colorize is experimental' require 'power_assert/configuration' PowerAssert.configure do |c| c.lazy_inspection = true c._colorize_message = true c._use_pp = true end PK ]{%}}WW9gems/power_assert-1.1.7/lib/power_assert/configuration.rbnu[module PowerAssert class << self def configuration @configuration ||= Configuration[false, false, true, false, false] end def configure yield configuration end end SUPPORT_ALIAS_METHOD = TracePoint.public_method_defined?(:callee_id) private_constant :SUPPORT_ALIAS_METHOD class Configuration < Struct.new(:lazy_inspection, :_trace_alias_method, :_redefinition, :_colorize_message, :_use_pp) def _trace_alias_method=(bool) super if SUPPORT_ALIAS_METHOD warn 'power_assert: _trace_alias_method option is obsolete. You no longer have to set it.' end end def _colorize_message=(bool) if bool require 'pry' end super end def lazy_inspection=(bool) unless bool raise 'lazy_inspection option must be enabled when using pp' if _use_pp end super end def _use_pp=(bool) if bool raise 'lazy_inspection option must be enabled when using pp' unless lazy_inspection require 'pp' end super end end private_constant :Configuration end PK ]^-  Dgems/power_assert-1.1.7/lib/power_assert/enable_tracepoint_events.rbnu[require 'power_assert/configuration' if defined?(RubyVM) if PowerAssert.configuration._redefinition if RUBY_VERSION == '2.3.2' warn 'power_assert: It is strongly recommended that you use Ruby 2.3.3 or later which fixes regression on 2.3.2.' warn 'power_assert: See https://www.ruby-lang.org/en/news/2016/11/21/ruby-2-3-3-released/ for more details.' end verbose = $VERBOSE begin $VERBOSE = nil module PowerAssert # set redefined flag basic_classes = [ Fixnum, Float, String, Array, Hash, Bignum, Symbol, Time, Regexp, NilClass, TrueClass, FalseClass ] basic_operators = [ :+, :-, :*, :/, :%, :==, :===, :<, :<=, :<<, :[], :[]=, :length, :size, :empty?, :succ, :>, :>=, :!, :!=, :=~, :freeze, :-@, :max, :min, :nil? ] bug11182 = Class.new do def fixed? true end end refine bug11182 do def fixed? end end _ = Class.new(bug11182) do alias _fixed? fixed? protected :_fixed? end if (bug11182.new.fixed? rescue false) basic_classes.each do |klass| basic_operators.each do |bop| if klass.public_method_defined?(bop) refine(klass) do define_method(bop) {} end end end end else # workaround for https://bugs.ruby-lang.org/issues/11182 basic_classes.each do |klass| basic_operators.each do |bop| if klass.public_method_defined?(bop) klass.ancestors.find {|i| i.instance_methods(false).index(bop) }.module_eval do public bop end end end end refine Symbol do def == end end end # bypass check_cfunc refine BasicObject do def ! end def == end end refine Module do def == end end end ensure $VERBOSE = verbose end end # disable optimization RubyVM::InstructionSequence.compile_option = { specialized_instruction: false } end PK ]G5gems/power_assert-1.1.7/lib/power_assert/inspector.rbnu[require 'power_assert/configuration' module PowerAssert class InspectedValue def initialize(value) @value = value end def inspect @value end end private_constant :InspectedValue class SafeInspectable def initialize(value) @value = value end def inspect inspected = @value.inspect if Encoding.compatible?(Encoding.default_external, inspected) inspected else begin "#{inspected.encode(Encoding.default_external)}(#{inspected.encoding})" rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError inspected.force_encoding(Encoding.default_external) end end rescue => e "InspectionFailure: #{e.class}: #{e.message.each_line.first}" end end private_constant :SafeInspectable class Formatter def initialize(value, indent) @value = value @indent = indent end def inspect if PowerAssert.configuration._colorize_message if PowerAssert.configuration._use_pp width = [(defined?(Pry::Terminal) ? Pry::Terminal.width! : Pry.new(output: StringIO.new).output.width) - 1 - @indent, 10].max Pry::ColorPrinter.pp(@value, '', width) else Pry::Code.new(@value.inspect).highlighted end else if PowerAssert.configuration._use_pp PP.pp(@value, '') else @value.inspect end end end end private_constant :Formatter end PK ]O3e: +gems/power_assert-1.1.7/lib/power_assert.rbnu[# power_assert.rb # # Copyright (C) 2014 Kazuki Tsujimoto begin unless defined?(Byebug) captured = false TracePoint.new(:return, :c_return) do |tp| captured = true unless tp.binding and tp.return_value raise '' end end.enable { __id__ } raise '' unless captured end rescue raise LoadError, 'Fully compatible TracePoint API required' end require 'power_assert/version' require 'power_assert/configuration' require 'power_assert/context' module PowerAssert POWER_ASSERT_LIB_DIR = File.dirname(caller_locations(1, 1).first.path) INTERNAL_LIB_DIRS = {PowerAssert => POWER_ASSERT_LIB_DIR} private_constant :POWER_ASSERT_LIB_DIR, :INTERNAL_LIB_DIRS # For backward compatibility IGNORED_LIB_DIRS = INTERNAL_LIB_DIRS private_constant :IGNORED_LIB_DIRS if respond_to?(:deprecate_constant) deprecate_constant :IGNORED_LIB_DIRS end class << self def start(assertion_proc_or_source, assertion_method: nil, source_binding: TOPLEVEL_BINDING) if respond_to?(:clear_global_method_cache, true) clear_global_method_cache end yield BlockContext.new(assertion_proc_or_source, assertion_method, source_binding) end def trace(frame) begin raise 'Byebug is not started yet' unless Byebug.started? rescue NameError raise "PowerAssert.#{__method__} requires Byebug" end ctx = TraceContext.new(frame._binding) ctx.enable ctx end def app_caller_locations caller_locations.drop_while {|i| internal_file?(i.path) }.take_while {|i| ! internal_file?(i.path) } end def app_context? top_frame = caller_locations.drop_while {|i| i.path.start_with?(POWER_ASSERT_LIB_DIR) }.first top_frame and ! internal_file?(top_frame.path) end private def internal_file?(file) setup_internal_lib_dir(Byebug, :attach, 2) if defined?(Byebug) setup_internal_lib_dir(PryByebug, :start_with_pry_byebug, 2, Pry) if defined?(PryByebug) INTERNAL_LIB_DIRS.find do |_, dir| file.start_with?(dir) end end def setup_internal_lib_dir(lib, mid, depth, lib_obj = lib) unless INTERNAL_LIB_DIRS.key?(lib) INTERNAL_LIB_DIRS[lib] = lib_dir(lib_obj, mid, depth) end rescue NameError end def lib_dir(obj, mid, depth) File.expand_path('../' * depth, obj.method(mid).source_location[0]) end if defined?(RubyVM) CLEAR_CACHE_ISEQ = RubyVM::InstructionSequence.compile('using PowerAssert.const_get(:Empty)') private_constant :CLEAR_CACHE_ISEQ def clear_global_method_cache CLEAR_CACHE_ISEQ.eval end end end module Empty end private_constant :Empty end PK ] gems/xmlrpc-0.3.0/LICENSE.txtnu[Ruby is copyrighted free software by Yukihiro Matsumoto . You can redistribute it and/or modify it under either the terms of the 2-clause BSDL (see the file BSDL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. PK ]K''gems/xmlrpc-0.3.0/Gemfilenu[source 'https://rubygems.org' gemspec PK ]Y gems/xmlrpc-0.3.0/xmlrpc.gemspecnu[# -*- encoding: utf-8 -*- # stub: xmlrpc 0.3.0 ruby lib Gem::Specification.new do |s| s.name = "xmlrpc".freeze s.version = "0.3.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["SHIBATA Hiroshi".freeze] s.bindir = "exe".freeze s.date = "2017-02-16" s.description = "XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP.".freeze s.email = ["hsbt@ruby-lang.org".freeze] s.files = [".gitignore".freeze, ".travis.yml".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "bin/console".freeze, "bin/setup".freeze, "lib/xmlrpc.rb".freeze, "lib/xmlrpc/base64.rb".freeze, "lib/xmlrpc/client.rb".freeze, "lib/xmlrpc/config.rb".freeze, "lib/xmlrpc/create.rb".freeze, "lib/xmlrpc/datetime.rb".freeze, "lib/xmlrpc/marshal.rb".freeze, "lib/xmlrpc/parser.rb".freeze, "lib/xmlrpc/server.rb".freeze, "lib/xmlrpc/utils.rb".freeze, "xmlrpc.gemspec".freeze] s.homepage = "https://github.com/ruby/xmlrpc".freeze s.licenses = ["Ruby".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3".freeze) s.rubygems_version = "3.3.5".freeze s.summary = "XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]\Wgems/xmlrpc-0.3.0/Rakefilenu[require "bundler/gem_tasks" require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList['test/**/test_*.rb'] end task :default => :test PK ]igems/xmlrpc-0.3.0/README.mdnu[# XMLRPC [![Build Status](https://travis-ci.org/ruby/xmlrpc.svg?branch=master)](https://travis-ci.org/ruby/xmlrpc) ## Overview XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP. It is defined at http://www.xmlrpc.com. XMLRPC allows you to create simple distributed computing solutions that span computer languages. Its distinctive feature is its simplicity compared to other approaches like SOAP and CORBA. The Ruby standard library package 'xmlrpc' enables you to create a server that implements remote procedures and a client that calls them. Very little code is required to achieve either of these. ## Installation Add this line to your application's Gemfile: ```ruby gem 'xmlrpc' ``` And then execute: $ bundle Or install it yourself as: $ gem install xmlrpc ## Example Try the following code. It calls a standard demonstration remote procedure. ```ruby require 'xmlrpc/client' require 'pp' server = XMLRPC::Client.new2("http://xmlrpc-c.sourceforge.net/api/sample.php") result = server.call("sample.sumAndDifference", 5, 3) pp result ``` ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/xmlrpc. ## License Released under the same term of license as Ruby. PK ]gems/xmlrpc-0.3.0/bin/setupnu[#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install # Do any other automated setup that you need to do here PK ]N=KKgems/xmlrpc-0.3.0/bin/consolenu[#!/usr/bin/env ruby require "bundler/setup" require "xmlrpc" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start PK ]Xgems/xmlrpc-0.3.0/lib/xmlrpc.rbnu[# frozen_string_literal: false # == Author and Copyright # # Copyright (C) 2001-2004 by Michael Neumann (mailto:mneumann@ntecs.de) # # Released under the same term of license as Ruby. # # == Overview # # XMLRPC is a lightweight protocol that enables remote procedure calls over # HTTP. It is defined at http://www.xmlrpc.com. # # XMLRPC allows you to create simple distributed computing solutions that span # computer languages. Its distinctive feature is its simplicity compared to # other approaches like SOAP and CORBA. # # The Ruby standard library package 'xmlrpc' enables you to create a server that # implements remote procedures and a client that calls them. Very little code # is required to achieve either of these. # # == Example # # Try the following code. It calls a standard demonstration remote procedure. # # require 'xmlrpc/client' # require 'pp' # # server = XMLRPC::Client.new2("http://xmlrpc-c.sourceforge.net/api/sample.php") # result = server.call("sample.sumAndDifference", 5, 3) # pp result # # == Documentation # # See http://www.ntecs.de/ruby/xmlrpc4r/. There is plenty of detail there to # use the client and implement a server. # # == Features of XMLRPC for Ruby # # * Extensions # * Introspection # * multiCall # * optionally nil values and integers larger than 32 Bit # # * Server # * Standalone XML-RPC server # * CGI-based (works with FastCGI) # * Apache mod_ruby server # * WEBrick servlet # # * Client # * synchronous/asynchronous calls # * Basic HTTP-401 Authentication # * HTTPS protocol (SSL) # # * Parsers # * REXML (XMLParser::REXMLStreamParser) # * Not compiled (pure ruby) # * See ruby standard library # * libxml (LibXMLStreamParser) # * Compiled # * See https://rubygems.org/gems/libxml-ruby/ # # * General # * possible to choose between XMLParser module (Expat wrapper) and REXML (pure Ruby) parsers # * Marshalling Ruby objects to Hashes and reconstruct them later from a Hash # * SandStorm component architecture XMLRPC::Client interface # # == Howto # # === Client # # require "xmlrpc/client" # # # Make an object to represent the XML-RPC server. # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # # # Call the remote server and get our result # result = server.call("sample.sumAndDifference", 5, 3) # # sum = result["sum"] # difference = result["difference"] # # puts "Sum: #{sum}, Difference: #{difference}" # # === XMLRPC::Client with XML-RPC fault-structure handling # # There are two possible ways, of handling a fault-structure: # # ==== by catching a XMLRPC::FaultException exception # # require "xmlrpc/client" # # # Make an object to represent the XML-RPC server. # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # # begin # # Call the remote server and get our result # result = server.call("sample.sumAndDifference", 5, 3) # # sum = result["sum"] # difference = result["difference"] # # puts "Sum: #{sum}, Difference: #{difference}" # # rescue XMLRPC::FaultException => e # puts "Error: " # puts e.faultCode # puts e.faultString # end # # ==== by calling "call2" which returns a boolean # # require "xmlrpc/client" # # # Make an object to represent the XML-RPC server. # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # # # Call the remote server and get our result # ok, result = server.call2("sample.sumAndDifference", 5, 3) # # if ok # sum = result["sum"] # difference = result["difference"] # # puts "Sum: #{sum}, Difference: #{difference}" # else # puts "Error: " # puts result.faultCode # puts result.faultString # end # # === Using XMLRPC::Client::Proxy # # You can create a Proxy object onto which you can call methods. This way it # looks nicer. Both forms, _call_ and _call2_ are supported through _proxy_ and # _proxy2_. You can additionally give arguments to the Proxy, which will be # given to each XML-RPC call using that Proxy. # # require "xmlrpc/client" # # # Make an object to represent the XML-RPC server. # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # # # Create a Proxy object # sample = server.proxy("sample") # # # Call the remote server and get our result # result = sample.sumAndDifference(5,3) # # sum = result["sum"] # difference = result["difference"] # # puts "Sum: #{sum}, Difference: #{difference}" # # === CGI-based server using XMLRPC::CGIServer # # There are also two ways to define handler, the first is # like C/PHP, the second like Java, of course both ways # can be mixed: # # ==== C/PHP-like (handler functions) # # require "xmlrpc/server" # # s = XMLRPC::CGIServer.new # # s.add_handler("sample.sumAndDifference") do |a,b| # { "sum" => a + b, "difference" => a - b } # end # # s.serve # # ==== Java-like (handler classes) # # require "xmlrpc/server" # # s = XMLRPC::CGIServer.new # # class MyHandler # def sumAndDifference(a, b) # { "sum" => a + b, "difference" => a - b } # end # end # # # NOTE: Security Hole (read below)!!! # s.add_handler("sample", MyHandler.new) # s.serve # # # To return a fault-structure you have to raise an XMLRPC::FaultException e.g.: # # raise XMLRPC::FaultException.new(3, "division by Zero") # # ===== Security Note # # From Brian Candler: # # Above code sample has an extremely nasty security hole, in that you can now call # any method of 'MyHandler' remotely, including methods inherited from Object # and Kernel! For example, in the client code, you can use # # puts server.call("sample.send","`","ls") # # (backtick being the method name for running system processes). Needless to # say, 'ls' can be replaced with something else. # # The version which binds proc objects (or the version presented below in the next section) # doesn't have this problem, but people may be tempted to use the second version because it's # so nice and 'Rubyesque'. I think it needs a big red disclaimer. # # # From Michael: # # A solution is to undef insecure methods or to use # XMLRPC::Service::PublicInstanceMethodsInterface as shown below: # # class MyHandler # def sumAndDifference(a, b) # { "sum" => a + b, "difference" => a - b } # end # end # # # ... server initialization ... # # s.add_handler(XMLRPC::iPIMethods("sample"), MyHandler.new) # # # ... # # This adds only public instance methods explicitly declared in class MyHandler # (and not those inherited from any other class). # # ==== With interface declarations # # Code sample from the book Ruby Developer's Guide: # # require "xmlrpc/server" # # class Num # INTERFACE = XMLRPC::interface("num") { # meth 'int add(int, int)', 'Add two numbers', 'add' # meth 'int div(int, int)', 'Divide two numbers' # } # # def add(a, b) a + b end # def div(a, b) a / b end # end # # # s = XMLRPC::CGIServer.new # s.add_handler(Num::INTERFACE, Num.new) # s.serve # # === Standalone XMLRPC::Server # # Same as CGI-based server, the only difference being # # server = XMLRPC::CGIServer.new # # must be changed to # # server = XMLRPC::Server.new(8080) # # if you want a server listening on port 8080. # The rest is the same. # # === Choosing a different XMLParser or XMLWriter # # The examples above all use the default parser (which is now since 1.8 # XMLParser::REXMLStreamParser) and a default XMLRPC::XMLWriter. # If you want to use a different XMLParser, then you have to call the # ParserWriterChooseMixin#set_parser method of XMLRPC::Client instances # or instances of subclasses of XMLRPC::BasicServer or by editing # xmlrpc/config.rb. # # XMLRPC::Client Example: # # # ... # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # server.set_parser(XMLRPC::XMLParser::XMLParser.new) # # ... # # XMLRPC::Server Example: # # # ... # s = XMLRPC::CGIServer.new # s.set_parser(XMLRPC::XMLParser::XMLParser.new) # # ... # # # You can change the XML-writer by calling method ParserWriterChooseMixin#set_writer. module XMLRPC VERSION = "0.3.0" end PK ]Gea a (gems/xmlrpc-0.3.0/lib/xmlrpc/datetime.rbnu[# frozen_string_literal: false # # xmlrpc/datetime.rb # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # Released under the same term of license as Ruby. # require "date" module XMLRPC # :nodoc: # This class is important to handle XMLRPC +dateTime.iso8601+ values, # correctly, because normal UNIX-dates, ie: Date, only handle dates # from year 1970 on, and ruby's native Time class handles dates without the # time component. # # XMLRPC::DateTime is able to store a XMLRPC +dateTime.iso8601+ value correctly. class DateTime # Return the value of the specified date/time component. attr_reader :year, :month, :day, :hour, :min, :sec # Set +value+ as the new date/time component. # # Raises ArgumentError if the given +value+ is out of range, or in the case # of XMLRPC::DateTime#year= if +value+ is not of type Integer. def year=(value) raise ArgumentError, "date/time out of range" unless value.is_a? Integer @year = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 1 and 12. def month=(value) raise ArgumentError, "date/time out of range" unless (1..12).include? value @month = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 1 and 31. def day=(value) raise ArgumentError, "date/time out of range" unless (1..31).include? value @day = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 0 and 24. def hour=(value) raise ArgumentError, "date/time out of range" unless (0..24).include? value @hour = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 0 and 59. def min=(value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @min = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 0 and 59. def sec=(value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @sec = value end # Alias for XMLRPC::DateTime#month. alias mon month # Alias for XMLRPC::DateTime#month=. alias mon= month= # Creates a new XMLRPC::DateTime instance with the # parameters +year+, +month+, +day+ as date and # +hour+, +min+, +sec+ as time. # # Raises an ArgumentError if a parameter is out of range, # or if +year+ is not of the Integer type. def initialize(year, month, day, hour, min, sec) self.year, self.month, self.day = year, month, day self.hour, self.min, self.sec = hour, min, sec end # Return a Time object of the date/time which represents +self+. # # The timezone used is GMT. def to_time Time.gm(*to_a) end # Return a Date object of the date which represents +self+. # # The Date object do _not_ contain the time component (only date). def to_date Date.new(*to_a[0,3]) end # Returns all date/time components in an array. # # Returns +[year, month, day, hour, min, sec]+. def to_a [@year, @month, @day, @hour, @min, @sec] end # Returns whether or not all date/time components are an array. def ==(o) self.to_a == Array(o) rescue false end end end # module XMLRPC =begin = History $Id$ =end PK ]-KKKK&gems/xmlrpc-0.3.0/lib/xmlrpc/client.rbnu[# frozen_string_literal: false # xmlrpc/client.rb # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # Released under the same term of license as Ruby. # # History # $Id$ # require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" # ParserWriterChooseMixin require "net/http" require "uri" module XMLRPC # :nodoc: # Provides remote procedure calls to a XML-RPC server. # # After setting the connection-parameters with XMLRPC::Client.new which # creates a new XMLRPC::Client instance, you can execute a remote procedure # by sending the XMLRPC::Client#call or XMLRPC::Client#call2 # message to this new instance. # # The given parameters indicate which method to call on the remote-side and # of course the parameters for the remote procedure. # # require "xmlrpc/client" # # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) # begin # param = server.call("michael.add", 4, 5) # puts "4 + 5 = #{param}" # rescue XMLRPC::FaultException => e # puts "Error:" # puts e.faultCode # puts e.faultString # end # # or # # require "xmlrpc/client" # # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) # ok, param = server.call2("michael.add", 4, 5) # if ok then # puts "4 + 5 = #{param}" # else # puts "Error:" # puts param.faultCode # puts param.faultString # end class Client USER_AGENT = "XMLRPC::Client (Ruby #{RUBY_VERSION})" include ParserWriterChooseMixin include ParseContentType # Creates an object which represents the remote XML-RPC server on the # given +host+. If the server is CGI-based, +path+ is the # path to the CGI-script, which will be called, otherwise (in the # case of a standalone server) +path+ should be "/RPC2". # +port+ is the port on which the XML-RPC server listens. # # If +proxy_host+ is given, then a proxy server listening at # +proxy_host+ is used. +proxy_port+ is the port of the # proxy server. # # Default values for +host+, +path+ and +port+ are 'localhost', '/RPC2' and # '80' respectively using SSL '443'. # # If +user+ and +password+ are given, each time a request is sent, # an Authorization header is sent. Currently only Basic Authentication is # implemented, no Digest. # # If +use_ssl+ is set to +true+, communication over SSL is enabled. # # Parameter +timeout+ is the time to wait for a XML-RPC response, defaults to 30. def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=nil, timeout=nil) @http_header_extra = nil @http_last_response = nil @cookie = nil @host = host || "localhost" @path = path || "/RPC2" @proxy_host = proxy_host @proxy_port = proxy_port @proxy_host ||= 'localhost' if @proxy_port != nil @proxy_port ||= 8080 if @proxy_host != nil @use_ssl = use_ssl || false @timeout = timeout || 30 if use_ssl require "net/https" @port = port || 443 else @port = port || 80 end @user, @password = user, password set_auth # convert ports to integers @port = @port.to_i if @port != nil @proxy_port = @proxy_port.to_i if @proxy_port != nil # HTTP object for synchronous calls @http = net_http(@host, @port, @proxy_host, @proxy_port) @http.use_ssl = @use_ssl if @use_ssl @http.read_timeout = @timeout @http.open_timeout = @timeout @parser = nil @create = nil end class << self # Creates an object which represents the remote XML-RPC server at the # given +uri+. The URI should have a host, port, path, user and password. # Example: https://user:password@host:port/path # # Raises an ArgumentError if the +uri+ is invalid, # or if the protocol isn't http or https. # # If a +proxy+ is given it should be in the form of "host:port". # # The optional +timeout+ defaults to 30 seconds. def new2(uri, proxy=nil, timeout=nil) begin url = URI(uri) rescue URI::InvalidURIError => e raise ArgumentError, e.message, e.backtrace end unless URI::HTTP === url raise ArgumentError, "Wrong protocol specified. Only http or https allowed!" end proto = url.scheme user = url.user passwd = url.password host = url.host port = url.port path = url.path.empty? ? nil : url.request_uri proxy_host, proxy_port = (proxy || "").split(":") proxy_port = proxy_port.to_i if proxy_port self.new(host, path, port, proxy_host, proxy_port, user, passwd, (proto == "https"), timeout) end alias new_from_uri new2 # Receives a Hash and calls XMLRPC::Client.new # with the corresponding values. # # The +hash+ parameter has following case-insensitive keys: # * host # * path # * port # * proxy_host # * proxy_port # * user # * password # * use_ssl # * timeout def new3(hash={}) # convert all keys into lowercase strings h = {} hash.each { |k,v| h[k.to_s.downcase] = v } self.new(h['host'], h['path'], h['port'], h['proxy_host'], h['proxy_port'], h['user'], h['password'], h['use_ssl'], h['timeout']) end alias new_from_hash new3 end # Returns the Net::HTTP object for the client. If you want to # change HTTP client options except header, cookie, timeout, # user and password, use Net::HTTP directly. # # Since 2.1.0. attr_reader :http # Add additional HTTP headers to the request attr_accessor :http_header_extra # Returns the Net::HTTPResponse object of the last RPC. attr_reader :http_last_response # Get and set the HTTP Cookie header. attr_accessor :cookie # Return the corresponding attributes. attr_reader :timeout, :user, :password # Sets the Net::HTTP#read_timeout and Net::HTTP#open_timeout to # +new_timeout+ def timeout=(new_timeout) @timeout = new_timeout @http.read_timeout = @timeout @http.open_timeout = @timeout end # Changes the user for the Basic Authentication header to +new_user+ def user=(new_user) @user = new_user set_auth end # Changes the password for the Basic Authentication header to # +new_password+ def password=(new_password) @password = new_password set_auth end # Invokes the method named +method+ with the parameters given by # +args+ on the XML-RPC server. # # The +method+ parameter is converted into a String and should # be a valid XML-RPC method-name. # # Each parameter of +args+ must be of one of the following types, # where Hash, Struct and Array can contain any of these listed _types_: # # * Integer # * TrueClass, FalseClass, +true+, +false+ # * String, Symbol # * Float # * Hash, Struct # * Array # * Date, Time, XMLRPC::DateTime # * XMLRPC::Base64 # * A Ruby object which class includes XMLRPC::Marshallable # (only if Config::ENABLE_MARSHALLING is +true+). # That object is converted into a hash, with one additional key/value # pair ___class___ which contains the class name # for restoring that object later. # # The method returns the return-value from the Remote Procedure Call. # # The type of the return-value is one of the types shown above. # # An Integer is only allowed when it fits in 32-bit. A XML-RPC # +dateTime.iso8601+ type is always returned as a XMLRPC::DateTime object. # Struct is never returned, only a Hash, the same for a Symbol, where as a # String is always returned. XMLRPC::Base64 is returned as a String from # xmlrpc4r version 1.6.1 on. # # If the remote procedure returned a fault-structure, then a # XMLRPC::FaultException exception is raised, which has two accessor-methods # +faultCode+ an Integer, and +faultString+ a String. def call(method, *args) ok, param = call2(method, *args) if ok param else raise param end end # The difference between this method and XMLRPC::Client#call is, that # this method will NOT raise a XMLRPC::FaultException exception. # # The method returns an array of two values. The first value indicates if # the second value is +true+ or an XMLRPC::FaultException. # # Both are explained in XMLRPC::Client#call. # # Simple to remember: The "2" in "call2" denotes the number of values it returns. def call2(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, false) parser().parseMethodResponse(data) end # Similar to XMLRPC::Client#call, however can be called concurrently and # use a new connection for each request. In contrast to the corresponding # method without the +_async+ suffix, which use connect-alive (one # connection for all requests). # # Note, that you have to use Thread to call these methods concurrently. # The following example calls two methods concurrently: # # Thread.new { # p client.call_async("michael.add", 4, 5) # } # # Thread.new { # p client.call_async("michael.div", 7, 9) # } # def call_async(method, *args) ok, param = call2_async(method, *args) if ok param else raise param end end # Same as XMLRPC::Client#call2, but can be called concurrently. # # See also XMLRPC::Client#call_async def call2_async(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, true) parser().parseMethodResponse(data) end # You can use this method to execute several methods on a XMLRPC server # which support the multi-call extension. # # s.multicall( # ['michael.add', 3, 4], # ['michael.sub', 4, 5] # ) # # => [7, -1] def multicall(*methods) ok, params = multicall2(*methods) if ok params else raise params end end # Same as XMLRPC::Client#multicall, but returns two parameters instead of # raising an XMLRPC::FaultException. # # See XMLRPC::Client#call2 def multicall2(*methods) gen_multicall(methods, false) end # Similar to XMLRPC::Client#multicall, however can be called concurrently and # use a new connection for each request. In contrast to the corresponding # method without the +_async+ suffix, which use connect-alive (one # connection for all requests). # # Note, that you have to use Thread to call these methods concurrently. # The following example calls two methods concurrently: # # Thread.new { # p client.multicall_async("michael.add", 4, 5) # } # # Thread.new { # p client.multicall_async("michael.div", 7, 9) # } # def multicall_async(*methods) ok, params = multicall2_async(*methods) if ok params else raise params end end # Same as XMLRPC::Client#multicall2, but can be called concurrently. # # See also XMLRPC::Client#multicall_async def multicall2_async(*methods) gen_multicall(methods, true) end # Returns an object of class XMLRPC::Client::Proxy, initialized with # +prefix+ and +args+. # # A proxy object returned by this method behaves like XMLRPC::Client#call, # i.e. a call on that object will raise a XMLRPC::FaultException when a # fault-structure is returned by that call. def proxy(prefix=nil, *args) Proxy.new(self, prefix, args, :call) end # Almost the same like XMLRPC::Client#proxy only that a call on the returned # XMLRPC::Client::Proxy object will return two parameters. # # See XMLRPC::Client#call2 def proxy2(prefix=nil, *args) Proxy.new(self, prefix, args, :call2) end # Similar to XMLRPC::Client#proxy, however can be called concurrently and # use a new connection for each request. In contrast to the corresponding # method without the +_async+ suffix, which use connect-alive (one # connection for all requests). # # Note, that you have to use Thread to call these methods concurrently. # The following example calls two methods concurrently: # # Thread.new { # p client.proxy_async("michael.add", 4, 5) # } # # Thread.new { # p client.proxy_async("michael.div", 7, 9) # } # def proxy_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call_async) end # Same as XMLRPC::Client#proxy2, but can be called concurrently. # # See also XMLRPC::Client#proxy_async def proxy2_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call2_async) end private def net_http(host, port, proxy_host, proxy_port) Net::HTTP.new host, port, proxy_host, proxy_port end def dup_net_http http = net_http(@http.address, @http.port, @http.proxy_address, @http.proxy_port) http.proxy_user = @http.proxy_user http.proxy_pass = @http.proxy_pass if @http.use_ssl? http.use_ssl = true Net::HTTP::SSL_ATTRIBUTES.each do |attribute| http.__send__("#{attribute}=", @http.__send__(attribute)) end end http.read_timeout = @http.read_timeout http.open_timeout = @http.open_timeout http end def set_auth if @user.nil? @auth = nil else a = "#@user" a << ":#@password" if @password != nil @auth = "Basic " + [a].pack("m0") end end def do_rpc(request, async=false) header = { "User-Agent" => USER_AGENT, "Content-Type" => "text/xml; charset=utf-8", "Content-Length" => request.bytesize.to_s, "Connection" => (async ? "close" : "keep-alive") } header["Cookie"] = @cookie if @cookie header.update(@http_header_extra) if @http_header_extra if @auth != nil # add authorization header header["Authorization"] = @auth end resp = nil @http_last_response = nil if async # use a new HTTP object for each call http = dup_net_http # post request http.start { resp = http.request_post(@path, request, header) } else # reuse the HTTP object for each call => connection alive is possible # we must start connection explicitly first time so that http.request # does not assume that we don't want keepalive @http.start if not @http.started? # post request resp = @http.request_post(@path, request, header) end @http_last_response = resp data = resp.body if resp.code == "401" # Authorization Required raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}" elsif resp.code[0,1] != "2" raise "HTTP-Error: #{resp.code} #{resp.message}" end # assume text/xml on instances where Content-Type header is not set ct_expected = resp["Content-Type"] || 'text/xml' ct = parse_content_type(ct_expected).first if ct != "text/xml" if ct == "text/html" raise "Wrong content-type (received '#{ct}' but expected 'text/xml'): \n#{data}" else raise "Wrong content-type (received '#{ct}' but expected 'text/xml')" end end expected = resp["Content-Length"] || "" if data.nil? or data.bytesize == 0 raise "Wrong size. Was #{data.bytesize}, should be #{expected}" end parse_set_cookies(resp.get_fields("Set-Cookie")) return data end def parse_set_cookies(set_cookies) return if set_cookies.nil? return if set_cookies.empty? require 'webrick/cookie' pairs = {} set_cookies.each do |set_cookie| cookie = WEBrick::Cookie.parse_set_cookie(set_cookie) pairs.delete(cookie.name) pairs[cookie.name] = cookie.value end cookies = pairs.collect do |name, value| WEBrick::Cookie.new(name, value).to_s end @cookie = cookies.join("; ") end def gen_multicall(methods=[], async=false) meth = :call2 meth = :call2_async if async ok, params = self.send(meth, "system.multicall", methods.collect {|m| {'methodName' => m[0], 'params' => m[1..-1]} } ) if ok params = params.collect do |param| if param.is_a? Array param[0] elsif param.is_a? Hash XMLRPC::FaultException.new(param["faultCode"], param["faultString"]) else raise "Wrong multicall return value" end end end return ok, params end # XML-RPC calls look nicer! # # You can call any method onto objects of that class - the object handles # XMLRPC::Client::Proxy#method_missing and will forward the method call to # a XML-RPC server. # # Don't use this class directly, instead use the public instance method # XMLRPC::Client#proxy or XMLRPC::Client#proxy2. # # require "xmlrpc/client" # # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) # # michael = server.proxy("michael") # michael2 = server.proxy("michael", 4) # # # both calls should return the same value '9'. # p michael.add(4,5) # p michael2.add(5) class Proxy # Creates an object which provides XMLRPC::Client::Proxy#method_missing. # # The given +server+ must be an instance of XMLRPC::Client, which is the # XML-RPC server to be used for a XML-RPC call. # # +prefix+ and +delim+ will be prepended to the method name called onto this object. # # An optional parameter +meth+ is the method to use for a RPC. # It can be either, call, call2, call_async, call2_async # # +args+ are arguments which are automatically given to every XML-RPC # call before being provided through +method_missing+. def initialize(server, prefix, args=[], meth=:call, delim=".") @server = server @prefix = prefix ? prefix + delim : "" @args = args @meth = meth end # Every method call is forwarded to the XML-RPC server defined in # XMLRPC::Client::Proxy#new. # # Note: Inherited methods from class Object cannot be used as XML-RPC # names, because they get around +method_missing+. def method_missing(mid, *args) pre = @prefix + mid.to_s arg = @args + args @server.send(@meth, pre, *arg) end end # class Proxy end # class Client end # module XMLRPC PK ]z[W(O(O&gems/xmlrpc-0.3.0/lib/xmlrpc/server.rbnu[# frozen_string_literal: false # xmlrpc/server.rb # Copyright (C) 2001, 2002, 2003, 2005 by Michael Neumann (mneumann@ntecs.de) # # Released under the same term of license as Ruby. require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" # ParserWriterChooseMixin module XMLRPC # :nodoc: # This is the base class for all XML-RPC server-types (CGI, standalone). # You can add handler and set a default handler. # Do not use this server, as this is/should be an abstract class. # # === How the method to call is found # The arity (number of accepted arguments) of a handler (method or Proc # object) is compared to the given arguments submitted by the client for a # RPC, or Remote Procedure Call. # # A handler is only called if it accepts the number of arguments, otherwise # the search for another handler will go on. When at the end no handler was # found, the default_handler, XMLRPC::BasicServer#set_default_handler will be # called. # # With this technique it is possible to do overloading by number of parameters, but # only for Proc handler, because you cannot define two methods of the same name in # the same class. class BasicServer include ParserWriterChooseMixin include ParseContentType ERR_METHOD_MISSING = 1 ERR_UNCAUGHT_EXCEPTION = 2 ERR_MC_WRONG_PARAM = 3 ERR_MC_MISSING_PARAMS = 4 ERR_MC_MISSING_METHNAME = 5 ERR_MC_RECURSIVE_CALL = 6 ERR_MC_WRONG_PARAM_PARAMS = 7 ERR_MC_EXPECTED_STRUCT = 8 # Creates a new XMLRPC::BasicServer instance, which should not be # done, because XMLRPC::BasicServer is an abstract class. This # method should be called from a subclass indirectly by a +super+ call # in the initialize method. # # The parameter +class_delim+ is used by add_handler, see # XMLRPC::BasicServer#add_handler, when an object is added as a handler, to # delimit the object-prefix and the method-name. def initialize(class_delim=".") @handler = [] @default_handler = nil @service_hook = nil @class_delim = class_delim @create = nil @parser = nil add_multicall if Config::ENABLE_MULTICALL add_introspection if Config::ENABLE_INTROSPECTION end # Adds +aBlock+ to the list of handlers, with +name+ as the name of # the method. # # Parameters +signature+ and +help+ are used by the Introspection method if # specified, where +signature+ is either an Array containing strings each # representing a type of it's signature (the first is the return value) or # an Array of Arrays if the method has multiple signatures. # # Value type-names are "int, boolean, double, string, dateTime.iso8601, # base64, array, struct". # # Parameter +help+ is a String with information about how to call this method etc. # # When a method fails, it can tell the client by throwing an # XMLRPC::FaultException like in this example: # # s.add_handler("michael.div") do |a,b| # if b == 0 # raise XMLRPC::FaultException.new(1, "division by zero") # else # a / b # end # end # # In the case of b==0 the client gets an object back of type # XMLRPC::FaultException that has a +faultCode+ and +faultString+ field. # # This is the second form of (()). # To add an object write: # # server.add_handler("michael", MyHandlerClass.new) # # All public methods of MyHandlerClass are accessible to # the XML-RPC clients by michael."name of method". This is # where the +class_delim+ in XMLRPC::BasicServer.new plays it's role, a # XML-RPC method-name is defined by +prefix+ + +class_delim+ + "name # of method". # # The third form of +add_handler is to use XMLRPC::Service::Interface to # generate an object, which represents an interface (with signature and # help text) for a handler class. # # The +interface+ parameter must be an instance of XMLRPC::Service::Interface. # Adds all methods of +obj+ which are defined in the +interface+ to the server. # # This is the recommended way of adding services to a server! def add_handler(prefix, obj_or_signature=nil, help=nil, &block) if block_given? # proc-handler @handler << [prefix, block, obj_or_signature, help] else if prefix.kind_of? String # class-handler raise ArgumentError, "Expected non-nil value" if obj_or_signature.nil? @handler << [prefix + @class_delim, obj_or_signature] elsif prefix.kind_of? XMLRPC::Service::BasicInterface # class-handler with interface # add all methods @handler += prefix.get_methods(obj_or_signature, @class_delim) else raise ArgumentError, "Wrong type for parameter 'prefix'" end end self end # Returns the service-hook, which is called on each service request (RPC) # unless it's +nil+. def get_service_hook @service_hook end # A service-hook is called for each service request (RPC). # # You can use a service-hook for example to wrap existing methods and catch # exceptions of them or convert values to values recognized by XMLRPC. # # You can disable it by passing +nil+ as the +handler+ parameter. # # The service-hook is called with a Proc object along with any parameters. # # An example: # # server.set_service_hook {|obj, *args| # begin # ret = obj.call(*args) # call the original service-method # # could convert the return value # rescue # # rescue exceptions # end # } # def set_service_hook(&handler) @service_hook = handler self end # Returns the default-handler, which is called when no handler for # a method-name is found. # # It is either a Proc object or +nil+. def get_default_handler @default_handler end # Sets +handler+ as the default-handler, which is called when # no handler for a method-name is found. # # +handler+ is a code-block. # # The default-handler is called with the (XML-RPC) method-name as first # argument, and the other arguments are the parameters given by the # client-call. # # If no block is specified the default of XMLRPC::BasicServer is # used, which raises a XMLRPC::FaultException saying "method missing". def set_default_handler(&handler) @default_handler = handler self end # Adds the multi-call handler "system.multicall". def add_multicall add_handler("system.multicall", %w(array array), "Multicall Extension") do |arrStructs| unless arrStructs.is_a? Array raise XMLRPC::FaultException.new(ERR_MC_WRONG_PARAM, "system.multicall expects an array") end arrStructs.collect {|call| if call.is_a? Hash methodName = call["methodName"] params = call["params"] if params.nil? multicall_fault(ERR_MC_MISSING_PARAMS, "Missing params") elsif methodName.nil? multicall_fault(ERR_MC_MISSING_METHNAME, "Missing methodName") else if methodName == "system.multicall" multicall_fault(ERR_MC_RECURSIVE_CALL, "Recursive system.multicall forbidden") else unless params.is_a? Array multicall_fault(ERR_MC_WRONG_PARAM_PARAMS, "Parameter params have to be an Array") else ok, val = call_method(methodName, *params) if ok # correct return value [val] else # exception multicall_fault(val.faultCode, val.faultString) end end end end else multicall_fault(ERR_MC_EXPECTED_STRUCT, "system.multicall expected struct") end } end # end add_handler self end # Adds the introspection handlers "system.listMethods", # "system.methodSignature" and # "system.methodHelp", where only the first one works. def add_introspection add_handler("system.listMethods",%w(array), "List methods available on this XML-RPC server") do methods = [] @handler.each do |name, obj| if obj.kind_of? Proc methods << name else obj.class.public_instance_methods(false).each do |meth| methods << "#{name}#{meth}" end end end methods end add_handler("system.methodSignature", %w(array string), "Returns method signature") do |meth| sigs = [] @handler.each do |name, obj, sig| if obj.kind_of? Proc and sig != nil and name == meth if sig[0].kind_of? Array # sig contains multiple signatures, e.g. [["array"], ["array", "string"]] sig.each {|s| sigs << s} else # sig is a single signature, e.g. ["array"] sigs << sig end end end sigs.uniq! || sigs # remove eventually duplicated signatures end add_handler("system.methodHelp", %w(string string), "Returns help on using this method") do |meth| help = nil @handler.each do |name, obj, sig, hlp| if obj.kind_of? Proc and name == meth help = hlp break end end help || "" end self end def process(data) method, params = parser().parseMethodCall(data) handle(method, *params) end private def multicall_fault(nr, str) {"faultCode" => nr, "faultString" => str} end def dispatch(methodname, *args) for name, obj in @handler if obj.kind_of? Proc next unless methodname == name else next unless methodname =~ /^#{name}(.+)$/ next unless obj.respond_to? $1 obj = obj.method($1) end if check_arity(obj, args.size) if @service_hook.nil? return obj.call(*args) else return @service_hook.call(obj, *args) end end end if @default_handler.nil? raise XMLRPC::FaultException.new(ERR_METHOD_MISSING, "Method #{methodname} missing or wrong number of parameters!") else @default_handler.call(methodname, *args) end end # Returns +true+, if the arity of +obj+ matches +n_args+ def check_arity(obj, n_args) ary = obj.arity if ary >= 0 n_args == ary else n_args >= (ary+1).abs end end def call_method(methodname, *args) begin [true, dispatch(methodname, *args)] rescue XMLRPC::FaultException => e [false, e] rescue Exception => e [false, XMLRPC::FaultException.new(ERR_UNCAUGHT_EXCEPTION, "Uncaught exception #{e.message} in method #{methodname}")] end end def handle(methodname, *args) create().methodResponse(*call_method(methodname, *args)) end end # Implements a CGI-based XML-RPC server. # # require "xmlrpc/server" # # s = XMLRPC::CGIServer.new # # s.add_handler("michael.add") do |a,b| # a + b # end # # s.add_handler("michael.div") do |a,b| # if b == 0 # raise XMLRPC::FaultException.new(1, "division by zero") # else # a / b # end # end # # s.set_default_handler do |name, *args| # raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + # " or wrong number of parameters!") # end # # s.serve # # # Note: Make sure that you don't write to standard-output in a # handler, or in any other part of your program, this would cause a CGI-based # server to fail! class CGIServer < BasicServer @@obj = nil # Creates a new XMLRPC::CGIServer instance. # # All parameters given are by-passed to XMLRPC::BasicServer.new. # # You can only create one XMLRPC::CGIServer instance, because more # than one makes no sense. def CGIServer.new(*a) @@obj = super(*a) if @@obj.nil? @@obj end def initialize(*a) super(*a) end # Call this after you have added all you handlers to the server. # # This method processes a XML-RPC method call and sends the answer # back to the client. def serve catch(:exit_serve) { length = ENV['CONTENT_LENGTH'].to_i http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST" http_error(400, "Bad Request") unless parse_content_type(ENV['CONTENT_TYPE']).first == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? $stdin.binmode if $stdin.respond_to? :binmode data = $stdin.read(length) http_error(400, "Bad Request") if data.nil? or data.bytesize != length http_write(process(data), "Content-type" => "text/xml; charset=utf-8") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

    #{err}

    Unexpected error occurred while processing XML-RPC request!

    MSGEND http_write(msg, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.bytesize.to_s str = "" h.each {|key, value| str << "#{key}: #{value}\r\n"} str << "\r\n#{body}" print str end end # Implements a XML-RPC server, which works with Apache mod_ruby. # # Use it in the same way as XMLRPC::CGIServer! class ModRubyServer < BasicServer # Creates a new XMLRPC::ModRubyServer instance. # # All parameters given are by-passed to XMLRPC::BasicServer.new. def initialize(*a) @ap = Apache::request super(*a) end # Call this after you have added all you handlers to the server. # # This method processes a XML-RPC method call and sends the answer # back to the client. def serve catch(:exit_serve) { header = {} @ap.headers_in.each {|key, value| header[key.capitalize] = value} length = header['Content-length'].to_i http_error(405, "Method Not Allowed") unless @ap.request_method == "POST" http_error(400, "Bad Request") unless parse_content_type(header['Content-type']).first == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? @ap.binmode data = @ap.read(length) http_error(400, "Bad Request") if data.nil? or data.bytesize != length http_write(process(data), 200, "Content-type" => "text/xml; charset=utf-8") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

    #{err}

    Unexpected error occurred while processing XML-RPC request!

    MSGEND http_write(msg, status, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, status, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.bytesize.to_s h.each {|key, value| @ap.headers_out[key] = value } @ap.content_type = h["Content-type"] @ap.status = status.to_i @ap.send_http_header @ap.print body end end class WEBrickServlet < BasicServer; end # forward declaration # Implements a standalone XML-RPC server. The method XMLRPC::Server#serve is # left if a SIGHUP is sent to the program. # # require "xmlrpc/server" # # s = XMLRPC::Server.new(8080) # # s.add_handler("michael.add") do |a,b| # a + b # end # # s.add_handler("michael.div") do |a,b| # if b == 0 # raise XMLRPC::FaultException.new(1, "division by zero") # else # a / b # end # end # # s.set_default_handler do |name, *args| # raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + # " or wrong number of parameters!") # end # # s.serve class Server < WEBrickServlet # Creates a new XMLRPC::Server instance, which is a XML-RPC server # listening on the given +port+ and accepts requests for the given +host+, # which is +localhost+ by default. # # The server is not started, to start it you have to call # XMLRPC::Server#serve. # # The optional +audit+ and +debug+ parameters are obsolete! # # All additionally provided parameters in *a are by-passed to # XMLRPC::BasicServer.new. def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a) super(*a) require 'webrick' @server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections, :Logger => WEBrick::Log.new(stdlog)) @server.mount("/", self) end # Call this after you have added all you handlers to the server. # This method starts the server to listen for XML-RPC requests and answer them. def serve signals = %w[INT TERM HUP] & Signal.list.keys signals.each { |signal| trap(signal) { @server.shutdown } } @server.start end # Stops and shuts the server down. def shutdown @server.shutdown end end # Implements a servlet for use with WEBrick, a pure Ruby (HTTP) server # framework. # # require "webrick" # require "xmlrpc/server" # # s = XMLRPC::WEBrickServlet.new # s.add_handler("michael.add") do |a,b| # a + b # end # # s.add_handler("michael.div") do |a,b| # if b == 0 # raise XMLRPC::FaultException.new(1, "division by zero") # else # a / b # end # end # # s.set_default_handler do |name, *args| # raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + # " or wrong number of parameters!") # end # # httpserver = WEBrick::HTTPServer.new(:Port => 8080) # httpserver.mount("/RPC2", s) # trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows # httpserver.start class WEBrickServlet < BasicServer def initialize(*a) super require "webrick/httpstatus" @valid_ip = nil end # Deprecated from WEBrick/1.2.2, but does not break anything. def require_path_info? false end def get_instance(config, *options) # TODO: set config & options self end # Specifies the valid IP addresses that are allowed to connect to the server. # # Each IP is either a String or a Regexp. def set_valid_ip(*ip_addr) if ip_addr.size == 1 and ip_addr[0].nil? @valid_ip = nil else @valid_ip = ip_addr end end # Return the valid IP addresses that are allowed to connect to the server. # # See also, XMLRPC::Server#set_valid_ip def get_valid_ip @valid_ip end def service(request, response) if @valid_ip raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip } end if request.request_method != "POST" raise WEBrick::HTTPStatus::MethodNotAllowed, "unsupported method `#{request.request_method}'." end if parse_content_type(request['Content-type']).first != "text/xml" raise WEBrick::HTTPStatus::BadRequest end length = (request['Content-length'] || 0).to_i raise WEBrick::HTTPStatus::LengthRequired unless length > 0 data = request.body if data.nil? or data.bytesize != length raise WEBrick::HTTPStatus::BadRequest end resp = process(data) if resp.nil? or resp.bytesize <= 0 raise WEBrick::HTTPStatus::InternalServerError end response.status = 200 response['Content-Length'] = resp.bytesize response['Content-Type'] = "text/xml; charset=utf-8" response.body = resp end end end # module XMLRPC =begin = History $Id$ =end PK ] T==&gems/xmlrpc-0.3.0/lib/xmlrpc/parser.rbnu[# frozen_string_literal: false # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "date" require "xmlrpc/base64" require "xmlrpc/datetime" module XMLRPC # :nodoc: # Raised when the remote procedure returns a fault-structure, which has two # accessor-methods +faultCode+ an Integer, and +faultString+ a String. class FaultException < StandardError attr_reader :faultCode, :faultString # Creates a new XMLRPC::FaultException instance. # # +faultString+ is passed to StandardError as the +msg+ of the Exception. def initialize(faultCode, faultString) @faultCode = faultCode @faultString = faultString super(@faultString) end # The +faultCode+ and +faultString+ of the exception in a Hash. def to_h {"faultCode" => @faultCode, "faultString" => @faultString} end end # Helper class used to convert types. module Convert # Converts a String to an Integer # # See also String.to_i def self.int(str) str.to_i end # Converts a String to +true+ or +false+ # # Raises an exception if +str+ is not +0+ or +1+ def self.boolean(str) case str when "0" then false when "1" then true else raise "RPC-value of type boolean is wrong" end end # Converts a String to a Float # # See also String.to_f def self.double(str) str.to_f end # Converts a the given +str+ to a +dateTime.iso8601+ formatted date. # # Raises an exception if the String isn't in +dateTime.iso8601+ format. # # See also, XMLRPC::DateTime def self.dateTime(str) case str when /^(-?\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(?:Z|([+-])(\d\d):?(\d\d))?$/ a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} if $7 ofs = $8.to_i*3600 + $9.to_i*60 ofs = -ofs if $7=='+' utc = Time.utc(*a) + ofs a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ] end XMLRPC::DateTime.new(*a) when /^(-?\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(Z|([+-]\d\d):(\d\d))?$/ a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} if a[0] < 70 a[0] += 2000 else a[0] += 1900 end if $7 ofs = $8.to_i*3600 + $9.to_i*60 ofs = -ofs if $7=='+' utc = Time.utc(*a) + ofs a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ] end XMLRPC::DateTime.new(*a) else raise "wrong dateTime.iso8601 format " + str end end # Decodes the given +str+ using XMLRPC::Base64.decode def self.base64(str) XMLRPC::Base64.decode(str) end # Converts the given +hash+ to a marshalled object. # # Returns the given +hash+ if an exception occurs. def self.struct(hash) # convert to marshalled object klass = hash["___class___"] if klass.nil? or Config::ENABLE_MARSHALLING == false hash else begin mod = Module klass.split("::").each {|const| mod = mod.const_get(const.strip)} obj = mod.allocate hash.delete "___class___" hash.each {|key, value| obj.instance_variable_set("@#{ key }", value) if key =~ /^([a-zA-Z_]\w*)$/ } obj rescue hash end end end # Converts the given +hash+ to an XMLRPC::FaultException object by passing # the +faultCode+ and +faultString+ attributes of the Hash to # XMLRPC::FaultException.new # # Raises an Exception if the given +hash+ doesn't meet the requirements. # Those requirements being: # * 2 keys # * 'faultCode' key is an Integer # * 'faultString' key is a String def self.fault(hash) if hash.kind_of? Hash and hash.size == 2 and hash.has_key? "faultCode" and hash.has_key? "faultString" and hash["faultCode"].kind_of? Integer and hash["faultString"].kind_of? String XMLRPC::FaultException.new(hash["faultCode"], hash["faultString"]) else raise "wrong fault-structure: #{hash.inspect}" end end end # module Convert # Parser for XML-RPC call and response module XMLParser class AbstractTreeParser def parseMethodResponse(str) methodResponse_document(createCleanedTree(str)) end def parseMethodCall(str) methodCall_document(createCleanedTree(str)) end private # Removes all whitespaces but in the tags i4, i8, int, boolean.... # and all comments def removeWhitespacesAndComments(node) remove = [] childs = node.childNodes.to_a childs.each do |nd| case _nodeType(nd) when :TEXT # TODO: add nil? unless %w(i4 i8 int boolean string double dateTime.iso8601 base64).include? node.nodeName if node.nodeName == "value" if not node.childNodes.to_a.detect {|n| _nodeType(n) == :ELEMENT}.nil? remove << nd if nd.nodeValue.strip == "" end else remove << nd if nd.nodeValue.strip == "" end end when :COMMENT remove << nd else removeWhitespacesAndComments(nd) end end remove.each { |i| node.removeChild(i) } end def nodeMustBe(node, name) cmp = case name when Array name.include?(node.nodeName) when String name == node.nodeName else raise "error" end if not cmp then raise "wrong xml-rpc (name)" end node end # Returns, when successfully the only child-node def hasOnlyOneChild(node, name=nil) if node.childNodes.to_a.size != 1 raise "wrong xml-rpc (size)" end if name != nil then nodeMustBe(node.firstChild, name) end end def assert(b) if not b then raise "assert-fail" end end # The node `node` has empty string or string def text_zero_one(node) nodes = node.childNodes.to_a.size if nodes == 1 text(node.firstChild) elsif nodes == 0 "" else raise "wrong xml-rpc (size)" end end def integer(node) #TODO: check string for float because to_i returnsa # 0 when wrong string nodeMustBe(node, %w(i4 i8 int)) hasOnlyOneChild(node) Convert.int(text(node.firstChild)) end def boolean(node) nodeMustBe(node, "boolean") hasOnlyOneChild(node) Convert.boolean(text(node.firstChild)) end def v_nil(node) nodeMustBe(node, "nil") assert( node.childNodes.to_a.size == 0 ) nil end def string(node) nodeMustBe(node, "string") text_zero_one(node) end def double(node) #TODO: check string for float because to_f returnsa # 0.0 when wrong string nodeMustBe(node, "double") hasOnlyOneChild(node) Convert.double(text(node.firstChild)) end def dateTime(node) nodeMustBe(node, "dateTime.iso8601") hasOnlyOneChild(node) Convert.dateTime( text(node.firstChild) ) end def base64(node) nodeMustBe(node, "base64") #hasOnlyOneChild(node) Convert.base64(text_zero_one(node)) end def member(node) nodeMustBe(node, "member") assert( node.childNodes.to_a.size == 2 ) [ name(node[0]), value(node[1]) ] end def name(node) nodeMustBe(node, "name") #hasOnlyOneChild(node) text_zero_one(node) end def array(node) nodeMustBe(node, "array") hasOnlyOneChild(node, "data") data(node.firstChild) end def data(node) nodeMustBe(node, "data") node.childNodes.to_a.collect do |val| value(val) end end def param(node) nodeMustBe(node, "param") hasOnlyOneChild(node, "value") value(node.firstChild) end def methodResponse(node) nodeMustBe(node, "methodResponse") hasOnlyOneChild(node, %w(params fault)) child = node.firstChild case child.nodeName when "params" [ true, params(child,false) ] when "fault" [ false, fault(child) ] else raise "unexpected error" end end def methodName(node) nodeMustBe(node, "methodName") hasOnlyOneChild(node) text(node.firstChild) end def params(node, call=true) nodeMustBe(node, "params") if call node.childNodes.to_a.collect do |n| param(n) end else # response (only one param) hasOnlyOneChild(node) param(node.firstChild) end end def fault(node) nodeMustBe(node, "fault") hasOnlyOneChild(node, "value") f = value(node.firstChild) Convert.fault(f) end # _nodeType is defined in the subclass def text(node) assert( _nodeType(node) == :TEXT ) assert( node.hasChildNodes == false ) assert( node.nodeValue != nil ) node.nodeValue.to_s end def struct(node) nodeMustBe(node, "struct") hash = {} node.childNodes.to_a.each do |me| n, v = member(me) hash[n] = v end Convert.struct(hash) end def value(node) nodeMustBe(node, "value") nodes = node.childNodes.to_a.size if nodes == 0 return "" elsif nodes > 1 raise "wrong xml-rpc (size)" end child = node.firstChild case _nodeType(child) when :TEXT text_zero_one(node) when :ELEMENT case child.nodeName when "i4", "i8", "int" then integer(child) when "boolean" then boolean(child) when "string" then string(child) when "double" then double(child) when "dateTime.iso8601" then dateTime(child) when "base64" then base64(child) when "struct" then struct(child) when "array" then array(child) when "nil" if Config::ENABLE_NIL_PARSER v_nil(child) else raise "wrong/unknown XML-RPC type 'nil'" end else raise "wrong/unknown XML-RPC type" end else raise "wrong type of node" end end def methodCall(node) nodeMustBe(node, "methodCall") assert( (1..2).include?( node.childNodes.to_a.size ) ) name = methodName(node[0]) if node.childNodes.to_a.size == 2 then pa = params(node[1]) else # no parameters given pa = [] end [name, pa] end end # module TreeParserMixin class AbstractStreamParser def parseMethodResponse(str) parser = @parser_class.new parser.parse(str) raise "No valid method response!" if parser.method_name != nil if parser.fault != nil # is a fault structure [false, parser.fault] else # is a normal return value raise "Missing return value!" if parser.params.size == 0 raise "Too many return values. Only one allowed!" if parser.params.size > 1 [true, parser.params[0]] end end def parseMethodCall(str) parser = @parser_class.new parser.parse(str) raise "No valid method call - missing method name!" if parser.method_name.nil? [parser.method_name, parser.params] end end module StreamParserMixin attr_reader :params attr_reader :method_name attr_reader :fault def initialize(*a) super(*a) @params = [] @values = [] @val_stack = [] @names = [] @name = [] @structs = [] @struct = {} @method_name = nil @fault = nil @data = nil end def startElement(name, attrs=[]) @data = nil case name when "value" @value = nil when "nil" raise "wrong/unknown XML-RPC type 'nil'" unless Config::ENABLE_NIL_PARSER @value = :nil when "array" @val_stack << @values @values = [] when "struct" @names << @name @name = [] @structs << @struct @struct = {} end end def endElement(name) @data ||= "" case name when "string" @value = @data when "i4", "i8", "int" @value = Convert.int(@data) when "boolean" @value = Convert.boolean(@data) when "double" @value = Convert.double(@data) when "dateTime.iso8601" @value = Convert.dateTime(@data) when "base64" @value = Convert.base64(@data) when "value" @value = @data if @value.nil? @values << (@value == :nil ? nil : @value) when "array" @value = @values @values = @val_stack.pop when "struct" @value = Convert.struct(@struct) @name = @names.pop @struct = @structs.pop when "name" @name[0] = @data when "member" @struct[@name[0]] = @values.pop when "param" @params << @values[0] @values = [] when "fault" @fault = Convert.fault(@values[0]) when "methodName" @method_name = @data end @data = nil end def character(data) if @data @data << data else @data = data end end end # module StreamParserMixin class REXMLStreamParser < AbstractStreamParser def initialize require "rexml/document" @parser_class = StreamListener end class StreamListener include StreamParserMixin alias :tag_start :startElement alias :tag_end :endElement alias :text :character alias :cdata :character def method_missing(*a) # ignore end def parse(str) REXML::Document.parse_stream(str, self) end end end class LibXMLStreamParser < AbstractStreamParser def initialize require 'libxml' @parser_class = LibXMLStreamListener end class LibXMLStreamListener include StreamParserMixin def on_start_element_ns(name, attributes, prefix, uri, namespaces) startElement(name) end def on_end_element_ns(name, prefix, uri) endElement(name) end alias :on_characters :character alias :on_cdata_block :character def method_missing(*a) end def parse(str) parser = LibXML::XML::SaxParser.string(str) parser.callbacks = self parser.parse() end end end Classes = [REXMLStreamParser, LibXMLStreamParser] # yields an instance of each installed parser def self.each_installed_parser XMLRPC::XMLParser::Classes.each do |klass| begin yield klass.new rescue LoadError end end end end # module XMLParser end # module XMLRPC PK ]HB%gems/xmlrpc-0.3.0/lib/xmlrpc/utils.rbnu[# frozen_string_literal: false # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # module XMLRPC # :nodoc: # This module enables a user-class to be marshalled # by XML-RPC for Ruby into a Hash, with one additional # key/value pair ___class___ => ClassName # module Marshallable end # Defines ParserWriterChooseMixin, which makes it possible to choose a # different XMLWriter and/or XMLParser then the default one. # # The Mixin is used in client.rb (class XMLRPC::Client) # and server.rb (class XMLRPC::BasicServer) module ParserWriterChooseMixin # Sets the XMLWriter to use for generating XML output. # # Should be an instance of a class from module XMLRPC::XMLWriter. # # If this method is not called, then XMLRPC::Config::DEFAULT_WRITER is used. def set_writer(writer) @create = Create.new(writer) self end # Sets the XMLParser to use for parsing XML documents. # # Should be an instance of a class from module XMLRPC::XMLParser. # # If this method is not called, then XMLRPC::Config::DEFAULT_PARSER is used. def set_parser(parser) @parser = parser self end private def create # if set_writer was not already called then call it now if @create.nil? then set_writer(Config::DEFAULT_WRITER.new) end @create end def parser # if set_parser was not already called then call it now if @parser.nil? then set_parser(Config::DEFAULT_PARSER.new) end @parser end end # module ParserWriterChooseMixin module Service # Base class for XMLRPC::Service::Interface definitions, used # by XMLRPC::BasicServer#add_handler class BasicInterface attr_reader :prefix, :methods def initialize(prefix) @prefix = prefix @methods = [] end def add_method(sig, help=nil, meth_name=nil) mname = nil sig = [sig] if sig.kind_of? String sig = sig.collect do |s| name, si = parse_sig(s) raise "Wrong signatures!" if mname != nil and name != mname mname = name si end @methods << [mname, meth_name || mname, sig, help] end private def parse_sig(sig) # sig is a String if sig =~ /^\s*(\w+)\s+([^(]+)(\(([^)]*)\))?\s*$/ params = [$1] name = $2.strip $4.split(",").each {|i| params << i.strip} if $4 != nil return name, params else raise "Syntax error in signature" end end end # class BasicInterface # # Class which wraps a XMLRPC::Service::Interface definition, used # by XMLRPC::BasicServer#add_handler # class Interface < BasicInterface def initialize(prefix, &p) raise "No interface specified" if p.nil? super(prefix) instance_eval(&p) end def get_methods(obj, delim=".") prefix = @prefix + delim @methods.collect { |name, meth, sig, help| [prefix + name.to_s, obj.method(meth).to_proc, sig, help] } end private def meth(*a) add_method(*a) end end # class Interface class PublicInstanceMethodsInterface < BasicInterface def initialize(prefix) super(prefix) end def get_methods(obj, delim=".") prefix = @prefix + delim obj.class.public_instance_methods(false).collect { |name| [prefix + name.to_s, obj.method(name).to_proc, nil, nil] } end end end # module Service # # Short-form to create a XMLRPC::Service::Interface # def self.interface(prefix, &p) Service::Interface.new(prefix, &p) end # Short-cut for creating a XMLRPC::Service::PublicInstanceMethodsInterface def self.iPIMethods(prefix) Service::PublicInstanceMethodsInterface.new(prefix) end module ParseContentType def parse_content_type(str) a, *b = str.split(";") return a.strip.downcase, *b end end end # module XMLRPC PK ]*#&gems/xmlrpc-0.3.0/lib/xmlrpc/create.rbnu[# frozen_string_literal: false # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "date" require "xmlrpc/base64" module XMLRPC # :nodoc: module XMLWriter class Abstract def ele(name, *children) element(name, nil, *children) end def tag(name, txt) element(name, nil, text(txt)) end end class Simple < Abstract def document_to_str(doc) doc end def document(*params) params.join("") end def pi(name, *params) "" end def element(name, attrs, *children) raise "attributes not yet implemented" unless attrs.nil? if children.empty? "<#{name}/>" else "<#{name}>" + children.join("") + "" end end def text(txt) cleaned = txt.dup cleaned.gsub!(/&/, '&') cleaned.gsub!(//, '>') cleaned end end # class Simple class XMLParser < Abstract def initialize require "xmltreebuilder" end def document_to_str(doc) doc.to_s end def document(*params) XML::SimpleTree::Document.new(*params) end def pi(name, *params) XML::SimpleTree::ProcessingInstruction.new(name, *params) end def element(name, attrs, *children) XML::SimpleTree::Element.new(name, attrs, *children) end def text(txt) XML::SimpleTree::Text.new(txt) end end # class XMLParser Classes = [Simple, XMLParser] # yields an instance of each installed XML writer def self.each_installed_writer XMLRPC::XMLWriter::Classes.each do |klass| begin yield klass.new rescue LoadError end end end end # module XMLWriter # Creates XML-RPC call/response documents # class Create def initialize(xml_writer = nil) @writer = xml_writer || Config::DEFAULT_WRITER.new end def methodCall(name, *params) name = name.to_s if name !~ /[a-zA-Z0-9_.:\/]+/ raise ArgumentError, "Wrong XML-RPC method-name" end parameter = params.collect do |param| @writer.ele("param", conv2value(param)) end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodCall", @writer.tag("methodName", name), @writer.ele("params", *parameter) ) ) @writer.document_to_str(tree) + "\n" end # # Generates a XML-RPC methodResponse document # # When +is_ret+ is +false+ then the +params+ array must # contain only one element, which is a structure # of a fault return-value. # # When +is_ret+ is +true+ then a normal # return-value of all the given +params+ is created. # def methodResponse(is_ret, *params) if is_ret resp = params.collect do |param| @writer.ele("param", conv2value(param)) end resp = [@writer.ele("params", *resp)] else if params.size != 1 or params[0] === XMLRPC::FaultException raise ArgumentError, "no valid fault-structure given" end resp = @writer.ele("fault", conv2value(params[0].to_h)) end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodResponse", resp) ) @writer.document_to_str(tree) + "\n" end private # # Converts a Ruby object into a XML-RPC tag # def conv2value(param) # :doc: val = case param when Integer # XML-RPC's int is 32bit int if Config::ENABLE_BIGINT @writer.tag("i4", param.to_s) else if param >= -(2**31) and param <= (2**31-1) @writer.tag("i4", param.to_s) else raise "Integer is too big! Must be signed 32-bit integer!" end end when TrueClass, FalseClass @writer.tag("boolean", param ? "1" : "0") when Symbol @writer.tag("string", param.to_s) when String @writer.tag("string", param) when NilClass if Config::ENABLE_NIL_CREATE @writer.ele("nil") else raise "Wrong type NilClass. Not allowed!" end when Float raise "Wrong value #{param}. Not allowed!" unless param.finite? @writer.tag("double", param.to_s) when Struct h = param.members.collect do |key| value = param[key] @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Hash # TODO: can a Hash be empty? h = param.collect do |key, value| @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Array # TODO: can an Array be empty? a = param.collect {|v| conv2value(v) } @writer.ele("array", @writer.ele("data", *a) ) when Time, Date, ::DateTime @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S")) when XMLRPC::DateTime @writer.tag("dateTime.iso8601", format("%.4d%02d%02dT%02d:%02d:%02d", *param.to_a)) when XMLRPC::Base64 @writer.tag("base64", param.encoded) else if Config::ENABLE_MARSHALLING and param.class.included_modules.include? XMLRPC::Marshallable # convert Ruby object into Hash ret = {"___class___" => param.class.name} param.instance_variables.each {|v| name = v[1..-1] val = param.instance_variable_get(v) if val.nil? ret[name] = val if Config::ENABLE_NIL_CREATE else ret[name] = val end } return conv2value(ret) else ok, pa = wrong_type(param) if ok return conv2value(pa) else raise "Wrong type!" end end end @writer.ele("value", val) end def wrong_type(value) false end end # class Create end # module XMLRPC PK ]N W'gems/xmlrpc-0.3.0/lib/xmlrpc/marshal.rbnu[# frozen_string_literal: false # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" module XMLRPC # :nodoc: # Marshalling of XMLRPC::Create#methodCall and XMLRPC::Create#methodResponse class Marshal include ParserWriterChooseMixin class << self def dump_call( methodName, *params ) new.dump_call( methodName, *params ) end def dump_response( param ) new.dump_response( param ) end def load_call( stringOrReadable ) new.load_call( stringOrReadable ) end def load_response( stringOrReadable ) new.load_response( stringOrReadable ) end alias dump dump_response alias load load_response end # class self def initialize( parser = nil, writer = nil ) set_parser( parser ) set_writer( writer ) end def dump_call( methodName, *params ) create.methodCall( methodName, *params ) end def dump_response( param ) create.methodResponse( ! param.kind_of?( XMLRPC::FaultException ) , param ) end # Returns [ methodname, params ] def load_call( stringOrReadable ) parser.parseMethodCall( stringOrReadable ) end # Returns +paramOrFault+ def load_response( stringOrReadable ) parser.parseMethodResponse( stringOrReadable )[1] end end # class Marshal end PK ]T&gems/xmlrpc-0.3.0/lib/xmlrpc/base64.rbnu[# frozen_string_literal: false # # xmlrpc/base64.rb # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # Released under the same term of license as Ruby. module XMLRPC # :nodoc: # This class is necessary for 'xmlrpc4r' to determine that a string should # be transmitted base64-encoded and not as a raw-string. # # You can use XMLRPC::Base64 on the client and server-side as a # parameter and/or return-value. class Base64 # Creates a new XMLRPC::Base64 instance with string +str+ as the # internal string. When +state+ is +:dec+ it assumes that the # string +str+ is not in base64 format (perhaps already decoded), # otherwise if +state+ is +:enc+ it decodes +str+ # and stores it as the internal string. def initialize(str, state = :dec) case state when :enc @str = Base64.decode(str) when :dec @str = str else raise ArgumentError, "wrong argument; either :enc or :dec" end end # Returns the decoded internal string. def decoded @str end # Returns the base64 encoded internal string. def encoded Base64.encode(@str) end # Decodes string +str+ with base64 and returns that value. def Base64.decode(str) str.gsub(/\s+/, "").unpack("m")[0] end # Encodes string +str+ with base64 and returns that value. def Base64.encode(str) [str].pack("m") end end end # module XMLRPC =begin = History $Id$ =end PK ]799&gems/xmlrpc-0.3.0/lib/xmlrpc/config.rbnu[# frozen_string_literal: false # # $Id$ # Configuration file for XML-RPC for Ruby # module XMLRPC # :nodoc: module Config # or XMLWriter::XMLParser DEFAULT_WRITER = XMLWriter::Simple # === Available parsers # # * XMLParser::REXMLStreamParser # * XMLParser::LibXMLStreamParser DEFAULT_PARSER = XMLParser::REXMLStreamParser # enable tag ENABLE_NIL_CREATE = false ENABLE_NIL_PARSER = false # allows integers greater than 32-bit if +true+ ENABLE_BIGINT = false # enable marshalling Ruby objects which include XMLRPC::Marshallable ENABLE_MARSHALLING = true # enable multiCall extension by default ENABLE_MULTICALL = false # enable Introspection extension by default ENABLE_INTROSPECTION = false end end PK ],,gems/bigdecimal-2.0.0/lib/bigdecimal/math.rbnu[# frozen_string_literal: false require 'bigdecimal' # #-- # Contents: # sqrt(x, prec) # sin (x, prec) # cos (x, prec) # atan(x, prec) Note: |x|<1, x=0.9999 may not converge. # PI (prec) # E (prec) == exp(1.0,prec) # # where: # x ... BigDecimal number to be computed. # |x| must be small enough to get convergence. # prec ... Number of digits to be obtained. #++ # # Provides mathematical functions. # # Example: # # require "bigdecimal/math" # # include BigMath # # a = BigDecimal((PI(100)/2).to_s) # puts sin(a,100) # => 0.99999999999999999999......e0 # module BigMath module_function # call-seq: # sqrt(decimal, numeric) -> BigDecimal # # Computes the square root of +decimal+ to the specified number of digits of # precision, +numeric+. # # BigMath.sqrt(BigDecimal('2'), 16).to_s # #=> "0.1414213562373095048801688724e1" # def sqrt(x, prec) x.sqrt(prec) end # call-seq: # sin(decimal, numeric) -> BigDecimal # # Computes the sine of +decimal+ to the specified number of digits of # precision, +numeric+. # # If +decimal+ is Infinity or NaN, returns NaN. # # BigMath.sin(BigMath.PI(5)/4, 5).to_s # #=> "0.70710678118654752440082036563292800375e0" # def sin(x, prec) raise ArgumentError, "Zero or negative precision for sin" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") two = BigDecimal("2") x = -x if neg = x < 0 if x > (twopi = two * BigMath.PI(prec)) if x > 30 x %= twopi else x -= twopi while x > twopi end end x1 = x x2 = x.mult(x,n) sign = 1 y = x d = y i = one z = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig sign = -sign x1 = x2.mult(x1,n) i += two z *= (i-one) * i d = sign * x1.div(z,m) y += d end neg ? -y : y end # call-seq: # cos(decimal, numeric) -> BigDecimal # # Computes the cosine of +decimal+ to the specified number of digits of # precision, +numeric+. # # If +decimal+ is Infinity or NaN, returns NaN. # # BigMath.cos(BigMath.PI(4), 16).to_s # #=> "-0.999999999999999999999999999999856613163740061349e0" # def cos(x, prec) raise ArgumentError, "Zero or negative precision for cos" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") two = BigDecimal("2") x = -x if x < 0 if x > (twopi = two * BigMath.PI(prec)) if x > 30 x %= twopi else x -= twopi while x > twopi end end x1 = one x2 = x.mult(x,n) sign = 1 y = one d = y i = BigDecimal("0") z = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig sign = -sign x1 = x2.mult(x1,n) i += two z *= (i-one) * i d = sign * x1.div(z,m) y += d end y end # call-seq: # atan(decimal, numeric) -> BigDecimal # # Computes the arctangent of +decimal+ to the specified number of digits of # precision, +numeric+. # # If +decimal+ is NaN, returns NaN. # # BigMath.atan(BigDecimal('-1'), 16).to_s # #=> "-0.785398163397448309615660845819878471907514682065e0" # def atan(x, prec) raise ArgumentError, "Zero or negative precision for atan" if prec <= 0 return BigDecimal("NaN") if x.nan? pi = PI(prec) x = -x if neg = x < 0 return pi.div(neg ? -2 : 2, prec) if x.infinite? return pi / (neg ? -4 : 4) if x.round(prec) == 1 x = BigDecimal("1").div(x, prec) if inv = x > 1 x = (-1 + sqrt(1 + x**2, prec))/x if dbl = x > 0.5 n = prec + BigDecimal.double_fig y = x d = y t = x r = BigDecimal("3") x2 = x.mult(x,n) while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = -t.mult(x2,n) d = t.div(r,m) y += d r += 2 end y *= 2 if dbl y = pi / 2 - y if inv y = -y if neg y end # call-seq: # PI(numeric) -> BigDecimal # # Computes the value of pi to the specified number of digits of precision, # +numeric+. # # BigMath.PI(10).to_s # #=> "0.3141592653589793238462643388813853786957412e1" # def PI(prec) raise ArgumentError, "Zero or negative precision for PI" if prec <= 0 n = prec + BigDecimal.double_fig zero = BigDecimal("0") one = BigDecimal("1") two = BigDecimal("2") m25 = BigDecimal("-0.04") m57121 = BigDecimal("-57121") pi = zero d = one k = one t = BigDecimal("-80") while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = t*m25 d = t.div(k,m) k = k+two pi = pi + d end d = one k = one t = BigDecimal("956") while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = t.div(m57121,n) d = t.div(k,m) pi = pi + d k = k+two end pi end # call-seq: # E(numeric) -> BigDecimal # # Computes e (the base of natural logarithms) to the specified number of # digits of precision, +numeric+. # # BigMath.E(10).to_s # #=> "0.271828182845904523536028752390026306410273e1" # def E(prec) raise ArgumentError, "Zero or negative precision for E" if prec <= 0 BigMath.exp(1, prec) end end PK ]; <]]0gems/bigdecimal-2.0.0/lib/bigdecimal/jacobian.rbnu[# frozen_string_literal: false require 'bigdecimal' # require 'bigdecimal/jacobian' # # Provides methods to compute the Jacobian matrix of a set of equations at a # point x. In the methods below: # # f is an Object which is used to compute the Jacobian matrix of the equations. # It must provide the following methods: # # f.values(x):: returns the values of all functions at x # # f.zero:: returns 0.0 # f.one:: returns 1.0 # f.two:: returns 2.0 # f.ten:: returns 10.0 # # f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. # # x is the point at which to compute the Jacobian. # # fx is f.values(x). # module Jacobian module_function # Determines the equality of two numbers by comparing to zero, or using the epsilon value def isEqual(a,b,zero=0.0,e=1.0e-8) aa = a.abs bb = b.abs if aa == zero && bb == zero then true else if ((a-b)/(aa+bb)).abs < e then true else false end end end # Computes the derivative of f[i] at x[i]. # fx is the value of f at x. def dfdxi(f,fx,x,i) nRetry = 0 n = x.size xSave = x[i] ok = 0 ratio = f.ten*f.ten*f.ten dx = x[i].abs/ratio dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps) dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps) until ok>0 do deriv = [] nRetry += 1 if nRetry > 100 raise "Singular Jacobian matrix. No change at x[" + i.to_s + "]" end dx = dx*f.two x[i] += dx fxNew = f.values(x) for j in 0...n do if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then ok += 1 deriv <<= (fxNew[j]-fx[j])/dx else deriv <<= f.zero end end x[i] = xSave end deriv end # Computes the Jacobian of f at x. fx is the value of f at x. def jacobian(f,fx,x) n = x.size dfdx = Array.new(n*n) for i in 0...n do df = dfdxi(f,fx,x,i) for j in 0...n do dfdx[j*n+i] = df[j] end end dfdx end end PK ]ь.gems/bigdecimal-2.0.0/lib/bigdecimal/ludcmp.rbnu[# frozen_string_literal: false require 'bigdecimal' # # Solves a*x = b for x, using LU decomposition. # module LUSolve module_function # Performs LU decomposition of the n by n matrix a. def ludecomp(a,n,zero=0,one=1) prec = BigDecimal.limit(nil) ps = [] scales = [] for i in 0...n do # pick up largest(abs. val.) element in each row. ps <<= i nrmrow = zero ixn = i*n for j in 0...n do biggst = a[ixn+j].abs nrmrow = biggst if biggst>nrmrow end if nrmrow>zero then scales <<= one.div(nrmrow,prec) else raise "Singular matrix" end end n1 = n - 1 for k in 0...n1 do # Gaussian elimination with partial pivoting. biggst = zero; for i in k...n do size = a[ps[i]*n+k].abs*scales[ps[i]] if size>biggst then biggst = size pividx = i end end raise "Singular matrix" if biggst<=zero if pividx!=k then j = ps[k] ps[k] = ps[pividx] ps[pividx] = j end pivot = a[ps[k]*n+k] for i in (k+1)...n do psin = ps[i]*n a[psin+k] = mult = a[psin+k].div(pivot,prec) if mult!=zero then pskn = ps[k]*n for j in (k+1)...n do a[psin+j] -= mult.mult(a[pskn+j],prec) end end end end raise "Singular matrix" if a[ps[n1]*n+n1] == zero ps end # Solves a*x = b for x, using LU decomposition. # # a is a matrix, b is a constant vector, x is the solution vector. # # ps is the pivot, a vector which indicates the permutation of rows performed # during LU decomposition. def lusolve(a,b,ps,zero=0.0) prec = BigDecimal.limit(nil) n = ps.size x = [] for i in 0...n do dot = zero psin = ps[i]*n for j in 0...i do dot = a[psin+j].mult(x[j],prec) + dot end x <<= b[ps[i]] - dot end (n-1).downto(0) do |i| dot = zero psin = ps[i]*n for j in (i+1)...n do dot = a[psin+j].mult(x[j],prec) + dot end x[i] = (x[i]-dot).div(a[psin+i],prec) end x end end PK ]h"AZZ.gems/bigdecimal-2.0.0/lib/bigdecimal/newton.rbnu[# frozen_string_literal: false require "bigdecimal/ludcmp" require "bigdecimal/jacobian" # # newton.rb # # Solves the nonlinear algebraic equation system f = 0 by Newton's method. # This program is not dependent on BigDecimal. # # To call: # n = nlsolve(f,x) # where n is the number of iterations required, # x is the initial value vector # f is an Object which is used to compute the values of the equations to be solved. # It must provide the following methods: # # f.values(x):: returns the values of all functions at x # # f.zero:: returns 0.0 # f.one:: returns 1.0 # f.two:: returns 2.0 # f.ten:: returns 10.0 # # f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. # # On exit, x is the solution vector. # module Newton include LUSolve include Jacobian module_function def norm(fv,zero=0.0) # :nodoc: s = zero n = fv.size for i in 0...n do s += fv[i]*fv[i] end s end # See also Newton def nlsolve(f,x) nRetry = 0 n = x.size f0 = f.values(x) zero = f.zero one = f.one two = f.two p5 = one/two d = norm(f0,zero) minfact = f.ten*f.ten*f.ten minfact = one/minfact e = f.eps while d >= e do nRetry += 1 # Not yet converged. => Compute Jacobian matrix dfdx = jacobian(f,f0,x) # Solve dfdx*dx = -f0 to estimate dx dx = lusolve(dfdx,f0,ludecomp(dfdx,n,zero,one),zero) fact = two xs = x.dup begin fact *= p5 if fact < minfact then raise "Failed to reduce function values." end for i in 0...n do x[i] = xs[i] - dx[i]*fact end f0 = f.values(x) dn = norm(f0,zero) end while(dn>=d) d = dn end nRetry end end PK ]< ,gems/bigdecimal-2.0.0/lib/bigdecimal/util.rbnu[# frozen_string_literal: false # #-- # bigdecimal/util extends various native classes to provide the #to_d method, # and provides BigDecimal#to_d and BigDecimal#to_digits. #++ require 'bigdecimal' class Integer < Numeric # call-seq: # int.to_d -> bigdecimal # # Returns the value of +int+ as a BigDecimal. # # require 'bigdecimal' # require 'bigdecimal/util' # # 42.to_d # => 0.42e2 # # See also BigDecimal::new. # def to_d BigDecimal(self) end end class Float < Numeric # call-seq: # float.to_d -> bigdecimal # float.to_d(precision) -> bigdecimal # # Returns the value of +float+ as a BigDecimal. # The +precision+ parameter is used to determine the number of # significant digits for the result (the default is Float::DIG). # # require 'bigdecimal' # require 'bigdecimal/util' # # 0.5.to_d # => 0.5e0 # 1.234.to_d(2) # => 0.12e1 # # See also BigDecimal::new. # def to_d(precision=Float::DIG) BigDecimal(self, precision) end end class String # call-seq: # str.to_d -> bigdecimal # # Returns the result of interpreting leading characters in +str+ # as a BigDecimal. # # require 'bigdecimal' # require 'bigdecimal/util' # # "0.5".to_d # => 0.5e0 # "123.45e1".to_d # => 0.12345e4 # "45.67 degrees".to_d # => 0.4567e2 # # See also BigDecimal::new. # def to_d BigDecimal.interpret_loosely(self) end end class BigDecimal < Numeric # call-seq: # a.to_digits -> string # # Converts a BigDecimal to a String of the form "nnnnnn.mmm". # This method is deprecated; use BigDecimal#to_s("F") instead. # # require 'bigdecimal/util' # # d = BigDecimal("3.14") # d.to_digits # => "3.14" # def to_digits if self.nan? || self.infinite? || self.zero? self.to_s else i = self.to_i.to_s _,f,_,z = self.frac.split i + "." + ("0"*(-z)) + f end end # call-seq: # a.to_d -> bigdecimal # # Returns self. # # require 'bigdecimal/util' # # d = BigDecimal("3.14") # d.to_d # => 0.314e1 # def to_d self end end class Rational < Numeric # call-seq: # rat.to_d(precision) -> bigdecimal # # Returns the value as a BigDecimal. # # The required +precision+ parameter is used to determine the number of # significant digits for the result. # # require 'bigdecimal' # require 'bigdecimal/util' # # Rational(22, 7).to_d(3) # => 0.314e1 # # See also BigDecimal::new. # def to_d(precision) BigDecimal(self, precision) end end class NilClass # call-seq: # nil.to_d -> bigdecimal # # Returns nil represented as a BigDecimal. # # require 'bigdecimal' # require 'bigdecimal/util' # # nil.to_d # => 0.0 # def to_d BigDecimal(0) end end PK ]Wgems/rake-13.0.1/MIT-LICENSEnu[Copyright (c) Jim Weirich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK ]/Igems/rake-13.0.1/Gemfilenu[source "https://rubygems.org" gemspec group :development do gem "bundler" gem "minitest" gem "coveralls" gem "rubocop" end PK ]Igems/rake-13.0.1/exe/rakenuȯ#!/usr/bin/ruby #-- # Copyright (c) 2003, 2004, 2005, 2006, 2007 Jim Weirich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. #++ require "rake" Rake.application.run PK ]VQOgems/rake-13.0.1/Rakefilenu[# Rakefile for rake -*- ruby -*- # Copyright 2003, 2004, 2005 by Jim Weirich (jim@weirichhouse.org) # All rights reserved. # This file may be distributed under an MIT style license. See # MIT-LICENSE for details. lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) begin require "bundler/gem_tasks" rescue LoadError end require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.verbose = true t.test_files = FileList["test/**/test_*.rb"] end require "rdoc/task" RDoc::Task.new do |doc| doc.main = "README.rdoc" doc.title = "Rake -- Ruby Make" doc.rdoc_files = FileList.new %w[lib MIT-LICENSE doc/**/*.rdoc *.rdoc] doc.rdoc_dir = "html" end task ghpages: :rdoc do %x[git checkout gh-pages] require "fileutils" FileUtils.rm_rf "/tmp/html" FileUtils.mv "html", "/tmp" FileUtils.rm_rf "*" FileUtils.cp_r Dir.glob("/tmp/html/*"), "." end task default: :test PK ]ogems/rake-13.0.1/README.rdocnu[= RAKE -- Ruby Make home :: https://github.com/ruby/rake bugs :: https://github.com/ruby/rake/issues docs :: https://ruby.github.io/rake == Description Rake is a Make-like program implemented in Ruby. Tasks and dependencies are specified in standard Ruby syntax. Rake has the following features: * Rakefiles (rake's version of Makefiles) are completely defined in standard Ruby syntax. No XML files to edit. No quirky Makefile syntax to worry about (is that a tab or a space?) * Users can specify tasks with prerequisites. * Rake supports rule patterns to synthesize implicit tasks. * Flexible FileLists that act like arrays but know about manipulating file names and paths. * A library of prepackaged tasks to make building rakefiles easier. For example, tasks for building tarballs. (Formerly tasks for building RDoc, Gems, and publishing to FTP were included in rake but they're now available in RDoc, RubyGems, and rake-contrib respectively.) * Supports parallel execution of tasks. == Installation === Gem Installation Download and install rake with the following. gem install rake == Usage === Simple Example First, you must write a "Rakefile" file which contains the build rules. Here's a simple example: task default: %w[test] task :test do ruby "test/unittest.rb" end This Rakefile has two tasks: * A task named "test", which -- upon invocation -- will run a unit test file in Ruby. * A task named "default". This task does nothing by itself, but it has exactly one dependency, namely the "test" task. Invoking the "default" task will cause Rake to invoke the "test" task as well. Running the "rake" command without any options will cause it to run the "default" task in the Rakefile: % ls Rakefile test/ % rake (in /home/some_user/Projects/rake) ruby test/unittest.rb ....unit test output here... Type "rake --help" for all available options. == Resources === Rake Information * {Rake command-line}[link:doc/command_line_usage.rdoc] * {Writing Rakefiles}[link:doc/rakefile.rdoc] * The original {Rake announcement}[link:doc/rational.rdoc] * Rake {glossary}[link:doc/glossary.rdoc] === Presentations and Articles about Rake * Avdi Grimm's rake series: 1. {Rake Basics}[http://devblog.avdi.org/2014/04/21/rake-part-1-basics/] 2. {Rake File Lists}[http://devblog.avdi.org/2014/04/22/rake-part-2-file-lists/] 3. {Rake Rules}[http://devblog.avdi.org/2014/04/23/rake-part-3-rules/] 4. {Rake Pathmap}[http://devblog.avdi.org/2014/04/24/rake-part-4-pathmap/] 5. {File Operations}[http://devblog.avdi.org/2014/04/25/rake-part-5-file-operations/] 6. {Clean and Clobber}[http://devblog.avdi.org/2014/04/28/rake-part-6-clean-and-clobber/] 7. {MultiTask}[http://devblog.avdi.org/2014/04/29/rake-part-7-multitask/] * {Jim Weirich's 2003 RubyConf presentation}[http://web.archive.org/web/20140221123354/http://onestepback.org/articles/buildingwithrake/] * Martin Fowler's article on Rake: http://martinfowler.com/articles/rake.html == Other Make Re-envisionings ... Rake is a late entry in the make replacement field. Here are links to other projects with similar (and not so similar) goals. * http://directory.fsf.org/wiki/Bras -- Bras, one of earliest implementations of "make in a scripting language". * http://www.a-a-p.org -- Make in Python * http://ant.apache.org -- The Ant project * http://search.cpan.org/search?query=PerlBuildSystem -- The Perl Build System * http://www.rubydoc.info/gems/rant/0.5.7/frames -- Rant, another Ruby make tool. == Credits [Jim Weirich] Who originally created Rake. [Ryan Dlugosz] For the initial conversation that sparked Rake. [Nobuyoshi Nakada ] For the initial patch for rule support. [Tilman Sauerbeck ] For the recursive rule patch. [Eric Hodel] For aid in maintaining rake. [Hiroshi SHIBATA] Maintainer of Rake 10.X and Rake 11.X == License Rake is available under an MIT-style license. :include: MIT-LICENSE --- = Other stuff Author:: Jim Weirich Requires:: Ruby 2.0.0 or later License:: Copyright Jim Weirich. Released under an MIT-style license. See the MIT-LICENSE file included in the distribution. == Warranty This software is provided "as is" and without any express or implied warranties, including, without limitation, the implied warranties of merchantability and fitness for a particular purpose. == Historical Rake was originally created by Jim Weirich, who unfortunately passed away in February 2014. This repository was originally hosted at {github.com/jimweirich/rake}[https://github.com/jimweirich/rake/], however with his passing, has been moved to {ruby/rake}[https://github.com/ruby/rake]. You can view Jim's last commit here: https://github.com/jimweirich/rake/tree/336559f28f55bce418e2ebcc0a57548dcbac4025 You can {read more about Jim}[https://en.wikipedia.org/wiki/Jim_Weirich] at Wikipedia. Thank you for this great tool, Jim. We'll remember you. PK ]vgems/rake-13.0.1/rake.gemspecnu[# -*- encoding: utf-8 -*- # stub: rake 13.0.1 ruby lib Gem::Specification.new do |s| s.name = "rake".freeze s.version = "13.0.1" s.required_rubygems_version = Gem::Requirement.new(">= 1.3.2".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "bug_tracker_uri" => "https://github.com/ruby/rake/issues", "changelog_uri" => "https://github.com/ruby/rake/blob/v13.0.1/History.rdoc", "documentation_uri" => "https://ruby.github.io/rake", "source_code_uri" => "https://github.com/ruby/rake/tree/v13.0.1" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Hiroshi SHIBATA".freeze, "Eric Hodel".freeze, "Jim Weirich".freeze] s.bindir = "exe".freeze s.date = "2019-11-12" s.description = "Rake is a Make-like program implemented in Ruby. Tasks and dependencies are\nspecified in standard Ruby syntax.\nRake has the following features:\n * Rakefiles (rake's version of Makefiles) are completely defined in standard Ruby syntax.\n No XML files to edit. No quirky Makefile syntax to worry about (is that a tab or a space?)\n * Users can specify tasks with prerequisites.\n * Rake supports rule patterns to synthesize implicit tasks.\n * Flexible FileLists that act like arrays but know about manipulating file names and paths.\n * Supports parallel execution of tasks.\n".freeze s.email = ["hsbt@ruby-lang.org".freeze, "drbrain@segment7.net".freeze, "".freeze] s.executables = ["rake".freeze] s.files = [".github/workflows/macos.yml".freeze, ".github/workflows/ubuntu-rvm.yml".freeze, ".github/workflows/ubuntu.yml".freeze, ".github/workflows/windows.yml".freeze, "CONTRIBUTING.rdoc".freeze, "Gemfile".freeze, "History.rdoc".freeze, "MIT-LICENSE".freeze, "README.rdoc".freeze, "Rakefile".freeze, "bin/bundle".freeze, "bin/console".freeze, "bin/rake".freeze, "bin/rdoc".freeze, "bin/rubocop".freeze, "bin/setup".freeze, "doc/command_line_usage.rdoc".freeze, "doc/example/Rakefile1".freeze, "doc/example/Rakefile2".freeze, "doc/example/a.c".freeze, "doc/example/b.c".freeze, "doc/example/main.c".freeze, "doc/glossary.rdoc".freeze, "doc/jamis.rb".freeze, "doc/proto_rake.rdoc".freeze, "doc/rake.1".freeze, "doc/rakefile.rdoc".freeze, "doc/rational.rdoc".freeze, "exe/rake".freeze, "lib/rake.rb".freeze, "lib/rake/application.rb".freeze, "lib/rake/backtrace.rb".freeze, "lib/rake/clean.rb".freeze, "lib/rake/cloneable.rb".freeze, "lib/rake/cpu_counter.rb".freeze, "lib/rake/default_loader.rb".freeze, "lib/rake/dsl_definition.rb".freeze, "lib/rake/early_time.rb".freeze, "lib/rake/ext/core.rb".freeze, "lib/rake/ext/string.rb".freeze, "lib/rake/file_creation_task.rb".freeze, "lib/rake/file_list.rb".freeze, "lib/rake/file_task.rb".freeze, "lib/rake/file_utils.rb".freeze, "lib/rake/file_utils_ext.rb".freeze, "lib/rake/invocation_chain.rb".freeze, "lib/rake/invocation_exception_mixin.rb".freeze, "lib/rake/late_time.rb".freeze, "lib/rake/linked_list.rb".freeze, "lib/rake/loaders/makefile.rb".freeze, "lib/rake/multi_task.rb".freeze, "lib/rake/name_space.rb".freeze, "lib/rake/packagetask.rb".freeze, "lib/rake/phony.rb".freeze, "lib/rake/private_reader.rb".freeze, "lib/rake/promise.rb".freeze, "lib/rake/pseudo_status.rb".freeze, "lib/rake/rake_module.rb".freeze, "lib/rake/rake_test_loader.rb".freeze, "lib/rake/rule_recursion_overflow_error.rb".freeze, "lib/rake/scope.rb".freeze, "lib/rake/task.rb".freeze, "lib/rake/task_argument_error.rb".freeze, "lib/rake/task_arguments.rb".freeze, "lib/rake/task_manager.rb".freeze, "lib/rake/tasklib.rb".freeze, "lib/rake/testtask.rb".freeze, "lib/rake/thread_history_display.rb".freeze, "lib/rake/thread_pool.rb".freeze, "lib/rake/trace_output.rb".freeze, "lib/rake/version.rb".freeze, "lib/rake/win32.rb".freeze, "rake.gemspec".freeze] s.homepage = "https://github.com/ruby/rake".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.2".freeze) s.rubygems_version = "3.3.5".freeze s.summary = "Rake is a Make-like program implemented in Ruby".freeze end PK ]?qFF,gems/rake-13.0.1/doc/command_line_usage.rdocnu[= Rake Command Line Usage Rake is invoked from the command line using: % rake [options ...] [VAR=VALUE ...] [targets ...] Options are: [name=value] Set the environment variable name to value during the execution of the rake command. You can access the value by using ENV['name']. [--all (-A)] Used in combination with the -T and -D options, will force those options to show all the tasks, even the ones without comments. [--backtrace{=_output_} (-n)] Enable a full backtrace (i.e. like --trace, but without the task tracing details). The _output_ parameter is optional, but if specified it controls where the backtrace output is sent. If _output_ is stdout, then backtrace output is directed to standard output. If _output_ is stderr, or if it is missing, then the backtrace output is sent to standard error. [--comments] Used in combination with the -W options to force the output to contain commented options only. This is the reverse of --all. [--describe _pattern_ (-D)] Describe the tasks (matching optional PATTERN), then exit. [--dry-run (-n)] Do a dry run. Print the tasks invoked and executed, but do not actually execute any of the actions. [--execute _code_ (-e)] Execute some Ruby code and exit. [--execute-print _code_ (-p)] Execute some Ruby code, print the result, and exit. [--execute-continue _code_ (-E)] Execute some Ruby code, then continue with normal task processing. [--help (-H)] Display some help text and exit. [--jobs _number_ (-j)] Specifies the maximum number of concurrent threads allowed. Rake will allocate threads as needed up to this maximum number. If omitted, Rake will attempt to estimate the number of CPUs on the system and add 4 to that number. The concurrent threads are used to execute the multitask prerequisites. Also see the -m option which turns all tasks into multitasks. Sample values: (no -j) : Allow up to (# of CPUs + 4) number of threads --jobs : Allow unlimited number of threads --jobs=1 : Allow only one thread (the main thread) --jobs=16 : Allow up to 16 concurrent threads [--job-stats _level_] Display job statistics at the completion of the run. By default, this will display the requested number of active threads (from the -j options) and the maximum number of threads in play at any given time. If the optional _level_ is history, then a complete trace of task history will be displayed on standard output. [--libdir _directory_ (-I)] Add _directory_ to the list of directories searched for require. [--multitask (-m)] Treat all tasks as multitasks. ('make/drake' semantics) [--nosearch (-N)] Do not search for a Rakefile in parent directories. [--prereqs (-P)] Display a list of all tasks and their immediate prerequisites. [--quiet (-q)] Do not echo commands from FileUtils. [--rakefile _filename_ (-f)] Use _filename_ as the name of the rakefile. The default rakefile names are +rakefile+ and +Rakefile+ (with +rakefile+ taking precedence). If the rakefile is not found in the current directory, +rake+ will search parent directories for a match. The directory where the Rakefile is found will become the current directory for the actions executed in the Rakefile. [--rakelibdir _rakelibdir_ (-R)] Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib') [--require _name_ (-r)] Require _name_ before executing the Rakefile. [--rules] Trace the rules resolution. [--silent (-s)] Like --quiet, but also suppresses the 'in directory' announcement. [--suppress-backtrace _pattern_ ] Line matching the regular expression _pattern_ will be removed from the backtrace output. Note that the --backtrace option is the full backtrace without these lines suppressed. [--system (-g)] Use the system wide (global) rakefiles. The project Rakefile is ignored. By default, the system wide rakefiles are used only if no project Rakefile is found. On Unix-like system, the system wide rake files are located in $HOME/.rake. On a windows system they are stored in $APPDATA/Rake. [--no-system (-G)] Use the project level Rakefile, ignoring the system-wide (global) rakefiles. [--tasks pattern (-T)] Display a list of the major tasks and their comments. Comments are defined using the "desc" command. If a pattern is given, then only tasks matching the pattern are displayed. [--trace{=_output_} (-t)] Turn on invoke/execute tracing. Also enable full backtrace on errors. The _output_ parameter is optional, but if specified it controls where the trace output is sent. If _output_ is stdout, then trace output is directed to standard output. If _output_ is stderr, or if it is missing, then trace output is sent to standard error. [--verbose (-v)] Echo the Sys commands to standard output. [--version (-V)] Display the program version and exit. [--where pattern (-W)] Display tasks that match pattern and the file and line number where the task is defined. By default this option will display all tasks, not just the tasks that have descriptions. [--no-deprecation-warnings (-X)] Do not display the deprecation warnings. In addition, any command line option of the form VAR=VALUE will be added to the environment hash ENV and may be tested in the Rakefile. PK ]@u,u,gems/rake-13.0.1/doc/jamis.rbnu[# frozen_string_literal: true module RDoc module Page FONTS = "\"Bitstream Vera Sans\", Verdana, Arial, Helvetica, sans-serif" STYLE = < pre { padding: 0.5em; border: 1px dotted black; background: #FFE; } CSS XHTML_PREAMBLE = %{ } HEADER = XHTML_PREAMBLE + < %title% ENDHEADER FILE_PAGE = <
    File
    %short_name%
    Path: %full_path% IF:cvsurl  (CVS) ENDIF:cvsurl
    Modified: %dtm_modified%

    HTML ################################################################### CLASS_PAGE = < %classmod%
    %full_name% IF:parent ENDIF:parent
    In: START:infiles HREF:full_path_url:full_path: IF:cvsurl  (CVS) ENDIF:cvsurl END:infiles
    Parent: IF:par_url ENDIF:par_url %parent% IF:par_url ENDIF:par_url
    HTML ################################################################### METHOD_LIST = < IF:diagram
    %diagram%
    ENDIF:diagram IF:description
    %description%
    ENDIF:description IF:requires
    Required Files
      START:requires
    • HREF:aref:name:
    • END:requires
    ENDIF:requires IF:toc
    Contents
    ENDIF:toc IF:methods
    Methods
      START:methods
    • HREF:aref:name:
    • END:methods
    ENDIF:methods IF:includes
    Included Modules
      START:includes
    • HREF:aref:name:
    • END:includes
    ENDIF:includes START:sections IF:sectitle IF:seccomment
    %seccomment%
    ENDIF:seccomment ENDIF:sectitle IF:classlist
    Classes and Modules
    %classlist% ENDIF:classlist IF:constants
    Constants
    START:constants IF:desc ENDIF:desc END:constants
    %name% = %value%
      %desc%
    ENDIF:constants IF:attributes
    Attributes
    START:attributes END:attributes
    IF:rw [%rw%] ENDIF:rw %name% %a_desc%
    ENDIF:attributes IF:method_list START:method_list IF:methods
    %type% %category% methods
    START:methods
    IF:callseq %callseq% ENDIF:callseq IFNOT:callseq %name%%params% ENDIF:callseq IF:codeurl [ source ] ENDIF:codeurl
    IF:m_desc
    %m_desc%
    ENDIF:m_desc IF:aka
    This method is also aliased as START:aka %name% END:aka
    ENDIF:aka IF:sourcecode
    %sourcecode%
    
    ENDIF:sourcecode
    END:methods ENDIF:methods END:method_list ENDIF:method_list END:sections HTML FOOTER = < ENDFOOTER BODY = HEADER + <
    #{METHOD_LIST}
    #{FOOTER} ENDBODY ########################## Source code ########################## SRC_PAGE = XHTML_PREAMBLE + < %title%
    %code%
    HTML ########################## Index ################################ FR_INDEX_BODY = <
    START:entries %name%
    END:entries
    HTML CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = XHTML_PREAMBLE + < %title% IF:inline_source ENDIF:inline_source IFNOT:inline_source ENDIF:inline_source <body bgcolor="white"> Click <a href="html/index.html">here</a> for a non-frames version of this page. </body> HTML end end PK ]Oq AA gems/rake-13.0.1/doc/example/a.cnu[#include void a() { printf ("In function a\n"); } PK ]۸ &gems/rake-13.0.1/doc/example/Rakefile1nu[# Example Rakefile -*- ruby -*- task :default => [:main] file "a.o" => ["a.c"] do |t| src = t.name.sub(/\.o$/, '.c') sh "gcc #{src} -c -o #{t.name}" end file "b.o" => ["b.c"] do |t| src = t.name.sub(/\.o$/, '.c') sh "gcc #{src} -c -o #{t.name}" end file "main.o" => ["main.c"] do |t| src = t.name.sub(/\.o$/, '.c') sh "gcc #{src} -c -o #{t.name}" end OBJFILES = ["a.o", "b.o", "main.o"] task :obj => OBJFILES file "main" => OBJFILES do |t| sh "gcc -o #{t.name} main.o a.o b.o" end task :clean do rm_f FileList['*.o'] Dir['*~'].each { |fn| rm_f fn } end task :clobber => [:clean] do rm_f "main" end task :run => ["main"] do sh "./main" end PK ]AA gems/rake-13.0.1/doc/example/b.cnu[#include void b() { printf ("In function b\n"); } PK ]";WW&gems/rake-13.0.1/doc/example/Rakefile2nu[# Example Rakefile -*- ruby -*- # Using the power of Ruby task :default => [:main] def ext(fn, newext) fn.sub(/\.[^.]+$/, newext) end SRCFILES = Dir['*.c'] OBJFILES = SRCFILES.collect { |fn| ext(fn,".o") } OBJFILES.each do |objfile| srcfile = ext(objfile, ".c") file objfile => [srcfile] do |t| sh "gcc #{srcfile} -c -o #{t.name}" end end file "main" => OBJFILES do |t| sh "gcc -o #{t.name} main.o a.o b.o" end task :clean do rm_f FileList['*.o'] Dir['*~'].each { |fn| rm_f fn } end task :clobber => [:clean] do rm_f "main" end task :run => ["main"] do sh "./main" end PK ]_bgg#gems/rake-13.0.1/doc/example/main.cnu[#include extern void a(); extern void b(); int main () { a(); b(); return 0; } PK ]PP"gems/rake-13.0.1/doc/rakefile.rdocnu[= Rakefile Format First of all, there is no special format for a Rakefile. A Rakefile contains executable Ruby code. Anything legal in a ruby script is allowed in a Rakefile. Now that we understand there is no special syntax in a Rakefile, there are some conventions that are used in a Rakefile that are a little unusual in a typical Ruby program. Since a Rakefile is tailored to specifying tasks and actions, the idioms used in a Rakefile are designed to support that. So, what goes into a Rakefile? == Tasks Tasks are the main unit of work in a Rakefile. Tasks have a name (usually given as a symbol or a string), a list of prerequisites (more symbols or strings) and a list of actions (given as a block). === Simple Tasks A task is declared by using the +task+ method. +task+ takes a single parameter that is the name of the task. task :name === Tasks with Prerequisites Any prerequisites are given as a list (enclosed in square brackets) following the name and an arrow (=>). task name: [:prereq1, :prereq2] *NOTE:* Although this syntax looks a little funky, it is legal Ruby. We are constructing a hash where the key is :name and the value for that key is the list of prerequisites. It is equivalent to the following ... hash = Hash.new hash[:name] = [:prereq1, :prereq2] task(hash) You can also use strings for task names and prerequisites, rake doesn't care. This is the same task definition: task 'name' => %w[prereq1 prereq2] As is this: task name: %w[prereq1 prereq2] We'll prefer this style for regular tasks with prerequisites throughout the rest of the document. Using an array of strings for the prerequisites means you will need to make fewer changes if you need to move tasks into namespaces or perform other refactorings. === Tasks with Actions Actions are defined by passing a block to the +task+ method. Any Ruby code can be placed in the block. The block may reference the task object via the block parameter. task name: [:prereq1, :prereq2] do |t| # actions (may reference t) end === Multiple Definitions A task may be specified more than once. Each specification adds its prerequisites and actions to the existing definition. This allows one part of a rakefile to specify the actions and a different rakefile (perhaps separately generated) to specify the dependencies. For example, the following is equivalent to the single task specification given above. task :name task name: :prereq1 task name: %w[prereq2] task :name do |t| # actions end == File Tasks Some tasks are designed to create a file from one or more other files. Tasks that generate these files may be skipped if the file already exists. File tasks are used to specify file creation tasks. File tasks are declared using the +file+ method (instead of the +task+ method). In addition, file tasks are usually named with a string rather than a symbol. The following file task creates a executable program (named +prog+) given two object files named +a.o+ and +b.o+. The tasks for creating +a.o+ and +b.o+ are not shown. file "prog" => ["a.o", "b.o"] do |t| sh "cc -o #{t.name} #{t.prerequisites.join(' ')}" end == Directory Tasks It is common to need to create directories upon demand. The +directory+ convenience method is a short-hand for creating a FileTask that creates the directory. For example, the following declaration ... directory "testdata/examples/doc" is equivalent to ... file "testdata" do |t| mkdir t.name end file "testdata/examples" => ["testdata"] do |t| mkdir t.name end file "testdata/examples/doc" => ["testdata/examples"] do |t| mkdir t.name end The +directory+ method does not accept prerequisites or actions, but both prerequisites and actions can be added later. For example ... directory "testdata" file "testdata" => ["otherdata"] file "testdata" do cp Dir["standard_data/*.data"], "testdata" end == Tasks with Parallel Prerequisites Rake allows parallel execution of prerequisites using the following syntax: multitask copy_files: %w[copy_src copy_doc copy_bin] do puts "All Copies Complete" end In this example, +copy_files+ is a normal rake task. Its actions are executed whenever all of its prerequisites are done. The big difference is that the prerequisites (+copy_src+, +copy_bin+ and +copy_doc+) are executed in parallel. Each of the prerequisites are run in their own Ruby thread, possibly allowing faster overall runtime. === Secondary Prerequisites If any of the primary prerequisites of a multitask have common secondary prerequisites, all of the primary/parallel prerequisites will wait until the common prerequisites have been run. For example, if the copy_xxx tasks have the following prerequisites: task copy_src: :prep_for_copy task copy_bin: :prep_for_copy task copy_doc: :prep_for_copy Then the +prep_for_copy+ task is run before starting all the copies in parallel. Once +prep_for_copy+ is complete, +copy_src+, +copy_bin+, and +copy_doc+ are all run in parallel. Note that +prep_for_copy+ is run only once, even though it is referenced in multiple threads. === Thread Safety The Rake internal data structures are thread-safe with respect to the multitask parallel execution, so there is no need for the user to do extra synchronization for Rake's benefit. However, if there are user data structures shared between the parallel prerequisites, the user must do whatever is necessary to prevent race conditions. == Tasks with Arguments Prior to version 0.8.0, rake was only able to handle command line arguments of the form NAME=VALUE that were passed into Rake via the ENV hash. Many folks had asked for some kind of simple command line arguments, perhaps using "--" to separate regular task names from argument values on the command line. The problem is that there was no easy way to associate positional arguments on the command line with different tasks. Suppose both tasks :a and :b expect a command line argument: does the first value go with :a? What if :b is run first? Should it then get the first command line argument. Rake 0.8.0 solves this problem by explicitly passing values directly to the tasks that need them. For example, if I had a release task that required a version number, I could say: rake release[0.8.2] And the string "0.8.2" will be passed to the :release task. Multiple arguments can be passed by separating them with a comma, for example: rake name[john,doe] Just a few words of caution. The rake task name and its arguments need to be a single command line argument to rake. This generally means no spaces. If spaces are needed, then the entire name + argument string should be quoted. Something like this: rake "name[billy bob, smith]" (Quoting rules vary between operating systems and shells, so make sure you consult the proper docs for your OS/shell). === Tasks that Expect Parameters Parameters are only given to tasks that are setup to expect them. In order to handle named parameters, the task declaration syntax for tasks has been extended slightly. For example, a task that needs a first name and last name might be declared as: task :name, [:first_name, :last_name] The first argument is still the name of the task (:name in this case). The next two arguments are the names of the parameters expected by :name in an array (:first_name and :last_name in the example). To access the values of the parameters, the block defining the task behaviour can now accept a second parameter: task :name, [:first_name, :last_name] do |t, args| puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end The first argument of the block "t" is always bound to the current task object. The second argument "args" is an open-struct like object that allows access to the task arguments. Extra command line arguments to a task are ignored. If you wish to specify default values for the arguments, you can use the with_defaults method in the task body. Here is the above example where we specify default values for the first and last names: task :name, [:first_name, :last_name] do |t, args| args.with_defaults(:first_name => "John", :last_name => "Dough") puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end === Tasks that Expect Parameters and Have Prerequisites Tasks that use parameters have a slightly different format for prerequisites. Use the arrow notation to indicate the prerequisites for tasks with arguments. For example: task :name, [:first_name, :last_name] => [:pre_name] do |t, args| args.with_defaults(:first_name => "John", :last_name => "Dough") puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end === Tasks that take Variable-length Parameters Tasks that need to handle a list of values as a parameter can use the extras method of the args variable. This allows for tasks that can loop over a variable number of values, and its compatible with named parameters as well: task :email, [:message] do |t, args| mail = Mail.new(args.message) recipients = args.extras recipients.each do |target| mail.send_to(target) end end There is also the convenience method to_a that returns all parameters in the sequential order they were given, including those associated with named parameters. === Deprecated Task Parameters Format There is an older format for declaring task parameters that omitted the task argument array and used the :needs keyword to introduce the dependencies. That format is still supported for compatibility, but is not recommended for use. The older format may be dropped in future versions of rake. == Accessing Task Programmatically Sometimes it is useful to manipulate tasks programmatically in a Rakefile. To find a task object use Rake::Task.[]. === Programmatic Task Example For example, the following Rakefile defines two tasks. The :doit task simply prints a simple "DONE" message. The :dont class will lookup the doit class and remove (clear) all of its prerequisites and actions. task :doit do puts "DONE" end task :dont do Rake::Task[:doit].clear end Running this example: $ rake doit (in /Users/jim/working/git/rake/x) DONE $ rake dont doit (in /Users/jim/working/git/rake/x) $ The ability to programmatically manipulate tasks gives rake very powerful meta-programming capabilities w.r.t. task execution, but should be used with caution. == Rules When a file is named as a prerequisite, but does not have a file task defined for it, Rake will attempt to synthesize a task by looking at a list of rules supplied in the Rakefile. Suppose we were trying to invoke task "mycode.o", but no task is defined for it. But the rakefile has a rule that look like this ... rule '.o' => ['.c'] do |t| sh "cc #{t.source} -c -o #{t.name}" end This rule will synthesize any task that ends in ".o". It has a prerequisite a source file with an extension of ".c" must exist. If Rake is able to find a file named "mycode.c", it will automatically create a task that builds "mycode.o" from "mycode.c". If the file "mycode.c" does not exist, rake will attempt to recursively synthesize a rule for it. When a task is synthesized from a rule, the +source+ attribute of the task is set to the matching source file. This allows us to write rules with actions that reference the source file. === Advanced Rules Any regular expression may be used as the rule pattern. Additionally, a proc may be used to calculate the name of the source file. This allows for complex patterns and sources. The following rule is equivalent to the example above. rule( /\.o$/ => [ proc {|task_name| task_name.sub(/\.[^.]+$/, '.c') } ]) do |t| sh "cc #{t.source} -c -o #{t.name}" end *NOTE:* Because of a _quirk_ in Ruby syntax, parenthesis are required on *rule* when the first argument is a regular expression. The following rule might be used for Java files ... rule '.class' => [ proc { |tn| tn.sub(/\.class$/, '.java').sub(/^classes\//, 'src/') } ] do |t| java_compile(t.source, t.name) end *NOTE:* +java_compile+ is a hypothetical method that invokes the java compiler. == Importing Dependencies Any ruby file (including other rakefiles) can be included with a standard Ruby +require+ command. The rules and declarations in the required file are just added to the definitions already accumulated. Because the files are loaded _before_ the rake targets are evaluated, the loaded files must be "ready to go" when the rake command is invoked. This makes generated dependency files difficult to use. By the time rake gets around to updating the dependencies file, it is too late to load it. The +import+ command addresses this by specifying a file to be loaded _after_ the main rakefile is loaded, but _before_ any targets on the command line are invoked. In addition, if the file name matches an explicit task, that task is invoked before loading the file. This allows dependency files to be generated and used in a single rake command invocation. Example: require 'rake/loaders/makefile' file ".depends.mf" => [SRC_LIST] do |t| sh "makedepend -f- -- #{CFLAGS} -- #{t.prerequisites} > #{t.name}" end import ".depends.mf" If ".depends" does not exist, or is out of date w.r.t. the source files, a new ".depends" file is generated using +makedepend+ before loading. == Comments Standard Ruby comments (beginning with "#") can be used anywhere it is legal in Ruby source code, including comments for tasks and rules. However, if you wish a task to be described using the "-T" switch, then you need to use the +desc+ command to describe the task. Example: desc "Create a distribution package" task package: %w[ ... ] do ... end The "-T" switch (or "--tasks" if you like to spell things out) will display a list of tasks that have a description. If you use +desc+ to describe your major tasks, you have a semi-automatic way of generating a summary of your Rake file. $ rake -T (in /home/.../rake) rake clean # Remove any temporary products. rake clobber # Remove any generated file. rake clobber_rdoc # Remove rdoc products rake contrib_test # Run tests for contrib_test rake default # Default Task rake install # Install the application rake lines # Count lines in the main rake file rake rdoc # Build the rdoc HTML Files rake rerdoc # Force a rebuild of the RDOC files rake test # Run tests rake testall # Run all test targets Only tasks with descriptions will be displayed with the "-T" switch. Use "-P" (or "--prereqs") to get a list of all tasks and their prerequisites. == Namespaces As projects grow (and along with it, the number of tasks), it is common for task names to begin to clash. For example, if you might have a main program and a set of sample programs built by a single Rakefile. By placing the tasks related to the main program in one namespace, and the tasks for building the sample programs in a different namespace, the task names will not interfere with each other. For example: namespace "main" do task :build do # Build the main program end end namespace "samples" do task :build do # Build the sample programs end end task build: %w[main:build samples:build] Referencing a task in a separate namespace can be achieved by prefixing the task name with the namespace and a colon (e.g. "main:build" refers to the :build task in the +main+ namespace). Nested namespaces are supported. Note that the name given in the +task+ command is always the unadorned task name without any namespace prefixes. The +task+ command always defines a task in the current namespace. === FileTasks File task names are not scoped by the namespace command. Since the name of a file task is the name of an actual file in the file system, it makes little sense to include file task names in name space. Directory tasks (created by the +directory+ command) are a type of file task and are also not affected by namespaces. === Name Resolution When looking up a task name, rake will start with the current namespace and attempt to find the name there. If it fails to find a name in the current namespace, it will search the parent namespaces until a match is found (or an error occurs if there is no match). The "rake" namespace is a special implicit namespace that refers to the toplevel names. If a task name begins with a "^" character, the name resolution will start in the parent namespace. Multiple "^" characters are allowed. Here is an example file with multiple :run tasks and how various names resolve in different locations. task :run namespace "one" do task :run namespace "two" do task :run # :run => "one:two:run" # "two:run" => "one:two:run" # "one:two:run" => "one:two:run" # "one:run" => "one:run" # "^run" => "one:run" # "^^run" => "rake:run" (the top level task) # "rake:run" => "rake:run" (the top level task) end # :run => "one:run" # "two:run" => "one:two:run" # "^run" => "rake:run" end # :run => "rake:run" # "one:run" => "one:run" # "one:two:run" => "one:two:run" == FileLists FileLists are the way Rake manages lists of files. You can treat a FileList as an array of strings for the most part, but FileLists support some additional operations. === Creating a FileList Creating a file list is easy. Just give it the list of file names: fl = FileList['file1.rb', file2.rb'] Or give it a glob pattern: fl = FileList['*.rb'] == Odds and Ends === do/end versus { } Blocks may be specified with either a +do+/+end+ pair, or with curly braces in Ruby. We _strongly_ recommend using +do+/+end+ to specify the actions for tasks and rules. Because the rakefile idiom tends to leave off parentheses on the task/file/rule methods, unusual ambiguities can arise when using curly braces. For example, suppose that the method +object_files+ returns a list of object files in a project. Now we use +object_files+ as the prerequisites in a rule specified with actions in curly braces. # DON'T DO THIS! file "prog" => object_files { # Actions are expected here (but it doesn't work)! } Because curly braces have a higher precedence than +do+/+end+, the block is associated with the +object_files+ method rather than the +file+ method. This is the proper way to specify the task ... # THIS IS FINE file "prog" => object_files do # Actions go here end == Rakefile Path When issuing the +rake+ command in a terminal, Rake will look for a Rakefile in the current directory. If a Rakefile is not found, it will search parent directories until one is found. For example, if a Rakefile resides in the +project/+ directory, moving deeper into the project's directory tree will not have an adverse effect on rake tasks: $ pwd /home/user/project $ cd lib/foo/bar $ pwd /home/user/project/lib/foo/bar $ rake run_pwd /home/user/project As far as rake is concerned, all tasks are run from the directory in which the Rakefile resides. === Multiple Rake Files Not all tasks need to be included in a single Rakefile. Additional rake files (with the file extension "+.rake+") may be placed in +rakelib+ directory located at the top level of a project (i.e. the same directory that contains the main +Rakefile+). Also, rails projects may include additional rake files in the +lib/tasks+ directory. === Clean and Clobber Tasks Through require 'rake/clean' Rake provides +clean+ and +clobber+ tasks: +clean+ :: Clean up the project by deleting scratch files and backup files. Add files to the +CLEAN+ FileList to have the +clean+ target handle them. +clobber+ :: Clobber all generated and non-source files in a project. The task depends on +clean+, so all the +CLEAN+ files will be deleted as well as files in the +CLOBBER+ FileList. The intent of this task is to return a project to its pristine, just unpacked state. You can add file names or glob patterns to both the +CLEAN+ and +CLOBBER+ lists. === Phony Task The phony task can be used as a dependency to allow file-based tasks to use non-file-based-tasks as prerequisites without forcing them to rebuild. You can require 'rake/phony' to add the +phony+ task. ---- == See * README.rdoc -- Main documentation for Rake. PK ]) $gems/rake-13.0.1/doc/proto_rake.rdocnu[= Original Prototype Rake This is the original 100 line prototype rake program. --- #!/usr/bin/env ruby require 'ftools' class Task TASKS = Hash.new attr_reader :prerequisites def initialize(task_name) @name = task_name @prerequisites = [] @actions = [] end def enhance(deps=nil, &block) @prerequisites |= deps if deps @actions << block if block_given? self end def name @name.to_s end def invoke @prerequisites.each { |n| Task[n].invoke } execute if needed? end def execute return if @triggered @triggered = true @actions.collect { |act| result = act.call(self) }.last end def needed? true end def timestamp Time.now end class << self def [](task_name) TASKS[intern(task_name)] or fail "Don't know how to rake #{task_name}" end def define_task(args, &block) case args when Hash fail "Too Many Target Names: #{args.keys.join(' ')}" if args.size > 1 fail "No Task Name Given" if args.size < 1 task_name = args.keys[0] deps = args[task_name] else task_name = args deps = [] end deps = deps.collect {|d| intern(d) } get(task_name).enhance(deps, &block) end def get(task_name) name = intern(task_name) TASKS[name] ||= self.new(name) end def intern(task_name) (Symbol === task_name) ? task_name : task_name.intern end end end class FileTask < Task def needed? return true unless File.exist?(name) latest_prereq = @prerequisites.collect{|n| Task[n].timestamp}.max return false if latest_prereq.nil? timestamp < latest_prereq end def timestamp File.new(name.to_s).mtime end end def task(args, &block) Task.define_task(args, &block) end def file(args, &block) FileTask.define_task(args, &block) end def sys(cmd) puts cmd system(cmd) or fail "Command Failed: [#{cmd}]" end def rake begin here = Dir.pwd while ! File.exist?("Rakefile") Dir.chdir("..") fail "No Rakefile found" if Dir.pwd == here here = Dir.pwd end puts "(in #{Dir.pwd})" load "./Rakefile" ARGV.push("default") if ARGV.size == 0 ARGV.each { |task_name| Task[task_name].invoke } rescue Exception => ex puts "rake aborted ... #{ex.message}" puts ex.backtrace.find {|str| str =~ /Rakefile/ } || "" end end if __FILE__ == $0 then rake end PK ]v3HH"gems/rake-13.0.1/doc/rational.rdocnu[= Why rake? Ok, let me state from the beginning that I never intended to write this code. I'm not convinced it is useful, and I'm not convinced anyone would even be interested in it. All I can say is that Why's onion truck must by been passing through the Ohio valley. What am I talking about? ... A Ruby version of Make. See, I can sense you cringing already, and I agree. The world certainly doesn't need yet another reworking of the "make" program. I mean, we already have "ant". Isn't that enough? It started yesterday. I was helping a coworker fix a problem in one of the Makefiles we use in our project. Not a particularly tough problem, but during the course of the conversation I began lamenting some of the shortcomings of make. In particular, in one of my makefiles I wanted to determine the name of a file dynamically and had to resort to some simple scripting (in Ruby) to make it work. "Wouldn't it be nice if you could just use Ruby inside a Makefile" I said. My coworker (a recent convert to Ruby) agreed, but wondered what it would look like. So I sketched the following on the whiteboard... "What if you could specify the make tasks in Ruby, like this ..." task "build" do java_compile(...args, etc ...) end "The task function would register "build" as a target to be made, and the block would be the action executed whenever the build system determined that it was time to do the build target." We agreed that would be cool, but writing make from scratch would be WAY too much work. And that was the end of that! ... Except I couldn't get the thought out of my head. What exactly would be needed to make the about syntax work as a make file? Hmmm, you would need to register the tasks, you need some way of specifying dependencies between tasks, and some way of kicking off the process. Hey! What if we did ... and fifteen minutes later I had a working prototype of Ruby make, complete with dependencies and actions. I showed the code to my coworker and we had a good laugh. It was just about a page worth of code that reproduced an amazing amount of the functionality of make. We were both truly stunned with the power of Ruby. But it didn't do everything make did. In particular, it didn't have timestamp based file dependencies (where a file is rebuilt if any of its prerequisite files have a later timestamp). Obviously THAT would be a pain to add and so Ruby Make would remain an interesting experiment. ... Except as I walked back to my desk, I started thinking about what file based dependencies would really need. Rats! I was hooked again, and by adding a new class and two new methods, file/timestamp dependencies were implemented. Ok, now I was really hooked. Last night (during CSI!) I massaged the code and cleaned it up a bit. The result is a bare-bones replacement for make in exactly 100 lines of code. For the curious, you can see it at ... * doc/proto_rake.rdoc Oh, about the name. When I wrote the example Ruby Make task on my whiteboard, my coworker exclaimed "Oh! I have the perfect name: Rake ... Get it? Ruby-Make. Rake!" He said he envisioned the tasks as leaves and Rake would clean them up ... or something like that. Anyways, the name stuck. Some quick examples ... A simple task to delete backup files ... task :clean do Dir['*~'].each {|fn| rm fn rescue nil} end Note that task names are symbols (they are slightly easier to type than quoted strings ... but you may use quoted string if you would rather). Rake makes the methods of the FileUtils module directly available, so we take advantage of the rm command. Also note the use of "rescue nil" to trap and ignore errors in the rm command. To run it, just type "rake clean". Rake will automatically find a Rakefile in the current directory (or above!) and will invoke the targets named on the command line. If there are no targets explicitly named, rake will invoke the task "default". Here's another task with dependencies ... task :clobber => [:clean] do rm_r "tempdir" end Task :clobber depends upon task :clean, so :clean will be run before :clobber is executed. Files are specified by using the "file" command. It is similar to the task command, except that the task name represents a file, and the task will be run only if the file doesn't exist, or if its modification time is earlier than any of its prerequisites. Here is a file based dependency that will compile "hello.cc" to "hello.o". file "hello.cc" file "hello.o" => ["hello.cc"] do |t| srcfile = t.name.sub(/\.o$/, ".cc") sh %{g++ #{srcfile} -c -o #{t.name}} end I normally specify file tasks with string (rather than symbols). Some file names can't be represented by symbols. Plus it makes the distinction between them more clear to the casual reader. Currently writing a task for each and every file in the project would be tedious at best. I envision a set of libraries to make this job easier. For instance, perhaps something like this ... require 'rake/ctools' Dir['*.c'].each do |fn| c_source_file(fn) end where "c_source_file" will create all the tasks need to compile all the C source files in a directory. Any number of useful libraries could be created for rake. That's it. There's no documentation (other than whats in this message). Does this sound interesting to anyone? If so, I'll continue to clean it up and write it up and publish it on RAA. Otherwise, I'll leave it as an interesting exercise and a tribute to the power of Ruby. Why /might/ rake be interesting to Ruby programmers. I don't know, perhaps ... * No weird make syntax (only weird Ruby syntax :-) * No need to edit or read XML (a la ant) * Platform independent build scripts. * Will run anywhere Ruby exists, so no need to have "make" installed. If you stay away from the "sys" command and use things like 'ftools', you can have a perfectly platform independent build script. Also rake is only 100 lines of code, so it can easily be packaged along with the rest of your code. So ... Sorry for the long rambling message. Like I said, I never intended to write this code at all. PK ]'S{"gems/rake-13.0.1/doc/glossary.rdocnu[= Glossary action :: Code to be executed in order to perform a task. Actions in a Rakefile are specified in a code block. (Usually delimited by +do+/+end+ pairs.) execute :: When a task is executed, all of its actions are performed in the order they were defined. Note that, unlike invoke, execute always executes the actions (without invoking or executing the prerequisites). file task (Rake::FileTask) :: A file task is a task whose purpose is to create a file (which has the same name as the task). When invoked, a file task will only execute if one or more of the following conditions are true. 1. The associated file does not exist. 2. A prerequisite has a later time stamp than the existing file. Because normal Tasks always have the current time as timestamp, a FileTask that has a normal Task prerequisite will always execute. invoke :: When a task is invoked, first we check to see if it has been invoked before. If it has been, then nothing else is done. If this is the first time it has been invoked, then we invoke each of its prerequisites. Finally, we check to see if we need to execute the actions of this task by calling Rake::Task#needed?. If the task is needed, we execute its actions. NOTE: Prerequisites are still invoked even if the task is not needed. prerequisites :: Every task has a (possibly empty) set of prerequisites. A prerequisite P to Task T is itself a task that must be invoked before Task T. rule :: A rule is a recipe for synthesizing a task when no task is explicitly defined. Rules generally synthesize file tasks. task (Rake::Task) :: The basic unit of work in a Rakefile. A task has a name, a set of prerequisites, and a list of actions to be performed. PK ]Xgems/rake-13.0.1/bin/rdocnu[#!/usr/bin/env ruby # frozen_string_literal: true # # This file was generated by Bundler. # # The application 'rdoc' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath) bundle_binstub = File.expand_path("../bundle", __FILE__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") end end require "rubygems" require "bundler/setup" load Gem.bin_path("rdoc", "rdoc") PK ]Ygems/rake-13.0.1/bin/rakenu[#!/usr/bin/env ruby # frozen_string_literal: true # # This file was generated by Bundler. # # The application 'rake' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath) bundle_binstub = File.expand_path("../bundle", __FILE__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") end end require "rubygems" require "bundler/setup" load Gem.bin_path("rake", "rake") PK ]|u%gems/rake-13.0.1/bin/rubocopnu[#!/usr/bin/env ruby # frozen_string_literal: true # # This file was generated by Bundler. # # The application 'rubocop' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath) bundle_binstub = File.expand_path("../bundle", __FILE__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") end end require "rubygems" require "bundler/setup" load Gem.bin_path("rubocop", "rubocop") PK ]t/;JJgems/rake-13.0.1/bin/setupnu[#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install PK ]r WUUgems/rake-13.0.1/bin/consolenu[#!/usr/bin/env ruby require "bundler/setup" require "rake" require "irb" IRB.start PK ]>h  gems/rake-13.0.1/bin/bundlenu[#!/usr/bin/env ruby # frozen_string_literal: true # # This file was generated by Bundler. # # The application 'bundle' is installed as part of a gem, and # this file is here to facilitate running it. # require "rubygems" m = Module.new do module_function def invoked_as_script? File.expand_path($0) == File.expand_path(__FILE__) end def env_var_version ENV["BUNDLER_VERSION"] end def cli_arg_version return unless invoked_as_script? # don't want to hijack other binstubs return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` bundler_version = nil update_index = nil ARGV.each_with_index do |a, i| if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN bundler_version = a end next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ bundler_version = $1 || ">= 0.a" update_index = i end bundler_version end def gemfile gemfile = ENV["BUNDLE_GEMFILE"] return gemfile if gemfile && !gemfile.empty? File.expand_path("../../Gemfile", __FILE__) end def lockfile lockfile = case File.basename(gemfile) when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) else "#{gemfile}.lock" end File.expand_path(lockfile) end def lockfile_version return unless File.file?(lockfile) lockfile_contents = File.read(lockfile) return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ Regexp.last_match(1) end def bundler_version @bundler_version ||= begin env_var_version || cli_arg_version || lockfile_version || "#{Gem::Requirement.default}.a" end end def load_bundler! ENV["BUNDLE_GEMFILE"] ||= gemfile # must dup string for RG < 1.8 compatibility activate_bundler(bundler_version.dup) end def activate_bundler(bundler_version) if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0") bundler_version = "< 2" end gem_error = activation_error_handling do gem "bundler", bundler_version end return if gem_error.nil? require_error = activation_error_handling do require "bundler/version" end return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION)) warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`" exit 42 end def activation_error_handling yield nil rescue StandardError, LoadError => e e end end m.load_bundler! if m.invoked_as_script? load Gem.bin_path("bundler", "bundle") end PK ]R  (gems/rake-13.0.1/lib/rake/linked_list.rbnu[# frozen_string_literal: true module Rake # Polylithic linked list structure used to implement several data # structures in Rake. class LinkedList include Enumerable attr_reader :head, :tail # Polymorphically add a new element to the head of a list. The # type of head node will be the same list type as the tail. def conj(item) self.class.cons(item, self) end # Is the list empty? # .make guards against a list being empty making any instantiated LinkedList # object not empty by default # You should consider overriding this method if you implement your own .make method def empty? false end # Lists are structurally equivalent. def ==(other) current = self while !current.empty? && !other.empty? return false if current.head != other.head current = current.tail other = other.tail end current.empty? && other.empty? end # Convert to string: LL(item, item...) def to_s items = map(&:to_s).join(", ") "LL(#{items})" end # Same as +to_s+, but with inspected items. def inspect items = map(&:inspect).join(", ") "LL(#{items})" end # For each item in the list. def each current = self while !current.empty? yield(current.head) current = current.tail end self end # Make a list out of the given arguments. This method is # polymorphic def self.make(*args) # return an EmptyLinkedList if there are no arguments return empty if !args || args.empty? # build a LinkedList by starting at the tail and iterating # through each argument # inject takes an EmptyLinkedList to start args.reverse.inject(empty) do |list, item| list = cons(item, list) list # return the newly created list for each item in the block end end # Cons a new head onto the tail list. def self.cons(head, tail) new(head, tail) end # The standard empty list class for the given LinkedList class. def self.empty self::EMPTY end protected def initialize(head, tail=EMPTY) @head = head @tail = tail end # Represent an empty list, using the Null Object Pattern. # # When inheriting from the LinkedList class, you should implement # a type specific Empty class as well. Make sure you set the class # instance variable @parent to the associated list class (this # allows conj, cons and make to work polymorphically). class EmptyLinkedList < LinkedList @parent = LinkedList def initialize end def empty? true end def self.cons(head, tail) @parent.cons(head, tail) end end EMPTY = EmptyLinkedList.new end end PK ]2bb-gems/rake-13.0.1/lib/rake/loaders/makefile.rbnu[# frozen_string_literal: true module Rake # Makefile loader to be used with the import file loader. Use this to # import dependencies from make dependency tools: # # require 'rake/loaders/makefile' # # file ".depends.mf" => [SRC_LIST] do |t| # sh "makedepend -f- -- #{CFLAGS} -- #{t.prerequisites} > #{t.name}" # end # # import ".depends.mf" # # See {Importing Dependencies}[link:doc/rakefile_rdoc.html#label-Importing+Dependencies] # for further details. class MakefileLoader include Rake::DSL SPACE_MARK = "\0" # :nodoc: # Load the makefile dependencies in +fn+. def load(fn) # :nodoc: lines = File.read fn lines.gsub!(/\\ /, SPACE_MARK) lines.gsub!(/#[^\n]*\n/m, "") lines.gsub!(/\\\n/, " ") lines.each_line do |line| process_line(line) end end private # Process one logical line of makefile data. def process_line(line) # :nodoc: file_tasks, args = line.split(":", 2) return if args.nil? dependents = args.split.map { |d| respace(d) } file_tasks.scan(/\S+/) do |file_task| file_task = respace(file_task) file file_task => dependents end end def respace(str) # :nodoc: str.tr SPACE_MARK, " " end end # Install the handler Rake.application.add_loader("mf", MakefileLoader.new) end PK ]u%gems/rake-13.0.1/lib/rake/ext/core.rbnu[# frozen_string_literal: true class Module # Check for an existing method in the current class before extending. If # the method already exists, then a warning is printed and the extension is # not added. Otherwise the block is yielded and any definitions in the # block will take effect. # # Usage: # # class String # rake_extension("xyz") do # def xyz # ... # end # end # end # def rake_extension(method) # :nodoc: if method_defined?(method) $stderr.puts "WARNING: Possible conflict with Rake extension: " + "#{self}##{method} already exists" else yield end end end PK ]yOurr'gems/rake-13.0.1/lib/rake/ext/string.rbnu[# frozen_string_literal: true require "rake/ext/core" class String rake_extension("ext") do # Replace the file extension with +newext+. If there is no extension on # the string, append the new extension to the end. If the new extension # is not given, or is the empty string, remove any existing extension. # # +ext+ is a user added method for the String class. # # This String extension comes from Rake def ext(newext="") return self.dup if [".", ".."].include? self if newext != "" newext = "." + newext unless newext =~ /^\./ end self.chomp(File.extname(self)) << newext end end rake_extension("pathmap") do # Explode a path into individual components. Used by +pathmap+. # # This String extension comes from Rake def pathmap_explode head, tail = File.split(self) return [self] if head == self return [tail] if head == "." || tail == "/" return [head, tail] if head == "/" return head.pathmap_explode + [tail] end protected :pathmap_explode # Extract a partial path from the path. Include +n+ directories from the # front end (left hand side) if +n+ is positive. Include |+n+| # directories from the back end (right hand side) if +n+ is negative. # # This String extension comes from Rake def pathmap_partial(n) dirs = File.dirname(self).pathmap_explode partial_dirs = if n > 0 dirs[0...n] elsif n < 0 dirs.reverse[0...-n].reverse else "." end File.join(partial_dirs) end protected :pathmap_partial # Perform the pathmap replacement operations on the given path. The # patterns take the form 'pat1,rep1;pat2,rep2...'. # # This String extension comes from Rake def pathmap_replace(patterns, &block) result = self patterns.split(";").each do |pair| pattern, replacement = pair.split(",") pattern = Regexp.new(pattern) if replacement == "*" && block_given? result = result.sub(pattern, &block) elsif replacement result = result.sub(pattern, replacement) else result = result.sub(pattern, "") end end result end protected :pathmap_replace # Map the path according to the given specification. The specification # controls the details of the mapping. The following special patterns are # recognized: # # %p :: The complete path. # %f :: The base file name of the path, with its file extension, # but without any directories. # %n :: The file name of the path without its file extension. # %d :: The directory list of the path. # %x :: The file extension of the path. An empty string if there # is no extension. # %X :: Everything *but* the file extension. # %s :: The alternate file separator if defined, otherwise use # # the standard file separator. # %% :: A percent sign. # # The %d specifier can also have a numeric prefix (e.g. '%2d'). # If the number is positive, only return (up to) +n+ directories in the # path, starting from the left hand side. If +n+ is negative, return (up # to) +n+ directories from the right hand side of the path. # # Examples: # # 'a/b/c/d/file.txt'.pathmap("%2d") => 'a/b' # 'a/b/c/d/file.txt'.pathmap("%-2d") => 'c/d' # # Also the %d, %p, %f, %n, # %x, and %X operators can take a pattern/replacement # argument to perform simple string substitutions on a particular part of # the path. The pattern and replacement are separated by a comma and are # enclosed by curly braces. The replacement spec comes after the % # character but before the operator letter. (e.g. "%{old,new}d"). # Multiple replacement specs should be separated by semi-colons (e.g. # "%{old,new;src,bin}d"). # # Regular expressions may be used for the pattern, and back refs may be # used in the replacement text. Curly braces, commas and semi-colons are # excluded from both the pattern and replacement text (let's keep parsing # reasonable). # # For example: # # "src/org/onestepback/proj/A.java".pathmap("%{^src,class}X.class") # # returns: # # "class/org/onestepback/proj/A.class" # # If the replacement text is '*', then a block may be provided to perform # some arbitrary calculation for the replacement. # # For example: # # "/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext| # ext.downcase # } # # Returns: # # "/path/to/file.txt" # # This String extension comes from Rake def pathmap(spec=nil, &block) return self if spec.nil? result = "".dup spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag| case frag when "%f" result << File.basename(self) when "%n" result << File.basename(self).ext when "%d" result << File.dirname(self) when "%x" result << File.extname(self) when "%X" result << self.ext when "%p" result << self when "%s" result << (File::ALT_SEPARATOR || File::SEPARATOR) when "%-" # do nothing when "%%" result << "%" when /%(-?\d+)d/ result << pathmap_partial($1.to_i) when /^%\{([^}]*)\}(\d*[dpfnxX])/ patterns, operator = $1, $2 result << pathmap("%" + operator).pathmap_replace(patterns, &block) when /^%/ fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'" else result << frag end end result end end end PK ].*C}}"gems/rake-13.0.1/lib/rake/phony.rbnu[# frozen_string_literal: true # Defines a :phony task that you can use as a dependency. This allows # file-based tasks to use non-file-based tasks as prerequisites # without forcing them to rebuild. # # See FileTask#out_of_date? and Task#timestamp for more info. require "rake" task :phony Rake::Task[:phony].tap do |task| def task.timestamp # :nodoc: Time.at 0 end end PK ]?{Hrr'gems/rake-13.0.1/lib/rake/early_time.rbnu[# frozen_string_literal: true module Rake # EarlyTime is a fake timestamp that occurs _before_ any other time value. class EarlyTime include Comparable include Singleton ## # The EarlyTime always comes before +other+! def <=>(other) -1 end def to_s # :nodoc: "" end end EARLY = EarlyTime.instance end PK ]n#0gems/rake-13.0.1/lib/rake/task_argument_error.rbnu[# frozen_string_literal: true module Rake # Error indicating an ill-formed task declaration. class TaskArgumentError < ArgumentError end end PK ]QG"gems/rake-13.0.1/lib/rake/clean.rbnu[# frozen_string_literal: true # The 'rake/clean' file defines two file lists (CLEAN and CLOBBER) and # two rake tasks (:clean and :clobber). # # [:clean] Clean up the project by deleting scratch files and backup # files. Add files to the CLEAN file list to have the :clean # target handle them. # # [:clobber] Clobber all generated and non-source files in a project. # The task depends on :clean, so all the clean files will # be deleted as well as files in the CLOBBER file list. # The intent of this task is to return a project to its # pristine, just unpacked state. require "rake" # :stopdoc: module Rake module Cleaner extend FileUtils module_function def cleanup_files(file_names) file_names.each do |file_name| cleanup(file_name) end end def cleanup(file_name, **opts) begin opts = { verbose: Rake.application.options.trace }.merge(opts) rm_r file_name, **opts rescue StandardError => ex puts "Failed to remove #{file_name}: #{ex}" unless file_already_gone?(file_name) end end def file_already_gone?(file_name) return false if File.exist?(file_name) path = file_name prev = nil while path = File.dirname(path) return false if cant_be_deleted?(path) break if [prev, "."].include?(path) prev = path end true end private_class_method :file_already_gone? def cant_be_deleted?(path_name) File.exist?(path_name) && (!File.readable?(path_name) || !File.executable?(path_name)) end private_class_method :cant_be_deleted? end end CLEAN = ::Rake::FileList["**/*~", "**/*.bak", "**/core"] CLEAN.clear_exclude.exclude { |fn| fn.pathmap("%f").downcase == "core" && File.directory?(fn) } desc "Remove any temporary products." task :clean do Rake::Cleaner.cleanup_files(CLEAN) end CLOBBER = ::Rake::FileList.new desc "Remove any generated files." task clobber: [:clean] do Rake::Cleaner.cleanup_files(CLOBBER) end PK ]d11&gems/rake-13.0.1/lib/rake/file_list.rbnu[# frozen_string_literal: true require "rake/cloneable" require "rake/file_utils_ext" require "rake/ext/string" module Rake ## # A FileList is essentially an array with a few helper methods defined to # make file manipulation a bit easier. # # FileLists are lazy. When given a list of glob patterns for possible files # to be included in the file list, instead of searching the file structures # to find the files, a FileList holds the pattern for latter use. # # This allows us to define a number of FileList to match any number of # files, but only search out the actual files when then FileList itself is # actually used. The key is that the first time an element of the # FileList/Array is requested, the pending patterns are resolved into a real # list of file names. # class FileList include Cloneable # == Method Delegation # # The lazy evaluation magic of FileLists happens by implementing all the # array specific methods to call +resolve+ before delegating the heavy # lifting to an embedded array object (@items). # # In addition, there are two kinds of delegation calls. The regular kind # delegates to the @items array and returns the result directly. Well, # almost directly. It checks if the returned value is the @items object # itself, and if so will return the FileList object instead. # # The second kind of delegation call is used in methods that normally # return a new Array object. We want to capture the return value of these # methods and wrap them in a new FileList object. We enumerate these # methods in the +SPECIAL_RETURN+ list below. # List of array methods (that are not in +Object+) that need to be # delegated. ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map(&:to_s) # List of additional methods that must be delegated. MUST_DEFINE = %w[inspect <=>] # List of methods that should not be delegated here (we define special # versions of them explicitly below). MUST_NOT_DEFINE = %w[to_a to_ary partition * <<] # List of delegated methods that return new array values which need # wrapping. SPECIAL_RETURN = %w[ map collect sort sort_by select find_all reject grep compact flatten uniq values_at + - & | ] DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).map(&:to_s).sort.uniq # Now do the delegation. DELEGATING_METHODS.each do |sym| if SPECIAL_RETURN.include?(sym) ln = __LINE__ + 1 class_eval %{ def #{sym}(*args, &block) resolve result = @items.send(:#{sym}, *args, &block) self.class.new.import(result) end }, __FILE__, ln else ln = __LINE__ + 1 class_eval %{ def #{sym}(*args, &block) resolve result = @items.send(:#{sym}, *args, &block) result.object_id == @items.object_id ? self : result end }, __FILE__, ln end end GLOB_PATTERN = %r{[*?\[\{]} # Create a file list from the globbable patterns given. If you wish to # perform multiple includes or excludes at object build time, use the # "yield self" pattern. # # Example: # file_list = FileList.new('lib/**/*.rb', 'test/test*.rb') # # pkg_files = FileList.new('lib/**/*') do |fl| # fl.exclude(/\bCVS\b/) # end # def initialize(*patterns) @pending_add = [] @pending = false @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup @exclude_procs = DEFAULT_IGNORE_PROCS.dup @items = [] patterns.each { |pattern| include(pattern) } yield self if block_given? end # Add file names defined by glob patterns to the file list. If an array # is given, add each element of the array. # # Example: # file_list.include("*.java", "*.cfg") # file_list.include %w( math.c lib.h *.o ) # def include(*filenames) # TODO: check for pending filenames.each do |fn| if fn.respond_to? :to_ary include(*fn.to_ary) else @pending_add << Rake.from_pathname(fn) end end @pending = true self end alias :add :include # Register a list of file name patterns that should be excluded from the # list. Patterns may be regular expressions, glob patterns or regular # strings. In addition, a block given to exclude will remove entries that # return true when given to the block. # # Note that glob patterns are expanded against the file system. If a file # is explicitly added to a file list, but does not exist in the file # system, then an glob pattern in the exclude list will not exclude the # file. # # Examples: # FileList['a.c', 'b.c'].exclude("a.c") => ['b.c'] # FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c'] # # If "a.c" is a file, then ... # FileList['a.c', 'b.c'].exclude("a.*") => ['b.c'] # # If "a.c" is not a file, then ... # FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c'] # def exclude(*patterns, &block) patterns.each do |pat| if pat.respond_to? :to_ary exclude(*pat.to_ary) else @exclude_patterns << Rake.from_pathname(pat) end end @exclude_procs << block if block_given? resolve_exclude unless @pending self end # Clear all the exclude patterns so that we exclude nothing. def clear_exclude @exclude_patterns = [] @exclude_procs = [] self end # A FileList is equal through array equality. def ==(array) to_ary == array end # Return the internal array object. def to_a resolve @items end # Return the internal array object. def to_ary to_a end # Lie about our class. def is_a?(klass) klass == Array || super(klass) end alias kind_of? is_a? # Redefine * to return either a string or a new file list. def *(other) result = @items * other case result when Array self.class.new.import(result) else result end end def <<(obj) resolve @items << Rake.from_pathname(obj) self end # Resolve all the pending adds now. def resolve if @pending @pending = false @pending_add.each do |fn| resolve_add(fn) end @pending_add = [] resolve_exclude end self end def resolve_add(fn) # :nodoc: case fn when GLOB_PATTERN add_matching(fn) else self << fn end end private :resolve_add def resolve_exclude # :nodoc: reject! { |fn| excluded_from_list?(fn) } self end private :resolve_exclude # Return a new FileList with the results of running +sub+ against each # element of the original list. # # Example: # FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o'] # def sub(pat, rep) inject(self.class.new) { |res, fn| res << fn.sub(pat, rep) } end # Return a new FileList with the results of running +gsub+ against each # element of the original list. # # Example: # FileList['lib/test/file', 'x/y'].gsub(/\//, "\\") # => ['lib\\test\\file', 'x\\y'] # def gsub(pat, rep) inject(self.class.new) { |res, fn| res << fn.gsub(pat, rep) } end # Same as +sub+ except that the original file list is modified. def sub!(pat, rep) each_with_index { |fn, i| self[i] = fn.sub(pat, rep) } self end # Same as +gsub+ except that the original file list is modified. def gsub!(pat, rep) each_with_index { |fn, i| self[i] = fn.gsub(pat, rep) } self end # Apply the pathmap spec to each of the included file names, returning a # new file list with the modified paths. (See String#pathmap for # details.) def pathmap(spec=nil, &block) collect { |fn| fn.pathmap(spec, &block) } end # Return a new FileList with String#ext method applied to # each member of the array. # # This method is a shortcut for: # # array.collect { |item| item.ext(newext) } # # +ext+ is a user added method for the Array class. def ext(newext="") collect { |fn| fn.ext(newext) } end # Grep each of the files in the filelist using the given pattern. If a # block is given, call the block on each matching line, passing the file # name, line number, and the matching line of text. If no block is given, # a standard emacs style file:linenumber:line message will be printed to # standard out. Returns the number of matched items. def egrep(pattern, *options) matched = 0 each do |fn| begin File.open(fn, "r", *options) do |inf| count = 0 inf.each do |line| count += 1 if pattern.match(line) matched += 1 if block_given? yield fn, count, line else puts "#{fn}:#{count}:#{line}" end end end end rescue StandardError => ex $stderr.puts "Error while processing '#{fn}': #{ex}" end end matched end # Return a new file list that only contains file names from the current # file list that exist on the file system. def existing select { |fn| File.exist?(fn) }.uniq end # Modify the current file list so that it contains only file name that # exist on the file system. def existing! resolve @items = @items.select { |fn| File.exist?(fn) }.uniq self end # FileList version of partition. Needed because the nested arrays should # be FileLists in this version. def partition(&block) # :nodoc: resolve result = @items.partition(&block) [ self.class.new.import(result[0]), self.class.new.import(result[1]), ] end # Convert a FileList to a string by joining all elements with a space. def to_s resolve self.join(" ") end # Add matching glob patterns. def add_matching(pattern) self.class.glob(pattern).each do |fn| self << fn unless excluded_from_list?(fn) end end private :add_matching # Should the given file name be excluded from the list? # # NOTE: This method was formerly named "exclude?", but Rails # introduced an exclude? method as an array method and setup a # conflict with file list. We renamed the method to avoid # confusion. If you were using "FileList#exclude?" in your user # code, you will need to update. def excluded_from_list?(fn) return true if @exclude_patterns.any? do |pat| case pat when Regexp fn =~ pat when GLOB_PATTERN flags = File::FNM_PATHNAME # Ruby <= 1.9.3 does not support File::FNM_EXTGLOB flags |= File::FNM_EXTGLOB if defined? File::FNM_EXTGLOB File.fnmatch?(pat, fn, flags) else fn == pat end end @exclude_procs.any? { |p| p.call(fn) } end DEFAULT_IGNORE_PATTERNS = [ /(^|[\/\\])CVS([\/\\]|$)/, /(^|[\/\\])\.svn([\/\\]|$)/, /\.bak$/, /~$/ ] DEFAULT_IGNORE_PROCS = [ proc { |fn| fn =~ /(^|[\/\\])core$/ && !File.directory?(fn) } ] def import(array) # :nodoc: @items = array self end class << self # Create a new file list including the files listed. Similar to: # # FileList.new(*args) def [](*args) new(*args) end # Get a sorted list of files matching the pattern. This method # should be preferred to Dir[pattern] and Dir.glob(pattern) because # the files returned are guaranteed to be sorted. def glob(pattern, *args) Dir.glob(pattern, *args).sort end end end end module Rake class << self # Yield each file or directory component. def each_dir_parent(dir) # :nodoc: old_length = nil while dir != "." && dir.length != old_length yield(dir) old_length = dir.length dir = File.dirname(dir) end end # Convert Pathname and Pathname-like objects to strings; # leave everything else alone def from_pathname(path) # :nodoc: path = path.to_path if path.respond_to?(:to_path) path = path.to_str if path.respond_to?(:to_str) path end end end # module Rake PK ]F- +gems/rake-13.0.1/lib/rake/dsl_definition.rbnu[# frozen_string_literal: true # Rake DSL functions. require "rake/file_utils_ext" module Rake ## # DSL is a module that provides #task, #desc, #namespace, etc. Use this # when you'd like to use rake outside the top level scope. # # For a Rakefile you run from the command line this module is automatically # included. module DSL #-- # Include the FileUtils file manipulation functions in the top # level module, but mark them private so that they don't # unintentionally define methods on other objects. #++ include FileUtilsExt private(*FileUtils.instance_methods(false)) private(*FileUtilsExt.instance_methods(false)) private # :call-seq: # task(task_name) # task(task_name: dependencies) # task(task_name, arguments => dependencies) # # Declare a basic task. The +task_name+ is always the first argument. If # the task name contains a ":" it is defined in that namespace. # # The +dependencies+ may be a single task name or an Array of task names. # The +argument+ (a single name) or +arguments+ (an Array of names) define # the arguments provided to the task. # # The task, argument and dependency names may be either symbols or # strings. # # A task with a single dependency: # # task clobber: %w[clean] do # rm_rf "html" # end # # A task with an argument and a dependency: # # task :package, [:version] => :test do |t, args| # # ... # end # # To invoke this task from the command line: # # $ rake package[1.2.3] # def task(*args, &block) # :doc: Rake::Task.define_task(*args, &block) end # Declare a file task. # # Example: # file "config.cfg" => ["config.template"] do # open("config.cfg", "w") do |outfile| # open("config.template") do |infile| # while line = infile.gets # outfile.puts line # end # end # end # end # def file(*args, &block) # :doc: Rake::FileTask.define_task(*args, &block) end # Declare a file creation task. # (Mainly used for the directory command). def file_create(*args, &block) Rake::FileCreationTask.define_task(*args, &block) end # Declare a set of files tasks to create the given directories on # demand. # # Example: # directory "testdata/doc" # def directory(*args, &block) # :doc: result = file_create(*args, &block) dir, _ = *Rake.application.resolve_args(args) dir = Rake.from_pathname(dir) Rake.each_dir_parent(dir) do |d| file_create d do |t| mkdir_p t.name unless File.exist?(t.name) end end result end # Declare a task that performs its prerequisites in # parallel. Multitasks does *not* guarantee that its prerequisites # will execute in any given order (which is obvious when you think # about it) # # Example: # multitask deploy: %w[deploy_gem deploy_rdoc] # def multitask(*args, &block) # :doc: Rake::MultiTask.define_task(*args, &block) end # Create a new rake namespace and use it for evaluating the given # block. Returns a NameSpace object that can be used to lookup # tasks defined in the namespace. # # Example: # # ns = namespace "nested" do # # the "nested:run" task # task :run # end # task_run = ns[:run] # find :run in the given namespace. # # Tasks can also be defined in a namespace by using a ":" in the task # name: # # task "nested:test" do # # ... # end # def namespace(name=nil, &block) # :doc: name = name.to_s if name.kind_of?(Symbol) name = name.to_str if name.respond_to?(:to_str) unless name.kind_of?(String) || name.nil? raise ArgumentError, "Expected a String or Symbol for a namespace name" end Rake.application.in_namespace(name, &block) end # Declare a rule for auto-tasks. # # Example: # rule '.o' => '.c' do |t| # sh 'cc', '-o', t.name, t.source # end # def rule(*args, &block) # :doc: Rake::Task.create_rule(*args, &block) end # Describes the next rake task. Duplicate descriptions are discarded. # Descriptions are shown with rake -T (up to the first # sentence) and rake -D (the entire description). # # Example: # desc "Run the Unit Tests" # task test: [:build] # # ... run tests # end # def desc(description) # :doc: Rake.application.last_description = description end # Import the partial Rakefiles +fn+. Imported files are loaded # _after_ the current file is completely loaded. This allows the # import statement to appear anywhere in the importing file, and yet # allowing the imported files to depend on objects defined in the # importing file. # # A common use of the import statement is to include files # containing dependency declarations. # # See also the --rakelibdir command line option. # # Example: # import ".depend", "my_rules" # def import(*fns) # :doc: fns.each do |fn| Rake.application.add_import(fn) end end end extend FileUtilsExt end # Extend the main object with the DSL commands. This allows top-level # calls to task, etc. to work from a Rakefile without polluting the # object inheritance tree. self.extend Rake::DSL PK ]&gems/rake-13.0.1/lib/rake/cloneable.rbnu[# frozen_string_literal: true module Rake ## # Mixin for creating easily cloned objects. module Cloneable # :nodoc: # The hook that is invoked by 'clone' and 'dup' methods. def initialize_copy(source) super source.instance_variables.each do |var| src_value = source.instance_variable_get(var) value = src_value.clone rescue src_value instance_variable_set(var, value) end end end end PK ];YII'gems/rake-13.0.1/lib/rake/file_utils.rbnu[# frozen_string_literal: true require "rbconfig" require "fileutils" #-- # This a FileUtils extension that defines several additional commands to be # added to the FileUtils utility functions. module FileUtils # Path to the currently running Ruby program RUBY = ENV["RUBY"] || File.join( RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"] + RbConfig::CONFIG["EXEEXT"]). sub(/.*\s.*/m, '"\&"') # Run the system command +cmd+. If multiple arguments are given the command # is run directly (without the shell, same semantics as Kernel::exec and # Kernel::system). # # It is recommended you use the multiple argument form over interpolating # user input for both usability and security reasons. With the multiple # argument form you can easily process files with spaces or other shell # reserved characters in them. With the multiple argument form your rake # tasks are not vulnerable to users providing an argument like # ; rm # -rf /. # # If a block is given, upon command completion the block is called with an # OK flag (true on a zero exit status) and a Process::Status object. # Without a block a RuntimeError is raised when the command exits non-zero. # # Examples: # # sh 'ls -ltr' # # sh 'ls', 'file with spaces' # # # check exit status after command runs # sh %{grep pattern file} do |ok, res| # if !ok # puts "pattern not found (status = #{res.exitstatus})" # end # end # def sh(*cmd, &block) options = (Hash === cmd.last) ? cmd.pop : {} shell_runner = block_given? ? block : create_shell_runner(cmd) set_verbose_option(options) verbose = options.delete :verbose noop = options.delete(:noop) || Rake::FileUtilsExt.nowrite_flag Rake.rake_output_message sh_show_command cmd if verbose unless noop res = (Hash === cmd.last) ? system(*cmd) : system(*cmd, options) status = $? status = Rake::PseudoStatus.new(1) if !res && status.nil? shell_runner.call(res, status) end end def create_shell_runner(cmd) # :nodoc: show_command = sh_show_command cmd show_command = show_command[0, 42] + "..." unless $trace lambda do |ok, status| ok or fail "Command failed with status (#{status.exitstatus}): " + "[#{show_command}]" end end private :create_shell_runner def sh_show_command(cmd) # :nodoc: cmd = cmd.dup if Hash === cmd.first env = cmd.first env = env.map { |name, value| "#{name}=#{value}" }.join " " cmd[0] = env end cmd.join " " end private :sh_show_command def set_verbose_option(options) # :nodoc: unless options.key? :verbose options[:verbose] = (Rake::FileUtilsExt.verbose_flag == Rake::FileUtilsExt::DEFAULT) || Rake::FileUtilsExt.verbose_flag end end private :set_verbose_option # Run a Ruby interpreter with the given arguments. # # Example: # ruby %{-pe '$_.upcase!' 1 sh(RUBY, *args, **options, &block) else sh("#{RUBY} #{args.first}", **options, &block) end end LN_SUPPORTED = [true] # Attempt to do a normal file link, but fall back to a copy if the link # fails. def safe_ln(*args, **options) if LN_SUPPORTED[0] begin return options.empty? ? ln(*args) : ln(*args, **options) rescue StandardError, NotImplementedError LN_SUPPORTED[0] = false end end options.empty? ? cp(*args) : cp(*args, **options) end # Split a file path into individual directory names. # # Example: # split_all("a/b/c") => ['a', 'b', 'c'] # def split_all(path) head, tail = File.split(path) return [tail] if head == "." || tail == "/" return [head, tail] if head == "/" return split_all(head) + [tail] end end PK ]"gems/rake-13.0.1/lib/rake/scope.rbnu[# frozen_string_literal: true module Rake class Scope < LinkedList # :nodoc: all # Path for the scope. def path map(&:to_s).reverse.join(":") end # Path for the scope + the named path. def path_with_task_name(task_name) "#{path}:#{task_name}" end # Trim +n+ innermost scope levels from the scope. In no case will # this trim beyond the toplevel scope. def trim(n) result = self while n > 0 && !result.empty? result = result.tail n -= 1 end result end # Scope lists always end with an EmptyScope object. See Null # Object Pattern) class EmptyScope < EmptyLinkedList @parent = Scope def path "" end def path_with_task_name(task_name) task_name end end # Singleton null object for an empty scope. EMPTY = EmptyScope.new end end PK ]sZZ+gems/rake-13.0.1/lib/rake/file_utils_ext.rbnu[# frozen_string_literal: true require "rake/file_utils" module Rake # # FileUtilsExt provides a custom version of the FileUtils methods # that respond to the verbose and nowrite # commands. # module FileUtilsExt include FileUtils class << self attr_accessor :verbose_flag, :nowrite_flag end DEFAULT = Object.new FileUtilsExt.verbose_flag = DEFAULT FileUtilsExt.nowrite_flag = false FileUtils.commands.each do |name| opts = FileUtils.options_of name default_options = [] if opts.include?("verbose") default_options << "verbose: FileUtilsExt.verbose_flag" end if opts.include?("noop") default_options << "noop: FileUtilsExt.nowrite_flag" end next if default_options.empty? module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args, **options, &block) super(*args, #{default_options.join(', ')}, **options, &block) end EOS end # Get/set the verbose flag controlling output from the FileUtils # utilities. If verbose is true, then the utility method is # echoed to standard output. # # Examples: # verbose # return the current value of the # # verbose flag # verbose(v) # set the verbose flag to _v_. # verbose(v) { code } # Execute code with the verbose flag set # # temporarily to _v_. Return to the # # original value when code is done. def verbose(value=nil) oldvalue = FileUtilsExt.verbose_flag FileUtilsExt.verbose_flag = value unless value.nil? if block_given? begin yield ensure FileUtilsExt.verbose_flag = oldvalue end end FileUtilsExt.verbose_flag end # Get/set the nowrite flag controlling output from the FileUtils # utilities. If verbose is true, then the utility method is # echoed to standard output. # # Examples: # nowrite # return the current value of the # # nowrite flag # nowrite(v) # set the nowrite flag to _v_. # nowrite(v) { code } # Execute code with the nowrite flag set # # temporarily to _v_. Return to the # # original value when code is done. def nowrite(value=nil) oldvalue = FileUtilsExt.nowrite_flag FileUtilsExt.nowrite_flag = value unless value.nil? if block_given? begin yield ensure FileUtilsExt.nowrite_flag = oldvalue end end oldvalue end # Use this function to prevent potentially destructive ruby code # from running when the :nowrite flag is set. # # Example: # # when_writing("Building Project") do # project.build # end # # The following code will build the project under normal # conditions. If the nowrite(true) flag is set, then the example # will print: # # DRYRUN: Building Project # # instead of actually building the project. # def when_writing(msg=nil) if FileUtilsExt.nowrite_flag $stderr.puts "DRYRUN: #{msg}" if msg else yield end end # Send the message to the default rake output (which is $stderr). def rake_output_message(message) $stderr.puts(message) end # Check that the options do not contain options not listed in # +optdecl+. An ArgumentError exception is thrown if non-declared # options are found. def rake_check_options(options, *optdecl) h = options.dup optdecl.each do |name| h.delete name end raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty? end extend self end end PK ])lq((gems/rake-13.0.1/lib/rake/packagetask.rbnu[# frozen_string_literal: true # Define a package task library to aid in the definition of # redistributable package files. require "rake" require "rake/tasklib" module Rake # Create a packaging task that will package the project into # distributable files (e.g zip archive or tar files). # # The PackageTask will create the following targets: # # +:package+ :: # Create all the requested package files. # # +:clobber_package+ :: # Delete all the package files. This target is automatically # added to the main clobber target. # # +:repackage+ :: # Rebuild the package files from scratch, even if they are not out # of date. # # "package_dir/name-version.tgz" :: # Create a gzipped tar package (if need_tar is true). # # "package_dir/name-version.tar.gz" :: # Create a gzipped tar package (if need_tar_gz is true). # # "package_dir/name-version.tar.bz2" :: # Create a bzip2'd tar package (if need_tar_bz2 is true). # # "package_dir/name-version.zip" :: # Create a zip package archive (if need_zip is true). # # Example: # # Rake::PackageTask.new("rake", "1.2.3") do |p| # p.need_tar = true # p.package_files.include("lib/**/*.rb") # end # class PackageTask < TaskLib # Name of the package (from the GEM Spec). attr_accessor :name # Version of the package (e.g. '1.3.2'). attr_accessor :version # Directory used to store the package files (default is 'pkg'). attr_accessor :package_dir # True if a gzipped tar file (tgz) should be produced (default is # false). attr_accessor :need_tar # True if a gzipped tar file (tar.gz) should be produced (default # is false). attr_accessor :need_tar_gz # True if a bzip2'd tar file (tar.bz2) should be produced (default # is false). attr_accessor :need_tar_bz2 # True if a xz'd tar file (tar.xz) should be produced (default is false) attr_accessor :need_tar_xz # True if a zip file should be produced (default is false) attr_accessor :need_zip # List of files to be included in the package. attr_accessor :package_files # Tar command for gzipped or bzip2ed archives. The default is 'tar'. attr_accessor :tar_command # Zip command for zipped archives. The default is 'zip'. attr_accessor :zip_command # True if parent directory should be omited (default is false) attr_accessor :without_parent_dir # Create a Package Task with the given name and version. Use +:noversion+ # as the version to build a package without a version or to provide a # fully-versioned package name. def initialize(name=nil, version=nil) init(name, version) yield self if block_given? define unless name.nil? end # Initialization that bypasses the "yield self" and "define" step. def init(name, version) @name = name @version = version @package_files = Rake::FileList.new @package_dir = "pkg" @need_tar = false @need_tar_gz = false @need_tar_bz2 = false @need_tar_xz = false @need_zip = false @tar_command = "tar" @zip_command = "zip" @without_parent_dir = false end # Create the tasks defined by this task library. def define fail "Version required (or :noversion)" if @version.nil? @version = nil if :noversion == @version desc "Build all the packages" task :package desc "Force a rebuild of the package files" task repackage: [:clobber_package, :package] desc "Remove package products" task :clobber_package do rm_r package_dir rescue nil end task clobber: [:clobber_package] [ [need_tar, tgz_file, "z"], [need_tar_gz, tar_gz_file, "z"], [need_tar_bz2, tar_bz2_file, "j"], [need_tar_xz, tar_xz_file, "J"] ].each do |need, file, flag| if need task package: ["#{package_dir}/#{file}"] file "#{package_dir}/#{file}" => [package_dir_path] + package_files do chdir(working_dir) { sh @tar_command, "#{flag}cvf", file, target_dir } mv "#{package_dir_path}/#{target_dir}", package_dir if without_parent_dir end end end if need_zip task package: ["#{package_dir}/#{zip_file}"] file "#{package_dir}/#{zip_file}" => [package_dir_path] + package_files do chdir(working_dir) { sh @zip_command, "-r", zip_file, target_dir } mv "#{package_dir_path}/#{zip_file}", package_dir if without_parent_dir end end directory package_dir_path => @package_files do @package_files.each do |fn| f = File.join(package_dir_path, fn) fdir = File.dirname(f) mkdir_p(fdir) unless File.exist?(fdir) if File.directory?(fn) mkdir_p(f) else rm_f f safe_ln(fn, f) end end end self end # The name of this package def package_name @version ? "#{@name}-#{@version}" : @name end # The directory this package will be built in def package_dir_path "#{package_dir}/#{package_name}" end # The package name with .tgz added def tgz_file "#{package_name}.tgz" end # The package name with .tar.gz added def tar_gz_file "#{package_name}.tar.gz" end # The package name with .tar.bz2 added def tar_bz2_file "#{package_name}.tar.bz2" end # The package name with .tar.xz added def tar_xz_file "#{package_name}.tar.xz" end # The package name with .zip added def zip_file "#{package_name}.zip" end def working_dir without_parent_dir ? package_dir_path : package_dir end # target directory relative to working_dir def target_dir without_parent_dir ? "." : package_name end end end PK ]4Tc(gems/rake-13.0.1/lib/rake/thread_pool.rbnu[# frozen_string_literal: true require "set" require "rake/promise" module Rake class ThreadPool # :nodoc: all # Creates a ThreadPool object. The +thread_count+ parameter is the size # of the pool. def initialize(thread_count) @max_active_threads = [thread_count, 0].max @threads = Set.new @threads_mon = Monitor.new @queue = Queue.new @join_cond = @threads_mon.new_cond @history_start_time = nil @history = [] @history_mon = Monitor.new @total_threads_in_play = 0 end # Creates a future executed by the +ThreadPool+. # # The args are passed to the block when executing (similarly to # Thread#new) The return value is an object representing # a future which has been created and added to the queue in the # pool. Sending #value to the object will sleep the # current thread until the future is finished and will return the # result (or raise an exception thrown from the future) def future(*args, &block) promise = Promise.new(args, &block) promise.recorder = lambda { |*stats| stat(*stats) } @queue.enq promise stat :queued, item_id: promise.object_id start_thread promise end # Waits until the queue of futures is empty and all threads have exited. def join @threads_mon.synchronize do begin stat :joining @join_cond.wait unless @threads.empty? stat :joined rescue Exception => e stat :joined $stderr.puts e $stderr.print "Queue contains #{@queue.size} items. " + "Thread pool contains #{@threads.count} threads\n" $stderr.print "Current Thread #{Thread.current} status = " + "#{Thread.current.status}\n" $stderr.puts e.backtrace.join("\n") @threads.each do |t| $stderr.print "Thread #{t} status = #{t.status}\n" $stderr.puts t.backtrace.join("\n") end raise e end end end # Enable the gathering of history events. def gather_history #:nodoc: @history_start_time = Time.now if @history_start_time.nil? end # Return a array of history events for the thread pool. # # History gathering must be enabled to be able to see the events # (see #gather_history). Best to call this when the job is # complete (i.e. after ThreadPool#join is called). def history # :nodoc: @history_mon.synchronize { @history.dup }. sort_by { |i| i[:time] }. each { |i| i[:time] -= @history_start_time } end # Return a hash of always collected statistics for the thread pool. def statistics # :nodoc: { total_threads_in_play: @total_threads_in_play, max_active_threads: @max_active_threads, } end private # processes one item on the queue. Returns true if there was an # item to process, false if there was no item def process_queue_item #:nodoc: return false if @queue.empty? # Even though we just asked if the queue was empty, it # still could have had an item which by this statement # is now gone. For this reason we pass true to Queue#deq # because we will sleep indefinitely if it is empty. promise = @queue.deq(true) stat :dequeued, item_id: promise.object_id promise.work return true rescue ThreadError # this means the queue is empty false end def safe_thread_count @threads_mon.synchronize do @threads.count end end def start_thread # :nodoc: @threads_mon.synchronize do next unless @threads.count < @max_active_threads t = Thread.new do begin while safe_thread_count <= @max_active_threads break unless process_queue_item end ensure @threads_mon.synchronize do @threads.delete Thread.current stat :ended, thread_count: @threads.count @join_cond.broadcast if @threads.empty? end end end @threads << t stat( :spawned, new_thread: t.object_id, thread_count: @threads.count) @total_threads_in_play = @threads.count if @threads.count > @total_threads_in_play end end def stat(event, data=nil) # :nodoc: return if @history_start_time.nil? info = { event: event, data: data, time: Time.now, thread: Thread.current.object_id, } @history_mon.synchronize { @history << info } end # for testing only def __queue__ # :nodoc: @queue end end end PK ]n $gems/rake-13.0.1/lib/rake/version.rbnu[# frozen_string_literal: true module Rake VERSION = "13.0.1" module Version # :nodoc: all MAJOR, MINOR, BUILD, *OTHER = Rake::VERSION.split "." NUMBERS = [MAJOR, MINOR, BUILD, *OTHER] end end PK ]^  $gems/rake-13.0.1/lib/rake/promise.rbnu[# frozen_string_literal: true module Rake # A Promise object represents a promise to do work (a chore) in the # future. The promise is created with a block and a list of # arguments for the block. Calling value will return the value of # the promised chore. # # Used by ThreadPool. # class Promise # :nodoc: all NOT_SET = Object.new.freeze # :nodoc: attr_accessor :recorder # Create a promise to do the chore specified by the block. def initialize(args, &block) @mutex = Mutex.new @result = NOT_SET @error = NOT_SET @args = args @block = block end # Return the value of this promise. # # If the promised chore is not yet complete, then do the work # synchronously. We will wait. def value unless complete? stat :sleeping_on, item_id: object_id @mutex.synchronize do stat :has_lock_on, item_id: object_id chore stat :releasing_lock_on, item_id: object_id end end error? ? raise(@error) : @result end # If no one else is working this promise, go ahead and do the chore. def work stat :attempting_lock_on, item_id: object_id if @mutex.try_lock stat :has_lock_on, item_id: object_id chore stat :releasing_lock_on, item_id: object_id @mutex.unlock else stat :bailed_on, item_id: object_id end end private # Perform the chore promised def chore if complete? stat :found_completed, item_id: object_id return end stat :will_execute, item_id: object_id begin @result = @block.call(*@args) rescue Exception => e @error = e end stat :did_execute, item_id: object_id discard end # Do we have a result for the promise def result? !@result.equal?(NOT_SET) end # Did the promise throw an error def error? !@error.equal?(NOT_SET) end # Are we done with the promise def complete? result? || error? end # free up these items for the GC def discard @args = nil @block = nil end # Record execution statistics if there is a recorder def stat(*args) @recorder.call(*args) if @recorder end end end PK ]YY'gems/rake-13.0.1/lib/rake/multi_task.rbnu[# frozen_string_literal: true module Rake # Same as a regular task, but the immediate prerequisites are done in # parallel using Ruby threads. # class MultiTask < Task private def invoke_prerequisites(task_args, invocation_chain) # :nodoc: invoke_prerequisites_concurrently(task_args, invocation_chain) end end end PK ]j"gems/rake-13.0.1/lib/rake/win32.rbnu[# frozen_string_literal: true require "rbconfig" module Rake # Win 32 interface methods for Rake. Windows specific functionality # will be placed here to collect that knowledge in one spot. module Win32 # :nodoc: all # Error indicating a problem in locating the home directory on a # Win32 system. class Win32HomeError < RuntimeError end class << self # True if running on a windows system. def windows? RbConfig::CONFIG["host_os"] =~ %r!(msdos|mswin|djgpp|mingw|[Ww]indows)! end # The standard directory containing system wide rake files on # Win 32 systems. Try the following environment variables (in # order): # # * HOME # * HOMEDRIVE + HOMEPATH # * APPDATA # * USERPROFILE # # If the above are not defined, the return nil. def win32_system_dir #:nodoc: win32_shared_path = ENV["HOME"] if win32_shared_path.nil? && ENV["HOMEDRIVE"] && ENV["HOMEPATH"] win32_shared_path = ENV["HOMEDRIVE"] + ENV["HOMEPATH"] end win32_shared_path ||= ENV["APPDATA"] win32_shared_path ||= ENV["USERPROFILE"] raise Win32HomeError, "Unable to determine home path environment variable." if win32_shared_path.nil? or win32_shared_path.empty? normalize(File.join(win32_shared_path, "Rake")) end # Normalize a win32 path so that the slashes are all forward slashes. def normalize(path) path.gsub(/\\/, "/") end end end end PK ]Ӭs~~:gems/rake-13.0.1/lib/rake/rule_recursion_overflow_error.rbnu[# frozen_string_literal: true module Rake # Error indicating a recursion overflow error in task selection. class RuleRecursionOverflowError < StandardError def initialize(*args) super @targets = [] end def add_target(target) @targets << target end def message super + ": [" + @targets.reverse.join(" => ") + "]" end end end PK ]0ZR+gems/rake-13.0.1/lib/rake/private_reader.rbnu[# frozen_string_literal: true module Rake # Include PrivateReader to use +private_reader+. module PrivateReader # :nodoc: all def self.included(base) base.extend(ClassMethods) end module ClassMethods # Declare a list of private accessors def private_reader(*names) attr_reader(*names) private(*names) end end end end PK ]7gems/rake-13.0.1/lib/rake/invocation_exception_mixin.rbnu[# frozen_string_literal: true module Rake module InvocationExceptionMixin # Return the invocation chain (list of Rake tasks) that were in # effect when this exception was detected by rake. May be null if # no tasks were active. def chain @rake_invocation_chain ||= nil end # Set the invocation chain in effect when this exception was # detected. def chain=(value) @rake_invocation_chain = value end end end PK ]R22!gems/rake-13.0.1/lib/rake/task.rbnu[# frozen_string_literal: true require "rake/invocation_exception_mixin" module Rake ## # A Task is the basic unit of work in a Rakefile. Tasks have associated # actions (possibly more than one) and a list of prerequisites. When # invoked, a task will first ensure that all of its prerequisites have an # opportunity to run and then it will execute its own actions. # # Tasks are not usually created directly using the new method, but rather # use the +file+ and +task+ convenience methods. # class Task # List of prerequisites for a task. attr_reader :prerequisites alias prereqs prerequisites # List of order only prerequisites for a task. attr_reader :order_only_prerequisites # List of actions attached to a task. attr_reader :actions # Application owning this task. attr_accessor :application # Array of nested namespaces names used for task lookup by this task. attr_reader :scope # File/Line locations of each of the task definitions for this # task (only valid if the task was defined with the detect # location option set). attr_reader :locations # Has this task already been invoked? Already invoked tasks # will be skipped unless you reenable them. attr_reader :already_invoked # Return task name def to_s name end def inspect # :nodoc: "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>" end # List of sources for task. attr_writer :sources def sources if defined?(@sources) @sources else prerequisites end end # List of prerequisite tasks def prerequisite_tasks (prerequisites + order_only_prerequisites).map { |pre| lookup_prerequisite(pre) } end def lookup_prerequisite(prerequisite_name) # :nodoc: scoped_prerequisite_task = application[prerequisite_name, @scope] if scoped_prerequisite_task == self unscoped_prerequisite_task = application[prerequisite_name] end unscoped_prerequisite_task || scoped_prerequisite_task end private :lookup_prerequisite # List of all unique prerequisite tasks including prerequisite tasks' # prerequisites. # Includes self when cyclic dependencies are found. def all_prerequisite_tasks seen = {} collect_prerequisites(seen) seen.values end def collect_prerequisites(seen) # :nodoc: prerequisite_tasks.each do |pre| next if seen[pre.name] seen[pre.name] = pre pre.collect_prerequisites(seen) end end protected :collect_prerequisites # First source from a rule (nil if no sources) def source sources.first end # Create a task named +task_name+ with no actions or prerequisites. Use # +enhance+ to add actions and prerequisites. def initialize(task_name, app) @name = task_name.to_s @prerequisites = [] @actions = [] @already_invoked = false @comments = [] @lock = Monitor.new @application = app @scope = app.current_scope @arg_names = nil @locations = [] @invocation_exception = nil @order_only_prerequisites = [] end # Enhance a task with prerequisites or actions. Returns self. def enhance(deps=nil, &block) @prerequisites |= deps if deps @actions << block if block_given? self end # Name of the task, including any namespace qualifiers. def name @name.to_s end # Name of task with argument list description. def name_with_args # :nodoc: if arg_description "#{name}#{arg_description}" else name end end # Argument description (nil if none). def arg_description # :nodoc: @arg_names ? "[#{arg_names.join(',')}]" : nil end # Name of arguments for this task. def arg_names @arg_names || [] end # Reenable the task, allowing its tasks to be executed if the task # is invoked again. def reenable @already_invoked = false @invocation_exception = nil end # Clear the existing prerequisites, actions, comments, and arguments of a rake task. def clear clear_prerequisites clear_actions clear_comments clear_args self end # Clear the existing prerequisites of a rake task. def clear_prerequisites prerequisites.clear self end # Clear the existing actions on a rake task. def clear_actions actions.clear self end # Clear the existing comments on a rake task. def clear_comments @comments = [] self end # Clear the existing arguments on a rake task. def clear_args @arg_names = nil self end # Invoke the task if it is needed. Prerequisites are invoked first. def invoke(*args) task_args = TaskArguments.new(arg_names, args) invoke_with_call_chain(task_args, InvocationChain::EMPTY) end # Same as invoke, but explicitly pass a call chain to detect # circular dependencies. # # If multiple tasks depend on this # one in parallel, they will all fail if the first execution of # this task fails. def invoke_with_call_chain(task_args, invocation_chain) new_chain = Rake::InvocationChain.append(self, invocation_chain) @lock.synchronize do begin if application.options.trace application.trace "** Invoke #{name} #{format_trace_flags}" end if @already_invoked if @invocation_exception if application.options.trace application.trace "** Previous invocation of #{name} failed #{format_trace_flags}" end raise @invocation_exception else return end end @already_invoked = true invoke_prerequisites(task_args, new_chain) execute(task_args) if needed? rescue Exception => ex add_chain_to(ex, new_chain) @invocation_exception = ex raise ex end end end protected :invoke_with_call_chain def add_chain_to(exception, new_chain) # :nodoc: exception.extend(InvocationExceptionMixin) unless exception.respond_to?(:chain) exception.chain = new_chain if exception.chain.nil? end private :add_chain_to # Invoke all the prerequisites of a task. def invoke_prerequisites(task_args, invocation_chain) # :nodoc: if application.options.always_multitask invoke_prerequisites_concurrently(task_args, invocation_chain) else prerequisite_tasks.each { |p| prereq_args = task_args.new_scope(p.arg_names) p.invoke_with_call_chain(prereq_args, invocation_chain) } end end # Invoke all the prerequisites of a task in parallel. def invoke_prerequisites_concurrently(task_args, invocation_chain)# :nodoc: futures = prerequisite_tasks.map do |p| prereq_args = task_args.new_scope(p.arg_names) application.thread_pool.future(p) do |r| r.invoke_with_call_chain(prereq_args, invocation_chain) end end # Iterate in reverse to improve performance related to thread waiting and switching futures.reverse_each(&:value) end # Format the trace flags for display. def format_trace_flags flags = [] flags << "first_time" unless @already_invoked flags << "not_needed" unless needed? flags.empty? ? "" : "(" + flags.join(", ") + ")" end private :format_trace_flags # Execute the actions associated with this task. def execute(args=nil) args ||= EMPTY_TASK_ARGS if application.options.dryrun application.trace "** Execute (dry run) #{name}" return end application.trace "** Execute #{name}" if application.options.trace application.enhance_with_matching_rule(name) if @actions.empty? if opts = Hash.try_convert(args) and !opts.empty? @actions.each { |act| act.call(self, args, **opts)} else @actions.each { |act| act.call(self, args)} end end # Is this task needed? def needed? true end # Timestamp for this task. Basic tasks return the current time for their # time stamp. Other tasks can be more sophisticated. def timestamp Time.now end # Add a description to the task. The description can consist of an option # argument list (enclosed brackets) and an optional comment. def add_description(description) return unless description comment = description.strip add_comment(comment) if comment && !comment.empty? end def comment=(comment) # :nodoc: add_comment(comment) end def add_comment(comment) # :nodoc: return if comment.nil? @comments << comment unless @comments.include?(comment) end private :add_comment # Full collection of comments. Multiple comments are separated by # newlines. def full_comment transform_comments("\n") end # First line (or sentence) of all comments. Multiple comments are # separated by a "/". def comment transform_comments(" / ") { |c| first_sentence(c) } end # Transform the list of comments as specified by the block and # join with the separator. def transform_comments(separator, &block) if @comments.empty? nil else block ||= lambda { |c| c } @comments.map(&block).join(separator) end end private :transform_comments # Get the first sentence in a string. The sentence is terminated # by the first period, exclamation mark, or the end of the line. # Decimal points do not count as periods. def first_sentence(string) string.split(/(?<=\w)(\.|!)[ \t]|(\.$|!)|\n/).first end private :first_sentence # Set the names of the arguments for this task. +args+ should be # an array of symbols, one for each argument name. def set_arg_names(args) @arg_names = args.map(&:to_sym) end # Return a string describing the internal state of a task. Useful for # debugging. def investigation result = "------------------------------\n".dup result << "Investigating #{name}\n" result << "class: #{self.class}\n" result << "task needed: #{needed?}\n" result << "timestamp: #{timestamp}\n" result << "pre-requisites: \n" prereqs = prerequisite_tasks prereqs.sort! { |a, b| a.timestamp <=> b.timestamp } prereqs.each do |p| result << "--#{p.name} (#{p.timestamp})\n" end latest_prereq = prerequisite_tasks.map(&:timestamp).max result << "latest-prerequisite time: #{latest_prereq}\n" result << "................................\n\n" return result end # Format dependencies parameter to pass to task. def self.format_deps(deps) deps = [deps] unless deps.respond_to?(:to_ary) deps.map { |d| Rake.from_pathname(d).to_s } end # Add order only dependencies. def |(deps) @order_only_prerequisites |= Task.format_deps(deps) - @prerequisites self end # ---------------------------------------------------------------- # Rake Module Methods # class << self # Clear the task list. This cause rake to immediately forget all the # tasks that have been assigned. (Normally used in the unit tests.) def clear Rake.application.clear end # List of all defined tasks. def tasks Rake.application.tasks end # Return a task with the given name. If the task is not currently # known, try to synthesize one from the defined rules. If no rules are # found, but an existing file matches the task name, assume it is a file # task with no dependencies or actions. def [](task_name) Rake.application[task_name] end # TRUE if the task name is already defined. def task_defined?(task_name) Rake.application.lookup(task_name) != nil end # Define a task given +args+ and an option block. If a rule with the # given name already exists, the prerequisites and actions are added to # the existing task. Returns the defined task. def define_task(*args, &block) Rake.application.define_task(self, *args, &block) end # Define a rule for synthesizing tasks. def create_rule(*args, &block) Rake.application.create_rule(*args, &block) end # Apply the scope to the task name according to the rules for # this kind of task. Generic tasks will accept the scope as # part of the name. def scope_name(scope, task_name) scope.path_with_task_name(task_name) end end # class << Rake::Task end # class Rake::Task end PK ]i  +gems/rake-13.0.1/lib/rake/default_loader.rbnu[# frozen_string_literal: true module Rake # Default Rakefile loader used by +import+. class DefaultLoader ## # Loads a rakefile into the current application from +fn+ def load(fn) Rake.load_rakefile(File.expand_path(fn)) end end end PK ]l??)gems/rake-13.0.1/lib/rake/trace_output.rbnu[# frozen_string_literal: true module Rake module TraceOutput # :nodoc: all # Write trace output to output stream +out+. # # The write is done as a single IO call (to print) to lessen the # chance that the trace output is interrupted by other tasks also # producing output. def trace_on(out, *strings) sep = $\ || "\n" if strings.empty? output = sep else output = strings.map { |s| next if s.nil? s.end_with?(sep) ? s : s + sep }.join end out.print(output) end end end PK ]I&gems/rake-13.0.1/lib/rake/file_task.rbnu[# frozen_string_literal: true require "rake/task" require "rake/early_time" module Rake # A FileTask is a task that includes time based dependencies. If any of a # FileTask's prerequisites have a timestamp that is later than the file # represented by this task, then the file must be rebuilt (using the # supplied actions). # class FileTask < Task # Is this file task needed? Yes if it doesn't exist, or if its time stamp # is out of date. def needed? !File.exist?(name) || out_of_date?(timestamp) || @application.options.build_all end # Time stamp for file task. def timestamp if File.exist?(name) File.mtime(name.to_s) else Rake::LATE end end private # Are there any prerequisites with a later time than the given time stamp? def out_of_date?(stamp) all_prerequisite_tasks.any? { |prereq| prereq_task = application[prereq, @scope] if prereq_task.instance_of?(Rake::FileTask) prereq_task.timestamp > stamp || @application.options.build_all else prereq_task.timestamp > stamp end } end # ---------------------------------------------------------------- # Task class methods. # class << self # Apply the scope to the task name according to the rules for this kind # of task. File based tasks ignore the scope when creating the name. def scope_name(scope, task_name) Rake.from_pathname(task_name) end end end end PK ]p,۞%gems/rake-13.0.1/lib/rake/testtask.rbnu[# frozen_string_literal: true require "rake" require "rake/tasklib" module Rake # Create a task that runs a set of tests. # # Example: # require "rake/testtask" # # Rake::TestTask.new do |t| # t.libs << "test" # t.test_files = FileList['test/test*.rb'] # t.verbose = true # end # # If rake is invoked with a "TEST=filename" command line option, # then the list of test files will be overridden to include only the # filename specified on the command line. This provides an easy way # to run just one test. # # If rake is invoked with a "TESTOPTS=options" command line option, # then the given options are passed to the test process after a # '--'. This allows Test::Unit options to be passed to the test # suite. # # Examples: # # rake test # run tests normally # rake test TEST=just_one_file.rb # run just one test file. # rake test TESTOPTS="-v" # run in verbose mode # rake test TESTOPTS="--runner=fox" # use the fox test runner # class TestTask < TaskLib # Name of test task. (default is :test) attr_accessor :name # List of directories added to $LOAD_PATH before running the # tests. (default is 'lib') attr_accessor :libs # True if verbose test output desired. (default is false) attr_accessor :verbose # Test options passed to the test suite. An explicit # TESTOPTS=opts on the command line will override this. (default # is NONE) attr_accessor :options # Request that the tests be run with the warning flag set. # E.g. warning=true implies "ruby -w" used to run the tests. # (default is true) attr_accessor :warning # Glob pattern to match test files. (default is 'test/test*.rb') attr_accessor :pattern # Style of test loader to use. Options are: # # * :rake -- Rake provided test loading script (default). # * :testrb -- Ruby provided test loading script. # * :direct -- Load tests using command line loader. # attr_accessor :loader # Array of command line options to pass to ruby when running test loader. attr_accessor :ruby_opts # Description of the test task. (default is 'Run tests') attr_accessor :description # Task prerequisites. attr_accessor :deps # Explicitly define the list of test files to be included in a # test. +list+ is expected to be an array of file names (a # FileList is acceptable). If both +pattern+ and +test_files+ are # used, then the list of test files is the union of the two. def test_files=(list) @test_files = list end # Create a testing task. def initialize(name=:test) @name = name @libs = ["lib"] @pattern = nil @options = nil @test_files = nil @verbose = false @warning = true @loader = :rake @ruby_opts = [] @description = "Run tests" + (@name == :test ? "" : " for #{@name}") @deps = [] if @name.is_a?(Hash) @deps = @name.values.first @name = @name.keys.first end yield self if block_given? @pattern = "test/test*.rb" if @pattern.nil? && @test_files.nil? define end # Create the tasks defined by this task lib. def define desc @description task @name => Array(deps) do FileUtilsExt.verbose(@verbose) do puts "Use TESTOPTS=\"--verbose\" to pass --verbose" \ ", etc. to runners." if ARGV.include? "--verbose" args = "#{ruby_opts_string} #{run_code} " + "#{file_list_string} #{option_list}" ruby args do |ok, status| if !ok && status.respond_to?(:signaled?) && status.signaled? raise SignalException.new(status.termsig) elsif !ok status = "Command failed with status (#{status.exitstatus})" details = ": [ruby #{args}]" message = if Rake.application.options.trace or @verbose status + details else status end fail message end end end end self end def option_list # :nodoc: (ENV["TESTOPTS"] || ENV["TESTOPT"] || ENV["TEST_OPTS"] || ENV["TEST_OPT"] || @options || "") end def ruby_opts_string # :nodoc: opts = @ruby_opts.dup opts.unshift("-I\"#{lib_path}\"") unless @libs.empty? opts.unshift("-w") if @warning opts.join(" ") end def lib_path # :nodoc: @libs.join(File::PATH_SEPARATOR) end def file_list_string # :nodoc: file_list.map { |fn| "\"#{fn}\"" }.join(" ") end def file_list # :nodoc: if ENV["TEST"] FileList[ENV["TEST"]] else result = [] result += @test_files.to_a if @test_files result += FileList[@pattern].to_a if @pattern result end end def ruby_version # :nodoc: RUBY_VERSION end def run_code # :nodoc: case @loader when :direct "-e \"ARGV.each{|f| require f}\"" when :testrb "-S testrb" when :rake "#{rake_include_arg} \"#{rake_loader}\"" end end def rake_loader # :nodoc: find_file("rake/rake_test_loader") or fail "unable to find rake test loader" end def find_file(fn) # :nodoc: $LOAD_PATH.each do |path| file_path = File.join(path, "#{fn}.rb") return file_path if File.exist? file_path end nil end def rake_include_arg # :nodoc: spec = Gem.loaded_specs["rake"] if spec.respond_to?(:default_gem?) && spec.default_gem? "" else "-I\"#{rake_lib_dir}\"" end end def rake_lib_dir # :nodoc: find_dir("rake") or fail "unable to find rake lib" end def find_dir(fn) # :nodoc: $LOAD_PATH.each do |path| file_path = File.join(path, "#{fn}.rb") return path if File.exist? file_path end nil end end end PK ]lD'gems/rake-13.0.1/lib/rake/name_space.rbnu[# frozen_string_literal: true ## # The NameSpace class will lookup task names in the scope defined by a # +namespace+ command. class Rake::NameSpace ## # Create a namespace lookup object using the given task manager # and the list of scopes. def initialize(task_manager, scope_list) @task_manager = task_manager @scope = scope_list.dup end ## # Lookup a task named +name+ in the namespace. def [](name) @task_manager.lookup(name, @scope) end ## # The scope of the namespace (a LinkedList) def scope @scope.dup end ## # Return the list of tasks defined in this and nested namespaces. def tasks @task_manager.tasks_in_scope(@scope) end end PK ]m3gems/rake-13.0.1/lib/rake/thread_history_display.rbnu[# frozen_string_literal: true require "rake/private_reader" module Rake class ThreadHistoryDisplay # :nodoc: all include Rake::PrivateReader private_reader :stats, :items, :threads def initialize(stats) @stats = stats @items = { _seq_: 1 } @threads = { _seq_: "A" } end def show puts "Job History:" stats.each do |stat| stat[:data] ||= {} rename(stat, :thread, threads) rename(stat[:data], :item_id, items) rename(stat[:data], :new_thread, threads) rename(stat[:data], :deleted_thread, threads) printf("%8d %2s %-20s %s\n", (stat[:time] * 1_000_000).round, stat[:thread], stat[:event], stat[:data].map do |k, v| "#{k}:#{v}" end.join(" ")) end end private def rename(hash, key, renames) if hash && hash[key] original = hash[key] value = renames[original] unless value value = renames[:_seq_] renames[:_seq_] = renames[:_seq_].succ renames[original] = value end hash[key] = value end end end end PK ]Jሀ&gems/rake-13.0.1/lib/rake/backtrace.rbnu[# frozen_string_literal: true module Rake module Backtrace # :nodoc: all SYS_KEYS = RbConfig::CONFIG.keys.grep(/(?:[a-z]prefix|libdir)\z/) SYS_PATHS = RbConfig::CONFIG.values_at(*SYS_KEYS).uniq + [ File.join(File.dirname(__FILE__), "..") ] SUPPRESSED_PATHS = SYS_PATHS. map { |s| s.tr("\\", "/") }. map { |f| File.expand_path(f) }. reject { |s| s.nil? || s =~ /^ *$/ } SUPPRESSED_PATHS_RE = SUPPRESSED_PATHS.map { |f| Regexp.quote(f) }.join("|") SUPPRESSED_PATHS_RE << "|^org\\/jruby\\/\\w+\\.java" if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == "jruby" SUPPRESS_PATTERN = %r!(\A(#{SUPPRESSED_PATHS_RE})|bin/rake:\d+)!i def self.collapse(backtrace) pattern = Rake.application.options.suppress_backtrace_pattern || SUPPRESS_PATTERN backtrace.reject { |elem| elem =~ pattern } end end end PK ]H bb(gems/rake-13.0.1/lib/rake/application.rbnu[# frozen_string_literal: true require "optparse" require "rake/task_manager" require "rake/file_list" require "rake/thread_pool" require "rake/thread_history_display" require "rake/trace_output" require "rake/win32" module Rake CommandLineOptionError = Class.new(StandardError) ## # Rake main application object. When invoking +rake+ from the # command line, a Rake::Application object is created and run. class Application include TaskManager include TraceOutput # The name of the application (typically 'rake') attr_reader :name # The original directory where rake was invoked. attr_reader :original_dir # Name of the actual rakefile used. attr_reader :rakefile # Number of columns on the terminal attr_accessor :terminal_columns # List of the top level task names (task names from the command line). attr_reader :top_level_tasks # Override the detected TTY output state (mostly for testing) attr_writer :tty_output DEFAULT_RAKEFILES = [ "rakefile", "Rakefile", "rakefile.rb", "Rakefile.rb" ].freeze # Initialize a Rake::Application object. def initialize super @name = "rake" @rakefiles = DEFAULT_RAKEFILES.dup @rakefile = nil @pending_imports = [] @imported = [] @loaders = {} @default_loader = Rake::DefaultLoader.new @original_dir = Dir.pwd @top_level_tasks = [] add_loader("rb", DefaultLoader.new) add_loader("rf", DefaultLoader.new) add_loader("rake", DefaultLoader.new) @tty_output = STDOUT.tty? @terminal_columns = ENV["RAKE_COLUMNS"].to_i set_default_options end # Run the Rake application. The run method performs the following # three steps: # # * Initialize the command line options (+init+). # * Define the tasks (+load_rakefile+). # * Run the top level tasks (+top_level+). # # If you wish to build a custom rake command, you should call # +init+ on your application. Then define any tasks. Finally, # call +top_level+ to run your top level tasks. def run(argv = ARGV) standard_exception_handling do init "rake", argv load_rakefile top_level end end # Initialize the command line parameters and app name. def init(app_name="rake", argv = ARGV) standard_exception_handling do @name = app_name begin args = handle_options argv rescue ArgumentError # Backward compatibility for capistrano args = handle_options end collect_command_line_tasks(args) end end # Find the rakefile and then load it and any pending imports. def load_rakefile standard_exception_handling do raw_load_rakefile end end # Run the top level tasks of a Rake application. def top_level run_with_threads do if options.show_tasks display_tasks_and_comments elsif options.show_prereqs display_prerequisites else top_level_tasks.each { |task_name| invoke_task(task_name) } end end end # Run the given block with the thread startup and shutdown. def run_with_threads thread_pool.gather_history if options.job_stats == :history yield thread_pool.join if options.job_stats stats = thread_pool.statistics puts "Maximum active threads: #{stats[:max_active_threads]} + main" puts "Total threads in play: #{stats[:total_threads_in_play]} + main" end ThreadHistoryDisplay.new(thread_pool.history).show if options.job_stats == :history end # Add a loader to handle imported files ending in the extension # +ext+. def add_loader(ext, loader) ext = ".#{ext}" unless ext =~ /^\./ @loaders[ext] = loader end # Application options from the command line def options @options ||= OpenStruct.new end # Return the thread pool used for multithreaded processing. def thread_pool # :nodoc: @thread_pool ||= ThreadPool.new(options.thread_pool_size || Rake.suggested_thread_count-1) end # internal ---------------------------------------------------------------- # Invokes a task with arguments that are extracted from +task_string+ def invoke_task(task_string) # :nodoc: name, args = parse_task_string(task_string) t = self[name] t.invoke(*args) end def parse_task_string(string) # :nodoc: /^([^\[]+)(?:\[(.*)\])$/ =~ string.to_s name = $1 remaining_args = $2 return string, [] unless name return name, [] if remaining_args.empty? args = [] begin /\s*((?:[^\\,]|\\.)*?)\s*(?:,\s*(.*))?$/ =~ remaining_args remaining_args = $2 args << $1.gsub(/\\(.)/, '\1') end while remaining_args return name, args end # Provide standard exception handling for the given block. def standard_exception_handling # :nodoc: yield rescue SystemExit # Exit silently with current status raise rescue OptionParser::InvalidOption => ex $stderr.puts ex.message exit(false) rescue Exception => ex # Exit with error message display_error_message(ex) exit_because_of_exception(ex) end # Exit the program because of an unhandled exception. # (may be overridden by subclasses) def exit_because_of_exception(ex) # :nodoc: exit(false) end # Display the error message that caused the exception. def display_error_message(ex) # :nodoc: trace "#{name} aborted!" display_exception_details(ex) trace "Tasks: #{ex.chain}" if has_chain?(ex) trace "(See full trace by running task with --trace)" unless options.backtrace end def display_exception_details(ex) # :nodoc: display_exception_details_seen << ex display_exception_message_details(ex) display_exception_backtrace(ex) display_cause_details(ex.cause) if has_cause?(ex) end def display_cause_details(ex) # :nodoc: return if display_exception_details_seen.include? ex trace "\nCaused by:" display_exception_details(ex) end def display_exception_details_seen # :nodoc: Thread.current[:rake_display_exception_details_seen] ||= [] end def has_cause?(ex) # :nodoc: ex.respond_to?(:cause) && ex.cause end def display_exception_message_details(ex) # :nodoc: if ex.instance_of?(RuntimeError) trace ex.message else trace "#{ex.class.name}: #{ex.message}" end end def display_exception_backtrace(ex) # :nodoc: if options.backtrace trace ex.backtrace.join("\n") else trace Backtrace.collapse(ex.backtrace).join("\n") end end # Warn about deprecated usage. # # Example: # Rake.application.deprecate("import", "Rake.import", caller.first) # def deprecate(old_usage, new_usage, call_site) # :nodoc: unless options.ignore_deprecate $stderr.puts "WARNING: '#{old_usage}' is deprecated. " + "Please use '#{new_usage}' instead.\n" + " at #{call_site}" end end # Does the exception have a task invocation chain? def has_chain?(exception) # :nodoc: exception.respond_to?(:chain) && exception.chain end private :has_chain? # True if one of the files in RAKEFILES is in the current directory. # If a match is found, it is copied into @rakefile. def have_rakefile # :nodoc: @rakefiles.each do |fn| if File.exist?(fn) others = FileList.glob(fn, File::FNM_CASEFOLD) return others.size == 1 ? others.first : fn elsif fn == "" return fn end end return nil end # True if we are outputting to TTY, false otherwise def tty_output? # :nodoc: @tty_output end # We will truncate output if we are outputting to a TTY or if we've been # given an explicit column width to honor def truncate_output? # :nodoc: tty_output? || @terminal_columns.nonzero? end # Display the tasks and comments. def display_tasks_and_comments # :nodoc: displayable_tasks = tasks.select { |t| (options.show_all_tasks || t.comment) && t.name =~ options.show_task_pattern } case options.show_tasks when :tasks width = displayable_tasks.map { |t| t.name_with_args.length }.max || 10 if truncate_output? max_column = terminal_width - name.size - width - 7 else max_column = nil end displayable_tasks.each do |t| printf("#{name} %-#{width}s # %s\n", t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment) end when :describe displayable_tasks.each do |t| puts "#{name} #{t.name_with_args}" comment = t.full_comment || "" comment.split("\n").each do |line| puts " #{line}" end puts end when :lines displayable_tasks.each do |t| t.locations.each do |loc| printf "#{name} %-30s %s\n", t.name_with_args, loc end end else fail "Unknown show task mode: '#{options.show_tasks}'" end end def terminal_width # :nodoc: if @terminal_columns.nonzero? result = @terminal_columns else result = unix? ? dynamic_width : 80 end (result < 10) ? 80 : result rescue 80 end # Calculate the dynamic width of the def dynamic_width # :nodoc: @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput) end def dynamic_width_stty # :nodoc: %x{stty size 2>/dev/null}.split[1].to_i end def dynamic_width_tput # :nodoc: %x{tput cols 2>/dev/null}.to_i end def unix? # :nodoc: RbConfig::CONFIG["host_os"] =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i end def windows? # :nodoc: Win32.windows? end def truncate(string, width) # :nodoc: if string.nil? "" elsif string.length <= width string else (string[0, width - 3] || "") + "..." end end # Display the tasks and prerequisites def display_prerequisites # :nodoc: tasks.each do |t| puts "#{name} #{t.name}" t.prerequisites.each { |pre| puts " #{pre}" } end end def trace(*strings) # :nodoc: options.trace_output ||= $stderr trace_on(options.trace_output, *strings) end def sort_options(options) # :nodoc: options.sort_by { |opt| opt.select { |o| o.is_a?(String) && o =~ /^-/ }.map(&:downcase).sort.reverse } end private :sort_options # A list of all the standard options used in rake, suitable for # passing to OptionParser. def standard_rake_options # :nodoc: sort_options( [ ["--all", "-A", "Show all tasks, even uncommented ones (in combination with -T or -D)", lambda { |value| options.show_all_tasks = value } ], ["--backtrace=[OUT]", "Enable full backtrace. OUT can be stderr (default) or stdout.", lambda { |value| options.backtrace = true select_trace_output(options, "backtrace", value) } ], ["--build-all", "-B", "Build all prerequisites, including those which are up-to-date.", lambda { |value| options.build_all = true } ], ["--comments", "Show commented tasks only", lambda { |value| options.show_all_tasks = !value } ], ["--describe", "-D [PATTERN]", "Describe the tasks (matching optional PATTERN), then exit.", lambda { |value| select_tasks_to_show(options, :describe, value) } ], ["--dry-run", "-n", "Do a dry run without executing actions.", lambda { |value| Rake.verbose(true) Rake.nowrite(true) options.dryrun = true options.trace = true } ], ["--execute", "-e CODE", "Execute some Ruby code and exit.", lambda { |value| eval(value) exit } ], ["--execute-print", "-p CODE", "Execute some Ruby code, print the result, then exit.", lambda { |value| puts eval(value) exit } ], ["--execute-continue", "-E CODE", "Execute some Ruby code, " + "then continue with normal task processing.", lambda { |value| eval(value) } ], ["--jobs", "-j [NUMBER]", "Specifies the maximum number of tasks to execute in parallel. " + "(default is number of CPU cores + 4)", lambda { |value| if value.nil? || value == "" value = Float::INFINITY elsif value =~ /^\d+$/ value = value.to_i else value = Rake.suggested_thread_count end value = 1 if value < 1 options.thread_pool_size = value - 1 } ], ["--job-stats [LEVEL]", "Display job statistics. " + "LEVEL=history displays a complete job list", lambda { |value| if value =~ /^history/i options.job_stats = :history else options.job_stats = true end } ], ["--libdir", "-I LIBDIR", "Include LIBDIR in the search path for required modules.", lambda { |value| $:.push(value) } ], ["--multitask", "-m", "Treat all tasks as multitasks.", lambda { |value| options.always_multitask = true } ], ["--no-search", "--nosearch", "-N", "Do not search parent directories for the Rakefile.", lambda { |value| options.nosearch = true } ], ["--prereqs", "-P", "Display the tasks and dependencies, then exit.", lambda { |value| options.show_prereqs = true } ], ["--quiet", "-q", "Do not log messages to standard output.", lambda { |value| Rake.verbose(false) } ], ["--rakefile", "-f [FILENAME]", "Use FILENAME as the rakefile to search for.", lambda { |value| value ||= "" @rakefiles.clear @rakefiles << value } ], ["--rakelibdir", "--rakelib", "-R RAKELIBDIR", "Auto-import any .rake files in RAKELIBDIR. " + "(default is 'rakelib')", lambda { |value| options.rakelib = value.split(File::PATH_SEPARATOR) } ], ["--require", "-r MODULE", "Require MODULE before executing rakefile.", lambda { |value| begin require value rescue LoadError => ex begin rake_require value rescue LoadError raise ex end end } ], ["--rules", "Trace the rules resolution.", lambda { |value| options.trace_rules = true } ], ["--silent", "-s", "Like --quiet, but also suppresses the " + "'in directory' announcement.", lambda { |value| Rake.verbose(false) options.silent = true } ], ["--suppress-backtrace PATTERN", "Suppress backtrace lines matching regexp PATTERN. " + "Ignored if --trace is on.", lambda { |value| options.suppress_backtrace_pattern = Regexp.new(value) } ], ["--system", "-g", "Using system wide (global) rakefiles " + "(usually '~/.rake/*.rake').", lambda { |value| options.load_system = true } ], ["--no-system", "--nosystem", "-G", "Use standard project Rakefile search paths, " + "ignore system wide rakefiles.", lambda { |value| options.ignore_system = true } ], ["--tasks", "-T [PATTERN]", "Display the tasks (matching optional PATTERN) " + "with descriptions, then exit. " + "-AT combination displays all of tasks contained no description.", lambda { |value| select_tasks_to_show(options, :tasks, value) } ], ["--trace=[OUT]", "-t", "Turn on invoke/execute tracing, enable full backtrace. " + "OUT can be stderr (default) or stdout.", lambda { |value| options.trace = true options.backtrace = true select_trace_output(options, "trace", value) Rake.verbose(true) } ], ["--verbose", "-v", "Log message to standard output.", lambda { |value| Rake.verbose(true) } ], ["--version", "-V", "Display the program version.", lambda { |value| puts "rake, version #{Rake::VERSION}" exit } ], ["--where", "-W [PATTERN]", "Describe the tasks (matching optional PATTERN), then exit.", lambda { |value| select_tasks_to_show(options, :lines, value) options.show_all_tasks = true } ], ["--no-deprecation-warnings", "-X", "Disable the deprecation warnings.", lambda { |value| options.ignore_deprecate = true } ], ]) end def select_tasks_to_show(options, show_tasks, value) # :nodoc: options.show_tasks = show_tasks options.show_task_pattern = Regexp.new(value || "") Rake::TaskManager.record_task_metadata = true end private :select_tasks_to_show def select_trace_output(options, trace_option, value) # :nodoc: value = value.strip unless value.nil? case value when "stdout" options.trace_output = $stdout when "stderr", nil options.trace_output = $stderr else fail CommandLineOptionError, "Unrecognized --#{trace_option} option '#{value}'" end end private :select_trace_output # Read and handle the command line options. Returns the command line # arguments that we didn't understand, which should (in theory) be just # task names and env vars. def handle_options(argv) # :nodoc: set_default_options OptionParser.new do |opts| opts.banner = "#{Rake.application.name} [-f rakefile] {options} targets..." opts.separator "" opts.separator "Options are ..." opts.on_tail("-h", "--help", "-H", "Display this help message.") do puts opts exit end standard_rake_options.each { |args| opts.on(*args) } opts.environment("RAKEOPT") end.parse(argv) end # Similar to the regular Ruby +require+ command, but will check # for *.rake files in addition to *.rb files. def rake_require(file_name, paths=$LOAD_PATH, loaded=$") # :nodoc: fn = file_name + ".rake" return false if loaded.include?(fn) paths.each do |path| full_path = File.join(path, fn) if File.exist?(full_path) Rake.load_rakefile(full_path) loaded << fn return true end end fail LoadError, "Can't find #{file_name}" end def find_rakefile_location # :nodoc: here = Dir.pwd until (fn = have_rakefile) Dir.chdir("..") return nil if Dir.pwd == here || options.nosearch here = Dir.pwd end [fn, here] ensure Dir.chdir(Rake.original_dir) end def print_rakefile_directory(location) # :nodoc: $stderr.puts "(in #{Dir.pwd})" unless options.silent or original_dir == location end def raw_load_rakefile # :nodoc: rakefile, location = find_rakefile_location if (!options.ignore_system) && (options.load_system || rakefile.nil?) && system_dir && File.directory?(system_dir) print_rakefile_directory(location) glob("#{system_dir}/*.rake") do |name| add_import name end else fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" if rakefile.nil? @rakefile = rakefile Dir.chdir(location) print_rakefile_directory(location) Rake.load_rakefile(File.expand_path(@rakefile)) if @rakefile && @rakefile != "" options.rakelib.each do |rlib| glob("#{rlib}/*.rake") do |name| add_import name end end end load_imports end def glob(path, &block) # :nodoc: FileList.glob(path.tr("\\", "/")).each(&block) end private :glob # The directory path containing the system wide rakefiles. def system_dir # :nodoc: @system_dir ||= begin if ENV["RAKE_SYSTEM"] ENV["RAKE_SYSTEM"] else standard_system_dir end end end # The standard directory containing system wide rake files. if Win32.windows? def standard_system_dir #:nodoc: Win32.win32_system_dir end else def standard_system_dir #:nodoc: File.join(File.expand_path("~"), ".rake") end end private :standard_system_dir # Collect the list of tasks on the command line. If no tasks are # given, return a list containing only the default task. # Environmental assignments are processed at this time as well. # # `args` is the list of arguments to peruse to get the list of tasks. # It should be the command line that was given to rake, less any # recognised command-line options, which OptionParser.parse will # have taken care of already. def collect_command_line_tasks(args) # :nodoc: @top_level_tasks = [] args.each do |arg| if arg =~ /^(\w+)=(.*)$/m ENV[$1] = $2 else @top_level_tasks << arg unless arg =~ /^-/ end end @top_level_tasks.push(default_task_name) if @top_level_tasks.empty? end # Default task name ("default"). # (May be overridden by subclasses) def default_task_name # :nodoc: "default" end # Add a file to the list of files to be imported. def add_import(fn) # :nodoc: @pending_imports << fn end # Load the pending list of imported files. def load_imports # :nodoc: while fn = @pending_imports.shift next if @imported.member?(fn) fn_task = lookup(fn) and fn_task.invoke ext = File.extname(fn) loader = @loaders[ext] || @default_loader loader.load(fn) if fn_task = lookup(fn) and fn_task.needed? fn_task.reenable fn_task.invoke loader.load(fn) end @imported << fn end end def rakefile_location(backtrace=caller) # :nodoc: backtrace.map { |t| t[/([^:]+):/, 1] } re = /^#{@rakefile}$/ re = /#{re.source}/i if windows? backtrace.find { |str| str =~ re } || "" end def set_default_options # :nodoc: options.always_multitask = false options.backtrace = false options.build_all = false options.dryrun = false options.ignore_deprecate = false options.ignore_system = false options.job_stats = false options.load_system = false options.nosearch = false options.rakelib = %w[rakelib] options.show_all_tasks = false options.show_prereqs = false options.show_task_pattern = nil options.show_tasks = nil options.silent = false options.suppress_backtrace_pattern = nil options.thread_pool_size = Rake.suggested_thread_count options.trace = false options.trace_output = $stderr options.trace_rules = false end end end PK ]Q(gems/rake-13.0.1/lib/rake/rake_module.rbnu[# frozen_string_literal: true require "rake/application" module Rake class << self # Current Rake Application def application @application ||= Rake::Application.new end # Set the current Rake application object. def application=(app) @application = app end def suggested_thread_count # :nodoc: @cpu_count ||= Rake::CpuCounter.count @cpu_count + 4 end # Return the original directory where the Rake application was started. def original_dir application.original_dir end # Load a rakefile. def load_rakefile(path) load(path) end # Add files to the rakelib list def add_rakelib(*files) application.options.rakelib ||= [] application.options.rakelib.concat(files) end # Make +block_application+ the default rake application inside a block so # you can load rakefiles into a different application. # # This is useful when you want to run rake tasks inside a library without # running rake in a sub-shell. # # Example: # # Dir.chdir 'other/directory' # # other_rake = Rake.with_application do |rake| # rake.load_rakefile # end # # puts other_rake.tasks def with_application(block_application = Rake::Application.new) orig_application = Rake.application Rake.application = block_application yield block_application block_application ensure Rake.application = orig_application end end end PK ]-x= ( ()gems/rake-13.0.1/lib/rake/task_manager.rbnu[# frozen_string_literal: true module Rake # The TaskManager module is a mixin for managing tasks. module TaskManager # Track the last comment made in the Rakefile. attr_accessor :last_description def initialize # :nodoc: super @tasks = Hash.new @rules = Array.new @scope = Scope.make @last_description = nil end def create_rule(*args, &block) # :nodoc: pattern, args, deps, order_only = resolve_args(args) pattern = Regexp.new(Regexp.quote(pattern) + "$") if String === pattern @rules << [pattern, args, deps, order_only, block] end def define_task(task_class, *args, &block) # :nodoc: task_name, arg_names, deps, order_only = resolve_args(args) original_scope = @scope if String === task_name and not task_class.ancestors.include? Rake::FileTask task_name, *definition_scope = *(task_name.split(":").reverse) @scope = Scope.make(*(definition_scope + @scope.to_a)) end task_name = task_class.scope_name(@scope, task_name) task = intern(task_class, task_name) task.set_arg_names(arg_names) unless arg_names.empty? if Rake::TaskManager.record_task_metadata add_location(task) task.add_description(get_description(task)) end task.enhance(Task.format_deps(deps), &block) task | order_only unless order_only.nil? task ensure @scope = original_scope end # Lookup a task. Return an existing task if found, otherwise # create a task of the current type. def intern(task_class, task_name) @tasks[task_name.to_s] ||= task_class.new(task_name, self) end # Find a matching task for +task_name+. def [](task_name, scopes=nil) task_name = task_name.to_s self.lookup(task_name, scopes) or enhance_with_matching_rule(task_name) or synthesize_file_task(task_name) or fail generate_message_for_undefined_task(task_name) end def generate_message_for_undefined_task(task_name) message = "Don't know how to build task '#{task_name}' "\ "(See the list of available tasks with `#{Rake.application.name} --tasks`)" message + generate_did_you_mean_suggestions(task_name) end def generate_did_you_mean_suggestions(task_name) return "" unless defined?(::DidYouMean::SpellChecker) suggestions = ::DidYouMean::SpellChecker.new(dictionary: @tasks.keys).correct(task_name.to_s) if ::DidYouMean.respond_to?(:formatter)# did_you_mean v1.2.0 or later ::DidYouMean.formatter.message_for(suggestions) elsif defined?(::DidYouMean::Formatter) # before did_you_mean v1.2.0 ::DidYouMean::Formatter.new(suggestions).to_s else "" end end def synthesize_file_task(task_name) # :nodoc: return nil unless File.exist?(task_name) define_task(Rake::FileTask, task_name) end # Resolve the arguments for a task/rule. Returns a tuple of # [task_name, arg_name_list, prerequisites, order_only_prerequisites]. def resolve_args(args) if args.last.is_a?(Hash) deps = args.pop resolve_args_with_dependencies(args, deps) else resolve_args_without_dependencies(args) end end # Resolve task arguments for a task or rule when there are no # dependencies declared. # # The patterns recognized by this argument resolving function are: # # task :t # task :t, [:a] # def resolve_args_without_dependencies(args) task_name = args.shift if args.size == 1 && args.first.respond_to?(:to_ary) arg_names = args.first.to_ary else arg_names = args end [task_name, arg_names, [], nil] end private :resolve_args_without_dependencies # Resolve task arguments for a task or rule when there are # dependencies declared. # # The patterns recognized by this argument resolving function are: # # task :t, order_only: [:e] # task :t => [:d] # task :t => [:d], order_only: [:e] # task :t, [a] => [:d] # task :t, [a] => [:d], order_only: [:e] # def resolve_args_with_dependencies(args, hash) # :nodoc: fail "Task Argument Error" if hash.size != 1 && (hash.size != 2 || !hash.key?(:order_only)) order_only = hash.delete(:order_only) key, value = hash.map { |k, v| [k, v] }.first if args.empty? task_name = key arg_names = [] deps = value || [] else task_name = args.shift arg_names = key || args.shift|| [] deps = value || [] end deps = [deps] unless deps.respond_to?(:to_ary) [task_name, arg_names, deps, order_only] end private :resolve_args_with_dependencies # If a rule can be found that matches the task name, enhance the # task with the prerequisites and actions from the rule. Set the # source attribute of the task appropriately for the rule. Return # the enhanced task or nil of no rule was found. def enhance_with_matching_rule(task_name, level=0) fail Rake::RuleRecursionOverflowError, "Rule Recursion Too Deep" if level >= 16 @rules.each do |pattern, args, extensions, order_only, block| if pattern && pattern.match(task_name) task = attempt_rule(task_name, pattern, args, extensions, block, level) task | order_only unless order_only.nil? return task if task end end nil rescue Rake::RuleRecursionOverflowError => ex ex.add_target(task_name) fail ex end # List of all defined tasks in this application. def tasks @tasks.values.sort_by { |t| t.name } end # List of all the tasks defined in the given scope (and its # sub-scopes). def tasks_in_scope(scope) prefix = scope.path tasks.select { |t| /^#{prefix}:/ =~ t.name } end # Clear all tasks in this application. def clear @tasks.clear @rules.clear end # Lookup a task, using scope and the scope hints in the task name. # This method performs straight lookups without trying to # synthesize file tasks or rules. Special scope names (e.g. '^') # are recognized. If no scope argument is supplied, use the # current scope. Return nil if the task cannot be found. def lookup(task_name, initial_scope=nil) initial_scope ||= @scope task_name = task_name.to_s if task_name =~ /^rake:/ scopes = Scope.make task_name = task_name.sub(/^rake:/, "") elsif task_name =~ /^(\^+)/ scopes = initial_scope.trim($1.size) task_name = task_name.sub(/^(\^+)/, "") else scopes = initial_scope end lookup_in_scope(task_name, scopes) end # Lookup the task name def lookup_in_scope(name, scope) loop do tn = scope.path_with_task_name(name) task = @tasks[tn] return task if task break if scope.empty? scope = scope.tail end nil end private :lookup_in_scope # Return the list of scope names currently active in the task # manager. def current_scope @scope end # Evaluate the block in a nested namespace named +name+. Create # an anonymous namespace if +name+ is nil. def in_namespace(name) name ||= generate_name @scope = Scope.new(name, @scope) ns = NameSpace.new(self, @scope) yield(ns) ns ensure @scope = @scope.tail end private # Add a location to the locations field of the given task. def add_location(task) loc = find_location task.locations << loc if loc task end # Find the location that called into the dsl layer. def find_location locations = caller i = 0 while locations[i] return locations[i + 1] if locations[i] =~ /rake\/dsl_definition.rb/ i += 1 end nil end # Generate an anonymous namespace name. def generate_name @seed ||= 0 @seed += 1 "_anon_#{@seed}" end def trace_rule(level, message) # :nodoc: options.trace_output.puts "#{" " * level}#{message}" if Rake.application.options.trace_rules end # Attempt to create a rule given the list of prerequisites. def attempt_rule(task_name, task_pattern, args, extensions, block, level) sources = make_sources(task_name, task_pattern, extensions) prereqs = sources.map { |source| trace_rule level, "Attempting Rule #{task_name} => #{source}" if File.exist?(source) || Rake::Task.task_defined?(source) trace_rule level, "(#{task_name} => #{source} ... EXIST)" source elsif parent = enhance_with_matching_rule(source, level + 1) trace_rule level, "(#{task_name} => #{source} ... ENHANCE)" parent.name else trace_rule level, "(#{task_name} => #{source} ... FAIL)" return nil end } task = FileTask.define_task(task_name, { args => prereqs }, &block) task.sources = prereqs task end # Make a list of sources from the list of file name extensions / # translation procs. def make_sources(task_name, task_pattern, extensions) result = extensions.map { |ext| case ext when /%/ task_name.pathmap(ext) when %r{/} ext when /^\./ source = task_name.sub(task_pattern, ext) source == ext ? task_name.ext(ext) : source when String ext when Proc, Method if ext.arity == 1 ext.call(task_name) else ext.call end else fail "Don't know how to handle rule dependent: #{ext.inspect}" end } result.flatten end # Return the current description, clearing it in the process. def get_description(task) desc = @last_description @last_description = nil desc end class << self attr_accessor :record_task_metadata # :nodoc: TaskManager.record_task_metadata = false end end end PK ]~y +gems/rake-13.0.1/lib/rake/task_arguments.rbnu[# frozen_string_literal: true module Rake ## # TaskArguments manage the arguments passed to a task. # class TaskArguments include Enumerable # Argument names attr_reader :names # Create a TaskArgument object with a list of argument +names+ and a set # of associated +values+. +parent+ is the parent argument object. def initialize(names, values, parent=nil) @names = names @parent = parent @hash = {} @values = values names.each_with_index { |name, i| next if values[i].nil? || values[i] == "" @hash[name.to_sym] = values[i] } end # Retrieve the complete array of sequential values def to_a @values.dup end # Retrieve the list of values not associated with named arguments def extras @values[@names.length..-1] || [] end # Create a new argument scope using the prerequisite argument # names. def new_scope(names) values = names.map { |n| self[n] } self.class.new(names, values + extras, self) end # Find an argument value by name or index. def [](index) lookup(index.to_sym) end # Specify a hash of default values for task arguments. Use the # defaults only if there is no specific value for the given # argument. def with_defaults(defaults) @hash = defaults.merge(@hash) end # Enumerates the arguments and their values def each(&block) @hash.each(&block) end # Extracts the argument values at +keys+ def values_at(*keys) keys.map { |k| lookup(k) } end # Returns the value of the given argument via method_missing def method_missing(sym, *args) lookup(sym.to_sym) end # Returns a Hash of arguments and their values def to_hash @hash.dup end def to_s # :nodoc: inspect end def inspect # :nodoc: inspection = @hash.map do |k,v| "#{k.to_s}: #{v.to_s}" end.join(", ") "#<#{self.class} #{inspection}>" end # Returns true if +key+ is one of the arguments def has_key?(key) @hash.has_key?(key) end alias key? has_key? def fetch(*args, &block) @hash.fetch(*args, &block) end protected def lookup(name) # :nodoc: if @hash.has_key?(name) @hash[name] elsif @parent @parent.lookup(name) end end end EMPTY_TASK_ARGS = TaskArguments.new([], []) # :nodoc: end PK ]K*gems/rake-13.0.1/lib/rake/pseudo_status.rbnu[# frozen_string_literal: true module Rake ## # Exit status class for times the system just gives us a nil. class PseudoStatus # :nodoc: all attr_reader :exitstatus def initialize(code=0) @exitstatus = code end def to_i @exitstatus << 8 end def >>(n) to_i >> n end def stopped? false end def exited? true end end end PK ]M M (gems/rake-13.0.1/lib/rake/cpu_counter.rbnu[# frozen_string_literal: true module Rake # Based on a script at: # http://stackoverflow.com/questions/891537/ruby-detect-number-of-cpus-installed class CpuCounter # :nodoc: all def self.count new.count_with_default end def count_with_default(default=4) count || default rescue StandardError default end begin require "etc" rescue LoadError else if Etc.respond_to?(:nprocessors) def count return Etc.nprocessors end end end end end unless Rake::CpuCounter.method_defined?(:count) Rake::CpuCounter.class_eval <<-'end;', __FILE__, __LINE__+1 require 'rbconfig' def count if RUBY_PLATFORM == 'java' count_via_java_runtime else case RbConfig::CONFIG['host_os'] when /linux/ count_via_cpuinfo when /darwin|bsd/ count_via_sysctl when /mswin|mingw/ count_via_win32 else # Try everything count_via_win32 || count_via_sysctl || count_via_cpuinfo end end end def count_via_java_runtime Java::Java.lang.Runtime.getRuntime.availableProcessors rescue StandardError nil end def count_via_win32 require 'win32ole' wmi = WIN32OLE.connect("winmgmts://") cpu = wmi.ExecQuery("select NumberOfCores from Win32_Processor") # TODO count hyper-threaded in this cpu.to_enum.first.NumberOfCores rescue StandardError, LoadError nil end def count_via_cpuinfo open('/proc/cpuinfo') { |f| f.readlines }.grep(/processor/).size rescue StandardError nil end def count_via_sysctl run 'sysctl', '-n', 'hw.ncpu' end def run(command, *args) cmd = resolve_command(command) if cmd IO.popen [cmd, *args] do |io| io.read.to_i end else nil end end def resolve_command(command) look_for_command("/usr/sbin", command) || look_for_command("/sbin", command) || in_path_command(command) end def look_for_command(dir, command) path = File.join(dir, command) File.exist?(path) ? path : nil end def in_path_command(command) IO.popen ['which', command] do |io| io.eof? ? nil : command end end end; end PK ]''&gems/rake-13.0.1/lib/rake/late_time.rbnu[# frozen_string_literal: true module Rake # LateTime is a fake timestamp that occurs _after_ any other time value. class LateTime include Comparable include Singleton def <=>(other) 1 end def to_s "" end end LATE = LateTime.instance end PK ]-gems/rake-13.0.1/lib/rake/rake_test_loader.rbnu[# frozen_string_literal: true require "rake" # Load the test files from the command line. argv = ARGV.select do |argument| begin case argument when /^-/ then argument when /\*/ then FileList[argument].to_a.each do |file| require File.expand_path file end false else require File.expand_path argument false end rescue LoadError => e raise unless e.path abort "\nFile does not exist: #{e.path}\n\n" end end ARGV.replace argv PK ]K\-gems/rake-13.0.1/lib/rake/invocation_chain.rbnu[# frozen_string_literal: true module Rake # InvocationChain tracks the chain of task invocations to detect # circular dependencies. class InvocationChain < LinkedList # Is the invocation already in the chain? def member?(invocation) head == invocation || tail.member?(invocation) end # Append an invocation to the chain of invocations. It is an error # if the invocation already listed. def append(invocation) if member?(invocation) fail RuntimeError, "Circular dependency detected: #{to_s} => #{invocation}" end conj(invocation) end # Convert to string, ie: TOP => invocation => invocation def to_s "#{prefix}#{head}" end # Class level append. def self.append(invocation, chain) chain.append(invocation) end private def prefix "#{tail} => " end # Null object for an empty chain. class EmptyInvocationChain < LinkedList::EmptyLinkedList @parent = InvocationChain def member?(obj) false end def append(invocation) conj(invocation) end def to_s "TOP" end end EMPTY = EmptyInvocationChain.new end end PK ]E.$gems/rake-13.0.1/lib/rake/tasklib.rbnu[# frozen_string_literal: true require "rake" module Rake # Base class for Task Libraries. class TaskLib include Cloneable include Rake::DSL end end PK ]l/gems/rake-13.0.1/lib/rake/file_creation_task.rbnu[# frozen_string_literal: true require "rake/file_task" require "rake/early_time" module Rake # A FileCreationTask is a file task that when used as a dependency will be # needed if and only if the file has not been created. Once created, it is # not re-triggered if any of its dependencies are newer, nor does trigger # any rebuilds of tasks that depend on it whenever it is updated. # class FileCreationTask < FileTask # Is this file task needed? Yes if it doesn't exist. def needed? !File.exist?(name) end # Time stamp for file creation task. This time stamp is earlier # than any other time stamp. def timestamp Rake::EARLY end end end PK ]Q=rrgems/rake-13.0.1/lib/rake.rbnu[# frozen_string_literal: true #-- # Copyright 2003-2010 by Jim Weirich (jim.weirich@gmail.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. #++ module Rake; end require "rake/version" require "rbconfig" require "fileutils" require "singleton" require "monitor" require "optparse" require "ostruct" require "rake/ext/string" require "rake/win32" require "rake/linked_list" require "rake/cpu_counter" require "rake/scope" require "rake/task_argument_error" require "rake/rule_recursion_overflow_error" require "rake/rake_module" require "rake/trace_output" require "rake/pseudo_status" require "rake/task_arguments" require "rake/invocation_chain" require "rake/task" require "rake/file_task" require "rake/file_creation_task" require "rake/multi_task" require "rake/dsl_definition" require "rake/file_utils_ext" require "rake/file_list" require "rake/default_loader" require "rake/early_time" require "rake/late_time" require "rake/name_space" require "rake/task_manager" require "rake/application" require "rake/backtrace" $trace = false # :stopdoc: # # Some top level Constants. FileList = Rake::FileList RakeFileUtils = Rake::FileUtilsExt PK ]A ugems/rake-13.0.1/History.rdocnu[=== 13.0.1 ==== Bug fixes * Fixed bug: Reenabled task raises previous exception on second invokation Pull Request #271 by thorsteneckel * Fix an incorrectly resolved arg pattern Pull Request #327 by mjbellantoni === 13.0.0 ==== Enhancements * Follows recent changes on keyword arguments in ruby 2.7. Pull Request #326 by nobu * Make `PackageTask` be able to omit parent directory while packing files Pull Request #310 by tonytonyjan * Add order only dependency Pull Request #269 by take-cheeze ==== Compatibility changes * Drop old ruby versions(< 2.2) === 12.3.3 ==== Bug fixes * Use the application's name in error message if a task is not found. Pull Request #303 by tmatilai ==== Enhancements: * Use File.open explicitly. === 12.3.2 ==== Bug fixes * Fixed test fails caused by 2.6 warnings. Pull Request #297 by hsbt ==== Enhancements: * Rdoc improvements. Pull Request #293 by colby-swandale * Improve multitask performance. Pull Request #273 by jsm * Add alias `prereqs`. Pull Request #268 by take-cheeze === 12.3.1 ==== Bug fixes * Support did_you_mean >= v1.2.0 which has a breaking change on formatters. Pull request #262 by FUJI Goro. ==== Enhancements: * Don't run task if it depends on already invoked but failed task. Pull request #252 by Gonzalo Rodriguez. * Make space trimming consistent for all task arguments. Pull request #259 by Gonzalo Rodriguez. * Removes duplicated inclusion of Rake::DSL in tests. Pull request #254 by Gonzalo Rodriguez. * Re-raise a LoadError that didn't come from require in the test loader. Pull request #250 by Dylan Thacker-Smith. === 12.3.0 ==== Compatibility Changes * Bump `required_ruby_version` to Ruby 2.0.0. Rake has already removed support for Ruby 1.9.x. ==== Enhancements: * Support `test-bundled-gems` task on ruby core. === 12.2.1 ==== Bug fixes * Fixed to break Capistrano::Application on capistrano3. === 12.2.0 ==== Enhancements: * Make rake easier to use as a library Pull request #211 by @drbrain * Fix quadratic performance in FileTask#out_of_date? Pull request #224 by @doudou * Clarify output when printing nested exception traces Pull request #232 by @urbanautomaton ==== Bug fixes * Account for a file that match 2 or more patterns. Pull request #231 by @styd === 12.1.0 ==== Enhancements: * Added did_you_mean feature for invalid rake task. Pull request #221 by @xtina-starr * Enabled to dependency chained by extensions. Pull request #39 by Petr Skocik. * Make all of string literals to frozen objects on Ruby 2.4 or later. ==== Bug fixes * Typo fixes in rakefile.rdoc. Pull request #180 by Yuta Kurotaki. * Fix unexpected behavior of file task with dryrun option. Pull request #183 by @aycabta. * Make LoadError from running tests more obvious. Pull request #195 by Eric Hodel. * Fix unexpected TypeError with hash style option. Pull request #202 by Kuniaki IGARASHI. === 12.0.0 ==== Compatibility Changes * Removed arguments on clear #157 by Jesse Bowes * Removed `rake/contrib` packages. These are extracted to `rake-contrib` gem. * Removed deprecated method named `last\_comment`. ==== Enhancements: * Re-use trace option on `cleanup` task. #164 by Brian Henderson * Actions adore keyword arguments #174 by Josh Cheek * Rake::TaskArguments#key? alias of #has_key? #175 by Paul Annesley === 11.3.0 / 2016-09-20 ==== Enhancements: * Remove to reference `Fixnum` constant. Pull request #160 by nobu === 11.2.2 / 2016-06-12 ==== Bug fixes * Fix unexpected behavior with multiple dependencies on Rake::TestTask === 11.2.1 / 2016-06-12 ==== Bug fixes * Fix regression of dependencies handling on Rake::TestTask. Report #139 === 11.2.0 / 2016-06-11 ==== Bug fixes * Fix unexpected cut-out behavior on task description using triple dots and exclamation. Report #106 from Stephan Kämper and Pull request #134 by Lee * Fix empty argument assignment with `with_defaults` option. Pull request #135 by bakunyo * Ignore to use `hwprefs` on Darwin platform. Use sysctl now. Report #128 ==== Enhancements * Spawn options for sh Pull equest #138 by Eric Hodel. * Allow to specify dependencies(prerequisites) for Rake::TestTask Pull request #117 by Tim Maslyuchenko * Use Bundler task instead of hoe for gem release. * Remove explicitly load to rubygems for Ruby 1.8. * Unify to declare `Rake::VERSION`. * Support xz format for PackageTask. === 11.1.2 / 2016-03-28 ==== Bug fixes * Remove `-W` option when Rake::TestTask#verbose enabled. It's misunderstanding specification change with Rake 11. Partly revert #67 === 11.1.1 / 2016-03-14 ==== Bug fixes * Use `-W` instead of `--verbose` when Rake::TestTask#verbose enabled. JRuby doesn't have `--verbose` option. === 11.1.0 / 2016-03-11 ==== Compatibility Changes * Revert to remove `last\_comment`. It will remove Rake 12. === 11.0.1 / 2016-03-09 ==== Bug fixes * Fixed packaging manifest. === 11.0.0 / 2016-03-09 ==== Bug fixes * Correctly handle bad encoding in exception messages. Pull request #113 by Tomer Brisker * Fix verbose option at TestTask. Pull request #67 by Mike Blumtritt ==== Enhancements * Make FileList#exclude more analogous to FileList#include. * Use IO.open instead of Open3.popen3 for CPU counter. * Make Rake::Task#already_invoked publicly accessible. Pull request #93 by Joe Rafaniello * Lookup prerequisites with same name outside of scope instead of matching self. Pull request #96 by Sandy Vanderbleek * Make FileList#pathmap behave like String#pathmap. Pull request #61 by Daniel Tamai * Add fetch method to task arguments. Pull request #12 by Chris Keathley * Use ruby warnings by default. Pull request #97 by Harold Giménez ==== Compatibility Changes * Removed to support Ruby 1.8.x * Removed constant named `RAKEVERSION` * Removed Rake::AltSystem * Removed Rake::RubyForgePublisher * Removed Rake::TaskManager#last\_comment. Use last\_description. * Removed Rake::TaskLib#paste * Removed Top-level SshDirPublisher, SshFreshDirPublisher, SshFilePublisher and CompositePublisher from lib/rake/contrib/publisher.rb * Removed "rake/runtest.rb" === 10.5.0 / 2016-01-13 ==== Enhancements * Removed monkey patching for Ruby 1.8. Pull request #46 by Pablo Herrero. * Inheritance class of Rake::FileList returns always self class. Pull request #74 by Thomas Scholz === 10.4.2 / 2014-12-02 ==== Bug fixes * Rake no longer edits ARGV. This allows you to re-exec rake from a rake task. Pull requset #9 by Matt Palmer. * Documented how Rake::DSL#desc handles sentences in task descriptions. Issue #7 by Raza Sayed. * Fixed test error on 1.9.3 with legacy RubyGems. Issue #8 by Matt Palmer. * Deleted duplicated History entry. Pull request #10 by Yuji Yamamoto. === 10.4.1 / 2014-12-01 ==== Bug fixes * Reverted fix for #277 as it caused numerous issues for rake users. rails/spring issue #366 by Gustavo Dutra. === 10.4.0 / 2014-11-22 ==== Enhancements * Upgraded to minitest 5. Pull request #292 by Teo Ljungberg. * Added support for Pathname in rake tasks. Pull request #271 by Randy Coulman. * Rake now ignores falsy dependencies which allows for easier programmatic creation of tasks. Pull request #273 by Manav. * Rake no longer edits ARGV. This allows you to re-exec rake from a rake task. Issue #277 by Matt Palmer. * Etc.nprocessors is used for counting the number of CPUs. ==== Bug fixes * Updated rake manpage. Issue #283 by Nathan Long, pull request #291 by skittleys. * Add Rake::LATE to allow rebuilding of files that depend on deleted files. Bug #286, pull request #287 by David Grayson. * Fix relinking of files when repackaging. Bug #276 by Muenze. * Fixed some typos. Pull request #280 by Jed Northridge. * Try counting CPUs via cpuinfo if host_os was not matched. Pull request #282 by Edouard B. === 10.3.2 / 2014-05-15 ==== Bug fixes * Rake no longer infinitely loops when showing exception causes that refer to each other. Bug #272 by Chris Bandy. * Fixed documentation typos. Bug #275 by Jake Worth. === 10.3.1 / 2014-04-17 ==== Bug fixes * Really stop reporting an error when cleaning already-deleted files. Pull request #269 by Randy Coulman * Fixed infinite loop when cleaning already-deleted files on windows. === 10.3 / 2014-04-15 ==== Enhancements * Added --build-all option to rake which treats all file prerequisites as out-of-date. Pull request #254 by Andrew Gilbert. * Added Rake::NameSpace#scope. Issue #263 by Jon San Miguel. ==== Bug fixes * Suppress org.jruby package files in rake error messages for JRuby users. Issue #213 by Charles Nutter. * Fixed typo, removed extra "h". Pull request #267 by Hsing-Hui Hsu. * Rake no longer reports an error when cleaning already-deleted files. Pull request #266 by Randy Coulman. * Consume stderr while determining CPU count to avoid hang. Issue #268 by Albert Sun. === 10.2.2 / 2014-03-27 ==== Bug fixes * Restored Ruby 1.8.7 compatibility === 10.2.1 / 2014-03-25 ==== Bug fixes * File tasks including a ':' are now top-level tasks again. Issue #262 by Josh Holtrop. * Use sysctl for CPU count for all BSDs. Pull request #261 by Joshua Stein. * Fixed CPU detection for unknown platforms. === 10.2.0 / 2014-03-24 ==== Enhancements * Rake now requires Ruby 1.9 or newer. For me, this is a breaking change, but it seems that Jim planned to release it with Rake 10.2. See also pull request #247 by Philip Arndt. * Rake now allows you to declare tasks under a namespace like: task 'a:b' do ... end Pull request #232 by Judson Lester. * Task#source defaults to the first prerequisite in non-rule tasks. Pull request #215 by Avdi Grimm. * Rake now automatically rebuilds and reloads imported files. Pull request #209 by Randy Coulman. * The rake task arguments can contain escaped commas. Pull request #214 by Filip Hrbek. * Rake now prints the exception class on errors. Patch #251 by David Cornu. ==== Bug fixes * Fixed typos. Pull request #256 by Valera Rozuvan, #250 via Jake Worth, #260 by Zachary Scott. * Fixed documentation for calling tasks with arguments. Pull request #235 by John Varghese. * Clarified `rake -f` usage message. Pull request #252 by Marco Pfatschbacher. * Fixed a test failure on windows. Pull request #231 by Hiroshi Shirosaki. * Fixed corrupted rake.1.gz. Pull request #225 by Michel Boaventura. * Fixed bug in can\_detect\_signals? in test. Patch from #243 by Alexey Borzenkov. === 10.1.1 * Use http://github.com/jimweirich/rake instead of http://rake.rubyforge.org for canonical project url. === 10.1.0 ==== Changes ===== New Features * Add support for variable length task argument lists. If more actual arguments are supplied than named arguments, then the extra arguments values will be in args.extras. * Application name is not displayed in the help banner. (Previously "rake" was hardcoded, now rake-based applications can display their own names). ===== Bug Fixes Bug fixes include: * Fix backtrace suppression issues. * Rules now explicit get task arguments passed to them. * Rename FileList#exclude? to FileList#exclude\_from\_list? to avoid conflict with new Rails method. * Clean / Clobber tasks now report failure to remove files. * Plus heaps of internal code cleanup. ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Michael Nikitochkin (general code cleanup) * Vipul A M (general code cleanup) * Dennis Bell (variable length task argument lists) * Jacob Swanner (rules arguments) * Rafael Rosa Fu (documentation typo) * Stuart Nelson (install.rb fixes) * Lee Hambley (application name in help banner) -- Jim Weirich === 10.0.3 "Jim, when will Rake reach version 1.0?" Over the past several years I've been asked that question at conferences, panels and over twitter. Due to historical reasons (or maybe just plain laziness) Rake has (incorrectly) been treating the second digit of the version as the major release number. So in my head Rake was already at version 9. Well, it's time to fix things. This next version of Rake drops old, crufty, backwards compatibility hacks such as top level constants, DSL methods defined in Object and numerous other features that are just no longer desired. It's also time to drop the leading zero from the version number as well and call this new version of rake what it really is: Version 10. So, welcome to Rake 10.0! Rake 10 is actually feature identical to the latest version of Rake 9 (that would be the version spelled 0.9.3), *except* that Rake 10 drops all the sundry deprecated features that have accumulated over the years. If your Rakefile is up to date and current with all the new features of Rake 10, you are ready to go. If your Rakefile still uses a few deprecated feeatures, feel free to use Rake 9 (0.9.3) with the same feature set. Just be aware that future features will be in Rake 10 family line. ==== Changes As mentioned above, there are no new features in Rake 10. However, there are a number of features missing: * Classic namespaces are now gone. Rake is no longer able to reflect the options settings in the global variables ($rakefile, $show\_tasks, $show\_prereqs, $trace, $dryrun and $silent). The --classic-namespace option is no longer supported. * Global constants are no longer supported. This includes Task, FileTask, FileCreationTask and RakeApp). The constant missing hook to warn about using global rake constants has been removed. * The Rake DSL methods (task, file, directory, etc) are in their own module (Rake::DSL). The stub versions of these methods (that printed warnings) in Object have been removed. However, the DSL methods are added to the top-level main object. Since main is not in the inheritance tree, the presence of the DSL methods in main should be low impact on other libraries. If you want to use the Rake DSL commands from your own code, just include Rake::DSL into your own classes and modules. * The deprecated syntax for task arguments (the one using :needs) has been removed. * The --reduce-compat flag has been removed (it's not needed anymore). * The deprecated rake/sys.rb library has been removed. * The deprecated rake/rdoctask.rb library has been removed. RDoc supplies its own rake task now. * The deprecated rake/gempackagetask.rb library has been removed. Gem supplies its own package task now. There is one small behavioral change: * Non-file tasks now always report the current time as their time stamp. This is different from the previous behavior where non-file tasks reported current time only if there were no prerequisites, and the max prerequisite timestamp otherwise. This lead to inconsistent and surprising behavior when adding prerequisites to tasks that in turn were prequisites to file tasks. The new behavior is more consistent and predictable. ==== Changes (from 0.9.3, 0.9.4, 0.9.5) Since Rake 10 includes the changes from the last version of Rake 9, we'll repeat the changes for versions 0.9.3 through 0.9.5 here. ===== New Features (in 0.9.3) * Multitask tasks now use a thread pool. Use -j to limit the number of available threads. * Use -m to turn regular tasks into multitasks (use at your own risk). * You can now do "Rake.add_rakelib 'dir'" in your Rakefile to programatically add rake task libraries. * You can specific backtrace suppression patterns (see --suppress-backtrace) * Directory tasks can now take prerequisites and actions * Use --backtrace to request a full backtrace without the task trace. * You can say "--backtrace=stdout" and "--trace=stdout" to route trace output to standard output rather than standard error. * Optional 'phony' target (enable with 'require 'rake/phony'") for special purpose builds. * Task#clear now clears task comments as well as actions and prerequisites. Task#clear_comment will specifically target comments. * The --all option will force -T and -D to consider all the tasks, with and without descriptions. ===== Bug Fixes (in 0.9.3) * Semi-colons in windows rakefile paths now work. * Improved Control-C support when invoking multiple test suites. * egrep method now reads files in text mode (better support for Windows) * Better deprecation line number reporting. * The -W option now works with all tasks, whether they have a description or not. * File globs in rake should not be sorted alphabetically, independent of file system and platform. * Numerous internal improvements. * Documentation typos and fixes. ===== Bug Fixes (in 0.9.4) * Exit status with failing tests is not correctly set to non-zero. * Simplified syntax for phony task (for older versions of RDoc). * Stand alone FileList usage gets glob function (without loading in extra dependencies) ===== Bug Fixes (in 0.9.5) * --trace and --backtrace no longer swallow following task names. ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 10.0.2 ==== Changes ===== Bug Fixes * --trace and --backtrace no longer swallow following task names. ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 10.0.1 ==== Changes ===== Bug Fixes * Exit status with failing tests is not correctly set to non-zero. * Simplified syntax for phony task (for older versions of RDoc). * Stand alone FileList usage gets glob function (without loading in extra dependencies) ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 10.0.0 "Jim, when will Rake reach version 1.0?" Over the past several years I've been asked that question at conferences, panels and over twitter. Due to historical reasons (or maybe just plain laziness) Rake has (incorrectly) been treating the second digit of the version as the major release number. So in my head Rake was already at version 9. Well, it's time to fix things. This next version of Rake drops old, crufty, backwards compatibility hacks such as top level constants, DSL methods defined in Object and numerous other features that are just no longer desired. It's also time to drop the leading zero from the version number as well and call this new version of rake what it really is: Version 10. So, welcome to Rake 10.0! Rake 10 is actually feature identical to the latest version of Rake 9 (that would be the version spelled 0.9.3), *except* that Rake 10 drops all the sundry deprecated features that have accumulated over the years. If your Rakefile is up to date and current with all the new features of Rake 10, you are ready to go. If your Rakefile still uses a few deprecated feeatures, feel free to use Rake 9 (0.9.3) with the same feature set. Just be aware that future features will be in Rake 10 family line. ==== Changes in 10.0 As mentioned above, there are no new features in Rake 10. However, there are a number of features missing: * Classic namespaces are now gone. Rake is no longer able to reflect the options settings in the global variables ($rakefile, $show\_tasks, $show\_prereqs, $trace, $dryrun and $silent). The --classic-namespace option is no longer supported. * Global constants are no longer supported. This includes Task, FileTask, FileCreationTask and RakeApp). The constant missing hook to warn about using global rake constants has been removed. * The Rake DSL methods (task, file, directory, etc) are in their own module (Rake::DSL). The stub versions of these methods (that printed warnings) in Object have been removed. However, the DSL methods are added to the top-level main object. Since main is not in the inheritance tree, the presence of the DSL methods in main should be low impact on other libraries. If you want to use the Rake DSL commands from your own code, just include Rake::DSL into your own classes and modules. * The deprecated syntax for task arguments (the one using :needs) has been removed. * The --reduce-compat flag has been removed (it's not needed anymore). * The deprecated rake/sys.rb library has been removed. * The deprecated rake/rdoctask.rb library has been removed. RDoc supplies its own rake task now. * The deprecated rake/gempackagetask.rb library has been removed. Gem supplies its own package task now. There is one small behavioral change: * Non-file tasks now always report the current time as their time stamp. This is different from the previous behavior where non-file tasks reported current time only if there were no prerequisites, and the max prerequisite timestamp otherwise. This lead to inconsistent and surprising behavior when adding prerequisites to tasks that in turn were prequisites to file tasks. The new behavior is more consistent and predictable. ==== Changes (from 0.9.3) Since Rake 10 includes the changes from the last version of Rake 9, we'll repeat the changes for version 0.9.3 here. ===== New Features * Multitask tasks now use a thread pool. Use -j to limit the number of available threads. * Use -m to turn regular tasks into multitasks (use at your own risk). * You can now do "Rake.add_rakelib 'dir'" in your Rakefile to programatically add rake task libraries. * You can specific backtrace suppression patterns (see --suppress-backtrace) * Directory tasks can now take prerequisites and actions * Use --backtrace to request a full backtrace without the task trace. * You can say "--backtrace=stdout" and "--trace=stdout" to route trace output to standard output rather than standard error. * Optional 'phony' target (enable with 'require 'rake/phony'") for special purpose builds. * Task#clear now clears task comments as well as actions and prerequisites. Task#clear_comment will specifically target comments. * The --all option will force -T and -D to consider all the tasks, with and without descriptions. ===== Bug Fixes * Semi-colons in windows rakefile paths now work. * Improved Control-C support when invoking multiple test suites. * egrep method now reads files in text mode (better support for Windows) * Better deprecation line number reporting. * The -W option now works with all tasks, whether they have a description or not. * File globs in rake should not be sorted alphabetically, independent of file system and platform. * Numerous internal improvements. * Documentation typos and fixes. ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 0.9.6 Rake version 0.9.6 contains a number of fixes mainly for merging Rake into the Ruby source tree and fixing tests. ==== Changes ===== Bug Fixes (0.9.6) * Better trace output when using a multi-threaded Rakefile. * Arg parsing is now consistent for tasks and multitasks. * Skip exit code test in versions of Ruby that don't support it well. Changes for better integration with the Ruby source tree: * Fix version literal for Ruby source tree build. * Better loading of libraries for testing in Ruby build. * Use the ruby version provided by Ruby's tests. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 0.9.5 Rake version 0.9.5 contains a number of bug fixes. ==== Changes ===== Bug Fixes (0.9.5) * --trace and --backtrace no longer swallow following task names. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 0.9.4 Rake version 0.9.4 contains a number of bug fixes. ==== Changes ===== Bug Fixes (0.9.4) * Exit status with failing tests is not correctly set to non-zero. * Simplified syntax for phony task (for older versions of RDoc). * Stand alone FileList usage gets glob function (without loading in extra dependencies) ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 0.9.3 Rake version 0.9.3 contains some new, backwards compatible features and a number of bug fixes. ==== Changes ===== New Features * Multitask tasks now use a thread pool. Use -j to limit the number of available threads. * Use -m to turn regular tasks into multitasks (use at your own risk). * You can now do "Rake.add_rakelib 'dir'" in your Rakefile to programatically add rake task libraries. * You can specific backtrace suppression patterns (see --suppress-backtrace) * Directory tasks can now take prerequisites and actions * Use --backtrace to request a full backtrace without the task trace. * You can say "--backtrace=stdout" and "--trace=stdout" to route trace output to standard output rather than standard error. * Optional 'phony' target (enable with 'require 'rake/phony'") for special purpose builds. * Task#clear now clears task comments as well as actions and prerequisites. Task#clear_comment will specifically target comments. * The --all option will force -T and -D to consider all the tasks, with and without descriptions. ===== Bug Fixes * Semi-colons in windows rakefile paths now work. * Improved Control-C support when invoking multiple test suites. * egrep method now reads files in text mode (better support for Windows) * Better deprecation line number reporting. * The -W option now works with all tasks, whether they have a description or not. * File globs in rake should not be sorted alphabetically, independent of file system and platform. * Numerous internal improvements. * Documentation typos and fixes. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === Rake 0.9.2.2 Rake version 0.9.2.2 is mainly bug fixes. ==== Changes * The rake test loader now removes arguments it has processed. Issue #51 * Rake::TaskArguments now responds to #values\_at * RakeFileUtils.verbose_flag = nil silences output the same as 0.8.7 * Rake tests are now directory-independent * Rake tests are no longer require flexmock * Commands constant is no longer polluting top level namespace. * Show only the interesting portion of the backtrace by default (James M. Lawrence). * Added --reduce-compat option to remove backward compatible DSL hacks (James M. Lawrence). ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence (quix) * Roger Pack * Cezary Baginski * Sean Scot August Moon * R.T. Lechow * Alex Chaffee * James Tucker * Matthias Lüdtke * Santiago Pastorino Also, bit thanks to Eric Hodel for assisting with getting this release out the door (where "assisting" includes, but is not by any means limited to, "pushing" me to get it done). -- Jim Weirich === 0.9.2 Rake version 0.9.2 has a few small fixes. See below for details. ==== Changes * Support for Ruby 1.8.6 was fixed. * Global DSL warnings now honor --no-deprecate ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence (quix) * Roger Pack * Cezary Baginski * Sean Scot August Moon * R.T. Lechow * Alex Chaffee * James Tucker * Matthias Lüdtke * Santiago Pastorino Also, bit thanks to Eric Hodel for assisting with getting this release out the door (where "assisting" includes, but is not by any means limited to, "pushing" me to get it done). -- Jim Weirich === 0.9.1 Rake version 0.9.1 has a number of bug fixes and enhancments (see below for more details). Additionally, the internals have be slightly restructured and improved. ==== Changes Rake 0.9.1 adds back the global DSL methods, but with deprecation messages. This allows Rake 0.9.1 to be used with older rakefiles with warning messages. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence (quix) * Roger Pack * Cezary Baginski * Sean Scot August Moon * R.T. Lechow * Alex Chaffee * James Tucker * Matthias Lüdtke * Santiago Pastorino Also, bit thanks to Eric Hodel for assisting with getting this release out the door (where "assisting" includes, but is not by any means limited to, "pushing" me to get it done). -- Jim Weirich === 0.9.0 Rake version 0.9.0 has a number of bug fixes and enhancments (see below for more details). Additionally, the internals have be slightly restructured and improved. ==== Changes ===== New Features / Enhancements / Bug Fixes in Version 0.9.0 * Rake now warns when the deprecated :needs syntax used (and suggests the proper syntax in the warning). * Moved Rake DSL commands to top level ruby object 'main'. Rake DSL commands are no longer private methods in Object. (Suggested by James M. Lawrence/quix) * Rake now uses case-insensitive comparisons to find the Rakefile on Windows. Based on patch by Roger Pack. * Rake now requires (instead of loads) files in the test task. Patch by Cezary Baginski. * Fixed typos. Patches by Sean Scot August Moon and R.T. Lechow. * Rake now prints the Rakefile directory only when it's different from the current directory. Patch by Alex Chaffee. * Improved rakefile_location discovery on Windows. Patch by James Tucker. * Rake now recognizes "Windows Server" as a windows system. Patch by Matthias Lüdtke * Rake::RDocTask is deprecated. Use RDoc::Task from RDoc 2.4.2+ (require 'rdoc/task') * Rake::GemPackageTask is deprecated. Use Gem::PackageTask (require 'rubygems/package\_task') * Rake now outputs various messages to $stderr instead of $stdout. * Rake no longer emits warnings for Config. Patch by Santiago Pastorino. * Removed Rake's DSL methods from the top level scope. If you need to call 'task :xzy' in your code, include Rake::DSL into your class, or put the code in a Rake::DSL.environment do ... end block. * Split rake.rb into individual files. * Support for the --where (-W) flag for showing where a task is defined. * Fixed quoting in test task. (http://onestepback.org/redmine/issues/show/44, http://www.pivotaltracker.com/story/show/1223138) * Fixed the silent option parsing problem. (http://onestepback.org/redmine/issues/show/47) * Fixed :verbose=>false flag on sh and ruby commands. * Rake command line options may be given by default in a RAKEOPT environment variable. * Errors in Rake will now display the task invocation chain in effect at the time of the error. * Accepted change by warnickr to not expand test patterns in shell (allowing more files in the test suite). * Fixed that file tasks did not perform prereq lookups in scope (Redmine #57). ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence (quix) * Roger Pack * Cezary Baginski * Sean Scot August Moon * R.T. Lechow * Alex Chaffee * James Tucker * Matthias Lüdtke * Santiago Pastorino Also, bit thanks to Eric Hodel for assisting with getting this release out the door (where "assisting" includes, but is not by any means limited to, "pushing" me to get it done). -- Jim Weirich === 0.8.7 Rake version 0.8.5 introduced greatly improved support for executing commands on Windows. The "sh" command now has the same semantics on Windows that it has on Unix based platforms. Rake version 0.8.6 includes minor fixes the the RDoc generation. Rake version 0.8.7 includes a minor fix for JRuby running on windows. ==== Changes ===== New Features / Enhancements in Version 0.8.5 * Improved implementation of the Rake system command for Windows. (patch from James M. Lawrence/quix) * Support for Ruby 1.9's improved system command. (patch from James M. Lawrence/quix) * Rake now includes the configured extension when invoking an executable (Config::CONFIG['EXEEXT]) ===== Bug Fixes in Version 0.8.5 * Environment variable keys are now correctly cased (it matters in some implementations). ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Charles Nutter -- Jim Weirich === 0.8.6 Rake version 0.8.5 introduced greatly improved support for executing commands on Windows. The "sh" command now has the same semantics on Windows that it has on Unix based platforms. Rake version 0.8.5 includes minor fixes the the RDoc generation. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence/quix * Luis Lavena -- Jim Weirich === 0.8.5 Rake version 0.8.5 is a new release of Rake with greatly improved support for executing commands on Windows. The "sh" command now has the same semantics on Windows that it has on Unix based platforms. ==== Changes ===== New Features / Enhancements in Version 0.8.5 * Improved implementation of the Rake system command for Windows. (patch from James M. Lawrence/quix) * Support for Ruby 1.9's improved system command. (patch from James M. Lawrence/quix) * Rake now includes the configured extension when invoking an executable (Config::CONFIG['EXEEXT]) ===== Bug Fixes in Version 0.8.5 * Environment variable keys are now correctly cased (it matters in some implementations). ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence/quix * Luis Lavena -- Jim Weirich === 0.8.4 Rake version 0.8.4 is a bug-fix release of rake. NOTE: The version of Rake that comes with Ruby 1.9 has diverged slightly from the core Rake code base. Rake 0.8.4 will work with Ruby 1.9, but is not a strict upgrade for the Rake that comes with Ruby 1.9. A (near) future release of Rake will unify those two codebases. ==== Letter Writing Campaign Thanks to Aaron Patterson (@tenderlove) and Eric Hodel (@drbrain) for their encouraging support in organizing a letter writing campaign to lobby for the "Warning Free" release of rake 0.8.4. A special callout goes to Jonathan D. Lord, Sr (Dr. Wingnut) whose postcard was the first to actually reach me. (see http://tenderlovemaking.com/2009/02/26/we-need-a-new-version-of-rake/ for details) ==== Changes ===== New Features / Enhancements in Version 0.8.4 * Case is preserved on rakefile names. (patch from James M. Lawrence/quix) * Improved Rakefile case insensitivity testing (patch from Luis Lavena). * Windows system dir search order is now: HOME, HOMEDRIVE + HOMEPATH, APPDATA, USERPROFILE (patch from Luis Lavena) * MingGW is now recognized as a windows platform. (patch from Luis Lavena) ===== Bug Fixes in Version 0.8.4 * Removed reference to manage_gem to fix the warning produced by the gem package task. * Fixed stray ARGV option problem that was interfering with Test::Unit::Runner. (patch from Pivotal Labs) ===== Infrastructure Improvements in Version 0.8.4 * Numerous fixes to the windows test suite (patch from Luis Lavena). * Improved Rakefile case insensitivity testing (patch from Luis Lavena). * Better support for windows paths in the test task (patch from Simon Chiang/bahuvrihi) ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence/quix * Luis Lavena * Pivotal Labs * Simon Chiang/bahuvrihi -- Jim Weirich === 0.8.3 Rake version 0.8.3 is a bug-fix release of rake. ==== Changes ===== Bug Fixes in Version 0.8.3 * Enhanced the system directory detection in windows. We now check HOMEDRIVE/HOMEPATH and USERPROFILE if APPDATA isn't found. (Patch supplied by James Tucker). Rake no long aborts if it can't find the directory. * Added fix to handle ruby installations in directories with spaces in their name. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Edwin Pratomo * Gavin Stark * Adam Q. Salter * Adam Majer * Emanuel Indermühle * Ittay Dror * Bheeshmar Redheendran (for spending an afternoon with me debugging windows issues) -- Jim Weirich === 0.8.2 Rake version 0.8.2 is a new release of rake that includes a number of new features and numerous bug fixes. ==== Changes ===== New Features in Version 0.8.2 * Switched from getoptlong to optparse (patches supplied by Edwin Pratomo). * The -T option will now attempt to dynamically sense the size of the terminal. The -T output will only self-truncate if the output is a tty. However, if RAKE_COLUMNS is explicitly set, it will be honored in any case. (Patch provided by Gavin Stark). * The following public methods have been added to rake task objects: * task.clear -- Clear both the prerequisites and actions of the target rake task. * task.clear_prerequisites -- Clear all the existing prerequisites from the target rake task. * task.clear_actions -- Clear all the existing actions from the target rake task. * task.reenable -- Re-enable a task, allowing its actions to be executed again if the task is invoked. * Changed RDoc test task to have no default template. This makes it easier for the tempate to pick up the template from the environment. * Default values for task arguments can easily be specified with the :with_defaults method. (Idea for default argument merging supplied by (Adam Q. Salter) ===== Bug Fixes in Version 0.8.2 * Fixed bug in package task so that it will include the subdir directory in the package for testing. (Bug found by Adam Majer) * Fixed filename dependency order bug in test\_inspect\_pending and test\_to\_s\_pending. (Bug found by Adam Majer) * Fixed check for file utils options to make them immune to the symbol/string differences. (Patch supplied by Edwin Pratomo) * Fixed bug with rules involving multiple source, where only the first dependency of a rule has any effect (Patch supplied by Emanuel Indermühle) * FileList#clone and FileList#dup have better sematics w.r.t. taint and freeze. * Changed from using Mutex to Monitor. Evidently Mutex causes thread join errors when Ruby is compiled with -disable-pthreads. (Patch supplied by Ittay Dror) * Fixed bug in makefile parser that had problems with extra spaces in file task names. (Patch supplied by Ittay Dror) ==== Other changes in Version 0.8.2 * Added ENV var to rake's own Rakefile to prevent OS X from including extended attribute junk in the rake package tar file. (Bug found by Adam Majer) * Added a performance patch for reading large makefile dependency files. (Patch supplied by Ittay Dror) ==== Task Argument Examples Prior to version 0.8.0, rake was only able to handle command line arguments of the form NAME=VALUE that were passed into Rake via the ENV hash. Many folks had asked for some kind of simple command line arguments, perhaps using "--" to separate regular task names from argument values on the command line. The problem is that there was no easy way to associate positional arguments on the command line with different tasks. Suppose both tasks :a and :b expect a command line argument: does the first value go with :a? What if :b is run first? Should it then get the first command line argument. Rake 0.8.0 solves this problem by explicitly passing values directly to the tasks that need them. For example, if I had a release task that required a version number, I could say: rake release[0.8.2] And the string "0.8.2" will be passed to the :release task. Multiple arguments can be passed by separating them with a comma, for example: rake name[john,doe] Just a few words of caution. The rake task name and its arguments need to be a single command line argument to rake. This generally means no spaces. If spaces are needed, then the entire rake + argument string should be quoted. Something like this: rake "name[billy bob, smith]" (Quoting rules vary between operating systems and shells, so make sure you consult the proper docs for your OS/shell). ===== Tasks that Expect Parameters Parameters are only given to tasks that are setup to expect them. In order to handle named parameters, the task declaration syntax for tasks has been extended slightly. For example, a task that needs a first name and last name might be declared as: task :name, :first_name, :last_name The first argument is still the name of the task (:name in this case). The next to argumements are the names of the parameters expected by :name (:first_name and :last_name in the example). To access the values of the parameters, the block defining the task behaviour can now accept a second parameter: task :name, :first_name, :last_name do |t, args| puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end The first argument of the block "t" is always bound to the current task object. The second argument "args" is an open-struct like object that allows access to the task arguments. Extra command line arguments to a task are ignored. Missing command line arguments are given the nil value. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Edwin Pratomo * Gavin Stark * Adam Q. Salter * Adam Majer * Emanuel Indermühle * Ittay Dror * Bheeshmar Redheendran (for spending an afternoon with me debugging windows issues) -- Jim Weirich === 0.8.0/0.8.1 Rake version 0.8.0 is a new release of rake that includes serveral new features. ==== Changes ===== New Features in Version 0.8.0 * Tasks can now receive command line parameters. See the examples below for more details. * Comments are limited to 80 columns on output, but full comments can be seen by using the -D parameter. (feature suggested by Jamis Buck). * Explicit exit(n) calls will now set the exit status to n. (patch provided by Stephen Touset). * Rake is now compatible with Ruby 1.9. Version 0.8.1 is a minor update that includes additional Ruby 1.9 compatibility fixes. ==== Task Argument Examples Prior to version 0.8.0, rake was only able to handle command line arguments of the form NAME=VALUE that were passed into Rake via the ENV hash. Many folks had asked for some kind of simple command line arguments, perhaps using "--" to separate regular task names from argument values on the command line. The problem is that there was no easy way to associate positional arguments on the command line with different tasks. Suppose both tasks :a and :b expect a command line argument: does the first value go with :a? What if :b is run first? Should it then get the first command line argument. Rake 0.8.0 solves this problem by explicitly passing values directly to the tasks that need them. For example, if I had a release task that required a version number, I could say: rake release[0.8.0] And the string "0.8.0" will be passed to the :release task. Multiple arguments can be passed by separating them with a comma, for example: rake name[john,doe] Just a few words of caution. The rake task name and its arguments need to be a single command line argument to rake. This generally means no spaces. If spaces are needed, then the entire rake + argument string should be quoted. Something like this: rake "name[billy bob, smith]" (Quoting rules vary between operating systems and shells, so make sure you consult the proper docs for your OS/shell). ===== Tasks that Expect Parameters Parameters are only given to tasks that are setup to expect them. In order to handle named parameters, the task declaration syntax for tasks has been extended slightly. For example, a task that needs a first name and last name might be declared as: task :name, :first_name, :last_name The first argument is still the name of the task (:name in this case). The next to argumements are the names of the parameters expected by :name (:first_name and :last_name in the example). To access the values of the parameters, the block defining the task behaviour can now accept a second parameter: task :name, :first_name, :last_name do |t, args| puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end The first argument of the block "t" is always bound to the current task object. The second argument "args" is an open-struct like object that allows access to the task arguments. Extra command line arguments to a task are ignored. Missing command line arguments are given the nil value. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Jamis Buck (for comment formatting suggestions) * Stephen Touset (for exit status patch). -- Jim Weirich === 0.7.3 Rake version 0.7.3 is a minor release that includes some refactoring to better support custom Rake applications. ==== Changes ===== New Features in Version 0.7.3 * Added the +init+ and +top_level+ methods to make the creation of custom Rake applications a bit easier. E.g. gem 'rake', ">= 0.7.3" require 'rake' Rake.application.init('myrake') task :default do something_interesting end Rake.application.top_level ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... -- Jim Weirich === 0.7.2 Version 0.7.2 supplies a bug fix and a few minor enhancements. In particular, the new version fixes an incompatibility with the soon to be released Ruby 1.8.6. We strongly recommend upgrading to Rake 0.7.2 in order to be compatible with the new version of Ruby. ==== Changes ===== Bug Fixes in 0.7.2 There are quite a number of bug fixes in the new 0.7.2 version of Rake: * Removed dependency on internal fu_xxx functions from FileUtils. * Error messages are now send to stderr rather than stdout (from Payton Quackenbush). * Better error handling on invalid command line arguments (from Payton Quackenbush). * Fixed some bugs where the application object was going to the global appliation instead of using its own data. * Fixed the method name leak from FileUtils (bug found by Glenn Vanderburg). * Added test for noop, bad_option and verbose flags to sh command. * Added a description to the gem task in GemPackageTask. * Fixed a bug when rules have multiple prerequisites (patch by Joel VanderWerf) * Added the handful of RakeFileUtils to the private method as well. ===== New Features in 0.7.2 The following new features are available in Rake version 0.7.2: * Added square and curly bracket patterns to FileList#include (Tilman Sauerbeck). * FileLists can now pass a block to FileList#exclude to exclude files based on calculated values. * Added plain filename support to rule dependents (suggested by Nobu Nakada). * Added pathmap support to rule dependents. In other words, if a pathmap format (beginning with a '%') is given as a Rake rule dependent, then the name of the depend will be the name of the target with the pathmap format applied. * Added a 'tasks' method to a namespace to get a list of tasks associated with the namespace. * Added tar_command and zip_command options to the Package task. * The clean task will no longer delete 'core' if it is a directory. ===== Internal Rake Improvements The following changes will are mainly internal improvements and refactorings and have little effect on the end user. But they may be of interest to the general public. * Added rcov task and updated unit testing for better code coverage. * Added a 'shame' task to the Rakefile. * Added rake_extension to handle detection of extension collisions. * Added a protected 'require "rubygems"' to test/test_application to unbreak cruisecontrol.rb. * Removed rake\_dup. Now we just simply rescue a bad dup. * Refactored the FileList reject logic to remove duplication. * Removed if \_\_FILE\_\_ at the end of the rake.rb file. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Payton Quackenbush -- For several error handling improvements. * Glenn Vanderburg -- For finding and fixing the method name leak from FileUtils. * Joel VanderWerf -- for finding and fixing a bug in the handling of multiple prerequisites. * Tilman Sauerbeck -- For some enhancing FileList to support more advanced file globbing. * Nobu Nakada -- For suggesting plain file name support to rule dependents. -- Jim Weirich === 0.7.1 Version 0.7.1 supplies a bug fix and a few minor enhancements. ==== Changes ===== Bug Fixes in 0.7.1 * Changes in the exception reported for the FileUtils.ln caused safe_ln to fail with a NotImplementedError. Rake 0.7.1 will now catch that error or any StandardError and properly fall back to using +cp+. ===== New Features in 0.7.1 * You can filter the results of the --task option by supplying an optional regular expression. This allows the user to easily find a particular task name in a long list of possible names. * Transforming procs in a rule may now return a list of prerequisites. This allows more flexible rule formation. * FileList and String now support a +pathmap+ melthod that makes the transforming paths a bit easier. See the API docs for +pathmap+ for details. * The -f option without a value will disable the search for a Rakefile. This allows the Rakefile to be defined entirely in a library (and loaded with the -r option). The current working directory is not changed when this is done. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James Britt and Assaph Mehr for reporting and helping to debug the safe_ln issue. -- Jim Weirich === 0.7.0 These changes for Rake have been brewing for a long time. Here they are, I hope you enjoy them. ==== Changes ===== New Features * Name space support for task names (see below). * Prerequisites can be executed in parallel (see below). * Added safe_ln support for openAFS (via Ludvig Omholt). * RDoc defaults to internal (in-process) invocation. The old behavior is still available by setting the +external+ flag to true. * Rakefiles are now loaded with the expanded path to prevent accidental pollution from the Ruby load path. * Task objects my now be used in prerequisite lists directly. * Task objects (in addition to task names) may now be included in the prerequisite list of a task. * Internals cleanup and refactoring. ===== Bug Fixes * Compatibility fixes for Ruby 1.8.4 FileUtils changes. ===== Namespaces Tasks can now be nested inside their own namespaces. Tasks within one namespace will not accidentally interfer with tasks named in a different namespace. For example: namespace "main" do task :build do # Build the main program end end namespace "samples" do task :build do # Build the sample programs end end task :build_all => ["main:build", "samples:build"] Even though both tasks are named :build, they are separate tasks in their own namespaces. The :build_all task (defined in the toplevel namespace) references both build tasks in its prerequisites. You may invoke each of the individual build tasks with the following commands: rake main:build rake samples:build Or invoke both via the :build_all command: rake build_all Namespaces may be nested arbitrarily. Since the name of file tasks correspond to the name of a file in the external file system, FileTasks are not affected by the namespaces. See the Rakefile format documentation (in the Rake API documents) for more information. ===== Parallel Tasks Sometimes you have several tasks that can be executed in parallel. By specifying these tasks as prerequisites to a +multitask+ task. In the following example the tasks copy\_src, copy\_doc and copy\_bin will all execute in parallel in their own thread. multitask :copy_files => [:copy_src, :copy_doc, :copy_bin] do puts "All Copies Complete" end ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Doug Young (inspiration for the parallel task) * David Heinemeier Hansson (for --trace message enhancement and for pushing for namespace support). * Ludvig Omholt (for the openAFS fix) -- Jim Weirich === 0.6.1 * Rebuilt 0.6.0 gem without signing. === 0.6.0 Its time for some long requested enhancements and lots of bug fixes ... And a whole new web page. ==== New Web Page The primary documentation for rake has moved from the RubyForge based wiki to its own Hieraki based web site. Constant spam on the wiki made it a difficult to keep clean. The new site will be easier to update and organize. Check out the new documentation at: http://docs.rubyrake.org We will be adding new documentation to the site as time goes on. In addition to the new docs page, make sure you check out Martin Fowlers article on rake at http://martinfowler.com/articles/rake.html ==== Changes ===== New Features * Multiple prerequisites on Rake rules now allowed. However, keep the following in mind: 1. All the prerequisites of a rule must be available before a rule is triggered, where "enabled" means (a) an existing file, (b) a defined rule, or (c) another rule which also must be trigger-able. 2. Rules are checked in order of definition, so it is important to order your rules properly. If a file can be created by two different rules, put the more specific rule first (otherwise the more general rule will trigger first and the specific one will never be triggered). 3. The source method now returns the name of the first prerequisite listed in the rule. sources returns the names of all the rule prerequisites, ordered as they are defined in the rule. If the task has other prerequisites not defined in the rule (but defined in an explicit task definition), then they will _not_ be included in the sources list. * FileLists may now use the egrep command. This popular enhancement is now a core part of the FileList object. If you want to get a list of all your to-dos, fixmes and TBD comments, add the following to your Rakefile. desc "Look for TODO and FIXME tags in the code" task :todo do FileList['**/*.rb'].egrep /#.*(FIXME|TODO|TBD)/ end * The investigation method was added to task object to dump out some important values. This makes it a bit easier to debug Rake tasks. For example, if you are having problems with a particular task, just print it out: task :huh do puts Rake::Task['huh'].investigation end * The Rake::TestTask class now supports a "ruby\_opts" option to pass arbitrary ruby options to a test subprocess. ===== Some Incompatibilities * When using the ruby command to start a Ruby subprocess, the Ruby interpreter that is currently running rake is used by default. This makes it easier to use rake in an environment with multiple ruby installation. (Previously, the first ruby command found in the PATH was used). If you wish to chose a different Ruby interpreter, you can explicitly choose the interpreter via the sh command. * The major rake classes (Task, FileTask, FileCreationTask, RakeApp) have been moved out of the toplevel scope and are now accessible as Rake::Task, Rake::FileTask, Rake::FileCreationTask and Rake::Application. If your Rakefile directly references any one of these tasks, you may: 1. Update your Rakefile to use the new classnames 2. Use the --classic-namespace option on the rake command to get the old behavior, 3. Add require 'rake/classic_namespace' to the Rakefile to get the old behavior. rake will print a rather annoying warning whenever a deprecated class name is referenced without enabling classic namespace. ===== Bug Fixes * Several unit tests and functional tests were fixed to run better under windows. * Directory tasks are now a specialized version of a File task. A directory task will only be triggered if it doesn't exist. It will not be triggered if it is out of date w.r.t. any of its prerequisites. * Fixed a bug in the Rake::GemPackageTask class so that the gem now properly contains the platform name. * Fixed a bug where a prerequisite on a file task would cause an exception if the prerequisite did not exist. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Greg Fast (better ruby_opt test options) * Kelly Felkins (requested by better namespace support) * Martin Fowler (suggested Task.investigation) * Stuart Jansen (send initial patch for multiple prerequisites). * Masao Mutch (better support for non-ruby Gem platforms) * Philipp Neubeck (patch for file task exception fix) -- Jim Weirich === 0.5.4 Time for some minor bug fixes and small enhancements ==== Changes Here are the changes for version 0.5.4 ... * Added double quotes to the test runner. This allows the location of the tests (and runner) to be in a directory path that contains spaces (e.g. "C:/Program Files/ruby/bin"). * Added .svn to default ignore list. Now subversion project metadata is automatically ignored by Rake's FileList. * Updated FileList#include to support nested arrays and filelists. FileLists are flat lists of file names. Using a FileList in an include will flatten out the nested file names. == Thanks As usual, it was input from users that drove a alot of these changes. Thanks to ... * Tilman Sauerbeck for the nested FileList suggestion. * Josh Knowles for pointing out the spaces in directory name problem. -- Jim Weirich === 0.5.3 Although it has only been two weeks since the last release, we have enough updates to the Rake program to make it time for another release. ==== Changes Here are the changes for version 0.5.3 ... * FileLists have been extensively changed so that they mimic the behavior of real arrays even more closely. In particular, operations on FileLists that return a new collection (e.g. collect, reject) will now return a FileList rather than an array. In addition, several places where FileLists were not properly expanded before use have been fixed. * A method (+ext+) to simplify the handling of file extensions was added to String and to Array. * The 'testrb' script in test/unit tends to silently swallow syntax errors in test suites. Because of that, the default test loader is now a rake-provided script. You can still use 'testrb' by setting the loader flag in the test task to :testrb. (See the API documents for TestTask for all the loader flag values). * FileUtil methods (e.g. cp, mv, install) are now declared to be private. This will cut down on the interference with user defined methods of the same name. * Fixed the verbose flag in the TestTask so that the test code is controlled by the flag. Also shortened up some failure messages. (Thanks to Tobias Luetke for the suggestion). * Rules will now properly detect a task that can generate a source file. Previously rules would only consider source files that were already present. * Added an +import+ command that allows Rake to dynamically import dependendencies into a running Rake session. The +import+ command can run tasks to update the dependency file before loading them. Dependency files can be in rake or make format, allowing rake to work with tools designed to generate dependencies for make. ==== Thanks As usual, it was input from users that drove a alot of these changes. Thanks to ... * Brian Gernhardt for the rules fix (especially for the patience to explain the problem to me until I got what he was talking about). * Stefan Lang for pointing out problems in the dark corners of the FileList implementation. * Alexey Verkhovsky pointing out the silently swallows syntax errors in tests. * Tobias Luetke for beautifying the test task output. * Sam Roberts for some of the ideas behind dependency loading. -- Jim Weirich === 0.5.0 It has been a long time in coming, but we finally have a new version of Rake available. ==== Changes * Fixed documentation that was lacking the Rake module name (Tilman Sauerbeck). * Added tar.gz and tar.bz2 support to package task (Tilman Sauerbeck). * Recursive rules are now supported (Tilman Sauerbeck). * Added warning option for the Test Task (requested by Eric Hodel). * The jamis rdoc template is only used if it exists. * Added fix for Ruby 1.8.2 test/unit and rails problem. * Added contributed rake man file (Jani Monoses). * Added Brian Candler's fix for problems in --trace and --dry-run mode. ==== Thanks Lots of people provided input to this release. Thanks to Tilman Sauerbeck for numerous patches, documentation fixes and suggestions. And for also pushing me to get this release out. Also, thanks to Brian Candler for the finding and fixing --trace/dry-run fix. That was an obscure bug. Also to Eric Hodel for some good suggestions. -- Jim Weirich === 0.4.15 ==== Changes Version 0.4.15 is a bug fix update for the Ruby 1.8.2 compatibility changes. This release includes: * Fixed a bug that prevented the TESTOPTS flag from working with the revised for 1.8.2 test task. * Updated the docs on --trace to indicate that it also enables a full backtrace on errors. * Several fixes for new warnings generated. ==== Mini-Roadmap I will continue to issue Rake updates in the 0.4.xx series as new Ruby-1.8.2 issues become manifest. Once the codebase stabilizes, I will release a 0.5.0 version incorporating all the changes. If you are not using Ruby-1.8.2 and wish to avoid version churn, I recommend staying with a release prior to Rake-0.4.14. === 0.4.14 Version 0.4.14 is a compatibility fix to allow Rake's test task to work under Ruby 1.8.2. A change in the Test::Unit autorun feature prevented Rake from running any tests. This release fixes the problem. Rake 0.4.14 is the recommended release for anyone using Ruby 1.8.2. === 0.4.13 * Fixed the dry-run flag so it is operating again. * Multiple arguments to sh and ruby commands will not be interpreted by the shell (patch provided by Jonathan Paisley). === 0.4.12 * Added --silent (-s) to suppress the (in directory) rake message. === 0.4.11 * Changed the "don't know how to rake" message (finally) * Changes references to a literal "Rakefile" to reference the global variable $rakefile (which contains the actual name of the rakefile). === 0.4.10 * Added block support to the "sh" command, allowing users to take special actions on the result of the system call. E.g. sh "shell_command" do |ok, res| puts "Program returned #{res.exitstatus}" if ! ok end === 0.4.9 * Switched to Jamis Buck's RDoc template. * Removed autorequire from Rake's gem spec. This prevents the Rake libraries from loading while using rails. === 0.4.8 * Added support for .rb versions of Rakefile. * Removed \\\n's from test task. * Fixed Ruby 1.9 compatibility issue with FileList. === 0.4.7 * Fixed problem in FileList that caused Ruby 1.9 to go into infinite recursion. Since to_a was removed from Object, it does not need to added back into the list of methods to rewrite in FileList. (Thanks to Kent Sibilev for pointing this out). === 0.4.6 * Removed test version of ln in FileUtils that prevented safe_ln from using ln. === 0.4.5 * Upgraded comments in TestTask. * FileList to_s and inspect now automatically resolve pending changes. * FileList#exclude properly returns the FileList. === 0.4.4 * Fixed initialization problem with @comment. * Now using multi -r technique in TestTask. Switch Rakefile back to using the built-in test task macros because the rake runtime is no longer needed. * Added 'TEST=filename' and 'TESTOPTS=options' to the Test Task macros. * Allow a +test_files+ attribute in test tasks. This allows more flexibility in specifying test files. === 0.4.3 * Fixed Comment leakage. === 0.4.2 * Added safe_ln that falls back to a copy if a file link is not supported. * Package builder now uses safe\_ln. === 0.4.1 * Task comments are now additive, combined with "/". * Works with (soon to be released) rubygems 0.6.2 (or 0.7.0) === 0.4.0 * FileList now uses deferred loading. The file system is not searched until the first call that needs the file names. * VAR=VALUE options are now accepted on the command line and are treated like environment variables. The values may be tested in a Rakefile by referencing ENV['VAR']. * File.mtime is now used (instead of File.new().mtime). === 0.3.2.x * Removed some hidden dependencies on rubygems. Tests now will test gems only if they are installed. * Removed Sys from some example files. I believe that is that last reference to Sys outside of the contrib area. * Updated all copyright notices to include 2004. === 0.3.2 * GEM Installation now works with the application stub. === 0.3.1 * FileLists now automatically ignore CVS, .bak, ! * GEM Installation now works. === 0.3.0 Promoted 0.2.10. === 0.2.10 General * Added title to Rake's rdocs * Contrib packages are no longer included in the documentation. RDoc Issues * Removed default for the '--main' option * Fixed rendering of the rdoc options * Fixed clean/clobber confusion with rerdoc * 'title' attribute added Package Task Library Issues * Version (or explicit :noversion) is required. * +package_file+ attribute is now writable FileList Issues * Dropped bang version of exclude. Now using ant-like include/exclude semantics. * Enabled the "yield self" idiom in FileList#initialize. === 0.2.9 This version contains numerous changes as the RubyConf.new(2003) presentation was being prepared. The changes include: * The monolithic rubyapp task library is in the process of being dropped in favor of lighter weight task libraries. === 0.2.7 * Added "desc" for task descriptions. * -T will now display tasks with descriptions. * -P will display tasks and prerequisites. * Dropped the Sys module in favor of the 1.8.x FileUtils module. Sys is still supported in the contrib area. === 0.2.6 * Moved to RubyForge === 0.2.5 * Switched to standard ruby app builder. * Added no_match option to file matcher. === 0.2.4 * Fixed indir, which neglected to actually change directories. === 0.2.3 * Added rake module for a help target * Added 'for\_files' to Sys * Added a $rakefile constant * Added test for selecting proper rule with multiple targets. PK ]U&"gems/rake-13.0.1/CONTRIBUTING.rdocnu[= Source Repository Rake is currently hosted at github. The github web page is https://github.com/ruby/rake . The public git clone URL is https://github.com/ruby/rake.git = Running the Rake Test Suite If you wish to run the unit and functional tests that come with Rake: * +cd+ into the top project directory of rake. * Install gem dependency using bundler: $ bundle install # Install bundler, minitest and rdoc * Run the test suite $ rake = Rubocop Rake uses Rubocop to enforce a consistent style on new changes being proposed. You can check your code with Rubocop using: $ ./bin/rubocop = Issues and Bug Reports Feel free to submit commits or feature requests. If you send a patch, remember to update the corresponding unit tests. In fact, I prefer new feature to be submitted in the form of new unit tests. For other information, feel free to ask on the ruby-talk mailing list. If you have found a bug in rake please try with the latest version of rake before filing an issue. Also check History.rdoc for bug fixes that may have addressed your issue. When submitting pull requests please check the rake Travis-CI page for test failures: https://travis-ci.org/ruby/rake PK ]mǯ gems/racc-1.4.16/bin/raccnuȯ#!/usr/bin/ruby # # $Id$ # # Copyright (c) 1999-2006 Minero Aoki # # This program is free software. # You can distribute/modify this program under the same terms of ruby. # see the file "COPYING". require 'racc/static' require 'optparse' def main output = nil debug_parser = false make_logfile = false logfilename = nil make_executable = false rubypath = nil embed_runtime = false debug_flags = Racc::DebugFlags.new line_convert = true line_convert_all = false omit_action_call = true superclass = nil check_only = false verbose = false profiler = RaccProfiler.new(false) parser = OptionParser.new parser.banner = "Usage: #{File.basename($0)} [options] " parser.on('-o', '--output-file=PATH', 'output file name [.tab.rb]') {|name| output = name } parser.on('-t', '--debug', 'Outputs debugging parser.') {|fl| debug_parser = fl } parser.on('-g', 'Equivalent to -t (obsolete).') {|fl| $stderr.puts "racc -g is obsolete. Use racc -t instead." if $VERBOSE debug_parser = fl } parser.on('-v', '--verbose', 'Creates .output log file.') {|fl| make_logfile = fl } parser.on('-O', '--log-file=PATH', 'Log file name [.output]') {|path| make_logfile = true logfilename = path } parser.on('-e', '--executable [RUBYPATH]', 'Makes executable parser.') {|path| executable = true rubypath = (path == 'ruby' ? nil : path) } parser.on('-E', '--embedded', "Embeds Racc runtime in output.") { embed_runtime = true } parser.on('--line-convert-all', 'Converts line numbers of user codes.') { line_convert_all = true } parser.on('-l', '--no-line-convert', 'Never convert line numbers.') { line_convert = false line_convert_all = false } parser.on('-a', '--no-omit-actions', 'Never omit actions.') { omit_action_call = false } parser.on('--superclass=CLASSNAME', 'Uses CLASSNAME instead of Racc::Parser.') {|name| superclass = name } parser.on('--runtime=FEATURE', "Uses FEATURE instead of 'racc/parser'") {|feat| runtime = feature } parser.on('-C', '--check-only', 'Checks syntax and quit immediately.') {|fl| check_only = fl } parser.on('-S', '--output-status', 'Outputs internal status time to time.') { verbose = true } parser.on('-P', 'Enables generator profile') { profiler = RaccProfiler.new(true) } parser.on('-D flags', "Flags for Racc debugging (do not use).") {|flags| debug_flags = Racc::DebugFlags.parse_option_string(flags) } #parser.on('--no-extensions', 'Run Racc without any Ruby extension.') { # Racc.const_set :Racc_No_Extentions, true #} parser.on('--version', 'Prints version and quit.') { puts "racc version #{Racc::Version}" exit 0 } parser.on('--runtime-version', 'Prints runtime version and quit.') { printf "racc runtime version %s (rev. %s); %s\n", Racc::Parser::Racc_Runtime_Version, Racc::Parser::Racc_Runtime_Revision, if Racc::Parser.racc_runtime_type == 'ruby' sprintf('ruby core version %s (rev. %s)', Racc::Parser::Racc_Runtime_Core_Version_R, Racc::Parser::Racc_Runtime_Core_Revision_R) else sprintf('c core version %s (rev. %s)', Racc::Parser::Racc_Runtime_Core_Version_C, Racc::Parser::Racc_Runtime_Core_Revision_C) end exit 0 } parser.on('--copyright', 'Prints copyright and quit.') { puts Racc::Copyright exit 0 } parser.on('--help', 'Prints this message and quit.') { puts parser.help exit 1 } begin parser.parse! rescue OptionParser::ParseError => err $stderr.puts err.message $stderr.puts parser.help exit 1 end if ARGV.empty? $stderr.puts 'no input' exit 1 end if ARGV.size > 1 $stderr.puts 'too many input' exit 1 end input = ARGV[0] begin $stderr.puts 'Parsing grammar file...' if verbose result = profiler.section('parse') { parser = Racc::GrammarFileParser.new(debug_flags) parser.parse(File.read(input), File.basename(input)) } if check_only $stderr.puts 'syntax ok' exit 0 end $stderr.puts 'Generating LALR states...' if verbose states = profiler.section('nfa') { Racc::States.new(result.grammar).nfa } $stderr.puts "Resolving #{states.size} states..." if verbose profiler.section('dfa') { states.dfa } $stderr.puts 'Creating parser file...' if verbose params = result.params.dup # Overwrites parameters given by a grammar file with command line options. params.superclass = superclass if superclass params.omit_action_call = true if omit_action_call # From command line option if make_executable params.make_executable = true params.interpreter = rubypath end params.debug_parser = debug_parser params.convert_line = line_convert params.convert_line_all = line_convert_all params.embed_runtime = embed_runtime profiler.section('generation') { generator = Racc::ParserFileGenerator.new(states, params) generator.generate_parser_file(output || make_filename(input, '.tab.rb')) } if make_logfile profiler.section('logging') { $stderr.puts 'Creating log file...' if verbose logfilename ||= make_filename(output || File.basename(input), '.output') File.open(logfilename, 'w') {|f| Racc::LogFileGenerator.new(states, debug_flags).output f } } end if debug_flags.status_logging log_useless states.grammar log_conflict states else report_useless states.grammar report_conflict states end profiler.report rescue Racc::Error, Errno::ENOENT, Errno::EPERM => err raise if $DEBUG or debug_flags.any? lineno = err.message.slice(/\A\d+:/).to_s $stderr.puts "#{File.basename $0}: #{input}:#{lineno} #{err.message.strip}" exit 1 end end def make_filename(path, suffix) path.sub(/(?:\..*?)?\z/, suffix) end def report_conflict(states) if states.should_report_srconflict? $stderr.puts "#{states.n_srconflicts} shift/reduce conflicts" end if states.rrconflict_exist? $stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts" end end def log_conflict(states) logging('w') {|f| f.puts "ex#{states.grammar.n_expected_srconflicts}" if states.should_report_srconflict? f.puts "sr#{states.n_srconflicts}" end if states.rrconflict_exist? f.puts "rr#{states.n_rrconflicts}" end } end def report_useless(grammar) if grammar.useless_nonterminal_exist? $stderr.puts "#{grammar.n_useless_nonterminals} useless nonterminals" end if grammar.useless_rule_exist? $stderr.puts "#{grammar.n_useless_rules} useless rules" end if grammar.start.useless? $stderr.puts 'fatal: start symbol does not derive any sentence' end end def log_useless(grammar) logging('a') {|f| if grammar.useless_nonterminal_exist? f.puts "un#{grammar.n_useless_nonterminals}" end if grammar.useless_rule_exist? f.puts "ur#{grammar.n_useless_rules}" end } end def logging(mode, &block) File.open("log/#{File.basename(ARGV[0])}", mode, &block) end class RaccProfiler def initialize(really) @really = really @log = [] unless ::Process.respond_to?(:times) # Ruby 1.6 @class = ::Time else @class = ::Process end end def section(name) if @really t1 = @class.times.utime result = yield t2 = @class.times.utime @log.push [name, t2 - t1] result else yield end end def report return unless @really f = $stderr total = cumulative_time() f.puts '--task-----------+--sec------+---%-' @log.each do |name, time| f.printf "%-19s %s %3d%%\n", name, pjust(time,4,4), (time/total*100).to_i end f.puts '-----------------+-----------+-----' f.printf "%-20s%s\n", 'total', pjust(total,4,4) end private def cumulative_time t = @log.inject(0) {|sum, (name, time)| sum + time } t == 0 ? 0.01 : t end def pjust(num, i, j) m = /(\d+)(\.\d+)?/.match(num.to_s) str = m[1].rjust(i) str.concat m[2].ljust(j+1)[0,j+1] if m[2] str end end main PK ]/gems/ruby-lsapi-5.6/ext/lsapi/.sitearchdir.timenu[PK ]Y//(gems/ruby-lsapi-5.6/ext/lsapi/lsapilib.hnu[/* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _LSAPILIB_H_ #define _LSAPILIB_H_ #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif #include "lsapidef.h" #include #include #include struct LSAPI_key_value_pair { char * pKey; char * pValue; int keyLen; int valLen; }; struct lsapi_child_status; #define LSAPI_MAX_RESP_HEADERS 1000 typedef struct lsapi_request { int m_fdListen; int m_fd; long m_lLastActive; long m_lReqBegin; char * m_pReqBuf; int m_reqBufSize; char * m_pRespBuf; char * m_pRespBufEnd; char * m_pRespBufPos; char * m_pRespHeaderBuf; char * m_pRespHeaderBufEnd; char * m_pRespHeaderBufPos; struct lsapi_child_status * child_status; struct iovec * m_pIovec; struct iovec * m_pIovecEnd; struct iovec * m_pIovecCur; struct iovec * m_pIovecToWrite; struct lsapi_packet_header * m_respPktHeaderEnd; struct lsapi_req_header * m_pHeader; struct LSAPI_key_value_pair * m_pEnvList; struct LSAPI_key_value_pair * m_pSpecialEnvList; int m_envListSize; int m_specialEnvListSize; struct lsapi_http_header_index * m_pHeaderIndex; struct lsapi_header_offset * m_pUnknownHeader; char * m_pScriptFile; char * m_pScriptName; char * m_pQueryString; char * m_pHttpHeader; char * m_pRequestMethod; int m_totalLen; int m_reqState; off_t m_reqBodyLen; off_t m_reqBodyRead; int m_bufProcessed; int m_bufRead; struct lsapi_packet_header m_respPktHeader[5]; struct lsapi_resp_header m_respHeader; short m_respHeaderLen[LSAPI_MAX_RESP_HEADERS]; void * m_pAppData; }LSAPI_Request; extern LSAPI_Request g_req; /* return: >0 continue, ==0 stop, -1 failed */ typedef int (*LSAPI_CB_EnvHandler )( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ); int LSAPI_Init(void); void LSAPI_Stop(void); int LSAPI_Is_Listen_r( LSAPI_Request * pReq); int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ); int LSAPI_Accept_r( LSAPI_Request * pReq ); void LSAPI_Reset_r( LSAPI_Request * pReq ); int LSAPI_Finish_r( LSAPI_Request * pReq ); int LSAPI_Release_r( LSAPI_Request * pReq ); char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ); int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ); ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t len ); int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ); int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF ); int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ); ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len ); ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size ); ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len ); int LSAPI_Flush_r( LSAPI_Request * pReq ); int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len ); int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName, const char * pHeaderValue ); int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders, const char * pBody, int bodyLen ); static inline int LSAPI_SetRespStatus_r( LSAPI_Request * pReq, int code ) { if ( !pReq ) return -1; pReq->m_respHeader.m_respInfo.m_status = code; return 0; } static inline int LSAPI_SetAppData_r( LSAPI_Request * pReq, void * data ) { if ( !pReq ) return -1; pReq->m_pAppData = data; return 0; } static inline void * LSAPI_GetAppData_r( LSAPI_Request * pReq ) { if ( !pReq ) return NULL; return pReq->m_pAppData; } static inline char * LSAPI_GetQueryString_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pQueryString; return NULL; } static inline char * LSAPI_GetScriptFileName_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pScriptFile; return NULL; } static inline char * LSAPI_GetScriptName_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pScriptName; return NULL; } static inline char * LSAPI_GetRequestMethod_r( LSAPI_Request * pReq) { if ( pReq ) return pReq->m_pRequestMethod; return NULL; } static inline off_t LSAPI_GetReqBodyLen_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_reqBodyLen; return -1; } static inline off_t LSAPI_GetReqBodyRemain_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_reqBodyLen - pReq->m_reqBodyRead; return -1; } int LSAPI_End_Response_r(LSAPI_Request * pReq); int LSAPI_Is_Listen(void); static inline int LSAPI_Accept( void ) { return LSAPI_Accept_r( &g_req ); } static inline int LSAPI_Finish(void) { return LSAPI_Finish_r( &g_req ); } static inline char * LSAPI_GetHeader( int headerIndex ) { return LSAPI_GetHeader_r( &g_req, headerIndex ); } static inline int LSAPI_ForeachHeader( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachHeader_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachOrgHeader( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachOrgHeader_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachEnv( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachEnv_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachSpecialEnv( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachSpecialEnv_r( &g_req, fn, arg ); } static inline char * LSAPI_GetEnv( const char * name ) { return LSAPI_GetEnv_r( &g_req, name ); } static inline char * LSAPI_GetQueryString(void) { return LSAPI_GetQueryString_r( &g_req ); } static inline char * LSAPI_GetScriptFileName(void) { return LSAPI_GetScriptFileName_r( &g_req ); } static inline char * LSAPI_GetScriptName(void) { return LSAPI_GetScriptName_r( &g_req ); } static inline char * LSAPI_GetRequestMethod(void) { return LSAPI_GetRequestMethod_r( &g_req ); } static inline off_t LSAPI_GetReqBodyLen(void) { return LSAPI_GetReqBodyLen_r( &g_req ); } static inline off_t LSAPI_GetReqBodyRemain(void) { return LSAPI_GetReqBodyRemain_r( &g_req ); } static inline ssize_t LSAPI_ReadReqBody( char * pBuf, size_t len ) { return LSAPI_ReadReqBody_r( &g_req, pBuf, len ); } static inline int LSAPI_ReqBodyGetChar(void) { return LSAPI_ReqBodyGetChar_r( &g_req ); } static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF ) { return LSAPI_ReqBodyGetLine_r( &g_req, pBuf, len, getLF ); } static inline int LSAPI_FinalizeRespHeaders(void) { return LSAPI_FinalizeRespHeaders_r( &g_req ); } static inline ssize_t LSAPI_Write( const char * pBuf, ssize_t len ) { return LSAPI_Write_r( &g_req, pBuf, len ); } static inline ssize_t LSAPI_sendfile( int fdIn, off_t* off, size_t size ) { return LSAPI_sendfile_r(&g_req, fdIn, off, size ); } static inline ssize_t LSAPI_Write_Stderr( const char * pBuf, ssize_t len ) { return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); } static inline int LSAPI_Flush(void) { return LSAPI_Flush_r( &g_req ); } static inline int LSAPI_AppendRespHeader( char * pBuf, int len ) { return LSAPI_AppendRespHeader_r( &g_req, pBuf, len ); } static inline int LSAPI_SetRespStatus( int code ) { return LSAPI_SetRespStatus_r( &g_req, code ); } static inline int LSAPI_ErrResponse( int code, const char ** pRespHeaders, const char * pBody, int bodyLen ) { return LSAPI_ErrResponse_r( &g_req, code, pRespHeaders, pBody, bodyLen ); } static inline int LSAPI_End_Response(void) { return LSAPI_End_Response_r( &g_req ); } int LSAPI_IsRunning(void); int LSAPI_CreateListenSock( const char * pBind, int backlog ); typedef int (*fn_select_t)( int, fd_set *, fd_set *, fd_set *, struct timeval * ); int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ); void LSAPI_Set_Server_fd( int fd ); int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ); void LSAPI_No_Check_ppid(void); void LSAPI_Set_Max_Reqs( int reqs ); void LSAPI_Set_Max_Idle( int secs ); void LSAPI_Set_Max_Children( int maxChildren ); void LSAPI_Set_Max_Idle_Children( int maxIdleChld ); void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ); void LSAPI_Set_Max_Process_Time( int secs ); int LSAPI_Init_Env_Parameters( fn_select_t fp ); void LSAPI_Set_Slow_Req_Msecs( int msecs ); int LSAPI_Get_Slow_Req_Msecs(void); int LSAPI_is_suEXEC_Daemon(void); int LSAPI_Set_Restored_Parent_Pid(int pid); typedef void (*LSAPI_On_Timer_pf)(int *forked_child_pid); void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf); int LSAPI_Inc_Req_Processed(int cnt); int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq); int LSAPI_Postfork_Child(LSAPI_Request * pReq); int LSAPI_Postfork_Parent(LSAPI_Request * pReq); #define LSAPI_LOG_LEVEL_BITS 0xff #define LSAPI_LOG_FLAG_NONE 0 #define LSAPI_LOG_FLAG_DEBUG 1 #define LSAPI_LOG_FLAG_INFO 2 #define LSAPI_LOG_FLAG_NOTICE 3 #define LSAPI_LOG_FLAG_WARN 4 #define LSAPI_LOG_FLAG_ERROR 5 #define LSAPI_LOG_FLAG_CRIT 6 #define LSAPI_LOG_FLAG_FATAL 7 #define LSAPI_LOG_TIMESTAMP_BITS (0xff00) #define LSAPI_LOG_TIMESTAMP_FULL (0x100) #define LSAPI_LOG_TIMESTAMP_HMS (0x200) #define LSAPI_LOG_TIMESTAMP_STDERR (0x400) #define LSAPI_LOG_PID (0x10000) void LSAPI_Log(int flag, const char * fmt, ...) #if __GNUC__ __attribute__((format(printf, 2, 3))) #endif ; #if defined (c_plusplus) || defined (__cplusplus) } #endif #endif PK ]7Zw(gems/ruby-lsapi-5.6/ext/lsapi/extconf.rbnu[require 'mkmf' dir_config( 'lsapi' ) if ( have_library( "socket" )) have_library( "nsl" ) end if RUBY_VERSION =~ /1.9/ then $CPPFLAGS += " -DRUBY_19" end if RUBY_VERSION =~ /2/ then $CPPFLAGS += " -DRUBY_2" end create_makefile( "lsapi" ) PK ]dCR[R[&gems/ruby-lsapi-5.6/ext/lsapi/lsruby.cnu[ #include "ruby.h" #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 #include "util.h" #else #include #include #endif #include "lsapilib.h" #include #include #include #include #include #include #include #include #include #ifndef RUBY_API_VERSION_CODE #define RUBY_API_VERSION_CODE (RUBY_API_VERSION_MAJOR*10000+RUBY_API_VERSION_MINOR*100+RUBY_API_VERSION_TEENY) #endif /* RUBY_EXTERN VALUE ruby_errinfo; */ RUBY_EXTERN VALUE rb_stdin; RUBY_EXTERN VALUE rb_stdout; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 RUBY_EXTERN VALUE rb_defout; #endif static VALUE orig_stdin; static VALUE orig_stdout; static VALUE orig_stderr; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 static VALUE orig_defout; #endif static VALUE orig_env; static VALUE env_copy; static VALUE lsapi_env; static int MAX_BODYBUF_LENGTH = (10 * 1024 * 1024); #if RUBY_API_VERSION_CODE >= 20700 # if defined rb_tainted_str_new # undef rb_tainted_str_new # endif # define rb_tainted_str_new(p,l) rb_str_new((p),(l)) #endif /* static VALUE lsapi_objrefs; */ typedef struct lsapi_data { LSAPI_Request * req; VALUE env; ssize_t (* fn_write)( LSAPI_Request *, const char * , size_t ); }lsapi_data; static VALUE cLSAPI; static VALUE s_req = Qnil; static lsapi_data * s_req_data; static VALUE s_req_stderr = Qnil; static lsapi_data * s_stderr_data; static pid_t s_pid = 0; typedef struct lsapi_body { char *bodyBuf; //we put small one into memory, otherwise, into a memory mapping file, and we still use the bodyBuf to access this mapping int bodyLen; //expected length got form content-length int bodyCurrentLen; //current length by read() readBodyToReqBuf int curPos; }lsapi_body; static lsapi_body s_body; static char sTempFile[1024] = {0}; /* * static void lsapi_ruby_setenv(const char *name, const char *value) * { * if (!name) return; * * if (value && *value) * ruby_setenv(name, value); * else * ruby_unsetenv(name); } * * */ static void lsapi_mark( lsapi_data * data ) { rb_gc_mark( data->env ); } /* * static void lsapi_free_data( lsapi_data * data ) * { * free( data ); } * * */ static int add_env_rails( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { char * p; int len; /* Fixup some environment variables for rails */ switch( *pKey ) { case 'Q': if ( strcmp( pKey, "QUERY_STRING" ) == 0 ) { if ( !*pValue ) return 1; } break; case 'R': if (( *(pKey+8) == 'U' )&&( strcmp( pKey, "REQUEST_URI" ) == 0 )) { p = strchr( pValue, '?' ); if ( p ) { len = valLen - ( p - pValue ) - 1; /* * valLen = p - pValue; *p++ = 0; */ } else { p = (char *)pValue + valLen; len = 0; } rb_hash_aset( lsapi_env,rb_tainted_str_new("PATH_INFO", 9), rb_tainted_str_new(pValue, p - pValue)); rb_hash_aset( lsapi_env,rb_tainted_str_new("REQUEST_PATH", 12), rb_tainted_str_new(pValue, p - pValue)); if ( *p == '?' ) ++p; rb_hash_aset( lsapi_env,rb_tainted_str_new("QUERY_STRING", 12), rb_tainted_str_new(p, len)); } break; case 'S': if ( strcmp( pKey, "SCRIPT_NAME" ) == 0 ) { pValue = "/"; valLen = 1; } break; case 'P': if ( strcmp( pKey, "PATH_INFO" ) == 0 ) return 1; default: break; } /* lsapi_ruby_setenv(pKey, pValue ); */ rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen), rb_tainted_str_new(pValue, valLen)); return 1; } static int add_env_no_fix( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen), rb_tainted_str_new(pValue, valLen)); return 1; } typedef int (*fn_add_env)( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ); fn_add_env s_fn_add_env = add_env_no_fix; static void clear_env() { /* rb_funcall( lsapi_env, rb_intern( "clear" ), 0 ); */ rb_funcall( lsapi_env, rb_intern( "replace" ), 1, env_copy ); } static void setup_cgi_env( lsapi_data * data ) { clear_env(); LSAPI_ForeachHeader_r( data->req, s_fn_add_env, data ); LSAPI_ForeachEnv_r( data->req, s_fn_add_env, data ); } static VALUE lsapi_s_accept( VALUE self ) { int pid; if ( LSAPI_Prefork_Accept_r( &g_req ) == -1 ) return Qnil; else { if (s_body.bodyBuf != NULL) free (s_body.bodyBuf); s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; pid = getpid(); if ( pid != s_pid ) { s_pid = pid; rb_funcall( Qnil, rb_intern( "srand" ), 0 ); } setup_cgi_env( s_req_data ); return s_req; } } static VALUE lsapi_s_accept_new_conn(VALUE self) { if (LSAPI_Accept_Before_Fork(&g_req) == -1 ) return Qnil; else return s_req; } static VALUE lsapi_s_postfork_child(VALUE self) { LSAPI_Postfork_Child(&g_req); return s_req; } static VALUE lsapi_s_postfork_parent(VALUE self) { LSAPI_Postfork_Parent(&g_req); return s_req; } /* * static int chdir_file( const char * pFile ) * { * char * p = strrchr( pFile, '/' ); * int ret; * if ( !p ) * return -1; *p = 0; ret = chdir( pFile ); *p = '/'; return ret; } */ static VALUE lsapi_eval_string_wrap(VALUE self, VALUE str) { #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4) { Check_Type(str, T_STRING); } else #endif { SafeStringValue(str); } return rb_eval_string_wrap(StringValuePtr(str), NULL); } static VALUE lsapi_process( VALUE self ) { /* lsapi_data *data; const char * pScriptPath; Data_Get_Struct(self,lsapi_data, data); pScriptPath = LSAPI_GetScriptFileName_r( data->req ); */ /* * if ( chdir_file( pScriptPath ) == -1 ) * { * lsapi_send_error( 404 ); * } * rb_load_file( pScriptPath ); */ return Qnil; } static VALUE lsapi_putc(VALUE self, VALUE c) { char ch = NUM2CHR(c); lsapi_data *data; Data_Get_Struct(self,lsapi_data, data); if ( (*data->fn_write)( data->req, &ch, 1 ) == 1 ) return c; else return INT2NUM( EOF ); } static VALUE lsapi_write( VALUE self, VALUE str ) { lsapi_data *data; int len; Data_Get_Struct(self,lsapi_data, data); /* len = LSAPI_Write_r( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); */ if (TYPE(str) != T_STRING) str = rb_obj_as_string(str); len = (*data->fn_write)( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); return INT2NUM( len ); } static VALUE lsapi_print( int argc, VALUE *argv, VALUE out ) { int i; VALUE line; /* if no argument given, print `$_' */ if (argc == 0) { argc = 1; line = rb_lastline_get(); argv = &line; } for (i = 0; i0) { lsapi_write(out, rb_output_fs); } switch (TYPE(argv[i])) { case T_NIL: lsapi_write(out, rb_str_new2("nil")); break; default: lsapi_write(out, argv[i]); break; } } if (!NIL_P(rb_output_rs)) { lsapi_write(out, rb_output_rs); } return Qnil; } static VALUE lsapi_printf(int argc, VALUE *argv, VALUE out) { lsapi_write(out, rb_f_sprintf(argc, argv)); return Qnil; } static VALUE lsapi_puts _((int, VALUE*, VALUE)); #if RUBY_API_VERSION_CODE >= 10900 static VALUE lsapi_puts_ary(VALUE ary, VALUE out, int recur ) { VALUE tmp; long i; if (recur) { tmp = rb_str_new2("[...]"); rb_io_puts(1, &tmp, out); return Qnil; } for (i=0; i= 10900 rb_exec_recursive(lsapi_puts_ary, argv[i], out); #else rb_protect_inspect(lsapi_puts_ary, argv[i], out); #endif continue; default: line = argv[i]; break; } line = rb_obj_as_string(line); lsapi_write(out, line); if (*( RSTRING_PTR(line) + RSTRING_LEN(line) - 1 ) != '\n') { lsapi_write(out, rb_default_rs); } } return Qnil; } static VALUE lsapi_addstr(VALUE out, VALUE str) { lsapi_write(out, str); return out; } static VALUE lsapi_flush( VALUE self ) { /* * lsapi_data *data; * Data_Get_Struct(self,lsapi_data, data); */ LSAPI_Flush_r( &g_req ); return Qnil; } static VALUE lsapi_getc( VALUE self ) { int ch; /* * lsapi_data *data; * Data_Get_Struct(self,lsapi_data, data); */ #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif ch = LSAPI_ReqBodyGetChar_r( &g_req ); if ( ch == EOF ) return Qnil; return INT2NUM( ch ); } static inline int isBodyWriteToFile() { return ((s_body.bodyLen >= MAX_BODYBUF_LENGTH)? (1): (0)); } //create a temp file and open it, if failed, fd = -1 static inline int createTempFile() { int fd = -1; char *sfn = strdup(sTempFile); if ((fd = mkstemp(sfn)) == -1) { fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); } else unlink(sfn); free(sfn); return fd; } //return 1 if error occured! //if already created, always OK (0) static int createBodyBuf() { int fd = -1; if (s_body.bodyLen == -1) { s_body.bodyLen = LSAPI_GetReqBodyLen_r(&g_req); //Error if get a zeor length, should not happen if (s_body.bodyLen < 0) { //Wrong bode length will be treated as 0 s_body.bodyLen = 0; } if (s_body.bodyLen > 0) { if (isBodyWriteToFile()) { //create file mapping fd = createTempFile(); if (fd == -1) { return 1; } if (ftruncate(fd, s_body.bodyLen) == 0) { perror("ftruncate() failed. \n"); close(fd); return 1; } s_body.bodyBuf = mmap(NULL, s_body.bodyLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (s_body.bodyBuf == MAP_FAILED) { perror("File mapping failed. \n"); close(fd); return 1; } close(fd); //close since needn't it anymore } else { s_body.bodyBuf = (char *)calloc(s_body.bodyLen, sizeof(char)); if (s_body.bodyBuf == NULL) { perror("Memory calloc error"); return 1; } } } } return 0; } static inline int isAllBodyRead() { return (s_body.bodyCurrentLen < s_body.bodyLen)? 0 : 1; } static inline int isEofBodyBuf() { return (s_body.curPos < s_body.bodyLen) ? 0 : 1; } //try to read length as times pagesize (such as 8KB * N) static int readBodyBuf(const int needRead) { const int blockSize = 8192; char *buff = s_body.bodyBuf + s_body.bodyCurrentLen; int nRead; int readMore = (needRead + blockSize -1) / blockSize * blockSize; int remain = LSAPI_GetReqBodyRemain_r( &g_req ); //Only when not enough left, needReadChange will be changed!!! if (remain < readMore) readMore = remain; if ( readMore <= 0 ) return 0; nRead = LSAPI_ReadReqBody_r(&g_req, buff, readMore); if ( nRead > 0 ) s_body.bodyCurrentLen += nRead; return nRead; } static VALUE lsapi_gets( VALUE self ) { VALUE str; const int blkSize = 4096; int n; char *p = NULL; #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif if (createBodyBuf() == 1) { return Qnil; } //comment: while((p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1)) == NULL) { if (isAllBodyRead() == 1) break; //read one page and check, then reply readBodyBuf(blkSize); } p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1); if (p != NULL) n = p - s_body.bodyBuf - s_body.curPos + 1; else n = s_body.bodyCurrentLen - s_body.curPos; str = rb_str_buf_new( n ); #if RUBY_API_VERSION_CODE < 20700 OBJ_TAINT(str); #endif if (n > 0) { rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n ); s_body.curPos += n; } return str; } static VALUE lsapi_read(int argc, VALUE *argv, VALUE self) { VALUE str; int n; int needRead; int nRead; #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif if (createBodyBuf() == 1) { return Qnil; } //we need to consider these 4 cases: //1, need all data since argc == 0, we may have all data 2, or not //3, need a length of data (argv >= 1), we may have enough data already read, 4, or not if (argc == 0) n = s_body.bodyLen - s_body.curPos; else { n = NUM2INT(argv[0]); //request that length from currentpos if (n < 0) return Qnil; if (n > s_body.bodyLen - s_body.curPos) n = s_body.bodyLen - s_body.curPos; } needRead = s_body.curPos + n - s_body.bodyCurrentLen; if (needRead < 0) needRead = 0; str = rb_str_buf_new( n ); #if RUBY_API_VERSION_CODE < 20700 OBJ_TAINT(str); #endif if (n == 0) return str; //copy already have part first if (n - needRead != 0) { rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n - needRead); s_body.curPos += (n - needRead); } if (needRead > 0) { //try to read needRead, but may be less (changed) when read the end of the data nRead = readBodyBuf(needRead); if (nRead > 0) { n = ((nRead < needRead) ? nRead : needRead); rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n ); s_body.curPos += n; } } return str; } static VALUE lsapi_rewind(VALUE self) { s_body.curPos = 0; return self; } static VALUE lsapi_each(VALUE self) { VALUE str; lsapi_rewind(self); while(isEofBodyBuf() != 1) { str = lsapi_gets(self); rb_yield(str); } return self; } static VALUE lsapi_eof(VALUE self) { return (LSAPI_GetReqBodyRemain_r( &g_req ) <= 0) ? Qtrue : Qfalse; } static VALUE lsapi_binmode(VALUE self) { return self; } static VALUE lsapi_isatty(VALUE self) { return Qfalse; } static VALUE lsapi_sync(VALUE self) { return Qfalse; } static VALUE lsapi_setsync(VALUE self,VALUE sync) { return Qfalse; } static VALUE lsapi_close(VALUE self) { LSAPI_Flush_r( &g_req ); if (isBodyWriteToFile()) { //msync(s_body.bodyBuf, s_body.bodyLen, MS_SYNC); //sleep(5); munmap(s_body.bodyBuf, s_body.bodyLen); } else free(s_body.bodyBuf); s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; //Should the temp be deleted here?! return Qnil; } static VALUE lsapi_reopen( int argc, VALUE *argv, VALUE self) { VALUE orig_verbose; if ( self == s_req_stderr ) { /* constant silence hack */ orig_verbose = (VALUE)ruby_verbose; ruby_verbose = Qnil; rb_define_global_const("STDERR", orig_stderr); ruby_verbose = (VALUE)orig_verbose; return rb_funcall2( orig_stderr, rb_intern( "reopen" ), argc, argv ); } return self; } static void readMaxBodyBufLength() { int n; const char *p = getenv( "LSAPI_MAX_BODYBUF_LENGTH" ); if ( p ) { n = atoi( p ); if (n > 0) { if (strstr(p, "M") || strstr(p, "m")) MAX_BODYBUF_LENGTH = n * 1024 * 1024; else if (strstr(p, "K") || strstr(p, "k")) MAX_BODYBUF_LENGTH = n * 1024; else MAX_BODYBUF_LENGTH = n; } } } static void readTempFileTemplate() { const char *p = getenv( "LSAPI_TEMPFILE" ); if (p == NULL || strlen(p) > 1024 - 7) p = "/tmp/lsapi.XXXXXX"; strcpy(sTempFile, p); if (strlen(p) <= 6 || strcmp(p + (strlen(p) - 6), "XXXXXX") != 0) strcat(sTempFile, ".XXXXXX"); } static void initBodyBuf() { s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; } void Init_lsapi() { VALUE orig_verbose; char * p; int prefork = 0; LSAPI_Init(); initBodyBuf(); readMaxBodyBufLength(); readTempFileTemplate(); p = getenv("LSAPI_CHILDREN"); if (p && atoi(p) > 1) prefork = 1; #ifdef rb_thread_select LSAPI_Init_Env_Parameters( rb_thread_select ); #else LSAPI_Init_Env_Parameters( select ); #endif s_pid = getpid(); p = getenv( "RACK_ROOT" ); if ( p ) { if ( chdir( p ) == -1 ) perror( "chdir()" ); } if ( p || getenv( "RACK_ENV" ) ) s_fn_add_env = add_env_rails; orig_stdin = rb_stdin; orig_stdout = rb_stdout; orig_stderr = rb_stderr; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 orig_defout = rb_defout; #endif orig_env = rb_const_get( rb_cObject, rb_intern("ENV") ); env_copy = rb_funcall( orig_env, rb_intern( "to_hash" ), 0 ); /* tell the garbage collector it is a global variable, do not recycle it. */ rb_global_variable(&env_copy); rb_hash_aset( env_copy,rb_tainted_str_new("GATEWAY_Irewindable_input.rbNTERFACE", 17), rb_tainted_str_new("CGI/1.2", 7)); rb_define_global_function("eval_string_wrap", lsapi_eval_string_wrap, 1); cLSAPI = rb_define_class("LSAPI", rb_cObject); rb_define_singleton_method(cLSAPI, "accept", lsapi_s_accept, 0); if (prefork) { rb_define_singleton_method(cLSAPI, "accept_new_connection", lsapi_s_accept_new_conn, 0); rb_define_singleton_method(cLSAPI, "postfork_child", lsapi_s_postfork_child, 0); rb_define_singleton_method(cLSAPI, "postfork_parent", lsapi_s_postfork_parent, 0); } rb_define_method(cLSAPI, "process", lsapi_process, 0 ); /* rb_define_method(cLSAPI, "initialize", lsapi_initialize, 0); */ rb_define_method(cLSAPI, "putc", lsapi_putc, 1); rb_define_method(cLSAPI, "write", lsapi_write, 1); rb_define_method(cLSAPI, "print", lsapi_print, -1); rb_define_method(cLSAPI, "printf", lsapi_printf, -1); rb_define_method(cLSAPI, "puts", lsapi_puts, -1); rb_define_method(cLSAPI, "<<", lsapi_addstr, 1); rb_define_method(cLSAPI, "flush", lsapi_flush, 0); rb_define_method(cLSAPI, "getc", lsapi_getc, 0); /* rb_define_method(cLSAPI, "ungetc", lsapi_ungetc, 1); */ rb_define_method(cLSAPI, "gets", lsapi_gets, 0); //TEST: adding readline function to make irb happy? /*rb_define_method(cLSAPI, "readline", lsapi_gets, 0); */ rb_define_method(cLSAPI, "read", lsapi_read, -1); rb_define_method(cLSAPI, "rewind", lsapi_rewind, 0); rb_define_method(cLSAPI, "each", lsapi_each, 0); rb_define_method(cLSAPI, "eof", lsapi_eof, 0); rb_define_method(cLSAPI, "eof?", lsapi_eof, 0); rb_define_method(cLSAPI, "close", lsapi_close, 0); /* rb_define_method(cLSAPI, "closed?", lsapi_closed, 0); */ rb_define_method(cLSAPI, "binmode", lsapi_binmode, 0); rb_define_method(cLSAPI, "isatty", lsapi_isatty, 0); rb_define_method(cLSAPI, "tty?", lsapi_isatty, 0); rb_define_method(cLSAPI, "sync", lsapi_sync, 0); rb_define_method(cLSAPI, "sync=", lsapi_setsync, 1); rb_define_method(cLSAPI, "reopen", lsapi_reopen, -1 ); s_req = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_req_data ); s_req_data->req = &g_req; s_req_data->fn_write = LSAPI_Write_r; rb_stdin = rb_stdout = s_req; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 rb_defout = s_req; #endif rb_global_variable(&s_req ); s_req_stderr = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_stderr_data ); s_stderr_data->req = &g_req; s_stderr_data->fn_write = LSAPI_Write_Stderr_r; rb_stderr = s_req_stderr; rb_global_variable(&s_req_stderr ); /* constant silence hack */ orig_verbose = (VALUE)ruby_verbose; ruby_verbose = Qnil; lsapi_env = rb_hash_new(); clear_env(); /* redefine ENV using a hash table, should be faster than char **environment */ rb_define_global_const("ENV", lsapi_env); rb_define_global_const("STDERR", rb_stderr); ruby_verbose = (VALUE)orig_verbose; return; } PK ]W q,,(gems/ruby-lsapi-5.6/ext/lsapi/lsapidef.hnu[/* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _LSAPIDEF_H_ #define _LSAPIDEF_H_ #include #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif enum { H_ACCEPT = 0, H_ACC_CHARSET, H_ACC_ENCODING, H_ACC_LANG, H_AUTHORIZATION, H_CONNECTION, H_CONTENT_TYPE, H_CONTENT_LENGTH, H_COOKIE, H_COOKIE2, H_HOST, H_PRAGMA, H_REFERER, H_USERAGENT, H_CACHE_CTRL, H_IF_MODIFIED_SINCE, H_IF_MATCH, H_IF_NO_MATCH, H_IF_RANGE, H_IF_UNMOD_SINCE, H_KEEP_ALIVE, H_RANGE, H_X_FORWARDED_FOR, H_VIA, H_TRANSFER_ENCODING }; #define LSAPI_SOCK_FILENO 0 #define LSAPI_VERSION_B0 'L' #define LSAPI_VERSION_B1 'S' /* Values for m_flag in lsapi_packet_header */ #define LSAPI_ENDIAN_LITTLE 0 #define LSAPI_ENDIAN_BIG 1 #define LSAPI_ENDIAN_BIT 1 #if defined(__i386__)||defined( __x86_64 )||defined( __x86_64__ ) #define LSAPI_ENDIAN LSAPI_ENDIAN_LITTLE #else #define LSAPI_ENDIAN LSAPI_ENDIAN_BIG #endif /* Values for m_type in lsapi_packet_header */ #define LSAPI_BEGIN_REQUEST 1 #define LSAPI_ABORT_REQUEST 2 #define LSAPI_RESP_HEADER 3 #define LSAPI_RESP_STREAM 4 #define LSAPI_RESP_END 5 #define LSAPI_STDERR_STREAM 6 #define LSAPI_REQ_RECEIVED 7 #define LSAPI_CONN_CLOSE 8 #define LSAPI_INTERNAL_ERROR 9 #define LSAPI_MAX_HEADER_LEN 65535 #define LSAPI_MAX_DATA_PACKET_LEN 16384 #define LSAPI_RESP_HTTP_HEADER_MAX 32768 #define LSAPI_PACKET_HEADER_LEN 8 struct lsapi_packet_header { char m_versionB0; /* LSAPI protocol version */ char m_versionB1; char m_type; char m_flag; union { int32_t m_iLen; /* include this header */ char m_bytes[4]; }m_packetLen; }; /* LSAPI request header packet 1. struct lsapi_req_header 2. struct lsapi_http_header_index 3. lsapi_header_offset * unknownHeaders 4. org http request header 5. request body if available */ struct lsapi_req_header { struct lsapi_packet_header m_pktHeader; int32_t m_httpHeaderLen; int32_t m_reqBodyLen; int32_t m_scriptFileOff; /* path to the script file. */ int32_t m_scriptNameOff; /* decrypted URI, without pathinfo, */ int32_t m_queryStringOff; /* Query string inside env */ int32_t m_requestMethodOff; int32_t m_cntUnknownHeaders; int32_t m_cntEnv; int32_t m_cntSpecialEnv; } ; struct lsapi_http_header_index { uint16_t m_headerLen[H_TRANSFER_ENCODING+1]; int32_t m_headerOff[H_TRANSFER_ENCODING+1]; } ; struct lsapi_header_offset { int32_t nameOff; int32_t nameLen; int32_t valueOff; int32_t valueLen; } ; struct lsapi_resp_info { int32_t m_cntHeaders; int32_t m_status; }; struct lsapi_resp_header { struct lsapi_packet_header m_pktHeader; struct lsapi_resp_info m_respInfo; }; #if defined (c_plusplus) || defined (__cplusplus) } #endif #endif PK ]ւg/(((gems/ruby-lsapi-5.6/ext/lsapi/lsapilib.onu[ELF>@@=< 02/3.4-5ff.ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=DÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH=1tIH=HcH5HH[ÉD1?H=HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHtHHtHHtH{@Ht1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDHu48u uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=HcB$HH@H,H9rZf.HH9vGH3LuHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L=L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$)H8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L LfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH L$DIH Ic LEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcUff.AWAVAUATUSHXHt$ HT$dH%(H$H1HIH1E1L-HL%HHHcHcT4t/HHAAtIL{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eHthILM)MUI9t HtDL+t$HL[]A\A]A^A_DM@@M)(IHt$HLHk8f.HAVLAUIATIUSHu\H߉AD${LǃLSHu0{L[L]A\A]A^[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIHLc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAMt$PHLIFID$PA:I|$PMD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHAI\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1HL$Aߺu#DHuDo߻D HDeOAkDH}An}NHtff.USHdH%(H$1HHu/HH$dH3%(uHĘ[]@1H=tAUATA'USH'DNuDH@AHHHHtH-ƉljUDk HDcEufH H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0ALJt` A1LHcIHIGAo IuID%D-B(AA1IcH4IILI 9HqH= IJDB(9xHqH= XIJB($AD$IKAzHL$;MbfoLt$ LAoL$AT$Ml$)$ LLHL$LHLLH$ID$H$I3L$H1H D$$Dl$EDDl$H=IHIDMH=t"LDLŃP|$Et$A9uHt$DŃ5$A?D5t AH5LHtHHf)#AH51H@H51LH 1HIH51H51D%DD$H=IHtZEW7E1111H=H51E|$M2;|$E1H5LuI}Ń1H5LKfD=-ED$AIFH51HH)H5H11H5L 1H5LA#LH H1H5Laff.AVAUATUSHdH%(H$1D$ HH ;1Ll$Ld$Lt$ Hkl{ul;LLD$CHHt@HHt{1f|$=u|H4tH舴Hd1H$dH3 %(u}HĠ[]A\A]A^D {H5Hfы{LA;ff.AWAVAUATUSHD=dH%(H$1ExHH-H};DH-Ht 1HEDEH$L|$PDcA:E1AfD EDEtHHt @fLH1HIcDHD$PHD$XA ?)ѺHH D9#11A|$MHD9#HHt @D9#AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$LH$LHHD$@AHLDŽ$hH$H$LHHD$0PH$LHHD$8+H$`L HHD$(H$ LHHD$HADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%EHHt H=1IL9t<1ձL5EDu EME1VHLH1HHc}}LD$LHD$PHD$X ?)ѺH1H T`1 8Ht$(1ҿ x=_5tHHt @f,D9# DCHHt@HHtDc1DN ={H5HHHt*HHB(@HHt@HH@8B-DAD9M==H HtDHHt A9HHtD҉T$$DE ~:E~5T$$AAAuDE UM D9vHAHtDH51D$0 H=T$fD}蠩C1mH|$IH|$HT$Ht$161E Mt AMgMg{E1CHt$1ҿH=f;>fDD$$0d T$$WH=T$T$fDD#AfDRDEBHH29{H5H{wH=H=0MAH… H{HH=Ht$1ҿHL=HHHtH11L=AGHHt{1蝦D-EuHHt!E9~;t Ht$@1ҿL$Ht$01ҿHt$H1ҿHt$81ҿHt$(1ҿ kHLSH$$L$H=%,H=QHHt*fC1CD$CCT$HC(HC fD=ff.@H,LSLSLSLS GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realignAnonymous mmap() failedlocalhost%02d:%02d:%02d [%s] [UID:%d][%d] %.*syesnosystem()%s, errno: %d (%s) /dev/nulllibpthread.sopthread_atforkHTTP_[UID:%d][%d] %s:%s: %s LSAPI: jail() failure./etc/Can't set signalsaccept() failedLSAPI_STDERR_LOGPHP_LSAPI_MAX_REQUESTSLSAPI_MAX_REQSLSAPI_KEEP_LISTENLSAPI_AVOID_FORKLSAPI_ACCEPT_NOTIFYLSAPI_SLOW_REQ_MSECSLSAPI_ALLOW_CORE_DUMPLSAPI_MAX_IDLEPHP_LSAPI_CHILDRENLSAPI_CHILDRENLSAPI_EXTRA_CHILDRENLSAPI_MAX_IDLE_CHILDRENLSAPI_PGRP_MAX_IDLELSAPI_MAX_PROCESS_TIMELSAPI_PPID_NO_CHECKLSAPI_MAX_BUSY_WORKERLSAPI_DUMP_DEBUG_INFOnobodyLSAPI_DEFAULT_UIDLSAPI_DEFAULT_GIDLSAPI_SECRETLSAPI_LVE_ENABLELVE_ENABLEliblve.so.0lve_is_availablelve_instance_initlve_destroylve_enterlve_leavejailLSAPI_PHP_LSAPI_PHPRC=packetLen < 0 packetLen > %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGINFONOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveRangeX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

    Resource Limit Is Reached

    The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
              ^ d/4-//// %-/Ga '9 (_intG )@/G G @ @ G @ G     G  `@ A C $E (J 0NL8PX@[+H\+X]+hj$xp4G- - N1 ooGGXa&& E18: ;1?A B C1GOI JK1 OQ RS TU1ac Ed EC^&e&g1 Y[ E]ah 1l5no 1tfv Ew x@ Cp3&5&<&Db_rtL&VO&i&p&y5G1$ +& ( * 0 { f|HCIRT Cv&"7&$ R  E+v"&T.1 4 c G@4HH//-Gldy"m - 911; CmGFy<d(eGfI@I@IEIE"1 36 |7 |8 |9 | : |(; |0< |8= |@@ |HA |PB |XD `F hHpItJ xM9NNO Q Y [ \ ] ^ E_ `b g+J  G J J  G4'  < ' ' '   T h4I ' T X@!      !!"! ! ! ""F " E" #!X@$  i0%9"# # # 4  G  "&4 &6 &7  < |"0'1 '3 |'4 |'6 '7 '8 |'9 | ': |(jtm8(, ( ( ( (  ( (((( ( ((0|< G'), ') ')'), ') ')H*! B@,H      !"#$%&'()*+,-./0123456789:;<<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'-$|'-2 '-7 '-; .U.m.4/"/*/!B@/) !)./23\^bgl00/{C/&/ &/ -&/ =-G=GMG"/h/ 4M'/h'/h"// ///-GK/,/ ///M/K0050708090: 0; F 0<0= | 0>( ,"n11 1 GkB@2,     C2q&2s9&2t"2k2m 2n 2o 2p 2u",22 2 92 9 2 92 92 92 92 9 2 9$2 9("222 4G9G"22 92 92 92 9 "2G2 92 9"2o2"2"/" / 1 | 2 | 3  4 k : < = ? @ B| C  E|( F|0 G|8 I|@ J|H K|P L!VX O ` P h Q p R x T'\ V'b W'h X'h Y' Z' \'n ]'t _| `| a| b| c| d e f g h iL k'zL m'G(L n'8L oE "0pVr s uhvwxz{ |(vGa=G q' s w9   EM X9    $EM x7=RH H"XOYbufP =Q YinRG-G?]!NB@j~            9     H  H  H  |      l "G * ^GN G t N  t G M>CQ L L @  J l E m  9    9#!  9 9 #! @! !9Z! #!  g!F!9! ! |'  ! m!        # # *"G&%" K "  K@ V#          ( 0 8M " z# V# @      #  -     H! x$2cnt!U$2pid'U  : YO%2buf'#!U#in>74r"4TsUs]4U T 4UsT  [5m4UsT 5UsT ,5UsT Q5UsT v5UsT 5U ʳY5U YU ;W6%;O";#;Y2x6k%2w~}׳6U2T~QwY7U 9Y,7U YK7U Yj7U Y7U Y7U ;Y7U Y7U <ytY,8U YK8U G<Yw8U ;Y8U ;Y8U <Y8U Q;Y'9U YF9U ^9Us<Y9U Y9U Q;{X9TvQ | $0.MX] ":!p], _ ":3:=GE `: E- G % :!p%) %2| %= ' :len( end) |:=G ;i pw!)p7 2;env ! )del! D TD ( ;*$U(;**U(<*'U(G<*&U(v<*$U(<*"U( <*U( =   H  -5+fd ret    ~ Et;=   5 >__d U| $ &585> 8! O EOOOOw PyPz%P{2P|?P~LPYPfPsPPPPtPtPuPvNPP p?P>QT?Q?U  y @y!y 9C@7@Ä*UvT|Q@T7@U}C AUAT|Qt7"AU}CGAU?T|QtClAU2T|QtCAU:T|QtCAU3T|Qt3AU OAU0KQ BU|[%BUV3KBT}Q0R0XtC|BU:TtQ0BU T BU [WVBUu7BUthCUtTAtDCU0TtQtLtCU2TtQCU  CU CU  DU 8DU tiDU2TtQ03DU0T0Q DT0LCDUATtQ0CEU?TtQ0C8EU3TtQ0C\EU2TtQ0CEU:TtQ0EU QU  ?yj"FQy-?y+Qy+y #/ y+y #  yy*T Q8ly 9G~y+y yy*T Q8zqQGUsOhGU03GU|TvQ0R0X[WGU|GU|T0Q HU LGHUs?Ãsx_HUsHUs?ÃsqpHUsOHU0M M M .5+ O 4 P 4Q }R E} S retT  V z#EactX ~;I   5I__d ;1J  #JU T7VJU|CJUATvQ 7JU|CJU?TvQ CJU2TvQ CKU:TvQ C@KU3TvQ 3[KU OrKU0KQKU}[KUV3KT|Q0R0XC LUAT Q0C2LU?T Q0C[LU3T Q0CLU2T Q0CLU:T Q0LU T LU [W )MU HMU gMU VMUu> @N > +5+5N C 4OU0L pO  *5+  y6 GOy!y@ 7NÄ 9O*UsTwQ@3OU0T0Q OT0LQ: Q : @z# ; 95+act=  =  = % = / >  >  ?  @ retA pidB  C 4 D 4 E  F E H  I FP   FQ__d )  D/ 1T+ : 6R  ,        %RU T   F lY  *  5 =X~ret pfd YSYUUTsZqYUsTv88 Z 8 ' 8 @ : Zp; | < |res=  = , > ? ZG -[  6[  Gret fd  D  ZT1Q0ZUsT2Q1[UsT1Q2RDX4?[UsTvQ} ][UsT|L,[Uv 8 [  /5+  B!len LF[ch )   ^  05+  C  ,   len ;\ch ;\ch 57]  U|  x]TTQ~  ]T}Qv]UvU} t^* 25+U- Ä F^  05+#fn !#arg ,E@p_QTRQt Fp_ t )5+#fnu !#argu ,E@p_QTRQ6a s` a 6h#nb #fnb (#argb 3E d #hrete qX} b  ,5+#fn !#arg ,Ei len! " |ret# $ ;Zb7 Z}p8 | 9 | : | ;  < &t < -t5(achK % O Fa__cO 9 ̋F 1b݋r}U~T}#X|3bUv3$|"T v2$}"X|$_d /5+#fn!#arg,Ei len  |ret  _d~5c |  &t -tEdUwQ R E=dUwT| $ &Q R 3QdXvA"pd=G d2v1'U2v27T|'f (5+ ; #h #h['ff$Ff$9fSf^fNkfelfwfffffUffUff9RU|Ts3$"RU|q|f q-5+ q@is t |)p | |  &t -t)ch) )__c8< -g </5+ <B!len<O >  ?p@ A - B -retC iovDg E  gGh $5+ret n .ph6$)CP]qTshhUshUs?Ãs^(iNi*'5+U "\  -Ä -j +5+ 5#offBj N "\ jÄg5jUs*RjT~Q8Z^yjTTQQRR^8 - k (5+ ;!lenH "\  p! " - # - $ - %  - l .5+ ;| Hlen -    l$UvQ|-o ʊlۊ@U~TvQsln -5+ :| G THlen -  -  |  |  |p |  >n#nTQsTQsmo no% ooU~jUT:Qs]mo -5++moo%ooUs o .5+  len -|Sp*+5+U 5off yJqp y&5+(nYp n%5+-`t}$qKzq K*5+h-qUsgEqUseqUs?Ãs^Us-r -%5+hqUsgqUsqpqUs^Ft %5+=X~ElenF ~~ ?yPsQy-?y+Qy+y / y+y   yy*T Q8zqhsUssT0sT|Q}sT0xsUssUv?ÃsqptUs8tT6Q1R~X4 yt*(5+Ut@FtU %w (5+#fd2  `Tu}$q  uvT Y' >vk%'w~~׳/vUvT~Q~ HveY'U T2ʳvU vUsT vUvT1wU0wT0( Sw2cb;*UD Tx EۄwU=T ۄxU:T ;xUIT1WxU2T1t{xU T0xU T1T A y A%5+lenC D 4/y!fd4) 6 /y?yG+^y!fd+,s y!fd5 y!fd 7y!fd.!pktN\ *z *5+ 4   |  | Wz 65+ D z D.5+uidF gidG H I J#h K#hiL 1 >{ 1.5+ 2|!len2 2+| 26 4 5>{-N{G { '5+!uid3L!gid>@ Prv pw! { 6 | +5+#uid7L#pwL!ret  Tw3o|UQTs|U T Q|Xs}|UvT Q0 $} ,5+!uid8L) ret  r} -5+r} } }G}=G#4}6{  {,5+ {? {R} ":_n~ i~ ~$zUvT Q1R X rf~U|Tv*~U2DrJ [ J%stLSfdM ) zrc+   )uid  -5+  i ) &t -t7 O 35+i F2bp|) &t -t7v /5+pb7 )Hp |b6t Y t4h tB*u! Q u#| w#h x xh!fdh j=XlenkF R ف R<ف SH S+ U#hh> >>\ >L)bF62 G 235+ 2=p4 |vTv$ Ă $+5+!n$5p&  05+ :  | i!fd 2i < Gret  n  -!fd' 2E!len?ret -7 у 35+ !fdret 6 U#fd# +val UsT3Q0@UUT47wф wJ\ x&!lenx0tR :A  A A2EsaC~CWUvT0Qs7oUsCUvTsQ0:8 υ2sig8!U:3 2sig3 Uu (7   .mUs@U T QURTvvwxfmt'PVbuf Tvyp |z Eap  u5VtvEuVtm u{iևzU|T Q1R X \i/XzU|T Q1R X õuUsT0ϵUsTu +۵T1Q}Ru\i-zUsTdQ1R X Yv3$" izUsTdQ1R X  > [[OT1Q X|rW  :5+ D.|ʊ|."-" "E"%.k|6kkk.\|`\\.>E>E>>.'E̋'E''.EG.8 18.did d<P.A]__sA]__nAAP.%|Ռ%%|sz' 8n n8i i8 B  BS.)s))PW11W"m"m,moooo-o ʊۊ@U~TvQ|,aq$ÃSу G$% L8Us+ $Ã, )6CP]UvQ|,Ot  OfT0,YYYYY}YYY}Y}YYG g)U|TsQ N ʑ)UvT|Ql  UsT0Q: ` T}q ̋ ݋ Uv 6\ SG) U|T:51U|T )OU}T]AzU}T0Q}R}NU|[U},UUUUQUQVV[UC ה$UUUUVVNVV+VU T|QgU TvQ3VUu,flEfggg,g9gDgQg^gkgxgf< ggf%g,g9gDgQg^gkgxg e6)CP]qTwQ2R} Z ÄgU~U~?Ã~*7U2T~,9= ::п `:b :}:r::_:: , 2sUwT 9 %ɌUsT|Q јTvQ0 3:g 6E:R:HGeY'UsT AQ UsڙUvT2LUvU2T1}U0T Qs9 ]  :% :}U0T QU,jjjjjjjjjkQk j jjjjjjjjkk S $Ä? cUTQvg{UsgUs^,[[[[}[ [$[$[>[,[>[3g[U|- TvQs,Y8YYYYYYYQYY@tUUTT,{X!#XXX-{X XXX՞U@T1[UU,x xxx oO/ʊ  ۊ@UsTvQ| xA hxxx߁1V۠O  o@iš%8ʊۊ@U}T|Qv yn yyzz~zA %Aˁ+5R %5ˁvT v $ &33$A %Aˁ+5R %5ˁvT v $ &33$  wODO X]%j v v[ v v v6 v vȦ v-vS K$% >#)&+v %O23@ v  v ڨ$ v $-v $*z1 ԩ"?o363A* @ 'n* A * A B1B( 1 : ; 9 I8 41B11 4: ;9 I 1RBUX YW  : ;9 IB 4: ;9 IB : ;9 I I: ; 9 I4: ;9 I1RBX YW .?<n: ; 9 4: ;9 I4: ;9 IBI41 U.: ;9 'I : ; 9 I!I/ .?: ;9 'I@B4: ; 9 I41 : ;9 I8 .?<n: ;9 I!: ;9 I" : ; 9 #: ;9 IB$1% & : ; 9 I'4: ; 9 I?<(.?: ;9 '@B) *: ;9 I+1RBX YW ,.1@B-1RBUX YW ..?: ; 9 'I 4/$ > 0(1 : ; 9 2: ;9 I34&I5 6.: ;9 'I@B7.: ;9 ' 8.?: ;9 'I 9'I:.: ;9 '@B; U<7I=!I/> 1?1B@B1A.?<n: ; B> I: ; 9 C : ; 9 D.?: ;9 'I@BE4: ;9 IF G5IH4: ;9 I?<I : ; I8 J<K : ;9 L : ; 9 I8M: ;9 IN 1UO 1PQ41 R'S1X YW T.?: ;9 '@BU 1UV4: ; 9 IW.: ; 9 'I X> I: ; 9 Y : ; 9 I8 ZB1[1UX YW \1RBX Y W ]: ; 9 I^% _$ > ` a : ; 9 b : ; 9 Ic'd&eIf : ; g: ; 9 h!i(j : ; 9 k : ; 9 l4G: ; 9 m'InB1o.?: ;9 'I@Bp4: ;9 I qrBs.: ;9 'I t.: ;9 ' u.: ;9 I v.?: ; 9 '@Bw: ; 9 IBx: ; 9 IBy4: ; 9 IBz4: ; 9 IB{1RBUX Y W |4: ; 9 I}1UX YW ~.?<n.?<n: ;9 6ddqd T)TuPPP(PPsPPKP[P"R+RRJQ^Q5Q5<v <Q{ PTt _X ~XX[TiT2TAXX[P[aQxT4T@PP{P{t XRr t;# $  %!r"p;# $  %!r"u?[gRSRbRHRQRR {RTKTiQX%vXvzr TiTTQq Ru .Q2QHQ+Q4QQoQQ;QQXP iR~Rv FRFW{ _Rz QK$KU$KKVKKUKIKTIKKSKK|hKKTK.KP.KPKQpKuKQuK}K?p K$KQ$KLKUpK}KU3KFK q 3KFK03KFKUQKpK8QKpK0QKpK\pKyK 7p yK}KQpK~K0pK}KUKK@KKUKKSKKVKKXKK0KKSKK|hJlJUlJJ]JJUJJ]JJUJJUJ0JT0JJSJJTJJTJJSJJTJJs@JJSJJSJJQJJ^JJQJJQJJ^JJ^7JTJPWJZJp?ZJaJPaJtJ\tJJPJJ_lJJUJJ | v"|JJ_|JJSJJTJJT|JJUJJ | v"JJ@JJSJJTJJs@JJ}JJ ~ JJQJJ\JJu`IIUII\IIUII\`IITIIT`IIQIIVIIvxIIVIIV`IIRII^IIRII^`IIXII]IIXII]dIITdIIUP@c@Uc@CVCrDUrDEVE.EU.EeEVeElFUlF;GV;GTIU@@P@@P@@P@APA0AS0ACAPVAiAP}AAPAAPAAPABP$B7BPKB^BPrBBPBBPBBPrDDSDDPDEPEEPEESlFFPDDsp"1DDP@@P@@PjApAPAAPAA0AAPBBPDDPDD0.E4EP:EQEP~@A0A!AP$AC\rDDPDD\DD0DD\DE0EE\lFF\FF0FH\H@I\EITI\@@P@@PAAPAAS5ACAP[AiAPAAPAAPBBP)B7BPPB^BPwBBPBBPBBPFGP"G,GP'CQCPE#EP HQHPFFPG!GP;GPGPPGTGUTGGVHHVHHQHHVI;IVEITIVFFPG!GPDGPGPPGTGUTGGVHHVHHQHHVI;IVEITIVWGpGPpGGSHHSI%IS%I6IP6I@ISEITISDGWG0DGPGPPGTGUTGWGV`GeG}eGpGQpGqG}`GpGPpGqGSGG@GG GGS]CtCP{C}C0G HP H HPfCtCPHHPHIS]>,?0,?C?]p;u<0<<P<=]=>]>,?0,?C?]p;u<0u<`=}=>}>>T>>}>,?0,?,?},?C?0p;u<0u<@=V@=V=PV==V==P=>V>>V>,?0,?0?V>?C?0p;`=S=:?S<< s $ &<<U=>0Z>c>0c>{>^{>>~>>~~>>~: ;U ;/;S/;0;U;;P99U9:S::U::S::U9S:\::S::@::6::W::4:: ::H4U4U U $$6U404^^ $^$6040000T9r0? $0404_\_\mm_ $_$60404K\KV\V\ $V$60SS 6S]] 6]USUSUST.V.T  wS  P ' S' W v(d r Pr x S     p`# p`# <$ c ~`# <$d x ~`# <$ vv" P c ^d x ^  \  0  P  S89P8:9QP+ PQQ + Q # 0 # 0 # P  U s U ) P) > S> k Pk n Sn r Pr s S 7L7UL77U 7H7TH7w7Vw7x7Tx77VM7Z7Px77P55U56V6?6U?66V66U66V66U56T6?6T?6F6TF66\66T66T66\66T66P66P66\T6g6Pg66S66UF66]66n2(3U(34\44U223T23(4V(404T044T223Q234]44Q63Y3PY3c3pc3t3Pt3~3^33p33P33S34P4,4,4h4L3p3Qp3~3R33Q33R3 4T 4 4tp 44T414^4(4V(404T0414T404|I4R4QR4S4VI4R4TR4S4]I4R4|_(l(Pl(v(u_(v(3_(l(ul(v(P''U''U''U''T''Q''T''T''Q''R''Q''QP''U''U''UP''T''Q''T''TP''Q''R''Q''Q0`U`SSU0`T`^TT0`Q`VQVQQ0`R`]R]RRD\~1$~"3$U"T $ &33$U"\~1$~"3$U"T $ &33$U"\`iP{P0%%U%&S&&}&+'U+'9'}9'@'U@'E'U0%%T%&_&9'}9'@'T@'E'}0%%Q%9'|9'@'Q@'E'|%%V%%vb%%0%%p 9'@'0%%Q&&Q%%P&&Pb%%0%%^%%~%&^&'}+'9'}9'@'0c&u&}u&&]&&}&&}&&]+'9'}K&&_+'9'_c&&S+'9'SK&X&V_&u&Vu&&}&&t&&T&&}#+'9'V%'\+'9'\&&P&'}+'9'}&&V&&v8$8&2$p"&& v8$8&2$p"c&c&5c&c& c&c&^#|$U|$$U$$U$ %U %%U%$%U#w#Tw#$S$$T$%S%%T%$%T#w#Qw#$V$$Q$%V% %Q %%V%%Q%$%Q##P##p$$0$$0$$^$%^<#w#0##r ##t %%0##Q$$q$!$qpI$Y$RY$m$q %%qp$$P$$P$%P<#w#0w##\##|#,$\,$_$|_$$\$%\ %%\%%0$!$T3$m$T %%T%%q`$!$X>$B$RB$$X %%X#$P %%P#$Y %%Y !U!7!S7!p!wp!{!{!!U!!S!*"w*""U""w !T uF!q!S!!S!!s""S""P""P{!!|I"o"|o""P{!!VD""V""v""V{!!_I""_{!!}D"d"}{!!]""]{!!^""^o""q2$u"""q2$u"o""v8$8&2$u"""v8$8&2$u"""v8$8&2$u"((U(=)S=)>)U>)Q)UQ)b)Sb))U()0) )P!)&) &)<)P>))0(( uu@()Q>)Q) uu@b)|) uu@()P( )s ))T))s()s()Pt u T p p# p`# tp# Q P 4 T2D2UD22S22~~22U22S22~~22U22U2D2TD22V22T22T22T22V22T22T2D2QD22]22Q22Q22Q22]22Q22Q2D2RD22\22R22R22R22\22R22R2)2u)22^22U#22^22U#22uU2Z2|Z2u2PU2u24U2u2^`U< ]< H UH b ]b k U`T< VH b V`Q5 SH [ S[ ^ sp^ b SP}q $ &}} $ &P\H b PP0< \H b \P\V 0 SH H S 0 VH H V 0 ^H H ^ PH b P  S  V  ^ZUZ^UH^H\UQTQ]TH]H\TZQZHQH\QZRZ\RH\H\RlSHS?ZSZ_H_HRSP\QTQZ]ZVUVVUHVH\TT__PPSS__UVU(4^(3 p $ &37 s $ &USUSUUSss $ &0yTyTMYQYn t2$x"#4nyRU)S)*UUPU0//U/0S0 0U 0#0S#0)0U./U/[/S[/\/U\/a/Ua/o/So/u/UWWUWXSXXUXYSYYUYPYSPYUYUY#YsY#YsY#YsY0Y Y#Ys U S"U"rSrU'T'V"]V]_P_rVrTdlP3  303}@3}S?LPL}\V]d2]d 3JP,2,U2,h,Vh,k,Uk,,V,<,T<,j,\j,k,Tk,,\,G,QG,,Q-,H,0H,L,Pk,,P,,R+:+U:++\++U++\+:+T:++^++T++^+:+Q:+V+SV++Q++P++p $  $-(q++ q++  U uh U T T q Rq w Rw y Ry R q Zw Z 0  [  p * X- q [q 0 0 T t  u|#- 4 T4 7 pD W T^ b tb q u|#q 00 C UC n Sn p Up w S0 G TG o Vo w TH _ P_ i sp u P U S U S U U S T V T V T V P P P0_U_VUV07T7\T\@JUJrVrvQvwU@UTUcScvRvwT@UV}U}V.U.VU@T|]|}T}.].5T5]v\S} S R.:v:\S\S P}Pv  \c c c\SWRWXuSWQWX]SWs} }d}S dUS.  (s U  S  U  S $ U$ * U Q$ * Q P ) P) * u t $ & P  \  \ T  V  V  ^  ^ P ] $ P \ V ^G P P U V U VU T _ T _T Q \ Q \Q R ^ R z^zRR P S %P%XSXdPdS R ] ]R U SS(S T VT9V 4}4]}*\kPS(P(QS*S04^0QTPThSsS'<'<S',},<\l\UvFQSs0s0s}Q | Q|V\dUdU}P_U_/0/LPLn__UdSPnSSPSdnPPQQRX))U)*^**U**U**U**U))T)*~**T**~**T**~))Q))w)*Q**Q**Q**Q**Q))Q))w)*Q))T)*~))U)*^**S)*~*`*_`*v*v**_&*f*Qf****}x**Qj**]**P{**P**]{**2{**w{**~{**P**]{**2D*T*qT*j*PD*j*6D*j*\,-U--V-T.UT..V..Q..U..U..V..U..V..U,- T.q. .. .. .. ,-W--ST.q.S..S..S..S,-U-{-V{--ST.q.S..U..V..S..V,V-0V-h-U..0r--P..P- - - -W{--_--\{--S{-- -.S*.T.S..S--P--V*.;.P;.T.V..P..V-- A--Sq..V..Q..U000U01S11U11S11U11S000T0111T1111T1111T11000Q00V01Q11Q11V11Q11V00V01Q11Q11V01111101S11S11S00]0 1T 11x1b1Tn11T11T01V11V000F1^F1R1rpR11^11^0-1_-151x511_11_0b1Yq11Y11Y11Y00R11R11 @00400T11V1111_45U5%5U%5/5U/55\55U55\55U45T5%5T%5F5TF55V55T55V55T45Q5%5Q%5P5QP55Q55Q55S55s55}%55S55}55S55P55st"%575P75F5st"1F5f5vs"1K5`5T`5b5tpb5f5Tq55Sq55Vq55|7 7U 77U77U7 7T 77T77T77U78U88U88U77T78V88T88V88T88V77Q78]88Q88]88Q88]77Q78]88Q88]88]77T78V88T88V88V77U7^8\88\K LU LWL_WLLULP_P$PU$POW_OWTWUTWW_LLP,LWL\LL\,LWLVLLV,LWLSLLS=LGLPLLP,L=L\,L=LV,L=LSLP_OPOW_TWW_qMMPLPSOPDUS\UOWSTWWSLL1LLPLLQ8MqMV8MqM\.MqM]NMXMPqMMP8MNMV8MNM\8MNM]MPSOP,RS\UUSV0VSW/WSMP_OP,R_\UU_V0V_W/W_MM p1OPQ p1MP\OP,R\\UU\V0V\W/W\MNVMNMNMNVMNMNMNPNONVNONNON!NONV!NON!NON8NONPyOO_RiR_RDU_\UV_5VV_4WOW_TWW_yOO#R,R#\UhU#yO{O0{OOPOOpOOPOOROPQ_OPQPOPkPpOPQpSPkPQkPyPp kPQp oPyPQyPPpyPQp}PPQPPpPPpPQp PPpPPpPQp PPpPPpPQpPPQPPpPPp PQp PPp!PPp$PQp$ PPp%PPp(PQp(PPQPPp)QEQPEQIQp"Q'Qp1$q""Q.Qp1$q"3QEQQ3QEQQ6QEQRiQQPQQppQRPpQRQQQPQQppQQPQRppQQRQQRQQRQQR\UU_iUUPvRRVvRR_RRPRU_UV_5VV_4WOW_TWW_RDS\DSGSPGSSwST\UU\UU0UU\RKS]KSSPSS~ST]UU]TUPRU0UV05VV04WOW0TWW0R SZ SSzhUUzhUU0 SSZUUZRRpRSXUUX_SS__SSz|_SSRSS~_SSz_SSzSS\SS}pSS@SS SS]TT0UV05VV0VV04WJW0TWW0WW0T T~UUP8VXV\VVVTT_UV_5VV_VV_4WJW_TWW_WW_^TpTPyTTPTTPTTPUUPUVVAVXVPiVVPVVPVVPVVVVVP4WIWPWWPWWVT2TP2TT]UUP5V@VP@VXV]XVzV0VV]VV]VVPTWW] TT_UU_XVzV_VV_TWW_ T3T 3T;TPTWgWPhWW_UUHUU0UU U4UU4UU4UUDU U4UPJP P$PU$PJP_.PJPP,d       9>ACFQxx| *)SX 05:@nOh"'3"'3TY}O[]dRV] 0 P P  0 P P {!!!"""{!!""`"h"p""""`"h"""%'0'9'.&5&B&G&c&c&_(e(l(v(((() )))* **`*f*{**D*D*I*Q*;+>+c+n+q++,,,-X.x.....,,- --.0.X...0111110000U2U2`2j2D3c3k3~333334%4,41464<4I4S455+5555q5w5{55777 8 888888s:}:::s:}:::::::::O<T<<<<<=>`>>@@@@BQC E0EFH HXHHHI;IEITIFGHHI;IEITIDGGHHI;IEITIQCChEpFH HXHHHIhEEXHHHIEpFHHdIdIxII_JJJJ|J|JJJJJJJJJJJJJJJpKpKuKwKyK~KKKKKKKKK,LWLLL0LWLLLWL\LL POPiSiSUUUUOWTWWMPOP,R\UUV5VW4WyOyOOOOP\PaPdPhPkP\PaPdPhPkPrPvPyPrPvPyPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQQQQQQQQQQQQQQQQQQQQQQQRiSiSUUV5VV4W@WEWOWTW`WcWWUSeSiSiSiSSSSUS_S_SeSiSiSiSSSSiSqSSSSSTTUV8VV4W@WEWOWTW`WcWWTTTTUUUV8VV4W@WEWOWTW`WcWW T;TUUTW`WcWW T;TTW`WcWWUUUUUDUYYYYY0YYYZ ZUZaZZZ@[]^_`_`8`` aHaaa0bstruct_FILE.hFILE.hstdio.hsys_errlist.hresource.hstruct_iovec.hsocket.hsocket_type.hsockaddr.htime.hpwd.hstruct_tm.htime.hunistd.hctype.hconfname.hgetopt_core.hstdint-uintn.hin.hnetdb.hun.hlsapidef.hstring.hresource.hdlfcn.hsocket.herrno.hselect2.hsched.hmman.hsendfile.huio.hstrings.hinet.hwait.hprctl.hgrp.h KK.K5J/I#KK1 0 z zJ Z " OJJ = ...v <K gfJ.T2KxJ.n=@<YDw<<=:/;<;/u;=IK=H</փ-K-=>:X-=;=0:/;=I<//sf=H</[G-K-=18=;=0:X;=-/I=;/?Gf-K-=I<-=;=-/e=-/t0//-</-</-</-<///-<///-J=t=Y-</ȑ-</J>Xtu-=ttu;/K-=-/X-/t;/gK-=Y-=;=J;=/K-=-/X;/u-=ttu-=K;</f;=;/fu-=t.V>,>t;=/.K-=-/t-=-//-/-X.I</t.W=-/0,0,<.W=-/t/t;=;/H ># K# = l Z< < h u$I$K="IY<IJ =$J$<=;"<J = vXF.L L = /d f.L u /O7@p$tik<=<>V L a$f mX Xm< .>m<X N1+ pk " kJJ k.XX"~K k  [ X O(kX  < kX  b>= E<>:<Y<; = vk<q R< !l   l<lz/ f X< Kffkv ~*~ X$ rJ~ # .?f h ~~<  .<1 ~) < ~t)X ~<= jtt        Z-JJXft X L!s gf  fF J Y Y :"foXXXJlt0 hd/ L. XN6g J yi< X$   Z  4tKK  ;:|". < Z IY6t(f+K"JMX"X< mJ< & AJX0J XXXV$J)I!4f<9X!Jh  .$r.XX`KJ Jt5<uY"J q<% 3$x.`XYBW[$g   F x \ *2. F^ \t;:j KK-uYIX Ki+JJK2KKu\/ u  u  (tX |  x(9?JL6J9xX<u1tu6,XJK,@g L,K /sJK u XQy  X KEW \ g x. < %  /s u Z ptt  /t.X  o tK !f J/ kt Zs gY  Z Y g Y  #!xwJKxJK K!JK sJ  s< ! KJ9J!JK!s  f K =J YYt YYt YYJ YY<xK t<YL ,<W ue [A<v v .KXe#!CJ;Cg K E dX ` x DNK$ JG MY<," g <    =  &> t u X   Y r< f Kr  < r rJ huJL |   fX.X  ]u u<   Z = = y<kJK,&J"Irt &s=r< !rff  "yJD!IK L%; K%H K KKK.7 .XB#I1u#J Q  F Z  KNJ U  X  hJ.$ .Xhr / X L*~Jf-S. LKI u YZ .HJ K Y)%fX80JJ )X%<XX$%4HJL<0YBL=;B=Vv<)/Mt z0<6u  zt/  L4K"vI4H =" @"F %#K%W Yz Q*uJf  uJ K mJJ .I  <vJ uMF =0J u) Y%#K,K"9 =& =X YsJY FX:JJ Z L N*<xX<JX>tJ e < 7/t  L4K xH4 = K *vJfJ  uJ  Y.W mJt mX K t Km \x JYKWiX<JJz NS =;0WX Y)? K  LeJf<Ki*_8tK )^ ~tf<_K z.` ztf< XKJZfv*=gJ Z AK=%, =%H KM, tY,Lho!(fot(= -K l X|K<x < o.K Ms f sf tJt    Z 93JJM _< . jy 93JJ Kw ' K"f/ s XM X X mXL  f   yr rX' =P Yr J:h6t YGu  uf>= . f  K  ^tj  !tJ<   jF % =%H K  Z7)K LK)8 K! K 2%o = K%: K2 GK  _X#< ]< <& Y ZX [f<Ȃ _Xy q   KK&,N>:hZs"  [sf  "Ui Xi g Y .. - sX ... K fh00< =  h+< Y  u<   Y Jz   . L+< g  /.  L g J JK*X.X v6= Y; u/ Xl f? lJXY lf"Kl "K8G8=P.4XK%      J.Jp<J*<X v6= Y;. / Xl f lJXY"=8G8= I/..c<<jBz<  sX&`" f [Z M   L  Y 0 U= =Y K ^f 4I gYK$/ fY L y^ /K-%]  K+/X>0XX<uj Yv Xg Y IgZ$Hv&L<X(.= /.u.Z .fJOwX(WuO=.ft"<*w  <K t Y /?N&tuKK  h g G] t Y t YtM   t  Y IgYJvYY g r Y >v t YK, <Y ._ho<x }KYWJtbXK X 9    ft "u ; <u WY rXu WY X"0", XX LXJ<f?JfjK t Y*=K t ,=K t 0=K t .=K t Y,=KgjKK 2K zt/ Y Z  c    Zc  cf  Zc <<   a,<  Zci  Zc x    Zc w X     c       Yc  v    Yc  v    Zc  w    Yc  v  Z [    Zc   g     Yb  f }r       g {  g1J }  <1-u-).K.X UJ.< Z .)J KIK XxK +zz< O=>;g< 0:>< Y6 2 _< < Z    \_<   _X<   _ @ /        J       f :v ZYw Yu    Zv  .X t   tXI/ /    u ~ft  Zr> Z J  z  X/X < zX   tX /  `ggWK>X u ~X~ }XYX |X |<Y ^  X ./ XR XUJ Y   h.eX> tYvtYK   M U -/](tq $~Zv <Qyt/Z t   t Z*(t N   bX J| < y  !#J Y  Z+KZ)=1K- M< <Y v.u. }Jt ZY< gJ f"<  /  np < }2NX)     ~ |X}Y"Xg![qg!p'Y>tYK&CXK%.ZY&i fYp<x u   Zv X w ~9}5Xl t.Z7j.+"<g7/W5K/I Mu_Kg\K _SC_THREAD_SPORADIC_SERVERpthread_atfork_functotalLSAPI_Set_Max_Process_Timelsapi_parent_dead__fxstatparseContentLenFromHeaderugidLen_SC_2_SW_DEVm_pScriptFileLSAPI_Stopsi_addr_lsb_unused2_SC_TIMERSm_iReqCounter_fileno_SC_SHELL_SC_MEMORY_PROTECTION_SC_SCHAR_MAX__pathtm_secH_AUTHORIZATION_SC_THREAD_SAFE_FUNCTIONS_SC_UCHAR_MAXmax_lenfreeaddrinfogid_tverifyHeader_SC_C_LANG_SUPPORTm_pIovecEndstrcpy__uint8_tIPPROTO_TPpw_uidwaitpidHTTP_HEADER_LEN_SC_TTY_NAME_MAX_SC_PASS_MAXLSAPI_ErrResponse_rsi_uidm_bytes_SC_2_PBS_TRACKfp_lve_destroym_pHeader_IO_buf_end__RLIM_NLIMITS_SC_SELECT_shortbufrlimitsockaddr_insa_family_tSOCK_DCCP_SC_BC_STRING_MAX_ISpunctis_enough_free_meminet_addr_SC_TRACE_INHERITinit_lve_exnewSizem_tmStartliblvesetgroups_SC_SEMAPHORES_SC_EQUIV_CLASS_MAXread__environ_sigpollsa_datauint16_t__builtin_memmoveai_protocol_valuem_pChildrenStatusCurIPPROTO_UDPoverflow_arg_areatime_tsin_zero_SC_DEVICE_SPECIFICin_port_t_flagsachMD5_SC_THREAD_THREADS_MAXerror_msg_SC_LEVEL3_CACHE_SIZE_SC_TRACEreg_save_areacalloc_archm_respPktHeaderg_running__off_t_addr_bndlsapi_cleanupachHeaderNamest_size_SC_THREAD_PROCESS_SHAREDallocateBuf_SC_JOB_CONTROLgetppidtm_isdstswapIntEndianlsapi_check_child_statussignal_locks_max_idle_secslsapi_set_nblockenvirons_schedule_notifysetUID_LVE_SC_NL_NMAX__RLIMIT_NPROCRLIMIT_DATApServeratoluint32_tinitgroups_SC_POLLm_pHttpHeader_SC_V6_ILP32_OFF32_SC_TRACE_SYS_MAXm_pScriptName__builtin_va_listst_blksizeRLIMIT_NOFILEm_pEnvList_SC_BASE_sigchldLSAPI_Set_Max_Idle_Childrenint32_t_SC_LONG_BITfixEndianLSAPI_GetEnv_r_upper__fmtsa_familym_specialEnvListSizepw_passwd_SC_CLOCK_SELECTIONmasklsapi_resp_infosigaction__RLIMIT_RTTIME_SC_V7_LPBIG_OFFBIGbodyLeftfcntllastTime_SC_AIO_LISTIO_MAXLSAPI_Init_Prefork_ServerpErr1pErr2st_gidm_cntHeaderss_notify_scheduledm_envListSizeacceptinggettimeofdaypBufai_addrm_iAvoidForks_secret_timerlsapi_MD5Context__syscall_slong_t__builtin_memset_SC_FILE_SYSTEMsa_restorerm_pChildrenStatusEnd_IO_write_endtype_SC_SCHAR_MIN_SC_LINE_MAXLSAPI_SetRespStatus_rlsapi_MD5_CTX__resst_nlinks_addr_SC_TZNAME_MAX__va_list_tag_syscallst_ctimnameLen__builtin___snprintf_chkLSAPI_Postfork_Child_SC_2_VERSIONfree_SC_2_PBS_CHECKPOINTIPPROTO_MPLS__sigset_tm_requestMethodOffm_tmWaitBeginreadSecretreadReq__tznameatoig_initedgetaddrinfovalLens_acklsapi_jailLVE__d0_SC_LEVEL4_CACHE_ASSOClsapi_MD5Final_SC_NL_LANGMAXdoAddrInfo__stack_chk_failmemcpy_killcurSizeRLIMIT_STACKIPPROTO_IPIPdlopenbacklogsin_family_SC_LEVEL1_ICACHE_ASSOCpIovrlim_maxm_iKillSentm_fdListen_SC_AIO_PRIO_DELTA_MAXvalidateHeadersst_atimm_statusm_reqBodyLensig_numoptargSOCK_RAWsnprintfold_int_SC_2_C_BINDs_enable_lve__clock_tparseRequestIPPROTO_RAWstrdupbufLen_SC_PRIORITY_SCHEDULING_SC_SS_REPL_MAXsys_errlistsival_ptrpStderrLogsetpgid__uid_tdaylightsi_stimeoptoptLSAPI_ReqBodyGetChar_rpKeysun_family__uint16_t_SC_FSYNCsin_portgetpeernameLSAPI_is_suEXEC_DaemonLSAPI_Is_Listen_rLSAPI_End_Response_r_SC_FILE_ATTRIBUTESsetreuidserverAddr_SC_NZEROm_pQueryString__gnuc_va_list_SC_2_C_DEV_chainpContentLen_call_addrEnvForeachnewfdm_iServerMaxIdleSOCK_NONBLOCKusleepSOCK_RDM_SC_SYMLOOP_MAXsockaddr_un_ISblankunsigned charIPPROTO_MAX_SC_MQ_OPEN_MAXSOCK_DGRAMm_tmReqBegin__fd_mask__blkcnt_tlsapi_enterLVE__builtin_calloc_IO_lock_tLSAPI_Is_ListenIPPROTO_COMPLSAPI_key_value_pairlsapi_check_pathLSAPI_ForeachHeader_rpHeaderName/builddir/build/BUILD/opt/alt/ruby27/share/gems/gems/ruby-lsapi-5.6/ext/lsapi_SC_SEM_NSEMS_MAX_SC_USHRT_MAXLSAPI_FinalizeRespHeaders_r__read_alias__fdelt_chkshouldFixEndianpBody_SC_STREAM_MAX_SC_ASYNCHRONOUS_IOserverMaxIdle__open_alias_SC_READER_WRITER_LOCKS_SC_CPUTIME__getcwd_alias_SC_2_PBS_LOCATE_SC_DEVICE_IOsa_flagspVecgeteuid_SC_SIGNALS__ctype_b_loc_SC_V7_ILP32_OFFBIGstatusoff_tchild_statuss_notified_pids_max_reqsH_X_FORWARDED_FORs_pid_dump_debug_info_ISalpha__fprintf_chktm_zone__mode_tm_queryStringOff_SC_V7_LP64_OFF64_SC_NPROCESSORS_CONF__RLIMIT_SIGPENDINGfdInlsapi_changeUGidtv_usec_SC_XOPEN_XCU_VERSIONold_childold_termLSAPI_sendfile_rlsapi_lve_erroraccept_SC_MEMLOCKallocateRespHeaderBuf_ISprintsched_yieldpMessages_liblvepValueH_CONTENT_LENGTHm_tmLastCheckPoint__vfprintf_chk_ISalnum_SC_SEM_VALUE_MAXs_req_processedstrtollopen_SC_XOPEN_XPG2_SC_XOPEN_XPG3_SC_XOPEN_XPG4LSAPI_STATE_CONNECTED_IO_write_ptr_SC_REALTIME_SIGNALSsystemlsapi_packet_headerIPPROTO_ENCAP_ISspacelsapi_suexec_authgetLFg_prefork_serverva_list__suseconds_treqsexitLSAPI_CreateListenSock2__rlim_ts_ignore_pid__RLIMIT_MEMLOCKpCurpHeaderValue__sizesizes_slow_req_msecslsapi_init_children_statusgetuidFILEH_COOKIELSAPI_ParseSockAddrdlsympthread_lib_SC_PII_INTERNET_DGRAM_SC_SINGLE_PROCESSbyteReversedump_debug_infoLSAPI_Accept_Before_Fork_SC_SHRT_MAX_ISxdigit_SC_RAW_SOCKETSfp_lve_enterLSAPI_AppendRespHeader_rsize_tH_CONNECTIONLSAPI_GetHeader_r_SC_MULTI_PROCESSs_stderr_log_pathm_statefp_lve_instance_init_SC_BC_BASE_MAXH_CONTENT_TYPELSAPI_STATE_ACCEPTING_SC_RTSIG_MAX_SC_NETWORKINGachCmdH_ACCEPT_SC_GETGR_R_SIZE_MAXperrorcompareValueLocation_SC_THREAD_ATTR_STACKADDR_SC_LEVEL2_CACHE_ASSOC_SC_IOV_MAX_SC_TRACE_EVENT_NAME_MAX_SC_PII_INTERNETIPPROTO_IGMPpServerAddrlsapi_acceptlsapi_initLVE_IO_save_baseLSAPI_Release_riovecold_usr1maxIdleChldsocklen_tm_iMaxChildren_SC_2_UPEai_canonnameIPPROTO_IPV6_SC_DELAYTIMER_MAXpw_dirsa_mask__sigval_tLSAPI_Set_Extra_Childrens_restored_ppidsin6_flowinfototalLenm_pid_SC_SYSTEM_DATABASElsapi_prefork_server_acceptm_pIovecToWritecodem_respHeaderLen_wide_dataH_IF_MATCHai_family__nlink_tsi_addrst_inost_modeLSAPI_IsRunning_SC_T_IOV_MAXCGI_HEADER_LENIPPROTO_DCCP__in6_usysconfGetHeaderVarH_ACC_CHARSET__stream_SC_XOPEN_STREAMSm_iMaxIdleChildrensendfile_IScntrlm_reqBufSizelsapi_child_statusprctlallocateEnvList_ISupperpStatuserr_nosival_intsi_codem_pReqBufwait_timestrcasecmpH_IF_UNMOD_SINCEpw_name_SC_TRACE_USER_EVENT_MAX__socklen_tsend_notification_pktlsapi_requestpKeyEndcurTimefprintflsapi_writev__ssize_t__srclsapi_closepChrootH_IF_RANGEtimespecnameOff__u6_addr8strerror__RLIMIT_RSSavoidForkm_packetLenLSAPI_ReadReqBody_rIPPROTO_MPTCP_SC_2_FORT_RUNbindfp_lve_leave__valin6_addr_SC_ADVISORY_INFOpacketLen__timezone__ctype_toupper_locsin6_addr_SC_TIMER_MAXpBufCur_SC_THREADSunset_lsapi_envs__sighandler_t_SC_USER_GROUPS_RLSAPI_Set_Server_fdLSAPI_CreateListenSock__RLIMIT_LOCKSm_respPktHeaderEndLSAPI_On_Timer_pfLSAPI_Set_Max_Reqs_SC_UINT_MAXst_uids_conn_close_pktLSAPI_Postfork_ParentpEndpktTypelsapilib.cset_skip_write_SC_TRACE_NAME_MAX_lowers_busy_workers_SC_THREAD_DESTRUCTOR_ITERATIONSm_flagmemsetlevelstderrm_pHeaderIndexnameidle_SC_CHILD_MAXlsapi_reopen_stderr2_IO_save_endtm_min__nptrLSAPI_InitLSAPI_Request_SC_V6_LP64_OFF64flag_SC_NGROUPS_MAXm_bufProcessedfixHeaderIndexEndianstdoutfp_offsetlsapi_MD5TransformLSAPI_Write_Stderr_r__time_t_SC_THREAD_ROBUST_PRIO_INHERITgp_offset_padLSAPI_ForeachOrgHeader_rsigaddsetLSAPI_Inc_Req_Processedm_httpHeaderLendyingrealpathtm_yday_SC_SSIZE_MAX_SC_PII_OSI_CLTS_SC_SYSTEM_DATABASE_RmsecspAuth_SC_LEVEL1_DCACHE_SIZEkeyLenextraChildrenLSAPI_Flush_rshort unsigned intrlim_cursigned charLSAPI_Reset_rs_lveold_ppidLSAPI_CB_EnvHandler_valueLen__blksize_t_SC_STREAMSSOCK_STREAMdigestpBufEnd_SC_PAGESIZE_SC_THREAD_PRIORITY_SCHEDULINGcountsi_pidIPPROTO_MTPs_stop_SC_CHARCLASS_NAME_MAXlsapi_header_offsetstrchrvfprintfsetgid_boundstm_wday__off64_t__fd__lenachBuf_sigsys_IO_read_base_SC_XBS5_ILP32_OFFBIGsend_req_received_notification_offsetIPPROTO_EGPLSAPI_reset_server_statesockaddrsigset_ts_defaultGids_keep_listenersecsm_cntUnknownHeadersreadfdsai_addrlenlongsopterr_SC_DEVICE_SPECIFIC_RLSAPI_Set_Restored_Parent_Pidpw_gecos_modem_iExtraChildrenLSAPI_No_Check_ppid_SC_PIPE_IO_write_base_SC_XOPEN_CRYPTvalueLenm_respInfotz_dsttime_SC_PHYS_PAGESlsapi_enable_core_dumpH_CACHE_CTRLH_COOKIE2_SC_ATEXIT_MAX__desttm_monclose_SC_SHRT_MIN_SC_FIFObitstimeH_USERAGENTs_min_avail_pages_SC_USER_GROUPSm_lLastActiveLSAPI_ForeachEnv_rlong intSOCK_PACKETsa_sigactionnotify_req_received_SC_XBS5_ILP32_OFF32dumps_worker_status_IO_marker__builtin_strncpys_ppidtm_yearlimitmax_children_SC_2_PBS_MESSAGEm_pRespBufEndtimevalorig_masktmCur_SC_XOPEN_REALTIME_THREADSfp_lve_is_availablepAddrs_defaultUidm_pChildrenStatus__fds_bits_SC_SPIN_LOCKSLSAPI_Set_Server_Max_Idle_Secswritem_bufRead_SC_SPORADIC_SERVERlsapi_close_connectionuint8_t_SC_LEVEL1_DCACHE_LINESIZE__sigaction_handlerlsapi_signal_SC_PRIORITIZED_IOin_addrSOCK_SEQPACKET__pid_t_IO_codecvt_SC_GETPW_R_SIZE_MAXpUgidheadershints_SC_XOPEN_VERSIONH_RANGE_SC_BC_SCALE_MAX_SC_2_C_VERSIONdup2strtolg_reqlong doubleparseEnvai_socktype_SC_THREAD_KEYS_MAXiov_len_SC_LEVEL4_CACHE_LINESIZEfd_setlsapi_MD5Init_SC_NL_TEXTMAXnonblocklong unsigned intlsapi_req_header_SC_LOGIN_NAME_MAXfind_child_statusIPPROTO_PIM_SC_XBS5_LP64_OFF64_SC_SPAWNmaxChildrennewlensi_statussigemptyset_pkeym_headerOff__RLIMIT_OFILEHTTP_HEADERS_SC_2_PBSs_proc_group_timer_cbpw_gid__errno_location_SC_XBS5_LPBIG_OFFBIG_SC_WORD_BITchar_SC_2_PBS_ACCOUNTINGm_pSpecialEnvListsin6_scope_idstdin_SC_AIO_MAX__oflag_SC_2_CHAR_TERMresolved_path_SC_LEVEL1_ICACHE_LINESIZE_IO_buf_baseai_flagsrealloc_SC_XOPEN_SHM__dev_t_SC_XOPEN_ENH_I18Nold_quitRLIMIT_CPU__glibc_reserved_IO_read_end_SC_ULONG_MAX_SC_TYPED_MEMORY_OBJECTS_SC_TIMEOUTS_SC_LEVEL2_CACHE_SIZEfinal_SC_XOPEN_UNIXm_pRespBufPos_IO_FILEin_addr_tm_fdH_HOST_IO_wide_datacookiestrlentzname_sifields_SC_LEVEL2_CACHE_LINESIZE__u6_addr16s_pidIPPROTO_AHLSAPI_ReqBodyGetLine_rtm_hoursetsidFlush_RespBuf_r_SC_THREAD_STACK_MINisPipe_SC_PII_OSI_Mm_respHeaders_global_counterRLIMIT_AS_SC_NL_MSGMAXsi_signom_pAppData__RLIMIT_MSGQUEUEachAddrm_inProcess_SC_THREAD_ROBUST_PRIO_PROTECT_ISgraph_lsapi_prefork_servertm_mdaypIntegerlsapi_siguser1__pad0_SC_BC_DIM_MAX__pad5_SC_LEVEL1_DCACHE_ASSOCmallocs_dump_debug_infos_avail_pages__u6_addr32_headerInfom_typesi_errnofinish_closelistensigno_SC_XOPEN_REALTIME_markersLSAPI_InitRequest_SC_SAVED_IDSpBindm_scriptFileOff_SC_INT_MAXsi_bands_log_level_namess_skip_writeH_VIAmemccpy_codecvtforkIPPROTO_ESPm_pRespHeaderBufEnd_SC_TRACE_LOGgetpwnamtimeout_SC_THREAD_PRIO_PROTECTg_fnSelectRLIMIT_FSIZE__builtin_memcpyst_rdevlsapi_http_header_indexpEnv_SC_OPEN_MAXst_devssize_tdlerrorheaderIndex_SC_UIO_MAXIOVLSAPI_Logm_pRespHeaderBuf__int32_tH_PRAGMA__uint32_tqsortpSecretFile__RLIMIT_NLIMITS__daylightIPPROTO_RSVPstrncpyH_REFERERIPPROTO_UDPLITESOCK_CLOEXECLSAPI_Set_Slow_Req_MsecsLSAPI_Prefork_Accept_r_sys_siglisthandler_SC_CHAR_MAXLSAPI_Get_ppid_ISlowerpEnvEndsigprocmaskm_pUnknownHeadergetpwuidm_reqState_SC_PII_XTIpRespHeadersleftkillGNU C17 8.5.0 20210514 (Red Hat 8.5.0-28) -mtune=generic -m64 -march=x86-64 -g -O2 -fPIC -fexceptions -fstack-protector-strong -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection=full -fplugin=gcc-annobinm_pRespBufm_iCurChildrensocketLSAPI_Write_r_SC_PII_OSI_COTSm_totalLenpasswdm_pIovecs_stderr_is_pipefstat__snprintf_chk_SC_PII_SOCKET__gid_tlsapi_sigpipe_SC_V6_LPBIG_OFFBIG_SC_MQ_PRIO_MAXgetcwdH_TRANSFER_ENCODINGH_IF_MODIFIED_SINCE__bsxai_nexts_enable_core_dump_SC_TRACE_EVENT_FILTERnodelaysin6_family__resolved_freeres_buf_sigfaultm_iChildrenMaxIdleTime_SC_THREAD_CPUTIMEsi_utimetv_sec_SC_VERSIONm_cntSpecialEnv_SC_C_LANG_SUPPORT_Rlong long unsigned intmemmovesa_handlersin_addr_cur_columnlsapi_load_lve_libtoWriteuid_t_SC_PIIsi_fd_SC_MAPPED_FILES_SC_LEVEL4_CACHE_SIZEIPPROTO_BEETPHfp_lve_jail_SC_2_FORT_DEVIPPROTO_IPm_pRespHeaderBufPosst_blockslsapi_initSuEXEC__bswap_16getpid__buf_SC_2_LOCALEDEFm_cntEnvlocaltime_r_SC_LEVEL1_ICACHE_SIZEreadBodyToReqBuftm_gmtoffIPPROTO_PUP_namesigval_IO_backup_baseH_KEEP_ALIVE_IO_read_ptr_SC_CHAR_BITLSAPI_Register_Pgrp_Timer_Callbackmd5ctx__socket_type__nbytes_nameLengetenv_freeres_list__aps_max_busy_workersIPPROTO_ETHERNETH_IF_NO_MATCHpEnvListrlim_tlsapi_readsun_pathtimezoneCGI_HEADERSsi_overrun__bswap_32pReq_SC_INT_MINlsapi_MD5Update_SC_RE_DUP_MAX_SC_PII_INTERNET_STREAMachBodyachPeerheader_SC_THREAD_ATTR_STACKSIZEfull_path_old_offset_SC_SIGQUEUE_MAXsiginfo_t_SC_FD_MGMTexpect_connected_SC_SYNCHRONIZED_IOLSAPI_STATE_IDLEvalueOffsighandler_t_SC_V7_ILP32_OFF32skipunlinksend_conn_close_notificationoptinds_accept_notifywritevH_ACC_LANG_SC_EXPR_NEST_MAX_SC_LEVEL3_CACHE_LINESIZElong long intm_pktHeaderin6addr_loopbackports_accepting_workersIPPROTO_IDP_flags2lsapi_prefork_serverallocateIovec_SC_MESSAGE_PASSING__ch_SC_REGEX_VERSIONm_iLenLSAPI_Set_Max_Children__d1setuidtv_nsecm_scriptNameOfflsapi_perror_SC_FILE_LOCKING_SC_AVPHYS_PAGES_SC_MB_LEN_MAXpHeader_ISdigitsockaddr_in6IPPROTO_SCTP_SC_PII_OSI_SC_ARG_MAX__ino_tsetsockopt_SC_MEMLOCK_RANGELSAPI_Finish_r_SC_SHARED_MEMORY_OBJECTSlsapi_resp_headersys_nerrin6addr_anym_pRequestMethodachError_SC_CHAR_MIN__realpath_chkiov_basem_lReqBegins_uids_total_pagespw_shell__namem_versionB0m_versionB1IPPROTO_GRE_SC_XOPEN_LEGACY_SC_NL_ARGMAXRLIMIT_COREsi_tidtobekilled_SC_THREAD_PRIO_INHERIT_SC_LEVEL3_CACHE_ASSOC_SC_NPROCESSORS_ONLNm_headerLenexpect_acceptingm_pIovecCurfdListenLSAPI_Init_Env_Parametersaddr_len_SC_HOST_NAME_MAXIPPROTO_TCPLSAPI_AppendRespHeader2_r_SC_COLL_WEIGHTS_MAX_SC_MONOTONIC_CLOCK__rlimit_resourcem_reqBodyReadLSAPI_Set_Max_Idle_SC_CLK_TCKLSAPI_ForeachSpecialEnv_rlsapi_buildPacketHeaderLSAPI_perror_r_SC_NL_SETMAXunsigned int_SC_BARRIERSbodyLenpBeginLSAPI_Accept_rwait_secslsapi_reopen_stderrstrcmpst_mtim__statbuf__RLIMIT_NICEfn_select_tshort intlsapi_notify_pidsi_sigvalsetrlimit_vtable_offsetaddrinfo_SC_IPV6mmapIPPROTO_ICMPlsapi_sigchild_SC_REGEXPlsapi_schedule_notifyLSAPI_Get_Slow_Req_Msecs_SC_V6_ILP32_OFFBIGstatmemchrtz_minuteswestsys_siglistH_ACC_ENCODINGsin6_portm_iMaxReqProcessTime__RLIMIT_RTPRIOGCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-28)GNUzRx 0D LXsEIB E(A0z (A BBBI A (D BBBA  @YGJB B(A0A80F(B DBb0BFC G  AABK Hk(\GADJ n AAA 4UAGK R CAG L JCG AG] AJ t C KFLBBE A(H0H (D BBBD  (D BBBA PXvFB A(D0D (A BBBB L(A BBBA$aAAD XAAHBBB B(A0A8D@N 8C0A(B BBBH $ OAf Q C E H@HYBBB A(D0J 0A(A BBBF xFEA C(G   (A ABBD M I c A  E M A k E E E E H V HFBB B(A0A8D`` 8A0A(B BBBD lT+BBB B(A0D8JYHPC Mi 8A0A(B BBBE LTMDd6BBB B(A0A8DP 8A0A(B BBBG  8J0H(G DBBK $,7EFF IIOTh|  4FAA G>  AABG EO D  A  (Y<JEDXS l]Ph H XAHlFBB B(A0A8LP 8A0A(B BBBH < FBB A(A0 (D BBBI i`0FBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH L$FBB A(A0H Q D 0A(A BBBH LFBB B(A0A8G 8A0A(B BBBF 4FHF\$pnCXJLlFBB B(A0A8DA 8A0A(B BBBA `BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0L BMD GL  AABA < =BAA G L@I@U  AABG $ TWEHG ag H SH FBB B(A0A8DPS 8D0A(B BBBF TX bIE D(C0P (F BBBM Q(H BBBAH FBB B(A0A8DP 8A0A(B BBBA T CBA A(G0` (A ABBD  (C ABBA J8T -FBD D(D@T (A ABBB  ( lECGF AAI L !cBG A(D0 (A ABBE XD0 4 ZH 10\ pFAA G@7  AABF  @LsL FBB B(A0A8G 8A0A(B BBBG   $ 8 L ` t     <  FBA K(G (A ABBG <FEE D(D0M (C BBBB X(HlFBH E(A0E8I@ 8A0A(B BBBE (FED ABH BBB B(A0A8G 8A0A(B BBBJ D0FBB A(A0G 0A(A BBBF Lx FBB B(A0A8G  8A0A(B BBBA    1 -  E2a~345.IWul -- "0s-Je s z )Y)2L0Yz+ k + w 0 Gw : X Ui s  s    x 5 P _ s(0x *  * # N0 al |  O& - =h9Y9 @ $@O e` rU+66 %  7 6S wm w   l      4 f   x    ]  '  ; ]\ m{ m     *+ *L k    \ \" k C k b    "   " $%@ `d0$%UE'xdE'''''D(m())* *+7+F+c,~, 0,.,=.u/*7u/[)0})011224C4k55667!7G7k78d X 8 8+8S:9y:9q9P q9: #h 3 (B:g0;0;H?   @  H?'^?GR^?tk?k????,?V?~???@,@T@z @+@+@?@?@;K@WK@TI ) p h d ` P H @# 80 X6TIYIzIJJJJ K(K?WTK \(b $o(|WUYUYZd Zd>qdiqdd!#$&()+2345671828F"KO(pRP [oy#)/5;AG8MXSY_ekqw+}=Nbw*@V %]+o17=CpIO@U[Tahgtms8yp6&(P,-./0) >Mcmy 1   " / 9 @C R a h v      @7      ! !'! #S!3!8!C!RK!@ Q!X!^!` p!p!Y!J!!0S!]!l!!!` "p i" %","@"#$Y"_"0%u"P'F"'F"'"(")l""""# #.#/1#00?#2P#Y#2s#z#4#5-#####7# 7l#7! $$$!$85$8ZN$@91a$9pv$:@$$0;$$$$P?$`? $p?%?%?:%?V%?u%@ % @ %0@%@@ %P@ %%%%&&& &`I4&I(B&JR&Ka&j&q&{&&&&&W&`Y &&&`d&d '.annobin_lsapilib.c.annobin_lsapilib.c_end.annobin_lsapilib.c.hot.annobin_lsapilib.c_end.hot.annobin_lsapilib.c.unlikely.annobin_lsapilib.c_end.unlikely.annobin_lsapilib.c.startup.annobin_lsapilib.c_end.startup.annobin_lsapilib.c.exit.annobin_lsapilib.c_end.exit.annobin_lsapi_sigpipe.start.annobin_lsapi_sigpipe.endlsapi_sigpipe.annobin_lsapi_siguser1.start.annobin_lsapi_siguser1.endlsapi_siguser1g_running.annobin_compareValueLocation.start.annobin_compareValueLocation.end.annobin_EnvForeach.start.annobin_EnvForeach.endEnvForeach.annobin_lsapi_cleanup.start.annobin_lsapi_cleanup.endlsapi_cleanups_stop.annobin_set_skip_write.start.annobin_set_skip_write.ends_skip_write.annobin_lsapi_MD5Transform.start.annobin_lsapi_MD5Transform.endlsapi_MD5Transform.annobin_lsapi_signal.start.annobin_lsapi_signal.endlsapi_signal.annobin_find_child_status.start.annobin_find_child_status.endfind_child_statusg_prefork_server.annobin_allocateRespHeaderBuf.start.annobin_allocateRespHeaderBuf.endallocateRespHeaderBuf.annobin_lsapi_set_nblock.start.annobin_lsapi_set_nblock.endlsapi_set_nblock.annobin_lsapi_accept.start.annobin_lsapi_accept.endlsapi_accept.annobin_parseEnv.start.annobin_parseEnv.endparseEnv.annobin_lsapi_init_children_status.start.annobin_lsapi_init_children_status.endlsapi_init_children_statuss_busy_workerss_accepting_workerss_avail_pagess_global_counter.annobin_readBodyToReqBuf.part.2.start.annobin_readBodyToReqBuf.part.2.endreadBodyToReqBuf.part.2.annobin_lsapi_close_connection.isra.4.start.annobin_lsapi_close_connection.isra.4.endlsapi_close_connection.isra.4s_worker_status.annobin_lsapi_writev.part.6.start.annobin_lsapi_writev.part.6.endlsapi_writev.part.6.annobin_lsapi_parent_dead.start.annobin_lsapi_parent_dead.endlsapi_parent_deads_ppids_restored_ppid.annobin_LSAPI_ParseSockAddr.part.13.start.annobin_LSAPI_ParseSockAddr.part.13.endLSAPI_ParseSockAddr.part.13.annobin_LSAPI_Log.start.annobin_LSAPI_Log.ends_stderr_is_pipes_log_level_namess_pid.annobin_lsapi_sigchild.start.annobin_lsapi_sigchild.endlsapi_sigchilds_pid_dump_debug_infos_ignore_pid.annobin_dump_debug_info.start.annobin_dump_debug_info.end.annobin_lsapi_check_child_status.start.annobin_lsapi_check_child_status.endlsapi_check_child_statuss_max_idle_secss_dump_debug_info.annobin_lsapi_perror.start.annobin_lsapi_perror.end.annobin_LSAPI_is_suEXEC_Daemon.start.annobin_LSAPI_is_suEXEC_Daemon.ends_uids_secret.annobin_LSAPI_Stop.start.annobin_LSAPI_Stop.end.annobin_LSAPI_IsRunning.start.annobin_LSAPI_IsRunning.end.annobin_LSAPI_Register_Pgrp_Timer_Callback.start.annobin_LSAPI_Register_Pgrp_Timer_Callback.ends_proc_group_timer_cb.annobin_LSAPI_InitRequest.start.annobin_LSAPI_InitRequest.end.annobin_LSAPI_Init.start.annobin_LSAPI_Init.endg_initedpthread_atfork_func.annobin_LSAPI_Is_Listen_r.start.annobin_LSAPI_Is_Listen_r.end.annobin_LSAPI_Is_Listen.start.annobin_LSAPI_Is_Listen.end.annobin_LSAPI_Reset_r.start.annobin_LSAPI_Reset_r.end.annobin_LSAPI_Release_r.start.annobin_LSAPI_Release_r.end.annobin_LSAPI_GetHeader_r.start.annobin_LSAPI_GetHeader_r.end.annobin_LSAPI_ReqBodyGetChar_r.start.annobin_LSAPI_ReqBodyGetChar_r.end.annobin_LSAPI_ReqBodyGetLine_r.start.annobin_LSAPI_ReqBodyGetLine_r.end.annobin_LSAPI_ReadReqBody_r.start.annobin_LSAPI_ReadReqBody_r.end.annobin_Flush_RespBuf_r.start.annobin_Flush_RespBuf_r.end.annobin_LSAPI_GetEnv_r.start.annobin_LSAPI_GetEnv_r.endCGI_HEADERS.annobin_LSAPI_ForeachOrgHeader_r.start.annobin_LSAPI_ForeachOrgHeader_r.endHTTP_HEADERSHTTP_HEADER_LEN.annobin_LSAPI_ForeachHeader_r.start.annobin_LSAPI_ForeachHeader_r.endCGI_HEADER_LEN.annobin_LSAPI_ForeachEnv_r.start.annobin_LSAPI_ForeachEnv_r.end.annobin_LSAPI_ForeachSpecialEnv_r.start.annobin_LSAPI_ForeachSpecialEnv_r.end.annobin_LSAPI_FinalizeRespHeaders_r.start.annobin_LSAPI_FinalizeRespHeaders_r.end.annobin_LSAPI_Flush_r.start.annobin_LSAPI_Flush_r.end.annobin_LSAPI_Write_Stderr_r.start.annobin_LSAPI_Write_Stderr_r.ends_stderr_log_path.annobin_LSAPI_perror_r.start.annobin_LSAPI_perror_r.endLSAPI_perror_r.annobin_lsapi_jailLVE.start.annobin_lsapi_jailLVE.endlsapi_jailLVEfp_lve_jail.annobin_lsapi_reopen_stderr.start.annobin_lsapi_reopen_stderr.endlsapi_reopen_stderr.annobin_LSAPI_Finish_r.start.annobin_LSAPI_Finish_r.endfinish_close.annobin_LSAPI_End_Response_r.start.annobin_LSAPI_End_Response_r.end.annobin_LSAPI_Write_r.start.annobin_LSAPI_Write_r.end.annobin_LSAPI_sendfile_r.start.annobin_LSAPI_sendfile_r.end.annobin_LSAPI_AppendRespHeader2_r.start.annobin_LSAPI_AppendRespHeader2_r.end.annobin_LSAPI_AppendRespHeader_r.start.annobin_LSAPI_AppendRespHeader_r.end.annobin_LSAPI_CreateListenSock2.start.annobin_LSAPI_CreateListenSock2.end.annobin_LSAPI_ParseSockAddr.start.annobin_LSAPI_ParseSockAddr.end.annobin_LSAPI_CreateListenSock.start.annobin_LSAPI_CreateListenSock.end.annobin_LSAPI_Init_Prefork_Server.start.annobin_LSAPI_Init_Prefork_Server.ends_max_busy_workersg_fnSelects_total_pages.annobin_LSAPI_Set_Server_fd.start.annobin_LSAPI_Set_Server_fd.end.annobin_LSAPI_reset_server_state.start.annobin_LSAPI_reset_server_state.end.annobin_is_enough_free_mem.start.annobin_is_enough_free_mem.ends_min_avail_pages.annobin_LSAPI_Postfork_Child.start.annobin_LSAPI_Postfork_Child.ends_req_processeds_keep_listeners_notified_pid.annobin_LSAPI_Postfork_Parent.start.annobin_LSAPI_Postfork_Parent.end.annobin_LSAPI_Accept_Before_Fork.start.annobin_LSAPI_Accept_Before_Fork.endold_childold_termold_intold_usr1old_quit.annobin_LSAPI_Set_Max_Reqs.start.annobin_LSAPI_Set_Max_Reqs.ends_max_reqs.annobin_LSAPI_Set_Max_Idle.start.annobin_LSAPI_Set_Max_Idle.end.annobin_LSAPI_Set_Max_Children.start.annobin_LSAPI_Set_Max_Children.end.annobin_LSAPI_Set_Extra_Children.start.annobin_LSAPI_Set_Extra_Children.end.annobin_LSAPI_Set_Max_Process_Time.start.annobin_LSAPI_Set_Max_Process_Time.end.annobin_LSAPI_Set_Max_Idle_Children.start.annobin_LSAPI_Set_Max_Idle_Children.end.annobin_LSAPI_Set_Server_Max_Idle_Secs.start.annobin_LSAPI_Set_Server_Max_Idle_Secs.end.annobin_LSAPI_Set_Slow_Req_Msecs.start.annobin_LSAPI_Set_Slow_Req_Msecs.ends_slow_req_msecs.annobin_LSAPI_Get_Slow_Req_Msecs.start.annobin_LSAPI_Get_Slow_Req_Msecs.end.annobin_LSAPI_No_Check_ppid.start.annobin_LSAPI_No_Check_ppid.end.annobin_LSAPI_Get_ppid.start.annobin_LSAPI_Get_ppid.end.annobin_LSAPI_Init_Env_Parameters.start.annobin_LSAPI_Init_Env_Parameters.ends_accept_notifys_enable_core_dumps_defaultUids_defaultGids_enable_lves_liblvefp_lve_is_availablefp_lve_instance_initfp_lve_enters_lve.annobin_LSAPI_ErrResponse_r.start.annobin_LSAPI_ErrResponse_r.end.annobin_lsapi_MD5Init.start.annobin_lsapi_MD5Init.end.annobin_lsapi_MD5Update.start.annobin_lsapi_MD5Update.end.annobin_lsapi_MD5Final.start.annobin_lsapi_MD5Final.end.annobin_readReq.start.annobin_readReq.endreadReqs_ackachBody.7025headers.7024.annobin_LSAPI_Accept_r.start.annobin_LSAPI_Accept_r.end.annobin_LSAPI_Prefork_Accept_r.start.annobin_LSAPI_Prefork_Accept_r.ends_conn_close_pkt.annobin_LSAPI_Set_Restored_Parent_Pid.start.annobin_LSAPI_Set_Restored_Parent_Pid.end.annobin_LSAPI_Inc_Req_Processed.start.annobin_LSAPI_Inc_Req_Processed.end.LC0.LC1.LC4.LC5.LC6.LC3.LC2.LC7.LC8.LC9.LC10.LC11.LC12.LC13.LC14.LC15.LC16.LC17.LC18.LC19.LC20.LC21.LC22.LC23.LC24.LC25.LC26.LC27.LC31.LC32.LC30.LC29.LC33.LC34.LC36.LC37.LC38.LC39.LC40.LC41.LC42.LC44.LC45.LC46.LC47.LC48.LC49.LC50.LC51.LC59.LC69.LC70.LC71.LC43.LC35.LC61.LC62.LC63.LC64.LC65.LC66.LC67.LC68.LC52.LC53.LC54.LC60.LC58.LC57.LC55.LC56.LC87.LC76.LC77.LC78.LC72.LC79.LC80.LC86.LC74.LC84.LC83.LC73.LC75.LC82.LC81.LC85.LC92.LC91.LC88.LC90.LC89.text.group.text.hot.group.text.unlikely.group.text.startup.group.text.exit.groupcompareValueLocationset_skip_write_GLOBAL_OFFSET_TABLE_sigactionsigemptyset__stack_chk_failreallocfcntlsetsockoptmmapmemsetsetsidread__errno_locationwritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkstrdupLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamenvirondlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectd \D   h o    2 9 H $O ,T g -o    h C M X h c z  h  h h a 8g.J5*T/0 *1%>Kw235R4Y5`6v\  "X 3/8M7`io89p3:?K_;<Rf=h{d h t8~KW>`i{h*$?*/?@GNw*"  ( h !A`!!!a"j#<q#\p$*}$$*$ %%%&A'((Y)))b***7+A+N+BW+_+}+C++++D,,{,D,,E,,h -n---F----.8.?.N.Y.~.G...H./*/ L/T/i/// /0_1111Q2v22/33-4O4|5N6h66666666I7W7777` 7` 77888#8-828<8G8T {8889'9G9$Q9L f9T 99999999999p:*:#:<:d G:Z:` d:h::::#:::: ;!;H;;;;;;|;;<<<<,<9<V<x<t<\ <<<$< :=S=e=o=}=|====<====>/>I6>@> F>w> > >>J>?K ??L#?D?Y?f?w?????@&@6@F@_@M@@@N@@@O@@@d @P@A'AQ,A@AFA%MARRAfAmAtASyAAhATAAAAAUAAAVA BBBW B4B;BBBXGB[BbBiBYnBBBBZBBB[BBB` B\BBBBhC` C\C]#C2Cd?CdEC`TC^YCqCwC\ChC*ChC_C`CazD` DDL D DbDDcE%E`1ENEUE*\EpEduEELEeEEDEE\EfEEgE<EEhEEiF4 FFjF%F,,FTGFkLFSFTXF_FPFFFFFlFFFdGm GG(G`/Gn4GQGmGG|GGGGdG`HoHH\"Hd,H`6H`DH\ZHXyHLHpHHHH<HTHHhHHDHXIh IIq+Ir7IAIKIsIIIIJJzK9LDLOLh JMUMdMh M4NOtOPuP*P.RhDR%JR$]R#}RRdR`RvSwmS|S!S"S"S# T$TT/T4GT+uT%T&T'TlThTTMTUU|*U$1UGUxSUeU}U(UyUUzUUdU`U$UTU)V{V V|,V=V%eV%V}V*V~V[VdV`V$VWW+W9WPWYWyWWW WWXh BXUXhXX$XXh XY$ YGYQYxYYYYYYYYh #Zh 3Z?ZeZ ZZZp[[[[[\C\\\t\\ \\\$] ^]u]]]]^^4^d B^$X^$]^s^^^^^_d __c +_D_c__ _ _ __I__ ` `%`\`k`-|`.```.``` a,aJ5abaqa` aa` aaaaaaabbh 3bK8bGbXb.gbpbvb{bbbbbbpb*bbbd bc` ch$cCcTcecvcccccc#ccLccd dd9dKdVdfdldd, s|2J +$,PX---D-Lpx 08)dl)))+ $,+ P+ Xw + w w  w   s D Ls ps x s   x  x 0x 8* dx l* *  *   $ ,PX99 9 D 9L p x       0 8 6d l 6 6 w 6 w w $ w, P X         D L p x     ]  ]0 ]8 md ]l m m  m   $,PX****DLpx\\\k \ k 0k 8 dk l  " ""$%$",$%P$%XE'$%E'E''E''''D'L'p'x('(()( )0)8*d)l**+*++,$+,,P,X.,..u/.u/u/)0Du/L)0p)0x1)01121 20284d2l4454556$5,6P6X767777778D7L8p8x8888:98 :90:98q9d:9lq9q9:q9::0;$:,0;P0;XH?0;H?H?^?H?^?^?k?D^?Lk?pk?x?k????? ?0?8?d?l??????@$?,@P@X@@@@+@@+@+@?@D+@L?@p?@xK@?@K@K@TIK@ TI0TI8IdTIlIIJIJJJ$ J, JP JX K J K K W K W!W!UYD!WL!UYp!UYx!Zd!UY!Zd!Zd!qd"Zd "qd0"qd8"dd"qdl"d % & ' (]CC C(X 01CC3C9C> CE(CJ0CP8CU@C[HCbPCqXC`ChCpCxCCCCCCCCCCCC+C4CHCSCYCiCm C(C0C8C@CHCPCXC`ChCpC!xC+C7CDCTCgC~CCCCCCCC  $+ $ $) #0 $8 < $YC $ 7J $"$Q $uV $d $7n $ z $* $* $! $% $ $e- $@4 $' $ $q $  $# $' " $. $E: $oM $Y $ e $q $ $F% $a $ $+ $ $4 $ $5 $  $+( $/  $ $ $n $  $, $9 $o.F $3T $U8a $[*n ${ $ $ $ $j $j( $)* $ $  $/ $  $j7  $ $.&5 $A $rM $/b $p $F  $* $!0 $ $  $$ $! $ $s5 $.1 $7( $!5 $B $7Y $!f $s $$ $f. $  $ $ $y $$ $ $ $} $f)( $/? $ L $Y $Qp $w| $  $ $9 $2. $M $ $' $( $ $j( $&, $18 $^ $.j $! $ $" $ $h $$ $`+ $p8 $2 $.. $b*: $^F $!S $o.` $n $z  $2" $# $  $ $ $m $ $ $< $&( $5 $E0B $?&O $\ $i $v $E $% $I $ $(0 $ $) $  $ $'3 $1 $. $7 $o, $9 $F $)S $` $0m $%.z $( $ $ $ $ $g! $# $& $g $%& $ 2 $J> $4Z $ f $6x $#&~ $ * $ $. $g5 $  $ $$ $' $t $ $C $h $' $|7 $8 $ $* $U $0 $y $l $  $, $49 $#G $S $0e $k $b q $ w $ } $# $ $! $#+ $ $ $! $ $V $1 $a8 $- ( $ -5 $@B $O $\ $ %i $v $ $5 $ $ $S' $J( $ $! $ $ $ $0 $= $ I $*U $a $&m $ y $1 $C $44 $j $6 $ $N* $ $ $ $6) $ $X $ $ $" $ 2 $  $/ $  $S4 $ $R3 $$ $t4* $10 $%6 $ < $B $R H $-N $v.T $Z $` $mf $wl $1r $x $^~ $q( $k# $ $V6 $* $2 $f $e1 $; $  $  $  $W/ $O $ $/ $/ $+ $V- $G $(4 $ $d $~* $" $t1 $K  $-& $, $'2 $8 $> $5D $J $(#P $E$V $\ $b $#h $r'n $t $z $1 $ $5 $) $ $S $5 $8  $3 $u  $ $Q# $ $& $  $& $% $% $|# $ $ $ $ $R0  $u+ $4 $Z) $I1" $f( $9%. $34 $ : $@ $ F $XL $R $ X $O^ $d $L&j $p $Y5v $ | $' $h $6 $ $ $=! $ $v$ $#% $H5 $) $! $ $7 $0 $ $. $ $. $S. $Z $ $ $1 $  $ $Y  $3 $$ $k6* $0 $b6 $< $B $="H $8N $k3T $Z $~` $$f ${"l $r $ux $~ $s& $Z& $  $ $$ $K% $I $! $  $  $ $$  $ $A8 $ ${- $6 $2 $- $ $) $/ $b  $% $ $( $"  $&& $ , $'2 $8 $5> $2D $&/J $ P $#V $7\ $b $F2h $n $At $z $p  $. $ $ $H $y $N $ ( $  $2 $ $  $" $^ $ $& $" $9 $f/? $7E $XK $; Q $06W $] $0c $i $3o $u $8{ $ $* $<5 $) $1' $( $  $A $F  $ $ $' $(N $v[ $En $4z $2 $ $W  $  $. $ $4 $. $8 $X $ $r%- $7; $%I $W $#e $ys $q $ $ $- $#  $  $1 $ $b  $|8 $2 $% $" $n( $;. $4 $k : $&@ $*F $ +L $ R $^ X $-^ $d $0j $p $/v $80| $c# $ $) $- $}3 $ $ $$5 $05 $( $6 $! $4$ $2  $- $ : $J)G $3T $0a $Q n $U{ $/ $. $1* $5 $$ $R $ $ $02 $  $- $q: $ H $4U $2b $" r $#w $  $  $4 $6 $  $ $  $& $  $4 $ $ $," $!/ $&< $*I $)V $q/c $p $'-} $ $5 $ $R $? $% $`% $ $ $Q $+  $ $& $ 3 $@ $4M $-Z $+g $ t $6 $ $q" $W $' $ $' $ $o $ $  $( $A" $/ $d < $m I $L $ $# $ $7+ $eO $i $  $ $2 $ $} $ $W! $  $gl $ $!1: $HGP $+']f $s| $@h  $( $ $ $) $ $,5 $3BK $'X0a $0nd w $/ $0- $`  $5X  $ P  $(( # $09 $$Fx_ $"1l  $) $$@ $` $n) $92 $- p $5 l( $"6 h? $3M dV $ d `m $ r $ X $+ P $! H $I @ $0*! $8!8[! $c! $K/!0! $2!)! $K! $~! $!(! $ !(" $" +" $(9"B" $(P" $0^" $0l" $z" $" $*"" $4(" $&" $" $" $," $" $ # $<.# $8# $,# $ ":# $H# $0W# $/3d# $Vr# # $## $"## $4## $## $&## $ $@ $ $$"$ $0$9$ $CF$ $R$dy$ $$`d$ $$ $ $ $$$ 1$ - % % j % ~$% R3% 7% pF% hJ% @V% $ ^%Ku% $% % % X% P% $% % % ( % " %3K%3K% s % q %  &  &  &  &QK$&QKA&  E&  N&  R&  [& 8 _& 6 i&pKs& " & _ & [ &  &  &  &  &~K&K& "`&  &  &  &  & M & K 'K ' "' r !' p *'  .'  7'  ;'  A'QK_'K' $U1'J'  '  '  '  ' h ' \ '  '  ' "@ ( ( (dJD(|JN( "p_( c( l( p( y( @}( <(J(J(J( "( ( ( ( ) )  )J/)J9) "J) $N)  W) d[) bd) h) m)J{)J) $#)I) $u) $|) $ *`I"* $D1.* 2* 7* $C* G* L* $+X* \\* Ra* $m* q* v* $'7* <* 4*dI* "* * * * *I*I*I+IB+ $5N+P@p+ t+ + + + + + + + $+ + +pF+ $!+F ,@,@3, 7, <,@Y,@c, " t, 6x, 4},@,A,A, ], Y,A,5A,5A- - -DA:-[AD-[Aa- e- j-jA-A-A- - -A-A-A- - .A!.B+.BH. )L. 'Q.Bn.)Bx.)B. N. L.8B.PB.PB. s. q._B/wB/wB// 3/ 8/BU/B_/B|/ / /B/B/B/ / /B/B/ " 0 " 0  0 0 E 0 ?)0 " 60 :0 C0FM0Fj0 rn0 ps0F0G0G0 0 0"G0DG0 " 0 0 1 " 1 1 r 1DG*1DGG1 K1 T1 AX1 ;]1UG1`G1`G1 1 1 1 1qG1G1G 2 2 2 A2 ?%2 o)2 m.2GE2U2Gm2H2H2;I2]2F2C]2G3Co 38G3C&3'C73CVG3QCQ3 "@ ^3 "@ g3 k3 t3fC~3fC3 3 3uC3hE3 " 3H3  3 3H 4H#4I84yEM4C^4Ey4C4E4E4 " 4 " 4 Z4 V4E4C4E4C5E#5C-5FH5CR5"Fm5Cw5PF5]5\F5H5]C5C5 H5C5C5C6C*6 .6 760DL6 P6 \6Ff6F6 4 6 2 6F6F6F6@6C7@7@#7C-7@B7C+L7@a7C=k70A7CN7VA7Cb7qA7}A7Cw7A7C7A8A8A#8C-8AB8CL8BY8$Bn8Cx8?B8KB8C8fB8rB8C8B8B8C8B 9B9C*(9B=9C@G9D_9Dl9D9C9E9C95E9RE9`E9EI9 $O7: $14: $xF: $1S: $ a: $ ~: $&: $]: $%: $/; $3; $+?;@@R; $Z;0@m; $(8y; @; $0+;@; $; $L";?; $; $B;? < $< $5!<?8< $PH< $/P<?g< $=w< $3<p?< $$< $6<`?< $P< $w<P?< $}= \ = X = $I+=`Y-= $D19=  ==  M= !!Q= !b= !f= !k= $E7w= ="{= /"= $i= $)= "= $ = $3=aZ= "= "=iZ >(_ > $,> #0> #:>@[D> "U> ($Y> $b> ($f> $o> $s> $x> "> %> %> 0&> &> 5'> +'> '> '> (> '> I)> /))? "A?]Z? W*^? S*c?]u?`_? *? *?_?_?_?c? "? +? +? "@c@ " @ +$@ +-@ +1@ +:@  ,>@ ,H@cR@co@ 1,s@ /,|@ W,@ U,@ },@ {,@c@c@E[@t[@[ A[#A[HA[mA"\AG\A\A` A\A\A\B\&Bb]LBy]YB]}B_B]B_B@`BS`B``Bo`C`EC`RC`_C`C`C]CaC9aCCCaC](CaCaD]D$J>2Ju;?J;WJ;wJJ;J;JJ<J@J!< KK=<7KAK<RK` \K<sK<K<K<K>=KW=Ks=K L=$L3L=ML\L=vL@L=LL:>L]LD>L>L> M> MC*M??MCIM'?^M]hM5?MH?M $M:M $D1M 2M  2M ;M $M a2M _2M;N%;N $N95N $D1AN 2EN 2JN $!VN 3ZN 3cN:mN " ~N *3N (3N " N:N " N O3N M3N u3N s3N 3N 3N:N "P N 3N 3O 3O 3O 4O 4O:'O:HO9UO9bO9oO:OO::O:O:O:O $O $O $D1 P $P $&&P $ 3P $@P $MP $ZP $E7P $(P $P $iP $)P $P $!P $ P $3Q $Q $Q@91Q $9QLQ $TQkQ $!wQ G4{Q 94Q $eQ 4Q 4Q $z5Q o5Q c5Q $Q 6Q 5Q $Q 6Q 6Q $Q ^7Q X7Q $Q 7Q 7QCR]P&RO=R[R]eR|RR R]RR $RR $R 8R 7S $!S 8S 8S $,S6SSS 8WS 8`S  9dS  9mS 69qS 29vSS]S S3S<SdS]pTm&T>TUTjTCRtTT $T T $T y9T o9T $T 9T 9T $!T :T :T U U ;$U ;-U B;1U @;:U j;>U f;CU dU UX Us UCU $7U $U $U $1V $5V $V $ ,V $R!;V $CV8ZV $fV ;jV ;oV ${V ;V ;V $X$VV $V ;V ;V $V *<V $<V V W u< W s<W <W <"W <&W <-W $5WLW $\W $qhW W $5W <W <W .=W "=W $.W $1W Xl 0Xs NX $VX8|X $DX $!X $X $,X 7X $D)X =X =X $O X =X =Y $v Y X>#Y T>5YM7TY[7rY7Y $%Y $D)Y $ "Y $'Y $Y $K#Y $ Y $3Z $"Z59Z $eEZ >IZ >NZ $O ZZ J?^Z :?oZ @sZ ?Z P@Z J@Z $Z $6Z @Z @ZR6Zl6Z6[6@[6^[6k[6x[6[6[ $[ $D1[ $[ $$[ $<6 \2"\ $D1.\ @2\ @7\ $C\ /AG\ 'AL\ $X\ A\\ Aa\ $m\ Aq\ Av\ $ \ LB\ FB\ B\ B\ "P \ B\ B\ " \ (C\ $C\3\ $$\ dC] ^C]4]4)] " :] C>] CG] CK] CT] +DX] )D]]14}]I4] " ] TD] PD] D] D] D] D]S4]33]3^ $^'&^ $D19^_(C^ "P^ DT^ D]^ )Ea^ 'Ej^ QEn^ MEu^ $6^'^ $D1^ E^ E^ E^ E^ KF^ CF^'^ $ ^P'_ $D1"_ F&_ F6_ G:_ FK_ kGO_ cGT_'q_ $ }_0_ $I*_ G_ G_ 6H_ .H_ H_ H_ 5I_ )I_ $_ I_ I` J ` J`{ ` $ ,`0%C` $D1O` JS` Jc` Kg` Kx` L|` L` lL` hL` L` L` $4` L` L` 9M` 5M` $` }M` oM` "@` $ a &Na Na $ !a N%a N*a $6a N:a N?a $6Ka 4OOa &OTa $`a Oda Oia $ua Pya P~ax&a cPa aPa&a $a Pa Pa&ac&a "pb Pb Pb Qb P(b /Q,b -Q2b&[b%bE'b $|b#b $D1b ^Qb RQb Qb Qb Rb }Rc JSc >Sc Sc S!c $4-c NT1c BTBc TFc TKc $Wc 5U[c #U`c $C#rc#c $ c Uc Uc $6c cVc [Vc $c Vc Vc $c Vc Vc$cd$4d>d$Rd$%qd $}d d $}d d $D1d EWd 3Wd $`d  Xd  Xd $/7 e 4Xe 0Xe $$e "`;e "`De rXHe lXQe XUe X^e "ke Xoe Xxe RY|e JYe Ye Ye Ye Ye *Ze &Ze dZe `Ze "e Ze Ze "e Ze Zee"e!fd!(f $U:f $D1Gf $`_f $4xf $ f $f $6f $f $f $f $0f $D1g $ g $1-g $Eg $Rg $fyg $z g $Kg(g $D1g e[g Y[g [g [g o\g g\g(h "h \h \(h ],h ]5h h]9h f]>h "Lh ]Ph ]Zh)qh(h!)h])h $b'hp h $D1h $3h ]h ]h $Q i T^ i R^i i " *i y^.i w^7i ^;i ^Di ^Hi ^Oi $[i2ri $D1~i ^i ^i $|i _i _i y`i i`i $i 7ai 'ai $3i ai aiU2i " i bi bj b j bj bj bjU26jz2Sj2zj2j $,j $D1j $j $3j $j $Q j $.k $k $Y2!k $--k`Dk $D1Pk cTk  cYk $ek cik cnk $Q zk c~k ck ddk Xdk $/k  ek ekk "k nek jek ek ekl l "l e!l e*l f.l f7l Af;l =f@l "Il {fMl wfVl `l }l fl fl fl fl fl fl l! l $<'ll $D1m *gm  g m $m gm gm $Q *m h.m h3m $P?m thCm jhTm hXm h]m $+im (imm  irm $~m im im $m im im $m jm jm jm jmm " m km km Tkm Pkm kn kn$nCn(Mn(jn knn ksn(n ln kn4nn $ nn $D1n Tln Hloo+o l/o l4oNo mRo mWono $/o $D1o $o $ o0o $D1o $r*o ;mo 7mo zmo tmp $p(p $D14p m8p m=pJpWpdp&rp $zpp $D1p #np npp "p qnp onp np np $D p/q $D1 q nq nq/.q/Fq/fq!0{q $e4q.q $D1q Doq 8oq#/qP/qX/qm/ r $67rW,r $D18r os(QsWisXsFXsXsXsXsXtXtKY9tUYGt $2 St`jt $D1zt $ tpttt $$)tt $D1t Eqt ;qt qu qu $ u Mru Kru(u "9u rr=u prFu rJu rYu3cu "@tu rxu ru ru ru "@u  su  su<uuu Esu Csu v0vCv]Mv "^v jsbv hskv sov stvdvCovvv=vOwmw&w $_0.wTw $ `wsw ${ww $ww "w $?w sw swwwwx xz $D1z $ { $=#{ $${ $01{ $O{ $]a{ $D1{ ${ $~{ $I*{ $ {,{ $D1{ s| s| Pt| Ht&| t*| t;| t?| tD| $U|H,p|,|]|,|C|,| $ | $D1 } $&%} $7} $D1D} $C#R}[} $1i} } $6}+} $D1} Yu} Qu} $^} u} u} $d} %v} v} $4~ uv~ qv#~q+-~ ">~ vB~ vK~ vO~ vY~+~C~;+~E+~[+~c+~+~+~+ $ $ $r 6 $*\ ${ $. $  $D1 $f $ $ $ $D14 $A $P $s^ $D1w $ $R( $# ̀ $0؀ w܀ w $ jw fw $/7 $ w w $+& x*  x/ $6; Sx? GxD $ P xT xZ $'x $1 $ $0 $& $́ $ $x $3 $ $&0 = $D1I yM yR $^ Fzb @zq zu zzH $D3 $D1ł $ׂ $D1 $ $ $ $q* $7 $fQ $+p $1 $ $"ă $D1҃ $ $2  , z0 z5 $$A {E {V &|Z  |_  $6 $3 $S҄ $G ܄ $"0 $) w| o| $m+ | |5`Xp $[(Ѕ $m-؅ $P $3@, $"8 E}< =}A $M }Q }VVnwC[ $*@ $ʆ ~Ά  ~ކ ~ ~ \ H $D 6 0.0eo "P     ܀ ڀ̇]ۇcc   / - W U$NC"YBvOS " ~ z ˆ ˈ ψ ԈX # , G0 E9 n= lBjC2~ "    ĉ ȉ ͉C8 " "#  , P0 N5)KCF\iw $s $D1 $ $- $/ $ˊ $>܊ $ $/ $0 $+ $  $* $7 $H $ T $a $=r $ ~ $f3 $ $. $ $ $͋ $ ދ $ $ $ $m $p $, $0? $P $p\ $j $ $ $ $5 $.֌ $ $ $  $ $A-( $5 $r7I $Z $f $%t $91 $- $/ $- ύ Ӎ t܍   H B "    ' @+ <0 "09 |= vF P m Džq Ņz ~     Ŏ0 @ @  6 4!G 9Q Lw Vw v c Y ߆ Ն [ Q ه ͇ŏ mɏ aҏ ֏  e+5 "`BPgy [ S   & Đ Ȑ    X R''$ ( 1 ʋ5 ȋ> B G<lv " , * S Q z vϑFّ "  Nx "1 ٌ5 ׌> B K (O $Yc "Pt ex a   ͍ ˍ "˒ ϒ ؒ ܒ  k (C2P{9ؓ Cܓ ? " "$ ( |1 V5 J> B ؏K vO pX "e i r v {z”ؔ)      ?# 1T)^){  ޒ 5 1 q m)  ɕ ԓ͕ ̓֕ <ڕ 4   Ô {* " * . 7 ";  D HH FQ nU lZ " h l u Εy ̕~*D* "p Ö ̖ 0Ж .ٖ Vݖ T)**8*J,e i y|, "  y     "̗ MЗ Gٗ ݗ - "@ ԙ ҙ   -7{-A{-^ #b k ^o \t{-  -r-Ҙ].ߘ..- "p  # "p, 0 9-C-` d m q v---<.ۙC.R..%]X;x.Ex.b ٛf ӛkx..]8.00ך 1ۚ % ɜ   "0, "= 0A (J N W [ ` "i Bm 6v ɟz ş    {   J D0ƛ "ܛ    11 " + / 8 /< -A1dc1|114 `Ü R̜  М ٜ ݜ  " / # 5# ' 1>5J FN @Sg5lq5v "P      ޥ5ǝ7   ] W7=7X \ e i r v 7 " ? 5   3 -7֞8'868@88(KC G |P <T :b,Ll "} c _   ת Ӫ "   0L0Lݟ I G n l  =L!HL4L> " O S X " a e n 2r *{LL    LѠ ۬ՠ ٬8M8M   % #! J% H*@M? qC mL@MV@Ms w  έ ̭  NMYMʡMԡ "     "    ^ T'M1MN ϯR ͯ[ _ h l qMMM D B i gȢ ̢ ѢM  MNN< ް@ ܰI M V +Z )_Ny!N!N S Q x v  !Nԣ ȱأ Ʊݣ8NyO " " ' "0 4 = A JO_ @c >l ep c|OPOP  OP Ť ΤOPؤ "0 Գ ҳ "0   "  kP! "p2 G6 E; "pD nH lQ U `yPj "{   "  ߴ  P "ĥ Cȥ Aͥ "֥ jڥ h  P "`   "` ޵# ܵ, 0 ;PE "V +Z )_ "h Rl Pu {y wP "   " ۶ ٶ ¦ ͦPצ "` ( & "` O M v tP "- 1 6 "? ÷C L P ]Q{Q ' #"Q a _ç ǧ Ч3Qڧ3Q  3Q ݸ ۸ " .bQC +G %P xT v]Qg "x |  " ۹ ׹  Q "0¨ "0Ш :Ԩ 8ߨQ "p "p _ ]Q" "0 "> B P\UZ\Uw { \U κ ̺iUUթpNN P)C30VQC6[/Wu]vRvR   ê ȪvRݪ = ;R R "' j+ `0 "9 = ٻF J ~S W ` (d m q z  ~  E ?_S "p    ɫ ߾ͫ ۾֫ ګ  C = "S " " & / 3 < @ FS^SSSǬTѬ "`       6 ( "  ( *, 5U? "U Y b "t xx rhWhW  hW­W 3T&hW=]RU\UuVV] TϮ\TyTTT6UNAV[iVhVCVVCɯVJWC W"C3T@T[CeUrU]8U]pİUΰU     6 4U ". d2 b;UE " R V _UiU  UU   ñ ȱ5Uٱ(P CTWU2C< WVC&m Pw P * ( T P P ò Ȳ.P߲TW $= $ $. $g $& $& $7 $7 $# $#( $, $ 4 $b8 $bA $>E $M $ Q $ Z $0^ $0g $)k $)s $w $ $m $m $H $H $9 $9 $j* $j* $ $ $ ³ $ ˳ $(ϳ $(س $ ܳ $ $% $% $ $ $ $ $ $  $ $ $/" $/+ $k"/ $k"8 $$< $$D $H $P $ T $ \ $M` $Mi $m $u $+y $+ $) $) $[' $[' $ $ $+ $+ $G- $ $ ô $ ̴ $д $ٴ $7ݴ $7 $ $ $H4 $H4 $, $, $" $" $^ $^! $(% $(- $^21 $^2: $> $F $*J $*S $c7W $c7_ $c $k $Z8o $Z8w $%{ $% $# $# $v $v $ $ $ $ĵ $ȵ $е $/Ե $/ܵ $_ $_ $ $ $2 $2 $+ $r! $  $* $" $* $f. $f6 $$: $$B $ F $ O $eS $e\ $` $h $l $t $-x $: $4 $4 $) $) $J $J $J $ $ $ $ $ȶ $̶ $Զ $+ض $+ $v $v $ $ $3 $3 $ $T+'-(- 38]QCp(sCovC]C",C2C85CF ʿI(   4H \00L`0     \ 0  $L@ X0@Xl`p,@\0p` p 4 #0%8P'L'`'t()+P , , . / 00\ 2 2 4X 5 7  7 7$ 88 8L @9` 9 : 0; P? `?( p?< ?P ?d ?x ? @  @ 0@ @@ P@`I\IpJKK4W|`Y`dd.symtab.strtab.shstrtab.rela.text.data.bss.rela.gnu.build.attributes.text.hot.rela.gnu.build.attributes.hot.text.unlikely.rela.gnu.build.attributes.unlikely.text.startup.rela.gnu.build.attributes.startup.text.exit.rela.gnu.build.attributes.exit.rodata.str1.1.rodata.str1.8.rodata.rela.data.rel.local.rela.data.rel.rela.data.rel.ro.local.rela.debug_info.debug_abbrev.rela.debug_loc.rela.debug_aranges.debug_ranges.rela.debug_line.debug_str.comment.text.hot.zzz.text.unlikely.zzz.text.startup.zzz.text.exit.zzz.note.GNU-stack.note.gnu.property.rela.eh_frame.groupP@:PT:Pl:P:P: d@@A@G:&`ep ,n 6nt"1@ : LT[TV@P0: u((@0:@0:ЖЖ@0:22/"D /`8 *@:D?@:S N@p:kf@(\:!wa-i@ :$/0@0:& 0`lJR@H:)0}807.eeueLe eeeeee.h FA@((:8x4; ('PWPK ]k##&gems/ruby-lsapi-5.6/ext/lsapi/Makefilenu[ SHELL = /bin/sh # V=0 quiet, V=1 verbose. other values don't work. V = 1 Q1 = $(V:1=) Q = $(Q1:0=@) ECHO1 = $(V:1=@ :) ECHO = $(ECHO1:0=@ echo) NULLCMD = : #### Start of system configuration section. #### srcdir = . topdir = /opt/alt/ruby27/include hdrdir = $(topdir) arch_hdrdir = /opt/alt/ruby27/include PATH_SEPARATOR = : VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby prefix = $(DESTDIR)/opt/alt/ruby27 rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) rubyarchprefix = $(DESTDIR)/opt/alt/ruby27/lib64/ruby rubylibprefix = $(exec_prefix)/share/ruby exec_prefix = $(DESTDIR)/opt/alt/ruby27 vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby rubyarchhdrdir = $(DESTDIR)/opt/alt/ruby27/include vendorhdrdir = $(rubyhdrdir)/vendor_ruby sitehdrdir = $(rubyhdrdir)/site_ruby rubyhdrdir = $(DESTDIR)/opt/alt/ruby27/include rubygemsdir = $(DESTDIR)/opt/alt/ruby27/share/rubygems vendorarchdir = $(DESTDIR)/opt/alt/ruby27/lib64/ruby/vendor_ruby vendorlibdir = $(vendordir) vendordir = $(DESTDIR)/opt/alt/ruby27/share/ruby/vendor_ruby sitearchdir = $(DESTDIR)./.gem.20260423-2006031-v30xda sitelibdir = $(DESTDIR)./.gem.20260423-2006031-v30xda sitedir = $(DESTDIR)/opt/alt/ruby27/share/ruby/site_ruby rubyarchdir = $(rubyarchprefix) rubylibdir = $(rubylibprefix) sitearchincludedir = $(includedir)/$(sitearch) archincludedir = $(includedir)/$(arch) sitearchlibdir = $(libdir)/$(sitearch) archlibdir = $(DESTDIR)/opt/alt/ruby27/lib64 ridir = $(datarootdir)/$(RI_BASE_NAME) mandir = $(DESTDIR)/opt/alt/ruby27/share/man localedir = $(datarootdir)/locale libdir = $(exec_prefix)/lib64 psdir = $(docdir) pdfdir = $(docdir) dvidir = $(docdir) htmldir = $(docdir) infodir = $(DESTDIR)/opt/alt/ruby27/share/info docdir = $(datarootdir)/doc/$(PACKAGE) oldincludedir = $(DESTDIR)/usr/include includedir = $(DESTDIR)/opt/alt/ruby27/include localstatedir = $(DESTDIR)/var sharedstatedir = $(DESTDIR)/var/lib sysconfdir = $(DESTDIR)/etc datadir = $(DESTDIR)/opt/alt/ruby27/share datarootdir = $(prefix)/share libexecdir = $(DESTDIR)/opt/alt/ruby27/libexec sbindir = $(DESTDIR)/opt/alt/ruby27/sbin bindir = $(exec_prefix)/bin archdir = $(rubyarchdir) CC_WRAPPER = CC = gcc CXX = g++ LIBRUBY = $(LIBRUBY_SO) LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a LIBRUBYARG_SHARED = -Wl,-rpath,$(archlibdir) -L$(archlibdir) -l$(RUBY_SO_NAME) LIBRUBYARG_STATIC = -Wl,-rpath,$(archlibdir) -L$(archlibdir) -l$(RUBY_SO_NAME)-static $(MAINLIBS) empty = OUTFLAG = -o $(empty) COUTFLAG = -o $(empty) CSRCFLAG = $(empty) RUBY_EXTCONF_H = cflags = $(optflags) $(debugflags) $(warnflags) cxxflags = optflags = -O3 debugflags = -ggdb3 warnflags = -Wall -Wextra -Wdeprecated-declarations -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable cppflags = CCDLFLAGS = -fPIC CFLAGS = $(CCDLFLAGS) -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection $(ARCH_FLAG) INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) DEFS = CPPFLAGS = $(DEFS) $(cppflags) -DRUBY_2 CXXFLAGS = $(CCDLFLAGS) -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection $(ARCH_FLAG) ldflags = -L. -L/opt/alt/ruby27/lib64 -Wl,-rpath=/opt/alt/ruby27/lib64 -fstack-protector-strong -rdynamic -Wl,-export-dynamic dldflags = -L/opt/alt/ruby27/lib64 -Wl,-rpath=/opt/alt/ruby27/lib64 ARCH_FLAG = -m64 DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) LDSHARED = $(CC) -shared LDSHAREDXX = $(CXX) -shared AR = ar EXEEXT = RUBY_INSTALL_NAME = $(RUBY_BASE_NAME) RUBY_SO_NAME = ruby RUBYW_INSTALL_NAME = RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version_dir_name) RUBYW_BASE_NAME = rubyw RUBY_BASE_NAME = ruby arch = x86_64-linux sitearch = $(arch) ruby_version = 2.7.0 ruby = $(bindir)/$(RUBY_BASE_NAME) RUBY = $(ruby) BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME) ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h RM = rm -f RM_RF = $(RUBY) -run -e rm -- -rf RMDIRS = rmdir --ignore-fail-on-non-empty -p MAKEDIRS = /usr/bin/mkdir -p INSTALL = /usr/bin/install -c INSTALL_PROG = $(INSTALL) -m 0755 INSTALL_DATA = $(INSTALL) -m 644 COPY = cp TOUCH = exit > #### End of system configuration section. #### preload = libpath = . $(archlibdir) LIBPATH = -L. -L$(archlibdir) -Wl,-rpath,$(archlibdir) DEFFILE = CLEANFILES = mkmf.log DISTCLEANFILES = DISTCLEANDIRS = extout = extout_prefix = target_prefix = LOCAL_LIBS = LIBS = $(LIBRUBYARG_SHARED) -lm -lc ORIG_SRCS = lsapilib.c lsruby.c SRCS = $(ORIG_SRCS) OBJS = lsapilib.o lsruby.o HDRS = $(srcdir)/lsapidef.h $(srcdir)/lsapilib.h LOCAL_HDRS = TARGET = lsapi TARGET_NAME = lsapi TARGET_ENTRY = Init_$(TARGET_NAME) DLLIB = $(TARGET).so EXTSTATIC = STATIC_LIB = TIMESTAMP_DIR = . BINDIR = $(bindir) RUBYCOMMONDIR = $(sitedir)$(target_prefix) RUBYLIBDIR = $(sitelibdir)$(target_prefix) RUBYARCHDIR = $(sitearchdir)$(target_prefix) HDRDIR = $(rubyhdrdir)/ruby$(target_prefix) ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix) TARGET_SO_DIR = TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) CLEANLIBS = $(TARGET_SO) CLEANOBJS = *.o *.bak all: $(DLLIB) static: $(STATIC_LIB) .PHONY: all install static install-so install-rb .PHONY: clean clean-so clean-static clean-rb clean-static:: clean-rb-default:: clean-rb:: clean-so:: clean: clean-so clean-static clean-rb-default clean-rb -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time distclean-rb-default:: distclean-rb:: distclean-so:: distclean-static:: distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true realclean: distclean install: install-so install-rb install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.time $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) clean-static:: -$(Q)$(RM) $(STATIC_LIB) install-rb: pre-install-rb do-install-rb install-rb-default install-rb-default: pre-install-rb-default do-install-rb-default pre-install-rb: Makefile pre-install-rb-default: Makefile do-install-rb: do-install-rb-default: pre-install-rb-default: @$(NULLCMD) $(TIMESTAMP_DIR)/.sitearchdir.time: $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) $(Q) $(TOUCH) $@ site-install: site-install-so site-install-rb site-install-so: install-so site-install-rb: install-rb .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S .cc.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cc.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .mm.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .mm.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .cxx.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cxx.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .cpp.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cpp.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .c.o: $(ECHO) compiling $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .c.S: $(ECHO) translating $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .m.o: $(ECHO) compiling $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .m.S: $(ECHO) translating $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< $(TARGET_SO): $(OBJS) Makefile $(ECHO) linking shared-object $(DLLIB) -$(Q)$(RM) $(@) $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) $(OBJS): $(HDRS) $(ruby_headers) PK ] 3O8aa(gems/ruby-lsapi-5.6/ext/lsapi/lsapilib.cnu[//#define LSAPI_DEBUG /* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lsapilib.h" #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #include #endif #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #include #endif #include #ifndef uint32 #define uint32 uint32_t #endif struct lsapi_MD5Context { uint32 buf[4]; uint32 bits[2]; unsigned char in[64]; }; void lsapi_MD5Init(struct lsapi_MD5Context *context); void lsapi_MD5Update(struct lsapi_MD5Context *context, unsigned char const *buf, unsigned len); void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *context); /* * This is needed to make RSAREF happy on some MS-DOS compilers. */ typedef struct lsapi_MD5Context lsapi_MD5_CTX; #define LSAPI_ST_REQ_HEADER 1 #define LSAPI_ST_REQ_BODY 2 #define LSAPI_ST_RESP_HEADER 4 #define LSAPI_ST_RESP_BODY 8 #define LSAPI_ST_BACKGROUND 16 #define LSAPI_RESP_BUF_SIZE 8192 #define LSAPI_INIT_RESP_HEADER_LEN 4096 enum { LSAPI_STATE_IDLE, LSAPI_STATE_CONNECTED, LSAPI_STATE_ACCEPTING, }; typedef struct lsapi_child_status { int m_pid; long m_tmStart; volatile short m_iKillSent; volatile char m_inProcess; volatile char m_state; volatile int m_iReqCounter; volatile long m_tmWaitBegin; volatile long m_tmReqBegin; volatile long m_tmLastCheckPoint; } lsapi_child_status; static lsapi_child_status * s_worker_status = NULL; static int g_inited = 0; static int g_running = 1; static int s_ppid; static int s_restored_ppid = 0; static int s_pid = 0; static int s_slow_req_msecs = 0; static int s_keep_listener = 1; static int s_dump_debug_info = 0; static int s_pid_dump_debug_info = 0; static int s_req_processed = 0; static int s_skip_write = 0; static int (*pthread_atfork_func)(void (*prepare)(void), void (*parent)(void), void (*child)(void)) = NULL; static int *s_busy_workers = NULL; static int *s_accepting_workers = NULL; static int *s_global_counter = &s_req_processed; static int s_max_busy_workers = -1; static char *s_stderr_log_path = NULL; static int s_stderr_is_pipe = 0; static int s_ignore_pid = -1; static size_t s_total_pages = 1; static size_t s_min_avail_pages = 256 * 1024; static size_t *s_avail_pages = &s_total_pages; LSAPI_Request g_req = { .m_fdListen = -1, .m_fd = -1 }; static char s_secret[24]; static LSAPI_On_Timer_pf s_proc_group_timer_cb = NULL; void Flush_RespBuf_r( LSAPI_Request * pReq ); static int lsapi_reopen_stderr(const char *p); static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] = { "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHORIZATION", "HTTP_CONNECTION", "CONTENT_TYPE", "CONTENT_LENGTH", "HTTP_COOKIE", "HTTP_COOKIE2", "HTTP_HOST", "HTTP_PRAGMA", "HTTP_REFERER", "HTTP_USER_AGENT", "HTTP_CACHE_CONTROL", "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH", "HTTP_IF_NONE_MATCH", "HTTP_IF_RANGE", "HTTP_IF_UNMODIFIED_SINCE", "HTTP_KEEP_ALIVE", "HTTP_RANGE", "HTTP_X_FORWARDED_FOR", "HTTP_VIA", "HTTP_TRANSFER_ENCODING" }; static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] = { 11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18, 22, 13, 18, 13, 24, 15, 10, 20, 8, 22 }; static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] = { "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Authorization", "Connection", "Content-Type", "Content-Length", "Cookie", "Cookie2", "Host", "Pragma", "Referer", "User-Agent", "Cache-Control", "If-Modified-Since", "If-Match", "If-None-Match", "If-Range", "If-Unmodified-Since", "Keep-Alive", "Range", "X-Forwarded-For", "Via", "Transfer-Encoding" }; static int HTTP_HEADER_LEN[H_TRANSFER_ENCODING+1] = { 6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, //user-agent 13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17 }; static const char *s_log_level_names[8] = { "", "DEBUG","INFO", "NOTICE", "WARN", "ERROR", "CRIT", "FATAL" }; void LSAPI_Log(int flag, const char * fmt, ...) { char buf[1024]; char *p = buf; if ((flag & LSAPI_LOG_TIMESTAMP_BITS) && !(s_stderr_is_pipe)) { struct timeval tv; struct tm tm; gettimeofday(&tv, NULL); localtime_r(&tv.tv_sec, &tm); if (flag & LSAPI_LOG_TIMESTAMP_FULL) { p += snprintf(p, 1024, "%04d-%02d-%02d %02d:%02d:%02d.%06d ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)tv.tv_usec); } else if (flag & LSAPI_LOG_TIMESTAMP_HMS) { p += snprintf(p, 1024, "%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec); } } int level = flag & LSAPI_LOG_LEVEL_BITS; if (level && level <= LSAPI_LOG_FLAG_FATAL) { p += snprintf(p, 100, "[%s] ", s_log_level_names[level]); } if (flag & LSAPI_LOG_PID) { p += snprintf(p, 100, "[UID:%d][%d] ", getuid(), s_pid); } if (p > buf) fprintf(stderr, "%.*s", (int)(p - buf), buf); va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #ifdef LSAPI_DEBUG #define DBGLOG_FLAG (LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_FLAG_DEBUG|LSAPI_LOG_PID) #define lsapi_dbg(...) LSAPI_Log(DBGLOG_FLAG, __VA_ARGS__) #else #define lsapi_dbg(...) #endif #define lsapi_log(...) LSAPI_Log(LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_PID, __VA_ARGS__) void lsapi_perror(const char * pMessage, int err_no) { lsapi_log("%s, errno: %d (%s)\n", pMessage, err_no, strerror(err_no)); } static int lsapi_parent_dead() { // Return non-zero if the parent is dead. 0 if still alive. if (!s_ppid) { // not checking, so not dead return(0); } if (s_restored_ppid) { if (kill(s_restored_ppid,0) == -1) { if (errno == EPERM) { return(0); // no permission, but it's still there. } return(1); // Dead } return(0); // it worked, so it's not dead } return(s_ppid != getppid()); } static void lsapi_sigpipe( int sig ) { } static void lsapi_siguser1( int sig ) { g_running = 0; } #ifndef sighandler_t typedef void (*sighandler_t)(int); #endif static void lsapi_signal(int signo, sighandler_t handler) { struct sigaction sa; sigaction(signo, NULL, &sa); if (sa.sa_handler == SIG_DFL) { sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; sigaction(signo, &sa, NULL); } } static int s_enable_core_dump = 0; static void lsapi_enable_core_dump(void) { #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) int mib[2]; size_t len; #if !defined(__OpenBSD__) len = 2; if ( sysctlnametomib("kern.sugid_coredump", mib, &len) == 0 ) { len = sizeof(s_enable_core_dump); if (sysctl(mib, 2, NULL, 0, &s_enable_core_dump, len) == -1) perror( "sysctl: Failed to set 'kern.sugid_coredump', " "core dump may not be available!"); } #else int set = 3; len = sizeof(set); mib[0] = CTL_KERN; mib[1] = KERN_NOSUIDCOREDUMP; if (sysctl(mib, 2, NULL, 0, &set, len) == 0) { s_enable_core_dump = 1; } #endif #endif #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if (prctl(PR_SET_DUMPABLE, s_enable_core_dump,0,0,0) == -1) perror( "prctl: Failed to set dumpable, " "core dump may not be available!"); #endif } static inline void lsapi_buildPacketHeader( struct lsapi_packet_header * pHeader, char type, int len ) { pHeader->m_versionB0 = LSAPI_VERSION_B0; /* LSAPI protocol version */ pHeader->m_versionB1 = LSAPI_VERSION_B1; pHeader->m_type = type; pHeader->m_flag = LSAPI_ENDIAN; pHeader->m_packetLen.m_iLen = len; } static int lsapi_set_nblock( int fd, int nonblock ) { int val = fcntl( fd, F_GETFL, 0 ); if ( nonblock ) { if (!( val & O_NONBLOCK )) { return fcntl( fd, F_SETFL, val | O_NONBLOCK ); } } else { if ( val & O_NONBLOCK ) { return fcntl( fd, F_SETFL, val &(~O_NONBLOCK) ); } } return 0; } static int lsapi_close( int fd ) { int ret; while( 1 ) { ret = close( fd ); if (( ret == -1 )&&( errno == EINTR )&&(g_running)) continue; return ret; } } static void lsapi_close_connection(LSAPI_Request *pReq) { if (pReq->m_fd == -1) return; lsapi_close(pReq->m_fd); pReq->m_fd = -1; if (s_busy_workers) __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST); if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_IDLE, __ATOMIC_SEQ_CST); } static inline ssize_t lsapi_read( int fd, void * pBuf, size_t len ) { ssize_t ret; while( 1 ) { ret = read( fd, (char *)pBuf, len ); if (( ret == -1 )&&( errno == EINTR )&&(g_running)) continue; return ret; } } /* static int lsapi_write( int fd, const void * pBuf, int len ) { int ret; const char * pCur; const char * pEnd; if ( len == 0 ) return 0; pCur = (const char *)pBuf; pEnd = pCur + len; while( g_running && (pCur < pEnd) ) { ret = write( fd, pCur, pEnd - pCur ); if ( ret >= 0) pCur += ret; else if (( ret == -1 )&&( errno != EINTR )) return ret; } return pCur - (const char *)pBuf; } */ static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen ) { int ret; int left = totalLen; int n = count; if (s_skip_write) return totalLen; while(( left > 0 )&&g_running ) { ret = writev( fd, *pVec, n ); if ( ret > 0 ) { left -= ret; if (( left <= 0)||( !g_running )) return totalLen - left; while( ret > 0 ) { if ( (*pVec)->iov_len <= (unsigned int )ret ) { ret -= (*pVec)->iov_len; ++(*pVec); } else { (*pVec)->iov_base = (char *)(*pVec)->iov_base + ret; (*pVec)->iov_len -= ret; break; } } } else if ( ret == -1 ) { if ( errno == EAGAIN ) { if ( totalLen - left > 0 ) return totalLen - left; else return -1; } else if ( errno != EINTR ) return ret; } } return totalLen - left; } /* static int getTotalLen( struct iovec * pVec, int count ) { struct iovec * pEnd = pVec + count; int total = 0; while( pVec < pEnd ) { total += pVec->iov_len; ++pVec; } return total; } */ static inline int allocateBuf( LSAPI_Request * pReq, int size ) { char * pBuf = (char *)realloc( pReq->m_pReqBuf, size ); if ( pBuf ) { pReq->m_pReqBuf = pBuf; pReq->m_reqBufSize = size; pReq->m_pHeader = (struct lsapi_req_header *)pReq->m_pReqBuf; return 0; } return -1; } static int allocateIovec( LSAPI_Request * pReq, int n ) { struct iovec * p = (struct iovec *)realloc( pReq->m_pIovec, sizeof(struct iovec) * n ); if ( !p ) return -1; pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec ); pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec ); pReq->m_pIovec = p; pReq->m_pIovecEnd = p + n; return 0; } static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size ) { char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size ); if ( !p ) return -1; pReq->m_pRespHeaderBufPos = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf ); pReq->m_pRespHeaderBuf = p; pReq->m_pRespHeaderBufEnd = p + size; return 0; } static inline int verifyHeader( struct lsapi_packet_header * pHeader, char pktType ) { if (( LSAPI_VERSION_B0 != pHeader->m_versionB0 )|| ( LSAPI_VERSION_B1 != pHeader->m_versionB1 )|| ( pktType != pHeader->m_type )) return -1; if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT )) { register char b; b = pHeader->m_packetLen.m_bytes[0]; pHeader->m_packetLen.m_bytes[0] = pHeader->m_packetLen.m_bytes[3]; pHeader->m_packetLen.m_bytes[3] = b; b = pHeader->m_packetLen.m_bytes[1]; pHeader->m_packetLen.m_bytes[1] = pHeader->m_packetLen.m_bytes[2]; pHeader->m_packetLen.m_bytes[2] = b; } return pHeader->m_packetLen.m_iLen; } static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList, int *curSize, int newSize ) { struct LSAPI_key_value_pair * pBuf; if ( *curSize >= newSize ) return 0; if ( newSize > 8192 ) return -1; pBuf = (struct LSAPI_key_value_pair *)realloc( *pEnvList, newSize * sizeof(struct LSAPI_key_value_pair) ); if ( pBuf ) { *pEnvList = pBuf; *curSize = newSize; return 0; } else return -1; } static inline int isPipe( int fd ) { char achPeer[128]; socklen_t len = 128; if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&& ( errno == ENOTCONN )) return 0; else return 1; } static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count, char **pBegin, char * pEnd ) { struct LSAPI_key_value_pair * pEnvEnd; int keyLen = 0, valLen = 0; if ( count > 8192 ) return -1; pEnvEnd = pEnvList + count; while( pEnvList != pEnvEnd ) { if ( pEnd - *pBegin < 4 ) return -1; keyLen = *((unsigned char *)((*pBegin)++)); keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++)); valLen = *((unsigned char *)((*pBegin)++)); valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++)); if ( *pBegin + keyLen + valLen > pEnd ) return -1; if (( !keyLen )||( !valLen )) return -1; pEnvList->pKey = *pBegin; *pBegin += keyLen; pEnvList->pValue = *pBegin; *pBegin += valLen; pEnvList->keyLen = keyLen - 1; pEnvList->valLen = valLen - 1; ++pEnvList; } if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 ) return -1; *pBegin += 4; return 0; } static inline void swapIntEndian( int * pInteger ) { char * p = (char *)pInteger; register char b; b = p[0]; p[0] = p[3]; p[3] = b; b = p[1]; p[1] = p[2]; p[2] = b; } static inline void fixEndian( LSAPI_Request * pReq ) { struct lsapi_req_header *p= pReq->m_pHeader; swapIntEndian( &p->m_httpHeaderLen ); swapIntEndian( &p->m_reqBodyLen ); swapIntEndian( &p->m_scriptFileOff ); swapIntEndian( &p->m_scriptNameOff ); swapIntEndian( &p->m_queryStringOff ); swapIntEndian( &p->m_requestMethodOff ); swapIntEndian( &p->m_cntUnknownHeaders ); swapIntEndian( &p->m_cntEnv ); swapIntEndian( &p->m_cntSpecialEnv ); } static void fixHeaderIndexEndian( LSAPI_Request * pReq ) { int i; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { register char b; char * p = (char *)(&pReq->m_pHeaderIndex->m_headerLen[i]); b = p[0]; p[0] = p[1]; p[1] = b; swapIntEndian( &pReq->m_pHeaderIndex->m_headerOff[i] ); } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { swapIntEndian( &pCur->nameOff ); swapIntEndian( &pCur->nameLen ); swapIntEndian( &pCur->valueOff ); swapIntEndian( &pCur->valueLen ); ++pCur; } } } static int validateHeaders( LSAPI_Request * pReq ) { int totalLen = pReq->m_pHeader->m_httpHeaderLen; int i; for(i = 0; i < H_TRANSFER_ENCODING; ++i) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { if (pReq->m_pHeaderIndex->m_headerOff[i] > totalLen || pReq->m_pHeaderIndex->m_headerLen[i] + pReq->m_pHeaderIndex->m_headerOff[i] > totalLen) return -1; } } if (pReq->m_pHeader->m_cntUnknownHeaders > 0) { struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { if (pCur->nameOff > totalLen || pCur->nameOff + pCur->nameLen > totalLen || pCur->valueOff > totalLen || pCur->valueOff + pCur->valueLen > totalLen) return -1; ++pCur; } } return 0; } static uid_t s_uid = 0; static uid_t s_defaultUid; //web server need set this static gid_t s_defaultGid; #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #define LSAPI_LVE_DISABLED 0 #define LSAPI_LVE_ENABLED 1 #define LSAPI_CAGEFS_ENABLED 2 #define LSAPI_CAGEFS_NO_SUEXEC 3 struct liblve; static int s_enable_lve = LSAPI_LVE_DISABLED; static struct liblve * s_lve = NULL; static void *s_liblve; static int (*fp_lve_is_available)(void) = NULL; static int (*fp_lve_instance_init)(struct liblve *) = NULL; static int (*fp_lve_destroy)(struct liblve *) = NULL; static int (*fp_lve_enter)(struct liblve *, uint32_t, int32_t, int32_t, uint32_t *) = NULL; static int (*fp_lve_leave)(struct liblve *, uint32_t *) = NULL; static int (*fp_lve_jail)( struct passwd *, char *) = NULL; static int lsapi_load_lve_lib(void) { s_liblve = dlopen("liblve.so.0", RTLD_NOW | RTLD_GLOBAL); if (s_liblve) { fp_lve_is_available = dlsym(s_liblve, "lve_is_available"); if (dlerror() == NULL) { if ( !(*fp_lve_is_available)() ) { int uid = getuid(); if ( uid ) { if (setreuid( s_uid, uid )) {}; if ( !(*fp_lve_is_available)() ) s_enable_lve = 0; if (setreuid( uid, s_uid )) {}; } } } } else { s_enable_lve = LSAPI_LVE_DISABLED; } return (s_liblve)? 0 : -1; } static int init_lve_ex(void) { int rc; if ( !s_liblve ) return -1; fp_lve_instance_init = dlsym(s_liblve, "lve_instance_init"); fp_lve_destroy = dlsym(s_liblve, "lve_destroy"); fp_lve_enter = dlsym(s_liblve, "lve_enter"); fp_lve_leave = dlsym(s_liblve, "lve_leave"); if ( s_enable_lve >= LSAPI_CAGEFS_ENABLED ) fp_lve_jail = dlsym(s_liblve, "jail" ); if ( s_lve == NULL ) { rc = (*fp_lve_instance_init)(NULL); s_lve = malloc(rc); } rc = (*fp_lve_instance_init)(s_lve); if (rc != 0) { perror( "LSAPI: Unable to initialize LVE" ); free( s_lve ); s_lve = NULL; return -1; } return 0; } #endif static int readSecret( const char * pSecretFile ) { struct stat st; int fd = open( pSecretFile, O_RDONLY , 0600 ); if ( fd == -1 ) { lsapi_log("LSAPI: failed to open secret file: %s!\n", pSecretFile ); return -1; } if ( fstat( fd, &st ) == -1 ) { lsapi_log("LSAPI: failed to check state of file: %s!\n", pSecretFile ); close( fd ); return -1; } /* if ( st.st_uid != s_uid ) { lsapi_log("LSAPI: file owner check failure: %s!\n", pSecretFile ); close( fd ); return -1; } */ if ( st.st_mode & 0077 ) { lsapi_log("LSAPI: file permission check failure: %s\n", pSecretFile ); close( fd ); return -1; } if ( read( fd, s_secret, 16 ) < 16 ) { lsapi_log("LSAPI: failed to read secret from secret file: %s\n", pSecretFile ); close( fd ); return -1; } close( fd ); return 0; } int LSAPI_is_suEXEC_Daemon(void) { if (( !s_uid )&&( s_secret[0] )) return 1; else return 0; } static int LSAPI_perror_r( LSAPI_Request * pReq, const char * pErr1, const char *pErr2 ) { char achError[4096]; int n = snprintf(achError, sizeof(achError), "[UID:%d][%d] %s:%s: %s\n", getuid(), getpid(), pErr1, (pErr2)?pErr2:"", strerror(errno)); if (n > (int)sizeof(achError)) n = sizeof(achError); if ( pReq ) LSAPI_Write_Stderr_r( pReq, achError, n ); else if (write( STDERR_FILENO, achError, n )) {}; return 0; } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) static int lsapi_lve_error( LSAPI_Request * pReq ) { static const char * headers[] = { "Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0", "Pragma: no-cache", "Retry-After: 60", "Content-Type: text/html", NULL }; static const char achBody[] = "\n" "\n508 Resource Limit Is Reached\n" "\n" "

    Resource Limit Is Reached

    \n" "The website is temporarily unable to service your request as it exceeded resource limit.\n" "Please try again later.\n" "
    \n" "\n"; LSAPI_ErrResponse_r( pReq, 508, headers, achBody, sizeof( achBody ) - 1 ); return 0; } static int lsapi_enterLVE( LSAPI_Request * pReq, uid_t uid ) { if ( s_lve && uid ) //root user should not do that { uint32_t cookie; int ret = -1; ret = (*fp_lve_enter)(s_lve, uid, -1, -1, &cookie); if ( ret < 0 ) { //lsapi_log("enter LVE (%d) : result: %d !\n", uid, ret ); LSAPI_perror_r(pReq, "LSAPI: lve_enter() failure, reached resource limit.", NULL ); lsapi_lve_error( pReq ); return -1; } } return 0; } static int lsapi_jailLVE( LSAPI_Request * pReq, uid_t uid, struct passwd * pw ) { int ret = 0; char error_msg[1024] = ""; ret = (*fp_lve_jail)( pw, error_msg ); if ( ret < 0 ) { lsapi_log("LSAPI: LVE jail(%d) result: %d, error: %s !\n", uid, ret, error_msg ); LSAPI_perror_r( pReq, "LSAPI: jail() failure.", NULL ); return -1; } return ret; } static int lsapi_initLVE(void) { const char * pEnv; if ( (pEnv = getenv( "LSAPI_LVE_ENABLE" ))!= NULL ) { s_enable_lve = atol( pEnv ); pEnv = NULL; } else if ( (pEnv = getenv( "LVE_ENABLE" ))!= NULL ) { s_enable_lve = atol( pEnv ); pEnv = NULL; } if ( s_enable_lve && !s_uid ) { lsapi_load_lve_lib(); if ( s_enable_lve ) { return init_lve_ex(); } } return 0; } #endif static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * pChroot) { int rv; struct passwd * pw; pw = getpwuid( uid ); #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if ( s_lve ) { if( lsapi_enterLVE( pReq, uid ) == -1 ) return -1; if ( pw && fp_lve_jail) { rv = lsapi_jailLVE( pReq, uid, pw ); if ( rv == -1 ) return -1; if (( rv == 1 )&&(s_enable_lve == LSAPI_CAGEFS_NO_SUEXEC )) //this mode only use cageFS, does not use suEXEC { uid = s_defaultUid; gid = s_defaultGid; pw = getpwuid( uid ); } } } #endif //if ( !uid || !gid ) //do not allow root //{ // return -1; //} #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) if ( s_enable_core_dump ) lsapi_enable_core_dump(); #endif rv = setgid(gid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setgid()", NULL); return -1; } if ( pw && (pw->pw_gid == gid )) { rv = initgroups( pw->pw_name, gid ); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: initgroups()", NULL); return -1; } } else { rv = setgroups(1, &gid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setgroups()", NULL); } } if ( pChroot ) { rv = chroot( pChroot ); if ( rv == -1 ) { LSAPI_perror_r(pReq, "LSAPI: chroot()", NULL); return -1; } } rv = setuid(uid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setuid()", NULL); return -1; } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if ( s_enable_core_dump ) lsapi_enable_core_dump(); #endif return 0; } static int lsapi_suexec_auth( LSAPI_Request *pReq, char * pAuth, int len, char * pUgid, int ugidLen ) { lsapi_MD5_CTX md5ctx; unsigned char achMD5[16]; if ( len < 32 ) return -1; memmove( achMD5, pAuth + 16, 16 ); memmove( pAuth + 16, s_secret, 16 ); lsapi_MD5Init( &md5ctx ); lsapi_MD5Update( &md5ctx, (unsigned char *)pAuth, 32 ); lsapi_MD5Update( &md5ctx, (unsigned char *)pUgid, 8 ); lsapi_MD5Final( (unsigned char *)pAuth + 16, &md5ctx); if ( memcmp( achMD5, pAuth + 16, 16 ) == 0 ) return 0; return 1; } static int lsapi_changeUGid( LSAPI_Request * pReq ) { int uid = s_defaultUid; int gid = s_defaultGid; const char *pStderrLog; const char *pChroot = NULL; struct LSAPI_key_value_pair * pEnv; struct LSAPI_key_value_pair * pAuth; int i; if ( s_uid ) return 0; //with special ID 0x00 //authenticate the suEXEC request; //first one should be MD5( nonce + lscgid secret ) //remember to clear the secret after verification //it should be set at the end of special env i = pReq->m_pHeader->m_cntSpecialEnv - 1; if ( i >= 0 ) { pEnv = pReq->m_pSpecialEnvList + i; if (( *pEnv->pKey == '\000' )&& ( strcmp( pEnv->pKey+1, "SUEXEC_AUTH" ) == 0 )) { --pReq->m_pHeader->m_cntSpecialEnv; pAuth = pEnv--; if (( *pEnv->pKey == '\000' )&& ( strcmp( pEnv->pKey+1, "SUEXEC_UGID" ) == 0 )) { --pReq->m_pHeader->m_cntSpecialEnv; uid = *(uint32_t *)pEnv->pValue; gid = *(((uint32_t *)pEnv->pValue) + 1 ); //lsapi_log("LSAPI: SUEXEC_UGID set UID: %d, GID: %d\n", uid, gid ); } else { lsapi_log("LSAPI: missing SUEXEC_UGID env, use default user!\n" ); pEnv = NULL; } if ( pEnv&& lsapi_suexec_auth( pReq, pAuth->pValue, pAuth->valLen, pEnv->pValue, pEnv->valLen ) == 0 ) { //read UID, GID from specialEnv } else { //authentication error lsapi_log("LSAPI: SUEXEC_AUTH authentication failed, use default user!\n" ); uid = 0; } } else { //lsapi_log("LSAPI: no SUEXEC_AUTH env, use default user!\n" ); } } if ( !uid ) { uid = s_defaultUid; gid = s_defaultGid; } //change uid if ( setUID_LVE( pReq, uid, gid, pChroot ) == -1 ) { return -1; } s_uid = uid; if ( pReq->m_fdListen != -1 ) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } pStderrLog = LSAPI_GetEnv_r( pReq, "LSAPI_STDERR_LOG"); if (pStderrLog) lsapi_reopen_stderr(pStderrLog); return 0; } static int parseContentLenFromHeader(LSAPI_Request * pReq) { const char * pContentLen = LSAPI_GetHeader_r( pReq, H_CONTENT_LENGTH ); if ( pContentLen ) pReq->m_reqBodyLen = strtoll( pContentLen, NULL, 10 ); return 0; } static int parseRequest( LSAPI_Request * pReq, int totalLen ) { int shouldFixEndian; char * pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header ); char * pEnd = pReq->m_pReqBuf + totalLen; shouldFixEndian = ( LSAPI_ENDIAN != ( pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) ); if ( shouldFixEndian ) { fixEndian( pReq ); } if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&& allocateEnvList( &pReq->m_pSpecialEnvList, &pReq->m_specialEnvListSize, pReq->m_pHeader->m_cntSpecialEnv ) == -1 ) return -1; if ( (pReq->m_envListSize < pReq->m_pHeader->m_cntEnv )&& allocateEnvList( &pReq->m_pEnvList, &pReq->m_envListSize, pReq->m_pHeader->m_cntEnv ) == -1 ) return -1; if ( parseEnv( pReq->m_pSpecialEnvList, pReq->m_pHeader->m_cntSpecialEnv, &pBegin, pEnd ) == -1 ) return -1; if ( parseEnv( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, &pBegin, pEnd ) == -1 ) return -1; if (pReq->m_pHeader->m_scriptFileOff < 0 || pReq->m_pHeader->m_scriptFileOff >= totalLen || pReq->m_pHeader->m_scriptNameOff < 0 || pReq->m_pHeader->m_scriptNameOff >= totalLen || pReq->m_pHeader->m_queryStringOff < 0 || pReq->m_pHeader->m_queryStringOff >= totalLen || pReq->m_pHeader->m_requestMethodOff < 0 || pReq->m_pHeader->m_requestMethodOff >= totalLen) { lsapi_log("Bad request header - ERROR#1\n"); return -1; } pReq->m_pScriptFile = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptFileOff; pReq->m_pScriptName = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff; pReq->m_pQueryString = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff; pReq->m_pRequestMethod = pReq->m_pReqBuf + pReq->m_pHeader->m_requestMethodOff; pBegin = pReq->m_pReqBuf + (( pBegin - pReq->m_pReqBuf + 7 ) & (~0x7)); pReq->m_pHeaderIndex = ( struct lsapi_http_header_index * )pBegin; pBegin += sizeof( struct lsapi_http_header_index ); pReq->m_pUnknownHeader = (struct lsapi_header_offset *)pBegin; pBegin += sizeof( struct lsapi_header_offset) * pReq->m_pHeader->m_cntUnknownHeaders; pReq->m_pHttpHeader = pBegin; pBegin += pReq->m_pHeader->m_httpHeaderLen; if ( pBegin != pEnd ) { lsapi_log("Request header does match total size, total: %d, " "real: %ld\n", totalLen, pBegin - pReq->m_pReqBuf ); return -1; } if ( shouldFixEndian ) { fixHeaderIndexEndian( pReq ); } if (validateHeaders(pReq) == -1) { lsapi_log("Bad request header - ERROR#2\n"); return -1; } pReq->m_reqBodyLen = pReq->m_pHeader->m_reqBodyLen; if ( pReq->m_reqBodyLen == -2 ) { parseContentLenFromHeader(pReq); } return 0; } //OPTIMIZATION static char s_accept_notify = 0; static char s_schedule_notify = 0; static char s_notify_scheduled = 0; static char s_notified_pid = 0; static struct lsapi_packet_header s_ack = {'L', 'S', LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; static struct lsapi_packet_header s_conn_close_pkt = {'L', 'S', LSAPI_CONN_CLOSE, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; static inline int send_notification_pkt( int fd, struct lsapi_packet_header *pkt ) { if ( write( fd, pkt, LSAPI_PACKET_HEADER_LEN ) < LSAPI_PACKET_HEADER_LEN ) return -1; return 0; } static inline int send_req_received_notification( int fd ) { return send_notification_pkt(fd, &s_ack); } static inline int send_conn_close_notification( int fd ) { return send_notification_pkt(fd, &s_conn_close_pkt); } //static void lsapi_sigalarm( int sig ) //{ // if ( s_notify_scheduled ) // { // s_notify_scheduled = 0; // if ( g_req.m_fd != -1 ) // write_req_received_notification( g_req.m_fd ); // } //} static inline int lsapi_schedule_notify(void) { if ( !s_notify_scheduled ) { alarm( 2 ); s_notify_scheduled = 1; } return 0; } static inline int notify_req_received( int fd ) { if ( s_schedule_notify ) return lsapi_schedule_notify(); return send_req_received_notification( fd ); } static inline int lsapi_notify_pid( int fd ) { char achBuf[16]; lsapi_buildPacketHeader( (struct lsapi_packet_header *)achBuf, LSAPI_STDERR_STREAM, 8 + LSAPI_PACKET_HEADER_LEN ); memmove( &achBuf[8], "\0PID", 4 ); *((int *)&achBuf[12]) = getpid(); if ( write( fd, achBuf, 16 ) < 16 ) return -1; return 0; } static int readReq( LSAPI_Request * pReq ) { int len; int packetLen; if ( !pReq ) return -1; if ( pReq->m_reqBufSize < 8192 ) { if ( allocateBuf( pReq, 8192 ) == -1 ) return -1; } while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN ) { len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize ); if ( len <= 0 ) return -1; pReq->m_bufRead += len; } pReq->m_reqState = LSAPI_ST_REQ_HEADER; packetLen = verifyHeader( &pReq->m_pHeader->m_pktHeader, LSAPI_BEGIN_REQUEST ); if ( packetLen < 0 ) { lsapi_log("packetLen < 0\n"); return -1; } if ( packetLen > LSAPI_MAX_HEADER_LEN ) { lsapi_log("packetLen > %d\n", LSAPI_MAX_HEADER_LEN ); return -1; } if ( packetLen + 1024 > pReq->m_reqBufSize ) { if ( allocateBuf( pReq, packetLen + 1024 ) == -1 ) return -1; } while( packetLen > pReq->m_bufRead ) { len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, packetLen - pReq->m_bufRead ); if ( len <= 0 ) return -1; pReq->m_bufRead += len; } if ( parseRequest( pReq, packetLen ) < 0 ) { lsapi_log("ParseRequest error\n"); return -1; } pReq->m_reqState = LSAPI_ST_REQ_BODY | LSAPI_ST_RESP_HEADER; if ( !s_uid ) { if ( lsapi_changeUGid( pReq ) ) return -1; memset(s_secret, 0, sizeof(s_secret)); } pReq->m_bufProcessed = packetLen; //OPTIMIZATION if ( !s_accept_notify && !s_notified_pid ) return notify_req_received( pReq->m_fd ); else { s_notified_pid = 0; return 0; } } int LSAPI_Init(void) { if ( !g_inited ) { s_uid = geteuid(); s_secret[0] = 0; lsapi_signal(SIGPIPE, lsapi_sigpipe); lsapi_signal(SIGUSR1, lsapi_siguser1); #if defined(SIGXFSZ) && defined(SIG_IGN) signal(SIGXFSZ, SIG_IGN); #endif /* let STDOUT function as STDERR, just in case writing to STDOUT directly */ dup2( 2, 1 ); if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 ) return -1; g_inited = 1; s_ppid = getppid(); void *pthread_lib = dlopen("libpthread.so", RTLD_LAZY); if (pthread_lib) pthread_atfork_func = dlsym(pthread_lib, "pthread_atfork"); } return 0; } void LSAPI_Stop(void) { g_running = 0; } int LSAPI_IsRunning(void) { return g_running; } void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf cb) { s_proc_group_timer_cb = cb; } int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ) { int newfd; if ( !pReq ) return -1; memset( pReq, 0, sizeof( LSAPI_Request ) ); if ( allocateIovec( pReq, 16 ) == -1 ) return -1; pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE ); if ( !pReq->m_pRespBuf ) return -1; pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5]; if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 ) return -1; if ( fd == STDIN_FILENO ) { fd = dup( fd ); newfd = open( "/dev/null", O_RDWR ); dup2( newfd, STDIN_FILENO ); } if ( isPipe( fd ) ) { pReq->m_fdListen = -1; pReq->m_fd = fd; } else { pReq->m_fdListen = fd; pReq->m_fd = -1; lsapi_set_nblock( fd, 1 ); } return 0; } int LSAPI_Is_Listen( void ) { return LSAPI_Is_Listen_r( &g_req ); } int LSAPI_Is_Listen_r( LSAPI_Request * pReq) { return pReq->m_fdListen != -1; } int LSAPI_Accept_r( LSAPI_Request * pReq ) { char achPeer[128]; socklen_t len; int nodelay = 1; if ( !pReq ) return -1; if ( LSAPI_Finish_r( pReq ) == -1 ) return -1; lsapi_set_nblock( pReq->m_fdListen , 0 ); while( g_running ) { if ( pReq->m_fd == -1 ) { if ( pReq->m_fdListen != -1) { len = sizeof( achPeer ); pReq->m_fd = accept( pReq->m_fdListen, (struct sockaddr *)&achPeer, &len ); if ( pReq->m_fd == -1 ) { if (( errno == EINTR )||( errno == EAGAIN)) continue; else return -1; } else { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd , 0 ); if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); } //init_conn_key( pReq->m_fd ); //OPTIMIZATION if ( s_accept_notify ) if ( notify_req_received( pReq->m_fd ) == -1 ) return -1; } } else return -1; } if ( !readReq( pReq ) ) break; //abort(); lsapi_close_connection(pReq); LSAPI_Reset_r( pReq ); } return 0; } static struct lsapi_packet_header finish_close[2] = { {'L', 'S', LSAPI_RESP_END, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }, {'L', 'S', LSAPI_CONN_CLOSE, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} } }; int LSAPI_Finish_r( LSAPI_Request * pReq ) { /* finish req body */ if ( !pReq ) return -1; if (pReq->m_reqState) { if ( pReq->m_fd != -1 ) { if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } pReq->m_pIovecCur->iov_base = (void *)finish_close; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; LSAPI_Flush_r( pReq ); } LSAPI_Reset_r( pReq ); } return 0; } int LSAPI_End_Response_r(LSAPI_Request * pReq) { if (!pReq) return -1; if (pReq->m_reqState & LSAPI_ST_BACKGROUND) return 0; if (pReq->m_reqState) { if ( pReq->m_fd != -1 ) { if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { if ( pReq->m_pRespHeaderBufPos <= pReq->m_pRespHeaderBuf ) return 0; LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } pReq->m_pIovecCur->iov_base = (void *)finish_close; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN << 1; pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN << 1; ++pReq->m_pIovecCur; LSAPI_Flush_r( pReq ); lsapi_close_connection(pReq); } pReq->m_reqState |= LSAPI_ST_BACKGROUND; } return 0; } void LSAPI_Reset_r( LSAPI_Request * pReq ) { pReq->m_pRespBufPos = pReq->m_pRespBuf; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; pReq->m_pRespHeaderBufPos = pReq->m_pRespHeaderBuf; memset( &pReq->m_pHeaderIndex, 0, (char *)(pReq->m_respHeaderLen) - (char *)&pReq->m_pHeaderIndex ); } int LSAPI_Release_r( LSAPI_Request * pReq ) { if ( pReq->m_pReqBuf ) free( pReq->m_pReqBuf ); if ( pReq->m_pSpecialEnvList ) free( pReq->m_pSpecialEnvList ); if ( pReq->m_pEnvList ) free( pReq->m_pEnvList ); if ( pReq->m_pRespHeaderBuf ) free( pReq->m_pRespHeaderBuf ); return 0; } char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ) { int off; if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) ) return NULL; off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ]; if ( !off ) return NULL; if ( *(pReq->m_pHttpHeader + off + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) ) { *( pReq->m_pHttpHeader + off + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0; } return pReq->m_pHttpHeader + off; } static int readBodyToReqBuf( LSAPI_Request * pReq ) { off_t bodyLeft; ssize_t len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len > 0 ) return len; pReq->m_bufRead = pReq->m_bufProcessed = pReq->m_pHeader->m_pktHeader.m_packetLen.m_iLen; bodyLeft = pReq->m_reqBodyLen - pReq->m_reqBodyRead; len = pReq->m_reqBufSize - pReq->m_bufRead; if ( len < 0 ) return -1; if ( len > bodyLeft ) len = bodyLeft; len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, len ); if ( len > 0 ) pReq->m_bufRead += len; return len; } int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ) { if (!pReq || (pReq->m_fd ==-1) ) return EOF; if ( pReq->m_bufProcessed >= pReq->m_bufRead ) { if ( readBodyToReqBuf( pReq ) <= 0 ) return EOF; } ++pReq->m_reqBodyRead; return (unsigned char)*(pReq->m_pReqBuf + pReq->m_bufProcessed++); } int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF ) { ssize_t len; ssize_t left; char * pBufEnd = pBuf + bufLen - 1; char * pBufCur = pBuf; char * pCur; char * p; if (!pReq || pReq->m_fd == -1 || !pBuf || !getLF) return -1; *getLF = 0; while( (left = pBufEnd - pBufCur ) > 0 ) { len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len <= 0 ) { if ( (len = readBodyToReqBuf( pReq )) <= 0 ) { *getLF = 1; break; } } if ( len > left ) len = left; pCur = pReq->m_pReqBuf + pReq->m_bufProcessed; p = memchr( pCur, '\n', len ); if ( p ) len = p - pCur + 1; memmove( pBufCur, pCur, len ); pBufCur += len; pReq->m_bufProcessed += len; pReq->m_reqBodyRead += len; if ( p ) { *getLF = 1; break; } } *pBufCur = 0; return pBufCur - pBuf; } ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen ) { ssize_t len; off_t total; /* char *pOldBuf = pBuf; */ if (!pReq || pReq->m_fd == -1 || !pBuf || (ssize_t)bufLen < 0) return -1; total = pReq->m_reqBodyLen - pReq->m_reqBodyRead; if ( total <= 0 ) return 0; if ( total < (ssize_t)bufLen ) bufLen = total; total = 0; len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len > 0 ) { if ( len > (ssize_t)bufLen ) len = bufLen; memmove( pBuf, pReq->m_pReqBuf + pReq->m_bufProcessed, len ); pReq->m_bufProcessed += len; total += len; pBuf += len; bufLen -= len; } while( bufLen > 0 ) { len = lsapi_read( pReq->m_fd, pBuf, bufLen ); if ( len > 0 ) { total += len; pBuf += len; bufLen -= len; } else if ( len <= 0 ) { if ( !total) return -1; break; } } pReq->m_reqBodyRead += total; return total; } ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len ) { struct lsapi_packet_header * pHeader; const char * pEnd; const char * p; ssize_t bufLen; ssize_t toWrite; ssize_t packetLen; int skip = 0; if (!pReq || !pBuf) return -1; if (pReq->m_reqState & LSAPI_ST_BACKGROUND) return len; if (pReq->m_fd == -1) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); /* if ( *pBuf == '\r' ) { ++skip; } if ( *pBuf == '\n' ) { ++skip; } */ } pReq->m_reqState |= LSAPI_ST_RESP_BODY; if ( ((ssize_t)len - skip) < pReq->m_pRespBufEnd - pReq->m_pRespBufPos ) { memmove( pReq->m_pRespBufPos, pBuf + skip, len - skip ); pReq->m_pRespBufPos += len - skip; return len; } pHeader = pReq->m_respPktHeader; p = pBuf + skip; pEnd = pBuf + len; bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; while( ( toWrite = pEnd - p ) > 0 ) { packetLen = toWrite + bufLen; if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { packetLen = LSAPI_MAX_DATA_PACKET_LEN; toWrite = packetLen - bufLen; } lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, packetLen + LSAPI_PACKET_HEADER_LEN ); pReq->m_totalLen += packetLen + LSAPI_PACKET_HEADER_LEN; pReq->m_pIovecCur->iov_base = (void *)pHeader; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; ++pHeader; if ( bufLen > 0 ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; pReq->m_pIovecCur->iov_len = bufLen; pReq->m_pRespBufPos = pReq->m_pRespBuf; ++pReq->m_pIovecCur; bufLen = 0; } pReq->m_pIovecCur->iov_base = (void *)p; pReq->m_pIovecCur->iov_len = toWrite; ++pReq->m_pIovecCur; p += toWrite; if ( pHeader >= pReq->m_respPktHeaderEnd - 1) { if ( LSAPI_Flush_r( pReq ) == -1 ) return -1; pHeader = pReq->m_respPktHeader; } } if ( pHeader != pReq->m_respPktHeader ) if ( LSAPI_Flush_r( pReq ) == -1 ) return -1; return p - pBuf; } #if defined(__FreeBSD__ ) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t written; ret = sendfile( fdIn, fdOut, *off, size, NULL, &written, 0 ); if ( written > 0 ) { ret = written; *off += ret; } return ret; } #endif #if defined(__OpenBSD__) || defined(__NetBSD__) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t written = 0; const size_t bufsiz = 16384; unsigned char in[bufsiz] = {0}; if (lseek(fdIn, *off, SEEK_SET) == -1) { return -1; } while (size > 0) { size_t tor = size > sizeof(in) ? sizeof(in) : size; ssize_t c = read(fdIn, in, tor); if (c <= 0) { goto end; } ssize_t w = write(fdOut, in, c); if (w > 0) written += w; if (w != c) { goto end; } size -= c; } end: *off += written; return 0; } #endif #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t len = size; ret = sendfile( fdIn, fdOut, *off, &len, NULL, 0 ); if (( ret == 0 )&&( len > 0 )) { ret = len; *off += len; } return ret; } #endif #if defined(sun) || defined(__sun) #include ssize_t gsendfile( int fdOut, int fdIn, off_t *off, size_t size ) { int n = 0 ; sendfilevec_t vec[1]; vec[n].sfv_fd = fdIn; vec[n].sfv_flag = 0; vec[n].sfv_off = *off; vec[n].sfv_len = size; ++n; size_t written; ssize_t ret = sendfilev( fdOut, vec, n, &written ); if (( !ret )||( errno == EAGAIN )) ret = written; if ( ret > 0 ) *off += ret; return ret; } #endif #if defined(linux) || defined(__linux) || defined(__linux__) || \ defined(__gnu_linux__) #include #define gsendfile sendfile #endif #if defined(HPUX) ssize_t gsendfile( int fdOut, int fdIn, off_t * off, size_t size ) { return sendfile( fdOut, fdIn, off, size, NULL, 0 ); } #endif ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size ) { struct lsapi_packet_header * pHeader = pReq->m_respPktHeader; if ( !pReq || (pReq->m_fd == -1) || fdIn == -1 ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } pReq->m_reqState |= LSAPI_ST_RESP_BODY; LSAPI_Flush_r(pReq); lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, size + LSAPI_PACKET_HEADER_LEN ); if (write(pReq->m_fd, (const char *) pHeader, LSAPI_PACKET_HEADER_LEN ) != LSAPI_PACKET_HEADER_LEN) return -1; return gsendfile( pReq->m_fd, fdIn, off, size ); } void Flush_RespBuf_r( LSAPI_Request * pReq ) { struct lsapi_packet_header * pHeader = pReq->m_respPktHeader; int bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; pReq->m_reqState |= LSAPI_ST_RESP_BODY; lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, bufLen + LSAPI_PACKET_HEADER_LEN ); pReq->m_totalLen += bufLen + LSAPI_PACKET_HEADER_LEN; pReq->m_pIovecCur->iov_base = (void *)pHeader; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; ++pHeader; if ( bufLen > 0 ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; pReq->m_pIovecCur->iov_len = bufLen; pReq->m_pRespBufPos = pReq->m_pRespBuf; ++pReq->m_pIovecCur; bufLen = 0; } } int LSAPI_Flush_r( LSAPI_Request * pReq ) { int ret = 0; int n; if ( !pReq ) return -1; n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf )) return 0; if ( pReq->m_fd == -1 ) { pReq->m_pRespBufPos = pReq->m_pRespBuf; pReq->m_totalLen = 0; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; return -1; } if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; if ( n > 0 ) { ret = lsapi_writev( pReq->m_fd, &pReq->m_pIovecToWrite, n, pReq->m_totalLen ); if ( ret < pReq->m_totalLen ) { lsapi_close_connection(pReq); ret = -1; } pReq->m_totalLen = 0; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; } return ret; } ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len ) { struct lsapi_packet_header header; const char * pEnd; const char * p; ssize_t packetLen; ssize_t totalLen; int ret; struct iovec iov[2]; struct iovec *pIov; if ( !pReq ) return -1; if (s_stderr_log_path || pReq->m_fd == -1 || pReq->m_fd == pReq->m_fdListen) return write( 2, pBuf, len ); if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { LSAPI_Flush_r( pReq ); } p = pBuf; pEnd = pBuf + len; while( ( packetLen = pEnd - p ) > 0 ) { if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { packetLen = LSAPI_MAX_DATA_PACKET_LEN; } lsapi_buildPacketHeader( &header, LSAPI_STDERR_STREAM, packetLen + LSAPI_PACKET_HEADER_LEN ); totalLen = packetLen + LSAPI_PACKET_HEADER_LEN; iov[0].iov_base = (void *)&header; iov[0].iov_len = LSAPI_PACKET_HEADER_LEN; iov[1].iov_base = (void *)p; iov[1].iov_len = packetLen; p += packetLen; pIov = iov; ret = lsapi_writev( pReq->m_fd, &pIov, 2, totalLen ); if ( ret < totalLen ) { lsapi_close_connection(pReq); ret = -1; } } return p - pBuf; } static char * GetHeaderVar( LSAPI_Request * pReq, const char * name ) { int i; char * pValue; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { if ( strcmp( name, CGI_HEADERS[i] ) == 0 ) { pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; if ( *(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) != '\0') { *(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) = '\0'; } return pValue; } } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { const char *p; char *pKey; char *pKeyEnd; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; pKeyEnd = pKey + keyLen; p = &name[5]; while(( pKey < pKeyEnd )&&( *p )) { char ch = toupper( *pKey ); if ((ch != *p )||(( *p == '_' )&&( ch != '-'))) break; ++p; ++pKey; } if (( pKey == pKeyEnd )&& (!*p )) { pValue = pReq->m_pHttpHeader + pCur->valueOff; if ( *(pValue + pCur->valueLen) != '\0') { *(pValue + pCur->valueLen) = '\0'; } return pValue; } ++pCur; } } return NULL; } char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ) { struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList; struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv; if ( !pReq || !name ) return NULL; if ( strncmp( name, "HTTP_", 5 ) == 0 ) { return GetHeaderVar( pReq, name ); } while( pBegin < pEnd ) { if ( strcmp( name, pBegin->pKey ) == 0 ) return pBegin->pValue; ++pBegin; } return NULL; } struct _headerInfo { const char * _name; int _nameLen; const char * _value; int _valueLen; }; int compareValueLocation(const void * v1, const void *v2 ) { return ((const struct _headerInfo *)v1)->_value - ((const struct _headerInfo *)v2)->_value; } int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { int i; int len = 0; char * pValue; int ret; int count = 0; struct _headerInfo headers[512]; if ( !pReq || !fn ) return -1; if ( !pReq->m_pHeaderIndex ) return 0; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { len = pReq->m_pHeaderIndex->m_headerLen[i]; pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; *(pValue + len ) = 0; headers[count]._name = HTTP_HEADERS[i]; headers[count]._nameLen = HTTP_HEADER_LEN[i]; headers[count]._value = pValue; headers[count]._valueLen = len; ++count; //ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i], // pValue, len, arg ); //if ( ret <= 0 ) // return ret; } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { char *pKey; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; *(pKey + keyLen ) = 0; pValue = pReq->m_pHttpHeader + pCur->valueOff; *(pValue + pCur->valueLen ) = 0; headers[count]._name = pKey; headers[count]._nameLen = keyLen; headers[count]._value = pValue; headers[count]._valueLen = pCur->valueLen; ++count; if ( count == 512 ) break; //ret = (*fn)( pKey, keyLen, // pValue, pCur->valueLen, arg ); //if ( ret <= 0 ) // return ret; ++pCur; } } qsort( headers, count, sizeof( struct _headerInfo ), compareValueLocation ); for( i = 0; i < count; ++i ) { ret = (*fn)( headers[i]._name, headers[i]._nameLen, headers[i]._value, headers[i]._valueLen, arg ); if ( ret <= 0 ) return ret; } return count; } int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { int i; int len = 0; char * pValue; int ret; int count = 0; if ( !pReq || !fn ) return -1; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { len = pReq->m_pHeaderIndex->m_headerLen[i]; pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; *(pValue + len ) = 0; ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i], pValue, len, arg ); ++count; if ( ret <= 0 ) return ret; } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { char achHeaderName[256]; char *p; char *pKey; char *pKeyEnd ; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; if ( keyLen > 250 ) keyLen = 250; pKeyEnd = pKey + keyLen; memcpy( achHeaderName, "HTTP_", 5 ); p = &achHeaderName[5]; while( pKey < pKeyEnd ) { char ch = *pKey++; if ( ch == '-' ) *p++ = '_'; else *p++ = toupper( ch ); } *p = 0; keyLen += 5; pValue = pReq->m_pHttpHeader + pCur->valueOff; *(pValue + pCur->valueLen ) = 0; ret = (*fn)( achHeaderName, keyLen, pValue, pCur->valueLen, arg ); if ( ret <= 0 ) return ret; ++pCur; } } return count + pReq->m_pHeader->m_cntUnknownHeaders; } static int EnvForeach( struct LSAPI_key_value_pair * pEnv, int n, LSAPI_CB_EnvHandler fn, void * arg ) { struct LSAPI_key_value_pair * pEnd = pEnv + n; int ret; if ( !pEnv || !fn ) return -1; while( pEnv < pEnd ) { ret = (*fn)( pEnv->pKey, pEnv->keyLen, pEnv->pValue, pEnv->valLen, arg ); if ( ret <= 0 ) return ret; ++pEnv; } return n; } int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { if ( !pReq || !fn ) return -1; if ( pReq->m_pHeader->m_cntEnv > 0 ) { return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, fn, arg ); } return 0; } int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { if ( !pReq || !fn ) return -1; if ( pReq->m_pHeader->m_cntSpecialEnv > 0 ) { return EnvForeach( pReq->m_pSpecialEnvList, pReq->m_pHeader->m_cntSpecialEnv, fn, arg ); } return 0; } int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ) { if ( !pReq || !pReq->m_pIovec ) return -1; if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) ) return 0; pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER; if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf; pReq->m_pIovecCur->iov_len = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf; pReq->m_totalLen += pReq->m_pIovecCur->iov_len; ++pReq->m_pIovecCur; } pReq->m_pIovec->iov_len = sizeof( struct lsapi_resp_header) + pReq->m_respHeader.m_respInfo.m_cntHeaders * sizeof( short ); pReq->m_totalLen += pReq->m_pIovec->iov_len; lsapi_buildPacketHeader( &pReq->m_respHeader.m_pktHeader, LSAPI_RESP_HEADER, pReq->m_totalLen ); pReq->m_pIovec->iov_base = (void *)&pReq->m_respHeader; pReq->m_pIovecToWrite = pReq->m_pIovec; return 0; } int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName, const char * pHeaderValue ) { int nameLen, valLen, len; if ( !pReq || !pHeaderName || !pHeaderValue ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) return -1; if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) return -1; nameLen = strlen( pHeaderName ); valLen = strlen( pHeaderValue ); if ( nameLen == 0 ) return -1; while( nameLen > 0 ) { char ch = *(pHeaderName + nameLen - 1 ); if (( ch == '\n' )||( ch == '\r' )) --nameLen; else break; } if ( nameLen <= 0 ) return 0; while( valLen > 0 ) { char ch = *(pHeaderValue + valLen - 1 ); if (( ch == '\n' )||( ch == '\r' )) --valLen; else break; } len = nameLen + valLen + 1; if ( len > LSAPI_RESP_HTTP_HEADER_MAX ) return -1; if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) { int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf; newlen -= newlen % 4096; if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) return -1; } memmove( pReq->m_pRespHeaderBufPos, pHeaderName, nameLen ); pReq->m_pRespHeaderBufPos += nameLen; *pReq->m_pRespHeaderBufPos++ = ':'; memmove( pReq->m_pRespHeaderBufPos, pHeaderValue, valLen ); pReq->m_pRespHeaderBufPos += valLen; *pReq->m_pRespHeaderBufPos++ = 0; ++len; /* add one byte padding for \0 */ pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len; ++pReq->m_respHeader.m_respInfo.m_cntHeaders; return 0; } int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len ) { if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) return -1; if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) return -1; while( len > 0 ) { char ch = *(pBuf + len - 1 ); if (( ch == '\n' )||( ch == '\r' )) --len; else break; } if ( len <= 0 ) return 0; if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) { int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf; newlen -= newlen % 4096; if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) return -1; } memmove( pReq->m_pRespHeaderBufPos, pBuf, len ); pReq->m_pRespHeaderBufPos += len; *pReq->m_pRespHeaderBufPos++ = 0; ++len; /* add one byte padding for \0 */ pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len; ++pReq->m_respHeader.m_respInfo.m_cntHeaders; return 0; } int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog ) { int ret; int fd; int flag = 1; int addr_len; switch( pServerAddr->sa_family ) { case AF_INET: addr_len = 16; break; case AF_INET6: addr_len = sizeof( struct sockaddr_in6 ); break; case AF_UNIX: addr_len = sizeof( struct sockaddr_un ); unlink( ((struct sockaddr_un *)pServerAddr)->sun_path ); break; default: return -1; } fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 ); if ( fd == -1 ) return -1; fcntl( fd, F_SETFD, FD_CLOEXEC ); if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char *)( &flag ), sizeof(flag)) == 0) { ret = bind( fd, pServerAddr, addr_len ); if ( !ret ) { ret = listen( fd, backlog ); if ( !ret ) return fd; } } ret = errno; close(fd); errno = ret; return -1; } int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr ) { char achAddr[256]; char * p = achAddr; char * pEnd; struct addrinfo *res, hints; int doAddrInfo = 0; int port; if ( !pBind ) return -1; while( isspace( *pBind ) ) ++pBind; strncpy(achAddr, pBind, 255); achAddr[255] = 0; switch( *p ) { case '/': pAddr->sa_family = AF_UNIX; strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p, sizeof(((struct sockaddr_un *)pAddr)->sun_path) ); return 0; case '[': pAddr->sa_family = AF_INET6; ++p; pEnd = strchr( p, ']' ); if ( !pEnd ) return -1; *pEnd++ = 0; if ( *p == '*' ) { strcpy( achAddr, "::" ); p = achAddr; } doAddrInfo = 1; break; default: pAddr->sa_family = AF_INET; pEnd = strchr( p, ':' ); if ( !pEnd ) return -1; *pEnd++ = 0; doAddrInfo = 0; if ( *p == '*' ) { ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY); } else if (!strcasecmp( p, "localhost" ) ) ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK ); else { #ifdef HAVE_INET_PTON if (!inet_pton(AF_INET, p, &((struct sockaddr_in *)pAddr)->sin_addr)) #else ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p ); if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST) #endif { doAddrInfo = 1; } } break; } if ( *pEnd == ':' ) ++pEnd; port = atoi( pEnd ); if (( port <= 0 )||( port > 65535 )) return -1; if ( doAddrInfo ) { memset(&hints, 0, sizeof(hints)); hints.ai_family = pAddr->sa_family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if ( getaddrinfo(p, NULL, &hints, &res) ) { return -1; } memcpy(pAddr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); } if ( pAddr->sa_family == AF_INET ) ((struct sockaddr_in *)pAddr)->sin_port = htons( port ); else ((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port ); return 0; } int LSAPI_CreateListenSock( const char * pBind, int backlog ) { char serverAddr[128]; int ret; int fd = -1; ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr ); if ( !ret ) { fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog ); } return fd; } static fn_select_t g_fnSelect = select; typedef struct _lsapi_prefork_server { int m_fd; int m_iMaxChildren; int m_iExtraChildren; int m_iCurChildren; int m_iMaxIdleChildren; int m_iServerMaxIdle; int m_iChildrenMaxIdleTime; int m_iMaxReqProcessTime; int m_iAvoidFork; lsapi_child_status * m_pChildrenStatus; lsapi_child_status * m_pChildrenStatusCur; lsapi_child_status * m_pChildrenStatusEnd; }lsapi_prefork_server; static lsapi_prefork_server * g_prefork_server = NULL; int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ) { if ( g_prefork_server ) return 0; if ( max_children <= 1 ) return -1; if ( max_children >= 10000) max_children = 10000; if (s_max_busy_workers == 0) s_max_busy_workers = max_children / 2 + 1; g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) ); if ( !g_prefork_server ) return -1; memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) ); if ( fp != NULL ) g_fnSelect = fp; s_ppid = getppid(); s_pid = getpid(); setpgid( s_pid, s_pid ); #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) s_total_pages = sysconf(_SC_PHYS_PAGES); #endif g_prefork_server->m_iAvoidFork = avoidFork; g_prefork_server->m_iMaxChildren = max_children; g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ; g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3); if ( g_prefork_server->m_iMaxIdleChildren == 0 ) g_prefork_server->m_iMaxIdleChildren = 1; g_prefork_server->m_iChildrenMaxIdleTime = 300; g_prefork_server->m_iMaxReqProcessTime = 3600; setsid(); return 0; } void LSAPI_Set_Server_fd( int fd ) { if( g_prefork_server ) g_prefork_server->m_fd = fd; } static int lsapi_accept( int fdListen ) { int fd; int nodelay = 1; socklen_t len; char achPeer[128]; len = sizeof( achPeer ); fd = accept( fdListen, (struct sockaddr *)&achPeer, &len ); if ( fd != -1 ) { if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); } //OPTIMIZATION //if ( s_accept_notify ) // notify_req_received( fd ); } return fd; } static unsigned int s_max_reqs = UINT_MAX; static int s_max_idle_secs = 300; static int s_stop; static void lsapi_cleanup(int signal) { s_stop = signal; } static lsapi_child_status * find_child_status( int pid ) { lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd; while( pStatus < pEnd ) { if ( pStatus->m_pid == pid ) { if (pid == 0) { memset(pStatus, 0, sizeof( *pStatus ) ); pStatus->m_pid = -1; } if ( pStatus + 1 > g_prefork_server->m_pChildrenStatusCur ) g_prefork_server->m_pChildrenStatusCur = pStatus + 1; return pStatus; } ++pStatus; } return NULL; } void LSAPI_reset_server_state( void ) { /* Reset child status */ g_prefork_server->m_iCurChildren = 0; lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd; while( pStatus < pEnd ) { pStatus->m_pid = 0; ++pStatus; } if (s_busy_workers) __atomic_store_n(s_busy_workers, 0, __ATOMIC_SEQ_CST); if (s_accepting_workers) __atomic_store_n(s_accepting_workers, 0, __ATOMIC_SEQ_CST); } static void lsapi_sigchild( int signal ) { int status, pid; char expect_connected = LSAPI_STATE_CONNECTED; char expect_accepting = LSAPI_STATE_ACCEPTING; lsapi_child_status * child_status; if (g_prefork_server == NULL) return; while( 1 ) { pid = waitpid( -1, &status, WNOHANG|WUNTRACED ); if ( pid <= 0 ) { break; } if ( WIFSIGNALED( status )) { int sig_num = WTERMSIG( status ); #ifdef WCOREDUMP const char * dump = WCOREDUMP( status ) ? "yes" : "no"; #else const char * dump = "unknown"; #endif lsapi_log("Child process with pid: %d was killed by signal: " "%d, core dumped: %s\n", pid, sig_num, dump ); } if ( pid == s_pid_dump_debug_info ) { pid = 0; continue; } if ( pid == s_ignore_pid ) { pid = 0; s_ignore_pid = -1; continue; } child_status = find_child_status( pid ); if ( child_status ) { if (__atomic_compare_exchange_n(&child_status->m_state, &expect_connected, LSAPI_STATE_IDLE, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { if (s_busy_workers) __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST); } else if (__atomic_compare_exchange_n(&child_status->m_state, &expect_accepting, LSAPI_STATE_IDLE, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { if (s_accepting_workers) __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST); } child_status->m_pid = 0; --g_prefork_server->m_iCurChildren; } } while(( g_prefork_server->m_pChildrenStatusCur > g_prefork_server->m_pChildrenStatus ) &&( g_prefork_server->m_pChildrenStatusCur[-1].m_pid == 0 )) --g_prefork_server->m_pChildrenStatusCur; } static int lsapi_init_children_status(void) { char * pBuf; int size = 4096; int max_children; if (g_prefork_server->m_pChildrenStatus) return 0; max_children = g_prefork_server->m_iMaxChildren + g_prefork_server->m_iExtraChildren; size = max_children * sizeof( lsapi_child_status ) * 2 + 3 * sizeof(int); size = (size + 4095) / 4096 * 4096; pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0 ); if ( pBuf == MAP_FAILED ) { perror( "Anonymous mmap() failed" ); return -1; } memset( pBuf, 0, size ); g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf; g_prefork_server->m_pChildrenStatusCur = (lsapi_child_status *)pBuf; g_prefork_server->m_pChildrenStatusEnd = (lsapi_child_status *)pBuf + max_children; s_busy_workers = (int *)g_prefork_server->m_pChildrenStatusEnd; s_accepting_workers = s_busy_workers + 1; s_global_counter = s_accepting_workers + 1; s_avail_pages = (size_t *)(s_global_counter + 1); setsid(); return 0; } static void dump_debug_info( lsapi_child_status * pStatus, long tmCur ) { char achCmd[1024]; if ( s_pid_dump_debug_info ) { if ( kill( s_pid_dump_debug_info, 0 ) == 0 ) return; } lsapi_log("Possible runaway process, UID: %d, PPID: %d, PID: %d, " "reqCount: %d, process time: %ld, checkpoint time: %ld, start " "time: %ld\n", getuid(), getppid(), pStatus->m_pid, pStatus->m_iReqCounter, tmCur - pStatus->m_tmReqBegin, tmCur - pStatus->m_tmLastCheckPoint, tmCur - pStatus->m_tmStart ); s_pid_dump_debug_info = fork(); if (s_pid_dump_debug_info == 0) { snprintf( achCmd, 1024, "gdb --batch -ex \"attach %d\" -ex \"set height 0\" " "-ex \"bt\" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2", pStatus->m_pid, pStatus->m_pid ); if ( system( achCmd ) == -1 ) perror( "system()" ); exit( 0 ); } } static void lsapi_check_child_status( long tmCur ) { int idle = 0; int tobekilled; int dying = 0; int count = 0; lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusCur; while( pStatus < pEnd ) { tobekilled = 0; if ( pStatus->m_pid != 0 && pStatus->m_pid != -1) { ++count; if ( !pStatus->m_inProcess ) { if (g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren || idle > g_prefork_server->m_iMaxIdleChildren) { ++pStatus->m_iKillSent; //tobekilled = SIGUSR1; } else { if (s_max_idle_secs> 0 && tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5) { ++pStatus->m_iKillSent; //tobekilled = SIGUSR1; } } if (!pStatus->m_iKillSent) ++idle; } else { if (tmCur - pStatus->m_tmReqBegin > g_prefork_server->m_iMaxReqProcessTime) { if ((pStatus->m_iKillSent % 5) == 0 && s_dump_debug_info) dump_debug_info( pStatus, tmCur ); if ( pStatus->m_iKillSent > 5 ) { tobekilled = SIGKILL; lsapi_log("Force killing runaway process PID: %d" " with SIGKILL\n", pStatus->m_pid ); } else { tobekilled = SIGTERM; lsapi_log("Killing runaway process PID: %d with " "SIGTERM\n", pStatus->m_pid ); } } } if ( tobekilled ) { if (( kill( pStatus->m_pid, tobekilled ) == -1 ) && ( errno == ESRCH )) { pStatus->m_pid = 0; --count; } else { ++pStatus->m_iKillSent; ++dying; } } } ++pStatus; } if ( abs( g_prefork_server->m_iCurChildren - count ) > 1 ) { lsapi_log("Children tracking is wrong: Cur Children: %d," " count: %d, idle: %d, dying: %d\n", g_prefork_server->m_iCurChildren, count, idle, dying ); } } //static int lsapi_all_children_must_die(void) //{ // int maxWait; // int sec =0; // g_prefork_server->m_iMaxReqProcessTime = 10; // g_prefork_server->m_iMaxIdleChildren = -1; // maxWait = 15; // // while( g_prefork_server->m_iCurChildren && (sec < maxWait) ) // { // lsapi_check_child_status(time(NULL)); // sleep( 1 ); // sec++; // } // if ( g_prefork_server->m_iCurChildren != 0 ) // kill( -getpgrp(), SIGKILL ); // return 0; //} void set_skip_write(void) { s_skip_write = 1; } int is_enough_free_mem(void) { #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) //minimum 1GB or 10% available free memory return (*s_avail_pages > s_min_avail_pages || (*s_avail_pages * 10) / s_total_pages > 0); #endif return 1; } static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Request * pReq ) { struct sigaction act, old_term, old_quit, old_int, old_usr1, old_child; lsapi_child_status * child_status; int wait_secs = 0; int ret = 0; int pid; time_t lastTime = 0; time_t curTime = 0; fd_set readfds; struct timeval timeout; sigset_t mask; sigset_t orig_mask; lsapi_init_children_status(); act.sa_flags = 0; act.sa_handler = lsapi_sigchild; sigemptyset(&(act.sa_mask)); if( sigaction( SIGCHLD, &act, &old_child ) ) { perror( "Can't set signal handler for SIGCHILD" ); return -1; } /* Set up handler to kill children upon exit */ act.sa_flags = 0; act.sa_handler = lsapi_cleanup; sigemptyset(&(act.sa_mask)); if( sigaction( SIGTERM, &act, &old_term ) || sigaction( SIGINT, &act, &old_int ) || sigaction( SIGUSR1, &act, &old_usr1 ) || sigaction( SIGQUIT, &act, &old_quit )) { perror( "Can't set signals" ); return -1; } while( !s_stop ) { if (s_proc_group_timer_cb != NULL) { s_proc_group_timer_cb(&s_ignore_pid); } curTime = time( NULL ); if (curTime != lastTime ) { lastTime = curTime; if (lsapi_parent_dead()) break; lsapi_check_child_status(curTime ); if (pServer->m_iServerMaxIdle) { if ( pServer->m_iCurChildren <= 0 ) { ++wait_secs; if ( wait_secs > pServer->m_iServerMaxIdle ) return -1; } else wait_secs = 0; } } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) *s_avail_pages = sysconf(_SC_AVPHYS_PAGES); // lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n", // s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages); #endif FD_ZERO( &readfds ); FD_SET( pServer->m_fd, &readfds ); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout); if (ret == 1 ) { int accepting = 0; if (s_accepting_workers) accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST); if (pServer->m_iCurChildren > 0 && accepting > 0) { usleep(400); while(accepting-- > 0) sched_yield(); continue; } } else if ( ret == -1 ) { if ( errno == EINTR ) continue; /* perror( "select()" ); */ break; } else { continue; } if (pServer->m_iCurChildren >= pServer->m_iMaxChildren + pServer->m_iExtraChildren) { lsapi_log("Reached max children process limit: %d, extra: %d," " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n", pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren, s_busy_workers ? *s_busy_workers : -1 ); usleep( 100000 ); continue; } pReq->m_fd = lsapi_accept( pServer->m_fd ); if ( pReq->m_fd != -1 ) { wait_secs = 0; child_status = find_child_status( 0 ); sigemptyset( &mask ); sigaddset( &mask, SIGCHLD ); if ( sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0 ) { perror( "sigprocmask(SIG_BLOCK) to block SIGCHLD" ); } pid = fork(); if ( !pid ) { setsid(); if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK in child" ); g_prefork_server = NULL; s_ppid = getppid(); s_pid = getpid(); s_req_processed = 0; s_proc_group_timer_cb = NULL; s_worker_status = child_status; if (pthread_atfork_func) (*pthread_atfork_func)(NULL, NULL, set_skip_write); __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd, 0 ); //keep it open if busy_count is used. if (!s_keep_listener && s_busy_workers && *s_busy_workers > (pServer->m_iMaxChildren >> 1)) s_keep_listener = 1; if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem()) && pReq->m_fdListen != -1 ) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } /* don't catch our signals */ sigaction( SIGCHLD, &old_child, 0 ); sigaction( SIGTERM, &old_term, 0 ); sigaction( SIGQUIT, &old_quit, 0 ); sigaction( SIGINT, &old_int, 0 ); sigaction( SIGUSR1, &old_usr1, 0 ); //init_conn_key( pReq->m_fd ); lsapi_notify_pid( pReq->m_fd ); s_notified_pid = 1; //if ( s_accept_notify ) // return notify_req_received( pReq->m_fd ); return 0; } else if ( pid == -1 ) { lsapi_perror("fork() failed, please increase process limit", errno); if (child_status) child_status->m_pid = 0; } else { ++pServer->m_iCurChildren; if ( child_status ) { child_status->m_pid = pid; child_status->m_tmWaitBegin = curTime; child_status->m_tmStart = curTime; } } close( pReq->m_fd ); pReq->m_fd = -1; if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK" ); } else { if (( errno == EINTR )||( errno == EAGAIN)) continue; lsapi_perror("accept() failed", errno); return -1; } } sigaction( SIGUSR1, &old_usr1, 0 ); //kill( -getpgrp(), SIGUSR1 ); //lsapi_all_children_must_die(); /* Sorry, children ;-) */ return -1; } static struct sigaction old_term, old_quit, old_int, old_usr1, old_child; int LSAPI_Postfork_Child(LSAPI_Request * pReq) { int max_children = g_prefork_server->m_iMaxChildren; s_pid = getpid(); __atomic_store_n(&pReq->child_status->m_pid, s_pid, __ATOMIC_SEQ_CST); s_worker_status = pReq->child_status; setsid(); g_prefork_server = NULL; s_ppid = getppid(); s_req_processed = 0; s_proc_group_timer_cb = NULL; if (pthread_atfork_func) (*pthread_atfork_func)(NULL, NULL, set_skip_write); __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd, 0 ); //keep it open if busy_count is used. if (!s_keep_listener && s_busy_workers && *s_busy_workers > (max_children >> 1)) s_keep_listener = 1; if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem()) && pReq->m_fdListen != -1 ) { close(pReq->m_fdListen); pReq->m_fdListen = -1; } //init_conn_key( pReq->m_fd ); lsapi_notify_pid(pReq->m_fd); s_notified_pid = 1; //if ( s_accept_notify ) // return notify_req_received( pReq->m_fd ); return 0; } int LSAPI_Postfork_Parent(LSAPI_Request * pReq) { ++g_prefork_server->m_iCurChildren; if (pReq->child_status) { time_t curTime = time( NULL ); pReq->child_status->m_tmWaitBegin = curTime; pReq->child_status->m_tmStart = curTime; } close(pReq->m_fd); pReq->m_fd = -1; return 0; } int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq) { time_t lastTime = 0; time_t curTime = 0; fd_set readfds; struct timeval timeout; int wait_secs = 0; int ret = 0; lsapi_prefork_server * pServer = g_prefork_server; struct sigaction act; lsapi_init_children_status(); act.sa_flags = 0; act.sa_handler = lsapi_sigchild; sigemptyset(&(act.sa_mask)); if (sigaction(SIGCHLD, &act, &old_child)) { perror( "Can't set signal handler for SIGCHILD" ); return -1; } /* Set up handler to kill children upon exit */ act.sa_flags = 0; act.sa_handler = lsapi_cleanup; sigemptyset(&(act.sa_mask)); if (sigaction(SIGTERM, &act, &old_term) || sigaction(SIGINT, &act, &old_int ) || sigaction(SIGUSR1, &act, &old_usr1) || sigaction(SIGQUIT, &act, &old_quit)) { perror( "Can't set signals" ); return -1; } s_stop = 0; pReq->m_reqState = 0; while(!s_stop) { if (s_proc_group_timer_cb != NULL) { s_proc_group_timer_cb(&s_ignore_pid); } curTime = time(NULL); if (curTime != lastTime) { lastTime = curTime; if (lsapi_parent_dead()) break; lsapi_check_child_status(curTime); if (pServer->m_iServerMaxIdle) { if (pServer->m_iCurChildren <= 0) { ++wait_secs; if ( wait_secs > pServer->m_iServerMaxIdle ) return -1; } else wait_secs = 0; } } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) *s_avail_pages = sysconf(_SC_AVPHYS_PAGES); // lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n", // s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages); #endif FD_ZERO(&readfds); FD_SET(pServer->m_fd, &readfds); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout); if (ret == 1 ) { int accepting = 0; if (s_accepting_workers) accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST); if (pServer->m_iCurChildren > 0 && accepting > 0) { usleep( 400); while(accepting-- > 0) sched_yield(); continue; } } else if (ret == -1) { if (errno == EINTR) continue; /* perror( "select()" ); */ break; } else { continue; } if (pServer->m_iCurChildren >= pServer->m_iMaxChildren + pServer->m_iExtraChildren) { lsapi_log("Reached max children process limit: %d, extra: %d," " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n", pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren, s_busy_workers ? *s_busy_workers : -1); usleep(100000); continue; } pReq->m_fd = lsapi_accept(pServer->m_fd); if (pReq->m_fd != -1) { wait_secs = 0; pReq->child_status = find_child_status(0); ret = 0; break; } else { if ((errno == EINTR) || (errno == EAGAIN)) continue; lsapi_perror("accept() failed", errno); ret = -1; break; } } sigaction(SIGCHLD, &old_child, 0); sigaction(SIGTERM, &old_term, 0); sigaction(SIGQUIT, &old_quit, 0); sigaction(SIGINT, &old_int, 0); sigaction(SIGUSR1, &old_usr1, 0); return ret; } int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ) { int fd; int ret; int wait_secs; fd_set readfds; struct timeval timeout; if (s_skip_write) return -1; LSAPI_Finish_r( pReq ); if ( g_prefork_server ) { if ( g_prefork_server->m_fd != -1 ) if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 ) return -1; } else if (s_req_processed > 0 && s_max_busy_workers > 0 && s_busy_workers) { ret = __atomic_load_n(s_busy_workers, __ATOMIC_SEQ_CST); if (ret >= s_max_busy_workers) { send_conn_close_notification(pReq->m_fd); lsapi_close_connection(pReq); } } if ( (unsigned int)s_req_processed > s_max_reqs ) return -1; if ( s_worker_status ) { s_worker_status->m_tmWaitBegin = time( NULL ); } while( g_running ) { if ( pReq->m_fd != -1 ) { fd = pReq->m_fd; } else if ( pReq->m_fdListen != -1 ) fd = pReq->m_fdListen; else { break; } wait_secs = 0; while( 1 ) { if ( !g_running ) return -1; if (s_req_processed && s_worker_status && s_worker_status->m_iKillSent) return -1; FD_ZERO( &readfds ); FD_SET( fd, &readfds ); timeout.tv_sec = 1; timeout.tv_usec = 0; if (fd == pReq->m_fdListen) { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_ACCEPTING, __ATOMIC_SEQ_CST); if (s_accepting_workers) __atomic_fetch_add(s_accepting_workers, 1, __ATOMIC_SEQ_CST); } ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout); if (fd == pReq->m_fdListen) { if (s_accepting_workers) __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST); if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_IDLE, __ATOMIC_SEQ_CST); } if ( ret == 0 ) { if ( s_worker_status ) { s_worker_status->m_inProcess = 0; if (fd == pReq->m_fdListen) { if (s_keep_listener == 0 || !is_enough_free_mem()) return -1; if (s_keep_listener == 1) { int wait_time = 10; if (s_busy_workers) wait_time += *s_busy_workers * 10; if (s_accepting_workers) wait_time >>= (*s_accepting_workers); if (wait_secs >= wait_time) return -1; } } } ++wait_secs; if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs )) return -1; if ( lsapi_parent_dead() ) return -1; } else if ( ret == -1 ) { if ( errno == EINTR ) continue; else return -1; } else if ( ret >= 1 ) { if (s_req_processed && s_worker_status && s_worker_status->m_iKillSent) return -1; if ( fd == pReq->m_fdListen ) { pReq->m_fd = lsapi_accept( pReq->m_fdListen ); if ( pReq->m_fd != -1 ) { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST); fd = pReq->m_fd; lsapi_set_nblock( fd, 0 ); //init_conn_key( pReq->m_fd ); if (!s_keep_listener) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } if ( s_accept_notify ) if ( notify_req_received( pReq->m_fd ) == -1 ) return -1; } else { if (( errno == EINTR )||( errno == EAGAIN)) continue; lsapi_perror( "lsapi_accept() error", errno ); return -1; } } else break; } } if ( !readReq( pReq ) ) { if ( s_worker_status ) { s_worker_status->m_iKillSent = 0; s_worker_status->m_inProcess = 1; ++s_worker_status->m_iReqCounter; s_worker_status->m_tmReqBegin = s_worker_status->m_tmLastCheckPoint = time(NULL); } ++s_req_processed; return 0; } lsapi_close_connection(pReq); LSAPI_Reset_r( pReq ); } return -1; } void LSAPI_Set_Max_Reqs( int reqs ) { s_max_reqs = reqs - 1; } void LSAPI_Set_Max_Idle( int secs ) { s_max_idle_secs = secs; } void LSAPI_Set_Max_Children( int maxChildren ) { if ( g_prefork_server ) g_prefork_server->m_iMaxChildren = maxChildren; } void LSAPI_Set_Extra_Children( int extraChildren ) { if (( g_prefork_server )&&( extraChildren >= 0 )) g_prefork_server->m_iExtraChildren = extraChildren; } void LSAPI_Set_Max_Process_Time( int secs ) { if (( g_prefork_server )&&( secs > 0 )) g_prefork_server->m_iMaxReqProcessTime = secs; } void LSAPI_Set_Max_Idle_Children( int maxIdleChld ) { if (( g_prefork_server )&&( maxIdleChld > 0 )) g_prefork_server->m_iMaxIdleChildren = maxIdleChld; } void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ) { if ( g_prefork_server ) g_prefork_server->m_iServerMaxIdle = serverMaxIdle; } void LSAPI_Set_Slow_Req_Msecs( int msecs ) { s_slow_req_msecs = msecs; } int LSAPI_Get_Slow_Req_Msecs(void) { return s_slow_req_msecs; } void LSAPI_No_Check_ppid(void) { s_ppid = 0; } int LSAPI_Get_ppid(void) { return(s_ppid); } #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #include #else extern char ** environ; #endif static void unset_lsapi_envs(void) { char **env; #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) env = *_NSGetEnviron(); #else env = environ; #endif while( env != NULL && *env != NULL ) { if (!strncmp(*env, "LSAPI_", 6) || !strncmp( *env, "PHP_LSAPI_", 10 ) || (!strncmp( *env, "PHPRC=", 6 )&&(!s_uid))) { char ** del = env; do *del = del[1]; while( *del++ ); } else ++env; } } static int lsapi_initSuEXEC(void) { int i; struct passwd * pw; s_defaultUid = 0; s_defaultGid = 0; if ( s_uid == 0 ) { const char * p = getenv( "LSAPI_DEFAULT_UID" ); if ( p ) { i = atoi( p ); if ( i > 0 ) s_defaultUid = i; } p = getenv( "LSAPI_DEFAULT_GID" ); if ( p ) { i = atoi( p ); if ( i > 0 ) s_defaultGid = i; } p = getenv( "LSAPI_SECRET" ); if (( !p )||( readSecret(p) == -1 )) return -1; if ( g_prefork_server ) { if ( g_prefork_server->m_iMaxChildren < 100 ) g_prefork_server->m_iMaxChildren = 100; if ( g_prefork_server->m_iExtraChildren < 1000 ) g_prefork_server->m_iExtraChildren = 1000; } } if ( !s_defaultUid || !s_defaultGid ) { pw = getpwnam( "nobody" ); if ( pw ) { if ( !s_defaultUid ) s_defaultUid = pw->pw_uid; if ( !s_defaultGid ) s_defaultGid = pw->pw_gid; } else { if ( !s_defaultUid ) s_defaultUid = 10000; if ( !s_defaultGid ) s_defaultGid = 10000; } } return 0; } static int lsapi_check_path(const char *p, char *final, int max_len) { char resolved_path[PATH_MAX+1]; int len = 0; char *end; if (*p != '/') { if (getcwd(final, max_len) == NULL) return -1; len = strlen(final); *(final + len) = '/'; ++len; } end = memccpy(&final[len], p, '\0', PATH_MAX - len); if (!end) { errno = EINVAL; return -1; } p = final; if (realpath(p, resolved_path) == NULL && errno != ENOENT && errno != EACCES) return -1; if (strncmp(resolved_path, "/etc/", 5) == 0) { errno = EPERM; return -1; } return 0; } static int lsapi_reopen_stderr2(const char *full_path) { int newfd = open(full_path, O_WRONLY | O_CREAT | O_APPEND, 0644); if (newfd == -1) { LSAPI_perror_r(NULL, "Failed to open custom stderr log", full_path); return -1; } if (newfd != 2) { dup2(newfd, 2); close(newfd); dup2(2, 1); } if (s_stderr_log_path && full_path != s_stderr_log_path) { free(s_stderr_log_path); s_stderr_log_path = NULL; } s_stderr_log_path = strdup(full_path); return 0; } static int lsapi_reopen_stderr(const char *p) { char full_path[PATH_MAX]; if (s_uid == 0) return -1; if (lsapi_check_path(p, full_path, PATH_MAX) == -1) { LSAPI_perror_r(NULL, "Invalid custom stderr log path", p); return -1; } return lsapi_reopen_stderr2(full_path); } int LSAPI_Init_Env_Parameters( fn_select_t fp ) { const char *p; char ch; int n; int avoidFork = 0; p = getenv("LSAPI_STDERR_LOG"); if (p) { lsapi_reopen_stderr(p); } if (!s_stderr_log_path) s_stderr_is_pipe = isPipe(STDERR_FILENO); p = getenv( "PHP_LSAPI_MAX_REQUESTS" ); if ( !p ) p = getenv( "LSAPI_MAX_REQS" ); if ( p ) { n = atoi( p ); if ( n > 0 ) LSAPI_Set_Max_Reqs( n ); } p = getenv( "LSAPI_KEEP_LISTEN" ); if ( p ) { n = atoi( p ); s_keep_listener = n; } p = getenv( "LSAPI_AVOID_FORK" ); if ( p ) { avoidFork = atoi( p ); if (avoidFork) { s_keep_listener = 2; ch = *(p + strlen(p) - 1); if ( ch == 'G' || ch == 'g' ) avoidFork *= 1024 * 1024 * 1024; else if ( ch == 'M' || ch == 'm' ) avoidFork *= 1024 * 1024; if (avoidFork >= 1024 * 10240) s_min_avail_pages = avoidFork / 4096; } } p = getenv( "LSAPI_ACCEPT_NOTIFY" ); if ( p ) { s_accept_notify = atoi( p ); } p = getenv( "LSAPI_SLOW_REQ_MSECS" ); if ( p ) { n = atoi( p ); LSAPI_Set_Slow_Req_Msecs( n ); } #if defined( RLIMIT_CORE ) p = getenv( "LSAPI_ALLOW_CORE_DUMP" ); if ( !p ) { struct rlimit limit = { 0, 0 }; setrlimit( RLIMIT_CORE, &limit ); } else s_enable_core_dump = 1; #endif p = getenv( "LSAPI_MAX_IDLE" ); if ( p ) { n = atoi( p ); LSAPI_Set_Max_Idle( n ); } if ( LSAPI_Is_Listen() ) { n = 0; p = getenv( "PHP_LSAPI_CHILDREN" ); if ( !p ) p = getenv( "LSAPI_CHILDREN" ); if ( p ) n = atoi( p ); if ( n > 1 ) { LSAPI_Init_Prefork_Server( n, fp, avoidFork != 0 ); LSAPI_Set_Server_fd( g_req.m_fdListen ); } p = getenv( "LSAPI_EXTRA_CHILDREN" ); if ( p ) LSAPI_Set_Extra_Children( atoi( p ) ); p = getenv( "LSAPI_MAX_IDLE_CHILDREN" ); if ( p ) LSAPI_Set_Max_Idle_Children( atoi( p ) ); p = getenv( "LSAPI_PGRP_MAX_IDLE" ); if ( p ) { LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) ); } p = getenv( "LSAPI_MAX_PROCESS_TIME" ); if ( p ) LSAPI_Set_Max_Process_Time( atoi( p ) ); if ( getenv( "LSAPI_PPID_NO_CHECK" ) ) { LSAPI_No_Check_ppid(); } p = getenv("LSAPI_MAX_BUSY_WORKER"); if (p) { n = atoi(p); s_max_busy_workers = n; if (n >= 0) LSAPI_No_Check_ppid(); } p = getenv( "LSAPI_DUMP_DEBUG_INFO" ); if ( p ) s_dump_debug_info = atoi( p ); if ( lsapi_initSuEXEC() == -1 ) return -1; #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) lsapi_initLVE(); #endif } unset_lsapi_envs(); return 0; } int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders, const char * pBody, int bodyLen ) { LSAPI_SetRespStatus_r( pReq, code ); if ( pRespHeaders ) { while( *pRespHeaders ) { LSAPI_AppendRespHeader_r( pReq, *pRespHeaders, strlen( *pRespHeaders ) ); ++pRespHeaders; } } if ( pBody &&( bodyLen > 0 )) { LSAPI_Write_r( pReq, pBody, bodyLen ); } LSAPI_Finish_r( pReq ); return 0; } static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]); /* * Note: this code is harmless on little-endian machines. */ static void byteReverse(unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void lsapi_MD5Init(struct lsapi_MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void lsapi_MD5Update(struct lsapi_MD5Context *ctx, unsigned char const *buf, unsigned len) { register uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memmove(p, buf, len); return; } memmove(p, buf, t); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memmove(ctx->in, buf, 64); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memmove(ctx->in, buf, len); } /* * Final wrap-up - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *ctx) { unsigned int count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1]; lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memmove(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } int LSAPI_Set_Restored_Parent_Pid(int pid) { int old_ppid = s_ppid; s_restored_ppid = pid; return old_ppid; } int LSAPI_Inc_Req_Processed(int cnt) { return __atomic_add_fetch(s_global_counter, cnt, __ATOMIC_SEQ_CST); } PK ]33&gems/ruby-lsapi-5.6/ext/lsapi/lsapi.sonuȯELF>S@@,@8 @ P P !P ! h h !h !888$$ Std PtdpppQtdRtdP P !P !GNU2Hv`t+ƚ_C H‚3@(L`qCSlP*fRn}'3qѮl>&Sɶ ܮʼnSO`[is|&߱RD/y7řkՊ eY&09=By:%/=ejOzJ6'l#mNULCB1{!\$O#W23S=apbU06aD7jp#7ĴDIΊ=\4yݾCEкQuo rSѮIo|q%h6 󝵛 ' =qX[ u  f ! ysO[ |  [7 P + k & !\  2LRT s ? + q ux >A  # -r cH  "./  " "$7x n, 9  A 9 4, 2( F"Xf E  L r PG  {F pD Ѓ  K 5 ti~ @ z! b `. 8! ] 0Z\ e n  v 1 p Y ` o@  и @rl yj U @| - q]   m pY n  5 @o Pw$ }l! s U pT E 0u qS m7 mT 0(  p    {F 0qJ Ѝp @! |I   `  !b g P @@$ '! pl 6 n  P @!__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizecompareValueLocationset_skip_writesigactionsigemptyset__stack_chk_failreallocfcntlacceptsetsockoptmmapmemsetsetsidread__errno_locationclosewritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemexitlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidsignalg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamdlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectrb_str_newrb_hash_asetrb_funcallvrb_intern2rb_gc_markmunmaprb_check_typerb_obj_as_stringrb_f_sprintfs_fn_add_envrb_string_valuerb_string_value_ptrrb_eval_string_wraprb_str_new_staticrb_ruby_verbose_ptrrb_define_global_construby_strdupmkstempftruncaterb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_exec_recursiverb_default_rsrb_output_fsrb_output_rsrb_lastline_getInit_lsapichdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocrb_stdoutrb_stdinrb_hash_new__memcpy_chkrb_define_global_functionrb_define_methodrb_define_singleton_methodlibruby.so.2.7libm.so.6libc.so.6__environ_edata__bss_start_endGLIBC_2.14GLIBC_2.15GLIBC_2.4GLIBC_2.3.4GLIBC_2.2.5GLIBC_2.3/opt/alt/ruby27/lib64 ) 4 ii ? ti I ui U ii a P !@TX !T` !` ! ! ! !A ! ! !# !) !. !4 !; !J !Z !j !x ! ! ! ! ! ! !( !0 !8 !@ !H !P !X ! ` !!h !p !,x !< !@ !R !^ !r ! ! ! ! ! ! ! ! ! !  ! !' !: !Q( !_0 !r8 !@ !H !P !X !` !!!!!!!!$#!8!X!`!h!p!x!!!!!2!!<!H!J!R!V!V!W!!!m!{!!! !(!0!8!@!H!P!X!`!h!p! x! ! ! ! !!!!!!!!!!!!!!!!! !(!0!8!@!H!P!X! `!"h!#p!x!$!%!&!!'!(!!)!!!!*!+!,!-!!!!!.!/ !0(!0!18!@!H!3P!4X!5`!6h!7p!8x!9!;!=!>!?!@!!A!B!C!D!E!F!!G!!I!K!L!M!N !O(!0!P8!Q@!H!SP!X!T`!Uh!Xp!Yx!Z![!\!]!^!!_!`!!a!b!c!d!e!f!g!h!i!!j!k !l(!0!8!n@!oH!pP!qX!r`!h!sp!tx!u!w!x!y!z!|!!}!~!!!!!!!!!!!! !(!0!8!@!H!P!HH9 HtH5 % hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhq% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% DH= H H9tH Ht H=y H5r H)HHH?HHtH HtfD=5 u+UH=ڻ Ht H=> d ]wff.^ ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=n D ÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH= 1XtIٲ tH=a -HcH5`HEHv [ÉD1?H= `HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHt:HHt)HHtH{@Ht 1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDjHu48u P uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=)\HcB$HH@H,H9rZf.HH9vGH3LluHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L= L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$){H8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L  LgfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH  L$DIH Ic LEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcUL{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eHmthILM)MUI9t HItDL+t$HL[]A\A]A^A_DM@@M)(KIHt$HLHk8f.HAVLAUIATIUSHu\H߉{AD${LǃLSHu0{L[L]A\A]A^k[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIH Lc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAMt$PHLIFID$PA:I|$P}MD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHAPI\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1HL$Aߺؿu#DH'uD o߻D HZDeOAkDH}An}NcHtff.USHdH%(H$1HHu/HH$dH3%(uHĘ[]Կ@1H= tAUATA'USH 'DNuD H@AHH. HHtH- tʖ iƉlj JUDk H DcEuD蟹jf.H=z>H=G 11H\$HCX= f= DH Htxff.H HtxxHu Ht~xHU Ht~xH5 Htxff.=Ǝ D D Ð DAUATUHH=@=SH8dH%(H$(1mHtH H= H==FHE1 H边H= =Ht 1H薹 H=<HHt 1HmIAąWE1H=<Ht 1H< H=<蚳HtHǺ 1菳H=<sH H=<THtHǺ 1иYH=< H1 H蘸OH=f<HtHǺ 1oH=T<̲HtHǺ 1H1H=E<襲HtHǺ 1!H=2<~HtHǺ 1òH="<WHt]H= <AHt 1H轷 _H=<Ht 1H菷 D~ p b EH=;H=B u P5 5+ H=;蓱H 1H  …t Hw HHHHDƊ L;L ;L;C HLt@HֹL€D t%HtAHHt9HLuHfDHJHHJHuHHu1ۉH$(dH3%(H8[]A\A]fD H趲D1 sAHc讲L% HH a裮Åt= @b u l 5r `HH5=uHH5=1u HH5=Fff.AVIAUEATIUHSHt4Hu!(fDHH褭HLwH]HuMtEL[1]A\A]A^ÐIcLLH#EgHGHHܺvT2HGAWAVAAUIATUHoSH1HGO@ƉWDW?t;AĉDHH|@D)A9rhAGt4LLDHL9A?vWEfAIIIH޺@HH@ HLL9uA?DLHH[]A\A]A^A_ܱIATLfUHSFH?LHz?)ƒw=t19rLHfCAD$AD$ ID$071)2HCHLHCP?o H{1HMHHCPH)KXH[]A\ff.fAWAVAUATUSHdH%(H$1Ht^ IAfMcg IoA_@LHCHuMX8u =)~ uٽH$dH3 %( HĨ[]A\A]A^A_f~AAuIALJf8LS|xr@tPHf@HPXN MgA;G ZA9~uEo)HHcIHLD2Hu$G85} uAMgA9ID$,HD$HcIIDhAh(A9}A /HcIH4@HeHAIIh$A9}A HcIH4@HHAIIHl$p(ILHIILp$hMIc@o9gIcP[9SIcpG9?IcH39+IHHHHIHT$IIc@ H)IHHIHHHIHIIcHIHHHD$I9E1DL4t9dfH "H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0J| ALJt`{ { A{ 1LHcϩIHIGAo IuID%{ D-{ B(AA1IcH4IILI 9HqH=- IJDB(9xHqH=, XIJB($AD$IKAzHL$;Mbfo{ Lt$ LAoL$AT$Ml$)$踪 LL8HL$LH#LLH$ID$H$I3L$H1H D$$Dl$EDDl$H=Tz IHIDz MH=y t"LDLŃP|$臨Et$A9uHt$螤D=Ń5y $A?D5y t @AH5(L*HtHHy f)wy #AH5 l 1KH@H5Z*1YLH 1H菤IH5D21H5i21D%x x DD$4H=x IHtZEW7E1111H=u2H5)1耨E|$迦M2;|$藦E1H5)LuI}觧Ń1H5q)LKfD=w -w w ED$AIFH5(1覧HH)H5x0H1聧1H5(L 1H50LA#LH s2H s 解1H5(Laff.AVAUATUSHdH%(H$1D$ HH ;1Ll$Ld$Lt$ Hklbr {ul;LLD$CHv Ht@HTv Ht{1f|$=u u|H4tH舴H`q d1H$dH3 %(u}HĠ[]A\A]A^D賜 {H5h \Hfы{LA; ff.AWAVAUATUSHD=Tu dH%(H$1ExH@H-t H}u ;Ng DH-%u Ht 1aHEDp EH$L|$PDcA:E1AfD Up EDt EtHt Ht @fLH1HIc臝DHD$PHD$XA ?)ѺHH D9#11A|$MH p D9#H%t Ht @D9#%f AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$L̞H$LHHD$@迚AHLDŽ$hH$腞H$LHHD$0xPH$LHHD$8S+H$`L HHD$(.H$ LHHD$H ADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%q EHq Ht H=m 1蔞IL9t<1ձL5EDu EME1VFHm LH1HHc}՚}LD$LHD$PHD$X ?)ѺH1H T`1fm  '8Ht$(1ҿ 轘x=_5 q tH&q Ht @f,D9# DCHp Ht@Hp HtDc1DN @l =o {H5b HHAp Ht*Hqp HB(@HQp Ht@Ho H@˖8B-DAD9M=rk 譟=Vk Ho HtDHpo Ht A9HQo HtD҉T$$DE ~:E~5WT$$A˙A輙AuDE UM D9vHn AHtDH5j&1ƞD$藕0 H=O gT$fD}蠩C1mH|$IH|$HT$Ht$1萔61E Mt AMgMg{E1cCHt$1ҿ;H=t(Gf;)>fDD$$菔0d T$$WH=cT$WT$fDD#AfDnm RDh EBH;m H29h {H5_ ДH{wH='f̓H=M'0讖MAH… H{H\h H=JHt$1ҿ贒Hk rl L=rl Xl H5l 7l Hk HtHlX 11L=7l AGHk Ht{1蝦D-g EuHk Ht!E9~jg hk ;t Ht$@1ҿL$ Ht$01ҿHt$H1ҿHt$81ҿ֒Ht$(1ҿ ŒkHLSH$*&$ޒL$踒ij j H=?"J%˚,H=$"QHj Ht*fC1CD$CCT$HC(HC j fD=~j |j ff.@H5f f.ffDn Hff.HV HH+HHODH1f1fATIHUSHchHcLHZH=#n HH[]A\ff.HH5i dH%(HD$1Hm H$Ht-H=m HHD$dH3%(u&H@H=0&跘HHi ffDHSHH=aU 謏HfHH=AU 茏Hc5 m ;5d H=l |6Hl Hl l HfD蛎f?IH=T HH+9M1~+HHcHc5yl H5fl 聐~cl Hfff.@HH=aT |tHHHDHff.UHSH H6Hm t]uaHHHtT؃tJ tEHH؉уu5HM u@HHpH}HH[]HD@HuHߎHMH tHPHpfSHCH[ff.SHSHH[ÐHH=1S LH}b HHH=S \H]b HHH=R 輑tH3b HHUSHH=R :H=uj HtKH`j H\j Zj 腍9Wj t H5e Hj Ht[11ҿ}1H4j ?H-Q H;HHu艔HuH;HjHka HH[]fH="HH}e SHH\$Ht$HH-1HH[ff.fAWAVAUAATIUSHHH=Z 1HH5"H=Z 1HH5H=Z 1HH5H=kZ 1HH5΂H=OZ 1HH5t貂H=3Z 1HH5^薂H=Z 1HH5JzH=Y 1HH55^H=Y 1HH5BH=Y H_H5#H=Y H H5~L%A H=~Y HLH-kA H A H=P HP HP HJH*H4Y H5A HH@ H[H=Y LH H @ H=RP HP HGP HJH*HS{H(K{HoHX 1H5X H= H3H= {H(H[]A\A]@HPHH=ET HwH3T H.XXXXXXH(Ht+H=uH=X 1HH5蜀H=W 1HH5耀H=W 1HH5dH=4ׂHHUS HW H=诂HH5S H=$ZH=xH>JfDmH{HfKHu{Ht -wN OkHU{Hu-ZN 2HHAnonymous mmap() failedlocalhost%02d:%02d:%02d [%s] [UID:%d][%d] %.*syesnosystem()%s, errno: %d (%s) /dev/nulllibpthread.sopthread_atforkHTTP_[UID:%d][%d] %s:%s: %s LSAPI: jail() failure./etc/Can't set signalsaccept() failedLSAPI_STDERR_LOGPHP_LSAPI_MAX_REQUESTSLSAPI_MAX_REQSLSAPI_KEEP_LISTENLSAPI_AVOID_FORKLSAPI_ACCEPT_NOTIFYLSAPI_SLOW_REQ_MSECSLSAPI_ALLOW_CORE_DUMPLSAPI_MAX_IDLEPHP_LSAPI_CHILDRENLSAPI_EXTRA_CHILDRENLSAPI_MAX_IDLE_CHILDRENLSAPI_PGRP_MAX_IDLELSAPI_MAX_PROCESS_TIMELSAPI_PPID_NO_CHECKLSAPI_MAX_BUSY_WORKERLSAPI_DUMP_DEBUG_INFOnobodyLSAPI_DEFAULT_UIDLSAPI_DEFAULT_GIDLSAPI_SECRETLSAPI_LVE_ENABLEliblve.so.0lve_is_availablelve_instance_initlve_destroylve_enterlve_leavejailPHP_LSAPI_PHPRC=packetLen < 0 packetLen > %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGNOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

    Resource Limit Is Reached

    The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
              replacesrandQUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMESTDERRreopenftruncate() failed. File mapping failed. Memory calloc error[...]nilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXRACK_ROOTchdir()to_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXX;{\f(q@qTrhr|rrrz8zl{`{{`|p},`~|pDl ,x P `x p @$ P8 `L ` | p Џ @ P@ T  0X l Й p p p Р ` 0| xpDX l`Ь0 @4PHp\pб 0@<|T@@`,@Th|` 80X @`0PPd@$8d zRx $X FJ w?:*3$"Dpb \mpmm LmsEIB E(A0z (A BBBI A (D BBBA m m@mYGJB B(A0A80F(B DBb0TtBFC G  AABK ,uk(uGADJ n AAA 4uUAGK R CAG L JCG uAG] AJ $Pvt C KFLH  AABG hEO D  A @ Th Y|XJEDS ؄]Ph H XAHlFBB B(A0A8LP 8A0A(B BBBH <8 FBB A(A0 (D BBBI \i`pdFBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH L $FBB A(A0H Q D 0A(A BBBH L$FBB B(A0A8G 8A0A(B BBBF tЌF FH$ԍnCXJLlFBB B(A0A8DA 8A0A(B BBBA `( ̏BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0 hBMD GL  AABA < =BAA G L@I@U  AABG $ TWEHG ( Lag H SHL ؓFBB B(A0A8DPS 8D0A(B BBBF T \bIE D(C0P (F BBBM Q(H BBBAH ԕFBB B(A0A8DP 8A0A(B BBBA T< hCBA A(G0` (A ABBD  (C ABBA J8 0-FBD D(D@T (A ABBB  $( 0lECGF AAI L t!cBG A(D0 (A ABBE XD0` Tt `Z 10 ؚpFAA G@7  AABF  @LsL 8FBB B(A0A8G 8A0A(B BBBG < P  d x   $ 0 <  8  40 <, FBA K(G (A ABBG <XFEE D(D0M (C BBBB <(HXFBH E(A0E8I@ 8A0A(B BBBE (FED ABH$ BBB B(A0A8G 8A0A(B BBBJ Dp4FBB A(A0G 0A(A BBBF L FBB B(A0A8G  8A0A(B BBBA LX4` H\\h+p|(xBFGA kFBzD O E  HU gHQ G <XaydT2HW I I(tEDL ] CAJ TELXEY\ HWd HWl-Hd( EAD  DAJ LH3ED hAHlhFBB E(D0C8GPm 8F0A(B BBBG ,<ZAD J ABL 4oAD  AAK pP \ 4FDA D(F0` (D ABBB j (D ABBE l(G DBBDBBI B(A0A8D@8D0A(B BBB\*HP H IlUKI8FBA D(D@ (A ABBE @t(TpEDG0 AAI HPFBB A(A0 (F BBBH {(F BBB@OFBB A(D0D@  0A(A BBBJ 8$KFBA A(D0 (A ABBE GNU@TT` !A#).4;JZjx !,<@R^r ':Q_r   k `> P !X !o` !.0&p o%oo$oDh !>>>>>>>?? ?0?@?P?`?p?????????@@ @0@@@P@`@p@@@@@@@@@AA A0A@APA`ApAAAAAAAAABB B0B@BPB`BpBBBBBBBBBCC C0C@CPC`CpCCCCCCCCCDD D0D@DPD`DpDDDDDDDDDEE E0E@EPE`EpEEEEEEEEEFF F0F@FPF`FpFFFFFFFFFGG G0G@GPG`GpGGGGGGGGGHH H0H@HPH`HpHHHHHHHHHI,LSLSLSLS!$#!GA$3a1`> GA$3p1113PTGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1113GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYPTGA+GLIBCXX_ASSERTIONSlsapi.so-5.6-3.el8.x86_64.debugԬ67zXZִF!t/wE]?Eh=ڊ2N뺉 ͕  (<φ5+#Sݠ`SNܓmA亍oLо3!pU]Ҍp1du~ ܡʎIq7sWMR-n8'QepFm@W^%%SKLd%58"] Dz0Nbv#8Rl G6hJ:tO~g4:YkrvX j2YL֠CS+gH< Ȅ5L`þ/鹌bځh̝t ljG穓I|x&[vE-i7hߠeȢ|SKPFYsEsceؚA'waj3ukқ rWC/! . N5:|Ė e7U$S ͐AO~I&3²c3vipHtjs4,acj'poapĤiGosa6عi^i뻪Ns(Fj]̚0?SB֋7cy ĜD[DГ?JA'&V rP05e-@c.(kto>4l 2'ezULvo-bVXߌn<@3~<'=b E1UXor+ǫ2g;&gA8L̵bOpW|}()*EPaJGz^"[3:ճ96Lɒ7L |1hE=Z_*/k1OLSO5=Y孽d e[8_uG _c 46`4+O(l|r\Fʚ=d,q0܁\mɮ- 8ءP724LJ)Q㘺 / ߗ-[Vq2kbT} t䛢iYzR>7'A<>2,X+:G@wA>+Bb Lwd{-{iJրd}aMM6uEG=rb+Ϛq/-bǿ_׸Q>[~kl S{v.ofT[oR#`GT1/[ ~zѓܹTo.aߓoh;0=1=G걟Wg7/c,D`+!kl?5*NMr5-mpI/P4H$T]sk_RZlKZU9aqu&x5U B')CAB&_\7"PHMiưrT+Hœ$f!\/+CM54#E բ$^*AU&\-rrߖ0ZcK-z-r!YݶOZznʊ̳mn+@&ZfQ WjF;^O4vAr-W9O3M\F @ƏIh-ƒPY{X9v[jۦi?6oq WUA {4Хԉ7I2 gWfp "OQEAVy\g(9dNC_/r {i0BiK_v(~oOES?A.6)D;bKvzY?<'ϱgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``p( 0 8o$$Eo%%pT0&0&p^B..h`>`>c>> nII wSSK}} p ppXXL P !P X !X ` !`  h !h X!X!X`!` @!@ 'a@\#$"#+1PK ]gy&gems/ruby-lsapi-5.6/ext/lsapi/lsruby.onu[ELF>@@98 ,.+/*0)1fDHff.HHH+HHODH1f1fATIHUSHcHcLHH=HH[]A\ff.HH5dH%(HD$1HH$Ht-H=HHD$dH3%(u&H@H=HHfDHHH=HfHH=Hc5;5H=|6HHHfDf?IH=HH+9M1~+HHcHc5H5~Hfff.@HH=tHHHDHff.UHSH HHm t]uaHHHtT؃tJ tEHH؉уu5HM u@HHpH}HH[]HD@HuHHMH tHPHpfSHCH[ff.SHHH[ÐHH=HHHH=HHHH=tHHHUSHH=H=HtHH9t H5Ht[11ҿ1H?H-H;HHuHuH;HHHH[]fH=HHSHH\$Ht$HH1HH[ff.fAWAVAUAATIUSHHJfDmHHfKHHt -OkHHu-2 GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realignreplacesrand/QUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMESTDERRreopen%s: %s ftruncate() failed. File mapping failed. Memory calloc error [...]nilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXLSAPI_CHILDRENRACK_ROOTchdir()ENVto_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXXF 9%I'P(int)@ 9 1 3 6  7  8  9 : ( ; 0 < 8 = @ @ H A P B X D` Fh Hp It J x MP NW O Q Y [ \ ] ^ G _ - ` b  +  9  9 ? M     UJ U   U a}^q!$2 7 ;  f9:IDg9@4 @b     I  @`  @ @ @x@v#w :xF@@  :@5   Z :len ptr aux5Zary  9(as@2 W$Flen aux%2ptr&F'Wary( F 9(as)(sA tu L v L w G L !GA "L ::::::::::::::::::::::::::::::::::::::::::::::::: : : : : ::::::::::::::::::: :!:":#:%:&:':(:*:,:,:,(:G:H:I:J:K::  9 7 89:;<=>#@,     $q=%s%t k m n  o  p  u ,  =                $  ( D D  T4 T 9 d 9                "= " 4 6 7  /k 1 2  3  4 & : < = ? @ B C E( F0 G8 I@ JH KP L!X O` Ph Qp Rx T' V' W' X' Y' Z' \' ]' _ ` a b c d e f g h i'k''m'('n'8'oG    G  -=)d = 9 j(9qks)?!!!!!G-.P  W  c  9 c A W   F*WTQQ  )4?JU`Akv$  !{$$% $% 4% D 4 9 D 9 T 9 o  Too I 9  9@+":+#:,$: ,(: ,*: ,,: ,.  9-req;-env<: =)!!!->Q,@: ,B: ,C ,E: +F,G~  Iy K L M NO7,Qy  (9,R  .  /4K$06 :1p7 08 23Z*K 4C5U 5T320[6[$0[23[K 4C5U 5T74C5Q05R02`0 :4C5TH5Q 5R|20:4C5TH5Q 5R|7 %:8-%<9:;%:F%8/: :;A:4C5Us5T05Q:<CY5U <Cw5Us5TM<C5Us5Tm<C5Us5TK4C5Us5Tk8%=9:!%8:(^;":;:4C5U 5Ts5Qv5R =9* ;9;9<C5U 4C5Us8/:@;A:4C5T05Q:> D<C@5U >D>$D<Cy5U >1D>>D<KD5U <XD5U 5T7<XD5U 5TA<eD5Q}??5U 5T 5Q1<rD^5U ?5T 5Q 5R0?5T 5Q 5R0?5T 5Q 5R1? 5T 5Q 5R1?@ 5T 5Q 5R ?n 5T 5Q 5R ? 5T 5Q 5R ? 5T 5Q 5R1? 5T 5Q 5R0?#!5T 5Q 5R0?P!5T 5Q 5R0?~!5T 5Q 5R ?!5T 5Q 5R0?!5T 5Q 5R0?"5T 5Q 5R0?2"5T 5Q 5R0?_"5T 5Q 5R0?"5T 5Q 5R0?"5T 5Q 5R0?"5T 5Q 5R0?#5T 5Q 5R0?@#5T 5Q 5R1?n#5T 5Q 5R <KD#5U <KD#5U >D>D>D>b4<D#5U <D$5U >D?X$5T 5Q 5R0?$5T 5Q 5R0?$5T 5Q 5R0<D$5U 4C5U  F$@%$A- B" -%Cp$B R%Cn CpD:%E E-E9:6 :F3 *K G:g4&H :Iw+ >D>D>DG:v&J":UJ-:TK:&E:D:&E!:G:&J":UG:+C'J:UL8 M8G:Ua(H:1str :=a( ';s(7+ 8)S(;*9N*:+*N8*:C*<>D(O*s>,+>DD:(E!:Gy:4)HyHy*Hy6:1str{ :1n| 0} 0~ 89 w);9>D>D>,+<D)5Us $ &<O*)5U|< E)5U}5Qs $ &4 E5U}5Q| $ &DJ:O*EJ :CstrL :6MCnN CpO G5 a+H5"P7 08 09 0: 6; 88;+M8>EQ0Q+R K+Cfd Rw+Cfd Csfn QG:2+H :1ch >%EG:%,H!:>DG:,Sout!:Sstr,:4/5Us5TTD:,EE*Tout6:Ci 6 :Dl:2-Taryl#:Toutl.:El7Ctmpn :Cio Gc:-HcHc,Soutc8:<1E-5UU5TT4/5UsG?:O/H?H?,Sout?8:1iA 3B :@8'9Qv.;99<XD.5U~5T3</.5Uv</.5Uv</.5Uv</.5Uv>>E>KEU3:0H3!:Sstr3-:051len6 897/;94TE5Uv5T<8'99 /;994aE5UsG':K1H':Sc'+:Vch) W0*8G9)0;Y9W9f;9<D05Us>D89+$1;94TE5Uv5T<?=15TW5Q1>KEG: ~1J#:UG:32H+:Sstr7:<nE15Us<{E15Us4E5T0X: S2Y,:>EX: 2Y+:>EX:-2Y,:>EX:H4Y$:Zpid 23[ + $[ 23, K 4C5U 5T54C5U85Q05R0\H4 4;U4>b4<E 45Qs4E5Qs>E>D>$D] b4^)_ z52 5`,*5``24,K 4C5U 5T74C5Q15Rw>KE F*5 95X B6Y)Y3YHYTaarg#G<E55UQ5T R $ &<E55U|5Ts $ &4eD5QvXk B8Yk(Yk2YkGYkSaargl"GZpn bleno <E65U|5T~<E65Us5Tv $ &<eD75Q|<E175U|5T?<EQ75U|5T<XDu75U 5T9<eD75Qw<E75U|5T<XD75U 5T<<eD75Qw<E 85U5T}<XD-85U 5T<4eD5Q}ca 8Ya&dEe8^?e8^<D8Ta:f !:D 9Ta$:Dy'9Tay:D?G9Tobj?:Dae9Txa:D:9Tx:EECDG9Tobj:D9Tx:g:^^g\/:^\^\hiO:Eigdz:^d!^d<ija(:ks(Uj&:k&UjR%;;d%;q%;~%N%WR%;~%;q%;d%9:%l%;4C5U 5T6>D>D<D;5U >DmC5QU5RTj,+>n>+=86<M8Iw+8,+ >9:>+8K+=9:]+:i+8O: =;l:;`:4F5T15Q 5Rs<F7=5U <FO=5Us<,Fg=5Us<D=5Us>9F>EF4D5Us<RF=5Uv5Ts<_F=5U05Ts5Q35R15Xv5Y0<kF>5Uv<D6>5U <kFN>5Uv<Dm>5U 4kF5Uv<xF>5T14D5U j)?:*N+*:8*:C*;*I+_ <O*E?5U <Fx?5U|"5Tv5Q 5R1<D?5Uv4 E5U|5Qvj)*@;*N*o+*N8*pC*>,+m>O*Uj,;B;,;,; -q-@:&-8 9w@;9=e9y@;9;9;w94F5Us88yZA;8988 DA;84F5Us=,'l B;,; -;,r'q-@N&-<XDA5U 5T54F5U15Tw5Qv<F-B5U15Tw5Qv>KEj,PC;,;,;,N,N,s,qCM,M,M,9:,:,8'9B;99<FC5U 5Qs>aE</>C5Us5T~</VC5Us4XD5U|5T34/5Usttetutwvw/tmp/lsapi.XXXXXXvw .XXXXXXtu{tnttt tttt7ttt0t t  uuL t3 ttttt$u uttxtRttVtWtcttt}uut^tutuZ u Dt t9 u% tt u9ta ttqw lsruby.ctttYt% : ; 9 I$ >  $ > &I I7I I !I/  : ; 9  : ; 9 I8 : ; 9 <4: ; 9 I?<!4: ;9 I?<: ; 9 I> I: ;9 ( (((   : ;9  : ;9 I8  : ;9  : ;9 I : ;9  : ;9 I8  : ;9 I : ;9 I 8 '!I": ;9 I#> I: ; 9 $ : ; 9 % : ; 9 I& : ; 9 ' : ; 9 I8(!I/)'I* : ;9 +4: ; 9 I,4: ; 9 I- : ; 9 I8 .4: ; 9 I?/.?: ;9 @B04: ;9 IB14: ;9 IB2 U34: ;9 I415B64: ;9 I71RB UX YW 81RB UX YW 9 U:41B;1B<1=1RB X YW >1?@!I/ A.: ;9 B.: ;9 C4: ;9 ID.: ;9 'I E: ;9 IF G.: ;9 'I@BH: ;9 IBI1RB X YW J: ;9 IK.: ;9 'IL1RB X YW M1N41O1BP4: ;9 IQ.: ;9 I R.: ;9 I S: ;9 IBT: ;9 IU.: ;9 'I@BV4: ;9 IW1RB UX YW X.: ; 9 'I@BY: ; 9 IBZ4: ; 9 IB[4: ; 9 IB\1RB UX Y W ].: ; 9 ' ^: ; 9 I_.: ; 9 @B`4: ; 9 I a: ; 9 IBb4: ; 9 I c.: ; 9 '@BdB1e.: ; 9 'I f.?: ;9 '<g.?: ; 9 'I 4h.?: ;9 'I ij.1@Bk1l 1UmB1n41 o41p41 q41r s1UX YW t.?<n: ;9 u.?<n: ; 9 v.?<n: ; w6x.?<nOVOTpqPPqP0uVT0V0T0?0T0?0nPP PPSSPS,8P8HSHcTSSH\TpSH\ Tp vv vPUU U  S  P U U  S  P S  S      0  0 U S D UD g Sg u Uu  S U S U T V D TD a Va u Tu  V T V T Q Q P  ] + P+ C ]C D P ] S  SW u P \ v| v| $0 $+(  v $0 $+( ? v $0 $+( v $0 $+(  P PL V Uu | U U u@aUN $ &"^a $ &"O^PNQ^aQpUUPPpUU`lUlqSqrP`lTlrTUUTTQSQPUwwUw1PT]wTTWPQpVpwQwQV{0S8=S0 s $ &3$}") s $ &3$}"UVWUTS,AS&V,WV+PUVS,9S0 U V U V0 S TS S T S PP S TS S S S S U VU3UTUUUUU U!U!UkPP0000SU\UTSTQQRRXX@USSSS@TVTTVTVT_V@Q\3Q3\JQJ_\@{R{]R]RG]G^ R Z]Z_^@XX3X3XJXJ_X7PPP_JTPT__`hUhmU`USQUS`TVRTV`QQQQVRTVSQUS\\rV * Vg q  q V@Y YiPiV * V* 4 P4 VRVPVyS* q SN q U Z pZ ^ UR n Pn \ PD } S  P6 > P * U U T UT S U S U  U T TT V T V T  V T QT Q Q  QT ] } ] ]T _ S Sd  d  y  yd l Sl  S Sv  S S U  U Q  Q T  V1U1.U.:U:PU1T1.T.=T=PT1Q1SQ.S.AQACSCPQ10UP^P.^1_UU,8U 8U/09szsz@ @r0 g < K N _ L W x  X _ l  v  P 08_0cXH\\cXpv@` 0@ $@LnW /opt/alt/ruby27/include/ruby/usr/include/bits/usr/include/usr/lib/gcc/x86_64-redhat-linux/8/include/usr/include/bits/types/usr/include/sys/usr/include/netinetlsruby.clsapilib.hruby.hstdio2.hstdlib.hstring_fortified.hstddef.htypes.hstruct_FILE.hFILE.hstdio.hsys_errlist.htypes.hstdint-intn.hstdint-uintn.hunistd.hgetopt_core.hmath.hintern.hversion.hlsapidef.htime.hstruct_iovec.herrno.hsockaddr.hsocket.hin.hsignal.hstring.hmman.hutil.h  JK?K| #t>iK>KK{KY;./*X **}( // RX} t     0Yf q\:>X. t" u t/u* uZ ^  %gfu Z3 X |t |< tXX uKt  .t.  X  f. f *8u t  X    o.@5< t-< ti JJ [X &JiX V  L( ff&X< u9= t; K1 tQJ/f J L 2  =t<UMtUX&<< ` 0z X .    =Yl  rX[wt Z " h   m grtX  h fY:g< KXfKY sbXtv  SY|X |X<   L/$ eX< z < zt yt5Y|X |.X z  Z rh Y   *xp*suqwZ7Mt -uDXZ;467954644584236:8648: "u{ wt JvI ;tZvpJuI==[X=XvXuv0X>f~z t gz t ` X p((* uv #G< Y(%[$ rb_mWaitWritable_sys_errlistm_pScriptFileRUBY_Qnilrb_eNoMemError_unused2_filenorb_cMethodrb_obj_wb_unprotectrb_eSyntaxErrorm_cntUnknownHeadersH_AUTHORIZATIONsockaddr_isoblockSizem_pIovecEndstrcpym_pRespBufPosRUBY_FL_EXIVAR__uint8_tdmarkRUBY_DATA_FUNCm_pktHeaderrb_eIOErrorm_bytesm_pHeaderrb_data_object_get_shortbufsockaddr_inrb_cFilerb_eSignalunlinklsapi_dataRUBY_T_ARRAYrb_eKeyErroradd_env_rails__environlsapi_addstrsa_datauint16_tm_totalLensin_zeroRUBY_FL_UNTRUSTEDrb_eZeroDivErrorin_port_t_flagslsapi_getscallocm_respPktHeader__off_tcreateTempFiledfreeRUBY_T_IMEMOrb_global_variable_lockROBJECT_EMBED_LEN_MAXRUBY_T_UNDEFrb_cStringrb_eEOFErroratoim_pHttpHeaderLSAPI_GetReqBodyRemain_rm_pScriptNamerb_mKernelm_pEnvListrb_output_fsint32_t__fmtsa_familym_specialEnvListSizerb_cModulesockaddr_ns__u6_addr8RUBY_T_FALSEruby_robject_flagsrb_cIntegerRUBY_T_FILE_IO_write_endm_iLensockaddrrb_cTrueClasss_addrRUBY_FL_USER0RUBY_FL_USER1RUBY_FL_USER2RUBY_FL_USER3RUBY_FL_USER4RUBY_FL_USER5RUBY_FL_USER6RUBY_FL_USER7RUBY_FL_USER8RUBY_FL_USER9nameLenLSAPI_Postfork_Childfreerb_fsm_requestMethodOffRUBY_T_COMPLEXdata_struct_objrb_eEncCompatErrorruby_special_constsvalLenRSTRING_EMBED_LEN_SHIFT__stack_chk_failruby_rarray_flagsruby_descriptionsin_familyRStringm_fdListenMAX_BODYBUF_LENGTHlsapi_bodym_statusm_reqBodyLenrb_eNameErroroptargneedReadrb_eRegexpErrorrb_cBasicObjectRUBY_T_STRUCTrb_cRationalrb_cFloatrb_cClassrb_cStatsys_errlistin_addr_tbasicRUBY_QtrueLSAPI_ReqBodyGetChar_rpKey__uint16_tsin_portRUBY_T_STRINGrb_cContrb_cFalseClassm_flagRARRAY_EMBED_LEN_SHIFTreadMaxBodyBufLengthm_pQueryString_chainRUBY_T_MODULErb_eArgErrorrb_eInterruptrecurrb_funcallvRUBY_FL_SINGLETONsockaddr_ununsigned charcapanReadm_cntSpecialEnv_IO_lock_tRUBY_T_ZOMBIEfloatLSAPI_key_value_pairLSAPI_ForeachHeader_r/builddir/build/BUILD/opt/alt/ruby27/share/gems/gems/ruby-lsapi-5.6/ext/lsapirb_stderrlsapi_eachm_cntHeadersrb_str_catbodyBufRARRAY_EMBED_LEN_MAXRUBY_T_FIXNUMrb_eSecurityErrorisEofBodyBuflsapi_processlsapi_flushRARRAY_EMBED_FLAGROBJECT_EMBEDoff_tchild_statusRUBY_SYMBOL_FLAGrb_mComparableH_X_FORWARDED_FOR__fprintf_chkm_queryStringOffRUBY_FLONUM_FLAGrb_stdoutruby_rstring_flagsH_CONTENT_LENGTHrb_cTimeruby_engine_IO_write_ptrrb_output_rsROBJECT_ENUM_ENDlsapi_packet_headerLSAPI_ReadReqBody_rrb_eFatallsapi_http_header_indexrb_funcall_argcsTempFilerb_funcall_argsclosesharedlsapi_printfRUBY_T_OBJECTFILEH_COOKIEs_fn_add_envmunmapRSTRING_EMBED_LEN_MAXbodyCurrentLenLSAPI_Accept_Before_Forkrb_cNumerics_req_stderrrb_cHashsize_trb_array_const_ptrH_CONNECTIONrb_rsuint8_tH_CONTENT_TYPERArraylsapi_markm_headerLenRUBY_ELTS_SHAREDperrorlsapi_envruby_release_daterb_cDirsetup_cgi_env_IO_save_baseioveclsapi_eofrb_array_const_ptr_transientenvironlsapi_child_statusreadTempFileTemplaterb_str_newsockaddr_x25rb_eLoadErrorsin6_flowinfom_pIovecToWriteorig_stderrm_respHeaderLen_wide_dataH_IF_MATCHRUBY_FL_PROMOTED0RUBY_FL_PROMOTED1__in6_uH_ACC_CHARSETruby_versionorig_stdout__streamsigngamruby_copyrightm_reqBufSizerb_eExceptionrb_yieldadd_env_no_fixRUBY_T_FLOATRUBY_T_CLASSrb_cDataftruncateruby_fl_typelsapi_requestrb_cComplexfprintfrb_check_typeRUBY_T_HASHsyncRUBY_T_NODEchdir__ssize_t__srcrb_mErrnolsapi_closeH_IF_RANGEnameOffruby_api_versionstrerrorsa_family_tm_packetLenreadMoreRUBY_FL_WB_PROTECTEDin6_addrisBodyWriteToFilelinesin6_addrrb_mWaitReadablelsapi_setsyncm_respPktHeaderEndRUBY_FL_TAINTLSAPI_Postfork_Parentfn_add_envlsapi_printrb_eSystemCallErrorrb_intern2stderrm_pHeaderIndexprogram_invocation_short_namerb_cUnboundMethodrb_f_sprintf_IO_save_endrb_const_get__nptrLSAPI_InitLSAPI_Requestrb_eScriptErrorfn_writelsapi_syncm_bufProcessedstdoutreadBodyBufoptoptlsapi_reopenrb_mGCrb_eIndexErrorm_httpHeaderLencurPosH_IF_NO_MATCHlsapi_s_acceptpreforkRUBY_T_DATAbuffssizetypekeyLenRUBY_FL_DUPPED__builtin_strchrLSAPI_Flush_rshort unsigned intsigned charrb_array_lentz_dsttimefilenamelsruby.clsapi_header_offset__off64_tsockaddr_eon_IO_read_base_offsetm_pIovecrb_string_value_ptrrb_eFloatDomainError_IO_buf_endm_respInfoopterrlsapi_puts_ary_modeblkSize_IO_write_basevalueLenInit_lsapirb_eStandardErrorrb_cSymbolrb_argv0H_CACHE_CTRLH_COOKIE2__destrb_cMatchrb_cEncodinglsapi_isattyH_USERAGENTRARRAY_EMBED_LEN_MASKLSAPI_ForeachEnv_rlong intRUBY_T_NONErb_mProcessrb_mFileTestremain_IO_markerrb_cEnumeratorm_pRespBufEnd__builtin___memcpy_chkrb_io_putslsapi_s_postfork_childrb_define_global_constrb_obj_as_stringm_bufReadin_addruint32_tsockaddr_in6__pid_t_IO_codecvtrb_funcall_nargsH_RANGERDatastrtolg_reqlong doublerb_cRangeiov_lenlsapi_resp_inforb_cObjectlong unsigned intlsapi_req_headerRVALUE_EMBED_LEN_MAXrb_gc_markinitBodyBufruby_strdupm_headerOffrb_eNotImpError__errno_locationlsapi_s_postfork_parentcharsockaddr_inarpm_pSpecialEnvListsin6_scope_idrb_cIORSTRING_ENUM_ENDstdinsin_addrRUBY_T_BIGNUM_IO_buf_baseRSTRING_NOEMBEDRUBY_T_RATIONALRUBY_FL_PROMOTEDs_bodyrb_eTypeErrorRBasicrb_eNoMethodError_IO_read_endRUBY_T_ICLASSrb_num2intcLSAPIRUBY_SPECIAL_SHIFT_IO_FILEH_IF_UNMOD_SINCEm_fdRUBY_T_SYMBOLH_HOSTrb_num2char_inline_IO_wide_datastrlen__u6_addr16s_pidselfrb_eSystemExitisAllBodyReadm_respHeaderrb_cThreadRUBY_FL_SEEN_OBJ_IDm_envListSizem_pAppDataruby_platformsockaddr_ax25RSTRING_FSTRrb_eThreadError__pad5rb_str_new_staticshared_root__u6_addr32rb_cNilClassm_type_markersrb_stdinrb_eStopIterationm_scriptFileOffRUBY_FL_USHIFTklassrb_define_classH_VIA_codecvtm_pRespHeaderBufEndH_PRAGMARUBY_FL_FINALIZErb_cRandomdoublemkstemplsapi_putcargcssize_tstrcatlsapi_writelsapi_putsorig_stdinRUBY_FIXNUM_FLAGargvRARRAY_ENUM_ENDrb_eRuntimeErrorm_pRespHeaderBuf__int32_trb_cProc__uint32_tRUBY_IMMEDIATE_MASKrb_hash_asetdataH_REFERERrb_cStructLSAPI_Prefork_Accept_rheap_sys_siglistRARRAY_TRANSIENT_FLAGm_pUnknownHeaderrb_typem_reqStateRUBY_T_NILRUBY_T_MOVEDrb_eSysStackErrorGNU C17 8.5.0 20210514 (Red Hat 8.5.0-28) -mtune=generic -m64 -march=x86-64 -g -O2 -fPIC -fexceptions -fstack-protector-strong -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection=full -fplugin=gcc-annobinm_pRespBufrb_num2int_inlineprogram_invocation_namerb_cArrayrb_eEncodingErrorrb_ruby_verbose_ptrrb_cBindingrb_intern_id_cacheH_TRANSFER_ENCODINGH_IF_MODIFIED_SINCErb_ary_detransientRUBY_FL_USER10RUBY_FL_USER11RUBY_FL_USER12RUBY_FL_USER13RUBY_FL_USER14RUBY_FL_USER15RUBY_FL_USER16RUBY_FL_USER17RUBY_FL_USER18RUBY_FL_USER19_freeres_bufRUBY_T_MATCHlong long unsigned intpid_t_cur_columnlsapi_rewinds_reqrb_eRangeErrorm_pRespHeaderBufPoss_stderr_datarb_eval_string_wrapgetpidm_cntEnvRUBY_T_MASKrb_lastline_getcreateBodyBuf_IO_backup_baseH_KEEP_ALIVE__memcpy_chk_IO_read_ptrrb_eMathDomainErrorrb_fix2intLSAPI_GetReqBodyLen_rrb_gc_writebarrier_unprotectrb_exec_recursivegetenv_freeres_listrb_eLocalJumpError_sys_nerrlsapi_readtimezonepReqlsapi_getcrb_hash_newclear_envrb_cRegexplsapi_binmode_old_offsetstrchrm_pReqBufrb_cNameErrorMesgvalueOffoptindH_ACC_LANGlong long intin6addr_loopback_flags2VALUErb_mMathRUBY_T_TRUEmemmemsin6_familysockaddr_atruby_value_typem_scriptNameOffH_ACCEPTm_lLastActiverb_eNoMatchingPatternErrorlsapi_resp_headersys_nerrin6addr_anym_pRequestMethods_req_dataiov_basem_lReqBeginruby_rvalue_flagsm_versionB0m_versionB1rb_str_buf_newRUBY_FLONUM_MASKruby_patchlevelRUBY_T_REGEXPm_pIovecCurLSAPI_Init_Env_Parametersorig_envm_reqBodyReadRUBY_Qundeflsapi_s_accept_new_connrb_eFrozenErrorsockaddr_dlRSTRING_EMBED_LEN_MASKRUBY_FL_FREEZEunsigned intbodyLensockaddr_ipxrb_default_rsshort intrb_string_value_vtable_offsetpValueenv_copymmaporig_verboserb_data_object_zallocrb_mEnumerableRUBY_Qfalseflagstz_minuteswestsys_siglistH_ACC_ENCODINGsin6_portlsapi_eval_string_wrapGCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-28)GNUzRx  0D+Xl(BFGA kFBzD O E  HUgHQ G $ayd<2HW I I(\EDL ] CAJ ELEY HW HW-Hd(EAD  DAJ 43ED hAHTFBB E(D0C8GPm 8F0A(B BBBG ,ZAD J ABL 4oAD  AAK pP \4FDA D(F0` (D ABBB j (D ABBE l(G DBBDhBBI B(A0A8D@8D0A(B BBB*HP H IUKI8FBA D(D@ (A ABBE ((<EDG0 AAI HhPFBB A(A0 (F BBBH {(F BBB@OFBB A(D0D@  0A(A BBBJ 8KFBA A(D0 (A ABBE   - )  ?.Yt/01 5 C _"y @"[0+[h` h)wCpPwmB pZz# < xEZ_mw` mpg0aIaUaop2WWr`r1KX   #J o-  X  ` 3D3[3x_@_`  3 N\ @f   4      '  *2  L  d  Uo     '   '   ' 0 2  L Pd Po P  PO          h "$%'./0123-4# ( - @2 )7 < 3A F K LP SU [ ba Zg xm s y           $ * f n s y             ! ' - 3 9 ? E 1K GQ VW ] c i u    ()*+,        & 4 ; @ T k y        /?Sgn% %0;BKhsK",7DWg}   .annobin_lsruby.c.annobin_lsruby.c_end.annobin_lsruby.c.hot.annobin_lsruby.c_end.hot.annobin_lsruby.c.unlikely.annobin_lsruby.c_end.unlikely.annobin_lsruby.c.startup.annobin_lsruby.c_end.startup.annobin_lsruby.c.exit.annobin_lsruby.c_end.exit.annobin_lsapi_process.start.annobin_lsapi_process.endlsapi_process.annobin_lsapi_rewind.start.annobin_lsapi_rewind.endlsapi_rewinds_body.annobin_lsapi_eof.start.annobin_lsapi_eof.endlsapi_eof.annobin_lsapi_binmode.start.annobin_lsapi_binmode.endlsapi_binmode.annobin_lsapi_isatty.start.annobin_lsapi_isatty.endlsapi_isatty.annobin_lsapi_setsync.start.annobin_lsapi_setsync.endlsapi_setsync.annobin_add_env_no_fix.start.annobin_add_env_no_fix.endadd_env_no_fixlsapi_env.annobin_clear_env.start.annobin_clear_env.endclear_envrb_intern_id_cache.15416env_copy.annobin_lsapi_mark.start.annobin_lsapi_mark.endlsapi_mark.annobin_lsapi_flush.start.annobin_lsapi_flush.endlsapi_flush.annobin_lsapi_close.start.annobin_lsapi_close.endlsapi_closeMAX_BODYBUF_LENGTH.annobin_readBodyBuf.start.annobin_readBodyBuf.endreadBodyBuf.annobin_lsapi_getc.start.annobin_lsapi_getc.endlsapi_getc.annobin_lsapi_write.start.annobin_lsapi_write.endlsapi_write.annobin_lsapi_addstr.start.annobin_lsapi_addstr.endlsapi_addstr.annobin_lsapi_printf.start.annobin_lsapi_printf.endlsapi_printf.annobin_lsapi_s_postfork_parent.start.annobin_lsapi_s_postfork_parent.endlsapi_s_postfork_parents_req.annobin_lsapi_s_postfork_child.start.annobin_lsapi_s_postfork_child.endlsapi_s_postfork_child.annobin_lsapi_s_accept_new_conn.start.annobin_lsapi_s_accept_new_conn.endlsapi_s_accept_new_conn.annobin_lsapi_s_accept.start.annobin_lsapi_s_accept.endlsapi_s_accepts_pidrb_intern_id_cache.15429s_req_data.annobin_lsapi_eval_string_wrap.start.annobin_lsapi_eval_string_wrap.endlsapi_eval_string_wrap.annobin_add_env_rails.start.annobin_add_env_rails.endadd_env_rails.annobin_lsapi_reopen.start.annobin_lsapi_reopen.endlsapi_reopens_req_stderrorig_stderrrb_intern_id_cache.15593.annobin_createBodyBuf.start.annobin_createBodyBuf.endcreateBodyBufsTempFile.annobin_lsapi_read.start.annobin_lsapi_read.endlsapi_read.annobin_lsapi_gets.part.2.start.annobin_lsapi_gets.part.2.endlsapi_gets.part.2.annobin_lsapi_gets.start.annobin_lsapi_gets.endlsapi_gets.annobin_lsapi_each.start.annobin_lsapi_each.endlsapi_each.annobin_lsapi_puts_ary.start.annobin_lsapi_puts_ary.endlsapi_puts_ary.annobin_lsapi_sync.start.annobin_lsapi_sync.endlsapi_sync.annobin_lsapi_putc.start.annobin_lsapi_putc.endlsapi_putc.annobin_lsapi_puts.start.annobin_lsapi_puts.endlsapi_puts.annobin_lsapi_print.start.annobin_lsapi_print.endlsapi_print.annobin_Init_lsapi.start.annobin_Init_lsapi.endrb_intern_id_cache.15609rb_intern_id_cache.15614orig_envcLSAPI.LC0.LC1.LC7.LC5.LC4.LC6.LC3.LC2.LC8.LC9.LC13.LC11.LC10.LC12.LC14.LC15.LC16.LC17.LC18.LC55.LC20.LC21.LC25.LC26.LC27.LC28.LC29.LC33.LC34.LC35.LC36.LC37.LC38.LC39.LC40.LC41.LC42.LC43.LC44.LC45.LC46.LC47.LC48.LC49.LC50.LC51.LC52.LC53.LC23.LC19.LC30.LC31.LC32.LC24.LC22.LC54.text.group.text.hot.group.text.unlikely.group.text.startup.group.text.exit.group_GLOBAL_OFFSET_TABLE_g_reqrb_str_newrb_hash_asetrb_funcallvrb_intern2__stack_chk_failrb_gc_markLSAPI_Flush_rmunmapfreeLSAPI_ReadReqBody_rLSAPI_ReqBodyGetChar_rrb_check_typerb_obj_as_stringrb_f_sprintfLSAPI_Postfork_ParentLSAPI_Postfork_ChildLSAPI_Accept_Before_ForkLSAPI_Prefork_Accept_rgetpids_fn_add_envLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rrb_string_valuerb_string_value_ptrrb_eval_string_wrapstrchrrb_str_new_staticrb_ruby_verbose_ptrrb_define_global_construby_strdupmkstempunlinkftruncatemmapcallocperror__errno_locationstrerror__fprintf_chkrb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_exec_recursiverb_default_rsrb_output_fsrb_output_rsrb_lastline_getInit_lsapiLSAPI_InitgetenvstrtolstrlenselectLSAPI_Init_Env_Parameterschdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocLSAPI_Write_rrb_stdoutrb_stdinLSAPI_Write_Stderr_rrb_hash_new__memcpy_chkrb_define_global_functionrb_define_methodrb_define_singleton_methodH7*ltl@EOV{**D <8DH*?HF<KUH{*=****"7<AH8XD^HgmTv|T\*)~l0\hq|lllAg  C* D6 C<HSf nuD  <  < @    1 8 G Q *[ c t y    D L H  L <( . LS ] Lc Dy  L <  L < D H  L2 K Y Lc <k q L D H  D Lh           &v*3**@* "8DH#$ %#5%QXL_<fm#$*&'T#(**)** +|,3t:t?,KP\dktv5-d7d6d6d6&d9>6EdX]6ddw|6d6d6d6d6d 6d%*61dAF6Md]b6idy~6d6d6d6d6d 6d$)60dCH6O*Vdj.q*x*/\*0*1,d.*2, 3l"l).8=Bg<l4y<d7d7d7 %/6|HMWch{#  i  $, P X" ""["[[hD[Lhphxwhwww 08dlZZZm$Z,mPmXmaDLapaxaW W0W8rdWlrrr$,PX     D  L p x 3  3 3 _ 3 _0 _8 d _l        $  ,  P  X            D  L  p  x     '   ' 0 ' 8  d ' l   P  P P $P,PX     W Z ) . < 0C L S Z -_ m r B~ q   B w  R     ' 4 A N H [ h 9u  >  `  8  N    * L  + 8 E R _ l y E   G   ,   ' Q3 ? [ g #s           y     d" `) . { ; W j p v ,| z  )     +       V /  /   +     V -  & l, 2 )8 > _D @ J P RV 8\ 6c v |   1  f  7     l       + 9 G U  ! * "3 1< @E ON ^W m` |j q x    {  S y   c    F   2 # , @ ,M   B     p    ) ?= ,J       % Y3 S ` m z q b  x     % k  # d0 = ( J W d mq b~    x V J  $ p { ' 4 A gN [ h u F  3   4 X  k    + J8 E R _ Ol y 7 r  ~   6    E  u" / b< I V uc p } A      V Q # Y /  ; G S &_ k <  K K       "    g     Z     x   p     % 1 '> t K X e 1r |  B   | \ ;    - 7 * 7 e cr  c     s }   8  F* f7 =D 9Q ^ l z J  T    6   `    # 0 = =J W $d /q ~   5          " |' l4 BA N 2\ uj x   L      @ SL X d q +~      V  7 M' "4 R ` n |       U         a  A U b C u      f   c @x& 3p< UIR }y . } h  ` |  " M/X8 hE R _ H l z h w@ @ [   ) N  # A' ;, 8 < A `J X aQr1       F B  )10 % 1 5 ~:nP`a `j v z `  P P      @ <;P1Z x    vH    ' 7+ 30pA@cvlv    )19v 0  "q71AN[p1z CxT1 hz$11@U1$_p1*}1f1n0 #1s  B$ 1y1 PA aR 1_ o  1   1 `  1 p !1!p$!5!1B! Q!b!1o! !.!1!!J!1! !f!1!0""1$"03"D"1Q"`"q"1~"`""1"p""1"p""1# #-%#12#A#LR#1S_#`o#########2#1$A$1L$F,$=$11J$Y$j$1Gw$$ $1V$$l$1$$1%  % s% .% S% ke% r% :% S% N% %% l %% S% % %% &&'&5& A&X& Sg& ; w& 7& S& & S& r&`& S& R &0 ' S'4('4D' P' g' Ss' ?w' 9' ' ' ' ' ' ' ' ' ' @' ' ( @( :( 6"( z&( v+( E( T( b( t( S( -( ( ( ( ( :( ( ( S( h( d( ( ) 7) / ) ) ) !) 1-) ` 1) \ :)L C) T) X) ])W j)} x) ) ) ), ) * * S,* P* X\*s* * * * * * ) * % * 1* * * * * * ** +O+ I+ g-+ RL+ Jx+ + F+p+ S+ + + 7 + 3 ++ d+p, S, q , m ,&, 2,`U, Y, j, n, s,m, , , :, ,  - 3- ?-V- b- : f- 6 k- :w- w {- s - - --- f-P- -  -  . :. \ . R #. '. 6. R:. J?. S.\. m. q. w....8.U.// /2/ S>/ B/ S/ ZW/ T\/ h/ l/ }/ / // / / /// / @/ </A0 00 '0 S30 ~70 vF0 J0 ^0 j0 Fn0 Dw0P 0 0 o0 i0 0 00 0 0 0 0 0 `1 1  1 %1 >1 L1 VX1o1 S1 11 S1 01 ,1 k1 i11#1-2 222 S=2 A2 F2T2 P_2v2 S2 2 22 22 S2 2 22 22 S 3 I 3 E3 !3 &3 0/3 :3 >3 C3 O3 Z3 ^3 c3 pl3 y3331333 3 63 433 4!4&.4E;4kI4 0 V4 c4 ]j44 4 4 4 4 @4 44I414 5Z05 ;5R5 =]5 _a5 Yf5 q5 u5 z5 95 5 5 5 >5 :5 {5 w5566  6@76 =B6 F6 K6 V6 ?Z6 -_6 9j6 n6 s6 ~6 6 6 y6 m6 6 6667427`R7ug71)v77771377 881.8C8 J8`a8 l8 lp8 hu8m8 8 A8 8 A8 8 8 \ 9 9(9 H9 f9 a9 Q9 9 99 A9 9 q9 \ : : q#: \ 0: B: P:  a: r m: %::p:`: : : +: !: :  ;; "; &; /; 3; <; @; ~E; N; R; [; d;u;1S;;;;1L;;;<<;<.D<.]<@f< Ps< P|< '< <@< < < < < < <N < < f< d< < <_ =1Z=L.=@8=WP=jh=r=5 =< =g ==>> ->1b7># O>} d>1xn> >>>1> > > > > > E> A? }? {? ? -? F?6 j?1y?O ?o ? ? ? ? ? @ /@ 3@ <@ @@ vI@  M@  ^@ y b@ q k@ t@ p@ @ @d @d @ !@ !@ Y!@ U!@ !@ !@l @l @ A !A !A !Av *A ;A !?A !EA _A hA A 2"A ."A o"A k"A "A "A A A1A B .B @B[B "_B "hB T#lB L#uB #yB #B B B a$B _$B $B $BB B %B $BzC C!C?CWCrCBC C C C C [C [C C C C C C C }C .C :D : D D D ID I%D &)D &2D L 6D L ?D CD LD lPD lYD ]D fD jD sD wD D D D QD QD gD gD  D  D D D + D + D D D D D D D D E E  E E E E &E &*E &2E 6E ?E BCE BLE PE UE ! YE ! bE ~fE ~oE sE |E E E E E EE EE kE kE W E W E {E {E E E E E E E E E hE hF  F F F  F $F -F v1F v:F >F FF JF SF WF `F IdF IlF pF yF +}F +F F F F F F F EF EF F  C  CJ@f@ C@< LM @k L| @y1Z(! F@! F f 4H0\`pp`p (@p`` 8X@`  l    , @0 lP.symtab.strtab.shstrtab.rela.text.data.bss.rela.gnu.build.attributes.text.hot.rela.gnu.build.attributes.hot.text.unlikely.rela.gnu.build.attributes.unlikely.text.startup.rela.gnu.build.attributes.startup.text.exit.rela.gnu.build.attributes.exit.rodata.str1.1.rodata.str1.8.rela.data.rel.local.rodata.cst16.rela.debug_info.debug_abbrev.rela.debug_loc.rela.debug_aranges.debug_ranges.rela.debug_line.debug_str.comment.text.hot.zzz.text.unlikely.zzz.text.startup.zzz.text.exit.zzz.note.GNU-stack.note.gnu.property.rela.eh_frame.group/@6/T6/l6/6/6 @h8"6&, 61@6 6 Lt'[t'V@C06 uH)H)@C06++@C06,,@ D062.20%'0"@PD670J0FE@hDx6Vw/i~8%d@86 y+0t@06"[@H6%00.uL   %0 @`064@7 P6PK ]whf:!gems/ruby-lsapi-5.6/lsapi.gemspecnu[Gem::Specification.new do |s| s.name = %q{ruby-lsapi} s.version = "5.6" s.date = %q{2024-01-22} s.description = "This is a ruby extension for fast communication with LiteSpeed Web Server." s.summary = %q{A ruby extension for fast communication with LiteSpeed Web Server.} s.has_rdoc = false s.authors = ["LiteSpeed Technologies Inc."] s.email = "info@litespeedtech.com" s.homepage = "http://www.litespeedtech.com/" s.rubyforge_project = "ruby-lsapi" s.files = ["lsapi.gemspec", "README", "examples", "examples/testlsapi.rb", "examples/lsapi_with_cgi.rb", "ext", "ext/lsapi", "ext/lsapi/extconf.rb", "ext/lsapi/lsapidef.h", "ext/lsapi/lsapilib.c", "ext/lsapi/lsapilib.h", "ext/lsapi/lsruby.c", "rails", "rails/dispatch.lsapi", "scripts", "scripts/lsruby_runner.rb", "setup.rb"] s.extra_rdoc_files = ["README"] s.extensions << "ext/lsapi/extconf.rb" s.require_paths << "lib" end PK ]^wͱgems/ruby-lsapi-5.6/READMEnu[ lsapi - LSAPI extension for Ruby ================================ INSTALL ------- $ ruby setup.rb config $ ruby setup.rb setup # ruby setup.rb install USAGE ----- General CGI scripts ^^^^^^^^^^^^^^^^^^^ The most efficient way to use LSAPI interface is to modify your CGI scripts. You need to add the following code to your CGI scripts: require 'lsapi' while LSAPI.accept != nil ... end There is no need to change the way that how CGI environment variables are being accessed in your scripts. You can find some examples under examples/ folder. Ruby Script Runner ^^^^^^^^^^^^^^^^^^ If you don't want to change your existing Ruby CGI code, you can use our Ruby script runner under scripts/ folder. You need to configure lsruby_runner.rb as a LSAPI application, then add a script handler for "rb" suffix. Rails dispatcher ^^^^^^^^^^^^^^^^ With Ruby LSAPI, we proudly provide a optimum platform for Rails application deployment. Ruby LSAPI has the following advantages over other solutions. * Easy configuration, deploy a Rails application only take a few clicks with our Rails easy configuration * Fast startup, the expensive Rails framework initialization only takes place once when multiple processes need to be started * Resource efficience, ruby processes can be started on demand, idle process will be stop. To use LSAPI with Ruby on Rails, please check out our toturial http://www.litespeedtech.com/support/wiki/doku.php There are a few environment variables that can be tweaked to tune ruby LSAPI process. * LSAPI_CHILDREN (default: 0) LSAPI_CHILDREN controls the maximum number of children processes can be started by the first ruby process started by web server. When set to <=1, the first ruby process will handle request by itself, without starting any child process. When LSAPI_CHILDREN is >1, the LSAPI application is stared in "Self Managed Mode", which will start children processes based on demand. With Rails easy configuration, LSAPI_CHILDREN is set to the value of "Max Connections" by web server, no need to set it explicitly. Usually, there is no need to set value of LSAPI_CHILDREN over 100 in most server environment. * LSAPI_AVOID_FORK (default: 0) LSAPI_AVOID_FORK specifies the policy of the internal process manager in "Self Managed Mode". When set to 0, the internal process manager will stop and start children process on demand to save system resource. This is preferred in a shared hosting environment. When set to 1, the internal process manager will try to avoid freqently stopping and starting children process. This might be preferred in a dedicate hosting environment. * LSAPI_EXTRA_CHILDREN (default: 1/3 of LSAPI_CHILDREN or 0) LSAPI_EXTRA_CHILDREN controls the maximum number of extra children processes can be started when some or all existing children processes are in malfunctioning state. Total number of children processes will be reduced to LSAPI_CHILDREN level as soon as service is back to normal. When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is 0. * LSAPI_MAX_REQS (default value: 10000) LSAPI_MAX_REQS specifies the maximum number of requests each child process will handle before it exits automatically. This parameter can help reducing memory usage when there are memory leaks in the application. * LSAPI_MAX_IDLE (default value: 300 seconds) In Self Managed Mode, LSAPI_MAX_IDLE controls how long a idle child process will wait for a new request before exit. This option help releasing system resources taken by idle processes. * LSAPI_MAX_IDLE_CHILDREN (default value: 1/3 of LSAPI_CHILDREN or LSAPI_CHILDREN) In Self Managed Mode, LSAI_MAX_IDLE_CHILDREN controls how many idle children processes are allowed. Excessive idle children processes will be killed by the parent process. When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is LSAPI_CHILDREN. * LSAPI_MAX_PROCESS_TIME (default value: 300 seconds) In Self Managed Mode, LSAPI_MAX_PROCESS_TIME controls the maximum processing time allowed when processing a request. If a child process can not finish processing of a request in the given time period, it will be killed by the parent process. This option can help getting rid of dead or runaway child process. * LSAPI_PGRP_MAX_IDLE (default value: FOREVER ) In Self Managed Mode, LSAPI_PGRP_MAX_IDLE controls how long the parent process will wait before exiting when there is no child process. This option help releasing system resources taken by an idle parent process. * LSAPI_PPID_NO_CHECK By default a LSAPI application check the existence of its parent process and exits automatically if the parent process died. This is to reduce orphan process when web server is restarted. However, it is desireable to disable this feature, such as when a LSAPI process was started manually from command line. LSAPI_PPID_NO_CHECK should be set when you want to disable the checking of existence of parent process. License ------- LSAPI library code is under BSD license LSAPI ruby extension code is under Ruby license * (()) (Japanese) * (()) (English) Copyright --------- Copyright (C) 2006 Lite Speed Technologies Inc. PK ]j2(gems/ruby-lsapi-5.6/rails/dispatch.lsapinuȯ#!/opt/alt/ruby27/bin/ruby if GC.respond_to?(:copy_on_write_friendly=) GC.copy_on_write_friendly = true end require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) # If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: # "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired require "dispatcher" require "lsapi" while LSAPI.accept != nil Dispatcher.dispatch end PK ]MM,gems/ruby-lsapi-5.6/scripts/lsruby_runner.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' class CodeCache def [](filename) mtime = File.mtime( filename ) entry = @cache[filename]; if entry != nil return entry end code = compile(filename) #entry = CodeEntry.new( filename, mtime, code ) @cache[filename] = code return code end private def initialize @cache = {} end def compile(filename) open(filename) do |f| s = f.read s.untaint binding = eval_string_wrap("binding") return eval(format("Proc.new {\n%s\n}", s), binding, filename, 0) end end end $count = 0; $cache = CodeCache.new while true $req = LSAPI.accept break if $req == nil filename = ENV['SCRIPT_FILENAME'] filename.untaint filename =~ %r{^(\/.*?)\/*([^\/]+)$} path = $1 Dir.chdir( path ) #load( filename, true ) code = $cache[filename] code.call end class CodeEntry public :path, :name, :mtime, :opcode def initizlize( filename, mtime, opcode ) filename =~ %r{^(\/.*?)\/*([^\/]+)$} @path = $1 @name = $2 @mtime = mtime @opcode = opcode end end PK ]##BBgems/ruby-lsapi-5.6/setup.rbnu[# # setup.rb # # Copyright (c) 2000-2005 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU LGPL, Lesser General Public License version 2.1. # unless Enumerable.method_defined?(:map) # Ruby 1.4.6 module Enumerable alias map collect end end unless File.respond_to?(:read) # Ruby 1.6 def File.read(fname) open(fname) {|f| return f.read } end end unless Errno.const_defined?(:ENOTEMPTY) # Windows? module Errno class ENOTEMPTY # We do not raise this exception, implementation is not needed. end end end def File.binread(fname) open(fname, 'rb') {|f| return f.read } end # for corrupted Windows' stat(2) def File.dir?(path) File.directory?((path[-1,1] == '/') ? path : path + '/') end class ConfigTable include Enumerable def initialize(rbconfig) @rbconfig = rbconfig @items = [] @table = {} # options @install_prefix = nil @config_opt = nil @verbose = true @no_harm = false end attr_accessor :install_prefix attr_accessor :config_opt attr_writer :verbose def verbose? @verbose end attr_writer :no_harm def no_harm? @no_harm end def [](key) lookup(key).resolve(self) end def []=(key, val) lookup(key).set val end def names @items.map {|i| i.name } end def each(&block) @items.each(&block) end def key?(name) @table.key?(name) end def lookup(name) @table[name] or setup_rb_error "no such config item: #{name}" end def add(item) @items.push item @table[item.name] = item end def remove(name) item = lookup(name) @items.delete_if {|i| i.name == name } @table.delete_if {|name, i| i.name == name } item end def load_script(path, inst = nil) if File.file?(path) MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path end end def savefile '.config' end def load_savefile begin File.foreach(savefile()) do |line| k, v = *line.split(/=/, 2) self[k] = v.strip end rescue Errno::ENOENT setup_rb_error $!.message + "\n#{File.basename($0)} config first" end end def save @items.each {|i| i.value } File.open(savefile(), 'w') {|f| @items.each do |i| f.printf "%s=%s\n", i.name, i.value if i.value? and i.value end } end def load_standard_entries standard_entries(@rbconfig).each do |ent| add ent end end def standard_entries(rbconfig) c = rbconfig rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) major = c['MAJOR'].to_i minor = c['MINOR'].to_i teeny = c['TEENY'].to_i version = "#{major}.#{minor}" # ruby ver. >= 1.4.4? newpath_p = ((major >= 2) or ((major == 1) and ((minor >= 5) or ((minor == 4) and (teeny >= 4))))) if c['rubylibdir'] # V > 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = c['rubylibdir'] librubyverarch = c['archdir'] siteruby = c['sitedir'] siterubyver = c['sitelibdir'] siterubyverarch = c['sitearchdir'] elsif newpath_p # 1.4.4 <= V <= 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = c['sitedir'] siterubyver = "$siteruby/#{version}" siterubyverarch = "$siterubyver/#{c['arch']}" else # V < 1.4.4 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" siterubyver = siteruby siterubyverarch = "$siterubyver/#{c['arch']}" end parameterize = lambda {|path| path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') } if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } makeprog = arg.sub(/'/, '').split(/=/, 2)[1] else makeprog = 'make' end [ ExecItem.new('installdirs', 'std/site/home', 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ {|val, table| case val when 'std' table['rbdir'] = '$librubyver' table['sodir'] = '$librubyverarch' when 'site' table['rbdir'] = '$siterubyver' table['sodir'] = '$siterubyverarch' when 'home' setup_rb_error '$HOME was not set' unless ENV['HOME'] table['prefix'] = ENV['HOME'] table['rbdir'] = '$libdir/ruby' table['sodir'] = '$libdir/ruby' end }, PathItem.new('prefix', 'path', c['prefix'], 'path prefix of target environment'), PathItem.new('bindir', 'path', parameterize.call(c['bindir']), 'the directory for commands'), PathItem.new('libdir', 'path', parameterize.call(c['libdir']), 'the directory for libraries'), PathItem.new('datadir', 'path', parameterize.call(c['datadir']), 'the directory for shared data'), PathItem.new('mandir', 'path', parameterize.call(c['mandir']), 'the directory for man pages'), PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), 'the directory for system configuration files'), PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), 'the directory for local state data'), PathItem.new('libruby', 'path', libruby, 'the directory for ruby libraries'), PathItem.new('librubyver', 'path', librubyver, 'the directory for standard ruby libraries'), PathItem.new('librubyverarch', 'path', librubyverarch, 'the directory for standard ruby extensions'), PathItem.new('siteruby', 'path', siteruby, 'the directory for version-independent aux ruby libraries'), PathItem.new('siterubyver', 'path', siterubyver, 'the directory for aux ruby libraries'), PathItem.new('siterubyverarch', 'path', siterubyverarch, 'the directory for aux ruby binaries'), PathItem.new('rbdir', 'path', '$siterubyver', 'the directory for ruby scripts'), PathItem.new('sodir', 'path', '$siterubyverarch', 'the directory for ruby extentions'), PathItem.new('rubypath', 'path', rubypath, 'the path to set to #! line'), ProgramItem.new('rubyprog', 'name', rubypath, 'the ruby program using for installation'), ProgramItem.new('makeprog', 'name', makeprog, 'the make program to compile ruby extentions'), SelectItem.new('shebang', 'all/ruby/never', 'ruby', 'shebang line (#!) editing mode'), BoolItem.new('without-ext', 'yes/no', 'no', 'does not compile/install ruby extentions') ] end private :standard_entries def load_multipackage_entries multipackage_entries().each do |ent| add ent end end def multipackage_entries [ PackageSelectionItem.new('with', 'name,name...', '', 'ALL', 'package names that you want to install'), PackageSelectionItem.new('without', 'name,name...', '', 'NONE', 'package names that you do not want to install') ] end private :multipackage_entries ALIASES = { 'std-ruby' => 'librubyver', 'stdruby' => 'librubyver', 'rubylibdir' => 'librubyver', 'archdir' => 'librubyverarch', 'site-ruby-common' => 'siteruby', # For backward compatibility 'site-ruby' => 'siterubyver', # For backward compatibility 'bin-dir' => 'bindir', 'bin-dir' => 'bindir', 'rb-dir' => 'rbdir', 'so-dir' => 'sodir', 'data-dir' => 'datadir', 'ruby-path' => 'rubypath', 'ruby-prog' => 'rubyprog', 'ruby' => 'rubyprog', 'make-prog' => 'makeprog', 'make' => 'makeprog' } def fixup ALIASES.each do |ali, name| @table[ali] = @table[name] end @items.freeze @table.freeze @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ end def parse_opt(opt) m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" m.to_a[1,2] end def dllext @rbconfig['DLEXT'] end def value_config?(name) lookup(name).value? end class Item def initialize(name, template, default, desc) @name = name.freeze @template = template @value = default @default = default @description = desc end attr_reader :name attr_reader :description attr_accessor :default alias help_default default def help_opt "--#{@name}=#{@template}" end def value? true end def value @value end def resolve(table) @value.gsub(%r<\$([^/]+)>) { table[$1] } end def set(val) @value = check(val) end private def check(val) setup_rb_error "config: --#{name} requires argument" unless val val end end class BoolItem < Item def config_type 'bool' end def help_opt "--#{@name}" end private def check(val) return 'yes' unless val case val when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' else setup_rb_error "config: --#{@name} accepts only yes/no for argument" end end end class PathItem < Item def config_type 'path' end private def check(path) setup_rb_error "config: --#{@name} requires argument" unless path path[0,1] == '$' ? path : File.expand_path(path) end end class ProgramItem < Item def config_type 'program' end end class SelectItem < Item def initialize(name, selection, default, desc) super @ok = selection.split('/') end def config_type 'select' end private def check(val) unless @ok.include?(val.strip) setup_rb_error "config: use --#{@name}=#{@template} (#{val})" end val.strip end end class ExecItem < Item def initialize(name, selection, desc, &block) super name, selection, nil, desc @ok = selection.split('/') @action = block end def config_type 'exec' end def value? false end def resolve(table) setup_rb_error "$#{name()} wrongly used as option value" end undef set def evaluate(val, table) v = val.strip.downcase unless @ok.include?(v) setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" end @action.call v, table end end class PackageSelectionItem < Item def initialize(name, template, default, help_default, desc) super name, template, default, desc @help_default = help_default end attr_reader :help_default def config_type 'package' end private def check(val) unless File.dir?("packages/#{val}") setup_rb_error "config: no such package: #{val}" end val end end class MetaConfigEnvironment def initialize(config, installer) @config = config @installer = installer end def config_names @config.names end def config?(name) @config.key?(name) end def bool_config?(name) @config.lookup(name).config_type == 'bool' end def path_config?(name) @config.lookup(name).config_type == 'path' end def value_config?(name) @config.lookup(name).config_type != 'exec' end def add_config(item) @config.add item end def add_bool_config(name, default, desc) @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) end def add_path_config(name, default, desc) @config.add PathItem.new(name, 'path', default, desc) end def set_config_default(name, default) @config.lookup(name).default = default end def remove_config(name) @config.remove(name) end # For only multipackage def packages raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer @installer.packages end # For only multipackage def declare_packages(list) raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer @installer.packages = list end end end # class ConfigTable # This module requires: #verbose?, #no_harm? module FileOperations def mkdir_p(dirname, prefix = nil) dirname = prefix + File.expand_path(dirname) if prefix $stderr.puts "mkdir -p #{dirname}" if verbose? return if no_harm? # Does not check '/', it's too abnormal. dirs = File.expand_path(dirname).split(%r<(?=/)>) if /\A[a-z]:\z/i =~ dirs[0] disk = dirs.shift dirs[0] = disk + dirs[0] end dirs.each_index do |idx| path = dirs[0..idx].join('') Dir.mkdir path unless File.dir?(path) end end def rm_f(path) $stderr.puts "rm -f #{path}" if verbose? return if no_harm? force_remove_file path end def rm_rf(path) $stderr.puts "rm -rf #{path}" if verbose? return if no_harm? remove_tree path end def remove_tree(path) if File.symlink?(path) remove_file path elsif File.dir?(path) remove_tree0 path else force_remove_file path end end def remove_tree0(path) Dir.foreach(path) do |ent| next if ent == '.' next if ent == '..' entpath = "#{path}/#{ent}" if File.symlink?(entpath) remove_file entpath elsif File.dir?(entpath) remove_tree0 entpath else force_remove_file entpath end end begin Dir.rmdir path rescue Errno::ENOTEMPTY # directory may not be empty end end def move_file(src, dest) force_remove_file dest begin File.rename src, dest rescue File.open(dest, 'wb') {|f| f.write File.binread(src) } File.chmod File.stat(src).mode, dest File.unlink src end end def force_remove_file(path) begin remove_file path rescue end end def remove_file(path) File.chmod 0777, path File.unlink path end def install(from, dest, mode, prefix = nil) $stderr.puts "install #{from} #{dest}" if verbose? return if no_harm? realdest = prefix ? prefix + File.expand_path(dest) : dest realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) str = File.binread(from) if diff?(str, realdest) verbose_off { rm_f realdest if File.exist?(realdest) } File.open(realdest, 'wb') {|f| f.write str } File.chmod mode, realdest File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| if prefix f.puts realdest.sub(prefix, '') else f.puts realdest end } end end def diff?(new_content, path) return true unless File.exist?(path) new_content != File.binread(path) end def command(*args) $stderr.puts args.join(' ') if verbose? system(*args) or raise RuntimeError, "system(#{args.map{|a| a.inspect }.join(' ')}) failed" end def ruby(*args) command config('rubyprog'), *args end def make(task = nil) command(*[config('makeprog'), task].compact) end def extdir?(dir) File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") end def files_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.file?("#{dir}/#{ent}") } } end DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) def directories_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT } end end # This module requires: #srcdir_root, #objdir_root, #relpath module HookScriptAPI def get_config(key) @config[key] end alias config get_config # obsolete: use metaconfig to change configuration def set_config(key, val) @config[key] = val end # # srcdir/objdir (works only in the package directory) # def curr_srcdir "#{srcdir_root()}/#{relpath()}" end def curr_objdir "#{objdir_root()}/#{relpath()}" end def srcfile(path) "#{curr_srcdir()}/#{path}" end def srcexist?(path) File.exist?(srcfile(path)) end def srcdirectory?(path) File.dir?(srcfile(path)) end def srcfile?(path) File.file?(srcfile(path)) end def srcentries(path = '.') Dir.open("#{curr_srcdir()}/#{path}") {|d| return d.to_a - %w(. ..) } end def srcfiles(path = '.') srcentries(path).select {|fname| File.file?(File.join(curr_srcdir(), path, fname)) } end def srcdirectories(path = '.') srcentries(path).select {|fname| File.dir?(File.join(curr_srcdir(), path, fname)) } end end class ToplevelInstaller Version = '3.4.1' Copyright = 'Copyright (c) 2000-2005 Minero Aoki' TASKS = [ [ 'all', 'do config, setup, then install' ], [ 'config', 'saves your configurations' ], [ 'show', 'shows current configuration' ], [ 'setup', 'compiles ruby extentions and others' ], [ 'install', 'installs files' ], [ 'test', 'run all tests in test/' ], [ 'clean', "does `make clean' for each extention" ], [ 'distclean',"does `make distclean' for each extention" ] ] def ToplevelInstaller.invoke config = ConfigTable.new(load_rbconfig()) config.load_standard_entries config.load_multipackage_entries if multipackage? config.fixup klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) klass.new(File.dirname($0), config).invoke end def ToplevelInstaller.multipackage? File.dir?(File.dirname($0) + '/packages') end def ToplevelInstaller.load_rbconfig if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } ARGV.delete(arg) load File.expand_path(arg.split(/=/, 2)[1]) $".push 'rbconfig.rb' else require 'rbconfig' end ::Config::CONFIG end def initialize(ardir_root, config) @ardir = File.expand_path(ardir_root) @config = config # cache @valid_task_re = nil end def config(key) @config[key] end def inspect "#<#{self.class} #{__id__()}>" end def invoke run_metaconfigs case task = parsearg_global() when nil, 'all' parsearg_config init_installers exec_config exec_setup exec_install else case task when 'config', 'test' ; when 'clean', 'distclean' @config.load_savefile if File.exist?(@config.savefile) else @config.load_savefile end __send__ "parsearg_#{task}" init_installers __send__ "exec_#{task}" end end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig" end def init_installers @installer = Installer.new(@config, @ardir, File.expand_path('.')) end # # Hook Script API bases # def srcdir_root @ardir end def objdir_root '.' end def relpath '.' end # # Option Parsing # def parsearg_global while arg = ARGV.shift case arg when /\A\w+\z/ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) return arg when '-q', '--quiet' @config.verbose = false when '--verbose' @config.verbose = true when '--help' print_usage $stdout exit 0 when '--version' puts "#{File.basename($0)} version #{Version}" exit 0 when '--copyright' puts Copyright exit 0 else setup_rb_error "unknown global option '#{arg}'" end end nil end def valid_task?(t) valid_task_re() =~ t end def valid_task_re @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ end def parsearg_no_options unless ARGV.empty? task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" end end alias parsearg_show parsearg_no_options alias parsearg_setup parsearg_no_options alias parsearg_test parsearg_no_options alias parsearg_clean parsearg_no_options alias parsearg_distclean parsearg_no_options def parsearg_config evalopt = [] set = [] @config.config_opt = [] while i = ARGV.shift if /\A--?\z/ =~ i @config.config_opt = ARGV.dup break end name, value = *@config.parse_opt(i) if @config.value_config?(name) @config[name] = value else evalopt.push [name, value] end set.push name end evalopt.each do |name, value| @config.lookup(name).evaluate value, @config end # Check if configuration is valid set.each do |n| @config[n] if @config.value_config?(n) end end def parsearg_install @config.no_harm = false @config.install_prefix = '' while a = ARGV.shift case a when '--no-harm' @config.no_harm = true when /\A--prefix=/ path = a.split(/=/, 2)[1] path = File.expand_path(path) unless path[0,1] == '/' @config.install_prefix = path else setup_rb_error "install: unknown option #{a}" end end end def print_usage(out) out.puts 'Typical Installation Procedure:' out.puts " $ ruby #{File.basename $0} config" out.puts " $ ruby #{File.basename $0} setup" out.puts " # ruby #{File.basename $0} install (may require root privilege)" out.puts out.puts 'Detailed Usage:' out.puts " ruby #{File.basename $0} " out.puts " ruby #{File.basename $0} [] []" fmt = " %-24s %s\n" out.puts out.puts 'Global options:' out.printf fmt, '-q,--quiet', 'suppress message outputs' out.printf fmt, ' --verbose', 'output messages verbosely' out.printf fmt, ' --help', 'print this message' out.printf fmt, ' --version', 'print version and quit' out.printf fmt, ' --copyright', 'print copyright and quit' out.puts out.puts 'Tasks:' TASKS.each do |name, desc| out.printf fmt, name, desc end fmt = " %-24s %s [%s]\n" out.puts out.puts 'Options for CONFIG or ALL:' @config.each do |item| out.printf fmt, item.help_opt, item.description, item.help_default end out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" out.puts out.puts 'Options for INSTALL:' out.printf fmt, '--no-harm', 'only display what to do if given', 'off' out.printf fmt, '--prefix=path', 'install path prefix', '' out.puts end # # Task Handlers # def exec_config @installer.exec_config @config.save # must be final end def exec_setup @installer.exec_setup end def exec_install @installer.exec_install end def exec_test @installer.exec_test end def exec_show @config.each do |i| printf "%-20s %s\n", i.name, i.value if i.value? end end def exec_clean @installer.exec_clean end def exec_distclean @installer.exec_distclean end end # class ToplevelInstaller class ToplevelInstallerMulti < ToplevelInstaller include FileOperations def initialize(ardir_root, config) super @packages = directories_of("#{@ardir}/packages") raise 'no package exists' if @packages.empty? @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig", self @packages.each do |name| @config.load_script "#{@ardir}/packages/#{name}/metaconfig" end end attr_reader :packages def packages=(list) raise 'package list is empty' if list.empty? list.each do |name| raise "directory packages/#{name} does not exist"\ unless File.dir?("#{@ardir}/packages/#{name}") end @packages = list end def init_installers @installers = {} @packages.each do |pack| @installers[pack] = Installer.new(@config, "#{@ardir}/packages/#{pack}", "packages/#{pack}") end with = extract_selection(config('with')) without = extract_selection(config('without')) @selected = @installers.keys.select {|name| (with.empty? or with.include?(name)) \ and not without.include?(name) } end def extract_selection(list) a = list.split(/,/) a.each do |name| setup_rb_error "no such package: #{name}" unless @installers.key?(name) end a end def print_usage(f) super f.puts 'Inluded packages:' f.puts ' ' + @packages.sort.join(' ') f.puts end # # Task Handlers # def exec_config run_hook 'pre-config' each_selected_installers {|inst| inst.exec_config } run_hook 'post-config' @config.save # must be final end def exec_setup run_hook 'pre-setup' each_selected_installers {|inst| inst.exec_setup } run_hook 'post-setup' end def exec_install run_hook 'pre-install' each_selected_installers {|inst| inst.exec_install } run_hook 'post-install' end def exec_test run_hook 'pre-test' each_selected_installers {|inst| inst.exec_test } run_hook 'post-test' end def exec_clean rm_f @config.savefile run_hook 'pre-clean' each_selected_installers {|inst| inst.exec_clean } run_hook 'post-clean' end def exec_distclean rm_f @config.savefile run_hook 'pre-distclean' each_selected_installers {|inst| inst.exec_distclean } run_hook 'post-distclean' end # # lib # def each_selected_installers Dir.mkdir 'packages' unless File.dir?('packages') @selected.each do |pack| $stderr.puts "Processing the package `#{pack}' ..." if verbose? Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") Dir.chdir "packages/#{pack}" yield @installers[pack] Dir.chdir '../..' end end def run_hook(id) @root_installer.run_hook id end # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end end # class ToplevelInstallerMulti class Installer FILETYPES = %w( bin lib ext data conf man ) include FileOperations include HookScriptAPI def initialize(config, srcroot, objroot) @config = config @srcdir = File.expand_path(srcroot) @objdir = File.expand_path(objroot) @currdir = '.' end def inspect "#<#{self.class} #{File.basename(@srcdir)}>" end def noop(rel) end # # Hook Script API base methods # def srcdir_root @srcdir end def objdir_root @objdir end def relpath @currdir end # # Config Access # # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end def verbose_off begin save, @config.verbose = @config.verbose?, false yield ensure @config.verbose = save end end # # TASK config # def exec_config exec_task_traverse 'config' end alias config_dir_bin noop alias config_dir_lib noop def config_dir_ext(rel) extconf if extdir?(curr_srcdir()) end alias config_dir_data noop alias config_dir_conf noop alias config_dir_man noop def extconf ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt end # # TASK setup # def exec_setup exec_task_traverse 'setup' end def setup_dir_bin(rel) files_of(curr_srcdir()).each do |fname| update_shebang_line "#{curr_srcdir()}/#{fname}" end end alias setup_dir_lib noop def setup_dir_ext(rel) make if extdir?(curr_srcdir()) end alias setup_dir_data noop alias setup_dir_conf noop alias setup_dir_man noop def update_shebang_line(path) return if no_harm? return if config('shebang') == 'never' old = Shebang.load(path) if old $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 new = new_shebang(old) return if new.to_s == old.to_s else return unless config('shebang') == 'all' new = Shebang.new(config('rubypath')) end $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? open_atomic_writer(path) {|output| File.open(path, 'rb') {|f| f.gets if old # discard output.puts new.to_s output.print f.read } } end def new_shebang(old) if /\Aruby/ =~ File.basename(old.cmd) Shebang.new(config('rubypath'), old.args) elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' Shebang.new(config('rubypath'), old.args[1..-1]) else return old unless config('shebang') == 'all' Shebang.new(config('rubypath')) end end def open_atomic_writer(path, &block) tmpfile = File.basename(path) + '.tmp' begin File.open(tmpfile, 'wb', &block) File.rename tmpfile, File.basename(path) ensure File.unlink tmpfile if File.exist?(tmpfile) end end class Shebang def Shebang.load(path) line = nil File.open(path) {|f| line = f.gets } return nil unless /\A#!/ =~ line parse(line) end def Shebang.parse(line) cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') new(cmd, args) end def initialize(cmd, args = []) @cmd = cmd @args = args end attr_reader :cmd attr_reader :args def to_s "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") end end # # TASK install # def exec_install rm_f 'InstalledFiles' exec_task_traverse 'install' end def install_dir_bin(rel) install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 end def install_dir_lib(rel) install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 end def install_dir_ext(rel) return unless extdir?(curr_srcdir()) install_files rubyextentions('.'), "#{config('sodir')}/#{File.dirname(rel)}", 0555 end def install_dir_data(rel) install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 end def install_dir_conf(rel) # FIXME: should not remove current config files # (rename previous file to .old/.org) install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 end def install_dir_man(rel) install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 end def install_files(list, dest, mode) mkdir_p dest, @config.install_prefix list.each do |fname| install fname, dest, mode, @config.install_prefix end end def libfiles glob_reject(%w(*.y *.output), targetfiles()) end def rubyextentions(dir) ents = glob_select("*.#{@config.dllext}", targetfiles()) if ents.empty? setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" end ents end def targetfiles mapdir(existfiles() - hookfiles()) end def mapdir(ents) ents.map {|ent| if File.exist?(ent) then ent # objdir else "#{curr_srcdir()}/#{ent}" # srcdir end } end # picked up many entries from cvs-1.11.1/src/ignore.c JUNK_FILES = %w( core RCSLOG tags TAGS .make.state .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$ *.org *.in .* ) def existfiles glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) end def hookfiles %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| %w( config setup install clean ).map {|t| sprintf(fmt, t) } }.flatten end def glob_select(pat, ents) re = globs2re([pat]) ents.select {|ent| re =~ ent } end def glob_reject(pats, ents) re = globs2re(pats) ents.reject {|ent| re =~ ent } end GLOB2REGEX = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' } def globs2re(pats) /\A(?:#{ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') })\z/ end # # TASK test # TESTDIR = 'test' def exec_test unless File.directory?('test') $stderr.puts 'no test in this package' if verbose? return end $stderr.puts 'Running tests...' if verbose? begin require 'test/unit' rescue LoadError setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' end runner = Test::Unit::AutoRunner.new(true) runner.to_run << TESTDIR runner.run end # # TASK clean # def exec_clean exec_task_traverse 'clean' rm_f @config.savefile rm_f 'InstalledFiles' end alias clean_dir_bin noop alias clean_dir_lib noop alias clean_dir_data noop alias clean_dir_conf noop alias clean_dir_man noop def clean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'clean' if File.file?('Makefile') end # # TASK distclean # def exec_distclean exec_task_traverse 'distclean' rm_f @config.savefile rm_f 'InstalledFiles' end alias distclean_dir_bin noop alias distclean_dir_lib noop def distclean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'distclean' if File.file?('Makefile') end alias distclean_dir_data noop alias distclean_dir_conf noop alias distclean_dir_man noop # # Traversing # def exec_task_traverse(task) run_hook "pre-#{task}" FILETYPES.each do |type| if type == 'ext' and config('without-ext') == 'yes' $stderr.puts 'skipping ext/* by user option' if verbose? next end traverse task, type, "#{task}_dir_#{type}" end run_hook "post-#{task}" end def traverse(task, rel, mid) dive_into(rel) { run_hook "pre-#{task}" __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') directories_of(curr_srcdir()).each do |d| traverse task, "#{rel}/#{d}", mid end run_hook "post-#{task}" } end def dive_into(rel) return unless File.dir?("#{@srcdir}/#{rel}") dir = File.basename(rel) Dir.mkdir dir unless File.dir?(dir) prevdir = Dir.pwd Dir.chdir dir $stderr.puts '---> ' + rel if verbose? @currdir = rel yield Dir.chdir prevdir $stderr.puts '<--- ' + rel if verbose? @currdir = File.dirname(rel) end def run_hook(id) path = [ "#{curr_srcdir()}/#{id}", "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } return unless path begin instance_eval File.read(path), path, 1 rescue raise if $DEBUG setup_rb_error "hook #{path} failed:\n" + $!.message end end end # class Installer class SetupError < StandardError; end def setup_rb_error(msg) raise SetupError, msg end if $0 == __FILE__ begin ToplevelInstaller.invoke rescue SetupError raise if $DEBUG $stderr.puts $!.message $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." exit 1 end end PK ]*  )gems/ruby-lsapi-5.6/examples/testlsapi.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' $count = 0; while LSAPI.accept != nil print "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\nHello World! \##{$count}
    \r\n" ENV.each_pair {|key, value| print "#{key} is #{value}
    \r\n" } $count = $count + 1 end PK ].gems/ruby-lsapi-5.6/examples/lsapi_with_cgi.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' require 'cgi' while LSAPI.accept != nil cgi = CGI.new name = cgi['name'] puts cgi.header puts "Hello #{name}!
    " if name puts "You are from #{cgi.remote_addr}
    " end PK ]L,gems/io-console-0.5.6/lib/io/console/size.rbnu[# frozen_string_literal: false # fallback to console window size def IO.default_console_size [ ENV["LINES"].to_i.nonzero? || 25, ENV["COLUMNS"].to_i.nonzero? || 80, ] end begin require 'io/console' rescue LoadError class << IO alias console_size default_console_size end else # returns console window size def IO.console_size console.winsize rescue NoMethodError default_console_size end end PK ]B^$gems/openssl-2.1.4/lib/openssl/bn.rbnu[# frozen_string_literal: false #-- # # = Ruby-space definitions that completes C-space funcs for BN # # = Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2002 Michal Rokos # All rights reserved. # # = Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ module OpenSSL class BN include Comparable def pretty_print(q) q.object_group(self) { q.text ' ' q.text to_i.to_s } end end # BN end # OpenSSL ## #-- # Add double dispatch to Integer #++ class Integer # Casts an Integer as an OpenSSL::BN # # See `man bn` for more info. def to_bn OpenSSL::BN::new(self) end end # Integer PK ]w+D(gems/openssl-2.1.4/lib/openssl/cipher.rbnu[# frozen_string_literal: false #-- # = Ruby-space predefined Cipher subclasses # # = Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2002 Michal Rokos # All rights reserved. # # = Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ module OpenSSL class Cipher %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name| klass = Class.new(Cipher){ define_method(:initialize){|*args| cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" } super(cipher_name.downcase) } } const_set(name, klass) } %w(128 192 256).each{|keylen| klass = Class.new(Cipher){ define_method(:initialize){|mode = "CBC"| super("aes-#{keylen}-#{mode}".downcase) } } const_set("AES#{keylen}", klass) } # call-seq: # cipher.random_key -> key # # Generate a random key with OpenSSL::Random.random_bytes and sets it to # the cipher, and returns it. # # You must call #encrypt or #decrypt before calling this method. def random_key str = OpenSSL::Random.random_bytes(self.key_len) self.key = str end # call-seq: # cipher.random_iv -> iv # # Generate a random IV with OpenSSL::Random.random_bytes and sets it to the # cipher, and returns it. # # You must call #encrypt or #decrypt before calling this method. def random_iv str = OpenSSL::Random.random_bytes(self.iv_len) self.iv = str end # Deprecated. # # This class is only provided for backwards compatibility. # Use OpenSSL::Cipher. class Cipher < Cipher; end deprecate_constant :Cipher end # Cipher end # OpenSSL PK ]̒O??%gems/openssl-2.1.4/lib/openssl/ssl.rbnu[# frozen_string_literal: false =begin = Info 'OpenSSL for Ruby 2' project Copyright (C) 2001 GOTOU YUUZOU All rights reserved. = Licence This program is licensed under the same licence as Ruby. (See the file 'LICENCE'.) =end require "openssl/buffering" require "io/nonblock" require "ipaddr" module OpenSSL module SSL class SSLContext DEFAULT_PARAMS = { # :nodoc: :min_version => OpenSSL::SSL::TLS1_VERSION, :verify_mode => OpenSSL::SSL::VERIFY_PEER, :verify_hostname => true, :options => -> { opts = OpenSSL::SSL::OP_ALL opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS opts |= OpenSSL::SSL::OP_NO_COMPRESSION opts }.call } if defined?(OpenSSL::PKey::DH) DEFAULT_2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_ -----BEGIN DH PARAMETERS----- MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6 YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3 1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD 7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg== -----END DH PARAMETERS----- _end_of_pem_ private_constant :DEFAULT_2048 DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc: warn "using default DH parameters." if $VERBOSE DEFAULT_2048 } end if !(OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL") && OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000) DEFAULT_PARAMS.merge!( ciphers: %w{ ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-DSS-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-DSS-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA DHE-DSS-AES128-SHA256 DHE-DSS-AES256-SHA256 DHE-DSS-AES128-SHA DHE-DSS-AES256-SHA AES128-GCM-SHA256 AES256-GCM-SHA384 AES128-SHA256 AES256-SHA256 AES128-SHA AES256-SHA }.join(":"), ) end DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc: DEFAULT_CERT_STORE.set_default_paths DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL # A callback invoked when DH parameters are required. # # The callback is invoked with the Session for the key exchange, an # flag indicating the use of an export cipher and the keylength # required. # # The callback must return an OpenSSL::PKey::DH instance of the correct # key length. attr_accessor :tmp_dh_callback # A callback invoked at connect time to distinguish between multiple # server names. # # The callback is invoked with an SSLSocket and a server name. The # callback must return an SSLContext for the server name or nil. attr_accessor :servername_cb # call-seq: # SSLContext.new -> ctx # SSLContext.new(:TLSv1) -> ctx # SSLContext.new("SSLv23") -> ctx # # Creates a new SSL context. # # If an argument is given, #ssl_version= is called with the value. Note # that this form is deprecated. New applications should use #min_version= # and #max_version= as necessary. def initialize(version = nil) self.options |= OpenSSL::SSL::OP_ALL self.ssl_version = version if version end ## # call-seq: # ctx.set_params(params = {}) -> params # # Sets saner defaults optimized for the use with HTTP-like protocols. # # If a Hash _params_ is given, the parameters are overridden with it. # The keys in _params_ must be assignment methods on SSLContext. # # If the verify_mode is not VERIFY_NONE and ca_file, ca_path and # cert_store are not set then the system default certificate store is # used. def set_params(params={}) params = DEFAULT_PARAMS.merge(params) self.options = params.delete(:options) # set before min_version/max_version params.each{|name, value| self.__send__("#{name}=", value) } if self.verify_mode != OpenSSL::SSL::VERIFY_NONE unless self.ca_file or self.ca_path or self.cert_store self.cert_store = DEFAULT_CERT_STORE end end return params end # call-seq: # ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION # ctx.min_version = :TLS1_2 # ctx.min_version = nil # # Sets the lower bound on the supported SSL/TLS protocol version. The # version may be specified by an integer constant named # OpenSSL::SSL::*_VERSION, a Symbol, or +nil+ which means "any version". # # Be careful that you don't overwrite OpenSSL::SSL::OP_NO_{SSL,TLS}v* # options by #options= once you have called #min_version= or # #max_version=. # # === Example # ctx = OpenSSL::SSL::SSLContext.new # ctx.min_version = OpenSSL::SSL::TLS1_1_VERSION # ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION # # sock = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx) # sock.connect # Initiates a connection using either TLS 1.1 or TLS 1.2 def min_version=(version) set_minmax_proto_version(version, @max_proto_version ||= nil) @min_proto_version = version end # call-seq: # ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION # ctx.max_version = :TLS1_2 # ctx.max_version = nil # # Sets the upper bound of the supported SSL/TLS protocol version. See # #min_version= for the possible values. def max_version=(version) set_minmax_proto_version(@min_proto_version ||= nil, version) @max_proto_version = version end # call-seq: # ctx.ssl_version = :TLSv1 # ctx.ssl_version = "SSLv23" # # Sets the SSL/TLS protocol version for the context. This forces # connections to use only the specified protocol version. This is # deprecated and only provided for backwards compatibility. Use # #min_version= and #max_version= instead. # # === History # As the name hints, this used to call the SSL_CTX_set_ssl_version() # function which sets the SSL method used for connections created from # the context. As of Ruby/OpenSSL 2.1, this accessor method is # implemented to call #min_version= and #max_version= instead. def ssl_version=(meth) meth = meth.to_s if meth.is_a?(Symbol) if /(?_client|_server)\z/ =~ meth meth = $` if $VERBOSE warn "#{caller(1, 1)[0]}: method type #{type.inspect} is ignored" end end version = METHODS_MAP[meth.intern] or raise ArgumentError, "unknown SSL method `%s'" % meth set_minmax_proto_version(version, version) @min_proto_version = @max_proto_version = version end METHODS_MAP = { SSLv23: 0, SSLv2: OpenSSL::SSL::SSL2_VERSION, SSLv3: OpenSSL::SSL::SSL3_VERSION, TLSv1: OpenSSL::SSL::TLS1_VERSION, TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION, TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION, }.freeze private_constant :METHODS_MAP # The list of available SSL/TLS methods. This constant is only provided # for backwards compatibility. METHODS = METHODS_MAP.flat_map { |name,| [name, :"#{name}_client", :"#{name}_server"] }.freeze deprecate_constant :METHODS end module SocketForwarder def addr to_io.addr end def peeraddr to_io.peeraddr end def setsockopt(level, optname, optval) to_io.setsockopt(level, optname, optval) end def getsockopt(level, optname) to_io.getsockopt(level, optname) end def fcntl(*args) to_io.fcntl(*args) end def closed? to_io.closed? end def do_not_reverse_lookup=(flag) to_io.do_not_reverse_lookup = flag end end def verify_certificate_identity(cert, hostname) should_verify_common_name = true cert.extensions.each{|ext| next if ext.oid != "subjectAltName" ostr = OpenSSL::ASN1.decode(ext.to_der).value.last sequence = OpenSSL::ASN1.decode(ostr.value) sequence.value.each{|san| case san.tag when 2 # dNSName in GeneralName (RFC5280) should_verify_common_name = false return true if verify_hostname(hostname, san.value) when 7 # iPAddress in GeneralName (RFC5280) should_verify_common_name = false if san.value.size == 4 || san.value.size == 16 begin return true if san.value == IPAddr.new(hostname).hton rescue IPAddr::InvalidAddressError end end end } } if should_verify_common_name cert.subject.to_a.each{|oid, value| if oid == "CN" return true if verify_hostname(hostname, value) end } end return false end module_function :verify_certificate_identity def verify_hostname(hostname, san) # :nodoc: # RFC 5280, IA5String is limited to the set of ASCII characters return false unless san.ascii_only? return false unless hostname.ascii_only? # See RFC 6125, section 6.4.1 # Matching is case-insensitive. san_parts = san.downcase.split(".") # TODO: this behavior should probably be more strict return san == hostname if san_parts.size < 2 # Matching is case-insensitive. host_parts = hostname.downcase.split(".") # RFC 6125, section 6.4.3, subitem 2. # If the wildcard character is the only character of the left-most # label in the presented identifier, the client SHOULD NOT compare # against anything but the left-most label of the reference # identifier (e.g., *.example.com would match foo.example.com but # not bar.foo.example.com or example.com). return false unless san_parts.size == host_parts.size # RFC 6125, section 6.4.3, subitem 1. # The client SHOULD NOT attempt to match a presented identifier in # which the wildcard character comprises a label other than the # left-most label (e.g., do not match bar.*.example.net). return false unless verify_wildcard(host_parts.shift, san_parts.shift) san_parts.join(".") == host_parts.join(".") end module_function :verify_hostname def verify_wildcard(domain_component, san_component) # :nodoc: parts = san_component.split("*", -1) return false if parts.size > 2 return san_component == domain_component if parts.size == 1 # RFC 6125, section 6.4.3, subitem 3. # The client SHOULD NOT attempt to match a presented identifier # where the wildcard character is embedded within an A-label or # U-label of an internationalized domain name. return false if domain_component.start_with?("xn--") && san_component != "*" parts[0].length + parts[1].length < domain_component.length && domain_component.start_with?(parts[0]) && domain_component.end_with?(parts[1]) end module_function :verify_wildcard class SSLSocket include Buffering include SocketForwarder attr_reader :hostname # The underlying IO object. attr_reader :io alias :to_io :io # The SSLContext object used in this connection. attr_reader :context # Whether to close the underlying socket as well, when the SSL/TLS # connection is shut down. This defaults to +false+. attr_accessor :sync_close # call-seq: # ssl.sysclose => nil # # Sends "close notify" to the peer and tries to shut down the SSL # connection gracefully. # # If sync_close is set to +true+, the underlying IO is also closed. def sysclose return if closed? stop io.close if sync_close end # call-seq: # ssl.post_connection_check(hostname) -> true # # Perform hostname verification following RFC 6125. # # This method MUST be called after calling #connect to ensure that the # hostname of a remote peer has been verified. def post_connection_check(hostname) if peer_cert.nil? msg = "Peer verification enabled, but no certificate received." if using_anon_cipher? msg += " Anonymous cipher suite #{cipher[0]} was negotiated. " \ "Anonymous suites must be disabled to use peer verification." end raise SSLError, msg end unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname) raise SSLError, "hostname \"#{hostname}\" does not match the server certificate" end return true end # call-seq: # ssl.session -> aSession # # Returns the SSLSession object currently used, or nil if the session is # not established. def session SSL::Session.new(self) rescue SSL::Session::SessionError nil end private def using_anon_cipher? ctx = OpenSSL::SSL::SSLContext.new ctx.ciphers = "aNULL" ctx.ciphers.include?(cipher) end def client_cert_cb @context.client_cert_cb end def tmp_dh_callback @context.tmp_dh_callback || OpenSSL::SSL::SSLContext::DEFAULT_TMP_DH_CALLBACK end def tmp_ecdh_callback @context.tmp_ecdh_callback end def session_new_cb @context.session_new_cb end def session_get_cb @context.session_get_cb end end ## # SSLServer represents a TCP/IP server socket with Secure Sockets Layer. class SSLServer include SocketForwarder # When true then #accept works exactly the same as TCPServer#accept attr_accessor :start_immediately # Creates a new instance of SSLServer. # * _srv_ is an instance of TCPServer. # * _ctx_ is an instance of OpenSSL::SSL::SSLContext. def initialize(svr, ctx) @svr = svr @ctx = ctx unless ctx.session_id_context # see #6137 - session id may not exceed 32 bytes prng = ::Random.new($0.hash) session_id = prng.bytes(16).unpack('H*')[0] @ctx.session_id_context = session_id end @start_immediately = true end # Returns the TCPServer passed to the SSLServer when initialized. def to_io @svr end # See TCPServer#listen for details. def listen(backlog=5) @svr.listen(backlog) end # See BasicSocket#shutdown for details. def shutdown(how=Socket::SHUT_RDWR) @svr.shutdown(how) end # Works similar to TCPServer#accept. def accept # Socket#accept returns [socket, addrinfo]. # TCPServer#accept returns a socket. # The following comma strips addrinfo. sock, = @svr.accept begin ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) ssl.sync_close = true ssl.accept if @start_immediately ssl rescue Exception => ex if ssl ssl.close else sock.close end raise ex end end # See IO#close for details. def close @svr.close end end end end PK ]S:_CC&gems/openssl-2.1.4/lib/openssl/x509.rbnu[# frozen_string_literal: false #-- # = Ruby-space definitions that completes C-space funcs for X509 and subclasses # # = Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2002 Michal Rokos # All rights reserved. # # = Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ module OpenSSL module X509 class ExtensionFactory def create_extension(*arg) if arg.size > 1 create_ext(*arg) else send("create_ext_from_"+arg[0].class.name.downcase, arg[0]) end end def create_ext_from_array(ary) raise ExtensionError, "unexpected array form" if ary.size > 3 create_ext(ary[0], ary[1], ary[2]) end def create_ext_from_string(str) # "oid = critical, value" oid, value = str.split(/=/, 2) oid.strip! value.strip! create_ext(oid, value) end def create_ext_from_hash(hash) create_ext(hash["oid"], hash["value"], hash["critical"]) end end class Extension def ==(other) return false unless Extension === other to_der == other.to_der end def to_s # "oid = critical, value" str = self.oid str << " = " str << "critical, " if self.critical? str << self.value.gsub(/\n/, ", ") end def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false} {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?} end def to_a [ self.oid, self.value, self.critical? ] end end class Name module RFC2253DN Special = ',=+<>#;' HexChar = /[0-9a-fA-F]/ HexPair = /#{HexChar}#{HexChar}/ HexString = /#{HexPair}+/ Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/ StringChar = /[^\\"#{Special}]/ QuoteChar = /[^\\"]/ AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/ AttributeValue = / (?!["#])((?:#{StringChar}|#{Pair})*)| \#(#{HexString})| "((?:#{QuoteChar}|#{Pair})*)" /x TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/ module_function def expand_pair(str) return nil unless str return str.gsub(Pair){ pair = $& case pair.size when 2 then pair[1,1] when 3 then Integer("0x#{pair[1,2]}").chr else raise OpenSSL::X509::NameError, "invalid pair: #{str}" end } end def expand_hexstring(str) return nil unless str der = str.gsub(HexPair){$&.to_i(16).chr } a1 = OpenSSL::ASN1.decode(der) return a1.value, a1.tag end def expand_value(str1, str2, str3) value = expand_pair(str1) value, tag = expand_hexstring(str2) unless value value = expand_pair(str3) unless value return value, tag end def scan(dn) str = dn ary = [] while true if md = TypeAndValue.match(str) remain = md.post_match type = md[1] value, tag = expand_value(md[2], md[3], md[4]) rescue nil if value type_and_value = [type, value] type_and_value.push(tag) if tag ary.unshift(type_and_value) if remain.length > 2 && remain[0] == ?, str = remain[1..-1] next elsif remain.length > 2 && remain[0] == ?+ raise OpenSSL::X509::NameError, "multi-valued RDN is not supported: #{dn}" elsif remain.empty? break end end end msg_dn = dn[0, dn.length - str.length] + " =>" + str raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}" end return ary end end class << self def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE) ary = OpenSSL::X509::Name::RFC2253DN.scan(str) self.new(ary, template) end def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE) if str.start_with?("/") # /A=B/C=D format ary = str[1..-1].split("/").map { |i| i.split("=", 2) } else # Comma-separated ary = str.split(",").map { |i| i.strip.split("=", 2) } end self.new(ary, template) end alias parse parse_openssl end def pretty_print(q) q.object_group(self) { q.text ' ' q.text to_s(OpenSSL::X509::Name::RFC2253) } end end class Attribute def ==(other) return false unless Attribute === other to_der == other.to_der end end class StoreContext def cleanup warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE end end class Certificate def pretty_print(q) q.object_group(self) { q.breakable q.text 'subject='; q.pp self.subject; q.text ','; q.breakable q.text 'issuer='; q.pp self.issuer; q.text ','; q.breakable q.text 'serial='; q.pp self.serial; q.text ','; q.breakable q.text 'not_before='; q.pp self.not_before; q.text ','; q.breakable q.text 'not_after='; q.pp self.not_after } end end class CRL def ==(other) return false unless CRL === other to_der == other.to_der end end class Revoked def ==(other) return false unless Revoked === other to_der == other.to_der end end class Request def ==(other) return false unless Request === other to_der == other.to_der end end end end PK ]I1&gems/openssl-2.1.4/lib/openssl/pkey.rbnu[# frozen_string_literal: false #-- # Ruby/OpenSSL Project # Copyright (C) 2017 Ruby/OpenSSL Project Authors #++ module OpenSSL::PKey if defined?(EC) class EC::Point # :call-seq: # point.to_bn([conversion_form]) -> OpenSSL::BN # # Returns the octet string representation of the EC point as an instance of # OpenSSL::BN. # # If _conversion_form_ is not given, the _point_conversion_form_ attribute # set to the group is used. # # See #to_octet_string for more information. def to_bn(conversion_form = group.point_conversion_form) OpenSSL::BN.new(to_octet_string(conversion_form), 2) end end end end PK ]Mff'gems/openssl-2.1.4/lib/openssl/pkcs5.rbnu[# frozen_string_literal: false #-- # Ruby/OpenSSL Project # Copyright (C) 2017 Ruby/OpenSSL Project Authors #++ module OpenSSL module PKCS5 module_function # OpenSSL::PKCS5.pbkdf2_hmac has been renamed to OpenSSL::KDF.pbkdf2_hmac. # This method is provided for backwards compatibility. def pbkdf2_hmac(pass, salt, iter, keylen, digest) OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter, length: keylen, hash: digest) end def pbkdf2_hmac_sha1(pass, salt, iter, keylen) pbkdf2_hmac(pass, salt, iter, keylen, "sha1") end end end PK ]d Ҽ&&+gems/openssl-2.1.4/lib/openssl/buffering.rbnu[# coding: binary # frozen_string_literal: false #-- #= Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2001 GOTOU YUUZOU # All rights reserved. # #= Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ ## # OpenSSL IO buffering mix-in module. # # This module allows an OpenSSL::SSL::SSLSocket to behave like an IO. # # You typically won't use this module directly, you can see it implemented in # OpenSSL::SSL::SSLSocket. module OpenSSL::Buffering include Enumerable ## # The "sync mode" of the SSLSocket. # # See IO#sync for full details. attr_accessor :sync ## # Default size to read from or write to the SSLSocket for buffer operations. BLOCK_SIZE = 1024*16 ## # Creates an instance of OpenSSL's buffering IO module. def initialize(*) super @eof = false @rbuffer = "" @sync = @io.sync end # # for reading. # private ## # Fills the buffer from the underlying SSLSocket def fill_rbuff begin @rbuffer << self.sysread(BLOCK_SIZE) rescue Errno::EAGAIN retry rescue EOFError @eof = true end end ## # Consumes _size_ bytes from the buffer def consume_rbuff(size=nil) if @rbuffer.empty? nil else size = @rbuffer.size unless size ret = @rbuffer[0, size] @rbuffer[0, size] = "" ret end end public ## # Reads _size_ bytes from the stream. If _buf_ is provided it must # reference a string which will receive the data. # # See IO#read for full details. def read(size=nil, buf=nil) if size == 0 if buf buf.clear return buf else return "" end end until @eof break if size && size <= @rbuffer.size fill_rbuff end ret = consume_rbuff(size) || "" if buf buf.replace(ret) ret = buf end (size && ret.empty?) ? nil : ret end ## # Reads at most _maxlen_ bytes from the stream. If _buf_ is provided it # must reference a string which will receive the data. # # See IO#readpartial for full details. def readpartial(maxlen, buf=nil) if maxlen == 0 if buf buf.clear return buf else return "" end end if @rbuffer.empty? begin return sysread(maxlen, buf) rescue Errno::EAGAIN retry end end ret = consume_rbuff(maxlen) if buf buf.replace(ret) ret = buf end ret end ## # Reads at most _maxlen_ bytes in the non-blocking manner. # # When no data can be read without blocking it raises # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable. # # IO::WaitReadable means SSL needs to read internally so read_nonblock # should be called again when the underlying IO is readable. # # IO::WaitWritable means SSL needs to write internally so read_nonblock # should be called again after the underlying IO is writable. # # OpenSSL::Buffering#read_nonblock needs two rescue clause as follows: # # # emulates blocking read (readpartial). # begin # result = ssl.read_nonblock(maxlen) # rescue IO::WaitReadable # IO.select([io]) # retry # rescue IO::WaitWritable # IO.select(nil, [io]) # retry # end # # Note that one reason that read_nonblock writes to the underlying IO is # when the peer requests a new TLS/SSL handshake. See openssl the FAQ for # more details. http://www.openssl.org/support/faq.html # # By specifying a keyword argument _exception_ to +false+, you can indicate # that read_nonblock should not raise an IO::Wait*able exception, but # return the symbol +:wait_writable+ or +:wait_readable+ instead. At EOF, # it will return +nil+ instead of raising EOFError. def read_nonblock(maxlen, buf=nil, exception: true) if maxlen == 0 if buf buf.clear return buf else return "" end end if @rbuffer.empty? return sysread_nonblock(maxlen, buf, exception: exception) end ret = consume_rbuff(maxlen) if buf buf.replace(ret) ret = buf end ret end ## # Reads the next "line" from the stream. Lines are separated by _eol_. If # _limit_ is provided the result will not be longer than the given number of # bytes. # # _eol_ may be a String or Regexp. # # Unlike IO#gets the line read will not be assigned to +$_+. # # Unlike IO#gets the separator must be provided if a limit is provided. def gets(eol=$/, limit=nil) idx = @rbuffer.index(eol) until @eof break if idx fill_rbuff idx = @rbuffer.index(eol) end if eol.is_a?(Regexp) size = idx ? idx+$&.size : nil else size = idx ? idx+eol.size : nil end if size && limit && limit >= 0 size = [size, limit].min end consume_rbuff(size) end ## # Executes the block for every line in the stream where lines are separated # by _eol_. # # See also #gets def each(eol=$/) while line = self.gets(eol) yield line end end alias each_line each ## # Reads lines from the stream which are separated by _eol_. # # See also #gets def readlines(eol=$/) ary = [] while line = self.gets(eol) ary << line end ary end ## # Reads a line from the stream which is separated by _eol_. # # Raises EOFError if at end of file. def readline(eol=$/) raise EOFError if eof? gets(eol) end ## # Reads one character from the stream. Returns nil if called at end of # file. def getc read(1) end ## # Calls the given block once for each byte in the stream. def each_byte # :yields: byte while c = getc yield(c.ord) end end ## # Reads a one-character string from the stream. Raises an EOFError at end # of file. def readchar raise EOFError if eof? getc end ## # Pushes character _c_ back onto the stream such that a subsequent buffered # character read will return it. # # Unlike IO#getc multiple bytes may be pushed back onto the stream. # # Has no effect on unbuffered reads (such as #sysread). def ungetc(c) @rbuffer[0,0] = c.chr end ## # Returns true if the stream is at file which means there is no more data to # be read. def eof? fill_rbuff if !@eof && @rbuffer.empty? @eof && @rbuffer.empty? end alias eof eof? # # for writing. # private ## # Writes _s_ to the buffer. When the buffer is full or #sync is true the # buffer is flushed to the underlying socket. def do_write(s) @wbuffer = "" unless defined? @wbuffer @wbuffer << s @wbuffer.force_encoding(Encoding::BINARY) @sync ||= false if @sync or @wbuffer.size > BLOCK_SIZE until @wbuffer.empty? begin nwrote = syswrite(@wbuffer) rescue Errno::EAGAIN retry end @wbuffer[0, nwrote] = "" end end end public ## # Writes _s_ to the stream. If the argument is not a String it will be # converted using +.to_s+ method. Returns the number of bytes written. def write(*s) s.inject(0) do |written, str| do_write(str) written + str.bytesize end end ## # Writes _s_ in the non-blocking manner. # # If there is buffered data, it is flushed first. This may block. # # write_nonblock returns number of bytes written to the SSL connection. # # When no data can be written without blocking it raises # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable. # # IO::WaitReadable means SSL needs to read internally so write_nonblock # should be called again after the underlying IO is readable. # # IO::WaitWritable means SSL needs to write internally so write_nonblock # should be called again after underlying IO is writable. # # So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows. # # # emulates blocking write. # begin # result = ssl.write_nonblock(str) # rescue IO::WaitReadable # IO.select([io]) # retry # rescue IO::WaitWritable # IO.select(nil, [io]) # retry # end # # Note that one reason that write_nonblock reads from the underlying IO # is when the peer requests a new TLS/SSL handshake. See the openssl FAQ # for more details. http://www.openssl.org/support/faq.html # # By specifying a keyword argument _exception_ to +false+, you can indicate # that write_nonblock should not raise an IO::Wait*able exception, but # return the symbol +:wait_writable+ or +:wait_readable+ instead. def write_nonblock(s, exception: true) flush syswrite_nonblock(s, exception: exception) end ## # Writes _s_ to the stream. _s_ will be converted to a String using # +.to_s+ method. def <<(s) do_write(s) self end ## # Writes _args_ to the stream along with a record separator. # # See IO#puts for full details. def puts(*args) s = "" if args.empty? s << "\n" end args.each{|arg| s << arg.to_s s.sub!(/(? = Licence This program is licensed under the same licence as Ruby. (See the file 'LICENCE'.) =end require 'stringio' module OpenSSL ## # = OpenSSL::Config # # Configuration for the openssl library. # # Many system's installation of openssl library will depend on your system # configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for # the location of the file for your host. # # See also http://www.openssl.org/docs/apps/config.html class Config include Enumerable class << self ## # Parses a given _string_ as a blob that contains configuration for # OpenSSL. # # If the source of the IO is a file, then consider using #parse_config. def parse(string) c = new() parse_config(StringIO.new(string)).each do |section, hash| c[section] = hash end c end ## # load is an alias to ::new alias load new ## # Parses the configuration data read from _io_, see also #parse. # # Raises a ConfigError on invalid configuration data. def parse_config(io) begin parse_config_lines(io) rescue ConfigError => e e.message.replace("error in line #{io.lineno}: " + e.message) raise end end def get_key_string(data, section, key) # :nodoc: if v = data[section] && data[section][key] return v elsif section == 'ENV' if v = ENV[key] return v end end if v = data['default'] && data['default'][key] return v end end private def parse_config_lines(io) section = 'default' data = {section => {}} io_stack = [io] while definition = get_definition(io_stack) definition = clear_comments(definition) next if definition.empty? case definition when /\A\[/ if /\[([^\]]*)\]/ =~ definition section = $1.strip data[section] ||= {} else raise ConfigError, "missing close square bracket" end when /\A\.include (\s*=\s*)?(.+)\z/ path = $2 if File.directory?(path) files = Dir.glob(File.join(path, "*.{cnf,conf}"), File::FNM_EXTGLOB) else files = [path] end files.each do |filename| begin io_stack << StringIO.new(File.read(filename)) rescue raise ConfigError, "could not include file '%s'" % filename end end when /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ if $2 section = $1 key = $2 else key = $1 end value = unescape_value(data, section, $3) (data[section] ||= {})[key] = value.strip else raise ConfigError, "missing equal sign" end end data end # escape with backslash QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/ # escape with backslash and doubled dq QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/ # escaped char map ESCAPE_MAP = { "r" => "\r", "n" => "\n", "b" => "\b", "t" => "\t", } def unescape_value(data, section, value) scanned = [] while m = value.match(/['"\\$]/) scanned << m.pre_match c = m[0] value = m.post_match case c when "'" if m = value.match(QUOTE_REGEXP_SQ) scanned << m[1].gsub(/\\(.)/, '\\1') value = m.post_match else break end when '"' if m = value.match(QUOTE_REGEXP_DQ) scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1') value = m.post_match else break end when "\\" c = value.slice!(0, 1) scanned << (ESCAPE_MAP[c] || c) when "$" ref, value = extract_reference(value) refsec = section if ref.index('::') refsec, ref = ref.split('::', 2) end if v = get_key_string(data, refsec, ref) scanned << v else raise ConfigError, "variable has no value" end else raise 'must not reaced' end end scanned << value scanned.join end def extract_reference(value) rest = '' if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/) value = m[1] || m[2] rest = m.post_match elsif [?(, ?{].include?(value[0]) raise ConfigError, "no close brace" end if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/) return m[0], m.post_match + rest else raise end end def clear_comments(line) # FCOMMENT if m = line.match(/\A([\t\n\f ]*);.*\z/) return m[1] end # COMMENT scanned = [] while m = line.match(/[#'"\\]/) scanned << m.pre_match c = m[0] line = m.post_match case c when '#' line = nil break when "'", '"' regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ scanned << c if m = line.match(regexp) scanned << m[0] line = m.post_match else scanned << line line = nil break end when "\\" scanned << c scanned << line.slice!(0, 1) else raise 'must not reaced' end end scanned << line scanned.join end def get_definition(io_stack) if line = get_line(io_stack) while /[^\\]\\\z/ =~ line if extra = get_line(io_stack) line += extra else break end end return line.strip end end def get_line(io_stack) while io = io_stack.last if line = io.gets return line.gsub(/[\r\n]*/, '') end io_stack.pop end end end ## # Creates an instance of OpenSSL's configuration class. # # This can be used in contexts like OpenSSL::X509::ExtensionFactory.config= # # If the optional _filename_ parameter is provided, then it is read in and # parsed via #parse_config. # # This can raise IO exceptions based on the access, or availability of the # file. A ConfigError exception may be raised depending on the validity of # the data being configured. # def initialize(filename = nil) @data = {} if filename File.open(filename.to_s) do |file| Config.parse_config(file).each do |section, hash| self[section] = hash end end end end ## # Gets the value of _key_ from the given _section_ # # Given the following configurating file being loaded: # # config = OpenSSL::Config.load('foo.cnf') # #=> # # puts config.to_s # #=> [ default ] # # foo=bar # # You can get a specific value from the config if you know the _section_ # and _key_ like so: # # config.get_value('default','foo') # #=> "bar" # def get_value(section, key) if section.nil? raise TypeError.new('nil not allowed') end section = 'default' if section.empty? get_key_string(section, key) end ## # # *Deprecated* # # Use #get_value instead def value(arg1, arg2 = nil) # :nodoc: warn('Config#value is deprecated; use Config#get_value') if arg2.nil? section, key = 'default', arg1 else section, key = arg1, arg2 end section ||= 'default' section = 'default' if section.empty? get_key_string(section, key) end ## # Set the target _key_ with a given _value_ under a specific _section_. # # Given the following configurating file being loaded: # # config = OpenSSL::Config.load('foo.cnf') # #=> # # puts config.to_s # #=> [ default ] # # foo=bar # # You can set the value of _foo_ under the _default_ section to a new # value: # # config.add_value('default', 'foo', 'buzz') # #=> "buzz" # puts config.to_s # #=> [ default ] # # foo=buzz # def add_value(section, key, value) check_modify (@data[section] ||= {})[key] = value end ## # Get a specific _section_ from the current configuration # # Given the following configurating file being loaded: # # config = OpenSSL::Config.load('foo.cnf') # #=> # # puts config.to_s # #=> [ default ] # # foo=bar # # You can get a hash of the specific section like so: # # config['default'] # #=> {"foo"=>"bar"} # def [](section) @data[section] || {} end ## # Deprecated # # Use #[] instead def section(name) # :nodoc: warn('Config#section is deprecated; use Config#[]') @data[name] || {} end ## # Sets a specific _section_ name with a Hash _pairs_. # # Given the following configuration being created: # # config = OpenSSL::Config.new # #=> # # config['default'] = {"foo"=>"bar","baz"=>"buz"} # #=> {"foo"=>"bar", "baz"=>"buz"} # puts config.to_s # #=> [ default ] # # foo=bar # # baz=buz # # It's important to note that this will essentially merge any of the keys # in _pairs_ with the existing _section_. For example: # # config['default'] # #=> {"foo"=>"bar", "baz"=>"buz"} # config['default'] = {"foo" => "changed"} # #=> {"foo"=>"changed"} # config['default'] # #=> {"foo"=>"changed", "baz"=>"buz"} # def []=(section, pairs) check_modify @data[section] ||= {} pairs.each do |key, value| self.add_value(section, key, value) end end ## # Get the names of all sections in the current configuration def sections @data.keys end ## # Get the parsable form of the current configuration # # Given the following configuration being created: # # config = OpenSSL::Config.new # #=> # # config['default'] = {"foo"=>"bar","baz"=>"buz"} # #=> {"foo"=>"bar", "baz"=>"buz"} # puts config.to_s # #=> [ default ] # # foo=bar # # baz=buz # # You can parse get the serialized configuration using #to_s and then parse # it later: # # serialized_config = config.to_s # # much later... # new_config = OpenSSL::Config.parse(serialized_config) # #=> # # puts new_config # #=> [ default ] # foo=bar # baz=buz # def to_s ary = [] @data.keys.sort.each do |section| ary << "[ #{section} ]\n" @data[section].keys.each do |key| ary << "#{key}=#{@data[section][key]}\n" end ary << "\n" end ary.join end ## # For a block. # # Receive the section and its pairs for the current configuration. # # config.each do |section, key, value| # # ... # end # def each @data.each do |section, hash| hash.each do |key, value| yield [section, key, value] end end end ## # String representation of this configuration object, including the class # name and its sections. def inspect "#<#{self.class.name} sections=#{sections.inspect}>" end protected def data # :nodoc: @data end private def initialize_copy(other) @data = other.data.dup end def check_modify raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen? end def get_key_string(section, key) Config.get_key_string(@data, section, key) end end end PK ](gems/openssl-2.1.4/lib/openssl/digest.rbnu[# frozen_string_literal: false #-- # = Ruby-space predefined Digest subclasses # # = Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2002 Michal Rokos # All rights reserved. # # = Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ module OpenSSL class Digest alg = %w(MD2 MD4 MD5 MDC2 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512) if OPENSSL_VERSION_NUMBER < 0x10100000 alg += %w(DSS DSS1 SHA) end # Return the hash value computed with _name_ Digest. _name_ is either the # long name or short name of a supported digest algorithm. # # === Examples # # OpenSSL::Digest.digest("SHA256", "abc") # # which is equivalent to: # # OpenSSL::Digest::SHA256.digest("abc") def self.digest(name, data) super(data, name) end alg.each{|name| klass = Class.new(self) { define_method(:initialize, ->(data = nil) {super(name, data)}) } singleton = (class << klass; self; end) singleton.class_eval{ define_method(:digest){|data| new.digest(data) } define_method(:hexdigest){|data| new.hexdigest(data) } } const_set(name, klass) } # Deprecated. # # This class is only provided for backwards compatibility. # Use OpenSSL::Digest instead. class Digest < Digest; end # :nodoc: deprecate_constant :Digest end # Digest # Returns a Digest subclass by _name_ # # require 'openssl' # # OpenSSL::Digest("MD5") # # => OpenSSL::Digest::MD5 # # Digest("Foo") # # => NameError: wrong constant name Foo def Digest(name) OpenSSL::Digest.const_get(name) end module_function :Digest end # OpenSSL PK ]>)!gems/openssl-2.1.4/lib/openssl.rbnu[# frozen_string_literal: false =begin = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licensed under the same licence as Ruby. (See the file 'LICENCE'.) =end require 'openssl.so' require 'openssl/bn' require 'openssl/pkey' require 'openssl/cipher' require 'openssl/config' require 'openssl/digest' require 'openssl/x509' require 'openssl/ssl' require 'openssl/pkcs5' PK ] !gems/net-telnet-0.2.0/LICENSE.txtnu[Ruby is copyrighted free software by Yukihiro Matsumoto . You can redistribute it and/or modify it under either the terms of the 2-clause BSDL (see the file BSDL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. PK ]V__gems/net-telnet-0.2.0/Gemfilenu[source 'https://rubygems.org' # Specify your gem's dependencies in net-telnet.gemspec gemspec PK ]Znn(gems/net-telnet-0.2.0/net-telnet.gemspecnu[# -*- encoding: utf-8 -*- # stub: net-telnet 0.2.0 ruby lib Gem::Specification.new do |s| s.name = "net-telnet".freeze s.version = "0.2.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["SHIBATA Hiroshi".freeze] s.bindir = "exe".freeze s.date = "2018-07-25" s.description = "Provides telnet client functionality.".freeze s.email = ["hsbt@ruby-lang.org".freeze] s.files = [".gitignore".freeze, ".travis.yml".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "bin/console".freeze, "bin/setup".freeze, "lib/net-telnet.rb".freeze, "lib/net/telnet.rb".freeze, "lib/net/telnet/version.rb".freeze, "net-telnet.gemspec".freeze] s.homepage = "https://github.com/ruby/net-telnet".freeze s.licenses = ["ruby".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.3.5".freeze s.summary = "Provides telnet client functionality.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PK ]77gems/net-telnet-0.2.0/Rakefilenu[require "bundler/gem_tasks" require 'rake/testtask' Rake::TestTask.new do |t| t.libs << "test" t.test_files = FileList['test/test_*.rb'] end task(default: :test) PK ]ɷ׽F F gems/net-telnet-0.2.0/README.mdnu[# Net::Telnet [![Build Status](https://travis-ci.org/ruby/net-telnet.svg?branch=master)](https://travis-ci.org/ruby/net-telnet) Provides telnet client functionality. This class also has, through delegation, all the methods of a socket object (by default, a **TCPSocket**, but can be set by the **Proxy** option to ```new()```). This provides methods such as ```close()``` to end the session and ```sysread()``` to read data directly from the host, instead of via the ```waitfor()``` mechanism. Note that if you do use ```sysread()``` directly when in telnet mode, you should probably pass the output through ```preprocess()``` to extract telnet command sequences. ## Installation Add this line to your application's Gemfile: ```ruby gem 'net-telnet' ``` And then execute: $ bundle Or install it yourself as: $ gem install net-telnet ## Usage ### Log in and send a command, echoing all output to stdout ```ruby localhost = Net::Telnet::new("Host" => "localhost", "Timeout" => 10, "Prompt" => /[$%#>] \z/n) localhost.login("username", "password") { |c| print c } localhost.cmd("command") { |c| print c } localhost.close ``` ### Check a POP server to see if you have mail ```ruby pop = Net::Telnet::new("Host" => "your_destination_host_here", "Port" => 110, "Telnetmode" => false, "Prompt" => /^\+OK/n) pop.cmd("user " + "your_username_here") { |c| print c } pop.cmd("pass " + "your_password_here") { |c| print c } pop.cmd("list") { |c| print c } ``` ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing 1. Fork it ( https://github.com/ruby/net-telnet/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request PK ]Gssgems/net-telnet-0.2.0/bin/setupnu[#!/bin/bash set -euo pipefail IFS=$'\n\t' bundle install # Do any other automated setup that you need to do here PK ]V?OO!gems/net-telnet-0.2.0/bin/consolenu[#!/usr/bin/env ruby require "bundler/setup" require "net/telnet" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start PK ]]8HH'gems/net-telnet-0.2.0/lib/net/telnet.rbnu[# = net/telnet.rb - Simple Telnet Client Library # # Author:: Wakou Aoyama # Documentation:: William Webber and Wakou Aoyama # # This file holds the class Net::Telnet, which provides client-side # telnet functionality. # # For documentation, see Net::Telnet. # require "net/protocol" require "English" module Net # # == Net::Telnet # # Provides telnet client functionality. # # This class also has, through delegation, all the methods of a # socket object (by default, a +TCPSocket+, but can be set by the # +Proxy+ option to new()). This provides methods such as # close() to end the session and sysread() to read # data directly from the host, instead of via the waitfor() # mechanism. Note that if you do use sysread() directly # when in telnet mode, you should probably pass the output through # preprocess() to extract telnet command sequences. # # == Overview # # The telnet protocol allows a client to login remotely to a user # account on a server and execute commands via a shell. The equivalent # is done by creating a Net::Telnet class with the +Host+ option # set to your host, calling #login() with your user and password, # issuing one or more #cmd() calls, and then calling #close() # to end the session. The #waitfor(), #print(), #puts(), and # #write() methods, which #cmd() is implemented on top of, are # only needed if you are doing something more complicated. # # A Net::Telnet object can also be used to connect to non-telnet # services, such as SMTP or HTTP. In this case, you normally # want to provide the +Port+ option to specify the port to # connect to, and set the +Telnetmode+ option to false to prevent # the client from attempting to interpret telnet command sequences. # Generally, #login() will not work with other protocols, and you # have to handle authentication yourself. # # For some protocols, it will be possible to specify the +Prompt+ # option once when you create the Telnet object and use #cmd() calls; # for others, you will have to specify the response sequence to # look for as the Match option to every #cmd() call, or call # #puts() and #waitfor() directly; for yet others, you will have # to use #sysread() instead of #waitfor() and parse server # responses yourself. # # It is worth noting that when you create a new Net::Telnet object, # you can supply a proxy IO channel via the Proxy option. This # can be used to attach the Telnet object to other Telnet objects, # to already open sockets, or to any read-write IO object. This # can be useful, for instance, for setting up a test fixture for # unit testing. # # == Examples # # === Log in and send a command, echoing all output to stdout # # localhost = Net::Telnet::new("Host" => "localhost", # "Timeout" => 10, # "Prompt" => /[$%#>] \z/n) # localhost.login("username", "password") { |c| print c } # localhost.cmd("command") { |c| print c } # localhost.close # # # === Check a POP server to see if you have mail # # pop = Net::Telnet::new("Host" => "your_destination_host_here", # "Port" => 110, # "Telnetmode" => false, # "Prompt" => /^\+OK/n) # pop.cmd("user " + "your_username_here") { |c| print c } # pop.cmd("pass " + "your_password_here") { |c| print c } # pop.cmd("list") { |c| print c } # # == References # # There are a large number of RFCs relevant to the Telnet protocol. # RFCs 854-861 define the base protocol. For a complete listing # of relevant RFCs, see # http://www.omnifarious.org/~hopper/technical/telnet-rfc.html # class Telnet # :stopdoc: IAC = 255.chr # "\377" # "\xff" # interpret as command DONT = 254.chr # "\376" # "\xfe" # you are not to use option DO = 253.chr # "\375" # "\xfd" # please, you use option WONT = 252.chr # "\374" # "\xfc" # I won't use option WILL = 251.chr # "\373" # "\xfb" # I will use option SB = 250.chr # "\372" # "\xfa" # interpret as subnegotiation GA = 249.chr # "\371" # "\xf9" # you may reverse the line EL = 248.chr # "\370" # "\xf8" # erase the current line EC = 247.chr # "\367" # "\xf7" # erase the current character AYT = 246.chr # "\366" # "\xf6" # are you there AO = 245.chr # "\365" # "\xf5" # abort output--but let prog finish IP = 244.chr # "\364" # "\xf4" # interrupt process--permanently BREAK = 243.chr # "\363" # "\xf3" # break DM = 242.chr # "\362" # "\xf2" # data mark--for connect. cleaning NOP = 241.chr # "\361" # "\xf1" # nop SE = 240.chr # "\360" # "\xf0" # end sub negotiation EOR = 239.chr # "\357" # "\xef" # end of record (transparent mode) ABORT = 238.chr # "\356" # "\xee" # Abort process SUSP = 237.chr # "\355" # "\xed" # Suspend process EOF = 236.chr # "\354" # "\xec" # End of file SYNCH = 242.chr # "\362" # "\xf2" # for telfunc calls OPT_BINARY = 0.chr # "\000" # "\x00" # Binary Transmission OPT_ECHO = 1.chr # "\001" # "\x01" # Echo OPT_RCP = 2.chr # "\002" # "\x02" # Reconnection OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead OPT_NAMS = 4.chr # "\004" # "\x04" # Approx Message Size Negotiation OPT_STATUS = 5.chr # "\005" # "\x05" # Status OPT_TM = 6.chr # "\006" # "\x06" # Timing Mark OPT_RCTE = 7.chr # "\a" # "\x07" # Remote Controlled Trans and Echo OPT_NAOL = 8.chr # "\010" # "\x08" # Output Line Width OPT_NAOP = 9.chr # "\t" # "\x09" # Output Page Size OPT_NAOCRD = 10.chr # "\n" # "\x0a" # Output Carriage-Return Disposition OPT_NAOHTS = 11.chr # "\v" # "\x0b" # Output Horizontal Tab Stops OPT_NAOHTD = 12.chr # "\f" # "\x0c" # Output Horizontal Tab Disposition OPT_NAOFFD = 13.chr # "\r" # "\x0d" # Output Formfeed Disposition OPT_NAOVTS = 14.chr # "\016" # "\x0e" # Output Vertical Tabstops OPT_NAOVTD = 15.chr # "\017" # "\x0f" # Output Vertical Tab Disposition OPT_NAOLFD = 16.chr # "\020" # "\x10" # Output Linefeed Disposition OPT_XASCII = 17.chr # "\021" # "\x11" # Extended ASCII OPT_LOGOUT = 18.chr # "\022" # "\x12" # Logout OPT_BM = 19.chr # "\023" # "\x13" # Byte Macro OPT_DET = 20.chr # "\024" # "\x14" # Data Entry Terminal OPT_SUPDUP = 21.chr # "\025" # "\x15" # SUPDUP OPT_SUPDUPOUTPUT = 22.chr # "\026" # "\x16" # SUPDUP Output OPT_SNDLOC = 23.chr # "\027" # "\x17" # Send Location OPT_TTYPE = 24.chr # "\030" # "\x18" # Terminal Type OPT_EOR = 25.chr # "\031" # "\x19" # End of Record OPT_TUID = 26.chr # "\032" # "\x1a" # TACACS User Identification OPT_OUTMRK = 27.chr # "\e" # "\x1b" # Output Marking OPT_TTYLOC = 28.chr # "\034" # "\x1c" # Terminal Location Number OPT_3270REGIME = 29.chr # "\035" # "\x1d" # Telnet 3270 Regime OPT_X3PAD = 30.chr # "\036" # "\x1e" # X.3 PAD OPT_NAWS = 31.chr # "\037" # "\x1f" # Negotiate About Window Size OPT_TSPEED = 32.chr # " " # "\x20" # Terminal Speed OPT_LFLOW = 33.chr # "!" # "\x21" # Remote Flow Control OPT_LINEMODE = 34.chr # "\"" # "\x22" # Linemode OPT_XDISPLOC = 35.chr # "#" # "\x23" # X Display Location OPT_OLD_ENVIRON = 36.chr # "$" # "\x24" # Environment Option OPT_AUTHENTICATION = 37.chr # "%" # "\x25" # Authentication Option OPT_ENCRYPT = 38.chr # "&" # "\x26" # Encryption Option OPT_NEW_ENVIRON = 39.chr # "'" # "\x27" # New Environment Option OPT_EXOPL = 255.chr # "\377" # "\xff" # Extended-Options-List NULL = "\000" CR = "\015" LF = "\012" EOL = CR + LF REVISION = '$Id$' # :startdoc: # # Creates a new Net::Telnet object. # # Attempts to connect to the host (unless the Proxy option is # provided: see below). If a block is provided, it is yielded # status messages on the attempt to connect to the server, of # the form: # # Trying localhost... # Connected to localhost. # # +options+ is a hash of options. The following example lists # all options and their default values. # # host = Net::Telnet::new( # "Host" => "localhost", # default: "localhost" # "Port" => 23, # default: 23 # "Binmode" => false, # default: false # "Output_log" => "output_log", # default: nil (no output) # "Dump_log" => "dump_log", # default: nil (no output) # "Prompt" => /[$%#>] \z/n, # default: /[$%#>] \z/n # "Telnetmode" => true, # default: true # "Timeout" => 10, # default: 10 # # if ignore timeout then set "Timeout" to false. # "Waittime" => 0, # default: 0 # "Proxy" => proxy # default: nil # # proxy is Net::Telnet or IO object # ) # # The options have the following meanings: # # Host:: the hostname or IP address of the host to connect to, as a String. # Defaults to "localhost". # # Port:: the port to connect to. Defaults to 23. # # Binmode:: if false (the default), newline substitution is performed. # Outgoing LF is # converted to CRLF, and incoming CRLF is converted to LF. If # true, this substitution is not performed. This value can # also be set with the #binmode() method. The # outgoing conversion only applies to the #puts() and #print() # methods, not the #write() method. The precise nature of # the newline conversion is also affected by the telnet options # SGA and BIN. # # Output_log:: the name of the file to write connection status messages # and all received traffic to. In the case of a proper # Telnet session, this will include the client input as # echoed by the host; otherwise, it only includes server # responses. Output is appended verbatim to this file. # By default, no output log is kept. # # Dump_log:: as for Output_log, except that output is written in hexdump # format (16 bytes per line as hex pairs, followed by their # printable equivalent), with connection status messages # preceded by '#', sent traffic preceded by '>', and # received traffic preceded by '<'. By default, not dump log # is kept. # # Prompt:: a regular expression matching the host's command-line prompt # sequence. This is needed by the Telnet class to determine # when the output from a command has finished and the host is # ready to receive a new command. By default, this regular # expression is /[$%#>] \z/n. # # Telnetmode:: a boolean value, true by default. In telnet mode, # traffic received from the host is parsed for special # command sequences, and these sequences are escaped # in outgoing traffic sent using #puts() or #print() # (but not #write()). If you are using the Net::Telnet # object to connect to a non-telnet service (such as # SMTP or POP), this should be set to "false" to prevent # undesired data corruption. This value can also be set # by the #telnetmode() method. # # Timeout:: the number of seconds to wait before timing out both the # initial attempt to connect to host (in this constructor), # which raises a Net::OpenTimeout, and all attempts to read data # from the host, which raises a Net::ReadTimeout (in #waitfor(), # #cmd(), and #login()). The default value is 10 seconds. # You can disable the timeout by setting this value to false. # In this case, the connect attempt will eventually timeout # on the underlying connect(2) socket call with an # Errno::ETIMEDOUT error (but generally only after a few # minutes), but other attempts to read data from the host # will hang indefinitely if no data is forthcoming. # # Waittime:: the amount of time to wait after seeing what looks like a # prompt (that is, received data that matches the Prompt # option regular expression) to see if more data arrives. # If more data does arrive in this time, Net::Telnet assumes # that what it saw was not really a prompt. This is to try to # avoid false matches, but it can also lead to missing real # prompts (if, for instance, a background process writes to # the terminal soon after the prompt is displayed). By # default, set to 0, meaning not to wait for more data. # # Proxy:: a proxy object to used instead of opening a direct connection # to the host. Must be either another Net::Telnet object or # an IO object. If it is another Net::Telnet object, this # instance will use that one's socket for communication. If an # IO object, it is used directly for communication. Any other # kind of object will cause an error to be raised. # def initialize(options) # :yield: mesg @options = options @options["Host"] = "localhost" unless @options.has_key?("Host") @options["Port"] = 23 unless @options.has_key?("Port") @options["Prompt"] = /[$%#>] \z/n unless @options.has_key?("Prompt") @options["Timeout"] = 10 unless @options.has_key?("Timeout") @options["Waittime"] = 0 unless @options.has_key?("Waittime") unless @options.has_key?("Binmode") @options["Binmode"] = false else unless (true == @options["Binmode"] or false == @options["Binmode"]) raise ArgumentError, "Binmode option must be true or false" end end unless @options.has_key?("Telnetmode") @options["Telnetmode"] = true else unless (true == @options["Telnetmode"] or false == @options["Telnetmode"]) raise ArgumentError, "Telnetmode option must be true or false" end end @telnet_option = { "SGA" => false, "BINARY" => false } if @options.has_key?("Output_log") @log = File.open(@options["Output_log"], 'a+') @log.sync = true @log.binmode end if @options.has_key?("Dump_log") @dumplog = File.open(@options["Dump_log"], 'a+') @dumplog.sync = true @dumplog.binmode def @dumplog.log_dump(dir, x) # :nodoc: len = x.length addr = 0 offset = 0 while 0 < len if len < 16 line = x[offset, len] else line = x[offset, 16] end hexvals = line.unpack('H*')[0] hexvals += ' ' * (32 - hexvals.length) hexvals = format("%s %s %s %s " * 4, *hexvals.unpack('a2' * 16)) line = line.gsub(/[\000-\037\177-\377]/n, '.') printf "%s 0x%5.5x: %s%s\n", dir, addr, hexvals, line addr += 16 offset += 16 len -= 16 end print "\n" end end if @options.has_key?("Proxy") if @options["Proxy"].kind_of?(Net::Telnet) @sock = @options["Proxy"].sock elsif @options["Proxy"].kind_of?(IO) @sock = @options["Proxy"] else raise "Error: Proxy must be an instance of Net::Telnet or IO." end else message = "Trying " + @options["Host"] + "...\n" yield(message) if block_given? @log.write(message) if @options.has_key?("Output_log") @dumplog.log_dump('#', message) if @options.has_key?("Dump_log") begin if @options["Timeout"] == false @sock = TCPSocket.open(@options["Host"], @options["Port"]) else Timeout.timeout(@options["Timeout"], Net::OpenTimeout) do @sock = TCPSocket.open(@options["Host"], @options["Port"]) end end rescue Net::OpenTimeout raise Net::OpenTimeout, "timed out while opening a connection to the host" rescue @log.write($ERROR_INFO.to_s + "\n") if @options.has_key?("Output_log") @dumplog.log_dump('#', $ERROR_INFO.to_s + "\n") if @options.has_key?("Dump_log") raise end @sock.sync = true @sock.binmode message = "Connected to " + @options["Host"] + ".\n" yield(message) if block_given? @log.write(message) if @options.has_key?("Output_log") @dumplog.log_dump('#', message) if @options.has_key?("Dump_log") end end # initialize # The socket the Telnet object is using. Note that this object becomes # a delegate of the Telnet object, so normally you invoke its methods # directly on the Telnet object. attr_reader :sock # Set telnet command interpretation on (+mode+ == true) or off # (+mode+ == false), or return the current value (+mode+ not # provided). It should be on for true telnet sessions, off if # using Net::Telnet to connect to a non-telnet service such # as SMTP. def telnetmode(mode = nil) case mode when nil @options["Telnetmode"] when true, false @options["Telnetmode"] = mode else raise ArgumentError, "argument must be true or false, or missing" end end # Turn telnet command interpretation on (true) or off (false). It # should be on for true telnet sessions, off if using Net::Telnet # to connect to a non-telnet service such as SMTP. def telnetmode=(mode) if (true == mode or false == mode) @options["Telnetmode"] = mode else raise ArgumentError, "argument must be true or false" end end # Turn newline conversion on (+mode+ == false) or off (+mode+ == true), # or return the current value (+mode+ is not specified). def binmode(mode = nil) case mode when nil @options["Binmode"] when true, false @options["Binmode"] = mode else raise ArgumentError, "argument must be true or false" end end # Turn newline conversion on (false) or off (true). def binmode=(mode) if (true == mode or false == mode) @options["Binmode"] = mode else raise ArgumentError, "argument must be true or false" end end # Preprocess received data from the host. # # Performs newline conversion and detects telnet command sequences. # Called automatically by #waitfor(). You should only use this # method yourself if you have read input directly using sysread() # or similar, and even then only if in telnet mode. def preprocess(string) # combine CR+NULL into CR string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"] # combine EOL into "\n" string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"] # remove NULL string = string.gsub(/#{NULL}/no, '') unless @options["Binmode"] string.gsub(/#{IAC}( [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]| [#{DO}#{DONT}#{WILL}#{WONT}] [#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}]| #{SB}[^#{IAC}]*#{IAC}#{SE} )/xno) do if IAC == $1 # handle escaped IAC characters IAC elsif AYT == $1 # respond to "IAC AYT" (are you there) self.write("nobody here but us pigeons" + EOL) '' elsif DO[0] == $1[0] # respond to "IAC DO x" if OPT_BINARY[0] == $1[1] @telnet_option["BINARY"] = true self.write(IAC + WILL + OPT_BINARY) else self.write(IAC + WONT + $1[1..1]) end '' elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x" self.write(IAC + WONT + $1[1..1]) '' elsif WILL[0] == $1[0] # respond to "IAC WILL x" if OPT_BINARY[0] == $1[1] self.write(IAC + DO + OPT_BINARY) elsif OPT_ECHO[0] == $1[1] self.write(IAC + DO + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = true self.write(IAC + DO + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' elsif WONT[0] == $1[0] # respond to "IAC WON'T x" if OPT_ECHO[0] == $1[1] self.write(IAC + DONT + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = false self.write(IAC + DONT + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' else '' end end end # preprocess # Read data from the host until a certain sequence is matched. # # If a block is given, the received data will be yielded as it # is read in (not necessarily all in one go), or nil if EOF # occurs before any data is received. Whether a block is given # or not, all data read will be returned in a single string, or again # nil if EOF occurs before any data is received. Note that # received data includes the matched sequence we were looking for. # # +options+ can be either a regular expression or a hash of options. # If a regular expression, this specifies the data to wait for. # If a hash, this can specify the following options: # # Match:: a regular expression, specifying the data to wait for. # Prompt:: as for Match; used only if Match is not specified. # String:: as for Match, except a string that will be converted # into a regular expression. Used only if Match and # Prompt are not specified. # Timeout:: the number of seconds to wait for data from the host # before raising a Timeout::Error. If set to false, # no timeout will occur. If not specified, the # Timeout option value specified when this instance # was created will be used, or, failing that, the # default value of 10 seconds. # Waittime:: the number of seconds to wait after matching against # the input data to see if more data arrives. If more # data arrives within this time, we will judge ourselves # not to have matched successfully, and will continue # trying to match. If not specified, the Waittime option # value specified when this instance was created will be # used, or, failing that, the default value of 0 seconds, # which means not to wait for more input. # FailEOF:: if true, when the remote end closes the connection then an # EOFError will be raised. Otherwise, defaults to the old # behaviour that the function will return whatever data # has been received already, or nil if nothing was received. # def waitfor(options) # :yield: recvdata time_out = @options["Timeout"] waittime = @options["Waittime"] fail_eof = @options["FailEOF"] if options.kind_of?(Hash) prompt = if options.has_key?("Match") options["Match"] elsif options.has_key?("Prompt") options["Prompt"] elsif options.has_key?("String") Regexp.new( Regexp.quote(options["String"]) ) end time_out = options["Timeout"] if options.has_key?("Timeout") waittime = options["Waittime"] if options.has_key?("Waittime") fail_eof = options["FailEOF"] if options.has_key?("FailEOF") else prompt = options end if time_out == false time_out = nil end line = '' buf = '' rest = '' until(prompt === line and not @sock.wait_readable(waittime)) unless @sock.wait_readable(time_out) raise Net::ReadTimeout, "timed out while waiting for more data" end begin c = @sock.readpartial(1024 * 1024) @dumplog.log_dump('<', c) if @options.has_key?("Dump_log") if @options["Telnetmode"] c = rest + c if Integer(c.rindex(/#{IAC}#{SE}/no) || 0) < Integer(c.rindex(/#{IAC}#{SB}/no) || 0) buf = preprocess(c[0 ... c.rindex(/#{IAC}#{SB}/no)]) rest = c[c.rindex(/#{IAC}#{SB}/no) .. -1] elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) || c.rindex(/\r\z/no) buf = preprocess(c[0 ... pt]) rest = c[pt .. -1] else buf = preprocess(c) rest = '' end else # Not Telnetmode. # # We cannot use preprocess() on this data, because that # method makes some Telnetmode-specific assumptions. buf = rest + c rest = '' unless @options["Binmode"] if pt = buf.rindex(/\r\z/no) buf = buf[0 ... pt] rest = buf[pt .. -1] end buf.gsub!(/#{EOL}/no, "\n") end end @log.print(buf) if @options.has_key?("Output_log") line += buf yield buf if block_given? rescue EOFError # End of file reached raise if fail_eof if line == '' line = nil yield nil if block_given? end break end end line end # Write +string+ to the host. # # Does not perform any conversions on +string+. Will log +string+ to the # dumplog, if the Dump_log option is set. def write(string) length = string.length while 0 < length @sock.wait_writable @dumplog.log_dump('>', string[-length..-1]) if @options.has_key?("Dump_log") length -= @sock.syswrite(string[-length..-1]) end end # Sends a string to the host. # # This does _not_ automatically append a newline to the string. Embedded # newlines may be converted and telnet command sequences escaped # depending upon the values of telnetmode, binmode, and telnet options # set by the host. def print(string) string = string.gsub(/#{IAC}/no, IAC + IAC) if @options["Telnetmode"] if @options["Binmode"] self.write(string) else if @telnet_option["BINARY"] and @telnet_option["SGA"] # IAC WILL SGA IAC DO BIN send EOL --> CR self.write(string.gsub(/\n/n, CR)) elsif @telnet_option["SGA"] # IAC WILL SGA send EOL --> CR+NULL self.write(string.gsub(/\n/n, CR + NULL)) else # NONE send EOL --> CR+LF self.write(string.gsub(/\n/n, EOL)) end end end # Sends a string to the host. # # Same as #print(), but appends a newline to the string. def puts(string) self.print(string + "\n") end # Send a command to the host. # # More exactly, sends a string to the host, and reads in all received # data until is sees the prompt or other matched sequence. # # If a block is given, the received data will be yielded to it as # it is read in. Whether a block is given or not, the received data # will be return as a string. Note that the received data includes # the prompt and in most cases the host's echo of our command. # # +options+ is either a String, specified the string or command to # send to the host; or it is a hash of options. If a hash, the # following options can be specified: # # String:: the command or other string to send to the host. # Match:: a regular expression, the sequence to look for in # the received data before returning. If not specified, # the Prompt option value specified when this instance # was created will be used, or, failing that, the default # prompt of /[$%#>] \z/n. # Timeout:: the seconds to wait for data from the host before raising # a Timeout error. If not specified, the Timeout option # value specified when this instance was created will be # used, or, failing that, the default value of 10 seconds. # # The command or other string will have the newline sequence appended # to it. def cmd(options) # :yield: recvdata match = @options["Prompt"] time_out = @options["Timeout"] fail_eof = @options["FailEOF"] if options.kind_of?(Hash) string = options["String"] match = options["Match"] if options.has_key?("Match") time_out = options["Timeout"] if options.has_key?("Timeout") fail_eof = options["FailEOF"] if options.has_key?("FailEOF") else string = options end self.puts(string) if block_given? waitfor({"Prompt" => match, "Timeout" => time_out, "FailEOF" => fail_eof}){|c| yield c } else waitfor({"Prompt" => match, "Timeout" => time_out, "FailEOF" => fail_eof}) end end # Login to the host with a given username and password. # # The username and password can either be provided as two string # arguments in that order, or as a hash with keys "Name" and # "Password". # # This method looks for the strings "login" and "Password" from the # host to determine when to send the username and password. If the # login sequence does not follow this pattern (for instance, you # are connecting to a service other than telnet), you will need # to handle login yourself. # # The password can be omitted, either by only # provided one String argument, which will be used as the username, # or by providing a has that has no "Password" key. In this case, # the method will not look for the "Password:" prompt; if it is # sent, it will have to be dealt with by later calls. # # The method returns all data received during the login process from # the host, including the echoed username but not the password (which # the host should not echo). If a block is passed in, this received # data is also yielded to the block as it is received. def login(options, password = nil) # :yield: recvdata login_prompt = /[Ll]ogin[: ]*\z/n password_prompt = /[Pp]ass(?:word|phrase)[: ]*\z/n if options.kind_of?(Hash) username = options["Name"] password = options["Password"] login_prompt = options["LoginPrompt"] if options["LoginPrompt"] password_prompt = options["PasswordPrompt"] if options["PasswordPrompt"] else username = options end if block_given? line = waitfor(login_prompt){|c| yield c } if password line += cmd({"String" => username, "Match" => password_prompt}){|c| yield c } line += cmd(password){|c| yield c } else line += cmd(username){|c| yield c } end else line = waitfor(login_prompt) if password line += cmd({"String" => username, "Match" => password_prompt}) line += cmd(password) else line += cmd(username) end end line end # Closes the connection def close @sock.close end end # class Telnet end # module Net PK ]>7C::/gems/net-telnet-0.2.0/lib/net/telnet/version.rbnu[module Net class Telnet VERSION = "0.2.0" end end PK ][J¼'gems/net-telnet-0.2.0/lib/net-telnet.rbnu[require 'net/telnet' PK ]$(QTTgems/psych-3.1.0/lib/psych.rbnu[# frozen_string_literal: true require 'psych/versions' case RUBY_ENGINE when 'jruby' require 'psych_jars' if JRuby::Util.respond_to?(:load_ext) JRuby::Util.load_ext('org.jruby.ext.psych.PsychLibrary') else require 'java'; require 'jruby' org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false) end else require 'psych.so' end require 'psych/nodes' require 'psych/streaming' require 'psych/visitors' require 'psych/handler' require 'psych/tree_builder' require 'psych/parser' require 'psych/omap' require 'psych/set' require 'psych/coder' require 'psych/core_ext' require 'psych/stream' require 'psych/json/tree_builder' require 'psych/json/stream' require 'psych/handlers/document_stream' require 'psych/class_loader' ### # = Overview # # Psych is a YAML parser and emitter. # Psych leverages libyaml [Home page: https://pyyaml.org/wiki/LibYAML] # or [HG repo: https://bitbucket.org/xi/libyaml] for its YAML parsing # and emitting capabilities. In addition to wrapping libyaml, Psych also # knows how to serialize and de-serialize most Ruby objects to and from # the YAML format. # # = I NEED TO PARSE OR EMIT YAML RIGHT NOW! # # # Parse some YAML # Psych.load("--- foo") # => "foo" # # # Emit some YAML # Psych.dump("foo") # => "--- foo\n...\n" # { :a => 'b'}.to_yaml # => "---\n:a: b\n" # # Got more time on your hands? Keep on reading! # # == YAML Parsing # # Psych provides a range of interfaces for parsing a YAML document ranging from # low level to high level, depending on your parsing needs. At the lowest # level, is an event based parser. Mid level is access to the raw YAML AST, # and at the highest level is the ability to unmarshal YAML to Ruby objects. # # == YAML Emitting # # Psych provides a range of interfaces ranging from low to high level for # producing YAML documents. Very similar to the YAML parsing interfaces, Psych # provides at the lowest level, an event based system, mid-level is building # a YAML AST, and the highest level is converting a Ruby object straight to # a YAML document. # # == High-level API # # === Parsing # # The high level YAML parser provided by Psych simply takes YAML as input and # returns a Ruby data structure. For information on using the high level parser # see Psych.load # # ==== Reading from a string # # Psych.load("--- a") # => 'a' # Psych.load("---\n - a\n - b") # => ['a', 'b'] # # ==== Reading from a file # # Psych.load_file("database.yml") # # ==== Exception handling # # begin # # The second argument changes only the exception contents # Psych.parse("--- `", "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # === Emitting # # The high level emitter has the easiest interface. Psych simply takes a Ruby # data structure and converts it to a YAML document. See Psych.dump for more # information on dumping a Ruby data structure. # # ==== Writing to a string # # # Dump an array, get back a YAML string # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" # # # Dump an array to an IO object # Psych.dump(['a', 'b'], StringIO.new) # => # # # # Dump an array with indentation set # Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n" # # # Dump an array to an IO with indentation set # Psych.dump(['a', ['b']], StringIO.new, :indentation => 3) # # ==== Writing to a file # # Currently there is no direct API for dumping Ruby structure to file: # # File.open('database.yml', 'w') do |file| # file.write(Psych.dump(['a', 'b'])) # end # # == Mid-level API # # === Parsing # # Psych provides access to an AST produced from parsing a YAML document. This # tree is built using the Psych::Parser and Psych::TreeBuilder. The AST can # be examined and manipulated freely. Please see Psych::parse_stream, # Psych::Nodes, and Psych::Nodes::Node for more information on dealing with # YAML syntax trees. # # ==== Reading from a string # # # Returns Psych::Nodes::Stream # Psych.parse_stream("---\n - a\n - b") # # # Returns Psych::Nodes::Document # Psych.parse("---\n - a\n - b") # # ==== Reading from a file # # # Returns Psych::Nodes::Stream # Psych.parse_stream(File.read('database.yml')) # # # Returns Psych::Nodes::Document # Psych.parse_file('database.yml') # # ==== Exception handling # # begin # # The second argument changes only the exception contents # Psych.parse("--- `", "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # === Emitting # # At the mid level is building an AST. This AST is exactly the same as the AST # used when parsing a YAML document. Users can build an AST by hand and the # AST knows how to emit itself as a YAML document. See Psych::Nodes, # Psych::Nodes::Node, and Psych::TreeBuilder for more information on building # a YAML AST. # # ==== Writing to a string # # # We need Psych::Nodes::Stream (not Psych::Nodes::Document) # stream = Psych.parse_stream("---\n - a\n - b") # # stream.to_yaml # => "---\n- a\n- b\n" # # ==== Writing to a file # # # We need Psych::Nodes::Stream (not Psych::Nodes::Document) # stream = Psych.parse_stream(File.read('database.yml')) # # File.open('database.yml', 'w') do |file| # file.write(stream.to_yaml) # end # # == Low-level API # # === Parsing # # The lowest level parser should be used when the YAML input is already known, # and the developer does not want to pay the price of building an AST or # automatic detection and conversion to Ruby objects. See Psych::Parser for # more information on using the event based parser. # # ==== Reading to Psych::Nodes::Stream structure # # parser = Psych::Parser.new(TreeBuilder.new) # => # # parser = Psych.parser # it's an alias for the above # # parser.parse("---\n - a\n - b") # => # # parser.handler # => # # parser.handler.root # => # # # ==== Receiving an events stream # # recorder = Psych::Handlers::Recorder.new # parser = Psych::Parser.new(recorder) # # parser.parse("---\n - a\n - b") # recorder.events # => [list of [event, args] lists] # # event is one of: Psych::Handler::EVENTS # # args are the arguments passed to the event # # === Emitting # # The lowest level emitter is an event based system. Events are sent to a # Psych::Emitter object. That object knows how to convert the events to a YAML # document. This interface should be used when document format is known in # advance or speed is a concern. See Psych::Emitter for more information. # # ==== Writing to a Ruby structure # # Psych.parser.parse("--- a") # => # # # parser.handler.first # => # # parser.handler.first.to_ruby # => ["a"] # # parser.handler.root.first # => # # parser.handler.root.first.to_ruby # => "a" # # # You can instantiate an Emitter manually # Psych::Visitors::ToRuby.new.accept(parser.handler.root.first) # # => "a" module Psych # The version of libyaml Psych is using LIBYAML_VERSION = Psych.libyaml_version.join '.' # Deprecation guard NOT_GIVEN = Object.new private_constant :NOT_GIVEN ### # Load +yaml+ in to a Ruby data structure. If multiple documents are # provided, the object contained in the first document will be returned. # +filename+ will be used in the exception message if any exception # is raised while parsing. If +yaml+ is empty, it returns # the specified +fallback+ return value, which defaults to +false+. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. # # Example: # # Psych.load("--- a") # => 'a' # Psych.load("---\n - a\n - b") # => ['a', 'b'] # # begin # Psych.load("--- `", filename: "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # When the optional +symbolize_names+ keyword argument is set to a # true value, returns symbols for keys in Hash objects (default: strings). # # Psych.load("---\n foo: bar") # => {"foo"=>"bar"} # Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} # # Raises a TypeError when `yaml` parameter is NilClass # # NOTE: This method *should not* be used to parse untrusted documents, such as # YAML documents that are supplied via user input. Instead, please use the # safe_load method. # def self.load yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: false, symbolize_names: false if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load is deprecated. Use keyword argument like Psych.load(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end result = parse(yaml, filename: filename) return fallback unless result result = result.to_ruby if result symbolize_names!(result) if symbolize_names result end ### # Safely load the yaml string in +yaml+. By default, only the following # classes are allowed to be deserialized: # # * TrueClass # * FalseClass # * NilClass # * Numeric # * String # * Array # * Hash # # Recursive data structures are not allowed by default. Arbitrary classes # can be allowed by adding those classes to the +permitted_classes+ keyword argument. They are # additive. For example, to allow Date deserialization: # # Psych.safe_load(yaml, permitted_classes: [Date]) # # Now the Date class can be loaded in addition to the classes listed above. # # Aliases can be explicitly allowed by changing the +aliases+ keyword argument. # For example: # # x = [] # x << x # yaml = Psych.dump x # Psych.safe_load yaml # => raises an exception # Psych.safe_load yaml, aliases: true # => loads the aliases # # A Psych::DisallowedClass exception will be raised if the yaml contains a # class that isn't in the +permitted_classes+ list. # # A Psych::BadAlias exception will be raised if the yaml contains aliases # but the +aliases+ keyword argument is set to false. # # +filename+ will be used in the exception message if any exception is raised # while parsing. # # When the optional +symbolize_names+ keyword argument is set to a # true value, returns symbols for keys in Hash objects (default: strings). # # Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"} # Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} # def self.safe_load yaml, legacy_permitted_classes = NOT_GIVEN, legacy_permitted_symbols = NOT_GIVEN, legacy_aliases = NOT_GIVEN, legacy_filename = NOT_GIVEN, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false if legacy_permitted_classes != NOT_GIVEN warn_with_uplevel 'Passing permitted_classes with the 2nd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_classes: ...) instead.', uplevel: 1 if $VERBOSE permitted_classes = legacy_permitted_classes end if legacy_permitted_symbols != NOT_GIVEN warn_with_uplevel 'Passing permitted_symbols with the 3rd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_symbols: ...) instead.', uplevel: 1 if $VERBOSE permitted_symbols = legacy_permitted_symbols end if legacy_aliases != NOT_GIVEN warn_with_uplevel 'Passing aliases with the 4th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, aliases: ...) instead.', uplevel: 1 if $VERBOSE aliases = legacy_aliases end if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 5th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end result = parse(yaml, filename: filename) return fallback unless result class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s), permitted_symbols.map(&:to_s)) scanner = ScalarScanner.new class_loader visitor = if aliases Visitors::ToRuby.new scanner, class_loader else Visitors::NoAliasRuby.new scanner, class_loader end result = visitor.accept result symbolize_names!(result) if symbolize_names result end ### # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Document. # +filename+ is used in the exception message if a Psych::SyntaxError is # raised. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. # # Example: # # Psych.parse("---\n - a\n - b") # => # # # begin # Psych.parse("--- `", filename: "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # See Psych::Nodes for more information about YAML AST. def self.parse yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: NOT_GIVEN if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse is deprecated. Use keyword argument like Psych.parse(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end parse_stream(yaml, filename: filename) do |node| return node end if fallback != NOT_GIVEN warn_with_uplevel 'Passing the `fallback` keyword argument of Psych.parse is deprecated.', uplevel: 1 if $VERBOSE fallback else false end end ### # Parse a file at +filename+. Returns the Psych::Nodes::Document. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. def self.parse_file filename, fallback: false result = File.open filename, 'r:bom|utf-8' do |f| parse f, filename: filename end result || fallback end ### # Returns a default parser def self.parser Psych::Parser.new(TreeBuilder.new) end ### # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Stream. # This method can handle multiple YAML documents contained in +yaml+. # +filename+ is used in the exception message if a Psych::SyntaxError is # raised. # # If a block is given, a Psych::Nodes::Document node will be yielded to the # block as it's being parsed. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. # # Example: # # Psych.parse_stream("---\n - a\n - b") # => # # # Psych.parse_stream("--- a\n--- b") do |node| # node # => # # end # # begin # Psych.parse_stream("--- `", filename: "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # Raises a TypeError when NilClass is passed. # # See Psych::Nodes for more information about YAML AST. def self.parse_stream yaml, legacy_filename = NOT_GIVEN, filename: nil, &block if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse_stream is deprecated. Use keyword argument like Psych.parse_stream(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end if block_given? parser = Psych::Parser.new(Handlers::DocumentStream.new(&block)) parser.parse yaml, filename else parser = self.parser parser.parse yaml, filename parser.handler.root end end ### # call-seq: # Psych.dump(o) -> string of yaml # Psych.dump(o, options) -> string of yaml # Psych.dump(o, io) -> io object passed in # Psych.dump(o, io, options) -> io object passed in # # Dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in # to control the output format. If an IO object is passed in, the YAML will # be dumped to that IO object. # # Currently supported options are: # # [:indentation] Number of space characters used to indent. # Acceptable value should be in 0..9 range, # otherwise option is ignored. # # Default: 2. # [:line_width] Max character to wrap line at. # # Default: 0 (meaning "wrap at 81"). # [:canonical] Write "canonical" YAML form (very verbose, yet # strictly formal). # # Default: false. # [:header] Write %YAML [version] at the beginning of document. # # Default: false. # # Example: # # # Dump an array, get back a YAML string # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" # # # Dump an array to an IO object # Psych.dump(['a', 'b'], StringIO.new) # => # # # # Dump an array with indentation set # Psych.dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n" # # # Dump an array to an IO with indentation set # Psych.dump(['a', ['b']], StringIO.new, indentation: 3) def self.dump o, io = nil, options = {} if Hash === io options = io io = nil end visitor = Psych::Visitors::YAMLTree.create options visitor << o visitor.tree.yaml io, options end ### # Dump a list of objects as separate documents to a document stream. # # Example: # # Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n" def self.dump_stream *objects visitor = Psych::Visitors::YAMLTree.create({}) objects.each do |o| visitor << o end visitor.tree.yaml end ### # Dump Ruby +object+ to a JSON string. def self.to_json object visitor = Psych::Visitors::JSONTree.create visitor << object visitor.tree.yaml end ### # Load multiple documents given in +yaml+. Returns the parsed documents # as a list. If a block is given, each document will be converted to Ruby # and passed to the block during parsing # # Example: # # Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] # # list = [] # Psych.load_stream("--- foo\n...\n--- bar\n...") do |ruby| # list << ruby # end # list # => ['foo', 'bar'] # def self.load_stream yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: [] if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load_stream is deprecated. Use keyword argument like Psych.load_stream(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end result = if block_given? parse_stream(yaml, filename: filename) do |node| yield node.to_ruby end else parse_stream(yaml, filename: filename).children.map(&:to_ruby) end return fallback if result.is_a?(Array) && result.empty? result end ### # Load the document contained in +filename+. Returns the yaml contained in # +filename+ as a Ruby object, or if the file is empty, it returns # the specified +fallback+ return value, which defaults to +false+. def self.load_file filename, fallback: false File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename: filename, fallback: fallback } end # :stopdoc: @domain_types = {} def self.add_domain_type domain, type_tag, &block key = ['tag', domain, type_tag].join ':' @domain_types[key] = [key, block] @domain_types["tag:#{type_tag}"] = [key, block] end def self.add_builtin_type type_tag, &block domain = 'yaml.org,2002' key = ['tag', domain, type_tag].join ':' @domain_types[key] = [key, block] end def self.remove_type type_tag @domain_types.delete type_tag end @load_tags = {} @dump_tags = {} def self.add_tag tag, klass @load_tags[tag] = klass.name @dump_tags[klass] = tag end def self.symbolize_names!(result) case result when Hash result.keys.each do |key| result[key.to_sym] = symbolize_names!(result.delete(key)) end when Array result.map! { |r| symbolize_names!(r) } end result end private_class_method :symbolize_names! # Workaround for emulating `warn '...', uplevel: 1` in Ruby 2.4 or lower. def self.warn_with_uplevel(message, uplevel: 1) at = parse_caller(caller[uplevel]).join(':') warn "#{at}: #{message}" end def self.parse_caller(at) if /^(.+?):(\d+)(?::in `.*')?/ =~ at file = $1 line = $2.to_i [file, line] end end private_class_method :warn_with_uplevel, :parse_caller class << self attr_accessor :load_tags attr_accessor :dump_tags attr_accessor :domain_types end # :startdoc: end PK ]H,gems/psych-3.1.0/lib/psych/scalar_scanner.rbnu[# frozen_string_literal: true require 'strscan' module Psych ### # Scan scalars for built in types class ScalarScanner # Taken from http://yaml.org/type/timestamp.html TIME = /^-?\d{4}-\d{1,2}-\d{1,2}(?:[Tt]|\s+)\d{1,2}:\d\d:\d\d(?:\.\d*)?(?:\s*(?:Z|[-+]\d{1,2}:?(?:\d\d)?))?$/ # Taken from http://yaml.org/type/float.html FLOAT = /^(?:[-+]?([0-9][0-9_,]*)?\.[0-9]*([eE][-+][0-9]+)?(?# base 10) |[-+]?\.(inf|Inf|INF)(?# infinity) |\.(nan|NaN|NAN)(?# not a number))$/x # Taken from http://yaml.org/type/int.html INTEGER = /^(?:[-+]?0b[0-1_,]+ (?# base 2) |[-+]?0[0-7_,]+ (?# base 8) |[-+]?(?:0|[1-9][0-9_,]*) (?# base 10) |[-+]?0x[0-9a-fA-F_,]+ (?# base 16))$/x attr_reader :class_loader # Create a new scanner def initialize class_loader @symbol_cache = {} @class_loader = class_loader end # Tokenize +string+ returning the Ruby object def tokenize string return nil if string.empty? return @symbol_cache[string] if @symbol_cache.key?(string) # Check for a String type, being careful not to get caught by hash keys, hex values, and # special floats (e.g., -.inf). if string.match?(/^[^\d\.:-]?[A-Za-z_\s!@#\$%\^&\*\(\)\{\}\<\>\|\/\\~;=]+/) || string.match?(/\n/) return string if string.length > 5 if string.match?(/^[^ytonf~]/i) string elsif string == '~' || string.match?(/^null$/i) nil elsif string.match?(/^(yes|true|on)$/i) true elsif string.match?(/^(no|false|off)$/i) false else string end elsif string.match?(TIME) begin parse_time string rescue ArgumentError string end elsif string.match?(/^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/) require 'date' begin class_loader.date.strptime(string, '%Y-%m-%d') rescue ArgumentError string end elsif string.match?(/^\.inf$/i) Float::INFINITY elsif string.match?(/^-\.inf$/i) -Float::INFINITY elsif string.match?(/^\.nan$/i) Float::NAN elsif string.match?(/^:./) if string =~ /^:(["'])(.*)\1/ @symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, '')) else @symbol_cache[string] = class_loader.symbolize(string.sub(/^:/, '')) end elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}$/) i = 0 string.split(':').each_with_index do |n,e| i += (n.to_i * 60 ** (e - 2).abs) end i elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}\.[0-9_]*$/) i = 0 string.split(':').each_with_index do |n,e| i += (n.to_f * 60 ** (e - 2).abs) end i elsif string.match?(FLOAT) if string.match?(/\A[-+]?\.\Z/) string else Float(string.gsub(/[,_]|\.([Ee]|$)/, '\1')) end elsif string.match?(INTEGER) parse_int string else string end end ### # Parse and return an int from +string+ def parse_int string Integer(string.gsub(/[,]/, '')) end ### # Parse and return a Time from +string+ def parse_time string klass = class_loader.load 'Time' date, time = *(string.split(/[ tT]/, 2)) (yy, m, dd) = date.match(/^(-?\d{4})-(\d{1,2})-(\d{1,2})/).captures.map { |x| x.to_i } md = time.match(/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/) (hh, mm, ss) = md[1].split(':').map { |x| x.to_i } us = (md[2] ? Rational("0.#{md[2]}") : 0) * 1000000 time = klass.utc(yy, m, dd, hh, mm, ss, us) return time if 'Z' == md[3] return klass.at(time.to_i, us) unless md[3] tz = md[3].match(/^([+\-]?\d{1,2})\:?(\d{1,2})?$/)[1..-1].compact.map { |digit| Integer(digit, 10) } offset = tz.first * 3600 if offset < 0 offset -= ((tz[1] || 0) * 60) else offset += ((tz[1] || 0) * 60) end klass.new(yy, m, dd, hh, mm, ss+us/(1_000_000r), offset) end end end PK ]KK"gems/psych-3.1.0/lib/psych/omap.rbnu[# frozen_string_literal: true module Psych class Omap < ::Hash end end PK ] [$gems/psych-3.1.0/lib/psych/parser.rbnu[# frozen_string_literal: true module Psych ### # YAML event parser class. This class parses a YAML document and calls # events on the handler that is passed to the constructor. The events can # be used for things such as constructing a YAML AST or deserializing YAML # documents. It can even be fed back to Psych::Emitter to emit the same # document that was parsed. # # See Psych::Handler for documentation on the events that Psych::Parser emits. # # Here is an example that prints out ever scalar found in a YAML document: # # # Handler for detecting scalar values # class ScalarHandler < Psych::Handler # def scalar value, anchor, tag, plain, quoted, style # puts value # end # end # # parser = Psych::Parser.new(ScalarHandler.new) # parser.parse(yaml_document) # # Here is an example that feeds the parser back in to Psych::Emitter. The # YAML document is read from STDIN and written back out to STDERR: # # parser = Psych::Parser.new(Psych::Emitter.new($stderr)) # parser.parse($stdin) # # Psych uses Psych::Parser in combination with Psych::TreeBuilder to # construct an AST of the parsed YAML document. class Parser class Mark < Struct.new(:index, :line, :column) end # The handler on which events will be called attr_accessor :handler # Set the encoding for this parser to +encoding+ attr_writer :external_encoding ### # Creates a new Psych::Parser instance with +handler+. YAML events will # be called on +handler+. See Psych::Parser for more details. def initialize handler = Handler.new @handler = handler @external_encoding = ANY end end end PK ]`[%gems/psych-3.1.0/lib/psych/handler.rbnu[# frozen_string_literal: true module Psych ### # Psych::Handler is an abstract base class that defines the events used # when dealing with Psych::Parser. Clients who want to use Psych::Parser # should implement a class that inherits from Psych::Handler and define # events that they can handle. # # Psych::Handler defines all events that Psych::Parser can possibly send to # event handlers. # # See Psych::Parser for more details class Handler ### # Configuration options for dumping YAML. class DumperOptions attr_accessor :line_width, :indentation, :canonical def initialize @line_width = 0 @indentation = 2 @canonical = false end end # Default dumping options OPTIONS = DumperOptions.new # Events that a Handler should respond to. EVENTS = [ :alias, :empty, :end_document, :end_mapping, :end_sequence, :end_stream, :scalar, :start_document, :start_mapping, :start_sequence, :start_stream ] ### # Called with +encoding+ when the YAML stream starts. This method is # called once per stream. A stream may contain multiple documents. # # See the constants in Psych::Parser for the possible values of +encoding+. def start_stream encoding end ### # Called when the document starts with the declared +version+, # +tag_directives+, if the document is +implicit+. # # +version+ will be an array of integers indicating the YAML version being # dealt with, +tag_directives+ is a list of tuples indicating the prefix # and suffix of each tag, and +implicit+ is a boolean indicating whether # the document is started implicitly. # # === Example # # Given the following YAML: # # %YAML 1.1 # %TAG ! tag:tenderlovemaking.com,2009: # --- !squee # # The parameters for start_document must be this: # # version # => [1, 1] # tag_directives # => [["!", "tag:tenderlovemaking.com,2009:"]] # implicit # => false def start_document version, tag_directives, implicit end ### # Called with the document ends. +implicit+ is a boolean value indicating # whether or not the document has an implicit ending. # # === Example # # Given the following YAML: # # --- # hello world # # +implicit+ will be true. Given this YAML: # # --- # hello world # ... # # +implicit+ will be false. def end_document implicit end ### # Called when an alias is found to +anchor+. +anchor+ will be the name # of the anchor found. # # === Example # # Here we have an example of an array that references itself in YAML: # # --- &ponies # - first element # - *ponies # # &ponies is the anchor, *ponies is the alias. In this case, alias is # called with "ponies". def alias anchor end ### # Called when a scalar +value+ is found. The scalar may have an # +anchor+, a +tag+, be implicitly +plain+ or implicitly +quoted+ # # +value+ is the string value of the scalar # +anchor+ is an associated anchor or nil # +tag+ is an associated tag or nil # +plain+ is a boolean value # +quoted+ is a boolean value # +style+ is an integer idicating the string style # # See the constants in Psych::Nodes::Scalar for the possible values of # +style+ # # === Example # # Here is a YAML document that exercises most of the possible ways this # method can be called: # # --- # - !str "foo" # - &anchor fun # - many # lines # - | # many # newlines # # The above YAML document contains a list with four strings. Here are # the parameters sent to this method in the same order: # # # value anchor tag plain quoted style # ["foo", nil, "!str", false, false, 3 ] # ["fun", "anchor", nil, true, false, 1 ] # ["many lines", nil, nil, true, false, 1 ] # ["many\nnewlines\n", nil, nil, false, true, 4 ] # def scalar value, anchor, tag, plain, quoted, style end ### # Called when a sequence is started. # # +anchor+ is the anchor associated with the sequence or nil. # +tag+ is the tag associated with the sequence or nil. # +implicit+ a boolean indicating whether or not the sequence was implicitly # started. # +style+ is an integer indicating the list style. # # See the constants in Psych::Nodes::Sequence for the possible values of # +style+. # # === Example # # Here is a YAML document that exercises most of the possible ways this # method can be called: # # --- # - !!seq [ # a # ] # - &pewpew # - b # # The above YAML document consists of three lists, an outer list that # contains two inner lists. Here is a matrix of the parameters sent # to represent these lists: # # # anchor tag implicit style # [nil, nil, true, 1 ] # [nil, "tag:yaml.org,2002:seq", false, 2 ] # ["pewpew", nil, true, 1 ] def start_sequence anchor, tag, implicit, style end ### # Called when a sequence ends. def end_sequence end ### # Called when a map starts. # # +anchor+ is the anchor associated with the map or +nil+. # +tag+ is the tag associated with the map or +nil+. # +implicit+ is a boolean indicating whether or not the map was implicitly # started. # +style+ is an integer indicating the mapping style. # # See the constants in Psych::Nodes::Mapping for the possible values of # +style+. # # === Example # # Here is a YAML document that exercises most of the possible ways this # method can be called: # # --- # k: !!map { hello: world } # v: &pewpew # hello: world # # The above YAML document consists of three maps, an outer map that contains # two inner maps. Below is a matrix of the parameters sent in order to # represent these three maps: # # # anchor tag implicit style # [nil, nil, true, 1 ] # [nil, "tag:yaml.org,2002:map", false, 2 ] # ["pewpew", nil, true, 1 ] def start_mapping anchor, tag, implicit, style end ### # Called when a map ends def end_mapping end ### # Called when an empty event happens. (Which, as far as I can tell, is # never). def empty end ### # Called when the YAML stream ends def end_stream end ### # Called before each event with line/column information. def event_location(start_line, start_column, end_line, end_column) end ### # Is this handler a streaming handler? def streaming? false end end end PK ] *gems/psych-3.1.0/lib/psych/tree_builder.rbnu[# frozen_string_literal: true require 'psych/handler' module Psych ### # This class works in conjunction with Psych::Parser to build an in-memory # parse tree that represents a YAML document. # # == Example # # parser = Psych::Parser.new Psych::TreeBuilder.new # parser.parse('--- foo') # tree = parser.handler.root # # See Psych::Handler for documentation on the event methods used in this # class. class TreeBuilder < Psych::Handler # Returns the root node for the built tree attr_reader :root # Create a new TreeBuilder instance def initialize @stack = [] @last = nil @root = nil @start_line = nil @start_column = nil @end_line = nil @end_column = nil end def event_location(start_line, start_column, end_line, end_column) @start_line = start_line @start_column = start_column @end_line = end_line @end_column = end_column end %w{ Sequence Mapping }.each do |node| class_eval %{ def start_#{node.downcase}(anchor, tag, implicit, style) n = Nodes::#{node}.new(anchor, tag, implicit, style) set_start_location(n) @last.children << n push n end def end_#{node.downcase} n = pop set_end_location(n) n end } end ### # Handles start_document events with +version+, +tag_directives+, # and +implicit+ styling. # # See Psych::Handler#start_document def start_document version, tag_directives, implicit n = Nodes::Document.new version, tag_directives, implicit set_start_location(n) @last.children << n push n end ### # Handles end_document events with +version+, +tag_directives+, # and +implicit+ styling. # # See Psych::Handler#start_document def end_document implicit_end = !streaming? @last.implicit_end = implicit_end n = pop set_end_location(n) n end def start_stream encoding @root = Nodes::Stream.new(encoding) set_start_location(@root) push @root end def end_stream n = pop set_end_location(n) n end def scalar value, anchor, tag, plain, quoted, style s = Nodes::Scalar.new(value,anchor,tag,plain,quoted,style) set_location(s) @last.children << s s end def alias anchor a = Nodes::Alias.new(anchor) set_location(a) @last.children << a a end private def push value @stack.push value @last = value end def pop x = @stack.pop @last = @stack.last x end def set_location(node) set_start_location(node) set_end_location(node) end def set_start_location(node) node.start_line = @start_line node.start_column = @start_column end def set_end_location(node) node.end_line = @end_line node.end_column = @end_column end end end PK ]'gems/psych-3.1.0/lib/psych/exception.rbnu[# frozen_string_literal: true module Psych class Exception < RuntimeError end class BadAlias < Exception end class DisallowedClass < Exception def initialize klass_name super "Tried to load unspecified class: #{klass_name}" end end end PK ]*JJ!gems/psych-3.1.0/lib/psych/set.rbnu[# frozen_string_literal: true module Psych class Set < ::Hash end end PK ]PKK0gems/psych-3.1.0/lib/psych/visitors/json_tree.rbnu[# frozen_string_literal: true require 'psych/json/ruby_events' module Psych module Visitors class JSONTree < YAMLTree include Psych::JSON::RubyEvents def self.create options = {} emitter = Psych::JSON::TreeBuilder.new class_loader = ClassLoader.new ss = ScalarScanner.new class_loader new(emitter, ss, options) end def accept target if target.respond_to?(:encode_with) dump_coder target else send(@dispatch_cache[target.class], target) end end end end end PK ]R(rr2gems/psych-3.1.0/lib/psych/visitors/depth_first.rbnu[# frozen_string_literal: true module Psych module Visitors class DepthFirst < Psych::Visitors::Visitor def initialize block @block = block end private def nary o o.children.each { |x| visit x } @block.call o end alias :visit_Psych_Nodes_Stream :nary alias :visit_Psych_Nodes_Document :nary alias :visit_Psych_Nodes_Sequence :nary alias :visit_Psych_Nodes_Mapping :nary def terminal o @block.call o end alias :visit_Psych_Nodes_Scalar :terminal alias :visit_Psych_Nodes_Alias :terminal end end end PK ]#<#<0gems/psych-3.1.0/lib/psych/visitors/yaml_tree.rbnu[# frozen_string_literal: true require 'psych/tree_builder' require 'psych/scalar_scanner' require 'psych/class_loader' module Psych module Visitors ### # YAMLTree builds a YAML ast given a Ruby object. For example: # # builder = Psych::Visitors::YAMLTree.new # builder << { :foo => 'bar' } # builder.tree # => # v } @emitter.end_sequence end def visit_Encoding o tag = "!ruby/encoding" @emitter.scalar o.name, nil, tag, false, false, Nodes::Scalar::ANY end def visit_Object o tag = Psych.dump_tags[o.class] unless tag klass = o.class == Object ? nil : o.class.name tag = ['!ruby/object', klass].compact.join(':') end map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) register(o, map) dump_ivars o @emitter.end_mapping end alias :visit_Delegator :visit_Object def visit_Struct o tag = ['!ruby/struct', o.class.name].compact.join(':') register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) o.members.each do |member| @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY accept o[member] end dump_ivars o @emitter.end_mapping end def visit_Exception o dump_exception o, private_iv_get(o, 'mesg') end def visit_NameError o dump_exception o, o.message.to_s end def visit_Regexp o register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY) end def visit_DateTime o formatted = if o.offset.zero? o.strftime("%Y-%m-%d %H:%M:%S.%9N Z".freeze) else o.strftime("%Y-%m-%d %H:%M:%S.%9N %:z".freeze) end tag = '!ruby/object:DateTime' register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY) end def visit_Time o formatted = format_time o register o, @emitter.scalar(formatted, nil, nil, true, false, Nodes::Scalar::ANY) end def visit_Rational o register o, @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK) [ 'denominator', o.denominator.to_s, 'numerator', o.numerator.to_s ].each do |m| @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY end @emitter.end_mapping end def visit_Complex o register o, @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK) ['real', o.real.to_s, 'image', o.imag.to_s].each do |m| @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY end @emitter.end_mapping end def visit_Integer o @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY end alias :visit_TrueClass :visit_Integer alias :visit_FalseClass :visit_Integer alias :visit_Date :visit_Integer def visit_Float o if o.nan? @emitter.scalar '.nan', nil, nil, true, false, Nodes::Scalar::ANY elsif o.infinite? @emitter.scalar((o.infinite? > 0 ? '.inf' : '-.inf'), nil, nil, true, false, Nodes::Scalar::ANY) else @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY end end def visit_BigDecimal o @emitter.scalar o._dump, nil, '!ruby/object:BigDecimal', false, false, Nodes::Scalar::ANY end def visit_String o plain = true quote = true style = Nodes::Scalar::PLAIN tag = nil if binary?(o) o = [o].pack('m0') tag = '!binary' # FIXME: change to below when syck is removed #tag = 'tag:yaml.org,2002:binary' style = Nodes::Scalar::LITERAL plain = false quote = false elsif o =~ /\n(?!\Z)/ # match \n except blank line at the end of string style = Nodes::Scalar::LITERAL elsif o == '<<' style = Nodes::Scalar::SINGLE_QUOTED tag = 'tag:yaml.org,2002:str' plain = false quote = false elsif @line_width && o.length > @line_width style = Nodes::Scalar::FOLDED elsif o =~ /^[^[:word:]][^"]*$/ style = Nodes::Scalar::DOUBLE_QUOTED elsif not String === @ss.tokenize(o) or /\A0[0-7]*[89]/ =~ o style = Nodes::Scalar::SINGLE_QUOTED end is_primitive = o.class == ::String ivars = is_primitive ? [] : o.instance_variables if ivars.empty? unless is_primitive tag = "!ruby/string:#{o.class}" plain = false quote = false end @emitter.scalar o, nil, tag, plain, quote, style else maptag = '!ruby/string'.dup maptag << ":#{o.class}" unless o.class == ::String register o, @emitter.start_mapping(nil, maptag, false, Nodes::Mapping::BLOCK) @emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY @emitter.scalar o, nil, tag, plain, quote, style dump_ivars o @emitter.end_mapping end end def visit_Module o raise TypeError, "can't dump anonymous module: #{o}" unless o.name register o, @emitter.scalar(o.name, nil, '!ruby/module', false, false, Nodes::Scalar::SINGLE_QUOTED) end def visit_Class o raise TypeError, "can't dump anonymous class: #{o}" unless o.name register o, @emitter.scalar(o.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED) end def visit_Range o register o, @emitter.start_mapping(nil, '!ruby/range', false, Nodes::Mapping::BLOCK) ['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m| accept m end @emitter.end_mapping end def visit_Hash o if o.class == ::Hash register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK)) o.each do |k,v| accept k accept v end @emitter.end_mapping else visit_hash_subclass o end end def visit_Psych_Set o register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK)) o.each do |k,v| accept k accept v end @emitter.end_mapping end def visit_Array o if o.class == ::Array visit_Enumerator o else visit_array_subclass o end end def visit_Enumerator o register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) o.each { |c| accept c } @emitter.end_sequence end def visit_NilClass o @emitter.scalar('', nil, 'tag:yaml.org,2002:null', true, false, Nodes::Scalar::ANY) end def visit_Symbol o if o.empty? @emitter.scalar "", nil, '!ruby/symbol', false, false, Nodes::Scalar::ANY else @emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY end end def visit_BasicObject o tag = Psych.dump_tags[o.class] tag ||= "!ruby/marshalable:#{o.class.name}" map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) register(o, map) o.marshal_dump.each(&method(:accept)) @emitter.end_mapping end private def binary? string string.encoding == Encoding::ASCII_8BIT && !string.ascii_only? end def visit_array_subclass o tag = "!ruby/array:#{o.class}" ivars = o.instance_variables if ivars.empty? node = @emitter.start_sequence(nil, tag, false, Nodes::Sequence::BLOCK) register o, node o.each { |c| accept c } @emitter.end_sequence else node = @emitter.start_mapping(nil, tag, false, Nodes::Sequence::BLOCK) register o, node # Dump the internal list accept 'internal' @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) o.each { |c| accept c } @emitter.end_sequence # Dump the ivars accept 'ivars' @emitter.start_mapping(nil, nil, true, Nodes::Sequence::BLOCK) ivars.each do |ivar| accept ivar accept o.instance_variable_get ivar end @emitter.end_mapping @emitter.end_mapping end end def visit_hash_subclass o ivars = o.instance_variables if ivars.any? tag = "!ruby/hash-with-ivars:#{o.class}" node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) register(o, node) # Dump the ivars accept 'ivars' @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK o.instance_variables.each do |ivar| accept ivar accept o.instance_variable_get ivar end @emitter.end_mapping # Dump the elements accept 'elements' @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK o.each do |k,v| accept k accept v end @emitter.end_mapping @emitter.end_mapping else tag = "!ruby/hash:#{o.class}" node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) register(o, node) o.each do |k,v| accept k accept v end @emitter.end_mapping end end def dump_list o end def dump_exception o, msg tag = ['!ruby/exception', o.class.name].join ':' @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK if msg @emitter.scalar 'message', nil, nil, true, false, Nodes::Scalar::ANY accept msg end @emitter.scalar 'backtrace', nil, nil, true, false, Nodes::Scalar::ANY accept o.backtrace dump_ivars o @emitter.end_mapping end def format_time time if time.utc? time.strftime("%Y-%m-%d %H:%M:%S.%9N Z") else time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z") end end def register target, yaml_obj @st.register target, yaml_obj yaml_obj end def dump_coder o @coders << o tag = Psych.dump_tags[o.class] unless tag klass = o.class == Object ? nil : o.class.name tag = ['!ruby/object', klass].compact.join(':') end c = Psych::Coder.new(tag) o.encode_with(c) emit_coder c, o end def emit_coder c, o case c.type when :scalar @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, Nodes::Scalar::ANY when :seq @emitter.start_sequence nil, c.tag, c.tag.nil?, Nodes::Sequence::BLOCK c.seq.each do |thing| accept thing end @emitter.end_sequence when :map register o, @emitter.start_mapping(nil, c.tag, c.implicit, c.style) c.map.each do |k,v| accept k accept v end @emitter.end_mapping when :object accept c.object end end def dump_ivars target target.instance_variables.each do |iv| @emitter.scalar("#{iv.to_s.sub(/^@/, '')}", nil, nil, true, false, Nodes::Scalar::ANY) accept target.instance_variable_get(iv) end end end end end PK ]6*4gg.gems/psych-3.1.0/lib/psych/visitors/visitor.rbnu[# frozen_string_literal: true module Psych module Visitors class Visitor def accept target visit target end private DISPATCH = Hash.new do |hash, klass| hash[klass] = "visit_#{klass.name.gsub('::', '_')}" end def visit target send DISPATCH[target.class], target end end end end PK ]Sܶ...gems/psych-3.1.0/lib/psych/visitors/to_ruby.rbnu[# frozen_string_literal: true require 'psych/scalar_scanner' require 'psych/class_loader' require 'psych/exception' unless defined?(Regexp::NOENCODING) Regexp::NOENCODING = 32 end module Psych module Visitors ### # This class walks a YAML AST, converting each node to Ruby class ToRuby < Psych::Visitors::Visitor def self.create class_loader = ClassLoader.new scanner = ScalarScanner.new class_loader new(scanner, class_loader) end attr_reader :class_loader def initialize ss, class_loader super() @st = {} @ss = ss @domain_types = Psych.domain_types @class_loader = class_loader end def accept target result = super return result if @domain_types.empty? || !target.tag key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:') key = "tag:#{key}" unless key =~ /^(?:tag:|x-private)/ if @domain_types.key? key value, block = @domain_types[key] return block.call value, result end result end def deserialize o if klass = resolve_class(Psych.load_tags[o.tag]) instance = klass.allocate if instance.respond_to?(:init_with) coder = Psych::Coder.new(o.tag) coder.scalar = o.value instance.init_with coder end return instance end return o.value if o.quoted return @ss.tokenize(o.value) unless o.tag case o.tag when '!binary', 'tag:yaml.org,2002:binary' o.value.unpack('m').first when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str' klass = resolve_class($1) if klass klass.allocate.replace o.value else o.value end when '!ruby/object:BigDecimal' require 'bigdecimal' unless defined? BigDecimal class_loader.big_decimal._load o.value when "!ruby/object:DateTime" class_loader.date_time require 'date' unless defined? DateTime @ss.parse_time(o.value).to_datetime when '!ruby/encoding' ::Encoding.find o.value when "!ruby/object:Complex" class_loader.complex Complex(o.value) when "!ruby/object:Rational" class_loader.rational Rational(o.value) when "!ruby/class", "!ruby/module" resolve_class o.value when "tag:yaml.org,2002:float", "!float" Float(@ss.tokenize(o.value)) when "!ruby/regexp" klass = class_loader.regexp o.value =~ /^\/(.*)\/([mixn]*)$/m source = $1 options = 0 lang = nil ($2 || '').split('').each do |option| case option when 'x' then options |= Regexp::EXTENDED when 'i' then options |= Regexp::IGNORECASE when 'm' then options |= Regexp::MULTILINE when 'n' then options |= Regexp::NOENCODING else lang = option end end klass.new(*[source, options, lang].compact) when "!ruby/range" klass = class_loader.range args = o.value.split(/([.]{2,3})/, 2).map { |s| accept Nodes::Scalar.new(s) } args.push(args.delete_at(1) == '...') klass.new(*args) when /^!ruby\/sym(bol)?:?(.*)?$/ class_loader.symbolize o.value else @ss.tokenize o.value end end private :deserialize def visit_Psych_Nodes_Scalar o register o, deserialize(o) end def visit_Psych_Nodes_Sequence o if klass = resolve_class(Psych.load_tags[o.tag]) instance = klass.allocate if instance.respond_to?(:init_with) coder = Psych::Coder.new(o.tag) coder.seq = o.children.map { |c| accept c } instance.init_with coder end return instance end case o.tag when nil register_empty(o) when '!omap', 'tag:yaml.org,2002:omap' map = register(o, Psych::Omap.new) o.children.each { |a| map[accept(a.children.first)] = accept a.children.last } map when /^!(?:seq|ruby\/array):(.*)$/ klass = resolve_class($1) list = register(o, klass.allocate) o.children.each { |c| list.push accept c } list else register_empty(o) end end def visit_Psych_Nodes_Mapping o if Psych.load_tags[o.tag] return revive(resolve_class(Psych.load_tags[o.tag]), o) end return revive_hash(register(o, {}), o) unless o.tag case o.tag when /^!ruby\/struct:?(.*)?$/ klass = resolve_class($1) if $1 if klass s = register(o, klass.allocate) members = {} struct_members = s.members.map { |x| class_loader.symbolize x } o.children.each_slice(2) do |k,v| member = accept(k) value = accept(v) if struct_members.include?(class_loader.symbolize(member)) s.send("#{member}=", value) else members[member.to_s.sub(/^@/, '')] = value end end init_with(s, members, o) else klass = class_loader.struct members = o.children.map { |c| accept c } h = Hash[*members] s = klass.new(*h.map { |k,v| class_loader.symbolize k }).new(*h.map { |k,v| v }) register(o, s) s end when /^!ruby\/object:?(.*)?$/ name = $1 || 'Object' if name == 'Complex' class_loader.complex h = Hash[*o.children.map { |c| accept c }] register o, Complex(h['real'], h['image']) elsif name == 'Rational' class_loader.rational h = Hash[*o.children.map { |c| accept c }] register o, Rational(h['numerator'], h['denominator']) elsif name == 'Hash' revive_hash(register(o, {}), o) else obj = revive((resolve_class(name) || class_loader.object), o) obj end when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str' klass = resolve_class($1) members = {} string = nil o.children.each_slice(2) do |k,v| key = accept k value = accept v if key == 'str' if klass string = klass.allocate.replace value else string = value end register(o, string) else members[key] = value end end init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o) when /^!ruby\/array:(.*)$/ klass = resolve_class($1) list = register(o, klass.allocate) members = Hash[o.children.map { |c| accept c }.each_slice(2).to_a] list.replace members['internal'] members['ivars'].each do |ivar, v| list.instance_variable_set ivar, v end list when '!ruby/range' klass = class_loader.range h = Hash[*o.children.map { |c| accept c }] register o, klass.new(h['begin'], h['end'], h['excl']) when /^!ruby\/exception:?(.*)?$/ h = Hash[*o.children.map { |c| accept c }] e = build_exception((resolve_class($1) || class_loader.exception), h.delete('message')) e.set_backtrace h.delete('backtrace') if h.key? 'backtrace' init_with(e, h, o) when '!set', 'tag:yaml.org,2002:set' set = class_loader.psych_set.new @st[o.anchor] = set if o.anchor o.children.each_slice(2) do |k,v| set[accept(k)] = accept(v) end set when /^!ruby\/hash-with-ivars(?::(.*))?$/ hash = $1 ? resolve_class($1).allocate : {} register o, hash o.children.each_slice(2) do |key, value| case key.value when 'elements' revive_hash hash, value when 'ivars' value.children.each_slice(2) do |k,v| hash.instance_variable_set accept(k), accept(v) end end end hash when /^!map:(.*)$/, /^!ruby\/hash:(.*)$/ revive_hash register(o, resolve_class($1).allocate), o when '!omap', 'tag:yaml.org,2002:omap' map = register(o, class_loader.psych_omap.new) o.children.each_slice(2) do |l,r| map[accept(l)] = accept r end map when /^!ruby\/marshalable:(.*)$/ name = $1 klass = resolve_class(name) obj = register(o, klass.allocate) if obj.respond_to?(:init_with) init_with(obj, revive_hash({}, o), o) elsif obj.respond_to?(:marshal_load) marshal_data = o.children.map(&method(:accept)) obj.marshal_load(marshal_data) obj else raise ArgumentError, "Cannot deserialize #{name}" end else revive_hash(register(o, {}), o) end end def visit_Psych_Nodes_Document o accept o.root end def visit_Psych_Nodes_Stream o o.children.map { |c| accept c } end def visit_Psych_Nodes_Alias o @st.fetch(o.anchor) { raise BadAlias, "Unknown alias: #{o.anchor}" } end private def register node, object @st[node.anchor] = object if node.anchor object end def register_empty object list = register(object, []) object.children.each { |c| list.push accept c } list end SHOVEL = '<<' def revive_hash hash, o o.children.each_slice(2) { |k,v| key = deduplicate(accept(k)) val = accept(v) if key == SHOVEL && k.tag != "tag:yaml.org,2002:str" case v when Nodes::Alias, Nodes::Mapping begin hash.merge! val rescue TypeError hash[key] = val end when Nodes::Sequence begin h = {} val.reverse_each do |value| h.merge! value end hash.merge! h rescue TypeError hash[key] = val end else hash[key] = val end else hash[key] = val end } hash end if RUBY_VERSION < '2.7' def deduplicate key if key.is_a?(String) -(key.untaint) else key end end else def deduplicate key if key.is_a?(String) -key else key end end end def merge_key hash, key, val end def revive klass, node s = register(node, klass.allocate) init_with(s, revive_hash({}, node), node) end def init_with o, h, node c = Psych::Coder.new(node.tag) c.map = h if o.respond_to?(:init_with) o.init_with c else h.each { |k,v| o.instance_variable_set(:"@#{k}", v) } end o end # Convert +klassname+ to a Class def resolve_class klassname class_loader.load klassname end end class NoAliasRuby < ToRuby def visit_Psych_Nodes_Alias o raise BadAlias, "Unknown alias: #{o.anchor}" end end end end PK ]Z.gems/psych-3.1.0/lib/psych/visitors/emitter.rbnu[# frozen_string_literal: true module Psych module Visitors class Emitter < Psych::Visitors::Visitor def initialize io, options = {} opts = [:indentation, :canonical, :line_width].find_all { |opt| options.key?(opt) } if opts.empty? @handler = Psych::Emitter.new io else du = Handler::DumperOptions.new opts.each { |option| du.send :"#{option}=", options[option] } @handler = Psych::Emitter.new io, du end end def visit_Psych_Nodes_Stream o @handler.start_stream o.encoding o.children.each { |c| accept c } @handler.end_stream end def visit_Psych_Nodes_Document o @handler.start_document o.version, o.tag_directives, o.implicit o.children.each { |c| accept c } @handler.end_document o.implicit_end end def visit_Psych_Nodes_Scalar o @handler.scalar o.value, o.anchor, o.tag, o.plain, o.quoted, o.style end def visit_Psych_Nodes_Sequence o @handler.start_sequence o.anchor, o.tag, o.implicit, o.style o.children.each { |c| accept c } @handler.end_sequence end def visit_Psych_Nodes_Mapping o @handler.start_mapping o.anchor, o.tag, o.implicit, o.style o.children.each { |c| accept c } @handler.end_mapping end def visit_Psych_Nodes_Alias o @handler.alias o.anchor end end end end PK ]fk k #gems/psych-3.1.0/lib/psych/nodes.rbnu[# frozen_string_literal: true require 'psych/nodes/node' require 'psych/nodes/stream' require 'psych/nodes/document' require 'psych/nodes/sequence' require 'psych/nodes/scalar' require 'psych/nodes/mapping' require 'psych/nodes/alias' module Psych ### # = Overview # # When using Psych.load to deserialize a YAML document, the document is # translated to an intermediary AST. That intermediary AST is then # translated in to a Ruby object graph. # # In the opposite direction, when using Psych.dump, the Ruby object graph is # translated to an intermediary AST which is then converted to a YAML # document. # # Psych::Nodes contains all of the classes that make up the nodes of a YAML # AST. You can manually build an AST and use one of the visitors (see # Psych::Visitors) to convert that AST to either a YAML document or to a # Ruby object graph. # # Here is an example of building an AST that represents a list with one # scalar: # # # Create our nodes # stream = Psych::Nodes::Stream.new # doc = Psych::Nodes::Document.new # seq = Psych::Nodes::Sequence.new # scalar = Psych::Nodes::Scalar.new('foo') # # # Build up our tree # stream.children << doc # doc.children << seq # seq.children << scalar # # The stream is the root of the tree. We can then convert the tree to YAML: # # stream.to_yaml => "---\n- foo\n" # # Or convert it to Ruby: # # stream.to_ruby => [["foo"]] # # == YAML AST Requirements # # A valid YAML AST *must* have one Psych::Nodes::Stream at the root. A # Psych::Nodes::Stream node must have 1 or more Psych::Nodes::Document nodes # as children. # # Psych::Nodes::Document nodes must have one and *only* one child. That child # may be one of: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar # # Psych::Nodes::Sequence and Psych::Nodes::Mapping nodes may have many # children, but Psych::Nodes::Mapping nodes should have an even number of # children. # # All of these are valid children for Psych::Nodes::Sequence and # Psych::Nodes::Mapping nodes: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar # * Psych::Nodes::Alias # # Psych::Nodes::Scalar and Psych::Nodes::Alias are both terminal nodes and # should not have any children. module Nodes end end PK ]'Kgems/psych-3.1.0/lib/psych/y.rbnu[# frozen_string_literal: true module Kernel ### # An alias for Psych.dump_stream meant to be used with IRB. def y *objects puts Psych.dump_stream(*objects) end private :y end PK ]%&gems/psych-3.1.0/lib/psych/versions.rbnu[ # frozen_string_literal: true module Psych # The version of Psych you are using VERSION = '3.1.0' unless defined?(::Psych::VERSION) if RUBY_ENGINE == 'jruby' DEFAULT_SNAKEYAML_VERSION = '1.23'.freeze end end PK ]r$gems/psych-3.1.0/lib/psych/stream.rbnu[# frozen_string_literal: true module Psych ### # Psych::Stream is a streaming YAML emitter. It will not buffer your YAML, # but send it straight to an IO. # # Here is an example use: # # stream = Psych::Stream.new($stdout) # stream.start # stream.push({:foo => 'bar'}) # stream.finish # # YAML will be immediately emitted to $stdout with no buffering. # # Psych::Stream#start will take a block and ensure that Psych::Stream#finish # is called, so you can do this form: # # stream = Psych::Stream.new($stdout) # stream.start do |em| # em.push(:foo => 'bar') # end # class Stream < Psych::Visitors::YAMLTree class Emitter < Psych::Emitter # :nodoc: def end_document implicit_end = !streaming? super end def streaming? true end end include Psych::Streaming extend Psych::Streaming::ClassMethods end end PK ]&3*II*gems/psych-3.1.0/lib/psych/syntax_error.rbnu[# frozen_string_literal: true require 'psych/exception' module Psych class SyntaxError < Psych::Exception attr_reader :file, :line, :column, :offset, :problem, :context def initialize file, line, col, offset, problem, context err = [problem, context].compact.join ' ' filename = file || '' message = "(%s): %s at line %d column %d" % [filename, err, line, col] @file = file @line = line @column = col @offset = offset @problem = problem @context = context super(message) end end end PK ]y2K'gems/psych-3.1.0/lib/psych/streaming.rbnu[# frozen_string_literal: true module Psych module Streaming module ClassMethods ### # Create a new streaming emitter. Emitter will print to +io+. See # Psych::Stream for an example. def new io emitter = const_get(:Emitter).new(io) class_loader = ClassLoader.new ss = ScalarScanner.new class_loader super(emitter, ss, {}) end end ### # Start streaming using +encoding+ def start encoding = Nodes::Stream::UTF8 super.tap { yield self if block_given? } ensure finish if block_given? end private def register target, obj end end end PK ]ӻ&gems/psych-3.1.0/lib/psych/visitors.rbnu[# frozen_string_literal: true require 'psych/visitors/visitor' require 'psych/visitors/to_ruby' require 'psych/visitors/emitter' require 'psych/visitors/yaml_tree' require 'psych/visitors/json_tree' require 'psych/visitors/depth_first' PK ]oe *gems/psych-3.1.0/lib/psych/class_loader.rbnu[# frozen_string_literal: true require 'psych/omap' require 'psych/set' module Psych class ClassLoader # :nodoc: BIG_DECIMAL = 'BigDecimal' COMPLEX = 'Complex' DATE = 'Date' DATE_TIME = 'DateTime' EXCEPTION = 'Exception' OBJECT = 'Object' PSYCH_OMAP = 'Psych::Omap' PSYCH_SET = 'Psych::Set' RANGE = 'Range' RATIONAL = 'Rational' REGEXP = 'Regexp' STRUCT = 'Struct' SYMBOL = 'Symbol' def initialize @cache = CACHE.dup end def load klassname return nil if !klassname || klassname.empty? find klassname end def symbolize sym symbol sym.to_sym end constants.each do |const| konst = const_get const define_method(const.to_s.downcase) do load konst end end private def find klassname @cache[klassname] ||= resolve(klassname) end def resolve klassname name = klassname retried = false begin path2class(name) rescue ArgumentError, NameError => ex unless retried name = "Struct::#{name}" retried = ex retry end raise retried end end CACHE = Hash[constants.map { |const| val = const_get const begin [val, ::Object.const_get(val)] rescue nil end }.compact] class Restricted < ClassLoader def initialize classes, symbols @classes = classes @symbols = symbols super() end def symbolize sym return super if @symbols.empty? if @symbols.include? sym super else raise DisallowedClass, 'Symbol' end end private def find klassname if @classes.include? klassname super else raise DisallowedClass, klassname end end end end end PK ]|uu/gems/psych-3.1.0/lib/psych/handlers/recorder.rbnu[# frozen_string_literal: true require 'psych/handler' module Psych module Handlers ### # This handler will capture an event and record the event. Recorder events # are available vial Psych::Handlers::Recorder#events. # # For example: # # recorder = Psych::Handlers::Recorder.new # parser = Psych::Parser.new recorder # parser.parse '--- foo' # # recorder.events # => [list of events] # # # Replay the events # # emitter = Psych::Emitter.new $stdout # recorder.events.each do |m, args| # emitter.send m, *args # end class Recorder < Psych::Handler attr_reader :events def initialize @events = [] super end EVENTS.each do |event| define_method event do |*args| @events << [event, args] end end end end end PK ]}6gems/psych-3.1.0/lib/psych/handlers/document_stream.rbnu[# frozen_string_literal: true require 'psych/tree_builder' module Psych module Handlers class DocumentStream < Psych::TreeBuilder # :nodoc: def initialize &block super @block = block end def start_document version, tag_directives, implicit n = Nodes::Document.new version, tag_directives, implicit push n end def end_document implicit_end = !streaming? @last.implicit_end = implicit_end @block.call pop end end end end PK ](Cee/gems/psych-3.1.0/lib/psych/json/tree_builder.rbnu[# frozen_string_literal: true require 'psych/json/yaml_events' module Psych module JSON ### # Psych::JSON::TreeBuilder is an event based AST builder. Events are sent # to an instance of Psych::JSON::TreeBuilder and a JSON AST is constructed. class TreeBuilder < Psych::TreeBuilder include Psych::JSON::YAMLEvents end end end PK ]  .gems/psych-3.1.0/lib/psych/json/yaml_events.rbnu[# frozen_string_literal: true module Psych module JSON module YAMLEvents # :nodoc: def start_document version, tag_directives, implicit super(version, tag_directives, !streaming?) end def end_document implicit_end = !streaming? super(implicit_end) end def start_mapping anchor, tag, implicit, style super(anchor, nil, true, Nodes::Mapping::FLOW) end def start_sequence anchor, tag, implicit, style super(anchor, nil, true, Nodes::Sequence::FLOW) end def scalar value, anchor, tag, plain, quoted, style if "tag:yaml.org,2002:null" == tag super('null', nil, nil, true, false, Nodes::Scalar::PLAIN) else super end end end end end PK ] Ej)gems/psych-3.1.0/lib/psych/json/stream.rbnu[# frozen_string_literal: true require 'psych/json/ruby_events' require 'psych/json/yaml_events' module Psych module JSON class Stream < Psych::Visitors::JSONTree include Psych::JSON::RubyEvents include Psych::Streaming extend Psych::Streaming::ClassMethods class Emitter < Psych::Stream::Emitter # :nodoc: include Psych::JSON::YAMLEvents end end end end PK ].gems/psych-3.1.0/lib/psych/json/ruby_events.rbnu[# frozen_string_literal: true module Psych module JSON module RubyEvents # :nodoc: def visit_Time o formatted = format_time o @emitter.scalar formatted, nil, nil, false, true, Nodes::Scalar::DOUBLE_QUOTED end def visit_DateTime o visit_Time o.to_time end def visit_String o @emitter.scalar o.to_s, nil, nil, false, true, Nodes::Scalar::DOUBLE_QUOTED end alias :visit_Symbol :visit_String end end end PK ]u>22#gems/psych-3.1.0/lib/psych/coder.rbnu[# frozen_string_literal: true module Psych ### # If an object defines +encode_with+, then an instance of Psych::Coder will # be passed to the method when the object is being serialized. The Coder # automatically assumes a Psych::Nodes::Mapping is being emitted. Other # objects like Sequence and Scalar may be emitted if +seq=+ or +scalar=+ are # called, respectively. class Coder attr_accessor :tag, :style, :implicit, :object attr_reader :type, :seq def initialize tag @map = {} @seq = [] @implicit = false @type = :map @tag = tag @style = Psych::Nodes::Mapping::BLOCK @scalar = nil @object = nil end def scalar *args if args.length > 0 warn "#{caller[0]}: Coder#scalar(a,b,c) is deprecated" if $VERBOSE @tag, @scalar, _ = args @type = :scalar end @scalar end # Emit a map. The coder will be yielded to the block. def map tag = @tag, style = @style @tag = tag @style = style yield self if block_given? @map end # Emit a scalar with +value+ and +tag+ def represent_scalar tag, value self.tag = tag self.scalar = value end # Emit a sequence with +list+ and +tag+ def represent_seq tag, list @tag = tag self.seq = list end # Emit a sequence with +map+ and +tag+ def represent_map tag, map @tag = tag self.map = map end # Emit an arbitrary object +obj+ and +tag+ def represent_object tag, obj @tag = tag @type = :object @object = obj end # Emit a scalar with +value+ def scalar= value @type = :scalar @scalar = value end # Emit a map with +value+ def map= map @type = :map @map = map end def []= k, v @type = :map @map[k] = v end alias :add :[]= def [] k @type = :map @map[k] end # Emit a sequence of +list+ def seq= list @type = :seq @seq = list end end end PK ]"+  (gems/psych-3.1.0/lib/psych/nodes/node.rbnu[# frozen_string_literal: true require 'stringio' require 'psych/class_loader' require 'psych/scalar_scanner' module Psych module Nodes ### # The base class for any Node in a YAML parse tree. This class should # never be instantiated. class Node include Enumerable # The children of this node attr_reader :children # An associated tag attr_reader :tag # The line number where this node start attr_accessor :start_line # The column number where this node start attr_accessor :start_column # The line number where this node ends attr_accessor :end_line # The column number where this node ends attr_accessor :end_column # Create a new Psych::Nodes::Node def initialize @children = [] end ### # Iterate over each node in the tree. Yields each node to +block+ depth # first. def each &block return enum_for :each unless block_given? Visitors::DepthFirst.new(block).accept self end ### # Convert this node to Ruby. # # See also Psych::Visitors::ToRuby def to_ruby Visitors::ToRuby.create.accept(self) end alias :transform :to_ruby ### # Convert this node to YAML. # # See also Psych::Visitors::Emitter def yaml io = nil, options = {} real_io = io || StringIO.new(''.encode('utf-8')) Visitors::Emitter.new(real_io, options).accept self return real_io.string unless io io end alias :to_yaml :yaml def alias?; false; end def document?; false; end def mapping?; false; end def scalar?; false; end def sequence?; false; end def stream?; false; end end end end PK ]믍!!,gems/psych-3.1.0/lib/psych/nodes/sequence.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This class represents a # {YAML sequence}[http://yaml.org/spec/1.1/#sequence/syntax]. # # A YAML sequence is basically a list, and looks like this: # # %YAML 1.1 # --- # - I am # - a Sequence # # A YAML sequence may have an anchor like this: # # %YAML 1.1 # --- # &A [ # "This sequence", # "has an anchor" # ] # # A YAML sequence may also have a tag like this: # # %YAML 1.1 # --- # !!seq [ # "This sequence", # "has a tag" # ] # # This class represents a sequence in a YAML document. A # Psych::Nodes::Sequence node may have 0 or more children. Valid children # for this node are: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar # * Psych::Nodes::Alias class Sequence < Psych::Nodes::Node # Any Styles, emitter chooses ANY = 0 # Block style sequence BLOCK = 1 # Flow style sequence FLOW = 2 # The anchor for this sequence (if any) attr_accessor :anchor # The tag name for this sequence (if any) attr_accessor :tag # Is this sequence started implicitly? attr_accessor :implicit # The sequence style used attr_accessor :style ### # Create a new object representing a YAML sequence. # # +anchor+ is the anchor associated with the sequence or nil. # +tag+ is the tag associated with the sequence or nil. # +implicit+ a boolean indicating whether or not the sequence was # implicitly started. # +style+ is an integer indicating the list style. # # See Psych::Handler#start_sequence def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK super() @anchor = anchor @tag = tag @implicit = implicit @style = style end def sequence?; true; end end end end PK ]ɉ  )gems/psych-3.1.0/lib/psych/nodes/alias.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This class represents a {YAML Alias}[http://yaml.org/spec/1.1/#alias]. # It points to an +anchor+. # # A Psych::Nodes::Alias is a terminal node and may have no children. class Alias < Psych::Nodes::Node # The anchor this alias links to attr_accessor :anchor # Create a new Alias that points to an +anchor+ def initialize anchor @anchor = anchor end def alias?; true; end end end end PK ])))+gems/psych-3.1.0/lib/psych/nodes/mapping.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This class represents a {YAML Mapping}[http://yaml.org/spec/1.1/#mapping]. # # A Psych::Nodes::Mapping node may have 0 or more children, but must have # an even number of children. Here are the valid children a # Psych::Nodes::Mapping node may have: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar # * Psych::Nodes::Alias class Mapping < Psych::Nodes::Node # Any Map Style ANY = 0 # Block Map Style BLOCK = 1 # Flow Map Style FLOW = 2 # The optional anchor for this mapping attr_accessor :anchor # The optional tag for this mapping attr_accessor :tag # Is this an implicit mapping? attr_accessor :implicit # The style of this mapping attr_accessor :style ### # Create a new Psych::Nodes::Mapping object. # # +anchor+ is the anchor associated with the map or +nil+. # +tag+ is the tag associated with the map or +nil+. # +implicit+ is a boolean indicating whether or not the map was implicitly # started. # +style+ is an integer indicating the mapping style. # # == See Also # See also Psych::Handler#start_mapping def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK super() @anchor = anchor @tag = tag @implicit = implicit @style = style end def mapping?; true; end end end end PK ]Ϧ[*gems/psych-3.1.0/lib/psych/nodes/stream.rbnu[# frozen_string_literal: true module Psych module Nodes ### # Represents a YAML stream. This is the root node for any YAML parse # tree. This node must have one or more child nodes. The only valid # child node for a Psych::Nodes::Stream node is Psych::Nodes::Document. class Stream < Psych::Nodes::Node # Encodings supported by Psych (and libyaml) # Any encoding ANY = Psych::Parser::ANY # UTF-8 encoding UTF8 = Psych::Parser::UTF8 # UTF-16LE encoding UTF16LE = Psych::Parser::UTF16LE # UTF-16BE encoding UTF16BE = Psych::Parser::UTF16BE # The encoding used for this stream attr_accessor :encoding ### # Create a new Psych::Nodes::Stream node with an +encoding+ that # defaults to Psych::Nodes::Stream::UTF8. # # See also Psych::Handler#start_stream def initialize encoding = UTF8 super() @encoding = encoding end def stream?; true; end end end end PK ](%*gems/psych-3.1.0/lib/psych/nodes/scalar.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This class represents a {YAML Scalar}[http://yaml.org/spec/1.1/#id858081]. # # This node type is a terminal node and should not have any children. class Scalar < Psych::Nodes::Node # Any style scalar, the emitter chooses ANY = 0 # Plain scalar style PLAIN = 1 # Single quoted style SINGLE_QUOTED = 2 # Double quoted style DOUBLE_QUOTED = 3 # Literal style LITERAL = 4 # Folded style FOLDED = 5 # The scalar value attr_accessor :value # The anchor value (if there is one) attr_accessor :anchor # The tag value (if there is one) attr_accessor :tag # Is this a plain scalar? attr_accessor :plain # Is this scalar quoted? attr_accessor :quoted # The style of this scalar attr_accessor :style ### # Create a new Psych::Nodes::Scalar object. # # +value+ is the string value of the scalar # +anchor+ is an associated anchor or nil # +tag+ is an associated tag or nil # +plain+ is a boolean value # +quoted+ is a boolean value # +style+ is an integer idicating the string style # # == See Also # # See also Psych::Handler#scalar def initialize value, anchor = nil, tag = nil, plain = true, quoted = false, style = ANY @value = value @anchor = anchor @tag = tag @plain = plain @quoted = quoted @style = style end def scalar?; true; end end end end PK ]AA,gems/psych-3.1.0/lib/psych/nodes/document.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This represents a YAML Document. This node must be a child of # Psych::Nodes::Stream. A Psych::Nodes::Document must have one child, # and that child may be one of the following: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar class Document < Psych::Nodes::Node # The version of the YAML document attr_accessor :version # A list of tag directives for this document attr_accessor :tag_directives # Was this document implicitly created? attr_accessor :implicit # Is the end of the document implicit? attr_accessor :implicit_end ### # Create a new Psych::Nodes::Document object. # # +version+ is a list indicating the YAML version. # +tags_directives+ is a list of tag directive declarations # +implicit+ is a flag indicating whether the document will be implicitly # started. # # == Example: # This creates a YAML document object that represents a YAML 1.1 document # with one tag directive, and has an implicit start: # # Psych::Nodes::Document.new( # [1,1], # [["!", "tag:tenderlovemaking.com,2009:"]], # true # ) # # == See Also # See also Psych::Handler#start_document def initialize version = [], tag_directives = [], implicit = false super() @version = version @tag_directives = tag_directives @implicit = implicit @implicit_end = true end ### # Returns the root node. A Document may only have one root node: # http://yaml.org/spec/1.1/#id898031 def root children.first end def document?; true; end end end end PK ]Rzgg&gems/psych-3.1.0/lib/psych/core_ext.rbnu[# frozen_string_literal: true class Object def self.yaml_tag url Psych.add_tag(url, self) end ### # call-seq: to_yaml(options = {}) # # Convert an object to YAML. See Psych.dump for more information on the # available +options+. def to_yaml options = {} Psych.dump self, options end end if defined?(::IRB) require 'psych/y' end PK ]I>>cache/rackup-2.1.0.gemnu[metadata.gz0000444000000000000000000000127114364637605013455 0ustar00wheelwheel00000000000000?cW]o0}0{S> ,1 @eC Pt&fclB۹ڮe+K+%>>>(拤?a BY,Ldc;([1ӣ(DGK K|kM R(+ {!|C}`_O(P5Bw'k"8GرeȀ>*GSRM* ZBd{ߍ#o4^+sK􅓶.m\ ;qoMWJ dll&mC^ĕ _gc*ګ+<)*ӲqUNFvRC[(/H&uIPٓNEՍF 9z$ uEQFzM_|4<4>RFY?%M?ä,o/2]snٴUn[;gD=| ;Ŷ 2T9.U1?t'Nɑ{&jlǬ[3^t~data.tar.gz0000444000000000000000000002611414364637605013376 0ustar00wheelwheel00000000000000?c}v7`.2!Pԇ/6%mIԐGM;jv9߾9o>}$[UqL4K(P*Tlwͷ⛯oOƃo6?zxu۸7l?' BT.g;T?ʽ(F {h,}0}=:v}iЏxl}X}YXs\GR~7}_pK#y[YāG_nmo=zy_+n|"w}8; ؁=n-}6 ls}ss_g%[;85ҥ廬 VKcPDBҧGH+7NKMu͚Ts%NJwaFOÇ[wܒ/Vpe/:Wwo*RGw,wB݅P؞[K>yf])g9Z[aKM<=w27jvN4S l#v_uZ1TD,sfIl(bȭΗbQ{ k~yD尙̠8[X+r4=6>| [f%meLa>_ș,1zPl@ )L"h#H@aCyO+@2&]I7,bb\ijkrvHx mwK( 3VuM-' GT8<7 sU O* :9%Jnlvwcӝ|_@8Jھqk+sz>ohGW4F0k:7ɞE* /#$ Y⛴P$Il/0&DϚDm Uc1@f:;h`C=N$o*~}]]Ds 'I ֘TcᓰҚܐ56wAނ~2²k$Efg ǖ[ˏ̋,eJ; 1&Gh׋Pld5d=ƞѓ Rg2 2ٔ\RU7$Ԭ4`d[xKl̵eMUK~Жc:Ͳk°Hl"gVpD>d+1nv(Ê0hd>@ѻs)' GsmK: &&rPAǐD *+l[nj3&YX1)MsmPp v8B]6.G6jRN9E! ~3m煂 n;'\@3Ō/=~UW_X~R2Y^)vGz9'vO&O1V.`F7,Yk;itZ}f_/ Vyc]cRUƒ^  RM6/sm ADV+% e?y_oz{_˱yR@Mc҆\.*`mVg/L ѿ ‰6F 0ݠf i;P`p< GA`\!O+4Eeک%PfVmD lUM=stvހ㮧ڽ^7ga[<uF!yurƞ, A5_Ɏ^3I׷އaBK ` [} 6q Fh @# mԮPVM7 ރI*.<zYʮW uVMf.l/ `OQinBPY]hͰgEEE2Tp:LӕWE7ƮJٿR*pD1W[ F+ꈛ=ciNsvFO·t<Ӽ,:/,Ǟ %v ޠU~fʨ{#Ԅspu粪ZYWg˸.=>5 G}u"2B<@ڋi67ih})!_ݨڮ0<, Z@c)^ЉycP(ڕBg϶-EH$ĐZ %}#tη%—Hxh'Y䞛 -ӪP3 OFTH"ϸ)ΌJ`l%u={(i.&`hi ^H6n.5=VN|&6oyh /,?1mҌ.0JۜhnEIBdH071AbP["0iPfR`Pօuk A^dj҃ãIzGᷰYr *F%z3YGY83"CĭoY2OI+"tݟҩͧ/nw +!@XiGx.;81fZL!dloXĂJT(yvO-"kܮvnm숕JX x:sWNc+ '"TfqΗuX tZ䇸SR X xiw())Ƃ/6zϫd4*b ف/=t Z1_)NET9D !XeO` j~l0**o@TCyk ~:YhYWBo9tQBˢřVNMABjwGO:q,o>PYR2.;T3$̽*(7vs,WԖMy XCV <2pE)" &>CZx4}vEB}(5@TT+0 NeWgIdŸ}{9n_|qwfOnq' 2}-dv%/؂Ōq`{BŁXJʆ/JGY*'ȵfNؔA{2v{lt_'b3Ӱԅhh_FVMGpAR+_b-jP_ˮD`Г׭l6Cȱo"J?*ͽ:oc|O,yh _zv A*+Wnͩ]-I4ڷ8QA{8rMֽnUͼ! PCk /8a&,b;nW@+#6#juGMd 5cTw7o>JN"\X>+B 2v(潏ͅswvWHP(Ҍh3P3߅|@AY /U~]A\-#2&0L[O^\Ԑ9SW\^ a1=-7B1\( 3dB|=G4GN˥t̬MBu4ZAtutU'rA稍!B؛r-̓.l=>hk w:G{``؃@¨%D쪔D`9 x -O3Vŗw޾k 5D5|xRK )+]=@9.gطaqXֽxqtʐnJn?uDGGNtKAGn#V[K0{t0 ?3sTcDetZS reIˣY6\c9Z:̧=#rg&>Eekѿ-kYΥH@n lm`^l<%85yהKcz [V gWT\QA2Q%O B:ZI ahYExF*b!X`#ÿQWE]m 7w] 'ZoۧX׵=K` Ju$A& *`e`}~V5 B'p e\4^[ttJ6X\g{S)>"%gLq퀖c媆;ܟͥZȬrq>:"0S*}(e<ª5D` {Iz+[ƄN!(G[K)ʚ ?VE=DdX E?R$[esT7kbUsUE2[eɸΒ9V1DM匯\ U=u7 E+ӭg*@"V 7rE߮Pr؏\ 잎.=ߙTN48u?%J'Kj/#B?&ur6Z"C1$̄b ҕ%sBxZaC賦bVIq F3H[jS_lUjQBx@n:3}u"3;3-,om z..зqjp 撒$6y0uHK5aA!ŵ{EMR8MA:k0$=VhljX8[uibp:UA aqlIٶp"ȴ?vv֖Z_o14iZS@:SkK@yF*p搓gO[+ix!} c@V֪* <d/6Afk\:t GC!^ѩJP^ڨToW/mDd"ݓ<*qm6Z-?z">.Jlu!gBBs] kxv1v GIְvP5yQ-i|F-4Ed& ={PʹiZj : `Zd;H 2X?SJ1ȋt*Pѵ~ITpUje}4Ѥ{Οԛի*,jc0~8Wɽ\$<53Nu_?]oλ Z ]O$QI;Mɤ,MXk5Y9=CB/-P<κ  @OkeMhq"Tu 1quuk{ آV&ҦsrᄚiXM׷մ$hGaZKk0^ _NŞͭLxcdɘ9PSQc=[} enOAX+a*9֞$#ȟu9̕D^J*3k-%a%(!h+(Q8Zc]* f4~*d3Zr +5ܛHt-beHE,2^h ^-|b^F(0J CrQ+1V2SLD܊R녶T&Ƴ CcaUNz7^1N۳DDY CR7yAK:#R`T.@ >6UjZ,6"u' PFnUt~LraJONUD@n?UYsb_3ClhUQﮐgٌ:K7[--sL_8anMa @3L&AG1PO|ў_6 5dK5jia,y14RBBr^ ?:W)5n55 yd8!+9dnn5gؓH 3͌r ÑB kݻyI+ԧQL/lAJ5{|AΣ閠֖P3gCt%0 B]*%iQ L#֌D^a{ >*FB9ka\!b+tp_aؼ4y=m8ՋGnN(KhddZ>Օ9=r)a>t kfMؓ\Nխa&Uŧok" .JW *cDrzq}dGKЉ"4sfu(Lw^CҖ^IW̠W }.j[%~n{=u>;^[YZ*뻦Q\n+xw>|85QHHs]hӓ*Е<{nB$*gA X)HS$>6[/e&[#f@jE)`Sɭ~gpL4ĆҽQnt!ʋ8_մD` w3x'ОZ$:U 6٠`Pe[ Sc0Bޣ[zGh t@>:;(f5VY}OΤq[#۵%3x8AQG`Fv8ԖTUPr8Q/^LP.mCyK2 jk9_U槉Zy* *+R<:m0g<G8CL!I??*E*ԛ3bd'a`':9b &8"H_6Zd%}gثU-2S6 ~ A2Ŧɖ|=S: k(ꋿe+nKFgЁ%7XX$\ 'uDܛ1/U(ƥL\jq1 ԛƺrŕ.g9(s`F4I;`>y& =&- 1iFߠ;Z08(zXƑ +kw_JI 9˾ad?&Hv!vSIUż*J~ZֿsrNE$,zqV1Q#p#^N/lW>7.Dko*dYtU@ԔdbkI+RiT%54J\[uqSKFxSGJPJ0Y9S0tkeW<wDpBT,u}/ WϋµT73l.ݩO{vo\`R^C|h\5ii% a恧0I=),NW٠T_eƶ/qЊs|]iM"n}'3^'&aЯmЬ}&Nnr1A".d-Y4{0䵹%ƒsw 5p$D<>YOW9}/אD2N+E<T)W12M' q쒆+qt(K,5 ʫDH2SZfH{ I)}g6"#64raEx3wbSͽ-s97뛛[-(;]t0fc^8yO^7ͭ)Gͥ돀ן/pkƎxtnw`ءW[}[Ÿm,t)@ƺhY.۱B]gg_qƣX;"^0,vy>&{cl u r#>z9`8֚ y`e{{HlAW"Y~v" <,uP  X̑ Hl1ޙB1Or3D'2Š<Ä~ [+HMKq72$ IY/kkurJ2*8H#VՇ .{ 7= (Auu*ӰDӬ&66=0#Qxfhէ-؀75N`@/ $h(ID7/gJSl Q%]S6\!hJe  *PdVeQ0KU!8!KO%-_Pj`g۬}9xYu{swݷdMh?>JNuvbo5w@wF]ʦ:>6vcks|^vGnq7=hq߆٣KR6Wx0jup]ZovzWL}Z;m j9aUju^ v~_a-owf9 ?ӃGLyUw:k+=PK@hI͌|~o vcen|<]&ol}a\8L'6(>1*l_$ZUqsDɽ$7- JnP}M|OEcv`m;ȚFpqVEn\=˗VVXmD!`?oSn?,:Rf0a}r}odF҅yϜ4қJ:|\cX˅MHBߤyH>6i@*^+]oNWeC!+Jo16aP\Ĉ@X#̀P*͗.\pk}lh*T(YҚL@e V߂Q0Sچ <%!yLqԪ(OǑ_q6 ߗ+{ `n Nk72:)ZC checksums.yaml.gz0000444000000000000000000000045014364637605014621 0ustar00wheelwheel00000000000000?ce=V@"o[ZRyz7)cfn e^ׯNJ{|^c$A+42a0hn)rmV{|?y3=}kMG^ThLFW]f)|"DeYK ljZu-iPGdu3q/jRF3m.4цaBZoN+9p-^r.qTm2KuBYN35GS?`R὎[I[@8As*u_~ PK ]"cache/rack-3.0.8.gemnu[metadata.gz0000444000000000000000000000230414442217575013450 0ustar00wheelwheel00000000000000}dX[OF~%-!meQ Y$B>=ݹsaYo,]9gfss>1b7(]v 2ˮ(q"E%dr݂(&ԩ"B6F/Y]HDԻZE19Z KnTPi{n 7Q eM9n˯_ijo⯏l?1h@1P%17kDy)CADrS^=x Yڄdn -5 U *,<=߂`XǕ9aٹW#4ƾ 0߆%|Gf`K @+AYrT6IyA hh!p,h =VP4qmK5YTy{ssMʶ CXZ\6 ȊIxx3[Dž˳M,A janV,9zVgHnȗ:.p^`UpZch,HaHL"`nO"ҷl;*`hhn. y7O$'o/NO7Wg9h%5OM|~v2$~HIL) "EKk6}Vl jy9`ڱӤܣUZGP̽c0l㥸[ 6 CImIGY{6j)]U}4ҳpwppWB(kTп* #dh38:D-a 'hhVe"+9Q OYt^lJ.GAOTzPXn<@noH|" 1]05r #y{|*(;a`o*\5~+7NE0ᜭ ip гSZAΏ45{ل30荐 qF GrZBC+$ sҴE6$T0#GX8 U:L ߿SʭD2|S&EM8T5t=iGF:j]93Z{SB^jO#8, ֪kC̢v.l`a,=kȾksar̶AT $m "6~Y^)$<Yd(^Jj98cLbSp_u:(data.tar.gz0000444000000000000000000031257414442217575013403 0ustar00wheelwheel00000000000000}dvٕ6QT-2ML)DIY_"@$GHAUV?{ܫ=Iz7'%]]UL"7^nO+t#t[[{{~gkoAyfqMiQp4Q4IGd$i&QHb,KEpS^ |%E4D I^2L4 4,z=w Qy'l>lF3hEt& ҢvG;nO{;?i<.%x(Â8y-u8Ωu=9:]^a2o~}O" wE.g`شk]E43ky5<5nP|[mt>'I9t>)bZqq][\N)mVo`[Eb־?vkwwo?'INk3ERߝ:\/IEuoQD?쥾۟t{r{۠䲸7'I,9.o+ U7Mx<{N"˜}eiF~DE؁PGϳppBKMo,D&R< G!`^:N[|:)AlWVL<G룳wWﮮ~m`ǟfo#Bq[Zp< D@x *s`*M_=tfOԧ^6=>|x#D8}κ<'pLҤ5fYAWtHMQyN;9JЎ}_ݨ_g~yy<\'q`7=lQ$DODG{XuDX2!rk_E>&w< s,ƄZ(b^:іwx4;+19!g՝Wo$MoЛMs~ۮB$ 3+:*>dlӌ`hF=π0]&AHCfЍ}bXYXW.z϶v϶Vbbyʻpc^v*5ݕRv)gZو5!t8-<`{qI `WA)1z]4ml^ E[;{]Ԯo\Wf3:-ք?0KDIo%IR D#9WC:t ķ@Š.4OdZƸEכh3iNQJj^o߱uC({iIvO͘T)1fA 5Ƹ>(͉SX`# %dؠL~1 ֣^^x1aixr$wEq:B9$&,m<ށa]v4X#m8oK n6j}ܛ:"> ^] m׍oQw>qOl\$u넋n(4a //~w|q}~qvuvtvSRׯIx H .:Lܾƈ;/B=6dHO}&p:pN3\iס:D.IdѾu批cW概Y2- i:~? oyQM7b+_FP{8pl y@KJv ^QHP%(T^M1 MFn[OL- l< c ^A?0qy0 W8 tҔe#}tJ;#\9immxzI;8Q}?{ zÐ0u bCCeLd&ΕՖ=Sŷo[Ӯ(Cz).lԎN&ڎ~ƬK+hF({y)qkK4zƇ$ȏMET DԲ\A(0KNl4/T5JHu3ZˠI1dGX xu^~lWĉ>*l2*Y:6+%a,Vzq;~;]4rQt el9Ecz+aDC;hoxbxL[ӡS;- Kqcc1և1w %3"W,f<55>QS\&gh"$ϋޱ8 ֝gAwivG@3ľ!Lϸ~S[ͩb'l](#@r6jzU{2bg.0})Z0T,qzU|j=k1i0VQsRԮu?bf"YDm#!~^ v;v$p2՛.Ia}9,a*=<  SΉaNՎ2.P_ugPSB1I5PaEn,!7F0r!Ō;C }ݧ |vE4N [FbSBl?zh% h< &ÔE=jFЈz݃uV #E>8T)gG7aln:?ugۀԙvpu@JRp'}9]&k7Yz#ֳiڨ݆ȏTm S=K%Mh`TZwjY }UKѡjs0OkEcIg!4YcnZ \D 5{p"gxRVa)t=^~zDl_;3je '¦{SU;M7avO](xGOᒱx5{+cq@g~7E9!4ل"ΚO0̸֞Fb&LIo(H@/3bQ>>Ў7yxsЌA&<#nĬ6$2zt;vg Ɖ`ՓL ia&S1݊BCg{0k9XÐnb$@]P7Ě |"Һ6O=XXqƆFY.GPM8gO>m|r<&[_/YNR/̖0UHgNģRmo+߯;>w17J g*M|TԹ佁K^;$y@n?ºP+U* ,ɉS%i={qreJ'SVn#>M ,P}{;|{4]\i͙xe>} :x_aʺR50e(Ɯ@}*оKY6b&o)wğ! ]u3{| V7tYaWSG De5oO=h 0mDOOhhAbU6u^/e6Fi$ sUʚ8 ro։QAa/gEx4G0*kƗ@W^ bՒo ;V} ѷX)㍾S1۰}{׬]C1 yX5,KUHK-f)mʊ1cTqn}>;iT: Q:x,2͇Z!kzDx Wt旄*@ kK̈9"g_ rJZ{m˒K& oY^4.QTRb_l!k@|Ì7Ǔۧ`F 5O-< TBHٖH'G<)~ vv6t h((n6RV7uZ8E_@ u ~_Z`J ᘨG(V.\zPœp9<;4ZˍizP.tGnwꇗ郃wNޝ\d~~ww;L0%W ;o;Jn!Ur \DڈqF"1 FliDX&faMD4t 6|_fZ>)(LPr veg,1/d 3;z!ZSX.m5M/QJ>XE!a_"ć#*y!t-#`3PQCaφr?x vM<'q:W9^UnU (a0fct`kߋ4eè6J@ރܤXԅ\S"R:!2ßb=$i{{OOˣѺ/dp(^qzwlTFFbe8JZ%F}C^+aǠ ͒ ϵ~i%9N A(~5z/4F}yyzg r4k(m4!A$a-++$.7gF_Y3p&W]%8Vi :<4 GQ+ONeGI" %0OyXo>ȩʄItOk| Ϛ!\}HwcY/]/5ud4(qYSuT>mh=ُH:uqɻןӁ(V;|rNy՘<#3X`"dya`vIL-ð!K5d "G6^\d~px:Xo(f>Y(|O-E);v/q/(ψ?A9"&덡X`nTr9,_3h&ƞ/' aPH=q]TȖC/ib1 ۨ2@,2gMLuF"}:ƭ/La~,[gk$ Cp3LLR lwa/jW'zEbNņW{ f'7.3Q΄Ţ>$>,|8|˝9%\VD+qg;P8b2K7;#&4!wV h-QiVHon\SΊ . z}|G! ]~ /)~x-=UAx4-Zlne) LK84m bM>0Xnooz+s㽪Y>+$4?_$}…$u[8&.1@X]aE_kZ ߖY[6mAUxpw+c!֨Eo=)7/q!t..Z'-c22< l\2ꅲfaȬfp1A~=QsNqC,B[7]08[\Sޱ3&a.Q|W\}"N7$y:i/3*?^#*Sb&uYݕ4|xzz4\|!".7ܳwtչ'XrOD oq |XZ* Kj;_|J3xj-I zd%5np^s-mսF9QB+$:!}MQr#66s6i[8{ͫrh֯ˑBl}-I (!' 3xvq迢pcC_JZEdj Yjue|Mu[6cVZ冷bFf-[ƎJ }>WS( JQ}c HߊDCxs iny8ו=s7C: [o贊/j\[@3\|4IZ]9<[̤LdH }Yg8v==EKKW"E9~ 9(R A8A%+B^'ɉSE5{㞉?[zOm?8t*@+"(fjDN^rJ&ҵYY>YJVª2pz?{Ot E:~#vX+mTBtt=pBxnS|2bx`DXl+<:GF;^^7U ZNWX-2&Ǵ8Ze/UFka1\$fA#OqbI:,*jH8opOD٠DUt _õ̰YEZ/i4h =-:c1rnhXtN[ gC Lj>uyj>ɉ˪K7{nQm,=>tF NB|LhHC3yZ2 ͎"~dYDOjwjZ;[Kc?MB`& SP2pB ?le,nEc*;$)%B̗h121K8<&nһ(p7RPj\毹=NA6i:jJ*P }^MBHp2xjH])%|ّQZ8Ұ,Pq7ƒo#Ē/?fHV/.Lu?Q>iä"H|s87zD`9U\ȶ sf$Iж!"ͅZd|U1p֦EL!͢DM6"jz{Z ^8fɆK4R%rWY=$JE$,=6dgdzܜy4o$}*Zf-20lwj cj{ŠH[4 &dv˨T߽?=r8_^.fSXHlUoV'1vms"B$+zy 뛸;%=Og8D_F|};lPiio04@3`+Q4a<M4%ߧk|·+|/pVpdx##VE˨ѤtEX.Hu'їtz@K1k\ֈfz0tES!zj2To/ޭ`8\&IaƣMe,6EwypF""M"0% {7Ń&Sx1Qur|nZbLZdMIz5\jJ|+dip2= E rO5~at80 6f:lc[SA 1$rk3pX_7XN:-zwCy<]0M78Œ)&93M@?o(NRM.GzMLsøM5thu8Tܫ0ETĒE NSxRG^b /~0b0 4?hc*x=> o aBP#@mKNJHm?3G㶲OvY`6% ϑ^{w& eMH)H ]~'lba]ġ^cTezt&&cYkk4- aoVE=bNK(*JQˇ`v-Hi@^-61ջĞ_٫'Nz ož^.8Ðk]J.^&`Ua1. AJq X{FS"$u_]on.=0uck;oc#4 aڥ$Ϝ+˥Cɵ3瑘ljOVpb3GZN#kᖠ}Ko+42R؍\pB+ȗs$dRh Ns=e?B{+Nr^6~_Es&=W)Hp<0D4 `4JdG~=# !_W-}d$3}#W$Iœg;P.wG2l.d#bԕ5k{Y}_dN!x݉~S[ҊǝG32SZauǽ瑠°jfM,Ȯ@g7ӄ{2)2iB`ϋ] ~iJpNjã߾?:9?>=y{r!|v-c1)K~owo#xA? 5$U{8Ϻa,0 '*f}3;H6R}2IKAA̠EXXhA*\~HL4t9 Vg"uxtt|NCcsdMo30OZFL4rl*Oڣt k4\zj3c -͌%:o?ݒks>݅}^4Gsv^!<yms% oJs jHXOk?&k뛨L6 ?4H^IO i@xK gv 30=Ay xҙTn 3./N/%a%旰ñ4.M⅖SDT;vלtSy{XR򰌐C#พE~u2o#&)>IL\nggRXQ(4:]4aOA&Wo2\e2N#WiyRw/n;`1a[9%V@=9]tHQ D!Q9p _λI~:EgeFjm+<%Q0#f c<-%+AUDE{5;>I[2ꪂ3-W&1*0IwРAq- J*-恄VӕlaslL8O M&Ŏ@%^bү֔kRv<ȑ:Q:jBb=yƴWu8 z2bWZƙNgDʉ .,vvV8NәsڤD??SroN&; .q"E @G޶ /ٔחeRsVX7yu80uBj2s(Eih9Sޠ*9I'>=Z.iL{,]U5j{/>[f+p҆O8h<8T,H >yvHVM|}@ nzth8E~q㍟Jm=kj;Q1+J g1;D1[2h|a-쑗s64yRm)y_^ Z\.zR9Ѱkw.iQ`W2İ똑A1"[8F+Jrdb@@"~^`ё 籍a=UXO:۬VbPDrjW] z&4脮C6bjbU\BrLLPC0ۚG]W9)}֊uw;{u: #vvy]..2J& 7LJ/7IWyEV+qE&#M+azzqx iUMY@',).$%fޟbdi>x)|!pI ޽`e,YsKI$$Q:÷k]ZȔYY!%fW٭h9u2 ˮ`f.jDtxVeRΥ7bj,E vNJd*3#KAd/S-)6MX3=o\=qJs]}8͛DM)xN8'x\ڀY)1s:ѓ8ĆKZ6眓#iI3pDPU|K jQ_EiL "kŊ@#\m'!{DR0T׏R^]蝼 QuNFh Q%ׯ.>^y['PMud$eh ^<Ӽygq i0lnݵ>INMneMCt:;mc+$\rz) fğh%  77Vik8=Nk˙P`Znq fp *D&yGic$v!_p tW'+{G8%f@K]ˤ2zMA !jc-w³DzK Fb ߃uۤ#'1{; fmVF[m( S!/0Yܐ{acaůBDq.0s(m3UctNiۜҾJYRzYAq\{nyQ[<쯿mr^#Ӌ!ke65 53oc>R;dB&c_e9(]/rܢMGQV+]:aUt@Y]Έw"ByC2e)O./rR{E1n $jdz84. Pʾ0$Xr^\hշ!vZZ}rv #H.%{n?0ĤT&94Txivu [I>g-;a!%|R Nάcaֶ6F[lDg9]a"$@Lо(s1OMAc>9u\د7$(Mfm{zs] ɼv<(:bC+Of? ]`e4fδ?G>h?d|Bph L*-ߣW:q4 V-3gط7prk}w'*gcY`FYN6ív+A|֞69%f*q(\Epl_f ,XMֈVҞF-eG5Q8ZpF t`N+[q^iTNn\{!N-DVa]S=q}K {K bw9p)mGĵ x/g(9yz0l{miƒ.Qt)$ČhSPkDB$Y!syB%eWVU bS˺W.ReX#An~暹>A8Hv:+ |[/D= ~*IBH * =OqL=֐05xKsb6yb~Ü *P_QR#&V!)J$4oRᓶi0$4ȵ ʒ1SEQqnS6lڹ:RaY9#:|M_L\mHߪhՑ<[u4"Rk;%>_8!2ޥ8a=3,rć |ͳuy-LJMlPa3 .Did 7hf! %<'2|X0"vHnS3s"@h;B!iwLËt)IQ͎n5eW 2H%є=٬\n@|kiji ma}،)jT)b3LqUK^)N#ʔ.4ڛ\Fs\# #2Ѯή}Vhds;wc+|Z^iBϞ,+꛱H&dDN%% +7]վW5~S3.@ԊWcM6,ʱ>9+(}h+բIc3;5ڛ2Le8rutyEy[2j(jM5lC^h&zT^r#WsEQ NkŧrJF^ Py8EZjgr)q\ Fc/Xב gjd-U*!B`XցN}`C іɨ53U,dBYOTʸYQ4GG 8exG$0ZBydRx@Δ0g!0fC܀/7- 7yD3?u,Ml)+a4EQo9fDtPbӚ$ pXi tZ4;De\1pJ,H(wt,]EC<-/Ф  Oz^Oj!]ArFub(!* EcCgk ecW-x,1Z X"'eICv6L=N+vZ@hV"z﬋Hۧn5u%z۞>(?!vvUTFVͧG4XSIjJ;ltjOMV)t`qhOj˜n /}X+WΘ7'!LbBkr^`ON"kvxg!wm ¤~ ְPB^L1Zj~*u*st:?mbkwww{{koo"-`Z v_^1JܤPk4 'ι IRHr /}%]@U;7t8YyCyQza=m "5Ys0;g6Wޟ#;|e4i!Xv,ez81ķX2Xr7Tɰ$D4Sm7oa<V (U:#[ƍSq!zYH[,+L;3H%wYC`p.%/ vg۰ ڒ>^٩D\xu4 F֗"D=~J3Ͳ[C\+Oѓգ.h&P1{vmCma - %d xVm<V),WW5678y+HCks(MC>NZׇH,h`|$yJO\јM~FtQ+j6U|d>7&Ѭ]K-{ N}-ʌONe5IYLJ/ZUtV.6IGL/- iݯHZD/D&p6G" zFkd%9Tͽ~?Va<9z qQa$4;pIflu;ռۜ5jSv (5JZ߃Tom&RǜSp9F{14Bl$~8Bkn8o Y;a<Y8d1i6MF!`iEAM+s߽S?Pwj[( syUﹼMCWo˳WW/Gw'/_kZ3prU@-.] pe38epv8y{~zrL;:}S_PwgHBJ^P:9`o/l_89=xurc: YLOޟ^/.i4컓w.h4+./.Ǵ2*m3xy5rQ n& >9O  ~bVџMŕ^\b.hx&'ݱS JOMcLJ4%67n]_+縟o?%JnmO*o"/ g:k1RLnSWUADCǃ/[.Cr!Ɖv-ytS-FR,+H«xt3rQ4 M՚04-k[D$pҔa& x fP=Q؄ Vlu~2b?…-1܄(9O``"P>De`ĉIXzT!8l ,-# ? gĚ 5ZȗlMl;)Sb(s2n6IU}gGԊ6D''3A%61?ڴ{|$>?_ZpCk=WErFI.+4:e^r 2(h3qavK[b,^eEh5HRJ.W!ɦ8t<  ]Wx,hVs<a()8k3,t5OiS*1ӀxiG`?k3X4fڧO hRtn ]X"9z Аgt6= ?[Xu톷h{b%H4)Iέ^eG[R 7QZ_8Oloo3h*WTl96DDyU;PS7`8W_<E17i߽>y}!,xr "IH,03'\ΐ]g祪ŀ'y =q*K#݊0{&"6ޞy**6E|}m.-v6>i Q ~DvMXچS:p $GvX˧uW W<([Zph}lIZ %mDbRbpbLo"'69KR%/ϙK(KZT!7 ϔ0-F``~gj *)cNľS0e_\n3oy}Rŋ/SD aSR ,B]VTo wo$ƮzK^aɠ"UkfF5ː&aHQm|U]pMޏe}8|1ޅyo+6.E,xENv^_У3JCl6'y$/-P|tM|"/dE'gл"&C^H^"48r>$zF-IF"]uGz|"wV4B,dM`Qontv%rũLjP둊-Hb*`Ai8f"DCH4- EcЉ~Vo֞, PzyLVG4vy^P]gS!Mlqԕtr'; Df%t,{N3mpaND.Mo]X>tNĦwiz%Z^}'dAP,@GWM.(Oy}/b6=s+z3-Ӕ!@#,GP<38f-nӲeh4jE MͥhvN^,Fy=fzvAp46_}ȸ\m͆-91YjRiIKJ{NZN 5)ư"}5jooï,_e4ήOK :#o%]Lru+ aWHdXl h0nBgHmқ_>!4<\ͶqbJ6opm+#3nt4Iٙ_i$/(|lUSתImJR l]Y:0+L L<_J5 zJ 8I#[7W!gq.J @rHO!ϗ.TxzIE(vNvi71>;|1#kP^,j 0xQklq)MDqK6>o^]8Y6{ 0fX-0ԖJqTph6~VܯϦ*y8.0ۅ!Mk t%>9hkFO?095pDŽx#VcĿp-wL2|߃@0 O[" \8\sFr8Op N !P?`A?,= ?:V}?m035r֯yǘQ wHrHQA~Gǔ[G0NWu|D܇\0l~3\G) Ѩ%Fdc>3]3A 5ѥ Ag>f7 RUeA)WFf]J٫&O!JY |*1 ‚bz%Jӕ(NXG9_?9;LJ^I>!$W7򉴞DF0B{/! ?ߨu!sSD3[4[Bee^X?ZѩIN 9BG+c 6v"tiIEӫ~K;Oh} ī?i3x%7qpE{"Hܯ3ǥ~;^J'I?HZx1u"d9y*G|Lc.v 桻~KD<\ҡlvrjAV!GOi148#271/bѬ Fq9:T\:L8ъilRRL #TJC45%t̹p)AcBCu1b_QMVp$sVG|d۠a% -_gt=SCIq2.F"g$搄)~ē@#E(w43ʒbѪhی%s3R^85&MSBTmۤ+DTf/4kTu4UKU_QdNTroìO~dKJ`5!f@ ъ#h]構3 խZo P5 6`{ 䢠w }?7+p0]p9"PqU%HO^hĤZPh[OǞR62cPV~qk d KIbf:k${C2(uY:+ZdHٱ8,< ,bSnXv8\A(Im,yU Mʇ.Oڍ8s5T16O[MC%a~LT6>HHik@IO47pƱY=ŝO s{` 9J>,rq"V&mB ǎl n/)Iٟ)Jѭt>Kο~N,o8hSա6jRl`Tlɣ#k7-__˫Wo^~I? A>Zip Ip|p8Ef)?IVM9Τ9\',^𥉽l_>΃5aY?Snu+dYCI%h*dU58ϣ9xx{Ǻ9m)mtUoeiZ܅D)ć]?@( -zﱸCDWZ zŵkʁTo +Y2Z]~q(@땔n$!%=qӤ z!$WM+](@yVm?1m¢M{FA„Y0k){j|{P-RQ27ޯP"8gTx%a6WJ ,pG`+j$H\t8UY-+Ϛ@~e I. h&] ({< 0ںs7aK{6=}GU72\`qa6ൔrqvuvtvjcxDͥ>tfeH xr;3@OS=K[4=ƥB؃e:<} vnz/A|J,p`P-ϭц|r +W̬N4}az[IQ1d)T6a}i5s ŪSPY:``礒lr42 ?ijC};VG_] 3L753$E|Wݥ>'5 ؖl 0,jVRe\Ț*]s3vUd[rKjMJ&[nxe})rf& |0=Iڞ8Q@no D_x+D-牵mIY3t$aHYz&Z4Aݰ_=ߨjF6ø}1Bba{'Q\\nlX⁦%!e@|W&ϰtRDdWo>zxsT xkEo>$,7'ā]/Gc吲g(Mݎ, 82ڔ"p:3ha!*zPz8d%&(NJf^: vL/HG''( RhnzV5fxy &XyČ7p5;^8^Ww9RgzQ; cɩ_8`B}"שbNw2‰ՙ?c0q~5-x֎O&8>V/Fs0fIjM ݂E S; <[UUZҘh<Q]#+/7QH*"5t\mZ$9Vt+r5(e5uno%*;ZTi/o r>I.'µ>[i,KJהi jEL%@ s|GE]Io:G<4G >ӆzt(4{h $ѩFZwAgî8=J%pzlD SQSKPr$*zS{dI[V3-υd>D䬞 [C0П] :hVqjѱi3v}W1^@W$`8X-ҨbY .R*T-<;Yk彚w)rDE w0,MI(UsiS@eGDsdvi! WkE+jx7P@ƒb űQ~գv`OIþKIHN G } `" 捊˗ Pfmj<%IM(l9(͡jMet<6NJk'_LXmE2#ƻ]cI H*QvkJ)/-U d`ƛ]mV'otD[V֤oGmamYN`X0n/1K̓_}ݯ?|]_,(wTUaoq5G:N+ hMt]70K&?&5 ~+ђ9r)!vg%n͔"}}RirFuڠ~Z /y1LeugXX$;vF@ !PNj֐b$uAg,?*NVzax<2\lۭr{a2[1 3"1eTZ Fem@""*AmQ֛ٳ:g.a*L0砤uGt aϱI/Eն ˻} ̩$e%ud cA1Ne֖T W:˩ָZ_7IoJ"րEIpVM7gGroXSr.ڀ۬ӎ@2e$TR%򄰼Ve3aܡR5}D7|HG\RP'v,dJR#+Ir砬ak-f-g%u=lS5^ ;Tʏ~hc?Q`B JKe@˲ș #0NFm6 5$r^uIn j2[oApD% \%|RȥyA NvòdKGkHJ]ʍV4Nع?ĎFP);'9ǓxWd9L D⛥8a˂ړP >aJޔ=#Xi蠤pXqH.Uc҉kl3i&l bڳ)C֙eiU:ް JniL2eZzɺkʜ"<%!gNM5omnDki$Me!Yӓ3K ؃KXMi1ʫE,B6MtV60ESϾm0Iγp$WZ4flM$M yhi ܏ɳ/&Hp QtBPھVtM)Lmٲb@9sgxc!Ajw8y\}і A35eBs?/W8{jϪ]M?Qm]Ki䀣P}@%GGI"t2 -q.6Qؔ #d,W x)ߤh"ڧRs)LRfQr̸K LzOt!يcaYd#Y8/R2YBm4ĭFbK#xɏ-+1ޑXMN˂n%}Mє?n4dK&ÌYnpfdfO\+!4owvE3F`"&5>$97 w`oO b~RuEfI+o>&1QJTL[FvI@/;kr Vs6`yM)nF-cNNFku,K=, MuDW)h̪!5?DLJ.[TeǘfTf;]tP퍽UGo-S>=†XeT0_}?\{t- &9_EZ>N>K,(pOypdq8uX _h<u n\.)- 96#>i@y'(1\\C %$췸_X0b;C46Qj<@`IPǟ͋FU7;BmW&UͲ=*6jpczdRۋ`&ݍ?х5:S/ߊC?Zٸ0WfQ TBZGz_@Ť'O[S C=ET頿8p`G9Pd(>7am:N Tv;UFV2=5@oc(w!fJFk~ȢswhX@Ͼvޛ_ۿU)$yrNc{c!?p|Fi³(O);FpStk^.'i竛fGxkBk࣍[J $۲yG^ ? tE,z 2K84䋨 b5RV~⊑$hE_%n G$Yl&HЖގxX~ҷ(]wgma> bD!扺jPWuzywޯԃ0-,9[|;)pf3! NV~Vi77GWa?F1Dr捗]íwD}aVz`kKydQ^C6/Uu1XZ,܋hKzQcx̓"e#_gmf+Gw-ưylS`8ZN@9Xʜjy@+X-R [VM*Rv!=eeT@?|_ %#@)J+I x;V W/2,g6f dM*R+\ps3@/YvԱALAx!)k(6_\JfX=N8 ؀ `opi9)UB]21W֏88 #kP#ӳ+j;Z^yf?}ՠɅQxMlW+u͌,傓8=̀B7Kjۭ?W*8^7sZ8"@"yC`qIJ`C ڪ!6} @x=BoCEa(ر@I>l-^P2Po`y0 )7-;M5ɔ}%FVAF\G5޿-ocduo#}ydͥ)۝ݟv켒 Ic'A,b``$)$&g;QOiQ( @Ar8;f EQ  (ϪSvaZlЈ8ݮeWA`-DT4qŭ<0@`GӬהp7B-5FaײvhJ R:_؛9esۑ0v~%t@k Xzep?C~\<84g&CzVPDԂ6\ǷPiJ1F mT\o)MI^Dp,_\&0epysN_R 0-P("4uu)pX<94n;U Z/t{v1~G/Q`㗨ptgUP#"ǿWSXm, 4@W= jVȜs N8=_{ 8RϿxj$v;ڝi3_8gee|OWhP# 揾ûwSοqwwsWοIlM&҇f#sТw&k[Y_:TYlm+L]5R-  yȴ.d#;o%^k|bQ3=&Wȳ𬄝etf~k,i ^&ݫ5"SL厢[l۾$ssھ?"mucw7pVͳlؖdv~6UN` O'iԞsm!t? 4\Fy4JUi3XhD3.Dp8+,ffgJonqM'lqfc\GlgE5-R][Ay^#%vJ+C&ǃۏ%~4]dgiGսV_eѺov3OF3Wq/M"CǤ DK&.0wIpSka"EJpnK9K.&GӃT ~@Ź򪩫Vea`C&eH4ֿ~yyer?Z/w%˓ˀ\HEΏ{чnwRUCE|ҸL4VNJ0T,#G!y4 F* KNC5EBn(٬qW D 9 q_׍ȪC.9N'.TWanqP< Iת^Vb3d ƒ>G G]'Y4J;n-hxeeE5>DE\#aI ,;@|rZ:DJ_pƦ־dr.+{w..\+[U73L};i@'M(wp cE|Po(+'5Ekzrmp LC[;>>xvL"!~>x9}Uyz!^IqF1B++_鮓FxIB6r~XbnhXW|G`+ ubs5_AgGp޾jo~h3\UZ m\RN VZLuH7k|5jW p%$`po!Qݤ340S)ukb.\QR=hkL*Y XleI̢*SODi*#E(Q<=QJb_K &Jib"WՄe2{>E )z$l+ 6OXXc"8 czyFl}Vq$e * _^,u햺M zh4q-zW/PSrj]VzE+ꆫfy,QdxJ'ZA5Jʢj̶\&*P\AbJRqeM_XD_ \h?+6ՔQjO(cYXXB!Wu5pQ:딫&Tt(hAK[M Y9T:9)3X ͧ.Lѭ6SJTU)6wYE4)u=[>m*үϬ1<xis:)=j4TS0,>EʇhΗq4wh<Ż8&l(z(ʀ쑓a)<7d"̤^3w߹{cϟ-ú>#;]_#AXZ7h#^G`w㓴N."D`*/Ea8XX{fp*o(2RϵQ6-F񵄕J&R=.FVK3Lؤl!<9?OqיU'm]BWKozXx }UV_ pC q8rnen-MnseT-%KiSL4isBdkFHSrUY4JFrq1=u5 [p_mPF_$1FVyB:zZ钙ƒ9g :.a.MJj 7*2 5ښeKHmsZaXMD:*9 "7=[ io'Gq( 9 j0:[7Sq{:~@#R_>g" څ&THpJEtkg_Uzo޵N]aHDM[%]~&C%ğ(:<9T 4bܕL)?4}N5 ws}.mI\ 5̊a2rcJ TR[RF3iwmD;odeOҨCL/;b-4!L7 J^Oi)-fRF~׭vX|v6Hh =][hE^.7%4'T3G7Fjhs;2G?UoC4oj["mz{G7𩽻Boς,#)Oؤ"\.!;-*K&%+=ab=#ǭǚ2զO23&k0|<h\D `9L$&+") {8$ 7F}atsi%60nBynb=#'$X~M<ŹIȚ51%$FZAL~ξ;Td_qf%Vaˍ1Ș1+·Y$.@jk]XW 7[Ji-\ksW_N)&p|ƣ|]7`Zéu\1.o% RG0;jQƬ i^+M ;%CjW z)|B d%@Yj$FH]d:j@_1qU8 cfh8tĬ"? y5(Xgd=(NU)t[&رelbeQeˮ!ZKyOVCq#צk]##B5TD?ش/B`RiγD0>q>u jn5\Ptb]_tD;&Pvs5\ jɐLfBOW¿T<&'lkCT1+k4dz!)UU;TU_U+9!AV~StPΆv%NƆ{q|.PgLw)\.Vzh sϠ|a+J%|[{vpޫcnểϻ/;o:7t~{KHaxD]p1)ګ_7:ys~ljOm0TVjV_hةYku[ԇ.Rp?-,i (2jfWra?d+zĖYEijDYE)nt >%^j[0qB7Gj6G?YND|_بRSib n{xBt nݽ 8H h,pZךA6En=n/ e&ڡpԢcۉTϔK2ݍ aׯ$@-$V[qCAW u,x l {LG?-vKe3D/gvK%HEjˠdWU`\u7>Xm+J:={JnbhdQi vvDߑ^ C3p|Rc X&SY_ƪnb>!Bkz*_Z_n?V;b̿j8{࿣+ı *TL_OγbDh% ׏+$<.3xa6NM>Q6u~x$?g?TiKM+Um-w U(dĺC77U.4W.}⇒ o~1q|Q b FR%OcY =fA( x8ǨEVJwN%<̈́;"9FR.C7J%iuV/lv  _]ӛ;X'zQõ;TwBc~<%mFzI 8!=bH1+ qtӉmӃP Zu}y"$uFq6l o' xfW6P` ^؍{Ž d ^*%pCG!XTˢ mZti/ 3p L>(qy?ЉK^-Ń௃$;K0kSO;)¤K/`9|n6:уe˸EDVW?/$I񎴛wό΢Z5̄RdUBy}×{Ϗm*/e{yB@"K؅ ?ζYG.[A zlqfg7c^j5ZG<:Yϵ0{/b' k;{'[/Dň4e=RLhGtaHlqElRvv_tiw@|Ҳ!ٮs#E55睃7U2|l褷ښΪ7=?|ѕ''r_ zYh]]%6wemiWcecf|$oS䖭 i:B4ӓ-d% DiTQ á ,{S0 _^(Ț#>h|fǦ"(πn"m| 8XK`8$ uXUO ٍVD!L;O%a#JKɷ,OՐ8A {Ȋ+xwn!J`>UYAB1[j),bz@`\%m!W}3܄hz.(wYh׷XG|B21y6,,k;Vd ~|_y<{LOc{yQ:>\Yr,fx(I4B 7e z_owK ՠ9tJ?` yb리 Ɋg6]\TI d0QO;~t}R#3BW6=_i; WW|pw>_7+>z#UfWaϔN5x&$ht%9sjU}v~дEuyl f'#W{?ޟWoM*^L< r YGmB.o>>oSOg饘p^nUα$&A'}/_o1sΒfm~~?o?{6lγW?Ž Xj߽:} <oOq؝Yw (oww}J8=B(飗hrĿ:K! 3`GI1,n$5=P$^8g4p̰ :I>r8Pl2ÊyBN  v8+ 9䦹#\:׾k_t_3tU@#룕G3G4+lI49FAJC/&); ':hQ~4]ڂrDl*bZ?vz[c9L h/9:\67G)qF1e~Ag-:woQ*O %[)V܎Ϩ ;dETYޤD򵨐| \whjE=N'ϸrT~d&s҃B~e8FWC攲&hl$K=!JJ(c\1=uQ5Z\p}u.V90,BڏU?8`a/ 1jpzYv#D]RN\(YABnV^M5h;nnZ)'DH;rZFEG*VP8<0K5'V5,~U8Z!0ieB Q.7?У'յ6; [6&NWů:' V\FүaS< l~߂Eemfd_$QhPd!ؚ֪jt OfyV9Lu:<LP,90]%`Jҋ3?1 2,S4#AFgJUcHxS8yBVKxY,G*x*[nX8l>6epwn[.I2>sbV+6ߕFEUFD+dyDi4ھ |10Gkl79!E#@pjLՓHq_Aqgv禎=w%ףQQƳ\)ZTrkn5zJIֹO+~=ё g^kЮ2]tSN M2Wqr g\͑\_r:`p:7P f e2c/ 0{hVUpLG^%ՃCd,AuHl}jgemP<5y7c?| P/\~Kusp ;B Ah1z![ުdƔm:KCwb2+9R3=_MO{ Rzb1!iW'(J>əxҙdkpOL?PL'c'}e`W PW''T5t@{jݫsS-bQ0R)1H KF ' _*Ҹi0?i*Il:jiyKN3[$Frf5QRx]-SB2>plRDKnnel }RҶr+`La O P NM]hp 'd,\.Reܻ wgQ֡ut3M/5q^8S%Hn=Ek-[S |ȫ&CH]Mو)A~\`W,,m q99)w)ȼrJ.c߷d"]zVEϩsq/G{p;ePnjm,t@ޡ T={)os);{.{R*Sl'&0@(a?$l$cbA!+]\ҝfl'JePt<\/7cQ~Qo9=VM0'Qp6Of3zMRd8 ݪ8;?;EއQmn.ヅM\'mO&pOao<Gd\&Ap+[/mό@,Ljd|}%hl|$m//>?>k%?B\(x-Ar?ɘ^4d&#̝JmCC]D?0&fb9l~#&kwo࿰g׼׼'SZvfPIlTCo{{7ejNM&%Bu9BE(\d'0iS$ϰiᑊ @[{ok-."2WU>trv^yZf!q֋.. I5պWܰ:98E[O}΀U:ؓ_i}Mf:<30)^@j&NQHq?|QBdmZdN`Ѩ뷚MfJUyD#e a;+Tş pRIQ۝G۳Q* X""|;Ŵ"tE[ QPpϫa8/,@_dM;1atX苼UmYtKx4B0SGus5 .jA %8"=#/+7h(U81lAr sDBs,(XHp}i ì*9{\eйZ5ɛ ai3D|$HI;{:ݨߑtdz0nC>G= t!sSFנ'-v {dwJ Iɓ*#'n< 3;w |ڔP Є &p9 9oSazF1RHә֕ORB T8 S7:3 6x [w1jjCٍb5!)4۵jΞ{f< Lj69H: ! 9Y8%kc Ƶ873!/ 4H]HFNblF>8vƦ0ߚJzay;E #pЊҟ2gs`c|v)8ʭqyA$eZąd$%U/?X]77OŏX]7Ѡ~TFTAyQ0kL5.jgH?_ӔakgLa'W2[᪘o,)rP(X+2H Gpr"[Mps*& )p)Ѳ{!$"Kh4L[=FCjoK'D2sY|rǰ *_àO&QH8˸K*Y•WkݞO(ҡ*E0a{`s3 жdc.|2M%a{ۄj&õ%GpL0GqL(M1KTece2Zsco1ۢ6mwrݫXddr E I`E+RCL.?*̮=bv)]JO2F_1H*ܔ&iClЎ7R $+5=/7#{Zc HU3xݒLBݕ$B6zaЩVi oگBtڷm2r!gk uc"̠/#UQrz<*Y_ь4[.G pjdy_k@Z3o(bqWƼ_*Ului>2f|D}Fn!U=1{ĝNQ4 pĕ*-UI-iVԄKYc‘Tn15,oGqjdw-C"$.#}FCuhfHьQ;8`Wl00=z5cZx P;H>o+H*(wZ'y-uj:PJG3ˋ Z(LS3?Rs QrP}~ k5~ 9!?"ZsG)-%hَNg6чXy j@v&ÙuIBT9!8u27qښ= <Ү j 2}B[—` ݗLISd~T0w|Jzh~eRԹ}m(wF>gIO hI_ ZW6rL ~őhTLl)bl }Y!$zZiw3;w?1柙r76nܝ0/̩J2pkTJ>NCPN MeVuFy@V>=4[=[^:[3ڒ&G+sYG!e',UP5o  +GLP}x^lGI ?FYKn)5k_[@*' 9S*:Dm!OmG.0o&iͣČShV$%y`ZrٔXܑK[ % -cScN䅩 zmk)Uxeԭp#s`MuLvD4NƦDKdok)9 x|wz7ƒ/+h:zD"Yd>&M69s1e맏b4&Y`5!lEe1ay_, y6aΗr{BɼL]DӋcAnxJb֘CؾA'ESw:Խ}*}̩ztʍc%Q'KrNψA"Sч X}GFc|L"FQ(VtWy&{FwpsʣP#eD?#y@Sz)/cn9INŽ:{E9E˳T'Cs#g[ sS쿫+;7ijZ(EfQ h5*$p_r 0+ {7UGݩN61ÏG|>8n{Nqf% B;WPA-1_Bɧgrʿr"M6@R2eI.9_ebMNR~c (!hH+ %m?#@5|q2GTfѱ> G̬[+Yea2z)Mw.&M2 N£3KNҹޖ% P7~H6X {sM_*j\/r5-UJyGѕ; q` GeΦw;@]0g[V@";KNlJ81\SUEEgS+w& G:c}"z[/n _5k{x댆'8ƄV;51F<0/}ٸPLXC-8> p)*T7#jVK)/t?9|4qg* tf7*-pp)њ?\w|C.rEnLUτc? zecMH_h7jhşx͂w\Ol\5|Jr;QL hs5@^A"Az[J6Rg;(n:ߠP7J{Aן?}9t\+)l͚ͯc4mDrA aF6]vu躠$=T ƣˮTqbēɚtq1P9zx7v3y:{kBG aey`,=0P&ȣKlZSZăiY抱؃M|< 7L`lgg:cU_t ڞp|{wٟ\JheXrE!W!gہi-wZ`8{aNl_F#rz}IjUҾ ]GN^!C}\fѮyru,f u@k^˒9s3؟ W4λ×{`v9"Q4l„/<)(:Eg${PpU 8^BJK0 @Ŵᱯs3ndJ&&6 9bjXc%e $sűӭB<2FN$E,#=5T+oalss#o*n+a{䇩Q!1` DsRCEHA6~\{vKql6% DX])Klkb># ?Z;ns4\7EKu#Lyii@2DͫȏzLJ Bh~̯,+u[*M?̡LBYBU (@QqAE .jP@)peI<̥U`%ģf Y5!̆e Sf1_vF0B Q8z%x a{o4٣*-0"Ldi9D' VD{ PnN9~W d4J sCTr=e`/ j1㞵3sP{Y2 o+W)a~guuK{_ٳ&A;.!~64ʼipe Lv<0f>73*- gl)gZ&+p4R dԹ&Ӛ 8^We QrV! % /ƨb Kd$F,]m|ڕhx盾Uu^w) zy7EdR(Hf7dE+b<'_%e\Ɣ9a~Qs. R$UdSr/q;_H=}?T3p({i3@&9h;{JXV9yR!> S!yAN:k?Bzc#9Vv҃9x^\XҕՒ0ji;5YF@6!/%Njs h_6 LsOؗ̀t20E/}&AnMtzKy;@`)D,.AS*JG q*:6=F$+ɻ/,n_UT|]e\VBe jJ;|_`|-k|sꤏ:&RކVQZJe6dnXwvcAFB"m[ܤqp,K ҹƗ(TPVH> jHYDlQ/{u(@<׻ۯ߾}yv-'ׅHio1}д[Z!N4pSK%N47*~[a8^$ucs|γwh4r+*VK\[ҳpTja ]Fw+ 1fԵV<hH>٘ WAC4>L'"N?4e@pC,:Q'X'{Q/=0T R)=[`̎Mҹ~z2a<2sƄKK(IEƗc`,0Ly*3ZV)&QW\zYWiv{>kQN-I\z ^z쉏!g)\Wi&ch*ÍПhnHD" ]YD s]K7cϗ̶'c 8}Ί<֋`~뢚kMHo<#ul+x:v=aW+{ h%W+s*w"8h)ZXE!W-z|o_ۙ aCVXRQ%gpr/OpvDp{ u7[sVJV5Ʋ{ygGpyL_C~eƣ,Z_/B$׹2Xpxׇ Ն~.z_)Fq0 "Y^뢸ʉӪS,ZJX<ZJjg[y-e{Pu) fWxٮ,:r[~oh:Pe'hO''N/{Jx6ߴ+d~UdYb מ5A=X(oB2"܀9p>o :\K\_ulQ-@6:lvXۦfU ~ӗmv~gT؛]Jgl .bgٗ r}l9N?vay|sG˿{W}Y>^z[s*xb(nar~1 I } Xi\Q{4n"JZKa}_Rw3|o?F4]JtYʕX<>,lZs_)g" A!wTcBGZa]P5,^hb b< ;4b9 2udyz8aR]Y UìWؑh}IZ"UuӬM $ôTjgҕيwK(ee㾥oT8*:j8 ]nB&Nc_]HN9(eYL-*gaE,[A$wZR&9O!O4DXX;9C@hdrZ.UЗ^:G#DmR"0*ECZ(+ aE k!-bN3lv>xyfe&26&K=|Qr6Y:Szy~~"\I$AٖseOBFr( jAC5s6.v:9p&ĔzR C눝 ERP1W]b5 'd]FeD5:g†wHgH%xM?o@'K،u*Ŋ+͎C@=HEU^eg Ŗ@.%v \BH,9i6)`"B'<9}!tGƙ߮zN2ὯL)V4\e_7p+kBcfjj h,z*(\ܜuA]T| fWG+yD1E8Z )(mqmJ\| /HRuKX/_5:H$l2S0 %:v7P8J*C ó!GԇeJζɰ7,Xy5)[#$W2M?*CtIguQ.:{&Lq+ n:>#+I $tŗZxdb m/U!2}`.v[ uuka#'Þ C0c49p{&6'8ҭ"@iΊcwv6XgZؒ׵rK qwgEucUL0A]Qـt+ QXhL8'  dªQDI Kt°Rn嗖ϑ!.)oU|DYr)Y7 jɸq ϒ$k|P,ӐM"㊾~(E"&)eXu.I5˝\wK{K&)NV(KsWx.vJ. 88eN,Ccm{dvLL}"Qe{Nf]][Ri"4,sFUNTah@,!L٩&PcЖW@U .ِ(XҌN .łCd&M0مr:.$*;sA!\AFZK Ł94hPQ chE"v"1}j4Ch'RW/W*&KS |7"b(<"٧,E3{@wIIx@>TrTziǟ`I^[]ƑtQ=+`+<B(%bV}'謼.9a.UϹD^KހԕEL@',+oἇQXl&$N )Ov[6Y{FpfaLE͵DbxW牾4u+Qw)`rH;[dAb7 \2TfZ]r |h4LϡS,6߂o+I)7eW ctRVA㣓eUrϬ(8y˓ ոtCe2IcdI :(,18yq5E‡q^S`ng-1}TF/S_SKD~HmHR?PɐXCHwP u;خ20XoToMfSVL^7e͑0MzR؃y\+7KJMfeee=48nC\֔ùYI屌<ȍ[/v#Ww=:,%: ذSÅA?+H݋kƚT\lwt~=|yi9=_V8$3MvjZ'dH25BD1DfK,o2~D)UwUg|p> a͟R"EƝ[x&P9x\6=-vJn9 <x@:&'dHM*rc̣K8ȏ1\[4llKvi?tb,Vx)}#T׳.rZ[8ҙ 'H[MVYv̳_H1VX(ͱp9K :G.$Yc >  D+x{8$I؅"y[TO:u)OX4p{)7|!,0P-O.A(N?KOmUV!79s*N ?]BB/G`0P"0YuXȚNFˑTK9]pOІއzHq3+_Y/kHZe}wrL]BG'rWtаMrh$e~I;8V^m޲/|)F!zy5zE .gTv>!2B螥`=Yɓ\16Vw4\vD?[ӟfvٯnOb*# 'tڒW :}ajJCvpρkRtNq%鈪kYMlV*%Ha^)Aݲ#۝@kԥC[K 8fvsw cᛞ[Bm,.Fi"wy7UT^RG:Pxp0$%d[x|<@^C|%6Dh_a֦sA : ̂V y0dmb9Tˆ`B&]E wW{0U ΂L{02(c0eDA nypc#v/(\7&O" u˕)BQurZšHmLy!~cvNpni4='q(,|5rʷϼ%vTAZ]p]XoJ)}V)N)V^?:DF*jؕ]Yմ\’6a04X`v8mV s*ޢhBSgG0ĕSU$zs9 s,qSEHQdFCgaiK0"ɂAMx*[WC5K-)ʄX~GDQ 8@;(s"`+?Gd;a-7_B=.5]Naynhl] u7|NdnH msGEKV(X$/kGق՜XwT 'P? ]$y8્ xG 50bƭaw@FP``aTcu)xv2ׅguiigRH1EdV/ýr%{EƅCN >=C.~C*#(ѢXt$FT*0e[A3k0~řYԯ.ZVM-Zt;tuNq z8܉?@Ib"[m>X#f1zu8U;lzj]E~N$[\N ?dAz&qW~J5(c`}}=7x{#?]AhVgW{\ WLً" /3= /1g/̎ ?ix1>W1]߷ot(6U8}<\]y?V766V?WV7ug,O& ,SzO_ߢvXC.‚] bYP>[Uua~̱+@%TzȘJh /;ǟA&ӊQ 3{*qs5읍a:8'.-BMn{5D6Hzo/8D\sVtRA -%L-xsxįi]EzQ~)l\bvӺ%b0s Z܋|;mʣG>zGT=E7`Vp!`&E`UΥ*"uZ rK . D 6l(׻KU#l+*DnPu=.,xR YEŸM`?ID_8kxp b5!DSp' iIe2yćm2A}{ysx}1s e1c5MT2@ʩ"唁Z49W6@30Ӱ$K%4n^ ddxk2>Y?AZF{h$CΕ@3a3ƄuefqEZ#`㸥HrdRt,kNzkVY[Em hZV ?бa]՜]oku8.jߵՋt+޾['ɂH5l辤Esx,@~`v25 l4!>hhnbU1iBSd l:9* ֓JpZj`8l^^P|{\%ͬRU4Q_U:i0!;w2xխ*>uENTq>HAjq xo'~ZJ(?{6$ g <Ӗn%nǝ(?YۙYۣP%1-$uqo %gһ}>g'Q( BUAڲ0 ػ\dktmS%@RXu??=C$i\M8F4! pң@;7]\;g%oߝ^{7g̳֫7޽?;{N^'m7F plwT ?z7f]ڨcd})L|˂xS;ٱeSjY-cOo^/_鯳y?B'f@)#Yªӡل [~ zAY<,G2eU5Q3{IV)H{۟FUF+Xbm; Pczv_H 7q!#+1~KϨa[Dpq3tܔ漥9Er?ƛlՐ;yq78t.k _o#.?;;`џ?a2/X>^[=-|h <2 M"ySy3dP7#  EYVirgJw3J77™a[颭R3OudYQc7N9ʶ%E`mG:̲Ւxv%λlK- v M@(5EWwcC'>≙:Ms!6 (D,+4ZזSE:Bpf=P@&XND{R|HQHKj/7S绠J8rOo3}K! qfK`ӏ`fr(ch^gOJDu%K&-6*=ex,x% Q^BF/A3!{L g0 Qϭq*mG95.yxF"uu:kK鋶9!P t(`Tcb<),l qM&wMlDCo_l$ fa6cbp>Hq倅 ʞ}yBJ.s,0Scxo~:4e*AW|N {woY?lc&*^g?5Q7J GP e/ޟ$;zOe6+ tᄣ8aJrmXzT5ms8FH ǍkkF^4Ix* $2tUHg Xi#cjX x+MJA^ @,ئ2 h}s҇N~8YMTVRQ<;cmJqʴ GK"Nzf~,W]׍lf(h+`6*OCt>E 'iF!ȡr홺1N)`Reŏ̀͆)xB5\Jn:+Qp1Pq0ݫ8}tfGNzI*ݘ% f0~&?J Q- {ŏ- kdܧJ SiQ +Cl@I~^#P^ A]5`a>ɊóOåtTh0 IjOn#׺vo#ĔV D0FKj 37JEi<7K[yMd4eǏ4g&e:B6XA 9M]_!iRV5ޔ* <ʆzrAod|/Mgt >O*ܠZ#MwvCf/(@ăIFjxYv:[:0HPcp u+s*(Ԋ1( " SF2)Kd@UԊ7.^${8KAbkx0Ť!,Y+ eyQ6OpE-שp \cуwvڬ37qbʣPV姇P\%p*v n(ț'ZYKVݱb^)fag=5L`:/J}$d" !nZ+OA'*IHK]C[w<^ZSmQsBQCҚ)3n?TFF'7=jzpN Q:u9j`(c;O2*Ǹ'huĒu䇵ێ} }ldU6GJToK+@:d枊h*ec ˒8P蕇ad )Id=D~! w)PU`W.WUc]3 5j'q0=GǙ*I>6!.  O2'ui!7ZU)j>U>>7͆& a]uv84+{} RrA浆'p@uF*#Oy^ŒջAqDm: ( JD>(J,אF AB.ݓ\Ù%`-Lzw:6 vGa>2I+GHޛ\SGH7pq!|SN Ou?/HW Bݲ%*WěL}⠪fzOč[Ѷ&xi⢗w7׫^2>tT8[|նt@T،"f}pj2;l;f2Pg+NLMB?Gјhu*ҌLl\!v˞Q0V ʺ!~@JYgtLaBPQy$[i` Rq܁[p1]{7c(DWsbENMVc4;ԖЭmQrJ;S*{S%r^;P4rv*ie ,F+[..u$7}FY4}>|Xhr0hRn|l\c1Y徇|6^`R%`oHoWu_īT-؟ ` Xy8eAA @1eSN6u1Q*^CL5cΒ %c°xu"s՚]z DU7\ wk#IJ k KAeH% h)ѰjmܲScAɧz_(sqE x#{꘼X S贈Xu0k %"pC@RT@`YDװavzm1Pтj ƼV#sG{AH^81F(OAxSGA*Ad`xgoLT@mO'^I*"1U6~4 L[IXua=I.JJj9T_Ugb4AF.{<]KO±oyR5\c6JxDNs⛕^T:GGNR qêB `LH~uS.uBTܴl>>U`;ΤPkb@|a(.q47KyZɂ*s(:P܂e\k)I\6 |Arڲv_]kWe=f~Bמc vzGZ2aͅ^fC+D65A4kͅ; J "T>&ݐ+zrnVu0\UqZU :)!&*E{J+ҵ* Gv3,kE臗tkQOC&w! 3 H 1pK.nD􎈘MwӉFh`&:\A4:rM\d^ R;*znv+ ׌k)،m뮱(`O5 4V}1bw+F,ΓIb;0CG(ݝ0aք|$ŏЏTQ'PQNKa+LINb'm3Wqp|T LQ:/ 6_qW &/\,H)KdJ.+kwǕ l~'h= kbbn Dن.|O s,`_{uQC\ _FU(j&61)<0KNBgNN?\CG(θ~$ H`;,ŝRvs!a}5}T֓TfeOax[ Tgyi'\pD,3W^։LY6_ƱUGF^X7ĸ`XHq=R#8a3AOѢv7[ͼ=m|Q;oGjdԲ$qWTuɉAX-"|U\L/N>X@5lqFiE@"VjݩG }tKVY:*%ՆDqqL 9o8Ռl}j&ߴ>TBA .ik7#zHp`:\ pjRN+N]M;Oj uábeI*y;R{[5S5'6@Y}*RV·nP@ zB t21ȭnP;2G@LulK3 P`\+lMoFID ^Jv?ӵ TkRuo R uA5N ʯjHEI#HNorW1fg*\>"HqI#j:ңPTb#V]İk N㵙y<YY&wx JA]ʰq-oյJ̸,/-j NiE/Iԓȹ6G̥\ViH^d!WOob7IY"g3yUᠸcNDX?*83Hc lG}7}-آ&uB: gv\gA9qE]ȜZ S2|S}z^WgFMn{ HS36B3*QhkԀ J6g(gD5=5SSaǛ;ɖ>jf! LK5bD-k%ވ`jW,q\5sEf$B+!K V SjH9Plq 6= &˕Y5# 2w8@G*ZVoaܜ͖H:39[f+g<ˋ0 >B;7 ʠlb< 2`v4DFf/,9kX\;>J(滋08HשÑo>vCpC(J͸K|X{A0WiQRs -0O1BtyvWq~!f,)V)&NB5rd2ghi M; ܺ(QM 'f2l-̏>d)s2}5UqA)>*0G &0_PPNդ)EPk,C"GdvP}qrMHKA+ iw 5VUSjS5b勦zPr[kԃzwUW2*hZQ!ˤ6 9tR[|$ #(iY^#u=M|1L]z 駰?`:1=#ҩ @9uߴ3Z^4.KuSgyY OTmqǡɕݰaT_Ro'ӎǣ:=y9ɸKU^J"C^E.U|rdx+J޹멶e m@鲾_m&QEu~O뺘yo5(`Y˫_TF;lh˨Ű˒>vB_Eaxle/V8OQ8rCXu'q)B>CLT'WXيO;W\8DLQ7*2qʗ~M1'V;ֆy+)?2uGJ6HgRc9y?l'z;v2=ywv=>`g? {te߯[U6q}r~%^8$ߵJ7^ѵ,段t[_ߘݽkomoŀh!@ƒ9 t}0 .S A87n5@2Z-OhҺf Y`-l2 7;Oom,£1 BQwj˱8[Ʊޝ"d(d;eLmc$n6K*޲!ڳ|:4лQjA;FL*hf UyS5I[ݛ̘OEV6e*L'Ys 6ٵ3ZH :v|k \rR YMu$c's|`Ԏ?$!)\"L])%\d8H%d>hȮ X`b 6 dmIB!u: 1L (MnՑ;`is6>Р#ghh?K"'sԍ?8z{wNsIieq|b-NOONom 6{>MXV1 OHp^nZk$_{ŀ;m֙Zۄ-ն8Kq-6 VR&,ۓ #M}]@z]x`V? |I8:#C/> z><{!:(uewa::j@쫨!Nޞ9nn`i'')g'- ˿νcsAaգOXykH$x^‰vy/-;v`6LsStJفL\ˇj \t]ܙ1=0|*EO] g*C.$,BY&scnõ '5hTk쑱r ;%X _L٥_}L=|eZHN =¥B:amO_<z(qIR/A>/<`rd-nA6m/;MV l_%=d$ej}_ƾHbyH\Snyyo{ lFLY,۠3K|T9jHHxS8\yb6eC 8nc "ȫޛ__6tEh=ɦ?kkSiX1C̛HOoN{ -ҍ[{ye1a0W/'ѹaYA@,>;խܔRRՀ\j}Qhti 8= Jm'7H<-y~mN֗E_vH%E*'J9bYP7 `%ޟ(pmsk4syD;fsf/Wp rlmnp+7f.F v=rAe\9T,-}»+>H'OHY;='.,%%S闓eI?V s˦8U{E5S@0-]J;sW$NRar`|F:ciL9Q LZX.f@MymL9~',W>Pu%l1t;#E2hjB# *"{6բ|ț֋uq78 GW]vX^wL2#+dMq-Fl-J%#7bH#[hL{}Vn ` Z}g#[o55:e۶lpt}軆UH]l."s $$7"p: cnAQ +S!m[{;΃+ lQvCDA|cKG+lj7n!wWQPeRis43"1wVVGI4K[Œ}M,;&5f2lH5/[a3=' ض`Z=8h 3o|/ (hIF`yqlaNҔȰEZ0V*Qk#RQ8^X_T`HZBU`مQp5vUشxLFTGYZʠI,* [Bچ/8@CoQ]i7/ ~,F.k[lCz>ǣжZjFpZުxcƇgفhbǜoº_1ٓ^wOɢg-lxҔʳs7w^??|h(uf ‘á `lgpTu|Q[ NO&yd5 [x Zދ3 mEټzQi)(vqL: vEV!/>s-Ոu8Z1ukf77F-gUQr<~U?邋wzh5׌w/^NgSw&Y89}+{Q[2v>XV"M Ұ9; bܴW X(|e;H_9dn4-s"$[U:UjROؖO?}~+I`Cpyb|%VdYxRc0(~*x o}y@%c%[{j00`Pըװȷ_9=_Pu1L0)0ss/u8;pbҎEW T|n"8ACfv_` P7s Zԋx;]_1[*Wz7웑*+.edoiC(6:'N21\lArbv%'W#pYR!26'-CYf_,Ha JbEYDMӥX u'J{ ʁl=.nVkG] rUcC%7ӺUXHmY3F" ha$|>.ۋ vDRۍf5=^\[-WU ^!ulD5]}$&nmQP[c(@%q.=J cl46].4¿\lYC !_P|6pE6e(so=pybXޯ^aG{<ECu#=5`n[2bLˊFQ{z9%D7=},o֎^G;N4Q)ʅt/eޖ/X+G(Uң҂) r\ˁFT a 4 *!1j|lo}E@΃?T>絺 qa+l]ݥm)hY7n~[K؛2X3i<^ՒTj W5MyJj厹V/n7W1犸*y9?Kw}!;a=U&KԋxaF/|ehF}@9/̎d$Զ̚D|^X3V&2w̼ծnQViAvݭX?P-nJtQ2b뮚wfw qGhzeyp* lbUV7t*52Q[98vwž1,/ ՄYe MRSeu^2|`bں\IWa<U6#J1wPVQIdŘ_1Kc!Ʒ/~>DavjDݲ G 2hynɭAUɇ//NN;:}.m]`z:6I?O> fKalڈ~8㌒UJO#7rUft(;m뎔X/q~\Wڥ-@m ZR\.!{_ѝz՗2 pb*2Sli aXZD%yŀ6k<*YW'%6%HPr-i0=5[stREm ԰j M2}MIlii+Ўŭ!/̮,mKsϊ:V5őYr Z%#~6]k<&;C\nSQlOUC9BMjmg(ҭNw2+Eb;2A6. -iPT2ګ܉͝pqDoY7l঵r6:lo~ڸբCA-CQIj7, ,o[{Ёڋ^"خnWJ3k-ugOӅ4N>ᣀ<Ч $$uguԄ1JbWL[#d3#[$1A_J/氙[R`q0tUGw0ˋ]^6M^w`rweJ|(ǀ`d:i*>tr=롫xJR7k2N!lH !n}NLbgvUqJz|VE 6;llgt@(dWܲJHs>,9)" 6ðlSߩF=P5ª ̼܆bz(uۚ >SŊTwk۝+!q#f hosoGJNeFk#=&%L (A#+k֤fv}YqXe7,B%E45YLP2<|0U@=9O \r/{J<,Lp!HaI^U$tZVv?V06@bG*\AT ( n]-9R^UcfU8*}gz9"7%j=Iam^]8HR#[ʨK-쪝].WI&{ѢHPQ|Cm7يAȧS͢k,KR/܃}JjorѐTAαsҸܶ 5s{;"2ʇ@=LgO|u믽+&I{R͉fDo} f@ )m=Pzm=YxF53ph=ʃůJ4$Y T]#]_O#'s3>FL}ī{ΩiL4韖j{s>*wl@ì7g4:ne7m񜆠h ΌÓ' h;硷_q@ã_;ϟH%^ŁH8R&nY\|eyׯOVqؾxL m_ C# lb+Y² Agt@ ТR ʱ[j5٣fX~"E* ƾG1dEHm5޹'V蘹5" n2ry¡+'[%Qu5Z1'{] 7!͹O(ʤj[8)FNؾ3euC[zp).x%;qbwMyʥ,)R5GT(9y0t^gZ@X:zUuk֕k'@2wFŇ%Ѽm9+YG`H34;@q茄zN ;1q'G0'܅mYIeIv2)V"c'k4&,Oc=x9B ж a:L[iS#UϒLGI/E\+DڶvZ_E&w ( -RC%7˂^K$j!̭za52yUԑbdʫtj$6yDg6+$ 3\c]+VBBR5|AW'#6.|yǕ(GuyE`6.۷(*8֋WDy *Q]qUr}EzHbԶoX-F ,zbpLL- Y񱆭/goF-v+b5 1dyquqse51b[C-I|^wػbIڔ<>^NQ$A/m΃+.}n\p23C#3 SSye҇7`|O9lu0HJi!"u_>5+6u9[f nŊҲttx[+g\>hN93*CT+<ՉR >r_ҊGz-6oh 1D4>l* 4ϒVH4.C@Oc=K!@l(O+@W[>ZהL8SI;.+)gJxj]+zO/bIxh!WPfInDg6ޝ#8JFnXЅyE(mG[*)IJܜvqTSgܛm(sM=! U[/Q O%{.̐Ol#}51yNMlV#㾳aS'vY,ViˢߐUp}فsThbSeh[-p<6i,; G/UijGq <:Ob 06o"91M]LcJ60XFVn f껉fHB7%  R>NW6{fa:޷_ܡ#TfI|6Mل%y =caS f*wƮBXE #:r8!8VqGņ̟F,,mE ~Or$͡ g Z2vXSMmտypӁ|9b͋sfuviHjr< ѐ7ٔӆ^m9S:xa z{dTOKo1T]V潔owG;&KtBF342\$I FȐR2>&,y'C4 |qnn0T*aarEr"Q͍܍I'**@{pntQR($i1vD~zWcb_.yqr c}FwOz%+=0]ٹQ?KޞvR?jUޕnO1,j3Ï@ۆK%ZE rE(1`XoJHn LBP04bI*Og[tRpPk¶'7,]2'zU]63ץWzozxN,N&Fd/ROytmIEFiT90>|,Ad,%rɒ?Y`I`E5<_؈877C?ON`эf}Ai\tQ\0wNm\;&!m+oڄPX;mLΆ9۝BpS>0g%$7ħ d#إ2ѿbE%GAj)^7F{3@<'ۚM;JN!vz@w[5Z`z#R"`oz$_Dܘ&=- wEOQa+u.?QcM zP8 jC:w ;",ei؏F5Vv4E@D]sCrTl3ؔ t]aGxgIoo I5W೛0s;',q—@^|ɀXNn[IF6:9Ga_ߝήY}ܐE}޲xmEg"*Yۗv3 fhn% 'JoJApx6XUIE/T/"i|fiI֑F}~܇C)MY;7 ()TB2ǣ{4-z+rە γC7Oo-CJ6 U_BSd/J(BnҤ{5hDO;h\ts]_"-?Fe Q>oϢf8^#j6E=a.zpI@=職§)-|T (8xg|~2d+> .\$gBtId,Һ;)YuX6G %4@10,f@ybf( MF?!yX$3wpe~ :VDK-uFW2E 0mK "'0 pv(hYBrsuWExM]ravgMZ}Axbe{>믲KPX1MG&W1:#rlIKLO)@ J*Uc±(hkl*p S_}ٽ:? `Z*6pw$(Q3}yh}|]}iQEc?~;`%l_@ghݭGVsA-/+7Nm k+HEd#wv,۶ƣX$|vI^<c +2'Z5cg>wlߵ~Oj'hqᏵOnل-ujSvU18ǘjy51.%{&S]!SRYPL9%y5l.n#̕`w-x {i << %ihDocAJ6$z;!5]l]d0Z`iͽgRLbSK$v%xM+4cy>;wpɭ2|iQLa}jXsXࠩczM SX/`x,fB҅g3CpF篢(NsoFm޿qXH\*kX['xug[0{.K䕓C>fF#Z`{8c7)/e-ʻX4kS]֖8w;'[kW}o*3>qFvRhUBCw{{X؋}et;>vRwfIIPt(sEהj*m|->>U KtQuUןz92we%h&\㣏Mr,"&G~t{eg2%6퐫%Y:<?`ۃx@ חUDy'vr]ߛxr Neѓm?s8}qrP)$eCXgOhhS*țj4W3̊8uYClnTO,[|WXL f$ Ì=>kLUD#SkˊbYެ !i C9H~gr ^MfR~ "[ri ^$4m! '<湉j蔮ON11UT# d,Һ9"Yit-7yTYX[j]E!s"_oL[1m,v4Tq_Z{{zr~blJԾ>s3P rKΖ'LspXni<{eóW[򩂏K=UIB(t[mqHU?ֱI~-z.i,I%J[&l}`<ܻkzrlk Q`Zs\AjuPܳ[kt%fWFA)UUWMX o[7Vke)!Z`$}uq wgѯǭez k&*Wx)^1 {L;!CC΁,aV~.{,X.j)Y uFAs[Q%qei6.F.ԺgUiV]F(U[ Rr]yz~Lc/d/衭0%"?=7] _h LJhCϭ`I8$m3͞'{2Ӡ luԪdv0I.R#/ KQ0L:mIJK|AUH2wS"j;`Q_R6RRfSpi汍궻nu9/4|%YwYG*U@yNutYr`oǽˣ-#,13oS%ZRso]QᠴqeFN\S ly8M-2R)Oi /kH+4I ɵG4rvxr9MM༟ߎ_67K٨:#SC>իF iE`O#Z Ci[v90_[ыTeCL+p x+/䏍x1P9(V%8TPjstsUۑ0z@ȟ3GV9HHF(.Ֆ")sϟ8`!&#N?Μ@V$'makO¹WMnEj9{{ґ]"X9jHT x_Ĝ]gFʒH XKq,%u*;9k) '*Дs,Q-- h*Y ,W>l}{Q2ʂCjobl\#1 P=zUa=M%5){f%*3̬ݩIا rj~IӼkT@_1C /J[ִh.WJZ ->ώ"M*b).2ϏjrU" Ƨ'[R L \}1EiSoQoK`UBXX~|dY< "Fd4C LQgu.wVg"ALfOۤZ<'@c}_Q`m X(t~)&HJ^d:jc*1o>>3M\ޓAo2q/]G'D.Kvb7-oe0%M6lHBRʊ'rDiERHDX+l!y/}0Ɲ1jPe@ADQ7L0J1}@} |ۏ$Vk?ax?7eeJI,;R%JCߖKDKPDj5bVmK^ˤ/tZ$iƈKX&*}=)?[[%9lޭ< :zb x!Pzɞ:AڛjH&qro`ti|"Eu_J73ey !l{ iA]߼{8XD9"z_Z:>;?uvmъW4]='Yn³4 #`"3sLWKa_މGi`L#RTIY{%QKWè y]'qJsU=c,Mh%wzz?9=ѫjOn2~D2J(,Ҁ6+y](v-b-&r&X m?2Qna@6. [u=- q.0UJ OQ+nGRRMZn!l #P^}jkޮ_ۖZ[ 2U5 gIYJ>Gc|K[}UKJum ?LIot0Ayxݧ bjq<1s1 % > AkWIVy@_[n"m̦f1 Ն 6VeN .%ؔ;1H7Cœ+@]O% e8Ӭc$;ۚ00 &uYys -N8&-:z뻣_{-Y@n(Gޘ,O$* S%JSxu19 eE|n^\Ɛ ,ܸ X:8[$=G3֛+ 11+g_J~^5شzskE.j+!uX?fżro+D¯scEtFaw'fXpq&/)![dAY% n)uN@ML9E /7K#dWj=I;n\IGD8gap*(5IMq߸W!T*JN+R<"nx*._wÖ>0. fۖ֙ ta#3O]{Gs/p"+ؾ课GQۨvQ'2I_mhȄy#2`1wJ)g,Vikޮݪ5mYjdcg視/Z(iMrM3*s=\n>ՉZѢR栒p.Xի 7exGIy'8Mzc}?-㻚foQ\Y%‘j k JuȈDWnc f(We"]dllZ0F!vo .`ޒ¢l_vk z[{0Rn y*:oŐO.?C3Vn:{)B1Fg;XR6ݖC0;E[$#$ؑ1?IaE;HZjF1|9#&NtW_uѼJ8[ n = D U JNiy ?㎸7`}HJ>L.V<fCԡdحST 2 YԞ(f"?,cj"VEIwNLKTkh )+d1lVLН7 EdËyI%=:>pDQ c ?x]uev&ÜG]R. J^Y [si jqDŔec}>vTm͌bTD}|Xy3Ɯ&ZQ4 ʒHOc7q(+R4L'R>Kp>x Zd{zPb&)d{XvIqIK~=U\WDbiNS?+0Nԏ@' /9;^ RVlRK+xY ٚ*.2YTfJڀaV-ijƁJ K YmW$*p|- xCÏ` (%S%b^{HEWP縂C4e~i ?1t8?M nazT_dj0cE&KQԢyFmɊ% JH)l_a˾s3- 8ig^ FrFcѶAȱ]K#'}땢r| k%gk* j]|+Dwz|@Zr>:- xK|7k[0D݃Vj@~[E 9ya 6Ajdv ]!0Q Y"p{k*ȸp˱4u IcZ gip %BEBJ)-|]/gN$/R%Kܹoz͊erLR殘ICTu}L)~:)i?I(|ӕ-ێ!p4WȳLf\G'ch<3ۙ*a" 77{OlckϩyR/ڥE&C|Fp:{R!*ȏ/uހs20W7ø^-C͊t" ƒ;l3S/ԲfgBure2Pǻ]^Lk!XXfxtmzdUf'(\#zM(sPH;+)!=xBz7@F6'_')?UlHF:"QmH p8S~ixꃱ@aۃ!.T@܍w=ſ[:lT˭l]ۻCk얓hkjŊ^zv8^v(ha͒ v1w<]6i9lRJ;)8Дtns(\r(| p: #H~EY/i0١@ eD@q'iks-*'(+(.gzZ,nВZif[gTa{X,5Td{t.1Hc*>-V-̳^+40+2l6cMfr\]Nt_:-kJxPaW3_шBq|w{t#c?c|J(an҃MÃ,k3!b(F Imq(h2鍱4O%Ǡ:0G~ːkQ/&簛x^IGEx!.#`MKx*EtڄF% [P\d4I9Hr^58\NE)xF8x,S6}q'۵/ܬ>* `'稃.htQcG2!˗v`}+;J1P$&k$b9{%Mt5AR0O)&$4h(Z +Tlea HfEW$ cnci@asI+#jT $j}aWpBk;bj~}cI`~kY(܃)PAL VFXÚpȫcuO(K@X1U;(^x:UxΉN{u]< Y>S31F5ԃA>*`{[elB)){H|my&ƽ+d=z~Y m<㆝(ƀLGr_t +sDpj(5Q01kaQ"NK]'! %;znZbT8 Ȟ̅1єfEإ5^V(Վ#ԁÎ*/ z=FG8a@(`Ob1 "б d(abV !~LreI%>Ehd70oIgMh*}Z րp.!+jaإtbc=}8|Se /n `jy{(NzМ|Av(0cf/.,EPU+Г+W BBc@g׆uڭ[rDQ laԉ_E?/6K"Tʤ1&K*x]w"GBy@pZ0 1o bJ', 7 7 (N~~a: ؐzq7qwi!@{VZOa.4$IZI@z:Ke:o oH (o67V,k]=YCaBLͯy? Ehgmmm#xt=(U&孻4N -۲Y ]Ou)˗}D4LH)X2JʜW,,HאQirE& h8(G MڔypJ`YR2vQbE>iy9 t=sH@Њ^28@7vۑtC0׋  E5$Y^ēiQ!c $3yPPJ["< erGd䝎!_UpШ,\=S%ewh5[ӷ\G tF<.Y¦##PQ.]tVP$HuY#S$ُcjbr4i| ֆuU(>KIKՋٲ"i^`Bc3~Y|HKj8WG:ND GFgZּ~xs,k({=8wo,9nK&`mjU'|`8-,*ގ4[Z_u3?JBjWX<>$ve5$F騢2n1YUz dݜKAsěeBojS> S\ /0vڛggBC֫8M,Ý7{ua:^l~ۻC|D'/6[\TOқ1DdGIRS\<14喻dwMz?|AfG|5 tl&HZD*Cr$]L&D %q7kzwz^ .lis8%0IEI06/ar=ܔ -c܃VTzin vSvZØ pg9Ca}ggÒtث e($%ka/d(-ij>^ve x<.,Օ@Wngy1W޼Lq3pkD:0?Q6kL _ |l6/,hq%=rC15WG1Eny (]ЉFr-(%sgk5L+ŴfIw5ʉaox fpfId{o-ָ|lڗa%9]HMpv͎s|Az&Z;F.3P(?5Wo9lFM`es@CeA!՘PgFAf+CUh}yݬLLg?/!)5#PrU)Pѓ>Lf!*?6+mƇTJ_?&Xq[Y|z 8ZG|`w,ۑ+sdHc+O,&9 ȇOG.,sg8JlL]z;+0`Q.m]b4gcrOݜ؏ Oon VȗcW#:/$ ֕r-D|(nOT8Რ򜂰+> mS[Q\68UJ:݁Z:xZqJ#/F?f|4WMgb[$ F~RP#AI߅`էrWM|c/rubU%j&( Z-THٯ~lcw{??tr񟟮=g= R z ?PuNO,pO F*T',㡹=ICl ӉJ049L߈\JypY Yn92[Bt QD2ǀ>4LgĔY_7ޡ;R,=sOTd>L&{x e0dY+CAG/i-{eA8fOSŐ2:kN15C F5P.{6ZPuٵћo8={k|M~G꟥|!gZ..yHʱ=:f },9wՏ+CR8(!= M/<în-mn=闸(t_eK=[TdRH{^>Gאk+{k]G/\Ztw-v.*1B?RCѺu*9W[{X> |Bz,/tKĎ5@gHRszY~]L@+kMu.1!CֆF(o_XvҐ+4xq Yt]ِښ[nRƇ÷NxXӒiŝ:KƂbUiiF `~om_YtXb?"׽_>}o<0 /0 'AQL, _i"K1Oqpo) c ,] A , 4#ByAyX_FZ`,$g`ђm#!h*.]e@h.〿)E896>~K~ȥveS ;'d^I0 }B w)eHU10׻Nu<\Ul.lN*tozl@ Q:tJ$g ^%jyuDvӲc#\28+ /r:[1LMj:|"iƁs6kx)fT̍c3 q?yWKN!ve*M"/'>ߕ+`EPOe 0vgeொGA/S+>돚5+U|gΫpMFF!k3"l =lq> 2耋,S:o|vH7,);;ov;CK(P‚PqN̉,;\Wx.InC|b!p :ȤJu rcJB/PwwsvoI o}( 2blnb|:)LL<9mn .!IkQ`"06|:۳VrщםUՈiW#ځa>''uZJHKegZwl-SnWȶ$vϱ|x{,n?&dh~VJLIQ;*R]1ιH!į{VK[2Ua<+HGG@($G3'e!MZU{% AH\~w.(J>J4MYjeqp2@ RklX(ނ֨V`H)`BGU :Xa.Ђa5-\ cyRx$7zk9ˆ+ u +דPPLHB,E,QO-nP2t`LH~c^ .%T _DHUyd_0c uw(}M=;Ac%47V sT'd,^ j'p]2[N⌽cZ▬$9q*"{O^mHk|eAMW[nl} UrdNHĝ7I \/gk o]bK4_X#5Ň;!zԔKT)ئ\ĢbC7GIb8=tBDZB@3$ȱ?Lj 8jeU_w&)+ 8]>+-37K}n>xsOEſ3[SLi#Z¢~ ].P`(7uVYf?),Ia;GaU'+9=" *HTA>DuG5s6GTѐ1`o hT*,FvIX&Si#R760sV k~fÙ& d> {+ܤ㷆8FK8.WZF.g@x!J<Ɯr:'|!Lj5/;FK6 $%<*VU+ (rQ?)I_f0E/Y]yTPTݍ5%_8B:*4d?WظƯ5)N/3 `K:@潏QaޏoL,4'nU1ºLq iyN jǃ'xݻ [pso;tu5 Iqk$ܢ`|&ɺH$f28S\#S`ya)I1Us%r'^yB,Y*4Ft8w~c A^8 +uTH՚Nu=/jLG0vUgE~ iӑS;跫mQ`#0 pRݾL tM.toQ^gp!\oH} ,za=~,>̀GA HB$8 GA+g-.ra8uvbF@=h,<ϴ+ꨀ7uR ' 1Y 7 bBd$p,7z(h=.< [`R7 89':V ŪStY V1$ĩ+EB##CU  @=VZ/eHR'u8OD4e{k}nGÞئ$Lvc kG7SFJl9xU\΍Mw*N(yiѸ𞹻*ۃ Fxvq ʠ.Y}VsDfԯ${z07/5A4V&#y ;V8,MTaw75@dizZ1VRؑLXd7Y|ӟh0M}d Dn`4((_!`A/H| ׼N!1&`ɓޚG ^ם ?9Y lƒ" ZKyd5?Y$q<ŶƗ㦊+gKY(}_ܿ!SGL^C)h`6S<2#-'x>Rfr&X6KV뾸+$RL|Z?eR3*UJ JvR}VCM ۹~Cײ-4.n]䨶f?W`^?͏tg24tрI>\*Xu2e8 CŎZ~َAJj4TuߒKc8nZ UIGķ4KCsfGG:^O _z#Roi!*Xm) ӷɞkb|"-+,ԠpJNyN)BNW|$sL6考>i0,#ίVWMpv7%P- uk7KRsNgqmlNUlZ`o:(DL5YKڴ@f:*Ɨs(./+`[Km9:\Ldmd^ՍpTgl6 `bghjݐH̬sdN4Lg\̱/'nJ11hXJ(,:r*̀@-ug&;o$VW[P@-âfOKj~O%wKX{V]mkպx,v]V3 D}\{~w Tp;2}^i8^/Urzy]T5;X[|xש}cC10+c J׺,vYcڌa"k&0 $'+,1^)1!]c9]@FijU+#0p9v S)0'IC8&`Vab*e x6f%EHZ;MBzMqGNWl邊"ZA}nI2Yu 3Jtd kXꗹ d +d)'3qW'7WtrCk/,҆Vz/*4)S,<{:rTr#f: *.²%DdZ͚!%Az!]߷5Ƀ 7dXN!Y9$H緧S8I`!ּ<\>?˚ܿHe $|0(Uzowh6. C~E0zd](|pD2ؽW}+F:%n*'jAf =ԫگJYI4%AI/+ލLtyL}8NszPؿokV"ڸ I!$U L\SIQ$!F39-+APY)d3s5UXWJ=^$ygvd[RiPu72l?CD|ߩLԣβal=SL=hy4YN9\%ŒX3hH1r-G[Hк Qe+3KgW~pϢ夵D*:0*P+oQn|_ !|Lvd_pD}[uF_ 0]77 E^;5.pTrW(`9}"yP !\3&'[ޢ4>^A?0vOu]OuE >jpD7Kӈٺb~61 P0q[ YC,a%-1m/ ;yv/~xw4Ԭ7 f,YjNh٫. i]oôZXHSn}Қ_&jaYv4zj4yz1`1y%1wG:1T^.&q\uݮ1_Lda2QNи2S"'Hi.;77w<'BRW$qz+J-[9chfuCR}!qR1w8#]gzɬ qZ'!)9 ix;fCAL־70'NO 4A|mO\IѺ;Ԍ)%( U|Ĕܝo>&:#TLP ^7JN|Dq=]ԛ$Eh.cmo,e9b-6JGam9]7SdBj H]`l^3fs!FB87b fx)̍ m-SGMkU#'B%E^y($T^ZS3)H@? N}*=syH$mq5C!5@Neũ'{C'cC@#O6v;+)GeZP]"\Α2%ҔJ 'H.b`&gED?~j*|Ba]bd F3м=eH / 9K?#pI owRF@9=ʿ)h=a@2?Q!ȤhSLt$h ~ UxN4=iQ:{NoĦ 4;0R5,Ԍ0 Uqyިm=qcCznK AiñUY1(էFռt<:>p49x{d9Btm2%A?t! hY2ҧMOkiןOwmUy7á;~5 qSj^U(tqNПZ)}HMηm}|ƝñSfMM859cX%x0 }-ޑxI[}@w O"Kp**s~awW6 FVWe햮aq@ԩ{FaZ;A~]sQ Xeo(.P OWɑ1mV[ QTAgw6u-FoK/ҫ{@ሼ= F kgզ2BG +KYM!hvPO8'Y _BVLlLB(ʫ_AȘ?ڭ!9Tv%(%` # ^2UJ↼)ٮlpUF܁`n t`*J]u44afW``+?>|lW"j饨Q9n\_Z ^c|t#_Pr?޵:͟66 `|%J "үI`D{+*_,-/q]m t$v.U_B_&+h컽&GLZlvogwhuJfLlP'd=JVhs2 q.g1p˲Jbɦ>q/,3G <oMy,fA.0+iLUueUgB6G:֣J@E Ҳ`NC=\9Қj@EV]YzTpown浽gla`2 t:!DibԔh럯~?KeBchecksums.yaml.gz0000444000000000000000000000045014442217575014616 0ustar00wheelwheel00000000000000}de;r@ D=^`Μs}H(GCH@Oz?^~y{-yxrLN5"1vNy}>O|2QSL cqD\vY 9-3ٟ>i>tMo8[x͉]'?Ղ)eAqD&qBZw6vNOk[V#?IuIdvrEFq4 gtZ]:'|DAOI$gijÛ4#d ȝO,Ҁw5 )q8'"QooDA0RIpDI6Gh$RN Y ( `1P#8z#X4C(< Ik!N8XpN8r7&cP2")94̋&7lYKHtpqlt CKݰ. $^6I6yOS!}epY-`Nk7Y6sww= C?`t=g;b>l.㏋\H ld ޷.bRe(`1y߀I6X/÷ӣ~?q0HQea$2֜(GN I=0I3mR.u& 2ثf:46dYL'M:f8,:EW5et$A%Z0Q!\[@C w ֚rnneTem.^ &]Ӂ!'"yO0&w'rpQ.DX?pBlzlr.`9]V. Z2 H\pIUE9+ذy;> 0F$ 'c@oTQ@1cf9 >|0)|}3L&HyLP7nbDlh֜hf U8 `@"s6@Q7Jq0i8QUƷq||;\l(oY"@'N|Lk]e~ʋc "S  3ݷ\EYdipLQIc 'd ez?*eR䢀s11h|t -72pp-uu~ݿVʆV>>QBe"TJK_gL'"g :G(8S}I`T s6.8`üY0dr%yLq ʂ[@2r<Qҋ%&D[8èF;h._H*QrԒ5JujgێK99h)edq4"GV0}T6~TT\sbDL7WfP)*ֿANDst.u kj"Z%r$4S2}v\TGq0Qœ0kn$aF 6/Y:7 5hrcZ؊J' \0'KB!@P?EtL3:a *DjE `s`Oڛ{ǎ<^M&,ո1G1U8n?WpNUF7òo2JL&oj 䅜qI4R03le5LlϷEyDT#E.hϨ~9 #?M2^r¯FXmr|O hU4( r!Cy^%~rόk04A M[nMAחWoMz;Nws; ٧ ǟQ ՃȪލ T`}گ+V&aZ/)d{(ר(=zp;^(Z^_?=Y4ysF;ҵi߁7qBd۠!ҔcHODvk^ikoXw*9 k(n1A)\Ժ3e]Ъjh3~ o:+筗߿(^ʽOZ{e͓/v-\O'GP⿕A'`޹fSl'w}f-k=ywt/gH|@ 4'OjK$eo?ssŸ#'l6܇m#,urd-Gl4t56rt YtnA<؁zgd HЃTZ?/.O;'-'NK#360MF͟nΆ=nc|'ڙN EmhaWԉAw#HS@=:1M#ÑσdfhcvNmD㐞Mb,^1;'' [8/Mij÷>_uțm_GZ 7@59twr'w=a;hQI9;N{zC(6";]ܙ?_u:] K=bi$7kT1XӺg^iCT6Et6"crj?nut>0 $ )(dQ2;gYx ڻoΏ~+yAȏv7ßN\~4<0Z힆5?ov( RJx#;SAd^KK܂|eٌEy65NyOAxu&hp:b at.w}[TR7uHˊiv}.;P G^xaAT<u A7ĕÓ_XH&_,֚WjִJJP!gk͵9~?;tiL%%Q!wvNarVB`P}Qpsodc+d שWٺhưmǻ t4*NM-ߨN[JHOռ<Xbē__ntm?,-og7z6SJaJzt0eϚ8+9iD/M&UZ`8o=o}ez%mz9&k™Ͷw7Z&`wIߢ7"H|FVh02GXMHtsߢś7tGNCl}@ d(fBşPh\mꉬ49#AE1d"ӢWuwLQiI< `ɽE >#z>0o$oB]y՘7ƺO`KRNQ,DyiГW{غ~6~G $jRk kbeoF؞>u+&f(WFoœ4ð:>ےW0FCh+dL,Ж-aQc6224[akX; C]9H)A#4vжf.?-;1mL#0rv#n€ix wk#_X^֊-%5C)bˤZԼS{:yӔ"qCG">UIsLs0Xސ\v{":2pƠZ;F0gJ3?h,n3d{*lSh@Ӄy(FUoiff9f;0I,9l4EwGLhRn'vJy u84A,,: 9 0bhPDYu tW] ժ$QXD9Yc^c?h::t K&舂*ȝI>c+lh<۫4րCtOY5I~E>>Ŕ 4-UP;YoAǷR;ÃEt G$-i99X|͸rBh#BjNԗy˼Aqa۩A\J8ٷnQUGնAqQ ӛ?g-TDVAyCb]T^)TW/Z/GNƌb6X ņMe5cݢ n#LG˗:y(DTܢuOmlds=!FSHbY uYxsD,GBkqi5 De=y(3ЫSh\nwN:jmpCVaQMצ*}B^lK eJ-!R|9\*q9E>iIN+ɀSes-yMkٲ*FgI@=R܎h'l1V 3ªKJEnК֙^ &Y-?, vB e㢥g*=gG `Gf'OĴ[bMkJR0#OZt_{^e S\pQpi (ܮA+a%|v{%k@. Ye ,b*1/+(䳬RI8_h<3 Qu;,}T"I%]mT8襩Q8tX2Pnځ8 [FĄ{b = E,F" .*gj$U!"[Ԯ&Koݢdk6{T`A7O [h"nʝ&r{{9c>^^M(N|/&粅 ' E\_Y(_5TA yTats$*}}i).U6f 51?eMnO!kgCtu.yWmgn@2ok=ccN\4UsLUF#(l-jaRVg[TE}Ye3[;ǮGven\ۂhjln6:ukcp_$cG˄Цʦ}Ʀ^G8Fa|#u0)G"̕KALp 9{4,ܒ귪I/Ǒ"mW3b- /hC|\RI~o֚Ț\ϗ+XFa~d%`H Z8"kHg5n<^Hb.LO+_VsoLh}%_btӂU(ԃ{-R UZ؊뵬4"y/oeM0Wq*ks!]pkW4=a3ŀ~(9,-Lzys,`V&őpm+m Sn۝nn9pxXEMU*?-jhZ9_^WhQ[:[>a> r+veIiiP=Ļ@&H [쟵TSbvU3h)J%è$$RWѕ ocή8eP=\czwaB%p[;ʻx={ڵ^oQ.{FӟQozGvlL+Ra{<vgkOx}%l6nS|}<9=9ռXS;6dIe֌->*_=+LK hD>BU=(},  ]MA>?֩MҧskJ!&S P*w)( [,yu^ROSzj&,0,<ۨX*4Ө@EGQ5W9YQ5^^K_ q㚭XLf iwJ!ѪJ}[/ e)?kc[&h XTcu%q?@g !uϐ4au*lnZ{H^tmxk7oqjMl&4+}T]B>TC=OOj1i%nvQ %r$Y P bX/ox7Ðᇪ mEmQ p8M~ Ya>MkpA*oFp1Y s@;Y;U.2PL]|f;P+ 4ݖaҮnJG7]c}}b}rQHzyGƭw~rSEpcvXʧgN}ZM"LI9sH 6;ip؃NF\Gژ>b L;Ic8}Vc^a[z"FE?M{+ AO=e0^JBPou&D"/jjmLÓO C(M@=H4lj{jVBwP6~WȃO#SD%4h()@J6} H,rߨ$A4 @˦8)D,F[x1 BUsP.F1-ᳩ-q1 U7f4h'݁] Pk,2gxT= _@E% vvUc 64"CnXĪ/1/KY֚|÷W]p[Tņ̫)y1kQ $mBf^GS,ӵp| 9`\٘:h1$MѦmʁv h;YG\ YtYZ3--ax<~~cn@)Boܶ`ܭbM4Ňi%[՜=j2P:qK!3_cS=>AM[)erϏ;6J;aHCRw9:W[˓컱^ WeK"/rP6ڤξFk9)9(i=vPgFV A#b`@<4a XLd%fbf"N2zW7Z9^1+'yrM,4/.C-لydDJxa$+،Gr+ TZ;6[ Z%CjYA-!lfw[;2>ۗEHCX&Z6Eiџ G$7fNou܁ĿñD}A +4NJŴ^[`>0 )7j_7˲s"/;sPܗӬd}V6 ®TfPLޢaV\U{J,xFn_o/8x) C?#F)ۀ ,J@tǕr] [Tv TTKUPvMgoʀm1+Y^vv/wHiNjY8.)-AI#K ˄2؏qPӧMt'3ݣn7gsSw 9* ߹^KuM=8Coz#zS@{ r;]F{ɲQ\ro7,Fd( $Nˌ$mQ@s*[C2YD1J? 5=/R @Fx 54e=a(x Ƌnk[ 9}שj-ßEnr4QQ%( <3nP= Ncߌ(yM䣇!J%ׄvGY㗾ZBZi4gk"7W\zn2+ww OBbq{Q^L(nliaTb.7&Sh]d_)zOϖն cXO^O]&1ȡG 2R ^4 Ώ* PֹH(3ug^ g{Үbmnsx6PRht ެXqsjqAN| S)mx|q?<;*{xܮ=z}P[{巘(QsQk'hUu} ګbt}s٥DE\uV4VFόy Lz.6K\+v:Z~@-9!O<=QkC-asZ v:xTgY~q,}b': kϖ7@F_6lJy B(i=Vwnb뵪{ :isN7+gMc6)3eTG?2n2ϸgḞW8i_4AŲ&e/(_-3QGÊW3`h-2HgC>o ƤuA/S|S9TIE=n{~S/uQyŞu6reb_ Pkdd67t= $q<3?]L>ûy|&S[Lv"?xc3y?`*=g3e^I /~euNJHnO\]ؒH6WΌ)\+s rlꬅ"t򠽍u VxeOuH T,T &g=P>hqSÆɡpŀBkH*Db+,cW\jEdt3WjDt#,oOxt{ RI ש7Ŵ벐Hj9 OPkGjI]S/EqYYqlވB֔b1#.z,Qh/}\T,v#vȑU'ʡBKIS2)xٖ*,T2UEJmk*uEew1sh㽝\BꏰNՋx|㠂֌a=3X%O YvsXx"V—[_~*RPNjűli3IKQpSh IUa+dKHVr?;܄#ųjl _-SSń#EN٭6%K‹ GaG9SQj; / 0QS׳Eʡ_H/Ud¡1̭aH2(7Xc̫i5uɿ2[NΫӪ#-K3W1vC\B{nv<Z5z%Q鎚k>)"[smOW\exuB.s-?_d˼5vmH],e׸}A"ὈL̢!7!Ab뼲%owfJ,&1۟1,`NQ'qn r`aHWglm3QlTBNo$) _T5ʵ'uDX159^aJU@ w˄KFھ9X4)*l`}D}N'$CwTR(H +l/?Ss=Rwi~#cɵm政!yMfAvYؙ[i/igGeFzڲO?کr`~iWC=Fޫ >l;Ԕ$/L괝{B1+> סMD| b؊F g\'/5]-ԝ(&wHW 冿eX>P"bt8 hjhҥxmV¾ F7Z?@Oo=ae |Ht=jUdk|ys<ޕU4t^eQܹC\cjk}Se7Z-~<+Qk5޺co\˜-a>" ~8}(Mx½vӠCF~-M|srtG7`x1IG(H@_gÏ5rn=mqx.}0.4y_Β*->r,ӑK $@}0 }ci+QbZuA[.@Wϱ|tpuke2@ RVᅷ$/:ՕF#֠+*kUOO:]G TQ6]OQ,]1m^Gp^xb~<6tVrnwͳ:`Tvc뀵LT"ڕ̫<1HyrVb &QStO]:"n8!J?f$]D5?1}&D"=q?N]{857cQ^*i>r)m:ɠK*JjC\ZVױ8˞ FGK+[lYߘD٧ۦQ&{Ξ=t']ۡT==ÔQf1gj_UVJ[<#]7:RuZO`)pc:ycc_U櫎7TLа4SFө5ٹi4rhZ)E"ՂVe5i鋜q* fRUIxY7FC"^, OZ%Òw_`YV0Gkt0yd?2u}uKÔHM2UQ,0cj+1$ԤW-RIҀks[pm .cH]:#5Z᪮!,Hb{_9UtʗM #2{l< rI_XN'+x !v?U!Ay,YUغh-*]Vh!8SBmRg KXǙV˭t6VD*5T1vǖK̴E[sQnJސ.Tv _Yv̯-YUaBOa+vH)78.6.:'k`&6ԋrQX^0Hd%uAPe8ldx kt!ءƳV/H@Sci`V;LTzBυ]퍕B FZX;LLù`q0sbhł$, rh-/ ֌.(s*@& Yl<8=F RհKPEo坝uO;]` RS9-=8 ' KA7 ۀV ;ԇcjpP]Άx2+|bBi%,F1}?Zo)qbZ&k|{@4t0LK1ͪi@T fAY^B Yhp\k-w}ހop"&Jֻ79@vTZVH!aq2 ,(">3([Q_h}P"QNڕoqG28r3[Us 2:|Ή? `v{dWU:]X`NJ8@ް0eXh,Jx_vNry6wG+Py>S{/As=s)/Z_;_ݣwBb,CEz>H@w^=im.llXu}NY2g, $+!%3%`]~.PI@1B{F9)d5 NtaYo\-07:.҂[J_ qlAi/sehjߥqOUK{'eպ e-]i?Y*ozG&i_W{ixuF> э.U]긵#yG6rqxo0_3%ұvh9NɳLt&Q+ɕ4qC hjؖۖκ2w!ITԶÚ %B2[V+4V:lӆyV;uOy+46o[}mlE?ˋ-AI\/dn(c)7d6u~ɞAkv~og΅9;?l8xݨI5BMO;S M2H ։~C')B 2aN4++53wVIōgn׵F΄Y?5/f^!%њCԻWԣ7) R޿f:.Ѩ["mkmkY34zNI1쯲3Vxvk5.ek}P-/@gGqH^\i^M,"ο[&v&$>$!]EH&}7J*.,`G\8FPi -A 14R3 β~bG.#OD1i4OufEv] z|+z >,20$3MFZhX rw.:÷_,d' #`xBW2k%@s NzfLtࢁtC0CrVj< t, ؾ8O3[J0"տQNz T3}u8e#y]l|Q'I/5n*ԭ}˜ҡdhIc1LўGZE @ƪE>in-}|1?n%xOIDJe*3ZVXyiib1m$3韋 .f^͊Q_T_}g%L0r^5NQYN;OɛieI]bH@5ԆdjVȭ?eE&8P8 =Py ,;0678BpyvOo'yl!-B (#ߞ51, Vya>(ڥ[ cPӣr7wS"KYL 9*Z`JN& *ipSL;6Z2lI!j-*PVy*0.||=#]$^= 7 ӭUz;]S9JU鯛Dh[NTl+x4F 5B&tqn U0 .R .r"Mގ;+n V G y<Rojt~j#: {f|=|ZP42Sej/n\G?:Kʲ95:q;z*y ڳB+7xuvޢʯrpZǝز'i%tȗY& ¾%`3HZ[$-dExc> ehs.v#VݾC#?L{ԭӈAViDv֦9fhLN=c MY -4M0"sv~: b4J~G~ljQfq+R ҆R^Q.h!x_e斲qJsr^I(Y"{)Tl8o-qI4,%P{sz~SST]y]h9]`ƣ5 S8@w ˍ燵¢3I{+ѯdDFhד& F\F q_58.%>Aٽ(Fڜus8 bӾOMh]AtKZѢuc@zW[経>μR}/BHGU)waG)@6 a R8oLSz,&p2=%TѮ*@_Օ 6[WUjV4YDp8], H*_q8FĈ:ŋD&L6pc4Spӌ[;+v.Z *Rrjl`8M!(oj.T^>eeCn;Q( ϸ#;7/ Xl(|\c<յ5WM-^kF(Uܬ䂿g.qկrgPp.ˊN9F߱Z%ͬ~2.E~K]qzښ9Ww2sCIw֨K' ߤHv|p W{2B^h3$o;ݽX_QuHmǴqG:W3;Stūe!mlݓMo7i۠n𥛌=[AhUJWTͫ+n[څѩʻt1 7j4dq\t nTc{VM^ zjV*67]43ג*/9;_vNtKtJN3Ju6XoD9֝Ca"NJY]+5B}]Eŝ~ŝ^̩ ie|R7}o|Aa/uw֎e~]vH `;]\r?\H2 ݾ_݂y[|g Mxqt[Lyʹck 5q"Cfi䎃>-E(G{Ra}|*ea@|o5{c \ l5V̟l; NqH BPًewk -aM.)@Adk>Gg.ĿB,L$B#5Wqȧ nٮM̞R<7l*am:XKlnm8Kˁ"HgdNxtK>vUiÀJUY ׏̈Z{$U]k) KvlI,KU"e{-AunP)F%^[<|Wp4{\C<6][b(>LÂv.4[miRb-%^dtHU|CMqYoIbKD'Y~}|ETK7}F&+NBwfdyӊ%w? CFhSdQB,T%}Q5yOVT#PT"G^,*(nH-[_VV\UGT,.TtM^"+,"Z+ cųSsTA- /^)x3u݂.+گr_2(2WnRGBʊ 7 65HJ4 4YJye¬p8<(::_1 0[ʕnk nzmnq{+>ܯV^[?ab-N˖S8'l(,mt6^|JϝqD/viÚLkU ]݄=%PRi&i7vdKBސ8bV ;쎉aѹ2DhC֟Bo,4%Qo{hƇ;g%@Med2_ISM.:^Te)G~;=?YS2>sk!̟] L/Cp;Aٰ1Uwb0^`8X;|*4j١#˸)yBzaٗȣev~>y2O5dB/M ]3s-vmrhaPNJ̿\?u(j97Z!U f4`cnw۲6Ѭ/ngpz *;̀SpR~gHrhJxQ:;*7|qҿ9l!A5#s؉ a]wUPn0A X`/{K>gK{t7X5XQrV8sџ-LDw}syΎϗUxXV5bv(|UԹ+( >De!u ৗ?<2rh_7#w+<F3n=}\>0Ky{Fj>P^>sW$!2J 첻[lsYL+>=d>aǀQn`6im:J,}Dz^6ɻI8-)FQ0x^*|TYkDySלe4;g0Z̮@ 1Kf'%G055I=->Rv5PT2jCTSԟ$ QZ;, q K޷7q$S42FFOl #@'fm,?Վ i ߪL4$wƚ~UWWWWW׃N 8zj pd@(ᜎͭ(IjЮuӞ2Mg!2ta#UE?xqǨJ`ޔrDX" Exց LbE9pr^۸pʛve4};4grbRK>YJɨB/a)AX4+D!GPak cԪ2 ~p'ă(W> C=opa <$Qmg?ye Tm~+1i[tQ~` 1aH @=CxL1 x5*Vṕ1Jt T]׀<]?~HOxHgV\mX9 J(V#8BŔޑqIlx=jZL|Oӭ qd{|(%iiݛSd}h, W-oiwO^;\.Z0x>#;%-6٦g4Cy`܂\w4Q7oԫ|F:oԭuz J)6 ިݭ~)m6V6-YnlֳMi[@zYeohhm6;6!˔joөeSMPΣnoqj$:Z%lg kNqZ*u6;uVvzr^­ZPܪY^MlZՍjg}G6I[YEUlRbGUGؔ"z[~4%IJFmcs=ۜH;~-8'vodZPls#u׷۽Ls۬vMIMw,S$vaN) &կ{MI^Hҳ0$F]Kf؜vk}NE5G{"~$SU|V;U(;Zy c#Ӥ@^MJ7[FgqNbvj9 Z Q4|]4)AH;j}T8)%#v/ۤղMJ}}g;g$~P[A5ۤ,^m62Io#j~IIԳMJ[lwݫw:&%|?s 1}u?CWX;,i=dvøŔ{$R$NʆI#.Yսaq,Xgax5A|{QUџoU/j !o7P_Rƪ̟(WA0\PoYy|r%*pr3\^͘-HZի58MZAjA1;pȨUn?h}+rAoͦΜ0^i71>堖(*qu8YnTZ`I͏1Z*KRԇaxZn8溰Fl3UfCE1Yi`AP  ZwCnt܋Av>f)Bo ̲71$ ugXD"/׫K F>P`^vыz3'#x 5=L#\@L0/ h-hpD7PV:|= p&{=&'dEavD%ȍETp6E4\u󌝝lrp`ӓ//O޾?mzbO^4N z:m>:9=Πe ߳?ޞ6)ky{ԄΠӃVqVbãw/(.+tOZ9j lN^7yzOlq'<|wtp޾;}{r`8ͳãƋ2#wȞe)nN=oD|?7Op'`j`=Xӊ폂 O{j,gfQ3޶_7o+u.`#歎<5%cH3s*V8HW]|RK$gI4Dy?) ~ MT7j4CJoh`huUUI4e5@誮koI.|J+$[;SW+8g|D)2!y# &ז OHwhq?&%6 8fmYoaj6ts?[haҁPwz,QNg`2{9{*E>7g /z 48w {Kg!hy R{`C܄|iS;}o;_J-M;|½I|+f %ĪJGxiL&/- {т W'U f'bh GIJ*\垣kմ/T.kЙħ wKr9P{v47]}7K4דXu]/TnSٰ8uڹ"CӀ--"iW^i/b%8|al'<1"3w'7 iښ(-rI+͇MȢK:Y6:)n '>^B/| @.7G*züR}ซwaׄ)"SO*g% aZdy2I į->=^ u1,Bf]vR[YX|Lp+wcߝP-%YqrRll(qWbi2yۻ FLAoh)-*h`z7ȩ#5D\>>90deK &) 6M .iNj4<}V,@$.1n0 -:jKcZ%My_Jh3 5^͆m-Pc@RR,oLJְ,@ˢC*.U.KEEC5'^!:8)Ӽͨ,C|B&3eaĐb'(-߸F잒B;)Cx69ik+ag0 ݏOEF4"PL7V6.aL"jVK ƥXHI##^`{~57DN{wʠw{wI洗)U jGFQem%T|z2Oۓ~*"A&7 vt"!=/^6|s$o[寥ohF[(. 8R[ؖ[G'GG1tqTzyt}|r fWMAF-z>飴8zZ_NӓSV٢>j%09(vj`Ye0vu'1%_fQX u>S91 pPڰp\ħDR%>9UMc^,j5A,GG  Ɛ{hydhVg{E[Ύ3ޱ_Zxy8\JY>h@MVăwFwxM[DV|X{42JȄRgOU&(&..CTi]PqcKĿRfǃZm tS4z%".D.ދ2*;x65%~G;tn +@@|i.u=b|Qw&/1Zct0vzQ(E> Ta֋(Rcbۉ{Jy@Ep gܓ͎gkmSun(W~roD_Вo5*"o"Q$JQ+M}RUќF<IbS,YcI aŢsʌBjBY[Uc9(<ƪzp]6*ErŽpڲfv{` %]f0P$W㇒w.x &`-3]jл~̂{2b$[ #MGR#eXz>lOx(vP]>5N߷ѩfO0RƺþkKՉ"sbBjrw`~܋A}F 2ۓ٬Nz.&3ںW],si!>57W [kL" 9Upw&wotTTM+zDS4hRLrqKG$L0aǐZ)wĆSNi{\{y_G).0:2CIG 4 HF<a"r<|8 Y$eB)X; \9(M6&t+$FV;C{`MnpUdM'(iOIwM'5/`ע`#f`Oq>GGEJ [=,\LٳE0XI|VхJb"?#ncl 4 n@Mk%u 4XݽN I.x*i!5Vd-mx˜z>3 FFf |jM$kȯ `gweﱚ`2Ɗ9W6fhK R5ΝEoo O$ĝR#Pi8[#AѤa`,Q[ZnMo5!k}3{L{76NGw!$Mk=+:@s ,ƚy [:x[2uߥg˫`vC6FuU%",/IAS˪0$"W]$w|Dȓr^^4rK oh9 $M)uk3 x] ;m8W<({/7OhiIJ%dQ#n~sCU:(#/5@lJ-Km^$+:?WM ?Iɋ HGuG2.U8兔$bX^Y[҈{lXתygCH6&eO泮.ƦS>b4oPfݫf]E :h76[ucBjp[L:wSWwm:cOmm$5!"*[6w8՞7x@yZ&$H;G.603iHӨ)Ĺlyem~;i쒼,bm#cM*X-YVAiUi8?||IS) njhbDۖl_%6\._)Lw&%B^mn}ږ=13NPFTENUrsBCFx)5dyyB 1@&iO٧vY-UxhA<&zfFו 6 6Xl`ͻ}瘘:Y1"sΈp@P\ S{T7μߧDM^g"uF%ihˠ &AI< k/hPYW(x$L-ȹJ)e$׸O98bӘP2et A@&oK7& 5~2vĖ 9 U `976Luv{\M^<ĩ&ʅ~c\I% ch'}œ$bnC0 IK|HJn# M6:{Kw0mDHָeeӠ[«kFǝbneY %t'u iolԌ>;H/i:Q$D53LךߍC^JQ6ƶ%pm_dMg2=! L52@$O`Gj]Ţc: [VH6+c=Wo.D>GӢiѓƒz0YtJOXZ}BݴNѸ[zYP=nȊ 9iH#A0i#;!˯ltIBl:2M3^>""6Ioxf涀vyI _1&rK&kKjޜZho6Qa62-1O5_b~R9ydl ޮi": )h]9P\OF ;ޟXU~_1wW~fi|[$s5umYd0oWL5mL}BΞфG*my;o%61%D OFϋ0,)#/!Iz ƃY\1[bʼL=p3=M"ל)E6*KRҞ$ui8oϏ?=ΩFF!9ph16Dx}fj-hhV5PROOjq9A G.%yv=|gtp6NGR uaLDc_ d1,AxxwhRLX&U *3#yu<DV-OA٧}BrP,ITw!ZHT3 7!)+ YQjmUgZpxujr706~yp@H 󇯚ZnGBBM9=h(<(_2Ar2U3NA  {h* Ӧ~'^9Cér #ѳ]sMWϼDw-ߺU>K66wiOiـܫ']i g]=>tވlCU+٣%׉v~Yd.cՆfvKSBz3;Unpc%Ip._sT#cFzLq_n5Zxjd3!/GG<);I՘?/dXJv}Ob{т&U;`a]ې*I5_Im{PwO*!T{ P4h_⚿,_(!JzDd#$kFfLfPx%RR/TRwUӳa.[U2WɁ 5foG#SFU!2ӉX I+M-z/fj u \I"p J(ItNcXf1&y MICf)JV*JCH5f}1ֶjxjW?߫`K .ڔk_TmFsK%"Z;j_7˛ygvZ__nUwx^QѢ!Ikݲ,So |,b׃;N=Kaês()-Vl5N U Ng{8e|SX6v”96[1sܯ̣ieva.\:^b^{>vQO@Û}r,hB$mLhm|kх;_)+cC@ͣG$iSytF 5&k.$dzUC@hX~Q1;Q81 va+ظ JV-TE`gkk:L?PNTQN&>S]菂Ȯ_\ϒp{ڕeIN_ժU߬Y!vCH*'D EJ3wo>XirVw/G[$g]\V؃2^bN >F$)>u42Y LvN2}'D~wWLO Fxbn[)vMN8o=@* xKG}ieK%1_>a=֋%& Ur&4܃n'`9ɬ<+z,ΕG3ŋ% )"GuyADǣ.t/>TʫO*??T.griY>SDܽ Vh _ 1Qee|.jpZ;AP%˻dNwߐ4,dgּ=&?VF"!X9AiR;ɻ9BO ¾}Wkb81~:1[du&{4d#d^N < kpκ O)[V@o.Ê͂)HaWѫG%vaUC̣A.ZzrGPr=awOVjknǓnH<NrraI{qHڱ.KS0pqOOt Q8UV|%@fIzlP'yx=5J~}|2 zuiPuW%蕕|`r+L; q$VH  ۫`p?ÁyQZT*zW>SNxAmʑv4'i_k??鵇 <"  SWUHwᰍBό_I}UFht6*N!b^6O޵JUcR@VE|jW6ɦS tTH>7E38oܟSyMH6P`7AZ%+#u ֮OL?R,hc?4P -UʏCF1"4l ֿ}ytEwYޜD4HV g x+Vx1r> " H|q53!{`s~*fPSL{g 81EB/VY\@7OZ^_+B2fJ?p0*v0󏸺xOr2gOp;.BVLp}8=bЁ/h#x[I䐚OP|CIrSth$as]\D@c_pm_uVRC?Q!ֵ~@=fӀVZ=un5P&JD;yW +@5yEʣQ? E5Dc (DŅ,lx`0OY6 /Df-0q^C +=zO5NM)<ԨY&͓e 'K`:4e݋I/D<>CʂThCVbP*d`Q#l@c~N.n:ot= fic|]䐪RlD ٣TE'~o$|xO\ BЛ 9KbYWo8 W1$6KOIb_~v| 3CWHh*VIpx\pE^cN/9eq?m%1+4 ׯ6kh ~Bі,kq 35?nM ]`h֣eEouvh'hj/~MP`+%n5F_*? =`br.ƴ/.HDeAanF56ð1wK)&((-`z _/_ Սa~φ^wn%b#MF Z$n%L\18 `f&.C Mez0;VbH ŒF DiÊC~ɰR<,Rlڸh/a`Y-ѕ? z&mlDE#C2m&Balf~a<&揬R_Q)dHۑ/X*`/Y"qa)91|̌lqcm]#cMR)Op{c`1րpAI?q晔!cyh G8}$߉O#Ye4"cL)}$: g!J/2F8 +"I7+22ù QHk*?-EQzFU :0]fw{|ْmVd̐HPp>[p CuB/0[EJՉ9R MLh> &~#nU}Z-usETWfb#KRD,WeptTX&_~&< PiE¥s|rvx3bu*5gW5b|x¬Wճ3` IuTZÂ\C95NKUy ܤS#n7n ᗡ8`֒ˋA:N Ǔ8tU B}V%v(kt"XC¬<6QUhUK)64׵}Z9`A&79WS |J_aw]xjHTم4/aXܦkkq~kx[{b*6Y= e׃#4/bc#/½8Gl*Z~a /uJ-m^|;5n%3n/ D LD].LX&4k"Z⓻S'}٥,~ L*e+@I~507|sDnr '2H!Jş_['}31aCZU 4FHV#V%j>;'Z=>)/BvָFKDQuIo"K )BGT&F/K+/ئaa1H:Pt":[ar_!9ғ4n "~<ŧbm^h4{hR& ț9GE̸-rBLX~G{udX:2ٴ:0 YQ*=' [1kƓeҼv!7}w̑eSXs4%YQT A]Լa{B / KX'K)s{&µ t[$1 >Ábzr7G3~Yx0,#j)ꡂuiA0ja"mڲ%xYWeט"e D' ~P?1F-VrEN214I,A:aIA A*YI@ɥL)ñB)Ln*V %bNMsmQ󢧨—% Hc= kߧR͵J|ВSGͪaPQ`m9z,o$#v(5.Z)"&7w8X2iS8 U M%곔fk]q?yUJ] 3jQxh51BM_6?sgrK}^-B(XިT9!K\ʈ}^鈭aU<ے0NA[3J2,N>r>f!u1ُnFM6wAkAPZH071:3FŖ55>w'\H+P%}Y^ NdD 3y(Ԫ aiM9m% *[6-Byi #&$'iq$2Ɣd Hj䢀б >K[bu+yP3#pn $&j9S'L . ۆ ms|%'z#j/+fhe *L6=̞9~+ecED yQ{ :'__^q4+#E "К 0)(#T $ ?9e?Eл༥]cp,*yvo+o/gYQS/?J\=ِsg#k ^íGz(gwTڧX\_KS7âbH= PkDѤV,jsqD;5 +4"xϘyx7W% daM T"s]"?b{eg^蓣!2=g\L5U:[+"JM%#K3!TBp,4=wqs*@Ji4R1fg@Sx4 ]} $f\V8TMZ? 'S*75Z()5CȔv:8 ׸e9d /dRN,^1 x$OA6vSDf*ߑl MAfFqLr_hbh,Q cJ1o1(bMyc^=O"X4vdO`m1ho՟sh(5A | ?21v&Si$*rϷYeJۙ}$gU&ټ*pIuW4#+njĤ7‡XKۼFxE*L e][ȶN_`DS8Y;(ZyΥ̏c$rsi-y $B\sb-JKױ {r*~Uv@IJPK9[Xrº*3z`ndm ydbEZw̴_y F0엉݆p=۩)Hd#xŜ!"bJ+Zo޶Rg|vb0 DӨIuiϮ%8TgsQ.wuYI]8gO6H y+_p^ZDnGX\lHb; o+z>]Yך {&dq)PZ)ƥoK0~&TD|mA5dfW Z*@p+49zl[&4;`,f!7^l i(S*)66ZaHkk*Yu`+m𣚮E͔ n!#m`fGR4:H&+_~E;H+EXJu7_h )EIaET Wȧ'\N Aฝ5W2`|!9Z>L4iw#öHM%>(d~ԫ z`7 OJ:lŭQOFZ0G#`Páb'5x} Ktݡ:ehLډy扝mſe \?M1 *{(nq҈|Uv)E=I&AZ!֬RHEH@\(_b#ZW!=1o8=_,@\ʳ")S8SvhX,kP0Os3ƺ<ÈH[/UnSn\Wp%&ǿ]hEO[Z(u>d>MлAo> v v<\Ÿ"vUe.&4d'gyCLHeP;ȴ2!N3Lu?goyn7\x=:wo?\DV߈[4WVx=žǵ^ #Ю -Mˀז#5YԞp_#+=9> Lr`I6`REWRo(n:Ir)Iz1a%֙],Yl~#Hu.vpt$ GG_4(Ԩt]? 6B2McZ$J|f)]InTs j0gx5zQ8.OJbJ ˌAݺ?"ݰ@b⢼>ma(2 txDݘ %ޫ,X]o5O& )4dtеzUpB n܊x %N;[KSǻGڋW?v?@n J0=1jYIxPCq^7IHJ 3;__EnT} 6N> /2)K'Fil+}Z [b Pt'k5U^[Ag*H-hC,E& Fά.t\vRᗯ _Rڲʨ9C6DS9^>)bwV| &qKYZ&x kM,פ+.& e \{/(, (.6a &y3+Uw7f7| r9BXש~ ۵Bs'Y {hzNgZieTfQY*1VV-W_x3z w'6`rJ"adžA ):0:Ml0` ]]Dv7--駲i(ݔ$;\,e/w& ձ+S~(& rio*kup&T R-*(eqn6E*s20`WKđׄQeY\0>4״Bd%&t aule_M> :1/EƕA҅wǯyKF>n-KEd6Etcb a.-3$,,y{ ˩,o2jxUA:vC =sOQ+awe<8̸3{0֜d{Q8˒ +ME:0VSh\KyP3Ћg[A']IKF-.7 ;>jA,w_++ʋbHpC? G4'D|C_e܆<_y/Y$0,K?աyhD!=YIN$:q 6p#]RdRD': Ɵ \YP!ryM&I Q)θ){5Mȴr9 Pv&bpoxH-[XUt  LX cS|N &"op5YN-*M"jsKb&D4#3^ 5 @ڎbm9`$3/Re򨹱A FF:O_\Wi1d#Qc<$rzA#tGHSeyFbөV&EkZIAv`;R:I$Y@Br_"L,0y}u{s3}[F"<5FcBPdUن\}JZ)@usPrٱ-8+eop!W(1%.6`iiι>ȨCibuFv!9`;3y`mxRW*‚FT&D~ 3ko|V\!/k1Ť׷s1|@.Js_-# шDLIl;_&wTTYI9\ Hĥh[5z?7.d}X#AA!bb=È q[a.Crf8= &#}0~j_: .4(;:A>n=яN^6m:ce]R|.(QUVeyw/";`??>? Lì+k?ً}0fURg\锘reg_el b˯zG#%?~G@Jny [̾[xdU4SA!%A ܋ &Tr> s(0(uCTz_zRfaNOЙ%76^D&ENo9 "Sp&]%.OR]nRX)GdrI(VP~PkywK-Ncl^CS1#3CsgdjWVY"Oݼ gEq7GЕg < P0p`J&0T7AT`53z8(>#o 3,WV4Y5S1% F^HhkY;m!UA xMV @՝~OLx/au/g,H9&'d%xd{#;z g=XbP!ܞΝA/ I/}BGgR,U=v nF8ZU c?^4{rc%I"1*/ 7g8 M1;J@?I@QDRtɣLt)js&Z4bߐZJ/}e'=l,X"S׿\rDchecksums.yaml.gz0000444000000000000000000000045214453724035014614 0ustar00wheelwheel00000000000000de9[A sB)̹Od p 2"«x7/ y[2'¢XBB3q.?xmG <=K܊hzZpS~#>gGъ{ڔ᪱0rDqJv<&/2expo}yig. +(l ԸLeeb_`u 3.dԦ2/0tJ/! 83͍S(,<Ռa'PK ]'Acache/ruby-lsapi-5.6.gemnu[metadata.gz0000444000000000000000000000105515172365607013453 0ustar00wheelwheel00000000000000iTn0+L/{.HTTBHpi+@(rI2vVgd$3~32Yns[wf-*fGP6x9"Fy$Ӽ8^Z)e[P<o0焎Mf \T/*|.gYq׼(b{/LFQ9 r8DG鑉"&oJZOfхo0{?Coѹ-q(9־#"`pj dIVʚV:B\cUb#ۏW3H=sNSE0$V!#e鷁Vk ;@8v$ $j?_"+7C 'n4eo5C G~(=w!j}?ds?8Pf7& <= |ϳpϠ_m̧=pL Ƿ@p1crI)mK2q &%uGsD'AǔNJ ,cf-dsI8IYp'U,ῌY{@'qpfi"I) d08zBzxʫ"ՠ IB+ NYxMsjCU(M@TFh%\g M_mO,HЏ,lN$۹ ?;b{~3'<DB- @" j g7` m=#O}L| +jjFY,5g'bv8qcgҽ&~uϸ:LL" pInq ~Y+NMl*(aI mΦFѕaM}f|mDxTyG0CH&mE+?UrIt`ɃHLIm GT!D'jr>PgM@tqNT:w&3%@H!Љ1j@WAc☥(ft‚*A-bQ.FtuSb {òCOADJ(\i*d3Z-BM \\Kw_~U{h{TPG"RWYg 3su:nuRI%Lwlw!}QSNX|1Zsش{S^c/ϷWl K5npQ#G3'1ΰU2SlM氬 RDca6S'[eZy!ga68L [>l a$,f>,,mhAg03_N-A0khVmH)`$JvPW3Z( MoG*tӖ[-tS-+lze}[S?ގgv);h4H~AB w)yx~+~ Kr ;z2-=ž>51h_iJ:N/ ֳ/?=Y4ysF;ҵi߁7qBd۠!ҔcHODvk^ikoXw*9 k(n1A)\Ժ3e]Ъjh3~ o:+筗߿(^ʽOZ{e͓/v-\O'GP⿕A'`޹fSl'w}f-k=ywt/gH|@ 4'OjK$eo?ss>k?r>&Ok0@]}6²['7mqNx1HAWc#7JET_̓w~Fd=Hus2 oa}.==h3DN@jn[_:o-o? {5 u:{ݭVfN3Z,~1i?v? =ƒF:{{tbH/ G5#-P,j!É!=JYb4xb%C/LW-f:Eq#5>'3J~8C7"РB $.p9Fœ9G ~ZLx eV*p M FޣjccJCq̒)x!S|vN4B 2ND䷈q^Նo{28?w |;7.9<;y;$oO`"#H={o.Am3k4szOz.N{ ;g^w$ˣIrv>Plxޤ1y77qoxmkr{>_uvzG:H?wφdszvY]$oysņh'z{:z{؃@.aBI::'еeQ2 . KNϏ(Ͻ`(.f3ІP AҬw6CP@0PaQ^]CHJ&mHOJ`;Š= ఖuON{'ݳ.#_zn7=, >yICXGat It~!ڼ0 ل-'vmcV}N" {jARF*Fװí^}s@aVa 7.R _75&Y;\#kT'hYj$}uCܒ6ؾ?$9e%|=0Rgzv5Ng'÷yOmW|}{>];':[{w+"dt s"w콃jFgxV~vn%8Q\4O9,SJ!HA$N _rj==ap~w"+XQo7-ӢrmiA~F@JOgd_RȬs43F`~nW̃2TZRoz'jRC:S`B~|y/_DO9q%zlk\ ^$굡r~EPo'3t޸i5Jzv`V~*yz*i!7`va>)~0JOqMV~~4J5sA粛t)PLI^xQAsSwȋ_>yIPPwxiahZ9 yAZ؛~g#?Q<%j{@4PE\ \4%ٮA48*X󷨗ÿς6BC&'<YQiozPSPvl<^'Zٶf9dgQ|̛6x۹#P<NHjE2sl1c챾磀ذ,J@=y8rq8 '=6s4镻h[ Y 6)yq0JCr`FiCZ%D @;!-pF)ѭ]]͌?Kmѭ#u!J3Ȟ9Im>b lLxwf";]ܙ?_u:] K=bi$7kT1XӺg^iCT6Et6"crj?nut>0 $ )(dQ2;gYx ڻoΏ~+yAȏv7ßN\~4<0Z힆5?ov( RJx#;SAd^KK܂|eٌEy65NyOAxu&hp:b at.w}[TR7uHˊiv}.;P G^xaAT<u A7ĕÓ_XH&_,֚WjִJJP!gk͵9~?;tiL%%Q!wvNarVB`P}Qpsodc+d שWٺhưmǻ t4*NM-ߨN[JHOռ<Xbē__ntm?,-og7z6SJaJzt0eϚ8+9iD/M&UZ`8o=o}ez%mz9&k™Ͷw7Z&`wIߢ7"H|FVh02GXMHtsߢś7tGNCl}@ d(fBşPh\mꉬ49#AE1d"ӢWuwLQiI< `ɽE >#z>0o$oB]y՘7ƺO`KRNQ,DyiГW{غ~6~G $jRk kbeoF؞>u+&f(WFoœ4ð:>ےW0FCh+dL,Ж-aQc6224[akX; C]9H)A#4vжf.?-;1mL#0rv#n€ix wk#_X^֊-%5C)bˤZԼS{:yӔ"qCG">UIsLs0Xސ\v{":2pƠZ;F0gJ3?h,n3d{*lSh@Ӄy(FUoiff9f;0I,9l4EwGLhRn'vJy u84A,,: 9 0bhPDYu tW] ժ$QXD9Yc^c?h::t K&舂*ȝI>c+lh<۫4րCtOY5I~E>>Ŕ 4-UP;YoAǷR;ÃEt G$-i99X|͸rBh#BjNԗy˼Aqa۩A\J8ٷnQUGնAqQ ӛ?g-TDVAyCb]T^)TW/Z/GNƌb6X ņMe5cݢ n#LG˗:y(DTܢuOmlds=!FSHbY uYxsD,GBkqi5 De=y(3ЫSh\nwN:jmpCVaQMצ*}B^lK eJ-!R|9\*q9E>iIN+ɀSes-yMkٲ*FgI@=R܎h'l1V 3ªKJEnК֙^ &Y-?, vB e㢥g*=gG `Gf'OĴ[bMkJR0#OZt_{^e S\pQpi (ܮA+a%|v{%k@. Ye ,b*1/+(䳬RI8_h<3 Qu;,}T"I%]mT8襩Q8tX2Pnځ8 [FĄ{b = E,F" .*gj$U!"[Ԯ&Koݢdk6{T`A7O [h"nʝ&r{{9c>^^M(N|/&粅 ' E\_Y(_5TA yTats$*}}i).U6f 51?eMnO!kgCtu.yWmgn@2ok=ccN\4UsLUF#(l-jaRVg[TE}Ye3[;ǮGven\ۂhjln6:ukcp_$cG˄Цʦ}Ʀ^G8Fa|#u0)G"̕KALp 9{4,ܒ귪I/Ǒ"mW3b- /hC|\RI~o֚Ț\ϗ+XFa~d%`H Z8"kHg5n<^Hb.LO+_VsoLh}%_btӂU(ԃ{-R UZ؊뵬4"y/oeM0Wq*ks!]pkW4=a3ŀ~(9,-Lzys,`V&őpm+m Sn۝nn9pxXEMU*?-jhZ9_^WhQ[:[>a> r+veIiiP=Ļ@&H [쟵TSbvU3h)J%è$$RWѕ ocή8eP=\czwaB%p[;ʻx={ڵ^oQ.{FӟQozGvlL+Ra{<vgkOx}%l6nS|}<9=9ռXS;6dIe֌->*_=+LK hD>BU=(},  ]MA>?֩MҧskJ!&S P*w)( [,yu^ROSzj&,0,<ۨX*4Ө@EGQ5W9YQ5^^K_ q㚭XLf iwJ!ѪJ}[/ e)?kc[&h XTcu%q?@g !uϐ4au*lnZ{H^tmxk7oqjMl&4+}T]B>TC=OOj1i%nvQ %r$Y P bX/ox7Ðᇪ mEmQ p8M~ Ya>MkpA*oFp1Y s@;Y;U.2PL]|f;P+ 4ݖaҮnJG7]c}}b}rQHzyGƭw~rSEpcvXʧgN}ZM"LI9sH 6;ip؃NF\Gژ>b L;Ic8}Vc^a[z"FE?M{+ AO=e0^JBPou&D"/jjmLÓO C(M@=H4lj{jVBwP6~WȃO#SD%4h()@J6} H,rߨ$A4 @˦8)D,F[x1 BUsP.F1-ᳩ-q1 U7f4h'݁] Pk,2gxT= _@E% vvUc 64"CnXĪ/1/KY֚|÷W]p[Tņ̫)y1kQ $mBf^GS,ӵp| 9`\٘:h1$MѦmʁv h;YG\ YtYZ3--ax<~~cn@)Boܶ`ܭbM4Ňi%[՜=j2P:qK!3_cS=>AM[)erϏ;6J;aHCRw9:W[˓컱^ WeK"/rP6ڤξFk9)9(i=vPgFV A#b`@<4a XLd%fbf"N2zW7Z9^1+'yrM,4/.C-لydDJxa$+،Gr+ TZ;6[ Z%CjYA-!lfw[;2>ۗEHCX&Z6Eiџ G$7fNou܁ĿñD}A +4NJŴ^[`>0 )7j_7˲s"/;sPܗӬd}V6 ®TfPLޢaV\U{J,xFn_o/8x) C?#F)ۀ ,J@tǕr] [Tv TTKUPvMgoʀm1+Y^vv/wHiNjY8.)-AI#K ˄2؏qPӧMt'3ݣn7gsSw 9* ߹^KuM=8Coz#zS@{ r;]F{ɲQ\ro7,Fd( $Nˌ$mQ@s*[C2YD1J? 5=/R @Fx 54e=a(x Ƌnk[ 9}שj-ßEnr4QQ%( <3nP= Ncߌ(yM䣇!J%ׄvGY㗾ZBZi4gk"7W\zn2+ww OBbq{Q^L(nliaTb.7&Sh]d_)zOϖն cXO^O]&1ȡG 2R ^4 Ώ* PֹH(3ug^ g{Үbmnsx6PRht ެXqsjqAN| S)mx|q?<;*{xܮ=z}P[{巘(QsQk'hUu} ګbt}s٥DE\uV4VFόy Lz.6K\+v:Z~@-9!O<=QkC-asZ v:xTgY~q,}b': kϖ7@F_6lJy B(i=Vwnb뵪{ :isN7+gMc6)3eTG?2n2ϸgḞW8i_4AŲ&e/(_-3QGÊW3`h-2HgC>o ƤuA/S|S9TIE=n{~S/uQyŞu6reb_ Pkdd67t= $q<3?]L>ûy|&S[Lv"?xc3y?`*=g3e^I /~euNJHnO\]ؒH6WΌ)\+s rlꬅ"t򠽍u VxeOuH T,T &g=P>hqSÆɡpŀBkH*Db+,cW\jEdt3WjDt#,oOxt{ RI ש7Ŵ벐Hj9 OPkGjI]S/EqYYqlވB֔b1#.z,Qh/}\T,v#vȑU'ʡBKIS2)xٖ*,T2UEJmk*uEew1sh㽝\BꏰNՋx|㠂֌a=3X%O YvsXx"V—[_~*RPNjűli3IKQpSh IUa+dKHVr?;܄#ųjl _-SSń#EN٭6%K‹ GaG9SQj; / 0QS׳Eʡ_H/Ud¡1̭aH2(7Xc̫i5uɿ2[NΫӪ#-K3W1vC\B{nv<Z5z%Q鎚k>)"[smOW\exuB.s-?_d˼5vmH],e׸}A"ὈL̢!7!Ab뼲%owfJ,&1۟1,`NQ'qn r`aHWglm3QlTBNo$) _T5ʵ'uDX159^aJU@ w˄KFھ9X4)*l`}D}N'$CwTR(H +l/?Ss=Rwi~#cɵm政!yMfAvYؙ[i/igGeFzڲO?کr`~iWC=Fޫ >l;Ԕ$/L괝{B1+> סMD| b؊F g\'/5]-ԝ(&wHW 冿eX>P"bt8 hjhҥxmV¾ F7Z?@Oo=ae |Ht=jUdk|ys<ޕU4t^eQܹC\cjk}Se7Z-~<+Qk5޺co\˜-a>" ~8}(Mx½vӠCF~-M|srtG7`x1IG(H@_gÏ5rn=mqx.}0.4y_Β*->r,ӑK $@}0 }ci+QbZuA[.@Wϱ|tpuke2@ RVᅷ$/:ՕF#֠+*kUOO:]G TQ6]OQ,]1m^Gp^xb~<6tVrnwͳ:`Tvc뀵LT"ڕ̫<1HyrVb &QStO]:"n8!J?f$]D5?1}&D"=q?N]{857cQ^*i>r)m:ɠK*JjC\ZVױ8˞ FGK+[lYߘD٧ۦQ&{Ξ=t']ۡT==ÔQf1gj_UVJ[<#]7:RuZO`)pc:ycc_U櫎7TLа4SFө5ٹi4rhZ)E"ՂVe5i鋜q* fRUIxY7FC"^, OZ%Òw_`YV0Gkt0yd?2u}uKÔHM2UQ,0cj+1$ԤW-RIҀks[pm .cH]:#5Z᪮!,Hb{_9UtʗM #2{l< rI_XN'+x !v?U!Ay,YUغh-*]Vh!8SBmRg KXǙV˭t6VD*5T1vǖK̴E[sQnJސ.Tv _Yv̯-YUaBOa+vH)78.6.:'k`&6ԋrQX^0Hd%uAPe8ldx kt!ءƳV/H@Sci`V;LTzBυ]퍕B FZX;LLù`q0sbhł$, rh-/ ֌.(s*@& Yl<8=F RհKPEo坝uO;]` RS9-=8 ' KA7 ۀV ;ԇcjpP]Άx2+|bBi%,F1}?Zo)qbZ&k|{@4t0LK1ͪi@T fAY^B Yhp\k-w}ހop"&Jֻ79@vTZVH!aq2 ,(">3([Q_h}P"QNڕoqG28r3[Us 2:|Ή? `v{dWU:]X`NJ8@ް0eXh,Jx_vNry6wG+Py>S{/As=s)/Z_;_ݣwBb,CEz>H@w^=im.llXu}NY2g, $+!%3%`]~.PI@1B{F9)d5 NtaYo\-07:.҂[J_ qlAi/sehjߥqOUK{'eպ e-]i?Y*ozG&i_W{ixuF> э.U]긵#yG6rqxo0_3%ұvh9NɳLt&Q+ɕ4qC hjؖۖκ2w!ITԶÚ %B2[V+4V:lӆyV;uOy+46o[}mlE?ˋ-AI\/dn(c)7d6u~ɞAkv~og΅9;?l8xݨI5BMO;S M2H ։~C')B 2aN4++53wVIōgn׵F΄Y?5/f^!%њCԻWԣ7) R޿f:.Ѩ["mkmkY34zNI1쯲3Vxvk5.ek}P-/@gGqH^\i^M,"ο[&v&$>$!]EH&}7J*.,`G\8FPi -A 14R3 β~bG.#OD1i4OufEv] z|+z >,20$3MFZhX rw.:÷_,d' #`xBW2k%@s NzfLtࢁtC0CrVj< t, ؾ8O3[J0"տQNz T3}u8e#y]l|Q'I/5n*ԭ}˜ҡdhIc1LўGZE @ƪE>in-}|1?n%xOIDJe*3ZVXyiib1m$3韋 .f^͊Q_T_}g%L0r^5NQYN;OɛieI]bH@5ԆdjVȭ?eE&8P8 =Py ,;0678BpyvOo'yl!-B (#ߞ51, Vya>(ڥ[ cPӣr7wS"KYL 9*Z`JN& *ipSL;6Z2lI!j-*PVy*0.||=#]$^= 7 ӭUz;]S9JU鯛Dh[NTl+x4F 5B&tqn U0 .R .r"Mގ;+n V G y<Rojt~j#: {f|=|ZP42Sej/n\G?:Kʲ95:q;z*y ڳB+7xuvޢʯrpZǝز'i%tȗY& ¾%`3HZ[$-dExc> ehs.v#VݾC#?L{ԭӈAViDv֦9fhLN=c MY -4M0"sv~: b4J~G~ljQfq+R ҆R^Q.h!x_e斲qJsr^I(Y"{)Tl8o-qI4,%P{sz~SST]y]h9]`ƣ5 S8@w ˍ燵¢3I{+ѯdDFhד& F\F q_58.%>Aٽ(Fڜus8 bӾOMh]AtKZѢuc@zW[経>μR}/BHGU)waG)@6 a R8oLSz,&p2=%TѮ*@_Օ 6[WUjV4YDp8], H*_q8FĈ:ŋD&L6pc4Spӌ[;+v.Z *Rrjl`8M!(oj.T^>eeCn;Q( ϸ#;7/ Xl(|\c<յ5WM-^kF(Uܬ䂿g.qկrgPp.ˊN9F߱Z%ͬ~2.E~K]qzښ9Ww2sCIw֨K' ߤHv|p W{2B^h3$o;ݽX_QuHmǴqG:W3;Stūe!mlݓMo7i۠n𥛌=[AhUJWTͫ+n[څѩʻt1 7j4dq\t nTc{VM^ zjV*67]43ג*/9;_vNtKtJN3Ju6XoD9֝Ca"NJY]+5B}]Eŝ~ŝ^̩ ie|R7}o|Aa/uw֎e~]vH `;]\r?\H2 ݾ_݂y[|g Mxqt[Lyʹck 5q"Cfi䎃>-E(G{Ra}|*ea@|o5{c \ l5V̟l; NqH BPًewk -aM.)@Adk>Gg.ĿB,L$B#5Wqȧ nٮM̞R<7l*am:XKlnm8Kˁ"HgdNxtK>vUiÀJUY ׏̈Z{$U]k) KvlI,KU"e{-AunP)F%^[<|Wp4{\C<6][b(>LÂv.4[miRb-%^dtHU|CMqYoIbKD'Y~}|ETK7}F&+NBwfdyӊ%w? CFhSdQB,T%}Q5yOVT#PT"G^,*(nH-[_VV\UGT,.TtM^"+,"Z+ cųSsTA- /^)x3u݂.+گr_2(2WnRGBʊ 7 65HJ4 4YJye¬p8<(::_1 0[ʕnk nzmnq{+>ܯV^[?ab-N˖S8'l(,mt6^|JϝqD/viÚLkU ]݄=%PRi&i7vdKBސ8bV ;쎉aѹ2DhC֟Bo,4%Qo{hƇ;g%@Med2_ISM.:^Te)G~;=?YS2>sk!̟] L/Cp;Aٰ1Uwb0^`8X;|*4j١#˸)yBzaٗȣev~>y2O5dB/M ]3s-vmrhaPNJ̿\?u(j97Z!U f4`cnw۲6Ѭ/ngpz *;̀SpR~gHrhJxQ:;*7|qҿ9l!A5#s؉ a]wUPn0A X`/{K>gK{t7X5XQrV8sџ-LDw}syΎϗUxXV5bv(|UԹ+( >De!u ৗ?<2rh_7#w+<F3n=}\>0Ky{Fj>P^>sW$!2J 첻[lsYL+>=d>aǀQn`6im:J,}Dz^6ɻI8-)FQ0x^*|TYkDySלe4;g0Z̮@ 1Kf'%G055I=->Rv5PT2jCTSԟ$ QZ;, q K޷7q$S42FFOl #@'fm,?Վ i ߪL4$wƚ~UWWWWW׃N 8zj pd@(ᜎͭ(IjЮuӞ2Mg!2ta#UE?xqǨJ`ޔrDX" Exց LbE9pr^۸pʛve4};4grbRK>YJɨB/a)AX4+D!GPak cԪ2 ~p'ă(W> C=opa <$Qmg?ye Tm~+1i[tQ~` 1aH @=CxL1 x5*Vṕ1Jt T]׀<]?~HOxHgV\mX9 J(V#8BŔޑqIlx=jZL|Oӭ qd{|(%iiݛSd}h, W-oiwO^;\.Z0x>#;%-6٦g4Cy`܂\w4Q7oԫ|F:oԭuz J)6 ިݭ~)m6V6-YnlֳMi[@zYeohhm6;6!˔joөeSMPΣnoqj$:Z%lg kNqZ*u6;uVvzr^­ZPܪY^MlZՍjg}G6I[YEUlRbGUGؔ"z[~4%IJFmcs=ۜH;~-8'vodZPls#u׷۽Ls۬vMIMw,S$vaN) &կ{MI^Hҳ0$F]Kf؜vk}NE5G{"~$SU|V;U(;Zy c#Ӥ@^MJ7[FgqNbvj9 Z Q4|]4)AH;j}T8)%#v/ۤղMJ}}g;g$~P[A5ۤ,^m62Io#j~IIԳMJ[lwݫw:&%|?s 1}u?CWX;,i=dvøŔ{$R$NʆI#.Yսaq,Xgax5A|{QUџoU/jVuoU ̣?P`޲KUVsf:1[Z_Wkp f;A8 bwʹQ~WN M93a1z nc|A-QT*pJ ( f3c2 ? Udpua6ʍ.gZ̆c},;',h @BK؍9}RN4 eo_c8,9iI$ΰ4DR1 0^_W|gNFN8PkzGJ׹`:T_"Z[Z-4nX't,{5@GL{0 LDOȊJ&A  ©m)/hz;;y﷧'?7_4^Yu}|^hu|urzA<g=mS| AǭfĚLJG^P\Vrd] Z'%4ٌdoQ{lX/ONsiy}wpZ/gG7eFdQё=/ǍSݜ"{`G̓G &y8ll_8﨔;{8l}IyN-0# apYzjW''/gӟ=vtrFzw(^h`0wgMY8=}<9.X B1Nhqr;EK ~$L c-lqQU'/ͳFy4,,>KPO`K`ʰgMA&> UGm~b5M@8iO4d^U2&G0Ͼ(ǃ܂嫼q4'淛A_o&ɉG|.~ nڟS} K^Z >r)v25e_[$8}z(bYnO̺Ʊ.8-"=WǾ;ZJP 8ae\Oݟw;<݃f?pR[M ojrD4=C{^˽l6H޶>z_K߆ьQ]pd-N^?7ϛ3cUA̮V9bZZ H}Gi5qSi5'Xc3iE}lxy:8.alѳsZ-.XymIo`-b}YEgn`]GV<($qR.dn:~wn,9h=7[ z ]^[,,oY?M,ܬcտ?--?5Ê{syr>J ?WQG]NzB$t]%Db}<*ԝ@RGB|w4gRFphIjM]"nQ2_K ieE3 p~_#?h)m|^|,Pa.wp>ۀɎ:7+P C/hIz{(%&r{c}ު(\Ĭ#)ޤO|)1&[UbQc]eF!5Բ1MD[cUcu.`[]aBs|dm?ZX5 c͒rCg'FqdS0Y!/:^`f?NZKV=t|Bd&atý2bt=@w'b( E?(0pv S<ymݱ鵹D91!t5;^ S_w&ݞH~wsY6 &׽ˆb O ܽ$\5]ci:u٬o5Ag}㽔"kZq%Tƿ$2ϜBVb^:%f>BW!)Rˬ9] ࢃ.Q-O0\1|>'h8NoBISҤ; \𴉉(YN6&t+$FV;C{`MnpUM'(iOIwM'5/`ע$fOq>GGEL [=,\LٳE0XI|OY!Jb"?#ncl54 n@Mk%u] 4XݽN I1.=x*i!5VX-mx8Ĉz>3#5LF3|Ndȯ `w ` 2sNJ9W6s{hK R5NEoL[o's OL좱 X#Pi8[#Ѥa`TQ[ZnM+t5!k}3{Lԇ@NGw!$M }:@s>5 ,ƚy |\:x\2uߥի`M6FuU%",/IAS˪0$9-W]/aw|D?ȓrf[p)At R1R)"2]X:kil<S+Fq]OHV9n e!ؽ*ajXĠvyhU=8y)Ysg*=UK}uy ڦ8f#jLo֩HQ㘾!mXy3c2v~!^[cwsG&rei\ɍ@5Xfs-{`dboE]>Ebz.1龙ȬNeL C?6FT0C5H|p1k{>|XtȐGaҰC^OiIЈ(%;qݩ |pQL6+webJԋs nY=F P9 B˦w[F6# . !"<(U7ZQi۟ވǗ45v-/&FmI%Qu'/!}GhR"ܧmy 3eNhDUX1+,9'4d']Q^If睧)HaFăV\$2x붵0ɺ|ar3Ƶ'&#*W_gg",\ǡ8 >6qpC TV5 \)P1&yr1B4!4 HbPdk#LI3О`Ϲ>RλP-+ Pob%80\;[=bQ{g: k4lqUc9U*=X HXݱӖ|MD4߳np mtU.7q ?.J1 Q3 XycQ2 Xt[tace:Cq|bI>m`_߿6[ɷJ,˃Q] ?c+\%RecqA`FB:|mIڅ]/>"90V*f^r& δ߉ۄj:t~0PIS8g*eTJl]W*3,$`ɲE q&e@hޥ;?='͊8wFWobpi ڣ)Gt>eOh[k6vc f0p@'z`ìb^`P!exxî`=0 K2Pb~߿o(hjf̌WAIBUmk)O0C5cH'|\y' n~/ƤP):93궷 (ING[U5,&{-RL \{Ap*BC$a`mAUJ)'}bƄR!( 2)_1P፵k$$UΙ$MrlXgC9ye:0WO=Nwm E N5Q.'J2,eF;1-$p3Y5MZb\+)<d2&'Ȭ=p RFb ݱH+ŅW%/պ?VIݬn yERrhw%Nh$/%a;_sXn#W/@zGƽ(u^]08g>\sS.((k?6KHs}CdfYG&Nɍ"!?`͌4nRWz1-spo k8) a y=r|U*<!lؒBYu!9O<T׃q̢SR}ZucwCVoHIm%mMCI a/ͨO#ma1 y^~eKRgyl: mx!|MzCG77KOz)7|[}5Yˈ7\R}RlG xƷ| ŝ9~n~ W#ۤ``vLmyiOAK,́?| 0 em ʀPM7K"Qgk:&qt.lxJFrE@ăHYD ggw m.b4CZG$7ZM㤵qD^ϲ$H,PYRL=I;.*o2:`g6d/ӎSbwl/>)8R&ciQSׯxeaD^Ĥaybrmcr&=9i-rڣJ\KzE3{l*ҝ˜%?,B#}3Yȃ":xDZ@RT fF+y>9ʉ@y[O`l JsY0DuO;>C%53.0p#% MgtoC8RfeVڪϴ }o`'Lm2ఁ28[_5+r:.ExG=;|A{ցsG{ZQ$xPdPdf#'T@HMOs,%c4 ,$SAlGNg;:~yZu}rW=՗ml6ҞW=O@Ϻz|,نV+K3G3&Kkl-Ȝ]Ǫ 7292|U藦fhwZhVK\F2njjvD++fBr-_2vy*NSv7dA1^Ȱ)duA ~*-CMwӻ!UjD2=2 S,sfU3KC6LiѾn5YPB,e6FH<#Y$ę4סJV+9b1/ܥz_ 5(gK\5;|dZݯ1J#SjH ߎH#FƥэNB Fe:ZœV@[^̪LoA27ʹD.…Q+6d3. $>&ٱLb'Lp![͖Sj!VU4(ǕQݳ1ֶjx*¿WhwR]2c)Î;+vTFsK%"Z;*67[ygvZXu^DBCha^R`,< :Z"+`hF7 `vŎAtRGp>wwaF՞B N@Oxџ!?EMy^mݫq8 /AĚn9AytφP?3^`8W( k;w5Mv+rvW.eпi<.=x?@= :m@\iJx*/p;|OY++) 3@`d)ڷVCIQogSȠq*Pjp:) {>²+^ρulPG4_Zo~eM+ð+pov@uzYEj;rm?o*axN?gro0ţk]F|\\V /Άh%OӃ=0`쳛p^y -"&W%1^OaVEDp>C334t1؅a`*W+ZSRiA~PRN5M|7ϑc_@l{ڕeIN_ժU/@tVʉ C"{yc&IY:. 1O}}D/=_Jr-L`V8v. SbL -Qǽ @_ɬuȼ9mO SLpk7.ɆH} Y獢ߣ_eam?`H/,_4q d<&#ˇ1ߢ3xDÒjQ`^΄f{ =䁜"<'pŹrߓx$=EDI8/xt`…baއJyiCe;=b z~PC9-h qM!=a7B F9o0“E N˓yg8]vy,w WRE]\l̚gԄ~'躃1ľ+Gt o': ?f5oZSk% !Ռy"T6!;?o&rP`Q؟]Ӡ އsydO߲p3M$sWѫG%vaUC̣A.ZzrGPrʴawOVjknǓnH<NrLISqHڱ.KSr0pqOy:izU)>x r= ,s(~<fBmj 62A78lg<% q]b]t ze%\a@# N@C Rut>Am1EE=O=

    whu, $^̪5HEa"8:7EiF%kL=4<5T,w23D&0h)APUpoVSxWJ4,>YRPh2̼~ -L#2드L:᲋P㸕3sG(|p(GϿ ~DwAx+|=o(I.! y=/V`Z(1AZCy4 2 PGV;h%pQ/U)6fA0e,3We{&Kz=RQopɵ){̷E`I_Y\qiP&l{u1gH &:#;tJ,=[Yڡ9 hŭRU=Ox=Ӭ9mO𣫒RUhԣ!U={`a\` 53/oиBUTz7tI,ᅅc=f)"8c6I/ߎo`&)aNχ ^2};^ʗ2<){ϘKhc%,Ӡ "`$tAa`U` }_AU#v"#a(BP(ڒy"NaF]Zsm VAA+ zP(8]9.B-YP-^^i|-ݾ&#tKGQB ^.\Ř6=)U5(-èf6Fqiyb=!]\L/ 741Xr­$CL")WD;@RM$+?\΅{(!LB|*PAZD(mXq/VEQMMq3 ,e9AY>}dhcGD3mԼo04UT2*,4`U)`;R WE0B %@$.,%<9'F-nlwkd,ѵ[* no ,?C:F.=3N뻌F3[D?R`)?DG,DrRqCW(G!uŒQ@4 fEFf87!\0iQ姅CH:JsXūi\eƁ*|Ǘ-yJo~OCd`yxx/5 G 8Y) .؉UT#5IJް݄ԫ`w?¡i\7R8WTNe|e`&6$Er\GG1. o9c[ ,\8'ǍoG<#&J[Q'NQqa9y[#*ʇ':~U=ZJ=C TGgG:,5MP]ZM:0k?e2ڗ]⧫t_bYW ~7G/Wp"3)_95 /zBG:6ZҩHcd Y:QHhU._""7jac D]*ԝ"DIH%9TZ?(NRbmaU I/b:()=IL "b:jyy-fF+Ej"ڀsD[|Ό"G,Č\w4<\ǚȋM5#,M p\enΫAA?ѓoy5fo*]qQS-Ҧ-˹_E{[v׀jP5!P1.Atg!s nb{ !\D:$3CO΢!1e.y\JQaʔ2-$o@P-4o5/z*|Y˙4-PZ}Z9-\-kz0U{T٬ 5@w֖DzhaJIKYn&}1:tŠ[|*] 4:K`:+.Y Ȏq_ &=qbg ZUBDQS)f%g%R&C¹vo&s#b+cHهW$p=m(7 ̟-g?TIl&`rpia7A:Dj]i҉ɣ) J(1e n %E-T\0u3,Za! УMMxrˢ6WLļMXB#WwN?q9~{UPJ0Nۼ@%2ו/#W1Y6qa,>9ޜ-\sVD[#(@=Q.4є\24>r:H-BC 3q]>1xzM#cvo $?JxH` ѷ@buhTp2Ezy\ë_3L)`Wx[IB;H&֥ J8MDhc79Hd6k1ɔv af$U hh&!H0Ƭi:Si?*֔?d0/IcGT ψf[>P˧c GCaGZh?K25!|\v(ߟG}Yu=nDAQwE3v>KLz+|;$ܱkMW´P\ֵlۭqF4ދ٘B\8F*G1FA(ȱ@+5G*֢Tt'/7^n+ %W|+">>6JܦG.Y%qW$v a~81^m ݓ|z8ZOv>"W)"2P m+|fg7}!i~ @44[Q]ZlM|f1"~WdyѥsxlnÌ,祕Nv%+ʵ6$I%~9 2gH[b\ƻ zlBMd׆0mlQTCf_ qPŬB y K3_ǶN=n2LbFxrS(hܚ<5YbcD2%I^?(]LVhR02rƳq++YZ#:j~%vE-,/WoMv!;R8lQ;L = OjLp 1_GvC𤤳+\ _hds: 5,vrYG`PϠOG]?^at<:`V;QyC#y g'H.WeWڝbP+j)b͊.em$.}p\$je@mqщU1(F;%Y|ң&A1|lĥ<+23e L?7c{H?4PŨ66 x% WbiI:~ۅVNR3>QhL4p ``WU/b/{PQwiBSMXIo!=|rW>Ȅ_E،_L/#1ԡ['|v{(Q}#EkQEzeuoNڃPwIJ~\51Kiߴ ym8O[ÛEI, L-OpEK&9$Jag0٢Z+7WI`$f$=Bװ .,6Do |;8:I/΂QdjT.{Y!n1Q ]PcʀQ 7Zz幀5eax@vORv% 1eF rnnk 1qQ^o0pL:GmqOZP%,FDg&xtkRN{DTr}HAJOCkhtP _*⻛B^t>dhT?mZ9FŠ,I=4H= 32~( qz C+zI+ƖP+ݯLC<=;NX~W0F pc _  p P60 .]@"S]H4nJ.Ų{λZڕAڋ)Cl?zO`SѶ&MDLr-y-v5<Eur# a/y':(邑x zEZV 80Z0Sg~ui]O3*޿^h}rHS7R,Jo&^9yLbi1}"elgzEKNmGDʜ0F?yBV#k#e' ūŴTڨ _Ap̣AR)L<#}i+{5PQm [$K, !Gd9NK/Pn{Z&~e> -i@kakc#}KOT!( *lCM.ž%LPZUO(}9d–z7]8y~EO044pdTʡ41: #;Jvw|0Fۂ@ ˯ryhdw&¤D vOɻ\n B{.$R4O C>t 1JaD{0i _!e3etMݏl~>lu?Ekr UpF iG'p^2.) (h`*+HJ Vjу_aVA@>*|)Q.dtJK2O6WA#NK?TI|?@#E TO%<C-f_Y-Z<* fbEJL*9ayT9^l!*u/ =D`?oWG'맍WeCYF ><Vća(ZpI?Lnd++|XzQAy{Հ{unM>׃!Љ';Z֋)*m/z"yK7Ga|)8n\~/ K; d$NCci)A9nźe2c9\"篕wNy2tGEyl{o w0|R]NܻhFD?~,,q%ԩ/ *S|[+=(U&\U䪲O| NJX(? E+ ] {P.+qb.ؒTa').7CGy#2$+h?񌵼Uջ16!!TY\we9`2A^+Cȧn\yL8#J3PXb(\80%\ukW| NDM*~ W=?WZ+f+,ӚFbnA/td${6Y䐪o&+N[?'zUW&亗Mo2Df`Cq~=?Pf,1nOˠPT×>v#G\гj)˪Mq7h{J RSK汀/߽JE$CmI3&h%{w$ ("M Zw[)vp&Udxm9O bINwKCEgoHu>ѓWd6Y,k_׿^bWDchecksums.yaml.gz0000444000000000000000000000045015172365607014617 0ustar00wheelwheel00000000000000ie;@EYl`] 5_)u}^߾"xǗ?˯]ڦutыhKҐ>Y(v0:+ItާBpAoLe<;LhINKgٌC9&;aƖ>X\WQF{D3WEO9ᒡhhLjD%6PKu]=wirb-1.2.6/exe/irbnuȯ#!/usr/bin/ruby # # irb.rb - interactive ruby # $Release Version: 0.9.6 $ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # require "irb" IRB.start(__FILE__) PKu]Skkirb-1.2.6/lib/irb.rbnu[# frozen_string_literal: false # # irb.rb - irb main module # $Release Version: 0.9.6 $ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "ripper" require "reline" require_relative "irb/init" require_relative "irb/context" require_relative "irb/extend-command" require_relative "irb/ruby-lex" require_relative "irb/input-method" require_relative "irb/locale" require_relative "irb/color" require_relative "irb/version" require_relative "irb/easter-egg" # IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby # expressions read from the standard input. # # The +irb+ command from your shell will start the interpreter. # # == Usage # # Use of irb is easy if you know Ruby. # # When executing irb, prompts are displayed as follows. Then, enter the Ruby # expression. An input is executed when it is syntactically complete. # # $ irb # irb(main):001:0> 1+2 # #=> 3 # irb(main):002:0> class Foo # irb(main):003:1> def foo # irb(main):004:2> print 1 # irb(main):005:2> end # irb(main):006:1> end # #=> nil # # The singleline editor module or multiline editor module can be used with irb. # Use of multiline editor is default if it's installed. # # == Command line options # # Usage: irb.rb [options] [programfile] [arguments] # -f Suppress read of ~/.irbrc # -d Set $DEBUG to true (same as `ruby -d') # -r load-module Same as `ruby -r' # -I path Specify $LOAD_PATH directory # -U Same as `ruby -U` # -E enc Same as `ruby -E` # -w Same as `ruby -w` # -W[level=2] Same as `ruby -W` # --inspect Use `inspect' for output (default except for bc mode) # --noinspect Don't use inspect for output # --multiline Use multiline editor module # --nomultiline Don't use multiline editor module # --singleline Use singleline editor module # --nosingleline Don't use singleline editor module # --colorize Use colorization # --nocolorize Don't use colorization # --prompt prompt-mode # --prompt-mode prompt-mode # Switch prompt mode. Pre-defined prompt modes are # `default', `simple', `xmp' and `inf-ruby' # --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs. # Suppresses --multiline and --singleline. # --simple-prompt Simple prompt mode # --noprompt No prompt mode # --tracer Display trace for each execution of commands. # --back-trace-limit n # Display backtrace top n and tail n. The default # value is 16. # -v, --version Print the version of irb # # == Configuration # # IRB reads from ~/.irbrc when it's invoked. # # If ~/.irbrc doesn't exist, +irb+ will try to read in the following order: # # * +.irbrc+ # * +irb.rc+ # * +_irbrc+ # * $irbrc # # The following are alternatives to the command line options. To use them type # as follows in an +irb+ session: # # IRB.conf[:IRB_NAME]="irb" # IRB.conf[:INSPECT_MODE]=nil # IRB.conf[:IRB_RC] = nil # IRB.conf[:BACK_TRACE_LIMIT]=16 # IRB.conf[:USE_LOADER] = false # IRB.conf[:USE_MULTILINE] = nil # IRB.conf[:USE_SINGLELINE] = nil # IRB.conf[:USE_COLORIZE] = true # IRB.conf[:USE_TRACER] = false # IRB.conf[:IGNORE_SIGINT] = true # IRB.conf[:IGNORE_EOF] = false # IRB.conf[:PROMPT_MODE] = :DEFAULT # IRB.conf[:PROMPT] = {...} # # === Auto indentation # # To disable auto-indent mode in irb, add the following to your +.irbrc+: # # IRB.conf[:AUTO_INDENT] = false # # === Autocompletion # # To enable autocompletion for irb, add the following to your +.irbrc+: # # require 'irb/completion' # # === History # # By default, irb will store the last 1000 commands you used in # IRB.conf[:HISTORY_FILE] (~/.irb_history by default). # # If you want to disable history, add the following to your +.irbrc+: # # IRB.conf[:SAVE_HISTORY] = nil # # See IRB::Context#save_history= for more information. # # The history of _results_ of commands evaluated is not stored by default, # but can be turned on to be stored with this +.irbrc+ setting: # # IRB.conf[:EVAL_HISTORY] = # # See IRB::Context#eval_history= and History class. The history of command # results is not permanently saved in any file. # # == Customizing the IRB Prompt # # In order to customize the prompt, you can change the following Hash: # # IRB.conf[:PROMPT] # # This example can be used in your +.irbrc+ # # IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode # :AUTO_INDENT => false, # disables auto-indent mode # :PROMPT_I => ">> ", # simple prompt # :PROMPT_S => nil, # prompt for continuated strings # :PROMPT_C => nil, # prompt for continuated statement # :RETURN => " ==>%s\n" # format to return value # } # # IRB.conf[:PROMPT_MODE] = :MY_PROMPT # # Or, invoke irb with the above prompt mode by: # # irb --prompt my-prompt # # Constants +PROMPT_I+, +PROMPT_S+ and +PROMPT_C+ specify the format. In the # prompt specification, some special strings are available: # # %N # command name which is running # %m # to_s of main object (self) # %M # inspect of main object (self) # %l # type of string(", ', /, ]), `]' is inner %w[...] # %NNi # indent level. NN is digits and means as same as printf("%NNd"). # # It can be omitted # %NNn # line number. # %% # % # # For instance, the default prompt mode is defined as follows: # # IRB.conf[:PROMPT_MODE][:DEFAULT] = { # :PROMPT_I => "%N(%m):%03n:%i> ", # :PROMPT_N => "%N(%m):%03n:%i> ", # :PROMPT_S => "%N(%m):%03n:%i%l ", # :PROMPT_C => "%N(%m):%03n:%i* ", # :RETURN => "%s\n" # used to printf # } # # irb comes with a number of available modes: # # # :NULL: # # :PROMPT_I: # # :PROMPT_N: # # :PROMPT_S: # # :PROMPT_C: # # :RETURN: | # # %s # # :DEFAULT: # # :PROMPT_I: ! '%N(%m):%03n:%i> ' # # :PROMPT_N: ! '%N(%m):%03n:%i> ' # # :PROMPT_S: ! '%N(%m):%03n:%i%l ' # # :PROMPT_C: ! '%N(%m):%03n:%i* ' # # :RETURN: | # # => %s # # :CLASSIC: # # :PROMPT_I: ! '%N(%m):%03n:%i> ' # # :PROMPT_N: ! '%N(%m):%03n:%i> ' # # :PROMPT_S: ! '%N(%m):%03n:%i%l ' # # :PROMPT_C: ! '%N(%m):%03n:%i* ' # # :RETURN: | # # %s # # :SIMPLE: # # :PROMPT_I: ! '>> ' # # :PROMPT_N: ! '>> ' # # :PROMPT_S: # # :PROMPT_C: ! '?> ' # # :RETURN: | # # => %s # # :INF_RUBY: # # :PROMPT_I: ! '%N(%m):%03n:%i> ' # # :PROMPT_N: # # :PROMPT_S: # # :PROMPT_C: # # :RETURN: | # # %s # # :AUTO_INDENT: true # # :XMP: # # :PROMPT_I: # # :PROMPT_N: # # :PROMPT_S: # # :PROMPT_C: # # :RETURN: |2 # # ==>%s # # == Restrictions # # Because irb evaluates input immediately after it is syntactically complete, # the results may be slightly different than directly using Ruby. # # == IRB Sessions # # IRB has a special feature, that allows you to manage many sessions at once. # # You can create new sessions with Irb.irb, and get a list of current sessions # with the +jobs+ command in the prompt. # # === Commands # # JobManager provides commands to handle the current sessions: # # jobs # List of current sessions # fg # Switches to the session of the given number # kill # Kills the session with the given number # # The +exit+ command, or ::irb_exit, will quit the current session and call any # exit hooks with IRB.irb_at_exit. # # A few commands for loading files within the session are also available: # # +source+:: # Loads a given file in the current session and displays the source lines, # see IrbLoader#source_file # +irb_load+:: # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load # +irb_require+:: # Loads the given file similarly to Kernel#require # # === Configuration # # The command line options, or IRB.conf, specify the default behavior of # Irb.irb. # # On the other hand, each conf in IRB@Command+line+options is used to # individually configure IRB.irb. # # If a proc is set for IRB.conf[:IRB_RC], its will be invoked after execution # of that proc with the context of the current session as its argument. Each # session can be configured using this mechanism. # # === Session variables # # There are a few variables in every Irb session that can come in handy: # # _:: # The value command executed, as a local variable # __:: # The history of evaluated commands. Available only if # IRB.conf[:EVAL_HISTORY] is not +nil+ (which is the default). # See also IRB::Context#eval_history= and IRB::History. # __[line_no]:: # Returns the evaluation value at the given line number, +line_no+. # If +line_no+ is a negative, the return value +line_no+ many lines before # the most recent return value. # # === Example using IRB Sessions # # # invoke a new session # irb(main):001:0> irb # # list open sessions # irb.1(main):001:0> jobs # #0->irb on main (# : stop) # #1->irb#1 on main (# : running) # # # change the active session # irb.1(main):002:0> fg 0 # # define class Foo in top-level session # irb(main):002:0> class Foo;end # # invoke a new session with the context of Foo # irb(main):003:0> irb Foo # # define Foo#foo # irb.2(Foo):001:0> def foo # irb.2(Foo):002:1> print 1 # irb.2(Foo):003:1> end # # # change the active session # irb.2(Foo):004:0> fg 0 # # list open sessions # irb(main):004:0> jobs # #0->irb on main (# : running) # #1->irb#1 on main (# : stop) # #2->irb#2 on Foo (# : stop) # # check if Foo#foo is available # irb(main):005:0> Foo.instance_methods #=> [:foo, ...] # # # change the active session # irb(main):006:0> fg 2 # # define Foo#bar in the context of Foo # irb.2(Foo):005:0> def bar # irb.2(Foo):006:1> print "bar" # irb.2(Foo):007:1> end # irb.2(Foo):010:0> Foo.instance_methods #=> [:bar, :foo, ...] # # # change the active session # irb.2(Foo):011:0> fg 0 # irb(main):007:0> f = Foo.new #=> # # # invoke a new session with the context of f (instance of Foo) # irb(main):008:0> irb f # # list open sessions # irb.3():001:0> jobs # #0->irb on main (# : stop) # #1->irb#1 on main (# : stop) # #2->irb#2 on Foo (# : stop) # #3->irb#3 on # (# : running) # # evaluate f.foo # irb.3():002:0> foo #=> 1 => nil # # evaluate f.bar # irb.3():003:0> bar #=> bar => nil # # kill jobs 1, 2, and 3 # irb.3():004:0> kill 1, 2, 3 # # list open sessions, should only include main session # irb(main):009:0> jobs # #0->irb on main (# : running) # # quit irb # irb(main):010:0> exit module IRB # An exception raised by IRB.irb_abort class Abort < Exception;end @CONF = {} # Displays current configuration. # # Modifying the configuration is achieved by sending a message to IRB.conf. # # See IRB@Configuration for more information. def IRB.conf @CONF end # Returns the current version of IRB, including release version and last # updated date. def IRB.version if v = @CONF[:VERSION] then return v end @CONF[:VERSION] = format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE) end # The current IRB::Context of the session, see IRB.conf # # irb # irb(main):001:0> IRB.CurrentContext.irb_name = "foo" # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo" def IRB.CurrentContext IRB.conf[:MAIN_CONTEXT] end # Initializes IRB and creates a new Irb.irb object at the +TOPLEVEL_BINDING+ def IRB.start(ap_path = nil) STDOUT.sync = true $0 = File::basename(ap_path, ".rb") if ap_path IRB.setup(ap_path) if @CONF[:SCRIPT] irb = Irb.new(nil, @CONF[:SCRIPT]) else irb = Irb.new end irb.run(@CONF) end # Calls each event hook of IRB.conf[:TA_EXIT] when the current session quits. def IRB.irb_at_exit @CONF[:AT_EXIT].each{|hook| hook.call} end # Quits irb def IRB.irb_exit(irb, ret) throw :IRB_EXIT, ret end # Aborts then interrupts irb. # # Will raise an Abort exception, or the given +exception+. def IRB.irb_abort(irb, exception = Abort) if defined? Thread irb.context.thread.raise exception, "abort then interrupt!" else raise exception, "abort then interrupt!" end end class Irb ASSIGNMENT_NODE_TYPES = [ # Local, instance, global, class, constant, instance, and index assignment: # "foo = bar", # "@foo = bar", # "$foo = bar", # "@@foo = bar", # "::Foo = bar", # "a::Foo = bar", # "Foo = bar" # "foo.bar = 1" # "foo[1] = bar" :assign, # Operation assignment: # "foo += bar" # "foo -= bar" # "foo ||= bar" # "foo &&= bar" :opassign, # Multiple assignment: # "foo, bar = 1, 2 :massign, ] # Note: instance and index assignment expressions could also be written like: # "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former # be parsed as :assign and echo will be suppressed, but the latter is # parsed as a :method_add_arg and the output won't be suppressed # Creates a new irb session def initialize(workspace = nil, input_method = nil) @context = Context.new(self, workspace, input_method) @context.main.extend ExtendCommandBundle @signal_status = :IN_IRB @scanner = RubyLex.new end def run(conf = IRB.conf) conf[:IRB_RC].call(context) if conf[:IRB_RC] conf[:MAIN_CONTEXT] = context trap("SIGINT") do signal_handle end begin catch(:IRB_EXIT) do eval_input end ensure conf[:AT_EXIT].each{|hook| hook.call} end end # Returns the current context of this irb session attr_reader :context # The lexer used by this irb session attr_accessor :scanner # Evaluates input for this session. def eval_input exc = nil @scanner.set_prompt do |ltype, indent, continue, line_no| if ltype f = @context.prompt_s elsif continue f = @context.prompt_c elsif indent > 0 f = @context.prompt_n else f = @context.prompt_i end f = "" unless f if @context.prompting? @context.io.prompt = p = prompt(f, ltype, indent, line_no) else @context.io.prompt = p = "" end if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent) unless ltype prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size + indent * 2 - p.size ind += 2 if continue @context.io.prompt = p + " " * ind if ind > 0 end end @context.io.prompt end @scanner.set_input(@context.io) do signal_status(:IN_INPUT) do if l = @context.io.gets print l if @context.verbose? else if @context.ignore_eof? and @context.io.readable_after_eof? l = "\n" if @context.verbose? printf "Use \"exit\" to leave %s\n", @context.ap_name end else print "\n" end end l end end @scanner.set_auto_indent(@context) if @context.auto_indent_mode @scanner.each_top_level_statement do |line, line_no| signal_status(:IN_EVAL) do begin line.untaint if RUBY_VERSION < '2.7' @context.evaluate(line, line_no, exception: exc) if @context.echo? if assignment_expression?(line) if @context.echo_on_assignment? output_value(@context.omit_on_assignment?) end else output_value end end rescue Interrupt => exc rescue SystemExit, SignalException raise rescue Exception => exc else exc = nil next end handle_exception(exc) end end end def handle_exception(exc) if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ && !(SyntaxError === exc) && !(EncodingError === exc) # The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno. irb_bug = true else irb_bug = false end if STDOUT.tty? attr = ATTR_TTY print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n" else attr = ATTR_PLAIN end messages = [] lasts = [] levels = 0 if exc.backtrace count = 0 exc.backtrace.each do |m| m = @context.workspace.filter_backtrace(m) or next unless irb_bug count += 1 if attr == ATTR_TTY m = sprintf("%9d: from %s", count, m) else m = "\tfrom #{m}" end if messages.size < @context.back_trace_limit messages.push(m) elsif lasts.size < @context.back_trace_limit lasts.push(m).shift levels += 1 end end end if attr == ATTR_TTY unless lasts.empty? puts lasts.reverse printf "... %d levels...\n", levels if levels > 0 end puts messages.reverse end m = exc.to_s.split(/\n/) print "#{attr[1]}#{exc.class} (#{attr[4]}#{m.shift}#{attr[0, 1]})#{attr[]}\n" puts m.map {|s| "#{attr[1]}#{s}#{attr[]}\n"} if attr == ATTR_PLAIN puts messages unless lasts.empty? puts lasts printf "... %d levels...\n", levels if levels > 0 end end print "Maybe IRB bug!\n" if irb_bug end # Evaluates the given block using the given +path+ as the Context#irb_path # and +name+ as the Context#irb_name. # # Used by the irb command +source+, see IRB@IRB+Sessions for more # information. def suspend_name(path = nil, name = nil) @context.irb_path, back_path = path, @context.irb_path if path @context.irb_name, back_name = name, @context.irb_name if name begin yield back_path, back_name ensure @context.irb_path = back_path if path @context.irb_name = back_name if name end end # Evaluates the given block using the given +workspace+ as the # Context#workspace. # # Used by the irb command +irb_load+, see IRB@IRB+Sessions for more # information. def suspend_workspace(workspace) @context.workspace, back_workspace = workspace, @context.workspace begin yield back_workspace ensure @context.workspace = back_workspace end end # Evaluates the given block using the given +input_method+ as the # Context#io. # # Used by the irb commands +source+ and +irb_load+, see IRB@IRB+Sessions # for more information. def suspend_input_method(input_method) back_io = @context.io @context.instance_eval{@io = input_method} begin yield back_io ensure @context.instance_eval{@io = back_io} end end # Evaluates the given block using the given +context+ as the Context. def suspend_context(context) @context, back_context = context, @context begin yield back_context ensure @context = back_context end end # Handler for the signal SIGINT, see Kernel#trap for more information. def signal_handle unless @context.ignore_sigint? print "\nabort!\n" if @context.verbose? exit end case @signal_status when :IN_INPUT print "^C\n" raise RubyLex::TerminateLineInput when :IN_EVAL IRB.irb_abort(self) when :IN_LOAD IRB.irb_abort(self, LoadAbort) when :IN_IRB # ignore else # ignore other cases as well end end # Evaluates the given block using the given +status+. def signal_status(status) return yield if @signal_status == :IN_LOAD signal_status_back = @signal_status @signal_status = status begin yield ensure @signal_status = signal_status_back end end def prompt(prompt, ltype, indent, line_no) # :nodoc: p = prompt.dup p.gsub!(/%([0-9]+)?([a-zA-Z])/) do case $2 when "N" @context.irb_name when "m" @context.main.to_s when "M" @context.main.inspect when "l" ltype when "i" if indent < 0 if $1 "-".rjust($1.to_i) else "-" end else if $1 format("%" + $1 + "d", indent) else indent.to_s end end when "n" if $1 format("%" + $1 + "d", line_no) else line_no.to_s end when "%" "%" end end p end def output_value(omit = false) # :nodoc: str = @context.inspect_last_value multiline_p = str.include?("\n") if omit winwidth = @context.io.winsize.last if multiline_p first_line = str.split("\n").first result = @context.newline_before_multiline_output? ? (@context.return_format % first_line) : first_line output_width = Reline::Unicode.calculate_width(result, true) diff_size = output_width - Reline::Unicode.calculate_width(first_line, true) if diff_size.positive? and output_width > winwidth lines, _ = Reline::Unicode.split_by_width(first_line, winwidth - diff_size - 3) str = "%s...\e[0m" % lines.first multiline_p = false else str.gsub!(/(\A.*?\n).*/m, "\\1...") end else output_width = Reline::Unicode.calculate_width(@context.return_format % str, true) diff_size = output_width - Reline::Unicode.calculate_width(str, true) if diff_size.positive? and output_width > winwidth lines, _ = Reline::Unicode.split_by_width(str, winwidth - diff_size - 3) str = "%s...\e[0m" % lines.first end end end if multiline_p && @context.newline_before_multiline_output? printf @context.return_format, "\n#{str}" else printf @context.return_format, str end end # Outputs the local variables to this current session, including # #signal_status and #context, using IRB::Locale. def inspect ary = [] for iv in instance_variables case (iv = iv.to_s) when "@signal_status" ary.push format("%s=:%s", iv, @signal_status.id2name) when "@context" ary.push format("%s=%s", iv, eval(iv).__to_s__) else ary.push format("%s=%s", iv, eval(iv)) end end format("#<%s: %s>", self.class, ary.join(", ")) end def assignment_expression?(line) # Try to parse the line and check if the last of possibly multiple # expressions is an assignment type. # If the expression is invalid, Ripper.sexp should return nil which will # result in false being returned. Any valid expression should return an # s-expression where the second selement of the top level array is an # array of parsed expressions. The first element of each expression is the # expression's type. verbose, $VERBOSE = $VERBOSE, nil result = ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0)) $VERBOSE = verbose result end ATTR_TTY = "\e[%sm" def ATTR_TTY.[](*a) self % a.join(";"); end ATTR_PLAIN = "" def ATTR_PLAIN.[](*) self; end end def @CONF.inspect IRB.version unless self[:VERSION] array = [] for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name} case k when :MAIN_CONTEXT, :__TMP__EHV__ array.push format("CONF[:%s]=...myself...", k.id2name) when :PROMPT s = v.collect{ |kk, vv| ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"} format(":%s=>{%s}", kk.id2name, ss.join(", ")) } array.push format("CONF[:%s]={%s}", k.id2name, s.join(", ")) else array.push format("CONF[:%s]=%s", k.id2name, v.inspect) end end array.join("\n") end end class Binding # Opens an IRB session where +binding.irb+ is called which allows for # interactive debugging. You can call any methods or variables available in # the current scope, and mutate state if you need to. # # # Given a Ruby file called +potato.rb+ containing the following code: # # class Potato # def initialize # @cooked = false # binding.irb # puts "Cooked potato: #{@cooked}" # end # end # # Potato.new # # Running ruby potato.rb will open an IRB session where # +binding.irb+ is called, and you will see the following: # # $ ruby potato.rb # # From: potato.rb @ line 4 : # # 1: class Potato # 2: def initialize # 3: @cooked = false # => 4: binding.irb # 5: puts "Cooked potato: #{@cooked}" # 6: end # 7: end # 8: # 9: Potato.new # # irb(#):001:0> # # You can type any valid Ruby code and it will be evaluated in the current # context. This allows you to debug without having to run your code repeatedly: # # irb(#):001:0> @cooked # => false # irb(#):002:0> self.class # => Potato # irb(#):003:0> caller.first # => ".../2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:in `eval'" # irb(#):004:0> @cooked = true # => true # # You can exit the IRB session with the +exit+ command. Note that exiting will # resume execution where +binding.irb+ had paused it, as you can see from the # output printed to standard output in this example: # # irb(#):005:0> exit # Cooked potato: true # # # See IRB@IRB+Usage for more information. def irb IRB.setup(source_location[0], argv: []) workspace = IRB::WorkSpace.new(self) STDOUT.print(workspace.code_around_binding) binding_irb = IRB::Irb.new(workspace) binding_irb.context.irb_path = File.expand_path(source_location[0]) binding_irb.run(IRB.conf) end end PKu])C=C=irb-1.2.6/lib/irb/context.rbnu[# frozen_string_literal: false # # irb/context.rb - irb context # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "workspace" require_relative "inspector" require_relative "input-method" require_relative "output-method" module IRB # A class that wraps the current state of the irb session, including the # configuration of IRB.conf. class Context # Creates a new IRB context. # # The optional +input_method+ argument: # # +nil+:: uses stdin or Reidline or Readline # +String+:: uses a File # +other+:: uses this as InputMethod def initialize(irb, workspace = nil, input_method = nil) @irb = irb if workspace @workspace = workspace else @workspace = WorkSpace.new end @thread = Thread.current if defined? Thread # copy of default configuration @ap_name = IRB.conf[:AP_NAME] @rc = IRB.conf[:RC] @load_modules = IRB.conf[:LOAD_MODULES] if IRB.conf.has_key?(:USE_SINGLELINE) @use_singleline = IRB.conf[:USE_SINGLELINE] elsif IRB.conf.has_key?(:USE_READLINE) # backward compatibility @use_singleline = IRB.conf[:USE_READLINE] else @use_singleline = nil end if IRB.conf.has_key?(:USE_MULTILINE) @use_multiline = IRB.conf[:USE_MULTILINE] elsif IRB.conf.has_key?(:USE_REIDLINE) # backward compatibility @use_multiline = IRB.conf[:USE_REIDLINE] else @use_multiline = nil end @use_colorize = IRB.conf[:USE_COLORIZE] @verbose = IRB.conf[:VERBOSE] @io = nil self.inspect_mode = IRB.conf[:INSPECT_MODE] self.use_tracer = IRB.conf[:USE_TRACER] if IRB.conf[:USE_TRACER] self.use_loader = IRB.conf[:USE_LOADER] if IRB.conf[:USE_LOADER] self.eval_history = IRB.conf[:EVAL_HISTORY] if IRB.conf[:EVAL_HISTORY] @ignore_sigint = IRB.conf[:IGNORE_SIGINT] @ignore_eof = IRB.conf[:IGNORE_EOF] @back_trace_limit = IRB.conf[:BACK_TRACE_LIMIT] self.prompt_mode = IRB.conf[:PROMPT_MODE] if IRB.conf[:SINGLE_IRB] or !defined?(IRB::JobManager) @irb_name = IRB.conf[:IRB_NAME] else @irb_name = IRB.conf[:IRB_NAME]+"#"+IRB.JobManager.n_jobs.to_s end @irb_path = "(" + @irb_name + ")" case input_method when nil @io = nil case use_multiline? when nil if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline? # Both of multiline mode and singleline mode aren't specified. @io = ReidlineInputMethod.new else @io = nil end when false @io = nil when true @io = ReidlineInputMethod.new end unless @io case use_singleline? when nil if (defined?(ReadlineInputMethod) && STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY) @io = ReadlineInputMethod.new else @io = nil end when false @io = nil when true if defined?(ReadlineInputMethod) @io = ReadlineInputMethod.new else @io = nil end else @io = nil end end @io = StdioInputMethod.new unless @io when String @io = FileInputMethod.new(input_method) @irb_name = File.basename(input_method) @irb_path = input_method else @io = input_method end self.save_history = IRB.conf[:SAVE_HISTORY] if IRB.conf[:SAVE_HISTORY] @echo = IRB.conf[:ECHO] if @echo.nil? @echo = true end @echo_on_assignment = IRB.conf[:ECHO_ON_ASSIGNMENT] if @echo_on_assignment.nil? @echo_on_assignment = true end @omit_on_assignment = IRB.conf[:OMIT_ON_ASSIGNMENT] if @omit_on_assignment.nil? @omit_on_assignment = true end @newline_before_multiline_output = IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] if @newline_before_multiline_output.nil? @newline_before_multiline_output = true end end # The top-level workspace, see WorkSpace#main def main @workspace.main end # The toplevel workspace, see #home_workspace attr_reader :workspace_home # WorkSpace in the current context attr_accessor :workspace # The current thread in this context attr_reader :thread # The current input method # # Can be either StdioInputMethod, ReadlineInputMethod, # ReidlineInputMethod, FileInputMethod or other specified when the # context is created. See ::new for more # information on +input_method+. attr_accessor :io # Current irb session attr_accessor :irb # A copy of the default IRB.conf[:AP_NAME] attr_accessor :ap_name # A copy of the default IRB.conf[:RC] attr_accessor :rc # A copy of the default IRB.conf[:LOAD_MODULES] attr_accessor :load_modules # Can be either name from IRB.conf[:IRB_NAME], or the number of # the current job set by JobManager, such as irb#2 attr_accessor :irb_name # Can be either the #irb_name surrounded by parenthesis, or the # +input_method+ passed to Context.new attr_accessor :irb_path # Whether multiline editor mode is enabled or not. # # A copy of the default IRB.conf[:USE_MULTILINE] attr_reader :use_multiline # Whether singleline editor mode is enabled or not. # # A copy of the default IRB.conf[:USE_SINGLELINE] attr_reader :use_singleline # Whether colorization is enabled or not. # # A copy of the default IRB.conf[:USE_COLORIZE] attr_reader :use_colorize # A copy of the default IRB.conf[:INSPECT_MODE] attr_reader :inspect_mode # A copy of the default IRB.conf[:PROMPT_MODE] attr_reader :prompt_mode # Standard IRB prompt # # See IRB@Customizing+the+IRB+Prompt for more information. attr_accessor :prompt_i # IRB prompt for continuated strings # # See IRB@Customizing+the+IRB+Prompt for more information. attr_accessor :prompt_s # IRB prompt for continuated statement (e.g. immediately after an +if+) # # See IRB@Customizing+the+IRB+Prompt for more information. attr_accessor :prompt_c # See IRB@Customizing+the+IRB+Prompt for more information. attr_accessor :prompt_n # Can be either the default IRB.conf[:AUTO_INDENT], or the # mode set by #prompt_mode= # # To disable auto-indentation in irb: # # IRB.conf[:AUTO_INDENT] = false # # or # # irb_context.auto_indent_mode = false # # or # # IRB.CurrentContext.auto_indent_mode = false # # See IRB@Configuration for more information. attr_accessor :auto_indent_mode # The format of the return statement, set by #prompt_mode= using the # +:RETURN+ of the +mode+ passed to set the current #prompt_mode. attr_accessor :return_format # Whether ^C (+control-c+) will be ignored or not. # # If set to +false+, ^C will quit irb. # # If set to +true+, # # * during input: cancel input then return to top level. # * during execute: abandon current execution. attr_accessor :ignore_sigint # Whether ^D (+control-d+) will be ignored or not. # # If set to +false+, ^D will quit irb. attr_accessor :ignore_eof # Whether to echo the return value to output or not. # # Uses IRB.conf[:ECHO] if available, or defaults to +true+. # # puts "hello" # # hello # #=> nil # IRB.CurrentContext.echo = false # puts "omg" # # omg attr_accessor :echo # Whether to echo for assignment expressions # # Uses IRB.conf[:ECHO_ON_ASSIGNMENT] if available, or defaults to +true+. # # a = "omg" # #=> omg # IRB.CurrentContext.echo_on_assignment = false # a = "omg" attr_accessor :echo_on_assignment # Whether to omit echo for assignment expressions # # Uses IRB.conf[:OMIT_ON_ASSIGNMENT] if available, or defaults to +true+. # # a = [1] * 10 # #=> [1, 1, 1, 1, 1, 1, 1, 1, ... # [1] * 10 # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # IRB.CurrentContext.omit_on_assignment = false # a = [1] * 10 # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # [1] * 10 # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] attr_accessor :omit_on_assignment # Whether a newline is put before multiline output. # # Uses IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] if available, # or defaults to +true+. # # "abc\ndef" # #=> # abc # def # IRB.CurrentContext.newline_before_multiline_output = false # "abc\ndef" # #=> abc # def attr_accessor :newline_before_multiline_output # Whether verbose messages are displayed or not. # # A copy of the default IRB.conf[:VERBOSE] attr_accessor :verbose # The limit of backtrace lines displayed as top +n+ and tail +n+. # # The default value is 16. # # Can also be set using the +--back-trace-limit+ command line option. # # See IRB@Command+line+options for more command line options. attr_accessor :back_trace_limit # Alias for #use_multiline alias use_multiline? use_multiline # Alias for #use_singleline alias use_singleline? use_singleline # backward compatibility alias use_reidline use_multiline # backward compatibility alias use_reidline? use_multiline # backward compatibility alias use_readline use_singleline # backward compatibility alias use_readline? use_singleline # Alias for #use_colorize alias use_colorize? use_colorize # Alias for #rc alias rc? rc alias ignore_sigint? ignore_sigint alias ignore_eof? ignore_eof alias echo? echo alias echo_on_assignment? echo_on_assignment alias omit_on_assignment? omit_on_assignment alias newline_before_multiline_output? newline_before_multiline_output # Returns whether messages are displayed or not. def verbose? if @verbose.nil? if @io.kind_of?(ReidlineInputMethod) false elsif defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod) false elsif !STDIN.tty? or @io.kind_of?(FileInputMethod) true else false end else @verbose end end # Whether #verbose? is +true+, and +input_method+ is either # StdioInputMethod or ReidlineInputMethod or ReadlineInputMethod, see #io # for more information. def prompting? verbose? || (STDIN.tty? && @io.kind_of?(StdioInputMethod) || @io.kind_of?(ReidlineInputMethod) || (defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod))) end # The return value of the last statement evaluated. attr_reader :last_value # Sets the return value from the last statement evaluated in this context # to #last_value. def set_last_value(value) @last_value = value @workspace.local_variable_set :_, value end # Sets the +mode+ of the prompt in this context. # # See IRB@Customizing+the+IRB+Prompt for more information. def prompt_mode=(mode) @prompt_mode = mode pconf = IRB.conf[:PROMPT][mode] @prompt_i = pconf[:PROMPT_I] @prompt_s = pconf[:PROMPT_S] @prompt_c = pconf[:PROMPT_C] @prompt_n = pconf[:PROMPT_N] @return_format = pconf[:RETURN] if ai = pconf.include?(:AUTO_INDENT) @auto_indent_mode = ai else @auto_indent_mode = IRB.conf[:AUTO_INDENT] end end # Whether #inspect_mode is set or not, see #inspect_mode= for more detail. def inspect? @inspect_mode.nil? or @inspect_mode end # Whether #io uses a File for the +input_method+ passed when creating the # current context, see ::new def file_input? @io.class == FileInputMethod end # Specifies the inspect mode with +opt+: # # +true+:: display +inspect+ # +false+:: display +to_s+ # +nil+:: inspect mode in non-math mode, # non-inspect mode in math mode # # See IRB::Inspector for more information. # # Can also be set using the +--inspect+ and +--noinspect+ command line # options. # # See IRB@Command+line+options for more command line options. def inspect_mode=(opt) if i = Inspector::INSPECTORS[opt] @inspect_mode = opt @inspect_method = i i.init else case opt when nil if Inspector.keys_with_inspector(Inspector::INSPECTORS[true]).include?(@inspect_mode) self.inspect_mode = false elsif Inspector.keys_with_inspector(Inspector::INSPECTORS[false]).include?(@inspect_mode) self.inspect_mode = true else puts "Can't switch inspect mode." return end when /^\s*\{.*\}\s*$/ begin inspector = eval "proc#{opt}" rescue Exception puts "Can't switch inspect mode(#{opt})." return end self.inspect_mode = inspector when Proc self.inspect_mode = IRB::Inspector(opt) when Inspector prefix = "usr%d" i = 1 while Inspector::INSPECTORS[format(prefix, i)]; i += 1; end @inspect_mode = format(prefix, i) @inspect_method = opt Inspector.def_inspector(format(prefix, i), @inspect_method) else puts "Can't switch inspect mode(#{opt})." return end end print "Switch to#{unless @inspect_mode; ' non';end} inspect mode.\n" if verbose? @inspect_mode end def evaluate(line, line_no, exception: nil) # :nodoc: @line_no = line_no if exception line_no -= 1 line = "begin ::Kernel.raise _; rescue _.class\n#{line}\n""end" @workspace.local_variable_set(:_, exception) end set_last_value(@workspace.evaluate(self, line, irb_path, line_no)) end def inspect_last_value # :nodoc: @inspect_method.inspect_value(@last_value) end alias __exit__ exit # Exits the current session, see IRB.irb_exit def exit(ret = 0) IRB.irb_exit(@irb, ret) end NOPRINTING_IVARS = ["@last_value"] # :nodoc: NO_INSPECTING_IVARS = ["@irb", "@io"] # :nodoc: IDNAME_IVARS = ["@prompt_mode"] # :nodoc: alias __inspect__ inspect def inspect # :nodoc: array = [] for ivar in instance_variables.sort{|e1, e2| e1 <=> e2} ivar = ivar.to_s name = ivar.sub(/^@(.*)$/, '\1') val = instance_eval(ivar) case ivar when *NOPRINTING_IVARS array.push format("conf.%s=%s", name, "...") when *NO_INSPECTING_IVARS array.push format("conf.%s=%s", name, val.to_s) when *IDNAME_IVARS array.push format("conf.%s=:%s", name, val.id2name) else array.push format("conf.%s=%s", name, val.inspect) end end array.join("\n") end alias __to_s__ to_s alias to_s inspect end end PKu]*\irb-1.2.6/lib/irb/help.rbnu[# frozen_string_literal: false # # irb/help.rb - print usage module # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # # # require_relative 'magic-file' module IRB # Outputs the irb help message, see IRB@Command+line+options. def IRB.print_usage lc = IRB.conf[:LC_MESSAGES] path = lc.find("irb/help-message") space_line = false IRB::MagicFile.open(path){|f| f.each_line do |l| if /^\s*$/ =~ l lc.puts l unless space_line space_line = true next end space_line = false l.sub!(/#.*$/, "") next if /^\s*$/ =~ l lc.puts l end } end end PKu],9Ykirb-1.2.6/lib/irb/lc/error.rbnu[# frozen_string_literal: false # # irb/lc/error.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # # :stopdoc: module IRB class UnrecognizedSwitch < StandardError def initialize(val) super("Unrecognized switch: #{val}") end end class NotImplementedError < StandardError def initialize(val) super("Need to define `#{val}'") end end class CantReturnToNormalMode < StandardError def initialize super("Can't return to normal mode.") end end class IllegalParameter < StandardError def initialize(val) super("Invalid parameter(#{val}).") end end class IrbAlreadyDead < StandardError def initialize super("Irb is already dead.") end end class IrbSwitchedToCurrentThread < StandardError def initialize super("Switched to current thread.") end end class NoSuchJob < StandardError def initialize(val) super("No such job(#{val}).") end end class CantShiftToMultiIrbMode < StandardError def initialize super("Can't shift to multi irb mode.") end end class CantChangeBinding < StandardError def initialize(val) super("Can't change binding to (#{val}).") end end class UndefinedPromptMode < StandardError def initialize(val) super("Undefined prompt mode(#{val}).") end end class IllegalRCGenerator < StandardError def initialize super("Define illegal RC_NAME_GENERATOR.") end end end # :startdoc: PKu]\`9+irb-1.2.6/lib/irb/lc/ja/encoding_aliases.rbnu[# frozen_string_literal: false # :stopdoc: module IRB class Locale @@legacy_encoding_alias_map = { 'ujis' => Encoding::EUC_JP, 'euc' => Encoding::EUC_JP }.freeze end end # :startdoc: PKu]. irb-1.2.6/lib/irb/lc/ja/error.rbnu[# -*- coding: utf-8 -*- # frozen_string_literal: false # irb/lc/ja/error.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # # :stopdoc: module IRB class UnrecognizedSwitch < StandardError def initialize(val) super("スイッチ(#{val})が分りません") end end class NotImplementedError < StandardError def initialize(val) super("`#{val}'の定義が必要です") end end class CantReturnToNormalMode < StandardError def initialize super("Normalモードに戻れません.") end end class IllegalParameter < StandardError def initialize(val) super("パラメータ(#{val})が間違っています.") end end class IrbAlreadyDead < StandardError def initialize super("Irbは既に死んでいます.") end end class IrbSwitchedToCurrentThread < StandardError def initialize super("カレントスレッドに切り替わりました.") end end class NoSuchJob < StandardError def initialize(val) super("そのようなジョブ(#{val})はありません.") end end class CantShiftToMultiIrbMode < StandardError def initialize super("multi-irb modeに移れません.") end end class CantChangeBinding < StandardError def initialize(val) super("バインディング(#{val})に変更できません.") end end class UndefinedPromptMode < StandardError def initialize(val) super("プロンプトモード(#{val})は定義されていません.") end end class IllegalRCGenerator < StandardError def initialize super("RC_NAME_GENERATORが正しく定義されていません.") end end end # :startdoc: # vim:fileencoding=utf-8 PKu]Ȇ@Dj j $irb-1.2.6/lib/irb/lc/ja/help-messagenu[# -*- coding: utf-8 -*- # irb/lc/ja/help-message.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # Usage: irb.rb [options] [programfile] [arguments] -f ~/.irbrc を読み込まない. -d $DEBUG をtrueにする(ruby -d と同じ) -r load-module ruby -r と同じ. -I path $LOAD_PATH に path を追加する. -U ruby -U と同じ. -E enc ruby -E と同じ. -w ruby -w と同じ. -W[level=2] ruby -W と同じ. --context-mode n 新しいワークスペースを作成した時に関連する Binding オブジェクトの作成方法を 0 から 3 のいずれかに設定する. --echo 実行結果を表示する(デフォルト). --noecho 実行結果を表示しない. --inspect 結果出力にinspectを用いる. --noinspect 結果出力にinspectを用いない. --multiline マルチラインエディタを利用する. --nomultiline マルチラインエディタを利用しない. --singleline シングルラインエディタを利用する. --nosingleline シングルラインエディタを利用しない. --colorize 色付けを利用する. --nocolorize 色付けを利用しない. --prompt prompt-mode/--prompt-mode prompt-mode プロンプトモードを切替えます. 現在定義されているプ ロンプトモードは, default, simple, xmp, inf-rubyが 用意されています. --inf-ruby-mode emacsのinf-ruby-mode用のプロンプト表示を行なう. 特 に指定がない限り, シングルラインエディタとマルチラ インエディタは使わなくなる. --sample-book-mode/--simple-prompt 非常にシンプルなプロンプトを用いるモードです. --noprompt プロンプト表示を行なわない. --single-irb irb 中で self を実行して得られるオブジェクトをサ ブ irb と共有する. --tracer コマンド実行時にトレースを行なう. --back-trace-limit n バックトレース表示をバックトレースの頭から n, 後ろ からnだけ行なう. デフォルトは16 --verbose 詳細なメッセージを出力する. --noverbose 詳細なメッセージを出力しない(デフォルト). -v, --version irbのバージョンを表示する. -h, --help irb のヘルプを表示する. -- 以降のコマンドライン引数をオプションとして扱わない. # vim:fileencoding=utf-8 PKu]o]!irb-1.2.6/lib/irb/lc/help-messagenu[# -*- coding: utf-8 -*- # # irb/lc/help-message.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # Usage: irb.rb [options] [programfile] [arguments] -f Suppress read of ~/.irbrc -d Set $DEBUG to true (same as `ruby -d') -r load-module Same as `ruby -r' -I path Specify $LOAD_PATH directory -U Same as `ruby -U` -E enc Same as `ruby -E` -w Same as `ruby -w` -W[level=2] Same as `ruby -W` --context-mode n Set n[0-3] to method to create Binding Object, when new workspace was created --echo Show result(default) --noecho Don't show result --inspect Use `inspect' for output --noinspect Don't use inspect for output --multiline Use multiline editor module --nomultiline Don't use multiline editor module --singleline Use singleline editor module --nosingleline Don't use singleline editor module --colorize Use colorization --nocolorize Don't use colorization --prompt prompt-mode/--prompt-mode prompt-mode Switch prompt mode. Pre-defined prompt modes are `default', `simple', `xmp' and `inf-ruby' --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs. Suppresses --multiline and --singleline. --sample-book-mode/--simple-prompt Simple prompt mode --noprompt No prompt mode --single-irb Share self with sub-irb. --tracer Display trace for each execution of commands. --back-trace-limit n Display backtrace top n and tail n. The default value is 16. --verbose Show details --noverbose Don't show details -v, --version Print the version of irb -h, --help Print help -- Separate options of irb from the list of command-line args # vim:fileencoding=utf-8 PKu]ᣟ##!irb-1.2.6/lib/irb/input-method.rbnu[# frozen_string_literal: false # # irb/input-method.rb - input methods used irb # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative 'src_encoding' require_relative 'magic-file' require_relative 'completion' require 'io/console' require 'reline' module IRB STDIN_FILE_NAME = "(line)" # :nodoc: class InputMethod # Creates a new input method object def initialize(file = STDIN_FILE_NAME) @file_name = file end # The file name of this input method, usually given during initialization. attr_reader :file_name # The irb prompt associated with this input method attr_accessor :prompt # Reads the next line from this input method. # # See IO#gets for more information. def gets fail NotImplementedError, "gets" end public :gets def winsize if instance_variable_defined?(:@stdout) @stdout.winsize else [24, 80] end end # Whether this input method is still readable when there is no more data to # read. # # See IO#eof for more information. def readable_after_eof? false end # For debug message def inspect 'Abstract InputMethod' end end class StdioInputMethod < InputMethod # Creates a new input method object def initialize super @line_no = 0 @line = [] @stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") @stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") end # Reads the next line from this input method. # # See IO#gets for more information. def gets print @prompt line = @stdin.gets @line[@line_no += 1] = line end # Whether the end of this input method has been reached, returns +true+ if # there is no more data to read. # # See IO#eof? for more information. def eof? @stdin.eof? end # Whether this input method is still readable when there is no more data to # read. # # See IO#eof for more information. def readable_after_eof? true end # Returns the current line number for #io. # # #line counts the number of times #gets is called. # # See IO#lineno for more information. def line(line_no) @line[line_no] end # The external encoding for standard input. def encoding @stdin.external_encoding end # For debug message def inspect 'StdioInputMethod' end end # Use a File for IO with irb, see InputMethod class FileInputMethod < InputMethod # Creates a new input method object def initialize(file) super @io = IRB::MagicFile.open(file) end # The file name of this input method, usually given during initialization. attr_reader :file_name # Whether the end of this input method has been reached, returns +true+ if # there is no more data to read. # # See IO#eof? for more information. def eof? @io.eof? end # Reads the next line from this input method. # # See IO#gets for more information. def gets print @prompt @io.gets end # The external encoding for standard input. def encoding @io.external_encoding end # For debug message def inspect 'FileInputMethod' end end begin class ReadlineInputMethod < InputMethod def self.initialize_readline require "readline" rescue LoadError else include ::Readline end # Creates a new input method object using Readline def initialize self.class.initialize_readline if Readline.respond_to?(:encoding_system_needs) IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false) end super @line_no = 0 @line = [] @eof = false @stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") @stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") if Readline.respond_to?("basic_word_break_characters=") Readline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS end Readline.completion_append_character = nil Readline.completion_proc = IRB::InputCompletor::CompletionProc end # Reads the next line from this input method. # # See IO#gets for more information. def gets Readline.input = @stdin Readline.output = @stdout if l = readline(@prompt, false) HISTORY.push(l) if !l.empty? @line[@line_no += 1] = l + "\n" else @eof = true l end end # Whether the end of this input method has been reached, returns +true+ # if there is no more data to read. # # See IO#eof? for more information. def eof? @eof end # Whether this input method is still readable when there is no more data to # read. # # See IO#eof for more information. def readable_after_eof? true end # Returns the current line number for #io. # # #line counts the number of times #gets is called. # # See IO#lineno for more information. def line(line_no) @line[line_no] end # The external encoding for standard input. def encoding @stdin.external_encoding end # For debug message def inspect readline_impl = (defined?(Reline) && Readline == Reline) ? 'Reline' : 'ext/readline' str = "ReadlineInputMethod with #{readline_impl} #{Readline::VERSION}" inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc') str += " and #{inputrc_path}" if File.exist?(inputrc_path) str end end end class ReidlineInputMethod < InputMethod include Reline # Creates a new input method object using Readline def initialize IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false) super @line_no = 0 @line = [] @eof = false @stdin = ::IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") @stdout = ::IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-") if Reline.respond_to?("basic_word_break_characters=") Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS end Reline.completion_append_character = nil Reline.completion_proc = IRB::InputCompletor::CompletionProc Reline.output_modifier_proc = if IRB.conf[:USE_COLORIZE] proc do |output, complete: | next unless IRB::Color.colorable? IRB::Color.colorize_code(output, complete: complete) end else proc do |output| Reline::Unicode.escape_for_print(output) end end Reline.dig_perfect_match_proc = IRB::InputCompletor::PerfectMatchedProc end def check_termination(&block) @check_termination_proc = block end def dynamic_prompt(&block) @prompt_proc = block end def auto_indent(&block) @auto_indent_proc = block end # Reads the next line from this input method. # # See IO#gets for more information. def gets Reline.input = @stdin Reline.output = @stdout Reline.prompt_proc = @prompt_proc Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc if l = readmultiline(@prompt, false, &@check_termination_proc) HISTORY.push(l) if !l.empty? @line[@line_no += 1] = l + "\n" else @eof = true l end end # Whether the end of this input method has been reached, returns +true+ # if there is no more data to read. # # See IO#eof? for more information. def eof? @eof end # Whether this input method is still readable when there is no more data to # read. # # See IO#eof for more information. def readable_after_eof? true end # Returns the current line number for #io. # # #line counts the number of times #gets is called. # # See IO#lineno for more information. def line(line_no) @line[line_no] end # The external encoding for standard input. def encoding @stdin.external_encoding end # For debug message def inspect config = Reline::Config.new str = "ReidlineInputMethod with Reline #{Reline::VERSION}" if config.respond_to?(:inputrc_path) inputrc_path = File.expand_path(config.inputrc_path) else inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc') end str += " and #{inputrc_path}" if File.exist?(inputrc_path) str end end end PKu]C5vlirb-1.2.6/lib/irb/ext/tracer.rbnu[# frozen_string_literal: false # # irb/lib/tracer.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # begin require "tracer" rescue LoadError $stderr.puts "Tracer extension of IRB is enabled but tracer gem doesn't found." module IRB TracerLoadError = true class Context def use_tracer=(opt) # do nothing end end end return # This is about to disable loading below end module IRB # initialize tracing function def IRB.initialize_tracer Tracer.verbose = false Tracer.add_filter { |event, file, line, id, binding, *rests| /^#{Regexp.quote(@CONF[:IRB_LIB_PATH])}/ !~ file and File::basename(file) != "irb.rb" } end class Context # Whether Tracer is used when evaluating statements in this context. # # See +lib/tracer.rb+ for more information. attr_reader :use_tracer alias use_tracer? use_tracer # Sets whether or not to use the Tracer library when evaluating statements # in this context. # # See +lib/tracer.rb+ for more information. def use_tracer=(opt) if opt Tracer.set_get_line_procs(@irb_path) { |line_no, *rests| @io.line(line_no) } elsif !opt && @use_tracer Tracer.off end @use_tracer=opt end end class WorkSpace alias __evaluate__ evaluate # Evaluate the context of this workspace and use the Tracer library to # output the exact lines of code are being executed in chronological order. # # See +lib/tracer.rb+ for more information. def evaluate(context, statements, file = nil, line = nil) if context.use_tracer? && file != nil && line != nil Tracer.on begin __evaluate__(context, statements, file, line) ensure Tracer.off end else __evaluate__(context, statements, file || __FILE__, line || __LINE__) end end end IRB.initialize_tracer end PKu]yr| | irb-1.2.6/lib/irb/ext/loader.rbnu[# frozen_string_literal: false # # loader.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: # Raised in the event of an exception in a file loaded from an Irb session class LoadAbort < Exception;end # Provides a few commands for loading files within an irb session. # # See ExtendCommandBundle for more information. module IrbLoader alias ruby_load load alias ruby_require require # Loads the given file similarly to Kernel#load def irb_load(fn, priv = nil) path = search_file_from_ruby_path(fn) raise LoadError, "No such file to load -- #{fn}" unless path load_file(path, priv) end def search_file_from_ruby_path(fn) # :nodoc: if /^#{Regexp.quote(File::Separator)}/ =~ fn return fn if File.exist?(fn) return nil end for path in $: if File.exist?(f = File.join(path, fn)) return f end end return nil end # Loads a given file in the current session and displays the source lines # # See Irb#suspend_input_method for more information. def source_file(path) irb.suspend_name(path, File.basename(path)) do irb.suspend_input_method(FileInputMethod.new(path)) do |back_io| irb.signal_status(:IN_LOAD) do if back_io.kind_of?(FileInputMethod) irb.eval_input else begin irb.eval_input rescue LoadAbort print "load abort!!\n" end end end end end end # Loads the given file in the current session's context and evaluates it. # # See Irb#suspend_input_method for more information. def load_file(path, priv = nil) irb.suspend_name(path, File.basename(path)) do if priv ws = WorkSpace.new(Module.new) else ws = WorkSpace.new end irb.suspend_workspace(ws) do irb.suspend_input_method(FileInputMethod.new(path)) do |back_io| irb.signal_status(:IN_LOAD) do if back_io.kind_of?(FileInputMethod) irb.eval_input else begin irb.eval_input rescue LoadAbort print "load abort!!\n" end end end end end end end def old # :nodoc: back_io = @io back_path = @irb_path back_name = @irb_name back_scanner = @irb.scanner begin @io = FileInputMethod.new(path) @irb_name = File.basename(path) @irb_path = path @irb.signal_status(:IN_LOAD) do if back_io.kind_of?(FileInputMethod) @irb.eval_input else begin @irb.eval_input rescue LoadAbort print "load abort!!\n" end end end ensure @io = back_io @irb_name = back_name @irb_path = back_path @irb.scanner = back_scanner end end end end PKu]](  "irb-1.2.6/lib/irb/ext/change-ws.rbnu[# frozen_string_literal: false # # irb/ext/cb.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: class Context # Inherited from +TOPLEVEL_BINDING+. def home_workspace if defined? @home_workspace @home_workspace else @home_workspace = @workspace end end # Changes the current workspace to given object or binding. # # If the optional argument is omitted, the workspace will be # #home_workspace which is inherited from +TOPLEVEL_BINDING+ or the main # object, IRB.conf[:MAIN_CONTEXT] when irb was initialized. # # See IRB::WorkSpace.new for more information. def change_workspace(*_main) if _main.empty? @workspace = home_workspace return main end @workspace = WorkSpace.new(_main[0]) if !(class<IRB.conf[:SAVE_HISTORY] def save_history IRB.conf[:SAVE_HISTORY] end remove_method(:save_history=) if method_defined?(:save_history=) # Sets IRB.conf[:SAVE_HISTORY] to the given +val+ and calls # #init_save_history with this context. # # Will store the number of +val+ entries of history in the #history_file # # Add the following to your +.irbrc+ to change the number of history # entries stored to 1000: # # IRB.conf[:SAVE_HISTORY] = 1000 def save_history=(val) IRB.conf[:SAVE_HISTORY] = val if val main_context = IRB.conf[:MAIN_CONTEXT] main_context = self unless main_context main_context.init_save_history end end # A copy of the default IRB.conf[:HISTORY_FILE] def history_file IRB.conf[:HISTORY_FILE] end # Set IRB.conf[:HISTORY_FILE] to the given +hist+. def history_file=(hist) IRB.conf[:HISTORY_FILE] = hist end end module HistorySavingAbility # :nodoc: def HistorySavingAbility.extended(obj) IRB.conf[:AT_EXIT].push proc{obj.save_history} obj.load_history obj end def load_history return unless self.class.const_defined?(:HISTORY) history = self.class::HISTORY if history_file = IRB.conf[:HISTORY_FILE] history_file = File.expand_path(history_file) end history_file = IRB.rc_file("_history") unless history_file if File.exist?(history_file) open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f| f.each { |l| l = l.chomp if self.class == ReidlineInputMethod and history.last&.end_with?("\\") history.last.delete_suffix!("\\") history.last << "\n" << l else history << l end } end end end def save_history return unless self.class.const_defined?(:HISTORY) history = self.class::HISTORY if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) != 0 if history_file = IRB.conf[:HISTORY_FILE] history_file = File.expand_path(history_file) end history_file = IRB.rc_file("_history") unless history_file # Change the permission of a file that already exists[BUG #7694] begin if File.stat(history_file).mode & 066 != 0 File.chmod(0600, history_file) end rescue Errno::ENOENT rescue Errno::EPERM return rescue raise end open(history_file, "w:#{IRB.conf[:LC_MESSAGES].encoding}", 0600) do |f| hist = history.map{ |l| l.split("\n").join("\\\n") } begin hist = hist.last(num) if hist.size > num and num > 0 rescue RangeError # bignum too big to convert into `long' # Do nothing because the bignum should be treated as inifinity end f.puts(hist) end end end end end PKu]uI"irb-1.2.6/lib/irb/ext/multi-irb.rbnu[# frozen_string_literal: false # # irb/multi-irb.rb - multiple irb module # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # fail CantShiftToMultiIrbMode unless defined?(Thread) module IRB class JobManager # Creates a new JobManager object def initialize @jobs = [] @current_job = nil end # The active irb session attr_accessor :current_job # The total number of irb sessions, used to set +irb_name+ of the current # Context. def n_jobs @jobs.size end # Returns the thread for the given +key+ object, see #search for more # information. def thread(key) th, = search(key) th end # Returns the irb session for the given +key+ object, see #search for more # information. def irb(key) _, irb = search(key) irb end # Returns the top level thread. def main_thread @jobs[0][0] end # Returns the top level irb session. def main_irb @jobs[0][1] end # Add the given +irb+ session to the jobs Array. def insert(irb) @jobs.push [Thread.current, irb] end # Changes the current active irb session to the given +key+ in the jobs # Array. # # Raises an IrbAlreadyDead exception if the given +key+ is no longer alive. # # If the given irb session is already active, an IrbSwitchedToCurrentThread # exception is raised. def switch(key) th, irb = search(key) fail IrbAlreadyDead unless th.alive? fail IrbSwitchedToCurrentThread if th == Thread.current @current_job = irb th.run Thread.stop @current_job = irb(Thread.current) end # Terminates the irb sessions specified by the given +keys+. # # Raises an IrbAlreadyDead exception if one of the given +keys+ is already # terminated. # # See Thread#exit for more information. def kill(*keys) for key in keys th, _ = search(key) fail IrbAlreadyDead unless th.alive? th.exit end end # Returns the associated job for the given +key+. # # If given an Integer, it will return the +key+ index for the jobs Array. # # When an instance of Irb is given, it will return the irb session # associated with +key+. # # If given an instance of Thread, it will return the associated thread # +key+ using Object#=== on the jobs Array. # # Otherwise returns the irb session with the same top-level binding as the # given +key+. # # Raises a NoSuchJob exception if no job can be found with the given +key+. def search(key) job = case key when Integer @jobs[key] when Irb @jobs.find{|k, v| v.equal?(key)} when Thread @jobs.assoc(key) else @jobs.find{|k, v| v.context.main.equal?(key)} end fail NoSuchJob, key if job.nil? job end # Deletes the job at the given +key+. def delete(key) case key when Integer fail NoSuchJob, key unless @jobs[key] @jobs[key] = nil else catch(:EXISTS) do @jobs.each_index do |i| if @jobs[i] and (@jobs[i][0] == key || @jobs[i][1] == key || @jobs[i][1].context.main.equal?(key)) @jobs[i] = nil throw :EXISTS end end fail NoSuchJob, key end end until assoc = @jobs.pop; end unless @jobs.empty? @jobs.push assoc end # Outputs a list of jobs, see the irb command +irb_jobs+, or +jobs+. def inspect ary = [] @jobs.each_index do |i| th, irb = @jobs[i] next if th.nil? if th.alive? if th.stop? t_status = "stop" else t_status = "running" end else t_status = "exited" end ary.push format("#%d->%s on %s (%s: %s)", i, irb.context.irb_name, irb.context.main, th, t_status) end ary.join("\n") end end @JobManager = JobManager.new # The current JobManager in the session def IRB.JobManager @JobManager end # The current Context in this session def IRB.CurrentContext IRB.JobManager.irb(Thread.current).context end # Creates a new IRB session, see Irb.new. # # The optional +file+ argument is given to Context.new, along with the # workspace created with the remaining arguments, see WorkSpace.new def IRB.irb(file = nil, *main) workspace = WorkSpace.new(*main) parent_thread = Thread.current Thread.start do begin irb = Irb.new(workspace, file) rescue print "Subirb can't start with context(self): ", workspace.main.inspect, "\n" print "return to main irb\n" Thread.pass Thread.main.wakeup Thread.exit end @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] @JobManager.insert(irb) @JobManager.current_job = irb begin system_exit = false catch(:IRB_EXIT) do irb.eval_input end rescue SystemExit system_exit = true raise #fail ensure unless system_exit @JobManager.delete(irb) if @JobManager.current_job == irb if parent_thread.alive? @JobManager.current_job = @JobManager.irb(parent_thread) parent_thread.run else @JobManager.current_job = @JobManager.main_irb @JobManager.main_thread.run end end end end end Thread.stop @JobManager.current_job = @JobManager.irb(Thread.current) end @CONF[:SINGLE_IRB_MODE] = false @JobManager.insert(@CONF[:MAIN_CONTEXT].irb) @JobManager.current_job = @CONF[:MAIN_CONTEXT].irb class Irb def signal_handle unless @context.ignore_sigint? print "\nabort!!\n" if @context.verbose? exit end case @signal_status when :IN_INPUT print "^C\n" IRB.JobManager.thread(self).raise RubyLex::TerminateLineInput when :IN_EVAL IRB.irb_abort(self) when :IN_LOAD IRB.irb_abort(self, LoadAbort) when :IN_IRB # ignore else # ignore other cases as well end end end trap("SIGINT") do @JobManager.current_job.signal_handle Thread.stop end end PKu]N9#irb-1.2.6/lib/irb/ext/use-loader.rbnu[# frozen_string_literal: false # # use-loader.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "../cmd/load" require_relative "loader" class Object alias __original__load__IRB_use_loader__ load alias __original__require__IRB_use_loader__ require end module IRB module ExtendCommandBundle remove_method :irb_load if method_defined?(:irb_load) # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load def irb_load(*opts, &b) ExtendCommand::Load.execute(irb_context, *opts, &b) end remove_method :irb_require if method_defined?(:irb_require) # Loads the given file similarly to Kernel#require def irb_require(*opts, &b) ExtendCommand::Require.execute(irb_context, *opts, &b) end end class Context IRB.conf[:USE_LOADER] = false # Returns whether +irb+'s own file reader method is used by # +load+/+require+ or not. # # This mode is globally affected (irb-wide). def use_loader IRB.conf[:USE_LOADER] end alias use_loader? use_loader remove_method :use_loader= if method_defined?(:use_loader=) # Sets IRB.conf[:USE_LOADER] # # See #use_loader for more information. def use_loader=(opt) if IRB.conf[:USE_LOADER] != opt IRB.conf[:USE_LOADER] = opt if opt if !$".include?("irb/cmd/load") end (class<<@workspace.main;self;end).instance_eval { alias_method :load, :irb_load alias_method :require, :irb_require } else (class<<@workspace.main;self;end).instance_eval { alias_method :load, :__original__load__IRB_use_loader__ alias_method :require, :__original__require__IRB_use_loader__ } end end print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose? opt end end end PKu]fcI#irb-1.2.6/lib/irb/ext/workspaces.rbnu[# frozen_string_literal: false # # push-ws.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: class Context # Size of the current WorkSpace stack def irb_level workspace_stack.size end # WorkSpaces in the current stack def workspaces if defined? @workspaces @workspaces else @workspaces = [] end end # Creates a new workspace with the given object or binding, and appends it # onto the current #workspaces stack. # # See IRB::Context#change_workspace and IRB::WorkSpace.new for more # information. def push_workspace(*_main) if _main.empty? if workspaces.empty? print "No other workspace\n" return nil end ws = workspaces.pop workspaces.push @workspace @workspace = ws return workspaces end workspaces.push @workspace @workspace = WorkSpace.new(@workspace.binding, _main[0]) if !(class<IRB.conf[:EVAL_HISTORY] in .irbrc). attr_reader :eval_history # Sets command result history limit. Default value is set from # IRB.conf[:EVAL_HISTORY]. # # +no+ is an Integer or +nil+. # # Returns +no+ of history items if greater than 0. # # If +no+ is 0, the number of history items is unlimited. # # If +no+ is +nil+, execution result history isn't used (default). # # History values are available via __ variable, see # IRB::History. def eval_history=(no) if no if defined?(@eval_history) && @eval_history @eval_history_values.size(no) else @eval_history_values = History.new(no) IRB.conf[:__TMP__EHV__] = @eval_history_values @workspace.evaluate(self, "__ = IRB.conf[:__TMP__EHV__]") IRB.conf.delete(:__TMP_EHV__) end else @eval_history_values = nil end @eval_history = no end end # Represents history of results of previously evaluated commands. # # Available via __ variable, only if IRB.conf[:EVAL_HISTORY] # or IRB::CurrentContext().eval_history is non-nil integer value # (by default it is +nil+). # # Example (in `irb`): # # # Initialize history # IRB::CurrentContext().eval_history = 10 # # => 10 # # # Perform some commands... # 1 + 2 # # => 3 # puts 'x' # # x # # => nil # raise RuntimeError # # ...error raised # # # Inspect history (format is " ": # __ # # => 1 10 # # 2 3 # # 3 nil # # __[1] # # => 10 # class History def initialize(size = 16) # :nodoc: @size = size @contents = [] end def size(size) # :nodoc: if size != 0 && size < @size @contents = @contents[@size - size .. @size] end @size = size end # Get one item of the content (both positive and negative indexes work). def [](idx) begin if idx >= 0 @contents.find{|no, val| no == idx}[1] else @contents[idx][1] end rescue NameError nil end end def push(no, val) # :nodoc: @contents.push [no, val] @contents.shift if @size != 0 && @contents.size > @size end alias real_inspect inspect def inspect # :nodoc: if @contents.empty? return real_inspect end unless (last = @contents.pop)[1].equal?(self) @contents.push last last = nil end str = @contents.collect{|no, val| if val.equal?(self) "#{no} ...self-history..." else "#{no} #{val.inspect}" end }.join("\n") if str == "" str = "Empty." end @contents.push last if last str end end end PKu]:?cBcBirb-1.2.6/lib/irb/ruby-lex.rbnu[# frozen_string_literal: false # # irb/ruby-lex.rb - ruby lexcal analyzer # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "ripper" require "jruby" if RUBY_ENGINE == "jruby" # :stopdoc: class RubyLex class TerminateLineInput < StandardError def initialize super("Terminate Line Input") end end def initialize @exp_line_no = @line_no = 1 @indent = 0 @continue = false @line = "" @prompt = nil end def self.compile_with_errors_suppressed(code) line_no = 1 begin result = yield code, line_no rescue ArgumentError code = ";\n#{code}" line_no = 0 result = yield code, line_no end result end # io functions def set_input(io, p = nil, &block) @io = io if @io.respond_to?(:check_termination) @io.check_termination do |code| code.gsub!(/\s*\z/, '').concat("\n") ltype, indent, continue, code_block_open = check_state(code) if ltype or indent > 0 or continue or code_block_open false else true end end end if @io.respond_to?(:dynamic_prompt) @io.dynamic_prompt do |lines| lines << '' if lines.empty? result = [] lines.each_index { |i| c = lines[0..i].map{ |l| l + "\n" }.join ltype, indent, continue, code_block_open = check_state(c) result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + i) } result end end if p.respond_to?(:call) @input = p elsif block_given? @input = block else @input = Proc.new{@io.gets} end end def set_prompt(p = nil, &block) p = block if block_given? if p.respond_to?(:call) @prompt = p else @prompt = Proc.new{print p} end end def ripper_lex_without_warning(code) verbose, $VERBOSE = $VERBOSE, nil tokens = nil self.class.compile_with_errors_suppressed(code) do |inner_code, line_no| tokens = Ripper.lex(inner_code, '-', line_no) end $VERBOSE = verbose tokens end def set_auto_indent(context) if @io.respond_to?(:auto_indent) and context.auto_indent_mode @io.auto_indent do |lines, line_index, byte_pointer, is_newline| if is_newline md = lines[line_index - 1].match(/(\A +)/) prev_spaces = md.nil? ? 0 : md[1].count(' ') @tokens = ripper_lex_without_warning(lines[0..line_index].join("\n")) depth_difference = check_newline_depth_difference prev_spaces + depth_difference * 2 else code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join last_line = lines[line_index]&.byteslice(0, byte_pointer) code += last_line if last_line @tokens = ripper_lex_without_warning(code) corresponding_token_depth = check_corresponding_token_depth if corresponding_token_depth corresponding_token_depth else nil end end end end end def check_state(code) @tokens = ripper_lex_without_warning(code) ltype = process_literal_type indent = process_nesting_level continue = process_continue code_block_open = check_code_block(code) [ltype, indent, continue, code_block_open] end def prompt if @prompt @prompt.call(@ltype, @indent, @continue, @line_no) end end def initialize_input @ltype = nil @indent = 0 @continue = false @line = "" @exp_line_no = @line_no @code_block_open = false end def each_top_level_statement initialize_input catch(:TERM_INPUT) do loop do begin prompt unless l = lex throw :TERM_INPUT if @line == '' else @line_no += l.count("\n") next if l == "\n" @line.concat l if @code_block_open or @ltype or @continue or @indent > 0 next end end if @line != "\n" @line.force_encoding(@io.encoding) yield @line, @exp_line_no end break if @io.eof? @line = '' @exp_line_no = @line_no @indent = 0 rescue TerminateLineInput initialize_input prompt end end end end def lex line = @input.call if @io.respond_to?(:check_termination) return line # multiline end code = @line + (line.nil? ? '' : line) code.gsub!(/\s*\z/, '').concat("\n") @tokens = ripper_lex_without_warning(code) @continue = process_continue @code_block_open = check_code_block(code) @indent = process_nesting_level @ltype = process_literal_type line end def process_continue # last token is always newline if @tokens.size >= 2 and @tokens[-2][1] == :on_regexp_end # end of regexp literal return false elsif @tokens.size >= 2 and @tokens[-2][1] == :on_semicolon return false elsif @tokens.size >= 2 and @tokens[-2][1] == :on_kw and ['begin', 'else', 'ensure'].include?(@tokens[-2][2]) return false elsif !@tokens.empty? and @tokens.last[2] == "\\\n" return true elsif @tokens.size >= 1 and @tokens[-1][1] == :on_heredoc_end # "EOH\n" return false elsif @tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and @tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME) # end of literal except for regexp return true end false end def check_code_block(code) return true if @tokens.empty? if @tokens.last[1] == :on_heredoc_beg return true end begin # check if parser error are available verbose, $VERBOSE = $VERBOSE, nil case RUBY_ENGINE when 'jruby' JRuby.compile_ir(code) else self.class.compile_with_errors_suppressed(code) do |inner_code, line_no| RubyVM::InstructionSequence.compile(inner_code, nil, nil, line_no) end end rescue EncodingError # This is for a hash with invalid encoding symbol, {"\xAE": 1} rescue SyntaxError => e case e.message when /unterminated (?:string|regexp) meets end of file/ # "unterminated regexp meets end of file" # # example: # / # # "unterminated string meets end of file" # # example: # ' return true when /syntax error, unexpected end-of-input/ # "syntax error, unexpected end-of-input, expecting keyword_end" # # example: # if ture # hoge # if false # fuga # end return true when /syntax error, unexpected keyword_end/ # "syntax error, unexpected keyword_end" # # example: # if ( # end # # example: # end return false when /syntax error, unexpected '\.'/ # "syntax error, unexpected '.'" # # example: # . return false when /unexpected tREGEXP_BEG/ # "syntax error, unexpected tREGEXP_BEG, expecting keyword_do or '{' or '('" # # example: # method / f / return false end ensure $VERBOSE = verbose end if defined?(Ripper::EXPR_BEG) last_lex_state = @tokens.last[3] if last_lex_state.allbits?(Ripper::EXPR_BEG) return false elsif last_lex_state.allbits?(Ripper::EXPR_DOT) return true elsif last_lex_state.allbits?(Ripper::EXPR_CLASS) return true elsif last_lex_state.allbits?(Ripper::EXPR_FNAME) return true elsif last_lex_state.allbits?(Ripper::EXPR_VALUE) return true elsif last_lex_state.allbits?(Ripper::EXPR_ARG) return false end end false end def process_nesting_level indent = 0 in_oneliner_def = nil @tokens.each_with_index { |t, index| # detecting one-liner method definition if in_oneliner_def.nil? if t[3].allbits?(Ripper::EXPR_ENDFN) in_oneliner_def = :ENDFN end else if t[3].allbits?(Ripper::EXPR_ENDFN) # continuing elsif t[3].allbits?(Ripper::EXPR_BEG) if t[2] == '=' in_oneliner_def = :BODY end elsif t[3].allbits?(Ripper::EXPR_END) if in_oneliner_def == :BODY # one-liner method definition indent -= 1 end in_oneliner_def = nil else in_oneliner_def = nil end end case t[1] when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg indent += 1 when :on_rbracket, :on_rbrace, :on_rparen indent -= 1 when :on_kw next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME) case t[2] when 'do' if index > 0 and @tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG) # method_with_block do; end indent += 1 else # while cond do; end # also "until" or "for" # This "do" doesn't increment indent because "while" already # incremented. end when 'def', 'case', 'for', 'begin', 'class', 'module' indent += 1 when 'if', 'unless', 'while', 'until' # postfix if/unless/while/until must be Ripper::EXPR_LABEL indent += 1 unless t[3].allbits?(Ripper::EXPR_LABEL) when 'end' indent -= 1 end end # percent literals are not indented } indent end def check_newline_depth_difference depth_difference = 0 open_brace_on_line = 0 in_oneliner_def = nil @tokens.each_with_index do |t, index| # detecting one-liner method definition if in_oneliner_def.nil? if t[3].allbits?(Ripper::EXPR_ENDFN) in_oneliner_def = :ENDFN end else if t[3].allbits?(Ripper::EXPR_ENDFN) # continuing elsif t[3].allbits?(Ripper::EXPR_BEG) if t[2] == '=' in_oneliner_def = :BODY end elsif t[3].allbits?(Ripper::EXPR_END) if in_oneliner_def == :BODY # one[-liner method definition depth_difference -= 1 end in_oneliner_def = nil else in_oneliner_def = nil end end case t[1] when :on_ignored_nl, :on_nl, :on_comment if index != (@tokens.size - 1) depth_difference = 0 open_brace_on_line = 0 end next when :on_sp next end case t[1] when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg depth_difference += 1 open_brace_on_line += 1 when :on_rbracket, :on_rbrace, :on_rparen depth_difference -= 1 if open_brace_on_line > 0 when :on_kw next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME) case t[2] when 'do' if index > 0 and @tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG) # method_with_block do; end depth_difference += 1 else # while cond do; end # also "until" or "for" # This "do" doesn't increment indent because "while" already # incremented. end when 'def', 'case', 'for', 'begin', 'class', 'module' depth_difference += 1 when 'if', 'unless', 'while', 'until', 'rescue' # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL unless t[3].allbits?(Ripper::EXPR_LABEL) depth_difference += 1 end when 'else', 'elsif', 'ensure', 'when', 'in' depth_difference += 1 end end end depth_difference end def check_corresponding_token_depth corresponding_token_depth = nil is_first_spaces_of_line = true is_first_printable_of_line = true spaces_of_nest = [] spaces_at_line_head = 0 open_brace_on_line = 0 in_oneliner_def = nil @tokens.each_with_index do |t, index| # detecting one-liner method definition if in_oneliner_def.nil? if t[3].allbits?(Ripper::EXPR_ENDFN) in_oneliner_def = :ENDFN end else if t[3].allbits?(Ripper::EXPR_ENDFN) # continuing elsif t[3].allbits?(Ripper::EXPR_BEG) if t[2] == '=' in_oneliner_def = :BODY end elsif t[3].allbits?(Ripper::EXPR_END) if in_oneliner_def == :BODY # one-liner method definition if is_first_printable_of_line corresponding_token_depth = spaces_of_nest.pop else spaces_of_nest.pop corresponding_token_depth = nil end end in_oneliner_def = nil else in_oneliner_def = nil end end case t[1] when :on_ignored_nl, :on_nl, :on_comment corresponding_token_depth = nil spaces_at_line_head = 0 is_first_spaces_of_line = true is_first_printable_of_line = true open_brace_on_line = 0 next when :on_sp spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line is_first_spaces_of_line = false next end case t[1] when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg spaces_of_nest.push(spaces_at_line_head + open_brace_on_line * 2) open_brace_on_line += 1 when :on_rbracket, :on_rbrace, :on_rparen if is_first_printable_of_line corresponding_token_depth = spaces_of_nest.pop else spaces_of_nest.pop corresponding_token_depth = nil end open_brace_on_line -= 1 when :on_kw next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME) case t[2] when 'def', 'do', 'case', 'for', 'begin', 'class', 'module' spaces_of_nest.push(spaces_at_line_head) when 'rescue' unless t[3].allbits?(Ripper::EXPR_LABEL) corresponding_token_depth = spaces_of_nest.last end when 'if', 'unless', 'while', 'until' # postfix if/unless/while/until must be Ripper::EXPR_LABEL unless t[3].allbits?(Ripper::EXPR_LABEL) spaces_of_nest.push(spaces_at_line_head) end when 'else', 'elsif', 'ensure', 'when', 'in' corresponding_token_depth = spaces_of_nest.last when 'end' if is_first_printable_of_line corresponding_token_depth = spaces_of_nest.pop else spaces_of_nest.pop corresponding_token_depth = nil end end end is_first_spaces_of_line = false is_first_printable_of_line = false end corresponding_token_depth end def check_string_literal i = 0 start_token = [] end_type = [] while i < @tokens.size t = @tokens[i] case t[1] when :on_tstring_beg start_token << t end_type << [:on_tstring_end, :on_label_end] when :on_regexp_beg start_token << t end_type << :on_regexp_end when :on_symbeg acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw} if (i + 1) < @tokens.size and acceptable_single_tokens.all?{ |t| @tokens[i + 1][1] != t } start_token << t end_type << :on_tstring_end end when :on_backtick start_token << t end_type << :on_tstring_end when :on_qwords_beg, :on_words_beg, :on_qsymbols_beg, :on_symbols_beg start_token << t end_type << :on_tstring_end when :on_heredoc_beg start_token << t end_type << :on_heredoc_end when *end_type.last start_token.pop end_type.pop end i += 1 end start_token.last.nil? ? '' : start_token.last end def process_literal_type start_token = check_string_literal case start_token[1] when :on_tstring_beg case start_token[2] when ?" then ?" when /^%.$/ then ?" when /^%Q.$/ then ?" when ?' then ?' when /^%q.$/ then ?' end when :on_regexp_beg then ?/ when :on_symbeg then ?: when :on_backtick then ?` when :on_qwords_beg then ?] when :on_words_beg then ?] when :on_qsymbols_beg then ?] when :on_symbols_beg then ?] when :on_heredoc_beg start_token[2] =~ /<<[-~]?(['"`])[_a-zA-Z0-9]+\1/ case $1 when ?" then ?" when ?' then ?' when ?` then ?` else ?" end else nil end end end # :startdoc: PKu]wirb-1.2.6/lib/irb/color.rbnu[# frozen_string_literal: true require 'reline' require 'ripper' require 'irb/ruby-lex' module IRB # :nodoc: module Color CLEAR = 0 BOLD = 1 UNDERLINE = 4 REVERSE = 7 RED = 31 GREEN = 32 YELLOW = 33 BLUE = 34 MAGENTA = 35 CYAN = 36 TOKEN_KEYWORDS = { on_kw: ['nil', 'self', 'true', 'false', '__FILE__', '__LINE__'], on_const: ['ENV'], } private_constant :TOKEN_KEYWORDS # A constant of all-bit 1 to match any Ripper's state in #dispatch_seq ALL = -1 private_constant :ALL begin # Following pry's colors where possible, but sometimes having a compromise like making # backtick and regexp as red (string's color, because they're sharing tokens). TOKEN_SEQ_EXPRS = { on_CHAR: [[BLUE, BOLD], ALL], on_backtick: [[RED, BOLD], ALL], on_comment: [[BLUE, BOLD], ALL], on_const: [[BLUE, BOLD, UNDERLINE], ALL], on_embexpr_beg: [[RED], ALL], on_embexpr_end: [[RED], ALL], on_embvar: [[RED], ALL], on_float: [[MAGENTA, BOLD], ALL], on_gvar: [[GREEN, BOLD], ALL], on_heredoc_beg: [[RED], ALL], on_heredoc_end: [[RED], ALL], on_ident: [[BLUE, BOLD], Ripper::EXPR_ENDFN], on_imaginary: [[BLUE, BOLD], ALL], on_int: [[BLUE, BOLD], ALL], on_kw: [[GREEN], ALL], on_label: [[MAGENTA], ALL], on_label_end: [[RED, BOLD], ALL], on_qsymbols_beg: [[RED, BOLD], ALL], on_qwords_beg: [[RED, BOLD], ALL], on_rational: [[BLUE, BOLD], ALL], on_regexp_beg: [[RED, BOLD], ALL], on_regexp_end: [[RED, BOLD], ALL], on_symbeg: [[YELLOW], ALL], on_symbols_beg: [[RED, BOLD], ALL], on_tstring_beg: [[RED, BOLD], ALL], on_tstring_content: [[RED], ALL], on_tstring_end: [[RED, BOLD], ALL], on_words_beg: [[RED, BOLD], ALL], on_parse_error: [[RED, REVERSE], ALL], compile_error: [[RED, REVERSE], ALL], } rescue NameError # Give up highlighting Ripper-incompatible older Ruby TOKEN_SEQ_EXPRS = {} end private_constant :TOKEN_SEQ_EXPRS class << self def colorable? $stdout.tty? && supported? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb')) end def inspect_colorable?(obj, seen: {}.compare_by_identity) case obj when String, Symbol, Regexp, Integer, Float, FalseClass, TrueClass, NilClass true when Hash without_circular_ref(obj, seen: seen) do obj.all? { |k, v| inspect_colorable?(k, seen: seen) && inspect_colorable?(v, seen: seen) } end when Array without_circular_ref(obj, seen: seen) do obj.all? { |o| inspect_colorable?(o, seen: seen) } end when Range inspect_colorable?(obj.begin, seen: seen) && inspect_colorable?(obj.end, seen: seen) when Module !obj.name.nil? else false end end def clear return '' unless colorable? "\e[#{CLEAR}m" end def colorize(text, seq) return text unless colorable? seq = seq.map { |s| "\e[#{const_get(s)}m" }.join('') "#{seq}#{text}#{clear}" end # If `complete` is false (code is incomplete), this does not warn compile_error. # This option is needed to avoid warning a user when the compile_error is happening # because the input is not wrong but just incomplete. def colorize_code(code, complete: true) return code unless colorable? symbol_state = SymbolState.new colored = +'' length = 0 scan(code, allow_last_error: !complete) do |token, str, expr| in_symbol = symbol_state.scan_token(token) str.each_line do |line| line = Reline::Unicode.escape_for_print(line) if seq = dispatch_seq(token, expr, line, in_symbol: in_symbol) colored << seq.map { |s| "\e[#{s}m" }.join('') colored << line.sub(/\Z/, clear) else colored << line end end length += str.bytesize end # give up colorizing incomplete Ripper tokens if length != code.bytesize return Reline::Unicode.escape_for_print(code) end colored end private def without_circular_ref(obj, seen:, &block) return false if seen.key?(obj) seen[obj] = true block.call ensure seen.delete(obj) end def supported? return @supported if defined?(@supported) @supported = Ripper::Lexer::Elem.method_defined?(:state) end def scan(code, allow_last_error:) pos = [1, 0] verbose, $VERBOSE = $VERBOSE, nil RubyLex.compile_with_errors_suppressed(code) do |inner_code, line_no| lexer = Ripper::Lexer.new(inner_code, '(ripper)', line_no) if lexer.respond_to?(:scan) # Ruby 2.7+ lexer.scan.each do |elem| str = elem.tok next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message next if ([elem.pos[0], elem.pos[1] + str.bytesize] <=> pos) <= 0 str.each_line do |line| if line.end_with?("\n") pos[0] += 1 pos[1] = 0 else pos[1] += line.bytesize end end yield(elem.event, str, elem.state) end else lexer.parse.each do |elem| yield(elem.event, elem.tok, elem.state) end end end $VERBOSE = verbose end def dispatch_seq(token, expr, str, in_symbol:) if token == :on_parse_error or token == :compile_error TOKEN_SEQ_EXPRS[token][0] elsif in_symbol [YELLOW] elsif TOKEN_KEYWORDS.fetch(token, []).include?(str) [CYAN, BOLD] elsif (seq, exprs = TOKEN_SEQ_EXPRS[token]; (expr & (exprs || 0)) != 0) seq else nil end end end # A class to manage a state to know whether the current token is for Symbol or not. class SymbolState def initialize # Push `true` to detect Symbol. `false` to increase the nest level for non-Symbol. @stack = [] end # Return true if the token is a part of Symbol. def scan_token(token) prev_state = @stack.last case token when :on_symbeg, :on_symbols_beg, :on_qsymbols_beg @stack << true when :on_ident, :on_op, :on_const, :on_ivar, :on_cvar, :on_gvar, :on_kw if @stack.last # Pop only when it's Symbol @stack.pop return prev_state end when :on_tstring_beg @stack << false when :on_embexpr_beg @stack << false return prev_state when :on_tstring_end # :on_tstring_end may close Symbol @stack.pop return prev_state when :on_embexpr_end @stack.pop end @stack.last end end private_constant :SymbolState end end PKu]yk/AAirb-1.2.6/lib/irb/locale.rbnu[# frozen_string_literal: false # # irb/locale.rb - internationalization module # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: class Locale LOCALE_NAME_RE = %r[ (?[[:alpha:]]{2,3}) (?:_ (?[[:alpha:]]{2,3}) )? (?:\. (?[^@]+) )? (?:@ (?.*) )? ]x LOCALE_DIR = "/lc/" @@legacy_encoding_alias_map = {}.freeze @@loaded = [] def initialize(locale = nil) @override_encoding = nil @lang = @territory = @encoding_name = @modifier = nil @locale = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] || "C" if m = LOCALE_NAME_RE.match(@locale) @lang, @territory, @encoding_name, @modifier = m[:language], m[:territory], m[:codeset], m[:modifier] if @encoding_name begin load 'irb/encoding_aliases.rb'; rescue LoadError; end if @encoding = @@legacy_encoding_alias_map[@encoding_name] warn(("%s is obsolete. use %s" % ["#{@lang}_#{@territory}.#{@encoding_name}", "#{@lang}_#{@territory}.#{@encoding.name}"]), uplevel: 1) end @encoding = Encoding.find(@encoding_name) rescue nil end end @encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT) end attr_reader :lang, :territory, :modifier def encoding @override_encoding || @encoding end def String(mes) mes = super(mes) if encoding mes.encode(encoding, undef: :replace) else mes end end def format(*opts) String(super(*opts)) end def gets(*rs) String(super(*rs)) end def readline(*rs) String(super(*rs)) end def print(*opts) ary = opts.collect{|opt| String(opt)} super(*ary) end def printf(*opts) s = format(*opts) print s end def puts(*opts) ary = opts.collect{|opt| String(opt)} super(*ary) end def require(file, priv = nil) rex = Regexp.new("lc/#{Regexp.quote(file)}\.(so|o|sl|rb)?") return false if $".find{|f| f =~ rex} case file when /\.rb$/ begin load(file, priv) $".push file return true rescue LoadError end when /\.(so|o|sl)$/ return super end begin load(f = file + ".rb") $".push f #" return true rescue LoadError return ruby_require(file) end end alias toplevel_load load def load(file, priv=nil) found = find(file) if found unless @@loaded.include?(found) @@loaded << found # cache return real_load(found, priv) end else raise LoadError, "No such file to load -- #{file}" end end def find(file , paths = $:) dir = File.dirname(file) dir = "" if dir == "." base = File.basename(file) if dir.start_with?('/') return each_localized_path(dir, base).find{|full_path| File.readable? full_path} else return search_file(paths, dir, base) end end private def real_load(path, priv) src = MagicFile.open(path){|f| f.read} if priv eval("self", TOPLEVEL_BINDING).extend(Module.new {eval(src, nil, path)}) else eval(src, TOPLEVEL_BINDING, path) end end # @param paths load paths in which IRB find a localized file. # @param dir directory # @param file basename to be localized # # typically, for the parameters and a in paths, it searches # /

    // def search_file(lib_paths, dir, file) each_localized_path(dir, file) do |lc_path| lib_paths.each do |libpath| full_path = File.join(libpath, lc_path) return full_path if File.readable?(full_path) end redo if defined?(Gem) and Gem.try_activate(lc_path) end nil end def each_localized_path(dir, file) return enum_for(:each_localized_path) unless block_given? each_sublocale do |lc| yield lc.nil? ? File.join(dir, LOCALE_DIR, file) : File.join(dir, LOCALE_DIR, lc, file) end end def each_sublocale if @lang if @territory if @encoding_name yield "#{@lang}_#{@territory}.#{@encoding_name}@#{@modifier}" if @modifier yield "#{@lang}_#{@territory}.#{@encoding_name}" end yield "#{@lang}_#{@territory}@#{@modifier}" if @modifier yield "#{@lang}_#{@territory}" end if @encoding_name yield "#{@lang}.#{@encoding_name}@#{@modifier}" if @modifier yield "#{@lang}.#{@encoding_name}" end yield "#{@lang}@#{@modifier}" if @modifier yield "#{@lang}" end yield nil end end end PKu]ppirb-1.2.6/lib/irb/easter-egg.rbnu[require "reline" module IRB class << self class Vec def initialize(x, y, z) @x, @y, @z = x, y, z end attr_reader :x, :y, :z def sub(other) Vec.new(@x - other.x, @y - other.y, @z - other.z) end def dot(other) @x*other.x + @y*other.y + @z*other.z end def cross(other) ox, oy, oz = other.x, other.y, other.z Vec.new(@y*oz-@z*oy, @z*ox-@x*oz, @x*oy-@y*ox) end def normalize r = Math.sqrt(self.dot(self)) Vec.new(@x / r, @y / r, @z / r) end end class Canvas def initialize((h, w)) @data = (0..h-2).map { [0] * w } @scale = [w / 2.0, h-2].min @center = Complex(w / 2, h-2) end def line((x1, y1), (x2, y2)) p1 = Complex(x1, y1) / 2 * @scale + @center p2 = Complex(x2, y2) / 2 * @scale + @center line0(p1, p2) end private def line0(p1, p2) mid = (p1 + p2) / 2 if (p1 - p2).abs < 1 x, y = mid.rect @data[y / 2][x] |= (y % 2 > 1 ? 2 : 1) else line0(p1, mid) line0(p2, mid) end end def draw @data.each {|row| row.fill(0) } yield @data.map {|row| row.map {|n| " ',;"[n] }.join }.join("\n") end end class RubyModel def initialize @faces = init_ruby_model end def init_ruby_model cap_vertices = (0..5).map {|i| Vec.new(*Complex.polar(1, i * Math::PI / 3).rect, 1) } middle_vertices = (0..5).map {|i| Vec.new(*Complex.polar(2, (i + 0.5) * Math::PI / 3).rect, 0) } bottom_vertex = Vec.new(0, 0, -2) faces = [cap_vertices] 6.times do |j| i = j-1 faces << [cap_vertices[i], middle_vertices[i], cap_vertices[j]] faces << [cap_vertices[j], middle_vertices[i], middle_vertices[j]] faces << [middle_vertices[i], bottom_vertex, middle_vertices[j]] end faces end def render_frame(i) angle = i / 10.0 dir = Vec.new(*Complex.polar(1, angle).rect, Math.sin(angle)).normalize dir2 = Vec.new(*Complex.polar(1, angle - Math::PI/2).rect, 0) up = dir.cross(dir2) nm = dir.cross(up) @faces.each do |vertices| v0, v1, v2, = vertices if v1.sub(v0).cross(v2.sub(v0)).dot(dir) > 0 points = vertices.map {|p| [nm.dot(p), up.dot(p)] } (points + [points[0]]).each_cons(2) do |p1, p2| yield p1, p2 end end end end end private def easter_egg(type = nil) type ||= [:logo, :dancing].sample case type when :logo File.open(File.join(__dir__, 'ruby_logo.aa')) do |f| require "rdoc" RDoc::RI::Driver.new.page do |io| IO.copy_stream(f, io) end end when :dancing begin canvas = Canvas.new(Reline.get_screen_size) Reline::IOGate.set_winch_handler do canvas = Canvas.new(Reline.get_screen_size) end ruby_model = RubyModel.new print "\e[?1049h" 0.step do |i| # TODO (0..).each needs Ruby 2.6 or later buff = canvas.draw do ruby_model.render_frame(i) do |p1, p2| canvas.line(p1, p2) end end buff[0, 20] = "\e[0mPress Ctrl+C to stop\e[31m\e[1m" print "\e[H" + buff sleep 0.05 end ensure print "\e[0m\e[?1049l" end end end end end IRB.send(:easter_egg, ARGV[0]&.to_sym) if $0 == __FILE__ PKu]fɁc"c"irb-1.2.6/lib/irb/init.rbnu[# frozen_string_literal: false # # irb/init.rb - irb initialize module # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: # initialize config def IRB.setup(ap_path, argv: ::ARGV) IRB.init_config(ap_path) IRB.init_error IRB.parse_opts(argv: argv) IRB.run_config IRB.load_modules unless @CONF[:PROMPT][@CONF[:PROMPT_MODE]] fail UndefinedPromptMode, @CONF[:PROMPT_MODE] end end # @CONF default setting def IRB.init_config(ap_path) # class instance variables @TRACER_INITIALIZED = false # default configurations unless ap_path and @CONF[:AP_NAME] ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb") end @CONF[:AP_NAME] = File::basename(ap_path, ".rb") @CONF[:IRB_NAME] = "irb" @CONF[:IRB_LIB_PATH] = File.dirname(__FILE__) @CONF[:RC] = true @CONF[:LOAD_MODULES] = [] @CONF[:IRB_RC] = nil @CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod) @CONF[:USE_COLORIZE] = true @CONF[:INSPECT_MODE] = true @CONF[:USE_TRACER] = false @CONF[:USE_LOADER] = false @CONF[:IGNORE_SIGINT] = true @CONF[:IGNORE_EOF] = false @CONF[:ECHO] = nil @CONF[:ECHO_ON_ASSIGNMENT] = nil @CONF[:OMIT_ON_ASSIGNMENT] = nil @CONF[:VERBOSE] = nil @CONF[:EVAL_HISTORY] = nil @CONF[:SAVE_HISTORY] = 1000 @CONF[:BACK_TRACE_LIMIT] = 16 @CONF[:PROMPT] = { :NULL => { :PROMPT_I => nil, :PROMPT_N => nil, :PROMPT_S => nil, :PROMPT_C => nil, :RETURN => "%s\n" }, :DEFAULT => { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_N => "%N(%m):%03n:%i> ", :PROMPT_S => "%N(%m):%03n:%i%l ", :PROMPT_C => "%N(%m):%03n:%i* ", :RETURN => "=> %s\n" }, :CLASSIC => { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_N => "%N(%m):%03n:%i> ", :PROMPT_S => "%N(%m):%03n:%i%l ", :PROMPT_C => "%N(%m):%03n:%i* ", :RETURN => "%s\n" }, :SIMPLE => { :PROMPT_I => ">> ", :PROMPT_N => ">> ", :PROMPT_S => "%l> ", :PROMPT_C => "?> ", :RETURN => "=> %s\n" }, :INF_RUBY => { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_N => nil, :PROMPT_S => nil, :PROMPT_C => nil, :RETURN => "%s\n", :AUTO_INDENT => true }, :XMP => { :PROMPT_I => nil, :PROMPT_N => nil, :PROMPT_S => nil, :PROMPT_C => nil, :RETURN => " ==>%s\n" } } @CONF[:PROMPT_MODE] = (STDIN.tty? ? :DEFAULT : :NULL) @CONF[:AUTO_INDENT] = true @CONF[:CONTEXT_MODE] = 3 # use binding in function on TOPLEVEL_BINDING @CONF[:SINGLE_IRB] = false @CONF[:LC_MESSAGES] = Locale.new @CONF[:AT_EXIT] = [] end def IRB.init_error @CONF[:LC_MESSAGES].load("irb/error.rb") end # option analyzing def IRB.parse_opts(argv: ::ARGV) load_path = [] while opt = argv.shift case opt when "-f" @CONF[:RC] = false when "-d" $DEBUG = true $VERBOSE = true when "-w" $VERBOSE = true when /^-W(.+)?/ opt = $1 || argv.shift case opt when "0" $VERBOSE = nil when "1" $VERBOSE = false else $VERBOSE = true end when /^-r(.+)?/ opt = $1 || argv.shift @CONF[:LOAD_MODULES].push opt if opt when /^-I(.+)?/ opt = $1 || argv.shift load_path.concat(opt.split(File::PATH_SEPARATOR)) if opt when '-U' set_encoding("UTF-8", "UTF-8") when /^-E(.+)?/, /^--encoding(?:=(.+))?/ opt = $1 || argv.shift set_encoding(*opt.split(':', 2)) when "--inspect" if /^-/ !~ argv.first @CONF[:INSPECT_MODE] = argv.shift else @CONF[:INSPECT_MODE] = true end when "--noinspect" @CONF[:INSPECT_MODE] = false when "--singleline", "--readline", "--legacy" @CONF[:USE_SINGLELINE] = true when "--nosingleline", "--noreadline" @CONF[:USE_SINGLELINE] = false when "--multiline", "--reidline" @CONF[:USE_MULTILINE] = true when "--nomultiline", "--noreidline" @CONF[:USE_MULTILINE] = false when "--echo" @CONF[:ECHO] = true when "--noecho" @CONF[:ECHO] = false when "--echo-on-assignment" @CONF[:ECHO_ON_ASSIGNMENT] = true when "--noecho-on-assignment" @CONF[:ECHO_ON_ASSIGNMENT] = false when "--omit-on-assignment" @CONF[:OMIT_ON_ASSIGNMENT] = true when "--noomit-on-assignment" @CONF[:OMIT_ON_ASSIGNMENT] = false when "--verbose" @CONF[:VERBOSE] = true when "--noverbose" @CONF[:VERBOSE] = false when "--colorize" @CONF[:USE_COLORIZE] = true when "--nocolorize" @CONF[:USE_COLORIZE] = false when /^--prompt-mode(?:=(.+))?/, /^--prompt(?:=(.+))?/ opt = $1 || argv.shift prompt_mode = opt.upcase.tr("-", "_").intern @CONF[:PROMPT_MODE] = prompt_mode when "--noprompt" @CONF[:PROMPT_MODE] = :NULL when "--inf-ruby-mode" @CONF[:PROMPT_MODE] = :INF_RUBY when "--sample-book-mode", "--simple-prompt" @CONF[:PROMPT_MODE] = :SIMPLE when "--tracer" @CONF[:USE_TRACER] = true when /^--back-trace-limit(?:=(.+))?/ @CONF[:BACK_TRACE_LIMIT] = ($1 || argv.shift).to_i when /^--context-mode(?:=(.+))?/ @CONF[:CONTEXT_MODE] = ($1 || argv.shift).to_i when "--single-irb" @CONF[:SINGLE_IRB] = true when "-v", "--version" print IRB.version, "\n" exit 0 when "-h", "--help" require_relative "help" IRB.print_usage exit 0 when "--" if opt = argv.shift @CONF[:SCRIPT] = opt $0 = opt end break when /^-/ fail UnrecognizedSwitch, opt else @CONF[:SCRIPT] = opt $0 = opt break end end load_path.collect! do |path| /\A\.\// =~ path ? path : File.expand_path(path) end $LOAD_PATH.unshift(*load_path) end # running config def IRB.run_config if @CONF[:RC] begin load rc_file rescue LoadError, Errno::ENOENT rescue # StandardError, ScriptError print "load error: #{rc_file}\n" print $!.class, ": ", $!, "\n" for err in $@[0, $@.size - 2] print "\t", err, "\n" end end end end IRBRC_EXT = "rc" def IRB.rc_file(ext = IRBRC_EXT) if !@CONF[:RC_NAME_GENERATOR] rc_file_generators do |rcgen| @CONF[:RC_NAME_GENERATOR] ||= rcgen if File.exist?(rcgen.call(IRBRC_EXT)) @CONF[:RC_NAME_GENERATOR] = rcgen break end end end case rc_file = @CONF[:RC_NAME_GENERATOR].call(ext) when String return rc_file else fail IllegalRCNameGenerator end end # enumerate possible rc-file base name generators def IRB.rc_file_generators if irbrc = ENV["IRBRC"] yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc} end if xdg_config_home = ENV["XDG_CONFIG_HOME"] irb_home = File.join(xdg_config_home, "irb") unless File.exist? irb_home require 'fileutils' FileUtils.mkdir_p irb_home end yield proc{|rc| irb_home + "/irb#{rc}"} end if home = ENV["HOME"] yield proc{|rc| home+"/.irb#{rc}"} end current_dir = Dir.pwd yield proc{|rc| current_dir+"/.config/irb/irb#{rc}"} yield proc{|rc| current_dir+"/.irb#{rc}"} yield proc{|rc| current_dir+"/irb#{rc.sub(/\A_?/, '.')}"} yield proc{|rc| current_dir+"/_irb#{rc}"} yield proc{|rc| current_dir+"/$irb#{rc}"} end # loading modules def IRB.load_modules for m in @CONF[:LOAD_MODULES] begin require m rescue LoadError => err warn "#{err.class}: #{err}", uplevel: 0 end end end DefaultEncodings = Struct.new(:external, :internal) class << IRB private def set_encoding(extern, intern = nil, override: true) verbose, $VERBOSE = $VERBOSE, nil Encoding.default_external = extern unless extern.nil? || extern.empty? Encoding.default_internal = intern unless intern.nil? || intern.empty? [$stdin, $stdout, $stderr].each do |io| io.set_encoding(extern, intern) end if override @CONF[:LC_MESSAGES].instance_variable_set(:@override_encoding, extern) else @CONF[:LC_MESSAGES].instance_variable_set(:@encoding, extern) end ensure $VERBOSE = verbose end end end PKu]I I irb-1.2.6/lib/irb/ruby_logo.aanu[ -+smJYYN?mm- HB"BBYT TQg NggT 9Q+g Nm,T 8g NJW YS+ N2NJ"Sg N? BQg #( gT Nggggk J 5j NJ NJ NNge #Q #JJ NgT N( @j bj mT J Bj @/d NJ ( #q #(( NgT #J 5d #(t mT $d #q @(@J NJB; @( 5d ? HHH H HQmgggggggmN qD 5d #uN 2QdH E O 5 5JSd Nd NJH @d j Fd @J4d s NQH #d ( #( #o6d Nd NgH #d #d 4 B&Od v NgT #d F #( 9JGd NH NgUd F #d #GJQ d NP $ #J #U+#Q N Q # j j /W BQ+ BQ d NJ NJ - NjJH HBIjTQggPJQgW N W k #J #J b HYWgggN j s Nag d NN b #d #J 5- D s Ngg N d Nd F Fd BKH2 #+ s NNgg J Q J ] F H @ J N y K(d P I F4 E N? #d y #Q NJ E j F W Nd q m Bg NxW N(H- F d b @ m Hd gW vKJ NJ d K d s Bg aT FDd b # d N m BQ mV N> e5 Nd #d NggggggQWH HHHH NJ - m7 NW H N HSVO1z=?11- NgTH bB kH WBHWWHBHWmQgg&gggggNNN NNggggggNN PKu]Oirb-1.2.6/lib/irb/cmd/help.rbnu[# frozen_string_literal: false # # help.rb - helper using ri # $Release Version: 0.9.6$ # $Revision$ # # -- # # # require_relative "nop" # :stopdoc: module IRB module ExtendCommand class Help < Nop def execute(*names) require 'rdoc/ri/driver' IRB::ExtendCommand::Help.const_set(:Ri, RDoc::RI::Driver.new) rescue LoadError, SystemExit IRB::ExtendCommand::Help.remove_method(:execute) # raise NoMethodError in ensure else def execute(*names) if names.empty? Ri.interactive return end names.each do |name| begin Ri.display_name(name.to_s) rescue RDoc::RI::Error puts $!.message end end nil end nil ensure execute(*names) end end end end # :startdoc: PKu]#oirb-1.2.6/lib/irb/cmd/load.rbnu[# frozen_string_literal: false # # load.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "nop" require_relative "../ext/loader" # :stopdoc: module IRB module ExtendCommand class Load < Nop include IrbLoader def execute(file_name, priv = nil) return irb_load(file_name, priv) end end class Require < Nop include IrbLoader def execute(file_name) rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?") return false if $".find{|f| f =~ rex} case file_name when /\.rb$/ begin if irb_load(file_name) $".push file_name return true end rescue LoadError end when /\.(so|o|sl)$/ return ruby_require(file_name) end begin irb_load(f = file_name + ".rb") $".push f return true rescue LoadError return ruby_require(file_name) end end end class Source < Nop include IrbLoader def execute(file_name) source_file(file_name) end end end end # :startdoc: PKu]Q~~irb-1.2.6/lib/irb/cmd/fork.rbnu[# frozen_string_literal: false # # fork.rb - # $Release Version: 0.9.6 $ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # # :stopdoc: module IRB module ExtendCommand class Fork < Nop def execute pid = send ExtendCommand.irb_original_method_name("fork") unless pid class << self alias_method :exit, ExtendCommand.irb_original_method_name('exit') end if block_given? begin yield ensure exit end end end pid end end end end # :startdoc: PKu]j$irb-1.2.6/lib/irb/cmd/chws.rbnu[# frozen_string_literal: false # # change-ws.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "nop" require_relative "../ext/change-ws" # :stopdoc: module IRB module ExtendCommand class CurrentWorkingWorkspace < Nop def execute(*obj) irb_context.main end end class ChangeWorkspace < Nop def execute(*obj) irb_context.change_workspace(*obj) irb_context.main end end end end # :startdoc: PKu])ڏ!!irb-1.2.6/lib/irb/cmd/nop.rbnu[# frozen_string_literal: false # # nop.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # # :stopdoc: module IRB module ExtendCommand class Nop def self.execute(conf, *opts) command = new(conf) command.execute(*opts) end def initialize(conf) @irb_context = conf end attr_reader :irb_context def irb @irb_context.irb end def execute(*opts) #nop end end end end # :startdoc: PKu]zirb-1.2.6/lib/irb/cmd/pushws.rbnu[# frozen_string_literal: false # # change-ws.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "nop" require_relative "../ext/workspaces" # :stopdoc: module IRB module ExtendCommand class Workspaces < Nop def execute(*obj) irb_context.workspaces.collect{|ws| ws.main} end end class PushWorkspace < Workspaces def execute(*obj) irb_context.push_workspace(*obj) super end end class PopWorkspace < Workspaces def execute(*obj) irb_context.pop_workspace(*obj) super end end end end # :startdoc: PKu]I]]irb-1.2.6/lib/irb/cmd/subirb.rbnu[# frozen_string_literal: false # multi.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "nop" require_relative "../ext/multi-irb" # :stopdoc: module IRB module ExtendCommand class IrbCommand < Nop def execute(*obj) IRB.irb(nil, *obj) end end class Jobs < Nop def execute IRB.JobManager end end class Foreground < Nop def execute(key) IRB.JobManager.switch(key) end end class Kill < Nop def execute(*keys) IRB.JobManager.kill(*keys) end end end end # :startdoc: PKu]{A5//irb-1.2.6/lib/irb/cmd/info.rbnu[# frozen_string_literal: false require_relative "nop" # :stopdoc: module IRB module ExtendCommand class Info < Nop def execute Class.new { def inspect str = "Ruby version: #{RUBY_VERSION}\n" str += "IRB version: #{IRB.version}\n" str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n" str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file) str end alias_method :to_s, :inspect }.new end end end end # :startdoc: PKu]tirb-1.2.6/lib/irb/xmp.rbnu[# frozen_string_literal: false # # xmp.rb - irb version of gotoken xmp # $Release Version: 0.9$ # $Revision$ # by Keiju ISHITSUKA(Nippon Rational Inc.) # # -- # # # require_relative "../irb" require_relative "frame" # An example printer for irb. # # It's much like the standard library PrettyPrint, that shows the value of each # expression as it runs. # # In order to use this library, you must first require it: # # require 'irb/xmp' # # Now, you can take advantage of the Object#xmp convenience method. # # xmp < foo = "bar" # #==>"bar" # #=> baz = 42 # #==>42 # # You can also create an XMP object, with an optional binding to print # expressions in the given binding: # # ctx = binding # x = XMP.new ctx # x.puts # #=> today = "a good day" # #==>"a good day" # ctx.eval 'today # is what?' # #=> "a good day" class XMP # Creates a new XMP object. # # The top-level binding or, optional +bind+ parameter will be used when # creating the workspace. See WorkSpace.new for more information. # # This uses the +:XMP+ prompt mode, see IRB@Customizing+the+IRB+Prompt for # full detail. def initialize(bind = nil) IRB.init_config(nil) IRB.conf[:PROMPT_MODE] = :XMP bind = IRB::Frame.top(1) unless bind ws = IRB::WorkSpace.new(bind) @io = StringInputMethod.new @irb = IRB::Irb.new(ws, @io) @irb.context.ignore_sigint = false IRB.conf[:MAIN_CONTEXT] = @irb.context end # Evaluates the given +exps+, for example: # # require 'irb/xmp' # x = XMP.new # # x.puts '{:a => 1, :b => 2, :c => 3}' # #=> {:a => 1, :b => 2, :c => 3} # # ==>{:a=>1, :b=>2, :c=>3} # x.puts 'foo = "bar"' # # => foo = "bar" # # ==>"bar" def puts(exps) @io.puts exps if @irb.context.ignore_sigint begin trap_proc_b = trap("SIGINT"){@irb.signal_handle} catch(:IRB_EXIT) do @irb.eval_input end ensure trap("SIGINT", trap_proc_b) end else catch(:IRB_EXIT) do @irb.eval_input end end end # A custom InputMethod class used by XMP for evaluating string io. class StringInputMethod < IRB::InputMethod # Creates a new StringInputMethod object def initialize super @exps = [] end # Whether there are any expressions left in this printer. def eof? @exps.empty? end # Reads the next expression from this printer. # # See IO#gets for more information. def gets while l = @exps.shift next if /^\s+$/ =~ l l.concat "\n" print @prompt, l break end l end # Concatenates all expressions in this printer, separated by newlines. # # An Encoding::CompatibilityError is raised of the given +exps+'s encoding # doesn't match the previous expression evaluated. def puts(exps) if @encoding and exps.encoding != @encoding enc = Encoding.compatible?(@exps.join("\n"), exps) if enc.nil? raise Encoding::CompatibilityError, "Encoding in which the passed expression is encoded is not compatible to the preceding's one" else @encoding = enc end else @encoding = exps.encoding end @exps.concat exps.split(/\n/) end # Returns the encoding of last expression printed by #puts. attr_reader :encoding end end # A convenience method that's only available when the you require the IRB::XMP standard library. # # Creates a new XMP object, using the given expressions as the +exps+ # parameter, and optional binding as +bind+ or uses the top-level binding. Then # evaluates the given expressions using the +:XMP+ prompt mode. # # For example: # # require 'irb/xmp' # ctx = binding # xmp 'foo = "bar"', ctx # #=> foo = "bar" # #==>"bar" # ctx.eval 'foo' # #=> "bar" # # See XMP.new for more information. def xmp(exps, bind = nil) bind = IRB::Frame.top(1) unless bind xmp = XMP.new(bind) xmp.puts exps xmp end PKu]c!irb-1.2.6/lib/irb/src_encoding.rbnu[# frozen_string_literal: false # DO NOT WRITE ANY MAGIC COMMENT HERE. module IRB def self.default_src_encoding return __ENCODING__ end end PKu]h((irb-1.2.6/lib/irb/version.rbnu[# frozen_string_literal: false # # irb/version.rb - irb version definition file # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # # # module IRB # :nodoc: VERSION = "1.2.6" @RELEASE_VERSION = VERSION @LAST_UPDATE_DATE = "2020-09-14" end PKu]Ɨ]%%irb-1.2.6/lib/irb/completion.rbnu[# frozen_string_literal: false # # irb/completion.rb - # $Release Version: 0.9$ # $Revision$ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # From Original Idea of shugo@ruby-lang.org # autoload :RDoc, "rdoc" module IRB module InputCompletor # :nodoc: # Set of reserved words used by Ruby, you should not use these for # constants or variables ReservedWords = %w[ __ENCODING__ __LINE__ __FILE__ BEGIN END alias and begin break case class def defined? do else elsif end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield ] BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{(" CompletionProc = proc { |input| retrieve_completion_data(input).compact.map{ |i| i.encode(Encoding.default_external) } } def self.retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false) case input when /^((["'`]).*\2)\.([^.]*)$/ # String receiver = $1 message = Regexp.quote($3) candidates = String.instance_methods.collect{|m| m.to_s} if doc_namespace "String.#{message}" else select_message(receiver, message, candidates) end when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp receiver = $1 message = Regexp.quote($2) candidates = Regexp.instance_methods.collect{|m| m.to_s} if doc_namespace "Regexp.#{message}" else select_message(receiver, message, candidates) end when /^([^\]]*\])\.([^.]*)$/ # Array receiver = $1 message = Regexp.quote($2) candidates = Array.instance_methods.collect{|m| m.to_s} if doc_namespace "Array.#{message}" else select_message(receiver, message, candidates) end when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash receiver = $1 message = Regexp.quote($2) proc_candidates = Proc.instance_methods.collect{|m| m.to_s} hash_candidates = Hash.instance_methods.collect{|m| m.to_s} if doc_namespace ["Proc.#{message}", "Hash.#{message}"] else select_message(receiver, message, proc_candidates | hash_candidates) end when /^(:[^:.]*)$/ # Symbol return nil if doc_namespace sym = $1 candidates = Symbol.all_symbols.collect do |s| ":" + s.id2name.encode(Encoding.default_external) rescue Encoding::UndefinedConversionError # ignore end candidates.grep(/^#{Regexp.quote(sym)}/) when /^::([A-Z][^:\.\(]*)$/ # Absolute Constant or class methods receiver = $1 candidates = Object.constants.collect{|m| m.to_s} if doc_namespace candidates.find { |i| i == receiver } else candidates.grep(/^#{receiver}/).collect{|e| "::" + e} end when /^([A-Z].*)::([^:.]*)$/ # Constant or class methods receiver = $1 message = Regexp.quote($2) begin candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind) candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind) rescue Exception candidates = [] end if doc_namespace "#{receiver}::#{message}" else select_message(receiver, message, candidates, "::") end when /^(:[^:.]+)(\.|::)([^.]*)$/ # Symbol receiver = $1 sep = $2 message = Regexp.quote($3) candidates = Symbol.instance_methods.collect{|m| m.to_s} if doc_namespace "Symbol.#{message}" else select_message(receiver, message, candidates, sep) end when /^(?-?(?:0[dbo])?[0-9_]+(?:\.[0-9_]+)?(?:(?:[eE][+-]?[0-9]+)?i?|r)?)(?\.|::)(?[^.]*)$/ # Numeric receiver = $~[:num] sep = $~[:sep] message = Regexp.quote($~[:mes]) begin instance = eval(receiver, bind) if doc_namespace "#{instance.class.name}.#{message}" else candidates = instance.methods.collect{|m| m.to_s} select_message(receiver, message, candidates, sep) end rescue Exception if doc_namespace nil else candidates = [] end end when /^(-?0x[0-9a-fA-F_]+)(\.|::)([^.]*)$/ # Numeric(0xFFFF) receiver = $1 sep = $2 message = Regexp.quote($3) begin instance = eval(receiver, bind) if doc_namespace "#{instance.class.name}.#{message}" else candidates = instance.methods.collect{|m| m.to_s} select_message(receiver, message, candidates, sep) end rescue Exception if doc_namespace nil else candidates = [] end end when /^(\$[^.]*)$/ # global var gvar = $1 all_gvars = global_variables.collect{|m| m.to_s} if doc_namespace all_gvars.find{ |i| i == gvar } else all_gvars.grep(Regexp.new(Regexp.quote(gvar))) end when /^([^."].*)(\.|::)([^.]*)$/ # variable.func or func.func receiver = $1 sep = $2 message = Regexp.quote($3) gv = eval("global_variables", bind).collect{|m| m.to_s}.push("true", "false", "nil") lv = eval("local_variables", bind).collect{|m| m.to_s} iv = eval("instance_variables", bind).collect{|m| m.to_s} cv = eval("self.class.constants", bind).collect{|m| m.to_s} if (gv | lv | iv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver # foo.func and foo is var. OR # foo::func and foo is var. OR # foo::Const and foo is var. OR # Foo::Bar.func begin candidates = [] rec = eval(receiver, bind) if sep == "::" and rec.kind_of?(Module) candidates = rec.constants.collect{|m| m.to_s} end candidates |= rec.methods.collect{|m| m.to_s} rescue Exception candidates = [] end else # func1.func2 candidates = [] to_ignore = ignored_modules ObjectSpace.each_object(Module){|m| next if (to_ignore.include?(m) rescue true) candidates.concat m.instance_methods(false).collect{|x| x.to_s} } candidates.sort! candidates.uniq! end if doc_namespace "#{rec.class.name}#{sep}#{candidates.find{ |i| i == message }}" else select_message(receiver, message, candidates, sep) end when /^\.([^.]*)$/ # unknown(maybe String) receiver = "" message = Regexp.quote($1) candidates = String.instance_methods(true).collect{|m| m.to_s} if doc_namespace "String.#{candidates.find{ |i| i == message }}" else select_message(receiver, message, candidates) end else candidates = eval("methods | private_methods | local_variables | instance_variables | self.class.constants", bind).collect{|m| m.to_s} candidates |= ReservedWords if doc_namespace candidates.find{ |i| i == input } else candidates.grep(/^#{Regexp.quote(input)}/) end end end PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) { RDocRIDriver ||= RDoc::RI::Driver.new if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER'] IRB.send(:easter_egg) return end namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true) return unless namespace if namespace.is_a?(Array) out = RDoc::Markup::Document.new namespace.each do |m| begin RDocRIDriver.add_method(out, m) rescue RDoc::RI::Driver::NotFoundError end end RDocRIDriver.display(out) else begin RDocRIDriver.display_names([namespace]) rescue RDoc::RI::Driver::NotFoundError end end } # Set of available operators in Ruby Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~] def self.select_message(receiver, message, candidates, sep = ".") candidates.grep(/^#{message}/).collect do |e| case e when /^[a-zA-Z_]/ receiver + sep + e when /^[0-9]/ when *Operators #receiver + " " + e end end end def self.ignored_modules # We could cache the result, but this is very fast already. # By using this approach, we avoid Module#name calls, which are # relatively slow when there are a lot of anonymous modules defined. s = {} scanner = lambda do |m| next if s.include?(m) # IRB::ExtendCommandBundle::EXCB recurses. s[m] = true m.constants(false).each do |c| value = m.const_get(c) scanner.call(value) if value.is_a?(Module) end end %i(IRB RubyLex).each do |sym| next unless Object.const_defined?(sym) scanner.call(Object.const_get(sym)) end s.delete(IRB::Context) if defined?(IRB::Context) s end end end PKu]DKCirb-1.2.6/lib/irb/workspace.rbnu[# frozen_string_literal: false # # irb/workspace-binding.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "delegate" module IRB # :nodoc: class WorkSpace # Creates a new workspace. # # set self to main if specified, otherwise # inherit main from TOPLEVEL_BINDING. def initialize(*main) if main[0].kind_of?(Binding) @binding = main.shift elsif IRB.conf[:SINGLE_IRB] @binding = TOPLEVEL_BINDING else case IRB.conf[:CONTEXT_MODE] when 0 # binding in proc on TOPLEVEL_BINDING @binding = eval("proc{binding}.call", TOPLEVEL_BINDING, __FILE__, __LINE__) when 1 # binding in loaded file require "tempfile" f = Tempfile.open("irb-binding") f.print <IRB.conf[:__MAIN__] attr_reader :main # Evaluate the given +statements+ within the context of this workspace. def evaluate(context, statements, file = __FILE__, line = __LINE__) eval(statements, @binding, file, line) end def local_variable_set(name, value) @binding.local_variable_set(name, value) end def local_variable_get(name) @binding.local_variable_get(name) end # error message manipulator def filter_backtrace(bt) return nil if bt =~ /\/irb\/.*\.rb/ return nil if bt =~ /\/irb\.rb/ case IRB.conf[:CONTEXT_MODE] when 1 return nil if bt =~ %r!/tmp/irb-binding! when 3 bt = bt.sub(/:\s*in `irb_binding'/, '') end bt end def code_around_binding if @binding.respond_to?(:source_location) file, pos = @binding.source_location else file, pos = @binding.eval('[__FILE__, __LINE__]') end if defined?(::SCRIPT_LINES__[file]) && lines = ::SCRIPT_LINES__[file] code = ::SCRIPT_LINES__[file].join('') else begin code = File.read(file) rescue SystemCallError return end end # NOT using #use_colorize? of IRB.conf[:MAIN_CONTEXT] because this method may be called before IRB::Irb#run use_colorize = IRB.conf.fetch(:USE_COLORIZE, true) if use_colorize lines = Color.colorize_code(code).lines else lines = code.lines end pos -= 1 start_pos = [pos - 5, 0].max end_pos = [pos + 5, lines.size - 1].min if use_colorize fmt = " %2s #{Color.colorize("%#{end_pos.to_s.length}d", [:BLUE, :BOLD])}: %s" else fmt = " %2s %#{end_pos.to_s.length}d: %s" end body = (start_pos..end_pos).map do |current_pos| sprintf(fmt, pos == current_pos ? '=>' : '', current_pos + 1, lines[current_pos]) end.join("") "\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n" end def IRB.delete_caller end end end PKu]ǀirb-1.2.6/lib/irb/frame.rbnu[# frozen_string_literal: false # # frame.rb - # $Release Version: 0.9$ # $Revision$ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # module IRB class Frame class FrameOverflow < StandardError def initialize super("frame overflow") end end class FrameUnderflow < StandardError def initialize super("frame underflow") end end # Default number of stack frames INIT_STACK_TIMES = 3 # Default number of frames offset CALL_STACK_OFFSET = 3 # Creates a new stack frame def initialize @frames = [TOPLEVEL_BINDING] * INIT_STACK_TIMES end # Used by Kernel#set_trace_func to register each event in the call stack def trace_func(event, file, line, id, binding) case event when 'call', 'class' @frames.push binding when 'return', 'end' @frames.pop end end # Returns the +n+ number of frames on the call stack from the last frame # initialized. # # Raises FrameUnderflow if there are no frames in the given stack range. def top(n = 0) bind = @frames[-(n + CALL_STACK_OFFSET)] fail FrameUnderflow unless bind bind end # Returns the +n+ number of frames on the call stack from the first frame # initialized. # # Raises FrameOverflow if there are no frames in the given stack range. def bottom(n = 0) bind = @frames[n] fail FrameOverflow unless bind bind end # Convenience method for Frame#bottom def Frame.bottom(n = 0) @backtrace.bottom(n) end # Convenience method for Frame#top def Frame.top(n = 0) @backtrace.top(n) end # Returns the binding context of the caller from the last frame initialized def Frame.sender eval "self", @backtrace.top end @backtrace = Frame.new set_trace_func proc{|event, file, line, id, binding, klass| @backtrace.trace_func(event, file, line, id, binding) } end end PKu]&/((#irb-1.2.6/lib/irb/extend-command.rbnu[# frozen_string_literal: false # # irb/extend-command.rb - irb extend command # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: # Installs the default irb extensions command bundle. module ExtendCommandBundle EXCB = ExtendCommandBundle # :nodoc: # See #install_alias_method. NO_OVERRIDE = 0 # See #install_alias_method. OVERRIDE_PRIVATE_ONLY = 0x01 # See #install_alias_method. OVERRIDE_ALL = 0x02 # Quits the current irb context # # +ret+ is the optional signal or message to send to Context#exit # # Same as IRB.CurrentContext.exit. def irb_exit(ret = 0) irb_context.exit(ret) end # Displays current configuration. # # Modifying the configuration is achieved by sending a message to IRB.conf. def irb_context IRB.CurrentContext end @ALIASES = [ [:context, :irb_context, NO_OVERRIDE], [:conf, :irb_context, NO_OVERRIDE], [:irb_quit, :irb_exit, OVERRIDE_PRIVATE_ONLY], [:exit, :irb_exit, OVERRIDE_PRIVATE_ONLY], [:quit, :irb_exit, OVERRIDE_PRIVATE_ONLY], ] @EXTEND_COMMANDS = [ [ :irb_current_working_workspace, :CurrentWorkingWorkspace, "irb/cmd/chws", [:irb_print_working_workspace, OVERRIDE_ALL], [:irb_cwws, OVERRIDE_ALL], [:irb_pwws, OVERRIDE_ALL], [:cwws, NO_OVERRIDE], [:pwws, NO_OVERRIDE], [:irb_current_working_binding, OVERRIDE_ALL], [:irb_print_working_binding, OVERRIDE_ALL], [:irb_cwb, OVERRIDE_ALL], [:irb_pwb, OVERRIDE_ALL], ], [ :irb_change_workspace, :ChangeWorkspace, "irb/cmd/chws", [:irb_chws, OVERRIDE_ALL], [:irb_cws, OVERRIDE_ALL], [:chws, NO_OVERRIDE], [:cws, NO_OVERRIDE], [:irb_change_binding, OVERRIDE_ALL], [:irb_cb, OVERRIDE_ALL], [:cb, NO_OVERRIDE], ], [ :irb_workspaces, :Workspaces, "irb/cmd/pushws", [:workspaces, NO_OVERRIDE], [:irb_bindings, OVERRIDE_ALL], [:bindings, NO_OVERRIDE], ], [ :irb_push_workspace, :PushWorkspace, "irb/cmd/pushws", [:irb_pushws, OVERRIDE_ALL], [:pushws, NO_OVERRIDE], [:irb_push_binding, OVERRIDE_ALL], [:irb_pushb, OVERRIDE_ALL], [:pushb, NO_OVERRIDE], ], [ :irb_pop_workspace, :PopWorkspace, "irb/cmd/pushws", [:irb_popws, OVERRIDE_ALL], [:popws, NO_OVERRIDE], [:irb_pop_binding, OVERRIDE_ALL], [:irb_popb, OVERRIDE_ALL], [:popb, NO_OVERRIDE], ], [ :irb_load, :Load, "irb/cmd/load"], [ :irb_require, :Require, "irb/cmd/load"], [ :irb_source, :Source, "irb/cmd/load", [:source, NO_OVERRIDE], ], [ :irb, :IrbCommand, "irb/cmd/subirb"], [ :irb_jobs, :Jobs, "irb/cmd/subirb", [:jobs, NO_OVERRIDE], ], [ :irb_fg, :Foreground, "irb/cmd/subirb", [:fg, NO_OVERRIDE], ], [ :irb_kill, :Kill, "irb/cmd/subirb", [:kill, OVERRIDE_PRIVATE_ONLY], ], [ :irb_help, :Help, "irb/cmd/help", [:help, NO_OVERRIDE], ], [ :irb_info, :Info, "irb/cmd/info" ], ] # Installs the default irb commands: # # +irb_current_working_workspace+:: Context#main # +irb_change_workspace+:: Context#change_workspace # +irb_workspaces+:: Context#workspaces # +irb_push_workspace+:: Context#push_workspace # +irb_pop_workspace+:: Context#pop_workspace # +irb_load+:: #irb_load # +irb_require+:: #irb_require # +irb_source+:: IrbLoader#source_file # +irb+:: IRB.irb # +irb_jobs+:: JobManager # +irb_fg+:: JobManager#switch # +irb_kill+:: JobManager#kill # +irb_help+:: IRB@Command+line+options def self.install_extend_commands for args in @EXTEND_COMMANDS def_extend_command(*args) end end # Evaluate the given +cmd_name+ on the given +cmd_class+ Class. # # Will also define any given +aliases+ for the method. # # The optional +load_file+ parameter will be required within the method # definition. def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases) case cmd_class when Symbol cmd_class = cmd_class.id2name when String when Class cmd_class = cmd_class.name end if load_file line = __LINE__; eval %[ def #{cmd_name}(*opts, &b) require "#{load_file}" arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s } args << "*opts" if arity < 0 args << "&block" args = args.join(", ") line = __LINE__; eval %[ unless self.class.class_variable_defined?(:@@#{cmd_name}_) self.class.class_variable_set(:@@#{cmd_name}_, true) def #{cmd_name}_(\#{args}) ExtendCommand::#{cmd_class}.execute(irb_context, \#{args}) end end ], nil, __FILE__, line send :#{cmd_name}_, *opts, &b end ], nil, __FILE__, line else line = __LINE__; eval %[ def #{cmd_name}(*opts, &b) ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b) end ], nil, __FILE__, line end for ali, flag in aliases @ALIASES.push [ali, cmd_name, flag] end end # Installs alias methods for the default irb commands, see # ::install_extend_commands. def install_alias_method(to, from, override = NO_OVERRIDE) to = to.id2name unless to.kind_of?(String) from = from.id2name unless from.kind_of?(String) if override == OVERRIDE_ALL or (override == OVERRIDE_PRIVATE_ONLY) && !respond_to?(to) or (override == NO_OVERRIDE) && !respond_to?(to, true) target = self (class << self; self; end).instance_eval{ if target.respond_to?(to, true) && !target.respond_to?(EXCB.irb_original_method_name(to), true) alias_method(EXCB.irb_original_method_name(to), to) end alias_method to, from } else print "irb: warn: can't alias #{to} from #{from}.\n" end end def self.irb_original_method_name(method_name) # :nodoc: "irb_" + method_name + "_org" end # Installs alias methods for the default irb commands on the given object # using #install_alias_method. def self.extend_object(obj) unless (class << obj; ancestors; end).include?(EXCB) super for ali, com, flg in @ALIASES obj.install_alias_method(ali, com, flg) end end end install_extend_commands end # Extends methods for the Context module module ContextExtender CE = ContextExtender # :nodoc: @EXTEND_COMMANDS = [ [:eval_history=, "irb/ext/history.rb"], [:use_tracer=, "irb/ext/tracer.rb"], [:use_loader=, "irb/ext/use-loader.rb"], [:save_history=, "irb/ext/save-history.rb"], ] # Installs the default context extensions as irb commands: # # Context#eval_history=:: +irb/ext/history.rb+ # Context#use_tracer=:: +irb/ext/tracer.rb+ # Context#use_loader=:: +irb/ext/use-loader.rb+ # Context#save_history=:: +irb/ext/save-history.rb+ def self.install_extend_commands for args in @EXTEND_COMMANDS def_extend_command(*args) end end # Evaluate the given +command+ from the given +load_file+ on the Context # module. # # Will also define any given +aliases+ for the method. def self.def_extend_command(cmd_name, load_file, *aliases) line = __LINE__; Context.module_eval %[ def #{cmd_name}(*opts, &b) Context.module_eval {remove_method(:#{cmd_name})} require "#{load_file}" send :#{cmd_name}, *opts, &b end for ali in aliases alias_method ali, cmd_name end ], __FILE__, line end CE.install_extend_commands end # A convenience module for extending Ruby methods. module MethodExtender # Extends the given +base_method+ with a prefix call to the given # +extend_method+. def def_pre_proc(base_method, extend_method) base_method = base_method.to_s extend_method = extend_method.to_s alias_name = new_alias_name(base_method) module_eval %[ alias_method alias_name, base_method def #{base_method}(*opts) send :#{extend_method}, *opts send :#{alias_name}, *opts end ] end # Extends the given +base_method+ with a postfix call to the given # +extend_method+. def def_post_proc(base_method, extend_method) base_method = base_method.to_s extend_method = extend_method.to_s alias_name = new_alias_name(base_method) module_eval %[ alias_method alias_name, base_method def #{base_method}(*opts) send :#{alias_name}, *opts send :#{extend_method}, *opts end ] end # Returns a unique method name to use as an alias for the given +name+. # # Usually returns #{prefix}#{name}#{postfix}, example: # # new_alias_name('foo') #=> __alias_of__foo__ # def bar; end # new_alias_name('bar') #=> __alias_of__bar__2 def new_alias_name(name, prefix = "__alias_of__", postfix = "__") base_name = "#{prefix}#{name}#{postfix}" all_methods = instance_methods(true) + private_instance_methods(true) same_methods = all_methods.grep(/^#{Regexp.quote(base_name)}[0-9]*$/) return base_name if same_methods.empty? no = same_methods.size while !same_methods.include?(alias_name = base_name + no) no += 1 end alias_name end end end PKu] ["irb-1.2.6/lib/irb/ws-for-case-2.rbnu[# frozen_string_literal: false # # irb/ws-for-case-2.rb - # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # while true IRB::BINDING_QUEUE.push _ = binding end PKu] V2 "irb-1.2.6/lib/irb/output-method.rbnu[# frozen_string_literal: false # # output-method.rb - output methods used by irb # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # An abstract output class for IO in irb. This is mainly used internally by # IRB::Notifier. You can define your own output method to use with Irb.new, # or Context.new class OutputMethod class NotImplementedError < StandardError def initialize(val) super("Need to define `#{val}'") end end # Open this method to implement your own output method, raises a # NotImplementedError if you don't define #print in your own class. def print(*opts) raise NotImplementedError, "print" end # Prints the given +opts+, with a newline delimiter. def printn(*opts) print opts.join(" "), "\n" end # Extends IO#printf to format the given +opts+ for Kernel#sprintf using # #parse_printf_format def printf(format, *opts) if /(%*)%I/ =~ format format, opts = parse_printf_format(format, opts) end print sprintf(format, *opts) end # Returns an array of the given +format+ and +opts+ to be used by # Kernel#sprintf, if there was a successful Regexp match in the given # +format+ from #printf # # % # [#0- +] # (\*|\*[1-9][0-9]*\$|[1-9][0-9]*) # .(\*|\*[1-9][0-9]*\$|[1-9][0-9]*|)? # #(hh|h|l|ll|L|q|j|z|t) # [diouxXeEfgGcsb%] def parse_printf_format(format, opts) return format, opts if $1.size % 2 == 1 end # Calls #print on each element in the given +objs+, followed by a newline # character. def puts(*objs) for obj in objs print(*obj) print "\n" end end # Prints the given +objs+ calling Object#inspect on each. # # See #puts for more detail. def pp(*objs) puts(*objs.collect{|obj| obj.inspect}) end # Prints the given +objs+ calling Object#inspect on each and appending the # given +prefix+. # # See #puts for more detail. def ppx(prefix, *objs) puts(*objs.collect{|obj| prefix+obj.inspect}) end end # A standard output printer class StdioOutputMethod < OutputMethod # Prints the given +opts+ to standard output, see IO#print for more # information. def print(*opts) STDOUT.print(*opts) end end end PKu]qirb-1.2.6/lib/irb/inspector.rbnu[# frozen_string_literal: false # # irb/inspector.rb - inspect methods # $Release Version: 0.9.6$ # $Revision: 1.19 $ # $Date: 2002/06/11 07:51:31 $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # :nodoc: # Convenience method to create a new Inspector, using the given +inspect+ # proc, and optional +init+ proc and passes them to Inspector.new # # irb(main):001:0> ins = IRB::Inspector(proc{ |v| "omg! #{v}" }) # irb(main):001:0> IRB.CurrentContext.inspect_mode = ins # => omg! # # irb(main):001:0> "what?" #=> omg! what? # def IRB::Inspector(inspect, init = nil) Inspector.new(inspect, init) end # An irb inspector # # In order to create your own custom inspector there are two things you # should be aware of: # # Inspector uses #inspect_value, or +inspect_proc+, for output of return values. # # This also allows for an optional #init+, or +init_proc+, which is called # when the inspector is activated. # # Knowing this, you can create a rudimentary inspector as follows: # # irb(main):001:0> ins = IRB::Inspector.new(proc{ |v| "omg! #{v}" }) # irb(main):001:0> IRB.CurrentContext.inspect_mode = ins # => omg! # # irb(main):001:0> "what?" #=> omg! what? # class Inspector # Default inspectors available to irb, this includes: # # +:pp+:: Using Kernel#pretty_inspect # +:yaml+:: Using YAML.dump # +:marshal+:: Using Marshal.dump INSPECTORS = {} # Determines the inspector to use where +inspector+ is one of the keys passed # during inspector definition. def self.keys_with_inspector(inspector) INSPECTORS.select{|k,v| v == inspector}.collect{|k, v| k} end # Example # # Inspector.def_inspector(key, init_p=nil){|v| v.inspect} # Inspector.def_inspector([key1,..], init_p=nil){|v| v.inspect} # Inspector.def_inspector(key, inspector) # Inspector.def_inspector([key1,...], inspector) def self.def_inspector(key, arg=nil, &block) if block_given? inspector = IRB::Inspector(block, arg) else inspector = arg end case key when Array for k in key def_inspector(k, inspector) end when Symbol INSPECTORS[key] = inspector INSPECTORS[key.to_s] = inspector when String INSPECTORS[key] = inspector INSPECTORS[key.intern] = inspector else INSPECTORS[key] = inspector end end # Creates a new inspector object, using the given +inspect_proc+ when # output return values in irb. def initialize(inspect_proc, init_proc = nil) @init = init_proc @inspect = inspect_proc end # Proc to call when the inspector is activated, good for requiring # dependent libraries. def init @init.call if @init end # Proc to call when the input is evaluated and output in irb. def inspect_value(v) @inspect.call(v) end end Inspector.def_inspector([false, :to_s, :raw]){|v| v.to_s} Inspector.def_inspector([true, :p, :inspect]){|v| begin result = v.inspect if IRB.conf[:MAIN_CONTEXT]&.use_colorize? && Color.inspect_colorable?(v) result = Color.colorize_code(result) end result rescue NoMethodError puts "(Object doesn't support #inspect)" '' end } Inspector.def_inspector([:pp, :pretty_inspect], proc{require "pp"}){|v| result = v.pretty_inspect.chomp if IRB.conf[:MAIN_CONTEXT]&.use_colorize? && Color.inspect_colorable?(v) result = Color.colorize_code(result) end result } Inspector.def_inspector([:yaml, :YAML], proc{require "yaml"}){|v| begin YAML.dump(v) rescue puts "(can't dump yaml. use inspect)" v.inspect end } Inspector.def_inspector([:marshal, :Marshal, :MARSHAL, Marshal]){|v| Marshal.dump(v) } end PKu][irb-1.2.6/lib/irb/magic-file.rbnu[# frozen_string_literal: false module IRB class << (MagicFile = Object.new) # see parser_magic_comment in parse.y ENCODING_SPEC_RE = %r"coding\s*[=:]\s*([[:alnum:]\-_]+)" def open(path) io = File.open(path, 'rb') line = io.gets line = io.gets if line[0,2] == "#!" encoding = detect_encoding(line) internal_encoding = encoding encoding ||= IRB.default_src_encoding io.rewind io.set_encoding(encoding, internal_encoding) if block_given? begin return (yield io) ensure io.close end else return io end end private def detect_encoding(line) return unless line[0] == ?# line = line[1..-1] line = $1 if line[/-\*-\s*(.*?)\s*-*-$/] return nil unless ENCODING_SPEC_RE =~ line encoding = $1 return encoding.sub(/-(?:mac|dos|unix)/i, '') end end end PKu]cp.irb-1.2.6/lib/irb/notifier.rbnu[# frozen_string_literal: false # # notifier.rb - output methods used by irb # $Release Version: 0.9.6$ # $Revision$ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require_relative "output-method" module IRB # An output formatter used internally by the lexer. module Notifier class ErrUndefinedNotifier < StandardError def initialize(val) super("undefined notifier level: #{val} is specified") end end class ErrUnrecognizedLevel < StandardError def initialize(val) super("unrecognized notifier level: #{val} is specified") end end # Define a new Notifier output source, returning a new CompositeNotifier # with the given +prefix+ and +output_method+. # # The optional +prefix+ will be appended to all objects being inspected # during output, using the given +output_method+ as the output source. If # no +output_method+ is given, StdioOutputMethod will be used, and all # expressions will be sent directly to STDOUT without any additional # formatting. def def_notifier(prefix = "", output_method = StdioOutputMethod.new) CompositeNotifier.new(prefix, output_method) end module_function :def_notifier # An abstract class, or superclass, for CompositeNotifier and # LeveledNotifier to inherit. It provides several wrapper methods for the # OutputMethod object used by the Notifier. class AbstractNotifier # Creates a new Notifier object def initialize(prefix, base_notifier) @prefix = prefix @base_notifier = base_notifier end # The +prefix+ for this Notifier, which is appended to all objects being # inspected during output. attr_reader :prefix # A wrapper method used to determine whether notifications are enabled. # # Defaults to +true+. def notify? true end # See OutputMethod#print for more detail. def print(*opts) @base_notifier.print prefix, *opts if notify? end # See OutputMethod#printn for more detail. def printn(*opts) @base_notifier.printn prefix, *opts if notify? end # See OutputMethod#printf for more detail. def printf(format, *opts) @base_notifier.printf(prefix + format, *opts) if notify? end # See OutputMethod#puts for more detail. def puts(*objs) if notify? @base_notifier.puts(*objs.collect{|obj| prefix + obj.to_s}) end end # Same as #ppx, except it uses the #prefix given during object # initialization. # See OutputMethod#ppx for more detail. def pp(*objs) if notify? @base_notifier.ppx @prefix, *objs end end # Same as #pp, except it concatenates the given +prefix+ with the #prefix # given during object initialization. # # See OutputMethod#ppx for more detail. def ppx(prefix, *objs) if notify? @base_notifier.ppx @prefix+prefix, *objs end end # Execute the given block if notifications are enabled. def exec_if yield(@base_notifier) if notify? end end # A class that can be used to create a group of notifier objects with the # intent of representing a leveled notification system for irb. # # This class will allow you to generate other notifiers, and assign them # the appropriate level for output. # # The Notifier class provides a class-method Notifier.def_notifier to # create a new composite notifier. Using the first composite notifier # object you create, sibling notifiers can be initialized with # #def_notifier. class CompositeNotifier < AbstractNotifier # Create a new composite notifier object with the given +prefix+, and # +base_notifier+ to use for output. def initialize(prefix, base_notifier) super @notifiers = [D_NOMSG] @level_notifier = D_NOMSG end # List of notifiers in the group attr_reader :notifiers # Creates a new LeveledNotifier in the composite #notifiers group. # # The given +prefix+ will be assigned to the notifier, and +level+ will # be used as the index of the #notifiers Array. # # This method returns the newly created instance. def def_notifier(level, prefix = "") notifier = LeveledNotifier.new(self, level, prefix) @notifiers[level] = notifier notifier end # Returns the leveled notifier for this object attr_reader :level_notifier alias level level_notifier # Sets the leveled notifier for this object. # # When the given +value+ is an instance of AbstractNotifier, # #level_notifier is set to the given object. # # When an Integer is given, #level_notifier is set to the notifier at the # index +value+ in the #notifiers Array. # # If no notifier exists at the index +value+ in the #notifiers Array, an # ErrUndefinedNotifier exception is raised. # # An ErrUnrecognizedLevel exception is raised if the given +value+ is not # found in the existing #notifiers Array, or an instance of # AbstractNotifier def level_notifier=(value) case value when AbstractNotifier @level_notifier = value when Integer l = @notifiers[value] raise ErrUndefinedNotifier, value unless l @level_notifier = l else raise ErrUnrecognizedLevel, value unless l end end alias level= level_notifier= end # A leveled notifier is comparable to the composite group from # CompositeNotifier#notifiers. class LeveledNotifier < AbstractNotifier include Comparable # Create a new leveled notifier with the given +base+, and +prefix+ to # send to AbstractNotifier.new # # The given +level+ is used to compare other leveled notifiers in the # CompositeNotifier group to determine whether or not to output # notifications. def initialize(base, level, prefix) super(prefix, base) @level = level end # The current level of this notifier object attr_reader :level # Compares the level of this notifier object with the given +other+ # notifier. # # See the Comparable module for more information. def <=>(other) @level <=> other.level end # Whether to output messages to the output method, depending on the level # of this notifier object. def notify? @base_notifier.level >= self end end # NoMsgNotifier is a LeveledNotifier that's used as the default notifier # when creating a new CompositeNotifier. # # This notifier is used as the +zero+ index, or level +0+, for # CompositeNotifier#notifiers, and will not output messages of any sort. class NoMsgNotifier < LeveledNotifier # Creates a new notifier that should not be used to output messages. def initialize @base_notifier = nil @level = 0 @prefix = "" end # Ensures notifications are ignored, see AbstractNotifier#notify? for # more information. def notify? false end end D_NOMSG = NoMsgNotifier.new # :nodoc: end end PKu]D\\bundler-2.2.24/libexec/bundlernuȯ#!/usr/bin/ruby # frozen_string_literal: true load File.expand_path("../bundle", __FILE__) PKu]ʏMbundler-2.2.24/libexec/bundlenuȯ#!/usr/bin/ruby # frozen_string_literal: true # Exit cleanly from an early interrupt Signal.trap("INT") do Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler) exit 1 end base_path = File.expand_path("../lib", __dir__) if File.exist?(base_path) require_relative "../lib/bundler" else require "bundler" end # Check if an older version of bundler is installed $LOAD_PATH.each do |path| next unless path =~ %r{/bundler-0\.(\d+)} && $1.to_i < 9 err = String.new err << "Looks like you have a version of bundler that's older than 0.9.\n" err << "Please remove your old versions.\n" err << "An easy way to do this is by running `gem cleanup bundler`." abort(err) end if File.exist?(base_path) require_relative "../lib/bundler/friendly_errors" else require "bundler/friendly_errors" end Bundler.with_friendly_errors do if File.exist?(base_path) require_relative "../lib/bundler/cli" else require "bundler/cli" end # Allow any command to use --help flag to show help for that command help_flags = %w[--help -h] help_flag_used = ARGV.any? {|a| help_flags.include? a } args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV Bundler::CLI.start(args, :debug => true) end PKu]^ ^^bundler-2.2.24/lib/bundler.rbnu[# frozen_string_literal: true require_relative "bundler/vendored_fileutils" require "pathname" require "rbconfig" require_relative "bundler/errors" require_relative "bundler/environment_preserver" require_relative "bundler/plugin" require_relative "bundler/rubygems_ext" require_relative "bundler/rubygems_integration" require_relative "bundler/version" require_relative "bundler/constants" require_relative "bundler/current_ruby" require_relative "bundler/build_metadata" # Bundler provides a consistent environment for Ruby projects by # tracking and installing the exact gems and versions that are needed. # # Since Ruby 2.6, Bundler is a part of Ruby's standard library. # # Bunder is used by creating _gemfiles_ listing all the project dependencies # and (optionally) their versions and then using # # require 'bundler/setup' # # or Bundler.setup to setup environment where only specified gems and their # specified versions could be used. # # See {Bundler website}[https://bundler.io/docs.html] for extensive documentation # on gemfiles creation and Bundler usage. # # As a standard library inside project, Bundler could be used for introspection # of loaded and required modules. # module Bundler environment_preserver = EnvironmentPreserver.from_env ORIGINAL_ENV = environment_preserver.restore environment_preserver.replace_with_backup SUDO_MUTEX = Mutex.new autoload :Definition, File.expand_path("bundler/definition", __dir__) autoload :Dependency, File.expand_path("bundler/dependency", __dir__) autoload :DepProxy, File.expand_path("bundler/dep_proxy", __dir__) autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__) autoload :Dsl, File.expand_path("bundler/dsl", __dir__) autoload :EndpointSpecification, File.expand_path("bundler/endpoint_specification", __dir__) autoload :Env, File.expand_path("bundler/env", __dir__) autoload :Fetcher, File.expand_path("bundler/fetcher", __dir__) autoload :FeatureFlag, File.expand_path("bundler/feature_flag", __dir__) autoload :GemHelper, File.expand_path("bundler/gem_helper", __dir__) autoload :GemHelpers, File.expand_path("bundler/gem_helpers", __dir__) autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__) autoload :Graph, File.expand_path("bundler/graph", __dir__) autoload :Index, File.expand_path("bundler/index", __dir__) autoload :Injector, File.expand_path("bundler/injector", __dir__) autoload :Installer, File.expand_path("bundler/installer", __dir__) autoload :LazySpecification, File.expand_path("bundler/lazy_specification", __dir__) autoload :LockfileParser, File.expand_path("bundler/lockfile_parser", __dir__) autoload :MatchPlatform, File.expand_path("bundler/match_platform", __dir__) autoload :ProcessLock, File.expand_path("bundler/process_lock", __dir__) autoload :RemoteSpecification, File.expand_path("bundler/remote_specification", __dir__) autoload :Resolver, File.expand_path("bundler/resolver", __dir__) autoload :Retry, File.expand_path("bundler/retry", __dir__) autoload :RubyDsl, File.expand_path("bundler/ruby_dsl", __dir__) autoload :RubyVersion, File.expand_path("bundler/ruby_version", __dir__) autoload :Runtime, File.expand_path("bundler/runtime", __dir__) autoload :Settings, File.expand_path("bundler/settings", __dir__) autoload :SharedHelpers, File.expand_path("bundler/shared_helpers", __dir__) autoload :Source, File.expand_path("bundler/source", __dir__) autoload :SourceList, File.expand_path("bundler/source_list", __dir__) autoload :SourceMap, File.expand_path("bundler/source_map", __dir__) autoload :SpecSet, File.expand_path("bundler/spec_set", __dir__) autoload :StubSpecification, File.expand_path("bundler/stub_specification", __dir__) autoload :UI, File.expand_path("bundler/ui", __dir__) autoload :URICredentialsFilter, File.expand_path("bundler/uri_credentials_filter", __dir__) autoload :VersionRanges, File.expand_path("bundler/version_ranges", __dir__) class << self def configure @configured ||= configure_gem_home_and_path end def ui (defined?(@ui) && @ui) || (self.ui = UI::Shell.new) end def ui=(ui) Bundler.rubygems.ui = UI::RGProxy.new(ui) @ui = ui end # Returns absolute path of where gems are installed on the filesystem. def bundle_path @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root) end def configured_bundle_path @configured_bundle_path ||= settings.path.tap(&:validate!) end # Returns absolute location of where binstubs are installed to. def bin_path @bin_path ||= begin path = settings[:bin] || "bin" path = Pathname.new(path).expand_path(root).expand_path SharedHelpers.filesystem_access(path) {|p| FileUtils.mkdir_p(p) } path end end # Turns on the Bundler runtime. After +Bundler.setup+ call, all +load+ or # +require+ of the gems would be allowed only if they are part of # the Gemfile or Ruby's standard library. If the versions specified # in Gemfile, only those versions would be loaded. # # Assuming Gemfile # # gem 'first_gem', '= 1.0' # group :test do # gem 'second_gem', '= 1.0' # end # # The code using Bundler.setup works as follows: # # require 'third_gem' # allowed, required from global gems # require 'first_gem' # allowed, loads the last installed version # Bundler.setup # require 'fourth_gem' # fails with LoadError # require 'second_gem' # loads exactly version 1.0 # # +Bundler.setup+ can be called only once, all subsequent calls are no-op. # # If _groups_ list is provided, only gems from specified groups would # be allowed (gems specified outside groups belong to special +:default+ group). # # To require all gems from Gemfile (or only some groups), see Bundler.require. # def setup(*groups) # Return if all groups are already loaded return @setup if defined?(@setup) && @setup definition.validate_runtime! SharedHelpers.print_major_deprecations! if groups.empty? # Load all groups, but only once @setup = load.setup else load.setup(*groups) end end # Setups Bundler environment (see Bundler.setup) if it is not already set, # and loads all gems from groups specified. Unlike ::setup, can be called # multiple times with different groups (if they were allowed by setup). # # Assuming Gemfile # # gem 'first_gem', '= 1.0' # group :test do # gem 'second_gem', '= 1.0' # end # # The code will work as follows: # # Bundler.setup # allow all groups # Bundler.require(:default) # requires only first_gem # # ...later # Bundler.require(:test) # requires second_gem # def require(*groups) setup(*groups).require(*groups) end def load @load ||= Runtime.new(root, definition) end def environment SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", :print_caller_location => true load end # Returns an instance of Bundler::Definition for given Gemfile and lockfile # # @param unlock [Hash, Boolean, nil] Gems that have been requested # to be updated or true if all gems should be updated # @return [Bundler::Definition] def definition(unlock = nil) @definition = nil if unlock @definition ||= begin configure Definition.build(default_gemfile, default_lockfile, unlock) end end def frozen_bundle? frozen = settings[:deployment] frozen ||= settings[:frozen] frozen end def locked_gems @locked_gems ||= if defined?(@definition) && @definition definition.locked_gems elsif Bundler.default_lockfile.file? lock = Bundler.read_file(Bundler.default_lockfile) LockfileParser.new(lock) end end def most_specific_locked_platform?(platform) return false unless defined?(@definition) && @definition definition.most_specific_locked_platform == platform end def ruby_scope "#{Bundler.rubygems.ruby_engine}/#{RbConfig::CONFIG["ruby_version"]}" end def user_home @user_home ||= begin home = Bundler.rubygems.user_home bundle_home = home ? File.join(home, ".bundle") : nil warning = if home.nil? "Your home directory is not set." elsif !File.directory?(home) "`#{home}` is not a directory." elsif !File.writable?(home) && (!File.directory?(bundle_home) || !File.writable?(bundle_home)) "`#{home}` is not writable." end if warning Bundler.ui.warn "#{warning}\n" user_home = tmp_home_path Bundler.ui.warn "Bundler will use `#{user_home}' as your home directory temporarily.\n" user_home else Pathname.new(home) end end end def user_bundle_path(dir = "home") env_var, fallback = case dir when "home" ["BUNDLE_USER_HOME", proc { Pathname.new(user_home).join(".bundle") }] when "cache" ["BUNDLE_USER_CACHE", proc { user_bundle_path.join("cache") }] when "config" ["BUNDLE_USER_CONFIG", proc { user_bundle_path.join("config") }] when "plugin" ["BUNDLE_USER_PLUGIN", proc { user_bundle_path.join("plugin") }] else raise BundlerError, "Unknown user path requested: #{dir}" end # `fallback` will already be a Pathname, but Pathname.new() is # idempotent so it's OK Pathname.new(ENV.fetch(env_var, &fallback)) end def user_cache user_bundle_path("cache") end def home bundle_path.join("bundler") end def install_path home.join("gems") end def specs_path bundle_path.join("specifications") end def root @root ||= begin SharedHelpers.root rescue GemfileNotFound bundle_dir = default_bundle_dir raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir Pathname.new(File.expand_path("..", bundle_dir)) end end def app_config_path if app_config = ENV["BUNDLE_APP_CONFIG"] app_config_pathname = Pathname.new(app_config) if app_config_pathname.absolute? app_config_pathname else app_config_pathname.expand_path(root) end else root.join(".bundle") end end def app_cache(custom_path = nil) path = custom_path || root Pathname.new(path).join(settings.app_cache_path) end def tmp(name = Process.pid.to_s) Kernel.send(:require, "tmpdir") Pathname.new(Dir.mktmpdir(["bundler", name])) end def rm_rf(path) FileUtils.remove_entry_secure(path) if path && File.exist?(path) rescue ArgumentError message = < true ) unbundled_env end # @return [Hash] Environment with all bundler-related variables removed def unbundled_env env = original_env if env.key?("BUNDLER_ORIG_MANPATH") env["MANPATH"] = env["BUNDLER_ORIG_MANPATH"] end env.delete_if {|k, _| k[0, 7] == "BUNDLE_" } if env.key?("RUBYOPT") rubyopt = env["RUBYOPT"].split(" ") rubyopt.delete("-r#{File.expand_path("bundler/setup", __dir__)}") rubyopt.delete("-rbundler/setup") env["RUBYOPT"] = rubyopt.join(" ") end if env.key?("RUBYLIB") rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR) rubylib.delete(File.expand_path("..", __FILE__)) env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR) end env end # Run block with environment present before Bundler was activated def with_original_env with_env(original_env) { yield } end # @deprecated Use `with_unbundled_env` instead def with_clean_env Bundler::SharedHelpers.major_deprecation( 2, "`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \ "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`", :print_caller_location => true ) with_env(unbundled_env) { yield } end # Run block with all bundler-related variables removed def with_unbundled_env with_env(unbundled_env) { yield } end # Run subcommand with the environment present before Bundler was activated def original_system(*args) with_original_env { Kernel.system(*args) } end # @deprecated Use `unbundled_system` instead def clean_system(*args) Bundler::SharedHelpers.major_deprecation( 2, "`Bundler.clean_system` has been deprecated in favor of `Bundler.unbundled_system`. " \ "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`", :print_caller_location => true ) with_env(unbundled_env) { Kernel.system(*args) } end # Run subcommand in an environment with all bundler related variables removed def unbundled_system(*args) with_unbundled_env { Kernel.system(*args) } end # Run a `Kernel.exec` to a subcommand with the environment present before Bundler was activated def original_exec(*args) with_original_env { Kernel.exec(*args) } end # @deprecated Use `unbundled_exec` instead def clean_exec(*args) Bundler::SharedHelpers.major_deprecation( 2, "`Bundler.clean_exec` has been deprecated in favor of `Bundler.unbundled_exec`. " \ "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`", :print_caller_location => true ) with_env(unbundled_env) { Kernel.exec(*args) } end # Run a `Kernel.exec` to a subcommand in an environment with all bundler related variables removed def unbundled_exec(*args) with_env(unbundled_env) { Kernel.exec(*args) } end def local_platform return Gem::Platform::RUBY if settings[:force_ruby_platform] || Gem.platforms == [Gem::Platform::RUBY] Gem::Platform.local end def default_gemfile SharedHelpers.default_gemfile end def default_lockfile SharedHelpers.default_lockfile end def default_bundle_dir SharedHelpers.default_bundle_dir end def system_bindir # Gem.bindir doesn't always return the location that RubyGems will install # system binaries. If you put '-n foo' in your .gemrc, RubyGems will # install binstubs there instead. Unfortunately, RubyGems doesn't expose # that directory at all, so rather than parse .gemrc ourselves, we allow # the directory to be set as well, via `bundle config set --local bindir foo`. Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir end def preferred_gemfile_name Bundler.settings[:init_gems_rb] ? "gems.rb" : "Gemfile" end def use_system_gems? configured_bundle_path.use_system_gems? end def requires_sudo? return @requires_sudo if defined?(@requires_sudo_ran) sudo_present = which "sudo" if settings.allow_sudo? if sudo_present # the bundle path and subdirectories need to be writable for RubyGems # to be able to unpack and install gems without exploding path = bundle_path path = path.parent until path.exist? # bins are written to a different location on OS X bin_dir = Pathname.new(Bundler.system_bindir) bin_dir = bin_dir.parent until bin_dir.exist? # if any directory is not writable, we need sudo files = [path, bin_dir] | Dir[bundle_path.join("build_info/*").to_s] | Dir[bundle_path.join("*").to_s] unwritable_files = files.reject {|f| File.writable?(f) } sudo_needed = !unwritable_files.empty? if sudo_needed Bundler.ui.warn "Following files may not be writable, so sudo is needed:\n #{unwritable_files.map(&:to_s).sort.join("\n ")}" end end @requires_sudo_ran = true @requires_sudo = settings.allow_sudo? && sudo_present && sudo_needed end def mkdir_p(path, options = {}) if requires_sudo? && !options[:no_sudo] sudo "mkdir -p '#{path}'" unless File.exist?(path) else SharedHelpers.filesystem_access(path, :write) do |p| FileUtils.mkdir_p(p) end end end def which(executable) if File.file?(executable) && File.executable?(executable) executable elsif paths = ENV["PATH"] quote = '"'.freeze paths.split(File::PATH_SEPARATOR).find do |path| path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote) executable_path = File.expand_path(executable, path) return executable_path if File.file?(executable_path) && File.executable?(executable_path) end end end def sudo(str) SUDO_MUTEX.synchronize do prompt = "\n\n" + <<-PROMPT.gsub(/^ {6}/, "").strip + " " Your user account isn't allowed to install to the system RubyGems. You can cancel this installation and run: bundle config set --local path 'vendor/bundle' bundle install to install the gems into ./vendor/bundle/, or you can enter your password and install the bundled gems to RubyGems using sudo. Password: PROMPT unless @prompted_for_sudo ||= system(%(sudo -k -p "#{prompt}" true)) raise SudoNotPermittedError, "Bundler requires sudo access to install at the moment. " \ "Try installing again, granting Bundler sudo access when prompted, or installing into a different path." end `sudo -p "#{prompt}" #{str}` end end def read_file(file) SharedHelpers.filesystem_access(file, :read) do File.open(file, "r:UTF-8", &:read) end end def load_marshal(data) Marshal.load(data) rescue StandardError => e raise MarshalError, "#{e.class}: #{e.message}" end def load_gemspec(file, validate = false) @gemspec_cache ||= {} key = File.expand_path(file) @gemspec_cache[key] ||= load_gemspec_uncached(file, validate) # Protect against caching side-effected gemspecs by returning a # new instance each time. @gemspec_cache[key].dup if @gemspec_cache[key] end def load_gemspec_uncached(file, validate = false) path = Pathname.new(file) contents = read_file(file) spec = if contents.start_with?("---") # YAML header eval_yaml_gemspec(path, contents) else # Eval the gemspec from its parent directory, because some gemspecs # depend on "./" relative paths. SharedHelpers.chdir(path.dirname.to_s) do eval_gemspec(path, contents) end end return unless spec spec.loaded_from = path.expand_path.to_s Bundler.rubygems.validate(spec) if validate spec end def clear_gemspec_cache @gemspec_cache = {} end def git_present? return @git_present if defined?(@git_present) @git_present = Bundler.which("git") || Bundler.which("git.exe") end def feature_flag @feature_flag ||= FeatureFlag.new(VERSION) end def reset! reset_paths! Plugin.reset! reset_rubygems! end def reset_settings_and_root! @settings = nil @root = nil end def reset_paths! @bin_path = nil @bundler_major_version = nil @bundle_path = nil @configured = nil @configured_bundle_path = nil @definition = nil @load = nil @locked_gems = nil @root = nil @settings = nil @setup = nil @user_home = nil end def reset_rubygems! return unless defined?(@rubygems) && @rubygems rubygems.undo_replacements rubygems.reset @rubygems = nil end private def eval_yaml_gemspec(path, contents) require_relative "bundler/psyched_yaml" # If the YAML is invalid, Syck raises an ArgumentError, and Psych # raises a Psych::SyntaxError. See psyched_yaml.rb for more info. Gem::Specification.from_yaml(contents) rescue YamlLibrarySyntaxError, ArgumentError, Gem::EndOfYAMLException, Gem::Exception eval_gemspec(path, contents) end def eval_gemspec(path, contents) eval(contents, TOPLEVEL_BINDING.dup, path.expand_path.to_s) rescue ScriptError, StandardError => e msg = "There was an error while loading `#{path.basename}`: #{e.message}" if e.is_a?(LoadError) msg += "\nDoes it try to require a relative path? That's been removed in Ruby 1.9" end raise GemspecError, Dsl::DSLError.new(msg, path, e.backtrace, contents) end def configure_gem_home_and_path configure_gem_path configure_gem_home bundle_path end def configure_gem_path(env = ENV) blank_home = env["GEM_HOME"].nil? || env["GEM_HOME"].empty? if !use_system_gems? # this needs to be empty string to cause # PathSupport.split_gem_path to only load up the # Bundler --path setting as the GEM_PATH. env["GEM_PATH"] = "" elsif blank_home possibles = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path] paths = possibles.flatten.compact.uniq.reject(&:empty?) env["GEM_PATH"] = paths.join(File::PATH_SEPARATOR) end end def configure_gem_home Bundler::SharedHelpers.set_env "GEM_HOME", File.expand_path(bundle_path, root) Bundler.rubygems.clear_paths end def tmp_home_path Kernel.send(:require, "tmpdir") SharedHelpers.filesystem_access(Dir.tmpdir) do path = Bundler.tmp at_exit { Bundler.rm_rf(path) } path end end # @param env [Hash] def with_env(env) backup = ENV.to_hash ENV.replace(env) yield ensure ENV.replace(backup) end end end PKu]tJT T $bundler-2.2.24/lib/bundler/source.rbnu[# frozen_string_literal: true module Bundler class Source autoload :Gemspec, File.expand_path("source/gemspec", __dir__) autoload :Git, File.expand_path("source/git", __dir__) autoload :Metadata, File.expand_path("source/metadata", __dir__) autoload :Path, File.expand_path("source/path", __dir__) autoload :Rubygems, File.expand_path("source/rubygems", __dir__) autoload :RubygemsAggregate, File.expand_path("source/rubygems_aggregate", __dir__) attr_accessor :dependency_names def unmet_deps specs.unmet_dependency_names end def version_message(spec) message = "#{spec.name} #{spec.version}" message += " (#{spec.platform})" if spec.platform != Gem::Platform::RUBY && !spec.platform.nil? if Bundler.locked_gems locked_spec = Bundler.locked_gems.specs.find {|s| s.name == spec.name } locked_spec_version = locked_spec.version if locked_spec if locked_spec_version && spec.version != locked_spec_version message += Bundler.ui.add_color(" (was #{locked_spec_version})", version_color(spec.version, locked_spec_version)) end end message end def can_lock?(spec) spec.source == self end def local!; end def local_only!; end def cached!; end def remote!; end def add_dependency_names(names) @dependency_names = Array(dependency_names) | Array(names) end # it's possible that gems from one source depend on gems from some # other source, so now we download gemspecs and iterate over those # dependencies, looking for gems we don't have info on yet. def double_check_for(*); end def dependency_names_to_double_check specs.dependency_names end def spec_names specs.spec_names end def include?(other) other == self end def inspect "#<#{self.class}:0x#{object_id} #{self}>" end def path? instance_of?(Bundler::Source::Path) end def extension_cache_path(spec) return unless Bundler.feature_flag.global_gem_cache? return unless source_slug = extension_cache_slug(spec) Bundler.user_cache.join( "extensions", Gem::Platform.local.to_s, Bundler.ruby_scope, source_slug, spec.full_name ) end private def version_color(spec_version, locked_spec_version) if Gem::Version.correct?(spec_version) && Gem::Version.correct?(locked_spec_version) # display yellow if there appears to be a regression earlier_version?(spec_version, locked_spec_version) ? :yellow : :green else # default to green if the versions cannot be directly compared :green end end def earlier_version?(spec_version, locked_spec_version) Gem::Version.new(spec_version) < Gem::Version.new(locked_spec_version) end def print_using_message(message) if !message.include?("(was ") && Bundler.feature_flag.suppress_install_using_messages? Bundler.ui.debug message else Bundler.ui.info message end end def extension_cache_slug(_) nil end end end PKu]${4bundler-2.2.24/lib/bundler/endpoint_specification.rbnu[# frozen_string_literal: true module Bundler # used for Creating Specifications from the Gemcutter Endpoint class EndpointSpecification < Gem::Specification ILLFORMED_MESSAGE = 'Ill-formed requirement ["# e raise GemspecError, "There was an error parsing the metadata for the gem #{name} (#{version}): #{e.class}\n#{e}\nThe metadata was #{data.inspect}" end def build_dependency(name, requirements) Gem::Dependency.new(name, requirements) rescue ArgumentError => e raise unless e.message.include?(ILLFORMED_MESSAGE) puts # we shouldn't print the error message on the "fetching info" status line raise GemspecError, "Unfortunately, the gem #{name} (#{version}) has an invalid " \ "gemspec.\nPlease ask the gem author to yank the bad version to fix " \ "this issue. For more information, see http://bit.ly/syck-defaultkey." end end end PKu]١"2)2)%bundler-2.2.24/lib/bundler/runtime.rbnu[# frozen_string_literal: true module Bundler class Runtime include SharedHelpers def initialize(root, definition) @root = root @definition = definition end def setup(*groups) @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen_bundle? # Has to happen first clean_load_path specs = @definition.specs_for(groups) SharedHelpers.set_bundle_environment Bundler.rubygems.replace_entrypoints(specs) # Activate the specs load_paths = specs.map do |spec| unless spec.loaded_from raise GemNotFound, "#{spec.full_name} is missing. Run `bundle install` to get it." end check_for_activated_spec!(spec) Bundler.rubygems.mark_loaded(spec) spec.load_paths.reject {|path| $LOAD_PATH.include?(path) } end.reverse.flatten Bundler.rubygems.add_to_load_path(load_paths) setup_manpath lock(:preserve_unknown_sections => true) self end def require(*groups) groups.map!(&:to_sym) groups = [:default] if groups.empty? @definition.dependencies.each do |dep| # Skip the dependency if it is not in any of the requested groups, or # not for the current platform, or doesn't match the gem constraints. next unless (dep.groups & groups).any? && dep.should_include? required_file = nil begin # Loop through all the specified autorequires for the # dependency. If there are none, use the dependency's name # as the autorequire. Array(dep.autorequire || dep.name).each do |file| # Allow `require: true` as an alias for `require: ` file = dep.name if file == true required_file = file begin Kernel.require file rescue RuntimeError => e raise e if e.is_a?(LoadError) # we handle this a little later raise Bundler::GemRequireError.new e, "There was an error while trying to load the gem '#{file}'." end end rescue LoadError => e raise if dep.autorequire || e.path != required_file if dep.autorequire.nil? && dep.name.include?("-") begin namespaced_file = dep.name.tr("-", "/") Kernel.require namespaced_file rescue LoadError => e raise if e.path != namespaced_file end end end end end def self.definition_method(meth) define_method(meth) do raise ArgumentError, "no definition when calling Runtime##{meth}" unless @definition @definition.send(meth) end end private_class_method :definition_method definition_method :requested_specs definition_method :specs definition_method :dependencies definition_method :current_dependencies definition_method :requires def lock(opts = {}) return if @definition.nothing_changed? && !@definition.unlocking? @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections]) end alias_method :gems, :specs def cache(custom_path = nil) cache_path = Bundler.app_cache(custom_path) SharedHelpers.filesystem_access(cache_path) do |p| FileUtils.mkdir_p(p) end unless File.exist?(cache_path) Bundler.ui.info "Updating files in #{Bundler.settings.app_cache_path}" specs_to_cache = Bundler.settings[:cache_all_platforms] ? @definition.resolve.materialized_for_all_platforms : specs specs_to_cache.each do |spec| next if spec.name == "bundler" next if spec.source.is_a?(Source::Gemspec) spec.source.send(:fetch_gem, spec) if Bundler.settings[:cache_all_platforms] && spec.source.respond_to?(:fetch_gem, true) spec.source.cache(spec, custom_path) if spec.source.respond_to?(:cache) end Dir[cache_path.join("*/.git")].each do |git_dir| FileUtils.rm_rf(git_dir) FileUtils.touch(File.expand_path("../.bundlecache", git_dir)) end prune_cache(cache_path) unless Bundler.settings[:no_prune] end def prune_cache(cache_path) SharedHelpers.filesystem_access(cache_path) do |p| FileUtils.mkdir_p(p) end unless File.exist?(cache_path) resolve = @definition.resolve prune_gem_cache(resolve, cache_path) prune_git_and_path_cache(resolve, cache_path) end def clean(dry_run = false) gem_bins = Dir["#{Gem.dir}/bin/*"] git_dirs = Dir["#{Gem.dir}/bundler/gems/*"] git_cache_dirs = Dir["#{Gem.dir}/cache/bundler/git/*"] gem_dirs = Dir["#{Gem.dir}/gems/*"] gem_files = Dir["#{Gem.dir}/cache/*.gem"] gemspec_files = Dir["#{Gem.dir}/specifications/*.gemspec"] extension_dirs = Dir["#{Gem.dir}/extensions/*/*/*"] + Dir["#{Gem.dir}/bundler/gems/extensions/*/*/*"] spec_gem_paths = [] # need to keep git sources around spec_git_paths = @definition.spec_git_paths spec_git_cache_dirs = [] spec_gem_executables = [] spec_cache_paths = [] spec_gemspec_paths = [] spec_extension_paths = [] Bundler.rubygems.add_default_gems_to(specs).values.each do |spec| spec_gem_paths << spec.full_gem_path # need to check here in case gems are nested like for the rails git repo md = %r{(.+bundler/gems/.+-[a-f0-9]{7,12})}.match(spec.full_gem_path) spec_git_paths << md[1] if md spec_gem_executables << spec.executables.collect do |executable| e = "#{Bundler.rubygems.gem_bindir}/#{executable}" [e, "#{e}.bat"] end spec_cache_paths << spec.cache_file spec_gemspec_paths << spec.spec_file spec_extension_paths << spec.extension_dir if spec.respond_to?(:extension_dir) spec_git_cache_dirs << spec.source.cache_path.to_s if spec.source.is_a?(Bundler::Source::Git) end spec_gem_paths.uniq! spec_gem_executables.flatten! stale_gem_bins = gem_bins - spec_gem_executables stale_git_dirs = git_dirs - spec_git_paths - ["#{Gem.dir}/bundler/gems/extensions"] stale_git_cache_dirs = git_cache_dirs - spec_git_cache_dirs stale_gem_dirs = gem_dirs - spec_gem_paths stale_gem_files = gem_files - spec_cache_paths stale_gemspec_files = gemspec_files - spec_gemspec_paths stale_extension_dirs = extension_dirs - spec_extension_paths removed_stale_gem_dirs = stale_gem_dirs.collect {|dir| remove_dir(dir, dry_run) } removed_stale_git_dirs = stale_git_dirs.collect {|dir| remove_dir(dir, dry_run) } output = removed_stale_gem_dirs + removed_stale_git_dirs unless dry_run stale_files = stale_gem_bins + stale_gem_files + stale_gemspec_files stale_files.each do |file| SharedHelpers.filesystem_access(File.dirname(file)) do |_p| FileUtils.rm(file) if File.exist?(file) end end stale_dirs = stale_git_cache_dirs + stale_extension_dirs stale_dirs.each do |stale_dir| SharedHelpers.filesystem_access(stale_dir) do |dir| FileUtils.rm_rf(dir) if File.exist?(dir) end end end output end private def prune_gem_cache(resolve, cache_path) cached = Dir["#{cache_path}/*.gem"] cached = cached.delete_if do |path| spec = Bundler.rubygems.spec_from_gem path resolve.any? do |s| s.name == spec.name && s.version == spec.version && !s.source.is_a?(Bundler::Source::Git) end end if cached.any? Bundler.ui.info "Removing outdated .gem files from #{Bundler.settings.app_cache_path}" cached.each do |path| Bundler.ui.info " * #{File.basename(path)}" File.delete(path) end end end def prune_git_and_path_cache(resolve, cache_path) cached = Dir["#{cache_path}/*/.bundlecache"] cached = cached.delete_if do |path| name = File.basename(File.dirname(path)) resolve.any? do |s| source = s.source source.respond_to?(:app_cache_dirname) && source.app_cache_dirname == name end end if cached.any? Bundler.ui.info "Removing outdated git and path gems from #{Bundler.settings.app_cache_path}" cached.each do |path| path = File.dirname(path) Bundler.ui.info " * #{File.basename(path)}" FileUtils.rm_rf(path) end end end def setup_manpath # Add man/ subdirectories from activated bundles to MANPATH for man(1) manuals = $LOAD_PATH.map do |path| man_subdir = path.sub(/lib$/, "man") man_subdir unless Dir[man_subdir + "/man?/"].empty? end.compact return if manuals.empty? Bundler::SharedHelpers.set_env "MANPATH", manuals.concat( ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR) ).uniq.join(File::PATH_SEPARATOR) end def remove_dir(dir, dry_run) full_name = Pathname.new(dir).basename.to_s parts = full_name.split("-") name = parts[0..-2].join("-") version = parts.last output = "#{name} (#{version})" if dry_run Bundler.ui.info "Would have removed #{output}" else Bundler.ui.info "Removing #{output}" FileUtils.rm_rf(dir) end output end def check_for_activated_spec!(spec) return unless activated_spec = Bundler.rubygems.loaded_specs(spec.name) return if activated_spec.version == spec.version suggestion = if Bundler.rubygems.spec_default_gem?(activated_spec) "Since #{spec.name} is a default gem, you can either remove your dependency on it" \ " or try updating to a newer version of bundler that supports #{spec.name} as a default gem." else "Prepending `bundle exec` to your command may solve this." end e = Gem::LoadError.new "You have already activated #{activated_spec.name} #{activated_spec.version}, " \ "but your Gemfile requires #{spec.name} #{spec.version}. #{suggestion}" e.name = spec.name if e.respond_to?(:requirement=) e.requirement = Gem::Requirement.new(spec.version.to_s) else e.version_requirement = Gem::Requirement.new(spec.version.to_s) end raise e end end end PKu]P0bundler-2.2.24/lib/bundler/lazy_specification.rbnu[# frozen_string_literal: true require_relative "match_platform" module Bundler class LazySpecification include MatchPlatform attr_reader :name, :version, :dependencies, :platform attr_accessor :source, :remote def initialize(name, version, platform, source = nil) @name = name @version = version @dependencies = [] @platform = platform || Gem::Platform::RUBY @source = source @specification = nil end def full_name if platform == Gem::Platform::RUBY || platform.nil? "#{@name}-#{@version}" else "#{@name}-#{@version}-#{platform}" end end def ==(other) identifier == other.identifier end def eql?(other) identifier.eql?(other.identifier) end def hash identifier.hash end def satisfies?(dependency) @name == dependency.name && dependency.requirement.satisfied_by?(Gem::Version.new(@version)) end def to_lock out = String.new if platform == Gem::Platform::RUBY || platform.nil? out << " #{name} (#{version})\n" else out << " #{name} (#{version}-#{platform})\n" end dependencies.sort_by(&:to_s).uniq.each do |dep| next if dep.type == :development out << " #{dep.to_lock}\n" end out end def __materialize__ @specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name source.gemspec.tap {|s| s.source = source } else search_object = if source.is_a?(Source::Path) Dependency.new(name, version) else ruby_platform_materializes_to_ruby_platform? ? self : Dependency.new(name, version) end platform_object = Gem::Platform.new(platform) candidates = source.specs.search(search_object) same_platform_candidates = candidates.select do |spec| MatchPlatform.platforms_match?(spec.platform, platform_object) end installable_candidates = same_platform_candidates.select do |spec| !spec.is_a?(EndpointSpecification) || (spec.required_ruby_version.satisfied_by?(Gem.ruby_version) && spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)) end search = installable_candidates.last || same_platform_candidates.last search.dependencies = dependencies if search && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) search end end def respond_to?(*args) super || @specification ? @specification.respond_to?(*args) : nil end def to_s @__to_s ||= if platform == Gem::Platform::RUBY || platform.nil? "#{name} (#{version})" else "#{name} (#{version}-#{platform})" end end def identifier @__identifier ||= [name, version, platform_string] end def git_version return unless source.is_a?(Bundler::Source::Git) " #{source.revision[0..6]}" end protected def platform_string platform_string = platform.to_s platform_string == Index::RUBY ? Index::NULL : platform_string end private def to_ary nil end def method_missing(method, *args, &blk) raise "LazySpecification has not been materialized yet (calling :#{method} #{args.inspect})" unless @specification return super unless respond_to?(method) @specification.send(method, *args, &blk) end # # For backwards compatibility with existing lockfiles, if the most specific # locked platform is RUBY, we keep the previous behaviour of resolving the # best platform variant at materiliazation time. For previous bundler # versions (before 2.2.0) this was always the case (except when the lockfile # only included non-ruby platforms), but we're also keeping this behaviour # on newer bundlers unless users generate the lockfile from scratch or # explicitly add a more specific platform. # def ruby_platform_materializes_to_ruby_platform? !Bundler.most_specific_locked_platform?(Gem::Platform::RUBY) || Bundler.settings[:force_ruby_platform] end end end PKu]eo}O}O!bundler-2.2.24/lib/bundler/dsl.rbnu[# frozen_string_literal: true require_relative "dependency" require_relative "ruby_dsl" module Bundler class Dsl include RubyDsl def self.evaluate(gemfile, lockfile, unlock) builder = new builder.eval_gemfile(gemfile) builder.to_definition(lockfile, unlock) end VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules platform platforms type source install_if gemfile].freeze attr_reader :gemspecs attr_accessor :dependencies def initialize @source = nil @sources = SourceList.new @git_sources = {} @dependencies = [] @groups = [] @install_conditionals = [] @optional_groups = [] @platforms = [] @env = nil @ruby_version = nil @gemspecs = [] @gemfile = nil @gemfiles = [] add_git_sources end def eval_gemfile(gemfile, contents = nil) expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile && @gemfile.parent) original_gemfile = @gemfile @gemfile = expanded_gemfile_path @gemfiles << expanded_gemfile_path contents ||= Bundler.read_file(@gemfile.to_s) instance_eval(contents.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1) rescue Exception => e # rubocop:disable Lint/RescueException message = "There was an error " \ "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ "`#{File.basename gemfile.to_s}`: #{e.message}" raise DSLError.new(message, gemfile, e.backtrace, contents) ensure @gemfile = original_gemfile end def gemspec(opts = nil) opts ||= {} path = opts[:path] || "." glob = opts[:glob] name = opts[:name] development_group = opts[:development_group] || :development expanded_path = gemfile_root.join(path) gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).map {|g| Bundler.load_gemspec(g) }.compact gemspecs.reject! {|s| s.name != name } if name Index.sort_specs(gemspecs) specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] } case specs_by_name_and_version.size when 1 specs = specs_by_name_and_version.values.first spec = specs.find {|s| s.match_platform(Bundler.local_platform) } || specs.first @gemspecs << spec gem spec.name, :name => spec.name, :path => path, :glob => glob group(development_group) do spec.development_dependencies.each do |dep| gem dep.name, *(dep.requirement.as_list + [:type => :development]) end end when 0 raise InvalidOption, "There are no gemspecs at #{expanded_path}" else raise InvalidOption, "There are multiple gemspecs at #{expanded_path}. " \ "Please use the :name option to specify which one should be used" end end def gem(name, *args) options = args.last.is_a?(Hash) ? args.pop.dup : {} options["gemfile"] = @gemfile version = args || [">= 0"] normalize_options(name, version, options) dep = Dependency.new(name, version, options) # if there's already a dependency with this name we try to prefer one if current = @dependencies.find {|d| d.name == dep.name } deleted_dep = @dependencies.delete(current) if current.type == :development unless deleted_dep if current.requirement != dep.requirement return if dep.type == :development update_prompt = "" if File.basename(@gemfile) == Injector::INJECTED_GEMS if dep.requirements_list.include?(">= 0") && !current.requirements_list.include?(">= 0") update_prompt = ". Gem already added" else update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`" update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current.requirements_list.include?(">= 0") end end raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \ "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \ "#{update_prompt}" else Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \ "You should probably keep only one of them.\n" \ "Remove any duplicate entries and specify the gem only once.\n" \ "While it's not a problem now, it could cause errors if you change the version of one of them later." end if current.source != dep.source return if dep.type == :development raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ "You specified that #{dep.name} (#{dep.requirement}) should come from " \ "#{current.source || "an unspecified source"} and #{dep.source}\n" end end end @dependencies << dep end def source(source, *args, &blk) options = args.last.is_a?(Hash) ? args.pop.dup : {} options = normalize_hash(options) source = normalize_source(source) if options.key?("type") options["type"] = options["type"].to_s unless Plugin.source?(options["type"]) raise InvalidOption, "No plugin sources available for #{options["type"]}" end unless block_given? raise InvalidOption, "You need to pass a block to #source with :type option" end source_opts = options.merge("uri" => source) with_source(@sources.add_plugin_source(options["type"], source_opts), &blk) elsif block_given? with_source(@sources.add_rubygems_source("remotes" => source), &blk) else @sources.add_global_rubygems_remote(source) end end def git_source(name, &block) unless block_given? raise InvalidOption, "You need to pass a block to #git_source" end if valid_keys.include?(name.to_s) raise InvalidOption, "You cannot use #{name} as a git source. It " \ "is a reserved key. Reserved keys are: #{valid_keys.join(", ")}" end @git_sources[name.to_s] = block end def path(path, options = {}, &blk) source_options = normalize_hash(options).merge( "path" => Pathname.new(path), "root_path" => gemfile_root, "gemspec" => gemspecs.find {|g| g.name == options["name"] } ) source_options["global"] = true unless block_given? source = @sources.add_path_source(source_options) with_source(source, &blk) end def git(uri, options = {}, &blk) unless block_given? msg = "You can no longer specify a git source by itself. Instead, \n" \ "either use the :git option on a gem, or specify the gems that \n" \ "bundler should find in the git source by passing a block to \n" \ "the git method, like: \n\n" \ " git 'git://github.com/rails/rails.git' do\n" \ " gem 'rails'\n" \ " end" raise DeprecatedError, msg end with_source(@sources.add_git_source(normalize_hash(options).merge("uri" => uri)), &blk) end def github(repo, options = {}) raise ArgumentError, "GitHub sources require a block" unless block_given? github_uri = @git_sources["github"].call(repo) git_options = normalize_hash(options).merge("uri" => github_uri) git_source = @sources.add_git_source(git_options) with_source(git_source) { yield } end def to_definition(lockfile, unlock) check_primary_source_safety Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles) end def group(*args, &blk) options = args.last.is_a?(Hash) ? args.pop.dup : {} normalize_group_options(options, args) @groups.concat args if options["optional"] optional_groups = args - @optional_groups @optional_groups.concat optional_groups end yield ensure args.each { @groups.pop } end def install_if(*args) @install_conditionals.concat args yield ensure args.each { @install_conditionals.pop } end def platforms(*platforms) @platforms.concat platforms yield ensure platforms.each { @platforms.pop } end alias_method :platform, :platforms def env(name) old = @env @env = name yield ensure @env = old end def plugin(*args) # Pass on end def method_missing(name, *args) raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" end def check_primary_source_safety check_path_source_safety check_rubygems_source_safety end private def add_git_sources git_source(:github) do |repo_name| warn_deprecated_git_source(:github, <<-'RUBY'.strip, 'Change any "reponame" :github sources to "username/reponame".') "https://github.com/#{repo_name}.git" RUBY repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") "https://github.com/#{repo_name}.git" end git_source(:gist) do |repo_name| warn_deprecated_git_source(:gist, '"https://gist.github.com/#{repo_name}.git"') "https://gist.github.com/#{repo_name}.git" end git_source(:bitbucket) do |repo_name| warn_deprecated_git_source(:bitbucket, <<-'RUBY'.strip) user_name, repo_name = repo_name.split("/") repo_name ||= user_name "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" RUBY user_name, repo_name = repo_name.split("/") repo_name ||= user_name "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" end end def with_source(source) old_source = @source if block_given? @source = source yield end source ensure @source = old_source end def normalize_hash(opts) opts.keys.each do |k| opts[k.to_s] = opts.delete(k) unless k.is_a?(String) end opts end def valid_keys @valid_keys ||= VALID_KEYS end def normalize_options(name, version, opts) if name.is_a?(Symbol) raise GemfileError, %(You need to specify gem names as Strings. Use 'gem "#{name}"' instead) end if name =~ /\s/ raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace) end raise GemfileError, %(an empty gem name is not valid) if name.empty? normalize_hash(opts) git_names = @git_sources.keys.map(&:to_s) validate_keys("gem '#{name}'", opts, valid_keys + git_names) groups = @groups.dup opts["group"] = opts.delete("groups") || opts["group"] groups.concat Array(opts.delete("group")) groups = [:default] if groups.empty? install_if = @install_conditionals.dup install_if.concat Array(opts.delete("install_if")) install_if = install_if.reduce(true) do |memo, val| memo && (val.respond_to?(:call) ? val.call : val) end platforms = @platforms.dup opts["platforms"] = opts["platform"] || opts["platforms"] platforms.concat Array(opts.delete("platforms")) platforms.map!(&:to_sym) platforms.each do |p| next if VALID_PLATFORMS.include?(p) raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}" end # Save sources passed in a key if opts.key?("source") source = normalize_source(opts["source"]) opts["source"] = @sources.add_rubygems_source("remotes" => source) end git_name = (git_names & opts.keys).last if @git_sources[git_name] opts["git"] = @git_sources[git_name].call(opts[git_name]) end %w[git path].each do |type| next unless param = opts[type] if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/ options = opts.merge("name" => name, "version" => $1) else options = opts.dup end source = send(type, param, options) {} opts["source"] = source end opts["source"] ||= @source opts["env"] ||= @env opts["platforms"] = platforms.dup opts["group"] = groups opts["should_include"] = install_if end def normalize_group_options(opts, groups) normalize_hash(opts) groups = groups.map {|group| ":#{group}" }.join(", ") validate_keys("group #{groups}", opts, %w[optional]) opts["optional"] ||= false end def validate_keys(command, opts, valid_keys) invalid_keys = opts.keys - valid_keys git_source = opts.keys & @git_sources.keys.map(&:to_s) if opts["branch"] && !(opts["git"] || opts["github"] || git_source.any?) raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch) end return true unless invalid_keys.any? message = String.new message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} " message << if invalid_keys.size > 1 "as options for #{command}, but they are invalid." else "as an option for #{command}, but it is invalid." end message << " Valid options are: #{valid_keys.join(", ")}." message << " You may be able to resolve this by upgrading Bundler to the newest version." raise InvalidOption, message end def normalize_source(source) case source when :gemcutter, :rubygems, :rubyforge Bundler::SharedHelpers.major_deprecation 2, "The source :#{source} is deprecated because HTTP " \ "requests are insecure.\nPlease change your source to 'https://" \ "rubygems.org' if possible, or 'http://rubygems.org' if not." "http://rubygems.org" when String source else raise GemfileError, "Unknown source '#{source}'" end end def check_path_source_safety return if @sources.global_path_source.nil? msg = "You can no longer specify a path source by itself. Instead, \n" \ "either use the :path option on a gem, or specify the gems that \n" \ "bundler should find in the path source by passing a block to \n" \ "the path method, like: \n\n" \ " path 'dir/containing/rails' do\n" \ " gem 'rails'\n" \ " end\n\n" SharedHelpers.major_deprecation(2, msg.strip) end def check_rubygems_source_safety return unless @sources.aggregate_global_source? if Bundler.feature_flag.bundler_3_mode? msg = "This Gemfile contains multiple primary sources. " \ "Each source after the first must include a block to indicate which gems " \ "should come from that source" raise GemfileEvalError, msg else Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple primary sources. " \ "Using `source` more than once without a block is a security risk, and " \ "may result in installing unexpected gems. To resolve this warning, use " \ "a block to indicate which gems should come from the secondary source." end end def warn_deprecated_git_source(name, replacement, additional_message = nil) additional_message &&= " #{additional_message}" replacement = if replacement.count("\n").zero? "{|repo_name| #{replacement} }" else "do |repo_name|\n#{replacement.to_s.gsub(/^/, " ")}\n end" end Bundler::SharedHelpers.major_deprecation 3, <<-EOS The :#{name} git source is deprecated, and will be removed in the future.#{additional_message} Add this code to the top of your Gemfile to ensure it continues to work: git_source(:#{name}) #{replacement} EOS end class DSLError < GemfileError # @return [String] the description that should be presented to the user. # attr_reader :description # @return [String] the path of the dsl file that raised the exception. # attr_reader :dsl_path # @return [Exception] the backtrace of the exception raised by the # evaluation of the dsl file. # attr_reader :backtrace # @param [Exception] backtrace @see backtrace # @param [String] dsl_path @see dsl_path # def initialize(description, dsl_path, backtrace, contents = nil) @status_code = $!.respond_to?(:status_code) && $!.status_code @description = description @dsl_path = dsl_path @backtrace = backtrace @contents = contents end def status_code @status_code || super end # @return [String] the contents of the DSL that cause the exception to # be raised. # def contents @contents ||= begin dsl_path && File.exist?(dsl_path) && File.read(dsl_path) end end # The message of the exception reports the content of podspec for the # line that generated the original exception. # # @example Output # # Invalid podspec at `RestKit.podspec` - undefined method # `exclude_header_search_paths=' for # # # from spec-repos/master/RestKit/0.9.3/RestKit.podspec:36 # ------------------------------------------- # # because it would break: #import # > ns.exclude_header_search_paths = 'Code/RestKit.h' # end # ------------------------------------------- # # @return [String] the message of the exception. # def to_s @to_s ||= begin trace_line, description = parse_line_number_from_description m = String.new("\n[!] ") m << description m << ". Bundler cannot continue.\n" return m unless backtrace && dsl_path && contents trace_line = backtrace.find {|l| l.include?(dsl_path.to_s) } || trace_line return m unless trace_line line_numer = trace_line.split(":")[1].to_i - 1 return m unless line_numer lines = contents.lines.to_a indent = " # " indicator = indent.tr("#", ">") first_line = line_numer.zero? last_line = (line_numer == (lines.count - 1)) m << "\n" m << "#{indent}from #{trace_line.gsub(/:in.*$/, "")}\n" m << "#{indent}-------------------------------------------\n" m << "#{indent}#{lines[line_numer - 1]}" unless first_line m << "#{indicator}#{lines[line_numer]}" m << "#{indent}#{lines[line_numer + 1]}" unless last_line m << "\n" unless m.end_with?("\n") m << "#{indent}-------------------------------------------\n" end end private def parse_line_number_from_description description = self.description if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path.to_s}):\d+)/ trace_line = Regexp.last_match[1] description = description.sub(/\n.*\n(\.\.\.)? *\^~+$/, "").sub(/#{Regexp.quote trace_line}:\s*/, "").sub("\n", " - ") end [trace_line, description] end end def gemfile_root @gemfile ||= Bundler.default_gemfile @gemfile.dirname end end end PKu]eAss(bundler-2.2.24/lib/bundler/capistrano.rbnu[# frozen_string_literal: true require_relative "shared_helpers" Bundler::SharedHelpers.major_deprecation 2, "The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler" # Capistrano task for Bundler. # # Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and # Bundler will be activated after each new deployment. require_relative "deployment" require "capistrano/version" if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release >= Gem::Version.new("3.0") raise "For Capistrano 3.x integration, please use https://github.com/capistrano/bundler" end Capistrano::Configuration.instance(:must_exist).load do before "deploy:finalize_update", "bundle:install" Bundler::Deployment.define_task(self, :task, :except => { :no_release => true }) set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" } end PKu]V,bundler-2.2.24/lib/bundler/match_platform.rbnu[# frozen_string_literal: true require_relative "gem_helpers" module Bundler module MatchPlatform include GemHelpers def match_platform(p) MatchPlatform.platforms_match?(platform, p) end def self.platforms_match?(gemspec_platform, local_platform) return true if gemspec_platform.nil? return true if Gem::Platform::RUBY == gemspec_platform return true if local_platform == gemspec_platform gemspec_platform = Gem::Platform.new(gemspec_platform) return true if GemHelpers.generic(gemspec_platform) === local_platform return true if gemspec_platform === local_platform false end end end PKu] .XX(bundler-2.2.24/lib/bundler/definition.rbnu[# frozen_string_literal: true require_relative "lockfile_parser" module Bundler class Definition include GemHelpers attr_reader( :dependencies, :locked_deps, :locked_gems, :platforms, :requires, :ruby_version, :lockfile, :gemfiles ) # Given a gemfile and lockfile creates a Bundler definition # # @param gemfile [Pathname] Path to Gemfile # @param lockfile [Pathname,nil] Path to Gemfile.lock # @param unlock [Hash, Boolean, nil] Gems that have been requested # to be updated or true if all gems should be updated # @return [Bundler::Definition] def self.build(gemfile, lockfile, unlock) unlock ||= {} gemfile = Pathname.new(gemfile).expand_path raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file? Dsl.evaluate(gemfile, lockfile, unlock) end # # How does the new system work? # # * Load information from Gemfile and Lockfile # * Invalidate stale locked specs # * All specs from stale source are stale # * All specs that are reachable only through a stale # dependency are stale. # * If all fresh dependencies are satisfied by the locked # specs, then we can try to resolve locally. # # @param lockfile [Pathname] Path to Gemfile.lock # @param dependencies [Array(Bundler::Dependency)] array of dependencies from Gemfile # @param sources [Bundler::SourceList] # @param unlock [Hash, Boolean, nil] Gems that have been requested # to be updated or true if all gems should be updated # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version # @param optional_groups [Array(String)] A list of optional groups def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) if [true, false].include?(unlock) @unlocking_bundler = false @unlocking = unlock else @unlocking_bundler = unlock.delete(:bundler) @unlocking = unlock.any? {|_k, v| !Array(v).empty? } end @dependencies = dependencies @sources = sources @unlock = unlock @optional_groups = optional_groups @remote = false @specs = nil @ruby_version = ruby_version @gemfiles = gemfiles @lockfile = lockfile @lockfile_contents = String.new @locked_bundler_version = nil @locked_ruby_version = nil @locked_specs_incomplete_for_platform = false @new_platform = nil if lockfile && File.exist?(lockfile) @lockfile_contents = Bundler.read_file(lockfile) @locked_gems = LockfileParser.new(@lockfile_contents) @locked_platforms = @locked_gems.platforms @platforms = @locked_platforms.dup @locked_bundler_version = @locked_gems.bundler_version @locked_ruby_version = @locked_gems.ruby_version if unlock != true @locked_deps = @locked_gems.dependencies @locked_specs = SpecSet.new(@locked_gems.specs) @locked_sources = @locked_gems.sources else @unlock = {} @locked_deps = {} @locked_specs = SpecSet.new([]) @locked_sources = [] end else @unlock = {} @platforms = [] @locked_gems = nil @locked_deps = {} @locked_specs = SpecSet.new([]) @locked_sources = [] @locked_platforms = [] end locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle? if @multisource_allowed unless sources.aggregate_global_source? msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." Bundler::SharedHelpers.major_deprecation 2, msg end @sources.merged_gem_lockfile_sections!(locked_gem_sources.first) end @unlock[:sources] ||= [] @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object @ruby_version.diff(locked_ruby_version_object) end @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version) add_current_platform unless current_ruby_platform_locked? || Bundler.frozen_bundle? converge_path_sources_to_gemspec_sources @path_changes = converge_paths @source_changes = converge_sources if @unlock[:conservative] @unlock[:gems] ||= @dependencies.map(&:name) else eager_unlock = expand_dependencies(@unlock[:gems] || [], true) @unlock[:gems] = @locked_specs.for(eager_unlock, false, false, false).map(&:name) end @dependency_changes = converge_dependencies @local_changes = converge_locals @requires = compute_requires end def gem_version_promoter @gem_version_promoter ||= begin locked_specs = if unlocking? && @locked_specs.empty? && !@lockfile_contents.empty? # Definition uses an empty set of locked_specs to indicate all gems # are unlocked, but GemVersionPromoter needs the locked_specs # for conservative comparison. Bundler::SpecSet.new(@locked_gems.specs) else @locked_specs end GemVersionPromoter.new(locked_specs, @unlock[:gems]) end end def multisource_allowed? @multisource_allowed end def resolve_only_locally! @remote = false sources.local_only! resolve end def resolve_with_cache! sources.cached! resolve end def resolve_remotely! @remote = true sources.remote! resolve end # For given dependency list returns a SpecSet with Gemspec of all the required # dependencies. # 1. The method first resolves the dependencies specified in Gemfile # 2. After that it tries and fetches gemspec of resolved dependencies # # @return [Bundler::SpecSet] def specs @specs ||= add_bundler_to(resolve.materialize(requested_dependencies)) rescue GemNotFound => e # Handle yanked gem gem_name, gem_version = extract_gem_info(e) locked_gem = @locked_specs[gem_name].last raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \ "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \ "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \ "removed in order to install." end def new_specs specs - @locked_specs end def removed_specs @locked_specs - specs end def missing_specs missing = [] resolve.materialize(requested_dependencies, missing) missing end def missing_specs? missing = missing_specs return false if missing.empty? Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}" true rescue BundlerError => e @resolve = nil @specs = nil @gem_version_promoter = nil Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})" true end def requested_specs specs_for(requested_groups) end def requested_dependencies dependencies_for(requested_groups) end def current_dependencies dependencies.select do |d| d.should_include? && !d.gem_platforms(@platforms).empty? end end def specs_for(groups) groups = requested_groups if groups.empty? deps = dependencies_for(groups) add_bundler_to(resolve.materialize(expand_dependencies(deps))) end def dependencies_for(groups) groups.map!(&:to_sym) current_dependencies.reject do |d| (d.groups & groups).empty? end end # Resolve all the dependencies specified in Gemfile. It ensures that # dependencies that have been already resolved via locked file and are fresh # are reused when resolving dependencies # # @return [SpecSet] resolved dependencies def resolve @resolve ||= begin last_resolve = converge_locked_specs if Bundler.frozen_bundle? Bundler.ui.debug "Frozen, using resolution from the lockfile" last_resolve elsif !unlocking? && nothing_changed? Bundler.ui.debug("Found no changes, using resolution from the lockfile") last_resolve else # Run a resolve against the locally available gems Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote) Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) end end end def has_rubygems_remotes? sources.rubygems_sources.any? {|s| s.remotes.any? } end def spec_git_paths sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact end def groups dependencies.map(&:groups).flatten.uniq end def lock(file, preserve_unknown_sections = false) contents = to_lock # Convert to \r\n if the existing lock has them # i.e., Windows with `git config core.autocrlf=true` contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match("\r\n") if @locked_bundler_version locked_major = @locked_bundler_version.segments.first current_major = Gem::Version.create(Bundler::VERSION).segments.first if updating_major = locked_major < current_major Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \ "after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}." end end preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler)) return if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) if Bundler.frozen_bundle? Bundler.ui.error "Cannot write a changed lockfile while frozen." return end SharedHelpers.filesystem_access(file) do |p| File.open(p, "wb") {|f| f.puts(contents) } end end def locked_bundler_version if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION) new_version = Bundler::VERSION end new_version || @locked_bundler_version || Bundler::VERSION end def locked_ruby_version return unless ruby_version if @unlock[:ruby] || !@locked_ruby_version Bundler::RubyVersion.system else @locked_ruby_version end end def locked_ruby_version_object return unless @locked_ruby_version @locked_ruby_version_object ||= begin unless version = RubyVersion.from_string(@locked_ruby_version) raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \ "#{@lockfile} could not be parsed. " \ "Try running bundle update --ruby to resolve this." end version end end def to_lock require_relative "lockfile_generator" LockfileGenerator.generate(self) end def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) msg = String.new msg << "You are trying to install in deployment mode after changing\n" \ "your Gemfile. Run `bundle install` elsewhere and add the\n" \ "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control." unless explicit_flag suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any? "bundle config unset frozen" elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? "bundle config unset deployment" end msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \ "freeze \nby running `#{suggested_command}`." end added = [] deleted = [] changed = [] new_platforms = @platforms - @locked_platforms deleted_platforms = @locked_platforms - @platforms added.concat new_platforms.map {|p| "* platform: #{p}" } deleted.concat deleted_platforms.map {|p| "* platform: #{p}" } gemfile_sources = sources.lock_sources new_sources = gemfile_sources - @locked_sources deleted_sources = @locked_sources - gemfile_sources new_deps = @dependencies - @locked_deps.values deleted_deps = @locked_deps.values - @dependencies # Check if it is possible that the source is only changed thing if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?) new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) } deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) } end if @locked_sources != gemfile_sources if new_sources.any? added.concat new_sources.map {|source| "* source: #{source}" } end if deleted_sources.any? deleted.concat deleted_sources.map {|source| "* source: #{source}" } end end added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any? if deleted_deps.any? deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } end both_sources = Hash.new {|h, k| h[k] = [] } @dependencies.each {|d| both_sources[d.name][0] = d } @locked_deps.each {|name, d| both_sources[name][1] = d.source } both_sources.each do |name, (dep, lock_source)| next if lock_source.nil? || (dep && lock_source.can_lock?(dep)) gemfile_source_name = (dep && dep.source) || "no specified source" lockfile_source_name = lock_source changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`" end reason = change_reason msg << "\n\n#{reason.split(", ").map(&:capitalize).join("\n")}" unless reason.strip.empty? msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? msg << "\n" raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed? end def validate_runtime! validate_ruby! validate_platforms! end def validate_ruby! return unless ruby_version if diff = ruby_version.diff(Bundler::RubyVersion.system) problem, expected, actual = diff msg = case problem when :engine "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}" when :version "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" when :engine_version "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" when :patchlevel if !expected.is_a?(String) "The Ruby patchlevel in your Gemfile must be a string" else "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}" end end raise RubyVersionMismatch, msg end end def validate_platforms! return if current_platform_locked? raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \ "but your local platform is #{Bundler.local_platform}. " \ "Add the current platform to the lockfile with `bundle lock --add-platform #{Bundler.local_platform}` and try again." end def add_platform(platform) @new_platform ||= !@platforms.include?(platform) @platforms |= [platform] end def remove_platform(platform) return if @platforms.delete(Gem::Platform.new(platform)) raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" end def most_specific_locked_platform @platforms.min_by do |bundle_platform| platform_specificity_match(bundle_platform, local_platform) end end attr_reader :sources private :sources def nothing_changed? !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform end def unlocking? @unlocking end private def add_bundler_to(specs) unless specs["bundler"].any? bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last specs["bundler"] = bundler end specs end def precompute_source_requirements_for_indirect_dependencies? sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? end def current_ruby_platform_locked? return false unless generic_local_platform == Gem::Platform::RUBY current_platform_locked? end def current_platform_locked? @platforms.any? do |bundle_platform| MatchPlatform.platforms_match?(bundle_platform, Bundler.local_platform) end end def add_current_platform add_platform(local_platform) end def change_reason if unlocking? unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v| if v == true k.to_s else v = Array(v) "#{k}: (#{v.join(", ")})" end end.join(", ") return "bundler is unlocking #{unlock_reason}" end [ [@source_changes, "the list of sources changed"], [@dependency_changes, "the dependencies in your gemfile changed"], [@new_platform, "you added a new platform to your gemfile"], [@path_changes, "the gemspecs for path gems changed"], [@local_changes, "the gemspecs for git local gems changed"], [@locked_specs_incomplete_for_platform, "the lockfile does not have all gems needed for the current platform"], ].select(&:first).map(&:last).join(", ") end def pretty_dep(dep, source = false) SharedHelpers.pretty_dependency(dep, source) end # Check if the specs of the given source changed # according to the locked source. def specs_changed?(source) locked = @locked_sources.find {|s| s == source } !locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source) end def dependencies_for_source_changed?(source, locked_source = source) deps_for_source = @dependencies.select {|s| s.source == source } locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source } deps_for_source.uniq.sort != locked_deps_for_source.sort end def specs_for_source_changed?(source) locked_index = Index.new locked_index.use(@locked_specs.select {|s| source.can_lock?(s) }) # order here matters, since Index#== is checking source.specs.include?(locked_index) locked_index != source.specs rescue PathError, GitError => e Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})" false end # Get all locals and override their matching sources. # Return true if any of the locals changed (for example, # they point to a new revision) or depend on new specs. def converge_locals locals = [] Bundler.settings.local_overrides.map do |k, v| spec = @dependencies.find {|s| s.name == k } source = spec && spec.source if source && source.respond_to?(:local_override!) source.unlock! if @unlock[:gems].include?(spec.name) locals << [source, source.local_override!(v)] end end sources_with_changes = locals.select do |source, changed| changed || specs_changed?(source) end.map(&:first) !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty? end def converge_paths sources.path_sources.any? do |source| specs_changed?(source) end end def converge_path_source_to_gemspec_source(source) return source unless source.instance_of?(Source::Path) gemspec_source = sources.path_sources.find {|s| s.is_a?(Source::Gemspec) && s.as_path_source == source } gemspec_source || source end def converge_path_sources_to_gemspec_sources @locked_sources.map! do |source| converge_path_source_to_gemspec_source(source) end @locked_specs.each do |spec| spec.source &&= converge_path_source_to_gemspec_source(spec.source) end @locked_deps.each do |_, dep| dep.source &&= converge_path_source_to_gemspec_source(dep.source) end end def converge_sources # Replace the sources from the Gemfile with the sources from the Gemfile.lock, # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent # source in the Gemfile.lock, use the one from the Gemfile. changes = sources.replace_sources!(@locked_sources) sources.all_sources.each do |source| # If the source is unlockable and the current command allows an unlock of # the source (for example, you are doing a `bundle update ` of a git-pinned # gem), unlock it. For git sources, this means to unlock the revision, which # will cause the `ref` used to be the most recent for the branch (or master) if # an explicit `ref` is not used. if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name) source.unlock! changes = true end end changes end def converge_dependencies frozen = Bundler.frozen_bundle? (@dependencies + @locked_deps.values).each do |dep| locked_source = @locked_deps[dep.name] # This is to make sure that if bundler is installing in deployment mode and # after locked_source and sources don't match, we still use locked_source. if frozen && !locked_source.nil? && locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist? dep.source = locked_source.source elsif dep.source dep.source = sources.get(dep.source) end end changes = false # We want to know if all match, but don't want to check all entries # This means we need to return false if any dependency doesn't match # the lock or doesn't exist in the lock. @dependencies.each do |dependency| unless locked_dep = @locked_deps[dependency.name] changes = true next end # Gem::Dependency#== matches Gem::Dependency#type. As the lockfile # doesn't carry a notion of the dependency type, if you use # add_development_dependency in a gemspec that's loaded with the gemspec # directive, the lockfile dependencies and resolved dependencies end up # with a mismatch on #type. Work around that by setting the type on the # dep from the lockfile. locked_dep.instance_variable_set(:@type, dependency.type) # We already know the name matches from the hash lookup # so we only need to check the requirement now changes ||= dependency.requirement != locked_dep.requirement end changes end # Remove elements from the locked specs that are expired. This will most # commonly happen if the Gemfile has changed since the lockfile was last # generated def converge_locked_specs deps = [] # Build a list of dependencies that are the same in the Gemfile # and Gemfile.lock. If the Gemfile modified a dependency, but # the gem in the Gemfile.lock still satisfies it, this is fine # too. @dependencies.each do |dep| locked_dep = @locked_deps[dep.name] # If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep locked_dep = nil unless locked_dep == dep if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep) deps << dep elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source) @locked_specs.each do |s| @unlock[:gems] << s.name if s.source == dep.source end dep.source.unlock! if dep.source.respond_to?(:unlock!) dep.source.specs.each {|s| @unlock[:gems] << s.name } end end converged = [] @locked_specs.each do |s| # Replace the locked dependency's source with the equivalent source from the Gemfile dep = @dependencies.find {|d| s.satisfies?(d) } s.source = (dep && dep.source) || sources.get(s.source) # Don't add a spec to the list if its source is expired. For example, # if you change a Git gem to RubyGems. next if s.source.nil? next if @unlock[:sources].include?(s.source.name) # If the spec is from a path source and it doesn't exist anymore # then we unlock it. # Path sources have special logic if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec) new_specs = begin s.source.specs rescue PathError, GitError # if we won't need the source (according to the lockfile), # don't error if the path/git source isn't available next if @locked_specs. for(requested_dependencies, false, true, false). none? {|locked_spec| locked_spec.source == s.source } raise end new_spec = new_specs[s].first # If the spec is no longer in the path source, unlock it. This # commonly happens if the version changed in the gemspec next unless new_spec s.dependencies.replace(new_spec.dependencies) end converged << s end resolve = SpecSet.new(converged) @locked_specs_incomplete_for_platform = !resolve.for(expand_dependencies(requested_dependencies & deps), true, true) resolve = SpecSet.new(resolve.for(expand_dependencies(deps, true), false, false, false).reject{|s| @unlock[:gems].include?(s.name) }) diff = nil # Now, we unlock any sources that do not have anymore gems pinned to it sources.all_sources.each do |source| next unless source.respond_to?(:unlock!) unless resolve.any? {|s| s.source == source } diff ||= @locked_specs.to_a - resolve.to_a source.unlock! if diff.any? {|s| s.source == source } end end resolve end def in_locked_deps?(dep, locked_dep) # Because the lockfile can't link a dep to a specific remote, we need to # treat sources as equivalent anytime the locked dep has all the remotes # that the Gemfile dep does. locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source) end def satisfies_locked_spec?(dep) @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) } end def metadata_dependencies @metadata_dependencies ||= begin ruby_versions = ruby_version_requirements(@ruby_version) [ Dependency.new("Ruby\0", ruby_versions), Dependency.new("RubyGems\0", Gem::VERSION), ] end end def ruby_version_requirements(ruby_version) return [] unless ruby_version if ruby_version.patchlevel [ruby_version.to_gem_version_with_patchlevel] else ruby_version.versions.map do |version| requirement = Gem::Requirement.new(version) if requirement.exact? "~> #{version}.0" else requirement end end end end def expand_dependencies(dependencies, remote = false) deps = [] dependencies.each do |dep| dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name) next unless remote || dep.current_platform? target_platforms = dep.gem_platforms(remote ? @platforms : [generic_local_platform]) deps += expand_dependency_with_platforms(dep, target_platforms) end deps end def expand_dependency_with_platforms(dep, platforms) platforms.map do |p| DepProxy.get_proxy(dep, p) end end def source_requirements # Record the specs available in each gem's source, so that those # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) source_requirements = if precompute_source_requirements_for_indirect_dependencies? { :default => sources.default_source }.merge(source_map.all_requirements) else { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements) end metadata_dependencies.each do |dep| source_requirements[dep.name] = sources.metadata_source end source_requirements[:default_bundler] = source_requirements["bundler"] || sources.default_source source_requirements["bundler"] = sources.metadata_source # needs to come last to override source_requirements end def requested_groups groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] end def lockfiles_equal?(current, proposed, preserve_unknown_sections) if preserve_unknown_sections sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version) sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current) sections_to_ignore += LockfileParser::ENVIRONMENT_VERSION_SECTIONS pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/ whitespace_cleanup = /\n{2,}/ current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip end current == proposed end def extract_gem_info(error) # This method will extract the error message like "Could not find foo-1.2.3 in any of the sources" # to an array. The first element will be the gem name (e.g. foo), the second will be the version number. error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten end def compute_requires dependencies.reduce({}) do |requires, dep| next requires unless dep.should_include? requires[dep.name] = Array(dep.autorequire || dep.name).map do |file| # Allow `require: true` as an alias for `require: ` file == true ? dep.name : file end requires end end def additional_base_requirements_for_resolve return [] unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources) dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) } @locked_gems.specs.reduce({}) do |requirements, locked_spec| name = locked_spec.name dependency = dependencies_by_name[name] next requirements if @locked_gems.dependencies[name] != dependency next requirements if dependency && dependency.source.is_a?(Source::Path) dep = Gem::Dependency.new(name, ">= #{locked_spec.version}") requirements[name] = DepProxy.get_proxy(dep, locked_spec.platform) requirements end.values end def equivalent_rubygems_remotes?(source) return false unless source.is_a?(Source::Rubygems) Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes) end def source_map @source_map ||= SourceMap.new(sources, dependencies) end end end PKu]W| bundler-2.2.24/lib/bundler/ui.rbnu[# frozen_string_literal: true module Bundler module UI autoload :RGProxy, File.expand_path("ui/rg_proxy", __dir__) autoload :Shell, File.expand_path("ui/shell", __dir__) autoload :Silent, File.expand_path("ui/silent", __dir__) end end PKu]HT4bundler-2.2.24/lib/bundler/rubygems_gem_installer.rbnu[# frozen_string_literal: true require "rubygems/installer" module Bundler class RubyGemsGemInstaller < Gem::Installer def check_executable_overwrite(filename) # Bundler needs to install gems regardless of binstub overwriting end def install pre_install_checks run_pre_install_hooks spec.loaded_from = spec_file # Completely remove any previous gem files FileUtils.rm_rf gem_dir FileUtils.rm_rf spec.extension_dir FileUtils.mkdir_p gem_dir, :mode => 0o755 extract_files build_extensions write_build_info_file run_post_build_hooks generate_bin generate_plugins write_spec write_cache_file say spec.post_install_message unless spec.post_install_message.nil? run_post_install_hooks spec end def generate_plugins return unless Gem::Installer.instance_methods(false).include?(:generate_plugins) latest = Gem::Specification.stubs_for(spec.name).first return if latest && latest.version > spec.version ensure_writable_dir @plugins_dir if spec.plugins.empty? remove_plugins_for(spec, @plugins_dir) else regenerate_plugins_for(spec, @plugins_dir) end end def pre_install_checks super && validate_bundler_checksum(options[:bundler_expected_checksum]) end def build_extensions extension_cache_path = options[:bundler_extension_cache_path] return super unless extension_cache_path && extension_dir = spec.extension_dir extension_dir = Pathname.new(extension_dir) build_complete = SharedHelpers.filesystem_access(extension_cache_path.join("gem.build_complete"), :read, &:file?) if build_complete && !options[:force] SharedHelpers.filesystem_access(extension_dir.parent, &:mkpath) SharedHelpers.filesystem_access(extension_cache_path) do FileUtils.cp_r extension_cache_path, spec.extension_dir end else super if extension_dir.directory? # not made for gems without extensions SharedHelpers.filesystem_access(extension_cache_path.parent, &:mkpath) SharedHelpers.filesystem_access(extension_cache_path) do FileUtils.cp_r extension_dir, extension_cache_path end end end end private def validate_bundler_checksum(checksum) return true if Bundler.settings[:disable_checksum_validation] return true unless checksum return true unless source = @package.instance_variable_get(:@gem) return true unless source.respond_to?(:with_read_io) digest = source.with_read_io do |io| digest = SharedHelpers.digest(:SHA256).new digest << io.read(16_384) until io.eof? io.rewind send(checksum_type(checksum), digest) end unless digest == checksum raise SecurityError, <<-MESSAGE Bundler cannot continue installing #{spec.name} (#{spec.version}). The checksum for the downloaded `#{spec.full_name}.gem` does not match \ the checksum given by the server. This means the contents of the downloaded \ gem is different from what was uploaded to the server, and could be a potential security issue. To resolve this issue: 1. delete the downloaded gem located at: `#{spec.gem_dir}/#{spec.full_name}.gem` 2. run `bundle install` If you wish to continue installing the downloaded gem, and are certain it does not pose a \ security issue despite the mismatching checksum, do the following: 1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification 2. run `bundle install` (More info: The expected SHA256 checksum was #{checksum.inspect}, but the \ checksum for the downloaded gem was #{digest.inspect}.) MESSAGE end true end def checksum_type(checksum) case checksum.length when 64 then :hexdigest! when 44 then :base64digest! else raise InstallError, "The given checksum for #{spec.full_name} (#{checksum.inspect}) is not a valid SHA256 hexdigest nor base64digest" end end def hexdigest!(digest) digest.hexdigest! end def base64digest!(digest) if digest.respond_to?(:base64digest!) digest.base64digest! else [digest.digest!].pack("m0") end end end end PKu]_l__-bundler-2.2.24/lib/bundler/vendored_tmpdir.rbnu[# frozen_string_literal: true module Bundler; end require_relative "vendor/tmpdir/lib/tmpdir" PKu]60bundler-2.2.24/lib/bundler/lockfile_generator.rbnu[# frozen_string_literal: true module Bundler class LockfileGenerator attr_reader :definition attr_reader :out # @private def initialize(definition) @definition = definition @out = String.new end def self.generate(definition) new(definition).generate! end def generate! add_sources add_platforms add_dependencies add_locked_ruby_version add_bundled_with out end private def add_sources definition.send(:sources).lock_sources.each_with_index do |source, idx| out << "\n" unless idx.zero? # Add the source header out << source.to_lock # Find all specs for this source specs = definition.resolve.select {|s| source.can_lock?(s) } add_specs(specs) end end def add_specs(specs) # This needs to be sorted by full name so that # gems with the same name, but different platform # are ordered consistently specs.sort_by(&:full_name).each do |spec| next if spec.name == "bundler".freeze out << spec.to_lock end end def add_platforms add_section("PLATFORMS", definition.platforms) end def add_dependencies out << "\nDEPENDENCIES\n" handled = [] definition.dependencies.sort_by(&:to_s).each do |dep| next if handled.include?(dep.name) out << dep.to_lock handled << dep.name end end def add_locked_ruby_version return unless locked_ruby_version = definition.locked_ruby_version add_section("RUBY VERSION", locked_ruby_version.to_s) end def add_bundled_with add_section("BUNDLED WITH", definition.locked_bundler_version.to_s) end def add_section(name, value) out << "\n#{name}\n" case value when Array value.map(&:to_s).sort.each do |val| out << " #{val}\n" end when Hash value.to_a.sort_by {|k, _| k.to_s }.each do |key, val| out << " #{key}: #{val}\n" end when String out << " #{value}\n" else raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile" end end end end PKu]xsn}*}*$bundler-2.2.24/lib/bundler/plugin.rbnu[# frozen_string_literal: true require_relative "plugin/api" module Bundler module Plugin autoload :DSL, File.expand_path("plugin/dsl", __dir__) autoload :Events, File.expand_path("plugin/events", __dir__) autoload :Index, File.expand_path("plugin/index", __dir__) autoload :Installer, File.expand_path("plugin/installer", __dir__) autoload :SourceList, File.expand_path("plugin/source_list", __dir__) class MalformattedPlugin < PluginError; end class UndefinedCommandError < PluginError; end class UnknownSourceError < PluginError; end PLUGIN_FILE_NAME = "plugins.rb".freeze module_function def reset! instance_variables.each {|i| remove_instance_variable(i) } @sources = {} @commands = {} @hooks_by_event = Hash.new {|h, k| h[k] = [] } @loaded_plugin_names = [] end reset! # Installs a new plugin by the given name # # @param [Array] names the name of plugin to be installed # @param [Hash] options various parameters as described in description. # Refer to cli/plugin for available options def install(names, options) specs = Installer.new.install(names, options) save_plugins names, specs rescue PluginError => e specs_to_delete = specs.select {|k, _v| names.include?(k) && !index.commands.values.include?(k) } specs_to_delete.each_value {|spec| Bundler.rm_rf(spec.full_gem_path) } names_list = names.map {|name| "`#{name}`" }.join(", ") Bundler.ui.error "Failed to install the following plugins: #{names_list}. The underlying error was: #{e.message}.\n #{e.backtrace.join("\n ")}" end # Uninstalls plugins by the given names # # @param [Array] names the names of plugins to be uninstalled def uninstall(names, options) if names.empty? && !options[:all] Bundler.ui.error "No plugins to uninstall. Specify at least 1 plugin to uninstall.\n"\ "Use --all option to uninstall all the installed plugins." return end names = index.installed_plugins if options[:all] if names.any? names.each do |name| if index.installed?(name) Bundler.rm_rf(index.plugin_path(name)) index.unregister_plugin(name) Bundler.ui.info "Uninstalled plugin #{name}" else Bundler.ui.error "Plugin #{name} is not installed \n" end end else Bundler.ui.info "No plugins installed" end end # List installed plugins and commands # def list installed_plugins = index.installed_plugins if installed_plugins.any? output = String.new installed_plugins.each do |plugin| output << "#{plugin}\n" output << "-----\n" index.plugin_commands(plugin).each do |command| output << " #{command}\n" end output << "\n" end else output = "No plugins installed" end Bundler.ui.info output end # Evaluates the Gemfile with a limited DSL and installs the plugins # specified by plugin method # # @param [Pathname] gemfile path # @param [Proc] block that can be evaluated for (inline) Gemfile def gemfile_install(gemfile = nil, &inline) Bundler.settings.temporary(:frozen => false, :deployment => false) do builder = DSL.new if block_given? builder.instance_eval(&inline) else builder.eval_gemfile(gemfile) end builder.check_primary_source_safety definition = builder.to_definition(nil, true) return if definition.dependencies.empty? plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p } installed_specs = Installer.new.install_definition(definition) save_plugins plugins, installed_specs, builder.inferred_plugins end rescue RuntimeError => e unless e.is_a?(GemfileError) Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}" end raise end # The index object used to store the details about the plugin def index @index ||= Index.new end # The directory root for all plugin related data # # If run in an app, points to local root, in app_config_path # Otherwise, points to global root, in Bundler.user_bundle_path("plugin") def root @root ||= if SharedHelpers.in_bundle? local_root else global_root end end def local_root Bundler.app_config_path.join("plugin") end # The global directory root for all plugin related data def global_root Bundler.user_bundle_path("plugin") end # The cache directory for plugin stuffs def cache @cache ||= root.join("cache") end # To be called via the API to register to handle a command def add_command(command, cls) @commands[command] = cls end # Checks if any plugin handles the command def command?(command) !index.command_plugin(command).nil? end # To be called from Cli class to pass the command and argument to # appropriate plugin class def exec_command(command, args) raise UndefinedCommandError, "Command `#{command}` not found" unless command? command load_plugin index.command_plugin(command) unless @commands.key? command @commands[command].new.exec(command, args) end # To be called via the API to register to handle a source plugin def add_source(source, cls) @sources[source] = cls end # Checks if any plugin declares the source def source?(name) !index.source_plugin(name.to_s).nil? end # @return [Class] that handles the source. The class includes API::Source def source(name) raise UnknownSourceError, "Source #{name} not found" unless source? name load_plugin(index.source_plugin(name)) unless @sources.key? name @sources[name] end # @param [Hash] The options that are present in the lock file # @return [API::Source] the instance of the class that handles the source # type passed in locked_opts def source_from_lock(locked_opts) src = source(locked_opts["type"]) src.new(locked_opts.merge("uri" => locked_opts["remote"])) end # To be called via the API to register a hooks and corresponding block that # will be called to handle the hook def add_hook(event, &block) unless Events.defined_event?(event) raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" end @hooks_by_event[event.to_s] << block end # Runs all the hooks that are registered for the passed event # # It passes the passed arguments and block to the block registered with # the api. # # @param [String] event def hook(event, *args, &arg_blk) return unless Bundler.feature_flag.plugins? unless Events.defined_event?(event) raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" end plugins = index.hook_plugins(event) return unless plugins.any? (plugins - @loaded_plugin_names).each {|name| load_plugin(name) } @hooks_by_event[event].each {|blk| blk.call(*args, &arg_blk) } end # currently only intended for specs # # @return [String, nil] installed path def installed?(plugin) Index.new.installed?(plugin) end # Post installation processing and registering with index # # @param [Array] plugins list to be installed # @param [Hash] specs of plugins mapped to installation path (currently they # contain all the installed specs, including plugins) # @param [Array] names of inferred source plugins that can be ignored def save_plugins(plugins, specs, optional_plugins = []) plugins.each do |name| spec = specs[name] validate_plugin! Pathname.new(spec.full_gem_path) installed = register_plugin(name, spec, optional_plugins.include?(name)) Bundler.ui.info "Installed plugin #{name}" if installed end end # Checks if the gem is good to be a plugin # # At present it only checks whether it contains plugins.rb file # # @param [Pathname] plugin_path the path plugin is installed at # @raise [MalformattedPlugin] if plugins.rb file is not found def validate_plugin!(plugin_path) plugin_file = plugin_path.join(PLUGIN_FILE_NAME) raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin." unless plugin_file.file? end # Runs the plugins.rb file in an isolated namespace, records the plugin # actions it registers for and then passes the data to index to be stored. # # @param [String] name the name of the plugin # @param [Specification] spec of installed plugin # @param [Boolean] optional_plugin, removed if there is conflict with any # other plugin (used for default source plugins) # # @raise [MalformattedPlugin] if plugins.rb raises any error def register_plugin(name, spec, optional_plugin = false) commands = @commands sources = @sources hooks = @hooks_by_event @commands = {} @sources = {} @hooks_by_event = Hash.new {|h, k| h[k] = [] } load_paths = spec.load_paths Bundler.rubygems.add_to_load_path(load_paths) path = Pathname.new spec.full_gem_path begin load path.join(PLUGIN_FILE_NAME), true rescue StandardError => e raise MalformattedPlugin, "#{e.class}: #{e.message}" end if optional_plugin && @sources.keys.any? {|s| source? s } Bundler.rm_rf(path) false else index.register_plugin(name, path.to_s, load_paths, @commands.keys, @sources.keys, @hooks_by_event.keys) true end ensure @commands = commands @sources = sources @hooks_by_event = hooks end # Executes the plugins.rb file # # @param [String] name of the plugin def load_plugin(name) return unless name && !name.empty? # Need to ensure before this that plugin root where the rest of gems # are installed to be on load path to support plugin deps. Currently not # done to avoid conflicts path = index.plugin_path(name) Bundler.rubygems.add_to_load_path(index.load_paths(name)) load path.join(PLUGIN_FILE_NAME) @loaded_plugin_names << name rescue RuntimeError => e Bundler.ui.error "Failed loading plugin #{name}: #{e.message}" raise end class << self private :load_plugin, :register_plugin, :save_plugins, :validate_plugin! end end end PKu]h&(2bundler-2.2.24/lib/bundler/remote_specification.rbnu[# frozen_string_literal: true module Bundler # Represents a lazily loaded gem specification, where the full specification # is on the source server in rubygems' "quick" index. The proxy object is to # be seeded with what we're given from the source's abbreviated index - the # full specification will only be fetched when necessary. class RemoteSpecification include MatchPlatform include Comparable attr_reader :name, :version, :platform attr_writer :dependencies attr_accessor :source, :remote def initialize(name, version, platform, spec_fetcher) @name = name @version = Gem::Version.create version @platform = platform @spec_fetcher = spec_fetcher @dependencies = nil end # Needed before installs, since the arch matters then and quick # specs don't bother to include the arch in the platform string def fetch_platform @platform = _remote_specification.platform end def full_name if platform == Gem::Platform::RUBY || platform.nil? "#{@name}-#{@version}" else "#{@name}-#{@version}-#{platform}" end end # Compare this specification against another object. Using sort_obj # is compatible with Gem::Specification and other Bundler or RubyGems # objects. Otherwise, use the default Object comparison. def <=>(other) if other.respond_to?(:sort_obj) sort_obj <=> other.sort_obj else super end end # Because Rubyforge cannot be trusted to provide valid specifications # once the remote gem is downloaded, the backend specification will # be swapped out. def __swap__(spec) raise APIResponseInvalidDependenciesError unless spec.dependencies.all? {|d| d.is_a?(Gem::Dependency) } SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies) @_remote_specification = spec end # Create a delegate used for sorting. This strategy is copied from # RubyGems 2.23 and ensures that Bundler's specifications can be # compared and sorted with RubyGems' own specifications. # # @see #<=> # @see Gem::Specification#sort_obj # # @return [Array] an object you can use to compare and sort this # specification against other specifications def sort_obj [@name, @version, @platform == Gem::Platform::RUBY ? -1 : 1] end def to_s "#<#{self.class} name=#{name} version=#{version} platform=#{platform}>" end def dependencies @dependencies ||= begin deps = method_missing(:dependencies) # allow us to handle when the specs dependencies are an array of array of string # in order to delay the crash to `#__swap__` where it results in a friendlier error # see https://github.com/rubygems/bundler/issues/5797 deps = deps.map {|d| d.is_a?(Gem::Dependency) ? d : Gem::Dependency.new(*d) } deps end end def git_version return unless loaded_from && source.is_a?(Bundler::Source::Git) " #{source.revision[0..6]}" end private def to_ary nil end def _remote_specification @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @platform]) @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \ " missing from the server! Try installing with `--full-index` as a workaround.") end def method_missing(method, *args, &blk) _remote_specification.send(method, *args, &blk) end def respond_to?(method, include_all = false) super || _remote_specification.respond_to?(method, include_all) end public :respond_to? end end PKu] F-bundler-2.2.24/lib/bundler/lockfile_parser.rbnu[# frozen_string_literal: true module Bundler class LockfileParser attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version BUNDLED = "BUNDLED WITH".freeze DEPENDENCIES = "DEPENDENCIES".freeze PLATFORMS = "PLATFORMS".freeze RUBY = "RUBY VERSION".freeze GIT = "GIT".freeze GEM = "GEM".freeze PATH = "PATH".freeze PLUGIN = "PLUGIN SOURCE".freeze SPECS = " specs:".freeze OPTIONS = /^ ([a-z]+): (.*)$/i.freeze SOURCE = [GIT, GEM, PATH, PLUGIN].freeze SECTIONS_BY_VERSION_INTRODUCED = { Gem::Version.create("1.0") => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze, Gem::Version.create("1.10") => [BUNDLED].freeze, Gem::Version.create("1.12") => [RUBY].freeze, Gem::Version.create("1.13") => [PLUGIN].freeze, }.freeze KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten.freeze ENVIRONMENT_VERSION_SECTIONS = [BUNDLED, RUBY].freeze def self.sections_in_lockfile(lockfile_contents) lockfile_contents.scan(/^\w[\w ]*$/).uniq end def self.unknown_sections_in_lockfile(lockfile_contents) sections_in_lockfile(lockfile_contents) - KNOWN_SECTIONS end def self.sections_to_ignore(base_version = nil) base_version &&= base_version.release base_version ||= Gem::Version.create("1.0".dup) attributes = [] SECTIONS_BY_VERSION_INTRODUCED.each do |version, introduced| next if version <= base_version attributes += introduced end attributes end def initialize(lockfile) @platforms = [] @sources = [] @dependencies = {} @state = nil @specs = {} if lockfile.match(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \ "Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock." end lockfile.split(/(?:\r?\n)+/).each do |line| if SOURCE.include?(line) @state = :source parse_source(line) elsif line == DEPENDENCIES @state = :dependency elsif line == PLATFORMS @state = :platform elsif line == RUBY @state = :ruby elsif line == BUNDLED @state = :bundled_with elsif line =~ /^[^\s]/ @state = nil elsif @state send("parse_#{@state}", line) end end @specs = @specs.values.sort_by(&:identifier) warn_for_outdated_bundler_version rescue ArgumentError => e Bundler.ui.debug(e) raise LockfileError, "Your lockfile is unreadable. Run `rm #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` " \ "and then `bundle install` to generate a new lockfile." end def warn_for_outdated_bundler_version return unless bundler_version prerelease_text = bundler_version.prerelease? ? " --pre" : "" current_version = Gem::Version.create(Bundler::VERSION) return unless current_version < bundler_version Bundler.ui.warn "Warning: the running version of Bundler (#{current_version}) is older " \ "than the version that created the lockfile (#{bundler_version}). We suggest you to " \ "upgrade to the version that created the lockfile by running `gem install " \ "bundler:#{bundler_version}#{prerelease_text}`.\n" end private TYPES = { GIT => Bundler::Source::Git, GEM => Bundler::Source::Rubygems, PATH => Bundler::Source::Path, PLUGIN => Bundler::Plugin, }.freeze def parse_source(line) case line when SPECS case @type when PATH @current_source = TYPES[@type].from_lock(@opts) @sources << @current_source when GIT @current_source = TYPES[@type].from_lock(@opts) @sources << @current_source when GEM @opts["remotes"] = Array(@opts.delete("remote")).reverse @current_source = TYPES[@type].from_lock(@opts) @sources << @current_source when PLUGIN @current_source = Plugin.source_from_lock(@opts) @sources << @current_source end when OPTIONS value = $2 value = true if value == "true" value = false if value == "false" key = $1 if @opts[key] @opts[key] = Array(@opts[key]) @opts[key] << value else @opts[key] = value end when *SOURCE @current_source = nil @opts = {} @type = line else parse_spec(line) end end space = / / NAME_VERSION = / ^(#{space}{2}|#{space}{4}|#{space}{6})(?!#{space}) # Exactly 2, 4, or 6 spaces at the start of the line (.*?) # Name (?:#{space}\(([^-]*) # Space, followed by version (?:-(.*))?\))? # Optional platform (!)? # Optional pinned marker $ # Line end /xo.freeze def parse_dependency(line) return unless line =~ NAME_VERSION spaces = $1 return unless spaces.size == 2 name = $2 version = $3 pinned = $5 version = version.split(",").map(&:strip) if version dep = Bundler::Dependency.new(name, version) if pinned && dep.name != "bundler" spec = @specs.find {|_, v| v.name == dep.name } dep.source = spec.last.source if spec # Path sources need to know what the default name / version # to use in the case that there are no gemspecs present. A fake # gemspec is created based on the version set on the dependency # TODO: Use the version from the spec instead of from the dependency if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path) dep.source.name = name dep.source.version = $1 end end @dependencies[dep.name] = dep end def parse_spec(line) return unless line =~ NAME_VERSION spaces = $1 name = $2 version = $3 platform = $4 if spaces.size == 4 version = Gem::Version.new(version) platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY @current_spec = LazySpecification.new(name, version, platform) @current_spec.source = @current_source @specs[@current_spec.identifier] = @current_spec elsif spaces.size == 6 version = version.split(",").map(&:strip) if version dep = Gem::Dependency.new(name, version) @current_spec.dependencies << dep end end def parse_platform(line) @platforms << Gem::Platform.new($1) if line =~ /^ (.*)$/ end def parse_bundled_with(line) line = line.strip return unless Gem::Version.correct?(line) @bundler_version = Gem::Version.create(line) end def parse_ruby(line) @ruby_version = line.strip end end end PKu]x4bundler-2.2.24/lib/bundler/uri_credentials_filter.rbnu[# frozen_string_literal: true module Bundler module URICredentialsFilter module_function def credential_filtered_uri(uri_to_anonymize) return uri_to_anonymize if uri_to_anonymize.nil? uri = uri_to_anonymize.dup if uri.is_a?(String) return uri if File.exist?(uri) require_relative "vendored_uri" uri = Bundler::URI(uri) end if uri.userinfo # oauth authentication if uri.password == "x-oauth-basic" || uri.password == "x" # URI as string does not display with password if no user is set oauth_designation = uri.password uri.user = oauth_designation end uri.password = nil end return uri.to_s if uri_to_anonymize.is_a?(String) uri rescue Bundler::URI::InvalidURIError # uri is not canonical uri scheme uri end def credential_filtered_string(str_to_filter, uri) return str_to_filter if uri.nil? || str_to_filter.nil? str_with_no_credentials = str_to_filter.dup anonymous_uri_str = credential_filtered_uri(uri).to_s uri_str = uri.to_s if anonymous_uri_str != uri_str str_with_no_credentials = str_with_no_credentials.gsub(uri_str, anonymous_uri_str) end str_with_no_credentials end end end PKu]--,bundler-2.2.24/lib/bundler/shared_helpers.rbnu[# frozen_string_literal: true require "pathname" require "rbconfig" require_relative "version" require_relative "constants" require_relative "rubygems_integration" require_relative "current_ruby" module Bundler module SharedHelpers def root gemfile = find_gemfile raise GemfileNotFound, "Could not locate Gemfile" unless gemfile Pathname.new(gemfile).tap{|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path.parent end def default_gemfile gemfile = find_gemfile raise GemfileNotFound, "Could not locate Gemfile" unless gemfile Pathname.new(gemfile).tap{|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path end def default_lockfile gemfile = default_gemfile case gemfile.basename.to_s when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked")) else Pathname.new("#{gemfile}.lock") end.tap{|x| x.untaint if RUBY_VERSION < "2.7" } end def default_bundle_dir bundle_dir = find_directory(".bundle") return nil unless bundle_dir bundle_dir = Pathname.new(bundle_dir) global_bundle_dir = Bundler.user_home.join(".bundle") return nil if bundle_dir == global_bundle_dir bundle_dir end def in_bundle? find_gemfile end def chdir(dir, &blk) Bundler.rubygems.ext_lock.synchronize do Dir.chdir dir, &blk end end def pwd Bundler.rubygems.ext_lock.synchronize do Pathname.pwd end end def with_clean_git_env(&block) keys = %w[GIT_DIR GIT_WORK_TREE] old_env = keys.inject({}) do |h, k| h.update(k => ENV[k]) end keys.each {|key| ENV.delete(key) } block.call ensure keys.each {|key| ENV[key] = old_env[key] } end def set_bundle_environment set_bundle_variables set_path set_rubyopt set_rubylib end # Rescues permissions errors raised by file system operations # (ie. Errno:EACCESS, Errno::EAGAIN) and raises more friendly errors instead. # # @param path [String] the path that the action will be attempted to # @param action [Symbol, #to_s] the type of operation that will be # performed. For example: :write, :read, :exec # # @yield path # # @raise [Bundler::PermissionError] if Errno:EACCES is raised in the # given block # @raise [Bundler::TemporaryResourceError] if Errno:EAGAIN is raised in the # given block # # @example # filesystem_access("vendor/cache", :write) do # FileUtils.mkdir_p("vendor/cache") # end # # @see {Bundler::PermissionError} def filesystem_access(path, action = :write, &block) yield(path.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }) rescue Errno::EACCES raise PermissionError.new(path, action) rescue Errno::EAGAIN raise TemporaryResourceError.new(path, action) rescue Errno::EPROTO raise VirtualProtocolError.new rescue Errno::ENOSPC raise NoSpaceOnDeviceError.new(path, action) rescue *[const_get_safely(:ENOTSUP, Errno)].compact raise OperationNotSupportedError.new(path, action) rescue Errno::EEXIST, Errno::ENOENT raise rescue SystemCallError => e raise GenericSystemCallError.new(e, "There was an error accessing `#{path}`.") end def const_get_safely(constant_name, namespace) const_in_namespace = namespace.constants.include?(constant_name.to_s) || namespace.constants.include?(constant_name.to_sym) return nil unless const_in_namespace namespace.const_get(constant_name) end def major_deprecation(major_version, message, print_caller_location: false) if print_caller_location caller_location = caller_locations(2, 2).first message = "#{message} (called at #{caller_location.path}:#{caller_location.lineno})" end bundler_major_version = Bundler.bundler_major_version if bundler_major_version > major_version require_relative "errors" raise DeprecatedError, "[REMOVED] #{message}" end return unless bundler_major_version >= major_version && prints_major_deprecations? Bundler.ui.warn("[DEPRECATED] #{message}") end def print_major_deprecations! multiple_gemfiles = search_up(".") do |dir| gemfiles = gemfile_names.select {|gf| File.file? File.expand_path(gf, dir) } next if gemfiles.empty? break gemfiles.size != 1 end return unless multiple_gemfiles message = "Multiple gemfiles (gems.rb and Gemfile) detected. " \ "Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.rb.locked." Bundler.ui.warn message end def trap(signal, override = false, &block) prior = Signal.trap(signal) do block.call prior.call unless override end end def ensure_same_dependencies(spec, old_deps, new_deps) new_deps = new_deps.reject {|d| d.type == :development } old_deps = old_deps.reject {|d| d.type == :development } without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) } new_deps.map!(&without_type) old_deps.map!(&without_type) extra_deps = new_deps - old_deps return if extra_deps.empty? Bundler.ui.debug "#{spec.full_name} from #{spec.remote} has either corrupted API or lockfile dependencies" \ " (was expecting #{old_deps.map(&:to_s)}, but the real spec has #{new_deps.map(&:to_s)})" raise APIResponseMismatchError, "Downloading #{spec.full_name} revealed dependencies not in the API or the lockfile (#{extra_deps.join(", ")})." \ "\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem." end def pretty_dependency(dep, print_source = false) msg = String.new(dep.name) msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default if dep.is_a?(Bundler::Dependency) platform_string = dep.platforms.join(", ") msg << " " << platform_string if !platform_string.empty? && platform_string != Gem::Platform::RUBY end msg << " from the `#{dep.source}` source" if print_source && dep.source msg end def md5_available? return @md5_available if defined?(@md5_available) @md5_available = begin require "openssl" ::OpenSSL::Digest.digest("MD5", "") true rescue LoadError true rescue ::OpenSSL::Digest::DigestError false end end def digest(name) require "digest" Digest(name) end def write_to_gemfile(gemfile_path, contents) filesystem_access(gemfile_path) {|g| File.open(g, "w") {|file| file.puts contents } } end private def validate_bundle_path path_separator = Bundler.rubygems.path_separator return unless Bundler.bundle_path.to_s.split(path_separator).size > 1 message = "Your bundle path contains text matching #{path_separator.inspect}, " \ "which is the path separator for your system. Bundler cannot " \ "function correctly when the Bundle path contains the " \ "system's PATH separator. Please change your " \ "bundle path to not match #{path_separator.inspect}." \ "\nYour current bundle path is '#{Bundler.bundle_path}'." raise Bundler::PathError, message end def find_gemfile given = ENV["BUNDLE_GEMFILE"] return given if given && !given.empty? find_file(*gemfile_names) end def gemfile_names ["gems.rb", "Gemfile"] end def find_file(*names) search_up(*names) do |filename| return filename if File.file?(filename) end end def find_directory(*names) search_up(*names) do |dirname| return dirname if File.directory?(dirname) end end def search_up(*names) previous = nil current = File.expand_path(SharedHelpers.pwd).tap{|x| x.untaint if RUBY_VERSION < "2.7" } until !File.directory?(current) || current == previous if ENV["BUNDLE_SPEC_RUN"] # avoid stepping above the tmp directory when testing gemspec = if ENV["GEM_COMMAND"] # for Ruby Core "lib/bundler/bundler.gemspec" else "bundler.gemspec" end # avoid stepping above the tmp directory when testing return nil if File.file?(File.join(current, gemspec)) end names.each do |name| filename = File.join(current, name) yield filename end previous = current current = File.expand_path("..", current) end end def set_env(key, value) raise ArgumentError, "new key #{key}" unless EnvironmentPreserver::BUNDLER_KEYS.include?(key) orig_key = "#{EnvironmentPreserver::BUNDLER_PREFIX}#{key}" orig = ENV[key] orig ||= EnvironmentPreserver::INTENTIONALLY_NIL ENV[orig_key] ||= orig ENV[key] = value end public :set_env def set_bundle_variables # bundler exe & lib folders have same root folder, typical gem installation exe_file = File.expand_path("../../../exe/bundle", __FILE__) # for Ruby core repository testing exe_file = File.expand_path("../../../libexec/bundle", __FILE__) unless File.exist?(exe_file) # bundler is a default gem, exe path is separate exe_file = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file) Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION end def set_path validate_bundle_path paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR) paths.unshift "#{Bundler.bundle_path}/bin" Bundler::SharedHelpers.set_env "PATH", paths.uniq.join(File::PATH_SEPARATOR) end def set_rubyopt rubyopt = [ENV["RUBYOPT"]].compact setup_require = "-r#{File.expand_path("setup", __dir__)}" return if !rubyopt.empty? && rubyopt.first =~ /#{setup_require}/ rubyopt.unshift setup_require Bundler::SharedHelpers.set_env "RUBYOPT", rubyopt.join(" ") end def set_rubylib rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR) rubylib.unshift bundler_ruby_lib unless RbConfig::CONFIG["rubylibdir"] == bundler_ruby_lib Bundler::SharedHelpers.set_env "RUBYLIB", rubylib.uniq.join(File::PATH_SEPARATOR) end def bundler_ruby_lib resolve_path File.expand_path("../..", __FILE__) end def clean_load_path bundler_lib = bundler_ruby_lib loaded_gem_paths = Bundler.rubygems.loaded_gem_paths $LOAD_PATH.reject! do |p| next if resolve_path(p).start_with?(bundler_lib) loaded_gem_paths.delete(p) end $LOAD_PATH.uniq! end def resolve_path(path) expanded = File.expand_path(path) return expanded unless File.respond_to?(:realpath) && File.exist?(expanded) File.realpath(expanded) end def prints_major_deprecations? require_relative "../bundler" return false if Bundler.settings[:silence_deprecations] require_relative "deprecate" return false if Bundler::Deprecate.skip true end extend self end end PKu]-)&bundler-2.2.24/lib/bundler/ruby_dsl.rbnu[# frozen_string_literal: true module Bundler module RubyDsl def ruby(*ruby_version) options = ruby_version.last.is_a?(Hash) ? ruby_version.pop : {} ruby_version.flatten! raise GemfileError, "Please define :engine_version" if options[:engine] && options[:engine_version].nil? raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil? if options[:engine] == "ruby" && options[:engine_version] && ruby_version != Array(options[:engine_version]) raise GemfileEvalError, "ruby_version must match the :engine_version for MRI" end @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version]) end end end PKu]zrr!bundler-2.2.24/lib/bundler/cli.rbnu[# frozen_string_literal: true require_relative "vendored_thor" module Bundler class CLI < Thor require_relative "cli/common" package_name "Bundler" AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze PARSEABLE_COMMANDS = %w[check config help exec platform show version].freeze COMMAND_ALIASES = { "check" => "c", "install" => "i", "plugin" => "", "list" => "ls", "exec" => ["e", "ex", "exe"], "cache" => ["package", "pack"], "version" => ["-v", "--version"], }.freeze def self.start(*) super ensure Bundler::SharedHelpers.print_major_deprecations! end def self.dispatch(*) super do |i| i.send(:print_command) i.send(:warn_on_outdated_bundler) end end def self.all_aliases @all_aliases ||= begin command_aliases = {} COMMAND_ALIASES.each do |name, aliases| Array(aliases).each do |one_alias| command_aliases[one_alias] = name end end command_aliases end end def self.aliases_for(command_name) COMMAND_ALIASES.select {|k, _| k == command_name }.invert end def initialize(*args) super custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile] if custom_gemfile && !custom_gemfile.empty? Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile) Bundler.reset_settings_and_root! end Bundler.settings.set_command_option_if_given :retry, options[:retry] current_cmd = args.last[:current_command].name auto_install if AUTO_INSTALL_CMDS.include?(current_cmd) rescue UnknownArgumentError => e raise InvalidOption, e.message ensure self.options ||= {} unprinted_warnings = Bundler.ui.unprinted_warnings Bundler.ui = UI::Shell.new(options) Bundler.ui.level = "debug" if options["verbose"] unprinted_warnings.each {|w| Bundler.ui.warn(w) } if ENV["RUBYGEMS_GEMDEPS"] && !ENV["RUBYGEMS_GEMDEPS"].empty? Bundler.ui.warn( "The RUBYGEMS_GEMDEPS environment variable is set. This enables RubyGems' " \ "experimental Gemfile mode, which may conflict with Bundler and cause unexpected errors. " \ "To remove this warning, unset RUBYGEMS_GEMDEPS.", :wrap => true ) end end check_unknown_options!(:except => [:config, :exec]) stop_on_unknown_option! :exec desc "cli_help", "Prints a summary of bundler commands", :hide => true def cli_help version Bundler.ui.info "\n" primary_commands = ["install", "update", "cache", "exec", "config", "help"] list = self.class.printable_commands(true) by_name = list.group_by {|name, _message| name.match(/^bundle (\w+)/)[1] } utilities = by_name.keys.sort - primary_commands primary_commands.map! {|name| (by_name[name] || raise("no primary command #{name}")).first } utilities.map! {|name| by_name[name].first } shell.say "Bundler commands:\n\n" shell.say " Primary commands:\n" shell.print_table(primary_commands, :indent => 4, :truncate => true) shell.say shell.say " Utilities:\n" shell.print_table(utilities, :indent => 4, :truncate => true) shell.say self.class.send(:class_options_help, shell) end default_task(Bundler.feature_flag.default_cli_command) class_option "no-color", :type => :boolean, :desc => "Disable colorization in output" class_option "retry", :type => :numeric, :aliases => "-r", :banner => "NUM", :desc => "Specify the number of times you wish to attempt network commands" class_option "verbose", :type => :boolean, :desc => "Enable verbose output mode", :aliases => "-V" def help(cli = nil) case cli when "gemfile" then command = "gemfile" when nil then command = "bundle" else command = "bundle-#{cli}" end man_path = File.expand_path("man", __dir__) man_pages = Hash[Dir.glob(File.join(man_path, "**", "*")).grep(/.*\.\d*\Z/).collect do |f| [File.basename(f, ".*"), f] end] if man_pages.include?(command) man_page = man_pages[command] if Bundler.which("man") && man_path !~ %r{^file:/.+!/META-INF/jruby.home/.+} Kernel.exec "man #{man_page}" else puts File.read("#{man_path}/#{File.basename(man_page)}.ronn") end elsif command_path = Bundler.which("bundler-#{cli}") Kernel.exec(command_path, "--help") else super end end def self.handle_no_command_error(command, has_namespace = $thor_runner) if Bundler.feature_flag.plugins? && Bundler::Plugin.command?(command) return Bundler::Plugin.exec_command(command, ARGV[1..-1]) end return super unless command_path = Bundler.which("bundler-#{command}") Kernel.exec(command_path, *ARGV[1..-1]) end desc "init [OPTIONS]", "Generates a Gemfile into the current working directory" long_desc <<-D Init generates a default Gemfile in the current working directory. When adding a Gemfile to a gem with a gemspec, the --gemspec option will automatically add each dependency listed in the gemspec file to the newly created Gemfile. D method_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile" def init require_relative "cli/init" Init.new(options.dup).run end desc "check [OPTIONS]", "Checks if the dependencies listed in Gemfile are satisfied by currently installed gems" long_desc <<-D Check searches the local machine for each of the gems requested in the Gemfile. If all gems are found, Bundler prints a success message and exits with a status of 0. If not, the first missing gem is listed and Bundler exits status 1. D method_option "dry-run", :type => :boolean, :default => false, :banner => "Lock the Gemfile" method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "path", :type => :string, :banner => "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" def check remembered_flag_deprecation("path") require_relative "cli/check" Check.new(options).run end map aliases_for("check") desc "remove [GEM [GEM ...]]", "Removes gems from the Gemfile" long_desc <<-D Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If the gem is not found, Bundler prints a error message and if gem could not be removed due to any reason Bundler will display a warning. D method_option "install", :type => :boolean, :banner => "Runs 'bundle install' after removing the gems from the Gemfile" def remove(*gems) require_relative "cli/remove" Remove.new(gems, options).run end desc "install [OPTIONS]", "Install the current environment to the system" long_desc <<-D Install will install all of the gems in the current bundle, making them available for use. In a freshly checked out repository, this command will give you the same gem versions as the last person who updated the Gemfile and ran `bundle update`. Passing [DIR] to install (e.g. vendor) will cause the unpacked gems to be installed into the [DIR] directory rather than into system gems. If the bundle has already been installed, bundler will tell you so and then exit. D method_option "binstubs", :type => :string, :lazy_default => "bin", :banner => "Generate bin stubs for bundled gems to ./bin" method_option "clean", :type => :boolean, :banner => "Run bundle clean automatically after install" method_option "deployment", :type => :boolean, :banner => "Install using defaults tuned for deployment environments" method_option "frozen", :type => :boolean, :banner => "Do not allow the Gemfile.lock to be updated after this install" method_option "full-index", :type => :boolean, :banner => "Fall back to using the single-file index of all gems" method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "jobs", :aliases => "-j", :type => :numeric, :banner => "Specify the number of jobs to run in parallel" method_option "local", :type => :boolean, :banner => "Do not attempt to fetch gems remotely and use the gem cache instead" method_option "no-cache", :type => :boolean, :banner => "Don't update the existing gem cache." method_option "redownload", :type => :boolean, :aliases => "--force", :banner => "Force downloading every gem." method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache." method_option "path", :type => :string, :banner => "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." method_option "shebang", :type => :string, :banner => "Specify a different shebang executable name than the default (usually 'ruby')" method_option "standalone", :type => :array, :lazy_default => [], :banner => "Make a bundle that can work without the Bundler runtime" method_option "system", :type => :boolean, :banner => "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application" method_option "trust-policy", :alias => "P", :type => :string, :banner => "Gem trust policy (like gem install -P). Must be one of " + Bundler.rubygems.security_policy_keys.join("|") method_option "without", :type => :array, :banner => "Exclude gems that are part of the specified named group." method_option "with", :type => :array, :banner => "Include gems that are part of the specified named group." def install SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force") %w[clean deployment frozen no-prune path shebang system without with].each do |option| remembered_flag_deprecation(option) end remembered_negative_flag_deprecation("no-deployment") require_relative "cli/install" Bundler.settings.temporary(:no_install => false) do Install.new(options.dup).run end end map aliases_for("install") desc "update [OPTIONS]", "Update the current environment" long_desc <<-D Update will install the newest versions of the gems listed in the Gemfile. Use update when you have changed the Gemfile, or if you want to get the newest possible versions of the gems in the bundle. D method_option "full-index", :type => :boolean, :banner => "Fall back to using the single-file index of all gems" method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "group", :aliases => "-g", :type => :array, :banner => "Update a specific group" method_option "jobs", :aliases => "-j", :type => :numeric, :banner => "Specify the number of jobs to run in parallel" method_option "local", :type => :boolean, :banner => "Do not attempt to fetch gems remotely and use the gem cache instead" method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." method_option "source", :type => :array, :banner => "Update a specific source (and all gems associated with it)" method_option "redownload", :type => :boolean, :aliases => "--force", :banner => "Force downloading every gem." method_option "ruby", :type => :boolean, :banner => "Update ruby specified in Gemfile.lock" method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner => "Update the locked version of bundler" method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version" method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version" method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" method_option "strict", :type => :boolean, :banner => "Do not allow any gem to be updated past latest --patch | --minor | --major" method_option "conservative", :type => :boolean, :banner => "Use bundle install conservative update behavior and do not allow shared dependencies to be updated." method_option "all", :type => :boolean, :banner => "Update everything." def update(*gems) SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force") require_relative "cli/update" Bundler.settings.temporary(:no_install => false) do Update.new(options, gems).run end end desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" long_desc <<-D Show lists the names and versions of all gems that are required by your Gemfile. Calling show with [GEM] will list the exact location of that gem on your machine. D method_option "paths", :type => :boolean, :banner => "List the paths of all gems that are required by your Gemfile." method_option "outdated", :type => :boolean, :banner => "Show verbose output including whether gems are outdated." def show(gem_name = nil) SharedHelpers.major_deprecation(2, "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement") if ARGV.include?("--outdated") require_relative "cli/show" Show.new(options, gem_name).run end desc "list", "List all gems in the bundle" method_option "name-only", :type => :boolean, :banner => "print only the gem names" method_option "only-group", :type => :array, :default => [], :banner => "print gems from a given set of groups" method_option "without-group", :type => :array, :default => [], :banner => "print all gems except from a given set of groups" method_option "paths", :type => :boolean, :banner => "print the path to each gem in the bundle" def list require_relative "cli/list" List.new(options).run end map aliases_for("list") desc "info GEM [OPTIONS]", "Show information for the given gem" method_option "path", :type => :boolean, :banner => "Print full path to gem" def info(gem_name) require_relative "cli/info" Info.new(options, gem_name).run end desc "binstubs GEM [OPTIONS]", "Install the binstubs of the listed gem" long_desc <<-D Generate binstubs for executables in [GEM]. Binstubs are put into bin, or the --binstubs directory if one has been set. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems. D method_option "force", :type => :boolean, :default => false, :banner => "Overwrite existing binstubs if they exist" method_option "path", :type => :string, :lazy_default => "bin", :banner => "Binstub destination directory (default bin)" method_option "shebang", :type => :string, :banner => "Specify a different shebang executable name than the default (usually 'ruby')" method_option "standalone", :type => :boolean, :banner => "Make binstubs that can work without the Bundler runtime" method_option "all", :type => :boolean, :banner => "Install binstubs for all gems" method_option "all-platforms", :type => :boolean, :default => false, :banner => "Install binstubs for all platforms" def binstubs(*gems) require_relative "cli/binstubs" Binstubs.new(options, gems).run end desc "add GEM VERSION", "Add gem to Gemfile and run bundle install" long_desc <<-D Adds the specified gem to Gemfile (if valid) and run 'bundle install' in one step. D method_option "version", :aliases => "-v", :type => :string method_option "group", :aliases => "-g", :type => :string method_option "source", :aliases => "-s", :type => :string method_option "git", :type => :string method_option "branch", :type => :string method_option "skip-install", :type => :boolean, :banner => "Adds gem to the Gemfile but does not install it" method_option "optimistic", :type => :boolean, :banner => "Adds optimistic declaration of version to gem" method_option "strict", :type => :boolean, :banner => "Adds strict declaration of version to gem" def add(*gems) require_relative "cli/add" Add.new(options.dup, gems).run end desc "outdated GEM [OPTIONS]", "List installed gems with newer versions available" long_desc <<-D Outdated lists the names and versions of gems that have a newer version available in the given source. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems. Prerelease gems are ignored by default. If your gems are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. For more information on patch level options (--major, --minor, --patch, --update-strict) see documentation on the same options on the update command. D method_option "group", :type => :string, :banner => "List gems from a specific group" method_option "groups", :type => :boolean, :banner => "List gems organized by groups" method_option "local", :type => :boolean, :banner => "Do not attempt to fetch gems remotely and use the gem cache instead" method_option "pre", :type => :boolean, :banner => "Check for newer pre-release gems" method_option "source", :type => :array, :banner => "Check against a specific source" strict_is_update = Bundler.feature_flag.forget_cli_options? method_option "filter-strict", :type => :boolean, :aliases => strict_is_update ? [] : %w[--strict], :banner => "Only list newer versions allowed by your Gemfile requirements" method_option "update-strict", :type => :boolean, :aliases => strict_is_update ? %w[--strict] : [], :banner => "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major" method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version" method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version" method_option "filter-major", :type => :boolean, :banner => "Only list major newer versions" method_option "filter-minor", :type => :boolean, :banner => "Only list minor newer versions" method_option "filter-patch", :type => :boolean, :banner => "Only list patch newer versions" method_option "parseable", :aliases => "--porcelain", :type => :boolean, :banner => "Use minimal formatting for more parseable output" method_option "only-explicit", :type => :boolean, :banner => "Only list gems specified in your Gemfile, not their dependencies" def outdated(*gems) require_relative "cli/outdated" Outdated.new(options, gems).run end desc "fund [OPTIONS]", "Lists information about gems seeking funding assistance" method_option "group", :aliases => "-g", :type => :array, :banner => "Fetch funding information for a specific group" def fund require_relative "cli/fund" Fund.new(options).run end desc "cache [OPTIONS]", "Locks and then caches all of the gems into vendor/cache" method_option "all", :type => :boolean, :default => Bundler.feature_flag.cache_all?, :banner => "Include all sources (including path and git)." method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one" method_option "cache-path", :type => :string, :banner => "Specify a different cache path than the default (vendor/cache)." method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "no-install", :type => :boolean, :banner => "Don't install the gems, only update the cache." method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache." method_option "path", :type => :string, :banner => "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." method_option "frozen", :type => :boolean, :banner => "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install" long_desc <<-D The cache command will copy the .gem files for every gem in the bundle into the directory ./vendor/cache. If you then check that directory into your source control repository, others who check out your source will be able to install the bundle without having to download any additional gems. D def cache SharedHelpers.major_deprecation 2, "The `--all` flag is deprecated because it relies on being " \ "remembered across bundler invocations, which bundler will no longer " \ "do in future versions. Instead please use `bundle config set cache_all true`, " \ "and stop using this flag" if ARGV.include?("--all") require_relative "cli/cache" Cache.new(options).run end map aliases_for("cache") desc "exec [OPTIONS]", "Run the command in context of the bundle" method_option :keep_file_descriptors, :type => :boolean, :default => false method_option :gemfile, :type => :string, :required => false long_desc <<-D Exec runs a command, providing it access to the gems in the bundle. While using bundle exec you can require and call the bundled gems as if they were installed into the system wide RubyGems repository. D def exec(*args) require_relative "cli/exec" Exec.new(options, args).run end map aliases_for("exec") desc "config NAME [VALUE]", "Retrieve or set a configuration value" long_desc <<-D Retrieves or sets a configuration value. If only one parameter is provided, retrieve the value. If two parameters are provided, replace the existing value with the newly provided one. By default, setting a configuration value sets it for all projects on the machine. If a global setting is superseded by local configuration, this command will show the current value, as well as any superseded values and where they were specified. D require_relative "cli/config" subcommand "config", Config desc "open GEM", "Opens the source directory of the given bundled gem" def open(name) require_relative "cli/open" Open.new(options, name).run end unless Bundler.feature_flag.bundler_3_mode? desc "console [GROUP]", "Opens an IRB session with the bundle pre-loaded" def console(group = nil) require_relative "cli/console" Console.new(options, group).run end end desc "version", "Prints the bundler's version information" def version cli_help = current_command.name == "cli_help" if cli_help || ARGV.include?("version") build_info = " (#{BuildMetadata.built_at} commit #{BuildMetadata.git_commit_sha})" end if !cli_help && Bundler.feature_flag.print_only_version_number? Bundler.ui.info "#{Bundler::VERSION}#{build_info}" else Bundler.ui.info "Bundler version #{Bundler::VERSION}#{build_info}" end end map aliases_for("version") desc "licenses", "Prints the license of all gems in the bundle" def licenses Bundler.load.specs.sort_by {|s| s.license.to_s }.reverse_each do |s| gem_name = s.name license = s.license || s.licenses if license.empty? Bundler.ui.warn "#{gem_name}: Unknown" else Bundler.ui.info "#{gem_name}: #{license}" end end end unless Bundler.feature_flag.bundler_3_mode? desc "viz [OPTIONS]", "Generates a visual dependency graph", :hide => true long_desc <<-D Viz generates a PNG file of the current Gemfile as a dependency graph. Viz requires the ruby-graphviz gem (and its dependencies). The associated gems must also be installed via 'bundle install'. D method_option :file, :type => :string, :default => "gem_graph", :aliases => "-f", :desc => "The name to use for the generated file. see format option" method_option :format, :type => :string, :default => "png", :aliases => "-F", :desc => "This is output format option. Supported format is png, jpg, svg, dot ..." method_option :requirements, :type => :boolean, :default => false, :aliases => "-R", :desc => "Set to show the version of each required dependency." method_option :version, :type => :boolean, :default => false, :aliases => "-v", :desc => "Set to show each gem version." method_option :without, :type => :array, :default => [], :aliases => "-W", :banner => "GROUP[ GROUP...]", :desc => "Exclude gems that are part of the specified named group." def viz SharedHelpers.major_deprecation 2, "The `viz` command has been moved to the `bundle-viz` gem, see https://github.com/bundler/bundler-viz" require_relative "cli/viz" Viz.new(options.dup).run end end old_gem = instance_method(:gem) desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem" method_option :exe, :type => :boolean, :default => false, :aliases => ["--bin", "-b"], :desc => "Generate a binary executable for your library." method_option :coc, :type => :boolean, :desc => "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`." method_option :edit, :type => :string, :aliases => "-e", :required => false, :banner => "EDITOR", :lazy_default => [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, :desc => "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)" method_option :ext, :type => :boolean, :default => false, :desc => "Generate the boilerplate for C extension code" method_option :git, :type => :boolean, :default => true, :desc => "Initialize a git repo inside your library." method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." method_option :rubocop, :type => :boolean, :desc => "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`." method_option :changelog, :type => :boolean, :desc => "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`." method_option :test, :type => :string, :lazy_default => Bundler.settings["gem.test"] || "", :aliases => "-t", :banner => "Use the specified test framework for your library", :desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`." method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "", :desc => "Generate CI configuration, either GitHub Actions, Travis CI, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|travis|gitlab|circle)`" method_option :github_username, :type => :string, :default => Bundler.settings["gem.github_username"], :banner => "Set your username on GitHub", :desc => "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username `." def gem(name) end commands["gem"].tap do |gem_command| def gem_command.run(instance, args = []) arity = 1 # name require_relative "cli/gem" cmd_args = args + [instance] cmd_args.unshift(instance.options) cmd = begin Gem.new(*cmd_args) rescue ArgumentError => e instance.class.handle_argument_error(self, e, args, arity) end cmd.run end end undef_method(:gem) define_method(:gem, old_gem) private :gem def self.source_root File.expand_path(File.join(File.dirname(__FILE__), "templates")) end desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", :hide => true method_option "dry-run", :type => :boolean, :default => false, :banner => "Only print out changes, do not clean gems" method_option "force", :type => :boolean, :default => false, :banner => "Forces clean even if --path is not set" def clean require_relative "cli/clean" Clean.new(options.dup).run end desc "platform [OPTIONS]", "Displays platform compatibility information" method_option "ruby", :type => :boolean, :default => false, :banner => "only display ruby related platform information" def platform require_relative "cli/platform" Platform.new(options).run end desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", :hide => true method_option "source", :type => :string, :banner => "Install gem from the given source" method_option "group", :type => :string, :banner => "Install gem into a bundler group" def inject(name, version) SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command" require_relative "cli/inject" Inject.new(options.dup, name, version).run end desc "lock", "Creates a lockfile without installing" method_option "update", :type => :array, :lazy_default => true, :banner => "ignore the existing lockfile, update all gems by default, or update list of given gems" method_option "local", :type => :boolean, :default => false, :banner => "do not attempt to fetch remote gemspecs and use the local gem cache only" method_option "print", :type => :boolean, :default => false, :banner => "print the lockfile to STDOUT instead of writing to the file system" method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "lockfile", :type => :string, :default => nil, :banner => "the path the lockfile should be written to" method_option "full-index", :type => :boolean, :default => false, :banner => "Fall back to using the single-file index of all gems" method_option "add-platform", :type => :array, :default => [], :banner => "Add a new platform to the lockfile" method_option "remove-platform", :type => :array, :default => [], :banner => "Remove a platform from the lockfile" method_option "patch", :type => :boolean, :banner => "If updating, prefer updating only to next patch version" method_option "minor", :type => :boolean, :banner => "If updating, prefer updating only to next minor version" method_option "major", :type => :boolean, :banner => "If updating, prefer updating to next major version (default)" method_option "strict", :type => :boolean, :banner => "If updating, do not allow any gem to be updated past latest --patch | --minor | --major" method_option "conservative", :type => :boolean, :banner => "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated" def lock require_relative "cli/lock" Lock.new(options).run end desc "env", "Print information about the environment Bundler is running under" def env Env.write($stdout) end desc "doctor [OPTIONS]", "Checks the bundle for common problems" long_desc <<-D Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If missing dependencies are detected, Bundler prints them and exits status 1. Otherwise, Bundler prints a success message and exits with a status of 0. D method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." def doctor require_relative "cli/doctor" Doctor.new(options).run end desc "issue", "Learn how to report an issue in Bundler" def issue require_relative "cli/issue" Issue.new.run end desc "pristine [GEMS...]", "Restores installed gems to pristine condition" long_desc <<-D Restores installed gems to pristine condition from files located in the gem cache. Gems installed from a git repository will be issued `git checkout --force`. D def pristine(*gems) require_relative "cli/pristine" Pristine.new(gems).run end if Bundler.feature_flag.plugins? require_relative "cli/plugin" desc "plugin", "Manage the bundler plugins" subcommand "plugin", Plugin end # Reformat the arguments passed to bundle that include a --help flag # into the corresponding `bundle help #{command}` call def self.reformatted_help_args(args) bundler_commands = (COMMAND_ALIASES.keys + COMMAND_ALIASES.values).flatten help_flags = %w[--help -h] exec_commands = ["exec"] + COMMAND_ALIASES["exec"] help_used = args.index {|a| help_flags.include? a } exec_used = args.index {|a| exec_commands.include? a } command = args.find {|a| bundler_commands.include? a } command = all_aliases[command] if all_aliases[command] if exec_used && help_used if exec_used + help_used == 1 %w[help exec] else args end elsif help_used args = args.dup args.delete_at(help_used) ["help", command || args].flatten.compact else args end end private # Automatically invoke `bundle install` and resume if # Bundler.settings[:auto_install] exists. This is set through config cmd # `bundle config set --global auto_install 1`. # # Note that this method `nil`s out the global Definition object, so it # should be called first, before you instantiate anything like an # `Installer` that'll keep a reference to the old one instead. def auto_install return unless Bundler.settings[:auto_install] begin Bundler.definition.specs rescue GemNotFound Bundler.ui.info "Automatically installing missing gems." Bundler.reset! invoke :install, [] Bundler.reset! end end def current_command _, _, config = @_initializer config[:current_command] end def print_command return unless Bundler.ui.debug? cmd = current_command command_name = cmd.name return if PARSEABLE_COMMANDS.include?(command_name) command = ["bundle", command_name] + args options_to_print = options.dup options_to_print.delete_if do |k, v| next unless o = cmd.options[k] o.default == v end command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip command.reject!(&:empty?) Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler::VERSION}" end def warn_on_outdated_bundler return if Bundler.settings[:disable_version_check] command_name = current_command.name return if PARSEABLE_COMMANDS.include?(command_name) return unless SharedHelpers.md5_available? latest = Fetcher::CompactIndex. new(nil, Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org")), nil). send(:compact_index_client). instance_variable_get(:@cache). dependencies("bundler"). map {|d| Gem::Version.new(d.first) }. max return unless latest current = Gem::Version.new(VERSION) return if current >= latest latest_installed = Bundler.rubygems.find_name("bundler").map(&:version).max installation = "To install the latest version, run `gem install bundler#{" --pre" if latest.prerelease?}`" if latest_installed && latest_installed > current suggestion = "To update to the most recent installed version (#{latest_installed}), run `bundle update --bundler`" suggestion = "#{installation}\n#{suggestion}" if latest_installed < latest else suggestion = installation end Bundler.ui.warn "The latest bundler is #{latest}, but you are currently running #{current}.\n#{suggestion}" rescue RuntimeError nil end def remembered_negative_flag_deprecation(name) positive_name = name.gsub(/\Ano-/, "") option = current_command.options[positive_name] flag_name = "--no-" + option.switch_name.gsub(/\A--/, "") flag_deprecation(positive_name, flag_name, option) end def remembered_flag_deprecation(name) option = current_command.options[name] flag_name = option.switch_name flag_deprecation(name, flag_name, option) end def flag_deprecation(name, flag_name, option) name_index = ARGV.find {|arg| flag_name == arg.split("=")[0] } return unless name_index value = options[name] value = value.join(" ").to_s if option.type == :array Bundler::SharedHelpers.major_deprecation 2, "The `#{flag_name}` flag is deprecated because it relies on being " \ "remembered across bundler invocations, which bundler will no longer " \ "do in future versions. Instead please use `bundle config set --local #{name.tr("-", "_")} " \ "'#{value}'`, and stop using this flag" end end end PKu]!6n n -bundler-2.2.24/lib/bundler/yaml_serializer.rbnu[# frozen_string_literal: true module Bundler # A stub yaml serializer that can handle only hashes and strings (as of now). module YAMLSerializer module_function def dump(hash) yaml = String.new("---") yaml << dump_hash(hash) end def dump_hash(hash) yaml = String.new("\n") hash.each do |k, v| yaml << k << ":" if v.is_a?(Hash) yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines elsif v.is_a?(Array) # Expected to be array of strings yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n" else yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n" end end yaml end ARRAY_REGEX = / ^ (?:[ ]*-[ ]) # '- ' before array items (['"]?) # optional opening quote (.*) # value \1 # matching closing quote $ /xo.freeze HASH_REGEX = / ^ ([ ]*) # indentations (.+) # key (?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value) [ ]? (['"]?) # optional opening quote (.*) # value \3 # matching closing quote $ /xo.freeze def load(str) res = {} stack = [res] last_hash = nil last_empty_key = nil str.split(/\r?\n/).each do |line| if match = HASH_REGEX.match(line) indent, key, quote, val = match.captures key = convert_to_backward_compatible_key(key) depth = indent.scan(/ /).length if quote.empty? && val.empty? new_hash = {} stack[depth][key] = new_hash stack[depth + 1] = new_hash last_empty_key = key last_hash = stack[depth] else stack[depth][key] = val end elsif match = ARRAY_REGEX.match(line) _, val = match.captures last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array) last_hash[last_empty_key].push(val) end end res end # for settings' keys def convert_to_backward_compatible_key(key) key = "#{key}/" if key =~ /https?:/i && key !~ %r{/\Z} key = key.gsub(".", "__") if key.include?(".") key end class << self private :dump_hash, :convert_to_backward_compatible_key end end end PKu]X33&bundler-2.2.24/lib/bundler/settings.rbnu[# frozen_string_literal: true module Bundler class Settings autoload :Mirror, File.expand_path("mirror", __dir__) autoload :Mirrors, File.expand_path("mirror", __dir__) autoload :Validator, File.expand_path("settings/validator", __dir__) BOOL_KEYS = %w[ allow_deployment_source_credential_changes allow_offline_install auto_clean_without_path auto_install cache_all cache_all_platforms clean default_install_uses_path deployment disable_checksum_validation disable_exec_load disable_local_branch_check disable_local_revision_check disable_shared_gems disable_version_check force_ruby_platform forget_cli_options frozen gem.changelog gem.coc gem.mit git.allow_insecure global_gem_cache ignore_messages init_gems_rb inline no_install no_prune path_relative_to_cwd path.system plugins prefer_patch print_only_version_number setup_makes_kernel_gem_public silence_deprecations silence_root_warning suppress_install_using_messages update_requires_all_flag use_gem_version_promoter_for_major_updates ].freeze NUMBER_KEYS = %w[ jobs redirect retry ssl_verify_mode timeout ].freeze ARRAY_KEYS = %w[ with without ].freeze STRING_KEYS = %w[ bin cache_path console gem.ci gem.github_username gem.linter gem.rubocop gem.test gemfile path shebang system_bindir trust-policy ].freeze DEFAULT_CONFIG = { "BUNDLE_SILENCE_DEPRECATIONS" => false, "BUNDLE_DISABLE_VERSION_CHECK" => true, "BUNDLE_PREFER_PATCH" => false, "BUNDLE_REDIRECT" => 5, "BUNDLE_RETRY" => 3, "BUNDLE_TIMEOUT" => 10, }.freeze def initialize(root = nil) @root = root @local_config = load_config(local_config_file) @env_config = ENV.to_h.select {|key, _value| key =~ /\ABUNDLE_.+/ } @global_config = load_config(global_config_file) @temporary = {} end def [](name) key = key_for(name) value = configs.values.map {|config| config[key] }.compact.first converted_value(value, name) end def set_command_option(key, value) if Bundler.feature_flag.forget_cli_options? temporary(key => value) value else set_local(key, value) end end def set_command_option_if_given(key, value) return if value.nil? set_command_option(key, value) end def set_local(key, value) local_config_file || raise(GemfileNotFound, "Could not locate Gemfile") set_key(key, value, @local_config, local_config_file) end def temporary(update) existing = Hash[update.map {|k, _| [k, @temporary[key_for(k)]] }] update.each do |k, v| set_key(k, v, @temporary, nil) end return unless block_given? begin yield ensure existing.each {|k, v| set_key(k, v, @temporary, nil) } end end def set_global(key, value) set_key(key, value, @global_config, global_config_file) end def all keys = @temporary.keys | @global_config.keys | @local_config.keys | @env_config.keys keys.map do |key| key.sub(/^BUNDLE_/, "").gsub(/___/, "-").gsub(/__/, ".").downcase end.sort end def local_overrides repos = {} all.each do |k| repos[$'] = self[k] if k =~ /^local\./ end repos end def mirror_for(uri) if uri.is_a?(String) require_relative "vendored_uri" uri = Bundler::URI(uri) end gem_mirrors.for(uri.to_s).uri end def credentials_for(uri) self[uri.to_s] || self[uri.host] end def gem_mirrors all.inject(Mirrors.new) do |mirrors, k| mirrors.parse(k, self[k]) if k.start_with?("mirror.") mirrors end end def locations(key) key = key_for(key) configs.keys.inject({}) do |partial_locations, level| value_on_level = configs[level][key] partial_locations[level] = value_on_level unless value_on_level.nil? partial_locations end end def pretty_values_for(exposed_key) key = key_for(exposed_key) locations = [] if value = @temporary[key] locations << "Set for the current command: #{printable_value(value, exposed_key).inspect}" end if value = @local_config[key] locations << "Set for your local app (#{local_config_file}): #{printable_value(value, exposed_key).inspect}" end if value = @env_config[key] locations << "Set via #{key}: #{printable_value(value, exposed_key).inspect}" end if value = @global_config[key] locations << "Set for the current user (#{global_config_file}): #{printable_value(value, exposed_key).inspect}" end return ["You have not configured a value for `#{exposed_key}`"] if locations.empty? locations end def processor_count require "etc" Etc.nprocessors rescue StandardError 1 end # for legacy reasons, in Bundler 2, we do not respect :disable_shared_gems def path configs.each do |_level, settings| path = value_for("path", settings) path_system = value_for("path.system", settings) disabled_shared_gems = value_for("disable_shared_gems", settings) next if path.nil? && path_system.nil? && disabled_shared_gems.nil? system_path = path_system || (disabled_shared_gems == false) return Path.new(path, system_path) end Path.new(nil, false) end Path = Struct.new(:explicit_path, :system_path) do def path path = base_path path = File.join(path, Bundler.ruby_scope) unless use_system_gems? path end def use_system_gems? return true if system_path return false if explicit_path !Bundler.feature_flag.default_install_uses_path? end def base_path path = explicit_path path ||= ".bundle" unless use_system_gems? path ||= Bundler.rubygems.gem_dir path end def base_path_relative_to_pwd base_path = Pathname.new(self.base_path) expanded_base_path = base_path.expand_path(Bundler.root) relative_path = expanded_base_path.relative_path_from(Pathname.pwd) if relative_path.to_s.start_with?("..") relative_path = base_path if base_path.absolute? else relative_path = Pathname.new(File.join(".", relative_path)) end relative_path rescue ArgumentError expanded_base_path end def validate! return unless explicit_path && system_path path = Bundler.settings.pretty_values_for(:path) path.unshift(nil, "path:") unless path.empty? system_path = Bundler.settings.pretty_values_for("path.system") system_path.unshift(nil, "path.system:") unless system_path.empty? disable_shared_gems = Bundler.settings.pretty_values_for(:disable_shared_gems) disable_shared_gems.unshift(nil, "disable_shared_gems:") unless disable_shared_gems.empty? raise InvalidOption, "Using a custom path while using system gems is unsupported.\n#{path.join("\n")}\n#{system_path.join("\n")}\n#{disable_shared_gems.join("\n")}" end end def allow_sudo? key = key_for(:path) path_configured = @temporary.key?(key) || @local_config.key?(key) !path_configured end def ignore_config? ENV["BUNDLE_IGNORE_CONFIG"] end def app_cache_path @app_cache_path ||= self[:cache_path] || "vendor/cache" end def validate! all.each do |raw_key| [@local_config, @env_config, @global_config].each do |settings| value = value_for(raw_key, settings) Validator.validate!(raw_key, value, settings.dup) end end end def key_for(key) self.class.key_for(key) end private def configs { :temporary => @temporary, :local => @local_config, :env => @env_config, :global => @global_config, :default => DEFAULT_CONFIG, } end def value_for(name, config) converted_value(config[key_for(name)], name) end def parent_setting_for(name) split_specific_setting_for(name)[0] end def specific_gem_for(name) split_specific_setting_for(name)[1] end def split_specific_setting_for(name) name.split(".") end def is_bool(name) BOOL_KEYS.include?(name.to_s) || BOOL_KEYS.include?(parent_setting_for(name.to_s)) end def is_string(name) STRING_KEYS.include?(name.to_s) || name.to_s.start_with?("local.") || name.to_s.start_with?("mirror.") || name.to_s.start_with?("build.") end def to_bool(value) case value when nil, /\A(false|f|no|n|0|)\z/i, false false else true end end def is_num(key) NUMBER_KEYS.include?(key.to_s) end def is_array(key) ARRAY_KEYS.include?(key.to_s) end def is_credential(key) key == "gem.push_key" end def is_userinfo(value) value.include?(":") end def to_array(value) return [] unless value value.split(":").map(&:to_sym) end def array_to_s(array) array = Array(array) return nil if array.empty? array.join(":").tr(" ", ":") end def set_key(raw_key, value, hash, file) raw_key = raw_key.to_s value = array_to_s(value) if is_array(raw_key) key = key_for(raw_key) return if hash[key] == value hash[key] = value hash.delete(key) if value.nil? Validator.validate!(raw_key, converted_value(value, raw_key), hash) return unless file SharedHelpers.filesystem_access(file) do |p| FileUtils.mkdir_p(p.dirname) require_relative "yaml_serializer" p.open("w") {|f| f.write(YAMLSerializer.dump(hash)) } end end def converted_value(value, key) if is_array(key) to_array(value) elsif value.nil? nil elsif is_bool(key) || value == "false" to_bool(value) elsif is_num(key) value.to_i else value.to_s end end def printable_value(value, key) converted = converted_value(value, key) return converted unless converted.is_a?(String) if is_string(key) converted elsif is_credential(key) "[REDACTED]" elsif is_userinfo(converted) converted.gsub(/:.*$/, ":[REDACTED]") else converted end end def global_config_file if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty? Pathname.new(ENV["BUNDLE_CONFIG"]) elsif Bundler.rubygems.user_home && !Bundler.rubygems.user_home.empty? Pathname.new(Bundler.rubygems.user_home).join(".bundle/config") end end def local_config_file Pathname.new(@root).join("config") if @root end def load_config(config_file) return {} if !config_file || ignore_config? SharedHelpers.filesystem_access(config_file, :read) do |file| valid_file = file.exist? && !file.size.zero? return {} unless valid_file require_relative "yaml_serializer" YAMLSerializer.load(file.read).inject({}) do |config, (k, v)| new_k = k if k.include?("-") Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \ "This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \ "Please edit #{file} and replace any dashes in configuration keys with a triple underscore (`___`)." new_k = k.gsub("-", "___") end config[new_k] = v config end end end PER_URI_OPTIONS = %w[ fallback_timeout ].freeze NORMALIZE_URI_OPTIONS_PATTERN = / \A (\w+\.)? # optional prefix key (https?.*?) # URI (\.#{Regexp.union(PER_URI_OPTIONS)})? # optional suffix key \z /ix.freeze def self.key_for(key) key = normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key key = key.to_s.gsub(".", "__").gsub("-", "___").upcase "BUNDLE_#{key}" end # TODO: duplicates Rubygems#normalize_uri # TODO: is this the correct place to validate mirror URIs? def self.normalize_uri(uri) uri = uri.to_s if uri =~ NORMALIZE_URI_OPTIONS_PATTERN prefix = $1 uri = $2 suffix = $3 end uri = "#{uri}/" unless uri.end_with?("/") require_relative "vendored_uri" uri = Bundler::URI(uri) unless uri.absolute? raise ArgumentError, format("Gem sources must be absolute. You provided '%s'.", uri) end "#{prefix}#{uri}#{suffix}" end end end PKu](|{ { 0bundler-2.2.24/lib/bundler/stub_specification.rbnu[# frozen_string_literal: true module Bundler class StubSpecification < RemoteSpecification def self.from_stub(stub) return stub if stub.is_a?(Bundler::StubSpecification) spec = new(stub.name, stub.version, stub.platform, nil) spec.stub = stub spec end attr_accessor :stub, :ignored def source=(source) super # Stub has no concept of source, which means that extension_dir may be wrong # This is the case for git-based gems. So, instead manually assign the extension dir return unless source.respond_to?(:extension_dir_name) path = File.join(stub.extensions_dir, source.extension_dir_name) stub.extension_dir = File.expand_path(path) end def to_yaml _remote_specification.to_yaml end # @!group Stub Delegates def manually_installed? # This is for manually installed gems which are gems that were fixed in place after a # failed installation. Once the issue was resolved, the user then manually created # the gem specification using the instructions provided by `gem help install` installed_by_version == Gem::Version.new(0) end # This is defined directly to avoid having to loading the full spec def missing_extensions? return false if default_gem? return false if extensions.empty? return false if File.exist? gem_build_complete_path return false if manually_installed? true end def activated stub.activated end def activated=(activated) stub.instance_variable_set(:@activated, activated) end def extensions stub.extensions end def gem_build_complete_path File.join(extension_dir, "gem.build_complete") end def default_gem? stub.default_gem? end def full_gem_path # deleted gems can have their stubs return nil, so in that case grab the # expired path from the full spec stub.full_gem_path || method_missing(:full_gem_path) end def full_require_paths stub.full_require_paths end def load_paths full_require_paths end def loaded_from stub.loaded_from end def matches_for_glob(glob) stub.matches_for_glob(glob) end def raw_require_paths stub.raw_require_paths end private def _remote_specification @_remote_specification ||= begin rs = stub.to_spec if rs.equal?(self) # happens when to_spec gets the spec from Gem.loaded_specs rs = Gem::Specification.load(loaded_from) Bundler.rubygems.stub_set_spec(stub, rs) end unless rs raise GemspecError, "The gemspec for #{full_name} at #{loaded_from}" \ " was missing or broken. Try running `gem pristine #{name} -v #{version}`" \ " to fix the cached spec." end rs.source = source rs end end end end PKu]e Hbundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool.rbnu[require_relative 'connection_pool/version' require_relative 'connection_pool/timed_stack' # Generic connection pool class for e.g. sharing a limited number of network connections # among many threads. Note: Connections are lazily created. # # Example usage with block (faster): # # @pool = Bundler::ConnectionPool.new { Redis.new } # # @pool.with do |redis| # redis.lpop('my-list') if redis.llen('my-list') > 0 # end # # Using optional timeout override (for that single invocation) # # @pool.with(timeout: 2.0) do |redis| # redis.lpop('my-list') if redis.llen('my-list') > 0 # end # # Example usage replacing an existing connection (slower): # # $redis = Bundler::ConnectionPool.wrap { Redis.new } # # def do_work # $redis.lpop('my-list') if $redis.llen('my-list') > 0 # end # # Accepts the following options: # - :size - number of connections to pool, defaults to 5 # - :timeout - amount of time to wait for a connection if none currently available, defaults to 5 seconds # class Bundler::ConnectionPool DEFAULTS = {size: 5, timeout: 5} class Error < RuntimeError end def self.wrap(options, &block) Wrapper.new(options, &block) end def initialize(options = {}, &block) raise ArgumentError, 'Connection pool requires a block' unless block options = DEFAULTS.merge(options) @size = options.fetch(:size) @timeout = options.fetch(:timeout) @available = TimedStack.new(@size, &block) @key = :"current-#{@available.object_id}" @key_count = :"current-#{@available.object_id}-count" end if Thread.respond_to?(:handle_interrupt) # MRI def with(options = {}) Thread.handle_interrupt(Exception => :never) do conn = checkout(options) begin Thread.handle_interrupt(Exception => :immediate) do yield conn end ensure checkin end end end else # jruby 1.7.x def with(options = {}) conn = checkout(options) begin yield conn ensure checkin end end end def checkout(options = {}) if ::Thread.current[@key] ::Thread.current[@key_count]+= 1 ::Thread.current[@key] else ::Thread.current[@key_count]= 1 ::Thread.current[@key]= @available.pop(options[:timeout] || @timeout) end end def checkin if ::Thread.current[@key] if ::Thread.current[@key_count] == 1 @available.push(::Thread.current[@key]) ::Thread.current[@key]= nil else ::Thread.current[@key_count]-= 1 end else raise Bundler::ConnectionPool::Error, 'no connections are checked out' end nil end def shutdown(&block) @available.shutdown(&block) end # Size of this connection pool def size @size end # Number of pool entries available for checkout at this instant. def available @available.length end private class Wrapper < ::BasicObject METHODS = [:with, :pool_shutdown] def initialize(options = {}, &block) @pool = options.fetch(:pool) { ::Bundler::ConnectionPool.new(options, &block) } end def with(&block) @pool.with(&block) end def pool_shutdown(&block) @pool.shutdown(&block) end def pool_size @pool.size end def pool_available @pool.available end def respond_to?(id, *args) METHODS.include?(id) || with { |c| c.respond_to?(id, *args) } end def method_missing(name, *args, &block) with do |connection| connection.send(name, *args, &block) end end end end PKu]\?66Pbundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rbnu[class Bundler::ConnectionPool VERSION = "2.2.2" end PKu]q.YYWbundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rbnu[# Global monotonic clock from Concurrent Ruby 1.0. # Copyright (c) Jerry D'Antonio -- released under the MIT license. # Slightly modified; used with permission. # https://github.com/ruby-concurrency/concurrent-ruby require 'thread' class Bundler::ConnectionPool class_definition = Class.new do if defined?(Process::CLOCK_MONOTONIC) # @!visibility private def get_time Process.clock_gettime(Process::CLOCK_MONOTONIC) end elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' # @!visibility private def get_time java.lang.System.nanoTime() / 1_000_000_000.0 end else # @!visibility private def initialize @mutex = Mutex.new @last_time = Time.now.to_f end # @!visibility private def get_time @mutex.synchronize do now = Time.now.to_f if @last_time < now @last_time = now else # clock has moved back in time @last_time += 0.000_001 end end end end end ## # Clock that cannot be set and represents monotonic time since # some unspecified starting point. # # @!visibility private GLOBAL_MONOTONIC_CLOCK = class_definition.new private_constant :GLOBAL_MONOTONIC_CLOCK class << self ## # Returns the current time a tracked by the application monotonic clock. # # @return [Float] The current monotonic time when `since` not given else # the elapsed monotonic time between `since` and the current time def monotonic_time GLOBAL_MONOTONIC_CLOCK.get_time end end end PKu]y<22Tbundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rbnu[require 'thread' require 'timeout' require_relative 'monotonic_time' ## # Raised when you attempt to retrieve a connection from a pool that has been # shut down. class Bundler::ConnectionPool::PoolShuttingDownError < RuntimeError; end ## # The TimedStack manages a pool of homogeneous connections (or any resource # you wish to manage). Connections are created lazily up to a given maximum # number. # Examples: # # ts = TimedStack.new(1) { MyConnection.new } # # # fetch a connection # conn = ts.pop # # # return a connection # ts.push conn # # conn = ts.pop # ts.pop timeout: 5 # #=> raises Timeout::Error after 5 seconds class Bundler::ConnectionPool::TimedStack attr_reader :max ## # Creates a new pool with +size+ connections that are created from the given # +block+. def initialize(size = 0, &block) @create_block = block @created = 0 @que = [] @max = size @mutex = Mutex.new @resource = ConditionVariable.new @shutdown_block = nil end ## # Returns +obj+ to the stack. +options+ is ignored in TimedStack but may be # used by subclasses that extend TimedStack. def push(obj, options = {}) @mutex.synchronize do if @shutdown_block @shutdown_block.call(obj) else store_connection obj, options end @resource.broadcast end end alias_method :<<, :push ## # Retrieves a connection from the stack. If a connection is available it is # immediately returned. If no connection is available within the given # timeout a Timeout::Error is raised. # # +:timeout+ is the only checked entry in +options+ and is preferred over # the +timeout+ argument (which will be removed in a future release). Other # options may be used by subclasses that extend TimedStack. def pop(timeout = 0.5, options = {}) options, timeout = timeout, 0.5 if Hash === timeout timeout = options.fetch :timeout, timeout deadline = Bundler::ConnectionPool.monotonic_time + timeout @mutex.synchronize do loop do raise Bundler::ConnectionPool::PoolShuttingDownError if @shutdown_block return fetch_connection(options) if connection_stored?(options) connection = try_create(options) return connection if connection to_wait = deadline - Bundler::ConnectionPool.monotonic_time raise Timeout::Error, "Waited #{timeout} sec" if to_wait <= 0 @resource.wait(@mutex, to_wait) end end end ## # Shuts down the TimedStack which prevents connections from being checked # out. The +block+ is called once for each connection on the stack. def shutdown(&block) raise ArgumentError, "shutdown must receive a block" unless block_given? @mutex.synchronize do @shutdown_block = block @resource.broadcast shutdown_connections end end ## # Returns +true+ if there are no available connections. def empty? (@created - @que.length) >= @max end ## # The number of connections available on the stack. def length @max - @created + @que.length end private ## # This is an extension point for TimedStack and is called with a mutex. # # This method must returns true if a connection is available on the stack. def connection_stored?(options = nil) !@que.empty? end ## # This is an extension point for TimedStack and is called with a mutex. # # This method must return a connection from the stack. def fetch_connection(options = nil) @que.pop end ## # This is an extension point for TimedStack and is called with a mutex. # # This method must shut down all connections on the stack. def shutdown_connections(options = nil) while connection_stored?(options) conn = fetch_connection(options) @shutdown_block.call(conn) end end ## # This is an extension point for TimedStack and is called with a mutex. # # This method must return +obj+ to the stack. def store_connection(obj, options = nil) @que.push obj end ## # This is an extension point for TimedStack and is called with a mutex. # # This method must create a connection if and only if the total number of # connections allowed has not been met. def try_create(options = nil) unless @created == @max object = @create_block.call @created += 1 object end end end PKu]홇>bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor.rbnu[require_relative "line_editor/basic" require_relative "line_editor/readline" class Bundler::Thor module LineEditor def self.readline(prompt, options = {}) best_available.new(prompt, options).readline end def self.best_available [ Bundler::Thor::LineEditor::Readline, Bundler::Thor::LineEditor::Basic ].detect(&:available?) end end end PKu]9bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser.rbnu[require_relative "parser/argument" require_relative "parser/arguments" require_relative "parser/option" require_relative "parser/options" PKu]Luvv>bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/rake_compat.rbnu[require "rake" require "rake/dsl_definition" class Bundler::Thor # Adds a compatibility layer to your Bundler::Thor classes which allows you to use # rake package tasks. For example, to use rspec rake tasks, one can do: # # require 'bundler/vendor/thor/lib/thor/rake_compat' # require 'rspec/core/rake_task' # # class Default < Bundler::Thor # include Bundler::Thor::RakeCompat # # RSpec::Core::RakeTask.new(:spec) do |t| # t.spec_opts = ['--options', './.rspec'] # t.spec_files = FileList['spec/**/*_spec.rb'] # end # end # module RakeCompat include Rake::DSL if defined?(Rake::DSL) def self.rake_classes @rake_classes ||= [] end def self.included(base) super(base) # Hack. Make rakefile point to invoker, so rdoc task is generated properly. rakefile = File.basename(caller[0].match(/(.*):\d+/)[1]) Rake.application.instance_variable_set(:@rakefile, rakefile) rake_classes << base end end end # override task on (main), for compatibility with Rake 0.9 instance_eval do alias rake_namespace namespace def task(*) task = super if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition non_namespaced_name = task.name.split(":").last description = non_namespaced_name description << task.arg_names.map { |n| n.to_s.upcase }.join(" ") description.strip! klass.desc description, Rake.application.last_description || non_namespaced_name Rake.application.last_description = nil klass.send :define_method, non_namespaced_name do |*args| Rake::Task[task.name.to_sym].invoke(*args) end end task end def namespace(name) if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition const_name = Bundler::Thor::Util.camel_case(name.to_s).to_sym klass.const_set(const_name, Class.new(Bundler::Thor)) new_klass = klass.const_get(const_name) Bundler::Thor::RakeCompat.rake_classes << new_klass end super Bundler::Thor::RakeCompat.rake_classes.pop end end PKu]ɗc 8bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/error.rbnu[class Bundler::Thor Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) # rubocop:disable Naming/ConstantName # In order to support versions of Ruby that don't have keyword # arguments, we need our own spell checker class that doesn't take key # words. Even though this code wouldn't be hit because of the check # above, it's still necessary because the interpreter would otherwise be # unable to parse the file. class NoKwargSpellChecker < DidYouMean::SpellChecker # :nodoc: def initialize(dictionary) @dictionary = dictionary end end DidYouMean::Correctable end # Bundler::Thor::Error is raised when it's caused by wrong usage of thor classes. Those # errors have their backtrace suppressed and are nicely shown to the user. # # Errors that are caused by the developer, like declaring a method which # overwrites a thor keyword, SHOULD NOT raise a Bundler::Thor::Error. This way, we # ensure that developer errors are shown with full backtrace. class Error < StandardError end # Raised when a command was not found. class UndefinedCommandError < Error class SpellChecker attr_reader :error def initialize(error) @error = error end def corrections @corrections ||= spell_checker.correct(error.command).map(&:inspect) end def spell_checker NoKwargSpellChecker.new(error.all_commands) end end attr_reader :command, :all_commands def initialize(command, all_commands, namespace) @command = command @all_commands = all_commands message = "Could not find command #{command.inspect}" message = namespace ? "#{message} in #{namespace.inspect} namespace." : "#{message}." super(message) end prepend Correctable if Correctable end UndefinedTaskError = UndefinedCommandError class AmbiguousCommandError < Error end AmbiguousTaskError = AmbiguousCommandError # Raised when a command was found, but not invoked properly. class InvocationError < Error end class UnknownArgumentError < Error class SpellChecker attr_reader :error def initialize(error) @error = error end def corrections @corrections ||= error.unknown.flat_map { |unknown| spell_checker.correct(unknown) }.uniq.map(&:inspect) end def spell_checker @spell_checker ||= NoKwargSpellChecker.new(error.switches) end end attr_reader :switches, :unknown def initialize(switches, unknown) @switches = switches @unknown = unknown super("Unknown switches #{unknown.map(&:inspect).join(', ')}") end prepend Correctable if Correctable end class RequiredArgumentMissingError < InvocationError end class MalformattedArgumentError < InvocationError end if Correctable DidYouMean::SPELL_CHECKERS.merge!( 'Bundler::Thor::UndefinedCommandError' => UndefinedCommandError::SpellChecker, 'Bundler::Thor::UnknownArgumentError' => UnknownArgumentError::SpellChecker ) end end PKu]#I`i#i#8bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/group.rbnu[require_relative "base" # Bundler::Thor has a special class called Bundler::Thor::Group. The main difference to Bundler::Thor class # is that it invokes all commands at once. It also include some methods that allows # invocations to be done at the class method, which are not available to Bundler::Thor # commands. class Bundler::Thor::Group class << self # The description for this Bundler::Thor::Group. If none is provided, but a source root # exists, tries to find the USAGE one folder above it, otherwise searches # in the superclass. # # ==== Parameters # description:: The description for this Bundler::Thor::Group. # def desc(description = nil) if description @desc = description else @desc ||= from_superclass(:desc, nil) end end # Prints help information. # # ==== Options # short:: When true, shows only usage. # def help(shell) shell.say "Usage:" shell.say " #{banner}\n" shell.say class_options_help(shell) shell.say desc if desc end # Stores invocations for this class merging with superclass values. # def invocations #:nodoc: @invocations ||= from_superclass(:invocations, {}) end # Stores invocation blocks used on invoke_from_option. # def invocation_blocks #:nodoc: @invocation_blocks ||= from_superclass(:invocation_blocks, {}) end # Invoke the given namespace or class given. It adds an instance # method that will invoke the klass and command. You can give a block to # configure how it will be invoked. # # The namespace/class given will have its options showed on the help # usage. Check invoke_from_option for more information. # def invoke(*names, &block) options = names.last.is_a?(Hash) ? names.pop : {} verbose = options.fetch(:verbose, true) names.each do |name| invocations[name] = false invocation_blocks[name] = block if block_given? class_eval <<-METHOD, __FILE__, __LINE__ + 1 def _invoke_#{name.to_s.gsub(/\W/, '_')} klass, command = self.class.prepare_for_invocation(nil, #{name.inspect}) if klass say_status :invoke, #{name.inspect}, #{verbose.inspect} block = self.class.invocation_blocks[#{name.inspect}] _invoke_for_class_method klass, command, &block else say_status :error, %(#{name.inspect} [not found]), :red end end METHOD end end # Invoke a thor class based on the value supplied by the user to the # given option named "name". A class option must be created before this # method is invoked for each name given. # # ==== Examples # # class GemGenerator < Bundler::Thor::Group # class_option :test_framework, :type => :string # invoke_from_option :test_framework # end # # ==== Boolean options # # In some cases, you want to invoke a thor class if some option is true or # false. This is automatically handled by invoke_from_option. Then the # option name is used to invoke the generator. # # ==== Preparing for invocation # # In some cases you want to customize how a specified hook is going to be # invoked. You can do that by overwriting the class method # prepare_for_invocation. The class method must necessarily return a klass # and an optional command. # # ==== Custom invocations # # You can also supply a block to customize how the option is going to be # invoked. The block receives two parameters, an instance of the current # class and the klass to be invoked. # def invoke_from_option(*names, &block) options = names.last.is_a?(Hash) ? names.pop : {} verbose = options.fetch(:verbose, :white) names.each do |name| unless class_options.key?(name) raise ArgumentError, "You have to define the option #{name.inspect} " \ "before setting invoke_from_option." end invocations[name] = true invocation_blocks[name] = block if block_given? class_eval <<-METHOD, __FILE__, __LINE__ + 1 def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')} return unless options[#{name.inspect}] value = options[#{name.inspect}] value = #{name.inspect} if TrueClass === value klass, command = self.class.prepare_for_invocation(#{name.inspect}, value) if klass say_status :invoke, value, #{verbose.inspect} block = self.class.invocation_blocks[#{name.inspect}] _invoke_for_class_method klass, command, &block else say_status :error, %(\#{value} [not found]), :red end end METHOD end end # Remove a previously added invocation. # # ==== Examples # # remove_invocation :test_framework # def remove_invocation(*names) names.each do |name| remove_command(name) remove_class_option(name) invocations.delete(name) invocation_blocks.delete(name) end end # Overwrite class options help to allow invoked generators options to be # shown recursively when invoking a generator. # def class_options_help(shell, groups = {}) #:nodoc: get_options_from_invocations(groups, class_options) do |klass| klass.send(:get_options_from_invocations, groups, class_options) end super(shell, groups) end # Get invocations array and merge options from invocations. Those # options are added to group_options hash. Options that already exists # in base_options are not added twice. # def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength invocations.each do |name, from_option| value = if from_option option = class_options[name] option.type == :boolean ? name : option.default else name end next unless value klass, _ = prepare_for_invocation(name, value) next unless klass && klass.respond_to?(:class_options) value = value.to_s human_name = value.respond_to?(:classify) ? value.classify : value group_options[human_name] ||= [] group_options[human_name] += klass.class_options.values.select do |class_option| base_options[class_option.name.to_sym].nil? && class_option.group.nil? && !group_options.values.flatten.any? { |i| i.name == class_option.name } end yield klass if block_given? end end # Returns commands ready to be printed. def printable_commands(*) item = [] item << banner item << (desc ? "# #{desc.gsub(/\s+/m, ' ')}" : "") [item] end alias_method :printable_tasks, :printable_commands def handle_argument_error(command, error, _args, arity) #:nodoc: msg = "#{basename} #{command.name} takes #{arity} argument".dup msg << "s" if arity > 1 msg << ", but it should not." raise error, msg end protected # The method responsible for dispatching given the args. def dispatch(command, given_args, given_opts, config) #:nodoc: if Bundler::Thor::HELP_MAPPINGS.include?(given_args.first) help(config[:shell]) return end args, opts = Bundler::Thor::Options.split(given_args) opts = given_opts || opts instance = new(args, opts, config) yield instance if block_given? if command instance.invoke_command(all_commands[command]) else instance.invoke_all end end # The banner for this class. You can customize it if you are invoking the # thor class by another ways which is not the Bundler::Thor::Runner. def banner "#{basename} #{self_command.formatted_usage(self, false)}" end # Represents the whole class as a command. def self_command #:nodoc: Bundler::Thor::DynamicCommand.new(namespace, class_options) end alias_method :self_task, :self_command def baseclass #:nodoc: Bundler::Thor::Group end def create_command(meth) #:nodoc: commands[meth.to_s] = Bundler::Thor::Command.new(meth, nil, nil, nil, nil) true end alias_method :create_task, :create_command end include Bundler::Thor::Base protected # Shortcut to invoke with padding and block handling. Use internally by # invoke and invoke_from_option class methods. def _invoke_for_class_method(klass, command = nil, *args, &block) #:nodoc: with_padding do if block case block.arity when 3 yield(self, klass, command) when 2 yield(self, klass) when 1 instance_exec(klass, &block) end else invoke klass, command, *args end end end end PKu]1UyXX>bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/color.rbnu[require_relative "basic" class Bundler::Thor module Shell # Inherit from Bundler::Thor::Shell::Basic and add set_color behavior. Check # Bundler::Thor::Shell::Basic to see all available methods. # class Color < Basic # Embed in a String to clear all previous ANSI sequences. CLEAR = "\e[0m" # The start of an ANSI bold sequence. BOLD = "\e[1m" # Set the terminal's foreground ANSI color to black. BLACK = "\e[30m" # Set the terminal's foreground ANSI color to red. RED = "\e[31m" # Set the terminal's foreground ANSI color to green. GREEN = "\e[32m" # Set the terminal's foreground ANSI color to yellow. YELLOW = "\e[33m" # Set the terminal's foreground ANSI color to blue. BLUE = "\e[34m" # Set the terminal's foreground ANSI color to magenta. MAGENTA = "\e[35m" # Set the terminal's foreground ANSI color to cyan. CYAN = "\e[36m" # Set the terminal's foreground ANSI color to white. WHITE = "\e[37m" # Set the terminal's background ANSI color to black. ON_BLACK = "\e[40m" # Set the terminal's background ANSI color to red. ON_RED = "\e[41m" # Set the terminal's background ANSI color to green. ON_GREEN = "\e[42m" # Set the terminal's background ANSI color to yellow. ON_YELLOW = "\e[43m" # Set the terminal's background ANSI color to blue. ON_BLUE = "\e[44m" # Set the terminal's background ANSI color to magenta. ON_MAGENTA = "\e[45m" # Set the terminal's background ANSI color to cyan. ON_CYAN = "\e[46m" # Set the terminal's background ANSI color to white. ON_WHITE = "\e[47m" # Set color by using a string or one of the defined constants. If a third # option is set to true, it also adds bold to the string. This is based # on Highline implementation and it automatically appends CLEAR to the end # of the returned String. # # Pass foreground, background and bold options to this method as # symbols. # # Example: # # set_color "Hi!", :red, :on_white, :bold # # The available colors are: # # :bold # :black # :red # :green # :yellow # :blue # :magenta # :cyan # :white # :on_black # :on_red # :on_green # :on_yellow # :on_blue # :on_magenta # :on_cyan # :on_white def set_color(string, *colors) if colors.compact.empty? || !can_display_colors? string elsif colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } ansi_colors = colors.map { |color| lookup_color(color) } "#{ansi_colors.join}#{string}#{CLEAR}" else # The old API was `set_color(color, bold=boolean)`. We # continue to support the old API because you should never # break old APIs unnecessarily :P foreground, bold = colors foreground = self.class.const_get(foreground.to_s.upcase) if foreground.is_a?(Symbol) bold = bold ? BOLD : "" "#{bold}#{foreground}#{string}#{CLEAR}" end end protected def can_display_colors? are_colors_supported? && !are_colors_disabled? end def are_colors_supported? stdout.tty? && ENV["TERM"] != "dumb" end def are_colors_disabled? !ENV['NO_COLOR'].nil? end # Overwrite show_diff to show diff with colors if Diff::LCS is # available. # def show_diff(destination, content) #:nodoc: if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil? actual = File.binread(destination).to_s.split("\n") content = content.to_s.split("\n") Diff::LCS.sdiff(actual, content).each do |diff| output_diff_line(diff) end else super end end def output_diff_line(diff) #:nodoc: case diff.action when "-" say "- #{diff.old_element.chomp}", :red, true when "+" say "+ #{diff.new_element.chomp}", :green, true when "!" say "- #{diff.old_element.chomp}", :red, true say "+ #{diff.new_element.chomp}", :green, true else say " #{diff.old_element.chomp}", nil, true end end # Check if Diff::LCS is loaded. If it is, use it to create pretty output # for diff. # def diff_lcs_loaded? #:nodoc: return true if defined?(Diff::LCS) return @diff_lcs_loaded unless @diff_lcs_loaded.nil? @diff_lcs_loaded = begin require "diff/lcs" true rescue LoadError false end end end end end PKu].=bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/html.rbnu[require_relative "basic" class Bundler::Thor module Shell # Inherit from Bundler::Thor::Shell::Basic and add set_color behavior. Check # Bundler::Thor::Shell::Basic to see all available methods. # class HTML < Basic # The start of an HTML bold sequence. BOLD = "font-weight: bold" # Set the terminal's foreground HTML color to black. BLACK = "color: black" # Set the terminal's foreground HTML color to red. RED = "color: red" # Set the terminal's foreground HTML color to green. GREEN = "color: green" # Set the terminal's foreground HTML color to yellow. YELLOW = "color: yellow" # Set the terminal's foreground HTML color to blue. BLUE = "color: blue" # Set the terminal's foreground HTML color to magenta. MAGENTA = "color: magenta" # Set the terminal's foreground HTML color to cyan. CYAN = "color: cyan" # Set the terminal's foreground HTML color to white. WHITE = "color: white" # Set the terminal's background HTML color to black. ON_BLACK = "background-color: black" # Set the terminal's background HTML color to red. ON_RED = "background-color: red" # Set the terminal's background HTML color to green. ON_GREEN = "background-color: green" # Set the terminal's background HTML color to yellow. ON_YELLOW = "background-color: yellow" # Set the terminal's background HTML color to blue. ON_BLUE = "background-color: blue" # Set the terminal's background HTML color to magenta. ON_MAGENTA = "background-color: magenta" # Set the terminal's background HTML color to cyan. ON_CYAN = "background-color: cyan" # Set the terminal's background HTML color to white. ON_WHITE = "background-color: white" # Set color by using a string or one of the defined constants. If a third # option is set to true, it also adds bold to the string. This is based # on Highline implementation and it automatically appends CLEAR to the end # of the returned String. # def set_color(string, *colors) if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } html_colors = colors.map { |color| lookup_color(color) } "#{Bundler::Thor::Util.escape_html(string)}" else color, bold = colors html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) styles = [html_color] styles << BOLD if bold "#{Bundler::Thor::Util.escape_html(string)}" end end # Ask something to the user and receives a response. # # ==== Example # ask("What is your name?") # # TODO: Implement #ask for Bundler::Thor::Shell::HTML def ask(statement, color = nil) raise NotImplementedError, "Implement #ask for Bundler::Thor::Shell::HTML" end protected def can_display_colors? true end # Overwrite show_diff to show diff with colors if Diff::LCS is # available. # def show_diff(destination, content) #:nodoc: if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil? actual = File.binread(destination).to_s.split("\n") content = content.to_s.split("\n") Diff::LCS.sdiff(actual, content).each do |diff| output_diff_line(diff) end else super end end def output_diff_line(diff) #:nodoc: case diff.action when "-" say "- #{diff.old_element.chomp}", :red, true when "+" say "+ #{diff.new_element.chomp}", :green, true when "!" say "- #{diff.old_element.chomp}", :red, true say "+ #{diff.new_element.chomp}", :green, true else say " #{diff.old_element.chomp}", nil, true end end # Check if Diff::LCS is loaded. If it is, use it to create pretty output # for diff. # def diff_lcs_loaded? #:nodoc: return true if defined?(Diff::LCS) return @diff_lcs_loaded unless @diff_lcs_loaded.nil? @diff_lcs_loaded = begin require "diff/lcs" true rescue LoadError false end end end end end PKu]699>bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/basic.rbnu[class Bundler::Thor module Shell class Basic DEFAULT_TERMINAL_WIDTH = 80 attr_accessor :base attr_reader :padding # Initialize base, mute and padding to nil. # def initialize #:nodoc: @base = nil @mute = false @padding = 0 @always_force = false end # Mute everything that's inside given block # def mute @mute = true yield ensure @mute = false end # Check if base is muted # def mute? @mute end # Sets the output padding, not allowing less than zero values. # def padding=(value) @padding = [0, value].max end # Sets the output padding while executing a block and resets it. # def indent(count = 1) orig_padding = padding self.padding = padding + count yield self.padding = orig_padding end # Asks something to the user and receives a response. # # If a default value is specified it will be presented to the user # and allows them to select that value with an empty response. This # option is ignored when limited answers are supplied. # # If asked to limit the correct responses, you can pass in an # array of acceptable answers. If one of those is not supplied, # they will be shown a message stating that one of those answers # must be given and re-asked the question. # # If asking for sensitive information, the :echo option can be set # to false to mask user input from $stdin. # # If the required input is a path, then set the path option to # true. This will enable tab completion for file paths relative # to the current working directory on systems that support # Readline. # # ==== Example # ask("What is your name?") # # ask("What is the planet furthest from the sun?", :default => "Pluto") # # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"]) # # ask("What is your password?", :echo => false) # # ask("Where should the file be saved?", :path => true) # def ask(statement, *args) options = args.last.is_a?(Hash) ? args.pop : {} color = args.first if options[:limited_to] ask_filtered(statement, color, options) else ask_simply(statement, color, options) end end # Say (print) something to the user. If the sentence ends with a whitespace # or tab character, a new line is not appended (print + flush). Otherwise # are passed straight to puts (behavior got from Highline). # # ==== Example # say("I know you knew that.") # def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/)) return if quiet? buffer = prepare_message(message, *color) buffer << "\n" if force_new_line && !message.to_s.end_with?("\n") stdout.print(buffer) stdout.flush end # Say a status with the given color and appends the message. Since this # method is used frequently by actions, it allows nil or false to be given # in log_status, avoiding the message from being shown. If a Symbol is # given in log_status, it's used as the color. # def say_status(status, message, log_status = true) return if quiet? || log_status == false spaces = " " * (padding + 1) color = log_status.is_a?(Symbol) ? log_status : :green status = status.to_s.rjust(12) status = set_color status, color, true if color buffer = "#{status}#{spaces}#{message}" buffer = "#{buffer}\n" unless buffer.end_with?("\n") stdout.print(buffer) stdout.flush end # Make a question the to user and returns true if the user replies "y" or # "yes". # def yes?(statement, color = nil) !!(ask(statement, color, :add_to_history => false) =~ is?(:yes)) end # Make a question the to user and returns true if the user replies "n" or # "no". # def no?(statement, color = nil) !!(ask(statement, color, :add_to_history => false) =~ is?(:no)) end # Prints values in columns # # ==== Parameters # Array[String, String, ...] # def print_in_columns(array) return if array.empty? colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2 array.each_with_index do |value, index| # Don't output trailing spaces when printing the last column if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length stdout.puts value else stdout.printf("%-#{colwidth}s", value) end end end # Prints a table. # # ==== Parameters # Array[Array[String, String, ...]] # # ==== Options # indent:: Indent the first column by indent value. # colwidth:: Force the first column to colwidth spaces wide. # def print_table(array, options = {}) # rubocop:disable MethodLength return if array.empty? formats = [] indent = options[:indent].to_i colwidth = options[:colwidth] options[:truncate] = terminal_width if options[:truncate] == true formats << "%-#{colwidth + 2}s".dup if colwidth start = colwidth ? 1 : 0 colcount = array.max { |a, b| a.size <=> b.size }.size maximas = [] start.upto(colcount - 1) do |index| maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max maximas << maxima formats << if index == colcount - 1 # Don't output 2 trailing spaces when printing the last column "%-s".dup else "%-#{maxima + 2}s".dup end end formats[0] = formats[0].insert(0, " " * indent) formats << "%s" array.each do |row| sentence = "".dup row.each_with_index do |column, index| maxima = maximas[index] f = if column.is_a?(Numeric) if index == row.size - 1 # Don't output 2 trailing spaces when printing the last column "%#{maxima}s" else "%#{maxima}s " end else formats[index] end sentence << f % column.to_s end sentence = truncate(sentence, options[:truncate]) if options[:truncate] stdout.puts sentence end end # Prints a long string, word-wrapping the text to the current width of the # terminal display. Ideal for printing heredocs. # # ==== Parameters # String # # ==== Options # indent:: Indent each line of the printed paragraph by indent value. # def print_wrapped(message, options = {}) indent = options[:indent] || 0 width = terminal_width - indent paras = message.split("\n\n") paras.map! do |unwrapped| words = unwrapped.split(" ") counter = words.first.length words.inject do |memo, word| word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n") counter = 0 if word.include? "\n" if (counter + word.length + 1) < width memo = "#{memo} #{word}" counter += (word.length + 1) else memo = "#{memo}\n#{word}" counter = word.length end memo end end.compact! paras.each do |para| para.split("\n").each do |line| stdout.puts line.insert(0, " " * indent) end stdout.puts unless para == paras.last end end # Deals with file collision and returns true if the file should be # overwritten and false otherwise. If a block is given, it uses the block # response as the content for the diff. # # ==== Parameters # destination:: the destination file to solve conflicts # block:: an optional block that returns the value to be used in diff and merge # def file_collision(destination) return true if @always_force options = block_given? ? "[Ynaqdhm]" : "[Ynaqh]" loop do answer = ask( %[Overwrite #{destination}? (enter "h" for help) #{options}], :add_to_history => false ) case answer when nil say "" return true when is?(:yes), is?(:force), "" return true when is?(:no), is?(:skip) return false when is?(:always) return @always_force = true when is?(:quit) say "Aborting..." raise SystemExit when is?(:diff) show_diff(destination, yield) if block_given? say "Retrying..." when is?(:merge) if block_given? && !merge_tool.empty? merge(destination, yield) return nil end say "Please specify merge tool to `THOR_MERGE` env." else say file_collision_help end end end # This code was copied from Rake, available under MIT-LICENSE # Copyright (c) 2003, 2004 Jim Weirich def terminal_width result = if ENV["THOR_COLUMNS"] ENV["THOR_COLUMNS"].to_i else unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH end result < 10 ? DEFAULT_TERMINAL_WIDTH : result rescue DEFAULT_TERMINAL_WIDTH end # Called if something goes wrong during the execution. This is used by Bundler::Thor # internally and should not be used inside your scripts. If something went # wrong, you can always raise an exception. If you raise a Bundler::Thor::Error, it # will be rescued and wrapped in the method below. # def error(statement) stderr.puts statement end # Apply color to the given string with optional bold. Disabled in the # Bundler::Thor::Shell::Basic class. # def set_color(string, *) #:nodoc: string end protected def prepare_message(message, *color) spaces = " " * padding spaces + set_color(message.to_s, *color) end def can_display_colors? false end def lookup_color(color) return color unless color.is_a?(Symbol) self.class.const_get(color.to_s.upcase) end def stdout $stdout end def stderr $stderr end def is?(value) #:nodoc: value = value.to_s if value.size == 1 /\A#{value}\z/i else /\A(#{value}|#{value[0, 1]})\z/i end end def file_collision_help #:nodoc: <<-HELP Y - yes, overwrite n - no, do not overwrite a - all, overwrite this and all others q - quit, abort d - diff, show the differences between the old and the new h - help, show this help m - merge, run merge tool HELP end def show_diff(destination, content) #:nodoc: diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u" require "tempfile" Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp| temp.write content temp.rewind system %(#{diff_cmd} "#{destination}" "#{temp.path}") end end def quiet? #:nodoc: mute? || (base && base.options[:quiet]) end # Calculate the dynamic width of the terminal def dynamic_width @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput) end def dynamic_width_stty `stty size 2>/dev/null`.split[1].to_i end def dynamic_width_tput `tput cols 2>/dev/null`.to_i end def unix? RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i end def truncate(string, width) as_unicode do chars = string.chars.to_a if chars.length <= width chars.join else chars[0, width - 3].join + "..." end end end if "".respond_to?(:encode) def as_unicode yield end else def as_unicode old = $KCODE $KCODE = "U" yield ensure $KCODE = old end end def ask_simply(statement, color, options) default = options[:default] message = [statement, ("(#{default})" if default), nil].uniq.join(" ") message = prepare_message(message, *color) result = Bundler::Thor::LineEditor.readline(message, options) return unless result result = result.strip if default && result == "" default else result end end def ask_filtered(statement, color, options) answer_set = options[:limited_to] case_insensitive = options.fetch(:case_insensitive, false) correct_answer = nil until correct_answer answers = answer_set.join(", ") answer = ask_simply("#{statement} [#{answers}]", color, options) correct_answer = answer_match(answer_set, answer, case_insensitive) say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer end correct_answer end def answer_match(possibilities, answer, case_insensitive) if case_insensitive possibilities.detect{ |possibility| possibility.downcase == answer.downcase } else possibilities.detect{ |possibility| possibility == answer } end end def merge(destination, content) #:nodoc: require "tempfile" Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp| temp.write content temp.rewind system %(#{merge_tool} "#{temp.path}" "#{destination}") end end def merge_tool #:nodoc: @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool end def git_merge_tool #:nodoc: `git config merge.tool`.rstrip rescue "" end end end end PKu];:bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/command.rbnu[class Bundler::Thor class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name) FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/ def initialize(name, description, long_description, usage, options = nil) super(name.to_s, description, long_description, usage, options || {}) end def initialize_copy(other) #:nodoc: super(other) self.options = other.options.dup if other.options end def hidden? false end # By default, a command invokes a method in the thor class. You can change this # implementation to create custom commands. def run(instance, args = []) arity = nil if private_method?(instance) instance.class.handle_no_command_error(name) elsif public_method?(instance) arity = instance.method(name).arity instance.__send__(name, *args) elsif local_method?(instance, :method_missing) instance.__send__(:method_missing, name.to_sym, *args) else instance.class.handle_no_command_error(name) end rescue ArgumentError => e handle_argument_error?(instance, e, caller) ? instance.class.handle_argument_error(self, e, args, arity) : (raise e) rescue NoMethodError => e handle_no_method_error?(instance, e, caller) ? instance.class.handle_no_command_error(name) : (raise e) end # Returns the formatted usage by injecting given required arguments # and required options into the given usage. def formatted_usage(klass, namespace = true, subcommand = false) if ancestor_name formatted = "#{ancestor_name} ".dup # add space elsif namespace namespace = klass.namespace formatted = "#{namespace.gsub(/^(default)/, '')}:".dup end formatted ||= "#{klass.namespace.split(':').last} ".dup if subcommand formatted ||= "".dup Array(usage).map do |specific_usage| formatted_specific_usage = formatted formatted_specific_usage += required_arguments_for(klass, specific_usage) # Add required options formatted_specific_usage += " #{required_options}" # Strip and go! formatted_specific_usage.strip end.join("\n") end protected # Add usage with required arguments def required_arguments_for(klass, usage) if klass && !klass.arguments.empty? usage.to_s.gsub(/^#{name}/) do |match| match << " " << klass.arguments.map(&:usage).compact.join(" ") end else usage.to_s end end def not_debugging?(instance) !(instance.class.respond_to?(:debugging) && instance.class.debugging) end def required_options @required_options ||= options.map { |_, o| o.usage if o.required? }.compact.sort.join(" ") end # Given a target, checks if this class name is a public method. def public_method?(instance) #:nodoc: !(instance.public_methods & [name.to_s, name.to_sym]).empty? end def private_method?(instance) !(instance.private_methods & [name.to_s, name.to_sym]).empty? end def local_method?(instance, name) methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false) !(methods & [name.to_s, name.to_sym]).empty? end def sans_backtrace(backtrace, caller) #:nodoc: saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) || (frame =~ %r{^kernel/} && RUBY_ENGINE =~ /rbx/) } saned - caller end def handle_argument_error?(instance, error, caller) not_debugging?(instance) && (error.message =~ /wrong number of arguments/ || error.message =~ /given \d*, expected \d*/) && begin saned = sans_backtrace(error.backtrace, caller) saned.empty? || saned.size == 1 end end def handle_no_method_error?(instance, error, caller) not_debugging?(instance) && error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ end end Task = Command # A command that is hidden in help messages but still invocable. class HiddenCommand < Command def hidden? true end end HiddenTask = HiddenCommand # A dynamic command that handles method missing scenarios. class DynamicCommand < Command def initialize(name, options = nil) super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options) end def run(instance, args = []) if (instance.methods & [name.to_s, name.to_sym]).empty? super else instance.class.handle_no_command_error(name) end end end DynamicTask = DynamicCommand end PKu]ᡇ++Abundler-2.2.24/lib/bundler/vendor/thor/lib/thor/nested_context.rbnu[class Bundler::Thor class NestedContext def initialize @depth = 0 end def enter push yield ensure pop end def entered? @depth > 0 end private def push @depth += 1 end def pop @depth -= 1 end end end PKu]_-[II=bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/invocation.rbnu[class Bundler::Thor module Invocation def self.included(base) #:nodoc: super(base) base.extend ClassMethods end module ClassMethods # This method is responsible for receiving a name and find the proper # class and command for it. The key is an optional parameter which is # available only in class methods invocations (i.e. in Bundler::Thor::Group). def prepare_for_invocation(key, name) #:nodoc: case name when Symbol, String Bundler::Thor::Util.find_class_and_command_by_namespace(name.to_s, !key) else name end end end # Make initializer aware of invocations and the initialization args. def initialize(args = [], options = {}, config = {}, &block) #:nodoc: @_invocations = config[:invocations] || Hash.new { |h, k| h[k] = [] } @_initializer = [args, options, config] super end # Make the current command chain accessible with in a Bundler::Thor-(sub)command def current_command_chain @_invocations.values.flatten.map(&:to_sym) end # Receives a name and invokes it. The name can be a string (either "command" or # "namespace:command"), a Bundler::Thor::Command, a Class or a Bundler::Thor instance. If the # command cannot be guessed by name, it can also be supplied as second argument. # # You can also supply the arguments, options and configuration values for # the command to be invoked, if none is given, the same values used to # initialize the invoker are used to initialize the invoked. # # When no name is given, it will invoke the default command of the current class. # # ==== Examples # # class A < Bundler::Thor # def foo # invoke :bar # invoke "b:hello", ["Erik"] # end # # def bar # invoke "b:hello", ["Erik"] # end # end # # class B < Bundler::Thor # def hello(name) # puts "hello #{name}" # end # end # # You can notice that the method "foo" above invokes two commands: "bar", # which belongs to the same class and "hello" which belongs to the class B. # # By using an invocation system you ensure that a command is invoked only once. # In the example above, invoking "foo" will invoke "b:hello" just once, even # if it's invoked later by "bar" method. # # When class A invokes class B, all arguments used on A initialization are # supplied to B. This allows lazy parse of options. Let's suppose you have # some rspec commands: # # class Rspec < Bundler::Thor::Group # class_option :mock_framework, :type => :string, :default => :rr # # def invoke_mock_framework # invoke "rspec:#{options[:mock_framework]}" # end # end # # As you noticed, it invokes the given mock framework, which might have its # own options: # # class Rspec::RR < Bundler::Thor::Group # class_option :style, :type => :string, :default => :mock # end # # Since it's not rspec concern to parse mock framework options, when RR # is invoked all options are parsed again, so RR can extract only the options # that it's going to use. # # If you want Rspec::RR to be initialized with its own set of options, you # have to do that explicitly: # # invoke "rspec:rr", [], :style => :foo # # Besides giving an instance, you can also give a class to invoke: # # invoke Rspec::RR, [], :style => :foo # def invoke(name = nil, *args) if name.nil? warn "[Bundler::Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}" return invoke_all end args.unshift(nil) if args.first.is_a?(Array) || args.first.nil? command, args, opts, config = args klass, command = _retrieve_class_and_command(name, command) raise "Missing Bundler::Thor class for invoke #{name}" unless klass raise "Expected Bundler::Thor class, got #{klass}" unless klass <= Bundler::Thor::Base args, opts, config = _parse_initialization_options(args, opts, config) klass.send(:dispatch, command, args, opts, config) do |instance| instance.parent_options = options end end # Invoke the given command if the given args. def invoke_command(command, *args) #:nodoc: current = @_invocations[self.class] unless current.include?(command.name) current << command.name command.run(self, *args) end end alias_method :invoke_task, :invoke_command # Invoke all commands for the current instance. def invoke_all #:nodoc: self.class.all_commands.map { |_, command| invoke_command(command) } end # Invokes using shell padding. def invoke_with_padding(*args) with_padding { invoke(*args) } end protected # Configuration values that are shared between invocations. def _shared_configuration #:nodoc: {:invocations => @_invocations} end # This method simply retrieves the class and command to be invoked. # If the name is nil or the given name is a command in the current class, # use the given name and return self as class. Otherwise, call # prepare_for_invocation in the current class. def _retrieve_class_and_command(name, sent_command = nil) #:nodoc: if name.nil? [self.class, nil] elsif self.class.all_commands[name.to_s] [self.class, name.to_s] else klass, command = self.class.prepare_for_invocation(nil, name) [klass, command || sent_command] end end alias_method :_retrieve_class_and_task, :_retrieve_class_and_command # Initialize klass using values stored in the @_initializer. def _parse_initialization_options(args, opts, config) #:nodoc: stored_args, stored_opts, stored_config = @_initializer args ||= stored_args.dup opts ||= stored_opts.dup config ||= {} config = stored_config.merge(_shared_configuration).merge!(config) [args, opts, config] end end end PKu]5,,:bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/version.rbnu[class Bundler::Thor VERSION = "1.1.0" end PKu]8Xbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rbnu[class Bundler::Thor module CoreExt #:nodoc: # A hash with indifferent access and magic predicates. # # hash = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true # # hash[:foo] #=> 'bar' # hash['foo'] #=> 'bar' # hash.foo? #=> true # class HashWithIndifferentAccess < ::Hash #:nodoc: def initialize(hash = {}) super() hash.each do |key, value| self[convert_key(key)] = value end end def [](key) super(convert_key(key)) end def []=(key, value) super(convert_key(key), value) end def delete(key) super(convert_key(key)) end def fetch(key, *args) super(convert_key(key), *args) end def key?(key) super(convert_key(key)) end def values_at(*indices) indices.map { |key| self[convert_key(key)] } end def merge(other) dup.merge!(other) end def merge!(other) other.each do |key, value| self[convert_key(key)] = value end self end def reverse_merge(other) self.class.new(other).merge(self) end def reverse_merge!(other_hash) replace(reverse_merge(other_hash)) end def replace(other_hash) super(other_hash) end # Convert to a Hash with String keys. def to_hash Hash.new(default).merge!(self) end protected def convert_key(key) key.is_a?(Symbol) ? key.to_s : key end # Magic predicates. For instance: # # options.force? # => !!options['force'] # options.shebang # => "/usr/lib/local/ruby" # options.test_framework?(:rspec) # => options[:test_framework] == :rspec # def method_missing(method, *args) method = method.to_s if method =~ /^(\w+)\?$/ if args.empty? !!self[$1] else self[$1] == args.first end else self[method] end end end end end PKu]dq=77Gbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rbnu[class Bundler::Thor module LineEditor class Readline < Basic def self.available? begin require "readline" rescue LoadError end Object.const_defined?(:Readline) end def readline if echo? ::Readline.completion_append_character = nil # rb-readline does not allow Readline.completion_proc= to receive nil. if complete = completion_proc ::Readline.completion_proc = complete end ::Readline.readline(prompt, add_to_history?) else super end end private def add_to_history? options.fetch(:add_to_history, true) end def completion_proc if use_path_completion? proc { |text| PathCompletion.new(text).matches } elsif completion_options.any? proc do |text| completion_options.select { |option| option.start_with?(text) } end end end def completion_options options.fetch(:limited_to, []) end def use_path_completion? options.fetch(:path, false) end class PathCompletion attr_reader :text private :text def initialize(text) @text = text end def matches relative_matches end private def relative_matches absolute_matches.map { |path| path.sub(base_path, "") } end def absolute_matches Dir[glob_pattern].map do |path| if File.directory?(path) "#{path}/" else path end end end def glob_pattern "#{base_path}#{text}*" end def base_path "#{Dir.pwd}/" end end end end end PKu]Yt}}Dbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rbnu[class Bundler::Thor module LineEditor class Basic attr_reader :prompt, :options def self.available? true end def initialize(prompt, options) @prompt = prompt @options = options end def readline $stdout.print(prompt) get_input end private def get_input if echo? $stdin.gets else # Lazy-load io/console since it is gem-ified as of 2.3 require "io/console" $stdin.noecho(&:gets) end end def echo? options.fetch(:echo, true) end end end end PKu])):bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions.rbnu[require_relative "actions/create_file" require_relative "actions/create_link" require_relative "actions/directory" require_relative "actions/empty_directory" require_relative "actions/file_manipulation" require_relative "actions/inject_into_file" class Bundler::Thor module Actions attr_accessor :behavior def self.included(base) #:nodoc: super(base) base.extend ClassMethods end module ClassMethods # Hold source paths for one Bundler::Thor instance. source_paths_for_search is the # method responsible to gather source_paths from this current class, # inherited paths and the source root. # def source_paths @_source_paths ||= [] end # Stores and return the source root for this class def source_root(path = nil) @_source_root = path if path @_source_root ||= nil end # Returns the source paths in the following order: # # 1) This class source paths # 2) Source root # 3) Parents source paths # def source_paths_for_search paths = [] paths += source_paths paths << source_root if source_root paths += from_superclass(:source_paths, []) paths end # Add runtime options that help actions execution. # def add_runtime_options! class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime, :desc => "Overwrite files that already exist" class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime, :desc => "Run but do not make any changes" class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime, :desc => "Suppress status output" class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime, :desc => "Skip files that already exist" end end # Extends initializer to add more configuration options. # # ==== Configuration # behavior:: The actions default behavior. Can be :invoke or :revoke. # It also accepts :force, :skip and :pretend to set the behavior # and the respective option. # # destination_root:: The root directory needed for some actions. # def initialize(args = [], options = {}, config = {}) self.behavior = case config[:behavior].to_s when "force", "skip" _cleanup_options_and_set(options, config[:behavior]) :invoke when "revoke" :revoke else :invoke end super self.destination_root = config[:destination_root] end # Wraps an action object and call it accordingly to the thor class behavior. # def action(instance) #:nodoc: if behavior == :revoke instance.revoke! else instance.invoke! end end # Returns the root for this thor class (also aliased as destination root). # def destination_root @destination_stack.last end # Sets the root for this thor class. Relatives path are added to the # directory where the script was invoked and expanded. # def destination_root=(root) @destination_stack ||= [] @destination_stack[0] = File.expand_path(root || "") end # Returns the given path relative to the absolute root (ie, root where # the script started). # def relative_to_original_destination_root(path, remove_dot = true) root = @destination_stack[0] if path.start_with?(root) && [File::SEPARATOR, File::ALT_SEPARATOR, nil, ''].include?(path[root.size..root.size]) path = path.dup path[0...root.size] = '.' remove_dot ? (path[2..-1] || "") : path else path end end # Holds source paths in instance so they can be manipulated. # def source_paths @source_paths ||= self.class.source_paths_for_search end # Receives a file or directory and search for it in the source paths. # def find_in_source_paths(file) possible_files = [file, file + TEMPLATE_EXTNAME] relative_root = relative_to_original_destination_root(destination_root, false) source_paths.each do |source| possible_files.each do |f| source_file = File.expand_path(f, File.join(source, relative_root)) return source_file if File.exist?(source_file) end end message = "Could not find #{file.inspect} in any of your source paths. ".dup unless self.class.source_root message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. " end message << if source_paths.empty? "Currently you have no source paths." else "Your current source paths are: \n#{source_paths.join("\n")}" end raise Error, message end # Do something in the root or on a provided subfolder. If a relative path # is given it's referenced from the current root. The full path is yielded # to the block you provide. The path is set back to the previous path when # the method exits. # # ==== Parameters # dir:: the directory to move to. # config:: give :verbose => true to log and use padding. # def inside(dir = "", config = {}, &block) verbose = config.fetch(:verbose, false) pretend = options[:pretend] say_status :inside, dir, verbose shell.padding += 1 if verbose @destination_stack.push File.expand_path(dir, destination_root) # If the directory doesnt exist and we're not pretending if !File.exist?(destination_root) && !pretend require "fileutils" FileUtils.mkdir_p(destination_root) end if pretend # In pretend mode, just yield down to the block block.arity == 1 ? yield(destination_root) : yield else require "fileutils" FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield } end @destination_stack.pop shell.padding -= 1 if verbose end # Goes to the root and execute the given block. # def in_root inside(@destination_stack.first) { yield } end # Loads an external file and execute it in the instance binding. # # ==== Parameters # path:: The path to the file to execute. Can be a web address or # a relative path from the source root. # # ==== Examples # # apply "http://gist.github.com/103208" # # apply "recipes/jquery.rb" # def apply(path, config = {}) verbose = config.fetch(:verbose, true) is_uri = path =~ %r{^https?\://} path = find_in_source_paths(path) unless is_uri say_status :apply, path, verbose shell.padding += 1 if verbose contents = if is_uri require "open-uri" URI.open(path, "Accept" => "application/x-thor-template", &:read) else open(path, &:read) end instance_eval(contents, path) shell.padding -= 1 if verbose end # Executes a command returning the contents of the command. # # ==== Parameters # command:: the command to be executed. # config:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with # to append an executable to command execution. # # ==== Example # # inside('vendor') do # run('ln -s ~/edge rails') # end # def run(command, config = {}) return unless behavior == :invoke destination = relative_to_original_destination_root(destination_root, false) desc = "#{command} from #{destination.inspect}" if config[:with] desc = "#{File.basename(config[:with].to_s)} #{desc}" command = "#{config[:with]} #{command}" end say_status :run, desc, config.fetch(:verbose, true) return if options[:pretend] env_splat = [config[:env]] if config[:env] if config[:capture] require "open3" result, status = Open3.capture2e(*env_splat, command.to_s) success = status.success? else result = system(*env_splat, command.to_s) success = result end abort if !success && config.fetch(:abort_on_failure, self.class.exit_on_failure?) result end # Executes a ruby script (taking into account WIN32 platform quirks). # # ==== Parameters # command:: the command to be executed. # config:: give :verbose => false to not log the status. # def run_ruby_script(command, config = {}) return unless behavior == :invoke run command, config.merge(:with => Bundler::Thor::Util.ruby_command) end # Run a thor command. A hash of options can be given and it's converted to # switches. # # ==== Parameters # command:: the command to be invoked # args:: arguments to the command # config:: give :verbose => false to not log the status, :capture => true to hide to output. # Other options are given as parameter to Bundler::Thor. # # # ==== Examples # # thor :install, "http://gist.github.com/103208" # #=> thor install http://gist.github.com/103208 # # thor :list, :all => true, :substring => 'rails' # #=> thor list --all --substring=rails # def thor(command, *args) config = args.last.is_a?(Hash) ? args.pop : {} verbose = config.key?(:verbose) ? config.delete(:verbose) : true pretend = config.key?(:pretend) ? config.delete(:pretend) : false capture = config.key?(:capture) ? config.delete(:capture) : false args.unshift(command) args.push Bundler::Thor::Options.to_switches(config) command = args.join(" ").strip run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture end protected # Allow current root to be shared between invocations. # def _shared_configuration #:nodoc: super.merge!(:destination_root => destination_root) end def _cleanup_options_and_set(options, key) #:nodoc: case options when Array %w(--force -f --skip -s).each { |i| options.delete(i) } options << "--#{key}" when Hash [:force, :skip, "force", "skip"].each { |i| options.delete(i) } options.merge!(key => true) end end end end PKu]``7bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/base.rbnu[require_relative "command" require_relative "core_ext/hash_with_indifferent_access" require_relative "error" require_relative "invocation" require_relative "nested_context" require_relative "parser" require_relative "shell" require_relative "line_editor" require_relative "util" class Bundler::Thor autoload :Actions, File.expand_path("actions", __dir__) autoload :RakeCompat, File.expand_path("rake_compat", __dir__) autoload :Group, File.expand_path("group", __dir__) # Shortcuts for help. HELP_MAPPINGS = %w(-h -? --help -D) # Bundler::Thor methods that should not be overwritten by the user. THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root action add_file create_file in_root inside run run_ruby_script) TEMPLATE_EXTNAME = ".tt" class << self def deprecation_warning(message) #:nodoc: unless ENV['THOR_SILENCE_DEPRECATION'] warn "Deprecation warning: #{message}\n" + 'You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.' end end end module Base attr_accessor :options, :parent_options, :args # It receives arguments in an Array and two hashes, one for options and # other for configuration. # # Notice that it does not check if all required arguments were supplied. # It should be done by the parser. # # ==== Parameters # args:: An array of objects. The objects are applied to their # respective accessors declared with argument. # # options:: An options hash that will be available as self.options. # The hash given is converted to a hash with indifferent # access, magic predicates (options.skip?) and then frozen. # # config:: Configuration for this Bundler::Thor class. # def initialize(args = [], local_options = {}, config = {}) parse_options = self.class.class_options # The start method splits inbound arguments at the first argument # that looks like an option (starts with - or --). It then calls # new, passing in the two halves of the arguments Array as the # first two parameters. command_options = config.delete(:command_options) # hook for start parse_options = parse_options.merge(command_options) if command_options if local_options.is_a?(Array) array_options = local_options hash_options = {} else # Handle the case where the class was explicitly instantiated # with pre-parsed options. array_options = [] hash_options = local_options end # Let Bundler::Thor::Options parse the options first, so it can remove # declared options from the array. This will leave us with # a list of arguments that weren't declared. stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command] disable_required_check = self.class.disable_required_check? config[:current_command] opts = Bundler::Thor::Options.new(parse_options, hash_options, stop_on_unknown, disable_required_check) self.options = opts.parse(array_options) self.options = config[:class_options].merge(options) if config[:class_options] # If unknown options are disallowed, make sure that none of the # remaining arguments looks like an option. opts.check_unknown! if self.class.check_unknown_options?(config) # Add the remaining arguments from the options parser to the # arguments passed in to initialize. Then remove any positional # arguments declared using #argument (this is primarily used # by Bundler::Thor::Group). Tis will leave us with the remaining # positional arguments. to_parse = args to_parse += opts.remaining unless self.class.strict_args_position?(config) thor_args = Bundler::Thor::Arguments.new(self.class.arguments) thor_args.parse(to_parse).each { |k, v| __send__("#{k}=", v) } @args = thor_args.remaining end class << self def included(base) #:nodoc: super(base) base.extend ClassMethods base.send :include, Invocation base.send :include, Shell end # Returns the classes that inherits from Bundler::Thor or Bundler::Thor::Group. # # ==== Returns # Array[Class] # def subclasses @subclasses ||= [] end # Returns the files where the subclasses are kept. # # ==== Returns # Hash[path => Class] # def subclass_files @subclass_files ||= Hash.new { |h, k| h[k] = [] } end # Whenever a class inherits from Bundler::Thor or Bundler::Thor::Group, we should track the # class and the file on Bundler::Thor::Base. This is the method responsible for it. # def register_klass_file(klass) #:nodoc: file = caller[1].match(/(.*):\d+/)[1] Bundler::Thor::Base.subclasses << klass unless Bundler::Thor::Base.subclasses.include?(klass) file_subclasses = Bundler::Thor::Base.subclass_files[File.expand_path(file)] file_subclasses << klass unless file_subclasses.include?(klass) end end module ClassMethods def attr_reader(*) #:nodoc: no_commands { super } end def attr_writer(*) #:nodoc: no_commands { super } end def attr_accessor(*) #:nodoc: no_commands { super } end # If you want to raise an error for unknown options, call check_unknown_options! # This is disabled by default to allow dynamic invocations. def check_unknown_options! @check_unknown_options = true end def check_unknown_options #:nodoc: @check_unknown_options ||= from_superclass(:check_unknown_options, false) end def check_unknown_options?(config) #:nodoc: !!check_unknown_options end # If you want to raise an error when the default value of an option does not match # the type call check_default_type! # This will be the default; for compatibility a deprecation warning is issued if necessary. def check_default_type! @check_default_type = true end # If you want to use defaults that don't match the type of an option, # either specify `check_default_type: false` or call `allow_incompatible_default_type!` def allow_incompatible_default_type! @check_default_type = false end def check_default_type #:nodoc: @check_default_type = from_superclass(:check_default_type, nil) unless defined?(@check_default_type) @check_default_type end # If true, option parsing is suspended as soon as an unknown option or a # regular argument is encountered. All remaining arguments are passed to # the command as regular arguments. def stop_on_unknown_option?(command_name) #:nodoc: false end # If true, option set will not suspend the execution of the command when # a required option is not provided. def disable_required_check?(command_name) #:nodoc: false end # If you want only strict string args (useful when cascading thor classes), # call strict_args_position! This is disabled by default to allow dynamic # invocations. def strict_args_position! @strict_args_position = true end def strict_args_position #:nodoc: @strict_args_position ||= from_superclass(:strict_args_position, false) end def strict_args_position?(config) #:nodoc: !!strict_args_position end # Adds an argument to the class and creates an attr_accessor for it. # # Arguments are different from options in several aspects. The first one # is how they are parsed from the command line, arguments are retrieved # from position: # # thor command NAME # # Instead of: # # thor command --name=NAME # # Besides, arguments are used inside your code as an accessor (self.argument), # while options are all kept in a hash (self.options). # # Finally, arguments cannot have type :default or :boolean but can be # optional (supplying :optional => :true or :required => false), although # you cannot have a required argument after a non-required argument. If you # try it, an error is raised. # # ==== Parameters # name:: The name of the argument. # options:: Described below. # # ==== Options # :desc - Description for the argument. # :required - If the argument is required or not. # :optional - If the argument is optional or not. # :type - The type of the argument, can be :string, :hash, :array, :numeric. # :default - Default value for this argument. It cannot be required and have default values. # :banner - String to show on usage notes. # # ==== Errors # ArgumentError:: Raised if you supply a required argument after a non required one. # def argument(name, options = {}) is_thor_reserved_word?(name, :argument) no_commands { attr_accessor name } required = if options.key?(:optional) !options[:optional] elsif options.key?(:required) options[:required] else options[:default].nil? end remove_argument name if required arguments.each do |argument| next if argument.required? raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " \ "the non-required argument #{argument.human_name.inspect}." end end options[:required] = required arguments << Bundler::Thor::Argument.new(name, options) end # Returns this class arguments, looking up in the ancestors chain. # # ==== Returns # Array[Bundler::Thor::Argument] # def arguments @arguments ||= from_superclass(:arguments, []) end # Adds a bunch of options to the set of class options. # # class_options :foo => false, :bar => :required, :baz => :string # # If you prefer more detailed declaration, check class_option. # # ==== Parameters # Hash[Symbol => Object] # def class_options(options = nil) @class_options ||= from_superclass(:class_options, {}) build_options(options, @class_options) if options @class_options end # Adds an option to the set of class options # # ==== Parameters # name:: The name of the argument. # options:: Described below. # # ==== Options # :desc:: -- Description for the argument. # :required:: -- If the argument is required or not. # :default:: -- Default value for this argument. # :group:: -- The group for this options. Use by class options to output options in different levels. # :aliases:: -- Aliases for this option. Note: Bundler::Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead. # :type:: -- The type of the argument, can be :string, :hash, :array, :numeric or :boolean. # :banner:: -- String to show on usage notes. # :hide:: -- If you want to hide this option from the help. # def class_option(name, options = {}) build_option(name, options, class_options) end # Removes a previous defined argument. If :undefine is given, undefine # accessors as well. # # ==== Parameters # names:: Arguments to be removed # # ==== Examples # # remove_argument :foo # remove_argument :foo, :bar, :baz, :undefine => true # def remove_argument(*names) options = names.last.is_a?(Hash) ? names.pop : {} names.each do |name| arguments.delete_if { |a| a.name == name.to_s } undef_method name, "#{name}=" if options[:undefine] end end # Removes a previous defined class option. # # ==== Parameters # names:: Class options to be removed # # ==== Examples # # remove_class_option :foo # remove_class_option :foo, :bar, :baz # def remove_class_option(*names) names.each do |name| class_options.delete(name) end end # Defines the group. This is used when thor list is invoked so you can specify # that only commands from a pre-defined group will be shown. Defaults to standard. # # ==== Parameters # name # def group(name = nil) if name @group = name.to_s else @group ||= from_superclass(:group, "standard") end end # Returns the commands for this Bundler::Thor class. # # ==== Returns # Hash:: An ordered hash with commands names as keys and Bundler::Thor::Command # objects as values. # def commands @commands ||= Hash.new end alias_method :tasks, :commands # Returns the commands for this Bundler::Thor class and all subclasses. # # ==== Returns # Hash:: An ordered hash with commands names as keys and Bundler::Thor::Command # objects as values. # def all_commands @all_commands ||= from_superclass(:all_commands, Hash.new) @all_commands.merge!(commands) end alias_method :all_tasks, :all_commands # Removes a given command from this Bundler::Thor class. This is usually done if you # are inheriting from another class and don't want it to be available # anymore. # # By default it only remove the mapping to the command. But you can supply # :undefine => true to undefine the method from the class as well. # # ==== Parameters # name:: The name of the command to be removed # options:: You can give :undefine => true if you want commands the method # to be undefined from the class as well. # def remove_command(*names) options = names.last.is_a?(Hash) ? names.pop : {} names.each do |name| commands.delete(name.to_s) all_commands.delete(name.to_s) undef_method name if options[:undefine] end end alias_method :remove_task, :remove_command # All methods defined inside the given block are not added as commands. # # So you can do: # # class MyScript < Bundler::Thor # no_commands do # def this_is_not_a_command # end # end # end # # You can also add the method and remove it from the command list: # # class MyScript < Bundler::Thor # def this_is_not_a_command # end # remove_command :this_is_not_a_command # end # def no_commands(&block) no_commands_context.enter(&block) end alias_method :no_tasks, :no_commands def no_commands_context @no_commands_context ||= NestedContext.new end def no_commands? no_commands_context.entered? end # Sets the namespace for the Bundler::Thor or Bundler::Thor::Group class. By default the # namespace is retrieved from the class name. If your Bundler::Thor class is named # Scripts::MyScript, the help method, for example, will be called as: # # thor scripts:my_script -h # # If you change the namespace: # # namespace :my_scripts # # You change how your commands are invoked: # # thor my_scripts -h # # Finally, if you change your namespace to default: # # namespace :default # # Your commands can be invoked with a shortcut. Instead of: # # thor :my_command # def namespace(name = nil) if name @namespace = name.to_s else @namespace ||= Bundler::Thor::Util.namespace_from_thor_class(self) end end # Parses the command and options from the given args, instantiate the class # and invoke the command. This method is used when the arguments must be parsed # from an array. If you are inside Ruby and want to use a Bundler::Thor class, you # can simply initialize it: # # script = MyScript.new(args, options, config) # script.invoke(:command, first_arg, second_arg, third_arg) # def start(given_args = ARGV, config = {}) config[:shell] ||= Bundler::Thor::Base.shell.new dispatch(nil, given_args.dup, nil, config) rescue Bundler::Thor::Error => e config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message) exit(false) if exit_on_failure? rescue Errno::EPIPE # This happens if a thor command is piped to something like `head`, # which closes the pipe when it's done reading. This will also # mean that if the pipe is closed, further unnecessary # computation will not occur. exit(true) end # Allows to use private methods from parent in child classes as commands. # # ==== Parameters # names:: Method names to be used as commands # # ==== Examples # # public_command :foo # public_command :foo, :bar, :baz # def public_command(*names) names.each do |name| class_eval "def #{name}(*); super end" end end alias_method :public_task, :public_command def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc: raise UndefinedCommandError.new(command, all_commands.keys, (namespace if has_namespace)) end alias_method :handle_no_task_error, :handle_no_command_error def handle_argument_error(command, error, args, arity) #:nodoc: name = [command.ancestor_name, command.name].compact.join(" ") msg = "ERROR: \"#{basename} #{name}\" was called with ".dup msg << "no arguments" if args.empty? msg << "arguments " << args.inspect unless args.empty? msg << "\nUsage: \"#{banner(command).split("\n").join("\"\n \"")}\"" raise InvocationError, msg end # A flag that makes the process exit with status 1 if any error happens. def exit_on_failure? Bundler::Thor.deprecation_warning "Bundler::Thor exit with status 0 on errors. To keep this behavior, you must define `exit_on_failure?` in `#{self.name}`" false end protected # Prints the class options per group. If an option does not belong to # any group, it's printed as Class option. # def class_options_help(shell, groups = {}) #:nodoc: # Group options by group class_options.each do |_, value| groups[value.group] ||= [] groups[value.group] << value end # Deal with default group global_options = groups.delete(nil) || [] print_options(shell, global_options) # Print all others groups.each do |group_name, options| print_options(shell, options, group_name) end end # Receives a set of options and print them. def print_options(shell, options, group_name = nil) return if options.empty? list = [] padding = options.map { |o| o.aliases.size }.max.to_i * 4 options.each do |option| next if option.hide item = [option.usage(padding)] item.push(option.description ? "# #{option.description}" : "") list << item list << ["", "# Default: #{option.default}"] if option.show_default? list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum end shell.say(group_name ? "#{group_name} options:" : "Options:") shell.print_table(list, :indent => 2) shell.say "" end # Raises an error if the word given is a Bundler::Thor reserved word. def is_thor_reserved_word?(word, type) #:nodoc: return false unless THOR_RESERVED_WORDS.include?(word.to_s) raise "#{word.inspect} is a Bundler::Thor reserved word and cannot be defined as #{type}" end # Build an option and adds it to the given scope. # # ==== Parameters # name:: The name of the argument. # options:: Described in both class_option and method_option. # scope:: Options hash that is being built up def build_option(name, options, scope) #:nodoc: scope[name] = Bundler::Thor::Option.new(name, {:check_default_type => check_default_type}.merge!(options)) end # Receives a hash of options, parse them and add to the scope. This is a # fast way to set a bunch of options: # # build_options :foo => true, :bar => :required, :baz => :string # # ==== Parameters # Hash[Symbol => Object] def build_options(options, scope) #:nodoc: options.each do |key, value| scope[key] = Bundler::Thor::Option.parse(key, value) end end # Finds a command with the given name. If the command belongs to the current # class, just return it, otherwise dup it and add the fresh copy to the # current command hash. def find_and_refresh_command(name) #:nodoc: if commands[name.to_s] commands[name.to_s] elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition commands[name.to_s] = command.clone else raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found." end end alias_method :find_and_refresh_task, :find_and_refresh_command # Everytime someone inherits from a Bundler::Thor class, register the klass # and file into baseclass. def inherited(klass) super(klass) Bundler::Thor::Base.register_klass_file(klass) klass.instance_variable_set(:@no_commands, 0) end # Fire this callback whenever a method is added. Added methods are # tracked as commands by invoking the create_command method. def method_added(meth) super(meth) meth = meth.to_s if meth == "initialize" initialize_added return end # Return if it's not a public instance method return unless public_method_defined?(meth.to_sym) return if no_commands? || !create_command(meth) is_thor_reserved_word?(meth, :command) Bundler::Thor::Base.register_klass_file(self) end # Retrieves a value from superclass. If it reaches the baseclass, # returns default. def from_superclass(method, default = nil) if self == baseclass || !superclass.respond_to?(method, true) default else value = superclass.send(method) # Ruby implements `dup` on Object, but raises a `TypeError` # if the method is called on immediates. As a result, we # don't have a good way to check whether dup will succeed # without calling it and rescuing the TypeError. begin value.dup rescue TypeError value end end end # # The basename of the program invoking the thor class. # def basename File.basename($PROGRAM_NAME).split(" ").first end # SIGNATURE: Sets the baseclass. This is where the superclass lookup # finishes. def baseclass #:nodoc: end # SIGNATURE: Creates a new command if valid_command? is true. This method is # called when a new method is added to the class. def create_command(meth) #:nodoc: end alias_method :create_task, :create_command # SIGNATURE: Defines behavior when the initialize method is added to the # class. def initialize_added #:nodoc: end # SIGNATURE: The hook invoked by start. def dispatch(command, given_args, given_opts, config) #:nodoc: raise NotImplementedError end end end end PKu]P?% % 8bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell.rbnu[require "rbconfig" class Bundler::Thor module Base class << self attr_writer :shell # Returns the shell used in all Bundler::Thor classes. If you are in a Unix platform # it will use a colored log, otherwise it will use a basic one without color. # def shell @shell ||= if ENV["THOR_SHELL"] && !ENV["THOR_SHELL"].empty? Bundler::Thor::Shell.const_get(ENV["THOR_SHELL"]) elsif RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ && !ENV["ANSICON"] Bundler::Thor::Shell::Basic else Bundler::Thor::Shell::Color end end end end module Shell SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width] attr_writer :shell autoload :Basic, File.expand_path("shell/basic", __dir__) autoload :Color, File.expand_path("shell/color", __dir__) autoload :HTML, File.expand_path("shell/html", __dir__) # Add shell to initialize config values. # # ==== Configuration # shell:: An instance of the shell to be used. # # ==== Examples # # class MyScript < Bundler::Thor # argument :first, :type => :numeric # end # # MyScript.new [1.0], { :foo => :bar }, :shell => Bundler::Thor::Shell::Basic.new # def initialize(args = [], options = {}, config = {}) super self.shell = config[:shell] shell.base ||= self if shell.respond_to?(:base) end # Holds the shell for the given Bundler::Thor instance. If no shell is given, # it gets a default shell from Bundler::Thor::Base.shell. def shell @shell ||= Bundler::Thor::Base.shell.new end # Common methods that are delegated to the shell. SHELL_DELEGATED_METHODS.each do |method| module_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{method}(*args,&block) shell.#{method}(*args,&block) end METHOD end # Yields the given block with padding. def with_padding shell.padding += 1 yield ensure shell.padding -= 1 end protected # Allow shell to be shared between invocations. # def _shared_configuration #:nodoc: super.merge!(:shell => shell) end end end PKu](_b'b'9bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/runner.rbnu[require_relative "../thor" require_relative "group" require "yaml" require "digest/md5" require "pathname" class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLength autoload :OpenURI, "open-uri" map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version def self.banner(command, all = false, subcommand = false) "thor " + command.formatted_usage(self, all, subcommand) end def self.exit_on_failure? true end # Override Bundler::Thor#help so it can give information about any class and any method. # def help(meth = nil) if meth && !respond_to?(meth) initialize_thorfiles(meth) klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth) self.class.handle_no_command_error(command, false) if klass.nil? klass.start(["-h", command].compact, :shell => shell) else super end end # If a command is not found on Bundler::Thor::Runner, method missing is invoked and # Bundler::Thor::Runner is then responsible for finding the command in all classes. # def method_missing(meth, *args) meth = meth.to_s initialize_thorfiles(meth) klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth) self.class.handle_no_command_error(command, false) if klass.nil? args.unshift(command) if command klass.start(args, :shell => shell) end desc "install NAME", "Install an optionally named Bundler::Thor file into your system commands" method_options :as => :string, :relative => :boolean, :force => :boolean def install(name) # rubocop:disable MethodLength initialize_thorfiles # If a directory name is provided as the argument, look for a 'main.thor' # command in said directory. begin if File.directory?(File.expand_path(name)) base = File.join(name, "main.thor") package = :directory contents = open(base, &:read) else base = name package = :file contents = open(name, &:read) end rescue OpenURI::HTTPError raise Error, "Error opening URI '#{name}'" rescue Errno::ENOENT raise Error, "Error opening file '#{name}'" end say "Your Thorfile contains:" say contents unless options["force"] return false if no?("Do you wish to continue [y/N]?") end as = options["as"] || begin first_line = contents.split("\n")[0] (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil end unless as basename = File.basename(name) as = ask("Please specify a name for #{name} in the system repository [#{basename}]:") as = basename if as.empty? end location = if options[:relative] || name =~ %r{^https?://} name else File.expand_path(name) end thor_yaml[as] = { :filename => Digest::MD5.hexdigest(name + as), :location => location, :namespaces => Bundler::Thor::Util.namespaces_in_content(contents, base) } save_yaml(thor_yaml) say "Storing thor file in your system repository" destination = File.join(thor_root, thor_yaml[as][:filename]) if package == :file File.open(destination, "w") { |f| f.puts contents } else require "fileutils" FileUtils.cp_r(name, destination) end thor_yaml[as][:filename] # Indicate success end desc "version", "Show Bundler::Thor version" def version require_relative "version" say "Bundler::Thor #{Bundler::Thor::VERSION}" end desc "uninstall NAME", "Uninstall a named Bundler::Thor module" def uninstall(name) raise Error, "Can't find module '#{name}'" unless thor_yaml[name] say "Uninstalling #{name}." require "fileutils" FileUtils.rm_rf(File.join(thor_root, (thor_yaml[name][:filename]).to_s)) thor_yaml.delete(name) save_yaml(thor_yaml) puts "Done." end desc "update NAME", "Update a Bundler::Thor file from its original location" def update(name) raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location] say "Updating '#{name}' from #{thor_yaml[name][:location]}" old_filename = thor_yaml[name][:filename] self.options = options.merge("as" => name) if File.directory? File.expand_path(name) require "fileutils" FileUtils.rm_rf(File.join(thor_root, old_filename)) thor_yaml.delete(old_filename) save_yaml(thor_yaml) filename = install(name) else filename = install(thor_yaml[name][:location]) end File.delete(File.join(thor_root, old_filename)) unless filename == old_filename end desc "installed", "List the installed Bundler::Thor modules and commands" method_options :internal => :boolean def installed initialize_thorfiles(nil, true) display_klasses(true, options["internal"]) end desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)" method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean def list(search = "") initialize_thorfiles search = ".*#{search}" if options["substring"] search = /^#{search}.*/i group = options[:group] || "standard" klasses = Bundler::Thor::Base.subclasses.select do |k| (options[:all] || k.group == group) && k.namespace =~ search end display_klasses(false, false, klasses) end private def thor_root Bundler::Thor::Util.thor_root end def thor_yaml @thor_yaml ||= begin yaml_file = File.join(thor_root, "thor.yml") yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file) yaml || {} end end # Save the yaml file. If none exists in thor root, creates one. # def save_yaml(yaml) yaml_file = File.join(thor_root, "thor.yml") unless File.exist?(yaml_file) require "fileutils" FileUtils.mkdir_p(thor_root) yaml_file = File.join(thor_root, "thor.yml") FileUtils.touch(yaml_file) end File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml } end # Load the Thorfiles. If relevant_to is supplied, looks for specific files # in the thor_root instead of loading them all. # # By default, it also traverses the current path until find Bundler::Thor files, as # described in thorfiles. This look up can be skipped by supplying # skip_lookup true. # def initialize_thorfiles(relevant_to = nil, skip_lookup = false) thorfiles(relevant_to, skip_lookup).each do |f| Bundler::Thor::Util.load_thorfile(f, nil, options[:debug]) unless Bundler::Thor::Base.subclass_files.keys.include?(File.expand_path(f)) end end # Finds Thorfiles by traversing from your current directory down to the root # directory of your system. If at any time we find a Bundler::Thor file, we stop. # # We also ensure that system-wide Thorfiles are loaded first, so local # Thorfiles can override them. # # ==== Example # # If we start at /Users/wycats/dev/thor ... # # 1. /Users/wycats/dev/thor # 2. /Users/wycats/dev # 3. /Users/wycats <-- we find a Thorfile here, so we stop # # Suppose we start at c:\Documents and Settings\james\dev\thor ... # # 1. c:\Documents and Settings\james\dev\thor # 2. c:\Documents and Settings\james\dev # 3. c:\Documents and Settings\james # 4. c:\Documents and Settings # 5. c:\ <-- no Thorfiles found! # def thorfiles(relevant_to = nil, skip_lookup = false) thorfiles = [] unless skip_lookup Pathname.pwd.ascend do |path| thorfiles = Bundler::Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten break unless thorfiles.empty? end end files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Bundler::Thor::Util.thor_root_glob) files += thorfiles files -= ["#{thor_root}/thor.yml"] files.map! do |file| File.directory?(file) ? File.join(file, "main.thor") : file end end # Load Thorfiles relevant to the given method. If you provide "foo:bar" it # will load all thor files in the thor.yaml that has "foo" e "foo:bar" # namespaces registered. # def thorfiles_relevant_to(meth) lookup = [meth, meth.split(":")[0...-1].join(":")] files = thor_yaml.select do |_, v| v[:namespaces] && !(v[:namespaces] & lookup).empty? end files.map { |_, v| File.join(thor_root, (v[:filename]).to_s) } end # Display information about the given klasses. If with_module is given, # it shows a table with information extracted from the yaml file. # def display_klasses(with_modules = false, show_internal = false, klasses = Bundler::Thor::Base.subclasses) klasses -= [Bundler::Thor, Bundler::Thor::Runner, Bundler::Thor::Group] unless show_internal raise Error, "No Bundler::Thor commands available" if klasses.empty? show_modules if with_modules && !thor_yaml.empty? list = Hash.new { |h, k| h[k] = [] } groups = klasses.select { |k| k.ancestors.include?(Bundler::Thor::Group) } # Get classes which inherit from Bundler::Thor (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) } # Get classes which inherit from Bundler::Thor::Base groups.map! { |k| k.printable_commands(false).first } list["root"] = groups # Order namespaces with default coming first list = list.sort { |a, b| a[0].sub(/^default/, "") <=> b[0].sub(/^default/, "") } list.each { |n, commands| display_commands(n, commands) unless commands.empty? } end def display_commands(namespace, list) #:nodoc: list.sort! { |a, b| a[0] <=> b[0] } say shell.set_color(namespace, :blue, true) say "-" * namespace.size print_table(list, :truncate => true) say end alias_method :display_tasks, :display_commands def show_modules #:nodoc: info = [] labels = %w(Modules Namespaces) info << labels info << ["-" * labels[0].size, "-" * labels[1].size] thor_yaml.each do |name, hash| info << [name, hash[:namespaces].join(", ")] end print_table info say "" end end PKu]aq@bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/option.rbnu[class Bundler::Thor class Option < Argument #:nodoc: attr_reader :aliases, :group, :lazy_default, :hide, :repeatable VALID_TYPES = [:boolean, :numeric, :hash, :array, :string] def initialize(name, options = {}) @check_default_type = options[:check_default_type] options[:required] = false unless options.key?(:required) @repeatable = options.fetch(:repeatable, false) super @lazy_default = options[:lazy_default] @group = options[:group].to_s.capitalize if options[:group] @aliases = Array(options[:aliases]) @hide = options[:hide] end # This parse quick options given as method_options. It makes several # assumptions, but you can be more specific using the option method. # # parse :foo => "bar" # #=> Option foo with default value bar # # parse [:foo, :baz] => "bar" # #=> Option foo with default value bar and alias :baz # # parse :foo => :required # #=> Required option foo without default value # # parse :foo => 2 # #=> Option foo with default value 2 and type numeric # # parse :foo => :numeric # #=> Option foo without default value and type numeric # # parse :foo => true # #=> Option foo with default value true and type boolean # # The valid types are :boolean, :numeric, :hash, :array and :string. If none # is given a default type is assumed. This default type accepts arguments as # string (--foo=value) or booleans (just --foo). # # By default all options are optional, unless :required is given. # def self.parse(key, value) if key.is_a?(Array) name, *aliases = key else name = key aliases = [] end name = name.to_s default = value type = case value when Symbol default = nil if VALID_TYPES.include?(value) value elsif required = (value == :required) # rubocop:disable AssignmentInCondition :string end when TrueClass, FalseClass :boolean when Numeric :numeric when Hash, Array, String value.class.name.downcase.to_sym end new(name.to_s, :required => required, :type => type, :default => default, :aliases => aliases) end def switch_name @switch_name ||= dasherized? ? name : dasherize(name) end def human_name @human_name ||= dasherized? ? undasherize(name) : name end def usage(padding = 0) sample = if banner && !banner.to_s.empty? "#{switch_name}=#{banner}".dup else switch_name end sample = "[#{sample}]".dup unless required? if boolean? sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.start_with?("no-") end if aliases.empty? (" " * padding) << sample else "#{aliases.join(', ')}, #{sample}" end end VALID_TYPES.each do |type| class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{type}? self.type == #{type.inspect} end RUBY end protected def validate! raise ArgumentError, "An option cannot be boolean and required." if boolean? && required? validate_default_type! end def validate_default_type! default_type = case @default when nil return when TrueClass, FalseClass required? ? :string : :boolean when Numeric :numeric when Symbol :string when Hash, Array, String @default.class.name.downcase.to_sym end expected_type = (@repeatable && @type != :hash) ? :array : @type if default_type != expected_type err = "Expected #{expected_type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})" if @check_default_type raise ArgumentError, err elsif @check_default_type == nil Bundler::Thor.deprecation_warning "#{err}.\n" + 'This will be rejected in the future unless you explicitly pass the options `check_default_type: false`' + ' or call `allow_incompatible_default_type!` in your code' end end end def dasherized? name.index("-") == 0 end def undasherize(str) str.sub(/^-{1,2}/, "") end def dasherize(str) (str.length > 1 ? "--" : "-") + str.tr("_", "-") end end end PKu]llCbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/arguments.rbnu[class Bundler::Thor class Arguments #:nodoc: # rubocop:disable ClassLength NUMERIC = /[-+]?(\d*\.\d+|\d+)/ # Receives an array of args and returns two arrays, one with arguments # and one with switches. # def self.split(args) arguments = [] args.each do |item| break if item.is_a?(String) && item =~ /^-/ arguments << item end [arguments, args[Range.new(arguments.size, -1)]] end def self.parse(*args) to_parse = args.pop new(*args).parse(to_parse) end # Takes an array of Bundler::Thor::Argument objects. # def initialize(arguments = []) @assigns = {} @non_assigned_required = [] @switches = arguments arguments.each do |argument| if !argument.default.nil? begin @assigns[argument.human_name] = argument.default.dup rescue TypeError # Compatibility shim for un-dup-able Fixnum in Ruby < 2.4 @assigns[argument.human_name] = argument.default end elsif argument.required? @non_assigned_required << argument end end end def parse(args) @pile = args.dup @switches.each do |argument| break unless peek @non_assigned_required.delete(argument) @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name) end check_requirement! @assigns end def remaining @pile end private def no_or_skip?(arg) arg =~ /^--(no|skip)-([-\w]+)$/ $2 end def last? @pile.empty? end def peek @pile.first end def shift @pile.shift end def unshift(arg) if arg.is_a?(Array) @pile = arg + @pile else @pile.unshift(arg) end end def current_is_value? peek && peek.to_s !~ /^-{1,2}\S+/ end # Runs through the argument array getting strings that contains ":" and # mark it as a hash: # # [ "name:string", "age:integer" ] # # Becomes: # # { "name" => "string", "age" => "integer" } # def parse_hash(name) return shift if peek.is_a?(Hash) hash = {} while current_is_value? && peek.include?(":") key, value = shift.split(":", 2) raise MalformattedArgumentError, "You can't specify '#{key}' more than once in option '#{name}'; got #{key}:#{hash[key]} and #{key}:#{value}" if hash.include? key hash[key] = value end hash end # Runs through the argument array getting all strings until no string is # found or a switch is found. # # ["a", "b", "c"] # # And returns it as an array: # # ["a", "b", "c"] # def parse_array(name) return shift if peek.is_a?(Array) array = [] array << shift while current_is_value? array end # Check if the peek is numeric format and return a Float or Integer. # Check if the peek is included in enum if enum is provided. # Otherwise raises an error. # def parse_numeric(name) return shift if peek.is_a?(Numeric) unless peek =~ NUMERIC && $& == peek raise MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}" end value = $&.index(".") ? shift.to_f : shift.to_i if @switches.is_a?(Hash) && switch = @switches[name] if switch.enum && !switch.enum.include?(value) raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}" end end value end # Parse string: # for --string-arg, just return the current value in the pile # for --no-string-arg, nil # Check if the peek is included in enum if enum is provided. Otherwise raises an error. # def parse_string(name) if no_or_skip?(name) nil else value = shift if @switches.is_a?(Hash) && switch = @switches[name] if switch.enum && !switch.enum.include?(value) raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}" end end value end end # Raises an error if @non_assigned_required array is not empty. # def check_requirement! return if @non_assigned_required.empty? names = @non_assigned_required.map do |o| o.respond_to?(:switch_name) ? o.switch_name : o.human_name end.join("', '") class_name = self.class.name.split("::").last.downcase raise RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'" end end end PKu]i Bbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/argument.rbnu[class Bundler::Thor class Argument #:nodoc: VALID_TYPES = [:numeric, :hash, :array, :string] attr_reader :name, :description, :enum, :required, :type, :default, :banner alias_method :human_name, :name def initialize(name, options = {}) class_name = self.class.name.split("::").last type = options[:type] raise ArgumentError, "#{class_name} name can't be nil." if name.nil? raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type) @name = name.to_s @description = options[:desc] @required = options.key?(:required) ? options[:required] : true @type = (type || :string).to_sym @default = options[:default] @banner = options[:banner] || default_banner @enum = options[:enum] validate! # Trigger specific validations end def usage required? ? banner : "[#{banner}]" end def required? required end def show_default? case default when Array, String, Hash !default.empty? else default end end protected def validate! raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil? raise ArgumentError, "An argument cannot have an enum other than an array." if @enum && !@enum.is_a?(Array) end def valid_type?(type) self.class::VALID_TYPES.include?(type.to_sym) end def default_banner case type when :boolean nil when :string, :default human_name.upcase when :numeric "N" when :hash "key:value" when :array "one two three" end end end end PKu]$IJ;;Abundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/options.rbnu[class Bundler::Thor class Options < Arguments #:nodoc: # rubocop:disable ClassLength LONG_RE = /^(--\w+(?:-\w+)*)$/ SHORT_RE = /^(-[a-z])$/i EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i OPTS_END = "--".freeze # Receives a hash and makes it switches. def self.to_switches(options) options.map do |key, value| case value when true "--#{key}" when Array "--#{key} #{value.map(&:inspect).join(' ')}" when Hash "--#{key} #{value.map { |k, v| "#{k}:#{v}" }.join(' ')}" when nil, false nil else "--#{key} #{value.inspect}" end end.compact.join(" ") end # Takes a hash of Bundler::Thor::Option and a hash with defaults. # # If +stop_on_unknown+ is true, #parse will stop as soon as it encounters # an unknown option or a regular argument. def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false) @stop_on_unknown = stop_on_unknown @disable_required_check = disable_required_check options = hash_options.values super(options) # Add defaults defaults.each do |key, value| @assigns[key.to_s] = value @non_assigned_required.delete(hash_options[key]) end @shorts = {} @switches = {} @extra = [] @stopped_parsing_after_extra_index = nil options.each do |option| @switches[option.switch_name] = option option.aliases.each do |short| name = short.to_s.sub(/^(?!\-)/, "-") @shorts[name] ||= option.switch_name end end end def remaining @extra end def peek return super unless @parsing_options result = super if result == OPTS_END shift @parsing_options = false @stopped_parsing_after_extra_index ||= @extra.size super else result end end def parse(args) # rubocop:disable MethodLength @pile = args.dup @parsing_options = true while peek if parsing_options? match, is_switch = current_is_switch? shifted = shift if is_switch case shifted when SHORT_SQ_RE unshift($1.split("").map { |f| "-#{f}" }) next when EQ_RE, SHORT_NUM unshift($2) switch = $1 when LONG_RE, SHORT_RE switch = $1 end switch = normalize_switch(switch) option = switch_option(switch) result = parse_peek(switch, option) assign_result!(option, result) elsif @stop_on_unknown @parsing_options = false @extra << shifted @stopped_parsing_after_extra_index ||= @extra.size @extra << shift while peek break elsif match @extra << shifted @extra << shift while peek && peek !~ /^-/ else @extra << shifted end else @extra << shift end end check_requirement! unless @disable_required_check assigns = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new(@assigns) assigns.freeze assigns end def check_unknown! to_check = @stopped_parsing_after_extra_index ? @extra[0...@stopped_parsing_after_extra_index] : @extra # an unknown option starts with - or -- and has no more --'s afterward. unknown = to_check.select { |str| str =~ /^--?(?:(?!--).)*$/ } raise UnknownArgumentError.new(@switches.keys, unknown) unless unknown.empty? end protected def assign_result!(option, result) if option.repeatable && option.type == :hash (@assigns[option.human_name] ||= {}).merge!(result) elsif option.repeatable (@assigns[option.human_name] ||= []) << result else @assigns[option.human_name] = result end end # Check if the current value in peek is a registered switch. # # Two booleans are returned. The first is true if the current value # starts with a hyphen; the second is true if it is a registered switch. def current_is_switch? case peek when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM [true, switch?($1)] when SHORT_SQ_RE [true, $1.split("").any? { |f| switch?("-#{f}") }] else [false, false] end end def current_is_switch_formatted? case peek when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE true else false end end def current_is_value? peek && (!parsing_options? || super) end def switch?(arg) !switch_option(normalize_switch(arg)).nil? end def switch_option(arg) if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition @switches[arg] || @switches["--#{match}"] else @switches[arg] end end # Check if the given argument is actually a shortcut. # def normalize_switch(arg) (@shorts[arg] || arg).tr("_", "-") end def parsing_options? peek @parsing_options end # Parse boolean values which can be given as --foo=true, --foo or --no-foo. # def parse_boolean(switch) if current_is_value? if ["true", "TRUE", "t", "T", true].include?(peek) shift true elsif ["false", "FALSE", "f", "F", false].include?(peek) shift false else @switches.key?(switch) || !no_or_skip?(switch) end else @switches.key?(switch) || !no_or_skip?(switch) end end # Parse the value at the peek analyzing if it requires an input or not. # def parse_peek(switch, option) if parsing_options? && (current_is_switch_formatted? || last?) if option.boolean? # No problem for boolean types elsif no_or_skip?(switch) return nil # User set value to nil elsif option.string? && !option.required? # Return the default if there is one, else the human name return option.lazy_default || option.default || option.human_name elsif option.lazy_default return option.lazy_default else raise MalformattedArgumentError, "No value provided for option '#{switch}'" end end @non_assigned_required.delete(option) send(:"parse_#{option.type}", switch) end end end PKu]V]Kbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rbnu[require_relative "empty_directory" class Bundler::Thor module Actions # Injects the given content into a file. Different from gsub_file, this # method is reversible. # # ==== Parameters # destination:: Relative path to the destination root # data:: Data to add to the file. Can be given as a block. # config:: give :verbose => false to not log the status and the flag # for injection (:after or :before) or :force => true for # insert two or more times the same content. # # ==== Examples # # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n" # # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do # gems = ask "Which gems would you like to add?" # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n") # end # WARNINGS = { unchanged_no_flag: 'File unchanged! The supplied flag value not found!' } def insert_into_file(destination, *args, &block) data = block_given? ? block : args.shift config = args.shift || {} config[:after] = /\z/ unless config.key?(:before) || config.key?(:after) action InjectIntoFile.new(self, destination, data, config) end alias_method :inject_into_file, :insert_into_file class InjectIntoFile < EmptyDirectory #:nodoc: attr_reader :replacement, :flag, :behavior def initialize(base, destination, data, config) super(base, destination, {:verbose => true}.merge(config)) @behavior, @flag = if @config.key?(:after) [:after, @config.delete(:after)] else [:before, @config.delete(:before)] end @replacement = data.is_a?(Proc) ? data.call : data @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp) end def invoke! content = if @behavior == :after '\0' + replacement else replacement + '\0' end if exists? if replace!(/#{flag}/, content, config[:force]) say_status(:invoke) else say_status(:unchanged, warning: WARNINGS[:unchanged_no_flag], color: :red) end else unless pretend? raise Bundler::Thor::Error, "The file #{ destination } does not appear to exist" end end end def revoke! say_status :revoke regexp = if @behavior == :after content = '\1\2' /(#{flag})(.*)(#{Regexp.escape(replacement)})/m else content = '\2\3' /(#{Regexp.escape(replacement)})(.*)(#{flag})/m end replace!(regexp, content, true) end protected def say_status(behavior, warning: nil, color: nil) status = if behavior == :invoke if flag == /\A/ :prepend elsif flag == /\z/ :append else :insert end elsif warning warning else :subtract end super(status, (color || config[:verbose])) end # Adds the content to the file. # def replace!(regexp, string, force) return if pretend? content = File.read(destination) if force || !content.include?(replacement) success = content.gsub!(regexp, string) File.open(destination, "wb") { |file| file.write(content) } success end end end end end PKu]s mmFbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/create_link.rbnu[require_relative "create_file" class Bundler::Thor module Actions # Create a new file relative to the destination root from the given source. # # ==== Parameters # destination:: the relative path to the destination root. # source:: the relative path to the source root. # config:: give :verbose => false to not log the status. # :: give :symbolic => false for hard link. # # ==== Examples # # create_link "config/apache.conf", "/etc/apache.conf" # def create_link(destination, *args) config = args.last.is_a?(Hash) ? args.pop : {} source = args.first action CreateLink.new(self, destination, source, config) end alias_method :add_link, :create_link # CreateLink is a subset of CreateFile, which instead of taking a block of # data, just takes a source string from the user. # class CreateLink < CreateFile #:nodoc: attr_reader :data # Checks if the content of the file at the destination is identical to the rendered result. # # ==== Returns # Boolean:: true if it is identical, false otherwise. # def identical? source = File.expand_path(render, File.dirname(destination)) exists? && File.identical?(source, destination) end def invoke! invoke_with_conflict_check do require "fileutils" FileUtils.mkdir_p(File.dirname(destination)) # Create a symlink by default config[:symbolic] = true if config[:symbolic].nil? File.unlink(destination) if exists? if config[:symbolic] File.symlink(render, destination) else File.link(render, destination) end end given_destination end def exists? super || File.symlink?(destination) end end end end PKu],;  Dbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/directory.rbnu[require_relative "empty_directory" class Bundler::Thor module Actions # Copies recursively the files from source directory to root directory. # If any of the files finishes with .tt, it's considered to be a template # and is placed in the destination without the extension .tt. If any # empty directory is found, it's copied and all .empty_directory files are # ignored. If any file name is wrapped within % signs, the text within # the % signs will be executed as a method and replaced with the returned # value. Let's suppose a doc directory with the following files: # # doc/ # components/.empty_directory # README # rdoc.rb.tt # %app_name%.rb # # When invoked as: # # directory "doc" # # It will create a doc directory in the destination with the following # files (assuming that the `app_name` method returns the value "blog"): # # doc/ # components/ # README # rdoc.rb # blog.rb # # Encoded path note: Since Bundler::Thor internals use Object#respond_to? to check if it can # expand %something%, this `something` should be a public method in the class calling # #directory. If a method is private, Bundler::Thor stack raises PrivateMethodEncodedError. # # ==== Parameters # source:: the relative path to the source root. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # If :recursive => false, does not look for paths recursively. # If :mode => :preserve, preserve the file mode from the source. # If :exclude_pattern => /regexp/, prevents copying files that match that regexp. # # ==== Examples # # directory "doc" # directory "doc", "docs", :recursive => false # def directory(source, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first || source action Directory.new(self, source, destination || source, config, &block) end class Directory < EmptyDirectory #:nodoc: attr_reader :source def initialize(base, source, destination = nil, config = {}, &block) @source = File.expand_path(Dir[Util.escape_globs(base.find_in_source_paths(source.to_s))].first) @block = block super(base, destination, {:recursive => true}.merge(config)) end def invoke! base.empty_directory given_destination, config execute! end def revoke! execute! end protected def execute! lookup = Util.escape_globs(source) lookup = config[:recursive] ? File.join(lookup, "**") : lookup lookup = file_level_lookup(lookup) files(lookup).sort.each do |file_source| next if File.directory?(file_source) next if config[:exclude_pattern] && file_source.match(config[:exclude_pattern]) file_destination = File.join(given_destination, file_source.gsub(source, ".")) file_destination.gsub!("/./", "/") case file_source when /\.empty_directory$/ dirname = File.dirname(file_destination).gsub(%r{/\.$}, "") next if dirname == given_destination base.empty_directory(dirname, config) when /#{TEMPLATE_EXTNAME}$/ base.template(file_source, file_destination[0..-4], config, &@block) else base.copy_file(file_source, file_destination, config, &@block) end end end def file_level_lookup(previous_lookup) File.join(previous_lookup, "*") end def files(lookup) Dir.glob(lookup, File::FNM_DOTMATCH) end end end end PKu]te) ) Fbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/create_file.rbnu[require_relative "empty_directory" class Bundler::Thor module Actions # Create a new file relative to the destination root with the given data, # which is the return value of a block or a data string. # # ==== Parameters # destination:: the relative path to the destination root. # data:: the data to append to the file. # config:: give :verbose => false to not log the status. # # ==== Examples # # create_file "lib/fun_party.rb" do # hostname = ask("What is the virtual hostname I should use?") # "vhost.name = #{hostname}" # end # # create_file "config/apache.conf", "your apache config" # def create_file(destination, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} data = args.first action CreateFile.new(self, destination, block || data.to_s, config) end alias_method :add_file, :create_file # CreateFile is a subset of Template, which instead of rendering a file with # ERB, it gets the content from the user. # class CreateFile < EmptyDirectory #:nodoc: attr_reader :data def initialize(base, destination, data, config = {}) @data = data super(base, destination, config) end # Checks if the content of the file at the destination is identical to the rendered result. # # ==== Returns # Boolean:: true if it is identical, false otherwise. # def identical? exists? && File.binread(destination) == render end # Holds the content to be added to the file. # def render @render ||= if data.is_a?(Proc) data.call else data end end def invoke! invoke_with_conflict_check do require "fileutils" FileUtils.mkdir_p(File.dirname(destination)) File.open(destination, "wb") { |f| f.write render } end given_destination end protected # Now on conflict we check if the file is identical or not. # def on_conflict_behavior(&block) if identical? say_status :identical, :blue else options = base.options.merge(config) force_or_skip_or_conflict(options[:force], options[:skip], &block) end end # If force is true, run the action, otherwise check if it's not being # skipped. If both are false, show the file_collision menu, if the menu # returns true, force it, otherwise skip. # def force_or_skip_or_conflict(force, skip, &block) if force say_status :force, :yellow yield unless pretend? elsif skip say_status :skip, :yellow else say_status :conflict, :red force_or_skip_or_conflict(force_on_collision?, true, &block) end end # Shows the file collision menu to the user and gets the result. # def force_on_collision? base.shell.file_collision(destination) { render } end end end end PKu]Iq3q3Lbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rbnu[require "erb" class Bundler::Thor module Actions # Copies the file from the relative source to the relative destination. If # the destination is not given it's assumed to be equal to the source. # # ==== Parameters # source:: the relative path to the source root. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status, and # :mode => :preserve, to preserve the file mode from the source. # # ==== Examples # # copy_file "README", "doc/README" # # copy_file "doc/README" # def copy_file(source, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first || source source = File.expand_path(find_in_source_paths(source.to_s)) resulting_destination = create_file destination, nil, config do content = File.binread(source) content = yield(content) if block content end if config[:mode] == :preserve mode = File.stat(source).mode chmod(resulting_destination, mode, config) end end # Links the file from the relative source to the relative destination. If # the destination is not given it's assumed to be equal to the source. # # ==== Parameters # source:: the relative path to the source root. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # # ==== Examples # # link_file "README", "doc/README" # # link_file "doc/README" # def link_file(source, *args) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first || source source = File.expand_path(find_in_source_paths(source.to_s)) create_link destination, source, config end # Gets the content at the given address and places it at the given relative # destination. If a block is given instead of destination, the content of # the url is yielded and used as location. # # +get+ relies on open-uri, so passing application user input would provide # a command injection attack vector. # # ==== Parameters # source:: the address of the given content. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # # ==== Examples # # get "http://gist.github.com/103208", "doc/README" # # get "http://gist.github.com/103208" do |content| # content.split("\n").first # end # def get(source, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first render = if source =~ %r{^https?\://} require "open-uri" URI.send(:open, source) { |input| input.binmode.read } else source = File.expand_path(find_in_source_paths(source.to_s)) open(source) { |input| input.binmode.read } end destination ||= if block_given? block.arity == 1 ? yield(render) : yield else File.basename(source) end create_file destination, render, config end # Gets an ERB template at the relative source, executes it and makes a copy # at the relative destination. If the destination is not given it's assumed # to be equal to the source removing .tt from the filename. # # ==== Parameters # source:: the relative path to the source root. # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # # ==== Examples # # template "README", "doc/README" # # template "doc/README" # def template(source, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, "") source = File.expand_path(find_in_source_paths(source.to_s)) context = config.delete(:context) || instance_eval("binding") create_file destination, nil, config do match = ERB.version.match(/(\d+\.\d+\.\d+)/) capturable_erb = if match && match[1] >= "2.2.0" # Ruby 2.6+ CapturableERB.new(::File.binread(source), :trim_mode => "-", :eoutvar => "@output_buffer") else CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer") end content = capturable_erb.tap do |erb| erb.filename = source end.result(context) content = yield(content) if block content end end # Changes the mode of the given file or directory. # # ==== Parameters # mode:: the file mode # path:: the name of the file to change mode # config:: give :verbose => false to not log the status. # # ==== Example # # chmod "script/server", 0755 # def chmod(path, mode, config = {}) return unless behavior == :invoke path = File.expand_path(path, destination_root) say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true) unless options[:pretend] require "fileutils" FileUtils.chmod_R(mode, path) end end # Prepend text to a file. Since it depends on insert_into_file, it's reversible. # # ==== Parameters # path:: path of the file to be changed # data:: the data to prepend to the file, can be also given as a block. # config:: give :verbose => false to not log the status. # # ==== Example # # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"' # # prepend_to_file 'config/environments/test.rb' do # 'config.gem "rspec"' # end # def prepend_to_file(path, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} config[:after] = /\A/ insert_into_file(path, *(args << config), &block) end alias_method :prepend_file, :prepend_to_file # Append text to a file. Since it depends on insert_into_file, it's reversible. # # ==== Parameters # path:: path of the file to be changed # data:: the data to append to the file, can be also given as a block. # config:: give :verbose => false to not log the status. # # ==== Example # # append_to_file 'config/environments/test.rb', 'config.gem "rspec"' # # append_to_file 'config/environments/test.rb' do # 'config.gem "rspec"' # end # def append_to_file(path, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} config[:before] = /\z/ insert_into_file(path, *(args << config), &block) end alias_method :append_file, :append_to_file # Injects text right after the class definition. Since it depends on # insert_into_file, it's reversible. # # ==== Parameters # path:: path of the file to be changed # klass:: the class to be manipulated # data:: the data to append to the class, can be also given as a block. # config:: give :verbose => false to not log the status. # # ==== Examples # # inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n" # # inject_into_class "app/controllers/application_controller.rb", ApplicationController do # " filter_parameter :password\n" # end # def inject_into_class(path, klass, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} config[:after] = /class #{klass}\n|class #{klass} .*\n/ insert_into_file(path, *(args << config), &block) end # Injects text right after the module definition. Since it depends on # insert_into_file, it's reversible. # # ==== Parameters # path:: path of the file to be changed # module_name:: the module to be manipulated # data:: the data to append to the class, can be also given as a block. # config:: give :verbose => false to not log the status. # # ==== Examples # # inject_into_module "app/helpers/application_helper.rb", ApplicationHelper, " def help; 'help'; end\n" # # inject_into_module "app/helpers/application_helper.rb", ApplicationHelper do # " def help; 'help'; end\n" # end # def inject_into_module(path, module_name, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} config[:after] = /module #{module_name}\n|module #{module_name} .*\n/ insert_into_file(path, *(args << config), &block) end # Run a regular expression replacement on a file. # # ==== Parameters # path:: path of the file to be changed # flag:: the regexp or string to be replaced # replacement:: the replacement, can be also given as a block # config:: give :verbose => false to not log the status, and # :force => true, to force the replacement regardless of runner behavior. # # ==== Example # # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1' # # gsub_file 'README', /rake/, :green do |match| # match << " no more. Use thor!" # end # def gsub_file(path, flag, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} return unless behavior == :invoke || config.fetch(:force, false) path = File.expand_path(path, destination_root) say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true) unless options[:pretend] content = File.binread(path) content.gsub!(flag, *args, &block) File.open(path, "wb") { |file| file.write(content) } end end # Uncomment all lines matching a given regex. It will leave the space # which existed before the comment hash in tact but will remove any spacing # between the comment hash and the beginning of the line. # # ==== Parameters # path:: path of the file to be changed # flag:: the regexp or string used to decide which lines to uncomment # config:: give :verbose => false to not log the status. # # ==== Example # # uncomment_lines 'config/initializers/session_store.rb', /active_record/ # def uncomment_lines(path, flag, *args) flag = flag.respond_to?(:source) ? flag.source : flag gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args) end # Comment all lines matching a given regex. It will leave the space # which existed before the beginning of the line in tact and will insert # a single space after the comment hash. # # ==== Parameters # path:: path of the file to be changed # flag:: the regexp or string used to decide which lines to comment # config:: give :verbose => false to not log the status. # # ==== Example # # comment_lines 'config/initializers/session_store.rb', /cookie_store/ # def comment_lines(path, flag, *args) flag = flag.respond_to?(:source) ? flag.source : flag gsub_file(path, /^(\s*)([^#\n]*#{flag})/, '\1# \2', *args) end # Removes a file at the given location. # # ==== Parameters # path:: path of the file to be changed # config:: give :verbose => false to not log the status. # # ==== Example # # remove_file 'README' # remove_file 'app/controllers/application_controller.rb' # def remove_file(path, config = {}) return unless behavior == :invoke path = File.expand_path(path, destination_root) say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true) if !options[:pretend] && File.exist?(path) require "fileutils" ::FileUtils.rm_rf(path) end end alias_method :remove_dir, :remove_file attr_accessor :output_buffer private :output_buffer, :output_buffer= private def concat(string) @output_buffer.concat(string) end def capture(*args) with_output_buffer { yield(*args) } end def with_output_buffer(buf = "".dup) #:nodoc: raise ArgumentError, "Buffer can not be a frozen object" if buf.frozen? old_buffer = output_buffer self.output_buffer = buf yield output_buffer ensure self.output_buffer = old_buffer end # Bundler::Thor::Actions#capture depends on what kind of buffer is used in ERB. # Thus CapturableERB fixes ERB to use String buffer. class CapturableERB < ERB def set_eoutvar(compiler, eoutvar = "_erbout") compiler.put_cmd = "#{eoutvar}.concat" compiler.insert_cmd = "#{eoutvar}.concat" compiler.pre_cmd = ["#{eoutvar} = ''.dup"] compiler.post_cmd = [eoutvar] end end end end PKu]O&Jbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rbnu[class Bundler::Thor module Actions # Creates an empty directory. # # ==== Parameters # destination:: the relative path to the destination root. # config:: give :verbose => false to not log the status. # # ==== Examples # # empty_directory "doc" # def empty_directory(destination, config = {}) action EmptyDirectory.new(self, destination, config) end # Class which holds create directory logic. This is the base class for # other actions like create_file and directory. # # This implementation is based in Templater actions, created by Jonas Nicklas # and Michael S. Klishin under MIT LICENSE. # class EmptyDirectory #:nodoc: attr_reader :base, :destination, :given_destination, :relative_destination, :config # Initializes given the source and destination. # # ==== Parameters # base:: A Bundler::Thor::Base instance # source:: Relative path to the source of this file # destination:: Relative path to the destination of this file # config:: give :verbose => false to not log the status. # def initialize(base, destination, config = {}) @base = base @config = {:verbose => true}.merge(config) self.destination = destination end # Checks if the destination file already exists. # # ==== Returns # Boolean:: true if the file exists, false otherwise. # def exists? ::File.exist?(destination) end def invoke! invoke_with_conflict_check do require "fileutils" ::FileUtils.mkdir_p(destination) end end def revoke! say_status :remove, :red require "fileutils" ::FileUtils.rm_rf(destination) if !pretend? && exists? given_destination end protected # Shortcut for pretend. # def pretend? base.options[:pretend] end # Sets the absolute destination value from a relative destination value. # It also stores the given and relative destination. Let's suppose our # script is being executed on "dest", it sets the destination root to # "dest". The destination, given_destination and relative_destination # are related in the following way: # # inside "bar" do # empty_directory "baz" # end # # destination #=> dest/bar/baz # relative_destination #=> bar/baz # given_destination #=> baz # def destination=(destination) return unless destination @given_destination = convert_encoded_instructions(destination.to_s) @destination = ::File.expand_path(@given_destination, base.destination_root) @relative_destination = base.relative_to_original_destination_root(@destination) end # Filenames in the encoded form are converted. If you have a file: # # %file_name%.rb # # It calls #file_name from the base and replaces %-string with the # return value (should be String) of #file_name: # # user.rb # # The method referenced can be either public or private. # def convert_encoded_instructions(filename) filename.gsub(/%(.*?)%/) do |initial_string| method = $1.strip base.respond_to?(method, true) ? base.send(method) : initial_string end end # Receives a hash of options and just execute the block if some # conditions are met. # def invoke_with_conflict_check(&block) if exists? on_conflict_behavior(&block) else yield unless pretend? say_status :create, :green end destination rescue Errno::EISDIR, Errno::EEXIST on_file_clash_behavior end def on_file_clash_behavior say_status :file_clash, :red end # What to do when the destination file already exists. # def on_conflict_behavior say_status :exist, :blue end # Shortcut to say_status shell method. # def say_status(status, color) base.shell.say_status status, relative_destination, color if config[:verbose] end end end end PKu]jU#U#7bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/util.rbnu[require "rbconfig" class Bundler::Thor module Sandbox #:nodoc: end # This module holds several utilities: # # 1) Methods to convert thor namespaces to constants and vice-versa. # # Bundler::Thor::Util.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz" # # 2) Loading thor files and sandboxing: # # Bundler::Thor::Util.load_thorfile("~/.thor/foo") # module Util class << self # Receives a namespace and search for it in the Bundler::Thor::Base subclasses. # # ==== Parameters # namespace:: The namespace to search for. # def find_by_namespace(namespace) namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/ Bundler::Thor::Base.subclasses.detect { |klass| klass.namespace == namespace } end # Receives a constant and converts it to a Bundler::Thor namespace. Since Bundler::Thor # commands can be added to a sandbox, this method is also responsible for # removing the sandbox namespace. # # This method should not be used in general because it's used to deal with # older versions of Bundler::Thor. On current versions, if you need to get the # namespace from a class, just call namespace on it. # # ==== Parameters # constant:: The constant to be converted to the thor path. # # ==== Returns # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz" # def namespace_from_thor_class(constant) constant = constant.to_s.gsub(/^Bundler::Thor::Sandbox::/, "") constant = snake_case(constant).squeeze(":") constant end # Given the contents, evaluate it inside the sandbox and returns the # namespaces defined in the sandbox. # # ==== Parameters # contents # # ==== Returns # Array[Object] # def namespaces_in_content(contents, file = __FILE__) old_constants = Bundler::Thor::Base.subclasses.dup Bundler::Thor::Base.subclasses.clear load_thorfile(file, contents) new_constants = Bundler::Thor::Base.subclasses.dup Bundler::Thor::Base.subclasses.replace(old_constants) new_constants.map!(&:namespace) new_constants.compact! new_constants end # Returns the thor classes declared inside the given class. # def thor_classes_in(klass) stringfied_constants = klass.constants.map(&:to_s) Bundler::Thor::Base.subclasses.select do |subclass| next unless subclass.name stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", "")) end end # Receives a string and convert it to snake case. SnakeCase returns snake_case. # # ==== Parameters # String # # ==== Returns # String # def snake_case(str) return str.downcase if str =~ /^[A-Z_]+$/ str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/ $+.downcase end # Receives a string and convert it to camel case. camel_case returns CamelCase. # # ==== Parameters # String # # ==== Returns # String # def camel_case(str) return str if str !~ /_/ && str =~ /[A-Z]+.*/ str.split("_").map(&:capitalize).join end # Receives a namespace and tries to retrieve a Bundler::Thor or Bundler::Thor::Group class # from it. It first searches for a class using the all the given namespace, # if it's not found, removes the highest entry and searches for the class # again. If found, returns the highest entry as the class name. # # ==== Examples # # class Foo::Bar < Bundler::Thor # def baz # end # end # # class Baz::Foo < Bundler::Thor::Group # end # # Bundler::Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default command # Bundler::Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil # Bundler::Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz" # # ==== Parameters # namespace # def find_class_and_command_by_namespace(namespace, fallback = true) if namespace.include?(":") # look for a namespaced command pieces = namespace.split(":") command = pieces.pop klass = Bundler::Thor::Util.find_by_namespace(pieces.join(":")) end unless klass # look for a Bundler::Thor::Group with the right name klass = Bundler::Thor::Util.find_by_namespace(namespace) command = nil end if !klass && fallback # try a command in the default namespace command = namespace klass = Bundler::Thor::Util.find_by_namespace("") end [klass, command] end alias_method :find_class_and_task_by_namespace, :find_class_and_command_by_namespace # Receives a path and load the thor file in the path. The file is evaluated # inside the sandbox to avoid namespacing conflicts. # def load_thorfile(path, content = nil, debug = false) content ||= File.binread(path) begin Bundler::Thor::Sandbox.class_eval(content, path) rescue StandardError => e $stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}") if debug $stderr.puts(*e.backtrace) else $stderr.puts(e.backtrace.first) end end end def user_home @@user_home ||= if ENV["HOME"] ENV["HOME"] elsif ENV["USERPROFILE"] ENV["USERPROFILE"] elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"] File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"]) elsif ENV["APPDATA"] ENV["APPDATA"] else begin File.expand_path("~") rescue if File::ALT_SEPARATOR "C:/" else "/" end end end end # Returns the root where thor files are located, depending on the OS. # def thor_root File.join(user_home, ".thor").tr('\\', "/") end # Returns the files in the thor root. On Windows thor_root will be something # like this: # # C:\Documents and Settings\james\.thor # # If we don't #gsub the \ character, Dir.glob will fail. # def thor_root_glob files = Dir["#{escape_globs(thor_root)}/*"] files.map! do |file| File.directory?(file) ? File.join(file, "main.thor") : file end end # Where to look for Bundler::Thor files. # def globs_for(path) path = escape_globs(path) ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"] end # Return the path to the ruby interpreter taking into account multiple # installations and windows extensions. # def ruby_command @ruby_command ||= begin ruby_name = RbConfig::CONFIG["ruby_install_name"] ruby = File.join(RbConfig::CONFIG["bindir"], ruby_name) ruby << RbConfig::CONFIG["EXEEXT"] # avoid using different name than ruby (on platforms supporting links) if ruby_name != "ruby" && File.respond_to?(:readlink) begin alternate_ruby = File.join(RbConfig::CONFIG["bindir"], "ruby") alternate_ruby << RbConfig::CONFIG["EXEEXT"] # ruby is a symlink if File.symlink? alternate_ruby linked_ruby = File.readlink alternate_ruby # symlink points to 'ruby_install_name' ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby end rescue NotImplementedError # rubocop:disable HandleExceptions # just ignore on windows end end # escape string in case path to ruby executable contain spaces. ruby.sub!(/.*\s.*/m, '"\&"') ruby end end # Returns a string that has had any glob characters escaped. # The glob characters are `* ? { } [ ]`. # # ==== Examples # # Bundler::Thor::Util.escape_globs('[apps]') # => '\[apps\]' # # ==== Parameters # String # # ==== Returns # String # def escape_globs(path) path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&') end # Returns a string that has had any HTML characters escaped. # # ==== Examples # # Bundler::Thor::Util.escape_html('
    ') # => "<div>" # # ==== Parameters # String # # ==== Returns # String # def escape_html(string) CGI.escapeHTML(string) end end end end PKu]q@q@2bundler-2.2.24/lib/bundler/vendor/thor/lib/thor.rbnu[require_relative "thor/base" class Bundler::Thor $thor_runner ||= false class << self # Allows for custom "Command" package naming. # # === Parameters # name # options # def package_name(name, _ = {}) @package_name = name.nil? || name == "" ? nil : name end # Sets the default command when thor is executed without an explicit command to be called. # # ==== Parameters # meth:: name of the default command # def default_command(meth = nil) if meth @default_command = meth == :none ? "help" : meth.to_s else @default_command ||= from_superclass(:default_command, "help") end end alias_method :default_task, :default_command # Registers another Bundler::Thor subclass as a command. # # ==== Parameters # klass:: Bundler::Thor subclass to register # command:: Subcommand name to use # usage:: Short usage for the subcommand # description:: Description for the subcommand def register(klass, subcommand_name, usage, description, options = {}) if klass <= Bundler::Thor::Group desc usage, description, options define_method(subcommand_name) { |*args| invoke(klass, args) } else desc usage, description, options subcommand subcommand_name, klass end end # Defines the usage and the description of the next command. # # ==== Parameters # usage # description # options # def desc(usage, description, options = {}) if options[:for] command = find_and_refresh_command(options[:for]) command.usage = usage if usage command.description = description if description else @usage = usage @desc = description @hide = options[:hide] || false end end # Defines the long description of the next command. # # ==== Parameters # long description # def long_desc(long_description, options = {}) if options[:for] command = find_and_refresh_command(options[:for]) command.long_description = long_description if long_description else @long_desc = long_description end end # Maps an input to a command. If you define: # # map "-T" => "list" # # Running: # # thor -T # # Will invoke the list command. # # ==== Parameters # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command. # def map(mappings = nil, **kw) @map ||= from_superclass(:map, {}) if mappings && !kw.empty? mappings = kw.merge!(mappings) else mappings ||= kw end if mappings mappings.each do |key, value| if key.respond_to?(:each) key.each { |subkey| @map[subkey] = value } else @map[key] = value end end end @map end # Declares the options for the next command to be declared. # # ==== Parameters # Hash[Symbol => Object]:: The hash key is the name of the option and the value # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric # or :required (string). If you give a value, the type of the value is used. # def method_options(options = nil) @method_options ||= {} build_options(options, @method_options) if options @method_options end alias_method :options, :method_options # Adds an option to the set of method options. If :for is given as option, # it allows you to change the options from a previous defined command. # # def previous_command # # magic # end # # method_option :foo => :bar, :for => :previous_command # # def next_command # # magic # end # # ==== Parameters # name:: The name of the argument. # options:: Described below. # # ==== Options # :desc - Description for the argument. # :required - If the argument is required or not. # :default - Default value for this argument. It cannot be required and have default values. # :aliases - Aliases for this option. # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean. # :banner - String to show on usage notes. # :hide - If you want to hide this option from the help. # def method_option(name, options = {}) scope = if options[:for] find_and_refresh_command(options[:for]).options else method_options end build_option(name, options, scope) end alias_method :option, :method_option # Prints help information for the given command. # # ==== Parameters # shell # command_name # def command_help(shell, command_name) meth = normalize_command_name(command_name) command = all_commands[meth] handle_no_command_error(meth) unless command shell.say "Usage:" shell.say " #{banner(command).split("\n").join("\n ")}" shell.say class_options_help(shell, nil => command.options.values) if command.long_description shell.say "Description:" shell.print_wrapped(command.long_description, :indent => 2) else shell.say command.description end end alias_method :task_help, :command_help # Prints help information for this class. # # ==== Parameters # shell # def help(shell, subcommand = false) list = printable_commands(true, subcommand) Bundler::Thor::Util.thor_classes_in(self).each do |klass| list += klass.printable_commands(false) end list.sort! { |a, b| a[0] <=> b[0] } if defined?(@package_name) && @package_name shell.say "#{@package_name} commands:" else shell.say "Commands:" end shell.print_table(list, :indent => 2, :truncate => true) shell.say class_options_help(shell) end # Returns commands ready to be printed. def printable_commands(all = true, subcommand = false) (all ? all_commands : commands).map do |_, command| next if command.hidden? item = [] item << banner(command, false, subcommand) item << (command.description ? "# #{command.description.gsub(/\s+/m, ' ')}" : "") item end.compact end alias_method :printable_tasks, :printable_commands def subcommands @subcommands ||= from_superclass(:subcommands, []) end alias_method :subtasks, :subcommands def subcommand_classes @subcommand_classes ||= {} end def subcommand(subcommand, subcommand_class) subcommands << subcommand.to_s subcommand_class.subcommand_help subcommand subcommand_classes[subcommand.to_s] = subcommand_class define_method(subcommand) do |*args| args, opts = Bundler::Thor::Arguments.split(args) invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}] invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h") invoke subcommand_class, *invoke_args end subcommand_class.commands.each do |_meth, command| command.ancestor_name = subcommand end end alias_method :subtask, :subcommand # Extend check unknown options to accept a hash of conditions. # # === Parameters # options: A hash containing :only and/or :except keys def check_unknown_options!(options = {}) @check_unknown_options ||= {} options.each do |key, value| if value @check_unknown_options[key] = Array(value) else @check_unknown_options.delete(key) end end @check_unknown_options end # Overwrite check_unknown_options? to take subcommands and options into account. def check_unknown_options?(config) #:nodoc: options = check_unknown_options return false unless options command = config[:current_command] return true unless command name = command.name if subcommands.include?(name) false elsif options[:except] !options[:except].include?(name.to_sym) elsif options[:only] options[:only].include?(name.to_sym) else true end end # Stop parsing of options as soon as an unknown option or a regular # argument is encountered. All remaining arguments are passed to the command. # This is useful if you have a command that can receive arbitrary additional # options, and where those additional options should not be handled by # Bundler::Thor. # # ==== Example # # To better understand how this is useful, let's consider a command that calls # an external command. A user may want to pass arbitrary options and # arguments to that command. The command itself also accepts some options, # which should be handled by Bundler::Thor. # # class_option "verbose", :type => :boolean # stop_on_unknown_option! :exec # check_unknown_options! :except => :exec # # desc "exec", "Run a shell command" # def exec(*args) # puts "diagnostic output" if options[:verbose] # Kernel.exec(*args) # end # # Here +exec+ can be called with +--verbose+ to get diagnostic output, # e.g.: # # $ thor exec --verbose echo foo # diagnostic output # foo # # But if +--verbose+ is given after +echo+, it is passed to +echo+ instead: # # $ thor exec echo --verbose foo # --verbose foo # # ==== Parameters # Symbol ...:: A list of commands that should be affected. def stop_on_unknown_option!(*command_names) @stop_on_unknown_option = stop_on_unknown_option | command_names end def stop_on_unknown_option?(command) #:nodoc: command && stop_on_unknown_option.include?(command.name.to_sym) end # Disable the check for required options for the given commands. # This is useful if you have a command that does not need the required options # to work, like help. # # ==== Parameters # Symbol ...:: A list of commands that should be affected. def disable_required_check!(*command_names) @disable_required_check = disable_required_check | command_names end def disable_required_check?(command) #:nodoc: command && disable_required_check.include?(command.name.to_sym) end protected def stop_on_unknown_option #:nodoc: @stop_on_unknown_option ||= [] end # help command has the required check disabled by default. def disable_required_check #:nodoc: @disable_required_check ||= [:help] end # The method responsible for dispatching given the args. def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength meth ||= retrieve_command_name(given_args) command = all_commands[normalize_command_name(meth)] if !command && config[:invoked_via_subcommand] # We're a subcommand and our first argument didn't match any of our # commands. So we put it back and call our default command. given_args.unshift(meth) command = all_commands[normalize_command_name(default_command)] end if command args, opts = Bundler::Thor::Options.split(given_args) if stop_on_unknown_option?(command) && !args.empty? # given_args starts with a non-option, so we treat everything as # ordinary arguments args.concat opts opts.clear end else args = given_args opts = nil command = dynamic_command_class.new(meth) end opts = given_opts || opts || [] config[:current_command] = command config[:command_options] = command.options instance = new(args, opts, config) yield instance if block_given? args = instance.args trailing = args[Range.new(arguments.size, -1)] instance.invoke_command(command, trailing || []) end # The banner for this class. You can customize it if you are invoking the # thor class by another ways which is not the Bundler::Thor::Runner. It receives # the command that is going to be invoked and a boolean which indicates if # the namespace should be displayed as arguments. # def banner(command, namespace = nil, subcommand = false) command.formatted_usage(self, $thor_runner, subcommand).split("\n").map do |formatted_usage| "#{basename} #{formatted_usage}" end.join("\n") end def baseclass #:nodoc: Bundler::Thor end def dynamic_command_class #:nodoc: Bundler::Thor::DynamicCommand end def create_command(meth) #:nodoc: @usage ||= nil @desc ||= nil @long_desc ||= nil @hide ||= nil if @usage && @desc base_class = @hide ? Bundler::Thor::HiddenCommand : Bundler::Thor::Command commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options) @usage, @desc, @long_desc, @method_options, @hide = nil true elsif all_commands[meth] || meth == "method_missing" true else puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " \ "Call desc if you want this method to be available as command or declare it inside a " \ "no_commands{} block. Invoked from #{caller[1].inspect}." false end end alias_method :create_task, :create_command def initialize_added #:nodoc: class_options.merge!(method_options) @method_options = nil end # Retrieve the command name from given args. def retrieve_command_name(args) #:nodoc: meth = args.first.to_s unless args.empty? args.shift if meth && (map[meth] || meth !~ /^\-/) end alias_method :retrieve_task_name, :retrieve_command_name # receives a (possibly nil) command name and returns a name that is in # the commands hash. In addition to normalizing aliases, this logic # will determine if a shortened command is an unambiguous substring of # a command or alias. # # +normalize_command_name+ also converts names like +animal-prison+ # into +animal_prison+. def normalize_command_name(meth) #:nodoc: return default_command.to_s.tr("-", "_") unless meth possibilities = find_command_possibilities(meth) raise AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]" if possibilities.size > 1 if possibilities.empty? meth ||= default_command elsif map[meth] meth = map[meth] else meth = possibilities.first end meth.to_s.tr("-", "_") # treat foo-bar as foo_bar end alias_method :normalize_task_name, :normalize_command_name # this is the logic that takes the command name passed in by the user # and determines whether it is an unambiguous substrings of a command or # alias name. def find_command_possibilities(meth) len = meth.to_s.length possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort unique_possibilities = possibilities.map { |k| map[k] || k }.uniq if possibilities.include?(meth) [meth] elsif unique_possibilities.size == 1 unique_possibilities else possibilities end end alias_method :find_task_possibilities, :find_command_possibilities def subcommand_help(cmd) desc "help [COMMAND]", "Describe subcommands or one specific subcommand" class_eval " def help(command = nil, subcommand = true); super; end " end alias_method :subtask_help, :subcommand_help end include Bundler::Thor::Base map HELP_MAPPINGS => :help desc "help [COMMAND]", "Describe available commands or one specific command" def help(command = nil, subcommand = false) if command if self.class.subcommands.include? command self.class.subcommand_classes[command].help(shell, true) else self.class.command_help(shell, command) end else self.class.help(shell, subcommand) end end end PKu]C}mmPbundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rbnu[require 'net/http' require_relative '../../../../uri/lib/uri' require 'cgi' # for escaping require_relative '../../../../connection_pool/lib/connection_pool' autoload :OpenSSL, 'openssl' ## # Persistent connections for Net::HTTP # # Bundler::Persistent::Net::HTTP::Persistent maintains persistent connections across all the # servers you wish to talk to. For each host:port you communicate with a # single persistent connection is created. # # Connections will be shared across threads through a connection pool to # increase reuse of connections. # # You can shut down any remaining HTTP connections when done by calling # #shutdown. # # Example: # # require 'bundler/vendor/net-http-persistent/lib/net/http/persistent' # # uri = Bundler::URI 'http://example.com/awesome/web/service' # # http = Bundler::Persistent::Net::HTTP::Persistent.new # # # perform a GET # response = http.request uri # # # or # # get = Net::HTTP::Get.new uri.request_uri # response = http.request get # # # create a POST # post_uri = uri + 'create' # post = Net::HTTP::Post.new post_uri.path # post.set_form_data 'some' => 'cool data' # # # perform the POST, the Bundler::URI is always required # response http.request post_uri, post # # Note that for GET, HEAD and other requests that do not have a body you want # to use Bundler::URI#request_uri not Bundler::URI#path. The request_uri contains the query # params which are sent in the body for other requests. # # == TLS/SSL # # TLS connections are automatically created depending upon the scheme of the # Bundler::URI. TLS connections are automatically verified against the default # certificate store for your computer. You can override this by changing # verify_mode or by specifying an alternate cert_store. # # Here are the TLS settings, see the individual methods for documentation: # # #certificate :: This client's certificate # #ca_file :: The certificate-authorities # #ca_path :: Directory with certificate-authorities # #cert_store :: An SSL certificate store # #ciphers :: List of SSl ciphers allowed # #private_key :: The client's SSL private key # #reuse_ssl_sessions :: Reuse a previously opened SSL session for a new # connection # #ssl_timeout :: Session lifetime # #ssl_version :: Which specific SSL version to use # #verify_callback :: For server certificate verification # #verify_depth :: Depth of certificate verification # #verify_mode :: How connections should be verified # # == Proxies # # A proxy can be set through #proxy= or at initialization time by providing a # second argument to ::new. The proxy may be the Bundler::URI of the proxy server or # :ENV which will consult environment variables. # # See #proxy= and #proxy_from_env for details. # # == Headers # # Headers may be specified for use in every request. #headers are appended to # any headers on the request. #override_headers replace existing headers on # the request. # # The difference between the two can be seen in setting the User-Agent. Using # http.headers['User-Agent'] = 'MyUserAgent' will send "Ruby, # MyUserAgent" while http.override_headers['User-Agent'] = # 'MyUserAgent' will send "MyUserAgent". # # == Tuning # # === Segregation # # Each Bundler::Persistent::Net::HTTP::Persistent instance has its own pool of connections. There # is no sharing with other instances (as was true in earlier versions). # # === Idle Timeout # # If a connection hasn't been used for this number of seconds it will # automatically be reset upon the next use to avoid attempting to send to a # closed connection. The default value is 5 seconds. nil means no timeout. # Set through #idle_timeout. # # Reducing this value may help avoid the "too many connection resets" error # when sending non-idempotent requests while increasing this value will cause # fewer round-trips. # # === Read Timeout # # The amount of time allowed between reading two chunks from the socket. Set # through #read_timeout # # === Max Requests # # The number of requests that should be made before opening a new connection. # Typically many keep-alive capable servers tune this to 100 or less, so the # 101st request will fail with ECONNRESET. If unset (default), this value has # no effect, if set, connections will be reset on the request after # max_requests. # # === Open Timeout # # The amount of time to wait for a connection to be opened. Set through # #open_timeout. # # === Socket Options # # Socket options may be set on newly-created connections. See #socket_options # for details. # # === Connection Termination # # If you are done using the Bundler::Persistent::Net::HTTP::Persistent instance you may shut down # all the connections in the current thread with #shutdown. This is not # recommended for normal use, it should only be used when it will be several # minutes before you make another HTTP request. # # If you are using multiple threads, call #shutdown in each thread when the # thread is done making requests. If you don't call shutdown, that's OK. # Ruby will automatically garbage collect and shutdown your HTTP connections # when the thread terminates. class Bundler::Persistent::Net::HTTP::Persistent ## # The beginning of Time EPOCH = Time.at 0 # :nodoc: ## # Is OpenSSL available? This test works with autoload HAVE_OPENSSL = defined? OpenSSL::SSL # :nodoc: ## # The default connection pool size is 1/4 the allowed open files # (ulimit -n) or 256 if your OS does not support file handle # limits (typically windows). if Process.const_defined? :RLIMIT_NOFILE open_file_limits = Process.getrlimit(Process::RLIMIT_NOFILE) # Under JRuby on Windows Process responds to `getrlimit` but returns something that does not match docs if open_file_limits.respond_to?(:first) DEFAULT_POOL_SIZE = open_file_limits.first / 4 else DEFAULT_POOL_SIZE = 256 end else DEFAULT_POOL_SIZE = 256 end ## # The version of Bundler::Persistent::Net::HTTP::Persistent you are using VERSION = '4.0.0' ## # Error class for errors raised by Bundler::Persistent::Net::HTTP::Persistent. Various # SystemCallErrors are re-raised with a human-readable message under this # class. class Error < StandardError; end ## # Use this method to detect the idle timeout of the host at +uri+. The # value returned can be used to configure #idle_timeout. +max+ controls the # maximum idle timeout to detect. # # After # # Idle timeout detection is performed by creating a connection then # performing a HEAD request in a loop until the connection terminates # waiting one additional second per loop. # # NOTE: This may not work on ruby > 1.9. def self.detect_idle_timeout uri, max = 10 uri = Bundler::URI uri unless Bundler::URI::Generic === uri uri += '/' req = Net::HTTP::Head.new uri.request_uri http = new 'net-http-persistent detect_idle_timeout' http.connection_for uri do |connection| sleep_time = 0 http = connection.http loop do response = http.request req $stderr.puts "HEAD #{uri} => #{response.code}" if $DEBUG unless Net::HTTPOK === response then raise Error, "bad response code #{response.code} detecting idle timeout" end break if sleep_time >= max sleep_time += 1 $stderr.puts "sleeping #{sleep_time}" if $DEBUG sleep sleep_time end end rescue # ignore StandardErrors, we've probably found the idle timeout. ensure return sleep_time unless $! end ## # This client's OpenSSL::X509::Certificate attr_reader :certificate ## # For Net::HTTP parity alias cert certificate ## # An SSL certificate authority. Setting this will set verify_mode to # VERIFY_PEER. attr_reader :ca_file ## # A directory of SSL certificates to be used as certificate authorities. # Setting this will set verify_mode to VERIFY_PEER. attr_reader :ca_path ## # An SSL certificate store. Setting this will override the default # certificate store. See verify_mode for more information. attr_reader :cert_store ## # The ciphers allowed for SSL connections attr_reader :ciphers ## # Sends debug_output to this IO via Net::HTTP#set_debug_output. # # Never use this method in production code, it causes a serious security # hole. attr_accessor :debug_output ## # Current connection generation attr_reader :generation # :nodoc: ## # Headers that are added to every request using Net::HTTP#add_field attr_reader :headers ## # Maps host:port to an HTTP version. This allows us to enable version # specific features. attr_reader :http_versions ## # Maximum time an unused connection can remain idle before being # automatically closed. attr_accessor :idle_timeout ## # Maximum number of requests on a connection before it is considered expired # and automatically closed. attr_accessor :max_requests ## # Number of retries to perform if a request fails. # # See also #max_retries=, Net::HTTP#max_retries=. attr_reader :max_retries ## # The value sent in the Keep-Alive header. Defaults to 30. Not needed for # HTTP/1.1 servers. # # This may not work correctly for HTTP/1.0 servers # # This method may be removed in a future version as RFC 2616 does not # require this header. attr_accessor :keep_alive ## # The name for this collection of persistent connections. attr_reader :name ## # Seconds to wait until a connection is opened. See Net::HTTP#open_timeout attr_accessor :open_timeout ## # Headers that are added to every request using Net::HTTP#[]= attr_reader :override_headers ## # This client's SSL private key attr_reader :private_key ## # For Net::HTTP parity alias key private_key ## # The URL through which requests will be proxied attr_reader :proxy_uri ## # List of host suffixes which will not be proxied attr_reader :no_proxy ## # Test-only accessor for the connection pool attr_reader :pool # :nodoc: ## # Seconds to wait until reading one block. See Net::HTTP#read_timeout attr_accessor :read_timeout ## # Seconds to wait until writing one block. See Net::HTTP#write_timeout attr_accessor :write_timeout ## # By default SSL sessions are reused to avoid extra SSL handshakes. Set # this to false if you have problems communicating with an HTTPS server # like: # # SSL_connect [...] read finished A: unexpected message (OpenSSL::SSL::SSLError) attr_accessor :reuse_ssl_sessions ## # An array of options for Socket#setsockopt. # # By default the TCP_NODELAY option is set on sockets. # # To set additional options append them to this array: # # http.socket_options << [Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1] attr_reader :socket_options ## # Current SSL connection generation attr_reader :ssl_generation # :nodoc: ## # SSL session lifetime attr_reader :ssl_timeout ## # SSL version to use. # # By default, the version will be negotiated automatically between client # and server. Ruby 1.9 and newer only. Deprecated since Ruby 2.5. attr_reader :ssl_version ## # Minimum SSL version to use, e.g. :TLS1_1 # # By default, the version will be negotiated automatically between client # and server. Ruby 2.5 and newer only. attr_reader :min_version ## # Maximum SSL version to use, e.g. :TLS1_2 # # By default, the version will be negotiated automatically between client # and server. Ruby 2.5 and newer only. attr_reader :max_version ## # Where this instance's last-use times live in the thread local variables attr_reader :timeout_key # :nodoc: ## # SSL verification callback. Used when ca_file or ca_path is set. attr_reader :verify_callback ## # Sets the depth of SSL certificate verification attr_reader :verify_depth ## # HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_PEER which verifies # the server certificate. # # If no ca_file, ca_path or cert_store is set the default system certificate # store is used. # # You can use +verify_mode+ to override any default values. attr_reader :verify_mode ## # Creates a new Bundler::Persistent::Net::HTTP::Persistent. # # Set a +name+ for fun. Your library name should be good enough, but this # otherwise has no purpose. # # +proxy+ may be set to a Bundler::URI::HTTP or :ENV to pick up proxy options from # the environment. See proxy_from_env for details. # # In order to use a Bundler::URI for the proxy you may need to do some extra work # beyond Bundler::URI parsing if the proxy requires a password: # # proxy = Bundler::URI 'http://proxy.example' # proxy.user = 'AzureDiamond' # proxy.password = 'hunter2' # # Set +pool_size+ to limit the maximum number of connections allowed. # Defaults to 1/4 the number of allowed file handles or 256 if your OS does # not support a limit on allowed file handles. You can have no more than # this many threads with active HTTP transactions. def initialize name: nil, proxy: nil, pool_size: DEFAULT_POOL_SIZE @name = name @debug_output = nil @proxy_uri = nil @no_proxy = [] @headers = {} @override_headers = {} @http_versions = {} @keep_alive = 30 @open_timeout = nil @read_timeout = nil @write_timeout = nil @idle_timeout = 5 @max_requests = nil @max_retries = 1 @socket_options = [] @ssl_generation = 0 # incremented when SSL session variables change @socket_options << [Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1] if Socket.const_defined? :TCP_NODELAY @pool = Bundler::Persistent::Net::HTTP::Persistent::Pool.new size: pool_size do |http_args| Bundler::Persistent::Net::HTTP::Persistent::Connection.new Net::HTTP, http_args, @ssl_generation end @certificate = nil @ca_file = nil @ca_path = nil @ciphers = nil @private_key = nil @ssl_timeout = nil @ssl_version = nil @min_version = nil @max_version = nil @verify_callback = nil @verify_depth = nil @verify_mode = nil @cert_store = nil @generation = 0 # incremented when proxy Bundler::URI changes if HAVE_OPENSSL then @verify_mode = OpenSSL::SSL::VERIFY_PEER @reuse_ssl_sessions = OpenSSL::SSL.const_defined? :Session end self.proxy = proxy if proxy end ## # Sets this client's OpenSSL::X509::Certificate def certificate= certificate @certificate = certificate reconnect_ssl end # For Net::HTTP parity alias cert= certificate= ## # Sets the SSL certificate authority file. def ca_file= file @ca_file = file reconnect_ssl end ## # Sets the SSL certificate authority path. def ca_path= path @ca_path = path reconnect_ssl end ## # Overrides the default SSL certificate store used for verifying # connections. def cert_store= store @cert_store = store reconnect_ssl end ## # The ciphers allowed for SSL connections def ciphers= ciphers @ciphers = ciphers reconnect_ssl end ## # Creates a new connection for +uri+ def connection_for uri use_ssl = uri.scheme.downcase == 'https' net_http_args = [uri.hostname, uri.port] # I'm unsure if uri.host or uri.hostname should be checked against # the proxy bypass list. if @proxy_uri and not proxy_bypass? uri.host, uri.port then net_http_args.concat @proxy_args else net_http_args.concat [nil, nil, nil, nil] end connection = @pool.checkout net_http_args http = connection.http connection.ressl @ssl_generation if connection.ssl_generation != @ssl_generation if not http.started? then ssl http if use_ssl start http elsif expired? connection then reset connection end http.keep_alive_timeout = @idle_timeout if @idle_timeout http.max_retries = @max_retries if http.respond_to?(:max_retries=) http.read_timeout = @read_timeout if @read_timeout http.write_timeout = @write_timeout if @write_timeout && http.respond_to?(:write_timeout=) return yield connection rescue Errno::ECONNREFUSED address = http.proxy_address || http.address port = http.proxy_port || http.port raise Error, "connection refused: #{address}:#{port}" rescue Errno::EHOSTDOWN address = http.proxy_address || http.address port = http.proxy_port || http.port raise Error, "host down: #{address}:#{port}" ensure @pool.checkin net_http_args end ## # CGI::escape wrapper def escape str CGI.escape str if str end ## # CGI::unescape wrapper def unescape str CGI.unescape str if str end ## # Returns true if the connection should be reset due to an idle timeout, or # maximum request count, false otherwise. def expired? connection return true if @max_requests && connection.requests >= @max_requests return false unless @idle_timeout return true if @idle_timeout.zero? Time.now - connection.last_use > @idle_timeout end ## # Starts the Net::HTTP +connection+ def start http http.set_debug_output @debug_output if @debug_output http.open_timeout = @open_timeout if @open_timeout http.start socket = http.instance_variable_get :@socket if socket then # for fakeweb @socket_options.each do |option| socket.io.setsockopt(*option) end end end ## # Finishes the Net::HTTP +connection+ def finish connection connection.finish connection.http.instance_variable_set :@last_communicated, nil connection.http.instance_variable_set :@ssl_session, nil unless @reuse_ssl_sessions end ## # Returns the HTTP protocol version for +uri+ def http_version uri @http_versions["#{uri.hostname}:#{uri.port}"] end ## # Adds "http://" to the String +uri+ if it is missing. def normalize_uri uri (uri =~ /^https?:/) ? uri : "http://#{uri}" end ## # Set the maximum number of retries for a request. # # Defaults to one retry. # # Set this to 0 to disable retries. def max_retries= retries retries = retries.to_int raise ArgumentError, "max_retries must be positive" if retries < 0 @max_retries = retries reconnect end ## # Sets this client's SSL private key def private_key= key @private_key = key reconnect_ssl end # For Net::HTTP parity alias key= private_key= ## # Sets the proxy server. The +proxy+ may be the Bundler::URI of the proxy server, # the symbol +:ENV+ which will read the proxy from the environment or nil to # disable use of a proxy. See #proxy_from_env for details on setting the # proxy from the environment. # # If the proxy Bundler::URI is set after requests have been made, the next request # will shut-down and re-open all connections. # # The +no_proxy+ query parameter can be used to specify hosts which shouldn't # be reached via proxy; if set it should be a comma separated list of # hostname suffixes, optionally with +:port+ appended, for example # example.com,some.host:8080. def proxy= proxy @proxy_uri = case proxy when :ENV then proxy_from_env when Bundler::URI::HTTP then proxy when nil then # ignore else raise ArgumentError, 'proxy must be :ENV or a Bundler::URI::HTTP' end @no_proxy.clear if @proxy_uri then @proxy_args = [ @proxy_uri.hostname, @proxy_uri.port, unescape(@proxy_uri.user), unescape(@proxy_uri.password), ] @proxy_connection_id = [nil, *@proxy_args].join ':' if @proxy_uri.query then @no_proxy = CGI.parse(@proxy_uri.query)['no_proxy'].join(',').downcase.split(',').map { |x| x.strip }.reject { |x| x.empty? } end end reconnect reconnect_ssl end ## # Creates a Bundler::URI for an HTTP proxy server from ENV variables. # # If +HTTP_PROXY+ is set a proxy will be returned. # # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the Bundler::URI is given the # indicated user and password unless HTTP_PROXY contains either of these in # the Bundler::URI. # # The +NO_PROXY+ ENV variable can be used to specify hosts which shouldn't # be reached via proxy; if set it should be a comma separated list of # hostname suffixes, optionally with +:port+ appended, for example # example.com,some.host:8080. When set to * no proxy will # be returned. # # For Windows users, lowercase ENV variables are preferred over uppercase ENV # variables. def proxy_from_env env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY'] return nil if env_proxy.nil? or env_proxy.empty? uri = Bundler::URI normalize_uri env_proxy env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY'] # '*' is special case for always bypass return nil if env_no_proxy == '*' if env_no_proxy then uri.query = "no_proxy=#{escape(env_no_proxy)}" end unless uri.user or uri.password then uri.user = escape ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER'] uri.password = escape ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS'] end uri end ## # Returns true when proxy should by bypassed for host. def proxy_bypass? host, port host = host.downcase host_port = [host, port].join ':' @no_proxy.each do |name| return true if host[-name.length, name.length] == name or host_port[-name.length, name.length] == name end false end ## # Forces reconnection of all HTTP connections, including TLS/SSL # connections. def reconnect @generation += 1 end ## # Forces reconnection of only TLS/SSL connections. def reconnect_ssl @ssl_generation += 1 end ## # Finishes then restarts the Net::HTTP +connection+ def reset connection http = connection.http finish connection start http rescue Errno::ECONNREFUSED e = Error.new "connection refused: #{http.address}:#{http.port}" e.set_backtrace $@ raise e rescue Errno::EHOSTDOWN e = Error.new "host down: #{http.address}:#{http.port}" e.set_backtrace $@ raise e end ## # Makes a request on +uri+. If +req+ is nil a Net::HTTP::Get is performed # against +uri+. # # If a block is passed #request behaves like Net::HTTP#request (the body of # the response will not have been read). # # +req+ must be a Net::HTTPGenericRequest subclass (see Net::HTTP for a list). def request uri, req = nil, &block uri = Bundler::URI uri req = request_setup req || uri response = nil connection_for uri do |connection| http = connection.http begin connection.requests += 1 response = http.request req, &block if req.connection_close? or (response.http_version <= '1.0' and not response.connection_keep_alive?) or response.connection_close? then finish connection end rescue Exception # make sure to close the connection when it was interrupted finish connection raise ensure connection.last_use = Time.now end end @http_versions["#{uri.hostname}:#{uri.port}"] ||= response.http_version response end ## # Creates a GET request if +req_or_uri+ is a Bundler::URI and adds headers to the # request. # # Returns the request. def request_setup req_or_uri # :nodoc: req = if req_or_uri.respond_to? 'request_uri' then Net::HTTP::Get.new req_or_uri.request_uri else req_or_uri end @headers.each do |pair| req.add_field(*pair) end @override_headers.each do |name, value| req[name] = value end unless req['Connection'] then req.add_field 'Connection', 'keep-alive' req.add_field 'Keep-Alive', @keep_alive end req end ## # Shuts down all connections # # *NOTE*: Calling shutdown for can be dangerous! # # If any thread is still using a connection it may cause an error! Call # #shutdown when you are completely done making requests! def shutdown @pool.shutdown { |http| http.finish } end ## # Enables SSL on +connection+ def ssl connection connection.use_ssl = true connection.ciphers = @ciphers if @ciphers connection.ssl_timeout = @ssl_timeout if @ssl_timeout connection.ssl_version = @ssl_version if @ssl_version connection.min_version = @min_version if @min_version connection.max_version = @max_version if @max_version connection.verify_depth = @verify_depth connection.verify_mode = @verify_mode if OpenSSL::SSL::VERIFY_PEER == OpenSSL::SSL::VERIFY_NONE and not Object.const_defined?(:I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG) then warn <<-WARNING !!!SECURITY WARNING!!! The SSL HTTP connection to: #{connection.address}:#{connection.port} !!!MAY NOT BE VERIFIED!!! On your platform your OpenSSL implementation is broken. There is no difference between the values of VERIFY_NONE and VERIFY_PEER. This means that attempting to verify the security of SSL connections may not work. This exposes you to man-in-the-middle exploits, snooping on the contents of your connection and other dangers to the security of your data. To disable this warning define the following constant at top-level in your application: I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG = nil WARNING end connection.ca_file = @ca_file if @ca_file connection.ca_path = @ca_path if @ca_path if @ca_file or @ca_path then connection.verify_mode = OpenSSL::SSL::VERIFY_PEER connection.verify_callback = @verify_callback if @verify_callback end if @certificate and @private_key then connection.cert = @certificate connection.key = @private_key end connection.cert_store = if @cert_store then @cert_store else store = OpenSSL::X509::Store.new store.set_default_paths store end end ## # SSL session lifetime def ssl_timeout= ssl_timeout @ssl_timeout = ssl_timeout reconnect_ssl end ## # SSL version to use def ssl_version= ssl_version @ssl_version = ssl_version reconnect_ssl end ## # Minimum SSL version to use def min_version= min_version @min_version = min_version reconnect_ssl end ## # maximum SSL version to use def max_version= max_version @max_version = max_version reconnect_ssl end ## # Sets the depth of SSL certificate verification def verify_depth= verify_depth @verify_depth = verify_depth reconnect_ssl end ## # Sets the HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_PEER. # # Setting this to VERIFY_NONE is a VERY BAD IDEA and should NEVER be used. # Securely transfer the correct certificate and update the default # certificate store or set the ca file instead. def verify_mode= verify_mode @verify_mode = verify_mode reconnect_ssl end ## # SSL verification callback. def verify_callback= callback @verify_callback = callback reconnect_ssl end end require_relative 'persistent/connection' require_relative 'persistent/pool' PKu]6lffbbundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rbnu[class Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti < Bundler::ConnectionPool::TimedStack # :nodoc: ## # Returns a new hash that has arrays for keys # # Using a class method to limit the bindings referenced by the hash's # default_proc def self.hash_of_arrays # :nodoc: Hash.new { |h,k| h[k] = [] } end def initialize(size = 0, &block) super @enqueued = 0 @ques = self.class.hash_of_arrays @lru = {} @key = :"connection_args-#{object_id}" end def empty? (@created - @enqueued) >= @max end def length @max - @created + @enqueued end private def connection_stored? options = {} # :nodoc: !@ques[options[:connection_args]].empty? end def fetch_connection options = {} # :nodoc: connection_args = options[:connection_args] @enqueued -= 1 lru_update connection_args @ques[connection_args].pop end def lru_update connection_args # :nodoc: @lru.delete connection_args @lru[connection_args] = true end def shutdown_connections # :nodoc: @ques.each_key do |key| super connection_args: key end end def store_connection obj, options = {} # :nodoc: @ques[options[:connection_args]].push obj @enqueued += 1 end def try_create options = {} # :nodoc: connection_args = options[:connection_args] if @created >= @max && @enqueued >= 1 oldest, = @lru.first @lru.delete oldest @ques[oldest].pop @created -= 1 end if @created < @max @created += 1 lru_update connection_args return @create_block.call(connection_args) end end end PKu]hO8Ubundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rbnu[class Bundler::Persistent::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc: attr_reader :available # :nodoc: attr_reader :key # :nodoc: def initialize(options = {}, &block) super @available = Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti.new(@size, &block) @key = "current-#{@available.object_id}" end def checkin net_http_args stack = Thread.current[@key][net_http_args] ||= [] raise Bundler::ConnectionPool::Error, 'no connections are checked out' if stack.empty? conn = stack.pop if stack.empty? @available.push conn, connection_args: net_http_args Thread.current[@key].delete(net_http_args) Thread.current[@key] = nil if Thread.current[@key].empty? end nil end def checkout net_http_args stacks = Thread.current[@key] ||= {} stack = stacks[net_http_args] ||= [] if stack.empty? then conn = @available.pop connection_args: net_http_args else conn = stack.last end stack.push conn conn end def shutdown Thread.current[@key] = nil super end end require_relative 'timed_stack_multi' PKu](ц[bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rbnu[## # A Net::HTTP connection wrapper that holds extra information for managing the # connection's lifetime. class Bundler::Persistent::Net::HTTP::Persistent::Connection # :nodoc: attr_accessor :http attr_accessor :last_use attr_accessor :requests attr_accessor :ssl_generation def initialize http_class, http_args, ssl_generation @http = http_class.new(*http_args) @ssl_generation = ssl_generation reset end def finish @http.finish rescue IOError ensure reset end def reset @last_use = Bundler::Persistent::Net::HTTP::Persistent::EPOCH @requests = 0 end def ressl ssl_generation @ssl_generation = ssl_generation finish end end PKu]t//<bundler-2.2.24/lib/bundler/vendor/fileutils/lib/fileutils.rbnu[# frozen_string_literal: true begin require 'rbconfig' rescue LoadError # for make mjit-headers end # # = fileutils.rb # # Copyright (c) 2000-2007 Minero Aoki # # This program is free software. # You can distribute/modify this program under the same terms of ruby. # # == module Bundler::FileUtils # # Namespace for several file utility methods for copying, moving, removing, etc. # # === Module Functions # # require 'bundler/vendor/fileutils/lib/fileutils' # # Bundler::FileUtils.cd(dir, **options) # Bundler::FileUtils.cd(dir, **options) {|dir| block } # Bundler::FileUtils.pwd() # Bundler::FileUtils.mkdir(dir, **options) # Bundler::FileUtils.mkdir(list, **options) # Bundler::FileUtils.mkdir_p(dir, **options) # Bundler::FileUtils.mkdir_p(list, **options) # Bundler::FileUtils.rmdir(dir, **options) # Bundler::FileUtils.rmdir(list, **options) # Bundler::FileUtils.ln(target, link, **options) # Bundler::FileUtils.ln(targets, dir, **options) # Bundler::FileUtils.ln_s(target, link, **options) # Bundler::FileUtils.ln_s(targets, dir, **options) # Bundler::FileUtils.ln_sf(target, link, **options) # Bundler::FileUtils.cp(src, dest, **options) # Bundler::FileUtils.cp(list, dir, **options) # Bundler::FileUtils.cp_r(src, dest, **options) # Bundler::FileUtils.cp_r(list, dir, **options) # Bundler::FileUtils.mv(src, dest, **options) # Bundler::FileUtils.mv(list, dir, **options) # Bundler::FileUtils.rm(list, **options) # Bundler::FileUtils.rm_r(list, **options) # Bundler::FileUtils.rm_rf(list, **options) # Bundler::FileUtils.install(src, dest, **options) # Bundler::FileUtils.chmod(mode, list, **options) # Bundler::FileUtils.chmod_R(mode, list, **options) # Bundler::FileUtils.chown(user, group, list, **options) # Bundler::FileUtils.chown_R(user, group, list, **options) # Bundler::FileUtils.touch(list, **options) # # Possible options are: # # :force :: forced operation (rewrite files if exist, remove # directories if not empty, etc.); # :verbose :: print command to be run, in bash syntax, before # performing it; # :preserve :: preserve object's group, user and modification # time on copying; # :noop :: no changes are made (usable in combination with # :verbose which will print the command to run) # # Each method documents the options that it honours. See also ::commands, # ::options and ::options_of methods to introspect which command have which # options. # # All methods that have the concept of a "source" file or directory can take # either one file or a list of files in that argument. See the method # documentation for examples. # # There are some `low level' methods, which do not accept keyword arguments: # # Bundler::FileUtils.copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) # Bundler::FileUtils.copy_file(src, dest, preserve = false, dereference = true) # Bundler::FileUtils.copy_stream(srcstream, deststream) # Bundler::FileUtils.remove_entry(path, force = false) # Bundler::FileUtils.remove_entry_secure(path, force = false) # Bundler::FileUtils.remove_file(path, force = false) # Bundler::FileUtils.compare_file(path_a, path_b) # Bundler::FileUtils.compare_stream(stream_a, stream_b) # Bundler::FileUtils.uptodate?(file, cmp_list) # # == module Bundler::FileUtils::Verbose # # This module has all methods of Bundler::FileUtils module, but it outputs messages # before acting. This equates to passing the :verbose flag to methods # in Bundler::FileUtils. # # == module Bundler::FileUtils::NoWrite # # This module has all methods of Bundler::FileUtils module, but never changes # files/directories. This equates to passing the :noop flag to methods # in Bundler::FileUtils. # # == module Bundler::FileUtils::DryRun # # This module has all methods of Bundler::FileUtils module, but never changes # files/directories. This equates to passing the :noop and # :verbose flags to methods in Bundler::FileUtils. # module Bundler::FileUtils VERSION = "1.4.1" def self.private_module_function(name) #:nodoc: module_function name private_class_method name end # # Returns the name of the current directory. # def pwd Dir.pwd end module_function :pwd alias getwd pwd module_function :getwd # # Changes the current directory to the directory +dir+. # # If this method is called with block, resumes to the previous # working directory after the block execution has finished. # # Bundler::FileUtils.cd('/') # change directory # # Bundler::FileUtils.cd('/', verbose: true) # change directory and report it # # Bundler::FileUtils.cd('/') do # change directory # # ... # do something # end # return to original directory # def cd(dir, verbose: nil, &block) # :yield: dir fu_output_message "cd #{dir}" if verbose result = Dir.chdir(dir, &block) fu_output_message 'cd -' if verbose and block result end module_function :cd alias chdir cd module_function :chdir # # Returns true if +new+ is newer than all +old_list+. # Non-existent files are older than any file. # # Bundler::FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \ # system 'make hello.o' # def uptodate?(new, old_list) return false unless File.exist?(new) new_time = File.mtime(new) old_list.each do |old| if File.exist?(old) return false unless new_time > File.mtime(old) end end true end module_function :uptodate? def remove_trailing_slash(dir) #:nodoc: dir == '/' ? dir : dir.chomp(?/) end private_module_function :remove_trailing_slash # # Creates one or more directories. # # Bundler::FileUtils.mkdir 'test' # Bundler::FileUtils.mkdir %w(tmp data) # Bundler::FileUtils.mkdir 'notexist', noop: true # Does not really create. # Bundler::FileUtils.mkdir 'tmp', mode: 0700 # def mkdir(list, mode: nil, noop: nil, verbose: nil) list = fu_list(list) fu_output_message "mkdir #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose return if noop list.each do |dir| fu_mkdir dir, mode end end module_function :mkdir # # Creates a directory and all its parent directories. # For example, # # Bundler::FileUtils.mkdir_p '/usr/local/lib/ruby' # # causes to make following directories, if they do not exist. # # * /usr # * /usr/local # * /usr/local/lib # * /usr/local/lib/ruby # # You can pass several directories at a time in a list. # def mkdir_p(list, mode: nil, noop: nil, verbose: nil) list = fu_list(list) fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose return *list if noop list.map {|path| remove_trailing_slash(path)}.each do |path| # optimize for the most common case begin fu_mkdir path, mode next rescue SystemCallError next if File.directory?(path) end stack = [] until path == stack.last # dirname("/")=="/", dirname("C:/")=="C:/" stack.push path path = File.dirname(path) end stack.pop # root directory should exist stack.reverse_each do |dir| begin fu_mkdir dir, mode rescue SystemCallError raise unless File.directory?(dir) end end end return *list end module_function :mkdir_p alias mkpath mkdir_p alias makedirs mkdir_p module_function :mkpath module_function :makedirs def fu_mkdir(path, mode) #:nodoc: path = remove_trailing_slash(path) if mode Dir.mkdir path, mode File.chmod mode, path else Dir.mkdir path end end private_module_function :fu_mkdir # # Removes one or more directories. # # Bundler::FileUtils.rmdir 'somedir' # Bundler::FileUtils.rmdir %w(somedir anydir otherdir) # # Does not really remove directory; outputs message. # Bundler::FileUtils.rmdir 'somedir', verbose: true, noop: true # def rmdir(list, parents: nil, noop: nil, verbose: nil) list = fu_list(list) fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose return if noop list.each do |dir| Dir.rmdir(dir = remove_trailing_slash(dir)) if parents begin until (parent = File.dirname(dir)) == '.' or parent == dir dir = parent Dir.rmdir(dir) end rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT end end end end module_function :rmdir # # :call-seq: # Bundler::FileUtils.ln(target, link, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln(target, dir, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln(targets, dir, force: nil, noop: nil, verbose: nil) # # In the first form, creates a hard link +link+ which points to +target+. # If +link+ already exists, raises Errno::EEXIST. # But if the +force+ option is set, overwrites +link+. # # Bundler::FileUtils.ln 'gcc', 'cc', verbose: true # Bundler::FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs' # # In the second form, creates a link +dir/target+ pointing to +target+. # In the third form, creates several hard links in the directory +dir+, # pointing to each item in +targets+. # If +dir+ is not a directory, raises Errno::ENOTDIR. # # Bundler::FileUtils.cd '/sbin' # Bundler::FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked. # def ln(src, dest, force: nil, noop: nil, verbose: nil) fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest0(src, dest) do |s,d| remove_file d, true if force File.link s, d end end module_function :ln alias link ln module_function :link # # Hard link +src+ to +dest+. If +src+ is a directory, this method links # all its contents recursively. If +dest+ is a directory, links # +src+ to +dest/src+. # # +src+ can be a list of files. # # If +dereference_root+ is true, this method dereference tree root. # # If +remove_destination+ is true, this method removes each destination file before copy. # # Bundler::FileUtils.rm_r site_ruby + '/mylib', force: true # Bundler::FileUtils.cp_lr 'lib/', site_ruby + '/mylib' # # # Examples of linking several files to target directory. # Bundler::FileUtils.cp_lr %w(mail.rb field.rb debug/), site_ruby + '/tmail' # Bundler::FileUtils.cp_lr Dir.glob('*.rb'), '/home/aamine/lib/ruby', noop: true, verbose: true # # # If you want to link all contents of a directory instead of the # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y, # # use the following code. # Bundler::FileUtils.cp_lr 'src/.', 'dest' # cp_lr('src', 'dest') makes dest/src, but this doesn't. # def cp_lr(src, dest, noop: nil, verbose: nil, dereference_root: true, remove_destination: false) fu_output_message "cp -lr#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest(src, dest) do |s, d| link_entry s, d, dereference_root, remove_destination end end module_function :cp_lr # # :call-seq: # Bundler::FileUtils.ln_s(target, link, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln_s(target, dir, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln_s(targets, dir, force: nil, noop: nil, verbose: nil) # # In the first form, creates a symbolic link +link+ which points to +target+. # If +link+ already exists, raises Errno::EEXIST. # But if the force option is set, overwrites +link+. # # Bundler::FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby' # Bundler::FileUtils.ln_s 'verylongsourcefilename.c', 'c', force: true # # In the second form, creates a link +dir/target+ pointing to +target+. # In the third form, creates several symbolic links in the directory +dir+, # pointing to each item in +targets+. # If +dir+ is not a directory, raises Errno::ENOTDIR. # # Bundler::FileUtils.ln_s Dir.glob('/bin/*.rb'), '/home/foo/bin' # def ln_s(src, dest, force: nil, noop: nil, verbose: nil) fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest0(src, dest) do |s,d| remove_file d, true if force File.symlink s, d end end module_function :ln_s alias symlink ln_s module_function :symlink # # :call-seq: # Bundler::FileUtils.ln_sf(*args) # # Same as # # Bundler::FileUtils.ln_s(*args, force: true) # def ln_sf(src, dest, noop: nil, verbose: nil) ln_s src, dest, force: true, noop: noop, verbose: verbose end module_function :ln_sf # # Hard links a file system entry +src+ to +dest+. # If +src+ is a directory, this method links its contents recursively. # # Both of +src+ and +dest+ must be a path name. # +src+ must exist, +dest+ must not exist. # # If +dereference_root+ is true, this method dereferences the tree root. # # If +remove_destination+ is true, this method removes each destination file before copy. # def link_entry(src, dest, dereference_root = false, remove_destination = false) Entry_.new(src, nil, dereference_root).traverse do |ent| destent = Entry_.new(dest, ent.rel, false) File.unlink destent.path if remove_destination && File.file?(destent.path) ent.link destent.path end end module_function :link_entry # # Copies a file content +src+ to +dest+. If +dest+ is a directory, # copies +src+ to +dest/src+. # # If +src+ is a list of files, then +dest+ must be a directory. # # Bundler::FileUtils.cp 'eval.c', 'eval.c.org' # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6' # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', verbose: true # Bundler::FileUtils.cp 'symlink', 'dest' # copy content, "dest" is not a symlink # def cp(src, dest, preserve: nil, noop: nil, verbose: nil) fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest(src, dest) do |s, d| copy_file s, d, preserve end end module_function :cp alias copy cp module_function :copy # # Copies +src+ to +dest+. If +src+ is a directory, this method copies # all its contents recursively. If +dest+ is a directory, copies # +src+ to +dest/src+. # # +src+ can be a list of files. # # If +dereference_root+ is true, this method dereference tree root. # # If +remove_destination+ is true, this method removes each destination file before copy. # # # Installing Ruby library "mylib" under the site_ruby # Bundler::FileUtils.rm_r site_ruby + '/mylib', force: true # Bundler::FileUtils.cp_r 'lib/', site_ruby + '/mylib' # # # Examples of copying several files to target directory. # Bundler::FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail' # Bundler::FileUtils.cp_r Dir.glob('*.rb'), '/home/foo/lib/ruby', noop: true, verbose: true # # # If you want to copy all contents of a directory instead of the # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y, # # use following code. # Bundler::FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes dest/src, # # but this doesn't. # def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil, dereference_root: true, remove_destination: nil) fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest(src, dest) do |s, d| copy_entry s, d, preserve, dereference_root, remove_destination end end module_function :cp_r # # Copies a file system entry +src+ to +dest+. # If +src+ is a directory, this method copies its contents recursively. # This method preserves file types, c.f. symlink, directory... # (FIFO, device files and etc. are not supported yet) # # Both of +src+ and +dest+ must be a path name. # +src+ must exist, +dest+ must not exist. # # If +preserve+ is true, this method preserves owner, group, and # modified time. Permissions are copied regardless +preserve+. # # If +dereference_root+ is true, this method dereference tree root. # # If +remove_destination+ is true, this method removes each destination file before copy. # def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) if dereference_root src = File.realpath(src) end Entry_.new(src, nil, false).wrap_traverse(proc do |ent| destent = Entry_.new(dest, ent.rel, false) File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path)) ent.copy destent.path end, proc do |ent| destent = Entry_.new(dest, ent.rel, false) ent.copy_metadata destent.path if preserve end) end module_function :copy_entry # # Copies file contents of +src+ to +dest+. # Both of +src+ and +dest+ must be a path name. # def copy_file(src, dest, preserve = false, dereference = true) ent = Entry_.new(src, nil, dereference) ent.copy_file dest ent.copy_metadata dest if preserve end module_function :copy_file # # Copies stream +src+ to +dest+. # +src+ must respond to #read(n) and # +dest+ must respond to #write(str). # def copy_stream(src, dest) IO.copy_stream(src, dest) end module_function :copy_stream # # Moves file(s) +src+ to +dest+. If +file+ and +dest+ exist on the different # disk partition, the file is copied then the original file is removed. # # Bundler::FileUtils.mv 'badname.rb', 'goodname.rb' # Bundler::FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', force: true # no error # # Bundler::FileUtils.mv %w(junk.txt dust.txt), '/home/foo/.trash/' # Bundler::FileUtils.mv Dir.glob('test*.rb'), 'test', noop: true, verbose: true # def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose return if noop fu_each_src_dest(src, dest) do |s, d| destent = Entry_.new(d, nil, true) begin if destent.exist? if destent.directory? raise Errno::EEXIST, d end end begin File.rename s, d rescue Errno::EXDEV, Errno::EPERM # move from unencrypted to encrypted dir (ext4) copy_entry s, d, true if secure remove_entry_secure s, force else remove_entry s, force end end rescue SystemCallError raise unless force end end end module_function :mv alias move mv module_function :move # # Remove file(s) specified in +list+. This method cannot remove directories. # All StandardErrors are ignored when the :force option is set. # # Bundler::FileUtils.rm %w( junk.txt dust.txt ) # Bundler::FileUtils.rm Dir.glob('*.so') # Bundler::FileUtils.rm 'NotExistFile', force: true # never raises exception # def rm(list, force: nil, noop: nil, verbose: nil) list = fu_list(list) fu_output_message "rm#{force ? ' -f' : ''} #{list.join ' '}" if verbose return if noop list.each do |path| remove_file path, force end end module_function :rm alias remove rm module_function :remove # # Equivalent to # # Bundler::FileUtils.rm(list, force: true) # def rm_f(list, noop: nil, verbose: nil) rm list, force: true, noop: noop, verbose: verbose end module_function :rm_f alias safe_unlink rm_f module_function :safe_unlink # # remove files +list+[0] +list+[1]... If +list+[n] is a directory, # removes its all contents recursively. This method ignores # StandardError when :force option is set. # # Bundler::FileUtils.rm_r Dir.glob('/tmp/*') # Bundler::FileUtils.rm_r 'some_dir', force: true # # WARNING: This method causes local vulnerability # if one of parent directories or removing directory tree are world # writable (including /tmp, whose permission is 1777), and the current # process has strong privilege such as Unix super user (root), and the # system has symbolic link. For secure removing, read the documentation # of remove_entry_secure carefully, and set :secure option to true. # Default is secure: false. # # NOTE: This method calls remove_entry_secure if :secure option is set. # See also remove_entry_secure. # def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) list = fu_list(list) fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose return if noop list.each do |path| if secure remove_entry_secure path, force else remove_entry path, force end end end module_function :rm_r # # Equivalent to # # Bundler::FileUtils.rm_r(list, force: true) # # WARNING: This method causes local vulnerability. # Read the documentation of rm_r first. # def rm_rf(list, noop: nil, verbose: nil, secure: nil) rm_r list, force: true, noop: noop, verbose: verbose, secure: secure end module_function :rm_rf alias rmtree rm_rf module_function :rmtree # # This method removes a file system entry +path+. +path+ shall be a # regular file, a directory, or something. If +path+ is a directory, # remove it recursively. This method is required to avoid TOCTTOU # (time-of-check-to-time-of-use) local security vulnerability of rm_r. # #rm_r causes security hole when: # # * Parent directory is world writable (including /tmp). # * Removing directory tree includes world writable directory. # * The system has symbolic link. # # To avoid this security hole, this method applies special preprocess. # If +path+ is a directory, this method chown(2) and chmod(2) all # removing directories. This requires the current process is the # owner of the removing whole directory tree, or is the super user (root). # # WARNING: You must ensure that *ALL* parent directories cannot be # moved by other untrusted users. For example, parent directories # should not be owned by untrusted users, and should not be world # writable except when the sticky bit set. # # WARNING: Only the owner of the removing directory tree, or Unix super # user (root) should invoke this method. Otherwise this method does not # work. # # For details of this security vulnerability, see Perl's case: # # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448 # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452 # # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100]. # def remove_entry_secure(path, force = false) unless fu_have_symlink? remove_entry path, force return end fullpath = File.expand_path(path) st = File.lstat(fullpath) unless st.directory? File.unlink fullpath return end # is a directory. parent_st = File.stat(File.dirname(fullpath)) unless parent_st.world_writable? remove_entry path, force return end unless parent_st.sticky? raise ArgumentError, "parent directory is world writable, Bundler::FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})" end # freeze tree root euid = Process.euid dot_file = fullpath + "/." begin File.open(dot_file) {|f| unless fu_stat_identical_entry?(st, f.stat) # symlink (TOC-to-TOU attack?) File.unlink fullpath return end f.chown euid, -1 f.chmod 0700 } rescue Errno::EISDIR # JRuby in non-native mode can't open files as dirs File.lstat(dot_file).tap {|fstat| unless fu_stat_identical_entry?(st, fstat) # symlink (TOC-to-TOU attack?) File.unlink fullpath return end File.chown euid, -1, dot_file File.chmod 0700, dot_file } end unless fu_stat_identical_entry?(st, File.lstat(fullpath)) # TOC-to-TOU attack? File.unlink fullpath return end # ---- tree root is frozen ---- root = Entry_.new(path) root.preorder_traverse do |ent| if ent.directory? ent.chown euid, -1 ent.chmod 0700 end end root.postorder_traverse do |ent| begin ent.remove rescue raise unless force end end rescue raise unless force end module_function :remove_entry_secure def fu_have_symlink? #:nodoc: File.symlink nil, nil rescue NotImplementedError return false rescue TypeError return true end private_module_function :fu_have_symlink? def fu_stat_identical_entry?(a, b) #:nodoc: a.dev == b.dev and a.ino == b.ino end private_module_function :fu_stat_identical_entry? # # This method removes a file system entry +path+. # +path+ might be a regular file, a directory, or something. # If +path+ is a directory, remove it recursively. # # See also remove_entry_secure. # def remove_entry(path, force = false) Entry_.new(path).postorder_traverse do |ent| begin ent.remove rescue raise unless force end end rescue raise unless force end module_function :remove_entry # # Removes a file +path+. # This method ignores StandardError if +force+ is true. # def remove_file(path, force = false) Entry_.new(path).remove_file rescue raise unless force end module_function :remove_file # # Removes a directory +dir+ and its contents recursively. # This method ignores StandardError if +force+ is true. # def remove_dir(path, force = false) remove_entry path, force # FIXME?? check if it is a directory end module_function :remove_dir # # Returns true if the contents of a file +a+ and a file +b+ are identical. # # Bundler::FileUtils.compare_file('somefile', 'somefile') #=> true # Bundler::FileUtils.compare_file('/dev/null', '/dev/urandom') #=> false # def compare_file(a, b) return false unless File.size(a) == File.size(b) File.open(a, 'rb') {|fa| File.open(b, 'rb') {|fb| return compare_stream(fa, fb) } } end module_function :compare_file alias identical? compare_file alias cmp compare_file module_function :identical? module_function :cmp # # Returns true if the contents of a stream +a+ and +b+ are identical. # def compare_stream(a, b) bsize = fu_stream_blksize(a, b) if RUBY_VERSION > "2.4" sa = String.new(capacity: bsize) sb = String.new(capacity: bsize) else sa = String.new sb = String.new end begin a.read(bsize, sa) b.read(bsize, sb) return true if sa.empty? && sb.empty? end while sa == sb false end module_function :compare_stream # # If +src+ is not same as +dest+, copies it and changes the permission # mode to +mode+. If +dest+ is a directory, destination is +dest+/+src+. # This method removes destination before copy. # # Bundler::FileUtils.install 'ruby', '/usr/local/bin/ruby', mode: 0755, verbose: true # Bundler::FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', verbose: true # def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil, noop: nil, verbose: nil) if verbose msg = +"install -c" msg << ' -p' if preserve msg << ' -m ' << mode_to_s(mode) if mode msg << " -o #{owner}" if owner msg << " -g #{group}" if group msg << ' ' << [src,dest].flatten.join(' ') fu_output_message msg end return if noop uid = fu_get_uid(owner) gid = fu_get_gid(group) fu_each_src_dest(src, dest) do |s, d| st = File.stat(s) unless File.exist?(d) and compare_file(s, d) remove_file d, true copy_file s, d File.utime st.atime, st.mtime, d if preserve File.chmod fu_mode(mode, st), d if mode File.chown uid, gid, d if uid or gid end end end module_function :install def user_mask(target) #:nodoc: target.each_char.inject(0) do |mask, chr| case chr when "u" mask | 04700 when "g" mask | 02070 when "o" mask | 01007 when "a" mask | 07777 else raise ArgumentError, "invalid `who' symbol in file mode: #{chr}" end end end private_module_function :user_mask def apply_mask(mode, user_mask, op, mode_mask) #:nodoc: case op when '=' (mode & ~user_mask) | (user_mask & mode_mask) when '+' mode | (user_mask & mode_mask) when '-' mode & ~(user_mask & mode_mask) end end private_module_function :apply_mask def symbolic_modes_to_i(mode_sym, path) #:nodoc: mode = if File::Stat === path path.mode else File.stat(path).mode end mode_sym.split(/,/).inject(mode & 07777) do |current_mode, clause| target, *actions = clause.split(/([=+-])/) raise ArgumentError, "invalid file mode: #{mode_sym}" if actions.empty? target = 'a' if target.empty? user_mask = user_mask(target) actions.each_slice(2) do |op, perm| need_apply = op == '=' mode_mask = (perm || '').each_char.inject(0) do |mask, chr| case chr when "r" mask | 0444 when "w" mask | 0222 when "x" mask | 0111 when "X" if FileTest.directory? path mask | 0111 else mask end when "s" mask | 06000 when "t" mask | 01000 when "u", "g", "o" if mask.nonzero? current_mode = apply_mask(current_mode, user_mask, op, mask) end need_apply = false copy_mask = user_mask(chr) (current_mode & copy_mask) / (copy_mask & 0111) * (user_mask & 0111) else raise ArgumentError, "invalid `perm' symbol in file mode: #{chr}" end end if mode_mask.nonzero? || need_apply current_mode = apply_mask(current_mode, user_mask, op, mode_mask) end end current_mode end end private_module_function :symbolic_modes_to_i def fu_mode(mode, path) #:nodoc: mode.is_a?(String) ? symbolic_modes_to_i(mode, path) : mode end private_module_function :fu_mode def mode_to_s(mode) #:nodoc: mode.is_a?(String) ? mode : "%o" % mode end private_module_function :mode_to_s # # Changes permission bits on the named files (in +list+) to the bit pattern # represented by +mode+. # # +mode+ is the symbolic and absolute mode can be used. # # Absolute mode is # Bundler::FileUtils.chmod 0755, 'somecommand' # Bundler::FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb) # Bundler::FileUtils.chmod 0755, '/usr/bin/ruby', verbose: true # # Symbolic mode is # Bundler::FileUtils.chmod "u=wrx,go=rx", 'somecommand' # Bundler::FileUtils.chmod "u=wr,go=rr", %w(my.rb your.rb his.rb her.rb) # Bundler::FileUtils.chmod "u=wrx,go=rx", '/usr/bin/ruby', verbose: true # # "a" :: is user, group, other mask. # "u" :: is user's mask. # "g" :: is group's mask. # "o" :: is other's mask. # "w" :: is write permission. # "r" :: is read permission. # "x" :: is execute permission. # "X" :: # is execute permission for directories only, must be used in conjunction with "+" # "s" :: is uid, gid. # "t" :: is sticky bit. # "+" :: is added to a class given the specified mode. # "-" :: Is removed from a given class given mode. # "=" :: Is the exact nature of the class will be given a specified mode. def chmod(mode, list, noop: nil, verbose: nil) list = fu_list(list) fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose return if noop list.each do |path| Entry_.new(path).chmod(fu_mode(mode, path)) end end module_function :chmod # # Changes permission bits on the named files (in +list+) # to the bit pattern represented by +mode+. # # Bundler::FileUtils.chmod_R 0700, "/tmp/app.#{$$}" # Bundler::FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}" # def chmod_R(mode, list, noop: nil, verbose: nil, force: nil) list = fu_list(list) fu_output_message sprintf('chmod -R%s %s %s', (force ? 'f' : ''), mode_to_s(mode), list.join(' ')) if verbose return if noop list.each do |root| Entry_.new(root).traverse do |ent| begin ent.chmod(fu_mode(mode, ent.path)) rescue raise unless force end end end end module_function :chmod_R # # Changes owner and group on the named files (in +list+) # to the user +user+ and the group +group+. +user+ and +group+ # may be an ID (Integer/String) or a name (String). # If +user+ or +group+ is nil, this method does not change # the attribute. # # Bundler::FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby' # Bundler::FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), verbose: true # def chown(user, group, list, noop: nil, verbose: nil) list = fu_list(list) fu_output_message sprintf('chown %s %s', (group ? "#{user}:#{group}" : user || ':'), list.join(' ')) if verbose return if noop uid = fu_get_uid(user) gid = fu_get_gid(group) list.each do |path| Entry_.new(path).chown uid, gid end end module_function :chown # # Changes owner and group on the named files (in +list+) # to the user +user+ and the group +group+ recursively. # +user+ and +group+ may be an ID (Integer/String) or # a name (String). If +user+ or +group+ is nil, this # method does not change the attribute. # # Bundler::FileUtils.chown_R 'www', 'www', '/var/www/htdocs' # Bundler::FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', verbose: true # def chown_R(user, group, list, noop: nil, verbose: nil, force: nil) list = fu_list(list) fu_output_message sprintf('chown -R%s %s %s', (force ? 'f' : ''), (group ? "#{user}:#{group}" : user || ':'), list.join(' ')) if verbose return if noop uid = fu_get_uid(user) gid = fu_get_gid(group) list.each do |root| Entry_.new(root).traverse do |ent| begin ent.chown uid, gid rescue raise unless force end end end end module_function :chown_R def fu_get_uid(user) #:nodoc: return nil unless user case user when Integer user when /\A\d+\z/ user.to_i else require 'etc' Etc.getpwnam(user) ? Etc.getpwnam(user).uid : nil end end private_module_function :fu_get_uid def fu_get_gid(group) #:nodoc: return nil unless group case group when Integer group when /\A\d+\z/ group.to_i else require 'etc' Etc.getgrnam(group) ? Etc.getgrnam(group).gid : nil end end private_module_function :fu_get_gid # # Updates modification time (mtime) and access time (atime) of file(s) in # +list+. Files are created if they don't exist. # # Bundler::FileUtils.touch 'timestamp' # Bundler::FileUtils.touch Dir.glob('*.c'); system 'make' # def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil) list = fu_list(list) t = mtime if verbose fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}" end return if noop list.each do |path| created = nocreate begin File.utime(t, t, path) rescue Errno::ENOENT raise if created File.open(path, 'a') { ; } created = true retry if t end end end module_function :touch private module StreamUtils_ private case (defined?(::RbConfig) ? ::RbConfig::CONFIG['host_os'] : ::RUBY_PLATFORM) when /mswin|mingw/ def fu_windows?; true end else def fu_windows?; false end end def fu_copy_stream0(src, dest, blksize = nil) #:nodoc: IO.copy_stream(src, dest) end def fu_stream_blksize(*streams) streams.each do |s| next unless s.respond_to?(:stat) size = fu_blksize(s.stat) return size if size end fu_default_blksize() end def fu_blksize(st) s = st.blksize return nil unless s return nil if s == 0 s end def fu_default_blksize 1024 end end include StreamUtils_ extend StreamUtils_ class Entry_ #:nodoc: internal use only include StreamUtils_ def initialize(a, b = nil, deref = false) @prefix = @rel = @path = nil if b @prefix = a @rel = b else @path = a end @deref = deref @stat = nil @lstat = nil end def inspect "\#<#{self.class} #{path()}>" end def path if @path File.path(@path) else join(@prefix, @rel) end end def prefix @prefix || @path end def rel @rel end def dereference? @deref end def exist? begin lstat true rescue Errno::ENOENT false end end def file? s = lstat! s and s.file? end def directory? s = lstat! s and s.directory? end def symlink? s = lstat! s and s.symlink? end def chardev? s = lstat! s and s.chardev? end def blockdev? s = lstat! s and s.blockdev? end def socket? s = lstat! s and s.socket? end def pipe? s = lstat! s and s.pipe? end S_IF_DOOR = 0xD000 def door? s = lstat! s and (s.mode & 0xF000 == S_IF_DOOR) end def entries opts = {} opts[:encoding] = ::Encoding::UTF_8 if fu_windows? files = if Dir.respond_to?(:children) Dir.children(path, **opts) else Dir.entries(path(), **opts) .reject {|n| n == '.' or n == '..' } end untaint = RUBY_VERSION < '2.7' files.map {|n| Entry_.new(prefix(), join(rel(), untaint ? n.untaint : n)) } end def stat return @stat if @stat if lstat() and lstat().symlink? @stat = File.stat(path()) else @stat = lstat() end @stat end def stat! return @stat if @stat if lstat! and lstat!.symlink? @stat = File.stat(path()) else @stat = lstat! end @stat rescue SystemCallError nil end def lstat if dereference? @lstat ||= File.stat(path()) else @lstat ||= File.lstat(path()) end end def lstat! lstat() rescue SystemCallError nil end def chmod(mode) if symlink? File.lchmod mode, path() if have_lchmod? else File.chmod mode, path() end end def chown(uid, gid) if symlink? File.lchown uid, gid, path() if have_lchown? else File.chown uid, gid, path() end end def link(dest) case when directory? if !File.exist?(dest) and descendant_directory?(dest, path) raise ArgumentError, "cannot link directory %s to itself %s" % [path, dest] end begin Dir.mkdir dest rescue raise unless File.directory?(dest) end else File.link path(), dest end end def copy(dest) lstat case when file? copy_file dest when directory? if !File.exist?(dest) and descendant_directory?(dest, path) raise ArgumentError, "cannot copy directory %s to itself %s" % [path, dest] end begin Dir.mkdir dest rescue raise unless File.directory?(dest) end when symlink? File.symlink File.readlink(path()), dest when chardev?, blockdev? raise "cannot handle device file" when socket? begin require 'socket' rescue LoadError raise "cannot handle socket" else raise "cannot handle socket" unless defined?(UNIXServer) end UNIXServer.new(dest).close File.chmod lstat().mode, dest when pipe? raise "cannot handle FIFO" unless File.respond_to?(:mkfifo) File.mkfifo dest, lstat().mode when door? raise "cannot handle door: #{path()}" else raise "unknown file type: #{path()}" end end def copy_file(dest) File.open(path()) do |s| File.open(dest, 'wb', s.stat.mode) do |f| IO.copy_stream(s, f) end end end def copy_metadata(path) st = lstat() if !st.symlink? File.utime st.atime, st.mtime, path end mode = st.mode begin if st.symlink? begin File.lchown st.uid, st.gid, path rescue NotImplementedError end else File.chown st.uid, st.gid, path end rescue Errno::EPERM, Errno::EACCES # clear setuid/setgid mode &= 01777 end if st.symlink? begin File.lchmod mode, path rescue NotImplementedError end else File.chmod mode, path end end def remove if directory? remove_dir1 else remove_file end end def remove_dir1 platform_support { Dir.rmdir path().chomp(?/) } end def remove_file platform_support { File.unlink path } end def platform_support return yield unless fu_windows? first_time_p = true begin yield rescue Errno::ENOENT raise rescue => err if first_time_p first_time_p = false begin File.chmod 0700, path() # Windows does not have symlink retry rescue SystemCallError end end raise err end end def preorder_traverse stack = [self] while ent = stack.pop yield ent stack.concat ent.entries.reverse if ent.directory? end end alias traverse preorder_traverse def postorder_traverse if directory? entries().each do |ent| ent.postorder_traverse do |e| yield e end end end ensure yield self end def wrap_traverse(pre, post) pre.call self if directory? entries.each do |ent| ent.wrap_traverse pre, post end end post.call self end private @@fileutils_rb_have_lchmod = nil def have_lchmod? # This is not MT-safe, but it does not matter. if @@fileutils_rb_have_lchmod == nil @@fileutils_rb_have_lchmod = check_have_lchmod? end @@fileutils_rb_have_lchmod end def check_have_lchmod? return false unless File.respond_to?(:lchmod) File.lchmod 0 return true rescue NotImplementedError return false end @@fileutils_rb_have_lchown = nil def have_lchown? # This is not MT-safe, but it does not matter. if @@fileutils_rb_have_lchown == nil @@fileutils_rb_have_lchown = check_have_lchown? end @@fileutils_rb_have_lchown end def check_have_lchown? return false unless File.respond_to?(:lchown) File.lchown nil, nil return true rescue NotImplementedError return false end def join(dir, base) return File.path(dir) if not base or base == '.' return File.path(base) if not dir or dir == '.' File.join(dir, base) end if File::ALT_SEPARATOR DIRECTORY_TERM = "(?=[/#{Regexp.quote(File::ALT_SEPARATOR)}]|\\z)" else DIRECTORY_TERM = "(?=/|\\z)" end def descendant_directory?(descendant, ascendant) if File::FNM_SYSCASE.nonzero? File.expand_path(File.dirname(descendant)).casecmp(File.expand_path(ascendant)) == 0 else File.expand_path(File.dirname(descendant)) == File.expand_path(ascendant) end end end # class Entry_ def fu_list(arg) #:nodoc: [arg].flatten.map {|path| File.path(path) } end private_module_function :fu_list def fu_each_src_dest(src, dest) #:nodoc: fu_each_src_dest0(src, dest) do |s, d| raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s, d) yield s, d end end private_module_function :fu_each_src_dest def fu_each_src_dest0(src, dest) #:nodoc: if tmp = Array.try_convert(src) tmp.each do |s| s = File.path(s) yield s, File.join(dest, File.basename(s)) end else src = File.path(src) if File.directory?(dest) yield src, File.join(dest, File.basename(src)) else yield src, File.path(dest) end end end private_module_function :fu_each_src_dest0 def fu_same?(a, b) #:nodoc: File.identical?(a, b) end private_module_function :fu_same? def fu_output_message(msg) #:nodoc: output = @fileutils_output if defined?(@fileutils_output) output ||= $stderr if defined?(@fileutils_label) msg = @fileutils_label + msg end output.puts msg end private_module_function :fu_output_message # This hash table holds command options. OPT_TABLE = {} #:nodoc: internal use only (private_instance_methods & methods(false)).inject(OPT_TABLE) {|tbl, name| (tbl[name.to_s] = instance_method(name).parameters).map! {|t, n| n if t == :key}.compact! tbl } public # # Returns an Array of names of high-level methods that accept any keyword # arguments. # # p Bundler::FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...] # def self.commands OPT_TABLE.keys end # # Returns an Array of option names. # # p Bundler::FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"] # def self.options OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s } end # # Returns true if the method +mid+ have an option +opt+. # # p Bundler::FileUtils.have_option?(:cp, :noop) #=> true # p Bundler::FileUtils.have_option?(:rm, :force) #=> true # p Bundler::FileUtils.have_option?(:rm, :preserve) #=> false # def self.have_option?(mid, opt) li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}" li.include?(opt) end # # Returns an Array of option names of the method +mid+. # # p Bundler::FileUtils.options_of(:rm) #=> ["noop", "verbose", "force"] # def self.options_of(mid) OPT_TABLE[mid.to_s].map {|sym| sym.to_s } end # # Returns an Array of methods names which have the option +opt+. # # p Bundler::FileUtils.collect_method(:preserve) #=> ["cp", "cp_r", "copy", "install"] # def self.collect_method(opt) OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) } end private LOW_METHODS = singleton_methods(false) - collect_method(:noop).map(&:intern) # :nodoc: module LowMethods # :nodoc: internal use only private def _do_nothing(*)end ::Bundler::FileUtils::LOW_METHODS.map {|name| alias_method name, :_do_nothing} end METHODS = singleton_methods() - [:private_module_function, # :nodoc: :commands, :options, :have_option?, :options_of, :collect_method] # # This module has all methods of Bundler::FileUtils module, but it outputs messages # before acting. This equates to passing the :verbose flag to # methods in Bundler::FileUtils. # module Verbose include Bundler::FileUtils names = ::Bundler::FileUtils.collect_method(:verbose) names.each do |name| module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args, **options) super(*args, **options, verbose: true) end EOS end private(*names) extend self class << self public(*::Bundler::FileUtils::METHODS) end end # # This module has all methods of Bundler::FileUtils module, but never changes # files/directories. This equates to passing the :noop flag # to methods in Bundler::FileUtils. # module NoWrite include Bundler::FileUtils include LowMethods names = ::Bundler::FileUtils.collect_method(:noop) names.each do |name| module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args, **options) super(*args, **options, noop: true) end EOS end private(*names) extend self class << self public(*::Bundler::FileUtils::METHODS) end end # # This module has all methods of Bundler::FileUtils module, but never changes # files/directories, with printing message before acting. # This equates to passing the :noop and :verbose flag # to methods in Bundler::FileUtils. # module DryRun include Bundler::FileUtils include LowMethods names = ::Bundler::FileUtils.collect_method(:noop) names.each do |name| module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args, **options) super(*args, **options, noop: true, verbose: true) end EOS end private(*names) extend self class << self public(*::Bundler::FileUtils::METHODS) end end end PKu]OU0 0bundler-2.2.24/lib/bundler/vendor/uri/lib/uri.rbnu[# frozen_string_literal: false # Bundler::URI is a module providing classes to handle Uniform Resource Identifiers # (RFC2396[http://tools.ietf.org/html/rfc2396]). # # == Features # # * Uniform way of handling URIs. # * Flexibility to introduce custom Bundler::URI schemes. # * Flexibility to have an alternate Bundler::URI::Parser (or just different patterns # and regexp's). # # == Basic example # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI("http://foo.com/posts?id=30&limit=5#time=1305298413") # #=> # # # uri.scheme #=> "http" # uri.host #=> "foo.com" # uri.path #=> "/posts" # uri.query #=> "id=30&limit=5" # uri.fragment #=> "time=1305298413" # # uri.to_s #=> "http://foo.com/posts?id=30&limit=5#time=1305298413" # # == Adding custom URIs # # module Bundler::URI # class RSYNC < Generic # DEFAULT_PORT = 873 # end # @@schemes['RSYNC'] = RSYNC # end # #=> Bundler::URI::RSYNC # # Bundler::URI.scheme_list # #=> {"FILE"=>Bundler::URI::File, "FTP"=>Bundler::URI::FTP, "HTTP"=>Bundler::URI::HTTP, # # "HTTPS"=>Bundler::URI::HTTPS, "LDAP"=>Bundler::URI::LDAP, "LDAPS"=>Bundler::URI::LDAPS, # # "MAILTO"=>Bundler::URI::MailTo, "RSYNC"=>Bundler::URI::RSYNC} # # uri = Bundler::URI("rsync://rsync.foo.com") # #=> # # # == RFC References # # A good place to view an RFC spec is http://www.ietf.org/rfc.html. # # Here is a list of all related RFC's: # - RFC822[http://tools.ietf.org/html/rfc822] # - RFC1738[http://tools.ietf.org/html/rfc1738] # - RFC2255[http://tools.ietf.org/html/rfc2255] # - RFC2368[http://tools.ietf.org/html/rfc2368] # - RFC2373[http://tools.ietf.org/html/rfc2373] # - RFC2396[http://tools.ietf.org/html/rfc2396] # - RFC2732[http://tools.ietf.org/html/rfc2732] # - RFC3986[http://tools.ietf.org/html/rfc3986] # # == Class tree # # - Bundler::URI::Generic (in uri/generic.rb) # - Bundler::URI::File - (in uri/file.rb) # - Bundler::URI::FTP - (in uri/ftp.rb) # - Bundler::URI::HTTP - (in uri/http.rb) # - Bundler::URI::HTTPS - (in uri/https.rb) # - Bundler::URI::LDAP - (in uri/ldap.rb) # - Bundler::URI::LDAPS - (in uri/ldaps.rb) # - Bundler::URI::MailTo - (in uri/mailto.rb) # - Bundler::URI::Parser - (in uri/common.rb) # - Bundler::URI::REGEXP - (in uri/common.rb) # - Bundler::URI::REGEXP::PATTERN - (in uri/common.rb) # - Bundler::URI::Util - (in uri/common.rb) # - Bundler::URI::Escape - (in uri/common.rb) # - Bundler::URI::Error - (in uri/common.rb) # - Bundler::URI::InvalidURIError - (in uri/common.rb) # - Bundler::URI::InvalidComponentError - (in uri/common.rb) # - Bundler::URI::BadURIError - (in uri/common.rb) # # == Copyright Info # # Author:: Akira Yamada # Documentation:: # Akira Yamada # Dmitry V. Sabanin # Vincent Batts # License:: # Copyright (c) 2001 akira yamada # You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # module Bundler::URI end require_relative 'uri/version' require_relative 'uri/common' require_relative 'uri/generic' require_relative 'uri/file' require_relative 'uri/ftp' require_relative 'uri/http' require_relative 'uri/https' require_relative 'uri/ldap' require_relative 'uri/ldaps' require_relative 'uri/mailto' PKu]M0 0 7bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/mailto.rbnu[# frozen_string_literal: false # = uri/mailto.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'generic' module Bundler::URI # # RFC6068, the mailto URL scheme. # class MailTo < Generic include REGEXP # A Default port of nil for Bundler::URI::MailTo. DEFAULT_PORT = nil # An Array of the available components for Bundler::URI::MailTo. COMPONENT = [ :scheme, :to, :headers ].freeze # :stopdoc: # "hname" and "hvalue" are encodings of an RFC 822 header name and # value, respectively. As with "to", all URL reserved characters must # be encoded. # # "#mailbox" is as specified in RFC 822 [RFC822]. This means that it # consists of zero or more comma-separated mail addresses, possibly # including "phrase" and "comment" components. Note that all URL # reserved characters in "to" must be encoded: in particular, # parentheses, commas, and the percent sign ("%"), which commonly occur # in the "mailbox" syntax. # # Within mailto URLs, the characters "?", "=", "&" are reserved. # ; RFC 6068 # hfields = "?" hfield *( "&" hfield ) # hfield = hfname "=" hfvalue # hfname = *qchar # hfvalue = *qchar # qchar = unreserved / pct-encoded / some-delims # some-delims = "!" / "$" / "'" / "(" / ")" / "*" # / "+" / "," / ";" / ":" / "@" # # ; RFC3986 # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" # pct-encoded = "%" HEXDIG HEXDIG HEADER_REGEXP = /\A(?(?:%\h\h|[!$'-.0-;@-Z_a-z~])*=(?:%\h\h|[!$'-.0-;@-Z_a-z~])*)(?:&\g)*\z/ # practical regexp for email address # https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address EMAIL_REGEXP = /\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/ # :startdoc: # # == Description # # Creates a new Bundler::URI::MailTo object from components, with syntax checking. # # Components can be provided as an Array or Hash. If an Array is used, # the components must be supplied as [to, headers]. # # If a Hash is used, the keys are the component names preceded by colons. # # The headers can be supplied as a pre-encoded string, such as # "subject=subscribe&cc=address", or as an Array of Arrays # like [['subject', 'subscribe'], ['cc', 'address']]. # # Examples: # # require 'bundler/vendor/uri/lib/uri' # # m1 = Bundler::URI::MailTo.build(['joe@example.com', 'subject=Ruby']) # m1.to_s # => "mailto:joe@example.com?subject=Ruby" # # m2 = Bundler::URI::MailTo.build(['john@example.com', [['Subject', 'Ruby'], ['Cc', 'jack@example.com']]]) # m2.to_s # => "mailto:john@example.com?Subject=Ruby&Cc=jack@example.com" # # m3 = Bundler::URI::MailTo.build({:to => 'listman@example.com', :headers => [['subject', 'subscribe']]}) # m3.to_s # => "mailto:listman@example.com?subject=subscribe" # def self.build(args) tmp = Util.make_components_hash(self, args) case tmp[:to] when Array tmp[:opaque] = tmp[:to].join(',') when String tmp[:opaque] = tmp[:to].dup else tmp[:opaque] = '' end if tmp[:headers] query = case tmp[:headers] when Array tmp[:headers].collect { |x| if x.kind_of?(Array) x[0] + '=' + x[1..-1].join else x.to_s end }.join('&') when Hash tmp[:headers].collect { |h,v| h + '=' + v }.join('&') else tmp[:headers].to_s end unless query.empty? tmp[:opaque] << '?' << query end end super(tmp) end # # == Description # # Creates a new Bundler::URI::MailTo object from generic URL components with # no syntax checking. # # This method is usually called from Bundler::URI::parse, which checks # the validity of each component. # def initialize(*arg) super(*arg) @to = nil @headers = [] # The RFC3986 parser does not normally populate opaque @opaque = "?#{@query}" if @query && !@opaque unless @opaque raise InvalidComponentError, "missing opaque part for mailto URL" end to, header = @opaque.split('?', 2) # allow semicolon as a addr-spec separator # http://support.microsoft.com/kb/820868 unless /\A(?:[^@,;]+@[^@,;]+(?:\z|[,;]))*\z/ =~ to raise InvalidComponentError, "unrecognised opaque part for mailtoURL: #{@opaque}" end if arg[10] # arg_check self.to = to self.headers = header else set_to(to) set_headers(header) end end # The primary e-mail address of the URL, as a String. attr_reader :to # E-mail headers set by the URL, as an Array of Arrays. attr_reader :headers # Checks the to +v+ component. def check_to(v) return true unless v return true if v.size == 0 v.split(/[,;]/).each do |addr| # check url safety as path-rootless if /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*\z/ !~ addr raise InvalidComponentError, "an address in 'to' is invalid as Bundler::URI #{addr.dump}" end # check addr-spec # don't s/\+/ /g addr.gsub!(/%\h\h/, Bundler::URI::TBLDECWWWCOMP_) if EMAIL_REGEXP !~ addr raise InvalidComponentError, "an address in 'to' is invalid as uri-escaped addr-spec #{addr.dump}" end end true end private :check_to # Private setter for to +v+. def set_to(v) @to = v end protected :set_to # Setter for to +v+. def to=(v) check_to(v) set_to(v) v end # Checks the headers +v+ component against either # * HEADER_REGEXP def check_headers(v) return true unless v return true if v.size == 0 if HEADER_REGEXP !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end true end private :check_headers # Private setter for headers +v+. def set_headers(v) @headers = [] if v v.split('&').each do |x| @headers << x.split(/=/, 2) end end end protected :set_headers # Setter for headers +v+. def headers=(v) check_headers(v) set_headers(v) v end # Constructs String from Bundler::URI. def to_s @scheme + ':' + if @to @to else '' end + if @headers.size > 0 '?' + @headers.collect{|x| x.join('=')}.join('&') else '' end + if @fragment '#' + @fragment else '' end end # Returns the RFC822 e-mail text equivalent of the URL, as a String. # # Example: # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("mailto:ruby-list@ruby-lang.org?Subject=subscribe&cc=myaddr") # uri.to_mailtext # # => "To: ruby-list@ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n" # def to_mailtext to = Bundler::URI.decode_www_form_component(@to) head = '' body = '' @headers.each do |x| case x[0] when 'body' body = Bundler::URI.decode_www_form_component(x[1]) when 'to' to << ', ' + Bundler::URI.decode_www_form_component(x[1]) else head << Bundler::URI.decode_www_form_component(x[0]).capitalize + ': ' + Bundler::URI.decode_www_form_component(x[1]) + "\n" end end "To: #{to} #{head} #{body} " end alias to_rfc822text to_mailtext end @@schemes['MAILTO'] = MailTo end PKu]M}5bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/file.rbnu[# frozen_string_literal: true require_relative 'generic' module Bundler::URI # # The "file" Bundler::URI is defined by RFC8089. # class File < Generic # A Default port of nil for Bundler::URI::File. DEFAULT_PORT = nil # # An Array of the available components for Bundler::URI::File. # COMPONENT = [ :scheme, :host, :path ].freeze # # == Description # # Creates a new Bundler::URI::File object from components, with syntax checking. # # The components accepted are +host+ and +path+. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the # order [host, path]. # # Examples: # # require 'bundler/vendor/uri/lib/uri' # # uri1 = Bundler::URI::File.build(['host.example.com', '/path/file.zip']) # uri1.to_s # => "file://host.example.com/path/file.zip" # # uri2 = Bundler::URI::File.build({:host => 'host.example.com', # :path => '/ruby/src'}) # uri2.to_s # => "file://host.example.com/ruby/src" # def self.build(args) tmp = Util::make_components_hash(self, args) super(tmp) end # Protected setter for the host component +v+. # # See also Bundler::URI::Generic.host=. # def set_host(v) v = "" if v.nil? || v == "localhost" @host = v end # do nothing def set_port(v) end # raise InvalidURIError def check_userinfo(user) raise Bundler::URI::InvalidURIError, "can not set userinfo for file Bundler::URI" end # raise InvalidURIError def check_user(user) raise Bundler::URI::InvalidURIError, "can not set user for file Bundler::URI" end # raise InvalidURIError def check_password(user) raise Bundler::URI::InvalidURIError, "can not set password for file Bundler::URI" end # do nothing def set_userinfo(v) end # do nothing def set_user(v) end # do nothing def set_password(v) end end @@schemes['FILE'] = File end PKu]]F֖֖8bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/generic.rbnu[# frozen_string_literal: true # = uri/generic.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'common' autoload :IPSocket, 'socket' autoload :IPAddr, 'ipaddr' module Bundler::URI # # Base class for all Bundler::URI classes. # Implements generic Bundler::URI syntax as per RFC 2396. # class Generic include Bundler::URI # # A Default port of nil for Bundler::URI::Generic. # DEFAULT_PORT = nil # # Returns default port. # def self.default_port self::DEFAULT_PORT end # # Returns default port. # def default_port self.class.default_port end # # An Array of the available components for Bundler::URI::Generic. # COMPONENT = [ :scheme, :userinfo, :host, :port, :registry, :path, :opaque, :query, :fragment ].freeze # # Components of the Bundler::URI in the order. # def self.component self::COMPONENT end USE_REGISTRY = false # :nodoc: def self.use_registry # :nodoc: self::USE_REGISTRY end # # == Synopsis # # See ::new. # # == Description # # At first, tries to create a new Bundler::URI::Generic instance using # Bundler::URI::Generic::build. But, if exception Bundler::URI::InvalidComponentError is raised, # then it does Bundler::URI::Escape.escape all Bundler::URI components and tries again. # def self.build2(args) begin return self.build(args) rescue InvalidComponentError if args.kind_of?(Array) return self.build(args.collect{|x| if x.is_a?(String) DEFAULT_PARSER.escape(x) else x end }) elsif args.kind_of?(Hash) tmp = {} args.each do |key, value| tmp[key] = if value DEFAULT_PARSER.escape(value) else value end end return self.build(tmp) end end end # # == Synopsis # # See ::new. # # == Description # # Creates a new Bundler::URI::Generic instance from components of Bundler::URI::Generic # with check. Components are: scheme, userinfo, host, port, registry, path, # opaque, query, and fragment. You can provide arguments either by an Array or a Hash. # See ::new for hash keys to use or for order of array items. # def self.build(args) if args.kind_of?(Array) && args.size == ::Bundler::URI::Generic::COMPONENT.size tmp = args.dup elsif args.kind_of?(Hash) tmp = ::Bundler::URI::Generic::COMPONENT.collect do |c| if args.include?(c) args[c] else nil end end else component = self.class.component rescue ::Bundler::URI::Generic::COMPONENT raise ArgumentError, "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})" end tmp << nil tmp << true return self.new(*tmp) end # # == Args # # +scheme+:: # Protocol scheme, i.e. 'http','ftp','mailto' and so on. # +userinfo+:: # User name and password, i.e. 'sdmitry:bla'. # +host+:: # Server host name. # +port+:: # Server port. # +registry+:: # Registry of naming authorities. # +path+:: # Path on server. # +opaque+:: # Opaque part. # +query+:: # Query data. # +fragment+:: # Part of the Bundler::URI after '#' character. # +parser+:: # Parser for internal use [Bundler::URI::DEFAULT_PARSER by default]. # +arg_check+:: # Check arguments [false by default]. # # == Description # # Creates a new Bundler::URI::Generic instance from ``generic'' components without check. # def initialize(scheme, userinfo, host, port, registry, path, opaque, query, fragment, parser = DEFAULT_PARSER, arg_check = false) @scheme = nil @user = nil @password = nil @host = nil @port = nil @path = nil @query = nil @opaque = nil @fragment = nil @parser = parser == DEFAULT_PARSER ? nil : parser if arg_check self.scheme = scheme self.userinfo = userinfo self.hostname = host self.port = port self.path = path self.query = query self.opaque = opaque self.fragment = fragment else self.set_scheme(scheme) self.set_userinfo(userinfo) self.set_host(host) self.set_port(port) self.set_path(path) self.query = query self.set_opaque(opaque) self.fragment=(fragment) end if registry raise InvalidURIError, "the scheme #{@scheme} does not accept registry part: #{registry} (or bad hostname?)" end @scheme&.freeze self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2) self.set_port(self.default_port) if self.default_port && !@port end # # Returns the scheme component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz").scheme #=> "http" # attr_reader :scheme # Returns the host component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz").host #=> "foo" # # It returns nil if no host component exists. # # Bundler::URI("mailto:foo@example.org").host #=> nil # # The component does not contain the port number. # # Bundler::URI("http://foo:8080/bar/baz").host #=> "foo" # # Since IPv6 addresses are wrapped with brackets in URIs, # this method returns IPv6 addresses wrapped with brackets. # This form is not appropriate to pass to socket methods such as TCPSocket.open. # If unwrapped host names are required, use the #hostname method. # # Bundler::URI("http://[::1]/bar/baz").host #=> "[::1]" # Bundler::URI("http://[::1]/bar/baz").hostname #=> "::1" # attr_reader :host # Returns the port component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz").port #=> 80 # Bundler::URI("http://foo:8080/bar/baz").port #=> 8080 # attr_reader :port def registry # :nodoc: nil end # Returns the path component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz").path #=> "/bar/baz" # attr_reader :path # Returns the query component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz?search=FooBar").query #=> "search=FooBar" # attr_reader :query # Returns the opaque part of the Bundler::URI. # # Bundler::URI("mailto:foo@example.org").opaque #=> "foo@example.org" # Bundler::URI("http://foo/bar/baz").opaque #=> nil # # The portion of the path that does not make use of the slash '/'. # The path typically refers to an absolute path or an opaque part. # (See RFC2396 Section 3 and 5.2.) # attr_reader :opaque # Returns the fragment component of the Bundler::URI. # # Bundler::URI("http://foo/bar/baz?search=FooBar#ponies").fragment #=> "ponies" # attr_reader :fragment # Returns the parser to be used. # # Unless a Bundler::URI::Parser is defined, DEFAULT_PARSER is used. # def parser if !defined?(@parser) || !@parser DEFAULT_PARSER else @parser || DEFAULT_PARSER end end # Replaces self by other Bundler::URI object. # def replace!(oth) if self.class != oth.class raise ArgumentError, "expected #{self.class} object" end component.each do |c| self.__send__("#{c}=", oth.__send__(c)) end end private :replace! # # Components of the Bundler::URI in the order. # def component self.class.component end # # Checks the scheme +v+ component against the Bundler::URI::Parser Regexp for :SCHEME. # def check_scheme(v) if v && parser.regexp[:SCHEME] !~ v raise InvalidComponentError, "bad component(expected scheme component): #{v}" end return true end private :check_scheme # Protected setter for the scheme component +v+. # # See also Bundler::URI::Generic.scheme=. # def set_scheme(v) @scheme = v&.downcase end protected :set_scheme # # == Args # # +v+:: # String # # == Description # # Public setter for the scheme component +v+ # (with validation). # # See also Bundler::URI::Generic.check_scheme. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.scheme = "https" # uri.to_s #=> "https://my.example.com" # def scheme=(v) check_scheme(v) set_scheme(v) v end # # Checks the +user+ and +password+. # # If +password+ is not provided, then +user+ is # split, using Bundler::URI::Generic.split_userinfo, to # pull +user+ and +password. # # See also Bundler::URI::Generic.check_user, Bundler::URI::Generic.check_password. # def check_userinfo(user, password = nil) if !password user, password = split_userinfo(user) end check_user(user) check_password(password, user) return true end private :check_userinfo # # Checks the user +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp for :USERINFO. # # Can not have a registry or opaque component defined, # with a user component defined. # def check_user(v) if @opaque raise InvalidURIError, "can not set user with opaque" end return v unless v if parser.regexp[:USERINFO] !~ v raise InvalidComponentError, "bad component(expected userinfo component or user component): #{v}" end return true end private :check_user # # Checks the password +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp for :USERINFO. # # Can not have a registry or opaque component defined, # with a user component defined. # def check_password(v, user = @user) if @opaque raise InvalidURIError, "can not set password with opaque" end return v unless v if !user raise InvalidURIError, "password component depends user component" end if parser.regexp[:USERINFO] !~ v raise InvalidComponentError, "bad password component" end return true end private :check_password # # Sets userinfo, argument is string like 'name:pass'. # def userinfo=(userinfo) if userinfo.nil? return nil end check_userinfo(*userinfo) set_userinfo(*userinfo) # returns userinfo end # # == Args # # +v+:: # String # # == Description # # Public setter for the +user+ component # (with validation). # # See also Bundler::URI::Generic.check_user. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://john:S3nsit1ve@my.example.com") # uri.user = "sam" # uri.to_s #=> "http://sam:V3ry_S3nsit1ve@my.example.com" # def user=(user) check_user(user) set_user(user) # returns user end # # == Args # # +v+:: # String # # == Description # # Public setter for the +password+ component # (with validation). # # See also Bundler::URI::Generic.check_password. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://john:S3nsit1ve@my.example.com") # uri.password = "V3ry_S3nsit1ve" # uri.to_s #=> "http://john:V3ry_S3nsit1ve@my.example.com" # def password=(password) check_password(password) set_password(password) # returns password end # Protected setter for the +user+ component, and +password+ if available # (with validation). # # See also Bundler::URI::Generic.userinfo=. # def set_userinfo(user, password = nil) unless password user, password = split_userinfo(user) end @user = user @password = password if password [@user, @password] end protected :set_userinfo # Protected setter for the user component +v+. # # See also Bundler::URI::Generic.user=. # def set_user(v) set_userinfo(v, @password) v end protected :set_user # Protected setter for the password component +v+. # # See also Bundler::URI::Generic.password=. # def set_password(v) @password = v # returns v end protected :set_password # Returns the userinfo +ui+ as [user, password] # if properly formatted as 'user:password'. def split_userinfo(ui) return nil, nil unless ui user, password = ui.split(':', 2) return user, password end private :split_userinfo # Escapes 'user:password' +v+ based on RFC 1738 section 3.1. def escape_userpass(v) parser.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/ end private :escape_userpass # Returns the userinfo, either as 'user' or 'user:password'. def userinfo if @user.nil? nil elsif @password.nil? @user else @user + ':' + @password end end # Returns the user component. def user @user end # Returns the password component. def password @password end # # Checks the host +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp for :HOST. # # Can not have a registry or opaque component defined, # with a host component defined. # def check_host(v) return v unless v if @opaque raise InvalidURIError, "can not set host with registry or opaque" elsif parser.regexp[:HOST] !~ v raise InvalidComponentError, "bad component(expected host component): #{v}" end return true end private :check_host # Protected setter for the host component +v+. # # See also Bundler::URI::Generic.host=. # def set_host(v) @host = v end protected :set_host # # == Args # # +v+:: # String # # == Description # # Public setter for the host component +v+ # (with validation). # # See also Bundler::URI::Generic.check_host. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.host = "foo.com" # uri.to_s #=> "http://foo.com" # def host=(v) check_host(v) set_host(v) v end # Extract the host part of the Bundler::URI and unwrap brackets for IPv6 addresses. # # This method is the same as Bundler::URI::Generic#host except # brackets for IPv6 (and future IP) addresses are removed. # # uri = Bundler::URI("http://[::1]/bar") # uri.hostname #=> "::1" # uri.host #=> "[::1]" # def hostname v = self.host /\A\[(.*)\]\z/ =~ v ? $1 : v end # Sets the host part of the Bundler::URI as the argument with brackets for IPv6 addresses. # # This method is the same as Bundler::URI::Generic#host= except # the argument can be a bare IPv6 address. # # uri = Bundler::URI("http://foo/bar") # uri.hostname = "::1" # uri.to_s #=> "http://[::1]/bar" # # If the argument seems to be an IPv6 address, # it is wrapped with brackets. # def hostname=(v) v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v self.host = v end # # Checks the port +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp for :PORT. # # Can not have a registry or opaque component defined, # with a port component defined. # def check_port(v) return v unless v if @opaque raise InvalidURIError, "can not set port with registry or opaque" elsif !v.kind_of?(Integer) && parser.regexp[:PORT] !~ v raise InvalidComponentError, "bad component(expected port component): #{v.inspect}" end return true end private :check_port # Protected setter for the port component +v+. # # See also Bundler::URI::Generic.port=. # def set_port(v) v = v.empty? ? nil : v.to_i unless !v || v.kind_of?(Integer) @port = v end protected :set_port # # == Args # # +v+:: # String # # == Description # # Public setter for the port component +v+ # (with validation). # # See also Bundler::URI::Generic.check_port. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.port = 8080 # uri.to_s #=> "http://my.example.com:8080" # def port=(v) check_port(v) set_port(v) port end def check_registry(v) # :nodoc: raise InvalidURIError, "can not set registry" end private :check_registry def set_registry(v) #:nodoc: raise InvalidURIError, "can not set registry" end protected :set_registry def registry=(v) raise InvalidURIError, "can not set registry" end # # Checks the path +v+ component for RFC2396 compliance # and against the Bundler::URI::Parser Regexp # for :ABS_PATH and :REL_PATH. # # Can not have a opaque component defined, # with a path component defined. # def check_path(v) # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if v && @opaque raise InvalidURIError, "path conflicts with opaque" end # If scheme is ftp, path may be relative. # See RFC 1738 section 3.2.2, and RFC 2396. if @scheme && @scheme != "ftp" if v && v != '' && parser.regexp[:ABS_PATH] !~ v raise InvalidComponentError, "bad component(expected absolute path component): #{v}" end else if v && v != '' && parser.regexp[:ABS_PATH] !~ v && parser.regexp[:REL_PATH] !~ v raise InvalidComponentError, "bad component(expected relative path component): #{v}" end end return true end private :check_path # Protected setter for the path component +v+. # # See also Bundler::URI::Generic.path=. # def set_path(v) @path = v end protected :set_path # # == Args # # +v+:: # String # # == Description # # Public setter for the path component +v+ # (with validation). # # See also Bundler::URI::Generic.check_path. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com/pub/files") # uri.path = "/faq/" # uri.to_s #=> "http://my.example.com/faq/" # def path=(v) check_path(v) set_path(v) v end # # == Args # # +v+:: # String # # == Description # # Public setter for the query component +v+. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com/?id=25") # uri.query = "id=1" # uri.to_s #=> "http://my.example.com/?id=1" # def query=(v) return @query = nil unless v raise InvalidURIError, "query conflicts with opaque" if @opaque x = v.to_str v = x.dup if x.equal? v v.encode!(Encoding::UTF_8) rescue nil v.delete!("\t\r\n") v.force_encoding(Encoding::ASCII_8BIT) raise InvalidURIError, "invalid percent escape: #{$1}" if /(%\H\H)/n.match(v) v.gsub!(/(?!%\h\h|[!$-&(-;=?-_a-~])./n.freeze){'%%%02X' % $&.ord} v.force_encoding(Encoding::US_ASCII) @query = v end # # Checks the opaque +v+ component for RFC2396 compliance and # against the Bundler::URI::Parser Regexp for :OPAQUE. # # Can not have a host, port, user, or path component defined, # with an opaque component defined. # def check_opaque(v) return v unless v # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if @host || @port || @user || @path # userinfo = @user + ':' + @password raise InvalidURIError, "can not set opaque with host, port, userinfo or path" elsif v && parser.regexp[:OPAQUE] !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end return true end private :check_opaque # Protected setter for the opaque component +v+. # # See also Bundler::URI::Generic.opaque=. # def set_opaque(v) @opaque = v end protected :set_opaque # # == Args # # +v+:: # String # # == Description # # Public setter for the opaque component +v+ # (with validation). # # See also Bundler::URI::Generic.check_opaque. # def opaque=(v) check_opaque(v) set_opaque(v) v end # # Checks the fragment +v+ component against the Bundler::URI::Parser Regexp for :FRAGMENT. # # # == Args # # +v+:: # String # # == Description # # Public setter for the fragment component +v+ # (with validation). # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com/?id=25#time=1305212049") # uri.fragment = "time=1305212086" # uri.to_s #=> "http://my.example.com/?id=25#time=1305212086" # def fragment=(v) return @fragment = nil unless v x = v.to_str v = x.dup if x.equal? v v.encode!(Encoding::UTF_8) rescue nil v.delete!("\t\r\n") v.force_encoding(Encoding::ASCII_8BIT) v.gsub!(/(?!%\h\h|[!-~])./n){'%%%02X' % $&.ord} v.force_encoding(Encoding::US_ASCII) @fragment = v end # # Returns true if Bundler::URI is hierarchical. # # == Description # # Bundler::URI has components listed in order of decreasing significance from left to right, # see RFC3986 https://tools.ietf.org/html/rfc3986 1.2.3. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com/") # uri.hierarchical? # #=> true # uri = Bundler::URI.parse("mailto:joe@example.com") # uri.hierarchical? # #=> false # def hierarchical? if @path true else false end end # # Returns true if Bundler::URI has a scheme (e.g. http:// or https://) specified. # def absolute? if @scheme true else false end end alias absolute absolute? # # Returns true if Bundler::URI does not have a scheme (e.g. http:// or https://) specified. # def relative? !absolute? end # # Returns an Array of the path split on '/'. # def split_path(path) path.split("/", -1) end private :split_path # # Merges a base path +base+, with relative path +rel+, # returns a modified base path. # def merge_path(base, rel) # RFC2396, Section 5.2, 5) # RFC2396, Section 5.2, 6) base_path = split_path(base) rel_path = split_path(rel) # RFC2396, Section 5.2, 6), a) base_path << '' if base_path.last == '..' while i = base_path.index('..') base_path.slice!(i - 1, 2) end if (first = rel_path.first) and first.empty? base_path.clear rel_path.shift end # RFC2396, Section 5.2, 6), c) # RFC2396, Section 5.2, 6), d) rel_path.push('') if rel_path.last == '.' || rel_path.last == '..' rel_path.delete('.') # RFC2396, Section 5.2, 6), e) tmp = [] rel_path.each do |x| if x == '..' && !(tmp.empty? || tmp.last == '..') tmp.pop else tmp << x end end add_trailer_slash = !tmp.empty? if base_path.empty? base_path = [''] # keep '/' for root directory elsif add_trailer_slash base_path.pop end while x = tmp.shift if x == '..' # RFC2396, Section 4 # a .. or . in an absolute path has no special meaning base_path.pop if base_path.size > 1 else # if x == '..' # valid absolute (but abnormal) path "/../..." # else # valid absolute path # end base_path << x tmp.each {|t| base_path << t} add_trailer_slash = false break end end base_path.push('') if add_trailer_slash return base_path.join('/') end private :merge_path # # == Args # # +oth+:: # Bundler::URI or String # # == Description # # Destructive form of #merge. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.merge!("/main.rbx?page=1") # uri.to_s # => "http://my.example.com/main.rbx?page=1" # def merge!(oth) t = merge(oth) if self == t nil else replace!(t) self end end # # == Args # # +oth+:: # Bundler::URI or String # # == Description # # Merges two URIs. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.merge("/main.rbx?page=1") # # => "http://my.example.com/main.rbx?page=1" # def merge(oth) rel = parser.send(:convert_to_uri, oth) if rel.absolute? #raise BadURIError, "both Bundler::URI are absolute" if absolute? # hmm... should return oth for usability? return rel end unless self.absolute? raise BadURIError, "both Bundler::URI are relative" end base = self.dup authority = rel.userinfo || rel.host || rel.port # RFC2396, Section 5.2, 2) if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query base.fragment=(rel.fragment) if rel.fragment return base end base.query = nil base.fragment=(nil) # RFC2396, Section 5.2, 4) if !authority base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path else # RFC2396, Section 5.2, 4) base.set_path(rel.path) if rel.path end # RFC2396, Section 5.2, 7) base.set_userinfo(rel.userinfo) if rel.userinfo base.set_host(rel.host) if rel.host base.set_port(rel.port) if rel.port base.query = rel.query if rel.query base.fragment=(rel.fragment) if rel.fragment return base end # merge alias + merge # :stopdoc: def route_from_path(src, dst) case dst when src # RFC2396, Section 4.2 return '' when %r{(?:\A|/)\.\.?(?:/|\z)} # dst has abnormal absolute path, # like "/./", "/../", "/x/../", ... return dst.dup end src_path = src.scan(%r{[^/]*/}) dst_path = dst.scan(%r{[^/]*/?}) # discard same parts while !dst_path.empty? && dst_path.first == src_path.first src_path.shift dst_path.shift end tmp = dst_path.join # calculate if src_path.empty? if tmp.empty? return './' elsif dst_path.first.include?(':') # (see RFC2396 Section 5) return './' + tmp else return tmp end end return '../' * src_path.size + tmp end private :route_from_path # :startdoc: # :stopdoc: def route_from0(oth) oth = parser.send(:convert_to_uri, oth) if self.relative? raise BadURIError, "relative Bundler::URI: #{self}" end if oth.relative? raise BadURIError, "relative Bundler::URI: #{oth}" end if self.scheme != oth.scheme return self, self.dup end rel = Bundler::URI::Generic.new(nil, # it is relative Bundler::URI self.userinfo, self.host, self.port, nil, self.path, self.opaque, self.query, self.fragment, parser) if rel.userinfo != oth.userinfo || rel.host.to_s.downcase != oth.host.to_s.downcase || rel.port != oth.port if self.userinfo.nil? && self.host.nil? return self, self.dup end rel.set_port(nil) if rel.port == oth.default_port return rel, rel end rel.set_userinfo(nil) rel.set_host(nil) rel.set_port(nil) if rel.path && rel.path == oth.path rel.set_path('') rel.query = nil if rel.query == oth.query return rel, rel elsif rel.opaque && rel.opaque == oth.opaque rel.set_opaque('') rel.query = nil if rel.query == oth.query return rel, rel end # you can modify `rel', but can not `oth'. return oth, rel end private :route_from0 # :startdoc: # # == Args # # +oth+:: # Bundler::URI or String # # == Description # # Calculates relative path from oth to self. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse('http://my.example.com/main.rbx?page=1') # uri.route_from('http://my.example.com') # #=> # # def route_from(oth) # you can modify `rel', but can not `oth'. begin oth, rel = route_from0(oth) rescue raise $!.class, $!.message end if oth == rel return rel end rel.set_path(route_from_path(oth.path, self.path)) if rel.path == './' && self.query # "./?foo" -> "?foo" rel.set_path('') end return rel end alias - route_from # # == Args # # +oth+:: # Bundler::URI or String # # == Description # # Calculates relative path to oth from self. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse('http://my.example.com') # uri.route_to('http://my.example.com/main.rbx?page=1') # #=> # # def route_to(oth) parser.send(:convert_to_uri, oth).route_from(self) end # # Returns normalized Bundler::URI. # # require 'bundler/vendor/uri/lib/uri' # # Bundler::URI("HTTP://my.EXAMPLE.com").normalize # #=> # # # Normalization here means: # # * scheme and host are converted to lowercase, # * an empty path component is set to "/". # def normalize uri = dup uri.normalize! uri end # # Destructive version of #normalize. # def normalize! if path&.empty? set_path('/') end if scheme && scheme != scheme.downcase set_scheme(self.scheme.downcase) end if host && host != host.downcase set_host(self.host.downcase) end end # # Constructs String from Bundler::URI. # def to_s str = ''.dup if @scheme str << @scheme str << ':' end if @opaque str << @opaque else if @host || %w[file postgres].include?(@scheme) str << '//' end if self.userinfo str << self.userinfo str << '@' end if @host str << @host end if @port && @port != self.default_port str << ':' str << @port.to_s end str << @path if @query str << '?' str << @query end end if @fragment str << '#' str << @fragment end str end # # Compares two URIs. # def ==(oth) if self.class == oth.class self.normalize.component_ary == oth.normalize.component_ary else false end end def hash self.component_ary.hash end def eql?(oth) self.class == oth.class && parser == oth.parser && self.component_ary.eql?(oth.component_ary) end =begin --- Bundler::URI::Generic#===(oth) =end # def ===(oth) # raise NotImplementedError # end =begin =end # Returns an Array of the components defined from the COMPONENT Array. def component_ary component.collect do |x| self.send(x) end end protected :component_ary # == Args # # +components+:: # Multiple Symbol arguments defined in Bundler::URI::HTTP. # # == Description # # Selects specified components from Bundler::URI. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse('http://myuser:mypass@my.example.com/test.rbx') # uri.select(:userinfo, :host, :path) # # => ["myuser:mypass", "my.example.com", "/test.rbx"] # def select(*components) components.collect do |c| if component.include?(c) self.send(c) else raise ArgumentError, "expected of components of #{self.class} (#{self.class.component.join(', ')})" end end end def inspect "#<#{self.class} #{self}>" end # # == Args # # +v+:: # Bundler::URI or String # # == Description # # Attempts to parse other Bundler::URI +oth+, # returns [parsed_oth, self]. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://my.example.com") # uri.coerce("http://foo.com") # #=> [#, #] # def coerce(oth) case oth when String oth = parser.parse(oth) else super end return oth, self end # Returns a proxy Bundler::URI. # The proxy Bundler::URI is obtained from environment variables such as http_proxy, # ftp_proxy, no_proxy, etc. # If there is no proper proxy, nil is returned. # # If the optional parameter +env+ is specified, it is used instead of ENV. # # Note that capitalized variables (HTTP_PROXY, FTP_PROXY, NO_PROXY, etc.) # are examined, too. # # But http_proxy and HTTP_PROXY is treated specially under CGI environment. # It's because HTTP_PROXY may be set by Proxy: header. # So HTTP_PROXY is not used. # http_proxy is not used too if the variable is case insensitive. # CGI_HTTP_PROXY can be used instead. def find_proxy(env=ENV) raise BadURIError, "relative Bundler::URI: #{self}" if self.relative? name = self.scheme.downcase + '_proxy' proxy_uri = nil if name == 'http_proxy' && env.include?('REQUEST_METHOD') # CGI? # HTTP_PROXY conflicts with *_proxy for proxy settings and # HTTP_* for header information in CGI. # So it should be careful to use it. pairs = env.reject {|k, v| /\Ahttp_proxy\z/i !~ k } case pairs.length when 0 # no proxy setting anyway. proxy_uri = nil when 1 k, _ = pairs.shift if k == 'http_proxy' && env[k.upcase] == nil # http_proxy is safe to use because ENV is case sensitive. proxy_uri = env[name] else proxy_uri = nil end else # http_proxy is safe to use because ENV is case sensitive. proxy_uri = env.to_hash[name] end if !proxy_uri # Use CGI_HTTP_PROXY. cf. libwww-perl. proxy_uri = env["CGI_#{name.upcase}"] end elsif name == 'http_proxy' unless proxy_uri = env[name] if proxy_uri = env[name.upcase] warn 'The environment variable HTTP_PROXY is discouraged. Use http_proxy.', uplevel: 1 end end else proxy_uri = env[name] || env[name.upcase] end if proxy_uri.nil? || proxy_uri.empty? return nil end if self.hostname begin addr = IPSocket.getaddress(self.hostname) return nil if /\A127\.|\A::1\z/ =~ addr rescue SocketError end end name = 'no_proxy' if no_proxy = env[name] || env[name.upcase] return nil unless Bundler::URI::Generic.use_proxy?(self.hostname, addr, self.port, no_proxy) end Bundler::URI.parse(proxy_uri) end def self.use_proxy?(hostname, addr, port, no_proxy) # :nodoc: hostname = hostname.downcase dothostname = ".#{hostname}" no_proxy.scan(/([^:,\s]+)(?::(\d+))?/) {|p_host, p_port| if !p_port || port == p_port.to_i if p_host.start_with?('.') return false if hostname.end_with?(p_host.downcase) else return false if dothostname.end_with?(".#{p_host.downcase}") end if addr begin return false if IPAddr.new(p_host).include?(addr) rescue IPAddr::InvalidAddressError next end end end } true end end end PKu]wL{{5bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ldap.rbnu[# frozen_string_literal: false # = uri/ldap.rb # # Author:: # Takaaki Tateishi # Akira Yamada # License:: # Bundler::URI::LDAP is copyrighted free software by Takaaki Tateishi and Akira Yamada. # You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'generic' module Bundler::URI # # LDAP Bundler::URI SCHEMA (described in RFC2255). #-- # ldap:///[?[?[?[?]]]] #++ class LDAP < Generic # A Default port of 389 for Bundler::URI::LDAP. DEFAULT_PORT = 389 # An Array of the available components for Bundler::URI::LDAP. COMPONENT = [ :scheme, :host, :port, :dn, :attributes, :scope, :filter, :extensions, ].freeze # Scopes available for the starting point. # # * SCOPE_BASE - the Base DN # * SCOPE_ONE - one level under the Base DN, not including the base DN and # not including any entries under this # * SCOPE_SUB - subtrees, all entries at all levels # SCOPE = [ SCOPE_ONE = 'one', SCOPE_SUB = 'sub', SCOPE_BASE = 'base', ].freeze # # == Description # # Creates a new Bundler::URI::LDAP object from components, with syntax checking. # # The components accepted are host, port, dn, attributes, # scope, filter, and extensions. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the # order [host, port, dn, attributes, scope, filter, extensions]. # # Example: # # uri = Bundler::URI::LDAP.build({:host => 'ldap.example.com', # :dn => '/dc=example'}) # # uri = Bundler::URI::LDAP.build(["ldap.example.com", nil, # "/dc=example;dc=com", "query", nil, nil, nil]) # def self.build(args) tmp = Util::make_components_hash(self, args) if tmp[:dn] tmp[:path] = tmp[:dn] end query = [] [:extensions, :filter, :scope, :attributes].collect do |x| next if !tmp[x] && query.size == 0 query.unshift(tmp[x]) end tmp[:query] = query.join('?') return super(tmp) end # # == Description # # Creates a new Bundler::URI::LDAP object from generic Bundler::URI components as per # RFC 2396. No LDAP-specific syntax checking is performed. # # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+, # +opaque+, +query+, and +fragment+, in that order. # # Example: # # uri = Bundler::URI::LDAP.new("ldap", nil, "ldap.example.com", nil, nil, # "/dc=example;dc=com", nil, "query", nil) # # See also Bundler::URI::Generic.new. # def initialize(*arg) super(*arg) if @fragment raise InvalidURIError, 'bad LDAP URL' end parse_dn parse_query end # Private method to cleanup +dn+ from using the +path+ component attribute. def parse_dn @dn = @path[1..-1] end private :parse_dn # Private method to cleanup +attributes+, +scope+, +filter+, and +extensions+ # from using the +query+ component attribute. def parse_query @attributes = nil @scope = nil @filter = nil @extensions = nil if @query attrs, scope, filter, extensions = @query.split('?') @attributes = attrs if attrs && attrs.size > 0 @scope = scope if scope && scope.size > 0 @filter = filter if filter && filter.size > 0 @extensions = extensions if extensions && extensions.size > 0 end end private :parse_query # Private method to assemble +query+ from +attributes+, +scope+, +filter+, and +extensions+. def build_path_query @path = '/' + @dn query = [] [@extensions, @filter, @scope, @attributes].each do |x| next if !x && query.size == 0 query.unshift(x) end @query = query.join('?') end private :build_path_query # Returns dn. def dn @dn end # Private setter for dn +val+. def set_dn(val) @dn = val build_path_query @dn end protected :set_dn # Setter for dn +val+. def dn=(val) set_dn(val) val end # Returns attributes. def attributes @attributes end # Private setter for attributes +val+. def set_attributes(val) @attributes = val build_path_query @attributes end protected :set_attributes # Setter for attributes +val+. def attributes=(val) set_attributes(val) val end # Returns scope. def scope @scope end # Private setter for scope +val+. def set_scope(val) @scope = val build_path_query @scope end protected :set_scope # Setter for scope +val+. def scope=(val) set_scope(val) val end # Returns filter. def filter @filter end # Private setter for filter +val+. def set_filter(val) @filter = val build_path_query @filter end protected :set_filter # Setter for filter +val+. def filter=(val) set_filter(val) val end # Returns extensions. def extensions @extensions end # Private setter for extensions +val+. def set_extensions(val) @extensions = val build_path_query @extensions end protected :set_extensions # Setter for extensions +val+. def extensions=(val) set_extensions(val) val end # Checks if Bundler::URI has a path. # For Bundler::URI::LDAP this will return +false+. def hierarchical? false end end @@schemes['LDAP'] = LDAP end PKu]I6bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ldaps.rbnu[# frozen_string_literal: false # = uri/ldap.rb # # License:: You can redistribute it and/or modify it under the same term as Ruby. # # See Bundler::URI for general documentation # require_relative 'ldap' module Bundler::URI # The default port for LDAPS URIs is 636, and the scheme is 'ldaps:' rather # than 'ldap:'. Other than that, LDAPS URIs are identical to LDAP URIs; # see Bundler::URI::LDAP. class LDAPS < LDAP # A Default port of 636 for Bundler::URI::LDAPS DEFAULT_PORT = 636 end @@schemes['LDAPS'] = LDAPS end PKu] %%4bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ftp.rbnu[# frozen_string_literal: false # = uri/ftp.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'generic' module Bundler::URI # # FTP Bundler::URI syntax is defined by RFC1738 section 3.2. # # This class will be redesigned because of difference of implementations; # the structure of its path. draft-hoffman-ftp-uri-04 is a draft but it # is a good summary about the de facto spec. # http://tools.ietf.org/html/draft-hoffman-ftp-uri-04 # class FTP < Generic # A Default port of 21 for Bundler::URI::FTP. DEFAULT_PORT = 21 # # An Array of the available components for Bundler::URI::FTP. # COMPONENT = [ :scheme, :userinfo, :host, :port, :path, :typecode ].freeze # # Typecode is "a", "i", or "d". # # * "a" indicates a text file (the FTP command was ASCII) # * "i" indicates a binary file (FTP command IMAGE) # * "d" indicates the contents of a directory should be displayed # TYPECODE = ['a', 'i', 'd'].freeze # Typecode prefix ";type=". TYPECODE_PREFIX = ';type='.freeze def self.new2(user, password, host, port, path, typecode = nil, arg_check = true) # :nodoc: # Do not use this method! Not tested. [Bug #7301] # This methods remains just for compatibility, # Keep it undocumented until the active maintainer is assigned. typecode = nil if typecode.size == 0 if typecode && !TYPECODE.include?(typecode) raise ArgumentError, "bad typecode is specified: #{typecode}" end # do escape self.new('ftp', [user, password], host, port, nil, typecode ? path + TYPECODE_PREFIX + typecode : path, nil, nil, nil, arg_check) end # # == Description # # Creates a new Bundler::URI::FTP object from components, with syntax checking. # # The components accepted are +userinfo+, +host+, +port+, +path+, and # +typecode+. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the # order [userinfo, host, port, path, typecode]. # # If the path supplied is absolute, it will be escaped in order to # make it absolute in the Bundler::URI. # # Examples: # # require 'bundler/vendor/uri/lib/uri' # # uri1 = Bundler::URI::FTP.build(['user:password', 'ftp.example.com', nil, # '/path/file.zip', 'i']) # uri1.to_s # => "ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=i" # # uri2 = Bundler::URI::FTP.build({:host => 'ftp.example.com', # :path => 'ruby/src'}) # uri2.to_s # => "ftp://ftp.example.com/ruby/src" # def self.build(args) # Fix the incoming path to be generic URL syntax # FTP path -> URL path # foo/bar /foo/bar # /foo/bar /%2Ffoo/bar # if args.kind_of?(Array) args[3] = '/' + args[3].sub(/^\//, '%2F') else args[:path] = '/' + args[:path].sub(/^\//, '%2F') end tmp = Util::make_components_hash(self, args) if tmp[:typecode] if tmp[:typecode].size == 1 tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode] end tmp[:path] << tmp[:typecode] end return super(tmp) end # # == Description # # Creates a new Bundler::URI::FTP object from generic URL components with no # syntax checking. # # Unlike build(), this method does not escape the path component as # required by RFC1738; instead it is treated as per RFC2396. # # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+, # +opaque+, +query+, and +fragment+, in that order. # def initialize(scheme, userinfo, host, port, registry, path, opaque, query, fragment, parser = nil, arg_check = false) raise InvalidURIError unless path path = path.sub(/^\//,'') path.sub!(/^%2F/,'/') super(scheme, userinfo, host, port, registry, path, opaque, query, fragment, parser, arg_check) @typecode = nil if tmp = @path.index(TYPECODE_PREFIX) typecode = @path[tmp + TYPECODE_PREFIX.size..-1] @path = @path[0..tmp - 1] if arg_check self.typecode = typecode else self.set_typecode(typecode) end end end # typecode accessor. # # See Bundler::URI::FTP::COMPONENT. attr_reader :typecode # Validates typecode +v+, # returns +true+ or +false+. # def check_typecode(v) if TYPECODE.include?(v) return true else raise InvalidComponentError, "bad typecode(expected #{TYPECODE.join(', ')}): #{v}" end end private :check_typecode # Private setter for the typecode +v+. # # See also Bundler::URI::FTP.typecode=. # def set_typecode(v) @typecode = v end protected :set_typecode # # == Args # # +v+:: # String # # == Description # # Public setter for the typecode +v+ # (with validation). # # See also Bundler::URI::FTP.check_typecode. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("ftp://john@ftp.example.com/my_file.img") # #=> # # uri.typecode = "i" # uri # #=> # # def typecode=(typecode) check_typecode(typecode) set_typecode(typecode) typecode end def merge(oth) # :nodoc: tmp = super(oth) if self != tmp tmp.set_typecode(oth.typecode) end return tmp end # Returns the path from an FTP Bundler::URI. # # RFC 1738 specifically states that the path for an FTP Bundler::URI does not # include the / which separates the Bundler::URI path from the Bundler::URI host. Example: # # ftp://ftp.example.com/pub/ruby # # The above Bundler::URI indicates that the client should connect to # ftp.example.com then cd to pub/ruby from the initial login directory. # # If you want to cd to an absolute directory, you must include an # escaped / (%2F) in the path. Example: # # ftp://ftp.example.com/%2Fpub/ruby # # This method will then return "/pub/ruby". # def path return @path.sub(/^\//,'').sub(/^%2F/,'/') end # Private setter for the path of the Bundler::URI::FTP. def set_path(v) super("/" + v.sub(/^\//, "%2F")) end protected :set_path # Returns a String representation of the Bundler::URI::FTP. def to_s save_path = nil if @typecode save_path = @path @path = @path + TYPECODE_PREFIX + @typecode end str = super if @typecode @path = save_path end return str end end @@schemes['FTP'] = FTP end PKu]38bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/version.rbnu[module Bundler::URI # :stopdoc: VERSION_CODE = '001000'.freeze VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze # :startdoc: end PKu]*@QQ7bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/common.rbnu[# frozen_string_literal: true #-- # = uri/common.rb # # Author:: Akira Yamada # Revision:: $Id$ # License:: # You can redistribute it and/or modify it under the same term as Ruby. # # See Bundler::URI for general documentation # require_relative "rfc2396_parser" require_relative "rfc3986_parser" module Bundler::URI REGEXP = RFC2396_REGEXP Parser = RFC2396_Parser RFC3986_PARSER = RFC3986_Parser.new # Bundler::URI::Parser.new DEFAULT_PARSER = Parser.new DEFAULT_PARSER.pattern.each_pair do |sym, str| unless REGEXP::PATTERN.const_defined?(sym) REGEXP::PATTERN.const_set(sym, str) end end DEFAULT_PARSER.regexp.each_pair do |sym, str| const_set(sym, str) end module Util # :nodoc: def make_components_hash(klass, array_hash) tmp = {} if array_hash.kind_of?(Array) && array_hash.size == klass.component.size - 1 klass.component[1..-1].each_index do |i| begin tmp[klass.component[i + 1]] = array_hash[i].clone rescue TypeError tmp[klass.component[i + 1]] = array_hash[i] end end elsif array_hash.kind_of?(Hash) array_hash.each do |key, value| begin tmp[key] = value.clone rescue TypeError tmp[key] = value end end else raise ArgumentError, "expected Array of or Hash of components of #{klass} (#{klass.component[1..-1].join(', ')})" end tmp[:scheme] = klass.to_s.sub(/\A.*::/, '').downcase return tmp end module_function :make_components_hash end # Module for escaping unsafe characters with codes. module Escape # # == Synopsis # # Bundler::URI.escape(str [, unsafe]) # # == Args # # +str+:: # String to replaces in. # +unsafe+:: # Regexp that matches all symbols that must be replaced with codes. # By default uses UNSAFE. # When this argument is a String, it represents a character set. # # == Description # # Escapes the string, replacing all unsafe characters with codes. # # This method is obsolete and should not be used. Instead, use # CGI.escape, Bundler::URI.encode_www_form or Bundler::URI.encode_www_form_component # depending on your specific use case. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # enc_uri = Bundler::URI.escape("http://example.com/?a=\11\15") # # => "http://example.com/?a=%09%0D" # # Bundler::URI.unescape(enc_uri) # # => "http://example.com/?a=\t\r" # # Bundler::URI.escape("@?@!", "!?") # # => "@%3F@%21" # def escape(*arg) warn "Bundler::URI.escape is obsolete", uplevel: 1 DEFAULT_PARSER.escape(*arg) end alias encode escape # # == Synopsis # # Bundler::URI.unescape(str) # # == Args # # +str+:: # String to unescape. # # == Description # # This method is obsolete and should not be used. Instead, use # CGI.unescape, Bundler::URI.decode_www_form or Bundler::URI.decode_www_form_component # depending on your specific use case. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # enc_uri = Bundler::URI.escape("http://example.com/?a=\11\15") # # => "http://example.com/?a=%09%0D" # # Bundler::URI.unescape(enc_uri) # # => "http://example.com/?a=\t\r" # def unescape(*arg) warn "Bundler::URI.unescape is obsolete", uplevel: 1 DEFAULT_PARSER.unescape(*arg) end alias decode unescape end # module Escape extend Escape include REGEXP @@schemes = {} # Returns a Hash of the defined schemes. def self.scheme_list @@schemes end # # Base class for all Bundler::URI exceptions. # class Error < StandardError; end # # Not a Bundler::URI. # class InvalidURIError < Error; end # # Not a Bundler::URI component. # class InvalidComponentError < Error; end # # Bundler::URI is valid, bad usage is not. # class BadURIError < Error; end # # == Synopsis # # Bundler::URI::split(uri) # # == Args # # +uri+:: # String with Bundler::URI. # # == Description # # Splits the string on following parts and returns array with result: # # * Scheme # * Userinfo # * Host # * Port # * Registry # * Path # * Opaque # * Query # * Fragment # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # Bundler::URI.split("http://www.ruby-lang.org/") # # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil] # def self.split(uri) RFC3986_PARSER.split(uri) end # # == Synopsis # # Bundler::URI::parse(uri_str) # # == Args # # +uri_str+:: # String with Bundler::URI. # # == Description # # Creates one of the Bundler::URI's subclasses instance from the string. # # == Raises # # Bundler::URI::InvalidURIError:: # Raised if Bundler::URI given is not a correct one. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # uri = Bundler::URI.parse("http://www.ruby-lang.org/") # # => # # uri.scheme # # => "http" # uri.host # # => "www.ruby-lang.org" # # It's recommended to first ::escape the provided +uri_str+ if there are any # invalid Bundler::URI characters. # def self.parse(uri) RFC3986_PARSER.parse(uri) end # # == Synopsis # # Bundler::URI::join(str[, str, ...]) # # == Args # # +str+:: # String(s) to work with, will be converted to RFC3986 URIs before merging. # # == Description # # Joins URIs. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # Bundler::URI.join("http://example.com/","main.rbx") # # => # # # Bundler::URI.join('http://example.com', 'foo') # # => # # # Bundler::URI.join('http://example.com', '/foo', '/bar') # # => # # # Bundler::URI.join('http://example.com', '/foo', 'bar') # # => # # # Bundler::URI.join('http://example.com', '/foo/', 'bar') # # => # # def self.join(*str) RFC3986_PARSER.join(*str) end # # == Synopsis # # Bundler::URI::extract(str[, schemes][,&blk]) # # == Args # # +str+:: # String to extract URIs from. # +schemes+:: # Limit Bundler::URI matching to specific schemes. # # == Description # # Extracts URIs from a string. If block given, iterates through all matched URIs. # Returns nil if block given or array with matches. # # == Usage # # require "bundler/vendor/uri/lib/uri" # # Bundler::URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.") # # => ["http://foo.example.com/bla", "mailto:test@example.com"] # def self.extract(str, schemes = nil, &block) warn "Bundler::URI.extract is obsolete", uplevel: 1 if $VERBOSE DEFAULT_PARSER.extract(str, schemes, &block) end # # == Synopsis # # Bundler::URI::regexp([match_schemes]) # # == Args # # +match_schemes+:: # Array of schemes. If given, resulting regexp matches to URIs # whose scheme is one of the match_schemes. # # == Description # # Returns a Regexp object which matches to Bundler::URI-like strings. # The Regexp object returned by this method includes arbitrary # number of capture group (parentheses). Never rely on it's number. # # == Usage # # require 'bundler/vendor/uri/lib/uri' # # # extract first Bundler::URI from html_string # html_string.slice(Bundler::URI.regexp) # # # remove ftp URIs # html_string.sub(Bundler::URI.regexp(['ftp']), '') # # # You should not rely on the number of parentheses # html_string.scan(Bundler::URI.regexp) do |*matches| # p $& # end # def self.regexp(schemes = nil) warn "Bundler::URI.regexp is obsolete", uplevel: 1 if $VERBOSE DEFAULT_PARSER.make_regexp(schemes) end TBLENCWWWCOMP_ = {} # :nodoc: 256.times do |i| TBLENCWWWCOMP_[-i.chr] = -('%%%02X' % i) end TBLENCWWWCOMP_[' '] = '+' TBLENCWWWCOMP_.freeze TBLDECWWWCOMP_ = {} # :nodoc: 256.times do |i| h, l = i>>4, i&15 TBLDECWWWCOMP_[-('%%%X%X' % [h, l])] = -i.chr TBLDECWWWCOMP_[-('%%%x%X' % [h, l])] = -i.chr TBLDECWWWCOMP_[-('%%%X%x' % [h, l])] = -i.chr TBLDECWWWCOMP_[-('%%%x%x' % [h, l])] = -i.chr end TBLDECWWWCOMP_['+'] = ' ' TBLDECWWWCOMP_.freeze # Encodes given +str+ to URL-encoded form data. # # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP # (ASCII space) to + and converts others to %XX. # # If +enc+ is given, convert +str+ to the encoding before percent encoding. # # This is an implementation of # http://www.w3.org/TR/2013/CR-html5-20130806/forms.html#url-encoded-form-data. # # See Bundler::URI.decode_www_form_component, Bundler::URI.encode_www_form. def self.encode_www_form_component(str, enc=nil) str = str.to_s.dup if str.encoding != Encoding::ASCII_8BIT if enc && enc != Encoding::ASCII_8BIT str.encode!(Encoding::UTF_8, invalid: :replace, undef: :replace) str.encode!(enc, fallback: ->(x){"&##{x.ord};"}) end str.force_encoding(Encoding::ASCII_8BIT) end str.gsub!(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_) str.force_encoding(Encoding::US_ASCII) end # Decodes given +str+ of URL-encoded form data. # # This decodes + to SP. # # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form. def self.decode_www_form_component(str, enc=Encoding::UTF_8) raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/ =~ str str.b.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc) end # Generates URL-encoded form data from given +enum+. # # This generates application/x-www-form-urlencoded data defined in HTML5 # from given an Enumerable object. # # This internally uses Bundler::URI.encode_www_form_component(str). # # This method doesn't convert the encoding of given items, so convert them # before calling this method if you want to send data as other than original # encoding or mixed encoding data. (Strings which are encoded in an HTML5 # ASCII incompatible encoding are converted to UTF-8.) # # This method doesn't handle files. When you send a file, use # multipart/form-data. # # This refers http://url.spec.whatwg.org/#concept-urlencoded-serializer # # Bundler::URI.encode_www_form([["q", "ruby"], ["lang", "en"]]) # #=> "q=ruby&lang=en" # Bundler::URI.encode_www_form("q" => "ruby", "lang" => "en") # #=> "q=ruby&lang=en" # Bundler::URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en") # #=> "q=ruby&q=perl&lang=en" # Bundler::URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]]) # #=> "q=ruby&q=perl&lang=en" # # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form. def self.encode_www_form(enum, enc=nil) enum.map do |k,v| if v.nil? encode_www_form_component(k, enc) elsif v.respond_to?(:to_ary) v.to_ary.map do |w| str = encode_www_form_component(k, enc) unless w.nil? str << '=' str << encode_www_form_component(w, enc) end end.join('&') else str = encode_www_form_component(k, enc) str << '=' str << encode_www_form_component(v, enc) end end.join('&') end # Decodes URL-encoded form data from given +str+. # # This decodes application/x-www-form-urlencoded data # and returns an array of key-value arrays. # # This refers http://url.spec.whatwg.org/#concept-urlencoded-parser, # so this supports only &-separator, and doesn't support ;-separator. # # ary = Bundler::URI.decode_www_form("a=1&a=2&b=3") # ary #=> [['a', '1'], ['a', '2'], ['b', '3']] # ary.assoc('a').last #=> '1' # ary.assoc('b').last #=> '3' # ary.rassoc('a').last #=> '2' # Hash[ary] #=> {"a"=>"2", "b"=>"3"} # # See Bundler::URI.decode_www_form_component, Bundler::URI.encode_www_form. def self.decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false) raise ArgumentError, "the input of #{self.name}.#{__method__} must be ASCII only string" unless str.ascii_only? ary = [] return ary if str.empty? enc = Encoding.find(enc) str.b.each_line(separator) do |string| string.chomp!(separator) key, sep, val = string.partition('=') if isindex if sep.empty? val = key key = +'' end isindex = false end if use__charset_ and key == '_charset_' and e = get_encoding(val) enc = e use__charset_ = false end key.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_) if val val.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_) else val = +'' end ary << [key, val] end ary.each do |k, v| k.force_encoding(enc) k.scrub! v.force_encoding(enc) v.scrub! end ary end private =begin command for WEB_ENCODINGS_ curl https://encoding.spec.whatwg.org/encodings.json| ruby -rjson -e 'H={} h={ "shift_jis"=>"Windows-31J", "euc-jp"=>"cp51932", "iso-2022-jp"=>"cp50221", "x-mac-cyrillic"=>"macCyrillic", } JSON($<.read).map{|x|x["encodings"]}.flatten.each{|x| Encoding.find(n=h.fetch(n=x["name"].downcase,n))rescue next x["labels"].each{|y|H[y]=n} } puts "{" H.each{|k,v|puts %[ #{k.dump}=>#{v.dump},]} puts "}" ' =end WEB_ENCODINGS_ = { "unicode-1-1-utf-8"=>"utf-8", "utf-8"=>"utf-8", "utf8"=>"utf-8", "866"=>"ibm866", "cp866"=>"ibm866", "csibm866"=>"ibm866", "ibm866"=>"ibm866", "csisolatin2"=>"iso-8859-2", "iso-8859-2"=>"iso-8859-2", "iso-ir-101"=>"iso-8859-2", "iso8859-2"=>"iso-8859-2", "iso88592"=>"iso-8859-2", "iso_8859-2"=>"iso-8859-2", "iso_8859-2:1987"=>"iso-8859-2", "l2"=>"iso-8859-2", "latin2"=>"iso-8859-2", "csisolatin3"=>"iso-8859-3", "iso-8859-3"=>"iso-8859-3", "iso-ir-109"=>"iso-8859-3", "iso8859-3"=>"iso-8859-3", "iso88593"=>"iso-8859-3", "iso_8859-3"=>"iso-8859-3", "iso_8859-3:1988"=>"iso-8859-3", "l3"=>"iso-8859-3", "latin3"=>"iso-8859-3", "csisolatin4"=>"iso-8859-4", "iso-8859-4"=>"iso-8859-4", "iso-ir-110"=>"iso-8859-4", "iso8859-4"=>"iso-8859-4", "iso88594"=>"iso-8859-4", "iso_8859-4"=>"iso-8859-4", "iso_8859-4:1988"=>"iso-8859-4", "l4"=>"iso-8859-4", "latin4"=>"iso-8859-4", "csisolatincyrillic"=>"iso-8859-5", "cyrillic"=>"iso-8859-5", "iso-8859-5"=>"iso-8859-5", "iso-ir-144"=>"iso-8859-5", "iso8859-5"=>"iso-8859-5", "iso88595"=>"iso-8859-5", "iso_8859-5"=>"iso-8859-5", "iso_8859-5:1988"=>"iso-8859-5", "arabic"=>"iso-8859-6", "asmo-708"=>"iso-8859-6", "csiso88596e"=>"iso-8859-6", "csiso88596i"=>"iso-8859-6", "csisolatinarabic"=>"iso-8859-6", "ecma-114"=>"iso-8859-6", "iso-8859-6"=>"iso-8859-6", "iso-8859-6-e"=>"iso-8859-6", "iso-8859-6-i"=>"iso-8859-6", "iso-ir-127"=>"iso-8859-6", "iso8859-6"=>"iso-8859-6", "iso88596"=>"iso-8859-6", "iso_8859-6"=>"iso-8859-6", "iso_8859-6:1987"=>"iso-8859-6", "csisolatingreek"=>"iso-8859-7", "ecma-118"=>"iso-8859-7", "elot_928"=>"iso-8859-7", "greek"=>"iso-8859-7", "greek8"=>"iso-8859-7", "iso-8859-7"=>"iso-8859-7", "iso-ir-126"=>"iso-8859-7", "iso8859-7"=>"iso-8859-7", "iso88597"=>"iso-8859-7", "iso_8859-7"=>"iso-8859-7", "iso_8859-7:1987"=>"iso-8859-7", "sun_eu_greek"=>"iso-8859-7", "csiso88598e"=>"iso-8859-8", "csisolatinhebrew"=>"iso-8859-8", "hebrew"=>"iso-8859-8", "iso-8859-8"=>"iso-8859-8", "iso-8859-8-e"=>"iso-8859-8", "iso-ir-138"=>"iso-8859-8", "iso8859-8"=>"iso-8859-8", "iso88598"=>"iso-8859-8", "iso_8859-8"=>"iso-8859-8", "iso_8859-8:1988"=>"iso-8859-8", "visual"=>"iso-8859-8", "csisolatin6"=>"iso-8859-10", "iso-8859-10"=>"iso-8859-10", "iso-ir-157"=>"iso-8859-10", "iso8859-10"=>"iso-8859-10", "iso885910"=>"iso-8859-10", "l6"=>"iso-8859-10", "latin6"=>"iso-8859-10", "iso-8859-13"=>"iso-8859-13", "iso8859-13"=>"iso-8859-13", "iso885913"=>"iso-8859-13", "iso-8859-14"=>"iso-8859-14", "iso8859-14"=>"iso-8859-14", "iso885914"=>"iso-8859-14", "csisolatin9"=>"iso-8859-15", "iso-8859-15"=>"iso-8859-15", "iso8859-15"=>"iso-8859-15", "iso885915"=>"iso-8859-15", "iso_8859-15"=>"iso-8859-15", "l9"=>"iso-8859-15", "iso-8859-16"=>"iso-8859-16", "cskoi8r"=>"koi8-r", "koi"=>"koi8-r", "koi8"=>"koi8-r", "koi8-r"=>"koi8-r", "koi8_r"=>"koi8-r", "koi8-ru"=>"koi8-u", "koi8-u"=>"koi8-u", "dos-874"=>"windows-874", "iso-8859-11"=>"windows-874", "iso8859-11"=>"windows-874", "iso885911"=>"windows-874", "tis-620"=>"windows-874", "windows-874"=>"windows-874", "cp1250"=>"windows-1250", "windows-1250"=>"windows-1250", "x-cp1250"=>"windows-1250", "cp1251"=>"windows-1251", "windows-1251"=>"windows-1251", "x-cp1251"=>"windows-1251", "ansi_x3.4-1968"=>"windows-1252", "ascii"=>"windows-1252", "cp1252"=>"windows-1252", "cp819"=>"windows-1252", "csisolatin1"=>"windows-1252", "ibm819"=>"windows-1252", "iso-8859-1"=>"windows-1252", "iso-ir-100"=>"windows-1252", "iso8859-1"=>"windows-1252", "iso88591"=>"windows-1252", "iso_8859-1"=>"windows-1252", "iso_8859-1:1987"=>"windows-1252", "l1"=>"windows-1252", "latin1"=>"windows-1252", "us-ascii"=>"windows-1252", "windows-1252"=>"windows-1252", "x-cp1252"=>"windows-1252", "cp1253"=>"windows-1253", "windows-1253"=>"windows-1253", "x-cp1253"=>"windows-1253", "cp1254"=>"windows-1254", "csisolatin5"=>"windows-1254", "iso-8859-9"=>"windows-1254", "iso-ir-148"=>"windows-1254", "iso8859-9"=>"windows-1254", "iso88599"=>"windows-1254", "iso_8859-9"=>"windows-1254", "iso_8859-9:1989"=>"windows-1254", "l5"=>"windows-1254", "latin5"=>"windows-1254", "windows-1254"=>"windows-1254", "x-cp1254"=>"windows-1254", "cp1255"=>"windows-1255", "windows-1255"=>"windows-1255", "x-cp1255"=>"windows-1255", "cp1256"=>"windows-1256", "windows-1256"=>"windows-1256", "x-cp1256"=>"windows-1256", "cp1257"=>"windows-1257", "windows-1257"=>"windows-1257", "x-cp1257"=>"windows-1257", "cp1258"=>"windows-1258", "windows-1258"=>"windows-1258", "x-cp1258"=>"windows-1258", "x-mac-cyrillic"=>"macCyrillic", "x-mac-ukrainian"=>"macCyrillic", "chinese"=>"gbk", "csgb2312"=>"gbk", "csiso58gb231280"=>"gbk", "gb2312"=>"gbk", "gb_2312"=>"gbk", "gb_2312-80"=>"gbk", "gbk"=>"gbk", "iso-ir-58"=>"gbk", "x-gbk"=>"gbk", "gb18030"=>"gb18030", "big5"=>"big5", "big5-hkscs"=>"big5", "cn-big5"=>"big5", "csbig5"=>"big5", "x-x-big5"=>"big5", "cseucpkdfmtjapanese"=>"cp51932", "euc-jp"=>"cp51932", "x-euc-jp"=>"cp51932", "csiso2022jp"=>"cp50221", "iso-2022-jp"=>"cp50221", "csshiftjis"=>"Windows-31J", "ms932"=>"Windows-31J", "ms_kanji"=>"Windows-31J", "shift-jis"=>"Windows-31J", "shift_jis"=>"Windows-31J", "sjis"=>"Windows-31J", "windows-31j"=>"Windows-31J", "x-sjis"=>"Windows-31J", "cseuckr"=>"euc-kr", "csksc56011987"=>"euc-kr", "euc-kr"=>"euc-kr", "iso-ir-149"=>"euc-kr", "korean"=>"euc-kr", "ks_c_5601-1987"=>"euc-kr", "ks_c_5601-1989"=>"euc-kr", "ksc5601"=>"euc-kr", "ksc_5601"=>"euc-kr", "windows-949"=>"euc-kr", "utf-16be"=>"utf-16be", "utf-16"=>"utf-16le", "utf-16le"=>"utf-16le", } # :nodoc: # :nodoc: # return encoding or nil # http://encoding.spec.whatwg.org/#concept-encoding-get def self.get_encoding(label) Encoding.find(WEB_ENCODINGS_[label.to_str.strip.downcase]) rescue nil end end # module Bundler::URI module Bundler # # Returns +uri+ converted to an Bundler::URI object. # def URI(uri) if uri.is_a?(Bundler::URI::Generic) uri elsif uri = String.try_convert(uri) Bundler::URI.parse(uri) else raise ArgumentError, "bad argument (expected Bundler::URI object or Bundler::URI string)" end end module_function :URI end PKu] 5bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/http.rbnu[# frozen_string_literal: false # = uri/http.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'generic' module Bundler::URI # # The syntax of HTTP URIs is defined in RFC1738 section 3.3. # # Note that the Ruby Bundler::URI library allows HTTP URLs containing usernames and # passwords. This is not legal as per the RFC, but used to be # supported in Internet Explorer 5 and 6, before the MS04-004 security # update. See . # class HTTP < Generic # A Default port of 80 for Bundler::URI::HTTP. DEFAULT_PORT = 80 # An Array of the available components for Bundler::URI::HTTP. COMPONENT = %i[ scheme userinfo host port path query fragment ].freeze # # == Description # # Creates a new Bundler::URI::HTTP object from components, with syntax checking. # # The components accepted are userinfo, host, port, path, query, and # fragment. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the # order [userinfo, host, port, path, query, fragment]. # # Example: # # uri = Bundler::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar') # # uri = Bundler::URI::HTTP.build([nil, "www.example.com", nil, "/path", # "query", 'fragment']) # # Currently, if passed userinfo components this method generates # invalid HTTP URIs as per RFC 1738. # def self.build(args) tmp = Util.make_components_hash(self, args) super(tmp) end # # == Description # # Returns the full path for an HTTP request, as required by Net::HTTP::Get. # # If the Bundler::URI contains a query, the full path is Bundler::URI#path + '?' + Bundler::URI#query. # Otherwise, the path is simply Bundler::URI#path. # # Example: # # uri = Bundler::URI::HTTP.build(path: '/foo/bar', query: 'test=true') # uri.request_uri # => "/foo/bar?test=true" # def request_uri return unless @path url = @query ? "#@path?#@query" : @path.dup url.start_with?(?/.freeze) ? url : ?/ + url end end @@schemes['HTTP'] = HTTP end PKu]="__6bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/https.rbnu[# frozen_string_literal: false # = uri/https.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See Bundler::URI for general documentation # require_relative 'http' module Bundler::URI # The default port for HTTPS URIs is 443, and the scheme is 'https:' rather # than 'http:'. Other than that, HTTPS URIs are identical to HTTP URIs; # see Bundler::URI::HTTP. class HTTPS < HTTP # A Default port of 443 for Bundler::URI::HTTPS DEFAULT_PORT = 443 end @@schemes['HTTPS'] = HTTPS end PKu]#TΉQQ?bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rbnu[# frozen_string_literal: false module Bundler::URI class RFC3986_Parser # :nodoc: # Bundler::URI defined in RFC3986 # this regexp is modified not to host is not empty string RFC3986_URI = /\A(?(?[A-Za-z][+\-.0-9A-Za-z]*):(?\/\/(?(?:(?(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?(?\[(?:(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{1,4}?::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?\d*))?)(?(?:\/(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?\/(?:(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g)*)?)|(?\g(?:\/\g)*)|(?))(?:\?(?[^#]*))?(?:\#(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/ RFC3986_relative_ref = /\A(?(?\/\/(?(?:(?(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?(?\[(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{1,4}?::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+)\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?\d*))?)(?(?:\/(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?\/(?:(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g)*)?)|(?(?(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g)*)|(?))(?:\?(?[^#]*))?(?:\#(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/ attr_reader :regexp def initialize @regexp = default_regexp.each_value(&:freeze).freeze end def split(uri) #:nodoc: begin uri = uri.to_str rescue NoMethodError raise InvalidURIError, "bad Bundler::URI(is not Bundler::URI?): #{uri.inspect}" end uri.ascii_only? or raise InvalidURIError, "Bundler::URI must be ascii only #{uri.dump}" if m = RFC3986_URI.match(uri) query = m["query".freeze] scheme = m["scheme".freeze] opaque = m["path-rootless".freeze] if opaque opaque << "?#{query}" if query [ scheme, nil, # userinfo nil, # host nil, # port nil, # registry nil, # path opaque, nil, # query m["fragment".freeze] ] else # normal [ scheme, m["userinfo".freeze], m["host".freeze], m["port".freeze], nil, # registry (m["path-abempty".freeze] || m["path-absolute".freeze] || m["path-empty".freeze]), nil, # opaque query, m["fragment".freeze] ] end elsif m = RFC3986_relative_ref.match(uri) [ nil, # scheme m["userinfo".freeze], m["host".freeze], m["port".freeze], nil, # registry, (m["path-abempty".freeze] || m["path-absolute".freeze] || m["path-noscheme".freeze] || m["path-empty".freeze]), nil, # opaque m["query".freeze], m["fragment".freeze] ] else raise InvalidURIError, "bad Bundler::URI(is not Bundler::URI?): #{uri.inspect}" end end def parse(uri) # :nodoc: scheme, userinfo, host, port, registry, path, opaque, query, fragment = self.split(uri) scheme_list = Bundler::URI.scheme_list if scheme && scheme_list.include?(uc = scheme.upcase) scheme_list[uc].new(scheme, userinfo, host, port, registry, path, opaque, query, fragment, self) else Generic.new(scheme, userinfo, host, port, registry, path, opaque, query, fragment, self) end end def join(*uris) # :nodoc: uris[0] = convert_to_uri(uris[0]) uris.inject :merge end @@to_s = Kernel.instance_method(:to_s) def inspect @@to_s.bind_call(self) end private def default_regexp # :nodoc: { SCHEME: /\A[A-Za-z][A-Za-z0-9+\-.]*\z/, USERINFO: /\A(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*\z/, HOST: /\A(?:(?\[(?:(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{,4}::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))\z/, ABS_PATH: /\A\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/, REL_PATH: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/, QUERY: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/, FRAGMENT: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/, OPAQUE: /\A(?:[^\/].*)?\z/, PORT: /\A[\x09\x0a\x0c\x0d ]*\d*[\x09\x0a\x0c\x0d ]*\z/, } end def convert_to_uri(uri) if uri.is_a?(Bundler::URI::Generic) uri elsif uri = String.try_convert(uri) parse(uri) else raise ArgumentError, "bad argument (expected Bundler::URI object or Bundler::URI string)" end end end # class Parser end # module Bundler::URI PKu]ٍ2G2G?bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rbnu[# frozen_string_literal: false #-- # = uri/common.rb # # Author:: Akira Yamada # Revision:: $Id$ # License:: # You can redistribute it and/or modify it under the same term as Ruby. # # See Bundler::URI for general documentation # module Bundler::URI # # Includes Bundler::URI::REGEXP::PATTERN # module RFC2396_REGEXP # # Patterns used to parse Bundler::URI's # module PATTERN # :stopdoc: # RFC 2396 (Bundler::URI Generic Syntax) # RFC 2732 (IPv6 Literal Addresses in URL's) # RFC 2373 (IPv6 Addressing Architecture) # alpha = lowalpha | upalpha ALPHA = "a-zA-Z" # alphanum = alpha | digit ALNUM = "#{ALPHA}\\d" # hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | # "a" | "b" | "c" | "d" | "e" | "f" HEX = "a-fA-F\\d" # escaped = "%" hex hex ESCAPED = "%[#{HEX}]{2}" # mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | # "(" | ")" # unreserved = alphanum | mark UNRESERVED = "\\-_.!~*'()#{ALNUM}" # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | # "$" | "," # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | # "$" | "," | "[" | "]" (RFC 2732) RESERVED = ";/?:@&=+$,\\[\\]" # domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)" # toplabel = alpha | alpha *( alphanum | "-" ) alphanum TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)" # hostname = *( domainlabel "." ) toplabel [ "." ] HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?" # :startdoc: end # PATTERN # :startdoc: end # REGEXP # Class that parses String's into Bundler::URI's. # # It contains a Hash set of patterns and Regexp's that match and validate. # class RFC2396_Parser include RFC2396_REGEXP # # == Synopsis # # Bundler::URI::Parser.new([opts]) # # == Args # # The constructor accepts a hash as options for parser. # Keys of options are pattern names of Bundler::URI components # and values of options are pattern strings. # The constructor generates set of regexps for parsing URIs. # # You can use the following keys: # # * :ESCAPED (Bundler::URI::PATTERN::ESCAPED in default) # * :UNRESERVED (Bundler::URI::PATTERN::UNRESERVED in default) # * :DOMLABEL (Bundler::URI::PATTERN::DOMLABEL in default) # * :TOPLABEL (Bundler::URI::PATTERN::TOPLABEL in default) # * :HOSTNAME (Bundler::URI::PATTERN::HOSTNAME in default) # # == Examples # # p = Bundler::URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})") # u = p.parse("http://example.jp/%uABCD") #=> # # Bundler::URI.parse(u.to_s) #=> raises Bundler::URI::InvalidURIError # # s = "http://example.com/ABCD" # u1 = p.parse(s) #=> # # u2 = Bundler::URI.parse(s) #=> # # u1 == u2 #=> true # u1.eql?(u2) #=> false # def initialize(opts = {}) @pattern = initialize_pattern(opts) @pattern.each_value(&:freeze) @pattern.freeze @regexp = initialize_regexp(@pattern) @regexp.each_value(&:freeze) @regexp.freeze end # The Hash of patterns. # # See also Bundler::URI::Parser.initialize_pattern. attr_reader :pattern # The Hash of Regexp. # # See also Bundler::URI::Parser.initialize_regexp. attr_reader :regexp # Returns a split Bundler::URI against regexp[:ABS_URI]. def split(uri) case uri when '' # null uri when @regexp[:ABS_URI] scheme, opaque, userinfo, host, port, registry, path, query, fragment = $~[1..-1] # Bundler::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] # opaque_part = uric_no_slash *uric # abs_path = "/" path_segments # net_path = "//" authority [ abs_path ] # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] if !scheme raise InvalidURIError, "bad Bundler::URI(absolute but no scheme): #{uri}" end if !opaque && (!path && (!host && !registry)) raise InvalidURIError, "bad Bundler::URI(absolute but no path): #{uri}" end when @regexp[:REL_URI] scheme = nil opaque = nil userinfo, host, port, registry, rel_segment, abs_path, query, fragment = $~[1..-1] if rel_segment && abs_path path = rel_segment + abs_path elsif rel_segment path = rel_segment elsif abs_path path = abs_path end # Bundler::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] # net_path = "//" authority [ abs_path ] # abs_path = "/" path_segments # rel_path = rel_segment [ abs_path ] # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] else raise InvalidURIError, "bad Bundler::URI(is not Bundler::URI?): #{uri}" end path = '' if !path && !opaque # (see RFC2396 Section 5.2) ret = [ scheme, userinfo, host, port, # X registry, # X path, # Y opaque, # Y query, fragment ] return ret end # # == Args # # +uri+:: # String # # == Description # # Parses +uri+ and constructs either matching Bundler::URI scheme object # (File, FTP, HTTP, HTTPS, LDAP, LDAPS, or MailTo) or Bundler::URI::Generic. # # == Usage # # p = Bundler::URI::Parser.new # p.parse("ldap://ldap.example.com/dc=example?user=john") # #=> # # def parse(uri) scheme, userinfo, host, port, registry, path, opaque, query, fragment = self.split(uri) if scheme && Bundler::URI.scheme_list.include?(scheme.upcase) Bundler::URI.scheme_list[scheme.upcase].new(scheme, userinfo, host, port, registry, path, opaque, query, fragment, self) else Generic.new(scheme, userinfo, host, port, registry, path, opaque, query, fragment, self) end end # # == Args # # +uris+:: # an Array of Strings # # == Description # # Attempts to parse and merge a set of URIs. # def join(*uris) uris[0] = convert_to_uri(uris[0]) uris.inject :merge end # # :call-seq: # extract( str ) # extract( str, schemes ) # extract( str, schemes ) {|item| block } # # == Args # # +str+:: # String to search # +schemes+:: # Patterns to apply to +str+ # # == Description # # Attempts to parse and merge a set of URIs. # If no +block+ given, then returns the result, # else it calls +block+ for each element in result. # # See also Bundler::URI::Parser.make_regexp. # def extract(str, schemes = nil) if block_given? str.scan(make_regexp(schemes)) { yield $& } nil else result = [] str.scan(make_regexp(schemes)) { result.push $& } result end end # Returns Regexp that is default self.regexp[:ABS_URI_REF], # unless +schemes+ is provided. Then it is a Regexp.union with self.pattern[:X_ABS_URI]. def make_regexp(schemes = nil) unless schemes @regexp[:ABS_URI_REF] else /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x end end # # :call-seq: # escape( str ) # escape( str, unsafe ) # # == Args # # +str+:: # String to make safe # +unsafe+:: # Regexp to apply. Defaults to self.regexp[:UNSAFE] # # == Description # # Constructs a safe String from +str+, removing unsafe characters, # replacing them with codes. # def escape(str, unsafe = @regexp[:UNSAFE]) unless unsafe.kind_of?(Regexp) # perhaps unsafe is String object unsafe = Regexp.new("[#{Regexp.quote(unsafe)}]", false) end str.gsub(unsafe) do us = $& tmp = '' us.each_byte do |uc| tmp << sprintf('%%%02X', uc) end tmp end.force_encoding(Encoding::US_ASCII) end # # :call-seq: # unescape( str ) # unescape( str, escaped ) # # == Args # # +str+:: # String to remove escapes from # +escaped+:: # Regexp to apply. Defaults to self.regexp[:ESCAPED] # # == Description # # Removes escapes from +str+. # def unescape(str, escaped = @regexp[:ESCAPED]) enc = str.encoding enc = Encoding::UTF_8 if enc == Encoding::US_ASCII str.gsub(escaped) { [$&[1, 2]].pack('H2').force_encoding(enc) } end @@to_s = Kernel.instance_method(:to_s) def inspect @@to_s.bind_call(self) end private # Constructs the default Hash of patterns. def initialize_pattern(opts = {}) ret = {} ret[:ESCAPED] = escaped = (opts.delete(:ESCAPED) || PATTERN::ESCAPED) ret[:UNRESERVED] = unreserved = opts.delete(:UNRESERVED) || PATTERN::UNRESERVED ret[:RESERVED] = reserved = opts.delete(:RESERVED) || PATTERN::RESERVED ret[:DOMLABEL] = opts.delete(:DOMLABEL) || PATTERN::DOMLABEL ret[:TOPLABEL] = opts.delete(:TOPLABEL) || PATTERN::TOPLABEL ret[:HOSTNAME] = hostname = opts.delete(:HOSTNAME) # RFC 2396 (Bundler::URI Generic Syntax) # RFC 2732 (IPv6 Literal Addresses in URL's) # RFC 2373 (IPv6 Addressing Architecture) # uric = reserved | unreserved | escaped ret[:URIC] = uric = "(?:[#{unreserved}#{reserved}]|#{escaped})" # uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | # "&" | "=" | "+" | "$" | "," ret[:URIC_NO_SLASH] = uric_no_slash = "(?:[#{unreserved};?:@&=+$,]|#{escaped})" # query = *uric ret[:QUERY] = query = "#{uric}*" # fragment = *uric ret[:FRAGMENT] = fragment = "#{uric}*" # hostname = *( domainlabel "." ) toplabel [ "." ] # reg-name = *( unreserved / pct-encoded / sub-delims ) # RFC3986 unless hostname ret[:HOSTNAME] = hostname = "(?:[a-zA-Z0-9\\-.]|%\\h\\h)+" end # RFC 2373, APPENDIX B: # IPv6address = hexpart [ ":" IPv4address ] # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT # hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ] # hexseq = hex4 *( ":" hex4) # hex4 = 1*4HEXDIG # # XXX: This definition has a flaw. "::" + IPv4address must be # allowed too. Here is a replacement. # # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT ret[:IPV4ADDR] = ipv4addr = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}" # hex4 = 1*4HEXDIG hex4 = "[#{PATTERN::HEX}]{1,4}" # lastpart = hex4 | IPv4address lastpart = "(?:#{hex4}|#{ipv4addr})" # hexseq1 = *( hex4 ":" ) hex4 hexseq1 = "(?:#{hex4}:)*#{hex4}" # hexseq2 = *( hex4 ":" ) lastpart hexseq2 = "(?:#{hex4}:)*#{lastpart}" # IPv6address = hexseq2 | [ hexseq1 ] "::" [ hexseq2 ] ret[:IPV6ADDR] = ipv6addr = "(?:#{hexseq2}|(?:#{hexseq1})?::(?:#{hexseq2})?)" # IPv6prefix = ( hexseq1 | [ hexseq1 ] "::" [ hexseq1 ] ) "/" 1*2DIGIT # unused # ipv6reference = "[" IPv6address "]" (RFC 2732) ret[:IPV6REF] = ipv6ref = "\\[#{ipv6addr}\\]" # host = hostname | IPv4address # host = hostname | IPv4address | IPv6reference (RFC 2732) ret[:HOST] = host = "(?:#{hostname}|#{ipv4addr}|#{ipv6ref})" # port = *digit ret[:PORT] = port = '\d*' # hostport = host [ ":" port ] ret[:HOSTPORT] = hostport = "#{host}(?::#{port})?" # userinfo = *( unreserved | escaped | # ";" | ":" | "&" | "=" | "+" | "$" | "," ) ret[:USERINFO] = userinfo = "(?:[#{unreserved};:&=+$,]|#{escaped})*" # pchar = unreserved | escaped | # ":" | "@" | "&" | "=" | "+" | "$" | "," pchar = "(?:[#{unreserved}:@&=+$,]|#{escaped})" # param = *pchar param = "#{pchar}*" # segment = *pchar *( ";" param ) segment = "#{pchar}*(?:;#{param})*" # path_segments = segment *( "/" segment ) ret[:PATH_SEGMENTS] = path_segments = "#{segment}(?:/#{segment})*" # server = [ [ userinfo "@" ] hostport ] server = "(?:#{userinfo}@)?#{hostport}" # reg_name = 1*( unreserved | escaped | "$" | "," | # ";" | ":" | "@" | "&" | "=" | "+" ) ret[:REG_NAME] = reg_name = "(?:[#{unreserved}$,;:@&=+]|#{escaped})+" # authority = server | reg_name authority = "(?:#{server}|#{reg_name})" # rel_segment = 1*( unreserved | escaped | # ";" | "@" | "&" | "=" | "+" | "$" | "," ) ret[:REL_SEGMENT] = rel_segment = "(?:[#{unreserved};@&=+$,]|#{escaped})+" # scheme = alpha *( alpha | digit | "+" | "-" | "." ) ret[:SCHEME] = scheme = "[#{PATTERN::ALPHA}][\\-+.#{PATTERN::ALPHA}\\d]*" # abs_path = "/" path_segments ret[:ABS_PATH] = abs_path = "/#{path_segments}" # rel_path = rel_segment [ abs_path ] ret[:REL_PATH] = rel_path = "#{rel_segment}(?:#{abs_path})?" # net_path = "//" authority [ abs_path ] ret[:NET_PATH] = net_path = "//#{authority}(?:#{abs_path})?" # hier_part = ( net_path | abs_path ) [ "?" query ] ret[:HIER_PART] = hier_part = "(?:#{net_path}|#{abs_path})(?:\\?(?:#{query}))?" # opaque_part = uric_no_slash *uric ret[:OPAQUE_PART] = opaque_part = "#{uric_no_slash}#{uric}*" # absoluteURI = scheme ":" ( hier_part | opaque_part ) ret[:ABS_URI] = abs_uri = "#{scheme}:(?:#{hier_part}|#{opaque_part})" # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] ret[:REL_URI] = rel_uri = "(?:#{net_path}|#{abs_path}|#{rel_path})(?:\\?#{query})?" # Bundler::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] ret[:URI_REF] = "(?:#{abs_uri}|#{rel_uri})?(?:##{fragment})?" ret[:X_ABS_URI] = " (#{scheme}): (?# 1: scheme) (?: (#{opaque_part}) (?# 2: opaque) | (?:(?: //(?: (?:(?:(#{userinfo})@)? (?# 3: userinfo) (?:(#{host})(?::(\\d*))?))? (?# 4: host, 5: port) | (#{reg_name}) (?# 6: registry) ) | (?!//)) (?# XXX: '//' is the mark for hostport) (#{abs_path})? (?# 7: path) )(?:\\?(#{query}))? (?# 8: query) ) (?:\\#(#{fragment}))? (?# 9: fragment) " ret[:X_REL_URI] = " (?: (?: // (?: (?:(#{userinfo})@)? (?# 1: userinfo) (#{host})?(?::(\\d*))? (?# 2: host, 3: port) | (#{reg_name}) (?# 4: registry) ) ) | (#{rel_segment}) (?# 5: rel_segment) )? (#{abs_path})? (?# 6: abs_path) (?:\\?(#{query}))? (?# 7: query) (?:\\#(#{fragment}))? (?# 8: fragment) " ret end # Constructs the default Hash of Regexp's. def initialize_regexp(pattern) ret = {} # for Bundler::URI::split ret[:ABS_URI] = Regexp.new('\A\s*' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED) ret[:REL_URI] = Regexp.new('\A\s*' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED) # for Bundler::URI::extract ret[:URI_REF] = Regexp.new(pattern[:URI_REF]) ret[:ABS_URI_REF] = Regexp.new(pattern[:X_ABS_URI], Regexp::EXTENDED) ret[:REL_URI_REF] = Regexp.new(pattern[:X_REL_URI], Regexp::EXTENDED) # for Bundler::URI::escape/unescape ret[:ESCAPED] = Regexp.new(pattern[:ESCAPED]) ret[:UNSAFE] = Regexp.new("[^#{pattern[:UNRESERVED]}#{pattern[:RESERVED]}]") # for Generic#initialize ret[:SCHEME] = Regexp.new("\\A#{pattern[:SCHEME]}\\z") ret[:USERINFO] = Regexp.new("\\A#{pattern[:USERINFO]}\\z") ret[:HOST] = Regexp.new("\\A#{pattern[:HOST]}\\z") ret[:PORT] = Regexp.new("\\A#{pattern[:PORT]}\\z") ret[:OPAQUE] = Regexp.new("\\A#{pattern[:OPAQUE_PART]}\\z") ret[:REGISTRY] = Regexp.new("\\A#{pattern[:REG_NAME]}\\z") ret[:ABS_PATH] = Regexp.new("\\A#{pattern[:ABS_PATH]}\\z") ret[:REL_PATH] = Regexp.new("\\A#{pattern[:REL_PATH]}\\z") ret[:QUERY] = Regexp.new("\\A#{pattern[:QUERY]}\\z") ret[:FRAGMENT] = Regexp.new("\\A#{pattern[:FRAGMENT]}\\z") ret end def convert_to_uri(uri) if uri.is_a?(Bundler::URI::Generic) uri elsif uri = String.try_convert(uri) parse(uri) else raise ArgumentError, "bad argument (expected Bundler::URI object or Bundler::URI string)" end end end # class Parser end # module Bundler::URI PKu] II6bundler-2.2.24/lib/bundler/vendor/tmpdir/lib/tmpdir.rbnu[# frozen_string_literal: true # # tmpdir - retrieve temporary directory path # # $Id$ # require_relative '../../fileutils/lib/fileutils' begin require 'etc.so' rescue LoadError # rescue LoadError for miniruby end class Bundler::Dir < Dir @systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp' ## # Returns the operating system's temporary file path. def self.tmpdir tmp = nil ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', @systmpdir], ['/tmp']*2, ['.']*2].each do |name, dir = ENV[name]| next if !dir dir = File.expand_path(dir) stat = File.stat(dir) rescue next case when !stat.directory? warn "#{name} is not a directory: #{dir}" when !stat.writable? warn "#{name} is not writable: #{dir}" when stat.world_writable? && !stat.sticky? warn "#{name} is world-writable: #{dir}" else tmp = dir break end end raise ArgumentError, "could not find a temporary directory" unless tmp tmp end # Bundler::Dir.mktmpdir creates a temporary directory. # # The directory is created with 0700 permission. # Application should not change the permission to make the temporary directory accessible from other users. # # The prefix and suffix of the name of the directory is specified by # the optional first argument, prefix_suffix. # - If it is not specified or nil, "d" is used as the prefix and no suffix is used. # - If it is a string, it is used as the prefix and no suffix is used. # - If it is an array, first element is used as the prefix and second element is used as a suffix. # # Bundler::Dir.mktmpdir {|dir| dir is ".../d..." } # Bundler::Dir.mktmpdir("foo") {|dir| dir is ".../foo..." } # Bundler::Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" } # # The directory is created under Bundler::Dir.tmpdir or # the optional second argument tmpdir if non-nil value is given. # # Bundler::Dir.mktmpdir {|dir| dir is "#{Bundler::Dir.tmpdir}/d..." } # Bundler::Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." } # # If a block is given, # it is yielded with the path of the directory. # The directory and its contents are removed # using Bundler::FileUtils.remove_entry before Bundler::Dir.mktmpdir returns. # The value of the block is returned. # # Bundler::Dir.mktmpdir {|dir| # # use the directory... # open("#{dir}/foo", "w") { ... } # } # # If a block is not given, # The path of the directory is returned. # In this case, Bundler::Dir.mktmpdir doesn't remove the directory. # # dir = Bundler::Dir.mktmpdir # begin # # use the directory... # open("#{dir}/foo", "w") { ... } # ensure # # remove the directory. # Bundler::FileUtils.remove_entry dir # end # def self.mktmpdir(prefix_suffix=nil, *rest, **options) base = nil path = Tmpname.create(prefix_suffix || "d", *rest, **options) {|p, _, _, d| base = d mkdir(p, 0700) } if block_given? begin yield path.dup ensure unless base stat = File.stat(File.dirname(path)) if stat.world_writable? and !stat.sticky? raise ArgumentError, "parent directory is world writable but not sticky" end end Bundler::FileUtils.remove_entry path end else path end end module Tmpname # :nodoc: module_function def tmpdir Bundler::Dir.tmpdir end UNUSABLE_CHARS = "^,-.0-9A-Z_a-z~" class << (RANDOM = Random.new) MAX = 36**6 # < 0x100000000 def next rand(MAX).to_s(36) end end private_constant :RANDOM def create(basename, tmpdir=nil, max_try: nil, **opts) origdir = tmpdir tmpdir ||= tmpdir() n = nil prefix, suffix = basename prefix = (String.try_convert(prefix) or raise ArgumentError, "unexpected prefix: #{prefix.inspect}") prefix = prefix.delete(UNUSABLE_CHARS) suffix &&= (String.try_convert(suffix) or raise ArgumentError, "unexpected suffix: #{suffix.inspect}") suffix &&= suffix.delete(UNUSABLE_CHARS) begin t = Time.now.strftime("%Y%m%d") path = "#{prefix}#{t}-#{$$}-#{RANDOM.next}"\ "#{n ? %[-#{n}] : ''}#{suffix||''}" path = File.join(tmpdir, path) yield(path, n, opts, origdir) rescue Errno::EEXIST n ||= 0 n += 1 retry if !max_try or n < max_try raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'" end path end end end PKu]lHYY<bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo.rbnu[# frozen_string_literal: true require_relative 'molinillo/gem_metadata' require_relative 'molinillo/errors' require_relative 'molinillo/resolver' require_relative 'molinillo/modules/ui' require_relative 'molinillo/modules/specification_provider' # Bundler::Molinillo is a generic dependency resolution algorithm. module Bundler::Molinillo end PKu]ԻHHTbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rbnu[# frozen_string_literal: true module Bundler::Molinillo class DependencyGraph # A vertex in a {DependencyGraph} that encapsulates a {#name} and a # {#payload} class Vertex # @return [String] the name of the vertex attr_accessor :name # @return [Object] the payload the vertex holds attr_accessor :payload # @return [Array] the explicit requirements that required # this vertex attr_reader :explicit_requirements # @return [Boolean] whether the vertex is considered a root vertex attr_accessor :root alias root? root # Initializes a vertex with the given name and payload. # @param [String] name see {#name} # @param [Object] payload see {#payload} def initialize(name, payload) @name = name.frozen? ? name : name.dup.freeze @payload = payload @explicit_requirements = [] @outgoing_edges = [] @incoming_edges = [] end # @return [Array] all of the requirements that required # this vertex def requirements (incoming_edges.map(&:requirement) + explicit_requirements).uniq end # @return [Array] the edges of {#graph} that have `self` as their # {Edge#origin} attr_accessor :outgoing_edges # @return [Array] the edges of {#graph} that have `self` as their # {Edge#destination} attr_accessor :incoming_edges # @return [Array] the vertices of {#graph} that have an edge with # `self` as their {Edge#destination} def predecessors incoming_edges.map(&:origin) end # @return [Set] the vertices of {#graph} where `self` is a # {#descendent?} def recursive_predecessors _recursive_predecessors end # @param [Set] vertices the set to add the predecessors to # @return [Set] the vertices of {#graph} where `self` is a # {#descendent?} def _recursive_predecessors(vertices = new_vertex_set) incoming_edges.each do |edge| vertex = edge.origin next unless vertices.add?(vertex) vertex._recursive_predecessors(vertices) end vertices end protected :_recursive_predecessors # @return [Array] the vertices of {#graph} that have an edge with # `self` as their {Edge#origin} def successors outgoing_edges.map(&:destination) end # @return [Set] the vertices of {#graph} where `self` is an # {#ancestor?} def recursive_successors _recursive_successors end # @param [Set] vertices the set to add the successors to # @return [Set] the vertices of {#graph} where `self` is an # {#ancestor?} def _recursive_successors(vertices = new_vertex_set) outgoing_edges.each do |edge| vertex = edge.destination next unless vertices.add?(vertex) vertex._recursive_successors(vertices) end vertices end protected :_recursive_successors # @return [String] a string suitable for debugging def inspect "#{self.class}:#{name}(#{payload.inspect})" end # @return [Boolean] whether the two vertices are equal, determined # by a recursive traversal of each {Vertex#successors} def ==(other) return true if equal?(other) shallow_eql?(other) && successors.to_set == other.successors.to_set end # @param [Vertex] other the other vertex to compare to # @return [Boolean] whether the two vertices are equal, determined # solely by {#name} and {#payload} equality def shallow_eql?(other) return true if equal?(other) other && name == other.name && payload == other.payload end alias eql? == # @return [Fixnum] a hash for the vertex based upon its {#name} def hash name.hash end # Is there a path from `self` to `other` following edges in the # dependency graph? # @return whether there is a path following edges within this {#graph} def path_to?(other) _path_to?(other) end alias descendent? path_to? # @param [Vertex] other the vertex to check if there's a path to # @param [Set] visited the vertices of {#graph} that have been visited # @return [Boolean] whether there is a path to `other` from `self` def _path_to?(other, visited = new_vertex_set) return false unless visited.add?(self) return true if equal?(other) successors.any? { |v| v._path_to?(other, visited) } end protected :_path_to? # Is there a path from `other` to `self` following edges in the # dependency graph? # @return whether there is a path following edges within this {#graph} def ancestor?(other) other.path_to?(self) end alias is_reachable_from? ancestor? def new_vertex_set require 'set' Set.new end private :new_vertex_set end end end PKu]:ʘ!abundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # @see DependencyGraph#detach_vertex_named class DetachVertexNamed < Action # @!group Action # (see Action#name) def self.action_name :add_vertex end # (see Action#up) def up(graph) return [] unless @vertex = graph.vertices.delete(name) removed_vertices = [@vertex] @vertex.outgoing_edges.each do |e| v = e.destination v.incoming_edges.delete(e) if !v.root? && v.incoming_edges.empty? removed_vertices.concat graph.detach_vertex_named(v.name) end end @vertex.incoming_edges.each do |e| v = e.origin v.outgoing_edges.delete(e) end removed_vertices end # (see Action#down) def down(graph) return unless @vertex graph.vertices[@vertex.name] = @vertex @vertex.outgoing_edges.each do |e| e.destination.incoming_edges << e end @vertex.incoming_edges.each do |e| e.origin.outgoing_edges << e end end # @!group DetachVertexNamed # @return [String] the name of the vertex to detach attr_reader :name # Initialize an action to detach a vertex from a dependency graph # @param [String] name the name of the vertex to detach def initialize(name) @name = name end end end end PKu]XAccXbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # (see DependencyGraph#add_vertex) class AddVertex < Action # :nodoc: # @!group Action # (see Action.action_name) def self.action_name :add_vertex end # (see Action#up) def up(graph) if existing = graph.vertices[name] @existing_payload = existing.payload @existing_root = existing.root end vertex = existing || Vertex.new(name, payload) graph.vertices[vertex.name] = vertex vertex.payload ||= payload vertex.root ||= root vertex end # (see Action#down) def down(graph) if defined?(@existing_payload) vertex = graph.vertices[name] vertex.payload = @existing_payload vertex.root = @existing_root else graph.vertices.delete(name) end end # @!group AddVertex # @return [String] the name of the vertex attr_reader :name # @return [Object] the payload for the vertex attr_reader :payload # @return [Boolean] whether the vertex is root or not attr_reader :root # Initialize an action to add a vertex to a dependency graph # @param [String] name the name of the vertex # @param [Object] payload the payload for the vertex # @param [Boolean] root whether the vertex is root or not def initialize(name, payload, root) @name = name @payload = payload @root = root end end end end PKu].mVQbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # @see DependencyGraph#tag class Tag < Action # @!group Action # (see Action.action_name) def self.action_name :tag end # (see Action#up) def up(graph) end # (see Action#down) def down(graph) end # @!group Tag # @return [Object] An opaque tag attr_reader :tag # Initialize an action to tag a state of a dependency graph # @param [Object] tag an opaque tag def initialize(tag) @tag = tag end end end end PKu]@G{Tbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rbnu[# frozen_string_literal: true module Bundler::Molinillo class DependencyGraph # An action that modifies a {DependencyGraph} that is reversible. # @abstract class Action # rubocop:disable Lint/UnusedMethodArgument # @return [Symbol] The name of the action. def self.action_name raise 'Abstract' end # Performs the action on the given graph. # @param [DependencyGraph] graph the graph to perform the action on. # @return [Void] def up(graph) raise 'Abstract' end # Reverses the action on the given graph. # @param [DependencyGraph] graph the graph to reverse the action on. # @return [Void] def down(graph) raise 'Abstract' end # @return [Action,Nil] The previous action attr_accessor :previous # @return [Action,Nil] The next action attr_accessor :next end end end PKu]5 Qbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rbnu[# frozen_string_literal: true require_relative 'add_edge_no_circular' require_relative 'add_vertex' require_relative 'delete_edge' require_relative 'detach_vertex_named' require_relative 'set_payload' require_relative 'tag' module Bundler::Molinillo class DependencyGraph # A log for dependency graph actions class Log # Initializes an empty log def initialize @current_action = @first_action = nil end # @!macro [new] action # {include:DependencyGraph#$0} # @param [Graph] graph the graph to perform the action on # @param (see DependencyGraph#$0) # @return (see DependencyGraph#$0) # @macro action def tag(graph, tag) push_action(graph, Tag.new(tag)) end # @macro action def add_vertex(graph, name, payload, root) push_action(graph, AddVertex.new(name, payload, root)) end # @macro action def detach_vertex_named(graph, name) push_action(graph, DetachVertexNamed.new(name)) end # @macro action def add_edge_no_circular(graph, origin, destination, requirement) push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement)) end # {include:DependencyGraph#delete_edge} # @param [Graph] graph the graph to perform the action on # @param [String] origin_name # @param [String] destination_name # @param [Object] requirement # @return (see DependencyGraph#delete_edge) def delete_edge(graph, origin_name, destination_name, requirement) push_action(graph, DeleteEdge.new(origin_name, destination_name, requirement)) end # @macro action def set_payload(graph, name, payload) push_action(graph, SetPayload.new(name, payload)) end # Pops the most recent action from the log and undoes the action # @param [DependencyGraph] graph # @return [Action] the action that was popped off the log def pop!(graph) return unless action = @current_action unless @current_action = action.previous @first_action = nil end action.down(graph) action end extend Enumerable # @!visibility private # Enumerates each action in the log # @yield [Action] def each return enum_for unless block_given? action = @first_action loop do break unless action yield action action = action.next end self end # @!visibility private # Enumerates each action in the log in reverse order # @yield [Action] def reverse_each return enum_for(:reverse_each) unless block_given? action = @current_action loop do break unless action yield action action = action.previous end self end # @macro action def rewind_to(graph, tag) loop do action = pop!(graph) raise "No tag #{tag.inspect} found" unless action break if action.class.action_name == :tag && action.tag == tag end end private # Adds the given action to the log, running the action # @param [DependencyGraph] graph # @param [Action] action # @return The value returned by `action.up` def push_action(graph, action) action.previous = @current_action @current_action.next = action if @current_action @current_action = action @first_action ||= action action.up(graph) end end end end PKu]D""Ybundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # (see DependencyGraph#delete_edge) class DeleteEdge < Action # @!group Action # (see Action.action_name) def self.action_name :delete_edge end # (see Action#up) def up(graph) edge = make_edge(graph) edge.origin.outgoing_edges.delete(edge) edge.destination.incoming_edges.delete(edge) end # (see Action#down) def down(graph) edge = make_edge(graph) edge.origin.outgoing_edges << edge edge.destination.incoming_edges << edge edge end # @!group DeleteEdge # @return [String] the name of the origin of the edge attr_reader :origin_name # @return [String] the name of the destination of the edge attr_reader :destination_name # @return [Object] the requirement that the edge represents attr_reader :requirement # @param [DependencyGraph] graph the graph to find vertices from # @return [Edge] The edge this action adds def make_edge(graph) Edge.new( graph.vertex_named(origin_name), graph.vertex_named(destination_name), requirement ) end # Initialize an action to add an edge to a dependency graph # @param [String] origin_name the name of the origin of the edge # @param [String] destination_name the name of the destination of the edge # @param [Object] requirement the requirement that the edge represents def initialize(origin_name, destination_name, requirement) @origin_name = origin_name @destination_name = destination_name @requirement = requirement end end end end PKu] ?=WWYbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # @see DependencyGraph#set_payload class SetPayload < Action # :nodoc: # @!group Action # (see Action.action_name) def self.action_name :set_payload end # (see Action#up) def up(graph) vertex = graph.vertex_named(name) @old_payload = vertex.payload vertex.payload = payload end # (see Action#down) def down(graph) graph.vertex_named(name).payload = @old_payload end # @!group SetPayload # @return [String] the name of the vertex attr_reader :name # @return [Object] the payload for the vertex attr_reader :payload # Initialize an action to add set the payload for a vertex in a dependency # graph # @param [String] name the name of the vertex # @param [Object] payload the payload for the vertex def initialize(name, payload) @name = name @payload = payload end end end end PKu]DNjoobbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rbnu[# frozen_string_literal: true require_relative 'action' module Bundler::Molinillo class DependencyGraph # @!visibility private # (see DependencyGraph#add_edge_no_circular) class AddEdgeNoCircular < Action # @!group Action # (see Action.action_name) def self.action_name :add_vertex end # (see Action#up) def up(graph) edge = make_edge(graph) edge.origin.outgoing_edges << edge edge.destination.incoming_edges << edge edge end # (see Action#down) def down(graph) edge = make_edge(graph) delete_first(edge.origin.outgoing_edges, edge) delete_first(edge.destination.incoming_edges, edge) end # @!group AddEdgeNoCircular # @return [String] the name of the origin of the edge attr_reader :origin # @return [String] the name of the destination of the edge attr_reader :destination # @return [Object] the requirement that the edge represents attr_reader :requirement # @param [DependencyGraph] graph the graph to find vertices from # @return [Edge] The edge this action adds def make_edge(graph) Edge.new(graph.vertex_named(origin), graph.vertex_named(destination), requirement) end # Initialize an action to add an edge to a dependency graph # @param [String] origin the name of the origin of the edge # @param [String] destination the name of the destination of the edge # @param [Object] requirement the requirement that the edge represents def initialize(origin, destination, requirement) @origin = origin @destination = destination @requirement = requirement end private def delete_first(array, item) return unless index = array.index(item) array.delete_at(index) end end end end PKu]cOu((Bbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/state.rbnu[# frozen_string_literal: true module Bundler::Molinillo # A state that a {Resolution} can be in # @attr [String] name the name of the current requirement # @attr [Array] requirements currently unsatisfied requirements # @attr [DependencyGraph] activated the graph of activated dependencies # @attr [Object] requirement the current requirement # @attr [Object] possibilities the possibilities to satisfy the current requirement # @attr [Integer] depth the depth of the resolution # @attr [Hash] conflicts unresolved conflicts, indexed by dependency name # @attr [Array] unused_unwind_options unwinds for previous conflicts that weren't explored ResolutionState = Struct.new( :name, :requirements, :activated, :requirement, :possibilities, :depth, :conflicts, :unused_unwind_options ) class ResolutionState # Returns an empty resolution state # @return [ResolutionState] an empty state def self.empty new(nil, [], DependencyGraph.new, nil, nil, 0, {}, []) end end # A state that encapsulates a set of {#requirements} with an {Array} of # possibilities class DependencyState < ResolutionState # Removes a possibility from `self` # @return [PossibilityState] a state with a single possibility, # the possibility that was removed from `self` def pop_possibility_state PossibilityState.new( name, requirements.dup, activated, requirement, [possibilities.pop], depth + 1, conflicts.dup, unused_unwind_options.dup ).tap do |state| state.activated.tag(state) end end end # A state that encapsulates a single possibility to fulfill the given # {#requirement} class PossibilityState < ResolutionState end end PKu]U#||Cbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/errors.rbnu[# frozen_string_literal: true module Bundler::Molinillo # An error that occurred during the resolution process class ResolverError < StandardError; end # An error caused by searching for a dependency that is completely unknown, # i.e. has no versions available whatsoever. class NoSuchDependencyError < ResolverError # @return [Object] the dependency that could not be found attr_accessor :dependency # @return [Array] the specifications that depended upon {#dependency} attr_accessor :required_by # Initializes a new error with the given missing dependency. # @param [Object] dependency @see {#dependency} # @param [Array] required_by @see {#required_by} def initialize(dependency, required_by = []) @dependency = dependency @required_by = required_by.uniq super() end # The error message for the missing dependency, including the specifications # that had this dependency. def message sources = required_by.map { |r| "`#{r}`" }.join(' and ') message = "Unable to find a specification for `#{dependency}`" message += " depended upon by #{sources}" unless sources.empty? message end end # An error caused by attempting to fulfil a dependency that was circular # # @note This exception will be thrown if and only if a {Vertex} is added to a # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an # existing {DependencyGraph::Vertex} class CircularDependencyError < ResolverError # [Set] the dependencies responsible for causing the error attr_reader :dependencies # Initializes a new error with the given circular vertices. # @param [Array] vertices the vertices in the dependency # that caused the error def initialize(vertices) super "There is a circular dependency between #{vertices.map(&:name).join(' and ')}" @dependencies = vertices.map { |vertex| vertex.payload.possibilities.last }.to_set end end # An error caused by conflicts in version class VersionConflict < ResolverError # @return [{String => Resolution::Conflict}] the conflicts that caused # resolution to fail attr_reader :conflicts # @return [SpecificationProvider] the specification provider used during # resolution attr_reader :specification_provider # Initializes a new error with the given version conflicts. # @param [{String => Resolution::Conflict}] conflicts see {#conflicts} # @param [SpecificationProvider] specification_provider see {#specification_provider} def initialize(conflicts, specification_provider) pairs = [] conflicts.values.flat_map(&:requirements).each do |conflicting| conflicting.each do |source, conflict_requirements| conflict_requirements.each do |c| pairs << [c, source] end end end super "Unable to satisfy the following requirements:\n\n" \ "#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}" @conflicts = conflicts @specification_provider = specification_provider end require_relative 'delegates/specification_provider' include Delegates::SpecificationProvider # @return [String] An error message that includes requirement trees, # which is much more detailed & customizable than the default message # @param [Hash] opts the options to create a message with. # @option opts [String] :solver_name The user-facing name of the solver # @option opts [String] :possibility_type The generic name of a possibility # @option opts [Proc] :reduce_trees A proc that reduced the list of requirement trees # @option opts [Proc] :printable_requirement A proc that pretty-prints requirements # @option opts [Proc] :additional_message_for_conflict A proc that appends additional # messages for each conflict # @option opts [Proc] :version_for_spec A proc that returns the version number for a # possibility def message_with_trees(opts = {}) solver_name = opts.delete(:solver_name) { self.class.name.split('::').first } possibility_type = opts.delete(:possibility_type) { 'possibility named' } reduce_trees = opts.delete(:reduce_trees) { proc { |trees| trees.uniq.sort_by(&:to_s) } } printable_requirement = opts.delete(:printable_requirement) { proc { |req| req.to_s } } additional_message_for_conflict = opts.delete(:additional_message_for_conflict) { proc {} } version_for_spec = opts.delete(:version_for_spec) { proc(&:to_s) } incompatible_version_message_for_conflict = opts.delete(:incompatible_version_message_for_conflict) do proc do |name, _conflict| %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":) end end conflicts.sort.reduce(''.dup) do |o, (name, conflict)| o << "\n" << incompatible_version_message_for_conflict.call(name, conflict) << "\n" if conflict.locked_requirement o << %( In snapshot (#{name_for_locking_dependency_source}):\n) o << %( #{printable_requirement.call(conflict.locked_requirement)}\n) o << %(\n) end o << %( In #{name_for_explicit_dependency_source}:\n) trees = reduce_trees.call(conflict.requirement_trees) o << trees.map do |tree| t = ''.dup depth = 2 tree.each do |req| t << ' ' * depth << printable_requirement.call(req) unless tree.last == req if spec = conflict.activated_by_name[name_for(req)] t << %( was resolved to #{version_for_spec.call(spec)}, which) end t << %( depends on) end t << %(\n) depth += 1 end t end.join("\n") additional_message_for_conflict.call(o, name, conflict) o end.strip end end end PKu]~Ebundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rbnu[# frozen_string_literal: true require_relative 'dependency_graph' module Bundler::Molinillo # This class encapsulates a dependency resolver. # The resolver is responsible for determining which set of dependencies to # activate, with feedback from the {#specification_provider} # # class Resolver require_relative 'resolution' # @return [SpecificationProvider] the specification provider used # in the resolution process attr_reader :specification_provider # @return [UI] the UI module used to communicate back to the user # during the resolution process attr_reader :resolver_ui # Initializes a new resolver. # @param [SpecificationProvider] specification_provider # see {#specification_provider} # @param [UI] resolver_ui # see {#resolver_ui} def initialize(specification_provider, resolver_ui) @specification_provider = specification_provider @resolver_ui = resolver_ui end # Resolves the requested dependencies into a {DependencyGraph}, # locking to the base dependency graph (if specified) # @param [Array] requested an array of 'requested' dependencies that the # {#specification_provider} can understand # @param [DependencyGraph,nil] base the base dependency graph to which # dependencies should be 'locked' def resolve(requested, base = DependencyGraph.new) Resolution.new(specification_provider, resolver_ui, requested, base). resolve end end end PKu] Mbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rbnu[# frozen_string_literal: true require 'tsort' require_relative 'dependency_graph/log' require_relative 'dependency_graph/vertex' module Bundler::Molinillo # A directed acyclic graph that is tuned to hold named dependencies class DependencyGraph include Enumerable # Enumerates through the vertices of the graph. # @return [Array] The graph's vertices. def each return vertices.values.each unless block_given? vertices.values.each { |v| yield v } end include TSort # @!visibility private alias tsort_each_node each # @!visibility private def tsort_each_child(vertex, &block) vertex.successors.each(&block) end # Topologically sorts the given vertices. # @param [Enumerable] vertices the vertices to be sorted, which must # all belong to the same graph. # @return [Array] The sorted vertices. def self.tsort(vertices) TSort.tsort( lambda { |b| vertices.each(&b) }, lambda { |v, &b| (v.successors & vertices).each(&b) } ) end # A directed edge of a {DependencyGraph} # @attr [Vertex] origin The origin of the directed edge # @attr [Vertex] destination The destination of the directed edge # @attr [Object] requirement The requirement the directed edge represents Edge = Struct.new(:origin, :destination, :requirement) # @return [{String => Vertex}] the vertices of the dependency graph, keyed # by {Vertex#name} attr_reader :vertices # @return [Log] the op log for this graph attr_reader :log # Initializes an empty dependency graph def initialize @vertices = {} @log = Log.new end # Tags the current state of the dependency as the given tag # @param [Object] tag an opaque tag for the current state of the graph # @return [Void] def tag(tag) log.tag(self, tag) end # Rewinds the graph to the state tagged as `tag` # @param [Object] tag the tag to rewind to # @return [Void] def rewind_to(tag) log.rewind_to(self, tag) end # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices} # are properly copied. # @param [DependencyGraph] other the graph to copy. def initialize_copy(other) super @vertices = {} @log = other.log.dup traverse = lambda do |new_v, old_v| return if new_v.outgoing_edges.size == old_v.outgoing_edges.size old_v.outgoing_edges.each do |edge| destination = add_vertex(edge.destination.name, edge.destination.payload) add_edge_no_circular(new_v, destination, edge.requirement) traverse.call(destination, edge.destination) end end other.vertices.each do |name, vertex| new_vertex = add_vertex(name, vertex.payload, vertex.root?) new_vertex.explicit_requirements.replace(vertex.explicit_requirements) traverse.call(new_vertex, vertex) end end # @return [String] a string suitable for debugging def inspect "#{self.class}:#{vertices.values.inspect}" end # @param [Hash] options options for dot output. # @return [String] Returns a dot format representation of the graph def to_dot(options = {}) edge_label = options.delete(:edge_label) raise ArgumentError, "Unknown options: #{options.keys}" unless options.empty? dot_vertices = [] dot_edges = [] vertices.each do |n, v| dot_vertices << " #{n} [label=\"{#{n}|#{v.payload}}\"]" v.outgoing_edges.each do |e| label = edge_label ? edge_label.call(e) : e.requirement dot_edges << " #{e.origin.name} -> #{e.destination.name} [label=#{label.to_s.dump}]" end end dot_vertices.uniq! dot_vertices.sort! dot_edges.uniq! dot_edges.sort! dot = dot_vertices.unshift('digraph G {').push('') + dot_edges.push('}') dot.join("\n") end # @param [DependencyGraph] other # @return [Boolean] whether the two dependency graphs are equal, determined # by a recursive traversal of each {#root_vertices} and its # {Vertex#successors} def ==(other) return false unless other return true if equal?(other) vertices.each do |name, vertex| other_vertex = other.vertex_named(name) return false unless other_vertex return false unless vertex.payload == other_vertex.payload return false unless other_vertex.successors.to_set == vertex.successors.to_set end end # @param [String] name # @param [Object] payload # @param [Array] parent_names # @param [Object] requirement the requirement that is requiring the child # @return [void] def add_child_vertex(name, payload, parent_names, requirement) root = !parent_names.delete(nil) { true } vertex = add_vertex(name, payload, root) vertex.explicit_requirements << requirement if root parent_names.each do |parent_name| parent_vertex = vertex_named(parent_name) add_edge(parent_vertex, vertex, requirement) end vertex end # Adds a vertex with the given name, or updates the existing one. # @param [String] name # @param [Object] payload # @return [Vertex] the vertex that was added to `self` def add_vertex(name, payload, root = false) log.add_vertex(self, name, payload, root) end # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively # removing any non-root vertices that were orphaned in the process # @param [String] name # @return [Array] the vertices which have been detached def detach_vertex_named(name) log.detach_vertex_named(self, name) end # @param [String] name # @return [Vertex,nil] the vertex with the given name def vertex_named(name) vertices[name] end # @param [String] name # @return [Vertex,nil] the root vertex with the given name def root_vertex_named(name) vertex = vertex_named(name) vertex if vertex && vertex.root? end # Adds a new {Edge} to the dependency graph # @param [Vertex] origin # @param [Vertex] destination # @param [Object] requirement the requirement that this edge represents # @return [Edge] the added edge def add_edge(origin, destination, requirement) if destination.path_to?(origin) raise CircularDependencyError.new(path(destination, origin)) end add_edge_no_circular(origin, destination, requirement) end # Deletes an {Edge} from the dependency graph # @param [Edge] edge # @return [Void] def delete_edge(edge) log.delete_edge(self, edge.origin.name, edge.destination.name, edge.requirement) end # Sets the payload of the vertex with the given name # @param [String] name the name of the vertex # @param [Object] payload the payload # @return [Void] def set_payload(name, payload) log.set_payload(self, name, payload) end private # Adds a new {Edge} to the dependency graph without checking for # circularity. # @param (see #add_edge) # @return (see #add_edge) def add_edge_no_circular(origin, destination, requirement) log.add_edge_no_circular(self, origin.name, destination.name, requirement) end # Returns the path between two vertices # @raise [ArgumentError] if there is no path between the vertices # @param [Vertex] from # @param [Vertex] to # @return [Array] the shortest path from `from` to `to` def path(from, to) distances = Hash.new(vertices.size + 1) distances[from.name] = 0 predecessors = {} each do |vertex| vertex.successors.each do |successor| if distances[successor.name] > distances[vertex.name] + 1 distances[successor.name] = distances[vertex.name] + 1 predecessors[successor] = vertex end end end path = [to] while before = predecessors[to] path << before to = before break if to == from end unless path.last.equal?(from) raise ArgumentError, "There is no path from #{from.name} to #{to.name}" end path.reverse end end end PKu]ۦ ]bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rbnu[# frozen_string_literal: true module Bundler::Molinillo module Delegates # Delegates all {Bundler::Molinillo::SpecificationProvider} methods to a # `#specification_provider` property. module SpecificationProvider # (see Bundler::Molinillo::SpecificationProvider#search_for) def search_for(dependency) with_no_such_dependency_error_handling do specification_provider.search_for(dependency) end end # (see Bundler::Molinillo::SpecificationProvider#dependencies_for) def dependencies_for(specification) with_no_such_dependency_error_handling do specification_provider.dependencies_for(specification) end end # (see Bundler::Molinillo::SpecificationProvider#requirement_satisfied_by?) def requirement_satisfied_by?(requirement, activated, spec) with_no_such_dependency_error_handling do specification_provider.requirement_satisfied_by?(requirement, activated, spec) end end # (see Bundler::Molinillo::SpecificationProvider#dependencies_equal?) def dependencies_equal?(dependencies, other_dependencies) with_no_such_dependency_error_handling do specification_provider.dependencies_equal?(dependencies, other_dependencies) end end # (see Bundler::Molinillo::SpecificationProvider#name_for) def name_for(dependency) with_no_such_dependency_error_handling do specification_provider.name_for(dependency) end end # (see Bundler::Molinillo::SpecificationProvider#name_for_explicit_dependency_source) def name_for_explicit_dependency_source with_no_such_dependency_error_handling do specification_provider.name_for_explicit_dependency_source end end # (see Bundler::Molinillo::SpecificationProvider#name_for_locking_dependency_source) def name_for_locking_dependency_source with_no_such_dependency_error_handling do specification_provider.name_for_locking_dependency_source end end # (see Bundler::Molinillo::SpecificationProvider#sort_dependencies) def sort_dependencies(dependencies, activated, conflicts) with_no_such_dependency_error_handling do specification_provider.sort_dependencies(dependencies, activated, conflicts) end end # (see Bundler::Molinillo::SpecificationProvider#allow_missing?) def allow_missing?(dependency) with_no_such_dependency_error_handling do specification_provider.allow_missing?(dependency) end end private # Ensures any raised {NoSuchDependencyError} has its # {NoSuchDependencyError#required_by} set. # @yield def with_no_such_dependency_error_handling yield rescue NoSuchDependencyError => error if state vertex = activated.vertex_named(name_for(error.dependency)) error.required_by += vertex.incoming_edges.map { |e| e.origin.name } error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty? end raise end end end end PKu]9DD??Wbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rbnu[# frozen_string_literal: true module Bundler::Molinillo # @!visibility private module Delegates # Delegates all {Bundler::Molinillo::ResolutionState} methods to a `#state` property. module ResolutionState # (see Bundler::Molinillo::ResolutionState#name) def name current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.name end # (see Bundler::Molinillo::ResolutionState#requirements) def requirements current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.requirements end # (see Bundler::Molinillo::ResolutionState#activated) def activated current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.activated end # (see Bundler::Molinillo::ResolutionState#requirement) def requirement current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.requirement end # (see Bundler::Molinillo::ResolutionState#possibilities) def possibilities current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.possibilities end # (see Bundler::Molinillo::ResolutionState#depth) def depth current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.depth end # (see Bundler::Molinillo::ResolutionState#conflicts) def conflicts current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.conflicts end # (see Bundler::Molinillo::ResolutionState#unused_unwind_options) def unused_unwind_options current_state = state || Bundler::Molinillo::ResolutionState.empty current_state.unused_unwind_options end end end end PKu]+4Gbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rbnu[# frozen_string_literal: true module Bundler::Molinillo # Conveys information about the resolution process to a user. module UI # The {IO} object that should be used to print output. `STDOUT`, by default. # # @return [IO] def output STDOUT end # Called roughly every {#progress_rate}, this method should convey progress # to the user. # # @return [void] def indicate_progress output.print '.' unless debug? end # How often progress should be conveyed to the user via # {#indicate_progress}, in seconds. A third of a second, by default. # # @return [Float] def progress_rate 0.33 end # Called before resolution begins. # # @return [void] def before_resolution output.print 'Resolving dependencies...' end # Called after resolution ends (either successfully or with an error). # By default, prints a newline. # # @return [void] def after_resolution output.puts end # Conveys debug information to the user. # # @param [Integer] depth the current depth of the resolution process. # @return [void] def debug(depth = 0) if debug? debug_info = yield debug_info = debug_info.inspect unless debug_info.is_a?(String) debug_info = debug_info.split("\n").map { |s| ":#{depth.to_s.rjust 4}: #{s}" } output.puts debug_info end end # Whether or not debug messages should be printed. # By default, whether or not the `MOLINILLO_DEBUG` environment variable is # set. # # @return [Boolean] def debug? return @debug_mode if defined?(@debug_mode) @debug_mode = ENV['MOLINILLO_DEBUG'] end end end PKu]!gpt[[[bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rbnu[# frozen_string_literal: true module Bundler::Molinillo # Provides information about specifications and dependencies to the resolver, # allowing the {Resolver} class to remain generic while still providing power # and flexibility. # # This module contains the methods that users of Bundler::Molinillo must to implement, # using knowledge of their own model classes. module SpecificationProvider # Search for the specifications that match the given dependency. # The specifications in the returned array will be considered in reverse # order, so the latest version ought to be last. # @note This method should be 'pure', i.e. the return value should depend # only on the `dependency` parameter. # # @param [Object] dependency # @return [Array] the specifications that satisfy the given # `dependency`. def search_for(dependency) [] end # Returns the dependencies of `specification`. # @note This method should be 'pure', i.e. the return value should depend # only on the `specification` parameter. # # @param [Object] specification # @return [Array] the dependencies that are required by the given # `specification`. def dependencies_for(specification) [] end # Determines whether the given `requirement` is satisfied by the given # `spec`, in the context of the current `activated` dependency graph. # # @param [Object] requirement # @param [DependencyGraph] activated the current dependency graph in the # resolution process. # @param [Object] spec # @return [Boolean] whether `requirement` is satisfied by `spec` in the # context of the current `activated` dependency graph. def requirement_satisfied_by?(requirement, activated, spec) true end # Determines whether two arrays of dependencies are equal, and thus can be # grouped. # # @param [Array] dependencies # @param [Array] other_dependencies # @return [Boolean] whether `dependencies` and `other_dependencies` should # be considered equal. def dependencies_equal?(dependencies, other_dependencies) dependencies == other_dependencies end # Returns the name for the given `dependency`. # @note This method should be 'pure', i.e. the return value should depend # only on the `dependency` parameter. # # @param [Object] dependency # @return [String] the name for the given `dependency`. def name_for(dependency) dependency.to_s end # @return [String] the name of the source of explicit dependencies, i.e. # those passed to {Resolver#resolve} directly. def name_for_explicit_dependency_source 'user-specified dependency' end # @return [String] the name of the source of 'locked' dependencies, i.e. # those passed to {Resolver#resolve} directly as the `base` def name_for_locking_dependency_source 'Lockfile' end # Sort dependencies so that the ones that are easiest to resolve are first. # Easiest to resolve is (usually) defined by: # 1) Is this dependency already activated? # 2) How relaxed are the requirements? # 3) Are there any conflicts for this dependency? # 4) How many possibilities are there to satisfy this dependency? # # @param [Array] dependencies # @param [DependencyGraph] activated the current dependency graph in the # resolution process. # @param [{String => Array}] conflicts # @return [Array] a sorted copy of `dependencies`. def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| name = name_for(dependency) [ activated.vertex_named(name).payload ? 0 : 1, conflicts[name] ? 0 : 1, ] end end # Returns whether this dependency, which has no possible matching # specifications, can safely be ignored. # # @param [Object] dependency # @return [Boolean] whether this dependency can safely be skipped. def allow_missing?(dependency) false end end end PKu]=Gbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rbnu[# frozen_string_literal: true module Bundler::Molinillo class Resolver # A specific resolution from a given {Resolver} class Resolution # A conflict that the resolution process encountered # @attr [Object] requirement the requirement that immediately led to the conflict # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict # @attr [Object, nil] existing the existing spec that was in conflict with # the {#possibility} # @attr [Object] possibility_set the set of specs that was unable to be # activated due to a conflict. # @attr [Object] locked_requirement the relevant locking requirement. # @attr [Array>] requirement_trees the different requirement # trees that led to every requirement for the conflicting name. # @attr [{String=>Object}] activated_by_name the already-activated specs. # @attr [Object] underlying_error an error that has occurred during resolution, and # will be raised at the end of it if no resolution is found. Conflict = Struct.new( :requirement, :requirements, :existing, :possibility_set, :locked_requirement, :requirement_trees, :activated_by_name, :underlying_error ) class Conflict # @return [Object] a spec that was unable to be activated due to a conflict def possibility possibility_set && possibility_set.latest_version end end # A collection of possibility states that share the same dependencies # @attr [Array] dependencies the dependencies for this set of possibilities # @attr [Array] possibilities the possibilities PossibilitySet = Struct.new(:dependencies, :possibilities) class PossibilitySet # String representation of the possibility set, for debugging def to_s "[#{possibilities.join(', ')}]" end # @return [Object] most up-to-date dependency in the possibility set def latest_version possibilities.last end end # Details of the state to unwind to when a conflict occurs, and the cause of the unwind # @attr [Integer] state_index the index of the state to unwind to # @attr [Object] state_requirement the requirement of the state we're unwinding to # @attr [Array] requirement_tree for the requirement we're relaxing # @attr [Array] conflicting_requirements the requirements that combined to cause the conflict # @attr [Array] requirement_trees for the conflict # @attr [Array] requirements_unwound_to_instead array of unwind requirements that were chosen over this unwind UnwindDetails = Struct.new( :state_index, :state_requirement, :requirement_tree, :conflicting_requirements, :requirement_trees, :requirements_unwound_to_instead ) class UnwindDetails include Comparable # We compare UnwindDetails when choosing which state to unwind to. If # two options have the same state_index we prefer the one most # removed from a requirement that caused the conflict. Both options # would unwind to the same state, but a `grandparent` option will # filter out fewer of its possibilities after doing so - where a state # is both a `parent` and a `grandparent` to requirements that have # caused a conflict this is the correct behaviour. # @param [UnwindDetail] other UnwindDetail to be compared # @return [Integer] integer specifying ordering def <=>(other) if state_index > other.state_index 1 elsif state_index == other.state_index reversed_requirement_tree_index <=> other.reversed_requirement_tree_index else -1 end end # @return [Integer] index of state requirement in reversed requirement tree # (the conflicting requirement itself will be at position 0) def reversed_requirement_tree_index @reversed_requirement_tree_index ||= if state_requirement requirement_tree.reverse.index(state_requirement) else 999_999 end end # @return [Boolean] where the requirement of the state we're unwinding # to directly caused the conflict. Note: in this case, it is # impossible for the state we're unwinding to to be a parent of # any of the other conflicting requirements (or we would have # circularity) def unwinding_to_primary_requirement? requirement_tree.last == state_requirement end # @return [Array] array of sub-dependencies to avoid when choosing a # new possibility for the state we've unwound to. Only relevant for # non-primary unwinds def sub_dependencies_to_avoid @requirements_to_avoid ||= requirement_trees.map do |tree| index = tree.index(state_requirement) tree[index + 1] if index end.compact end # @return [Array] array of all the requirements that led to the need for # this unwind def all_requirements @all_requirements ||= requirement_trees.flatten(1) end end # @return [SpecificationProvider] the provider that knows about # dependencies, requirements, specifications, versions, etc. attr_reader :specification_provider # @return [UI] the UI that knows how to communicate feedback about the # resolution process back to the user attr_reader :resolver_ui # @return [DependencyGraph] the base dependency graph to which # dependencies should be 'locked' attr_reader :base # @return [Array] the dependencies that were explicitly required attr_reader :original_requested # Initializes a new resolution. # @param [SpecificationProvider] specification_provider # see {#specification_provider} # @param [UI] resolver_ui see {#resolver_ui} # @param [Array] requested see {#original_requested} # @param [DependencyGraph] base see {#base} def initialize(specification_provider, resolver_ui, requested, base) @specification_provider = specification_provider @resolver_ui = resolver_ui @original_requested = requested @base = base @states = [] @iteration_counter = 0 @parents_of = Hash.new { |h, k| h[k] = [] } end # Resolves the {#original_requested} dependencies into a full dependency # graph # @raise [ResolverError] if successful resolution is impossible # @return [DependencyGraph] the dependency graph of successfully resolved # dependencies def resolve start_resolution while state break if !state.requirement && state.requirements.empty? indicate_progress if state.respond_to?(:pop_possibility_state) # DependencyState debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" } state.pop_possibility_state.tap do |s| if s states.push(s) activated.tag(s) end end end process_topmost_state end resolve_activated_specs ensure end_resolution end # @return [Integer] the number of resolver iterations in between calls to # {#resolver_ui}'s {UI#indicate_progress} method attr_accessor :iteration_rate private :iteration_rate # @return [Time] the time at which resolution began attr_accessor :started_at private :started_at # @return [Array] the stack of states for the resolution attr_accessor :states private :states private # Sets up the resolution process # @return [void] def start_resolution @started_at = Time.now push_initial_state debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" } resolver_ui.before_resolution end def resolve_activated_specs activated.vertices.each do |_, vertex| next unless vertex.payload latest_version = vertex.payload.possibilities.reverse_each.find do |possibility| vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) } end activated.set_payload(vertex.name, latest_version) end activated.freeze end # Ends the resolution process # @return [void] def end_resolution resolver_ui.after_resolution debug do "Finished resolution (#{@iteration_counter} steps) " \ "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})" end debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state end require_relative 'state' require_relative 'modules/specification_provider' require_relative 'delegates/resolution_state' require_relative 'delegates/specification_provider' include Bundler::Molinillo::Delegates::ResolutionState include Bundler::Molinillo::Delegates::SpecificationProvider # Processes the topmost available {RequirementState} on the stack # @return [void] def process_topmost_state if possibility attempt_to_activate else create_conflict unwind_for_conflict end rescue CircularDependencyError => underlying_error create_conflict(underlying_error) unwind_for_conflict end # @return [Object] the current possibility that the resolution is trying # to activate def possibility possibilities.last end # @return [RequirementState] the current state the resolution is # operating upon def state states.last end # Creates and pushes the initial state for the resolution, based upon the # {#requested} dependencies # @return [void] def push_initial_state graph = DependencyGraph.new.tap do |dg| original_requested.each do |requested| vertex = dg.add_vertex(name_for(requested), nil, true) vertex.explicit_requirements << requested end dg.tag(:initial_state) end push_state_for_requirements(original_requested, true, graph) end # Unwinds the states stack because a conflict has been encountered # @return [void] def unwind_for_conflict details_for_unwind = build_details_for_unwind unwind_options = unused_unwind_options debug(depth) { "Unwinding for conflict: #{requirement} to #{details_for_unwind.state_index / 2}" } conflicts.tap do |c| sliced_states = states.slice!((details_for_unwind.state_index + 1)..-1) raise_error_unless_state(c) activated.rewind_to(sliced_states.first || :initial_state) if sliced_states state.conflicts = c state.unused_unwind_options = unwind_options filter_possibilities_after_unwind(details_for_unwind) index = states.size - 1 @parents_of.each { |_, a| a.reject! { |i| i >= index } } state.unused_unwind_options.reject! { |uw| uw.state_index >= index } end end # Raises a VersionConflict error, or any underlying error, if there is no # current state # @return [void] def raise_error_unless_state(conflicts) return if state error = conflicts.values.map(&:underlying_error).compact.first raise error || VersionConflict.new(conflicts, specification_provider) end # @return [UnwindDetails] Details of the nearest index to which we could unwind def build_details_for_unwind # Get the possible unwinds for the current conflict current_conflict = conflicts[name] binding_requirements = binding_requirements_for_conflict(current_conflict) unwind_details = unwind_options_for_requirements(binding_requirements) last_detail_for_current_unwind = unwind_details.sort.last current_detail = last_detail_for_current_unwind # Look for past conflicts that could be unwound to affect the # requirement tree for the current conflict all_reqs = last_detail_for_current_unwind.all_requirements all_reqs_size = all_reqs.size relevant_unused_unwinds = unused_unwind_options.select do |alternative| diff_reqs = all_reqs - alternative.requirements_unwound_to_instead next if diff_reqs.size == all_reqs_size # Find the highest index unwind whilst looping through current_detail = alternative if alternative > current_detail alternative end # Add the current unwind options to the `unused_unwind_options` array. # The "used" option will be filtered out during `unwind_for_conflict`. state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 } # Update the requirements_unwound_to_instead on any relevant unused unwinds relevant_unused_unwinds.each do |d| (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq! end unwind_details.each do |d| (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq! end current_detail end # @param [Array] binding_requirements array of requirements that combine to create a conflict # @return [Array] array of UnwindDetails that have a chance # of resolving the passed requirements def unwind_options_for_requirements(binding_requirements) unwind_details = [] trees = [] binding_requirements.reverse_each do |r| partial_tree = [r] trees << partial_tree unwind_details << UnwindDetails.new(-1, nil, partial_tree, binding_requirements, trees, []) # If this requirement has alternative possibilities, check if any would # satisfy the other requirements that created this conflict requirement_state = find_state_for(r) if conflict_fixing_possibilities?(requirement_state, binding_requirements) unwind_details << UnwindDetails.new( states.index(requirement_state), r, partial_tree, binding_requirements, trees, [] ) end # Next, look at the parent of this requirement, and check if the requirement # could have been avoided if an alternative PossibilitySet had been chosen parent_r = parent_of(r) next if parent_r.nil? partial_tree.unshift(parent_r) requirement_state = find_state_for(parent_r) if requirement_state.possibilities.any? { |set| !set.dependencies.include?(r) } unwind_details << UnwindDetails.new( states.index(requirement_state), parent_r, partial_tree, binding_requirements, trees, [] ) end # Finally, look at the grandparent and up of this requirement, looking # for any possibilities that wouldn't create their parent requirement grandparent_r = parent_of(parent_r) until grandparent_r.nil? partial_tree.unshift(grandparent_r) requirement_state = find_state_for(grandparent_r) if requirement_state.possibilities.any? { |set| !set.dependencies.include?(parent_r) } unwind_details << UnwindDetails.new( states.index(requirement_state), grandparent_r, partial_tree, binding_requirements, trees, [] ) end parent_r = grandparent_r grandparent_r = parent_of(parent_r) end end unwind_details end # @param [DependencyState] state # @param [Array] binding_requirements array of requirements # @return [Boolean] whether or not the given state has any possibilities # that could satisfy the given requirements def conflict_fixing_possibilities?(state, binding_requirements) return false unless state state.possibilities.any? do |possibility_set| possibility_set.possibilities.any? do |poss| possibility_satisfies_requirements?(poss, binding_requirements) end end end # Filter's a state's possibilities to remove any that would not fix the # conflict we've just rewound from # @param [UnwindDetails] unwind_details details of the conflict just # unwound from # @return [void] def filter_possibilities_after_unwind(unwind_details) return unless state && !state.possibilities.empty? if unwind_details.unwinding_to_primary_requirement? filter_possibilities_for_primary_unwind(unwind_details) else filter_possibilities_for_parent_unwind(unwind_details) end end # Filter's a state's possibilities to remove any that would not satisfy # the requirements in the conflict we've just rewound from # @param [UnwindDetails] unwind_details details of the conflict just unwound from # @return [void] def filter_possibilities_for_primary_unwind(unwind_details) unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index } unwinds_to_state << unwind_details unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements) state.possibilities.reject! do |possibility_set| possibility_set.possibilities.none? do |poss| unwind_requirement_sets.any? do |requirements| possibility_satisfies_requirements?(poss, requirements) end end end end # @param [Object] possibility a single possibility # @param [Array] requirements an array of requirements # @return [Boolean] whether the possibility satisfies all of the # given requirements def possibility_satisfies_requirements?(possibility, requirements) name = name_for(possibility) activated.tag(:swap) activated.set_payload(name, possibility) if activated.vertex_named(name) satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) } activated.rewind_to(:swap) satisfied end # Filter's a state's possibilities to remove any that would (eventually) # create a requirement in the conflict we've just rewound from # @param [UnwindDetails] unwind_details details of the conflict just unwound from # @return [void] def filter_possibilities_for_parent_unwind(unwind_details) unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index } unwinds_to_state << unwind_details primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq parent_unwinds = unwinds_to_state.uniq - primary_unwinds allowed_possibility_sets = primary_unwinds.flat_map do |unwind| states[unwind.state_index].possibilities.select do |possibility_set| possibility_set.possibilities.any? do |poss| possibility_satisfies_requirements?(poss, unwind.conflicting_requirements) end end end requirements_to_avoid = parent_unwinds.flat_map(&:sub_dependencies_to_avoid) state.possibilities.reject! do |possibility_set| !allowed_possibility_sets.include?(possibility_set) && (requirements_to_avoid - possibility_set.dependencies).empty? end end # @param [Conflict] conflict # @return [Array] minimal array of requirements that would cause the passed # conflict to occur. def binding_requirements_for_conflict(conflict) return [conflict.requirement] if conflict.possibility.nil? possible_binding_requirements = conflict.requirements.values.flatten(1).uniq # When there's a `CircularDependency` error the conflicting requirement # (the one causing the circular) won't be `conflict.requirement` # (which won't be for the right state, because we won't have created it, # because it's circular). # We need to make sure we have that requirement in the conflict's list, # otherwise we won't be able to unwind properly, so we just return all # the requirements for the conflict. return possible_binding_requirements if conflict.underlying_error possibilities = search_for(conflict.requirement) # If all the requirements together don't filter out all possibilities, # then the only two requirements we need to consider are the initial one # (where the dependency's version was first chosen) and the last if binding_requirement_in_set?(nil, possible_binding_requirements, possibilities) return [conflict.requirement, requirement_for_existing_name(name_for(conflict.requirement))].compact end # Loop through the possible binding requirements, removing each one # that doesn't bind. Use a `reverse_each` as we want the earliest set of # binding requirements, and don't use `reject!` as we wish to refine the # array *on each iteration*. binding_requirements = possible_binding_requirements.dup possible_binding_requirements.reverse_each do |req| next if req == conflict.requirement unless binding_requirement_in_set?(req, binding_requirements, possibilities) binding_requirements -= [req] end end binding_requirements end # @param [Object] requirement we wish to check # @param [Array] possible_binding_requirements array of requirements # @param [Array] possibilities array of possibilities the requirements will be used to filter # @return [Boolean] whether or not the given requirement is required to filter # out all elements of the array of possibilities. def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities) possibilities.any? do |poss| possibility_satisfies_requirements?(poss, possible_binding_requirements - [requirement]) end end # @param [Object] requirement # @return [Object] the requirement that led to `requirement` being added # to the list of requirements. def parent_of(requirement) return unless requirement return unless index = @parents_of[requirement].last return unless parent_state = @states[index] parent_state.requirement end # @param [String] name # @return [Object] the requirement that led to a version of a possibility # with the given name being activated. def requirement_for_existing_name(name) return nil unless vertex = activated.vertex_named(name) return nil unless vertex.payload states.find { |s| s.name == name }.requirement end # @param [Object] requirement # @return [ResolutionState] the state whose `requirement` is the given # `requirement`. def find_state_for(requirement) return nil unless requirement states.find { |i| requirement == i.requirement } end # @param [Object] underlying_error # @return [Conflict] a {Conflict} that reflects the failure to activate # the {#possibility} in conjunction with the current {#state} def create_conflict(underlying_error = nil) vertex = activated.vertex_named(name) locked_requirement = locked_requirement_named(name) requirements = {} unless vertex.explicit_requirements.empty? requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements end requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement vertex.incoming_edges.each do |edge| (requirements[edge.origin.payload.latest_version] ||= []).unshift(edge.requirement) end activated_by_name = {} activated.each { |v| activated_by_name[v.name] = v.payload.latest_version if v.payload } conflicts[name] = Conflict.new( requirement, requirements, vertex.payload && vertex.payload.latest_version, possibility, locked_requirement, requirement_trees, activated_by_name, underlying_error ) end # @return [Array>] The different requirement # trees that led to every requirement for the current spec. def requirement_trees vertex = activated.vertex_named(name) vertex.requirements.map { |r| requirement_tree_for(r) } end # @param [Object] requirement # @return [Array] the list of requirements that led to # `requirement` being required. def requirement_tree_for(requirement) tree = [] while requirement tree.unshift(requirement) requirement = parent_of(requirement) end tree end # Indicates progress roughly once every second # @return [void] def indicate_progress @iteration_counter += 1 @progress_rate ||= resolver_ui.progress_rate if iteration_rate.nil? if Time.now - started_at >= @progress_rate self.iteration_rate = @iteration_counter end end if iteration_rate && (@iteration_counter % iteration_rate) == 0 resolver_ui.indicate_progress end end # Calls the {#resolver_ui}'s {UI#debug} method # @param [Integer] depth the depth of the {#states} stack # @param [Proc] block a block that yields a {#to_s} # @return [void] def debug(depth = 0, &block) resolver_ui.debug(depth, &block) end # Attempts to activate the current {#possibility} # @return [void] def attempt_to_activate debug(depth) { 'Attempting to activate ' + possibility.to_s } existing_vertex = activated.vertex_named(name) if existing_vertex.payload debug(depth) { "Found existing spec (#{existing_vertex.payload})" } attempt_to_filter_existing_spec(existing_vertex) else latest = possibility.latest_version possibility.possibilities.select! do |possibility| requirement_satisfied_by?(requirement, activated, possibility) end if possibility.latest_version.nil? # ensure there's a possibility for better error messages possibility.possibilities << latest if latest create_conflict unwind_for_conflict else activate_new_spec end end end # Attempts to update the existing vertex's `PossibilitySet` with a filtered version # @return [void] def attempt_to_filter_existing_spec(vertex) filtered_set = filtered_possibility_set(vertex) if !filtered_set.possibilities.empty? activated.set_payload(name, filtered_set) new_requirements = requirements.dup push_state_for_requirements(new_requirements, false) else create_conflict debug(depth) { "Unsatisfied by existing spec (#{vertex.payload})" } unwind_for_conflict end end # Generates a filtered version of the existing vertex's `PossibilitySet` using the # current state's `requirement` # @param [Object] vertex existing vertex # @return [PossibilitySet] filtered possibility set def filtered_possibility_set(vertex) PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities) end # @param [String] requirement_name the spec name to search for # @return [Object] the locked spec named `requirement_name`, if one # is found on {#base} def locked_requirement_named(requirement_name) vertex = base.vertex_named(requirement_name) vertex && vertex.payload end # Add the current {#possibility} to the dependency graph of the current # {#state} # @return [void] def activate_new_spec conflicts.delete(name) debug(depth) { "Activated #{name} at #{possibility}" } activated.set_payload(name, possibility) require_nested_dependencies_for(possibility) end # Requires the dependencies that the recently activated spec has # @param [Object] possibility_set the PossibilitySet that has just been # activated # @return [void] def require_nested_dependencies_for(possibility_set) nested_dependencies = dependencies_for(possibility_set.latest_version) debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" } nested_dependencies.each do |d| activated.add_child_vertex(name_for(d), nil, [name_for(possibility_set.latest_version)], d) parent_index = states.size - 1 parents = @parents_of[d] parents << parent_index if parents.empty? end push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?) end # Pushes a new {DependencyState} that encapsulates both existing and new # requirements # @param [Array] new_requirements # @param [Boolean] requires_sort # @param [Object] new_activated # @return [void] def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated) new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort new_requirement = nil loop do new_requirement = new_requirements.shift break if new_requirement.nil? || states.none? { |s| s.requirement == new_requirement } end new_name = new_requirement ? name_for(new_requirement) : ''.freeze possibilities = possibilities_for_requirement(new_requirement) handle_missing_or_push_dependency_state DependencyState.new( new_name, new_requirements, new_activated, new_requirement, possibilities, depth, conflicts.dup, unused_unwind_options.dup ) end # Checks a proposed requirement with any existing locked requirement # before generating an array of possibilities for it. # @param [Object] requirement the proposed requirement # @param [Object] activated # @return [Array] possibilities def possibilities_for_requirement(requirement, activated = self.activated) return [] unless requirement if locked_requirement_named(name_for(requirement)) return locked_requirement_possibility_set(requirement, activated) end group_possibilities(search_for(requirement)) end # @param [Object] requirement the proposed requirement # @param [Object] activated # @return [Array] possibility set containing only the locked requirement, if any def locked_requirement_possibility_set(requirement, activated = self.activated) all_possibilities = search_for(requirement) locked_requirement = locked_requirement_named(name_for(requirement)) # Longwinded way to build a possibilities array with either the locked # requirement or nothing in it. Required, since the API for # locked_requirement isn't guaranteed. locked_possibilities = all_possibilities.select do |possibility| requirement_satisfied_by?(locked_requirement, activated, possibility) end group_possibilities(locked_possibilities) end # Build an array of PossibilitySets, with each element representing a group of # dependency versions that all have the same sub-dependency version constraints # and are contiguous. # @param [Array] possibilities an array of possibilities # @return [Array] an array of possibility sets def group_possibilities(possibilities) possibility_sets = [] current_possibility_set = nil possibilities.reverse_each do |possibility| dependencies = dependencies_for(possibility) if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies) current_possibility_set.possibilities.unshift(possibility) else possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility])) current_possibility_set = possibility_sets.first end end possibility_sets end # Pushes a new {DependencyState}. # If the {#specification_provider} says to # {SpecificationProvider#allow_missing?} that particular requirement, and # there are no possibilities for that requirement, then `state` is not # pushed, and the vertex in {#activated} is removed, and we continue # resolving the remaining requirements. # @param [DependencyState] state # @return [void] def handle_missing_or_push_dependency_state(state) if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement) state.activated.detach_vertex_named(state.name) push_state_for_requirements(state.requirements.dup, false, state.activated) else states.push(state).tap { activated.tag(state) } end end end end end PKu]."Ibundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rbnu[# frozen_string_literal: true module Bundler::Molinillo # The version of Bundler::Molinillo. VERSION = '0.7.0'.freeze end PKu]}X'bundler-2.2.24/lib/bundler/gem_tasks.rbnu[# frozen_string_literal: true require "rake/clean" CLOBBER.include "pkg" require_relative "gem_helper" Bundler::GemHelper.install_tasks PKu] D##)bundler-2.2.24/lib/bundler/source/path.rbnu[# frozen_string_literal: true module Bundler class Source class Path < Source autoload :Installer, File.expand_path("path/installer", __dir__) attr_reader :path, :options, :root_path, :original_path attr_writer :name attr_accessor :version protected :original_path DEFAULT_GLOB = "{,*,*/*}.gemspec".freeze def initialize(options) @options = options.dup @glob = options["glob"] || DEFAULT_GLOB @allow_cached = false @allow_remote = false @root_path = options["root_path"] || root if options["path"] @path = Pathname.new(options["path"]) expanded_path = expand(@path) @path = if @path.relative? expanded_path.relative_path_from(root_path.expand_path) else expanded_path end end @name = options["name"] @version = options["version"] # Stores the original path. If at any point we move to the # cached directory, we still have the original path to copy from. @original_path = @path end def remote! @local_specs = nil @allow_remote = true end def cached! @local_specs = nil @allow_cached = true end def self.from_lock(options) new(options.merge("path" => options.delete("remote"))) end def to_lock out = String.new("PATH\n") out << " remote: #{lockfile_path}\n" out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB out << " specs:\n" end def to_s "source at `#{@path}`" end def hash [self.class, expanded_path, version].hash end def eql?(other) return unless other.class == self.class expanded_original_path == other.expanded_original_path && version == other.version end alias_method :==, :eql? def name File.basename(expanded_path.to_s) end def install(spec, options = {}) using_message = "Using #{version_message(spec)} from #{self}" using_message += " and installing its executables" unless spec.executables.empty? print_using_message using_message generate_bin(spec, :disable_extensions => true) nil # no post-install message end def cache(spec, custom_path = nil) app_cache_path = app_cache_path(custom_path) return unless Bundler.feature_flag.cache_all? return if expand(@original_path).to_s.index(root_path.to_s + "/") == 0 unless @original_path.exist? raise GemNotFound, "Can't cache gem #{version_message(spec)} because #{self} is missing!" end FileUtils.rm_rf(app_cache_path) FileUtils.cp_r("#{@original_path}/.", app_cache_path) FileUtils.touch(app_cache_path.join(".bundlecache")) end def local_specs(*) @local_specs ||= load_spec_files end def specs if has_app_cache? @path = app_cache_path @expanded_path = nil # Invalidate end local_specs end def app_cache_dirname name end def root Bundler.root end def expanded_original_path @expanded_original_path ||= expand(original_path) end private def expanded_path @expanded_path ||= expand(path) end def expand(somepath) if Bundler.current_ruby.jruby? # TODO: Unify when https://github.com/rubygems/bundler/issues/7598 fixed upstream and all supported jrubies include the fix somepath.expand_path(root_path).expand_path else somepath.expand_path(root_path) end rescue ArgumentError => e Bundler.ui.debug(e) raise PathError, "There was an error while trying to use the path " \ "`#{somepath}`.\nThe error message was: #{e.message}." end def lockfile_path return relative_path(original_path) if original_path.absolute? expand(original_path).relative_path_from(root) end def app_cache_path(custom_path = nil) @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) end def has_app_cache? SharedHelpers.in_bundle? && app_cache_path.exist? end def load_gemspec(file) return unless spec = Bundler.load_gemspec(file) Bundler.rubygems.set_installed_by_version(spec) spec end def validate_spec(spec) Bundler.rubygems.validate(spec) end def load_spec_files index = Index.new if File.directory?(expanded_path) # We sort depth-first since `<<` will override the earlier-found specs Gem::Util.glob_files_in_dir(@glob, expanded_path).sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file| next unless spec = load_gemspec(file) spec.source = self # Validation causes extension_dir to be calculated, which depends # on #source, so we validate here instead of load_gemspec validate_spec(spec) index << spec end if index.empty? && @name && @version index << Gem::Specification.new do |s| s.name = @name s.source = self s.version = Gem::Version.new(@version) s.platform = Gem::Platform::RUBY s.summary = "Fake gemspec for #{@name}" s.relative_loaded_from = "#{@name}.gemspec" s.authors = ["no one"] if expanded_path.join("bin").exist? executables = expanded_path.join("bin").children executables.reject! {|p| File.directory?(p) } s.executables = executables.map {|c| c.basename.to_s } end end end else message = String.new("The path `#{expanded_path}` ") message << if File.exist?(expanded_path) "is not a directory." else "does not exist." end raise PathError, message end index end def relative_path(path = self.path) if path.to_s.start_with?(root_path.to_s) return path.relative_path_from(root_path) end path end def generate_bin(spec, options = {}) gem_dir = Pathname.new(spec.full_gem_path) # Some gem authors put absolute paths in their gemspec # and we have to save them from themselves spec.files = spec.files.map do |p| next p unless p =~ /\A#{Pathname::SEPARATOR_PAT}/ next if File.directory?(p) begin Pathname.new(p).relative_path_from(gem_dir).to_s rescue ArgumentError p end end.compact installer = Path::Installer.new( spec, :env_shebang => false, :disable_extensions => options[:disable_extensions], :build_args => options[:build_args], :bundler_extension_cache_path => extension_cache_path(spec) ) installer.post_install rescue Gem::InvalidSpecificationException => e Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \ "This prevents bundler from installing bins or native extensions, but " \ "that may not affect its functionality." if !spec.extensions.empty? && !spec.email.empty? Bundler.ui.warn "If you need to use this package without installing it from a gem " \ "repository, please contact #{spec.email} and ask them " \ "to modify their .gemspec so it can work with `gem build`." end Bundler.ui.warn "The validation message from RubyGems was:\n #{e.message}" end end end end PKu]uR!xx3bundler-2.2.24/lib/bundler/source/path/installer.rbnu[# frozen_string_literal: true require_relative "../../rubygems_gem_installer" module Bundler class Source class Path class Installer < Bundler::RubyGemsGemInstaller attr_reader :spec def initialize(spec, options = {}) @options = options @spec = spec @gem_dir = Bundler.rubygems.path(spec.full_gem_path) @wrappers = true @env_shebang = true @format_executable = options[:format_executable] || false @build_args = options[:build_args] || Bundler.rubygems.build_args @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin" @disable_extensions = options[:disable_extensions] if Bundler.requires_sudo? @tmp_dir = Bundler.tmp(spec.full_name).to_s @bin_dir = "#{@tmp_dir}/bin" else @bin_dir = @gem_bin_dir end end def post_install run_hooks(:pre_install) unless @disable_extensions build_extensions run_hooks(:post_build) end generate_bin unless spec.executables.empty? run_hooks(:post_install) ensure Bundler.rm_rf(@tmp_dir) if Bundler.requires_sudo? end private def generate_bin super if Bundler.requires_sudo? SharedHelpers.filesystem_access(@gem_bin_dir) do |p| Bundler.mkdir_p(p) end spec.executables.each do |exe| Bundler.sudo "cp -R #{@bin_dir}/#{exe} #{@gem_bin_dir}" end end end def run_hooks(type) hooks_meth = "#{type}_hooks" return unless Gem.respond_to?(hooks_meth) Gem.send(hooks_meth).each do |hook| result = hook.call(self) next unless result == false location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/ message = "#{type} hook#{location} failed for #{spec.full_name}" raise InstallHookError, message end end end end end end PKu].۬-bundler-2.2.24/lib/bundler/source/metadata.rbnu[# frozen_string_literal: true module Bundler class Source class Metadata < Source def specs @specs ||= Index.build do |idx| idx << Gem::Specification.new("Ruby\0", RubyVersion.system.to_gem_version_with_patchlevel) idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s| s.required_rubygems_version = Gem::Requirement.default end idx << Gem::Specification.new do |s| s.name = "bundler" s.version = VERSION s.license = "MIT" s.platform = Gem::Platform::RUBY s.source = self s.authors = ["bundler team"] s.bindir = "exe" s.homepage = "https://bundler.io" s.summary = "The best way to manage your application's dependencies" s.executables = %w[bundle] # can't point to the actual gemspec or else the require paths will be wrong s.loaded_from = File.expand_path("..", __FILE__) end if local_spec = Bundler.rubygems.find_name("bundler").find {|s| s.version.to_s == VERSION } idx << local_spec end idx.each {|s| s.source = self } end end def options {} end def install(spec, _opts = {}) print_using_message "Using #{version_message(spec)}" nil end def to_s "the local ruby installation" end def ==(other) self.class == other.class end alias_method :eql?, :== def hash self.class.hash end def version_message(spec) "#{spec.name} #{spec.version}" end end end end PKu]gYGG-bundler-2.2.24/lib/bundler/source/rubygems.rbnu[# frozen_string_literal: true require "rubygems/user_interaction" module Bundler class Source class Rubygems < Source autoload :Remote, File.expand_path("rubygems/remote", __dir__) # Use the API when installing less than X gems API_REQUEST_LIMIT = 500 # Ask for X gems per API request API_REQUEST_SIZE = 50 attr_reader :remotes, :caches def initialize(options = {}) @options = options @remotes = [] @dependency_names = [] @allow_remote = false @allow_cached = false @allow_local = options["allow_local"] || false @caches = [cache_path, *Bundler.rubygems.gem_cache] Array(options["remotes"]).reverse_each {|r| add_remote(r) } end def local_only! @specs = nil @allow_local = true @allow_remote = false end def local! return if @allow_local @specs = nil @allow_local = true end def remote! return if @allow_remote @specs = nil @allow_remote = true end def cached! return if @allow_cached @specs = nil @allow_cached = true end def hash @remotes.hash end def eql?(other) other.is_a?(Rubygems) && other.credless_remotes == credless_remotes end alias_method :==, :eql? def include?(o) o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty? end def multiple_remotes? @remotes.size > 1 end def can_lock?(spec) return super unless multiple_remotes? include?(spec.source) end def options { "remotes" => @remotes.map(&:to_s) } end def self.from_lock(options) new(options) end def to_lock out = String.new("GEM\n") remotes.reverse_each do |remote| out << " remote: #{suppress_configured_credentials remote}\n" end out << " specs:\n" end def to_s if remotes.empty? "locally installed gems" else remote_names = remotes.map(&:to_s).join(", ") "rubygems repository #{remote_names} or installed locally" end end alias_method :name, :to_s def specs @specs ||= begin # remote_specs usually generates a way larger Index than the other # sources, and large_idx.use small_idx is way faster than # small_idx.use large_idx. idx = @allow_remote ? remote_specs.dup : Index.new idx.use(cached_specs, :override_dupes) if @allow_cached || @allow_remote idx.use(installed_specs, :override_dupes) if @allow_local idx end end def install(spec, opts = {}) force = opts[:force] ensure_builtin_gems_cached = opts[:ensure_builtin_gems_cached] if ensure_builtin_gems_cached && builtin_gem?(spec) if !cached_path(spec) cached_built_in_gem(spec) unless spec.remote force = true else spec.loaded_from = loaded_from(spec) end end if (installed?(spec) || Plugin.installed?(spec.name)) && !force print_using_message "Using #{version_message(spec)}" return nil # no post-install message end # Download the gem to get the spec, because some specs that are returned # by rubygems.org are broken and wrong. if spec.remote # Check for this spec from other sources uris = [spec.remote.anonymized_uri] uris += remotes_for_spec(spec).map(&:anonymized_uri) uris.uniq! Installer.ambiguous_gems << [spec.name, *uris] if uris.length > 1 path = fetch_gem(spec) begin s = Bundler.rubygems.spec_from_gem(path, Bundler.settings["trust-policy"]) spec.__swap__(s) rescue StandardError Bundler.rm_rf(path) raise end end unless Bundler.settings[:no_install] message = "Installing #{version_message(spec)}" message += " with native extensions" if spec.extensions.any? Bundler.ui.confirm message path = cached_gem(spec) if requires_sudo? install_path = Bundler.tmp(spec.full_name) bin_path = install_path.join("bin") else install_path = rubygems_dir bin_path = Bundler.system_bindir end Bundler.mkdir_p bin_path, :no_sudo => true unless spec.executables.empty? || Bundler.rubygems.provides?(">= 2.7.5") require_relative "../rubygems_gem_installer" installed_spec = Bundler::RubyGemsGemInstaller.at( path, :install_dir => install_path.to_s, :bin_dir => bin_path.to_s, :ignore_dependencies => true, :wrappers => true, :env_shebang => true, :build_args => opts[:build_args], :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum, :bundler_extension_cache_path => extension_cache_path(spec) ).install spec.full_gem_path = installed_spec.full_gem_path # SUDO HAX if requires_sudo? Bundler.rubygems.repository_subdirectories.each do |name| src = File.join(install_path, name, "*") dst = File.join(rubygems_dir, name) if name == "extensions" && Dir.glob(src).any? src = File.join(src, "*/*") ext_src = Dir.glob(src).first ext_src.gsub!(src[0..-6], "") dst = File.dirname(File.join(dst, ext_src)) end SharedHelpers.filesystem_access(dst) do |p| Bundler.mkdir_p(p) end Bundler.sudo "cp -R #{src} #{dst}" if Dir[src].any? end spec.executables.each do |exe| SharedHelpers.filesystem_access(Bundler.system_bindir) do |p| Bundler.mkdir_p(p) end Bundler.sudo "cp -R #{install_path}/bin/#{exe} #{Bundler.system_bindir}/" end end installed_spec.loaded_from = loaded_from(spec) end spec.loaded_from = loaded_from(spec) spec.post_install_message ensure Bundler.rm_rf(install_path) if requires_sudo? end def cache(spec, custom_path = nil) if builtin_gem?(spec) cached_path = cached_built_in_gem(spec) else cached_path = cached_gem(spec) end raise GemNotFound, "Missing gem file '#{spec.full_name}.gem'." unless cached_path return if File.dirname(cached_path) == Bundler.app_cache.to_s Bundler.ui.info " * #{File.basename(cached_path)}" FileUtils.cp(cached_path, Bundler.app_cache(custom_path)) rescue Errno::EACCES => e Bundler.ui.debug(e) raise InstallError, e.message end def cached_built_in_gem(spec) cached_path = cached_path(spec) if cached_path.nil? remote_spec = remote_specs.search(spec).first if remote_spec cached_path = fetch_gem(remote_spec) else Bundler.ui.warn "#{spec.full_name} is built in to Ruby, and can't be cached because your Gemfile doesn't have any sources that contain it." end end cached_path end def add_remote(source) uri = normalize_uri(source) @remotes.unshift(uri) unless @remotes.include?(uri) end def equivalent_remotes?(other_remotes) other_remotes.map(&method(:remove_auth)) == @remotes.map(&method(:remove_auth)) end def spec_names if @allow_remote && dependency_api_available? remote_specs.spec_names else [] end end def unmet_deps if @allow_remote && dependency_api_available? remote_specs.unmet_dependency_names else [] end end def fetchers @fetchers ||= remotes.map do |uri| remote = Source::Rubygems::Remote.new(uri) Bundler::Fetcher.new(remote) end end def double_check_for(unmet_dependency_names) return unless @allow_remote return unless dependency_api_available? unmet_dependency_names = unmet_dependency_names.call unless unmet_dependency_names.nil? if api_fetchers.size <= 1 # can't do this when there are multiple fetchers because then we might not fetch from _all_ # of them unmet_dependency_names -= remote_specs.spec_names # avoid re-fetching things we've already gotten end return if unmet_dependency_names.empty? end Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}" fetch_names(api_fetchers, unmet_dependency_names, specs, false) end def dependency_names_to_double_check names = [] remote_specs.each do |spec| case spec when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification names.concat(spec.runtime_dependencies.map(&:name)) when RemoteSpecification # from the full index return nil else raise "unhandled spec type (#{spec.inspect})" end end names end def dependency_api_available? api_fetchers.any? end protected def credless_remotes remotes.map(&method(:suppress_configured_credentials)) end def remotes_for_spec(spec) specs.search_all(spec.name).inject([]) do |uris, s| uris << s.remote if s.remote uris end end def loaded_from(spec) "#{rubygems_dir}/specifications/#{spec.full_name}.gemspec" end def cached_gem(spec) cached_gem = cached_path(spec) unless cached_gem raise Bundler::GemNotFound, "Could not find #{spec.file_name} for installation" end cached_gem end def cached_path(spec) possibilities = @caches.map {|p| "#{p}/#{spec.file_name}" } possibilities.find {|p| File.exist?(p) } end def normalize_uri(uri) uri = uri.to_s uri = "#{uri}/" unless uri =~ %r{/$} require_relative "../vendored_uri" uri = Bundler::URI(uri) raise ArgumentError, "The source must be an absolute URI. For example:\n" \ "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(Bundler::URI::HTTP) && uri.host.nil?) uri end def suppress_configured_credentials(remote) remote_nouser = remove_auth(remote) if remote.userinfo && remote.userinfo == Bundler.settings[remote_nouser] remote_nouser else remote end end def remove_auth(remote) if remote.user || remote.password remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s else remote.to_s end end def installed_specs @installed_specs ||= Index.build do |idx| Bundler.rubygems.all_specs.reverse_each do |spec| spec.source = self if Bundler.rubygems.spec_missing_extensions?(spec, false) Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions" next end idx << spec end end end def cached_specs @cached_specs ||= begin idx = @allow_local ? installed_specs.dup : Index.new Dir["#{cache_path}/*.gem"].each do |gemfile| next if gemfile =~ /^bundler\-[\d\.]+?\.gem/ s ||= Bundler.rubygems.spec_from_gem(gemfile) s.source = self idx << s end idx end end def api_fetchers fetchers.select {|f| f.use_api && f.fetchers.first.api_fetcher? } end def remote_specs @remote_specs ||= Index.build do |idx| index_fetchers = fetchers - api_fetchers # gather lists from non-api sites fetch_names(index_fetchers, nil, idx, false) # because ensuring we have all the gems we need involves downloading # the gemspecs of those gems, if the non-api sites contain more than # about 500 gems, we treat all sites as non-api for speed. allow_api = idx.size < API_REQUEST_LIMIT && dependency_names.size < API_REQUEST_LIMIT Bundler.ui.debug "Need to query more than #{API_REQUEST_LIMIT} gems." \ " Downloading full index instead..." unless allow_api fetch_names(api_fetchers, allow_api && dependency_names, idx, false) end end def fetch_names(fetchers, dependency_names, index, override_dupes) fetchers.each do |f| if dependency_names Bundler.ui.info "Fetching gem metadata from #{URICredentialsFilter.credential_filtered_uri(f.uri)}", Bundler.ui.debug? index.use f.specs_with_retry(dependency_names, self), override_dupes Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over else Bundler.ui.info "Fetching source index from #{URICredentialsFilter.credential_filtered_uri(f.uri)}" index.use f.specs_with_retry(nil, self), override_dupes end end end def fetch_gem(spec) return false unless spec.remote spec.fetch_platform download_path = requires_sudo? ? Bundler.tmp(spec.full_name) : rubygems_dir gem_path = "#{rubygems_dir}/cache/#{spec.full_name}.gem" SharedHelpers.filesystem_access("#{download_path}/cache") do |p| FileUtils.mkdir_p(p) end download_gem(spec, download_path) if requires_sudo? SharedHelpers.filesystem_access("#{rubygems_dir}/cache") do |p| Bundler.mkdir_p(p) end Bundler.sudo "mv #{download_path}/cache/#{spec.full_name}.gem #{gem_path}" end gem_path ensure Bundler.rm_rf(download_path) if requires_sudo? end def builtin_gem?(spec) # Ruby 2.1, where all included gems have this summary return true if spec.summary =~ /is bundled with Ruby/ # Ruby 2.0, where gemspecs are stored in specifications/default/ spec.loaded_from && spec.loaded_from.include?("specifications/default/") end def installed?(spec) installed_specs[spec].any? end def requires_sudo? Bundler.requires_sudo? end def rubygems_dir Bundler.rubygems.gem_dir end def cache_path Bundler.app_cache end private # Checks if the requested spec exists in the global cache. If it does, # we copy it to the download path, and if it does not, we download it. # # @param [Specification] spec # the spec we want to download or retrieve from the cache. # # @param [String] download_path # the local directory the .gem will end up in. # def download_gem(spec, download_path) local_path = File.join(download_path, "cache/#{spec.full_name}.gem") if (cache_path = download_cache_path(spec)) && cache_path.file? SharedHelpers.filesystem_access(local_path) do FileUtils.cp(cache_path, local_path) end else uri = spec.remote.uri Bundler.ui.confirm("Fetching #{version_message(spec)}") rubygems_local_path = Bundler.rubygems.download_gem(spec, uri, download_path) # older rubygems return varying file:// variants depending on version rubygems_local_path = rubygems_local_path.gsub(/\Afile:/, "") unless Bundler.rubygems.provides?(">= 3.2.0.rc.2") rubygems_local_path = rubygems_local_path.gsub(%r{\A//}, "") if Bundler.rubygems.provides?("< 3.1.0") if rubygems_local_path != local_path SharedHelpers.filesystem_access(local_path) do FileUtils.mv(rubygems_local_path, local_path) end end cache_globally(spec, local_path) end end # Checks if the requested spec exists in the global cache. If it does # not, we create the relevant global cache subdirectory if it does not # exist and copy the spec from the local cache to the global cache. # # @param [Specification] spec # the spec we want to copy to the global cache. # # @param [String] local_cache_path # the local directory from which we want to copy the .gem. # def cache_globally(spec, local_cache_path) return unless cache_path = download_cache_path(spec) return if cache_path.exist? SharedHelpers.filesystem_access(cache_path.dirname, &:mkpath) SharedHelpers.filesystem_access(cache_path) do FileUtils.cp(local_cache_path, cache_path) end end # Returns the global cache path of the calling Rubygems::Source object. # # Note that the Source determines the path's subdirectory. We use this # subdirectory in the global cache path so that gems with the same name # -- and possibly different versions -- from different sources are saved # to their respective subdirectories and do not override one another. # # @param [Gem::Specification] specification # # @return [Pathname] The global cache path. # def download_cache_path(spec) return unless Bundler.feature_flag.global_gem_cache? return unless remote = spec.remote return unless cache_slug = remote.cache_slug Bundler.user_cache.join("gems", cache_slug, spec.file_name) end def extension_cache_slug(spec) return unless remote = spec.remote remote.cache_slug end end end end PKu]:U''4bundler-2.2.24/lib/bundler/source/rubygems/remote.rbnu[# frozen_string_literal: true module Bundler class Source class Rubygems class Remote attr_reader :uri, :anonymized_uri, :original_uri def initialize(uri) orig_uri = uri uri = Bundler.settings.mirror_for(uri) @original_uri = orig_uri if orig_uri != uri fallback_auth = Bundler.settings.credentials_for(uri) @uri = apply_auth(uri, fallback_auth).freeze @anonymized_uri = remove_auth(@uri).freeze end # @return [String] A slug suitable for use as a cache key for this # remote. # def cache_slug @cache_slug ||= begin return nil unless SharedHelpers.md5_available? cache_uri = original_uri || uri host = cache_uri.to_s.start_with?("file://") ? nil : cache_uri.host uri_parts = [host, cache_uri.user, cache_uri.port, cache_uri.path] uri_digest = SharedHelpers.digest(:MD5).hexdigest(uri_parts.compact.join(".")) uri_parts[-1] = uri_digest uri_parts.compact.join(".") end end def to_s "rubygems remote at #{anonymized_uri}" end private def apply_auth(uri, auth) if auth && uri.userinfo.nil? uri = uri.dup uri.userinfo = auth end uri rescue Bundler::URI::InvalidComponentError error_message = "Please CGI escape your usernames and passwords before " \ "setting them for authentication." raise HTTPError.new(error_message) end def remove_auth(uri) if uri.userinfo uri = uri.dup uri.user = uri.password = nil end uri end end end end end PKu]ƨ',bundler-2.2.24/lib/bundler/source/gemspec.rbnu[# frozen_string_literal: true module Bundler class Source class Gemspec < Path attr_reader :gemspec def initialize(options) super @gemspec = options["gemspec"] end def as_path_source Path.new(options) end end end end PKu] E//7bundler-2.2.24/lib/bundler/source/rubygems_aggregate.rbnu[# frozen_string_literal: true module Bundler class Source class RubygemsAggregate attr_reader :source_map, :sources def initialize(sources, source_map) @sources = sources @source_map = source_map @index = build_index end def specs @index end def to_s "any of the sources" end private def build_index Index.build do |idx| dependency_names = source_map.pinned_spec_names sources.all_sources.each do |source| source.dependency_names = dependency_names - source_map.pinned_spec_names(source) idx.add_source source.specs dependency_names.concat(source.unmet_deps).uniq! end double_check_for_index(idx, dependency_names) end end # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both # sources A and B. At this point, the API request will have found all the versions of Bar in source A, # but will not have found any versions of Bar from source B, which is a problem if the requested version # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for # each spec we found, we add all possible versions from all sources to the index. def double_check_for_index(idx, dependency_names) pinned_names = source_map.pinned_spec_names names = :names # do this so we only have to traverse to get dependency_names from the index once unmet_dependency_names = lambda do return names unless names == :names new_names = sources.all_sources.map(&:dependency_names_to_double_check) return names = nil if new_names.compact! names = new_names.flatten(1).concat(dependency_names) names.uniq! names -= pinned_names names end sources.all_sources.each do |source| source.double_check_for(unmet_dependency_names) end end end end end PKu]Ƌ}(}((bundler-2.2.24/lib/bundler/source/git.rbnu[# frozen_string_literal: true require_relative "../vendored_fileutils" module Bundler class Source class Git < Path autoload :GitProxy, File.expand_path("git/git_proxy", __dir__) attr_reader :uri, :ref, :branch, :options, :glob, :submodules def initialize(options) @options = options @glob = options["glob"] || DEFAULT_GLOB @allow_cached = false @allow_remote = false # Stringify options that could be set as symbols %w[ref branch tag revision].each {|k| options[k] = options[k].to_s if options[k] } @uri = options["uri"] || "" @safe_uri = URICredentialsFilter.credential_filtered_uri(@uri) @branch = options["branch"] @ref = options["ref"] || options["branch"] || options["tag"] @submodules = options["submodules"] @name = options["name"] @version = options["version"].to_s.strip.gsub("-", ".pre.") @copied = false @local = false end def self.from_lock(options) new(options.merge("uri" => options.delete("remote"))) end def to_lock out = String.new("GIT\n") out << " remote: #{@uri}\n" out << " revision: #{revision}\n" %w[ref branch tag submodules].each do |opt| out << " #{opt}: #{options[opt]}\n" if options[opt] end out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB out << " specs:\n" end def hash [self.class, uri, ref, branch, name, version, glob, submodules].hash end def eql?(other) other.is_a?(Git) && uri == other.uri && ref == other.ref && branch == other.branch && name == other.name && version == other.version && glob == other.glob && submodules == other.submodules end alias_method :==, :eql? def to_s begin at = if local? path elsif user_ref = options["ref"] if ref =~ /\A[a-z0-9]{4,}\z/i shortref_for_display(user_ref) else user_ref end elsif ref ref else git_proxy.branch end rev = " (at #{at}@#{shortref_for_display(revision)})" rescue GitError "" end "#{@safe_uri}#{rev}" end def name File.basename(@uri, ".git") end # This is the path which is going to contain a specific # checkout of the git repository. When using local git # repos, this is set to the local repo. def install_path @install_path ||= begin git_scope = "#{base_name}-#{shortref_for_path(revision)}" path = Bundler.install_path.join(git_scope) if !path.exist? && Bundler.requires_sudo? Bundler.user_bundle_path.join(Bundler.ruby_scope).join(git_scope) else path end end end alias_method :path, :install_path def extension_dir_name "#{base_name}-#{shortref_for_path(revision)}" end def unlock! git_proxy.revision = nil options["revision"] = nil @unlocked = true end def local_override!(path) return false if local? original_path = path path = Pathname.new(path) path = path.expand_path(Bundler.root) unless path.relative? unless options["branch"] || Bundler.settings[:disable_local_branch_check] raise GitError, "Cannot use local override for #{name} at #{path} because " \ ":branch is not specified in Gemfile. Specify a branch or run " \ "`bundle config unset local.#{override_for(original_path)}` to remove the local override" end unless path.exist? raise GitError, "Cannot use local override for #{name} because #{path} " \ "does not exist. Run `bundle config unset local.#{override_for(original_path)}` to remove the local override" end set_local!(path) # Create a new git proxy without the cached revision # so the Gemfile.lock always picks up the new revision. @git_proxy = GitProxy.new(path, uri, ref) if git_proxy.branch != options["branch"] && !Bundler.settings[:disable_local_branch_check] raise GitError, "Local override for #{name} at #{path} is using branch " \ "#{git_proxy.branch} but Gemfile specifies #{options["branch"]}" end changed = cached_revision && cached_revision != git_proxy.revision if !Bundler.settings[:disable_local_revision_check] && changed && !@unlocked && !git_proxy.contains?(cached_revision) raise GitError, "The Gemfile lock is pointing to revision #{shortref_for_display(cached_revision)} " \ "but the current branch in your local override for #{name} does not contain such commit. " \ "Please make sure your branch is up to date." end changed end def specs(*) set_local!(app_cache_path) if has_app_cache? && !local? if requires_checkout? && !@copied fetch git_proxy.copy_to(install_path, submodules) serialize_gemspecs_in(install_path) @copied = true end local_specs end def install(spec, options = {}) force = options[:force] print_using_message "Using #{version_message(spec)} from #{self}" if (requires_checkout? && !@copied) || force Bundler.ui.debug " * Checking out revision: #{ref}" git_proxy.copy_to(install_path, submodules) serialize_gemspecs_in(install_path) @copied = true end generate_bin_options = { :disable_extensions => !Bundler.rubygems.spec_missing_extensions?(spec), :build_args => options[:build_args] } generate_bin(spec, generate_bin_options) requires_checkout? ? spec.post_install_message : nil end def cache(spec, custom_path = nil) app_cache_path = app_cache_path(custom_path) return unless Bundler.feature_flag.cache_all? return if path == app_cache_path cached! FileUtils.rm_rf(app_cache_path) git_proxy.checkout if requires_checkout? git_proxy.copy_to(app_cache_path, @submodules) serialize_gemspecs_in(app_cache_path) end def load_spec_files super rescue PathError => e Bundler.ui.trace e raise GitError, "#{self} is not yet checked out. Run `bundle install` first." end # This is the path which is going to contain a cache # of the git repository. When using the same git repository # across different projects, this cache will be shared. # When using local git repos, this is set to the local repo. def cache_path @cache_path ||= begin if Bundler.requires_sudo? || Bundler.feature_flag.global_gem_cache? Bundler.user_cache else Bundler.bundle_path.join("cache", "bundler") end.join("git", git_scope) end end def app_cache_dirname "#{base_name}-#{shortref_for_path(cached_revision || revision)}" end def revision git_proxy.revision end def allow_git_ops? @allow_remote || @allow_cached end def local? @local end private def serialize_gemspecs_in(destination) destination = destination.expand_path(Bundler.root) if destination.relative? Dir["#{destination}/#{@glob}"].each do |spec_path| # Evaluate gemspecs and cache the result. Gemspecs # in git might require git or other dependencies. # The gemspecs we cache should already be evaluated. spec = Bundler.load_gemspec(spec_path) next unless spec Bundler.rubygems.set_installed_by_version(spec) Bundler.rubygems.validate(spec) File.open(spec_path, "wb") {|file| file.write(spec.to_ruby) } end end def set_local!(path) @local = true @local_specs = @git_proxy = nil @cache_path = @install_path = path end def has_app_cache? cached_revision && super end def requires_checkout? allow_git_ops? && !local? && !cached_revision_checked_out? end def cached_revision_checked_out? cached_revision && cached_revision == revision && install_path.exist? end def base_name File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)?(//\w*/)?(\w*/)*}, ""), ".git") end def shortref_for_display(ref) ref[0..6] end def shortref_for_path(ref) ref[0..11] end def uri_hash if uri =~ %r{^\w+://(\w+@)?} # Downcase the domain component of the URI # and strip off a trailing slash, if one is present input = Bundler::URI.parse(uri).normalize.to_s.sub(%r{/$}, "") else # If there is no URI scheme, assume it is an ssh/git URI input = uri end SharedHelpers.digest(:SHA1).hexdigest(input) end def cached_revision options["revision"] end def cached? cache_path.exist? end def git_proxy @git_proxy ||= GitProxy.new(cache_path, uri, ref, cached_revision, self) end def fetch git_proxy.checkout rescue GitError => e raise unless Bundler.feature_flag.allow_offline_install? Bundler.ui.warn "Using cached git data because of network errors:\n#{e}" end # no-op, since we validate when re-serializing the gemspec def validate_spec(_spec); end def load_gemspec(file) stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent) stub.full_gem_path = Pathname.new(file).dirname.expand_path(root).to_s.tap{|x| x.untaint if RUBY_VERSION < "2.7" } StubSpecification.from_stub(stub) end def git_scope "#{base_name}-#{uri_hash}" end def extension_cache_slug(_) extension_dir_name end def override_for(path) Bundler.settings.local_overrides.key(path) end end end end PKu])g@##2bundler-2.2.24/lib/bundler/source/git/git_proxy.rbnu[# frozen_string_literal: true require "shellwords" module Bundler class Source class Git class GitNotInstalledError < GitError def initialize msg = String.new msg << "You need to install git to be able to use gems from git repositories. " msg << "For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git" super msg end end class GitNotAllowedError < GitError def initialize(command) msg = String.new msg << "Bundler is trying to run `#{command}` at runtime. You probably need to run `bundle install`. However, " msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md " msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}" super msg end end class GitCommandError < GitError attr_reader :command def initialize(command, path, extra_info = nil) @command = command msg = String.new msg << "Git error: command `#{command}` in directory #{path} has failed." msg << "\n#{extra_info}" if extra_info msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if path.exist? super msg end end class MissingGitRevisionError < GitCommandError def initialize(command, destination_path, ref, repo) msg = "Revision #{ref} does not exist in the repository #{repo}. Maybe you misspelled it?" super command, destination_path, msg end end # The GitProxy is responsible to interact with git repositories. # All actions required by the Git source is encapsulated in this # object. class GitProxy attr_accessor :path, :uri, :ref attr_writer :revision def initialize(path, uri, ref, revision = nil, git = nil) @path = path @uri = uri @ref = ref @revision = revision @git = git raise GitNotInstalledError.new if allow? && !Bundler.git_present? end def revision @revision ||= find_local_revision end def branch @branch ||= allowed_with_path do git("rev-parse", "--abbrev-ref", "HEAD", :dir => path).strip end end def contains?(commit) allowed_with_path do result, status = git_null("branch", "--contains", commit, :dir => path) status.success? && result =~ /^\* (.*)$/ end end def version git("--version").match(/(git version\s*)?((\.?\d+)+).*/)[2] end def full_version git("--version").sub("git version", "").strip end def checkout return if path.exist? && has_revision_cached? extra_ref = "#{ref}:#{ref}" if ref && ref.start_with?("refs/") Bundler.ui.info "Fetching #{URICredentialsFilter.credential_filtered_uri(uri)}" configured_uri = configured_uri_for(uri).to_s unless path.exist? SharedHelpers.filesystem_access(path.dirname) do |p| FileUtils.mkdir_p(p) end git_retry "clone", configured_uri, path.to_s, "--bare", "--no-hardlinks", "--quiet" return unless extra_ref end with_path do git_retry(*["fetch", "--force", "--quiet", "--tags", configured_uri, "refs/heads/*:refs/heads/*", extra_ref].compact, :dir => path) end end def copy_to(destination, submodules = false) # method 1 unless File.exist?(destination.join(".git")) begin SharedHelpers.filesystem_access(destination.dirname) do |p| FileUtils.mkdir_p(p) end SharedHelpers.filesystem_access(destination) do |p| FileUtils.rm_rf(p) end git_retry "clone", "--no-checkout", "--quiet", path.to_s, destination.to_s File.chmod(((File.stat(destination).mode | 0o777) & ~File.umask), destination) rescue Errno::EEXIST => e file_path = e.message[%r{.*?((?:[a-zA-Z]:)?/.*)}, 1] raise GitError, "Bundler could not install a gem because it needs to " \ "create a directory, but a file exists - #{file_path}. Please delete " \ "this file and try again." end end # method 2 git_retry "fetch", "--force", "--quiet", "--tags", path.to_s, :dir => destination begin git "reset", "--hard", @revision, :dir => destination rescue GitCommandError => e raise MissingGitRevisionError.new(e.command, destination, @revision, URICredentialsFilter.credential_filtered_uri(uri)) end if submodules git_retry "submodule", "update", "--init", "--recursive", :dir => destination elsif Gem::Version.create(version) >= Gem::Version.create("2.9.0") inner_command = "git -C $toplevel submodule deinit --force $sm_path" git_retry "submodule", "foreach", "--quiet", inner_command, :dir => destination end end private def git_null(*command, dir: nil) check_allowed(command) out, status = SharedHelpers.with_clean_git_env do capture_and_ignore_stderr(*capture3_args_for(command, dir)) end [URICredentialsFilter.credential_filtered_string(out, uri), status] end def git_retry(*command, dir: nil) command_with_no_credentials = check_allowed(command) Bundler::Retry.new("`#{command_with_no_credentials}` at #{dir || SharedHelpers.pwd}").attempts do git(*command, :dir => dir) end end def git(*command, dir: nil) command_with_no_credentials = check_allowed(command) out, status = SharedHelpers.with_clean_git_env do capture_and_filter_stderr(*capture3_args_for(command, dir)) end filtered_out = URICredentialsFilter.credential_filtered_string(out, uri) raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, filtered_out) unless status.success? filtered_out end def has_revision_cached? return unless @revision with_path { git("cat-file", "-e", @revision, :dir => path) } true rescue GitError false end def remove_cache FileUtils.rm_rf(path) end def find_local_revision allowed_with_path do git("rev-parse", "--verify", ref || "HEAD", :dir => path).strip end rescue GitCommandError => e raise MissingGitRevisionError.new(e.command, path, ref, URICredentialsFilter.credential_filtered_uri(uri)) end # Adds credentials to the URI as Fetcher#configured_uri_for does def configured_uri_for(uri) if /https?:/ =~ uri remote = Bundler::URI(uri) config_auth = Bundler.settings[remote.to_s] || Bundler.settings[remote.host] remote.userinfo ||= config_auth remote.to_s else uri end end def allow? @git ? @git.allow_git_ops? : true end def with_path(&blk) checkout unless path.exist? blk.call end def allowed_with_path return with_path { yield } if allow? raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application" end def check_allowed(command) command_with_no_credentials = URICredentialsFilter.credential_filtered_string("git #{command.shelljoin}", uri) raise GitNotAllowedError.new(command_with_no_credentials) unless allow? command_with_no_credentials end def capture_and_filter_stderr(*cmd) require "open3" return_value, captured_err, status = Open3.capture3(*cmd) Bundler.ui.warn URICredentialsFilter.credential_filtered_string(captured_err, uri) unless captured_err.empty? [return_value, status] end def capture_and_ignore_stderr(*cmd) require "open3" return_value, _, status = Open3.capture3(*cmd) [return_value, status] end def capture3_args_for(cmd, dir) return ["git", *cmd] unless dir if Bundler.feature_flag.bundler_3_mode? || supports_minus_c? ["git", "-C", dir.to_s, *cmd] else ["git", *cmd, { :chdir => dir.to_s }] end end def supports_minus_c? @supports_minus_c ||= Gem::Version.new(version) >= Gem::Version.new("1.8.5") end end end end end PKu]ƣZ&bundler-2.2.24/lib/bundler/spec_set.rbnu[# frozen_string_literal: true require "tsort" module Bundler class SpecSet include Enumerable include TSort def initialize(specs) @specs = specs end def for(dependencies, check = false, match_current_platform = false, raise_on_missing = true) handled = [] deps = dependencies.dup specs = [] loop do break unless dep = deps.shift next if handled.any?{|d| d.name == dep.name && (match_current_platform || d.__platform == dep.__platform) } || dep.name == "bundler" handled << dep specs_for_dep = spec_for_dependency(dep, match_current_platform) if specs_for_dep.any? specs += specs_for_dep specs_for_dep.first.dependencies.each do |d| next if d.type == :development d = DepProxy.get_proxy(d, dep.__platform) unless match_current_platform deps << d end elsif check return false elsif raise_on_missing others = lookup[dep.name] if match_current_platform message = "Unable to find a spec satisfying #{dep} in the set. Perhaps the lockfile is corrupted?" message += " Found #{others.join(", ")} that did not match the current platform." if others && !others.empty? raise GemNotFound, message end end if spec = lookup["bundler"].first specs << spec end check ? true : specs end def [](key) key = key.name if key.respond_to?(:name) lookup[key].reverse end def []=(key, value) @specs << value @lookup = nil @sorted = nil end def sort! self end def to_a sorted.dup end def to_hash lookup.dup end def materialize(deps, missing_specs = nil) materialized = self.for(deps, false, true, !missing_specs) materialized.group_by(&:source).each do |source, specs| next unless specs.any?{|s| s.is_a?(LazySpecification) } source.local! names = -> { specs.map(&:name).uniq } source.double_check_for(names) end materialized.map! do |s| next s unless s.is_a?(LazySpecification) spec = s.__materialize__ unless spec unless missing_specs raise GemNotFound, "Could not find #{s.full_name} in any of the sources" end missing_specs << s end spec end SpecSet.new(missing_specs ? materialized.compact : materialized) end # Materialize for all the specs in the spec set, regardless of what platform they're for # This is in contrast to how for does platform filtering (and specifically different from how `materialize` calls `for` only for the current platform) # @return [Array] def materialized_for_all_platforms @specs.group_by(&:source).each do |source, specs| next unless specs.any?{|s| s.is_a?(LazySpecification) } source.local! source.remote! names = -> { specs.map(&:name).uniq } source.double_check_for(names) end @specs.map do |s| next s unless s.is_a?(LazySpecification) spec = s.__materialize__ raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec spec end end def merge(set) arr = sorted.dup set.each do |set_spec| full_name = set_spec.full_name next if arr.any? {|spec| spec.full_name == full_name } arr << set_spec end SpecSet.new(arr) end def find_by_name_and_platform(name, platform) @specs.detect {|spec| spec.name == name && spec.match_platform(platform) } end def what_required(spec) unless req = find {|s| s.dependencies.any? {|d| d.type == :runtime && d.name == spec.name } } return [spec] end what_required(req) << spec end def <<(spec) @specs << spec end def length @specs.length end def size @specs.size end def empty? @specs.empty? end def each(&b) sorted.each(&b) end private def sorted rake = @specs.find {|s| s.name == "rake" } begin @sorted ||= ([rake] + tsort).compact.uniq rescue TSort::Cyclic => error cgems = extract_circular_gems(error) raise CyclicDependencyError, "Your bundle requires gems that depend" \ " on each other, creating an infinite loop. Please remove either" \ " gem '#{cgems[1]}' or gem '#{cgems[0]}' and try again." end end def extract_circular_gems(error) error.message.scan(/@name="(.*?)"/).flatten end def lookup @lookup ||= begin lookup = Hash.new {|h, k| h[k] = [] } Index.sort_specs(@specs).reverse_each do |s| lookup[s.name] << s end lookup end end def tsort_each_node # MUST sort by name for backwards compatibility @specs.sort_by(&:name).each {|s| yield s } end def spec_for_dependency(dep, match_current_platform) specs_for_platforms = lookup[dep.name] if match_current_platform GemHelpers.select_best_platform_match(specs_for_platforms.select{|s| Gem::Platform.match_spec?(s) }, Bundler.local_platform) else GemHelpers.select_best_platform_match(specs_for_platforms, dep.__platform) end end def tsort_each_child(s) s.dependencies.sort_by(&:name).each do |d| next if d.type == :development lookup[d.name].each {|s2| yield s2 } end end end end PKu]4f++2bundler-2.2.24/lib/bundler/gem_version_promoter.rbnu[# frozen_string_literal: true module Bundler # This class contains all of the logic for determining the next version of a # Gem to update to based on the requested level (patch, minor, major). # Primarily designed to work with Resolver which will provide it the list of # available dependency versions as found in its index, before returning it to # to the resolution engine to select the best version. class GemVersionPromoter DEBUG = ENV["BUNDLER_DEBUG_RESOLVER"] || ENV["DEBUG_RESOLVER"] attr_reader :level, :locked_specs, :unlock_gems # By default, strict is false, meaning every available version of a gem # is returned from sort_versions. The order gives preference to the # requested level (:patch, :minor, :major) but in complicated requirement # cases some gems will by necessity by promoted past the requested level, # or even reverted to older versions. # # If strict is set to true, the results from sort_versions will be # truncated, eliminating any version outside the current level scope. # This can lead to unexpected outcomes or even VersionConflict exceptions # that report a version of a gem not existing for versions that indeed do # existing in the referenced source. attr_accessor :strict attr_accessor :prerelease_specified # Given a list of locked_specs and a list of gems to unlock creates a # GemVersionPromoter instance. # # @param locked_specs [SpecSet] All current locked specs. Unlike Definition # where this list is empty if all gems are being updated, this should # always be populated for all gems so this class can properly function. # @param unlock_gems [String] List of gem names being unlocked. If empty, # all gems will be considered unlocked. # @return [GemVersionPromoter] def initialize(locked_specs = SpecSet.new([]), unlock_gems = []) @level = :major @strict = false @locked_specs = locked_specs @unlock_gems = unlock_gems @sort_versions = {} @prerelease_specified = {} end # @param value [Symbol] One of three Symbols: :major, :minor or :patch. def level=(value) v = case value when String, Symbol value.to_sym end raise ArgumentError, "Unexpected level #{v}. Must be :major, :minor or :patch" unless [:major, :minor, :patch].include?(v) @level = v end # Given a Dependency and an Array of SpecGroups of available versions for a # gem, this method will return the Array of SpecGroups sorted (and possibly # truncated if strict is true) in an order to give preference to the current # level (:major, :minor or :patch) when resolution is deciding what versions # best resolve all dependencies in the bundle. # @param dep [Dependency] The Dependency of the gem. # @param spec_groups [SpecGroup] An array of SpecGroups for the same gem # named in the @dep param. # @return [SpecGroup] A new instance of the SpecGroup Array sorted and # possibly filtered. def sort_versions(dep, spec_groups) before_result = "before sort_versions: #{debug_format_result(dep, spec_groups).inspect}" if DEBUG @sort_versions[dep] ||= begin gem_name = dep.name # An Array per version returned, different entries for different platforms. # We only need the version here so it's ok to hard code this to the first instance. locked_spec = locked_specs[gem_name].first if strict filter_dep_specs(spec_groups, locked_spec) else sort_dep_specs(spec_groups, locked_spec) end.tap do |specs| if DEBUG puts before_result puts " after sort_versions: #{debug_format_result(dep, specs).inspect}" end end end end # @return [bool] Convenience method for testing value of level variable. def major? level == :major end # @return [bool] Convenience method for testing value of level variable. def minor? level == :minor end private def filter_dep_specs(spec_groups, locked_spec) res = spec_groups.select do |spec_group| if locked_spec && !major? gsv = spec_group.version lsv = locked_spec.version must_match = minor? ? [0] : [0, 1] matches = must_match.map {|idx| gsv.segments[idx] == lsv.segments[idx] } matches.uniq == [true] ? (gsv >= lsv) : false else true end end sort_dep_specs(res, locked_spec) end def sort_dep_specs(spec_groups, locked_spec) return spec_groups unless locked_spec @gem_name = locked_spec.name @locked_version = locked_spec.version result = spec_groups.sort do |a, b| @a_ver = a.version @b_ver = b.version unless @prerelease_specified[@gem_name] a_pre = @a_ver.prerelease? b_pre = @b_ver.prerelease? next -1 if a_pre && !b_pre next 1 if b_pre && !a_pre end if major? @a_ver <=> @b_ver elsif either_version_older_than_locked @a_ver <=> @b_ver elsif segments_do_not_match(:major) @b_ver <=> @a_ver elsif !minor? && segments_do_not_match(:minor) @b_ver <=> @a_ver else @a_ver <=> @b_ver end end post_sort(result) end def either_version_older_than_locked @a_ver < @locked_version || @b_ver < @locked_version end def segments_do_not_match(level) index = [:major, :minor].index(level) @a_ver.segments[index] != @b_ver.segments[index] end def unlocking_gem? unlock_gems.empty? || unlock_gems.include?(@gem_name) end # Specific version moves can't always reliably be done during sorting # as not all elements are compared against each other. def post_sort(result) # default :major behavior in Bundler does not do this return result if major? if unlocking_gem? result else move_version_to_end(result, @locked_version) end end def move_version_to_end(result, version) move, keep = result.partition {|s| s.version.to_s == version.to_s } keep.concat(move) end def debug_format_result(dep, spec_groups) a = [dep.to_s, spec_groups.map {|sg| [sg.version, sg.dependencies_for_activated_platforms.map {|dp| [dp.name, dp.requirement.to_s] }] }] last_map = a.last.map {|sg_data| [sg_data.first.version, sg_data.last.map {|aa| aa.join(" ") }] } [a.first, last_map, level, strict ? :strict : :not_strict] end end end PKu]Tee0bundler-2.2.24/lib/bundler/vendored_molinillo.rbnu[# frozen_string_literal: true module Bundler; end require_relative "vendor/molinillo/lib/molinillo" PKu]z]EE2bundler-2.2.24/lib/bundler/rubygems_integration.rbnu[# frozen_string_literal: true require "rubygems" unless defined?(Gem) module Bundler class RubygemsIntegration if defined?(Gem::Ext::Builder::CHDIR_MONITOR) EXT_LOCK = Gem::Ext::Builder::CHDIR_MONITOR else require "monitor" EXT_LOCK = Monitor.new end def self.version @version ||= Gem::Version.new(Gem::VERSION) end def self.provides?(req_str) Gem::Requirement.new(req_str).satisfied_by?(version) end def initialize @replaced_methods = {} backport_ext_builder_monitor end def version self.class.version end def provides?(req_str) self.class.provides?(req_str) end def build_args Gem::Command.build_args end def build_args=(args) Gem::Command.build_args = args end def loaded_specs(name) Gem.loaded_specs[name] end def add_to_load_path(paths) return Gem.add_to_load_path(*paths) if Gem.respond_to?(:add_to_load_path) if insert_index = Gem.load_path_insert_index # Gem directories must come after -I and ENV['RUBYLIB'] $LOAD_PATH.insert(insert_index, *paths) else # We are probably testing in core, -I and RUBYLIB don't apply $LOAD_PATH.unshift(*paths) end end def mark_loaded(spec) if spec.respond_to?(:activated=) current = Gem.loaded_specs[spec.name] current.activated = false if current spec.activated = true end Gem.loaded_specs[spec.name] = spec end def validate(spec) Bundler.ui.silence { spec.validate(false) } rescue Gem::InvalidSpecificationException => e error_message = "The gemspec at #{spec.loaded_from} is not valid. Please fix this gemspec.\n" \ "The validation error was '#{e.message}'\n" raise Gem::InvalidSpecificationException.new(error_message) rescue Errno::ENOENT nil end def set_installed_by_version(spec, installed_by_version = Gem::VERSION) return unless spec.respond_to?(:installed_by_version=) spec.installed_by_version = Gem::Version.create(installed_by_version) end def spec_missing_extensions?(spec, default = true) return spec.missing_extensions? if spec.respond_to?(:missing_extensions?) return false if spec_default_gem?(spec) return false if spec.extensions.empty? default end def spec_default_gem?(spec) spec.respond_to?(:default_gem?) && spec.default_gem? end def spec_matches_for_glob(spec, glob) return spec.matches_for_glob(glob) if spec.respond_to?(:matches_for_glob) spec.load_paths.map do |lp| Dir["#{lp}/#{glob}#{suffix_pattern}"] end.flatten(1) end def stub_set_spec(stub, spec) stub.instance_variable_set(:@spec, spec) end def path(obj) obj.to_s end def configuration require_relative "psyched_yaml" Gem.configuration rescue Gem::SystemExitException, LoadError => e Bundler.ui.error "#{e.class}: #{e.message}" Bundler.ui.trace e raise rescue YamlLibrarySyntaxError => e raise YamlSyntaxError.new(e, "Your RubyGems configuration, which is " \ "usually located in ~/.gemrc, contains invalid YAML syntax.") end def ruby_engine Gem.ruby_engine end def read_binary(path) Gem.read_binary(path) end def inflate(obj) Gem::Util.inflate(obj) end def correct_for_windows_path(path) if Gem::Util.respond_to?(:correct_for_windows_path) Gem::Util.correct_for_windows_path(path) elsif path[0].chr == "/" && path[1].chr =~ /[a-z]/i && path[2].chr == ":" path[1..-1] else path end end def sources=(val) # Gem.configuration creates a new Gem::ConfigFile, which by default will read ~/.gemrc # If that file exists, its settings (including sources) will overwrite the values we # are about to set here. In order to avoid that, we force memoizing the config file now. configuration Gem.sources = val end def sources Gem.sources end def gem_dir Gem.dir end def gem_bindir Gem.bindir end def user_home Gem.user_home end def gem_path Gem.path end def reset Gem::Specification.reset end def post_reset_hooks Gem.post_reset_hooks end def suffix_pattern Gem.suffix_pattern end def gem_cache gem_path.map {|p| File.expand_path("cache", p) } end def spec_cache_dirs @spec_cache_dirs ||= begin dirs = gem_path.map {|dir| File.join(dir, "specifications") } dirs << Gem.spec_cache_dir if Gem.respond_to?(:spec_cache_dir) # Not in RubyGems 2.0.3 or earlier dirs.uniq.select {|dir| File.directory? dir } end end def marshal_spec_dir Gem::MARSHAL_SPEC_DIR end def clear_paths Gem.clear_paths end def bin_path(gem, bin, ver) Gem.bin_path(gem, bin, ver) end def loaded_gem_paths loaded_gem_paths = Gem.loaded_specs.map {|_, s| s.full_require_paths } loaded_gem_paths.flatten end def load_plugins Gem.load_plugins if Gem.respond_to?(:load_plugins) end def load_plugin_files(files) Gem.load_plugin_files(files) if Gem.respond_to?(:load_plugin_files) end def load_env_plugins Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins) end def ui=(obj) Gem::DefaultUserInteraction.ui = obj end def ext_lock EXT_LOCK end def with_build_args(args) ext_lock.synchronize do old_args = build_args begin self.build_args = args yield ensure self.build_args = old_args end end end def spec_from_gem(path, policy = nil) require "rubygems/security" require_relative "psyched_yaml" gem_from_path(path, security_policies[policy]).spec rescue Exception, Gem::Exception, Gem::Security::Exception => e # rubocop:disable Lint/RescueException if e.is_a?(Gem::Security::Exception) || e.message =~ /unknown trust policy|unsigned gem/i || e.message =~ /couldn't verify (meta)?data signature/i raise SecurityError, "The gem #{File.basename(path, ".gem")} can't be installed because " \ "the security policy didn't allow it, with the message: #{e.message}" else raise e end end def build_gem(gem_dir, spec) build(spec) end def security_policy_keys %w[High Medium Low AlmostNo No].map {|level| "#{level}Security" } end def security_policies @security_policies ||= begin require "rubygems/security" Gem::Security::Policies rescue LoadError, NameError {} end end def reverse_rubygems_kernel_mixin # Disable rubygems' gem activation system kernel = (class << ::Kernel; self; end) [kernel, ::Kernel].each do |k| if k.private_method_defined?(:gem_original_require) redefine_method(k, :require, k.instance_method(:gem_original_require)) end end end def replace_gem(specs, specs_by_name) reverse_rubygems_kernel_mixin executables = nil kernel = (class << ::Kernel; self; end) [kernel, ::Kernel].each do |kernel_class| redefine_method(kernel_class, :gem) do |dep, *reqs| if executables && executables.include?(File.basename(caller.first.split(":").first)) break end reqs.pop if reqs.last.is_a?(Hash) unless dep.respond_to?(:name) && dep.respond_to?(:requirement) dep = Gem::Dependency.new(dep, reqs) end if spec = specs_by_name[dep.name] return true if dep.matches_spec?(spec) end message = if spec.nil? target_file = begin Bundler.default_gemfile.basename rescue GemfileNotFound "inline Gemfile" end "#{dep.name} is not part of the bundle." \ " Add it to your #{target_file}." else "can't activate #{dep}, already activated #{spec.full_name}. " \ "Make sure all dependencies are added to Gemfile." end e = Gem::LoadError.new(message) e.name = dep.name if e.respond_to?(:requirement=) e.requirement = dep.requirement elsif e.respond_to?(:version_requirement=) e.version_requirement = dep.requirement end raise e end # backwards compatibility shim, see https://github.com/rubygems/bundler/issues/5102 kernel_class.send(:public, :gem) if Bundler.feature_flag.setup_makes_kernel_gem_public? end end # Used to make bin stubs that are not created by bundler work # under bundler. The new Gem.bin_path only considers gems in # +specs+ def replace_bin_path(specs_by_name) gem_class = (class << Gem; self; end) redefine_method(gem_class, :find_spec_for_exe) do |gem_name, *args| exec_name = args.first raise ArgumentError, "you must supply exec_name" unless exec_name spec_with_name = specs_by_name[gem_name] matching_specs_by_exec_name = specs_by_name.values.select {|s| s.executables.include?(exec_name) } spec = matching_specs_by_exec_name.delete(spec_with_name) unless spec || !matching_specs_by_exec_name.empty? message = "can't find executable #{exec_name} for gem #{gem_name}" if spec_with_name.nil? message += ". #{gem_name} is not currently included in the bundle, " \ "perhaps you meant to add it to your #{Bundler.default_gemfile.basename}?" end raise Gem::Exception, message end unless spec spec = matching_specs_by_exec_name.shift warn \ "Bundler is using a binstub that was created for a different gem (#{spec.name}).\n" \ "You should run `bundle binstub #{gem_name}` " \ "to work around a system/bundle conflict." end unless matching_specs_by_exec_name.empty? conflicting_names = matching_specs_by_exec_name.map(&:name).join(", ") warn \ "The `#{exec_name}` executable in the `#{spec.name}` gem is being loaded, but it's also present in other gems (#{conflicting_names}).\n" \ "If you meant to run the executable for another gem, make sure you use a project specific binstub (`bundle binstub `).\n" \ "If you plan to use multiple conflicting executables, generate binstubs for them and disambiguate their names." end spec end redefine_method(gem_class, :activate_bin_path) do |name, *args| exec_name = args.first return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle" # Copy of Rubygems activate_bin_path impl requirement = args.last spec = find_spec_for_exe name, exec_name, [requirement] gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name) gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name) File.exist?(gem_bin) ? gem_bin : gem_from_path_bin end redefine_method(gem_class, :bin_path) do |name, *args| exec_name = args.first return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle" spec = find_spec_for_exe(name, *args) exec_name ||= spec.default_executable gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name) gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name) File.exist?(gem_bin) ? gem_bin : gem_from_path_bin end end # Replace or hook into RubyGems to provide a bundlerized view # of the world. def replace_entrypoints(specs) specs_by_name = add_default_gems_to(specs) replace_gem(specs, specs_by_name) stub_rubygems(specs) replace_bin_path(specs_by_name) Gem.clear_paths end # Add default gems not already present in specs, and return them as a hash. def add_default_gems_to(specs) specs_by_name = specs.reduce({}) do |h, s| h[s.name] = s h end Bundler.rubygems.default_stubs.each do |stub| default_spec = stub.to_spec default_spec_name = default_spec.name next if specs_by_name.key?(default_spec_name) specs << default_spec specs_by_name[default_spec_name] = default_spec end specs_by_name end def undo_replacements @replaced_methods.each do |(sym, klass), method| redefine_method(klass, sym, method) end if Binding.public_method_defined?(:source_location) post_reset_hooks.reject! {|proc| proc.binding.source_location[0] == __FILE__ } else post_reset_hooks.reject! {|proc| proc.binding.eval("__FILE__") == __FILE__ } end @replaced_methods.clear end def redefine_method(klass, method, unbound_method = nil, &block) visibility = method_visibility(klass, method) begin if (instance_method = klass.instance_method(method)) && method != :initialize # doing this to ensure we also get private methods klass.send(:remove_method, method) end rescue NameError # method isn't defined nil end @replaced_methods[[method, klass]] = instance_method if unbound_method klass.send(:define_method, method, unbound_method) klass.send(visibility, method) elsif block klass.send(:define_method, method, &block) klass.send(visibility, method) end end def method_visibility(klass, method) if klass.private_method_defined?(method) :private elsif klass.protected_method_defined?(method) :protected else :public end end def stub_rubygems(specs) Gem::Specification.all = specs Gem.post_reset do Gem::Specification.all = specs end redefine_method((class << Gem; self; end), :finish_resolve) do |*| [] end end def plain_specs Gem::Specification._all end def plain_specs=(specs) Gem::Specification.all = specs end def fetch_specs(remote, name) path = remote.uri.to_s + "#{name}.#{Gem.marshal_version}.gz" fetcher = gem_remote_fetcher fetcher.headers = { "X-Gemfile-Source" => remote.original_uri.to_s } if remote.original_uri string = fetcher.fetch_path(path) Bundler.load_marshal(string) rescue Gem::RemoteFetcher::FetchError => e # it's okay for prerelease to fail raise e unless name == "prerelease_specs" end def fetch_all_remote_specs(remote) specs = fetch_specs(remote, "specs") pres = fetch_specs(remote, "prerelease_specs") || [] specs.concat(pres) end def download_gem(spec, uri, path) uri = Bundler.settings.mirror_for(uri) fetcher = gem_remote_fetcher fetcher.headers = { "X-Gemfile-Source" => spec.remote.original_uri.to_s } if spec.remote.original_uri Bundler::Retry.new("download gem from #{uri}").attempts do fetcher.download(spec, uri, path) end rescue Gem::RemoteFetcher::FetchError => e raise Bundler::HTTPError, "Could not download gem from #{uri} due to underlying error <#{e.message}>" end def gem_remote_fetcher require "rubygems/remote_fetcher" proxy = configuration[:http_proxy] Gem::RemoteFetcher.new(proxy) end def gem_from_path(path, policy = nil) require "rubygems/package" p = Gem::Package.new(path) p.security_policy = policy if policy p end def build(spec, skip_validation = false) require "rubygems/package" Gem::Package.build(spec, skip_validation) end def repository_subdirectories Gem::REPOSITORY_SUBDIRECTORIES end def install_with_build_args(args) yield end def path_separator Gem.path_separator end def all_specs Gem::Specification.stubs.map do |stub| StubSpecification.from_stub(stub) end end def backport_ext_builder_monitor # So we can avoid requiring "rubygems/ext" in its entirety Gem.module_eval <<-RUBY, __FILE__, __LINE__ + 1 module Ext end RUBY require "rubygems/ext/builder" Gem::Ext::Builder.class_eval do unless const_defined?(:CHDIR_MONITOR) const_set(:CHDIR_MONITOR, EXT_LOCK) end remove_const(:CHDIR_MUTEX) if const_defined?(:CHDIR_MUTEX) const_set(:CHDIR_MUTEX, const_get(:CHDIR_MONITOR)) end end def find_name(name) Gem::Specification.stubs_for(name).map(&:to_spec) end if Gem::Specification.respond_to?(:default_stubs) def default_stubs Gem::Specification.default_stubs("*.gemspec") end else def default_stubs Gem::Specification.send(:default_stubs, "*.gemspec") end end def use_gemdeps(gemfile) ENV["BUNDLE_GEMFILE"] ||= File.expand_path(gemfile) require_relative "gemdeps" runtime = Bundler.setup activated_spec_names = runtime.requested_specs.map(&:to_spec).sort_by(&:name) [Gemdeps.new(runtime), activated_spec_names] end end def self.rubygems @rubygems ||= RubygemsIntegration.new end end PKu] X6%bundler-2.2.24/lib/bundler/version.rbnu[# frozen_string_literal: false module Bundler VERSION = "2.2.24".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i end end PKu]#*bundler-2.2.24/lib/bundler/current_ruby.rbnu[# frozen_string_literal: true module Bundler # Returns current version of Ruby # # @return [CurrentRuby] Current version of Ruby def self.current_ruby @current_ruby ||= CurrentRuby.new end class CurrentRuby KNOWN_MINOR_VERSIONS = %w[ 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 3.0 ].freeze KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze KNOWN_PLATFORMS = %w[ jruby maglev mingw mri mswin mswin64 rbx ruby truffleruby x64_mingw ].freeze def ruby? return true if Bundler::GemHelpers.generic_local_platform == Gem::Platform::RUBY !mswin? && (RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby") end def mri? !mswin? && RUBY_ENGINE == "ruby" end def rbx? ruby? && RUBY_ENGINE == "rbx" end def jruby? RUBY_ENGINE == "jruby" end def maglev? RUBY_ENGINE == "maglev" end def truffleruby? RUBY_ENGINE == "truffleruby" end def mswin? Gem.win_platform? end def mswin64? Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64" end def mingw? Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64" end def x64_mingw? Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64" end (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version| trimmed_version = version.tr(".", "") define_method(:"on_#{trimmed_version}?") do RUBY_VERSION.start_with?("#{version}.") end KNOWN_PLATFORMS.each do |platform| define_method(:"#{platform}_#{trimmed_version}?") do send(:"#{platform}?") && send(:"on_#{trimmed_version}?") end end end end end PKu])PY\\1bundler-2.2.24/lib/bundler/similarity_detector.rbnu[# frozen_string_literal: true module Bundler class SimilarityDetector SimilarityScore = Struct.new(:string, :distance) # initialize with an array of words to be matched against def initialize(corpus) @corpus = corpus end # return an array of words similar to 'word' from the corpus def similar_words(word, limit = 3) words_by_similarity = @corpus.map {|w| SimilarityScore.new(w, levenshtein_distance(word, w)) } words_by_similarity.select {|s| s.distance <= limit }.sort_by(&:distance).map(&:string) end # return the result of 'similar_words', concatenated into a list # (eg "a, b, or c") def similar_word_list(word, limit = 3) words = similar_words(word, limit) if words.length == 1 words[0] elsif words.length > 1 [words[0..-2].join(", "), words[-1]].join(" or ") end end protected # https://www.informit.com/articles/article.aspx?p=683059&seqNum=36 def levenshtein_distance(this, that, ins = 2, del = 2, sub = 1) # ins, del, sub are weighted costs return nil if this.nil? return nil if that.nil? dm = [] # distance matrix # Initialize first row values dm[0] = (0..this.length).collect {|i| i * ins } fill = [0] * (this.length - 1) # Initialize first column values (1..that.length).each do |i| dm[i] = [i * del, fill.flatten] end # populate matrix (1..that.length).each do |i| (1..this.length).each do |j| # critical comparison dm[i][j] = [ dm[i - 1][j - 1] + (this[j - 1] == that[i - 1] ? 0 : sub), dm[i][j - 1] + ins, dm[i - 1][j] + del, ].min end end # The last value in matrix is the Levenshtein distance between the strings dm[that.length][this.length] end end end PKu]6e$ll'bundler-2.2.24/lib/bundler/deprecate.rbnu[# frozen_string_literal: true begin require "rubygems/deprecate" rescue LoadError # it's fine if it doesn't exist on the current RubyGems... nil end module Bundler # If Bundler::Deprecate is an autoload constant, we need to define it if defined?(Bundler::Deprecate) && !autoload?(:Deprecate) # nothing to do! elsif defined? ::Deprecate Deprecate = ::Deprecate elsif defined? Gem::Deprecate Deprecate = Gem::Deprecate else class Deprecate end end unless Deprecate.respond_to?(:skip_during) def Deprecate.skip_during original = skip self.skip = true yield ensure self.skip = original end end unless Deprecate.respond_to?(:skip) def Deprecate.skip @skip ||= false end end unless Deprecate.respond_to?(:skip=) def Deprecate.skip=(skip) @skip = skip end end end PKu]|YY*bundler-2.2.24/lib/bundler/vendored_uri.rbnu[# frozen_string_literal: true module Bundler; end require_relative "vendor/uri/lib/uri" PKu]یYY2bundler-2.2.24/lib/bundler/compact_index_client.rbnu[# frozen_string_literal: true require "pathname" require "set" module Bundler class CompactIndexClient DEBUG_MUTEX = Mutex.new def self.debug return unless ENV["DEBUG_COMPACT_INDEX"] DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") } end class Error < StandardError; end require_relative "compact_index_client/cache" require_relative "compact_index_client/updater" attr_reader :directory def initialize(directory, fetcher) @directory = Pathname.new(directory) @updater = Updater.new(fetcher) @cache = Cache.new(@directory) @endpoints = Set.new @info_checksums_by_name = {} @parsed_checksums = false @mutex = Mutex.new end def execution_mode=(block) Bundler::CompactIndexClient.debug { "execution_mode=" } @endpoints = Set.new @execution_mode = block end # @return [Lambda] A lambda that takes an array of inputs and a block, and # maps the inputs with the block in parallel. # def execution_mode @execution_mode || sequentially end def sequential_execution_mode! self.execution_mode = sequentially end def sequentially @sequentially ||= lambda do |inputs, &blk| inputs.map(&blk) end end def names Bundler::CompactIndexClient.debug { "/names" } update(@cache.names_path, "names") @cache.names end def versions Bundler::CompactIndexClient.debug { "/versions" } update(@cache.versions_path, "versions") versions, @info_checksums_by_name = @cache.versions versions end def dependencies(names) Bundler::CompactIndexClient.debug { "dependencies(#{names})" } execution_mode.call(names) do |name| update_info(name) @cache.dependencies(name).map {|d| d.unshift(name) } end.flatten(1) end def spec(name, version, platform = nil) Bundler::CompactIndexClient.debug { "spec(name = #{name}, version = #{version}, platform = #{platform})" } update_info(name) @cache.specific_dependency(name, version, platform) end def update_and_parse_checksums! Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" } return @info_checksums_by_name if @parsed_checksums update(@cache.versions_path, "versions") @info_checksums_by_name = @cache.checksums @parsed_checksums = true end private def update(local_path, remote_path) Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" } unless synchronize { @endpoints.add?(remote_path) } Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" } return end @updater.update(local_path, url(remote_path)) end def update_info(name) Bundler::CompactIndexClient.debug { "update_info(#{name})" } path = @cache.info_path(name) checksum = @updater.checksum_for_file(path) unless existing = @info_checksums_by_name[name] Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" } return end if checksum == existing Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" } return end Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" } update(path, "info/#{name}") end def url(path) path end def synchronize @mutex.synchronize { yield } end end end PKu]j[] ] $bundler-2.2.24/lib/bundler/worker.rbnu[# frozen_string_literal: true module Bundler class Worker POISON = Object.new class WrappedException < StandardError attr_reader :exception def initialize(exn) @exception = exn end end # @return [String] the name of the worker attr_reader :name # Creates a worker pool of specified size # # @param size [Integer] Size of pool # @param name [String] name the name of the worker # @param func [Proc] job to run in inside the worker pool def initialize(size, name, func) @name = name @request_queue = Queue.new @response_queue = Queue.new @func = func @size = size @threads = nil SharedHelpers.trap("INT") { abort_threads } end # Enqueue a request to be executed in the worker pool # # @param obj [String] mostly it is name of spec that should be downloaded def enq(obj) create_threads unless @threads @request_queue.enq obj end # Retrieves results of job function being executed in worker pool def deq result = @response_queue.deq raise result.exception if result.is_a?(WrappedException) result end def stop stop_threads end private def process_queue(i) loop do obj = @request_queue.deq break if obj.equal? POISON @response_queue.enq apply_func(obj, i) end end def apply_func(obj, i) @func.call(obj, i) rescue Exception => e # rubocop:disable Lint/RescueException WrappedException.new(e) end # Stop the worker threads by sending a poison object down the request queue # so as worker threads after retrieving it, shut themselves down def stop_threads return unless @threads @threads.each { @request_queue.enq POISON } @threads.each(&:join) @threads = nil end def abort_threads return unless @threads Bundler.ui.debug("\n#{caller.join("\n")}") @threads.each(&:exit) exit 1 end def create_threads creation_errors = [] @threads = Array.new(@size) do |i| begin Thread.start { process_queue(i) }.tap do |thread| thread.name = "#{name} Worker ##{i}" if thread.respond_to?(:name=) end rescue ThreadError => e creation_errors << e nil end end.compact return if creation_errors.empty? message = "Failed to create threads for the #{name} worker: #{creation_errors.map(&:to_s).uniq.join(", ")}" raise ThreadCreationError, message if @threads.empty? Bundler.ui.info message end end end PKu]<, , 0bundler-2.2.24/lib/bundler/settings/validator.rbnu[# frozen_string_literal: true module Bundler class Settings class Validator class Rule attr_reader :description def initialize(keys, description, &validate) @keys = keys @description = description @validate = validate end def validate!(key, value, settings) instance_exec(key, value, settings, &@validate) end def fail!(key, value, *reasons) reasons.unshift @description raise InvalidOption, "Setting `#{key}` to #{value.inspect} failed:\n#{reasons.map {|r| " - #{r}" }.join("\n")}" end def set(settings, key, value, *reasons) hash_key = k(key) return if settings[hash_key] == value reasons.unshift @description Bundler.ui.info "Setting `#{key}` to #{value.inspect}, since #{reasons.join(", ")}" if value.nil? settings.delete(hash_key) else settings[hash_key] = value end end def k(key) Bundler.settings.key_for(key) end end def self.rules @rules ||= Hash.new {|h, k| h[k] = [] } end private_class_method :rules def self.rule(keys, description, &blk) rule = Rule.new(keys, description, &blk) keys.each {|k| rules[k] << rule } end private_class_method :rule def self.validate!(key, value, settings) rules_to_validate = rules[key] rules_to_validate.each {|rule| rule.validate!(key, value, settings) } end rule %w[path path.system], "path and path.system are mutually exclusive" do |key, value, settings| if key == "path" && value set(settings, "path.system", nil) elsif key == "path.system" && value set(settings, :path, nil) end end rule %w[with without], "a group cannot be in both `with` & `without` simultaneously" do |key, value, settings| with = settings.fetch(k(:with), "").split(":").map(&:to_sym) without = settings.fetch(k(:without), "").split(":").map(&:to_sym) other_key = key == "with" ? :without : :with other_setting = key == "with" ? without : with conflicting = with & without if conflicting.any? fail!(key, value, "`#{other_key}` is current set to #{other_setting.inspect}", "the `#{conflicting.join("`, `")}` groups conflict") end end rule %w[path], "relative paths are expanded relative to the current working directory" do |key, value, settings| next if value.nil? path = Pathname.new(value) next if !path.relative? || !Bundler.feature_flag.path_relative_to_cwd? path = path.expand_path root = begin Bundler.root rescue GemfileNotFound Pathname.pwd.expand_path end path = begin path.relative_path_from(root) rescue ArgumentError path end set(settings, key, path.to_s) end end end end PKu]h 8bundler-2.2.24/lib/bundler/compact_index_client/cache.rbnu[# frozen_string_literal: true require_relative "gem_parser" module Bundler class CompactIndexClient class Cache attr_reader :directory def initialize(directory) @directory = Pathname.new(directory).expand_path info_roots.each do |dir| SharedHelpers.filesystem_access(dir) do FileUtils.mkdir_p(dir) end end end def names lines(names_path) end def names_path directory.join("names") end def versions versions_by_name = Hash.new {|hash, key| hash[key] = [] } info_checksums_by_name = {} lines(versions_path).each do |line| name, versions_string, info_checksum = line.split(" ", 3) info_checksums_by_name[name] = info_checksum || "" versions_string.split(",").each do |version| if version.start_with?("-") version = version[1..-1].split("-", 2).unshift(name) versions_by_name[name].delete(version) else version = version.split("-", 2).unshift(name) versions_by_name[name] << version end end end [versions_by_name, info_checksums_by_name] end def versions_path directory.join("versions") end def checksums checksums = {} lines(versions_path).each do |line| name, _, checksum = line.split(" ", 3) checksums[name] = checksum end checksums end def dependencies(name) lines(info_path(name)).map do |line| parse_gem(line) end end def info_path(name) name = name.to_s if name =~ /[^a-z0-9_-]/ name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}" info_roots.last.join(name) else info_roots.first.join(name) end end def specific_dependency(name, version, platform) pattern = [version, platform].compact.join("-") return nil if pattern.empty? gem_lines = info_path(name).read gem_line = gem_lines[/^#{Regexp.escape(pattern)}\b.*/, 0] gem_line ? parse_gem(gem_line) : nil end private def lines(path) return [] unless path.file? lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n") header = lines.index("---") header ? lines[header + 1..-1] : lines end def parse_gem(line) @dependency_parser ||= GemParser.new @dependency_parser.parse(line) end def info_roots [ directory.join("info"), directory.join("info-special-characters"), ] end end end end PKu]CXj=bundler-2.2.24/lib/bundler/compact_index_client/gem_parser.rbnu[# frozen_string_literal: true module Bundler class CompactIndexClient if defined?(Gem::Resolver::APISet::GemParser) GemParser = Gem::Resolver::APISet::GemParser else class GemParser def parse(line) version_and_platform, rest = line.split(" ", 2) version, platform = version_and_platform.split("-", 2) dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : [] requirements = requirements ? requirements.map {|d| parse_dependency(d) } : [] [version, platform, dependencies, requirements] end private def parse_dependency(string) dependency = string.split(":") dependency[-1] = dependency[-1].split("&") if dependency.size > 1 dependency end end end end end PKu]q cc:bundler-2.2.24/lib/bundler/compact_index_client/updater.rbnu[# frozen_string_literal: true require_relative "../vendored_fileutils" module Bundler class CompactIndexClient class Updater class MisMatchedChecksumError < Error def initialize(path, server_checksum, local_checksum) @path = path @server_checksum = server_checksum @local_checksum = local_checksum end def message "The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \ "(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})." end end def initialize(fetcher) @fetcher = fetcher require_relative "../vendored_tmpdir" end def update(local_path, remote_path, retrying = nil) headers = {} Bundler::Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir| local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename) # first try to fetch any new bytes on the existing file if retrying.nil? && local_path.file? SharedHelpers.filesystem_access(local_temp_path) do FileUtils.cp local_path, local_temp_path end headers["If-None-Match"] = etag_for(local_temp_path) headers["Range"] = if local_temp_path.size.nonzero? # Subtract a byte to ensure the range won't be empty. # Avoids 416 (Range Not Satisfiable) responses. "bytes=#{local_temp_path.size - 1}-" else "bytes=#{local_temp_path.size}-" end end response = @fetcher.call(remote_path, headers) return nil if response.is_a?(Net::HTTPNotModified) content = response.body etag = (response["ETag"] || "").gsub(%r{\AW/}, "") correct_response = SharedHelpers.filesystem_access(local_temp_path) do if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero? local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) } etag_for(local_temp_path) == etag else local_temp_path.open("wb") {|f| f << content } etag.length.zero? || etag_for(local_temp_path) == etag end end if correct_response SharedHelpers.filesystem_access(local_path) do FileUtils.mv(local_temp_path, local_path) end return nil end if retrying raise MisMatchedChecksumError.new(remote_path, etag, etag_for(local_temp_path)) end update(local_path, remote_path, :retrying) end rescue Errno::EACCES raise Bundler::PermissionError, "Bundler does not have write access to create a temp directory " \ "within #{Dir.tmpdir}. Bundler must have write access to your " \ "systems temp directory to function properly. " rescue Zlib::GzipFile::Error raise Bundler::HTTPError end def etag_for(path) sum = checksum_for_file(path) sum ? %("#{sum}") : nil end def slice_body(body, range) body.byteslice(range) end def checksum_for_file(path) return nil unless path.file? # This must use File.read instead of Digest.file().hexdigest # because we need to preserve \n line endings on windows when calculating # the checksum SharedHelpers.filesystem_access(path, :read) do SharedHelpers.digest(:MD5).hexdigest(File.read(path)) end end end end end PKu]Hu""#bundler-2.2.24/lib/bundler/setup.rbnu[# frozen_string_literal: true require_relative "shared_helpers" if Bundler::SharedHelpers.in_bundle? require_relative "../bundler" if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"] begin Bundler.ui.silence { Bundler.setup } rescue Bundler::BundlerError => e Bundler.ui.warn "\e[31m#{e.message}\e[0m" Bundler.ui.warn e.backtrace.join("\n") if ENV["DEBUG"] if e.is_a?(Bundler::GemNotFound) Bundler.ui.warn "\e[33mRun `bundle install` to install missing gems.\e[0m" end exit e.status_code end else Bundler.ui.silence { Bundler.setup } end # We might be in the middle of shelling out to rubygems # (RUBYOPT=-rbundler/setup), so we need to give rubygems the opportunity of # not being silent. Gem::DefaultUserInteraction.ui = nil end PKu]hFF*bundler-2.2.24/lib/bundler/psyched_yaml.rbnu[# frozen_string_literal: true # Psych could be in the stdlib # but it's too late if Syck is already loaded begin require "psych" unless defined?(Syck) rescue LoadError # Apparently Psych wasn't available. Oh well. end # At least load the YAML stdlib, whatever that may be require "yaml" unless defined?(YAML.dump) module Bundler # On encountering invalid YAML, # Psych raises Psych::SyntaxError if defined?(::Psych::SyntaxError) YamlLibrarySyntaxError = ::Psych::SyntaxError else # Syck raises ArgumentError YamlLibrarySyntaxError = ::ArgumentError end end PKu]hc3bundler-2.2.24/lib/bundler/environment_preserver.rbnu[# frozen_string_literal: true module Bundler class EnvironmentPreserver INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL".freeze BUNDLER_KEYS = %w[ BUNDLE_BIN_PATH BUNDLE_GEMFILE BUNDLER_VERSION GEM_HOME GEM_PATH MANPATH PATH RB_USER_INSTALL RUBYLIB RUBYOPT ].map(&:freeze).freeze BUNDLER_PREFIX = "BUNDLER_ORIG_".freeze def self.from_env new(env_to_hash(ENV), BUNDLER_KEYS) end def self.env_to_hash(env) to_hash = env.to_hash return to_hash unless Gem.win_platform? to_hash.each_with_object({}) {|(k,v), a| a[k.upcase] = v } end # @param env [Hash] # @param keys [Array] def initialize(env, keys) @original = env @keys = keys @prefix = BUNDLER_PREFIX end # Replaces `ENV` with the bundler environment variables backed up def replace_with_backup ENV.replace(backup) unless Gem.win_platform? # Fallback logic for Windows below to workaround # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all # supported rubies include the fix for that. ENV.clear backup.each {|k, v| ENV[k] = v } end # @return [Hash] def backup env = @original.clone @keys.each do |key| value = env[key] if !value.nil? && !value.empty? env[@prefix + key] ||= value elsif value.nil? env[@prefix + key] ||= INTENTIONALLY_NIL end end env end # @return [Hash] def restore env = @original.clone @keys.each do |key| value_original = env[@prefix + key] next if value_original.nil? || value_original.empty? if value_original == INTENTIONALLY_NIL env.delete(key) else env[key] = value_original end env.delete(@prefix + key) end env end end end PKu]I~] 7bundler-2.2.24/lib/bundler/templates/Executable.bundlernu[#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> # frozen_string_literal: true # # This file was generated by Bundler. # # The application '<%= executable %>' is installed as part of a gem, and # this file is here to facilitate running it. # require "rubygems" m = Module.new do module_function def invoked_as_script? File.expand_path($0) == File.expand_path(__FILE__) end def env_var_version ENV["BUNDLER_VERSION"] end def cli_arg_version return unless invoked_as_script? # don't want to hijack other binstubs return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` bundler_version = nil update_index = nil ARGV.each_with_index do |a, i| if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN bundler_version = a end next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ bundler_version = $1 update_index = i end bundler_version end def gemfile gemfile = ENV["BUNDLE_GEMFILE"] return gemfile if gemfile && !gemfile.empty? File.expand_path("../<%= relative_gemfile_path %>", __FILE__) end def lockfile lockfile = case File.basename(gemfile) when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) else "#{gemfile}.lock" end File.expand_path(lockfile) end def lockfile_version return unless File.file?(lockfile) lockfile_contents = File.read(lockfile) return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ Regexp.last_match(1) end def bundler_version @bundler_version ||= env_var_version || cli_arg_version || lockfile_version end def bundler_requirement return "#{Gem::Requirement.default}.a" unless bundler_version bundler_gem_version = Gem::Version.new(bundler_version) requirement = bundler_gem_version.approximate_recommendation return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") requirement += ".a" if bundler_gem_version.prerelease? requirement end def load_bundler! ENV["BUNDLE_GEMFILE"] ||= gemfile activate_bundler end def activate_bundler gem_error = activation_error_handling do gem "bundler", bundler_requirement end return if gem_error.nil? require_error = activation_error_handling do require "bundler/version" end return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" exit 42 end def activation_error_handling yield nil rescue StandardError, LoadError => e e end end m.load_bundler! if m.invoked_as_script? load Gem.bin_path("<%= spec.name %>", "<%= executable %>") end PKu]MBbundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/newgem.c.ttnu[#include "<%= config[:underscored_name] %>.h" VALUE rb_m<%= config[:constant_array].join %>; void Init_<%= config[:underscored_name] %>(void) { rb_m<%= config[:constant_array].join %> = rb_define_module(<%= config[:constant_name].inspect %>); } PKu]?Bbundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/newgem.h.ttnu[#ifndef <%= config[:underscored_name].upcase %>_H #define <%= config[:underscored_name].upcase %>_H 1 #include "ruby.h" #endif /* <%= config[:underscored_name].upcase %>_H */ PKu]95ffDbundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/extconf.rb.ttnu[# frozen_string_literal: true require "mkmf" create_makefile(<%= config[:makefile_path].inspect %>) PKu]7##=bundler-2.2.24/lib/bundler/templates/newgem/newgem.gemspec.ttnu[# frozen_string_literal: true require_relative "lib/<%=config[:namespaced_path]%>/version" Gem::Specification.new do |spec| spec.name = <%= config[:name].inspect %> spec.version = <%= config[:constant_name] %>::VERSION spec.authors = [<%= config[:author].inspect %>] spec.email = [<%= config[:email].inspect %>] spec.summary = "TODO: Write a short summary, because RubyGems requires one." spec.description = "TODO: Write a longer description or delete this line." spec.homepage = "TODO: Put your gem's website or public repo URL here." <%- if config[:mit] -%> spec.license = "MIT" <%- end -%> spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>" spec.metadata["allowed_push_host"] = "TODO: Set to 'https://mygemserver.com'" spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the RubyGem that have been added into git. spec.files = Dir.chdir(File.expand_path(__dir__)) do `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) } end spec.bindir = "exe" spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] <%- if config[:ext] -%> spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"] <%- end -%> # Uncomment to register a new dependency of your gem # spec.add_dependency "example-gem", "~> 1.0" # For more information and examples about making a new gem, checkout our # guide at: https://bundler.io/guides/creating_gem.html end PKu]!5c| | 8bundler-2.2.24/lib/bundler/templates/newgem/README.md.ttnu[# <%= config[:constant_name] %> Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/<%= config[:namespaced_path] %>`. To experiment with that code, run `bin/console` for an interactive prompt. TODO: Delete this and the text above, and describe your gem ## Installation Add this line to your application's Gemfile: ```ruby gem '<%= config[:name] %>' ``` And then execute: $ bundle install Or install it yourself as: $ gem install <%= config[:name] %> ## Usage TODO: Write usage instructions here ## Development After checking out the repo, run `bin/setup` to install dependencies.<% if config[:test] %> Then, run `rake <%= config[:test].sub('mini', '').sub('rspec', 'spec') %>` to run the tests.<% end %> You can also run `bin/console` for an interactive prompt that will allow you to experiment.<% if config[:bin] %> Run `bundle exec <%= config[:name] %>` to use the gem in this directory, ignoring other installed copies of this gem.<% end %> To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). <% if config[:git] -%> ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md).<% end %> <% end -%> <% if config[:mit] -%> ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). <% end -%> <% if config[:git] && config[:coc] -%> ## Code of Conduct Everyone interacting in the <%= config[:constant_name] %> project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md). <% end -%> PKu]+7bundler-2.2.24/lib/bundler/templates/newgem/Rakefile.ttnu[# frozen_string_literal: true require "bundler/gem_tasks" <% default_task_names = [config[:test_task]].compact -%> <% case config[:test] -%> <% when "minitest", "test-unit" -%> require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList["test/**/*_test.rb"] end <% when "rspec" -%> require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) <% end -%> <% if config[:rubocop] -%> <% default_task_names << :rubocop -%> require "rubocop/rake_task" RuboCop::RakeTask.new <% end -%> <% if config[:ext] -%> <% default_task_names.unshift(:clobber, :compile) -%> require "rake/extensiontask" task build: :compile Rake::ExtensionTask.new("<%= config[:underscored_name] %>") do |ext| ext.lib_dir = "lib/<%= config[:namespaced_path] %>" end <% end -%> <% if default_task_names.size == 1 -%> task default: <%= default_task_names.first.inspect %> <% else -%> task default: %i[<%= default_task_names.join(" ") %>] <% end -%> PKu]~~9bundler-2.2.24/lib/bundler/templates/newgem/travis.yml.ttnu[--- language: ruby cache: bundler rvm: - <%= RUBY_VERSION %> before_install: gem install bundler -v <%= Bundler::VERSION %> PKu]Ҧ+Bbundler-2.2.24/lib/bundler/templates/newgem/spec/spec_helper.rb.ttnu[# frozen_string_literal: true require "<%= config[:namespaced_path] %>" RSpec.configure do |config| # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = ".rspec_status" # Disable RSpec exposing methods globally on `Module` and `main` config.disable_monkey_patching! config.expect_with :rspec do |c| c.syntax = :expect end end PKu]32 Bbundler-2.2.24/lib/bundler/templates/newgem/spec/newgem_spec.rb.ttnu[# frozen_string_literal: true RSpec.describe <%= config[:constant_name] %> do it "has a version number" do expect(<%= config[:constant_name] %>::VERSION).not_to be nil end it "does something useful" do expect(false).to eq(true) end end PKu]rə6bundler-2.2.24/lib/bundler/templates/newgem/Gemfile.ttnu[# frozen_string_literal: true source "https://rubygems.org" # Specify your gem's dependencies in <%= config[:name] %>.gemspec gemspec gem "rake", "~> 13.0" <%- if config[:ext] -%> gem "rake-compiler" <%- end -%> <%- if config[:test] -%> gem "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>" <%- end -%> <%- if config[:rubocop] -%> gem "rubocop", "~> <%= config[:rubocop_version] %>" <%- end -%> PKu]z??9bundler-2.2.24/lib/bundler/templates/newgem/exe/newgem.ttnu[#!/usr/bin/env ruby require "<%= config[:namespaced_path] %>" PKu]lq554bundler-2.2.24/lib/bundler/templates/newgem/rspec.ttnu[--format documentation --color --require spec_helper PKu]G>JLbundler-2.2.24/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.ttnu[# frozen_string_literal: true $LOAD_PATH.unshift File.expand_path("../lib", __dir__) require "<%= config[:namespaced_path] %>" require "test-unit" PKu]q{33Lbundler-2.2.24/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.ttnu[# frozen_string_literal: true require "test_helper" class <%= config[:constant_name] %>Test < Test::Unit::TestCase test "VERSION" do assert do ::<%= config[:constant_name] %>.const_defined?(:VERSION) end end test "something useful" do assert_equal("expected", "actual") end end PKu]M-nKbundler-2.2.24/lib/bundler/templates/newgem/test/minitest/test_helper.rb.ttnu[# frozen_string_literal: true $LOAD_PATH.unshift File.expand_path("../lib", __dir__) require "<%= config[:namespaced_path] %>" require "minitest/autorun" PKu]-Kbundler-2.2.24/lib/bundler/templates/newgem/test/minitest/newgem_test.rb.ttnu[# frozen_string_literal: true require "test_helper" class <%= config[:constant_name] %>Test < Minitest::Test def test_that_it_has_a_version_number refute_nil ::<%= config[:constant_name] %>::VERSION end def test_it_does_something_useful assert false end end PKu]/++:bundler-2.2.24/lib/bundler/templates/newgem/rubocop.yml.ttnu[AllCops: TargetRubyVersion: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %> Style/StringLiterals: Enabled: true EnforcedStyle: double_quotes Style/StringLiteralsInInterpolation: Enabled: true EnforcedStyle: double_quotes Layout/LineLength: Max: 120 PKu]v@@Hbundler-2.2.24/lib/bundler/templates/newgem/github/workflows/main.yml.ttnu[name: Ruby on: [push,pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: <%= RUBY_VERSION %> bundler-cache: true - name: Run the default task run: bundle exec rake PKu]g28bundler-2.2.24/lib/bundler/templates/newgem/gitignore.ttnu[/.bundle/ /.yardoc /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ <%- if config[:ext] -%> *.bundle *.so *.o *.a mkmf.log <%- end -%> <%- if config[:test] == "rspec" -%> # rspec failure tracking .rspec_status <%- end -%> PKu]44.<bundler-2.2.24/lib/bundler/templates/newgem/gitlab-ci.yml.ttnu[image: ruby:<%= RUBY_VERSION %> before_script: - gem install bundler -v <%= Bundler::VERSION %> - bundle install example_job: script: - bundle exec rake PKu]!5PP;bundler-2.2.24/lib/bundler/templates/newgem/CHANGELOG.md.ttnu[## [Unreleased] ## [0.1.0] - <%= Time.now.strftime('%F') %> - Initial release PKu]QQ:bundler-2.2.24/lib/bundler/templates/newgem/LICENSE.txt.ttnu[The MIT License (MIT) Copyright (c) <%= Time.now.year %> <%= config[:author] %> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PKu]_ccAbundler-2.2.24/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.ttnu[# Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at <%= config[:email] %>. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. PKu]eە:bundler-2.2.24/lib/bundler/templates/newgem/bin/console.ttnu[#!/usr/bin/env ruby # frozen_string_literal: true require "bundler/setup" require "<%= config[:namespaced_path] %>" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start(__FILE__) PKu]8bundler-2.2.24/lib/bundler/templates/newgem/bin/setup.ttnu[#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install # Do any other automated setup that you need to do here PKu]^6)g&&Bbundler-2.2.24/lib/bundler/templates/newgem/circleci/config.yml.ttnu[version: 2.1 jobs: build: docker: - image: ruby:<%= RUBY_VERSION %> steps: - checkout - run: name: Run the default task command: | gem install bundler -v <%= Bundler::VERSION %> bundle install bundle exec rake PKu]Dbundler-2.2.24/lib/bundler/templates/newgem/lib/newgem/version.rb.ttnu[# frozen_string_literal: true <%- config[:constant_array].each_with_index do |c, i| -%> <%= " " * i %>module <%= c %> <%- end -%> <%= " " * config[:constant_array].size %>VERSION = "0.1.0" <%- (config[:constant_array].size-1).downto(0) do |i| -%> <%= " " * i %>end <%- end -%> PKu]Br==<bundler-2.2.24/lib/bundler/templates/newgem/lib/newgem.rb.ttnu[# frozen_string_literal: true require_relative "<%= File.basename(config[:namespaced_path]) %>/version" <%- if config[:ext] -%> require_relative "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>" <%- end -%> <%- config[:constant_array].each_with_index do |c, i| -%> <%= " " * i %>module <%= c %> <%- end -%> <%= " " * config[:constant_array].size %>class Error < StandardError; end <%= " " * config[:constant_array].size %># Your code goes here... <%- (config[:constant_array].size-1).downto(0) do |i| -%> <%= " " * i %>end <%- end -%> PKu]”}Ñ/bundler-2.2.24/lib/bundler/templates/Executablenu[#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> # frozen_string_literal: true # # This file was generated by Bundler. # # The application '<%= executable %>' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../<%= relative_gemfile_path %>", Pathname.new(__FILE__).realpath) bundle_binstub = File.expand_path("../bundle", __FILE__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") end end require "rubygems" require "bundler/setup" load Gem.bin_path("<%= spec.name %>", "<%= executable %>") PKu]t,bundler-2.2.24/lib/bundler/templates/Gemfilenu[# frozen_string_literal: true source "https://rubygems.org" git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } # gem "rails" PKu]{:bundler-2.2.24/lib/bundler/templates/Executable.standalonenu[#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> # # This file was generated by Bundler. # # The application '<%= executable %>' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" path = Pathname.new(__FILE__) $:.unshift File.expand_path "../<%= standalone_path %>", path.realpath require "bundler/setup" load File.expand_path "../<%= executable_path %>", path.realpath PKu]Ba7,bundler-2.2.24/lib/bundler/templates/gems.rbnu[# frozen_string_literal: true # A sample gems.rb source "https://rubygems.org" git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } # gem "rails" PKu]9rQ' ' $bundler-2.2.24/lib/bundler/inline.rbnu[# frozen_string_literal: true # Allows for declaring a Gemfile inline in a ruby script, optionally installing # any gems that aren't already installed on the user's system. # # @note Every gem that is specified in this 'Gemfile' will be `require`d, as if # the user had manually called `Bundler.require`. To avoid a requested gem # being automatically required, add the `:require => false` option to the # `gem` dependency declaration. # # @param install [Boolean] whether gems that aren't already installed on the # user's system should be installed. # Defaults to `false`. # # @param gemfile [Proc] a block that is evaluated as a `Gemfile`. # # @example Using an inline Gemfile # # #!/usr/bin/env ruby # # require 'bundler/inline' # # gemfile do # source 'https://rubygems.org' # gem 'json', require: false # gem 'nap', require: 'rest' # gem 'cocoapods', '~> 0.34.1' # end # # puts Pod::VERSION # => "0.34.4" # def gemfile(install = false, options = {}, &gemfile) require_relative "../bundler" opts = options.dup ui = opts.delete(:ui) { Bundler::UI::Shell.new } ui.level = "silent" if opts.delete(:quiet) raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty? begin old_root = Bundler.method(:root) bundler_module = class << Bundler; self; end bundler_module.send(:remove_method, :root) def Bundler.root Bundler::SharedHelpers.pwd.expand_path end old_gemfile = ENV["BUNDLE_GEMFILE"] Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile" Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? builder = Bundler::Dsl.new builder.instance_eval(&gemfile) builder.check_primary_source_safety Bundler.settings.temporary(:deployment => false, :frozen => false) do definition = builder.to_definition(nil, true) def definition.lock(*); end definition.validate_runtime! Bundler.ui = install ? ui : Bundler::UI::Silent.new if install || definition.missing_specs? Bundler.settings.temporary(:inline => true) do installer = Bundler::Installer.install(Bundler.root, definition, :system => true) installer.post_install_messages.each do |name, message| Bundler.ui.info "Post-install message from #{name}:\n#{message}" end end end runtime = Bundler::Runtime.new(nil, definition) runtime.setup.require end ensure if bundler_module bundler_module.send(:remove_method, :root) bundler_module.send(:define_method, :root, old_root) end if old_gemfile ENV["BUNDLE_GEMFILE"] = old_gemfile else ENV["BUNDLE_GEMFILE"] = "" end end end PKu]4%%&bundler-2.2.24/lib/bundler/injector.rbnu[# frozen_string_literal: true module Bundler class Injector INJECTED_GEMS = "injected gems".freeze def self.inject(new_deps, options = {}) injector = new(new_deps, options) injector.inject(Bundler.default_gemfile, Bundler.default_lockfile) end def self.remove(gems, options = {}) injector = new(gems, options) injector.remove(Bundler.default_gemfile, Bundler.default_lockfile) end def initialize(deps, options = {}) @deps = deps @options = options end # @param [Pathname] gemfile_path The Gemfile in which to inject the new dependency. # @param [Pathname] lockfile_path The lockfile in which to inject the new dependency. # @return [Array] def inject(gemfile_path, lockfile_path) if Bundler.frozen_bundle? # ensure the lock and Gemfile are synced Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true) end # temporarily unfreeze Bundler.settings.temporary(:deployment => false, :frozen => false) do # evaluate the Gemfile we have now builder = Dsl.new builder.eval_gemfile(gemfile_path) # don't inject any gems that are already in the Gemfile @deps -= builder.dependencies # add new deps to the end of the in-memory Gemfile # Set conservative versioning to false because # we want to let the resolver resolve the version first builder.eval_gemfile(INJECTED_GEMS, build_gem_lines(false)) if @deps.any? # resolve to see if the new deps broke anything @definition = builder.to_definition(lockfile_path, {}) @definition.resolve_remotely! # since nothing broke, we can add those gems to the gemfile append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any? # since we resolved successfully, write out the lockfile @definition.lock(Bundler.default_lockfile) # invalidate the cached Bundler.definition Bundler.reset_paths! # return an array of the deps that we added @deps end end # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. # @param [Pathname] lockfile_path The lockfile from which to remove dependencies. # @return [Array] def remove(gemfile_path, lockfile_path) # remove gems from each gemfiles we have Bundler.definition.gemfiles.each do |path| deps = remove_deps(path) show_warning("No gems were removed from the gemfile.") if deps.empty? deps.each {|dep| Bundler.ui.confirm "#{SharedHelpers.pretty_dependency(dep, false)} was removed." } end end private def conservative_version(spec) version = spec.version return ">= 0" if version.nil? segments = version.segments seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2 prerelease_suffix = version.to_s.gsub(version.release.to_s, "") if version.prerelease? "#{version_prefix}#{segments[0..seg_end_index].join(".")}#{prerelease_suffix}" end def version_prefix if @options[:strict] "= " elsif @options[:optimistic] ">= " else "~> " end end def build_gem_lines(conservative_versioning) @deps.map do |d| name = d.name.dump requirement = if conservative_versioning ", \"#{conservative_version(@definition.specs[d.name][0])}\"" else ", #{d.requirement.as_list.map(&:dump).join(", ")}" end if d.groups != Array(:default) group = d.groups.size == 1 ? ", :group => #{d.groups.first.inspect}" : ", :groups => #{d.groups.inspect}" end source = ", :source => \"#{d.source}\"" unless d.source.nil? git = ", :git => \"#{d.git}\"" unless d.git.nil? branch = ", :branch => \"#{d.branch}\"" unless d.branch.nil? %(gem #{name}#{requirement}#{group}#{source}#{git}#{branch}) end.join("\n") end def append_to(gemfile_path, new_gem_lines) gemfile_path.open("a") do |f| f.puts f.puts new_gem_lines end end # evaluates a gemfile to remove the specified gem # from it. def remove_deps(gemfile_path) initial_gemfile = File.readlines(gemfile_path) Bundler.ui.info "Removing gems from #{gemfile_path}" # evaluate the Gemfile we have builder = Dsl.new builder.eval_gemfile(gemfile_path) removed_deps = remove_gems_from_dependencies(builder, @deps, gemfile_path) # abort the operation if no gems were removed # no need to operate on gemfile further return [] if removed_deps.empty? cleaned_gemfile = remove_gems_from_gemfile(@deps, gemfile_path) SharedHelpers.write_to_gemfile(gemfile_path, cleaned_gemfile) # check for errors # including extra gems being removed # or some gems not being removed # and return the actual removed deps cross_check_for_errors(gemfile_path, builder.dependencies, removed_deps, initial_gemfile) end # @param [Dsl] builder Dsl object of current Gemfile. # @param [Array] gems Array of names of gems to be removed. # @param [Pathname] gemfile_path Path of the Gemfile. # @return [Array] Array of removed dependencies. def remove_gems_from_dependencies(builder, gems, gemfile_path) removed_deps = [] gems.each do |gem_name| deleted_dep = builder.dependencies.find {|d| d.name == gem_name } if deleted_dep.nil? raise GemfileError, "`#{gem_name}` is not specified in #{gemfile_path} so it could not be removed." end builder.dependencies.delete(deleted_dep) removed_deps << deleted_dep end removed_deps end # @param [Array] gems Array of names of gems to be removed. # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. def remove_gems_from_gemfile(gems, gemfile_path) patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2\)/ new_gemfile = [] multiline_removal = false File.readlines(gemfile_path).each do |line| match_data = line.match(patterns) if match_data && is_not_within_comment?(line, match_data) multiline_removal = line.rstrip.end_with?(",") # skip lines which match the regex next end # skip followup lines until line does not end with ',' new_gemfile << line unless multiline_removal multiline_removal = line.rstrip.end_with?(",") if multiline_removal end # remove line \n and append them with other strings new_gemfile.each_with_index do |_line, index| if new_gemfile[index + 1] == "\n" new_gemfile[index] += new_gemfile[index + 1] new_gemfile.delete_at(index + 1) end end %w[group source env install_if].each {|block| remove_nested_blocks(new_gemfile, block) } new_gemfile.join.chomp end # @param [String] line Individual line of gemfile content. # @param [MatchData] match_data Data about Regex match. def is_not_within_comment?(line, match_data) match_start_index = match_data.offset(0).first !line[0..match_start_index].include?("#") end # @param [Array] gemfile Array of gemfile contents. # @param [String] block_name Name of block name to look for. def remove_nested_blocks(gemfile, block_name) nested_blocks = 0 # count number of nested blocks gemfile.each_with_index {|line, index| nested_blocks += 1 if !gemfile[index + 1].nil? && gemfile[index + 1].include?(block_name) && line.include?(block_name) } while nested_blocks >= 0 nested_blocks -= 1 gemfile.each_with_index do |line, index| next unless !line.nil? && line.strip.start_with?(block_name) if gemfile[index + 1] =~ /^\s*end\s*$/ gemfile[index] = nil gemfile[index + 1] = nil end end gemfile.compact! end end # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. # @param [Array] original_deps Array of original dependencies. # @param [Array] removed_deps Array of removed dependencies. # @param [Array] initial_gemfile Contents of original Gemfile before any operation. def cross_check_for_errors(gemfile_path, original_deps, removed_deps, initial_gemfile) # evaluate the new gemfile to look for any failure cases builder = Dsl.new builder.eval_gemfile(gemfile_path) # record gems which were removed but not requested extra_removed_gems = original_deps - builder.dependencies # if some extra gems were removed then raise error # and revert Gemfile to original unless extra_removed_gems.empty? SharedHelpers.write_to_gemfile(gemfile_path, initial_gemfile.join) raise InvalidOption, "Gems could not be removed. #{extra_removed_gems.join(", ")} would also have been removed. Bundler cannot continue." end # record gems which could not be removed due to some reasons errored_deps = builder.dependencies.select {|d| d.gemfile == gemfile_path } & removed_deps.select {|d| d.gemfile == gemfile_path } show_warning "#{errored_deps.map(&:name).join(", ")} could not be removed." unless errored_deps.empty? # return actual removed dependencies removed_deps - errored_deps end def show_warning(message) Bundler.ui.info Bundler.ui.add_color(message, :yellow) end end end PKu] G'bundler-2.2.24/lib/bundler/dep_proxy.rbnu[# frozen_string_literal: true module Bundler class DepProxy attr_reader :__platform, :dep @proxies = {} def self.get_proxy(dep, platform) @proxies[[dep, platform]] ||= new(dep, platform).freeze end def initialize(dep, platform) @dep = dep @__platform = platform end private_class_method :new alias_method :eql?, :== def type @dep.type end def name @dep.name end def requirement @dep.requirement end def to_s s = name.dup s << " (#{requirement})" unless requirement == Gem::Requirement.default s << " #{__platform}" unless __platform == Gem::Platform::RUBY s end def dup raise NoMethodError.new("DepProxy cannot be duplicated") end def clone raise NoMethodError.new("DepProxy cannot be cloned") end private def method_missing(*args, &blk) @dep.send(*args, &blk) end end end PKu]\"bundler-2.2.24/lib/bundler/vlad.rbnu[# frozen_string_literal: true require_relative "shared_helpers" Bundler::SharedHelpers.major_deprecation 2, "The Bundler task for Vlad" # Vlad task for Bundler. # # Add "require 'bundler/vlad'" in your Vlad deploy.rb, and # include the vlad:bundle:install task in your vlad:deploy task. require_relative "deployment" include Rake::DSL if defined? Rake::DSL namespace :vlad do Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, :roles => :app) end PKu]oJ$bundler-2.2.24/lib/bundler/errors.rbnu[# frozen_string_literal: true module Bundler class BundlerError < StandardError def self.status_code(code) define_method(:status_code) { code } if match = BundlerError.all_errors.find {|_k, v| v == code } error, _ = match raise ArgumentError, "Trying to register #{self} for status code #{code} but #{error} is already registered" end BundlerError.all_errors[self] = code end def self.all_errors @all_errors ||= {} end end class GemfileError < BundlerError; status_code(4); end class InstallError < BundlerError; status_code(5); end # Internal error, should be rescued class VersionConflict < BundlerError attr_reader :conflicts def initialize(conflicts, msg = nil) super(msg) @conflicts = conflicts end status_code(6) end class GemNotFound < BundlerError; status_code(7); end class InstallHookError < BundlerError; status_code(8); end class GemfileNotFound < BundlerError; status_code(10); end class GitError < BundlerError; status_code(11); end class DeprecatedError < BundlerError; status_code(12); end class PathError < BundlerError; status_code(13); end class GemspecError < BundlerError; status_code(14); end class InvalidOption < BundlerError; status_code(15); end class ProductionError < BundlerError; status_code(16); end class HTTPError < BundlerError status_code(17) def filter_uri(uri) URICredentialsFilter.credential_filtered_uri(uri) end end class RubyVersionMismatch < BundlerError; status_code(18); end class SecurityError < BundlerError; status_code(19); end class LockfileError < BundlerError; status_code(20); end class CyclicDependencyError < BundlerError; status_code(21); end class GemfileLockNotFound < BundlerError; status_code(22); end class PluginError < BundlerError; status_code(29); end class SudoNotPermittedError < BundlerError; status_code(30); end class ThreadCreationError < BundlerError; status_code(33); end class APIResponseMismatchError < BundlerError; status_code(34); end class APIResponseInvalidDependenciesError < BundlerError; status_code(35); end class GemfileEvalError < GemfileError; end class MarshalError < StandardError; end class PermissionError < BundlerError def initialize(path, permission_type = :write) @path = path @permission_type = permission_type end def action case @permission_type when :read then "read from" when :write then "write to" when :executable, :exec then "execute" else @permission_type.to_s end end def message "There was an error while trying to #{action} `#{@path}`. " \ "It is likely that you need to grant #{@permission_type} permissions " \ "for that path." end status_code(23) end class GemRequireError < BundlerError attr_reader :orig_exception def initialize(orig_exception, msg) full_message = msg + "\nGem Load Error is: #{orig_exception.message}\n"\ "Backtrace for gem load error is:\n"\ "#{orig_exception.backtrace.join("\n")}\n"\ "Bundler Error Backtrace:\n" super(full_message) @orig_exception = orig_exception end status_code(24) end class YamlSyntaxError < BundlerError attr_reader :orig_exception def initialize(orig_exception, msg) super(msg) @orig_exception = orig_exception end status_code(25) end class TemporaryResourceError < PermissionError def message "There was an error while trying to #{action} `#{@path}`. " \ "Some resource was temporarily unavailable. It's suggested that you try" \ "the operation again." end status_code(26) end class VirtualProtocolError < BundlerError def message "There was an error relating to virtualization and file access." \ "It is likely that you need to grant access to or mount some file system correctly." end status_code(27) end class OperationNotSupportedError < PermissionError def message "Attempting to #{action} `#{@path}` is unsupported by your OS." end status_code(28) end class NoSpaceOnDeviceError < PermissionError def message "There was an error while trying to #{action} `#{@path}`. " \ "There was insufficient space remaining on the device." end status_code(31) end class GenericSystemCallError < BundlerError attr_reader :underlying_error def initialize(underlying_error, message) @underlying_error = underlying_error super("#{message}\nThe underlying system error is #{@underlying_error.class}: #{@underlying_error}") end status_code(32) end end PKu]Ǵ+bundler-2.2.24/lib/bundler/vendored_thor.rbnu[# frozen_string_literal: true module Bundler def self.require_thor_actions require_relative "vendor/thor/lib/thor/actions" end end require_relative "vendor/thor/lib/thor" PKu]p2Ǥ'bundler-2.2.24/lib/bundler/constants.rbnu[# frozen_string_literal: true module Bundler WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/ FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/ NULL = WINDOWS ? "NUL" : "/dev/null" end PKu]88)bundler-2.2.24/lib/bundler/cli/console.rbnu[# frozen_string_literal: true module Bundler class CLI::Console attr_reader :options, :group def initialize(options, group) @options = options @group = group end def run Bundler::SharedHelpers.major_deprecation 2, "bundle console will be replaced " \ "by `bin/console` generated by `bundle gem `" group ? Bundler.require(:default, *group.split(" ").map!(&:to_sym)) : Bundler.require ARGV.clear console = get_console(Bundler.settings[:console] || "irb") console.start end def get_console(name) require name get_constant(name) rescue LoadError Bundler.ui.error "Couldn't load console #{name}, falling back to irb" require "irb" get_constant("irb") end def get_constant(name) const_name = { "pry" => :Pry, "ripl" => :Ripl, "irb" => :IRB, }[name] Object.const_get(const_name) rescue NameError Bundler.ui.error "Could not find constant #{const_name}" exit 1 end end end PKu]'bundler-2.2.24/lib/bundler/cli/check.rbnu[# frozen_string_literal: true module Bundler class CLI::Check attr_reader :options def initialize(options) @options = options end def run Bundler.settings.set_command_option_if_given :path, options[:path] definition = Bundler.definition definition.validate_runtime! begin definition.resolve_only_locally! not_installed = definition.missing_specs rescue GemNotFound, VersionConflict Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies." Bundler.ui.warn "Install missing gems with `bundle install`." exit 1 end if not_installed.any? Bundler.ui.error "The following gems are missing" not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" } Bundler.ui.warn "Install missing gems with `bundle install`" exit 1 elsif !Bundler.default_lockfile.file? && Bundler.frozen_bundle? Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present" exit 1 else Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"] Bundler.ui.info "The Gemfile's dependencies are satisfied" end end end end PKu]j&bundler-2.2.24/lib/bundler/cli/show.rbnu[# frozen_string_literal: true module Bundler class CLI::Show attr_reader :options, :gem_name, :latest_specs def initialize(options, gem_name) @options = options @gem_name = gem_name @verbose = options[:verbose] || options[:outdated] @latest_specs = fetch_latest_specs if @verbose end def run Bundler.ui.silence do Bundler.definition.validate_runtime! Bundler.load.lock end if gem_name if gem_name == "bundler" path = File.expand_path("../../../..", __FILE__) else spec = Bundler::CLI::Common.select_spec(gem_name, :regex_match) return unless spec path = spec.full_gem_path unless File.directory?(path) return Bundler.ui.warn "The gem #{gem_name} has been deleted. It was installed at: #{path}" end end return Bundler.ui.info(path) end if options[:paths] Bundler.load.specs.sort_by(&:name).map do |s| Bundler.ui.info s.full_gem_path end else Bundler.ui.info "Gems included by the bundle:" Bundler.load.specs.sort_by(&:name).each do |s| desc = " * #{s.name} (#{s.version}#{s.git_version})" if @verbose latest = latest_specs.find {|l| l.name == s.name } Bundler.ui.info <<-END.gsub(/^ +/, "") #{desc} \tSummary: #{s.summary || "No description available."} \tHomepage: #{s.homepage || "No website available."} \tStatus: #{outdated?(s, latest) ? "Outdated - #{s.version} < #{latest.version}" : "Up to date"} END else Bundler.ui.info desc end end end end private def fetch_latest_specs definition = Bundler.definition(true) if options[:outdated] Bundler.ui.info "Fetching remote specs for outdated check...\n\n" Bundler.ui.silence { definition.resolve_remotely! } else definition.resolve_with_cache! end Bundler.reset! definition.specs end def outdated?(current, latest) return false unless latest Gem::Version.new(current.version) < Gem::Version.new(latest.version) end end end PKu]`K&bundler-2.2.24/lib/bundler/cli/lock.rbnu[# frozen_string_literal: true module Bundler class CLI::Lock attr_reader :options def initialize(options) @options = options end def run unless Bundler.default_gemfile Bundler.ui.error "Unable to find a Gemfile to lock" exit 1 end print = options[:print] ui = Bundler.ui Bundler.ui = UI::Silent.new if print Bundler::Fetcher.disable_endpoint = options["full-index"] update = options[:update] conservative = options[:conservative] if update.is_a?(Array) # unlocking specific gems Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update) update = { :gems => update, :conservative => conservative } elsif update update = { :conservative => conservative } if conservative end definition = Bundler.definition(update) Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update] options["remove-platform"].each do |platform| definition.remove_platform(platform) end options["add-platform"].each do |platform_string| platform = Gem::Platform.new(platform_string) if platform.to_s == "unknown" Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \ "and adding it will likely lead to resolution errors" end definition.add_platform(platform) end if definition.platforms.empty? raise InvalidOption, "Removing all platforms from the bundle is not allowed" end definition.resolve_remotely! unless options[:local] if print puts definition.to_lock else file = options[:lockfile] file = file ? File.expand_path(file) : Bundler.default_lockfile puts "Writing lockfile to #{file}" definition.lock(file) end Bundler.ui = ui end end end PKu])``'bundler-2.2.24/lib/bundler/cli/clean.rbnu[# frozen_string_literal: true module Bundler class CLI::Clean attr_reader :options def initialize(options) @options = options end def run require_path_or_force unless options[:"dry-run"] Bundler.load.clean(options[:"dry-run"]) end protected def require_path_or_force return unless Bundler.use_system_gems? && !options[:force] raise InvalidOption, "Cleaning all the gems on your system is dangerous! " \ "If you're sure you want to remove every system gem not in this " \ "bundle, run `bundle clean --force`." end end end PKu]m/Ċ&bundler-2.2.24/lib/bundler/cli/init.rbnu[# frozen_string_literal: true module Bundler class CLI::Init attr_reader :options def initialize(options) @options = options end def run if File.exist?(gemfile) Bundler.ui.error "#{gemfile} already exists at #{File.expand_path(gemfile)}" exit 1 end unless File.writable?(Dir.pwd) Bundler.ui.error "Can not create #{gemfile} as the current directory is not writable." exit 1 end if options[:gemspec] gemspec = File.expand_path(options[:gemspec]) unless File.exist?(gemspec) Bundler.ui.error "Gem specification #{gemspec} doesn't exist" exit 1 end spec = Bundler.load_gemspec_uncached(gemspec) File.open(gemfile, "wb") do |file| file << "# Generated from #{gemspec}\n" file << spec.to_gemfile end else FileUtils.cp(File.expand_path("../../templates/#{gemfile}", __FILE__), gemfile) end puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}" end private def gemfile @gemfile ||= Bundler.preferred_gemfile_name end end end PKu]Ak(bundler-2.2.24/lib/bundler/cli/plugin.rbnu[# frozen_string_literal: true require_relative "../vendored_thor" module Bundler class CLI::Plugin < Thor desc "install PLUGINS", "Install the plugin from the source" long_desc <<-D Install plugins either from the rubygems source provided (with --source option) or from a git source provided with --git (for remote repos) or --local_git (for local repos). If no sources are provided, it uses Gem.sources D method_option "source", :type => :string, :default => nil, :banner => "URL of the RubyGems source to fetch the plugin from" method_option "version", :type => :string, :default => nil, :banner => "The version of the plugin to fetch" method_option "git", :type => :string, :default => nil, :banner => "URL of the git repo to fetch from" method_option "local_git", :type => :string, :default => nil, :banner => "Path of the local git repo to fetch from" method_option "branch", :type => :string, :default => nil, :banner => "The git branch to checkout" method_option "ref", :type => :string, :default => nil, :banner => "The git revision to check out" def install(*plugins) Bundler::Plugin.install(plugins, options) end desc "uninstall PLUGINS", "Uninstall the plugins" long_desc <<-D Uninstall given list of plugins. To uninstall all the plugins, use -all option. D method_option "all", :type => :boolean, :default => nil, :banner => "Uninstall all the installed plugins. If no plugin is installed, then it does nothing." def uninstall(*plugins) Bundler::Plugin.uninstall(plugins, options) end desc "list", "List the installed plugins and available commands" def list Bundler::Plugin.list end end end PKu]N  &bundler-2.2.24/lib/bundler/cli/exec.rbnu[# frozen_string_literal: true require_relative "../current_ruby" module Bundler class CLI::Exec attr_reader :options, :args, :cmd TRAPPED_SIGNALS = %w[INT].freeze def initialize(options, args) @options = options @cmd = args.shift @args = args if !Bundler.current_ruby.jruby? @args << { :close_others => !options.keep_file_descriptors? } elsif options.keep_file_descriptors? Bundler.ui.warn "Ruby version #{RUBY_VERSION} defaults to keeping non-standard file descriptors on Kernel#exec." end end def run validate_cmd! SharedHelpers.set_bundle_environment if bin_path = Bundler.which(cmd) if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path) return kernel_load(bin_path, *args) end kernel_exec(bin_path, *args) else # exec using the given command kernel_exec(cmd, *args) end end private def validate_cmd! return unless cmd.nil? Bundler.ui.error "bundler: exec needs a command to run" exit 128 end def kernel_exec(*args) Kernel.exec(*args) rescue Errno::EACCES, Errno::ENOEXEC Bundler.ui.error "bundler: not executable: #{cmd}" exit 126 rescue Errno::ENOENT Bundler.ui.error "bundler: command not found: #{cmd}" Bundler.ui.warn "Install missing gem executables with `bundle install`" exit 127 end def kernel_load(file, *args) args.pop if args.last.is_a?(Hash) ARGV.replace(args) $0 = file Process.setproctitle(process_title(file, args)) if Process.respond_to?(:setproctitle) require_relative "../setup" TRAPPED_SIGNALS.each {|s| trap(s, "DEFAULT") } Kernel.load(file) rescue SystemExit, SignalException raise rescue Exception # rubocop:disable Lint/RescueException Bundler.ui.error "bundler: failed to load command: #{cmd} (#{file})" Bundler::FriendlyErrors.disable! raise end def process_title(file, args) "#{file} #{args.join(" ")}".strip end def ruby_shebang?(file) possibilities = [ "#!/usr/bin/env ruby\n", "#!/usr/bin/env jruby\n", "#!/usr/bin/env truffleruby\n", "#!#{Gem.ruby}\n", ] if File.zero?(file) Bundler.ui.warn "#{file} is empty" return false end first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) } possibilities.any? {|shebang| first_line.start_with?(shebang) } end end end PKu]|jj'bundler-2.2.24/lib/bundler/cli/cache.rbnu[# frozen_string_literal: true module Bundler class CLI::Cache attr_reader :options def initialize(options) @options = options end def run Bundler.ui.level = "error" if options[:quiet] Bundler.settings.set_command_option_if_given :path, options[:path] Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"] setup_cache_all install # TODO: move cache contents here now that all bundles are locked custom_path = Bundler.settings[:path] if options[:path] Bundler.settings.temporary(:cache_all_platforms => options["all-platforms"]) do Bundler.load.cache(custom_path) end end private def install require_relative "install" options = self.options.dup options["local"] = false if Bundler.settings[:cache_all_platforms] options["no-cache"] = true Bundler::CLI::Install.new(options).run end def setup_cache_all all = options.fetch(:all, Bundler.feature_flag.cache_all? || nil) Bundler.settings.set_command_option_if_given :cache_all, all end end end PKu]%4*bundler-2.2.24/lib/bundler/cli/platform.rbnu[# frozen_string_literal: true module Bundler class CLI::Platform attr_reader :options def initialize(options) @options = options end def run platforms, ruby_version = Bundler.ui.silence do locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string [Bundler.definition.platforms.map {|p| "* #{p}" }, locked_ruby_version || gemfile_ruby_version] end output = [] if options[:ruby] if ruby_version output << ruby_version else output << "No ruby version specified" end else output << "Your platform is: #{RUBY_PLATFORM}" output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}" if ruby_version output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}" begin Bundler.definition.validate_runtime! output << "Your current platform satisfies the Ruby version requirement." rescue RubyVersionMismatch => e output << e.message end else output << "Your Gemfile does not specify a Ruby version requirement." end end Bundler.ui.info output.join("\n\n") end end end PKu]22%bundler-2.2.24/lib/bundler/cli/gem.rbnu[# frozen_string_literal: true require "pathname" module Bundler class CLI Bundler.require_thor_actions include Thor::Actions end class CLI::Gem TEST_FRAMEWORK_VERSIONS = { "rspec" => "3.0", "minitest" => "5.0", "test-unit" => "3.0", }.freeze attr_reader :options, :gem_name, :thor, :name, :target def initialize(options, gem_name, thor) @options = options @gem_name = resolve_name(gem_name) @thor = thor thor.behavior = :invoke thor.destination_root = nil @name = @gem_name @target = SharedHelpers.pwd.join(gem_name) validate_ext_name if options[:ext] end def run Bundler.ui.confirm "Creating gem '#{name}'..." underscored_name = name.tr("-", "_") namespaced_path = name.tr("-", "/") constant_name = name.gsub(/-[_-]*(?![_-]|$)/) { "::" }.gsub(/([_-]+|(::)|^)(.|$)/) { $2.to_s + $3.upcase } constant_array = constant_name.split("::") use_git = Bundler.git_present? && options[:git] git_author_name = use_git ? `git config user.name`.chomp : "" git_username = use_git ? `git config github.user`.chomp : "" git_user_email = use_git ? `git config user.email`.chomp : "" github_username = if options[:github_username].nil? git_username elsif options[:github_username] == false "" else options[:github_username] end config = { :name => name, :underscored_name => underscored_name, :namespaced_path => namespaced_path, :makefile_path => "#{underscored_name}/#{underscored_name}", :constant_name => constant_name, :constant_array => constant_array, :author => git_author_name.empty? ? "TODO: Write your name" : git_author_name, :email => git_user_email.empty? ? "TODO: Write your email address" : git_user_email, :test => options[:test], :ext => options[:ext], :exe => options[:exe], :bundler_version => bundler_dependency_version, :git => use_git, :github_username => github_username.empty? ? "[USERNAME]" : github_username, :required_ruby_version => Gem.ruby_version < Gem::Version.new("2.4.a") ? "2.3.0" : "2.4.0", } ensure_safe_gem_name(name, constant_array) templates = { "#{Bundler.preferred_gemfile_name}.tt" => Bundler.preferred_gemfile_name, "lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb", "lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb", "newgem.gemspec.tt" => "#{name}.gemspec", "Rakefile.tt" => "Rakefile", "README.md.tt" => "README.md", "bin/console.tt" => "bin/console", "bin/setup.tt" => "bin/setup", } executables = %w[ bin/console bin/setup ] templates.merge!("gitignore.tt" => ".gitignore") if use_git if test_framework = ask_and_set_test_framework config[:test] = test_framework config[:test_framework_version] = TEST_FRAMEWORK_VERSIONS[test_framework] case test_framework when "rspec" templates.merge!( "rspec.tt" => ".rspec", "spec/spec_helper.rb.tt" => "spec/spec_helper.rb", "spec/newgem_spec.rb.tt" => "spec/#{namespaced_path}_spec.rb" ) config[:test_task] = :spec when "minitest" templates.merge!( "test/minitest/test_helper.rb.tt" => "test/test_helper.rb", "test/minitest/newgem_test.rb.tt" => "test/#{namespaced_path}_test.rb" ) config[:test_task] = :test when "test-unit" templates.merge!( "test/test-unit/test_helper.rb.tt" => "test/test_helper.rb", "test/test-unit/newgem_test.rb.tt" => "test/#{namespaced_path}_test.rb" ) config[:test_task] = :test end end config[:ci] = ask_and_set_ci case config[:ci] when "github" templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml") when "travis" templates.merge!("travis.yml.tt" => ".travis.yml") when "gitlab" templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml") when "circle" templates.merge!("circleci/config.yml.tt" => ".circleci/config.yml") end if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?", "This means that any other developer or company will be legally allowed to use your code " \ "for free as long as they admit you created it. You can read more about the MIT license " \ "at https://choosealicense.com/licenses/mit.") config[:mit] = true Bundler.ui.info "MIT License enabled in config" templates.merge!("LICENSE.txt.tt" => "LICENSE.txt") end if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?", "Codes of conduct can increase contributions to your project by contributors who " \ "prefer collaborative, safe spaces. You can read more about the code of conduct at " \ "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \ "of enforcing it, so be sure that you are prepared to do that. Be sure that your email " \ "address is specified as a contact in the generated code of conduct so that people know " \ "who to contact in case of a violation. For suggestions about " \ "how to enforce codes of conduct, see https://bit.ly/coc-enforcement.") config[:coc] = true Bundler.ui.info "Code of conduct enabled in config" templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") end if ask_and_set(:changelog, "Do you want to include a changelog?", "A changelog is a file which contains a curated, chronologically ordered list of notable " \ "changes for each version of a project. To make it easier for users and contributors to" \ " see precisely what notable changes have been made between each release (or version) of" \ " the project. Whether consumers or developers, the end users of software are" \ " human beings who care about what's in the software. When the software changes, people " \ "want to know why and how. see https://keepachangelog.com") config[:changelog] = true Bundler.ui.info "Changelog enabled in config" templates.merge!("CHANGELOG.md.tt" => "CHANGELOG.md") end if ask_and_set(:rubocop, "Do you want to add rubocop as a dependency for gems you generate?", "RuboCop is a static code analyzer that has out-of-the-box rules for many " \ "of the guidelines in the community style guide. " \ "For more information, see the RuboCop docs (https://docs.rubocop.org/en/stable/) " \ "and the Ruby Style Guides (https://github.com/rubocop-hq/ruby-style-guide).") config[:rubocop] = true config[:rubocop_version] = Gem.ruby_version < Gem::Version.new("2.4.a") ? "0.81.0" : "1.7" Bundler.ui.info "RuboCop enabled in config" templates.merge!("rubocop.yml.tt" => ".rubocop.yml") end templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe] if options[:ext] templates.merge!( "ext/newgem/extconf.rb.tt" => "ext/#{name}/extconf.rb", "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", "ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c" ) end if File.exist?(target) && !File.directory?(target) Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`." exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError] end if use_git Bundler.ui.info "Initializing git repo in #{target}" `git init #{target}` config[:git_default_branch] = File.read("#{target}/.git/HEAD").split("/").last.chomp end templates.each do |src, dst| destination = target.join(dst) thor.template("newgem/#{src}", destination, config) end executables.each do |file| path = target.join(file) executable = (path.stat.mode | 0o111) path.chmod(executable) end if use_git Dir.chdir(target) do `git add .` end end # Open gemspec in editor open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit] Bundler.ui.info "Gem '#{name}' was successfully created. " \ "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html" end private def resolve_name(name) SharedHelpers.pwd.join(name).basename.to_s end def ask_and_set(key, header, message) choice = options[key] choice = Bundler.settings["gem.#{key}"] if choice.nil? if choice.nil? Bundler.ui.confirm header choice = Bundler.ui.yes? "#{message} y/(n):" Bundler.settings.set_global("gem.#{key}", choice) end choice end def validate_ext_name return unless gem_name.index("-") Bundler.ui.error "You have specified a gem name which does not conform to the \n" \ "naming guidelines for C extensions. For more information, \n" \ "see the 'Extension Naming' section at the following URL:\n" \ "https://guides.rubygems.org/gems-with-extensions/\n" exit 1 end def ask_and_set_test_framework test_framework = options[:test] || Bundler.settings["gem.test"] if test_framework.to_s.empty? Bundler.ui.confirm "Do you want to generate tests with your gem?" Bundler.ui.info hint_text("test") result = Bundler.ui.ask "Enter a test framework. rspec/minitest/test-unit/(none):" if result =~ /rspec|minitest|test-unit/ test_framework = result else test_framework = false end end if Bundler.settings["gem.test"].nil? Bundler.settings.set_global("gem.test", test_framework) end if options[:test] == Bundler.settings["gem.test"] Bundler.ui.info "#{options[:test]} is already configured, ignoring --test flag." end test_framework end def hint_text(setting) if Bundler.settings["gem.#{setting}"] == false "Your choice will only be applied to this gem." else "Future `bundle gem` calls will use your choice. " \ "This setting can be changed anytime with `bundle config gem.#{setting}`." end end def ask_and_set_ci ci_template = options[:ci] || Bundler.settings["gem.ci"] if ci_template.to_s.empty? Bundler.ui.confirm "Do you want to set up continuous integration for your gem? " \ "Supported services:\n" \ "* CircleCI: https://circleci.com/\n" \ "* GitHub Actions: https://github.com/features/actions\n" \ "* GitLab CI: https://docs.gitlab.com/ee/ci/\n" \ "* Travis CI: https://travis-ci.org/\n" \ "\n" Bundler.ui.info hint_text("ci") result = Bundler.ui.ask "Enter a CI service. github/travis/gitlab/circle/(none):" if result =~ /github|travis|gitlab|circle/ ci_template = result else ci_template = false end end if Bundler.settings["gem.ci"].nil? Bundler.settings.set_global("gem.ci", ci_template) end if options[:ci] == Bundler.settings["gem.ci"] Bundler.ui.info "#{options[:ci]} is already configured, ignoring --ci flag." end ci_template end def bundler_dependency_version v = Gem::Version.new(Bundler::VERSION) req = v.segments[0..1] req << "a" if v.prerelease? req.join(".") end def ensure_safe_gem_name(name, constant_array) if name =~ /^\d/ Bundler.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers." exit 1 end constant_name = constant_array.join("::") existing_constant = constant_array.inject(Object) do |c, s| defined = begin c.const_defined?(s) rescue NameError Bundler.ui.error "Invalid gem name #{name} -- `#{constant_name}` is an invalid constant name" exit 1 end (defined && c.const_get(s)) || break end return unless existing_constant Bundler.ui.error "Invalid gem name #{name} constant #{constant_name} is already in use. Please choose another gem name." exit 1 end def open_editor(editor, file) thor.run(%(#{editor} "#{file}")) end end end PKu]lqOww(bundler-2.2.24/lib/bundler/cli/inject.rbnu[# frozen_string_literal: true module Bundler class CLI::Inject attr_reader :options, :name, :version, :group, :source, :gems def initialize(options, name, version) @options = options @name = name @version = version || last_version_number @group = options[:group].split(",") unless options[:group].nil? @source = options[:source] @gems = [] end def run # The required arguments allow Thor to give useful feedback when the arguments # are incorrect. This adds those first two arguments onto the list as a whole. gems.unshift(source).unshift(group).unshift(version).unshift(name) # Build an array of Dependency objects out of the arguments deps = [] # when `inject` support addition of more than one gem, then this loop will # help. Currently this loop is running once. gems.each_slice(4) do |gem_name, gem_version, gem_group, gem_source| ops = Gem::Requirement::OPS.map {|key, _val| key } has_op = ops.any? {|op| gem_version.start_with? op } gem_version = "~> #{gem_version}" unless has_op deps << Bundler::Dependency.new(gem_name, gem_version, "group" => gem_group, "source" => gem_source) end added = Injector.inject(deps, options) if added.any? Bundler.ui.confirm "Added to Gemfile:" Bundler.ui.confirm(added.map do |d| name = "'#{d.name}'" requirement = ", '#{d.requirement}'" group = ", :group => #{d.groups.inspect}" if d.groups != Array(:default) source = ", :source => '#{d.source}'" unless d.source.nil? %(gem #{name}#{requirement}#{group}#{source}) end.join("\n")) else Bundler.ui.confirm "All gems were already present in the Gemfile" end end private def last_version_number definition = Bundler.definition(true) definition.resolve_remotely! specs = definition.index[name].sort_by(&:version) unless options[:pre] specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } end spec = specs.last spec.version.to_s end end end PKu];.>>%bundler-2.2.24/lib/bundler/cli/viz.rbnu[# frozen_string_literal: true module Bundler class CLI::Viz attr_reader :options, :gem_name def initialize(options) @options = options end def run # make sure we get the right `graphviz`. There is also a `graphviz` # gem we're not built to support gem "ruby-graphviz" require "graphviz" options[:without] = options[:without].join(":").tr(" ", ":").split(":") output_file = File.expand_path(options[:file]) graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format], options[:without]) graph.viz rescue LoadError => e Bundler.ui.error e.inspect Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" Bundler.ui.warn "`gem install ruby-graphviz`" rescue StandardError => e raise unless e.message =~ /GraphViz not installed or dot not in PATH/ Bundler.ui.error e.message Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`." end end end PKu]V9&bundler-2.2.24/lib/bundler/cli/fund.rbnu[# frozen_string_literal: true module Bundler class CLI::Fund attr_reader :options def initialize(options) @options = options end def run Bundler.definition.validate_runtime! groups = Array(options[:group]).map(&:to_sym) deps = if groups.any? Bundler.definition.dependencies_for(groups) else Bundler.definition.current_dependencies end fund_info = deps.each_with_object([]) do |dep, arr| spec = Bundler.definition.specs[dep.name].first if spec.metadata.key?("funding_uri") arr << "* #{spec.name} (#{spec.version})\n Funding: #{spec.metadata["funding_uri"]}" end end if fund_info.empty? Bundler.ui.info "None of the installed gems you directly depend on are looking for funding." else Bundler.ui.info fund_info.join("\n") end end end end PKu](bundler-2.2.24/lib/bundler/cli/common.rbnu[# frozen_string_literal: true module Bundler module CLI::Common def self.output_post_install_messages(messages) return if Bundler.settings["ignore_messages"] messages.to_a.each do |name, msg| print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"] end end def self.print_post_install_message(name, msg) Bundler.ui.confirm "Post-install message from #{name}:" Bundler.ui.info msg end def self.output_fund_metadata_summary definition = Bundler.definition current_dependencies = definition.requested_dependencies current_specs = definition.specs count = current_dependencies.count {|dep| current_specs[dep.name].first.metadata.key?("funding_uri") } return if count.zero? intro = count > 1 ? "#{count} installed gems you directly depend on are" : "#{count} installed gem you directly depend on is" message = "#{intro} looking for funding.\n Run `bundle fund` for details" Bundler.ui.info message end def self.output_without_groups_message(command) return if Bundler.settings[:without].empty? Bundler.ui.confirm without_groups_message(command) end def self.without_groups_message(command) command_in_past_tense = command == :install ? "installed" : "updated" groups = Bundler.settings[:without] "Gems in the #{verbalize_groups(groups)} were not #{command_in_past_tense}." end def self.verbalize_groups(groups) groups.map!{|g| "'#{g}'" } group_list = [groups[0...-1].join(", "), groups[-1..-1]]. reject {|s| s.to_s.empty? }.join(" and ") group_str = groups.size == 1 ? "group" : "groups" "#{group_str} #{group_list}" end def self.select_spec(name, regex_match = nil) specs = [] regexp = Regexp.new(name) if regex_match Bundler.definition.specs.each do |spec| return spec if spec.name == name specs << spec if regexp && spec.name =~ regexp end case specs.count when 0 dep_in_other_group = Bundler.definition.current_dependencies.find {|dep|dep.name == name } if dep_in_other_group raise GemNotFound, "Could not find gem '#{name}', because it's in the #{verbalize_groups(dep_in_other_group.groups)}, configured to be ignored." else raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) end when 1 specs.first else ask_for_spec_from(specs) end rescue RegexpError raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) end def self.ask_for_spec_from(specs) specs.each_with_index do |spec, index| Bundler.ui.info "#{index.succ} : #{spec.name}", true end Bundler.ui.info "0 : - exit -", true num = Bundler.ui.ask("> ").to_i num > 0 ? specs[num - 1] : nil end def self.gem_not_found_message(missing_gem_name, alternatives) require_relative "../similarity_detector" message = "Could not find gem '#{missing_gem_name}'." alternate_names = alternatives.map {|a| a.respond_to?(:name) ? a.name : a } suggestions = SimilarityDetector.new(alternate_names).similar_word_list(missing_gem_name) message += "\nDid you mean #{suggestions}?" if suggestions message end def self.ensure_all_gems_in_lockfile!(names, locked_gems = Bundler.locked_gems) return unless locked_gems locked_names = locked_gems.specs.map(&:name).uniq names.-(locked_names).each do |g| raise GemNotFound, gem_not_found_message(g, locked_names) end end def self.configure_gem_version_promoter(definition, options) patch_level = patch_level_options(options) patch_level << :patch if patch_level.empty? && Bundler.settings[:prefer_patch] raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1 definition.gem_version_promoter.tap do |gvp| gvp.level = patch_level.first || :major gvp.strict = options[:strict] || options["update-strict"] || options["filter-strict"] end end def self.patch_level_options(options) [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) } end def self.clean_after_install? clean = Bundler.settings[:clean] return clean unless clean.nil? clean ||= Bundler.feature_flag.auto_clean_without_path? && Bundler.settings[:path].nil? clean &&= !Bundler.use_system_gems? clean end end end PKu]RR&bundler-2.2.24/lib/bundler/cli/list.rbnu[# frozen_string_literal: true module Bundler class CLI::List def initialize(options) @options = options @without_group = options["without-group"].map(&:to_sym) @only_group = options["only-group"].map(&:to_sym) end def run raise InvalidOption, "The `--only-group` and `--without-group` options cannot be used together" if @only_group.any? && @without_group.any? raise InvalidOption, "The `--name-only` and `--paths` options cannot be used together" if @options["name-only"] && @options[:paths] specs = if @only_group.any? || @without_group.any? filtered_specs_by_groups else Bundler.load.specs end.reject {|s| s.name == "bundler" }.sort_by(&:name) return Bundler.ui.info "No gems in the Gemfile" if specs.empty? return specs.each {|s| Bundler.ui.info s.name } if @options["name-only"] return specs.each {|s| Bundler.ui.info s.full_gem_path } if @options["paths"] Bundler.ui.info "Gems included by the bundle:" specs.each {|s| Bundler.ui.info " * #{s.name} (#{s.version}#{s.git_version})" } Bundler.ui.info "Use `bundle info` to print more detailed information about a gem" end private def verify_group_exists(groups) (@without_group + @only_group).each do |group| raise InvalidOption, "`#{group}` group could not be found." unless groups.include?(group) end end def filtered_specs_by_groups definition = Bundler.definition groups = definition.groups verify_group_exists(groups) show_groups = if @without_group.any? groups.reject {|g| @without_group.include?(g) } elsif @only_group.any? groups.select {|g| @only_group.include?(g) } else groups end.map(&:to_sym) definition.specs_for(show_groups) end end end PKu]&bundler-2.2.24/lib/bundler/cli/open.rbnu[# frozen_string_literal: true require "shellwords" module Bundler class CLI::Open attr_reader :options, :name def initialize(options, name) @options = options @name = name end def run editor = [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? } return Bundler.ui.info("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR") unless editor return unless spec = Bundler::CLI::Common.select_spec(name, :regex_match) if spec.default_gem? Bundler.ui.info "Unable to open #{name} because it's a default gem, so the directory it would normally be installed to does not exist." else path = spec.full_gem_path Dir.chdir(path) do command = Shellwords.split(editor) + [path] Bundler.with_original_env do system(*command) end || Bundler.ui.info("Could not run '#{command.join(" ")}'") end end end end end PKu]lww(bundler-2.2.24/lib/bundler/cli/remove.rbnu[# frozen_string_literal: true module Bundler class CLI::Remove def initialize(gems, options) @gems = gems @options = options end def run raise InvalidOption, "Please specify gems to remove." if @gems.empty? Injector.remove(@gems, {}) Installer.install(Bundler.root, Bundler.definition) if @options["install"] end end end PKu] (bundler-2.2.24/lib/bundler/cli/doctor.rbnu[# frozen_string_literal: true require "rbconfig" module Bundler class CLI::Doctor DARWIN_REGEX = /\s+(.+) \(compatibility /.freeze LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/.freeze attr_reader :options def initialize(options) @options = options end def otool_available? Bundler.which("otool") end def ldd_available? Bundler.which("ldd") end def dylibs_darwin(path) output = `/usr/bin/otool -L "#{path}"`.chomp dylibs = output.split("\n")[1..-1].map {|l| l.match(DARWIN_REGEX).captures[0] }.uniq # ignore @rpath and friends dylibs.reject {|dylib| dylib.start_with? "@" } end def dylibs_ldd(path) output = `/usr/bin/ldd "#{path}"`.chomp output.split("\n").map do |l| match = l.match(LDD_REGEX) next if match.nil? match.captures[0] end.compact end def dylibs(path) case RbConfig::CONFIG["host_os"] when /darwin/ return [] unless otool_available? dylibs_darwin(path) when /(linux|solaris|bsd)/ return [] unless ldd_available? dylibs_ldd(path) else # Windows, etc. Bundler.ui.warn("Dynamic library check not supported on this platform.") [] end end def bundles_for_gem(spec) Dir.glob("#{spec.full_gem_path}/**/*.bundle") end def check! require_relative "check" Bundler::CLI::Check.new({}).run end def run Bundler.ui.level = "error" if options[:quiet] Bundler.settings.validate! check! definition = Bundler.definition broken_links = {} definition.specs.each do |spec| bundles_for_gem(spec).each do |bundle| bad_paths = dylibs(bundle).select {|f| !File.exist?(f) } if bad_paths.any? broken_links[spec] ||= [] broken_links[spec].concat(bad_paths) end end end permissions_valid = check_home_permissions if broken_links.any? message = "The following gems are missing OS dependencies:" broken_links.map do |spec, paths| paths.uniq.map do |path| "\n * #{spec.name}: #{path}" end end.flatten.sort.each {|m| message += m } raise ProductionError, message elsif !permissions_valid Bundler.ui.info "No issues found with the installed bundle" end end private def check_home_permissions require "find" files_not_readable_or_writable = [] files_not_rw_and_owned_by_different_user = [] files_not_owned_by_current_user_but_still_rw = [] broken_symlinks = [] Find.find(Bundler.bundle_path.to_s).each do |f| if !File.exist?(f) broken_symlinks << f elsif !File.writable?(f) || !File.readable?(f) if File.stat(f).uid != Process.uid files_not_rw_and_owned_by_different_user << f else files_not_readable_or_writable << f end elsif File.stat(f).uid != Process.uid files_not_owned_by_current_user_but_still_rw << f end end ok = true if broken_symlinks.any? Bundler.ui.warn "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{broken_symlinks.join("\n - ")}" ok = false end if files_not_owned_by_current_user_but_still_rw.any? Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ "user, but are still readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" ok = false end if files_not_rw_and_owned_by_different_user.any? Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ "user, and are not readable/writable. These files are:\n - #{files_not_rw_and_owned_by_different_user.join("\n - ")}" ok = false end if files_not_readable_or_writable.any? Bundler.ui.warn "Files exist in the Bundler home that are not " \ "readable/writable by the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" ok = false end ok end end end PKu],(bundler-2.2.24/lib/bundler/cli/update.rbnu[# frozen_string_literal: true module Bundler class CLI::Update attr_reader :options, :gems def initialize(options, gems) @options = options @gems = gems end def run Bundler.ui.level = "error" if options[:quiet] Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? sources = Array(options[:source]) groups = Array(options[:group]).map(&:to_sym) full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !options[:bundler] if full_update && !options[:all] if Bundler.feature_flag.update_requires_all_flag? raise InvalidOption, "To update everything, pass the `--all` flag." end SharedHelpers.major_deprecation 3, "Pass --all to `bundle update` to update everything" elsif !full_update && options[:all] raise InvalidOption, "Cannot specify --all along with specific options." end conservative = options[:conservative] if full_update if conservative Bundler.definition(:conservative => conservative) else Bundler.definition(true) end else unless Bundler.default_lockfile.exist? raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \ "Run `bundle install` to update and install the bundled gems." end Bundler::CLI::Common.ensure_all_gems_in_lockfile!(gems) if groups.any? deps = Bundler.definition.dependencies.select {|d| (d.groups & groups).any? } gems.concat(deps.map(&:name)) end Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby], :conservative => conservative, :bundler => options[:bundler]) end Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) Bundler::Fetcher.disable_endpoint = options["full-index"] opts = options.dup opts["update"] = true opts["local"] = options[:local] Bundler.settings.set_command_option_if_given :jobs, opts["jobs"] Bundler.definition.validate_runtime! if locked_gems = Bundler.definition.locked_gems previous_locked_info = locked_gems.specs.reduce({}) do |h, s| h[s.name] = { :spec => s, :version => s.version, :source => s.source.to_s } h end end installer = Installer.install Bundler.root, Bundler.definition, opts Bundler.load.cache if Bundler.app_cache.exist? if CLI::Common.clean_after_install? require_relative "clean" Bundler::CLI::Clean.new(options).run end if locked_gems gems.each do |name| locked_info = previous_locked_info[name] next unless locked_info locked_spec = locked_info[:spec] new_spec = Bundler.definition.specs[name].first unless new_spec unless locked_spec.match_platform(Bundler.local_platform) Bundler.ui.warn "Bundler attempted to update #{name} but it was not considered because it is for a different platform from the current one" end next end locked_source = locked_info[:source] new_source = new_spec.source.to_s next if locked_source != new_source new_version = new_spec.version locked_version = locked_info[:version] if new_version < locked_version Bundler.ui.warn "Note: #{name} version regressed from #{locked_version} to #{new_version}" elsif new_version == locked_version Bundler.ui.warn "Bundler attempted to update #{name} but its version stayed the same" end end end Bundler.ui.confirm "Bundle updated!" Bundler::CLI::Common.output_without_groups_message(:update) Bundler::CLI::Common.output_post_install_messages installer.post_install_messages Bundler::CLI::Common.output_fund_metadata_summary end end end PKu]="$"$*bundler-2.2.24/lib/bundler/cli/outdated.rbnu[# frozen_string_literal: true module Bundler class CLI::Outdated attr_reader :options, :gems, :options_include_groups, :filter_options_patch, :sources, :strict attr_accessor :outdated_gems def initialize(options, gems) @options = options @gems = gems @sources = Array(options[:source]) @filter_options_patch = options.keys & %w[filter-major filter-minor filter-patch] @outdated_gems = [] @options_include_groups = [:group, :groups].any? do |v| options.keys.include?(v.to_s) end # the patch level options imply strict is also true. It wouldn't make # sense otherwise. @strict = options["filter-strict"] || Bundler::CLI::Common.patch_level_options(options).any? end def run check_for_deployment_mode! gems.each do |gem_name| Bundler::CLI::Common.select_spec(gem_name) end Bundler.definition.validate_runtime! current_specs = Bundler.ui.silence { Bundler.definition.resolve } current_dependencies = Bundler.ui.silence do Bundler.load.dependencies.map {|dep| [dep.name, dep] }.to_h end definition = if gems.empty? && sources.empty? # We're doing a full update Bundler.definition(true) else Bundler.definition(:gems => gems, :sources => sources) end Bundler::CLI::Common.configure_gem_version_promoter( Bundler.definition, options ) definition_resolution = proc do options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely! end if options[:parseable] Bundler.ui.silence(&definition_resolution) else definition_resolution.call end Bundler.ui.info "" # Loop through the current specs gemfile_specs, dependency_specs = current_specs.partition do |spec| current_dependencies.key? spec.name end specs = if options["only-explicit"] gemfile_specs else gemfile_specs + dependency_specs end specs.sort_by(&:name).uniq(&:name).each do |current_spec| next unless gems.empty? || gems.include?(current_spec.name) active_spec = retrieve_active_spec(definition, current_spec) next unless active_spec next unless filter_options_patch.empty? || update_present_via_semver_portions(current_spec, active_spec, options) gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version) next unless gem_outdated || (current_spec.git_version != active_spec.git_version) dependency = current_dependencies[current_spec.name] groups = "" if dependency && !options[:parseable] groups = dependency.groups.join(", ") end outdated_gems << { :active_spec => active_spec, :current_spec => current_spec, :dependency => dependency, :groups => groups, } end if outdated_gems.empty? unless options[:parseable] Bundler.ui.info(nothing_outdated_message) end else if options_include_groups relevant_outdated_gems = outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems| contains_group = groups.split(", ").include?(options[:group]) next unless options[:groups] || contains_group gems end.compact if options[:parseable] relevant_outdated_gems.each do |gems| print_gems(gems) end else print_gems_table(relevant_outdated_gems) end elsif options[:parseable] print_gems(outdated_gems) else print_gems_table(outdated_gems) end exit 1 end end private def groups_text(group_text, groups) "#{group_text}#{groups.split(",").size > 1 ? "s" : ""} \"#{groups}\"" end def nothing_outdated_message if filter_options_patch.any? display = filter_options_patch.map do |o| o.sub("filter-", "") end.join(" or ") "No #{display} updates to display.\n" else "Bundle up to date!\n" end end def retrieve_active_spec(definition, current_spec) active_spec = definition.resolve.find_by_name_and_platform(current_spec.name, current_spec.platform) return unless active_spec return active_spec if strict active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } end active_specs.last end def print_gems(gems_list) gems_list.each do |gem| print_gem( gem[:current_spec], gem[:active_spec], gem[:dependency], gem[:groups], ) end end def print_gems_table(gems_list) data = gems_list.map do |gem| gem_column_for( gem[:current_spec], gem[:active_spec], gem[:dependency], gem[:groups], ) end print_indented([table_header] + data) end def print_gem(current_spec, active_spec, dependency, groups) spec_version = "#{active_spec.version}#{active_spec.git_version}" spec_version += " (from #{active_spec.loaded_from})" if Bundler.ui.debug? && active_spec.loaded_from current_version = "#{current_spec.version}#{current_spec.git_version}" if dependency && dependency.specific? dependency_version = %(, requested #{dependency.requirement}) end spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \ "installed #{current_version}#{dependency_version})" output_message = if options[:parseable] spec_outdated_info.to_s elsif options_include_groups || groups.empty? " * #{spec_outdated_info}" else " * #{spec_outdated_info} in #{groups_text("group", groups)}" end Bundler.ui.info output_message.rstrip end def gem_column_for(current_spec, active_spec, dependency, groups) current_version = "#{current_spec.version}#{current_spec.git_version}" spec_version = "#{active_spec.version}#{active_spec.git_version}" dependency = dependency.requirement if dependency ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s] ret_val << active_spec.loaded_from.to_s if Bundler.ui.debug? ret_val end def check_for_deployment_mode! return unless Bundler.frozen_bundle? suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any? "bundle config unset frozen" elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? "bundle config unset deployment" end raise ProductionError, "You are trying to check outdated gems in " \ "deployment mode. Run `bundle outdated` elsewhere.\n" \ "\nIf this is a development machine, remove the " \ "#{Bundler.default_gemfile} freeze" \ "\nby running `#{suggested_command}`." end def update_present_via_semver_portions(current_spec, active_spec, options) current_major = current_spec.version.segments.first active_major = active_spec.version.segments.first update_present = false update_present = active_major > current_major if options["filter-major"] if !update_present && (options["filter-minor"] || options["filter-patch"]) && current_major == active_major current_minor = get_version_semver_portion_value(current_spec, 1) active_minor = get_version_semver_portion_value(active_spec, 1) update_present = active_minor > current_minor if options["filter-minor"] if !update_present && options["filter-patch"] && current_minor == active_minor current_patch = get_version_semver_portion_value(current_spec, 2) active_patch = get_version_semver_portion_value(active_spec, 2) update_present = active_patch > current_patch end end update_present end def get_version_semver_portion_value(spec, version_portion_index) version_section = spec.version.segments[version_portion_index, 1] version_section.to_a[0].to_i end def print_indented(matrix) header = matrix[0] data = matrix[1..-1] column_sizes = Array.new(header.size) do |index| matrix.max_by {|row| row[index].length }[index].length end Bundler.ui.info justify(header, column_sizes) data.sort_by! {|row| row[0] } data.each do |row| Bundler.ui.info justify(row, column_sizes) end end def table_header header = ["Gem", "Current", "Latest", "Requested", "Groups"] header << "Path" if Bundler.ui.debug? header end def justify(row, sizes) row.each_with_index.map do |element, index| element.ljust(sizes[index]) end.join(" ").strip + "\n" end end end PKu]w#w#)bundler-2.2.24/lib/bundler/cli/install.rbnu[# frozen_string_literal: true module Bundler class CLI::Install attr_reader :options def initialize(options) @options = options end def run Bundler.ui.level = "error" if options[:quiet] warn_if_root Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD # Disable color in deployment mode Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment] check_for_options_conflicts check_trust_policy if options[:deployment] || options[:frozen] || Bundler.frozen_bundle? unless Bundler.default_lockfile.exist? flag = "--deployment flag" if options[:deployment] flag ||= "--frozen flag" if options[:frozen] flag ||= "deployment setting" raise ProductionError, "The #{flag} requires a #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}. Please make " \ "sure you have checked your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} into version control " \ "before deploying." end options[:local] = true if Bundler.app_cache.exist? Bundler.settings.set_command_option :deployment, true if options[:deployment] Bundler.settings.set_command_option :frozen, true if options[:frozen] end # When install is called with --no-deployment, disable deployment mode if options[:deployment] == false Bundler.settings.set_command_option :frozen, nil options[:system] = true end normalize_settings Bundler::Fetcher.disable_endpoint = options["full-index"] if options["binstubs"] Bundler::SharedHelpers.major_deprecation 2, "The --binstubs option will be removed in favor of `bundle binstubs --all`" end Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? definition = Bundler.definition definition.validate_runtime! installer = Installer.install(Bundler.root, definition, options) Bundler.settings.temporary(:cache_all_platforms => options[:local] ? false : Bundler.settings[:cache_all_platforms]) do Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle? end Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}." Bundler::CLI::Common.output_without_groups_message(:install) if Bundler.use_system_gems? Bundler.ui.confirm "Use `bundle info [gemname]` to see where a bundled gem is installed." else relative_path = Bundler.configured_bundle_path.base_path_relative_to_pwd Bundler.ui.confirm "Bundled gems are installed into `#{relative_path}`" end Bundler::CLI::Common.output_post_install_messages installer.post_install_messages warn_ambiguous_gems if CLI::Common.clean_after_install? require_relative "clean" Bundler::CLI::Clean.new(options).run end Bundler::CLI::Common.output_fund_metadata_summary rescue GemNotFound, VersionConflict => e if options[:local] && Bundler.app_cache.exist? Bundler.ui.warn "Some gems seem to be missing from your #{Bundler.settings.app_cache_path} directory." end unless Bundler.definition.has_rubygems_remotes? Bundler.ui.warn <<-WARN, :wrap => true Your Gemfile has no gem server sources. If you need gems that are \ not already on your machine, add a line like this to your Gemfile: source 'https://rubygems.org' WARN end raise e rescue Gem::InvalidSpecificationException => e Bundler.ui.warn "You have one or more invalid gemspecs that need to be fixed." raise e end private def warn_if_root return if Bundler.settings[:silence_root_warning] || Gem.win_platform? || !Process.uid.zero? Bundler.ui.warn "Don't run Bundler as root. Bundler can ask for sudo " \ "if it is needed, and installing your bundle as root will break this " \ "application for all non-root users on this machine.", :wrap => true end def dependencies_count_for(definition) count = definition.dependencies.count "#{count} Gemfile #{count == 1 ? "dependency" : "dependencies"}" end def gems_installed_for(definition) count = definition.specs.count "#{count} #{count == 1 ? "gem" : "gems"} now installed" end def check_for_group_conflicts_in_cli_options conflicting_groups = Array(options[:without]) & Array(options[:with]) return if conflicting_groups.empty? raise InvalidOption, "You can't list a group in both with and without." \ " The offending groups are: #{conflicting_groups.join(", ")}." end def check_for_options_conflicts if (options[:path] || options[:deployment]) && options[:system] error_message = String.new error_message << "You have specified both --path as well as --system. Please choose only one option.\n" if options[:path] error_message << "You have specified both --deployment as well as --system. Please choose only one option.\n" if options[:deployment] raise InvalidOption.new(error_message) end end def check_trust_policy trust_policy = options["trust-policy"] unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy) raise InvalidOption, "RubyGems doesn't know about trust policy '#{trust_policy}'. " \ "The known policies are: #{Bundler.rubygems.security_policies.keys.join(", ")}." end Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy end def normalize_groups options[:with] &&= options[:with].join(":").tr(" ", ":").split(":") options[:without] &&= options[:without].join(":").tr(" ", ":").split(":") check_for_group_conflicts_in_cli_options Bundler.settings.set_command_option :with, nil if options[:with] == [] Bundler.settings.set_command_option :without, nil if options[:without] == [] with = options.fetch(:with, []) with |= Bundler.settings[:with].map(&:to_s) with -= options[:without] if options[:without] without = options.fetch(:without, []) without |= Bundler.settings[:without].map(&:to_s) without -= options[:with] if options[:with] options[:with] = with options[:without] = without unless Bundler.settings[:without] == options[:without] && Bundler.settings[:with] == options[:with] # need to nil them out first to get around validation for backwards compatibility Bundler.settings.set_command_option :without, nil Bundler.settings.set_command_option :with, nil Bundler.settings.set_command_option :without, options[:without] - options[:with] Bundler.settings.set_command_option :with, options[:with] end end def normalize_settings Bundler.settings.set_command_option :path, nil if options[:system] Bundler.settings.temporary(:path_relative_to_cwd => false) do Bundler.settings.set_command_option :path, "vendor/bundle" if Bundler.settings[:deployment] && Bundler.settings[:path].nil? end Bundler.settings.set_command_option_if_given :path, options[:path] Bundler.settings.temporary(:path_relative_to_cwd => false) do Bundler.settings.set_command_option :path, "bundle" if options["standalone"] && Bundler.settings[:path].nil? end bin_option = options["binstubs"] bin_option = nil if bin_option && bin_option.empty? Bundler.settings.set_command_option :bin, bin_option if options["binstubs"] Bundler.settings.set_command_option_if_given :shebang, options["shebang"] Bundler.settings.set_command_option_if_given :jobs, options["jobs"] Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"] Bundler.settings.set_command_option_if_given :no_install, options["no-install"] Bundler.settings.set_command_option_if_given :clean, options["clean"] normalize_groups options[:force] = options[:redownload] end def warn_ambiguous_gems # TODO: remove this when we drop Bundler 1.x support Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris| Bundler.ui.warn "Warning: the gem '#{name}' was found in multiple sources." Bundler.ui.warn "Installed from: #{installed_from_uri}" Bundler.ui.warn "Also found in:" also_found_in_uris.each {|uri| Bundler.ui.warn " * #{uri}" } Bundler.ui.warn "You should add a source requirement to restrict this gem to your preferred source." Bundler.ui.warn "For example:" Bundler.ui.warn " gem '#{name}', :source => '#{installed_from_uri}'" Bundler.ui.warn "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again." end end end end PKu]3LT*bundler-2.2.24/lib/bundler/cli/pristine.rbnu[# frozen_string_literal: true module Bundler class CLI::Pristine def initialize(gems) @gems = gems end def run CLI::Common.ensure_all_gems_in_lockfile!(@gems) definition = Bundler.definition definition.validate_runtime! installer = Bundler::Installer.new(Bundler.root, definition) Bundler.load.specs.each do |spec| next if spec.name == "bundler" # Source::Rubygems doesn't install bundler next if !@gems.empty? && !@gems.include?(spec.name) gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})" gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY case source = spec.source when Source::Rubygems cached_gem = spec.cache_file unless File.exist?(cached_gem) Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.") next end FileUtils.rm_rf spec.full_gem_path when Source::Git if source.local? Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is locally overridden.") next end source.remote! if extension_cache_path = source.extension_cache_path(spec) FileUtils.rm_rf extension_cache_path end FileUtils.rm_rf spec.extension_dir FileUtils.rm_rf spec.full_gem_path else Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") next end Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec end end end end PKu]Ʊe}}(bundler-2.2.24/lib/bundler/cli/config.rbnu[# frozen_string_literal: true module Bundler class CLI::Config < Thor class_option :parseable, :type => :boolean, :banner => "Use minimal formatting for more parseable output" def self.scope_options method_option :global, :type => :boolean, :banner => "Only change the global config" method_option :local, :type => :boolean, :banner => "Only change the local config" end private_class_method :scope_options desc "base NAME [VALUE]", "The Bundler 1 config interface", :hide => true scope_options method_option :delete, :type => :boolean, :banner => "delete" def base(name = nil, *value) new_args = if ARGV.size == 1 ["config", "list"] elsif ARGV.include?("--delete") ARGV.map {|arg| arg == "--delete" ? "unset" : arg } elsif ARGV.include?("--global") || ARGV.include?("--local") || ARGV.size == 3 ["config", "set", *ARGV[1..-1]] else ["config", "get", ARGV[1]] end SharedHelpers.major_deprecation 3, "Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle #{new_args.join(" ")}` instead." Base.new(options, name, value, self).run end desc "list", "List out all configured settings" def list Base.new(options, nil, nil, self).run end desc "get NAME", "Returns the value for the given key" def get(name) Base.new(options, name, nil, self).run end desc "set NAME VALUE", "Sets the given value for the given key" scope_options def set(name, value, *value_) Base.new(options, name, value_.unshift(value), self).run end desc "unset NAME", "Unsets the value for the given key" scope_options def unset(name) options[:delete] = true Base.new(options, name, nil, self).run end default_task :base class Base attr_reader :name, :value, :options, :scope, :thor def initialize(options, name, value, thor) @options = options @name = name value = Array(value) @value = value.empty? ? nil : value.join(" ") @thor = thor validate_scope! end def run unless name warn_unused_scope "Ignoring --#{scope}" confirm_all return end if options[:delete] if !explicit_scope? || scope != "global" Bundler.settings.set_local(name, nil) end if !explicit_scope? || scope != "local" Bundler.settings.set_global(name, nil) end return end if value.nil? warn_unused_scope "Ignoring --#{scope} since no value to set was given" if options[:parseable] if value = Bundler.settings[name] Bundler.ui.info("#{name}=#{value}") end return end confirm(name) return end Bundler.ui.info(message) if message Bundler.settings.send("set_#{scope}", name, new_value) end def confirm_all if @options[:parseable] thor.with_padding do Bundler.settings.all.each do |setting| val = Bundler.settings[setting] Bundler.ui.info "#{setting}=#{val}" end end else Bundler.ui.confirm "Settings are listed in order of priority. The top value will be used.\n" Bundler.settings.all.each do |setting| Bundler.ui.confirm setting show_pretty_values_for(setting) Bundler.ui.confirm "" end end end def confirm(name) Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used" show_pretty_values_for(name) end def new_value pathname = Pathname.new(value) if name.start_with?("local.") && pathname.directory? pathname.expand_path.to_s else value end end def message locations = Bundler.settings.locations(name) if @options[:parseable] "#{name}=#{new_value}" if new_value elsif scope == "global" if !locations[:local].nil? "Your application has set #{name} to #{locations[:local].inspect}. " \ "This will override the global value you are currently setting" elsif locations[:env] "You have a bundler environment variable for #{name} set to " \ "#{locations[:env].inspect}. This will take precedence over the global value you are setting" elsif !locations[:global].nil? && locations[:global] != value "You are replacing the current global value of #{name}, which is currently " \ "#{locations[:global].inspect}" end elsif scope == "local" && !locations[:local].nil? && locations[:local] != value "You are replacing the current local value of #{name}, which is currently " \ "#{locations[:local].inspect}" end end def show_pretty_values_for(setting) thor.with_padding do Bundler.settings.pretty_values_for(setting).each do |line| Bundler.ui.info line end end end def explicit_scope? @explicit_scope end def warn_unused_scope(msg) return unless explicit_scope? return if options[:parseable] Bundler.ui.warn(msg) end def validate_scope! @explicit_scope = true scopes = %w[global local].select {|s| options[s] } case scopes.size when 0 @scope = "global" @explicit_scope = false when 1 @scope = scopes.first else raise InvalidOption, "The options #{scopes.join " and "} were specified. Please only use one of the switches at a time." end end end end end PKu]RL%bundler-2.2.24/lib/bundler/cli/add.rbnu[# frozen_string_literal: true module Bundler class CLI::Add attr_reader :gems, :options, :version def initialize(options, gems) @gems = gems @options = options @options[:group] = options[:group].split(",").map(&:strip) unless options[:group].nil? @version = options[:version].split(",").map(&:strip) unless options[:version].nil? end def run validate_options! inject_dependencies perform_bundle_install unless options["skip-install"] end private def perform_bundle_install Installer.install(Bundler.root, Bundler.definition) Bundler.load.cache if Bundler.app_cache.exist? end def inject_dependencies dependencies = gems.map {|g| Bundler::Dependency.new(g, version, options) } Injector.inject(dependencies, :conservative_versioning => options[:version].nil?, # Perform conservative versioning only when version is not specified :optimistic => options[:optimistic], :strict => options[:strict]) end def validate_options! raise InvalidOption, "You can not specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic] # raise error when no gems are specified raise InvalidOption, "Please specify gems to add." if gems.empty? version.to_a.each do |v| raise InvalidOption, "Invalid gem requirement pattern '#{v}'" unless Gem::Requirement::PATTERN =~ v.to_s end end end end PKu]u)'bundler-2.2.24/lib/bundler/cli/issue.rbnu[# frozen_string_literal: true require "rbconfig" module Bundler class CLI::Issue def run Bundler.ui.info <<-EOS.gsub(/^ {8}/, "") Did you find an issue with Bundler? Before filing a new issue, be sure to check out these resources: 1. Check out our troubleshooting guide for quick fixes to common issues: https://github.com/rubygems/rubygems/blob/master/bundler/doc/TROUBLESHOOTING.md 2. Instructions for common Bundler uses can be found on the documentation site: https://bundler.io/ 3. Information about each Bundler command can be found in the Bundler man pages: https://bundler.io/man/bundle.1.html Hopefully the troubleshooting steps above resolved your problem! If things still aren't working the way you expect them to, please let us know so that we can diagnose and help fix the problem you're having. Please view the Filing Issues guide for more information: https://github.com/rubygems/rubygems/blob/master/bundler/doc/contributing/ISSUES.md EOS Bundler.ui.info Bundler::Env.report Bundler.ui.info "\n## Bundle Doctor" doctor end def doctor require_relative "doctor" Bundler::CLI::Doctor.new({}).run end end end PKu]"G*bundler-2.2.24/lib/bundler/cli/binstubs.rbnu[# frozen_string_literal: true module Bundler class CLI::Binstubs attr_reader :options, :gems def initialize(options, gems) @options = options @gems = gems end def run Bundler.definition.validate_runtime! path_option = options["path"] path_option = nil if path_option && path_option.empty? Bundler.settings.set_command_option :bin, path_option if options["path"] Bundler.settings.set_command_option_if_given :shebang, options["shebang"] installer = Installer.new(Bundler.root, Bundler.definition) installer_opts = { :force => options[:force], :binstubs_cmd => true, :all_platforms => options["all-platforms"], } if options[:all] raise InvalidOption, "Cannot specify --all with specific gems" unless gems.empty? @gems = Bundler.definition.specs.map(&:name) installer_opts.delete(:binstubs_cmd) elsif gems.empty? Bundler.ui.error "`bundle binstubs` needs at least one gem to run." exit 1 end gems.each do |gem_name| spec = Bundler.definition.specs.find {|s| s.name == gem_name } unless spec raise GemNotFound, Bundler::CLI::Common.gem_not_found_message( gem_name, Bundler.definition.specs ) end if options[:standalone] next Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") if gem_name == "bundler" Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do installer.generate_standalone_bundler_executable_stubs(spec, installer_opts) end else installer.generate_bundler_executable_stubs(spec, installer_opts) end end end end end PKu]W{ { &bundler-2.2.24/lib/bundler/cli/info.rbnu[# frozen_string_literal: true module Bundler class CLI::Info attr_reader :gem_name, :options def initialize(options, gem_name) @options = options @gem_name = gem_name end def run Bundler.ui.silence do Bundler.definition.validate_runtime! Bundler.load.lock end spec = spec_for_gem(gem_name) if spec return print_gem_path(spec) if @options[:path] print_gem_info(spec) end end private def spec_for_gem(gem_name) spec = Bundler.definition.specs.find {|s| s.name == gem_name } spec || default_gem_spec(gem_name) || Bundler::CLI::Common.select_spec(gem_name, :regex_match) end def default_gem_spec(gem_name) return unless Gem::Specification.respond_to?(:find_all_by_name) gem_spec = Gem::Specification.find_all_by_name(gem_name).last return gem_spec if gem_spec && gem_spec.respond_to?(:default_gem?) && gem_spec.default_gem? end def spec_not_found(gem_name) raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(gem_name, Bundler.definition.dependencies) end def print_gem_path(spec) if spec.name == "bundler" path = File.expand_path("../../../..", __FILE__) else path = spec.full_gem_path unless File.directory?(path) return Bundler.ui.warn "The gem #{gem_name} has been deleted. It was installed at: #{path}" end end Bundler.ui.info path end def print_gem_info(spec) metadata = spec.metadata gem_info = String.new gem_info << " * #{spec.name} (#{spec.version}#{spec.git_version})\n" gem_info << "\tSummary: #{spec.summary}\n" if spec.summary gem_info << "\tHomepage: #{spec.homepage}\n" if spec.homepage gem_info << "\tDocumentation: #{metadata["documentation_uri"]}\n" if metadata.key?("documentation_uri") gem_info << "\tSource Code: #{metadata["source_code_uri"]}\n" if metadata.key?("source_code_uri") gem_info << "\tFunding: #{metadata["funding_uri"]}\n" if metadata.key?("funding_uri") gem_info << "\tWiki: #{metadata["wiki_uri"]}\n" if metadata.key?("wiki_uri") gem_info << "\tChangelog: #{metadata["changelog_uri"]}\n" if metadata.key?("changelog_uri") gem_info << "\tBug Tracker: #{metadata["bug_tracker_uri"]}\n" if metadata.key?("bug_tracker_uri") gem_info << "\tMailing List: #{metadata["mailing_list_uri"]}\n" if metadata.key?("mailing_list_uri") gem_info << "\tPath: #{spec.full_gem_path}\n" gem_info << "\tDefault Gem: yes" if spec.respond_to?(:default_gem?) && spec.default_gem? Bundler.ui.info gem_info end end end PKu]?z(bundler-2.2.24/lib/bundler/gem_helper.rbnu[# frozen_string_literal: true require_relative "../bundler" require "shellwords" module Bundler class GemHelper include Rake::DSL if defined? Rake::DSL class << self # set when install'd. attr_accessor :instance def install_tasks(opts = {}) new(opts[:dir], opts[:name]).install end def tag_prefix=(prefix) instance.tag_prefix = prefix end def gemspec(&block) gemspec = instance.gemspec block.call(gemspec) if block gemspec end end attr_reader :spec_path, :base, :gemspec attr_writer :tag_prefix def initialize(base = nil, name = nil) @base = File.expand_path(base || SharedHelpers.pwd) gemspecs = name ? [File.join(@base, "#{name}.gemspec")] : Gem::Util.glob_files_in_dir("{,*}.gemspec", @base) raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1 @spec_path = gemspecs.first @gemspec = Bundler.load_gemspec(@spec_path) @tag_prefix = "" end def install built_gem_path = nil desc "Build #{name}-#{version}.gem into the pkg directory." task "build" do built_gem_path = build_gem end desc "Generate SHA512 checksum if #{name}-#{version}.gem into the checksums directory." task "build:checksum" => "build" do build_checksum(built_gem_path) end desc "Build and install #{name}-#{version}.gem into system gems." task "install" => "build" do install_gem(built_gem_path) end desc "Build and install #{name}-#{version}.gem into system gems without network access." task "install:local" => "build" do install_gem(built_gem_path, :local) end desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to #{gem_push_host}\n" \ "To prevent publishing in RubyGems use `gem_push=no rake release`" task "release", [:remote] => ["build", "release:guard_clean", "release:source_control_push", "release:rubygem_push"] do end task "release:guard_clean" do guard_clean end task "release:source_control_push", [:remote] do |_, args| tag_version { git_push(args[:remote]) } unless already_tagged? end task "release:rubygem_push" do rubygem_push(built_gem_path) if gem_push? end GemHelper.instance = self end def build_gem file_name = nil sh([*gem_command, "build", "-V", spec_path]) do file_name = File.basename(built_gem_path) SharedHelpers.filesystem_access(File.join(base, "pkg")) {|p| FileUtils.mkdir_p(p) } FileUtils.mv(built_gem_path, "pkg") Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}." end File.join(base, "pkg", file_name) end def install_gem(built_gem_path = nil, local = false) built_gem_path ||= build_gem cmd = [*gem_command, "install", built_gem_path.to_s] cmd << "--local" if local _, status = sh_with_status(cmd) unless status.success? raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" end Bundler.ui.confirm "#{name} (#{version}) installed." end def build_checksum(built_gem_path = nil) built_gem_path ||= build_gem SharedHelpers.filesystem_access(File.join(base, "checksums")) {|p| FileUtils.mkdir_p(p) } file_name = "#{File.basename(built_gem_path)}.sha512" require "digest/sha2" checksum = Digest::SHA512.new.hexdigest(built_gem_path.to_s) target = File.join(base, "checksums", file_name) File.write(target, checksum) Bundler.ui.confirm "#{name} #{version} checksum written to checksums/#{file_name}." end protected def rubygem_push(path) cmd = [*gem_command, "push", path] cmd << "--key" << gem_key if gem_key cmd << "--host" << allowed_push_host if allowed_push_host sh_with_input(cmd) Bundler.ui.confirm "Pushed #{name} #{version} to #{gem_push_host}" end def built_gem_path Gem::Util.glob_files_in_dir("#{name}-*.gem", base).sort_by {|f| File.mtime(f) }.last end def git_push(remote = nil) remote ||= default_remote perform_git_push "#{remote} refs/heads/#{current_branch}" perform_git_push "#{remote} refs/tags/#{version_tag}" Bundler.ui.confirm "Pushed git commits and release tag." end def default_remote remote_for_branch, status = sh_with_status(%W[git config --get branch.#{current_branch}.remote]) return "origin" unless status.success? remote_for_branch.strip end def current_branch # We can replace this with `git branch --show-current` once we drop support for git < 2.22.0 sh(%w[git rev-parse --abbrev-ref HEAD]).gsub(%r{\Aheads/}, "").strip end def allowed_push_host @gemspec.metadata["allowed_push_host"] if @gemspec.respond_to?(:metadata) end def gem_push_host env_rubygems_host = ENV["RUBYGEMS_HOST"] env_rubygems_host = nil if env_rubygems_host && env_rubygems_host.empty? allowed_push_host || env_rubygems_host || "rubygems.org" end def perform_git_push(options = "") cmd = "git push #{options}" out, status = sh_with_status(cmd.shellsplit) return if status.success? raise "Couldn't git push. `#{cmd}' failed with the following output:\n\n#{out}\n" end def already_tagged? return false unless sh(%w[git tag]).split(/\n/).include?(version_tag) Bundler.ui.confirm "Tag #{version_tag} has already been created." true end def guard_clean clean? && committed? || raise("There are files that need to be committed first.") end def clean? sh_with_status(%w[git diff --exit-code])[1].success? end def committed? sh_with_status(%w[git diff-index --quiet --cached HEAD])[1].success? end def tag_version sh %W[git tag -m Version\ #{version} #{version_tag}] Bundler.ui.confirm "Tagged #{version_tag}." yield if block_given? rescue RuntimeError Bundler.ui.error "Untagging #{version_tag} due to error." sh_with_status %W[git tag -d #{version_tag}] raise end def version gemspec.version end def version_tag "#{@tag_prefix}v#{version}" end def name gemspec.name end def sh_with_input(cmd) Bundler.ui.debug(cmd) SharedHelpers.chdir(base) do abort unless Kernel.system(*cmd) end end def sh(cmd, &block) out, status = sh_with_status(cmd, &block) unless status.success? cmd = cmd.shelljoin if cmd.respond_to?(:shelljoin) raise(out.empty? ? "Running `#{cmd}` failed. Run this command directly for more detailed output." : out) end out end def sh_with_status(cmd, &block) Bundler.ui.debug(cmd) SharedHelpers.chdir(base) do outbuf = IO.popen(cmd, :err => [:child, :out], &:read) status = $? block.call(outbuf) if status.success? && block [outbuf, status] end end def gem_key Bundler.settings["gem.push_key"].to_s.downcase if Bundler.settings["gem.push_key"] end def gem_push? !%w[n no nil false off 0].include?(ENV["gem_push"].to_s.downcase) end def gem_command ENV["GEM_COMMAND"]&.shellsplit || ["gem"] end end end PKu]`f<<&bundler-2.2.24/lib/bundler/resolver.rbnu[# frozen_string_literal: true module Bundler class Resolver require_relative "vendored_molinillo" require_relative "resolver/spec_group" include GemHelpers # Figures out the best possible configuration of gems that satisfies # the list of passed dependencies and any child dependencies without # causing any gem activation errors. # # ==== Parameters # *dependencies:: The list of dependencies to resolve # # ==== Returns # ,nil:: If the list of dependencies can be resolved, a # collection of gemspecs is returned. Otherwise, nil is returned. def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) base = SpecSet.new(base) unless base.is_a?(SpecSet) resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) result = resolver.start(requirements) SpecSet.new(SpecSet.new(result).for(requirements.reject{|dep| dep.name.end_with?("\0") })) end def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) @source_requirements = source_requirements @base = base @resolver = Molinillo::Resolver.new(self, self) @search_for = {} @base_dg = Molinillo::DependencyGraph.new aggregate_global_source = @source_requirements[:default].is_a?(Source::RubygemsAggregate) @base.each do |ls| dep = Dependency.new(ls.name, ls.version) ls.source = source_for(ls.name) unless aggregate_global_source @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true) end additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } @platforms = platforms.reject {|p| p != Gem::Platform::RUBY && (platforms - [p]).any? {|pl| generic(pl) == p } } @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY] @gem_version_promoter = gem_version_promoter @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? end def start(requirements) @gem_version_promoter.prerelease_specified = @prerelease_specified = {} requirements.each {|dep| @prerelease_specified[dep.name] ||= dep.prerelease? } verify_gemfile_dependencies_are_found!(requirements) dg = @resolver.resolve(requirements, @base_dg) dg. map(&:payload). reject {|sg| sg.name.end_with?("\0") }. map(&:to_specs). flatten rescue Molinillo::VersionConflict => e message = version_conflict_message(e) raise VersionConflict.new(e.conflicts.keys.uniq, message) rescue Molinillo::CircularDependencyError => e names = e.dependencies.sort_by(&:name).map {|d| "gem '#{d.name}'" } raise CyclicDependencyError, "Your bundle requires gems that depend" \ " on each other, creating an infinite loop. Please remove" \ " #{names.count > 1 ? "either " : ""}#{names.join(" or ")}" \ " and try again." end include Molinillo::UI # Conveys debug information to the user. # # @param [Integer] depth the current depth of the resolution process. # @return [void] def debug(depth = 0) return unless debug? debug_info = yield debug_info = debug_info.inspect unless debug_info.is_a?(String) puts debug_info.split("\n").map {|s| depth == 0 ? "BUNDLER: #{s}" : "BUNDLER(#{depth}): #{s}" } end def debug? return @debug_mode if defined?(@debug_mode) @debug_mode = ENV["BUNDLER_DEBUG_RESOLVER"] || ENV["BUNDLER_DEBUG_RESOLVER_TREE"] || ENV["DEBUG_RESOLVER"] || ENV["DEBUG_RESOLVER_TREE"] || false end def before_resolution Bundler.ui.info "Resolving dependencies...", debug? end def after_resolution Bundler.ui.info "" end def indicate_progress Bundler.ui.info ".", false unless debug? end include Molinillo::SpecificationProvider def dependencies_for(specification) specification.dependencies_for_activated_platforms end def search_for(dependency_proxy) platform = dependency_proxy.__platform dependency = dependency_proxy.dep name = dependency.name @search_for[dependency_proxy] ||= begin results = results_for(dependency, @base[name]) if vertex = @base_dg.vertex_named(name) locked_requirement = vertex.payload.requirement end if !@prerelease_specified[name] && (!@use_gvp || locked_requirement.nil?) # Move prereleases to the beginning of the list, so they're considered # last during resolution. pre, results = results.partition {|spec| spec.version.prerelease? } results = pre + results end spec_groups = if results.any? nested = [] results.each do |spec| version, specs = nested.last if version == spec.version specs << spec else nested << [spec.version, [spec]] end end nested.reduce([]) do |groups, (version, specs)| next groups if locked_requirement && !locked_requirement.satisfied_by?(version) specs_by_platform = Hash.new do |current_specs, current_platform| current_specs[current_platform] = select_best_platform_match(specs, current_platform) end spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY) groups << spec_group_ruby if spec_group_ruby next groups if @resolving_only_for_ruby spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform) groups << spec_group if spec_group groups end else [] end # GVP handles major itself, but it's still a bit risky to trust it with it # until we get it settled with new behavior. For 2.x it can take over all cases. if !@use_gvp spec_groups else @gem_version_promoter.sort_versions(dependency, spec_groups) end end end def index_for(dependency) source_for(dependency.name).specs end def source_for(name) @source_requirements[name] || @source_requirements[:default] end def results_for(dependency, base) index_for(dependency).search(dependency, base) end def name_for(dependency) dependency.name end def name_for_explicit_dependency_source Bundler.default_gemfile.basename.to_s rescue StandardError "Gemfile" end def name_for_locking_dependency_source Bundler.default_lockfile.basename.to_s rescue StandardError "Gemfile.lock" end def requirement_satisfied_by?(requirement, activated, spec) requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec) end def dependencies_equal?(dependencies, other_dependencies) dependencies.map(&:dep) == other_dependencies.map(&:dep) end def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| name = name_for(dependency) vertex = activated.vertex_named(name) [ @base_dg.vertex_named(name) ? 0 : 1, vertex.payload ? 0 : 1, vertex.root? ? 0 : 1, amount_constrained(dependency), conflicts[name] ? 0 : 1, vertex.payload ? 0 : search_for(dependency).count, self.class.platform_sort_key(dependency.__platform), ] end end def self.platform_sort_key(platform) # Prefer specific platform to not specific platform return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform ["00", *platform.to_a.map {|part| part || "" }] end private # returns an integer \in (-\infty, 0] # a number closer to 0 means the dependency is less constraining # # dependencies w/ 0 or 1 possibilities (ignoring version requirements) # are given very negative values, so they _always_ sort first, # before dependencies that are unconstrained def amount_constrained(dependency) @amount_constrained ||= {} @amount_constrained[dependency.name] ||= begin if (base = @base[dependency.name]) && !base.empty? dependency.requirement.satisfied_by?(base.first.version) ? 0 : 1 else all = index_for(dependency).search(dependency.name).size if all <= 1 all - 1_000_000 else search = search_for(dependency) search = @prerelease_specified[dependency.name] ? search.count : search.count {|s| !s.version.prerelease? } search - all end end end end def verify_gemfile_dependencies_are_found!(requirements) requirements.each do |requirement| name = requirement.name next if name == "bundler" next unless search_for(requirement).empty? cache_message = begin " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist? rescue GemfileNotFound nil end if (base = @base[name]) && !base.empty? version = base.first.version message = "You have requested:\n" \ " #{name} #{requirement.requirement}\n\n" \ "The bundle currently has #{name} locked at #{version}.\n" \ "Try running `bundle update #{name}`\n\n" \ "If you are updating multiple gems in your Gemfile at once,\n" \ "try passing them all to `bundle update`" elsif source = @source_requirements[name] specs = source.specs.search(name) versions_with_platforms = specs.map {|s| [s.version, s.platform] } message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n") message << if versions_with_platforms.any? "The source contains the following versions of '#{name}': #{formatted_versions_with_platforms(versions_with_platforms)}" else "The source does not contain any versions of '#{name}'" end else message = "Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in any of the gem sources " \ "listed in your Gemfile#{cache_message}." end raise GemNotFound, message end end def formatted_versions_with_platforms(versions_with_platforms) version_platform_strs = versions_with_platforms.map do |vwp| version = vwp.first platform = vwp.last version_platform_str = String.new(version.to_s) version_platform_str << " #{platform}" unless platform.nil? || platform == Gem::Platform::RUBY version_platform_str end version_platform_strs.join(", ") end def version_conflict_message(e) # only show essential conflicts, if possible conflicts = e.conflicts.dup if conflicts["bundler"] conflicts.replace("bundler" => conflicts["bundler"]) else conflicts.delete_if do |_name, conflict| deps = conflict.requirement_trees.map(&:last).flatten(1) !Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement))) end end e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty? solver_name = "Bundler" possibility_type = "gem" e.message_with_trees( :solver_name => solver_name, :possibility_type => possibility_type, :reduce_trees => lambda do |trees| # called first, because we want to reduce the amount of work required to find maximal empty sets trees = trees.uniq {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } } # bail out if tree size is too big for Array#combination to make any sense return trees if trees.size > 15 maximal = 1.upto(trees.size).map do |size| trees.map(&:last).flatten(1).combination(size).to_a end.flatten(1).select do |deps| Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement))) end.min_by(&:size) trees.reject! {|t| !maximal.include?(t.last) } if maximal trees.sort_by {|t| t.reverse.map(&:name) } end, :printable_requirement => lambda {|req| SharedHelpers.pretty_dependency(req) }, :additional_message_for_conflict => lambda do |o, name, conflict| if name == "bundler" o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION})) conflict_dependency = conflict.requirement conflict_requirement = conflict_dependency.requirement other_bundler_required = !conflict_requirement.satisfied_by?(Gem::Version.new(Bundler::VERSION)) if other_bundler_required o << "\n\n" candidate_specs = source_for(:default_bundler).specs.search(conflict_dependency) if candidate_specs.any? target_version = candidate_specs.last.version new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ") o << "Your bundle requires a different version of Bundler than the one you're running.\n" o << "Install the necessary version with `gem install bundler:#{target_version}` and rerun bundler using `#{new_command}`\n" else o << "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n" end end elsif conflict.locked_requirement o << "\n" o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n) o << %(the gems in your Gemfile, which may resolve the conflict.\n) elsif !conflict.existing o << "\n" relevant_source = conflict.requirement.source || source_for(name) metadata_requirement = name.end_with?("\0") o << "Could not find gem '" unless metadata_requirement o << SharedHelpers.pretty_dependency(conflict.requirement) o << "'" unless metadata_requirement if conflict.requirement_trees.first.size > 1 o << ", which is required by " o << "gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}'," end o << " " o << if metadata_requirement "is not available in #{relevant_source}" else "in #{relevant_source}.\n" end end end, :version_for_spec => lambda {|spec| spec.version }, :incompatible_version_message_for_conflict => lambda do |name, _conflict| if name.end_with?("\0") %(#{solver_name} found conflicting requirements for the #{name} version:) else %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":) end end ) end end end PKu]ω~%%(bundler-2.2.24/lib/bundler/dependency.rbnu[# frozen_string_literal: true require "rubygems/dependency" require_relative "shared_helpers" require_relative "rubygems_ext" module Bundler class Dependency < Gem::Dependency attr_reader :autorequire attr_reader :groups, :platforms, :gemfile, :git, :branch PLATFORM_MAP = { :ruby => Gem::Platform::RUBY, :ruby_18 => Gem::Platform::RUBY, :ruby_19 => Gem::Platform::RUBY, :ruby_20 => Gem::Platform::RUBY, :ruby_21 => Gem::Platform::RUBY, :ruby_22 => Gem::Platform::RUBY, :ruby_23 => Gem::Platform::RUBY, :ruby_24 => Gem::Platform::RUBY, :ruby_25 => Gem::Platform::RUBY, :ruby_26 => Gem::Platform::RUBY, :mri => Gem::Platform::RUBY, :mri_18 => Gem::Platform::RUBY, :mri_19 => Gem::Platform::RUBY, :mri_20 => Gem::Platform::RUBY, :mri_21 => Gem::Platform::RUBY, :mri_22 => Gem::Platform::RUBY, :mri_23 => Gem::Platform::RUBY, :mri_24 => Gem::Platform::RUBY, :mri_25 => Gem::Platform::RUBY, :mri_26 => Gem::Platform::RUBY, :rbx => Gem::Platform::RUBY, :truffleruby => Gem::Platform::RUBY, :jruby => Gem::Platform::JAVA, :jruby_18 => Gem::Platform::JAVA, :jruby_19 => Gem::Platform::JAVA, :mswin => Gem::Platform::MSWIN, :mswin_18 => Gem::Platform::MSWIN, :mswin_19 => Gem::Platform::MSWIN, :mswin_20 => Gem::Platform::MSWIN, :mswin_21 => Gem::Platform::MSWIN, :mswin_22 => Gem::Platform::MSWIN, :mswin_23 => Gem::Platform::MSWIN, :mswin_24 => Gem::Platform::MSWIN, :mswin_25 => Gem::Platform::MSWIN, :mswin_26 => Gem::Platform::MSWIN, :mswin64 => Gem::Platform::MSWIN64, :mswin64_19 => Gem::Platform::MSWIN64, :mswin64_20 => Gem::Platform::MSWIN64, :mswin64_21 => Gem::Platform::MSWIN64, :mswin64_22 => Gem::Platform::MSWIN64, :mswin64_23 => Gem::Platform::MSWIN64, :mswin64_24 => Gem::Platform::MSWIN64, :mswin64_25 => Gem::Platform::MSWIN64, :mswin64_26 => Gem::Platform::MSWIN64, :mingw => Gem::Platform::MINGW, :mingw_18 => Gem::Platform::MINGW, :mingw_19 => Gem::Platform::MINGW, :mingw_20 => Gem::Platform::MINGW, :mingw_21 => Gem::Platform::MINGW, :mingw_22 => Gem::Platform::MINGW, :mingw_23 => Gem::Platform::MINGW, :mingw_24 => Gem::Platform::MINGW, :mingw_25 => Gem::Platform::MINGW, :mingw_26 => Gem::Platform::MINGW, :x64_mingw => Gem::Platform::X64_MINGW, :x64_mingw_20 => Gem::Platform::X64_MINGW, :x64_mingw_21 => Gem::Platform::X64_MINGW, :x64_mingw_22 => Gem::Platform::X64_MINGW, :x64_mingw_23 => Gem::Platform::X64_MINGW, :x64_mingw_24 => Gem::Platform::X64_MINGW, :x64_mingw_25 => Gem::Platform::X64_MINGW, :x64_mingw_26 => Gem::Platform::X64_MINGW, }.freeze def initialize(name, version, options = {}, &blk) type = options["type"] || :runtime super(name, version, type) @autorequire = nil @groups = Array(options["group"] || :default).map(&:to_sym) @source = options["source"] @git = options["git"] @branch = options["branch"] @platforms = Array(options["platforms"]) @env = options["env"] @should_include = options.fetch("should_include", true) @gemfile = options["gemfile"] @autorequire = Array(options["require"] || []) if options.key?("require") end # Returns the platforms this dependency is valid for, in the same order as # passed in the `valid_platforms` parameter def gem_platforms(valid_platforms) return valid_platforms if @platforms.empty? valid_generic_platforms = valid_platforms.map {|p| [p, GemHelpers.generic(p)] }.to_h @gem_platforms ||= expanded_platforms.compact.uniq filtered_generic_platforms = valid_generic_platforms.values & @gem_platforms valid_generic_platforms.select {|_, v| filtered_generic_platforms.include?(v) }.keys end def expanded_platforms @platforms.map {|pl| PLATFORM_MAP[pl] } end def should_include? @should_include && current_env? && current_platform? end def current_env? return true unless @env if @env.is_a?(Hash) @env.all? do |key, val| ENV[key.to_s] && (val.is_a?(String) ? ENV[key.to_s] == val : ENV[key.to_s] =~ val) end else ENV[@env.to_s] end end def current_platform? return true if @platforms.empty? @platforms.any? do |p| Bundler.current_ruby.send("#{p}?") end end def to_lock out = super out << "!" if source out << "\n" end def specific? super rescue NoMethodError requirement != ">= 0" end end end PKu]N˾*bundler-2.2.24/lib/bundler/process_lock.rbnu[# frozen_string_literal: true module Bundler class ProcessLock def self.lock(bundle_path = Bundler.bundle_path) lock_file_path = File.join(bundle_path, "bundler.lock") has_lock = false File.open(lock_file_path, "w") do |f| f.flock(File::LOCK_EX) has_lock = true yield f.flock(File::LOCK_UN) end rescue Errno::EACCES, Errno::ENOLCK, *[SharedHelpers.const_get_safely(:ENOTSUP, Errno)].compact # In the case the user does not have access to # create the lock file or is using NFS where # locks are not available we skip locking. yield ensure FileUtils.rm_f(lock_file_path) if has_lock end end end PKu]h (bundler-2.2.24/lib/bundler/deployment.rbnu[# frozen_string_literal: true require_relative "shared_helpers" Bundler::SharedHelpers.major_deprecation 2, "Bundler no longer integrates with " \ "Capistrano, but Capistrano provides its own integration with " \ "Bundler via the capistrano-bundler gem. Use it instead." module Bundler class Deployment def self.define_task(context, task_method = :task, opts = {}) if defined?(Capistrano) && context.is_a?(Capistrano::Configuration) context_name = "capistrano" role_default = "{:except => {:no_release => true}}" error_type = ::Capistrano::CommandError else context_name = "vlad" role_default = "[:app]" error_type = ::Rake::CommandFailedError end roles = context.fetch(:bundle_roles, false) opts[:roles] = roles if roles context.send :namespace, :bundle do send :desc, <<-DESC Install the current Bundler environment. By default, gems will be \ installed to the shared/bundle path. Gems in the development and \ test group will not be installed. The install command is executed \ with the --deployment and --quiet flags. If the bundle cmd cannot \ be found then you can override the bundle_cmd variable to specify \ which one it should use. The base path to the app is fetched from \ the :latest_release variable. Set it for custom deploy layouts. You can override any of these defaults by setting the variables shown below. N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \ in your deploy.rb file. set :bundle_gemfile, "Gemfile" set :bundle_dir, File.join(fetch(:shared_path), 'bundle') set :bundle_flags, "--deployment --quiet" set :bundle_without, [:development, :test] set :bundle_with, [:mysql] set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle" set :bundle_roles, #{role_default} # e.g. [:app, :batch] DESC send task_method, :install, opts do bundle_cmd = context.fetch(:bundle_cmd, "bundle") bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet") bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), "bundle")) bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile") bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact bundle_with = [*context.fetch(:bundle_with, [])].compact app_path = context.fetch(:latest_release) if app_path.to_s.empty? raise error_type.new("Cannot detect current release path - make sure you have deployed at least once.") end args = ["--gemfile #{File.join(app_path, bundle_gemfile)}"] args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty? args << bundle_flags.to_s args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty? args << "--with #{bundle_with.join(" ")}" unless bundle_with.empty? run "cd #{app_path} && #{bundle_cmd} install #{args.join(" ")}" end end end end end PKu]aXeXX-bundler-2.2.24/lib/bundler/friendly_errors.rbnu[# frozen_string_literal: true require_relative "vendored_thor" module Bundler module FriendlyErrors module_function def enable! @disabled = false end def disabled? @disabled end def disable! @disabled = true end def log_error(error) case error when YamlSyntaxError Bundler.ui.error error.message Bundler.ui.trace error.orig_exception when Dsl::DSLError, GemspecError Bundler.ui.error error.message when GemRequireError Bundler.ui.error error.message Bundler.ui.trace error.orig_exception when BundlerError Bundler.ui.error error.message, :wrap => true Bundler.ui.trace error when Thor::Error Bundler.ui.error error.message when LoadError raise error unless error.message =~ /cannot load such file -- openssl|openssl.so|libcrypto.so/ Bundler.ui.error "\nCould not load OpenSSL. #{error.class}: #{error}\n#{error.backtrace.join("\n ")}" when Interrupt Bundler.ui.error "\nQuitting..." Bundler.ui.trace error when Gem::InvalidSpecificationException Bundler.ui.error error.message, :wrap => true when SystemExit when *[defined?(Java::JavaLang::OutOfMemoryError) && Java::JavaLang::OutOfMemoryError].compact Bundler.ui.error "\nYour JVM has run out of memory, and Bundler cannot continue. " \ "You can decrease the amount of memory Bundler needs by removing gems from your Gemfile, " \ "especially large gems. (Gems can be as large as hundreds of megabytes, and Bundler has to read those files!). " \ "Alternatively, you can increase the amount of memory the JVM is able to use by running Bundler with jruby -J-Xmx1024m -S bundle (JRuby defaults to 500MB)." else request_issue_report_for(error) end end def exit_status(error) case error when BundlerError then error.status_code when Thor::Error then 15 when SystemExit then error.status else 1 end end def request_issue_report_for(e) Bundler.ui.error <<-EOS.gsub(/^ {8}/, ""), nil, nil --- ERROR REPORT TEMPLATE ------------------------------------------------------- # Error Report ## Questions Please fill out answers to these questions, it'll help us figure out why things are going wrong. - **What did you do?** I ran the command `#{$PROGRAM_NAME} #{ARGV.join(" ")}` - **What did you expect to happen?** I expected Bundler to... - **What happened instead?** Instead, what happened was... - **Have you tried any solutions posted on similar issues in our issue tracker, stack overflow, or google?** I tried... - **Have you read our issues document, https://github.com/rubygems/rubygems/blob/master/bundler/doc/contributing/ISSUES.md?** ... ## Backtrace ``` #{e.class}: #{e.message} #{e.backtrace && e.backtrace.join("\n ").chomp} ``` #{Bundler::Env.report} --- TEMPLATE END ---------------------------------------------------------------- EOS Bundler.ui.error "Unfortunately, an unexpected error occurred, and Bundler cannot continue." Bundler.ui.error <<-EOS.gsub(/^ {8}/, ""), nil, :yellow First, try this link to see if there are any existing issue reports for this error: #{issues_url(e)} If there aren't any reports for this error yet, please copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at: https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md EOS end def issues_url(exception) message = exception.message.lines.first.tr(":", " ").chomp message = message.split("-").first if exception.is_a?(Errno) require "cgi" "https://github.com/rubygems/rubygems/search?q=" \ "#{CGI.escape(message)}&type=Issues" end end def self.with_friendly_errors FriendlyErrors.enable! yield rescue SignalException raise rescue Exception => e # rubocop:disable Lint/RescueException raise if FriendlyErrors.disabled? FriendlyErrors.log_error(e) exit FriendlyErrors.exit_status(e) end end PKu]^cc)bundler-2.2.24/lib/bundler/gem_helpers.rbnu[# frozen_string_literal: true module Bundler module GemHelpers GENERIC_CACHE = { Gem::Platform::RUBY => Gem::Platform::RUBY } # rubocop:disable Style/MutableConstant GENERICS = [ [Gem::Platform.new("java"), Gem::Platform.new("java")], [Gem::Platform.new("mswin32"), Gem::Platform.new("mswin32")], [Gem::Platform.new("mswin64"), Gem::Platform.new("mswin64")], [Gem::Platform.new("universal-mingw32"), Gem::Platform.new("universal-mingw32")], [Gem::Platform.new("x64-mingw32"), Gem::Platform.new("x64-mingw32")], [Gem::Platform.new("x86_64-mingw32"), Gem::Platform.new("x64-mingw32")], [Gem::Platform.new("mingw32"), Gem::Platform.new("x86-mingw32")], ].freeze def generic(p) GENERIC_CACHE[p] ||= begin _, found = GENERICS.find do |match, _generic| p.os == match.os && (!match.cpu || p.cpu == match.cpu) end found || Gem::Platform::RUBY end end module_function :generic def generic_local_platform generic(local_platform) end module_function :generic_local_platform def local_platform Bundler.local_platform end module_function :local_platform def platform_specificity_match(spec_platform, user_platform) spec_platform = Gem::Platform.new(spec_platform) PlatformMatch.specificity_score(spec_platform, user_platform) end module_function :platform_specificity_match def select_best_platform_match(specs, platform) matching = specs.select {|spec| spec.match_platform(platform) } exact = matching.select {|spec| spec.platform == platform } return exact if exact.any? sorted_matching = matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) } exemplary_spec = sorted_matching.first sorted_matching.take_while{|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) } end module_function :select_best_platform_match class PlatformMatch def self.specificity_score(spec_platform, user_platform) return -1 if spec_platform == user_platform return 1_000_000 if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY os_match(spec_platform, user_platform) + cpu_match(spec_platform, user_platform) * 10 + platform_version_match(spec_platform, user_platform) * 100 end def self.os_match(spec_platform, user_platform) if spec_platform.os == user_platform.os 0 else 1 end end def self.cpu_match(spec_platform, user_platform) if spec_platform.cpu == user_platform.cpu 0 elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm") 0 elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal" 1 else 2 end end def self.platform_version_match(spec_platform, user_platform) if spec_platform.version == user_platform.version 0 elsif spec_platform.version.nil? 1 else 2 end end end def same_specificity(platform, spec, exemplary_spec) platform_specificity_match(spec.platform, platform) == platform_specificity_match(exemplary_spec.platform, platform) end module_function :same_specificity def same_deps(spec, exemplary_spec) same_runtime_deps = spec.dependencies.sort == exemplary_spec.dependencies.sort return same_runtime_deps unless spec.is_a?(Gem::Specification) && exemplary_spec.is_a?(Gem::Specification) same_metadata_deps = spec.required_ruby_version == exemplary_spec.required_ruby_version && spec.required_rubygems_version == exemplary_spec.required_rubygems_version same_runtime_deps && same_metadata_deps end module_function :same_deps end end PKu]a! 5bundler-2.2.24/lib/bundler/installer/gem_installer.rbnu[# frozen_string_literal: true require "shellwords" module Bundler class GemInstaller attr_reader :spec, :standalone, :worker, :force, :installer def initialize(spec, installer, standalone = false, worker = 0, force = false) @spec = spec @installer = installer @standalone = standalone @worker = worker @force = force end def install_from_spec post_install_message = spec_settings ? install_with_settings : install Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}" generate_executable_stubs return true, post_install_message rescue Bundler::InstallHookError, Bundler::SecurityError, Bundler::APIResponseMismatchError raise rescue Errno::ENOSPC return false, out_of_space_message rescue Bundler::BundlerError, Gem::InstallError, Bundler::APIResponseInvalidDependenciesError => e return false, specific_failure_message(e) end private def specific_failure_message(e) message = "#{e.class}: #{e.message}\n" message += " " + e.backtrace.join("\n ") + "\n\n" if Bundler.ui.debug? message = message.lines.first + Bundler.ui.add_color(message.lines.drop(1).join, :clear) message + Bundler.ui.add_color(failure_message, :red) end def failure_message return install_error_message if spec.source.options["git"] "#{install_error_message}\n#{gem_install_message}" end def install_error_message "An error occurred while installing #{spec.name} (#{spec.version}), and Bundler cannot continue." end def gem_install_message source = spec.source return unless source.respond_to?(:remotes) if source.remotes.size == 1 "Make sure that `gem install #{spec.name} -v '#{spec.version}' --source '#{source.remotes.first}'` succeeds before bundling." else "Make sure that `gem install #{spec.name} -v '#{spec.version}'` succeeds before bundling." end end def spec_settings # Fetch the build settings, if there are any if settings = Bundler.settings["build.#{spec.name}"] Shellwords.shellsplit(settings) end end def install spec.source.install(spec, :force => force, :ensure_builtin_gems_cached => standalone, :build_args => Array(spec_settings)) end def install_with_settings # Build arguments are global, so this is mutexed Bundler.rubygems.install_with_build_args([spec_settings]) { install } end def out_of_space_message "#{install_error_message}\nYour disk is out of space. Free some space to be able to install your bundle." end def generate_executable_stubs return if Bundler.feature_flag.forget_cli_options? return if Bundler.settings[:inline] if Bundler.settings[:bin] && standalone installer.generate_standalone_bundler_executable_stubs(spec) elsif Bundler.settings[:bin] installer.generate_bundler_executable_stubs(spec, :force => true) end end end end PKu]y:bundler-2.2.24/lib/bundler/installer/parallel_installer.rbnu[# frozen_string_literal: true require_relative "../worker" require_relative "gem_installer" module Bundler class ParallelInstaller class SpecInstallation attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error def initialize(spec) @spec = spec @name = spec.name @full_name = spec.full_name @state = :none @post_install_message = "" @error = nil end def installed? state == :installed end def enqueued? state == :enqueued end def failed? state == :failed end def ready_to_enqueue? state == :none end def has_post_install_message? !post_install_message.empty? end def ignorable_dependency?(dep) dep.type == :development || dep.name == @name end # Checks installed dependencies against spec's dependencies to make # sure needed dependencies have been installed. def dependencies_installed?(all_specs) installed_specs = all_specs.select(&:installed?).map(&:name) dependencies.all? {|d| installed_specs.include? d.name } end # Represents only the non-development dependencies, the ones that are # itself and are in the total list. def dependencies @dependencies ||= all_dependencies.reject {|dep| ignorable_dependency? dep } end def missing_lockfile_dependencies(all_spec_names) dependencies.reject {|dep| all_spec_names.include? dep.name } end # Represents all dependencies def all_dependencies @spec.dependencies end def to_s "#<#{self.class} #{full_name} (#{state})>" end end def self.call(*args) new(*args).call end attr_reader :size def initialize(installer, all_specs, size, standalone, force) @installer = installer @size = size @standalone = standalone @force = force @specs = all_specs.map {|s| SpecInstallation.new(s) } @spec_set = all_specs @rake = @specs.find {|s| s.name == "rake" } end def call check_for_corrupt_lockfile if @rake do_install(@rake, 0) Gem::Specification.reset end if @size > 1 install_with_worker else install_serially end check_for_unmet_dependencies handle_error if failed_specs.any? @specs ensure worker_pool && worker_pool.stop end def check_for_unmet_dependencies unmet_dependencies = @specs.map do |s| [ s, s.dependencies.reject {|dep| @specs.any? {|spec| dep.matches_spec?(spec.spec) } }, ] end.reject {|a| a.last.empty? } return if unmet_dependencies.empty? warning = [] warning << "Your lockfile doesn't include a valid resolution." warning << "You can fix this by regenerating your lockfile or trying to manually editing the bad locked gems to a version that satisfies all dependencies." warning << "The unmet dependencies are:" unmet_dependencies.each do |spec, unmet_spec_dependencies| unmet_spec_dependencies.each do |unmet_spec_dependency| warning << "* #{unmet_spec_dependency}, depended upon #{spec.full_name}, unsatisfied by #{@specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) }.full_name}" end end Bundler.ui.warn(warning.join("\n")) end def check_for_corrupt_lockfile missing_dependencies = @specs.map do |s| [ s, s.missing_lockfile_dependencies(@specs.map(&:name)), ] end.reject {|a| a.last.empty? } return if missing_dependencies.empty? warning = [] warning << "Your lockfile was created by an old Bundler that left some things out." if @size != 1 warning << "Because of the missing DEPENDENCIES, we can only install gems one at a time, instead of installing #{@size} at a time." @size = 1 end warning << "You can fix this by adding the missing gems to your Gemfile, running bundle install, and then removing the gems from your Gemfile." warning << "The missing gems are:" missing_dependencies.each do |spec, missing| warning << "* #{missing.map(&:name).join(", ")} depended upon by #{spec.name}" end Bundler.ui.warn(warning.join("\n")) end private def failed_specs @specs.select(&:failed?) end def install_with_worker enqueue_specs process_specs until finished_installing? end def install_serially until finished_installing? raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?) spec_install.state = :enqueued do_install(spec_install, 0) end end def worker_pool @worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda {|spec_install, worker_num| do_install(spec_install, worker_num) } end def do_install(spec_install, worker_num) Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install) gem_installer = Bundler::GemInstaller.new( spec_install.spec, @installer, @standalone, worker_num, @force ) success, message = gem_installer.install_from_spec if success spec_install.state = :installed spec_install.post_install_message = message unless message.nil? else spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}" spec_install.state = :failed end Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL, spec_install) spec_install end # Dequeue a spec and save its post-install message and then enqueue the # remaining specs. # Some specs might've had to wait til this spec was installed to be # processed so the call to `enqueue_specs` is important after every # dequeue. def process_specs worker_pool.deq enqueue_specs end def finished_installing? @specs.all? do |spec| return true if spec.failed? spec.installed? end end def handle_error errors = failed_specs.map(&:error) if exception = errors.find {|e| e.is_a?(Bundler::BundlerError) } raise exception end raise Bundler::InstallError, errors.join("\n\n") end def require_tree_for_spec(spec) tree = @spec_set.what_required(spec) t = String.new("In #{File.basename(SharedHelpers.default_gemfile)}:\n") tree.each_with_index do |s, depth| t << " " * depth.succ << s.name unless tree.last == s t << %( was resolved to #{s.version}, which depends on) end t << %(\n) end t end # Keys in the remains hash represent uninstalled gems specs. # We enqueue all gem specs that do not have any dependencies. # Later we call this lambda again to install specs that depended on # previously installed specifications. We continue until all specs # are installed. def enqueue_specs @specs.select(&:ready_to_enqueue?).each do |spec| if spec.dependencies_installed? @specs spec.state = :enqueued worker_pool.enq spec end end end end end PKu]{sEjj2bundler-2.2.24/lib/bundler/installer/standalone.rbnu[# frozen_string_literal: true module Bundler class Standalone def initialize(groups, definition) @specs = definition.specs_for(groups) end def generate SharedHelpers.filesystem_access(bundler_path) do |p| FileUtils.mkdir_p(p) end File.open File.join(bundler_path, "setup.rb"), "w" do |file| file.puts "require 'rbconfig'" file.puts "ruby_engine = RUBY_ENGINE" file.puts "ruby_version = RbConfig::CONFIG[\"ruby_version\"]" file.puts "path = File.expand_path('..', __FILE__)" file.puts reverse_rubygems_kernel_mixin paths.each do |path| file.puts %($:.unshift File.expand_path("\#{path}/#{path}")) end end end private def paths @specs.map do |spec| next if spec.name == "bundler" Array(spec.require_paths).map do |path| gem_path(path, spec).sub(version_dir, '#{ruby_engine}/#{ruby_version}') # This is a static string intentionally. It's interpolated at a later time. end end.flatten end def version_dir "#{Bundler::RubyVersion.system.engine}/#{RbConfig::CONFIG["ruby_version"]}" end def bundler_path Bundler.root.join(Bundler.settings[:path], "bundler") end def gem_path(path, spec) full_path = Pathname.new(path).absolute? ? path : File.join(spec.full_gem_path, path) Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s rescue TypeError error_message = "#{spec.name} #{spec.version} has an invalid gemspec" raise Gem::InvalidSpecificationException.new(error_message) end def reverse_rubygems_kernel_mixin <<~END kernel = (class << ::Kernel; self; end) [kernel, ::Kernel].each do |k| if k.private_method_defined?(:gem_original_require) private_require = k.private_method_defined?(:require) k.send(:remove_method, :require) k.send(:define_method, :require, k.instance_method(:gem_original_require)) k.send(:private, :require) if private_require end end END end end end PKu]3dMM.bundler-2.2.24/lib/bundler/man/bundle-remove.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-REMOVE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile . .SH "SYNOPSIS" \fBbundle remove [GEM [GEM \.\.\.]] [\-\-install]\fR . .SH "DESCRIPTION" Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid\. If a gem cannot be removed, a warning is printed\. If a gem is already absent from the Gemfile, and error is raised\. . .SH "OPTIONS" . .TP \fB\-\-install\fR Runs \fBbundle install\fR after the given gems have been removed from the Gemfile, which ensures that both the lockfile and the installed gems on disk are also updated to remove the given gem(s)\. . .P Example: . .P bundle remove rails . .P bundle remove rails rack . .P bundle remove rails rack \-\-install PKu])&LYY2bundler-2.2.24/lib/bundler/man/bundle-check.1.ronnnu[bundle-check(1) -- Verifies if dependencies are satisfied by installed gems =========================================================================== ## SYNOPSIS `bundle check` [--dry-run] [--gemfile=FILE] [--path=PATH] ## DESCRIPTION `check` searches the local machine for each of the gems requested in the Gemfile. If all gems are found, Bundler prints a success message and exits with a status of 0. If not, the first missing gem is listed and Bundler exits status 1. ## OPTIONS * `--dry-run`: Locks the [`Gemfile(5)`][Gemfile(5)] before running the command. * `--gemfile`: Use the specified gemfile instead of the [`Gemfile(5)`][Gemfile(5)]. * `--path`: Specify a different path than the system default (`$BUNDLE_PATH` or `$GEM_HOME`). Bundler will remember this value for future installs on this machine. PKu](V0bundler-2.2.24/lib/bundler/man/bundle-viz.1.ronnnu[bundle-viz(1) -- Generates a visual dependency graph for your Gemfile ===================================================================== ## SYNOPSIS `bundle viz` [--file=FILE] [--format=FORMAT] [--requirements] [--version] [--without=GROUP GROUP] ## DESCRIPTION `viz` generates a PNG file of the current `Gemfile(5)` as a dependency graph. `viz` requires the ruby-graphviz gem (and its dependencies). The associated gems must also be installed via [`bundle install(1)`](bundle-install.1.html). ## OPTIONS * `--file`, `-f`: The name to use for the generated file. See `--format` option * `--format`, `-F`: This is output format option. Supported format is png, jpg, svg, dot ... * `--requirements`, `-R`: Set to show the version of each required dependency. * `--version`, `-v`: Set to show each gem version. * `--without`, `-W`: Exclude gems that are part of the specified named group. PKu];7676.bundler-2.2.24/lib/bundler/man/bundle-update.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-UPDATE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions . .SH "SYNOPSIS" \fBbundle update\fR \fI*gems\fR [\-\-all] [\-\-group=NAME] [\-\-source=NAME] [\-\-local] [\-\-ruby] [\-\-bundler[=VERSION]] [\-\-full\-index] [\-\-jobs=JOBS] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-redownload] [\-\-strict] [\-\-conservative] . .SH "DESCRIPTION" Update the gems specified (all gems, if \fB\-\-all\fR flag is used), ignoring the previously installed gems specified in the \fBGemfile\.lock\fR\. In general, you should use bundle install(1) \fIbundle\-install\.1\.html\fR to install the same exact gems and versions across machines\. . .P You would use \fBbundle update\fR to explicitly update the version of a gem\. . .SH "OPTIONS" . .TP \fB\-\-all\fR Update all gems specified in Gemfile\. . .TP \fB\-\-group=\fR, \fB\-g=[]\fR Only update the gems in the specified group\. For instance, you can update all gems in the development group with \fBbundle update \-\-group development\fR\. You can also call \fBbundle update rails \-\-group test\fR to update the rails gem and all gems in the test group, for example\. . .TP \fB\-\-source=\fR The name of a \fB:git\fR or \fB:path\fR source used in the Gemfile(5)\. For instance, with a \fB:git\fR source of \fBhttp://github\.com/rails/rails\.git\fR, you would call \fBbundle update \-\-source rails\fR . .TP \fB\-\-local\fR Do not attempt to fetch gems remotely and use the gem cache instead\. . .TP \fB\-\-ruby\fR Update the locked version of Ruby to the current version of Ruby\. . .TP \fB\-\-bundler\fR Update the locked version of bundler to the invoked bundler version\. . .TP \fB\-\-full\-index\fR Fall back to using the single\-file index of all gems\. . .TP \fB\-\-jobs=[]\fR, \fB\-j[]\fR Specify the number of jobs to run in parallel\. The default is \fB1\fR\. . .TP \fB\-\-retry=[]\fR Retry failed network or git requests for \fInumber\fR times\. . .TP \fB\-\-quiet\fR Only output warnings and errors\. . .TP \fB\-\-redownload\fR Force downloading every gem\. . .TP \fB\-\-patch\fR Prefer updating only to next patch version\. . .TP \fB\-\-minor\fR Prefer updating only to next minor version\. . .TP \fB\-\-major\fR Prefer updating to next major version (default)\. . .TP \fB\-\-strict\fR Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\. . .TP \fB\-\-conservative\fR Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\. . .SH "UPDATING ALL GEMS" If you run \fBbundle update \-\-all\fR, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. . .P Consider the following Gemfile(5): . .IP "" 4 . .nf source "https://rubygems\.org" gem "rails", "3\.0\.0\.rc" gem "nokogiri" . .fi . .IP "" 0 . .P When you run bundle install(1) \fIbundle\-install\.1\.html\fR the first time, bundler will resolve all of the dependencies, all the way down, and install what you need: . .IP "" 4 . .nf Fetching gem metadata from https://rubygems\.org/\.\.\.\.\.\.\.\.\. Resolving dependencies\.\.\. Installing builder 2\.1\.2 Installing abstract 1\.0\.0 Installing rack 1\.2\.8 Using bundler 1\.7\.6 Installing rake 10\.4\.0 Installing polyglot 0\.3\.5 Installing mime\-types 1\.25\.1 Installing i18n 0\.4\.2 Installing mini_portile 0\.6\.1 Installing tzinfo 0\.3\.42 Installing rack\-mount 0\.6\.14 Installing rack\-test 0\.5\.7 Installing treetop 1\.4\.15 Installing thor 0\.14\.6 Installing activesupport 3\.0\.0\.rc Installing erubis 2\.6\.6 Installing activemodel 3\.0\.0\.rc Installing arel 0\.4\.0 Installing mail 2\.2\.20 Installing activeresource 3\.0\.0\.rc Installing actionpack 3\.0\.0\.rc Installing activerecord 3\.0\.0\.rc Installing actionmailer 3\.0\.0\.rc Installing railties 3\.0\.0\.rc Installing rails 3\.0\.0\.rc Installing nokogiri 1\.6\.5 Bundle complete! 2 Gemfile dependencies, 26 gems total\. Use `bundle show [gemname]` to see where a bundled gem is installed\. . .fi . .IP "" 0 . .P As you can see, even though you have two gems in the Gemfile(5), your application needs 26 different gems in order to run\. Bundler remembers the exact versions it installed in \fBGemfile\.lock\fR\. The next time you run bundle install(1) \fIbundle\-install\.1\.html\fR, bundler skips the dependency resolution and installs the same gems as it installed last time\. . .P After checking in the \fBGemfile\.lock\fR into version control and cloning it on another machine, running bundle install(1) \fIbundle\-install\.1\.html\fR will \fIstill\fR install the gems that you installed last time\. You don\'t need to worry that a new release of \fBerubis\fR or \fBmail\fR changes the gems you use\. . .P However, from time to time, you might want to update the gems you are using to the newest versions that still match the gems in your Gemfile(5)\. . .P To do this, run \fBbundle update \-\-all\fR, which will ignore the \fBGemfile\.lock\fR, and resolve all the dependencies again\. Keep in mind that this process can result in a significantly different set of the 25 gems, based on the requirements of new gems that the gem authors released since the last time you ran \fBbundle update \-\-all\fR\. . .SH "UPDATING A LIST OF GEMS" Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. . .P For instance, in the scenario above, imagine that \fBnokogiri\fR releases version \fB1\.4\.4\fR, and you want to update it \fIwithout\fR updating Rails and all of its dependencies\. To do this, run \fBbundle update nokogiri\fR\. . .P Bundler will update \fBnokogiri\fR and any of its dependencies, but leave alone Rails and its dependencies\. . .SH "OVERLAPPING DEPENDENCIES" Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same second\-level dependency\. For instance, consider the case of \fBthin\fR and \fBrack\-perftools\-profiler\fR\. . .IP "" 4 . .nf source "https://rubygems\.org" gem "thin" gem "rack\-perftools\-profiler" . .fi . .IP "" 0 . .P The \fBthin\fR gem depends on \fBrack >= 1\.0\fR, while \fBrack\-perftools\-profiler\fR depends on \fBrack ~> 1\.0\fR\. If you run bundle install, you get: . .IP "" 4 . .nf Fetching source index for https://rubygems\.org/ Installing daemons (1\.1\.0) Installing eventmachine (0\.12\.10) with native extensions Installing open4 (1\.0\.1) Installing perftools\.rb (0\.4\.7) with native extensions Installing rack (1\.2\.1) Installing rack\-perftools_profiler (0\.0\.2) Installing thin (1\.2\.7) with native extensions Using bundler (1\.0\.0\.rc\.3) . .fi . .IP "" 0 . .P In this case, the two gems have their own set of dependencies, but they share \fBrack\fR in common\. If you run \fBbundle update thin\fR, bundler will update \fBdaemons\fR, \fBeventmachine\fR and \fBrack\fR, which are dependencies of \fBthin\fR, but not \fBopen4\fR or \fBperftools\.rb\fR, which are dependencies of \fBrack\-perftools_profiler\fR\. Note that \fBbundle update thin\fR will update \fBrack\fR even though it\'s \fIalso\fR a dependency of \fBrack\-perftools_profiler\fR\. . .P In short, by default, when you update a gem using \fBbundle update\fR, bundler will update all dependencies of that gem, including those that are also dependencies of another gem\. . .P To prevent updating indirect dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR: . .P In this scenario, updating the \fBthin\fR version manually in the Gemfile(5), and then running bundle install(1) \fIbundle\-install\.1\.html\fR will only update \fBdaemons\fR and \fBeventmachine\fR, but not \fBrack\fR\. For more information, see the \fBCONSERVATIVE UPDATING\fR section of bundle install(1) \fIbundle\-install\.1\.html\fR\. . .P Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent indirect dependencies from being updated\. . .SH "PATCH LEVEL OPTIONS" Version 1\.14 introduced 4 patch\-level options that will influence how gem versions are resolved\. One of the following options can be used: \fB\-\-patch\fR, \fB\-\-minor\fR or \fB\-\-major\fR\. \fB\-\-strict\fR can be added to further influence resolution\. . .TP \fB\-\-patch\fR Prefer updating only to next patch version\. . .TP \fB\-\-minor\fR Prefer updating only to next minor version\. . .TP \fB\-\-major\fR Prefer updating to next major version (default)\. . .TP \fB\-\-strict\fR Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\. . .P When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don\'t satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order\. . .P Providing one of the patch level options (e\.g\. \fB\-\-patch\fR) changes the sort order of the satisfying versions, causing Bundler to consider the latest \fB\-\-patch\fR or \fB\-\-minor\fR version available before other versions\. Note that versions outside the stated patch level could still be resolved to if necessary to find a suitable dependency graph\. . .P For example, if gem \'foo\' is locked at 1\.0\.2, with no gem requirement defined in the Gemfile, and versions 1\.0\.3, 1\.0\.4, 1\.1\.0, 1\.1\.1, 2\.0\.0 all exist, the default order of preference by default (\fB\-\-major\fR) will be "2\.0\.0, 1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\. . .P If the \fB\-\-patch\fR option is used, the order of preference will change to "1\.0\.4, 1\.0\.3, 1\.0\.2, 1\.1\.1, 1\.1\.0, 2\.0\.0"\. . .P If the \fB\-\-minor\fR option is used, the order of preference will change to "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2, 2\.0\.0"\. . .P Combining the \fB\-\-strict\fR option with any of the patch level options will remove any versions beyond the scope of the patch level option, to ensure that no gem is updated that far\. . .P To continue the previous example, if both \fB\-\-patch\fR and \fB\-\-strict\fR options are used, the available versions for resolution would be "1\.0\.4, 1\.0\.3, 1\.0\.2"\. If \fB\-\-minor\fR and \fB\-\-strict\fR are used, it would be "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\. . .P Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available\. If the gem requirement for \fBfoo\fR in the Gemfile is \'~> 1\.0\', that will accomplish the same thing as providing the \fB\-\-minor\fR and \fB\-\-strict\fR options\. . .SH "PATCH LEVEL EXAMPLES" Given the following gem specifications: . .IP "" 4 . .nf foo 1\.4\.3, requires: ~> bar 2\.0 foo 1\.4\.4, requires: ~> bar 2\.0 foo 1\.4\.5, requires: ~> bar 2\.1 foo 1\.5\.0, requires: ~> bar 2\.1 foo 1\.5\.1, requires: ~> bar 3\.0 bar with versions 2\.0\.3, 2\.0\.4, 2\.1\.0, 2\.1\.1, 3\.0\.0 . .fi . .IP "" 0 . .P Gemfile: . .IP "" 4 . .nf gem \'foo\' . .fi . .IP "" 0 . .P Gemfile\.lock: . .IP "" 4 . .nf foo (1\.4\.3) bar (~> 2\.0) bar (2\.0\.3) . .fi . .IP "" 0 . .P Cases: . .IP "" 4 . .nf # Command Line Result \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- 1 bundle update \-\-patch \'foo 1\.4\.5\', \'bar 2\.1\.1\' 2 bundle update \-\-patch foo \'foo 1\.4\.5\', \'bar 2\.1\.1\' 3 bundle update \-\-minor \'foo 1\.5\.1\', \'bar 3\.0\.0\' 4 bundle update \-\-minor \-\-strict \'foo 1\.5\.0\', \'bar 2\.1\.1\' 5 bundle update \-\-patch \-\-strict \'foo 1\.4\.4\', \'bar 2\.0\.4\' . .fi . .IP "" 0 . .P In case 1, bar is upgraded to 2\.1\.1, a minor version increase, because the dependency from foo 1\.4\.5 required it\. . .P In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it\'s not a declared dependency in the Gemfile\. . .P In case 3, bar goes up a whole major release, because a minor increase is preferred now for foo, and when it goes to 1\.5\.1, it requires 3\.0\.0 of bar\. . .P In case 4, foo is preferred up to a minor version, but 1\.5\.1 won\'t work because the \-\-strict flag removes bar 3\.0\.0 from consideration since it\'s a major increment\. . .P In case 5, both foo and bar have any minor or major increments removed from consideration because of the \-\-strict flag, so the most they can move is up to 1\.4\.4 and 2\.0\.4\. . .SH "RECOMMENDED WORKFLOW" In general, when working with an application managed with bundler, you should use the following workflow: . .IP "\(bu" 4 After you create your Gemfile(5) for the first time, run . .IP $ bundle install . .IP "\(bu" 4 Check the resulting \fBGemfile\.lock\fR into version control . .IP $ git add Gemfile\.lock . .IP "\(bu" 4 When checking out this repository on another development machine, run . .IP $ bundle install . .IP "\(bu" 4 When checking out this repository on a deployment machine, run . .IP $ bundle install \-\-deployment . .IP "\(bu" 4 After changing the Gemfile(5) to reflect a new or update dependency, run . .IP $ bundle install . .IP "\(bu" 4 Make sure to check the updated \fBGemfile\.lock\fR into version control . .IP $ git add Gemfile\.lock . .IP "\(bu" 4 If bundle install(1) \fIbundle\-install\.1\.html\fR reports a conflict, manually update the specific gems that you changed in the Gemfile(5) . .IP $ bundle update rails thin . .IP "\(bu" 4 If you want to update all the gems to the latest possible versions that still match the gems listed in the Gemfile(5), run . .IP $ bundle update \-\-all . .IP "" 0 PKu]MM+bundler-2.2.24/lib/bundler/man/bundle-viz.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-VIZ" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile . .SH "SYNOPSIS" \fBbundle viz\fR [\-\-file=FILE] [\-\-format=FORMAT] [\-\-requirements] [\-\-version] [\-\-without=GROUP GROUP] . .SH "DESCRIPTION" \fBviz\fR generates a PNG file of the current \fBGemfile(5)\fR as a dependency graph\. \fBviz\fR requires the ruby\-graphviz gem (and its dependencies)\. . .P The associated gems must also be installed via \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR\. . .SH "OPTIONS" . .TP \fB\-\-file\fR, \fB\-f\fR The name to use for the generated file\. See \fB\-\-format\fR option . .TP \fB\-\-format\fR, \fB\-F\fR This is output format option\. Supported format is png, jpg, svg, dot \.\.\. . .TP \fB\-\-requirements\fR, \fB\-R\fR Set to show the version of each required dependency\. . .TP \fB\-\-version\fR, \fB\-v\fR Set to show each gem version\. . .TP \fB\-\-without\fR, \fB\-W\fR Exclude gems that are part of the specified named group\. PKu]l42bundler-2.2.24/lib/bundler/man/bundle-clean.1.ronnnu[bundle-clean(1) -- Cleans up unused gems in your bundler directory ================================================================== ## SYNOPSIS `bundle clean` [--dry-run] [--force] ## DESCRIPTION This command will remove all unused gems in your bundler directory. This is useful when you have made many changes to your gem dependencies. ## OPTIONS * `--dry-run`: Print the changes, but do not clean the unused gems. * `--force`: Force a clean even if `--path` is not set. PKu]k  2bundler-2.2.24/lib/bundler/man/bundle-cache.1.ronnnu[bundle-cache(1) -- Package your needed `.gem` files into your application =========================================================================== ## SYNOPSIS `bundle cache` ## DESCRIPTION Copy all of the `.gem` files needed to run the application into the `vendor/cache` directory. In the future, when running [bundle install(1)][bundle-install], use the gems in the cache in preference to the ones on `rubygems.org`. ## GIT AND PATH GEMS The `bundle cache` command can also package `:git` and `:path` dependencies besides .gem files. This needs to be explicitly enabled via the `--all` option. Once used, the `--all` option will be remembered. ## SUPPORT FOR MULTIPLE PLATFORMS When using gems that have different packages for different platforms, Bundler supports caching of gems for other platforms where the Gemfile has been resolved (i.e. present in the lockfile) in `vendor/cache`. This needs to be enabled via the `--all-platforms` option. This setting will be remembered in your local bundler configuration. ## REMOTE FETCHING By default, if you run `bundle install(1)`](bundle-install.1.html) after running [bundle cache(1)](bundle-cache.1.html), bundler will still connect to `rubygems.org` to check whether a platform-specific gem exists for any of the gems in `vendor/cache`. For instance, consider this Gemfile(5): source "https://rubygems.org" gem "nokogiri" If you run `bundle cache` under C Ruby, bundler will retrieve the version of `nokogiri` for the `"ruby"` platform. If you deploy to JRuby and run `bundle install`, bundler is forced to check to see whether a `"java"` platformed `nokogiri` exists. Even though the `nokogiri` gem for the Ruby platform is _technically_ acceptable on JRuby, it has a C extension that does not run on JRuby. As a result, bundler will, by default, still connect to `rubygems.org` to check whether it has a version of one of your gems more specific to your platform. This problem is also not limited to the `"java"` platform. A similar (common) problem can happen when developing on Windows and deploying to Linux, or even when developing on OSX and deploying to Linux. If you know for sure that the gems packaged in `vendor/cache` are appropriate for the platform you are on, you can run `bundle install --local` to skip checking for more appropriate gems, and use the ones in `vendor/cache`. One way to be sure that you have the right platformed versions of all your gems is to run `bundle cache` on an identical machine and check in the gems. For instance, you can run `bundle cache` on an identical staging box during your staging process, and check in the `vendor/cache` before deploying to production. By default, [bundle cache(1)](bundle-cache.1.html) fetches and also installs the gems to the default location. To package the dependencies to `vendor/cache` without installing them to the local install location, you can run `bundle cache --no-install`. PKu]&+bundler-2.2.24/lib/bundler/man/bundle-add.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-ADD" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install . .SH "SYNOPSIS" \fBbundle add\fR \fIGEM_NAME\fR [\-\-group=GROUP] [\-\-version=VERSION] [\-\-source=SOURCE] [\-\-git=GIT] [\-\-branch=BRANCH] [\-\-skip\-install] [\-\-strict] [\-\-optimistic] . .SH "DESCRIPTION" Adds the named gem to the Gemfile and run \fBbundle install\fR\. \fBbundle install\fR can be avoided by using the flag \fB\-\-skip\-install\fR\. . .P Example: . .P bundle add rails . .P bundle add rails \-\-version "< 3\.0, > 1\.1" . .P bundle add rails \-\-version "~> 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development" . .P bundle add rails \-\-skip\-install . .P bundle add rails \-\-group "development, test" . .SH "OPTIONS" . .TP \fB\-\-version\fR, \fB\-v\fR Specify version requirements(s) for the added gem\. . .TP \fB\-\-group\fR, \fB\-g\fR Specify the group(s) for the added gem\. Multiple groups should be separated by commas\. . .TP \fB\-\-source\fR, , \fB\-s\fR Specify the source for the added gem\. . .TP \fB\-\-git\fR Specify the git source for the added gem\. . .TP \fB\-\-branch\fR Specify the git branch for the added gem\. . .TP \fB\-\-skip\-install\fR Adds the gem to the Gemfile but does not install it\. . .TP \fB\-\-optimistic\fR Adds optimistic declaration of version . .TP \fB\-\-strict\fR Adds strict declaration of version PKu]H,bundler-2.2.24/lib/bundler/man/bundle-show.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-SHOW" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem . .SH "SYNOPSIS" \fBbundle show\fR [GEM] [\-\-paths] . .SH "DESCRIPTION" Without the [GEM] option, \fBshow\fR will print a list of the names and versions of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by name\. . .P Calling show with [GEM] will list the exact location of that gem on your machine\. . .SH "OPTIONS" . .TP \fB\-\-paths\fR List the paths of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by gem name\. PKu]B5UU3bundler-2.2.24/lib/bundler/man/bundle-inject.1.ronnnu[bundle-inject(1) -- Add named gem(s) with version requirements to Gemfile ========================================================================= ## SYNOPSIS `bundle inject` [GEM] [VERSION] ## DESCRIPTION Adds the named gem(s) with their version requirements to the resolved [`Gemfile(5)`][Gemfile(5)]. This command will add the gem to both your [`Gemfile(5)`][Gemfile(5)] and Gemfile.lock if it isn't listed yet. Example: bundle install bundle inject 'rack' '> 0' This will inject the 'rack' gem with a version greater than 0 in your [`Gemfile(5)`][Gemfile(5)] and Gemfile.lock PKu]$.bundler-2.2.24/lib/bundler/man/bundle-doctor.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-DOCTOR" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems . .SH "SYNOPSIS" \fBbundle doctor\fR [\-\-quiet] [\-\-gemfile=GEMFILE] . .SH "DESCRIPTION" Checks your Gemfile and gem environment for common problems\. If issues are detected, Bundler prints them and exits status 1\. Otherwise, Bundler prints a success message and exits status 0\. . .P Examples of common problems caught by bundle\-doctor include: . .IP "\(bu" 4 Invalid Bundler settings . .IP "\(bu" 4 Mismatched Ruby versions . .IP "\(bu" 4 Mismatched platforms . .IP "\(bu" 4 Uninstalled gems . .IP "\(bu" 4 Missing dependencies . .IP "" 0 . .SH "OPTIONS" . .TP \fB\-\-quiet\fR Only output warnings and errors\. . .TP \fB\-\-gemfile=\fR The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project\'s root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\. PKu]9IG 1bundler-2.2.24/lib/bundler/man/bundle-lock.1.ronnnu[bundle-lock(1) -- Creates / Updates a lockfile without installing ================================================================= ## SYNOPSIS `bundle lock` [--update] [--local] [--print] [--lockfile=PATH] [--full-index] [--add-platform] [--remove-platform] [--patch] [--minor] [--major] [--strict] [--conservative] ## DESCRIPTION Lock the gems specified in Gemfile. ## OPTIONS * `--update=<*gems>`: Ignores the existing lockfile. Resolve then updates lockfile. Taking a list of gems or updating all gems if no list is given. * `--local`: Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the gems already present in Rubygems' cache or in `vendor/cache`. Note that if a appropriate platform-specific gem exists on `rubygems.org` it will not be found. * `--print`: Prints the lockfile to STDOUT instead of writing to the file system. * `--lockfile=`: The path where the lockfile should be written to. * `--full-index`: Fall back to using the single-file index of all gems. * `--add-platform`: Add a new platform to the lockfile, re-resolving for the addition of that platform. * `--remove-platform`: Remove a platform from the lockfile. * `--patch`: If updating, prefer updating only to next patch version. * `--minor`: If updating, prefer updating only to next minor version. * `--major`: If updating, prefer updating to next major version (default). * `--strict`: If updating, do not allow any gem to be updated past latest --patch | --minor | --major. * `--conservative`: If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated. ## UPDATING ALL GEMS If you run `bundle lock` with `--update` option without list of gems, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources. ## UPDATING A LIST OF GEMS Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the `Gemfile.lock`. For instance, you only want to update `nokogiri`, run `bundle lock --update nokogiri`. Bundler will update `nokogiri` and any of its dependencies, but leave the rest of the gems that you specified locked to the versions in the `Gemfile.lock`. ## SUPPORTING OTHER PLATFORMS If you want your bundle to support platforms other than the one you're running locally, you can run `bundle lock --add-platform PLATFORM` to add PLATFORM to the lockfile, force bundler to re-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform-specific gems on. For a full explanation of gem platforms, see `gem help platform`. ## PATCH LEVEL OPTIONS See [bundle update(1)](bundle-update.1.html) for details. PKu]Iߚ 5bundler-2.2.24/lib/bundler/man/bundle-outdated.1.ronnnu[bundle-outdated(1) -- List installed gems with newer versions available ======================================================================= ## SYNOPSIS `bundle outdated` [GEM] [--local] [--pre] [--source] [--strict] [--parseable | --porcelain] [--group=GROUP] [--groups] [--update-strict] [--patch|--minor|--major] [--filter-major] [--filter-minor] [--filter-patch] [--only-explicit] ## DESCRIPTION Outdated lists the names and versions of gems that have a newer version available in the given source. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems. Prerelease gems are ignored by default. If your gems are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. ## OPTIONS * `--local`: Do not attempt to fetch gems remotely and use the gem cache instead. * `--pre`: Check for newer pre-release gems. * `--source`: Check against a specific source. * `--strict`: Only list newer versions allowed by your Gemfile requirements. * `--parseable`, `--porcelain`: Use minimal formatting for more parseable output. * `--group`: List gems from a specific group. * `--groups`: List gems organized by groups. * `--update-strict`: Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor| --major. * `--minor`: Prefer updating only to next minor version. * `--major`: Prefer updating to next major version (default). * `--patch`: Prefer updating only to next patch version. * `--filter-major`: Only list major newer versions. * `--filter-minor`: Only list minor newer versions. * `--filter-patch`: Only list patch newer versions. * `--only-explicit`: Only list gems specified in your Gemfile, not their dependencies. ## PATCH LEVEL OPTIONS See [bundle update(1)](bundle-update.1.html) for details. One difference between the patch level options in `bundle update` and here is the `--strict` option. `--strict` was already an option on outdated before the patch level options were added. `--strict` wasn't altered, and the `--update-strict` option on `outdated` reflects what `--strict` does on `bundle update`. ## FILTERING OUTPUT The 3 filtering options do not affect the resolution of versions, merely what versions are shown in the output. If the regular output shows the following: * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test" * hashie (newest 3.4.6, installed 1.2.0, requested = 1.2.0) in groups "default" * headless (newest 2.3.1, installed 2.2.3) in groups "test" `--filter-major` would only show: * hashie (newest 3.4.6, installed 1.2.0, requested = 1.2.0) in groups "default" `--filter-minor` would only show: * headless (newest 2.3.1, installed 2.2.3) in groups "test" `--filter-patch` would only show: * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test" Filter options can be combined. `--filter-minor` and `--filter-patch` would show: * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test" * headless (newest 2.3.1, installed 2.2.3) in groups "test" Combining all three `filter` options would be the same result as providing none of them. PKu]1~5bundler-2.2.24/lib/bundler/man/bundle-binstubs.1.ronnnu[bundle-binstubs(1) -- Install the binstubs of the listed gems ============================================================= ## SYNOPSIS `bundle binstubs` [--force] [--path PATH] [--standalone] ## DESCRIPTION Binstubs are scripts that wrap around executables. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into `bin/`. Binstubs are a shortcut-or alternative- to always using `bundle exec`. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application. For example, if you run `bundle binstubs rspec-core`, Bundler will create the file `bin/rspec`. That file will contain enough code to load Bundler, tell it to load the bundled gems, and then run rspec. This command generates binstubs for executables in `GEM_NAME`. Binstubs are put into `bin`, or the `--path` directory if one has been set. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems. ## OPTIONS * `--force`: Overwrite existing binstubs if they exist. * `--path`: The location to install the specified binstubs to. This defaults to `bin`. * `--standalone`: Makes binstubs that can work without depending on Rubygems or Bundler at runtime. * `--shebang`: Specify a different shebang executable name than the default (default 'ruby') * `--all`: Create binstubs for all gems in the bundle. PKu]UM -bundler-2.2.24/lib/bundler/man/bundle-cache.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-CACHE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application . .SH "SYNOPSIS" \fBbundle cache\fR . .SH "DESCRIPTION" Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running [bundle install(1)][bundle\-install], use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\. . .SH "GIT AND PATH GEMS" The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This needs to be explicitly enabled via the \fB\-\-all\fR option\. Once used, the \fB\-\-all\fR option will be remembered\. . .SH "SUPPORT FOR MULTIPLE PLATFORMS" When using gems that have different packages for different platforms, Bundler supports caching of gems for other platforms where the Gemfile has been resolved (i\.e\. present in the lockfile) in \fBvendor/cache\fR\. This needs to be enabled via the \fB\-\-all\-platforms\fR option\. This setting will be remembered in your local bundler configuration\. . .SH "REMOTE FETCHING" By default, if you run \fBbundle install(1)\fR](bundle\-install\.1\.html) after running bundle cache(1) \fIbundle\-cache\.1\.html\fR, bundler will still connect to \fBrubygems\.org\fR to check whether a platform\-specific gem exists for any of the gems in \fBvendor/cache\fR\. . .P For instance, consider this Gemfile(5): . .IP "" 4 . .nf source "https://rubygems\.org" gem "nokogiri" . .fi . .IP "" 0 . .P If you run \fBbundle cache\fR under C Ruby, bundler will retrieve the version of \fBnokogiri\fR for the \fB"ruby"\fR platform\. If you deploy to JRuby and run \fBbundle install\fR, bundler is forced to check to see whether a \fB"java"\fR platformed \fBnokogiri\fR exists\. . .P Even though the \fBnokogiri\fR gem for the Ruby platform is \fItechnically\fR acceptable on JRuby, it has a C extension that does not run on JRuby\. As a result, bundler will, by default, still connect to \fBrubygems\.org\fR to check whether it has a version of one of your gems more specific to your platform\. . .P This problem is also not limited to the \fB"java"\fR platform\. A similar (common) problem can happen when developing on Windows and deploying to Linux, or even when developing on OSX and deploying to Linux\. . .P If you know for sure that the gems packaged in \fBvendor/cache\fR are appropriate for the platform you are on, you can run \fBbundle install \-\-local\fR to skip checking for more appropriate gems, and use the ones in \fBvendor/cache\fR\. . .P One way to be sure that you have the right platformed versions of all your gems is to run \fBbundle cache\fR on an identical machine and check in the gems\. For instance, you can run \fBbundle cache\fR on an identical staging box during your staging process, and check in the \fBvendor/cache\fR before deploying to production\. . .P By default, bundle cache(1) \fIbundle\-cache\.1\.html\fR fetches and also installs the gems to the default location\. To package the dependencies to \fBvendor/cache\fR without installing them to the local install location, you can run \fBbundle cache \-\-no\-install\fR\. PKu]0bundler-2.2.24/lib/bundler/man/bundle-outdated.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-OUTDATED" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available . .SH "SYNOPSIS" \fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-update\-strict] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit] . .SH "DESCRIPTION" Outdated lists the names and versions of gems that have a newer version available in the given source\. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems\. Prerelease gems are ignored by default\. If your gems are up to date, Bundler will exit with a status of 0\. Otherwise, it will exit 1\. . .SH "OPTIONS" . .TP \fB\-\-local\fR Do not attempt to fetch gems remotely and use the gem cache instead\. . .TP \fB\-\-pre\fR Check for newer pre\-release gems\. . .TP \fB\-\-source\fR Check against a specific source\. . .TP \fB\-\-strict\fR Only list newer versions allowed by your Gemfile requirements\. . .TP \fB\-\-parseable\fR, \fB\-\-porcelain\fR Use minimal formatting for more parseable output\. . .TP \fB\-\-group\fR List gems from a specific group\. . .TP \fB\-\-groups\fR List gems organized by groups\. . .TP \fB\-\-update\-strict\fR Strict conservative resolution, do not allow any gem to be updated past latest \-\-patch | \-\-minor| \-\-major\. . .TP \fB\-\-minor\fR Prefer updating only to next minor version\. . .TP \fB\-\-major\fR Prefer updating to next major version (default)\. . .TP \fB\-\-patch\fR Prefer updating only to next patch version\. . .TP \fB\-\-filter\-major\fR Only list major newer versions\. . .TP \fB\-\-filter\-minor\fR Only list minor newer versions\. . .TP \fB\-\-filter\-patch\fR Only list patch newer versions\. . .TP \fB\-\-only\-explicit\fR Only list gems specified in your Gemfile, not their dependencies\. . .SH "PATCH LEVEL OPTIONS" See bundle update(1) \fIbundle\-update\.1\.html\fR for details\. . .P One difference between the patch level options in \fBbundle update\fR and here is the \fB\-\-strict\fR option\. \fB\-\-strict\fR was already an option on outdated before the patch level options were added\. \fB\-\-strict\fR wasn\'t altered, and the \fB\-\-update\-strict\fR option on \fBoutdated\fR reflects what \fB\-\-strict\fR does on \fBbundle update\fR\. . .SH "FILTERING OUTPUT" The 3 filtering options do not affect the resolution of versions, merely what versions are shown in the output\. . .P If the regular output shows the following: . .IP "" 4 . .nf * faker (newest 1\.6\.6, installed 1\.6\.5, requested ~> 1\.4) in groups "development, test" * hashie (newest 3\.4\.6, installed 1\.2\.0, requested = 1\.2\.0) in groups "default" * headless (newest 2\.3\.1, installed 2\.2\.3) in groups "test" . .fi . .IP "" 0 . .P \fB\-\-filter\-major\fR would only show: . .IP "" 4 . .nf * hashie (newest 3\.4\.6, installed 1\.2\.0, requested = 1\.2\.0) in groups "default" . .fi . .IP "" 0 . .P \fB\-\-filter\-minor\fR would only show: . .IP "" 4 . .nf * headless (newest 2\.3\.1, installed 2\.2\.3) in groups "test" . .fi . .IP "" 0 . .P \fB\-\-filter\-patch\fR would only show: . .IP "" 4 . .nf * faker (newest 1\.6\.6, installed 1\.6\.5, requested ~> 1\.4) in groups "development, test" . .fi . .IP "" 0 . .P Filter options can be combined\. \fB\-\-filter\-minor\fR and \fB\-\-filter\-patch\fR would show: . .IP "" 4 . .nf * faker (newest 1\.6\.6, installed 1\.6\.5, requested ~> 1\.4) in groups "development, test" * headless (newest 2\.3\.1, installed 2\.2\.3) in groups "test" . .fi . .IP "" 0 . .P Combining all three \fBfilter\fR options would be the same result as providing none of them\. PKu]N-'bundler-2.2.24/lib/bundler/man/bundle.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management . .SH "SYNOPSIS" \fBbundle\fR COMMAND [\-\-no\-color] [\-\-verbose] [ARGS] . .SH "DESCRIPTION" Bundler manages an \fBapplication\'s dependencies\fR through its entire life across many machines systematically and repeatably\. . .P See the bundler website \fIhttps://bundler\.io\fR for information on getting started, and Gemfile(5) for more information on the \fBGemfile\fR format\. . .SH "OPTIONS" . .TP \fB\-\-no\-color\fR Print all output without color . .TP \fB\-\-retry\fR, \fB\-r\fR Specify the number of times you wish to attempt network commands . .TP \fB\-\-verbose\fR, \fB\-V\fR Print out additional logging information . .SH "BUNDLE COMMANDS" We divide \fBbundle\fR subcommands into primary commands and utilities: . .SH "PRIMARY COMMANDS" . .TP \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR Install the gems specified by the \fBGemfile\fR or \fBGemfile\.lock\fR . .TP \fBbundle update(1)\fR \fIbundle\-update\.1\.html\fR Update dependencies to their latest versions . .TP \fBbundle package(1)\fR \fIbundle\-package\.1\.html\fR Package the \.gem files required by your application into the \fBvendor/cache\fR directory . .TP \fBbundle exec(1)\fR \fIbundle\-exec\.1\.html\fR Execute a script in the current bundle . .TP \fBbundle config(1)\fR \fIbundle\-config\.1\.html\fR Specify and read configuration options for Bundler . .TP \fBbundle help(1)\fR Display detailed help for each subcommand . .SH "UTILITIES" . .TP \fBbundle add(1)\fR \fIbundle\-add\.1\.html\fR Add the named gem to the Gemfile and run \fBbundle install\fR . .TP \fBbundle binstubs(1)\fR \fIbundle\-binstubs\.1\.html\fR Generate binstubs for executables in a gem . .TP \fBbundle check(1)\fR \fIbundle\-check\.1\.html\fR Determine whether the requirements for your application are installed and available to Bundler . .TP \fBbundle show(1)\fR \fIbundle\-show\.1\.html\fR Show the source location of a particular gem in the bundle . .TP \fBbundle outdated(1)\fR \fIbundle\-outdated\.1\.html\fR Show all of the outdated gems in the current bundle . .TP \fBbundle console(1)\fR Start an IRB session in the current bundle . .TP \fBbundle open(1)\fR \fIbundle\-open\.1\.html\fR Open an installed gem in the editor . .TP \fBbundle lock(1)\fR \fIbundle\-lock\.1\.html\fR Generate a lockfile for your dependencies . .TP \fBbundle viz(1)\fR \fIbundle\-viz\.1\.html\fR Generate a visual representation of your dependencies . .TP \fBbundle init(1)\fR \fIbundle\-init\.1\.html\fR Generate a simple \fBGemfile\fR, placed in the current directory . .TP \fBbundle gem(1)\fR \fIbundle\-gem\.1\.html\fR Create a simple gem, suitable for development with Bundler . .TP \fBbundle platform(1)\fR \fIbundle\-platform\.1\.html\fR Display platform compatibility information . .TP \fBbundle clean(1)\fR \fIbundle\-clean\.1\.html\fR Clean up unused gems in your Bundler directory . .TP \fBbundle doctor(1)\fR \fIbundle\-doctor\.1\.html\fR Display warnings about common problems . .TP \fBbundle remove(1)\fR \fIbundle\-remove\.1\.html\fR Removes gems from the Gemfile . .SH "PLUGINS" When running a command that isn\'t listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named \fBbundler\-\fR and execute it, passing down any extra arguments to it\. . .SH "OBSOLETE" These commands are obsolete and should no longer be used: . .IP "\(bu" 4 \fBbundle cache(1)\fR . .IP "\(bu" 4 \fBbundle show(1)\fR . .IP "" 0 PKu]|)$J$J3bundler-2.2.24/lib/bundler/man/bundle-config.1.ronnnu[bundle-config(1) -- Set bundler configuration options ===================================================== ## SYNOPSIS `bundle config` [list|get|set|unset] [ []] ## DESCRIPTION This command allows you to interact with Bundler's configuration system. Bundler loads configuration settings in this order: 1. Local config (`/.bundle/config` or `$BUNDLE_APP_CONFIG/config`) 2. Environmental variables (`ENV`) 3. Global config (`~/.bundle/config`) 4. Bundler default config Executing `bundle config list` with will print a list of all bundler configuration for the current bundle, and where that configuration was set. Executing `bundle config get ` will print the value of that configuration setting, and where it was set. Executing `bundle config set ` will set that configuration to the value specified for all bundles executed as the current user. The configuration will be stored in `~/.bundle/config`. If already is set, will be overridden and user will be warned. Executing `bundle config set --global ` works the same as above. Executing `bundle config set --local ` will set that configuration in the directory for the local application. The configuration will be stored in `/.bundle/config`. If `BUNDLE_APP_CONFIG` is set, the configuration will be stored in `$BUNDLE_APP_CONFIG/config`. Executing `bundle config unset ` will delete the configuration in both local and global sources. Executing `bundle config unset --global ` will delete the configuration only from the user configuration. Executing `bundle config unset --local ` will delete the configuration only from the local application. Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will cause it to ignore all configuration. ## REMEMBERING OPTIONS Flags passed to `bundle install` or the Bundler runtime, such as `--path foo` or `--without production`, are remembered between commands and saved to your local application's configuration (normally, `./.bundle/config`). However, this will be changed in bundler 3, so it's better not to rely on this behavior. If these options must be remembered, it's better to set them using `bundle config` (e.g., `bundle config set --local path foo`). The options that can be configured are: * `bin`: Creates a directory (defaults to `~/bin`) and place any executables from the gem there. These executables run in Bundler's context. If used, you might add this directory to your environment's `PATH` variable. For instance, if the `rails` gem comes with a `rails` executable, this flag will create a `bin/rails` executable that ensures that all referred dependencies will be resolved using the bundled gems. * `deployment`: In deployment mode, Bundler will 'roll-out' the bundle for `production` use. Please check carefully if you want to have this option enabled in `development` or `test` environments. * `path`: The location to install the specified gems to. This defaults to Rubygems' setting. Bundler shares this location with Rubygems, `gem install ...` will have gem installed there, too. Therefore, gems installed without a `--path ...` setting will show up by calling `gem list`. Accordingly, gems installed to other locations will not get listed. * `without`: A space-separated list of groups referencing gems to skip during installation. * `with`: A space-separated list of groups referencing gems to include during installation. ## BUILD OPTIONS You can use `bundle config` to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem. A very common example, the `mysql` gem, requires Snow Leopard users to pass configuration flags to `gem install` to specify where to find the `mysql_config` executable. gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config Since the specific location of that executable can change from machine to machine, you can specify these flags on a per-machine basis. bundle config set --global build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config After running this command, every time bundler needs to install the `mysql` gem, it will pass along the flags you specified. ## CONFIGURATION KEYS Configuration keys in bundler have two forms: the canonical form and the environment variable form. For instance, passing the `--without` flag to [bundle install(1)](bundle-install.1.html) prevents Bundler from installing certain groups specified in the Gemfile(5). Bundler persists this value in `app/.bundle/config` so that calls to `Bundler.setup` do not try to find gems from the `Gemfile` that you didn't install. Additionally, subsequent calls to [bundle install(1)](bundle-install.1.html) remember this setting and skip those groups. The canonical form of this configuration is `"without"`. To convert the canonical form to the environment variable form, capitalize it, and prepend `BUNDLE_`. The environment variable form of `"without"` is `BUNDLE_WITHOUT`. Any periods in the configuration keys must be replaced with two underscores when setting it via environment variables. The configuration key `local.rack` becomes the environment variable `BUNDLE_LOCAL__RACK`. ## LIST OF AVAILABLE KEYS The following is a list of all configuration keys and their purpose. You can learn more about their operation in [bundle install(1)](bundle-install.1.html). * `allow_deployment_source_credential_changes` (`BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES`): When in deployment mode, allow changing the credentials to a gem's source. Ex: `https://some.host.com/gems/path/` -> `https://user_name:password@some.host.com/gems/path` * `allow_offline_install` (`BUNDLE_ALLOW_OFFLINE_INSTALL`): Allow Bundler to use cached data when installing without network access. * `auto_clean_without_path` (`BUNDLE_AUTO_CLEAN_WITHOUT_PATH`): Automatically run `bundle clean` after installing when an explicit `path` has not been set and Bundler is not installing into the system gems. * `auto_install` (`BUNDLE_AUTO_INSTALL`): Automatically run `bundle install` when gems are missing. * `bin` (`BUNDLE_BIN`): Install executables from gems in the bundle to the specified directory. Defaults to `false`. * `cache_all` (`BUNDLE_CACHE_ALL`): Cache all gems, including path and git gems. This needs to be explicitly configured on bundler 1 and bundler 2, but will be the default on bundler 3. * `cache_all_platforms` (`BUNDLE_CACHE_ALL_PLATFORMS`): Cache gems for all platforms. * `cache_path` (`BUNDLE_CACHE_PATH`): The directory that bundler will place cached gems in when running bundle package, and that bundler will look in when installing gems. Defaults to `vendor/cache`. * `clean` (`BUNDLE_CLEAN`): Whether Bundler should run `bundle clean` automatically after `bundle install`. * `console` (`BUNDLE_CONSOLE`): The console that `bundle console` starts. Defaults to `irb`. * `default_install_uses_path` (`BUNDLE_DEFAULT_INSTALL_USES_PATH`): Whether a `bundle install` without an explicit `--path` argument defaults to installing gems in `.bundle`. * `deployment` (`BUNDLE_DEPLOYMENT`): Disallow changes to the `Gemfile`. When the `Gemfile` is changed and the lockfile has not been updated, running Bundler commands will be blocked. * `disable_checksum_validation` (`BUNDLE_DISABLE_CHECKSUM_VALIDATION`): Allow installing gems even if they do not match the checksum provided by RubyGems. * `disable_exec_load` (`BUNDLE_DISABLE_EXEC_LOAD`): Stop Bundler from using `load` to launch an executable in-process in `bundle exec`. * `disable_local_branch_check` (`BUNDLE_DISABLE_LOCAL_BRANCH_CHECK`): Allow Bundler to use a local git override without a branch specified in the Gemfile. * `disable_local_revision_check` (`BUNDLE_DISABLE_LOCAL_REVISION_CHECK`): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository. * `disable_shared_gems` (`BUNDLE_DISABLE_SHARED_GEMS`): Stop Bundler from accessing gems installed to RubyGems' normal location. * `disable_version_check` (`BUNDLE_DISABLE_VERSION_CHECK`): Stop Bundler from checking if a newer Bundler version is available on rubygems.org. * `force_ruby_platform` (`BUNDLE_FORCE_RUBY_PLATFORM`): Ignore the current machine's platform and install only `ruby` platform gems. As a result, gems with native extensions will be compiled from source. * `frozen` (`BUNDLE_FROZEN`): Disallow changes to the `Gemfile`. When the `Gemfile` is changed and the lockfile has not been updated, running Bundler commands will be blocked. Defaults to `true` when `--deployment` is used. * `gem.github_username` (`BUNDLE_GEM__GITHUB_USERNAME`): Sets a GitHub username or organization to be used in `README` file when you create a new gem via `bundle gem` command. It can be overridden by passing an explicit `--github-username` flag to `bundle gem`. * `gem.push_key` (`BUNDLE_GEM__PUSH_KEY`): Sets the `--key` parameter for `gem push` when using the `rake release` command with a private gemstash server. * `gemfile` (`BUNDLE_GEMFILE`): The name of the file that bundler should use as the `Gemfile`. This location of this file also sets the root of the project, which is used to resolve relative paths in the `Gemfile`, among other things. By default, bundler will search up from the current working directory until it finds a `Gemfile`. * `global_gem_cache` (`BUNDLE_GLOBAL_GEM_CACHE`): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation. * `ignore_messages` (`BUNDLE_IGNORE_MESSAGES`): When set, no post install messages will be printed. To silence a single gem, use dot notation like `ignore_messages.httparty true`. * `init_gems_rb` (`BUNDLE_INIT_GEMS_RB`): Generate a `gems.rb` instead of a `Gemfile` when running `bundle init`. * `jobs` (`BUNDLE_JOBS`): The number of gems Bundler can install in parallel. Defaults to 1 on Windows, and to the the number of processors on other platforms. * `no_install` (`BUNDLE_NO_INSTALL`): Whether `bundle package` should skip installing gems. * `no_prune` (`BUNDLE_NO_PRUNE`): Whether Bundler should leave outdated gems unpruned when caching. * `path` (`BUNDLE_PATH`): The location on disk where all gems in your bundle will be located regardless of `$GEM_HOME` or `$GEM_PATH` values. Bundle gems not found in this location will be installed by `bundle install`. Defaults to `Gem.dir`. When --deployment is used, defaults to vendor/bundle. * `path.system` (`BUNDLE_PATH__SYSTEM`): Whether Bundler will install gems into the default system path (`Gem.dir`). * `path_relative_to_cwd` (`BUNDLE_PATH_RELATIVE_TO_CWD`) Makes `--path` relative to the CWD instead of the `Gemfile`. * `plugins` (`BUNDLE_PLUGINS`): Enable Bundler's experimental plugin system. * `prefer_patch` (BUNDLE_PREFER_PATCH): Prefer updating only to next patch version during updates. Makes `bundle update` calls equivalent to `bundler update --patch`. * `print_only_version_number` (`BUNDLE_PRINT_ONLY_VERSION_NUMBER`): Print only version number from `bundler --version`. * `redirect` (`BUNDLE_REDIRECT`): The number of redirects allowed for network requests. Defaults to `5`. * `retry` (`BUNDLE_RETRY`): The number of times to retry failed network requests. Defaults to `3`. * `setup_makes_kernel_gem_public` (`BUNDLE_SETUP_MAKES_KERNEL_GEM_PUBLIC`): Have `Bundler.setup` make the `Kernel#gem` method public, even though RubyGems declares it as private. * `shebang` (`BUNDLE_SHEBANG`): The program name that should be invoked for generated binstubs. Defaults to the ruby install name used to generate the binstub. * `silence_deprecations` (`BUNDLE_SILENCE_DEPRECATIONS`): Whether Bundler should silence deprecation warnings for behavior that will be changed in the next major version. * `silence_root_warning` (`BUNDLE_SILENCE_ROOT_WARNING`): Silence the warning Bundler prints when installing gems as root. * `ssl_ca_cert` (`BUNDLE_SSL_CA_CERT`): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format. * `ssl_client_cert` (`BUNDLE_SSL_CLIENT_CERT`): Path to a designated file containing a X.509 client certificate and key in PEM format. * `ssl_verify_mode` (`BUNDLE_SSL_VERIFY_MODE`): The SSL verification mode Bundler uses when making HTTPS requests. Defaults to verify peer. * `suppress_install_using_messages` (`BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES`): Avoid printing `Using ...` messages during installation when the version of a gem has not changed. * `system_bindir` (`BUNDLE_SYSTEM_BINDIR`): The location where RubyGems installs binstubs. Defaults to `Gem.bindir`. * `timeout` (`BUNDLE_TIMEOUT`): The seconds allowed before timing out for network requests. Defaults to `10`. * `update_requires_all_flag` (`BUNDLE_UPDATE_REQUIRES_ALL_FLAG`): Require passing `--all` to `bundle update` when everything should be updated, and disallow passing no options to `bundle update`. * `user_agent` (`BUNDLE_USER_AGENT`): The custom user agent fragment Bundler includes in API requests. * `with` (`BUNDLE_WITH`): A `:`-separated list of groups whose gems bundler should install. * `without` (`BUNDLE_WITHOUT`): A `:`-separated list of groups whose gems bundler should not install. In general, you should set these settings per-application by using the applicable flag to the [bundle install(1)](bundle-install.1.html) or [bundle package(1)](bundle-package.1.html) command. You can set them globally either via environment variables or `bundle config`, whichever is preferable for your setup. If you use both, environment variables will take preference over global settings. ## LOCAL GIT REPOS Bundler also allows you to work against a git repository locally instead of using the remote version. This can be achieved by setting up a local override: bundle config set --local local.GEM_NAME /path/to/local/git/repository For example, in order to use a local Rack repository, a developer could call: bundle config set --local local.rack ~/Work/git/rack Now instead of checking out the remote git repository, the local override will be used. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler. This means a commit in the local git repo will update the revision in the `Gemfile.lock` to the local git repo revision. This requires the same attention as git submodules. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine. You'll also need to CGI escape your usernames and passwords as well. Bundler does many checks to ensure a developer won't work with invalid references. Particularly, we force a developer to specify a branch in the `Gemfile` in order to use this feature. If the branch specified in the `Gemfile` and the current branch in the local git repository do not match, Bundler will abort. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch. Finally, Bundler also ensures that the current revision in the `Gemfile.lock` exists in the local git repository. By doing this, Bundler forces you to fetch the latest changes in the remotes. ## MIRRORS OF GEM SOURCES Bundler supports overriding gem sources with mirrors. This allows you to configure rubygems.org as the gem source in your Gemfile while still using your mirror to fetch gems. bundle config set --global mirror.SOURCE_URL MIRROR_URL For example, to use a mirror of rubygems.org hosted at rubygems-mirror.org: bundle config set --global mirror.http://rubygems.org http://rubygems-mirror.org Each mirror also provides a fallback timeout setting. If the mirror does not respond within the fallback timeout, Bundler will try to use the original server instead of the mirror. bundle config set --global mirror.SOURCE_URL.fallback_timeout TIMEOUT For example, to fall back to rubygems.org after 3 seconds: bundle config set --global mirror.https://rubygems.org.fallback_timeout 3 The default fallback timeout is 0.1 seconds, but the setting can currently only accept whole seconds (for example, 1, 15, or 30). ## CREDENTIALS FOR GEM SOURCES Bundler allows you to configure credentials for any gem source, which allows you to avoid putting secrets into your Gemfile. bundle config set --global SOURCE_HOSTNAME USERNAME:PASSWORD For example, to save the credentials of user `claudette` for the gem source at `gems.longerous.com`, you would run: bundle config set --global gems.longerous.com claudette:s00pers3krit Or you can set the credentials as an environment variable like this: export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit" For gems with a git source with HTTP(S) URL you can specify credentials like so: bundle config set --global https://github.com/rubygems/rubygems.git username:password Or you can set the credentials as an environment variable like so: export BUNDLE_GITHUB__COM=username:password This is especially useful for private repositories on hosts such as Github, where you can use personal OAuth tokens: export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x-oauth-basic Note that any configured credentials will be redacted by informative commands such as `bundle config list` or `bundle config get`, unless you use the `--parseable` flag. This is to avoid unintentially leaking credentials when copy-pasting bundler output. Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations: * Any `-` characters in a host name are mapped to a triple dash (`___`) in the corresponding enviroment variable. * Any `.` characters in a host name are mapped to a double dash (`__`) in the corresponding environment variable. This means that if you have a gem server named `my.gem-host.com`, you'll need to use the `BUNDLE_MY__GEM___HOST__COM` variable to configure credentials for it through ENV. ## CONFIGURE BUNDLER DIRECTORIES Bundler's home, config, cache and plugin directories are able to be configured through environment variables. The default location for Bundler's home directory is `~/.bundle`, which all directories inherit from by default. The following outlines the available environment variables and their default values BUNDLE_USER_HOME : $HOME/.bundle BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin PKu]ms s ,bundler-2.2.24/lib/bundler/man/bundle-lock.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-LOCK" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing . .SH "SYNOPSIS" \fBbundle lock\fR [\-\-update] [\-\-local] [\-\-print] [\-\-lockfile=PATH] [\-\-full\-index] [\-\-add\-platform] [\-\-remove\-platform] [\-\-patch] [\-\-minor] [\-\-major] [\-\-strict] [\-\-conservative] . .SH "DESCRIPTION" Lock the gems specified in Gemfile\. . .SH "OPTIONS" . .TP \fB\-\-update=<*gems>\fR Ignores the existing lockfile\. Resolve then updates lockfile\. Taking a list of gems or updating all gems if no list is given\. . .TP \fB\-\-local\fR Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. . .TP \fB\-\-print\fR Prints the lockfile to STDOUT instead of writing to the file system\. . .TP \fB\-\-lockfile=\fR The path where the lockfile should be written to\. . .TP \fB\-\-full\-index\fR Fall back to using the single\-file index of all gems\. . .TP \fB\-\-add\-platform\fR Add a new platform to the lockfile, re\-resolving for the addition of that platform\. . .TP \fB\-\-remove\-platform\fR Remove a platform from the lockfile\. . .TP \fB\-\-patch\fR If updating, prefer updating only to next patch version\. . .TP \fB\-\-minor\fR If updating, prefer updating only to next minor version\. . .TP \fB\-\-major\fR If updating, prefer updating to next major version (default)\. . .TP \fB\-\-strict\fR If updating, do not allow any gem to be updated past latest \-\-patch | \-\-minor | \-\-major\. . .TP \fB\-\-conservative\fR If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated\. . .SH "UPDATING ALL GEMS" If you run \fBbundle lock\fR with \fB\-\-update\fR option without list of gems, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. . .SH "UPDATING A LIST OF GEMS" Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. . .P For instance, you only want to update \fBnokogiri\fR, run \fBbundle lock \-\-update nokogiri\fR\. . .P Bundler will update \fBnokogiri\fR and any of its dependencies, but leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. . .SH "SUPPORTING OTHER PLATFORMS" If you want your bundle to support platforms other than the one you\'re running locally, you can run \fBbundle lock \-\-add\-platform PLATFORM\fR to add PLATFORM to the lockfile, force bundler to re\-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform\-specific gems on\. . .P For a full explanation of gem platforms, see \fBgem help platform\fR\. . .SH "PATCH LEVEL OPTIONS" See bundle update(1) \fIbundle\-update\.1\.html\fR for details\. PKu]m-bundler-2.2.24/lib/bundler/man/bundle-check.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-CHECK" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems . .SH "SYNOPSIS" \fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE] [\-\-path=PATH] . .SH "DESCRIPTION" \fBcheck\fR searches the local machine for each of the gems requested in the Gemfile\. If all gems are found, Bundler prints a success message and exits with a status of 0\. . .P If not, the first missing gem is listed and Bundler exits status 1\. . .SH "OPTIONS" . .TP \fB\-\-dry\-run\fR Locks the [\fBGemfile(5)\fR][Gemfile(5)] before running the command\. . .TP \fB\-\-gemfile\fR Use the specified gemfile instead of the [\fBGemfile(5)\fR][Gemfile(5)]\. . .TP \fB\-\-path\fR Specify a different path than the system default (\fB$BUNDLE_PATH\fR or \fB$GEM_HOME\fR)\. Bundler will remember this value for future installs on this machine\. PKu]\'iTT1bundler-2.2.24/lib/bundler/man/bundle-show.1.ronnnu[bundle-show(1) -- Shows all the gems in your bundle, or the path to a gem ========================================================================= ## SYNOPSIS `bundle show` [GEM] [--paths] ## DESCRIPTION Without the [GEM] option, `show` will print a list of the names and versions of all gems that are required by your [`Gemfile(5)`][Gemfile(5)], sorted by name. Calling show with [GEM] will list the exact location of that gem on your machine. ## OPTIONS * `--paths`: List the paths of all gems that are required by your [`Gemfile(5)`][Gemfile(5)], sorted by gem name. PKu]˱[y3bundler-2.2.24/lib/bundler/man/bundle-remove.1.ronnnu[bundle-remove(1) -- Removes gems from the Gemfile =========================================================================== ## SYNOPSIS `bundle remove [GEM [GEM ...]] [--install]` ## DESCRIPTION Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If a gem cannot be removed, a warning is printed. If a gem is already absent from the Gemfile, and error is raised. ## OPTIONS * `--install`: Runs `bundle install` after the given gems have been removed from the Gemfile, which ensures that both the lockfile and the installed gems on disk are also updated to remove the given gem(s). Example: bundle remove rails bundle remove rails rack bundle remove rails rack --install PKu]h1bundler-2.2.24/lib/bundler/man/bundle-init.1.ronnnu[bundle-init(1) -- Generates a Gemfile into the current working directory ======================================================================== ## SYNOPSIS `bundle init` [--gemspec=FILE] ## DESCRIPTION Init generates a default [`Gemfile(5)`][Gemfile(5)] in the current working directory. When adding a [`Gemfile(5)`][Gemfile(5)] to a gem with a gemspec, the `--gemspec` option will automatically add each dependency listed in the gemspec file to the newly created [`Gemfile(5)`][Gemfile(5)]. ## OPTIONS * `--gemspec`: Use the specified .gemspec to create the [`Gemfile(5)`][Gemfile(5)] ## FILES Included in the default [`Gemfile(5)`][Gemfile(5)] generated is the line `# frozen_string_literal: true`. This is a magic comment supported for the first time in Ruby 2.3. The presence of this line results in all string literals in the file being implicitly frozen. ## SEE ALSO [Gemfile(5)](https://bundler.io/man/gemfile.5.html) PKu]+B+B4bundler-2.2.24/lib/bundler/man/bundle-install.1.ronnnu[bundle-install(1) -- Install the dependencies specified in your Gemfile ======================================================================= ## SYNOPSIS `bundle install` [--binstubs[=DIRECTORY]] [--clean] [--deployment] [--frozen] [--full-index] [--gemfile=GEMFILE] [--jobs=NUMBER] [--local] [--no-cache] [--no-prune] [--path PATH] [--quiet] [--redownload] [--retry=NUMBER] [--shebang] [--standalone[=GROUP[ GROUP...]]] [--system] [--trust-policy=POLICY] [--with=GROUP[ GROUP...]] [--without=GROUP[ GROUP...]] ## DESCRIPTION Install the gems specified in your Gemfile(5). If this is the first time you run bundle install (and a `Gemfile.lock` does not exist), Bundler will fetch all remote sources, resolve dependencies and install all needed gems. If a `Gemfile.lock` does exist, and you have not updated your Gemfile(5), Bundler will fetch all remote sources, but use the dependencies specified in the `Gemfile.lock` instead of resolving dependencies. If a `Gemfile.lock` does exist, and you have updated your Gemfile(5), Bundler will use the dependencies in the `Gemfile.lock` for all gems that you did not update, but will re-resolve the dependencies of gems that you did update. You can find more information about this update process below under [CONSERVATIVE UPDATING][]. ## OPTIONS The `--clean`, `--deployment`, `--frozen`, `--no-prune`, `--path`, `--shebang`, `--system`, `--without` and `--with` options are deprecated because they only make sense if they are applied to every subsequent `bundle install` run automatically and that requires `bundler` to silently remember them. Since `bundler` will no longer remember CLI flags in future versions, `bundle config` (see bundle-config(1)) should be used to apply them permanently. * `--binstubs[=]`: Binstubs are scripts that wrap around executables. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it in `bin/`. This lets you link the binstub inside of an application to the exact gem version the application needs. Creates a directory (defaults to `~/bin`) and places any executables from the gem there. These executables run in Bundler's context. If used, you might add this directory to your environment's `PATH` variable. For instance, if the `rails` gem comes with a `rails` executable, this flag will create a `bin/rails` executable that ensures that all referred dependencies will be resolved using the bundled gems. * `--clean`: On finishing the installation Bundler is going to remove any gems not present in the current Gemfile(5). Don't worry, gems currently in use will not be removed. This option is deprecated in favor of the `clean` setting. * `--deployment`: In [deployment mode][DEPLOYMENT MODE], Bundler will 'roll-out' the bundle for production or CI use. Please check carefully if you want to have this option enabled in your development environment. This option is deprecated in favor of the `deployment` setting. * `--redownload`: Force download every gem, even if the required versions are already available locally. * `--frozen`: Do not allow the Gemfile.lock to be updated after this install. Exits non-zero if there are going to be changes to the Gemfile.lock. This option is deprecated in favor of the `frozen` setting. * `--full-index`: Bundler will not call Rubygems' API endpoint (default) but download and cache a (currently big) index file of all gems. Performance can be improved for large bundles that seldom change by enabling this option. * `--gemfile=`: The location of the Gemfile(5) which Bundler should use. This defaults to a Gemfile(5) in the current working directory. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find `Gemfile.lock` and `vendor/cache` relative to this location. * `--jobs=[]`, `-j[]`: The maximum number of parallel download and install jobs. The default is `1`. * `--local`: Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the gems already present in Rubygems' cache or in `vendor/cache`. Note that if an appropriate platform-specific gem exists on `rubygems.org` it will not be found. * `--no-cache`: Do not update the cache in `vendor/cache` with the newly bundled gems. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install. * `--no-prune`: Don't remove stale gems from the cache when the installation finishes. This option is deprecated in favor of the `no_prune` setting. * `--path=`: The location to install the specified gems to. This defaults to Rubygems' setting. Bundler shares this location with Rubygems, `gem install ...` will have gem installed there, too. Therefore, gems installed without a `--path ...` setting will show up by calling `gem list`. Accordingly, gems installed to other locations will not get listed. This option is deprecated in favor of the `path` setting. * `--quiet`: Do not print progress information to the standard output. Instead, Bundler will exit using a status code (`$?`). * `--retry=[]`: Retry failed network or git requests for times. * `--shebang=`: Uses the specified ruby executable (usually `ruby`) to execute the scripts created with `--binstubs`. In addition, if you use `--binstubs` together with `--shebang jruby` these executables will be changed to execute `jruby` instead. This option is deprecated in favor of the `shebang` setting. * `--standalone[=]`: Makes a bundle that can work without depending on Rubygems or Bundler at runtime. A space separated list of groups to install has to be specified. Bundler creates a directory named `bundle` and installs the bundle there. It also generates a `bundle/bundler/setup.rb` file to replace Bundler's own setup in the manner required. Using this option implicitly sets `path`, which is a [remembered option][REMEMBERED OPTIONS]. * `--system`: Installs the gems specified in the bundle to the system's Rubygems location. This overrides any previous configuration of `--path`. This option is deprecated in favor of the `system` setting. * `--trust-policy=[]`: Apply the Rubygems security policy , where policy is one of `HighSecurity`, `MediumSecurity`, `LowSecurity`, `AlmostNoSecurity`, or `NoSecurity`. For more details, please see the Rubygems signing documentation linked below in [SEE ALSO][]. * `--with=`: A space-separated list of groups referencing gems to install. If an optional group is given it is installed. If a group is given that is in the remembered list of groups given to --without, it is removed from that list. This option is deprecated in favor of the `with` setting. * `--without=`: A space-separated list of groups referencing gems to skip during installation. If a group is given that is in the remembered list of groups given to --with, it is removed from that list. This option is deprecated in favor of the `without` setting. ## DEPLOYMENT MODE Bundler's defaults are optimized for development. To switch to defaults optimized for deployment and for CI, use the `--deployment` flag. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified. 1. A `Gemfile.lock` is required. To ensure that the same versions of the gems you developed with and tested with are also used in deployments, a `Gemfile.lock` is required. This is mainly to ensure that you remember to check your `Gemfile.lock` into version control. 2. The `Gemfile.lock` must be up to date In development, you can modify your Gemfile(5) and re-run `bundle install` to [conservatively update][CONSERVATIVE UPDATING] your `Gemfile.lock` snapshot. In deployment, your `Gemfile.lock` should be up-to-date with changes made in your Gemfile(5). 3. Gems are installed to `vendor/bundle` not your default system location In development, it's convenient to share the gems used in your application with other applications and other scripts that run on the system. In deployment, isolation is a more important default. In addition, the user deploying the application may not have permission to install gems to the system, or the web server may not have permission to read them. As a result, `bundle install --deployment` installs gems to the `vendor/bundle` directory in the application. This may be overridden using the `--path` option. ## SUDO USAGE By default, Bundler installs gems to the same location as `gem install`. In some cases, that location may not be writable by your Unix user. In that case, Bundler will stage everything in a temporary directory, then ask you for your `sudo` password in order to copy the gems into their system location. From your perspective, this is identical to installing the gems directly into the system. You should never use `sudo bundle install`. This is because several other steps in `bundle install` must be performed as the current user: * Updating your `Gemfile.lock` * Updating your `vendor/cache`, if necessary * Checking out private git repositories using your user's SSH keys Of these three, the first two could theoretically be performed by `chown`ing the resulting files to `$SUDO_USER`. The third, however, can only be performed by invoking the `git` command as the current user. Therefore, git gems are downloaded and installed into `~/.bundle` rather than $GEM_HOME or $BUNDLE_PATH. As a result, you should run `bundle install` as the current user, and Bundler will ask for your password if it is needed to put the gems into their final location. ## INSTALLING GROUPS By default, `bundle install` will install all gems in all groups in your Gemfile(5), except those declared for a different platform. However, you can explicitly tell Bundler to skip installing certain groups with the `--without` option. This option takes a space-separated list of groups. While the `--without` option will skip _installing_ the gems in the specified groups, it will still _download_ those gems and use them to resolve the dependencies of every gem in your Gemfile(5). This is so that installing a different set of groups on another machine (such as a production server) will not change the gems and versions that you have already developed and tested against. `Bundler offers a rock-solid guarantee that the third-party code you are running in development and testing is also the third-party code you are running in production. You can choose to exclude some of that code in different environments, but you will never be caught flat-footed by different versions of third-party code being used in different environments.` For a simple illustration, consider the following Gemfile(5): source 'https://rubygems.org' gem 'sinatra' group :production do gem 'rack-perftools-profiler' end In this case, `sinatra` depends on any version of Rack (`>= 1.0`), while `rack-perftools-profiler` depends on 1.x (`~> 1.0`). When you run `bundle install --without production` in development, we look at the dependencies of `rack-perftools-profiler` as well. That way, you do not spend all your time developing against Rack 2.0, using new APIs unavailable in Rack 1.x, only to have Bundler switch to Rack 1.2 when the `production` group _is_ used. This should not cause any problems in practice, because we do not attempt to `install` the gems in the excluded groups, and only evaluate as part of the dependency resolution process. This also means that you cannot include different versions of the same gem in different groups, because doing so would result in different sets of dependencies used in development and production. Because of the vagaries of the dependency resolution process, this usually affects more than the gems you list in your Gemfile(5), and can (surprisingly) radically change the gems you are using. ## THE GEMFILE.LOCK When you run `bundle install`, Bundler will persist the full names and versions of all gems that you used (including dependencies of the gems specified in the Gemfile(5)) into a file called `Gemfile.lock`. Bundler uses this file in all subsequent calls to `bundle install`, which guarantees that you always use the same exact code, even as your application moves across machines. Because of the way dependency resolution works, even a seemingly small change (for instance, an update to a point-release of a dependency of a gem in your Gemfile(5)) can result in radically different gems being needed to satisfy all dependencies. As a result, you `SHOULD` check your `Gemfile.lock` into version control, in both applications and gems. If you do not, every machine that checks out your repository (including your production server) will resolve all dependencies again, which will result in different versions of third-party code being used if `any` of the gems in the Gemfile(5) or any of their dependencies have been updated. When Bundler first shipped, the `Gemfile.lock` was included in the `.gitignore` file included with generated gems. Over time, however, it became clear that this practice forces the pain of broken dependencies onto new contributors, while leaving existing contributors potentially unaware of the problem. Since `bundle install` is usually the first step towards a contribution, the pain of broken dependencies would discourage new contributors from contributing. As a result, we have revised our guidance for gem authors to now recommend checking in the lock for gems. ## CONSERVATIVE UPDATING When you make a change to the Gemfile(5) and then run `bundle install`, Bundler will update only the gems that you modified. In other words, if a gem that you `did not modify` worked before you called `bundle install`, it will continue to use the exact same versions of all dependencies as it used before the update. Let's take a look at an example. Here's your original Gemfile(5): source 'https://rubygems.org' gem 'actionpack', '2.3.8' gem 'activemerchant' In this case, both `actionpack` and `activemerchant` depend on `activesupport`. The `actionpack` gem depends on `activesupport 2.3.8` and `rack ~> 1.1.0`, while the `activemerchant` gem depends on `activesupport >= 2.3.2`, `braintree >= 2.0.0`, and `builder >= 2.0.0`. When the dependencies are first resolved, Bundler will select `activesupport 2.3.8`, which satisfies the requirements of both gems in your Gemfile(5). Next, you modify your Gemfile(5) to: source 'https://rubygems.org' gem 'actionpack', '3.0.0.rc' gem 'activemerchant' The `actionpack 3.0.0.rc` gem has a number of new dependencies, and updates the `activesupport` dependency to `= 3.0.0.rc` and the `rack` dependency to `~> 1.2.1`. When you run `bundle install`, Bundler notices that you changed the `actionpack` gem, but not the `activemerchant` gem. It evaluates the gems currently being used to satisfy its requirements: * `activesupport 2.3.8`: also used to satisfy a dependency in `activemerchant`, which is not being updated * `rack ~> 1.1.0`: not currently being used to satisfy another dependency Because you did not explicitly ask to update `activemerchant`, you would not expect it to suddenly stop working after updating `actionpack`. However, satisfying the new `activesupport 3.0.0.rc` dependency of actionpack requires updating one of its dependencies. Even though `activemerchant` declares a very loose dependency that theoretically matches `activesupport 3.0.0.rc`, Bundler treats gems in your Gemfile(5) that have not changed as an atomic unit together with their dependencies. In this case, the `activemerchant` dependency is treated as `activemerchant 1.7.1 + activesupport 2.3.8`, so `bundle install` will report that it cannot update `actionpack`. To explicitly update `actionpack`, including its dependencies which other gems in the Gemfile(5) still depend on, run `bundle update actionpack` (see `bundle update(1)`). `Summary`: In general, after making a change to the Gemfile(5) , you should first try to run `bundle install`, which will guarantee that no other gem in the Gemfile(5) is impacted by the change. If that does not work, run [bundle update(1)](bundle-update.1.html). ## SEE ALSO * [Gem install docs](http://guides.rubygems.org/rubygems-basics/#installing-gems) * [Rubygems signing docs](http://guides.rubygems.org/security/) PKu]^ ;ff,bundler-2.2.24/lib/bundler/man/bundle-exec.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-EXEC" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle . .SH "SYNOPSIS" \fBbundle exec\fR [\-\-keep\-file\-descriptors] \fIcommand\fR . .SH "DESCRIPTION" This command executes the command, making all gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] available to \fBrequire\fR in Ruby programs\. . .P Essentially, if you would normally have run something like \fBrspec spec/my_spec\.rb\fR, and you want to use the gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] and installed via bundle install(1) \fIbundle\-install\.1\.html\fR, you should run \fBbundle exec rspec spec/my_spec\.rb\fR\. . .P Note that \fBbundle exec\fR does not require that an executable is available on your shell\'s \fB$PATH\fR\. . .SH "OPTIONS" . .TP \fB\-\-keep\-file\-descriptors\fR Exec in Ruby 2\.0 began discarding non\-standard file descriptors\. When this flag is passed, exec will revert to the 1\.9 behaviour of passing all file descriptors to the new process\. . .SH "BUNDLE INSTALL \-\-BINSTUBS" If you use the \fB\-\-binstubs\fR flag in bundle install(1) \fIbundle\-install\.1\.html\fR, Bundler will automatically create a directory (which defaults to \fBapp_root/bin\fR) containing all of the executables available from gems in the bundle\. . .P After using \fB\-\-binstubs\fR, \fBbin/rspec spec/my_spec\.rb\fR is identical to \fBbundle exec rspec spec/my_spec\.rb\fR\. . .SH "ENVIRONMENT MODIFICATIONS" \fBbundle exec\fR makes a number of changes to the shell environment, then executes the command you specify in full\. . .IP "\(bu" 4 make sure that it\'s still possible to shell out to \fBbundle\fR from inside a command invoked by \fBbundle exec\fR (using \fB$BUNDLE_BIN_PATH\fR) . .IP "\(bu" 4 put the directory containing executables (like \fBrails\fR, \fBrspec\fR, \fBrackup\fR) for your bundle on \fB$PATH\fR . .IP "\(bu" 4 make sure that if bundler is invoked in the subshell, it uses the same \fBGemfile\fR (by setting \fBBUNDLE_GEMFILE\fR) . .IP "\(bu" 4 add \fB\-rbundler/setup\fR to \fB$RUBYOPT\fR, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle . .IP "" 0 . .P It also modifies Rubygems: . .IP "\(bu" 4 disallow loading additional gems not in the bundle . .IP "\(bu" 4 modify the \fBgem\fR method to be a no\-op if a gem matching the requirements is in the bundle, and to raise a \fBGem::LoadError\fR if it\'s not . .IP "\(bu" 4 Define \fBGem\.refresh\fR to be a no\-op, since the source index is always frozen when using bundler, and to prevent gems from the system leaking into the environment . .IP "\(bu" 4 Override \fBGem\.bin_path\fR to use the gems in the bundle, making system executables work . .IP "\(bu" 4 Add all gems in the bundle into Gem\.loaded_specs . .IP "" 0 . .P Finally, \fBbundle exec\fR also implicitly modifies \fBGemfile\.lock\fR if the lockfile and the Gemfile do not match\. Bundler needs the Gemfile to determine things such as a gem\'s groups, \fBautorequire\fR, and platforms, etc\., and that information isn\'t stored in the lockfile\. The Gemfile and lockfile must be synced in order to \fBbundle exec\fR successfully, so \fBbundle exec\fR updates the lockfile beforehand\. . .SS "Loading" By default, when attempting to \fBbundle exec\fR to a file with a ruby shebang, Bundler will \fBKernel\.load\fR that file instead of using \fBKernel\.exec\fR\. For the vast majority of cases, this is a performance improvement\. In a rare few cases, this could cause some subtle side\-effects (such as dependence on the exact contents of \fB$0\fR or \fB__FILE__\fR) and the optimization can be disabled by enabling the \fBdisable_exec_load\fR setting\. . .SS "Shelling out" Any Ruby code that opens a subshell (like \fBsystem\fR, backticks, or \fB%x{}\fR) will automatically use the current Bundler environment\. If you need to shell out to a Ruby command that is not part of your current bundle, use the \fBwith_clean_env\fR method with a block\. Any subshells created inside the block will be given the environment present before Bundler was activated\. For example, Homebrew commands run Ruby, but don\'t work inside a bundle: . .IP "" 4 . .nf Bundler\.with_clean_env do `brew install wget` end . .fi . .IP "" 0 . .P Using \fBwith_clean_env\fR is also necessary if you are shelling out to a different bundle\. Any Bundler commands run in a subshell will inherit the current Gemfile, so commands that need to run in the context of a different bundle also need to use \fBwith_clean_env\fR\. . .IP "" 4 . .nf Bundler\.with_clean_env do Dir\.chdir "/other/bundler/project" do `bundle exec \./script` end end . .fi . .IP "" 0 . .P Bundler provides convenience helpers that wrap \fBsystem\fR and \fBexec\fR, and they can be used like this: . .IP "" 4 . .nf Bundler\.clean_system(\'brew install wget\') Bundler\.clean_exec(\'brew install wget\') . .fi . .IP "" 0 . .SH "RUBYGEMS PLUGINS" At present, the Rubygems plugin system requires all files named \fBrubygems_plugin\.rb\fR on the load path of \fIany\fR installed gem when any Ruby code requires \fBrubygems\.rb\fR\. This includes executables installed into the system, like \fBrails\fR, \fBrackup\fR, and \fBrspec\fR\. . .P Since Rubygems plugins can contain arbitrary Ruby code, they commonly end up activating themselves or their dependencies\. . .P For instance, the \fBgemcutter 0\.5\fR gem depended on \fBjson_pure\fR\. If you had that version of gemcutter installed (even if you \fIalso\fR had a newer version without this problem), Rubygems would activate \fBgemcutter 0\.5\fR and \fBjson_pure \fR\. . .P If your Gemfile(5) also contained \fBjson_pure\fR (or a gem with a dependency on \fBjson_pure\fR), the latest version on your system might conflict with the version in your Gemfile(5), or the snapshot version in your \fBGemfile\.lock\fR\. . .P If this happens, bundler will say: . .IP "" 4 . .nf You have already activated json_pure 1\.4\.6 but your Gemfile requires json_pure 1\.4\.3\. Consider using bundle exec\. . .fi . .IP "" 0 . .P In this situation, you almost certainly want to remove the underlying gem with the problematic gem plugin\. In general, the authors of these plugins (in this case, the \fBgemcutter\fR gem) have released newer versions that are more careful in their plugins\. . .P You can find a list of all the gems containing gem plugins by running . .IP "" 4 . .nf ruby \-rrubygems \-e "puts Gem\.find_files(\'rubygems_plugin\.rb\')" . .fi . .IP "" 0 . .P At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren\'t using (\fBgem uninstall gem_name\fR)\. PKu]qq1bundler-2.2.24/lib/bundler/man/bundle-info.1.ronnnu[bundle-info(1) -- Show information for the given gem in your bundle ========================================================================= ## SYNOPSIS `bundle info` [GEM] [--path] ## DESCRIPTION Print the basic information about the provided GEM such as homepage, version, path and summary. ## OPTIONS * `--path`: Print the path of the given gem PKu]Ag880bundler-2.2.24/lib/bundler/man/bundle-platform.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-PLATFORM" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information . .SH "SYNOPSIS" \fBbundle platform\fR [\-\-ruby] . .SH "DESCRIPTION" \fBplatform\fR will display information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\. . .P For instance, using this Gemfile(5): . .IP "" 4 . .nf source "https://rubygems\.org" ruby "1\.9\.3" gem "rack" . .fi . .IP "" 0 . .P If you run \fBbundle platform\fR on Ruby 1\.9\.3, it will display the following output: . .IP "" 4 . .nf Your platform is: x86_64\-linux Your app has gems that work on these platforms: * ruby Your Gemfile specifies a Ruby version requirement: * ruby 1\.9\.3 Your current platform satisfies the Ruby version requirement\. . .fi . .IP "" 0 . .P \fBplatform\fR will list all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It will also let you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn\'t match the running Ruby VM, it will tell you what part does not\. . .SH "OPTIONS" . .TP \fB\-\-ruby\fR It will display the ruby directive information, so you don\'t have to parse it from the Gemfile(5)\. PKu]QdUU(bundler-2.2.24/lib/bundler/man/gemfile.5nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "GEMFILE" "5" "June 2021" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs . .SH "SYNOPSIS" A \fBGemfile\fR describes the gem dependencies required to execute associated Ruby code\. . .P Place the \fBGemfile\fR in the root of the directory containing the associated code\. For instance, in a Rails application, place the \fBGemfile\fR in the same directory as the \fBRakefile\fR\. . .SH "SYNTAX" A \fBGemfile\fR is evaluated as Ruby code, in a context which makes available a number of methods used to describe the gem requirements\. . .SH "GLOBAL SOURCES" At the top of the \fBGemfile\fR, add a line for the \fBRubygems\fR source that contains the gems listed in the \fBGemfile\fR\. . .IP "" 4 . .nf source "https://rubygems\.org" . .fi . .IP "" 0 . .P It is possible, but not recommended as of Bundler 1\.7, to add multiple global \fBsource\fR lines\. Each of these \fBsource\fRs \fBMUST\fR be a valid Rubygems repository\. . .P Sources are checked for gems following the heuristics described in \fISOURCE PRIORITY\fR\. If a gem is found in more than one global source, Bundler will print a warning after installing the gem indicating which source was used, and listing the other sources where the gem is available\. A specific source can be selected for gems that need to use a non\-standard repository, suppressing this warning, by using the \fI\fB:source\fR option\fR or a \fI\fBsource\fR block\fR\. . .SS "CREDENTIALS" Some gem sources require a username and password\. Use bundle config(1) \fIbundle\-config\.1\.html\fR to set the username and password for any of the sources that need it\. The command must be run once on each computer that will install the Gemfile, but this keeps the credentials from being stored in plain text in version control\. . .IP "" 4 . .nf bundle config gems\.example\.com user:password . .fi . .IP "" 0 . .P For some sources, like a company Gemfury account, it may be easier to include the credentials in the Gemfile as part of the source URL\. . .IP "" 4 . .nf source "https://user:password@gems\.example\.com" . .fi . .IP "" 0 . .P Credentials in the source URL will take precedence over credentials set using \fBconfig\fR\. . .SH "RUBY" If your application requires a specific Ruby version or engine, specify your requirements using the \fBruby\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\. . .SS "VERSION (required)" The version of Ruby that your application requires\. If your application requires an alternate Ruby engine, such as JRuby, Rubinius or TruffleRuby, this should be the Ruby version that the engine is compatible with\. . .IP "" 4 . .nf ruby "1\.9\.3" . .fi . .IP "" 0 . .SS "ENGINE" Each application \fImay\fR specify a Ruby engine\. If an engine is specified, an engine version \fImust\fR also be specified\. . .P What exactly is an Engine? \- A Ruby engine is an implementation of the Ruby language\. . .IP "\(bu" 4 For background: the reference or original implementation of the Ruby programming language is called Matz\'s Ruby Interpreter \fIhttps://en\.wikipedia\.org/wiki/Ruby_MRI\fR, or MRI for short\. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz\. MRI is also known as CRuby, because it is written in C\. MRI is the most widely used Ruby engine\. . .IP "\(bu" 4 Other implementations \fIhttps://www\.ruby\-lang\.org/en/about/\fR of Ruby exist\. Some of the more well\-known implementations include Rubinius \fIhttps://rubinius\.com/\fR, and JRuby \fIhttp://jruby\.org/\fR\. Rubinius is an alternative implementation of Ruby written in Ruby\. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine\. . .IP "" 0 . .SS "ENGINE VERSION" Each application \fImay\fR specify a Ruby engine version\. If an engine version is specified, an engine \fImust\fR also be specified\. If the engine is "ruby" the engine version specified \fImust\fR match the Ruby version\. . .IP "" 4 . .nf ruby "1\.8\.7", :engine => "jruby", :engine_version => "1\.6\.7" . .fi . .IP "" 0 . .SS "PATCHLEVEL" Each application \fImay\fR specify a Ruby patchlevel\. . .IP "" 4 . .nf ruby "2\.0\.0", :patchlevel => "247" . .fi . .IP "" 0 . .SH "GEMS" Specify gem requirements using the \fBgem\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\. . .SS "NAME (required)" For each gem requirement, list a single \fIgem\fR line\. . .IP "" 4 . .nf gem "nokogiri" . .fi . .IP "" 0 . .SS "VERSION" Each \fIgem\fR \fBMAY\fR have one or more version specifiers\. . .IP "" 4 . .nf gem "nokogiri", ">= 1\.4\.2" gem "RedCloth", ">= 4\.1\.0", "< 4\.2\.0" . .fi . .IP "" 0 . .SS "REQUIRE AS" Each \fIgem\fR \fBMAY\fR specify files that should be used when autorequiring via \fBBundler\.require\fR\. You may pass an array with multiple files or \fBtrue\fR if the file you want \fBrequired\fR has the same name as \fIgem\fR or \fBfalse\fR to prevent any file from being autorequired\. . .IP "" 4 . .nf gem "redis", :require => ["redis/connection/hiredis", "redis"] gem "webmock", :require => false gem "byebug", :require => true . .fi . .IP "" 0 . .P The argument defaults to the name of the gem\. For example, these are identical: . .IP "" 4 . .nf gem "nokogiri" gem "nokogiri", :require => "nokogiri" gem "nokogiri", :require => true . .fi . .IP "" 0 . .SS "GROUPS" Each \fIgem\fR \fBMAY\fR specify membership in one or more groups\. Any \fIgem\fR that does not specify membership in any group is placed in the \fBdefault\fR group\. . .IP "" 4 . .nf gem "rspec", :group => :test gem "wirble", :groups => [:development, :test] . .fi . .IP "" 0 . .P The Bundler runtime allows its two main methods, \fBBundler\.setup\fR and \fBBundler\.require\fR, to limit their impact to particular groups\. . .IP "" 4 . .nf # setup adds gems to Ruby\'s load path Bundler\.setup # defaults to all groups require "bundler/setup" # same as Bundler\.setup Bundler\.setup(:default) # only set up the _default_ group Bundler\.setup(:test) # only set up the _test_ group (but `not` _default_) Bundler\.setup(:default, :test) # set up the _default_ and _test_ groups, but no others # require requires all of the gems in the specified groups Bundler\.require # defaults to the _default_ group Bundler\.require(:default) # identical Bundler\.require(:default, :test) # requires the _default_ and _test_ groups Bundler\.require(:test) # requires the _test_ group . .fi . .IP "" 0 . .P The Bundler CLI allows you to specify a list of groups whose gems \fBbundle install\fR should not install with the \fBwithout\fR configuration\. . .P To specify multiple groups to ignore, specify a list of groups separated by spaces\. . .IP "" 4 . .nf bundle config set \-\-local without test bundle config set \-\-local without development test . .fi . .IP "" 0 . .P Also, calling \fBBundler\.setup\fR with no parameters, or calling \fBrequire "bundler/setup"\fR will setup all groups except for the ones you excluded via \fB\-\-without\fR (since they are not available)\. . .P Note that on \fBbundle install\fR, bundler downloads and evaluates all gems, in order to create a single canonical list of all of the required gems and their dependencies\. This means that you cannot list different versions of the same gems in different groups\. For more details, see Understanding Bundler \fIhttps://bundler\.io/rationale\.html\fR\. . .SS "PLATFORMS" If a gem should only be used in a particular platform or set of platforms, you can specify them\. Platforms are essentially identical to groups, except that you do not need to use the \fB\-\-without\fR install\-time flag to exclude groups of gems for other platforms\. . .P There are a number of \fBGemfile\fR platforms: . .TP \fBruby\fR C Ruby (MRI), Rubinius or TruffleRuby, but \fBNOT\fR Windows . .TP \fBmri\fR Same as \fIruby\fR, but only C Ruby (MRI) . .TP \fBmingw\fR Windows 32 bit \'mingw32\' platform (aka RubyInstaller) . .TP \fBx64_mingw\fR Windows 64 bit \'mingw32\' platform (aka RubyInstaller x64) . .TP \fBrbx\fR Rubinius . .TP \fBjruby\fR JRuby . .TP \fBtruffleruby\fR TruffleRuby . .TP \fBmswin\fR Windows . .P You can restrict further by platform and version for all platforms \fIexcept\fR for \fBrbx\fR, \fBjruby\fR, \fBtruffleruby\fR and \fBmswin\fR\. . .P To specify a version in addition to a platform, append the version number without the delimiter to the platform\. For example, to specify that a gem should only be used on platforms with Ruby 2\.3, use: . .IP "" 4 . .nf ruby_23 . .fi . .IP "" 0 . .P The full list of platforms and supported versions includes: . .TP \fBruby\fR 1\.8, 1\.9, 2\.0, 2\.1, 2\.2, 2\.3, 2\.4, 2\.5, 2\.6 . .TP \fBmri\fR 1\.8, 1\.9, 2\.0, 2\.1, 2\.2, 2\.3, 2\.4, 2\.5, 2\.6 . .TP \fBmingw\fR 1\.8, 1\.9, 2\.0, 2\.1, 2\.2, 2\.3, 2\.4, 2\.5, 2\.6 . .TP \fBx64_mingw\fR 2\.0, 2\.1, 2\.2, 2\.3, 2\.4, 2\.5, 2\.6 . .P As with groups, you can specify one or more platforms: . .IP "" 4 . .nf gem "weakling", :platforms => :jruby gem "ruby\-debug", :platforms => :mri_18 gem "nokogiri", :platforms => [:mri_18, :jruby] . .fi . .IP "" 0 . .P All operations involving groups (\fBbundle install\fR \fIbundle\-install\.1\.html\fR, \fBBundler\.setup\fR, \fBBundler\.require\fR) behave exactly the same as if any groups not matching the current platform were explicitly excluded\. . .SS "SOURCE" You can select an alternate Rubygems repository for a gem using the \':source\' option\. . .IP "" 4 . .nf gem "some_internal_gem", :source => "https://gems\.example\.com" . .fi . .IP "" 0 . .P This forces the gem to be loaded from this source and ignores any global sources declared at the top level of the file\. If the gem does not exist in this source, it will not be installed\. . .P Bundler will search for child dependencies of this gem by first looking in the source selected for the parent, but if they are not found there, it will fall back on global sources using the ordering described in \fISOURCE PRIORITY\fR\. . .P Selecting a specific source repository this way also suppresses the ambiguous gem warning described above in \fIGLOBAL SOURCES (#source)\fR\. . .P Using the \fB:source\fR option for an individual gem will also make that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when adding gems with explicit sources, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources\. . .SS "GIT" If necessary, you can specify that a gem is located at a particular git repository using the \fB:git\fR parameter\. The repository can be accessed via several protocols: . .TP \fBHTTP(S)\fR gem "rails", :git => "https://github\.com/rails/rails\.git" . .TP \fBSSH\fR gem "rails", :git => "git@github\.com:rails/rails\.git" . .TP \fBgit\fR gem "rails", :git => "git://github\.com/rails/rails\.git" . .P If using SSH, the user that you use to run \fBbundle install\fR \fBMUST\fR have the appropriate keys available in their \fB$HOME/\.ssh\fR\. . .P \fBNOTE\fR: \fBhttp://\fR and \fBgit://\fR URLs should be avoided if at all possible\. These protocols are unauthenticated, so a man\-in\-the\-middle attacker can deliver malicious code and compromise your system\. HTTPS and SSH are strongly preferred\. . .P The \fBgroup\fR, \fBplatforms\fR, and \fBrequire\fR options are available and behave exactly the same as they would for a normal gem\. . .P A git repository \fBSHOULD\fR have at least one file, at the root of the directory containing the gem, with the extension \fB\.gemspec\fR\. This file \fBMUST\fR contain a valid gem specification, as expected by the \fBgem build\fR command\. . .P If a git repository does not have a \fB\.gemspec\fR, bundler will attempt to create one, but it will not contain any dependencies, executables, or C extension compilation instructions\. As a result, it may fail to properly integrate into your application\. . .P If a git repository does have a \fB\.gemspec\fR for the gem you attached it to, a version specifier, if provided, means that the git repository is only valid if the \fB\.gemspec\fR specifies a version matching the version specifier\. If not, bundler will print a warning\. . .IP "" 4 . .nf gem "rails", "2\.3\.8", :git => "https://github\.com/rails/rails\.git" # bundle install will fail, because the \.gemspec in the rails # repository\'s master branch specifies version 3\.0\.0 . .fi . .IP "" 0 . .P If a git repository does \fBnot\fR have a \fB\.gemspec\fR for the gem you attached it to, a version specifier \fBMUST\fR be provided\. Bundler will use this version in the simple \fB\.gemspec\fR it creates\. . .P Git repositories support a number of additional options\. . .TP \fBbranch\fR, \fBtag\fR, and \fBref\fR You \fBMUST\fR only specify at most one of these options\. The default is \fB:branch => "master"\fR\. For example: . .IP gem "rails", :git => "https://github\.com/rails/rails\.git", :branch => "5\-0\-stable" . .IP gem "rails", :git => "https://github\.com/rails/rails\.git", :tag => "v5\.0\.0" . .IP gem "rails", :git => "https://github\.com/rails/rails\.git", :ref => "4aded" . .TP \fBsubmodules\fR For reference, a git submodule \fIhttps://git\-scm\.com/book/en/v2/Git\-Tools\-Submodules\fR lets you have another git repository within a subfolder of your repository\. Specify \fB:submodules => true\fR to cause bundler to expand any submodules included in the git repository . .P If a git repository contains multiple \fB\.gemspecs\fR, each \fB\.gemspec\fR represents a gem located at the same place in the file system as the \fB\.gemspec\fR\. . .IP "" 4 . .nf |~rails [git root] | |\-rails\.gemspec [rails gem located here] |~actionpack | |\-actionpack\.gemspec [actionpack gem located here] |~activesupport | |\-activesupport\.gemspec [activesupport gem located here] |\.\.\. . .fi . .IP "" 0 . .P To install a gem located in a git repository, bundler changes to the directory containing the gemspec, runs \fBgem build name\.gemspec\fR and then installs the resulting gem\. The \fBgem build\fR command, which comes standard with Rubygems, evaluates the \fB\.gemspec\fR in the context of the directory in which it is located\. . .SS "GIT SOURCE" A custom git source can be defined via the \fBgit_source\fR method\. Provide the source\'s name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address: . .IP "" 4 . .nf git_source(:stash){ |repo_name| "https://stash\.corp\.acme\.pl/#{repo_name}\.git" } gem \'rails\', :stash => \'forks/rails\' . .fi . .IP "" 0 . .P In addition, if you wish to choose a specific branch: . .IP "" 4 . .nf gem "rails", :stash => "forks/rails", :branch => "branch_name" . .fi . .IP "" 0 . .SS "GITHUB" \fBNOTE\fR: This shorthand should be avoided until Bundler 2\.0, since it currently expands to an insecure \fBgit://\fR URL\. This allows a man\-in\-the\-middle attacker to compromise your system\. . .P If the git repository you want to use is hosted on GitHub and is public, you can use the :github shorthand to specify the github username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\. . .IP "" 4 . .nf gem "rails", :github => "rails/rails" gem "rails", :github => "rails" . .fi . .IP "" 0 . .P Are both equivalent to . .IP "" 4 . .nf gem "rails", :git => "git://github\.com/rails/rails\.git" . .fi . .IP "" 0 . .P Since the \fBgithub\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. . .SS "GIST" If the git repository you want to use is hosted as a Github Gist and is public, you can use the :gist shorthand to specify the gist identifier (without the trailing "\.git")\. . .IP "" 4 . .nf gem "the_hatch", :gist => "4815162342" . .fi . .IP "" 0 . .P Is equivalent to: . .IP "" 4 . .nf gem "the_hatch", :git => "https://gist\.github\.com/4815162342\.git" . .fi . .IP "" 0 . .P Since the \fBgist\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. . .SS "BITBUCKET" If the git repository you want to use is hosted on Bitbucket and is public, you can use the :bitbucket shorthand to specify the bitbucket username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\. . .IP "" 4 . .nf gem "rails", :bitbucket => "rails/rails" gem "rails", :bitbucket => "rails" . .fi . .IP "" 0 . .P Are both equivalent to . .IP "" 4 . .nf gem "rails", :git => "https://rails@bitbucket\.org/rails/rails\.git" . .fi . .IP "" 0 . .P Since the \fBbitbucket\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. . .SS "PATH" You can specify that a gem is located in a particular location on the file system\. Relative paths are resolved relative to the directory containing the \fBGemfile\fR\. . .P Similar to the semantics of the \fB:git\fR option, the \fB:path\fR option requires that the directory in question either contains a \fB\.gemspec\fR for the gem, or that you specify an explicit version that bundler should use\. . .P Unlike \fB:git\fR, bundler does not compile C extensions for gems specified as paths\. . .IP "" 4 . .nf gem "rails", :path => "vendor/rails" . .fi . .IP "" 0 . .P If you would like to use multiple local gems directly from the filesystem, you can set a global \fBpath\fR option to the path containing the gem\'s files\. This will automatically load gemspec files from subdirectories\. . .IP "" 4 . .nf path \'components\' do gem \'admin_ui\' gem \'public_ui\' end . .fi . .IP "" 0 . .SH "BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS" The \fB:source\fR, \fB:git\fR, \fB:path\fR, \fB:group\fR, and \fB:platforms\fR options may be applied to a group of gems by using block form\. . .IP "" 4 . .nf source "https://gems\.example\.com" do gem "some_internal_gem" gem "another_internal_gem" end git "https://github\.com/rails/rails\.git" do gem "activesupport" gem "actionpack" end platforms :ruby do gem "ruby\-debug" gem "sqlite3" end group :development, :optional => true do gem "wirble" gem "faker" end . .fi . .IP "" 0 . .P In the case of the group block form the :optional option can be given to prevent a group from being installed unless listed in the \fB\-\-with\fR option given to the \fBbundle install\fR command\. . .P In the case of the \fBgit\fR block form, the \fB:ref\fR, \fB:branch\fR, \fB:tag\fR, and \fB:submodules\fR options may be passed to the \fBgit\fR method, and all gems in the block will inherit those options\. . .P The presence of a \fBsource\fR block in a Gemfile also makes that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when defining source blocks, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources, either via source blocks or \fB:source\fR directives on individual gems\. . .SH "INSTALL_IF" The \fBinstall_if\fR method allows gems to be installed based on a proc or lambda\. This is especially useful for optional gems that can only be used if certain software is installed or some other conditions are met\. . .IP "" 4 . .nf install_if \-> { RUBY_PLATFORM =~ /darwin/ } do gem "pasteboard" end . .fi . .IP "" 0 . .SH "GEMSPEC" The \fB\.gemspec\fR \fIhttp://guides\.rubygems\.org/specification\-reference/\fR file is where you provide metadata about your gem to Rubygems\. Some required Gemspec attributes include the name, description, and homepage of your gem\. This is also where you specify the dependencies your gem needs to run\. . .P If you wish to use Bundler to help install dependencies for a gem while it is being developed, use the \fBgemspec\fR method to pull in the dependencies listed in the \fB\.gemspec\fR file\. . .P The \fBgemspec\fR method adds any runtime dependencies as gem requirements in the default group\. It also adds development dependencies as gem requirements in the \fBdevelopment\fR group\. Finally, it adds a gem requirement on your project (\fB:path => \'\.\'\fR)\. In conjunction with \fBBundler\.setup\fR, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths\. . .P The \fBgemspec\fR method supports optional \fB:path\fR, \fB:glob\fR, \fB:name\fR, and \fB:development_group\fR options, which control where bundler looks for the \fB\.gemspec\fR, the glob it uses to look for the gemspec (defaults to: "{,\fI,\fR/*}\.gemspec"), what named \fB\.gemspec\fR it uses (if more than one is present), and which group development dependencies are included in\. . .P When a \fBgemspec\fR dependency encounters version conflicts during resolution, the local version under development will always be selected \-\- even if there are remote versions that better match other requirements for the \fBgemspec\fR gem\. . .SH "SOURCE PRIORITY" When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order: . .IP "1." 4 The source explicitly attached to the gem (using \fB:source\fR, \fB:path\fR, or \fB:git\fR) . .IP "2." 4 For implicit gems (dependencies of explicit gems), any source, git, or path repository declared on the parent\. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from \fBrubygems\.org\fR . .IP "3." 4 The sources specified via global \fBsource\fR lines, searching each source in your \fBGemfile\fR from last added to first added\. . .IP "" 0 PKu]n½,bundler-2.2.24/lib/bundler/man/bundle-info.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-INFO" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle . .SH "SYNOPSIS" \fBbundle info\fR [GEM] [\-\-path] . .SH "DESCRIPTION" Print the basic information about the provided GEM such as homepage, version, path and summary\. . .SH "OPTIONS" . .TP \fB\-\-path\fR Print the path of the given gem PKu]6H3bundler-2.2.24/lib/bundler/man/bundle-doctor.1.ronnnu[bundle-doctor(1) -- Checks the bundle for common problems ========================================================= ## SYNOPSIS `bundle doctor` [--quiet] [--gemfile=GEMFILE] ## DESCRIPTION Checks your Gemfile and gem environment for common problems. If issues are detected, Bundler prints them and exits status 1. Otherwise, Bundler prints a success message and exits status 0. Examples of common problems caught by bundle-doctor include: * Invalid Bundler settings * Mismatched Ruby versions * Mismatched platforms * Uninstalled gems * Missing dependencies ## OPTIONS * `--quiet`: Only output warnings and errors. * `--gemfile=`: The location of the Gemfile(5) which Bundler should use. This defaults to a Gemfile(5) in the current working directory. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find `Gemfile.lock` and `vendor/cache` relative to this location. PKu]8XX-bundler-2.2.24/lib/bundler/man/bundle-clean.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-CLEAN" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory . .SH "SYNOPSIS" \fBbundle clean\fR [\-\-dry\-run] [\-\-force] . .SH "DESCRIPTION" This command will remove all unused gems in your bundler directory\. This is useful when you have made many changes to your gem dependencies\. . .SH "OPTIONS" . .TP \fB\-\-dry\-run\fR Print the changes, but do not clean the unused gems\. . .TP \fB\-\-force\fR Force a clean even if \fB\-\-path\fR is not set\. PKu]Y|LL0bundler-2.2.24/lib/bundler/man/bundle-binstubs.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-BINSTUBS" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems . .SH "SYNOPSIS" \fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-path PATH] [\-\-standalone] . .SH "DESCRIPTION" Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into \fBbin/\fR\. Binstubs are a shortcut\-or alternative\- to always using \fBbundle exec\fR\. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application\. . .P For example, if you run \fBbundle binstubs rspec\-core\fR, Bundler will create the file \fBbin/rspec\fR\. That file will contain enough code to load Bundler, tell it to load the bundled gems, and then run rspec\. . .P This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the \fB\-\-path\fR directory if one has been set\. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems\. . .SH "OPTIONS" . .TP \fB\-\-force\fR Overwrite existing binstubs if they exist\. . .TP \fB\-\-path\fR The location to install the specified binstubs to\. This defaults to \fBbin\fR\. . .TP \fB\-\-standalone\fR Makes binstubs that can work without depending on Rubygems or Bundler at runtime\. . .TP \fB\-\-shebang\fR Specify a different shebang executable name than the default (default \'ruby\') . .TP \fB\-\-all\fR Create binstubs for all gems in the bundle\. PKu]V#1bundler-2.2.24/lib/bundler/man/bundle-list.1.ronnnu[bundle-list(1) -- List all the gems in the bundle ========================================================================= ## SYNOPSIS `bundle list` [--name-only] [--paths] [--without-group=GROUP[ GROUP...]] [--only-group=GROUP[ GROUP...]] ## DESCRIPTION Prints a list of all the gems in the bundle including their version. Example: bundle list --name-only bundle list --paths bundle list --without-group test bundle list --only-group dev bundle list --only-group dev test --paths ## OPTIONS * `--name-only`: Print only the name of each gem. * `--paths`: Print the path to each gem in the bundle. * `--without-group=`: A space-separated list of groups of gems to skip during printing. * `--only-group=`: A space-separated list of groups of gems to print. PKu]#s5bundler-2.2.24/lib/bundler/man/bundle-pristine.1.ronnnu[bundle-pristine(1) -- Restores installed gems to their pristine condition =========================================================================== ## SYNOPSIS `bundle pristine` ## DESCRIPTION `pristine` restores the installed gems in the bundle to their pristine condition using the local gem cache from RubyGems. For git gems, a forced checkout will be performed. For further explanation, `bundle pristine` ignores unpacked files on disk. In other words, this command utilizes the local `.gem` cache or the gem's git repository as if one were installing from scratch. Note: the Bundler gem cannot be restored to its original state with `pristine`. One also cannot use `bundle pristine` on gems with a 'path' option in the Gemfile, because bundler has no original copy it can restore from. When is it practical to use `bundle pristine`? It comes in handy when a developer is debugging a gem. `bundle pristine` is a great way to get rid of experimental changes to a gem that one may not want. Why use `bundle pristine` over `gem pristine --all`? Both commands are very similar. For context: `bundle pristine`, without arguments, cleans all gems from the lockfile. Meanwhile, `gem pristine --all` cleans all installed gems for that Ruby version. If a developer forgets which gems in their project they might have been debugging, the Rubygems `gem pristine [GEMNAME]` command may be inconvenient. One can avoid waiting for `gem pristine --all`, and instead run `bundle pristine`. PKu]C..0bundler-2.2.24/lib/bundler/man/bundle-gem.1.ronnnu[bundle-gem(1) -- Generate a project skeleton for creating a rubygem ==================================================================== ## SYNOPSIS `bundle gem` [OPTIONS] ## DESCRIPTION Generates a directory named `GEM_NAME` with a `Rakefile`, `GEM_NAME.gemspec`, and other supporting files and directories that can be used to develop a rubygem with that name. Run `rake -T` in the resulting project for a list of Rake tasks that can be used to test and publish the gem to rubygems.org. The generated project skeleton can be customized with OPTIONS, as explained below. Note that these options can also be specified via Bundler's global configuration file using the following names: * `gem.coc` * `gem.mit` * `gem.test` ## OPTIONS * `--exe` or `-b` or `--bin`: Specify that Bundler should create a binary executable (as `exe/GEM_NAME`) in the generated rubygem project. This binary will also be added to the `GEM_NAME.gemspec` manifest. This behavior is disabled by default. * `--no-exe`: Do not create a binary (overrides `--exe` specified in the global config). * `--coc`: Add a `CODE_OF_CONDUCT.md` file to the root of the generated project. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future `bundle gem` use. * `--no-coc`: Do not create a `CODE_OF_CONDUCT.md` (overrides `--coc` specified in the global config). * `--ext`: Add boilerplate for C extension code to the generated project. This behavior is disabled by default. * `--no-ext`: Do not add C extension code (overrides `--ext` specified in the global config). * `--mit`: Add an MIT license to a `LICENSE.txt` file in the root of the generated project. Your name from the global git config is used for the copyright statement. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future `bundle gem` use. * `--no-mit`: Do not create a `LICENSE.txt` (overrides `--mit` specified in the global config). * `-t`, `--test=minitest`, `--test=rspec`, `--test=test-unit`: Specify the test framework that Bundler should use when generating the project. Acceptable values are `minitest`, `rspec` and `test-unit`. The `GEM_NAME.gemspec` will be configured and a skeleton test/spec directory will be created based on this option. Given no option is specified: When Bundler is configured to generate tests, this defaults to Bundler's global config setting `gem.test`. When Bundler is configured to not generate tests, an interactive prompt will be displayed and the answer will be used for the current rubygem project. When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future `bundle gem` use. * `--ci`, `--ci=github`, `--ci=travis`, `--ci=gitlab`, `--ci=circle`: Specify the continuous integration service that Bundler should use when generating the project. Acceptable values are `github`, `travis`, `gitlab` and `circle`. A configuration file will be generated in the project directory. Given no option is specified: When Bundler is configured to generate CI files, this defaults to Bundler's global config setting `gem.ci`. When Bundler is configured to not generate CI files, an interactive prompt will be displayed and the answer will be used for the current rubygem project. When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future `bundle gem` use. * `-e`, `--edit[=EDITOR]`: Open the resulting GEM_NAME.gemspec in EDITOR, or the default editor if not specified. The default is `$BUNDLER_EDITOR`, `$VISUAL`, or `$EDITOR`. ## SEE ALSO * [bundle config(1)](bundle-config.1.html) PKu]^-+bundler-2.2.24/lib/bundler/man/bundle-gem.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-GEM" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem . .SH "SYNOPSIS" \fBbundle gem\fR \fIGEM_NAME\fR \fIOPTIONS\fR . .SH "DESCRIPTION" Generates a directory named \fBGEM_NAME\fR with a \fBRakefile\fR, \fBGEM_NAME\.gemspec\fR, and other supporting files and directories that can be used to develop a rubygem with that name\. . .P Run \fBrake \-T\fR in the resulting project for a list of Rake tasks that can be used to test and publish the gem to rubygems\.org\. . .P The generated project skeleton can be customized with OPTIONS, as explained below\. Note that these options can also be specified via Bundler\'s global configuration file using the following names: . .IP "\(bu" 4 \fBgem\.coc\fR . .IP "\(bu" 4 \fBgem\.mit\fR . .IP "\(bu" 4 \fBgem\.test\fR . .IP "" 0 . .SH "OPTIONS" . .TP \fB\-\-exe\fR or \fB\-b\fR or \fB\-\-bin\fR Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\. . .TP \fB\-\-no\-exe\fR Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\. . .TP \fB\-\-coc\fR Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . .TP \fB\-\-no\-coc\fR Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\. . .TP \fB\-\-ext\fR Add boilerplate for C extension code to the generated project\. This behavior is disabled by default\. . .TP \fB\-\-no\-ext\fR Do not add C extension code (overrides \fB\-\-ext\fR specified in the global config)\. . .TP \fB\-\-mit\fR Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . .TP \fB\-\-no\-mit\fR Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\. . .TP \fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified: . .IP When Bundler is configured to generate tests, this defaults to Bundler\'s global config setting \fBgem\.test\fR\. . .IP When Bundler is configured to not generate tests, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. . .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . .TP \fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=travis\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBtravis\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified: . .IP When Bundler is configured to generate CI files, this defaults to Bundler\'s global config setting \fBgem\.ci\fR\. . .IP When Bundler is configured to not generate CI files, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. . .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . .TP \fB\-e\fR, \fB\-\-edit[=EDITOR]\fR Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\. . .SH "SEE ALSO" . .IP "\(bu" 4 bundle config(1) \fIbundle\-config\.1\.html\fR . .IP "" 0 PKu]51bundler-2.2.24/lib/bundler/man/bundle-open.1.ronnnu[bundle-open(1) -- Opens the source directory for a gem in your bundle ===================================================================== ## SYNOPSIS `bundle open` [GEM] ## DESCRIPTION Opens the source directory of the provided GEM in your editor. For this to work the `EDITOR` or `BUNDLER_EDITOR` environment variable has to be set. Example: bundle open 'rack' Will open the source directory for the 'rack' gem in your bundle. PKu]P~||1bundler-2.2.24/lib/bundler/man/bundle-exec.1.ronnnu[bundle-exec(1) -- Execute a command in the context of the bundle ================================================================ ## SYNOPSIS `bundle exec` [--keep-file-descriptors] ## DESCRIPTION This command executes the command, making all gems specified in the [`Gemfile(5)`][Gemfile(5)] available to `require` in Ruby programs. Essentially, if you would normally have run something like `rspec spec/my_spec.rb`, and you want to use the gems specified in the [`Gemfile(5)`][Gemfile(5)] and installed via [bundle install(1)](bundle-install.1.html), you should run `bundle exec rspec spec/my_spec.rb`. Note that `bundle exec` does not require that an executable is available on your shell's `$PATH`. ## OPTIONS * `--keep-file-descriptors`: Exec in Ruby 2.0 began discarding non-standard file descriptors. When this flag is passed, exec will revert to the 1.9 behaviour of passing all file descriptors to the new process. ## BUNDLE INSTALL --BINSTUBS If you use the `--binstubs` flag in [bundle install(1)](bundle-install.1.html), Bundler will automatically create a directory (which defaults to `app_root/bin`) containing all of the executables available from gems in the bundle. After using `--binstubs`, `bin/rspec spec/my_spec.rb` is identical to `bundle exec rspec spec/my_spec.rb`. ## ENVIRONMENT MODIFICATIONS `bundle exec` makes a number of changes to the shell environment, then executes the command you specify in full. * make sure that it's still possible to shell out to `bundle` from inside a command invoked by `bundle exec` (using `$BUNDLE_BIN_PATH`) * put the directory containing executables (like `rails`, `rspec`, `rackup`) for your bundle on `$PATH` * make sure that if bundler is invoked in the subshell, it uses the same `Gemfile` (by setting `BUNDLE_GEMFILE`) * add `-rbundler/setup` to `$RUBYOPT`, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle It also modifies Rubygems: * disallow loading additional gems not in the bundle * modify the `gem` method to be a no-op if a gem matching the requirements is in the bundle, and to raise a `Gem::LoadError` if it's not * Define `Gem.refresh` to be a no-op, since the source index is always frozen when using bundler, and to prevent gems from the system leaking into the environment * Override `Gem.bin_path` to use the gems in the bundle, making system executables work * Add all gems in the bundle into Gem.loaded_specs Finally, `bundle exec` also implicitly modifies `Gemfile.lock` if the lockfile and the Gemfile do not match. Bundler needs the Gemfile to determine things such as a gem's groups, `autorequire`, and platforms, etc., and that information isn't stored in the lockfile. The Gemfile and lockfile must be synced in order to `bundle exec` successfully, so `bundle exec` updates the lockfile beforehand. ### Loading By default, when attempting to `bundle exec` to a file with a ruby shebang, Bundler will `Kernel.load` that file instead of using `Kernel.exec`. For the vast majority of cases, this is a performance improvement. In a rare few cases, this could cause some subtle side-effects (such as dependence on the exact contents of `$0` or `__FILE__`) and the optimization can be disabled by enabling the `disable_exec_load` setting. ### Shelling out Any Ruby code that opens a subshell (like `system`, backticks, or `%x{}`) will automatically use the current Bundler environment. If you need to shell out to a Ruby command that is not part of your current bundle, use the `with_clean_env` method with a block. Any subshells created inside the block will be given the environment present before Bundler was activated. For example, Homebrew commands run Ruby, but don't work inside a bundle: Bundler.with_clean_env do `brew install wget` end Using `with_clean_env` is also necessary if you are shelling out to a different bundle. Any Bundler commands run in a subshell will inherit the current Gemfile, so commands that need to run in the context of a different bundle also need to use `with_clean_env`. Bundler.with_clean_env do Dir.chdir "/other/bundler/project" do `bundle exec ./script` end end Bundler provides convenience helpers that wrap `system` and `exec`, and they can be used like this: Bundler.clean_system('brew install wget') Bundler.clean_exec('brew install wget') ## RUBYGEMS PLUGINS At present, the Rubygems plugin system requires all files named `rubygems_plugin.rb` on the load path of _any_ installed gem when any Ruby code requires `rubygems.rb`. This includes executables installed into the system, like `rails`, `rackup`, and `rspec`. Since Rubygems plugins can contain arbitrary Ruby code, they commonly end up activating themselves or their dependencies. For instance, the `gemcutter 0.5` gem depended on `json_pure`. If you had that version of gemcutter installed (even if you _also_ had a newer version without this problem), Rubygems would activate `gemcutter 0.5` and `json_pure `. If your Gemfile(5) also contained `json_pure` (or a gem with a dependency on `json_pure`), the latest version on your system might conflict with the version in your Gemfile(5), or the snapshot version in your `Gemfile.lock`. If this happens, bundler will say: You have already activated json_pure 1.4.6 but your Gemfile requires json_pure 1.4.3. Consider using bundle exec. In this situation, you almost certainly want to remove the underlying gem with the problematic gem plugin. In general, the authors of these plugins (in this case, the `gemcutter` gem) have released newer versions that are more careful in their plugins. You can find a list of all the gems containing gem plugins by running ruby -rrubygems -e "puts Gem.find_files('rubygems_plugin.rb')" At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren't using (`gem uninstall gem_name`). PKu]w,w113bundler-2.2.24/lib/bundler/man/bundle-update.1.ronnnu[bundle-update(1) -- Update your gems to the latest available versions ===================================================================== ## SYNOPSIS `bundle update` <*gems> [--all] [--group=NAME] [--source=NAME] [--local] [--ruby] [--bundler[=VERSION]] [--full-index] [--jobs=JOBS] [--quiet] [--patch|--minor|--major] [--redownload] [--strict] [--conservative] ## DESCRIPTION Update the gems specified (all gems, if `--all` flag is used), ignoring the previously installed gems specified in the `Gemfile.lock`. In general, you should use [bundle install(1)](bundle-install.1.html) to install the same exact gems and versions across machines. You would use `bundle update` to explicitly update the version of a gem. ## OPTIONS * `--all`: Update all gems specified in Gemfile. * `--group=`, `-g=[]`: Only update the gems in the specified group. For instance, you can update all gems in the development group with `bundle update --group development`. You can also call `bundle update rails --group test` to update the rails gem and all gems in the test group, for example. * `--source=`: The name of a `:git` or `:path` source used in the Gemfile(5). For instance, with a `:git` source of `http://github.com/rails/rails.git`, you would call `bundle update --source rails` * `--local`: Do not attempt to fetch gems remotely and use the gem cache instead. * `--ruby`: Update the locked version of Ruby to the current version of Ruby. * `--bundler`: Update the locked version of bundler to the invoked bundler version. * `--full-index`: Fall back to using the single-file index of all gems. * `--jobs=[]`, `-j[]`: Specify the number of jobs to run in parallel. The default is `1`. * `--retry=[]`: Retry failed network or git requests for times. * `--quiet`: Only output warnings and errors. * `--redownload`: Force downloading every gem. * `--patch`: Prefer updating only to next patch version. * `--minor`: Prefer updating only to next minor version. * `--major`: Prefer updating to next major version (default). * `--strict`: Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. * `--conservative`: Use bundle install conservative update behavior and do not allow indirect dependencies to be updated. ## UPDATING ALL GEMS If you run `bundle update --all`, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources. Consider the following Gemfile(5): source "https://rubygems.org" gem "rails", "3.0.0.rc" gem "nokogiri" When you run [bundle install(1)](bundle-install.1.html) the first time, bundler will resolve all of the dependencies, all the way down, and install what you need: Fetching gem metadata from https://rubygems.org/......... Resolving dependencies... Installing builder 2.1.2 Installing abstract 1.0.0 Installing rack 1.2.8 Using bundler 1.7.6 Installing rake 10.4.0 Installing polyglot 0.3.5 Installing mime-types 1.25.1 Installing i18n 0.4.2 Installing mini_portile 0.6.1 Installing tzinfo 0.3.42 Installing rack-mount 0.6.14 Installing rack-test 0.5.7 Installing treetop 1.4.15 Installing thor 0.14.6 Installing activesupport 3.0.0.rc Installing erubis 2.6.6 Installing activemodel 3.0.0.rc Installing arel 0.4.0 Installing mail 2.2.20 Installing activeresource 3.0.0.rc Installing actionpack 3.0.0.rc Installing activerecord 3.0.0.rc Installing actionmailer 3.0.0.rc Installing railties 3.0.0.rc Installing rails 3.0.0.rc Installing nokogiri 1.6.5 Bundle complete! 2 Gemfile dependencies, 26 gems total. Use `bundle show [gemname]` to see where a bundled gem is installed. As you can see, even though you have two gems in the Gemfile(5), your application needs 26 different gems in order to run. Bundler remembers the exact versions it installed in `Gemfile.lock`. The next time you run [bundle install(1)](bundle-install.1.html), bundler skips the dependency resolution and installs the same gems as it installed last time. After checking in the `Gemfile.lock` into version control and cloning it on another machine, running [bundle install(1)](bundle-install.1.html) will _still_ install the gems that you installed last time. You don't need to worry that a new release of `erubis` or `mail` changes the gems you use. However, from time to time, you might want to update the gems you are using to the newest versions that still match the gems in your Gemfile(5). To do this, run `bundle update --all`, which will ignore the `Gemfile.lock`, and resolve all the dependencies again. Keep in mind that this process can result in a significantly different set of the 25 gems, based on the requirements of new gems that the gem authors released since the last time you ran `bundle update --all`. ## UPDATING A LIST OF GEMS Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the `Gemfile.lock`. For instance, in the scenario above, imagine that `nokogiri` releases version `1.4.4`, and you want to update it _without_ updating Rails and all of its dependencies. To do this, run `bundle update nokogiri`. Bundler will update `nokogiri` and any of its dependencies, but leave alone Rails and its dependencies. ## OVERLAPPING DEPENDENCIES Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same second-level dependency. For instance, consider the case of `thin` and `rack-perftools-profiler`. source "https://rubygems.org" gem "thin" gem "rack-perftools-profiler" The `thin` gem depends on `rack >= 1.0`, while `rack-perftools-profiler` depends on `rack ~> 1.0`. If you run bundle install, you get: Fetching source index for https://rubygems.org/ Installing daemons (1.1.0) Installing eventmachine (0.12.10) with native extensions Installing open4 (1.0.1) Installing perftools.rb (0.4.7) with native extensions Installing rack (1.2.1) Installing rack-perftools_profiler (0.0.2) Installing thin (1.2.7) with native extensions Using bundler (1.0.0.rc.3) In this case, the two gems have their own set of dependencies, but they share `rack` in common. If you run `bundle update thin`, bundler will update `daemons`, `eventmachine` and `rack`, which are dependencies of `thin`, but not `open4` or `perftools.rb`, which are dependencies of `rack-perftools_profiler`. Note that `bundle update thin` will update `rack` even though it's _also_ a dependency of `rack-perftools_profiler`. In short, by default, when you update a gem using `bundle update`, bundler will update all dependencies of that gem, including those that are also dependencies of another gem. To prevent updating indirect dependencies, prior to version 1.14 the only option was the `CONSERVATIVE UPDATING` behavior in [bundle install(1)](bundle-install.1.html): In this scenario, updating the `thin` version manually in the Gemfile(5), and then running [bundle install(1)](bundle-install.1.html) will only update `daemons` and `eventmachine`, but not `rack`. For more information, see the `CONSERVATIVE UPDATING` section of [bundle install(1)](bundle-install.1.html). Starting with 1.14, specifying the `--conservative` option will also prevent indirect dependencies from being updated. ## PATCH LEVEL OPTIONS Version 1.14 introduced 4 patch-level options that will influence how gem versions are resolved. One of the following options can be used: `--patch`, `--minor` or `--major`. `--strict` can be added to further influence resolution. * `--patch`: Prefer updating only to next patch version. * `--minor`: Prefer updating only to next minor version. * `--major`: Prefer updating to next major version (default). * `--strict`: Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don't satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order. Providing one of the patch level options (e.g. `--patch`) changes the sort order of the satisfying versions, causing Bundler to consider the latest `--patch` or `--minor` version available before other versions. Note that versions outside the stated patch level could still be resolved to if necessary to find a suitable dependency graph. For example, if gem 'foo' is locked at 1.0.2, with no gem requirement defined in the Gemfile, and versions 1.0.3, 1.0.4, 1.1.0, 1.1.1, 2.0.0 all exist, the default order of preference by default (`--major`) will be "2.0.0, 1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". If the `--patch` option is used, the order of preference will change to "1.0.4, 1.0.3, 1.0.2, 1.1.1, 1.1.0, 2.0.0". If the `--minor` option is used, the order of preference will change to "1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2, 2.0.0". Combining the `--strict` option with any of the patch level options will remove any versions beyond the scope of the patch level option, to ensure that no gem is updated that far. To continue the previous example, if both `--patch` and `--strict` options are used, the available versions for resolution would be "1.0.4, 1.0.3, 1.0.2". If `--minor` and `--strict` are used, it would be "1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available. If the gem requirement for `foo` in the Gemfile is '~> 1.0', that will accomplish the same thing as providing the `--minor` and `--strict` options. ## PATCH LEVEL EXAMPLES Given the following gem specifications: foo 1.4.3, requires: ~> bar 2.0 foo 1.4.4, requires: ~> bar 2.0 foo 1.4.5, requires: ~> bar 2.1 foo 1.5.0, requires: ~> bar 2.1 foo 1.5.1, requires: ~> bar 3.0 bar with versions 2.0.3, 2.0.4, 2.1.0, 2.1.1, 3.0.0 Gemfile: gem 'foo' Gemfile.lock: foo (1.4.3) bar (~> 2.0) bar (2.0.3) Cases: # Command Line Result ------------------------------------------------------------ 1 bundle update --patch 'foo 1.4.5', 'bar 2.1.1' 2 bundle update --patch foo 'foo 1.4.5', 'bar 2.1.1' 3 bundle update --minor 'foo 1.5.1', 'bar 3.0.0' 4 bundle update --minor --strict 'foo 1.5.0', 'bar 2.1.1' 5 bundle update --patch --strict 'foo 1.4.4', 'bar 2.0.4' In case 1, bar is upgraded to 2.1.1, a minor version increase, because the dependency from foo 1.4.5 required it. In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it's not a declared dependency in the Gemfile. In case 3, bar goes up a whole major release, because a minor increase is preferred now for foo, and when it goes to 1.5.1, it requires 3.0.0 of bar. In case 4, foo is preferred up to a minor version, but 1.5.1 won't work because the --strict flag removes bar 3.0.0 from consideration since it's a major increment. In case 5, both foo and bar have any minor or major increments removed from consideration because of the --strict flag, so the most they can move is up to 1.4.4 and 2.0.4. ## RECOMMENDED WORKFLOW In general, when working with an application managed with bundler, you should use the following workflow: * After you create your Gemfile(5) for the first time, run $ bundle install * Check the resulting `Gemfile.lock` into version control $ git add Gemfile.lock * When checking out this repository on another development machine, run $ bundle install * When checking out this repository on a deployment machine, run $ bundle install --deployment * After changing the Gemfile(5) to reflect a new or update dependency, run $ bundle install * Make sure to check the updated `Gemfile.lock` into version control $ git add Gemfile.lock * If [bundle install(1)](bundle-install.1.html) reports a conflict, manually update the specific gems that you changed in the Gemfile(5) $ bundle update rails thin * If you want to update all the gems to the latest possible versions that still match the gems listed in the Gemfile(5), run $ bundle update --all PKu]|=.bundler-2.2.24/lib/bundler/man/bundle-inject.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-INJECT" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile . .SH "SYNOPSIS" \fBbundle inject\fR [GEM] [VERSION] . .SH "DESCRIPTION" Adds the named gem(s) with their version requirements to the resolved [\fBGemfile(5)\fR][Gemfile(5)]\. . .P This command will add the gem to both your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock if it isn\'t listed yet\. . .P Example: . .IP "" 4 . .nf bundle install bundle inject \'rack\' \'> 0\' . .fi . .IP "" 0 . .P This will inject the \'rack\' gem with a version greater than 0 in your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock PKu],,bundler-2.2.24/lib/bundler/man/bundle-list.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-LIST" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle . .SH "SYNOPSIS" \fBbundle list\fR [\-\-name\-only] [\-\-paths] [\-\-without\-group=GROUP[ GROUP\.\.\.]] [\-\-only\-group=GROUP[ GROUP\.\.\.]] . .SH "DESCRIPTION" Prints a list of all the gems in the bundle including their version\. . .P Example: . .P bundle list \-\-name\-only . .P bundle list \-\-paths . .P bundle list \-\-without\-group test . .P bundle list \-\-only\-group dev . .P bundle list \-\-only\-group dev test \-\-paths . .SH "OPTIONS" . .TP \fB\-\-name\-only\fR Print only the name of each gem\. . .TP \fB\-\-paths\fR Print the path to each gem in the bundle\. . .TP \fB\-\-without\-group=\fR A space\-separated list of groups of gems to skip during printing\. . .TP \fB\-\-only\-group=\fR A space\-separated list of groups of gems to print\. PKu]8EDFDF/bundler-2.2.24/lib/bundler/man/bundle-install.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-INSTALL" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile . .SH "SYNOPSIS" \fBbundle install\fR [\-\-binstubs[=DIRECTORY]] [\-\-clean] [\-\-deployment] [\-\-frozen] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-no\-cache] [\-\-no\-prune] [\-\-path PATH] [\-\-quiet] [\-\-redownload] [\-\-retry=NUMBER] [\-\-shebang] [\-\-standalone[=GROUP[ GROUP\.\.\.]]] [\-\-system] [\-\-trust\-policy=POLICY] [\-\-with=GROUP[ GROUP\.\.\.]] [\-\-without=GROUP[ GROUP\.\.\.]] . .SH "DESCRIPTION" Install the gems specified in your Gemfile(5)\. If this is the first time you run bundle install (and a \fBGemfile\.lock\fR does not exist), Bundler will fetch all remote sources, resolve dependencies and install all needed gems\. . .P If a \fBGemfile\.lock\fR does exist, and you have not updated your Gemfile(5), Bundler will fetch all remote sources, but use the dependencies specified in the \fBGemfile\.lock\fR instead of resolving dependencies\. . .P If a \fBGemfile\.lock\fR does exist, and you have updated your Gemfile(5), Bundler will use the dependencies in the \fBGemfile\.lock\fR for all gems that you did not update, but will re\-resolve the dependencies of gems that you did update\. You can find more information about this update process below under \fICONSERVATIVE UPDATING\fR\. . .SH "OPTIONS" The \fB\-\-clean\fR, \fB\-\-deployment\fR, \fB\-\-frozen\fR, \fB\-\-no\-prune\fR, \fB\-\-path\fR, \fB\-\-shebang\fR, \fB\-\-system\fR, \fB\-\-without\fR and \fB\-\-with\fR options are deprecated because they only make sense if they are applied to every subsequent \fBbundle install\fR run automatically and that requires \fBbundler\fR to silently remember them\. Since \fBbundler\fR will no longer remember CLI flags in future versions, \fBbundle config\fR (see bundle\-config(1)) should be used to apply them permanently\. . .TP \fB\-\-binstubs[=]\fR Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it in \fBbin/\fR\. This lets you link the binstub inside of an application to the exact gem version the application needs\. . .IP Creates a directory (defaults to \fB~/bin\fR) and places any executables from the gem there\. These executables run in Bundler\'s context\. If used, you might add this directory to your environment\'s \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\. . .TP \fB\-\-clean\fR On finishing the installation Bundler is going to remove any gems not present in the current Gemfile(5)\. Don\'t worry, gems currently in use will not be removed\. . .IP This option is deprecated in favor of the \fBclean\fR setting\. . .TP \fB\-\-deployment\fR In \fIdeployment mode\fR, Bundler will \'roll\-out\' the bundle for production or CI use\. Please check carefully if you want to have this option enabled in your development environment\. . .IP This option is deprecated in favor of the \fBdeployment\fR setting\. . .TP \fB\-\-redownload\fR Force download every gem, even if the required versions are already available locally\. . .TP \fB\-\-frozen\fR Do not allow the Gemfile\.lock to be updated after this install\. Exits non\-zero if there are going to be changes to the Gemfile\.lock\. . .IP This option is deprecated in favor of the \fBfrozen\fR setting\. . .TP \fB\-\-full\-index\fR Bundler will not call Rubygems\' API endpoint (default) but download and cache a (currently big) index file of all gems\. Performance can be improved for large bundles that seldom change by enabling this option\. . .TP \fB\-\-gemfile=\fR The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project\'s root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\. . .TP \fB\-\-jobs=[]\fR, \fB\-j[]\fR The maximum number of parallel download and install jobs\. The default is \fB1\fR\. . .TP \fB\-\-local\fR Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. . .TP \fB\-\-no\-cache\fR Do not update the cache in \fBvendor/cache\fR with the newly bundled gems\. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install\. . .TP \fB\-\-no\-prune\fR Don\'t remove stale gems from the cache when the installation finishes\. . .IP This option is deprecated in favor of the \fBno_prune\fR setting\. . .TP \fB\-\-path=\fR The location to install the specified gems to\. This defaults to Rubygems\' setting\. Bundler shares this location with Rubygems, \fBgem install \.\.\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \.\.\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\. . .IP This option is deprecated in favor of the \fBpath\fR setting\. . .TP \fB\-\-quiet\fR Do not print progress information to the standard output\. Instead, Bundler will exit using a status code (\fB$?\fR)\. . .TP \fB\-\-retry=[]\fR Retry failed network or git requests for \fInumber\fR times\. . .TP \fB\-\-shebang=\fR Uses the specified ruby executable (usually \fBruby\fR) to execute the scripts created with \fB\-\-binstubs\fR\. In addition, if you use \fB\-\-binstubs\fR together with \fB\-\-shebang jruby\fR these executables will be changed to execute \fBjruby\fR instead\. . .IP This option is deprecated in favor of the \fBshebang\fR setting\. . .TP \fB\-\-standalone[=]\fR Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install has to be specified\. Bundler creates a directory named \fBbundle\fR and installs the bundle there\. It also generates a \fBbundle/bundler/setup\.rb\fR file to replace Bundler\'s own setup in the manner required\. Using this option implicitly sets \fBpath\fR, which is a [remembered option][REMEMBERED OPTIONS]\. . .TP \fB\-\-system\fR Installs the gems specified in the bundle to the system\'s Rubygems location\. This overrides any previous configuration of \fB\-\-path\fR\. . .IP This option is deprecated in favor of the \fBsystem\fR setting\. . .TP \fB\-\-trust\-policy=[]\fR Apply the Rubygems security policy \fIpolicy\fR, where policy is one of \fBHighSecurity\fR, \fBMediumSecurity\fR, \fBLowSecurity\fR, \fBAlmostNoSecurity\fR, or \fBNoSecurity\fR\. For more details, please see the Rubygems signing documentation linked below in \fISEE ALSO\fR\. . .TP \fB\-\-with=\fR A space\-separated list of groups referencing gems to install\. If an optional group is given it is installed\. If a group is given that is in the remembered list of groups given to \-\-without, it is removed from that list\. . .IP This option is deprecated in favor of the \fBwith\fR setting\. . .TP \fB\-\-without=\fR A space\-separated list of groups referencing gems to skip during installation\. If a group is given that is in the remembered list of groups given to \-\-with, it is removed from that list\. . .IP This option is deprecated in favor of the \fBwithout\fR setting\. . .SH "DEPLOYMENT MODE" Bundler\'s defaults are optimized for development\. To switch to defaults optimized for deployment and for CI, use the \fB\-\-deployment\fR flag\. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified\. . .IP "1." 4 A \fBGemfile\.lock\fR is required\. . .IP To ensure that the same versions of the gems you developed with and tested with are also used in deployments, a \fBGemfile\.lock\fR is required\. . .IP This is mainly to ensure that you remember to check your \fBGemfile\.lock\fR into version control\. . .IP "2." 4 The \fBGemfile\.lock\fR must be up to date . .IP In development, you can modify your Gemfile(5) and re\-run \fBbundle install\fR to \fIconservatively update\fR your \fBGemfile\.lock\fR snapshot\. . .IP In deployment, your \fBGemfile\.lock\fR should be up\-to\-date with changes made in your Gemfile(5)\. . .IP "3." 4 Gems are installed to \fBvendor/bundle\fR not your default system location . .IP In development, it\'s convenient to share the gems used in your application with other applications and other scripts that run on the system\. . .IP In deployment, isolation is a more important default\. In addition, the user deploying the application may not have permission to install gems to the system, or the web server may not have permission to read them\. . .IP As a result, \fBbundle install \-\-deployment\fR installs gems to the \fBvendor/bundle\fR directory in the application\. This may be overridden using the \fB\-\-path\fR option\. . .IP "" 0 . .SH "SUDO USAGE" By default, Bundler installs gems to the same location as \fBgem install\fR\. . .P In some cases, that location may not be writable by your Unix user\. In that case, Bundler will stage everything in a temporary directory, then ask you for your \fBsudo\fR password in order to copy the gems into their system location\. . .P From your perspective, this is identical to installing the gems directly into the system\. . .P You should never use \fBsudo bundle install\fR\. This is because several other steps in \fBbundle install\fR must be performed as the current user: . .IP "\(bu" 4 Updating your \fBGemfile\.lock\fR . .IP "\(bu" 4 Updating your \fBvendor/cache\fR, if necessary . .IP "\(bu" 4 Checking out private git repositories using your user\'s SSH keys . .IP "" 0 . .P Of these three, the first two could theoretically be performed by \fBchown\fRing the resulting files to \fB$SUDO_USER\fR\. The third, however, can only be performed by invoking the \fBgit\fR command as the current user\. Therefore, git gems are downloaded and installed into \fB~/\.bundle\fR rather than $GEM_HOME or $BUNDLE_PATH\. . .P As a result, you should run \fBbundle install\fR as the current user, and Bundler will ask for your password if it is needed to put the gems into their final location\. . .SH "INSTALLING GROUPS" By default, \fBbundle install\fR will install all gems in all groups in your Gemfile(5), except those declared for a different platform\. . .P However, you can explicitly tell Bundler to skip installing certain groups with the \fB\-\-without\fR option\. This option takes a space\-separated list of groups\. . .P While the \fB\-\-without\fR option will skip \fIinstalling\fR the gems in the specified groups, it will still \fIdownload\fR those gems and use them to resolve the dependencies of every gem in your Gemfile(5)\. . .P This is so that installing a different set of groups on another machine (such as a production server) will not change the gems and versions that you have already developed and tested against\. . .P \fBBundler offers a rock\-solid guarantee that the third\-party code you are running in development and testing is also the third\-party code you are running in production\. You can choose to exclude some of that code in different environments, but you will never be caught flat\-footed by different versions of third\-party code being used in different environments\.\fR . .P For a simple illustration, consider the following Gemfile(5): . .IP "" 4 . .nf source \'https://rubygems\.org\' gem \'sinatra\' group :production do gem \'rack\-perftools\-profiler\' end . .fi . .IP "" 0 . .P In this case, \fBsinatra\fR depends on any version of Rack (\fB>= 1\.0\fR), while \fBrack\-perftools\-profiler\fR depends on 1\.x (\fB~> 1\.0\fR)\. . .P When you run \fBbundle install \-\-without production\fR in development, we look at the dependencies of \fBrack\-perftools\-profiler\fR as well\. That way, you do not spend all your time developing against Rack 2\.0, using new APIs unavailable in Rack 1\.x, only to have Bundler switch to Rack 1\.2 when the \fBproduction\fR group \fIis\fR used\. . .P This should not cause any problems in practice, because we do not attempt to \fBinstall\fR the gems in the excluded groups, and only evaluate as part of the dependency resolution process\. . .P This also means that you cannot include different versions of the same gem in different groups, because doing so would result in different sets of dependencies used in development and production\. Because of the vagaries of the dependency resolution process, this usually affects more than the gems you list in your Gemfile(5), and can (surprisingly) radically change the gems you are using\. . .SH "THE GEMFILE\.LOCK" When you run \fBbundle install\fR, Bundler will persist the full names and versions of all gems that you used (including dependencies of the gems specified in the Gemfile(5)) into a file called \fBGemfile\.lock\fR\. . .P Bundler uses this file in all subsequent calls to \fBbundle install\fR, which guarantees that you always use the same exact code, even as your application moves across machines\. . .P Because of the way dependency resolution works, even a seemingly small change (for instance, an update to a point\-release of a dependency of a gem in your Gemfile(5)) can result in radically different gems being needed to satisfy all dependencies\. . .P As a result, you \fBSHOULD\fR check your \fBGemfile\.lock\fR into version control, in both applications and gems\. If you do not, every machine that checks out your repository (including your production server) will resolve all dependencies again, which will result in different versions of third\-party code being used if \fBany\fR of the gems in the Gemfile(5) or any of their dependencies have been updated\. . .P When Bundler first shipped, the \fBGemfile\.lock\fR was included in the \fB\.gitignore\fR file included with generated gems\. Over time, however, it became clear that this practice forces the pain of broken dependencies onto new contributors, while leaving existing contributors potentially unaware of the problem\. Since \fBbundle install\fR is usually the first step towards a contribution, the pain of broken dependencies would discourage new contributors from contributing\. As a result, we have revised our guidance for gem authors to now recommend checking in the lock for gems\. . .SH "CONSERVATIVE UPDATING" When you make a change to the Gemfile(5) and then run \fBbundle install\fR, Bundler will update only the gems that you modified\. . .P In other words, if a gem that you \fBdid not modify\fR worked before you called \fBbundle install\fR, it will continue to use the exact same versions of all dependencies as it used before the update\. . .P Let\'s take a look at an example\. Here\'s your original Gemfile(5): . .IP "" 4 . .nf source \'https://rubygems\.org\' gem \'actionpack\', \'2\.3\.8\' gem \'activemerchant\' . .fi . .IP "" 0 . .P In this case, both \fBactionpack\fR and \fBactivemerchant\fR depend on \fBactivesupport\fR\. The \fBactionpack\fR gem depends on \fBactivesupport 2\.3\.8\fR and \fBrack ~> 1\.1\.0\fR, while the \fBactivemerchant\fR gem depends on \fBactivesupport >= 2\.3\.2\fR, \fBbraintree >= 2\.0\.0\fR, and \fBbuilder >= 2\.0\.0\fR\. . .P When the dependencies are first resolved, Bundler will select \fBactivesupport 2\.3\.8\fR, which satisfies the requirements of both gems in your Gemfile(5)\. . .P Next, you modify your Gemfile(5) to: . .IP "" 4 . .nf source \'https://rubygems\.org\' gem \'actionpack\', \'3\.0\.0\.rc\' gem \'activemerchant\' . .fi . .IP "" 0 . .P The \fBactionpack 3\.0\.0\.rc\fR gem has a number of new dependencies, and updates the \fBactivesupport\fR dependency to \fB= 3\.0\.0\.rc\fR and the \fBrack\fR dependency to \fB~> 1\.2\.1\fR\. . .P When you run \fBbundle install\fR, Bundler notices that you changed the \fBactionpack\fR gem, but not the \fBactivemerchant\fR gem\. It evaluates the gems currently being used to satisfy its requirements: . .TP \fBactivesupport 2\.3\.8\fR also used to satisfy a dependency in \fBactivemerchant\fR, which is not being updated . .TP \fBrack ~> 1\.1\.0\fR not currently being used to satisfy another dependency . .P Because you did not explicitly ask to update \fBactivemerchant\fR, you would not expect it to suddenly stop working after updating \fBactionpack\fR\. However, satisfying the new \fBactivesupport 3\.0\.0\.rc\fR dependency of actionpack requires updating one of its dependencies\. . .P Even though \fBactivemerchant\fR declares a very loose dependency that theoretically matches \fBactivesupport 3\.0\.0\.rc\fR, Bundler treats gems in your Gemfile(5) that have not changed as an atomic unit together with their dependencies\. In this case, the \fBactivemerchant\fR dependency is treated as \fBactivemerchant 1\.7\.1 + activesupport 2\.3\.8\fR, so \fBbundle install\fR will report that it cannot update \fBactionpack\fR\. . .P To explicitly update \fBactionpack\fR, including its dependencies which other gems in the Gemfile(5) still depend on, run \fBbundle update actionpack\fR (see \fBbundle update(1)\fR)\. . .P \fBSummary\fR: In general, after making a change to the Gemfile(5) , you should first try to run \fBbundle install\fR, which will guarantee that no other gem in the Gemfile(5) is impacted by the change\. If that does not work, run bundle update(1) \fIbundle\-update\.1\.html\fR\. . .SH "SEE ALSO" . .IP "\(bu" 4 Gem install docs \fIhttp://guides\.rubygems\.org/rubygems\-basics/#installing\-gems\fR . .IP "\(bu" 4 Rubygems signing docs \fIhttp://guides\.rubygems\.org/security/\fR . .IP "" 0 PKu]-N-N-bundler-2.2.24/lib/bundler/man/gemfile.5.ronnnu[Gemfile(5) -- A format for describing gem dependencies for Ruby programs ======================================================================== ## SYNOPSIS A `Gemfile` describes the gem dependencies required to execute associated Ruby code. Place the `Gemfile` in the root of the directory containing the associated code. For instance, in a Rails application, place the `Gemfile` in the same directory as the `Rakefile`. ## SYNTAX A `Gemfile` is evaluated as Ruby code, in a context which makes available a number of methods used to describe the gem requirements. ## GLOBAL SOURCES At the top of the `Gemfile`, add a line for the `Rubygems` source that contains the gems listed in the `Gemfile`. source "https://rubygems.org" It is possible, but not recommended as of Bundler 1.7, to add multiple global `source` lines. Each of these `source`s `MUST` be a valid Rubygems repository. Sources are checked for gems following the heuristics described in [SOURCE PRIORITY][]. If a gem is found in more than one global source, Bundler will print a warning after installing the gem indicating which source was used, and listing the other sources where the gem is available. A specific source can be selected for gems that need to use a non-standard repository, suppressing this warning, by using the [`:source` option](#SOURCE) or a [`source` block](#BLOCK-FORM-OF-SOURCE-GIT-PATH-GROUP-and-PLATFORMS). ### CREDENTIALS Some gem sources require a username and password. Use [bundle config(1)](bundle-config.1.html) to set the username and password for any of the sources that need it. The command must be run once on each computer that will install the Gemfile, but this keeps the credentials from being stored in plain text in version control. bundle config gems.example.com user:password For some sources, like a company Gemfury account, it may be easier to include the credentials in the Gemfile as part of the source URL. source "https://user:password@gems.example.com" Credentials in the source URL will take precedence over credentials set using `config`. ## RUBY If your application requires a specific Ruby version or engine, specify your requirements using the `ruby` method, with the following arguments. All parameters are `OPTIONAL` unless otherwise specified. ### VERSION (required) The version of Ruby that your application requires. If your application requires an alternate Ruby engine, such as JRuby, Rubinius or TruffleRuby, this should be the Ruby version that the engine is compatible with. ruby "1.9.3" ### ENGINE Each application _may_ specify a Ruby engine. If an engine is specified, an engine version _must_ also be specified. What exactly is an Engine? - A Ruby engine is an implementation of the Ruby language. - For background: the reference or original implementation of the Ruby programming language is called [Matz's Ruby Interpreter](https://en.wikipedia.org/wiki/Ruby_MRI), or MRI for short. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz. MRI is also known as CRuby, because it is written in C. MRI is the most widely used Ruby engine. - [Other implementations](https://www.ruby-lang.org/en/about/) of Ruby exist. Some of the more well-known implementations include [Rubinius](https://rubinius.com/), and [JRuby](http://jruby.org/). Rubinius is an alternative implementation of Ruby written in Ruby. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine. ### ENGINE VERSION Each application _may_ specify a Ruby engine version. If an engine version is specified, an engine _must_ also be specified. If the engine is "ruby" the engine version specified _must_ match the Ruby version. ruby "1.8.7", :engine => "jruby", :engine_version => "1.6.7" ### PATCHLEVEL Each application _may_ specify a Ruby patchlevel. ruby "2.0.0", :patchlevel => "247" ## GEMS Specify gem requirements using the `gem` method, with the following arguments. All parameters are `OPTIONAL` unless otherwise specified. ### NAME (required) For each gem requirement, list a single _gem_ line. gem "nokogiri" ### VERSION Each _gem_ `MAY` have one or more version specifiers. gem "nokogiri", ">= 1.4.2" gem "RedCloth", ">= 4.1.0", "< 4.2.0" ### REQUIRE AS Each _gem_ `MAY` specify files that should be used when autorequiring via `Bundler.require`. You may pass an array with multiple files or `true` if the file you want `required` has the same name as _gem_ or `false` to prevent any file from being autorequired. gem "redis", :require => ["redis/connection/hiredis", "redis"] gem "webmock", :require => false gem "byebug", :require => true The argument defaults to the name of the gem. For example, these are identical: gem "nokogiri" gem "nokogiri", :require => "nokogiri" gem "nokogiri", :require => true ### GROUPS Each _gem_ `MAY` specify membership in one or more groups. Any _gem_ that does not specify membership in any group is placed in the `default` group. gem "rspec", :group => :test gem "wirble", :groups => [:development, :test] The Bundler runtime allows its two main methods, `Bundler.setup` and `Bundler.require`, to limit their impact to particular groups. # setup adds gems to Ruby's load path Bundler.setup # defaults to all groups require "bundler/setup" # same as Bundler.setup Bundler.setup(:default) # only set up the _default_ group Bundler.setup(:test) # only set up the _test_ group (but `not` _default_) Bundler.setup(:default, :test) # set up the _default_ and _test_ groups, but no others # require requires all of the gems in the specified groups Bundler.require # defaults to the _default_ group Bundler.require(:default) # identical Bundler.require(:default, :test) # requires the _default_ and _test_ groups Bundler.require(:test) # requires the _test_ group The Bundler CLI allows you to specify a list of groups whose gems `bundle install` should not install with the `without` configuration. To specify multiple groups to ignore, specify a list of groups separated by spaces. bundle config set --local without test bundle config set --local without development test Also, calling `Bundler.setup` with no parameters, or calling `require "bundler/setup"` will setup all groups except for the ones you excluded via `--without` (since they are not available). Note that on `bundle install`, bundler downloads and evaluates all gems, in order to create a single canonical list of all of the required gems and their dependencies. This means that you cannot list different versions of the same gems in different groups. For more details, see [Understanding Bundler](https://bundler.io/rationale.html). ### PLATFORMS If a gem should only be used in a particular platform or set of platforms, you can specify them. Platforms are essentially identical to groups, except that you do not need to use the `--without` install-time flag to exclude groups of gems for other platforms. There are a number of `Gemfile` platforms: * `ruby`: C Ruby (MRI), Rubinius or TruffleRuby, but `NOT` Windows * `mri`: Same as _ruby_, but only C Ruby (MRI) * `mingw`: Windows 32 bit 'mingw32' platform (aka RubyInstaller) * `x64_mingw`: Windows 64 bit 'mingw32' platform (aka RubyInstaller x64) * `rbx`: Rubinius * `jruby`: JRuby * `truffleruby`: TruffleRuby * `mswin`: Windows You can restrict further by platform and version for all platforms *except* for `rbx`, `jruby`, `truffleruby` and `mswin`. To specify a version in addition to a platform, append the version number without the delimiter to the platform. For example, to specify that a gem should only be used on platforms with Ruby 2.3, use: ruby_23 The full list of platforms and supported versions includes: * `ruby`: 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 * `mri`: 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 * `mingw`: 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 * `x64_mingw`: 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 As with groups, you can specify one or more platforms: gem "weakling", :platforms => :jruby gem "ruby-debug", :platforms => :mri_18 gem "nokogiri", :platforms => [:mri_18, :jruby] All operations involving groups ([`bundle install`](bundle-install.1.html), `Bundler.setup`, `Bundler.require`) behave exactly the same as if any groups not matching the current platform were explicitly excluded. ### SOURCE You can select an alternate Rubygems repository for a gem using the ':source' option. gem "some_internal_gem", :source => "https://gems.example.com" This forces the gem to be loaded from this source and ignores any global sources declared at the top level of the file. If the gem does not exist in this source, it will not be installed. Bundler will search for child dependencies of this gem by first looking in the source selected for the parent, but if they are not found there, it will fall back on global sources using the ordering described in [SOURCE PRIORITY][]. Selecting a specific source repository this way also suppresses the ambiguous gem warning described above in [GLOBAL SOURCES (#source)](#GLOBAL-SOURCES). Using the `:source` option for an individual gem will also make that source available as a possible global source for any other gems which do not specify explicit sources. Thus, when adding gems with explicit sources, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources. ### GIT If necessary, you can specify that a gem is located at a particular git repository using the `:git` parameter. The repository can be accessed via several protocols: * `HTTP(S)`: gem "rails", :git => "https://github.com/rails/rails.git" * `SSH`: gem "rails", :git => "git@github.com:rails/rails.git" * `git`: gem "rails", :git => "git://github.com/rails/rails.git" If using SSH, the user that you use to run `bundle install` `MUST` have the appropriate keys available in their `$HOME/.ssh`. `NOTE`: `http://` and `git://` URLs should be avoided if at all possible. These protocols are unauthenticated, so a man-in-the-middle attacker can deliver malicious code and compromise your system. HTTPS and SSH are strongly preferred. The `group`, `platforms`, and `require` options are available and behave exactly the same as they would for a normal gem. A git repository `SHOULD` have at least one file, at the root of the directory containing the gem, with the extension `.gemspec`. This file `MUST` contain a valid gem specification, as expected by the `gem build` command. If a git repository does not have a `.gemspec`, bundler will attempt to create one, but it will not contain any dependencies, executables, or C extension compilation instructions. As a result, it may fail to properly integrate into your application. If a git repository does have a `.gemspec` for the gem you attached it to, a version specifier, if provided, means that the git repository is only valid if the `.gemspec` specifies a version matching the version specifier. If not, bundler will print a warning. gem "rails", "2.3.8", :git => "https://github.com/rails/rails.git" # bundle install will fail, because the .gemspec in the rails # repository's master branch specifies version 3.0.0 If a git repository does `not` have a `.gemspec` for the gem you attached it to, a version specifier `MUST` be provided. Bundler will use this version in the simple `.gemspec` it creates. Git repositories support a number of additional options. * `branch`, `tag`, and `ref`: You `MUST` only specify at most one of these options. The default is `:branch => "master"`. For example: gem "rails", :git => "https://github.com/rails/rails.git", :branch => "5-0-stable" gem "rails", :git => "https://github.com/rails/rails.git", :tag => "v5.0.0" gem "rails", :git => "https://github.com/rails/rails.git", :ref => "4aded" * `submodules`: For reference, a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) lets you have another git repository within a subfolder of your repository. Specify `:submodules => true` to cause bundler to expand any submodules included in the git repository If a git repository contains multiple `.gemspecs`, each `.gemspec` represents a gem located at the same place in the file system as the `.gemspec`. |~rails [git root] | |-rails.gemspec [rails gem located here] |~actionpack | |-actionpack.gemspec [actionpack gem located here] |~activesupport | |-activesupport.gemspec [activesupport gem located here] |... To install a gem located in a git repository, bundler changes to the directory containing the gemspec, runs `gem build name.gemspec` and then installs the resulting gem. The `gem build` command, which comes standard with Rubygems, evaluates the `.gemspec` in the context of the directory in which it is located. ### GIT SOURCE A custom git source can be defined via the `git_source` method. Provide the source's name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address: git_source(:stash){ |repo_name| "https://stash.corp.acme.pl/#{repo_name}.git" } gem 'rails', :stash => 'forks/rails' In addition, if you wish to choose a specific branch: gem "rails", :stash => "forks/rails", :branch => "branch_name" ### GITHUB `NOTE`: This shorthand should be avoided until Bundler 2.0, since it currently expands to an insecure `git://` URL. This allows a man-in-the-middle attacker to compromise your system. If the git repository you want to use is hosted on GitHub and is public, you can use the :github shorthand to specify the github username and repository name (without the trailing ".git"), separated by a slash. If both the username and repository name are the same, you can omit one. gem "rails", :github => "rails/rails" gem "rails", :github => "rails" Are both equivalent to gem "rails", :git => "git://github.com/rails/rails.git" Since the `github` method is a specialization of `git_source`, it accepts a `:branch` named argument. ### GIST If the git repository you want to use is hosted as a Github Gist and is public, you can use the :gist shorthand to specify the gist identifier (without the trailing ".git"). gem "the_hatch", :gist => "4815162342" Is equivalent to: gem "the_hatch", :git => "https://gist.github.com/4815162342.git" Since the `gist` method is a specialization of `git_source`, it accepts a `:branch` named argument. ### BITBUCKET If the git repository you want to use is hosted on Bitbucket and is public, you can use the :bitbucket shorthand to specify the bitbucket username and repository name (without the trailing ".git"), separated by a slash. If both the username and repository name are the same, you can omit one. gem "rails", :bitbucket => "rails/rails" gem "rails", :bitbucket => "rails" Are both equivalent to gem "rails", :git => "https://rails@bitbucket.org/rails/rails.git" Since the `bitbucket` method is a specialization of `git_source`, it accepts a `:branch` named argument. ### PATH You can specify that a gem is located in a particular location on the file system. Relative paths are resolved relative to the directory containing the `Gemfile`. Similar to the semantics of the `:git` option, the `:path` option requires that the directory in question either contains a `.gemspec` for the gem, or that you specify an explicit version that bundler should use. Unlike `:git`, bundler does not compile C extensions for gems specified as paths. gem "rails", :path => "vendor/rails" If you would like to use multiple local gems directly from the filesystem, you can set a global `path` option to the path containing the gem's files. This will automatically load gemspec files from subdirectories. path 'components' do gem 'admin_ui' gem 'public_ui' end ## BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS The `:source`, `:git`, `:path`, `:group`, and `:platforms` options may be applied to a group of gems by using block form. source "https://gems.example.com" do gem "some_internal_gem" gem "another_internal_gem" end git "https://github.com/rails/rails.git" do gem "activesupport" gem "actionpack" end platforms :ruby do gem "ruby-debug" gem "sqlite3" end group :development, :optional => true do gem "wirble" gem "faker" end In the case of the group block form the :optional option can be given to prevent a group from being installed unless listed in the `--with` option given to the `bundle install` command. In the case of the `git` block form, the `:ref`, `:branch`, `:tag`, and `:submodules` options may be passed to the `git` method, and all gems in the block will inherit those options. The presence of a `source` block in a Gemfile also makes that source available as a possible global source for any other gems which do not specify explicit sources. Thus, when defining source blocks, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources, either via source blocks or `:source` directives on individual gems. ## INSTALL_IF The `install_if` method allows gems to be installed based on a proc or lambda. This is especially useful for optional gems that can only be used if certain software is installed or some other conditions are met. install_if -> { RUBY_PLATFORM =~ /darwin/ } do gem "pasteboard" end ## GEMSPEC The [`.gemspec`](http://guides.rubygems.org/specification-reference/) file is where you provide metadata about your gem to Rubygems. Some required Gemspec attributes include the name, description, and homepage of your gem. This is also where you specify the dependencies your gem needs to run. If you wish to use Bundler to help install dependencies for a gem while it is being developed, use the `gemspec` method to pull in the dependencies listed in the `.gemspec` file. The `gemspec` method adds any runtime dependencies as gem requirements in the default group. It also adds development dependencies as gem requirements in the `development` group. Finally, it adds a gem requirement on your project (`:path => '.'`). In conjunction with `Bundler.setup`, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths. The `gemspec` method supports optional `:path`, `:glob`, `:name`, and `:development_group` options, which control where bundler looks for the `.gemspec`, the glob it uses to look for the gemspec (defaults to: "{,*,*/*}.gemspec"), what named `.gemspec` it uses (if more than one is present), and which group development dependencies are included in. When a `gemspec` dependency encounters version conflicts during resolution, the local version under development will always be selected -- even if there are remote versions that better match other requirements for the `gemspec` gem. ## SOURCE PRIORITY When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order: 1. The source explicitly attached to the gem (using `:source`, `:path`, or `:git`) 2. For implicit gems (dependencies of explicit gems), any source, git, or path repository declared on the parent. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from `rubygems.org` 3. The sources specified via global `source` lines, searching each source in your `Gemfile` from last added to first added. PKu]>^gH H ,bundler-2.2.24/lib/bundler/man/bundle.1.ronnnu[bundle(1) -- Ruby Dependency Management ======================================= ## SYNOPSIS `bundle` COMMAND [--no-color] [--verbose] [ARGS] ## DESCRIPTION Bundler manages an `application's dependencies` through its entire life across many machines systematically and repeatably. See [the bundler website](https://bundler.io) for information on getting started, and Gemfile(5) for more information on the `Gemfile` format. ## OPTIONS * `--no-color`: Print all output without color * `--retry`, `-r`: Specify the number of times you wish to attempt network commands * `--verbose`, `-V`: Print out additional logging information ## BUNDLE COMMANDS We divide `bundle` subcommands into primary commands and utilities: ## PRIMARY COMMANDS * [`bundle install(1)`](bundle-install.1.html): Install the gems specified by the `Gemfile` or `Gemfile.lock` * [`bundle update(1)`](bundle-update.1.html): Update dependencies to their latest versions * [`bundle package(1)`](bundle-package.1.html): Package the .gem files required by your application into the `vendor/cache` directory * [`bundle exec(1)`](bundle-exec.1.html): Execute a script in the current bundle * [`bundle config(1)`](bundle-config.1.html): Specify and read configuration options for Bundler * `bundle help(1)`: Display detailed help for each subcommand ## UTILITIES * [`bundle add(1)`](bundle-add.1.html): Add the named gem to the Gemfile and run `bundle install` * [`bundle binstubs(1)`](bundle-binstubs.1.html): Generate binstubs for executables in a gem * [`bundle check(1)`](bundle-check.1.html): Determine whether the requirements for your application are installed and available to Bundler * [`bundle show(1)`](bundle-show.1.html): Show the source location of a particular gem in the bundle * [`bundle outdated(1)`](bundle-outdated.1.html): Show all of the outdated gems in the current bundle * `bundle console(1)`: Start an IRB session in the current bundle * [`bundle open(1)`](bundle-open.1.html): Open an installed gem in the editor * [`bundle lock(1)`](bundle-lock.1.html): Generate a lockfile for your dependencies * [`bundle viz(1)`](bundle-viz.1.html): Generate a visual representation of your dependencies * [`bundle init(1)`](bundle-init.1.html): Generate a simple `Gemfile`, placed in the current directory * [`bundle gem(1)`](bundle-gem.1.html): Create a simple gem, suitable for development with Bundler * [`bundle platform(1)`](bundle-platform.1.html): Display platform compatibility information * [`bundle clean(1)`](bundle-clean.1.html): Clean up unused gems in your Bundler directory * [`bundle doctor(1)`](bundle-doctor.1.html): Display warnings about common problems * [`bundle remove(1)`](bundle-remove.1.html): Removes gems from the Gemfile ## PLUGINS When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named `bundler-` and execute it, passing down any extra arguments to it. ## OBSOLETE These commands are obsolete and should no longer be used: * `bundle cache(1)` * `bundle show(1)` PKu]2P33,bundler-2.2.24/lib/bundler/man/bundle-init.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-INIT" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory . .SH "SYNOPSIS" \fBbundle init\fR [\-\-gemspec=FILE] . .SH "DESCRIPTION" Init generates a default [\fBGemfile(5)\fR][Gemfile(5)] in the current working directory\. When adding a [\fBGemfile(5)\fR][Gemfile(5)] to a gem with a gemspec, the \fB\-\-gemspec\fR option will automatically add each dependency listed in the gemspec file to the newly created [\fBGemfile(5)\fR][Gemfile(5)]\. . .SH "OPTIONS" . .TP \fB\-\-gemspec\fR Use the specified \.gemspec to create the [\fBGemfile(5)\fR][Gemfile(5)] . .SH "FILES" Included in the default [\fBGemfile(5)\fR][Gemfile(5)] generated is the line \fB# frozen_string_literal: true\fR\. This is a magic comment supported for the first time in Ruby 2\.3\. The presence of this line results in all string literals in the file being implicitly frozen\. . .SH "SEE ALSO" Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR PKu]ߕ}}5bundler-2.2.24/lib/bundler/man/bundle-platform.1.ronnnu[bundle-platform(1) -- Displays platform compatibility information ================================================================= ## SYNOPSIS `bundle platform` [--ruby] ## DESCRIPTION `platform` will display information from your Gemfile, Gemfile.lock, and Ruby VM about your platform. For instance, using this Gemfile(5): source "https://rubygems.org" ruby "1.9.3" gem "rack" If you run `bundle platform` on Ruby 1.9.3, it will display the following output: Your platform is: x86_64-linux Your app has gems that work on these platforms: * ruby Your Gemfile specifies a Ruby version requirement: * ruby 1.9.3 Your current platform satisfies the Ruby version requirement. `platform` will list all the platforms in your `Gemfile.lock` as well as the `ruby` directive if applicable from your Gemfile(5). It will also let you know if the `ruby` directive requirement has been met. If `ruby` directive doesn't match the running Ruby VM, it will tell you what part does not. ## OPTIONS * `--ruby`: It will display the ruby directive information, so you don't have to parse it from the Gemfile(5). PKu]j0bundler-2.2.24/lib/bundler/man/bundle-pristine.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-PRISTINE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition . .SH "SYNOPSIS" \fBbundle pristine\fR . .SH "DESCRIPTION" \fBpristine\fR restores the installed gems in the bundle to their pristine condition using the local gem cache from RubyGems\. For git gems, a forced checkout will be performed\. . .P For further explanation, \fBbundle pristine\fR ignores unpacked files on disk\. In other words, this command utilizes the local \fB\.gem\fR cache or the gem\'s git repository as if one were installing from scratch\. . .P Note: the Bundler gem cannot be restored to its original state with \fBpristine\fR\. One also cannot use \fBbundle pristine\fR on gems with a \'path\' option in the Gemfile, because bundler has no original copy it can restore from\. . .P When is it practical to use \fBbundle pristine\fR? . .P It comes in handy when a developer is debugging a gem\. \fBbundle pristine\fR is a great way to get rid of experimental changes to a gem that one may not want\. . .P Why use \fBbundle pristine\fR over \fBgem pristine \-\-all\fR? . .P Both commands are very similar\. For context: \fBbundle pristine\fR, without arguments, cleans all gems from the lockfile\. Meanwhile, \fBgem pristine \-\-all\fR cleans all installed gems for that Ruby version\. . .P If a developer forgets which gems in their project they might have been debugging, the Rubygems \fBgem pristine [GEMNAME]\fR command may be inconvenient\. One can avoid waiting for \fBgem pristine \-\-all\fR, and instead run \fBbundle pristine\fR\. PKu]'uw^0bundler-2.2.24/lib/bundler/man/bundle-add.1.ronnnu[bundle-add(1) -- Add gem to the Gemfile and run bundle install ================================================================ ## SYNOPSIS `bundle add` [--group=GROUP] [--version=VERSION] [--source=SOURCE] [--git=GIT] [--branch=BRANCH] [--skip-install] [--strict] [--optimistic] ## DESCRIPTION Adds the named gem to the Gemfile and run `bundle install`. `bundle install` can be avoided by using the flag `--skip-install`. Example: bundle add rails bundle add rails --version "< 3.0, > 1.1" bundle add rails --version "~> 5.0.0" --source "https://gems.example.com" --group "development" bundle add rails --skip-install bundle add rails --group "development, test" ## OPTIONS * `--version`, `-v`: Specify version requirements(s) for the added gem. * `--group`, `-g`: Specify the group(s) for the added gem. Multiple groups should be separated by commas. * `--source`, , `-s`: Specify the source for the added gem. * `--git`: Specify the git source for the added gem. * `--branch`: Specify the git branch for the added gem. * `--skip-install`: Adds the gem to the Gemfile but does not install it. * `--optimistic`: Adds optimistic declaration of version * `--strict`: Adds strict declaration of version PKu]?OAA,bundler-2.2.24/lib/bundler/man/bundle-open.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-OPEN" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle . .SH "SYNOPSIS" \fBbundle open\fR [GEM] . .SH "DESCRIPTION" Opens the source directory of the provided GEM in your editor\. . .P For this to work the \fBEDITOR\fR or \fBBUNDLER_EDITOR\fR environment variable has to be set\. . .P Example: . .IP "" 4 . .nf bundle open \'rack\' . .fi . .IP "" 0 . .P Will open the source directory for the \'rack\' gem in your bundle\. PKu]"&YxSS.bundler-2.2.24/lib/bundler/man/bundle-config.1nu[.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "BUNDLE\-CONFIG" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options . .SH "SYNOPSIS" \fBbundle config\fR [list|get|set|unset] [\fIname\fR [\fIvalue\fR]] . .SH "DESCRIPTION" This command allows you to interact with Bundler\'s configuration system\. . .P Bundler loads configuration settings in this order: . .IP "1." 4 Local config (\fB/\.bundle/config\fR or \fB$BUNDLE_APP_CONFIG/config\fR) . .IP "2." 4 Environmental variables (\fBENV\fR) . .IP "3." 4 Global config (\fB~/\.bundle/config\fR) . .IP "4." 4 Bundler default config . .IP "" 0 . .P Executing \fBbundle config list\fR with will print a list of all bundler configuration for the current bundle, and where that configuration was set\. . .P Executing \fBbundle config get \fR will print the value of that configuration setting, and where it was set\. . .P Executing \fBbundle config set \fR will set that configuration to the value specified for all bundles executed as the current user\. The configuration will be stored in \fB~/\.bundle/config\fR\. If \fIname\fR already is set, \fIname\fR will be overridden and user will be warned\. . .P Executing \fBbundle config set \-\-global \fR works the same as above\. . .P Executing \fBbundle config set \-\-local \fR will set that configuration in the directory for the local application\. The configuration will be stored in \fB/\.bundle/config\fR\. If \fBBUNDLE_APP_CONFIG\fR is set, the configuration will be stored in \fB$BUNDLE_APP_CONFIG/config\fR\. . .P Executing \fBbundle config unset \fR will delete the configuration in both local and global sources\. . .P Executing \fBbundle config unset \-\-global \fR will delete the configuration only from the user configuration\. . .P Executing \fBbundle config unset \-\-local \fR will delete the configuration only from the local application\. . .P Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. . .SH "REMEMBERING OPTIONS" Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application\'s configuration (normally, \fB\./\.bundle/config\fR)\. . .P However, this will be changed in bundler 3, so it\'s better not to rely on this behavior\. If these options must be remembered, it\'s better to set them using \fBbundle config\fR (e\.g\., \fBbundle config set \-\-local path foo\fR)\. . .P The options that can be configured are: . .TP \fBbin\fR Creates a directory (defaults to \fB~/bin\fR) and place any executables from the gem there\. These executables run in Bundler\'s context\. If used, you might add this directory to your environment\'s \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\. . .TP \fBdeployment\fR In deployment mode, Bundler will \'roll\-out\' the bundle for \fBproduction\fR use\. Please check carefully if you want to have this option enabled in \fBdevelopment\fR or \fBtest\fR environments\. . .TP \fBpath\fR The location to install the specified gems to\. This defaults to Rubygems\' setting\. Bundler shares this location with Rubygems, \fBgem install \.\.\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \.\.\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\. . .TP \fBwithout\fR A space\-separated list of groups referencing gems to skip during installation\. . .TP \fBwith\fR A space\-separated list of groups referencing gems to include during installation\. . .SH "BUILD OPTIONS" You can use \fBbundle config\fR to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem\. . .P A very common example, the \fBmysql\fR gem, requires Snow Leopard users to pass configuration flags to \fBgem install\fR to specify where to find the \fBmysql_config\fR executable\. . .IP "" 4 . .nf gem install mysql \-\- \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config . .fi . .IP "" 0 . .P Since the specific location of that executable can change from machine to machine, you can specify these flags on a per\-machine basis\. . .IP "" 4 . .nf bundle config set \-\-global build\.mysql \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config . .fi . .IP "" 0 . .P After running this command, every time bundler needs to install the \fBmysql\fR gem, it will pass along the flags you specified\. . .SH "CONFIGURATION KEYS" Configuration keys in bundler have two forms: the canonical form and the environment variable form\. . .P For instance, passing the \fB\-\-without\fR flag to bundle install(1) \fIbundle\-install\.1\.html\fR prevents Bundler from installing certain groups specified in the Gemfile(5)\. Bundler persists this value in \fBapp/\.bundle/config\fR so that calls to \fBBundler\.setup\fR do not try to find gems from the \fBGemfile\fR that you didn\'t install\. Additionally, subsequent calls to bundle install(1) \fIbundle\-install\.1\.html\fR remember this setting and skip those groups\. . .P The canonical form of this configuration is \fB"without"\fR\. To convert the canonical form to the environment variable form, capitalize it, and prepend \fBBUNDLE_\fR\. The environment variable form of \fB"without"\fR is \fBBUNDLE_WITHOUT\fR\. . .P Any periods in the configuration keys must be replaced with two underscores when setting it via environment variables\. The configuration key \fBlocal\.rack\fR becomes the environment variable \fBBUNDLE_LOCAL__RACK\fR\. . .SH "LIST OF AVAILABLE KEYS" The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\. . .IP "\(bu" 4 \fBallow_deployment_source_credential_changes\fR (\fBBUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES\fR): When in deployment mode, allow changing the credentials to a gem\'s source\. Ex: \fBhttps://some\.host\.com/gems/path/\fR \-> \fBhttps://user_name:password@some\.host\.com/gems/path\fR . .IP "\(bu" 4 \fBallow_offline_install\fR (\fBBUNDLE_ALLOW_OFFLINE_INSTALL\fR): Allow Bundler to use cached data when installing without network access\. . .IP "\(bu" 4 \fBauto_clean_without_path\fR (\fBBUNDLE_AUTO_CLEAN_WITHOUT_PATH\fR): Automatically run \fBbundle clean\fR after installing when an explicit \fBpath\fR has not been set and Bundler is not installing into the system gems\. . .IP "\(bu" 4 \fBauto_install\fR (\fBBUNDLE_AUTO_INSTALL\fR): Automatically run \fBbundle install\fR when gems are missing\. . .IP "\(bu" 4 \fBbin\fR (\fBBUNDLE_BIN\fR): Install executables from gems in the bundle to the specified directory\. Defaults to \fBfalse\fR\. . .IP "\(bu" 4 \fBcache_all\fR (\fBBUNDLE_CACHE_ALL\fR): Cache all gems, including path and git gems\. This needs to be explicitly configured on bundler 1 and bundler 2, but will be the default on bundler 3\. . .IP "\(bu" 4 \fBcache_all_platforms\fR (\fBBUNDLE_CACHE_ALL_PLATFORMS\fR): Cache gems for all platforms\. . .IP "\(bu" 4 \fBcache_path\fR (\fBBUNDLE_CACHE_PATH\fR): The directory that bundler will place cached gems in when running \fBbundle package\fR, and that bundler will look in when installing gems\. Defaults to \fBvendor/cache\fR\. . .IP "\(bu" 4 \fBclean\fR (\fBBUNDLE_CLEAN\fR): Whether Bundler should run \fBbundle clean\fR automatically after \fBbundle install\fR\. . .IP "\(bu" 4 \fBconsole\fR (\fBBUNDLE_CONSOLE\fR): The console that \fBbundle console\fR starts\. Defaults to \fBirb\fR\. . .IP "\(bu" 4 \fBdefault_install_uses_path\fR (\fBBUNDLE_DEFAULT_INSTALL_USES_PATH\fR): Whether a \fBbundle install\fR without an explicit \fB\-\-path\fR argument defaults to installing gems in \fB\.bundle\fR\. . .IP "\(bu" 4 \fBdeployment\fR (\fBBUNDLE_DEPLOYMENT\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\. . .IP "\(bu" 4 \fBdisable_checksum_validation\fR (\fBBUNDLE_DISABLE_CHECKSUM_VALIDATION\fR): Allow installing gems even if they do not match the checksum provided by RubyGems\. . .IP "\(bu" 4 \fBdisable_exec_load\fR (\fBBUNDLE_DISABLE_EXEC_LOAD\fR): Stop Bundler from using \fBload\fR to launch an executable in\-process in \fBbundle exec\fR\. . .IP "\(bu" 4 \fBdisable_local_branch_check\fR (\fBBUNDLE_DISABLE_LOCAL_BRANCH_CHECK\fR): Allow Bundler to use a local git override without a branch specified in the Gemfile\. . .IP "\(bu" 4 \fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\. . .IP "\(bu" 4 \fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems\' normal location\. . .IP "\(bu" 4 \fBdisable_version_check\fR (\fBBUNDLE_DISABLE_VERSION_CHECK\fR): Stop Bundler from checking if a newer Bundler version is available on rubygems\.org\. . .IP "\(bu" 4 \fBforce_ruby_platform\fR (\fBBUNDLE_FORCE_RUBY_PLATFORM\fR): Ignore the current machine\'s platform and install only \fBruby\fR platform gems\. As a result, gems with native extensions will be compiled from source\. . .IP "\(bu" 4 \fBfrozen\fR (\fBBUNDLE_FROZEN\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\. Defaults to \fBtrue\fR when \fB\-\-deployment\fR is used\. . .IP "\(bu" 4 \fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in \fBREADME\fR file when you create a new gem via \fBbundle gem\fR command\. It can be overridden by passing an explicit \fB\-\-github\-username\fR flag to \fBbundle gem\fR\. . .IP "\(bu" 4 \fBgem\.push_key\fR (\fBBUNDLE_GEM__PUSH_KEY\fR): Sets the \fB\-\-key\fR parameter for \fBgem push\fR when using the \fBrake release\fR command with a private gemstash server\. . .IP "\(bu" 4 \fBgemfile\fR (\fBBUNDLE_GEMFILE\fR): The name of the file that bundler should use as the \fBGemfile\fR\. This location of this file also sets the root of the project, which is used to resolve relative paths in the \fBGemfile\fR, among other things\. By default, bundler will search up from the current working directory until it finds a \fBGemfile\fR\. . .IP "\(bu" 4 \fBglobal_gem_cache\fR (\fBBUNDLE_GLOBAL_GEM_CACHE\fR): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation\. . .IP "\(bu" 4 \fBignore_messages\fR (\fBBUNDLE_IGNORE_MESSAGES\fR): When set, no post install messages will be printed\. To silence a single gem, use dot notation like \fBignore_messages\.httparty true\fR\. . .IP "\(bu" 4 \fBinit_gems_rb\fR (\fBBUNDLE_INIT_GEMS_RB\fR): Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\. . .IP "\(bu" 4 \fBjobs\fR (\fBBUNDLE_JOBS\fR): The number of gems Bundler can install in parallel\. Defaults to 1 on Windows, and to the the number of processors on other platforms\. . .IP "\(bu" 4 \fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR): Whether \fBbundle package\fR should skip installing gems\. . .IP "\(bu" 4 \fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR): Whether Bundler should leave outdated gems unpruned when caching\. . .IP "\(bu" 4 \fBpath\fR (\fBBUNDLE_PATH\fR): The location on disk where all gems in your bundle will be located regardless of \fB$GEM_HOME\fR or \fB$GEM_PATH\fR values\. Bundle gems not found in this location will be installed by \fBbundle install\fR\. Defaults to \fBGem\.dir\fR\. When \-\-deployment is used, defaults to vendor/bundle\. . .IP "\(bu" 4 \fBpath\.system\fR (\fBBUNDLE_PATH__SYSTEM\fR): Whether Bundler will install gems into the default system path (\fBGem\.dir\fR)\. . .IP "\(bu" 4 \fBpath_relative_to_cwd\fR (\fBBUNDLE_PATH_RELATIVE_TO_CWD\fR) Makes \fB\-\-path\fR relative to the CWD instead of the \fBGemfile\fR\. . .IP "\(bu" 4 \fBplugins\fR (\fBBUNDLE_PLUGINS\fR): Enable Bundler\'s experimental plugin system\. . .IP "\(bu" 4 \fBprefer_patch\fR (BUNDLE_PREFER_PATCH): Prefer updating only to next patch version during updates\. Makes \fBbundle update\fR calls equivalent to \fBbundler update \-\-patch\fR\. . .IP "\(bu" 4 \fBprint_only_version_number\fR (\fBBUNDLE_PRINT_ONLY_VERSION_NUMBER\fR): Print only version number from \fBbundler \-\-version\fR\. . .IP "\(bu" 4 \fBredirect\fR (\fBBUNDLE_REDIRECT\fR): The number of redirects allowed for network requests\. Defaults to \fB5\fR\. . .IP "\(bu" 4 \fBretry\fR (\fBBUNDLE_RETRY\fR): The number of times to retry failed network requests\. Defaults to \fB3\fR\. . .IP "\(bu" 4 \fBsetup_makes_kernel_gem_public\fR (\fBBUNDLE_SETUP_MAKES_KERNEL_GEM_PUBLIC\fR): Have \fBBundler\.setup\fR make the \fBKernel#gem\fR method public, even though RubyGems declares it as private\. . .IP "\(bu" 4 \fBshebang\fR (\fBBUNDLE_SHEBANG\fR): The program name that should be invoked for generated binstubs\. Defaults to the ruby install name used to generate the binstub\. . .IP "\(bu" 4 \fBsilence_deprecations\fR (\fBBUNDLE_SILENCE_DEPRECATIONS\fR): Whether Bundler should silence deprecation warnings for behavior that will be changed in the next major version\. . .IP "\(bu" 4 \fBsilence_root_warning\fR (\fBBUNDLE_SILENCE_ROOT_WARNING\fR): Silence the warning Bundler prints when installing gems as root\. . .IP "\(bu" 4 \fBssl_ca_cert\fR (\fBBUNDLE_SSL_CA_CERT\fR): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format\. . .IP "\(bu" 4 \fBssl_client_cert\fR (\fBBUNDLE_SSL_CLIENT_CERT\fR): Path to a designated file containing a X\.509 client certificate and key in PEM format\. . .IP "\(bu" 4 \fBssl_verify_mode\fR (\fBBUNDLE_SSL_VERIFY_MODE\fR): The SSL verification mode Bundler uses when making HTTPS requests\. Defaults to verify peer\. . .IP "\(bu" 4 \fBsuppress_install_using_messages\fR (\fBBUNDLE_SUPPRESS_INSTALL_USING_MESSAGES\fR): Avoid printing \fBUsing \.\.\.\fR messages during installation when the version of a gem has not changed\. . .IP "\(bu" 4 \fBsystem_bindir\fR (\fBBUNDLE_SYSTEM_BINDIR\fR): The location where RubyGems installs binstubs\. Defaults to \fBGem\.bindir\fR\. . .IP "\(bu" 4 \fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\. . .IP "\(bu" 4 \fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\. . .IP "\(bu" 4 \fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR): The custom user agent fragment Bundler includes in API requests\. . .IP "\(bu" 4 \fBwith\fR (\fBBUNDLE_WITH\fR): A \fB:\fR\-separated list of groups whose gems bundler should install\. . .IP "\(bu" 4 \fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A \fB:\fR\-separated list of groups whose gems bundler should not install\. . .IP "" 0 . .P In general, you should set these settings per\-application by using the applicable flag to the bundle install(1) \fIbundle\-install\.1\.html\fR or bundle package(1) \fIbundle\-package\.1\.html\fR command\. . .P You can set them globally either via environment variables or \fBbundle config\fR, whichever is preferable for your setup\. If you use both, environment variables will take preference over global settings\. . .SH "LOCAL GIT REPOS" Bundler also allows you to work against a git repository locally instead of using the remote version\. This can be achieved by setting up a local override: . .IP "" 4 . .nf bundle config set \-\-local local\.GEM_NAME /path/to/local/git/repository . .fi . .IP "" 0 . .P For example, in order to use a local Rack repository, a developer could call: . .IP "" 4 . .nf bundle config set \-\-local local\.rack ~/Work/git/rack . .fi . .IP "" 0 . .P Now instead of checking out the remote git repository, the local override will be used\. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler\. This means a commit in the local git repo will update the revision in the \fBGemfile\.lock\fR to the local git repo revision\. This requires the same attention as git submodules\. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine\. You\'ll also need to CGI escape your usernames and passwords as well\. . .P Bundler does many checks to ensure a developer won\'t work with invalid references\. Particularly, we force a developer to specify a branch in the \fBGemfile\fR in order to use this feature\. If the branch specified in the \fBGemfile\fR and the current branch in the local git repository do not match, Bundler will abort\. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch\. . .P Finally, Bundler also ensures that the current revision in the \fBGemfile\.lock\fR exists in the local git repository\. By doing this, Bundler forces you to fetch the latest changes in the remotes\. . .SH "MIRRORS OF GEM SOURCES" Bundler supports overriding gem sources with mirrors\. This allows you to configure rubygems\.org as the gem source in your Gemfile while still using your mirror to fetch gems\. . .IP "" 4 . .nf bundle config set \-\-global mirror\.SOURCE_URL MIRROR_URL . .fi . .IP "" 0 . .P For example, to use a mirror of rubygems\.org hosted at rubygems\-mirror\.org: . .IP "" 4 . .nf bundle config set \-\-global mirror\.http://rubygems\.org http://rubygems\-mirror\.org . .fi . .IP "" 0 . .P Each mirror also provides a fallback timeout setting\. If the mirror does not respond within the fallback timeout, Bundler will try to use the original server instead of the mirror\. . .IP "" 4 . .nf bundle config set \-\-global mirror\.SOURCE_URL\.fallback_timeout TIMEOUT . .fi . .IP "" 0 . .P For example, to fall back to rubygems\.org after 3 seconds: . .IP "" 4 . .nf bundle config set \-\-global mirror\.https://rubygems\.org\.fallback_timeout 3 . .fi . .IP "" 0 . .P The default fallback timeout is 0\.1 seconds, but the setting can currently only accept whole seconds (for example, 1, 15, or 30)\. . .SH "CREDENTIALS FOR GEM SOURCES" Bundler allows you to configure credentials for any gem source, which allows you to avoid putting secrets into your Gemfile\. . .IP "" 4 . .nf bundle config set \-\-global SOURCE_HOSTNAME USERNAME:PASSWORD . .fi . .IP "" 0 . .P For example, to save the credentials of user \fBclaudette\fR for the gem source at \fBgems\.longerous\.com\fR, you would run: . .IP "" 4 . .nf bundle config set \-\-global gems\.longerous\.com claudette:s00pers3krit . .fi . .IP "" 0 . .P Or you can set the credentials as an environment variable like this: . .IP "" 4 . .nf export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit" . .fi . .IP "" 0 . .P For gems with a git source with HTTP(S) URL you can specify credentials like so: . .IP "" 4 . .nf bundle config set \-\-global https://github\.com/rubygems/rubygems\.git username:password . .fi . .IP "" 0 . .P Or you can set the credentials as an environment variable like so: . .IP "" 4 . .nf export BUNDLE_GITHUB__COM=username:password . .fi . .IP "" 0 . .P This is especially useful for private repositories on hosts such as Github, where you can use personal OAuth tokens: . .IP "" 4 . .nf export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x\-oauth\-basic . .fi . .IP "" 0 . .P Note that any configured credentials will be redacted by informative commands such as \fBbundle config list\fR or \fBbundle config get\fR, unless you use the \fB\-\-parseable\fR flag\. This is to avoid unintentially leaking credentials when copy\-pasting bundler output\. . .P Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations: . .IP "\(bu" 4 Any \fB\-\fR characters in a host name are mapped to a triple dash (\fB___\fR) in the corresponding enviroment variable\. . .IP "\(bu" 4 Any \fB\.\fR characters in a host name are mapped to a double dash (\fB__\fR) in the corresponding environment variable\. . .IP "" 0 . .P This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you\'ll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\. . .SH "CONFIGURE BUNDLER DIRECTORIES" Bundler\'s home, config, cache and plugin directories are able to be configured through environment variables\. The default location for Bundler\'s home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values . .IP "" 4 . .nf BUNDLE_USER_HOME : $HOME/\.bundle BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin . .fi . .IP "" 0 PKu]uw-w-'bundler-2.2.24/lib/bundler/installer.rbnu[# frozen_string_literal: true require "rubygems/dependency_installer" require_relative "worker" require_relative "installer/parallel_installer" require_relative "installer/standalone" require_relative "installer/gem_installer" module Bundler class Installer class << self attr_accessor :ambiguous_gems Installer.ambiguous_gems = [] end attr_reader :post_install_messages # Begins the installation process for Bundler. # For more information see the #run method on this class. def self.install(root, definition, options = {}) installer = new(root, definition) Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL_ALL, definition.dependencies) installer.run(options) Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL_ALL, definition.dependencies) installer end def initialize(root, definition) @root = root @definition = definition @post_install_messages = {} end # Runs the install procedures for a specific Gemfile. # # Firstly, this method will check to see if `Bundler.bundle_path` exists # and if not then Bundler will create the directory. This is usually the same # location as RubyGems which typically is the `~/.gem` directory # unless other specified. # # Secondly, it checks if Bundler has been configured to be "frozen". # Frozen ensures that the Gemfile and the Gemfile.lock file are matching. # This stops a situation where a developer may update the Gemfile but may not run # `bundle install`, which leads to the Gemfile.lock file not being correctly updated. # If this file is not correctly updated then any other developer running # `bundle install` will potentially not install the correct gems. # # Thirdly, Bundler checks if there are any dependencies specified in the Gemfile. # If there are no dependencies specified then Bundler returns a warning message stating # so and this method returns. # # Fourthly, Bundler checks if the Gemfile.lock exists, and if so # then proceeds to set up a definition based on the Gemfile and the Gemfile.lock. # During this step Bundler will also download information about any new gems # that are not in the Gemfile.lock and resolve any dependencies if needed. # # Fifthly, Bundler resolves the dependencies either through a cache of gems or by remote. # This then leads into the gems being installed, along with stubs for their executables, # but only if the --binstubs option has been passed or Bundler.options[:bin] has been set # earlier. # # Sixthly, a new Gemfile.lock is created from the installed gems to ensure that the next time # that a user runs `bundle install` they will receive any updates from this process. # # Finally, if the user has specified the standalone flag, Bundler will generate the needed # require paths and save them in a `setup.rb` file. See `bundle standalone --help` for more # information. def run(options) create_bundle_path ProcessLock.lock do if Bundler.frozen_bundle? @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment]) end if @definition.dependencies.empty? Bundler.ui.warn "The Gemfile specifies no dependencies" lock return end if resolve_if_needed(options) ensure_specs_are_compatible! load_plugins options.delete(:jobs) else options[:jobs] = 1 # to avoid the overhead of Bundler::Worker end install(options) Gem::Specification.reset # invalidate gem specification cache so that installed gems are immediately available lock unless Bundler.frozen_bundle? Standalone.new(options[:standalone], @definition).generate if options[:standalone] end end def generate_bundler_executable_stubs(spec, options = {}) if options[:binstubs_cmd] && spec.executables.empty? options = {} spec.runtime_dependencies.each do |dep| bins = @definition.specs[dep].first.executables options[dep.name] = bins unless bins.empty? end if options.any? Bundler.ui.warn "#{spec.name} has no executables, but you may want " \ "one from a gem it depends on." options.each {|name, bins| Bundler.ui.warn " #{name} has: #{bins.join(", ")}" } else Bundler.ui.warn "There are no executables for the gem #{spec.name}." end return end # double-assignment to avoid warnings about variables that will be used by ERB bin_path = Bundler.bin_path bin_path = bin_path relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path) relative_gemfile_path = relative_gemfile_path ruby_command = Thor::Util.ruby_command ruby_command = ruby_command template_path = File.expand_path("../templates/Executable", __FILE__) if spec.name == "bundler" template_path += ".bundler" spec.executables = %(bundle) end template = File.read(template_path) exists = [] spec.executables.each do |executable| binstub_path = "#{bin_path}/#{executable}" if File.exist?(binstub_path) && !options[:force] exists << executable next end mode = Gem.win_platform? ? "wb:UTF-8" : "w" require "erb" content = if RUBY_VERSION >= "2.6" ERB.new(template, :trim_mode => "-").result(binding) else ERB.new(template, nil, "-").result(binding) end File.write(binstub_path, content, :mode => mode, :perm => 0o777 & ~File.umask) if Gem.win_platform? || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{binstub_path}.cmd", prefix + content, :mode => mode) end end if options[:binstubs_cmd] && exists.any? case exists.size when 1 Bundler.ui.warn "Skipped #{exists[0]} since it already exists." when 2 Bundler.ui.warn "Skipped #{exists.join(" and ")} since they already exist." else items = exists[0...-1].empty? ? nil : exists[0...-1].join(", ") skipped = [items, exists[-1]].compact.join(" and ") Bundler.ui.warn "Skipped #{skipped} since they already exist." end Bundler.ui.warn "If you want to overwrite skipped stubs, use --force." end end def generate_standalone_bundler_executable_stubs(spec, options = {}) # double-assignment to avoid warnings about variables that will be used by ERB bin_path = Bundler.bin_path unless path = Bundler.settings[:path] raise "Can't standalone without an explicit path set" end standalone_path = Bundler.root.join(path).relative_path_from(bin_path) standalone_path = standalone_path template = File.read(File.expand_path("../templates/Executable.standalone", __FILE__)) ruby_command = Thor::Util.ruby_command ruby_command = ruby_command spec.executables.each do |executable| next if executable == "bundle" executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) executable_path = executable_path mode = Gem.win_platform? ? "wb:UTF-8" : "w" require "erb" content = if RUBY_VERSION >= "2.6" ERB.new(template, :trim_mode => "-").result(binding) else ERB.new(template, nil, "-").result(binding) end File.write("#{bin_path}/#{executable}", content, :mode => mode, :perm => 0o755) if Gem.win_platform? || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{bin_path}/#{executable}.cmd", prefix + content, :mode => mode) end end end private # the order that the resolver provides is significant, since # dependencies might affect the installation of a gem. # that said, it's a rare situation (other than rake), and parallel # installation is SO MUCH FASTER. so we let people opt in. def install(options) force = options["force"] jobs = installation_parallelization(options) install_in_parallel jobs, options[:standalone], force end def installation_parallelization(options) if jobs = options.delete(:jobs) return jobs end if jobs = Bundler.settings[:jobs] return jobs end # Parallelization has some issues on Windows, so it's not yet the default return 1 if Gem.win_platform? Bundler.settings.processor_count end def load_plugins Bundler.rubygems.load_plugins requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) } path_plugin_files = requested_path_gems.map do |spec| begin Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}") rescue TypeError error_message = "#{spec.name} #{spec.version} has an invalid gemspec" raise Gem::InvalidSpecificationException, error_message end end.flatten Bundler.rubygems.load_plugin_files(path_plugin_files) Bundler.rubygems.load_env_plugins end def ensure_specs_are_compatible! system_ruby = Bundler::RubyVersion.system rubygems_version = Gem::Version.create(Gem::VERSION) @definition.specs.each do |spec| if required_ruby_version = spec.required_ruby_version unless required_ruby_version.satisfied_by?(system_ruby.gem_version) raise InstallError, "#{spec.full_name} requires ruby version #{required_ruby_version}, " \ "which is incompatible with the current version, #{system_ruby}" end end next unless required_rubygems_version = spec.required_rubygems_version unless required_rubygems_version.satisfied_by?(rubygems_version) raise InstallError, "#{spec.full_name} requires rubygems version #{required_rubygems_version}, " \ "which is incompatible with the current version, #{rubygems_version}" end end end def install_in_parallel(size, standalone, force = false) spec_installations = ParallelInstaller.call(self, @definition.specs, size, standalone, force) spec_installations.each do |installation| post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message? end end def create_bundle_path SharedHelpers.filesystem_access(Bundler.bundle_path.to_s) do |p| Bundler.mkdir_p(p) end unless Bundler.bundle_path.exist? rescue Errno::EEXIST raise PathError, "Could not install to path `#{Bundler.bundle_path}` " \ "because a file already exists at that path. Either remove or rename the file so the directory can be created." end # returns whether or not a re-resolve was needed def resolve_if_needed(options) if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file? return false if @definition.nothing_changed? && !@definition.missing_specs? end options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely! true end def lock(opts = {}) @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections]) end end end PKu]Vw3bundler-2.2.24/lib/bundler/fetcher/compact_index.rbnu[# frozen_string_literal: true require_relative "base" require_relative "../worker" module Bundler autoload :CompactIndexClient, File.expand_path("../compact_index_client", __dir__) class Fetcher class CompactIndex < Base def self.compact_index_request(method_name) method = instance_method(method_name) undef_method(method_name) define_method(method_name) do |*args, &blk| begin method.bind(self).call(*args, &blk) rescue NetworkDownError, CompactIndexClient::Updater::MisMatchedChecksumError => e raise HTTPError, e.message rescue AuthenticationRequiredError # Fail since we got a 401 from the server. raise rescue HTTPError => e Bundler.ui.trace(e) nil end end end def specs(gem_names) specs_for_names(gem_names) end compact_index_request :specs def specs_for_names(gem_names) gem_info = [] complete_gems = [] remaining_gems = gem_names.dup until remaining_gems.empty? log_specs "Looking up gems #{remaining_gems.inspect}" deps = begin parallel_compact_index_client.dependencies(remaining_gems) rescue TooManyRequestsError @bundle_worker.stop if @bundle_worker @bundle_worker = nil # reset it. Not sure if necessary serial_compact_index_client.dependencies(remaining_gems) end next_gems = deps.map {|d| d[3].map(&:first).flatten(1) }.flatten(1).uniq deps.each {|dep| gem_info << dep } complete_gems.concat(deps.map(&:first)).uniq! remaining_gems = next_gems - complete_gems end @bundle_worker.stop if @bundle_worker @bundle_worker = nil # reset it. Not sure if necessary gem_info end def fetch_spec(spec) spec -= [nil, "ruby", ""] contents = compact_index_client.spec(*spec) return nil if contents.nil? contents.unshift(spec.first) contents[3].map! {|d| Gem::Dependency.new(*d) } EndpointSpecification.new(*contents) end compact_index_request :fetch_spec def available? return nil unless SharedHelpers.md5_available? user_home = Bundler.user_home return nil unless user_home.directory? && user_home.writable? # Read info file checksums out of /versions, so we can know if gems are up to date fetch_uri.scheme != "file" && compact_index_client.update_and_parse_checksums! rescue CompactIndexClient::Updater::MisMatchedChecksumError => e Bundler.ui.debug(e.message) nil end compact_index_request :available? def api_fetcher? true end private def compact_index_client @compact_index_client ||= SharedHelpers.filesystem_access(cache_path) do CompactIndexClient.new(cache_path, client_fetcher) end end def parallel_compact_index_client compact_index_client.execution_mode = lambda do |inputs, &blk| func = lambda {|object, _index| blk.call(object) } worker = bundle_worker(func) inputs.each {|input| worker.enq(input) } inputs.map { worker.deq } end compact_index_client end def serial_compact_index_client compact_index_client.sequential_execution_mode! compact_index_client end def bundle_worker(func = nil) @bundle_worker ||= begin worker_name = "Compact Index (#{display_uri.host})" Bundler::Worker.new(Bundler.settings.processor_count, worker_name, func) end @bundle_worker.tap do |worker| worker.instance_variable_set(:@func, func) if func end end def cache_path Bundler.user_cache.join("compact_index", remote.cache_slug) end def client_fetcher ClientFetcher.new(self, Bundler.ui) end ClientFetcher = Struct.new(:fetcher, :ui) do def call(path, headers) fetcher.downloader.fetch(fetcher.fetch_uri + path, headers) rescue NetworkDownError => e raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"] ui.warn "Using the cached data for the new index because of a network error: #{e}" Net::HTTPNotModified.new(nil, nil, nil) end end end end end PKu]L;8 0bundler-2.2.24/lib/bundler/fetcher/dependency.rbnu[# frozen_string_literal: true require_relative "base" require "cgi" module Bundler class Fetcher class Dependency < Base def available? @available ||= fetch_uri.scheme != "file" && downloader.fetch(dependency_api_uri) rescue NetworkDownError => e raise HTTPError, e.message rescue AuthenticationRequiredError # Fail since we got a 401 from the server. raise rescue HTTPError false end def api_fetcher? true end def specs(gem_names, full_dependency_list = [], last_spec_list = []) query_list = gem_names.uniq - full_dependency_list log_specs "Query List: #{query_list.inspect}" return last_spec_list if query_list.empty? spec_list, deps_list = Bundler::Retry.new("dependency api", FAIL_ERRORS).attempts do dependency_specs(query_list) end returned_gems = spec_list.map(&:first).uniq specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list) rescue MarshalError Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over Bundler.ui.debug "could not fetch from the dependency API, trying the full index" nil rescue HTTPError, GemspecError Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over Bundler.ui.debug "could not fetch from the dependency API\nit's suggested to retry using the full index via `bundle install --full-index`" nil end def dependency_specs(gem_names) Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(",")}" gem_list = unmarshalled_dep_gems(gem_names) get_formatted_specs_and_deps(gem_list) end def unmarshalled_dep_gems(gem_names) gem_list = [] gem_names.each_slice(Source::Rubygems::API_REQUEST_SIZE) do |names| marshalled_deps = downloader.fetch(dependency_api_uri(names)).body gem_list.concat(Bundler.load_marshal(marshalled_deps)) end gem_list end def get_formatted_specs_and_deps(gem_list) deps_list = [] spec_list = [] gem_list.each do |s| deps_list.concat(s[:dependencies].map(&:first)) deps = s[:dependencies].map {|n, d| [n, d.split(", ")] } spec_list.push([s[:name], s[:number], s[:platform], deps]) end [spec_list, deps_list] end def dependency_api_uri(gem_names = []) uri = fetch_uri + "api/v1/dependencies" uri.query = "gems=#{CGI.escape(gem_names.sort.join(","))}" if gem_names.any? uri end end end end PKu]*bundler-2.2.24/lib/bundler/fetcher/base.rbnu[# frozen_string_literal: true module Bundler class Fetcher class Base attr_reader :downloader attr_reader :display_uri attr_reader :remote def initialize(downloader, remote, display_uri) raise "Abstract class" if self.class == Base @downloader = downloader @remote = remote @display_uri = display_uri end def remote_uri @remote.uri end def fetch_uri @fetch_uri ||= begin if remote_uri.host == "rubygems.org" uri = remote_uri.dup uri.host = "index.rubygems.org" uri else remote_uri end end end def available? true end def api_fetcher? false end private def log_specs(debug_msg) if Bundler.ui.debug? Bundler.ui.debug debug_msg else Bundler.ui.info ".", false end end end end end PKu],dd+bundler-2.2.24/lib/bundler/fetcher/index.rbnu[# frozen_string_literal: true require_relative "base" module Bundler class Fetcher class Index < Base def specs(_gem_names) Bundler.rubygems.fetch_all_remote_specs(remote) rescue Gem::RemoteFetcher::FetchError => e case e.message when /certificate verify failed/ raise CertificateFailureError.new(display_uri) when /401/ raise BadAuthenticationError, remote_uri if remote_uri.userinfo raise AuthenticationRequiredError, remote_uri when /403/ raise BadAuthenticationError, remote_uri if remote_uri.userinfo raise AuthenticationRequiredError, remote_uri else raise HTTPError, "Could not fetch specs from #{display_uri} due to underlying error <#{e.message}>" end end def fetch_spec(spec) spec -= [nil, "ruby", ""] spec_file_name = "#{spec.join "-"}.gemspec" uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") if uri.scheme == "file" path = Bundler.rubygems.correct_for_windows_path(uri.path) Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(path)) elsif cached_spec_path = gemspec_cached_path(spec_file_name) Bundler.load_gemspec(cached_spec_path) else Bundler.load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) end rescue MarshalError raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ "Your network or your gem server is probably having issues right now." end private # cached gem specification path, if one exists def gemspec_cached_path(spec_file_name) paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } paths.find {|path| File.file? path } end end end end PKu]]Y Y 0bundler-2.2.24/lib/bundler/fetcher/downloader.rbnu[# frozen_string_literal: true module Bundler class Fetcher class Downloader attr_reader :connection attr_reader :redirect_limit def initialize(connection, redirect_limit) @connection = connection @redirect_limit = redirect_limit end def fetch(uri, headers = {}, counter = 0) raise HTTPError, "Too many redirects" if counter >= redirect_limit filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) response = request(uri, headers) Bundler.ui.debug("HTTP #{response.code} #{response.message} #{filtered_uri}") case response when Net::HTTPSuccess, Net::HTTPNotModified response when Net::HTTPRedirection new_uri = Bundler::URI.parse(response["location"]) if new_uri.host == uri.host new_uri.user = uri.user new_uri.password = uri.password end fetch(new_uri, headers, counter + 1) when Net::HTTPRequestedRangeNotSatisfiable new_headers = headers.dup new_headers.delete("Range") new_headers["Accept-Encoding"] = "gzip" fetch(uri, new_headers) when Net::HTTPRequestEntityTooLarge raise FallbackError, response.body when Net::HTTPTooManyRequests raise TooManyRequestsError, response.body when Net::HTTPUnauthorized raise BadAuthenticationError, uri.host if uri.userinfo raise AuthenticationRequiredError, uri.host when Net::HTTPNotFound raise FallbackError, "Net::HTTPNotFound: #{filtered_uri}" else raise HTTPError, "#{response.class}#{": #{response.body}" unless response.body.empty?}" end end def request(uri, headers) validate_uri_scheme!(uri) filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) Bundler.ui.debug "HTTP GET #{filtered_uri}" req = Net::HTTP::Get.new uri.request_uri, headers if uri.user user = CGI.unescape(uri.user) password = uri.password ? CGI.unescape(uri.password) : nil req.basic_auth(user, password) end connection.request(uri, req) rescue NoMethodError => e raise unless ["undefined method", "use_ssl="].all? {|snippet| e.message.include? snippet } raise LoadError.new("cannot load such file -- openssl") rescue OpenSSL::SSL::SSLError raise CertificateFailureError.new(uri) rescue *HTTP_ERRORS => e Bundler.ui.trace e if e.is_a?(SocketError) || e.message =~ /host down:/ raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \ "connection and try again." else raise HTTPError, "Network error while fetching #{filtered_uri}" \ " (#{e})" end end private def validate_uri_scheme!(uri) return if uri.scheme =~ /\Ahttps?\z/ raise InvalidOption, "The request uri `#{uri}` has an invalid scheme (`#{uri.scheme}`). " \ "Did you mean `http` or `https`?" end end end end PKu]+#bundler-2.2.24/lib/bundler/index.rbnu[# frozen_string_literal: true module Bundler class Index include Enumerable def self.build i = new yield i i end attr_reader :specs, :all_specs, :sources protected :specs, :all_specs RUBY = "ruby".freeze NULL = "\0".freeze def initialize @sources = [] @cache = {} @specs = Hash.new {|h, k| h[k] = {} } @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH } end def initialize_copy(o) @sources = o.sources.dup @cache = {} @specs = Hash.new {|h, k| h[k] = {} } @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH } o.specs.each do |name, hash| @specs[name] = hash.dup end o.all_specs.each do |name, array| @all_specs[name] = array.dup end end def inspect "#<#{self.class}:0x#{object_id} sources=#{sources.map(&:inspect)} specs.size=#{specs.size}>" end def empty? each { return false } true end def search_all(name) all_matches = local_search(name) + @all_specs[name] @sources.each do |source| all_matches.concat(source.search_all(name)) end all_matches end # Search this index's specs, and any source indexes that this index knows # about, returning all of the results. def search(query, base = nil) sort_specs(unsorted_search(query, base)) end def unsorted_search(query, base) results = local_search(query, base) seen = results.map(&:full_name).uniq unless @sources.empty? @sources.each do |source| source.unsorted_search(query, base).each do |spec| next if seen.include?(spec.full_name) seen << spec.full_name results << spec end end results end protected :unsorted_search def self.sort_specs(specs) specs.sort_by do |s| platform_string = s.platform.to_s [s.version, platform_string == RUBY ? NULL : platform_string] end end def sort_specs(specs) self.class.sort_specs(specs) end def local_search(query, base = nil) case query when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query) when String then specs_by_name(query) when Gem::Dependency then search_by_dependency(query, base) when DepProxy then search_by_dependency(query.dep, base) else raise "You can't search for a #{query.inspect}." end end alias_method :[], :search def <<(spec) @specs[spec.name][spec.full_name] = spec spec end def each(&blk) return enum_for(:each) unless blk specs.values.each do |spec_sets| spec_sets.values.each(&blk) end sources.each {|s| s.each(&blk) } self end def spec_names names = specs.keys + sources.map(&:spec_names) names.uniq! names end def unmet_dependency_names dependency_names.select do |name| search(name).empty? end end def dependency_names names = [] each do |spec| spec.dependencies.each do |dep| next if dep.type == :development names << dep.name end end names.uniq end def use(other, override_dupes = false) return unless other other.each do |s| if (dupes = search_by_spec(s)) && !dupes.empty? # safe to << since it's a new array when it has contents @all_specs[s.name] = dupes << s next unless override_dupes end self << s end self end def size @sources.inject(@specs.size) do |size, source| size += source.size end end # Whether all the specs in self are in other # TODO: rename to #include? def ==(other) all? do |spec| other_spec = other[spec].first other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source end end def dependencies_eql?(spec, other_spec) deps = spec.dependencies.select {|d| d.type != :development } other_deps = other_spec.dependencies.select {|d| d.type != :development } deps.sort == other_deps.sort end def add_source(index) raise ArgumentError, "Source must be an index, not #{index.class}" unless index.is_a?(Index) @sources << index @sources.uniq! # need to use uniq! here instead of checking for the item before adding end private def specs_by_name(name) @specs[name].values end def search_by_dependency(dependency, base = nil) @cache[base || false] ||= {} @cache[base || false][dependency] ||= begin specs = specs_by_name(dependency.name) specs += base if base found = specs.select do |spec| next true if spec.source.is_a?(Source::Gemspec) if base # allow all platforms when searching from a lockfile dependency.matches_spec?(spec) else dependency.matches_spec?(spec) && Gem::Platform.match_spec?(spec) end end found end end EMPTY_SEARCH = [].freeze def search_by_spec(spec) spec = @specs[spec.name][spec.full_name] spec ? [spec] : EMPTY_SEARCH end end end PKu]PCm*bundler-2.2.24/lib/bundler/ruby_version.rbnu[# frozen_string_literal: true module Bundler class RubyVersion attr_reader :versions, :patchlevel, :engine, :engine_versions, :gem_version, :engine_gem_version def initialize(versions, patchlevel, engine, engine_version) # The parameters to this method must satisfy the # following constraints, which are verified in # the DSL: # # * If an engine is specified, an engine version # must also be specified # * If an engine version is specified, an engine # must also be specified # * If the engine is "ruby", the engine version # must not be specified, or the engine version # specified must match the version. @versions = Array(versions).map do |v| op, v = Gem::Requirement.parse(v) op == "=" ? v.to_s : "#{op} #{v}" end @gem_version = Gem::Requirement.create(@versions.first).requirements.first.last @input_engine = engine && engine.to_s @engine = engine && engine.to_s || "ruby" @engine_versions = (engine_version && Array(engine_version)) || @versions @engine_gem_version = Gem::Requirement.create(@engine_versions.first).requirements.first.last @patchlevel = patchlevel end def to_s(versions = self.versions) output = String.new("ruby #{versions_string(versions)}") output << "p#{patchlevel}" if patchlevel output << " (#{engine} #{versions_string(engine_versions)})" unless engine == "ruby" output end # @private PATTERN = / ruby\s ([\d.]+) # ruby version (?:p(-?\d+))? # optional patchlevel (?:\s\((\S+)\s(.+)\))? # optional engine info /xo.freeze # Returns a RubyVersion from the given string. # @param [String] the version string to match. # @return [RubyVersion,Nil] The version if the string is a valid RubyVersion # description, and nil otherwise. def self.from_string(string) new($1, $2, $3, $4) if string =~ PATTERN end def single_version_string to_s(gem_version) end def ==(other) versions == other.versions && engine == other.engine && engine_versions == other.engine_versions && patchlevel == other.patchlevel end def host @host ||= [ RbConfig::CONFIG["host_cpu"], RbConfig::CONFIG["host_vendor"], RbConfig::CONFIG["host_os"], ].join("-") end # Returns a tuple of these things: # [diff, this, other] # The priority of attributes are # 1. engine # 2. ruby_version # 3. engine_version def diff(other) raise ArgumentError, "Can only diff with a RubyVersion, not a #{other.class}" unless other.is_a?(RubyVersion) if engine != other.engine && @input_engine [:engine, engine, other.engine] elsif versions.empty? || !matches?(versions, other.gem_version) [:version, versions_string(versions), versions_string(other.versions)] elsif @input_engine && !matches?(engine_versions, other.engine_gem_version) [:engine_version, versions_string(engine_versions), versions_string(other.engine_versions)] elsif patchlevel && (!patchlevel.is_a?(String) || !other.patchlevel.is_a?(String) || !matches?(patchlevel, other.patchlevel)) [:patchlevel, patchlevel, other.patchlevel] end end def versions_string(versions) Array(versions).join(", ") end def self.system ruby_engine = RUBY_ENGINE.dup ruby_version = ENV.fetch("BUNDLER_SPEC_RUBY_VERSION") { RUBY_VERSION }.dup ruby_engine_version = RUBY_ENGINE_VERSION.dup patchlevel = RUBY_PATCHLEVEL.to_s @ruby_version ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version) end def to_gem_version_with_patchlevel @gem_version_with_patch ||= begin Gem::Version.create("#{@gem_version}.#{@patchlevel}") rescue ArgumentError @gem_version end end def exact? return @exact if defined?(@exact) @exact = versions.all? {|v| Gem::Requirement.create(v).exact? } end private def matches?(requirements, version) # Handles RUBY_PATCHLEVEL of -1 for instances like ruby-head return requirements == version if requirements.to_s == "-1" || version.to_s == "-1" Array(requirements).all? do |requirement| Gem::Requirement.create(requirement).satisfied_by?(Gem::Version.create(version)) end end end end PKu]ؤ-""(bundler-2.2.24/lib/bundler/source_map.rbnu[# frozen_string_literal: true module Bundler class SourceMap attr_reader :sources, :dependencies def initialize(sources, dependencies) @sources = sources @dependencies = dependencies end def pinned_spec_names(skip = nil) direct_requirements.reject {|_, source| source == skip }.keys end def all_requirements requirements = direct_requirements.dup unmet_deps = sources.non_default_explicit_sources.map do |source| (source.spec_names - pinned_spec_names).each do |indirect_dependency_name| previous_source = requirements[indirect_dependency_name] if previous_source.nil? requirements[indirect_dependency_name] = source else no_ambiguous_sources = Bundler.feature_flag.bundler_3_mode? msg = ["The gem '#{indirect_dependency_name}' was found in multiple relevant sources."] msg.concat [previous_source, source].map {|s| " * #{s}" }.sort msg << "You #{no_ambiguous_sources ? :must : :should} add this gem to the source block for the source you wish it to be installed from." msg = msg.join("\n") raise SecurityError, msg if no_ambiguous_sources Bundler.ui.warn "Warning: #{msg}" end end source.unmet_deps end sources.default_source.add_dependency_names(unmet_deps.flatten - requirements.keys) requirements end def direct_requirements @direct_requirements ||= begin requirements = {} default = sources.default_source dependencies.each do |dep| dep_source = dep.source || default dep_source.add_dependency_names(dep.name) requirements[dep.name] = dep_source end requirements end end end end PKu]0*bundler-2.2.24/lib/bundler/rubygems_ext.rbnu[# frozen_string_literal: true require "pathname" require "rubygems/specification" # Possible use in Gem::Specification#source below and require # shouldn't be deferred. require "rubygems/source" require_relative "match_platform" module Gem class Specification attr_accessor :remote, :location, :relative_loaded_from remove_method :source attr_writer :source def source (defined?(@source) && @source) || Gem::Source::Installed.new end alias_method :rg_full_gem_path, :full_gem_path alias_method :rg_loaded_from, :loaded_from def full_gem_path # this cannot check source.is_a?(Bundler::Plugin::API::Source) # because that _could_ trip the autoload, and if there are unresolved # gems at that time, this method could be called inside another require, # thus raising with that constant being undefined. Better to check a method if source.respond_to?(:path) || (source.respond_to?(:bundler_plugin_api_source?) && source.bundler_plugin_api_source?) Pathname.new(loaded_from).dirname.expand_path(source.root).to_s.tap{|x| x.untaint if RUBY_VERSION < "2.7" } else rg_full_gem_path end end def loaded_from if relative_loaded_from source.path.join(relative_loaded_from).to_s else rg_loaded_from end end def load_paths full_require_paths end alias_method :rg_extension_dir, :extension_dir def extension_dir @bundler_extension_dir ||= if source.respond_to?(:extension_dir_name) unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-") File.expand_path(File.join(extensions_dir, unique_extension_dir)) else rg_extension_dir end end remove_method :gem_dir if instance_methods(false).include?(:gem_dir) def gem_dir full_gem_path end def groups @groups ||= [] end def git_version return unless loaded_from && source.is_a?(Bundler::Source::Git) " #{source.revision[0..6]}" end def to_gemfile(path = nil) gemfile = String.new("source 'https://rubygems.org'\n") gemfile << dependencies_to_gemfile(nondevelopment_dependencies) unless development_dependencies.empty? gemfile << "\n" gemfile << dependencies_to_gemfile(development_dependencies, :development) end gemfile end def nondevelopment_dependencies dependencies - development_dependencies end private def dependencies_to_gemfile(dependencies, group = nil) gemfile = String.new if dependencies.any? gemfile << "group :#{group} do\n" if group dependencies.each do |dependency| gemfile << " " if group gemfile << %(gem "#{dependency.name}") req = dependency.requirements_list.first gemfile << %(, "#{req}") if req gemfile << "\n" end gemfile << "end\n" if group end gemfile end end class Dependency attr_accessor :source, :groups alias_method :eql?, :== def encode_with(coder) to_yaml_properties.each do |ivar| coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar) end end def to_yaml_properties instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) } end def to_lock out = String.new(" #{name}") unless requirement.none? reqs = requirement.requirements.map {|o, v| "#{o} #{v}" }.sort.reverse out << " (#{reqs.join(", ")})" end out end end # comparison is done order independently since rubygems 3.2.0.rc.2 unless Gem::Requirement.new("> 1", "< 2") == Gem::Requirement.new("< 2", "> 1") class Requirement module OrderIndependentComparison def ==(other) return unless Gem::Requirement === other if _requirements_sorted? && other._requirements_sorted? super else _with_sorted_requirements == other._with_sorted_requirements end end protected def _requirements_sorted? return @_are_requirements_sorted if defined?(@_are_requirements_sorted) strings = as_list @_are_requirements_sorted = strings == strings.sort end def _with_sorted_requirements @_with_sorted_requirements ||= _requirements_sorted? ? self : self.class.new(as_list.sort) end end prepend OrderIndependentComparison end end if Gem::Requirement.new("~> 2.0").hash == Gem::Requirement.new("~> 2.0.0").hash class Requirement module CorrectHashForLambdaOperator def hash if requirements.any? {|r| r.first == "~>" } requirements.map {|r| r.first == "~>" ? [r[0], r[1].to_s] : r }.sort.hash else super end end end prepend CorrectHashForLambdaOperator end end require "rubygems/platform" class Platform JAVA = Gem::Platform.new("java") unless defined?(JAVA) MSWIN = Gem::Platform.new("mswin32") unless defined?(MSWIN) MSWIN64 = Gem::Platform.new("mswin64") unless defined?(MSWIN64) MINGW = Gem::Platform.new("x86-mingw32") unless defined?(MINGW) X64_MINGW = Gem::Platform.new("x64-mingw32") unless defined?(X64_MINGW) end Platform.singleton_class.module_eval do unless Platform.singleton_methods.include?(:match_spec?) def match_spec?(spec) match_gem?(spec.platform, spec.name) end def match_gem?(platform, gem_name) match_platforms?(platform, Gem.platforms) end private def match_platforms?(platform, platforms) platforms.any? do |local_platform| platform.nil? || local_platform == platform || (local_platform != Gem::Platform::RUBY && local_platform =~ platform) end end end end require "rubygems/util" Util.singleton_class.module_eval do if Util.singleton_methods.include?(:glob_files_in_dir) # since 3.0.0.beta.2 remove_method :glob_files_in_dir end def glob_files_in_dir(glob, base_path) if RUBY_VERSION >= "2.5" Dir.glob(glob, :base => base_path).map! {|f| File.expand_path(f, base_path) } else Dir.glob(File.join(base_path.to_s.gsub(/[\[\]]/, '\\\\\\&'), glob)).map! {|f| File.expand_path(f) } end end end end module Gem class Specification include ::Bundler::MatchPlatform end end PKu]i *  !bundler-2.2.24/lib/bundler/env.rbnu[# frozen_string_literal: true require_relative "rubygems_integration" require_relative "source/git/git_proxy" module Bundler class Env def self.write(io) io.write report end def self.report(options = {}) print_gemfile = options.delete(:print_gemfile) { true } print_gemspecs = options.delete(:print_gemspecs) { true } out = String.new append_formatted_table("Environment", environment, out) append_formatted_table("Bundler Build Metadata", BuildMetadata.to_h, out) unless Bundler.settings.all.empty? out << "\n## Bundler settings\n\n```\n" Bundler.settings.all.each do |setting| out << setting << "\n" Bundler.settings.pretty_values_for(setting).each do |line| out << " " << line << "\n" end end out << "```\n" end return out unless SharedHelpers.in_bundle? if print_gemfile gemfiles = [Bundler.default_gemfile] begin gemfiles = Bundler.definition.gemfiles rescue GemfileNotFound nil end out << "\n## Gemfile\n" gemfiles.each do |gemfile| out << "\n### #{Pathname.new(gemfile).relative_path_from(SharedHelpers.pwd)}\n\n" out << "```ruby\n" << read_file(gemfile).chomp << "\n```\n" end out << "\n### #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}\n\n" out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n" end if print_gemspecs dsl = Dsl.new.tap {|d| d.eval_gemfile(Bundler.default_gemfile) } out << "\n## Gemspecs\n" unless dsl.gemspecs.empty? dsl.gemspecs.each do |gs| out << "\n### #{File.basename(gs.loaded_from)}" out << "\n\n```ruby\n" << read_file(gs.loaded_from).chomp << "\n```\n" end end out end def self.read_file(filename) Bundler.read_file(filename.to_s).strip rescue Errno::ENOENT "" rescue RuntimeError => e "#{e.class}: #{e.message}" end def self.ruby_version str = String.new(RUBY_VERSION) str << "p#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL str << " (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{RUBY_PLATFORM}]" end def self.git_version Bundler::Source::Git::GitProxy.new(nil, nil, nil).full_version rescue Bundler::Source::Git::GitNotInstalledError "not installed" end def self.version_of(script) return "not installed" unless Bundler.which(script) `#{script} --version`.chomp end def self.chruby_version return "not installed" unless Bundler.which("chruby-exec") `chruby-exec -- chruby --version`. sub(/.*^chruby: (#{Gem::Version::VERSION_PATTERN}).*/m, '\1') end def self.environment out = [] out << ["Bundler", Bundler::VERSION] out << [" Platforms", Gem.platforms.join(", ")] out << ["Ruby", ruby_version] out << [" Full Path", Gem.ruby] out << [" Config Dir", Pathname.new(Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE).dirname] out << ["RubyGems", Gem::VERSION] out << [" Gem Home", Gem.dir] out << [" Gem Path", Gem.path.join(File::PATH_SEPARATOR)] out << [" User Home", Gem.user_home] out << [" User Path", Gem.user_dir] out << [" Bin Dir", Gem.bindir] if defined?(OpenSSL::SSL) out << ["OpenSSL"] out << [" Compiled", OpenSSL::OPENSSL_VERSION] if defined?(OpenSSL::OPENSSL_VERSION) out << [" Loaded", OpenSSL::OPENSSL_LIBRARY_VERSION] if defined?(OpenSSL::OPENSSL_LIBRARY_VERSION) out << [" Cert File", OpenSSL::X509::DEFAULT_CERT_FILE] if defined?(OpenSSL::X509::DEFAULT_CERT_FILE) out << [" Cert Dir", OpenSSL::X509::DEFAULT_CERT_DIR] if defined?(OpenSSL::X509::DEFAULT_CERT_DIR) end out << ["Tools"] out << [" Git", git_version] out << [" RVM", ENV.fetch("rvm_version") { version_of("rvm") }] out << [" rbenv", version_of("rbenv")] out << [" chruby", chruby_version] %w[rubygems-bundler open_gem].each do |name| specs = Bundler.rubygems.find_name(name) out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty? end if (exe = caller.last.split(":").first) && exe =~ %r{(exe|bin)/bundler?\z} shebang = File.read(exe).lines.first shebang.sub!(/^#!\s*/, "") unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby") out << ["Gem.ruby", Gem.ruby] out << ["bundle #!", shebang] end end out end def self.append_formatted_table(title, pairs, out) return if pairs.empty? out << "\n" unless out.empty? out << "## #{title}\n\n```\n" ljust = pairs.map {|k, _v| k.to_s.length }.max pairs.each do |k, v| out << "#{k.to_s.ljust(ljust)} #{v}\n" end out << "```\n" end private_class_method :read_file, :ruby_version, :git_version, :append_formatted_table, :version_of, :chruby_version end end PKu]Piy@ @ 1bundler-2.2.24/lib/bundler/resolver/spec_group.rbnu[# frozen_string_literal: true module Bundler class Resolver class SpecGroup attr_accessor :name, :version, :source attr_accessor :activated_platforms def self.create_for(specs, all_platforms, specific_platform) specific_platform_specs = specs[specific_platform] return unless specific_platform_specs.any? platforms = all_platforms.select {|p| specs[p].any? } new(specific_platform_specs.first, specs, platforms) end def initialize(exemplary_spec, specs, relevant_platforms) @exemplary_spec = exemplary_spec @name = exemplary_spec.name @version = exemplary_spec.version @source = exemplary_spec.source @activated_platforms = relevant_platforms @dependencies = Hash.new do |dependencies, platforms| dependencies[platforms] = dependencies_for(platforms) end @specs = specs end def to_specs activated_platforms.map do |p| specs = @specs[p] next unless specs.any? specs.map do |s| lazy_spec = LazySpecification.new(name, version, s.platform, source) lazy_spec.dependencies.replace s.dependencies lazy_spec end end.flatten.compact.uniq end def to_s activated_platforms_string = sorted_activated_platforms.join(", ") "#{name} (#{version}) (#{activated_platforms_string})" end def dependencies_for_activated_platforms @dependencies[activated_platforms] end def ==(other) return unless other.is_a?(SpecGroup) name == other.name && version == other.version && sorted_activated_platforms == other.sorted_activated_platforms && source == other.source end def eql?(other) return unless other.is_a?(SpecGroup) name.eql?(other.name) && version.eql?(other.version) && sorted_activated_platforms.eql?(other.sorted_activated_platforms) && source.eql?(other.source) end def hash name.hash ^ version.hash ^ sorted_activated_platforms.hash ^ source.hash end protected def sorted_activated_platforms activated_platforms.sort_by(&:to_s) end private def dependencies_for(platforms) platforms.map do |platform| __dependencies(platform) + metadata_dependencies(platform) end.flatten end def __dependencies(platform) dependencies = [] @specs[platform].first.dependencies.each do |dep| next if dep.type == :development dependencies << DepProxy.get_proxy(dep, platform) end dependencies end def metadata_dependencies(platform) spec = @specs[platform].first return [] unless spec.is_a?(Gem::Specification) dependencies = [] if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none? dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform) end if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none? dependencies << DepProxy.get_proxy(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform) end dependencies end end end end PKu]B$hHH$bundler-2.2.24/lib/bundler/mirror.rbnu[# frozen_string_literal: true require "socket" module Bundler class Settings # Class used to build the mirror set and then find a mirror for a given URI # # @param prober [Prober object, nil] by default a TCPSocketProbe, this object # will be used to probe the mirror address to validate that the mirror replies. class Mirrors def initialize(prober = nil) @all = Mirror.new @prober = prober || TCPSocketProbe.new @mirrors = {} end # Returns a mirror for the given uri. # # Depending on the uri having a valid mirror or not, it may be a # mirror that points to the provided uri def for(uri) if @all.validate!(@prober).valid? @all else fetch_valid_mirror_for(Settings.normalize_uri(uri)) end end def each @mirrors.each do |k, v| yield k, v.uri.to_s end end def parse(key, value) config = MirrorConfig.new(key, value) mirror = if config.all? @all else @mirrors[config.uri] ||= Mirror.new end config.update_mirror(mirror) end private def fetch_valid_mirror_for(uri) downcased = uri.to_s.downcase mirror = @mirrors[downcased] || @mirrors[Bundler::URI(downcased).host] || Mirror.new(uri) mirror.validate!(@prober) mirror = Mirror.new(uri) unless mirror.valid? mirror end end # A mirror # # Contains both the uri that should be used as a mirror and the # fallback timeout which will be used for probing if the mirror # replies on time or not. class Mirror DEFAULT_FALLBACK_TIMEOUT = 0.1 attr_reader :uri, :fallback_timeout def initialize(uri = nil, fallback_timeout = 0) self.uri = uri self.fallback_timeout = fallback_timeout @valid = nil end def uri=(uri) @uri = if uri.nil? nil else Bundler::URI(uri.to_s) end @valid = nil end def fallback_timeout=(timeout) case timeout when true, "true" @fallback_timeout = DEFAULT_FALLBACK_TIMEOUT when false, "false" @fallback_timeout = 0 else @fallback_timeout = timeout.to_i end @valid = nil end def ==(other) !other.nil? && uri == other.uri && fallback_timeout == other.fallback_timeout end def valid? return false if @uri.nil? return @valid unless @valid.nil? false end def validate!(probe = nil) @valid = false if uri.nil? if @valid.nil? @valid = fallback_timeout == 0 || (probe || TCPSocketProbe.new).replies?(self) end self end end # Class used to parse one configuration line # # Gets the configuration line and the value. # This object provides a `update_mirror` method # used to setup the given mirror value. class MirrorConfig attr_accessor :uri, :value def initialize(config_line, value) uri, fallback = config_line.match(%r{\Amirror\.(all|.+?)(\.fallback_timeout)?\/?\z}).captures @fallback = !fallback.nil? @all = false if uri == "all" @all = true else @uri = Bundler::URI(uri).absolute? ? Settings.normalize_uri(uri) : uri end @value = value end def all? @all end def update_mirror(mirror) if @fallback mirror.fallback_timeout = @value else mirror.uri = Settings.normalize_uri(@value) end end end # Class used for probing TCP availability for a given mirror. class TCPSocketProbe def replies?(mirror) MirrorSockets.new(mirror).any? do |socket, address, timeout| begin socket.connect_nonblock(address) rescue Errno::EINPROGRESS wait_for_writtable_socket(socket, address, timeout) rescue RuntimeError # Connection failed somehow, again false end end end private def wait_for_writtable_socket(socket, address, timeout) if IO.select(nil, [socket], nil, timeout) probe_writtable_socket(socket, address) else # TCP Handshake timed out, or there is something dropping packets false end end def probe_writtable_socket(socket, address) socket.connect_nonblock(address) rescue Errno::EISCONN true rescue StandardError # Connection failed false end end end # Class used to build the list of sockets that correspond to # a given mirror. # # One mirror may correspond to many different addresses, both # because of it having many dns entries or because # the network interface is both ipv4 and ipv5 class MirrorSockets def initialize(mirror) @timeout = mirror.fallback_timeout @addresses = Socket.getaddrinfo(mirror.uri.host, mirror.uri.port).map do |address| SocketAddress.new(address[0], address[3], address[1]) end end def any? @addresses.any? do |address| socket = Socket.new(Socket.const_get(address.type), Socket::SOCK_STREAM, 0) socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) value = yield socket, address.to_socket_address, @timeout socket.close unless socket.closed? value end end end # Socket address builder. # # Given a socket type, a host and a port, # provides a method to build sockaddr string class SocketAddress attr_reader :type, :host, :port def initialize(type, host, port) @type = type @host = host @port = port end def to_socket_address Socket.pack_sockaddr_in(@port, @host) end end end PKu]"x(bundler-2.2.24/lib/bundler/plugin/dsl.rbnu[# frozen_string_literal: true module Bundler module Plugin # Dsl to parse the Gemfile looking for plugins to install class DSL < Bundler::Dsl class PluginGemfileError < PluginError; end alias_method :_gem, :gem # To use for plugin installation as gem # So that we don't have to override all there methods to dummy ones # explicitly. # They will be handled by method_missing [:gemspec, :gem, :install_if, :platforms, :env].each {|m| undef_method m } # This lists the plugins that was added automatically and not specified by # the user. # # When we encounter :type attribute with a source block, we add a plugin # by name bundler-source- to list of plugins to be installed. # # These plugins are optional and are not installed when there is conflict # with any other plugin. attr_reader :inferred_plugins def initialize super @sources = Plugin::SourceList.new @inferred_plugins = [] # The source plugins inferred from :type end def plugin(name, *args) _gem(name, *args) end def method_missing(name, *args) raise PluginGemfileError, "Undefined local variable or method `#{name}' for Gemfile" unless Bundler::Dsl.method_defined? name end def source(source, *args, &blk) options = args.last.is_a?(Hash) ? args.pop.dup : {} options = normalize_hash(options) return super unless options.key?("type") plugin_name = "bundler-source-#{options["type"]}" return if @dependencies.any? {|d| d.name == plugin_name } plugin(plugin_name) @inferred_plugins << plugin_name end end end end PKu]ӃnDD+bundler-2.2.24/lib/bundler/plugin/events.rbnu[# frozen_string_literal: true module Bundler module Plugin module Events def self.define(const, event) const = const.to_sym.freeze if const_defined?(const) && const_get(const) != event raise ArgumentError, "Attempting to reassign #{const} to a different value" end const_set(const, event) unless const_defined?(const) @events ||= {} @events[event] = const end private_class_method :define def self.reset @events.each_value do |const| remove_const(const) end @events = nil end private_class_method :reset # Check if an event has been defined # @param event [String] An event to check # @return [Boolean] A boolean indicating if the event has been defined def self.defined_event?(event) @events ||= {} @events.key?(event) end # @!parse # A hook called before each individual gem is installed # Includes a Bundler::ParallelInstaller::SpecInstallation. # No state, error, post_install_message will be present as nothing has installed yet # GEM_BEFORE_INSTALL = "before-install" define :GEM_BEFORE_INSTALL, "before-install" # @!parse # A hook called after each individual gem is installed # Includes a Bundler::ParallelInstaller::SpecInstallation. # - If state is failed, an error will be present. # - If state is success, a post_install_message may be present. # GEM_AFTER_INSTALL = "after-install" define :GEM_AFTER_INSTALL, "after-install" # @!parse # A hook called before any gems install # Includes an Array of Bundler::Dependency objects # GEM_BEFORE_INSTALL_ALL = "before-install-all" define :GEM_BEFORE_INSTALL_ALL, "before-install-all" # @!parse # A hook called after any gems install # Includes an Array of Bundler::Dependency objects # GEM_AFTER_INSTALL_ALL = "after-install-all" define :GEM_AFTER_INSTALL_ALL, "after-install-all" end end end PKu]6P P (bundler-2.2.24/lib/bundler/plugin/api.rbnu[# frozen_string_literal: true module Bundler # This is the interfacing class represents the API that we intend to provide # the plugins to use. # # For plugins to be independent of the Bundler internals they shall limit their # interactions to methods of this class only. This will save them from breaking # when some internal change. # # Currently we are delegating the methods defined in Bundler class to # itself. So, this class acts as a buffer. # # If there is some change in the Bundler class that is incompatible to its # previous behavior or if otherwise desired, we can reimplement(or implement) # the method to preserve compatibility. # # To use this, either the class can inherit this class or use it directly. # For example of both types of use, refer the file `spec/plugins/command.rb` # # To use it without inheriting, you will have to create an object of this # to use the functions (except for declaration functions like command, source, # and hooks). module Plugin class API autoload :Source, File.expand_path("api/source", __dir__) # The plugins should declare that they handle a command through this helper. # # @param [String] command being handled by them # @param [Class] (optional) class that handles the command. If not # provided, the `self` class will be used. def self.command(command, cls = self) Plugin.add_command command, cls end # The plugins should declare that they provide a installation source # through this helper. # # @param [String] the source type they provide # @param [Class] (optional) class that handles the source. If not # provided, the `self` class will be used. def self.source(source, cls = self) cls.send :include, Bundler::Plugin::API::Source Plugin.add_source source, cls end def self.hook(event, &block) Plugin.add_hook(event, &block) end # The cache dir to be used by the plugins for storage # # @return [Pathname] path of the cache dir def cache_dir Plugin.cache.join("plugins") end # A tmp dir to be used by plugins # Accepts names that get concatenated as suffix # # @return [Pathname] object for the new directory created def tmp(*names) Bundler.tmp(["plugin", *names].join("-")) end def method_missing(name, *args, &blk) return Bundler.send(name, *args, &blk) if Bundler.respond_to?(name) return SharedHelpers.send(name, *args, &blk) if SharedHelpers.respond_to?(name) super end def respond_to_missing?(name, include_private = false) SharedHelpers.respond_to?(name, include_private) || Bundler.respond_to?(name, include_private) || super end end end end PKu] g../bundler-2.2.24/lib/bundler/plugin/api/source.rbnu[# frozen_string_literal: true module Bundler module Plugin class API # This class provides the base to build source plugins # All the method here are required to build a source plugin (except # `uri_hash`, `gem_install_dir`; they are helpers). # # Defaults for methods, where ever possible are provided which is # expected to work. But, all source plugins have to override # `fetch_gemspec_files` and `install`. Defaults are also not provided for # `remote!`, `cache!` and `unlock!`. # # The defaults shall work for most situations but nevertheless they can # be (preferably should be) overridden as per the plugins' needs safely # (as long as they behave as expected). # On overriding `initialize` you should call super first. # # If required plugin should override `hash`, `==` and `eql?` methods to be # able to match objects representing same sources, but may be created in # different situation (like form gemfile and lockfile). The default ones # checks only for class and uri, but elaborate source plugins may need # more comparisons (e.g. git checking on branch or tag). # # @!attribute [r] uri # @return [String] the remote specified with `source` block in Gemfile # # @!attribute [r] options # @return [String] options passed during initialization (either from # lockfile or Gemfile) # # @!attribute [r] name # @return [String] name that can be used to uniquely identify a source # # @!attribute [rw] dependency_names # @return [Array] Names of dependencies that the source should # try to resolve. It is not necessary to use this list internally. This # is present to be compatible with `Definition` and is used by # rubygems source. module Source attr_reader :uri, :options, :name attr_accessor :dependency_names def initialize(opts) @options = opts @dependency_names = [] @uri = opts["uri"] @type = opts["type"] @name = opts["name"] || "#{@type} at #{@uri}" end # This is used by the default `spec` method to constructs the # Specification objects for the gems and versions that can be installed # by this source plugin. # # Note: If the spec method is overridden, this function is not necessary # # @return [Array] paths of the gemspec files for gems that can # be installed def fetch_gemspec_files [] end # Options to be saved in the lockfile so that the source plugin is able # to check out same version of gem later. # # There options are passed when the source plugin is created from the # lock file. # # @return [Hash] def options_to_lock {} end # Install the gem specified by the spec at appropriate path. # `install_path` provides a sufficient default, if the source can only # satisfy one gem, but is not binding. # # @return [String] post installation message (if any) def install(spec, opts) raise MalformattedPlugin, "Source plugins need to override the install method." end # It builds extensions, generates bins and installs them for the spec # provided. # # It depends on `spec.loaded_from` to get full_gem_path. The source # plugins should set that. # # It should be called in `install` after the plugin is done placing the # gem at correct install location. # # It also runs Gem hooks `pre_install`, `post_build` and `post_install` # # Note: Do not override if you don't know what you are doing. def post_install(spec, disable_exts = false) opts = { :env_shebang => false, :disable_extensions => disable_exts } installer = Bundler::Source::Path::Installer.new(spec, opts) installer.post_install end # A default installation path to install a single gem. If the source # servers multiple gems, it's not of much use and the source should one # of its own. def install_path @install_path ||= begin base_name = File.basename(Bundler::URI.parse(uri).normalize.path) gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") end end # Parses the gemspec files to find the specs for the gems that can be # satisfied by the source. # # Few important points to keep in mind: # - If the gems are not installed then it shall return specs for all # the gems it can satisfy # - If gem is installed (that is to be detected by the plugin itself) # then it shall return at least the specs that are installed. # - The `loaded_from` for each of the specs shall be correct (it is # used to find the load path) # # @return [Bundler::Index] index containing the specs def specs files = fetch_gemspec_files Bundler::Index.build do |index| files.each do |file| next unless spec = Bundler.load_gemspec(file) Bundler.rubygems.set_installed_by_version(spec) spec.source = self Bundler.rubygems.validate(spec) index << spec end end end # Set internal representation to fetch the gems/specs locally. # # When this is called, the source should try to fetch the specs and # install from the local system. def local! end # Set internal representation to fetch the gems/specs from remote. # # When this is called, the source should try to fetch the specs and # install from remote path. def remote! end # Set internal representation to fetch the gems/specs from app cache. # # When this is called, the source should try to fetch the specs and # install from the path provided by `app_cache_path`. def cached! end # This is called to update the spec and installation. # # If the source plugin is loaded from lockfile or otherwise, it shall # refresh the cache/specs (e.g. git sources can make a fresh clone). def unlock! end # Name of directory where plugin the is expected to cache the gems when # #cache is called. # # Also this name is matched against the directories in cache for pruning # # This is used by `app_cache_path` def app_cache_dirname base_name = File.basename(Bundler::URI.parse(uri).normalize.path) "#{base_name}-#{uri_hash}" end # This method is called while caching to save copy of the gems that the # source can resolve to path provided by `app_cache_app`so that they can # be reinstalled from the cache without querying the remote (i.e. an # alternative to remote) # # This is stored with the app and source plugins should try to provide # specs and install only from this cache when `cached!` is called. # # This cache is different from the internal caching that can be done # at sub paths of `cache_path` (from API). This can be though as caching # by bundler. def cache(spec, custom_path = nil) new_cache_path = app_cache_path(custom_path) FileUtils.rm_rf(new_cache_path) FileUtils.cp_r(install_path, new_cache_path) FileUtils.touch(app_cache_path.join(".bundlecache")) end # This shall check if two source object represent the same source. # # The comparison shall take place only on the attribute that can be # inferred from the options passed from Gemfile and not on attributes # that are used to pin down the gem to specific version (e.g. Git # sources should compare on branch and tag but not on commit hash) # # The sources objects are constructed from Gemfile as well as from # lockfile. To converge the sources, it is necessary that they match. # # The same applies for `eql?` and `hash` def ==(other) other.is_a?(self.class) && uri == other.uri end # When overriding `eql?` please preserve the behaviour as mentioned in # docstring for `==` method. alias_method :eql?, :== # When overriding `hash` please preserve the behaviour as mentioned in # docstring for `==` method, i.e. two methods equal by above comparison # should have same hash. def hash [self.class, uri].hash end # A helper method, not necessary if not used internally. def installed? File.directory?(install_path) end # The full path where the plugin should cache the gem so that it can be # installed latter. # # Note: Do not override if you don't know what you are doing. def app_cache_path(custom_path = nil) @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) end # Used by definition. # # Note: Do not override if you don't know what you are doing. def unmet_deps specs.unmet_dependency_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def spec_names specs.spec_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def add_dependency_names(names) @dependencies |= Array(names) end # Note: Do not override if you don't know what you are doing. def can_lock?(spec) spec.source == self end # Generates the content to be entered into the lockfile. # Saves type and remote and also calls to `options_to_lock`. # # Plugin should use `options_to_lock` to save information in lockfile # and not override this. # # Note: Do not override if you don't know what you are doing. def to_lock out = String.new("#{LockfileParser::PLUGIN}\n") out << " remote: #{@uri}\n" out << " type: #{@type}\n" options_to_lock.each do |opt, value| out << " #{opt}: #{value}\n" end out << " specs:\n" end def to_s "plugin source for #{@type} with uri #{@uri}" end # Note: Do not override if you don't know what you are doing. def include?(other) other == self end def uri_hash SharedHelpers.digest(:SHA1).hexdigest(uri) end # Note: Do not override if you don't know what you are doing. def gem_install_dir Bundler.install_path end # It is used to obtain the full_gem_path. # # spec's loaded_from path is expanded against this to get full_gem_path # # Note: Do not override if you don't know what you are doing. def root Bundler.root end # @private # Returns true def bundler_plugin_api_source? true end # @private # This API on source might not be stable, and for now we expect plugins # to download all specs in `#specs`, so we implement the method for # compatibility purposes and leave it undocumented (and don't support) # overriding it) def double_check_for(*); end end end end end PKu]A7bundler-2.2.24/lib/bundler/plugin/installer/rubygems.rbnu[# frozen_string_literal: true module Bundler module Plugin class Installer class Rubygems < Bundler::Source::Rubygems def version_message(spec) "#{spec.name} #{spec.version}" end private def requires_sudo? false # Will change on implementation of project level plugins end def rubygems_dir Plugin.root end def cache_path Plugin.cache end end end end end PKu]ߛ"Maa2bundler-2.2.24/lib/bundler/plugin/installer/git.rbnu[# frozen_string_literal: true module Bundler module Plugin class Installer class Git < Bundler::Source::Git def cache_path @cache_path ||= begin git_scope = "#{base_name}-#{uri_hash}" Plugin.cache.join("bundler", "git", git_scope) end end def install_path @install_path ||= begin git_scope = "#{base_name}-#{shortref_for_path(revision)}" Plugin.root.join("bundler", "gems", git_scope) end end def version_message(spec) "#{spec.name} #{spec.version}" end def root Plugin.root end def generate_bin(spec, disable_extensions = false) # Need to find a way without code duplication # For now, we can ignore this end end end end end PKu]{׳ .bundler-2.2.24/lib/bundler/plugin/installer.rbnu[# frozen_string_literal: true module Bundler # Handles the installation of plugin in appropriate directories. # # This class is supposed to be wrapper over the existing gem installation infra # but currently it itself handles everything as the Source's subclasses (e.g. Source::RubyGems) # are heavily dependent on the Gemfile. module Plugin class Installer autoload :Rubygems, File.expand_path("installer/rubygems", __dir__) autoload :Git, File.expand_path("installer/git", __dir__) def install(names, options) check_sources_consistency!(options) version = options[:version] || [">= 0"] if options[:git] install_git(names, version, options) elsif options[:local_git] install_local_git(names, version, options) else sources = options[:source] || Bundler.rubygems.sources install_rubygems(names, version, sources) end end # Installs the plugin from Definition object created by limited parsing of # Gemfile searching for plugins to be installed # # @param [Definition] definition object # @return [Hash] map of names to their specs they are installed with def install_definition(definition) def definition.lock(*); end definition.resolve_remotely! specs = definition.specs install_from_specs specs end private def check_sources_consistency!(options) if options.key?(:git) && options.key?(:local_git) raise InvalidOption, "Remote and local plugin git sources can't be both specified" end end def install_git(names, version, options) uri = options.delete(:git) options["uri"] = uri install_all_sources(names, version, options, options[:source]) end def install_local_git(names, version, options) uri = options.delete(:local_git) options["uri"] = uri install_all_sources(names, version, options, options[:source]) end # Installs the plugin from rubygems source and returns the path where the # plugin was installed # # @param [String] name of the plugin gem to search in the source # @param [Array] version of the gem to install # @param [String, Array] source(s) to resolve the gem # # @return [Hash] map of names to the specs of plugins installed def install_rubygems(names, version, sources) install_all_sources(names, version, nil, sources) end def install_all_sources(names, version, git_source_options, rubygems_source) source_list = SourceList.new source_list.add_git_source(git_source_options) if git_source_options Array(rubygems_source).each {|remote| source_list.add_global_rubygems_remote(remote) } if rubygems_source deps = names.map {|name| Dependency.new name, version } definition = Definition.new(nil, deps, source_list, true) install_definition(definition) end # Installs the plugins and deps from the provided specs and returns map of # gems to their paths # # @param specs to install # # @return [Hash] map of names to the specs def install_from_specs(specs) paths = {} specs.each do |spec| spec.source.install spec paths[spec.name] = spec end paths end end end end PKu].*bundler-2.2.24/lib/bundler/plugin/index.rbnu[# frozen_string_literal: true module Bundler # Manages which plugins are installed and their sources. This also is supposed to map # which plugin does what (currently the features are not implemented so this class is # now a stub class). module Plugin class Index class CommandConflict < PluginError def initialize(plugin, commands) msg = "Command(s) `#{commands.join("`, `")}` declared by #{plugin} are already registered." super msg end end class SourceConflict < PluginError def initialize(plugin, sources) msg = "Source(s) `#{sources.join("`, `")}` declared by #{plugin} are already registered." super msg end end attr_reader :commands def initialize @plugin_paths = {} @commands = {} @sources = {} @hooks = {} @load_paths = {} begin load_index(global_index_file, true) rescue GenericSystemCallError # no need to fail when on a read-only FS, for example nil end load_index(local_index_file) if SharedHelpers.in_bundle? end # This function is to be called when a new plugin is installed. This # function shall add the functions of the plugin to existing maps and also # the name to source location. # # @param [String] name of the plugin to be registered # @param [String] path where the plugin is installed # @param [Array] load_paths for the plugin # @param [Array] commands that are handled by the plugin # @param [Array] sources that are handled by the plugin def register_plugin(name, path, load_paths, commands, sources, hooks) old_commands = @commands.dup common = commands & @commands.keys raise CommandConflict.new(name, common) unless common.empty? commands.each {|c| @commands[c] = name } common = sources & @sources.keys raise SourceConflict.new(name, common) unless common.empty? sources.each {|k| @sources[k] = name } hooks.each do |event| event_hooks = (@hooks[event] ||= []) << name event_hooks.uniq! end @plugin_paths[name] = path @load_paths[name] = load_paths save_index rescue StandardError @commands = old_commands raise end def unregister_plugin(name) @commands.delete_if {|_, v| v == name } @sources.delete_if {|_, v| v == name } @hooks.each do |hook, names| names.delete(name) @hooks.delete(hook) if names.empty? end @plugin_paths.delete(name) @load_paths.delete(name) save_index end # Path of default index file def index_file Plugin.root.join("index") end # Path where the global index file is stored def global_index_file Plugin.global_root.join("index") end # Path where the local index file is stored def local_index_file Plugin.local_root.join("index") end def plugin_path(name) Pathname.new @plugin_paths[name] end def load_paths(name) @load_paths[name] end # Fetch the name of plugin handling the command def command_plugin(command) @commands[command] end def installed?(name) @plugin_paths[name] end def installed_plugins @plugin_paths.keys end def plugin_commands(plugin) @commands.find_all {|_, n| n == plugin }.map(&:first) end def source?(source) @sources.key? source end def source_plugin(name) @sources[name] end # Returns the list of plugin names handling the passed event def hook_plugins(event) @hooks[event] || [] end private # Reads the index file from the directory and initializes the instance # variables. # # It skips the sources if the second param is true # @param [Pathname] index file path # @param [Boolean] is the index file global index def load_index(index_file, global = false) SharedHelpers.filesystem_access(index_file, :read) do |index_f| valid_file = index_f && index_f.exist? && !index_f.size.zero? break unless valid_file data = index_f.read require_relative "../yaml_serializer" index = YAMLSerializer.load(data) @commands.merge!(index["commands"]) @hooks.merge!(index["hooks"]) @load_paths.merge!(index["load_paths"]) @plugin_paths.merge!(index["plugin_paths"]) @sources.merge!(index["sources"]) unless global end end # Should be called when any of the instance variables change. Stores the # instance variables in YAML format. (The instance variables are supposed # to be only String key value pairs) def save_index index = { "commands" => @commands, "hooks" => @hooks, "load_paths" => @load_paths, "plugin_paths" => @plugin_paths, "sources" => @sources, } require_relative "../yaml_serializer" SharedHelpers.filesystem_access(index_file) do |index_f| FileUtils.mkdir_p(index_f.dirname) File.open(index_f, "w") {|f| f.puts YAMLSerializer.dump(index) } end end end end end PKu]ΦAA0bundler-2.2.24/lib/bundler/plugin/source_list.rbnu[# frozen_string_literal: true module Bundler # SourceList object to be used while parsing the Gemfile, setting the # approptiate options to be used with Source classes for plugin installation module Plugin class SourceList < Bundler::SourceList def add_git_source(options = {}) add_source_to_list Plugin::Installer::Git.new(options), git_sources end def add_rubygems_source(options = {}) add_source_to_list Plugin::Installer::Rubygems.new(options), @rubygems_sources end def all_sources path_sources + git_sources + rubygems_sources + [metadata_source] end def default_source git_sources.first || global_rubygems_source end private def rubygems_aggregate_class Plugin::Installer::Rubygems end end end end PKu]wz,,%bundler-2.2.24/lib/bundler/fetcher.rbnu[# frozen_string_literal: true require_relative "vendored_persistent" require "cgi" require "securerandom" require "zlib" require "rubygems/request" module Bundler # Handles all the fetching with the rubygems server class Fetcher autoload :CompactIndex, File.expand_path("fetcher/compact_index", __dir__) autoload :Downloader, File.expand_path("fetcher/downloader", __dir__) autoload :Dependency, File.expand_path("fetcher/dependency", __dir__) autoload :Index, File.expand_path("fetcher/index", __dir__) # This error is raised when it looks like the network is down class NetworkDownError < HTTPError; end # This error is raised if we should rate limit our requests to the API class TooManyRequestsError < HTTPError; end # This error is raised if the API returns a 413 (only printed in verbose) class FallbackError < HTTPError; end # This is the error raised if OpenSSL fails the cert verification class CertificateFailureError < HTTPError def initialize(remote_uri) remote_uri = filter_uri(remote_uri) super "Could not verify the SSL certificate for #{remote_uri}.\nThere" \ " is a chance you are experiencing a man-in-the-middle attack, but" \ " most likely your system doesn't have the CA certificates needed" \ " for verification. For information about OpenSSL certificates, see" \ " http://bit.ly/ruby-ssl. To connect without using SSL, edit your Gemfile" \ " sources and change 'https' to 'http'." end end # This is the error raised when a source is HTTPS and OpenSSL didn't load class SSLError < HTTPError def initialize(msg = nil) super msg || "Could not load OpenSSL.\n" \ "You must recompile Ruby with OpenSSL support or change the sources in your " \ "Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL " \ "using RVM are available at rvm.io/packages/openssl." end end # This error is raised if HTTP authentication is required, but not provided. class AuthenticationRequiredError < HTTPError def initialize(remote_uri) remote_uri = filter_uri(remote_uri) super "Authentication is required for #{remote_uri}.\n" \ "Please supply credentials for this source. You can do this by running:\n" \ "`bundle config set --global #{remote_uri} username:password`\n" \ "or by storing the credentials in the `#{Settings.key_for(remote_uri)}` environment variable" end end # This error is raised if HTTP authentication is provided, but incorrect. class BadAuthenticationError < HTTPError def initialize(remote_uri) remote_uri = filter_uri(remote_uri) super "Bad username or password for #{remote_uri}.\n" \ "Please double-check your credentials and correct them." end end # Exceptions classes that should bypass retry attempts. If your password didn't work the # first time, it's not going to the third time. NET_ERRORS = [:HTTPBadGateway, :HTTPBadRequest, :HTTPFailedDependency, :HTTPForbidden, :HTTPInsufficientStorage, :HTTPMethodNotAllowed, :HTTPMovedPermanently, :HTTPNoContent, :HTTPNotFound, :HTTPNotImplemented, :HTTPPreconditionFailed, :HTTPRequestEntityTooLarge, :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity, :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze FAIL_ERRORS = begin fail_errors = [AuthenticationRequiredError, BadAuthenticationError, FallbackError] fail_errors << Gem::Requirement::BadRequirementError if defined?(Gem::Requirement::BadRequirementError) fail_errors.concat(NET_ERRORS.map {|e| SharedHelpers.const_get_safely(e, Net) }.compact) end.freeze class << self attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries end self.redirect_limit = Bundler.settings[:redirect] # How many redirects to allow in one request self.api_timeout = Bundler.settings[:timeout] # How long to wait for each API call self.max_retries = Bundler.settings[:retry] # How many retries for the API call def initialize(remote) @remote = remote Socket.do_not_reverse_lookup = true connection # create persistent connection end def uri @remote.anonymized_uri end # fetch a gem specification def fetch_spec(spec) spec -= [nil, "ruby", ""] spec_file_name = "#{spec.join "-"}.gemspec" uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") if uri.scheme == "file" path = Bundler.rubygems.correct_for_windows_path(uri.path) Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(path)) elsif cached_spec_path = gemspec_cached_path(spec_file_name) Bundler.load_gemspec(cached_spec_path) else Bundler.load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) end rescue MarshalError raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ "Your network or your gem server is probably having issues right now." end # return the specs in the bundler format as an index with retries def specs_with_retry(gem_names, source) Bundler::Retry.new("fetcher", FAIL_ERRORS).attempts do specs(gem_names, source) end end # return the specs in the bundler format as an index def specs(gem_names, source) old = Bundler.rubygems.sources index = Bundler::Index.new if Bundler::Fetcher.disable_endpoint @use_api = false specs = fetchers.last.specs(gem_names) else specs = [] fetchers.shift until fetchers.first.available? || fetchers.empty? fetchers.dup.each do |f| break unless f.api_fetcher? && !gem_names || !specs = f.specs(gem_names) fetchers.delete(f) end @use_api = false if fetchers.none?(&:api_fetcher?) end specs.each do |name, version, platform, dependencies, metadata| spec = if dependencies EndpointSpecification.new(name, version, platform, dependencies, metadata) else RemoteSpecification.new(name, version, platform, self) end spec.source = source spec.remote = @remote index << spec end index rescue CertificateFailureError Bundler.ui.info "" if gem_names && use_api # newline after dots raise ensure Bundler.rubygems.sources = old end def use_api return @use_api if defined?(@use_api) fetchers.shift until fetchers.first.available? @use_api = if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint false else fetchers.first.api_fetcher? end end def user_agent @user_agent ||= begin ruby = Bundler::RubyVersion.system agent = String.new("bundler/#{Bundler::VERSION}") agent << " rubygems/#{Gem::VERSION}" agent << " ruby/#{ruby.versions_string(ruby.versions)}" agent << " (#{ruby.host})" agent << " command/#{ARGV.first}" if ruby.engine != "ruby" # engine_version raises on unknown engines engine_version = begin ruby.engine_versions rescue RuntimeError "???" end agent << " #{ruby.engine}/#{ruby.versions_string(engine_version)}" end agent << " options/#{Bundler.settings.all.join(",")}" agent << " ci/#{cis.join(",")}" if cis.any? # add a random ID so we can consolidate runs server-side agent << " " << SecureRandom.hex(8) # add any user agent strings set in the config extra_ua = Bundler.settings[:user_agent] agent << " " << extra_ua if extra_ua agent end end def fetchers @fetchers ||= FETCHERS.map {|f| f.new(downloader, @remote, uri) } end def http_proxy return unless uri = connection.proxy_uri uri.to_s end def inspect "#<#{self.class}:0x#{object_id} uri=#{uri}>" end private FETCHERS = [CompactIndex, Dependency, Index].freeze def cis env_cis = { "TRAVIS" => "travis", "CIRCLECI" => "circle", "SEMAPHORE" => "semaphore", "JENKINS_URL" => "jenkins", "BUILDBOX" => "buildbox", "GO_SERVER_URL" => "go", "SNAP_CI" => "snap", "GITLAB_CI" => "gitlab", "CI_NAME" => ENV["CI_NAME"], "CI" => "ci", } env_cis.find_all {|env, _| ENV[env] }.map {|_, ci| ci } end def connection @connection ||= begin needs_ssl = remote_uri.scheme == "https" || Bundler.settings[:ssl_verify_mode] || Bundler.settings[:ssl_client_cert] raise SSLError if needs_ssl && !defined?(OpenSSL::SSL) con = PersistentHTTP.new :name => "bundler", :proxy => :ENV if gem_proxy = Bundler.rubygems.configuration[:http_proxy] con.proxy = Bundler::URI.parse(gem_proxy) if gem_proxy != :no_proxy end if remote_uri.scheme == "https" con.verify_mode = (Bundler.settings[:ssl_verify_mode] || OpenSSL::SSL::VERIFY_PEER) con.cert_store = bundler_cert_store end ssl_client_cert = Bundler.settings[:ssl_client_cert] || (Bundler.rubygems.configuration.ssl_client_cert if Bundler.rubygems.configuration.respond_to?(:ssl_client_cert)) if ssl_client_cert pem = File.read(ssl_client_cert) con.cert = OpenSSL::X509::Certificate.new(pem) con.key = OpenSSL::PKey::RSA.new(pem) end con.read_timeout = Fetcher.api_timeout con.open_timeout = Fetcher.api_timeout con.override_headers["User-Agent"] = user_agent con.override_headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri con end end # cached gem specification path, if one exists def gemspec_cached_path(spec_file_name) paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } paths = paths.select {|path| File.file? path } paths.first end HTTP_ERRORS = [ Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH, Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, PersistentHTTP::Error, Zlib::BufError, Errno::EHOSTUNREACH ].freeze def bundler_cert_store store = OpenSSL::X509::Store.new ssl_ca_cert = Bundler.settings[:ssl_ca_cert] || (Bundler.rubygems.configuration.ssl_ca_cert if Bundler.rubygems.configuration.respond_to?(:ssl_ca_cert)) if ssl_ca_cert if File.directory? ssl_ca_cert store.add_path ssl_ca_cert else store.add_file ssl_ca_cert end else store.set_default_paths Gem::Request.get_cert_files.each {|c| store.add_file c } end store end private def remote_uri @remote.uri end def downloader @downloader ||= Downloader.new(connection, self.class.redirect_limit) end end end PKu]•n)bundler-2.2.24/lib/bundler/source_list.rbnu[# frozen_string_literal: true module Bundler class SourceList attr_reader :path_sources, :git_sources, :plugin_sources, :global_path_source, :metadata_source def global_rubygems_source @global_rubygems_source ||= rubygems_aggregate_class.new("allow_local" => true) end def initialize @path_sources = [] @git_sources = [] @plugin_sources = [] @global_rubygems_source = nil @global_path_source = nil @rubygems_sources = [] @metadata_source = Source::Metadata.new @merged_gem_lockfile_sections = false end def merged_gem_lockfile_sections? @merged_gem_lockfile_sections end def merged_gem_lockfile_sections!(replacement_source) @merged_gem_lockfile_sections = true @global_rubygems_source = replacement_source end def aggregate_global_source? global_rubygems_source.multiple_remotes? end def add_path_source(options = {}) if options["gemspec"] add_source_to_list Source::Gemspec.new(options), path_sources else path_source = add_source_to_list Source::Path.new(options), path_sources @global_path_source ||= path_source if options["global"] path_source end end def add_git_source(options = {}) add_source_to_list(Source::Git.new(options), git_sources).tap do |source| warn_on_git_protocol(source) end end def add_rubygems_source(options = {}) new_source = Source::Rubygems.new(options) return @global_rubygems_source if @global_rubygems_source == new_source add_source_to_list new_source, @rubygems_sources end def add_plugin_source(source, options = {}) add_source_to_list Plugin.source(source).new(options), @plugin_sources end def add_global_rubygems_remote(uri) global_rubygems_source.add_remote(uri) global_rubygems_source end def default_source global_path_source || global_rubygems_source end def rubygems_sources non_global_rubygems_sources + [global_rubygems_source] end def non_global_rubygems_sources @rubygems_sources end def rubygems_remotes rubygems_sources.map(&:remotes).flatten.uniq end def all_sources path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source] end def non_default_explicit_sources all_sources - [default_source, metadata_source] end def get(source) source_list_for(source).find {|s| equal_source?(source, s) || equivalent_source?(source, s) } end def lock_sources lock_other_sources + lock_rubygems_sources end def lock_other_sources (path_sources + git_sources + plugin_sources).sort_by(&:to_s) end def lock_rubygems_sources if merged_gem_lockfile_sections? [combine_rubygems_sources] else rubygems_sources.sort_by(&:to_s) end end # Returns true if there are changes def replace_sources!(replacement_sources) return false if replacement_sources.empty? @path_sources, @git_sources, @plugin_sources = map_sources(replacement_sources) different_sources?(lock_sources, replacement_sources) end # Returns true if there are changes def expired_sources?(replacement_sources) return false if replacement_sources.empty? lock_sources = dup_with_replaced_sources(replacement_sources).lock_sources different_sources?(lock_sources, replacement_sources) end def local_only! all_sources.each(&:local_only!) end def cached! all_sources.each(&:cached!) end def remote! all_sources.each(&:remote!) end private def dup_with_replaced_sources(replacement_sources) new_source_list = dup new_source_list.replace_sources!(replacement_sources) new_source_list end def map_sources(replacement_sources) [path_sources, git_sources, plugin_sources].map do |sources| sources.map do |source| replacement_sources.find {|s| s == source } || source end end end def different_sources?(lock_sources, replacement_sources) !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources) end def rubygems_aggregate_class Source::Rubygems end def add_source_to_list(source, list) list.unshift(source).uniq! source end def source_list_for(source) case source when Source::Git then git_sources when Source::Path then path_sources when Source::Rubygems then rubygems_sources when Plugin::API::Source then plugin_sources else raise ArgumentError, "Invalid source: #{source.inspect}" end end def combine_rubygems_sources Source::Rubygems.new("remotes" => rubygems_remotes) end def warn_on_git_protocol(source) return if Bundler.settings["git.allow_insecure"] if source.uri =~ /^git\:/ Bundler.ui.warn "The git source `#{source.uri}` uses the `git` protocol, " \ "which transmits data without encryption. Disable this warning with " \ "`bundle config set --local git.allow_insecure true`, or switch to the `https` " \ "protocol to keep your data secure." end end def equal_sources?(lock_sources, replacement_sources) lock_sources.sort_by(&:to_s) == replacement_sources.sort_by(&:to_s) end def equal_source?(source, other_source) return source.include?(other_source) if source.is_a?(Source::Rubygems) && other_source.is_a?(Source::Rubygems) && !merged_gem_lockfile_sections? source == other_source end def equivalent_source?(source, other_source) return false unless Bundler.settings[:allow_deployment_source_credential_changes] && source.is_a?(Source::Rubygems) equivalent_rubygems_sources?([source], [other_source]) end def equivalent_sources?(lock_sources, replacement_sources) return false unless Bundler.settings[:allow_deployment_source_credential_changes] lock_rubygems_sources, lock_other_sources = lock_sources.partition {|s| s.is_a?(Source::Rubygems) } replacement_rubygems_sources, replacement_other_sources = replacement_sources.partition {|s| s.is_a?(Source::Rubygems) } equivalent_rubygems_sources?(lock_rubygems_sources, replacement_rubygems_sources) && equal_sources?(lock_other_sources, replacement_other_sources) end def equivalent_rubygems_sources?(lock_sources, replacement_sources) actual_remotes = replacement_sources.map(&:remotes).flatten.uniq lock_sources.all? {|s| s.equivalent_remotes?(actual_remotes) } end end end PKu]wj5,bundler-2.2.24/lib/bundler/build_metadata.rbnu[# frozen_string_literal: true module Bundler # Represents metadata from when the Bundler gem was built. module BuildMetadata # begin ivars @release = false # end ivars # A hash representation of the build metadata. def self.to_h { "Built At" => built_at, "Git SHA" => git_commit_sha, "Released Version" => release?, } end # A string representing the date the bundler gem was built. def self.built_at @built_at ||= Time.now.utc.strftime("%Y-%m-%d").freeze end # The SHA for the git commit the bundler gem was built from. def self.git_commit_sha return @git_commit_sha if instance_variable_defined? :@git_commit_sha # If Bundler has been installed without its .git directory and without a # commit instance variable then we can't determine its commits SHA. git_dir = File.join(File.expand_path("../../../..", __FILE__), ".git") if File.directory?(git_dir) return @git_commit_sha = Dir.chdir(git_dir) { `git rev-parse --short HEAD`.strip.freeze } end @git_commit_sha ||= "unknown" end # Whether this is an official release build of Bundler. def self.release? @release end end end PKu][51bundler-2.2.24/lib/bundler/vendored_persistent.rbnu[# frozen_string_literal: true module Bundler module Persistent module Net module HTTP end end end end require_relative "vendor/net-http-persistent/lib/net/http/persistent" module Bundler class PersistentHTTP < Persistent::Net::HTTP::Persistent def connection_for(uri) super(uri) do |connection| result = yield connection warn_old_tls_version_rubygems_connection(uri, connection) result end end def warn_old_tls_version_rubygems_connection(uri, connection) return unless connection.http.use_ssl? return unless (uri.host || "").end_with?("rubygems.org") socket = connection.instance_variable_get(:@socket) return unless socket socket_io = socket.io return unless socket_io.respond_to?(:ssl_version) ssl_version = socket_io.ssl_version case ssl_version when /TLSv([\d\.]+)/ version = Gem::Version.new($1) if version < Gem::Version.new("1.2") Bundler.ui.warn \ "Warning: Your Ruby version is compiled against a copy of OpenSSL that is very old. " \ "Starting in January 2018, RubyGems.org will refuse connection requests from these " \ "very old versions of OpenSSL. If you will need to continue installing gems after " \ "January 2018, please follow this guide to upgrade: http://ruby.to/tls-outdated.", :wrap => true end end end end end PKu][  'bundler-2.2.24/lib/bundler/ui/silent.rbnu[# frozen_string_literal: true module Bundler module UI class Silent attr_writer :shell def initialize @warnings = [] end def add_color(string, color) string end def info(message, newline = nil) end def confirm(message, newline = nil) end def warn(message, newline = nil) @warnings |= [message] end def error(message, newline = nil) end def debug(message, newline = nil) end def debug? false end def quiet? false end def ask(message) end def yes?(msg) raise "Cannot ask yes? with a silent shell" end def no? raise "Cannot ask no? with a silent shell" end def level=(name) end def level(name = nil) end def trace(message, newline = nil, force = false) end def silence yield end def unprinted_warnings @warnings end end end end PKu]K66)bundler-2.2.24/lib/bundler/ui/rg_proxy.rbnu[# frozen_string_literal: true require_relative "../ui" require "rubygems/user_interaction" module Bundler module UI class RGProxy < ::Gem::SilentUI def initialize(ui) @ui = ui super() end def say(message) @ui && @ui.debug(message) end end end end PKu]Xȷr r &bundler-2.2.24/lib/bundler/ui/shell.rbnu[# frozen_string_literal: true require_relative "../vendored_thor" module Bundler module UI class Shell LEVELS = %w[silent error warn confirm info debug].freeze attr_writer :shell def initialize(options = {}) Thor::Base.shell = options["no-color"] ? Thor::Shell::Basic : nil @shell = Thor::Base.shell.new @level = ENV["DEBUG"] ? "debug" : "info" @warning_history = [] end def add_color(string, *color) @shell.set_color(string, *color) end def info(msg, newline = nil) tell_me(msg, nil, newline) if level("info") end def confirm(msg, newline = nil) tell_me(msg, :green, newline) if level("confirm") end def warn(msg, newline = nil, color = :yellow) return unless level("warn") return if @warning_history.include? msg @warning_history << msg tell_err(msg, color, newline) end def error(msg, newline = nil, color = :red) return unless level("error") tell_err(msg, color, newline) end def debug(msg, newline = nil) tell_me(msg, nil, newline) if debug? end def debug? level("debug") end def quiet? level("quiet") end def ask(msg) @shell.ask(msg) end def yes?(msg) @shell.yes?(msg) end def no? @shell.no?(msg) end def level=(level) raise ArgumentError unless LEVELS.include?(level.to_s) @level = level.to_s end def level(name = nil) return @level unless name unless index = LEVELS.index(name) raise "#{name.inspect} is not a valid level" end index <= LEVELS.index(@level) end def trace(e, newline = nil, force = false) return unless debug? || force msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n ")}" tell_me(msg, nil, newline) end def silence(&blk) with_level("silent", &blk) end def unprinted_warnings [] end private # valimism def tell_me(msg, color = nil, newline = nil) msg = word_wrap(msg) if newline.is_a?(Hash) && newline[:wrap] if newline.nil? @shell.say(msg, color) else @shell.say(msg, color, newline) end end def tell_err(message, color = nil, newline = nil) return if @shell.send(:stderr).closed? newline ||= message.to_s !~ /( |\t)\Z/ message = word_wrap(message) if newline.is_a?(Hash) && newline[:wrap] color = nil if color && !$stderr.tty? buffer = @shell.send(:prepare_message, message, *color) buffer << "\n" if newline && !message.to_s.end_with?("\n") @shell.send(:stderr).print(buffer) @shell.send(:stderr).flush end def strip_leading_spaces(text) spaces = text[/\A\s+/, 0] spaces ? text.gsub(/#{spaces}/, "") : text end def word_wrap(text, line_width = @shell.terminal_width) strip_leading_spaces(text).split("\n").collect do |line| line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line end * "\n" end def with_level(level) original = @level @level = level yield ensure @level = original end end end end PKu]unuu#bundler-2.2.24/lib/bundler/retry.rbnu[# frozen_string_literal: true module Bundler # General purpose class for retrying code that may fail class Retry attr_accessor :name, :total_runs, :current_run class << self def default_attempts default_retries + 1 end alias_method :attempts, :default_attempts def default_retries Bundler.settings[:retry] end end def initialize(name, exceptions = nil, retries = self.class.default_retries) @name = name @retries = retries @exceptions = Array(exceptions) || [] @total_runs = @retries + 1 # will run once, then upto attempts.times end def attempt(&block) @current_run = 0 @failed = false @error = nil run(&block) while keep_trying? @result end alias_method :attempts, :attempt private def run(&block) @failed = false @current_run += 1 @result = block.call rescue StandardError => e fail_attempt(e) end def fail_attempt(e) @failed = true if last_attempt? || @exceptions.any? {|k| e.is_a?(k) } Bundler.ui.info "" unless Bundler.ui.debug? raise e end return true unless name Bundler.ui.info "" unless Bundler.ui.debug? # Add new line in case dots preceded this Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", Bundler.ui.debug? end def keep_trying? return true if current_run.zero? return false if last_attempt? return true if @failed end def last_attempt? current_run >= total_runs end end end PKu]0ee0bundler-2.2.24/lib/bundler/vendored_fileutils.rbnu[# frozen_string_literal: true module Bundler; end require_relative "vendor/fileutils/lib/fileutils" PKu]'*bundler-2.2.24/lib/bundler/feature_flag.rbnu[# frozen_string_literal: true module Bundler class FeatureFlag def self.settings_flag(flag, &default) unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s) raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key" end settings_method("#{flag}?", flag, &default) end private_class_method :settings_flag def self.settings_option(key, &default) settings_method(key, key, &default) end private_class_method :settings_option def self.settings_method(name, key, &default) define_method(name) do value = Bundler.settings[key] value = instance_eval(&default) if value.nil? value end end private_class_method :settings_method (1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } } settings_flag(:allow_offline_install) { bundler_3_mode? } settings_flag(:auto_clean_without_path) { bundler_3_mode? } settings_flag(:cache_all) { bundler_3_mode? } settings_flag(:default_install_uses_path) { bundler_3_mode? } settings_flag(:forget_cli_options) { bundler_3_mode? } settings_flag(:global_gem_cache) { bundler_3_mode? } settings_flag(:path_relative_to_cwd) { bundler_3_mode? } settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") } settings_flag(:print_only_version_number) { bundler_3_mode? } settings_flag(:setup_makes_kernel_gem_public) { !bundler_3_mode? } settings_flag(:suppress_install_using_messages) { bundler_3_mode? } settings_flag(:update_requires_all_flag) { bundler_4_mode? } settings_flag(:use_gem_version_promoter_for_major_updates) { bundler_3_mode? } settings_option(:default_cli_command) { bundler_3_mode? ? :cli_help : :install } def initialize(bundler_version) @bundler_version = Gem::Version.create(bundler_version) end def major_version @bundler_version.segments.first end private :major_version end end PKu]O ɧ%bundler-2.2.24/lib/bundler/gemdeps.rbnu[# frozen_string_literal: true module Bundler class Gemdeps def initialize(runtime) @runtime = runtime end def requested_specs @runtime.requested_specs end def specs @runtime.specs end def dependencies @runtime.dependencies end def current_dependencies @runtime.current_dependencies end def requires @runtime.requires end end end PKu]-L00,bundler-2.2.24/lib/bundler/version_ranges.rbnu[# frozen_string_literal: true module Bundler module VersionRanges NEq = Struct.new(:version) ReqR = Struct.new(:left, :right) class ReqR Endpoint = Struct.new(:version, :inclusive) do def <=>(other) if version.equal?(INFINITY) return 0 if other.version.equal?(INFINITY) return 1 elsif other.version.equal?(INFINITY) return -1 end comp = version <=> other.version return comp unless comp.zero? if inclusive && !other.inclusive 1 elsif !inclusive && other.inclusive -1 else 0 end end end def to_s "#{left.inclusive ? "[" : "("}#{left.version}, #{right.version}#{right.inclusive ? "]" : ")"}" end INFINITY = begin inf = Object.new def inf.to_s "∞" end def inf.<=>(other) return 0 if other.equal?(self) 1 end inf.freeze end ZERO = Gem::Version.new("0.a") def cover?(v) return false if left.inclusive && left.version > v return false if !left.inclusive && left.version >= v if right.version != INFINITY return false if right.inclusive && right.version < v return false if !right.inclusive && right.version <= v end true end def empty? left.version == right.version && !(left.inclusive && right.inclusive) end def single? left.version == right.version end def <=>(other) return -1 if other.equal?(INFINITY) comp = left <=> other.left return comp unless comp.zero? right <=> other.right end UNIVERSAL = ReqR.new(ReqR::Endpoint.new(Gem::Version.new("0.a"), true), ReqR::Endpoint.new(ReqR::INFINITY, false)).freeze end def self.for_many(requirements) requirements = requirements.map(&:requirements).flatten(1).map {|r| r.join(" ") } requirements << ">= 0.a" if requirements.empty? requirement = Gem::Requirement.new(requirements) self.for(requirement) end def self.for(requirement) ranges = requirement.requirements.map do |op, v| case op when "=" then ReqR.new(ReqR::Endpoint.new(v, true), ReqR::Endpoint.new(v, true)) when "!=" then NEq.new(v) when ">=" then ReqR.new(ReqR::Endpoint.new(v, true), ReqR::Endpoint.new(ReqR::INFINITY, false)) when ">" then ReqR.new(ReqR::Endpoint.new(v, false), ReqR::Endpoint.new(ReqR::INFINITY, false)) when "<" then ReqR.new(ReqR::Endpoint.new(ReqR::ZERO, true), ReqR::Endpoint.new(v, false)) when "<=" then ReqR.new(ReqR::Endpoint.new(ReqR::ZERO, true), ReqR::Endpoint.new(v, true)) when "~>" then ReqR.new(ReqR::Endpoint.new(v, true), ReqR::Endpoint.new(v.bump, false)) else raise "unknown version op #{op} in requirement #{requirement}" end end.uniq ranges, neqs = ranges.partition {|r| !r.is_a?(NEq) } [ranges.sort, neqs.map(&:version)] end def self.empty?(ranges, neqs) !ranges.reduce(ReqR::UNIVERSAL) do |last_range, curr_range| next false unless last_range next false if curr_range.single? && neqs.include?(curr_range.left.version) next curr_range if last_range.right.version == ReqR::INFINITY case last_range.right.version <=> curr_range.left.version # higher when 1 then next ReqR.new(curr_range.left, last_range.right) # equal when 0 if last_range.right.inclusive && curr_range.left.inclusive && !neqs.include?(curr_range.left.version) ReqR.new(curr_range.left, [curr_range.right, last_range.right].max) end # lower when -1 then next false end end end end end PKu]3,#bundler-2.2.24/lib/bundler/graph.rbnu[# frozen_string_literal: true require "set" module Bundler class Graph GRAPH_NAME = :Gemfile def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png", without = []) @env = env @output_file = output_file @show_version = show_version @show_requirements = show_requirements @output_format = output_format @without_groups = without.map(&:to_sym) @groups = [] @relations = Hash.new {|h, k| h[k] = Set.new } @node_options = {} @edge_options = {} _populate_relations end attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format def viz GraphVizClient.new(self).run end private def _populate_relations parent_dependencies = _groups.values.to_set.flatten loop do break if parent_dependencies.empty? tmp = Set.new parent_dependencies.each do |dependency| child_dependencies = spec_for_dependency(dependency).runtime_dependencies.to_set @relations[dependency.name] += child_dependencies.map(&:name).to_set tmp += child_dependencies @node_options[dependency.name] = _make_label(dependency, :node) child_dependencies.each do |c_dependency| @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge) end end parent_dependencies = tmp end end def _groups relations = Hash.new {|h, k| h[k] = Set.new } @env.current_dependencies.each do |dependency| dependency.groups.each do |group| next if @without_groups.include?(group) relations[group.to_s].add(dependency) @relations[group.to_s].add(dependency.name) @node_options[group.to_s] ||= _make_label(group, :node) @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge) end end @groups = relations.keys relations end def _make_label(symbol_or_string_or_dependency, element_type) case element_type.to_sym when :node if symbol_or_string_or_dependency.is_a?(Gem::Dependency) label = symbol_or_string_or_dependency.name.dup label << "\n#{spec_for_dependency(symbol_or_string_or_dependency).version}" if @show_version else label = symbol_or_string_or_dependency.to_s end when :edge label = nil if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements tmp = symbol_or_string_or_dependency.requirements_list.join(", ") label = tmp if tmp != ">= 0" end else raise ArgumentError, "2nd argument is invalid" end label.nil? ? {} : { :label => label } end def spec_for_dependency(dependency) @env.requested_specs.find {|s| s.name == dependency.name } end class GraphVizClient def initialize(graph_instance) @graph_name = graph_instance.class::GRAPH_NAME @groups = graph_instance.groups @relations = graph_instance.relations @node_options = graph_instance.node_options @edge_options = graph_instance.edge_options @output_file = graph_instance.output_file @output_format = graph_instance.output_format end def g @g ||= ::GraphViz.digraph(@graph_name, :concentrate => true, :normalize => true, :nodesep => 0.55) do |g| g.edge[:weight] = 2 g.edge[:fontname] = g.node[:fontname] = "Arial, Helvetica, SansSerif" g.edge[:fontsize] = 12 end end def run @groups.each do |group| g.add_nodes( group, { :style => "filled", :fillcolor => "#B9B9D5", :shape => "box3d", :fontsize => 16, }.merge(@node_options[group]) ) end @relations.each do |parent, children| children.each do |child| if @groups.include?(parent) g.add_nodes(child, { :style => "filled", :fillcolor => "#B9B9D5" }.merge(@node_options[child])) g.add_edges(parent, child, { :constraint => false }.merge(@edge_options["#{parent}_#{child}"])) else g.add_nodes(child, @node_options[child]) g.add_edges(parent, child, @edge_options["#{parent}_#{child}"]) end end end if @output_format.to_s == "debug" $stdout.puts g.output :none => String Bundler.ui.info "debugging bundle viz..." else begin g.output @output_format.to_sym => "#{@output_file}.#{@output_format}" Bundler.ui.info "#{@output_file}.#{@output_format}" rescue ArgumentError => e warn "Unsupported output format. See Ruby-Graphviz/lib/graphviz/constants.rb" raise e end end end end end end PKu]YE[hrdoc-6.2.1.1/exe/rdocnuȯ#!/usr/bin/ruby # # RDoc: Documentation tool for source code # (see lib/rdoc/rdoc.rb for more information) # # Copyright (c) 2003 Dave Thomas # Released under the same terms as Ruby begin gem 'rdoc' rescue NameError => e # --disable-gems raise unless e.name == :gem rescue Gem::LoadError end require 'rdoc/rdoc' begin r = RDoc::RDoc.new r.document ARGV rescue Errno::ENOSPC $stderr.puts 'Ran out of space creating documentation' $stderr.puts $stderr.puts 'Please free up some space and try again' rescue SystemExit raise rescue Exception => e if $DEBUG_RDOC then $stderr.puts e.message $stderr.puts "#{e.backtrace.join "\n\t"}" $stderr.puts elsif Interrupt === e then $stderr.puts $stderr.puts 'Interrupted' else $stderr.puts "uh-oh! RDoc had a problem:" $stderr.puts e.message $stderr.puts $stderr.puts "run with --debug for full backtrace" end exit 1 end PKu]ֳsrdoc-6.2.1.1/exe/rinuȯ#!/usr/bin/ruby begin gem 'rdoc' rescue NameError => e # --disable-gems raise unless e.name == :gem rescue Gem::LoadError end require 'rdoc/ri/driver' RDoc::RI::Driver.run ARGV PKu]u`x`x rdoc-6.2.1.1/lib/rdoc/context.rbnu[# frozen_string_literal: true require 'cgi' ## # A Context is something that can hold modules, classes, methods, attributes, # aliases, requires, and includes. Classes, modules, and files are all # Contexts. class RDoc::Context < RDoc::CodeObject include Comparable ## # Types of methods TYPES = %w[class instance] ## # If a context has these titles it will be sorted in this order. TOMDOC_TITLES = [nil, 'Public', 'Internal', 'Deprecated'] # :nodoc: TOMDOC_TITLES_SORT = TOMDOC_TITLES.sort_by { |title| title.to_s } # :nodoc: ## # Class/module aliases attr_reader :aliases ## # All attr* methods attr_reader :attributes ## # Block params to be used in the next MethodAttr parsed under this context attr_accessor :block_params ## # Constants defined attr_reader :constants ## # Sets the current documentation section of documentation attr_writer :current_section ## # Files this context is found in attr_reader :in_files ## # Modules this context includes attr_reader :includes ## # Modules this context is extended with attr_reader :extends ## # Methods defined in this context attr_reader :method_list ## # Name of this class excluding namespace. See also full_name attr_reader :name ## # Files this context requires attr_reader :requires ## # Use this section for the next method, attribute or constant added. attr_accessor :temporary_section ## # Hash old_name => [aliases], for aliases # that haven't (yet) been resolved to a method/attribute. # (Not to be confused with the aliases of the context.) attr_accessor :unmatched_alias_lists ## # Aliases that could not be resolved. attr_reader :external_aliases ## # Current visibility of this context attr_accessor :visibility ## # Current visibility of this line attr_writer :current_line_visibility ## # Hash of registered methods. Attributes are also registered here, # twice if they are RW. attr_reader :methods_hash ## # Params to be used in the next MethodAttr parsed under this context attr_accessor :params ## # Hash of registered constants. attr_reader :constants_hash ## # Creates an unnamed empty context with public current visibility def initialize super @in_files = [] @name ||= "unknown" @parent = nil @visibility = :public @current_section = Section.new self, nil, nil @sections = { nil => @current_section } @temporary_section = nil @classes = {} @modules = {} initialize_methods_etc end ## # Sets the defaults for methods and so-forth def initialize_methods_etc @method_list = [] @attributes = [] @aliases = [] @requires = [] @includes = [] @extends = [] @constants = [] @external_aliases = [] @current_line_visibility = nil # This Hash maps a method name to a list of unmatched aliases (aliases of # a method not yet encountered). @unmatched_alias_lists = {} @methods_hash = {} @constants_hash = {} @params = nil @store ||= nil end ## # Contexts are sorted by full_name def <=>(other) return nil unless RDoc::CodeObject === other full_name <=> other.full_name end ## # Adds an item of type +klass+ with the given +name+ and +comment+ to the # context. # # Currently only RDoc::Extend and RDoc::Include are supported. def add klass, name, comment if RDoc::Extend == klass then ext = RDoc::Extend.new name, comment add_extend ext elsif RDoc::Include == klass then incl = RDoc::Include.new name, comment add_include incl else raise NotImplementedError, "adding a #{klass} is not implemented" end end ## # Adds +an_alias+ that is automatically resolved def add_alias an_alias return an_alias unless @document_self method_attr = find_method(an_alias.old_name, an_alias.singleton) || find_attribute(an_alias.old_name, an_alias.singleton) if method_attr then method_attr.add_alias an_alias, self else add_to @external_aliases, an_alias unmatched_alias_list = @unmatched_alias_lists[an_alias.pretty_old_name] ||= [] unmatched_alias_list.push an_alias end an_alias end ## # Adds +attribute+ if not already there. If it is (as method(s) or attribute), # updates the comment if it was empty. # # The attribute is registered only if it defines a new method. # For instance, attr_reader :foo will not be registered # if method +foo+ exists, but attr_accessor :foo will be registered # if method +foo+ exists, but foo= does not. def add_attribute attribute return attribute unless @document_self # mainly to check for redefinition of an attribute as a method # TODO find a policy for 'attr_reader :foo' + 'def foo=()' register = false key = nil if attribute.rw.index 'R' then key = attribute.pretty_name known = @methods_hash[key] if known then known.comment = attribute.comment if known.comment.empty? elsif registered = @methods_hash[attribute.pretty_name + '='] and RDoc::Attr === registered then registered.rw = 'RW' else @methods_hash[key] = attribute register = true end end if attribute.rw.index 'W' then key = attribute.pretty_name + '=' known = @methods_hash[key] if known then known.comment = attribute.comment if known.comment.empty? elsif registered = @methods_hash[attribute.pretty_name] and RDoc::Attr === registered then registered.rw = 'RW' else @methods_hash[key] = attribute register = true end end if register then attribute.visibility = @visibility add_to @attributes, attribute resolve_aliases attribute end attribute end ## # Adds a class named +given_name+ with +superclass+. # # Both +given_name+ and +superclass+ may contain '::', and are # interpreted relative to the +self+ context. This allows handling correctly # examples like these: # class RDoc::Gauntlet < Gauntlet # module Mod # class Object # implies < ::Object # class SubObject < Object # this is _not_ ::Object # # Given class Container::Item RDoc assumes +Container+ is a module # unless it later sees class Container. +add_class+ automatically # upgrades +given_name+ to a class in this case. def add_class class_type, given_name, superclass = '::Object' # superclass +nil+ is passed by the C parser in the following cases: # - registering Object in 1.8 (correct) # - registering BasicObject in 1.9 (correct) # - registering RubyVM in 1.9 in iseq.c (incorrect: < Object in vm.c) # # If we later find a superclass for a registered class with a nil # superclass, we must honor it. # find the name & enclosing context if given_name =~ /^:+(\w+)$/ then full_name = $1 enclosing = top_level name = full_name.split(/:+/).last else full_name = child_name given_name if full_name =~ /^(.+)::(\w+)$/ then name = $2 ename = $1 enclosing = @store.classes_hash[ename] || @store.modules_hash[ename] # HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming) unless enclosing then # try the given name at top level (will work for the above example) enclosing = @store.classes_hash[given_name] || @store.modules_hash[given_name] return enclosing if enclosing # not found: create the parent(s) names = ename.split('::') enclosing = self names.each do |n| enclosing = enclosing.classes_hash[n] || enclosing.modules_hash[n] || enclosing.add_module(RDoc::NormalModule, n) end end else name = full_name enclosing = self end end # fix up superclass if full_name == 'BasicObject' then superclass = nil elsif full_name == 'Object' then superclass = '::BasicObject' end # find the superclass full name if superclass then if superclass =~ /^:+/ then superclass = $' #' else if superclass =~ /^(\w+):+(.+)$/ then suffix = $2 mod = find_module_named($1) superclass = mod.full_name + '::' + suffix if mod else mod = find_module_named(superclass) superclass = mod.full_name if mod end end # did we believe it was a module? mod = @store.modules_hash.delete superclass upgrade_to_class mod, RDoc::NormalClass, mod.parent if mod # e.g., Object < Object superclass = nil if superclass == full_name end klass = @store.classes_hash[full_name] if klass then # if TopLevel, it may not be registered in the classes: enclosing.classes_hash[name] = klass # update the superclass if needed if superclass then existing = klass.superclass existing = existing.full_name unless existing.is_a?(String) if existing if existing.nil? || (existing == 'Object' && superclass != 'Object') then klass.superclass = superclass end end else # this is a new class mod = @store.modules_hash.delete full_name if mod then klass = upgrade_to_class mod, RDoc::NormalClass, enclosing klass.superclass = superclass unless superclass.nil? else klass = class_type.new name, superclass enclosing.add_class_or_module(klass, enclosing.classes_hash, @store.classes_hash) end end klass.parent = self klass end ## # Adds the class or module +mod+ to the modules or # classes Hash +self_hash+, and to +all_hash+ (either # TopLevel::modules_hash or TopLevel::classes_hash), # unless #done_documenting is +true+. Sets the #parent of +mod+ # to +self+, and its #section to #current_section. Returns +mod+. def add_class_or_module mod, self_hash, all_hash mod.section = current_section # TODO declaring context? something is # wrong here... mod.parent = self mod.full_name = nil mod.store = @store unless @done_documenting then self_hash[mod.name] = mod # this must be done AFTER adding mod to its parent, so that the full # name is correct: all_hash[mod.full_name] = mod if @store.unmatched_constant_alias[mod.full_name] then to, file = @store.unmatched_constant_alias[mod.full_name] add_module_alias mod, mod.name, to, file end end mod end ## # Adds +constant+ if not already there. If it is, updates the comment, # value and/or is_alias_for of the known constant if they were empty/nil. def add_constant constant return constant unless @document_self # HACK: avoid duplicate 'PI' & 'E' in math.c (1.8.7 source code) # (this is a #ifdef: should be handled by the C parser) known = @constants_hash[constant.name] if known then known.comment = constant.comment if known.comment.empty? known.value = constant.value if known.value.nil? or known.value.strip.empty? known.is_alias_for ||= constant.is_alias_for else @constants_hash[constant.name] = constant add_to @constants, constant end constant end ## # Adds included module +include+ which should be an RDoc::Include def add_include include add_to @includes, include include end ## # Adds extension module +ext+ which should be an RDoc::Extend def add_extend ext add_to @extends, ext ext end ## # Adds +method+ if not already there. If it is (as method or attribute), # updates the comment if it was empty. def add_method method return method unless @document_self # HACK: avoid duplicate 'new' in io.c & struct.c (1.8.7 source code) key = method.pretty_name known = @methods_hash[key] if known then if @store then # otherwise we are loading known.comment = method.comment if known.comment.empty? previously = ", previously in #{known.file}" unless method.file == known.file @store.rdoc.options.warn \ "Duplicate method #{known.full_name} in #{method.file}#{previously}" end else @methods_hash[key] = method if @current_line_visibility method.visibility, @current_line_visibility = @current_line_visibility, nil else method.visibility = @visibility end add_to @method_list, method resolve_aliases method end method end ## # Adds a module named +name+. If RDoc already knows +name+ is a class then # that class is returned instead. See also #add_class. def add_module(class_type, name) mod = @classes[name] || @modules[name] return mod if mod full_name = child_name name mod = @store.modules_hash[full_name] || class_type.new(name) add_class_or_module mod, @modules, @store.modules_hash end ## # Adds a module by +RDoc::NormalModule+ instance. See also #add_module. def add_module_by_normal_module(mod) add_class_or_module mod, @modules, @store.modules_hash end ## # Adds an alias from +from+ (a class or module) to +name+ which was defined # in +file+. def add_module_alias from, from_name, to, file return from if @done_documenting to_full_name = child_name to.name # if we already know this name, don't register an alias: # see the metaprogramming in lib/active_support/basic_object.rb, # where we already know BasicObject is a class when we find # BasicObject = BlankSlate return from if @store.find_class_or_module to_full_name unless from @store.unmatched_constant_alias[child_name(from_name)] = [to, file] return to end new_to = from.dup new_to.name = to.name new_to.full_name = nil if new_to.module? then @store.modules_hash[to_full_name] = new_to @modules[to.name] = new_to else @store.classes_hash[to_full_name] = new_to @classes[to.name] = new_to end # Registers a constant for this alias. The constant value and comment # will be updated later, when the Ruby parser adds the constant const = RDoc::Constant.new to.name, nil, new_to.comment const.record_location file const.is_alias_for = from add_constant const new_to end ## # Adds +require+ to this context's top level def add_require(require) return require unless @document_self if RDoc::TopLevel === self then add_to @requires, require else parent.add_require require end end ## # Returns a section with +title+, creating it if it doesn't already exist. # +comment+ will be appended to the section's comment. # # A section with a +title+ of +nil+ will return the default section. # # See also RDoc::Context::Section def add_section title, comment = nil if section = @sections[title] then section.add_comment comment if comment else section = Section.new self, title, comment @sections[title] = section end section end ## # Adds +thing+ to the collection +array+ def add_to array, thing array << thing if @document_self thing.parent = self thing.store = @store if @store thing.section = current_section end ## # Is there any content? # # This means any of: comment, aliases, methods, attributes, external # aliases, require, constant. # # Includes and extends are also checked unless includes == false. def any_content(includes = true) @any_content ||= !( @comment.empty? && @method_list.empty? && @attributes.empty? && @aliases.empty? && @external_aliases.empty? && @requires.empty? && @constants.empty? ) @any_content || (includes && !(@includes + @extends).empty? ) end ## # Creates the full name for a child with +name+ def child_name name if name =~ /^:+/ $' #' elsif RDoc::TopLevel === self then name else "#{self.full_name}::#{name}" end end ## # Class attributes def class_attributes @class_attributes ||= attributes.select { |a| a.singleton } end ## # Class methods def class_method_list @class_method_list ||= method_list.select { |a| a.singleton } end ## # Array of classes in this context def classes @classes.values end ## # All classes and modules in this namespace def classes_and_modules classes + modules end ## # Hash of classes keyed by class name def classes_hash @classes end ## # The current documentation section that new items will be added to. If # temporary_section is available it will be used. def current_section if section = @temporary_section then @temporary_section = nil else section = @current_section end section end ## # Is part of this thing was defined in +file+? def defined_in?(file) @in_files.include?(file) end def display(method_attr) # :nodoc: if method_attr.is_a? RDoc::Attr "#{method_attr.definition} #{method_attr.pretty_name}" else "method #{method_attr.pretty_name}" end end ## # Iterator for ancestors for duck-typing. Does nothing. See # RDoc::ClassModule#each_ancestor. # # This method exists to make it easy to work with Context subclasses that # aren't part of RDoc. def each_ancestor # :nodoc: end ## # Iterator for attributes def each_attribute # :yields: attribute @attributes.each { |a| yield a } end ## # Iterator for classes and modules def each_classmodule(&block) # :yields: module classes_and_modules.sort.each(&block) end ## # Iterator for constants def each_constant # :yields: constant @constants.each {|c| yield c} end ## # Iterator for included modules def each_include # :yields: include @includes.each do |i| yield i end end ## # Iterator for extension modules def each_extend # :yields: extend @extends.each do |e| yield e end end ## # Iterator for methods def each_method # :yields: method return enum_for __method__ unless block_given? @method_list.sort.each { |m| yield m } end ## # Iterator for each section's contents sorted by title. The +section+, the # section's +constants+ and the sections +attributes+ are yielded. The # +constants+ and +attributes+ collections are sorted. # # To retrieve methods in a section use #methods_by_type with the optional # +section+ parameter. # # NOTE: Do not edit collections yielded by this method def each_section # :yields: section, constants, attributes return enum_for __method__ unless block_given? constants = @constants.group_by do |constant| constant.section end attributes = @attributes.group_by do |attribute| attribute.section end constants.default = [] attributes.default = [] sort_sections.each do |section| yield section, constants[section].select(&:display?).sort, attributes[section].select(&:display?).sort end end ## # Finds an attribute +name+ with singleton value +singleton+. def find_attribute(name, singleton) name = $1 if name =~ /^(.*)=$/ @attributes.find { |a| a.name == name && a.singleton == singleton } end ## # Finds an attribute with +name+ in this context def find_attribute_named(name) case name when /\A#/ then find_attribute name[1..-1], false when /\A::/ then find_attribute name[2..-1], true else @attributes.find { |a| a.name == name } end end ## # Finds a class method with +name+ in this context def find_class_method_named(name) @method_list.find { |meth| meth.singleton && meth.name == name } end ## # Finds a constant with +name+ in this context def find_constant_named(name) @constants.find do |m| m.name == name || m.full_name == name end end ## # Find a module at a higher scope def find_enclosing_module_named(name) parent && parent.find_module_named(name) end ## # Finds an external alias +name+ with singleton value +singleton+. def find_external_alias(name, singleton) @external_aliases.find { |m| m.name == name && m.singleton == singleton } end ## # Finds an external alias with +name+ in this context def find_external_alias_named(name) case name when /\A#/ then find_external_alias name[1..-1], false when /\A::/ then find_external_alias name[2..-1], true else @external_aliases.find { |a| a.name == name } end end ## # Finds a file with +name+ in this context def find_file_named name @store.find_file_named name end ## # Finds an instance method with +name+ in this context def find_instance_method_named(name) @method_list.find { |meth| !meth.singleton && meth.name == name } end ## # Finds a method, constant, attribute, external alias, module or file # named +symbol+ in this context. def find_local_symbol(symbol) find_method_named(symbol) or find_constant_named(symbol) or find_attribute_named(symbol) or find_external_alias_named(symbol) or find_module_named(symbol) or find_file_named(symbol) end ## # Finds a method named +name+ with singleton value +singleton+. def find_method(name, singleton) @method_list.find { |m| if m.singleton m.name == name && m.singleton == singleton else m.name == name && !m.singleton && !singleton end } end ## # Finds a instance or module method with +name+ in this context def find_method_named(name) case name when /\A#/ then find_method name[1..-1], false when /\A::/ then find_method name[2..-1], true else @method_list.find { |meth| meth.name == name } end end ## # Find a module with +name+ using ruby's scoping rules def find_module_named(name) res = @modules[name] || @classes[name] return res if res return self if self.name == name find_enclosing_module_named name end ## # Look up +symbol+, first as a module, then as a local symbol. def find_symbol(symbol) find_symbol_module(symbol) || find_local_symbol(symbol) end ## # Look up a module named +symbol+. def find_symbol_module(symbol) result = nil # look for a class or module 'symbol' case symbol when /^::/ then result = @store.find_class_or_module symbol when /^(\w+):+(.+)$/ suffix = $2 top = $1 searched = self while searched do mod = searched.find_module_named(top) break unless mod result = @store.find_class_or_module "#{mod.full_name}::#{suffix}" break if result || searched.is_a?(RDoc::TopLevel) searched = searched.parent end else searched = self while searched do result = searched.find_module_named(symbol) break if result || searched.is_a?(RDoc::TopLevel) searched = searched.parent end end result end ## # The full name for this context. This method is overridden by subclasses. def full_name '(unknown)' end ## # Does this context and its methods and constants all have documentation? # # (Yes, fully documented doesn't mean everything.) def fully_documented? documented? and attributes.all? { |a| a.documented? } and method_list.all? { |m| m.documented? } and constants.all? { |c| c.documented? } end ## # URL for this with a +prefix+ def http_url(prefix) path = name_for_path path = path.gsub(/<<\s*(\w*)/, 'from-\1') if path =~ /<'class' or # 'instance') and visibility (+:public+, +:protected+, +:private+). # # If +section+ is provided only methods in that RDoc::Context::Section will # be returned. def methods_by_type section = nil methods = {} TYPES.each do |type| visibilities = {} RDoc::VISIBILITIES.each do |vis| visibilities[vis] = [] end methods[type] = visibilities end each_method do |method| next if section and not method.section == section methods[method.type][method.visibility] << method end methods end ## # Yields AnyMethod and Attr entries matching the list of names in +methods+. def methods_matching(methods, singleton = false, &block) (@method_list + @attributes).each do |m| yield m if methods.include?(m.name) and m.singleton == singleton end each_ancestor do |parent| parent.methods_matching(methods, singleton, &block) end end ## # Array of modules in this context def modules @modules.values end ## # Hash of modules keyed by module name def modules_hash @modules end ## # Name to use to generate the url. # #full_name by default. def name_for_path full_name end ## # Changes the visibility for new methods to +visibility+ def ongoing_visibility=(visibility) @visibility = visibility end ## # Record +top_level+ as a file +self+ is in. def record_location(top_level) @in_files << top_level unless @in_files.include?(top_level) end ## # Should we remove this context from the documentation? # # The answer is yes if: # * #received_nodoc is +true+ # * #any_content is +false+ (not counting includes) # * All #includes are modules (not a string), and their module has # #remove_from_documentation? == true # * All classes and modules have #remove_from_documentation? == true def remove_from_documentation? @remove_from_documentation ||= @received_nodoc && !any_content(false) && @includes.all? { |i| !i.module.is_a?(String) && i.module.remove_from_documentation? } && classes_and_modules.all? { |cm| cm.remove_from_documentation? } end ## # Removes methods and attributes with a visibility less than +min_visibility+. #-- # TODO mark the visibility of attributes in the template (if not public?) def remove_invisible min_visibility return if [:private, :nodoc].include? min_visibility remove_invisible_in @method_list, min_visibility remove_invisible_in @attributes, min_visibility remove_invisible_in @constants, min_visibility end ## # Only called when min_visibility == :public or :private def remove_invisible_in array, min_visibility # :nodoc: if min_visibility == :public then array.reject! { |e| e.visibility != :public and not e.force_documentation } else array.reject! { |e| e.visibility == :private and not e.force_documentation } end end ## # Tries to resolve unmatched aliases when a method or attribute has just # been added. def resolve_aliases added # resolve any pending unmatched aliases key = added.pretty_name unmatched_alias_list = @unmatched_alias_lists[key] return unless unmatched_alias_list unmatched_alias_list.each do |unmatched_alias| added.add_alias unmatched_alias, self @external_aliases.delete unmatched_alias end @unmatched_alias_lists.delete key end ## # Returns RDoc::Context::Section objects referenced in this context for use # in a table of contents. def section_contents used_sections = {} each_method do |method| next unless method.display? used_sections[method.section] = true end # order found sections sections = sort_sections.select do |section| used_sections[section] end # only the default section is used return [] if sections.length == 1 and not sections.first.title sections end ## # Sections in this context def sections @sections.values end def sections_hash # :nodoc: @sections end ## # Sets the current section to a section with +title+. See also #add_section def set_current_section title, comment @current_section = add_section title, comment end ## # Given an array +methods+ of method names, set the visibility of each to # +visibility+ def set_visibility_for(methods, visibility, singleton = false) methods_matching methods, singleton do |m| m.visibility = visibility end end ## # Given an array +names+ of constants, set the visibility of each constant to # +visibility+ def set_constant_visibility_for(names, visibility) names.each do |name| constant = @constants_hash[name] or next constant.visibility = visibility end end ## # Sorts sections alphabetically (default) or in TomDoc fashion (none, # Public, Internal, Deprecated) def sort_sections titles = @sections.map { |title, _| title } if titles.length > 1 and TOMDOC_TITLES_SORT == (titles | TOMDOC_TITLES).sort_by { |title| title.to_s } then @sections.values_at(*TOMDOC_TITLES).compact else @sections.sort_by { |title, _| title.to_s }.map { |_, section| section } end end def to_s # :nodoc: "#{self.class.name} #{self.full_name}" end ## # Return the TopLevel that owns us #-- # FIXME we can be 'owned' by several TopLevel (see #record_location & # #in_files) def top_level return @top_level if defined? @top_level @top_level = self @top_level = @top_level.parent until RDoc::TopLevel === @top_level @top_level end ## # Upgrades NormalModule +mod+ in +enclosing+ to a +class_type+ def upgrade_to_class mod, class_type, enclosing enclosing.modules_hash.delete mod.name klass = RDoc::ClassModule.from_module class_type, mod klass.store = @store # if it was there, then we keep it even if done_documenting @store.classes_hash[mod.full_name] = klass enclosing.classes_hash[mod.name] = klass klass end autoload :Section, 'rdoc/context/section' end PKu]FvEErdoc-6.2.1.1/lib/rdoc/rd.rbnu[# frozen_string_literal: true ## # RDoc::RD implements the RD format from the rdtool gem. # # To choose RD as your only default format see # RDoc::Options@Saved+Options for instructions on setting up a # .doc_options file to store your project default. # # == LICENSE # # The grammar that produces RDoc::RD::BlockParser and RDoc::RD::InlineParser # is included in RDoc under the Ruby License. # # You can find the original source for rdtool at # https://github.com/uwabami/rdtool/ # # You can use, re-distribute or change these files under Ruby's License or GPL. # # 1. You may make and give away verbatim copies of the source form of the # software without restriction, provided that you duplicate all of the # original copyright notices and associated disclaimers. # # 2. You may modify your copy of the software in any way, provided that # you do at least ONE of the following: # # a. place your modifications in the Public Domain or otherwise # make them Freely Available, such as by posting said # modifications to Usenet or an equivalent medium, or by allowing # the author to include your modifications in the software. # # b. use the modified software only within your corporation or # organization. # # c. give non-standard binaries non-standard names, with # instructions on where to get the original software distribution. # # d. make other distribution arrangements with the author. # # 3. You may distribute the software in object code or binary form, # provided that you do at least ONE of the following: # # a. distribute the binaries and library files of the software, # together with instructions (in the manual page or equivalent) # on where to get the original distribution. # # b. accompany the distribution with the machine-readable source of # the software. # # c. give non-standard binaries non-standard names, with # instructions on where to get the original software distribution. # # d. make other distribution arrangements with the author. # # 4. You may modify and include the part of the software into any other # software (possibly commercial). But some files in the distribution # are not written by the author, so that they are not under these terms. # # For the list of those files and their copying conditions, see the # file LEGAL. # # 5. The scripts and library files supplied as input to or produced as # output from the software do not automatically fall under the # copyright of the software, but belong to whomever generated them, # and may be sold commercially, and may be aggregated with this # software. # # 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE. class RDoc::RD ## # Parses +rd+ source and returns an RDoc::Markup::Document. If the # =begin or =end lines are missing they will be added. def self.parse rd rd = rd.lines.to_a if rd.find { |i| /\S/ === i } and !rd.find{|i| /^=begin\b/ === i } then rd.unshift("=begin\n").push("=end\n") end parser = RDoc::RD::BlockParser.new document = parser.parse rd # isn't this always true? document.parts.shift if RDoc::Markup::BlankLine === document.parts.first document.parts.pop if RDoc::Markup::BlankLine === document.parts.last document end autoload :BlockParser, 'rdoc/rd/block_parser' autoload :InlineParser, 'rdoc/rd/inline_parser' autoload :Inline, 'rdoc/rd/inline' end PKu]533rdoc-6.2.1.1/lib/rdoc/parser.rbnu[# -*- coding: us-ascii -*- # frozen_string_literal: true ## # A parser is simple a class that subclasses RDoc::Parser and implements #scan # to fill in an RDoc::TopLevel with parsed data. # # The initialize method takes an RDoc::TopLevel to fill with parsed content, # the name of the file to be parsed, the content of the file, an RDoc::Options # object and an RDoc::Stats object to inform the user of parsed items. The # scan method is then called to parse the file and must return the # RDoc::TopLevel object. By calling super these items will be set for you. # # In order to be used by RDoc the parser needs to register the file extensions # it can parse. Use ::parse_files_matching to register extensions. # # require 'rdoc' # # class RDoc::Parser::Xyz < RDoc::Parser # parse_files_matching /\.xyz$/ # # def initialize top_level, file_name, content, options, stats # super # # # extra initialization if needed # end # # def scan # # parse file and fill in @top_level # end # end class RDoc::Parser @parsers = [] class << self ## # An Array of arrays that maps file extension (or name) regular # expressions to parser classes that will parse matching filenames. # # Use parse_files_matching to register a parser's file extensions. attr_reader :parsers end ## # The name of the file being parsed attr_reader :file_name ## # Alias an extension to another extension. After this call, files ending # "new_ext" will be parsed using the same parser as "old_ext" def self.alias_extension(old_ext, new_ext) old_ext = old_ext.sub(/^\.(.*)/, '\1') new_ext = new_ext.sub(/^\.(.*)/, '\1') parser = can_parse_by_name "xxx.#{old_ext}" return false unless parser RDoc::Parser.parsers.unshift [/\.#{new_ext}$/, parser] true end ## # Determines if the file is a "binary" file which basically means it has # content that an RDoc parser shouldn't try to consume. def self.binary?(file) return false if file =~ /\.(rdoc|txt)$/ s = File.read(file, 1024) or return false return true if s[0, 2] == Marshal.dump('')[0, 2] or s.index("\x00") mode = 'r:utf-8' # default source encoding has been chagened to utf-8 s.sub!(/\A#!.*\n/, '') # assume shebang line isn't longer than 1024. encoding = s[/^\s*\#\s*(?:-\*-\s*)?(?:en)?coding:\s*([^\s;]+?)(?:-\*-|[\s;])/, 1] mode = "rb:#{encoding}" if encoding s = File.open(file, mode) {|f| f.gets(nil, 1024)} not s.valid_encoding? end ## # Checks if +file+ is a zip file in disguise. Signatures from # http://www.garykessler.net/library/file_sigs.html def self.zip? file zip_signature = File.read file, 4 zip_signature == "PK\x03\x04" or zip_signature == "PK\x05\x06" or zip_signature == "PK\x07\x08" rescue false end ## # Return a parser that can handle a particular extension def self.can_parse file_name parser = can_parse_by_name file_name # HACK Selenium hides a jar file using a .txt extension return if parser == RDoc::Parser::Simple and zip? file_name parser end ## # Returns a parser that can handle the extension for +file_name+. This does # not depend upon the file being readable. def self.can_parse_by_name file_name _, parser = RDoc::Parser.parsers.find { |regexp,| regexp =~ file_name } # The default parser must not parse binary files ext_name = File.extname file_name return parser if ext_name.empty? if parser == RDoc::Parser::Simple and ext_name !~ /txt|rdoc/ then case check_modeline file_name when nil, 'rdoc' then # continue else return nil end end parser rescue Errno::EACCES end ## # Returns the file type from the modeline in +file_name+ def self.check_modeline file_name line = File.open file_name do |io| io.gets end /-\*-\s*(.*?\S)\s*-\*-/ =~ line return nil unless type = $1 if /;/ =~ type then return nil unless /(?:\s|\A)mode:\s*([^\s;]+)/i =~ type type = $1 end return nil if /coding:/i =~ type type.downcase rescue ArgumentError rescue Encoding::InvalidByteSequenceError # invalid byte sequence end ## # Finds and instantiates the correct parser for the given +file_name+ and # +content+. def self.for top_level, file_name, content, options, stats return if binary? file_name parser = use_markup content unless parser then parse_name = file_name # If no extension, look for shebang if file_name !~ /\.\w+$/ && content =~ %r{\A#!(.+)} then shebang = $1 case shebang when %r{env\s+ruby}, %r{/ruby} parse_name = 'dummy.rb' end end parser = can_parse parse_name end return unless parser content = remove_modeline content parser.new top_level, file_name, content, options, stats rescue SystemCallError nil end ## # Record which file types this parser can understand. # # It is ok to call this multiple times. def self.parse_files_matching(regexp) RDoc::Parser.parsers.unshift [regexp, self] end ## # Removes an emacs-style modeline from the first line of the document def self.remove_modeline content content.sub(/\A.*-\*-\s*(.*?\S)\s*-\*-.*\r?\n/, '') end ## # If there is a markup: parser_name comment at the front of the # file, use it to determine the parser. For example: # # # markup: rdoc # # Class comment can go here # # class C # end # # The comment should appear as the first line of the +content+. # # If the content contains a shebang or editor modeline the comment may # appear on the second or third line. # # Any comment style may be used to hide the markup comment. def self.use_markup content markup = content.lines.first(3).grep(/markup:\s+(\w+)/) { $1 }.first return unless markup # TODO Ruby should be returned only when the filename is correct return RDoc::Parser::Ruby if %w[tomdoc markdown].include? markup markup = Regexp.escape markup _, selected = RDoc::Parser.parsers.find do |_, parser| /^#{markup}$/i =~ parser.name.sub(/.*:/, '') end selected end ## # Creates a new Parser storing +top_level+, +file_name+, +content+, # +options+ and +stats+ in instance variables. In +@preprocess+ an # RDoc::Markup::PreProcess object is created which allows processing of # directives. def initialize top_level, file_name, content, options, stats @top_level = top_level @top_level.parser = self.class @store = @top_level.store @file_name = file_name @content = content @options = options @stats = stats @preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include @preprocess.options = @options end autoload :RubyTools, 'rdoc/parser/ruby_tools' autoload :Text, 'rdoc/parser/text' end # simple must come first in order to show up last in the parsers list require 'rdoc/parser/simple' require 'rdoc/parser/c' require 'rdoc/parser/changelog' require 'rdoc/parser/markdown' require 'rdoc/parser/rd' require 'rdoc/parser/ruby' PKu]m|`rdoc-6.2.1.1/lib/rdoc/i18n.rbnu[# frozen_string_literal: true ## # This module provides i18n related features. module RDoc::I18n autoload :Locale, 'rdoc/i18n/locale' require 'rdoc/i18n/text' end PKu]H"--"rdoc-6.2.1.1/lib/rdoc/top_level.rbnu[# frozen_string_literal: true ## # A TopLevel context is a representation of the contents of a single file class RDoc::TopLevel < RDoc::Context MARSHAL_VERSION = 0 # :nodoc: ## # This TopLevel's File::Stat struct attr_accessor :file_stat ## # Relative name of this file attr_accessor :relative_name ## # Absolute name of this file attr_accessor :absolute_name ## # All the classes or modules that were declared in # this file. These are assigned to either +#classes_hash+ # or +#modules_hash+ once we know what they really are. attr_reader :classes_or_modules attr_accessor :diagram # :nodoc: ## # The parser class that processed this file attr_reader :parser ## # Creates a new TopLevel for the file at +absolute_name+. If documentation # is being generated outside the source dir +relative_name+ is relative to # the source directory. def initialize absolute_name, relative_name = absolute_name super() @name = nil @absolute_name = absolute_name @relative_name = relative_name @file_stat = File.stat(absolute_name) rescue nil # HACK for testing @diagram = nil @parser = nil @classes_or_modules = [] end def parser=(val) @parser = val @store.update_parser_of_file(absolute_name, val) if @store @parser end ## # An RDoc::TopLevel is equal to another with the same relative_name def == other self.class === other and @relative_name == other.relative_name end alias eql? == ## # Adds +an_alias+ to +Object+ instead of +self+. def add_alias(an_alias) object_class.record_location self return an_alias unless @document_self object_class.add_alias an_alias end ## # Adds +constant+ to +Object+ instead of +self+. def add_constant constant object_class.record_location self return constant unless @document_self object_class.add_constant constant end ## # Adds +include+ to +Object+ instead of +self+. def add_include(include) object_class.record_location self return include unless @document_self object_class.add_include include end ## # Adds +method+ to +Object+ instead of +self+. def add_method(method) object_class.record_location self return method unless @document_self object_class.add_method method end ## # Adds class or module +mod+. Used in the building phase # by the Ruby parser. def add_to_classes_or_modules mod @classes_or_modules << mod end ## # Base name of this file def base_name File.basename @relative_name end alias name base_name ## # Only a TopLevel that contains text file) will be displayed. See also # RDoc::CodeObject#display? def display? text? and super end ## # See RDoc::TopLevel::find_class_or_module #-- # TODO Why do we search through all classes/modules found, not just the # ones of this instance? def find_class_or_module name @store.find_class_or_module name end ## # Finds a class or module named +symbol+ def find_local_symbol(symbol) find_class_or_module(symbol) || super end ## # Finds a module or class with +name+ def find_module_named(name) find_class_or_module(name) end ## # Returns the relative name of this file def full_name @relative_name end ## # An RDoc::TopLevel has the same hash as another with the same # relative_name def hash @relative_name.hash end ## # URL for this with a +prefix+ def http_url(prefix) path = [prefix, @relative_name.tr('.', '_')] File.join(*path.compact) + '.html' end def inspect # :nodoc: "#<%s:0x%x %p modules: %p classes: %p>" % [ self.class, object_id, base_name, @modules.map { |n,m| m }, @classes.map { |n,c| c } ] end ## # Time this file was last modified, if known def last_modified @file_stat ? file_stat.mtime : nil end ## # Dumps this TopLevel for use by ri. See also #marshal_load def marshal_dump [ MARSHAL_VERSION, @relative_name, @parser, parse(@comment), ] end ## # Loads this TopLevel from +array+. def marshal_load array # :nodoc: initialize array[1] @parser = array[2] @comment = array[3] @file_stat = nil end ## # Returns the NormalClass "Object", creating it if not found. # # Records +self+ as a location in "Object". def object_class @object_class ||= begin oc = @store.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object') oc.record_location self oc end end ## # Base name of this file without the extension def page_name basename = File.basename @relative_name basename =~ /\.(rb|rdoc|txt|md)$/i $` || basename end ## # Path to this file for use with HTML generator output. def path http_url @store.rdoc.generator.file_dir end def pretty_print q # :nodoc: q.group 2, "[#{self.class}: ", "]" do q.text "base name: #{base_name.inspect}" q.breakable items = @modules.map { |n,m| m } items.concat @modules.map { |n,c| c } q.seplist items do |mod| q.pp mod end end end ## # Search record used by RDoc::Generator::JsonIndex def search_record return unless @parser < RDoc::Parser::Text [ page_name, '', page_name, '', path, '', snippet(@comment), ] end ## # Is this TopLevel from a text file instead of a source code file? def text? @parser and @parser.include? RDoc::Parser::Text end def to_s # :nodoc: "file #{full_name}" end end PKu]󈗢&rdoc-6.2.1.1/lib/rdoc/normal_module.rbnu[# frozen_string_literal: true ## # A normal module, like NormalClass class RDoc::NormalModule < RDoc::ClassModule def aref_prefix # :nodoc: 'module' end def inspect # :nodoc: "#<%s:0x%x module %s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [ self.class, object_id, full_name, @includes, @extends, @attributes, @method_list, @aliases ] end ## # The definition of this module, module MyModuleName def definition "module #{full_name}" end ## # This is a module, returns true def module? true end def pretty_print q # :nodoc: q.group 2, "[module #{full_name}: ", "]" do q.breakable q.text "includes:" q.breakable q.seplist @includes do |inc| q.pp inc end q.breakable q.breakable q.text "constants:" q.breakable q.seplist @constants do |const| q.pp const end q.text "attributes:" q.breakable q.seplist @attributes do |attr| q.pp attr end q.breakable q.text "methods:" q.breakable q.seplist @method_list do |meth| q.pp meth end q.breakable q.text "aliases:" q.breakable q.seplist @aliases do |aliaz| q.pp aliaz end q.breakable q.text "comment:" q.breakable q.pp comment end end ## # Modules don't have one, raises NoMethodError def superclass raise NoMethodError, "#{full_name} is a module" end end PKu]|y%rdoc-6.2.1.1/lib/rdoc/single_class.rbnu[# frozen_string_literal: true ## # A singleton class class RDoc::SingleClass < RDoc::ClassModule ## # Adds the superclass to the included modules. def ancestors superclass ? super + [superclass] : super end def aref_prefix # :nodoc: 'sclass' end ## # The definition of this singleton class, class << MyClassName def definition "class << #{full_name}" end end PKu]Ԣ&&#rdoc-6.2.1.1/lib/rdoc/any_method.rbnu[# frozen_string_literal: true ## # AnyMethod is the base class for objects representing methods class RDoc::AnyMethod < RDoc::MethodAttr ## # 2:: # RDoc 4 # Added calls_super # Added parent name and class # Added section title # 3:: # RDoc 4.1 # Added is_alias_for MARSHAL_VERSION = 3 # :nodoc: ## # Don't rename \#initialize to \::new attr_accessor :dont_rename_initialize ## # The C function that implements this method (if it was defined in a C file) attr_accessor :c_function ## # Different ways to call this method attr_reader :call_seq ## # Parameters for this method attr_accessor :params ## # If true this method uses +super+ to call a superclass version attr_accessor :calls_super include RDoc::TokenStream ## # Creates a new AnyMethod with a token stream +text+ and +name+ def initialize text, name super @c_function = nil @dont_rename_initialize = false @token_stream = nil @calls_super = false @superclass_method = nil end ## # Adds +an_alias+ as an alias for this method in +context+. def add_alias an_alias, context = nil method = self.class.new an_alias.text, an_alias.new_name method.record_location an_alias.file method.singleton = self.singleton method.params = self.params method.visibility = self.visibility method.comment = an_alias.comment method.is_alias_for = self @aliases << method context.add_method method if context method end ## # Prefix for +aref+ is 'method'. def aref_prefix 'method' end ## # The call_seq or the param_seq with method name, if there is no call_seq. # # Use this for displaying a method's argument lists. def arglists if @call_seq then @call_seq elsif @params then "#{name}#{param_seq}" end end ## # Sets the different ways you can call this method. If an empty +call_seq+ # is given nil is assumed. # # See also #param_seq def call_seq= call_seq return if call_seq.empty? @call_seq = call_seq end ## # Loads is_alias_for from the internal name. Returns nil if the alias # cannot be found. def is_alias_for # :nodoc: case @is_alias_for when RDoc::MethodAttr then @is_alias_for when Array then return nil unless @store klass_name, singleton, method_name = @is_alias_for return nil unless klass = @store.find_class_or_module(klass_name) @is_alias_for = klass.find_method method_name, singleton end end ## # Dumps this AnyMethod for use by ri. See also #marshal_load def marshal_dump aliases = @aliases.map do |a| [a.name, parse(a.comment)] end is_alias_for = [ @is_alias_for.parent.full_name, @is_alias_for.singleton, @is_alias_for.name ] if @is_alias_for [ MARSHAL_VERSION, @name, full_name, @singleton, @visibility, parse(@comment), @call_seq, @block_params, aliases, @params, @file.relative_name, @calls_super, @parent.name, @parent.class, @section.title, is_alias_for, ] end ## # Loads this AnyMethod from +array+. For a loaded AnyMethod the following # methods will return cached values: # # * #full_name # * #parent_name def marshal_load array initialize_visibility @dont_rename_initialize = nil @token_stream = nil @aliases = [] @parent = nil @parent_name = nil @parent_class = nil @section = nil @file = nil version = array[0] @name = array[1] @full_name = array[2] @singleton = array[3] @visibility = array[4] @comment = array[5] @call_seq = array[6] @block_params = array[7] # 8 handled below @params = array[9] # 10 handled below @calls_super = array[11] @parent_name = array[12] @parent_title = array[13] @section_title = array[14] @is_alias_for = array[15] array[8].each do |new_name, comment| add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton) end @parent_name ||= if @full_name =~ /#/ then $` else name = @full_name.split('::') name.pop name.join '::' end @file = RDoc::TopLevel.new array[10] if version > 0 end ## # Method name # # If the method has no assigned name, it extracts it from #call_seq. def name return @name if @name @name = @call_seq[/^.*?\.(\w+)/, 1] || @call_seq[/^.*?(\w+)/, 1] || @call_seq if @call_seq end ## # A list of this method's method and yield parameters. +call-seq+ params # are preferred over parsed method and block params. def param_list if @call_seq then params = @call_seq.split("\n").last params = params.sub(/.*?\((.*)\)/, '\1') params = params.sub(/(\{|do)\s*\|([^|]*)\|.*/, ',\2') elsif @params then params = @params.sub(/\((.*)\)/, '\1') params << ",#{@block_params}" if @block_params elsif @block_params then params = @block_params else return [] end if @block_params then # If this method has explicit block parameters, remove any explicit # &block params = params.sub(/,?\s*&\w+/, '') else params = params.sub(/\&(\w+)/, '\1') end params = params.gsub(/\s+/, '').split(',').reject(&:empty?) params.map { |param| param.sub(/=.*/, '') } end ## # Pretty parameter list for this method. If the method's parameters were # given by +call-seq+ it is preferred over the parsed values. def param_seq if @call_seq then params = @call_seq.split("\n").last params = params.sub(/[^( ]+/, '') params = params.sub(/(\|[^|]+\|)\s*\.\.\.\s*(end|\})/, '\1 \2') elsif @params then params = @params.gsub(/\s*\#.*/, '') params = params.tr_s("\n ", " ") params = "(#{params})" unless params[0] == ?( else params = '' end if @block_params then # If this method has explicit block parameters, remove any explicit # &block params = params.sub(/,?\s*&\w+/, '') block = @block_params.tr_s("\n ", " ") if block[0] == ?( block = block.sub(/^\(/, '').sub(/\)/, '') end params << " { |#{block}| ... }" end params end ## # Sets the store for this method and its referenced code objects. def store= store super @file = @store.add_file @file.full_name if @file end ## # For methods that +super+, find the superclass method that would be called. def superclass_method return unless @calls_super return @superclass_method if @superclass_method parent.each_ancestor do |ancestor| if method = ancestor.method_list.find { |m| m.name == @name } then @superclass_method = method break end end @superclass_method end end PKu]c7 rdoc-6.2.1.1/lib/rdoc/comment.rbnu[# frozen_string_literal: true ## # A comment holds the text comment for a RDoc::CodeObject and provides a # unified way of cleaning it up and parsing it into an RDoc::Markup::Document. # # Each comment may have a different markup format set by #format=. By default # 'rdoc' is used. The :markup: directive tells RDoc which format to use. # # See RDoc::Markup@Other+directives for instructions on adding an alternate # format. class RDoc::Comment include RDoc::Text ## # The format of this comment. Defaults to RDoc::Markup attr_reader :format ## # The RDoc::TopLevel this comment was found in attr_accessor :location ## # Line where this Comment was written attr_accessor :line ## # For duck-typing when merging classes at load time alias file location # :nodoc: ## # The text for this comment attr_reader :text ## # Alias for text alias to_s text ## # Overrides the content returned by #parse. Use when there is no #text # source for this comment attr_writer :document ## # Creates a new comment with +text+ that is found in the RDoc::TopLevel # +location+. def initialize text = nil, location = nil, language = nil @location = location @text = text.nil? ? nil : text.dup @language = language @document = nil @format = 'rdoc' @normalized = false end ## #-- # TODO deep copy @document def initialize_copy copy # :nodoc: @text = copy.text.dup end def == other # :nodoc: self.class === other and other.text == @text and other.location == @location end ## # Look for a 'call-seq' in the comment to override the normal parameter # handling. The :call-seq: is indented from the baseline. All lines of the # same indentation level and prefix are consumed. # # For example, all of the following will be used as the :call-seq: # # # :call-seq: # # ARGF.readlines(sep=$/) -> array # # ARGF.readlines(limit) -> array # # ARGF.readlines(sep, limit) -> array # # # # ARGF.to_a(sep=$/) -> array # # ARGF.to_a(limit) -> array # # ARGF.to_a(sep, limit) -> array def extract_call_seq method # we must handle situations like the above followed by an unindented first # comment. The difficulty is to make sure not to match lines starting # with ARGF at the same indent, but that are after the first description # paragraph. if @text =~ /^\s*:?call-seq:(.*?(?:\S).*?)^\s*$/m then all_start, all_stop = $~.offset(0) seq_start, seq_stop = $~.offset(1) # we get the following lines that start with the leading word at the # same indent, even if they have blank lines before if $1 =~ /(^\s*\n)+^(\s*\w+)/m then leading = $2 # ' * ARGF' in the example above re = %r% \A( (^\s*\n)+ (^#{Regexp.escape leading}.*?\n)+ )+ ^\s*$ %xm if @text[seq_stop..-1] =~ re then all_stop = seq_stop + $~.offset(0).last seq_stop = seq_stop + $~.offset(1).last end end seq = @text[seq_start..seq_stop] seq.gsub!(/^\s*(\S|\n)/m, '\1') @text.slice! all_start...all_stop method.call_seq = seq.chomp else regexp = /^\s*:?call-seq:(.*?)(^\s*$|\z)/m if regexp =~ @text then @text = @text.sub(regexp, '') seq = $1 seq.gsub!(/^\s*/, '') method.call_seq = seq end end method end ## # A comment is empty if its text String is empty. def empty? @text.empty? end ## # HACK dubious def encode! encoding # TODO: Remove this condition after Ruby 2.2 EOL if RUBY_VERSION < '2.3.0' @text = @text.force_encoding encoding else @text = String.new @text, encoding: encoding end self end ## # Sets the format of this comment and resets any parsed document def format= format @format = format @document = nil end def inspect # :nodoc: location = @location ? @location.relative_name : '(unknown)' "#<%s:%x %s %p>" % [self.class, object_id, location, @text] end ## # Normalizes the text. See RDoc::Text#normalize_comment for details def normalize return self unless @text return self if @normalized # TODO eliminate duplicate normalization @text = normalize_comment @text @normalized = true self end ## # Was this text normalized? def normalized? # :nodoc: @normalized end ## # Parses the comment into an RDoc::Markup::Document. The parsed document is # cached until the text is changed. def parse return @document if @document @document = super @text, @format @document.file = @location @document end ## # Removes private sections from this comment. Private sections are flush to # the comment marker and start with -- and end with ++. # For C-style comments, a private marker may not start at the opening of the # comment. # # /* # *-- # * private # *++ # * public # */ def remove_private # Workaround for gsub encoding for Ruby 1.9.2 and earlier empty = '' empty = RDoc::Encoding.change_encoding empty, @text.encoding @text = @text.gsub(%r%^\s*([#*]?)--.*?^\s*(\1)\+\+\n?%m, empty) @text = @text.sub(%r%^\s*[#*]?--.*%m, '') end ## # Replaces this comment's text with +text+ and resets the parsed document. # # An error is raised if the comment contains a document but no text. def text= text raise RDoc::Error, 'replacing document-only comment is not allowed' if @text.nil? and @document @document = nil @text = text.nil? ? nil : text.dup end ## # Returns true if this comment is in TomDoc format. def tomdoc? @format == 'tomdoc' end end PKu]VU} } &rdoc-6.2.1.1/lib/rdoc/known_classes.rbnu[# frozen_string_literal: true module RDoc ## # Ruby's built-in classes, modules and exceptions KNOWN_CLASSES = { "rb_cArray" => "Array", "rb_cBasicObject" => "BasicObject", "rb_cBignum" => "Bignum", "rb_cClass" => "Class", "rb_cData" => "Data", "rb_cDir" => "Dir", "rb_cEncoding" => "Encoding", "rb_cFalseClass" => "FalseClass", "rb_cFile" => "File", "rb_cFixnum" => "Fixnum", "rb_cFloat" => "Float", "rb_cHash" => "Hash", "rb_cIO" => "IO", "rb_cInteger" => "Integer", "rb_cModule" => "Module", "rb_cNilClass" => "NilClass", "rb_cNumeric" => "Numeric", "rb_cObject" => "Object", "rb_cProc" => "Proc", "rb_cRange" => "Range", "rb_cRegexp" => "Regexp", "rb_cRubyVM" => "RubyVM", "rb_cSocket" => "Socket", "rb_cString" => "String", "rb_cStruct" => "Struct", "rb_cSymbol" => "Symbol", "rb_cThread" => "Thread", "rb_cTime" => "Time", "rb_cTrueClass" => "TrueClass", "rb_eArgError" => "ArgError", "rb_eEOFError" => "EOFError", "rb_eException" => "Exception", "rb_eFatal" => "fatal", "rb_eFloatDomainError" => "FloatDomainError", "rb_eIOError" => "IOError", "rb_eIndexError" => "IndexError", "rb_eInterrupt" => "Interrupt", "rb_eLoadError" => "LoadError", "rb_eNameError" => "NameError", "rb_eNoMemError" => "NoMemError", "rb_eNotImpError" => "NotImpError", "rb_eRangeError" => "RangeError", "rb_eRuntimeError" => "RuntimeError", "rb_eScriptError" => "ScriptError", "rb_eSecurityError" => "SecurityError", "rb_eSignal" => "SignalException", "rb_eStandardError" => "StandardError", "rb_eSyntaxError" => "SyntaxError", "rb_eSystemCallError" => "SystemCallError", "rb_eSystemExit" => "SystemExit", "rb_eTypeError" => "TypeError", "rb_eZeroDivError" => "ZeroDivError", "rb_mComparable" => "Comparable", "rb_mEnumerable" => "Enumerable", "rb_mErrno" => "Errno", "rb_mFConst" => "File::Constants", "rb_mFileTest" => "FileTest", "rb_mGC" => "GC", "rb_mKernel" => "Kernel", "rb_mMath" => "Math", "rb_mProcess" => "Process" } end PKu]HLf*q0q0 rdoc-6.2.1.1/lib/rdoc/servlet.rbnu[# frozen_string_literal: true require 'rdoc' require 'erb' require 'time' require 'json' require 'webrick' ## # This is a WEBrick servlet that allows you to browse ri documentation. # # You can show documentation through either `ri --server` or, with RubyGems # 2.0 or newer, `gem server`. For ri, the server runs on port 8214 by # default. For RubyGems the server runs on port 8808 by default. # # You can use this servlet in your own project by mounting it on a WEBrick # server: # # require 'webrick' # # server = WEBrick::HTTPServer.new Port: 8000 # # server.mount '/', RDoc::Servlet # # If you want to mount the servlet some other place than the root, provide the # base path when mounting: # # server.mount '/rdoc', RDoc::Servlet, '/rdoc' class RDoc::Servlet < WEBrick::HTTPServlet::AbstractServlet @server_stores = Hash.new { |hash, server| hash[server] = {} } @cache = Hash.new { |hash, store| hash[store] = {} } ## # Maps an asset type to its path on the filesystem attr_reader :asset_dirs ## # An RDoc::Options instance used for rendering options attr_reader :options ## # Creates an instance of this servlet that shares cached data between # requests. def self.get_instance server, *options # :nodoc: stores = @server_stores[server] new server, stores, @cache, *options end ## # Creates a new WEBrick servlet. # # Use +mount_path+ when mounting the servlet somewhere other than /. # # Use +extra_doc_dirs+ for additional documentation directories. # # +server+ is provided automatically by WEBrick when mounting. +stores+ and # +cache+ are provided automatically by the servlet. def initialize server, stores, cache, mount_path = nil, extra_doc_dirs = [] super server @cache = cache @mount_path = mount_path @extra_doc_dirs = extra_doc_dirs @stores = stores @options = RDoc::Options.new @options.op_dir = '.' darkfish_dir = nil # HACK dup $LOAD_PATH.each do |path| darkfish_dir = File.join path, 'rdoc/generator/template/darkfish/' next unless File.directory? darkfish_dir @options.template_dir = darkfish_dir break end @asset_dirs = { :darkfish => darkfish_dir, :json_index => File.expand_path('../generator/template/json_index/', __FILE__), } end ## # Serves the asset at the path in +req+ for +generator_name+ via +res+. def asset generator_name, req, res asset_dir = @asset_dirs[generator_name] asset_path = File.join asset_dir, req.path if_modified_since req, res, asset_path res.body = File.read asset_path res.content_type = case req.path when /\.css\z/ then 'text/css' when /\.js\z/ then 'application/javascript' else 'application/octet-stream' end end ## # GET request entry point. Fills in +res+ for the path, etc. in +req+. def do_GET req, res req.path.sub!(/\A#{Regexp.escape @mount_path}/, '') if @mount_path case req.path when '/' then root req, res when '/js/darkfish.js', '/js/jquery.js', '/js/search.js', %r%^/css/%, %r%^/images/%, %r%^/fonts/% then asset :darkfish, req, res when '/js/navigation.js', '/js/searcher.js' then asset :json_index, req, res when '/js/search_index.js' then root_search req, res else show_documentation req, res end rescue WEBrick::HTTPStatus::NotFound => e generator = generator_for RDoc::Store.new not_found generator, req, res, e.message rescue WEBrick::HTTPStatus::Status raise rescue => e error e, req, res end ## # Fills in +res+ with the class, module or page for +req+ from +store+. # # +path+ is relative to the mount_path and is used to determine the class, # module or page name (/RDoc/Servlet.html becomes RDoc::Servlet). # +generator+ is used to create the page. def documentation_page store, generator, path, req, res text_name = path.chomp '.html' name = text_name.gsub '/', '::' if klass = store.find_class_or_module(name) then res.body = generator.generate_class klass elsif page = store.find_text_page(name.sub(/_([^_]*)\z/, '.\1')) then res.body = generator.generate_page page elsif page = store.find_text_page(text_name.sub(/_([^_]*)\z/, '.\1')) then res.body = generator.generate_page page else not_found generator, req, res end end ## # Creates the JSON search index on +res+ for the given +store+. +generator+ # must respond to \#json_index to build. +req+ is ignored. def documentation_search store, generator, req, res json_index = @cache[store].fetch :json_index do @cache[store][:json_index] = JSON.dump generator.json_index.build_index end res.content_type = 'application/javascript' res.body = "var search_data = #{json_index}" end ## # Returns the RDoc::Store and path relative to +mount_path+ for # documentation at +path+. def documentation_source path _, source_name, path = path.split '/', 3 store = @stores[source_name] return store, path if store store = store_for source_name store.load_all @stores[source_name] = store return store, path end ## # Generates an error page for the +exception+ while handling +req+ on +res+. def error exception, req, res backtrace = exception.backtrace.join "\n" res.content_type = 'text/html' res.status = 500 res.body = <<-BODY Error - #{ERB::Util.html_escape exception.class}

    Error

    While processing #{ERB::Util.html_escape req.request_uri} the RDoc (#{ERB::Util.html_escape RDoc::VERSION}) server has encountered a #{ERB::Util.html_escape exception.class} exception:

    #{ERB::Util.html_escape exception.message}

    Please report this to the RDoc issues tracker. Please include the RDoc version, the URI above and exception class, message and backtrace. If you're viewing a gem's documentation, include the gem name and version. If you're viewing Ruby's documentation, include the version of ruby.

    Backtrace:

    #{ERB::Util.html_escape backtrace}
    BODY end ## # Instantiates a Darkfish generator for +store+ def generator_for store generator = RDoc::Generator::Darkfish.new store, @options generator.file_output = false generator.asset_rel_path = '..' rdoc = RDoc::RDoc.new rdoc.store = store rdoc.generator = generator rdoc.options = @options @options.main_page = store.main @options.title = store.title generator end ## # Handles the If-Modified-Since HTTP header on +req+ for +path+. If the # file has not been modified a Not Modified response is returned. If the # file has been modified a Last-Modified header is added to +res+. def if_modified_since req, res, path = nil last_modified = File.stat(path).mtime if path res['last-modified'] = last_modified.httpdate return unless ims = req['if-modified-since'] ims = Time.parse ims unless ims < last_modified then res.body = '' raise WEBrick::HTTPStatus::NotModified end end ## # Returns an Array of installed documentation. # # Each entry contains the documentation name (gem name, 'Ruby # Documentation', etc.), the path relative to the mount point, whether the # documentation exists, the type of documentation (See RDoc::RI::Paths#each) # and the filesystem to the RDoc::Store for the documentation. def installed_docs extra_counter = 0 ri_paths.map do |path, type| store = RDoc::Store.new path, type exists = File.exist? store.cache_path case type when :gem then gem_path = path[%r%/([^/]*)/ri$%, 1] [gem_path, "#{gem_path}/", exists, type, path] when :system then ['Ruby Documentation', 'ruby/', exists, type, path] when :site then ['Site Documentation', 'site/', exists, type, path] when :home then ['Home Documentation', 'home/', exists, type, path] when :extra then extra_counter += 1 store.load_cache if exists title = store.title || "Extra Documentation" [title, "extra-#{extra_counter}/", exists, type, path] end end end ## # Returns a 404 page built by +generator+ for +req+ on +res+. def not_found generator, req, res, message = nil message ||= "The page #{ERB::Util.h req.path} was not found" res.body = generator.generate_servlet_not_found message res.status = 404 end ## # Enumerates the ri paths. See RDoc::RI::Paths#each def ri_paths &block RDoc::RI::Paths.each true, true, true, :all, *@extra_doc_dirs, &block #TODO: pass extra_dirs end ## # Generates the root page on +res+. +req+ is ignored. def root req, res generator = RDoc::Generator::Darkfish.new nil, @options res.body = generator.generate_servlet_root installed_docs res.content_type = 'text/html' end ## # Generates a search index for the root page on +res+. +req+ is ignored. def root_search req, res search_index = [] info = [] installed_docs.map do |name, href, exists, type, path| next unless exists search_index << name case type when :gem gemspec = path.gsub(%r%/doc/([^/]*?)/ri$%, '/specifications/\1.gemspec') spec = Gem::Specification.load gemspec path = spec.full_name comment = spec.summary when :system then path = 'ruby' comment = 'Documentation for the Ruby standard library' when :site then path = 'site' comment = 'Documentation for non-gem libraries' when :home then path = 'home' comment = 'Documentation from your home directory' when :extra comment = name end info << [name, '', path, '', comment] end index = { :index => { :searchIndex => search_index, :longSearchIndex => search_index, :info => info, } } res.body = "var search_data = #{JSON.dump index};" res.content_type = 'application/javascript' end ## # Displays documentation for +req+ on +res+, whether that be HTML or some # asset. def show_documentation req, res store, path = documentation_source req.path if_modified_since req, res, store.cache_path generator = generator_for store case path when nil, '', 'index.html' then res.body = generator.generate_index when 'table_of_contents.html' then res.body = generator.generate_table_of_contents when 'js/search_index.js' then documentation_search store, generator, req, res else documentation_page store, generator, path, req, res end ensure res.content_type ||= 'text/html' end ## # Returns an RDoc::Store for the given +source_name+ ('ruby' or a gem name). def store_for source_name case source_name when 'home' then RDoc::Store.new RDoc::RI::Paths.home_dir, :home when 'ruby' then RDoc::Store.new RDoc::RI::Paths.system_dir, :system when 'site' then RDoc::Store.new RDoc::RI::Paths.site_dir, :site when /\Aextra-(\d+)\z/ then index = $1.to_i - 1 ri_dir = installed_docs[index][4] RDoc::Store.new ri_dir, :extra else ri_dir, type = ri_paths.find do |dir, dir_type| next unless dir_type == :gem source_name == dir[%r%/([^/]*)/ri$%, 1] end raise WEBrick::HTTPStatus::NotFound, "Could not find gem \"#{ERB::Util.html_escape(source_name)}\". Are you sure you installed it?" unless ri_dir store = RDoc::Store.new ri_dir, type return store if File.exist? store.cache_path raise WEBrick::HTTPStatus::NotFound, "Could not find documentation for \"#{ERB::Util.html_escape(source_name)}\". Please run `gem rdoc --ri gem_name`" end end end PKu]58$rdoc-6.2.1.1/lib/rdoc/erb_partial.rbnu[# frozen_string_literal: true ## # Allows an ERB template to be rendered in the context (binding) of an # existing ERB template evaluation. class RDoc::ERBPartial < ERB ## # Overrides +compiler+ startup to set the +eoutvar+ to an empty string only # if it isn't already set. def set_eoutvar compiler, eoutvar = '_erbout' super compiler.pre_cmd = ["#{eoutvar} ||= ''"] end end PKu]p-}}rdoc-6.2.1.1/lib/rdoc/alias.rbnu[# frozen_string_literal: true ## # Represent an alias, which is an old_name/new_name pair associated with a # particular context #-- # TODO implement Alias as a proxy to a method/attribute, inheriting from # MethodAttr class RDoc::Alias < RDoc::CodeObject ## # Aliased method's name attr_reader :new_name alias name new_name ## # Aliasee method's name attr_reader :old_name ## # Is this an alias declared in a singleton context? attr_accessor :singleton ## # Source file token stream attr_reader :text ## # Creates a new Alias with a token stream of +text+ that aliases +old_name+ # to +new_name+, has +comment+ and is a +singleton+ context. def initialize(text, old_name, new_name, comment, singleton = false) super() @text = text @singleton = singleton @old_name = old_name @new_name = new_name self.comment = comment end ## # Order by #singleton then #new_name def <=>(other) [@singleton ? 0 : 1, new_name] <=> [other.singleton ? 0 : 1, other.new_name] end ## # HTML fragment reference for this alias def aref type = singleton ? 'c' : 'i' "#alias-#{type}-#{html_name}" end ## # Full old name including namespace def full_old_name @full_name || "#{parent.name}#{pretty_old_name}" end ## # HTML id-friendly version of +#new_name+. def html_name CGI.escape(@new_name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '') end def inspect # :nodoc: parent_name = parent ? parent.name : '(unknown)' "#<%s:0x%x %s.alias_method %s, %s>" % [ self.class, object_id, parent_name, @old_name, @new_name, ] end ## # '::' for the alias of a singleton method/attribute, '#' for instance-level. def name_prefix singleton ? '::' : '#' end ## # Old name with prefix '::' or '#'. def pretty_old_name "#{singleton ? '::' : '#'}#{@old_name}" end ## # New name with prefix '::' or '#'. def pretty_new_name "#{singleton ? '::' : '#'}#{@new_name}" end alias pretty_name pretty_new_name def to_s # :nodoc: "alias: #{self.new_name} -> #{self.pretty_old_name} in: #{parent}" end end PKu]epC0$rdoc-6.2.1.1/lib/rdoc/meta_method.rbnu[# frozen_string_literal: true ## # MetaMethod represents a meta-programmed method class RDoc::MetaMethod < RDoc::AnyMethod end PKu]/ rdoc-6.2.1.1/lib/rdoc/include.rbnu[# frozen_string_literal: true ## # A Module included in a class with \#include # # RDoc::Include.new 'Enumerable', 'comment ...' class RDoc::Include < RDoc::Mixin end PKu]ocrdoc-6.2.1.1/lib/rdoc/erbio.rbnu[# frozen_string_literal: true require 'erb' ## # A subclass of ERB that writes directly to an IO. Credit to Aaron Patterson # and Masatoshi SEKI. # # To use: # # erbio = RDoc::ERBIO.new '<%= "hello world" %>', nil, nil # # File.open 'hello.txt', 'w' do |io| # erbio.result binding # end # # Note that binding must enclose the io you wish to output on. class RDoc::ERBIO < ERB ## # Defaults +eoutvar+ to 'io', otherwise is identical to ERB's initialize def initialize str, safe_level = nil, trim_mode = nil, eoutvar = 'io' if RUBY_VERSION >= '2.6' super(str, trim_mode: trim_mode, eoutvar: eoutvar) else super end end ## # Instructs +compiler+ how to write to +io_variable+ def set_eoutvar compiler, io_variable compiler.put_cmd = "#{io_variable}.write" compiler.insert_cmd = "#{io_variable}.write" compiler.pre_cmd = [] compiler.post_cmd = [] end end PKu]&“ rdoc-6.2.1.1/lib/rdoc/require.rbnu[# frozen_string_literal: true ## # A file loaded by \#require class RDoc::Require < RDoc::CodeObject ## # Name of the required file attr_accessor :name ## # Creates a new Require that loads +name+ with +comment+ def initialize(name, comment) super() @name = name.gsub(/'|"/, "") #' @top_level = nil self.comment = comment end def inspect # :nodoc: "#<%s:0x%x require '%s' in %s>" % [ self.class, object_id, @name, parent_file_name, ] end def to_s # :nodoc: "require #{name} in: #{parent}" end ## # The RDoc::TopLevel corresponding to this require, or +nil+ if not found. def top_level @top_level ||= begin tl = RDoc::TopLevel.all_files_hash[name + '.rb'] if tl.nil? and RDoc::TopLevel.all_files.first.full_name =~ %r(^lib/) then # second chance tl = RDoc::TopLevel.all_files_hash['lib/' + name + '.rb'] end tl end end end PKu]W,%rdoc-6.2.1.1/lib/rdoc/normal_class.rbnu[# frozen_string_literal: true ## # A normal class, neither singleton nor anonymous class RDoc::NormalClass < RDoc::ClassModule ## # The ancestors of this class including modules. Unlike Module#ancestors, # this class is not included in the result. The result will contain both # RDoc::ClassModules and Strings. def ancestors if String === superclass then super << superclass elsif superclass then ancestors = super ancestors << superclass ancestors.concat superclass.ancestors else super end end def aref_prefix # :nodoc: 'class' end ## # The definition of this class, class MyClassName def definition "class #{full_name}" end def direct_ancestors superclass ? super + [superclass] : super end def inspect # :nodoc: superclass = @superclass ? " < #{@superclass}" : nil "<%s:0x%x class %s%s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [ self.class, object_id, full_name, superclass, @includes, @extends, @attributes, @method_list, @aliases ] end def to_s # :nodoc: display = "#{self.class.name} #{self.full_name}" if superclass display += ' < ' + (superclass.is_a?(String) ? superclass : superclass.full_name) end display += ' -> ' + is_alias_for.to_s if is_alias_for display end def pretty_print q # :nodoc: superclass = @superclass ? " < #{@superclass}" : nil q.group 2, "[class #{full_name}#{superclass} ", "]" do q.breakable q.text "includes:" q.breakable q.seplist @includes do |inc| q.pp inc end q.breakable q.text "constants:" q.breakable q.seplist @constants do |const| q.pp const end q.breakable q.text "attributes:" q.breakable q.seplist @attributes do |attr| q.pp attr end q.breakable q.text "methods:" q.breakable q.seplist @method_list do |meth| q.pp meth end q.breakable q.text "aliases:" q.breakable q.seplist @aliases do |aliaz| q.pp aliaz end q.breakable q.text "comment:" q.breakable q.pp comment end end end PKu]- % %$rdoc-6.2.1.1/lib/rdoc/code_object.rbnu[# frozen_string_literal: true ## # Base class for the RDoc code tree. # # We contain the common stuff for contexts (which are containers) and other # elements (methods, attributes and so on) # # Here's the tree of the CodeObject subclasses: # # * RDoc::Context # * RDoc::TopLevel # * RDoc::ClassModule # * RDoc::AnonClass (never used so far) # * RDoc::NormalClass # * RDoc::NormalModule # * RDoc::SingleClass # * RDoc::MethodAttr # * RDoc::Attr # * RDoc::AnyMethod # * RDoc::GhostMethod # * RDoc::MetaMethod # * RDoc::Alias # * RDoc::Constant # * RDoc::Mixin # * RDoc::Require # * RDoc::Include class RDoc::CodeObject include RDoc::Text ## # Our comment attr_reader :comment ## # Do we document our children? attr_reader :document_children ## # Do we document ourselves? attr_reader :document_self ## # Are we done documenting (ie, did we come across a :enddoc:)? attr_reader :done_documenting ## # Which file this code object was defined in attr_reader :file ## # Force documentation of this CodeObject attr_reader :force_documentation ## # Line in #file where this CodeObject was defined attr_accessor :line ## # Hash of arbitrary metadata for this CodeObject attr_reader :metadata ## # Sets the parent CodeObject attr_writer :parent ## # Did we ever receive a +:nodoc:+ directive? attr_reader :received_nodoc ## # Set the section this CodeObject is in attr_writer :section ## # The RDoc::Store for this object. attr_reader :store ## # We are the model of the code, but we know that at some point we will be # worked on by viewers. By implementing the Viewable protocol, viewers can # associated themselves with these objects. attr_accessor :viewer ## # Creates a new CodeObject that will document itself and its children def initialize @metadata = {} @comment = '' @parent = nil @parent_name = nil # for loading @parent_class = nil # for loading @section = nil @section_title = nil # for loading @file = nil @full_name = nil @store = nil @track_visibility = true initialize_visibility end ## # Initializes state for visibility of this CodeObject and its children. def initialize_visibility # :nodoc: @document_children = true @document_self = true @done_documenting = false @force_documentation = false @received_nodoc = false @ignored = false @suppressed = false @track_visibility = true end ## # Replaces our comment with +comment+, unless it is empty. def comment=(comment) @comment = case comment when NilClass then '' when RDoc::Markup::Document then comment when RDoc::Comment then comment.normalize else if comment and not comment.empty? then normalize_comment comment else # HACK correct fix is to have #initialize create @comment # with the correct encoding if String === @comment and @comment.empty? then @comment = RDoc::Encoding.change_encoding @comment, comment.encoding end @comment end end end ## # Should this CodeObject be displayed in output? # # A code object should be displayed if: # # * The item didn't have a nodoc or wasn't in a container that had nodoc # * The item wasn't ignored # * The item has documentation and was not suppressed def display? @document_self and not @ignored and (documented? or not @suppressed) end ## # Enables or disables documentation of this CodeObject's children unless it # has been turned off by :enddoc: def document_children=(document_children) return unless @track_visibility @document_children = document_children unless @done_documenting end ## # Enables or disables documentation of this CodeObject unless it has been # turned off by :enddoc:. If the argument is +nil+ it means the # documentation is turned off by +:nodoc:+. def document_self=(document_self) return unless @track_visibility return if @done_documenting @document_self = document_self @received_nodoc = true if document_self.nil? end ## # Does this object have a comment with content or is #received_nodoc true? def documented? @received_nodoc or !@comment.empty? end ## # Turns documentation on/off, and turns on/off #document_self # and #document_children. # # Once documentation has been turned off (by +:enddoc:+), # the object will refuse to turn #document_self or # #document_children on, so +:doc:+ and +:start_doc:+ directives # will have no effect in the current file. def done_documenting=(value) return unless @track_visibility @done_documenting = value @document_self = !value @document_children = @document_self end ## # Yields each parent of this CodeObject. See also # RDoc::ClassModule#each_ancestor def each_parent code_object = self while code_object = code_object.parent do yield code_object end self end ## # File name where this CodeObject was found. # # See also RDoc::Context#in_files def file_name return unless @file @file.absolute_name end ## # Force the documentation of this object unless documentation # has been turned off by :enddoc: #-- # HACK untested, was assigning to an ivar def force_documentation=(value) @force_documentation = value unless @done_documenting end ## # Sets the full_name overriding any computed full name. # # Set to +nil+ to clear RDoc's cached value def full_name= full_name @full_name = full_name end ## # Use this to ignore a CodeObject and all its children until found again # (#record_location is called). An ignored item will not be displayed in # documentation. # # See github issue #55 # # The ignored status is temporary in order to allow implementation details # to be hidden. At the end of processing a file RDoc allows all classes # and modules to add new documentation to previously created classes. # # If a class was ignored (via stopdoc) then reopened later with additional # documentation it should be displayed. If a class was ignored and never # reopened it should not be displayed. The ignore flag allows this to # occur. def ignore return unless @track_visibility @ignored = true stop_doc end ## # Has this class been ignored? # # See also #ignore def ignored? @ignored end ## # The options instance from the store this CodeObject is attached to, or a # default options instance if the CodeObject is not attached. # # This is used by Text#snippet def options if @store and @store.rdoc then @store.rdoc.options else RDoc::Options.new end end ## # Our parent CodeObject. The parent may be missing for classes loaded from # legacy RI data stores. def parent return @parent if @parent return nil unless @parent_name if @parent_class == RDoc::TopLevel then @parent = @store.add_file @parent_name else @parent = @store.find_class_or_module @parent_name return @parent if @parent begin @parent = @store.load_class @parent_name rescue RDoc::Store::MissingFileError nil end end end ## # File name of our parent def parent_file_name @parent ? @parent.base_name : '(unknown)' end ## # Name of our parent def parent_name @parent ? @parent.full_name : '(unknown)' end ## # Records the RDoc::TopLevel (file) where this code object was defined def record_location top_level @ignored = false @suppressed = false @file = top_level end ## # The section this CodeObject is in. Sections allow grouping of constants, # attributes and methods inside a class or module. def section return @section if @section @section = parent.add_section @section_title if parent end ## # Enable capture of documentation unless documentation has been # turned off by :enddoc: def start_doc return if @done_documenting @document_self = true @document_children = true @ignored = false @suppressed = false end ## # Disable capture of documentation def stop_doc return unless @track_visibility @document_self = false @document_children = false end ## # Sets the +store+ that contains this CodeObject def store= store @store = store return unless @track_visibility if :nodoc == options.visibility then initialize_visibility @track_visibility = false end end ## # Use this to suppress a CodeObject and all its children until the next file # it is seen in or documentation is discovered. A suppressed item with # documentation will be displayed while an ignored item with documentation # may not be displayed. def suppress return unless @track_visibility @suppressed = true stop_doc end ## # Has this class been suppressed? # # See also #suppress def suppressed? @suppressed end end PKu]#SpSprdoc-6.2.1.1/lib/rdoc/markup.rbnu[# frozen_string_literal: true ## # RDoc::Markup parses plain text documents and attempts to decompose them into # their constituent parts. Some of these parts are high-level: paragraphs, # chunks of verbatim text, list entries and the like. Other parts happen at # the character level: a piece of bold text, a word in code font. This markup # is similar in spirit to that used on WikiWiki webs, where folks create web # pages using a simple set of formatting rules. # # RDoc::Markup and other markup formats do no output formatting, this is # handled by the RDoc::Markup::Formatter subclasses. # # = Supported Formats # # Besides the RDoc::Markup format, the following formats are built in to RDoc: # # markdown:: # The markdown format as described by # http://daringfireball.net/projects/markdown/. See RDoc::Markdown for # details on the parser and supported extensions. # rd:: # The rdtool format. See RDoc::RD for details on the parser and format. # tomdoc:: # The TomDoc format as described by http://tomdoc.org/. See RDoc::TomDoc # for details on the parser and supported extensions. # # You can choose a markup format using the following methods: # # per project:: # If you build your documentation with rake use RDoc::Task#markup. # # If you build your documentation by hand run: # # rdoc --markup your_favorite_format --write-options # # and commit .rdoc_options and ship it with your packaged gem. # per file:: # At the top of the file use the :markup: directive to set the # default format for the rest of the file. # per comment:: # Use the :markup: directive at the top of a comment you want # to write in a different format. # # = RDoc::Markup # # RDoc::Markup is extensible at runtime: you can add \new markup elements to # be recognized in the documents that RDoc::Markup parses. # # RDoc::Markup is intended to be the basis for a family of tools which share # the common requirement that simple, plain-text should be rendered in a # variety of different output formats and media. It is envisaged that # RDoc::Markup could be the basis for formatting RDoc style comment blocks, # Wiki entries, and online FAQs. # # == Synopsis # # This code converts +input_string+ to HTML. The conversion takes place in # the +convert+ method, so you can use the same RDoc::Markup converter to # convert multiple input strings. # # require 'rdoc' # # h = RDoc::Markup::ToHtml.new(RDoc::Options.new) # # puts h.convert(input_string) # # You can extend the RDoc::Markup parser to recognize new markup # sequences, and to add regexp handling. Here we make WikiWords significant to # the parser, and also make the sequences {word} and \text... signify # strike-through text. We then subclass the HTML output class to deal # with these: # # require 'rdoc' # # class WikiHtml < RDoc::Markup::ToHtml # def handle_regexp_WIKIWORD(target) # "" + target.text + "" # end # end # # markup = RDoc::Markup.new # markup.add_word_pair("{", "}", :STRIKE) # markup.add_html("no", :STRIKE) # # markup.add_regexp_handling(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # wh = WikiHtml.new RDoc::Options.new, markup # wh.add_tag(:STRIKE, "", "") # # puts "#{wh.convert ARGF.read}" # # == Encoding # # Where Encoding support is available, RDoc will automatically convert all # documents to the same output encoding. The output encoding can be set via # RDoc::Options#encoding and defaults to Encoding.default_external. # # = \RDoc Markup Reference # # == Block Markup # # === Paragraphs and Verbatim # # The markup engine looks for a document's natural left margin. This is # used as the initial margin for the document. # # Consecutive lines starting at this margin are considered to be a # paragraph. Empty lines separate paragraphs. # # Any line that starts to the right of the current margin is treated # as verbatim text. This is useful for code listings: # # 3.times { puts "Ruby" } # # In verbatim text, two or more blank lines are collapsed into one, # and trailing blank lines are removed: # # This is the first line # # # This is the second non-blank line, # after 2 blank lines in the source markup. # # # There were two trailing blank lines right above this paragraph, that # have been removed. In addition, the verbatim text has been shifted # left, so the amount of indentation of verbatim text is unimportant. # # For HTML output RDoc makes a small effort to determine if a verbatim section # contains Ruby source code. If so, the verbatim block will be marked up as # HTML. Triggers include "def", "class", "module", "require", the "hash # rocket"# (=>) or a block call with a parameter. # # === Headers # # A line starting with an equal sign (=) is treated as a # heading. Level one headings have one equals sign, level two headings # have two, and so on until level six, which is the maximum # (seven hyphens or more result in a level six heading). # # For example, the above header was obtained with: # # === Headers # # In HTML output headers have an id matching their name. The above example's # HTML is: # #

    Headers

    # # If a heading is inside a method body the id will be prefixed with the # method's id. If the above header where in the documentation for a method # such as: # # ## # # This method does fun things # # # # = Example # # # # Example of fun things goes here ... # # def do_fun_things # end # # The header's id would be: # #

    Example

    # # The label can be linked-to using SomeClass@Headers. See # {Links}[RDoc::Markup@Links] for further details. # # === Rules # # A line starting with three or more hyphens (at the current indent) # generates a horizontal rule. # # --- # # produces: # # --- # # === Simple Lists # # If a paragraph starts with a "*", "-", "." or ".", # then it is taken to be the start of a list. The margin is increased to be # the first non-space following the list start flag. Subsequent lines # should be indented to this new margin until the list ends. For example: # # * this is a list with three paragraphs in # the first item. This is the first paragraph. # # And this is the second paragraph. # # 1. This is an indented, numbered list. # 2. This is the second item in that list # # This is the third conventional paragraph in the # first list item. # # * This is the second item in the original list # # produces: # # * this is a list with three paragraphs in # the first item. This is the first paragraph. # # And this is the second paragraph. # # 1. This is an indented, numbered list. # 2. This is the second item in that list # # This is the third conventional paragraph in the # first list item. # # * This is the second item in the original list # # === Labeled Lists # # You can also construct labeled lists, sometimes called description # or definition lists. Do this by putting the label in square brackets # and indenting the list body: # # [cat] a small furry mammal # that seems to sleep a lot # # [ant] a little insect that is known # to enjoy picnics # # produces: # # [cat] a small furry mammal # that seems to sleep a lot # # [ant] a little insect that is known # to enjoy picnics # # If you want the list bodies to line up to the left of the labels, # use two colons: # # cat:: a small furry mammal # that seems to sleep a lot # # ant:: a little insect that is known # to enjoy picnics # # produces: # # cat:: a small furry mammal # that seems to sleep a lot # # ant:: a little insect that is known # to enjoy picnics # # Notice that blank lines right after the label are ignored in labeled lists: # # [one] # # definition 1 # # [two] # # definition 2 # # produces the same output as # # [one] definition 1 # [two] definition 2 # # # === Lists and Verbatim # # If you want to introduce a verbatim section right after a list, it has to be # less indented than the list item bodies, but more indented than the list # label, letter, digit or bullet. For instance: # # * point 1 # # * point 2, first paragraph # # point 2, second paragraph # verbatim text inside point 2 # point 2, third paragraph # verbatim text outside of the list (the list is therefore closed) # regular paragraph after the list # # produces: # # * point 1 # # * point 2, first paragraph # # point 2, second paragraph # verbatim text inside point 2 # point 2, third paragraph # verbatim text outside of the list (the list is therefore closed) # regular paragraph after the list # # == Text Markup # # === Bold, Italic, Typewriter Text # # You can use markup within text (except verbatim) to change the # appearance of parts of that text. Out of the box, RDoc::Markup # supports word-based and general markup. # # Word-based markup uses flag characters around individual words: # # \*_word_\*:: displays _word_ in a *bold* font # \__word_\_:: displays _word_ in an _emphasized_ font # \+_word_\+:: displays _word_ in a +code+ font # # General markup affects text between a start delimiter and an end # delimiter. Not surprisingly, these delimiters look like HTML markup. # # \_text_:: displays _text_ in a *bold* font # \_text_:: displays _text_ in an _emphasized_ font # (alternate tag: \) # \_text_\:: displays _text_ in a +code+ font # (alternate tag: \) # # Unlike conventional Wiki markup, general markup can cross line # boundaries. You can turn off the interpretation of markup by # preceding the first character with a backslash (see Escaping # Text Markup, below). # # === Links # # Links to starting with +http:+, +https:+, +mailto:+, +ftp:+ or +www.+ # are recognized. An HTTP url that references an external image is converted # into an inline image element. # # Classes and methods will be automatically linked to their definition. For # example, RDoc::Markup will link to this documentation. By default # methods will only be automatically linked if they contain an _ (all # methods can be automatically linked through the --hyperlink-all # command line option). # # Single-word methods can be linked by using the # character for # instance methods or :: for class methods. For example, # #convert links to #convert. A class or method may be combined like # RDoc::Markup#convert. # # A heading inside the documentation can be linked by following the class # or method by an @ then the heading name. # RDoc::Markup@Links will link to this section like this: # RDoc::Markup@Links. Spaces in headings with multiple words must be escaped # with + like RDoc::Markup@Escaping+Text+Markup. # Punctuation and other special characters must be escaped like CGI.escape. # # The @ can also be used to link to sections. If a section and a # heading share the same name the section is preferred for the link. # # Links can also be of the form label[url], in which case +label+ is # used in the displayed text, and +url+ is used as the target. If +label+ # contains multiple words, put it in braces: {multi word label}[url]. # The +url+ may be an +http:+-type link or a cross-reference to a class, # module or method with a label. # # Links with the rdoc-image: scheme will create an image tag for # HTML output. Only fully-qualified URLs are supported. # # Links with the rdoc-ref: scheme will link to the referenced class, # module, method, file, etc. If the referenced item is does not exist # no link will be generated and rdoc-ref: will be removed from the # resulting text. # # Links starting with rdoc-label:label_name will link to the # +label_name+. You can create a label for the current link (for # bidirectional links) by supplying a name for the current link like # rdoc-label:label-other:label-mine. # # Links starting with +link:+ refer to local files whose path is relative to # the --op directory. Use rdoc-ref: instead of # link: to link to files generated by RDoc as the link target may # be different across RDoc generators. # # Example links: # # https://github.com/ruby/rdoc # mailto:user@example.com # {RDoc Documentation}[http://rdoc.rubyforge.org] # {RDoc Markup}[rdoc-ref:RDoc::Markup] # # === Escaping Text Markup # # Text markup can be escaped with a backslash, as in \, which was obtained # with \\. Except in verbatim sections and between \ tags, # to produce a backslash you have to double it unless it is followed by a # space, tab or newline. Otherwise, the HTML formatter will discard it, as it # is used to escape potential links: # # * The \ must be doubled if not followed by white space: \\. # * But not in \ tags: in a Regexp, \S matches non-space. # * This is a link to {ruby-lang}[www.ruby-lang.org]. # * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org]. # * This will not be linked to \RDoc::RDoc#document # # generates: # # * The \ must be doubled if not followed by white space: \\. # * But not in \ tags: in a Regexp, \S matches non-space. # * This is a link to {ruby-lang}[www.ruby-lang.org] # * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org] # * This will not be linked to \RDoc::RDoc#document # # Inside \ tags, more precisely, leading backslashes are removed only if # followed by a markup character (<*_+), a backslash, or a known link # reference (a known class or method). So in the example above, the backslash # of \S would be removed if there was a class or module named +S+ in # the current context. # # This behavior is inherited from RDoc version 1, and has been kept for # compatibility with existing RDoc documentation. # # === Conversion of characters # # HTML will convert two/three dashes to an em-dash. Other common characters are # converted as well: # # em-dash:: -- or --- # ellipsis:: ... # # single quotes:: 'text' or `text' # double quotes:: "text" or ``text'' # # copyright:: (c) # registered trademark:: (r) # # produces: # # em-dash:: -- or --- # ellipsis:: ... # # single quotes:: 'text' or `text' # double quotes:: "text" or ``text'' # # copyright:: (c) # registered trademark:: (r) # # # == Documenting Source Code # # Comment blocks can be written fairly naturally, either using # on # successive lines of the comment, or by including the comment in # a =begin/=end block. If you use the latter form, # the =begin line _must_ be flagged with an +rdoc+ tag: # # =begin rdoc # Documentation to be processed by RDoc. # # ... # =end # # RDoc stops processing comments if it finds a comment line starting # with -- right after the # character (otherwise, # it will be treated as a rule if it has three dashes or more). # This can be used to separate external from internal comments, # or to stop a comment being associated with a method, class, or module. # Commenting can be turned back on with a line that starts with ++. # # ## # # Extract the age and calculate the date-of-birth. # #-- # # FIXME: fails if the birthday falls on February 29th # #++ # # The DOB is returned as a Time object. # # def get_dob(person) # # ... # end # # Names of classes, files, and any method names containing an underscore or # preceded by a hash character are automatically linked from comment text to # their description. This linking works inside the current class or module, # and with ancestor methods (in included modules or in the superclass). # # Method parameter lists are extracted and displayed with the method # description. If a method calls +yield+, then the parameters passed to yield # will also be displayed: # # def fred # ... # yield line, address # # This will get documented as: # # fred() { |line, address| ... } # # You can override this using a comment containing ':yields: ...' immediately # after the method definition # # def fred # :yields: index, position # # ... # # yield line, address # # which will get documented as # # fred() { |index, position| ... } # # +:yields:+ is an example of a documentation directive. These appear # immediately after the start of the document element they are modifying. # # RDoc automatically cross-references words with underscores or camel-case. # To suppress cross-references, prefix the word with a \ character. To # include special characters like "\n", you'll need to use # two \ characters in normal text, but only one in \ text: # # "\\n" or "\n" # # produces: # # "\\n" or "\n" # # == Directives # # Directives are keywords surrounded by ":" characters. # # === Controlling what is documented # # [+:nodoc:+ / :nodoc: all] # This directive prevents documentation for the element from # being generated. For classes and modules, methods, aliases, # constants, and attributes directly within the affected class or # module also will be omitted. By default, though, modules and # classes within that class or module _will_ be documented. This is # turned off by adding the +all+ modifier. # # module MyModule # :nodoc: # class Input # end # end # # module OtherModule # :nodoc: all # class Output # end # end # # In the above code, only class MyModule::Input will be documented. # # The +:nodoc:+ directive, like +:enddoc:+, +:stopdoc:+ and +:startdoc:+ # presented below, is local to the current file: if you do not want to # document a module that appears in several files, specify +:nodoc:+ on each # appearance, at least once per file. # # [+:stopdoc:+ / +:startdoc:+] # Stop and start adding new documentation elements to the current container. # For example, if a class has a number of constants that you don't want to # document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the # last. If you don't specify a +:startdoc:+ by the end of the container, # disables documentation for the rest of the current file. # # [+:doc:+] # Forces a method or attribute to be documented even if it wouldn't be # otherwise. Useful if, for example, you want to include documentation of a # particular private method. # # [+:enddoc:+] # Document nothing further at the current level: directives +:startdoc:+ and # +:doc:+ that appear after this will not be honored for the current container # (file, class or module), in the current file. # # [+:notnew:+ / +:not_new:+ / +:not-new:+ ] # Only applicable to the +initialize+ instance method. Normally RDoc # assumes that the documentation and parameters for +initialize+ are # actually for the +new+ method, and so fakes out a +new+ for the class. # The +:notnew:+ directive stops this. Remember that +initialize+ is private, # so you won't see the documentation unless you use the +-a+ command line # option. # # === Method arguments # # [+:arg:+ or +:args:+ _parameters_] # Overrides the default argument handling with exactly these parameters. # # ## # # :args: a, b # # def some_method(*a) # end # # [+:yield:+ or +:yields:+ _parameters_] # Overrides the default yield discovery with these parameters. # # ## # # :yields: key, value # # def each_thing &block # @things.each(&block) # end # # [+:call-seq:+] # Lines up to the next blank line or lines with a common prefix in the # comment are treated as the method's calling sequence, overriding the # default parsing of method parameters and yield arguments. # # Multiple lines may be used. # # # :call-seq: # # ARGF.readlines(sep=$/) -> array # # ARGF.readlines(limit) -> array # # ARGF.readlines(sep, limit) -> array # # # # ARGF.to_a(sep=$/) -> array # # ARGF.to_a(limit) -> array # # ARGF.to_a(sep, limit) -> array # # # # The remaining lines are documentation ... # # === Sections # # Sections allow you to group methods in a class into sensible containers. If # you use the sections 'Public', 'Internal' and 'Deprecated' (the three # allowed method statuses from TomDoc) the sections will be displayed in that # order placing the most useful methods at the top. Otherwise, sections will # be displayed in alphabetical order. # # [+:category:+ _section_] # Adds this item to the named +section+ overriding the current section. Use # this to group methods by section in RDoc output while maintaining a # sensible ordering (like alphabetical). # # # :category: Utility Methods # # # # CGI escapes +text+ # # def convert_string text # CGI.escapeHTML text # end # # An empty category will place the item in the default category: # # # :category: # # # # This method is in the default category # # def some_method # # ... # end # # Unlike the :section: directive, :category: is not sticky. The category # only applies to the item immediately following the comment. # # Use the :section: directive to provide introductory text for a section of # documentation. # # [+:section:+ _title_] # Provides section introductory text in RDoc output. The title following # +:section:+ is used as the section name and the remainder of the comment # containing the section is used as introductory text. A section's comment # block must be separated from following comment blocks. Use an empty title # to switch to the default section. # # The :section: directive is sticky, so subsequent methods, aliases, # attributes, and classes will be contained in this section until the # section is changed. The :category: directive will override the :section: # directive. # # A :section: comment block may have one or more lines before the :section: # directive. These will be removed, and any identical lines at the end of # the block are also removed. This allows you to add visual cues to the # section. # # Example: # # # ---------------------------------------- # # :section: My Section # # This is the section that I wrote. # # See it glisten in the noon-day sun. # # ---------------------------------------- # # ## # # Comment for some_method # # def some_method # # ... # end # # === Other directives # # [+:markup:+ _type_] # Overrides the default markup type for this comment with the specified # markup type. For Ruby files, if the first comment contains this directive # it is applied automatically to all comments in the file. # # Unless you are converting between markup formats you should use a # .rdoc_options file to specify the default documentation # format for your entire project. See RDoc::Options@Saved+Options for # instructions. # # At the top of a file the +:markup:+ directive applies to the entire file: # # # coding: UTF-8 # # :markup: TomDoc # # # TomDoc comment here ... # # class MyClass # # ... # # For just one comment: # # # ... # end # # # :markup: RDoc # # # # This is a comment in RDoc markup format ... # # def some_method # # ... # # See Markup@CONTRIBUTING for instructions on adding a new markup format. # # [+:include:+ _filename_] # Include the contents of the named file at this point. This directive # must appear alone on one line, possibly preceded by spaces. In this # position, it can be escaped with a \ in front of the first colon. # # The file will be searched for in the directories listed by the +--include+ # option, or in the current directory by default. The contents of the file # will be shifted to have the same indentation as the ':' at the start of # the +:include:+ directive. # # [+:title:+ _text_] # Sets the title for the document. Equivalent to the --title # command line parameter. (The command line parameter overrides any :title: # directive in the source). # # [+:main:+ _name_] # Equivalent to the --main command line parameter. # #-- # Original Author:: Dave Thomas, dave@pragmaticprogrammer.com # License:: Ruby license class RDoc::Markup ## # An AttributeManager which handles inline markup. attr_reader :attribute_manager ## # Parses +str+ into an RDoc::Markup::Document. def self.parse str RDoc::Markup::Parser.parse str rescue RDoc::Markup::Parser::Error => e $stderr.puts <<-EOF While parsing markup, RDoc encountered a #{e.class}: #{e} \tfrom #{e.backtrace.join "\n\tfrom "} ---8<--- #{text} ---8<--- RDoc #{RDoc::VERSION} Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} #{RUBY_RELEASE_DATE} Please file a bug report with the above information at: https://github.com/ruby/rdoc/issues EOF raise end ## # Take a block of text and use various heuristics to determine its # structure (paragraphs, lists, and so on). Invoke an event handler as we # identify significant chunks. def initialize attribute_manager = nil @attribute_manager = attribute_manager || RDoc::Markup::AttributeManager.new @output = nil end ## # Add to the sequences used to add formatting to an individual word (such # as *bold*). Matching entries will generate attributes that the output # formatters can recognize by their +name+. def add_word_pair(start, stop, name) @attribute_manager.add_word_pair(start, stop, name) end ## # Add to the sequences recognized as general markup. def add_html(tag, name) @attribute_manager.add_html(tag, name) end ## # Add to other inline sequences. For example, we could add WikiWords using # something like: # # parser.add_regexp_handling(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # Each wiki word will be presented to the output formatter. def add_regexp_handling(pattern, name) @attribute_manager.add_regexp_handling(pattern, name) end ## # We take +input+, parse it if necessary, then invoke the output +formatter+ # using a Visitor to render the result. def convert input, formatter document = case input when RDoc::Markup::Document then input else RDoc::Markup::Parser.parse input end document.accept formatter end autoload :Parser, 'rdoc/markup/parser' autoload :PreProcess, 'rdoc/markup/pre_process' # Inline markup classes autoload :AttrChanger, 'rdoc/markup/attr_changer' autoload :AttrSpan, 'rdoc/markup/attr_span' autoload :Attributes, 'rdoc/markup/attributes' autoload :AttributeManager, 'rdoc/markup/attribute_manager' autoload :RegexpHandling, 'rdoc/markup/regexp_handling' # RDoc::Markup AST autoload :BlankLine, 'rdoc/markup/blank_line' autoload :BlockQuote, 'rdoc/markup/block_quote' autoload :Document, 'rdoc/markup/document' autoload :HardBreak, 'rdoc/markup/hard_break' autoload :Heading, 'rdoc/markup/heading' autoload :Include, 'rdoc/markup/include' autoload :IndentedParagraph, 'rdoc/markup/indented_paragraph' autoload :List, 'rdoc/markup/list' autoload :ListItem, 'rdoc/markup/list_item' autoload :Paragraph, 'rdoc/markup/paragraph' autoload :Raw, 'rdoc/markup/raw' autoload :Rule, 'rdoc/markup/rule' autoload :Verbatim, 'rdoc/markup/verbatim' # Formatters autoload :Formatter, 'rdoc/markup/formatter' autoload :ToAnsi, 'rdoc/markup/to_ansi' autoload :ToBs, 'rdoc/markup/to_bs' autoload :ToHtml, 'rdoc/markup/to_html' autoload :ToHtmlCrossref, 'rdoc/markup/to_html_crossref' autoload :ToHtmlSnippet, 'rdoc/markup/to_html_snippet' autoload :ToLabel, 'rdoc/markup/to_label' autoload :ToMarkdown, 'rdoc/markup/to_markdown' autoload :ToRdoc, 'rdoc/markup/to_rdoc' autoload :ToTableOfContents, 'rdoc/markup/to_table_of_contents' autoload :ToTest, 'rdoc/markup/to_test' autoload :ToTtOnly, 'rdoc/markup/to_tt_only' end PKu]ʘw  *rdoc-6.2.1.1/lib/rdoc/markup/to_tt_only.rbnu[# frozen_string_literal: true ## # Extracts sections of text enclosed in plus, tt or code. Used to discover # undocumented parameters. class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter ## # Stack of list types attr_reader :list_type ## # Output accumulator attr_reader :res ## # Creates a new tt-only formatter. def initialize markup = nil super nil, markup add_tag :TT, nil, nil end ## # Adds tts from +block_quote+ to the output def accept_block_quote block_quote tt_sections block_quote.text end ## # Pops the list type for +list+ from #list_type def accept_list_end list @list_type.pop end ## # Pushes the list type for +list+ onto #list_type def accept_list_start list @list_type << list.type end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start list_item case @list_type.last when :NOTE, :LABEL then Array(list_item.label).map do |label| tt_sections label end.flatten end end ## # Adds +paragraph+ to the output def accept_paragraph paragraph tt_sections(paragraph.text) end ## # Does nothing to +markup_item+ because it doesn't have any user-built # content def do_nothing markup_item end alias accept_blank_line do_nothing # :nodoc: alias accept_heading do_nothing # :nodoc: alias accept_list_item_end do_nothing # :nodoc: alias accept_raw do_nothing # :nodoc: alias accept_rule do_nothing # :nodoc: alias accept_verbatim do_nothing # :nodoc: ## # Extracts tt sections from +text+ def tt_sections text flow = @am.flow text.dup flow.each do |item| case item when String then @res << item if in_tt? when RDoc::Markup::AttrChanger then off_tags res, item on_tags res, item when RDoc::Markup::RegexpHandling then @res << convert_regexp_handling(item) if in_tt? # TODO can this happen? else raise "Unknown flow element: #{item.inspect}" end end res end ## # Returns an Array of items that were wrapped in plus, tt or code. def end_accepting @res.compact end ## # Prepares the visitor for gathering tt sections def start_accepting @res = [] @list_type = [] end end PKu][nA##(rdoc-6.2.1.1/lib/rdoc/markup/verbatim.rbnu[# frozen_string_literal: true ## # A section of verbatim text class RDoc::Markup::Verbatim < RDoc::Markup::Raw ## # Format of this verbatim section attr_accessor :format def initialize *parts # :nodoc: super @format = nil end def == other # :nodoc: super and @format == other.format end ## # Calls #accept_verbatim on +visitor+ def accept visitor visitor.accept_verbatim self end ## # Collapses 3+ newlines into two newlines def normalize parts = [] newlines = 0 @parts.each do |part| case part when /^\s*\n/ then newlines += 1 parts << part if newlines == 1 else newlines = 0 parts << part end end parts.pop if parts.last =~ /\A\r?\n\z/ @parts = parts end def pretty_print q # :nodoc: self.class.name =~ /.*::(\w{1,4})/i q.group 2, "[#{$1.downcase}: ", ']' do if @format then q.text "format: #{@format}" q.breakable end q.seplist @parts do |part| q.pp part end end end ## # Is this verbatim section Ruby code? def ruby? @format ||= nil # TODO for older ri data, switch the tree to marshal_dump @format == :ruby end ## # The text of the section def text @parts.join end end PKu]eM/rdoc-6.2.1.1/lib/rdoc/markup/to_html_snippet.rbnu[# frozen_string_literal: true ## # Outputs RDoc markup as paragraphs with inline markup only. class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml ## # After this many characters the input will be cut off. attr_reader :character_limit ## # The number of characters seen so far. attr_reader :characters # :nodoc: ## # The attribute bitmask attr_reader :mask ## # After this many paragraphs the input will be cut off. attr_reader :paragraph_limit ## # Count of paragraphs found attr_reader :paragraphs ## # Creates a new ToHtmlSnippet formatter that will cut off the input on the # next word boundary after the given number of +characters+ or +paragraphs+ # of text have been encountered. def initialize options, characters = 100, paragraphs = 3, markup = nil super options, markup @character_limit = characters @paragraph_limit = paragraphs @characters = 0 @mask = 0 @paragraphs = 0 @markup.add_regexp_handling RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF end ## # Adds +heading+ to the output as a paragraph def accept_heading heading @res << "

    #{to_html heading.text}\n" add_paragraph end ## # Raw sections are untrusted and ignored alias accept_raw ignore ## # Rules are ignored alias accept_rule ignore def accept_paragraph paragraph para = @in_list_entry.last || "

    " text = paragraph.text @hard_break @res << "#{para}#{to_html text}\n" add_paragraph end ## # Finishes consumption of +list_item+ def accept_list_item_end list_item end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start list_item @res << list_item_start(list_item, @list.last) end ## # Prepares the visitor for consuming +list+ def accept_list_start list @list << list.type @res << html_list_name(list.type, true) @in_list_entry.push '' end ## # Adds +verbatim+ to the output def accept_verbatim verbatim throw :done if @characters >= @character_limit input = verbatim.text.rstrip text = truncate input text << ' ...' unless text == input super RDoc::Markup::Verbatim.new text add_paragraph end ## # Prepares the visitor for HTML snippet generation def start_accepting super @characters = 0 end ## # Removes escaping from the cross-references in +target+ def handle_regexp_CROSSREF target target.text.sub(/\A\\/, '') end ## # +target+ is a
    def handle_regexp_HARD_BREAK target @characters -= 4 '
    ' end ## # Lists are paragraphs, but notes and labels have a separator def list_item_start list_item, list_type throw :done if @characters >= @character_limit case list_type when :BULLET, :LALPHA, :NUMBER, :UALPHA then "

    " when :LABEL, :NOTE then labels = Array(list_item.label).map do |label| to_html label end.join ', ' labels << " — " unless labels.empty? start = "

    #{labels}" @characters += 1 # try to include the label start else raise RDoc::Error, "Invalid list type: #{list_type.inspect}" end end ## # Returns just the text of +link+, +url+ is only used to determine the link # type. def gen_url url, text if url =~ /^rdoc-label:([^:]*)(?::(.*))?/ then type = "link" elsif url =~ /([A-Za-z]+):(.*)/ then type = $1 else type = "http" end if (type == "http" or type == "https" or type == "link") and url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then '' else text.sub(%r%^#{type}:/*%, '') end end ## # In snippets, there are no lists def html_list_name list_type, open_tag '' end ## # Throws +:done+ when paragraph_limit paragraphs have been encountered def add_paragraph @paragraphs += 1 throw :done if @paragraphs >= @paragraph_limit end ## # Marks up +content+ def convert content catch :done do return super end end_accepting end ## # Converts flow items +flow+ def convert_flow flow throw :done if @characters >= @character_limit res = [] @mask = 0 flow.each do |item| case item when RDoc::Markup::AttrChanger then off_tags res, item on_tags res, item when String then text = convert_string item res << truncate(text) when RDoc::Markup::RegexpHandling then text = convert_regexp_handling item res << truncate(text) else raise "Unknown flow element: #{item.inspect}" end if @characters >= @character_limit then off_tags res, RDoc::Markup::AttrChanger.new(0, @mask) break end end res << ' ...' if @characters >= @character_limit res.join end ## # Maintains a bitmask to allow HTML elements to be closed properly. See # RDoc::Markup::Formatter. def on_tags res, item @mask ^= item.turn_on super end ## # Maintains a bitmask to allow HTML elements to be closed properly. See # RDoc::Markup::Formatter. def off_tags res, item @mask ^= item.turn_off super end ## # Truncates +text+ at the end of the first word after the character_limit. def truncate text length = text.length characters = @characters @characters += length return text if @characters < @character_limit remaining = @character_limit - characters text =~ /\A(.{#{remaining},}?)(\s|$)/m # TODO word-break instead of \s? $1 end end PKu]N_+rdoc-6.2.1.1/lib/rdoc/markup/block_quote.rbnu[# frozen_string_literal: true ## # A quoted section which contains markup items. class RDoc::Markup::BlockQuote < RDoc::Markup::Raw ## # Calls #accept_block_quote on +visitor+ def accept visitor visitor.accept_block_quote self end end PKu]tԇ*rdoc-6.2.1.1/lib/rdoc/markup/blank_line.rbnu[# frozen_string_literal: true ## # An empty line. This class is a singleton. class RDoc::Markup::BlankLine @instance = new ## # RDoc::Markup::BlankLine is a singleton def self.new @instance end ## # Calls #accept_blank_line on +visitor+ def accept visitor visitor.accept_blank_line self end def pretty_print q # :nodoc: q.text 'blankline' end end PKu]<88&rdoc-6.2.1.1/lib/rdoc/markup/parser.rbnu[# frozen_string_literal: true require 'strscan' ## # A recursive-descent parser for RDoc markup. # # The parser tokenizes an input string then parses the tokens into a Document. # Documents can be converted into output formats by writing a visitor like # RDoc::Markup::ToHTML. # # The parser only handles the block-level constructs Paragraph, List, # ListItem, Heading, Verbatim, BlankLine, Rule and BlockQuote. # Inline markup such as \+blah\+ is handled separately by # RDoc::Markup::AttributeManager. # # To see what markup the Parser implements read RDoc. To see how to use # RDoc markup to format text in your program read RDoc::Markup. class RDoc::Markup::Parser include RDoc::Text ## # List token types LIST_TOKENS = [ :BULLET, :LABEL, :LALPHA, :NOTE, :NUMBER, :UALPHA, ] ## # Parser error subclass class Error < RuntimeError; end ## # Raised when the parser is unable to handle the given markup class ParseError < Error; end ## # Enables display of debugging information attr_accessor :debug ## # Token accessor attr_reader :tokens ## # Parses +str+ into a Document. # # Use RDoc::Markup#parse instead of this method. def self.parse str parser = new parser.tokenize str doc = RDoc::Markup::Document.new parser.parse doc end ## # Returns a token stream for +str+, for testing def self.tokenize str parser = new parser.tokenize str parser.tokens end ## # Creates a new Parser. See also ::parse def initialize @binary_input = nil @current_token = nil @debug = false @s = nil @tokens = [] end ## # Builds a Heading of +level+ def build_heading level type, text, = get text = case type when :TEXT then skip :NEWLINE text else unget '' end RDoc::Markup::Heading.new level, text end ## # Builds a List flush to +margin+ def build_list margin p :list_start => margin if @debug list = RDoc::Markup::List.new label = nil until @tokens.empty? do type, data, column, = get case type when *LIST_TOKENS then if column < margin || (list.type && list.type != type) then unget break end list.type = type peek_type, _, column, = peek_token case type when :NOTE, :LABEL then label = [] unless label if peek_type == :NEWLINE then # description not on the same line as LABEL/NOTE # skip the trailing newline & any blank lines below while peek_type == :NEWLINE get peek_type, _, column, = peek_token end # we may be: # - at end of stream # - at a column < margin: # [text] # blah blah blah # - at the same column, but with a different type of list item # [text] # * blah blah # - at the same column, with the same type of list item # [one] # [two] # In all cases, we have an empty description. # In the last case only, we continue. if peek_type.nil? || column < margin then empty = true elsif column == margin then case peek_type when type empty = :continue when *LIST_TOKENS empty = true else empty = false end else empty = false end if empty then label << data next if empty == :continue break end end else data = nil end if label then data = label << data label = nil end list_item = RDoc::Markup::ListItem.new data parse list_item, column list << list_item else unget break end end p :list_end => margin if @debug if list.empty? then return nil unless label return nil unless [:LABEL, :NOTE].include? list.type list_item = RDoc::Markup::ListItem.new label, RDoc::Markup::BlankLine.new list << list_item end list end ## # Builds a Paragraph that is flush to +margin+ def build_paragraph margin p :paragraph_start => margin if @debug paragraph = RDoc::Markup::Paragraph.new until @tokens.empty? do type, data, column, = get if type == :TEXT and column == margin then paragraph << data break if peek_token.first == :BREAK data << ' ' if skip :NEWLINE else unget break end end paragraph.parts.last.sub!(/ \z/, '') # cleanup p :paragraph_end => margin if @debug paragraph end ## # Builds a Verbatim that is indented from +margin+. # # The verbatim block is shifted left (the least indented lines start in # column 0). Each part of the verbatim is one line of text, always # terminated by a newline. Blank lines always consist of a single newline # character, and there is never a single newline at the end of the verbatim. def build_verbatim margin p :verbatim_begin => margin if @debug verbatim = RDoc::Markup::Verbatim.new min_indent = nil generate_leading_spaces = true line = ''.dup until @tokens.empty? do type, data, column, = get if type == :NEWLINE then line << data verbatim << line line = ''.dup generate_leading_spaces = true next end if column <= margin unget break end if generate_leading_spaces then indent = column - margin line << ' ' * indent min_indent = indent if min_indent.nil? || indent < min_indent generate_leading_spaces = false end case type when :HEADER then line << '=' * data _, _, peek_column, = peek_token peek_column ||= column + data indent = peek_column - column - data line << ' ' * indent when :RULE then width = 2 + data line << '-' * width _, _, peek_column, = peek_token peek_column ||= column + width indent = peek_column - column - width line << ' ' * indent when :BREAK, :TEXT then line << data else # *LIST_TOKENS list_marker = case type when :BULLET then data when :LABEL then "[#{data}]" when :NOTE then "#{data}::" else # :LALPHA, :NUMBER, :UALPHA "#{data}." end line << list_marker peek_type, _, peek_column = peek_token unless peek_type == :NEWLINE then peek_column ||= column + list_marker.length indent = peek_column - column - list_marker.length line << ' ' * indent end end end verbatim << line << "\n" unless line.empty? verbatim.parts.each { |p| p.slice!(0, min_indent) unless p == "\n" } if min_indent > 0 verbatim.normalize p :verbatim_end => margin if @debug verbatim end ## # Pulls the next token from the stream. def get @current_token = @tokens.shift p :get => @current_token if @debug @current_token end ## # Parses the tokens into an array of RDoc::Markup::XXX objects, # and appends them to the passed +parent+ RDoc::Markup::YYY object. # # Exits at the end of the token stream, or when it encounters a token # in a column less than +indent+ (unless it is a NEWLINE). # # Returns +parent+. def parse parent, indent = 0 p :parse_start => indent if @debug until @tokens.empty? do type, data, column, = get case type when :BREAK then parent << RDoc::Markup::BlankLine.new skip :NEWLINE, false next when :NEWLINE then # trailing newlines are skipped below, so this is a blank line parent << RDoc::Markup::BlankLine.new skip :NEWLINE, false next end # indentation change: break or verbatim if column < indent then unget break elsif column > indent then unget parent << build_verbatim(indent) next end # indentation is the same case type when :HEADER then parent << build_heading(data) when :RULE then parent << RDoc::Markup::Rule.new(data) skip :NEWLINE when :TEXT then unget parse_text parent, indent when :BLOCKQUOTE then type, _, column = get if type == :NEWLINE type, _, column = get end unget if type bq = RDoc::Markup::BlockQuote.new p :blockquote_start => [data, column] if @debug parse bq, column p :blockquote_end => indent if @debug parent << bq when *LIST_TOKENS then unget parent << build_list(indent) else type, data, column, line = @current_token raise ParseError, "Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}" end end p :parse_end => indent if @debug parent end ## # Small hook that is overridden by RDoc::TomDoc def parse_text parent, indent # :nodoc: parent << build_paragraph(indent) end ## # Returns the next token on the stream without modifying the stream def peek_token token = @tokens.first || [] p :peek => token if @debug token end ## # A simple wrapper of StringScanner that is aware of the current column and lineno class MyStringScanner def initialize(input) @line = @column = 0 @s = StringScanner.new input end def scan(re) ret = @s.scan(re) @column += ret.length if ret ret end def unscan(s) @s.pos -= s.bytesize @column -= s.length end def pos [@column, @line] end def newline! @column = 0 @line += 1 end def eos? @s.eos? end def matched @s.matched end def [](i) @s[i] end end ## # Creates the StringScanner def setup_scanner input @s = MyStringScanner.new input end ## # Skips the next token if its type is +token_type+. # # Optionally raises an error if the next token is not of the expected type. def skip token_type, error = true type, = get return unless type # end of stream return @current_token if token_type == type unget raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if error end ## # Turns text +input+ into a stream of tokens def tokenize input setup_scanner input until @s.eos? do pos = @s.pos # leading spaces will be reflected by the column of the next token # the only thing we loose are trailing spaces at the end of the file next if @s.scan(/ +/) # note: after BULLET, LABEL, etc., # indent will be the column of the next non-newline token @tokens << case # [CR]LF => :NEWLINE when @s.scan(/\r?\n/) then token = [:NEWLINE, @s.matched, *pos] @s.newline! token # === text => :HEADER then :TEXT when @s.scan(/(=+)(\s*)/) then level = @s[1].length header = [:HEADER, level, *pos] if @s[2] =~ /^\r?\n/ then @s.unscan(@s[2]) header else pos = @s.pos @s.scan(/.*/) @tokens << header [:TEXT, @s.matched.sub(/\r$/, ''), *pos] end # --- (at least 3) and nothing else on the line => :RULE when @s.scan(/(-{3,}) *\r?$/) then [:RULE, @s[1].length - 2, *pos] # * or - followed by white space and text => :BULLET when @s.scan(/([*-]) +(\S)/) then @s.unscan(@s[2]) [:BULLET, @s[1], *pos] # A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER when @s.scan(/([a-z]|\d+)\. +(\S)/i) then # FIXME if tab(s), the column will be wrong # either support tabs everywhere by first expanding them to # spaces, or assume that they will have been replaced # before (and provide a check for that at least in debug # mode) list_label = @s[1] @s.unscan(@s[2]) list_type = case list_label when /[a-z]/ then :LALPHA when /[A-Z]/ then :UALPHA when /\d/ then :NUMBER else raise ParseError, "BUG token #{list_label}" end [list_type, list_label, *pos] # [text] followed by spaces or end of line => :LABEL when @s.scan(/\[(.*?)\]( +|\r?$)/) then [:LABEL, @s[1], *pos] # text:: followed by spaces or end of line => :NOTE when @s.scan(/(.*?)::( +|\r?$)/) then [:NOTE, @s[1], *pos] # >>> followed by end of line => :BLOCKQUOTE when @s.scan(/>>> *(\w+)?$/) then [:BLOCKQUOTE, @s[1], *pos] # anything else: :TEXT else @s.scan(/(.*?)( )?\r?$/) token = [:TEXT, @s[1], *pos] if @s[2] then @tokens << token [:BREAK, @s[2], pos[0] + @s[1].length, pos[1]] else token end end end self end ## # Returns the current token to the token stream def unget token = @current_token p :unget => token if @debug raise Error, 'too many #ungets' if token == @tokens.first @tokens.unshift token if token end end PKu]V'rdoc-6.2.1.1/lib/rdoc/markup/to_test.rbnu[# frozen_string_literal: true ## # This Markup outputter is used for testing purposes. class RDoc::Markup::ToTest < RDoc::Markup::Formatter # :stopdoc: ## # :section: Visitor def start_accepting @res = [] @list = [] end def end_accepting @res end def accept_paragraph(paragraph) @res << convert_flow(@am.flow(paragraph.text)) end def accept_raw raw @res << raw.parts.join end def accept_verbatim(verbatim) @res << verbatim.text.gsub(/^(\S)/, ' \1') end def accept_list_start(list) @list << case list.type when :BULLET then '*' when :NUMBER then '1' else list.type end end def accept_list_end(list) @list.pop end def accept_list_item_start(list_item) @res << "#{' ' * (@list.size - 1)}#{@list.last}: " end def accept_list_item_end(list_item) end def accept_blank_line(blank_line) @res << "\n" end def accept_heading(heading) @res << "#{'=' * heading.level} #{heading.text}" end def accept_rule(rule) @res << '-' * rule.weight end # :startdoc: end PKu]fQ`66'rdoc-6.2.1.1/lib/rdoc/markup/to_ansi.rbnu[# frozen_string_literal: true ## # Outputs RDoc markup with vibrant ANSI color! class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc ## # Creates a new ToAnsi visitor that is ready to output vibrant ANSI color! def initialize markup = nil super @headings.clear @headings[1] = ["\e[1;32m", "\e[m"] # bold @headings[2] = ["\e[4;32m", "\e[m"] # underline @headings[3] = ["\e[32m", "\e[m"] # just green end ## # Maps attributes to ANSI sequences def init_tags add_tag :BOLD, "\e[1m", "\e[m" add_tag :TT, "\e[7m", "\e[m" add_tag :EM, "\e[4m", "\e[m" end ## # Overrides indent width to ensure output lines up correctly. def accept_list_item_end list_item width = case @list_type.last when :BULLET then 2 when :NOTE, :LABEL then if @prefix then @res << @prefix.strip @prefix = nil end @res << "\n" unless res.length == 1 2 else bullet = @list_index.last.to_s @list_index[-1] = @list_index.last.succ bullet.length + 2 end @indent -= width end ## # Adds coloring to note and label list items def accept_list_item_start list_item bullet = case @list_type.last when :BULLET then '*' when :NOTE, :LABEL then labels = Array(list_item.label).map do |label| attributes(label).strip end.join "\n" labels << ":\n" unless labels.empty? labels else @list_index.last.to_s + '.' end case @list_type.last when :NOTE, :LABEL then @indent += 2 @prefix = bullet + (' ' * @indent) else @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1) width = bullet.gsub(/\e\[[\d;]*m/, '').length + 1 @indent += width end end ## # Starts accepting with a reset screen def start_accepting super @res = ["\e[0m"] end end PKu]d)rdoc-6.2.1.1/lib/rdoc/markup/paragraph.rbnu[# frozen_string_literal: true ## # A Paragraph of text class RDoc::Markup::Paragraph < RDoc::Markup::Raw ## # Calls #accept_paragraph on +visitor+ def accept visitor visitor.accept_paragraph self end ## # Joins the raw paragraph text and converts inline HardBreaks to the # +hard_break+ text. def text hard_break = '' @parts.map do |part| if RDoc::Markup::HardBreak === part then hard_break else part end end.join end end PKu]$$0rdoc-6.2.1.1/lib/rdoc/markup/to_html_crossref.rbnu[# frozen_string_literal: true ## # Subclass of the RDoc::Markup::ToHtml class that supports looking up method # names, classes, etc to create links. RDoc::CrossReference is used to # generate those links based on the current context. class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml # :stopdoc: ALL_CROSSREF_REGEXP = RDoc::CrossReference::ALL_CROSSREF_REGEXP CLASS_REGEXP_STR = RDoc::CrossReference::CLASS_REGEXP_STR CROSSREF_REGEXP = RDoc::CrossReference::CROSSREF_REGEXP METHOD_REGEXP_STR = RDoc::CrossReference::METHOD_REGEXP_STR # :startdoc: ## # RDoc::CodeObject for generating references attr_accessor :context ## # Should we show '#' characters on method references? attr_accessor :show_hash ## # Creates a new crossref resolver that generates links relative to +context+ # which lives at +from_path+ in the generated files. '#' characters on # references are removed unless +show_hash+ is true. Only method names # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true. def initialize(options, from_path, context, markup = nil) raise ArgumentError, 'from_path cannot be nil' if from_path.nil? super options, markup @context = context @from_path = from_path @hyperlink_all = @options.hyperlink_all @show_hash = @options.show_hash crossref_re = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP @markup.add_regexp_handling crossref_re, :CROSSREF @cross_reference = RDoc::CrossReference.new @context end ## # Creates a link to the reference +name+ if the name exists. If +text+ is # given it is used as the link text, otherwise +name+ is used. def cross_reference name, text = nil, code = true lookup = name name = name[1..-1] unless @show_hash if name[0, 1] == '#' if name =~ /(.*[^#:])@/ text ||= "#{CGI.unescape $'} at #{$1}" code = false else text ||= name end link lookup, text, code end ## # We're invoked when any text matches the CROSSREF pattern. If we find the # corresponding reference, generate a link. If the name we're looking for # contains no punctuation, we look for it up the module/class chain. For # example, ToHtml is found, even without the RDoc::Markup:: prefix, # because we look for it in module Markup first. def handle_regexp_CROSSREF(target) name = target.text return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails unless @hyperlink_all then # This ensures that words entirely consisting of lowercase letters will # not have cross-references generated (to suppress lots of erroneous # cross-references to "new" in text, for instance) return name if name =~ /\A[a-z]*\z/ end cross_reference name end ## # Handles rdoc-ref: scheme links and allows RDoc::Markup::ToHtml to # handle other schemes. def handle_regexp_HYPERLINK target return cross_reference $' if target.text =~ /\Ardoc-ref:/ super end ## # +target+ is an rdoc-schemed link that will be converted into a hyperlink. # For the rdoc-ref scheme the cross-reference will be looked up and the # given name will be used. # # All other contents are handled by # {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_regexp_RDOCLINK] def handle_regexp_RDOCLINK target url = target.text case url when /\Ardoc-ref:/ then cross_reference $' else super end end ## # Generates links for rdoc-ref: scheme URLs and allows # RDoc::Markup::ToHtml to handle other schemes. def gen_url url, text return super unless url =~ /\Ardoc-ref:/ name = $' cross_reference name, text, name == text end ## # Creates an HTML link to +name+ with the given +text+. def link name, text, code = true if name =~ /(.*[^#:])@/ then name = $1 label = $' end ref = @cross_reference.resolve name, text case ref when String then ref else path = ref.as_href @from_path if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref) text = "#{text}" end if path =~ /#/ then path << "-label-#{label}" elsif ref.sections and ref.sections.any? { |section| label == section.title } then path << "##{label}" else if ref.respond_to?(:aref) path << "##{ref.aref}-label-#{label}" else path << "#label-#{label}" end end if label "#{text}" end end end PKu]Q'rdoc-6.2.1.1/lib/rdoc/markup/to_rdoc.rbnu[# frozen_string_literal: true ## # Outputs RDoc markup as RDoc markup! (mostly) class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter ## # Current indent amount for output in characters attr_accessor :indent ## # Output width in characters attr_accessor :width ## # Stack of current list indexes for alphabetic and numeric lists attr_reader :list_index ## # Stack of list types attr_reader :list_type ## # Stack of list widths for indentation attr_reader :list_width ## # Prefix for the next list item. See #use_prefix attr_reader :prefix ## # Output accumulator attr_reader :res ## # Creates a new formatter that will output (mostly) \RDoc markup def initialize markup = nil super nil, markup @markup.add_regexp_handling(/\\\S/, :SUPPRESSED_CROSSREF) @width = 78 init_tags @headings = {} @headings.default = [] @headings[1] = ['= ', ''] @headings[2] = ['== ', ''] @headings[3] = ['=== ', ''] @headings[4] = ['==== ', ''] @headings[5] = ['===== ', ''] @headings[6] = ['====== ', ''] @hard_break = "\n" end ## # Maps attributes to HTML sequences def init_tags add_tag :BOLD, "", "" add_tag :TT, "", "" add_tag :EM, "", "" end ## # Adds +blank_line+ to the output def accept_blank_line blank_line @res << "\n" end ## # Adds +paragraph+ to the output def accept_block_quote block_quote @indent += 2 block_quote.parts.each do |part| @prefix = '> ' part.accept self end @indent -= 2 end ## # Adds +heading+ to the output def accept_heading heading use_prefix or @res << ' ' * @indent @res << @headings[heading.level][0] @res << attributes(heading.text) @res << @headings[heading.level][1] @res << "\n" end ## # Finishes consumption of +list+ def accept_list_end list @list_index.pop @list_type.pop @list_width.pop end ## # Finishes consumption of +list_item+ def accept_list_item_end list_item width = case @list_type.last when :BULLET then 2 when :NOTE, :LABEL then if @prefix then @res << @prefix.strip @prefix = nil end @res << "\n" 2 else bullet = @list_index.last.to_s @list_index[-1] = @list_index.last.succ bullet.length + 2 end @indent -= width end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start list_item type = @list_type.last case type when :NOTE, :LABEL then bullets = Array(list_item.label).map do |label| attributes(label).strip end.join "\n" bullets << ":\n" unless bullets.empty? @prefix = ' ' * @indent @indent += 2 @prefix << bullets + (' ' * @indent) else bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1) width = bullet.length + 1 @indent += width end end ## # Prepares the visitor for consuming +list+ def accept_list_start list case list.type when :BULLET then @list_index << nil @list_width << 1 when :LABEL, :NOTE then @list_index << nil @list_width << 2 when :LALPHA then @list_index << 'a' @list_width << list.items.length.to_s.length when :NUMBER then @list_index << 1 @list_width << list.items.length.to_s.length when :UALPHA then @list_index << 'A' @list_width << list.items.length.to_s.length else raise RDoc::Error, "invalid list type #{list.type}" end @list_type << list.type end ## # Adds +paragraph+ to the output def accept_paragraph paragraph text = paragraph.text @hard_break wrap attributes text end ## # Adds +paragraph+ to the output def accept_indented_paragraph paragraph @indent += paragraph.indent text = paragraph.text @hard_break wrap attributes text @indent -= paragraph.indent end ## # Adds +raw+ to the output def accept_raw raw @res << raw.parts.join("\n") end ## # Adds +rule+ to the output def accept_rule rule use_prefix or @res << ' ' * @indent @res << '-' * (@width - @indent) @res << "\n" end ## # Outputs +verbatim+ indented 2 columns def accept_verbatim verbatim indent = ' ' * (@indent + 2) verbatim.parts.each do |part| @res << indent unless part == "\n" @res << part end @res << "\n" end ## # Applies attribute-specific markup to +text+ using RDoc::AttributeManager def attributes text flow = @am.flow text.dup convert_flow flow end ## # Returns the generated output def end_accepting @res.join end ## # Removes preceding \\ from the suppressed crossref +target+ def handle_regexp_SUPPRESSED_CROSSREF target text = target.text text = text.sub('\\', '') unless in_tt? text end ## # Adds a newline to the output def handle_regexp_HARD_BREAK target "\n" end ## # Prepares the visitor for text generation def start_accepting @res = [""] @indent = 0 @prefix = nil @list_index = [] @list_type = [] @list_width = [] end ## # Adds the stored #prefix to the output and clears it. Lists generate a # prefix for later consumption. def use_prefix prefix, @prefix = @prefix, nil @res << prefix if prefix prefix end ## # Wraps +text+ to #width def wrap text return unless text && !text.empty? text_len = @width - @indent text_len = 20 if text_len < 20 re = /^(.{0,#{text_len}})[ \n]/ next_prefix = ' ' * @indent prefix = @prefix || next_prefix @prefix = nil @res << prefix while text.length > text_len if text =~ re then @res << $1 text.slice!(0, $&.length) else @res << text.slice!(0, text_len) end @res << "\n" << next_prefix end if text.empty? then @res.pop @res.pop else @res << text @res << "\n" end end end PKu]C"=='rdoc-6.2.1.1/lib/rdoc/markup/include.rbnu[# frozen_string_literal: true ## # A file included at generation time. Objects of this class are created by # RDoc::RD for an extension-less include. # # This implementation in incomplete. class RDoc::Markup::Include ## # The filename to be included, without extension attr_reader :file ## # Directories to search for #file attr_reader :include_path ## # Creates a new include that will import +file+ from +include_path+ def initialize file, include_path @file = file @include_path = include_path end def == other # :nodoc: self.class === other and @file == other.file and @include_path == other.include_path end def pretty_print q # :nodoc: q.group 2, '[incl ', ']' do q.text file q.breakable q.text 'from ' q.pp include_path end end end PKu]-Ǘ)rdoc-6.2.1.1/lib/rdoc/markup/formatter.rbnu[# frozen_string_literal: true ## # Base class for RDoc markup formatters # # Formatters are a visitor that converts an RDoc::Markup tree (from a comment) # into some kind of output. RDoc ships with formatters for converting back to # rdoc, ANSI text, HTML, a Table of Contents and other formats. # # If you'd like to write your own Formatter use # RDoc::Markup::FormatterTestCase. If you're writing a text-output formatter # use RDoc::Markup::TextFormatterTestCase which provides extra test cases. class RDoc::Markup::Formatter ## # Tag for inline markup containing a +bit+ for the bitmask and the +on+ and # +off+ triggers. InlineTag = Struct.new(:bit, :on, :off) ## # Converts a target url to one that is relative to a given path def self.gen_relative_url path, target from = File.dirname path to, to_file = File.split target from = from.split "/" to = to.split "/" from.delete '.' to.delete '.' while from.size > 0 and to.size > 0 and from[0] == to[0] do from.shift to.shift end from.fill ".." from.concat to from << to_file File.join(*from) end ## # Creates a new Formatter def initialize options, markup = nil @options = options @markup = markup || RDoc::Markup.new @am = @markup.attribute_manager @am.add_regexp_handling(/
    /, :HARD_BREAK) @attributes = @am.attributes @attr_tags = [] @in_tt = 0 @tt_bit = @attributes.bitmap_for :TT @hard_break = '' @from_path = '.' end ## # Adds +document+ to the output def accept_document document document.parts.each do |item| case item when RDoc::Markup::Document then # HACK accept_document item else item.accept self end end end ## # Adds a regexp handling for links of the form rdoc-...: def add_regexp_handling_RDOCLINK @markup.add_regexp_handling(/rdoc-[a-z]+:[^\s\]]+/, :RDOCLINK) end ## # Adds a regexp handling for links of the form {}[] and # [] def add_regexp_handling_TIDYLINK @markup.add_regexp_handling(/(?: \{.*?\} | # multi-word label \b[^\s{}]+? # single-word label ) \[\S+?\] # link target /x, :TIDYLINK) end ## # Add a new set of tags for an attribute. We allow separate start and end # tags for flexibility def add_tag(name, start, stop) attr = @attributes.bitmap_for name @attr_tags << InlineTag.new(attr, start, stop) end ## # Allows +tag+ to be decorated with additional information. def annotate(tag) tag end ## # Marks up +content+ def convert content @markup.convert content, self end ## # Converts flow items +flow+ def convert_flow(flow) res = [] flow.each do |item| case item when String then res << convert_string(item) when RDoc::Markup::AttrChanger then off_tags res, item on_tags res, item when RDoc::Markup::RegexpHandling then res << convert_regexp_handling(item) else raise "Unknown flow element: #{item.inspect}" end end res.join end ## # Converts added regexp handlings. See RDoc::Markup#add_regexp_handling def convert_regexp_handling target return target.text if in_tt? handled = false @attributes.each_name_of target.type do |name| method_name = "handle_regexp_#{name}" if respond_to? method_name then target.text = send method_name, target handled = true end end unless handled then target_name = @attributes.as_string target.type raise RDoc::Error, "Unhandled regexp handling #{target_name}: #{target}" end target.text end ## # Converts a string to be fancier if desired def convert_string string string end ## # Use ignore in your subclass to ignore the content of a node. # # ## # # We don't support raw nodes in ToNoRaw # # alias accept_raw ignore def ignore *node end ## # Are we currently inside tt tags? def in_tt? @in_tt > 0 end ## # Turns on tags for +item+ on +res+ def on_tags res, item attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 then res << annotate(tag.on) @in_tt += 1 if tt? tag end end end ## # Turns off tags for +item+ on +res+ def off_tags res, item attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 then @in_tt -= 1 if tt? tag res << annotate(tag.off) end end end ## # Extracts and a scheme, url and an anchor id from +url+ and returns them. def parse_url url case url when /^rdoc-label:([^:]*)(?::(.*))?/ then scheme = 'link' path = "##{$1}" id = " id=\"#{$2}\"" if $2 when /([A-Za-z]+):(.*)/ then scheme = $1.downcase path = $2 when /^#/ then else scheme = 'http' path = url url = url end if scheme == 'link' then url = if path[0, 1] == '#' then # is this meaningful? path else self.class.gen_relative_url @from_path, path end end [scheme, url, id] end ## # Is +tag+ a tt tag? def tt? tag tag.bit == @tt_bit end end PKu]|/rdoc-6.2.1.1/lib/rdoc/markup/regexp_handling.rbnu[# frozen_string_literal: true ## # Hold details of a regexp handling sequence class RDoc::Markup::RegexpHandling ## # Regexp handling type attr_reader :type ## # Regexp handling text attr_accessor :text ## # Creates a new regexp handling sequence of +type+ with +text+ def initialize(type, text) @type, @text = type, text end ## # Regexp handlings are equal when the have the same text and type def ==(o) self.text == o.text && self.type == o.type end def inspect # :nodoc: "#" % [ object_id, @type, text.dump] end def to_s # :nodoc: "RegexpHandling: type=#{type} text=#{text.dump}" end end PKu]ߦo,rdoc-6.2.1.1/lib/rdoc/markup/attr_changer.rbnu[# frozen_string_literal: true class RDoc::Markup AttrChanger = Struct.new :turn_on, :turn_off # :nodoc: end ## # An AttrChanger records a change in attributes. It contains a bitmap of the # attributes to turn on, and a bitmap of those to turn off. class RDoc::Markup::AttrChanger def to_s # :nodoc: "Attr: +#{turn_on}/-#{turn_off}" end def inspect # :nodoc: '+%d/-%d' % [turn_on, turn_off] end end PKu]|""'rdoc-6.2.1.1/lib/rdoc/markup/to_html.rbnu[# frozen_string_literal: true require 'cgi' ## # Outputs RDoc markup as HTML. class RDoc::Markup::ToHtml < RDoc::Markup::Formatter include RDoc::Text # :section: Utilities ## # Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags LIST_TYPE_TO_HTML = { :BULLET => ['

      ', '
    '], :LABEL => ['
    ', '
    '], :LALPHA => ['
      ', '
    '], :NOTE => ['
    ', '
    '], :NUMBER => ['
      ', '
    '], :UALPHA => ['
      ', '
    '], } attr_reader :res # :nodoc: attr_reader :in_list_entry # :nodoc: attr_reader :list # :nodoc: ## # The RDoc::CodeObject HTML is being generated for. This is used to # generate namespaced URI fragments attr_accessor :code_object ## # Path to this document for relative links attr_accessor :from_path # :section: ## # Creates a new formatter that will output HTML def initialize options, markup = nil super @code_object = nil @from_path = '' @in_list_entry = nil @list = nil @th = nil @hard_break = "
    \n" # external links @markup.add_regexp_handling(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/, :HYPERLINK) add_regexp_handling_RDOCLINK add_regexp_handling_TIDYLINK init_tags end # :section: Regexp Handling # # These methods are used by regexp handling markup added by RDoc::Markup#add_regexp_handling. def handle_RDOCLINK url # :nodoc: case url when /^rdoc-ref:/ $' when /^rdoc-label:/ text = $' text = case text when /\Alabel-/ then $' when /\Afootmark-/ then $' when /\Afoottext-/ then $' else text end gen_url url, text when /^rdoc-image:/ "" else url =~ /\Ardoc-[a-z]+:/ $' end end ## # +target+ is a
    def handle_regexp_HARD_BREAK target '
    ' end ## # +target+ is a potential link. The following schemes are handled: # # mailto::: # Inserted as-is. # http::: # Links are checked to see if they reference an image. If so, that image # gets inserted using an tag. Otherwise a conventional # is used. # link::: # Reference to a local file relative to the output directory. def handle_regexp_HYPERLINK(target) url = target.text gen_url url, url end ## # +target+ is an rdoc-schemed link that will be converted into a hyperlink. # # For the +rdoc-ref+ scheme the named reference will be returned without # creating a link. # # For the +rdoc-label+ scheme the footnote and label prefixes are stripped # when creating a link. All other contents will be linked verbatim. def handle_regexp_RDOCLINK target handle_RDOCLINK target.text end ## # This +target+ is a link where the label is different from the URL # label[url] or {long label}[url] def handle_regexp_TIDYLINK(target) text = target.text return text unless text =~ /^\{(.*)\}\[(.*?)\]$/ or text =~ /^(\S+)\[(.*?)\]$/ label = $1 url = $2 label = handle_RDOCLINK label if /^rdoc-image:/ =~ label gen_url url, label end # :section: Visitor # # These methods implement the HTML visitor. ## # Prepares the visitor for HTML generation def start_accepting @res = [] @in_list_entry = [] @list = [] end ## # Returns the generated output def end_accepting @res.join end ## # Adds +block_quote+ to the output def accept_block_quote block_quote @res << "\n
    " block_quote.parts.each do |part| part.accept self end @res << "
    \n" end ## # Adds +paragraph+ to the output def accept_paragraph paragraph @res << "\n

    " text = paragraph.text @hard_break text = text.gsub(/\r?\n/, ' ') @res << to_html(text) @res << "

    \n" end ## # Adds +verbatim+ to the output def accept_verbatim verbatim text = verbatim.text.rstrip klass = nil content = if verbatim.ruby? or parseable? text then begin tokens = RDoc::Parser::RipperStateLex.parse text klass = ' class="ruby"' result = RDoc::TokenStream.to_html tokens result = result + "\n" unless "\n" == result[-1] result rescue CGI.escapeHTML text end else CGI.escapeHTML text end if @options.pipe then @res << "\n
    #{CGI.escapeHTML text}\n
    \n" else @res << "\n#{content}\n" end end ## # Adds +rule+ to the output def accept_rule rule @res << "
    \n" end ## # Prepares the visitor for consuming +list+ def accept_list_start(list) @list << list.type @res << html_list_name(list.type, true) @in_list_entry.push false end ## # Finishes consumption of +list+ def accept_list_end(list) @list.pop if tag = @in_list_entry.pop @res << tag end @res << html_list_name(list.type, false) << "\n" end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start(list_item) if tag = @in_list_entry.last @res << tag end @res << list_item_start(list_item, @list.last) end ## # Finishes consumption of +list_item+ def accept_list_item_end(list_item) @in_list_entry[-1] = list_end_for(@list.last) end ## # Adds +blank_line+ to the output def accept_blank_line(blank_line) # @res << annotate("

    ") << "\n" end ## # Adds +heading+ to the output. The headings greater than 6 are trimmed to # level 6. def accept_heading heading level = [6, heading.level].min label = heading.label @code_object @res << if @options.output_decoration "\n" else "\n" end @res << to_html(heading.text) unless @options.pipe then @res << "" @res << " " end @res << "\n" end ## # Adds +raw+ to the output def accept_raw raw @res << raw.parts.join("\n") end # :section: Utilities ## # CGI-escapes +text+ def convert_string(text) CGI.escapeHTML text end ## # Generate a link to +url+ with content +text+. Handles the special cases # for img: and link: described under handle_regexp_HYPERLINK def gen_url url, text scheme, url, id = parse_url url if %w[http https link].include?(scheme) and url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then "" else text = text.sub %r%^#{scheme}:/*%i, '' text = text.sub %r%^[*\^](\d+)$%, '\1' link = "#{text}" link = "#{link}" if /"foot/ =~ id link end end ## # Determines the HTML list element for +list_type+ and +open_tag+ def html_list_name(list_type, open_tag) tags = LIST_TYPE_TO_HTML[list_type] raise RDoc::Error, "Invalid list type: #{list_type.inspect}" unless tags tags[open_tag ? 0 : 1] end ## # Maps attributes to HTML tags def init_tags add_tag :BOLD, "", "" add_tag :TT, "", "" add_tag :EM, "", "" end ## # Returns the HTML tag for +list_type+, possible using a label from # +list_item+ def list_item_start(list_item, list_type) case list_type when :BULLET, :LALPHA, :NUMBER, :UALPHA then "

  • " when :LABEL, :NOTE then Array(list_item.label).map do |label| "
    #{to_html label}\n" end.join << "
    " else raise RDoc::Error, "Invalid list type: #{list_type.inspect}" end end ## # Returns the HTML end-tag for +list_type+ def list_end_for(list_type) case list_type when :BULLET, :LALPHA, :NUMBER, :UALPHA then "
  • " when :LABEL, :NOTE then "" else raise RDoc::Error, "Invalid list type: #{list_type.inspect}" end end ## # Returns true if text is valid ruby syntax def parseable? text verbose, $VERBOSE = $VERBOSE, nil eval("BEGIN {return true}\n#{text}") rescue SyntaxError false ensure $VERBOSE = verbose end ## # Converts +item+ to HTML using RDoc::Text#to_html def to_html item super convert_flow @am.flow item end end PKu]FVV(rdoc-6.2.1.1/lib/rdoc/markup/to_label.rbnu[# frozen_string_literal: true require 'cgi' ## # Creates HTML-safe labels suitable for use in id attributes. Tidylinks are # converted to their link part and cross-reference links have the suppression # marks removed (\\SomeClass is converted to SomeClass). class RDoc::Markup::ToLabel < RDoc::Markup::Formatter attr_reader :res # :nodoc: ## # Creates a new formatter that will output HTML-safe labels def initialize markup = nil super nil, markup @markup.add_regexp_handling RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF @markup.add_regexp_handling(/(((\{.*?\})|\b\S+?)\[\S+?\])/, :TIDYLINK) add_tag :BOLD, '', '' add_tag :TT, '', '' add_tag :EM, '', '' @res = [] end ## # Converts +text+ to an HTML-safe label def convert text label = convert_flow @am.flow text CGI.escape(label).gsub('%', '-').sub(/^-/, '') end ## # Converts the CROSSREF +target+ to plain text, removing the suppression # marker, if any def handle_regexp_CROSSREF target text = target.text text.sub(/^\\/, '') end ## # Converts the TIDYLINK +target+ to just the text part def handle_regexp_TIDYLINK target text = target.text return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/ $1 end alias accept_blank_line ignore alias accept_block_quote ignore alias accept_heading ignore alias accept_list_end ignore alias accept_list_item_end ignore alias accept_list_item_start ignore alias accept_list_start ignore alias accept_paragraph ignore alias accept_raw ignore alias accept_rule ignore alias accept_verbatim ignore alias end_accepting ignore alias handle_regexp_HARD_BREAK ignore alias start_accepting ignore end PKu]<)rdoc-6.2.1.1/lib/rdoc/markup/attr_span.rbnu[# frozen_string_literal: true ## # An array of attributes which parallels the characters in a string. class RDoc::Markup::AttrSpan ## # Creates a new AttrSpan for +length+ characters def initialize(length) @attrs = Array.new(length, 0) end ## # Toggles +bits+ from +start+ to +length+ def set_attrs(start, length, bits) for i in start ... (start+length) @attrs[i] |= bits end end ## # Accesses flags for character +n+ def [](n) @attrs[n] end end PKu]ua1%rdoc-6.2.1.1/lib/rdoc/markup/to_bs.rbnu[# frozen_string_literal: true ## # Outputs RDoc markup with hot backspace action! You will probably need a # pager to use this output format. # # This formatter won't work on 1.8.6 because it lacks String#chars. class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc ## # Returns a new ToBs that is ready for hot backspace action! def initialize markup = nil super @in_b = false @in_em = false end ## # Sets a flag that is picked up by #annotate to do the right thing in # #convert_string def init_tags add_tag :BOLD, '+b', '-b' add_tag :EM, '+_', '-_' add_tag :TT, '' , '' # we need in_tt information maintained end ## # Makes heading text bold. def accept_heading heading use_prefix or @res << ' ' * @indent @res << @headings[heading.level][0] @in_b = true @res << attributes(heading.text) @in_b = false @res << @headings[heading.level][1] @res << "\n" end ## # Turns on or off regexp handling for +convert_string+ def annotate tag case tag when '+b' then @in_b = true when '-b' then @in_b = false when '+_' then @in_em = true when '-_' then @in_em = false end '' end ## # Calls convert_string on the result of convert_regexp_handling def convert_regexp_handling target convert_string super end ## # Adds bold or underline mixed with backspaces def convert_string string return string unless @in_b or @in_em chars = if @in_b then string.chars.map do |char| "#{char}\b#{char}" end elsif @in_em then string.chars.map do |char| "_\b#{char}" end end chars.join end end PKu]y *rdoc-6.2.1.1/lib/rdoc/markup/hard_break.rbnu[# frozen_string_literal: true ## # A hard-break in the middle of a paragraph. class RDoc::Markup::HardBreak @instance = new ## # RDoc::Markup::HardBreak is a singleton def self.new @instance end ## # Calls #accept_hard_break on +visitor+ def accept visitor visitor.accept_hard_break self end def == other # :nodoc: self.class === other end def pretty_print q # :nodoc: q.text "[break]" end end PKu] 7>?4rdoc-6.2.1.1/lib/rdoc/markup/to_table_of_contents.rbnu[# frozen_string_literal: true ## # Extracts just the RDoc::Markup::Heading elements from a # RDoc::Markup::Document to help build a table of contents class RDoc::Markup::ToTableOfContents < RDoc::Markup::Formatter @to_toc = nil ## # Singleton for table-of-contents generation def self.to_toc @to_toc ||= new end ## # Output accumulator attr_reader :res ## # Omits headings with a level less than the given level. attr_accessor :omit_headings_below def initialize # :nodoc: super nil @omit_headings_below = nil end ## # Adds +document+ to the output, using its heading cutoff if present def accept_document document @omit_headings_below = document.omit_headings_below super end ## # Adds +heading+ to the table of contents def accept_heading heading @res << heading unless suppressed? heading end ## # Returns the table of contents def end_accepting @res end ## # Prepares the visitor for text generation def start_accepting @omit_headings_below = nil @res = [] end ## # Returns true if +heading+ is below the display threshold def suppressed? heading return false unless @omit_headings_below heading.level > @omit_headings_below end # :stopdoc: alias accept_block_quote ignore alias accept_raw ignore alias accept_rule ignore alias accept_blank_line ignore alias accept_paragraph ignore alias accept_verbatim ignore alias accept_list_end ignore alias accept_list_item_start ignore alias accept_list_item_end ignore alias accept_list_end_bullet ignore alias accept_list_start ignore # :startdoc: end PKu]f !r r 1rdoc-6.2.1.1/lib/rdoc/markup/attribute_manager.rbnu[# frozen_string_literal: true ## # Manages changes of attributes in a block of text class RDoc::Markup::AttributeManager ## # The NUL character NULL = "\000".freeze #-- # We work by substituting non-printing characters in to the text. For now # I'm assuming that I can substitute a character in the range 0..8 for a 7 # bit character without damaging the encoded string, but this might be # optimistic #++ A_PROTECT = 004 # :nodoc: ## # Special mask character to prevent inline markup handling PROTECT_ATTR = A_PROTECT.chr # :nodoc: ## # The attributes enabled for this markup object. attr_reader :attributes ## # This maps delimiters that occur around words (such as *bold* or +tt+) # where the start and end delimiters and the same. This lets us optimize # the regexp attr_reader :matching_word_pairs ## # And this is used when the delimiters aren't the same. In this case the # hash maps a pattern to the attribute character attr_reader :word_pair_map ## # This maps HTML tags to the corresponding attribute char attr_reader :html_tags ## # A \ in front of a character that would normally be processed turns off # processing. We do this by turning \< into <#{PROTECT} attr_reader :protectable ## # And this maps _regexp handling_ sequences to a name. A regexp handling # sequence is something like a WikiWord attr_reader :regexp_handlings ## # Creates a new attribute manager that understands bold, emphasized and # teletype text. def initialize @html_tags = {} @matching_word_pairs = {} @protectable = %w[<] @regexp_handlings = [] @word_pair_map = {} @attributes = RDoc::Markup::Attributes.new add_word_pair "*", "*", :BOLD add_word_pair "_", "_", :EM add_word_pair "+", "+", :TT add_html "em", :EM add_html "i", :EM add_html "b", :BOLD add_html "tt", :TT add_html "code", :TT end ## # Return an attribute object with the given turn_on and turn_off bits set def attribute(turn_on, turn_off) RDoc::Markup::AttrChanger.new turn_on, turn_off end ## # Changes the current attribute from +current+ to +new+ def change_attribute current, new diff = current ^ new attribute(new & diff, current & diff) end ## # Used by the tests to change attributes by name from +current_set+ to # +new_set+ def changed_attribute_by_name current_set, new_set current = new = 0 current_set.each do |name| current |= @attributes.bitmap_for(name) end new_set.each do |name| new |= @attributes.bitmap_for(name) end change_attribute(current, new) end ## # Copies +start_pos+ to +end_pos+ from the current string def copy_string(start_pos, end_pos) res = @str[start_pos...end_pos] res.gsub!(/\000/, '') res end ## # Map attributes like textto the sequence # \001\002\001\003, where is a per-attribute specific # character def convert_attrs(str, attrs) # first do matching ones tags = @matching_word_pairs.keys.join("") re = /(^|\W)([#{tags}])([#\\]?[\w:.\/-]+?\S?)\2(\W|$)/ 1 while str.gsub!(re) do attr = @matching_word_pairs[$2] attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr) $1 + NULL * $2.length + $3 + NULL * $2.length + $4 end # then non-matching unless @word_pair_map.empty? then @word_pair_map.each do |regexp, attr| str.gsub!(regexp) { attrs.set_attrs($`.length + $1.length, $2.length, attr) NULL * $1.length + $2 + NULL * $3.length } end end end ## # Converts HTML tags to RDoc attributes def convert_html(str, attrs) tags = @html_tags.keys.join '|' 1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) { attr = @html_tags[$1.downcase] html_length = $1.length + 2 seq = NULL * html_length attrs.set_attrs($`.length + html_length, $2.length, attr) seq + $2 + seq + NULL } end ## # Converts regexp handling sequences to RDoc attributes def convert_regexp_handlings str, attrs @regexp_handlings.each do |regexp, attribute| str.scan(regexp) do capture = $~.size == 1 ? 0 : 1 s, e = $~.offset capture attrs.set_attrs s, e - s, attribute | @attributes.regexp_handling end end end ## # Escapes regexp handling sequences of text to prevent conversion to RDoc def mask_protected_sequences # protect __send__, __FILE__, etc. @str.gsub!(/__([a-z]+)__/i, "_#{PROTECT_ATTR}_#{PROTECT_ATTR}\\1_#{PROTECT_ATTR}_#{PROTECT_ATTR}") @str.gsub!(/(\A|[^\\])\\([#{Regexp.escape @protectable.join}])/m, "\\1\\2#{PROTECT_ATTR}") @str.gsub!(/\\(\\[#{Regexp.escape @protectable.join}])/m, "\\1") end ## # Unescapes regexp handling sequences of text def unmask_protected_sequences @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000") end ## # Adds a markup class with +name+ for words wrapped in the +start+ and # +stop+ character. To make words wrapped with "*" bold: # # am.add_word_pair '*', '*', :BOLD def add_word_pair(start, stop, name) raise ArgumentError, "Word flags may not start with '<'" if start[0,1] == '<' bitmap = @attributes.bitmap_for name if start == stop then @matching_word_pairs[start] = bitmap else pattern = /(#{Regexp.escape start})(\S+)(#{Regexp.escape stop})/ @word_pair_map[pattern] = bitmap end @protectable << start[0,1] @protectable.uniq! end ## # Adds a markup class with +name+ for words surrounded by HTML tag +tag+. # To process emphasis tags: # # am.add_html 'em', :EM def add_html(tag, name) @html_tags[tag.downcase] = @attributes.bitmap_for name end ## # Adds a regexp handling for +pattern+ with +name+. A simple URL handler # would be: # # @am.add_regexp_handling(/((https?:)\S+\w)/, :HYPERLINK) def add_regexp_handling pattern, name @regexp_handlings << [pattern, @attributes.bitmap_for(name)] end ## # Processes +str+ converting attributes, HTML and regexp handlings def flow str @str = str.dup mask_protected_sequences @attrs = RDoc::Markup::AttrSpan.new @str.length convert_attrs @str, @attrs convert_html @str, @attrs convert_regexp_handlings @str, @attrs unmask_protected_sequences split_into_flow end ## # Debug method that prints a string along with its attributes def display_attributes puts puts @str.tr(NULL, "!") bit = 1 16.times do |bno| line = "" @str.length.times do |i| if (@attrs[i] & bit) == 0 line << " " else if bno.zero? line << "S" else line << ("%d" % (bno+1)) end end end puts(line) unless line =~ /^ *$/ bit <<= 1 end end ## # Splits the string into chunks by attribute change def split_into_flow res = [] current_attr = 0 str_len = @str.length # skip leading invisible text i = 0 i += 1 while i < str_len and @str[i].chr == "\0" start_pos = i # then scan the string, chunking it on attribute changes while i < str_len new_attr = @attrs[i] if new_attr != current_attr if i > start_pos res << copy_string(start_pos, i) start_pos = i end res << change_attribute(current_attr, new_attr) current_attr = new_attr if (current_attr & @attributes.regexp_handling) != 0 then i += 1 while i < str_len and (@attrs[i] & @attributes.regexp_handling) != 0 res << RDoc::Markup::RegexpHandling.new(current_attr, copy_string(start_pos, i)) start_pos = i next end end # move on, skipping any invisible characters begin i += 1 end while i < str_len and @str[i].chr == "\0" end # tidy up trailing text if start_pos < str_len res << copy_string(start_pos, str_len) end # and reset to all attributes off res << change_attribute(current_attr, 0) if current_attr != 0 res end end PKu]6WG!G!+rdoc-6.2.1.1/lib/rdoc/markup/pre_process.rbnu[# frozen_string_literal: true ## # Handle common directives that can occur in a block of text: # # \:include: filename # # Directives can be escaped by preceding them with a backslash. # # RDoc plugin authors can register additional directives to be handled by # using RDoc::Markup::PreProcess::register. # # Any directive that is not built-in to RDoc (including those registered via # plugins) will be stored in the metadata hash on the CodeObject the comment # is attached to. See RDoc::Markup@Directives for the list of built-in # directives. class RDoc::Markup::PreProcess ## # An RDoc::Options instance that will be filled in with overrides from # directives attr_accessor :options ## # Adds a post-process handler for directives. The handler will be called # with the result RDoc::Comment (or text String) and the code object for the # comment (if any). def self.post_process &block @post_processors << block end ## # Registered post-processors def self.post_processors @post_processors end ## # Registers +directive+ as one handled by RDoc. If a block is given the # directive will be replaced by the result of the block, otherwise the # directive will be removed from the processed text. # # The block will be called with the directive name and the directive # parameter: # # RDoc::Markup::PreProcess.register 'my-directive' do |directive, param| # # replace text, etc. # end def self.register directive, &block @registered[directive] = block end ## # Registered directives def self.registered @registered end ## # Clears all registered directives and post-processors def self.reset @post_processors = [] @registered = {} end reset ## # Creates a new pre-processor for +input_file_name+ that will look for # included files in +include_path+ def initialize(input_file_name, include_path) @input_file_name = input_file_name @include_path = include_path @options = nil end ## # Look for directives in the given +text+. # # Options that we don't handle are yielded. If the block returns false the # directive is restored to the text. If the block returns nil or no block # was given the directive is handled according to the registered directives. # If a String was returned the directive is replaced with the string. # # If no matching directive was registered the directive is restored to the # text. # # If +code_object+ is given and the directive is unknown then the # directive's parameter is set as metadata on the +code_object+. See # RDoc::CodeObject#metadata for details. def handle text, code_object = nil, &block if RDoc::Comment === text then comment = text text = text.text end # regexp helper (square brackets for optional) # $1 $2 $3 $4 $5 # [prefix][\]:directive:[spaces][param]newline text = text.gsub(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?(\r?\n|$)/) do # skip something like ':toto::' next $& if $4.empty? and $5 and $5[0, 1] == ':' # skip if escaped next "#$1:#$3:#$4#$5\n" unless $2.empty? # This is not in handle_directive because I didn't want to pass another # argument into it if comment and $3 == 'markup' then next "#{$1.strip}\n" unless $5 comment.format = $5.downcase next "#{$1.strip}\n" end handle_directive $1, $3, $5, code_object, text.encoding, &block end if comment then comment.text = text else comment = text end self.class.post_processors.each do |handler| handler.call comment, code_object end text end ## # Performs the actions described by +directive+ and its parameter +param+. # # +code_object+ is used for directives that operate on a class or module. # +prefix+ is used to ensure the replacement for handled directives is # correct. +encoding+ is used for the include directive. # # For a list of directives in RDoc see RDoc::Markup. #-- # When 1.8.7 support is ditched prefix can be defaulted to '' def handle_directive prefix, directive, param, code_object = nil, encoding = nil blankline = "#{prefix.strip}\n" directive = directive.downcase case directive when 'arg', 'args' then return "#{prefix}:#{directive}: #{param}\n" unless code_object && code_object.kind_of?(RDoc::AnyMethod) code_object.params = param blankline when 'category' then if RDoc::Context === code_object then section = code_object.add_section param code_object.temporary_section = section end blankline # ignore category if we're not on an RDoc::Context when 'doc' then return blankline unless code_object code_object.document_self = true code_object.force_documentation = true blankline when 'enddoc' then return blankline unless code_object code_object.done_documenting = true blankline when 'include' then filename = param.split.first include_file filename, prefix, encoding when 'main' then @options.main_page = param if @options.respond_to? :main_page blankline when 'nodoc' then return blankline unless code_object code_object.document_self = nil # notify nodoc code_object.document_children = param !~ /all/i blankline when 'notnew', 'not_new', 'not-new' then return blankline unless RDoc::AnyMethod === code_object code_object.dont_rename_initialize = true blankline when 'startdoc' then return blankline unless code_object code_object.start_doc code_object.force_documentation = true blankline when 'stopdoc' then return blankline unless code_object code_object.stop_doc blankline when 'title' then @options.default_title = param if @options.respond_to? :default_title= blankline when 'yield', 'yields' then return blankline unless code_object # remove parameter &block code_object.params = code_object.params.sub(/,?\s*&\w+/, '') if code_object.params code_object.block_params = param blankline else result = yield directive, param if block_given? case result when nil then code_object.metadata[directive] = param if code_object if RDoc::Markup::PreProcess.registered.include? directive then handler = RDoc::Markup::PreProcess.registered[directive] result = handler.call directive, param if handler else result = "#{prefix}:#{directive}: #{param}\n" end when false then result = "#{prefix}:#{directive}: #{param}\n" end result end end ## # Handles the :include: _filename_ directive. # # If the first line of the included file starts with '#', and contains # an encoding information in the form 'coding:' or 'coding=', it is # removed. # # If all lines in the included file start with a '#', this leading '#' # is removed before inclusion. The included content is indented like # the :include: directive. #-- # so all content will be verbatim because of the likely space after '#'? # TODO shift left the whole file content in that case # TODO comment stop/start #-- and #++ in included file must be processed here def include_file name, indent, encoding full_name = find_include_file name unless full_name then warn "Couldn't find file to include '#{name}' from #{@input_file_name}" return '' end content = RDoc::Encoding.read_file full_name, encoding, true content = RDoc::Encoding.remove_magic_comment content # strip magic comment content = content.sub(/\A# .*coding[=:].*$/, '').lstrip # strip leading '#'s, but only if all lines start with them if content =~ /^[^#]/ then content.gsub(/^/, indent) else content.gsub(/^#?/, indent) end end ## # Look for the given file in the directory containing the current file, # and then in each of the directories specified in the RDOC_INCLUDE path def find_include_file(name) to_search = [File.dirname(@input_file_name)].concat @include_path to_search.each do |dir| full_name = File.join(dir, name) stat = File.stat(full_name) rescue next return full_name if stat.readable? end nil end end PKu]ھ*rdoc-6.2.1.1/lib/rdoc/markup/attributes.rbnu[# frozen_string_literal: true ## # We manage a set of attributes. Each attribute has a symbol name and a bit # value. class RDoc::Markup::Attributes ## # The regexp handling attribute type. See RDoc::Markup#add_regexp_handling attr_reader :regexp_handling ## # Creates a new attributes set. def initialize @regexp_handling = 1 @name_to_bitmap = [ [:_REGEXP_HANDLING_, @regexp_handling], ] @next_bitmap = @regexp_handling << 1 end ## # Returns a unique bit for +name+ def bitmap_for name bitmap = @name_to_bitmap.assoc name unless bitmap then bitmap = @next_bitmap @next_bitmap <<= 1 @name_to_bitmap << [name, bitmap] else bitmap = bitmap.last end bitmap end ## # Returns a string representation of +bitmap+ def as_string bitmap return 'none' if bitmap.zero? res = [] @name_to_bitmap.each do |name, bit| res << name if (bitmap & bit) != 0 end res.join ',' end ## # yields each attribute name in +bitmap+ def each_name_of bitmap return enum_for __method__, bitmap unless block_given? @name_to_bitmap.each do |name, bit| next if bit == @regexp_handling yield name.to_s if (bitmap & bit) != 0 end end end PKu]6%Vee3rdoc-6.2.1.1/lib/rdoc/markup/to_joined_paragraph.rbnu[# frozen_string_literal: true ## # Joins the parts of an RDoc::Markup::Paragraph into a single String. # # This allows for easier maintenance and testing of Markdown support. # # This formatter only works on Paragraph instances. Attempting to process # other markup syntax items will not work. class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter def initialize # :nodoc: super nil end def start_accepting # :nodoc: end def end_accepting # :nodoc: end ## # Converts the parts of +paragraph+ to a single entry. def accept_paragraph paragraph parts = paragraph.parts.chunk do |part| String === part end.map do |string, chunk| string ? chunk.join.rstrip : chunk end.flatten paragraph.parts.replace parts end alias accept_block_quote ignore alias accept_heading ignore alias accept_list_end ignore alias accept_list_item_end ignore alias accept_list_item_start ignore alias accept_list_start ignore alias accept_raw ignore alias accept_rule ignore alias accept_verbatim ignore end PKu]ԄEE$rdoc-6.2.1.1/lib/rdoc/markup/list.rbnu[# frozen_string_literal: true ## # A List is a homogeneous set of ListItems. # # The supported list types include: # # :BULLET:: # An unordered list # :LABEL:: # An unordered definition list, but using an alternate RDoc::Markup syntax # :LALPHA:: # An ordered list using increasing lowercase English letters # :NOTE:: # An unordered definition list # :NUMBER:: # An ordered list using increasing Arabic numerals # :UALPHA:: # An ordered list using increasing uppercase English letters # # Definition lists behave like HTML definition lists. Each list item can # describe multiple terms. See RDoc::Markup::ListItem for how labels and # definition are stored as list items. class RDoc::Markup::List ## # The list's type attr_accessor :type ## # Items in the list attr_reader :items ## # Creates a new list of +type+ with +items+. Valid list types are: # +:BULLET+, +:LABEL+, +:LALPHA+, +:NOTE+, +:NUMBER+, +:UALPHA+ def initialize type = nil, *items @type = type @items = [] @items.concat items end ## # Appends +item+ to the list def << item @items << item end def == other # :nodoc: self.class == other.class and @type == other.type and @items == other.items end ## # Runs this list and all its #items through +visitor+ def accept visitor visitor.accept_list_start self @items.each do |item| item.accept visitor end visitor.accept_list_end self end ## # Is the list empty? def empty? @items.empty? end ## # Returns the last item in the list def last @items.last end def pretty_print q # :nodoc: q.group 2, "[list: #{@type} ", ']' do q.seplist @items do |item| q.pp item end end end ## # Appends +items+ to the list def push *items @items.concat items end end PKu]fcr)rdoc-6.2.1.1/lib/rdoc/markup/list_item.rbnu[# frozen_string_literal: true ## # An item within a List that contains paragraphs, headings, etc. # # For BULLET, NUMBER, LALPHA and UALPHA lists, the label will always be nil. # For NOTE and LABEL lists, the list label may contain: # # * a single String for a single label # * an Array of Strings for a list item with multiple terms # * nil for an extra description attached to a previously labeled list item class RDoc::Markup::ListItem ## # The label for the ListItem attr_accessor :label ## # Parts of the ListItem attr_reader :parts ## # Creates a new ListItem with an optional +label+ containing +parts+ def initialize label = nil, *parts @label = label @parts = [] @parts.concat parts end ## # Appends +part+ to the ListItem def << part @parts << part end def == other # :nodoc: self.class == other.class and @label == other.label and @parts == other.parts end ## # Runs this list item and all its #parts through +visitor+ def accept visitor visitor.accept_list_item_start self @parts.each do |part| part.accept visitor end visitor.accept_list_item_end self end ## # Is the ListItem empty? def empty? @parts.empty? end ## # Length of parts in the ListItem def length @parts.length end def pretty_print q # :nodoc: q.group 2, '[item: ', ']' do case @label when Array then q.pp @label q.text ';' q.breakable when String then q.pp @label q.text ';' q.breakable end q.seplist @parts do |part| q.pp part end end end ## # Adds +parts+ to the ListItem def push *parts @parts.concat parts end end PKu]Т2rdoc-6.2.1.1/lib/rdoc/markup/indented_paragraph.rbnu[# frozen_string_literal: true ## # An Indented Paragraph of text class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw ## # The indent in number of spaces attr_reader :indent ## # Creates a new IndentedParagraph containing +parts+ indented with +indent+ # spaces def initialize indent, *parts @indent = indent super(*parts) end def == other # :nodoc: super and indent == other.indent end ## # Calls #accept_indented_paragraph on +visitor+ def accept visitor visitor.accept_indented_paragraph self end ## # Joins the raw paragraph text and converts inline HardBreaks to the # +hard_break+ text followed by the indent. def text hard_break = nil @parts.map do |part| if RDoc::Markup::HardBreak === part then '%1$s%3$*2$s' % [hard_break, @indent, ' '] if hard_break else part end end.join end end PKu];;$rdoc-6.2.1.1/lib/rdoc/markup/rule.rbnu[# frozen_string_literal: true ## # A horizontal rule with a weight class RDoc::Markup::Rule < Struct.new :weight ## # Calls #accept_rule on +visitor+ def accept visitor visitor.accept_rule self end def pretty_print q # :nodoc: q.group 2, '[rule:', ']' do q.pp weight end end end PKu]M#rdoc-6.2.1.1/lib/rdoc/markup/raw.rbnu[# frozen_string_literal: true ## # A section of text that is added to the output document as-is class RDoc::Markup::Raw ## # The component parts of the list attr_reader :parts ## # Creates a new Raw containing +parts+ def initialize *parts @parts = [] @parts.concat parts end ## # Appends +text+ def << text @parts << text end def == other # :nodoc: self.class == other.class and @parts == other.parts end ## # Calls #accept_raw+ on +visitor+ def accept visitor visitor.accept_raw self end ## # Appends +other+'s parts def merge other @parts.concat other.parts end def pretty_print q # :nodoc: self.class.name =~ /.*::(\w{1,4})/i q.group 2, "[#{$1.downcase}: ", ']' do q.seplist @parts do |part| q.pp part end end end ## # Appends +texts+ onto this Paragraph def push *texts self.parts.concat texts end ## # The raw text def text @parts.join ' ' end end PKu]p'rdoc-6.2.1.1/lib/rdoc/markup/heading.rbnu[# frozen_string_literal: true ## # A heading with a level (1-6) and text RDoc::Markup::Heading = Struct.new :level, :text do @to_html = nil @to_label = nil ## # A singleton RDoc::Markup::ToLabel formatter for headings. def self.to_label @to_label ||= RDoc::Markup::ToLabel.new end ## # A singleton plain HTML formatter for headings. Used for creating labels # for the Table of Contents def self.to_html return @to_html if @to_html markup = RDoc::Markup.new markup.add_regexp_handling RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF @to_html = RDoc::Markup::ToHtml.new nil def @to_html.handle_regexp_CROSSREF target target.text.sub(/^\\/, '') end @to_html end ## # Calls #accept_heading on +visitor+ def accept visitor visitor.accept_heading self end ## # An HTML-safe anchor reference for this header. def aref "label-#{self.class.to_label.convert text.dup}" end ## # Creates a fully-qualified label which will include the label from # +context+. This helps keep ids unique in HTML. def label context = nil label = aref label = [context.aref, label].compact.join '-' if context and context.respond_to? :aref label end ## # HTML markup of the text of this label without the surrounding header # element. def plain_html self.class.to_html.to_html(text.dup) end def pretty_print q # :nodoc: q.group 2, "[head: #{level} ", ']' do q.pp text end end end PKu]WY (rdoc-6.2.1.1/lib/rdoc/markup/document.rbnu[# frozen_string_literal: true ## # A Document containing lists, headings, paragraphs, etc. class RDoc::Markup::Document include Enumerable ## # The file this document was created from. See also # RDoc::ClassModule#add_comment attr_reader :file ## # If a heading is below the given level it will be omitted from the # table_of_contents attr_accessor :omit_headings_below ## # The parts of the Document attr_reader :parts ## # Creates a new Document with +parts+ def initialize *parts @parts = [] @parts.concat parts @file = nil @omit_headings_from_table_of_contents_below = nil end ## # Appends +part+ to the document def << part case part when RDoc::Markup::Document then unless part.empty? then parts.concat part.parts parts << RDoc::Markup::BlankLine.new end when String then raise ArgumentError, "expected RDoc::Markup::Document and friends, got String" unless part.empty? else parts << part end end def == other # :nodoc: self.class == other.class and @file == other.file and @parts == other.parts end ## # Runs this document and all its #items through +visitor+ def accept visitor visitor.start_accepting visitor.accept_document self visitor.end_accepting end ## # Concatenates the given +parts+ onto the document def concat parts self.parts.concat parts end ## # Enumerator for the parts of this document def each &block @parts.each(&block) end ## # Does this document have no parts? def empty? @parts.empty? or (@parts.length == 1 and merged? and @parts.first.empty?) end ## # The file this Document was created from. def file= location @file = case location when RDoc::TopLevel then location.relative_name else location end end ## # When this is a collection of documents (#file is not set and this document # contains only other documents as its direct children) #merge replaces # documents in this class with documents from +other+ when the file matches # and adds documents from +other+ when the files do not. # # The information in +other+ is preferred over the receiver def merge other if empty? then @parts = other.parts return self end other.parts.each do |other_part| self.parts.delete_if do |self_part| self_part.file and self_part.file == other_part.file end self.parts << other_part end self end ## # Does this Document contain other Documents? def merged? RDoc::Markup::Document === @parts.first end def pretty_print q # :nodoc: start = @file ? "[doc (#{@file}): " : '[doc: ' q.group 2, start, ']' do q.seplist @parts do |part| q.pp part end end end ## # Appends +parts+ to the document def push *parts self.parts.concat parts end ## # Returns an Array of headings in the document. # # Require 'rdoc/markup/formatter' before calling this method. def table_of_contents accept RDoc::Markup::ToTableOfContents.to_toc end end PKu] t{ll+rdoc-6.2.1.1/lib/rdoc/markup/to_markdown.rbnu[# frozen_string_literal: true # :markup: markdown ## # Outputs parsed markup as Markdown class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc ## # Creates a new formatter that will output Markdown format text def initialize markup = nil super @headings[1] = ['# ', ''] @headings[2] = ['## ', ''] @headings[3] = ['### ', ''] @headings[4] = ['#### ', ''] @headings[5] = ['##### ', ''] @headings[6] = ['###### ', ''] add_regexp_handling_RDOCLINK add_regexp_handling_TIDYLINK @hard_break = " \n" end ## # Maps attributes to HTML sequences def init_tags add_tag :BOLD, '**', '**' add_tag :EM, '*', '*' add_tag :TT, '`', '`' end ## # Adds a newline to the output def handle_regexp_HARD_BREAK target " \n" end ## # Finishes consumption of `list` def accept_list_end list @res << "\n" super end ## # Finishes consumption of `list_item` def accept_list_item_end list_item width = case @list_type.last when :BULLET then 4 when :NOTE, :LABEL then use_prefix 4 else @list_index[-1] = @list_index.last.succ 4 end @indent -= width end ## # Prepares the visitor for consuming `list_item` def accept_list_item_start list_item type = @list_type.last case type when :NOTE, :LABEL then bullets = Array(list_item.label).map do |label| attributes(label).strip end.join "\n" bullets << "\n:" @prefix = ' ' * @indent @indent += 4 @prefix << bullets + (' ' * (@indent - 1)) else bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' @prefix = (' ' * @indent) + bullet.ljust(4) @indent += 4 end end ## # Prepares the visitor for consuming `list` def accept_list_start list case list.type when :BULLET, :LABEL, :NOTE then @list_index << nil when :LALPHA, :NUMBER, :UALPHA then @list_index << 1 else raise RDoc::Error, "invalid list type #{list.type}" end @list_width << 4 @list_type << list.type end ## # Adds `rule` to the output def accept_rule rule use_prefix or @res << ' ' * @indent @res << '-' * 3 @res << "\n" end ## # Outputs `verbatim` indented 4 columns def accept_verbatim verbatim indent = ' ' * (@indent + 4) verbatim.parts.each do |part| @res << indent unless part == "\n" @res << part end @res << "\n" end ## # Creates a Markdown-style URL from +url+ with +text+. def gen_url url, text scheme, url, = parse_url url "[#{text.sub(%r{^#{scheme}:/*}i, '')}](#{url})" end ## # Handles rdoc- type links for footnotes. def handle_rdoc_link url case url when /^rdoc-ref:/ then $' when /^rdoc-label:footmark-(\d+)/ then "[^#{$1}]:" when /^rdoc-label:foottext-(\d+)/ then "[^#{$1}]" when /^rdoc-label:label-/ then gen_url url, $' when /^rdoc-image:/ then "![](#{$'})" when /^rdoc-[a-z]+:/ then $' end end ## # Converts the RDoc markup tidylink into a Markdown.style link. def handle_regexp_TIDYLINK target text = target.text return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/ label = $1 url = $2 if url =~ /^rdoc-label:foot/ then handle_rdoc_link url else gen_url url, label end end ## # Converts the rdoc-...: links into a Markdown.style links. def handle_regexp_RDOCLINK target handle_rdoc_link target.text end end PKu]Vnrr%rdoc-6.2.1.1/lib/rdoc/ri/formatter.rbnu[# frozen_string_literal: true ## # For RubyGems backwards compatibility module RDoc::RI::Formatter # :nodoc: end PKu] qh!rdoc-6.2.1.1/lib/rdoc/ri/paths.rbnu[# frozen_string_literal: true require 'rdoc/rdoc' ## # The directories where ri data lives. Paths can be enumerated via ::each, or # queried individually via ::system_dir, ::site_dir, ::home_dir and ::gem_dir. module RDoc::RI::Paths #:stopdoc: require 'rbconfig' version = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] BASE = if RbConfig::CONFIG.key? 'ridir' then File.join RbConfig::CONFIG['ridir'], version else File.join RbConfig::CONFIG['datadir'], 'ri', version end homedir = begin File.expand_path('~') rescue ArgumentError end homedir ||= ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH'] # for 1.8 compatibility HOMEDIR = if homedir then File.join homedir, ".rdoc" end #:startdoc: ## # Iterates over each selected path yielding the directory and type. # # Yielded types: # :system:: Where Ruby's ri data is stored. Yielded when +system+ is # true # :site:: Where ri for installed libraries are stored. Yielded when # +site+ is true. Normally no ri data is stored here. # :home:: ~/.rdoc. Yielded when +home+ is true. # :gem:: ri data for an installed gem. Yielded when +gems+ is true. # :extra:: ri data directory from the command line. Yielded for each # entry in +extra_dirs+ def self.each system = true, site = true, home = true, gems = :latest, *extra_dirs # :yields: directory, type return enum_for __method__, system, site, home, gems, *extra_dirs unless block_given? extra_dirs.each do |dir| yield dir, :extra end yield system_dir, :system if system yield site_dir, :site if site yield home_dir, :home if home and HOMEDIR gemdirs(gems).each do |dir| yield dir, :gem end if gems nil end ## # The ri directory for the gem with +gem_name+. def self.gem_dir name, version req = Gem::Requirement.new "= #{version}" spec = Gem::Specification.find_by_name name, req File.join spec.doc_dir, 'ri' end ## # The latest installed gems' ri directories. +filter+ can be :all or # :latest. # # A +filter+ :all includes all versions of gems and includes gems without # ri documentation. def self.gemdirs filter = :latest ri_paths = {} all = Gem::Specification.map do |spec| [File.join(spec.doc_dir, 'ri'), spec.name, spec.version] end if filter == :all then gemdirs = [] all.group_by do |_, name, _| name end.sort_by do |group, _| group end.map do |group, items| items.sort_by do |_, _, version| version end.reverse_each do |dir,| gemdirs << dir end end return gemdirs end all.each do |dir, name, ver| next unless File.exist? dir if ri_paths[name].nil? or ver > ri_paths[name].first then ri_paths[name] = [ver, name, dir] end end ri_paths.sort_by { |_, (_, name, _)| name }.map { |k, v| v.last } rescue LoadError [] end ## # The location of the rdoc data in the user's home directory. # # Like ::system, ri data in the user's home directory is rare and predates # libraries distributed via RubyGems. ri data is rarely generated into this # directory. def self.home_dir HOMEDIR end ## # Returns existing directories from the selected documentation directories # as an Array. # # See also ::each def self.path(system = true, site = true, home = true, gems = :latest, *extra_dirs) path = raw_path system, site, home, gems, *extra_dirs path.select { |directory| File.directory? directory } end ## # Returns selected documentation directories including nonexistent # directories. # # See also ::each def self.raw_path(system, site, home, gems, *extra_dirs) path = [] each(system, site, home, gems, *extra_dirs) do |dir, type| path << dir end path.compact end ## # The location of ri data installed into the site dir. # # Historically this was available for documentation installed by Ruby # libraries predating RubyGems. It is unlikely to contain any content for # modern Ruby installations. def self.site_dir File.join BASE, 'site' end ## # The location of the built-in ri data. # # This data is built automatically when `make` is run when Ruby is # installed. If you did not install Ruby by hand you may need to install # the documentation yourself. Please consult the documentation for your # package manager or Ruby installer for details. You can also use the # rdoc-data gem to install system ri data for common versions of Ruby. def self.system_dir File.join BASE, 'system' end end PKu]tUU!rdoc-6.2.1.1/lib/rdoc/ri/store.rbnu[# frozen_string_literal: true module RDoc::RI Store = RDoc::Store # :nodoc: end PKu]L!66 rdoc-6.2.1.1/lib/rdoc/ri/task.rbnu[# frozen_string_literal: true begin gem 'rdoc' rescue Gem::LoadError end unless defined?(RDoc) require 'rdoc/task' ## # RDoc::RI::Task creates ri data in ./.rdoc for your project. # # It contains the following tasks: # # [ri] # Build ri data # # [clobber_ri] # Delete ri data files. This target is automatically added to the main # clobber target. # # [reri] # Rebuild the ri data from scratch even if they are not out of date. # # Simple example: # # require 'rdoc/ri/task' # # RDoc::RI::Task.new do |ri| # ri.main = 'README.rdoc' # ri.rdoc_files.include 'README.rdoc', 'lib/**/*.rb' # end # # For further configuration details see RDoc::Task. class RDoc::RI::Task < RDoc::Task DEFAULT_NAMES = { # :nodoc: :clobber_rdoc => :clobber_ri, :rdoc => :ri, :rerdoc => :reri, } ## # Create an ri task with the given name. See RDoc::Task for documentation on # setting names. def initialize name = DEFAULT_NAMES # :yield: self super end def clobber_task_description # :nodoc: "Remove RI data files" end ## # Sets default task values def defaults super @rdoc_dir = '.rdoc' end def rdoc_task_description # :nodoc: 'Build RI data files' end def rerdoc_task_description # :nodoc: 'Rebuild RI data files' end end PKu]yy"rdoc-6.2.1.1/lib/rdoc/ri/driver.rbnu[# frozen_string_literal: true require 'abbrev' require 'optparse' begin require 'readline' rescue LoadError end begin require 'win32console' rescue LoadError end require 'rdoc' ## # For RubyGems backwards compatibility require 'rdoc/ri/formatter' ## # The RI driver implements the command-line ri tool. # # The driver supports: # * loading RI data from: # * Ruby's standard library # * RubyGems # * ~/.rdoc # * A user-supplied directory # * Paging output (uses RI_PAGER environment variable, PAGER environment # variable or the less, more and pager programs) # * Interactive mode with tab-completion # * Abbreviated names (ri Zl shows Zlib documentation) # * Colorized output # * Merging output from multiple RI data sources class RDoc::RI::Driver ## # Base Driver error class class Error < RDoc::RI::Error; end ## # Raised when a name isn't found in the ri data stores class NotFoundError < Error def initialize(klass, suggestions = nil) # :nodoc: @klass = klass @suggestions = suggestions end ## # Name that wasn't found def name @klass end def message # :nodoc: str = "Nothing known about #{@klass}" if @suggestions and !@suggestions.empty? str += "\nDid you mean? #{@suggestions.join("\n ")}" end str end end ## # Show all method documentation following a class or module attr_accessor :show_all ## # An RDoc::RI::Store for each entry in the RI path attr_accessor :stores ## # Controls the user of the pager vs $stdout attr_accessor :use_stdout ## # Default options for ri def self.default_options options = {} options[:interactive] = false options[:profile] = false options[:show_all] = false options[:use_stdout] = !$stdout.tty? options[:width] = 72 # By default all standard paths are used. options[:use_system] = true options[:use_site] = true options[:use_home] = true options[:use_gems] = true options[:extra_doc_dirs] = [] return options end ## # Dump +data_path+ using pp def self.dump data_path require 'pp' File.open data_path, 'rb' do |io| pp Marshal.load(io.read) end end ## # Parses +argv+ and returns a Hash of options def self.process_args argv options = default_options opts = OptionParser.new do |opt| opt.accept File do |file,| File.readable?(file) and not File.directory?(file) and file end opt.program_name = File.basename $0 opt.version = RDoc::VERSION opt.release = nil opt.summary_indent = ' ' * 4 opt.banner = <<-EOT Usage: #{opt.program_name} [options] [name ...] Where name can be: Class | Module | Module::Class Class::method | Class#method | Class.method | method gem_name: | gem_name:README | gem_name:History All class names may be abbreviated to their minimum unambiguous form. If a name is ambiguous, all valid options will be listed. A '.' matches either class or instance methods, while #method matches only instance and ::method matches only class methods. README and other files may be displayed by prefixing them with the gem name they're contained in. If the gem name is followed by a ':' all files in the gem will be shown. The file name extension may be omitted where it is unambiguous. For example: #{opt.program_name} Fil #{opt.program_name} File #{opt.program_name} File.new #{opt.program_name} zip #{opt.program_name} rdoc:README Note that shell quoting or escaping may be required for method names containing punctuation: #{opt.program_name} 'Array.[]' #{opt.program_name} compact\\! To see the default directories #{opt.program_name} will search, run: #{opt.program_name} --list-doc-dirs Specifying the --system, --site, --home, --gems, or --doc-dir options will limit ri to searching only the specified directories. ri options may be set in the RI environment variable. The ri pager can be set with the RI_PAGER environment variable or the PAGER environment variable. EOT opt.separator nil opt.separator "Options:" opt.separator nil opt.on("--[no-]interactive", "-i", "In interactive mode you can repeatedly", "look up methods with autocomplete.") do |interactive| options[:interactive] = interactive end opt.separator nil opt.on("--[no-]all", "-a", "Show all documentation for a class or", "module.") do |show_all| options[:show_all] = show_all end opt.separator nil opt.on("--[no-]list", "-l", "List classes ri knows about.") do |list| options[:list] = list end opt.separator nil opt.on("--[no-]pager", "Send output to a pager,", "rather than directly to stdout.") do |use_pager| options[:use_stdout] = !use_pager end opt.separator nil opt.on("-T", "Synonym for --no-pager.") do options[:use_stdout] = true end opt.separator nil opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger, "Set the width of the output.") do |width| options[:width] = width end opt.separator nil opt.on("--server[=PORT]", Integer, "Run RDoc server on the given port.", "The default port is 8214.") do |port| options[:server] = port || 8214 end opt.separator nil formatters = RDoc::Markup.constants.grep(/^To[A-Z][a-z]+$/).sort formatters = formatters.sort.map do |formatter| formatter.to_s.sub('To', '').downcase end formatters -= %w[html label test] # remove useless output formats opt.on("--format=NAME", "-f", "Use the selected formatter. The default", "formatter is bs for paged output and ansi", "otherwise. Valid formatters are:", "#{formatters.join(', ')}.", formatters) do |value| options[:formatter] = RDoc::Markup.const_get "To#{value.capitalize}" end opt.separator nil opt.on("--help", "-h", "Show help and exit.") do puts opts exit end opt.separator nil opt.on("--version", "-v", "Output version information and exit.") do puts "#{opts.program_name} #{opts.version}" exit end opt.separator nil opt.separator "Data source options:" opt.separator nil opt.on("--[no-]list-doc-dirs", "List the directories from which ri will", "source documentation on stdout and exit.") do |list_doc_dirs| options[:list_doc_dirs] = list_doc_dirs end opt.separator nil opt.on("--doc-dir=DIRNAME", "-d", Array, "List of directories from which to source", "documentation in addition to the standard", "directories. May be repeated.") do |value| value.each do |dir| unless File.directory? dir then raise OptionParser::InvalidArgument, "#{dir} is not a directory" end options[:extra_doc_dirs] << File.expand_path(dir) end end opt.separator nil opt.on("--no-standard-docs", "Do not include documentation from", "the Ruby standard library, site_lib,", "installed gems, or ~/.rdoc.", "Use with --doc-dir.") do options[:use_system] = false options[:use_site] = false options[:use_gems] = false options[:use_home] = false end opt.separator nil opt.on("--[no-]system", "Include documentation from Ruby's", "standard library. Defaults to true.") do |value| options[:use_system] = value end opt.separator nil opt.on("--[no-]site", "Include documentation from libraries", "installed in site_lib.", "Defaults to true.") do |value| options[:use_site] = value end opt.separator nil opt.on("--[no-]gems", "Include documentation from RubyGems.", "Defaults to true.") do |value| options[:use_gems] = value end opt.separator nil opt.on("--[no-]home", "Include documentation stored in ~/.rdoc.", "Defaults to true.") do |value| options[:use_home] = value end opt.separator nil opt.separator "Debug options:" opt.separator nil opt.on("--[no-]profile", "Run with the ruby profiler.") do |value| options[:profile] = value end opt.separator nil opt.on("--dump=CACHE", File, "Dump data from an ri cache or data file.") do |value| options[:dump_path] = value end end argv = ENV['RI'].to_s.split.concat argv opts.parse! argv options[:names] = argv options[:use_stdout] ||= !$stdout.tty? options[:use_stdout] ||= options[:interactive] options[:width] ||= 72 options rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e puts opts puts puts e exit 1 end ## # Runs the ri command line executable using +argv+ def self.run argv = ARGV options = process_args argv if options[:dump_path] then dump options[:dump_path] return end ri = new options ri.run end ## # Creates a new driver using +initial_options+ from ::process_args def initialize initial_options = {} @paging = false @classes = nil options = self.class.default_options.update(initial_options) @formatter_klass = options[:formatter] require 'profile' if options[:profile] @names = options[:names] @list = options[:list] @doc_dirs = [] @stores = [] RDoc::RI::Paths.each(options[:use_system], options[:use_site], options[:use_home], options[:use_gems], *options[:extra_doc_dirs]) do |path, type| @doc_dirs << path store = RDoc::RI::Store.new path, type store.load_cache @stores << store end @list_doc_dirs = options[:list_doc_dirs] @interactive = options[:interactive] @server = options[:server] @use_stdout = options[:use_stdout] @show_all = options[:show_all] @width = options[:width] # pager process for jruby @jruby_pager_process = nil end ## # Adds paths for undocumented classes +also_in+ to +out+ def add_also_in out, also_in return if also_in.empty? out << RDoc::Markup::Rule.new(1) out << RDoc::Markup::Paragraph.new("Also found in:") paths = RDoc::Markup::Verbatim.new also_in.each do |store| paths.parts.push store.friendly_path, "\n" end out << paths end ## # Adds a class header to +out+ for class +name+ which is described in # +classes+. def add_class out, name, classes heading = if classes.all? { |klass| klass.module? } then name else superclass = classes.map do |klass| klass.superclass unless klass.module? end.compact.shift || 'Object' superclass = superclass.full_name unless String === superclass "#{name} < #{superclass}" end out << RDoc::Markup::Heading.new(1, heading) out << RDoc::Markup::BlankLine.new end ## # Adds "(from ...)" to +out+ for +store+ def add_from out, store out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})") end ## # Adds +extends+ to +out+ def add_extends out, extends add_extension_modules out, 'Extended by', extends end ## # Adds a list of +extensions+ to this module of the given +type+ to +out+. # add_includes and add_extends call this, so you should use those directly. def add_extension_modules out, type, extensions return if extensions.empty? out << RDoc::Markup::Rule.new(1) out << RDoc::Markup::Heading.new(1, "#{type}:") extensions.each do |modules, store| if modules.length == 1 then add_extension_modules_single out, store, modules.first else add_extension_modules_multiple out, store, modules end end end ## # Renders multiple included +modules+ from +store+ to +out+. def add_extension_modules_multiple out, store, modules # :nodoc: out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})") wout, with = modules.partition { |incl| incl.comment.empty? } out << RDoc::Markup::BlankLine.new unless with.empty? with.each do |incl| out << RDoc::Markup::Paragraph.new(incl.name) out << RDoc::Markup::BlankLine.new out << incl.comment end unless wout.empty? then verb = RDoc::Markup::Verbatim.new wout.each do |incl| verb.push incl.name, "\n" end out << verb end end ## # Adds a single extension module +include+ from +store+ to +out+ def add_extension_modules_single out, store, include # :nodoc: name = include.name path = store.friendly_path out << RDoc::Markup::Paragraph.new("#{name} (from #{path})") if include.comment then out << RDoc::Markup::BlankLine.new out << include.comment end end ## # Adds +includes+ to +out+ def add_includes out, includes add_extension_modules out, 'Includes', includes end ## # Looks up the method +name+ and adds it to +out+ def add_method out, name filtered = lookup_method name method_out = method_document name, filtered out.concat method_out.parts end ## # Adds documentation for all methods in +klass+ to +out+ def add_method_documentation out, klass klass.method_list.each do |method| begin add_method out, method.full_name rescue NotFoundError next end end end ## # Adds a list of +methods+ to +out+ with a heading of +name+ def add_method_list out, methods, name return if methods.empty? out << RDoc::Markup::Heading.new(1, "#{name}:") out << RDoc::Markup::BlankLine.new if @use_stdout and !@interactive then out.concat methods.map { |method| RDoc::Markup::Verbatim.new method } else out << RDoc::Markup::IndentedParagraph.new(2, methods.join(', ')) end out << RDoc::Markup::BlankLine.new end ## # Returns ancestor classes of +klass+ def ancestors_of klass ancestors = [] unexamined = [klass] seen = [] loop do break if unexamined.empty? current = unexamined.shift seen << current stores = classes[current] break unless stores and not stores.empty? klasses = stores.map do |store| store.ancestors[current] end.flatten.uniq klasses = klasses - seen ancestors.concat klasses unexamined.concat klasses end ancestors.reverse end ## # For RubyGems backwards compatibility def class_cache # :nodoc: end ## # Builds a RDoc::Markup::Document from +found+, +klasess+ and +includes+ def class_document name, found, klasses, includes, extends also_in = [] out = RDoc::Markup::Document.new add_class out, name, klasses add_includes out, includes add_extends out, extends found.each do |store, klass| render_class out, store, klass, also_in end add_also_in out, also_in out end ## # Adds the class +comment+ to +out+. def class_document_comment out, comment # :nodoc: unless comment.empty? then out << RDoc::Markup::Rule.new(1) if comment.merged? then parts = comment.parts parts = parts.zip [RDoc::Markup::BlankLine.new] * parts.length parts.flatten! parts.pop out.concat parts else out << comment end end end ## # Adds the constants from +klass+ to the Document +out+. def class_document_constants out, klass # :nodoc: return if klass.constants.empty? out << RDoc::Markup::Heading.new(1, "Constants:") out << RDoc::Markup::BlankLine.new list = RDoc::Markup::List.new :NOTE constants = klass.constants.sort_by { |constant| constant.name } list.items.concat constants.map { |constant| parts = constant.comment.parts if constant.comment parts << RDoc::Markup::Paragraph.new('[not documented]') if parts.empty? RDoc::Markup::ListItem.new(constant.name, *parts) } out << list out << RDoc::Markup::BlankLine.new end ## # Hash mapping a known class or module to the stores it can be loaded from def classes return @classes if @classes @classes = {} @stores.each do |store| store.cache[:modules].each do |mod| # using default block causes searched-for modules to be added @classes[mod] ||= [] @classes[mod] << store end end @classes end ## # Returns the stores wherein +name+ is found along with the classes, # extends and includes that match it def classes_and_includes_and_extends_for name klasses = [] extends = [] includes = [] found = @stores.map do |store| begin klass = store.load_class name klasses << klass extends << [klass.extends, store] if klass.extends includes << [klass.includes, store] if klass.includes [store, klass] rescue RDoc::Store::MissingFileError end end.compact extends.reject! do |modules,| modules.empty? end includes.reject! do |modules,| modules.empty? end [found, klasses, includes, extends] end ## # Completes +name+ based on the caches. For Readline def complete name completions = [] klass, selector, method = parse_name name complete_klass name, klass, selector, method, completions complete_method name, klass, selector, completions completions.sort.uniq end def complete_klass name, klass, selector, method, completions # :nodoc: klasses = classes.keys # may need to include Foo when given Foo:: klass_name = method ? name : klass if name !~ /#|\./ then completions.replace klasses.grep(/^#{Regexp.escape klass_name}[^:]*$/) completions.concat klasses.grep(/^#{Regexp.escape name}[^:]*$/) if name =~ /::$/ completions << klass if classes.key? klass # to complete a method name elsif selector then completions << klass if classes.key? klass elsif classes.key? klass_name then completions << klass_name end end def complete_method name, klass, selector, completions # :nodoc: if completions.include? klass and name =~ /#|\.|::/ then methods = list_methods_matching name if not methods.empty? then # remove Foo if given Foo:: and a method was found completions.delete klass elsif selector then # replace Foo with Foo:: as given completions.delete klass completions << "#{klass}#{selector}" end completions.concat methods end end ## # Converts +document+ to text and writes it to the pager def display document page do |io| f = formatter(io) f.width = @width if @width and f.respond_to?(:width) text = document.accept f io.write text end end ## # Outputs formatted RI data for class +name+. Groups undocumented classes def display_class name return if name =~ /#|\./ found, klasses, includes, extends = classes_and_includes_and_extends_for name return if found.empty? out = class_document name, found, klasses, includes, extends display out end ## # Outputs formatted RI data for method +name+ def display_method name out = RDoc::Markup::Document.new add_method out, name display out end ## # Outputs formatted RI data for the class or method +name+. # # Returns true if +name+ was found, false if it was not an alternative could # be guessed, raises an error if +name+ couldn't be guessed. def display_name name if name =~ /\w:(\w|$)/ then display_page name return true end return true if display_class name display_method name if name =~ /::|#|\./ true rescue NotFoundError matches = list_methods_matching name if name =~ /::|#|\./ matches = classes.keys.grep(/^#{Regexp.escape name}/) if matches.empty? raise if matches.empty? page do |io| io.puts "#{name} not found, maybe you meant:" io.puts io.puts matches.sort.join("\n") end false end ## # Displays each name in +name+ def display_names names names.each do |name| name = expand_name name display_name name end end ## # Outputs formatted RI data for page +name+. def display_page name store_name, page_name = name.split ':', 2 store = @stores.find { |s| s.source == store_name } return display_page_list store if page_name.empty? pages = store.cache[:pages] unless pages.include? page_name then found_names = pages.select do |n| n =~ /#{Regexp.escape page_name}\.[^.]+$/ end if found_names.length.zero? then return display_page_list store, pages elsif found_names.length > 1 then return display_page_list store, found_names, page_name end page_name = found_names.first end page = store.load_page page_name display page.comment end ## # Outputs a formatted RI page list for the pages in +store+. def display_page_list store, pages = store.cache[:pages], search = nil out = RDoc::Markup::Document.new title = if search then "#{search} pages" else 'Pages' end out << RDoc::Markup::Heading.new(1, "#{title} in #{store.friendly_path}") out << RDoc::Markup::BlankLine.new list = RDoc::Markup::List.new(:BULLET) pages.each do |page| list << RDoc::Markup::Paragraph.new(page) end out << list display out end def check_did_you_mean # :nodoc: if defined? DidYouMean::SpellChecker true else begin require 'did_you_mean' if defined? DidYouMean::SpellChecker true else false end rescue LoadError false end end end ## # Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da" # will be expanded to Zlib::DataError. def expand_class klass class_names = classes.keys ary = class_names.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z")) if ary.length != 1 && ary.first != klass if check_did_you_mean suggestions = DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass) raise NotFoundError.new(klass, suggestions) else raise NotFoundError, klass end end ary.first end ## # Expands the class portion of +name+ into a fully-qualified class. See # #expand_class. def expand_name name klass, selector, method = parse_name name return [selector, method].join if klass.empty? case selector when ':' then [find_store(klass), selector, method] else [expand_class(klass), selector, method] end.join end ## # Filters the methods in +found+ trying to find a match for +name+. def filter_methods found, name regexp = name_regexp name filtered = found.find_all do |store, methods| methods.any? { |method| method.full_name =~ regexp } end return filtered unless filtered.empty? found end ## # Yields items matching +name+ including the store they were found in, the # class being searched for, the class they were found in (an ancestor) the # types of methods to look up (from #method_type), and the method name being # searched for def find_methods name klass, selector, method = parse_name name types = method_type selector klasses = nil ambiguous = klass.empty? if ambiguous then klasses = classes.keys else klasses = ancestors_of klass klasses.unshift klass end methods = [] klasses.each do |ancestor| ancestors = classes[ancestor] next unless ancestors klass = ancestor if ambiguous ancestors.each do |store| methods << [store, klass, ancestor, types, method] end end methods = methods.sort_by do |_, k, a, _, m| [k, a, m].compact end methods.each do |item| yield(*item) # :yields: store, klass, ancestor, types, method end self end ## # Finds the given +pager+ for jruby. Returns an IO if +pager+ was found. # # Returns false if +pager+ does not exist. # # Returns nil if the jruby JVM doesn't support ProcessBuilder redirection # (1.6 and older). def find_pager_jruby pager require 'java' require 'shellwords' return nil unless java.lang.ProcessBuilder.constants.include? :Redirect pager = Shellwords.split pager pb = java.lang.ProcessBuilder.new(*pager) pb = pb.redirect_output java.lang.ProcessBuilder::Redirect::INHERIT @jruby_pager_process = pb.start input = @jruby_pager_process.output_stream io = input.to_io io.sync = true io rescue java.io.IOException false end ## # Finds a store that matches +name+ which can be the name of a gem, "ruby", # "home" or "site". # # See also RDoc::Store#source def find_store name @stores.each do |store| source = store.source return source if source == name return source if store.type == :gem and source =~ /^#{Regexp.escape name}-\d/ end raise RDoc::RI::Driver::NotFoundError, name end ## # Creates a new RDoc::Markup::Formatter. If a formatter is given with -f, # use it. If we're outputting to a pager, use bs, otherwise ansi. def formatter(io) if @formatter_klass then @formatter_klass.new elsif paging? or !io.tty? then RDoc::Markup::ToBs.new else RDoc::Markup::ToAnsi.new end end ## # Runs ri interactively using Readline if it is available. def interactive puts "\nEnter the method name you want to look up." if defined? Readline then Readline.completion_proc = method :complete puts "You can use tab to autocomplete." end puts "Enter a blank line to exit.\n\n" loop do name = if defined? Readline then Readline.readline ">> " else print ">> " $stdin.gets end return if name.nil? or name.empty? begin display_name expand_name(name.strip) rescue NotFoundError => e puts e.message end end rescue Interrupt exit end ## # Is +file+ in ENV['PATH']? def in_path? file return true if file =~ %r%\A/% and File.exist? file ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path| File.exist? File.join(path, file) end end ## # Lists classes known to ri starting with +names+. If +names+ is empty all # known classes are shown. def list_known_classes names = [] classes = [] stores.each do |store| classes << store.module_names end classes = classes.flatten.uniq.sort unless names.empty? then filter = Regexp.union names.map { |name| /^#{name}/ } classes = classes.grep filter end page do |io| if paging? or io.tty? then if names.empty? then io.puts "Classes and Modules known to ri:" else io.puts "Classes and Modules starting with #{names.join ', '}:" end io.puts end io.puts classes.join("\n") end end ## # Returns an Array of methods matching +name+ def list_methods_matching name found = [] find_methods name do |store, klass, ancestor, types, method| if types == :instance or types == :both then methods = store.instance_methods[ancestor] if methods then matches = methods.grep(/^#{Regexp.escape method.to_s}/) matches = matches.map do |match| "#{klass}##{match}" end found.concat matches end end if types == :class or types == :both then methods = store.class_methods[ancestor] next unless methods matches = methods.grep(/^#{Regexp.escape method.to_s}/) matches = matches.map do |match| "#{klass}::#{match}" end found.concat matches end end found.uniq end ## # Loads RI data for method +name+ on +klass+ from +store+. +type+ and # +cache+ indicate if it is a class or instance method. def load_method store, cache, klass, type, name methods = store.send(cache)[klass] return unless methods method = methods.find do |method_name| method_name == name end return unless method store.load_method klass, "#{type}#{method}" rescue RDoc::Store::MissingFileError => e comment = RDoc::Comment.new("missing documentation at #{e.file}").parse method = RDoc::AnyMethod.new nil, name method.comment = comment method end ## # Returns an Array of RI data for methods matching +name+ def load_methods_matching name found = [] find_methods name do |store, klass, ancestor, types, method| methods = [] methods << load_method(store, :class_methods, ancestor, '::', method) if [:class, :both].include? types methods << load_method(store, :instance_methods, ancestor, '#', method) if [:instance, :both].include? types found << [store, methods.compact] end found.reject do |path, methods| methods.empty? end end ## # Returns a filtered list of methods matching +name+ def lookup_method name found = load_methods_matching name if found.empty? if check_did_you_mean methods = [] _, _, method_name = parse_name name find_methods name do |store, klass, ancestor, types, method| methods.push(*store.class_methods[klass]) if [:class, :both].include? types methods.push(*store.instance_methods[klass]) if [:instance, :both].include? types end methods = methods.uniq suggestions = DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name) raise NotFoundError.new(name, suggestions) else raise NotFoundError, name end end filter_methods found, name end ## # Builds a RDoc::Markup::Document from +found+, +klasses+ and +includes+ def method_document name, filtered out = RDoc::Markup::Document.new out << RDoc::Markup::Heading.new(1, name) out << RDoc::Markup::BlankLine.new filtered.each do |store, methods| methods.each do |method| render_method out, store, method, name end end out end ## # Returns the type of method (:both, :instance, :class) for +selector+ def method_type selector case selector when '.', nil then :both when '#' then :instance else :class end end ## # Returns a regular expression for +name+ that will match an # RDoc::AnyMethod's name. def name_regexp name klass, type, name = parse_name name case type when '#', '::' then /^#{klass}#{type}#{Regexp.escape name}$/ else /^#{klass}(#|::)#{Regexp.escape name}$/ end end ## # Paginates output through a pager program. def page if pager = setup_pager then begin yield pager ensure pager.close @jruby_pager_process.wait_for if @jruby_pager_process end else yield $stdout end rescue Errno::EPIPE ensure @paging = false end ## # Are we using a pager? def paging? @paging end ## # Extracts the class, selector and method name parts from +name+ like # Foo::Bar#baz. # # NOTE: Given Foo::Bar, Bar is considered a class even though it may be a # method def parse_name name parts = name.split(/(::?|#|\.)/) if parts.length == 1 then if parts.first =~ /^[a-z]|^([%&*+\/<>^`|~-]|\+@|-@|<<|<=>?|===?|=>|=~|>>|\[\]=?|~@)$/ then type = '.' meth = parts.pop else type = nil meth = nil end elsif parts.length == 2 or parts.last =~ /::|#|\./ then type = parts.pop meth = nil elsif parts[1] == ':' then klass = parts.shift type = parts.shift meth = parts.join elsif parts[-2] != '::' or parts.last !~ /^[A-Z]/ then meth = parts.pop type = parts.pop end klass ||= parts.join [klass, type, meth] end ## # Renders the +klass+ from +store+ to +out+. If the klass has no # documentable items the class is added to +also_in+ instead. def render_class out, store, klass, also_in # :nodoc: comment = klass.comment # TODO the store's cache should always return an empty Array class_methods = store.class_methods[klass.full_name] || [] instance_methods = store.instance_methods[klass.full_name] || [] attributes = store.attributes[klass.full_name] || [] if comment.empty? and instance_methods.empty? and class_methods.empty? then also_in << store return end add_from out, store class_document_comment out, comment if class_methods or instance_methods or not klass.constants.empty? then out << RDoc::Markup::Rule.new(1) end class_document_constants out, klass add_method_list out, class_methods, 'Class methods' add_method_list out, instance_methods, 'Instance methods' add_method_list out, attributes, 'Attributes' add_method_documentation out, klass if @show_all end def render_method out, store, method, name # :nodoc: out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})") unless name =~ /^#{Regexp.escape method.parent_name}/ then out << RDoc::Markup::Heading.new(3, "Implementation from #{method.parent_name}") end out << RDoc::Markup::Rule.new(1) render_method_arguments out, method.arglists render_method_superclass out, method if method.is_alias_for al = method.is_alias_for alias_for = store.load_method al.parent_name, "#{al.name_prefix}#{al.name}" render_method_comment out, method, alias_for else render_method_comment out, method end end def render_method_arguments out, arglists # :nodoc: return unless arglists arglists = arglists.chomp.split "\n" arglists = arglists.map { |line| line + "\n" } out << RDoc::Markup::Verbatim.new(*arglists) out << RDoc::Markup::Rule.new(1) end def render_method_comment out, method, alias_for = nil# :nodoc: if alias_for unless method.comment.nil? or method.comment.empty? out << RDoc::Markup::BlankLine.new out << method.comment end out << RDoc::Markup::BlankLine.new out << RDoc::Markup::Paragraph.new("(This method is an alias for #{alias_for.full_name}.)") out << RDoc::Markup::BlankLine.new out << alias_for.comment out << RDoc::Markup::BlankLine.new else out << RDoc::Markup::BlankLine.new out << method.comment out << RDoc::Markup::BlankLine.new end end def render_method_superclass out, method # :nodoc: return unless method.respond_to?(:superclass_method) and method.superclass_method out << RDoc::Markup::BlankLine.new out << RDoc::Markup::Heading.new(4, "(Uses superclass method #{method.superclass_method})") out << RDoc::Markup::Rule.new(1) end ## # Looks up and displays ri data according to the options given. def run if @list_doc_dirs then puts @doc_dirs elsif @list then list_known_classes @names elsif @server then start_server elsif @interactive or @names.empty? then interactive else display_names @names end rescue NotFoundError => e abort e.message end ## # Sets up a pager program to pass output through. Tries the RI_PAGER and # PAGER environment variables followed by pager, less then more. def setup_pager return if @use_stdout jruby = RUBY_ENGINE == 'jruby' pagers = [ENV['RI_PAGER'], ENV['PAGER'], 'pager', 'less', 'more'] pagers.compact.uniq.each do |pager| next unless pager pager_cmd = pager.split.first next unless in_path? pager_cmd if jruby then case io = find_pager_jruby(pager) when nil then break when false then next else io end else io = IO.popen(pager, 'w') rescue next end next if $? and $?.pid == io.pid and $?.exited? # pager didn't work @paging = true return io end @use_stdout = true nil end ## # Starts a WEBrick server for ri. def start_server require 'webrick' server = WEBrick::HTTPServer.new :Port => @server extra_doc_dirs = @stores.map {|s| s.type == :extra ? s.path : nil}.compact server.mount '/', RDoc::Servlet, nil, extra_doc_dirs trap 'INT' do server.shutdown end trap 'TERM' do server.shutdown end server.start end end PKu]y!rdoc-6.2.1.1/lib/rdoc/encoding.rbnu[# coding: US-ASCII # frozen_string_literal: true ## # This class is a wrapper around File IO and Encoding that helps RDoc load # files and convert them to the correct encoding. module RDoc::Encoding HEADER_REGEXP = /^ (?: \A\#!.*\n | ^\#\s+frozen[-_]string[-_]literal[=:].+\n | ^\#[^\n]+\b(?:en)?coding[=:]\s*(?[^\s;]+).*\n | <\?xml[^?]*encoding=(?["'])(?.*?)\k.*\n )+ /xi # :nodoc: ## # Reads the contents of +filename+ and handles any encoding directives in # the file. # # The content will be converted to the +encoding+. If the file cannot be # converted a warning will be printed and nil will be returned. # # If +force_transcode+ is true the document will be transcoded and any # unknown character in the target encoding will be replaced with '?' def self.read_file filename, encoding, force_transcode = false content = File.open filename, "rb" do |f| f.read end content.gsub!("\r\n", "\n") if RUBY_PLATFORM =~ /mswin|mingw/ utf8 = content.sub!(/\A\xef\xbb\xbf/, '') enc = RDoc::Encoding.detect_encoding content content = RDoc::Encoding.change_encoding content, enc if enc begin encoding ||= Encoding.default_external orig_encoding = content.encoding if not orig_encoding.ascii_compatible? then content = content.encode encoding elsif utf8 then content = RDoc::Encoding.change_encoding content, Encoding::UTF_8 content = content.encode encoding else # assume the content is in our output encoding content = RDoc::Encoding.change_encoding content, encoding end unless content.valid_encoding? then # revert and try to transcode content = RDoc::Encoding.change_encoding content, orig_encoding content = content.encode encoding end unless content.valid_encoding? then warn "unable to convert #{filename} to #{encoding}, skipping" content = nil end rescue Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError => e if force_transcode then content = RDoc::Encoding.change_encoding content, orig_encoding content = content.encode(encoding, :invalid => :replace, :undef => :replace, :replace => '?') return content else warn "unable to convert #{e.message} for #{filename}, skipping" return nil end end content rescue ArgumentError => e raise unless e.message =~ /unknown encoding name - (.*)/ warn "unknown encoding name \"#{$1}\" for #{filename}, skipping" nil rescue Errno::EISDIR, Errno::ENOENT nil end def self.remove_frozen_string_literal string string =~ /\A(?:#!.*\n)?(.*\n)/ first_line = $1 if first_line =~ /\A# +frozen[-_]string[-_]literal[=:].+$/i string = string.sub first_line, '' end string end ## # Detects the encoding of +string+ based on the magic comment def self.detect_encoding string result = HEADER_REGEXP.match string name = result && result[:name] name ? Encoding.find(name) : nil end ## # Removes magic comments and shebang def self.remove_magic_comment string string.sub HEADER_REGEXP do |s| s.gsub(/[^\n]/, '') end end ## # Changes encoding based on +encoding+ without converting and returns new # string def self.change_encoding text, encoding if text.kind_of? RDoc::Comment text.encode! encoding else # TODO: Remove this condition after Ruby 2.2 EOL if RUBY_VERSION < '2.3.0' text.force_encoding encoding else String.new text, encoding: encoding end end end end PKu]rdoc-6.2.1.1/lib/rdoc/extend.rbnu[# frozen_string_literal: true ## # A Module extension to a class with \#extend # # RDoc::Extend.new 'Enumerable', 'comment ...' class RDoc::Extend < RDoc::Mixin end PKu] =MM rdoc-6.2.1.1/lib/rdoc/version.rbnu[module RDoc ## # RDoc version you are using VERSION = '6.2.1.1' end PKu]g*%rdoc-6.2.1.1/lib/rdoc/code_objects.rbnu[# frozen_string_literal: true # This file was used to load all the RDoc::CodeObject subclasses at once. Now # autoload handles this. require 'rdoc' PKu]bb]]!rdoc-6.2.1.1/lib/rdoc/constant.rbnu[# frozen_string_literal: true ## # A constant class RDoc::Constant < RDoc::CodeObject MARSHAL_VERSION = 0 # :nodoc: ## # Sets the module or class this is constant is an alias for. attr_writer :is_alias_for ## # The constant's name attr_accessor :name ## # The constant's value attr_accessor :value ## # The constant's visibility attr_accessor :visibility ## # Creates a new constant with +name+, +value+ and +comment+ def initialize(name, value, comment) super() @name = name @value = value @is_alias_for = nil @visibility = :public self.comment = comment end ## # Constants are ordered by name def <=> other return unless self.class === other [parent_name, name] <=> [other.parent_name, other.name] end ## # Constants are equal when their #parent and #name is the same def == other self.class == other.class and @parent == other.parent and @name == other.name end ## # A constant is documented if it has a comment, or is an alias # for a documented class or module. def documented? return true if super return false unless @is_alias_for case @is_alias_for when String then found = @store.find_class_or_module @is_alias_for return false unless found @is_alias_for = found end @is_alias_for.documented? end ## # Full constant name including namespace def full_name @full_name ||= "#{parent_name}::#{@name}" end ## # The module or class this constant is an alias for def is_alias_for case @is_alias_for when String then found = @store.find_class_or_module @is_alias_for @is_alias_for = found if found @is_alias_for else @is_alias_for end end def inspect # :nodoc: "#<%s:0x%x %s::%s>" % [ self.class, object_id, parent_name, @name, ] end ## # Dumps this Constant for use by ri. See also #marshal_load def marshal_dump alias_name = case found = is_alias_for when RDoc::CodeObject then found.full_name else found end [ MARSHAL_VERSION, @name, full_name, @visibility, alias_name, parse(@comment), @file.relative_name, parent.name, parent.class, section.title, ] end ## # Loads this Constant from +array+. For a loaded Constant the following # methods will return cached values: # # * #full_name # * #parent_name def marshal_load array initialize array[1], nil, array[5] @full_name = array[2] @visibility = array[3] || :public @is_alias_for = array[4] # 5 handled above # 6 handled below @parent_name = array[7] @parent_class = array[8] @section_title = array[9] @file = RDoc::TopLevel.new array[6] end ## # Path to this constant for use with HTML generator output. def path "#{@parent.path}##{@name}" end def pretty_print q # :nodoc: q.group 2, "[#{self.class.name} #{full_name}", "]" do unless comment.empty? then q.breakable q.text "comment:" q.breakable q.pp @comment end end end ## # Sets the store for this class or module and its contained code objects. def store= store super @file = @store.add_file @file.full_name if @file end def to_s # :nodoc: parent_name = parent ? parent.full_name : '(unknown)' if is_alias_for "constant #{parent_name}::#@name -> #{is_alias_for}" else "constant #{parent_name}::#@name" end end end PKu]I#$#$$rdoc-6.2.1.1/lib/rdoc/method_attr.rbnu[# frozen_string_literal: true ## # Abstract class representing either a method or an attribute. class RDoc::MethodAttr < RDoc::CodeObject include Comparable ## # Name of this method/attribute. attr_accessor :name ## # public, protected, private attr_accessor :visibility ## # Is this a singleton method/attribute? attr_accessor :singleton ## # Source file token stream attr_reader :text ## # Array of other names for this method/attribute attr_reader :aliases ## # The method/attribute we're aliasing attr_accessor :is_alias_for #-- # The attributes below are for AnyMethod only. # They are left here for the time being to # allow ri to operate. # TODO modify ri to avoid calling these on attributes. #++ ## # Parameters yielded by the called block attr_reader :block_params ## # Parameters for this method attr_accessor :params ## # Different ways to call this method attr_accessor :call_seq ## # The call_seq or the param_seq with method name, if there is no call_seq. attr_reader :arglists ## # Pretty parameter list for this method attr_reader :param_seq ## # Creates a new MethodAttr from token stream +text+ and method or attribute # name +name+. # # Usually this is called by super from a subclass. def initialize text, name super() @text = text @name = name @aliases = [] @is_alias_for = nil @parent_name = nil @singleton = nil @visibility = :public @see = false @arglists = nil @block_params = nil @call_seq = nil @param_seq = nil @params = nil end ## # Resets cached data for the object so it can be rebuilt by accessor methods def initialize_copy other # :nodoc: @full_name = nil end def initialize_visibility # :nodoc: super @see = nil end ## # Order by #singleton then #name def <=>(other) return unless other.respond_to?(:singleton) && other.respond_to?(:name) [ @singleton ? 0 : 1, name] <=> [other.singleton ? 0 : 1, other.name] end def == other # :nodoc: equal?(other) or self.class == other.class and full_name == other.full_name end ## # A method/attribute is documented if any of the following is true: # - it was marked with :nodoc:; # - it has a comment; # - it is an alias for a documented method; # - it has a +#see+ method that is documented. def documented? super or (is_alias_for and is_alias_for.documented?) or (see and see.documented?) end ## # A method/attribute to look at, # in particular if this method/attribute has no documentation. # # It can be a method/attribute of the superclass or of an included module, # including the Kernel module, which is always appended to the included # modules. # # Returns +nil+ if there is no such method/attribute. # The +#is_alias_for+ method/attribute, if any, is not included. # # Templates may generate a "see also ..." if this method/attribute # has documentation, and "see ..." if it does not. def see @see = find_see if @see == false @see end ## # Sets the store for this class or module and its contained code objects. def store= store super @file = @store.add_file @file.full_name if @file end def find_see # :nodoc: return nil if singleton || is_alias_for # look for the method other = find_method_or_attribute name return other if other # if it is a setter, look for a getter return nil unless name =~ /[a-z_]=$/i # avoid == or === return find_method_or_attribute name[0..-2] end def find_method_or_attribute name # :nodoc: return nil unless parent.respond_to? :ancestors searched = parent.ancestors kernel = @store.modules_hash['Kernel'] searched << kernel if kernel && parent != kernel && !searched.include?(kernel) searched.each do |ancestor| next if String === ancestor next if parent == ancestor other = ancestor.find_method_named('#' + name) || ancestor.find_attribute_named(name) return other if other end nil end ## # Abstract method. Contexts in their building phase call this # to register a new alias for this known method/attribute. # # - creates a new AnyMethod/Attribute named an_alias.new_name; # - adds +self+ as an alias for the new method or attribute # - adds the method or attribute to #aliases # - adds the method or attribute to +context+. def add_alias(an_alias, context) raise NotImplementedError end ## # HTML fragment reference for this method def aref type = singleton ? 'c' : 'i' # % characters are not allowed in html names => dash instead "#{aref_prefix}-#{type}-#{html_name}" end ## # Prefix for +aref+, defined by subclasses. def aref_prefix raise NotImplementedError end ## # Attempts to sanitize the content passed by the Ruby parser: # remove outer parentheses, etc. def block_params=(value) # 'yield.to_s' or 'assert yield, msg' return @block_params = '' if value =~ /^[\.,]/ # remove trailing 'if/unless ...' return @block_params = '' if value =~ /^(if|unless)\s/ value = $1.strip if value =~ /^(.+)\s(if|unless)\s/ # outer parentheses value = $1 if value =~ /^\s*\((.*)\)\s*$/ value = value.strip # proc/lambda return @block_params = $1 if value =~ /^(proc|lambda)(\s*\{|\sdo)/ # surrounding +...+ or [...] value = $1.strip if value =~ /^\+(.*)\+$/ value = $1.strip if value =~ /^\[(.*)\]$/ return @block_params = '' if value.empty? # global variable return @block_params = 'str' if value =~ /^\$[&0-9]$/ # wipe out array/hash indices value.gsub!(/(\w)\[[^\[]+\]/, '\1') # remove @ from class/instance variables value.gsub!(/@@?([a-z0-9_]+)/, '\1') # method calls => method name value.gsub!(/([A-Z:a-z0-9_]+)\.([a-z0-9_]+)(\s*\(\s*[a-z0-9_.,\s]*\s*\)\s*)?/) do case $2 when 'to_s' then $1 when 'const_get' then 'const' when 'new' then $1.split('::').last. # ClassName => class_name gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). gsub(/([a-z\d])([A-Z])/,'\1_\2'). downcase else $2 end end # class prefixes value.gsub!(/[A-Za-z0-9_:]+::/, '') # simple expressions value = $1 if value =~ /^([a-z0-9_]+)\s*[-*+\/]/ @block_params = value.strip end ## # HTML id-friendly method/attribute name def html_name require 'cgi' CGI.escape(@name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '') end ## # Full method/attribute name including namespace def full_name @full_name ||= "#{parent_name}#{pretty_name}" end def inspect # :nodoc: alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil visibility = self.visibility visibility = "forced #{visibility}" if force_documentation "#<%s:0x%x %s (%s)%s>" % [ self.class, object_id, full_name, visibility, alias_for, ] end ## # '::' for a class method/attribute, '#' for an instance method. def name_prefix @singleton ? '::' : '#' end ## # Name for output to HTML. For class methods the full name with a "." is # used like +SomeClass.method_name+. For instance methods the class name is # used if +context+ does not match the parent. # # This is to help prevent people from using :: to call class methods. def output_name context return "#{name_prefix}#{@name}" if context == parent "#{parent_name}#{@singleton ? '.' : '#'}#{@name}" end ## # Method/attribute name with class/instance indicator def pretty_name "#{name_prefix}#{@name}" end ## # Type of method/attribute (class or instance) def type singleton ? 'class' : 'instance' end ## # Path to this method for use with HTML generator output. def path "#{@parent.path}##{aref}" end ## # Name of our parent with special handling for un-marshaled methods def parent_name @parent_name || super end def pretty_print q # :nodoc: alias_for = if @is_alias_for.respond_to? :name then "alias for #{@is_alias_for.name}" elsif Array === @is_alias_for then "alias for #{@is_alias_for.last}" end q.group 2, "[#{self.class.name} #{full_name} #{visibility}", "]" do if alias_for then q.breakable q.text alias_for end if text then q.breakable q.text "text:" q.breakable q.pp @text end unless comment.empty? then q.breakable q.text "comment:" q.breakable q.pp @comment end end end ## # Used by RDoc::Generator::JsonIndex to create a record for the search # engine. def search_record [ @name, full_name, @name, @parent.full_name, path, params, snippet(@comment), ] end def to_s # :nodoc: if @is_alias_for "#{self.class.name}: #{full_name} -> #{is_alias_for}" else "#{self.class.name}: #{full_name}" end end end PKu]OG!!*rdoc-6.2.1.1/lib/rdoc/markdown/entities.rbnu[# frozen_string_literal: true ## # HTML entity name map for RDoc::Markdown RDoc::Markdown::HTML_ENTITIES = { "AElig" => [0x000C6], "AMP" => [0x00026], "Aacute" => [0x000C1], "Abreve" => [0x00102], "Acirc" => [0x000C2], "Acy" => [0x00410], "Afr" => [0x1D504], "Agrave" => [0x000C0], "Alpha" => [0x00391], "Amacr" => [0x00100], "And" => [0x02A53], "Aogon" => [0x00104], "Aopf" => [0x1D538], "ApplyFunction" => [0x02061], "Aring" => [0x000C5], "Ascr" => [0x1D49C], "Assign" => [0x02254], "Atilde" => [0x000C3], "Auml" => [0x000C4], "Backslash" => [0x02216], "Barv" => [0x02AE7], "Barwed" => [0x02306], "Bcy" => [0x00411], "Because" => [0x02235], "Bernoullis" => [0x0212C], "Beta" => [0x00392], "Bfr" => [0x1D505], "Bopf" => [0x1D539], "Breve" => [0x002D8], "Bscr" => [0x0212C], "Bumpeq" => [0x0224E], "CHcy" => [0x00427], "COPY" => [0x000A9], "Cacute" => [0x00106], "Cap" => [0x022D2], "CapitalDifferentialD" => [0x02145], "Cayleys" => [0x0212D], "Ccaron" => [0x0010C], "Ccedil" => [0x000C7], "Ccirc" => [0x00108], "Cconint" => [0x02230], "Cdot" => [0x0010A], "Cedilla" => [0x000B8], "CenterDot" => [0x000B7], "Cfr" => [0x0212D], "Chi" => [0x003A7], "CircleDot" => [0x02299], "CircleMinus" => [0x02296], "CirclePlus" => [0x02295], "CircleTimes" => [0x02297], "ClockwiseContourIntegral" => [0x02232], "CloseCurlyDoubleQuote" => [0x0201D], "CloseCurlyQuote" => [0x02019], "Colon" => [0x02237], "Colone" => [0x02A74], "Congruent" => [0x02261], "Conint" => [0x0222F], "ContourIntegral" => [0x0222E], "Copf" => [0x02102], "Coproduct" => [0x02210], "CounterClockwiseContourIntegral" => [0x02233], "Cross" => [0x02A2F], "Cscr" => [0x1D49E], "Cup" => [0x022D3], "CupCap" => [0x0224D], "DD" => [0x02145], "DDotrahd" => [0x02911], "DJcy" => [0x00402], "DScy" => [0x00405], "DZcy" => [0x0040F], "Dagger" => [0x02021], "Darr" => [0x021A1], "Dashv" => [0x02AE4], "Dcaron" => [0x0010E], "Dcy" => [0x00414], "Del" => [0x02207], "Delta" => [0x00394], "Dfr" => [0x1D507], "DiacriticalAcute" => [0x000B4], "DiacriticalDot" => [0x002D9], "DiacriticalDoubleAcute" => [0x002DD], "DiacriticalGrave" => [0x00060], "DiacriticalTilde" => [0x002DC], "Diamond" => [0x022C4], "DifferentialD" => [0x02146], "Dopf" => [0x1D53B], "Dot" => [0x000A8], "DotDot" => [0x020DC], "DotEqual" => [0x02250], "DoubleContourIntegral" => [0x0222F], "DoubleDot" => [0x000A8], "DoubleDownArrow" => [0x021D3], "DoubleLeftArrow" => [0x021D0], "DoubleLeftRightArrow" => [0x021D4], "DoubleLeftTee" => [0x02AE4], "DoubleLongLeftArrow" => [0x027F8], "DoubleLongLeftRightArrow" => [0x027FA], "DoubleLongRightArrow" => [0x027F9], "DoubleRightArrow" => [0x021D2], "DoubleRightTee" => [0x022A8], "DoubleUpArrow" => [0x021D1], "DoubleUpDownArrow" => [0x021D5], "DoubleVerticalBar" => [0x02225], "DownArrow" => [0x02193], "DownArrowBar" => [0x02913], "DownArrowUpArrow" => [0x021F5], "DownBreve" => [0x00311], "DownLeftRightVector" => [0x02950], "DownLeftTeeVector" => [0x0295E], "DownLeftVector" => [0x021BD], "DownLeftVectorBar" => [0x02956], "DownRightTeeVector" => [0x0295F], "DownRightVector" => [0x021C1], "DownRightVectorBar" => [0x02957], "DownTee" => [0x022A4], "DownTeeArrow" => [0x021A7], "Downarrow" => [0x021D3], "Dscr" => [0x1D49F], "Dstrok" => [0x00110], "ENG" => [0x0014A], "ETH" => [0x000D0], "Eacute" => [0x000C9], "Ecaron" => [0x0011A], "Ecirc" => [0x000CA], "Ecy" => [0x0042D], "Edot" => [0x00116], "Efr" => [0x1D508], "Egrave" => [0x000C8], "Element" => [0x02208], "Emacr" => [0x00112], "EmptySmallSquare" => [0x025FB], "EmptyVerySmallSquare" => [0x025AB], "Eogon" => [0x00118], "Eopf" => [0x1D53C], "Epsilon" => [0x00395], "Equal" => [0x02A75], "EqualTilde" => [0x02242], "Equilibrium" => [0x021CC], "Escr" => [0x02130], "Esim" => [0x02A73], "Eta" => [0x00397], "Euml" => [0x000CB], "Exists" => [0x02203], "ExponentialE" => [0x02147], "Fcy" => [0x00424], "Ffr" => [0x1D509], "FilledSmallSquare" => [0x025FC], "FilledVerySmallSquare" => [0x025AA], "Fopf" => [0x1D53D], "ForAll" => [0x02200], "Fouriertrf" => [0x02131], "Fscr" => [0x02131], "GJcy" => [0x00403], "GT" => [0x0003E], "Gamma" => [0x00393], "Gammad" => [0x003DC], "Gbreve" => [0x0011E], "Gcedil" => [0x00122], "Gcirc" => [0x0011C], "Gcy" => [0x00413], "Gdot" => [0x00120], "Gfr" => [0x1D50A], "Gg" => [0x022D9], "Gopf" => [0x1D53E], "GreaterEqual" => [0x02265], "GreaterEqualLess" => [0x022DB], "GreaterFullEqual" => [0x02267], "GreaterGreater" => [0x02AA2], "GreaterLess" => [0x02277], "GreaterSlantEqual" => [0x02A7E], "GreaterTilde" => [0x02273], "Gscr" => [0x1D4A2], "Gt" => [0x0226B], "HARDcy" => [0x0042A], "Hacek" => [0x002C7], "Hat" => [0x0005E], "Hcirc" => [0x00124], "Hfr" => [0x0210C], "HilbertSpace" => [0x0210B], "Hopf" => [0x0210D], "HorizontalLine" => [0x02500], "Hscr" => [0x0210B], "Hstrok" => [0x00126], "HumpDownHump" => [0x0224E], "HumpEqual" => [0x0224F], "IEcy" => [0x00415], "IJlig" => [0x00132], "IOcy" => [0x00401], "Iacute" => [0x000CD], "Icirc" => [0x000CE], "Icy" => [0x00418], "Idot" => [0x00130], "Ifr" => [0x02111], "Igrave" => [0x000CC], "Im" => [0x02111], "Imacr" => [0x0012A], "ImaginaryI" => [0x02148], "Implies" => [0x021D2], "Int" => [0x0222C], "Integral" => [0x0222B], "Intersection" => [0x022C2], "InvisibleComma" => [0x02063], "InvisibleTimes" => [0x02062], "Iogon" => [0x0012E], "Iopf" => [0x1D540], "Iota" => [0x00399], "Iscr" => [0x02110], "Itilde" => [0x00128], "Iukcy" => [0x00406], "Iuml" => [0x000CF], "Jcirc" => [0x00134], "Jcy" => [0x00419], "Jfr" => [0x1D50D], "Jopf" => [0x1D541], "Jscr" => [0x1D4A5], "Jsercy" => [0x00408], "Jukcy" => [0x00404], "KHcy" => [0x00425], "KJcy" => [0x0040C], "Kappa" => [0x0039A], "Kcedil" => [0x00136], "Kcy" => [0x0041A], "Kfr" => [0x1D50E], "Kopf" => [0x1D542], "Kscr" => [0x1D4A6], "LJcy" => [0x00409], "LT" => [0x0003C], "Lacute" => [0x00139], "Lambda" => [0x0039B], "Lang" => [0x027EA], "Laplacetrf" => [0x02112], "Larr" => [0x0219E], "Lcaron" => [0x0013D], "Lcedil" => [0x0013B], "Lcy" => [0x0041B], "LeftAngleBracket" => [0x027E8], "LeftArrow" => [0x02190], "LeftArrowBar" => [0x021E4], "LeftArrowRightArrow" => [0x021C6], "LeftCeiling" => [0x02308], "LeftDoubleBracket" => [0x027E6], "LeftDownTeeVector" => [0x02961], "LeftDownVector" => [0x021C3], "LeftDownVectorBar" => [0x02959], "LeftFloor" => [0x0230A], "LeftRightArrow" => [0x02194], "LeftRightVector" => [0x0294E], "LeftTee" => [0x022A3], "LeftTeeArrow" => [0x021A4], "LeftTeeVector" => [0x0295A], "LeftTriangle" => [0x022B2], "LeftTriangleBar" => [0x029CF], "LeftTriangleEqual" => [0x022B4], "LeftUpDownVector" => [0x02951], "LeftUpTeeVector" => [0x02960], "LeftUpVector" => [0x021BF], "LeftUpVectorBar" => [0x02958], "LeftVector" => [0x021BC], "LeftVectorBar" => [0x02952], "Leftarrow" => [0x021D0], "Leftrightarrow" => [0x021D4], "LessEqualGreater" => [0x022DA], "LessFullEqual" => [0x02266], "LessGreater" => [0x02276], "LessLess" => [0x02AA1], "LessSlantEqual" => [0x02A7D], "LessTilde" => [0x02272], "Lfr" => [0x1D50F], "Ll" => [0x022D8], "Lleftarrow" => [0x021DA], "Lmidot" => [0x0013F], "LongLeftArrow" => [0x027F5], "LongLeftRightArrow" => [0x027F7], "LongRightArrow" => [0x027F6], "Longleftarrow" => [0x027F8], "Longleftrightarrow" => [0x027FA], "Longrightarrow" => [0x027F9], "Lopf" => [0x1D543], "LowerLeftArrow" => [0x02199], "LowerRightArrow" => [0x02198], "Lscr" => [0x02112], "Lsh" => [0x021B0], "Lstrok" => [0x00141], "Lt" => [0x0226A], "Map" => [0x02905], "Mcy" => [0x0041C], "MediumSpace" => [0x0205F], "Mellintrf" => [0x02133], "Mfr" => [0x1D510], "MinusPlus" => [0x02213], "Mopf" => [0x1D544], "Mscr" => [0x02133], "Mu" => [0x0039C], "NJcy" => [0x0040A], "Nacute" => [0x00143], "Ncaron" => [0x00147], "Ncedil" => [0x00145], "Ncy" => [0x0041D], "NegativeMediumSpace" => [0x0200B], "NegativeThickSpace" => [0x0200B], "NegativeThinSpace" => [0x0200B], "NegativeVeryThinSpace" => [0x0200B], "NestedGreaterGreater" => [0x0226B], "NestedLessLess" => [0x0226A], "NewLine" => [0x0000A], "Nfr" => [0x1D511], "NoBreak" => [0x02060], "NonBreakingSpace" => [0x000A0], "Nopf" => [0x02115], "Not" => [0x02AEC], "NotCongruent" => [0x02262], "NotCupCap" => [0x0226D], "NotDoubleVerticalBar" => [0x02226], "NotElement" => [0x02209], "NotEqual" => [0x02260], "NotEqualTilde" => [0x02242, 0x00338], "NotExists" => [0x02204], "NotGreater" => [0x0226F], "NotGreaterEqual" => [0x02271], "NotGreaterFullEqual" => [0x02267, 0x00338], "NotGreaterGreater" => [0x0226B, 0x00338], "NotGreaterLess" => [0x02279], "NotGreaterSlantEqual" => [0x02A7E, 0x00338], "NotGreaterTilde" => [0x02275], "NotHumpDownHump" => [0x0224E, 0x00338], "NotHumpEqual" => [0x0224F, 0x00338], "NotLeftTriangle" => [0x022EA], "NotLeftTriangleBar" => [0x029CF, 0x00338], "NotLeftTriangleEqual" => [0x022EC], "NotLess" => [0x0226E], "NotLessEqual" => [0x02270], "NotLessGreater" => [0x02278], "NotLessLess" => [0x0226A, 0x00338], "NotLessSlantEqual" => [0x02A7D, 0x00338], "NotLessTilde" => [0x02274], "NotNestedGreaterGreater" => [0x02AA2, 0x00338], "NotNestedLessLess" => [0x02AA1, 0x00338], "NotPrecedes" => [0x02280], "NotPrecedesEqual" => [0x02AAF, 0x00338], "NotPrecedesSlantEqual" => [0x022E0], "NotReverseElement" => [0x0220C], "NotRightTriangle" => [0x022EB], "NotRightTriangleBar" => [0x029D0, 0x00338], "NotRightTriangleEqual" => [0x022ED], "NotSquareSubset" => [0x0228F, 0x00338], "NotSquareSubsetEqual" => [0x022E2], "NotSquareSuperset" => [0x02290, 0x00338], "NotSquareSupersetEqual" => [0x022E3], "NotSubset" => [0x02282, 0x020D2], "NotSubsetEqual" => [0x02288], "NotSucceeds" => [0x02281], "NotSucceedsEqual" => [0x02AB0, 0x00338], "NotSucceedsSlantEqual" => [0x022E1], "NotSucceedsTilde" => [0x0227F, 0x00338], "NotSuperset" => [0x02283, 0x020D2], "NotSupersetEqual" => [0x02289], "NotTilde" => [0x02241], "NotTildeEqual" => [0x02244], "NotTildeFullEqual" => [0x02247], "NotTildeTilde" => [0x02249], "NotVerticalBar" => [0x02224], "Nscr" => [0x1D4A9], "Ntilde" => [0x000D1], "Nu" => [0x0039D], "OElig" => [0x00152], "Oacute" => [0x000D3], "Ocirc" => [0x000D4], "Ocy" => [0x0041E], "Odblac" => [0x00150], "Ofr" => [0x1D512], "Ograve" => [0x000D2], "Omacr" => [0x0014C], "Omega" => [0x003A9], "Omicron" => [0x0039F], "Oopf" => [0x1D546], "OpenCurlyDoubleQuote" => [0x0201C], "OpenCurlyQuote" => [0x02018], "Or" => [0x02A54], "Oscr" => [0x1D4AA], "Oslash" => [0x000D8], "Otilde" => [0x000D5], "Otimes" => [0x02A37], "Ouml" => [0x000D6], "OverBar" => [0x0203E], "OverBrace" => [0x023DE], "OverBracket" => [0x023B4], "OverParenthesis" => [0x023DC], "PartialD" => [0x02202], "Pcy" => [0x0041F], "Pfr" => [0x1D513], "Phi" => [0x003A6], "Pi" => [0x003A0], "PlusMinus" => [0x000B1], "Poincareplane" => [0x0210C], "Popf" => [0x02119], "Pr" => [0x02ABB], "Precedes" => [0x0227A], "PrecedesEqual" => [0x02AAF], "PrecedesSlantEqual" => [0x0227C], "PrecedesTilde" => [0x0227E], "Prime" => [0x02033], "Product" => [0x0220F], "Proportion" => [0x02237], "Proportional" => [0x0221D], "Pscr" => [0x1D4AB], "Psi" => [0x003A8], "QUOT" => [0x00022], "Qfr" => [0x1D514], "Qopf" => [0x0211A], "Qscr" => [0x1D4AC], "RBarr" => [0x02910], "REG" => [0x000AE], "Racute" => [0x00154], "Rang" => [0x027EB], "Rarr" => [0x021A0], "Rarrtl" => [0x02916], "Rcaron" => [0x00158], "Rcedil" => [0x00156], "Rcy" => [0x00420], "Re" => [0x0211C], "ReverseElement" => [0x0220B], "ReverseEquilibrium" => [0x021CB], "ReverseUpEquilibrium" => [0x0296F], "Rfr" => [0x0211C], "Rho" => [0x003A1], "RightAngleBracket" => [0x027E9], "RightArrow" => [0x02192], "RightArrowBar" => [0x021E5], "RightArrowLeftArrow" => [0x021C4], "RightCeiling" => [0x02309], "RightDoubleBracket" => [0x027E7], "RightDownTeeVector" => [0x0295D], "RightDownVector" => [0x021C2], "RightDownVectorBar" => [0x02955], "RightFloor" => [0x0230B], "RightTee" => [0x022A2], "RightTeeArrow" => [0x021A6], "RightTeeVector" => [0x0295B], "RightTriangle" => [0x022B3], "RightTriangleBar" => [0x029D0], "RightTriangleEqual" => [0x022B5], "RightUpDownVector" => [0x0294F], "RightUpTeeVector" => [0x0295C], "RightUpVector" => [0x021BE], "RightUpVectorBar" => [0x02954], "RightVector" => [0x021C0], "RightVectorBar" => [0x02953], "Rightarrow" => [0x021D2], "Ropf" => [0x0211D], "RoundImplies" => [0x02970], "Rrightarrow" => [0x021DB], "Rscr" => [0x0211B], "Rsh" => [0x021B1], "RuleDelayed" => [0x029F4], "SHCHcy" => [0x00429], "SHcy" => [0x00428], "SOFTcy" => [0x0042C], "Sacute" => [0x0015A], "Sc" => [0x02ABC], "Scaron" => [0x00160], "Scedil" => [0x0015E], "Scirc" => [0x0015C], "Scy" => [0x00421], "Sfr" => [0x1D516], "ShortDownArrow" => [0x02193], "ShortLeftArrow" => [0x02190], "ShortRightArrow" => [0x02192], "ShortUpArrow" => [0x02191], "Sigma" => [0x003A3], "SmallCircle" => [0x02218], "Sopf" => [0x1D54A], "Sqrt" => [0x0221A], "Square" => [0x025A1], "SquareIntersection" => [0x02293], "SquareSubset" => [0x0228F], "SquareSubsetEqual" => [0x02291], "SquareSuperset" => [0x02290], "SquareSupersetEqual" => [0x02292], "SquareUnion" => [0x02294], "Sscr" => [0x1D4AE], "Star" => [0x022C6], "Sub" => [0x022D0], "Subset" => [0x022D0], "SubsetEqual" => [0x02286], "Succeeds" => [0x0227B], "SucceedsEqual" => [0x02AB0], "SucceedsSlantEqual" => [0x0227D], "SucceedsTilde" => [0x0227F], "SuchThat" => [0x0220B], "Sum" => [0x02211], "Sup" => [0x022D1], "Superset" => [0x02283], "SupersetEqual" => [0x02287], "Supset" => [0x022D1], "THORN" => [0x000DE], "TRADE" => [0x02122], "TSHcy" => [0x0040B], "TScy" => [0x00426], "Tab" => [0x00009], "Tau" => [0x003A4], "Tcaron" => [0x00164], "Tcedil" => [0x00162], "Tcy" => [0x00422], "Tfr" => [0x1D517], "Therefore" => [0x02234], "Theta" => [0x00398], "ThickSpace" => [0x0205F, 0x0200A], "ThinSpace" => [0x02009], "Tilde" => [0x0223C], "TildeEqual" => [0x02243], "TildeFullEqual" => [0x02245], "TildeTilde" => [0x02248], "Topf" => [0x1D54B], "TripleDot" => [0x020DB], "Tscr" => [0x1D4AF], "Tstrok" => [0x00166], "Uacute" => [0x000DA], "Uarr" => [0x0219F], "Uarrocir" => [0x02949], "Ubrcy" => [0x0040E], "Ubreve" => [0x0016C], "Ucirc" => [0x000DB], "Ucy" => [0x00423], "Udblac" => [0x00170], "Ufr" => [0x1D518], "Ugrave" => [0x000D9], "Umacr" => [0x0016A], "UnderBar" => [0x0005F], "UnderBrace" => [0x023DF], "UnderBracket" => [0x023B5], "UnderParenthesis" => [0x023DD], "Union" => [0x022C3], "UnionPlus" => [0x0228E], "Uogon" => [0x00172], "Uopf" => [0x1D54C], "UpArrow" => [0x02191], "UpArrowBar" => [0x02912], "UpArrowDownArrow" => [0x021C5], "UpDownArrow" => [0x02195], "UpEquilibrium" => [0x0296E], "UpTee" => [0x022A5], "UpTeeArrow" => [0x021A5], "Uparrow" => [0x021D1], "Updownarrow" => [0x021D5], "UpperLeftArrow" => [0x02196], "UpperRightArrow" => [0x02197], "Upsi" => [0x003D2], "Upsilon" => [0x003A5], "Uring" => [0x0016E], "Uscr" => [0x1D4B0], "Utilde" => [0x00168], "Uuml" => [0x000DC], "VDash" => [0x022AB], "Vbar" => [0x02AEB], "Vcy" => [0x00412], "Vdash" => [0x022A9], "Vdashl" => [0x02AE6], "Vee" => [0x022C1], "Verbar" => [0x02016], "Vert" => [0x02016], "VerticalBar" => [0x02223], "VerticalLine" => [0x0007C], "VerticalSeparator" => [0x02758], "VerticalTilde" => [0x02240], "VeryThinSpace" => [0x0200A], "Vfr" => [0x1D519], "Vopf" => [0x1D54D], "Vscr" => [0x1D4B1], "Vvdash" => [0x022AA], "Wcirc" => [0x00174], "Wedge" => [0x022C0], "Wfr" => [0x1D51A], "Wopf" => [0x1D54E], "Wscr" => [0x1D4B2], "Xfr" => [0x1D51B], "Xi" => [0x0039E], "Xopf" => [0x1D54F], "Xscr" => [0x1D4B3], "YAcy" => [0x0042F], "YIcy" => [0x00407], "YUcy" => [0x0042E], "Yacute" => [0x000DD], "Ycirc" => [0x00176], "Ycy" => [0x0042B], "Yfr" => [0x1D51C], "Yopf" => [0x1D550], "Yscr" => [0x1D4B4], "Yuml" => [0x00178], "ZHcy" => [0x00416], "Zacute" => [0x00179], "Zcaron" => [0x0017D], "Zcy" => [0x00417], "Zdot" => [0x0017B], "ZeroWidthSpace" => [0x0200B], "Zeta" => [0x00396], "Zfr" => [0x02128], "Zopf" => [0x02124], "Zscr" => [0x1D4B5], "aacute" => [0x000E1], "abreve" => [0x00103], "ac" => [0x0223E], "acE" => [0x0223E, 0x00333], "acd" => [0x0223F], "acirc" => [0x000E2], "acute" => [0x000B4], "acy" => [0x00430], "aelig" => [0x000E6], "af" => [0x02061], "afr" => [0x1D51E], "agrave" => [0x000E0], "alefsym" => [0x02135], "aleph" => [0x02135], "alpha" => [0x003B1], "amacr" => [0x00101], "amalg" => [0x02A3F], "amp" => [0x00026], "and" => [0x02227], "andand" => [0x02A55], "andd" => [0x02A5C], "andslope" => [0x02A58], "andv" => [0x02A5A], "ang" => [0x02220], "ange" => [0x029A4], "angle" => [0x02220], "angmsd" => [0x02221], "angmsdaa" => [0x029A8], "angmsdab" => [0x029A9], "angmsdac" => [0x029AA], "angmsdad" => [0x029AB], "angmsdae" => [0x029AC], "angmsdaf" => [0x029AD], "angmsdag" => [0x029AE], "angmsdah" => [0x029AF], "angrt" => [0x0221F], "angrtvb" => [0x022BE], "angrtvbd" => [0x0299D], "angsph" => [0x02222], "angst" => [0x000C5], "angzarr" => [0x0237C], "aogon" => [0x00105], "aopf" => [0x1D552], "ap" => [0x02248], "apE" => [0x02A70], "apacir" => [0x02A6F], "ape" => [0x0224A], "apid" => [0x0224B], "apos" => [0x00027], "approx" => [0x02248], "approxeq" => [0x0224A], "aring" => [0x000E5], "ascr" => [0x1D4B6], "ast" => [0x0002A], "asymp" => [0x02248], "asympeq" => [0x0224D], "atilde" => [0x000E3], "auml" => [0x000E4], "awconint" => [0x02233], "awint" => [0x02A11], "bNot" => [0x02AED], "backcong" => [0x0224C], "backepsilon" => [0x003F6], "backprime" => [0x02035], "backsim" => [0x0223D], "backsimeq" => [0x022CD], "barvee" => [0x022BD], "barwed" => [0x02305], "barwedge" => [0x02305], "bbrk" => [0x023B5], "bbrktbrk" => [0x023B6], "bcong" => [0x0224C], "bcy" => [0x00431], "bdquo" => [0x0201E], "becaus" => [0x02235], "because" => [0x02235], "bemptyv" => [0x029B0], "bepsi" => [0x003F6], "bernou" => [0x0212C], "beta" => [0x003B2], "beth" => [0x02136], "between" => [0x0226C], "bfr" => [0x1D51F], "bigcap" => [0x022C2], "bigcirc" => [0x025EF], "bigcup" => [0x022C3], "bigodot" => [0x02A00], "bigoplus" => [0x02A01], "bigotimes" => [0x02A02], "bigsqcup" => [0x02A06], "bigstar" => [0x02605], "bigtriangledown" => [0x025BD], "bigtriangleup" => [0x025B3], "biguplus" => [0x02A04], "bigvee" => [0x022C1], "bigwedge" => [0x022C0], "bkarow" => [0x0290D], "blacklozenge" => [0x029EB], "blacksquare" => [0x025AA], "blacktriangle" => [0x025B4], "blacktriangledown" => [0x025BE], "blacktriangleleft" => [0x025C2], "blacktriangleright" => [0x025B8], "blank" => [0x02423], "blk12" => [0x02592], "blk14" => [0x02591], "blk34" => [0x02593], "block" => [0x02588], "bne" => [0x0003D, 0x020E5], "bnequiv" => [0x02261, 0x020E5], "bnot" => [0x02310], "bopf" => [0x1D553], "bot" => [0x022A5], "bottom" => [0x022A5], "bowtie" => [0x022C8], "boxDL" => [0x02557], "boxDR" => [0x02554], "boxDl" => [0x02556], "boxDr" => [0x02553], "boxH" => [0x02550], "boxHD" => [0x02566], "boxHU" => [0x02569], "boxHd" => [0x02564], "boxHu" => [0x02567], "boxUL" => [0x0255D], "boxUR" => [0x0255A], "boxUl" => [0x0255C], "boxUr" => [0x02559], "boxV" => [0x02551], "boxVH" => [0x0256C], "boxVL" => [0x02563], "boxVR" => [0x02560], "boxVh" => [0x0256B], "boxVl" => [0x02562], "boxVr" => [0x0255F], "boxbox" => [0x029C9], "boxdL" => [0x02555], "boxdR" => [0x02552], "boxdl" => [0x02510], "boxdr" => [0x0250C], "boxh" => [0x02500], "boxhD" => [0x02565], "boxhU" => [0x02568], "boxhd" => [0x0252C], "boxhu" => [0x02534], "boxminus" => [0x0229F], "boxplus" => [0x0229E], "boxtimes" => [0x022A0], "boxuL" => [0x0255B], "boxuR" => [0x02558], "boxul" => [0x02518], "boxur" => [0x02514], "boxv" => [0x02502], "boxvH" => [0x0256A], "boxvL" => [0x02561], "boxvR" => [0x0255E], "boxvh" => [0x0253C], "boxvl" => [0x02524], "boxvr" => [0x0251C], "bprime" => [0x02035], "breve" => [0x002D8], "brvbar" => [0x000A6], "bscr" => [0x1D4B7], "bsemi" => [0x0204F], "bsim" => [0x0223D], "bsime" => [0x022CD], "bsol" => [0x0005C], "bsolb" => [0x029C5], "bsolhsub" => [0x027C8], "bull" => [0x02022], "bullet" => [0x02022], "bump" => [0x0224E], "bumpE" => [0x02AAE], "bumpe" => [0x0224F], "bumpeq" => [0x0224F], "cacute" => [0x00107], "cap" => [0x02229], "capand" => [0x02A44], "capbrcup" => [0x02A49], "capcap" => [0x02A4B], "capcup" => [0x02A47], "capdot" => [0x02A40], "caps" => [0x02229, 0x0FE00], "caret" => [0x02041], "caron" => [0x002C7], "ccaps" => [0x02A4D], "ccaron" => [0x0010D], "ccedil" => [0x000E7], "ccirc" => [0x00109], "ccups" => [0x02A4C], "ccupssm" => [0x02A50], "cdot" => [0x0010B], "cedil" => [0x000B8], "cemptyv" => [0x029B2], "cent" => [0x000A2], "centerdot" => [0x000B7], "cfr" => [0x1D520], "chcy" => [0x00447], "check" => [0x02713], "checkmark" => [0x02713], "chi" => [0x003C7], "cir" => [0x025CB], "cirE" => [0x029C3], "circ" => [0x002C6], "circeq" => [0x02257], "circlearrowleft" => [0x021BA], "circlearrowright" => [0x021BB], "circledR" => [0x000AE], "circledS" => [0x024C8], "circledast" => [0x0229B], "circledcirc" => [0x0229A], "circleddash" => [0x0229D], "cire" => [0x02257], "cirfnint" => [0x02A10], "cirmid" => [0x02AEF], "cirscir" => [0x029C2], "clubs" => [0x02663], "clubsuit" => [0x02663], "colon" => [0x0003A], "colone" => [0x02254], "coloneq" => [0x02254], "comma" => [0x0002C], "commat" => [0x00040], "comp" => [0x02201], "compfn" => [0x02218], "complement" => [0x02201], "complexes" => [0x02102], "cong" => [0x02245], "congdot" => [0x02A6D], "conint" => [0x0222E], "copf" => [0x1D554], "coprod" => [0x02210], "copy" => [0x000A9], "copysr" => [0x02117], "crarr" => [0x021B5], "cross" => [0x02717], "cscr" => [0x1D4B8], "csub" => [0x02ACF], "csube" => [0x02AD1], "csup" => [0x02AD0], "csupe" => [0x02AD2], "ctdot" => [0x022EF], "cudarrl" => [0x02938], "cudarrr" => [0x02935], "cuepr" => [0x022DE], "cuesc" => [0x022DF], "cularr" => [0x021B6], "cularrp" => [0x0293D], "cup" => [0x0222A], "cupbrcap" => [0x02A48], "cupcap" => [0x02A46], "cupcup" => [0x02A4A], "cupdot" => [0x0228D], "cupor" => [0x02A45], "cups" => [0x0222A, 0x0FE00], "curarr" => [0x021B7], "curarrm" => [0x0293C], "curlyeqprec" => [0x022DE], "curlyeqsucc" => [0x022DF], "curlyvee" => [0x022CE], "curlywedge" => [0x022CF], "curren" => [0x000A4], "curvearrowleft" => [0x021B6], "curvearrowright" => [0x021B7], "cuvee" => [0x022CE], "cuwed" => [0x022CF], "cwconint" => [0x02232], "cwint" => [0x02231], "cylcty" => [0x0232D], "dArr" => [0x021D3], "dHar" => [0x02965], "dagger" => [0x02020], "daleth" => [0x02138], "darr" => [0x02193], "dash" => [0x02010], "dashv" => [0x022A3], "dbkarow" => [0x0290F], "dblac" => [0x002DD], "dcaron" => [0x0010F], "dcy" => [0x00434], "dd" => [0x02146], "ddagger" => [0x02021], "ddarr" => [0x021CA], "ddotseq" => [0x02A77], "deg" => [0x000B0], "delta" => [0x003B4], "demptyv" => [0x029B1], "dfisht" => [0x0297F], "dfr" => [0x1D521], "dharl" => [0x021C3], "dharr" => [0x021C2], "diam" => [0x022C4], "diamond" => [0x022C4], "diamondsuit" => [0x02666], "diams" => [0x02666], "die" => [0x000A8], "digamma" => [0x003DD], "disin" => [0x022F2], "div" => [0x000F7], "divide" => [0x000F7], "divideontimes" => [0x022C7], "divonx" => [0x022C7], "djcy" => [0x00452], "dlcorn" => [0x0231E], "dlcrop" => [0x0230D], "dollar" => [0x00024], "dopf" => [0x1D555], "dot" => [0x002D9], "doteq" => [0x02250], "doteqdot" => [0x02251], "dotminus" => [0x02238], "dotplus" => [0x02214], "dotsquare" => [0x022A1], "doublebarwedge" => [0x02306], "downarrow" => [0x02193], "downdownarrows" => [0x021CA], "downharpoonleft" => [0x021C3], "downharpoonright" => [0x021C2], "drbkarow" => [0x02910], "drcorn" => [0x0231F], "drcrop" => [0x0230C], "dscr" => [0x1D4B9], "dscy" => [0x00455], "dsol" => [0x029F6], "dstrok" => [0x00111], "dtdot" => [0x022F1], "dtri" => [0x025BF], "dtrif" => [0x025BE], "duarr" => [0x021F5], "duhar" => [0x0296F], "dwangle" => [0x029A6], "dzcy" => [0x0045F], "dzigrarr" => [0x027FF], "eDDot" => [0x02A77], "eDot" => [0x02251], "eacute" => [0x000E9], "easter" => [0x02A6E], "ecaron" => [0x0011B], "ecir" => [0x02256], "ecirc" => [0x000EA], "ecolon" => [0x02255], "ecy" => [0x0044D], "edot" => [0x00117], "ee" => [0x02147], "efDot" => [0x02252], "efr" => [0x1D522], "eg" => [0x02A9A], "egrave" => [0x000E8], "egs" => [0x02A96], "egsdot" => [0x02A98], "el" => [0x02A99], "elinters" => [0x023E7], "ell" => [0x02113], "els" => [0x02A95], "elsdot" => [0x02A97], "emacr" => [0x00113], "empty" => [0x02205], "emptyset" => [0x02205], "emptyv" => [0x02205], "emsp" => [0x02003], "emsp13" => [0x02004], "emsp14" => [0x02005], "eng" => [0x0014B], "ensp" => [0x02002], "eogon" => [0x00119], "eopf" => [0x1D556], "epar" => [0x022D5], "eparsl" => [0x029E3], "eplus" => [0x02A71], "epsi" => [0x003B5], "epsilon" => [0x003B5], "epsiv" => [0x003F5], "eqcirc" => [0x02256], "eqcolon" => [0x02255], "eqsim" => [0x02242], "eqslantgtr" => [0x02A96], "eqslantless" => [0x02A95], "equals" => [0x0003D], "equest" => [0x0225F], "equiv" => [0x02261], "equivDD" => [0x02A78], "eqvparsl" => [0x029E5], "erDot" => [0x02253], "erarr" => [0x02971], "escr" => [0x0212F], "esdot" => [0x02250], "esim" => [0x02242], "eta" => [0x003B7], "eth" => [0x000F0], "euml" => [0x000EB], "euro" => [0x020AC], "excl" => [0x00021], "exist" => [0x02203], "expectation" => [0x02130], "exponentiale" => [0x02147], "fallingdotseq" => [0x02252], "fcy" => [0x00444], "female" => [0x02640], "ffilig" => [0x0FB03], "fflig" => [0x0FB00], "ffllig" => [0x0FB04], "ffr" => [0x1D523], "filig" => [0x0FB01], "fjlig" => [0x00066, 0x0006A], "flat" => [0x0266D], "fllig" => [0x0FB02], "fltns" => [0x025B1], "fnof" => [0x00192], "fopf" => [0x1D557], "forall" => [0x02200], "fork" => [0x022D4], "forkv" => [0x02AD9], "fpartint" => [0x02A0D], "frac12" => [0x000BD], "frac13" => [0x02153], "frac14" => [0x000BC], "frac15" => [0x02155], "frac16" => [0x02159], "frac18" => [0x0215B], "frac23" => [0x02154], "frac25" => [0x02156], "frac34" => [0x000BE], "frac35" => [0x02157], "frac38" => [0x0215C], "frac45" => [0x02158], "frac56" => [0x0215A], "frac58" => [0x0215D], "frac78" => [0x0215E], "frasl" => [0x02044], "frown" => [0x02322], "fscr" => [0x1D4BB], "gE" => [0x02267], "gEl" => [0x02A8C], "gacute" => [0x001F5], "gamma" => [0x003B3], "gammad" => [0x003DD], "gap" => [0x02A86], "gbreve" => [0x0011F], "gcirc" => [0x0011D], "gcy" => [0x00433], "gdot" => [0x00121], "ge" => [0x02265], "gel" => [0x022DB], "geq" => [0x02265], "geqq" => [0x02267], "geqslant" => [0x02A7E], "ges" => [0x02A7E], "gescc" => [0x02AA9], "gesdot" => [0x02A80], "gesdoto" => [0x02A82], "gesdotol" => [0x02A84], "gesl" => [0x022DB, 0x0FE00], "gesles" => [0x02A94], "gfr" => [0x1D524], "gg" => [0x0226B], "ggg" => [0x022D9], "gimel" => [0x02137], "gjcy" => [0x00453], "gl" => [0x02277], "glE" => [0x02A92], "gla" => [0x02AA5], "glj" => [0x02AA4], "gnE" => [0x02269], "gnap" => [0x02A8A], "gnapprox" => [0x02A8A], "gne" => [0x02A88], "gneq" => [0x02A88], "gneqq" => [0x02269], "gnsim" => [0x022E7], "gopf" => [0x1D558], "grave" => [0x00060], "gscr" => [0x0210A], "gsim" => [0x02273], "gsime" => [0x02A8E], "gsiml" => [0x02A90], "gt" => [0x0003E], "gtcc" => [0x02AA7], "gtcir" => [0x02A7A], "gtdot" => [0x022D7], "gtlPar" => [0x02995], "gtquest" => [0x02A7C], "gtrapprox" => [0x02A86], "gtrarr" => [0x02978], "gtrdot" => [0x022D7], "gtreqless" => [0x022DB], "gtreqqless" => [0x02A8C], "gtrless" => [0x02277], "gtrsim" => [0x02273], "gvertneqq" => [0x02269, 0x0FE00], "gvnE" => [0x02269, 0x0FE00], "hArr" => [0x021D4], "hairsp" => [0x0200A], "half" => [0x000BD], "hamilt" => [0x0210B], "hardcy" => [0x0044A], "harr" => [0x02194], "harrcir" => [0x02948], "harrw" => [0x021AD], "hbar" => [0x0210F], "hcirc" => [0x00125], "hearts" => [0x02665], "heartsuit" => [0x02665], "hellip" => [0x02026], "hercon" => [0x022B9], "hfr" => [0x1D525], "hksearow" => [0x02925], "hkswarow" => [0x02926], "hoarr" => [0x021FF], "homtht" => [0x0223B], "hookleftarrow" => [0x021A9], "hookrightarrow" => [0x021AA], "hopf" => [0x1D559], "horbar" => [0x02015], "hscr" => [0x1D4BD], "hslash" => [0x0210F], "hstrok" => [0x00127], "hybull" => [0x02043], "hyphen" => [0x02010], "iacute" => [0x000ED], "ic" => [0x02063], "icirc" => [0x000EE], "icy" => [0x00438], "iecy" => [0x00435], "iexcl" => [0x000A1], "iff" => [0x021D4], "ifr" => [0x1D526], "igrave" => [0x000EC], "ii" => [0x02148], "iiiint" => [0x02A0C], "iiint" => [0x0222D], "iinfin" => [0x029DC], "iiota" => [0x02129], "ijlig" => [0x00133], "imacr" => [0x0012B], "image" => [0x02111], "imagline" => [0x02110], "imagpart" => [0x02111], "imath" => [0x00131], "imof" => [0x022B7], "imped" => [0x001B5], "in" => [0x02208], "incare" => [0x02105], "infin" => [0x0221E], "infintie" => [0x029DD], "inodot" => [0x00131], "int" => [0x0222B], "intcal" => [0x022BA], "integers" => [0x02124], "intercal" => [0x022BA], "intlarhk" => [0x02A17], "intprod" => [0x02A3C], "iocy" => [0x00451], "iogon" => [0x0012F], "iopf" => [0x1D55A], "iota" => [0x003B9], "iprod" => [0x02A3C], "iquest" => [0x000BF], "iscr" => [0x1D4BE], "isin" => [0x02208], "isinE" => [0x022F9], "isindot" => [0x022F5], "isins" => [0x022F4], "isinsv" => [0x022F3], "isinv" => [0x02208], "it" => [0x02062], "itilde" => [0x00129], "iukcy" => [0x00456], "iuml" => [0x000EF], "jcirc" => [0x00135], "jcy" => [0x00439], "jfr" => [0x1D527], "jmath" => [0x00237], "jopf" => [0x1D55B], "jscr" => [0x1D4BF], "jsercy" => [0x00458], "jukcy" => [0x00454], "kappa" => [0x003BA], "kappav" => [0x003F0], "kcedil" => [0x00137], "kcy" => [0x0043A], "kfr" => [0x1D528], "kgreen" => [0x00138], "khcy" => [0x00445], "kjcy" => [0x0045C], "kopf" => [0x1D55C], "kscr" => [0x1D4C0], "lAarr" => [0x021DA], "lArr" => [0x021D0], "lAtail" => [0x0291B], "lBarr" => [0x0290E], "lE" => [0x02266], "lEg" => [0x02A8B], "lHar" => [0x02962], "lacute" => [0x0013A], "laemptyv" => [0x029B4], "lagran" => [0x02112], "lambda" => [0x003BB], "lang" => [0x027E8], "langd" => [0x02991], "langle" => [0x027E8], "lap" => [0x02A85], "laquo" => [0x000AB], "larr" => [0x02190], "larrb" => [0x021E4], "larrbfs" => [0x0291F], "larrfs" => [0x0291D], "larrhk" => [0x021A9], "larrlp" => [0x021AB], "larrpl" => [0x02939], "larrsim" => [0x02973], "larrtl" => [0x021A2], "lat" => [0x02AAB], "latail" => [0x02919], "late" => [0x02AAD], "lates" => [0x02AAD, 0x0FE00], "lbarr" => [0x0290C], "lbbrk" => [0x02772], "lbrace" => [0x0007B], "lbrack" => [0x0005B], "lbrke" => [0x0298B], "lbrksld" => [0x0298F], "lbrkslu" => [0x0298D], "lcaron" => [0x0013E], "lcedil" => [0x0013C], "lceil" => [0x02308], "lcub" => [0x0007B], "lcy" => [0x0043B], "ldca" => [0x02936], "ldquo" => [0x0201C], "ldquor" => [0x0201E], "ldrdhar" => [0x02967], "ldrushar" => [0x0294B], "ldsh" => [0x021B2], "le" => [0x02264], "leftarrow" => [0x02190], "leftarrowtail" => [0x021A2], "leftharpoondown" => [0x021BD], "leftharpoonup" => [0x021BC], "leftleftarrows" => [0x021C7], "leftrightarrow" => [0x02194], "leftrightarrows" => [0x021C6], "leftrightharpoons" => [0x021CB], "leftrightsquigarrow" => [0x021AD], "leftthreetimes" => [0x022CB], "leg" => [0x022DA], "leq" => [0x02264], "leqq" => [0x02266], "leqslant" => [0x02A7D], "les" => [0x02A7D], "lescc" => [0x02AA8], "lesdot" => [0x02A7F], "lesdoto" => [0x02A81], "lesdotor" => [0x02A83], "lesg" => [0x022DA, 0x0FE00], "lesges" => [0x02A93], "lessapprox" => [0x02A85], "lessdot" => [0x022D6], "lesseqgtr" => [0x022DA], "lesseqqgtr" => [0x02A8B], "lessgtr" => [0x02276], "lesssim" => [0x02272], "lfisht" => [0x0297C], "lfloor" => [0x0230A], "lfr" => [0x1D529], "lg" => [0x02276], "lgE" => [0x02A91], "lhard" => [0x021BD], "lharu" => [0x021BC], "lharul" => [0x0296A], "lhblk" => [0x02584], "ljcy" => [0x00459], "ll" => [0x0226A], "llarr" => [0x021C7], "llcorner" => [0x0231E], "llhard" => [0x0296B], "lltri" => [0x025FA], "lmidot" => [0x00140], "lmoust" => [0x023B0], "lmoustache" => [0x023B0], "lnE" => [0x02268], "lnap" => [0x02A89], "lnapprox" => [0x02A89], "lne" => [0x02A87], "lneq" => [0x02A87], "lneqq" => [0x02268], "lnsim" => [0x022E6], "loang" => [0x027EC], "loarr" => [0x021FD], "lobrk" => [0x027E6], "longleftarrow" => [0x027F5], "longleftrightarrow" => [0x027F7], "longmapsto" => [0x027FC], "longrightarrow" => [0x027F6], "looparrowleft" => [0x021AB], "looparrowright" => [0x021AC], "lopar" => [0x02985], "lopf" => [0x1D55D], "loplus" => [0x02A2D], "lotimes" => [0x02A34], "lowast" => [0x02217], "lowbar" => [0x0005F], "loz" => [0x025CA], "lozenge" => [0x025CA], "lozf" => [0x029EB], "lpar" => [0x00028], "lparlt" => [0x02993], "lrarr" => [0x021C6], "lrcorner" => [0x0231F], "lrhar" => [0x021CB], "lrhard" => [0x0296D], "lrm" => [0x0200E], "lrtri" => [0x022BF], "lsaquo" => [0x02039], "lscr" => [0x1D4C1], "lsh" => [0x021B0], "lsim" => [0x02272], "lsime" => [0x02A8D], "lsimg" => [0x02A8F], "lsqb" => [0x0005B], "lsquo" => [0x02018], "lsquor" => [0x0201A], "lstrok" => [0x00142], "lt" => [0x0003C], "ltcc" => [0x02AA6], "ltcir" => [0x02A79], "ltdot" => [0x022D6], "lthree" => [0x022CB], "ltimes" => [0x022C9], "ltlarr" => [0x02976], "ltquest" => [0x02A7B], "ltrPar" => [0x02996], "ltri" => [0x025C3], "ltrie" => [0x022B4], "ltrif" => [0x025C2], "lurdshar" => [0x0294A], "luruhar" => [0x02966], "lvertneqq" => [0x02268, 0x0FE00], "lvnE" => [0x02268, 0x0FE00], "mDDot" => [0x0223A], "macr" => [0x000AF], "male" => [0x02642], "malt" => [0x02720], "maltese" => [0x02720], "map" => [0x021A6], "mapsto" => [0x021A6], "mapstodown" => [0x021A7], "mapstoleft" => [0x021A4], "mapstoup" => [0x021A5], "marker" => [0x025AE], "mcomma" => [0x02A29], "mcy" => [0x0043C], "mdash" => [0x02014], "measuredangle" => [0x02221], "mfr" => [0x1D52A], "mho" => [0x02127], "micro" => [0x000B5], "mid" => [0x02223], "midast" => [0x0002A], "midcir" => [0x02AF0], "middot" => [0x000B7], "minus" => [0x02212], "minusb" => [0x0229F], "minusd" => [0x02238], "minusdu" => [0x02A2A], "mlcp" => [0x02ADB], "mldr" => [0x02026], "mnplus" => [0x02213], "models" => [0x022A7], "mopf" => [0x1D55E], "mp" => [0x02213], "mscr" => [0x1D4C2], "mstpos" => [0x0223E], "mu" => [0x003BC], "multimap" => [0x022B8], "mumap" => [0x022B8], "nGg" => [0x022D9, 0x00338], "nGt" => [0x0226B, 0x020D2], "nGtv" => [0x0226B, 0x00338], "nLeftarrow" => [0x021CD], "nLeftrightarrow" => [0x021CE], "nLl" => [0x022D8, 0x00338], "nLt" => [0x0226A, 0x020D2], "nLtv" => [0x0226A, 0x00338], "nRightarrow" => [0x021CF], "nVDash" => [0x022AF], "nVdash" => [0x022AE], "nabla" => [0x02207], "nacute" => [0x00144], "nang" => [0x02220, 0x020D2], "nap" => [0x02249], "napE" => [0x02A70, 0x00338], "napid" => [0x0224B, 0x00338], "napos" => [0x00149], "napprox" => [0x02249], "natur" => [0x0266E], "natural" => [0x0266E], "naturals" => [0x02115], "nbsp" => [0x000A0], "nbump" => [0x0224E, 0x00338], "nbumpe" => [0x0224F, 0x00338], "ncap" => [0x02A43], "ncaron" => [0x00148], "ncedil" => [0x00146], "ncong" => [0x02247], "ncongdot" => [0x02A6D, 0x00338], "ncup" => [0x02A42], "ncy" => [0x0043D], "ndash" => [0x02013], "ne" => [0x02260], "neArr" => [0x021D7], "nearhk" => [0x02924], "nearr" => [0x02197], "nearrow" => [0x02197], "nedot" => [0x02250, 0x00338], "nequiv" => [0x02262], "nesear" => [0x02928], "nesim" => [0x02242, 0x00338], "nexist" => [0x02204], "nexists" => [0x02204], "nfr" => [0x1D52B], "ngE" => [0x02267, 0x00338], "nge" => [0x02271], "ngeq" => [0x02271], "ngeqq" => [0x02267, 0x00338], "ngeqslant" => [0x02A7E, 0x00338], "nges" => [0x02A7E, 0x00338], "ngsim" => [0x02275], "ngt" => [0x0226F], "ngtr" => [0x0226F], "nhArr" => [0x021CE], "nharr" => [0x021AE], "nhpar" => [0x02AF2], "ni" => [0x0220B], "nis" => [0x022FC], "nisd" => [0x022FA], "niv" => [0x0220B], "njcy" => [0x0045A], "nlArr" => [0x021CD], "nlE" => [0x02266, 0x00338], "nlarr" => [0x0219A], "nldr" => [0x02025], "nle" => [0x02270], "nleftarrow" => [0x0219A], "nleftrightarrow" => [0x021AE], "nleq" => [0x02270], "nleqq" => [0x02266, 0x00338], "nleqslant" => [0x02A7D, 0x00338], "nles" => [0x02A7D, 0x00338], "nless" => [0x0226E], "nlsim" => [0x02274], "nlt" => [0x0226E], "nltri" => [0x022EA], "nltrie" => [0x022EC], "nmid" => [0x02224], "nopf" => [0x1D55F], "not" => [0x000AC], "notin" => [0x02209], "notinE" => [0x022F9, 0x00338], "notindot" => [0x022F5, 0x00338], "notinva" => [0x02209], "notinvb" => [0x022F7], "notinvc" => [0x022F6], "notni" => [0x0220C], "notniva" => [0x0220C], "notnivb" => [0x022FE], "notnivc" => [0x022FD], "npar" => [0x02226], "nparallel" => [0x02226], "nparsl" => [0x02AFD, 0x020E5], "npart" => [0x02202, 0x00338], "npolint" => [0x02A14], "npr" => [0x02280], "nprcue" => [0x022E0], "npre" => [0x02AAF, 0x00338], "nprec" => [0x02280], "npreceq" => [0x02AAF, 0x00338], "nrArr" => [0x021CF], "nrarr" => [0x0219B], "nrarrc" => [0x02933, 0x00338], "nrarrw" => [0x0219D, 0x00338], "nrightarrow" => [0x0219B], "nrtri" => [0x022EB], "nrtrie" => [0x022ED], "nsc" => [0x02281], "nsccue" => [0x022E1], "nsce" => [0x02AB0, 0x00338], "nscr" => [0x1D4C3], "nshortmid" => [0x02224], "nshortparallel" => [0x02226], "nsim" => [0x02241], "nsime" => [0x02244], "nsimeq" => [0x02244], "nsmid" => [0x02224], "nspar" => [0x02226], "nsqsube" => [0x022E2], "nsqsupe" => [0x022E3], "nsub" => [0x02284], "nsubE" => [0x02AC5, 0x00338], "nsube" => [0x02288], "nsubset" => [0x02282, 0x020D2], "nsubseteq" => [0x02288], "nsubseteqq" => [0x02AC5, 0x00338], "nsucc" => [0x02281], "nsucceq" => [0x02AB0, 0x00338], "nsup" => [0x02285], "nsupE" => [0x02AC6, 0x00338], "nsupe" => [0x02289], "nsupset" => [0x02283, 0x020D2], "nsupseteq" => [0x02289], "nsupseteqq" => [0x02AC6, 0x00338], "ntgl" => [0x02279], "ntilde" => [0x000F1], "ntlg" => [0x02278], "ntriangleleft" => [0x022EA], "ntrianglelefteq" => [0x022EC], "ntriangleright" => [0x022EB], "ntrianglerighteq" => [0x022ED], "nu" => [0x003BD], "num" => [0x00023], "numero" => [0x02116], "numsp" => [0x02007], "nvDash" => [0x022AD], "nvHarr" => [0x02904], "nvap" => [0x0224D, 0x020D2], "nvdash" => [0x022AC], "nvge" => [0x02265, 0x020D2], "nvgt" => [0x0003E, 0x020D2], "nvinfin" => [0x029DE], "nvlArr" => [0x02902], "nvle" => [0x02264, 0x020D2], "nvlt" => [0x0003C, 0x020D2], "nvltrie" => [0x022B4, 0x020D2], "nvrArr" => [0x02903], "nvrtrie" => [0x022B5, 0x020D2], "nvsim" => [0x0223C, 0x020D2], "nwArr" => [0x021D6], "nwarhk" => [0x02923], "nwarr" => [0x02196], "nwarrow" => [0x02196], "nwnear" => [0x02927], "oS" => [0x024C8], "oacute" => [0x000F3], "oast" => [0x0229B], "ocir" => [0x0229A], "ocirc" => [0x000F4], "ocy" => [0x0043E], "odash" => [0x0229D], "odblac" => [0x00151], "odiv" => [0x02A38], "odot" => [0x02299], "odsold" => [0x029BC], "oelig" => [0x00153], "ofcir" => [0x029BF], "ofr" => [0x1D52C], "ogon" => [0x002DB], "ograve" => [0x000F2], "ogt" => [0x029C1], "ohbar" => [0x029B5], "ohm" => [0x003A9], "oint" => [0x0222E], "olarr" => [0x021BA], "olcir" => [0x029BE], "olcross" => [0x029BB], "oline" => [0x0203E], "olt" => [0x029C0], "omacr" => [0x0014D], "omega" => [0x003C9], "omicron" => [0x003BF], "omid" => [0x029B6], "ominus" => [0x02296], "oopf" => [0x1D560], "opar" => [0x029B7], "operp" => [0x029B9], "oplus" => [0x02295], "or" => [0x02228], "orarr" => [0x021BB], "ord" => [0x02A5D], "order" => [0x02134], "orderof" => [0x02134], "ordf" => [0x000AA], "ordm" => [0x000BA], "origof" => [0x022B6], "oror" => [0x02A56], "orslope" => [0x02A57], "orv" => [0x02A5B], "oscr" => [0x02134], "oslash" => [0x000F8], "osol" => [0x02298], "otilde" => [0x000F5], "otimes" => [0x02297], "otimesas" => [0x02A36], "ouml" => [0x000F6], "ovbar" => [0x0233D], "par" => [0x02225], "para" => [0x000B6], "parallel" => [0x02225], "parsim" => [0x02AF3], "parsl" => [0x02AFD], "part" => [0x02202], "pcy" => [0x0043F], "percnt" => [0x00025], "period" => [0x0002E], "permil" => [0x02030], "perp" => [0x022A5], "pertenk" => [0x02031], "pfr" => [0x1D52D], "phi" => [0x003C6], "phiv" => [0x003D5], "phmmat" => [0x02133], "phone" => [0x0260E], "pi" => [0x003C0], "pitchfork" => [0x022D4], "piv" => [0x003D6], "planck" => [0x0210F], "planckh" => [0x0210E], "plankv" => [0x0210F], "plus" => [0x0002B], "plusacir" => [0x02A23], "plusb" => [0x0229E], "pluscir" => [0x02A22], "plusdo" => [0x02214], "plusdu" => [0x02A25], "pluse" => [0x02A72], "plusmn" => [0x000B1], "plussim" => [0x02A26], "plustwo" => [0x02A27], "pm" => [0x000B1], "pointint" => [0x02A15], "popf" => [0x1D561], "pound" => [0x000A3], "pr" => [0x0227A], "prE" => [0x02AB3], "prap" => [0x02AB7], "prcue" => [0x0227C], "pre" => [0x02AAF], "prec" => [0x0227A], "precapprox" => [0x02AB7], "preccurlyeq" => [0x0227C], "preceq" => [0x02AAF], "precnapprox" => [0x02AB9], "precneqq" => [0x02AB5], "precnsim" => [0x022E8], "precsim" => [0x0227E], "prime" => [0x02032], "primes" => [0x02119], "prnE" => [0x02AB5], "prnap" => [0x02AB9], "prnsim" => [0x022E8], "prod" => [0x0220F], "profalar" => [0x0232E], "profline" => [0x02312], "profsurf" => [0x02313], "prop" => [0x0221D], "propto" => [0x0221D], "prsim" => [0x0227E], "prurel" => [0x022B0], "pscr" => [0x1D4C5], "psi" => [0x003C8], "puncsp" => [0x02008], "qfr" => [0x1D52E], "qint" => [0x02A0C], "qopf" => [0x1D562], "qprime" => [0x02057], "qscr" => [0x1D4C6], "quaternions" => [0x0210D], "quatint" => [0x02A16], "quest" => [0x0003F], "questeq" => [0x0225F], "quot" => [0x00022], "rAarr" => [0x021DB], "rArr" => [0x021D2], "rAtail" => [0x0291C], "rBarr" => [0x0290F], "rHar" => [0x02964], "race" => [0x0223D, 0x00331], "racute" => [0x00155], "radic" => [0x0221A], "raemptyv" => [0x029B3], "rang" => [0x027E9], "rangd" => [0x02992], "range" => [0x029A5], "rangle" => [0x027E9], "raquo" => [0x000BB], "rarr" => [0x02192], "rarrap" => [0x02975], "rarrb" => [0x021E5], "rarrbfs" => [0x02920], "rarrc" => [0x02933], "rarrfs" => [0x0291E], "rarrhk" => [0x021AA], "rarrlp" => [0x021AC], "rarrpl" => [0x02945], "rarrsim" => [0x02974], "rarrtl" => [0x021A3], "rarrw" => [0x0219D], "ratail" => [0x0291A], "ratio" => [0x02236], "rationals" => [0x0211A], "rbarr" => [0x0290D], "rbbrk" => [0x02773], "rbrace" => [0x0007D], "rbrack" => [0x0005D], "rbrke" => [0x0298C], "rbrksld" => [0x0298E], "rbrkslu" => [0x02990], "rcaron" => [0x00159], "rcedil" => [0x00157], "rceil" => [0x02309], "rcub" => [0x0007D], "rcy" => [0x00440], "rdca" => [0x02937], "rdldhar" => [0x02969], "rdquo" => [0x0201D], "rdquor" => [0x0201D], "rdsh" => [0x021B3], "real" => [0x0211C], "realine" => [0x0211B], "realpart" => [0x0211C], "reals" => [0x0211D], "rect" => [0x025AD], "reg" => [0x000AE], "rfisht" => [0x0297D], "rfloor" => [0x0230B], "rfr" => [0x1D52F], "rhard" => [0x021C1], "rharu" => [0x021C0], "rharul" => [0x0296C], "rho" => [0x003C1], "rhov" => [0x003F1], "rightarrow" => [0x02192], "rightarrowtail" => [0x021A3], "rightharpoondown" => [0x021C1], "rightharpoonup" => [0x021C0], "rightleftarrows" => [0x021C4], "rightleftharpoons" => [0x021CC], "rightrightarrows" => [0x021C9], "rightsquigarrow" => [0x0219D], "rightthreetimes" => [0x022CC], "ring" => [0x002DA], "risingdotseq" => [0x02253], "rlarr" => [0x021C4], "rlhar" => [0x021CC], "rlm" => [0x0200F], "rmoust" => [0x023B1], "rmoustache" => [0x023B1], "rnmid" => [0x02AEE], "roang" => [0x027ED], "roarr" => [0x021FE], "robrk" => [0x027E7], "ropar" => [0x02986], "ropf" => [0x1D563], "roplus" => [0x02A2E], "rotimes" => [0x02A35], "rpar" => [0x00029], "rpargt" => [0x02994], "rppolint" => [0x02A12], "rrarr" => [0x021C9], "rsaquo" => [0x0203A], "rscr" => [0x1D4C7], "rsh" => [0x021B1], "rsqb" => [0x0005D], "rsquo" => [0x02019], "rsquor" => [0x02019], "rthree" => [0x022CC], "rtimes" => [0x022CA], "rtri" => [0x025B9], "rtrie" => [0x022B5], "rtrif" => [0x025B8], "rtriltri" => [0x029CE], "ruluhar" => [0x02968], "rx" => [0x0211E], "sacute" => [0x0015B], "sbquo" => [0x0201A], "sc" => [0x0227B], "scE" => [0x02AB4], "scap" => [0x02AB8], "scaron" => [0x00161], "sccue" => [0x0227D], "sce" => [0x02AB0], "scedil" => [0x0015F], "scirc" => [0x0015D], "scnE" => [0x02AB6], "scnap" => [0x02ABA], "scnsim" => [0x022E9], "scpolint" => [0x02A13], "scsim" => [0x0227F], "scy" => [0x00441], "sdot" => [0x022C5], "sdotb" => [0x022A1], "sdote" => [0x02A66], "seArr" => [0x021D8], "searhk" => [0x02925], "searr" => [0x02198], "searrow" => [0x02198], "sect" => [0x000A7], "semi" => [0x0003B], "seswar" => [0x02929], "setminus" => [0x02216], "setmn" => [0x02216], "sext" => [0x02736], "sfr" => [0x1D530], "sfrown" => [0x02322], "sharp" => [0x0266F], "shchcy" => [0x00449], "shcy" => [0x00448], "shortmid" => [0x02223], "shortparallel" => [0x02225], "shy" => [0x000AD], "sigma" => [0x003C3], "sigmaf" => [0x003C2], "sigmav" => [0x003C2], "sim" => [0x0223C], "simdot" => [0x02A6A], "sime" => [0x02243], "simeq" => [0x02243], "simg" => [0x02A9E], "simgE" => [0x02AA0], "siml" => [0x02A9D], "simlE" => [0x02A9F], "simne" => [0x02246], "simplus" => [0x02A24], "simrarr" => [0x02972], "slarr" => [0x02190], "smallsetminus" => [0x02216], "smashp" => [0x02A33], "smeparsl" => [0x029E4], "smid" => [0x02223], "smile" => [0x02323], "smt" => [0x02AAA], "smte" => [0x02AAC], "smtes" => [0x02AAC, 0x0FE00], "softcy" => [0x0044C], "sol" => [0x0002F], "solb" => [0x029C4], "solbar" => [0x0233F], "sopf" => [0x1D564], "spades" => [0x02660], "spadesuit" => [0x02660], "spar" => [0x02225], "sqcap" => [0x02293], "sqcaps" => [0x02293, 0x0FE00], "sqcup" => [0x02294], "sqcups" => [0x02294, 0x0FE00], "sqsub" => [0x0228F], "sqsube" => [0x02291], "sqsubset" => [0x0228F], "sqsubseteq" => [0x02291], "sqsup" => [0x02290], "sqsupe" => [0x02292], "sqsupset" => [0x02290], "sqsupseteq" => [0x02292], "squ" => [0x025A1], "square" => [0x025A1], "squarf" => [0x025AA], "squf" => [0x025AA], "srarr" => [0x02192], "sscr" => [0x1D4C8], "ssetmn" => [0x02216], "ssmile" => [0x02323], "sstarf" => [0x022C6], "star" => [0x02606], "starf" => [0x02605], "straightepsilon" => [0x003F5], "straightphi" => [0x003D5], "strns" => [0x000AF], "sub" => [0x02282], "subE" => [0x02AC5], "subdot" => [0x02ABD], "sube" => [0x02286], "subedot" => [0x02AC3], "submult" => [0x02AC1], "subnE" => [0x02ACB], "subne" => [0x0228A], "subplus" => [0x02ABF], "subrarr" => [0x02979], "subset" => [0x02282], "subseteq" => [0x02286], "subseteqq" => [0x02AC5], "subsetneq" => [0x0228A], "subsetneqq" => [0x02ACB], "subsim" => [0x02AC7], "subsub" => [0x02AD5], "subsup" => [0x02AD3], "succ" => [0x0227B], "succapprox" => [0x02AB8], "succcurlyeq" => [0x0227D], "succeq" => [0x02AB0], "succnapprox" => [0x02ABA], "succneqq" => [0x02AB6], "succnsim" => [0x022E9], "succsim" => [0x0227F], "sum" => [0x02211], "sung" => [0x0266A], "sup" => [0x02283], "sup1" => [0x000B9], "sup2" => [0x000B2], "sup3" => [0x000B3], "supE" => [0x02AC6], "supdot" => [0x02ABE], "supdsub" => [0x02AD8], "supe" => [0x02287], "supedot" => [0x02AC4], "suphsol" => [0x027C9], "suphsub" => [0x02AD7], "suplarr" => [0x0297B], "supmult" => [0x02AC2], "supnE" => [0x02ACC], "supne" => [0x0228B], "supplus" => [0x02AC0], "supset" => [0x02283], "supseteq" => [0x02287], "supseteqq" => [0x02AC6], "supsetneq" => [0x0228B], "supsetneqq" => [0x02ACC], "supsim" => [0x02AC8], "supsub" => [0x02AD4], "supsup" => [0x02AD6], "swArr" => [0x021D9], "swarhk" => [0x02926], "swarr" => [0x02199], "swarrow" => [0x02199], "swnwar" => [0x0292A], "szlig" => [0x000DF], "target" => [0x02316], "tau" => [0x003C4], "tbrk" => [0x023B4], "tcaron" => [0x00165], "tcedil" => [0x00163], "tcy" => [0x00442], "tdot" => [0x020DB], "telrec" => [0x02315], "tfr" => [0x1D531], "there4" => [0x02234], "therefore" => [0x02234], "theta" => [0x003B8], "thetasym" => [0x003D1], "thetav" => [0x003D1], "thickapprox" => [0x02248], "thicksim" => [0x0223C], "thinsp" => [0x02009], "thkap" => [0x02248], "thksim" => [0x0223C], "thorn" => [0x000FE], "tilde" => [0x002DC], "times" => [0x000D7], "timesb" => [0x022A0], "timesbar" => [0x02A31], "timesd" => [0x02A30], "tint" => [0x0222D], "toea" => [0x02928], "top" => [0x022A4], "topbot" => [0x02336], "topcir" => [0x02AF1], "topf" => [0x1D565], "topfork" => [0x02ADA], "tosa" => [0x02929], "tprime" => [0x02034], "trade" => [0x02122], "triangle" => [0x025B5], "triangledown" => [0x025BF], "triangleleft" => [0x025C3], "trianglelefteq" => [0x022B4], "triangleq" => [0x0225C], "triangleright" => [0x025B9], "trianglerighteq" => [0x022B5], "tridot" => [0x025EC], "trie" => [0x0225C], "triminus" => [0x02A3A], "triplus" => [0x02A39], "trisb" => [0x029CD], "tritime" => [0x02A3B], "trpezium" => [0x023E2], "tscr" => [0x1D4C9], "tscy" => [0x00446], "tshcy" => [0x0045B], "tstrok" => [0x00167], "twixt" => [0x0226C], "twoheadleftarrow" => [0x0219E], "twoheadrightarrow" => [0x021A0], "uArr" => [0x021D1], "uHar" => [0x02963], "uacute" => [0x000FA], "uarr" => [0x02191], "ubrcy" => [0x0045E], "ubreve" => [0x0016D], "ucirc" => [0x000FB], "ucy" => [0x00443], "udarr" => [0x021C5], "udblac" => [0x00171], "udhar" => [0x0296E], "ufisht" => [0x0297E], "ufr" => [0x1D532], "ugrave" => [0x000F9], "uharl" => [0x021BF], "uharr" => [0x021BE], "uhblk" => [0x02580], "ulcorn" => [0x0231C], "ulcorner" => [0x0231C], "ulcrop" => [0x0230F], "ultri" => [0x025F8], "umacr" => [0x0016B], "uml" => [0x000A8], "uogon" => [0x00173], "uopf" => [0x1D566], "uparrow" => [0x02191], "updownarrow" => [0x02195], "upharpoonleft" => [0x021BF], "upharpoonright" => [0x021BE], "uplus" => [0x0228E], "upsi" => [0x003C5], "upsih" => [0x003D2], "upsilon" => [0x003C5], "upuparrows" => [0x021C8], "urcorn" => [0x0231D], "urcorner" => [0x0231D], "urcrop" => [0x0230E], "uring" => [0x0016F], "urtri" => [0x025F9], "uscr" => [0x1D4CA], "utdot" => [0x022F0], "utilde" => [0x00169], "utri" => [0x025B5], "utrif" => [0x025B4], "uuarr" => [0x021C8], "uuml" => [0x000FC], "uwangle" => [0x029A7], "vArr" => [0x021D5], "vBar" => [0x02AE8], "vBarv" => [0x02AE9], "vDash" => [0x022A8], "vangrt" => [0x0299C], "varepsilon" => [0x003F5], "varkappa" => [0x003F0], "varnothing" => [0x02205], "varphi" => [0x003D5], "varpi" => [0x003D6], "varpropto" => [0x0221D], "varr" => [0x02195], "varrho" => [0x003F1], "varsigma" => [0x003C2], "varsubsetneq" => [0x0228A, 0x0FE00], "varsubsetneqq" => [0x02ACB, 0x0FE00], "varsupsetneq" => [0x0228B, 0x0FE00], "varsupsetneqq" => [0x02ACC, 0x0FE00], "vartheta" => [0x003D1], "vartriangleleft" => [0x022B2], "vartriangleright" => [0x022B3], "vcy" => [0x00432], "vdash" => [0x022A2], "vee" => [0x02228], "veebar" => [0x022BB], "veeeq" => [0x0225A], "vellip" => [0x022EE], "verbar" => [0x0007C], "vert" => [0x0007C], "vfr" => [0x1D533], "vltri" => [0x022B2], "vnsub" => [0x02282, 0x020D2], "vnsup" => [0x02283, 0x020D2], "vopf" => [0x1D567], "vprop" => [0x0221D], "vrtri" => [0x022B3], "vscr" => [0x1D4CB], "vsubnE" => [0x02ACB, 0x0FE00], "vsubne" => [0x0228A, 0x0FE00], "vsupnE" => [0x02ACC, 0x0FE00], "vsupne" => [0x0228B, 0x0FE00], "vzigzag" => [0x0299A], "wcirc" => [0x00175], "wedbar" => [0x02A5F], "wedge" => [0x02227], "wedgeq" => [0x02259], "weierp" => [0x02118], "wfr" => [0x1D534], "wopf" => [0x1D568], "wp" => [0x02118], "wr" => [0x02240], "wreath" => [0x02240], "wscr" => [0x1D4CC], "xcap" => [0x022C2], "xcirc" => [0x025EF], "xcup" => [0x022C3], "xdtri" => [0x025BD], "xfr" => [0x1D535], "xhArr" => [0x027FA], "xharr" => [0x027F7], "xi" => [0x003BE], "xlArr" => [0x027F8], "xlarr" => [0x027F5], "xmap" => [0x027FC], "xnis" => [0x022FB], "xodot" => [0x02A00], "xopf" => [0x1D569], "xoplus" => [0x02A01], "xotime" => [0x02A02], "xrArr" => [0x027F9], "xrarr" => [0x027F6], "xscr" => [0x1D4CD], "xsqcup" => [0x02A06], "xuplus" => [0x02A04], "xutri" => [0x025B3], "xvee" => [0x022C1], "xwedge" => [0x022C0], "yacute" => [0x000FD], "yacy" => [0x0044F], "ycirc" => [0x00177], "ycy" => [0x0044B], "yen" => [0x000A5], "yfr" => [0x1D536], "yicy" => [0x00457], "yopf" => [0x1D56A], "yscr" => [0x1D4CE], "yucy" => [0x0044E], "yuml" => [0x000FF], "zacute" => [0x0017A], "zcaron" => [0x0017E], "zcy" => [0x00437], "zdot" => [0x0017C], "zeetrf" => [0x02128], "zeta" => [0x003B6], "zfr" => [0x1D537], "zhcy" => [0x00436], "zigrarr" => [0x021DD], "zopf" => [0x1D56B], "zscr" => [0x1D4CF], "zwj" => [0x0200D], "zwnj" => [0x0200C], } PKu]LRh$h$*rdoc-6.2.1.1/lib/rdoc/markdown/literals.rbnu[# coding: UTF-8 # frozen_string_literal: true # :markup: markdown ## #-- # This set of literals is for Ruby 1.9 regular expressions and gives full # unicode support. # # Unlike peg-markdown, this set of literals recognizes Unicode alphanumeric # characters, newlines and spaces. class RDoc::Markdown::Literals # :stopdoc: # This is distinct from setup_parser so that a standalone parser # can redefine #initialize and still have access to the proper # parser setup code. def initialize(str, debug=false) setup_parser(str, debug) end # Prepares for parsing +str+. If you define a custom initialize you must # call this method before #parse def setup_parser(str, debug=false) set_string str, 0 @memoizations = Hash.new { |h,k| h[k] = {} } @result = nil @failed_rule = nil @failing_rule_offset = -1 setup_foreign_grammar end attr_reader :string attr_reader :failing_rule_offset attr_accessor :result, :pos def current_column(target=pos) if c = string.rindex("\n", target-1) return target - c - 1 end target + 1 end def current_line(target=pos) cur_offset = 0 cur_line = 0 string.each_line do |line| cur_line += 1 cur_offset += line.size return cur_line if cur_offset >= target end -1 end def lines lines = [] string.each_line { |l| lines << l } lines end def get_text(start) @string[start..@pos-1] end # Sets the string and current parsing position for the parser. def set_string string, pos @string = string @string_size = string ? string.size : 0 @pos = pos end def show_pos width = 10 if @pos < width "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")" else "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")" end end def failure_info l = current_line @failing_rule_offset c = current_column @failing_rule_offset if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'" else "line #{l}, column #{c}: failed rule '#{@failed_rule}'" end end def failure_caret l = current_line @failing_rule_offset c = current_column @failing_rule_offset line = lines[l-1] "#{line}\n#{' ' * (c - 1)}^" end def failure_character l = current_line @failing_rule_offset c = current_column @failing_rule_offset lines[l-1][c-1, 1] end def failure_oneline l = current_line @failing_rule_offset c = current_column @failing_rule_offset char = lines[l-1][c-1, 1] if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'" else "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'" end end class ParseError < RuntimeError end def raise_error raise ParseError, failure_oneline end def show_error(io=STDOUT) error_pos = @failing_rule_offset line_no = current_line(error_pos) col_no = current_column(error_pos) io.puts "On line #{line_no}, column #{col_no}:" if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')" else io.puts "Failed to match rule '#{@failed_rule}'" end io.puts "Got: #{string[error_pos,1].inspect}" line = lines[line_no-1] io.puts "=> #{line}" io.print(" " * (col_no + 3)) io.puts "^" end def set_failed_rule(name) if @pos > @failing_rule_offset @failed_rule = name @failing_rule_offset = @pos end end attr_reader :failed_rule def match_string(str) len = str.size if @string[pos,len] == str @pos += len return str end return nil end def scan(reg) if m = reg.match(@string[@pos..-1]) width = m.end(0) @pos += width return true end return nil end if "".respond_to? :ord def get_byte if @pos >= @string_size return nil end s = @string[@pos].ord @pos += 1 s end else def get_byte if @pos >= @string_size return nil end s = @string[@pos] @pos += 1 s end end def parse(rule=nil) # We invoke the rules indirectly via apply # instead of by just calling them as methods because # if the rules use left recursion, apply needs to # manage that. if !rule apply(:_root) else method = rule.gsub("-","_hyphen_") apply :"_#{method}" end end class MemoEntry def initialize(ans, pos) @ans = ans @pos = pos @result = nil @set = false @left_rec = false end attr_reader :ans, :pos, :result, :set attr_accessor :left_rec def move!(ans, pos, result) @ans = ans @pos = pos @result = result @set = true @left_rec = false end end def external_invoke(other, rule, *args) old_pos = @pos old_string = @string set_string other.string, other.pos begin if val = __send__(rule, *args) other.pos = @pos other.result = @result else other.set_failed_rule "#{self.class}##{rule}" end val ensure set_string old_string, old_pos end end def apply_with_args(rule, *args) memo_key = [rule, args] if m = @memoizations[memo_key][@pos] @pos = m.pos if !m.set m.left_rec = true return nil end @result = m.result return m.ans else m = MemoEntry.new(nil, @pos) @memoizations[memo_key][@pos] = m start_pos = @pos ans = __send__ rule, *args lr = m.left_rec m.move! ans, @pos, @result # Don't bother trying to grow the left recursion # if it's failing straight away (thus there is no seed) if ans and lr return grow_lr(rule, args, start_pos, m) else return ans end end end def apply(rule) if m = @memoizations[rule][@pos] @pos = m.pos if !m.set m.left_rec = true return nil end @result = m.result return m.ans else m = MemoEntry.new(nil, @pos) @memoizations[rule][@pos] = m start_pos = @pos ans = __send__ rule lr = m.left_rec m.move! ans, @pos, @result # Don't bother trying to grow the left recursion # if it's failing straight away (thus there is no seed) if ans and lr return grow_lr(rule, nil, start_pos, m) else return ans end end end def grow_lr(rule, args, start_pos, m) while true @pos = start_pos @result = m.result if args ans = __send__ rule, *args else ans = __send__ rule end return nil unless ans break if @pos <= m.pos m.move! ans, @pos, @result end @result = m.result @pos = m.pos return m.ans end class RuleInfo def initialize(name, rendered) @name = name @rendered = rendered end attr_reader :name, :rendered end def self.rule_info(name, rendered) RuleInfo.new(name, rendered) end # :startdoc: # :stopdoc: def setup_foreign_grammar; end # Alphanumeric = /\p{Word}/ def _Alphanumeric _tmp = scan(/\A(?-mix:\p{Word})/) set_failed_rule :_Alphanumeric unless _tmp return _tmp end # AlphanumericAscii = /[A-Za-z0-9]/ def _AlphanumericAscii _tmp = scan(/\A(?-mix:[A-Za-z0-9])/) set_failed_rule :_AlphanumericAscii unless _tmp return _tmp end # BOM = "uFEFF" def _BOM _tmp = match_string("uFEFF") set_failed_rule :_BOM unless _tmp return _tmp end # Newline = /\n|\r\n?|\p{Zl}|\p{Zp}/ def _Newline _tmp = scan(/\A(?-mix:\n|\r\n?|\p{Zl}|\p{Zp})/) set_failed_rule :_Newline unless _tmp return _tmp end # NonAlphanumeric = /\p{^Word}/ def _NonAlphanumeric _tmp = scan(/\A(?-mix:\p{^Word})/) set_failed_rule :_NonAlphanumeric unless _tmp return _tmp end # Spacechar = /\t|\p{Zs}/ def _Spacechar _tmp = scan(/\A(?-mix:\t|\p{Zs})/) set_failed_rule :_Spacechar unless _tmp return _tmp end Rules = {} Rules[:_Alphanumeric] = rule_info("Alphanumeric", "/\\p{Word}/") Rules[:_AlphanumericAscii] = rule_info("AlphanumericAscii", "/[A-Za-z0-9]/") Rules[:_BOM] = rule_info("BOM", "\"uFEFF\"") Rules[:_Newline] = rule_info("Newline", "/\\n|\\r\\n?|\\p{Zl}|\\p{Zp}/") Rules[:_NonAlphanumeric] = rule_info("NonAlphanumeric", "/\\p{^Word}/") Rules[:_Spacechar] = rule_info("Spacechar", "/\\t|\\p{Zs}/") # :startdoc: end PKu]FMYYrdoc-6.2.1.1/lib/rdoc/store.rbnu[# frozen_string_literal: true require 'fileutils' ## # A set of rdoc data for a single project (gem, path, etc.). # # The store manages reading and writing ri data for a project and maintains a # cache of methods, classes and ancestors in the store. # # The store maintains a #cache of its contents for faster lookup. After # adding items to the store it must be flushed using #save_cache. The cache # contains the following structures: # # @cache = { # :ancestors => {}, # class name => ancestor names # :attributes => {}, # class name => attributes # :class_methods => {}, # class name => class methods # :instance_methods => {}, # class name => instance methods # :modules => [], # classes and modules in this store # :pages => [], # page names # } #-- # TODO need to prune classes class RDoc::Store ## # Errors raised from loading or saving the store class Error < RDoc::Error end ## # Raised when a stored file for a class, module, page or method is missing. class MissingFileError < Error ## # The store the file should exist in attr_reader :store ## # The file the #name should be saved as attr_reader :file ## # The name of the object the #file would be loaded from attr_reader :name ## # Creates a new MissingFileError for the missing +file+ for the given # +name+ that should have been in the +store+. def initialize store, file, name @store = store @file = file @name = name end def message # :nodoc: "store at #{@store.path} missing file #{@file} for #{@name}" end end ## # Stores the name of the C variable a class belongs to. This helps wire up # classes defined from C across files. attr_reader :c_enclosure_classes # :nodoc: attr_reader :c_enclosure_names # :nodoc: ## # Maps C variables to class or module names for each parsed C file. attr_reader :c_class_variables ## # Maps C variables to singleton class names for each parsed C file. attr_reader :c_singleton_class_variables ## # If true this Store will not write any files attr_accessor :dry_run ## # Path this store reads or writes attr_accessor :path ## # The RDoc::RDoc driver for this parse tree. This allows classes consulting # the documentation tree to access user-set options, for example. attr_accessor :rdoc ## # Type of ri datastore this was loaded from. See RDoc::RI::Driver, # RDoc::RI::Paths. attr_accessor :type ## # The contents of the Store attr_reader :cache ## # The encoding of the contents in the Store attr_accessor :encoding ## # The lazy constants alias will be discovered in passing attr_reader :unmatched_constant_alias ## # Creates a new Store of +type+ that will load or save to +path+ def initialize path = nil, type = nil @dry_run = false @encoding = nil @path = path @rdoc = nil @type = type @cache = { :ancestors => {}, :attributes => {}, :class_methods => {}, :c_class_variables => {}, :c_singleton_class_variables => {}, :encoding => @encoding, :instance_methods => {}, :main => nil, :modules => [], :pages => [], :title => nil, } @classes_hash = {} @modules_hash = {} @files_hash = {} @text_files_hash = {} @c_enclosure_classes = {} @c_enclosure_names = {} @c_class_variables = {} @c_singleton_class_variables = {} @unique_classes = nil @unique_modules = nil @unmatched_constant_alias = {} end ## # Adds +module+ as an enclosure (namespace) for the given +variable+ for C # files. def add_c_enclosure variable, namespace @c_enclosure_classes[variable] = namespace end ## # Adds C variables from an RDoc::Parser::C def add_c_variables c_parser filename = c_parser.top_level.relative_name @c_class_variables[filename] = make_variable_map c_parser.classes @c_singleton_class_variables[filename] = c_parser.singleton_classes end ## # Adds the file with +name+ as an RDoc::TopLevel to the store. Returns the # created RDoc::TopLevel. def add_file absolute_name, relative_name: absolute_name, parser: nil unless top_level = @files_hash[relative_name] then top_level = RDoc::TopLevel.new absolute_name, relative_name top_level.parser = parser if parser top_level.store = self @files_hash[relative_name] = top_level @text_files_hash[relative_name] = top_level if top_level.text? end top_level end def update_parser_of_file(absolute_name, parser) if top_level = @files_hash[absolute_name] then @text_files_hash[absolute_name] = top_level if top_level.text? end end ## # Returns all classes discovered by RDoc def all_classes @classes_hash.values end ## # Returns all classes and modules discovered by RDoc def all_classes_and_modules @classes_hash.values + @modules_hash.values end ## # All TopLevels known to RDoc def all_files @files_hash.values end ## # Returns all modules discovered by RDoc def all_modules modules_hash.values end ## # Ancestors cache accessor. Maps a klass name to an Array of its ancestors # in this store. If Foo in this store inherits from Object, Kernel won't be # listed (it will be included from ruby's ri store). def ancestors @cache[:ancestors] end ## # Attributes cache accessor. Maps a class to an Array of its attributes. def attributes @cache[:attributes] end ## # Path to the cache file def cache_path File.join @path, 'cache.ri' end ## # Path to the ri data for +klass_name+ def class_file klass_name name = klass_name.split('::').last File.join class_path(klass_name), "cdesc-#{name}.ri" end ## # Class methods cache accessor. Maps a class to an Array of its class # methods (not full name). def class_methods @cache[:class_methods] end ## # Path where data for +klass_name+ will be stored (methods or class data) def class_path klass_name File.join @path, *klass_name.split('::') end ## # Hash of all classes known to RDoc def classes_hash @classes_hash end ## # Removes empty items and ensures item in each collection are unique and # sorted def clean_cache_collection collection # :nodoc: collection.each do |name, item| if item.empty? then collection.delete name else # HACK mongrel-1.1.5 documents its files twice item.uniq! item.sort! end end end ## # Prepares the RDoc code object tree for use by a generator. # # It finds unique classes/modules defined, and replaces classes/modules that # are aliases for another one by a copy with RDoc::ClassModule#is_alias_for # set. # # It updates the RDoc::ClassModule#constant_aliases attribute of "real" # classes or modules. # # It also completely removes the classes and modules that should be removed # from the documentation and the methods that have a visibility below # +min_visibility+, which is the --visibility option. # # See also RDoc::Context#remove_from_documentation? def complete min_visibility fix_basic_object_inheritance # cache included modules before they are removed from the documentation all_classes_and_modules.each { |cm| cm.ancestors } unless min_visibility == :nodoc then remove_nodoc @classes_hash remove_nodoc @modules_hash end @unique_classes = find_unique @classes_hash @unique_modules = find_unique @modules_hash unique_classes_and_modules.each do |cm| cm.complete min_visibility end @files_hash.each_key do |file_name| tl = @files_hash[file_name] unless tl.text? then tl.modules_hash.clear tl.classes_hash.clear tl.classes_or_modules.each do |cm| name = cm.full_name if cm.type == 'class' then tl.classes_hash[name] = cm if @classes_hash[name] else tl.modules_hash[name] = cm if @modules_hash[name] end end end end end ## # Hash of all files known to RDoc def files_hash @files_hash end ## # Finds the enclosure (namespace) for the given C +variable+. def find_c_enclosure variable @c_enclosure_classes.fetch variable do break unless name = @c_enclosure_names[variable] mod = find_class_or_module name unless mod then loaded_mod = load_class_data name file = loaded_mod.in_files.first return unless file # legacy data source file.store = self mod = file.add_module RDoc::NormalModule, name end @c_enclosure_classes[variable] = mod end end ## # Finds the class with +name+ in all discovered classes def find_class_named name @classes_hash[name] end ## # Finds the class with +name+ starting in namespace +from+ def find_class_named_from name, from from = find_class_named from unless RDoc::Context === from until RDoc::TopLevel === from do return nil unless from klass = from.find_class_named name return klass if klass from = from.parent end find_class_named name end ## # Finds the class or module with +name+ def find_class_or_module name name = $' if name =~ /^::/ @classes_hash[name] || @modules_hash[name] end ## # Finds the file with +name+ in all discovered files def find_file_named name @files_hash[name] end ## # Finds the module with +name+ in all discovered modules def find_module_named name @modules_hash[name] end ## # Returns the RDoc::TopLevel that is a text file and has the given # +file_name+ def find_text_page file_name @text_files_hash.each_value.find do |file| file.full_name == file_name end end ## # Finds unique classes/modules defined in +all_hash+, # and returns them as an array. Performs the alias # updates in +all_hash+: see ::complete. #-- # TODO aliases should be registered by Context#add_module_alias def find_unique all_hash unique = [] all_hash.each_pair do |full_name, cm| unique << cm if full_name == cm.full_name end unique end ## # Fixes the erroneous BasicObject < Object in 1.9. # # Because we assumed all classes without a stated superclass # inherit from Object, we have the above wrong inheritance. # # We fix BasicObject right away if we are running in a Ruby # version >= 1.9. def fix_basic_object_inheritance basic = classes_hash['BasicObject'] return unless basic basic.superclass = nil end ## # Friendly rendition of #path def friendly_path case type when :gem then parent = File.expand_path '..', @path "gem #{File.basename parent}" when :home then '~/.rdoc' when :site then 'ruby site' when :system then 'ruby core' else @path end end def inspect # :nodoc: "#<%s:0x%x %s %p>" % [self.class, object_id, @path, module_names.sort] end ## # Instance methods cache accessor. Maps a class to an Array of its # instance methods (not full name). def instance_methods @cache[:instance_methods] end ## # Loads all items from this store into memory. This recreates a # documentation tree for use by a generator def load_all load_cache module_names.each do |module_name| mod = find_class_or_module(module_name) || load_class(module_name) # load method documentation since the loaded class/module does not have # it loaded_methods = mod.method_list.map do |method| load_method module_name, method.full_name end mod.method_list.replace loaded_methods loaded_attributes = mod.attributes.map do |attribute| load_method module_name, attribute.full_name end mod.attributes.replace loaded_attributes end all_classes_and_modules.each do |mod| descendent_re = /^#{mod.full_name}::[^:]+$/ module_names.each do |name| next unless name =~ descendent_re descendent = find_class_or_module name case descendent when RDoc::NormalClass then mod.classes_hash[name] = descendent when RDoc::NormalModule then mod.modules_hash[name] = descendent end end end @cache[:pages].each do |page_name| page = load_page page_name @files_hash[page_name] = page @text_files_hash[page_name] = page if page.text? end end ## # Loads cache file for this store def load_cache #orig_enc = @encoding File.open cache_path, 'rb' do |io| @cache = Marshal.load io.read end load_enc = @cache[:encoding] # TODO this feature will be time-consuming to add: # a) Encodings may be incompatible but transcodeable # b) Need to warn in the appropriate spots, wherever they may be # c) Need to handle cross-cache differences in encodings # d) Need to warn when generating into a cache with different encodings # #if orig_enc and load_enc != orig_enc then # warn "Cached encoding #{load_enc} is incompatible with #{orig_enc}\n" \ # "from #{path}/cache.ri" unless # Encoding.compatible? orig_enc, load_enc #end @encoding = load_enc unless @encoding @cache[:pages] ||= [] @cache[:main] ||= nil @cache[:c_class_variables] ||= {} @cache[:c_singleton_class_variables] ||= {} @cache[:c_class_variables].each do |_, map| map.each do |variable, name| @c_enclosure_names[variable] = name end end @cache rescue Errno::ENOENT end ## # Loads ri data for +klass_name+ and hooks it up to this store. def load_class klass_name obj = load_class_data klass_name obj.store = self case obj when RDoc::NormalClass then @classes_hash[klass_name] = obj when RDoc::SingleClass then @classes_hash[klass_name] = obj when RDoc::NormalModule then @modules_hash[klass_name] = obj end end ## # Loads ri data for +klass_name+ def load_class_data klass_name file = class_file klass_name File.open file, 'rb' do |io| Marshal.load io.read end rescue Errno::ENOENT => e error = MissingFileError.new(self, file, klass_name) error.set_backtrace e.backtrace raise error end ## # Loads ri data for +method_name+ in +klass_name+ def load_method klass_name, method_name file = method_file klass_name, method_name File.open file, 'rb' do |io| obj = Marshal.load io.read obj.store = self obj.parent = find_class_or_module(klass_name) || load_class(klass_name) unless obj.parent obj end rescue Errno::ENOENT => e error = MissingFileError.new(self, file, klass_name + method_name) error.set_backtrace e.backtrace raise error end ## # Loads ri data for +page_name+ def load_page page_name file = page_file page_name File.open file, 'rb' do |io| obj = Marshal.load io.read obj.store = self obj end rescue Errno::ENOENT => e error = MissingFileError.new(self, file, page_name) error.set_backtrace e.backtrace raise error end ## # Gets the main page for this RDoc store. This page is used as the root of # the RDoc server. def main @cache[:main] end ## # Sets the main page for this RDoc store. def main= page @cache[:main] = page end ## # Converts the variable => ClassModule map +variables+ from a C parser into # a variable => class name map. def make_variable_map variables map = {} variables.each { |variable, class_module| map[variable] = class_module.full_name } map end ## # Path to the ri data for +method_name+ in +klass_name+ def method_file klass_name, method_name method_name = method_name.split('::').last method_name =~ /#(.*)/ method_type = $1 ? 'i' : 'c' method_name = $1 if $1 method_name = method_name.gsub(/\W/) { "%%%02x" % $&[0].ord } File.join class_path(klass_name), "#{method_name}-#{method_type}.ri" end ## # Modules cache accessor. An Array of all the module (and class) names in # the store. def module_names @cache[:modules] end ## # Hash of all modules known to RDoc def modules_hash @modules_hash end ## # Returns the RDoc::TopLevel that is a text file and has the given +name+ def page name @text_files_hash.each_value.find do |file| file.page_name == name end end ## # Path to the ri data for +page_name+ def page_file page_name file_name = File.basename(page_name).gsub('.', '_') File.join @path, File.dirname(page_name), "page-#{file_name}.ri" end ## # Removes from +all_hash+ the contexts that are nodoc or have no content. # # See RDoc::Context#remove_from_documentation? def remove_nodoc all_hash all_hash.keys.each do |name| context = all_hash[name] all_hash.delete(name) if context.remove_from_documentation? end end ## # Saves all entries in the store def save load_cache all_classes_and_modules.each do |klass| save_class klass klass.each_method do |method| save_method klass, method end klass.each_attribute do |attribute| save_method klass, attribute end end all_files.each do |file| save_page file end save_cache end ## # Writes the cache file for this store def save_cache clean_cache_collection @cache[:ancestors] clean_cache_collection @cache[:attributes] clean_cache_collection @cache[:class_methods] clean_cache_collection @cache[:instance_methods] @cache[:modules].uniq! @cache[:modules].sort! @cache[:pages].uniq! @cache[:pages].sort! @cache[:encoding] = @encoding # this gets set twice due to assert_cache @cache[:c_class_variables].merge! @c_class_variables @cache[:c_singleton_class_variables].merge! @c_singleton_class_variables return if @dry_run File.open cache_path, 'wb' do |io| Marshal.dump @cache, io end end ## # Writes the ri data for +klass+ (or module) def save_class klass full_name = klass.full_name FileUtils.mkdir_p class_path(full_name) unless @dry_run @cache[:modules] << full_name path = class_file full_name begin disk_klass = load_class full_name klass = disk_klass.merge klass rescue MissingFileError end # BasicObject has no ancestors ancestors = klass.direct_ancestors.compact.map do |ancestor| # HACK for classes we don't know about (class X < RuntimeError) String === ancestor ? ancestor : ancestor.full_name end @cache[:ancestors][full_name] ||= [] @cache[:ancestors][full_name].concat ancestors attribute_definitions = klass.attributes.map do |attribute| "#{attribute.definition} #{attribute.name}" end unless attribute_definitions.empty? then @cache[:attributes][full_name] ||= [] @cache[:attributes][full_name].concat attribute_definitions end to_delete = [] unless klass.method_list.empty? then @cache[:class_methods][full_name] ||= [] @cache[:instance_methods][full_name] ||= [] class_methods, instance_methods = klass.method_list.partition { |meth| meth.singleton } class_methods = class_methods. map { |method| method.name } instance_methods = instance_methods.map { |method| method.name } attribute_names = klass.attributes.map { |attr| attr.name } old = @cache[:class_methods][full_name] - class_methods to_delete.concat old.map { |method| method_file full_name, "#{full_name}::#{method}" } old = @cache[:instance_methods][full_name] - instance_methods - attribute_names to_delete.concat old.map { |method| method_file full_name, "#{full_name}##{method}" } @cache[:class_methods][full_name] = class_methods @cache[:instance_methods][full_name] = instance_methods end return if @dry_run FileUtils.rm_f to_delete File.open path, 'wb' do |io| Marshal.dump klass, io end end ## # Writes the ri data for +method+ on +klass+ def save_method klass, method full_name = klass.full_name FileUtils.mkdir_p class_path(full_name) unless @dry_run cache = if method.singleton then @cache[:class_methods] else @cache[:instance_methods] end cache[full_name] ||= [] cache[full_name] << method.name return if @dry_run File.open method_file(full_name, method.full_name), 'wb' do |io| Marshal.dump method, io end end ## # Writes the ri data for +page+ def save_page page return unless page.text? path = page_file page.full_name FileUtils.mkdir_p File.dirname(path) unless @dry_run cache[:pages] ||= [] cache[:pages] << page.full_name return if @dry_run File.open path, 'wb' do |io| Marshal.dump page, io end end ## # Source of the contents of this store. # # For a store from a gem the source is the gem name. For a store from the # home directory the source is "home". For system ri store (the standard # library documentation) the source is"ruby". For a store from the site # ri directory the store is "site". For other stores the source is the # #path. def source case type when :gem then File.basename File.expand_path '..', @path when :home then 'home' when :site then 'site' when :system then 'ruby' else @path end end ## # Gets the title for this RDoc store. This is used as the title in each # page on the RDoc server def title @cache[:title] end ## # Sets the title page for this RDoc store. def title= title @cache[:title] = title end ## # Returns the unique classes discovered by RDoc. # # ::complete must have been called prior to using this method. def unique_classes @unique_classes end ## # Returns the unique classes and modules discovered by RDoc. # ::complete must have been called prior to using this method. def unique_classes_and_modules @unique_classes + @unique_modules end ## # Returns the unique modules discovered by RDoc. # ::complete must have been called prior to using this method. def unique_modules @unique_modules end end PKu]]"rdoc-6.2.1.1/lib/rdoc/rd/inline.rbnu[# frozen_string_literal: true ## # Inline keeps track of markup and labels to create proper links. class RDoc::RD::Inline ## # The text of the reference attr_reader :reference ## # The markup of this reference in RDoc format attr_reader :rdoc ## # Creates a new Inline for +rdoc+ and +reference+. # # +rdoc+ may be another Inline or a String. If +reference+ is not given it # will use the text from +rdoc+. def self.new rdoc, reference = rdoc if self === rdoc and reference.equal? rdoc then rdoc else super end end ## # Initializes the Inline with +rdoc+ and +inline+ def initialize rdoc, reference # :not-new: @reference = reference.equal?(rdoc) ? reference.dup : reference # unpack @reference = @reference.reference if self.class === @reference @rdoc = rdoc end def == other # :nodoc: self.class === other and @reference == other.reference and @rdoc == other.rdoc end ## # Appends +more+ to this inline. +more+ may be a String or another Inline. def append more case more when String then @reference += more @rdoc += more when RDoc::RD::Inline then @reference += more.reference @rdoc += more.rdoc else raise "unknown thingy #{more}" end self end def inspect # :nodoc: "(inline: #{self})" end alias to_s rdoc # :nodoc: end PKu]kXX(rdoc-6.2.1.1/lib/rdoc/rd/block_parser.rbnu[# frozen_string_literal: true # # DO NOT MODIFY!!!! # This file is automatically generated by Racc 1.4.16 # from Racc grammar file "". # require 'racc/parser.rb' class RDoc::RD ## # RD format parser for headings, paragraphs, lists, verbatim sections that # exist as blocks. class BlockParser < Racc::Parser # :stopdoc: TMPFILE = ["rdtmp", $$, 0] MARK_TO_LEVEL = { '=' => 1, '==' => 2, '===' => 3, '====' => 4, '+' => 5, '++' => 6, } # :startdoc: ## # Footnotes for this document attr_reader :footnotes ## # Labels for items in this document attr_reader :labels ## # Path to find included files in attr_accessor :include_path ## # Creates a new RDoc::RD::BlockParser. Use #parse to parse an rd-format # document. def initialize @inline_parser = RDoc::RD::InlineParser.new self @include_path = [] # for testing @footnotes = [] @labels = {} end ## # Parses +src+ and returns an RDoc::Markup::Document. def parse src @src = src @src.push false @footnotes = [] @labels = {} # @i: index(line no.) of src @i = 0 # stack for current indentation @indent_stack = [] # how indented. @current_indent = @indent_stack.join("") # RDoc::RD::BlockParser for tmp src @subparser = nil # which part is in now @in_part = nil @part_content = [] @in_verbatim = false @yydebug = true document = do_parse unless @footnotes.empty? then blankline = document.parts.pop document.parts << RDoc::Markup::Rule.new(1) document.parts.concat @footnotes document.parts.push blankline end document end ## # Returns the next token from the document def next_token # :nodoc: # preprocessing # if it is not in RD part # => method while @in_part != "rd" line = @src[@i] @i += 1 # next line case line # src end when false return [false, false] # RD part begin when /^=begin\s*(?:\bRD\b.*)?\s*$/ if @in_part # if in non-RD part @part_content.push(line) else @in_part = "rd" return [:WHITELINE, "=begin\n"] # <= for textblockand end # non-RD part begin when /^=begin\s+(\w+)/ part = $1 if @in_part # if in non-RD part @part_content.push(line) else @in_part = part if @tree.filter[part] # if filter exists # p "BEGIN_PART: #{@in_part}" # DEBUG end # non-RD part end when /^=end/ if @in_part # if in non-RD part # p "END_PART: #{@in_part}" # DEBUG # make Part-in object part = RDoc::RD::Part.new(@part_content.join(""), @tree, "r") @part_content.clear # call filter, part_out is output(Part object) part_out = @tree.filter[@in_part].call(part) if @tree.filter[@in_part].mode == :rd # if output is RD formatted subtree = parse_subtree(part_out.to_a) else # if output is target formatted basename = TMPFILE.join('.') TMPFILE[-1] += 1 tmpfile = open(@tree.tmp_dir + "/" + basename + ".#{@in_part}", "w") tmpfile.print(part_out) tmpfile.close subtree = parse_subtree(["=begin\n", "<<< #{basename}\n", "=end\n"]) end @in_part = nil return [:SUBTREE, subtree] end else if @in_part # if in non-RD part @part_content.push(line) end end end @current_indent = @indent_stack.join("") line = @src[@i] case line when false if_current_indent_equal("") do [false, false] end when /^=end/ if_current_indent_equal("") do @in_part = nil [:WHITELINE, "=end"] # MUST CHANGE?? end when /^\s*$/ @i += 1 # next line return [:WHITELINE, ':WHITELINE'] when /^\#/ # comment line @i += 1 # next line self.next_token() when /^(={1,4})(?!=)\s*(?=\S)/, /^(\+{1,2})(?!\+)\s*(?=\S)/ rest = $' # ' rest.strip! mark = $1 if_current_indent_equal("") do return [:HEADLINE, [MARK_TO_LEVEL[mark], rest]] end when /^<<<\s*(\S+)/ file = $1 if_current_indent_equal("") do suffix = file[-3 .. -1] if suffix == ".rd" or suffix == ".rb" subtree = parse_subtree(get_included(file)) [:SUBTREE, subtree] else [:INCLUDE, file] end end when /^(\s*)\*(\s*)/ rest = $' # ' newIndent = $2 if_current_indent_equal($1) do if @in_verbatim [:STRINGLINE, line] else @indent_stack.push("\s" + newIndent) [:ITEMLISTLINE, rest] end end when /^(\s*)(\(\d+\))(\s*)/ rest = $' # ' mark = $2 newIndent = $3 if_current_indent_equal($1) do if @in_verbatim [:STRINGLINE, line] else @indent_stack.push("\s" * mark.size + newIndent) [:ENUMLISTLINE, rest] end end when /^(\s*):(\s*)/ rest = $' # ' newIndent = $2 if_current_indent_equal($1) do if @in_verbatim [:STRINGLINE, line] else @indent_stack.push("\s#{$2}") [:DESCLISTLINE, rest] end end when /^(\s*)---(?!-|\s*$)/ indent = $1 rest = $' /\s*/ === rest term = $' new_indent = $& if_current_indent_equal(indent) do if @in_verbatim [:STRINGLINE, line] else @indent_stack.push("\s\s\s" + new_indent) [:METHODLISTLINE, term] end end when /^(\s*)/ if_current_indent_equal($1) do [:STRINGLINE, line] end else raise "[BUG] parsing error may occurred." end end ## # Yields to the given block if +indent+ matches the current indent, otherwise # an indentation token is processed. def if_current_indent_equal(indent) indent = indent.sub(/\t/, "\s" * 8) if @current_indent == indent @i += 1 # next line yield elsif indent.index(@current_indent) == 0 @indent_stack.push(indent[@current_indent.size .. -1]) [:INDENT, ":INDENT"] else @indent_stack.pop [:DEDENT, ":DEDENT"] end end private :if_current_indent_equal ## # Cuts off excess whitespace in +src+ def cut_off(src) ret = [] whiteline_buf = [] line = src.shift /^\s*/ =~ line indent = Regexp.quote($&) ret.push($') while line = src.shift if /^(\s*)$/ =~ line whiteline_buf.push(line) elsif /^#{indent}/ =~ line unless whiteline_buf.empty? ret.concat(whiteline_buf) whiteline_buf.clear end ret.push($') else raise "[BUG]: probably Parser Error while cutting off.\n" end end ret end private :cut_off def set_term_to_element(parent, term) # parent.set_term_under_document_struct(term, @tree.document_struct) parent.set_term_without_document_struct(term) end private :set_term_to_element ## # Raises a ParseError when invalid formatting is found def on_error(et, ev, _values) prv, cur, nxt = format_line_num(@i, @i+1, @i+2) raise ParseError, <|#{@src[@i].chomp} #{nxt} |#{@src[@i+1].chomp} Msg end ## # Current line number def line_index @i end ## # Parses subtree +src+ def parse_subtree src @subparser ||= RDoc::RD::BlockParser.new @subparser.parse src end private :parse_subtree ## # Retrieves the content for +file+ from the include_path def get_included(file) included = [] @include_path.each do |dir| file_name = File.join dir, file if File.exist? file_name then included = IO.readlines file_name break end end included end private :get_included ## # Formats line numbers +line_numbers+ prettily def format_line_num(*line_numbers) width = line_numbers.collect{|i| i.to_s.length }.max line_numbers.collect{|i| sprintf("%#{width}d", i) } end private :format_line_num ## # Retrieves the content of +values+ as a single String def content values values.map { |value| value.content }.join end ## # Creates a paragraph for +value+ def paragraph value content = cut_off(value).join(' ').rstrip contents = @inline_parser.parse content RDoc::Markup::Paragraph.new(*contents) end ## # Adds footnote +content+ to the document def add_footnote content index = @footnotes.length / 2 + 1 footmark_link = "{^#{index}}[rdoc-label:footmark-#{index}:foottext-#{index}]" @footnotes << RDoc::Markup::Paragraph.new(footmark_link, ' ', *content) @footnotes << RDoc::Markup::BlankLine.new index end ## # Adds label +label+ to the document def add_label label @labels[label] = true label end # :stopdoc: ##### State transition tables begin ### racc_action_table = [ 34, 35, 30, 33, 40, 34, 35, 30, 33, 40, 65, 34, 35, 30, 33, 14, 73, 36, 38, 34, 15, 88, 34, 35, 30, 33, 14, 9, 10, 11, 12, 15, 34, 35, 30, 33, 14, 9, 10, 11, 12, 15, 34, 35, 30, 33, 35, 47, 30, 54, 33, 15, 34, 35, 30, 33, 54, 47, 14, 14, 59, 15, 34, 35, 30, 33, 14, 73, 67, 76, 77, 15, 34, 35, 30, 33, 14, 73, 54, 81, 38, 15, 34, 35, 30, 33, 14, 73, 38, 40, 83, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, nil, 15, 34, 35, 30, 33, 14, 73, 61, 63, nil, 15, 14, 62, 60, 61, 63, 79, 61, 63, 62, 87, nil, 62, 34, 35, 30, 33 ] racc_action_check = [ 41, 41, 41, 41, 41, 15, 15, 15, 15, 15, 41, 86, 86, 86, 86, 86, 86, 1, 13, 22, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 24, 24, 24, 24, 25, 24, 28, 30, 31, 24, 27, 27, 27, 27, 33, 27, 34, 35, 36, 27, 45, 45, 45, 45, 45, 45, 44, 49, 51, 45, 46, 46, 46, 46, 46, 46, 54, 56, 57, 46, 47, 47, 47, 47, 47, 47, 58, 62, 66, 47, 68, 68, 68, 68, 68, 68, nil, nil, nil, 68, 74, 74, 74, 74, 74, 74, nil, nil, nil, 74, 75, 75, 75, 75, 75, 75, nil, nil, nil, 75, 78, 78, 78, 78, 78, 78, nil, nil, nil, 78, 79, 79, 79, 79, 79, 79, nil, nil, nil, 79, 85, 85, 85, 85, 85, 85, 39, 39, nil, 85, 52, 39, 39, 82, 82, 52, 64, 64, 82, 82, nil, 64, 20, 20, 20, 20 ] racc_action_pointer = [ 19, 17, 29, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 11, nil, 2, nil, nil, nil, nil, 161, nil, 16, nil, 39, 42, nil, 49, 43, nil, 41, 44, nil, 48, 51, 52, 60, nil, nil, 141, nil, -3, nil, nil, 55, 59, 69, 79, nil, 56, nil, 57, 145, nil, 70, nil, 66, 73, 81, nil, nil, nil, 82, nil, 151, nil, 77, nil, 89, nil, nil, nil, nil, nil, 99, 109, nil, nil, 119, 129, nil, nil, 148, nil, nil, 139, 8, nil, nil ] racc_action_default = [ -2, -73, -1, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -16, -73, -23, -24, -25, -26, -27, -31, -32, -34, -72, -36, -38, -72, -40, -42, -59, -44, -46, -59, -63, -65, -73, -3, -15, -73, -22, -73, -30, -33, -73, -69, -70, -71, -37, -73, -41, -73, -51, -58, -61, -45, -73, -62, -64, 89, -17, -19, -73, -21, -18, -28, -73, -35, -66, -53, -54, -55, -56, -57, -67, -68, -39, -43, -49, -73, -60, -47, -73, -29, -52, -48, -73, -20, -50 ] racc_goto_table = [ 4, 39, 4, 68, 74, 75, 5, 6, 5, 6, 44, 42, 51, 49, 3, 56, 37, 57, 58, 1, 2, 66, 84, 41, 43, 48, 50, 64, 84, 84, 45, 46, 42, 45, 46, 55, 85, 86, 80, 84, 84, nil, nil, nil, nil, nil, nil, nil, 82, nil, nil, nil, 78 ] racc_goto_check = [ 4, 10, 4, 31, 31, 31, 5, 6, 5, 6, 21, 12, 27, 21, 3, 27, 3, 9, 9, 1, 2, 11, 32, 17, 19, 23, 26, 10, 32, 32, 5, 6, 12, 5, 6, 29, 31, 31, 33, 32, 32, nil, nil, nil, nil, nil, nil, nil, 10, nil, nil, nil, 4 ] racc_goto_pointer = [ nil, 19, 20, 14, 0, 6, 7, nil, nil, -17, -14, -20, -9, nil, nil, nil, nil, 8, nil, 2, nil, -14, nil, 0, nil, nil, -2, -18, nil, 4, nil, -42, -46, -16 ] racc_goto_default = [ nil, nil, nil, nil, 70, 71, 72, 7, 8, 13, nil, nil, 21, 16, 17, 18, 19, 20, 22, 23, 24, nil, 25, 26, 27, 28, 29, nil, 31, 32, 52, nil, 69, 53 ] racc_reduce_table = [ 0, 0, :racc_error, 1, 15, :_reduce_1, 0, 15, :_reduce_2, 2, 16, :_reduce_3, 1, 16, :_reduce_4, 1, 17, :_reduce_5, 1, 17, :_reduce_6, 1, 17, :_reduce_none, 1, 17, :_reduce_8, 1, 17, :_reduce_9, 1, 17, :_reduce_10, 1, 17, :_reduce_11, 1, 21, :_reduce_12, 1, 22, :_reduce_13, 1, 18, :_reduce_14, 2, 23, :_reduce_15, 1, 23, :_reduce_16, 3, 19, :_reduce_17, 1, 25, :_reduce_18, 2, 24, :_reduce_19, 4, 24, :_reduce_20, 2, 24, :_reduce_21, 1, 24, :_reduce_22, 1, 26, :_reduce_none, 1, 26, :_reduce_none, 1, 26, :_reduce_none, 1, 26, :_reduce_none, 1, 20, :_reduce_27, 3, 20, :_reduce_28, 4, 20, :_reduce_29, 2, 31, :_reduce_30, 1, 31, :_reduce_31, 1, 27, :_reduce_32, 2, 32, :_reduce_33, 1, 32, :_reduce_34, 3, 33, :_reduce_35, 1, 28, :_reduce_36, 2, 36, :_reduce_37, 1, 36, :_reduce_38, 3, 37, :_reduce_39, 1, 29, :_reduce_40, 2, 39, :_reduce_41, 1, 39, :_reduce_42, 3, 40, :_reduce_43, 1, 30, :_reduce_44, 2, 42, :_reduce_45, 1, 42, :_reduce_46, 3, 43, :_reduce_47, 3, 41, :_reduce_48, 2, 41, :_reduce_49, 4, 41, :_reduce_50, 1, 41, :_reduce_51, 2, 45, :_reduce_52, 1, 45, :_reduce_none, 1, 46, :_reduce_54, 1, 46, :_reduce_55, 1, 46, :_reduce_none, 1, 46, :_reduce_57, 1, 44, :_reduce_none, 0, 44, :_reduce_none, 2, 47, :_reduce_none, 1, 47, :_reduce_none, 2, 34, :_reduce_62, 1, 34, :_reduce_63, 2, 38, :_reduce_64, 1, 38, :_reduce_65, 2, 35, :_reduce_66, 2, 35, :_reduce_67, 2, 35, :_reduce_68, 1, 35, :_reduce_69, 1, 35, :_reduce_none, 1, 35, :_reduce_71, 0, 35, :_reduce_72 ] racc_reduce_n = 73 racc_shift_n = 89 racc_token_table = { false => 0, :error => 1, :DUMMY => 2, :ITEMLISTLINE => 3, :ENUMLISTLINE => 4, :DESCLISTLINE => 5, :METHODLISTLINE => 6, :STRINGLINE => 7, :WHITELINE => 8, :SUBTREE => 9, :HEADLINE => 10, :INCLUDE => 11, :INDENT => 12, :DEDENT => 13 } racc_nt_base = 14 racc_use_result_var = true Racc_arg = [ racc_action_table, racc_action_check, racc_action_default, racc_action_pointer, racc_goto_table, racc_goto_check, racc_goto_default, racc_goto_pointer, racc_nt_base, racc_reduce_table, racc_token_table, racc_shift_n, racc_reduce_n, racc_use_result_var ] Racc_token_to_s_table = [ "$end", "error", "DUMMY", "ITEMLISTLINE", "ENUMLISTLINE", "DESCLISTLINE", "METHODLISTLINE", "STRINGLINE", "WHITELINE", "SUBTREE", "HEADLINE", "INCLUDE", "INDENT", "DEDENT", "$start", "document", "blocks", "block", "textblock", "verbatim", "lists", "headline", "include", "textblockcontent", "verbatimcontent", "verbatim_after_lists", "list", "itemlist", "enumlist", "desclist", "methodlist", "lists2", "itemlistitems", "itemlistitem", "first_textblock_in_itemlist", "other_blocks_in_list", "enumlistitems", "enumlistitem", "first_textblock_in_enumlist", "desclistitems", "desclistitem", "description_part", "methodlistitems", "methodlistitem", "whitelines", "blocks_in_list", "block_in_list", "whitelines2" ] Racc_debug_parser = false ##### State transition tables end ##### # reduce 0 omitted def _reduce_1(val, _values, result) result = RDoc::Markup::Document.new(*val[0]) result end def _reduce_2(val, _values, result) raise ParseError, "file empty" result end def _reduce_3(val, _values, result) result = val[0].concat val[1] result end def _reduce_4(val, _values, result) result = val[0] result end def _reduce_5(val, _values, result) result = val result end def _reduce_6(val, _values, result) result = val result end # reduce 7 omitted def _reduce_8(val, _values, result) result = val result end def _reduce_9(val, _values, result) result = val result end def _reduce_10(val, _values, result) result = [RDoc::Markup::BlankLine.new] result end def _reduce_11(val, _values, result) result = val[0].parts result end def _reduce_12(val, _values, result) # val[0] is like [level, title] title = @inline_parser.parse(val[0][1]) result = RDoc::Markup::Heading.new(val[0][0], title) result end def _reduce_13(val, _values, result) result = RDoc::Markup::Include.new val[0], @include_path result end def _reduce_14(val, _values, result) # val[0] is Array of String result = paragraph val[0] result end def _reduce_15(val, _values, result) result << val[1].rstrip result end def _reduce_16(val, _values, result) result = [val[0].rstrip] result end def _reduce_17(val, _values, result) # val[1] is Array of String content = cut_off val[1] result = RDoc::Markup::Verbatim.new(*content) # imform to lexer. @in_verbatim = false result end def _reduce_18(val, _values, result) # val[0] is Array of String content = cut_off val[0] result = RDoc::Markup::Verbatim.new(*content) # imform to lexer. @in_verbatim = false result end def _reduce_19(val, _values, result) result << val[1] result end def _reduce_20(val, _values, result) result.concat val[2] result end def _reduce_21(val, _values, result) result << "\n" result end def _reduce_22(val, _values, result) result = val # inform to lexer. @in_verbatim = true result end # reduce 23 omitted # reduce 24 omitted # reduce 25 omitted # reduce 26 omitted def _reduce_27(val, _values, result) result = val[0] result end def _reduce_28(val, _values, result) result = val[1] result end def _reduce_29(val, _values, result) result = val[1].push(val[2]) result end def _reduce_30(val, _values, result) result = val[0] << val[1] result end def _reduce_31(val, _values, result) result = [val[0]] result end def _reduce_32(val, _values, result) result = RDoc::Markup::List.new :BULLET, *val[0] result end def _reduce_33(val, _values, result) result.push(val[1]) result end def _reduce_34(val, _values, result) result = val result end def _reduce_35(val, _values, result) result = RDoc::Markup::ListItem.new nil, val[0], *val[1] result end def _reduce_36(val, _values, result) result = RDoc::Markup::List.new :NUMBER, *val[0] result end def _reduce_37(val, _values, result) result.push(val[1]) result end def _reduce_38(val, _values, result) result = val result end def _reduce_39(val, _values, result) result = RDoc::Markup::ListItem.new nil, val[0], *val[1] result end def _reduce_40(val, _values, result) result = RDoc::Markup::List.new :NOTE, *val[0] result end def _reduce_41(val, _values, result) result.push(val[1]) result end def _reduce_42(val, _values, result) result = val result end def _reduce_43(val, _values, result) term = @inline_parser.parse val[0].strip result = RDoc::Markup::ListItem.new term, *val[1] result end def _reduce_44(val, _values, result) result = RDoc::Markup::List.new :LABEL, *val[0] result end def _reduce_45(val, _values, result) result.push(val[1]) result end def _reduce_46(val, _values, result) result = val result end def _reduce_47(val, _values, result) result = RDoc::Markup::ListItem.new "#{val[0].strip}", *val[1] result end def _reduce_48(val, _values, result) result = [val[1]].concat(val[2]) result end def _reduce_49(val, _values, result) result = [val[1]] result end def _reduce_50(val, _values, result) result = val[2] result end def _reduce_51(val, _values, result) result = [] result end def _reduce_52(val, _values, result) result.concat val[1] result end # reduce 53 omitted def _reduce_54(val, _values, result) result = val result end def _reduce_55(val, _values, result) result = val result end # reduce 56 omitted def _reduce_57(val, _values, result) result = [] result end # reduce 58 omitted # reduce 59 omitted # reduce 60 omitted # reduce 61 omitted def _reduce_62(val, _values, result) result = paragraph [val[0]].concat(val[1]) result end def _reduce_63(val, _values, result) result = paragraph [val[0]] result end def _reduce_64(val, _values, result) result = paragraph [val[0]].concat(val[1]) result end def _reduce_65(val, _values, result) result = paragraph [val[0]] result end def _reduce_66(val, _values, result) result = [val[0]].concat(val[1]) result end def _reduce_67(val, _values, result) result.concat val[1] result end def _reduce_68(val, _values, result) result = val[1] result end def _reduce_69(val, _values, result) result = val result end # reduce 70 omitted def _reduce_71(val, _values, result) result = [] result end def _reduce_72(val, _values, result) result = [] result end def _reduce_none(val, _values, result) val[0] end end # class BlockParser end PKu]M<}})rdoc-6.2.1.1/lib/rdoc/rd/inline_parser.rbnu[# frozen_string_literal: true # # DO NOT MODIFY!!!! # This file is automatically generated by Racc 1.4.16 # from Racc grammar file "". # require 'racc/parser.rb' require 'strscan' class RDoc::RD ## # RD format parser for inline markup such as emphasis, links, footnotes, etc. class InlineParser < Racc::Parser # :stopdoc: EM_OPEN = '((*' EM_OPEN_RE = /\A#{Regexp.quote(EM_OPEN)}/ EM_CLOSE = '*))' EM_CLOSE_RE = /\A#{Regexp.quote(EM_CLOSE)}/ CODE_OPEN = '(({' CODE_OPEN_RE = /\A#{Regexp.quote(CODE_OPEN)}/ CODE_CLOSE = '}))' CODE_CLOSE_RE = /\A#{Regexp.quote(CODE_CLOSE)}/ VAR_OPEN = '((|' VAR_OPEN_RE = /\A#{Regexp.quote(VAR_OPEN)}/ VAR_CLOSE = '|))' VAR_CLOSE_RE = /\A#{Regexp.quote(VAR_CLOSE)}/ KBD_OPEN = '((%' KBD_OPEN_RE = /\A#{Regexp.quote(KBD_OPEN)}/ KBD_CLOSE = '%))' KBD_CLOSE_RE = /\A#{Regexp.quote(KBD_CLOSE)}/ INDEX_OPEN = '((:' INDEX_OPEN_RE = /\A#{Regexp.quote(INDEX_OPEN)}/ INDEX_CLOSE = ':))' INDEX_CLOSE_RE = /\A#{Regexp.quote(INDEX_CLOSE)}/ REF_OPEN = '((<' REF_OPEN_RE = /\A#{Regexp.quote(REF_OPEN)}/ REF_CLOSE = '>))' REF_CLOSE_RE = /\A#{Regexp.quote(REF_CLOSE)}/ FOOTNOTE_OPEN = '((-' FOOTNOTE_OPEN_RE = /\A#{Regexp.quote(FOOTNOTE_OPEN)}/ FOOTNOTE_CLOSE = '-))' FOOTNOTE_CLOSE_RE = /\A#{Regexp.quote(FOOTNOTE_CLOSE)}/ VERB_OPEN = "(('" VERB_OPEN_RE = /\A#{Regexp.quote(VERB_OPEN)}/ VERB_CLOSE = "'))" VERB_CLOSE_RE = /\A#{Regexp.quote(VERB_CLOSE)}/ BAR = "|" BAR_RE = /\A#{Regexp.quote(BAR)}/ QUOTE = '"' QUOTE_RE = /\A#{Regexp.quote(QUOTE)}/ SLASH = "/" SLASH_RE = /\A#{Regexp.quote(SLASH)}/ BACK_SLASH = "\\" BACK_SLASH_RE = /\A#{Regexp.quote(BACK_SLASH)}/ URL = "URL:" URL_RE = /\A#{Regexp.quote(URL)}/ other_re_mode = Regexp::EXTENDED other_re_mode |= Regexp::MULTILINE OTHER_RE = Regexp.new( "\\A.+?(?=#{Regexp.quote(EM_OPEN)}|#{Regexp.quote(EM_CLOSE)}| #{Regexp.quote(CODE_OPEN)}|#{Regexp.quote(CODE_CLOSE)}| #{Regexp.quote(VAR_OPEN)}|#{Regexp.quote(VAR_CLOSE)}| #{Regexp.quote(KBD_OPEN)}|#{Regexp.quote(KBD_CLOSE)}| #{Regexp.quote(INDEX_OPEN)}|#{Regexp.quote(INDEX_CLOSE)}| #{Regexp.quote(REF_OPEN)}|#{Regexp.quote(REF_CLOSE)}| #{Regexp.quote(FOOTNOTE_OPEN)}|#{Regexp.quote(FOOTNOTE_CLOSE)}| #{Regexp.quote(VERB_OPEN)}|#{Regexp.quote(VERB_CLOSE)}| #{Regexp.quote(BAR)}| #{Regexp.quote(QUOTE)}| #{Regexp.quote(SLASH)}| #{Regexp.quote(BACK_SLASH)}| #{Regexp.quote(URL)})", other_re_mode) # :startdoc: ## # Creates a new parser for inline markup in the rd format. The +block_parser+ # is used to for footnotes and labels in the inline text. def initialize block_parser @block_parser = block_parser end ## # Parses the +inline+ text from RD format into RDoc format. def parse inline @inline = inline @src = StringScanner.new inline @pre = "".dup @yydebug = true do_parse.to_s end ## # Returns the next token from the inline text def next_token return [false, false] if @src.eos? # p @src.rest if @yydebug if ret = @src.scan(EM_OPEN_RE) @pre << ret [:EM_OPEN, ret] elsif ret = @src.scan(EM_CLOSE_RE) @pre << ret [:EM_CLOSE, ret] elsif ret = @src.scan(CODE_OPEN_RE) @pre << ret [:CODE_OPEN, ret] elsif ret = @src.scan(CODE_CLOSE_RE) @pre << ret [:CODE_CLOSE, ret] elsif ret = @src.scan(VAR_OPEN_RE) @pre << ret [:VAR_OPEN, ret] elsif ret = @src.scan(VAR_CLOSE_RE) @pre << ret [:VAR_CLOSE, ret] elsif ret = @src.scan(KBD_OPEN_RE) @pre << ret [:KBD_OPEN, ret] elsif ret = @src.scan(KBD_CLOSE_RE) @pre << ret [:KBD_CLOSE, ret] elsif ret = @src.scan(INDEX_OPEN_RE) @pre << ret [:INDEX_OPEN, ret] elsif ret = @src.scan(INDEX_CLOSE_RE) @pre << ret [:INDEX_CLOSE, ret] elsif ret = @src.scan(REF_OPEN_RE) @pre << ret [:REF_OPEN, ret] elsif ret = @src.scan(REF_CLOSE_RE) @pre << ret [:REF_CLOSE, ret] elsif ret = @src.scan(FOOTNOTE_OPEN_RE) @pre << ret [:FOOTNOTE_OPEN, ret] elsif ret = @src.scan(FOOTNOTE_CLOSE_RE) @pre << ret [:FOOTNOTE_CLOSE, ret] elsif ret = @src.scan(VERB_OPEN_RE) @pre << ret [:VERB_OPEN, ret] elsif ret = @src.scan(VERB_CLOSE_RE) @pre << ret [:VERB_CLOSE, ret] elsif ret = @src.scan(BAR_RE) @pre << ret [:BAR, ret] elsif ret = @src.scan(QUOTE_RE) @pre << ret [:QUOTE, ret] elsif ret = @src.scan(SLASH_RE) @pre << ret [:SLASH, ret] elsif ret = @src.scan(BACK_SLASH_RE) @pre << ret [:BACK_SLASH, ret] elsif ret = @src.scan(URL_RE) @pre << ret [:URL, ret] elsif ret = @src.scan(OTHER_RE) @pre << ret [:OTHER, ret] else ret = @src.rest @pre << ret @src.terminate [:OTHER, ret] end end ## # Raises a ParseError when invalid formatting is found def on_error(et, ev, values) lines_of_rest = @src.rest.lines.to_a.length prev_words = prev_words_on_error(ev) at = 4 + prev_words.length message = <<-MSG RD syntax error: line #{@block_parser.line_index - lines_of_rest}: ...#{prev_words} #{(ev||'')} #{next_words_on_error()} ... MSG message << " " * at + "^" * (ev ? ev.length : 0) + "\n" raise ParseError, message end ## # Returns words before the error def prev_words_on_error(ev) pre = @pre if ev and /#{Regexp.quote(ev)}$/ =~ pre pre = $` end last_line(pre) end ## # Returns the last line of +src+ def last_line(src) if n = src.rindex("\n") src[(n+1) .. -1] else src end end private :last_line ## # Returns words following an error def next_words_on_error if n = @src.rest.index("\n") @src.rest[0 .. (n-1)] else @src.rest end end ## # Creates a new RDoc::RD::Inline for the +rdoc+ markup and the raw +reference+ def inline rdoc, reference = rdoc RDoc::RD::Inline.new rdoc, reference end # :stopdoc: ##### State transition tables begin ### racc_action_table = [ 104, 103, 102, 100, 101, 99, 115, 116, 117, 29, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 84, 118, 119, 63, 64, 65, 61, 81, 62, 76, 78, 79, 85, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 80, 149, 63, 64, 65, 153, 81, 62, 76, 78, 79, 86, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 80, 152, 104, 103, 102, 100, 101, 99, 115, 116, 117, 87, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 88, 118, 119, 104, 103, 102, 100, 101, 99, 115, 116, 117, 89, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 96, 118, 119, 104, 103, 102, 100, 101, 99, 115, 116, 117, 124, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 137, 118, 119, 22, 23, 24, 25, 26, 21, 18, 19, 176, 177, 13, 148, 14, 154, 15, 137, 16, 161, 17, 164, 173, 20, 22, 23, 24, 25, 26, 21, 18, 19, 175, 177, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 42, nil, 20, 54, 38, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 63, 64, 65, 61, 81, 62, 76, 78, 79, nil, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 80, 122, nil, nil, 54, nil, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 135, 136, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 135, 136, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, 135, 136, 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, 95, nil, 20, 54, 91, 53, 55, 56, 57, 145, nil, nil, 54, 133, 53, 55, 56, 57, 158, nil, nil, 54, nil, 53, 55, 56, 57, 165, 135, 136, 54, 133, 53, 55, 56, 57, 145, nil, nil, 54, 133, 53, 55, 56, 57, 172, 135, 136, 54, 133, 53, 55, 56, 57, 174, 135, 136, 54, 133, 53, 55, 56, 57, 178, 135, 136, 54, 133, 53, 55, 56, 57, 135, 136, 54, 133, 53, 55, 56, 57, 135, 136, 54, 133, 53, 55, 56, 57, 135, 136, 54, 133, 53, 55, 56, 57, 22, 23, 24, 25, 26, 21 ] racc_action_check = [ 38, 38, 38, 38, 38, 38, 38, 38, 38, 1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 29, 38, 38, 59, 59, 59, 59, 59, 59, 59, 59, 59, 31, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 61, 61, 61, 61, 61, 61, 61, 32, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 91, 91, 91, 91, 91, 91, 91, 91, 91, 33, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 34, 91, 91, 97, 97, 97, 97, 97, 97, 97, 97, 97, 35, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 37, 97, 97, 155, 155, 155, 155, 155, 155, 155, 155, 155, 41, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 43, 155, 155, 0, 0, 0, 0, 0, 0, 0, 0, 165, 165, 0, 58, 0, 90, 0, 94, 0, 100, 0, 125, 162, 0, 2, 2, 2, 2, 2, 2, 2, 2, 164, 172, 2, nil, 2, nil, 2, nil, 2, nil, 2, nil, nil, 2, 13, 13, 13, 13, 13, 13, 13, 13, nil, nil, 13, nil, 13, nil, 13, nil, 13, nil, 13, nil, nil, 13, 14, 14, 14, 14, 14, 14, 14, 14, nil, nil, 14, nil, 14, nil, 14, nil, 14, nil, 14, nil, nil, 14, 15, 15, 15, 15, 15, 15, 15, 15, nil, nil, 15, nil, 15, nil, 15, nil, 15, nil, 15, nil, nil, 15, 16, 16, 16, 16, 16, 16, 16, 16, nil, nil, 16, nil, 16, nil, 16, nil, 16, nil, 16, nil, nil, 16, 17, 17, 17, 17, 17, 17, 17, 17, nil, nil, 17, nil, 17, nil, 17, nil, 17, nil, 17, 18, nil, 17, 18, 18, 18, 18, 18, 18, nil, 18, nil, 18, nil, 18, nil, 18, nil, 18, nil, nil, 18, 19, 19, 19, 19, 19, 19, 19, 19, nil, nil, 19, nil, 19, nil, 19, nil, 19, nil, 19, nil, nil, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, nil, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 39, nil, nil, 39, nil, 39, 39, 39, 39, nil, 39, nil, 39, nil, 39, nil, 39, nil, 39, 44, nil, 39, 44, 44, 44, 44, 44, 44, nil, 44, nil, 44, nil, 44, nil, 44, nil, 44, 45, nil, 44, 45, 45, 45, 45, 45, 45, nil, 45, nil, 45, nil, 45, nil, 45, nil, 45, 138, nil, 45, 138, 138, 138, 138, 138, 138, nil, 138, nil, 138, nil, 138, nil, 138, nil, 138, 146, nil, 138, 146, 146, 146, 146, 146, 146, nil, 146, nil, 146, nil, 146, nil, 146, nil, 146, nil, nil, 146, 42, 42, 42, 42, 42, 42, 42, 42, nil, 42, nil, 42, nil, 42, nil, 42, nil, 42, nil, nil, 42, 122, 122, 122, 122, 122, 122, 122, 122, nil, 122, nil, 122, nil, 122, nil, 122, nil, 122, nil, nil, 122, 127, 127, 127, 127, 127, 127, 127, 127, nil, 127, nil, 127, nil, 127, nil, 127, nil, 127, 36, nil, 127, 36, 36, 36, 36, 36, 36, 52, nil, nil, 52, 52, 52, 52, 52, 52, 92, nil, nil, 92, nil, 92, 92, 92, 92, 126, 126, 126, 126, 126, 126, 126, 126, 126, 142, nil, nil, 142, 142, 142, 142, 142, 142, 159, 159, 159, 159, 159, 159, 159, 159, 159, 163, 163, 163, 163, 163, 163, 163, 163, 163, 171, 171, 171, 171, 171, 171, 171, 171, 171, 95, 95, 95, 95, 95, 95, 95, 95, 158, 158, 158, 158, 158, 158, 158, 158, 168, 168, 168, 168, 168, 168, 168, 168, 27, 27, 27, 27, 27, 27 ] racc_action_pointer = [ 135, 9, 157, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 179, 201, 223, 245, 267, 286, 308, 330, nil, nil, nil, nil, nil, nil, 606, nil, 20, nil, 18, 39, 60, 69, 79, 510, 89, -3, 352, nil, 120, 449, 130, 371, 390, nil, nil, nil, nil, nil, nil, 519, nil, nil, nil, nil, nil, 138, 20, nil, 43, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 128, 66, 528, nil, 148, 581, nil, 89, nil, nil, 149, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 470, nil, nil, 154, 537, 491, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 409, nil, nil, nil, 546, nil, nil, nil, 428, nil, nil, nil, nil, nil, nil, nil, nil, 112, nil, nil, 589, 555, nil, nil, 155, 564, 164, 142, nil, nil, 597, nil, nil, 573, 164, nil, nil, nil, nil, nil, nil ] racc_action_default = [ -138, -138, -1, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -138, -138, -138, -138, -138, -138, -138, -138, -103, -104, -105, -106, -107, -108, -111, -110, -138, -2, -138, -138, -138, -138, -138, -138, -138, -138, -27, -26, -35, -138, -58, -41, -40, -47, -48, -49, -50, -51, -52, -63, -66, -67, -68, -69, -70, -138, -138, -112, -138, -116, -117, -118, -119, -120, -121, -122, -123, -124, -125, -126, -127, -128, -129, -130, -131, -132, -133, -134, -135, -137, -109, 179, -13, -14, -15, -16, -17, -138, -138, -23, -22, -33, -138, -19, -24, -79, -80, -138, -82, -83, -84, -85, -86, -87, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, -100, -25, -35, -138, -58, -28, -138, -59, -42, -46, -55, -56, -65, -71, -72, -75, -76, -77, -31, -38, -44, -53, -54, -57, -61, -73, -74, -39, -62, -101, -102, -136, -113, -114, -115, -18, -20, -21, -33, -138, -138, -78, -81, -138, -59, -36, -37, -64, -45, -59, -43, -60, -138, -34, -36, -37, -29, -30, -32, -34 ] racc_goto_table = [ 126, 44, 125, 43, 144, 144, 160, 93, 97, 52, 166, 82, 144, 40, 41, 39, 138, 146, 169, 30, 36, 94, 44, 1, 123, 129, 169, 52, 90, 37, 52, 167, 147, 92, 120, 121, 31, 32, 33, 34, 35, 170, 58, 166, 59, 83, 170, 166, 151, nil, 150, nil, 166, 159, 4, 166, 4, nil, nil, nil, nil, 155, nil, 156, 160, nil, nil, 4, 4, 4, 4, 4, nil, 4, 5, nil, 5, 157, nil, nil, 163, nil, 162, 52, nil, 168, nil, 5, 5, 5, 5, 5, nil, 5, nil, nil, nil, nil, 144, nil, nil, nil, 144, nil, nil, 129, 144, 144, nil, 6, 129, 6, nil, nil, nil, nil, 171, 7, nil, 7, nil, nil, 6, 6, 6, 6, 6, 8, 6, 8, 7, 7, 7, 7, 7, 11, 7, 11, nil, nil, 8, 8, 8, 8, 8, nil, 8, nil, 11, 11, 11, 11, 11, nil, 11 ] racc_goto_check = [ 22, 24, 21, 23, 36, 36, 37, 18, 16, 34, 35, 41, 36, 19, 20, 17, 25, 25, 28, 3, 13, 23, 24, 1, 23, 24, 28, 34, 14, 15, 34, 29, 32, 17, 19, 20, 1, 1, 1, 1, 1, 33, 1, 35, 38, 39, 33, 35, 42, nil, 41, nil, 35, 22, 4, 35, 4, nil, nil, nil, nil, 16, nil, 18, 37, nil, nil, 4, 4, 4, 4, 4, nil, 4, 5, nil, 5, 23, nil, nil, 22, nil, 21, 34, nil, 22, nil, 5, 5, 5, 5, 5, nil, 5, nil, nil, nil, nil, 36, nil, nil, nil, 36, nil, nil, 24, 36, 36, nil, 6, 24, 6, nil, nil, nil, nil, 22, 7, nil, 7, nil, nil, 6, 6, 6, 6, 6, 8, 6, 8, 7, 7, 7, 7, 7, 11, 7, 11, nil, nil, 8, 8, 8, 8, 8, nil, 8, nil, 11, 11, 11, 11, 11, nil, 11 ] racc_goto_pointer = [ nil, 23, nil, 17, 54, 74, 109, 117, 127, nil, nil, 135, nil, 2, -8, 11, -30, -3, -29, -5, -4, -40, -42, -15, -17, -28, nil, nil, -120, -96, nil, nil, -20, -101, -9, -116, -40, -91, 24, 18, nil, -9, -13 ] racc_goto_default = [ nil, nil, 2, 3, 46, 47, 48, 49, 50, 9, 10, 51, 12, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 140, nil, 45, 127, 139, 128, 141, 130, 142, 143, 132, 131, 134, 98, nil, 28, 27, nil, 60 ] racc_reduce_table = [ 0, 0, :racc_error, 1, 27, :_reduce_none, 2, 28, :_reduce_2, 1, 28, :_reduce_3, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 1, 29, :_reduce_none, 3, 30, :_reduce_13, 3, 31, :_reduce_14, 3, 32, :_reduce_15, 3, 33, :_reduce_16, 3, 34, :_reduce_17, 4, 35, :_reduce_18, 3, 35, :_reduce_19, 2, 40, :_reduce_20, 2, 40, :_reduce_21, 1, 40, :_reduce_22, 1, 40, :_reduce_23, 2, 41, :_reduce_24, 2, 41, :_reduce_25, 1, 41, :_reduce_26, 1, 41, :_reduce_27, 2, 39, :_reduce_none, 4, 39, :_reduce_29, 4, 39, :_reduce_30, 2, 43, :_reduce_31, 4, 43, :_reduce_32, 1, 44, :_reduce_33, 3, 44, :_reduce_34, 1, 45, :_reduce_none, 3, 45, :_reduce_36, 3, 45, :_reduce_37, 2, 46, :_reduce_38, 2, 46, :_reduce_39, 1, 46, :_reduce_40, 1, 46, :_reduce_41, 1, 47, :_reduce_none, 2, 51, :_reduce_43, 1, 51, :_reduce_44, 2, 53, :_reduce_45, 1, 53, :_reduce_46, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 50, :_reduce_none, 1, 54, :_reduce_none, 1, 54, :_reduce_none, 1, 55, :_reduce_none, 1, 55, :_reduce_none, 1, 56, :_reduce_57, 1, 52, :_reduce_58, 1, 57, :_reduce_59, 2, 58, :_reduce_60, 1, 58, :_reduce_none, 2, 49, :_reduce_62, 1, 49, :_reduce_none, 2, 48, :_reduce_64, 1, 48, :_reduce_none, 1, 60, :_reduce_none, 1, 60, :_reduce_none, 1, 60, :_reduce_none, 1, 60, :_reduce_none, 1, 60, :_reduce_none, 1, 62, :_reduce_none, 1, 62, :_reduce_none, 1, 59, :_reduce_none, 1, 59, :_reduce_none, 1, 61, :_reduce_none, 1, 61, :_reduce_none, 1, 61, :_reduce_none, 2, 42, :_reduce_78, 1, 42, :_reduce_none, 1, 63, :_reduce_none, 2, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 1, 63, :_reduce_none, 3, 36, :_reduce_101, 3, 37, :_reduce_102, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 1, 65, :_reduce_none, 2, 66, :_reduce_109, 1, 66, :_reduce_none, 1, 38, :_reduce_111, 1, 67, :_reduce_none, 2, 67, :_reduce_113, 2, 67, :_reduce_114, 2, 67, :_reduce_115, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 1, 68, :_reduce_none, 2, 64, :_reduce_136, 1, 64, :_reduce_none ] racc_reduce_n = 138 racc_shift_n = 179 racc_token_table = { false => 0, :error => 1, :EX_LOW => 2, :QUOTE => 3, :BAR => 4, :SLASH => 5, :BACK_SLASH => 6, :URL => 7, :OTHER => 8, :REF_OPEN => 9, :FOOTNOTE_OPEN => 10, :FOOTNOTE_CLOSE => 11, :EX_HIGH => 12, :EM_OPEN => 13, :EM_CLOSE => 14, :CODE_OPEN => 15, :CODE_CLOSE => 16, :VAR_OPEN => 17, :VAR_CLOSE => 18, :KBD_OPEN => 19, :KBD_CLOSE => 20, :INDEX_OPEN => 21, :INDEX_CLOSE => 22, :REF_CLOSE => 23, :VERB_OPEN => 24, :VERB_CLOSE => 25 } racc_nt_base = 26 racc_use_result_var = true Racc_arg = [ racc_action_table, racc_action_check, racc_action_default, racc_action_pointer, racc_goto_table, racc_goto_check, racc_goto_default, racc_goto_pointer, racc_nt_base, racc_reduce_table, racc_token_table, racc_shift_n, racc_reduce_n, racc_use_result_var ] Racc_token_to_s_table = [ "$end", "error", "EX_LOW", "QUOTE", "BAR", "SLASH", "BACK_SLASH", "URL", "OTHER", "REF_OPEN", "FOOTNOTE_OPEN", "FOOTNOTE_CLOSE", "EX_HIGH", "EM_OPEN", "EM_CLOSE", "CODE_OPEN", "CODE_CLOSE", "VAR_OPEN", "VAR_CLOSE", "KBD_OPEN", "KBD_CLOSE", "INDEX_OPEN", "INDEX_CLOSE", "REF_CLOSE", "VERB_OPEN", "VERB_CLOSE", "$start", "content", "elements", "element", "emphasis", "code", "var", "keyboard", "index", "reference", "footnote", "verb", "normal_str_ele", "substitute", "ref_label", "ref_label2", "ref_url_strings", "filename", "element_label", "element_label2", "ref_subst_content", "ref_subst_content_q", "ref_subst_strings_q", "ref_subst_strings_first", "ref_subst_ele2", "ref_subst_eles", "ref_subst_str_ele_first", "ref_subst_eles_q", "ref_subst_ele", "ref_subst_ele_q", "ref_subst_str_ele", "ref_subst_str_ele_q", "ref_subst_strings", "ref_subst_string3", "ref_subst_string", "ref_subst_string_q", "ref_subst_string2", "ref_url_string", "verb_strings", "normal_string", "normal_strings", "verb_string", "verb_normal_string" ] Racc_debug_parser = false ##### State transition tables end ##### # reduce 0 omitted # reduce 1 omitted def _reduce_2(val, _values, result) result.append val[1] result end def _reduce_3(val, _values, result) result = val[0] result end # reduce 4 omitted # reduce 5 omitted # reduce 6 omitted # reduce 7 omitted # reduce 8 omitted # reduce 9 omitted # reduce 10 omitted # reduce 11 omitted # reduce 12 omitted def _reduce_13(val, _values, result) content = val[1] result = inline "#{content}", content result end def _reduce_14(val, _values, result) content = val[1] result = inline "#{content}", content result end def _reduce_15(val, _values, result) content = val[1] result = inline "+#{content}+", content result end def _reduce_16(val, _values, result) content = val[1] result = inline "#{content}", content result end def _reduce_17(val, _values, result) label = val[1] @block_parser.add_label label.reference result = "#{label}" result end def _reduce_18(val, _values, result) result = "{#{val[1]}}[#{val[2].join}]" result end def _reduce_19(val, _values, result) scheme, inline = val[1] result = "{#{inline}}[#{scheme}#{inline.reference}]" result end def _reduce_20(val, _values, result) result = [nil, inline(val[1])] result end def _reduce_21(val, _values, result) result = [ 'rdoc-label:', inline("#{val[0].reference}/#{val[1].reference}") ] result end def _reduce_22(val, _values, result) result = ['rdoc-label:', val[0].reference] result end def _reduce_23(val, _values, result) result = ['rdoc-label:', "#{val[0].reference}/"] result end def _reduce_24(val, _values, result) result = [nil, inline(val[1])] result end def _reduce_25(val, _values, result) result = [ 'rdoc-label:', inline("#{val[0].reference}/#{val[1].reference}") ] result end def _reduce_26(val, _values, result) result = ['rdoc-label:', val[0]] result end def _reduce_27(val, _values, result) ref = val[0].reference result = ['rdoc-label:', inline(ref, "#{ref}/")] result end # reduce 28 omitted def _reduce_29(val, _values, result) result = val[1] result end def _reduce_30(val, _values, result) result = val[1] result end def _reduce_31(val, _values, result) result = inline val[0] result end def _reduce_32(val, _values, result) result = inline "\"#{val[1]}\"" result end def _reduce_33(val, _values, result) result = inline val[0] result end def _reduce_34(val, _values, result) result = inline "\"#{val[1]}\"" result end # reduce 35 omitted def _reduce_36(val, _values, result) result = val[1] result end def _reduce_37(val, _values, result) result = inline val[1] result end def _reduce_38(val, _values, result) result = val[0].append val[1] result end def _reduce_39(val, _values, result) result = val[0].append val[1] result end def _reduce_40(val, _values, result) result = val[0] result end def _reduce_41(val, _values, result) result = inline val[0] result end # reduce 42 omitted def _reduce_43(val, _values, result) result = val[0].append val[1] result end def _reduce_44(val, _values, result) result = inline val[0] result end def _reduce_45(val, _values, result) result = val[0].append val[1] result end def _reduce_46(val, _values, result) result = val[0] result end # reduce 47 omitted # reduce 48 omitted # reduce 49 omitted # reduce 50 omitted # reduce 51 omitted # reduce 52 omitted # reduce 53 omitted # reduce 54 omitted # reduce 55 omitted # reduce 56 omitted def _reduce_57(val, _values, result) result = val[0] result end def _reduce_58(val, _values, result) result = inline val[0] result end def _reduce_59(val, _values, result) result = inline val[0] result end def _reduce_60(val, _values, result) result << val[1] result end # reduce 61 omitted def _reduce_62(val, _values, result) result << val[1] result end # reduce 63 omitted def _reduce_64(val, _values, result) result << val[1] result end # reduce 65 omitted # reduce 66 omitted # reduce 67 omitted # reduce 68 omitted # reduce 69 omitted # reduce 70 omitted # reduce 71 omitted # reduce 72 omitted # reduce 73 omitted # reduce 74 omitted # reduce 75 omitted # reduce 76 omitted # reduce 77 omitted def _reduce_78(val, _values, result) result << val[1] result end # reduce 79 omitted # reduce 80 omitted # reduce 81 omitted # reduce 82 omitted # reduce 83 omitted # reduce 84 omitted # reduce 85 omitted # reduce 86 omitted # reduce 87 omitted # reduce 88 omitted # reduce 89 omitted # reduce 90 omitted # reduce 91 omitted # reduce 92 omitted # reduce 93 omitted # reduce 94 omitted # reduce 95 omitted # reduce 96 omitted # reduce 97 omitted # reduce 98 omitted # reduce 99 omitted # reduce 100 omitted def _reduce_101(val, _values, result) index = @block_parser.add_footnote val[1].rdoc result = "{*#{index}}[rdoc-label:foottext-#{index}:footmark-#{index}]" result end def _reduce_102(val, _values, result) result = inline "#{val[1]}", val[1] result end # reduce 103 omitted # reduce 104 omitted # reduce 105 omitted # reduce 106 omitted # reduce 107 omitted # reduce 108 omitted def _reduce_109(val, _values, result) result << val[1] result end # reduce 110 omitted def _reduce_111(val, _values, result) result = inline val[0] result end # reduce 112 omitted def _reduce_113(val, _values, result) result = val[1] result end def _reduce_114(val, _values, result) result = val[1] result end def _reduce_115(val, _values, result) result = val[1] result end # reduce 116 omitted # reduce 117 omitted # reduce 118 omitted # reduce 119 omitted # reduce 120 omitted # reduce 121 omitted # reduce 122 omitted # reduce 123 omitted # reduce 124 omitted # reduce 125 omitted # reduce 126 omitted # reduce 127 omitted # reduce 128 omitted # reduce 129 omitted # reduce 130 omitted # reduce 131 omitted # reduce 132 omitted # reduce 133 omitted # reduce 134 omitted # reduce 135 omitted def _reduce_136(val, _values, result) result << val[1] result end # reduce 137 omitted def _reduce_none(val, _values, result) val[0] end end # class InlineParser end PKu]xrdoc-6.2.1.1/lib/rdoc/task.rbnu[# frozen_string_literal: true #-- # Copyright (c) 2003, 2004 Jim Weirich, 2009 Eric Hodel # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ begin gem 'rdoc' rescue Gem::LoadError end unless defined?(RDoc) begin gem 'rake' rescue Gem::LoadError end unless defined?(Rake) require 'rdoc' require 'rake' require 'rake/tasklib' ## # RDoc::Task creates the following rake tasks to generate and clean up RDoc # output: # # [rdoc] # Main task for this RDoc task. # # [clobber_rdoc] # Delete all the rdoc files. This target is automatically added to the main # clobber target. # # [rerdoc] # Rebuild the rdoc files from scratch, even if they are not out of date. # # Simple Example: # # require 'rdoc/task' # # RDoc::Task.new do |rdoc| # rdoc.main = "README.rdoc" # rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb") # end # # The +rdoc+ object passed to the block is an RDoc::Task object. See the # attributes list for the RDoc::Task class for available customization options. # # == Specifying different task names # # You may wish to give the task a different name, such as if you are # generating two sets of documentation. For instance, if you want to have a # development set of documentation including private methods: # # require 'rdoc/task' # # RDoc::Task.new :rdoc_dev do |rdoc| # rdoc.main = "README.doc" # rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb") # rdoc.options << "--all" # end # # The tasks would then be named :rdoc_dev, # :clobber_rdoc_dev, and :rerdoc_dev. # # If you wish to have completely different task names, then pass a Hash as # first argument. With the :rdoc, :clobber_rdoc and # :rerdoc options, you can customize the task names to your liking. # # For example: # # require 'rdoc/task' # # RDoc::Task.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean", # :rerdoc => "rdoc:force") # # This will create the tasks :rdoc, :rdoc:clean and # :rdoc:force. class RDoc::Task < Rake::TaskLib ## # Name of the main, top level task. (default is :rdoc) attr_accessor :name ## # Comment markup format. rdoc, rd and tomdoc are supported. (default is # 'rdoc') attr_accessor :markup ## # Name of directory to receive the html output files. (default is "html") attr_accessor :rdoc_dir ## # Title of RDoc documentation. (defaults to rdoc's default) attr_accessor :title ## # Name of file to be used as the main, top level file of the RDoc. (default # is none) attr_accessor :main ## # Name of template to be used by rdoc. (defaults to rdoc's default) attr_accessor :template ## # Name of format generator (--format) used by rdoc. (defaults to # rdoc's default) attr_accessor :generator ## # List of files to be included in the rdoc generation. (default is []) attr_accessor :rdoc_files ## # Additional list of options to be passed rdoc. (default is []) attr_accessor :options ## # Whether to run the rdoc process as an external shell (default is false) attr_accessor :external ## # Create an RDoc task with the given name. See the RDoc::Task class overview # for documentation. def initialize name = :rdoc # :yield: self defaults check_names name @name = name yield self if block_given? define end ## # Ensures that +names+ only includes names for the :rdoc, :clobber_rdoc and # :rerdoc. If other names are given an ArgumentError is raised. def check_names names return unless Hash === names invalid_options = names.keys.map { |k| k.to_sym } - [:rdoc, :clobber_rdoc, :rerdoc] unless invalid_options.empty? then raise ArgumentError, "invalid options: #{invalid_options.join ', '}" end end ## # Task description for the clobber rdoc task or its renamed equivalent def clobber_task_description "Remove RDoc HTML files" end ## # Sets default task values def defaults @name = :rdoc @rdoc_files = Rake::FileList.new @rdoc_dir = 'html' @main = nil @title = nil @template = nil @generator = nil @options = [] end ## # All source is inline now. This method is deprecated def inline_source # :nodoc: warn "RDoc::Task#inline_source is deprecated" true end ## # All source is inline now. This method is deprecated def inline_source=(value) # :nodoc: warn "RDoc::Task#inline_source is deprecated" end ## # Create the tasks defined by this task lib. def define desc rdoc_task_description task rdoc_task_name desc rerdoc_task_description task rerdoc_task_name => [clobber_task_name, rdoc_task_name] desc clobber_task_description task clobber_task_name do rm_r @rdoc_dir rescue nil end task :clobber => [clobber_task_name] directory @rdoc_dir rdoc_target_deps = [ @rdoc_files, Rake.application.rakefile ].flatten.compact task rdoc_task_name => [rdoc_target] file rdoc_target => rdoc_target_deps do @before_running_rdoc.call if @before_running_rdoc args = option_list + @rdoc_files $stderr.puts "rdoc #{args.join ' '}" if Rake.application.options.trace RDoc::RDoc.new.document args end self end ## # List of options that will be supplied to RDoc def option_list result = @options.dup result << "-o" << @rdoc_dir result << "--main" << main if main result << "--markup" << markup if markup result << "--title" << title if title result << "-T" << template if template result << '-f' << generator if generator result end ## # The block passed to this method will be called just before running the # RDoc generator. It is allowed to modify RDoc::Task attributes inside the # block. def before_running_rdoc(&block) @before_running_rdoc = block end ## # Task description for the rdoc task or its renamed equivalent def rdoc_task_description 'Build RDoc HTML files' end ## # Task description for the rerdoc task or its renamed description def rerdoc_task_description "Rebuild RDoc HTML files" end private def rdoc_target "#{rdoc_dir}/created.rid" end def rdoc_task_name case name when Hash then (name[:rdoc] || "rdoc").to_s else name.to_s end end def clobber_task_name case name when Hash then (name[:clobber_rdoc] || "clobber_rdoc").to_s else "clobber_#{name}" end end def rerdoc_task_name case name when Hash then (name[:rerdoc] || "rerdoc").to_s else "re#{name}" end end end # :stopdoc: module Rake ## # For backwards compatibility RDocTask = RDoc::Task end # :startdoc: PKu]刊--"rdoc-6.2.1.1/lib/rdoc/generator.rbnu[# frozen_string_literal: true ## # RDoc uses generators to turn parsed source code in the form of an # RDoc::CodeObject tree into some form of output. RDoc comes with the HTML # generator RDoc::Generator::Darkfish and an ri data generator # RDoc::Generator::RI. # # == Registering a Generator # # Generators are registered by calling RDoc::RDoc.add_generator with the class # of the generator: # # class My::Awesome::Generator # RDoc::RDoc.add_generator self # end # # == Adding Options to +rdoc+ # # Before option processing in +rdoc+, RDoc::Options will call ::setup_options # on the generator class with an RDoc::Options instance. The generator can # use RDoc::Options#option_parser to add command-line options to the +rdoc+ # tool. See RDoc::Options@Custom+Options for an example and see OptionParser # for details on how to add options. # # You can extend the RDoc::Options instance with additional accessors for your # generator. # # == Generator Instantiation # # After parsing, RDoc::RDoc will instantiate a generator by calling # #initialize with an RDoc::Store instance and an RDoc::Options instance. # # The RDoc::Store instance holds documentation for parsed source code. In # RDoc 3 and earlier the RDoc::TopLevel class held this data. When upgrading # a generator from RDoc 3 and earlier you should only need to replace # RDoc::TopLevel with the store instance. # # RDoc will then call #generate on the generator instance. You can use the # various methods on RDoc::Store and in the RDoc::CodeObject tree to create # your desired output format. module RDoc::Generator autoload :Markup, 'rdoc/generator/markup' autoload :Darkfish, 'rdoc/generator/darkfish' autoload :JsonIndex, 'rdoc/generator/json_index' autoload :RI, 'rdoc/generator/ri' autoload :POT, 'rdoc/generator/pot' end PKu]Ȅ#rdoc-6.2.1.1/lib/rdoc/anon_class.rbnu[# frozen_string_literal: true ## # An anonymous class like: # # c = Class.new do end # # AnonClass is currently not used. class RDoc::AnonClass < RDoc::ClassModule end PKu]  rdoc-6.2.1.1/lib/rdoc/mixin.rbnu[# frozen_string_literal: true ## # A Mixin adds features from a module into another context. RDoc::Include and # RDoc::Extend are both mixins. class RDoc::Mixin < RDoc::CodeObject ## # Name of included module attr_accessor :name ## # Creates a new Mixin for +name+ with +comment+ def initialize(name, comment) super() @name = name self.comment = comment @module = nil # cache for module if found end ## # Mixins are sorted by name def <=> other return unless self.class === other name <=> other.name end def == other # :nodoc: self.class === other and @name == other.name end alias eql? == # :nodoc: ## # Full name based on #module def full_name m = self.module RDoc::ClassModule === m ? m.full_name : @name end def hash # :nodoc: [@name, self.module].hash end def inspect # :nodoc: "#<%s:0x%x %s.%s %s>" % [ self.class, object_id, parent_name, self.class.name.downcase, @name, ] end ## # Attempts to locate the included module object. Returns the name if not # known. # # The scoping rules of Ruby to resolve the name of an included module are: # - first look into the children of the current context; # - if not found, look into the children of included modules, # in reverse inclusion order; # - if still not found, go up the hierarchy of names. # # This method has O(n!) behavior when the module calling # include is referencing nonexistent modules. Avoid calling #module until # after all the files are parsed. This behavior is due to ruby's constant # lookup behavior. # # As of the beginning of October, 2011, no gem includes nonexistent modules. def module return @module if @module # search the current context return @name unless parent full_name = parent.child_name(@name) @module = @store.modules_hash[full_name] return @module if @module return @name if @name =~ /^::/ # search the includes before this one, in reverse order searched = parent.includes.take_while { |i| i != self }.reverse searched.each do |i| inc = i.module next if String === inc full_name = inc.child_name(@name) @module = @store.modules_hash[full_name] return @module if @module end # go up the hierarchy of names up = parent.parent while up full_name = up.child_name(@name) @module = @store.modules_hash[full_name] return @module if @module up = up.parent end @name end ## # Sets the store for this class or module and its contained code objects. def store= store super @file = @store.add_file @file.full_name if @file end def to_s # :nodoc: "#{self.class.name.downcase} #@name in: #{parent}" end end PKu]s(rdoc-6.2.1.1/lib/rdoc/context/section.rbnu[# frozen_string_literal: true ## # A section of documentation like: # # # :section: The title # # The body # # Sections can be referenced multiple times and will be collapsed into a # single section. class RDoc::Context::Section include RDoc::Text MARSHAL_VERSION = 0 # :nodoc: ## # Section comment attr_reader :comment ## # Section comments attr_reader :comments ## # Context this Section lives in attr_reader :parent ## # Section title attr_reader :title @@sequence = "SEC00000" ## # Creates a new section with +title+ and +comment+ def initialize parent, title, comment @parent = parent @title = title ? title.strip : title @@sequence = @@sequence.succ @sequence = @@sequence.dup @comments = [] add_comment comment end ## # Sections are equal when they have the same #title def == other self.class === other and @title == other.title end alias eql? == ## # Adds +comment+ to this section def add_comment comment comment = extract_comment comment return if comment.empty? case comment when RDoc::Comment then @comments << comment when RDoc::Markup::Document then @comments.concat comment.parts when Array then @comments.concat comment else raise TypeError, "unknown comment type: #{comment.inspect}" end end ## # Anchor reference for linking to this section def aref title = @title || '[untitled]' CGI.escape(title).gsub('%', '-').sub(/^-/, '') end ## # Extracts the comment for this section from the original comment block. # If the first line contains :section:, strip it and use the rest. # Otherwise remove lines up to the line containing :section:, and look # for those lines again at the end and remove them. This lets us write # # # :section: The title # # The body def extract_comment comment case comment when Array then comment.map do |c| extract_comment c end when nil RDoc::Comment.new '' when RDoc::Comment then if comment.text =~ /^#[ \t]*:section:.*\n/ then start = $` rest = $' comment.text = if start.empty? then rest else rest.sub(/#{start.chomp}\Z/, '') end end comment when RDoc::Markup::Document then comment else raise TypeError, "unknown comment #{comment.inspect}" end end def inspect # :nodoc: "#<%s:0x%x %p>" % [self.class, object_id, title] end def hash # :nodoc: @title.hash end ## # The files comments in this section come from def in_files return [] if @comments.empty? case @comments when Array then @comments.map do |comment| comment.file end when RDoc::Markup::Document then @comment.parts.map do |document| document.file end else raise RDoc::Error, "BUG: unknown comment class #{@comments.class}" end end ## # Serializes this Section. The title and parsed comment are saved, but not # the section parent which must be restored manually. def marshal_dump [ MARSHAL_VERSION, @title, parse, ] end ## # De-serializes this Section. The section parent must be restored manually. def marshal_load array @parent = nil @title = array[1] @comments = array[2] end ## # Parses +comment_location+ into an RDoc::Markup::Document composed of # multiple RDoc::Markup::Documents with their file set. def parse case @comments when String then super when Array then docs = @comments.map do |comment, location| doc = super comment doc.file = location if location doc end RDoc::Markup::Document.new(*docs) when RDoc::Comment then doc = super @comments.text, comments.format doc.file = @comments.location doc when RDoc::Markup::Document then return @comments else raise ArgumentError, "unknown comment class #{comments.class}" end end ## # The section's title, or 'Top Section' if the title is nil. # # This is used by the table of contents template so the name is silly. def plain_html @title || 'Top Section' end ## # Removes a comment from this section if it is from the same file as # +comment+ def remove_comment comment return if @comments.empty? case @comments when Array then @comments.delete_if do |my_comment| my_comment.file == comment.file end when RDoc::Markup::Document then @comments.parts.delete_if do |document| document.file == comment.file.name end else raise RDoc::Error, "BUG: unknown comment class #{@comments.class}" end end ## # Section sequence number (deprecated) def sequence warn "RDoc::Context::Section#sequence is deprecated, use #aref" @sequence end end PKu]e3 %rdoc-6.2.1.1/lib/rdoc/token_stream.rbnu[# frozen_string_literal: true ## # A TokenStream is a list of tokens, gathered during the parse of some entity # (say a method). Entities populate these streams by being registered with the # lexer. Any class can collect tokens by including TokenStream. From the # outside, you use such an object by calling the start_collecting_tokens # method, followed by calls to add_token and pop_token. module RDoc::TokenStream ## # Converts +token_stream+ to HTML wrapping various tokens with # elements. Some tokens types are wrapped in spans # with the given class names. Other token types are not wrapped in spans. def self.to_html token_stream starting_title = false token_stream.map do |t| next unless t style = case t[:kind] when :on_const then 'ruby-constant' when :on_kw then 'ruby-keyword' when :on_ivar then 'ruby-ivar' when :on_cvar then 'ruby-identifier' when :on_gvar then 'ruby-identifier' when '=' != t[:text] && :on_op then 'ruby-operator' when :on_tlambda then 'ruby-operator' when :on_ident then 'ruby-identifier' when :on_label then 'ruby-value' when :on_backref, :on_dstring then 'ruby-node' when :on_comment then 'ruby-comment' when :on_embdoc then 'ruby-comment' when :on_regexp then 'ruby-regexp' when :on_tstring then 'ruby-string' when :on_int, :on_float, :on_rational, :on_imaginary, :on_heredoc, :on_symbol, :on_CHAR then 'ruby-value' when :on_heredoc_beg, :on_heredoc_end then 'ruby-identifier' end comment_with_nl = false if :on_comment == t[:kind] or :on_embdoc == t[:kind] or :on_heredoc_end == t[:kind] comment_with_nl = true if "\n" == t[:text][-1] text = t[:text].rstrip else text = t[:text] end if :on_ident == t[:kind] && starting_title starting_title = false style = 'ruby-identifier ruby-title' end if :on_kw == t[:kind] and 'def' == t[:text] starting_title = true end text = CGI.escapeHTML text if style then "#{text}#{"\n" if comment_with_nl}" else text end end.join end ## # Adds +tokens+ to the collected tokens def add_tokens(tokens) @token_stream.concat(tokens) end ## # Adds one +token+ to the collected tokens def add_token(token) @token_stream.push(token) end ## # Starts collecting tokens def collect_tokens @token_stream = [] end alias start_collecting_tokens collect_tokens ## # Remove the last token from the collected tokens def pop_token @token_stream.pop end ## # Current token stream def token_stream @token_stream end ## # Returns a string representation of the token stream def tokens_to_s token_stream.compact.map { |token| token[:text] }.join '' end end PKu]vTDODO%rdoc-6.2.1.1/lib/rdoc/class_module.rbnu[# frozen_string_literal: true ## # ClassModule is the base class for objects representing either a class or a # module. class RDoc::ClassModule < RDoc::Context ## # 1:: # RDoc 3.7 # * Added visibility, singleton and file to attributes # * Added file to constants # * Added file to includes # * Added file to methods # 2:: # RDoc 3.13 # * Added extends # 3:: # RDoc 4.0 # * Added sections # * Added in_files # * Added parent name # * Complete Constant dump MARSHAL_VERSION = 3 # :nodoc: ## # Constants that are aliases for this class or module attr_accessor :constant_aliases ## # Comment and the location it came from. Use #add_comment to add comments attr_accessor :comment_location attr_accessor :diagram # :nodoc: ## # Class or module this constant is an alias for attr_accessor :is_alias_for ## # Return a RDoc::ClassModule of class +class_type+ that is a copy # of module +module+. Used to promote modules to classes. #-- # TODO move to RDoc::NormalClass (I think) def self.from_module class_type, mod klass = class_type.new mod.name mod.comment_location.each do |comment, location| klass.add_comment comment, location end klass.parent = mod.parent klass.section = mod.section klass.viewer = mod.viewer klass.attributes.concat mod.attributes klass.method_list.concat mod.method_list klass.aliases.concat mod.aliases klass.external_aliases.concat mod.external_aliases klass.constants.concat mod.constants klass.includes.concat mod.includes klass.extends.concat mod.extends klass.methods_hash.update mod.methods_hash klass.constants_hash.update mod.constants_hash klass.current_section = mod.current_section klass.in_files.concat mod.in_files klass.sections.concat mod.sections klass.unmatched_alias_lists = mod.unmatched_alias_lists klass.current_section = mod.current_section klass.visibility = mod.visibility klass.classes_hash.update mod.classes_hash klass.modules_hash.update mod.modules_hash klass.metadata.update mod.metadata klass.document_self = mod.received_nodoc ? nil : mod.document_self klass.document_children = mod.document_children klass.force_documentation = mod.force_documentation klass.done_documenting = mod.done_documenting # update the parent of all children (klass.attributes + klass.method_list + klass.aliases + klass.external_aliases + klass.constants + klass.includes + klass.extends + klass.classes + klass.modules).each do |obj| obj.parent = klass obj.full_name = nil end klass end ## # Creates a new ClassModule with +name+ with optional +superclass+ # # This is a constructor for subclasses, and must never be called directly. def initialize(name, superclass = nil) @constant_aliases = [] @diagram = nil @is_alias_for = nil @name = name @superclass = superclass @comment_location = [] # [[comment, location]] super() end ## # Adds +comment+ to this ClassModule's list of comments at +location+. This # method is preferred over #comment= since it allows ri data to be updated # across multiple runs. def add_comment comment, location return unless document_self original = comment comment = case comment when RDoc::Comment then comment.normalize else normalize_comment comment end if location.parser == RDoc::Parser::C @comment_location.delete_if { |(_, l)| l == location } end @comment_location << [comment, location] self.comment = original end def add_things my_things, other_things # :nodoc: other_things.each do |group, things| my_things[group].each { |thing| yield false, thing } if my_things.include? group things.each do |thing| yield true, thing end end end ## # Ancestors list for this ClassModule: the list of included modules # (classes will add their superclass if any). # # Returns the included classes or modules, not the includes # themselves. The returned values are either String or # RDoc::NormalModule instances (see RDoc::Include#module). # # The values are returned in reverse order of their inclusion, # which is the order suitable for searching methods/attributes # in the ancestors. The superclass, if any, comes last. def ancestors includes.map { |i| i.module }.reverse end def aref_prefix # :nodoc: raise NotImplementedError, "missing aref_prefix for #{self.class}" end ## # HTML fragment reference for this module or class. See # RDoc::NormalClass#aref and RDoc::NormalModule#aref def aref "#{aref_prefix}-#{full_name}" end ## # Ancestors of this class or module only alias direct_ancestors ancestors ## # Clears the comment. Used by the Ruby parser. def clear_comment @comment = '' end ## # This method is deprecated, use #add_comment instead. # # Appends +comment+ to the current comment, but separated by a rule. Works # more like +=. def comment= comment # :nodoc: comment = case comment when RDoc::Comment then comment.normalize else normalize_comment comment end comment = "#{@comment.to_s}\n---\n#{comment.to_s}" unless @comment.empty? super comment end ## # Prepares this ClassModule for use by a generator. # # See RDoc::Store#complete def complete min_visibility update_aliases remove_nodoc_children update_includes remove_invisible min_visibility end ## # Does this ClassModule or any of its methods have document_self set? def document_self_or_methods document_self || method_list.any?{ |m| m.document_self } end ## # Does this class or module have a comment with content or is # #received_nodoc true? def documented? return true if @received_nodoc return false if @comment_location.empty? @comment_location.any? { |comment, _| not comment.empty? } end ## # Iterates the ancestors of this class or module for which an # RDoc::ClassModule exists. def each_ancestor # :yields: module return enum_for __method__ unless block_given? ancestors.each do |mod| next if String === mod next if self == mod yield mod end end ## # Looks for a symbol in the #ancestors. See Context#find_local_symbol. def find_ancestor_local_symbol symbol each_ancestor do |m| res = m.find_local_symbol(symbol) return res if res end nil end ## # Finds a class or module with +name+ in this namespace or its descendants def find_class_named name return self if full_name == name return self if @name == name @classes.values.find do |klass| next if klass == self klass.find_class_named name end end ## # Return the fully qualified name of this class or module def full_name @full_name ||= if RDoc::ClassModule === parent then "#{parent.full_name}::#{@name}" else @name end end ## # TODO: filter included items by #display? def marshal_dump # :nodoc: attrs = attributes.sort.map do |attr| next unless attr.display? [ attr.name, attr.rw, attr.visibility, attr.singleton, attr.file_name, ] end.compact method_types = methods_by_type.map do |type, visibilities| visibilities = visibilities.map do |visibility, methods| method_names = methods.map do |method| next unless method.display? [method.name, method.file_name] end.compact [visibility, method_names.uniq] end [type, visibilities] end [ MARSHAL_VERSION, @name, full_name, @superclass, parse(@comment_location), attrs, constants.select { |constant| constant.display? }, includes.map do |incl| next unless incl.display? [incl.name, parse(incl.comment), incl.file_name] end.compact, method_types, extends.map do |ext| next unless ext.display? [ext.name, parse(ext.comment), ext.file_name] end.compact, @sections.values, @in_files.map do |tl| tl.relative_name end, parent.full_name, parent.class, ] end def marshal_load array # :nodoc: initialize_visibility initialize_methods_etc @current_section = nil @document_self = true @done_documenting = false @parent = nil @temporary_section = nil @visibility = nil @classes = {} @modules = {} @name = array[1] @full_name = array[2] @superclass = array[3] @comment = array[4] @comment_location = if RDoc::Markup::Document === @comment.parts.first then @comment else RDoc::Markup::Document.new @comment end array[5].each do |name, rw, visibility, singleton, file| singleton ||= false visibility ||= :public attr = RDoc::Attr.new nil, name, rw, nil, singleton add_attribute attr attr.visibility = visibility attr.record_location RDoc::TopLevel.new file end array[6].each do |constant, comment, file| case constant when RDoc::Constant then add_constant constant else constant = add_constant RDoc::Constant.new(constant, nil, comment) constant.record_location RDoc::TopLevel.new file end end array[7].each do |name, comment, file| incl = add_include RDoc::Include.new(name, comment) incl.record_location RDoc::TopLevel.new file end array[8].each do |type, visibilities| visibilities.each do |visibility, methods| @visibility = visibility methods.each do |name, file| method = RDoc::AnyMethod.new nil, name method.singleton = true if type == 'class' method.record_location RDoc::TopLevel.new file add_method method end end end array[9].each do |name, comment, file| ext = add_extend RDoc::Extend.new(name, comment) ext.record_location RDoc::TopLevel.new file end if array[9] # Support Marshal version 1 sections = (array[10] || []).map do |section| [section.title, section] end @sections = Hash[*sections.flatten] @current_section = add_section nil @in_files = [] (array[11] || []).each do |filename| record_location RDoc::TopLevel.new filename end @parent_name = array[12] @parent_class = array[13] end ## # Merges +class_module+ into this ClassModule. # # The data in +class_module+ is preferred over the receiver. def merge class_module @parent = class_module.parent @parent_name = class_module.parent_name other_document = parse class_module.comment_location if other_document then document = parse @comment_location document = document.merge other_document @comment = @comment_location = document end cm = class_module other_files = cm.in_files merge_collections attributes, cm.attributes, other_files do |add, attr| if add then add_attribute attr else @attributes.delete attr @methods_hash.delete attr.pretty_name end end merge_collections constants, cm.constants, other_files do |add, const| if add then add_constant const else @constants.delete const @constants_hash.delete const.name end end merge_collections includes, cm.includes, other_files do |add, incl| if add then add_include incl else @includes.delete incl end end @includes.uniq! # clean up merge_collections extends, cm.extends, other_files do |add, ext| if add then add_extend ext else @extends.delete ext end end @extends.uniq! # clean up merge_collections method_list, cm.method_list, other_files do |add, meth| if add then add_method meth else @method_list.delete meth @methods_hash.delete meth.pretty_name end end merge_sections cm self end ## # Merges collection +mine+ with +other+ preferring other. +other_files+ is # used to help determine which items should be deleted. # # Yields whether the item should be added or removed (true or false) and the # item to be added or removed. # # merge_collections things, other.things, other.in_files do |add, thing| # if add then # # add the thing # else # # remove the thing # end # end def merge_collections mine, other, other_files, &block # :nodoc: my_things = mine. group_by { |thing| thing.file } other_things = other.group_by { |thing| thing.file } remove_things my_things, other_files, &block add_things my_things, other_things, &block end ## # Merges the comments in this ClassModule with the comments in the other # ClassModule +cm+. def merge_sections cm # :nodoc: my_sections = sections.group_by { |section| section.title } other_sections = cm.sections.group_by { |section| section.title } other_files = cm.in_files remove_things my_sections, other_files do |_, section| @sections.delete section.title end other_sections.each do |group, sections| if my_sections.include? group my_sections[group].each do |my_section| other_section = cm.sections_hash[group] my_comments = my_section.comments other_comments = other_section.comments other_files = other_section.in_files merge_collections my_comments, other_comments, other_files do |add, comment| if add then my_section.add_comment comment else my_section.remove_comment comment end end end else sections.each do |section| add_section group, section.comments end end end end ## # Does this object represent a module? def module? false end ## # Allows overriding the initial name. # # Used for modules and classes that are constant aliases. def name= new_name @name = new_name end ## # Parses +comment_location+ into an RDoc::Markup::Document composed of # multiple RDoc::Markup::Documents with their file set. def parse comment_location case comment_location when String then super when Array then docs = comment_location.map do |comment, location| doc = super comment doc.file = location doc end RDoc::Markup::Document.new(*docs) when RDoc::Comment then doc = super comment_location.text, comment_location.format doc.file = comment_location.location doc when RDoc::Markup::Document then return comment_location else raise ArgumentError, "unknown comment class #{comment_location.class}" end end ## # Path to this class or module for use with HTML generator output. def path http_url @store.rdoc.generator.class_dir end ## # Name to use to generate the url: # modules and classes that are aliases for another # module or class return the name of the latter. def name_for_path is_alias_for ? is_alias_for.full_name : full_name end ## # Returns the classes and modules that are not constants # aliasing another class or module. For use by formatters # only (caches its result). def non_aliases @non_aliases ||= classes_and_modules.reject { |cm| cm.is_alias_for } end ## # Updates the child modules or classes of class/module +parent+ by # deleting the ones that have been removed from the documentation. # # +parent_hash+ is either parent.modules_hash or # parent.classes_hash and +all_hash+ is ::all_modules_hash or # ::all_classes_hash. def remove_nodoc_children prefix = self.full_name + '::' modules_hash.each_key do |name| full_name = prefix + name modules_hash.delete name unless @store.modules_hash[full_name] end classes_hash.each_key do |name| full_name = prefix + name classes_hash.delete name unless @store.classes_hash[full_name] end end def remove_things my_things, other_files # :nodoc: my_things.delete_if do |file, things| next false unless other_files.include? file things.each do |thing| yield false, thing end true end end ## # Search record used by RDoc::Generator::JsonIndex def search_record [ name, full_name, full_name, '', path, '', snippet(@comment_location), ] end ## # Sets the store for this class or module and its contained code objects. def store= store super @attributes .each do |attr| attr.store = store end @constants .each do |const| const.store = store end @includes .each do |incl| incl.store = store end @extends .each do |ext| ext.store = store end @method_list.each do |meth| meth.store = store end end ## # Get the superclass of this class. Attempts to retrieve the superclass # object, returns the name if it is not known. def superclass @store.find_class_named(@superclass) || @superclass end ## # Set the superclass of this class to +superclass+ def superclass=(superclass) raise NoMethodError, "#{full_name} is a module" if module? @superclass = superclass end def to_s # :nodoc: if is_alias_for then "#{self.class.name} #{self.full_name} -> #{is_alias_for}" else super end end ## # 'module' or 'class' def type module? ? 'module' : 'class' end ## # Updates the child modules & classes by replacing the ones that are # aliases through a constant. # # The aliased module/class is replaced in the children and in # RDoc::Store#modules_hash or RDoc::Store#classes_hash # by a copy that has RDoc::ClassModule#is_alias_for set to # the aliased module/class, and this copy is added to #aliases # of the aliased module/class. # # Formatters can use the #non_aliases method to retrieve children that # are not aliases, for instance to list the namespace content, since # the aliased modules are included in the constants of the class/module, # that are listed separately. def update_aliases constants.each do |const| next unless cm = const.is_alias_for cm_alias = cm.dup cm_alias.name = const.name # Don't move top-level aliases under Object, they look ugly there unless RDoc::TopLevel === cm_alias.parent then cm_alias.parent = self cm_alias.full_name = nil # force update for new parent end cm_alias.aliases.clear cm_alias.is_alias_for = cm if cm.module? then @store.modules_hash[cm_alias.full_name] = cm_alias modules_hash[const.name] = cm_alias else @store.classes_hash[cm_alias.full_name] = cm_alias classes_hash[const.name] = cm_alias end cm.aliases << cm_alias end end ## # Deletes from #includes those whose module has been removed from the # documentation. #-- # FIXME: includes are not reliably removed, see _possible_bug test case def update_includes includes.reject! do |include| mod = include.module !(String === mod) && @store.modules_hash[mod.full_name].nil? end includes.uniq! end ## # Deletes from #extends those whose module has been removed from the # documentation. #-- # FIXME: like update_includes, extends are not reliably removed def update_extends extends.reject! do |ext| mod = ext.module !(String === mod) && @store.modules_hash[mod.full_name].nil? end extends.uniq! end end PKu]V*6*6rdoc-6.2.1.1/lib/rdoc/rdoc.rbnu[# frozen_string_literal: true require 'rdoc' require 'find' require 'fileutils' require 'pathname' require 'time' ## # This is the driver for generating RDoc output. It handles file parsing and # generation of output. # # To use this class to generate RDoc output via the API, the recommended way # is: # # rdoc = RDoc::RDoc.new # options = rdoc.load_options # returns an RDoc::Options instance # # set extra options # rdoc.document options # # You can also generate output like the +rdoc+ executable: # # rdoc = RDoc::RDoc.new # rdoc.document argv # # Where +argv+ is an array of strings, each corresponding to an argument you'd # give rdoc on the command line. See rdoc --help for details. class RDoc::RDoc @current = nil ## # This is the list of supported output generators GENERATORS = {} ## # Generator instance used for creating output attr_accessor :generator ## # Hash of files and their last modified times. attr_reader :last_modified ## # RDoc options attr_accessor :options ## # Accessor for statistics. Available after each call to parse_files attr_reader :stats ## # The current documentation store attr_reader :store ## # Add +klass+ that can generate output after parsing def self.add_generator(klass) name = klass.name.sub(/^RDoc::Generator::/, '').downcase GENERATORS[name] = klass end ## # Active RDoc::RDoc instance def self.current @current end ## # Sets the active RDoc::RDoc instance def self.current= rdoc @current = rdoc end ## # Creates a new RDoc::RDoc instance. Call #document to parse files and # generate documentation. def initialize @current = nil @generator = nil @last_modified = {} @old_siginfo = nil @options = nil @stats = nil @store = nil end ## # Report an error message and exit def error(msg) raise RDoc::Error, msg end ## # Gathers a set of parseable files from the files and directories listed in # +files+. def gather_files files files = ["."] if files.empty? file_list = normalized_file_list files, true, @options.exclude file_list = file_list.uniq file_list = remove_unparseable file_list file_list.sort end ## # Turns RDoc from stdin into HTML def handle_pipe @html = RDoc::Markup::ToHtml.new @options parser = RDoc::Text::MARKUP_FORMAT[@options.markup] document = parser.parse $stdin.read out = @html.convert document $stdout.write out end ## # Installs a siginfo handler that prints the current filename. def install_siginfo_handler return unless Signal.list.include? 'INFO' @old_siginfo = trap 'INFO' do puts @current if @current end end ## # Loads options from .rdoc_options if the file exists, otherwise creates a # new RDoc::Options instance. def load_options options_file = File.expand_path '.rdoc_options' return RDoc::Options.new unless File.exist? options_file RDoc.load_yaml begin options = YAML.load_file '.rdoc_options' rescue Psych::SyntaxError end raise RDoc::Error, "#{options_file} is not a valid rdoc options file" unless RDoc::Options === options options end ## # Create an output dir if it doesn't exist. If it does exist, but doesn't # contain the flag file created.rid then we refuse to use it, as # we may clobber some manually generated documentation def setup_output_dir(dir, force) flag_file = output_flag_file dir last = {} if @options.dry_run then # do nothing elsif File.exist? dir then error "#{dir} exists and is not a directory" unless File.directory? dir begin File.open flag_file do |io| unless force then Time.parse io.gets io.each do |line| file, time = line.split "\t", 2 time = Time.parse(time) rescue next last[file] = time end end end rescue SystemCallError, TypeError error <<-ERROR Directory #{dir} already exists, but it looks like it isn't an RDoc directory. Because RDoc doesn't want to risk destroying any of your existing files, you'll need to specify a different output directory name (using the --op
    option) ERROR end unless @options.force_output else FileUtils.mkdir_p dir FileUtils.touch flag_file end last end ## # Sets the current documentation tree to +store+ and sets the store's rdoc # driver to this instance. def store= store @store = store @store.rdoc = self end ## # Update the flag file in an output directory. def update_output_dir(op_dir, time, last = {}) return if @options.dry_run or not @options.update_output_dir unless ENV['SOURCE_DATE_EPOCH'].nil? time = Time.at(ENV['SOURCE_DATE_EPOCH'].to_i).gmtime end File.open output_flag_file(op_dir), "w" do |f| f.puts time.rfc2822 last.each do |n, t| f.puts "#{n}\t#{t.rfc2822}" end end end ## # Return the path name of the flag file in an output directory. def output_flag_file(op_dir) File.join op_dir, "created.rid" end ## # The .document file contains a list of file and directory name patterns, # representing candidates for documentation. It may also contain comments # (starting with '#') def parse_dot_doc_file in_dir, filename # read and strip comments patterns = File.read(filename).gsub(/#.*/, '') result = [] patterns.split.each do |patt| candidates = Dir.glob(File.join(in_dir, patt)) result.concat normalized_file_list(candidates, false, @options.exclude) end result end ## # Given a list of files and directories, create a list of all the Ruby # files they contain. # # If +force_doc+ is true we always add the given files, if false, only # add files that we guarantee we can parse. It is true when looking at # files given on the command line, false when recursing through # subdirectories. # # The effect of this is that if you want a file with a non-standard # extension parsed, you must name it explicitly. def normalized_file_list(relative_files, force_doc = false, exclude_pattern = nil) file_list = [] relative_files.each do |rel_file_name| next if rel_file_name.end_with? 'created.rid' next if exclude_pattern && exclude_pattern =~ rel_file_name stat = File.stat rel_file_name rescue next case type = stat.ftype when "file" then next if last_modified = @last_modified[rel_file_name] and stat.mtime.to_i <= last_modified.to_i if force_doc or RDoc::Parser.can_parse(rel_file_name) then file_list << rel_file_name.sub(/^\.\//, '') @last_modified[rel_file_name] = stat.mtime end when "directory" then next if rel_file_name == "CVS" || rel_file_name == ".svn" created_rid = File.join rel_file_name, "created.rid" next if File.file? created_rid dot_doc = File.join rel_file_name, RDoc::DOT_DOC_FILENAME if File.file? dot_doc then file_list << parse_dot_doc_file(rel_file_name, dot_doc) else file_list << list_files_in_directory(rel_file_name) end else warn "rdoc can't parse the #{type} #{rel_file_name}" end end file_list.flatten end ## # Return a list of the files to be processed in a directory. We know that # this directory doesn't have a .document file, so we're looking for real # files. However we may well contain subdirectories which must be tested # for .document files. def list_files_in_directory dir files = Dir.glob File.join(dir, "*") normalized_file_list files, false, @options.exclude end ## # Parses +filename+ and returns an RDoc::TopLevel def parse_file filename encoding = @options.encoding filename = filename.encode encoding @stats.add_file filename return if RDoc::Parser.binary? filename content = RDoc::Encoding.read_file filename, encoding return unless content filename_path = Pathname(filename).expand_path begin relative_path = filename_path.relative_path_from @options.root rescue ArgumentError relative_path = filename_path end if @options.page_dir and relative_path.to_s.start_with? @options.page_dir.to_s then relative_path = relative_path.relative_path_from @options.page_dir end top_level = @store.add_file filename, relative_name: relative_path.to_s parser = RDoc::Parser.for top_level, filename, content, @options, @stats return unless parser parser.scan # restart documentation for the classes & modules found top_level.classes_or_modules.each do |cm| cm.done_documenting = false end top_level rescue Errno::EACCES => e $stderr.puts <<-EOF Unable to read #{filename}, #{e.message} Please check the permissions for this file. Perhaps you do not have access to it or perhaps the original author's permissions are to restrictive. If the this is not your library please report a bug to the author. EOF rescue => e $stderr.puts <<-EOF Before reporting this, could you check that the file you're documenting has proper syntax: #{Gem.ruby} -c #{filename} RDoc is not a full Ruby parser and will fail when fed invalid ruby programs. The internal error was: \t(#{e.class}) #{e.message} EOF $stderr.puts e.backtrace.join("\n\t") if $DEBUG_RDOC raise e nil end ## # Parse each file on the command line, recursively entering directories. def parse_files files file_list = gather_files files @stats = RDoc::Stats.new @store, file_list.length, @options.verbosity return [] if file_list.empty? original_options = @options.dup @stats.begin_adding file_info = file_list.map do |filename| @current = filename parse_file filename end.compact @stats.done_adding @options = original_options file_info end ## # Removes file extensions known to be unparseable from +files+ and TAGS # files for emacs and vim. def remove_unparseable files files.reject do |file| file =~ /\.(?:class|eps|erb|scpt\.txt|svg|ttf|yml)$/i or (file =~ /tags$/i and File.open(file, 'rb') { |io| io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/ }) end end ## # Generates documentation or a coverage report depending upon the settings # in +options+. # # +options+ can be either an RDoc::Options instance or an array of strings # equivalent to the strings that would be passed on the command line like # %w[-q -o doc -t My\ Doc\ Title]. #document will automatically # call RDoc::Options#finish if an options instance was given. # # For a list of options, see either RDoc::Options or rdoc --help. # # By default, output will be stored in a directory called "doc" below the # current directory, so make sure you're somewhere writable before invoking. def document options self.store = RDoc::Store.new if RDoc::Options === options then @options = options @options.finish else @options = load_options @options.parse options end if @options.pipe then handle_pipe exit end unless @options.coverage_report then @last_modified = setup_output_dir @options.op_dir, @options.force_update end @store.encoding = @options.encoding @store.dry_run = @options.dry_run @store.main = @options.main_page @store.title = @options.title @store.path = @options.op_dir @start_time = Time.now @store.load_cache file_info = parse_files @options.files @options.default_title = "RDoc Documentation" @store.complete @options.visibility @stats.coverage_level = @options.coverage_report if @options.coverage_report then puts puts @stats.report.accept RDoc::Markup::ToRdoc.new elsif file_info.empty? then $stderr.puts "\nNo newer files." unless @options.quiet else gen_klass = @options.generator @generator = gen_klass.new @store, @options generate end if @stats and (@options.coverage_report or not @options.quiet) then puts puts @stats.summary.accept RDoc::Markup::ToRdoc.new end exit @stats.fully_documented? if @options.coverage_report end ## # Generates documentation for +file_info+ (from #parse_files) into the # output dir using the generator selected # by the RDoc options def generate if @options.dry_run then # do nothing @generator.generate else Dir.chdir @options.op_dir do unless @options.quiet then $stderr.puts "\nGenerating #{@generator.class.name.sub(/^.*::/, '')} format into #{Dir.pwd}..." end @generator.generate update_output_dir '.', @start_time, @last_modified end end end ## # Removes a siginfo handler and replaces the previous def remove_siginfo_handler return unless Signal.list.key? 'INFO' handler = @old_siginfo || 'DEFAULT' trap 'INFO', handler end end begin require 'rubygems' rdoc_extensions = Gem.find_files 'rdoc/discover' rdoc_extensions.each do |extension| begin load extension rescue => e warn "error loading #{extension.inspect}: #{e.message} (#{e.class})" warn "\t#{e.backtrace.join "\n\t"}" if $DEBUG end end rescue LoadError end # require built-in generators after discovery in case they've been replaced require 'rdoc/generator/darkfish' require 'rdoc/generator/ri' require 'rdoc/generator/pot' PKu]v}&rdoc-6.2.1.1/lib/rdoc/rubygems_hook.rbnu[# frozen_string_literal: true require 'rubygems/user_interaction' require 'fileutils' require 'rdoc' ## # Gem::RDoc provides methods to generate RDoc and ri data for installed gems # upon gem installation. # # This file is automatically required by RubyGems 1.9 and newer. class RDoc::RubygemsHook include Gem::UserInteraction extend Gem::UserInteraction @rdoc_version = nil @specs = [] ## # Force installation of documentation? attr_accessor :force ## # Generate rdoc? attr_accessor :generate_rdoc ## # Generate ri data? attr_accessor :generate_ri class << self ## # Loaded version of RDoc. Set by ::load_rdoc attr_reader :rdoc_version end ## # Post installs hook that generates documentation for each specification in # +specs+ def self.generation_hook installer, specs start = Time.now types = installer.document generate_rdoc = types.include? 'rdoc' generate_ri = types.include? 'ri' specs.each do |spec| new(spec, generate_rdoc, generate_ri).generate end return unless generate_rdoc or generate_ri duration = (Time.now - start).to_i names = specs.map(&:name).join ', ' say "Done installing documentation for #{names} after #{duration} seconds" end ## # Loads the RDoc generator def self.load_rdoc return if @rdoc_version require 'rdoc/rdoc' @rdoc_version = Gem::Version.new ::RDoc::VERSION end ## # Creates a new documentation generator for +spec+. RDoc and ri data # generation can be enabled or disabled through +generate_rdoc+ and # +generate_ri+ respectively. # # Only +generate_ri+ is enabled by default. def initialize spec, generate_rdoc = false, generate_ri = true @doc_dir = spec.doc_dir @force = false @rdoc = nil @spec = spec @generate_rdoc = generate_rdoc @generate_ri = generate_ri @rdoc_dir = spec.doc_dir 'rdoc' @ri_dir = spec.doc_dir 'ri' end ## # Removes legacy rdoc arguments from +args+ #-- # TODO move to RDoc::Options def delete_legacy_args args args.delete '--inline-source' args.delete '--promiscuous' args.delete '-p' args.delete '--one-file' end ## # Generates documentation using the named +generator+ ("darkfish" or "ri") # and following the given +options+. # # Documentation will be generated into +destination+ def document generator, options, destination generator_name = generator options = options.dup options.exclude ||= [] # TODO maybe move to RDoc::Options#finish options.setup_generator generator options.op_dir = destination options.finish generator = options.generator.new @rdoc.store, options @rdoc.options = options @rdoc.generator = generator say "Installing #{generator_name} documentation for #{@spec.full_name}" FileUtils.mkdir_p options.op_dir Dir.chdir options.op_dir do begin @rdoc.class.current = @rdoc @rdoc.generator.generate ensure @rdoc.class.current = nil end end end ## # Generates RDoc and ri data def generate return if @spec.default_gem? return unless @generate_ri or @generate_rdoc setup options = nil args = @spec.rdoc_options args.concat @spec.source_paths args.concat @spec.extra_rdoc_files case config_args = Gem.configuration[:rdoc] when String then args = args.concat config_args.split when Array then args = args.concat config_args end delete_legacy_args args Dir.chdir @spec.full_gem_path do options = ::RDoc::Options.new options.default_title = "#{@spec.full_name} Documentation" options.parse args end options.quiet = !Gem.configuration.really_verbose @rdoc = new_rdoc @rdoc.options = options store = RDoc::Store.new store.encoding = options.encoding store.dry_run = options.dry_run store.main = options.main_page store.title = options.title @rdoc.store = store say "Parsing documentation for #{@spec.full_name}" Dir.chdir @spec.full_gem_path do @rdoc.parse_files options.files end document 'ri', options, @ri_dir if @generate_ri and (@force or not File.exist? @ri_dir) document 'darkfish', options, @rdoc_dir if @generate_rdoc and (@force or not File.exist? @rdoc_dir) end ## # #new_rdoc creates a new RDoc instance. This method is provided only to # make testing easier. def new_rdoc # :nodoc: ::RDoc::RDoc.new end ## # Is rdoc documentation installed? def rdoc_installed? File.exist? @rdoc_dir end ## # Removes generated RDoc and ri data def remove base_dir = @spec.base_dir raise Gem::FilePermissionError, base_dir unless File.writable? base_dir FileUtils.rm_rf @rdoc_dir FileUtils.rm_rf @ri_dir end ## # Is ri data installed? def ri_installed? File.exist? @ri_dir end ## # Prepares the spec for documentation generation def setup self.class.load_rdoc raise Gem::FilePermissionError, @doc_dir if File.exist?(@doc_dir) and not File.writable?(@doc_dir) FileUtils.mkdir_p @doc_dir unless File.exist? @doc_dir end end PKu]ʥ9e rdoc-6.2.1.1/lib/rdoc/tom_doc.rbnu[# frozen_string_literal: true # :markup: tomdoc # A parser for TomDoc based on TomDoc 1.0.0-rc1 (02adef9b5a) # # The TomDoc specification can be found at: # # http://tomdoc.org # # The latest version of the TomDoc specification can be found at: # # https://github.com/mojombo/tomdoc/blob/master/tomdoc.md # # To choose TomDoc as your only default format see RDoc::Options@Saved+Options # for instructions on setting up a .rdoc_options file to store # your project default. # # There are a few differences between this parser and the specification. A # best-effort was made to follow the specification as closely as possible but # some choices to deviate were made. # # A future version of RDoc will warn when a MUST or MUST NOT is violated and # may warn when a SHOULD or SHOULD NOT is violated. RDoc will always try # to emit documentation even if given invalid TomDoc. # # Here are some implementation choices this parser currently makes: # # This parser allows rdoc-style inline markup but you should not depended on # it. # # This parser allows a space between the comment and the method body. # # This parser does not require the default value to be described for an # optional argument. # # This parser does not examine the order of sections. An Examples section may # precede the Arguments section. # # This class is documented in TomDoc format. Since this is a subclass of the # RDoc markup parser there isn't much to see here, unfortunately. class RDoc::TomDoc < RDoc::Markup::Parser # Internal: Token accessor attr_reader :tokens # Internal: Adds a post-processor which sets the RDoc section based on the # comment's status. # # Returns nothing. def self.add_post_processor # :nodoc: RDoc::Markup::PreProcess.post_process do |comment, code_object| next unless code_object and RDoc::Comment === comment and comment.format == 'tomdoc' comment.text.gsub!(/(\A\s*# )(Public|Internal|Deprecated):\s+/) do section = code_object.add_section $2 code_object.temporary_section = section $1 end end end add_post_processor # Public: Parses TomDoc from text # # text - A String containing TomDoc-format text. # # Examples # # RDoc::TomDoc.parse <<-TOMDOC # This method does some things # # Returns nothing. # TOMDOC # # => # # # Returns an RDoc::Markup::Document representing the TomDoc format. def self.parse text parser = new parser.tokenize text doc = RDoc::Markup::Document.new parser.parse doc doc end # Internal: Extracts the Signature section's method signature # # comment - An RDoc::Comment that will be parsed and have the signature # extracted # # Returns a String containing the signature and nil if not def self.signature comment return unless comment.tomdoc? document = comment.parse signature = nil found_heading = false found_signature = false document.parts.delete_if do |part| next false if found_signature found_heading ||= RDoc::Markup::Heading === part && part.text == 'Signature' next false unless found_heading next true if RDoc::Markup::BlankLine === part if RDoc::Markup::Verbatim === part then signature = part found_signature = true end end signature and signature.text end # Public: Creates a new TomDoc parser. See also RDoc::Markup::parse def initialize super @section = nil @seen_returns = false end # Internal: Builds a heading from the token stream # # level - The level of heading to create # # Returns an RDoc::Markup::Heading def build_heading level heading = super @section = heading.text heading end # Internal: Builds a verbatim from the token stream. A verbatim in the # Examples section will be marked as in Ruby format. # # margin - The indentation from the margin for lines that belong to this # verbatim section. # # Returns an RDoc::Markup::Verbatim def build_verbatim margin verbatim = super verbatim.format = :ruby if @section == 'Examples' verbatim end # Internal: Builds a paragraph from the token stream # # margin - Unused # # Returns an RDoc::Markup::Paragraph. def build_paragraph margin p :paragraph_start => margin if @debug paragraph = RDoc::Markup::Paragraph.new until @tokens.empty? do type, data, = get case type when :TEXT then @section = 'Returns' if data =~ /\A(Returns|Raises)/ paragraph << data when :NEWLINE then if :TEXT == peek_token[0] then # Lines beginning with 'Raises' in the Returns section should not be # treated as multiline text if 'Returns' == @section and peek_token[1].start_with?('Raises') then break else paragraph << ' ' end else break end else unget break end end p :paragraph_end => margin if @debug paragraph end ## # Detects a section change to "Returns" and adds a heading def parse_text parent, indent # :nodoc: paragraph = build_paragraph indent if false == @seen_returns and 'Returns' == @section then @seen_returns = true parent << RDoc::Markup::Heading.new(3, 'Returns') parent << RDoc::Markup::BlankLine.new end parent << paragraph end # Internal: Turns text into an Array of tokens # # text - A String containing TomDoc-format text. # # Returns self. def tokenize text text = text.sub(/\A(Public|Internal|Deprecated):\s+/, '') setup_scanner text until @s.eos? do pos = @s.pos # leading spaces will be reflected by the column of the next token # the only thing we loose are trailing spaces at the end of the file next if @s.scan(/ +/) @tokens << case when @s.scan(/\r?\n/) then token = [:NEWLINE, @s.matched, *pos] @s.newline! token when @s.scan(/(Examples|Signature)$/) then @tokens << [:HEADER, 3, *pos] [:TEXT, @s[1], *pos] when @s.scan(/([:\w][\w\[\]]*)[ ]+- /) then [:NOTE, @s[1], *pos] else @s.scan(/.*/) [:TEXT, @s.matched.sub(/\r$/, ''), *pos] end end self end end PKu] [>  rdoc-6.2.1.1/lib/rdoc/attr.rbnu[# frozen_string_literal: true ## # An attribute created by \#attr, \#attr_reader, \#attr_writer or # \#attr_accessor class RDoc::Attr < RDoc::MethodAttr ## # 3:: # RDoc 4 # Added parent name and class # Added section title MARSHAL_VERSION = 3 # :nodoc: ## # Is the attribute readable ('R'), writable ('W') or both ('RW')? attr_accessor :rw ## # Creates a new Attr with body +text+, +name+, read/write status +rw+ and # +comment+. +singleton+ marks this as a class attribute. def initialize(text, name, rw, comment, singleton = false) super text, name @rw = rw @singleton = singleton self.comment = comment end ## # Attributes are equal when their names, singleton and rw are identical def == other self.class == other.class and self.name == other.name and self.rw == other.rw and self.singleton == other.singleton end ## # Add +an_alias+ as an attribute in +context+. def add_alias(an_alias, context) new_attr = self.class.new(self.text, an_alias.new_name, self.rw, self.comment, self.singleton) new_attr.record_location an_alias.file new_attr.visibility = self.visibility new_attr.is_alias_for = self @aliases << new_attr context.add_attribute new_attr new_attr end ## # The #aref prefix for attributes def aref_prefix 'attribute' end ## # Attributes never call super. See RDoc::AnyMethod#calls_super # # An RDoc::Attr can show up in the method list in some situations (see # Gem::ConfigFile) def calls_super # :nodoc: false end ## # Returns attr_reader, attr_writer or attr_accessor as appropriate. def definition case @rw when 'RW' then 'attr_accessor' when 'R' then 'attr_reader' when 'W' then 'attr_writer' end end def inspect # :nodoc: alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil visibility = self.visibility visibility = "forced #{visibility}" if force_documentation "#<%s:0x%x %s %s (%s)%s>" % [ self.class, object_id, full_name, rw, visibility, alias_for, ] end ## # Dumps this Attr for use by ri. See also #marshal_load def marshal_dump [ MARSHAL_VERSION, @name, full_name, @rw, @visibility, parse(@comment), singleton, @file.relative_name, @parent.full_name, @parent.class, @section.title ] end ## # Loads this Attr from +array+. For a loaded Attr the following # methods will return cached values: # # * #full_name # * #parent_name def marshal_load array initialize_visibility @aliases = [] @parent = nil @parent_name = nil @parent_class = nil @section = nil @file = nil version = array[0] @name = array[1] @full_name = array[2] @rw = array[3] @visibility = array[4] @comment = array[5] @singleton = array[6] || false # MARSHAL_VERSION == 0 # 7 handled below @parent_name = array[8] @parent_class = array[9] @section_title = array[10] @file = RDoc::TopLevel.new array[7] if version > 1 @parent_name ||= @full_name.split('#', 2).first end def pretty_print q # :nodoc: q.group 2, "[#{self.class.name} #{full_name} #{rw} #{visibility}", "]" do unless comment.empty? then q.breakable q.text "comment:" q.breakable q.pp @comment end end end def to_s # :nodoc: "#{definition} #{name} in: #{parent}" end ## # Attributes do not have token streams. # # An RDoc::Attr can show up in the method list in some situations (see # Gem::ConfigFile) def token_stream # :nodoc: end end PKu]KzVf f $rdoc-6.2.1.1/lib/rdoc/i18n/locale.rbnu[# frozen_string_literal: true ## # A message container for a locale. # # This object provides the following two features: # # * Loads translated messages from .po file. # * Translates a message into the locale. class RDoc::I18n::Locale @@locales = {} # :nodoc: class << self ## # Returns the locale object for +locale_name+. def [](locale_name) @@locales[locale_name] ||= new(locale_name) end ## # Sets the locale object for +locale_name+. # # Normally, this method is not used. This method is useful for # testing. def []=(locale_name, locale) @@locales[locale_name] = locale end end ## # The name of the locale. It uses IETF language tag format # +[language[_territory][.codeset][@modifier]]+. # # See also {BCP 47 - Tags for Identifying # Languages}[http://tools.ietf.org/rfc/bcp/bcp47.txt]. attr_reader :name ## # Creates a new locale object for +name+ locale. +name+ must # follow IETF language tag format. def initialize(name) @name = name @messages = {} end ## # Loads translation messages from +locale_directory+/+@name+/rdoc.po # or +locale_directory+/+@name+.po. The former has high priority. # # This method requires gettext gem for parsing .po file. If you # don't have gettext gem, this method doesn't load .po file. This # method warns and returns +false+. # # Returns +true+ if succeeded, +false+ otherwise. def load(locale_directory) return false if @name.nil? po_file_candidates = [ File.join(locale_directory, @name, 'rdoc.po'), File.join(locale_directory, "#{@name}.po"), ] po_file = po_file_candidates.find do |po_file_candidate| File.exist?(po_file_candidate) end return false unless po_file begin require 'gettext/po_parser' require 'gettext/mo' rescue LoadError warn('Need gettext gem for i18n feature:') warn(' gem install gettext') return false end po_parser = GetText::POParser.new messages = GetText::MO.new po_parser.report_warning = false po_parser.parse_file(po_file, messages) @messages.merge!(messages) true end ## # Translates the +message+ into locale. If there is no translation # messages for +message+ in locale, +message+ itself is returned. def translate(message) @messages[message] || message end end PKu]S2 "rdoc-6.2.1.1/lib/rdoc/i18n/text.rbnu[# frozen_string_literal: true ## # An i18n supported text. # # This object provides the following two features: # # * Extracts translation messages from wrapped raw text. # * Translates wrapped raw text in specified locale. # # Wrapped raw text is one of String, RDoc::Comment or Array of them. class RDoc::I18n::Text ## # Creates a new i18n supported text for +raw+ text. def initialize(raw) @raw = raw end ## # Extracts translation target messages and yields each message. # # Each yielded message is a Hash. It consists of the followings: # # :type :: :paragraph # :paragraph :: String (The translation target message itself.) # :line_no :: Integer (The line number of the :paragraph is started.) # # The above content may be added in the future. def extract_messages parse do |part| case part[:type] when :empty_line # ignore when :paragraph yield(part) end end end # Translates raw text into +locale+. def translate(locale) translated_text = '' parse do |part| case part[:type] when :paragraph translated_text += locale.translate(part[:paragraph]) when :empty_line translated_text += part[:line] else raise "should not reach here: unexpected type: #{type}" end end translated_text end private def parse(&block) paragraph = '' paragraph_start_line = 0 line_no = 0 each_line(@raw) do |line| line_no += 1 case line when /\A\s*\z/ if paragraph.empty? emit_empty_line_event(line, line_no, &block) else paragraph += line emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) paragraph = '' end else paragraph_start_line = line_no if paragraph.empty? paragraph += line end end unless paragraph.empty? emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) end end def each_line(raw, &block) case raw when RDoc::Comment raw.text.each_line(&block) when Array raw.each do |comment, location| each_line(comment, &block) end else raw.each_line(&block) end end def emit_empty_line_event(line, line_no) part = { :type => :empty_line, :line => line, :line_no => line_no, } yield(part) end def emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) paragraph_part = { :type => :paragraph, :line_no => paragraph_start_line, } match_data = /(\s*)\z/.match(paragraph) if match_data paragraph_part[:paragraph] = match_data.pre_match yield(paragraph_part) emit_empty_line_event(match_data[1], line_no, &block) else paragraph_part[:paragraph] = paragraph yield(paragraph_part) end end end PKu]>rdoc-6.2.1.1/lib/rdoc/text.rbnu[# frozen_string_literal: true ## # For RDoc::Text#to_html require 'strscan' ## # Methods for manipulating comment text module RDoc::Text attr_accessor :language ## # Maps markup formats to classes that can parse them. If the format is # unknown, "rdoc" format is used. MARKUP_FORMAT = { 'markdown' => RDoc::Markdown, 'rdoc' => RDoc::Markup, 'rd' => RDoc::RD, 'tomdoc' => RDoc::TomDoc, } MARKUP_FORMAT.default = RDoc::Markup ## # Maps an encoding to a Hash of characters properly transcoded for that # encoding. # # See also encode_fallback. TO_HTML_CHARACTERS = Hash.new do |h, encoding| h[encoding] = { :close_dquote => encode_fallback('”', encoding, '"'), :close_squote => encode_fallback('’', encoding, '\''), :copyright => encode_fallback('©', encoding, '(c)'), :ellipsis => encode_fallback('…', encoding, '...'), :em_dash => encode_fallback('—', encoding, '---'), :en_dash => encode_fallback('–', encoding, '--'), :open_dquote => encode_fallback('“', encoding, '"'), :open_squote => encode_fallback('‘', encoding, '\''), :trademark => encode_fallback('®', encoding, '(r)'), } end ## # Transcodes +character+ to +encoding+ with a +fallback+ character. def self.encode_fallback character, encoding, fallback character.encode(encoding, :fallback => { character => fallback }, :undef => :replace, :replace => fallback) end ## # Expands tab characters in +text+ to eight spaces def expand_tabs text expanded = [] text.each_line do |line| nil while line.gsub!(/(?:\G|\r)((?:.{8})*?)([^\t\r\n]{0,7})\t/) do r = "#{$1}#{$2}#{' ' * (8 - $2.size)}" r = RDoc::Encoding.change_encoding r, text.encoding r end expanded << line end expanded.join end ## # Flush +text+ left based on the shortest line def flush_left text indent = 9999 text.each_line do |line| line_indent = line =~ /\S/ || 9999 indent = line_indent if indent > line_indent end empty = '' empty = RDoc::Encoding.change_encoding empty, text.encoding text.gsub(/^ {0,#{indent}}/, empty) end ## # Convert a string in markup format into HTML. # # Requires the including class to implement #formatter def markup text if @store.rdoc.options locale = @store.rdoc.options.locale else locale = nil end if locale i18n_text = RDoc::I18n::Text.new(text) text = i18n_text.translate(locale) end parse(text).accept formatter end ## # Strips hashes, expands tabs then flushes +text+ to the left def normalize_comment text return text if text.empty? case language when :ruby text = strip_hashes text when :c text = strip_stars text end text = expand_tabs text text = flush_left text text = strip_newlines text text end ## # Normalizes +text+ then builds a RDoc::Markup::Document from it def parse text, format = 'rdoc' return text if RDoc::Markup::Document === text return text.parse if RDoc::Comment === text text = normalize_comment text # TODO remove, should not be necessary return RDoc::Markup::Document.new if text =~ /\A\n*\z/ MARKUP_FORMAT[format].parse text end ## # The first +limit+ characters of +text+ as HTML def snippet text, limit = 100 document = parse text RDoc::Markup::ToHtmlSnippet.new(options, limit).convert document end ## # Strips leading # characters from +text+ def strip_hashes text return text if text =~ /^(?>\s*)[^\#]/ empty = '' empty = RDoc::Encoding.change_encoding empty, text.encoding text.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }.gsub(/^\s+$/, empty) end ## # Strips leading and trailing \n characters from +text+ def strip_newlines text text.gsub(/\A\n*(.*?)\n*\z/m) do $1 end # block preserves String encoding end ## # Strips /* */ style comments def strip_stars text return text unless text =~ %r%/\*.*\*/%m encoding = text.encoding text = text.gsub %r%Document-method:\s+[\w:.#=!?|^&<>~+\-/*\%@`\[\]]+%, '' space = ' ' space = RDoc::Encoding.change_encoding space, encoding if encoding text.sub! %r%/\*+% do space * $&.length end text.sub! %r%\*+/% do space * $&.length end text.gsub! %r%^[ \t]*\*%m do space * $&.length end empty = '' empty = RDoc::Encoding.change_encoding empty, encoding if encoding text.gsub(/^\s+$/, empty) end ## # Converts ampersand, dashes, ellipsis, quotes, copyright and registered # trademark symbols in +text+ to properly encoded characters. def to_html text html = (''.encode text.encoding).dup encoded = RDoc::Text::TO_HTML_CHARACTERS[text.encoding] s = StringScanner.new text insquotes = false indquotes = false after_word = nil until s.eos? do case when s.scan(/<(tt|code)>.*?<\/\1>/) then # skip contents of tt html << s.matched.gsub('\\\\', '\\') when s.scan(/<(tt|code)>.*?/) then warn "mismatched <#{s[1]}> tag" # TODO signal file/line html << s.matched when s.scan(/<[^>]+\/?s*>/) then # skip HTML tags html << s.matched when s.scan(/\\(\S)/) then # unhandled suppressed crossref html << s[1] after_word = nil when s.scan(/\.\.\.(\.?)/) then html << s[1] << encoded[:ellipsis] after_word = nil when s.scan(/\(c\)/) then html << encoded[:copyright] after_word = nil when s.scan(/\(r\)/) then html << encoded[:trademark] after_word = nil when s.scan(/---/) then html << encoded[:em_dash] after_word = nil when s.scan(/--/) then html << encoded[:en_dash] after_word = nil when s.scan(/"|"/) then html << encoded[indquotes ? :close_dquote : :open_dquote] indquotes = !indquotes after_word = nil when s.scan(/``/) then # backtick double quote html << encoded[:open_dquote] after_word = nil when s.scan(/''/) then # tick double quote html << encoded[:close_dquote] after_word = nil when s.scan(/'/) then # single quote if insquotes html << encoded[:close_squote] insquotes = false elsif after_word # Mary's dog, my parents' house: do not start paired quotes html << encoded[:close_squote] else html << encoded[:open_squote] insquotes = true end after_word = nil else # advance to the next potentially significant character match = s.scan(/.+?(?=[<\\.("'`&-])/) #" if match then html << match after_word = match =~ /\w$/ else html << s.rest break end end end html end ## # Wraps +txt+ to +line_len+ def wrap(txt, line_len = 76) res = [] sp = 0 ep = txt.length while sp < ep # scan back for a space p = sp + line_len - 1 if p >= ep p = ep else while p > sp and txt[p] != ?\s p -= 1 end if p <= sp p = sp + line_len while p < ep and txt[p] != ?\s p += 1 end end end res << txt[sp...p] << "\n" sp = p sp += 1 while sp < ep and txt[sp] == ?\s end res.join.strip end end PKu]at))rdoc-6.2.1.1/lib/rdoc/stats.rbnu[# frozen_string_literal: true ## # RDoc statistics collector which prints a summary and report of a project's # documentation totals. class RDoc::Stats include RDoc::Text ## # Output level for the coverage report attr_reader :coverage_level ## # Count of files parsed during parsing attr_reader :files_so_far ## # Total number of files found attr_reader :num_files ## # Creates a new Stats that will have +num_files+. +verbosity+ defaults to 1 # which will create an RDoc::Stats::Normal outputter. def initialize store, num_files, verbosity = 1 @num_files = num_files @store = store @coverage_level = 0 @doc_items = nil @files_so_far = 0 @fully_documented = false @num_params = 0 @percent_doc = nil @start = Time.now @undoc_params = 0 @display = case verbosity when 0 then Quiet.new num_files when 1 then Normal.new num_files else Verbose.new num_files end end ## # Records the parsing of an alias +as+. def add_alias as @display.print_alias as end ## # Records the parsing of an attribute +attribute+ def add_attribute attribute @display.print_attribute attribute end ## # Records the parsing of a class +klass+ def add_class klass @display.print_class klass end ## # Records the parsing of +constant+ def add_constant constant @display.print_constant constant end ## # Records the parsing of +file+ def add_file(file) @files_so_far += 1 @display.print_file @files_so_far, file end ## # Records the parsing of +method+ def add_method(method) @display.print_method method end ## # Records the parsing of a module +mod+ def add_module(mod) @display.print_module mod end ## # Call this to mark the beginning of parsing for display purposes def begin_adding @display.begin_adding end ## # Calculates documentation totals and percentages for classes, modules, # constants, attributes and methods. def calculate return if @doc_items ucm = @store.unique_classes_and_modules classes = @store.unique_classes.reject { |cm| cm.full_name == 'Object' } constants = [] ucm.each { |cm| constants.concat cm.constants } methods = [] ucm.each { |cm| methods.concat cm.method_list } attributes = [] ucm.each { |cm| attributes.concat cm.attributes } @num_attributes, @undoc_attributes = doc_stats attributes @num_classes, @undoc_classes = doc_stats classes @num_constants, @undoc_constants = doc_stats constants @num_methods, @undoc_methods = doc_stats methods @num_modules, @undoc_modules = doc_stats @store.unique_modules @num_items = @num_attributes + @num_classes + @num_constants + @num_methods + @num_modules + @num_params @undoc_items = @undoc_attributes + @undoc_classes + @undoc_constants + @undoc_methods + @undoc_modules + @undoc_params @doc_items = @num_items - @undoc_items end ## # Sets coverage report level. Accepted values are: # # false or nil:: No report # 0:: Classes, modules, constants, attributes, methods # 1:: Level 0 + method parameters def coverage_level= level level = -1 unless level @coverage_level = level end ## # Returns the length and number of undocumented items in +collection+. def doc_stats collection visible = collection.select { |item| item.display? } [visible.length, visible.count { |item| not item.documented? }] end ## # Call this to mark the end of parsing for display purposes def done_adding @display.done_adding end ## # The documentation status of this project. +true+ when 100%, +false+ when # less than 100% and +nil+ when unknown. # # Set by calling #calculate def fully_documented? @fully_documented end ## # A report that says you did a great job! def great_job report = RDoc::Markup::Document.new report << RDoc::Markup::Paragraph.new('100% documentation!') report << RDoc::Markup::Paragraph.new('Great Job!') report end ## # Calculates the percentage of items documented. def percent_doc return @percent_doc if @percent_doc @fully_documented = (@num_items - @doc_items) == 0 @percent_doc = @doc_items.to_f / @num_items * 100 if @num_items.nonzero? @percent_doc ||= 0 @percent_doc end ## # Returns a report on which items are not documented def report if @coverage_level > 0 then extend RDoc::Text end if @coverage_level.zero? then calculate return great_job if @num_items == @doc_items end ucm = @store.unique_classes_and_modules report = RDoc::Markup::Document.new report << RDoc::Markup::Paragraph.new('The following items are not documented:') report << RDoc::Markup::BlankLine.new ucm.sort.each do |cm| body = report_class_module(cm) { [ report_constants(cm), report_attributes(cm), report_methods(cm), ].compact } report << body if body end if @coverage_level > 0 then calculate return great_job if @num_items == @doc_items end report end ## # Returns a report on undocumented attributes in ClassModule +cm+ def report_attributes cm return if cm.attributes.empty? report = [] cm.each_attribute do |attr| next if attr.documented? line = attr.line ? ":#{attr.line}" : nil report << " #{attr.definition} :#{attr.name} # in file #{attr.file.full_name}#{line}\n" report << "\n" end report end ## # Returns a report on undocumented items in ClassModule +cm+ def report_class_module cm return if cm.fully_documented? and @coverage_level.zero? return unless cm.display? report = RDoc::Markup::Document.new if cm.in_files.empty? then report << RDoc::Markup::Paragraph.new("#{cm.definition} is referenced but empty.") report << RDoc::Markup::Paragraph.new("It probably came from another project. I'm sorry I'm holding it against you.") return report elsif cm.documented? then documented = true klass = RDoc::Markup::Verbatim.new("#{cm.definition} # is documented\n") else report << RDoc::Markup::Paragraph.new('In files:') list = RDoc::Markup::List.new :BULLET cm.in_files.each do |file| para = RDoc::Markup::Paragraph.new file.full_name list << RDoc::Markup::ListItem.new(nil, para) end report << list report << RDoc::Markup::BlankLine.new klass = RDoc::Markup::Verbatim.new("#{cm.definition}\n") end klass << "\n" body = yield.flatten # HACK remove #flatten if body.empty? then return if documented klass.parts.pop else klass.parts.concat body end klass << "end\n" report << klass report end ## # Returns a report on undocumented constants in ClassModule +cm+ def report_constants cm return if cm.constants.empty? report = [] cm.each_constant do |constant| # TODO constant aliases are listed in the summary but not reported # figure out what to do here next if constant.documented? || constant.is_alias_for line = constant.line ? ":#{constant.line}" : line report << " # in file #{constant.file.full_name}#{line}\n" report << " #{constant.name} = nil\n" report << "\n" end report end ## # Returns a report on undocumented methods in ClassModule +cm+ def report_methods cm return if cm.method_list.empty? report = [] cm.each_method do |method| next if method.documented? and @coverage_level.zero? if @coverage_level > 0 then params, undoc = undoc_params method @num_params += params unless undoc.empty? then @undoc_params += undoc.length undoc = undoc.map do |param| "+#{param}+" end param_report = " # #{undoc.join ', '} is not documented\n" end end next if method.documented? and not param_report line = method.line ? ":#{method.line}" : nil scope = method.singleton ? 'self.' : nil report << " # in file #{method.file.full_name}#{line}\n" report << param_report if param_report report << " def #{scope}#{method.name}#{method.params}; end\n" report << "\n" end report end ## # Returns a summary of the collected statistics. def summary calculate num_width = [@num_files, @num_items].max.to_s.length undoc_width = [ @undoc_attributes, @undoc_classes, @undoc_constants, @undoc_items, @undoc_methods, @undoc_modules, @undoc_params, ].max.to_s.length report = RDoc::Markup::Verbatim.new report << "Files: %*d\n" % [num_width, @num_files] report << "\n" report << "Classes: %*d (%*d undocumented)\n" % [ num_width, @num_classes, undoc_width, @undoc_classes] report << "Modules: %*d (%*d undocumented)\n" % [ num_width, @num_modules, undoc_width, @undoc_modules] report << "Constants: %*d (%*d undocumented)\n" % [ num_width, @num_constants, undoc_width, @undoc_constants] report << "Attributes: %*d (%*d undocumented)\n" % [ num_width, @num_attributes, undoc_width, @undoc_attributes] report << "Methods: %*d (%*d undocumented)\n" % [ num_width, @num_methods, undoc_width, @undoc_methods] report << "Parameters: %*d (%*d undocumented)\n" % [ num_width, @num_params, undoc_width, @undoc_params] if @coverage_level > 0 report << "\n" report << "Total: %*d (%*d undocumented)\n" % [ num_width, @num_items, undoc_width, @undoc_items] report << "%6.2f%% documented\n" % percent_doc report << "\n" report << "Elapsed: %0.1fs\n" % (Time.now - @start) RDoc::Markup::Document.new report end ## # Determines which parameters in +method+ were not documented. Returns a # total parameter count and an Array of undocumented methods. def undoc_params method @formatter ||= RDoc::Markup::ToTtOnly.new params = method.param_list params = params.map { |param| param.gsub(/^\*\*?/, '') } return 0, [] if params.empty? document = parse method.comment tts = document.accept @formatter undoc = params - tts [params.length, undoc] end autoload :Quiet, 'rdoc/stats/quiet' autoload :Normal, 'rdoc/stats/normal' autoload :Verbose, 'rdoc/stats/verbose' end PKu] $rdoc-6.2.1.1/lib/rdoc/parser/ruby.rbnu[# frozen_string_literal: true ## # This file contains stuff stolen outright from: # # rtags.rb - # ruby-lex.rb - ruby lexcal analyzer # ruby-token.rb - ruby tokens # by Keiju ISHITSUKA (Nippon Rational Inc.) # ## # Extracts code elements from a source file returning a TopLevel object # containing the constituent file elements. # # This file is based on rtags # # RubyParser understands how to document: # * classes # * modules # * methods # * constants # * aliases # * private, public, protected # * private_class_function, public_class_function # * private_constant, public_constant # * module_function # * attr, attr_reader, attr_writer, attr_accessor # * extra accessors given on the command line # * metaprogrammed methods # * require # * include # # == Method Arguments # #-- # NOTE: I don't think this works, needs tests, remove the paragraph following # this block when known to work # # The parser extracts the arguments from the method definition. You can # override this with a custom argument definition using the :args: directive: # # ## # # This method tries over and over until it is tired # # def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try # puts thing_to_try # go_go_go thing_to_try, tries - 1 # end # # If you have a more-complex set of overrides you can use the :call-seq: # directive: #++ # # The parser extracts the arguments from the method definition. You can # override this with a custom argument definition using the :call-seq: # directive: # # ## # # This method can be called with a range or an offset and length # # # # :call-seq: # # my_method(Range) # # my_method(offset, length) # # def my_method(*args) # end # # The parser extracts +yield+ expressions from method bodies to gather the # yielded argument names. If your method manually calls a block instead of # yielding or you want to override the discovered argument names use # the :yields: directive: # # ## # # My method is awesome # # def my_method(&block) # :yields: happy, times # block.call 1, 2 # end # # == Metaprogrammed Methods # # To pick up a metaprogrammed method, the parser looks for a comment starting # with '##' before an identifier: # # ## # # This is a meta-programmed method! # # add_my_method :meta_method, :arg1, :arg2 # # The parser looks at the token after the identifier to determine the name, in # this example, :meta_method. If a name cannot be found, a warning is printed # and 'unknown is used. # # You can force the name of a method using the :method: directive: # # ## # # :method: some_method! # # By default, meta-methods are instance methods. To indicate that a method is # a singleton method instead use the :singleton-method: directive: # # ## # # :singleton-method: # # You can also use the :singleton-method: directive with a name: # # ## # # :singleton-method: some_method! # # You can define arguments for metaprogrammed methods via either the # :call-seq:, :arg: or :args: directives. # # Additionally you can mark a method as an attribute by # using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like # for :method:, the name is optional. # # ## # # :attr_reader: my_attr_name # # == Hidden methods and attributes # # You can provide documentation for methods that don't appear using # the :method:, :singleton-method: and :attr: directives: # # ## # # :attr_writer: ghost_writer # # There is an attribute here, but you can't see it! # # ## # # :method: ghost_method # # There is a method here, but you can't see it! # # ## # # this is a comment for a regular method # # def regular_method() end # # Note that by default, the :method: directive will be ignored if there is a # standard rdocable item following it. require 'ripper' require_relative 'ripper_state_lex' class RDoc::Parser::Ruby < RDoc::Parser parse_files_matching(/\.rbw?$/) include RDoc::TokenStream include RDoc::Parser::RubyTools ## # RDoc::NormalClass type NORMAL = "::" ## # RDoc::SingleClass type SINGLE = "<<" ## # Creates a new Ruby parser. def initialize(top_level, file_name, content, options, stats) super if /\t/ =~ content then tab_width = @options.tab_width content = content.split(/\n/).map do |line| 1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width) } && $~ line end.join("\n") end @size = 0 @token_listeners = nil content = RDoc::Encoding.remove_magic_comment content @scanner = RDoc::Parser::RipperStateLex.parse(content) @content = content @scanner_point = 0 @prev_seek = nil @markup = @options.markup @track_visibility = :nodoc != @options.visibility @encoding = @options.encoding reset end def tk_nl?(tk) :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind] end ## # Retrieves the read token stream and replaces +pattern+ with +replacement+ # using gsub. If the result is only a ";" returns an empty string. def get_tkread_clean pattern, replacement # :nodoc: read = get_tkread.gsub(pattern, replacement).strip return '' if read == ';' read end ## # Extracts the visibility information for the visibility token +tk+ # and +single+ class type identifier. # # Returns the visibility type (a string), the visibility (a symbol) and # +singleton+ if the methods following should be converted to singleton # methods. def get_visibility_information tk, single # :nodoc: vis_type = tk[:text] singleton = single == SINGLE vis = case vis_type when 'private' then :private when 'protected' then :protected when 'public' then :public when 'private_class_method' then singleton = true :private when 'public_class_method' then singleton = true :public when 'module_function' then singleton = true :public else raise RDoc::Error, "Invalid visibility: #{tk.name}" end return vis_type, vis, singleton end ## # Look for the first comment in a file that isn't a shebang line. def collect_first_comment skip_tkspace comment = ''.dup comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding first_line = true first_comment_tk_kind = nil line_no = nil tk = get_tk while tk && (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) comment_body = retrieve_comment_body(tk) if first_line and comment_body =~ /\A#!/ then skip_tkspace tk = get_tk elsif first_line and comment_body =~ /\A#\s*-\*-/ then first_line = false skip_tkspace tk = get_tk else break if first_comment_tk_kind and not first_comment_tk_kind === tk[:kind] first_comment_tk_kind = tk[:kind] line_no = tk[:line_no] if first_line first_line = false comment << comment_body tk = get_tk if :on_nl === tk then skip_tkspace_without_nl tk = get_tk end end end unget_tk tk new_comment comment, line_no end ## # Consumes trailing whitespace from the token stream def consume_trailing_spaces # :nodoc: skip_tkspace_without_nl end ## # Creates a new attribute in +container+ with +name+. def create_attr container, single, name, rw, comment # :nodoc: att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE record_location att container.add_attribute att @stats.add_attribute att att end ## # Creates a module alias in +container+ at +rhs_name+ (or at the top-level # for "::") with the name from +constant+. def create_module_alias container, constant, rhs_name # :nodoc: mod = if rhs_name =~ /^::/ then @store.find_class_or_module rhs_name else container.find_module_named rhs_name end container.add_module_alias mod, rhs_name, constant, @top_level end ## # Aborts with +msg+ def error(msg) msg = make_message msg abort msg end ## # Looks for a true or false token. def get_bool skip_tkspace tk = get_tk if :on_kw == tk[:kind] && 'true' == tk[:text] true elsif :on_kw == tk[:kind] && ('false' == tk[:text] || 'nil' == tk[:text]) false else unget_tk tk true end end ## # Look for the name of a class of module (optionally with a leading :: or # with :: separated named) and return the ultimate name, the associated # container, and the given name (with the ::). def get_class_or_module container, ignore_constants = false skip_tkspace name_t = get_tk given_name = ''.dup # class ::A -> A is in the top level if :on_op == name_t[:kind] and '::' == name_t[:text] then # bug name_t = get_tk container = @top_level given_name << '::' end skip_tkspace_without_nl given_name << name_t[:text] is_self = name_t[:kind] == :on_op && name_t[:text] == '<<' new_modules = [] while !is_self && (tk = peek_tk) and :on_op == tk[:kind] and '::' == tk[:text] do prev_container = container container = container.find_module_named name_t[:text] container ||= if ignore_constants then c = RDoc::NormalModule.new name_t[:text] c.store = @store new_modules << [prev_container, c] c else c = prev_container.add_module RDoc::NormalModule, name_t[:text] c.ignore unless prev_container.document_children @top_level.add_to_classes_or_modules c c end record_location container get_tk skip_tkspace if :on_lparen == peek_tk[:kind] # ProcObjectInConstant::() parse_method_or_yield_parameters break end name_t = get_tk unless :on_const == name_t[:kind] || :on_ident == name_t[:kind] raise RDoc::Error, "Invalid class or module definition: #{given_name}" end if prev_container == container and !ignore_constants given_name = name_t[:text] else given_name << '::' + name_t[:text] end end skip_tkspace_without_nl return [container, name_t, given_name, new_modules] end ## # Return a superclass, which can be either a constant of an expression def get_class_specification tk = peek_tk if tk.nil? return '' elsif :on_kw == tk[:kind] && 'self' == tk[:text] return 'self' elsif :on_gvar == tk[:kind] return '' end res = get_constant skip_tkspace_without_nl get_tkread # empty out read buffer tk = get_tk return res unless tk case tk[:kind] when :on_nl, :on_comment, :on_embdoc, :on_semicolon then unget_tk(tk) return res end res += parse_call_parameters(tk) res end ## # Parse a constant, which might be qualified by one or more class or module # names def get_constant res = "" skip_tkspace_without_nl tk = get_tk while tk && ((:on_op == tk[:kind] && '::' == tk[:text]) || :on_const == tk[:kind]) do res += tk[:text] tk = get_tk end unget_tk(tk) res end ## # Get an included module that may be surrounded by parens def get_included_module_with_optional_parens skip_tkspace_without_nl get_tkread tk = get_tk end_token = get_end_token tk return '' unless end_token nest = 0 continue = false only_constant = true while tk != nil do is_element_of_constant = false case tk[:kind] when :on_semicolon then break if nest == 0 when :on_lbracket then nest += 1 when :on_rbracket then nest -= 1 when :on_lbrace then nest += 1 when :on_rbrace then nest -= 1 if nest <= 0 # we might have a.each { |i| yield i } unget_tk(tk) if nest < 0 break end when :on_lparen then nest += 1 when end_token[:kind] then if end_token[:kind] == :on_rparen nest -= 1 break if nest <= 0 else break if nest <= 0 end when :on_rparen then nest -= 1 when :on_comment, :on_embdoc then @read.pop if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and (!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then break if !continue and nest <= 0 end when :on_comma then continue = true when :on_ident then continue = false if continue when :on_kw then case tk[:text] when 'def', 'do', 'case', 'for', 'begin', 'class', 'module' nest += 1 when 'if', 'unless', 'while', 'until', 'rescue' # postfix if/unless/while/until/rescue must be EXPR_LABEL nest += 1 unless (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0 when 'end' nest -= 1 break if nest == 0 end when :on_const then is_element_of_constant = true when :on_op then is_element_of_constant = true if '::' == tk[:text] end only_constant = false unless is_element_of_constant tk = get_tk end if only_constant get_tkread_clean(/\s+/, ' ') else '' end end ## # Little hack going on here. In the statement: # # f = 2*(1+yield) # # We see the RPAREN as the next token, so we need to exit early. This still # won't catch all cases (such as "a = yield + 1" def get_end_token tk # :nodoc: case tk[:kind] when :on_lparen token = RDoc::Parser::RipperStateLex::Token.new token[:kind] = :on_rparen token[:text] = ')' token when :on_rparen nil else token = RDoc::Parser::RipperStateLex::Token.new token[:kind] = :on_nl token[:text] = "\n" token end end ## # Retrieves the method container for a singleton method. def get_method_container container, name_t # :nodoc: prev_container = container container = container.find_module_named(name_t[:text]) unless container then constant = prev_container.constants.find do |const| const.name == name_t[:text] end if constant then parse_method_dummy prev_container return end end unless container then # TODO seems broken, should starting at Object in @store obj = name_t[:text].split("::").inject(Object) do |state, item| state.const_get(item) end rescue nil type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule unless [Class, Module].include?(obj.class) then warn("Couldn't find #{name_t[:text]}. Assuming it's a module") end if type == RDoc::NormalClass then sclass = obj.superclass ? obj.superclass.name : nil container = prev_container.add_class type, name_t[:text], sclass else container = prev_container.add_module type, name_t[:text] end record_location container end container end ## # Extracts a name or symbol from the token stream. def get_symbol_or_name tk = get_tk case tk[:kind] when :on_symbol then text = tk[:text].sub(/^:/, '') next_tk = peek_tk if next_tk && :on_op == next_tk[:kind] && '=' == next_tk[:text] then get_tk text << '=' end text when :on_ident, :on_const, :on_gvar, :on_cvar, :on_ivar, :on_op, :on_kw then tk[:text] when :on_tstring, :on_dstring then tk[:text][1..-2] else raise RDoc::Error, "Name or symbol expected (got #{tk})" end end ## # Marks containers between +container+ and +ancestor+ as ignored def suppress_parents container, ancestor # :nodoc: while container and container != ancestor do container.suppress unless container.documented? container = container.parent end end ## # Look for directives in a normal comment block: # # # :stopdoc: # # Don't display comment from this point forward # # This routine modifies its +comment+ parameter. def look_for_directives_in container, comment @preprocess.handle comment, container do |directive, param| case directive when 'method', 'singleton-method', 'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then false # handled elsewhere when 'section' then break unless container.kind_of?(RDoc::Context) container.set_current_section param, comment.dup comment.text = '' break end end comment.remove_private end ## # Adds useful info about the parser to +message+ def make_message message prefix = "#{@file_name}:".dup tk = peek_tk prefix << "#{tk[:line_no]}:#{tk[:char_no]}:" if tk "#{prefix} #{message}" end ## # Creates a comment with the correct format def new_comment comment, line_no = nil c = RDoc::Comment.new comment, @top_level, :ruby c.line = line_no c.format = @markup c end ## # Creates an RDoc::Attr for the name following +tk+, setting the comment to # +comment+. def parse_attr(context, single, tk, comment) line_no = tk[:line_no] args = parse_symbol_arg 1 if args.size > 0 then name = args[0] rw = "R" skip_tkspace_without_nl tk = get_tk if :on_comma == tk[:kind] then rw = "RW" if get_bool else unget_tk tk end att = create_attr context, single, name, rw, comment att.line = line_no read_documentation_modifiers att, RDoc::ATTR_MODIFIERS else warn "'attr' ignored - looks like a variable" end end ## # Creates an RDoc::Attr for each attribute listed after +tk+, setting the # comment for each to +comment+. def parse_attr_accessor(context, single, tk, comment) line_no = tk[:line_no] args = parse_symbol_arg rw = "?" tmp = RDoc::CodeObject.new read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS # TODO In most other places we let the context keep track of document_self # and add found items appropriately but here we do not. I'm not sure why. return if @track_visibility and not tmp.document_self case tk[:text] when "attr_reader" then rw = "R" when "attr_writer" then rw = "W" when "attr_accessor" then rw = "RW" else rw = '?' end for name in args att = create_attr context, single, name, rw, comment att.line = line_no end end ## # Parses an +alias+ in +context+ with +comment+ def parse_alias(context, single, tk, comment) line_no = tk[:line_no] skip_tkspace if :on_lparen === peek_tk[:kind] then get_tk skip_tkspace end new_name = get_symbol_or_name skip_tkspace if :on_comma === peek_tk[:kind] then get_tk skip_tkspace end begin old_name = get_symbol_or_name rescue RDoc::Error return end al = RDoc::Alias.new(get_tkread, old_name, new_name, comment, single == SINGLE) record_location al al.line = line_no read_documentation_modifiers al, RDoc::ATTR_MODIFIERS context.add_alias al @stats.add_alias al al end ## # Extracts call parameters from the token stream. def parse_call_parameters(tk) end_token = case tk[:kind] when :on_lparen :on_rparen when :on_rparen return "" else :on_nl end nest = 0 loop do break if tk.nil? case tk[:kind] when :on_semicolon break when :on_lparen nest += 1 when end_token if end_token == :on_rparen nest -= 1 break if RDoc::Parser::RipperStateLex.end?(tk) and nest <= 0 else break if RDoc::Parser::RipperStateLex.end?(tk) end when :on_comment, :on_embdoc unget_tk(tk) break when :on_op if tk[:text] =~ /^(.{1,2})?=$/ unget_tk(tk) break end end tk = get_tk end get_tkread_clean "\n", " " end ## # Parses a class in +context+ with +comment+ def parse_class container, single, tk, comment line_no = tk[:line_no] declaration_context = container container, name_t, given_name, = get_class_or_module container if name_t[:kind] == :on_const cls = parse_class_regular container, declaration_context, single, name_t, given_name, comment elsif name_t[:kind] == :on_op && name_t[:text] == '<<' case name = get_class_specification when 'self', container.name read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS parse_statements container, SINGLE return # don't update line else cls = parse_class_singleton container, name, comment end else warn "Expected class name or '<<'. Got #{name_t[:kind]}: #{name_t[:text].inspect}" return end cls.line = line_no # after end modifiers read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS cls end ## # Parses and creates a regular class def parse_class_regular container, declaration_context, single, # :nodoc: name_t, given_name, comment superclass = '::Object' if given_name =~ /^::/ then declaration_context = @top_level given_name = $' end tk = peek_tk if tk[:kind] == :on_op && tk[:text] == '<' then get_tk skip_tkspace superclass = get_class_specification superclass = '(unknown)' if superclass.empty? end cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass cls = declaration_context.add_class cls_type, given_name, superclass cls.ignore unless container.document_children read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS record_location cls cls.add_comment comment, @top_level @top_level.add_to_classes_or_modules cls @stats.add_class cls suppress_parents container, declaration_context unless cls.document_self parse_statements cls cls end ## # Parses a singleton class in +container+ with the given +name+ and # +comment+. def parse_class_singleton container, name, comment # :nodoc: other = @store.find_class_named name unless other then if name =~ /^::/ then name = $' container = @top_level end other = container.add_module RDoc::NormalModule, name record_location other # class << $gvar other.ignore if name.empty? other.add_comment comment, @top_level end # notify :nodoc: all if not a constant-named class/module # (and remove any comment) unless name =~ /\A(::)?[A-Z]/ then other.document_self = nil other.document_children = false other.clear_comment end @top_level.add_to_classes_or_modules other @stats.add_class other read_documentation_modifiers other, RDoc::CLASS_MODIFIERS parse_statements(other, SINGLE) other end ## # Parses a constant in +context+ with +comment+. If +ignore_constants+ is # true, no found constants will be added to RDoc. def parse_constant container, tk, comment, ignore_constants = false line_no = tk[:line_no] name = tk[:text] skip_tkspace_without_nl return unless name =~ /^\w+$/ new_modules = [] if :on_op == peek_tk[:kind] && '::' == peek_tk[:text] then unget_tk tk container, name_t, _, new_modules = get_class_or_module container, true name = name_t[:text] end is_array_or_hash = false if peek_tk && :on_lbracket == peek_tk[:kind] get_tk nest = 1 while bracket_tk = get_tk case bracket_tk[:kind] when :on_lbracket nest += 1 when :on_rbracket nest -= 1 break if nest == 0 end end skip_tkspace_without_nl is_array_or_hash = true end unless peek_tk && :on_op == peek_tk[:kind] && '=' == peek_tk[:text] then return false end get_tk unless ignore_constants new_modules.each do |prev_c, new_module| prev_c.add_module_by_normal_module new_module new_module.ignore unless prev_c.document_children @top_level.add_to_classes_or_modules new_module end end value = '' con = RDoc::Constant.new name, value, comment body = parse_constant_body container, con, is_array_or_hash return unless body con.value = body record_location con con.line = line_no read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS return if is_array_or_hash @stats.add_constant con container.add_constant con true end def parse_constant_body container, constant, is_array_or_hash # :nodoc: nest = 0 rhs_name = ''.dup get_tkread tk = get_tk body = nil loop do break if tk.nil? if :on_semicolon == tk[:kind] then break if nest <= 0 elsif [:on_tlambeg, :on_lparen, :on_lbrace, :on_lbracket].include?(tk[:kind]) then nest += 1 elsif (:on_kw == tk[:kind] && 'def' == tk[:text]) then nest += 1 elsif (:on_kw == tk[:kind] && %w{do if unless case begin}.include?(tk[:text])) then if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0 nest += 1 end elsif [:on_rparen, :on_rbrace, :on_rbracket].include?(tk[:kind]) || (:on_kw == tk[:kind] && 'end' == tk[:text]) then nest -= 1 elsif (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) then unget_tk tk if nest <= 0 and RDoc::Parser::RipperStateLex.end?(tk) then body = get_tkread_clean(/^[ \t]+/, '') read_documentation_modifiers constant, RDoc::CONSTANT_MODIFIERS break else read_documentation_modifiers constant, RDoc::CONSTANT_MODIFIERS end elsif :on_const == tk[:kind] then rhs_name << tk[:text] next_tk = peek_tk if nest <= 0 and (next_tk.nil? || :on_nl == next_tk[:kind]) then create_module_alias container, constant, rhs_name unless is_array_or_hash break end elsif :on_nl == tk[:kind] then if nest <= 0 and RDoc::Parser::RipperStateLex.end?(tk) then unget_tk tk break end elsif :on_op == tk[:kind] && '::' == tk[:text] rhs_name << '::' end tk = get_tk end body ? body : get_tkread_clean(/^[ \t]+/, '') end ## # Generates an RDoc::Method or RDoc::Attr from +comment+ by looking for # :method: or :attr: directives in +comment+. def parse_comment container, tk, comment return parse_comment_tomdoc container, tk, comment if @markup == 'tomdoc' column = tk[:char_no] line_no = comment.line.nil? ? tk[:line_no] : comment.line comment.text = comment.text.sub(/(^# +:?)(singleton-)(method:)/, '\1\3') singleton = !!$~ co = if (comment.text = comment.text.sub(/^# +:?method: *(\S*).*?\n/i, '')) && !!$~ then line_no += $`.count("\n") parse_comment_ghost container, comment.text, $1, column, line_no, comment elsif (comment.text = comment.text.sub(/# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '')) && !!$~ then parse_comment_attr container, $1, $3, comment end if co then co.singleton = singleton co.line = line_no end true end ## # Parse a comment that is describing an attribute in +container+ with the # given +name+ and +comment+. def parse_comment_attr container, type, name, comment # :nodoc: return if name.empty? rw = case type when 'attr_reader' then 'R' when 'attr_writer' then 'W' else 'RW' end create_attr container, NORMAL, name, rw, comment end def parse_comment_ghost container, text, name, column, line_no, # :nodoc: comment name = nil if name.empty? meth = RDoc::GhostMethod.new get_tkread, name record_location meth meth.start_collecting_tokens indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column) position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment) position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}" newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n") meth.add_tokens [position_comment, newline, indent] meth.params = if text.sub!(/^#\s+:?args?:\s*(.*?)\s*$/i, '') then $1 else '' end comment.normalize comment.extract_call_seq meth return unless meth.name container.add_method meth meth.comment = comment @stats.add_method meth meth end ## # Creates an RDoc::Method on +container+ from +comment+ if there is a # Signature section in the comment def parse_comment_tomdoc container, tk, comment return unless signature = RDoc::TomDoc.signature(comment) column = tk[:char_no] line_no = tk[:line_no] name, = signature.split %r%[ \(]%, 2 meth = RDoc::GhostMethod.new get_tkread, name record_location meth meth.line = line_no meth.start_collecting_tokens indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column) position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment) position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}" newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n") meth.add_tokens [position_comment, newline, indent] meth.call_seq = signature comment.normalize return unless meth.name container.add_method meth meth.comment = comment @stats.add_method meth end ## # Parses an +include+ or +extend+, indicated by the +klass+ and adds it to # +container+ # with +comment+ def parse_extend_or_include klass, container, comment # :nodoc: loop do skip_tkspace_comment name = get_included_module_with_optional_parens unless name.empty? then obj = container.add klass, name, comment record_location obj end return if peek_tk.nil? || :on_comma != peek_tk[:kind] get_tk end end ## # Parses identifiers that can create new methods or change visibility. # # Returns true if the comment was not consumed. def parse_identifier container, single, tk, comment # :nodoc: case tk[:text] when 'private', 'protected', 'public', 'private_class_method', 'public_class_method', 'module_function' then parse_visibility container, single, tk return true when 'private_constant', 'public_constant' parse_constant_visibility container, single, tk return true when 'attr' then parse_attr container, single, tk, comment when /^attr_(reader|writer|accessor)$/ then parse_attr_accessor container, single, tk, comment when 'alias_method' then parse_alias container, single, tk, comment when 'require', 'include' then # ignore else if comment.text =~ /\A#\#$/ then case comment.text when /^# +:?attr(_reader|_writer|_accessor)?:/ then parse_meta_attr container, single, tk, comment else method = parse_meta_method container, single, tk, comment method.params = container.params if container.params method.block_params = container.block_params if container.block_params end end end false end ## # Parses a meta-programmed attribute and creates an RDoc::Attr. # # To create foo and bar attributes on class C with comment "My attributes": # # class C # # ## # # :attr: # # # # My attributes # # my_attr :foo, :bar # # end # # To create a foo attribute on class C with comment "My attribute": # # class C # # ## # # :attr: foo # # # # My attribute # # my_attr :foo, :bar # # end def parse_meta_attr(context, single, tk, comment) args = parse_symbol_arg rw = "?" # If nodoc is given, don't document any of them tmp = RDoc::CodeObject.new read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS regexp = /^# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i if regexp =~ comment.text then comment.text = comment.text.sub(regexp, '') rw = case $1 when 'attr_reader' then 'R' when 'attr_writer' then 'W' else 'RW' end name = $3 unless $3.empty? end if name then att = create_attr context, single, name, rw, comment else args.each do |attr_name| att = create_attr context, single, attr_name, rw, comment end end att end ## # Parses a meta-programmed method def parse_meta_method(container, single, tk, comment) column = tk[:char_no] line_no = tk[:line_no] start_collecting_tokens add_token tk add_token_listener self skip_tkspace_without_nl comment.text = comment.text.sub(/(^# +:?)(singleton-)(method:)/, '\1\3') singleton = !!$~ name = parse_meta_method_name comment, tk return unless name meth = RDoc::MetaMethod.new get_tkread, name record_location meth meth.line = line_no meth.singleton = singleton remove_token_listener self meth.start_collecting_tokens indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column) position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment) position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}" newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n") meth.add_tokens [position_comment, newline, indent] meth.add_tokens @token_stream parse_meta_method_params container, single, meth, tk, comment meth.comment = comment @stats.add_method meth meth end ## # Parses the name of a metaprogrammed method. +comment+ is used to # determine the name while +tk+ is used in an error message if the name # cannot be determined. def parse_meta_method_name comment, tk # :nodoc: if comment.text.sub!(/^# +:?method: *(\S*).*?\n/i, '') then return $1 unless $1.empty? end name_t = get_tk if :on_symbol == name_t[:kind] then name_t[:text][1..-1] elsif :on_tstring == name_t[:kind] then name_t[:text][1..-2] elsif :on_op == name_t[:kind] && '=' == name_t[:text] then # ignore remove_token_listener self nil else warn "unknown name token #{name_t.inspect} for meta-method '#{tk[:text]}'" 'unknown' end end ## # Parses the parameters and block for a meta-programmed method. def parse_meta_method_params container, single, meth, tk, comment # :nodoc: token_listener meth do meth.params = '' look_for_directives_in meth, comment comment.normalize comment.extract_call_seq meth container.add_method meth last_tk = tk while tk = get_tk do if :on_semicolon == tk[:kind] then break elsif :on_nl == tk[:kind] then break unless last_tk and :on_comma == last_tk[:kind] elsif :on_sp == tk[:kind] then # expression continues elsif :on_kw == tk[:kind] && 'do' == tk[:text] then parse_statements container, single, meth break else last_tk = tk end end end end ## # Parses a normal method defined by +def+ def parse_method(container, single, tk, comment) singleton = nil added_container = false name = nil column = tk[:char_no] line_no = tk[:line_no] start_collecting_tokens add_token tk token_listener self do prev_container = container name, container, singleton = parse_method_name container added_container = container != prev_container end return unless name meth = RDoc::AnyMethod.new get_tkread, name look_for_directives_in meth, comment meth.singleton = single == SINGLE ? true : singleton record_location meth meth.line = line_no meth.start_collecting_tokens indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column) token = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment) token[:text] = "# File #{@top_level.relative_name}, line #{line_no}" newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n") meth.add_tokens [token, newline, indent] meth.add_tokens @token_stream parse_method_params_and_body container, single, meth, added_container comment.normalize comment.extract_call_seq meth meth.comment = comment # after end modifiers read_documentation_modifiers meth, RDoc::METHOD_MODIFIERS @stats.add_method meth end ## # Parses the parameters and body of +meth+ def parse_method_params_and_body container, single, meth, added_container token_listener meth do parse_method_parameters meth if meth.document_self or not @track_visibility then container.add_method meth elsif added_container then container.document_self = false end # Having now read the method parameters and documentation modifiers, we # now know whether we have to rename #initialize to ::new if meth.name == "initialize" && !meth.singleton then if meth.dont_rename_initialize then meth.visibility = :protected else meth.singleton = true meth.name = "new" meth.visibility = :public end end parse_statements container, single, meth end end ## # Parses a method that needs to be ignored. def parse_method_dummy container dummy = RDoc::Context.new dummy.parent = container dummy.store = container.store skip_method dummy end ## # Parses the name of a method in +container+. # # Returns the method name, the container it is in (for def Foo.name) and if # it is a singleton or regular method. def parse_method_name container # :nodoc: skip_tkspace name_t = get_tk back_tk = skip_tkspace_without_nl singleton = false dot = get_tk if dot[:kind] == :on_period || (dot[:kind] == :on_op && dot[:text] == '::') then singleton = true name, container = parse_method_name_singleton container, name_t else unget_tk dot back_tk.reverse_each do |token| unget_tk token end name = parse_method_name_regular container, name_t end return name, container, singleton end ## # For the given +container+ and initial name token +name_t+ the method name # is parsed from the token stream for a regular method. def parse_method_name_regular container, name_t # :nodoc: if :on_op == name_t[:kind] && (%w{* & [] []= <<}.include?(name_t[:text])) then name_t[:text] else unless [:on_kw, :on_const, :on_ident].include?(name_t[:kind]) then warn "expected method name token, . or ::, got #{name_t.inspect}" skip_method container return end name_t[:text] end end ## # For the given +container+ and initial name token +name_t+ the method name # and the new +container+ (if necessary) are parsed from the token stream # for a singleton method. def parse_method_name_singleton container, name_t # :nodoc: skip_tkspace name_t2 = get_tk if (:on_kw == name_t[:kind] && 'self' == name_t[:text]) || (:on_op == name_t[:kind] && '%' == name_t[:text]) then # NOTE: work around '[' being consumed early if :on_lbracket == name_t2[:kind] get_tk name = '[]' else name = name_t2[:text] end elsif :on_const == name_t[:kind] then name = name_t2[:text] container = get_method_container container, name_t return unless container name elsif :on_ident == name_t[:kind] || :on_ivar == name_t[:kind] || :on_gvar == name_t[:kind] then parse_method_dummy container name = nil elsif (:on_kw == name_t[:kind]) && ('true' == name_t[:text] || 'false' == name_t[:text] || 'nil' == name_t[:text]) then klass_name = "#{name_t[:text].capitalize}Class" container = @store.find_class_named klass_name container ||= @top_level.add_class RDoc::NormalClass, klass_name name = name_t2[:text] else warn "unexpected method name token #{name_t.inspect}" # break skip_method container name = nil end return name, container end ## # Extracts +yield+ parameters from +method+ def parse_method_or_yield_parameters(method = nil, modifiers = RDoc::METHOD_MODIFIERS) skip_tkspace_without_nl tk = get_tk end_token = get_end_token tk return '' unless end_token nest = 0 continue = false while tk != nil do case tk[:kind] when :on_semicolon then break if nest == 0 when :on_lbracket then nest += 1 when :on_rbracket then nest -= 1 when :on_lbrace then nest += 1 when :on_rbrace then nest -= 1 if nest <= 0 # we might have a.each { |i| yield i } unget_tk(tk) if nest < 0 break end when :on_lparen then nest += 1 when end_token[:kind] then if end_token[:kind] == :on_rparen nest -= 1 break if nest <= 0 else break end when :on_rparen then nest -= 1 when :on_comment, :on_embdoc then @read.pop if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and (!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then if method && method.block_params.nil? then unget_tk tk read_documentation_modifiers method, modifiers end break if !continue and nest <= 0 end when :on_comma then continue = true when :on_ident then continue = false if continue end tk = get_tk end get_tkread_clean(/\s+/, ' ') end ## # Capture the method's parameters. Along the way, look for a comment # containing: # # # yields: .... # # and add this as the block_params for the method def parse_method_parameters method res = parse_method_or_yield_parameters method res = "(#{res})" unless res =~ /\A\(/ method.params = res unless method.params return if method.block_params skip_tkspace_without_nl read_documentation_modifiers method, RDoc::METHOD_MODIFIERS end ## # Parses an RDoc::NormalModule in +container+ with +comment+ def parse_module container, single, tk, comment container, name_t, = get_class_or_module container name = name_t[:text] mod = container.add_module RDoc::NormalModule, name mod.ignore unless container.document_children record_location mod read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS mod.add_comment comment, @top_level parse_statements mod # after end modifiers read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS @stats.add_module mod end ## # Parses an RDoc::Require in +context+ containing +comment+ def parse_require(context, comment) skip_tkspace_comment tk = get_tk if :on_lparen == tk[:kind] then skip_tkspace_comment tk = get_tk end name = tk[:text][1..-2] if :on_tstring == tk[:kind] if name then @top_level.add_require RDoc::Require.new(name, comment) else unget_tk tk end end ## # Parses a rescue def parse_rescue skip_tkspace_without_nl while tk = get_tk case tk[:kind] when :on_nl, :on_semicolon, :on_comment then break when :on_comma then skip_tkspace_without_nl get_tk if :on_nl == peek_tk[:kind] end skip_tkspace_without_nl end end ## # Retrieve comment body without =begin/=end def retrieve_comment_body(tk) if :on_embdoc == tk[:kind] tk[:text].gsub(/\A=begin.*\n/, '').gsub(/=end\n?\z/, '') else tk[:text] end end ## # The core of the Ruby parser. def parse_statements(container, single = NORMAL, current_method = nil, comment = new_comment('')) raise 'no' unless RDoc::Comment === comment comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding nest = 1 save_visibility = container.visibility non_comment_seen = true while tk = get_tk do keep_comment = false try_parse_comment = false non_comment_seen = true unless (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) case tk[:kind] when :on_nl, :on_ignored_nl, :on_comment, :on_embdoc then if :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind] skip_tkspace tk = get_tk else past_tokens = @read.size > 1 ? @read[0..-2] : [] nl_position = 0 past_tokens.reverse.each_with_index do |read_tk, i| if read_tk =~ /^\n$/ then nl_position = (past_tokens.size - 1) - i break elsif read_tk =~ /^#.*\n$/ then nl_position = ((past_tokens.size - 1) - i) + 1 break end end comment_only_line = past_tokens[nl_position..-1].all?{ |c| c =~ /^\s+$/ } unless comment_only_line then tk = get_tk end end if tk and (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) then if non_comment_seen then # Look for RDoc in a comment about to be thrown away non_comment_seen = parse_comment container, tk, comment unless comment.empty? comment = '' comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding end line_no = nil while tk and (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) do comment_body = retrieve_comment_body(tk) line_no = tk[:line_no] if comment.empty? comment += comment_body comment << "\n" unless comment_body =~ /\n\z/ if comment_body.size > 1 && comment_body =~ /\n\z/ then skip_tkspace_without_nl # leading spaces end tk = get_tk end comment = new_comment comment, line_no unless comment.empty? then look_for_directives_in container, comment if container.done_documenting then throw :eof if RDoc::TopLevel === container container.ongoing_visibility = save_visibility end end keep_comment = true else non_comment_seen = true end unget_tk tk keep_comment = true container.current_line_visibility = nil when :on_kw then case tk[:text] when 'class' then parse_class container, single, tk, comment when 'module' then parse_module container, single, tk, comment when 'def' then parse_method container, single, tk, comment when 'alias' then parse_alias container, single, tk, comment unless current_method when 'yield' then if current_method.nil? then warn "Warning: yield outside of method" if container.document_self else parse_yield container, single, tk, current_method end when 'until', 'while' then if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0 nest += 1 skip_optional_do_after_expression end # Until and While can have a 'do', which shouldn't increase the nesting. # We can't solve the general case, but we can handle most occurrences by # ignoring a do at the end of a line. # 'for' is trickier when 'for' then nest += 1 skip_for_variable skip_optional_do_after_expression when 'case', 'do', 'if', 'unless', 'begin' then if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0 nest += 1 end when 'super' then current_method.calls_super = true if current_method when 'rescue' then parse_rescue when 'end' then nest -= 1 if nest == 0 then container.ongoing_visibility = save_visibility parse_comment container, tk, comment unless comment.empty? return end end when :on_const then unless parse_constant container, tk, comment, current_method then try_parse_comment = true end when :on_ident then if nest == 1 and current_method.nil? then keep_comment = parse_identifier container, single, tk, comment end case tk[:text] when "require" then parse_require container, comment when "include" then parse_extend_or_include RDoc::Include, container, comment when "extend" then parse_extend_or_include RDoc::Extend, container, comment end else try_parse_comment = nest == 1 end if try_parse_comment then non_comment_seen = parse_comment container, tk, comment unless comment.empty? keep_comment = false end unless keep_comment then comment = new_comment '' comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding container.params = nil container.block_params = nil end consume_trailing_spaces end container.params = nil container.block_params = nil end ## # Parse up to +no+ symbol arguments def parse_symbol_arg(no = nil) skip_tkspace_comment tk = get_tk if tk[:kind] == :on_lparen parse_symbol_arg_paren no else parse_symbol_arg_space no, tk end end ## # Parses up to +no+ symbol arguments surrounded by () and places them in # +args+. def parse_symbol_arg_paren no # :nodoc: args = [] loop do skip_tkspace_comment if tk1 = parse_symbol_in_arg args.push tk1 break if no and args.size >= no end skip_tkspace_comment case (tk2 = get_tk)[:kind] when :on_rparen break when :on_comma else warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC break end end args end ## # Parses up to +no+ symbol arguments separated by spaces and places them in # +args+. def parse_symbol_arg_space no, tk # :nodoc: args = [] unget_tk tk if tk = parse_symbol_in_arg args.push tk return args if no and args.size >= no end loop do skip_tkspace_without_nl tk1 = get_tk if tk1.nil? || :on_comma != tk1[:kind] then unget_tk tk1 break end skip_tkspace_comment if tk = parse_symbol_in_arg args.push tk break if no and args.size >= no end end args end ## # Returns symbol text from the next token def parse_symbol_in_arg tk = get_tk if :on_symbol == tk[:kind] then tk[:text].sub(/^:/, '') elsif :on_tstring == tk[:kind] then tk[:text][1..-2] elsif :on_dstring == tk[:kind] or :on_ident == tk[:kind] then nil # ignore else warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC nil end end ## # Parses statements in the top-level +container+ def parse_top_level_statements container comment = collect_first_comment look_for_directives_in container, comment throw :eof if container.done_documenting @markup = comment.format # HACK move if to RDoc::Context#comment= container.comment = comment if container.document_self unless comment.empty? parse_statements container, NORMAL, nil, comment end ## # Determines the visibility in +container+ from +tk+ def parse_visibility(container, single, tk) vis_type, vis, singleton = get_visibility_information tk, single skip_tkspace_comment false ptk = peek_tk # Ryan Davis suggested the extension to ignore modifiers, because he # often writes # # protected unless $TESTING # if [:on_nl, :on_semicolon].include?(ptk[:kind]) || (:on_kw == ptk[:kind] && (['if', 'unless'].include?(ptk[:text]))) then container.ongoing_visibility = vis elsif :on_kw == ptk[:kind] && 'def' == ptk[:text] container.current_line_visibility = vis else update_visibility container, vis_type, vis, singleton end end ## # Parses a Module#private_constant or Module#public_constant call from +tk+. def parse_constant_visibility(container, single, tk) args = parse_symbol_arg case tk[:text] when 'private_constant' vis = :private when 'public_constant' vis = :public else raise RDoc::Error, 'Unreachable' end container.set_constant_visibility_for args, vis end ## # Determines the block parameter for +context+ def parse_yield(context, single, tk, method) return if method.block_params get_tkread method.block_params = parse_method_or_yield_parameters end ## # Directives are modifier comments that can appear after class, module, or # method names. For example: # # def fred # :yields: a, b # # or: # # class MyClass # :nodoc: # # We return the directive name and any parameters as a two element array if # the name is in +allowed+. A directive can be found anywhere up to the end # of the current line. def read_directive allowed tokens = [] while tk = get_tk do tokens << tk if :on_nl == tk[:kind] or (:on_kw == tk[:kind] && 'def' == tk[:text]) then return elsif :on_comment == tk[:kind] or :on_embdoc == tk[:kind] then return unless tk[:text] =~ /\s*:?([\w-]+):\s*(.*)/ directive = $1.downcase return [directive, $2] if allowed.include? directive return end end ensure unless tokens.length == 1 and (:on_comment == tokens.first[:kind] or :on_embdoc == tokens.first[:kind]) then tokens.reverse_each do |token| unget_tk token end end end ## # Handles directives following the definition for +context+ (any # RDoc::CodeObject) if the directives are +allowed+ at this point. # # See also RDoc::Markup::PreProcess#handle_directive def read_documentation_modifiers context, allowed skip_tkspace_without_nl directive, value = read_directive allowed return unless directive @preprocess.handle_directive '', directive, value, context do |dir, param| if %w[notnew not_new not-new].include? dir then context.dont_rename_initialize = true true end end end ## # Records the location of this +container+ in the file for this parser and # adds it to the list of classes and modules in the file. def record_location container # :nodoc: case container when RDoc::ClassModule then @top_level.add_to_classes_or_modules container end container.record_location @top_level end ## # Scans this Ruby file for Ruby constructs def scan reset catch :eof do begin parse_top_level_statements @top_level rescue StandardError => e if @content.include?('<%') and @content.include?('%>') then # Maybe, this is ERB. $stderr.puts "\033[2KRDoc detects ERB file. Skips it for compatibility:" $stderr.puts @file_name return end if @scanner_point >= @scanner.size now_line_no = @scanner[@scanner.size - 1][:line_no] else now_line_no = peek_tk[:line_no] end first_tk_index = @scanner.find_index { |tk| tk[:line_no] == now_line_no } last_tk_index = @scanner.find_index { |tk| tk[:line_no] == now_line_no + 1 } last_tk_index = last_tk_index ? last_tk_index - 1 : @scanner.size - 1 code = @scanner[first_tk_index..last_tk_index].map{ |t| t[:text] }.join $stderr.puts <<-EOF #{self.class} failure around line #{now_line_no} of #{@file_name} EOF unless code.empty? then $stderr.puts code $stderr.puts end raise e end end @top_level end ## # while, until, and for have an optional do def skip_optional_do_after_expression skip_tkspace_without_nl tk = get_tk b_nest = 0 nest = 0 loop do break unless tk case tk[:kind] when :on_semicolon, :on_nl, :on_ignored_nl then break if b_nest.zero? when :on_lparen then nest += 1 when :on_rparen then nest -= 1 when :on_kw then case tk[:text] when 'begin' b_nest += 1 when 'end' b_nest -= 1 when 'do' break if nest.zero? end when :on_comment, :on_embdoc then if b_nest.zero? and "\n" == tk[:text][-1] then break end end tk = get_tk end skip_tkspace_without_nl get_tk if peek_tk && :on_kw == peek_tk[:kind] && 'do' == peek_tk[:text] end ## # skip the var [in] part of a 'for' statement def skip_for_variable skip_tkspace_without_nl get_tk skip_tkspace_without_nl tk = get_tk unget_tk(tk) unless :on_kw == tk[:kind] and 'in' == tk[:text] end ## # Skips the next method in +container+ def skip_method container meth = RDoc::AnyMethod.new "", "anon" parse_method_parameters meth parse_statements container, false, meth end ## # Skip spaces until a comment is found def skip_tkspace_comment(skip_nl = true) loop do skip_nl ? skip_tkspace : skip_tkspace_without_nl next_tk = peek_tk return if next_tk.nil? || (:on_comment != next_tk[:kind] and :on_embdoc != next_tk[:kind]) get_tk end end ## # Updates visibility in +container+ from +vis_type+ and +vis+. def update_visibility container, vis_type, vis, singleton # :nodoc: new_methods = [] case vis_type when 'module_function' then args = parse_symbol_arg container.set_visibility_for args, :private, false container.methods_matching args do |m| s_m = m.dup record_location s_m s_m.singleton = true new_methods << s_m end when 'public_class_method', 'private_class_method' then args = parse_symbol_arg container.methods_matching args, true do |m| if m.parent != container then m = m.dup record_location m new_methods << m end m.visibility = vis end else args = parse_symbol_arg container.set_visibility_for args, vis, singleton end new_methods.each do |method| case method when RDoc::AnyMethod then container.add_method method when RDoc::Attr then container.add_attribute method end method.visibility = vis end end ## # Prints +message+ to +$stderr+ unless we're being quiet def warn message @options.warn make_message message end end PKu]:ܶ"rdoc-6.2.1.1/lib/rdoc/parser/rd.rbnu[# frozen_string_literal: true ## # Parse a RD format file. The parsed RDoc::Markup::Document is attached as a # file comment. class RDoc::Parser::RD < RDoc::Parser include RDoc::Parser::Text parse_files_matching(/\.rd(?:\.[^.]+)?$/) ## # Creates an rd-format TopLevel for the given file. def scan comment = RDoc::Comment.new @content, @top_level comment.format = 'rd' @top_level.comment = comment end end PKu]Og)rdoc-6.2.1.1/lib/rdoc/parser/changelog.rbnu[# frozen_string_literal: true require 'time' ## # A ChangeLog file parser. # # This parser converts a ChangeLog into an RDoc::Markup::Document. When # viewed as HTML a ChangeLog page will have an entry for each day's entries in # the sidebar table of contents. # # This parser is meant to parse the MRI ChangeLog, but can be used to parse any # {GNU style Change # Log}[http://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html]. class RDoc::Parser::ChangeLog < RDoc::Parser include RDoc::Parser::Text parse_files_matching(/(\/|\\|\A)ChangeLog[^\/\\]*\z/) ## # Attaches the +continuation+ of the previous line to the +entry_body+. # # Continued function listings are joined together as a single entry. # Continued descriptions are joined to make a single paragraph. def continue_entry_body entry_body, continuation return unless last = entry_body.last if last =~ /\)\s*\z/ and continuation =~ /\A\(/ then last.sub!(/\)\s*\z/, ',') continuation = continuation.sub(/\A\(/, '') end if last =~ /\s\z/ then last << continuation else last << ' ' + continuation end end ## # Creates an RDoc::Markup::Document given the +groups+ of ChangeLog entries. def create_document groups doc = RDoc::Markup::Document.new doc.omit_headings_below = 2 doc.file = @top_level doc << RDoc::Markup::Heading.new(1, File.basename(@file_name)) doc << RDoc::Markup::BlankLine.new groups.sort_by do |day,| day end.reverse_each do |day, entries| doc << RDoc::Markup::Heading.new(2, day.dup) doc << RDoc::Markup::BlankLine.new doc.concat create_entries entries end doc end ## # Returns a list of ChangeLog entries an RDoc::Markup nodes for the given # +entries+. def create_entries entries out = [] entries.each do |entry, items| out << RDoc::Markup::Heading.new(3, entry) out << RDoc::Markup::BlankLine.new out << create_items(items) end out end ## # Returns an RDoc::Markup::List containing the given +items+ in the # ChangeLog def create_items items list = RDoc::Markup::List.new :NOTE items.each do |item| item =~ /\A(.*?(?:\([^)]+\))?):\s*/ title = $1 body = $' paragraph = RDoc::Markup::Paragraph.new body list_item = RDoc::Markup::ListItem.new title, paragraph list << list_item end list end ## # Groups +entries+ by date. def group_entries entries @time_cache ||= {} entries.group_by do |title, _| begin time = @time_cache[title] (time || Time.parse(title)).strftime '%Y-%m-%d' rescue NoMethodError, ArgumentError time, = title.split ' ', 2 Time.parse(time).strftime '%Y-%m-%d' end end end ## # Parses the entries in the ChangeLog. # # Returns an Array of each ChangeLog entry in order of parsing. # # A ChangeLog entry is an Array containing the ChangeLog title (date and # committer) and an Array of ChangeLog items (file and function changed with # description). # # An example result would be: # # [ 'Tue Dec 4 08:33:46 2012 Eric Hodel ', # [ 'README.EXT: Converted to RDoc format', # 'README.EXT.ja: ditto']] def parse_entries @time_cache ||= {} entries = [] entry_name = nil entry_body = [] @content.each_line do |line| case line when /^\s*$/ then next when /^\w.*/ then entries << [entry_name, entry_body] if entry_name entry_name = $& begin time = Time.parse entry_name @time_cache[entry_name] = time # HACK Ruby 1.8 does not raise ArgumentError for Time.parse "Other" entry_name = nil unless entry_name =~ /#{time.year}/ rescue NoMethodError # HACK Ruby 2.1.2 and earlier raises NoMethodError if time part is absent entry_name.split ' ', 2 rescue ArgumentError if /out of range/ =~ $!.message Time.parse(entry_name.split(' ', 2)[0]) rescue entry_name = nil else entry_name = nil end end entry_body = [] when /^(\t| {8})?\*\s*(.*)/ then # "\t* file.c (func): ..." entry_body << $2.dup when /^(\t| {8})?\s*(\(.*)/ then # "\t(func): ..." entry = $2 if entry_body.last =~ /:/ then entry_body << entry.dup else continue_entry_body entry_body, entry end when /^(\t| {8})?\s*(.*)/ then continue_entry_body entry_body, $2 end end entries << [entry_name, entry_body] if entry_name entries.reject! do |(entry,_)| entry == nil end entries end ## # Converts the ChangeLog into an RDoc::Markup::Document def scan @time_cache = {} entries = parse_entries grouped_entries = group_entries entries doc = create_document grouped_entries @top_level.comment = doc @top_level end end PKu]4QՆ *rdoc-6.2.1.1/lib/rdoc/parser/ruby_tools.rbnu[# frozen_string_literal: true ## # Collection of methods for writing parsers module RDoc::Parser::RubyTools ## # Adds a token listener +obj+, but you should probably use token_listener def add_token_listener(obj) @token_listeners ||= [] @token_listeners << obj end ## # Fetches the next token from the scanner def get_tk tk = nil if @tokens.empty? then if @scanner_point >= @scanner.size return nil else tk = @scanner[@scanner_point] @scanner_point += 1 @read.push tk[:text] end else @read.push @unget_read.shift tk = @tokens.shift end if tk == nil || :on___end__ == tk[:kind] tk = nil end return nil unless tk # inform any listeners of our shiny new token @token_listeners.each do |obj| obj.add_token(tk) end if @token_listeners tk end ## # Reads and returns all tokens up to one of +tokens+. Leaves the matched # token in the token list. def get_tk_until(*tokens) read = [] loop do tk = get_tk case tk when *tokens then unget_tk tk break end read << tk end read end ## # Retrieves a String representation of the read tokens def get_tkread read = @read.join("") @read = [] read end ## # Peek equivalent for get_tkread def peek_read @read.join('') end ## # Peek at the next token, but don't remove it from the stream def peek_tk unget_tk(tk = get_tk) tk end ## # Removes the token listener +obj+ def remove_token_listener(obj) @token_listeners.delete(obj) end ## # Resets the tools def reset @read = [] @tokens = [] @unget_read = [] @nest = 0 @scanner_point = 0 end ## # Skips whitespace tokens including newlines def skip_tkspace tokens = [] while (tk = get_tk) and (:on_sp == tk[:kind] or :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind]) do tokens.push(tk) end unget_tk(tk) tokens end ## # Skips whitespace tokens excluding newlines def skip_tkspace_without_nl tokens = [] while (tk = get_tk) and :on_sp == tk[:kind] do tokens.push(tk) end unget_tk(tk) tokens end ## # Has +obj+ listen to tokens def token_listener(obj) add_token_listener obj yield ensure remove_token_listener obj end ## # Returns +tk+ to the scanner def unget_tk(tk) @tokens.unshift tk @unget_read.unshift @read.pop # Remove this token from any listeners @token_listeners.each do |obj| obj.pop_token end if @token_listeners nil end end PKu]9GG!rdoc-6.2.1.1/lib/rdoc/parser/c.rbnu[# frozen_string_literal: true require 'tsort' ## # RDoc::Parser::C attempts to parse C extension files. It looks for # the standard patterns that you find in extensions: +rb_define_class+, # +rb_define_method+ and so on. It tries to find the corresponding # C source for the methods and extract comments, but if we fail # we don't worry too much. # # The comments associated with a Ruby method are extracted from the C # comment block associated with the routine that _implements_ that # method, that is to say the method whose name is given in the # +rb_define_method+ call. For example, you might write: # # /* # * Returns a new array that is a one-dimensional flattening of this # * array (recursively). That is, for every element that is an array, # * extract its elements into the new array. # * # * s = [ 1, 2, 3 ] #=> [1, 2, 3] # * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] # * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] # * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # */ # static VALUE # rb_ary_flatten(VALUE ary) # { # ary = rb_obj_dup(ary); # rb_ary_flatten_bang(ary); # return ary; # } # # ... # # void # Init_Array(void) # { # ... # rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0); # # Here RDoc will determine from the +rb_define_method+ line that there's a # method called "flatten" in class Array, and will look for the implementation # in the method +rb_ary_flatten+. It will then use the comment from that # method in the HTML output. This method must be in the same source file # as the +rb_define_method+. # # The comment blocks may include special directives: # # [Document-class: +name+] # Documentation for the named class. # # [Document-module: +name+] # Documentation for the named module. # # [Document-const: +name+] # Documentation for the named +rb_define_const+. # # Constant values can be supplied on the first line of the comment like so: # # /* 300: The highest possible score in bowling */ # rb_define_const(cFoo, "PERFECT", INT2FIX(300)); # # The value can contain internal colons so long as they are escaped with a \ # # [Document-global: +name+] # Documentation for the named +rb_define_global_const+ # # [Document-variable: +name+] # Documentation for the named +rb_define_variable+ # # [Document-method\: +method_name+] # Documentation for the named method. Use this when the method name is # unambiguous. # # [Document-method\: ClassName::method_name] # Documentation for a singleton method in the given class. Use this when # the method name alone is ambiguous. # # [Document-method\: ClassName#method_name] # Documentation for a instance method in the given class. Use this when the # method name alone is ambiguous. # # [Document-attr: +name+] # Documentation for the named attribute. # # [call-seq: text up to an empty line] # Because C source doesn't give descriptive names to Ruby-level parameters, # you need to document the calling sequence explicitly # # In addition, RDoc assumes by default that the C method implementing a # Ruby function is in the same source file as the rb_define_method call. # If this isn't the case, add the comment: # # rb_define_method(....); // in filename # # As an example, we might have an extension that defines multiple classes # in its Init_xxx method. We could document them using # # /* # * Document-class: MyClass # * # * Encapsulate the writing and reading of the configuration # * file. ... # */ # # /* # * Document-method: read_value # * # * call-seq: # * cfg.read_value(key) -> value # * cfg.read_value(key} { |key| } -> value # * # * Return the value corresponding to +key+ from the configuration. # * In the second form, if the key isn't found, invoke the # * block and return its value. # */ class RDoc::Parser::C < RDoc::Parser parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/) include RDoc::Text ## # Maps C variable names to names of Ruby classes or modules attr_reader :classes ## # C file the parser is parsing attr_accessor :content ## # Dependencies from a missing enclosing class to the classes in # missing_dependencies that depend upon it. attr_reader :enclosure_dependencies ## # Maps C variable names to names of Ruby classes (and singleton classes) attr_reader :known_classes ## # Classes found while parsing the C file that were not yet registered due to # a missing enclosing class. These are processed by do_missing attr_reader :missing_dependencies ## # Maps C variable names to names of Ruby singleton classes attr_reader :singleton_classes ## # The TopLevel items in the parsed file belong to attr_reader :top_level ## # Prepares for parsing a C file. See RDoc::Parser#initialize for details on # the arguments. def initialize top_level, file_name, content, options, stats super @known_classes = RDoc::KNOWN_CLASSES.dup @content = handle_tab_width handle_ifdefs_in @content @file_dir = File.dirname @file_name @classes = load_variable_map :c_class_variables @singleton_classes = load_variable_map :c_singleton_class_variables # class_variable => { function => [method, ...] } @methods = Hash.new { |h, f| h[f] = Hash.new { |i, m| i[m] = [] } } # missing variable => [handle_class_module arguments] @missing_dependencies = {} # missing enclosure variable => [dependent handle_class_module arguments] @enclosure_dependencies = Hash.new { |h, k| h[k] = [] } @enclosure_dependencies.instance_variable_set :@missing_dependencies, @missing_dependencies @enclosure_dependencies.extend TSort def @enclosure_dependencies.tsort_each_node &block each_key(&block) rescue TSort::Cyclic => e cycle_vars = e.message.scan(/"(.*?)"/).flatten cycle = cycle_vars.sort.map do |var_name| delete var_name var_name, type, mod_name, = @missing_dependencies[var_name] "#{type} #{mod_name} (#{var_name})" end.join ', ' warn "Unable to create #{cycle} due to a cyclic class or module creation" retry end def @enclosure_dependencies.tsort_each_child node, &block fetch(node, []).each(&block) end end ## # Removes duplicate call-seq entries for methods using the same # implementation. def deduplicate_call_seq @methods.each do |var_name, functions| class_name = @known_classes[var_name] next unless class_name class_obj = find_class var_name, class_name functions.each_value do |method_names| next if method_names.length == 1 method_names.each do |method_name| deduplicate_method_name class_obj, method_name end end end end ## # If two ruby methods share a C implementation (and comment) this # deduplicates the examples in the call_seq for the method to reduce # confusion in the output. def deduplicate_method_name class_obj, method_name # :nodoc: return unless method = class_obj.method_list.find { |m| m.name == method_name } return unless call_seq = method.call_seq method_name = method_name[0, 1] if method_name =~ /\A\[/ entries = call_seq.split "\n" matching = entries.select do |entry| entry =~ /^\w*\.?#{Regexp.escape method_name}/ or entry =~ /\s#{Regexp.escape method_name}\s/ end method.call_seq = matching.join "\n" end ## # Scans #content for rb_define_alias def do_aliases @content.scan(/rb_define_alias\s*\( \s*(\w+), \s*"(.+?)", \s*"(.+?)" \s*\)/xm) do |var_name, new_name, old_name| class_name = @known_classes[var_name] unless class_name then @options.warn "Enclosing class or module %p for alias %s %s is not known" % [ var_name, new_name, old_name] next end class_obj = find_class var_name, class_name al = RDoc::Alias.new '', old_name, new_name, '' al.singleton = @singleton_classes.key? var_name comment = find_alias_comment var_name, new_name, old_name comment.normalize al.comment = comment al.record_location @top_level class_obj.add_alias al @stats.add_alias al end end ## # Scans #content for rb_attr and rb_define_attr def do_attrs @content.scan(/rb_attr\s*\( \s*(\w+), \s*([\w"()]+), \s*([01]), \s*([01]), \s*\w+\);/xm) do |var_name, attr_name, read, write| handle_attr var_name, attr_name, read, write end @content.scan(%r%rb_define_attr\( \s*([\w\.]+), \s*"([^"]+)", \s*(\d+), \s*(\d+)\s*\); %xm) do |var_name, attr_name, read, write| handle_attr var_name, attr_name, read, write end end ## # Scans #content for boot_defclass def do_boot_defclass @content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do |var_name, class_name, parent| parent = nil if parent == "0" handle_class_module(var_name, :class, class_name, parent, nil) end end ## # Scans #content for rb_define_class, boot_defclass, rb_define_class_under # and rb_singleton_class def do_classes_and_modules do_boot_defclass if @file_name == "class.c" @content.scan( %r( (?[\w\.]+)\s* = \s*rb_(?: define_(?: class(?: # rb_define_class(class_name_1, parent_name_1) \s*\( \s*"(?\w+)", \s*(?\w+)\s* \) | _under\s*\( # rb_define_class_under(class_under, class_name2, parent_name2...) \s* (?\w+), \s* "(?\w+)", \s* (?: (?[\w\*\s\(\)\.\->]+) | rb_path2class\("(?[\w:]+)"\) ) \s*\) ) | module(?: # rb_define_module(module_name_1) \s*\( \s*"(?\w+)"\s* \) | _under\s*\( # rb_define_module_under(module_under, module_name_1) \s*(?\w+), \s*"(?\w+)" \s*\) ) ) | struct_define_without_accessor\s*\( # rb_struct_define_without_accessor(class_name_3, parent_name_3, ...) \s*"(?\w+)", \s*(?\w+), \s*\w+, # Allocation function (?:\s*"\w+",)* # Attributes \s*NULL \) | singleton_class\s*\( # rb_singleton_class(target_class_name) \s*(?\w+) \) ) )mx ) do class_name = $~[:class_name_1] type = :class if class_name # rb_define_class(class_name_1, parent_name_1) parent_name = $~[:parent_name_1] #under = nil else class_name = $~[:class_name_2] if class_name # rb_define_class_under(class_under, class_name2, parent_name2...) parent_name = $~[:parent_name_2] || $~[:path] under = $~[:class_under] else class_name = $~[:class_name_3] if class_name # rb_struct_define_without_accessor(class_name_3, parent_name_3, ...) parent_name = $~[:parent_name_3] #under = nil else type = :module class_name = $~[:module_name_1] #parent_name = nil if class_name # rb_define_module(module_name_1) #under = nil else class_name = $~[:module_name_2] if class_name # rb_define_module_under(module_under, module_name_1) under = $~[:module_under] else # rb_singleton_class(target_class_name) target_class_name = $~[:target_class_name] handle_singleton $~[:var_name], target_class_name next end end end end end handle_class_module($~[:var_name], type, class_name, parent_name, under) end end ## # Scans #content for rb_define_variable, rb_define_readonly_variable, # rb_define_const and rb_define_global_const def do_constants @content.scan(%r%\Wrb_define_ ( variable | readonly_variable | const | global_const ) \s*\( (?:\s*(\w+),)? \s*"(\w+)", \s*(.*?)\s*\)\s*; %xm) do |type, var_name, const_name, definition| var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel" handle_constants type, var_name, const_name, definition end @content.scan(%r% \Wrb_curses_define_const \s*\( \s* (\w+) \s* \) \s*;%xm) do |consts| const = consts.first handle_constants 'const', 'mCurses', const, "UINT2NUM(#{const})" end @content.scan(%r% \Wrb_file_const \s*\( \s* "([^"]+)", \s* (.*?) \s* \) \s*;%xm) do |name, value| handle_constants 'const', 'rb_mFConst', name, value end end ## # Scans #content for rb_include_module def do_includes @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m| next unless cls = @classes[c] m = @known_classes[m] || m comment = RDoc::Comment.new '', @top_level, :c incl = cls.add_include RDoc::Include.new(m, comment) incl.record_location @top_level end end ## # Scans #content for rb_define_method, rb_define_singleton_method, # rb_define_module_function, rb_define_private_method, # rb_define_global_function and define_filetest_function def do_methods @content.scan(%r%rb_define_ ( singleton_method | method | module_function | private_method ) \s*\(\s*([\w\.]+), \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\(|\(METHOD\))?(\w+)\)?, \s*(-?\w+)\s*\) (?:;\s*/[*/]\s+in\s+(\w+?\.(?:cpp|c|y)))? %xm) do |type, var_name, meth_name, function, param_count, source_file| # Ignore top-object and weird struct.c dynamic stuff next if var_name == "ruby_top_self" next if var_name == "nstr" var_name = "rb_cObject" if var_name == "rb_mKernel" handle_method(type, var_name, meth_name, function, param_count, source_file) end @content.scan(%r%rb_define_global_function\s*\( \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\) (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))? %xm) do |meth_name, function, param_count, source_file| handle_method("method", "rb_mKernel", meth_name, function, param_count, source_file) end @content.scan(/define_filetest_function\s*\( \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\)/xm) do |meth_name, function, param_count| handle_method("method", "rb_mFileTest", meth_name, function, param_count) handle_method("singleton_method", "rb_cFile", meth_name, function, param_count) end end ## # Creates classes and module that were missing were defined due to the file # order being different than the declaration order. def do_missing return if @missing_dependencies.empty? @enclosure_dependencies.tsort.each do |in_module| arguments = @missing_dependencies.delete in_module next unless arguments # dependency on existing class handle_class_module(*arguments) end end ## # Finds the comment for an alias on +class_name+ from +new_name+ to # +old_name+ def find_alias_comment class_name, new_name, old_name content =~ %r%((?>/\*.*?\*/\s+)) rb_define_alias\(\s*#{Regexp.escape class_name}\s*, \s*"#{Regexp.escape new_name}"\s*, \s*"#{Regexp.escape old_name}"\s*\);%xm RDoc::Comment.new($1 || '', @top_level, :c) end ## # Finds a comment for rb_define_attr, rb_attr or Document-attr. # # +var_name+ is the C class variable the attribute is defined on. # +attr_name+ is the attribute's name. # # +read+ and +write+ are the read/write flags ('1' or '0'). Either both or # neither must be provided. def find_attr_comment var_name, attr_name, read = nil, write = nil attr_name = Regexp.escape attr_name rw = if read and write then /\s*#{read}\s*,\s*#{write}\s*/xm else /.*?/m end comment = if @content =~ %r%((?>/\*.*?\*/\s+)) rb_define_attr\((?:\s*#{var_name},)?\s* "#{attr_name}"\s*, #{rw}\)\s*;%xm then $1 elsif @content =~ %r%((?>/\*.*?\*/\s+)) rb_attr\(\s*#{var_name}\s*, \s*#{attr_name}\s*, #{rw},.*?\)\s*;%xm then $1 elsif @content =~ %r%(/\*.*?(?:\s*\*\s*)?) Document-attr:\s#{attr_name}\s*?\n ((?>(.|\n)*?\*/))%x then "#{$1}\n#{$2}" else '' end RDoc::Comment.new comment, @top_level, :c end ## # Generate a Ruby-method table def gen_body_table file_content table = {} file_content.scan(%r{ ((?>/\*.*?\*/\s*)?) ((?:(?:\w+)\s+)? (?:intern\s+)?VALUE\s+(\w+) \s*(?:\([^)]*\))(?:[^;]|$)) | ((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+(\w+)\s+(\w+)) | ^\s*\#\s*define\s+(\w+)\s+(\w+) }xm) do case when $1 table[$3] = [:func_def, $1, $2, $~.offset(2)] if !table[$3] || table[$3][0] != :func_def when $4 table[$6] = [:macro_def, $4, $5, $~.offset(5), $7] if !table[$6] || table[$6][0] == :macro_alias when $8 table[$8] ||= [:macro_alias, $9] end end table end ## # Find the C code corresponding to a Ruby method def find_body class_name, meth_name, meth_obj, file_content, quiet = false if file_content @body_table ||= {} @body_table[file_content] ||= gen_body_table file_content type, *args = @body_table[file_content][meth_name] end case type when :func_def comment = RDoc::Comment.new args[0], @top_level, :c body = args[1] offset, = args[2] comment.remove_private if comment # try to find the whole body body = $& if /#{Regexp.escape body}[^(]*?\{.*?^\}/m =~ file_content # The comment block may have been overridden with a 'Document-method' # block. This happens in the interpreter when multiple methods are # vectored through to the same C method but those methods are logically # distinct (for example Kernel.hash and Kernel.object_id share the same # implementation override_comment = find_override_comment class_name, meth_obj comment = override_comment if override_comment comment.normalize find_modifiers comment, meth_obj if comment #meth_obj.params = params meth_obj.start_collecting_tokens tk = { :line_no => 1, :char_no => 1, :text => body } meth_obj.add_token tk meth_obj.comment = comment meth_obj.line = file_content[0, offset].count("\n") + 1 body when :macro_def comment = RDoc::Comment.new args[0], @top_level, :c body = args[1] offset, = args[2] find_body class_name, args[3], meth_obj, file_content, true comment.normalize find_modifiers comment, meth_obj meth_obj.start_collecting_tokens tk = { :line_no => 1, :char_no => 1, :text => body } meth_obj.add_token tk meth_obj.comment = comment meth_obj.line = file_content[0, offset].count("\n") + 1 body when :macro_alias # with no comment we hope the aliased definition has it and use it's # definition body = find_body(class_name, args[0], meth_obj, file_content, true) return body if body @options.warn "No definition for #{meth_name}" false else # No body, but might still have an override comment comment = find_override_comment class_name, meth_obj if comment then comment.normalize find_modifiers comment, meth_obj meth_obj.comment = comment '' else @options.warn "No definition for #{meth_name}" false end end end ## # Finds a RDoc::NormalClass or RDoc::NormalModule for +raw_name+ def find_class(raw_name, name) unless @classes[raw_name] if raw_name =~ /^rb_m/ container = @top_level.add_module RDoc::NormalModule, name else container = @top_level.add_class RDoc::NormalClass, name end container.record_location @top_level @classes[raw_name] = container end @classes[raw_name] end ## # Look for class or module documentation above Init_+class_name+(void), # in a Document-class +class_name+ (or module) comment or above an # rb_define_class (or module). If a comment is supplied above a matching # Init_ and a rb_define_class the Init_ comment is used. # # /* # * This is a comment for Foo # */ # Init_Foo(void) { # VALUE cFoo = rb_define_class("Foo", rb_cObject); # } # # /* # * Document-class: Foo # * This is a comment for Foo # */ # Init_foo(void) { # VALUE cFoo = rb_define_class("Foo", rb_cObject); # } # # /* # * This is a comment for Foo # */ # VALUE cFoo = rb_define_class("Foo", rb_cObject); def find_class_comment class_name, class_mod comment = nil if @content =~ %r% ((?>/\*.*?\*/\s+)) (static\s+)? void\s+ Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)%xmi then comment = $1.sub(%r%Document-(?:class|module):\s+#{class_name}%, '') elsif @content =~ %r%Document-(?:class|module):\s+#{class_name}\s*? (?:<\s+[:,\w]+)?\n((?>.*?\*/))%xm then comment = "/*\n#{$1}" elsif @content =~ %r%((?>/\*.*?\*/\s+)) ([\w\.\s]+\s* = \s+)?rb_define_(class|module)[\t (]*?"(#{class_name})"%xm then comment = $1 elsif @content =~ %r%((?>/\*.*?\*/\s+)) ([\w\. \t]+ = \s+)?rb_define_(class|module)_under[\t\w, (]*?"(#{class_name.split('::').last})"%xm then comment = $1 else comment = '' end comment = RDoc::Comment.new comment, @top_level, :c comment.normalize look_for_directives_in class_mod, comment class_mod.add_comment comment, @top_level end ## # Generate a const table def gen_const_table file_content table = {} @content.scan(%r{ ((?>^\s*/\*.*?\*/\s+)) rb_define_(\w+)\((?:\s*(?:\w+),)?\s* "(\w+)"\s*, .*?\)\s*; | Document-(?:const|global|variable):\s ((?:\w+::)*\w+) \s*?\n((?>.*?\*/)) }mxi) do case when $1 then table[[$2, $3]] = $1 when $4 then table[$4] = "/*\n" + $5 end end table end ## # Finds a comment matching +type+ and +const_name+ either above the # comment or in the matching Document- section. def find_const_comment(type, const_name, class_name = nil) @const_table ||= {} @const_table[@content] ||= gen_const_table @content table = @const_table[@content] comment = table[[type, const_name]] || (class_name && table[class_name + "::" + const_name]) || table[const_name] || '' RDoc::Comment.new comment, @top_level, :c end ## # Handles modifiers in +comment+ and updates +meth_obj+ as appropriate. def find_modifiers comment, meth_obj comment.normalize comment.extract_call_seq meth_obj look_for_directives_in meth_obj, comment end ## # Finds a Document-method override for +meth_obj+ on +class_name+ def find_override_comment class_name, meth_obj name = Regexp.escape meth_obj.name prefix = Regexp.escape meth_obj.name_prefix comment = if @content =~ %r%Document-method: \s+#{class_name}#{prefix}#{name} \s*?\n((?>.*?\*/))%xm then "/*#{$1}" elsif @content =~ %r%Document-method: \s#{name}\s*?\n((?>.*?\*/))%xm then "/*#{$1}" end return unless comment RDoc::Comment.new comment, @top_level, :c end ## # Creates a new RDoc::Attr +attr_name+ on class +var_name+ that is either # +read+, +write+ or both def handle_attr(var_name, attr_name, read, write) rw = '' rw += 'R' if '1' == read rw += 'W' if '1' == write class_name = @known_classes[var_name] return unless class_name class_obj = find_class var_name, class_name return unless class_obj comment = find_attr_comment var_name, attr_name comment.normalize name = attr_name.gsub(/rb_intern(?:_const)?\("([^"]+)"\)/, '\1') attr = RDoc::Attr.new '', name, rw, comment attr.record_location @top_level class_obj.add_attribute attr @stats.add_attribute attr end ## # Creates a new RDoc::NormalClass or RDoc::NormalModule based on +type+ # named +class_name+ in +parent+ which was assigned to the C +var_name+. def handle_class_module(var_name, type, class_name, parent, in_module) parent_name = @known_classes[parent] || parent if in_module then enclosure = @classes[in_module] || @store.find_c_enclosure(in_module) if enclosure.nil? and enclosure = @known_classes[in_module] then enc_type = /^rb_m/ =~ in_module ? :module : :class handle_class_module in_module, enc_type, enclosure, nil, nil enclosure = @classes[in_module] end unless enclosure then @enclosure_dependencies[in_module] << var_name @missing_dependencies[var_name] = [var_name, type, class_name, parent, in_module] return end else enclosure = @top_level end if type == :class then full_name = if RDoc::ClassModule === enclosure then enclosure.full_name + "::#{class_name}" else class_name end if @content =~ %r%Document-class:\s+#{full_name}\s*<\s+([:,\w]+)% then parent_name = $1 end cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name else cm = enclosure.add_module RDoc::NormalModule, class_name end cm.record_location enclosure.top_level find_class_comment cm.full_name, cm case cm when RDoc::NormalClass @stats.add_class cm when RDoc::NormalModule @stats.add_module cm end @classes[var_name] = cm @known_classes[var_name] = cm.full_name @store.add_c_enclosure var_name, cm end ## # Adds constants. By providing some_value: at the start of the comment you # can override the C value of the comment to give a friendly definition. # # /* 300: The perfect score in bowling */ # rb_define_const(cFoo, "PERFECT", INT2FIX(300)); # # Will override INT2FIX(300) with the value +300+ in the output # RDoc. Values may include quotes and escaped colons (\:). def handle_constants(type, var_name, const_name, definition) class_name = @known_classes[var_name] return unless class_name class_obj = find_class var_name, class_name unless class_obj then @options.warn 'Enclosing class or module %p is not known' % [const_name] return end comment = find_const_comment type, const_name, class_name comment.normalize # In the case of rb_define_const, the definition and comment are in # "/* definition: comment */" form. The literal ':' and '\' characters # can be escaped with a backslash. if type.downcase == 'const' then no_match, new_definition, new_comment = comment.text.split(/(\A.*):/) if no_match and no_match.empty? then if new_definition.empty? then # Default to literal C definition new_definition = definition else new_definition = new_definition.gsub("\:", ":") new_definition = new_definition.gsub("\\", '\\') end new_definition.sub!(/\A(\s+)/, '') new_comment = "#{$1}#{new_comment.lstrip}" new_comment = RDoc::Comment.new new_comment, @top_level, :c con = RDoc::Constant.new const_name, new_definition, new_comment else con = RDoc::Constant.new const_name, definition, comment end else con = RDoc::Constant.new const_name, definition, comment end con.record_location @top_level @stats.add_constant con class_obj.add_constant con end ## # Removes #ifdefs that would otherwise confuse us def handle_ifdefs_in(body) body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1') end ## # Adds an RDoc::AnyMethod +meth_name+ defined on a class or module assigned # to +var_name+. +type+ is the type of method definition function used. # +singleton_method+ and +module_function+ create a singleton method. def handle_method(type, var_name, meth_name, function, param_count, source_file = nil) class_name = @known_classes[var_name] singleton = @singleton_classes.key? var_name @methods[var_name][function] << meth_name return unless class_name class_obj = find_class var_name, class_name if class_obj then if meth_name == 'initialize' then meth_name = 'new' singleton = true type = 'method' # force public end meth_obj = RDoc::AnyMethod.new '', meth_name meth_obj.c_function = function meth_obj.singleton = singleton || %w[singleton_method module_function].include?(type) p_count = Integer(param_count) rescue -1 if source_file then file_name = File.join @file_dir, source_file if File.exist? file_name then file_content = File.read file_name else @options.warn "unknown source #{source_file} for #{meth_name} in #{@file_name}" end else file_content = @content end body = find_body class_name, function, meth_obj, file_content if body and meth_obj.document_self then meth_obj.params = if p_count < -1 then # -2 is Array '(*args)' elsif p_count == -1 then # argc, argv rb_scan_args body else "(#{(1..p_count).map { |i| "p#{i}" }.join ', '})" end meth_obj.record_location @top_level class_obj.add_method meth_obj @stats.add_method meth_obj meth_obj.visibility = :private if 'private_method' == type end end end ## # Registers a singleton class +sclass_var+ as a singleton of +class_var+ def handle_singleton sclass_var, class_var class_name = @known_classes[class_var] @known_classes[sclass_var] = class_name @singleton_classes[sclass_var] = class_name end ## # Normalizes tabs in +body+ def handle_tab_width(body) if /\t/ =~ body tab_width = @options.tab_width body.split(/\n/).map do |line| 1 while line.gsub!(/\t+/) do ' ' * (tab_width * $&.length - $`.length % tab_width) end && $~ line end.join "\n" else body end end ## # Loads the variable map with the given +name+ from the RDoc::Store, if # present. def load_variable_map map_name return {} unless files = @store.cache[map_name] return {} unless name_map = files[@file_name] class_map = {} name_map.each do |variable, name| next unless mod = @store.find_class_or_module(name) class_map[variable] = if map_name == :c_class_variables then mod else name end @known_classes[variable] = name end class_map end ## # Look for directives in a normal comment block: # # /* # * :title: My Awesome Project # */ # # This method modifies the +comment+ def look_for_directives_in context, comment @preprocess.handle comment, context do |directive, param| case directive when 'main' then @options.main_page = param '' when 'title' then @options.default_title = param if @options.respond_to? :default_title= '' end end comment end ## # Extracts parameters from the +method_body+ and returns a method # parameter string. Follows 1.9.3dev's scan-arg-spec, see README.EXT def rb_scan_args method_body method_body =~ /rb_scan_args\((.*?)\)/m return '(*args)' unless $1 $1.split(/,/)[2] =~ /"(.*?)"/ # format argument format = $1.split(//) lead = opt = trail = 0 if format.first =~ /\d/ then lead = $&.to_i format.shift if format.first =~ /\d/ then opt = $&.to_i format.shift if format.first =~ /\d/ then trail = $&.to_i format.shift block_arg = true end end end if format.first == '*' and not block_arg then var = true format.shift if format.first =~ /\d/ then trail = $&.to_i format.shift end end if format.first == ':' then hash = true format.shift end if format.first == '&' then block = true format.shift end # if the format string is not empty there's a bug in the C code, ignore it args = [] position = 1 (1...(position + lead)).each do |index| args << "p#{index}" end position += lead (position...(position + opt)).each do |index| args << "p#{index} = v#{index}" end position += opt if var then args << '*args' position += 1 end (position...(position + trail)).each do |index| args << "p#{index}" end position += trail if hash then args << "p#{position} = {}" end args << '&block' if block "(#{args.join ', '})" end ## # Removes lines that are commented out that might otherwise get picked up # when scanning for classes and methods def remove_commented_out_lines @content = @content.gsub(%r%//.*rb_define_%, '//') end ## # Extracts the classes, modules, methods, attributes, constants and aliases # from a C file and returns an RDoc::TopLevel for this file def scan remove_commented_out_lines do_classes_and_modules do_missing do_constants do_methods do_includes do_aliases do_attrs deduplicate_call_seq @store.add_c_variables self @top_level end end PKu]U&rdoc-6.2.1.1/lib/rdoc/parser/simple.rbnu[# frozen_string_literal: true ## # Parse a non-source file. We basically take the whole thing as one big # comment. class RDoc::Parser::Simple < RDoc::Parser include RDoc::Parser::Text parse_files_matching(//) attr_reader :content # :nodoc: ## # Prepare to parse a plain file def initialize(top_level, file_name, content, options, stats) super preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include @content = preprocess.handle @content, @top_level end ## # Extract the file contents and attach them to the TopLevel as a comment def scan comment = remove_coding_comment @content comment = remove_private_comment comment comment = RDoc::Comment.new comment, @top_level @top_level.comment = comment @top_level end ## # Removes the encoding magic comment from +text+ def remove_coding_comment text text.sub(/\A# .*coding[=:].*$/, '') end ## # Removes private comments. # # Unlike RDoc::Comment#remove_private this implementation only looks for two # dashes at the beginning of the line. Three or more dashes are considered # to be a rule and ignored. def remove_private_comment comment # Workaround for gsub encoding for Ruby 1.9.2 and earlier empty = '' empty = RDoc::Encoding.change_encoding empty, comment.encoding comment = comment.gsub(%r%^--\n.*?^\+\+\n?%m, empty) comment.sub(%r%^--\n.*%m, empty) end end PKu]733$rdoc-6.2.1.1/lib/rdoc/parser/text.rbnu[# frozen_string_literal: true ## # Indicates this parser is text and doesn't contain code constructs. # # Include this module in a RDoc::Parser subclass to make it show up as a file, # not as part of a class or module. #-- # This is not named File to avoid overriding ::File module RDoc::Parser::Text end PKu]_A(rdoc-6.2.1.1/lib/rdoc/parser/markdown.rbnu[# frozen_string_literal: true ## # Parse a Markdown format file. The parsed RDoc::Markup::Document is attached # as a file comment. class RDoc::Parser::Markdown < RDoc::Parser include RDoc::Parser::Text parse_files_matching(/\.(md|markdown)(?:\.[^.]+)?$/) ## # Creates an Markdown-format TopLevel for the given file. def scan comment = RDoc::Comment.new @content, @top_level comment.format = 'markdown' @top_level.comment = comment end end PKu] />>0rdoc-6.2.1.1/lib/rdoc/parser/ripper_state_lex.rbnu[# frozen_string_literal: true require 'ripper' class RDoc::Parser::RipperStateLex # TODO: Remove this constants after Ruby 2.4 EOL RIPPER_HAS_LEX_STATE = Ripper::Filter.method_defined?(:state) Token = Struct.new(:line_no, :char_no, :kind, :text, :state) EXPR_NONE = 0 EXPR_BEG = 1 EXPR_END = 2 EXPR_ENDARG = 4 EXPR_ENDFN = 8 EXPR_ARG = 16 EXPR_CMDARG = 32 EXPR_MID = 64 EXPR_FNAME = 128 EXPR_DOT = 256 EXPR_CLASS = 512 EXPR_LABEL = 1024 EXPR_LABELED = 2048 EXPR_FITEM = 4096 EXPR_VALUE = EXPR_BEG EXPR_BEG_ANY = (EXPR_BEG | EXPR_MID | EXPR_CLASS) EXPR_ARG_ANY = (EXPR_ARG | EXPR_CMDARG) EXPR_END_ANY = (EXPR_END | EXPR_ENDARG | EXPR_ENDFN) class InnerStateLex < Ripper::Filter attr_accessor :lex_state def initialize(code) @lex_state = EXPR_BEG @in_fname = false @continue = false reset super(code) end def reset @command_start = false @cmd_state = @command_start end def on_nl(tok, data) case @lex_state when EXPR_FNAME, EXPR_DOT @continue = true else @continue = false @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0 end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_ignored_nl(tok, data) case @lex_state when EXPR_FNAME, EXPR_DOT @continue = true else @continue = false @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0 end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_op(tok, data) case tok when '&', '|', '!', '!=', '!~' case @lex_state when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end when '<<' # TODO next token? case @lex_state when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end when '?' @lex_state = EXPR_BEG when '&&', '||', '+=', '-=', '*=', '**=', '&=', '|=', '^=', '<<=', '>>=', '||=', '&&=' @lex_state = EXPR_BEG when '::' case @lex_state when EXPR_ARG, EXPR_CMDARG @lex_state = EXPR_DOT when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end else case @lex_state when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_kw(tok, data) case tok when 'class' @lex_state = EXPR_CLASS @in_fname = true when 'def' @lex_state = EXPR_FNAME @continue = true @in_fname = true when 'if', 'unless', 'while', 'until' if ((EXPR_MID | EXPR_END | EXPR_ENDARG | EXPR_ENDFN | EXPR_ARG | EXPR_CMDARG) & @lex_state) != 0 # postfix if @lex_state = EXPR_BEG | EXPR_LABEL else @lex_state = EXPR_BEG end when 'begin', 'case', 'when' @lex_state = EXPR_BEG when 'return', 'break' @lex_state = EXPR_MID else if @lex_state == EXPR_FNAME @lex_state = EXPR_END else @lex_state = EXPR_END end end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_tstring_beg(tok, data) @lex_state = EXPR_BEG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_tstring_end(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_CHAR(tok, data) @lex_state = EXPR_END data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_period(tok, data) @lex_state = EXPR_DOT data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_int(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_float(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_rational(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_imaginary(tok, data) @lex_state = EXPR_END | EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_symbeg(tok, data) @lex_state = EXPR_FNAME @continue = true @in_fname = true data << Token.new(lineno, column, __method__, tok, @lex_state) end private def on_variables(event, tok, data) if @in_fname @lex_state = EXPR_ENDFN @in_fname = false @continue = false elsif @continue case @lex_state when EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_ENDFN @continue = false end else @lex_state = EXPR_CMDARG end data << Token.new(lineno, column, event, tok, @lex_state) end def on_ident(tok, data) on_variables(__method__, tok, data) end def on_ivar(tok, data) @lex_state = EXPR_END on_variables(__method__, tok, data) end def on_cvar(tok, data) @lex_state = EXPR_END on_variables(__method__, tok, data) end def on_gvar(tok, data) @lex_state = EXPR_END on_variables(__method__, tok, data) end def on_backref(tok, data) @lex_state = EXPR_END on_variables(__method__, tok, data) end def on_lparen(tok, data) @lex_state = EXPR_LABEL | EXPR_BEG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_rparen(tok, data) @lex_state = EXPR_ENDFN data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_lbrace(tok, data) @lex_state = EXPR_LABEL | EXPR_BEG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_rbrace(tok, data) @lex_state = EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_lbracket(tok, data) @lex_state = EXPR_LABEL | EXPR_BEG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_rbracket(tok, data) @lex_state = EXPR_ENDARG data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_const(tok, data) case @lex_state when EXPR_FNAME @lex_state = EXPR_ENDFN when EXPR_CLASS, EXPR_CMDARG, EXPR_MID @lex_state = EXPR_ARG else @lex_state = EXPR_CMDARG end data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_sp(tok, data) data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_comma(tok, data) @lex_state = EXPR_BEG | EXPR_LABEL if (EXPR_ARG_ANY & @lex_state) != 0 data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_comment(tok, data) @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0 data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_ignored_sp(tok, data) @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0 data << Token.new(lineno, column, __method__, tok, @lex_state) end def on_heredoc_beg(tok, data) data << Token.new(lineno, column, __method__, tok, @lex_state) @lex_state = EXPR_END data end def on_heredoc_end(tok, data) data << Token.new(lineno, column, __method__, tok, @lex_state) @lex_state = EXPR_BEG data end def on_default(event, tok, data) reset data << Token.new(lineno, column, event, tok, @lex_state) end end unless RIPPER_HAS_LEX_STATE class InnerStateLex < Ripper::Filter def initialize(code) super(code) end def on_default(event, tok, data) data << Token.new(lineno, column, event, tok, state) end end if RIPPER_HAS_LEX_STATE def get_squashed_tk if @buf.empty? tk = @tokens.shift else tk = @buf.shift end return nil if tk.nil? case tk[:kind] when :on_symbeg then tk = get_symbol_tk(tk) when :on_tstring_beg then tk = get_string_tk(tk) when :on_backtick then if (tk[:state] & (EXPR_FNAME | EXPR_ENDFN)) != 0 @inner_lex.lex_state = EXPR_ARG unless RIPPER_HAS_LEX_STATE tk[:kind] = :on_ident tk[:state] = Ripper::Lexer.const_defined?(:State) ? Ripper::Lexer::State.new(EXPR_ARG) : EXPR_ARG else tk = get_string_tk(tk) end when :on_regexp_beg then tk = get_regexp_tk(tk) when :on_embdoc_beg then tk = get_embdoc_tk(tk) when :on_heredoc_beg then @heredoc_queue << retrieve_heredoc_info(tk) @inner_lex.lex_state = EXPR_END unless RIPPER_HAS_LEX_STATE when :on_nl, :on_ignored_nl, :on_comment, :on_heredoc_end then if !@heredoc_queue.empty? get_heredoc_tk(*@heredoc_queue.shift) elsif tk[:text].nil? # :on_ignored_nl sometimes gives nil tk[:text] = '' end when :on_words_beg then tk = get_words_tk(tk) when :on_qwords_beg then tk = get_words_tk(tk) when :on_symbols_beg then tk = get_words_tk(tk) when :on_qsymbols_beg then tk = get_words_tk(tk) when :on_op then if '&.' == tk[:text] tk[:kind] = :on_period else tk = get_op_tk(tk) end end tk end private def get_symbol_tk(tk) is_symbol = true symbol_tk = Token.new(tk.line_no, tk.char_no, :on_symbol) if ":'" == tk[:text] or ':"' == tk[:text] tk1 = get_string_tk(tk) symbol_tk[:text] = tk1[:text] symbol_tk[:state] = tk1[:state] else case (tk1 = get_squashed_tk)[:kind] when :on_ident symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_tstring_content symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = get_squashed_tk[:state] # skip :on_tstring_end when :on_tstring_end symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_op symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_ivar symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_cvar symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_gvar symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_const symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] when :on_kw symbol_tk[:text] = ":#{tk1[:text]}" symbol_tk[:state] = tk1[:state] else is_symbol = false tk = tk1 end end if is_symbol tk = symbol_tk end tk end private def get_string_tk(tk) string = tk[:text] state = nil kind = :on_tstring loop do inner_str_tk = get_squashed_tk if inner_str_tk.nil? break elsif :on_tstring_end == inner_str_tk[:kind] string = string + inner_str_tk[:text] state = inner_str_tk[:state] break elsif :on_label_end == inner_str_tk[:kind] string = string + inner_str_tk[:text] state = inner_str_tk[:state] kind = :on_symbol break else string = string + inner_str_tk[:text] if :on_embexpr_beg == inner_str_tk[:kind] then kind = :on_dstring if :on_tstring == kind end end end Token.new(tk.line_no, tk.char_no, kind, string, state) end private def get_regexp_tk(tk) string = tk[:text] state = nil loop do inner_str_tk = get_squashed_tk if inner_str_tk.nil? break elsif :on_regexp_end == inner_str_tk[:kind] string = string + inner_str_tk[:text] state = inner_str_tk[:state] break else string = string + inner_str_tk[:text] end end Token.new(tk.line_no, tk.char_no, :on_regexp, string, state) end private def get_embdoc_tk(tk) string = tk[:text] until :on_embdoc_end == (embdoc_tk = get_squashed_tk)[:kind] do string = string + embdoc_tk[:text] end string = string + embdoc_tk[:text] Token.new(tk.line_no, tk.char_no, :on_embdoc, string, embdoc_tk.state) end private def get_heredoc_tk(heredoc_name, indent) string = '' start_tk = nil prev_tk = nil until heredoc_end?(heredoc_name, indent, tk = @tokens.shift) do start_tk = tk unless start_tk if (prev_tk.nil? or "\n" == prev_tk[:text][-1]) and 0 != tk[:char_no] string = string + (' ' * tk[:char_no]) end string = string + tk[:text] prev_tk = tk end start_tk = tk unless start_tk prev_tk = tk unless prev_tk @buf.unshift tk # closing heredoc heredoc_tk = Token.new(start_tk.line_no, start_tk.char_no, :on_heredoc, string, prev_tk.state) @buf.unshift heredoc_tk end private def retrieve_heredoc_info(tk) name = tk[:text].gsub(/\A<<[-~]?(['"`]?)(.+)\1\z/, '\2') indent = tk[:text] =~ /\A<<[-~]/ [name, indent] end private def heredoc_end?(name, indent, tk) result = false if :on_heredoc_end == tk[:kind] then tk_name = tk[:text].chomp tk_name.lstrip! if indent if name == tk_name result = true end end result end private def get_words_tk(tk) string = '' start_token = tk[:text] start_quote = tk[:text].rstrip[-1] line_no = tk[:line_no] char_no = tk[:char_no] state = tk[:state] end_quote = case start_quote when ?( then ?) when ?[ then ?] when ?{ then ?} when ?< then ?> else start_quote end end_token = nil loop do tk = get_squashed_tk if tk.nil? end_token = end_quote break elsif :on_tstring_content == tk[:kind] then string += tk[:text] elsif :on_words_sep == tk[:kind] or :on_tstring_end == tk[:kind] then if end_quote == tk[:text].strip then end_token = tk[:text] break else string += tk[:text] end else string += tk[:text] end end text = "#{start_token}#{string}#{end_token}" Token.new(line_no, char_no, :on_dstring, text, state) end private def get_op_tk(tk) redefinable_operators = %w[! != !~ % & * ** + +@ - -@ / < << <= <=> == === =~ > >= >> [] []= ^ ` | ~] if redefinable_operators.include?(tk[:text]) and tk[:state] == EXPR_ARG then @inner_lex.lex_state = EXPR_ARG unless RIPPER_HAS_LEX_STATE tk[:state] = Ripper::Lexer.const_defined?(:State) ? Ripper::Lexer::State.new(EXPR_ARG) : EXPR_ARG tk[:kind] = :on_ident elsif tk[:text] =~ /^[-+]$/ then tk_ahead = get_squashed_tk case tk_ahead[:kind] when :on_int, :on_float, :on_rational, :on_imaginary then tk[:text] += tk_ahead[:text] tk[:kind] = tk_ahead[:kind] tk[:state] = tk_ahead[:state] when :on_heredoc_beg, :on_tstring, :on_dstring # frozen/non-frozen string literal tk[:text] += tk_ahead[:text] tk[:kind] = tk_ahead[:kind] tk[:state] = tk_ahead[:state] else @buf.unshift tk_ahead end end tk end def initialize(code) @buf = [] @heredoc_queue = [] @inner_lex = InnerStateLex.new(code) @tokens = @inner_lex.parse([]) end def self.parse(code) lex = self.new(code) tokens = [] begin while tk = lex.get_squashed_tk tokens.push tk end rescue StopIteration end tokens end def self.end?(token) (token[:state] & EXPR_END) end end PKu]mh fEE!rdoc-6.2.1.1/lib/rdoc/markdown.rbnu[# coding: UTF-8 # frozen_string_literal: true # :markup: markdown ## # RDoc::Markdown as described by the [markdown syntax][syntax]. # # To choose Markdown as your only default format see # RDoc::Options@Saved+Options for instructions on setting up a `.doc_options` # file to store your project default. # # ## Usage # # Here is a brief example of using this parse to read a markdown file by hand. # # data = File.read("README.md") # formatter = RDoc::Markup::ToHtml.new(RDoc::Options.new, nil) # html = RDoc::Markdown.parse(data).accept(formatter) # # # do something with html # # ## Extensions # # The following markdown extensions are supported by the parser, but not all # are used in RDoc output by default. # # ### RDoc # # The RDoc Markdown parser has the following built-in behaviors that cannot be # disabled. # # Underscores embedded in words are never interpreted as emphasis. (While the # [markdown dingus][dingus] emphasizes in-word underscores, neither the # Markdown syntax nor MarkdownTest mention this behavior.) # # For HTML output, RDoc always auto-links bare URLs. # # ### Break on Newline # # The break_on_newline extension converts all newlines into hard line breaks # as in [Github Flavored Markdown][GFM]. This extension is disabled by # default. # # ### CSS # # The #css extension enables CSS blocks to be included in the output, but they # are not used for any built-in RDoc output format. This extension is disabled # by default. # # Example: # # # # ### Definition Lists # # The definition_lists extension allows definition lists using the [PHP # Markdown Extra syntax][PHPE], but only one label and definition are supported # at this time. This extension is enabled by default. # # Example: # # ``` # cat # : A small furry mammal # that seems to sleep a lot # # ant # : A little insect that is known # to enjoy picnics # # ``` # # Produces: # # cat # : A small furry mammal # that seems to sleep a lot # # ant # : A little insect that is known # to enjoy picnics # # ### Strike # # Example: # # ``` # This is ~~striked~~. # ``` # # Produces: # # This is ~~striked~~. # # ### Github # # The #github extension enables a partial set of [Github Flavored Markdown] # [GFM]. This extension is enabled by default. # # Supported github extensions include: # # #### Fenced code blocks # # Use ` ``` ` around a block of code instead of indenting it four spaces. # # #### Syntax highlighting # # Use ` ``` ruby ` as the start of a code fence to add syntax highlighting. # (Currently only `ruby` syntax is supported). # # ### HTML # # Enables raw HTML to be included in the output. This extension is enabled by # default. # # Example: # # # ... #
    # # ### Notes # # The #notes extension enables footnote support. This extension is enabled by # default. # # Example: # # Here is some text[^1] including an inline footnote ^[for short footnotes] # # ... # # [^1]: With the footnote text down at the bottom # # Produces: # # Here is some text[^1] including an inline footnote ^[for short footnotes] # # [^1]: With the footnote text down at the bottom # # ## Limitations # # * Link titles are not used # * Footnotes are collapsed into a single paragraph # # ## Author # # This markdown parser is a port to kpeg from [peg-markdown][pegmarkdown] by # John MacFarlane. # # It is used under the MIT license: # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # The port to kpeg was performed by Eric Hodel and Evan Phoenix # # [dingus]: http://daringfireball.net/projects/markdown/dingus # [GFM]: http://github.github.com/github-flavored-markdown/ # [pegmarkdown]: https://github.com/jgm/peg-markdown # [PHPE]: http://michelf.com/projects/php-markdown/extra/#def-list # [syntax]: http://daringfireball.net/projects/markdown/syntax #-- # Last updated to jgm/peg-markdown commit 8f8fc22ef0 class RDoc::Markdown # :stopdoc: # This is distinct from setup_parser so that a standalone parser # can redefine #initialize and still have access to the proper # parser setup code. def initialize(str, debug=false) setup_parser(str, debug) end # Prepares for parsing +str+. If you define a custom initialize you must # call this method before #parse def setup_parser(str, debug=false) set_string str, 0 @memoizations = Hash.new { |h,k| h[k] = {} } @result = nil @failed_rule = nil @failing_rule_offset = -1 setup_foreign_grammar end attr_reader :string attr_reader :failing_rule_offset attr_accessor :result, :pos def current_column(target=pos) if c = string.rindex("\n", target-1) return target - c - 1 end target + 1 end def current_line(target=pos) cur_offset = 0 cur_line = 0 string.each_line do |line| cur_line += 1 cur_offset += line.size return cur_line if cur_offset >= target end -1 end def lines lines = [] string.each_line { |l| lines << l } lines end def get_text(start) @string[start..@pos-1] end # Sets the string and current parsing position for the parser. def set_string string, pos @string = string @string_size = string ? string.size : 0 @pos = pos end def show_pos width = 10 if @pos < width "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")" else "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")" end end def failure_info l = current_line @failing_rule_offset c = current_column @failing_rule_offset if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'" else "line #{l}, column #{c}: failed rule '#{@failed_rule}'" end end def failure_caret l = current_line @failing_rule_offset c = current_column @failing_rule_offset line = lines[l-1] "#{line}\n#{' ' * (c - 1)}^" end def failure_character l = current_line @failing_rule_offset c = current_column @failing_rule_offset lines[l-1][c-1, 1] end def failure_oneline l = current_line @failing_rule_offset c = current_column @failing_rule_offset char = lines[l-1][c-1, 1] if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'" else "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'" end end class ParseError < RuntimeError end def raise_error raise ParseError, failure_oneline end def show_error(io=STDOUT) error_pos = @failing_rule_offset line_no = current_line(error_pos) col_no = current_column(error_pos) io.puts "On line #{line_no}, column #{col_no}:" if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')" else io.puts "Failed to match rule '#{@failed_rule}'" end io.puts "Got: #{string[error_pos,1].inspect}" line = lines[line_no-1] io.puts "=> #{line}" io.print(" " * (col_no + 3)) io.puts "^" end def set_failed_rule(name) if @pos > @failing_rule_offset @failed_rule = name @failing_rule_offset = @pos end end attr_reader :failed_rule def match_string(str) len = str.size if @string[pos,len] == str @pos += len return str end return nil end def scan(reg) if m = reg.match(@string[@pos..-1]) width = m.end(0) @pos += width return true end return nil end if "".respond_to? :ord def get_byte if @pos >= @string_size return nil end s = @string[@pos].ord @pos += 1 s end else def get_byte if @pos >= @string_size return nil end s = @string[@pos] @pos += 1 s end end def parse(rule=nil) # We invoke the rules indirectly via apply # instead of by just calling them as methods because # if the rules use left recursion, apply needs to # manage that. if !rule apply(:_root) else method = rule.gsub("-","_hyphen_") apply :"_#{method}" end end class MemoEntry def initialize(ans, pos) @ans = ans @pos = pos @result = nil @set = false @left_rec = false end attr_reader :ans, :pos, :result, :set attr_accessor :left_rec def move!(ans, pos, result) @ans = ans @pos = pos @result = result @set = true @left_rec = false end end def external_invoke(other, rule, *args) old_pos = @pos old_string = @string set_string other.string, other.pos begin if val = __send__(rule, *args) other.pos = @pos other.result = @result else other.set_failed_rule "#{self.class}##{rule}" end val ensure set_string old_string, old_pos end end def apply_with_args(rule, *args) memo_key = [rule, args] if m = @memoizations[memo_key][@pos] @pos = m.pos if !m.set m.left_rec = true return nil end @result = m.result return m.ans else m = MemoEntry.new(nil, @pos) @memoizations[memo_key][@pos] = m start_pos = @pos ans = __send__ rule, *args lr = m.left_rec m.move! ans, @pos, @result # Don't bother trying to grow the left recursion # if it's failing straight away (thus there is no seed) if ans and lr return grow_lr(rule, args, start_pos, m) else return ans end end end def apply(rule) if m = @memoizations[rule][@pos] @pos = m.pos if !m.set m.left_rec = true return nil end @result = m.result return m.ans else m = MemoEntry.new(nil, @pos) @memoizations[rule][@pos] = m start_pos = @pos ans = __send__ rule lr = m.left_rec m.move! ans, @pos, @result # Don't bother trying to grow the left recursion # if it's failing straight away (thus there is no seed) if ans and lr return grow_lr(rule, nil, start_pos, m) else return ans end end end def grow_lr(rule, args, start_pos, m) while true @pos = start_pos @result = m.result if args ans = __send__ rule, *args else ans = __send__ rule end return nil unless ans break if @pos <= m.pos m.move! ans, @pos, @result end @result = m.result @pos = m.pos return m.ans end class RuleInfo def initialize(name, rendered) @name = name @rendered = rendered end attr_reader :name, :rendered end def self.rule_info(name, rendered) RuleInfo.new(name, rendered) end # :startdoc: require 'rdoc' require 'rdoc/markup/to_joined_paragraph' require 'rdoc/markdown/entities' require 'rdoc/markdown/literals' ## # Supported extensions EXTENSIONS = [] ## # Extensions enabled by default DEFAULT_EXTENSIONS = [ :definition_lists, :github, :html, :notes, :strike, ] # :section: Extensions ## # Creates extension methods for the `name` extension to enable and disable # the extension and to query if they are active. def self.extension name EXTENSIONS << name define_method "#{name}?" do extension? name end define_method "#{name}=" do |enable| extension name, enable end end ## # Converts all newlines into hard breaks extension :break_on_newline ## # Allow style blocks extension :css ## # Allow PHP Markdown Extras style definition lists extension :definition_lists ## # Allow Github Flavored Markdown extension :github ## # Allow HTML extension :html ## # Enables the notes extension extension :notes ## # Enables the strike extension extension :strike # :section: ## # Parses the `markdown` document into an RDoc::Document using the default # extensions. def self.parse markdown parser = new parser.parse markdown end # TODO remove when kpeg 0.10 is released alias orig_initialize initialize # :nodoc: ## # Creates a new markdown parser that enables the given +extensions+. def initialize extensions = DEFAULT_EXTENSIONS, debug = false @debug = debug @formatter = RDoc::Markup::ToJoinedParagraph.new @extensions = extensions @references = nil @unlinked_references = nil @footnotes = nil @note_order = nil end ## # Wraps `text` in emphasis for rdoc inline formatting def emphasis text if text =~ /\A[a-z\d.\/]+\z/i then "_#{text}_" else "#{text}" end end ## # :category: Extensions # # Is the extension `name` enabled? def extension? name @extensions.include? name end ## # :category: Extensions # # Enables or disables the extension with `name` def extension name, enable if enable then @extensions |= [name] else @extensions -= [name] end end ## # Parses `text` in a clone of this parser. This is used for handling nested # lists the same way as markdown_parser. def inner_parse text # :nodoc: parser = clone parser.setup_parser text, @debug parser.peg_parse doc = parser.result doc.accept @formatter doc.parts end ## # Finds a link reference for `label` and creates a new link to it with # `content` as the link text. If `label` was not encountered in the # reference-gathering parser pass the label and content are reconstructed # with the linking `text` (usually whitespace). def link_to content, label = content, text = nil raise ParseError, 'enable notes extension' if content.start_with? '^' and label.equal? content if ref = @references[label] then "{#{content}}[#{ref}]" elsif label.equal? content then "[#{content}]#{text}" else "[#{content}]#{text}[#{label}]" end end ## # Creates an RDoc::Markup::ListItem by parsing the `unparsed` content from # the first parsing pass. def list_item_from unparsed parsed = inner_parse unparsed.join RDoc::Markup::ListItem.new nil, *parsed end ## # Stores `label` as a note and fills in previously unknown note references. def note label #foottext = "rdoc-label:foottext-#{label}:footmark-#{label}" #ref.replace foottext if ref = @unlinked_notes.delete(label) @notes[label] = foottext #"{^1}[rdoc-label:footmark-#{label}:foottext-#{label}] " end ## # Creates a new link for the footnote `reference` and adds the reference to # the note order list for proper display at the end of the document. def note_for ref @note_order << ref label = @note_order.length "{*#{label}}[rdoc-label:foottext-#{label}:footmark-#{label}]" end ## # The internal kpeg parse method alias peg_parse parse # :nodoc: ## # Creates an RDoc::Markup::Paragraph from `parts` and including # extension-specific behavior def paragraph parts parts = parts.map do |part| if "\n" == part then RDoc::Markup::HardBreak.new else part end end if break_on_newline? RDoc::Markup::Paragraph.new(*parts) end ## # Parses `markdown` into an RDoc::Document def parse markdown @references = {} @unlinked_references = {} markdown += "\n\n" setup_parser markdown, @debug peg_parse 'References' if notes? then @footnotes = {} setup_parser markdown, @debug peg_parse 'Notes' # using note_order on the first pass would be a bug @note_order = [] end setup_parser markdown, @debug peg_parse doc = result if notes? and not @footnotes.empty? then doc << RDoc::Markup::Rule.new(1) @note_order.each_with_index do |ref, index| label = index + 1 note = @footnotes[ref] link = "{^#{label}}[rdoc-label:footmark-#{label}:foottext-#{label}] " note.parts.unshift link doc << note end end doc.accept @formatter doc end ## # Stores `label` as a reference to `link` and fills in previously unknown # link references. def reference label, link if ref = @unlinked_references.delete(label) then ref.replace link end @references[label] = link end ## # Wraps `text` in strong markup for rdoc inline formatting def strong text if text =~ /\A[a-z\d.\/-]+\z/i then "*#{text}*" else "#{text}" end end ## # Wraps `text` in strike markup for rdoc inline formatting def strike text if text =~ /\A[a-z\d.\/-]+\z/i then "~#{text}~" else "#{text}" end end # :stopdoc: def setup_foreign_grammar @_grammar_literals = RDoc::Markdown::Literals.new(nil) end # root = Doc def _root _tmp = apply(:_Doc) set_failed_rule :_root unless _tmp return _tmp end # Doc = BOM? Block*:a { RDoc::Markup::Document.new(*a.compact) } def _Doc _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_BOM) unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save break end _ary = [] while true _tmp = apply(:_Block) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Document.new(*a.compact) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Doc unless _tmp return _tmp end # Block = @BlankLine* (BlockQuote | Verbatim | CodeFence | Note | Reference | HorizontalRule | Heading | OrderedList | BulletList | DefinitionList | HtmlBlock | StyleBlock | Para | Plain) def _Block _save = self.pos while true # sequence while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _save2 = self.pos while true # choice _tmp = apply(:_BlockQuote) break if _tmp self.pos = _save2 _tmp = apply(:_Verbatim) break if _tmp self.pos = _save2 _tmp = apply(:_CodeFence) break if _tmp self.pos = _save2 _tmp = apply(:_Note) break if _tmp self.pos = _save2 _tmp = apply(:_Reference) break if _tmp self.pos = _save2 _tmp = apply(:_HorizontalRule) break if _tmp self.pos = _save2 _tmp = apply(:_Heading) break if _tmp self.pos = _save2 _tmp = apply(:_OrderedList) break if _tmp self.pos = _save2 _tmp = apply(:_BulletList) break if _tmp self.pos = _save2 _tmp = apply(:_DefinitionList) break if _tmp self.pos = _save2 _tmp = apply(:_HtmlBlock) break if _tmp self.pos = _save2 _tmp = apply(:_StyleBlock) break if _tmp self.pos = _save2 _tmp = apply(:_Para) break if _tmp self.pos = _save2 _tmp = apply(:_Plain) break if _tmp self.pos = _save2 break end # end choice unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Block unless _tmp return _tmp end # Para = @NonindentSpace Inlines:a @BlankLine+ { paragraph a } def _Para _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _tmp = apply(:_Inlines) a = @result unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; paragraph a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Para unless _tmp return _tmp end # Plain = Inlines:a { paragraph a } def _Plain _save = self.pos while true # sequence _tmp = apply(:_Inlines) a = @result unless _tmp self.pos = _save break end @result = begin; paragraph a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Plain unless _tmp return _tmp end # AtxInline = !@Newline !(@Sp /#*/ @Sp @Newline) Inline def _AtxInline _save = self.pos while true # sequence _save1 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save3 break end _tmp = scan(/\A(?-mix:#*)/) unless _tmp self.pos = _save3 break end _tmp = _Sp() unless _tmp self.pos = _save3 break end _tmp = _Newline() unless _tmp self.pos = _save3 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _tmp = apply(:_Inline) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AtxInline unless _tmp return _tmp end # AtxStart = < /\#{1,6}/ > { text.length } def _AtxStart _save = self.pos while true # sequence _text_start = self.pos _tmp = scan(/\A(?-mix:\#{1,6})/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text.length ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AtxStart unless _tmp return _tmp end # AtxHeading = AtxStart:s @Sp AtxInline+:a (@Sp /#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) } def _AtxHeading _save = self.pos while true # sequence _tmp = apply(:_AtxStart) s = @result unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _save1 = self.pos _ary = [] _tmp = apply(:_AtxInline) if _tmp _ary << @result while true _tmp = apply(:_AtxInline) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save3 break end _tmp = scan(/\A(?-mix:#*)/) unless _tmp self.pos = _save3 break end _tmp = _Sp() unless _tmp self.pos = _save3 end break end # end sequence unless _tmp _tmp = true self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Heading.new(s, a.join) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AtxHeading unless _tmp return _tmp end # SetextHeading = (SetextHeading1 | SetextHeading2) def _SetextHeading _save = self.pos while true # choice _tmp = apply(:_SetextHeading1) break if _tmp self.pos = _save _tmp = apply(:_SetextHeading2) break if _tmp self.pos = _save break end # end choice set_failed_rule :_SetextHeading unless _tmp return _tmp end # SetextBottom1 = /={1,}/ @Newline def _SetextBottom1 _save = self.pos while true # sequence _tmp = scan(/\A(?-mix:={1,})/) unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_SetextBottom1 unless _tmp return _tmp end # SetextBottom2 = /-{1,}/ @Newline def _SetextBottom2 _save = self.pos while true # sequence _tmp = scan(/\A(?-mix:-{1,})/) unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_SetextBottom2 unless _tmp return _tmp end # SetextHeading1 = &(@RawLine SetextBottom1) @StartList:a (!@Endline Inline:b { a << b })+ @Sp @Newline SetextBottom1 { RDoc::Markup::Heading.new(1, a.join) } def _SetextHeading1 _save = self.pos while true # sequence _save1 = self.pos _save2 = self.pos while true # sequence _tmp = _RawLine() unless _tmp self.pos = _save2 break end _tmp = apply(:_SetextBottom1) unless _tmp self.pos = _save2 end break end # end sequence self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save3 = self.pos _save4 = self.pos while true # sequence _save5 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence if _tmp while true _save6 = self.pos while true # sequence _save7 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save3 end unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _tmp = apply(:_SetextBottom1) unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Heading.new(1, a.join) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_SetextHeading1 unless _tmp return _tmp end # SetextHeading2 = &(@RawLine SetextBottom2) @StartList:a (!@Endline Inline:b { a << b })+ @Sp @Newline SetextBottom2 { RDoc::Markup::Heading.new(2, a.join) } def _SetextHeading2 _save = self.pos while true # sequence _save1 = self.pos _save2 = self.pos while true # sequence _tmp = _RawLine() unless _tmp self.pos = _save2 break end _tmp = apply(:_SetextBottom2) unless _tmp self.pos = _save2 end break end # end sequence self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save3 = self.pos _save4 = self.pos while true # sequence _save5 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence if _tmp while true _save6 = self.pos while true # sequence _save7 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save3 end unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _tmp = apply(:_SetextBottom2) unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Heading.new(2, a.join) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_SetextHeading2 unless _tmp return _tmp end # Heading = (SetextHeading | AtxHeading) def _Heading _save = self.pos while true # choice _tmp = apply(:_SetextHeading) break if _tmp self.pos = _save _tmp = apply(:_AtxHeading) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Heading unless _tmp return _tmp end # BlockQuote = BlockQuoteRaw:a { RDoc::Markup::BlockQuote.new(*a) } def _BlockQuote _save = self.pos while true # sequence _tmp = apply(:_BlockQuoteRaw) a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::BlockQuote.new(*a) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_BlockQuote unless _tmp return _tmp end # BlockQuoteRaw = @StartList:a (">" " "? Line:l { a << l } (!">" !@BlankLine Line:c { a << c })* (@BlankLine:n { a << n })*)+ { inner_parse a.join } def _BlockQuoteRaw _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos while true # sequence _tmp = match_string(">") unless _tmp self.pos = _save2 break end _save3 = self.pos _tmp = match_string(" ") unless _tmp _tmp = true self.pos = _save3 end unless _tmp self.pos = _save2 break end _tmp = apply(:_Line) l = @result unless _tmp self.pos = _save2 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save2 break end while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _save7 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save5 break end _tmp = apply(:_Line) c = @result unless _tmp self.pos = _save5 break end @result = begin; a << c ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save2 break end while true _save9 = self.pos while true # sequence _tmp = _BlankLine() n = @result unless _tmp self.pos = _save9 break end @result = begin; a << n ; end _tmp = true unless _tmp self.pos = _save9 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence if _tmp while true _save10 = self.pos while true # sequence _tmp = match_string(">") unless _tmp self.pos = _save10 break end _save11 = self.pos _tmp = match_string(" ") unless _tmp _tmp = true self.pos = _save11 end unless _tmp self.pos = _save10 break end _tmp = apply(:_Line) l = @result unless _tmp self.pos = _save10 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save10 break end while true _save13 = self.pos while true # sequence _save14 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save14 unless _tmp self.pos = _save13 break end _save15 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save15 unless _tmp self.pos = _save13 break end _tmp = apply(:_Line) c = @result unless _tmp self.pos = _save13 break end @result = begin; a << c ; end _tmp = true unless _tmp self.pos = _save13 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save10 break end while true _save17 = self.pos while true # sequence _tmp = _BlankLine() n = @result unless _tmp self.pos = _save17 break end @result = begin; a << n ; end _tmp = true unless _tmp self.pos = _save17 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save10 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; inner_parse a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_BlockQuoteRaw unless _tmp return _tmp end # NonblankIndentedLine = !@BlankLine IndentedLine def _NonblankIndentedLine _save = self.pos while true # sequence _save1 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_IndentedLine) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_NonblankIndentedLine unless _tmp return _tmp end # VerbatimChunk = @BlankLine*:a NonblankIndentedLine+:b { a.concat b } def _VerbatimChunk _save = self.pos while true # sequence _ary = [] while true _tmp = _BlankLine() _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary a = @result unless _tmp self.pos = _save break end _save2 = self.pos _ary = [] _tmp = apply(:_NonblankIndentedLine) if _tmp _ary << @result while true _tmp = apply(:_NonblankIndentedLine) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save2 end b = @result unless _tmp self.pos = _save break end @result = begin; a.concat b ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_VerbatimChunk unless _tmp return _tmp end # Verbatim = VerbatimChunk+:a { RDoc::Markup::Verbatim.new(*a.flatten) } def _Verbatim _save = self.pos while true # sequence _save1 = self.pos _ary = [] _tmp = apply(:_VerbatimChunk) if _tmp _ary << @result while true _tmp = apply(:_VerbatimChunk) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Verbatim.new(*a.flatten) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Verbatim unless _tmp return _tmp end # HorizontalRule = @NonindentSpace ("*" @Sp "*" @Sp "*" (@Sp "*")* | "-" @Sp "-" @Sp "-" (@Sp "-")* | "_" @Sp "_" @Sp "_" (@Sp "_")*) @Sp @Newline @BlankLine+ { RDoc::Markup::Rule.new 1 } def _HorizontalRule _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _save2 = self.pos while true # sequence _tmp = match_string("*") unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 break end _tmp = match_string("*") unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 break end _tmp = match_string("*") unless _tmp self.pos = _save2 break end while true _save4 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save4 break end _tmp = match_string("*") unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save1 _save5 = self.pos while true # sequence _tmp = match_string("-") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = match_string("-") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = match_string("-") unless _tmp self.pos = _save5 break end while true _save7 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save7 break end _tmp = match_string("-") unless _tmp self.pos = _save7 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save1 _save8 = self.pos while true # sequence _tmp = match_string("_") unless _tmp self.pos = _save8 break end _tmp = _Sp() unless _tmp self.pos = _save8 break end _tmp = match_string("_") unless _tmp self.pos = _save8 break end _tmp = _Sp() unless _tmp self.pos = _save8 break end _tmp = match_string("_") unless _tmp self.pos = _save8 break end while true _save10 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save10 break end _tmp = match_string("_") unless _tmp self.pos = _save10 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save8 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _save11 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save11 end unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::Rule.new 1 ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HorizontalRule unless _tmp return _tmp end # Bullet = !HorizontalRule @NonindentSpace /[+*-]/ @Spacechar+ def _Bullet _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_HorizontalRule) _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _tmp = scan(/\A(?-mix:[+*-])/) unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _Spacechar() if _tmp while true _tmp = _Spacechar() break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Bullet unless _tmp return _tmp end # BulletList = &Bullet (ListTight | ListLoose):a { RDoc::Markup::List.new(:BULLET, *a) } def _BulletList _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_Bullet) self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos while true # choice _tmp = apply(:_ListTight) break if _tmp self.pos = _save2 _tmp = apply(:_ListLoose) break if _tmp self.pos = _save2 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::List.new(:BULLET, *a) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_BulletList unless _tmp return _tmp end # ListTight = ListItemTight+:a @BlankLine* !(Bullet | Enumerator) { a } def _ListTight _save = self.pos while true # sequence _save1 = self.pos _ary = [] _tmp = apply(:_ListItemTight) if _tmp _ary << @result while true _tmp = apply(:_ListItemTight) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end a = @result unless _tmp self.pos = _save break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _save3 = self.pos _save4 = self.pos while true # choice _tmp = apply(:_Bullet) break if _tmp self.pos = _save4 _tmp = apply(:_Enumerator) break if _tmp self.pos = _save4 break end # end choice _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListTight unless _tmp return _tmp end # ListLoose = @StartList:a (ListItem:b @BlankLine* { a << b })+ { a } def _ListLoose _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos while true # sequence _tmp = apply(:_ListItem) b = @result unless _tmp self.pos = _save2 break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save2 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence if _tmp while true _save4 = self.pos while true # sequence _tmp = apply(:_ListItem) b = @result unless _tmp self.pos = _save4 break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListLoose unless _tmp return _tmp end # ListItem = (Bullet | Enumerator) @StartList:a ListBlock:b { a << b } (ListContinuationBlock:c { a.push(*c) })* { list_item_from a } def _ListItem _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_Bullet) break if _tmp self.pos = _save1 _tmp = apply(:_Enumerator) break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _tmp = apply(:_ListBlock) b = @result unless _tmp self.pos = _save break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save break end while true _save3 = self.pos while true # sequence _tmp = apply(:_ListContinuationBlock) c = @result unless _tmp self.pos = _save3 break end @result = begin; a.push(*c) ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; list_item_from a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListItem unless _tmp return _tmp end # ListItemTight = (Bullet | Enumerator) ListBlock:a (!@BlankLine ListContinuationBlock:b { a.push(*b) })* !ListContinuationBlock { list_item_from a } def _ListItemTight _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_Bullet) break if _tmp self.pos = _save1 _tmp = apply(:_Enumerator) break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_ListBlock) a = @result unless _tmp self.pos = _save break end while true _save3 = self.pos while true # sequence _save4 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_ListContinuationBlock) b = @result unless _tmp self.pos = _save3 break end @result = begin; a.push(*b) ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _save5 = self.pos _tmp = apply(:_ListContinuationBlock) _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save break end @result = begin; list_item_from a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListItemTight unless _tmp return _tmp end # ListBlock = !@BlankLine Line:a ListBlockLine*:c { [a, *c] } def _ListBlock _save = self.pos while true # sequence _save1 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_Line) a = @result unless _tmp self.pos = _save break end _ary = [] while true _tmp = apply(:_ListBlockLine) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary c = @result unless _tmp self.pos = _save break end @result = begin; [a, *c] ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListBlock unless _tmp return _tmp end # ListContinuationBlock = @StartList:a @BlankLine* { a << "\n" } (Indent ListBlock:b { a.concat b })+ { a } def _ListContinuationBlock _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; a << "\n" ; end _tmp = true unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _tmp = apply(:_Indent) unless _tmp self.pos = _save3 break end _tmp = apply(:_ListBlock) b = @result unless _tmp self.pos = _save3 break end @result = begin; a.concat b ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save4 = self.pos while true # sequence _tmp = apply(:_Indent) unless _tmp self.pos = _save4 break end _tmp = apply(:_ListBlock) b = @result unless _tmp self.pos = _save4 break end @result = begin; a.concat b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListContinuationBlock unless _tmp return _tmp end # Enumerator = @NonindentSpace [0-9]+ "." @Spacechar+ def _Enumerator _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos _tmp = get_byte if _tmp unless _tmp >= 48 and _tmp <= 57 self.pos = _save2 _tmp = nil end end if _tmp while true _save3 = self.pos _tmp = get_byte if _tmp unless _tmp >= 48 and _tmp <= 57 self.pos = _save3 _tmp = nil end end break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end _tmp = match_string(".") unless _tmp self.pos = _save break end _save4 = self.pos _tmp = _Spacechar() if _tmp while true _tmp = _Spacechar() break unless _tmp end _tmp = true else self.pos = _save4 end unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Enumerator unless _tmp return _tmp end # OrderedList = &Enumerator (ListTight | ListLoose):a { RDoc::Markup::List.new(:NUMBER, *a) } def _OrderedList _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_Enumerator) self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos while true # choice _tmp = apply(:_ListTight) break if _tmp self.pos = _save2 _tmp = apply(:_ListLoose) break if _tmp self.pos = _save2 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::List.new(:NUMBER, *a) ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_OrderedList unless _tmp return _tmp end # ListBlockLine = !@BlankLine !(Indent? (Bullet | Enumerator)) !HorizontalRule OptionallyIndentedLine def _ListBlockLine _save = self.pos while true # sequence _save1 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_Indent) unless _tmp _tmp = true self.pos = _save4 end unless _tmp self.pos = _save3 break end _save5 = self.pos while true # choice _tmp = apply(:_Bullet) break if _tmp self.pos = _save5 _tmp = apply(:_Enumerator) break if _tmp self.pos = _save5 break end # end choice unless _tmp self.pos = _save3 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _save6 = self.pos _tmp = apply(:_HorizontalRule) _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save break end _tmp = apply(:_OptionallyIndentedLine) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ListBlockLine unless _tmp return _tmp end # HtmlOpenAnchor = "<" Spnl ("a" | "A") Spnl HtmlAttribute* ">" def _HtmlOpenAnchor _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("a") break if _tmp self.pos = _save1 _tmp = match_string("A") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlOpenAnchor unless _tmp return _tmp end # HtmlCloseAnchor = "<" Spnl "/" ("a" | "A") Spnl ">" def _HtmlCloseAnchor _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("a") break if _tmp self.pos = _save1 _tmp = match_string("A") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlCloseAnchor unless _tmp return _tmp end # HtmlAnchor = HtmlOpenAnchor (HtmlAnchor | !HtmlCloseAnchor .)* HtmlCloseAnchor def _HtmlAnchor _save = self.pos while true # sequence _tmp = apply(:_HtmlOpenAnchor) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlAnchor) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlCloseAnchor) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlCloseAnchor) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlAnchor unless _tmp return _tmp end # HtmlBlockOpenAddress = "<" Spnl ("address" | "ADDRESS") Spnl HtmlAttribute* ">" def _HtmlBlockOpenAddress _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("address") break if _tmp self.pos = _save1 _tmp = match_string("ADDRESS") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenAddress unless _tmp return _tmp end # HtmlBlockCloseAddress = "<" Spnl "/" ("address" | "ADDRESS") Spnl ">" def _HtmlBlockCloseAddress _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("address") break if _tmp self.pos = _save1 _tmp = match_string("ADDRESS") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseAddress unless _tmp return _tmp end # HtmlBlockAddress = HtmlBlockOpenAddress (HtmlBlockAddress | !HtmlBlockCloseAddress .)* HtmlBlockCloseAddress def _HtmlBlockAddress _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenAddress) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockAddress) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseAddress) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseAddress) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockAddress unless _tmp return _tmp end # HtmlBlockOpenBlockquote = "<" Spnl ("blockquote" | "BLOCKQUOTE") Spnl HtmlAttribute* ">" def _HtmlBlockOpenBlockquote _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("blockquote") break if _tmp self.pos = _save1 _tmp = match_string("BLOCKQUOTE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenBlockquote unless _tmp return _tmp end # HtmlBlockCloseBlockquote = "<" Spnl "/" ("blockquote" | "BLOCKQUOTE") Spnl ">" def _HtmlBlockCloseBlockquote _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("blockquote") break if _tmp self.pos = _save1 _tmp = match_string("BLOCKQUOTE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseBlockquote unless _tmp return _tmp end # HtmlBlockBlockquote = HtmlBlockOpenBlockquote (HtmlBlockBlockquote | !HtmlBlockCloseBlockquote .)* HtmlBlockCloseBlockquote def _HtmlBlockBlockquote _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenBlockquote) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockBlockquote) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseBlockquote) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseBlockquote) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockBlockquote unless _tmp return _tmp end # HtmlBlockOpenCenter = "<" Spnl ("center" | "CENTER") Spnl HtmlAttribute* ">" def _HtmlBlockOpenCenter _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("center") break if _tmp self.pos = _save1 _tmp = match_string("CENTER") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenCenter unless _tmp return _tmp end # HtmlBlockCloseCenter = "<" Spnl "/" ("center" | "CENTER") Spnl ">" def _HtmlBlockCloseCenter _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("center") break if _tmp self.pos = _save1 _tmp = match_string("CENTER") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseCenter unless _tmp return _tmp end # HtmlBlockCenter = HtmlBlockOpenCenter (HtmlBlockCenter | !HtmlBlockCloseCenter .)* HtmlBlockCloseCenter def _HtmlBlockCenter _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenCenter) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockCenter) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseCenter) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseCenter) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCenter unless _tmp return _tmp end # HtmlBlockOpenDir = "<" Spnl ("dir" | "DIR") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDir _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dir") break if _tmp self.pos = _save1 _tmp = match_string("DIR") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDir unless _tmp return _tmp end # HtmlBlockCloseDir = "<" Spnl "/" ("dir" | "DIR") Spnl ">" def _HtmlBlockCloseDir _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dir") break if _tmp self.pos = _save1 _tmp = match_string("DIR") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDir unless _tmp return _tmp end # HtmlBlockDir = HtmlBlockOpenDir (HtmlBlockDir | !HtmlBlockCloseDir .)* HtmlBlockCloseDir def _HtmlBlockDir _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDir) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDir) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDir) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDir) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDir unless _tmp return _tmp end # HtmlBlockOpenDiv = "<" Spnl ("div" | "DIV") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDiv _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("div") break if _tmp self.pos = _save1 _tmp = match_string("DIV") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDiv unless _tmp return _tmp end # HtmlBlockCloseDiv = "<" Spnl "/" ("div" | "DIV") Spnl ">" def _HtmlBlockCloseDiv _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("div") break if _tmp self.pos = _save1 _tmp = match_string("DIV") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDiv unless _tmp return _tmp end # HtmlBlockDiv = HtmlBlockOpenDiv (HtmlBlockDiv | !HtmlBlockCloseDiv .)* HtmlBlockCloseDiv def _HtmlBlockDiv _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDiv) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDiv) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDiv) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDiv) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDiv unless _tmp return _tmp end # HtmlBlockOpenDl = "<" Spnl ("dl" | "DL") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dl") break if _tmp self.pos = _save1 _tmp = match_string("DL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDl unless _tmp return _tmp end # HtmlBlockCloseDl = "<" Spnl "/" ("dl" | "DL") Spnl ">" def _HtmlBlockCloseDl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dl") break if _tmp self.pos = _save1 _tmp = match_string("DL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDl unless _tmp return _tmp end # HtmlBlockDl = HtmlBlockOpenDl (HtmlBlockDl | !HtmlBlockCloseDl .)* HtmlBlockCloseDl def _HtmlBlockDl _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDl) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDl) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDl) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDl) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDl unless _tmp return _tmp end # HtmlBlockOpenFieldset = "<" Spnl ("fieldset" | "FIELDSET") Spnl HtmlAttribute* ">" def _HtmlBlockOpenFieldset _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("fieldset") break if _tmp self.pos = _save1 _tmp = match_string("FIELDSET") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenFieldset unless _tmp return _tmp end # HtmlBlockCloseFieldset = "<" Spnl "/" ("fieldset" | "FIELDSET") Spnl ">" def _HtmlBlockCloseFieldset _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("fieldset") break if _tmp self.pos = _save1 _tmp = match_string("FIELDSET") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseFieldset unless _tmp return _tmp end # HtmlBlockFieldset = HtmlBlockOpenFieldset (HtmlBlockFieldset | !HtmlBlockCloseFieldset .)* HtmlBlockCloseFieldset def _HtmlBlockFieldset _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenFieldset) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockFieldset) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseFieldset) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseFieldset) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockFieldset unless _tmp return _tmp end # HtmlBlockOpenForm = "<" Spnl ("form" | "FORM") Spnl HtmlAttribute* ">" def _HtmlBlockOpenForm _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("form") break if _tmp self.pos = _save1 _tmp = match_string("FORM") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenForm unless _tmp return _tmp end # HtmlBlockCloseForm = "<" Spnl "/" ("form" | "FORM") Spnl ">" def _HtmlBlockCloseForm _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("form") break if _tmp self.pos = _save1 _tmp = match_string("FORM") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseForm unless _tmp return _tmp end # HtmlBlockForm = HtmlBlockOpenForm (HtmlBlockForm | !HtmlBlockCloseForm .)* HtmlBlockCloseForm def _HtmlBlockForm _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenForm) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockForm) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseForm) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseForm) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockForm unless _tmp return _tmp end # HtmlBlockOpenH1 = "<" Spnl ("h1" | "H1") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH1 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h1") break if _tmp self.pos = _save1 _tmp = match_string("H1") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH1 unless _tmp return _tmp end # HtmlBlockCloseH1 = "<" Spnl "/" ("h1" | "H1") Spnl ">" def _HtmlBlockCloseH1 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h1") break if _tmp self.pos = _save1 _tmp = match_string("H1") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH1 unless _tmp return _tmp end # HtmlBlockH1 = HtmlBlockOpenH1 (HtmlBlockH1 | !HtmlBlockCloseH1 .)* HtmlBlockCloseH1 def _HtmlBlockH1 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH1) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH1) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH1) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH1) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH1 unless _tmp return _tmp end # HtmlBlockOpenH2 = "<" Spnl ("h2" | "H2") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH2 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h2") break if _tmp self.pos = _save1 _tmp = match_string("H2") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH2 unless _tmp return _tmp end # HtmlBlockCloseH2 = "<" Spnl "/" ("h2" | "H2") Spnl ">" def _HtmlBlockCloseH2 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h2") break if _tmp self.pos = _save1 _tmp = match_string("H2") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH2 unless _tmp return _tmp end # HtmlBlockH2 = HtmlBlockOpenH2 (HtmlBlockH2 | !HtmlBlockCloseH2 .)* HtmlBlockCloseH2 def _HtmlBlockH2 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH2) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH2) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH2) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH2) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH2 unless _tmp return _tmp end # HtmlBlockOpenH3 = "<" Spnl ("h3" | "H3") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH3 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h3") break if _tmp self.pos = _save1 _tmp = match_string("H3") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH3 unless _tmp return _tmp end # HtmlBlockCloseH3 = "<" Spnl "/" ("h3" | "H3") Spnl ">" def _HtmlBlockCloseH3 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h3") break if _tmp self.pos = _save1 _tmp = match_string("H3") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH3 unless _tmp return _tmp end # HtmlBlockH3 = HtmlBlockOpenH3 (HtmlBlockH3 | !HtmlBlockCloseH3 .)* HtmlBlockCloseH3 def _HtmlBlockH3 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH3) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH3) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH3) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH3) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH3 unless _tmp return _tmp end # HtmlBlockOpenH4 = "<" Spnl ("h4" | "H4") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH4 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h4") break if _tmp self.pos = _save1 _tmp = match_string("H4") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH4 unless _tmp return _tmp end # HtmlBlockCloseH4 = "<" Spnl "/" ("h4" | "H4") Spnl ">" def _HtmlBlockCloseH4 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h4") break if _tmp self.pos = _save1 _tmp = match_string("H4") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH4 unless _tmp return _tmp end # HtmlBlockH4 = HtmlBlockOpenH4 (HtmlBlockH4 | !HtmlBlockCloseH4 .)* HtmlBlockCloseH4 def _HtmlBlockH4 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH4) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH4) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH4) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH4) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH4 unless _tmp return _tmp end # HtmlBlockOpenH5 = "<" Spnl ("h5" | "H5") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH5 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h5") break if _tmp self.pos = _save1 _tmp = match_string("H5") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH5 unless _tmp return _tmp end # HtmlBlockCloseH5 = "<" Spnl "/" ("h5" | "H5") Spnl ">" def _HtmlBlockCloseH5 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h5") break if _tmp self.pos = _save1 _tmp = match_string("H5") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH5 unless _tmp return _tmp end # HtmlBlockH5 = HtmlBlockOpenH5 (HtmlBlockH5 | !HtmlBlockCloseH5 .)* HtmlBlockCloseH5 def _HtmlBlockH5 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH5) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH5) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH5) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH5) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH5 unless _tmp return _tmp end # HtmlBlockOpenH6 = "<" Spnl ("h6" | "H6") Spnl HtmlAttribute* ">" def _HtmlBlockOpenH6 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h6") break if _tmp self.pos = _save1 _tmp = match_string("H6") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenH6 unless _tmp return _tmp end # HtmlBlockCloseH6 = "<" Spnl "/" ("h6" | "H6") Spnl ">" def _HtmlBlockCloseH6 _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("h6") break if _tmp self.pos = _save1 _tmp = match_string("H6") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseH6 unless _tmp return _tmp end # HtmlBlockH6 = HtmlBlockOpenH6 (HtmlBlockH6 | !HtmlBlockCloseH6 .)* HtmlBlockCloseH6 def _HtmlBlockH6 _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenH6) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockH6) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseH6) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseH6) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockH6 unless _tmp return _tmp end # HtmlBlockOpenMenu = "<" Spnl ("menu" | "MENU") Spnl HtmlAttribute* ">" def _HtmlBlockOpenMenu _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("menu") break if _tmp self.pos = _save1 _tmp = match_string("MENU") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenMenu unless _tmp return _tmp end # HtmlBlockCloseMenu = "<" Spnl "/" ("menu" | "MENU") Spnl ">" def _HtmlBlockCloseMenu _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("menu") break if _tmp self.pos = _save1 _tmp = match_string("MENU") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseMenu unless _tmp return _tmp end # HtmlBlockMenu = HtmlBlockOpenMenu (HtmlBlockMenu | !HtmlBlockCloseMenu .)* HtmlBlockCloseMenu def _HtmlBlockMenu _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenMenu) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockMenu) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseMenu) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseMenu) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockMenu unless _tmp return _tmp end # HtmlBlockOpenNoframes = "<" Spnl ("noframes" | "NOFRAMES") Spnl HtmlAttribute* ">" def _HtmlBlockOpenNoframes _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("noframes") break if _tmp self.pos = _save1 _tmp = match_string("NOFRAMES") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenNoframes unless _tmp return _tmp end # HtmlBlockCloseNoframes = "<" Spnl "/" ("noframes" | "NOFRAMES") Spnl ">" def _HtmlBlockCloseNoframes _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("noframes") break if _tmp self.pos = _save1 _tmp = match_string("NOFRAMES") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseNoframes unless _tmp return _tmp end # HtmlBlockNoframes = HtmlBlockOpenNoframes (HtmlBlockNoframes | !HtmlBlockCloseNoframes .)* HtmlBlockCloseNoframes def _HtmlBlockNoframes _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenNoframes) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockNoframes) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseNoframes) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseNoframes) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockNoframes unless _tmp return _tmp end # HtmlBlockOpenNoscript = "<" Spnl ("noscript" | "NOSCRIPT") Spnl HtmlAttribute* ">" def _HtmlBlockOpenNoscript _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("noscript") break if _tmp self.pos = _save1 _tmp = match_string("NOSCRIPT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenNoscript unless _tmp return _tmp end # HtmlBlockCloseNoscript = "<" Spnl "/" ("noscript" | "NOSCRIPT") Spnl ">" def _HtmlBlockCloseNoscript _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("noscript") break if _tmp self.pos = _save1 _tmp = match_string("NOSCRIPT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseNoscript unless _tmp return _tmp end # HtmlBlockNoscript = HtmlBlockOpenNoscript (HtmlBlockNoscript | !HtmlBlockCloseNoscript .)* HtmlBlockCloseNoscript def _HtmlBlockNoscript _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenNoscript) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockNoscript) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseNoscript) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseNoscript) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockNoscript unless _tmp return _tmp end # HtmlBlockOpenOl = "<" Spnl ("ol" | "OL") Spnl HtmlAttribute* ">" def _HtmlBlockOpenOl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("ol") break if _tmp self.pos = _save1 _tmp = match_string("OL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenOl unless _tmp return _tmp end # HtmlBlockCloseOl = "<" Spnl "/" ("ol" | "OL") Spnl ">" def _HtmlBlockCloseOl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("ol") break if _tmp self.pos = _save1 _tmp = match_string("OL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseOl unless _tmp return _tmp end # HtmlBlockOl = HtmlBlockOpenOl (HtmlBlockOl | !HtmlBlockCloseOl .)* HtmlBlockCloseOl def _HtmlBlockOl _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenOl) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockOl) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseOl) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseOl) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOl unless _tmp return _tmp end # HtmlBlockOpenP = "<" Spnl ("p" | "P") Spnl HtmlAttribute* ">" def _HtmlBlockOpenP _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("p") break if _tmp self.pos = _save1 _tmp = match_string("P") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenP unless _tmp return _tmp end # HtmlBlockCloseP = "<" Spnl "/" ("p" | "P") Spnl ">" def _HtmlBlockCloseP _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("p") break if _tmp self.pos = _save1 _tmp = match_string("P") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseP unless _tmp return _tmp end # HtmlBlockP = HtmlBlockOpenP (HtmlBlockP | !HtmlBlockCloseP .)* HtmlBlockCloseP def _HtmlBlockP _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenP) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockP) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseP) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseP) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockP unless _tmp return _tmp end # HtmlBlockOpenPre = "<" Spnl ("pre" | "PRE") Spnl HtmlAttribute* ">" def _HtmlBlockOpenPre _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("pre") break if _tmp self.pos = _save1 _tmp = match_string("PRE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenPre unless _tmp return _tmp end # HtmlBlockClosePre = "<" Spnl "/" ("pre" | "PRE") Spnl ">" def _HtmlBlockClosePre _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("pre") break if _tmp self.pos = _save1 _tmp = match_string("PRE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockClosePre unless _tmp return _tmp end # HtmlBlockPre = HtmlBlockOpenPre (HtmlBlockPre | !HtmlBlockClosePre .)* HtmlBlockClosePre def _HtmlBlockPre _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenPre) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockPre) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockClosePre) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockClosePre) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockPre unless _tmp return _tmp end # HtmlBlockOpenTable = "<" Spnl ("table" | "TABLE") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTable _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("table") break if _tmp self.pos = _save1 _tmp = match_string("TABLE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTable unless _tmp return _tmp end # HtmlBlockCloseTable = "<" Spnl "/" ("table" | "TABLE") Spnl ">" def _HtmlBlockCloseTable _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("table") break if _tmp self.pos = _save1 _tmp = match_string("TABLE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTable unless _tmp return _tmp end # HtmlBlockTable = HtmlBlockOpenTable (HtmlBlockTable | !HtmlBlockCloseTable .)* HtmlBlockCloseTable def _HtmlBlockTable _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTable) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTable) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTable) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTable) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTable unless _tmp return _tmp end # HtmlBlockOpenUl = "<" Spnl ("ul" | "UL") Spnl HtmlAttribute* ">" def _HtmlBlockOpenUl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("ul") break if _tmp self.pos = _save1 _tmp = match_string("UL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenUl unless _tmp return _tmp end # HtmlBlockCloseUl = "<" Spnl "/" ("ul" | "UL") Spnl ">" def _HtmlBlockCloseUl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("ul") break if _tmp self.pos = _save1 _tmp = match_string("UL") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseUl unless _tmp return _tmp end # HtmlBlockUl = HtmlBlockOpenUl (HtmlBlockUl | !HtmlBlockCloseUl .)* HtmlBlockCloseUl def _HtmlBlockUl _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenUl) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockUl) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseUl) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseUl) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockUl unless _tmp return _tmp end # HtmlBlockOpenDd = "<" Spnl ("dd" | "DD") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDd _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dd") break if _tmp self.pos = _save1 _tmp = match_string("DD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDd unless _tmp return _tmp end # HtmlBlockCloseDd = "<" Spnl "/" ("dd" | "DD") Spnl ">" def _HtmlBlockCloseDd _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dd") break if _tmp self.pos = _save1 _tmp = match_string("DD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDd unless _tmp return _tmp end # HtmlBlockDd = HtmlBlockOpenDd (HtmlBlockDd | !HtmlBlockCloseDd .)* HtmlBlockCloseDd def _HtmlBlockDd _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDd) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDd) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDd) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDd) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDd unless _tmp return _tmp end # HtmlBlockOpenDt = "<" Spnl ("dt" | "DT") Spnl HtmlAttribute* ">" def _HtmlBlockOpenDt _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dt") break if _tmp self.pos = _save1 _tmp = match_string("DT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenDt unless _tmp return _tmp end # HtmlBlockCloseDt = "<" Spnl "/" ("dt" | "DT") Spnl ">" def _HtmlBlockCloseDt _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("dt") break if _tmp self.pos = _save1 _tmp = match_string("DT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseDt unless _tmp return _tmp end # HtmlBlockDt = HtmlBlockOpenDt (HtmlBlockDt | !HtmlBlockCloseDt .)* HtmlBlockCloseDt def _HtmlBlockDt _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenDt) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockDt) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseDt) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseDt) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockDt unless _tmp return _tmp end # HtmlBlockOpenFrameset = "<" Spnl ("frameset" | "FRAMESET") Spnl HtmlAttribute* ">" def _HtmlBlockOpenFrameset _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("frameset") break if _tmp self.pos = _save1 _tmp = match_string("FRAMESET") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenFrameset unless _tmp return _tmp end # HtmlBlockCloseFrameset = "<" Spnl "/" ("frameset" | "FRAMESET") Spnl ">" def _HtmlBlockCloseFrameset _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("frameset") break if _tmp self.pos = _save1 _tmp = match_string("FRAMESET") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseFrameset unless _tmp return _tmp end # HtmlBlockFrameset = HtmlBlockOpenFrameset (HtmlBlockFrameset | !HtmlBlockCloseFrameset .)* HtmlBlockCloseFrameset def _HtmlBlockFrameset _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenFrameset) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockFrameset) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseFrameset) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseFrameset) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockFrameset unless _tmp return _tmp end # HtmlBlockOpenLi = "<" Spnl ("li" | "LI") Spnl HtmlAttribute* ">" def _HtmlBlockOpenLi _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("li") break if _tmp self.pos = _save1 _tmp = match_string("LI") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenLi unless _tmp return _tmp end # HtmlBlockCloseLi = "<" Spnl "/" ("li" | "LI") Spnl ">" def _HtmlBlockCloseLi _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("li") break if _tmp self.pos = _save1 _tmp = match_string("LI") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseLi unless _tmp return _tmp end # HtmlBlockLi = HtmlBlockOpenLi (HtmlBlockLi | !HtmlBlockCloseLi .)* HtmlBlockCloseLi def _HtmlBlockLi _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenLi) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockLi) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseLi) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseLi) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockLi unless _tmp return _tmp end # HtmlBlockOpenTbody = "<" Spnl ("tbody" | "TBODY") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTbody _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tbody") break if _tmp self.pos = _save1 _tmp = match_string("TBODY") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTbody unless _tmp return _tmp end # HtmlBlockCloseTbody = "<" Spnl "/" ("tbody" | "TBODY") Spnl ">" def _HtmlBlockCloseTbody _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tbody") break if _tmp self.pos = _save1 _tmp = match_string("TBODY") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTbody unless _tmp return _tmp end # HtmlBlockTbody = HtmlBlockOpenTbody (HtmlBlockTbody | !HtmlBlockCloseTbody .)* HtmlBlockCloseTbody def _HtmlBlockTbody _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTbody) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTbody) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTbody) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTbody) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTbody unless _tmp return _tmp end # HtmlBlockOpenTd = "<" Spnl ("td" | "TD") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTd _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("td") break if _tmp self.pos = _save1 _tmp = match_string("TD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTd unless _tmp return _tmp end # HtmlBlockCloseTd = "<" Spnl "/" ("td" | "TD") Spnl ">" def _HtmlBlockCloseTd _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("td") break if _tmp self.pos = _save1 _tmp = match_string("TD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTd unless _tmp return _tmp end # HtmlBlockTd = HtmlBlockOpenTd (HtmlBlockTd | !HtmlBlockCloseTd .)* HtmlBlockCloseTd def _HtmlBlockTd _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTd) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTd) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTd) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTd) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTd unless _tmp return _tmp end # HtmlBlockOpenTfoot = "<" Spnl ("tfoot" | "TFOOT") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTfoot _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tfoot") break if _tmp self.pos = _save1 _tmp = match_string("TFOOT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTfoot unless _tmp return _tmp end # HtmlBlockCloseTfoot = "<" Spnl "/" ("tfoot" | "TFOOT") Spnl ">" def _HtmlBlockCloseTfoot _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tfoot") break if _tmp self.pos = _save1 _tmp = match_string("TFOOT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTfoot unless _tmp return _tmp end # HtmlBlockTfoot = HtmlBlockOpenTfoot (HtmlBlockTfoot | !HtmlBlockCloseTfoot .)* HtmlBlockCloseTfoot def _HtmlBlockTfoot _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTfoot) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTfoot) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTfoot) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTfoot) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTfoot unless _tmp return _tmp end # HtmlBlockOpenTh = "<" Spnl ("th" | "TH") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTh _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("th") break if _tmp self.pos = _save1 _tmp = match_string("TH") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTh unless _tmp return _tmp end # HtmlBlockCloseTh = "<" Spnl "/" ("th" | "TH") Spnl ">" def _HtmlBlockCloseTh _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("th") break if _tmp self.pos = _save1 _tmp = match_string("TH") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTh unless _tmp return _tmp end # HtmlBlockTh = HtmlBlockOpenTh (HtmlBlockTh | !HtmlBlockCloseTh .)* HtmlBlockCloseTh def _HtmlBlockTh _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTh) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTh) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTh) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTh) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTh unless _tmp return _tmp end # HtmlBlockOpenThead = "<" Spnl ("thead" | "THEAD") Spnl HtmlAttribute* ">" def _HtmlBlockOpenThead _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("thead") break if _tmp self.pos = _save1 _tmp = match_string("THEAD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenThead unless _tmp return _tmp end # HtmlBlockCloseThead = "<" Spnl "/" ("thead" | "THEAD") Spnl ">" def _HtmlBlockCloseThead _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("thead") break if _tmp self.pos = _save1 _tmp = match_string("THEAD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseThead unless _tmp return _tmp end # HtmlBlockThead = HtmlBlockOpenThead (HtmlBlockThead | !HtmlBlockCloseThead .)* HtmlBlockCloseThead def _HtmlBlockThead _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenThead) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockThead) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseThead) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseThead) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockThead unless _tmp return _tmp end # HtmlBlockOpenTr = "<" Spnl ("tr" | "TR") Spnl HtmlAttribute* ">" def _HtmlBlockOpenTr _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tr") break if _tmp self.pos = _save1 _tmp = match_string("TR") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenTr unless _tmp return _tmp end # HtmlBlockCloseTr = "<" Spnl "/" ("tr" | "TR") Spnl ">" def _HtmlBlockCloseTr _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("tr") break if _tmp self.pos = _save1 _tmp = match_string("TR") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseTr unless _tmp return _tmp end # HtmlBlockTr = HtmlBlockOpenTr (HtmlBlockTr | !HtmlBlockCloseTr .)* HtmlBlockCloseTr def _HtmlBlockTr _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenTr) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # choice _tmp = apply(:_HtmlBlockTr) break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_HtmlBlockCloseTr) _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseTr) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockTr unless _tmp return _tmp end # HtmlBlockOpenScript = "<" Spnl ("script" | "SCRIPT") Spnl HtmlAttribute* ">" def _HtmlBlockOpenScript _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("script") break if _tmp self.pos = _save1 _tmp = match_string("SCRIPT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenScript unless _tmp return _tmp end # HtmlBlockCloseScript = "<" Spnl "/" ("script" | "SCRIPT") Spnl ">" def _HtmlBlockCloseScript _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("script") break if _tmp self.pos = _save1 _tmp = match_string("SCRIPT") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseScript unless _tmp return _tmp end # HtmlBlockScript = HtmlBlockOpenScript (!HtmlBlockCloseScript .)* HtmlBlockCloseScript def _HtmlBlockScript _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenScript) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _tmp = apply(:_HtmlBlockCloseScript) _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseScript) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockScript unless _tmp return _tmp end # HtmlBlockOpenHead = "<" Spnl ("head" | "HEAD") Spnl HtmlAttribute* ">" def _HtmlBlockOpenHead _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("head") break if _tmp self.pos = _save1 _tmp = match_string("HEAD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockOpenHead unless _tmp return _tmp end # HtmlBlockCloseHead = "<" Spnl "/" ("head" | "HEAD") Spnl ">" def _HtmlBlockCloseHead _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("head") break if _tmp self.pos = _save1 _tmp = match_string("HEAD") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockCloseHead unless _tmp return _tmp end # HtmlBlockHead = HtmlBlockOpenHead (!HtmlBlockCloseHead .)* HtmlBlockCloseHead def _HtmlBlockHead _save = self.pos while true # sequence _tmp = apply(:_HtmlBlockOpenHead) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _tmp = apply(:_HtmlBlockCloseHead) _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockCloseHead) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockHead unless _tmp return _tmp end # HtmlBlockInTags = (HtmlAnchor | HtmlBlockAddress | HtmlBlockBlockquote | HtmlBlockCenter | HtmlBlockDir | HtmlBlockDiv | HtmlBlockDl | HtmlBlockFieldset | HtmlBlockForm | HtmlBlockH1 | HtmlBlockH2 | HtmlBlockH3 | HtmlBlockH4 | HtmlBlockH5 | HtmlBlockH6 | HtmlBlockMenu | HtmlBlockNoframes | HtmlBlockNoscript | HtmlBlockOl | HtmlBlockP | HtmlBlockPre | HtmlBlockTable | HtmlBlockUl | HtmlBlockDd | HtmlBlockDt | HtmlBlockFrameset | HtmlBlockLi | HtmlBlockTbody | HtmlBlockTd | HtmlBlockTfoot | HtmlBlockTh | HtmlBlockThead | HtmlBlockTr | HtmlBlockScript | HtmlBlockHead) def _HtmlBlockInTags _save = self.pos while true # choice _tmp = apply(:_HtmlAnchor) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockAddress) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockBlockquote) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockCenter) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDir) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDiv) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDl) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockFieldset) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockForm) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH1) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH2) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH3) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH4) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH5) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockH6) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockMenu) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockNoframes) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockNoscript) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockOl) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockP) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockPre) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTable) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockUl) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDd) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockDt) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockFrameset) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockLi) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTbody) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTd) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTfoot) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTh) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockThead) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockTr) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockScript) break if _tmp self.pos = _save _tmp = apply(:_HtmlBlockHead) break if _tmp self.pos = _save break end # end choice set_failed_rule :_HtmlBlockInTags unless _tmp return _tmp end # HtmlBlock = < (HtmlBlockInTags | HtmlComment | HtmlBlockSelfClosing | HtmlUnclosed) > @BlankLine+ { if html? then RDoc::Markup::Raw.new text end } def _HtmlBlock _save = self.pos while true # sequence _text_start = self.pos _save1 = self.pos while true # choice _tmp = apply(:_HtmlBlockInTags) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlComment) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlBlockSelfClosing) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlUnclosed) break if _tmp self.pos = _save1 break end # end choice if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end @result = begin; if html? then RDoc::Markup::Raw.new text end ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlock unless _tmp return _tmp end # HtmlUnclosed = "<" Spnl HtmlUnclosedType Spnl HtmlAttribute* Spnl ">" def _HtmlUnclosed _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = apply(:_HtmlUnclosedType) unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlUnclosed unless _tmp return _tmp end # HtmlUnclosedType = ("HR" | "hr") def _HtmlUnclosedType _save = self.pos while true # choice _tmp = match_string("HR") break if _tmp self.pos = _save _tmp = match_string("hr") break if _tmp self.pos = _save break end # end choice set_failed_rule :_HtmlUnclosedType unless _tmp return _tmp end # HtmlBlockSelfClosing = "<" Spnl HtmlBlockType Spnl HtmlAttribute* "/" Spnl ">" def _HtmlBlockSelfClosing _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = apply(:_HtmlBlockType) unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlBlockSelfClosing unless _tmp return _tmp end # HtmlBlockType = ("ADDRESS" | "BLOCKQUOTE" | "CENTER" | "DD" | "DIR" | "DIV" | "DL" | "DT" | "FIELDSET" | "FORM" | "FRAMESET" | "H1" | "H2" | "H3" | "H4" | "H5" | "H6" | "HR" | "ISINDEX" | "LI" | "MENU" | "NOFRAMES" | "NOSCRIPT" | "OL" | "P" | "PRE" | "SCRIPT" | "TABLE" | "TBODY" | "TD" | "TFOOT" | "TH" | "THEAD" | "TR" | "UL" | "address" | "blockquote" | "center" | "dd" | "dir" | "div" | "dl" | "dt" | "fieldset" | "form" | "frameset" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "hr" | "isindex" | "li" | "menu" | "noframes" | "noscript" | "ol" | "p" | "pre" | "script" | "table" | "tbody" | "td" | "tfoot" | "th" | "thead" | "tr" | "ul") def _HtmlBlockType _save = self.pos while true # choice _tmp = match_string("ADDRESS") break if _tmp self.pos = _save _tmp = match_string("BLOCKQUOTE") break if _tmp self.pos = _save _tmp = match_string("CENTER") break if _tmp self.pos = _save _tmp = match_string("DD") break if _tmp self.pos = _save _tmp = match_string("DIR") break if _tmp self.pos = _save _tmp = match_string("DIV") break if _tmp self.pos = _save _tmp = match_string("DL") break if _tmp self.pos = _save _tmp = match_string("DT") break if _tmp self.pos = _save _tmp = match_string("FIELDSET") break if _tmp self.pos = _save _tmp = match_string("FORM") break if _tmp self.pos = _save _tmp = match_string("FRAMESET") break if _tmp self.pos = _save _tmp = match_string("H1") break if _tmp self.pos = _save _tmp = match_string("H2") break if _tmp self.pos = _save _tmp = match_string("H3") break if _tmp self.pos = _save _tmp = match_string("H4") break if _tmp self.pos = _save _tmp = match_string("H5") break if _tmp self.pos = _save _tmp = match_string("H6") break if _tmp self.pos = _save _tmp = match_string("HR") break if _tmp self.pos = _save _tmp = match_string("ISINDEX") break if _tmp self.pos = _save _tmp = match_string("LI") break if _tmp self.pos = _save _tmp = match_string("MENU") break if _tmp self.pos = _save _tmp = match_string("NOFRAMES") break if _tmp self.pos = _save _tmp = match_string("NOSCRIPT") break if _tmp self.pos = _save _tmp = match_string("OL") break if _tmp self.pos = _save _tmp = match_string("P") break if _tmp self.pos = _save _tmp = match_string("PRE") break if _tmp self.pos = _save _tmp = match_string("SCRIPT") break if _tmp self.pos = _save _tmp = match_string("TABLE") break if _tmp self.pos = _save _tmp = match_string("TBODY") break if _tmp self.pos = _save _tmp = match_string("TD") break if _tmp self.pos = _save _tmp = match_string("TFOOT") break if _tmp self.pos = _save _tmp = match_string("TH") break if _tmp self.pos = _save _tmp = match_string("THEAD") break if _tmp self.pos = _save _tmp = match_string("TR") break if _tmp self.pos = _save _tmp = match_string("UL") break if _tmp self.pos = _save _tmp = match_string("address") break if _tmp self.pos = _save _tmp = match_string("blockquote") break if _tmp self.pos = _save _tmp = match_string("center") break if _tmp self.pos = _save _tmp = match_string("dd") break if _tmp self.pos = _save _tmp = match_string("dir") break if _tmp self.pos = _save _tmp = match_string("div") break if _tmp self.pos = _save _tmp = match_string("dl") break if _tmp self.pos = _save _tmp = match_string("dt") break if _tmp self.pos = _save _tmp = match_string("fieldset") break if _tmp self.pos = _save _tmp = match_string("form") break if _tmp self.pos = _save _tmp = match_string("frameset") break if _tmp self.pos = _save _tmp = match_string("h1") break if _tmp self.pos = _save _tmp = match_string("h2") break if _tmp self.pos = _save _tmp = match_string("h3") break if _tmp self.pos = _save _tmp = match_string("h4") break if _tmp self.pos = _save _tmp = match_string("h5") break if _tmp self.pos = _save _tmp = match_string("h6") break if _tmp self.pos = _save _tmp = match_string("hr") break if _tmp self.pos = _save _tmp = match_string("isindex") break if _tmp self.pos = _save _tmp = match_string("li") break if _tmp self.pos = _save _tmp = match_string("menu") break if _tmp self.pos = _save _tmp = match_string("noframes") break if _tmp self.pos = _save _tmp = match_string("noscript") break if _tmp self.pos = _save _tmp = match_string("ol") break if _tmp self.pos = _save _tmp = match_string("p") break if _tmp self.pos = _save _tmp = match_string("pre") break if _tmp self.pos = _save _tmp = match_string("script") break if _tmp self.pos = _save _tmp = match_string("table") break if _tmp self.pos = _save _tmp = match_string("tbody") break if _tmp self.pos = _save _tmp = match_string("td") break if _tmp self.pos = _save _tmp = match_string("tfoot") break if _tmp self.pos = _save _tmp = match_string("th") break if _tmp self.pos = _save _tmp = match_string("thead") break if _tmp self.pos = _save _tmp = match_string("tr") break if _tmp self.pos = _save _tmp = match_string("ul") break if _tmp self.pos = _save break end # end choice set_failed_rule :_HtmlBlockType unless _tmp return _tmp end # StyleOpen = "<" Spnl ("style" | "STYLE") Spnl HtmlAttribute* ">" def _StyleOpen _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("style") break if _tmp self.pos = _save1 _tmp = match_string("STYLE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StyleOpen unless _tmp return _tmp end # StyleClose = "<" Spnl "/" ("style" | "STYLE") Spnl ">" def _StyleClose _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("/") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = match_string("style") break if _tmp self.pos = _save1 _tmp = match_string("STYLE") break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StyleClose unless _tmp return _tmp end # InStyleTags = StyleOpen (!StyleClose .)* StyleClose def _InStyleTags _save = self.pos while true # sequence _tmp = apply(:_StyleOpen) unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _tmp = apply(:_StyleClose) _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = apply(:_StyleClose) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_InStyleTags unless _tmp return _tmp end # StyleBlock = < InStyleTags > @BlankLine* { if css? then RDoc::Markup::Raw.new text end } def _StyleBlock _save = self.pos while true # sequence _text_start = self.pos _tmp = apply(:_InStyleTags) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; if css? then RDoc::Markup::Raw.new text end ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StyleBlock unless _tmp return _tmp end # Inlines = (!@Endline Inline:i { i } | @Endline:c &Inline { c })+:chunks @Endline? { chunks } def _Inlines _save = self.pos while true # sequence _save1 = self.pos _ary = [] _save2 = self.pos while true # choice _save3 = self.pos while true # sequence _save4 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_Inline) i = @result unless _tmp self.pos = _save3 break end @result = begin; i ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 _save5 = self.pos while true # sequence _tmp = _Endline() c = @result unless _tmp self.pos = _save5 break end _save6 = self.pos _tmp = apply(:_Inline) self.pos = _save6 unless _tmp self.pos = _save5 break end @result = begin; c ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice if _tmp _ary << @result while true _save7 = self.pos while true # choice _save8 = self.pos while true # sequence _save9 = self.pos _tmp = _Endline() _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Inline) i = @result unless _tmp self.pos = _save8 break end @result = begin; i ; end _tmp = true unless _tmp self.pos = _save8 end break end # end sequence break if _tmp self.pos = _save7 _save10 = self.pos while true # sequence _tmp = _Endline() c = @result unless _tmp self.pos = _save10 break end _save11 = self.pos _tmp = apply(:_Inline) self.pos = _save11 unless _tmp self.pos = _save10 break end @result = begin; c ; end _tmp = true unless _tmp self.pos = _save10 end break end # end sequence break if _tmp self.pos = _save7 break end # end choice _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end chunks = @result unless _tmp self.pos = _save break end _save12 = self.pos _tmp = _Endline() unless _tmp _tmp = true self.pos = _save12 end unless _tmp self.pos = _save break end @result = begin; chunks ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Inlines unless _tmp return _tmp end # Inline = (Str | @Endline | UlOrStarLine | @Space | Strong | Emph | Strike | Image | Link | NoteReference | InlineNote | Code | RawHtml | Entity | EscapedChar | Symbol) def _Inline _save = self.pos while true # choice _tmp = apply(:_Str) break if _tmp self.pos = _save _tmp = _Endline() break if _tmp self.pos = _save _tmp = apply(:_UlOrStarLine) break if _tmp self.pos = _save _tmp = _Space() break if _tmp self.pos = _save _tmp = apply(:_Strong) break if _tmp self.pos = _save _tmp = apply(:_Emph) break if _tmp self.pos = _save _tmp = apply(:_Strike) break if _tmp self.pos = _save _tmp = apply(:_Image) break if _tmp self.pos = _save _tmp = apply(:_Link) break if _tmp self.pos = _save _tmp = apply(:_NoteReference) break if _tmp self.pos = _save _tmp = apply(:_InlineNote) break if _tmp self.pos = _save _tmp = apply(:_Code) break if _tmp self.pos = _save _tmp = apply(:_RawHtml) break if _tmp self.pos = _save _tmp = apply(:_Entity) break if _tmp self.pos = _save _tmp = apply(:_EscapedChar) break if _tmp self.pos = _save _tmp = apply(:_Symbol) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Inline unless _tmp return _tmp end # Space = @Spacechar+ { " " } def _Space _save = self.pos while true # sequence _save1 = self.pos _tmp = _Spacechar() if _tmp while true _tmp = _Spacechar() break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; " " ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Space unless _tmp return _tmp end # Str = @StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { a } def _Str _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _text_start = self.pos _save1 = self.pos _tmp = _NormalChar() if _tmp while true _tmp = _NormalChar() break unless _tmp end _tmp = true else self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; a = text ; end _tmp = true unless _tmp self.pos = _save break end while true _save3 = self.pos while true # sequence _tmp = apply(:_StrChunk) c = @result unless _tmp self.pos = _save3 break end @result = begin; a << c ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Str unless _tmp return _tmp end # StrChunk = < (@NormalChar | /_+/ &Alphanumeric)+ > { text } def _StrChunk _save = self.pos while true # sequence _text_start = self.pos _save1 = self.pos _save2 = self.pos while true # choice _tmp = _NormalChar() break if _tmp self.pos = _save2 _save3 = self.pos while true # sequence _tmp = scan(/\A(?-mix:_+)/) unless _tmp self.pos = _save3 break end _save4 = self.pos _tmp = apply(:_Alphanumeric) self.pos = _save4 unless _tmp self.pos = _save3 end break end # end sequence break if _tmp self.pos = _save2 break end # end choice if _tmp while true _save5 = self.pos while true # choice _tmp = _NormalChar() break if _tmp self.pos = _save5 _save6 = self.pos while true # sequence _tmp = scan(/\A(?-mix:_+)/) unless _tmp self.pos = _save6 break end _save7 = self.pos _tmp = apply(:_Alphanumeric) self.pos = _save7 unless _tmp self.pos = _save6 end break end # end sequence break if _tmp self.pos = _save5 break end # end choice break unless _tmp end _tmp = true else self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StrChunk unless _tmp return _tmp end # EscapedChar = "\\" !@Newline < /[:\\`|*_{}\[\]()#+.!><-]/ > { text } def _EscapedChar _save = self.pos while true # sequence _tmp = match_string("\\") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _text_start = self.pos _tmp = scan(/\A(?-mix:[:\\`|*_{}\[\]()#+.!><-])/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_EscapedChar unless _tmp return _tmp end # Entity = (HexEntity | DecEntity | CharEntity):a { a } def _Entity _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_HexEntity) break if _tmp self.pos = _save1 _tmp = apply(:_DecEntity) break if _tmp self.pos = _save1 _tmp = apply(:_CharEntity) break if _tmp self.pos = _save1 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Entity unless _tmp return _tmp end # Endline = (@LineBreak | @TerminalEndline | @NormalEndline) def _Endline _save = self.pos while true # choice _tmp = _LineBreak() break if _tmp self.pos = _save _tmp = _TerminalEndline() break if _tmp self.pos = _save _tmp = _NormalEndline() break if _tmp self.pos = _save break end # end choice set_failed_rule :_Endline unless _tmp return _tmp end # NormalEndline = @Sp @Newline !@BlankLine !">" !AtxStart !(Line /={1,}|-{1,}/ @Newline) { "\n" } def _NormalEndline _save = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _save3 = self.pos _tmp = apply(:_AtxStart) _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save break end _save4 = self.pos _save5 = self.pos while true # sequence _tmp = apply(:_Line) unless _tmp self.pos = _save5 break end _tmp = scan(/\A(?-mix:={1,}|-{1,})/) unless _tmp self.pos = _save5 break end _tmp = _Newline() unless _tmp self.pos = _save5 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save break end @result = begin; "\n" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_NormalEndline unless _tmp return _tmp end # TerminalEndline = @Sp @Newline @Eof def _TerminalEndline _save = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end _tmp = _Eof() unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_TerminalEndline unless _tmp return _tmp end # LineBreak = " " @NormalEndline { RDoc::Markup::HardBreak.new } def _LineBreak _save = self.pos while true # sequence _tmp = match_string(" ") unless _tmp self.pos = _save break end _tmp = _NormalEndline() unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::HardBreak.new ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_LineBreak unless _tmp return _tmp end # Symbol = < @SpecialChar > { text } def _Symbol _save = self.pos while true # sequence _text_start = self.pos _tmp = _SpecialChar() if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Symbol unless _tmp return _tmp end # UlOrStarLine = (UlLine | StarLine):a { a } def _UlOrStarLine _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_UlLine) break if _tmp self.pos = _save1 _tmp = apply(:_StarLine) break if _tmp self.pos = _save1 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_UlOrStarLine unless _tmp return _tmp end # StarLine = (< /\*{4,}/ > { text } | < @Spacechar /\*+/ &@Spacechar > { text }) def _StarLine _save = self.pos while true # choice _save1 = self.pos while true # sequence _text_start = self.pos _tmp = scan(/\A(?-mix:\*{4,})/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save1 break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save1 end break end # end sequence break if _tmp self.pos = _save _save2 = self.pos while true # sequence _text_start = self.pos _save3 = self.pos while true # sequence _tmp = _Spacechar() unless _tmp self.pos = _save3 break end _tmp = scan(/\A(?-mix:\*+)/) unless _tmp self.pos = _save3 break end _save4 = self.pos _tmp = _Spacechar() self.pos = _save4 unless _tmp self.pos = _save3 end break end # end sequence if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save2 break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save break end # end choice set_failed_rule :_StarLine unless _tmp return _tmp end # UlLine = (< /_{4,}/ > { text } | < @Spacechar /_+/ &@Spacechar > { text }) def _UlLine _save = self.pos while true # choice _save1 = self.pos while true # sequence _text_start = self.pos _tmp = scan(/\A(?-mix:_{4,})/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save1 break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save1 end break end # end sequence break if _tmp self.pos = _save _save2 = self.pos while true # sequence _text_start = self.pos _save3 = self.pos while true # sequence _tmp = _Spacechar() unless _tmp self.pos = _save3 break end _tmp = scan(/\A(?-mix:_+)/) unless _tmp self.pos = _save3 break end _save4 = self.pos _tmp = _Spacechar() self.pos = _save4 unless _tmp self.pos = _save3 end break end # end sequence if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save2 break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save break end # end choice set_failed_rule :_UlLine unless _tmp return _tmp end # Emph = (EmphStar | EmphUl) def _Emph _save = self.pos while true # choice _tmp = apply(:_EmphStar) break if _tmp self.pos = _save _tmp = apply(:_EmphUl) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Emph unless _tmp return _tmp end # Whitespace = (@Spacechar | @Newline) def _Whitespace _save = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save _tmp = _Newline() break if _tmp self.pos = _save break end # end choice set_failed_rule :_Whitespace unless _tmp return _tmp end # EmphStar = "*" !@Whitespace @StartList:a (!"*" Inline:b { a << b } | StrongStar:b { a << b })+ "*" { emphasis a.join } def _EmphStar _save = self.pos while true # sequence _tmp = match_string("*") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # choice _save4 = self.pos while true # sequence _save5 = self.pos _tmp = match_string("*") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break if _tmp self.pos = _save3 _save6 = self.pos while true # sequence _tmp = apply(:_StrongStar) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break if _tmp self.pos = _save3 break end # end choice if _tmp while true _save7 = self.pos while true # choice _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string("*") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save8 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save8 end break end # end sequence break if _tmp self.pos = _save7 _save10 = self.pos while true # sequence _tmp = apply(:_StrongStar) b = @result unless _tmp self.pos = _save10 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save10 end break end # end sequence break if _tmp self.pos = _save7 break end # end choice break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("*") unless _tmp self.pos = _save break end @result = begin; emphasis a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_EmphStar unless _tmp return _tmp end # EmphUl = "_" !@Whitespace @StartList:a (!"_" Inline:b { a << b } | StrongUl:b { a << b })+ "_" { emphasis a.join } def _EmphUl _save = self.pos while true # sequence _tmp = match_string("_") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # choice _save4 = self.pos while true # sequence _save5 = self.pos _tmp = match_string("_") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break if _tmp self.pos = _save3 _save6 = self.pos while true # sequence _tmp = apply(:_StrongUl) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break if _tmp self.pos = _save3 break end # end choice if _tmp while true _save7 = self.pos while true # choice _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string("_") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save8 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save8 end break end # end sequence break if _tmp self.pos = _save7 _save10 = self.pos while true # sequence _tmp = apply(:_StrongUl) b = @result unless _tmp self.pos = _save10 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save10 end break end # end sequence break if _tmp self.pos = _save7 break end # end choice break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("_") unless _tmp self.pos = _save break end @result = begin; emphasis a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_EmphUl unless _tmp return _tmp end # Strong = (StrongStar | StrongUl) def _Strong _save = self.pos while true # choice _tmp = apply(:_StrongStar) break if _tmp self.pos = _save _tmp = apply(:_StrongUl) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Strong unless _tmp return _tmp end # StrongStar = "**" !@Whitespace @StartList:a (!"**" Inline:b { a << b })+ "**" { strong a.join } def _StrongStar _save = self.pos while true # sequence _tmp = match_string("**") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("**") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save3 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = match_string("**") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save5 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("**") unless _tmp self.pos = _save break end @result = begin; strong a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StrongStar unless _tmp return _tmp end # StrongUl = "__" !@Whitespace @StartList:a (!"__" Inline:b { a << b })+ "__" { strong a.join } def _StrongUl _save = self.pos while true # sequence _tmp = match_string("__") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("__") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save3 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = match_string("__") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save5 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("__") unless _tmp self.pos = _save break end @result = begin; strong a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StrongUl unless _tmp return _tmp end # Strike = &{ strike? } "~~" !@Whitespace @StartList:a (!"~~" Inline:b { a << b })+ "~~" { strike a.join } def _Strike _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; strike? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = match_string("~~") unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _Whitespace() _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save3 = self.pos _save4 = self.pos while true # sequence _save5 = self.pos _tmp = match_string("~~") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save4 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence if _tmp while true _save6 = self.pos while true # sequence _save7 = self.pos _tmp = match_string("~~") _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _tmp = apply(:_Inline) b = @result unless _tmp self.pos = _save6 break end @result = begin; a << b ; end _tmp = true unless _tmp self.pos = _save6 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save3 end unless _tmp self.pos = _save break end _tmp = match_string("~~") unless _tmp self.pos = _save break end @result = begin; strike a.join ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Strike unless _tmp return _tmp end # Image = "!" (ExplicitLink | ReferenceLink):a { "rdoc-image:#{a[/\[(.*)\]/, 1]}" } def _Image _save = self.pos while true # sequence _tmp = match_string("!") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _tmp = apply(:_ExplicitLink) break if _tmp self.pos = _save1 _tmp = apply(:_ReferenceLink) break if _tmp self.pos = _save1 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; "rdoc-image:#{a[/\[(.*)\]/, 1]}" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Image unless _tmp return _tmp end # Link = (ExplicitLink | ReferenceLink | AutoLink) def _Link _save = self.pos while true # choice _tmp = apply(:_ExplicitLink) break if _tmp self.pos = _save _tmp = apply(:_ReferenceLink) break if _tmp self.pos = _save _tmp = apply(:_AutoLink) break if _tmp self.pos = _save break end # end choice set_failed_rule :_Link unless _tmp return _tmp end # ReferenceLink = (ReferenceLinkDouble | ReferenceLinkSingle) def _ReferenceLink _save = self.pos while true # choice _tmp = apply(:_ReferenceLinkDouble) break if _tmp self.pos = _save _tmp = apply(:_ReferenceLinkSingle) break if _tmp self.pos = _save break end # end choice set_failed_rule :_ReferenceLink unless _tmp return _tmp end # ReferenceLinkDouble = Label:content < Spnl > !"[]" Label:label { link_to content, label, text } def _ReferenceLinkDouble _save = self.pos while true # sequence _tmp = apply(:_Label) content = @result unless _tmp self.pos = _save break end _text_start = self.pos _tmp = apply(:_Spnl) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("[]") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_Label) label = @result unless _tmp self.pos = _save break end @result = begin; link_to content, label, text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ReferenceLinkDouble unless _tmp return _tmp end # ReferenceLinkSingle = Label:content < (Spnl "[]")? > { link_to content, content, text } def _ReferenceLinkSingle _save = self.pos while true # sequence _tmp = apply(:_Label) content = @result unless _tmp self.pos = _save break end _text_start = self.pos _save1 = self.pos _save2 = self.pos while true # sequence _tmp = apply(:_Spnl) unless _tmp self.pos = _save2 break end _tmp = match_string("[]") unless _tmp self.pos = _save2 end break end # end sequence unless _tmp _tmp = true self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; link_to content, content, text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ReferenceLinkSingle unless _tmp return _tmp end # ExplicitLink = Label:l "(" @Sp Source:s Spnl Title @Sp ")" { "{#{l}}[#{s}]" } def _ExplicitLink _save = self.pos while true # sequence _tmp = apply(:_Label) l = @result unless _tmp self.pos = _save break end _tmp = match_string("(") unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = apply(:_Source) s = @result unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = apply(:_Title) unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = match_string(")") unless _tmp self.pos = _save break end @result = begin; "{#{l}}[#{s}]" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ExplicitLink unless _tmp return _tmp end # Source = ("<" < SourceContents > ">" | < SourceContents >) { text } def _Source _save = self.pos while true # sequence _save1 = self.pos while true # choice _save2 = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save2 break end _text_start = self.pos _tmp = apply(:_SourceContents) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save2 break end _tmp = match_string(">") unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save1 _text_start = self.pos _tmp = apply(:_SourceContents) if _tmp text = get_text(_text_start) end break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Source unless _tmp return _tmp end # SourceContents = ((!"(" !")" !">" Nonspacechar)+ | "(" SourceContents ")")* def _SourceContents while true _save1 = self.pos while true # choice _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("(") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _save5 = self.pos _tmp = match_string(")") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save3 break end _save6 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save3 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save7 = self.pos while true # sequence _save8 = self.pos _tmp = match_string("(") _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save7 break end _save9 = self.pos _tmp = match_string(")") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save7 break end _save10 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save10 unless _tmp self.pos = _save7 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save7 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end break if _tmp self.pos = _save1 _save11 = self.pos while true # sequence _tmp = match_string("(") unless _tmp self.pos = _save11 break end _tmp = apply(:_SourceContents) unless _tmp self.pos = _save11 break end _tmp = match_string(")") unless _tmp self.pos = _save11 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice break unless _tmp end _tmp = true set_failed_rule :_SourceContents unless _tmp return _tmp end # Title = (TitleSingle | TitleDouble | ""):a { a } def _Title _save = self.pos while true # sequence _save1 = self.pos while true # choice _tmp = apply(:_TitleSingle) break if _tmp self.pos = _save1 _tmp = apply(:_TitleDouble) break if _tmp self.pos = _save1 _tmp = match_string("") break if _tmp self.pos = _save1 break end # end choice a = @result unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Title unless _tmp return _tmp end # TitleSingle = "'" (!("'" @Sp (")" | @Newline)) .)* "'" def _TitleSingle _save = self.pos while true # sequence _tmp = match_string("'") unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # sequence _tmp = match_string("'") unless _tmp self.pos = _save4 break end _tmp = _Sp() unless _tmp self.pos = _save4 break end _save5 = self.pos while true # choice _tmp = match_string(")") break if _tmp self.pos = _save5 _tmp = _Newline() break if _tmp self.pos = _save5 break end # end choice unless _tmp self.pos = _save4 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("'") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_TitleSingle unless _tmp return _tmp end # TitleDouble = "\"" (!("\"" @Sp (")" | @Newline)) .)* "\"" def _TitleDouble _save = self.pos while true # sequence _tmp = match_string("\"") unless _tmp self.pos = _save break end while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # sequence _tmp = match_string("\"") unless _tmp self.pos = _save4 break end _tmp = _Sp() unless _tmp self.pos = _save4 break end _save5 = self.pos while true # choice _tmp = match_string(")") break if _tmp self.pos = _save5 _tmp = _Newline() break if _tmp self.pos = _save5 break end # end choice unless _tmp self.pos = _save4 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("\"") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_TitleDouble unless _tmp return _tmp end # AutoLink = (AutoLinkUrl | AutoLinkEmail) def _AutoLink _save = self.pos while true # choice _tmp = apply(:_AutoLinkUrl) break if _tmp self.pos = _save _tmp = apply(:_AutoLinkEmail) break if _tmp self.pos = _save break end # end choice set_failed_rule :_AutoLink unless _tmp return _tmp end # AutoLinkUrl = "<" < /[A-Za-z]+/ "://" (!@Newline !">" .)+ > ">" { text } def _AutoLinkUrl _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _text_start = self.pos _save1 = self.pos while true # sequence _tmp = scan(/\A(?-mix:[A-Za-z]+)/) unless _tmp self.pos = _save1 break end _tmp = match_string("://") unless _tmp self.pos = _save1 break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _save5 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save6 = self.pos while true # sequence _save7 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _save8 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save6 break end _tmp = get_byte unless _tmp self.pos = _save6 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save1 end break end # end sequence if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AutoLinkUrl unless _tmp return _tmp end # AutoLinkEmail = "<" "mailto:"? < /[\w+.\/!%~$-]+/i "@" (!@Newline !">" .)+ > ">" { "mailto:#{text}" } def _AutoLinkEmail _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("mailto:") unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save break end _text_start = self.pos _save2 = self.pos while true # sequence _tmp = scan(/\A(?i-mx:[\w+.\/!%~$-]+)/) unless _tmp self.pos = _save2 break end _tmp = match_string("@") unless _tmp self.pos = _save2 break end _save3 = self.pos _save4 = self.pos while true # sequence _save5 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _save6 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save4 break end _tmp = get_byte unless _tmp self.pos = _save4 end break end # end sequence if _tmp while true _save7 = self.pos while true # sequence _save8 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save7 break end _save9 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save7 break end _tmp = get_byte unless _tmp self.pos = _save7 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save3 end unless _tmp self.pos = _save2 end break end # end sequence if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save break end @result = begin; "mailto:#{text}" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_AutoLinkEmail unless _tmp return _tmp end # Reference = @NonindentSpace !"[]" Label:label ":" Spnl RefSrc:link RefTitle @BlankLine+ { # TODO use title reference label, link nil } def _Reference _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("[]") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_Label) label = @result unless _tmp self.pos = _save break end _tmp = match_string(":") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = apply(:_RefSrc) link = @result unless _tmp self.pos = _save break end _tmp = apply(:_RefTitle) unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end @result = begin; # TODO use title reference label, link nil ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Reference unless _tmp return _tmp end # Label = "[" (!"^" &{ notes? } | &. &{ !notes? }) @StartList:a (!"]" Inline:l { a << l })* "]" { a.join.gsub(/\s+/, ' ') } def _Label _save = self.pos while true # sequence _tmp = match_string("[") unless _tmp self.pos = _save break end _save1 = self.pos while true # choice _save2 = self.pos while true # sequence _save3 = self.pos _tmp = match_string("^") _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _save4 = self.pos _tmp = begin; notes? ; end self.pos = _save4 unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save1 _save5 = self.pos while true # sequence _save6 = self.pos _tmp = get_byte self.pos = _save6 unless _tmp self.pos = _save5 break end _save7 = self.pos _tmp = begin; !notes? ; end self.pos = _save7 unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end while true _save9 = self.pos while true # sequence _save10 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save10 unless _tmp self.pos = _save9 break end _tmp = apply(:_Inline) l = @result unless _tmp self.pos = _save9 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save9 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("]") unless _tmp self.pos = _save break end @result = begin; a.join.gsub(/\s+/, ' ') ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Label unless _tmp return _tmp end # RefSrc = < Nonspacechar+ > { text } def _RefSrc _save = self.pos while true # sequence _text_start = self.pos _save1 = self.pos _tmp = apply(:_Nonspacechar) if _tmp while true _tmp = apply(:_Nonspacechar) break unless _tmp end _tmp = true else self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RefSrc unless _tmp return _tmp end # RefTitle = (RefTitleSingle | RefTitleDouble | RefTitleParens | EmptyTitle) def _RefTitle _save = self.pos while true # choice _tmp = apply(:_RefTitleSingle) break if _tmp self.pos = _save _tmp = apply(:_RefTitleDouble) break if _tmp self.pos = _save _tmp = apply(:_RefTitleParens) break if _tmp self.pos = _save _tmp = apply(:_EmptyTitle) break if _tmp self.pos = _save break end # end choice set_failed_rule :_RefTitle unless _tmp return _tmp end # EmptyTitle = "" def _EmptyTitle _tmp = match_string("") set_failed_rule :_EmptyTitle unless _tmp return _tmp end # RefTitleSingle = Spnl "'" < (!("'" @Sp @Newline | @Newline) .)* > "'" { text } def _RefTitleSingle _save = self.pos while true # sequence _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("'") unless _tmp self.pos = _save break end _text_start = self.pos while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # choice _save5 = self.pos while true # sequence _tmp = match_string("'") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = _Newline() unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save4 _tmp = _Newline() break if _tmp self.pos = _save4 break end # end choice _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string("'") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RefTitleSingle unless _tmp return _tmp end # RefTitleDouble = Spnl "\"" < (!("\"" @Sp @Newline | @Newline) .)* > "\"" { text } def _RefTitleDouble _save = self.pos while true # sequence _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("\"") unless _tmp self.pos = _save break end _text_start = self.pos while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # choice _save5 = self.pos while true # sequence _tmp = match_string("\"") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = _Newline() unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save4 _tmp = _Newline() break if _tmp self.pos = _save4 break end # end choice _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string("\"") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RefTitleDouble unless _tmp return _tmp end # RefTitleParens = Spnl "(" < (!(")" @Sp @Newline | @Newline) .)* > ")" { text } def _RefTitleParens _save = self.pos while true # sequence _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string("(") unless _tmp self.pos = _save break end _text_start = self.pos while true _save2 = self.pos while true # sequence _save3 = self.pos _save4 = self.pos while true # choice _save5 = self.pos while true # sequence _tmp = match_string(")") unless _tmp self.pos = _save5 break end _tmp = _Sp() unless _tmp self.pos = _save5 break end _tmp = _Newline() unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save4 _tmp = _Newline() break if _tmp self.pos = _save4 break end # end choice _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(")") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RefTitleParens unless _tmp return _tmp end # References = (Reference | SkipBlock)* def _References while true _save1 = self.pos while true # choice _tmp = apply(:_Reference) break if _tmp self.pos = _save1 _tmp = apply(:_SkipBlock) break if _tmp self.pos = _save1 break end # end choice break unless _tmp end _tmp = true set_failed_rule :_References unless _tmp return _tmp end # Ticks1 = "`" !"`" def _Ticks1 _save = self.pos while true # sequence _tmp = match_string("`") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks1 unless _tmp return _tmp end # Ticks2 = "``" !"`" def _Ticks2 _save = self.pos while true # sequence _tmp = match_string("``") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks2 unless _tmp return _tmp end # Ticks3 = "```" !"`" def _Ticks3 _save = self.pos while true # sequence _tmp = match_string("```") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks3 unless _tmp return _tmp end # Ticks4 = "````" !"`" def _Ticks4 _save = self.pos while true # sequence _tmp = match_string("````") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks4 unless _tmp return _tmp end # Ticks5 = "`````" !"`" def _Ticks5 _save = self.pos while true # sequence _tmp = match_string("`````") unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Ticks5 unless _tmp return _tmp end # Code = (Ticks1 @Sp < ((!"`" Nonspacechar)+ | !Ticks1 /`+/ | !(@Sp Ticks1) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks1 | Ticks2 @Sp < ((!"`" Nonspacechar)+ | !Ticks2 /`+/ | !(@Sp Ticks2) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks2 | Ticks3 @Sp < ((!"`" Nonspacechar)+ | !Ticks3 /`+/ | !(@Sp Ticks3) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks3 | Ticks4 @Sp < ((!"`" Nonspacechar)+ | !Ticks4 /`+/ | !(@Sp Ticks4) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks4 | Ticks5 @Sp < ((!"`" Nonspacechar)+ | !Ticks5 /`+/ | !(@Sp Ticks5) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks5) { "#{text}" } def _Code _save = self.pos while true # sequence _save1 = self.pos while true # choice _save2 = self.pos while true # sequence _tmp = apply(:_Ticks1) unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 break end _text_start = self.pos _save3 = self.pos _save4 = self.pos while true # choice _save5 = self.pos _save6 = self.pos while true # sequence _save7 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save6 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save6 end break end # end sequence if _tmp while true _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save8 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save5 end break if _tmp self.pos = _save4 _save10 = self.pos while true # sequence _save11 = self.pos _tmp = apply(:_Ticks1) _tmp = _tmp ? nil : true self.pos = _save11 unless _tmp self.pos = _save10 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save10 end break end # end sequence break if _tmp self.pos = _save4 _save12 = self.pos while true # sequence _save13 = self.pos _save14 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save14 break end _tmp = apply(:_Ticks1) unless _tmp self.pos = _save14 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save13 unless _tmp self.pos = _save12 break end _save15 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save15 _save16 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save16 break end _save17 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save17 unless _tmp self.pos = _save16 end break end # end sequence break if _tmp self.pos = _save15 break end # end choice unless _tmp self.pos = _save12 end break end # end sequence break if _tmp self.pos = _save4 break end # end choice if _tmp while true _save18 = self.pos while true # choice _save19 = self.pos _save20 = self.pos while true # sequence _save21 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save21 unless _tmp self.pos = _save20 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save20 end break end # end sequence if _tmp while true _save22 = self.pos while true # sequence _save23 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save23 unless _tmp self.pos = _save22 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save22 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save19 end break if _tmp self.pos = _save18 _save24 = self.pos while true # sequence _save25 = self.pos _tmp = apply(:_Ticks1) _tmp = _tmp ? nil : true self.pos = _save25 unless _tmp self.pos = _save24 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save24 end break end # end sequence break if _tmp self.pos = _save18 _save26 = self.pos while true # sequence _save27 = self.pos _save28 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save28 break end _tmp = apply(:_Ticks1) unless _tmp self.pos = _save28 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save27 unless _tmp self.pos = _save26 break end _save29 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save29 _save30 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save30 break end _save31 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save31 unless _tmp self.pos = _save30 end break end # end sequence break if _tmp self.pos = _save29 break end # end choice unless _tmp self.pos = _save26 end break end # end sequence break if _tmp self.pos = _save18 break end # end choice break unless _tmp end _tmp = true else self.pos = _save3 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 break end _tmp = apply(:_Ticks1) unless _tmp self.pos = _save2 end break end # end sequence break if _tmp self.pos = _save1 _save32 = self.pos while true # sequence _tmp = apply(:_Ticks2) unless _tmp self.pos = _save32 break end _tmp = _Sp() unless _tmp self.pos = _save32 break end _text_start = self.pos _save33 = self.pos _save34 = self.pos while true # choice _save35 = self.pos _save36 = self.pos while true # sequence _save37 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save37 unless _tmp self.pos = _save36 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save36 end break end # end sequence if _tmp while true _save38 = self.pos while true # sequence _save39 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save39 unless _tmp self.pos = _save38 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save38 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save35 end break if _tmp self.pos = _save34 _save40 = self.pos while true # sequence _save41 = self.pos _tmp = apply(:_Ticks2) _tmp = _tmp ? nil : true self.pos = _save41 unless _tmp self.pos = _save40 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save40 end break end # end sequence break if _tmp self.pos = _save34 _save42 = self.pos while true # sequence _save43 = self.pos _save44 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save44 break end _tmp = apply(:_Ticks2) unless _tmp self.pos = _save44 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save43 unless _tmp self.pos = _save42 break end _save45 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save45 _save46 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save46 break end _save47 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save47 unless _tmp self.pos = _save46 end break end # end sequence break if _tmp self.pos = _save45 break end # end choice unless _tmp self.pos = _save42 end break end # end sequence break if _tmp self.pos = _save34 break end # end choice if _tmp while true _save48 = self.pos while true # choice _save49 = self.pos _save50 = self.pos while true # sequence _save51 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save51 unless _tmp self.pos = _save50 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save50 end break end # end sequence if _tmp while true _save52 = self.pos while true # sequence _save53 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save53 unless _tmp self.pos = _save52 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save52 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save49 end break if _tmp self.pos = _save48 _save54 = self.pos while true # sequence _save55 = self.pos _tmp = apply(:_Ticks2) _tmp = _tmp ? nil : true self.pos = _save55 unless _tmp self.pos = _save54 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save54 end break end # end sequence break if _tmp self.pos = _save48 _save56 = self.pos while true # sequence _save57 = self.pos _save58 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save58 break end _tmp = apply(:_Ticks2) unless _tmp self.pos = _save58 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save57 unless _tmp self.pos = _save56 break end _save59 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save59 _save60 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save60 break end _save61 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save61 unless _tmp self.pos = _save60 end break end # end sequence break if _tmp self.pos = _save59 break end # end choice unless _tmp self.pos = _save56 end break end # end sequence break if _tmp self.pos = _save48 break end # end choice break unless _tmp end _tmp = true else self.pos = _save33 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save32 break end _tmp = _Sp() unless _tmp self.pos = _save32 break end _tmp = apply(:_Ticks2) unless _tmp self.pos = _save32 end break end # end sequence break if _tmp self.pos = _save1 _save62 = self.pos while true # sequence _tmp = apply(:_Ticks3) unless _tmp self.pos = _save62 break end _tmp = _Sp() unless _tmp self.pos = _save62 break end _text_start = self.pos _save63 = self.pos _save64 = self.pos while true # choice _save65 = self.pos _save66 = self.pos while true # sequence _save67 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save67 unless _tmp self.pos = _save66 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save66 end break end # end sequence if _tmp while true _save68 = self.pos while true # sequence _save69 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save69 unless _tmp self.pos = _save68 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save68 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save65 end break if _tmp self.pos = _save64 _save70 = self.pos while true # sequence _save71 = self.pos _tmp = apply(:_Ticks3) _tmp = _tmp ? nil : true self.pos = _save71 unless _tmp self.pos = _save70 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save70 end break end # end sequence break if _tmp self.pos = _save64 _save72 = self.pos while true # sequence _save73 = self.pos _save74 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save74 break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save74 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save73 unless _tmp self.pos = _save72 break end _save75 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save75 _save76 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save76 break end _save77 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save77 unless _tmp self.pos = _save76 end break end # end sequence break if _tmp self.pos = _save75 break end # end choice unless _tmp self.pos = _save72 end break end # end sequence break if _tmp self.pos = _save64 break end # end choice if _tmp while true _save78 = self.pos while true # choice _save79 = self.pos _save80 = self.pos while true # sequence _save81 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save81 unless _tmp self.pos = _save80 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save80 end break end # end sequence if _tmp while true _save82 = self.pos while true # sequence _save83 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save83 unless _tmp self.pos = _save82 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save82 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save79 end break if _tmp self.pos = _save78 _save84 = self.pos while true # sequence _save85 = self.pos _tmp = apply(:_Ticks3) _tmp = _tmp ? nil : true self.pos = _save85 unless _tmp self.pos = _save84 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save84 end break end # end sequence break if _tmp self.pos = _save78 _save86 = self.pos while true # sequence _save87 = self.pos _save88 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save88 break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save88 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save87 unless _tmp self.pos = _save86 break end _save89 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save89 _save90 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save90 break end _save91 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save91 unless _tmp self.pos = _save90 end break end # end sequence break if _tmp self.pos = _save89 break end # end choice unless _tmp self.pos = _save86 end break end # end sequence break if _tmp self.pos = _save78 break end # end choice break unless _tmp end _tmp = true else self.pos = _save63 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save62 break end _tmp = _Sp() unless _tmp self.pos = _save62 break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save62 end break end # end sequence break if _tmp self.pos = _save1 _save92 = self.pos while true # sequence _tmp = apply(:_Ticks4) unless _tmp self.pos = _save92 break end _tmp = _Sp() unless _tmp self.pos = _save92 break end _text_start = self.pos _save93 = self.pos _save94 = self.pos while true # choice _save95 = self.pos _save96 = self.pos while true # sequence _save97 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save97 unless _tmp self.pos = _save96 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save96 end break end # end sequence if _tmp while true _save98 = self.pos while true # sequence _save99 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save99 unless _tmp self.pos = _save98 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save98 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save95 end break if _tmp self.pos = _save94 _save100 = self.pos while true # sequence _save101 = self.pos _tmp = apply(:_Ticks4) _tmp = _tmp ? nil : true self.pos = _save101 unless _tmp self.pos = _save100 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save100 end break end # end sequence break if _tmp self.pos = _save94 _save102 = self.pos while true # sequence _save103 = self.pos _save104 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save104 break end _tmp = apply(:_Ticks4) unless _tmp self.pos = _save104 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save103 unless _tmp self.pos = _save102 break end _save105 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save105 _save106 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save106 break end _save107 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save107 unless _tmp self.pos = _save106 end break end # end sequence break if _tmp self.pos = _save105 break end # end choice unless _tmp self.pos = _save102 end break end # end sequence break if _tmp self.pos = _save94 break end # end choice if _tmp while true _save108 = self.pos while true # choice _save109 = self.pos _save110 = self.pos while true # sequence _save111 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save111 unless _tmp self.pos = _save110 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save110 end break end # end sequence if _tmp while true _save112 = self.pos while true # sequence _save113 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save113 unless _tmp self.pos = _save112 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save112 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save109 end break if _tmp self.pos = _save108 _save114 = self.pos while true # sequence _save115 = self.pos _tmp = apply(:_Ticks4) _tmp = _tmp ? nil : true self.pos = _save115 unless _tmp self.pos = _save114 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save114 end break end # end sequence break if _tmp self.pos = _save108 _save116 = self.pos while true # sequence _save117 = self.pos _save118 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save118 break end _tmp = apply(:_Ticks4) unless _tmp self.pos = _save118 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save117 unless _tmp self.pos = _save116 break end _save119 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save119 _save120 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save120 break end _save121 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save121 unless _tmp self.pos = _save120 end break end # end sequence break if _tmp self.pos = _save119 break end # end choice unless _tmp self.pos = _save116 end break end # end sequence break if _tmp self.pos = _save108 break end # end choice break unless _tmp end _tmp = true else self.pos = _save93 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save92 break end _tmp = _Sp() unless _tmp self.pos = _save92 break end _tmp = apply(:_Ticks4) unless _tmp self.pos = _save92 end break end # end sequence break if _tmp self.pos = _save1 _save122 = self.pos while true # sequence _tmp = apply(:_Ticks5) unless _tmp self.pos = _save122 break end _tmp = _Sp() unless _tmp self.pos = _save122 break end _text_start = self.pos _save123 = self.pos _save124 = self.pos while true # choice _save125 = self.pos _save126 = self.pos while true # sequence _save127 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save127 unless _tmp self.pos = _save126 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save126 end break end # end sequence if _tmp while true _save128 = self.pos while true # sequence _save129 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save129 unless _tmp self.pos = _save128 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save128 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save125 end break if _tmp self.pos = _save124 _save130 = self.pos while true # sequence _save131 = self.pos _tmp = apply(:_Ticks5) _tmp = _tmp ? nil : true self.pos = _save131 unless _tmp self.pos = _save130 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save130 end break end # end sequence break if _tmp self.pos = _save124 _save132 = self.pos while true # sequence _save133 = self.pos _save134 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save134 break end _tmp = apply(:_Ticks5) unless _tmp self.pos = _save134 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save133 unless _tmp self.pos = _save132 break end _save135 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save135 _save136 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save136 break end _save137 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save137 unless _tmp self.pos = _save136 end break end # end sequence break if _tmp self.pos = _save135 break end # end choice unless _tmp self.pos = _save132 end break end # end sequence break if _tmp self.pos = _save124 break end # end choice if _tmp while true _save138 = self.pos while true # choice _save139 = self.pos _save140 = self.pos while true # sequence _save141 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save141 unless _tmp self.pos = _save140 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save140 end break end # end sequence if _tmp while true _save142 = self.pos while true # sequence _save143 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save143 unless _tmp self.pos = _save142 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save142 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save139 end break if _tmp self.pos = _save138 _save144 = self.pos while true # sequence _save145 = self.pos _tmp = apply(:_Ticks5) _tmp = _tmp ? nil : true self.pos = _save145 unless _tmp self.pos = _save144 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save144 end break end # end sequence break if _tmp self.pos = _save138 _save146 = self.pos while true # sequence _save147 = self.pos _save148 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save148 break end _tmp = apply(:_Ticks5) unless _tmp self.pos = _save148 end break end # end sequence _tmp = _tmp ? nil : true self.pos = _save147 unless _tmp self.pos = _save146 break end _save149 = self.pos while true # choice _tmp = _Spacechar() break if _tmp self.pos = _save149 _save150 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save150 break end _save151 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save151 unless _tmp self.pos = _save150 end break end # end sequence break if _tmp self.pos = _save149 break end # end choice unless _tmp self.pos = _save146 end break end # end sequence break if _tmp self.pos = _save138 break end # end choice break unless _tmp end _tmp = true else self.pos = _save123 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save122 break end _tmp = _Sp() unless _tmp self.pos = _save122 break end _tmp = apply(:_Ticks5) unless _tmp self.pos = _save122 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end @result = begin; "#{text}" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Code unless _tmp return _tmp end # RawHtml = < (HtmlComment | HtmlBlockScript | HtmlTag) > { if html? then text else '' end } def _RawHtml _save = self.pos while true # sequence _text_start = self.pos _save1 = self.pos while true # choice _tmp = apply(:_HtmlComment) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlBlockScript) break if _tmp self.pos = _save1 _tmp = apply(:_HtmlTag) break if _tmp self.pos = _save1 break end # end choice if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; if html? then text else '' end ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RawHtml unless _tmp return _tmp end # BlankLine = @Sp @Newline { "\n" } def _BlankLine _save = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end @result = begin; "\n" ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_BlankLine unless _tmp return _tmp end # Quoted = ("\"" (!"\"" .)* "\"" | "'" (!"'" .)* "'") def _Quoted _save = self.pos while true # choice _save1 = self.pos while true # sequence _tmp = match_string("\"") unless _tmp self.pos = _save1 break end while true _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("\"") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = get_byte unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save1 break end _tmp = match_string("\"") unless _tmp self.pos = _save1 end break end # end sequence break if _tmp self.pos = _save _save5 = self.pos while true # sequence _tmp = match_string("'") unless _tmp self.pos = _save5 break end while true _save7 = self.pos while true # sequence _save8 = self.pos _tmp = match_string("'") _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save7 break end _tmp = get_byte unless _tmp self.pos = _save7 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save5 break end _tmp = match_string("'") unless _tmp self.pos = _save5 end break end # end sequence break if _tmp self.pos = _save break end # end choice set_failed_rule :_Quoted unless _tmp return _tmp end # HtmlAttribute = (AlphanumericAscii | "-")+ Spnl ("=" Spnl (Quoted | (!">" Nonspacechar)+))? Spnl def _HtmlAttribute _save = self.pos while true # sequence _save1 = self.pos _save2 = self.pos while true # choice _tmp = apply(:_AlphanumericAscii) break if _tmp self.pos = _save2 _tmp = match_string("-") break if _tmp self.pos = _save2 break end # end choice if _tmp while true _save3 = self.pos while true # choice _tmp = apply(:_AlphanumericAscii) break if _tmp self.pos = _save3 _tmp = match_string("-") break if _tmp self.pos = _save3 break end # end choice break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save4 = self.pos _save5 = self.pos while true # sequence _tmp = match_string("=") unless _tmp self.pos = _save5 break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save5 break end _save6 = self.pos while true # choice _tmp = apply(:_Quoted) break if _tmp self.pos = _save6 _save7 = self.pos _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save8 end break end # end sequence if _tmp while true _save10 = self.pos while true # sequence _save11 = self.pos _tmp = match_string(">") _tmp = _tmp ? nil : true self.pos = _save11 unless _tmp self.pos = _save10 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save10 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save7 end break if _tmp self.pos = _save6 break end # end choice unless _tmp self.pos = _save5 end break end # end sequence unless _tmp _tmp = true self.pos = _save4 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlAttribute unless _tmp return _tmp end # HtmlComment = "" .)* "-->" def _HtmlComment _save = self.pos while true # sequence _tmp = match_string("") _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _tmp = match_string("-->") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlComment unless _tmp return _tmp end # HtmlTag = "<" Spnl "/"? AlphanumericAscii+ Spnl HtmlAttribute* "/"? Spnl ">" def _HtmlTag _save = self.pos while true # sequence _tmp = match_string("<") unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _save1 = self.pos _tmp = match_string("/") unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save break end _save2 = self.pos _tmp = apply(:_AlphanumericAscii) if _tmp while true _tmp = apply(:_AlphanumericAscii) break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end while true _tmp = apply(:_HtmlAttribute) break unless _tmp end _tmp = true unless _tmp self.pos = _save break end _save4 = self.pos _tmp = match_string("/") unless _tmp _tmp = true self.pos = _save4 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _tmp = match_string(">") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HtmlTag unless _tmp return _tmp end # Eof = !. def _Eof _save = self.pos _tmp = get_byte _tmp = _tmp ? nil : true self.pos = _save set_failed_rule :_Eof unless _tmp return _tmp end # Nonspacechar = !@Spacechar !@Newline . def _Nonspacechar _save = self.pos while true # sequence _save1 = self.pos _tmp = _Spacechar() _tmp = _tmp ? nil : true self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save2 unless _tmp self.pos = _save break end _tmp = get_byte unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Nonspacechar unless _tmp return _tmp end # Sp = @Spacechar* def _Sp while true _tmp = _Spacechar() break unless _tmp end _tmp = true set_failed_rule :_Sp unless _tmp return _tmp end # Spnl = @Sp (@Newline @Sp)? def _Spnl _save = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos while true # sequence _tmp = _Newline() unless _tmp self.pos = _save2 break end _tmp = _Sp() unless _tmp self.pos = _save2 end break end # end sequence unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Spnl unless _tmp return _tmp end # SpecialChar = (/[~*_`&\[\]()= 48 and _tmp <= 57 self.pos = _save _tmp = nil end end set_failed_rule :_Digit unless _tmp return _tmp end # Alphanumeric = %literals.Alphanumeric def _Alphanumeric _tmp = @_grammar_literals.external_invoke(self, :_Alphanumeric) set_failed_rule :_Alphanumeric unless _tmp return _tmp end # AlphanumericAscii = %literals.AlphanumericAscii def _AlphanumericAscii _tmp = @_grammar_literals.external_invoke(self, :_AlphanumericAscii) set_failed_rule :_AlphanumericAscii unless _tmp return _tmp end # BOM = %literals.BOM def _BOM _tmp = @_grammar_literals.external_invoke(self, :_BOM) set_failed_rule :_BOM unless _tmp return _tmp end # Newline = %literals.Newline def _Newline _tmp = @_grammar_literals.external_invoke(self, :_Newline) set_failed_rule :_Newline unless _tmp return _tmp end # Spacechar = %literals.Spacechar def _Spacechar _tmp = @_grammar_literals.external_invoke(self, :_Spacechar) set_failed_rule :_Spacechar unless _tmp return _tmp end # HexEntity = /&#x/i < /[0-9a-fA-F]+/ > ";" { [text.to_i(16)].pack 'U' } def _HexEntity _save = self.pos while true # sequence _tmp = scan(/\A(?i-mx:&#x)/) unless _tmp self.pos = _save break end _text_start = self.pos _tmp = scan(/\A(?-mix:[0-9a-fA-F]+)/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(";") unless _tmp self.pos = _save break end @result = begin; [text.to_i(16)].pack 'U' ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_HexEntity unless _tmp return _tmp end # DecEntity = "&#" < /[0-9]+/ > ";" { [text.to_i].pack 'U' } def _DecEntity _save = self.pos while true # sequence _tmp = match_string("&#") unless _tmp self.pos = _save break end _text_start = self.pos _tmp = scan(/\A(?-mix:[0-9]+)/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(";") unless _tmp self.pos = _save break end @result = begin; [text.to_i].pack 'U' ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DecEntity unless _tmp return _tmp end # CharEntity = "&" < /[A-Za-z0-9]+/ > ";" { if entity = HTML_ENTITIES[text] then entity.pack 'U*' else "&#{text};" end } def _CharEntity _save = self.pos while true # sequence _tmp = match_string("&") unless _tmp self.pos = _save break end _text_start = self.pos _tmp = scan(/\A(?-mix:[A-Za-z0-9]+)/) if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string(";") unless _tmp self.pos = _save break end @result = begin; if entity = HTML_ENTITIES[text] then entity.pack 'U*' else "&#{text};" end ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_CharEntity unless _tmp return _tmp end # NonindentSpace = / {0,3}/ def _NonindentSpace _tmp = scan(/\A(?-mix: {0,3})/) set_failed_rule :_NonindentSpace unless _tmp return _tmp end # Indent = /\t| / def _Indent _tmp = scan(/\A(?-mix:\t| )/) set_failed_rule :_Indent unless _tmp return _tmp end # IndentedLine = Indent Line def _IndentedLine _save = self.pos while true # sequence _tmp = apply(:_Indent) unless _tmp self.pos = _save break end _tmp = apply(:_Line) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_IndentedLine unless _tmp return _tmp end # OptionallyIndentedLine = Indent? Line def _OptionallyIndentedLine _save = self.pos while true # sequence _save1 = self.pos _tmp = apply(:_Indent) unless _tmp _tmp = true self.pos = _save1 end unless _tmp self.pos = _save break end _tmp = apply(:_Line) unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_OptionallyIndentedLine unless _tmp return _tmp end # StartList = &. { [] } def _StartList _save = self.pos while true # sequence _save1 = self.pos _tmp = get_byte self.pos = _save1 unless _tmp self.pos = _save break end @result = begin; [] ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_StartList unless _tmp return _tmp end # Line = @RawLine:a { a } def _Line _save = self.pos while true # sequence _tmp = _RawLine() a = @result unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Line unless _tmp return _tmp end # RawLine = (< (!"\r" !"\n" .)* @Newline > | < .+ > @Eof) { text } def _RawLine _save = self.pos while true # sequence _save1 = self.pos while true # choice _text_start = self.pos _save2 = self.pos while true # sequence while true _save4 = self.pos while true # sequence _save5 = self.pos _tmp = match_string("\r") _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _save6 = self.pos _tmp = match_string("\n") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save4 break end _tmp = get_byte unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save2 break end _tmp = _Newline() unless _tmp self.pos = _save2 end break end # end sequence if _tmp text = get_text(_text_start) end break if _tmp self.pos = _save1 _save7 = self.pos while true # sequence _text_start = self.pos _save8 = self.pos _tmp = get_byte if _tmp while true _tmp = get_byte break unless _tmp end _tmp = true else self.pos = _save8 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save7 break end _tmp = _Eof() unless _tmp self.pos = _save7 end break end # end sequence break if _tmp self.pos = _save1 break end # end choice unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RawLine unless _tmp return _tmp end # SkipBlock = (HtmlBlock | (!"#" !SetextBottom1 !SetextBottom2 !@BlankLine @RawLine)+ @BlankLine* | @BlankLine+ | @RawLine) def _SkipBlock _save = self.pos while true # choice _tmp = apply(:_HtmlBlock) break if _tmp self.pos = _save _save1 = self.pos while true # sequence _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("#") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _save5 = self.pos _tmp = apply(:_SetextBottom1) _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save3 break end _save6 = self.pos _tmp = apply(:_SetextBottom2) _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save3 break end _save7 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save3 break end _tmp = _RawLine() unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save8 = self.pos while true # sequence _save9 = self.pos _tmp = match_string("#") _tmp = _tmp ? nil : true self.pos = _save9 unless _tmp self.pos = _save8 break end _save10 = self.pos _tmp = apply(:_SetextBottom1) _tmp = _tmp ? nil : true self.pos = _save10 unless _tmp self.pos = _save8 break end _save11 = self.pos _tmp = apply(:_SetextBottom2) _tmp = _tmp ? nil : true self.pos = _save11 unless _tmp self.pos = _save8 break end _save12 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save12 unless _tmp self.pos = _save8 break end _tmp = _RawLine() unless _tmp self.pos = _save8 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save1 break end while true _tmp = _BlankLine() break unless _tmp end _tmp = true unless _tmp self.pos = _save1 end break end # end sequence break if _tmp self.pos = _save _save14 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save14 end break if _tmp self.pos = _save _tmp = _RawLine() break if _tmp self.pos = _save break end # end choice set_failed_rule :_SkipBlock unless _tmp return _tmp end # ExtendedSpecialChar = &{ notes? } "^" def _ExtendedSpecialChar _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; notes? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = match_string("^") unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_ExtendedSpecialChar unless _tmp return _tmp end # NoteReference = &{ notes? } RawNoteReference:ref { note_for ref } def _NoteReference _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; notes? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_RawNoteReference) ref = @result unless _tmp self.pos = _save break end @result = begin; note_for ref ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_NoteReference unless _tmp return _tmp end # RawNoteReference = "[^" < (!@Newline !"]" .)+ > "]" { text } def _RawNoteReference _save = self.pos while true # sequence _tmp = match_string("[^") unless _tmp self.pos = _save break end _text_start = self.pos _save1 = self.pos _save2 = self.pos while true # sequence _save3 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _save4 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save2 break end _tmp = get_byte unless _tmp self.pos = _save2 end break end # end sequence if _tmp while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = _Newline() _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _save7 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save7 unless _tmp self.pos = _save5 break end _tmp = get_byte unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save1 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = match_string("]") unless _tmp self.pos = _save break end @result = begin; text ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RawNoteReference unless _tmp return _tmp end # Note = &{ notes? } @NonindentSpace RawNoteReference:ref ":" @Sp @StartList:a RawNoteBlock:i { a.concat i } (&Indent RawNoteBlock:i { a.concat i })* { @footnotes[ref] = paragraph a nil } def _Note _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; notes? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _tmp = apply(:_RawNoteReference) ref = @result unless _tmp self.pos = _save break end _tmp = match_string(":") unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _tmp = apply(:_RawNoteBlock) i = @result unless _tmp self.pos = _save break end @result = begin; a.concat i ; end _tmp = true unless _tmp self.pos = _save break end while true _save3 = self.pos while true # sequence _save4 = self.pos _tmp = apply(:_Indent) self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_RawNoteBlock) i = @result unless _tmp self.pos = _save3 break end @result = begin; a.concat i ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; @footnotes[ref] = paragraph a nil ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_Note unless _tmp return _tmp end # InlineNote = &{ notes? } "^[" @StartList:a (!"]" Inline:l { a << l })+ "]" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref } def _InlineNote _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; notes? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = match_string("^[") unless _tmp self.pos = _save break end _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _save4 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save4 unless _tmp self.pos = _save3 break end _tmp = apply(:_Inline) l = @result unless _tmp self.pos = _save3 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save3 end break end # end sequence if _tmp while true _save5 = self.pos while true # sequence _save6 = self.pos _tmp = match_string("]") _tmp = _tmp ? nil : true self.pos = _save6 unless _tmp self.pos = _save5 break end _tmp = apply(:_Inline) l = @result unless _tmp self.pos = _save5 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save5 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = match_string("]") unless _tmp self.pos = _save break end @result = begin; ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_InlineNote unless _tmp return _tmp end # Notes = (Note | SkipBlock)* def _Notes while true _save1 = self.pos while true # choice _tmp = apply(:_Note) break if _tmp self.pos = _save1 _tmp = apply(:_SkipBlock) break if _tmp self.pos = _save1 break end # end choice break unless _tmp end _tmp = true set_failed_rule :_Notes unless _tmp return _tmp end # RawNoteBlock = @StartList:a (!@BlankLine OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a } def _RawNoteBlock _save = self.pos while true # sequence _tmp = _StartList() a = @result unless _tmp self.pos = _save break end _save1 = self.pos _save2 = self.pos while true # sequence _save3 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save3 unless _tmp self.pos = _save2 break end _tmp = apply(:_OptionallyIndentedLine) l = @result unless _tmp self.pos = _save2 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save2 end break end # end sequence if _tmp while true _save4 = self.pos while true # sequence _save5 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true self.pos = _save5 unless _tmp self.pos = _save4 break end _tmp = apply(:_OptionallyIndentedLine) l = @result unless _tmp self.pos = _save4 break end @result = begin; a << l ; end _tmp = true unless _tmp self.pos = _save4 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end _text_start = self.pos while true _tmp = _BlankLine() break unless _tmp end _tmp = true if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end @result = begin; a << text ; end _tmp = true unless _tmp self.pos = _save break end @result = begin; a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_RawNoteBlock unless _tmp return _tmp end # CodeFence = &{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!"`" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim } def _CodeFence _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; github? ; end self.pos = _save1 unless _tmp self.pos = _save break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save break end _save2 = self.pos _save3 = self.pos while true # sequence _tmp = _Sp() unless _tmp self.pos = _save3 break end _tmp = apply(:_StrChunk) format = @result unless _tmp self.pos = _save3 end break end # end sequence unless _tmp _tmp = true self.pos = _save2 end unless _tmp self.pos = _save break end _tmp = apply(:_Spnl) unless _tmp self.pos = _save break end _text_start = self.pos _save4 = self.pos _save5 = self.pos while true # choice _save6 = self.pos _save7 = self.pos while true # sequence _save8 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save8 unless _tmp self.pos = _save7 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save7 end break end # end sequence if _tmp while true _save9 = self.pos while true # sequence _save10 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save10 unless _tmp self.pos = _save9 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save9 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save6 end break if _tmp self.pos = _save5 _save11 = self.pos while true # sequence _save12 = self.pos _tmp = apply(:_Ticks3) _tmp = _tmp ? nil : true self.pos = _save12 unless _tmp self.pos = _save11 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save11 end break end # end sequence break if _tmp self.pos = _save5 _tmp = apply(:_Spacechar) break if _tmp self.pos = _save5 _tmp = _Newline() break if _tmp self.pos = _save5 break end # end choice if _tmp while true _save13 = self.pos while true # choice _save14 = self.pos _save15 = self.pos while true # sequence _save16 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save16 unless _tmp self.pos = _save15 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save15 end break end # end sequence if _tmp while true _save17 = self.pos while true # sequence _save18 = self.pos _tmp = match_string("`") _tmp = _tmp ? nil : true self.pos = _save18 unless _tmp self.pos = _save17 break end _tmp = apply(:_Nonspacechar) unless _tmp self.pos = _save17 end break end # end sequence break unless _tmp end _tmp = true else self.pos = _save14 end break if _tmp self.pos = _save13 _save19 = self.pos while true # sequence _save20 = self.pos _tmp = apply(:_Ticks3) _tmp = _tmp ? nil : true self.pos = _save20 unless _tmp self.pos = _save19 break end _tmp = scan(/\A(?-mix:`+)/) unless _tmp self.pos = _save19 end break end # end sequence break if _tmp self.pos = _save13 _tmp = apply(:_Spacechar) break if _tmp self.pos = _save13 _tmp = _Newline() break if _tmp self.pos = _save13 break end # end choice break unless _tmp end _tmp = true else self.pos = _save4 end if _tmp text = get_text(_text_start) end unless _tmp self.pos = _save break end _tmp = apply(:_Ticks3) unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end while true _tmp = _Newline() break unless _tmp end _tmp = true unless _tmp self.pos = _save break end @result = begin; verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_CodeFence unless _tmp return _tmp end # DefinitionList = &{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten } def _DefinitionList _save = self.pos while true # sequence _save1 = self.pos _tmp = begin; definition_lists? ; end self.pos = _save1 unless _tmp self.pos = _save break end _save2 = self.pos _ary = [] _tmp = apply(:_DefinitionListItem) if _tmp _ary << @result while true _tmp = apply(:_DefinitionListItem) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save2 end list = @result unless _tmp self.pos = _save break end @result = begin; RDoc::Markup::List.new :NOTE, *list.flatten ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DefinitionList unless _tmp return _tmp end # DefinitionListItem = DefinitionListLabel+:label DefinitionListDefinition+:defns { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items } def _DefinitionListItem _save = self.pos while true # sequence _save1 = self.pos _ary = [] _tmp = apply(:_DefinitionListLabel) if _tmp _ary << @result while true _tmp = apply(:_DefinitionListLabel) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save1 end label = @result unless _tmp self.pos = _save break end _save2 = self.pos _ary = [] _tmp = apply(:_DefinitionListDefinition) if _tmp _ary << @result while true _tmp = apply(:_DefinitionListDefinition) _ary << @result if _tmp break unless _tmp end _tmp = true @result = _ary else self.pos = _save2 end defns = @result unless _tmp self.pos = _save break end @result = begin; list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DefinitionListItem unless _tmp return _tmp end # DefinitionListLabel = StrChunk:label @Sp @Newline { label } def _DefinitionListLabel _save = self.pos while true # sequence _tmp = apply(:_StrChunk) label = @result unless _tmp self.pos = _save break end _tmp = _Sp() unless _tmp self.pos = _save break end _tmp = _Newline() unless _tmp self.pos = _save break end @result = begin; label ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DefinitionListLabel unless _tmp return _tmp end # DefinitionListDefinition = @NonindentSpace ":" @Space Inlines:a @BlankLine+ { paragraph a } def _DefinitionListDefinition _save = self.pos while true # sequence _tmp = _NonindentSpace() unless _tmp self.pos = _save break end _tmp = match_string(":") unless _tmp self.pos = _save break end _tmp = _Space() unless _tmp self.pos = _save break end _tmp = apply(:_Inlines) a = @result unless _tmp self.pos = _save break end _save1 = self.pos _tmp = _BlankLine() if _tmp while true _tmp = _BlankLine() break unless _tmp end _tmp = true else self.pos = _save1 end unless _tmp self.pos = _save break end @result = begin; paragraph a ; end _tmp = true unless _tmp self.pos = _save end break end # end sequence set_failed_rule :_DefinitionListDefinition unless _tmp return _tmp end Rules = {} Rules[:_root] = rule_info("root", "Doc") Rules[:_Doc] = rule_info("Doc", "BOM? Block*:a { RDoc::Markup::Document.new(*a.compact) }") Rules[:_Block] = rule_info("Block", "@BlankLine* (BlockQuote | Verbatim | CodeFence | Note | Reference | HorizontalRule | Heading | OrderedList | BulletList | DefinitionList | HtmlBlock | StyleBlock | Para | Plain)") Rules[:_Para] = rule_info("Para", "@NonindentSpace Inlines:a @BlankLine+ { paragraph a }") Rules[:_Plain] = rule_info("Plain", "Inlines:a { paragraph a }") Rules[:_AtxInline] = rule_info("AtxInline", "!@Newline !(@Sp /\#*/ @Sp @Newline) Inline") Rules[:_AtxStart] = rule_info("AtxStart", "< /\\\#{1,6}/ > { text.length }") Rules[:_AtxHeading] = rule_info("AtxHeading", "AtxStart:s @Sp AtxInline+:a (@Sp /\#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) }") Rules[:_SetextHeading] = rule_info("SetextHeading", "(SetextHeading1 | SetextHeading2)") Rules[:_SetextBottom1] = rule_info("SetextBottom1", "/={1,}/ @Newline") Rules[:_SetextBottom2] = rule_info("SetextBottom2", "/-{1,}/ @Newline") Rules[:_SetextHeading1] = rule_info("SetextHeading1", "&(@RawLine SetextBottom1) @StartList:a (!@Endline Inline:b { a << b })+ @Sp @Newline SetextBottom1 { RDoc::Markup::Heading.new(1, a.join) }") Rules[:_SetextHeading2] = rule_info("SetextHeading2", "&(@RawLine SetextBottom2) @StartList:a (!@Endline Inline:b { a << b })+ @Sp @Newline SetextBottom2 { RDoc::Markup::Heading.new(2, a.join) }") Rules[:_Heading] = rule_info("Heading", "(SetextHeading | AtxHeading)") Rules[:_BlockQuote] = rule_info("BlockQuote", "BlockQuoteRaw:a { RDoc::Markup::BlockQuote.new(*a) }") Rules[:_BlockQuoteRaw] = rule_info("BlockQuoteRaw", "@StartList:a (\">\" \" \"? Line:l { a << l } (!\">\" !@BlankLine Line:c { a << c })* (@BlankLine:n { a << n })*)+ { inner_parse a.join }") Rules[:_NonblankIndentedLine] = rule_info("NonblankIndentedLine", "!@BlankLine IndentedLine") Rules[:_VerbatimChunk] = rule_info("VerbatimChunk", "@BlankLine*:a NonblankIndentedLine+:b { a.concat b }") Rules[:_Verbatim] = rule_info("Verbatim", "VerbatimChunk+:a { RDoc::Markup::Verbatim.new(*a.flatten) }") Rules[:_HorizontalRule] = rule_info("HorizontalRule", "@NonindentSpace (\"*\" @Sp \"*\" @Sp \"*\" (@Sp \"*\")* | \"-\" @Sp \"-\" @Sp \"-\" (@Sp \"-\")* | \"_\" @Sp \"_\" @Sp \"_\" (@Sp \"_\")*) @Sp @Newline @BlankLine+ { RDoc::Markup::Rule.new 1 }") Rules[:_Bullet] = rule_info("Bullet", "!HorizontalRule @NonindentSpace /[+*-]/ @Spacechar+") Rules[:_BulletList] = rule_info("BulletList", "&Bullet (ListTight | ListLoose):a { RDoc::Markup::List.new(:BULLET, *a) }") Rules[:_ListTight] = rule_info("ListTight", "ListItemTight+:a @BlankLine* !(Bullet | Enumerator) { a }") Rules[:_ListLoose] = rule_info("ListLoose", "@StartList:a (ListItem:b @BlankLine* { a << b })+ { a }") Rules[:_ListItem] = rule_info("ListItem", "(Bullet | Enumerator) @StartList:a ListBlock:b { a << b } (ListContinuationBlock:c { a.push(*c) })* { list_item_from a }") Rules[:_ListItemTight] = rule_info("ListItemTight", "(Bullet | Enumerator) ListBlock:a (!@BlankLine ListContinuationBlock:b { a.push(*b) })* !ListContinuationBlock { list_item_from a }") Rules[:_ListBlock] = rule_info("ListBlock", "!@BlankLine Line:a ListBlockLine*:c { [a, *c] }") Rules[:_ListContinuationBlock] = rule_info("ListContinuationBlock", "@StartList:a @BlankLine* { a << \"\\n\" } (Indent ListBlock:b { a.concat b })+ { a }") Rules[:_Enumerator] = rule_info("Enumerator", "@NonindentSpace [0-9]+ \".\" @Spacechar+") Rules[:_OrderedList] = rule_info("OrderedList", "&Enumerator (ListTight | ListLoose):a { RDoc::Markup::List.new(:NUMBER, *a) }") Rules[:_ListBlockLine] = rule_info("ListBlockLine", "!@BlankLine !(Indent? (Bullet | Enumerator)) !HorizontalRule OptionallyIndentedLine") Rules[:_HtmlOpenAnchor] = rule_info("HtmlOpenAnchor", "\"<\" Spnl (\"a\" | \"A\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlCloseAnchor] = rule_info("HtmlCloseAnchor", "\"<\" Spnl \"/\" (\"a\" | \"A\") Spnl \">\"") Rules[:_HtmlAnchor] = rule_info("HtmlAnchor", "HtmlOpenAnchor (HtmlAnchor | !HtmlCloseAnchor .)* HtmlCloseAnchor") Rules[:_HtmlBlockOpenAddress] = rule_info("HtmlBlockOpenAddress", "\"<\" Spnl (\"address\" | \"ADDRESS\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseAddress] = rule_info("HtmlBlockCloseAddress", "\"<\" Spnl \"/\" (\"address\" | \"ADDRESS\") Spnl \">\"") Rules[:_HtmlBlockAddress] = rule_info("HtmlBlockAddress", "HtmlBlockOpenAddress (HtmlBlockAddress | !HtmlBlockCloseAddress .)* HtmlBlockCloseAddress") Rules[:_HtmlBlockOpenBlockquote] = rule_info("HtmlBlockOpenBlockquote", "\"<\" Spnl (\"blockquote\" | \"BLOCKQUOTE\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseBlockquote] = rule_info("HtmlBlockCloseBlockquote", "\"<\" Spnl \"/\" (\"blockquote\" | \"BLOCKQUOTE\") Spnl \">\"") Rules[:_HtmlBlockBlockquote] = rule_info("HtmlBlockBlockquote", "HtmlBlockOpenBlockquote (HtmlBlockBlockquote | !HtmlBlockCloseBlockquote .)* HtmlBlockCloseBlockquote") Rules[:_HtmlBlockOpenCenter] = rule_info("HtmlBlockOpenCenter", "\"<\" Spnl (\"center\" | \"CENTER\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseCenter] = rule_info("HtmlBlockCloseCenter", "\"<\" Spnl \"/\" (\"center\" | \"CENTER\") Spnl \">\"") Rules[:_HtmlBlockCenter] = rule_info("HtmlBlockCenter", "HtmlBlockOpenCenter (HtmlBlockCenter | !HtmlBlockCloseCenter .)* HtmlBlockCloseCenter") Rules[:_HtmlBlockOpenDir] = rule_info("HtmlBlockOpenDir", "\"<\" Spnl (\"dir\" | \"DIR\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDir] = rule_info("HtmlBlockCloseDir", "\"<\" Spnl \"/\" (\"dir\" | \"DIR\") Spnl \">\"") Rules[:_HtmlBlockDir] = rule_info("HtmlBlockDir", "HtmlBlockOpenDir (HtmlBlockDir | !HtmlBlockCloseDir .)* HtmlBlockCloseDir") Rules[:_HtmlBlockOpenDiv] = rule_info("HtmlBlockOpenDiv", "\"<\" Spnl (\"div\" | \"DIV\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDiv] = rule_info("HtmlBlockCloseDiv", "\"<\" Spnl \"/\" (\"div\" | \"DIV\") Spnl \">\"") Rules[:_HtmlBlockDiv] = rule_info("HtmlBlockDiv", "HtmlBlockOpenDiv (HtmlBlockDiv | !HtmlBlockCloseDiv .)* HtmlBlockCloseDiv") Rules[:_HtmlBlockOpenDl] = rule_info("HtmlBlockOpenDl", "\"<\" Spnl (\"dl\" | \"DL\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDl] = rule_info("HtmlBlockCloseDl", "\"<\" Spnl \"/\" (\"dl\" | \"DL\") Spnl \">\"") Rules[:_HtmlBlockDl] = rule_info("HtmlBlockDl", "HtmlBlockOpenDl (HtmlBlockDl | !HtmlBlockCloseDl .)* HtmlBlockCloseDl") Rules[:_HtmlBlockOpenFieldset] = rule_info("HtmlBlockOpenFieldset", "\"<\" Spnl (\"fieldset\" | \"FIELDSET\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseFieldset] = rule_info("HtmlBlockCloseFieldset", "\"<\" Spnl \"/\" (\"fieldset\" | \"FIELDSET\") Spnl \">\"") Rules[:_HtmlBlockFieldset] = rule_info("HtmlBlockFieldset", "HtmlBlockOpenFieldset (HtmlBlockFieldset | !HtmlBlockCloseFieldset .)* HtmlBlockCloseFieldset") Rules[:_HtmlBlockOpenForm] = rule_info("HtmlBlockOpenForm", "\"<\" Spnl (\"form\" | \"FORM\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseForm] = rule_info("HtmlBlockCloseForm", "\"<\" Spnl \"/\" (\"form\" | \"FORM\") Spnl \">\"") Rules[:_HtmlBlockForm] = rule_info("HtmlBlockForm", "HtmlBlockOpenForm (HtmlBlockForm | !HtmlBlockCloseForm .)* HtmlBlockCloseForm") Rules[:_HtmlBlockOpenH1] = rule_info("HtmlBlockOpenH1", "\"<\" Spnl (\"h1\" | \"H1\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH1] = rule_info("HtmlBlockCloseH1", "\"<\" Spnl \"/\" (\"h1\" | \"H1\") Spnl \">\"") Rules[:_HtmlBlockH1] = rule_info("HtmlBlockH1", "HtmlBlockOpenH1 (HtmlBlockH1 | !HtmlBlockCloseH1 .)* HtmlBlockCloseH1") Rules[:_HtmlBlockOpenH2] = rule_info("HtmlBlockOpenH2", "\"<\" Spnl (\"h2\" | \"H2\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH2] = rule_info("HtmlBlockCloseH2", "\"<\" Spnl \"/\" (\"h2\" | \"H2\") Spnl \">\"") Rules[:_HtmlBlockH2] = rule_info("HtmlBlockH2", "HtmlBlockOpenH2 (HtmlBlockH2 | !HtmlBlockCloseH2 .)* HtmlBlockCloseH2") Rules[:_HtmlBlockOpenH3] = rule_info("HtmlBlockOpenH3", "\"<\" Spnl (\"h3\" | \"H3\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH3] = rule_info("HtmlBlockCloseH3", "\"<\" Spnl \"/\" (\"h3\" | \"H3\") Spnl \">\"") Rules[:_HtmlBlockH3] = rule_info("HtmlBlockH3", "HtmlBlockOpenH3 (HtmlBlockH3 | !HtmlBlockCloseH3 .)* HtmlBlockCloseH3") Rules[:_HtmlBlockOpenH4] = rule_info("HtmlBlockOpenH4", "\"<\" Spnl (\"h4\" | \"H4\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH4] = rule_info("HtmlBlockCloseH4", "\"<\" Spnl \"/\" (\"h4\" | \"H4\") Spnl \">\"") Rules[:_HtmlBlockH4] = rule_info("HtmlBlockH4", "HtmlBlockOpenH4 (HtmlBlockH4 | !HtmlBlockCloseH4 .)* HtmlBlockCloseH4") Rules[:_HtmlBlockOpenH5] = rule_info("HtmlBlockOpenH5", "\"<\" Spnl (\"h5\" | \"H5\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH5] = rule_info("HtmlBlockCloseH5", "\"<\" Spnl \"/\" (\"h5\" | \"H5\") Spnl \">\"") Rules[:_HtmlBlockH5] = rule_info("HtmlBlockH5", "HtmlBlockOpenH5 (HtmlBlockH5 | !HtmlBlockCloseH5 .)* HtmlBlockCloseH5") Rules[:_HtmlBlockOpenH6] = rule_info("HtmlBlockOpenH6", "\"<\" Spnl (\"h6\" | \"H6\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseH6] = rule_info("HtmlBlockCloseH6", "\"<\" Spnl \"/\" (\"h6\" | \"H6\") Spnl \">\"") Rules[:_HtmlBlockH6] = rule_info("HtmlBlockH6", "HtmlBlockOpenH6 (HtmlBlockH6 | !HtmlBlockCloseH6 .)* HtmlBlockCloseH6") Rules[:_HtmlBlockOpenMenu] = rule_info("HtmlBlockOpenMenu", "\"<\" Spnl (\"menu\" | \"MENU\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseMenu] = rule_info("HtmlBlockCloseMenu", "\"<\" Spnl \"/\" (\"menu\" | \"MENU\") Spnl \">\"") Rules[:_HtmlBlockMenu] = rule_info("HtmlBlockMenu", "HtmlBlockOpenMenu (HtmlBlockMenu | !HtmlBlockCloseMenu .)* HtmlBlockCloseMenu") Rules[:_HtmlBlockOpenNoframes] = rule_info("HtmlBlockOpenNoframes", "\"<\" Spnl (\"noframes\" | \"NOFRAMES\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseNoframes] = rule_info("HtmlBlockCloseNoframes", "\"<\" Spnl \"/\" (\"noframes\" | \"NOFRAMES\") Spnl \">\"") Rules[:_HtmlBlockNoframes] = rule_info("HtmlBlockNoframes", "HtmlBlockOpenNoframes (HtmlBlockNoframes | !HtmlBlockCloseNoframes .)* HtmlBlockCloseNoframes") Rules[:_HtmlBlockOpenNoscript] = rule_info("HtmlBlockOpenNoscript", "\"<\" Spnl (\"noscript\" | \"NOSCRIPT\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseNoscript] = rule_info("HtmlBlockCloseNoscript", "\"<\" Spnl \"/\" (\"noscript\" | \"NOSCRIPT\") Spnl \">\"") Rules[:_HtmlBlockNoscript] = rule_info("HtmlBlockNoscript", "HtmlBlockOpenNoscript (HtmlBlockNoscript | !HtmlBlockCloseNoscript .)* HtmlBlockCloseNoscript") Rules[:_HtmlBlockOpenOl] = rule_info("HtmlBlockOpenOl", "\"<\" Spnl (\"ol\" | \"OL\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseOl] = rule_info("HtmlBlockCloseOl", "\"<\" Spnl \"/\" (\"ol\" | \"OL\") Spnl \">\"") Rules[:_HtmlBlockOl] = rule_info("HtmlBlockOl", "HtmlBlockOpenOl (HtmlBlockOl | !HtmlBlockCloseOl .)* HtmlBlockCloseOl") Rules[:_HtmlBlockOpenP] = rule_info("HtmlBlockOpenP", "\"<\" Spnl (\"p\" | \"P\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseP] = rule_info("HtmlBlockCloseP", "\"<\" Spnl \"/\" (\"p\" | \"P\") Spnl \">\"") Rules[:_HtmlBlockP] = rule_info("HtmlBlockP", "HtmlBlockOpenP (HtmlBlockP | !HtmlBlockCloseP .)* HtmlBlockCloseP") Rules[:_HtmlBlockOpenPre] = rule_info("HtmlBlockOpenPre", "\"<\" Spnl (\"pre\" | \"PRE\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockClosePre] = rule_info("HtmlBlockClosePre", "\"<\" Spnl \"/\" (\"pre\" | \"PRE\") Spnl \">\"") Rules[:_HtmlBlockPre] = rule_info("HtmlBlockPre", "HtmlBlockOpenPre (HtmlBlockPre | !HtmlBlockClosePre .)* HtmlBlockClosePre") Rules[:_HtmlBlockOpenTable] = rule_info("HtmlBlockOpenTable", "\"<\" Spnl (\"table\" | \"TABLE\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTable] = rule_info("HtmlBlockCloseTable", "\"<\" Spnl \"/\" (\"table\" | \"TABLE\") Spnl \">\"") Rules[:_HtmlBlockTable] = rule_info("HtmlBlockTable", "HtmlBlockOpenTable (HtmlBlockTable | !HtmlBlockCloseTable .)* HtmlBlockCloseTable") Rules[:_HtmlBlockOpenUl] = rule_info("HtmlBlockOpenUl", "\"<\" Spnl (\"ul\" | \"UL\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseUl] = rule_info("HtmlBlockCloseUl", "\"<\" Spnl \"/\" (\"ul\" | \"UL\") Spnl \">\"") Rules[:_HtmlBlockUl] = rule_info("HtmlBlockUl", "HtmlBlockOpenUl (HtmlBlockUl | !HtmlBlockCloseUl .)* HtmlBlockCloseUl") Rules[:_HtmlBlockOpenDd] = rule_info("HtmlBlockOpenDd", "\"<\" Spnl (\"dd\" | \"DD\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDd] = rule_info("HtmlBlockCloseDd", "\"<\" Spnl \"/\" (\"dd\" | \"DD\") Spnl \">\"") Rules[:_HtmlBlockDd] = rule_info("HtmlBlockDd", "HtmlBlockOpenDd (HtmlBlockDd | !HtmlBlockCloseDd .)* HtmlBlockCloseDd") Rules[:_HtmlBlockOpenDt] = rule_info("HtmlBlockOpenDt", "\"<\" Spnl (\"dt\" | \"DT\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseDt] = rule_info("HtmlBlockCloseDt", "\"<\" Spnl \"/\" (\"dt\" | \"DT\") Spnl \">\"") Rules[:_HtmlBlockDt] = rule_info("HtmlBlockDt", "HtmlBlockOpenDt (HtmlBlockDt | !HtmlBlockCloseDt .)* HtmlBlockCloseDt") Rules[:_HtmlBlockOpenFrameset] = rule_info("HtmlBlockOpenFrameset", "\"<\" Spnl (\"frameset\" | \"FRAMESET\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseFrameset] = rule_info("HtmlBlockCloseFrameset", "\"<\" Spnl \"/\" (\"frameset\" | \"FRAMESET\") Spnl \">\"") Rules[:_HtmlBlockFrameset] = rule_info("HtmlBlockFrameset", "HtmlBlockOpenFrameset (HtmlBlockFrameset | !HtmlBlockCloseFrameset .)* HtmlBlockCloseFrameset") Rules[:_HtmlBlockOpenLi] = rule_info("HtmlBlockOpenLi", "\"<\" Spnl (\"li\" | \"LI\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseLi] = rule_info("HtmlBlockCloseLi", "\"<\" Spnl \"/\" (\"li\" | \"LI\") Spnl \">\"") Rules[:_HtmlBlockLi] = rule_info("HtmlBlockLi", "HtmlBlockOpenLi (HtmlBlockLi | !HtmlBlockCloseLi .)* HtmlBlockCloseLi") Rules[:_HtmlBlockOpenTbody] = rule_info("HtmlBlockOpenTbody", "\"<\" Spnl (\"tbody\" | \"TBODY\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTbody] = rule_info("HtmlBlockCloseTbody", "\"<\" Spnl \"/\" (\"tbody\" | \"TBODY\") Spnl \">\"") Rules[:_HtmlBlockTbody] = rule_info("HtmlBlockTbody", "HtmlBlockOpenTbody (HtmlBlockTbody | !HtmlBlockCloseTbody .)* HtmlBlockCloseTbody") Rules[:_HtmlBlockOpenTd] = rule_info("HtmlBlockOpenTd", "\"<\" Spnl (\"td\" | \"TD\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTd] = rule_info("HtmlBlockCloseTd", "\"<\" Spnl \"/\" (\"td\" | \"TD\") Spnl \">\"") Rules[:_HtmlBlockTd] = rule_info("HtmlBlockTd", "HtmlBlockOpenTd (HtmlBlockTd | !HtmlBlockCloseTd .)* HtmlBlockCloseTd") Rules[:_HtmlBlockOpenTfoot] = rule_info("HtmlBlockOpenTfoot", "\"<\" Spnl (\"tfoot\" | \"TFOOT\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTfoot] = rule_info("HtmlBlockCloseTfoot", "\"<\" Spnl \"/\" (\"tfoot\" | \"TFOOT\") Spnl \">\"") Rules[:_HtmlBlockTfoot] = rule_info("HtmlBlockTfoot", "HtmlBlockOpenTfoot (HtmlBlockTfoot | !HtmlBlockCloseTfoot .)* HtmlBlockCloseTfoot") Rules[:_HtmlBlockOpenTh] = rule_info("HtmlBlockOpenTh", "\"<\" Spnl (\"th\" | \"TH\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTh] = rule_info("HtmlBlockCloseTh", "\"<\" Spnl \"/\" (\"th\" | \"TH\") Spnl \">\"") Rules[:_HtmlBlockTh] = rule_info("HtmlBlockTh", "HtmlBlockOpenTh (HtmlBlockTh | !HtmlBlockCloseTh .)* HtmlBlockCloseTh") Rules[:_HtmlBlockOpenThead] = rule_info("HtmlBlockOpenThead", "\"<\" Spnl (\"thead\" | \"THEAD\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseThead] = rule_info("HtmlBlockCloseThead", "\"<\" Spnl \"/\" (\"thead\" | \"THEAD\") Spnl \">\"") Rules[:_HtmlBlockThead] = rule_info("HtmlBlockThead", "HtmlBlockOpenThead (HtmlBlockThead | !HtmlBlockCloseThead .)* HtmlBlockCloseThead") Rules[:_HtmlBlockOpenTr] = rule_info("HtmlBlockOpenTr", "\"<\" Spnl (\"tr\" | \"TR\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseTr] = rule_info("HtmlBlockCloseTr", "\"<\" Spnl \"/\" (\"tr\" | \"TR\") Spnl \">\"") Rules[:_HtmlBlockTr] = rule_info("HtmlBlockTr", "HtmlBlockOpenTr (HtmlBlockTr | !HtmlBlockCloseTr .)* HtmlBlockCloseTr") Rules[:_HtmlBlockOpenScript] = rule_info("HtmlBlockOpenScript", "\"<\" Spnl (\"script\" | \"SCRIPT\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseScript] = rule_info("HtmlBlockCloseScript", "\"<\" Spnl \"/\" (\"script\" | \"SCRIPT\") Spnl \">\"") Rules[:_HtmlBlockScript] = rule_info("HtmlBlockScript", "HtmlBlockOpenScript (!HtmlBlockCloseScript .)* HtmlBlockCloseScript") Rules[:_HtmlBlockOpenHead] = rule_info("HtmlBlockOpenHead", "\"<\" Spnl (\"head\" | \"HEAD\") Spnl HtmlAttribute* \">\"") Rules[:_HtmlBlockCloseHead] = rule_info("HtmlBlockCloseHead", "\"<\" Spnl \"/\" (\"head\" | \"HEAD\") Spnl \">\"") Rules[:_HtmlBlockHead] = rule_info("HtmlBlockHead", "HtmlBlockOpenHead (!HtmlBlockCloseHead .)* HtmlBlockCloseHead") Rules[:_HtmlBlockInTags] = rule_info("HtmlBlockInTags", "(HtmlAnchor | HtmlBlockAddress | HtmlBlockBlockquote | HtmlBlockCenter | HtmlBlockDir | HtmlBlockDiv | HtmlBlockDl | HtmlBlockFieldset | HtmlBlockForm | HtmlBlockH1 | HtmlBlockH2 | HtmlBlockH3 | HtmlBlockH4 | HtmlBlockH5 | HtmlBlockH6 | HtmlBlockMenu | HtmlBlockNoframes | HtmlBlockNoscript | HtmlBlockOl | HtmlBlockP | HtmlBlockPre | HtmlBlockTable | HtmlBlockUl | HtmlBlockDd | HtmlBlockDt | HtmlBlockFrameset | HtmlBlockLi | HtmlBlockTbody | HtmlBlockTd | HtmlBlockTfoot | HtmlBlockTh | HtmlBlockThead | HtmlBlockTr | HtmlBlockScript | HtmlBlockHead)") Rules[:_HtmlBlock] = rule_info("HtmlBlock", "< (HtmlBlockInTags | HtmlComment | HtmlBlockSelfClosing | HtmlUnclosed) > @BlankLine+ { if html? then RDoc::Markup::Raw.new text end }") Rules[:_HtmlUnclosed] = rule_info("HtmlUnclosed", "\"<\" Spnl HtmlUnclosedType Spnl HtmlAttribute* Spnl \">\"") Rules[:_HtmlUnclosedType] = rule_info("HtmlUnclosedType", "(\"HR\" | \"hr\")") Rules[:_HtmlBlockSelfClosing] = rule_info("HtmlBlockSelfClosing", "\"<\" Spnl HtmlBlockType Spnl HtmlAttribute* \"/\" Spnl \">\"") Rules[:_HtmlBlockType] = rule_info("HtmlBlockType", "(\"ADDRESS\" | \"BLOCKQUOTE\" | \"CENTER\" | \"DD\" | \"DIR\" | \"DIV\" | \"DL\" | \"DT\" | \"FIELDSET\" | \"FORM\" | \"FRAMESET\" | \"H1\" | \"H2\" | \"H3\" | \"H4\" | \"H5\" | \"H6\" | \"HR\" | \"ISINDEX\" | \"LI\" | \"MENU\" | \"NOFRAMES\" | \"NOSCRIPT\" | \"OL\" | \"P\" | \"PRE\" | \"SCRIPT\" | \"TABLE\" | \"TBODY\" | \"TD\" | \"TFOOT\" | \"TH\" | \"THEAD\" | \"TR\" | \"UL\" | \"address\" | \"blockquote\" | \"center\" | \"dd\" | \"dir\" | \"div\" | \"dl\" | \"dt\" | \"fieldset\" | \"form\" | \"frameset\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"hr\" | \"isindex\" | \"li\" | \"menu\" | \"noframes\" | \"noscript\" | \"ol\" | \"p\" | \"pre\" | \"script\" | \"table\" | \"tbody\" | \"td\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"ul\")") Rules[:_StyleOpen] = rule_info("StyleOpen", "\"<\" Spnl (\"style\" | \"STYLE\") Spnl HtmlAttribute* \">\"") Rules[:_StyleClose] = rule_info("StyleClose", "\"<\" Spnl \"/\" (\"style\" | \"STYLE\") Spnl \">\"") Rules[:_InStyleTags] = rule_info("InStyleTags", "StyleOpen (!StyleClose .)* StyleClose") Rules[:_StyleBlock] = rule_info("StyleBlock", "< InStyleTags > @BlankLine* { if css? then RDoc::Markup::Raw.new text end }") Rules[:_Inlines] = rule_info("Inlines", "(!@Endline Inline:i { i } | @Endline:c &Inline { c })+:chunks @Endline? { chunks }") Rules[:_Inline] = rule_info("Inline", "(Str | @Endline | UlOrStarLine | @Space | Strong | Emph | Strike | Image | Link | NoteReference | InlineNote | Code | RawHtml | Entity | EscapedChar | Symbol)") Rules[:_Space] = rule_info("Space", "@Spacechar+ { \" \" }") Rules[:_Str] = rule_info("Str", "@StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { a }") Rules[:_StrChunk] = rule_info("StrChunk", "< (@NormalChar | /_+/ &Alphanumeric)+ > { text }") Rules[:_EscapedChar] = rule_info("EscapedChar", "\"\\\\\" !@Newline < /[:\\\\`|*_{}\\[\\]()\#+.!><-]/ > { text }") Rules[:_Entity] = rule_info("Entity", "(HexEntity | DecEntity | CharEntity):a { a }") Rules[:_Endline] = rule_info("Endline", "(@LineBreak | @TerminalEndline | @NormalEndline)") Rules[:_NormalEndline] = rule_info("NormalEndline", "@Sp @Newline !@BlankLine !\">\" !AtxStart !(Line /={1,}|-{1,}/ @Newline) { \"\\n\" }") Rules[:_TerminalEndline] = rule_info("TerminalEndline", "@Sp @Newline @Eof") Rules[:_LineBreak] = rule_info("LineBreak", "\" \" @NormalEndline { RDoc::Markup::HardBreak.new }") Rules[:_Symbol] = rule_info("Symbol", "< @SpecialChar > { text }") Rules[:_UlOrStarLine] = rule_info("UlOrStarLine", "(UlLine | StarLine):a { a }") Rules[:_StarLine] = rule_info("StarLine", "(< /\\*{4,}/ > { text } | < @Spacechar /\\*+/ &@Spacechar > { text })") Rules[:_UlLine] = rule_info("UlLine", "(< /_{4,}/ > { text } | < @Spacechar /_+/ &@Spacechar > { text })") Rules[:_Emph] = rule_info("Emph", "(EmphStar | EmphUl)") Rules[:_Whitespace] = rule_info("Whitespace", "(@Spacechar | @Newline)") Rules[:_EmphStar] = rule_info("EmphStar", "\"*\" !@Whitespace @StartList:a (!\"*\" Inline:b { a << b } | StrongStar:b { a << b })+ \"*\" { emphasis a.join }") Rules[:_EmphUl] = rule_info("EmphUl", "\"_\" !@Whitespace @StartList:a (!\"_\" Inline:b { a << b } | StrongUl:b { a << b })+ \"_\" { emphasis a.join }") Rules[:_Strong] = rule_info("Strong", "(StrongStar | StrongUl)") Rules[:_StrongStar] = rule_info("StrongStar", "\"**\" !@Whitespace @StartList:a (!\"**\" Inline:b { a << b })+ \"**\" { strong a.join }") Rules[:_StrongUl] = rule_info("StrongUl", "\"__\" !@Whitespace @StartList:a (!\"__\" Inline:b { a << b })+ \"__\" { strong a.join }") Rules[:_Strike] = rule_info("Strike", "&{ strike? } \"~~\" !@Whitespace @StartList:a (!\"~~\" Inline:b { a << b })+ \"~~\" { strike a.join }") Rules[:_Image] = rule_info("Image", "\"!\" (ExplicitLink | ReferenceLink):a { \"rdoc-image:\#{a[/\\[(.*)\\]/, 1]}\" }") Rules[:_Link] = rule_info("Link", "(ExplicitLink | ReferenceLink | AutoLink)") Rules[:_ReferenceLink] = rule_info("ReferenceLink", "(ReferenceLinkDouble | ReferenceLinkSingle)") Rules[:_ReferenceLinkDouble] = rule_info("ReferenceLinkDouble", "Label:content < Spnl > !\"[]\" Label:label { link_to content, label, text }") Rules[:_ReferenceLinkSingle] = rule_info("ReferenceLinkSingle", "Label:content < (Spnl \"[]\")? > { link_to content, content, text }") Rules[:_ExplicitLink] = rule_info("ExplicitLink", "Label:l \"(\" @Sp Source:s Spnl Title @Sp \")\" { \"{\#{l}}[\#{s}]\" }") Rules[:_Source] = rule_info("Source", "(\"<\" < SourceContents > \">\" | < SourceContents >) { text }") Rules[:_SourceContents] = rule_info("SourceContents", "((!\"(\" !\")\" !\">\" Nonspacechar)+ | \"(\" SourceContents \")\")*") Rules[:_Title] = rule_info("Title", "(TitleSingle | TitleDouble | \"\"):a { a }") Rules[:_TitleSingle] = rule_info("TitleSingle", "\"'\" (!(\"'\" @Sp (\")\" | @Newline)) .)* \"'\"") Rules[:_TitleDouble] = rule_info("TitleDouble", "\"\\\"\" (!(\"\\\"\" @Sp (\")\" | @Newline)) .)* \"\\\"\"") Rules[:_AutoLink] = rule_info("AutoLink", "(AutoLinkUrl | AutoLinkEmail)") Rules[:_AutoLinkUrl] = rule_info("AutoLinkUrl", "\"<\" < /[A-Za-z]+/ \"://\" (!@Newline !\">\" .)+ > \">\" { text }") Rules[:_AutoLinkEmail] = rule_info("AutoLinkEmail", "\"<\" \"mailto:\"? < /[\\w+.\\/!%~$-]+/i \"@\" (!@Newline !\">\" .)+ > \">\" { \"mailto:\#{text}\" }") Rules[:_Reference] = rule_info("Reference", "@NonindentSpace !\"[]\" Label:label \":\" Spnl RefSrc:link RefTitle @BlankLine+ { \# TODO use title reference label, link nil }") Rules[:_Label] = rule_info("Label", "\"[\" (!\"^\" &{ notes? } | &. &{ !notes? }) @StartList:a (!\"]\" Inline:l { a << l })* \"]\" { a.join.gsub(/\\s+/, ' ') }") Rules[:_RefSrc] = rule_info("RefSrc", "< Nonspacechar+ > { text }") Rules[:_RefTitle] = rule_info("RefTitle", "(RefTitleSingle | RefTitleDouble | RefTitleParens | EmptyTitle)") Rules[:_EmptyTitle] = rule_info("EmptyTitle", "\"\"") Rules[:_RefTitleSingle] = rule_info("RefTitleSingle", "Spnl \"'\" < (!(\"'\" @Sp @Newline | @Newline) .)* > \"'\" { text }") Rules[:_RefTitleDouble] = rule_info("RefTitleDouble", "Spnl \"\\\"\" < (!(\"\\\"\" @Sp @Newline | @Newline) .)* > \"\\\"\" { text }") Rules[:_RefTitleParens] = rule_info("RefTitleParens", "Spnl \"(\" < (!(\")\" @Sp @Newline | @Newline) .)* > \")\" { text }") Rules[:_References] = rule_info("References", "(Reference | SkipBlock)*") Rules[:_Ticks1] = rule_info("Ticks1", "\"`\" !\"`\"") Rules[:_Ticks2] = rule_info("Ticks2", "\"``\" !\"`\"") Rules[:_Ticks3] = rule_info("Ticks3", "\"```\" !\"`\"") Rules[:_Ticks4] = rule_info("Ticks4", "\"````\" !\"`\"") Rules[:_Ticks5] = rule_info("Ticks5", "\"`````\" !\"`\"") Rules[:_Code] = rule_info("Code", "(Ticks1 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks1 /`+/ | !(@Sp Ticks1) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks1 | Ticks2 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks2 /`+/ | !(@Sp Ticks2) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks2 | Ticks3 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | !(@Sp Ticks3) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks3 | Ticks4 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks4 /`+/ | !(@Sp Ticks4) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks4 | Ticks5 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks5 /`+/ | !(@Sp Ticks5) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks5) { \"\#{text}\" }") Rules[:_RawHtml] = rule_info("RawHtml", "< (HtmlComment | HtmlBlockScript | HtmlTag) > { if html? then text else '' end }") Rules[:_BlankLine] = rule_info("BlankLine", "@Sp @Newline { \"\\n\" }") Rules[:_Quoted] = rule_info("Quoted", "(\"\\\"\" (!\"\\\"\" .)* \"\\\"\" | \"'\" (!\"'\" .)* \"'\")") Rules[:_HtmlAttribute] = rule_info("HtmlAttribute", "(AlphanumericAscii | \"-\")+ Spnl (\"=\" Spnl (Quoted | (!\">\" Nonspacechar)+))? Spnl") Rules[:_HtmlComment] = rule_info("HtmlComment", "\"\" .)* \"-->\"") Rules[:_HtmlTag] = rule_info("HtmlTag", "\"<\" Spnl \"/\"? AlphanumericAscii+ Spnl HtmlAttribute* \"/\"? Spnl \">\"") Rules[:_Eof] = rule_info("Eof", "!.") Rules[:_Nonspacechar] = rule_info("Nonspacechar", "!@Spacechar !@Newline .") Rules[:_Sp] = rule_info("Sp", "@Spacechar*") Rules[:_Spnl] = rule_info("Spnl", "@Sp (@Newline @Sp)?") Rules[:_SpecialChar] = rule_info("SpecialChar", "(/[~*_`&\\[\\]() \";\" { [text.to_i(16)].pack 'U' }") Rules[:_DecEntity] = rule_info("DecEntity", "\"&\#\" < /[0-9]+/ > \";\" { [text.to_i].pack 'U' }") Rules[:_CharEntity] = rule_info("CharEntity", "\"&\" < /[A-Za-z0-9]+/ > \";\" { if entity = HTML_ENTITIES[text] then entity.pack 'U*' else \"&\#{text};\" end }") Rules[:_NonindentSpace] = rule_info("NonindentSpace", "/ {0,3}/") Rules[:_Indent] = rule_info("Indent", "/\\t| /") Rules[:_IndentedLine] = rule_info("IndentedLine", "Indent Line") Rules[:_OptionallyIndentedLine] = rule_info("OptionallyIndentedLine", "Indent? Line") Rules[:_StartList] = rule_info("StartList", "&. { [] }") Rules[:_Line] = rule_info("Line", "@RawLine:a { a }") Rules[:_RawLine] = rule_info("RawLine", "(< (!\"\\r\" !\"\\n\" .)* @Newline > | < .+ > @Eof) { text }") Rules[:_SkipBlock] = rule_info("SkipBlock", "(HtmlBlock | (!\"\#\" !SetextBottom1 !SetextBottom2 !@BlankLine @RawLine)+ @BlankLine* | @BlankLine+ | @RawLine)") Rules[:_ExtendedSpecialChar] = rule_info("ExtendedSpecialChar", "&{ notes? } \"^\"") Rules[:_NoteReference] = rule_info("NoteReference", "&{ notes? } RawNoteReference:ref { note_for ref }") Rules[:_RawNoteReference] = rule_info("RawNoteReference", "\"[^\" < (!@Newline !\"]\" .)+ > \"]\" { text }") Rules[:_Note] = rule_info("Note", "&{ notes? } @NonindentSpace RawNoteReference:ref \":\" @Sp @StartList:a RawNoteBlock:i { a.concat i } (&Indent RawNoteBlock:i { a.concat i })* { @footnotes[ref] = paragraph a nil }") Rules[:_InlineNote] = rule_info("InlineNote", "&{ notes? } \"^[\" @StartList:a (!\"]\" Inline:l { a << l })+ \"]\" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref }") Rules[:_Notes] = rule_info("Notes", "(Note | SkipBlock)*") Rules[:_RawNoteBlock] = rule_info("RawNoteBlock", "@StartList:a (!@BlankLine OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a }") Rules[:_CodeFence] = rule_info("CodeFence", "&{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim }") Rules[:_DefinitionList] = rule_info("DefinitionList", "&{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten }") Rules[:_DefinitionListItem] = rule_info("DefinitionListItem", "DefinitionListLabel+:label DefinitionListDefinition+:defns { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items }") Rules[:_DefinitionListLabel] = rule_info("DefinitionListLabel", "StrChunk:label @Sp @Newline { label }") Rules[:_DefinitionListDefinition] = rule_info("DefinitionListDefinition", "@NonindentSpace \":\" @Space Inlines:a @BlankLine+ { paragraph a }") # :startdoc: end PKu]WnYYrdoc-6.2.1.1/lib/rdoc/ri.rbnu[# frozen_string_literal: true require 'rdoc' ## # Namespace for the ri command line tool's implementation. # # See ri --help for details. module RDoc::RI ## # Base RI error class class Error < RDoc::Error; end autoload :Driver, 'rdoc/ri/driver' autoload :Paths, 'rdoc/ri/paths' autoload :Store, 'rdoc/ri/store' end PKu]+Zq{q{ rdoc-6.2.1.1/lib/rdoc/options.rbnu[# frozen_string_literal: true require 'optparse' require 'pathname' ## # RDoc::Options handles the parsing and storage of options # # == Saved Options # # You can save some options like the markup format in the # .rdoc_options file in your gem. The easiest way to do this is: # # rdoc --markup tomdoc --write-options # # Which will automatically create the file and fill it with the options you # specified. # # The following options will not be saved since they interfere with the user's # preferences or with the normal operation of RDoc: # # * +--coverage-report+ # * +--dry-run+ # * +--encoding+ # * +--force-update+ # * +--format+ # * +--pipe+ # * +--quiet+ # * +--template+ # * +--verbose+ # # == Custom Options # # Generators can hook into RDoc::Options to add generator-specific command # line options. # # When --format is encountered in ARGV, RDoc calls ::setup_options on # the generator class to add extra options to the option parser. Options for # custom generators must occur after --format. rdoc --help # will list options for all installed generators. # # Example: # # class RDoc::Generator::Spellcheck # RDoc::RDoc.add_generator self # # def self.setup_options rdoc_options # op = rdoc_options.option_parser # # op.on('--spell-dictionary DICTIONARY', # RDoc::Options::Path) do |dictionary| # rdoc_options.spell_dictionary = dictionary # end # end # end # # Of course, RDoc::Options does not respond to +spell_dictionary+ by default # so you will need to add it: # # class RDoc::Options # # ## # # The spell dictionary used by the spell-checking plugin. # # attr_accessor :spell_dictionary # # end # # == Option Validators # # OptionParser validators will validate and cast user input values. In # addition to the validators that ship with OptionParser (String, Integer, # Float, TrueClass, FalseClass, Array, Regexp, Date, Time, URI, etc.), # RDoc::Options adds Path, PathArray and Template. class RDoc::Options ## # The deprecated options. DEPRECATED = { '--accessor' => 'support discontinued', '--diagram' => 'support discontinued', '--help-output' => 'support discontinued', '--image-format' => 'was an option for --diagram', '--inline-source' => 'source code is now always inlined', '--merge' => 'ri now always merges class information', '--one-file' => 'support discontinued', '--op-name' => 'support discontinued', '--opname' => 'support discontinued', '--promiscuous' => 'files always only document their content', '--ri-system' => 'Ruby installers use other techniques', } ## # RDoc options ignored (or handled specially) by --write-options SPECIAL = %w[ coverage_report dry_run encoding files force_output force_update generator generator_name generator_options generators op_dir option_parser pipe rdoc_include root static_path stylesheet_url template template_dir update_output_dir verbosity write_options ] ## # Option validator for OptionParser that matches a directory that exists on # the filesystem. Directory = Object.new ## # Option validator for OptionParser that matches a file or directory that # exists on the filesystem. Path = Object.new ## # Option validator for OptionParser that matches a comma-separated list of # files or directories that exist on the filesystem. PathArray = Object.new ## # Option validator for OptionParser that matches a template directory for an # installed generator that lives in # "rdoc/generator/template/#{template_name}" Template = Object.new ## # Character-set for HTML output. #encoding is preferred over #charset attr_accessor :charset ## # If true, RDoc will not write any files. attr_accessor :dry_run ## # The output encoding. All input files will be transcoded to this encoding. # # The default encoding is UTF-8. This is set via --encoding. attr_accessor :encoding ## # Files matching this pattern will be excluded attr_writer :exclude ## # The list of files to be processed attr_accessor :files ## # Create the output even if the output directory does not look # like an rdoc output directory attr_accessor :force_output ## # Scan newer sources than the flag file if true. attr_accessor :force_update ## # Formatter to mark up text with attr_accessor :formatter ## # Description of the output generator (set with the --format option) attr_accessor :generator ## # For #== attr_reader :generator_name # :nodoc: ## # Loaded generator options. Used to prevent --help from loading the same # options multiple times. attr_accessor :generator_options ## # Old rdoc behavior: hyperlink all words that match a method name, # even if not preceded by '#' or '::' attr_accessor :hyperlink_all ## # Include line numbers in the source code attr_accessor :line_numbers ## # The output locale. attr_accessor :locale ## # The directory where locale data live. attr_accessor :locale_dir ## # Name of the file, class or module to display in the initial index page (if # not specified the first file we encounter is used) attr_accessor :main_page ## # The default markup format. The default is 'rdoc'. 'markdown', 'tomdoc' # and 'rd' are also built-in. attr_accessor :markup ## # If true, only report on undocumented files attr_accessor :coverage_report ## # The name of the output directory attr_accessor :op_dir ## # The OptionParser for this instance attr_accessor :option_parser ## # Output heading decorations? attr_accessor :output_decoration ## # Directory where guides, FAQ, and other pages not associated with a class # live. You may leave this unset if these are at the root of your project. attr_accessor :page_dir ## # Is RDoc in pipe mode? attr_accessor :pipe ## # Array of directories to search for files to satisfy an :include: attr_accessor :rdoc_include ## # Root of the source documentation will be generated for. Set this when # building documentation outside the source directory. Defaults to the # current directory. attr_accessor :root ## # Include the '#' at the front of hyperlinked instance method names attr_accessor :show_hash ## # Directory to copy static files from attr_accessor :static_path ## # The number of columns in a tab attr_accessor :tab_width ## # Template to be used when generating output attr_accessor :template ## # Directory the template lives in attr_accessor :template_dir ## # Additional template stylesheets attr_accessor :template_stylesheets ## # Documentation title attr_accessor :title ## # Should RDoc update the timestamps in the output dir? attr_accessor :update_output_dir ## # Verbosity, zero means quiet attr_accessor :verbosity ## # URL of web cvs frontend attr_accessor :webcvs ## # Minimum visibility of a documented method. One of +:public+, +:protected+, # +:private+ or +:nodoc+. # # The +:nodoc+ visibility ignores all directives related to visibility. The # other visibilities may be overridden on a per-method basis with the :doc: # directive. attr_reader :visibility def initialize # :nodoc: init_ivars end def init_ivars # :nodoc: @dry_run = false @exclude = %w[ ~\z \.orig\z \.rej\z \.bak\z \.gemspec\z ] @files = nil @force_output = false @force_update = true @generator = nil @generator_name = nil @generator_options = [] @generators = RDoc::RDoc::GENERATORS @hyperlink_all = false @line_numbers = false @locale = nil @locale_name = nil @locale_dir = 'locale' @main_page = nil @markup = 'rdoc' @coverage_report = false @op_dir = nil @page_dir = nil @pipe = false @output_decoration = true @rdoc_include = [] @root = Pathname(Dir.pwd) @show_hash = false @static_path = [] @stylesheet_url = nil # TODO remove in RDoc 4 @tab_width = 8 @template = nil @template_dir = nil @template_stylesheets = [] @title = nil @update_output_dir = true @verbosity = 1 @visibility = :protected @webcvs = nil @write_options = false @encoding = Encoding::UTF_8 @charset = @encoding.name end def init_with map # :nodoc: init_ivars encoding = map['encoding'] @encoding = encoding ? Encoding.find(encoding) : encoding @charset = map['charset'] @exclude = map['exclude'] @generator_name = map['generator_name'] @hyperlink_all = map['hyperlink_all'] @line_numbers = map['line_numbers'] @locale_name = map['locale_name'] @locale_dir = map['locale_dir'] @main_page = map['main_page'] @markup = map['markup'] @op_dir = map['op_dir'] @show_hash = map['show_hash'] @tab_width = map['tab_width'] @template_dir = map['template_dir'] @title = map['title'] @visibility = map['visibility'] @webcvs = map['webcvs'] @rdoc_include = sanitize_path map['rdoc_include'] @static_path = sanitize_path map['static_path'] end def yaml_initialize tag, map # :nodoc: init_with map end def == other # :nodoc: self.class === other and @encoding == other.encoding and @generator_name == other.generator_name and @hyperlink_all == other.hyperlink_all and @line_numbers == other.line_numbers and @locale == other.locale and @locale_dir == other.locale_dir and @main_page == other.main_page and @markup == other.markup and @op_dir == other.op_dir and @rdoc_include == other.rdoc_include and @show_hash == other.show_hash and @static_path == other.static_path and @tab_width == other.tab_width and @template == other.template and @title == other.title and @visibility == other.visibility and @webcvs == other.webcvs end ## # Check that the files on the command line exist def check_files @files.delete_if do |file| if File.exist? file then if File.readable? file then false else warn "file '#{file}' not readable" true end else warn "file '#{file}' not found" true end end end ## # Ensure only one generator is loaded def check_generator if @generator then raise OptionParser::InvalidOption, "generator already set to #{@generator_name}" end end ## # Set the title, but only if not already set. Used to set the title # from a source file, so that a title set from the command line # will have the priority. def default_title=(string) @title ||= string end ## # For dumping YAML def encode_with coder # :nodoc: encoding = @encoding ? @encoding.name : nil coder.add 'encoding', encoding coder.add 'static_path', sanitize_path(@static_path) coder.add 'rdoc_include', sanitize_path(@rdoc_include) ivars = instance_variables.map { |ivar| ivar.to_s[1..-1] } ivars -= SPECIAL ivars.sort.each do |ivar| coder.add ivar, instance_variable_get("@#{ivar}") end end ## # Create a regexp for #exclude def exclude if @exclude.nil? or Regexp === @exclude then # done, #finish is being re-run @exclude elsif @exclude.empty? then nil else Regexp.new(@exclude.join("|")) end end ## # Completes any unfinished option setup business such as filtering for # existent files, creating a regexp for #exclude and setting a default # #template. def finish @op_dir ||= 'doc' @rdoc_include << "." if @rdoc_include.empty? root = @root.to_s @rdoc_include << root unless @rdoc_include.include?(root) @exclude = self.exclude finish_page_dir check_files # If no template was specified, use the default template for the output # formatter unless @template then @template = @generator_name @template_dir = template_dir_for @template end if @locale_name @locale = RDoc::I18n::Locale[@locale_name] @locale.load(@locale_dir) else @locale = nil end self end ## # Fixes the page_dir to be relative to the root_dir and adds the page_dir to # the files list. def finish_page_dir return unless @page_dir @files << @page_dir.to_s page_dir = nil begin page_dir = @page_dir.expand_path.relative_path_from @root rescue ArgumentError # On Windows, sometimes crosses different drive letters. page_dir = @page_dir.expand_path end @page_dir = page_dir end ## # Returns a properly-space list of generators and their descriptions. def generator_descriptions lengths = [] generators = RDoc::RDoc::GENERATORS.map do |name, generator| lengths << name.length description = generator::DESCRIPTION if generator.const_defined? :DESCRIPTION [name, description] end longest = lengths.max generators.sort.map do |name, description| if description then " %-*s - %s" % [longest, name, description] else " #{name}" end end.join "\n" end ## # Parses command line options. def parse argv ignore_invalid = true argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT'] opts = OptionParser.new do |opt| @option_parser = opt opt.program_name = File.basename $0 opt.version = RDoc::VERSION opt.release = nil opt.summary_indent = ' ' * 4 opt.banner = <<-EOF Usage: #{opt.program_name} [options] [names...] Files are parsed, and the information they contain collected, before any output is produced. This allows cross references between all files to be resolved. If a name is a directory, it is traversed. If no names are specified, all Ruby files in the current directory (and subdirectories) are processed. How RDoc generates output depends on the output formatter being used, and on the options you give. Options can be specified via the RDOCOPT environment variable, which functions similar to the RUBYOPT environment variable for ruby. $ export RDOCOPT="--show-hash" will make rdoc show hashes in method links by default. Command-line options always will override those in RDOCOPT. Available formatters: #{generator_descriptions} RDoc understands the following file formats: EOF parsers = Hash.new { |h,parser| h[parser] = [] } RDoc::Parser.parsers.each do |regexp, parser| parsers[parser.name.sub('RDoc::Parser::', '')] << regexp.source end parsers.sort.each do |parser, regexp| opt.banner += " - #{parser}: #{regexp.join ', '}\n" end opt.banner += " - TomDoc: Only in ruby files\n" opt.banner += "\n The following options are deprecated:\n\n" name_length = DEPRECATED.keys.sort_by { |k| k.length }.last.length DEPRECATED.sort_by { |k,| k }.each do |name, reason| opt.banner += " %*1$2$s %3$s\n" % [-name_length, name, reason] end opt.accept Template do |template| template_dir = template_dir_for template unless template_dir then $stderr.puts "could not find template #{template}" nil else [template, template_dir] end end opt.accept Directory do |directory| directory = File.expand_path directory raise OptionParser::InvalidArgument unless File.directory? directory directory end opt.accept Path do |path| path = File.expand_path path raise OptionParser::InvalidArgument unless File.exist? path path end opt.accept PathArray do |paths,| paths = if paths then paths.split(',').map { |d| d unless d.empty? } end paths.map do |path| path = File.expand_path path raise OptionParser::InvalidArgument unless File.exist? path path end end opt.separator nil opt.separator "Parsing options:" opt.separator nil opt.on("--encoding=ENCODING", "-e", Encoding.list.map { |e| e.name }, "Specifies the output encoding. All files", "read will be converted to this encoding.", "The default encoding is UTF-8.", "--encoding is preferred over --charset") do |value| @encoding = Encoding.find value @charset = @encoding.name # may not be valid value end opt.separator nil opt.on("--locale=NAME", "Specifies the output locale.") do |value| @locale_name = value end opt.on("--locale-data-dir=DIR", "Specifies the directory where locale data live.") do |value| @locale_dir = value end opt.separator nil opt.on("--all", "-a", "Synonym for --visibility=private.") do |value| @visibility = :private end opt.separator nil opt.on("--exclude=PATTERN", "-x", Regexp, "Do not process files or directories", "matching PATTERN.") do |value| @exclude << value end opt.separator nil opt.on("--extension=NEW=OLD", "-E", "Treat files ending with .new as if they", "ended with .old. Using '-E cgi=rb' will", "cause xxx.cgi to be parsed as a Ruby file.") do |value| new, old = value.split(/=/, 2) unless new and old then raise OptionParser::InvalidArgument, "Invalid parameter to '-E'" end unless RDoc::Parser.alias_extension old, new then raise OptionParser::InvalidArgument, "Unknown extension .#{old} to -E" end end opt.separator nil opt.on("--[no-]force-update", "-U", "Forces rdoc to scan all sources even if", "newer than the flag file.") do |value| @force_update = value end opt.separator nil opt.on("--pipe", "-p", "Convert RDoc on stdin to HTML") do @pipe = true end opt.separator nil opt.on("--tab-width=WIDTH", "-w", Integer, "Set the width of tab characters.") do |value| raise OptionParser::InvalidArgument, "#{value} is an invalid tab width" if value <= 0 @tab_width = value end opt.separator nil opt.on("--visibility=VISIBILITY", "-V", RDoc::VISIBILITIES + [:nodoc], "Minimum visibility to document a method.", "One of 'public', 'protected' (the default),", "'private' or 'nodoc' (show everything)") do |value| @visibility = value end opt.separator nil markup_formats = RDoc::Text::MARKUP_FORMAT.keys.sort opt.on("--markup=MARKUP", markup_formats, "The markup format for the named files.", "The default is rdoc. Valid values are:", markup_formats.join(', ')) do |value| @markup = value end opt.separator nil opt.on("--root=ROOT", Directory, "Root of the source tree documentation", "will be generated for. Set this when", "building documentation outside the", "source directory. Default is the", "current directory.") do |root| @root = Pathname(root) end opt.separator nil opt.on("--page-dir=DIR", Directory, "Directory where guides, your FAQ or", "other pages not associated with a class", "live. Set this when you don't store", "such files at your project root.", "NOTE: Do not use the same file name in", "the page dir and the root of your project") do |page_dir| @page_dir = Pathname(page_dir) end opt.separator nil opt.separator "Common generator options:" opt.separator nil opt.on("--force-output", "-O", "Forces rdoc to write the output files,", "even if the output directory exists", "and does not seem to have been created", "by rdoc.") do |value| @force_output = value end opt.separator nil generator_text = @generators.keys.map { |name| " #{name}" }.sort opt.on("-f", "--fmt=FORMAT", "--format=FORMAT", @generators.keys, "Set the output formatter. One of:", *generator_text) do |value| check_generator @generator_name = value.downcase setup_generator end opt.separator nil opt.on("--include=DIRECTORIES", "-i", PathArray, "Set (or add to) the list of directories to", "be searched when satisfying :include:", "requests. Can be used more than once.") do |value| @rdoc_include.concat value.map { |dir| dir.strip } end opt.separator nil opt.on("--[no-]coverage-report=[LEVEL]", "--[no-]dcov", "-C", Integer, "Prints a report on undocumented items.", "Does not generate files.") do |value| value = 0 if value.nil? # Integer converts -C to nil @coverage_report = value @force_update = true if value end opt.separator nil opt.on("--output=DIR", "--op", "-o", "Set the output directory.") do |value| @op_dir = value end opt.separator nil opt.on("-d", "Deprecated --diagram option.", "Prevents firing debug mode", "with legacy invocation.") do |value| end opt.separator nil opt.separator 'HTML generator options:' opt.separator nil opt.on("--charset=CHARSET", "-c", "Specifies the output HTML character-set.", "Use --encoding instead of --charset if", "available.") do |value| @charset = value end opt.separator nil opt.on("--hyperlink-all", "-A", "Generate hyperlinks for all words that", "correspond to known methods, even if they", "do not start with '#' or '::' (legacy", "behavior).") do |value| @hyperlink_all = value end opt.separator nil opt.on("--main=NAME", "-m", "NAME will be the initial page displayed.") do |value| @main_page = value end opt.separator nil opt.on("--[no-]line-numbers", "-N", "Include line numbers in the source code.", "By default, only the number of the first", "line is displayed, in a leading comment.") do |value| @line_numbers = value end opt.separator nil opt.on("--show-hash", "-H", "A name of the form #name in a comment is a", "possible hyperlink to an instance method", "name. When displayed, the '#' is removed", "unless this option is specified.") do |value| @show_hash = value end opt.separator nil opt.on("--template=NAME", "-T", Template, "Set the template used when generating", "output. The default depends on the", "formatter used.") do |(template, template_dir)| @template = template @template_dir = template_dir end opt.separator nil opt.on("--template-stylesheets=FILES", PathArray, "Set (or add to) the list of files to", "include with the html template.") do |value| @template_stylesheets << value end opt.separator nil opt.on("--title=TITLE", "-t", "Set TITLE as the title for HTML output.") do |value| @title = value end opt.separator nil opt.on("--copy-files=PATH", Path, "Specify a file or directory to copy static", "files from.", "If a file is given it will be copied into", "the output dir. If a directory is given the", "entire directory will be copied.", "You can use this multiple times") do |value| @static_path << value end opt.separator nil opt.on("--webcvs=URL", "-W", "Specify a URL for linking to a web frontend", "to CVS. If the URL contains a '\%s', the", "name of the current file will be", "substituted; if the URL doesn't contain a", "'\%s', the filename will be appended to it.") do |value| @webcvs = value end opt.separator nil opt.separator "ri generator options:" opt.separator nil opt.on("--ri", "-r", "Generate output for use by `ri`. The files", "are stored in the '.rdoc' directory under", "your home directory unless overridden by a", "subsequent --op parameter, so no special", "privileges are needed.") do |value| check_generator @generator_name = "ri" @op_dir ||= RDoc::RI::Paths::HOMEDIR setup_generator end opt.separator nil opt.on("--ri-site", "-R", "Generate output for use by `ri`. The files", "are stored in a site-wide directory,", "making them accessible to others, so", "special privileges are needed.") do |value| check_generator @generator_name = "ri" @op_dir = RDoc::RI::Paths.site_dir setup_generator end opt.separator nil opt.separator "Generic options:" opt.separator nil opt.on("--write-options", "Write .rdoc_options to the current", "directory with the given options. Not all", "options will be used. See RDoc::Options", "for details.") do |value| @write_options = true end opt.separator nil opt.on("--[no-]dry-run", "Don't write any files") do |value| @dry_run = value end opt.separator nil opt.on("-D", "--[no-]debug", "Displays lots on internal stuff.") do |value| $DEBUG_RDOC = value end opt.separator nil opt.on("--[no-]ignore-invalid", "Ignore invalid options and continue", "(default true).") do |value| ignore_invalid = value end opt.separator nil opt.on("--quiet", "-q", "Don't show progress as we parse.") do |value| @verbosity = 0 end opt.separator nil opt.on("--verbose", "-V", "Display extra progress as RDoc parses") do |value| @verbosity = 2 end opt.separator nil opt.on("--version", "-v", "print the version") do puts opt.version exit end opt.separator nil opt.on("--help", "-h", "Display this help") do RDoc::RDoc::GENERATORS.each_key do |generator| setup_generator generator end puts opt.help exit end opt.separator nil end setup_generator 'darkfish' if argv.grep(/\A(-f|--fmt|--format|-r|-R|--ri|--ri-site)\b/).empty? deprecated = [] invalid = [] begin opts.parse! argv rescue OptionParser::ParseError => e if DEPRECATED[e.args.first] then deprecated << e.args.first elsif %w[--format --ri -r --ri-site -R].include? e.args.first then raise else invalid << e.args.join(' ') end retry end unless @generator then @generator = RDoc::Generator::Darkfish @generator_name = 'darkfish' end if @pipe and not argv.empty? then @pipe = false invalid << '-p (with files)' end unless quiet then deprecated.each do |opt| $stderr.puts 'option ' + opt + ' is deprecated: ' + DEPRECATED[opt] end end unless invalid.empty? then invalid = "invalid options: #{invalid.join ', '}" if ignore_invalid then unless quiet then $stderr.puts invalid $stderr.puts '(invalid options are ignored)' end else unless quiet then $stderr.puts opts end $stderr.puts invalid exit 1 end end @files = argv.dup finish if @write_options then write_options exit end self end ## # Don't display progress as we process the files def quiet @verbosity.zero? end ## # Set quietness to +bool+ def quiet= bool @verbosity = bool ? 0 : 1 end ## # Removes directories from +path+ that are outside the current directory def sanitize_path path require 'pathname' dot = Pathname.new('.').expand_path path.reject do |item| path = Pathname.new(item).expand_path is_reject = nil relative = nil begin relative = path.relative_path_from(dot).to_s rescue ArgumentError # On Windows, sometimes crosses different drive letters. is_reject = true else is_reject = relative.start_with? '..' end is_reject end end ## # Set up an output generator for the named +generator_name+. # # If the found generator responds to :setup_options it will be called with # the options instance. This allows generators to add custom options or set # default options. def setup_generator generator_name = @generator_name @generator = @generators[generator_name] unless @generator then raise OptionParser::InvalidArgument, "Invalid output formatter #{generator_name}" end return if @generator_options.include? @generator @generator_name = generator_name @generator_options << @generator if @generator.respond_to? :setup_options then @option_parser ||= OptionParser.new @generator.setup_options self end end ## # Finds the template dir for +template+ def template_dir_for template template_path = File.join 'rdoc', 'generator', 'template', template $LOAD_PATH.map do |path| File.join File.expand_path(path), template_path end.find do |dir| File.directory? dir end end # Sets the minimum visibility of a documented method. # # Accepts +:public+, +:protected+, +:private+, +:nodoc+, or +:all+. # # When +:all+ is passed, visibility is set to +:private+, similarly to # RDOCOPT="--all", see #visibility for more information. def visibility= visibility case visibility when :all @visibility = :private else @visibility = visibility end end ## # Displays a warning using Kernel#warn if we're being verbose def warn message super message if @verbosity > 1 end ## # Writes the YAML file .rdoc_options to the current directory containing the # parsed options. def write_options RDoc.load_yaml File.open '.rdoc_options', 'w' do |io| io.set_encoding Encoding::UTF_8 YAML.dump self, io end end end PKu]R5%rdoc-6.2.1.1/lib/rdoc/ghost_method.rbnu[# frozen_string_literal: true ## # GhostMethod represents a method referenced only by a comment class RDoc::GhostMethod < RDoc::AnyMethod end PKu]#@@$rdoc-6.2.1.1/lib/rdoc/stats/quiet.rbnu[# frozen_string_literal: true ## # Stats printer that prints nothing class RDoc::Stats::Quiet ## # Creates a new Quiet that will print nothing def initialize num_files @num_files = num_files end ## # Prints a message at the beginning of parsing def begin_adding(*) end ## # Prints when an alias is added def print_alias(*) end ## # Prints when an attribute is added def print_attribute(*) end ## # Prints when a class is added def print_class(*) end ## # Prints when a constant is added def print_constant(*) end ## # Prints when a file is added def print_file(*) end ## # Prints when a method is added def print_method(*) end ## # Prints when a module is added def print_module(*) end ## # Prints when RDoc is done def done_adding(*) end end PKu] &rdoc-6.2.1.1/lib/rdoc/stats/verbose.rbnu[# frozen_string_literal: true ## # Stats printer that prints everything documented, including the documented # status class RDoc::Stats::Verbose < RDoc::Stats::Normal ## # Returns a marker for RDoc::CodeObject +co+ being undocumented def nodoc co " (undocumented)" unless co.documented? end def print_alias as # :nodoc: puts " alias #{as.new_name} #{as.old_name}#{nodoc as}" end def print_attribute attribute # :nodoc: puts " #{attribute.definition} #{attribute.name}#{nodoc attribute}" end def print_class(klass) # :nodoc: puts " class #{klass.full_name}#{nodoc klass}" end def print_constant(constant) # :nodoc: puts " #{constant.name}#{nodoc constant}" end def print_file(files_so_far, file) # :nodoc: super puts end def print_method(method) # :nodoc: puts " #{method.singleton ? '::' : '#'}#{method.name}#{nodoc method}" end def print_module(mod) # :nodoc: puts " module #{mod.full_name}#{nodoc mod}" end end PKu]9)-$00%rdoc-6.2.1.1/lib/rdoc/stats/normal.rbnu[# frozen_string_literal: true begin require 'io/console/size' rescue LoadError # for JRuby require 'io/console' end ## # Stats printer that prints just the files being documented with a progress # bar class RDoc::Stats::Normal < RDoc::Stats::Quiet def begin_adding # :nodoc: puts "Parsing sources..." @last_width = 0 end ## # Prints a file with a progress bar def print_file files_so_far, filename progress_bar = sprintf("%3d%% [%2d/%2d] ", 100 * files_so_far / @num_files, files_so_far, @num_files) if $stdout.tty? # Print a progress bar, but make sure it fits on a single line. Filename # will be truncated if necessary. size = IO.respond_to?(:console_size) ? IO.console_size : IO.console.winsize terminal_width = size[1].to_i.nonzero? || 80 max_filename_size = (terminal_width - progress_bar.size) - 1 if filename.size > max_filename_size then # Turn "some_long_filename.rb" to "...ong_filename.rb" filename = filename[(filename.size - max_filename_size) .. -1] filename[0..2] = "..." end # Clean the line with whitespaces so that leftover output from the # previous line doesn't show up. $stdout.print("\r\e[K") if @last_width && @last_width > 0 @last_width = progress_bar.size + filename.size term = "\r" else term = "\n" end $stdout.print(progress_bar, filename, term) $stdout.flush end def done_adding # :nodoc: puts end end PKu]+<ߐ<<Irdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtmlnu[<% unless klass.sections.length == 1 then %> <% end %> PKu]JiHrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtmlnu[<% unless klass.extends.empty? then %> <% end %> PKu] NNNIrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtmlnu[

    Not Found

    <%= message %>

    PKu] y=rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_head.rhtmlnu[ <%= h @title %> <% if @options.template_stylesheets.flatten.any? then %> <% @options.template_stylesheets.flatten.each do |stylesheet| %> <% end %> <% end %> PKu]C..=rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/class.rhtmlnu[

    <%= klass.type %> <%= klass.full_name %>

    <%= klass.description %>
    <% klass.each_section do |section, constants, attributes| %>
    <% if section.title then %>

    <%= section.title %>

    ↑ top
    <% end %> <% if section.comment then %>
    <%= section.description %>
    <% end %> <% unless constants.empty? then %>

    Constants

    <% constants.each do |const| %>
    <%= const.name %> <% if const.comment then %>
    <%= const.description.strip %> <% else %>
    (Not documented) <% end %> <% end %>
    <% end %> <% unless attributes.empty? then %>

    Attributes

    <% attributes.each do |attrib| %>
    <%= h attrib.name %>[<%= attrib.rw %>]
    <% if attrib.comment then %> <%= attrib.description.strip %> <% else %>

    (Not documented) <% end %>

    <% end %>
    <% end %> <% klass.methods_by_type(section).each do |type, visibilities| next if visibilities.empty? visibilities.each do |visibility, methods| next if methods.empty? %>

    <%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods

    <% methods.each do |method| %>
    "> <% if method.call_seq then %> <% method.call_seq.strip.split("\n").each_with_index do |call_seq, i| %>
    <%= h(call_seq.strip. gsub( /^\w+\./m, '')). gsub(/(.*)[-=]>/, '\1→') %> <% if i == 0 and method.token_stream then %> click to toggle source <% end %>
    <% end %> <% else %>
    <%= h method.name %><%= h method.param_seq %> <% if method.token_stream then %> click to toggle source <% end %>
    <% end %>
    <% if method.comment then %> <%= method.description.strip %> <% else %>

    (Not documented) <% end %> <% if method.calls_super then %>

    Calls superclass method <%= method.superclass_method ? method.formatter.link(method.superclass_method.full_name, method.superclass_method.full_name) : nil %>
    <% end %> <% if method.token_stream then %>
    <%= method.markup_code %>
    <% end %>
    <% unless method.aliases.empty? then %>
    Also aliased as: <%= method.aliases.map do |aka| if aka.parent then # HACK lib/rexml/encodings %{#{h aka.name}} else h aka.name end end.join ", " %>
    <% end %> <% if method.is_alias_for then %> <% end %>
    <% end %>
    <% end end %>
    <% end %>
    PKu]3^^?rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_footer.rhtmlnu[ PKu]13 3 @rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/js/darkfish.jsnu[/** * * Darkfish Page Functions * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $ * * Author: Michael Granger * */ /* Provide console simulation for firebug-less environments */ /* if (!("console" in window) || !("firebug" in console)) { var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; window.console = {}; for (var i = 0; i < names.length; ++i) window.console[names[i]] = function() {}; }; */ function showSource( e ) { var target = e.target; while (!target.classList.contains('method-detail')) { target = target.parentNode; } if (typeof target !== "undefined" && target !== null) { target = target.querySelector('.method-source-code'); } if (typeof target !== "undefined" && target !== null) { target.classList.toggle('active-menu') } }; function hookSourceViews() { document.querySelectorAll('.method-heading').forEach(function (codeObject) { codeObject.addEventListener('click', showSource); }); }; function hookSearch() { var input = document.querySelector('#search-field'); var result = document.querySelector('#search-results'); result.classList.remove("initially-hidden"); var search_section = document.querySelector('#search-section'); search_section.classList.remove("initially-hidden"); var search = new Search(search_data, input, result); search.renderItem = function(result) { var li = document.createElement('li'); var html = ''; // TODO add relative path to

    <%=h exception.class %> at <%=h path %>

    <% if exception.respond_to?(:detailed_message) %>

    <%=h exception.detailed_message(highlight: false) %>

    <% else %>

    <%=h exception.message %>

    <% end %>
    Ruby <% if first = frames.first %> <%=h first.filename %>: in <%=h first.function %>, line <%=h frames.first.lineno %> <% else %> unknown location <% end %>
    Web <%=h req.request_method %> <%=h(req.host + path)%>

    Jump to:

    Traceback (innermost first)

      <% frames.each { |frame| %>
    • <%=h frame.filename %>: in <%=h frame.function %> <% if frame.context_line %>
      <% if frame.pre_context %>
        <% frame.pre_context.each { |line| %>
      1. <%=h line %>
      2. <% } %>
      <% end %>
      1. <%=h frame.context_line %>...
      <% if frame.post_context %>
        <% frame.post_context.each { |line| %>
      1. <%=h line %>
      2. <% } %>
      <% end %>
      <% end %>
    • <% } %>

    Request information

    GET

    <% if req.GET and not req.GET.empty? %> <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> <% } %>
    Variable Value
    <%=h key %>
    <%=h val.inspect %>
    <% else %>

    No GET data.

    <% end %>

    POST

    <% if ((req.POST and not req.POST.empty?) rescue (no_post_data = "Invalid POST data"; nil)) %> <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> <% } %>
    Variable Value
    <%=h key %>
    <%=h val.inspect %>
    <% else %>

    <%= no_post_data || "No POST data" %>.

    <% end %> <% unless req.cookies.empty? %> <% req.cookies.each { |key, val| %> <% } %>
    Variable Value
    <%=h key %>
    <%=h val.inspect %>
    <% else %>

    No cookie data.

    <% end %>

    Rack ENV

    <% env.sort_by { |k, v| k.to_s }.each { |key, val| %> <% } %>
    Variable Value
    <%=h key %>
    <%=h val.inspect %>

    You're seeing this error because you use Rack::ShowExceptions.

    HTML # :startdoc: end end PKu][Jrack-3.0.8/lib/rack/deflater.rbnu[# frozen_string_literal: true require "zlib" require "time" # for Time.httpdate require_relative 'constants' require_relative 'utils' require_relative 'request' require_relative 'body_proxy' module Rack # This middleware enables content encoding of http responses, # usually for purposes of compression. # # Currently supported encodings: # # * gzip # * identity (no transformation) # # This middleware automatically detects when encoding is supported # and allowed. For example no encoding is made when a cache # directive of 'no-transform' is present, when the response status # code is one that doesn't allow an entity body, or when the body # is empty. # # Note that despite the name, Deflater does not support the +deflate+ # encoding. class Deflater # Creates Rack::Deflater middleware. Options: # # :if :: a lambda enabling / disabling deflation based on returned boolean value # (e.g use Rack::Deflater, :if => lambda { |*, body| sum=0; body.each { |i| sum += i.length }; sum > 512 }). # However, be aware that calling `body.each` inside the block will break cases where `body.each` is not idempotent, # such as when it is an +IO+ instance. # :include :: a list of content types that should be compressed. By default, all content types are compressed. # :sync :: determines if the stream is going to be flushed after every chunk. Flushing after every chunk reduces # latency for time-sensitive streaming applications, but hurts compression and throughput. # Defaults to +true+. def initialize(app, options = {}) @app = app @condition = options[:if] @compressible_types = options[:include] @sync = options.fetch(:sync, true) end def call(env) status, headers, body = response = @app.call(env) unless should_deflate?(env, status, headers, body) return response end request = Request.new(env) encoding = Utils.select_best_encoding(%w(gzip identity), request.accept_encoding) # Set the Vary HTTP header. vary = headers["vary"].to_s.split(",").map(&:strip) unless vary.include?("*") || vary.any?{|v| v.downcase == 'accept-encoding'} headers["vary"] = vary.push("Accept-Encoding").join(",") end case encoding when "gzip" headers['content-encoding'] = "gzip" headers.delete(CONTENT_LENGTH) mtime = headers["last-modified"] mtime = Time.httpdate(mtime).to_i if mtime response[2] = GzipStream.new(body, mtime, @sync) response when "identity" response else # when nil # Only possible encoding values here are 'gzip', 'identity', and nil message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." bp = Rack::BodyProxy.new([message]) { body.close if body.respond_to?(:close) } [406, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => message.length.to_s }, bp] end end # Body class used for gzip encoded responses. class GzipStream BUFFER_LENGTH = 128 * 1_024 # Initialize the gzip stream. Arguments: # body :: Response body to compress with gzip # mtime :: The modification time of the body, used to set the # modification time in the gzip header. # sync :: Whether to flush each gzip chunk as soon as it is ready. def initialize(body, mtime, sync) @body = body @mtime = mtime @sync = sync end # Yield gzip compressed strings to the given block. def each(&block) @writer = block gzip = ::Zlib::GzipWriter.new(self) gzip.mtime = @mtime if @mtime # @body.each is equivalent to @body.gets (slow) if @body.is_a? ::File # XXX: Should probably be ::IO while part = @body.read(BUFFER_LENGTH) gzip.write(part) gzip.flush if @sync end else @body.each { |part| # Skip empty strings, as they would result in no output, # and flushing empty parts would raise Zlib::BufError. next if part.empty? gzip.write(part) gzip.flush if @sync } end ensure gzip.finish end # Call the block passed to #each with the gzipped data. def write(data) @writer.call(data) end # Close the original body if possible. def close @body.close if @body.respond_to?(:close) end end private # Whether the body should be compressed. def should_deflate?(env, status, headers, body) # Skip compressing empty entity body responses and responses with # no-transform set. if Utils::STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) || /\bno-transform\b/.match?(headers[CACHE_CONTROL].to_s) || headers['content-encoding']&.!~(/\bidentity\b/) return false end # Skip if @compressible_types are given and does not include request's content type return false if @compressible_types && !(headers.has_key?(CONTENT_TYPE) && @compressible_types.include?(headers[CONTENT_TYPE][/[^;]*/])) # Skip if @condition lambda is given and evaluates to false return false if @condition && !@condition.call(env, status, headers, body) # No point in compressing empty body, also handles usage with # Rack::Sendfile. return false if headers[CONTENT_LENGTH] == '0' true end end end PKu]>==rack-3.0.8/lib/rack/lock.rbnu[# frozen_string_literal: true require_relative 'body_proxy' module Rack # Rack::Lock locks every request inside a mutex, so that every request # will effectively be executed synchronously. class Lock def initialize(app, mutex = Mutex.new) @app, @mutex = app, mutex end def call(env) @mutex.lock begin response = @app.call(env) returned = response << BodyProxy.new(response.pop) { unlock } ensure unlock unless returned end end private def unlock @mutex.unlock end end end PKu]/{{#rack-3.0.8/lib/rack/mock_request.rbnu[# frozen_string_literal: true require 'uri' require 'stringio' require_relative 'constants' require_relative 'mock_response' module Rack # Rack::MockRequest helps testing your Rack application without # actually using HTTP. # # After performing a request on a URL with get/post/put/patch/delete, it # returns a MockResponse with useful helper methods for effective # testing. # # You can pass a hash with additional configuration to the # get/post/put/patch/delete. # :input:: A String or IO-like to be used as rack.input. # :fatal:: Raise a FatalWarning if the app writes to rack.errors. # :lint:: If true, wrap the application in a Rack::Lint. class MockRequest class FatalWarning < RuntimeError end class FatalWarner def puts(warning) raise FatalWarning, warning end def write(warning) raise FatalWarning, warning end def flush end def string "" end end DEFAULT_ENV = { RACK_INPUT => StringIO.new, RACK_ERRORS => StringIO.new, }.freeze def initialize(app) @app = app end # Make a GET request and return a MockResponse. See #request. def get(uri, opts = {}) request(GET, uri, opts) end # Make a POST request and return a MockResponse. See #request. def post(uri, opts = {}) request(POST, uri, opts) end # Make a PUT request and return a MockResponse. See #request. def put(uri, opts = {}) request(PUT, uri, opts) end # Make a PATCH request and return a MockResponse. See #request. def patch(uri, opts = {}) request(PATCH, uri, opts) end # Make a DELETE request and return a MockResponse. See #request. def delete(uri, opts = {}) request(DELETE, uri, opts) end # Make a HEAD request and return a MockResponse. See #request. def head(uri, opts = {}) request(HEAD, uri, opts) end # Make an OPTIONS request and return a MockResponse. See #request. def options(uri, opts = {}) request(OPTIONS, uri, opts) end # Make a request using the given request method for the given # uri to the rack application and return a MockResponse. # Options given are passed to MockRequest.env_for. def request(method = GET, uri = "", opts = {}) env = self.class.env_for(uri, opts.merge(method: method)) if opts[:lint] app = Rack::Lint.new(@app) else app = @app end errors = env[RACK_ERRORS] status, headers, body = app.call(env) MockResponse.new(status, headers, body, errors) ensure body.close if body.respond_to?(:close) end # For historical reasons, we're pinning to RFC 2396. # URI::Parser = URI::RFC2396_Parser def self.parse_uri_rfc2396(uri) @parser ||= URI::Parser.new @parser.parse(uri) end # Return the Rack environment used for a request to +uri+. # All options that are strings are added to the returned environment. # Options: # :fatal :: Whether to raise an exception if request outputs to rack.errors # :input :: The rack.input to set # :http_version :: The SERVER_PROTOCOL to set # :method :: The HTTP request method to use # :params :: The params to use # :script_name :: The SCRIPT_NAME to set def self.env_for(uri = "", opts = {}) uri = parse_uri_rfc2396(uri) uri.path = "/#{uri.path}" unless uri.path[0] == ?/ env = DEFAULT_ENV.dup env[REQUEST_METHOD] = (opts[:method] ? opts[:method].to_s.upcase : GET).b env[SERVER_NAME] = (uri.host || "example.org").b env[SERVER_PORT] = (uri.port ? uri.port.to_s : "80").b env[SERVER_PROTOCOL] = opts[:http_version] || 'HTTP/1.1' env[QUERY_STRING] = (uri.query.to_s).b env[PATH_INFO] = (uri.path).b env[RACK_URL_SCHEME] = (uri.scheme || "http").b env[HTTPS] = (env[RACK_URL_SCHEME] == "https" ? "on" : "off").b env[SCRIPT_NAME] = opts[:script_name] || "" if opts[:fatal] env[RACK_ERRORS] = FatalWarner.new else env[RACK_ERRORS] = StringIO.new end if params = opts[:params] if env[REQUEST_METHOD] == GET params = Utils.parse_nested_query(params) if params.is_a?(String) params.update(Utils.parse_nested_query(env[QUERY_STRING])) env[QUERY_STRING] = Utils.build_nested_query(params) elsif !opts.has_key?(:input) opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" if params.is_a?(Hash) if data = Rack::Multipart.build_multipart(params) opts[:input] = data opts["CONTENT_LENGTH"] ||= data.length.to_s opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Rack::Multipart::MULTIPART_BOUNDARY}" else opts[:input] = Utils.build_nested_query(params) end else opts[:input] = params end end end opts[:input] ||= String.new if String === opts[:input] rack_input = StringIO.new(opts[:input]) else rack_input = opts[:input] end rack_input.set_encoding(Encoding::BINARY) env[RACK_INPUT] = rack_input env["CONTENT_LENGTH"] ||= env[RACK_INPUT].size.to_s if env[RACK_INPUT].respond_to?(:size) opts.each { |field, value| env[field] = value if String === field } env end end end PKu]gG!rack-3.0.8/lib/rack/media_type.rbnu[# frozen_string_literal: true module Rack # Rack::MediaType parse media type and parameters out of content_type string class MediaType SPLIT_PATTERN = %r{\s*[;,]\s*} class << self # The media type (type/subtype) portion of the CONTENT_TYPE header # without any media type parameters. e.g., when CONTENT_TYPE is # "text/plain;charset=utf-8", the media-type is "text/plain". # # For more information on the use of media types in HTTP, see: # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 def type(content_type) return nil unless content_type content_type.split(SPLIT_PATTERN, 2).first.tap(&:downcase!) end # The media type parameters provided in CONTENT_TYPE as a Hash, or # an empty Hash if no CONTENT_TYPE or media-type parameters were # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", # this method responds with the following Hash: # { 'charset' => 'utf-8' } def params(content_type) return {} if content_type.nil? content_type.split(SPLIT_PATTERN)[1..-1].each_with_object({}) do |s, hsh| k, v = s.split('=', 2) hsh[k.tap(&:downcase!)] = strip_doublequotes(v) end end private def strip_doublequotes(str) (str.start_with?('"') && str.end_with?('"')) ? str[1..-2] : str end end end end PKu]*rack-3.0.8/lib/rack/auth/digest/request.rbnu[require_relative '../digest' PKu]&rack-3.0.8/lib/rack/auth/digest/md5.rbnu[require_relative '../digest' PKu](rack-3.0.8/lib/rack/auth/digest/nonce.rbnu[require_relative '../digest' PKu])rack-3.0.8/lib/rack/auth/digest/params.rbnu[require_relative '../digest' PKu],UU,rack-3.0.8/lib/rack/auth/abstract/request.rbnu[# frozen_string_literal: true require_relative '../../request' module Rack module Auth class AbstractRequest def initialize(env) @env = env end def request @request ||= Request.new(@env) end def provided? !authorization_key.nil? && valid? end def valid? !@env[authorization_key].nil? end def parts @parts ||= @env[authorization_key].split(' ', 2) end def scheme @scheme ||= parts.first&.downcase end def params @params ||= parts.last end private AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'] def authorization_key @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) } end end end end PKu]lGRR,rack-3.0.8/lib/rack/auth/abstract/handler.rbnu[# frozen_string_literal: true require_relative '../../constants' module Rack module Auth # Rack::Auth::AbstractHandler implements common authentication functionality. # # +realm+ should be set for all handlers. class AbstractHandler attr_accessor :realm def initialize(app, realm = nil, &authenticator) @app, @realm, @authenticator = app, realm, authenticator end private def unauthorized(www_authenticate = challenge) return [ 401, { CONTENT_TYPE => 'text/plain', CONTENT_LENGTH => '0', 'www-authenticate' => www_authenticate.to_s }, [] ] end def bad_request return [ 400, { CONTENT_TYPE => 'text/plain', CONTENT_LENGTH => '0' }, [] ] end end end end PKu]!rack-3.0.8/lib/rack/auth/basic.rbnu[# frozen_string_literal: true require_relative 'abstract/handler' require_relative 'abstract/request' require 'base64' module Rack module Auth # Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617. # # Initialize with the Rack application that you want protecting, # and a block that checks if a username and password pair are valid. class Basic < AbstractHandler def call(env) auth = Basic::Request.new(env) return unauthorized unless auth.provided? return bad_request unless auth.basic? if valid?(auth) env['REMOTE_USER'] = auth.username return @app.call(env) end unauthorized end private def challenge 'Basic realm="%s"' % realm end def valid?(auth) @authenticator.call(*auth.credentials) end class Request < Auth::AbstractRequest def basic? "basic" == scheme && credentials.length == 2 end def credentials @credentials ||= Base64.decode64(params).split(':', 2) end def username credentials.first end end end end end PKu]  "rack-3.0.8/lib/rack/auth/digest.rbnu[# frozen_string_literal: true require_relative 'abstract/handler' require_relative 'abstract/request' require 'digest/md5' require 'base64' module Rack warn "Rack::Auth::Digest is deprecated and will be removed in Rack 3.1", uplevel: 1 module Auth module Digest # Rack::Auth::Digest::Nonce is the default nonce generator for the # Rack::Auth::Digest::MD5 authentication handler. # # +private_key+ needs to set to a constant string. # # +time_limit+ can be optionally set to an integer (number of seconds), # to limit the validity of the generated nonces. class Nonce class << self attr_accessor :private_key, :time_limit end def self.parse(string) new(*Base64.decode64(string).split(' ', 2)) end def initialize(timestamp = Time.now, given_digest = nil) @timestamp, @given_digest = timestamp.to_i, given_digest end def to_s Base64.encode64("#{@timestamp} #{digest}").strip end def digest ::Digest::MD5.hexdigest("#{@timestamp}:#{self.class.private_key}") end def valid? digest == @given_digest end def stale? !self.class.time_limit.nil? && (Time.now.to_i - @timestamp) > self.class.time_limit end def fresh? !stale? end end class Params < Hash def self.parse(str) Params[*split_header_value(str).map do |param| k, v = param.split('=', 2) [k, dequote(v)] end.flatten] end def self.dequote(str) # From WEBrick::HTTPUtils ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup ret.gsub!(/\\(.)/, "\\1") ret end def self.split_header_value(str) str.scan(/\w+\=(?:"[^\"]+"|[^,]+)/n) end def initialize super() yield self if block_given? end def [](k) super k.to_s end def []=(k, v) super k.to_s, v.to_s end UNQUOTED = ['nc', 'stale'] def to_s map do |k, v| "#{k}=#{(UNQUOTED.include?(k) ? v.to_s : quote(v))}" end.join(', ') end def quote(str) # From WEBrick::HTTPUtils '"' + str.gsub(/[\\\"]/o, "\\\1") + '"' end end class Request < Auth::AbstractRequest def method @env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] || @env[REQUEST_METHOD] end def digest? "digest" == scheme end def correct_uri? request.fullpath == uri end def nonce @nonce ||= Nonce.parse(params['nonce']) end def params @params ||= Params.parse(parts.last) end def respond_to?(sym, *) super or params.has_key? sym.to_s end def method_missing(sym, *args) return super unless params.has_key?(key = sym.to_s) return params[key] if args.size == 0 raise ArgumentError, "wrong number of arguments (#{args.size} for 0)" end end # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of # HTTP Digest Authentication, as per RFC 2617. # # Initialize with the [Rack] application that you want protecting, # and a block that looks up a plaintext password for a given username. # # +opaque+ needs to be set to a constant base64/hexadecimal string. # class MD5 < AbstractHandler attr_accessor :opaque attr_writer :passwords_hashed def initialize(app, realm = nil, opaque = nil, &authenticator) @passwords_hashed = nil if opaque.nil? and realm.respond_to? :values_at realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed end super(app, realm, &authenticator) @opaque = opaque end def passwords_hashed? !!@passwords_hashed end def call(env) auth = Request.new(env) unless auth.provided? return unauthorized end if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth) return bad_request end if valid?(auth) if auth.nonce.stale? return unauthorized(challenge(stale: true)) else env['REMOTE_USER'] = auth.username return @app.call(env) end end unauthorized end private QOP = 'auth' def params(hash = {}) Params.new do |params| params['realm'] = realm params['nonce'] = Nonce.new.to_s params['opaque'] = H(opaque) params['qop'] = QOP hash.each { |k, v| params[k] = v } end end def challenge(hash = {}) "Digest #{params(hash)}" end def valid?(auth) valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) end def valid_qop?(auth) QOP == auth.qop end def valid_opaque?(auth) H(opaque) == auth.opaque end def valid_nonce?(auth) auth.nonce.valid? end def valid_digest?(auth) pw = @authenticator.call(auth.username) pw && Rack::Utils.secure_compare(digest(auth, pw), auth.response) end def md5(data) ::Digest::MD5.hexdigest(data) end alias :H :md5 def KD(secret, data) H "#{secret}:#{data}" end def A1(auth, password) "#{auth.username}:#{auth.realm}:#{password}" end def A2(auth) "#{auth.method}:#{auth.uri}" end def digest(auth, password) password_hash = passwords_hashed? ? password : H(A1(auth, password)) KD password_hash, "#{auth.nonce}:#{auth.nc}:#{auth.cnonce}:#{QOP}:#{H A2(auth)}" end end end end end PKu]>Sf?"?"rack-3.0.8/lib/rack/builder.rbnu[# frozen_string_literal: true require_relative 'urlmap' module Rack # Rack::Builder provides a domain-specific language (DSL) to construct Rack # applications. It is primarily used to parse +config.ru+ files which # instantiate several middleware and a final application which are hosted # by a Rack-compatible web server. # # Example: # # app = Rack::Builder.new do # use Rack::CommonLogger # map "/ok" do # run lambda { |env| [200, {'content-type' => 'text/plain'}, ['OK']] } # end # end # # run app # # Or # # app = Rack::Builder.app do # use Rack::CommonLogger # run lambda { |env| [200, {'content-type' => 'text/plain'}, ['OK']] } # end # # run app # # +use+ adds middleware to the stack, +run+ dispatches to an application. # You can use +map+ to construct a Rack::URLMap in a convenient way. class Builder # https://stackoverflow.com/questions/2223882/whats-the-difference-between-utf-8-and-utf-8-without-bom UTF_8_BOM = '\xef\xbb\xbf' # Parse the given config file to get a Rack application. # # If the config file ends in +.ru+, it is treated as a # rackup file and the contents will be treated as if # specified inside a Rack::Builder block. # # If the config file does not end in +.ru+, it is # required and Rack will use the basename of the file # to guess which constant will be the Rack application to run. # # Examples: # # Rack::Builder.parse_file('config.ru') # # Rack application built using Rack::Builder.new # # Rack::Builder.parse_file('app.rb') # # requires app.rb, which can be anywhere in Ruby's # # load path. After requiring, assumes App constant # # contains Rack application # # Rack::Builder.parse_file('./my_app.rb') # # requires ./my_app.rb, which should be in the # # process's current directory. After requiring, # # assumes MyApp constant contains Rack application def self.parse_file(path) if path.end_with?('.ru') return self.load_file(path) else require path return Object.const_get(::File.basename(path, '.rb').split('_').map(&:capitalize).join('')) end end # Load the given file as a rackup file, treating the # contents as if specified inside a Rack::Builder block. # # Ignores content in the file after +__END__+, so that # use of +__END__+ will not result in a syntax error. # # Example config.ru file: # # $ cat config.ru # # use Rack::ContentLength # require './app.rb' # run App def self.load_file(path) config = ::File.read(path) config.slice!(/\A#{UTF_8_BOM}/) if config.encoding == Encoding::UTF_8 if config[/^#\\(.*)/] fail "Parsing options from the first comment line is no longer supported: #{path}" end config.sub!(/^__END__\n.*\Z/m, '') return new_from_string(config, path) end # Evaluate the given +builder_script+ string in the context of # a Rack::Builder block, returning a Rack application. def self.new_from_string(builder_script, file = "(rackup)") # We want to build a variant of TOPLEVEL_BINDING with self as a Rack::Builder instance. # We cannot use instance_eval(String) as that would resolve constants differently. binding, builder = TOPLEVEL_BINDING.eval('Rack::Builder.new.instance_eval { [binding, self] }') eval builder_script, binding, file return builder.to_app end # Initialize a new Rack::Builder instance. +default_app+ specifies the # default application if +run+ is not called later. If a block # is given, it is evaluated in the context of the instance. def initialize(default_app = nil, &block) @use = [] @map = nil @run = default_app @warmup = nil @freeze_app = false instance_eval(&block) if block_given? end # Create a new Rack::Builder instance and return the Rack application # generated from it. def self.app(default_app = nil, &block) self.new(default_app, &block).to_app end # Specifies middleware to use in a stack. # # class Middleware # def initialize(app) # @app = app # end # # def call(env) # env["rack.some_header"] = "setting an example" # @app.call(env) # end # end # # use Middleware # run lambda { |env| [200, { "content-type" => "text/plain" }, ["OK"]] } # # All requests through to this application will first be processed by the middleware class. # The +call+ method in this example sets an additional environment key which then can be # referenced in the application if required. def use(middleware, *args, &block) if @map mapping, @map = @map, nil @use << proc { |app| generate_map(app, mapping) } end @use << proc { |app| middleware.new(app, *args, &block) } end # :nocov: ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true) # :nocov: # Takes a block or argument that is an object that responds to #call and # returns a Rack response. # # You can use a block: # # run do |env| # [200, { "content-type" => "text/plain" }, ["Hello World!"]] # end # # You can also provide a lambda: # # run lambda { |env| [200, { "content-type" => "text/plain" }, ["OK"]] } # # You can also provide a class instance: # # class Heartbeat # def call(env) # [200, { "content-type" => "text/plain" }, ["OK"]] # end # end # # run Heartbeat.new # def run(app = nil, &block) raise ArgumentError, "Both app and block given!" if app && block_given? @run = app || block end # Takes a lambda or block that is used to warm-up the application. This block is called # before the Rack application is returned by to_app. # # warmup do |app| # client = Rack::MockRequest.new(app) # client.get('/') # end # # use SomeMiddleware # run MyApp def warmup(prc = nil, &block) @warmup = prc || block end # Creates a route within the application. Routes under the mapped path will be sent to # the Rack application specified by run inside the block. Other requests will be sent to the # default application specified by run outside the block. # # class App # def call(env) # [200, {'content-type' => 'text/plain'}, ["Hello World"]] # end # end # # class Heartbeat # def call(env) # [200, { "content-type" => "text/plain" }, ["OK"]] # end # end # # app = Rack::Builder.app do # map '/heartbeat' do # run Heartbeat.new # end # run App.new # end # # run app # # The +use+ method can also be used inside the block to specify middleware to run under a specific path: # # app = Rack::Builder.app do # map '/heartbeat' do # use Middleware # run Heartbeat.new # end # run App.new # end # # This example includes a piece of middleware which will run before +/heartbeat+ requests hit +Heartbeat+. # # Note that providing a +path+ of +/+ will ignore any default application given in a +run+ statement # outside the block. def map(path, &block) @map ||= {} @map[path] = block end # Freeze the app (set using run) and all middleware instances when building the application # in to_app. def freeze_app @freeze_app = true end # Return the Rack application generated by this instance. def to_app app = @map ? generate_map(@run, @map) : @run fail "missing run or map statement" unless app app.freeze if @freeze_app app = @use.reverse.inject(app) { |a, e| e[a].tap { |x| x.freeze if @freeze_app } } @warmup.call(app) if @warmup app end # Call the Rack application generated by this builder instance. Note that # this rebuilds the Rack application and runs the warmup code (if any) # every time it is called, so it should not be used if performance is important. def call(env) to_app.call(env) end private # Generate a URLMap instance by generating new Rack applications for each # map block in this instance. def generate_map(default_app, mapping) mapped = default_app ? { '/' => default_app } : {} mapping.each { |r, b| mapped[r] = self.class.new(default_app, &b).to_app } URLMap.new(mapped) end end end PKu]O~ rack-3.0.8/lib/rack/recursive.rbnu[# frozen_string_literal: true require 'uri' require_relative 'constants' module Rack # Rack::ForwardRequest gets caught by Rack::Recursive and redirects # the current request to the app at +url+. # # raise ForwardRequest.new("/not-found") # class ForwardRequest < Exception attr_reader :url, :env def initialize(url, env = {}) @url = URI(url) @env = env @env[PATH_INFO] = @url.path @env[QUERY_STRING] = @url.query if @url.query @env[HTTP_HOST] = @url.host if @url.host @env[HTTP_PORT] = @url.port if @url.port @env[RACK_URL_SCHEME] = @url.scheme if @url.scheme super "forwarding to #{url}" end end # Rack::Recursive allows applications called down the chain to # include data from other applications (by using # rack['rack.recursive.include'][...] or raise a # ForwardRequest to redirect internally. class Recursive def initialize(app) @app = app end def call(env) dup._call(env) end def _call(env) @script_name = env[SCRIPT_NAME] @app.call(env.merge(RACK_RECURSIVE_INCLUDE => method(:include))) rescue ForwardRequest => req call(env.merge(req.env)) end def include(env, path) unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ || path[@script_name.size].nil?) raise ArgumentError, "can only include below #{@script_name}, not #{path}" end env = env.merge(PATH_INFO => path, SCRIPT_NAME => @script_name, REQUEST_METHOD => GET, "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", RACK_INPUT => StringIO.new("")) @app.call(env) end end end PKu]ӎ cTcTrack-3.0.8/lib/rack/utils.rbnu[# -*- encoding: binary -*- # frozen_string_literal: true require 'uri' require 'fileutils' require 'set' require 'tempfile' require 'time' require_relative 'query_parser' require_relative 'mime' require_relative 'headers' require_relative 'constants' module Rack # Rack::Utils contains a grab-bag of useful methods for writing web # applications adopted from all kinds of Ruby libraries. module Utils ParameterTypeError = QueryParser::ParameterTypeError InvalidParameterError = QueryParser::InvalidParameterError ParamsTooDeepError = QueryParser::ParamsTooDeepError DEFAULT_SEP = QueryParser::DEFAULT_SEP COMMON_SEP = QueryParser::COMMON_SEP KeySpaceConstrainedParams = QueryParser::Params class << self attr_accessor :default_query_parser end # The default amount of nesting to allowed by hash parameters. # This helps prevent a rogue client from triggering a possible stack overflow # when parsing parameters. self.default_query_parser = QueryParser.make_default(32) module_function # URI escapes. (CGI style space to +) def escape(s) URI.encode_www_form_component(s) end # Like URI escaping, but with %20 instead of +. Strictly speaking this is # true URI escaping. def escape_path(s) ::URI::DEFAULT_PARSER.escape s end # Unescapes the **path** component of a URI. See Rack::Utils.unescape for # unescaping query parameters or form components. def unescape_path(s) ::URI::DEFAULT_PARSER.unescape s end # Unescapes a URI escaped string with +encoding+. +encoding+ will be the # target encoding of the string returned, and it defaults to UTF-8 def unescape(s, encoding = Encoding::UTF_8) URI.decode_www_form_component(s, encoding) end class << self attr_accessor :multipart_total_part_limit attr_accessor :multipart_file_limit # multipart_part_limit is the original name of multipart_file_limit, but # the limit only counts parts with filenames. alias multipart_part_limit multipart_file_limit alias multipart_part_limit= multipart_file_limit= end # The maximum number of file parts a request can contain. Accepting too # many parts can lead to the server running out of file handles. # Set to `0` for no limit. self.multipart_file_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || ENV['RACK_MULTIPART_FILE_LIMIT'] || 128).to_i # The maximum total number of parts a request can contain. Accepting too # many can lead to excessive memory use and parsing time. self.multipart_total_part_limit = (ENV['RACK_MULTIPART_TOTAL_PART_LIMIT'] || 4096).to_i def self.param_depth_limit default_query_parser.param_depth_limit end def self.param_depth_limit=(v) self.default_query_parser = self.default_query_parser.new_depth_limit(v) end def self.key_space_limit warn("`Rack::Utils.key_space_limit` is deprecated as this value no longer has an effect. It will be removed in Rack 3.1", uplevel: 1) 65536 end def self.key_space_limit=(v) warn("`Rack::Utils.key_space_limit=` is deprecated and no longer has an effect. It will be removed in Rack 3.1", uplevel: 1) end if defined?(Process::CLOCK_MONOTONIC) def clock_time Process.clock_gettime(Process::CLOCK_MONOTONIC) end else # :nocov: def clock_time Time.now.to_f end # :nocov: end def parse_query(qs, d = nil, &unescaper) Rack::Utils.default_query_parser.parse_query(qs, d, &unescaper) end def parse_nested_query(qs, d = nil) Rack::Utils.default_query_parser.parse_nested_query(qs, d) end def build_query(params) params.map { |k, v| if v.class == Array build_query(v.map { |x| [k, x] }) else v.nil? ? escape(k) : "#{escape(k)}=#{escape(v)}" end }.join("&") end def build_nested_query(value, prefix = nil) case value when Array value.map { |v| build_nested_query(v, "#{prefix}[]") }.join("&") when Hash value.map { |k, v| build_nested_query(v, prefix ? "#{prefix}[#{k}]" : k) }.delete_if(&:empty?).join('&') when nil escape(prefix) else raise ArgumentError, "value must be a Hash" if prefix.nil? "#{escape(prefix)}=#{escape(value)}" end end def q_values(q_value_header) q_value_header.to_s.split(/\s*,\s*/).map do |part| value, parameters = part.split(/\s*;\s*/, 2) quality = 1.0 if parameters && (md = /\Aq=([\d.]+)/.match(parameters)) quality = md[1].to_f end [value, quality] end end def forwarded_values(forwarded_header) return nil unless forwarded_header forwarded_header = forwarded_header.to_s.gsub("\n", ";") forwarded_header.split(/\s*;\s*/).each_with_object({}) do |field, values| field.split(/\s*,\s*/).each do |pair| return nil unless pair =~ /\A\s*(by|for|host|proto)\s*=\s*"?([^"]+)"?\s*\Z/i (values[$1.downcase.to_sym] ||= []) << $2 end end end module_function :forwarded_values # Return best accept value to use, based on the algorithm # in RFC 2616 Section 14. If there are multiple best # matches (same specificity and quality), the value returned # is arbitrary. def best_q_match(q_value_header, available_mimes) values = q_values(q_value_header) matches = values.map do |req_mime, quality| match = available_mimes.find { |am| Rack::Mime.match?(am, req_mime) } next unless match [match, quality] end.compact.sort_by do |match, quality| (match.split('/', 2).count('*') * -10) + quality end.last matches&.first end ESCAPE_HTML = { "&" => "&", "<" => "<", ">" => ">", "'" => "'", '"' => """, "/" => "/" } ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys) # Escape ampersands, brackets and quotes to their HTML/XML entities. def escape_html(string) string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] } end def select_best_encoding(available_encodings, accept_encoding) # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html expanded_accept_encoding = [] accept_encoding.each do |m, q| preference = available_encodings.index(m) || available_encodings.size if m == "*" (available_encodings - accept_encoding.map(&:first)).each do |m2| expanded_accept_encoding << [m2, q, preference] end else expanded_accept_encoding << [m, q, preference] end end encoding_candidates = expanded_accept_encoding .sort_by { |_, q, p| [-q, p] } .map!(&:first) unless encoding_candidates.include?("identity") encoding_candidates.push("identity") end expanded_accept_encoding.each do |m, q| encoding_candidates.delete(m) if q == 0.0 end (encoding_candidates & available_encodings)[0] end # :call-seq: # parse_cookies_header(value) -> hash # # Parse cookies from the provided header +value+ according to RFC6265. The # syntax for cookie headers only supports semicolons. Returns a map of # cookie +key+ to cookie +value+. # # parse_cookies_header('myname=myvalue; max-age=0') # # => {"myname"=>"myvalue", "max-age"=>"0"} # def parse_cookies_header(value) return {} unless value value.split(/; */n).each_with_object({}) do |cookie, cookies| next if cookie.empty? key, value = cookie.split('=', 2) cookies[key] = (unescape(value) rescue value) unless cookies.key?(key) end end def add_cookie_to_header(header, key, value) warn("add_cookie_to_header is deprecated and will be removed in Rack 3.1", uplevel: 1) case header when nil, '' return set_cookie_header(key, value) when String [header, set_cookie_header(key, value)] when Array header + [set_cookie_header(key, value)] else raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}" end end # :call-seq: # parse_cookies(env) -> hash # # Parse cookies from the provided request environment using # parse_cookies_header. Returns a map of cookie +key+ to cookie +value+. # # parse_cookies({'HTTP_COOKIE' => 'myname=myvalue'}) # # => {'myname' => 'myvalue'} # def parse_cookies(env) parse_cookies_header env[HTTP_COOKIE] end # :call-seq: # set_cookie_header(key, value) -> encoded string # # Generate an encoded string using the provided +key+ and +value+ suitable # for the +set-cookie+ header according to RFC6265. The +value+ may be an # instance of either +String+ or +Hash+. # # If the cookie +value+ is an instance of +Hash+, it considers the following # cookie attribute keys: +domain+, +max_age+, +expires+ (must be instance # of +Time+), +secure+, +http_only+, +same_site+ and +value+. For more # details about the interpretation of these fields, consult # [RFC6265 Section 5.2](https://datatracker.ietf.org/doc/html/rfc6265#section-5.2). # # An extra cookie attribute +escape_key+ can be provided to control whether # or not the cookie key is URL encoded. If explicitly set to +false+, the # cookie key name will not be url encoded (escaped). The default is +true+. # # set_cookie_header("myname", "myvalue") # # => "myname=myvalue" # # set_cookie_header("myname", {value: "myvalue", max_age: 10}) # # => "myname=myvalue; max-age=10" # def set_cookie_header(key, value) case value when Hash key = escape(key) unless value[:escape_key] == false domain = "; domain=#{value[:domain]}" if value[:domain] path = "; path=#{value[:path]}" if value[:path] max_age = "; max-age=#{value[:max_age]}" if value[:max_age] expires = "; expires=#{value[:expires].httpdate}" if value[:expires] secure = "; secure" if value[:secure] httponly = "; httponly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only]) same_site = case value[:same_site] when false, nil nil when :none, 'None', :None '; SameSite=None' when :lax, 'Lax', :Lax '; SameSite=Lax' when true, :strict, 'Strict', :Strict '; SameSite=Strict' else raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}" end value = value[:value] else key = escape(key) end value = [value] unless Array === value return "#{key}=#{value.map { |v| escape v }.join('&')}#{domain}" \ "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}" end # :call-seq: # set_cookie_header!(headers, key, value) -> header value # # Append a cookie in the specified headers with the given cookie +key+ and # +value+ using set_cookie_header. # # If the headers already contains a +set-cookie+ key, it will be converted # to an +Array+ if not already, and appended to. def set_cookie_header!(headers, key, value) if header = headers[SET_COOKIE] if header.is_a?(Array) header << set_cookie_header(key, value) else headers[SET_COOKIE] = [header, set_cookie_header(key, value)] end else headers[SET_COOKIE] = set_cookie_header(key, value) end end # :call-seq: # delete_set_cookie_header(key, value = {}) -> encoded string # # Generate an encoded string based on the given +key+ and +value+ using # set_cookie_header for the purpose of causing the specified cookie to be # deleted. The +value+ may be an instance of +Hash+ and can include # attributes as outlined by set_cookie_header. The encoded cookie will have # a +max_age+ of 0 seconds, an +expires+ date in the past and an empty # +value+. When used with the +set-cookie+ header, it will cause the client # to *remove* any matching cookie. # # delete_set_cookie_header("myname") # # => "myname=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT" # def delete_set_cookie_header(key, value = {}) set_cookie_header(key, value.merge(max_age: '0', expires: Time.at(0), value: '')) end def make_delete_cookie_header(header, key, value) warn("make_delete_cookie_header is deprecated and will be removed in Rack 3.1, use delete_set_cookie_header! instead", uplevel: 1) delete_set_cookie_header!(header, key, value) end def delete_cookie_header!(headers, key, value = {}) headers[SET_COOKIE] = delete_set_cookie_header!(headers[SET_COOKIE], key, value) return nil end def add_remove_cookie_to_header(header, key, value = {}) warn("add_remove_cookie_to_header is deprecated and will be removed in Rack 3.1, use delete_set_cookie_header! instead", uplevel: 1) delete_set_cookie_header!(header, key, value) end # :call-seq: # delete_set_cookie_header!(header, key, value = {}) -> header value # # Set an expired cookie in the specified headers with the given cookie # +key+ and +value+ using delete_set_cookie_header. This causes # the client to immediately delete the specified cookie. # # delete_set_cookie_header!(nil, "mycookie") # # => "mycookie=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT" # # If the header is non-nil, it will be modified in place. # # header = [] # delete_set_cookie_header!(header, "mycookie") # # => ["mycookie=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"] # header # # => ["mycookie=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"] # def delete_set_cookie_header!(header, key, value = {}) if header header = Array(header) header << delete_set_cookie_header(key, value) else header = delete_set_cookie_header(key, value) end return header end def rfc2822(time) time.rfc2822 end # Parses the "Range:" header, if present, into an array of Range objects. # Returns nil if the header is missing or syntactically invalid. # Returns an empty array if none of the ranges are satisfiable. def byte_ranges(env, size) get_byte_ranges env['HTTP_RANGE'], size end def get_byte_ranges(http_range, size) # See return nil unless http_range && http_range =~ /bytes=([^;]+)/ ranges = [] $1.split(/,\s*/).each do |range_spec| return nil unless range_spec.include?('-') range = range_spec.split('-') r0, r1 = range[0], range[1] if r0.nil? || r0.empty? return nil if r1.nil? # suffix-byte-range-spec, represents trailing suffix of file r0 = size - r1.to_i r0 = 0 if r0 < 0 r1 = size - 1 else r0 = r0.to_i if r1.nil? r1 = size - 1 else r1 = r1.to_i return nil if r1 < r0 # backwards range is syntactically invalid r1 = size - 1 if r1 >= size end end ranges << (r0..r1) if r0 <= r1 end ranges end # :nocov: if defined?(OpenSSL.fixed_length_secure_compare) # Constant time string comparison. # # NOTE: the values compared should be of fixed length, such as strings # that have already been processed by HMAC. This should not be used # on variable length plaintext strings because it could leak length info # via timing attacks. def secure_compare(a, b) return false unless a.bytesize == b.bytesize OpenSSL.fixed_length_secure_compare(a, b) end # :nocov: else def secure_compare(a, b) return false unless a.bytesize == b.bytesize l = a.unpack("C*") r, i = 0, -1 b.each_byte { |v| r |= v ^ l[i += 1] } r == 0 end end # Context allows the use of a compatible middleware at different points # in a request handling stack. A compatible middleware must define # #context which should take the arguments env and app. The first of which # would be the request environment. The second of which would be the rack # application that the request would be forwarded to. class Context attr_reader :for, :app def initialize(app_f, app_r) raise 'running context does not respond to #context' unless app_f.respond_to? :context @for, @app = app_f, app_r end def call(env) @for.context(env, @app) end def recontext(app) self.class.new(@for, app) end def context(env, app = @app) recontext(app).call(env) end end # A wrapper around Headers # header when set. # # @api private class HeaderHash < Hash # :nodoc: def self.[](headers) warn "Rack::Utils::HeaderHash is deprecated and will be removed in Rack 3.1, switch to Rack::Headers", uplevel: 1 if headers.is_a?(Headers) && !headers.frozen? return headers end new_headers = Headers.new headers.each{|k,v| new_headers[k] = v} new_headers end def self.new(hash = {}) warn "Rack::Utils::HeaderHash is deprecated and will be removed in Rack 3.1, switch to Rack::Headers", uplevel: 1 headers = Headers.new hash.each{|k,v| headers[k] = v} headers end def self.allocate raise TypeError, "cannot allocate HeaderHash" end end # Every standard HTTP code mapped to the appropriate message. # Generated with: # curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \ # ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \ # puts "#{m[1]} => \x27#{m[2].strip}\x27,"' HTTP_STATUS_CODES = { 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 103 => 'Early Hints', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 208 => 'Already Reported', 226 => 'IM Used', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => '(Unused)', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Payload Too Large', 414 => 'URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Range Not Satisfiable', 417 => 'Expectation Failed', 421 => 'Misdirected Request', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Too Early', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable for Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 509 => 'Bandwidth Limit Exceeded', 510 => 'Not Extended', 511 => 'Network Authentication Required' } # Responses with HTTP status codes that should not have an entity body STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])] SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message| [message.downcase.gsub(/\s|-|'/, '_').to_sym, code] }.flatten] def status_code(status) if status.is_a?(Symbol) SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" } else status.to_i end end PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact) def clean_path_info(path_info) parts = path_info.split PATH_SEPS clean = [] parts.each do |part| next if part.empty? || part == '.' part == '..' ? clean.pop : clean << part end clean_path = clean.join(::File::SEPARATOR) clean_path.prepend("/") if parts.empty? || parts.first.empty? clean_path end NULL_BYTE = "\0" def valid_path?(path) path.valid_encoding? && !path.include?(NULL_BYTE) end end end PKu]&44'rack-3.0.8/lib/rack/multipart/parser.rbnu[# frozen_string_literal: true require 'strscan' require_relative '../utils' module Rack module Multipart class MultipartPartLimitError < Errno::EMFILE; end class MultipartTotalPartLimitError < StandardError; end # Use specific error class when parsing multipart request # that ends early. class EmptyContentError < ::EOFError; end # Base class for multipart exceptions that do not subclass from # other exception classes for backwards compatibility. class Error < StandardError; end EOL = "\r\n" MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/ CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/ BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:[^:]*;\s*name=(#{VALUE})/ni MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni # Updated definitions from RFC 2231 ATTRIBUTE_CHAR = %r{[^ \x00-\x1f\x7f)(><@,;:\\"/\[\]?='*%]} ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/ SECTION = /\*[0-9]+/ REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/ REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/ EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/ EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/ EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/ EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/ EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/ EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/ EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/ DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/ RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i class Parser BUFSIZE = 1_048_576 TEXT_PLAIN = "text/plain" TEMPFILE_FACTORY = lambda { |filename, content_type| Tempfile.new(["RackMultipart", ::File.extname(filename.gsub("\0", '%00'))]) } class BoundedIO # :nodoc: def initialize(io, content_length) @io = io @content_length = content_length @cursor = 0 end def read(size, outbuf = nil) return if @cursor >= @content_length left = @content_length - @cursor str = if left < size @io.read left, outbuf else @io.read size, outbuf end if str @cursor += str.bytesize else # Raise an error for mismatching content-length and actual contents raise EOFError, "bad content body" end str end end MultipartInfo = Struct.new :params, :tmp_files EMPTY = MultipartInfo.new(nil, []) def self.parse_boundary(content_type) return unless content_type data = content_type.match(MULTIPART) return unless data data[1] end def self.parse(io, content_length, content_type, tmpfile, bufsize, qp) return EMPTY if 0 == content_length boundary = parse_boundary content_type return EMPTY unless boundary if boundary.length > 70 # RFC 1521 Section 7.2.1 imposes a 70 character maximum for the boundary. # Most clients use no more than 55 characters. raise Error, "multipart boundary size too large (#{boundary.length} characters)" end io = BoundedIO.new(io, content_length) if content_length parser = new(boundary, tmpfile, bufsize, qp) parser.parse(io) parser.result end class Collector class MimePart < Struct.new(:body, :head, :filename, :content_type, :name) def get_data data = body if filename == "" # filename is blank which means no file has been selected return elsif filename body.rewind if body.respond_to?(:rewind) # Take the basename of the upload's original filename. # This handles the full Windows paths given by Internet Explorer # (and perhaps other broken user agents) without affecting # those which give the lone filename. fn = filename.split(/[\/\\]/).last data = { filename: fn, type: content_type, name: name, tempfile: body, head: head } end yield data end end class BufferPart < MimePart def file?; false; end def close; end end class TempfilePart < MimePart def file?; true; end def close; body.close; end end include Enumerable def initialize(tempfile) @tempfile = tempfile @mime_parts = [] @open_files = 0 end def each @mime_parts.each { |part| yield part } end def on_mime_head(mime_index, head, filename, content_type, name) if filename body = @tempfile.call(filename, content_type) body.binmode if body.respond_to?(:binmode) klass = TempfilePart @open_files += 1 else body = String.new klass = BufferPart end @mime_parts[mime_index] = klass.new(body, head, filename, content_type, name) check_part_limits end def on_mime_body(mime_index, content) @mime_parts[mime_index].body << content end def on_mime_finish(mime_index) end private def check_part_limits file_limit = Utils.multipart_file_limit part_limit = Utils.multipart_total_part_limit if file_limit && file_limit > 0 if @open_files >= file_limit @mime_parts.each(&:close) raise MultipartPartLimitError, 'Maximum file multiparts in content reached' end end if part_limit && part_limit > 0 if @mime_parts.size >= part_limit @mime_parts.each(&:close) raise MultipartTotalPartLimitError, 'Maximum total multiparts in content reached' end end end end attr_reader :state def initialize(boundary, tempfile, bufsize, query_parser) @query_parser = query_parser @params = query_parser.make_params @bufsize = bufsize @state = :FAST_FORWARD @mime_index = 0 @collector = Collector.new tempfile @sbuf = StringScanner.new("".dup) @body_regex = /(?:#{EOL}|\A)--#{Regexp.quote(boundary)}(?:#{EOL}|--)/m @rx_max_size = boundary.bytesize + 6 # (\r\n-- at start, either \r\n or -- at finish) @head_regex = /(.*?#{EOL})#{EOL}/m end def parse(io) outbuf = String.new read_data(io, outbuf) loop do status = case @state when :FAST_FORWARD handle_fast_forward when :CONSUME_TOKEN handle_consume_token when :MIME_HEAD handle_mime_head when :MIME_BODY handle_mime_body else # when :DONE return end read_data(io, outbuf) if status == :want_read end end def result @collector.each do |part| part.get_data do |data| tag_multipart_encoding(part.filename, part.content_type, part.name, data) @query_parser.normalize_params(@params, part.name, data) end end MultipartInfo.new @params.to_params_hash, @collector.find_all(&:file?).map(&:body) end private def dequote(str) # From WEBrick::HTTPUtils ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup ret.gsub!(/\\(.)/, "\\1") ret end def read_data(io, outbuf) content = io.read(@bufsize, outbuf) handle_empty_content!(content) @sbuf.concat(content) end # This handles the initial parser state. We read until we find the starting # boundary, then we can transition to the next state. If we find the ending # boundary, this is an invalid multipart upload, but keep scanning for opening # boundary in that case. If no boundary found, we need to keep reading data # and retry. It's highly unlikely the initial read will not consume the # boundary. The client would have to deliberately craft a response # with the opening boundary beyond the buffer size for that to happen. def handle_fast_forward while true case consume_boundary when :BOUNDARY # found opening boundary, transition to next state @state = :MIME_HEAD return when :END_BOUNDARY # invalid multipart upload, but retry for opening boundary else # no boundary found, keep reading data return :want_read end end end def handle_consume_token tok = consume_boundary # break if we're at the end of a buffer, but not if it is the end of a field @state = if tok == :END_BOUNDARY || (@sbuf.eos? && tok != :BOUNDARY) :DONE else :MIME_HEAD end end def handle_mime_head if @sbuf.scan_until(@head_regex) head = @sbuf[1] content_type = head[MULTIPART_CONTENT_TYPE, 1] if name = head[MULTIPART_CONTENT_DISPOSITION, 1] name = dequote(name) else name = head[MULTIPART_CONTENT_ID, 1] end filename = get_filename(head) if name.nil? || name.empty? name = filename || "#{content_type || TEXT_PLAIN}[]".dup end @collector.on_mime_head @mime_index, head, filename, content_type, name @state = :MIME_BODY else :want_read end end def handle_mime_body if (body_with_boundary = @sbuf.check_until(@body_regex)) # check but do not advance the pointer yet body = body_with_boundary.sub(/#{@body_regex}\z/m, '') # remove the boundary from the string @collector.on_mime_body @mime_index, body @sbuf.pos += body.length + 2 # skip \r\n after the content @state = :CONSUME_TOKEN @mime_index += 1 else # Save what we have so far if @rx_max_size < @sbuf.rest_size delta = @sbuf.rest_size - @rx_max_size @collector.on_mime_body @mime_index, @sbuf.peek(delta) @sbuf.pos += delta @sbuf.string = @sbuf.rest end :want_read end end # Scan until the we find the start or end of the boundary. # If we find it, return the appropriate symbol for the start or # end of the boundary. If we don't find the start or end of the # boundary, clear the buffer and return nil. def consume_boundary if read_buffer = @sbuf.scan_until(@body_regex) read_buffer.end_with?(EOL) ? :BOUNDARY : :END_BOUNDARY else @sbuf.terminate nil end end def get_filename(head) filename = nil case head when RFC2183 params = Hash[*head.scan(DISPPARM).flat_map(&:compact)] if filename = params['filename*'] encoding, _, filename = filename.split("'", 3) elsif filename = params['filename'] filename = $1 if filename =~ /^"(.*)"$/ end when BROKEN filename = $1 filename = $1 if filename =~ /^"(.*)"$/ end return unless filename if filename.scan(/%.?.?/).all? { |s| /%[0-9a-fA-F]{2}/.match?(s) } filename = Utils.unescape_path(filename) end filename.scrub! if filename !~ /\\[^\\"]/ filename = filename.gsub(/\\(.)/, '\1') end if encoding filename.force_encoding ::Encoding.find(encoding) end filename end CHARSET = "charset" deprecate_constant :CHARSET def tag_multipart_encoding(filename, content_type, name, body) name = name.to_s encoding = Encoding::UTF_8 name.force_encoding(encoding) return if filename if content_type list = content_type.split(';') type_subtype = list.first type_subtype.strip! if TEXT_PLAIN == type_subtype rest = list.drop 1 rest.each do |param| k, v = param.split('=', 2) k.strip! v.strip! v = v[1..-2] if v.start_with?('"') && v.end_with?('"') if k == "charset" encoding = begin Encoding.find v rescue ArgumentError Encoding::BINARY end end end end end name.force_encoding(encoding) body.force_encoding(encoding) end def handle_empty_content!(content) if content.nil? || content.empty? raise EmptyContentError end end end end end PKu]l *rack-3.0.8/lib/rack/multipart/generator.rbnu[# frozen_string_literal: true require_relative 'uploaded_file' module Rack module Multipart class Generator def initialize(params, first = true) @params, @first = params, first if @first && !@params.is_a?(Hash) raise ArgumentError, "value must be a Hash" end end def dump return nil if @first && !multipart? return flattened_params unless @first flattened_params.map do |name, file| if file.respond_to?(:original_filename) if file.path ::File.open(file.path, 'rb') do |f| f.set_encoding(Encoding::BINARY) content_for_tempfile(f, file, name) end else content_for_tempfile(file, file, name) end else content_for_other(file, name) end end.join << "--#{MULTIPART_BOUNDARY}--\r" end private def multipart? query = lambda { |value| case value when Array value.any?(&query) when Hash value.values.any?(&query) when Rack::Multipart::UploadedFile true end } @params.values.any?(&query) end def flattened_params @flattened_params ||= begin h = Hash.new @params.each do |key, value| k = @first ? key.to_s : "[#{key}]" case value when Array value.map { |v| Multipart.build_multipart(v, false).each { |subkey, subvalue| h["#{k}[]#{subkey}"] = subvalue } } when Hash Multipart.build_multipart(value, false).each { |subkey, subvalue| h[k + subkey] = subvalue } else h[k] = value end end h end end def content_for_tempfile(io, file, name) length = ::File.stat(file.path).size if file.path filename = "; filename=\"#{Utils.escape_path(file.original_filename)}\"" <<-EOF --#{MULTIPART_BOUNDARY}\r content-disposition: form-data; name="#{name}"#{filename}\r content-type: #{file.content_type}\r #{"content-length: #{length}\r\n" if length}\r #{io.read}\r EOF end def content_for_other(file, name) <<-EOF --#{MULTIPART_BOUNDARY}\r content-disposition: form-data; name="#{name}"\r \r #{file}\r EOF end end end end PKu]N$$.rack-3.0.8/lib/rack/multipart/uploaded_file.rbnu[# frozen_string_literal: true require 'tempfile' require 'fileutils' module Rack module Multipart class UploadedFile # The filename, *not* including the path, of the "uploaded" file attr_reader :original_filename # The content type of the "uploaded" file attr_accessor :content_type def initialize(filepath = nil, ct = "text/plain", bin = false, path: filepath, content_type: ct, binary: bin, filename: nil, io: nil) if io @tempfile = io @original_filename = filename else raise "#{path} file does not exist" unless ::File.exist?(path) @original_filename = filename || ::File.basename(path) @tempfile = Tempfile.new([@original_filename, ::File.extname(path)], encoding: Encoding::BINARY) @tempfile.binmode if binary FileUtils.copy_file(path, @tempfile.path) end @content_type = content_type end def path @tempfile.path if @tempfile.respond_to?(:path) end alias_method :local_path, :path def respond_to?(*args) super or @tempfile.respond_to?(*args) end def method_missing(method_name, *args, &block) #:nodoc: @tempfile.__send__(method_name, *args, &block) end end end end PKu] Cx x $rack-3.0.8/lib/rack/common_logger.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' require_relative 'body_proxy' require_relative 'request' module Rack # Rack::CommonLogger forwards every request to the given +app+, and # logs a line in the # {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common] # to the configured logger. class CommonLogger # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common # # lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 - # # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % # # The actual format is slightly different than the above due to the # separation of SCRIPT_NAME and PATH_INFO, and because the elapsed # time in seconds is included at the end. FORMAT = %{%s - %s [%s] "%s %s%s%s %s" %d %s %0.4f\n} # +logger+ can be any object that supports the +write+ or +<<+ methods, # which includes the standard library Logger. These methods are called # with a single string argument, the log message. # If +logger+ is nil, CommonLogger will fall back env['rack.errors']. def initialize(app, logger = nil) @app = app @logger = logger end # Log all requests in common_log format after a response has been # returned. Note that if the app raises an exception, the request # will not be logged, so if exception handling middleware are used, # they should be loaded after this middleware. Additionally, because # the logging happens after the request body has been fully sent, any # exceptions raised during the sending of the response body will # cause the request not to be logged. def call(env) began_at = Utils.clock_time status, headers, body = response = @app.call(env) response[2] = BodyProxy.new(body) { log(env, status, headers, began_at) } response end private # Log the request to the configured logger. def log(env, status, response_headers, began_at) request = Rack::Request.new(env) length = extract_content_length(response_headers) msg = sprintf(FORMAT, request.ip || "-", request.get_header("REMOTE_USER") || "-", Time.now.strftime("%d/%b/%Y:%H:%M:%S %z"), request.request_method, request.script_name, request.path_info, request.query_string.empty? ? "" : "?#{request.query_string}", request.get_header(SERVER_PROTOCOL), status.to_s[0..3], length, Utils.clock_time - began_at) msg.gsub!(/[^[:print:]\n]/) { |c| sprintf("\\x%x", c.ord) } logger = @logger || request.get_header(RACK_ERRORS) # Standard library logger doesn't support write but it supports << which actually # calls to write on the log device without formatting if logger.respond_to?(:write) logger.write(msg) else logger << msg end end # Attempt to determine the content length for the response to # include it in the logged data. def extract_content_length(headers) value = headers[CONTENT_LENGTH] !value || value.to_s == '0' ? '-' : value end end end PKu]YYd  &rack-3.0.8/lib/rack/tempfile_reaper.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'body_proxy' module Rack # Middleware tracks and cleans Tempfiles created throughout a request (i.e. Rack::Multipart) # Ideas/strategy based on posts by Eric Wong and Charles Oliver Nutter # https://groups.google.com/forum/#!searchin/rack-devel/temp/rack-devel/brK8eh-MByw/sw61oJJCGRMJ class TempfileReaper def initialize(app) @app = app end def call(env) env[RACK_TEMPFILES] ||= [] begin _, _, body = response = @app.call(env) rescue Exception env[RACK_TEMPFILES]&.each(&:close!) raise end response[2] = BodyProxy.new(body) do env[RACK_TEMPFILES]&.each(&:close!) end response end end end PKu]Kbx  rack-3.0.8/lib/rack/reloader.rbnu[# frozen_string_literal: true # Copyright (C) 2009-2018 Michael Fellinger # Rack::Reloader is subject to the terms of an MIT-style license. # See MIT-LICENSE or https://opensource.org/licenses/MIT. require 'pathname' module Rack # High performant source reloader # # This class acts as Rack middleware. # # What makes it especially suited for use in a production environment is that # any file will only be checked once and there will only be made one system # call stat(2). # # Please note that this will not reload files in the background, it does so # only when actively called. # # It is performing a check/reload cycle at the start of every request, but # also respects a cool down time, during which nothing will be done. class Reloader def initialize(app, cooldown = 10, backend = Stat) @app = app @cooldown = cooldown @last = (Time.now - cooldown) @cache = {} @mtimes = {} @reload_mutex = Mutex.new extend backend end def call(env) if @cooldown and Time.now > @last + @cooldown if Thread.list.size > 1 @reload_mutex.synchronize{ reload! } else reload! end @last = Time.now end @app.call(env) end def reload!(stderr = $stderr) rotation do |file, mtime| previous_mtime = @mtimes[file] ||= mtime safe_load(file, mtime, stderr) if mtime > previous_mtime end end # A safe Kernel::load, issuing the hooks depending on the results def safe_load(file, mtime, stderr = $stderr) load(file) stderr.puts "#{self.class}: reloaded `#{file}'" file rescue LoadError, SyntaxError => ex stderr.puts ex ensure @mtimes[file] = mtime end module Stat def rotation files = [$0, *$LOADED_FEATURES].uniq paths = ['./', *$LOAD_PATH].uniq files.map{|file| next if /\.(so|bundle)$/.match?(file) # cannot reload compiled files found, stat = figure_path(file, paths) next unless found && stat && mtime = stat.mtime @cache[file] = found yield(found, mtime) }.compact end # Takes a relative or absolute +file+ name, a couple possible +paths+ that # the +file+ might reside in. Returns the full path and File::Stat for the # path. def figure_path(file, paths) found = @cache[file] found = file if !found and Pathname.new(file).absolute? found, stat = safe_stat(found) return found, stat if found paths.find do |possible_path| path = ::File.join(possible_path, file) found, stat = safe_stat(path) return ::File.expand_path(found), stat if found end return false, false end def safe_stat(file) return unless file stat = ::File.stat(file) return file, stat if stat.file? rescue Errno::ENOENT, Errno::ENOTDIR, Errno::ESRCH @cache.delete(file) and false end end end end PKu]&{!{!#rack-3.0.8/lib/rack/query_parser.rbnu[# frozen_string_literal: true require 'uri' module Rack class QueryParser DEFAULT_SEP = /[&] */n COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n } # ParameterTypeError is the error that is raised when incoming structural # parameters (parsed by parse_nested_query) contain conflicting types. class ParameterTypeError < TypeError; end # InvalidParameterError is the error that is raised when incoming structural # parameters (parsed by parse_nested_query) contain invalid format or byte # sequence. class InvalidParameterError < ArgumentError; end # ParamsTooDeepError is the error that is raised when params are recursively # nested over the specified limit. class ParamsTooDeepError < RangeError; end def self.make_default(_key_space_limit=(not_deprecated = true; nil), param_depth_limit) unless not_deprecated warn("`first argument `key_space limit` is deprecated and no longer has an effect. Please call with only one argument, which will be required in a future version of Rack", uplevel: 1) end new Params, param_depth_limit end attr_reader :param_depth_limit def initialize(params_class, _key_space_limit=(not_deprecated = true; nil), param_depth_limit) unless not_deprecated warn("`second argument `key_space limit` is deprecated and no longer has an effect. Please call with only two arguments, which will be required in a future version of Rack", uplevel: 1) end @params_class = params_class @param_depth_limit = param_depth_limit end # Stolen from Mongrel, with some small modifications: # Parses a query string by breaking it up at the '&'. You can also use this # to parse cookies by changing the characters used in the second parameter # (which defaults to '&'). def parse_query(qs, separator = nil, &unescaper) unescaper ||= method(:unescape) params = make_params (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p| next if p.empty? k, v = p.split('=', 2).map!(&unescaper) if cur = params[k] if cur.class == Array params[k] << v else params[k] = [cur, v] end else params[k] = v end end return params.to_h end # parse_nested_query expands a query string into structural types. Supported # types are Arrays, Hashes and basic value types. It is possible to supply # query strings with parameters of conflicting types, in this case a # ParameterTypeError is raised. Users are encouraged to return a 400 in this # case. def parse_nested_query(qs, separator = nil) params = make_params unless qs.nil? || qs.empty? (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p| k, v = p.split('=', 2).map! { |s| unescape(s) } _normalize_params(params, k, v, 0) end end return params.to_h rescue ArgumentError => e raise InvalidParameterError, e.message, e.backtrace end # normalize_params recursively expands parameters into structural types. If # the structural types represented by two different parameter names are in # conflict, a ParameterTypeError is raised. The depth argument is deprecated # and should no longer be used, it is kept for backwards compatibility with # earlier versions of rack. def normalize_params(params, name, v, _depth=nil) _normalize_params(params, name, v, 0) end private def _normalize_params(params, name, v, depth) raise ParamsTooDeepError if depth >= param_depth_limit if !name # nil name, treat same as empty string (required by tests) k = after = '' elsif depth == 0 # Start of parsing, don't treat [] or [ at start of string specially if start = name.index('[', 1) # Start of parameter nesting, use part before brackets as key k = name[0, start] after = name[start, name.length] else # Plain parameter with no nesting k = name after = '' end elsif name.start_with?('[]') # Array nesting k = '[]' after = name[2, name.length] elsif name.start_with?('[') && (start = name.index(']', 1)) # Hash nesting, use the part inside brackets as the key k = name[1, start-1] after = name[start+1, name.length] else # Probably malformed input, nested but not starting with [ # treat full name as key for backwards compatibility. k = name after = '' end return if k.empty? if after == '' if k == '[]' && depth != 0 return [v] else params[k] = v end elsif after == "[" params[name] = v elsif after == "[]" params[k] ||= [] raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) params[k] << v elsif after.start_with?('[]') # Recognize x[][y] (hash inside array) parameters unless after[2] == '[' && after.end_with?(']') && (child_key = after[3, after.length-4]) && !child_key.empty? && !child_key.index('[') && !child_key.index(']') # Handle other nested array parameters child_key = after[2, after.length] end params[k] ||= [] raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key) _normalize_params(params[k].last, child_key, v, depth + 1) else params[k] << _normalize_params(make_params, child_key, v, depth + 1) end else params[k] ||= make_params raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k]) params[k] = _normalize_params(params[k], after, v, depth + 1) end params end def make_params @params_class.new end def new_depth_limit(param_depth_limit) self.class.new @params_class, param_depth_limit end private def params_hash_type?(obj) obj.kind_of?(@params_class) end def params_hash_has_key?(hash, key) return false if /\[\]/.match?(key) key.split(/[\[\]]+/).inject(hash) do |h, part| next h if part == '' return false unless params_hash_type?(h) && h.key?(part) h[part] end true end def unescape(string, encoding = Encoding::UTF_8) URI.decode_www_form_component(string, encoding) end class Params def initialize @size = 0 @params = {} end def [](key) @params[key] end def []=(key, value) @params[key] = value end def key?(key) @params.key?(key) end # Recursively unwraps nested `Params` objects and constructs an object # of the same shape, but using the objects' internal representations # (Ruby hashes) in place of the objects. The result is a hash consisting # purely of Ruby primitives. # # Mutation warning! # # 1. This method mutates the internal representation of the `Params` # objects in order to save object allocations. # # 2. The value you get back is a reference to the internal hash # representation, not a copy. # # 3. Because the `Params` object's internal representation is mutable # through the `#[]=` method, it is not thread safe. The result of # getting the hash representation while another thread is adding a # key to it is non-deterministic. # def to_h @params.each do |key, value| case value when self # Handle circular references gracefully. @params[key] = @params when Params @params[key] = value.to_h when Array value.map! { |v| v.kind_of?(Params) ? v.to_h : v } else # Ignore anything that is not a `Params` object or # a collection that can contain one. end end @params end alias_method :to_params_hash, :to_h end end end PKu]U``" rack-3.0.8/lib/rack/multipart.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' require_relative 'multipart/parser' require_relative 'multipart/generator' module Rack # A multipart form data parser, adapted from IOWA. # # Usually, Rack::Request#POST takes care of calling this. module Multipart MULTIPART_BOUNDARY = "AaB03x" class << self def parse_multipart(env, params = Rack::Utils.default_query_parser) io = env[RACK_INPUT] if content_length = env['CONTENT_LENGTH'] content_length = content_length.to_i end content_type = env['CONTENT_TYPE'] tempfile = env[RACK_MULTIPART_TEMPFILE_FACTORY] || Parser::TEMPFILE_FACTORY bufsize = env[RACK_MULTIPART_BUFFER_SIZE] || Parser::BUFSIZE info = Parser.parse(io, content_length, content_type, tempfile, bufsize, params) env[RACK_TEMPFILES] = info.tmp_files return info.params end def extract_multipart(request, params = Rack::Utils.default_query_parser) parse_multipart(request.env) end def build_multipart(params, first = true) Generator.new(params, first).dump end end end end PKu]|Хrack-3.0.8/lib/rack/files.rbnu[# frozen_string_literal: true require 'time' require_relative 'constants' require_relative 'head' require_relative 'utils' require_relative 'request' require_relative 'mime' module Rack # Rack::Files serves files below the +root+ directory given, according to the # path info of the Rack request. # e.g. when Rack::Files.new("/etc") is used, you can access 'passwd' file # as http://localhost:9292/passwd # # Handlers can detect if bodies are a Rack::Files, and use mechanisms # like sendfile on the +path+. class Files ALLOWED_VERBS = %w[GET HEAD OPTIONS] ALLOW_HEADER = ALLOWED_VERBS.join(', ') MULTIPART_BOUNDARY = 'AaB03x' attr_reader :root def initialize(root, headers = {}, default_mime = 'text/plain') @root = (::File.expand_path(root) if root) @headers = headers @default_mime = default_mime @head = Rack::Head.new(lambda { |env| get env }) end def call(env) # HEAD requests drop the response body, including 4xx error messages. @head.call env end def get(env) request = Rack::Request.new env unless ALLOWED_VERBS.include? request.request_method return fail(405, "Method Not Allowed", { 'allow' => ALLOW_HEADER }) end path_info = Utils.unescape_path request.path_info return fail(400, "Bad Request") unless Utils.valid_path?(path_info) clean_path_info = Utils.clean_path_info(path_info) path = ::File.join(@root, clean_path_info) available = begin ::File.file?(path) && ::File.readable?(path) rescue SystemCallError # Not sure in what conditions this exception can occur, but this # is a safe way to handle such an error. # :nocov: false # :nocov: end if available serving(request, path) else fail(404, "File not found: #{path_info}") end end def serving(request, path) if request.options? return [200, { 'allow' => ALLOW_HEADER, CONTENT_LENGTH => '0' }, []] end last_modified = ::File.mtime(path).httpdate return [304, {}, []] if request.get_header('HTTP_IF_MODIFIED_SINCE') == last_modified headers = { "last-modified" => last_modified } mime_type = mime_type path, @default_mime headers[CONTENT_TYPE] = mime_type if mime_type # Set custom headers headers.merge!(@headers) if @headers status = 200 size = filesize path ranges = Rack::Utils.get_byte_ranges(request.get_header('HTTP_RANGE'), size) if ranges.nil? # No ranges: ranges = [0..size - 1] elsif ranges.empty? # Unsatisfiable. Return error, and file size: response = fail(416, "Byte range unsatisfiable") response[1]["content-range"] = "bytes */#{size}" return response else # Partial content partial_content = true if ranges.size == 1 range = ranges[0] headers["content-range"] = "bytes #{range.begin}-#{range.end}/#{size}" else headers[CONTENT_TYPE] = "multipart/byteranges; boundary=#{MULTIPART_BOUNDARY}" end status = 206 body = BaseIterator.new(path, ranges, mime_type: mime_type, size: size) size = body.bytesize end headers[CONTENT_LENGTH] = size.to_s if request.head? body = [] elsif !partial_content body = Iterator.new(path, ranges, mime_type: mime_type, size: size) end [status, headers, body] end class BaseIterator attr_reader :path, :ranges, :options def initialize(path, ranges, options) @path = path @ranges = ranges @options = options end def each ::File.open(path, "rb") do |file| ranges.each do |range| yield multipart_heading(range) if multipart? each_range_part(file, range) do |part| yield part end end yield "\r\n--#{MULTIPART_BOUNDARY}--\r\n" if multipart? end end def bytesize size = ranges.inject(0) do |sum, range| sum += multipart_heading(range).bytesize if multipart? sum += range.size end size += "\r\n--#{MULTIPART_BOUNDARY}--\r\n".bytesize if multipart? size end def close; end private def multipart? ranges.size > 1 end def multipart_heading(range) <<-EOF \r --#{MULTIPART_BOUNDARY}\r content-type: #{options[:mime_type]}\r content-range: bytes #{range.begin}-#{range.end}/#{options[:size]}\r \r EOF end def each_range_part(file, range) file.seek(range.begin) remaining_len = range.end - range.begin + 1 while remaining_len > 0 part = file.read([8192, remaining_len].min) break unless part remaining_len -= part.length yield part end end end class Iterator < BaseIterator alias :to_path :path end private def fail(status, body, headers = {}) body += "\n" [ status, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => body.size.to_s, "x-cascade" => "pass" }.merge!(headers), [body] ] end # The MIME type for the contents of the file located at @path def mime_type(path, default_mime) Mime.mime_type(::File.extname(path), default_mime) end def filesize(path) # We check via File::size? whether this file provides size info # via stat (e.g. /proc files often don't), otherwise we have to # figure it out by reading the whole file into memory. ::File.size?(path) || ::File.read(path).bytesize end end end PKu]44rack-3.0.8/lib/rack/events.rbnu[# frozen_string_literal: true require_relative 'body_proxy' require_relative 'request' require_relative 'response' module Rack ### This middleware provides hooks to certain places in the request / # response lifecycle. This is so that middleware that don't need to filter # the response data can safely leave it alone and not have to send messages # down the traditional "rack stack". # # The events are: # # * on_start(request, response) # # This event is sent at the start of the request, before the next # middleware in the chain is called. This method is called with a request # object, and a response object. Right now, the response object is always # nil, but in the future it may actually be a real response object. # # * on_commit(request, response) # # The response has been committed. The application has returned, but the # response has not been sent to the webserver yet. This method is always # called with a request object and the response object. The response # object is constructed from the rack triple that the application returned. # Changes may still be made to the response object at this point. # # * on_send(request, response) # # The webserver has started iterating over the response body and presumably # has started sending data over the wire. This method is always called with # a request object and the response object. The response object is # constructed from the rack triple that the application returned. Changes # SHOULD NOT be made to the response object as the webserver has already # started sending data. Any mutations will likely result in an exception. # # * on_finish(request, response) # # The webserver has closed the response, and all data has been written to # the response socket. The request and response object should both be # read-only at this point. The body MAY NOT be available on the response # object as it may have been flushed to the socket. # # * on_error(request, response, error) # # An exception has occurred in the application or an `on_commit` event. # This method will get the request, the response (if available) and the # exception that was raised. # # ## Order # # `on_start` is called on the handlers in the order that they were passed to # the constructor. `on_commit`, on_send`, `on_finish`, and `on_error` are # called in the reverse order. `on_finish` handlers are called inside an # `ensure` block, so they are guaranteed to be called even if something # raises an exception. If something raises an exception in a `on_finish` # method, then nothing is guaranteed. class Events module Abstract def on_start(req, res) end def on_commit(req, res) end def on_send(req, res) end def on_finish(req, res) end def on_error(req, res, e) end end class EventedBodyProxy < Rack::BodyProxy # :nodoc: attr_reader :request, :response def initialize(body, request, response, handlers, &block) super(body, &block) @request = request @response = response @handlers = handlers end def each @handlers.reverse_each { |handler| handler.on_send request, response } super end end class BufferedResponse < Rack::Response::Raw # :nodoc: attr_reader :body def initialize(status, headers, body) super(status, headers) @body = body end def to_a; [status, headers, body]; end end def initialize(app, handlers) @app = app @handlers = handlers end def call(env) request = make_request env on_start request, nil begin status, headers, body = @app.call request.env response = make_response status, headers, body on_commit request, response rescue StandardError => e on_error request, response, e on_finish request, response raise end body = EventedBodyProxy.new(body, request, response, @handlers) do on_finish request, response end [response.status, response.headers, body] end private def on_error(request, response, e) @handlers.reverse_each { |handler| handler.on_error request, response, e } end def on_commit(request, response) @handlers.reverse_each { |handler| handler.on_commit request, response } end def on_start(request, response) @handlers.each { |handler| handler.on_start request, nil } end def on_finish(request, response) @handlers.reverse_each { |handler| handler.on_finish request, response } end def make_request(env) Rack::Request.new env end def make_response(status, headers, body) BufferedResponse.new status, headers, body end end end PKu]A rack-3.0.8/lib/rack/directory.rbnu[# frozen_string_literal: true require 'time' require_relative 'constants' require_relative 'utils' require_relative 'head' require_relative 'mime' require_relative 'files' module Rack # Rack::Directory serves entries below the +root+ given, according to the # path info of the Rack request. If a directory is found, the file's contents # will be presented in an html based index. If a file is found, the env will # be passed to the specified +app+. # # If +app+ is not specified, a Rack::Files of the same +root+ will be used. class Directory DIR_FILE = "%s%s%s%s\n" DIR_PAGE_HEADER = <<-PAGE %s

    %s


    PAGE DIR_PAGE_FOOTER = <<-PAGE
    Name Size Type Last Modified

    PAGE # Body class for directory entries, showing an index page with links # to each file. class DirectoryBody < Struct.new(:root, :path, :files) # Yield strings for each part of the directory entry def each show_path = Utils.escape_html(path.sub(/^#{root}/, '')) yield(DIR_PAGE_HEADER % [ show_path, show_path ]) unless path.chomp('/') == root yield(DIR_FILE % DIR_FILE_escape(files.call('..'))) end Dir.foreach(path) do |basename| next if basename.start_with?('.') next unless f = files.call(basename) yield(DIR_FILE % DIR_FILE_escape(f)) end yield(DIR_PAGE_FOOTER) end private # Escape each element in the array of html strings. def DIR_FILE_escape(htmls) htmls.map { |e| Utils.escape_html(e) } end end # The root of the directory hierarchy. Only requests for files and # directories inside of the root directory are supported. attr_reader :root # Set the root directory and application for serving files. def initialize(root, app = nil) @root = ::File.expand_path(root) @app = app || Files.new(@root) @head = Head.new(method(:get)) end def call(env) # strip body if this is a HEAD call @head.call env end # Internals of request handling. Similar to call but does # not remove body for HEAD requests. def get(env) script_name = env[SCRIPT_NAME] path_info = Utils.unescape_path(env[PATH_INFO]) if client_error_response = check_bad_request(path_info) || check_forbidden(path_info) client_error_response else path = ::File.join(@root, path_info) list_path(env, path, path_info, script_name) end end # Rack response to use for requests with invalid paths, or nil if path is valid. def check_bad_request(path_info) return if Utils.valid_path?(path_info) body = "Bad Request\n" [400, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => body.bytesize.to_s, "x-cascade" => "pass" }, [body]] end # Rack response to use for requests with paths outside the root, or nil if path is inside the root. def check_forbidden(path_info) return unless path_info.include? ".." return if ::File.expand_path(::File.join(@root, path_info)).start_with?(@root) body = "Forbidden\n" [403, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => body.bytesize.to_s, "x-cascade" => "pass" }, [body]] end # Rack response to use for directories under the root. def list_directory(path_info, path, script_name) url_head = (script_name.split('/') + path_info.split('/')).map do |part| Utils.escape_path part end # Globbing not safe as path could contain glob metacharacters body = DirectoryBody.new(@root, path, ->(basename) do stat = stat(::File.join(path, basename)) next unless stat url = ::File.join(*url_head + [Utils.escape_path(basename)]) mtime = stat.mtime.httpdate if stat.directory? type = 'directory' size = '-' url << '/' if basename == '..' basename = 'Parent Directory' else basename << '/' end else type = Mime.mime_type(::File.extname(basename)) size = filesize_format(stat.size) end [ url, basename, size, type, mtime ] end) [ 200, { CONTENT_TYPE => 'text/html; charset=utf-8' }, body ] end # File::Stat for the given path, but return nil for missing/bad entries. def stat(path) ::File.stat(path) rescue Errno::ENOENT, Errno::ELOOP return nil end # Rack response to use for files and directories under the root. # Unreadable and non-file, non-directory entries will get a 404 response. def list_path(env, path, path_info, script_name) if (stat = stat(path)) && stat.readable? return @app.call(env) if stat.file? return list_directory(path_info, path, script_name) if stat.directory? end entity_not_found(path_info) end # Rack response to use for unreadable and non-file, non-directory entries. def entity_not_found(path_info) body = "Entity not found: #{path_info}\n" [404, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => body.bytesize.to_s, "x-cascade" => "pass" }, [body]] end # Stolen from Ramaze FILESIZE_FORMAT = [ ['%.1fT', 1 << 40], ['%.1fG', 1 << 30], ['%.1fM', 1 << 20], ['%.1fK', 1 << 10], ] # Provide human readable file sizes def filesize_format(int) FILESIZE_FORMAT.each do |format, size| return format % (int.to_f / size) if int >= size end "#{int}B" end end end PKu]iZ&&%rack-3.0.8/lib/rack/content_length.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' module Rack # Sets the content-length header on responses that do not specify # a content-length or transfer-encoding header. Note that this # does not fix responses that have an invalid content-length # header specified. class ContentLength include Rack::Utils def initialize(app) @app = app end def call(env) status, headers, body = response = @app.call(env) if !STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) && !headers[CONTENT_LENGTH] && !headers[TRANSFER_ENCODING] && body.respond_to?(:to_ary) response[2] = body = body.to_ary headers[CONTENT_LENGTH] = body.sum(&:bytesize).to_s end response end end end PKu]ɸHOrack-3.0.8/lib/rack/version.rbnu[# frozen_string_literal: true # Copyright (C) 2007-2019 Leah Neukirchen # # Rack is freely distributable under the terms of an MIT-style license. # See MIT-LICENSE or https://opensource.org/licenses/MIT. # The Rack main module, serving as a namespace for all core Rack # modules and classes. # # All modules meant for use in your application are autoloaded here, # so it should be enough just to require 'rack' in your code. module Rack # The Rack protocol version number implemented. VERSION = [1, 3].freeze deprecate_constant :VERSION VERSION_STRING = "1.3".freeze deprecate_constant :VERSION_STRING # The Rack protocol version number implemented. def self.version warn "Rack.version is deprecated and will be removed in Rack 3.1!", uplevel: 1 VERSION end RELEASE = "3.0.8" # Return the Rack release as a dotted string. def self.release RELEASE end end PKu]R  $rack-3.0.8/lib/rack/mock_response.rbnu[# frozen_string_literal: true require 'cgi/cookie' require 'time' require_relative 'response' module Rack # Rack::MockResponse provides useful helpers for testing your apps. # Usually, you don't create the MockResponse on your own, but use # MockRequest. class MockResponse < Rack::Response class << self alias [] new end # Headers attr_reader :original_headers, :cookies # Errors attr_accessor :errors def initialize(status, headers, body, errors = nil) @original_headers = headers if errors @errors = errors.string if errors.respond_to?(:string) else @errors = "" end super(body, status, headers) @cookies = parse_cookies_from_header buffered_body! end def =~(other) body =~ other end def match(other) body.match other end def body return @buffered_body if defined?(@buffered_body) # FIXME: apparently users of MockResponse expect the return value of # MockResponse#body to be a string. However, the real response object # returns the body as a list. # # See spec_showstatus.rb: # # should "not replace existing messages" do # ... # res.body.should == "foo!" # end buffer = @buffered_body = String.new @body.each do |chunk| buffer << chunk end return buffer end def empty? [201, 204, 304].include? status end def cookie(name) cookies.fetch(name, nil) end private def parse_cookies_from_header cookies = Hash.new if headers.has_key? 'set-cookie' set_cookie_header = headers.fetch('set-cookie') Array(set_cookie_header).each do |header_value| header_value.split("\n").each do |cookie| cookie_name, cookie_filling = cookie.split('=', 2) cookie_attributes = identify_cookie_attributes cookie_filling parsed_cookie = CGI::Cookie.new( 'name' => cookie_name.strip, 'value' => cookie_attributes.fetch('value'), 'path' => cookie_attributes.fetch('path', nil), 'domain' => cookie_attributes.fetch('domain', nil), 'expires' => cookie_attributes.fetch('expires', nil), 'secure' => cookie_attributes.fetch('secure', false) ) cookies.store(cookie_name, parsed_cookie) end end end cookies end def identify_cookie_attributes(cookie_filling) cookie_bits = cookie_filling.split(';') cookie_attributes = Hash.new cookie_attributes.store('value', cookie_bits[0].strip) cookie_bits.drop(1).each do |bit| if bit.include? '=' cookie_attribute, attribute_value = bit.split('=', 2) cookie_attributes.store(cookie_attribute.strip.downcase, attribute_value.strip) end if bit.include? 'secure' cookie_attributes.store('secure', true) end end if cookie_attributes.key? 'max-age' cookie_attributes.store('expires', Time.now + cookie_attributes['max-age'].to_i) elsif cookie_attributes.key? 'expires' cookie_attributes.store('expires', Time.httpdate(cookie_attributes['expires'])) end cookie_attributes end end end PKu]Y488rack-3.0.8/lib/rack/sendfile.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' require_relative 'body_proxy' module Rack # = Sendfile # # The Sendfile middleware intercepts responses whose body is being # served from a file and replaces it with a server specific x-sendfile # header. The web server is then responsible for writing the file contents # to the client. This can dramatically reduce the amount of work required # by the Ruby backend and takes advantage of the web server's optimized file # delivery code. # # In order to take advantage of this middleware, the response body must # respond to +to_path+ and the request must include an x-sendfile-type # header. Rack::Files and other components implement +to_path+ so there's # rarely anything you need to do in your application. The x-sendfile-type # header is typically set in your web servers configuration. The following # sections attempt to document # # === Nginx # # Nginx supports the x-accel-redirect header. This is similar to x-sendfile # but requires parts of the filesystem to be mapped into a private URL # hierarchy. # # The following example shows the Nginx configuration required to create # a private "/files/" area, enable x-accel-redirect, and pass the special # x-sendfile-type and x-accel-mapping headers to the backend: # # location ~ /files/(.*) { # internal; # alias /var/www/$1; # } # # location / { # proxy_redirect off; # # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # # proxy_set_header x-sendfile-type x-accel-redirect; # proxy_set_header x-accel-mapping /var/www/=/files/; # # proxy_pass http://127.0.0.1:8080/; # } # # Note that the x-sendfile-type header must be set exactly as shown above. # The x-accel-mapping header should specify the location on the file system, # followed by an equals sign (=), followed name of the private URL pattern # that it maps to. The middleware performs a simple substitution on the # resulting path. # # See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile # # === lighttpd # # Lighttpd has supported some variation of the x-sendfile header for some # time, although only recent version support x-sendfile in a reverse proxy # configuration. # # $HTTP["host"] == "example.com" { # proxy-core.protocol = "http" # proxy-core.balancer = "round-robin" # proxy-core.backends = ( # "127.0.0.1:8000", # "127.0.0.1:8001", # ... # ) # # proxy-core.allow-x-sendfile = "enable" # proxy-core.rewrite-request = ( # "x-sendfile-type" => (".*" => "x-sendfile") # ) # } # # See Also: http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModProxyCore # # === Apache # # x-sendfile is supported under Apache 2.x using a separate module: # # https://tn123.org/mod_xsendfile/ # # Once the module is compiled and installed, you can enable it using # XSendFile config directive: # # RequestHeader Set x-sendfile-type x-sendfile # ProxyPassReverse / http://localhost:8001/ # XSendFile on # # === Mapping parameter # # The third parameter allows for an overriding extension of the # x-accel-mapping header. Mappings should be provided in tuples of internal to # external. The internal values may contain regular expression syntax, they # will be matched with case indifference. class Sendfile def initialize(app, variation = nil, mappings = []) @app = app @variation = variation @mappings = mappings.map do |internal, external| [/^#{internal}/i, external] end end def call(env) _, headers, body = response = @app.call(env) if body.respond_to?(:to_path) case type = variation(env) when /x-accel-redirect/i path = ::File.expand_path(body.to_path) if url = map_accel_path(env, path) headers[CONTENT_LENGTH] = '0' # '?' must be percent-encoded because it is not query string but a part of path headers[type.downcase] = ::Rack::Utils.escape_path(url).gsub('?', '%3F') obody = body response[2] = Rack::BodyProxy.new([]) do obody.close if obody.respond_to?(:close) end else env[RACK_ERRORS].puts "x-accel-mapping header missing" end when /x-sendfile|x-lighttpd-send-file/i path = ::File.expand_path(body.to_path) headers[CONTENT_LENGTH] = '0' headers[type.downcase] = path obody = body response[2] = Rack::BodyProxy.new([]) do obody.close if obody.respond_to?(:close) end when '', nil else env[RACK_ERRORS].puts "Unknown x-sendfile variation: '#{type}'.\n" end end response end private def variation(env) @variation || env['sendfile.type'] || env['HTTP_X_SENDFILE_TYPE'] end def map_accel_path(env, path) if mapping = @mappings.find { |internal, _| internal =~ path } path.sub(*mapping) elsif mapping = env['HTTP_X_ACCEL_MAPPING'] mapping.split(',').map(&:strip).each do |m| internal, external = m.split('=', 2).map(&:strip) new_path = path.sub(/^#{internal}/i, external) return new_path unless path == new_path end path end end end end PKu]dPrack-3.0.8/lib/rack/logger.rbnu[# frozen_string_literal: true require 'logger' require_relative 'constants' module Rack # Sets up rack.logger to write to rack.errors stream class Logger def initialize(app, level = ::Logger::INFO) @app, @level = app, level end def call(env) logger = ::Logger.new(env[RACK_ERRORS]) logger.level = @level env[RACK_LOGGER] = logger @app.call(env) end end end PKu]M}Y??rack-3.0.8/lib/rack/mock.rbnu[# frozen_string_literal: true require_relative 'mock_request' PKu]K?33!rack-3.0.8/lib/rack/body_proxy.rbnu[# frozen_string_literal: true module Rack # Proxy for response bodies allowing calling a block when # the response body is closed (after the response has been fully # sent to the client). class BodyProxy # Set the response body to wrap, and the block to call when the # response has been fully sent. def initialize(body, &block) @body = body @block = block @closed = false end # Return whether the wrapped body responds to the method. def respond_to_missing?(method_name, include_all = false) super or @body.respond_to?(method_name, include_all) end # If not already closed, close the wrapped body and # then call the block the proxy was initialized with. def close return if @closed @closed = true begin @body.close if @body.respond_to?(:close) ensure @block.call end end # Whether the proxy is closed. The proxy starts as not closed, # and becomes closed on the first call to close. def closed? @closed end # Delegate missing methods to the wrapped body. def method_missing(method_name, *args, &block) @body.__send__(method_name, *args, &block) end # :nocov: ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true) # :nocov: end end PKu]ю rack-3.0.8/lib/rack/static.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'files' require_relative 'mime' module Rack # The Rack::Static middleware intercepts requests for static files # (javascript files, images, stylesheets, etc) based on the url prefixes or # route mappings passed in the options, and serves them using a Rack::Files # object. This allows a Rack stack to serve both static and dynamic content. # # Examples: # # Serve all requests beginning with /media from the "media" folder located # in the current directory (ie media/*): # # use Rack::Static, :urls => ["/media"] # # Same as previous, but instead of returning 404 for missing files under # /media, call the next middleware: # # use Rack::Static, :urls => ["/media"], :cascade => true # # Serve all requests beginning with /css or /images from the folder "public" # in the current directory (ie public/css/* and public/images/*): # # use Rack::Static, :urls => ["/css", "/images"], :root => "public" # # Serve all requests to / with "index.html" from the folder "public" in the # current directory (ie public/index.html): # # use Rack::Static, :urls => {"/" => 'index.html'}, :root => 'public' # # Serve all requests normally from the folder "public" in the current # directory but uses index.html as default route for "/" # # use Rack::Static, :urls => [""], :root => 'public', :index => # 'index.html' # # Set custom HTTP Headers for based on rules: # # use Rack::Static, :root => 'public', # :header_rules => [ # [rule, {header_field => content, header_field => content}], # [rule, {header_field => content}] # ] # # Rules for selecting files: # # 1) All files # Provide the :all symbol # :all => Matches every file # # 2) Folders # Provide the folder path as a string # '/folder' or '/folder/subfolder' => Matches files in a certain folder # # 3) File Extensions # Provide the file extensions as an array # ['css', 'js'] or %w(css js) => Matches files ending in .css or .js # # 4) Regular Expressions / Regexp # Provide a regular expression # %r{\.(?:css|js)\z} => Matches files ending in .css or .js # /\.(?:eot|ttf|otf|woff2|woff|svg)\z/ => Matches files ending in # the most common web font formats (.eot, .ttf, .otf, .woff2, .woff, .svg) # Note: This Regexp is available as a shortcut, using the :fonts rule # # 5) Font Shortcut # Provide the :fonts symbol # :fonts => Uses the Regexp rule stated right above to match all common web font endings # # Rule Ordering: # Rules are applied in the order that they are provided. # List rather general rules above special ones. # # Complete example use case including HTTP header rules: # # use Rack::Static, :root => 'public', # :header_rules => [ # # Cache all static files in public caches (e.g. Rack::Cache) # # as well as in the browser # [:all, {'cache-control' => 'public, max-age=31536000'}], # # # Provide web fonts with cross-origin access-control-headers # # Firefox requires this when serving assets using a Content Delivery Network # [:fonts, {'access-control-allow-origin' => '*'}] # ] # class Static def initialize(app, options = {}) @app = app @urls = options[:urls] || ["/favicon.ico"] @index = options[:index] @gzip = options[:gzip] @cascade = options[:cascade] root = options[:root] || Dir.pwd # HTTP Headers @header_rules = options[:header_rules] || [] # Allow for legacy :cache_control option while prioritizing global header_rules setting @header_rules.unshift([:all, { CACHE_CONTROL => options[:cache_control] }]) if options[:cache_control] @file_server = Rack::Files.new(root) end def add_index_root?(path) @index && route_file(path) && path.end_with?('/') end def overwrite_file_path(path) @urls.kind_of?(Hash) && @urls.key?(path) || add_index_root?(path) end def route_file(path) @urls.kind_of?(Array) && @urls.any? { |url| path.index(url) == 0 } end def can_serve(path) route_file(path) || overwrite_file_path(path) end def call(env) path = env[PATH_INFO] if can_serve(path) if overwrite_file_path(path) env[PATH_INFO] = (add_index_root?(path) ? path + @index : @urls[path]) elsif @gzip && env['HTTP_ACCEPT_ENCODING'] && /\bgzip\b/.match?(env['HTTP_ACCEPT_ENCODING']) path = env[PATH_INFO] env[PATH_INFO] += '.gz' response = @file_server.call(env) env[PATH_INFO] = path if response[0] == 404 response = nil elsif response[0] == 304 # Do nothing, leave headers as is else response[1][CONTENT_TYPE] = Mime.mime_type(::File.extname(path), 'text/plain') response[1]['content-encoding'] = 'gzip' end end path = env[PATH_INFO] response ||= @file_server.call(env) if @cascade && response[0] == 404 return @app.call(env) end headers = response[1] applicable_rules(path).each do |rule, new_headers| new_headers.each { |field, content| headers[field] = content } end response else @app.call(env) end end # Convert HTTP header rules to HTTP headers def applicable_rules(path) @header_rules.find_all do |rule, new_headers| case rule when :all true when :fonts /\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path) when String path = ::Rack::Utils.unescape(path) path.start_with?(rule) || path.start_with?('/' + rule) when Array /\.(#{rule.join('|')})\z/.match?(path) when Regexp rule.match?(path) else false end end end end end PKu]VMVwwrack-3.0.8/lib/rack/etag.rbnu[# frozen_string_literal: true require 'digest/sha2' require_relative 'constants' require_relative 'utils' module Rack # Automatically sets the etag header on all String bodies. # # The etag header is skipped if etag or last-modified headers are sent or if # a sendfile body (body.responds_to :to_path) is given (since such cases # should be handled by apache/nginx). # # On initialization, you can pass two parameters: a cache-control directive # used when etag is absent and a directive when it is present. The first # defaults to nil, while the second defaults to "max-age=0, private, must-revalidate" class ETag ETAG_STRING = Rack::ETAG DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate" def initialize(app, no_cache_control = nil, cache_control = DEFAULT_CACHE_CONTROL) @app = app @cache_control = cache_control @no_cache_control = no_cache_control end def call(env) status, headers, body = response = @app.call(env) if etag_status?(status) && body.respond_to?(:to_ary) && !skip_caching?(headers) body = body.to_ary digest = digest_body(body) headers[ETAG_STRING] = %(W/"#{digest}") if digest end unless headers[CACHE_CONTROL] if digest headers[CACHE_CONTROL] = @cache_control if @cache_control else headers[CACHE_CONTROL] = @no_cache_control if @no_cache_control end end response end private def etag_status?(status) status == 200 || status == 201 end def skip_caching?(headers) headers.key?(ETAG_STRING) || headers.key?('last-modified') end def digest_body(body) digest = nil body.each do |part| (digest ||= Digest::SHA256.new) << part unless part.empty? end digest && digest.hexdigest.byteslice(0,32) end end end PKu];~ ~ 'rack-3.0.8/lib/rack/rewindable_input.rbnu[# -*- encoding: binary -*- # frozen_string_literal: true require 'tempfile' require_relative 'constants' module Rack # Class which can make any IO object rewindable, including non-rewindable ones. It does # this by buffering the data into a tempfile, which is rewindable. # # Don't forget to call #close when you're done. This frees up temporary resources that # RewindableInput uses, though it does *not* close the original IO object. class RewindableInput # Makes rack.input rewindable, for compatibility with applications and middleware # designed for earlier versions of Rack (where rack.input was required to be # rewindable). class Middleware def initialize(app) @app = app end def call(env) env[RACK_INPUT] = RewindableInput.new(env[RACK_INPUT]) @app.call(env) end end def initialize(io) @io = io @rewindable_io = nil @unlinked = false end def gets make_rewindable unless @rewindable_io @rewindable_io.gets end def read(*args) make_rewindable unless @rewindable_io @rewindable_io.read(*args) end def each(&block) make_rewindable unless @rewindable_io @rewindable_io.each(&block) end def rewind make_rewindable unless @rewindable_io @rewindable_io.rewind end def size make_rewindable unless @rewindable_io @rewindable_io.size end # Closes this RewindableInput object without closing the originally # wrapped IO object. Cleans up any temporary resources that this RewindableInput # has created. # # This method may be called multiple times. It does nothing on subsequent calls. def close if @rewindable_io if @unlinked @rewindable_io.close else @rewindable_io.close! end @rewindable_io = nil end end private def make_rewindable # Buffer all data into a tempfile. Since this tempfile is private to this # RewindableInput object, we chmod it so that nobody else can read or write # it. On POSIX filesystems we also unlink the file so that it doesn't # even have a file entry on the filesystem anymore, though we can still # access it because we have the file handle open. @rewindable_io = Tempfile.new('RackRewindableInput') @rewindable_io.chmod(0000) @rewindable_io.set_encoding(Encoding::BINARY) @rewindable_io.binmode # :nocov: if filesystem_has_posix_semantics? raise 'Unlink failed. IO closed.' if @rewindable_io.closed? @unlinked = true end # :nocov: buffer = "".dup while @io.read(1024 * 4, buffer) entire_buffer_written_out = false while !entire_buffer_written_out written = @rewindable_io.write(buffer) entire_buffer_written_out = written == buffer.bytesize if !entire_buffer_written_out buffer.slice!(0 .. written - 1) end end end @rewindable_io.rewind end def filesystem_has_posix_semantics? RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ end end end PKu]$**rack-3.0.8/lib/rack/response.rbnu[# frozen_string_literal: true require 'time' require_relative 'constants' require_relative 'utils' require_relative 'media_type' require_relative 'headers' module Rack # Rack::Response provides a convenient interface to create a Rack # response. # # It allows setting of headers and cookies, and provides useful # defaults (an OK response with empty headers and body). # # You can use Response#write to iteratively generate your response, # but note that this is buffered by Rack::Response until you call # +finish+. +finish+ however can take a block inside which calls to # +write+ are synchronous with the Rack response. # # Your application's +call+ should end returning Response#finish. class Response def self.[](status, headers, body) self.new(body, status, headers) end CHUNKED = 'chunked' STATUS_WITH_NO_ENTITY_BODY = Utils::STATUS_WITH_NO_ENTITY_BODY attr_accessor :length, :status, :body attr_reader :headers # Deprecated, use headers instead. def header warn 'Rack::Response#header is deprecated and will be removed in Rack 3.1', uplevel: 1 headers end # Initialize the response object with the specified +body+, +status+ # and +headers+. # # If the +body+ is +nil+, construct an empty response object with internal # buffering. # # If the +body+ responds to +to_str+, assume it's a string-like object and # construct a buffered response object containing using that string as the # initial contents of the buffer. # # Otherwise it is expected +body+ conforms to the normal requirements of a # Rack response body, typically implementing one of +each+ (enumerable # body) or +call+ (streaming body). # # The +status+ defaults to +200+ which is the "OK" HTTP status code. You # can provide any other valid status code. # # The +headers+ must be a +Hash+ of key-value header pairs which conform to # the Rack specification for response headers. The key must be a +String+ # instance and the value can be either a +String+ or +Array+ instance. def initialize(body = nil, status = 200, headers = {}) @status = status.to_i unless headers.is_a?(Hash) warn "Providing non-hash headers to Rack::Response is deprecated and will be removed in Rack 3.1", uplevel: 1 end @headers = Headers.new # Convert headers input to a plain hash with lowercase keys. headers.each do |k, v| @headers[k] = v end @writer = self.method(:append) @block = nil # Keep track of whether we have expanded the user supplied body. if body.nil? @body = [] @buffered = true @length = 0 elsif body.respond_to?(:to_str) @body = [body] @buffered = true @length = body.to_str.bytesize else @body = body @buffered = nil # undetermined as of yet. @length = 0 end yield self if block_given? end def redirect(target, status = 302) self.status = status self.location = target end def chunked? CHUNKED == get_header(TRANSFER_ENCODING) end def no_entity_body? # The response body is an enumerable body and it is not allowed to have an entity body. @body.respond_to?(:each) && STATUS_WITH_NO_ENTITY_BODY[@status] end # Generate a response array consistent with the requirements of the SPEC. # @return [Array] a 3-tuple suitable of `[status, headers, body]` # which is suitable to be returned from the middleware `#call(env)` method. def finish(&block) if no_entity_body? delete_header CONTENT_TYPE delete_header CONTENT_LENGTH close return [@status, @headers, []] else if block_given? @block = block return [@status, @headers, self] else return [@status, @headers, @body] end end end alias to_a finish # For *response def each(&callback) @body.each(&callback) @buffered = true if @block @writer = callback @block.call(self) end end # Append to body and update content-length. # # NOTE: Do not mix #write and direct #body access! # def write(chunk) buffered_body! @writer.call(chunk.to_s) end def close @body.close if @body.respond_to?(:close) end def empty? @block == nil && @body.empty? end def has_header?(key) raise ArgumentError unless key.is_a?(String) @headers.key?(key) end def get_header(key) raise ArgumentError unless key.is_a?(String) @headers[key] end def set_header(key, value) raise ArgumentError unless key.is_a?(String) @headers[key] = value end def delete_header(key) raise ArgumentError unless key.is_a?(String) @headers.delete key end alias :[] :get_header alias :[]= :set_header module Helpers def invalid?; status < 100 || status >= 600; end def informational?; status >= 100 && status < 200; end def successful?; status >= 200 && status < 300; end def redirection?; status >= 300 && status < 400; end def client_error?; status >= 400 && status < 500; end def server_error?; status >= 500 && status < 600; end def ok?; status == 200; end def created?; status == 201; end def accepted?; status == 202; end def no_content?; status == 204; end def moved_permanently?; status == 301; end def bad_request?; status == 400; end def unauthorized?; status == 401; end def forbidden?; status == 403; end def not_found?; status == 404; end def method_not_allowed?; status == 405; end def not_acceptable?; status == 406; end def request_timeout?; status == 408; end def precondition_failed?; status == 412; end def unprocessable?; status == 422; end def redirect?; [301, 302, 303, 307, 308].include? status; end def include?(header) has_header?(header) end # Add a header that may have multiple values. # # Example: # response.add_header 'vary', 'accept-encoding' # response.add_header 'vary', 'cookie' # # assert_equal 'accept-encoding,cookie', response.get_header('vary') # # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 def add_header(key, value) raise ArgumentError unless key.is_a?(String) if value.nil? return get_header(key) end value = value.to_s if header = get_header(key) if header.is_a?(Array) header << value else set_header(key, [header, value]) end else set_header(key, value) end end # Get the content type of the response. def content_type get_header CONTENT_TYPE end # Set the content type of the response. def content_type=(content_type) set_header CONTENT_TYPE, content_type end def media_type MediaType.type(content_type) end def media_type_params MediaType.params(content_type) end def content_length cl = get_header CONTENT_LENGTH cl ? cl.to_i : cl end def location get_header "location" end def location=(location) set_header "location", location end def set_cookie(key, value) add_header SET_COOKIE, Utils.set_cookie_header(key, value) end def delete_cookie(key, value = {}) set_header(SET_COOKIE, Utils.delete_set_cookie_header!( get_header(SET_COOKIE), key, value ) ) end def set_cookie_header get_header SET_COOKIE end def set_cookie_header=(value) set_header SET_COOKIE, value end def cache_control get_header CACHE_CONTROL end def cache_control=(value) set_header CACHE_CONTROL, value end # Specifies that the content shouldn't be cached. Overrides `cache!` if already called. def do_not_cache! set_header CACHE_CONTROL, "no-cache, must-revalidate" set_header EXPIRES, Time.now.httpdate end # Specify that the content should be cached. # @param duration [Integer] The number of seconds until the cache expires. # @option directive [String] The cache control directive, one of "public", "private", "no-cache" or "no-store". def cache!(duration = 3600, directive: "public") unless headers[CACHE_CONTROL] =~ /no-cache/ set_header CACHE_CONTROL, "#{directive}, max-age=#{duration}" set_header EXPIRES, (Time.now + duration).httpdate end end def etag get_header ETAG end def etag=(value) set_header ETAG, value end protected def buffered_body! if @buffered.nil? if @body.is_a?(Array) # The user supplied body was an array: @body = @body.compact @body.each do |part| @length += part.to_s.bytesize end elsif @body.respond_to?(:each) # Turn the user supplied body into a buffered array: body = @body @body = Array.new body.each do |part| @writer.call(part.to_s) end body.close if body.respond_to?(:close) @buffered = true else @buffered = false end end return @buffered end def append(chunk) @body << chunk unless chunked? @length += chunk.bytesize set_header(CONTENT_LENGTH, @length.to_s) end return chunk end end include Helpers class Raw include Helpers attr_reader :headers attr_accessor :status def initialize(status, headers) @status = status @headers = headers end def has_header?(key) headers.key?(key) end def get_header(key) headers[key] end def set_header(key, value) headers[key] = value end def delete_header(key) headers.delete(key) end end end end PKu]3&rack-3.0.8/lib/rack/method_override.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'request' require_relative 'utils' module Rack class MethodOverride HTTP_METHODS = %w[GET HEAD PUT POST DELETE OPTIONS PATCH LINK UNLINK] METHOD_OVERRIDE_PARAM_KEY = "_method" HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE" ALLOWED_METHODS = %w[POST] def initialize(app) @app = app end def call(env) if allowed_methods.include?(env[REQUEST_METHOD]) method = method_override(env) if HTTP_METHODS.include?(method) env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] = env[REQUEST_METHOD] env[REQUEST_METHOD] = method end end @app.call(env) end def method_override(env) req = Request.new(env) method = method_override_param(req) || env[HTTP_METHOD_OVERRIDE_HEADER] begin method.to_s.upcase rescue ArgumentError env[RACK_ERRORS].puts "Invalid string for method" end end private def allowed_methods ALLOWED_METHODS end def method_override_param(req) req.POST[METHOD_OVERRIDE_PARAM_KEY] if req.form_data? || req.parseable_data? rescue Utils::InvalidParameterError, Utils::ParameterTypeError, QueryParser::ParamsTooDeepError req.get_header(RACK_ERRORS).puts "Invalid or incomplete POST params" rescue EOFError req.get_header(RACK_ERRORS).puts "Bad request content body" end end end PKu]@j rack-3.0.8/lib/rack/constants.rbnu[# frozen_string_literal: true module Rack # Request env keys HTTP_HOST = 'HTTP_HOST' HTTP_PORT = 'HTTP_PORT' HTTPS = 'HTTPS' PATH_INFO = 'PATH_INFO' REQUEST_METHOD = 'REQUEST_METHOD' REQUEST_PATH = 'REQUEST_PATH' SCRIPT_NAME = 'SCRIPT_NAME' QUERY_STRING = 'QUERY_STRING' SERVER_PROTOCOL = 'SERVER_PROTOCOL' SERVER_NAME = 'SERVER_NAME' SERVER_PORT = 'SERVER_PORT' HTTP_COOKIE = 'HTTP_COOKIE' # Response Header Keys CACHE_CONTROL = 'cache-control' CONTENT_LENGTH = 'content-length' CONTENT_TYPE = 'content-type' ETAG = 'etag' EXPIRES = 'expires' SET_COOKIE = 'set-cookie' TRANSFER_ENCODING = 'transfer-encoding' # HTTP method verbs GET = 'GET' POST = 'POST' PUT = 'PUT' PATCH = 'PATCH' DELETE = 'DELETE' HEAD = 'HEAD' OPTIONS = 'OPTIONS' LINK = 'LINK' UNLINK = 'UNLINK' TRACE = 'TRACE' # Rack environment variables RACK_VERSION = 'rack.version' RACK_TEMPFILES = 'rack.tempfiles' RACK_ERRORS = 'rack.errors' RACK_LOGGER = 'rack.logger' RACK_INPUT = 'rack.input' RACK_SESSION = 'rack.session' RACK_SESSION_OPTIONS = 'rack.session.options' RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail' RACK_URL_SCHEME = 'rack.url_scheme' RACK_HIJACK = 'rack.hijack' RACK_IS_HIJACK = 'rack.hijack?' RACK_RECURSIVE_INCLUDE = 'rack.recursive.include' RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size' RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory' RACK_RESPONSE_FINISHED = 'rack.response_finished' RACK_REQUEST_FORM_INPUT = 'rack.request.form_input' RACK_REQUEST_FORM_HASH = 'rack.request.form_hash' RACK_REQUEST_FORM_VARS = 'rack.request.form_vars' RACK_REQUEST_FORM_ERROR = 'rack.request.form_error' RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash' RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string' RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash' RACK_REQUEST_QUERY_STRING = 'rack.request.query_string' RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method' end PKu]Oi rack-3.0.8/lib/rack/headers.rbnu[module Rack # Rack::Headers is a Hash subclass that downcases all keys. It's designed # to be used by rack applications that don't implement the Rack 3 SPEC # (by using non-lowercase response header keys), automatically handling # the downcasing of keys. class Headers < Hash def self.[](*items) if items.length % 2 != 0 if items.length == 1 && items.first.is_a?(Hash) new.merge!(items.first) else raise ArgumentError, "odd number of arguments for Rack::Headers" end else hash = new loop do break if items.length == 0 key = items.shift value = items.shift hash[key] = value end hash end end def [](key) super(downcase_key(key)) end def []=(key, value) super(key.downcase.freeze, value) end alias store []= def assoc(key) super(downcase_key(key)) end def compare_by_identity raise TypeError, "Rack::Headers cannot compare by identity, use regular Hash" end def delete(key) super(downcase_key(key)) end def dig(key, *a) super(downcase_key(key), *a) end def fetch(key, *default, &block) key = downcase_key(key) super end def fetch_values(*a) super(*a.map!{|key| downcase_key(key)}) end def has_key?(key) super(downcase_key(key)) end alias include? has_key? alias key? has_key? alias member? has_key? def invert hash = self.class.new each{|key, value| hash[value] = key} hash end def merge(hash, &block) dup.merge!(hash, &block) end def reject(&block) hash = dup hash.reject!(&block) hash end def replace(hash) clear update(hash) end def select(&block) hash = dup hash.select!(&block) hash end def to_proc lambda{|x| self[x]} end def transform_values(&block) dup.transform_values!(&block) end def update(hash, &block) hash.each do |key, value| self[key] = if block_given? && include?(key) block.call(key, self[key], value) else value end end self end alias merge! update def values_at(*keys) keys.map{|key| self[key]} end # :nocov: if RUBY_VERSION >= '2.5' # :nocov: def slice(*a) h = self.class.new a.each{|k| h[k] = self[k] if has_key?(k)} h end def transform_keys(&block) dup.transform_keys!(&block) end def transform_keys! hash = self.class.new each do |k, v| hash[yield k] = v end replace(hash) end end # :nocov: if RUBY_VERSION >= '3.0' # :nocov: def except(*a) super(*a.map!{|key| downcase_key(key)}) end end private def downcase_key(key) key.is_a?(String) ? key.downcase : key end end end PKu]ѝo  rack-3.0.8/lib/rack/head.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'body_proxy' module Rack # Rack::Head returns an empty body for all HEAD requests. It leaves # all other requests unchanged. class Head def initialize(app) @app = app end def call(env) _, _, body = response = @app.call(env) if env[REQUEST_METHOD] == HEAD response[2] = Rack::BodyProxy.new([]) do body.close if body.respond_to? :close end end response end end end PKu]՝[[rack-3.0.8/lib/rack/lint.rbnuȯ# frozen_string_literal: true require 'forwardable' require_relative 'constants' require_relative 'utils' module Rack # Rack::Lint validates your application and the requests and # responses according to the Rack spec. class Lint def initialize(app) @app = app end # :stopdoc: class LintError < RuntimeError; end # AUTHORS: n.b. The trailing whitespace between paragraphs is important and # should not be removed. The whitespace creates paragraphs in the RDoc # output. # ## This specification aims to formalize the Rack protocol. You ## can (and should) use Rack::Lint to enforce it. ## ## When you develop middleware, be sure to add a Lint before and ## after to catch all mistakes. ## ## = Rack applications ## ## A Rack application is a Ruby object (not a class) that ## responds to +call+. def call(env = nil) Wrapper.new(@app, env).response end class Wrapper def initialize(app, env) @app = app @env = env @response = nil @head_request = false @status = nil @headers = nil @body = nil @invoked = nil @content_length = nil @closed = false @size = 0 end def response ## It takes exactly one argument, the *environment* raise LintError, "No env given" unless @env check_environment(@env) @env[RACK_INPUT] = InputWrapper.new(@env[RACK_INPUT]) @env[RACK_ERRORS] = ErrorWrapper.new(@env[RACK_ERRORS]) ## and returns a non-frozen Array of exactly three values: @response = @app.call(@env) raise LintError, "response is not an Array, but #{@response.class}" unless @response.kind_of? Array raise LintError, "response is frozen" if @response.frozen? raise LintError, "response array has #{@response.size} elements instead of 3" unless @response.size == 3 @status, @headers, @body = @response ## The *status*, check_status(@status) ## the *headers*, check_headers(@headers) hijack_proc = check_hijack_response(@headers, @env) if hijack_proc @headers[RACK_HIJACK] = hijack_proc end ## and the *body*. check_content_type(@status, @headers) check_content_length(@status, @headers) @head_request = @env[REQUEST_METHOD] == HEAD @lint = (@env['rack.lint'] ||= []) << self if (@env['rack.lint.body_iteration'] ||= 0) > 0 raise LintError, "Middleware must not call #each directly" end return [@status, @headers, self] end ## ## == The Environment ## def check_environment(env) ## The environment must be an unfrozen instance of Hash that includes ## CGI-like headers. The Rack application is free to modify the ## environment. raise LintError, "env #{env.inspect} is not a Hash, but #{env.class}" unless env.kind_of? Hash raise LintError, "env should not be frozen, but is" if env.frozen? ## ## The environment is required to include these variables ## (adopted from {PEP 333}[https://peps.python.org/pep-0333/]), except when they'd be empty, but see ## below. ## REQUEST_METHOD:: The HTTP request method, such as ## "GET" or "POST". This cannot ever ## be an empty string, and so is ## always required. ## SCRIPT_NAME:: The initial portion of the request ## URL's "path" that corresponds to the ## application object, so that the ## application knows its virtual ## "location". This may be an empty ## string, if the application corresponds ## to the "root" of the server. ## PATH_INFO:: The remainder of the request URL's ## "path", designating the virtual ## "location" of the request's target ## within the application. This may be an ## empty string, if the request URL targets ## the application root and does not have a ## trailing slash. This value may be ## percent-encoded when originating from ## a URL. ## QUERY_STRING:: The portion of the request URL that ## follows the ?, if any. May be ## empty, but is always required! ## SERVER_NAME:: When combined with SCRIPT_NAME and ## PATH_INFO, these variables can be ## used to complete the URL. Note, however, ## that HTTP_HOST, if present, ## should be used in preference to ## SERVER_NAME for reconstructing ## the request URL. ## SERVER_NAME can never be an empty ## string, and so is always required. ## SERVER_PORT:: An optional +Integer+ which is the port the ## server is running on. Should be specified if ## the server is running on a non-standard port. ## SERVER_PROTOCOL:: A string representing the HTTP version used ## for the request. ## HTTP_ Variables:: Variables corresponding to the ## client-supplied HTTP request ## headers (i.e., variables whose ## names begin with HTTP_). The ## presence or absence of these ## variables should correspond with ## the presence or absence of the ## appropriate HTTP header in the ## request. See ## {RFC3875 section 4.1.18}[https://tools.ietf.org/html/rfc3875#section-4.1.18] ## for specific behavior. ## In addition to this, the Rack environment must include these ## Rack-specific variables: ## rack.url_scheme:: +http+ or +https+, depending on the ## request URL. ## rack.input:: See below, the input stream. ## rack.errors:: See below, the error stream. ## rack.hijack?:: See below, if present and true, indicates ## that the server supports partial hijacking. ## rack.hijack:: See below, if present, an object responding ## to +call+ that is used to perform a full ## hijack. ## Additional environment specifications have approved to ## standardized middleware APIs. None of these are required to ## be implemented by the server. ## rack.session:: A hash-like interface for storing ## request session data. ## The store must implement: if session = env[RACK_SESSION] ## store(key, value) (aliased as []=); unless session.respond_to?(:store) && session.respond_to?(:[]=) raise LintError, "session #{session.inspect} must respond to store and []=" end ## fetch(key, default = nil) (aliased as []); unless session.respond_to?(:fetch) && session.respond_to?(:[]) raise LintError, "session #{session.inspect} must respond to fetch and []" end ## delete(key); unless session.respond_to?(:delete) raise LintError, "session #{session.inspect} must respond to delete" end ## clear; unless session.respond_to?(:clear) raise LintError, "session #{session.inspect} must respond to clear" end ## to_hash (returning unfrozen Hash instance); unless session.respond_to?(:to_hash) && session.to_hash.kind_of?(Hash) && !session.to_hash.frozen? raise LintError, "session #{session.inspect} must respond to to_hash and return unfrozen Hash instance" end end ## rack.logger:: A common object interface for logging messages. ## The object must implement: if logger = env[RACK_LOGGER] ## info(message, &block) unless logger.respond_to?(:info) raise LintError, "logger #{logger.inspect} must respond to info" end ## debug(message, &block) unless logger.respond_to?(:debug) raise LintError, "logger #{logger.inspect} must respond to debug" end ## warn(message, &block) unless logger.respond_to?(:warn) raise LintError, "logger #{logger.inspect} must respond to warn" end ## error(message, &block) unless logger.respond_to?(:error) raise LintError, "logger #{logger.inspect} must respond to error" end ## fatal(message, &block) unless logger.respond_to?(:fatal) raise LintError, "logger #{logger.inspect} must respond to fatal" end end ## rack.multipart.buffer_size:: An Integer hint to the multipart parser as to what chunk size to use for reads and writes. if bufsize = env[RACK_MULTIPART_BUFFER_SIZE] unless bufsize.is_a?(Integer) && bufsize > 0 raise LintError, "rack.multipart.buffer_size must be an Integer > 0 if specified" end end ## rack.multipart.tempfile_factory:: An object responding to #call with two arguments, the filename and content_type given for the multipart form field, and returning an IO-like object that responds to #<< and optionally #rewind. This factory will be used to instantiate the tempfile for each multipart form file upload field, rather than the default class of Tempfile. if tempfile_factory = env[RACK_MULTIPART_TEMPFILE_FACTORY] raise LintError, "rack.multipart.tempfile_factory must respond to #call" unless tempfile_factory.respond_to?(:call) env[RACK_MULTIPART_TEMPFILE_FACTORY] = lambda do |filename, content_type| io = tempfile_factory.call(filename, content_type) raise LintError, "rack.multipart.tempfile_factory return value must respond to #<<" unless io.respond_to?(:<<) io end end ## The server or the application can store their own data in the ## environment, too. The keys must contain at least one dot, ## and should be prefixed uniquely. The prefix rack. ## is reserved for use with the Rack core distribution and other ## accepted specifications and must not be used otherwise. ## %w[REQUEST_METHOD SERVER_NAME QUERY_STRING SERVER_PROTOCOL rack.input rack.errors].each { |header| raise LintError, "env missing required key #{header}" unless env.include? header } ## The SERVER_PORT must be an Integer if set. server_port = env["SERVER_PORT"] unless server_port.nil? || (Integer(server_port) rescue false) raise LintError, "env[SERVER_PORT] is not an Integer" end ## The SERVER_NAME must be a valid authority as defined by RFC7540. unless (URI.parse("http://#{env[SERVER_NAME]}/") rescue false) raise LintError, "#{env[SERVER_NAME]} must be a valid authority" end ## The HTTP_HOST must be a valid authority as defined by RFC7540. unless (URI.parse("http://#{env[HTTP_HOST]}/") rescue false) raise LintError, "#{env[HTTP_HOST]} must be a valid authority" end ## The SERVER_PROTOCOL must match the regexp HTTP/\d(\.\d)?. server_protocol = env['SERVER_PROTOCOL'] unless %r{HTTP/\d(\.\d)?}.match?(server_protocol) raise LintError, "env[SERVER_PROTOCOL] does not match HTTP/\\d(\\.\\d)?" end ## If the HTTP_VERSION is present, it must equal the SERVER_PROTOCOL. if env['HTTP_VERSION'] && env['HTTP_VERSION'] != server_protocol raise LintError, "env[HTTP_VERSION] does not equal env[SERVER_PROTOCOL]" end ## The environment must not contain the keys ## HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH ## (use the versions without HTTP_). %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header| if env.include? header raise LintError, "env contains #{header}, must use #{header[5..-1]}" end } ## The CGI keys (named without a period) must have String values. ## If the string values for CGI keys contain non-ASCII characters, ## they should use ASCII-8BIT encoding. env.each { |key, value| next if key.include? "." # Skip extensions unless value.kind_of? String raise LintError, "env variable #{key} has non-string value #{value.inspect}" end next if value.encoding == Encoding::ASCII_8BIT unless value.b !~ /[\x80-\xff]/n raise LintError, "env variable #{key} has value containing non-ASCII characters and has non-ASCII-8BIT encoding #{value.inspect} encoding: #{value.encoding}" end } ## There are the following restrictions: ## * rack.url_scheme must either be +http+ or +https+. unless %w[http https].include?(env[RACK_URL_SCHEME]) raise LintError, "rack.url_scheme unknown: #{env[RACK_URL_SCHEME].inspect}" end ## * There must be a valid input stream in rack.input. check_input env[RACK_INPUT] ## * There must be a valid error stream in rack.errors. check_error env[RACK_ERRORS] ## * There may be a valid hijack callback in rack.hijack check_hijack env ## * The REQUEST_METHOD must be a valid token. unless env[REQUEST_METHOD] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/ raise LintError, "REQUEST_METHOD unknown: #{env[REQUEST_METHOD].dump}" end ## * The SCRIPT_NAME, if non-empty, must start with / if env.include?(SCRIPT_NAME) && env[SCRIPT_NAME] != "" && env[SCRIPT_NAME] !~ /\A\// raise LintError, "SCRIPT_NAME must start with /" end ## * The PATH_INFO, if non-empty, must start with / if env.include?(PATH_INFO) && env[PATH_INFO] != "" && env[PATH_INFO] !~ /\A\// raise LintError, "PATH_INFO must start with /" end ## * The CONTENT_LENGTH, if given, must consist of digits only. if env.include?("CONTENT_LENGTH") && env["CONTENT_LENGTH"] !~ /\A\d+\z/ raise LintError, "Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}" end ## * One of SCRIPT_NAME or PATH_INFO must be ## set. PATH_INFO should be / if ## SCRIPT_NAME is empty. unless env[SCRIPT_NAME] || env[PATH_INFO] raise LintError, "One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)" end ## SCRIPT_NAME never should be /, but instead be empty. unless env[SCRIPT_NAME] != "/" raise LintError, "SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'" end ## rack.response_finished:: An array of callables run by the server after the response has been ## processed. This would typically be invoked after sending the response to the client, but it could also be ## invoked if an error occurs while generating the response or sending the response; in that case, the error ## argument will be a subclass of +Exception+. ## The callables are invoked with +env, status, headers, error+ arguments and should not raise any ## exceptions. They should be invoked in reverse order of registration. if callables = env[RACK_RESPONSE_FINISHED] raise LintError, "rack.response_finished must be an array of callable objects" unless callables.is_a?(Array) callables.each do |callable| raise LintError, "rack.response_finished values must respond to call(env, status, headers, error)" unless callable.respond_to?(:call) end end end ## ## === The Input Stream ## ## The input stream is an IO-like object which contains the raw HTTP ## POST data. def check_input(input) ## When applicable, its external encoding must be "ASCII-8BIT" and it ## must be opened in binary mode, for Ruby 1.9 compatibility. if input.respond_to?(:external_encoding) && input.external_encoding != Encoding::ASCII_8BIT raise LintError, "rack.input #{input} does not have ASCII-8BIT as its external encoding" end if input.respond_to?(:binmode?) && !input.binmode? raise LintError, "rack.input #{input} is not opened in binary mode" end ## The input stream must respond to +gets+, +each+, and +read+. [:gets, :each, :read].each { |method| unless input.respond_to? method raise LintError, "rack.input #{input} does not respond to ##{method}" end } end class InputWrapper def initialize(input) @input = input end ## * +gets+ must be called without arguments and return a string, ## or +nil+ on EOF. def gets(*args) raise LintError, "rack.input#gets called with arguments" unless args.size == 0 v = @input.gets unless v.nil? or v.kind_of? String raise LintError, "rack.input#gets didn't return a String" end v end ## * +read+ behaves like IO#read. ## Its signature is read([length, [buffer]]). ## ## If given, +length+ must be a non-negative Integer (>= 0) or +nil+, ## and +buffer+ must be a String and may not be nil. ## ## If +length+ is given and not nil, then this method reads at most ## +length+ bytes from the input stream. ## ## If +length+ is not given or nil, then this method reads ## all data until EOF. ## ## When EOF is reached, this method returns nil if +length+ is given ## and not nil, or "" if +length+ is not given or is nil. ## ## If +buffer+ is given, then the read data will be placed ## into +buffer+ instead of a newly created String object. def read(*args) unless args.size <= 2 raise LintError, "rack.input#read called with too many arguments" end if args.size >= 1 unless args.first.kind_of?(Integer) || args.first.nil? raise LintError, "rack.input#read called with non-integer and non-nil length" end unless args.first.nil? || args.first >= 0 raise LintError, "rack.input#read called with a negative length" end end if args.size >= 2 unless args[1].kind_of?(String) raise LintError, "rack.input#read called with non-String buffer" end end v = @input.read(*args) unless v.nil? or v.kind_of? String raise LintError, "rack.input#read didn't return nil or a String" end if args[0].nil? unless !v.nil? raise LintError, "rack.input#read(nil) returned nil on EOF" end end v end ## * +each+ must be called without arguments and only yield Strings. def each(*args) raise LintError, "rack.input#each called with arguments" unless args.size == 0 @input.each { |line| unless line.kind_of? String raise LintError, "rack.input#each didn't yield a String" end yield line } end ## * +close+ can be called on the input stream to indicate that the ## any remaining input is not needed. def close(*args) @input.close(*args) end end ## ## === The Error Stream ## def check_error(error) ## The error stream must respond to +puts+, +write+ and +flush+. [:puts, :write, :flush].each { |method| unless error.respond_to? method raise LintError, "rack.error #{error} does not respond to ##{method}" end } end class ErrorWrapper def initialize(error) @error = error end ## * +puts+ must be called with a single argument that responds to +to_s+. def puts(str) @error.puts str end ## * +write+ must be called with a single argument that is a String. def write(str) raise LintError, "rack.errors#write not called with a String" unless str.kind_of? String @error.write str end ## * +flush+ must be called without arguments and must be called ## in order to make the error appear for sure. def flush @error.flush end ## * +close+ must never be called on the error stream. def close(*args) raise LintError, "rack.errors#close must not be called" end end ## ## === Hijacking ## ## The hijacking interfaces provides a means for an application to take ## control of the HTTP connection. There are two distinct hijack ## interfaces: full hijacking where the application takes over the raw ## connection, and partial hijacking where the application takes over ## just the response body stream. In both cases, the application is ## responsible for closing the hijacked stream. ## ## Full hijacking only works with HTTP/1. Partial hijacking is functionally ## equivalent to streaming bodies, and is still optionally supported for ## backwards compatibility with older Rack versions. ## ## ==== Full Hijack ## ## Full hijack is used to completely take over an HTTP/1 connection. It ## occurs before any headers are written and causes the request to ## ignores any response generated by the application. ## ## It is intended to be used when applications need access to raw HTTP/1 ## connection. ## def check_hijack(env) ## If +rack.hijack+ is present in +env+, it must respond to +call+ if original_hijack = env[RACK_HIJACK] raise LintError, "rack.hijack must respond to call" unless original_hijack.respond_to?(:call) env[RACK_HIJACK] = proc do io = original_hijack.call ## and return an +IO+ instance which can be used to read and write ## to the underlying connection using HTTP/1 semantics and ## formatting. raise LintError, "rack.hijack must return an IO instance" unless io.is_a?(IO) io end end end ## ## ==== Partial Hijack ## ## Partial hijack is used for bi-directional streaming of the request and ## response body. It occurs after the status and headers are written by ## the server and causes the server to ignore the Body of the response. ## ## It is intended to be used when applications need bi-directional ## streaming. ## def check_hijack_response(headers, env) ## If +rack.hijack?+ is present in +env+ and truthy, if env[RACK_IS_HIJACK] ## an application may set the special response header +rack.hijack+ if original_hijack = headers[RACK_HIJACK] ## to an object that responds to +call+, unless original_hijack.respond_to?(:call) raise LintError, 'rack.hijack header must respond to #call' end ## accepting a +stream+ argument. return proc do |io| original_hijack.call StreamWrapper.new(io) end end ## ## After the response status and headers have been sent, this hijack ## callback will be invoked with a +stream+ argument which follows the ## same interface as outlined in "Streaming Body". Servers must ## ignore the +body+ part of the response tuple when the ## +rack.hijack+ response header is present. Using an empty +Array+ ## instance is recommended. else ## ## The special response header +rack.hijack+ must only be set ## if the request +env+ has a truthy +rack.hijack?+. if headers.key?(RACK_HIJACK) raise LintError, 'rack.hijack header must not be present if server does not support hijacking' end end nil end ## == The Response ## ## === The Status ## def check_status(status) ## This is an HTTP status. It must be an Integer greater than or equal to ## 100. unless status.is_a?(Integer) && status >= 100 raise LintError, "Status must be an Integer >=100" end end ## ## === The Headers ## def check_headers(headers) ## The headers must be a unfrozen Hash. unless headers.kind_of?(Hash) raise LintError, "headers object should be a hash, but isn't (got #{headers.class} as headers)" end if headers.frozen? raise LintError, "headers object should not be frozen, but is" end headers.each do |key, value| ## The header keys must be Strings. unless key.kind_of? String raise LintError, "header key must be a string, was #{key.class}" end ## Special headers starting "rack." are for communicating with the ## server, and must not be sent back to the client. next if key.start_with?("rack.") ## The header must not contain a +Status+ key. raise LintError, "header must not contain status" if key == "status" ## Header keys must conform to RFC7230 token specification, i.e. cannot ## contain non-printable ASCII, DQUOTE or "(),/:;<=>?@[\]{}". raise LintError, "invalid header name: #{key}" if key =~ /[\(\),\/:;<=>\?@\[\\\]{}[:cntrl:]]/ ## Header keys must not contain uppercase ASCII characters (A-Z). raise LintError, "uppercase character in header name: #{key}" if key =~ /[A-Z]/ ## Header values must be either a String instance, if value.kind_of?(String) check_header_value(key, value) elsif value.kind_of?(Array) ## or an Array of String instances, value.each{|value| check_header_value(key, value)} else raise LintError, "a header value must be a String or Array of Strings, but the value of '#{key}' is a #{value.class}" end end end def check_header_value(key, value) ## such that each String instance must not contain characters below 037. if value =~ /[\000-\037]/ raise LintError, "invalid header value #{key}: #{value.inspect}" end end ## ## === The content-type ## def check_content_type(status, headers) headers.each { |key, value| ## There must not be a content-type header key when the +Status+ is 1xx, ## 204, or 304. if key == "content-type" if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key? status.to_i raise LintError, "content-type header found in #{status} response, not allowed" end return end } end ## ## === The content-length ## def check_content_length(status, headers) headers.each { |key, value| if key == 'content-length' ## There must not be a content-length header key when the ## +Status+ is 1xx, 204, or 304. if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key? status.to_i raise LintError, "content-length header found in #{status} response, not allowed" end @content_length = value end } end def verify_content_length(size) if @head_request unless size == 0 raise LintError, "Response body was given for HEAD request, but should be empty" end elsif @content_length unless @content_length == size.to_s raise LintError, "content-length header was #{@content_length}, but should be #{size}" end end end ## ## === The Body ## ## The Body is typically an +Array+ of +String+ instances, an enumerable ## that yields +String+ instances, a +Proc+ instance, or a File-like ## object. ## ## The Body must respond to +each+ or +call+. It may optionally respond ## to +to_path+ or +to_ary+. A Body that responds to +each+ is considered ## to be an Enumerable Body. A Body that responds to +call+ is considered ## to be a Streaming Body. ## ## A Body that responds to both +each+ and +call+ must be treated as an ## Enumerable Body, not a Streaming Body. If it responds to +each+, you ## must call +each+ and not +call+. If the Body doesn't respond to ## +each+, then you can assume it responds to +call+. ## ## The Body must either be consumed or returned. The Body is consumed by ## optionally calling either +each+ or +call+. ## Then, if the Body responds to +close+, it must be called to release ## any resources associated with the generation of the body. ## In other words, +close+ must always be called at least once; typically ## after the web server has sent the response to the client, but also in ## cases where the Rack application makes internal/virtual requests and ## discards the response. ## def close ## ## After calling +close+, the Body is considered closed and should not ## be consumed again. @closed = true ## If the original Body is replaced by a new Body, the new Body must ## also consume the original Body by calling +close+ if possible. @body.close if @body.respond_to?(:close) index = @lint.index(self) unless @env['rack.lint'][0..index].all? {|lint| lint.instance_variable_get(:@closed)} raise LintError, "Body has not been closed" end end def verify_to_path ## ## If the Body responds to +to_path+, it must return a +String+ ## path for the local file system whose contents are identical ## to that produced by calling +each+; this may be used by the ## server as an alternative, possibly more efficient way to ## transport the response. The +to_path+ method does not consume ## the body. if @body.respond_to?(:to_path) unless ::File.exist? @body.to_path raise LintError, "The file identified by body.to_path does not exist" end end end ## ## ==== Enumerable Body ## def each ## The Enumerable Body must respond to +each+. raise LintError, "Enumerable Body must respond to each" unless @body.respond_to?(:each) ## It must only be called once. raise LintError, "Response body must only be invoked once (#{@invoked})" unless @invoked.nil? ## It must not be called after being closed. raise LintError, "Response body is already closed" if @closed @invoked = :each @body.each do |chunk| ## and must only yield String values. unless chunk.kind_of? String raise LintError, "Body yielded non-string value #{chunk.inspect}" end ## ## The Body itself should not be an instance of String, as this will ## break in Ruby 1.9. ## ## Middleware must not call +each+ directly on the Body. ## Instead, middleware can return a new Body that calls +each+ on the ## original Body, yielding at least once per iteration. if @lint[0] == self @env['rack.lint.body_iteration'] += 1 else if (@env['rack.lint.body_iteration'] -= 1) > 0 raise LintError, "New body must yield at least once per iteration of old body" end end @size += chunk.bytesize yield chunk end verify_content_length(@size) verify_to_path end BODY_METHODS = {to_ary: true, each: true, call: true, to_path: true} def to_path @body.to_path end def respond_to?(name, *) if BODY_METHODS.key?(name) @body.respond_to?(name) else super end end ## ## If the Body responds to +to_ary+, it must return an +Array+ whose ## contents are identical to that produced by calling +each+. ## Middleware may call +to_ary+ directly on the Body and return a new ## Body in its place. In other words, middleware can only process the ## Body directly if it responds to +to_ary+. If the Body responds to both ## +to_ary+ and +close+, its implementation of +to_ary+ must call ## +close+. def to_ary @body.to_ary.tap do |content| unless content == @body.enum_for.to_a raise LintError, "#to_ary not identical to contents produced by calling #each" end end ensure close end ## ## ==== Streaming Body ## def call(stream) ## The Streaming Body must respond to +call+. raise LintError, "Streaming Body must respond to call" unless @body.respond_to?(:call) ## It must only be called once. raise LintError, "Response body must only be invoked once (#{@invoked})" unless @invoked.nil? ## It must not be called after being closed. raise LintError, "Response body is already closed" if @closed @invoked = :call ## It takes a +stream+ argument. ## ## The +stream+ argument must implement: ## read, write, <<, flush, close, close_read, close_write, closed? ## @body.call(StreamWrapper.new(stream)) end class StreamWrapper extend Forwardable ## The semantics of these IO methods must be a best effort match to ## those of a normal Ruby IO or Socket object, using standard arguments ## and raising standard exceptions. Servers are encouraged to simply ## pass on real IO objects, although it is recognized that this approach ## is not directly compatible with HTTP/2. REQUIRED_METHODS = [ :read, :write, :<<, :flush, :close, :close_read, :close_write, :closed? ] def_delegators :@stream, *REQUIRED_METHODS def initialize(stream) @stream = stream REQUIRED_METHODS.each do |method_name| raise LintError, "Stream must respond to #{method_name}" unless stream.respond_to?(method_name) end end end # :startdoc: end end end ## ## == Thanks ## Some parts of this specification are adopted from {PEP 333 – Python Web Server Gateway Interface v1.0}[https://peps.python.org/pep-0333/] ## I'd like to thank everyone involved in that effort. PKu]|| &rack-3.0.8/lib/rack/conditional_get.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' require_relative 'body_proxy' module Rack # Middleware that enables conditional GET using if-none-match and # if-modified-since. The application should set either or both of the # last-modified or etag response headers according to RFC 2616. When # either of the conditions is met, the response body is set to be zero # length and the response status is set to 304 Not Modified. # # Applications that defer response body generation until the body's each # message is received will avoid response body generation completely when # a conditional GET matches. # # Adapted from Michael Klishin's Merb implementation: # https://github.com/wycats/merb/blob/master/merb-core/lib/merb-core/rack/middleware/conditional_get.rb class ConditionalGet def initialize(app) @app = app end # Return empty 304 response if the response has not been # modified since the last request. def call(env) case env[REQUEST_METHOD] when "GET", "HEAD" status, headers, body = response = @app.call(env) if status == 200 && fresh?(env, headers) response[0] = 304 headers.delete(CONTENT_TYPE) headers.delete(CONTENT_LENGTH) response[2] = Rack::BodyProxy.new([]) do body.close if body.respond_to?(:close) end end response else @app.call(env) end end private # Return whether the response has not been modified since the # last request. def fresh?(env, headers) # if-none-match has priority over if-modified-since per RFC 7232 if none_match = env['HTTP_IF_NONE_MATCH'] etag_matches?(none_match, headers) elsif (modified_since = env['HTTP_IF_MODIFIED_SINCE']) && (modified_since = to_rfc2822(modified_since)) modified_since?(modified_since, headers) end end # Whether the etag response header matches the if-none-match request header. # If so, the request has not been modified. def etag_matches?(none_match, headers) headers[ETAG] == none_match end # Whether the last-modified response header matches the if-modified-since # request header. If so, the request has not been modified. def modified_since?(modified_since, headers) last_modified = to_rfc2822(headers['last-modified']) and modified_since >= last_modified end # Return a Time object for the given string (which should be in RFC2822 # format), or nil if the string cannot be parsed. def to_rfc2822(since) # shortest possible valid date is the obsolete: 1 Nov 97 09:55 A # anything shorter is invalid, this avoids exceptions for common cases # most common being the empty string if since && since.length >= 16 # NOTE: there is no trivial way to write this in a non exception way # _rfc2822 returns a hash but is not that usable Time.rfc2822(since) rescue nil end end end end PKu]N4q#rack-3.0.8/lib/rack/content_type.rbnu[# frozen_string_literal: true require_relative 'constants' require_relative 'utils' module Rack # Sets the content-type header on responses which don't have one. # # Builder Usage: # use Rack::ContentType, "text/plain" # # When no content type argument is provided, "text/html" is the # default. class ContentType include Rack::Utils def initialize(app, content_type = "text/html") @app = app @content_type = content_type end def call(env) status, headers, _ = response = @app.call(env) unless STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) headers[CONTENT_TYPE] ||= @content_type end response end end end PKu]dNN"rack-3.0.8/lib/rack/show_status.rbnu[# frozen_string_literal: true require 'erb' require_relative 'constants' require_relative 'utils' require_relative 'request' require_relative 'body_proxy' module Rack # Rack::ShowStatus catches all empty responses and replaces them # with a site explaining the error. # # Additional details can be put into rack.showstatus.detail # and will be shown as HTML. If such details exist, the error page # is always rendered, even if the reply was not empty. class ShowStatus def initialize(app) @app = app @template = ERB.new(TEMPLATE) end def call(env) status, headers, body = response = @app.call(env) empty = headers[CONTENT_LENGTH].to_i <= 0 # client or server error, or explicit message if (status.to_i >= 400 && empty) || env[RACK_SHOWSTATUS_DETAIL] # This double assignment is to prevent an "unused variable" warning. # Yes, it is dumb, but I don't like Ruby yelling at me. req = req = Rack::Request.new(env) message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s # This double assignment is to prevent an "unused variable" warning. # Yes, it is dumb, but I don't like Ruby yelling at me. detail = detail = env[RACK_SHOWSTATUS_DETAIL] || message html = @template.result(binding) size = html.bytesize response[2] = Rack::BodyProxy.new([html]) do body.close if body.respond_to?(:close) end headers[CONTENT_TYPE] = "text/html" headers[CONTENT_LENGTH] = size.to_s end response end def h(obj) # :nodoc: case obj when String Utils.escape_html(obj) else Utils.escape_html(obj.inspect) end end # :stopdoc: # adapted from Django # Copyright (c) Django Software Foundation and individual contributors. # Used under the modified BSD license: # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 TEMPLATE = <<'HTML' <%=h message %> at <%=h req.script_name + req.path_info %>

    <%=h message %> (<%= status.to_i %>)

    Request Method: <%=h req.request_method %>
    Request URL: <%=h req.url %>

    <%=h detail %>

    You're seeing this error because you use Rack::ShowStatus.

    HTML # :startdoc: end end PKu]?6/rack-3.0.8/lib/rack/mime.rbnu[# frozen_string_literal: true module Rack module Mime # Returns String with mime type if found, otherwise use +fallback+. # +ext+ should be filename extension in the '.ext' format that # File.extname(file) returns. # +fallback+ may be any object # # Also see the documentation for MIME_TYPES # # Usage: # Rack::Mime.mime_type('.foo') # # This is a shortcut for: # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream') def mime_type(ext, fallback = 'application/octet-stream') MIME_TYPES.fetch(ext.to_s.downcase, fallback) end module_function :mime_type # Returns true if the given value is a mime match for the given mime match # specification, false otherwise. # # Rack::Mime.match?('text/html', 'text/*') => true # Rack::Mime.match?('text/plain', '*') => true # Rack::Mime.match?('text/html', 'application/json') => false def match?(value, matcher) v1, v2 = value.split('/', 2) m1, m2 = matcher.split('/', 2) (m1 == '*' || v1 == m1) && (m2.nil? || m2 == '*' || m2 == v2) end module_function :match? # List of most common mime-types, selected various sources # according to their usefulness in a webserving scope for Ruby # users. # # To amend this list with your local mime.types list you can use: # # require 'webrick/httputils' # list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types') # Rack::Mime::MIME_TYPES.merge!(list) # # N.B. On Ubuntu the mime.types file does not include the leading period, so # users may need to modify the data before merging into the hash. MIME_TYPES = { ".123" => "application/vnd.lotus-1-2-3", ".3dml" => "text/vnd.in3d.3dml", ".3g2" => "video/3gpp2", ".3gp" => "video/3gpp", ".a" => "application/octet-stream", ".acc" => "application/vnd.americandynamics.acc", ".ace" => "application/x-ace-compressed", ".acu" => "application/vnd.acucobol", ".aep" => "application/vnd.audiograph", ".afp" => "application/vnd.ibm.modcap", ".ai" => "application/postscript", ".aif" => "audio/x-aiff", ".aiff" => "audio/x-aiff", ".ami" => "application/vnd.amiga.ami", ".apng" => "image/apng", ".appcache" => "text/cache-manifest", ".apr" => "application/vnd.lotus-approach", ".asc" => "application/pgp-signature", ".asf" => "video/x-ms-asf", ".asm" => "text/x-asm", ".aso" => "application/vnd.accpac.simply.aso", ".asx" => "video/x-ms-asf", ".atc" => "application/vnd.acucorp", ".atom" => "application/atom+xml", ".atomcat" => "application/atomcat+xml", ".atomsvc" => "application/atomsvc+xml", ".atx" => "application/vnd.antix.game-component", ".au" => "audio/basic", ".avi" => "video/x-msvideo", ".avif" => "image/avif", ".bat" => "application/x-msdownload", ".bcpio" => "application/x-bcpio", ".bdm" => "application/vnd.syncml.dm+wbxml", ".bh2" => "application/vnd.fujitsu.oasysprs", ".bin" => "application/octet-stream", ".bmi" => "application/vnd.bmi", ".bmp" => "image/bmp", ".box" => "application/vnd.previewsystems.box", ".btif" => "image/prs.btif", ".bz" => "application/x-bzip", ".bz2" => "application/x-bzip2", ".c" => "text/x-c", ".c4g" => "application/vnd.clonk.c4group", ".cab" => "application/vnd.ms-cab-compressed", ".cc" => "text/x-c", ".ccxml" => "application/ccxml+xml", ".cdbcmsg" => "application/vnd.contact.cmsg", ".cdkey" => "application/vnd.mediastation.cdkey", ".cdx" => "chemical/x-cdx", ".cdxml" => "application/vnd.chemdraw+xml", ".cdy" => "application/vnd.cinderella", ".cer" => "application/pkix-cert", ".cgm" => "image/cgm", ".chat" => "application/x-chat", ".chm" => "application/vnd.ms-htmlhelp", ".chrt" => "application/vnd.kde.kchart", ".cif" => "chemical/x-cif", ".cii" => "application/vnd.anser-web-certificate-issue-initiation", ".cil" => "application/vnd.ms-artgalry", ".cla" => "application/vnd.claymore", ".class" => "application/octet-stream", ".clkk" => "application/vnd.crick.clicker.keyboard", ".clkp" => "application/vnd.crick.clicker.palette", ".clkt" => "application/vnd.crick.clicker.template", ".clkw" => "application/vnd.crick.clicker.wordbank", ".clkx" => "application/vnd.crick.clicker", ".clp" => "application/x-msclip", ".cmc" => "application/vnd.cosmocaller", ".cmdf" => "chemical/x-cmdf", ".cml" => "chemical/x-cml", ".cmp" => "application/vnd.yellowriver-custom-menu", ".cmx" => "image/x-cmx", ".com" => "application/x-msdownload", ".conf" => "text/plain", ".cpio" => "application/x-cpio", ".cpp" => "text/x-c", ".cpt" => "application/mac-compactpro", ".crd" => "application/x-mscardfile", ".crl" => "application/pkix-crl", ".crt" => "application/x-x509-ca-cert", ".csh" => "application/x-csh", ".csml" => "chemical/x-csml", ".csp" => "application/vnd.commonspace", ".css" => "text/css", ".csv" => "text/csv", ".curl" => "application/vnd.curl", ".cww" => "application/prs.cww", ".cxx" => "text/x-c", ".daf" => "application/vnd.mobius.daf", ".davmount" => "application/davmount+xml", ".dcr" => "application/x-director", ".dd2" => "application/vnd.oma.dd2+xml", ".ddd" => "application/vnd.fujixerox.ddd", ".deb" => "application/x-debian-package", ".der" => "application/x-x509-ca-cert", ".dfac" => "application/vnd.dreamfactory", ".diff" => "text/x-diff", ".dis" => "application/vnd.mobius.dis", ".djv" => "image/vnd.djvu", ".djvu" => "image/vnd.djvu", ".dll" => "application/x-msdownload", ".dmg" => "application/octet-stream", ".dna" => "application/vnd.dna", ".doc" => "application/msword", ".docm" => "application/vnd.ms-word.document.macroEnabled.12", ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".dot" => "application/msword", ".dotm" => "application/vnd.ms-word.template.macroEnabled.12", ".dotx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template", ".dp" => "application/vnd.osgi.dp", ".dpg" => "application/vnd.dpgraph", ".dsc" => "text/prs.lines.tag", ".dtd" => "application/xml-dtd", ".dts" => "audio/vnd.dts", ".dtshd" => "audio/vnd.dts.hd", ".dv" => "video/x-dv", ".dvi" => "application/x-dvi", ".dwf" => "model/vnd.dwf", ".dwg" => "image/vnd.dwg", ".dxf" => "image/vnd.dxf", ".dxp" => "application/vnd.spotfire.dxp", ".ear" => "application/java-archive", ".ecelp4800" => "audio/vnd.nuera.ecelp4800", ".ecelp7470" => "audio/vnd.nuera.ecelp7470", ".ecelp9600" => "audio/vnd.nuera.ecelp9600", ".ecma" => "application/ecmascript", ".edm" => "application/vnd.novadigm.edm", ".edx" => "application/vnd.novadigm.edx", ".efif" => "application/vnd.picsel", ".ei6" => "application/vnd.pg.osasli", ".eml" => "message/rfc822", ".eol" => "audio/vnd.digital-winds", ".eot" => "application/vnd.ms-fontobject", ".eps" => "application/postscript", ".es3" => "application/vnd.eszigno3+xml", ".esf" => "application/vnd.epson.esf", ".etx" => "text/x-setext", ".exe" => "application/x-msdownload", ".ext" => "application/vnd.novadigm.ext", ".ez" => "application/andrew-inset", ".ez2" => "application/vnd.ezpix-album", ".ez3" => "application/vnd.ezpix-package", ".f" => "text/x-fortran", ".f77" => "text/x-fortran", ".f90" => "text/x-fortran", ".fbs" => "image/vnd.fastbidsheet", ".fdf" => "application/vnd.fdf", ".fe_launch" => "application/vnd.denovo.fcselayout-link", ".fg5" => "application/vnd.fujitsu.oasysgp", ".fli" => "video/x-fli", ".flif" => "image/flif", ".flo" => "application/vnd.micrografx.flo", ".flv" => "video/x-flv", ".flw" => "application/vnd.kde.kivio", ".flx" => "text/vnd.fmi.flexstor", ".fly" => "text/vnd.fly", ".fm" => "application/vnd.framemaker", ".fnc" => "application/vnd.frogans.fnc", ".for" => "text/x-fortran", ".fpx" => "image/vnd.fpx", ".fsc" => "application/vnd.fsc.weblaunch", ".fst" => "image/vnd.fst", ".ftc" => "application/vnd.fluxtime.clip", ".fti" => "application/vnd.anser-web-funds-transfer-initiation", ".fvt" => "video/vnd.fvt", ".fzs" => "application/vnd.fuzzysheet", ".g3" => "image/g3fax", ".gac" => "application/vnd.groove-account", ".gdl" => "model/vnd.gdl", ".gem" => "application/octet-stream", ".gemspec" => "text/x-script.ruby", ".ghf" => "application/vnd.groove-help", ".gif" => "image/gif", ".gim" => "application/vnd.groove-identity-message", ".gmx" => "application/vnd.gmx", ".gph" => "application/vnd.flographit", ".gqf" => "application/vnd.grafeq", ".gram" => "application/srgs", ".grv" => "application/vnd.groove-injector", ".grxml" => "application/srgs+xml", ".gtar" => "application/x-gtar", ".gtm" => "application/vnd.groove-tool-message", ".gtw" => "model/vnd.gtw", ".gv" => "text/vnd.graphviz", ".gz" => "application/x-gzip", ".h" => "text/x-c", ".h261" => "video/h261", ".h263" => "video/h263", ".h264" => "video/h264", ".hbci" => "application/vnd.hbci", ".hdf" => "application/x-hdf", ".heic" => "image/heic", ".heics" => "image/heic-sequence", ".heif" => "image/heif", ".heifs" => "image/heif-sequence", ".hh" => "text/x-c", ".hlp" => "application/winhlp", ".hpgl" => "application/vnd.hp-hpgl", ".hpid" => "application/vnd.hp-hpid", ".hps" => "application/vnd.hp-hps", ".hqx" => "application/mac-binhex40", ".htc" => "text/x-component", ".htke" => "application/vnd.kenameaapp", ".htm" => "text/html", ".html" => "text/html", ".hvd" => "application/vnd.yamaha.hv-dic", ".hvp" => "application/vnd.yamaha.hv-voice", ".hvs" => "application/vnd.yamaha.hv-script", ".icc" => "application/vnd.iccprofile", ".ice" => "x-conference/x-cooltalk", ".ico" => "image/vnd.microsoft.icon", ".ics" => "text/calendar", ".ief" => "image/ief", ".ifb" => "text/calendar", ".ifm" => "application/vnd.shana.informed.formdata", ".igl" => "application/vnd.igloader", ".igs" => "model/iges", ".igx" => "application/vnd.micrografx.igx", ".iif" => "application/vnd.shana.informed.interchange", ".imp" => "application/vnd.accpac.simply.imp", ".ims" => "application/vnd.ms-ims", ".ipk" => "application/vnd.shana.informed.package", ".irm" => "application/vnd.ibm.rights-management", ".irp" => "application/vnd.irepository.package+xml", ".iso" => "application/octet-stream", ".itp" => "application/vnd.shana.informed.formtemplate", ".ivp" => "application/vnd.immervision-ivp", ".ivu" => "application/vnd.immervision-ivu", ".jad" => "text/vnd.sun.j2me.app-descriptor", ".jam" => "application/vnd.jam", ".jar" => "application/java-archive", ".java" => "text/x-java-source", ".jisp" => "application/vnd.jisp", ".jlt" => "application/vnd.hp-jlyt", ".jnlp" => "application/x-java-jnlp-file", ".joda" => "application/vnd.joost.joda-archive", ".jp2" => "image/jp2", ".jpeg" => "image/jpeg", ".jpg" => "image/jpeg", ".jpgv" => "video/jpeg", ".jpm" => "video/jpm", ".js" => "application/javascript", ".json" => "application/json", ".karbon" => "application/vnd.kde.karbon", ".kfo" => "application/vnd.kde.kformula", ".kia" => "application/vnd.kidspiration", ".kml" => "application/vnd.google-earth.kml+xml", ".kmz" => "application/vnd.google-earth.kmz", ".kne" => "application/vnd.kinar", ".kon" => "application/vnd.kde.kontour", ".kpr" => "application/vnd.kde.kpresenter", ".ksp" => "application/vnd.kde.kspread", ".ktz" => "application/vnd.kahootz", ".kwd" => "application/vnd.kde.kword", ".latex" => "application/x-latex", ".lbd" => "application/vnd.llamagraphics.life-balance.desktop", ".lbe" => "application/vnd.llamagraphics.life-balance.exchange+xml", ".les" => "application/vnd.hhe.lesson-player", ".link66" => "application/vnd.route66.link66+xml", ".log" => "text/plain", ".lostxml" => "application/lost+xml", ".lrm" => "application/vnd.ms-lrm", ".ltf" => "application/vnd.frogans.ltf", ".lvp" => "audio/vnd.lucent.voice", ".lwp" => "application/vnd.lotus-wordpro", ".m3u" => "audio/x-mpegurl", ".m3u8" => "application/x-mpegurl", ".m4a" => "audio/mp4a-latm", ".m4v" => "video/mp4", ".ma" => "application/mathematica", ".mag" => "application/vnd.ecowin.chart", ".man" => "text/troff", ".manifest" => "text/cache-manifest", ".mathml" => "application/mathml+xml", ".mbk" => "application/vnd.mobius.mbk", ".mbox" => "application/mbox", ".mc1" => "application/vnd.medcalcdata", ".mcd" => "application/vnd.mcd", ".mdb" => "application/x-msaccess", ".mdi" => "image/vnd.ms-modi", ".mdoc" => "text/troff", ".me" => "text/troff", ".mfm" => "application/vnd.mfmp", ".mgz" => "application/vnd.proteus.magazine", ".mid" => "audio/midi", ".midi" => "audio/midi", ".mif" => "application/vnd.mif", ".mime" => "message/rfc822", ".mj2" => "video/mj2", ".mlp" => "application/vnd.dolby.mlp", ".mmd" => "application/vnd.chipnuts.karaoke-mmd", ".mmf" => "application/vnd.smaf", ".mml" => "application/mathml+xml", ".mmr" => "image/vnd.fujixerox.edmics-mmr", ".mng" => "video/x-mng", ".mny" => "application/x-msmoney", ".mov" => "video/quicktime", ".movie" => "video/x-sgi-movie", ".mp3" => "audio/mpeg", ".mp4" => "video/mp4", ".mp4a" => "audio/mp4", ".mp4s" => "application/mp4", ".mp4v" => "video/mp4", ".mpc" => "application/vnd.mophun.certificate", ".mpd" => "application/dash+xml", ".mpeg" => "video/mpeg", ".mpg" => "video/mpeg", ".mpga" => "audio/mpeg", ".mpkg" => "application/vnd.apple.installer+xml", ".mpm" => "application/vnd.blueice.multipass", ".mpn" => "application/vnd.mophun.application", ".mpp" => "application/vnd.ms-project", ".mpy" => "application/vnd.ibm.minipay", ".mqy" => "application/vnd.mobius.mqy", ".mrc" => "application/marc", ".ms" => "text/troff", ".mscml" => "application/mediaservercontrol+xml", ".mseq" => "application/vnd.mseq", ".msf" => "application/vnd.epson.msf", ".msh" => "model/mesh", ".msi" => "application/x-msdownload", ".msl" => "application/vnd.mobius.msl", ".msty" => "application/vnd.muvee.style", ".mts" => "model/vnd.mts", ".mus" => "application/vnd.musician", ".mvb" => "application/x-msmediaview", ".mwf" => "application/vnd.mfer", ".mxf" => "application/mxf", ".mxl" => "application/vnd.recordare.musicxml", ".mxml" => "application/xv+xml", ".mxs" => "application/vnd.triscape.mxs", ".mxu" => "video/vnd.mpegurl", ".n" => "application/vnd.nokia.n-gage.symbian.install", ".nc" => "application/x-netcdf", ".ngdat" => "application/vnd.nokia.n-gage.data", ".nlu" => "application/vnd.neurolanguage.nlu", ".nml" => "application/vnd.enliven", ".nnd" => "application/vnd.noblenet-directory", ".nns" => "application/vnd.noblenet-sealer", ".nnw" => "application/vnd.noblenet-web", ".npx" => "image/vnd.net-fpx", ".nsf" => "application/vnd.lotus-notes", ".oa2" => "application/vnd.fujitsu.oasys2", ".oa3" => "application/vnd.fujitsu.oasys3", ".oas" => "application/vnd.fujitsu.oasys", ".obd" => "application/x-msbinder", ".oda" => "application/oda", ".odc" => "application/vnd.oasis.opendocument.chart", ".odf" => "application/vnd.oasis.opendocument.formula", ".odg" => "application/vnd.oasis.opendocument.graphics", ".odi" => "application/vnd.oasis.opendocument.image", ".odp" => "application/vnd.oasis.opendocument.presentation", ".ods" => "application/vnd.oasis.opendocument.spreadsheet", ".odt" => "application/vnd.oasis.opendocument.text", ".oga" => "audio/ogg", ".ogg" => "application/ogg", ".ogv" => "video/ogg", ".ogx" => "application/ogg", ".org" => "application/vnd.lotus-organizer", ".otc" => "application/vnd.oasis.opendocument.chart-template", ".otf" => "application/vnd.oasis.opendocument.formula-template", ".otg" => "application/vnd.oasis.opendocument.graphics-template", ".oth" => "application/vnd.oasis.opendocument.text-web", ".oti" => "application/vnd.oasis.opendocument.image-template", ".otm" => "application/vnd.oasis.opendocument.text-master", ".ots" => "application/vnd.oasis.opendocument.spreadsheet-template", ".ott" => "application/vnd.oasis.opendocument.text-template", ".oxt" => "application/vnd.openofficeorg.extension", ".p" => "text/x-pascal", ".p10" => "application/pkcs10", ".p12" => "application/x-pkcs12", ".p7b" => "application/x-pkcs7-certificates", ".p7m" => "application/pkcs7-mime", ".p7r" => "application/x-pkcs7-certreqresp", ".p7s" => "application/pkcs7-signature", ".pas" => "text/x-pascal", ".pbd" => "application/vnd.powerbuilder6", ".pbm" => "image/x-portable-bitmap", ".pcl" => "application/vnd.hp-pcl", ".pclxl" => "application/vnd.hp-pclxl", ".pcx" => "image/x-pcx", ".pdb" => "chemical/x-pdb", ".pdf" => "application/pdf", ".pem" => "application/x-x509-ca-cert", ".pfr" => "application/font-tdpfr", ".pgm" => "image/x-portable-graymap", ".pgn" => "application/x-chess-pgn", ".pgp" => "application/pgp-encrypted", ".pic" => "image/x-pict", ".pict" => "image/pict", ".pkg" => "application/octet-stream", ".pki" => "application/pkixcmp", ".pkipath" => "application/pkix-pkipath", ".pl" => "text/x-script.perl", ".plb" => "application/vnd.3gpp.pic-bw-large", ".plc" => "application/vnd.mobius.plc", ".plf" => "application/vnd.pocketlearn", ".pls" => "application/pls+xml", ".pm" => "text/x-script.perl-module", ".pml" => "application/vnd.ctc-posml", ".png" => "image/png", ".pnm" => "image/x-portable-anymap", ".pntg" => "image/x-macpaint", ".portpkg" => "application/vnd.macports.portpkg", ".pot" => "application/vnd.ms-powerpoint", ".potm" => "application/vnd.ms-powerpoint.template.macroEnabled.12", ".potx" => "application/vnd.openxmlformats-officedocument.presentationml.template", ".ppa" => "application/vnd.ms-powerpoint", ".ppam" => "application/vnd.ms-powerpoint.addin.macroEnabled.12", ".ppd" => "application/vnd.cups-ppd", ".ppm" => "image/x-portable-pixmap", ".pps" => "application/vnd.ms-powerpoint", ".ppsm" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", ".ppsx" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow", ".ppt" => "application/vnd.ms-powerpoint", ".pptm" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12", ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", ".prc" => "application/vnd.palm", ".pre" => "application/vnd.lotus-freelance", ".prf" => "application/pics-rules", ".ps" => "application/postscript", ".psb" => "application/vnd.3gpp.pic-bw-small", ".psd" => "image/vnd.adobe.photoshop", ".ptid" => "application/vnd.pvi.ptid1", ".pub" => "application/x-mspublisher", ".pvb" => "application/vnd.3gpp.pic-bw-var", ".pwn" => "application/vnd.3m.post-it-notes", ".py" => "text/x-script.python", ".pya" => "audio/vnd.ms-playready.media.pya", ".pyv" => "video/vnd.ms-playready.media.pyv", ".qam" => "application/vnd.epson.quickanime", ".qbo" => "application/vnd.intu.qbo", ".qfx" => "application/vnd.intu.qfx", ".qps" => "application/vnd.publishare-delta-tree", ".qt" => "video/quicktime", ".qtif" => "image/x-quicktime", ".qxd" => "application/vnd.quark.quarkxpress", ".ra" => "audio/x-pn-realaudio", ".rake" => "text/x-script.ruby", ".ram" => "audio/x-pn-realaudio", ".rar" => "application/x-rar-compressed", ".ras" => "image/x-cmu-raster", ".rb" => "text/x-script.ruby", ".rcprofile" => "application/vnd.ipunplugged.rcprofile", ".rdf" => "application/rdf+xml", ".rdz" => "application/vnd.data-vision.rdz", ".rep" => "application/vnd.businessobjects", ".rgb" => "image/x-rgb", ".rif" => "application/reginfo+xml", ".rl" => "application/resource-lists+xml", ".rlc" => "image/vnd.fujixerox.edmics-rlc", ".rld" => "application/resource-lists-diff+xml", ".rm" => "application/vnd.rn-realmedia", ".rmp" => "audio/x-pn-realaudio-plugin", ".rms" => "application/vnd.jcp.javame.midlet-rms", ".rnc" => "application/relax-ng-compact-syntax", ".roff" => "text/troff", ".rpm" => "application/x-redhat-package-manager", ".rpss" => "application/vnd.nokia.radio-presets", ".rpst" => "application/vnd.nokia.radio-preset", ".rq" => "application/sparql-query", ".rs" => "application/rls-services+xml", ".rsd" => "application/rsd+xml", ".rss" => "application/rss+xml", ".rtf" => "application/rtf", ".rtx" => "text/richtext", ".ru" => "text/x-script.ruby", ".s" => "text/x-asm", ".saf" => "application/vnd.yamaha.smaf-audio", ".sbml" => "application/sbml+xml", ".sc" => "application/vnd.ibm.secure-container", ".scd" => "application/x-msschedule", ".scm" => "application/vnd.lotus-screencam", ".scq" => "application/scvp-cv-request", ".scs" => "application/scvp-cv-response", ".sdkm" => "application/vnd.solent.sdkm+xml", ".sdp" => "application/sdp", ".see" => "application/vnd.seemail", ".sema" => "application/vnd.sema", ".semd" => "application/vnd.semd", ".semf" => "application/vnd.semf", ".setpay" => "application/set-payment-initiation", ".setreg" => "application/set-registration-initiation", ".sfd" => "application/vnd.hydrostatix.sof-data", ".sfs" => "application/vnd.spotfire.sfs", ".sgm" => "text/sgml", ".sgml" => "text/sgml", ".sh" => "application/x-sh", ".shar" => "application/x-shar", ".shf" => "application/shf+xml", ".sig" => "application/pgp-signature", ".sit" => "application/x-stuffit", ".sitx" => "application/x-stuffitx", ".skp" => "application/vnd.koan", ".slt" => "application/vnd.epson.salt", ".smi" => "application/smil+xml", ".snd" => "audio/basic", ".so" => "application/octet-stream", ".spf" => "application/vnd.yamaha.smaf-phrase", ".spl" => "application/x-futuresplash", ".spot" => "text/vnd.in3d.spot", ".spp" => "application/scvp-vp-response", ".spq" => "application/scvp-vp-request", ".src" => "application/x-wais-source", ".srt" => "text/srt", ".srx" => "application/sparql-results+xml", ".sse" => "application/vnd.kodak-descriptor", ".ssf" => "application/vnd.epson.ssf", ".ssml" => "application/ssml+xml", ".stf" => "application/vnd.wt.stf", ".stk" => "application/hyperstudio", ".str" => "application/vnd.pg.format", ".sus" => "application/vnd.sus-calendar", ".sv4cpio" => "application/x-sv4cpio", ".sv4crc" => "application/x-sv4crc", ".svd" => "application/vnd.svd", ".svg" => "image/svg+xml", ".svgz" => "image/svg+xml", ".swf" => "application/x-shockwave-flash", ".swi" => "application/vnd.arastra.swi", ".t" => "text/troff", ".tao" => "application/vnd.tao.intent-module-archive", ".tar" => "application/x-tar", ".tbz" => "application/x-bzip-compressed-tar", ".tcap" => "application/vnd.3gpp2.tcap", ".tcl" => "application/x-tcl", ".tex" => "application/x-tex", ".texi" => "application/x-texinfo", ".texinfo" => "application/x-texinfo", ".text" => "text/plain", ".tif" => "image/tiff", ".tiff" => "image/tiff", ".tmo" => "application/vnd.tmobile-livetv", ".torrent" => "application/x-bittorrent", ".tpl" => "application/vnd.groove-tool-template", ".tpt" => "application/vnd.trid.tpt", ".tr" => "text/troff", ".tra" => "application/vnd.trueapp", ".trm" => "application/x-msterminal", ".ts" => "video/mp2t", ".tsv" => "text/tab-separated-values", ".ttf" => "application/octet-stream", ".twd" => "application/vnd.simtech-mindmapper", ".txd" => "application/vnd.genomatix.tuxedo", ".txf" => "application/vnd.mobius.txf", ".txt" => "text/plain", ".ufd" => "application/vnd.ufdl", ".umj" => "application/vnd.umajin", ".unityweb" => "application/vnd.unity", ".uoml" => "application/vnd.uoml+xml", ".uri" => "text/uri-list", ".ustar" => "application/x-ustar", ".utz" => "application/vnd.uiq.theme", ".uu" => "text/x-uuencode", ".vcd" => "application/x-cdlink", ".vcf" => "text/x-vcard", ".vcg" => "application/vnd.groove-vcard", ".vcs" => "text/x-vcalendar", ".vcx" => "application/vnd.vcx", ".vis" => "application/vnd.visionary", ".viv" => "video/vnd.vivo", ".vrml" => "model/vrml", ".vsd" => "application/vnd.visio", ".vsf" => "application/vnd.vsf", ".vtt" => "text/vtt", ".vtu" => "model/vnd.vtu", ".vxml" => "application/voicexml+xml", ".war" => "application/java-archive", ".wasm" => "application/wasm", ".wav" => "audio/x-wav", ".wax" => "audio/x-ms-wax", ".wbmp" => "image/vnd.wap.wbmp", ".wbs" => "application/vnd.criticaltools.wbs+xml", ".wbxml" => "application/vnd.wap.wbxml", ".webm" => "video/webm", ".webp" => "image/webp", ".wm" => "video/x-ms-wm", ".wma" => "audio/x-ms-wma", ".wmd" => "application/x-ms-wmd", ".wmf" => "application/x-msmetafile", ".wml" => "text/vnd.wap.wml", ".wmlc" => "application/vnd.wap.wmlc", ".wmls" => "text/vnd.wap.wmlscript", ".wmlsc" => "application/vnd.wap.wmlscriptc", ".wmv" => "video/x-ms-wmv", ".wmx" => "video/x-ms-wmx", ".wmz" => "application/x-ms-wmz", ".woff" => "application/font-woff", ".woff2" => "application/font-woff2", ".wpd" => "application/vnd.wordperfect", ".wpl" => "application/vnd.ms-wpl", ".wps" => "application/vnd.ms-works", ".wqd" => "application/vnd.wqd", ".wri" => "application/x-mswrite", ".wrl" => "model/vrml", ".wsdl" => "application/wsdl+xml", ".wspolicy" => "application/wspolicy+xml", ".wtb" => "application/vnd.webturbo", ".wvx" => "video/x-ms-wvx", ".x3d" => "application/vnd.hzn-3d-crossword", ".xar" => "application/vnd.xara", ".xbd" => "application/vnd.fujixerox.docuworks.binder", ".xbm" => "image/x-xbitmap", ".xdm" => "application/vnd.syncml.dm+xml", ".xdp" => "application/vnd.adobe.xdp+xml", ".xdw" => "application/vnd.fujixerox.docuworks", ".xenc" => "application/xenc+xml", ".xer" => "application/patch-ops-error+xml", ".xfdf" => "application/vnd.adobe.xfdf", ".xfdl" => "application/vnd.xfdl", ".xhtml" => "application/xhtml+xml", ".xif" => "image/vnd.xiff", ".xla" => "application/vnd.ms-excel", ".xlam" => "application/vnd.ms-excel.addin.macroEnabled.12", ".xls" => "application/vnd.ms-excel", ".xlsb" => "application/vnd.ms-excel.sheet.binary.macroEnabled.12", ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".xlsm" => "application/vnd.ms-excel.sheet.macroEnabled.12", ".xlt" => "application/vnd.ms-excel", ".xltx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template", ".xml" => "application/xml", ".xo" => "application/vnd.olpc-sugar", ".xop" => "application/xop+xml", ".xpm" => "image/x-xpixmap", ".xpr" => "application/vnd.is-xpr", ".xps" => "application/vnd.ms-xpsdocument", ".xpw" => "application/vnd.intercon.formnet", ".xsl" => "application/xml", ".xslt" => "application/xslt+xml", ".xsm" => "application/vnd.syncml+xml", ".xspf" => "application/xspf+xml", ".xul" => "application/vnd.mozilla.xul+xml", ".xwd" => "image/x-xwindowdump", ".xyz" => "chemical/x-xyz", ".yaml" => "text/yaml", ".yml" => "text/yaml", ".zaz" => "application/vnd.zzazz.deck+xml", ".zip" => "application/zip", ".zmm" => "application/vnd.handheld-entertainment+xml", } end end PKu]i\rack-3.0.8/lib/rack/config.rbnu[# frozen_string_literal: true module Rack # Rack::Config modifies the environment using the block given during # initialization. # # Example: # use Rack::Config do |env| # env['my-key'] = 'some-value' # end class Config def initialize(app, &block) @app = app @block = block end def call(env) @block.call(env) @app.call(env) end end end PKu]Y  rack-3.0.8/lib/rack/cascade.rbnu[# frozen_string_literal: true require_relative 'constants' module Rack # Rack::Cascade tries a request on several apps, and returns the # first response that is not 404 or 405 (or in a list of configured # status codes). If all applications tried return one of the configured # status codes, return the last response. class Cascade # deprecated, no longer used NotFound = [404, { CONTENT_TYPE => "text/plain" }, []] # An array of applications to try in order. attr_reader :apps # Set the apps to send requests to, and what statuses result in # cascading. Arguments: # # apps: An enumerable of rack applications. # cascade_for: The statuses to use cascading for. If a response is received # from an app, the next app is tried. def initialize(apps, cascade_for = [404, 405]) @apps = [] apps.each { |app| add app } @cascade_for = {} [*cascade_for].each { |status| @cascade_for[status] = true } end # Call each app in order. If the responses uses a status that requires # cascading, try the next app. If all responses require cascading, # return the response from the last app. def call(env) return [404, { CONTENT_TYPE => "text/plain" }, []] if @apps.empty? result = nil last_body = nil @apps.each do |app| # The SPEC says that the body must be closed after it has been iterated # by the server, or if it is replaced by a middleware action. Cascade # replaces the body each time a cascade happens. It is assumed that nil # does not respond to close, otherwise the previous application body # will be closed. The final application body will not be closed, as it # will be passed to the server as a result. last_body.close if last_body.respond_to? :close result = app.call(env) return result unless @cascade_for.include?(result[0].to_i) last_body = result[2] end result end # Append an app to the list of apps to cascade. This app will # be tried last. def add(app) @apps << app end # Whether the given app is one of the apps to cascade to. def include?(app) @apps.include?(app) end alias_method :<<, :add end end PKu]_l"rack-3.0.8/lib/rack/null_logger.rbnu[# frozen_string_literal: true require_relative 'constants' module Rack class NullLogger def initialize(app) @app = app end def call(env) env[RACK_LOGGER] = self @app.call(env) end def info(progname = nil, &block); end def debug(progname = nil, &block); end def warn(progname = nil, &block); end def error(progname = nil, &block); end def fatal(progname = nil, &block); end def unknown(progname = nil, &block); end def info? ; end def debug? ; end def warn? ; end def error? ; end def fatal? ; end def debug! ; end def error! ; end def fatal! ; end def info! ; end def warn! ; end def level ; end def progname ; end def datetime_format ; end def formatter ; end def sev_threshold ; end def level=(level); end def progname=(progname); end def datetime_format=(datetime_format); end def formatter=(formatter); end def sev_threshold=(sev_threshold); end def close ; end def add(severity, message = nil, progname = nil, &block); end def log(severity, message = nil, progname = nil, &block); end def <<(msg); end def reopen(logdev = nil); end end end PKu]*ruby-lsapi-5.5/ext/lsapi/.sitearchdir.timenu[PKu]Y//#ruby-lsapi-5.5/ext/lsapi/lsapilib.hnu[/* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _LSAPILIB_H_ #define _LSAPILIB_H_ #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif #include "lsapidef.h" #include #include #include struct LSAPI_key_value_pair { char * pKey; char * pValue; int keyLen; int valLen; }; struct lsapi_child_status; #define LSAPI_MAX_RESP_HEADERS 1000 typedef struct lsapi_request { int m_fdListen; int m_fd; long m_lLastActive; long m_lReqBegin; char * m_pReqBuf; int m_reqBufSize; char * m_pRespBuf; char * m_pRespBufEnd; char * m_pRespBufPos; char * m_pRespHeaderBuf; char * m_pRespHeaderBufEnd; char * m_pRespHeaderBufPos; struct lsapi_child_status * child_status; struct iovec * m_pIovec; struct iovec * m_pIovecEnd; struct iovec * m_pIovecCur; struct iovec * m_pIovecToWrite; struct lsapi_packet_header * m_respPktHeaderEnd; struct lsapi_req_header * m_pHeader; struct LSAPI_key_value_pair * m_pEnvList; struct LSAPI_key_value_pair * m_pSpecialEnvList; int m_envListSize; int m_specialEnvListSize; struct lsapi_http_header_index * m_pHeaderIndex; struct lsapi_header_offset * m_pUnknownHeader; char * m_pScriptFile; char * m_pScriptName; char * m_pQueryString; char * m_pHttpHeader; char * m_pRequestMethod; int m_totalLen; int m_reqState; off_t m_reqBodyLen; off_t m_reqBodyRead; int m_bufProcessed; int m_bufRead; struct lsapi_packet_header m_respPktHeader[5]; struct lsapi_resp_header m_respHeader; short m_respHeaderLen[LSAPI_MAX_RESP_HEADERS]; void * m_pAppData; }LSAPI_Request; extern LSAPI_Request g_req; /* return: >0 continue, ==0 stop, -1 failed */ typedef int (*LSAPI_CB_EnvHandler )( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ); int LSAPI_Init(void); void LSAPI_Stop(void); int LSAPI_Is_Listen_r( LSAPI_Request * pReq); int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ); int LSAPI_Accept_r( LSAPI_Request * pReq ); void LSAPI_Reset_r( LSAPI_Request * pReq ); int LSAPI_Finish_r( LSAPI_Request * pReq ); int LSAPI_Release_r( LSAPI_Request * pReq ); char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ); int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ); ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t len ); int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ); int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF ); int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ); ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len ); ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size ); ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len ); int LSAPI_Flush_r( LSAPI_Request * pReq ); int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len ); int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName, const char * pHeaderValue ); int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders, const char * pBody, int bodyLen ); static inline int LSAPI_SetRespStatus_r( LSAPI_Request * pReq, int code ) { if ( !pReq ) return -1; pReq->m_respHeader.m_respInfo.m_status = code; return 0; } static inline int LSAPI_SetAppData_r( LSAPI_Request * pReq, void * data ) { if ( !pReq ) return -1; pReq->m_pAppData = data; return 0; } static inline void * LSAPI_GetAppData_r( LSAPI_Request * pReq ) { if ( !pReq ) return NULL; return pReq->m_pAppData; } static inline char * LSAPI_GetQueryString_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pQueryString; return NULL; } static inline char * LSAPI_GetScriptFileName_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pScriptFile; return NULL; } static inline char * LSAPI_GetScriptName_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pScriptName; return NULL; } static inline char * LSAPI_GetRequestMethod_r( LSAPI_Request * pReq) { if ( pReq ) return pReq->m_pRequestMethod; return NULL; } static inline off_t LSAPI_GetReqBodyLen_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_reqBodyLen; return -1; } static inline off_t LSAPI_GetReqBodyRemain_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_reqBodyLen - pReq->m_reqBodyRead; return -1; } int LSAPI_End_Response_r(LSAPI_Request * pReq); int LSAPI_Is_Listen(void); static inline int LSAPI_Accept( void ) { return LSAPI_Accept_r( &g_req ); } static inline int LSAPI_Finish(void) { return LSAPI_Finish_r( &g_req ); } static inline char * LSAPI_GetHeader( int headerIndex ) { return LSAPI_GetHeader_r( &g_req, headerIndex ); } static inline int LSAPI_ForeachHeader( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachHeader_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachOrgHeader( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachOrgHeader_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachEnv( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachEnv_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachSpecialEnv( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachSpecialEnv_r( &g_req, fn, arg ); } static inline char * LSAPI_GetEnv( const char * name ) { return LSAPI_GetEnv_r( &g_req, name ); } static inline char * LSAPI_GetQueryString(void) { return LSAPI_GetQueryString_r( &g_req ); } static inline char * LSAPI_GetScriptFileName(void) { return LSAPI_GetScriptFileName_r( &g_req ); } static inline char * LSAPI_GetScriptName(void) { return LSAPI_GetScriptName_r( &g_req ); } static inline char * LSAPI_GetRequestMethod(void) { return LSAPI_GetRequestMethod_r( &g_req ); } static inline off_t LSAPI_GetReqBodyLen(void) { return LSAPI_GetReqBodyLen_r( &g_req ); } static inline off_t LSAPI_GetReqBodyRemain(void) { return LSAPI_GetReqBodyRemain_r( &g_req ); } static inline ssize_t LSAPI_ReadReqBody( char * pBuf, size_t len ) { return LSAPI_ReadReqBody_r( &g_req, pBuf, len ); } static inline int LSAPI_ReqBodyGetChar(void) { return LSAPI_ReqBodyGetChar_r( &g_req ); } static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF ) { return LSAPI_ReqBodyGetLine_r( &g_req, pBuf, len, getLF ); } static inline int LSAPI_FinalizeRespHeaders(void) { return LSAPI_FinalizeRespHeaders_r( &g_req ); } static inline ssize_t LSAPI_Write( const char * pBuf, ssize_t len ) { return LSAPI_Write_r( &g_req, pBuf, len ); } static inline ssize_t LSAPI_sendfile( int fdIn, off_t* off, size_t size ) { return LSAPI_sendfile_r(&g_req, fdIn, off, size ); } static inline ssize_t LSAPI_Write_Stderr( const char * pBuf, ssize_t len ) { return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); } static inline int LSAPI_Flush(void) { return LSAPI_Flush_r( &g_req ); } static inline int LSAPI_AppendRespHeader( char * pBuf, int len ) { return LSAPI_AppendRespHeader_r( &g_req, pBuf, len ); } static inline int LSAPI_SetRespStatus( int code ) { return LSAPI_SetRespStatus_r( &g_req, code ); } static inline int LSAPI_ErrResponse( int code, const char ** pRespHeaders, const char * pBody, int bodyLen ) { return LSAPI_ErrResponse_r( &g_req, code, pRespHeaders, pBody, bodyLen ); } static inline int LSAPI_End_Response(void) { return LSAPI_End_Response_r( &g_req ); } int LSAPI_IsRunning(void); int LSAPI_CreateListenSock( const char * pBind, int backlog ); typedef int (*fn_select_t)( int, fd_set *, fd_set *, fd_set *, struct timeval * ); int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ); void LSAPI_Set_Server_fd( int fd ); int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ); void LSAPI_No_Check_ppid(void); void LSAPI_Set_Max_Reqs( int reqs ); void LSAPI_Set_Max_Idle( int secs ); void LSAPI_Set_Max_Children( int maxChildren ); void LSAPI_Set_Max_Idle_Children( int maxIdleChld ); void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ); void LSAPI_Set_Max_Process_Time( int secs ); int LSAPI_Init_Env_Parameters( fn_select_t fp ); void LSAPI_Set_Slow_Req_Msecs( int msecs ); int LSAPI_Get_Slow_Req_Msecs(void); int LSAPI_is_suEXEC_Daemon(void); int LSAPI_Set_Restored_Parent_Pid(int pid); typedef void (*LSAPI_On_Timer_pf)(int *forked_child_pid); void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf); int LSAPI_Inc_Req_Processed(int cnt); int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq); int LSAPI_Postfork_Child(LSAPI_Request * pReq); int LSAPI_Postfork_Parent(LSAPI_Request * pReq); #define LSAPI_LOG_LEVEL_BITS 0xff #define LSAPI_LOG_FLAG_NONE 0 #define LSAPI_LOG_FLAG_DEBUG 1 #define LSAPI_LOG_FLAG_INFO 2 #define LSAPI_LOG_FLAG_NOTICE 3 #define LSAPI_LOG_FLAG_WARN 4 #define LSAPI_LOG_FLAG_ERROR 5 #define LSAPI_LOG_FLAG_CRIT 6 #define LSAPI_LOG_FLAG_FATAL 7 #define LSAPI_LOG_TIMESTAMP_BITS (0xff00) #define LSAPI_LOG_TIMESTAMP_FULL (0x100) #define LSAPI_LOG_TIMESTAMP_HMS (0x200) #define LSAPI_LOG_TIMESTAMP_STDERR (0x400) #define LSAPI_LOG_PID (0x10000) void LSAPI_Log(int flag, const char * fmt, ...) #if __GNUC__ __attribute__((format(printf, 2, 3))) #endif ; #if defined (c_plusplus) || defined (__cplusplus) } #endif #endif PKu]7Zw#ruby-lsapi-5.5/ext/lsapi/extconf.rbnu[require 'mkmf' dir_config( 'lsapi' ) if ( have_library( "socket" )) have_library( "nsl" ) end if RUBY_VERSION =~ /1.9/ then $CPPFLAGS += " -DRUBY_19" end if RUBY_VERSION =~ /2/ then $CPPFLAGS += " -DRUBY_2" end create_makefile( "lsapi" ) PKu].ZZ!ruby-lsapi-5.5/ext/lsapi/lsruby.cnu[ #include "ruby.h" #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 #include "util.h" #else #include #include #endif #include "lsapilib.h" #include #include #include #include #include #include #include #include #include #ifndef RUBY_API_VERSION_CODE #define RUBY_API_VERSION_CODE (RUBY_API_VERSION_MAJOR*10000+RUBY_API_VERSION_MINOR*100+RUBY_API_VERSION_TEENY) #endif /* RUBY_EXTERN VALUE ruby_errinfo; */ RUBY_EXTERN VALUE rb_stdin; RUBY_EXTERN VALUE rb_stdout; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 RUBY_EXTERN VALUE rb_defout; #endif static VALUE orig_stdin; static VALUE orig_stdout; static VALUE orig_stderr; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 static VALUE orig_defout; #endif static VALUE orig_env; static VALUE env_copy; static VALUE lsapi_env; static int MAX_BODYBUF_LENGTH = (10 * 1024 * 1024); /* static VALUE lsapi_objrefs; */ typedef struct lsapi_data { LSAPI_Request * req; VALUE env; ssize_t (* fn_write)( LSAPI_Request *, const char * , size_t ); }lsapi_data; static VALUE cLSAPI; static VALUE s_req = Qnil; static lsapi_data * s_req_data; static VALUE s_req_stderr = Qnil; static lsapi_data * s_stderr_data; static pid_t s_pid = 0; typedef struct lsapi_body { char *bodyBuf; //we put small one into memory, otherwise, into a memory mapping file, and we still use the bodyBuf to access this mapping int bodyLen; //expected length got form content-length int bodyCurrentLen; //current length by read() readBodyToReqBuf int curPos; }lsapi_body; static lsapi_body s_body; static char sTempFile[1024] = {0}; /* * static void lsapi_ruby_setenv(const char *name, const char *value) * { * if (!name) return; * * if (value && *value) * ruby_setenv(name, value); * else * ruby_unsetenv(name); } * * */ static void lsapi_mark( lsapi_data * data ) { rb_gc_mark( data->env ); } /* * static void lsapi_free_data( lsapi_data * data ) * { * free( data ); } * * */ static int add_env_rails( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { char * p; int len; /* Fixup some environment variables for rails */ switch( *pKey ) { case 'Q': if ( strcmp( pKey, "QUERY_STRING" ) == 0 ) { if ( !*pValue ) return 1; } break; case 'R': if (( *(pKey+8) == 'U' )&&( strcmp( pKey, "REQUEST_URI" ) == 0 )) { p = strchr( pValue, '?' ); if ( p ) { len = valLen - ( p - pValue ) - 1; /* * valLen = p - pValue; *p++ = 0; */ } else { p = (char *)pValue + valLen; len = 0; } rb_hash_aset( lsapi_env,rb_tainted_str_new("PATH_INFO", 9), rb_tainted_str_new(pValue, p - pValue)); rb_hash_aset( lsapi_env,rb_tainted_str_new("REQUEST_PATH", 12), rb_tainted_str_new(pValue, p - pValue)); if ( *p == '?' ) ++p; rb_hash_aset( lsapi_env,rb_tainted_str_new("QUERY_STRING", 12), rb_tainted_str_new(p, len)); } break; case 'S': if ( strcmp( pKey, "SCRIPT_NAME" ) == 0 ) { pValue = "/"; valLen = 1; } break; case 'P': if ( strcmp( pKey, "PATH_INFO" ) == 0 ) return 1; default: break; } /* lsapi_ruby_setenv(pKey, pValue ); */ rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen), rb_tainted_str_new(pValue, valLen)); return 1; } static int add_env_no_fix( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen), rb_tainted_str_new(pValue, valLen)); return 1; } typedef int (*fn_add_env)( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ); fn_add_env s_fn_add_env = add_env_no_fix; static void clear_env() { /* rb_funcall( lsapi_env, rb_intern( "clear" ), 0 ); */ rb_funcall( lsapi_env, rb_intern( "replace" ), 1, env_copy ); } static void setup_cgi_env( lsapi_data * data ) { clear_env(); LSAPI_ForeachHeader_r( data->req, s_fn_add_env, data ); LSAPI_ForeachEnv_r( data->req, s_fn_add_env, data ); } static VALUE lsapi_s_accept( VALUE self ) { int pid; if ( LSAPI_Prefork_Accept_r( &g_req ) == -1 ) return Qnil; else { if (s_body.bodyBuf != NULL) free (s_body.bodyBuf); s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; pid = getpid(); if ( pid != s_pid ) { s_pid = pid; rb_funcall( Qnil, rb_intern( "srand" ), 0 ); } setup_cgi_env( s_req_data ); return s_req; } } static VALUE lsapi_s_accept_new_conn(VALUE self) { if (LSAPI_Accept_Before_Fork(&g_req) == -1 ) return Qnil; else return s_req; } static VALUE lsapi_s_postfork_child(VALUE self) { LSAPI_Postfork_Child(&g_req); return s_req; } static VALUE lsapi_s_postfork_parent(VALUE self) { LSAPI_Postfork_Parent(&g_req); return s_req; } /* * static int chdir_file( const char * pFile ) * { * char * p = strrchr( pFile, '/' ); * int ret; * if ( !p ) * return -1; *p = 0; ret = chdir( pFile ); *p = '/'; return ret; } */ static VALUE lsapi_eval_string_wrap(VALUE self, VALUE str) { #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4) { Check_Type(str, T_STRING); } else #endif { SafeStringValue(str); } return rb_eval_string_wrap(StringValuePtr(str), NULL); } static VALUE lsapi_process( VALUE self ) { /* lsapi_data *data; const char * pScriptPath; Data_Get_Struct(self,lsapi_data, data); pScriptPath = LSAPI_GetScriptFileName_r( data->req ); */ /* * if ( chdir_file( pScriptPath ) == -1 ) * { * lsapi_send_error( 404 ); * } * rb_load_file( pScriptPath ); */ return Qnil; } static VALUE lsapi_putc(VALUE self, VALUE c) { char ch = NUM2CHR(c); lsapi_data *data; Data_Get_Struct(self,lsapi_data, data); if ( (*data->fn_write)( data->req, &ch, 1 ) == 1 ) return c; else return INT2NUM( EOF ); } static VALUE lsapi_write( VALUE self, VALUE str ) { lsapi_data *data; int len; Data_Get_Struct(self,lsapi_data, data); /* len = LSAPI_Write_r( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); */ if (TYPE(str) != T_STRING) str = rb_obj_as_string(str); len = (*data->fn_write)( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); return INT2NUM( len ); } static VALUE lsapi_print( int argc, VALUE *argv, VALUE out ) { int i; VALUE line; /* if no argument given, print `$_' */ if (argc == 0) { argc = 1; line = rb_lastline_get(); argv = &line; } for (i = 0; i0) { lsapi_write(out, rb_output_fs); } switch (TYPE(argv[i])) { case T_NIL: lsapi_write(out, rb_str_new2("nil")); break; default: lsapi_write(out, argv[i]); break; } } if (!NIL_P(rb_output_rs)) { lsapi_write(out, rb_output_rs); } return Qnil; } static VALUE lsapi_printf(int argc, VALUE *argv, VALUE out) { lsapi_write(out, rb_f_sprintf(argc, argv)); return Qnil; } static VALUE lsapi_puts _((int, VALUE*, VALUE)); #if RUBY_API_VERSION_CODE >= 10900 static VALUE lsapi_puts_ary(VALUE ary, VALUE out, int recur ) { VALUE tmp; long i; if (recur) { tmp = rb_str_new2("[...]"); rb_io_puts(1, &tmp, out); return Qnil; } for (i=0; i= 10900 rb_exec_recursive(lsapi_puts_ary, argv[i], out); #else rb_protect_inspect(lsapi_puts_ary, argv[i], out); #endif continue; default: line = argv[i]; break; } line = rb_obj_as_string(line); lsapi_write(out, line); if (*( RSTRING_PTR(line) + RSTRING_LEN(line) - 1 ) != '\n') { lsapi_write(out, rb_default_rs); } } return Qnil; } static VALUE lsapi_addstr(VALUE out, VALUE str) { lsapi_write(out, str); return out; } static VALUE lsapi_flush( VALUE self ) { /* * lsapi_data *data; * Data_Get_Struct(self,lsapi_data, data); */ LSAPI_Flush_r( &g_req ); return Qnil; } static VALUE lsapi_getc( VALUE self ) { int ch; /* * lsapi_data *data; * Data_Get_Struct(self,lsapi_data, data); */ #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif ch = LSAPI_ReqBodyGetChar_r( &g_req ); if ( ch == EOF ) return Qnil; return INT2NUM( ch ); } static inline int isBodyWriteToFile() { return ((s_body.bodyLen >= MAX_BODYBUF_LENGTH)? (1): (0)); } //create a temp file and open it, if failed, fd = -1 static inline int createTempFile() { int fd = -1; char *sfn = strdup(sTempFile); if ((fd = mkstemp(sfn)) == -1) { fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); } else unlink(sfn); free(sfn); return fd; } //return 1 if error occured! //if already created, always OK (0) static int createBodyBuf() { int fd = -1; if (s_body.bodyLen == -1) { s_body.bodyLen = LSAPI_GetReqBodyLen_r(&g_req); //Error if get a zeor length, should not happen if (s_body.bodyLen < 0) { //Wrong bode length will be treated as 0 s_body.bodyLen = 0; } if (s_body.bodyLen > 0) { if (isBodyWriteToFile()) { //create file mapping fd = createTempFile(); if (fd == -1) { return 1; } if (ftruncate(fd, s_body.bodyLen) == 0) { perror("ftruncate() failed. \n"); close(fd); return 1; } s_body.bodyBuf = mmap(NULL, s_body.bodyLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (s_body.bodyBuf == MAP_FAILED) { perror("File mapping failed. \n"); close(fd); return 1; } close(fd); //close since needn't it anymore } else { s_body.bodyBuf = (char *)calloc(s_body.bodyLen, sizeof(char)); if (s_body.bodyBuf == NULL) { perror("Memory calloc error"); return 1; } } } } return 0; } static inline int isAllBodyRead() { return (s_body.bodyCurrentLen < s_body.bodyLen)? 0 : 1; } static inline int isEofBodyBuf() { return (s_body.curPos < s_body.bodyLen) ? 0 : 1; } //try to read length as times pagesize (such as 8KB * N) static int readBodyBuf(const int needRead) { const int blockSize = 8192; char *buff = s_body.bodyBuf + s_body.bodyCurrentLen; int nRead; int readMore = (needRead + blockSize -1) / blockSize * blockSize; int remain = LSAPI_GetReqBodyRemain_r( &g_req ); //Only when not enough left, needReadChange will be changed!!! if (remain < readMore) readMore = remain; if ( readMore <= 0 ) return 0; nRead = LSAPI_ReadReqBody_r(&g_req, buff, readMore); if ( nRead > 0 ) s_body.bodyCurrentLen += nRead; return nRead; } static VALUE lsapi_gets( VALUE self ) { VALUE str; const int blkSize = 4096; int n; char *p = NULL; #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif if (createBodyBuf() == 1) { return Qnil; } //comment: while((p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1)) == NULL) { if (isAllBodyRead() == 1) break; //read one page and check, then reply readBodyBuf(blkSize); } p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1); if (p != NULL) n = p - s_body.bodyBuf - s_body.curPos + 1; else n = s_body.bodyCurrentLen - s_body.curPos; str = rb_str_buf_new( n ); #if RUBY_API_VERSION_CODE < 20700 OBJ_TAINT(str); #endif if (n > 0) { rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n ); s_body.curPos += n; } return str; } static VALUE lsapi_read(int argc, VALUE *argv, VALUE self) { VALUE str; int n; int needRead; int nRead; #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif if (createBodyBuf() == 1) { return Qnil; } //we need to consider these 4 cases: //1, need all data since argc == 0, we may have all data 2, or not //3, need a length of data (argv >= 1), we may have enough data already read, 4, or not if (argc == 0) n = s_body.bodyLen - s_body.curPos; else { n = NUM2INT(argv[0]); //request that length from currentpos if (n < 0) return Qnil; if (n > s_body.bodyLen - s_body.curPos) n = s_body.bodyLen - s_body.curPos; } needRead = s_body.curPos + n - s_body.bodyCurrentLen; if (needRead < 0) needRead = 0; str = rb_str_buf_new( n ); #if RUBY_API_VERSION_CODE < 20700 OBJ_TAINT(str); #endif if (n == 0) return str; //copy already have part first if (n - needRead != 0) { rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n - needRead); s_body.curPos += (n - needRead); } if (needRead > 0) { //try to read needRead, but may be less (changed) when read the end of the data nRead = readBodyBuf(needRead); if (nRead > 0) { n = ((nRead < needRead) ? nRead : needRead); rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n ); s_body.curPos += n; } } return str; } static VALUE lsapi_rewind(VALUE self) { s_body.curPos = 0; return self; } static VALUE lsapi_each(VALUE self) { VALUE str; lsapi_rewind(self); while(isEofBodyBuf() != 1) { str = lsapi_gets(self); rb_yield(str); } return self; } static VALUE lsapi_eof(VALUE self) { return (LSAPI_GetReqBodyRemain_r( &g_req ) <= 0) ? Qtrue : Qfalse; } static VALUE lsapi_binmode(VALUE self) { return self; } static VALUE lsapi_isatty(VALUE self) { return Qfalse; } static VALUE lsapi_sync(VALUE self) { return Qfalse; } static VALUE lsapi_setsync(VALUE self,VALUE sync) { return Qfalse; } static VALUE lsapi_close(VALUE self) { LSAPI_Flush_r( &g_req ); if (isBodyWriteToFile()) { //msync(s_body.bodyBuf, s_body.bodyLen, MS_SYNC); //sleep(5); munmap(s_body.bodyBuf, s_body.bodyLen); } else free(s_body.bodyBuf); s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; //Should the temp be deleted here?! return Qnil; } static VALUE lsapi_reopen( int argc, VALUE *argv, VALUE self) { VALUE orig_verbose; if ( self == s_req_stderr ) { /* constant silence hack */ orig_verbose = (VALUE)ruby_verbose; ruby_verbose = Qnil; rb_define_global_const("STDERR", orig_stderr); ruby_verbose = (VALUE)orig_verbose; return rb_funcall2( orig_stderr, rb_intern( "reopen" ), argc, argv ); } return self; } static void readMaxBodyBufLength() { int n; const char *p = getenv( "LSAPI_MAX_BODYBUF_LENGTH" ); if ( p ) { n = atoi( p ); if (n > 0) { if (strstr(p, "M") || strstr(p, "m")) MAX_BODYBUF_LENGTH = n * 1024 * 1024; else if (strstr(p, "K") || strstr(p, "k")) MAX_BODYBUF_LENGTH = n * 1024; else MAX_BODYBUF_LENGTH = n; } } } static void readTempFileTemplate() { const char *p = getenv( "LSAPI_TEMPFILE" ); if (p == NULL || strlen(p) > 1024 - 7) p = "/tmp/lsapi.XXXXXX"; strcpy(sTempFile, p); if (strlen(p) <= 6 || strcmp(p + (strlen(p) - 6), "XXXXXX") != 0) strcat(sTempFile, ".XXXXXX"); } static void initBodyBuf() { s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; } void Init_lsapi() { VALUE orig_verbose; char * p; int prefork = 0; LSAPI_Init(); initBodyBuf(); readMaxBodyBufLength(); readTempFileTemplate(); p = getenv("LSAPI_CHILDREN"); if (p && atoi(p) > 1) prefork = 1; #ifdef rb_thread_select LSAPI_Init_Env_Parameters( rb_thread_select ); #else LSAPI_Init_Env_Parameters( select ); #endif s_pid = getpid(); p = getenv( "RACK_ROOT" ); if ( p ) { if ( chdir( p ) == -1 ) perror( "chdir()" ); } if ( p || getenv( "RACK_ENV" ) ) s_fn_add_env = add_env_rails; orig_stdin = rb_stdin; orig_stdout = rb_stdout; orig_stderr = rb_stderr; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 orig_defout = rb_defout; #endif orig_env = rb_const_get( rb_cObject, rb_intern("ENV") ); env_copy = rb_funcall( orig_env, rb_intern( "to_hash" ), 0 ); /* tell the garbage collector it is a global variable, do not recycle it. */ rb_global_variable(&env_copy); rb_hash_aset( env_copy,rb_tainted_str_new("GATEWAY_Irewindable_input.rbNTERFACE", 17), rb_tainted_str_new("CGI/1.2", 7)); rb_define_global_function("eval_string_wrap", lsapi_eval_string_wrap, 1); cLSAPI = rb_define_class("LSAPI", rb_cObject); rb_define_singleton_method(cLSAPI, "accept", lsapi_s_accept, 0); if (prefork) { rb_define_singleton_method(cLSAPI, "accept_new_connection", lsapi_s_accept_new_conn, 0); rb_define_singleton_method(cLSAPI, "postfork_child", lsapi_s_postfork_child, 0); rb_define_singleton_method(cLSAPI, "postfork_parent", lsapi_s_postfork_parent, 0); } rb_define_method(cLSAPI, "process", lsapi_process, 0 ); /* rb_define_method(cLSAPI, "initialize", lsapi_initialize, 0); */ rb_define_method(cLSAPI, "putc", lsapi_putc, 1); rb_define_method(cLSAPI, "write", lsapi_write, 1); rb_define_method(cLSAPI, "print", lsapi_print, -1); rb_define_method(cLSAPI, "printf", lsapi_printf, -1); rb_define_method(cLSAPI, "puts", lsapi_puts, -1); rb_define_method(cLSAPI, "<<", lsapi_addstr, 1); rb_define_method(cLSAPI, "flush", lsapi_flush, 0); rb_define_method(cLSAPI, "getc", lsapi_getc, 0); /* rb_define_method(cLSAPI, "ungetc", lsapi_ungetc, 1); */ rb_define_method(cLSAPI, "gets", lsapi_gets, 0); //TEST: adding readline function to make irb happy? /*rb_define_method(cLSAPI, "readline", lsapi_gets, 0); */ rb_define_method(cLSAPI, "read", lsapi_read, -1); rb_define_method(cLSAPI, "rewind", lsapi_rewind, 0); rb_define_method(cLSAPI, "each", lsapi_each, 0); rb_define_method(cLSAPI, "eof", lsapi_eof, 0); rb_define_method(cLSAPI, "eof?", lsapi_eof, 0); rb_define_method(cLSAPI, "close", lsapi_close, 0); /* rb_define_method(cLSAPI, "closed?", lsapi_closed, 0); */ rb_define_method(cLSAPI, "binmode", lsapi_binmode, 0); rb_define_method(cLSAPI, "isatty", lsapi_isatty, 0); rb_define_method(cLSAPI, "tty?", lsapi_isatty, 0); rb_define_method(cLSAPI, "sync", lsapi_sync, 0); rb_define_method(cLSAPI, "sync=", lsapi_setsync, 1); rb_define_method(cLSAPI, "reopen", lsapi_reopen, -1 ); s_req = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_req_data ); s_req_data->req = &g_req; s_req_data->fn_write = LSAPI_Write_r; rb_stdin = rb_stdout = s_req; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 rb_defout = s_req; #endif rb_global_variable(&s_req ); s_req_stderr = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_stderr_data ); s_stderr_data->req = &g_req; s_stderr_data->fn_write = LSAPI_Write_Stderr_r; rb_stderr = s_req_stderr; rb_global_variable(&s_req_stderr ); /* constant silence hack */ orig_verbose = (VALUE)ruby_verbose; ruby_verbose = Qnil; lsapi_env = rb_hash_new(); clear_env(); /* redefine ENV using a hash table, should be faster than char **environment */ rb_define_global_const("ENV", lsapi_env); rb_define_global_const("STDERR", rb_stderr); ruby_verbose = (VALUE)orig_verbose; return; } PKu]W q,,#ruby-lsapi-5.5/ext/lsapi/lsapidef.hnu[/* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _LSAPIDEF_H_ #define _LSAPIDEF_H_ #include #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif enum { H_ACCEPT = 0, H_ACC_CHARSET, H_ACC_ENCODING, H_ACC_LANG, H_AUTHORIZATION, H_CONNECTION, H_CONTENT_TYPE, H_CONTENT_LENGTH, H_COOKIE, H_COOKIE2, H_HOST, H_PRAGMA, H_REFERER, H_USERAGENT, H_CACHE_CTRL, H_IF_MODIFIED_SINCE, H_IF_MATCH, H_IF_NO_MATCH, H_IF_RANGE, H_IF_UNMOD_SINCE, H_KEEP_ALIVE, H_RANGE, H_X_FORWARDED_FOR, H_VIA, H_TRANSFER_ENCODING }; #define LSAPI_SOCK_FILENO 0 #define LSAPI_VERSION_B0 'L' #define LSAPI_VERSION_B1 'S' /* Values for m_flag in lsapi_packet_header */ #define LSAPI_ENDIAN_LITTLE 0 #define LSAPI_ENDIAN_BIG 1 #define LSAPI_ENDIAN_BIT 1 #if defined(__i386__)||defined( __x86_64 )||defined( __x86_64__ ) #define LSAPI_ENDIAN LSAPI_ENDIAN_LITTLE #else #define LSAPI_ENDIAN LSAPI_ENDIAN_BIG #endif /* Values for m_type in lsapi_packet_header */ #define LSAPI_BEGIN_REQUEST 1 #define LSAPI_ABORT_REQUEST 2 #define LSAPI_RESP_HEADER 3 #define LSAPI_RESP_STREAM 4 #define LSAPI_RESP_END 5 #define LSAPI_STDERR_STREAM 6 #define LSAPI_REQ_RECEIVED 7 #define LSAPI_CONN_CLOSE 8 #define LSAPI_INTERNAL_ERROR 9 #define LSAPI_MAX_HEADER_LEN 65535 #define LSAPI_MAX_DATA_PACKET_LEN 16384 #define LSAPI_RESP_HTTP_HEADER_MAX 32768 #define LSAPI_PACKET_HEADER_LEN 8 struct lsapi_packet_header { char m_versionB0; /* LSAPI protocol version */ char m_versionB1; char m_type; char m_flag; union { int32_t m_iLen; /* include this header */ char m_bytes[4]; }m_packetLen; }; /* LSAPI request header packet 1. struct lsapi_req_header 2. struct lsapi_http_header_index 3. lsapi_header_offset * unknownHeaders 4. org http request header 5. request body if available */ struct lsapi_req_header { struct lsapi_packet_header m_pktHeader; int32_t m_httpHeaderLen; int32_t m_reqBodyLen; int32_t m_scriptFileOff; /* path to the script file. */ int32_t m_scriptNameOff; /* decrypted URI, without pathinfo, */ int32_t m_queryStringOff; /* Query string inside env */ int32_t m_requestMethodOff; int32_t m_cntUnknownHeaders; int32_t m_cntEnv; int32_t m_cntSpecialEnv; } ; struct lsapi_http_header_index { uint16_t m_headerLen[H_TRANSFER_ENCODING+1]; int32_t m_headerOff[H_TRANSFER_ENCODING+1]; } ; struct lsapi_header_offset { int32_t nameOff; int32_t nameLen; int32_t valueOff; int32_t valueLen; } ; struct lsapi_resp_info { int32_t m_cntHeaders; int32_t m_status; }; struct lsapi_resp_header { struct lsapi_packet_header m_pktHeader; struct lsapi_resp_info m_respInfo; }; #if defined (c_plusplus) || defined (__cplusplus) } #endif #endif PKu]((#ruby-lsapi-5.5/ext/lsapi/lsapilib.onu[ELF>@@=< 02/3.4-5ff.ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=DÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH=1tIH=HcH5HH[ÉD1?H=HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHtHHtHHtH{@Ht1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDHu48u uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=HcB$HH@H,H9rZf.HH9vGH3LuHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L=L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$)H8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L LfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH L$DIH Ic LEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcUff.AWAVAUATUSHXHt$ HT$dH%(H$H1HIH1E1L-HL%HHHcHcT4t/HHAAtIL{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eHthILM)MUI9t HtDL+t$HL[]A\A]A^A_DM@@M)(IHt$HLHk8f.HAVLAUIATIUSHu\H߉AD${LǃLSHu0{L[L]A\A]A^[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIHLc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAMt$PHLIFID$PA:I|$PMD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHAI\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1HL$Aߺu#DHuDo߻D HDeOAkDH}An}NHtff.USHdH%(H$1HHu/HH$dH3%(uHĘ[]@1H=tAUATA'USH'DNuDH@AHHHHtH-ƉljUDk HDcEufH H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0ALJt` A1LHcIHIGAo IuID%D-B(AA1IcH4IILI 9HqH= IJDB(9xHqH= XIJB($AD$IKAzHL$;MbfoLt$ LAoL$AT$Ml$)$ LLHL$LHLLH$ID$H$I3L$H1H D$$Dl$EDDl$H=IHIDMH=t"LDLŃP|$Et$A9uHt$DŃ5$A?D5t AH5LHtHHf)#AH51H@H51LH 1HIH51H51D%DD$H=IHtZEW7E1111H=H51E|$M2;|$E1H5LuI}Ń1H5LKfD=-ED$AIFH51HH)H5H11H5L 1H5LA#LH H1H5Laff.AVAUATUSHdH%(H$1D$ HH ;1Ll$Ld$Lt$ Hkl{ul;LLD$CHHt@HHt{1f|$=u|H4tH舴Hd1H$dH3 %(u}HĠ[]A\A]A^D {H5Hfы{LA;ff.AWAVAUATUSHD=dH%(H$1ExHH-H};DH-Ht 1HEDEH$L|$PDcA:E1AfD EDEtHHt @fLH1HIcDHD$PHD$XA ?)ѺHH D9#11A|$MHD9#HHt @D9#AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$LH$LHHD$@AHLDŽ$hH$H$LHHD$0PH$LHHD$8+H$`L HHD$(H$ LHHD$HADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%EHHt H=1IL9t<1ձL5EDu EME1VHLH1HHc}}LD$LHD$PHD$X ?)ѺH1H T`1 8Ht$(1ҿ x=_5tHHt @f,D9# DCHHt@HHtDc1DN ={H5HHHt*HHB(@HHt@HH@8B-DAD9M==H HtDHHt A9HHtD҉T$$DE ~:E~5T$$AAAuDE UM D9vHAHtDH51D$0 H=T$fD}蠩C1mH|$IH|$HT$Ht$161E Mt AMgMg{E1CHt$1ҿH=f;>fDD$$0d T$$WH=T$T$fDD#AfDRDEBHH29{H5H{wH=H=0MAH… H{HH=Ht$1ҿHL=HHHtH11L=AGHHt{1蝦D-EuHHt!E9~;t Ht$@1ҿL$Ht$01ҿHt$H1ҿHt$81ҿHt$(1ҿ kHLSH$$L$H=%,H=QHHt*fC1CD$CCT$HC(HC fD=ff.@H,LSLSLSLS GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realignAnonymous mmap() failedlocalhost%02d:%02d:%02d [%s] [UID:%d][%d] %.*syesnosystem()%s, errno: %d (%s) /dev/nulllibpthread.sopthread_atforkHTTP_[UID:%d][%d] %s:%s: %s LSAPI: jail() failure./etc/Can't set signalsaccept() failedLSAPI_STDERR_LOGPHP_LSAPI_MAX_REQUESTSLSAPI_MAX_REQSLSAPI_KEEP_LISTENLSAPI_AVOID_FORKLSAPI_ACCEPT_NOTIFYLSAPI_SLOW_REQ_MSECSLSAPI_ALLOW_CORE_DUMPLSAPI_MAX_IDLEPHP_LSAPI_CHILDRENLSAPI_CHILDRENLSAPI_EXTRA_CHILDRENLSAPI_MAX_IDLE_CHILDRENLSAPI_PGRP_MAX_IDLELSAPI_MAX_PROCESS_TIMELSAPI_PPID_NO_CHECKLSAPI_MAX_BUSY_WORKERLSAPI_DUMP_DEBUG_INFOnobodyLSAPI_DEFAULT_UIDLSAPI_DEFAULT_GIDLSAPI_SECRETLSAPI_LVE_ENABLELVE_ENABLEliblve.so.0lve_is_availablelve_instance_initlve_destroylve_enterlve_leavejailLSAPI_PHP_LSAPI_PHPRC=packetLen < 0 packetLen > %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGINFONOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveRangeX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

    Resource Limit Is Reached

    The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
              ^ d/4-//// %-/Ga '9 (_intG )@/G G @ @ G @ G     G  `@ A C $E (J 0NL8PX@[+H\+X]+hj$xp4G- - N1 ooGGXa&& E18: ;1?A B C1GOI JK1 OQ RS TU1ac Ed EC^&e&g1 Y[ E]ah 1l5no 1tfv Ew x@ Cp3&5&<&Db_rtL&VO&i&p&y5G1$ +& ( * 0 { f|HCIRT Cv&"7&$ R  E+v"&T.1 4 c G@4HH//-Gldy"m - 911; CmGFy<d(eGfI@I@IEIE"1 36 |7 |8 |9 | : |(; |0< |8= |@@ |HA |PB |XD `F hHpItJ xM9NNO Q Y [ \ ] ^ E_ `b g+J  G J J  G4'  < ' ' '   T h4I ' T X@!      !!"! ! ! ""F " E" #!X@$  i0%9"# # # 4  G  "&4 &6 &7  < |"0'1 '3 |'4 |'6 '7 '8 |'9 | ': |(jtm8(, ( ( ( (  ( (((( ( ((0|< G'), ') ')'), ') ')H*! B@,H      !"#$%&'()*+,-./0123456789:;<<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'-$|'-2 '-7 '-; .U.m.4/"/*/!B@/) !)./23\^bgl00/{C/&/ &/ -&/ =-G=GMG"/h/ 4M'/h'/h"// ///-GK/,/ ///M/K0050708090: 0; F 0<0= | 0>( ,"n11 1 GkB@2,     C2q&2s9&2t"2k2m 2n 2o 2p 2u",22 2 92 9 2 92 92 92 92 9 2 9$2 9("222 4G9G"22 92 92 92 9 "2G2 92 9"2o2"2"/" / 1 | 2 | 3  4 k : < = ? @ B| C  E|( F|0 G|8 I|@ J|H K|P L!VX O ` P h Q p R x T'\ V'b W'h X'h Y' Z' \'n ]'t _| `| a| b| c| d e f g h iL k'zL m'G(L n'8L oE "0pVr s uhvwxz{ |(vGa=G q' s w9   EM X9    $EM x7=RH H"XOYbufP =Q YinRG-G?]!NB@j~            9     H  H  H  |      l "G * ^GN G t N  t G M>CQ L L @  J l E m  9    9#!  9 9 #! @! !9Z! #!  g!F!9! ! |'  ! m!        # # *"G&%" K "  K@ V#          ( 0 8M " z# V# @      #  -     H! x$2cnt!U$2pid'U  : YO%2buf'#!U#in>74r"4TsUs]4U T 4UsT  [5m4UsT 5UsT ,5UsT Q5UsT v5UsT 5U ʳY5U YU ;W6%;O";#;Y2x6k%2w~}׳6U2T~QwY7U 9Y,7U YK7U Yj7U Y7U Y7U ;Y7U Y7U <ytY,8U YK8U G<Yw8U ;Y8U ;Y8U <Y8U Q;Y'9U YF9U ^9Us<Y9U Y9U Q;{X9TvQ | $0.MX] ":!p], _ ":3:=GE `: E- G % :!p%) %2| %= ' :len( end) |:=G ;i pw!)p7 2;env ! )del! D TD ( ;*$U(;**U(<*'U(G<*&U(v<*$U(<*"U( <*U( =   H  -5+fd ret    ~ Et;=   5 >__d U| $ &585> 8! O EOOOOw PyPz%P{2P|?P~LPYPfPsPPPPtPtPuPvNPP p?P>QT?Q?U  y @y!y 9C@7@Ä*UvT|Q@T7@U}C AUAT|Qt7"AU}CGAU?T|QtClAU2T|QtCAU:T|QtCAU3T|Qt3AU OAU0KQ BU|[%BUV3KBT}Q0R0XtC|BU:TtQ0BU T BU [WVBUu7BUthCUtTAtDCU0TtQtLtCU2TtQCU  CU CU  DU 8DU tiDU2TtQ03DU0T0Q DT0LCDUATtQ0CEU?TtQ0C8EU3TtQ0C\EU2TtQ0CEU:TtQ0EU QU  ?yj"FQy-?y+Qy+y #/ y+y #  yy*T Q8ly 9G~y+y yy*T Q8zqQGUsOhGU03GU|TvQ0R0X[WGU|GU|T0Q HU LGHUs?Ãsx_HUsHUs?ÃsqpHUsOHU0M M M .5+ O 4 P 4Q }R E} S retT  V z#EactX ~;I   5I__d ;1J  #JU T7VJU|CJUATvQ 7JU|CJU?TvQ CJU2TvQ CKU:TvQ C@KU3TvQ 3[KU OrKU0KQKU}[KUV3KT|Q0R0XC LUAT Q0C2LU?T Q0C[LU3T Q0CLU2T Q0CLU:T Q0LU T LU [W )MU HMU gMU VMUu> @N > +5+5N C 4OU0L pO  *5+  y6 GOy!y@ 7NÄ 9O*UsTwQ@3OU0T0Q OT0LQ: Q : @z# ; 95+act=  =  = % = / >  >  ?  @ retA pidB  C 4 D 4 E  F E H  I FP   FQ__d )  D/ 1T+ : 6R  ,        %RU T   F lY  *  5 =X~ret pfd YSYUUTsZqYUsTv88 Z 8 ' 8 @ : Zp; | < |res=  = , > ? ZG -[  6[  Gret fd  D  ZT1Q0ZUsT2Q1[UsT1Q2RDX4?[UsTvQ} ][UsT|L,[Uv 8 [  /5+  B!len LF[ch )   ^  05+  C  ,   len ;\ch ;\ch 57]  U|  x]TTQ~  ]T}Qv]UvU} t^* 25+U- Ä F^  05+#fn !#arg ,E@p_QTRQt Fp_ t )5+#fnu !#argu ,E@p_QTRQ6a s` a 6h#nb #fnb (#argb 3E d #hrete qX} b  ,5+#fn !#arg ,Ei len! " |ret# $ ;Zb7 Z}p8 | 9 | : | ;  < &t < -t5(achK % O Fa__cO 9 ̋F 1b݋r}U~T}#X|3bUv3$|"T v2$}"X|$_d /5+#fn!#arg,Ei len  |ret  _d~5c |  &t -tEdUwQ R E=dUwT| $ &Q R 3QdXvA"pd=G d2v1'U2v27T|'f (5+ ; #h #h['ff$Ff$9fSf^fNkfelfwfffffUffUff9RU|Ts3$"RU|q|f q-5+ q@is t |)p | |  &t -t)ch) )__c8< -g </5+ <B!len<O >  ?p@ A - B -retC iovDg E  gGh $5+ret n .ph6$)CP]qTshhUshUs?Ãs^(iNi*'5+U "\  -Ä -j +5+ 5#offBj N "\ jÄg5jUs*RjT~Q8Z^yjTTQQRR^8 - k (5+ ;!lenH "\  p! " - # - $ - %  - l .5+ ;| Hlen -    l$UvQ|-o ʊlۊ@U~TvQsln -5+ :| G THlen -  -  |  |  |p |  >n#nTQsTQsmo no% ooU~jUT:Qs]mo -5++moo%ooUs o .5+  len -|Sp*+5+U 5off yJqp y&5+(nYp n%5+-`t}$qKzq K*5+h-qUsgEqUseqUs?Ãs^Us-r -%5+hqUsgqUsqpqUs^Ft %5+=X~ElenF ~~ ?yPsQy-?y+Qy+y / y+y   yy*T Q8zqhsUssT0sT|Q}sT0xsUssUv?ÃsqptUs8tT6Q1R~X4 yt*(5+Ut@FtU %w (5+#fd2  `Tu}$q  uvT Y' >vk%'w~~׳/vUvT~Q~ HveY'U T2ʳvU vUsT vUvT1wU0wT0( Sw2cb;*UD Tx EۄwU=T ۄxU:T ;xUIT1WxU2T1t{xU T0xU T1T A y A%5+lenC D 4/y!fd4) 6 /y?yG+^y!fd+,s y!fd5 y!fd 7y!fd.!pktN\ *z *5+ 4   |  | Wz 65+ D z D.5+uidF gidG H I J#h K#hiL 1 >{ 1.5+ 2|!len2 2+| 26 4 5>{-N{G { '5+!uid3L!gid>@ Prv pw! { 6 | +5+#uid7L#pwL!ret  Tw3o|UQTs|U T Q|Xs}|UvT Q0 $} ,5+!uid8L) ret  r} -5+r} } }G}=G#4}6{  {,5+ {? {R} ":_n~ i~ ~$zUvT Q1R X rf~U|Tv*~U2DrJ [ J%stLSfdM ) zrc+   )uid  -5+  i ) &t -t7 O 35+i F2bp|) &t -t7v /5+pb7 )Hp |b6t Y t4h tB*u! Q u#| w#h x xh!fdh j=XlenkF R ف R<ف SH S+ U#hh> >>\ >L)bF62 G 235+ 2=p4 |vTv$ Ă $+5+!n$5p&  05+ :  | i!fd 2i < Gret  n  -!fd' 2E!len?ret -7 у 35+ !fdret 6 U#fd# +val UsT3Q0@UUT47wф wJ\ x&!lenx0tR :A  A A2EsaC~CWUvT0Qs7oUsCUvTsQ0:8 υ2sig8!U:3 2sig3 Uu (7   .mUs@U T QURTvvwxfmt'PVbuf Tvyp |z Eap  u5VtvEuVtm u{iևzU|T Q1R X \i/XzU|T Q1R X õuUsT0ϵUsTu +۵T1Q}Ru\i-zUsTdQ1R X Yv3$" izUsTdQ1R X  > [[OT1Q X|rW  :5+ D.|ʊ|."-" "E"%.k|6kkk.\|`\\.>E>E>>.'E̋'E''.EG.8 18.did d<P.A]__sA]__nAAP.%|Ռ%%|sz' 8n n8i i8 B  BS.)s))PW11W"m"m,moooo-o ʊۊ@U~TvQ|,aq$ÃSу G$% L8Us+ $Ã, )6CP]UvQ|,Ot  OfT0,YYYYY}YYY}Y}YYG g)U|TsQ N ʑ)UvT|Ql  UsT0Q: ` T}q ̋ ݋ Uv 6\ SG) U|T:51U|T )OU}T]AzU}T0Q}R}NU|[U},UUUUQUQVV[UC ה$UUUUVVNVV+VU T|QgU TvQ3VUu,flEfggg,g9gDgQg^gkgxgf< ggf%g,g9gDgQg^gkgxg e6)CP]qTwQ2R} Z ÄgU~U~?Ã~*7U2T~,9= ::п `:b :}:r::_:: , 2sUwT 9 %ɌUsT|Q јTvQ0 3:g 6E:R:HGeY'UsT AQ UsڙUvT2LUvU2T1}U0T Qs9 ]  :% :}U0T QU,jjjjjjjjjkQk j jjjjjjjjkk S $Ä? cUTQvg{UsgUs^,[[[[}[ [$[$[>[,[>[3g[U|- TvQs,Y8YYYYYYYQYY@tUUTT,{X!#XXX-{X XXX՞U@T1[UU,x xxx oO/ʊ  ۊ@UsTvQ| xA hxxx߁1V۠O  o@iš%8ʊۊ@U}T|Qv yn yyzz~zA %Aˁ+5R %5ˁvT v $ &33$A %Aˁ+5R %5ˁvT v $ &33$  wODO X]%j v v[ v v v6 v vȦ v-vS K$% >#)&+v %O23@ v  v ڨ$ v $-v $*z1 ԩ"?o363A* @ 'n* A * A B1B( 1 : ; 9 I8 41B11 4: ;9 I 1RBUX YW  : ;9 IB 4: ;9 IB : ;9 I I: ; 9 I4: ;9 I1RBX YW .?<n: ; 9 4: ;9 I4: ;9 IBI41 U.: ;9 'I : ; 9 I!I/ .?: ;9 'I@B4: ; 9 I41 : ;9 I8 .?<n: ;9 I!: ;9 I" : ; 9 #: ;9 IB$1% & : ; 9 I'4: ; 9 I?<(.?: ;9 '@B) *: ;9 I+1RBX YW ,.1@B-1RBUX YW ..?: ; 9 'I 4/$ > 0(1 : ; 9 2: ;9 I34&I5 6.: ;9 'I@B7.: ;9 ' 8.?: ;9 'I 9'I:.: ;9 '@B; U<7I=!I/> 1?1B@B1A.?<n: ; B> I: ; 9 C : ; 9 D.?: ;9 'I@BE4: ;9 IF G5IH4: ;9 I?<I : ; I8 J<K : ;9 L : ; 9 I8M: ;9 IN 1UO 1PQ41 R'S1X YW T.?: ;9 '@BU 1UV4: ; 9 IW.: ; 9 'I X> I: ; 9 Y : ; 9 I8 ZB1[1UX YW \1RBX Y W ]: ; 9 I^% _$ > ` a : ; 9 b : ; 9 Ic'd&eIf : ; g: ; 9 h!i(j : ; 9 k : ; 9 l4G: ; 9 m'InB1o.?: ;9 'I@Bp4: ;9 I qrBs.: ;9 'I t.: ;9 ' u.: ;9 I v.?: ; 9 '@Bw: ; 9 IBx: ; 9 IBy4: ; 9 IBz4: ; 9 IB{1RBUX Y W |4: ; 9 I}1UX YW ~.?<n.?<n: ;9 6ddqd T)TuPPP(PPsPPKP[P"R+RRJQ^Q5Q5<v <Q{ PTt _X ~XX[TiT2TAXX[P[aQxT4T@PP{P{t XRr t;# $  %!r"p;# $  %!r"u?[gRSRbRHRQRR {RTKTiQX%vXvzr TiTTQq Ru .Q2QHQ+Q4QQoQQ;QQXP iR~Rv FRFW{ _Rz QK$KU$KKVKKUKIKTIKKSKK|hKKTK.KP.KPKQpKuKQuK}K?p K$KQ$KLKUpK}KU3KFK q 3KFK03KFKUQKpK8QKpK0QKpK\pKyK 7p yK}KQpK~K0pK}KUKK@KKUKKSKKVKKXKK0KKSKK|hJlJUlJJ]JJUJJ]JJUJJUJ0JT0JJSJJTJJTJJSJJTJJs@JJSJJSJJQJJ^JJQJJQJJ^JJ^7JTJPWJZJp?ZJaJPaJtJ\tJJPJJ_lJJUJJ | v"|JJ_|JJSJJTJJT|JJUJJ | v"JJ@JJSJJTJJs@JJ}JJ ~ JJQJJ\JJu`IIUII\IIUII\`IITIIT`IIQIIVIIvxIIVIIV`IIRII^IIRII^`IIXII]IIXII]dIITdIIUP@c@Uc@CVCrDUrDEVE.EU.EeEVeElFUlF;GV;GTIU@@P@@P@@P@APA0AS0ACAPVAiAP}AAPAAPAAPABP$B7BPKB^BPrBBPBBPBBPrDDSDDPDEPEEPEESlFFPDDsp"1DDP@@P@@PjApAPAAPAA0AAPBBPDDPDD0.E4EP:EQEP~@A0A!AP$AC\rDDPDD\DD0DD\DE0EE\lFF\FF0FH\H@I\EITI\@@P@@PAAPAAS5ACAP[AiAPAAPAAPBBP)B7BPPB^BPwBBPBBPBBPFGP"G,GP'CQCPE#EP HQHPFFPG!GP;GPGPPGTGUTGGVHHVHHQHHVI;IVEITIVFFPG!GPDGPGPPGTGUTGGVHHVHHQHHVI;IVEITIVWGpGPpGGSHHSI%IS%I6IP6I@ISEITISDGWG0DGPGPPGTGUTGWGV`GeG}eGpGQpGqG}`GpGPpGqGSGG@GG GGS]CtCP{C}C0G HP H HPfCtCPHHPHIS]>,?0,?C?]p;u<0<<P<=]=>]>,?0,?C?]p;u<0u<`=}=>}>>T>>}>,?0,?,?},?C?0p;u<0u<@=V@=V=PV==V==P=>V>>V>,?0,?0?V>?C?0p;`=S=:?S<< s $ &<<U=>0Z>c>0c>{>^{>>~>>~~>>~: ;U ;/;S/;0;U;;P99U9:S::U::S::U9S:\::S::@::6::W::4:: ::H4U4U U $$6U404^^ $^$6040000T9r0? $0404_\_\mm_ $_$60404K\KV\V\ $V$60SS 6S]] 6]USUSUST.V.T  wS  P ' S' W v(d r Pr x S     p`# p`# <$ c ~`# <$d x ~`# <$ vv" P c ^d x ^  \  0  P  S89P8:9QP+ PQQ + Q # 0 # 0 # P  U s U ) P) > S> k Pk n Sn r Pr s S 7L7UL77U 7H7TH7w7Vw7x7Tx77VM7Z7Px77P55U56V6?6U?66V66U66V66U56T6?6T?6F6TF66\66T66T66\66T66P66P66\T6g6Pg66S66UF66]66n2(3U(34\44U223T23(4V(404T044T223Q234]44Q63Y3PY3c3pc3t3Pt3~3^33p33P33S34P4,4,4h4L3p3Qp3~3R33Q33R3 4T 4 4tp 44T414^4(4V(404T0414T404|I4R4QR4S4VI4R4TR4S4]I4R4|_(l(Pl(v(u_(v(3_(l(ul(v(P''U''U''U''T''Q''T''T''Q''R''Q''QP''U''U''UP''T''Q''T''TP''Q''R''Q''Q0`U`SSU0`T`^TT0`Q`VQVQQ0`R`]R]RRD\~1$~"3$U"T $ &33$U"\~1$~"3$U"T $ &33$U"\`iP{P0%%U%&S&&}&+'U+'9'}9'@'U@'E'U0%%T%&_&9'}9'@'T@'E'}0%%Q%9'|9'@'Q@'E'|%%V%%vb%%0%%p 9'@'0%%Q&&Q%%P&&Pb%%0%%^%%~%&^&'}+'9'}9'@'0c&u&}u&&]&&}&&}&&]+'9'}K&&_+'9'_c&&S+'9'SK&X&V_&u&Vu&&}&&t&&T&&}#+'9'V%'\+'9'\&&P&'}+'9'}&&V&&v8$8&2$p"&& v8$8&2$p"c&c&5c&c& c&c&^#|$U|$$U$$U$ %U %%U%$%U#w#Tw#$S$$T$%S%%T%$%T#w#Qw#$V$$Q$%V% %Q %%V%%Q%$%Q##P##p$$0$$0$$^$%^<#w#0##r ##t %%0##Q$$q$!$qpI$Y$RY$m$q %%qp$$P$$P$%P<#w#0w##\##|#,$\,$_$|_$$\$%\ %%\%%0$!$T3$m$T %%T%%q`$!$X>$B$RB$$X %%X#$P %%P#$Y %%Y !U!7!S7!p!wp!{!{!!U!!S!*"w*""U""w !T uF!q!S!!S!!s""S""P""P{!!|I"o"|o""P{!!VD""V""v""V{!!_I""_{!!}D"d"}{!!]""]{!!^""^o""q2$u"""q2$u"o""v8$8&2$u"""v8$8&2$u"""v8$8&2$u"((U(=)S=)>)U>)Q)UQ)b)Sb))U()0) )P!)&) &)<)P>))0(( uu@()Q>)Q) uu@b)|) uu@()P( )s ))T))s()s()Pt u T p p# p`# tp# Q P 4 T2D2UD22S22~~22U22S22~~22U22U2D2TD22V22T22T22T22V22T22T2D2QD22]22Q22Q22Q22]22Q22Q2D2RD22\22R22R22R22\22R22R2)2u)22^22U#22^22U#22uU2Z2|Z2u2PU2u24U2u2^`U< ]< H UH b ]b k U`T< VH b V`Q5 SH [ S[ ^ sp^ b SP}q $ &}} $ &P\H b PP0< \H b \P\V 0 SH H S 0 VH H V 0 ^H H ^ PH b P  S  V  ^ZUZ^UH^H\UQTQ]TH]H\TZQZHQH\QZRZ\RH\H\RlSHS?ZSZ_H_HRSP\QTQZ]ZVUVVUHVH\TT__PPSS__UVU(4^(3 p $ &37 s $ &USUSUUSss $ &0yTyTMYQYn t2$x"#4nyRU)S)*UUPU0//U/0S0 0U 0#0S#0)0U./U/[/S[/\/U\/a/Ua/o/So/u/UWWUWXSXXUXYSYYUYPYSPYUYUY#YsY#YsY#YsY0Y Y#Ys U S"U"rSrU'T'V"]V]_P_rVrTdlP3  303}@3}S?LPL}\V]d2]d 3JP,2,U2,h,Vh,k,Uk,,V,<,T<,j,\j,k,Tk,,\,G,QG,,Q-,H,0H,L,Pk,,P,,R+:+U:++\++U++\+:+T:++^++T++^+:+Q:+V+SV++Q++P++p $  $-(q++ q++  U uh U T T q Rq w Rw y Ry R q Zw Z 0  [  p * X- q [q 0 0 T t  u|#- 4 T4 7 pD W T^ b tb q u|#q 00 C UC n Sn p Up w S0 G TG o Vo w TH _ P_ i sp u P U S U S U U S T V T V T V P P P0_U_VUV07T7\T\@JUJrVrvQvwU@UTUcScvRvwT@UV}U}V.U.VU@T|]|}T}.].5T5]v\S} S R.:v:\S\S P}Pv  \c c c\SWRWXuSWQWX]SWs} }d}S dUS.  (s U  S  U  S $ U$ * U Q$ * Q P ) P) * u t $ & P  \  \ T  V  V  ^  ^ P ] $ P \ V ^G P P U V U VU T _ T _T Q \ Q \Q R ^ R z^zRR P S %P%XSXdPdS R ] ]R U SS(S T VT9V 4}4]}*\kPS(P(QS*S04^0QTPThSsS'<'<S',},<\l\UvFQSs0s0s}Q | Q|V\dUdU}P_U_/0/LPLn__UdSPnSSPSdnPPQQRX))U)*^**U**U**U**U))T)*~**T**~**T**~))Q))w)*Q**Q**Q**Q**Q))Q))w)*Q))T)*~))U)*^**S)*~*`*_`*v*v**_&*f*Qf****}x**Qj**]**P{**P**]{**2{**w{**~{**P**]{**2D*T*qT*j*PD*j*6D*j*\,-U--V-T.UT..V..Q..U..U..V..U..V..U,- T.q. .. .. .. ,-W--ST.q.S..S..S..S,-U-{-V{--ST.q.S..U..V..S..V,V-0V-h-U..0r--P..P- - - -W{--_--\{--S{-- -.S*.T.S..S--P--V*.;.P;.T.V..P..V-- A--Sq..V..Q..U000U01S11U11S11U11S000T0111T1111T1111T11000Q00V01Q11Q11V11Q11V00V01Q11Q11V01111101S11S11S00]0 1T 11x1b1Tn11T11T01V11V000F1^F1R1rpR11^11^0-1_-151x511_11_0b1Yq11Y11Y11Y00R11R11 @00400T11V1111_45U5%5U%5/5U/55\55U55\55U45T5%5T%5F5TF55V55T55V55T45Q5%5Q%5P5QP55Q55Q55S55s55}%55S55}55S55P55st"%575P75F5st"1F5f5vs"1K5`5T`5b5tpb5f5Tq55Sq55Vq55|7 7U 77U77U7 7T 77T77T77U78U88U88U77T78V88T88V88T88V77Q78]88Q88]88Q88]77Q78]88Q88]88]77T78V88T88V88V77U7^8\88\K LU LWL_WLLULP_P$PU$POW_OWTWUTWW_LLP,LWL\LL\,LWLVLLV,LWLSLLS=LGLPLLP,L=L\,L=LV,L=LSLP_OPOW_TWW_qMMPLPSOPDUS\UOWSTWWSLL1LLPLLQ8MqMV8MqM\.MqM]NMXMPqMMP8MNMV8MNM\8MNM]MPSOP,RS\UUSV0VSW/WSMP_OP,R_\UU_V0V_W/W_MM p1OPQ p1MP\OP,R\\UU\V0V\W/W\MNVMNMNMNVMNMNMNPNONVNONNON!NONV!NON!NON8NONPyOO_RiR_RDU_\UV_5VV_4WOW_TWW_yOO#R,R#\UhU#yO{O0{OOPOOpOOPOOROPQ_OPQPOPkPpOPQpSPkPQkPyPp kPQp oPyPQyPPpyPQp}PPQPPpPPpPQp PPpPPpPQp PPpPPpPQpPPQPPpPPp PQp PPp!PPp$PQp$ PPp%PPp(PQp(PPQPPp)QEQPEQIQp"Q'Qp1$q""Q.Qp1$q"3QEQQ3QEQQ6QEQRiQQPQQppQRPpQRQQQPQQppQQPQRppQQRQQRQQRQQR\UU_iUUPvRRVvRR_RRPRU_UV_5VV_4WOW_TWW_RDS\DSGSPGSSwST\UU\UU0UU\RKS]KSSPSS~ST]UU]TUPRU0UV05VV04WOW0TWW0R SZ SSzhUUzhUU0 SSZUUZRRpRSXUUX_SS__SSz|_SSRSS~_SSz_SSzSS\SS}pSS@SS SS]TT0UV05VV0VV04WJW0TWW0WW0T T~UUP8VXV\VVVTT_UV_5VV_VV_4WJW_TWW_WW_^TpTPyTTPTTPTTPUUPUVVAVXVPiVVPVVPVVPVVVVVP4WIWPWWPWWVT2TP2TT]UUP5V@VP@VXV]XVzV0VV]VV]VVPTWW] TT_UU_XVzV_VV_TWW_ T3T 3T;TPTWgWPhWW_UUHUU0UU U4UU4UU4UUDU U4UPJP P$PU$PJP_.PJPP,d       9>ACFQxx| *)SX 05:@nOh"'3"'3TY}O[]dRV] 0 P P  0 P P {!!!"""{!!""`"h"p""""`"h"""%'0'9'.&5&B&G&c&c&_(e(l(v(((() )))* **`*f*{**D*D*I*Q*;+>+c+n+q++,,,-X.x.....,,- --.0.X...0111110000U2U2`2j2D3c3k3~333334%4,41464<4I4S455+5555q5w5{55777 8 888888s:}:::s:}:::::::::O<T<<<<<=>`>>@@@@BQC E0EFH HXHHHI;IEITIFGHHI;IEITIDGGHHI;IEITIQCChEpFH HXHHHIhEEXHHHIEpFHHdIdIxII_JJJJ|J|JJJJJJJJJJJJJJJpKpKuKwKyK~KKKKKKKKK,LWLLL0LWLLLWL\LL POPiSiSUUUUOWTWWMPOP,R\UUV5VW4WyOyOOOOP\PaPdPhPkP\PaPdPhPkPrPvPyPrPvPyPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQQQQQQQQQQQQQQQQQQQQQQQRiSiSUUV5VV4W@WEWOWTW`WcWWUSeSiSiSiSSSSUS_S_SeSiSiSiSSSSiSqSSSSSTTUV8VV4W@WEWOWTW`WcWWTTTTUUUV8VV4W@WEWOWTW`WcWW T;TUUTW`WcWW T;TTW`WcWWUUUUUDUYYYYY0YYYZ ZUZaZZZ@[]^_`_`8`` aHaaa0bstruct_FILE.hFILE.hstdio.hsys_errlist.hresource.hstruct_iovec.hsocket.hsocket_type.hsockaddr.htime.hpwd.hstruct_tm.htime.hunistd.hctype.hconfname.hgetopt_core.hstdint-uintn.hin.hnetdb.hun.hlsapidef.hstring.hresource.hdlfcn.hsocket.herrno.hselect2.hsched.hmman.hsendfile.huio.hstrings.hinet.hwait.hprctl.hgrp.h KK.K5J/I#KK1 0 z zJ Z " OJJ = ...v <K gfJ.T2KxJ.n=@<YDw<<=:/;<;/u;=IK=H</փ-K-=>:X-=;=0:/;=I<//sf=H</[G-K-=18=;=0:X;=-/I=;/?Gf-K-=I<-=;=-/e=-/t0//-</-</-</-<///-<///-J=t=Y-</ȑ-</J>Xtu-=ttu;/K-=-/X-/t;/gK-=Y-=;=J;=/K-=-/X;/u-=ttu-=K;</f;=;/fu-=t.V>,>t;=/.K-=-/t-=-//-/-X.I</t.W=-/0,0,<.W=-/t/t;=;/H ># K# = l Z< < h u$I$K="IY<IJ =$J$<=;"<J = vXF.L L = /d f.L u /O7@p$tik<=<>V L a$f mX Xm< .>m<X N1+ pk " kJJ k.XX"~K k  [ X O(kX  < kX  b>= E<>:<Y<; = vk<q R< !l   l<lz/ f X< Kffkv ~*~ X$ rJ~ # .?f h ~~<  .<1 ~) < ~t)X ~<= jtt        Z-JJXft X L!s gf  fF J Y Y :"foXXXJlt0 hd/ L. XN6g J yi< X$   Z  4tKK  ;:|". < Z IY6t(f+K"JMX"X< mJ< & AJX0J XXXV$J)I!4f<9X!Jh  .$r.XX`KJ Jt5<uY"J q<% 3$x.`XYBW[$g   F x \ *2. F^ \t;:j KK-uYIX Ki+JJK2KKu\/ u  u  (tX |  x(9?JL6J9xX<u1tu6,XJK,@g L,K /sJK u XQy  X KEW \ g x. < %  /s u Z ptt  /t.X  o tK !f J/ kt Zs gY  Z Y g Y  #!xwJKxJK K!JK sJ  s< ! KJ9J!JK!s  f K =J YYt YYt YYJ YY<xK t<YL ,<W ue [A<v v .KXe#!CJ;Cg K E dX ` x DNK$ JG MY<," g <    =  &> t u X   Y r< f Kr  < r rJ huJL |   fX.X  ]u u<   Z = = y<kJK,&J"Irt &s=r< !rff  "yJD!IK L%; K%H K KKK.7 .XB#I1u#J Q  F Z  KNJ U  X  hJ.$ .Xhr / X L*~Jf-S. LKI u YZ .HJ K Y)%fX80JJ )X%<XX$%4HJL<0YBL=;B=Vv<)/Mt z0<6u  zt/  L4K"vI4H =" @"F %#K%W Yz Q*uJf  uJ K mJJ .I  <vJ uMF =0J u) Y%#K,K"9 =& =X YsJY FX:JJ Z L N*<xX<JX>tJ e < 7/t  L4K xH4 = K *vJfJ  uJ  Y.W mJt mX K t Km \x JYKWiX<JJz NS =;0WX Y)? K  LeJf<Ki*_8tK )^ ~tf<_K z.` ztf< XKJZfv*=gJ Z AK=%, =%H KM, tY,Lho!(fot(= -K l X|K<x < o.K Ms f sf tJt    Z 93JJM _< . jy 93JJ Kw ' K"f/ s XM X X mXL  f   yr rX' =P Yr J:h6t YGu  uf>= . f  K  ^tj  !tJ<   jF % =%H K  Z7)K LK)8 K! K 2%o = K%: K2 GK  _X#< ]< <& Y ZX [f<Ȃ _Xy q   KK&,N>:hZs"  [sf  "Ui Xi g Y .. - sX ... K fh00< =  h+< Y  u<   Y Jz   . L+< g  /.  L g J JK*X.X v6= Y; u/ Xl f? lJXY lf"Kl "K8G8=P.4XK%      J.Jp<J*<X v6= Y;. / Xl f lJXY"=8G8= I/..c<<jBz<  sX&`" f [Z M   L  Y 0 U= =Y K ^f 4I gYK$/ fY L y^ /K-%]  K+/X>0XX<uj Yv Xg Y IgZ$Hv&L<X(.= /.u.Z .fJOwX(WuO=.ft"<*w  <K t Y /?N&tuKK  h g G] t Y t YtM   t  Y IgYJvYY g r Y >v t YK, <Y ._ho<x }KYWJtbXK X 9    ft "u ; <u WY rXu WY X"0", XX LXJ<f?JfjK t Y*=K t ,=K t 0=K t .=K t Y,=KgjKK 2K zt/ Y Z  c    Zc  cf  Zc <<   a,<  Zci  Zc x    Zc w X     c       Yc  v    Yc  v    Zc  w    Yc  v  Z [    Zc   g     Yb  f }r       g {  g1J }  <1-u-).K.X UJ.< Z .)J KIK XxK +zz< O=>;g< 0:>< Y6 2 _< < Z    \_<   _X<   _ @ /        J       f :v ZYw Yu    Zv  .X t   tXI/ /    u ~ft  Zr> Z J  z  X/X < zX   tX /  `ggWK>X u ~X~ }XYX |X |<Y ^  X ./ XR XUJ Y   h.eX> tYvtYK   M U -/](tq $~Zv <Qyt/Z t   t Z*(t N   bX J| < y  !#J Y  Z+KZ)=1K- M< <Y v.u. }Jt ZY< gJ f"<  /  np < }2NX)     ~ |X}Y"Xg![qg!p'Y>tYK&CXK%.ZY&i fYp<x u   Zv X w ~9}5Xl t.Z7j.+"<g7/W5K/I Mu_Kg\K _SC_THREAD_SPORADIC_SERVERpthread_atfork_functotalLSAPI_Set_Max_Process_Timelsapi_parent_dead__fxstatparseContentLenFromHeaderugidLen_SC_2_SW_DEVm_pScriptFileLSAPI_Stopsi_addr_lsb_unused2_SC_TIMERSm_iReqCounter_fileno_SC_SHELL_SC_MEMORY_PROTECTION_SC_SCHAR_MAX__pathtm_secH_AUTHORIZATION_SC_THREAD_SAFE_FUNCTIONS_SC_UCHAR_MAXmax_lenfreeaddrinfogid_tverifyHeader_SC_C_LANG_SUPPORTm_pIovecEndstrcpy__uint8_tIPPROTO_TPpw_uidwaitpidHTTP_HEADER_LEN_SC_TTY_NAME_MAX_SC_PASS_MAXLSAPI_ErrResponse_rsi_uidm_bytes_SC_2_PBS_TRACKfp_lve_destroym_pHeader_IO_buf_end__RLIM_NLIMITS_SC_SELECT_shortbufrlimitsockaddr_insa_family_tSOCK_DCCP_SC_BC_STRING_MAX_ISpunctis_enough_free_meminet_addr_SC_TRACE_INHERITinit_lve_exnewSizem_tmStartliblvesetgroups_SC_SEMAPHORES_SC_EQUIV_CLASS_MAXread__environ_sigpollsa_datauint16_t__builtin_memmoveai_protocol_valuem_pChildrenStatusCurIPPROTO_UDPoverflow_arg_areatime_tsin_zero_SC_DEVICE_SPECIFICin_port_t_flagsachMD5_SC_THREAD_THREADS_MAXerror_msg_SC_LEVEL3_CACHE_SIZE_SC_TRACEreg_save_areacalloc_archm_respPktHeaderg_running__off_t_addr_bndlsapi_cleanupachHeaderNamest_size_SC_THREAD_PROCESS_SHAREDallocateBuf_SC_JOB_CONTROLgetppidtm_isdstswapIntEndianlsapi_check_child_statussignal_locks_max_idle_secslsapi_set_nblockenvirons_schedule_notifysetUID_LVE_SC_NL_NMAX__RLIMIT_NPROCRLIMIT_DATApServeratoluint32_tinitgroups_SC_POLLm_pHttpHeader_SC_V6_ILP32_OFF32_SC_TRACE_SYS_MAXm_pScriptName__builtin_va_listst_blksizeRLIMIT_NOFILEm_pEnvList_SC_BASE_sigchldLSAPI_Set_Max_Idle_Childrenint32_t_SC_LONG_BITfixEndianLSAPI_GetEnv_r_upper__fmtsa_familym_specialEnvListSizepw_passwd_SC_CLOCK_SELECTIONmasklsapi_resp_infosigaction__RLIMIT_RTTIME_SC_V7_LPBIG_OFFBIGbodyLeftfcntllastTime_SC_AIO_LISTIO_MAXLSAPI_Init_Prefork_ServerpErr1pErr2st_gidm_cntHeaderss_notify_scheduledm_envListSizeacceptinggettimeofdaypBufai_addrm_iAvoidForks_secret_timerlsapi_MD5Context__syscall_slong_t__builtin_memset_SC_FILE_SYSTEMsa_restorerm_pChildrenStatusEnd_IO_write_endtype_SC_SCHAR_MIN_SC_LINE_MAXLSAPI_SetRespStatus_rlsapi_MD5_CTX__resst_nlinks_addr_SC_TZNAME_MAX__va_list_tag_syscallst_ctimnameLen__builtin___snprintf_chkLSAPI_Postfork_Child_SC_2_VERSIONfree_SC_2_PBS_CHECKPOINTIPPROTO_MPLS__sigset_tm_requestMethodOffm_tmWaitBeginreadSecretreadReq__tznameatoig_initedgetaddrinfovalLens_acklsapi_jailLVE__d0_SC_LEVEL4_CACHE_ASSOClsapi_MD5Final_SC_NL_LANGMAXdoAddrInfo__stack_chk_failmemcpy_killcurSizeRLIMIT_STACKIPPROTO_IPIPdlopenbacklogsin_family_SC_LEVEL1_ICACHE_ASSOCpIovrlim_maxm_iKillSentm_fdListen_SC_AIO_PRIO_DELTA_MAXvalidateHeadersst_atimm_statusm_reqBodyLensig_numoptargSOCK_RAWsnprintfold_int_SC_2_C_BINDs_enable_lve__clock_tparseRequestIPPROTO_RAWstrdupbufLen_SC_PRIORITY_SCHEDULING_SC_SS_REPL_MAXsys_errlistsival_ptrpStderrLogsetpgid__uid_tdaylightsi_stimeoptoptLSAPI_ReqBodyGetChar_rpKeysun_family__uint16_t_SC_FSYNCsin_portgetpeernameLSAPI_is_suEXEC_DaemonLSAPI_Is_Listen_rLSAPI_End_Response_r_SC_FILE_ATTRIBUTESsetreuidserverAddr_SC_NZEROm_pQueryString__gnuc_va_list_SC_2_C_DEV_chainpContentLen_call_addrEnvForeachnewfdm_iServerMaxIdleSOCK_NONBLOCKusleepSOCK_RDM_SC_SYMLOOP_MAXsockaddr_un_ISblankunsigned charIPPROTO_MAX_SC_MQ_OPEN_MAXSOCK_DGRAMm_tmReqBegin__fd_mask__blkcnt_tlsapi_enterLVE__builtin_calloc_IO_lock_tLSAPI_Is_ListenIPPROTO_COMPLSAPI_key_value_pairlsapi_check_pathLSAPI_ForeachHeader_rpHeaderName_SC_SEM_NSEMS_MAX_SC_USHRT_MAXLSAPI_FinalizeRespHeaders_r__read_alias__fdelt_chkshouldFixEndianpBody_SC_STREAM_MAX_SC_ASYNCHRONOUS_IOserverMaxIdle__open_alias_SC_READER_WRITER_LOCKS_SC_CPUTIME__getcwd_alias_SC_2_PBS_LOCATE_SC_DEVICE_IOsa_flagspVecgeteuid_SC_SIGNALS__ctype_b_loc_SC_V7_ILP32_OFFBIGstatusoff_tchild_statuss_notified_pids_max_reqsH_X_FORWARDED_FORs_pid_dump_debug_info_ISalpha__fprintf_chktm_zone__mode_tm_queryStringOff_SC_V7_LP64_OFF64_SC_NPROCESSORS_CONF__RLIMIT_SIGPENDINGfdInlsapi_changeUGidtv_usec_SC_XOPEN_XCU_VERSIONold_childold_termLSAPI_sendfile_rlsapi_lve_erroraccept_SC_MEMLOCKallocateRespHeaderBuf_ISprintsched_yieldpMessages_liblvepValueH_CONTENT_LENGTHm_tmLastCheckPoint__vfprintf_chk_ISalnum_SC_SEM_VALUE_MAXs_req_processedstrtollopen_SC_XOPEN_XPG2_SC_XOPEN_XPG3_SC_XOPEN_XPG4LSAPI_STATE_CONNECTED_IO_write_ptr_SC_REALTIME_SIGNALSsystemlsapi_packet_headerIPPROTO_ENCAP_ISspacelsapi_suexec_authgetLFg_prefork_serverva_list__suseconds_treqsexitLSAPI_CreateListenSock2__rlim_ts_ignore_pid__RLIMIT_MEMLOCKpCurpHeaderValue__sizesizes_slow_req_msecslsapi_init_children_statusgetuidFILEH_COOKIELSAPI_ParseSockAddrdlsympthread_lib_SC_PII_INTERNET_DGRAM_SC_SINGLE_PROCESSbyteReversedump_debug_infoLSAPI_Accept_Before_Fork_SC_SHRT_MAX_ISxdigit_SC_RAW_SOCKETSfp_lve_enterLSAPI_AppendRespHeader_rsize_tH_CONNECTIONLSAPI_GetHeader_r_SC_MULTI_PROCESSs_stderr_log_pathm_statefp_lve_instance_init_SC_BC_BASE_MAXH_CONTENT_TYPELSAPI_STATE_ACCEPTING_SC_RTSIG_MAX_SC_NETWORKINGachCmdH_ACCEPT_SC_GETGR_R_SIZE_MAXperrorcompareValueLocation_SC_THREAD_ATTR_STACKADDR_SC_LEVEL2_CACHE_ASSOC_SC_IOV_MAX_SC_TRACE_EVENT_NAME_MAX_SC_PII_INTERNETIPPROTO_IGMPpServerAddrlsapi_acceptlsapi_initLVE_IO_save_baseLSAPI_Release_riovecold_usr1maxIdleChldsocklen_tm_iMaxChildren_SC_2_UPEai_canonnameIPPROTO_IPV6_SC_DELAYTIMER_MAXpw_dirsa_mask__sigval_tLSAPI_Set_Extra_Childrens_restored_ppidsin6_flowinfototalLenm_pid_SC_SYSTEM_DATABASElsapi_prefork_server_acceptm_pIovecToWritecodem_respHeaderLen_wide_dataH_IF_MATCHai_family__nlink_tsi_addrst_inost_modeLSAPI_IsRunning_SC_T_IOV_MAXCGI_HEADER_LENIPPROTO_DCCP__in6_usysconfGNU C17 8.5.0 20210514 (Red Hat 8.5.0-18) -mtune=generic -m64 -march=x86-64 -g -O2 -fPIC -fexceptions -fstack-protector-strong -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection=full -fplugin=gcc-annobinGetHeaderVarH_ACC_CHARSET__stream_SC_XOPEN_STREAMSm_iMaxIdleChildrensendfile_IScntrlm_reqBufSizelsapi_child_statusprctlallocateEnvList_ISupperpStatuserr_nosival_intsi_codem_pReqBufwait_timestrcasecmpH_IF_UNMOD_SINCEpw_name_SC_TRACE_USER_EVENT_MAX__socklen_tsend_notification_pktlsapi_requestpKeyEndcurTimefprintflsapi_writev__ssize_t__srclsapi_closepChrootH_IF_RANGEtimespecnameOff__u6_addr8strerror__RLIMIT_RSSavoidForkm_packetLenLSAPI_ReadReqBody_rIPPROTO_MPTCP_SC_2_FORT_RUNbindfp_lve_leave__valin6_addr_SC_ADVISORY_INFOpacketLen__timezone__ctype_toupper_locsin6_addr_SC_TIMER_MAXpBufCur_SC_THREADSunset_lsapi_envs__sighandler_t_SC_USER_GROUPS_RLSAPI_Set_Server_fdLSAPI_CreateListenSock__RLIMIT_LOCKSm_respPktHeaderEndLSAPI_On_Timer_pfLSAPI_Set_Max_Reqs_SC_UINT_MAXst_uids_conn_close_pktLSAPI_Postfork_ParentpEndpktTypelsapilib.cset_skip_write_SC_TRACE_NAME_MAX_lowers_busy_workers_SC_THREAD_DESTRUCTOR_ITERATIONSm_flagmemsetlevelstderrm_pHeaderIndexnameidle_SC_CHILD_MAXlsapi_reopen_stderr2_IO_save_endtm_min__nptrLSAPI_InitLSAPI_Request_SC_V6_LP64_OFF64flag_SC_NGROUPS_MAXm_bufProcessedfixHeaderIndexEndianstdoutfp_offsetlsapi_MD5TransformLSAPI_Write_Stderr_r__time_t_SC_THREAD_ROBUST_PRIO_INHERITgp_offset_padLSAPI_ForeachOrgHeader_rsigaddsetLSAPI_Inc_Req_Processedm_httpHeaderLendyingrealpathtm_yday_SC_SSIZE_MAX_SC_PII_OSI_CLTS_SC_SYSTEM_DATABASE_RmsecspAuth_SC_LEVEL1_DCACHE_SIZEkeyLenextraChildrenLSAPI_Flush_rshort unsigned intrlim_cursigned charLSAPI_Reset_rs_lveold_ppidLSAPI_CB_EnvHandler_valueLen__blksize_t_SC_STREAMSSOCK_STREAMdigestpBufEnd_SC_PAGESIZE_SC_THREAD_PRIORITY_SCHEDULINGcountsi_pidIPPROTO_MTPs_stop_SC_CHARCLASS_NAME_MAXlsapi_header_offsetstrchrvfprintfsetgid_boundstm_wday__off64_t__fd__lenachBuf_sigsys_IO_read_base_SC_XBS5_ILP32_OFFBIGsend_req_received_notification_offsetIPPROTO_EGPLSAPI_reset_server_statesockaddrsigset_ts_defaultGids_keep_listenersecsm_cntUnknownHeadersreadfdsai_addrlenlongsopterr_SC_DEVICE_SPECIFIC_RLSAPI_Set_Restored_Parent_Pidpw_gecos_modem_iExtraChildrenLSAPI_No_Check_ppid_SC_PIPE_IO_write_base_SC_XOPEN_CRYPTvalueLenm_respInfotz_dsttime_SC_PHYS_PAGESlsapi_enable_core_dumpH_CACHE_CTRLH_COOKIE2_SC_ATEXIT_MAX__desttm_monclose_SC_SHRT_MIN_SC_FIFObitstimeH_USERAGENTs_min_avail_pages_SC_USER_GROUPSm_lLastActiveLSAPI_ForeachEnv_rlong intSOCK_PACKETsa_sigactionnotify_req_received_SC_XBS5_ILP32_OFF32dumps_worker_status_IO_marker__builtin_strncpys_ppidtm_yearlimitmax_children_SC_2_PBS_MESSAGEm_pRespBufEndtimevalorig_masktmCur_SC_XOPEN_REALTIME_THREADSfp_lve_is_availablepAddrs_defaultUidm_pChildrenStatus__fds_bits_SC_SPIN_LOCKSLSAPI_Set_Server_Max_Idle_Secswritem_bufRead_SC_SPORADIC_SERVERlsapi_close_connectionuint8_t_SC_LEVEL1_DCACHE_LINESIZE__sigaction_handlerlsapi_signal_SC_PRIORITIZED_IOin_addrSOCK_SEQPACKET__pid_t_IO_codecvt_SC_GETPW_R_SIZE_MAXpUgidheadershints_SC_XOPEN_VERSIONH_RANGE_SC_BC_SCALE_MAX_SC_2_C_VERSIONdup2strtolg_reqlong doubleparseEnvai_socktype_SC_THREAD_KEYS_MAXiov_len_SC_LEVEL4_CACHE_LINESIZEfd_setlsapi_MD5Init_SC_NL_TEXTMAXnonblocklong unsigned intlsapi_req_header_SC_LOGIN_NAME_MAXfind_child_statusIPPROTO_PIM_SC_XBS5_LP64_OFF64_SC_SPAWNmaxChildrennewlensi_statussigemptyset_pkeym_headerOff__RLIMIT_OFILEHTTP_HEADERS_SC_2_PBSs_proc_group_timer_cbpw_gid__errno_location_SC_XBS5_LPBIG_OFFBIG_SC_WORD_BITchar_SC_2_PBS_ACCOUNTINGm_pSpecialEnvListsin6_scope_idstdin_SC_AIO_MAX__oflag_SC_2_CHAR_TERMresolved_path_SC_LEVEL1_ICACHE_LINESIZE_IO_buf_baseai_flagsrealloc_SC_XOPEN_SHM__dev_t_SC_XOPEN_ENH_I18Nold_quitRLIMIT_CPU__glibc_reserved_IO_read_end_SC_ULONG_MAX_SC_TYPED_MEMORY_OBJECTS_SC_TIMEOUTS_SC_LEVEL2_CACHE_SIZEfinal_SC_XOPEN_UNIXm_pRespBufPos_IO_FILEin_addr_tm_fdH_HOST_IO_wide_datacookiestrlentzname_sifields_SC_LEVEL2_CACHE_LINESIZE__u6_addr16s_pidIPPROTO_AHLSAPI_ReqBodyGetLine_rtm_hoursetsidFlush_RespBuf_r_SC_THREAD_STACK_MINisPipe_SC_PII_OSI_Mm_respHeaders_global_counterRLIMIT_AS_SC_NL_MSGMAXsi_signom_pAppData__RLIMIT_MSGQUEUEachAddrm_inProcess_SC_THREAD_ROBUST_PRIO_PROTECT_ISgraph_lsapi_prefork_servertm_mdaypIntegerlsapi_siguser1__pad0_SC_BC_DIM_MAX__pad5_SC_LEVEL1_DCACHE_ASSOCmallocs_dump_debug_infos_avail_pages__u6_addr32_headerInfom_typesi_errnofinish_closelistensigno_SC_XOPEN_REALTIME_markersLSAPI_InitRequest_SC_SAVED_IDSpBindm_scriptFileOff_SC_INT_MAXsi_bands_log_level_namess_skip_writeH_VIAmemccpy_codecvtforkIPPROTO_ESPm_pRespHeaderBufEnd_SC_TRACE_LOGgetpwnamtimeout_SC_THREAD_PRIO_PROTECTg_fnSelectRLIMIT_FSIZE__builtin_memcpyst_rdevlsapi_http_header_indexpEnv_SC_OPEN_MAXst_devssize_tdlerrorheaderIndex_SC_UIO_MAXIOVLSAPI_Logm_pRespHeaderBuf__int32_tH_PRAGMA__uint32_tqsortpSecretFile__RLIMIT_NLIMITS__daylightIPPROTO_RSVPstrncpyH_REFERERIPPROTO_UDPLITESOCK_CLOEXECLSAPI_Set_Slow_Req_MsecsLSAPI_Prefork_Accept_r_sys_siglisthandler_SC_CHAR_MAXLSAPI_Get_ppid_ISlowerpEnvEndsigprocmaskm_pUnknownHeadergetpwuidm_reqState_SC_PII_XTIpRespHeadersleftkill/builddir/build/BUILD/opt/alt/ruby27/share/gems/gems/ruby-lsapi-5.5/ext/lsapim_pRespBufm_iCurChildrensocketLSAPI_Write_r_SC_PII_OSI_COTSm_totalLenpasswdm_pIovecs_stderr_is_pipefstat__snprintf_chk_SC_PII_SOCKET__gid_tlsapi_sigpipe_SC_V6_LPBIG_OFFBIG_SC_MQ_PRIO_MAXgetcwdH_TRANSFER_ENCODINGH_IF_MODIFIED_SINCE__bsxai_nexts_enable_core_dump_SC_TRACE_EVENT_FILTERnodelaysin6_family__resolved_freeres_buf_sigfaultm_iChildrenMaxIdleTime_SC_THREAD_CPUTIMEsi_utimetv_sec_SC_VERSIONm_cntSpecialEnv_SC_C_LANG_SUPPORT_Rlong long unsigned intmemmovesa_handlersin_addr_cur_columnlsapi_load_lve_libtoWriteuid_t_SC_PIIsi_fd_SC_MAPPED_FILES_SC_LEVEL4_CACHE_SIZEIPPROTO_BEETPHfp_lve_jail_SC_2_FORT_DEVIPPROTO_IPm_pRespHeaderBufPosst_blockslsapi_initSuEXEC__bswap_16getpid__buf_SC_2_LOCALEDEFm_cntEnvlocaltime_r_SC_LEVEL1_ICACHE_SIZEreadBodyToReqBuftm_gmtoffIPPROTO_PUP_namesigval_IO_backup_baseH_KEEP_ALIVE_IO_read_ptr_SC_CHAR_BITLSAPI_Register_Pgrp_Timer_Callbackmd5ctx__socket_type__nbytes_nameLengetenv_freeres_list__aps_max_busy_workersIPPROTO_ETHERNETH_IF_NO_MATCHpEnvListrlim_tlsapi_readsun_pathtimezoneCGI_HEADERSsi_overrun__bswap_32pReq_SC_INT_MINlsapi_MD5Update_SC_RE_DUP_MAX_SC_PII_INTERNET_STREAMachBodyachPeerheader_SC_THREAD_ATTR_STACKSIZEfull_path_old_offset_SC_SIGQUEUE_MAXsiginfo_t_SC_FD_MGMTexpect_connected_SC_SYNCHRONIZED_IOLSAPI_STATE_IDLEvalueOffsighandler_t_SC_V7_ILP32_OFF32skipunlinksend_conn_close_notificationoptinds_accept_notifywritevH_ACC_LANG_SC_EXPR_NEST_MAX_SC_LEVEL3_CACHE_LINESIZElong long intm_pktHeaderin6addr_loopbackports_accepting_workersIPPROTO_IDP_flags2lsapi_prefork_serverallocateIovec_SC_MESSAGE_PASSING__ch_SC_REGEX_VERSIONm_iLenLSAPI_Set_Max_Children__d1setuidtv_nsecm_scriptNameOfflsapi_perror_SC_FILE_LOCKING_SC_AVPHYS_PAGES_SC_MB_LEN_MAXpHeader_ISdigitsockaddr_in6IPPROTO_SCTP_SC_PII_OSI_SC_ARG_MAX__ino_tsetsockopt_SC_MEMLOCK_RANGELSAPI_Finish_r_SC_SHARED_MEMORY_OBJECTSlsapi_resp_headersys_nerrin6addr_anym_pRequestMethodachError_SC_CHAR_MIN__realpath_chkiov_basem_lReqBegins_uids_total_pagespw_shell__namem_versionB0m_versionB1IPPROTO_GRE_SC_XOPEN_LEGACY_SC_NL_ARGMAXRLIMIT_COREsi_tidtobekilled_SC_THREAD_PRIO_INHERIT_SC_LEVEL3_CACHE_ASSOC_SC_NPROCESSORS_ONLNm_headerLenexpect_acceptingm_pIovecCurfdListenLSAPI_Init_Env_Parametersaddr_len_SC_HOST_NAME_MAXIPPROTO_TCPLSAPI_AppendRespHeader2_r_SC_COLL_WEIGHTS_MAX_SC_MONOTONIC_CLOCK__rlimit_resourcem_reqBodyReadLSAPI_Set_Max_Idle_SC_CLK_TCKLSAPI_ForeachSpecialEnv_rlsapi_buildPacketHeaderLSAPI_perror_r_SC_NL_SETMAXunsigned int_SC_BARRIERSbodyLenpBeginLSAPI_Accept_rwait_secslsapi_reopen_stderrstrcmpst_mtim__statbuf__RLIMIT_NICEfn_select_tshort intlsapi_notify_pidsi_sigvalsetrlimit_vtable_offsetaddrinfo_SC_IPV6mmapIPPROTO_ICMPlsapi_sigchild_SC_REGEXPlsapi_schedule_notifyLSAPI_Get_Slow_Req_Msecs_SC_V6_ILP32_OFFBIGstatmemchrtz_minuteswestsys_siglistH_ACC_ENCODINGsin6_portm_iMaxReqProcessTime__RLIMIT_RTPRIOGCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-18)GNUzRx 0D LXsEIB E(A0z (A BBBI A (D BBBA  @YGJB B(A0A80F(B DBb0BFC G  AABK Hk(\GADJ n AAA 4UAGK R CAG L JCG AG] AJ t C KFLBBE A(H0H (D BBBD  (D BBBA PXvFB A(D0D (A BBBB L(A BBBA$aAAD XAAHBBB B(A0A8D@N 8C0A(B BBBH $ OAf Q C E H@HYBBB A(D0J 0A(A BBBF xFEA C(G   (A ABBD M I c A  E M A k E E E E H V HFBB B(A0A8D`` 8A0A(B BBBD lT+BBB B(A0D8JYHPC Mi 8A0A(B BBBE LTMDd6BBB B(A0A8DP 8A0A(B BBBG  8J0H(G DBBK $,7EFF IIOTh|  4FAA G>  AABG EO D  A  (Y<JEDXS l]Ph H XAHlFBB B(A0A8LP 8A0A(B BBBH < FBB A(A0 (D BBBI i`0FBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH L$FBB A(A0H Q D 0A(A BBBH LFBB B(A0A8G 8A0A(B BBBF 4FHF\$pnCXJLlFBB B(A0A8DA 8A0A(B BBBA `BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0L BMD GL  AABA < =BAA G L@I@U  AABG $ TWEHG ag H SH FBB B(A0A8DPS 8D0A(B BBBF TX bIE D(C0P (F BBBM Q(H BBBAH FBB B(A0A8DP 8A0A(B BBBA T CBA A(G0` (A ABBD  (C ABBA J8T -FBD D(D@T (A ABBB  ( lECGF AAI L !cBG A(D0 (A ABBE XD0 4 ZH 10\ pFAA G@7  AABF  @LsL FBB B(A0A8G 8A0A(B BBBG   $ 8 L ` t     <  FBA K(G (A ABBG <FEE D(D0M (C BBBB X(HlFBH E(A0E8I@ 8A0A(B BBBE (FED ABH BBB B(A0A8G 8A0A(B BBBJ D0FBB A(A0G 0A(A BBBF Lx FBB B(A0A8G  8A0A(B BBBA    1 -  E2a~345.IWul -- "0s-Je s z )Y)2L0Yz+ k + w 0 Gw : X Ui s  s    x 5 P _ s(0x *  * # N0 al |  O& - =h9Y9 @ $@O e` rU+66 %  7 6S wm w   l      4 f   x    ]  '  ; ]\ m{ m     *+ *L k    \ \" k C k b    "   " $%@ `d0$%UE'xdE'''''D(m())* *+7+F+c,~, 0,.,=.u/*7u/[)0})011224C4k55667!7G7k78d X 8 8+8S:9y:9q9P q9: #h 3 (B:g0;0;H?   @  H?'^?GR^?tk?k????,?V?~???@,@T@z @+@+@?@?@;K@WK@TI ) p h d ` P H @# 80 X6TIYIzIJJJJ K(K?WTK \(b $o(|WUYUYZd Zd>qdiqdd!#$&()+2345671828F"KO(pRP [oy#)/5;AG8MXSY_ekqw+}=Nbw*@V %]+o17=CpIO@U[Tahgtms8yp6&(P,-./0) >Mcmy 1   " / 9 @C R a h v      @7      ! !'! #S!3!8!C!RK!@ Q!X!^!` p!p!Y!J!!0S!]!l!!!` "p i" %","@"#$Y"_"0%u"P'F"'F"'"(")l""""# #.#/1#00?#2P#Y#2s#z#4#5-#####7# 7l#7! $$$!$85$8ZN$@91a$9pv$:@$$0;$$$$P?$`? $p?%?%?:%?V%?u%@ % @ %0@%@@ %P@ %%%%&&& &`I4&I(B&JR&Ka&j&q&{&&&&&W&`Y &&&`d&d '.annobin_lsapilib.c.annobin_lsapilib.c_end.annobin_lsapilib.c.hot.annobin_lsapilib.c_end.hot.annobin_lsapilib.c.unlikely.annobin_lsapilib.c_end.unlikely.annobin_lsapilib.c.startup.annobin_lsapilib.c_end.startup.annobin_lsapilib.c.exit.annobin_lsapilib.c_end.exit.annobin_lsapi_sigpipe.start.annobin_lsapi_sigpipe.endlsapi_sigpipe.annobin_lsapi_siguser1.start.annobin_lsapi_siguser1.endlsapi_siguser1g_running.annobin_compareValueLocation.start.annobin_compareValueLocation.end.annobin_EnvForeach.start.annobin_EnvForeach.endEnvForeach.annobin_lsapi_cleanup.start.annobin_lsapi_cleanup.endlsapi_cleanups_stop.annobin_set_skip_write.start.annobin_set_skip_write.ends_skip_write.annobin_lsapi_MD5Transform.start.annobin_lsapi_MD5Transform.endlsapi_MD5Transform.annobin_lsapi_signal.start.annobin_lsapi_signal.endlsapi_signal.annobin_find_child_status.start.annobin_find_child_status.endfind_child_statusg_prefork_server.annobin_allocateRespHeaderBuf.start.annobin_allocateRespHeaderBuf.endallocateRespHeaderBuf.annobin_lsapi_set_nblock.start.annobin_lsapi_set_nblock.endlsapi_set_nblock.annobin_lsapi_accept.start.annobin_lsapi_accept.endlsapi_accept.annobin_parseEnv.start.annobin_parseEnv.endparseEnv.annobin_lsapi_init_children_status.start.annobin_lsapi_init_children_status.endlsapi_init_children_statuss_busy_workerss_accepting_workerss_avail_pagess_global_counter.annobin_readBodyToReqBuf.part.2.start.annobin_readBodyToReqBuf.part.2.endreadBodyToReqBuf.part.2.annobin_lsapi_close_connection.isra.4.start.annobin_lsapi_close_connection.isra.4.endlsapi_close_connection.isra.4s_worker_status.annobin_lsapi_writev.part.6.start.annobin_lsapi_writev.part.6.endlsapi_writev.part.6.annobin_lsapi_parent_dead.start.annobin_lsapi_parent_dead.endlsapi_parent_deads_ppids_restored_ppid.annobin_LSAPI_ParseSockAddr.part.13.start.annobin_LSAPI_ParseSockAddr.part.13.endLSAPI_ParseSockAddr.part.13.annobin_LSAPI_Log.start.annobin_LSAPI_Log.ends_stderr_is_pipes_log_level_namess_pid.annobin_lsapi_sigchild.start.annobin_lsapi_sigchild.endlsapi_sigchilds_pid_dump_debug_infos_ignore_pid.annobin_dump_debug_info.start.annobin_dump_debug_info.end.annobin_lsapi_check_child_status.start.annobin_lsapi_check_child_status.endlsapi_check_child_statuss_max_idle_secss_dump_debug_info.annobin_lsapi_perror.start.annobin_lsapi_perror.end.annobin_LSAPI_is_suEXEC_Daemon.start.annobin_LSAPI_is_suEXEC_Daemon.ends_uids_secret.annobin_LSAPI_Stop.start.annobin_LSAPI_Stop.end.annobin_LSAPI_IsRunning.start.annobin_LSAPI_IsRunning.end.annobin_LSAPI_Register_Pgrp_Timer_Callback.start.annobin_LSAPI_Register_Pgrp_Timer_Callback.ends_proc_group_timer_cb.annobin_LSAPI_InitRequest.start.annobin_LSAPI_InitRequest.end.annobin_LSAPI_Init.start.annobin_LSAPI_Init.endg_initedpthread_atfork_func.annobin_LSAPI_Is_Listen_r.start.annobin_LSAPI_Is_Listen_r.end.annobin_LSAPI_Is_Listen.start.annobin_LSAPI_Is_Listen.end.annobin_LSAPI_Reset_r.start.annobin_LSAPI_Reset_r.end.annobin_LSAPI_Release_r.start.annobin_LSAPI_Release_r.end.annobin_LSAPI_GetHeader_r.start.annobin_LSAPI_GetHeader_r.end.annobin_LSAPI_ReqBodyGetChar_r.start.annobin_LSAPI_ReqBodyGetChar_r.end.annobin_LSAPI_ReqBodyGetLine_r.start.annobin_LSAPI_ReqBodyGetLine_r.end.annobin_LSAPI_ReadReqBody_r.start.annobin_LSAPI_ReadReqBody_r.end.annobin_Flush_RespBuf_r.start.annobin_Flush_RespBuf_r.end.annobin_LSAPI_GetEnv_r.start.annobin_LSAPI_GetEnv_r.endCGI_HEADERS.annobin_LSAPI_ForeachOrgHeader_r.start.annobin_LSAPI_ForeachOrgHeader_r.endHTTP_HEADERSHTTP_HEADER_LEN.annobin_LSAPI_ForeachHeader_r.start.annobin_LSAPI_ForeachHeader_r.endCGI_HEADER_LEN.annobin_LSAPI_ForeachEnv_r.start.annobin_LSAPI_ForeachEnv_r.end.annobin_LSAPI_ForeachSpecialEnv_r.start.annobin_LSAPI_ForeachSpecialEnv_r.end.annobin_LSAPI_FinalizeRespHeaders_r.start.annobin_LSAPI_FinalizeRespHeaders_r.end.annobin_LSAPI_Flush_r.start.annobin_LSAPI_Flush_r.end.annobin_LSAPI_Write_Stderr_r.start.annobin_LSAPI_Write_Stderr_r.ends_stderr_log_path.annobin_LSAPI_perror_r.start.annobin_LSAPI_perror_r.endLSAPI_perror_r.annobin_lsapi_jailLVE.start.annobin_lsapi_jailLVE.endlsapi_jailLVEfp_lve_jail.annobin_lsapi_reopen_stderr.start.annobin_lsapi_reopen_stderr.endlsapi_reopen_stderr.annobin_LSAPI_Finish_r.start.annobin_LSAPI_Finish_r.endfinish_close.annobin_LSAPI_End_Response_r.start.annobin_LSAPI_End_Response_r.end.annobin_LSAPI_Write_r.start.annobin_LSAPI_Write_r.end.annobin_LSAPI_sendfile_r.start.annobin_LSAPI_sendfile_r.end.annobin_LSAPI_AppendRespHeader2_r.start.annobin_LSAPI_AppendRespHeader2_r.end.annobin_LSAPI_AppendRespHeader_r.start.annobin_LSAPI_AppendRespHeader_r.end.annobin_LSAPI_CreateListenSock2.start.annobin_LSAPI_CreateListenSock2.end.annobin_LSAPI_ParseSockAddr.start.annobin_LSAPI_ParseSockAddr.end.annobin_LSAPI_CreateListenSock.start.annobin_LSAPI_CreateListenSock.end.annobin_LSAPI_Init_Prefork_Server.start.annobin_LSAPI_Init_Prefork_Server.ends_max_busy_workersg_fnSelects_total_pages.annobin_LSAPI_Set_Server_fd.start.annobin_LSAPI_Set_Server_fd.end.annobin_LSAPI_reset_server_state.start.annobin_LSAPI_reset_server_state.end.annobin_is_enough_free_mem.start.annobin_is_enough_free_mem.ends_min_avail_pages.annobin_LSAPI_Postfork_Child.start.annobin_LSAPI_Postfork_Child.ends_req_processeds_keep_listeners_notified_pid.annobin_LSAPI_Postfork_Parent.start.annobin_LSAPI_Postfork_Parent.end.annobin_LSAPI_Accept_Before_Fork.start.annobin_LSAPI_Accept_Before_Fork.endold_childold_termold_intold_usr1old_quit.annobin_LSAPI_Set_Max_Reqs.start.annobin_LSAPI_Set_Max_Reqs.ends_max_reqs.annobin_LSAPI_Set_Max_Idle.start.annobin_LSAPI_Set_Max_Idle.end.annobin_LSAPI_Set_Max_Children.start.annobin_LSAPI_Set_Max_Children.end.annobin_LSAPI_Set_Extra_Children.start.annobin_LSAPI_Set_Extra_Children.end.annobin_LSAPI_Set_Max_Process_Time.start.annobin_LSAPI_Set_Max_Process_Time.end.annobin_LSAPI_Set_Max_Idle_Children.start.annobin_LSAPI_Set_Max_Idle_Children.end.annobin_LSAPI_Set_Server_Max_Idle_Secs.start.annobin_LSAPI_Set_Server_Max_Idle_Secs.end.annobin_LSAPI_Set_Slow_Req_Msecs.start.annobin_LSAPI_Set_Slow_Req_Msecs.ends_slow_req_msecs.annobin_LSAPI_Get_Slow_Req_Msecs.start.annobin_LSAPI_Get_Slow_Req_Msecs.end.annobin_LSAPI_No_Check_ppid.start.annobin_LSAPI_No_Check_ppid.end.annobin_LSAPI_Get_ppid.start.annobin_LSAPI_Get_ppid.end.annobin_LSAPI_Init_Env_Parameters.start.annobin_LSAPI_Init_Env_Parameters.ends_accept_notifys_enable_core_dumps_defaultUids_defaultGids_enable_lves_liblvefp_lve_is_availablefp_lve_instance_initfp_lve_enters_lve.annobin_LSAPI_ErrResponse_r.start.annobin_LSAPI_ErrResponse_r.end.annobin_lsapi_MD5Init.start.annobin_lsapi_MD5Init.end.annobin_lsapi_MD5Update.start.annobin_lsapi_MD5Update.end.annobin_lsapi_MD5Final.start.annobin_lsapi_MD5Final.end.annobin_readReq.start.annobin_readReq.endreadReqs_ackachBody.7025headers.7024.annobin_LSAPI_Accept_r.start.annobin_LSAPI_Accept_r.end.annobin_LSAPI_Prefork_Accept_r.start.annobin_LSAPI_Prefork_Accept_r.ends_conn_close_pkt.annobin_LSAPI_Set_Restored_Parent_Pid.start.annobin_LSAPI_Set_Restored_Parent_Pid.end.annobin_LSAPI_Inc_Req_Processed.start.annobin_LSAPI_Inc_Req_Processed.end.LC0.LC1.LC4.LC5.LC6.LC3.LC2.LC7.LC8.LC9.LC10.LC11.LC12.LC13.LC14.LC15.LC16.LC17.LC18.LC19.LC20.LC21.LC22.LC23.LC24.LC25.LC26.LC27.LC31.LC32.LC30.LC29.LC33.LC34.LC36.LC37.LC38.LC39.LC40.LC41.LC42.LC44.LC45.LC46.LC47.LC48.LC49.LC50.LC51.LC59.LC69.LC70.LC71.LC43.LC35.LC61.LC62.LC63.LC64.LC65.LC66.LC67.LC68.LC52.LC53.LC54.LC60.LC58.LC57.LC55.LC56.LC87.LC76.LC77.LC78.LC72.LC79.LC80.LC86.LC74.LC84.LC83.LC73.LC75.LC82.LC81.LC85.LC92.LC91.LC88.LC90.LC89.text.group.text.hot.group.text.unlikely.group.text.startup.group.text.exit.groupcompareValueLocationset_skip_write_GLOBAL_OFFSET_TABLE_sigactionsigemptyset__stack_chk_failreallocfcntlsetsockoptmmapmemsetsetsidread__errno_locationwritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkstrdupLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamenvirondlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectd \D   h o    2 9 H $O ,T g -o    h C M X h c z  h  h h a 8g.J5*T/0 *1%>Kw235R4Y5`6v\  "X 3/8M7`io89p3:?K_;<Rf=h{d h t8~KW>`i{h*$?*/?@GNw*"  ( h !A`!!!a"j#<q#\p$*}$$*$ %%%&A'((Y)))b***7+A+N+BW+_+}+C++++D,,{,D,,E,,h -n---F----.8.?.N.Y.~.G...H./*/ L/T/i/// /0_1111Q2v22/33-4O4|5N6h66666666I7W7777` 7` 77888#8-828<8G8T {8889'9G9$Q9L f9T 99999999999p:*:#:<:d G:Z:` d:h::::#:::: ;!;H;;;;;;|;;<<<<,<9<V<x<t<\ <<<$< :=S=e=o=}=|====<====>/>I6>@> F>w> > >>J>?K ??L#?D?Y?f?w?????@&@6@F@_@M@@@N@@@O@@@d @P@A'AQ,A@AFA%MARRAfAmAtASyAAhATAAAAAUAAAVA BBBW B4B;BBBXGB[BbBiBYnBBBBZBBB[BBB` B\BBBBhC` C\C]#C2Cd?CdEC`TC^YCqCwC\ChC*ChC_C`CazD` DDL D DbDDcE%E`1ENEUE*\EpEduEELEeEEDEE\EfEEgE<EEhEEiF4 FFjF%F,,FTGFkLFSFTXF_FPFFFFFlFFFdGm GG(G`/Gn4GQGmGG|GGGGdG`HoHH\"Hd,H`6H`DH\ZHXyHLHpHHHH<HTHHhHHDHXIh IIq+Ir7IAIKIsIIIIJJzK9LDLOLh JMUMdMh M4NOtOPuP*P.RhDR%JR$]R#}RRdR`RvSwmS|S!S"S"S# T$TT/T4GT+uT%T&T'TlThTTMTUU|*U$1UGUxSUeU}U(UyUUzUUdU`U$UTU)V{V V|,V=V%eV%V}V*V~V[VdV`V$VWW+W9WPWYWyWWW WWXh BXUXhXX$XXh XY$ YGYQYxYYYYYYYYh #Zh 3Z?ZeZ ZZZp[[[[[\C\\\t\\ \\\$] ^]u]]]]^^4^d B^$X^$]^s^^^^^_d __c +_D_c__ _ _ __I__ ` `%`\`k`-|`.```.``` a,aJ5abaqa` aa` aaaaaaabbh 3bK8bGbXb.gbpbvb{bbbbbbpb*bbbd bc` ch$cCcTcecvcccccc#ccLccd dd9dKdVdfdldd, s|2J +$,PX---D-Lpx 08)dl)))+ $,+ P+ Xw + w w  w   s D Ls ps x s   x  x 0x 8* dx l* *  *   $ ,PX99 9 D 9L p x       0 8 6d l 6 6 w 6 w w $ w, P X         D L p x     ]  ]0 ]8 md ]l m m  m   $,PX****DLpx\\\k \ k 0k 8 dk l  " ""$%$",$%P$%XE'$%E'E''E''''D'L'p'x('(()( )0)8*d)l**+*++,$+,,P,X.,..u/.u/u/)0Du/L)0p)0x1)01121 20284d2l4454556$5,6P6X767777778D7L8p8x8888:98 :90:98q9d:9lq9q9:q9::0;$:,0;P0;XH?0;H?H?^?H?^?^?k?D^?Lk?pk?x?k????? ?0?8?d?l??????@$?,@P@X@@@@+@@+@+@?@D+@L?@p?@xK@?@K@K@TIK@ TI0TI8IdTIlIIJIJJJ$ J, JP JX K J K K W K W!W!UYD!WL!UYp!UYx!Zd!UY!Zd!Zd!qd"Zd "qd0"qd8"dd"qdl"d % & ' (]CC C(X 01CC3C9C> CE(CJ0CP8CU@C[HCbPCqXC`ChCpCxCCCCCCCCCCCC+C4CHCSCYCiCm C(C0C8C@CHCPCXC`ChCpC!xC+C7CDCTCgC~CCCCCCCC  $ $c $,) #0 $8 < $C $ 7J $$Q $V $d $7n $ z $9+ $L+ $! $& $ $e- $@4 $ $ $q $  $# $' " $Q. $: $!M $MY $ e $Gq $ $% $ $w $", $ $4 $i $ $ $( $/  $8 $ $  $  $e, $v9 $o.F $3T $U8a $*n ${ $ $ $( $j $( $* $ $  $/ $  $j7  $ $&5 $A $rM $/b $ $F  $ $!0 $ $  $ $ $ $s5 $.1 $7( $5 $B $7Y $f $s $8% $f. $  $ $ $y $N% $ $ $ $)( $/? $ L $Y $Qp $| $  $ $9 $2. $M $: $c( $v) $ $( $', $18 $^ $.j $! $ $Z# $ $ $$ $+ $p8 $2 $.. $*: $^F $W"S $o.` $Dn $z  $" $$ $  $ $ $ $ $ $< $J'( $5 $E0B $&O $B\ $ i $v $E $d& $I $> $(0 $ $) $  $ $'3 $1 $. $7 $o, $9 $F $,*S $|` $0m $%.z $) $W $ $ $ $! $# $i' $ $&& $2 $> $4Z $ f $6x $&~ $* $ $. $g5 $ $ $`% $K( $t $g $ $ $w( $|7 $8 $ $i+ $U $0 $y $ $  $\, $49 $d$G $wS $0e $ek $b q $ w $ } $# $ $! $+ $ $ $ $ $V $1 $a8 $ ( $ -5 $B $O $\ $%i $N v $ $5 $ $+ $' $( $! $" $ $g $ $0 $= $ I $z+U $,a $'m $ y $1 $C $44 $ $6 $i $* $ $ $ $) $ $X $ $ ${# $ 2 $  $/ $  $S4 $ $R3 $$ $t4* $10 $&6 $ < $B $R H $-N $v.T $Z $E` $f $)l $1r $Ux $~ $) $# $ $V6 $* $2 $f $e1 $ $  $  $  $W/ $ $ $/ $/ $d, $V- $ $(4 $ $d $+ $ $t1 $  $-& $}, $(2 $8 $k> $5D $rJ $#P $$V $\ $b $P$h $(n $t $z $1 $ $5 $y* $ $ $5 $  $3 $! $ $# $L $-' $  $& $& $+& $ $ $ $X $g $v $R0  $, $4 $) $I1" $f( $%. $34 $ : $o@ $ F $XL $\R $)!X $O^ $d $&j $1p $Y5v $ | $U( $h $6 $$ $! $P $% $% $H5 $) $o" $ $7 $0 $ $. $ $ $S. $  $ $  $1 $6!  $  $Y  $3 $$ $k6* $0 $6 $S< $B $"H $8N $k3T $Z $0` $%f $ #l $r $'x $~ $' $& $g! $ $|% $% $ $7" $  $  $Y $$  $ $A8 $R ${- $6 $2 $- $ $Z* $/ $b  $I& $ $) $?#  $'& $, $'2 $8 $5> $2D $&/J $ P $l$V $7\ $sb $F2h $Jn $t $z $p  $ $} $ $ $  $ $( $  $2 $  $  $7# $^ $ $S' $# $9 $f/? $7E $ K $; Q $06W $] $0c $i $3o $u ${ $ $+ $<5 $:* $' $ $  $ $F  $ $ $' $W)N $[ $n $4z $2 $ $W  $  $. $ $4 $. $8 $  $K $&- $7; $q&I $W $D$e $ys $  $ $ $- $#  $  $1 $i $  $|8 $2 $% $" $ ( $. $4 $ : $b'@ $C+F $+L $I!R $ X $-^ $d $0j $kp $v $80| $# $ $* $- $}3 $ $ $$5 $05 $o) $ $ $$ $2  $H- $ : $)G $3T $a $Q n ${ $/ $. $* $5 $T% $ $ $ $02 $  $- $q: $ H $4U $2b $ r $/$w $  $  $ $ $  $ $  $]' $w! $4 $ $A $," $I"/ $<'< $(+I $F*V $q/c $kp $'-} $ $5 $W $ $? $% $% $ $ $ $?,  $ $& $ 3 $@ $4M $-Z $Y,g $ t $6 $y $# $W $-( $l $l( $N $! $ $  $( $" $/ $d < $m I $ $D $)$ $/ $7+ $O $i $?! $ $2 $ $/ $N $! $  $gl $ $"1: $GP $']f $s| $h  $7) $ $; $* $ $,5 $3BK $:(X0a $0nd w $ $0- $Z`  $5X  $U!P  $I)( # $09 $%Fx_ $"1l  $ $o%@ $` $) $92 $- p $5 l( $"6 h? $M dV $ d `m $ r $  X $ P $" H $ @ $0*! $8!8[! $! $K/!0! $2!)! $K! $~! $x!(! $ !(" $/" +" $)9"B" $c)P" $0^" $0l" $z" $C" $*"" $(" $]'" $" $] " $," $" $ # $<.# $8# $,# $":# $H# $0W# $/3d# $r# # $## $"## $## $l## $&## $ $@ $ $b$"$ $b0$9$ $CF$ $0R$dy$ $0 $`d$ $&$ $ $ $$$ 1$ - % % j % ~$% R3% 7% pF% hJ% @V% $ ^%Ku% $q% % % X% P% $% % % ( % " %3K%3K% s % q %  &  &  &  &QK$&QKA&  E&  N&  R&  [& 8 _& 6 i&pKs& " & _ & [ &  &  &  &  &~K&K& "`&  &  &  &  & M & K 'K ' "' r !' p *'  .'  7'  ;'  A'QK_'K' $U1'J'  '  '  '  ' h ' \ '  '  ' "@ ( ( (dJD(|JN( "p_( c( l( p( y( @}( <(J(J(J( "( ( ( ( ) )  )J/)J9) "J) $N)  W) d[) bd) h) m)J{)J) $$)I) $') $ ) $ *`I"* $D1.* 2* 7* $gC* G* L* $p,X* \\* Ra* $m* q* v* $'7* <* 4*dI* "* * * * *I*I*I+IB+ $5N+P@p+ t+ + + + + + + + $+ + +pF+ $$"+F ,@,@3, 7, <,@Y,@c, " t, 6x, 4},@,A,A, ], Y,A,5A,5A- - -DA:-[AD-[Aa- e- j-jA-A-A- - -A-A-A- - .A!.B+.BH. )L. 'Q.Bn.)Bx.)B. N. L.8B.PB.PB. s. q._B/wB/wB// 3/ 8/BU/B_/B|/ / /B/B/B/ / /B/B/ " 0 " 0  0 0 E 0 ?)0 " 60 :0 C0FM0Fj0 rn0 ps0F0G0G0 0 0"G0DG0 " 0 0 1 " 1 1 r 1DG*1DGG1 K1 T1 AX1 ;]1UG1`G1`G1 1 1 1 1qG1G1G 2 2 2 A2 ?%2 o)2 m.2GE2U2Gm2H2H2;I2]2F2C]2G3Co 38G3C&3'C73CVG3QCQ3 "@ ^3 "@ g3 k3 t3fC~3fC3 3 3uC3hE3 " 3H3  3 3H 4H#4I84yEM4C^4Ey4C4E4E4 " 4 " 4 Z4 V4E4C4E4C5E#5C-5FH5CR5"Fm5Cw5PF5]5\F5H5]C5C5 H5C5C5C6C*6 .6 760DL6 P6 \6Ff6F6 4 6 2 6F6F6F6@6C7@7@#7C-7@B7C+L7@a7C=k70A7CN7VA7Cb7qA7}A7Cw7A7C7A8A8A#8C-8AB8CL8BY8$Bn8Cx8?B8KB8C8fB8rB8C8B8B8C8B 9B9C*(9B=9C@G9D_9Dl9D9C9E9C95E9RE9`E9EI9 $O7: $14: $ F: $1S: $ a: $ ~: $'': $]: $;&: $/; $w3; $,?;@@R; $n Z;0@m; $(8y; @; $+;@; $; $";?; $; $B;? < $k< $5!<?8< $H< $P<?g< $w< $3<p?< $%%< $6<`?< $< $<P?< $/= \ = X = $+=`Y-= $D19=  ==  M= !!Q= !b= !f= !k= $E7w= ="{= /"= $= $q*= "= $ = $3=aZ= "= "=iZ >(_ > $,> #0> #:>@[D> "U> ($Y> $b> ($f> $o> $s> $x> "> %> %> 0&> &> 5'> +'> '> '> (> '> I)> /))? "A?]Z? W*^? S*c?]u?`_? *? *?_?_?_?c? "? +? +? "@c@ " @ +$@ +-@ +1@ +:@  ,>@ ,H@cR@co@ 1,s@ /,|@ W,@ U,@ },@ {,@c@c@E[@t[@[ A[#A[HA[mA"\AG\A\A` A\A\A\B\&Bb]LBy]YB]}B_B]B_B@`BS`B``Bo`C`EC`RC`_C`C`C]CaC9aCCCaC](CaCaD]D$J>2Ju;?J;WJ;wJJ;J;JJ<J@J!< KK=<7KAK<RK` \K<sK<K<K<K>=KW=Ks=K L=$L3L=ML\L=vL@L=LL:>L]LD>L>L> M> MC*M??MCIM'?^M]hM5?MH?M $@M:M $D1M 2M  2M ;M $*M a2M _2M;N%;N $N95N $D1AN 2EN 2JN $*"VN 3ZN 3cN:mN " ~N *3N (3N " N:N " N O3N M3N u3N s3N 3N 3N:N "P N 3N 3O 3O 3O 4O 4O:'O:HO9UO9bO9oO:OO::O:O:O:O $;O $O $D1 P $lP $&&P $ 3P $b@P $bMP $kZP $E7P $(P $*P $P $q*P $P $_"P $ P $3Q $Q $Q@91Q $n9QLQ $TQkQ $i"wQ G4{Q 94Q $Q 4Q 4Q $z5Q o5Q c5Q $XQ 6Q 5Q $Q 6Q 6Q $Q ^7Q X7Q $VQ 7Q 7QCR]P&RO=R[R]eR|RR R]RR $3RR $R 8R 7S $i"S 8S 8S $b,S6SSS 8WS 8`S  9dS  9mS 69qS 29vSS]S S3S<SdS]pTm&T>TUTjTCRtTT $T T $T y9T o9T $T 9T 9T $*"T :T :T U U ;$U ;-U B;1U @;:U j;>U f;CU dU UX Us UCU $7U $U $^U $1V $5V $kV $ ,V $!;V $CV8ZV $fV ;jV ;oV $V{V ;V ;V $$VV $V ;V ;V $VV *<V $<V V W u< W s<W <W <"W <&W <-W $5WLW $\W $#hW W $5W <W <W .=W "=W $.W $1W Xl 0Xs NX $VX8|X $DX $*"X $X $X 7X $)X =X =X $O X =X =Y $v Y X>#Y T>5YM7TY[7rY7Y $Y $)Y $"Y $(Y $VY $#Y $ Y $3Z $9"Z59Z $EZ >IZ >NZ $O ZZ J?^Z :?oZ @sZ ?Z P@Z J@Z $dZ $6Z @Z @ZR6Zl6Z6[6@[6^[6k[6x[6[6[ $[ $D1[ $[ $1%[ $<6 \2"\ $D1.\ @2\ @7\ $C\ /AG\ 'AL\ $}X\ A\\ Aa\ $m\ Aq\ Av\ $ \ LB\ FB\ B\ B\ "P \ B\ B\ " \ (C\ $C\3\ $1%\ dC] ^C]4]4)] " :] C>] CG] CK] CT] +DX] )D]]14}]I4] " ] TD] PD] D] D] D] D]S4]33]3^ $?^'&^ $D19^_(C^ "P^ DT^ D]^ )Ea^ 'Ej^ QEn^ MEu^ $6^'^ $D1^ E^ E^ E^ E^ KF^ CF^'^ $!^P'_ $D1"_ F&_ F6_ G:_ FK_ kGO_ cGT_'q_ $ }_0_ $*_ G_ G_ 6H_ .H_ H_ H_ 5I_ )I_ $V_ I_ I` J ` J`{ ` $ ,`0%C` $D1O` JS` Jc` Kg` Kx` L|` L` lL` hL` L` L` $` L` L` 9M` 5M` $` }M` oM` "@` $ a &Na Na $ !a N%a N*a $"6a N:a N?a $Ka 4OOa &OTa $x`a Oda Oia $Vua Pya P~ax&a cPa aPa&a $a Pa Pa&ac&a "pb Pb Pb Qb P(b /Q,b -Q2b&[b%bE'b $ b#b $D1b ^Qb RQb Qb Qb Rb }Rc JSc >Sc Sc S!c $-c NT1c BTBc TFc TKc $Wc 5U[c #U`c $#rc#c $ c Uc Uc $c cVc [Vc $xc Vc Vc $Vc Vc Vc$cd$4d>d$Rd$%qd $}d d $}d d $D1d EWd 3Wd $d  Xd  Xd $/7 e 4Xe 0Xe $V$e "`;e "`De rXHe lXQe XUe X^e "ke Xoe Xxe RY|e JYe Ye Ye Ye Ye *Ze &Ze dZe `Ze "e Ze Ze "e Ze Zee"e!fd!(f $:f $D1Gf $_f $xf $ f $"f $f $xf $Vf $f $f $D1g $ g $1-g $VEg $"Rg $yg $z g $g(g $D1g e[g Y[g [g [g o\g g\g(h "h \h \(h ],h ]5h h]9h f]>h "Lh ]Ph ]Zh)qh(h!)h])h $'hp h $D1h $3h ]h ]h $Q i T^ i R^i i " *i y^.i w^7i ^;i ^Di ^Hi ^Oi $u[i2ri $D1~i ^i ^i $.i _i _i y`i i`i $i 7ai 'ai $3i ai aiU2i " i bi bj b j bj bj bjU26jz2Sj2zj2j $,j $D1j $j $3j $Vj $Q j $.k $"k $Y2!k $-k`Dk $D1Pk cTk  cYk $ek cik cnk $Q zk c~k ck ddk Xdk $/k  ek ekk "k nek jek ek ekl l "l e!l e*l f.l f7l Af;l =f@l "Il {fMl wfVl `l }l fl fl fl fl fl fl l! l $'ll $D1m *gm  g m $m gm gm $Q *m h.m h3m $?m thCm jhTm hXm h]m $},im (imm  irm $x~m im im $cm im im $xm jm jm jm jmm " m km km Tkm Pkm kn kn$nCn(Mn(jn knn ksn(n ln kn4nn $ nn $D1n Tln Hloo+o l/o l4oNo mRo mWono $/o $D1o $o $o0o $D1o $+o ;mo 7mo zmo tmp $Lp(p $D14p m8p m=pJpWpdp&rp $zpp $D1p #np npp "p qnp onp np np $D p/q $D1 q nq nq/.q/Fq/fq!0{q $e4q.q $D1q Doq 8oq#/qP/qX/qm/ r $67rW,r $D18r os(QsWisXsFXsXsXsXsXtXtKY9tUYGt $2 St`jt $D1zt $ tpttt $)tt $D1t Eqt ;qt qu qu $ u Mru Kru(u "9u rr=u prFu rJu rYu3cu "@tu rxu ru ru ru "@u  su  su<uuu Esu Csu v0vCv]Mv "^v jsbv hskv sov stvdvCovvv=vOwmw&w $_0.wTw $`wsw ${ww $9ww "w $w sw swwwwx x~ vB~ vK~ vO~ vY~+~C~;+~E+~[+~c+~+~+~+ $ $ $r 6 $]+\ ${ $. $  $D1 $ $x $V $ $D14 $xA $VP $s^ $D1w $ $( $;$ ̀ $0؀ w܀ w $ jw fw $/7 $V w w $+,& x*  x/ $; Sx? GxD $ P xT xZ $(x $1 $g $0 $& $́ $ $x $3 $[ $&0 = $D1I yM yR $^ Fzb @zq zu zzH $D3 $D1ł $ׂ $D1 $ $ $: $#* $7 $Q $},p $1 $ $ #ă $D1҃ $W $2  , z0 z5 $$A {E {V &|Z  |_  $6 $3 $S҄ $ ܄ $n#0 $) w| o| $+ | |5`Xp $(Ѕ $m-؅ $P $3@, $8 E}< =}A $M }Q }VVnwC[ $+@ $dʆ ~Ά  ~ކ ~ ~ \ H $ 6 0.0eo "P     ܀ ڀ̇]ۇcc   / - W U$NC"YBvOS " ~ z ˆ ˈ ψ ԈX # , G0 E9 n= lBjC2~ "    ĉ ȉ ͉C8 " "#  , P0 N5)KCF\iw $s $D1 $g $- $/ $ˊ $>܊ $( $/ $0 $+ $! $Q* $-7 $H $!T $Qa $r $!~ $f3 $- $. $! $Q $-͋ $ ދ $! $Q $- $ $ $, $0? $2P $\ $j $ $ $^ $5 $.֌ $ $2 $  $2 $A-( $(5 $r7I $SZ $f $#&t $91 $- $/ $- ύ Ӎ t܍   H B "    ' @+ <0 "09 |= vF P m Džq Ņz ~     Ŏ0 @ @  6 4!G 9Q Lw Vw v c Y ߆ Ն [ Q ه ͇ŏ mɏ aҏ ֏  e+5 "`BPgy [ S   & Đ Ȑ    X R''$ ( 1 ʋ5 ȋ> B G<lv " , * S Q z vϑFّ "  Nx "1 ٌ5 ׌> B K (O $Yc "Pt ex a   ͍ ˍ "˒ ϒ ؒ ܒ  k (C2P{9ؓ Cܓ ? " "$ ( |1 V5 J> B ؏K vO pX "e i r v {z”ؔ)      ?# 1T)^){  ޒ 5 1 q m)  ɕ ԓ͕ ̓֕ <ڕ 4   Ô {* " * . 7 ";  D HH FQ nU lZ " h l u Εy ̕~*D* "p Ö ̖ 0Ж .ٖ Vݖ T)**8*J,e i y|, "  y     "̗ MЗ Gٗ ݗ - "@ ԙ ҙ   -7{-A{-^ #b k ^o \t{-  -r-Ҙ].ߘ..- "p  # "p, 0 9-C-` d m q v---<.ۙC.R..%]X;x.Ex.b ٛf ӛkx..]8.00ך 1ۚ % ɜ   "0, "= 0A (J N W [ ` "i Bm 6v ɟz ş    {   J D0ƛ "ܛ    11 " + / 8 /< -A1dc1|114 `Ü R̜  М ٜ ݜ  " / # 5# ' 1>5J FN @Sg5lq5v "P      ޥ5ǝ7   ] W7=7X \ e i r v 7 " ? 5   3 -7֞8'868@88(KC G |P <T :b,Ll "} c _   ת Ӫ "   0L0Lݟ I G n l  =L!HL4L> " O S X " a e n 2r *{LL    LѠ ۬ՠ ٬8M8M   % #! J% H*@M? qC mL@MV@Ms w  έ ̭  NMYMʡMԡ "     "    ^ T'M1MN ϯR ͯ[ _ h l qMMM D B i gȢ ̢ ѢM  MNN< ް@ ܰI M V +Z )_Ny!N!N S Q x v  !Nԣ ȱأ Ʊݣ8NyO " " ' "0 4 = A JO_ @c >l ep c|OPOP  OP Ť ΤOPؤ "0 Գ ҳ "0   "  kP! "p2 G6 E; "pD nH lQ U `yPj "{   "  ߴ  P "ĥ Cȥ Aͥ "֥ jڥ h  P "`   "` ޵# ܵ, 0 ;PE "V +Z )_ "h Rl Pu {y wP "   " ۶ ٶ ¦ ͦPצ "` ( & "` O M v tP "- 1 6 "? ÷C L P ]Q{Q ' #"Q a _ç ǧ Ч3Qڧ3Q  3Q ݸ ۸ " .bQC +G %P xT v]Qg "x |  " ۹ ׹  Q "0¨ "0Ш :Ԩ 8ߨQ "p "p _ ]Q" "0 "> B P\UZ\Uw { \U κ ̺iUUթpNN P)C30VQC6[/Wu]vRvR   ê ȪvRݪ = ;R R "' j+ `0 "9 = ٻF J ~S W ` (d m q z  ~  E ?_S "p    ɫ ߾ͫ ۾֫ ګ  C = "S " " & / 3 < @ FS^SSSǬTѬ "`       6 ( "  ( *, 5U? "U Y b "t xx rhWhW  hW­W 3T&hW=]RU\UuVV] TϮ\TyTTT6UNAV[iVhVCVVCɯVJWC W"C3T@T[CeUrU]8U]pİUΰU     6 4U ". d2 b;UE " R V _UiU  UU   ñ ȱ5Uٱ(P CTWU2C< WVC&m Pw P * ( T P P ò Ȳ.P߲TW $ $ $. $g $~' $~' $7 $7 $"$ $"$( $S, $4 $b8 $bA $>E $[M $#!Q $#!Z $0^ $0g $h*k $h*s $w $ $m $m $H $H $ $ $* $* $ $ $ ³ $ ˳ $0)ϳ $0)س $ ܳ $ $% $% $ $ $h $h $ $  $ $ $/" $/+ $"/ $"8 $B%< $B%D $H $P $D!T $D!\ $` $i $&m $&u $3,y $3, $5* $5* $' $' $ $ $, $, $G- $ $ô $̴ $4д $4ٴ $7ݴ $7 $ $ $H4 $H4 $, $, $" $" $ $! $)% $)- $^21 $^2: $7> $7F $W+J $W+S $c7W $c7_ $/c $/k $Z8o $Z8w $z&{ $z& $$ $$ $( $( $ $ $ $ĵ $ȵ $е $/Ե $/ܵ $ $ $ $ $2 $2 $+ $" $  $* $<" $<* $. $6 $: $B $ F $ O $eS $e\ $` $h $l $t $-x $ $4 $4 $$* $$* $J $J $J $ $ $ $K $Kȶ $a̶ $aԶ $P,ض $P, $ $ $ $ $3 $3 $ $T+'-(- 38]QCp(sCovC]C",C2C85CF ʿI(   4H \00L`0     \ 0  $L@ X0@Xl`p,@\0p` p 4 #0%8P'L'`'t()+P , , . / 00\ 2 2 4X 5 7  7 7$ 88 8L @9` 9 : 0; P? `?( p?< ?P ?d ?x ? @  @ 0@ @@ P@`I\IpJKK4W|`Y`dd.symtab.strtab.shstrtab.rela.text.data.bss.rela.gnu.build.attributes.text.hot.rela.gnu.build.attributes.hot.text.unlikely.rela.gnu.build.attributes.unlikely.text.startup.rela.gnu.build.attributes.startup.text.exit.rela.gnu.build.attributes.exit.rodata.str1.1.rodata.str1.8.rodata.rela.data.rel.local.rela.data.rel.rela.data.rel.ro.local.rela.debug_info.debug_abbrev.rela.debug_loc.rela.debug_aranges.debug_ranges.rela.debug_line.debug_str.comment.text.hot.zzz.text.unlikely.zzz.text.startup.zzz.text.exit.zzz.note.GNU-stack.note.gnu.property.rela.eh_frame.groupP@:PT:Pl:P:P: d@@A@G:&`ep ,n 6nt"1@ : LT[TV@P0: u((@0:@0:ЖЖ@0:22/"D /`8 *@:D?@:S N@p:kf@(\:!wa-i@ :$/0@0:& 0`lJR@H:)0}807.eeueLe eeeeee.h FA@((:8x4; ('PWPKu]]z.##!ruby-lsapi-5.5/ext/lsapi/Makefilenu[ SHELL = /bin/sh # V=0 quiet, V=1 verbose. other values don't work. V = 1 Q1 = $(V:1=) Q = $(Q1:0=@) ECHO1 = $(V:1=@ :) ECHO = $(ECHO1:0=@ echo) NULLCMD = : #### Start of system configuration section. #### srcdir = . topdir = /opt/alt/ruby27/include hdrdir = $(topdir) arch_hdrdir = /opt/alt/ruby27/include PATH_SEPARATOR = : VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby prefix = $(DESTDIR)/opt/alt/ruby27 rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) rubyarchprefix = $(DESTDIR)/opt/alt/ruby27/lib64/ruby rubylibprefix = $(exec_prefix)/share/ruby exec_prefix = $(DESTDIR)/opt/alt/ruby27 vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby rubyarchhdrdir = $(DESTDIR)/opt/alt/ruby27/include vendorhdrdir = $(rubyhdrdir)/vendor_ruby sitehdrdir = $(rubyhdrdir)/site_ruby rubyhdrdir = $(DESTDIR)/opt/alt/ruby27/include rubygemsdir = $(DESTDIR)/opt/alt/ruby27/share/rubygems vendorarchdir = $(DESTDIR)/opt/alt/ruby27/lib64/ruby/vendor_ruby vendorlibdir = $(vendordir) vendordir = $(DESTDIR)/opt/alt/ruby27/share/ruby/vendor_ruby sitearchdir = $(DESTDIR)./.gem.20230713-1832549-9v9h3w sitelibdir = $(DESTDIR)./.gem.20230713-1832549-9v9h3w sitedir = $(DESTDIR)/opt/alt/ruby27/share/ruby/site_ruby rubyarchdir = $(rubyarchprefix) rubylibdir = $(rubylibprefix) sitearchincludedir = $(includedir)/$(sitearch) archincludedir = $(includedir)/$(arch) sitearchlibdir = $(libdir)/$(sitearch) archlibdir = $(DESTDIR)/opt/alt/ruby27/lib64 ridir = $(datarootdir)/$(RI_BASE_NAME) mandir = $(DESTDIR)/opt/alt/ruby27/share/man localedir = $(datarootdir)/locale libdir = $(exec_prefix)/lib64 psdir = $(docdir) pdfdir = $(docdir) dvidir = $(docdir) htmldir = $(docdir) infodir = $(DESTDIR)/opt/alt/ruby27/share/info docdir = $(datarootdir)/doc/$(PACKAGE) oldincludedir = $(DESTDIR)/usr/include includedir = $(DESTDIR)/opt/alt/ruby27/include localstatedir = $(DESTDIR)/var sharedstatedir = $(DESTDIR)/var/lib sysconfdir = $(DESTDIR)/etc datadir = $(DESTDIR)/opt/alt/ruby27/share datarootdir = $(prefix)/share libexecdir = $(DESTDIR)/opt/alt/ruby27/libexec sbindir = $(DESTDIR)/opt/alt/ruby27/sbin bindir = $(exec_prefix)/bin archdir = $(rubyarchdir) CC_WRAPPER = CC = gcc CXX = g++ LIBRUBY = $(LIBRUBY_SO) LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a LIBRUBYARG_SHARED = -Wl,-rpath,$(archlibdir) -L$(archlibdir) -l$(RUBY_SO_NAME) LIBRUBYARG_STATIC = -Wl,-rpath,$(archlibdir) -L$(archlibdir) -l$(RUBY_SO_NAME)-static $(MAINLIBS) empty = OUTFLAG = -o $(empty) COUTFLAG = -o $(empty) CSRCFLAG = $(empty) RUBY_EXTCONF_H = cflags = $(optflags) $(debugflags) $(warnflags) cxxflags = optflags = -O3 debugflags = -ggdb3 warnflags = -Wall -Wextra -Wdeprecated-declarations -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable cppflags = CCDLFLAGS = -fPIC CFLAGS = $(CCDLFLAGS) -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection $(ARCH_FLAG) INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) DEFS = CPPFLAGS = $(DEFS) $(cppflags) -DRUBY_2 CXXFLAGS = $(CCDLFLAGS) -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection $(ARCH_FLAG) ldflags = -L. -L/opt/alt/ruby27/lib64 -Wl,-rpath=/opt/alt/ruby27/lib64 -fstack-protector-strong -rdynamic -Wl,-export-dynamic dldflags = -L/opt/alt/ruby27/lib64 -Wl,-rpath=/opt/alt/ruby27/lib64 ARCH_FLAG = -m64 DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) LDSHARED = $(CC) -shared LDSHAREDXX = $(CXX) -shared AR = ar EXEEXT = RUBY_INSTALL_NAME = $(RUBY_BASE_NAME) RUBY_SO_NAME = ruby RUBYW_INSTALL_NAME = RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version_dir_name) RUBYW_BASE_NAME = rubyw RUBY_BASE_NAME = ruby arch = x86_64-linux sitearch = $(arch) ruby_version = 2.7.0 ruby = $(bindir)/$(RUBY_BASE_NAME) RUBY = $(ruby) BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME) ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h RM = rm -f RM_RF = $(RUBY) -run -e rm -- -rf RMDIRS = rmdir --ignore-fail-on-non-empty -p MAKEDIRS = /usr/bin/mkdir -p INSTALL = /usr/bin/install -c INSTALL_PROG = $(INSTALL) -m 0755 INSTALL_DATA = $(INSTALL) -m 644 COPY = cp TOUCH = exit > #### End of system configuration section. #### preload = libpath = . $(archlibdir) LIBPATH = -L. -L$(archlibdir) -Wl,-rpath,$(archlibdir) DEFFILE = CLEANFILES = mkmf.log DISTCLEANFILES = DISTCLEANDIRS = extout = extout_prefix = target_prefix = LOCAL_LIBS = LIBS = $(LIBRUBYARG_SHARED) -lm -lc ORIG_SRCS = lsapilib.c lsruby.c SRCS = $(ORIG_SRCS) OBJS = lsapilib.o lsruby.o HDRS = $(srcdir)/lsapidef.h $(srcdir)/lsapilib.h LOCAL_HDRS = TARGET = lsapi TARGET_NAME = lsapi TARGET_ENTRY = Init_$(TARGET_NAME) DLLIB = $(TARGET).so EXTSTATIC = STATIC_LIB = TIMESTAMP_DIR = . BINDIR = $(bindir) RUBYCOMMONDIR = $(sitedir)$(target_prefix) RUBYLIBDIR = $(sitelibdir)$(target_prefix) RUBYARCHDIR = $(sitearchdir)$(target_prefix) HDRDIR = $(rubyhdrdir)/ruby$(target_prefix) ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix) TARGET_SO_DIR = TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) CLEANLIBS = $(TARGET_SO) CLEANOBJS = *.o *.bak all: $(DLLIB) static: $(STATIC_LIB) .PHONY: all install static install-so install-rb .PHONY: clean clean-so clean-static clean-rb clean-static:: clean-rb-default:: clean-rb:: clean-so:: clean: clean-so clean-static clean-rb-default clean-rb -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time distclean-rb-default:: distclean-rb:: distclean-so:: distclean-static:: distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true realclean: distclean install: install-so install-rb install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.time $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) clean-static:: -$(Q)$(RM) $(STATIC_LIB) install-rb: pre-install-rb do-install-rb install-rb-default install-rb-default: pre-install-rb-default do-install-rb-default pre-install-rb: Makefile pre-install-rb-default: Makefile do-install-rb: do-install-rb-default: pre-install-rb-default: @$(NULLCMD) $(TIMESTAMP_DIR)/.sitearchdir.time: $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) $(Q) $(TOUCH) $@ site-install: site-install-so site-install-rb site-install-so: install-so site-install-rb: install-rb .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S .cc.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cc.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .mm.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .mm.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .cxx.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cxx.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .cpp.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cpp.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .c.o: $(ECHO) compiling $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .c.S: $(ECHO) translating $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .m.o: $(ECHO) compiling $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .m.S: $(ECHO) translating $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< $(TARGET_SO): $(OBJS) Makefile $(ECHO) linking shared-object $(DLLIB) -$(Q)$(RM) $(@) $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) $(OBJS): $(HDRS) $(ruby_headers) PKu] 3O8aa#ruby-lsapi-5.5/ext/lsapi/lsapilib.cnu[//#define LSAPI_DEBUG /* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lsapilib.h" #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #include #endif #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #include #endif #include #ifndef uint32 #define uint32 uint32_t #endif struct lsapi_MD5Context { uint32 buf[4]; uint32 bits[2]; unsigned char in[64]; }; void lsapi_MD5Init(struct lsapi_MD5Context *context); void lsapi_MD5Update(struct lsapi_MD5Context *context, unsigned char const *buf, unsigned len); void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *context); /* * This is needed to make RSAREF happy on some MS-DOS compilers. */ typedef struct lsapi_MD5Context lsapi_MD5_CTX; #define LSAPI_ST_REQ_HEADER 1 #define LSAPI_ST_REQ_BODY 2 #define LSAPI_ST_RESP_HEADER 4 #define LSAPI_ST_RESP_BODY 8 #define LSAPI_ST_BACKGROUND 16 #define LSAPI_RESP_BUF_SIZE 8192 #define LSAPI_INIT_RESP_HEADER_LEN 4096 enum { LSAPI_STATE_IDLE, LSAPI_STATE_CONNECTED, LSAPI_STATE_ACCEPTING, }; typedef struct lsapi_child_status { int m_pid; long m_tmStart; volatile short m_iKillSent; volatile char m_inProcess; volatile char m_state; volatile int m_iReqCounter; volatile long m_tmWaitBegin; volatile long m_tmReqBegin; volatile long m_tmLastCheckPoint; } lsapi_child_status; static lsapi_child_status * s_worker_status = NULL; static int g_inited = 0; static int g_running = 1; static int s_ppid; static int s_restored_ppid = 0; static int s_pid = 0; static int s_slow_req_msecs = 0; static int s_keep_listener = 1; static int s_dump_debug_info = 0; static int s_pid_dump_debug_info = 0; static int s_req_processed = 0; static int s_skip_write = 0; static int (*pthread_atfork_func)(void (*prepare)(void), void (*parent)(void), void (*child)(void)) = NULL; static int *s_busy_workers = NULL; static int *s_accepting_workers = NULL; static int *s_global_counter = &s_req_processed; static int s_max_busy_workers = -1; static char *s_stderr_log_path = NULL; static int s_stderr_is_pipe = 0; static int s_ignore_pid = -1; static size_t s_total_pages = 1; static size_t s_min_avail_pages = 256 * 1024; static size_t *s_avail_pages = &s_total_pages; LSAPI_Request g_req = { .m_fdListen = -1, .m_fd = -1 }; static char s_secret[24]; static LSAPI_On_Timer_pf s_proc_group_timer_cb = NULL; void Flush_RespBuf_r( LSAPI_Request * pReq ); static int lsapi_reopen_stderr(const char *p); static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] = { "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHORIZATION", "HTTP_CONNECTION", "CONTENT_TYPE", "CONTENT_LENGTH", "HTTP_COOKIE", "HTTP_COOKIE2", "HTTP_HOST", "HTTP_PRAGMA", "HTTP_REFERER", "HTTP_USER_AGENT", "HTTP_CACHE_CONTROL", "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH", "HTTP_IF_NONE_MATCH", "HTTP_IF_RANGE", "HTTP_IF_UNMODIFIED_SINCE", "HTTP_KEEP_ALIVE", "HTTP_RANGE", "HTTP_X_FORWARDED_FOR", "HTTP_VIA", "HTTP_TRANSFER_ENCODING" }; static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] = { 11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18, 22, 13, 18, 13, 24, 15, 10, 20, 8, 22 }; static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] = { "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Authorization", "Connection", "Content-Type", "Content-Length", "Cookie", "Cookie2", "Host", "Pragma", "Referer", "User-Agent", "Cache-Control", "If-Modified-Since", "If-Match", "If-None-Match", "If-Range", "If-Unmodified-Since", "Keep-Alive", "Range", "X-Forwarded-For", "Via", "Transfer-Encoding" }; static int HTTP_HEADER_LEN[H_TRANSFER_ENCODING+1] = { 6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, //user-agent 13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17 }; static const char *s_log_level_names[8] = { "", "DEBUG","INFO", "NOTICE", "WARN", "ERROR", "CRIT", "FATAL" }; void LSAPI_Log(int flag, const char * fmt, ...) { char buf[1024]; char *p = buf; if ((flag & LSAPI_LOG_TIMESTAMP_BITS) && !(s_stderr_is_pipe)) { struct timeval tv; struct tm tm; gettimeofday(&tv, NULL); localtime_r(&tv.tv_sec, &tm); if (flag & LSAPI_LOG_TIMESTAMP_FULL) { p += snprintf(p, 1024, "%04d-%02d-%02d %02d:%02d:%02d.%06d ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)tv.tv_usec); } else if (flag & LSAPI_LOG_TIMESTAMP_HMS) { p += snprintf(p, 1024, "%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec); } } int level = flag & LSAPI_LOG_LEVEL_BITS; if (level && level <= LSAPI_LOG_FLAG_FATAL) { p += snprintf(p, 100, "[%s] ", s_log_level_names[level]); } if (flag & LSAPI_LOG_PID) { p += snprintf(p, 100, "[UID:%d][%d] ", getuid(), s_pid); } if (p > buf) fprintf(stderr, "%.*s", (int)(p - buf), buf); va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #ifdef LSAPI_DEBUG #define DBGLOG_FLAG (LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_FLAG_DEBUG|LSAPI_LOG_PID) #define lsapi_dbg(...) LSAPI_Log(DBGLOG_FLAG, __VA_ARGS__) #else #define lsapi_dbg(...) #endif #define lsapi_log(...) LSAPI_Log(LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_PID, __VA_ARGS__) void lsapi_perror(const char * pMessage, int err_no) { lsapi_log("%s, errno: %d (%s)\n", pMessage, err_no, strerror(err_no)); } static int lsapi_parent_dead() { // Return non-zero if the parent is dead. 0 if still alive. if (!s_ppid) { // not checking, so not dead return(0); } if (s_restored_ppid) { if (kill(s_restored_ppid,0) == -1) { if (errno == EPERM) { return(0); // no permission, but it's still there. } return(1); // Dead } return(0); // it worked, so it's not dead } return(s_ppid != getppid()); } static void lsapi_sigpipe( int sig ) { } static void lsapi_siguser1( int sig ) { g_running = 0; } #ifndef sighandler_t typedef void (*sighandler_t)(int); #endif static void lsapi_signal(int signo, sighandler_t handler) { struct sigaction sa; sigaction(signo, NULL, &sa); if (sa.sa_handler == SIG_DFL) { sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; sigaction(signo, &sa, NULL); } } static int s_enable_core_dump = 0; static void lsapi_enable_core_dump(void) { #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) int mib[2]; size_t len; #if !defined(__OpenBSD__) len = 2; if ( sysctlnametomib("kern.sugid_coredump", mib, &len) == 0 ) { len = sizeof(s_enable_core_dump); if (sysctl(mib, 2, NULL, 0, &s_enable_core_dump, len) == -1) perror( "sysctl: Failed to set 'kern.sugid_coredump', " "core dump may not be available!"); } #else int set = 3; len = sizeof(set); mib[0] = CTL_KERN; mib[1] = KERN_NOSUIDCOREDUMP; if (sysctl(mib, 2, NULL, 0, &set, len) == 0) { s_enable_core_dump = 1; } #endif #endif #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if (prctl(PR_SET_DUMPABLE, s_enable_core_dump,0,0,0) == -1) perror( "prctl: Failed to set dumpable, " "core dump may not be available!"); #endif } static inline void lsapi_buildPacketHeader( struct lsapi_packet_header * pHeader, char type, int len ) { pHeader->m_versionB0 = LSAPI_VERSION_B0; /* LSAPI protocol version */ pHeader->m_versionB1 = LSAPI_VERSION_B1; pHeader->m_type = type; pHeader->m_flag = LSAPI_ENDIAN; pHeader->m_packetLen.m_iLen = len; } static int lsapi_set_nblock( int fd, int nonblock ) { int val = fcntl( fd, F_GETFL, 0 ); if ( nonblock ) { if (!( val & O_NONBLOCK )) { return fcntl( fd, F_SETFL, val | O_NONBLOCK ); } } else { if ( val & O_NONBLOCK ) { return fcntl( fd, F_SETFL, val &(~O_NONBLOCK) ); } } return 0; } static int lsapi_close( int fd ) { int ret; while( 1 ) { ret = close( fd ); if (( ret == -1 )&&( errno == EINTR )&&(g_running)) continue; return ret; } } static void lsapi_close_connection(LSAPI_Request *pReq) { if (pReq->m_fd == -1) return; lsapi_close(pReq->m_fd); pReq->m_fd = -1; if (s_busy_workers) __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST); if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_IDLE, __ATOMIC_SEQ_CST); } static inline ssize_t lsapi_read( int fd, void * pBuf, size_t len ) { ssize_t ret; while( 1 ) { ret = read( fd, (char *)pBuf, len ); if (( ret == -1 )&&( errno == EINTR )&&(g_running)) continue; return ret; } } /* static int lsapi_write( int fd, const void * pBuf, int len ) { int ret; const char * pCur; const char * pEnd; if ( len == 0 ) return 0; pCur = (const char *)pBuf; pEnd = pCur + len; while( g_running && (pCur < pEnd) ) { ret = write( fd, pCur, pEnd - pCur ); if ( ret >= 0) pCur += ret; else if (( ret == -1 )&&( errno != EINTR )) return ret; } return pCur - (const char *)pBuf; } */ static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen ) { int ret; int left = totalLen; int n = count; if (s_skip_write) return totalLen; while(( left > 0 )&&g_running ) { ret = writev( fd, *pVec, n ); if ( ret > 0 ) { left -= ret; if (( left <= 0)||( !g_running )) return totalLen - left; while( ret > 0 ) { if ( (*pVec)->iov_len <= (unsigned int )ret ) { ret -= (*pVec)->iov_len; ++(*pVec); } else { (*pVec)->iov_base = (char *)(*pVec)->iov_base + ret; (*pVec)->iov_len -= ret; break; } } } else if ( ret == -1 ) { if ( errno == EAGAIN ) { if ( totalLen - left > 0 ) return totalLen - left; else return -1; } else if ( errno != EINTR ) return ret; } } return totalLen - left; } /* static int getTotalLen( struct iovec * pVec, int count ) { struct iovec * pEnd = pVec + count; int total = 0; while( pVec < pEnd ) { total += pVec->iov_len; ++pVec; } return total; } */ static inline int allocateBuf( LSAPI_Request * pReq, int size ) { char * pBuf = (char *)realloc( pReq->m_pReqBuf, size ); if ( pBuf ) { pReq->m_pReqBuf = pBuf; pReq->m_reqBufSize = size; pReq->m_pHeader = (struct lsapi_req_header *)pReq->m_pReqBuf; return 0; } return -1; } static int allocateIovec( LSAPI_Request * pReq, int n ) { struct iovec * p = (struct iovec *)realloc( pReq->m_pIovec, sizeof(struct iovec) * n ); if ( !p ) return -1; pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec ); pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec ); pReq->m_pIovec = p; pReq->m_pIovecEnd = p + n; return 0; } static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size ) { char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size ); if ( !p ) return -1; pReq->m_pRespHeaderBufPos = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf ); pReq->m_pRespHeaderBuf = p; pReq->m_pRespHeaderBufEnd = p + size; return 0; } static inline int verifyHeader( struct lsapi_packet_header * pHeader, char pktType ) { if (( LSAPI_VERSION_B0 != pHeader->m_versionB0 )|| ( LSAPI_VERSION_B1 != pHeader->m_versionB1 )|| ( pktType != pHeader->m_type )) return -1; if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT )) { register char b; b = pHeader->m_packetLen.m_bytes[0]; pHeader->m_packetLen.m_bytes[0] = pHeader->m_packetLen.m_bytes[3]; pHeader->m_packetLen.m_bytes[3] = b; b = pHeader->m_packetLen.m_bytes[1]; pHeader->m_packetLen.m_bytes[1] = pHeader->m_packetLen.m_bytes[2]; pHeader->m_packetLen.m_bytes[2] = b; } return pHeader->m_packetLen.m_iLen; } static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList, int *curSize, int newSize ) { struct LSAPI_key_value_pair * pBuf; if ( *curSize >= newSize ) return 0; if ( newSize > 8192 ) return -1; pBuf = (struct LSAPI_key_value_pair *)realloc( *pEnvList, newSize * sizeof(struct LSAPI_key_value_pair) ); if ( pBuf ) { *pEnvList = pBuf; *curSize = newSize; return 0; } else return -1; } static inline int isPipe( int fd ) { char achPeer[128]; socklen_t len = 128; if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&& ( errno == ENOTCONN )) return 0; else return 1; } static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count, char **pBegin, char * pEnd ) { struct LSAPI_key_value_pair * pEnvEnd; int keyLen = 0, valLen = 0; if ( count > 8192 ) return -1; pEnvEnd = pEnvList + count; while( pEnvList != pEnvEnd ) { if ( pEnd - *pBegin < 4 ) return -1; keyLen = *((unsigned char *)((*pBegin)++)); keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++)); valLen = *((unsigned char *)((*pBegin)++)); valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++)); if ( *pBegin + keyLen + valLen > pEnd ) return -1; if (( !keyLen )||( !valLen )) return -1; pEnvList->pKey = *pBegin; *pBegin += keyLen; pEnvList->pValue = *pBegin; *pBegin += valLen; pEnvList->keyLen = keyLen - 1; pEnvList->valLen = valLen - 1; ++pEnvList; } if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 ) return -1; *pBegin += 4; return 0; } static inline void swapIntEndian( int * pInteger ) { char * p = (char *)pInteger; register char b; b = p[0]; p[0] = p[3]; p[3] = b; b = p[1]; p[1] = p[2]; p[2] = b; } static inline void fixEndian( LSAPI_Request * pReq ) { struct lsapi_req_header *p= pReq->m_pHeader; swapIntEndian( &p->m_httpHeaderLen ); swapIntEndian( &p->m_reqBodyLen ); swapIntEndian( &p->m_scriptFileOff ); swapIntEndian( &p->m_scriptNameOff ); swapIntEndian( &p->m_queryStringOff ); swapIntEndian( &p->m_requestMethodOff ); swapIntEndian( &p->m_cntUnknownHeaders ); swapIntEndian( &p->m_cntEnv ); swapIntEndian( &p->m_cntSpecialEnv ); } static void fixHeaderIndexEndian( LSAPI_Request * pReq ) { int i; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { register char b; char * p = (char *)(&pReq->m_pHeaderIndex->m_headerLen[i]); b = p[0]; p[0] = p[1]; p[1] = b; swapIntEndian( &pReq->m_pHeaderIndex->m_headerOff[i] ); } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { swapIntEndian( &pCur->nameOff ); swapIntEndian( &pCur->nameLen ); swapIntEndian( &pCur->valueOff ); swapIntEndian( &pCur->valueLen ); ++pCur; } } } static int validateHeaders( LSAPI_Request * pReq ) { int totalLen = pReq->m_pHeader->m_httpHeaderLen; int i; for(i = 0; i < H_TRANSFER_ENCODING; ++i) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { if (pReq->m_pHeaderIndex->m_headerOff[i] > totalLen || pReq->m_pHeaderIndex->m_headerLen[i] + pReq->m_pHeaderIndex->m_headerOff[i] > totalLen) return -1; } } if (pReq->m_pHeader->m_cntUnknownHeaders > 0) { struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { if (pCur->nameOff > totalLen || pCur->nameOff + pCur->nameLen > totalLen || pCur->valueOff > totalLen || pCur->valueOff + pCur->valueLen > totalLen) return -1; ++pCur; } } return 0; } static uid_t s_uid = 0; static uid_t s_defaultUid; //web server need set this static gid_t s_defaultGid; #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #define LSAPI_LVE_DISABLED 0 #define LSAPI_LVE_ENABLED 1 #define LSAPI_CAGEFS_ENABLED 2 #define LSAPI_CAGEFS_NO_SUEXEC 3 struct liblve; static int s_enable_lve = LSAPI_LVE_DISABLED; static struct liblve * s_lve = NULL; static void *s_liblve; static int (*fp_lve_is_available)(void) = NULL; static int (*fp_lve_instance_init)(struct liblve *) = NULL; static int (*fp_lve_destroy)(struct liblve *) = NULL; static int (*fp_lve_enter)(struct liblve *, uint32_t, int32_t, int32_t, uint32_t *) = NULL; static int (*fp_lve_leave)(struct liblve *, uint32_t *) = NULL; static int (*fp_lve_jail)( struct passwd *, char *) = NULL; static int lsapi_load_lve_lib(void) { s_liblve = dlopen("liblve.so.0", RTLD_NOW | RTLD_GLOBAL); if (s_liblve) { fp_lve_is_available = dlsym(s_liblve, "lve_is_available"); if (dlerror() == NULL) { if ( !(*fp_lve_is_available)() ) { int uid = getuid(); if ( uid ) { if (setreuid( s_uid, uid )) {}; if ( !(*fp_lve_is_available)() ) s_enable_lve = 0; if (setreuid( uid, s_uid )) {}; } } } } else { s_enable_lve = LSAPI_LVE_DISABLED; } return (s_liblve)? 0 : -1; } static int init_lve_ex(void) { int rc; if ( !s_liblve ) return -1; fp_lve_instance_init = dlsym(s_liblve, "lve_instance_init"); fp_lve_destroy = dlsym(s_liblve, "lve_destroy"); fp_lve_enter = dlsym(s_liblve, "lve_enter"); fp_lve_leave = dlsym(s_liblve, "lve_leave"); if ( s_enable_lve >= LSAPI_CAGEFS_ENABLED ) fp_lve_jail = dlsym(s_liblve, "jail" ); if ( s_lve == NULL ) { rc = (*fp_lve_instance_init)(NULL); s_lve = malloc(rc); } rc = (*fp_lve_instance_init)(s_lve); if (rc != 0) { perror( "LSAPI: Unable to initialize LVE" ); free( s_lve ); s_lve = NULL; return -1; } return 0; } #endif static int readSecret( const char * pSecretFile ) { struct stat st; int fd = open( pSecretFile, O_RDONLY , 0600 ); if ( fd == -1 ) { lsapi_log("LSAPI: failed to open secret file: %s!\n", pSecretFile ); return -1; } if ( fstat( fd, &st ) == -1 ) { lsapi_log("LSAPI: failed to check state of file: %s!\n", pSecretFile ); close( fd ); return -1; } /* if ( st.st_uid != s_uid ) { lsapi_log("LSAPI: file owner check failure: %s!\n", pSecretFile ); close( fd ); return -1; } */ if ( st.st_mode & 0077 ) { lsapi_log("LSAPI: file permission check failure: %s\n", pSecretFile ); close( fd ); return -1; } if ( read( fd, s_secret, 16 ) < 16 ) { lsapi_log("LSAPI: failed to read secret from secret file: %s\n", pSecretFile ); close( fd ); return -1; } close( fd ); return 0; } int LSAPI_is_suEXEC_Daemon(void) { if (( !s_uid )&&( s_secret[0] )) return 1; else return 0; } static int LSAPI_perror_r( LSAPI_Request * pReq, const char * pErr1, const char *pErr2 ) { char achError[4096]; int n = snprintf(achError, sizeof(achError), "[UID:%d][%d] %s:%s: %s\n", getuid(), getpid(), pErr1, (pErr2)?pErr2:"", strerror(errno)); if (n > (int)sizeof(achError)) n = sizeof(achError); if ( pReq ) LSAPI_Write_Stderr_r( pReq, achError, n ); else if (write( STDERR_FILENO, achError, n )) {}; return 0; } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) static int lsapi_lve_error( LSAPI_Request * pReq ) { static const char * headers[] = { "Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0", "Pragma: no-cache", "Retry-After: 60", "Content-Type: text/html", NULL }; static const char achBody[] = "\n" "\n508 Resource Limit Is Reached\n" "\n" "

    Resource Limit Is Reached

    \n" "The website is temporarily unable to service your request as it exceeded resource limit.\n" "Please try again later.\n" "
    \n" "\n"; LSAPI_ErrResponse_r( pReq, 508, headers, achBody, sizeof( achBody ) - 1 ); return 0; } static int lsapi_enterLVE( LSAPI_Request * pReq, uid_t uid ) { if ( s_lve && uid ) //root user should not do that { uint32_t cookie; int ret = -1; ret = (*fp_lve_enter)(s_lve, uid, -1, -1, &cookie); if ( ret < 0 ) { //lsapi_log("enter LVE (%d) : result: %d !\n", uid, ret ); LSAPI_perror_r(pReq, "LSAPI: lve_enter() failure, reached resource limit.", NULL ); lsapi_lve_error( pReq ); return -1; } } return 0; } static int lsapi_jailLVE( LSAPI_Request * pReq, uid_t uid, struct passwd * pw ) { int ret = 0; char error_msg[1024] = ""; ret = (*fp_lve_jail)( pw, error_msg ); if ( ret < 0 ) { lsapi_log("LSAPI: LVE jail(%d) result: %d, error: %s !\n", uid, ret, error_msg ); LSAPI_perror_r( pReq, "LSAPI: jail() failure.", NULL ); return -1; } return ret; } static int lsapi_initLVE(void) { const char * pEnv; if ( (pEnv = getenv( "LSAPI_LVE_ENABLE" ))!= NULL ) { s_enable_lve = atol( pEnv ); pEnv = NULL; } else if ( (pEnv = getenv( "LVE_ENABLE" ))!= NULL ) { s_enable_lve = atol( pEnv ); pEnv = NULL; } if ( s_enable_lve && !s_uid ) { lsapi_load_lve_lib(); if ( s_enable_lve ) { return init_lve_ex(); } } return 0; } #endif static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * pChroot) { int rv; struct passwd * pw; pw = getpwuid( uid ); #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if ( s_lve ) { if( lsapi_enterLVE( pReq, uid ) == -1 ) return -1; if ( pw && fp_lve_jail) { rv = lsapi_jailLVE( pReq, uid, pw ); if ( rv == -1 ) return -1; if (( rv == 1 )&&(s_enable_lve == LSAPI_CAGEFS_NO_SUEXEC )) //this mode only use cageFS, does not use suEXEC { uid = s_defaultUid; gid = s_defaultGid; pw = getpwuid( uid ); } } } #endif //if ( !uid || !gid ) //do not allow root //{ // return -1; //} #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) if ( s_enable_core_dump ) lsapi_enable_core_dump(); #endif rv = setgid(gid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setgid()", NULL); return -1; } if ( pw && (pw->pw_gid == gid )) { rv = initgroups( pw->pw_name, gid ); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: initgroups()", NULL); return -1; } } else { rv = setgroups(1, &gid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setgroups()", NULL); } } if ( pChroot ) { rv = chroot( pChroot ); if ( rv == -1 ) { LSAPI_perror_r(pReq, "LSAPI: chroot()", NULL); return -1; } } rv = setuid(uid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setuid()", NULL); return -1; } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if ( s_enable_core_dump ) lsapi_enable_core_dump(); #endif return 0; } static int lsapi_suexec_auth( LSAPI_Request *pReq, char * pAuth, int len, char * pUgid, int ugidLen ) { lsapi_MD5_CTX md5ctx; unsigned char achMD5[16]; if ( len < 32 ) return -1; memmove( achMD5, pAuth + 16, 16 ); memmove( pAuth + 16, s_secret, 16 ); lsapi_MD5Init( &md5ctx ); lsapi_MD5Update( &md5ctx, (unsigned char *)pAuth, 32 ); lsapi_MD5Update( &md5ctx, (unsigned char *)pUgid, 8 ); lsapi_MD5Final( (unsigned char *)pAuth + 16, &md5ctx); if ( memcmp( achMD5, pAuth + 16, 16 ) == 0 ) return 0; return 1; } static int lsapi_changeUGid( LSAPI_Request * pReq ) { int uid = s_defaultUid; int gid = s_defaultGid; const char *pStderrLog; const char *pChroot = NULL; struct LSAPI_key_value_pair * pEnv; struct LSAPI_key_value_pair * pAuth; int i; if ( s_uid ) return 0; //with special ID 0x00 //authenticate the suEXEC request; //first one should be MD5( nonce + lscgid secret ) //remember to clear the secret after verification //it should be set at the end of special env i = pReq->m_pHeader->m_cntSpecialEnv - 1; if ( i >= 0 ) { pEnv = pReq->m_pSpecialEnvList + i; if (( *pEnv->pKey == '\000' )&& ( strcmp( pEnv->pKey+1, "SUEXEC_AUTH" ) == 0 )) { --pReq->m_pHeader->m_cntSpecialEnv; pAuth = pEnv--; if (( *pEnv->pKey == '\000' )&& ( strcmp( pEnv->pKey+1, "SUEXEC_UGID" ) == 0 )) { --pReq->m_pHeader->m_cntSpecialEnv; uid = *(uint32_t *)pEnv->pValue; gid = *(((uint32_t *)pEnv->pValue) + 1 ); //lsapi_log("LSAPI: SUEXEC_UGID set UID: %d, GID: %d\n", uid, gid ); } else { lsapi_log("LSAPI: missing SUEXEC_UGID env, use default user!\n" ); pEnv = NULL; } if ( pEnv&& lsapi_suexec_auth( pReq, pAuth->pValue, pAuth->valLen, pEnv->pValue, pEnv->valLen ) == 0 ) { //read UID, GID from specialEnv } else { //authentication error lsapi_log("LSAPI: SUEXEC_AUTH authentication failed, use default user!\n" ); uid = 0; } } else { //lsapi_log("LSAPI: no SUEXEC_AUTH env, use default user!\n" ); } } if ( !uid ) { uid = s_defaultUid; gid = s_defaultGid; } //change uid if ( setUID_LVE( pReq, uid, gid, pChroot ) == -1 ) { return -1; } s_uid = uid; if ( pReq->m_fdListen != -1 ) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } pStderrLog = LSAPI_GetEnv_r( pReq, "LSAPI_STDERR_LOG"); if (pStderrLog) lsapi_reopen_stderr(pStderrLog); return 0; } static int parseContentLenFromHeader(LSAPI_Request * pReq) { const char * pContentLen = LSAPI_GetHeader_r( pReq, H_CONTENT_LENGTH ); if ( pContentLen ) pReq->m_reqBodyLen = strtoll( pContentLen, NULL, 10 ); return 0; } static int parseRequest( LSAPI_Request * pReq, int totalLen ) { int shouldFixEndian; char * pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header ); char * pEnd = pReq->m_pReqBuf + totalLen; shouldFixEndian = ( LSAPI_ENDIAN != ( pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) ); if ( shouldFixEndian ) { fixEndian( pReq ); } if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&& allocateEnvList( &pReq->m_pSpecialEnvList, &pReq->m_specialEnvListSize, pReq->m_pHeader->m_cntSpecialEnv ) == -1 ) return -1; if ( (pReq->m_envListSize < pReq->m_pHeader->m_cntEnv )&& allocateEnvList( &pReq->m_pEnvList, &pReq->m_envListSize, pReq->m_pHeader->m_cntEnv ) == -1 ) return -1; if ( parseEnv( pReq->m_pSpecialEnvList, pReq->m_pHeader->m_cntSpecialEnv, &pBegin, pEnd ) == -1 ) return -1; if ( parseEnv( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, &pBegin, pEnd ) == -1 ) return -1; if (pReq->m_pHeader->m_scriptFileOff < 0 || pReq->m_pHeader->m_scriptFileOff >= totalLen || pReq->m_pHeader->m_scriptNameOff < 0 || pReq->m_pHeader->m_scriptNameOff >= totalLen || pReq->m_pHeader->m_queryStringOff < 0 || pReq->m_pHeader->m_queryStringOff >= totalLen || pReq->m_pHeader->m_requestMethodOff < 0 || pReq->m_pHeader->m_requestMethodOff >= totalLen) { lsapi_log("Bad request header - ERROR#1\n"); return -1; } pReq->m_pScriptFile = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptFileOff; pReq->m_pScriptName = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff; pReq->m_pQueryString = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff; pReq->m_pRequestMethod = pReq->m_pReqBuf + pReq->m_pHeader->m_requestMethodOff; pBegin = pReq->m_pReqBuf + (( pBegin - pReq->m_pReqBuf + 7 ) & (~0x7)); pReq->m_pHeaderIndex = ( struct lsapi_http_header_index * )pBegin; pBegin += sizeof( struct lsapi_http_header_index ); pReq->m_pUnknownHeader = (struct lsapi_header_offset *)pBegin; pBegin += sizeof( struct lsapi_header_offset) * pReq->m_pHeader->m_cntUnknownHeaders; pReq->m_pHttpHeader = pBegin; pBegin += pReq->m_pHeader->m_httpHeaderLen; if ( pBegin != pEnd ) { lsapi_log("Request header does match total size, total: %d, " "real: %ld\n", totalLen, pBegin - pReq->m_pReqBuf ); return -1; } if ( shouldFixEndian ) { fixHeaderIndexEndian( pReq ); } if (validateHeaders(pReq) == -1) { lsapi_log("Bad request header - ERROR#2\n"); return -1; } pReq->m_reqBodyLen = pReq->m_pHeader->m_reqBodyLen; if ( pReq->m_reqBodyLen == -2 ) { parseContentLenFromHeader(pReq); } return 0; } //OPTIMIZATION static char s_accept_notify = 0; static char s_schedule_notify = 0; static char s_notify_scheduled = 0; static char s_notified_pid = 0; static struct lsapi_packet_header s_ack = {'L', 'S', LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; static struct lsapi_packet_header s_conn_close_pkt = {'L', 'S', LSAPI_CONN_CLOSE, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; static inline int send_notification_pkt( int fd, struct lsapi_packet_header *pkt ) { if ( write( fd, pkt, LSAPI_PACKET_HEADER_LEN ) < LSAPI_PACKET_HEADER_LEN ) return -1; return 0; } static inline int send_req_received_notification( int fd ) { return send_notification_pkt(fd, &s_ack); } static inline int send_conn_close_notification( int fd ) { return send_notification_pkt(fd, &s_conn_close_pkt); } //static void lsapi_sigalarm( int sig ) //{ // if ( s_notify_scheduled ) // { // s_notify_scheduled = 0; // if ( g_req.m_fd != -1 ) // write_req_received_notification( g_req.m_fd ); // } //} static inline int lsapi_schedule_notify(void) { if ( !s_notify_scheduled ) { alarm( 2 ); s_notify_scheduled = 1; } return 0; } static inline int notify_req_received( int fd ) { if ( s_schedule_notify ) return lsapi_schedule_notify(); return send_req_received_notification( fd ); } static inline int lsapi_notify_pid( int fd ) { char achBuf[16]; lsapi_buildPacketHeader( (struct lsapi_packet_header *)achBuf, LSAPI_STDERR_STREAM, 8 + LSAPI_PACKET_HEADER_LEN ); memmove( &achBuf[8], "\0PID", 4 ); *((int *)&achBuf[12]) = getpid(); if ( write( fd, achBuf, 16 ) < 16 ) return -1; return 0; } static int readReq( LSAPI_Request * pReq ) { int len; int packetLen; if ( !pReq ) return -1; if ( pReq->m_reqBufSize < 8192 ) { if ( allocateBuf( pReq, 8192 ) == -1 ) return -1; } while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN ) { len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize ); if ( len <= 0 ) return -1; pReq->m_bufRead += len; } pReq->m_reqState = LSAPI_ST_REQ_HEADER; packetLen = verifyHeader( &pReq->m_pHeader->m_pktHeader, LSAPI_BEGIN_REQUEST ); if ( packetLen < 0 ) { lsapi_log("packetLen < 0\n"); return -1; } if ( packetLen > LSAPI_MAX_HEADER_LEN ) { lsapi_log("packetLen > %d\n", LSAPI_MAX_HEADER_LEN ); return -1; } if ( packetLen + 1024 > pReq->m_reqBufSize ) { if ( allocateBuf( pReq, packetLen + 1024 ) == -1 ) return -1; } while( packetLen > pReq->m_bufRead ) { len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, packetLen - pReq->m_bufRead ); if ( len <= 0 ) return -1; pReq->m_bufRead += len; } if ( parseRequest( pReq, packetLen ) < 0 ) { lsapi_log("ParseRequest error\n"); return -1; } pReq->m_reqState = LSAPI_ST_REQ_BODY | LSAPI_ST_RESP_HEADER; if ( !s_uid ) { if ( lsapi_changeUGid( pReq ) ) return -1; memset(s_secret, 0, sizeof(s_secret)); } pReq->m_bufProcessed = packetLen; //OPTIMIZATION if ( !s_accept_notify && !s_notified_pid ) return notify_req_received( pReq->m_fd ); else { s_notified_pid = 0; return 0; } } int LSAPI_Init(void) { if ( !g_inited ) { s_uid = geteuid(); s_secret[0] = 0; lsapi_signal(SIGPIPE, lsapi_sigpipe); lsapi_signal(SIGUSR1, lsapi_siguser1); #if defined(SIGXFSZ) && defined(SIG_IGN) signal(SIGXFSZ, SIG_IGN); #endif /* let STDOUT function as STDERR, just in case writing to STDOUT directly */ dup2( 2, 1 ); if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 ) return -1; g_inited = 1; s_ppid = getppid(); void *pthread_lib = dlopen("libpthread.so", RTLD_LAZY); if (pthread_lib) pthread_atfork_func = dlsym(pthread_lib, "pthread_atfork"); } return 0; } void LSAPI_Stop(void) { g_running = 0; } int LSAPI_IsRunning(void) { return g_running; } void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf cb) { s_proc_group_timer_cb = cb; } int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ) { int newfd; if ( !pReq ) return -1; memset( pReq, 0, sizeof( LSAPI_Request ) ); if ( allocateIovec( pReq, 16 ) == -1 ) return -1; pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE ); if ( !pReq->m_pRespBuf ) return -1; pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5]; if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 ) return -1; if ( fd == STDIN_FILENO ) { fd = dup( fd ); newfd = open( "/dev/null", O_RDWR ); dup2( newfd, STDIN_FILENO ); } if ( isPipe( fd ) ) { pReq->m_fdListen = -1; pReq->m_fd = fd; } else { pReq->m_fdListen = fd; pReq->m_fd = -1; lsapi_set_nblock( fd, 1 ); } return 0; } int LSAPI_Is_Listen( void ) { return LSAPI_Is_Listen_r( &g_req ); } int LSAPI_Is_Listen_r( LSAPI_Request * pReq) { return pReq->m_fdListen != -1; } int LSAPI_Accept_r( LSAPI_Request * pReq ) { char achPeer[128]; socklen_t len; int nodelay = 1; if ( !pReq ) return -1; if ( LSAPI_Finish_r( pReq ) == -1 ) return -1; lsapi_set_nblock( pReq->m_fdListen , 0 ); while( g_running ) { if ( pReq->m_fd == -1 ) { if ( pReq->m_fdListen != -1) { len = sizeof( achPeer ); pReq->m_fd = accept( pReq->m_fdListen, (struct sockaddr *)&achPeer, &len ); if ( pReq->m_fd == -1 ) { if (( errno == EINTR )||( errno == EAGAIN)) continue; else return -1; } else { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd , 0 ); if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); } //init_conn_key( pReq->m_fd ); //OPTIMIZATION if ( s_accept_notify ) if ( notify_req_received( pReq->m_fd ) == -1 ) return -1; } } else return -1; } if ( !readReq( pReq ) ) break; //abort(); lsapi_close_connection(pReq); LSAPI_Reset_r( pReq ); } return 0; } static struct lsapi_packet_header finish_close[2] = { {'L', 'S', LSAPI_RESP_END, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }, {'L', 'S', LSAPI_CONN_CLOSE, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} } }; int LSAPI_Finish_r( LSAPI_Request * pReq ) { /* finish req body */ if ( !pReq ) return -1; if (pReq->m_reqState) { if ( pReq->m_fd != -1 ) { if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } pReq->m_pIovecCur->iov_base = (void *)finish_close; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; LSAPI_Flush_r( pReq ); } LSAPI_Reset_r( pReq ); } return 0; } int LSAPI_End_Response_r(LSAPI_Request * pReq) { if (!pReq) return -1; if (pReq->m_reqState & LSAPI_ST_BACKGROUND) return 0; if (pReq->m_reqState) { if ( pReq->m_fd != -1 ) { if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { if ( pReq->m_pRespHeaderBufPos <= pReq->m_pRespHeaderBuf ) return 0; LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } pReq->m_pIovecCur->iov_base = (void *)finish_close; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN << 1; pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN << 1; ++pReq->m_pIovecCur; LSAPI_Flush_r( pReq ); lsapi_close_connection(pReq); } pReq->m_reqState |= LSAPI_ST_BACKGROUND; } return 0; } void LSAPI_Reset_r( LSAPI_Request * pReq ) { pReq->m_pRespBufPos = pReq->m_pRespBuf; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; pReq->m_pRespHeaderBufPos = pReq->m_pRespHeaderBuf; memset( &pReq->m_pHeaderIndex, 0, (char *)(pReq->m_respHeaderLen) - (char *)&pReq->m_pHeaderIndex ); } int LSAPI_Release_r( LSAPI_Request * pReq ) { if ( pReq->m_pReqBuf ) free( pReq->m_pReqBuf ); if ( pReq->m_pSpecialEnvList ) free( pReq->m_pSpecialEnvList ); if ( pReq->m_pEnvList ) free( pReq->m_pEnvList ); if ( pReq->m_pRespHeaderBuf ) free( pReq->m_pRespHeaderBuf ); return 0; } char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ) { int off; if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) ) return NULL; off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ]; if ( !off ) return NULL; if ( *(pReq->m_pHttpHeader + off + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) ) { *( pReq->m_pHttpHeader + off + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0; } return pReq->m_pHttpHeader + off; } static int readBodyToReqBuf( LSAPI_Request * pReq ) { off_t bodyLeft; ssize_t len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len > 0 ) return len; pReq->m_bufRead = pReq->m_bufProcessed = pReq->m_pHeader->m_pktHeader.m_packetLen.m_iLen; bodyLeft = pReq->m_reqBodyLen - pReq->m_reqBodyRead; len = pReq->m_reqBufSize - pReq->m_bufRead; if ( len < 0 ) return -1; if ( len > bodyLeft ) len = bodyLeft; len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, len ); if ( len > 0 ) pReq->m_bufRead += len; return len; } int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ) { if (!pReq || (pReq->m_fd ==-1) ) return EOF; if ( pReq->m_bufProcessed >= pReq->m_bufRead ) { if ( readBodyToReqBuf( pReq ) <= 0 ) return EOF; } ++pReq->m_reqBodyRead; return (unsigned char)*(pReq->m_pReqBuf + pReq->m_bufProcessed++); } int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF ) { ssize_t len; ssize_t left; char * pBufEnd = pBuf + bufLen - 1; char * pBufCur = pBuf; char * pCur; char * p; if (!pReq || pReq->m_fd == -1 || !pBuf || !getLF) return -1; *getLF = 0; while( (left = pBufEnd - pBufCur ) > 0 ) { len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len <= 0 ) { if ( (len = readBodyToReqBuf( pReq )) <= 0 ) { *getLF = 1; break; } } if ( len > left ) len = left; pCur = pReq->m_pReqBuf + pReq->m_bufProcessed; p = memchr( pCur, '\n', len ); if ( p ) len = p - pCur + 1; memmove( pBufCur, pCur, len ); pBufCur += len; pReq->m_bufProcessed += len; pReq->m_reqBodyRead += len; if ( p ) { *getLF = 1; break; } } *pBufCur = 0; return pBufCur - pBuf; } ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen ) { ssize_t len; off_t total; /* char *pOldBuf = pBuf; */ if (!pReq || pReq->m_fd == -1 || !pBuf || (ssize_t)bufLen < 0) return -1; total = pReq->m_reqBodyLen - pReq->m_reqBodyRead; if ( total <= 0 ) return 0; if ( total < (ssize_t)bufLen ) bufLen = total; total = 0; len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len > 0 ) { if ( len > (ssize_t)bufLen ) len = bufLen; memmove( pBuf, pReq->m_pReqBuf + pReq->m_bufProcessed, len ); pReq->m_bufProcessed += len; total += len; pBuf += len; bufLen -= len; } while( bufLen > 0 ) { len = lsapi_read( pReq->m_fd, pBuf, bufLen ); if ( len > 0 ) { total += len; pBuf += len; bufLen -= len; } else if ( len <= 0 ) { if ( !total) return -1; break; } } pReq->m_reqBodyRead += total; return total; } ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len ) { struct lsapi_packet_header * pHeader; const char * pEnd; const char * p; ssize_t bufLen; ssize_t toWrite; ssize_t packetLen; int skip = 0; if (!pReq || !pBuf) return -1; if (pReq->m_reqState & LSAPI_ST_BACKGROUND) return len; if (pReq->m_fd == -1) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); /* if ( *pBuf == '\r' ) { ++skip; } if ( *pBuf == '\n' ) { ++skip; } */ } pReq->m_reqState |= LSAPI_ST_RESP_BODY; if ( ((ssize_t)len - skip) < pReq->m_pRespBufEnd - pReq->m_pRespBufPos ) { memmove( pReq->m_pRespBufPos, pBuf + skip, len - skip ); pReq->m_pRespBufPos += len - skip; return len; } pHeader = pReq->m_respPktHeader; p = pBuf + skip; pEnd = pBuf + len; bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; while( ( toWrite = pEnd - p ) > 0 ) { packetLen = toWrite + bufLen; if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { packetLen = LSAPI_MAX_DATA_PACKET_LEN; toWrite = packetLen - bufLen; } lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, packetLen + LSAPI_PACKET_HEADER_LEN ); pReq->m_totalLen += packetLen + LSAPI_PACKET_HEADER_LEN; pReq->m_pIovecCur->iov_base = (void *)pHeader; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; ++pHeader; if ( bufLen > 0 ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; pReq->m_pIovecCur->iov_len = bufLen; pReq->m_pRespBufPos = pReq->m_pRespBuf; ++pReq->m_pIovecCur; bufLen = 0; } pReq->m_pIovecCur->iov_base = (void *)p; pReq->m_pIovecCur->iov_len = toWrite; ++pReq->m_pIovecCur; p += toWrite; if ( pHeader >= pReq->m_respPktHeaderEnd - 1) { if ( LSAPI_Flush_r( pReq ) == -1 ) return -1; pHeader = pReq->m_respPktHeader; } } if ( pHeader != pReq->m_respPktHeader ) if ( LSAPI_Flush_r( pReq ) == -1 ) return -1; return p - pBuf; } #if defined(__FreeBSD__ ) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t written; ret = sendfile( fdIn, fdOut, *off, size, NULL, &written, 0 ); if ( written > 0 ) { ret = written; *off += ret; } return ret; } #endif #if defined(__OpenBSD__) || defined(__NetBSD__) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t written = 0; const size_t bufsiz = 16384; unsigned char in[bufsiz] = {0}; if (lseek(fdIn, *off, SEEK_SET) == -1) { return -1; } while (size > 0) { size_t tor = size > sizeof(in) ? sizeof(in) : size; ssize_t c = read(fdIn, in, tor); if (c <= 0) { goto end; } ssize_t w = write(fdOut, in, c); if (w > 0) written += w; if (w != c) { goto end; } size -= c; } end: *off += written; return 0; } #endif #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t len = size; ret = sendfile( fdIn, fdOut, *off, &len, NULL, 0 ); if (( ret == 0 )&&( len > 0 )) { ret = len; *off += len; } return ret; } #endif #if defined(sun) || defined(__sun) #include ssize_t gsendfile( int fdOut, int fdIn, off_t *off, size_t size ) { int n = 0 ; sendfilevec_t vec[1]; vec[n].sfv_fd = fdIn; vec[n].sfv_flag = 0; vec[n].sfv_off = *off; vec[n].sfv_len = size; ++n; size_t written; ssize_t ret = sendfilev( fdOut, vec, n, &written ); if (( !ret )||( errno == EAGAIN )) ret = written; if ( ret > 0 ) *off += ret; return ret; } #endif #if defined(linux) || defined(__linux) || defined(__linux__) || \ defined(__gnu_linux__) #include #define gsendfile sendfile #endif #if defined(HPUX) ssize_t gsendfile( int fdOut, int fdIn, off_t * off, size_t size ) { return sendfile( fdOut, fdIn, off, size, NULL, 0 ); } #endif ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size ) { struct lsapi_packet_header * pHeader = pReq->m_respPktHeader; if ( !pReq || (pReq->m_fd == -1) || fdIn == -1 ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } pReq->m_reqState |= LSAPI_ST_RESP_BODY; LSAPI_Flush_r(pReq); lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, size + LSAPI_PACKET_HEADER_LEN ); if (write(pReq->m_fd, (const char *) pHeader, LSAPI_PACKET_HEADER_LEN ) != LSAPI_PACKET_HEADER_LEN) return -1; return gsendfile( pReq->m_fd, fdIn, off, size ); } void Flush_RespBuf_r( LSAPI_Request * pReq ) { struct lsapi_packet_header * pHeader = pReq->m_respPktHeader; int bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; pReq->m_reqState |= LSAPI_ST_RESP_BODY; lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, bufLen + LSAPI_PACKET_HEADER_LEN ); pReq->m_totalLen += bufLen + LSAPI_PACKET_HEADER_LEN; pReq->m_pIovecCur->iov_base = (void *)pHeader; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; ++pHeader; if ( bufLen > 0 ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; pReq->m_pIovecCur->iov_len = bufLen; pReq->m_pRespBufPos = pReq->m_pRespBuf; ++pReq->m_pIovecCur; bufLen = 0; } } int LSAPI_Flush_r( LSAPI_Request * pReq ) { int ret = 0; int n; if ( !pReq ) return -1; n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf )) return 0; if ( pReq->m_fd == -1 ) { pReq->m_pRespBufPos = pReq->m_pRespBuf; pReq->m_totalLen = 0; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; return -1; } if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; if ( n > 0 ) { ret = lsapi_writev( pReq->m_fd, &pReq->m_pIovecToWrite, n, pReq->m_totalLen ); if ( ret < pReq->m_totalLen ) { lsapi_close_connection(pReq); ret = -1; } pReq->m_totalLen = 0; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; } return ret; } ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len ) { struct lsapi_packet_header header; const char * pEnd; const char * p; ssize_t packetLen; ssize_t totalLen; int ret; struct iovec iov[2]; struct iovec *pIov; if ( !pReq ) return -1; if (s_stderr_log_path || pReq->m_fd == -1 || pReq->m_fd == pReq->m_fdListen) return write( 2, pBuf, len ); if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { LSAPI_Flush_r( pReq ); } p = pBuf; pEnd = pBuf + len; while( ( packetLen = pEnd - p ) > 0 ) { if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { packetLen = LSAPI_MAX_DATA_PACKET_LEN; } lsapi_buildPacketHeader( &header, LSAPI_STDERR_STREAM, packetLen + LSAPI_PACKET_HEADER_LEN ); totalLen = packetLen + LSAPI_PACKET_HEADER_LEN; iov[0].iov_base = (void *)&header; iov[0].iov_len = LSAPI_PACKET_HEADER_LEN; iov[1].iov_base = (void *)p; iov[1].iov_len = packetLen; p += packetLen; pIov = iov; ret = lsapi_writev( pReq->m_fd, &pIov, 2, totalLen ); if ( ret < totalLen ) { lsapi_close_connection(pReq); ret = -1; } } return p - pBuf; } static char * GetHeaderVar( LSAPI_Request * pReq, const char * name ) { int i; char * pValue; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { if ( strcmp( name, CGI_HEADERS[i] ) == 0 ) { pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; if ( *(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) != '\0') { *(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) = '\0'; } return pValue; } } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { const char *p; char *pKey; char *pKeyEnd; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; pKeyEnd = pKey + keyLen; p = &name[5]; while(( pKey < pKeyEnd )&&( *p )) { char ch = toupper( *pKey ); if ((ch != *p )||(( *p == '_' )&&( ch != '-'))) break; ++p; ++pKey; } if (( pKey == pKeyEnd )&& (!*p )) { pValue = pReq->m_pHttpHeader + pCur->valueOff; if ( *(pValue + pCur->valueLen) != '\0') { *(pValue + pCur->valueLen) = '\0'; } return pValue; } ++pCur; } } return NULL; } char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ) { struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList; struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv; if ( !pReq || !name ) return NULL; if ( strncmp( name, "HTTP_", 5 ) == 0 ) { return GetHeaderVar( pReq, name ); } while( pBegin < pEnd ) { if ( strcmp( name, pBegin->pKey ) == 0 ) return pBegin->pValue; ++pBegin; } return NULL; } struct _headerInfo { const char * _name; int _nameLen; const char * _value; int _valueLen; }; int compareValueLocation(const void * v1, const void *v2 ) { return ((const struct _headerInfo *)v1)->_value - ((const struct _headerInfo *)v2)->_value; } int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { int i; int len = 0; char * pValue; int ret; int count = 0; struct _headerInfo headers[512]; if ( !pReq || !fn ) return -1; if ( !pReq->m_pHeaderIndex ) return 0; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { len = pReq->m_pHeaderIndex->m_headerLen[i]; pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; *(pValue + len ) = 0; headers[count]._name = HTTP_HEADERS[i]; headers[count]._nameLen = HTTP_HEADER_LEN[i]; headers[count]._value = pValue; headers[count]._valueLen = len; ++count; //ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i], // pValue, len, arg ); //if ( ret <= 0 ) // return ret; } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { char *pKey; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; *(pKey + keyLen ) = 0; pValue = pReq->m_pHttpHeader + pCur->valueOff; *(pValue + pCur->valueLen ) = 0; headers[count]._name = pKey; headers[count]._nameLen = keyLen; headers[count]._value = pValue; headers[count]._valueLen = pCur->valueLen; ++count; if ( count == 512 ) break; //ret = (*fn)( pKey, keyLen, // pValue, pCur->valueLen, arg ); //if ( ret <= 0 ) // return ret; ++pCur; } } qsort( headers, count, sizeof( struct _headerInfo ), compareValueLocation ); for( i = 0; i < count; ++i ) { ret = (*fn)( headers[i]._name, headers[i]._nameLen, headers[i]._value, headers[i]._valueLen, arg ); if ( ret <= 0 ) return ret; } return count; } int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { int i; int len = 0; char * pValue; int ret; int count = 0; if ( !pReq || !fn ) return -1; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { len = pReq->m_pHeaderIndex->m_headerLen[i]; pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; *(pValue + len ) = 0; ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i], pValue, len, arg ); ++count; if ( ret <= 0 ) return ret; } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { char achHeaderName[256]; char *p; char *pKey; char *pKeyEnd ; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; if ( keyLen > 250 ) keyLen = 250; pKeyEnd = pKey + keyLen; memcpy( achHeaderName, "HTTP_", 5 ); p = &achHeaderName[5]; while( pKey < pKeyEnd ) { char ch = *pKey++; if ( ch == '-' ) *p++ = '_'; else *p++ = toupper( ch ); } *p = 0; keyLen += 5; pValue = pReq->m_pHttpHeader + pCur->valueOff; *(pValue + pCur->valueLen ) = 0; ret = (*fn)( achHeaderName, keyLen, pValue, pCur->valueLen, arg ); if ( ret <= 0 ) return ret; ++pCur; } } return count + pReq->m_pHeader->m_cntUnknownHeaders; } static int EnvForeach( struct LSAPI_key_value_pair * pEnv, int n, LSAPI_CB_EnvHandler fn, void * arg ) { struct LSAPI_key_value_pair * pEnd = pEnv + n; int ret; if ( !pEnv || !fn ) return -1; while( pEnv < pEnd ) { ret = (*fn)( pEnv->pKey, pEnv->keyLen, pEnv->pValue, pEnv->valLen, arg ); if ( ret <= 0 ) return ret; ++pEnv; } return n; } int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { if ( !pReq || !fn ) return -1; if ( pReq->m_pHeader->m_cntEnv > 0 ) { return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, fn, arg ); } return 0; } int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { if ( !pReq || !fn ) return -1; if ( pReq->m_pHeader->m_cntSpecialEnv > 0 ) { return EnvForeach( pReq->m_pSpecialEnvList, pReq->m_pHeader->m_cntSpecialEnv, fn, arg ); } return 0; } int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ) { if ( !pReq || !pReq->m_pIovec ) return -1; if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) ) return 0; pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER; if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf; pReq->m_pIovecCur->iov_len = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf; pReq->m_totalLen += pReq->m_pIovecCur->iov_len; ++pReq->m_pIovecCur; } pReq->m_pIovec->iov_len = sizeof( struct lsapi_resp_header) + pReq->m_respHeader.m_respInfo.m_cntHeaders * sizeof( short ); pReq->m_totalLen += pReq->m_pIovec->iov_len; lsapi_buildPacketHeader( &pReq->m_respHeader.m_pktHeader, LSAPI_RESP_HEADER, pReq->m_totalLen ); pReq->m_pIovec->iov_base = (void *)&pReq->m_respHeader; pReq->m_pIovecToWrite = pReq->m_pIovec; return 0; } int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName, const char * pHeaderValue ) { int nameLen, valLen, len; if ( !pReq || !pHeaderName || !pHeaderValue ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) return -1; if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) return -1; nameLen = strlen( pHeaderName ); valLen = strlen( pHeaderValue ); if ( nameLen == 0 ) return -1; while( nameLen > 0 ) { char ch = *(pHeaderName + nameLen - 1 ); if (( ch == '\n' )||( ch == '\r' )) --nameLen; else break; } if ( nameLen <= 0 ) return 0; while( valLen > 0 ) { char ch = *(pHeaderValue + valLen - 1 ); if (( ch == '\n' )||( ch == '\r' )) --valLen; else break; } len = nameLen + valLen + 1; if ( len > LSAPI_RESP_HTTP_HEADER_MAX ) return -1; if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) { int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf; newlen -= newlen % 4096; if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) return -1; } memmove( pReq->m_pRespHeaderBufPos, pHeaderName, nameLen ); pReq->m_pRespHeaderBufPos += nameLen; *pReq->m_pRespHeaderBufPos++ = ':'; memmove( pReq->m_pRespHeaderBufPos, pHeaderValue, valLen ); pReq->m_pRespHeaderBufPos += valLen; *pReq->m_pRespHeaderBufPos++ = 0; ++len; /* add one byte padding for \0 */ pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len; ++pReq->m_respHeader.m_respInfo.m_cntHeaders; return 0; } int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len ) { if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) return -1; if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) return -1; while( len > 0 ) { char ch = *(pBuf + len - 1 ); if (( ch == '\n' )||( ch == '\r' )) --len; else break; } if ( len <= 0 ) return 0; if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) { int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf; newlen -= newlen % 4096; if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) return -1; } memmove( pReq->m_pRespHeaderBufPos, pBuf, len ); pReq->m_pRespHeaderBufPos += len; *pReq->m_pRespHeaderBufPos++ = 0; ++len; /* add one byte padding for \0 */ pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len; ++pReq->m_respHeader.m_respInfo.m_cntHeaders; return 0; } int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog ) { int ret; int fd; int flag = 1; int addr_len; switch( pServerAddr->sa_family ) { case AF_INET: addr_len = 16; break; case AF_INET6: addr_len = sizeof( struct sockaddr_in6 ); break; case AF_UNIX: addr_len = sizeof( struct sockaddr_un ); unlink( ((struct sockaddr_un *)pServerAddr)->sun_path ); break; default: return -1; } fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 ); if ( fd == -1 ) return -1; fcntl( fd, F_SETFD, FD_CLOEXEC ); if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char *)( &flag ), sizeof(flag)) == 0) { ret = bind( fd, pServerAddr, addr_len ); if ( !ret ) { ret = listen( fd, backlog ); if ( !ret ) return fd; } } ret = errno; close(fd); errno = ret; return -1; } int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr ) { char achAddr[256]; char * p = achAddr; char * pEnd; struct addrinfo *res, hints; int doAddrInfo = 0; int port; if ( !pBind ) return -1; while( isspace( *pBind ) ) ++pBind; strncpy(achAddr, pBind, 255); achAddr[255] = 0; switch( *p ) { case '/': pAddr->sa_family = AF_UNIX; strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p, sizeof(((struct sockaddr_un *)pAddr)->sun_path) ); return 0; case '[': pAddr->sa_family = AF_INET6; ++p; pEnd = strchr( p, ']' ); if ( !pEnd ) return -1; *pEnd++ = 0; if ( *p == '*' ) { strcpy( achAddr, "::" ); p = achAddr; } doAddrInfo = 1; break; default: pAddr->sa_family = AF_INET; pEnd = strchr( p, ':' ); if ( !pEnd ) return -1; *pEnd++ = 0; doAddrInfo = 0; if ( *p == '*' ) { ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY); } else if (!strcasecmp( p, "localhost" ) ) ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK ); else { #ifdef HAVE_INET_PTON if (!inet_pton(AF_INET, p, &((struct sockaddr_in *)pAddr)->sin_addr)) #else ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p ); if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST) #endif { doAddrInfo = 1; } } break; } if ( *pEnd == ':' ) ++pEnd; port = atoi( pEnd ); if (( port <= 0 )||( port > 65535 )) return -1; if ( doAddrInfo ) { memset(&hints, 0, sizeof(hints)); hints.ai_family = pAddr->sa_family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if ( getaddrinfo(p, NULL, &hints, &res) ) { return -1; } memcpy(pAddr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); } if ( pAddr->sa_family == AF_INET ) ((struct sockaddr_in *)pAddr)->sin_port = htons( port ); else ((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port ); return 0; } int LSAPI_CreateListenSock( const char * pBind, int backlog ) { char serverAddr[128]; int ret; int fd = -1; ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr ); if ( !ret ) { fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog ); } return fd; } static fn_select_t g_fnSelect = select; typedef struct _lsapi_prefork_server { int m_fd; int m_iMaxChildren; int m_iExtraChildren; int m_iCurChildren; int m_iMaxIdleChildren; int m_iServerMaxIdle; int m_iChildrenMaxIdleTime; int m_iMaxReqProcessTime; int m_iAvoidFork; lsapi_child_status * m_pChildrenStatus; lsapi_child_status * m_pChildrenStatusCur; lsapi_child_status * m_pChildrenStatusEnd; }lsapi_prefork_server; static lsapi_prefork_server * g_prefork_server = NULL; int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ) { if ( g_prefork_server ) return 0; if ( max_children <= 1 ) return -1; if ( max_children >= 10000) max_children = 10000; if (s_max_busy_workers == 0) s_max_busy_workers = max_children / 2 + 1; g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) ); if ( !g_prefork_server ) return -1; memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) ); if ( fp != NULL ) g_fnSelect = fp; s_ppid = getppid(); s_pid = getpid(); setpgid( s_pid, s_pid ); #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) s_total_pages = sysconf(_SC_PHYS_PAGES); #endif g_prefork_server->m_iAvoidFork = avoidFork; g_prefork_server->m_iMaxChildren = max_children; g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ; g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3); if ( g_prefork_server->m_iMaxIdleChildren == 0 ) g_prefork_server->m_iMaxIdleChildren = 1; g_prefork_server->m_iChildrenMaxIdleTime = 300; g_prefork_server->m_iMaxReqProcessTime = 3600; setsid(); return 0; } void LSAPI_Set_Server_fd( int fd ) { if( g_prefork_server ) g_prefork_server->m_fd = fd; } static int lsapi_accept( int fdListen ) { int fd; int nodelay = 1; socklen_t len; char achPeer[128]; len = sizeof( achPeer ); fd = accept( fdListen, (struct sockaddr *)&achPeer, &len ); if ( fd != -1 ) { if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); } //OPTIMIZATION //if ( s_accept_notify ) // notify_req_received( fd ); } return fd; } static unsigned int s_max_reqs = UINT_MAX; static int s_max_idle_secs = 300; static int s_stop; static void lsapi_cleanup(int signal) { s_stop = signal; } static lsapi_child_status * find_child_status( int pid ) { lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd; while( pStatus < pEnd ) { if ( pStatus->m_pid == pid ) { if (pid == 0) { memset(pStatus, 0, sizeof( *pStatus ) ); pStatus->m_pid = -1; } if ( pStatus + 1 > g_prefork_server->m_pChildrenStatusCur ) g_prefork_server->m_pChildrenStatusCur = pStatus + 1; return pStatus; } ++pStatus; } return NULL; } void LSAPI_reset_server_state( void ) { /* Reset child status */ g_prefork_server->m_iCurChildren = 0; lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd; while( pStatus < pEnd ) { pStatus->m_pid = 0; ++pStatus; } if (s_busy_workers) __atomic_store_n(s_busy_workers, 0, __ATOMIC_SEQ_CST); if (s_accepting_workers) __atomic_store_n(s_accepting_workers, 0, __ATOMIC_SEQ_CST); } static void lsapi_sigchild( int signal ) { int status, pid; char expect_connected = LSAPI_STATE_CONNECTED; char expect_accepting = LSAPI_STATE_ACCEPTING; lsapi_child_status * child_status; if (g_prefork_server == NULL) return; while( 1 ) { pid = waitpid( -1, &status, WNOHANG|WUNTRACED ); if ( pid <= 0 ) { break; } if ( WIFSIGNALED( status )) { int sig_num = WTERMSIG( status ); #ifdef WCOREDUMP const char * dump = WCOREDUMP( status ) ? "yes" : "no"; #else const char * dump = "unknown"; #endif lsapi_log("Child process with pid: %d was killed by signal: " "%d, core dumped: %s\n", pid, sig_num, dump ); } if ( pid == s_pid_dump_debug_info ) { pid = 0; continue; } if ( pid == s_ignore_pid ) { pid = 0; s_ignore_pid = -1; continue; } child_status = find_child_status( pid ); if ( child_status ) { if (__atomic_compare_exchange_n(&child_status->m_state, &expect_connected, LSAPI_STATE_IDLE, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { if (s_busy_workers) __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST); } else if (__atomic_compare_exchange_n(&child_status->m_state, &expect_accepting, LSAPI_STATE_IDLE, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { if (s_accepting_workers) __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST); } child_status->m_pid = 0; --g_prefork_server->m_iCurChildren; } } while(( g_prefork_server->m_pChildrenStatusCur > g_prefork_server->m_pChildrenStatus ) &&( g_prefork_server->m_pChildrenStatusCur[-1].m_pid == 0 )) --g_prefork_server->m_pChildrenStatusCur; } static int lsapi_init_children_status(void) { char * pBuf; int size = 4096; int max_children; if (g_prefork_server->m_pChildrenStatus) return 0; max_children = g_prefork_server->m_iMaxChildren + g_prefork_server->m_iExtraChildren; size = max_children * sizeof( lsapi_child_status ) * 2 + 3 * sizeof(int); size = (size + 4095) / 4096 * 4096; pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0 ); if ( pBuf == MAP_FAILED ) { perror( "Anonymous mmap() failed" ); return -1; } memset( pBuf, 0, size ); g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf; g_prefork_server->m_pChildrenStatusCur = (lsapi_child_status *)pBuf; g_prefork_server->m_pChildrenStatusEnd = (lsapi_child_status *)pBuf + max_children; s_busy_workers = (int *)g_prefork_server->m_pChildrenStatusEnd; s_accepting_workers = s_busy_workers + 1; s_global_counter = s_accepting_workers + 1; s_avail_pages = (size_t *)(s_global_counter + 1); setsid(); return 0; } static void dump_debug_info( lsapi_child_status * pStatus, long tmCur ) { char achCmd[1024]; if ( s_pid_dump_debug_info ) { if ( kill( s_pid_dump_debug_info, 0 ) == 0 ) return; } lsapi_log("Possible runaway process, UID: %d, PPID: %d, PID: %d, " "reqCount: %d, process time: %ld, checkpoint time: %ld, start " "time: %ld\n", getuid(), getppid(), pStatus->m_pid, pStatus->m_iReqCounter, tmCur - pStatus->m_tmReqBegin, tmCur - pStatus->m_tmLastCheckPoint, tmCur - pStatus->m_tmStart ); s_pid_dump_debug_info = fork(); if (s_pid_dump_debug_info == 0) { snprintf( achCmd, 1024, "gdb --batch -ex \"attach %d\" -ex \"set height 0\" " "-ex \"bt\" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2", pStatus->m_pid, pStatus->m_pid ); if ( system( achCmd ) == -1 ) perror( "system()" ); exit( 0 ); } } static void lsapi_check_child_status( long tmCur ) { int idle = 0; int tobekilled; int dying = 0; int count = 0; lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusCur; while( pStatus < pEnd ) { tobekilled = 0; if ( pStatus->m_pid != 0 && pStatus->m_pid != -1) { ++count; if ( !pStatus->m_inProcess ) { if (g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren || idle > g_prefork_server->m_iMaxIdleChildren) { ++pStatus->m_iKillSent; //tobekilled = SIGUSR1; } else { if (s_max_idle_secs> 0 && tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5) { ++pStatus->m_iKillSent; //tobekilled = SIGUSR1; } } if (!pStatus->m_iKillSent) ++idle; } else { if (tmCur - pStatus->m_tmReqBegin > g_prefork_server->m_iMaxReqProcessTime) { if ((pStatus->m_iKillSent % 5) == 0 && s_dump_debug_info) dump_debug_info( pStatus, tmCur ); if ( pStatus->m_iKillSent > 5 ) { tobekilled = SIGKILL; lsapi_log("Force killing runaway process PID: %d" " with SIGKILL\n", pStatus->m_pid ); } else { tobekilled = SIGTERM; lsapi_log("Killing runaway process PID: %d with " "SIGTERM\n", pStatus->m_pid ); } } } if ( tobekilled ) { if (( kill( pStatus->m_pid, tobekilled ) == -1 ) && ( errno == ESRCH )) { pStatus->m_pid = 0; --count; } else { ++pStatus->m_iKillSent; ++dying; } } } ++pStatus; } if ( abs( g_prefork_server->m_iCurChildren - count ) > 1 ) { lsapi_log("Children tracking is wrong: Cur Children: %d," " count: %d, idle: %d, dying: %d\n", g_prefork_server->m_iCurChildren, count, idle, dying ); } } //static int lsapi_all_children_must_die(void) //{ // int maxWait; // int sec =0; // g_prefork_server->m_iMaxReqProcessTime = 10; // g_prefork_server->m_iMaxIdleChildren = -1; // maxWait = 15; // // while( g_prefork_server->m_iCurChildren && (sec < maxWait) ) // { // lsapi_check_child_status(time(NULL)); // sleep( 1 ); // sec++; // } // if ( g_prefork_server->m_iCurChildren != 0 ) // kill( -getpgrp(), SIGKILL ); // return 0; //} void set_skip_write(void) { s_skip_write = 1; } int is_enough_free_mem(void) { #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) //minimum 1GB or 10% available free memory return (*s_avail_pages > s_min_avail_pages || (*s_avail_pages * 10) / s_total_pages > 0); #endif return 1; } static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Request * pReq ) { struct sigaction act, old_term, old_quit, old_int, old_usr1, old_child; lsapi_child_status * child_status; int wait_secs = 0; int ret = 0; int pid; time_t lastTime = 0; time_t curTime = 0; fd_set readfds; struct timeval timeout; sigset_t mask; sigset_t orig_mask; lsapi_init_children_status(); act.sa_flags = 0; act.sa_handler = lsapi_sigchild; sigemptyset(&(act.sa_mask)); if( sigaction( SIGCHLD, &act, &old_child ) ) { perror( "Can't set signal handler for SIGCHILD" ); return -1; } /* Set up handler to kill children upon exit */ act.sa_flags = 0; act.sa_handler = lsapi_cleanup; sigemptyset(&(act.sa_mask)); if( sigaction( SIGTERM, &act, &old_term ) || sigaction( SIGINT, &act, &old_int ) || sigaction( SIGUSR1, &act, &old_usr1 ) || sigaction( SIGQUIT, &act, &old_quit )) { perror( "Can't set signals" ); return -1; } while( !s_stop ) { if (s_proc_group_timer_cb != NULL) { s_proc_group_timer_cb(&s_ignore_pid); } curTime = time( NULL ); if (curTime != lastTime ) { lastTime = curTime; if (lsapi_parent_dead()) break; lsapi_check_child_status(curTime ); if (pServer->m_iServerMaxIdle) { if ( pServer->m_iCurChildren <= 0 ) { ++wait_secs; if ( wait_secs > pServer->m_iServerMaxIdle ) return -1; } else wait_secs = 0; } } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) *s_avail_pages = sysconf(_SC_AVPHYS_PAGES); // lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n", // s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages); #endif FD_ZERO( &readfds ); FD_SET( pServer->m_fd, &readfds ); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout); if (ret == 1 ) { int accepting = 0; if (s_accepting_workers) accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST); if (pServer->m_iCurChildren > 0 && accepting > 0) { usleep(400); while(accepting-- > 0) sched_yield(); continue; } } else if ( ret == -1 ) { if ( errno == EINTR ) continue; /* perror( "select()" ); */ break; } else { continue; } if (pServer->m_iCurChildren >= pServer->m_iMaxChildren + pServer->m_iExtraChildren) { lsapi_log("Reached max children process limit: %d, extra: %d," " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n", pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren, s_busy_workers ? *s_busy_workers : -1 ); usleep( 100000 ); continue; } pReq->m_fd = lsapi_accept( pServer->m_fd ); if ( pReq->m_fd != -1 ) { wait_secs = 0; child_status = find_child_status( 0 ); sigemptyset( &mask ); sigaddset( &mask, SIGCHLD ); if ( sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0 ) { perror( "sigprocmask(SIG_BLOCK) to block SIGCHLD" ); } pid = fork(); if ( !pid ) { setsid(); if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK in child" ); g_prefork_server = NULL; s_ppid = getppid(); s_pid = getpid(); s_req_processed = 0; s_proc_group_timer_cb = NULL; s_worker_status = child_status; if (pthread_atfork_func) (*pthread_atfork_func)(NULL, NULL, set_skip_write); __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd, 0 ); //keep it open if busy_count is used. if (!s_keep_listener && s_busy_workers && *s_busy_workers > (pServer->m_iMaxChildren >> 1)) s_keep_listener = 1; if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem()) && pReq->m_fdListen != -1 ) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } /* don't catch our signals */ sigaction( SIGCHLD, &old_child, 0 ); sigaction( SIGTERM, &old_term, 0 ); sigaction( SIGQUIT, &old_quit, 0 ); sigaction( SIGINT, &old_int, 0 ); sigaction( SIGUSR1, &old_usr1, 0 ); //init_conn_key( pReq->m_fd ); lsapi_notify_pid( pReq->m_fd ); s_notified_pid = 1; //if ( s_accept_notify ) // return notify_req_received( pReq->m_fd ); return 0; } else if ( pid == -1 ) { lsapi_perror("fork() failed, please increase process limit", errno); if (child_status) child_status->m_pid = 0; } else { ++pServer->m_iCurChildren; if ( child_status ) { child_status->m_pid = pid; child_status->m_tmWaitBegin = curTime; child_status->m_tmStart = curTime; } } close( pReq->m_fd ); pReq->m_fd = -1; if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK" ); } else { if (( errno == EINTR )||( errno == EAGAIN)) continue; lsapi_perror("accept() failed", errno); return -1; } } sigaction( SIGUSR1, &old_usr1, 0 ); //kill( -getpgrp(), SIGUSR1 ); //lsapi_all_children_must_die(); /* Sorry, children ;-) */ return -1; } static struct sigaction old_term, old_quit, old_int, old_usr1, old_child; int LSAPI_Postfork_Child(LSAPI_Request * pReq) { int max_children = g_prefork_server->m_iMaxChildren; s_pid = getpid(); __atomic_store_n(&pReq->child_status->m_pid, s_pid, __ATOMIC_SEQ_CST); s_worker_status = pReq->child_status; setsid(); g_prefork_server = NULL; s_ppid = getppid(); s_req_processed = 0; s_proc_group_timer_cb = NULL; if (pthread_atfork_func) (*pthread_atfork_func)(NULL, NULL, set_skip_write); __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd, 0 ); //keep it open if busy_count is used. if (!s_keep_listener && s_busy_workers && *s_busy_workers > (max_children >> 1)) s_keep_listener = 1; if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem()) && pReq->m_fdListen != -1 ) { close(pReq->m_fdListen); pReq->m_fdListen = -1; } //init_conn_key( pReq->m_fd ); lsapi_notify_pid(pReq->m_fd); s_notified_pid = 1; //if ( s_accept_notify ) // return notify_req_received( pReq->m_fd ); return 0; } int LSAPI_Postfork_Parent(LSAPI_Request * pReq) { ++g_prefork_server->m_iCurChildren; if (pReq->child_status) { time_t curTime = time( NULL ); pReq->child_status->m_tmWaitBegin = curTime; pReq->child_status->m_tmStart = curTime; } close(pReq->m_fd); pReq->m_fd = -1; return 0; } int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq) { time_t lastTime = 0; time_t curTime = 0; fd_set readfds; struct timeval timeout; int wait_secs = 0; int ret = 0; lsapi_prefork_server * pServer = g_prefork_server; struct sigaction act; lsapi_init_children_status(); act.sa_flags = 0; act.sa_handler = lsapi_sigchild; sigemptyset(&(act.sa_mask)); if (sigaction(SIGCHLD, &act, &old_child)) { perror( "Can't set signal handler for SIGCHILD" ); return -1; } /* Set up handler to kill children upon exit */ act.sa_flags = 0; act.sa_handler = lsapi_cleanup; sigemptyset(&(act.sa_mask)); if (sigaction(SIGTERM, &act, &old_term) || sigaction(SIGINT, &act, &old_int ) || sigaction(SIGUSR1, &act, &old_usr1) || sigaction(SIGQUIT, &act, &old_quit)) { perror( "Can't set signals" ); return -1; } s_stop = 0; pReq->m_reqState = 0; while(!s_stop) { if (s_proc_group_timer_cb != NULL) { s_proc_group_timer_cb(&s_ignore_pid); } curTime = time(NULL); if (curTime != lastTime) { lastTime = curTime; if (lsapi_parent_dead()) break; lsapi_check_child_status(curTime); if (pServer->m_iServerMaxIdle) { if (pServer->m_iCurChildren <= 0) { ++wait_secs; if ( wait_secs > pServer->m_iServerMaxIdle ) return -1; } else wait_secs = 0; } } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) *s_avail_pages = sysconf(_SC_AVPHYS_PAGES); // lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n", // s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages); #endif FD_ZERO(&readfds); FD_SET(pServer->m_fd, &readfds); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout); if (ret == 1 ) { int accepting = 0; if (s_accepting_workers) accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST); if (pServer->m_iCurChildren > 0 && accepting > 0) { usleep( 400); while(accepting-- > 0) sched_yield(); continue; } } else if (ret == -1) { if (errno == EINTR) continue; /* perror( "select()" ); */ break; } else { continue; } if (pServer->m_iCurChildren >= pServer->m_iMaxChildren + pServer->m_iExtraChildren) { lsapi_log("Reached max children process limit: %d, extra: %d," " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n", pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren, s_busy_workers ? *s_busy_workers : -1); usleep(100000); continue; } pReq->m_fd = lsapi_accept(pServer->m_fd); if (pReq->m_fd != -1) { wait_secs = 0; pReq->child_status = find_child_status(0); ret = 0; break; } else { if ((errno == EINTR) || (errno == EAGAIN)) continue; lsapi_perror("accept() failed", errno); ret = -1; break; } } sigaction(SIGCHLD, &old_child, 0); sigaction(SIGTERM, &old_term, 0); sigaction(SIGQUIT, &old_quit, 0); sigaction(SIGINT, &old_int, 0); sigaction(SIGUSR1, &old_usr1, 0); return ret; } int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ) { int fd; int ret; int wait_secs; fd_set readfds; struct timeval timeout; if (s_skip_write) return -1; LSAPI_Finish_r( pReq ); if ( g_prefork_server ) { if ( g_prefork_server->m_fd != -1 ) if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 ) return -1; } else if (s_req_processed > 0 && s_max_busy_workers > 0 && s_busy_workers) { ret = __atomic_load_n(s_busy_workers, __ATOMIC_SEQ_CST); if (ret >= s_max_busy_workers) { send_conn_close_notification(pReq->m_fd); lsapi_close_connection(pReq); } } if ( (unsigned int)s_req_processed > s_max_reqs ) return -1; if ( s_worker_status ) { s_worker_status->m_tmWaitBegin = time( NULL ); } while( g_running ) { if ( pReq->m_fd != -1 ) { fd = pReq->m_fd; } else if ( pReq->m_fdListen != -1 ) fd = pReq->m_fdListen; else { break; } wait_secs = 0; while( 1 ) { if ( !g_running ) return -1; if (s_req_processed && s_worker_status && s_worker_status->m_iKillSent) return -1; FD_ZERO( &readfds ); FD_SET( fd, &readfds ); timeout.tv_sec = 1; timeout.tv_usec = 0; if (fd == pReq->m_fdListen) { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_ACCEPTING, __ATOMIC_SEQ_CST); if (s_accepting_workers) __atomic_fetch_add(s_accepting_workers, 1, __ATOMIC_SEQ_CST); } ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout); if (fd == pReq->m_fdListen) { if (s_accepting_workers) __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST); if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_IDLE, __ATOMIC_SEQ_CST); } if ( ret == 0 ) { if ( s_worker_status ) { s_worker_status->m_inProcess = 0; if (fd == pReq->m_fdListen) { if (s_keep_listener == 0 || !is_enough_free_mem()) return -1; if (s_keep_listener == 1) { int wait_time = 10; if (s_busy_workers) wait_time += *s_busy_workers * 10; if (s_accepting_workers) wait_time >>= (*s_accepting_workers); if (wait_secs >= wait_time) return -1; } } } ++wait_secs; if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs )) return -1; if ( lsapi_parent_dead() ) return -1; } else if ( ret == -1 ) { if ( errno == EINTR ) continue; else return -1; } else if ( ret >= 1 ) { if (s_req_processed && s_worker_status && s_worker_status->m_iKillSent) return -1; if ( fd == pReq->m_fdListen ) { pReq->m_fd = lsapi_accept( pReq->m_fdListen ); if ( pReq->m_fd != -1 ) { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST); fd = pReq->m_fd; lsapi_set_nblock( fd, 0 ); //init_conn_key( pReq->m_fd ); if (!s_keep_listener) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } if ( s_accept_notify ) if ( notify_req_received( pReq->m_fd ) == -1 ) return -1; } else { if (( errno == EINTR )||( errno == EAGAIN)) continue; lsapi_perror( "lsapi_accept() error", errno ); return -1; } } else break; } } if ( !readReq( pReq ) ) { if ( s_worker_status ) { s_worker_status->m_iKillSent = 0; s_worker_status->m_inProcess = 1; ++s_worker_status->m_iReqCounter; s_worker_status->m_tmReqBegin = s_worker_status->m_tmLastCheckPoint = time(NULL); } ++s_req_processed; return 0; } lsapi_close_connection(pReq); LSAPI_Reset_r( pReq ); } return -1; } void LSAPI_Set_Max_Reqs( int reqs ) { s_max_reqs = reqs - 1; } void LSAPI_Set_Max_Idle( int secs ) { s_max_idle_secs = secs; } void LSAPI_Set_Max_Children( int maxChildren ) { if ( g_prefork_server ) g_prefork_server->m_iMaxChildren = maxChildren; } void LSAPI_Set_Extra_Children( int extraChildren ) { if (( g_prefork_server )&&( extraChildren >= 0 )) g_prefork_server->m_iExtraChildren = extraChildren; } void LSAPI_Set_Max_Process_Time( int secs ) { if (( g_prefork_server )&&( secs > 0 )) g_prefork_server->m_iMaxReqProcessTime = secs; } void LSAPI_Set_Max_Idle_Children( int maxIdleChld ) { if (( g_prefork_server )&&( maxIdleChld > 0 )) g_prefork_server->m_iMaxIdleChildren = maxIdleChld; } void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ) { if ( g_prefork_server ) g_prefork_server->m_iServerMaxIdle = serverMaxIdle; } void LSAPI_Set_Slow_Req_Msecs( int msecs ) { s_slow_req_msecs = msecs; } int LSAPI_Get_Slow_Req_Msecs(void) { return s_slow_req_msecs; } void LSAPI_No_Check_ppid(void) { s_ppid = 0; } int LSAPI_Get_ppid(void) { return(s_ppid); } #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #include #else extern char ** environ; #endif static void unset_lsapi_envs(void) { char **env; #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) env = *_NSGetEnviron(); #else env = environ; #endif while( env != NULL && *env != NULL ) { if (!strncmp(*env, "LSAPI_", 6) || !strncmp( *env, "PHP_LSAPI_", 10 ) || (!strncmp( *env, "PHPRC=", 6 )&&(!s_uid))) { char ** del = env; do *del = del[1]; while( *del++ ); } else ++env; } } static int lsapi_initSuEXEC(void) { int i; struct passwd * pw; s_defaultUid = 0; s_defaultGid = 0; if ( s_uid == 0 ) { const char * p = getenv( "LSAPI_DEFAULT_UID" ); if ( p ) { i = atoi( p ); if ( i > 0 ) s_defaultUid = i; } p = getenv( "LSAPI_DEFAULT_GID" ); if ( p ) { i = atoi( p ); if ( i > 0 ) s_defaultGid = i; } p = getenv( "LSAPI_SECRET" ); if (( !p )||( readSecret(p) == -1 )) return -1; if ( g_prefork_server ) { if ( g_prefork_server->m_iMaxChildren < 100 ) g_prefork_server->m_iMaxChildren = 100; if ( g_prefork_server->m_iExtraChildren < 1000 ) g_prefork_server->m_iExtraChildren = 1000; } } if ( !s_defaultUid || !s_defaultGid ) { pw = getpwnam( "nobody" ); if ( pw ) { if ( !s_defaultUid ) s_defaultUid = pw->pw_uid; if ( !s_defaultGid ) s_defaultGid = pw->pw_gid; } else { if ( !s_defaultUid ) s_defaultUid = 10000; if ( !s_defaultGid ) s_defaultGid = 10000; } } return 0; } static int lsapi_check_path(const char *p, char *final, int max_len) { char resolved_path[PATH_MAX+1]; int len = 0; char *end; if (*p != '/') { if (getcwd(final, max_len) == NULL) return -1; len = strlen(final); *(final + len) = '/'; ++len; } end = memccpy(&final[len], p, '\0', PATH_MAX - len); if (!end) { errno = EINVAL; return -1; } p = final; if (realpath(p, resolved_path) == NULL && errno != ENOENT && errno != EACCES) return -1; if (strncmp(resolved_path, "/etc/", 5) == 0) { errno = EPERM; return -1; } return 0; } static int lsapi_reopen_stderr2(const char *full_path) { int newfd = open(full_path, O_WRONLY | O_CREAT | O_APPEND, 0644); if (newfd == -1) { LSAPI_perror_r(NULL, "Failed to open custom stderr log", full_path); return -1; } if (newfd != 2) { dup2(newfd, 2); close(newfd); dup2(2, 1); } if (s_stderr_log_path && full_path != s_stderr_log_path) { free(s_stderr_log_path); s_stderr_log_path = NULL; } s_stderr_log_path = strdup(full_path); return 0; } static int lsapi_reopen_stderr(const char *p) { char full_path[PATH_MAX]; if (s_uid == 0) return -1; if (lsapi_check_path(p, full_path, PATH_MAX) == -1) { LSAPI_perror_r(NULL, "Invalid custom stderr log path", p); return -1; } return lsapi_reopen_stderr2(full_path); } int LSAPI_Init_Env_Parameters( fn_select_t fp ) { const char *p; char ch; int n; int avoidFork = 0; p = getenv("LSAPI_STDERR_LOG"); if (p) { lsapi_reopen_stderr(p); } if (!s_stderr_log_path) s_stderr_is_pipe = isPipe(STDERR_FILENO); p = getenv( "PHP_LSAPI_MAX_REQUESTS" ); if ( !p ) p = getenv( "LSAPI_MAX_REQS" ); if ( p ) { n = atoi( p ); if ( n > 0 ) LSAPI_Set_Max_Reqs( n ); } p = getenv( "LSAPI_KEEP_LISTEN" ); if ( p ) { n = atoi( p ); s_keep_listener = n; } p = getenv( "LSAPI_AVOID_FORK" ); if ( p ) { avoidFork = atoi( p ); if (avoidFork) { s_keep_listener = 2; ch = *(p + strlen(p) - 1); if ( ch == 'G' || ch == 'g' ) avoidFork *= 1024 * 1024 * 1024; else if ( ch == 'M' || ch == 'm' ) avoidFork *= 1024 * 1024; if (avoidFork >= 1024 * 10240) s_min_avail_pages = avoidFork / 4096; } } p = getenv( "LSAPI_ACCEPT_NOTIFY" ); if ( p ) { s_accept_notify = atoi( p ); } p = getenv( "LSAPI_SLOW_REQ_MSECS" ); if ( p ) { n = atoi( p ); LSAPI_Set_Slow_Req_Msecs( n ); } #if defined( RLIMIT_CORE ) p = getenv( "LSAPI_ALLOW_CORE_DUMP" ); if ( !p ) { struct rlimit limit = { 0, 0 }; setrlimit( RLIMIT_CORE, &limit ); } else s_enable_core_dump = 1; #endif p = getenv( "LSAPI_MAX_IDLE" ); if ( p ) { n = atoi( p ); LSAPI_Set_Max_Idle( n ); } if ( LSAPI_Is_Listen() ) { n = 0; p = getenv( "PHP_LSAPI_CHILDREN" ); if ( !p ) p = getenv( "LSAPI_CHILDREN" ); if ( p ) n = atoi( p ); if ( n > 1 ) { LSAPI_Init_Prefork_Server( n, fp, avoidFork != 0 ); LSAPI_Set_Server_fd( g_req.m_fdListen ); } p = getenv( "LSAPI_EXTRA_CHILDREN" ); if ( p ) LSAPI_Set_Extra_Children( atoi( p ) ); p = getenv( "LSAPI_MAX_IDLE_CHILDREN" ); if ( p ) LSAPI_Set_Max_Idle_Children( atoi( p ) ); p = getenv( "LSAPI_PGRP_MAX_IDLE" ); if ( p ) { LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) ); } p = getenv( "LSAPI_MAX_PROCESS_TIME" ); if ( p ) LSAPI_Set_Max_Process_Time( atoi( p ) ); if ( getenv( "LSAPI_PPID_NO_CHECK" ) ) { LSAPI_No_Check_ppid(); } p = getenv("LSAPI_MAX_BUSY_WORKER"); if (p) { n = atoi(p); s_max_busy_workers = n; if (n >= 0) LSAPI_No_Check_ppid(); } p = getenv( "LSAPI_DUMP_DEBUG_INFO" ); if ( p ) s_dump_debug_info = atoi( p ); if ( lsapi_initSuEXEC() == -1 ) return -1; #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) lsapi_initLVE(); #endif } unset_lsapi_envs(); return 0; } int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders, const char * pBody, int bodyLen ) { LSAPI_SetRespStatus_r( pReq, code ); if ( pRespHeaders ) { while( *pRespHeaders ) { LSAPI_AppendRespHeader_r( pReq, *pRespHeaders, strlen( *pRespHeaders ) ); ++pRespHeaders; } } if ( pBody &&( bodyLen > 0 )) { LSAPI_Write_r( pReq, pBody, bodyLen ); } LSAPI_Finish_r( pReq ); return 0; } static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]); /* * Note: this code is harmless on little-endian machines. */ static void byteReverse(unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void lsapi_MD5Init(struct lsapi_MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void lsapi_MD5Update(struct lsapi_MD5Context *ctx, unsigned char const *buf, unsigned len) { register uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memmove(p, buf, len); return; } memmove(p, buf, t); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memmove(ctx->in, buf, 64); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memmove(ctx->in, buf, len); } /* * Final wrap-up - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *ctx) { unsigned int count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1]; lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memmove(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } int LSAPI_Set_Restored_Parent_Pid(int pid) { int old_ppid = s_ppid; s_restored_ppid = pid; return old_ppid; } int LSAPI_Inc_Req_Processed(int cnt) { return __atomic_add_fetch(s_global_counter, cnt, __ATOMIC_SEQ_CST); } PKu]Mr33!ruby-lsapi-5.5/ext/lsapi/lsapi.sonuȯELF>S@P,@8 @ P P !P ! h h !h !888$$ Std PtdpppQtdRtdP P !P !GNU}C5@/㤈fC H‚3@(L`qCSlP*fRn}'3qѮl>&Sɶ ܮʼnSO`[is|&߱RD/y7řkՊ eY&09=By:%/=ejOzJ6'l#mNULCB1{!\$O#W23S=apbU06aD7jp#7ĴDIΊ=\4yݾCEкQuo rSѮIo|q%h6 󝵛 ' =qX[ uw  f ) ysOQ    [- F ! k & !d  2TRT s G + g }n >7   -z kH  ".%  " "$7x v4 A  A 9 4, 2 F"`\ E"  T r `G  |F pD   K 5 ti~ P 0z! b p. 8! ] @Z\ e n  v 1 p Y ` o@   Prl yj U P| 0- q]   n pY n  5 Po `w$ }l! s U T E @u qS m7 mT @(   Г  {F @qJ p @! |I   p  !b 0g ` P@, '! l 6 0n  ` @!__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizecompareValueLocationset_skip_writesigactionsigemptyset__stack_chk_failreallocfcntlacceptsetsockoptmmapmemsetsetsidread__errno_locationclosewritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemexitlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidsignalg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamdlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectrb_tainted_str_newrb_hash_asetrb_funcallvrb_intern2rb_gc_markmunmaprb_check_typerb_obj_as_stringrb_f_sprintfs_fn_add_envrb_string_valuerb_string_value_ptrrb_eval_string_wraprb_ruby_verbose_ptrrb_define_global_construby_strdupmkstempftruncaterb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_str_new_staticrb_exec_recursiverb_default_rsrb_output_fsrb_output_rsrb_lastline_getInit_lsapichdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocrb_stdoutrb_stdinrb_hash_new__memcpy_chkrb_define_global_functionrb_define_methodrb_define_singleton_methodlibruby.so.2.7libm.so.6libc.so.6__environ_edata__bss_start_endGLIBC_2.14GLIBC_2.15GLIBC_2.4GLIBC_2.3.4GLIBC_2.2.5GLIBC_2.3/opt/alt/ruby27/lib64 1 < ii G ti Q ui ] ii i P !PTX !T` !` ! ! ! !A ! ! !# !) !. !4 !; !J !Z !j !x ! ! ! ! ! ! !( !0 !8 !@ !H !P !X ! ` !!h !p !,x !< !@ !R !^ !r ! ! ! ! ! ! ! ! ! !  ! !' !: !Q( !_0 !r8 !@ !H !P !X !` !!!!!!!!$#!8!X!`!h!p!x!!!!!2!!<!H!J!R!V!V!W!!!m!{!!! !(!0!8!@!H!P!X!`!h!p! x! ! ! ! !!!!!!!!!!!!!!!!! !(!0!8!@!H!P!X! `!"h!#p!x!$!%!&!!'!(!!)!!!!*!+!,!-!!!!!.!/ !0(!0!18!@!H!3P!4X!5`!6h!7p!8x!9!;!=!>!?!@!!A!B!C!D!E!F!!G!!I!K!L!M!N !O(!0!P8!Q@!H!SP!X!T`!Uh!Xp!Yx!Z![!\!]!^!!_!`!!a!b!c!d!e!f!g!h!i!!j!k !l(!0!8!n@!oH!pP!qX!r`!h!sp!tx!u!w!x!y!z!|!!}!~!!!!!!!!!!!! !(!0!8!@!H!P!HH1 HtH5r %s hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhq% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% DH= H H9tH Ht H=i H5b H)HHH?HHtH HtfD=% u+UH=ʻ Ht H=. d ]wff.N ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=^ D ÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH=o 1XtIɲ tH=` -HcH5`HEHf [ÉD1?H= `HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHt:HHt)HHtH{@Ht 1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDjHu48u @ uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=\HcB$HH@H,H9rZf.HH9vGH3LluHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L={ L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$){H8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L LgfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH  L$DIH Ic LEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcUL{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eHmthILM)MUI9t HItDL+t$HL[]A\A]A^A_DM@@M)(KIHt$HLHk8f.HAVLAUIATIUSHu\H߉{AD${LǃLSHu0{L[L]A\A]A^k[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIH Lc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAMt$PHLIFID$PA:I|$P}MD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHAPI\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1HL$Aߺؿu#DH'uD o߻D HZDeOAkDH}An}NcHtff.USHdH%(H$1HHu/HH$dH3%(uHĘ[]Կ@1H= tAUATA'USH 'DNuD H@AHH HHtH- t iƉlj JUDk H DcEuD蟹jf.H=j>H=F 11H\$HCX= f= DH Htxff.H HtxxHe Ht~xHE Ht~xH% Htxff.= D D Ð DAUATUHH=0=SH8dH%(H$(1mHtH H= H=<FHE1 H边H=<Ht 1H薹x H=<HHt 1HmIAąWE1H=<Ht 1H<ߌ H=<蚳HtHǺ 1菳H=<sH H=<THtHǺ 1иYH=p< H1 H蘸OH=V<HtHǺ 1oH=D<̲HtHǺ 1H1H=5<襲HtHǺ 1!H="<~HtHǺ 1òH=<WHt]H=<AHt 1H轷 _H=;Ht 1H菷Ջ Dn ` R EH=;H=2 u P% 5 H=;蓱H 1H  …t Hw HHHHD L;L ;L;C HLt@HֹL€D t%HtAHHt9HLuHfDHJHHJHuHHu1ۉH$(dH3%(H8[]A\A]fD H趲D1 sAHc讲L%w HH a裮Åt= @R u \ 5b `HH5=uHH5y=1u HH5=Fff.AVIAUEATIUHSHt4Hu!(fDHH褭HLwH]HuMtEL[1]A\A]A^ÐIcLLH#EgHGHHܺvT2HGAWAVAAUIATUHoSH1HGO@ƉWDW?t;AĉDHH|@D)A9rhAGt4LLDHL9A?vWEfAIIIH޺@HH@ HLL9uA?DLHH[]A\A]A^A_ܱIATLfUHSFH?LHz?)ƒw=t19rLHfCAD$AD$ ID$071)2HCHLHCP?o H{1HMHHCPH)KXH[]A\ff.fAWAVAUATUSHdH%(H$1Ht^ IAfMcg IoA_@LHCHuMX8u =~ uٽH$dH3 %( HĨ[]A\A]A^A_f~AAuIALJf8LS|xr@tPHf@HPXN MgA;G ZA9~uEo)HHcIHLD2Hu$G85} uAMgA9ID$,HD$HcIIDhAh(A9}A /HcIH4@HeHAIIh$A9}A HcIH4@HHAIIHl$p(ILHIILp$hMIc@o9gIcP[9SIcpG9?IcH39+IHHHHIHT$IIc@ H)IHHIHHHIHIIcHIHHHD$I9E1DL4t9dfH "H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0:| ALJt`{ { A{ 1LHcϩIHIGAo IuID%{ D-{ B(AA1IcH4IILI 9HqH=, IJDB(9xHqH=, XIJB($AD$IKAzHL$;Mbfo{ Lt$ LAoL$AT$Ml$)$踪 LL8HL$LH#LLH$ID$H$I3L$H1H D$$Dl$EDDl$H=Dz IHIDz MH=y t"LDLŃP|$臨Et$A9uHt$螤D=Ń5y $A?D5y t @AH5(L*HtHHy f)gy #AH5k 1KH@H5J*1YLH 1H菤IH5421H5Y21D%x x DD$4H=x IHtZEW7E1111H=e2H5)1耨E|$迦M2;|$藦E1H5)LuI}觧Ń1H5a)LKfD=w -w w ED$AIFH5(1覧HH)H5h0H1聧1H5(L 1H50LA#LH c2Hr 解1H5(Laff.AVAUATUSHdH%(H$1D$ HH ;1Ll$Ld$Lt$ HklRr {ul;LLD$CHv Ht@HDv Ht{1f|$=u u|H4tH舴H`q d1H$dH3 %(u}HĠ[]A\A]A^D賜 {H5 h \Hfы{LA; ff.AWAVAUATUSHD=Du dH%(H$1ExH@H-yt H}u ;>g DH-u Ht 1aHEDp EH$L|$PDcA:E1AfD Ep EDt EtHt Ht @fLH1HIc臝DHD$PHD$XA ?)ѺHH D9#11A|$MHo D9#Ht Ht @D9#f AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$L̞H$LHHD$@迚AHLDŽ$hH$腞H$LHHD$0xPH$LHHD$8S+H$`L HHD$(.H$ LHHD$H ADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%q EHq Ht H=m 1蔞IL9t<1ձL5EDu EME1VFHm LH1HHc}՚}LD$LHD$PHD$X ?)ѺH1H T`1Vm  '8Ht$(1ҿ 轘x=_5p tHq Ht @f,D9# DCHp Ht@Hp HtDc1DN 0l =o {H5b HH1p Ht*Hap HB(@HAp Ht@Ho H@˖8B-DAD9M=bk 譟=Fk Ho HtDH`o Ht A9HAo HtD҉T$$DE ~:E~5WT$$A˙A輙AuDE UM D9vHn AHtDH5Z&1ƞD$藕0 H=? gT$fD}蠩C1mH|$IH|$HT$Ht$1萔61E Mt AMgMg{E1cCHt$1ҿ;H=d(Gf;)>fDD$$菔0d T$$WH=ST$WT$fDD#AfD^m RDh EBH+m H29h {H5u_ ДH{wH=&f̓H=='0讖MAH… H{HLh H=:Ht$1ҿ贒Hk bl L=bl Hl H%l 'l Hk HtH\X 11L='l AGHk Ht{1蝦D-~g EuHk Ht!E9~Zg Xk ;t Ht$@1ҿL$ Ht$01ҿHt$H1ҿHt$81ҿ֒Ht$(1ҿ ŒkHLSH$&$ޒL$踒Yj j H=/"J%˚,H=$"QHj Ht*fC1CD$CCT$HC(HC tj fD=nj lj ff.@H%f f.ffDn Hff.HV HH+HHODH1f1fATIHUSHcxHcLHjH=n HH[]A\ff.HH5ui dH%(HD$1Hm H$Ht-H=m HHD$dH3%(u&H@H= &跘HH i ffDHSHH=QU 謏HfHH=1U 茏Hc5l ;5d H=l |6Hl Hl l HfD蛎f?IH=T HH+9M1~+HHcHc5il H5Vl 聐~Sl Hfff.@HH=QT |tHHHDHff.UHSH H6Hm t]uaHHHtT؃tJ tEHH؉уu5HM u@HHpH}HH[]HD@HuHߎHMH tHPHpfSHCH[ff.SHSHH[ÐHH=!S LHmb HHH=S \HMb HHH=R 輑tH#b HHUSHH=R :H=ej HtKHPj HLj Jj 腍9Gj t H5e 8j Ht[11ҿ}1H$j ?H-Q H;HHu艔HuH;HjH[a HH[]fH="HHme SHH\$Ht$HH-1HH[ff.fAWAVAUAATIUSHHJfDmH{HfKHu{Ht -gN OkHU{Hu-JN 2HHAnonymous mmap() failedlocalhost%02d:%02d:%02d [%s] [UID:%d][%d] %.*syesnosystem()%s, errno: %d (%s) /dev/nulllibpthread.sopthread_atforkHTTP_[UID:%d][%d] %s:%s: %s LSAPI: jail() failure./etc/Can't set signalsaccept() failedLSAPI_STDERR_LOGPHP_LSAPI_MAX_REQUESTSLSAPI_MAX_REQSLSAPI_KEEP_LISTENLSAPI_AVOID_FORKLSAPI_ACCEPT_NOTIFYLSAPI_SLOW_REQ_MSECSLSAPI_ALLOW_CORE_DUMPLSAPI_MAX_IDLEPHP_LSAPI_CHILDRENLSAPI_EXTRA_CHILDRENLSAPI_MAX_IDLE_CHILDRENLSAPI_PGRP_MAX_IDLELSAPI_MAX_PROCESS_TIMELSAPI_PPID_NO_CHECKLSAPI_MAX_BUSY_WORKERLSAPI_DUMP_DEBUG_INFOnobodyLSAPI_DEFAULT_UIDLSAPI_DEFAULT_GIDLSAPI_SECRETLSAPI_LVE_ENABLEliblve.so.0lve_is_availablelve_instance_initlve_destroylve_enterlve_leavejailPHP_LSAPI_PHPRC=packetLen < 0 packetLen > %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGNOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

    Resource Limit Is Reached

    The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
              replacesrandQUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMESTDERRreopenftruncate() failed. File mapping failed. Memory calloc error[...]nilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXRACK_ROOTchdir()to_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXX;{ \f(q@rTrh r|rrr z8zl {p{{p|},p~| DЀl0,x0P px P$ `8 pL Ў` | P `@ ВT  @X l p p  0| xDЪX0lp @ P4`H\p 0@P<л|TPPp,@Th| p  8@X0Pp0P `d P$8d0zRx $X FJ w?:*3$"Db \mpmm LmsEIB E(A0z (A BBBI A (D BBBA m m@mYGJB B(A0A80F(B DBb0TtBFC G  AABK   AABG xEO D  A @$ T hY|hJEDS ]Ph H XAH$lFBB B(A0A8LP 8A0A(B BBBH <H FBB A(A0 (D BBBI \i`ptFBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH L0$FBB A(A0H Q D 0A(A BBBH L$FBB B(A0A8G 8A0A(B BBBF tFFX$nCXJLlFBB B(A0A8DA 8A0A(B BBBA `( ܏BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0 xBMD GL  AABA < =BAA G L@I@U  AABG $ TWEHG ( \ag H SHL FBB B(A0A8DPS 8D0A(B BBBF T lbIE D(C0P (F BBBM Q(H BBBAH FBB B(A0A8DP 8A0A(B BBBA T< xCBA A(G0` (A ABBD  (C ABBA J8 @-FBD D(D@T (A ABBB  4( @lECGF AAI L !cBG A(D0 (A ABBE XD0` dt pZ 10 pFAA G@7  AABF  $@LsL HFBB B(A0A8G 8A0A(B BBBG < P  d x  ( 4 @ L  H  D@ << FBA K(G (A ABBG <X FEE D(D0M (C BBBB L(HhFBH E(A0E8I@ 8A0A(B BBBE ( FED ABH$ BBB B(A0A8G 8A0A(B BBBJ DpDFBB A(A0G 0A(A BBBF L FBB B(A0A8G  8A0A(B BBBA \h4p Hl\x+p(BFGA kFBzD O E   HU gHQ G <haydT2HW I I(tEDL ] CAJ dELhEYl HWt HW|-Hd( EAD  DAJ LX3ED hAHlxFBB E(D0C8GPm 8F0A(B BBBG ,LZAD J ABL 4oAD  AAK pP \ 4FDA D(F0` (D ABBB j (D ABBE l(G DBBDBBI B(A0A8D@8D0A(B BBBl*HP H I|UKI8FBA D(D@ (A ABBE @(TEDG0 AAI H$PFBB A(A0 (F BBBH {(F BBB@(OFBB A(D0D@  0A(A BBBJ 84KFBA A(D0 (A ABBE GNUPTT` !A#).4;JZjx !,<@R^r ':Q_r   s h> P !X !o` !.8&p o%oo"$oDh !>>>>>>?? ?0?@?P?`?p?????????@@ @0@@@P@`@p@@@@@@@@@AA A0A@APA`ApAAAAAAAAABB B0B@BPB`BpBBBBBBBBBCC C0C@CPC`CpCCCCCCCCCDD D0D@DPD`DpDDDDDDDDDEE E0E@EPE`EpEEEEEEEEEFF F0F@FPF`FpFFFFFFFFFGG G0G@GPG`GpGGGGGGGGGHH H0H@HPH`HpHHHHHHHHHII,LSLSLSLS!$#!GA$3a1h> GA$3p1067`TGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1067GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY`T GA+GLIBCXX_ASSERTIONSlsapi.so-5.5-1.el8.x86_64.debugܣ7zXZִF!t/wZ]?Eh=ڊ2NI ͕  (<φ5+#Su-a?'L<nr)>!T:Iw'a;W2aI;bq]]bkQpQ DGymYE{E:C m4b_3fw@(]|simko:.4tܰ0!TL=k(#fHJuSX]1;#ewpZvPzfWh&9\JXW.\O)ĮW)Ê\iSkts ԇ*?`ʳP6eHtR p*rH`FR¹JIY=k06j{  c~82vAOIʝ/`m}~t7zP=>9x.xc_" [t#j`t8BMtze01_0㶚h/ݜJh7?Dj!"B56JJv}aJI⦬w7}N+)a^Jgi~v0&SSMpfIC7\&ߥ?xphDBO"FP1>") xSdr}hT/mGkS-~lX. gg7J|`n6Ͻ0s(d\bg;3qe{MiJ/X:ФOv`bʟDSregj#72?|#xFl{(yܪ+2TQjPr(RRΔLeR4S M/.Pԙg+|wOL,ZmQI}B,zo-7y+G ӺKx& !N Bp^+wwOΒ|7fhNu9ʖ/]8V`M-}Z>.Eed^TϒOC@=zJˏ 5,c{K1Obڡ8.&)aT?S}[@G$گ`'9BjU(Ch}uU$LfQt=&DL.C1!UymLH壄69anCuTȎ:Շ֌r&Q`Wpj؂#@?F~|2tAi)>hڷ ѫ%lќar I?2ak<^%eq҂z10oz,F3\X+E$:G }|kKݵKTnG`E:}jIQrGRlX?^pיFHh&Y3YF \[LA-b6xKGvu'8F*R+29Ħ]EMO2LI\<]FMTwMiA.#:`)\|D <{ l$,HlѲ%z؃kUn0.;5[.N /%5>GtX k똞 );4.éZ ݢ?цuinIX1HAsuW#*JW:! w9͔oZZr $ΓAMY5r@ՀM1yhB 7K''SSE50OJpzӱuF4*3 .+C8 _X"ZúEULBm C]Af\{$6p.͸ViR# }&~[@7U6:SS.~Q#Mf-PȗjaUfp5r8A(, D7< ѱgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``p( 0 8o"$"$Eo%%pT8&8&p^B..hh>h>c>> n I I wSSK}} p ppXXL P !P X !X ` !`  h !h X!X!X`!` @!@ 'a@\#$"#+1PKu].c|!ruby-lsapi-5.5/ext/lsapi/lsruby.onu[ELF>@@98 ,.+/*0)1fDHff.HHH+HHODH1f1fATIHUSHcHcLHH=HH[]A\ff.HH5dH%(HD$1HH$Ht-H=HHD$dH3%(u&H@H=HHfDHHH=HfHH=Hc5;5H=|6HHHfDf?IH=HH+9M1~+HHcHc5H5~Hfff.@HH=tHHHDHff.UHSH HHm t]uaHHHtT؃tJ tEHH؉уu5HM u@HHpH}HH[]HD@HuHHMH tHPHpfSHCH[ff.SHHH[ÐHH=HHHH=HHHH=tHHHUSHH=H=HtHH9t H5Ht[11ҿ1H?H-H;HHuHuH;HHHH[]fH=HHSHH\$Ht$HH1HH[ff.fAWAVAUAATIUSHHJfDmHHfKHHt -OkHHu-2 GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1067GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realignreplacesrand/QUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMESTDERRreopen%s: %s ftruncate() failed. File mapping failed. Memory calloc error [...]nilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXLSAPI_CHILDRENRACK_ROOTchdir()ENVto_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXXF 9%I'P(int)@ 9 1 3 6  7  8  9 : ( ; 0 < 8 = @ @ H A P B X D` Fh Hp It J x MP NW O Q Y [ \ ] ^ G _ - ` b  +  9  9 ? M     UJ U   U a}^q!$2 7 ;  f9:IDg9@4 @b     I  @`  @ @ @x@v#w :xF@@  :@5   Z :len ptr aux5Zary  9(as@2 W$Flen aux%2ptr&F'Wary( F 9(as)(sA tu L v L w G L !GA "L ::::::::::::::::::::::::::::::::::::::::::::::::: : : : : ::::::::::::::::::: :!:":#:%:&:':(:*:,:,:,(:G:H:I:J:K::  9 7 89:;<=>#@,     $q=%s%t k m n  o  p  u ,  =                $  ( D D  T4 T 9 d 9                "= " 4 6 7  /k 1 2  3  4 & : < = ? @ B C E( F0 G8 I@ JH KP L!X O` Ph Qp Rx T' V' W' X' Y' Z' \' ]' _ ` a b c d e f g h i'k''m'('n'8'oG    G  -=)d = 9 j(9qks)?!!!!!G-.P  W  c  9 c A W   F*WTQQ  )4?JU`Akv$  !{$$% $% 4% D 4 9 D 9 T 9 o  Too I 9  9@+":+#:,$: ,(: ,*: ,,: ,.  2-req4-env5: 6)!!!-7Q,9: ,;: ,< ,>: +?,@~  By D E F GH7,Jy  (9,K  .  /-K$0/ :1p0 01 23S*K 4C5U 5T320T6T$0T23TK 4C5U 5T74C5Q05R02`0 :4C5TH5Q 5R|20:4C5TH5Q 5R|7 %38-%59:;%:F%8,: :;>:4C5Us5T05Q:<CY5U <Cw5Us5TM<C5Us5Tm<C5Us5TK4C5Us5Tk8%69:!%8:!^;:;:4C5U 5Ts5Qv5R =9# ;9;9<C5U 4C5Us8,:9;>:4C5T05Q:>D<C@5U >D>!D<Cy5U >.D>;D<HD5U <UD5U 5T7<UD5U 5TA<bD5Q}??5U 5T 5Q1<oD^5U ?5T 5Q 5R0?5T 5Q 5R0?5T 5Q 5R1? 5T 5Q 5R1?@ 5T 5Q 5R ?n 5T 5Q 5R ? 5T 5Q 5R ? 5T 5Q 5R1? 5T 5Q 5R0?#!5T 5Q 5R0?P!5T 5Q 5R0?~!5T 5Q 5R ?!5T 5Q 5R0?!5T 5Q 5R0?"5T 5Q 5R0?2"5T 5Q 5R0?_"5T 5Q 5R0?"5T 5Q 5R0?"5T 5Q 5R0?"5T 5Q 5R0?#5T 5Q 5R0?@#5T 5Q 5R1?n#5T 5Q 5R <HD#5U <HD#5U >|D>|D>D>_4<D#5U <D$5U >|D?X$5T 5Q 5R0?$5T 5Q 5R0?$5T 5Q 5R0<D$5U 4C5U  F$@%$A& B -%CpB R%Cn  Cp D:%E E-E9:6 :F3*K G:g4&H :Iw+ >D>D>DG:v&J":UJ-:TK:&E:D:&E!:G:&J":UG:+C'J:UL8 M8G:Ua(H:1str :=a( ';s(7+ 8)S(;*9N*:+*N8*:C*<>D(O*s>,+>DD:(E!:Gr:4)HrHr*Hr6:1strt :1nu 0v 0w 89 w);9>D>D>,+<D)5Us $ &<O*)5U|< E)5U}5Qs $ &4 E5U}5Q| $ &DC:O*EC :CstrE :6FCnG CpH G. a+H."P0 01 02 03 64 884+M8>EQ)Q$R K+Cfd Rw+Cfd Csfn QG:2+H :1ch >"EG:%,H!:>DG:,Sout!:Sstr,:4/5Us5TTD:,EE*Tout6:Ci 6 :De:2-Tarye#:Toute.:Ee7Ctmpg :Cih G\:-H\H\,Sout\8:<.E-5UU5TT4/5UsG8:O/H8H8,Sout88:1i: 3; :@8$9Jv.;69<;E.5U~5T3</.5Uv</.5Uv</.5Uv</.5Uv>HE>UEU,:0H,!:Sstr,-:0.1len/ 890/;94^E5Uv5T<8$92 /;694kE5UsG :K1H :Sc +:Vch" W0#8D9"0;V9W9f;9<D05Us>D89$$1;94^E5Uv5T<?=15TW5Q1>UEG: ~1J#:UX:3 2Y+:Zstr7:<xE15Us<E15Us4E5T0X: P2Y,:>EX: 2Y+:>EX:-2Y,:>EX:E4Y$:[pid 23\ + $\ 23, K 4C5U 5T54C5U85Q05R0]E4 4;R4>_4<E45Qs4E5Qs>E>D>!D^ _4_)` z52 5a,'5`a24,K 4C5U 5T74C5Q15Rw>UE F'5 95X B6Y)Y3YHYTZarg#G<UD55UQ5T R $ &<UD55U|5Ts $ &4bD5QvXd ?8Yd(Yd2YdGYdSZarge"G[pg blenh <UD65U|5T~<UD65Us5Tv $ &<bD75Q|<E.75U|5T?<UDN75U|5T<UDr75U 5T9<bD75Qw<UD75U|5T<UD75U 5T<<bD75Qw<UD85U5T}<UD*85U 5T<4bD5Q}cZ 8YZ&dEe8_?e8_<D8Ta:f !:D9Ta$:Dy$9Tay:D?D9Tobj?:Dab9Txa:D:9Tx:EECDG9Tobj:D9Tx:g:__g\,:_\_\hiL:Eigdw:_d!_d<ija(:ks(Uj&:k&UjR%;;d%;q%;~%N%WR%;~%;q%;d%9:%l%;4C5U 5T6>|D>|D<D;5U >|DmC5QU5RTj,+>n>+=83<M8Iw+8,+ >9:>+8K+=9:]+:i+8L: =;i:;]:4F5T15Q 5Rs<F4=5U <FL=5Us<)Fd=5Us<D|=5Us>6F>BF4D5Us<OF=5Uv5Ts<\F=5U05Ts5Q35R15Xv5Y0<hF>5Uv<D3>5U <hFK>5Uv<Dj>5U 4hF5Uv<uF>5T14D5U j)?:*N+*:8*:C*;*I+X <O*B?5U <Fu?5U|"5Tv5Q 5R1<D?5Uv4 E5U|5Qvj)* @;*N*o+*N8*pC*>,+m>O*Uj,8B;,;,; -q-@:&-89p@;9=b9r@;9;9;t94F5Us88rWA;8988 AA;84F5Us=,'eB;,; -;,r'q-@N&-<;EA5U 5T54F5U15Tw5Qv<F*B5U15Tw5Qv>UEj,PC;,;,;,N,N,s,nCM,M,M,9:,:,8$9B;69<FC5U 5Qs>kE</;C5Us5T~</SC5Us4;E5U|5T34/5Usttetutwvw/tmp/lsapi.XXXXXXvw .XXXXXXtu{tnttt tttt7ttt0t t  uuL t3 ttttt$u utttxtRttVtWtcttt}uut^utuZ u Dt t9 u% tt u9ta ttqw lsruby.ctttYt% : ; 9 I$ >  $ > &I I7I I !I/  : ; 9  : ; 9 I8 : ; 9 <4: ; 9 I?<!4: ;9 I?<: ; 9 I> I: ;9 ( (((   : ;9  : ;9 I8  : ;9  : ;9 I : ;9  : ;9 I8  : ;9 I : ;9 I 8 '!I": ;9 I#> I: ; 9 $ : ; 9 % : ; 9 I& : ; 9 ' : ; 9 I8(!I/)'I* : ;9 +4: ; 9 I,4: ; 9 I- : ; 9 I8 .4: ; 9 I?/.?: ;9 @B04: ;9 IB14: ;9 IB2 U34: ;9 I415B64: ;9 I71RB UX YW 81RB UX YW 9 U:41B;1B<1=1RB X YW >1?@!I/ A.: ;9 B.: ;9 C4: ;9 ID.: ;9 'I E: ;9 IF G.: ;9 'I@BH: ;9 IBI1RB X YW J: ;9 IK.: ;9 'IL1RB X YW M1N41O1BP4: ;9 IQ.: ;9 I R.: ;9 I S: ;9 IBT: ;9 IU.: ;9 'I@BV4: ;9 IW1RB UX YW X.: ; 9 'I@BY: ; 9 IBZ: ; 9 IB[4: ; 9 IB\4: ; 9 IB]1RB UX Y W ^.: ; 9 ' _: ; 9 I`.: ; 9 @Ba4: ; 9 I b4: ; 9 I c.: ; 9 '@BdB1e.: ; 9 'I f.?: ;9 '<g.?: ; 9 'I 4h.?: ;9 'I ij.1@Bk1l 1UmB1n41 o41p41 q41r s1UX YW t.?<n: ;9 u.?<n: ; 9 v.?<n: ; w6x.?<nOVOTpqPPqP0uVT0V0T0?0T0?0nPP PPSSPS,8P8HSHcTSSH\TpSH\ Tp vv vPUU U  S  P U U  S  P S  S      0  0 U S D UD g Sg u Uu  S U S U T V D TD a Va u Tu  V T V T Q Q P  ] + P+ C ]C D P ] S  SW u P \ v| v| $0 $+(  v $0 $+( ? v $0 $+( v $0 $+(  P PL V Uu | U U u@aUN $ &"^a $ &"O^PNQ^aQpUUPPpUU`lUlqSqrP`lTlrTUUTTQSQPUwwUw1PT]wTTWPQpVpwQwQV{0S8=S0 s $ &3$}") s $ &3$}"UVWUTS,AS&V,WV+PUVS,9S0 U V U V0 S TS S T S PP S TS S S S S U VU3UTUUUUU U!U!UkPP0000SU\UTSTQQRRXX@USSSS@TVTTVTVT_V@Q\3Q3\JQJ_\@{R{]R]RG]G^ R Z]Z_^@XX3X3XJXJ_X7PPP_JTPT__`hUhmU`USQUS`TVRTV`QQQQVRTVSQUS\\rV * Vg q  q V@Y YiPiV * V* 4 P4 VRVPVyS* q SN q U Z pZ ^ UR n Pn \ PD } S  P6 > P * U U T UT S U S U  U T TT V T V T  V T QT Q Q  QT ] } ] ]T _ S Sd  d  r  rd l Sl  S Sv  S S U  U Q  Q T  V1U1.U.:U:PU1T1.T.=T=PT1Q1SQ.S.AQACSCPQ10UP^P.^1_UU,8U 8U/09szsz@ @r0 g < K N _ L W x  X _ l  v  P 08_0cXH\\cXpv@` 0@ $@LnW /opt/alt/ruby27/include/ruby/usr/include/bits/usr/include/usr/lib/gcc/x86_64-redhat-linux/8/include/usr/include/bits/types/usr/include/sys/usr/include/netinetlsruby.clsapilib.hruby.hstdio2.hstdlib.hstring_fortified.hstddef.htypes.hstruct_FILE.hFILE.hstdio.hsys_errlist.htypes.hstdint-intn.hstdint-uintn.hunistd.hgetopt_core.hmath.hintern.hversion.hlsapidef.htime.hstruct_iovec.herrno.hsockaddr.hsocket.hin.hsignal.hstring.hmman.hutil.h  JK?K| #t>iK>KK{KY;./*X **}( // RX} t     0Yf q\:>X. t" u t/u* uZ ^  %gfu Z3 X }t }< tXX uKt  .t.  X  f. f *8u t  X    o.@5< t-< ti JJ [X -JiX O  L( ff-X< n9= t; K1 tQJ/f J L 2  =t<UMtUX&<< ` 0z X .    =Yl  qX[wt Z " h   m grtX  h fY:g< KXfKY sbXtv  SY|X |X<   L/$ eX< z < zt yt5Y|X |.X z  Z rh Y   *xp*suqwZ7Mt -uDXZ;467954644584236:8648: "u{ wt JvI ;tZvpJuI==[X=XvXuv0X>f~z t gz t ` X p((* uv #G< Y(%[$ rb_mWaitWritable_sys_errlistm_pScriptFileRUBY_Qnilrb_eNoMemError_unused2_filenorb_cMethodrb_obj_wb_unprotectrb_eSyntaxErrorm_cntUnknownHeadersH_AUTHORIZATIONsockaddr_isoblockSizem_pIovecEndstrcpym_pRespBufPosRUBY_FL_EXIVAR__uint8_tdmarkRUBY_DATA_FUNCm_pktHeaderrb_eIOErrorm_bytesm_pHeaderrb_data_object_get_shortbufsockaddr_inrb_cFilerb_eSignalunlinklsapi_dataRUBY_T_ARRAYrb_eKeyErroradd_env_rails__environlsapi_addstrsa_datauint16_tm_totalLensin_zeroRUBY_FL_UNTRUSTEDrb_eZeroDivErrorin_port_t_flagslsapi_getscallocm_respPktHeader__off_tcreateTempFiledfreeRUBY_T_IMEMOrb_global_variable_lockROBJECT_EMBED_LEN_MAXRUBY_T_UNDEFrb_cStringrb_eEOFErroratoim_pHttpHeaderLSAPI_GetReqBodyRemain_rm_pScriptNamerb_mKernelm_pEnvListrb_output_fsint32_t__fmtsa_familym_specialEnvListSizerb_cModulesockaddr_ns__u6_addr8RUBY_T_FALSEruby_robject_flagsrb_cIntegerRUBY_T_FILE_IO_write_endm_iLensockaddrrb_cTrueClasss_addrRUBY_FL_USER0RUBY_FL_USER1RUBY_FL_USER2RUBY_FL_USER3RUBY_FL_USER4RUBY_FL_USER5RUBY_FL_USER6RUBY_FL_USER7RUBY_FL_USER8RUBY_FL_USER9nameLenLSAPI_Postfork_Childfreerb_fsm_requestMethodOffRUBY_T_COMPLEXdata_struct_objrb_eEncCompatErrorruby_special_constsvalLenRSTRING_EMBED_LEN_SHIFT__stack_chk_failruby_rarray_flagsruby_descriptionsin_familyRStringm_fdListenMAX_BODYBUF_LENGTHlsapi_bodym_statusm_reqBodyLenrb_eNameErroroptargneedReadrb_eRegexpErrorrb_cBasicObjectRUBY_T_STRUCTrb_cRationalrb_cFloatrb_cClassrb_cStatsys_errlistin_addr_tbasicRUBY_QtrueLSAPI_ReqBodyGetChar_rpKey__uint16_tsin_portRUBY_T_STRINGrb_cContrb_cFalseClassm_flagRARRAY_EMBED_LEN_SHIFTreadMaxBodyBufLengthm_pQueryString_chainRUBY_T_MODULErb_eArgErrorrb_eInterruptrecurrb_funcallvRUBY_FL_SINGLETONsockaddr_ununsigned charcapanReadm_cntSpecialEnv_IO_lock_tRUBY_T_ZOMBIEfloatLSAPI_key_value_pairLSAPI_ForeachHeader_rrb_stderrlsapi_eachm_cntHeadersrb_str_catbodyBufRARRAY_EMBED_LEN_MAXRUBY_T_FIXNUMrb_eSecurityErrorisEofBodyBuflsapi_processlsapi_flushRARRAY_EMBED_FLAGROBJECT_EMBEDoff_tchild_statusRUBY_SYMBOL_FLAGrb_mComparableH_X_FORWARDED_FOR__fprintf_chkm_queryStringOffRUBY_FLONUM_FLAGrb_stdoutruby_rstring_flagsH_CONTENT_LENGTHrb_cTimeruby_engine_IO_write_ptrrb_output_rsROBJECT_ENUM_ENDlsapi_packet_headerLSAPI_ReadReqBody_rrb_eFatallsapi_http_header_indexrb_funcall_argcsTempFilerb_funcall_argsclosesharedlsapi_printfRUBY_T_OBJECTFILEH_COOKIEs_fn_add_envmunmapRSTRING_EMBED_LEN_MAXbodyCurrentLenLSAPI_Accept_Before_Forkrb_cNumerics_req_stderrrb_cHashsize_trb_array_const_ptrH_CONNECTIONrb_rsuint8_tH_CONTENT_TYPERArraylsapi_markm_headerLenRUBY_ELTS_SHAREDperrorlsapi_envruby_release_daterb_cDirsetup_cgi_env_IO_save_baseioveclsapi_eofrb_array_const_ptr_transientenvironlsapi_child_statusreadTempFileTemplatesockaddr_x25rb_eLoadErrorsin6_flowinfom_pIovecToWriteorig_stderrm_respHeaderLen_wide_dataH_IF_MATCHRUBY_FL_PROMOTED0RUBY_FL_PROMOTED1__in6_uGNU C17 8.5.0 20210514 (Red Hat 8.5.0-18) -mtune=generic -m64 -march=x86-64 -g -O2 -fPIC -fexceptions -fstack-protector-strong -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection=full -fplugin=gcc-annobinH_ACC_CHARSETruby_versionorig_stdout__streamsigngamruby_copyrightm_reqBufSizerb_eExceptionrb_yieldadd_env_no_fixRUBY_T_FLOATRUBY_T_CLASSrb_cDataftruncateruby_fl_typelsapi_requestrb_cComplexfprintfrb_check_typeRUBY_T_HASHsyncRUBY_T_NODEchdir__ssize_t__srcrb_mErrnolsapi_closeH_IF_RANGEnameOffruby_api_versionstrerrorsa_family_tm_packetLenreadMoreRUBY_FL_WB_PROTECTEDin6_addrisBodyWriteToFilelinesin6_addrrb_mWaitReadablelsapi_setsyncm_respPktHeaderEndRUBY_FL_TAINTLSAPI_Postfork_Parentfn_add_envlsapi_printrb_eSystemCallErrorrb_intern2stderrm_pHeaderIndexprogram_invocation_short_namerb_cUnboundMethodrb_f_sprintf_IO_save_endrb_const_get__nptrLSAPI_InitLSAPI_Requestrb_eScriptErrorrb_tainted_str_newfn_writelsapi_syncm_bufProcessedstdoutreadBodyBufoptoptlsapi_reopenrb_mGCrb_eIndexErrorm_httpHeaderLencurPosH_IF_NO_MATCHlsapi_s_acceptpreforkRUBY_T_DATAbuffssizetypekeyLenRUBY_FL_DUPPED__builtin_strchrLSAPI_Flush_rshort unsigned intsigned charrb_array_lentz_dsttimefilenamelsruby.clsapi_header_offset__off64_tsockaddr_eon_IO_read_base_offsetm_pIovecrb_string_value_ptrrb_eFloatDomainError_IO_buf_endm_respInfoopterrlsapi_puts_ary_modeblkSize_IO_write_basevalueLenInit_lsapirb_eStandardErrorrb_cSymbolrb_argv0H_CACHE_CTRLH_COOKIE2__destrb_cMatchrb_cEncodinglsapi_isattyH_USERAGENTRARRAY_EMBED_LEN_MASKLSAPI_ForeachEnv_rlong intRUBY_T_NONErb_mProcessrb_mFileTestremain_IO_markerrb_cEnumeratorm_pRespBufEnd__builtin___memcpy_chkrb_io_putslsapi_s_postfork_childrb_define_global_constrb_obj_as_stringm_bufReadin_addruint32_tsockaddr_in6__pid_t_IO_codecvtrb_funcall_nargsH_RANGERDatastrtolg_reqlong doublerb_cRangeiov_lenlsapi_resp_inforb_cObjectlong unsigned intlsapi_req_headerRVALUE_EMBED_LEN_MAXrb_gc_markinitBodyBufruby_strdupm_headerOffrb_eNotImpError__errno_locationlsapi_s_postfork_parentcharsockaddr_inarpm_pSpecialEnvListsin6_scope_idrb_cIORSTRING_ENUM_ENDstdinsin_addrRUBY_T_BIGNUM_IO_buf_baseRSTRING_NOEMBEDRUBY_T_RATIONALRUBY_FL_PROMOTEDs_bodyrb_eTypeErrorRBasicrb_eNoMethodError_IO_read_endRUBY_T_ICLASSrb_num2intcLSAPIRUBY_SPECIAL_SHIFT_IO_FILEH_IF_UNMOD_SINCEm_fdRUBY_T_SYMBOLH_HOSTrb_num2char_inline_IO_wide_datastrlen__u6_addr16s_pidselfrb_eSystemExitisAllBodyReadm_respHeaderrb_cThreadRUBY_FL_SEEN_OBJ_IDm_envListSizem_pAppDataruby_platformsockaddr_ax25RSTRING_FSTRrb_eThreadError__pad5rb_str_new_staticshared_root__u6_addr32rb_cNilClassm_type_markersrb_stdinrb_eStopIterationm_scriptFileOffRUBY_FL_USHIFTklassrb_define_classH_VIA_codecvtm_pRespHeaderBufEndH_PRAGMARUBY_FL_FINALIZErb_cRandomdoublemkstemplsapi_putcargcssize_tstrcatlsapi_writelsapi_putsorig_stdinRUBY_FIXNUM_FLAGargvRARRAY_ENUM_ENDrb_eRuntimeErrorm_pRespHeaderBuf__int32_trb_cProc__uint32_tRUBY_IMMEDIATE_MASKrb_hash_asetdataH_REFERERrb_cStructLSAPI_Prefork_Accept_rheap_sys_siglistRARRAY_TRANSIENT_FLAGm_pUnknownHeaderrb_typem_reqStateRUBY_T_NILRUBY_T_MOVEDrb_eSysStackError/builddir/build/BUILD/opt/alt/ruby27/share/gems/gems/ruby-lsapi-5.5/ext/lsapim_pRespBufrb_num2int_inlineprogram_invocation_namerb_cArrayrb_eEncodingErrorrb_ruby_verbose_ptrrb_cBindingrb_intern_id_cacheH_TRANSFER_ENCODINGH_IF_MODIFIED_SINCErb_ary_detransientRUBY_FL_USER10RUBY_FL_USER11RUBY_FL_USER12RUBY_FL_USER13RUBY_FL_USER14RUBY_FL_USER15RUBY_FL_USER16RUBY_FL_USER17RUBY_FL_USER18RUBY_FL_USER19_freeres_bufRUBY_T_MATCHlong long unsigned intpid_t_cur_columnlsapi_rewinds_reqrb_eRangeErrorm_pRespHeaderBufPoss_stderr_datarb_eval_string_wrapgetpidm_cntEnvRUBY_T_MASKrb_lastline_getcreateBodyBuf_IO_backup_baseH_KEEP_ALIVE__memcpy_chk_IO_read_ptrrb_eMathDomainErrorrb_fix2intLSAPI_GetReqBodyLen_rrb_gc_writebarrier_unprotectrb_exec_recursivegetenv_freeres_listrb_eLocalJumpError_sys_nerrlsapi_readtimezonepReqlsapi_getcrb_hash_newclear_envrb_cRegexplsapi_binmode_old_offsetstrchrm_pReqBufrb_cNameErrorMesgvalueOffoptindH_ACC_LANGlong long intin6addr_loopback_flags2VALUErb_mMathRUBY_T_TRUEmemmemsin6_familysockaddr_atruby_value_typem_scriptNameOffH_ACCEPTm_lLastActiverb_eNoMatchingPatternErrorlsapi_resp_headersys_nerrin6addr_anym_pRequestMethods_req_dataiov_basem_lReqBeginruby_rvalue_flagsm_versionB0m_versionB1rb_str_buf_newRUBY_FLONUM_MASKruby_patchlevelRUBY_T_REGEXPm_pIovecCurLSAPI_Init_Env_Parametersorig_envm_reqBodyReadRUBY_Qundeflsapi_s_accept_new_connrb_eFrozenErrorsockaddr_dlRSTRING_EMBED_LEN_MASKRUBY_FL_FREEZEunsigned intbodyLensockaddr_ipxrb_default_rsshort intrb_string_value_vtable_offsetpValueenv_copymmaporig_verboserb_data_object_zallocrb_mEnumerableRUBY_Qfalseflagstz_minuteswestsys_siglistH_ACC_ENCODINGsin6_portlsapi_eval_string_wrapGCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-18)GNUzRx  0D+Xl(BFGA kFBzD O E  HUgHQ G $ayd<2HW I I(\EDL ] CAJ ELEY HW HW-Hd(EAD  DAJ 43ED hAHTFBB E(D0C8GPm 8F0A(B BBBG ,ZAD J ABL 4oAD  AAK pP \4FDA D(F0` (D ABBB j (D ABBE l(G DBBDhBBI B(A0A8D@8D0A(B BBB*HP H IUKI8FBA D(D@ (A ABBE ((<EDG0 AAI HhPFBB A(A0 (F BBBH {(F BBB@OFBB A(D0D@  0A(A BBBJ 8KFBA A(D0 (A ABBE   - )  ?.Yt/01 5 C _"y @"[0+[h` h)wCpPwmB pZz# < xEZ_mw` mpg0aIaUaop2WWr`r1KX   #J o-  X  ` 3D3[3x_@_`  3 N\ @f   4      '  *2  L  d  Uo     '   '   ' 0 2  L Pd Po P  PO          h "$%'./0123-4# ( - @2 )7 < 3A F K LP SU [ ba Zg xm s y           $ * f n s y             ! ' - 3 9 ? E 1K GQ VW ] c i u    ()*+,       # . < C H \ s        $7G[ov-&18A^i|K $*4?L_o   .annobin_lsruby.c.annobin_lsruby.c_end.annobin_lsruby.c.hot.annobin_lsruby.c_end.hot.annobin_lsruby.c.unlikely.annobin_lsruby.c_end.unlikely.annobin_lsruby.c.startup.annobin_lsruby.c_end.startup.annobin_lsruby.c.exit.annobin_lsruby.c_end.exit.annobin_lsapi_process.start.annobin_lsapi_process.endlsapi_process.annobin_lsapi_rewind.start.annobin_lsapi_rewind.endlsapi_rewinds_body.annobin_lsapi_eof.start.annobin_lsapi_eof.endlsapi_eof.annobin_lsapi_binmode.start.annobin_lsapi_binmode.endlsapi_binmode.annobin_lsapi_isatty.start.annobin_lsapi_isatty.endlsapi_isatty.annobin_lsapi_setsync.start.annobin_lsapi_setsync.endlsapi_setsync.annobin_add_env_no_fix.start.annobin_add_env_no_fix.endadd_env_no_fixlsapi_env.annobin_clear_env.start.annobin_clear_env.endclear_envrb_intern_id_cache.15416env_copy.annobin_lsapi_mark.start.annobin_lsapi_mark.endlsapi_mark.annobin_lsapi_flush.start.annobin_lsapi_flush.endlsapi_flush.annobin_lsapi_close.start.annobin_lsapi_close.endlsapi_closeMAX_BODYBUF_LENGTH.annobin_readBodyBuf.start.annobin_readBodyBuf.endreadBodyBuf.annobin_lsapi_getc.start.annobin_lsapi_getc.endlsapi_getc.annobin_lsapi_write.start.annobin_lsapi_write.endlsapi_write.annobin_lsapi_addstr.start.annobin_lsapi_addstr.endlsapi_addstr.annobin_lsapi_printf.start.annobin_lsapi_printf.endlsapi_printf.annobin_lsapi_s_postfork_parent.start.annobin_lsapi_s_postfork_parent.endlsapi_s_postfork_parents_req.annobin_lsapi_s_postfork_child.start.annobin_lsapi_s_postfork_child.endlsapi_s_postfork_child.annobin_lsapi_s_accept_new_conn.start.annobin_lsapi_s_accept_new_conn.endlsapi_s_accept_new_conn.annobin_lsapi_s_accept.start.annobin_lsapi_s_accept.endlsapi_s_accepts_pidrb_intern_id_cache.15429s_req_data.annobin_lsapi_eval_string_wrap.start.annobin_lsapi_eval_string_wrap.endlsapi_eval_string_wrap.annobin_add_env_rails.start.annobin_add_env_rails.endadd_env_rails.annobin_lsapi_reopen.start.annobin_lsapi_reopen.endlsapi_reopens_req_stderrorig_stderrrb_intern_id_cache.15593.annobin_createBodyBuf.start.annobin_createBodyBuf.endcreateBodyBufsTempFile.annobin_lsapi_read.start.annobin_lsapi_read.endlsapi_read.annobin_lsapi_gets.part.2.start.annobin_lsapi_gets.part.2.endlsapi_gets.part.2.annobin_lsapi_gets.start.annobin_lsapi_gets.endlsapi_gets.annobin_lsapi_each.start.annobin_lsapi_each.endlsapi_each.annobin_lsapi_puts_ary.start.annobin_lsapi_puts_ary.endlsapi_puts_ary.annobin_lsapi_sync.start.annobin_lsapi_sync.endlsapi_sync.annobin_lsapi_putc.start.annobin_lsapi_putc.endlsapi_putc.annobin_lsapi_puts.start.annobin_lsapi_puts.endlsapi_puts.annobin_lsapi_print.start.annobin_lsapi_print.endlsapi_print.annobin_Init_lsapi.start.annobin_Init_lsapi.endrb_intern_id_cache.15609rb_intern_id_cache.15614orig_envcLSAPI.LC0.LC1.LC7.LC5.LC4.LC6.LC3.LC2.LC8.LC9.LC13.LC11.LC10.LC12.LC14.LC15.LC16.LC17.LC18.LC55.LC20.LC21.LC25.LC26.LC27.LC28.LC29.LC33.LC34.LC35.LC36.LC37.LC38.LC39.LC40.LC41.LC42.LC43.LC44.LC45.LC46.LC47.LC48.LC49.LC50.LC51.LC52.LC53.LC23.LC19.LC30.LC31.LC32.LC24.LC22.LC54.text.group.text.hot.group.text.unlikely.group.text.startup.group.text.exit.group_GLOBAL_OFFSET_TABLE_g_reqrb_tainted_str_newrb_hash_asetrb_funcallvrb_intern2__stack_chk_failrb_gc_markLSAPI_Flush_rmunmapfreeLSAPI_ReadReqBody_rLSAPI_ReqBodyGetChar_rrb_check_typerb_obj_as_stringrb_f_sprintfLSAPI_Postfork_ParentLSAPI_Postfork_ChildLSAPI_Accept_Before_ForkLSAPI_Prefork_Accept_rgetpids_fn_add_envLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rrb_string_valuerb_string_value_ptrrb_eval_string_wrapstrchrrb_ruby_verbose_ptrrb_define_global_construby_strdupmkstempunlinkftruncatemmapcallocperror__errno_locationstrerror__fprintf_chkrb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_str_new_staticrb_exec_recursiverb_default_rsrb_output_fsrb_output_rsrb_lastline_getInit_lsapiLSAPI_InitgetenvstrtolstrlenselectLSAPI_Init_Env_Parameterschdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocLSAPI_Write_rrb_stdoutrb_stdinLSAPI_Write_Stderr_rrb_hash_new__memcpy_chkrb_define_global_functionrb_define_methodrb_define_singleton_methodH7*ltl@EOV{**D <8DH*?HF<KUH{*=****"7<AH8XD^HgmTv|T\*)~l0\hq|lllAg  C* D6 C<HSfnuD  <  <  @     1 8 G Q *[ c t y     D L H  L <( . LS ] Lc Dy  L <  L < D H  L2 K Y Lc <k q L D H  D Lh           &v*3**@* "8DH#$ %#5%QXL_<fm#$*&'T#(**)** +|,3t:t?,KP\dktv5-d7d6d6d6&d9>6EdX]6ddw|6d6d6d6d6d 6d%*61dAF6Md]b6idy~6d6d6d6d6d 6d$)60dCH6O*Vdj.q*x*/\*0*1,d.*2, 3l"l).8=Bg<l4y<d7d7d7 %/6|HMWch {#  i  $, P X" ""["[[hD[Lhphxwhwww 08dlZZZm$Z,mPmXmaDLapaxaW W0W8rdWlrrr$,PX     D  L p x 3  3 3 _ 3 _0 _8 d _l        $  ,  P  X            D  L  p  x     '   ' 0 ' 8  d ' l   P  P P $P,PX       ) . D < C L S Z _ m r B~   j B  P i ~   ' >4 'A N [ h u o  h j   N    2 L  5+ 08 E R _ l y E  G  X  B  ' 3 ? [ g +s       q   :  +     " `) r.  ; W j p v ,|  (    U k 3 s  X   K  V 7      c      & l, 2 8 > _D J KP RV \ >c x v L|    V   &          + 9 G U  ! * *3 9< HE WN fW u` j q x  %     y  4       # o, @ ,M  z B     " A   ) = ,J  z   }  % Y3 IS ` m fz y        s  # d0 e = J W d mq b~  ;    V J   "  g' 4 A oN [ h Xu     K %    k N    + 8 E R _ l y   |   0 6 , Z    }" / j< I V uc h p }      k    # / ; SG 'S &_ k  S     ^  y      M N 5    >   x u  u * % 1 '> & K X e r | 7   ' |  C    5 7 X * 7 $e r  c     s   { @  * f7 =D AQ ~^ l z J  \     >    9   H# =0 = EJ W d /q ~ } : 5           |' t4 A (N 2\ j x H 3       @ [L -X +d q +~  ' a   V  7 M' 4 R C` n | v    n   U    [   2   a   U ab u        k Hx& 3p< UIR }y  } dh  ` .  " /X8 hE R _ l 7z h @ @    V  # A' ;, [8 < A `J X aQr1  p     d F B  )10 % 1 5 ~:nP`a `j v z `  P P      @ <;P1Z x    vH    ' 7+ 30pA@cvlv    )19v 0  "q71AN[p1z CxT1 hz$11@U1$_p1*}1f1n0 #1s  B$ 1y1 PA aR 1_ o  1   1 `  1 p !1!p$!5!1B! Q!b!1o! !.!1!!J!1! !f!1!0""1$"03"D"1Q"`"q"1~"`""1"p""1"p""1# #-%#12#A#LR#1S_#`o#########2#1$A$1L$F,$=$11J$Y$j$1Gw$$ $1V$$l$1$$1% t % % F .% S% e% r% % % V% %% %% % % %% &&'&5& A&X& g& w& & & (& & z&`& &  &0 ' '4('4D' P' g' s' ?w' 9' ' ' ' ' ' ' ' ' ' @' ' ( @( :( 6"( z&( v+( E( T( b( t( ( 5( ( ( ( ( ( ( ( ( h( d( ( ) 7) / ) ) ) !) 1-) ` 1) \ :)L C) T) X) ])W j)} x) ) ) ), ) * * ,* P* \*s* * * * * o* ) * % * 1* * * C* * * ** +O+ + -+ ZL+ Jx+ j+ N+p+ + + + 7 + 3 ++ +p, , q , m ,&, 2,`U, Y, j, n, s,m, , , , |,  - 3- ?-V- b- : f- 6 k- w- w {- s - - --- -P- -  -  . . \ . R #. '. 6. R:. J?. |S.\. m. q. w....8.U.// /2/ >/ B/ S/ ZW/ T\/ Ih/ l/ }/ / // / / /// / @/ </A0 00 '0 30 ~70 vF0 J0 ^0 Ij0 Fn0 Dw0P 0 0 o0 i0 0 00 0 0 0 0 0 `1 1  1 %1 >1 L1 X1o1 1 11 1 01 ,1 k1 i11#1- 2 Q2/2 :2 >2 C2Q2 \2s2 ~2 2 22 22 2 2 22 L22 3 I 3 E3 3 #3 0,3 p 73 ;3 @3 L3 dW3 [3 `3 pi3 v3331333 3 63 433 44&+4E84kF4 S4 I`4 eg4~4 4 p 4 4 d4 @4 44I414 5Z-5 < 85O5 =Z5 _^5 Yc5 ~n5 r5 w5 A5 5 5 5 >5 :5 {5 w5556 6@46 =?6 C6 H6 ~S6 ?W6 -\6 Ag6 k6 p6 {6 6 6 y6 m6 6 66674/7`O7ud71)s77771377881+8@8 G8`^8 Ii8 lm8 hr8m8 8 I8 8 I8 K 8 8  9 %9 E9 c9 a9 9 |9 99 I9 9 9 : :  : -: ?: M: ^: j: %|::p:`: : : +: !: :  ;; ; #; ,; 0; 9; =; ~B; K; O; X; a;r;1S;;;;1L;;; <<8<.A<.Z<@c< Pp< Py< '}< <@< < < < < < <N < < f< d< < <_ =1Z=L+=@5=WM=je=r}=5 =< =g ===> *>1b4># L>} a>1xk> >>>1> > > > > > E> A> }? { ? ? *? C?6 g?1v?O ?o ? ? ? ? ? @ ,@ 0@ 9@ =@ vF@  J@  [@ y _@ q h@ q@ p@ @ @d @d @ !@ !@ Y!@ U!@ !@ !@l @l @  A !A !A Av 'A 8A ! ... end There is no need to change the way that how CGI environment variables are being accessed in your scripts. You can find some examples under examples/ folder. Ruby Script Runner ^^^^^^^^^^^^^^^^^^ If you don't want to change your existing Ruby CGI code, you can use our Ruby script runner under scripts/ folder. You need to configure lsruby_runner.rb as a LSAPI application, then add a script handler for "rb" suffix. Rails dispatcher ^^^^^^^^^^^^^^^^ With Ruby LSAPI, we proudly provide a optimum platform for Rails application deployment. Ruby LSAPI has the following advantages over other solutions. * Easy configuration, deploy a Rails application only take a few clicks with our Rails easy configuration * Fast startup, the expensive Rails framework initialization only takes place once when multiple processes need to be started * Resource efficience, ruby processes can be started on demand, idle process will be stop. To use LSAPI with Ruby on Rails, please check out our toturial http://www.litespeedtech.com/support/wiki/doku.php There are a few environment variables that can be tweaked to tune ruby LSAPI process. * LSAPI_CHILDREN (default: 0) LSAPI_CHILDREN controls the maximum number of children processes can be started by the first ruby process started by web server. When set to <=1, the first ruby process will handle request by itself, without starting any child process. When LSAPI_CHILDREN is >1, the LSAPI application is stared in "Self Managed Mode", which will start children processes based on demand. With Rails easy configuration, LSAPI_CHILDREN is set to the value of "Max Connections" by web server, no need to set it explicitly. Usually, there is no need to set value of LSAPI_CHILDREN over 100 in most server environment. * LSAPI_AVOID_FORK (default: 0) LSAPI_AVOID_FORK specifies the policy of the internal process manager in "Self Managed Mode". When set to 0, the internal process manager will stop and start children process on demand to save system resource. This is preferred in a shared hosting environment. When set to 1, the internal process manager will try to avoid freqently stopping and starting children process. This might be preferred in a dedicate hosting environment. * LSAPI_EXTRA_CHILDREN (default: 1/3 of LSAPI_CHILDREN or 0) LSAPI_EXTRA_CHILDREN controls the maximum number of extra children processes can be started when some or all existing children processes are in malfunctioning state. Total number of children processes will be reduced to LSAPI_CHILDREN level as soon as service is back to normal. When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is 0. * LSAPI_MAX_REQS (default value: 10000) LSAPI_MAX_REQS specifies the maximum number of requests each child process will handle before it exits automatically. This parameter can help reducing memory usage when there are memory leaks in the application. * LSAPI_MAX_IDLE (default value: 300 seconds) In Self Managed Mode, LSAPI_MAX_IDLE controls how long a idle child process will wait for a new request before exit. This option help releasing system resources taken by idle processes. * LSAPI_MAX_IDLE_CHILDREN (default value: 1/3 of LSAPI_CHILDREN or LSAPI_CHILDREN) In Self Managed Mode, LSAI_MAX_IDLE_CHILDREN controls how many idle children processes are allowed. Excessive idle children processes will be killed by the parent process. When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is LSAPI_CHILDREN. * LSAPI_MAX_PROCESS_TIME (default value: 300 seconds) In Self Managed Mode, LSAPI_MAX_PROCESS_TIME controls the maximum processing time allowed when processing a request. If a child process can not finish processing of a request in the given time period, it will be killed by the parent process. This option can help getting rid of dead or runaway child process. * LSAPI_PGRP_MAX_IDLE (default value: FOREVER ) In Self Managed Mode, LSAPI_PGRP_MAX_IDLE controls how long the parent process will wait before exiting when there is no child process. This option help releasing system resources taken by an idle parent process. * LSAPI_PPID_NO_CHECK By default a LSAPI application check the existence of its parent process and exits automatically if the parent process died. This is to reduce orphan process when web server is restarted. However, it is desireable to disable this feature, such as when a LSAPI process was started manually from command line. LSAPI_PPID_NO_CHECK should be set when you want to disable the checking of existence of parent process. License ------- LSAPI library code is under BSD license LSAPI ruby extension code is under Ruby license * (()) (Japanese) * (()) (English) Copyright --------- Copyright (C) 2006 Lite Speed Technologies Inc. PKu]j2#ruby-lsapi-5.5/rails/dispatch.lsapinuȯ#!/opt/alt/ruby27/bin/ruby if GC.respond_to?(:copy_on_write_friendly=) GC.copy_on_write_friendly = true end require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) # If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: # "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired require "dispatcher" require "lsapi" while LSAPI.accept != nil Dispatcher.dispatch end PKu]MM'ruby-lsapi-5.5/scripts/lsruby_runner.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' class CodeCache def [](filename) mtime = File.mtime( filename ) entry = @cache[filename]; if entry != nil return entry end code = compile(filename) #entry = CodeEntry.new( filename, mtime, code ) @cache[filename] = code return code end private def initialize @cache = {} end def compile(filename) open(filename) do |f| s = f.read s.untaint binding = eval_string_wrap("binding") return eval(format("Proc.new {\n%s\n}", s), binding, filename, 0) end end end $count = 0; $cache = CodeCache.new while true $req = LSAPI.accept break if $req == nil filename = ENV['SCRIPT_FILENAME'] filename.untaint filename =~ %r{^(\/.*?)\/*([^\/]+)$} path = $1 Dir.chdir( path ) #load( filename, true ) code = $cache[filename] code.call end class CodeEntry public :path, :name, :mtime, :opcode def initizlize( filename, mtime, opcode ) filename =~ %r{^(\/.*?)\/*([^\/]+)$} @path = $1 @name = $2 @mtime = mtime @opcode = opcode end end PKu]##BBruby-lsapi-5.5/setup.rbnu[# # setup.rb # # Copyright (c) 2000-2005 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU LGPL, Lesser General Public License version 2.1. # unless Enumerable.method_defined?(:map) # Ruby 1.4.6 module Enumerable alias map collect end end unless File.respond_to?(:read) # Ruby 1.6 def File.read(fname) open(fname) {|f| return f.read } end end unless Errno.const_defined?(:ENOTEMPTY) # Windows? module Errno class ENOTEMPTY # We do not raise this exception, implementation is not needed. end end end def File.binread(fname) open(fname, 'rb') {|f| return f.read } end # for corrupted Windows' stat(2) def File.dir?(path) File.directory?((path[-1,1] == '/') ? path : path + '/') end class ConfigTable include Enumerable def initialize(rbconfig) @rbconfig = rbconfig @items = [] @table = {} # options @install_prefix = nil @config_opt = nil @verbose = true @no_harm = false end attr_accessor :install_prefix attr_accessor :config_opt attr_writer :verbose def verbose? @verbose end attr_writer :no_harm def no_harm? @no_harm end def [](key) lookup(key).resolve(self) end def []=(key, val) lookup(key).set val end def names @items.map {|i| i.name } end def each(&block) @items.each(&block) end def key?(name) @table.key?(name) end def lookup(name) @table[name] or setup_rb_error "no such config item: #{name}" end def add(item) @items.push item @table[item.name] = item end def remove(name) item = lookup(name) @items.delete_if {|i| i.name == name } @table.delete_if {|name, i| i.name == name } item end def load_script(path, inst = nil) if File.file?(path) MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path end end def savefile '.config' end def load_savefile begin File.foreach(savefile()) do |line| k, v = *line.split(/=/, 2) self[k] = v.strip end rescue Errno::ENOENT setup_rb_error $!.message + "\n#{File.basename($0)} config first" end end def save @items.each {|i| i.value } File.open(savefile(), 'w') {|f| @items.each do |i| f.printf "%s=%s\n", i.name, i.value if i.value? and i.value end } end def load_standard_entries standard_entries(@rbconfig).each do |ent| add ent end end def standard_entries(rbconfig) c = rbconfig rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) major = c['MAJOR'].to_i minor = c['MINOR'].to_i teeny = c['TEENY'].to_i version = "#{major}.#{minor}" # ruby ver. >= 1.4.4? newpath_p = ((major >= 2) or ((major == 1) and ((minor >= 5) or ((minor == 4) and (teeny >= 4))))) if c['rubylibdir'] # V > 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = c['rubylibdir'] librubyverarch = c['archdir'] siteruby = c['sitedir'] siterubyver = c['sitelibdir'] siterubyverarch = c['sitearchdir'] elsif newpath_p # 1.4.4 <= V <= 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = c['sitedir'] siterubyver = "$siteruby/#{version}" siterubyverarch = "$siterubyver/#{c['arch']}" else # V < 1.4.4 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" siterubyver = siteruby siterubyverarch = "$siterubyver/#{c['arch']}" end parameterize = lambda {|path| path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') } if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } makeprog = arg.sub(/'/, '').split(/=/, 2)[1] else makeprog = 'make' end [ ExecItem.new('installdirs', 'std/site/home', 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ {|val, table| case val when 'std' table['rbdir'] = '$librubyver' table['sodir'] = '$librubyverarch' when 'site' table['rbdir'] = '$siterubyver' table['sodir'] = '$siterubyverarch' when 'home' setup_rb_error '$HOME was not set' unless ENV['HOME'] table['prefix'] = ENV['HOME'] table['rbdir'] = '$libdir/ruby' table['sodir'] = '$libdir/ruby' end }, PathItem.new('prefix', 'path', c['prefix'], 'path prefix of target environment'), PathItem.new('bindir', 'path', parameterize.call(c['bindir']), 'the directory for commands'), PathItem.new('libdir', 'path', parameterize.call(c['libdir']), 'the directory for libraries'), PathItem.new('datadir', 'path', parameterize.call(c['datadir']), 'the directory for shared data'), PathItem.new('mandir', 'path', parameterize.call(c['mandir']), 'the directory for man pages'), PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), 'the directory for system configuration files'), PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), 'the directory for local state data'), PathItem.new('libruby', 'path', libruby, 'the directory for ruby libraries'), PathItem.new('librubyver', 'path', librubyver, 'the directory for standard ruby libraries'), PathItem.new('librubyverarch', 'path', librubyverarch, 'the directory for standard ruby extensions'), PathItem.new('siteruby', 'path', siteruby, 'the directory for version-independent aux ruby libraries'), PathItem.new('siterubyver', 'path', siterubyver, 'the directory for aux ruby libraries'), PathItem.new('siterubyverarch', 'path', siterubyverarch, 'the directory for aux ruby binaries'), PathItem.new('rbdir', 'path', '$siterubyver', 'the directory for ruby scripts'), PathItem.new('sodir', 'path', '$siterubyverarch', 'the directory for ruby extentions'), PathItem.new('rubypath', 'path', rubypath, 'the path to set to #! line'), ProgramItem.new('rubyprog', 'name', rubypath, 'the ruby program using for installation'), ProgramItem.new('makeprog', 'name', makeprog, 'the make program to compile ruby extentions'), SelectItem.new('shebang', 'all/ruby/never', 'ruby', 'shebang line (#!) editing mode'), BoolItem.new('without-ext', 'yes/no', 'no', 'does not compile/install ruby extentions') ] end private :standard_entries def load_multipackage_entries multipackage_entries().each do |ent| add ent end end def multipackage_entries [ PackageSelectionItem.new('with', 'name,name...', '', 'ALL', 'package names that you want to install'), PackageSelectionItem.new('without', 'name,name...', '', 'NONE', 'package names that you do not want to install') ] end private :multipackage_entries ALIASES = { 'std-ruby' => 'librubyver', 'stdruby' => 'librubyver', 'rubylibdir' => 'librubyver', 'archdir' => 'librubyverarch', 'site-ruby-common' => 'siteruby', # For backward compatibility 'site-ruby' => 'siterubyver', # For backward compatibility 'bin-dir' => 'bindir', 'bin-dir' => 'bindir', 'rb-dir' => 'rbdir', 'so-dir' => 'sodir', 'data-dir' => 'datadir', 'ruby-path' => 'rubypath', 'ruby-prog' => 'rubyprog', 'ruby' => 'rubyprog', 'make-prog' => 'makeprog', 'make' => 'makeprog' } def fixup ALIASES.each do |ali, name| @table[ali] = @table[name] end @items.freeze @table.freeze @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ end def parse_opt(opt) m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" m.to_a[1,2] end def dllext @rbconfig['DLEXT'] end def value_config?(name) lookup(name).value? end class Item def initialize(name, template, default, desc) @name = name.freeze @template = template @value = default @default = default @description = desc end attr_reader :name attr_reader :description attr_accessor :default alias help_default default def help_opt "--#{@name}=#{@template}" end def value? true end def value @value end def resolve(table) @value.gsub(%r<\$([^/]+)>) { table[$1] } end def set(val) @value = check(val) end private def check(val) setup_rb_error "config: --#{name} requires argument" unless val val end end class BoolItem < Item def config_type 'bool' end def help_opt "--#{@name}" end private def check(val) return 'yes' unless val case val when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' else setup_rb_error "config: --#{@name} accepts only yes/no for argument" end end end class PathItem < Item def config_type 'path' end private def check(path) setup_rb_error "config: --#{@name} requires argument" unless path path[0,1] == '$' ? path : File.expand_path(path) end end class ProgramItem < Item def config_type 'program' end end class SelectItem < Item def initialize(name, selection, default, desc) super @ok = selection.split('/') end def config_type 'select' end private def check(val) unless @ok.include?(val.strip) setup_rb_error "config: use --#{@name}=#{@template} (#{val})" end val.strip end end class ExecItem < Item def initialize(name, selection, desc, &block) super name, selection, nil, desc @ok = selection.split('/') @action = block end def config_type 'exec' end def value? false end def resolve(table) setup_rb_error "$#{name()} wrongly used as option value" end undef set def evaluate(val, table) v = val.strip.downcase unless @ok.include?(v) setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" end @action.call v, table end end class PackageSelectionItem < Item def initialize(name, template, default, help_default, desc) super name, template, default, desc @help_default = help_default end attr_reader :help_default def config_type 'package' end private def check(val) unless File.dir?("packages/#{val}") setup_rb_error "config: no such package: #{val}" end val end end class MetaConfigEnvironment def initialize(config, installer) @config = config @installer = installer end def config_names @config.names end def config?(name) @config.key?(name) end def bool_config?(name) @config.lookup(name).config_type == 'bool' end def path_config?(name) @config.lookup(name).config_type == 'path' end def value_config?(name) @config.lookup(name).config_type != 'exec' end def add_config(item) @config.add item end def add_bool_config(name, default, desc) @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) end def add_path_config(name, default, desc) @config.add PathItem.new(name, 'path', default, desc) end def set_config_default(name, default) @config.lookup(name).default = default end def remove_config(name) @config.remove(name) end # For only multipackage def packages raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer @installer.packages end # For only multipackage def declare_packages(list) raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer @installer.packages = list end end end # class ConfigTable # This module requires: #verbose?, #no_harm? module FileOperations def mkdir_p(dirname, prefix = nil) dirname = prefix + File.expand_path(dirname) if prefix $stderr.puts "mkdir -p #{dirname}" if verbose? return if no_harm? # Does not check '/', it's too abnormal. dirs = File.expand_path(dirname).split(%r<(?=/)>) if /\A[a-z]:\z/i =~ dirs[0] disk = dirs.shift dirs[0] = disk + dirs[0] end dirs.each_index do |idx| path = dirs[0..idx].join('') Dir.mkdir path unless File.dir?(path) end end def rm_f(path) $stderr.puts "rm -f #{path}" if verbose? return if no_harm? force_remove_file path end def rm_rf(path) $stderr.puts "rm -rf #{path}" if verbose? return if no_harm? remove_tree path end def remove_tree(path) if File.symlink?(path) remove_file path elsif File.dir?(path) remove_tree0 path else force_remove_file path end end def remove_tree0(path) Dir.foreach(path) do |ent| next if ent == '.' next if ent == '..' entpath = "#{path}/#{ent}" if File.symlink?(entpath) remove_file entpath elsif File.dir?(entpath) remove_tree0 entpath else force_remove_file entpath end end begin Dir.rmdir path rescue Errno::ENOTEMPTY # directory may not be empty end end def move_file(src, dest) force_remove_file dest begin File.rename src, dest rescue File.open(dest, 'wb') {|f| f.write File.binread(src) } File.chmod File.stat(src).mode, dest File.unlink src end end def force_remove_file(path) begin remove_file path rescue end end def remove_file(path) File.chmod 0777, path File.unlink path end def install(from, dest, mode, prefix = nil) $stderr.puts "install #{from} #{dest}" if verbose? return if no_harm? realdest = prefix ? prefix + File.expand_path(dest) : dest realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) str = File.binread(from) if diff?(str, realdest) verbose_off { rm_f realdest if File.exist?(realdest) } File.open(realdest, 'wb') {|f| f.write str } File.chmod mode, realdest File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| if prefix f.puts realdest.sub(prefix, '') else f.puts realdest end } end end def diff?(new_content, path) return true unless File.exist?(path) new_content != File.binread(path) end def command(*args) $stderr.puts args.join(' ') if verbose? system(*args) or raise RuntimeError, "system(#{args.map{|a| a.inspect }.join(' ')}) failed" end def ruby(*args) command config('rubyprog'), *args end def make(task = nil) command(*[config('makeprog'), task].compact) end def extdir?(dir) File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") end def files_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.file?("#{dir}/#{ent}") } } end DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) def directories_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT } end end # This module requires: #srcdir_root, #objdir_root, #relpath module HookScriptAPI def get_config(key) @config[key] end alias config get_config # obsolete: use metaconfig to change configuration def set_config(key, val) @config[key] = val end # # srcdir/objdir (works only in the package directory) # def curr_srcdir "#{srcdir_root()}/#{relpath()}" end def curr_objdir "#{objdir_root()}/#{relpath()}" end def srcfile(path) "#{curr_srcdir()}/#{path}" end def srcexist?(path) File.exist?(srcfile(path)) end def srcdirectory?(path) File.dir?(srcfile(path)) end def srcfile?(path) File.file?(srcfile(path)) end def srcentries(path = '.') Dir.open("#{curr_srcdir()}/#{path}") {|d| return d.to_a - %w(. ..) } end def srcfiles(path = '.') srcentries(path).select {|fname| File.file?(File.join(curr_srcdir(), path, fname)) } end def srcdirectories(path = '.') srcentries(path).select {|fname| File.dir?(File.join(curr_srcdir(), path, fname)) } end end class ToplevelInstaller Version = '3.4.1' Copyright = 'Copyright (c) 2000-2005 Minero Aoki' TASKS = [ [ 'all', 'do config, setup, then install' ], [ 'config', 'saves your configurations' ], [ 'show', 'shows current configuration' ], [ 'setup', 'compiles ruby extentions and others' ], [ 'install', 'installs files' ], [ 'test', 'run all tests in test/' ], [ 'clean', "does `make clean' for each extention" ], [ 'distclean',"does `make distclean' for each extention" ] ] def ToplevelInstaller.invoke config = ConfigTable.new(load_rbconfig()) config.load_standard_entries config.load_multipackage_entries if multipackage? config.fixup klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) klass.new(File.dirname($0), config).invoke end def ToplevelInstaller.multipackage? File.dir?(File.dirname($0) + '/packages') end def ToplevelInstaller.load_rbconfig if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } ARGV.delete(arg) load File.expand_path(arg.split(/=/, 2)[1]) $".push 'rbconfig.rb' else require 'rbconfig' end ::Config::CONFIG end def initialize(ardir_root, config) @ardir = File.expand_path(ardir_root) @config = config # cache @valid_task_re = nil end def config(key) @config[key] end def inspect "#<#{self.class} #{__id__()}>" end def invoke run_metaconfigs case task = parsearg_global() when nil, 'all' parsearg_config init_installers exec_config exec_setup exec_install else case task when 'config', 'test' ; when 'clean', 'distclean' @config.load_savefile if File.exist?(@config.savefile) else @config.load_savefile end __send__ "parsearg_#{task}" init_installers __send__ "exec_#{task}" end end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig" end def init_installers @installer = Installer.new(@config, @ardir, File.expand_path('.')) end # # Hook Script API bases # def srcdir_root @ardir end def objdir_root '.' end def relpath '.' end # # Option Parsing # def parsearg_global while arg = ARGV.shift case arg when /\A\w+\z/ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) return arg when '-q', '--quiet' @config.verbose = false when '--verbose' @config.verbose = true when '--help' print_usage $stdout exit 0 when '--version' puts "#{File.basename($0)} version #{Version}" exit 0 when '--copyright' puts Copyright exit 0 else setup_rb_error "unknown global option '#{arg}'" end end nil end def valid_task?(t) valid_task_re() =~ t end def valid_task_re @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ end def parsearg_no_options unless ARGV.empty? task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" end end alias parsearg_show parsearg_no_options alias parsearg_setup parsearg_no_options alias parsearg_test parsearg_no_options alias parsearg_clean parsearg_no_options alias parsearg_distclean parsearg_no_options def parsearg_config evalopt = [] set = [] @config.config_opt = [] while i = ARGV.shift if /\A--?\z/ =~ i @config.config_opt = ARGV.dup break end name, value = *@config.parse_opt(i) if @config.value_config?(name) @config[name] = value else evalopt.push [name, value] end set.push name end evalopt.each do |name, value| @config.lookup(name).evaluate value, @config end # Check if configuration is valid set.each do |n| @config[n] if @config.value_config?(n) end end def parsearg_install @config.no_harm = false @config.install_prefix = '' while a = ARGV.shift case a when '--no-harm' @config.no_harm = true when /\A--prefix=/ path = a.split(/=/, 2)[1] path = File.expand_path(path) unless path[0,1] == '/' @config.install_prefix = path else setup_rb_error "install: unknown option #{a}" end end end def print_usage(out) out.puts 'Typical Installation Procedure:' out.puts " $ ruby #{File.basename $0} config" out.puts " $ ruby #{File.basename $0} setup" out.puts " # ruby #{File.basename $0} install (may require root privilege)" out.puts out.puts 'Detailed Usage:' out.puts " ruby #{File.basename $0} " out.puts " ruby #{File.basename $0} [] []" fmt = " %-24s %s\n" out.puts out.puts 'Global options:' out.printf fmt, '-q,--quiet', 'suppress message outputs' out.printf fmt, ' --verbose', 'output messages verbosely' out.printf fmt, ' --help', 'print this message' out.printf fmt, ' --version', 'print version and quit' out.printf fmt, ' --copyright', 'print copyright and quit' out.puts out.puts 'Tasks:' TASKS.each do |name, desc| out.printf fmt, name, desc end fmt = " %-24s %s [%s]\n" out.puts out.puts 'Options for CONFIG or ALL:' @config.each do |item| out.printf fmt, item.help_opt, item.description, item.help_default end out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" out.puts out.puts 'Options for INSTALL:' out.printf fmt, '--no-harm', 'only display what to do if given', 'off' out.printf fmt, '--prefix=path', 'install path prefix', '' out.puts end # # Task Handlers # def exec_config @installer.exec_config @config.save # must be final end def exec_setup @installer.exec_setup end def exec_install @installer.exec_install end def exec_test @installer.exec_test end def exec_show @config.each do |i| printf "%-20s %s\n", i.name, i.value if i.value? end end def exec_clean @installer.exec_clean end def exec_distclean @installer.exec_distclean end end # class ToplevelInstaller class ToplevelInstallerMulti < ToplevelInstaller include FileOperations def initialize(ardir_root, config) super @packages = directories_of("#{@ardir}/packages") raise 'no package exists' if @packages.empty? @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig", self @packages.each do |name| @config.load_script "#{@ardir}/packages/#{name}/metaconfig" end end attr_reader :packages def packages=(list) raise 'package list is empty' if list.empty? list.each do |name| raise "directory packages/#{name} does not exist"\ unless File.dir?("#{@ardir}/packages/#{name}") end @packages = list end def init_installers @installers = {} @packages.each do |pack| @installers[pack] = Installer.new(@config, "#{@ardir}/packages/#{pack}", "packages/#{pack}") end with = extract_selection(config('with')) without = extract_selection(config('without')) @selected = @installers.keys.select {|name| (with.empty? or with.include?(name)) \ and not without.include?(name) } end def extract_selection(list) a = list.split(/,/) a.each do |name| setup_rb_error "no such package: #{name}" unless @installers.key?(name) end a end def print_usage(f) super f.puts 'Inluded packages:' f.puts ' ' + @packages.sort.join(' ') f.puts end # # Task Handlers # def exec_config run_hook 'pre-config' each_selected_installers {|inst| inst.exec_config } run_hook 'post-config' @config.save # must be final end def exec_setup run_hook 'pre-setup' each_selected_installers {|inst| inst.exec_setup } run_hook 'post-setup' end def exec_install run_hook 'pre-install' each_selected_installers {|inst| inst.exec_install } run_hook 'post-install' end def exec_test run_hook 'pre-test' each_selected_installers {|inst| inst.exec_test } run_hook 'post-test' end def exec_clean rm_f @config.savefile run_hook 'pre-clean' each_selected_installers {|inst| inst.exec_clean } run_hook 'post-clean' end def exec_distclean rm_f @config.savefile run_hook 'pre-distclean' each_selected_installers {|inst| inst.exec_distclean } run_hook 'post-distclean' end # # lib # def each_selected_installers Dir.mkdir 'packages' unless File.dir?('packages') @selected.each do |pack| $stderr.puts "Processing the package `#{pack}' ..." if verbose? Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") Dir.chdir "packages/#{pack}" yield @installers[pack] Dir.chdir '../..' end end def run_hook(id) @root_installer.run_hook id end # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end end # class ToplevelInstallerMulti class Installer FILETYPES = %w( bin lib ext data conf man ) include FileOperations include HookScriptAPI def initialize(config, srcroot, objroot) @config = config @srcdir = File.expand_path(srcroot) @objdir = File.expand_path(objroot) @currdir = '.' end def inspect "#<#{self.class} #{File.basename(@srcdir)}>" end def noop(rel) end # # Hook Script API base methods # def srcdir_root @srcdir end def objdir_root @objdir end def relpath @currdir end # # Config Access # # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end def verbose_off begin save, @config.verbose = @config.verbose?, false yield ensure @config.verbose = save end end # # TASK config # def exec_config exec_task_traverse 'config' end alias config_dir_bin noop alias config_dir_lib noop def config_dir_ext(rel) extconf if extdir?(curr_srcdir()) end alias config_dir_data noop alias config_dir_conf noop alias config_dir_man noop def extconf ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt end # # TASK setup # def exec_setup exec_task_traverse 'setup' end def setup_dir_bin(rel) files_of(curr_srcdir()).each do |fname| update_shebang_line "#{curr_srcdir()}/#{fname}" end end alias setup_dir_lib noop def setup_dir_ext(rel) make if extdir?(curr_srcdir()) end alias setup_dir_data noop alias setup_dir_conf noop alias setup_dir_man noop def update_shebang_line(path) return if no_harm? return if config('shebang') == 'never' old = Shebang.load(path) if old $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 new = new_shebang(old) return if new.to_s == old.to_s else return unless config('shebang') == 'all' new = Shebang.new(config('rubypath')) end $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? open_atomic_writer(path) {|output| File.open(path, 'rb') {|f| f.gets if old # discard output.puts new.to_s output.print f.read } } end def new_shebang(old) if /\Aruby/ =~ File.basename(old.cmd) Shebang.new(config('rubypath'), old.args) elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' Shebang.new(config('rubypath'), old.args[1..-1]) else return old unless config('shebang') == 'all' Shebang.new(config('rubypath')) end end def open_atomic_writer(path, &block) tmpfile = File.basename(path) + '.tmp' begin File.open(tmpfile, 'wb', &block) File.rename tmpfile, File.basename(path) ensure File.unlink tmpfile if File.exist?(tmpfile) end end class Shebang def Shebang.load(path) line = nil File.open(path) {|f| line = f.gets } return nil unless /\A#!/ =~ line parse(line) end def Shebang.parse(line) cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') new(cmd, args) end def initialize(cmd, args = []) @cmd = cmd @args = args end attr_reader :cmd attr_reader :args def to_s "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") end end # # TASK install # def exec_install rm_f 'InstalledFiles' exec_task_traverse 'install' end def install_dir_bin(rel) install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 end def install_dir_lib(rel) install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 end def install_dir_ext(rel) return unless extdir?(curr_srcdir()) install_files rubyextentions('.'), "#{config('sodir')}/#{File.dirname(rel)}", 0555 end def install_dir_data(rel) install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 end def install_dir_conf(rel) # FIXME: should not remove current config files # (rename previous file to .old/.org) install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 end def install_dir_man(rel) install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 end def install_files(list, dest, mode) mkdir_p dest, @config.install_prefix list.each do |fname| install fname, dest, mode, @config.install_prefix end end def libfiles glob_reject(%w(*.y *.output), targetfiles()) end def rubyextentions(dir) ents = glob_select("*.#{@config.dllext}", targetfiles()) if ents.empty? setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" end ents end def targetfiles mapdir(existfiles() - hookfiles()) end def mapdir(ents) ents.map {|ent| if File.exist?(ent) then ent # objdir else "#{curr_srcdir()}/#{ent}" # srcdir end } end # picked up many entries from cvs-1.11.1/src/ignore.c JUNK_FILES = %w( core RCSLOG tags TAGS .make.state .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$ *.org *.in .* ) def existfiles glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) end def hookfiles %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| %w( config setup install clean ).map {|t| sprintf(fmt, t) } }.flatten end def glob_select(pat, ents) re = globs2re([pat]) ents.select {|ent| re =~ ent } end def glob_reject(pats, ents) re = globs2re(pats) ents.reject {|ent| re =~ ent } end GLOB2REGEX = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' } def globs2re(pats) /\A(?:#{ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') })\z/ end # # TASK test # TESTDIR = 'test' def exec_test unless File.directory?('test') $stderr.puts 'no test in this package' if verbose? return end $stderr.puts 'Running tests...' if verbose? begin require 'test/unit' rescue LoadError setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' end runner = Test::Unit::AutoRunner.new(true) runner.to_run << TESTDIR runner.run end # # TASK clean # def exec_clean exec_task_traverse 'clean' rm_f @config.savefile rm_f 'InstalledFiles' end alias clean_dir_bin noop alias clean_dir_lib noop alias clean_dir_data noop alias clean_dir_conf noop alias clean_dir_man noop def clean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'clean' if File.file?('Makefile') end # # TASK distclean # def exec_distclean exec_task_traverse 'distclean' rm_f @config.savefile rm_f 'InstalledFiles' end alias distclean_dir_bin noop alias distclean_dir_lib noop def distclean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'distclean' if File.file?('Makefile') end alias distclean_dir_data noop alias distclean_dir_conf noop alias distclean_dir_man noop # # Traversing # def exec_task_traverse(task) run_hook "pre-#{task}" FILETYPES.each do |type| if type == 'ext' and config('without-ext') == 'yes' $stderr.puts 'skipping ext/* by user option' if verbose? next end traverse task, type, "#{task}_dir_#{type}" end run_hook "post-#{task}" end def traverse(task, rel, mid) dive_into(rel) { run_hook "pre-#{task}" __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') directories_of(curr_srcdir()).each do |d| traverse task, "#{rel}/#{d}", mid end run_hook "post-#{task}" } end def dive_into(rel) return unless File.dir?("#{@srcdir}/#{rel}") dir = File.basename(rel) Dir.mkdir dir unless File.dir?(dir) prevdir = Dir.pwd Dir.chdir dir $stderr.puts '---> ' + rel if verbose? @currdir = rel yield Dir.chdir prevdir $stderr.puts '<--- ' + rel if verbose? @currdir = File.dirname(rel) end def run_hook(id) path = [ "#{curr_srcdir()}/#{id}", "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } return unless path begin instance_eval File.read(path), path, 1 rescue raise if $DEBUG setup_rb_error "hook #{path} failed:\n" + $!.message end end end # class Installer class SetupError < StandardError; end def setup_rb_error(msg) raise SetupError, msg end if $0 == __FILE__ begin ToplevelInstaller.invoke rescue SetupError raise if $DEBUG $stderr.puts $!.message $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." exit 1 end end PKu]*  $ruby-lsapi-5.5/examples/testlsapi.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' $count = 0; while LSAPI.accept != nil print "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\nHello World! \##{$count}
    \r\n" ENV.each_pair {|key, value| print "#{key} is #{value}
    \r\n" } $count = $count + 1 end PKu])ruby-lsapi-5.5/examples/lsapi_with_cgi.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' require 'cgi' while LSAPI.accept != nil cgi = CGI.new name = cgi['name'] puts cgi.header puts "Hello #{name}!
    " if name puts "You are from #{cgi.remote_addr}
    " end PKu]minitest-5.13.0/Manifest.txtnu[.autotest History.rdoc Manifest.txt README.rdoc Rakefile design_rationale.rb lib/hoe/minitest.rb lib/minitest.rb lib/minitest/assertions.rb lib/minitest/autorun.rb lib/minitest/benchmark.rb lib/minitest/expectations.rb lib/minitest/hell.rb lib/minitest/mock.rb lib/minitest/parallel.rb lib/minitest/pride.rb lib/minitest/pride_plugin.rb lib/minitest/spec.rb lib/minitest/test.rb lib/minitest/unit.rb test/minitest/metametameta.rb test/minitest/test_minitest_assertions.rb test/minitest/test_minitest_benchmark.rb test/minitest/test_minitest_mock.rb test/minitest/test_minitest_reporter.rb test/minitest/test_minitest_spec.rb test/minitest/test_minitest_test.rb PKu]S`minitest-5.13.0/Rakefilenu[# -*- ruby -*- require "rubygems" require "hoe" Hoe.plugin :seattlerb Hoe.plugin :rdoc Hoe.spec "minitest" do developer "Ryan Davis", "ryand-ruby@zenspider.com" license "MIT" require_ruby_version "~> 2.2" end desc "Find missing expectations" task :specs do $:.unshift "lib" require "minitest/test" require "minitest/spec" pos_prefix, neg_prefix = "must", "wont" skip_re = /^(must|wont)$|wont_(throw)|must_(block|not?_|nothing|raise$)/x dont_flip_re = /(must|wont)_(include|respond_to)/ map = { /(must_throw)s/ => '\1', /(?!not)_same/ => "_be_same_as", /_in_/ => "_be_within_", /_operator/ => "_be", /_includes/ => "_include", /(must|wont)_(.*_of|nil|silent|empty)/ => '\1_be_\2', /must_raises/ => "must_raise", } expectations = Minitest::Expectations.public_instance_methods.map(&:to_s) assertions = Minitest::Assertions.public_instance_methods.map(&:to_s) assertions.sort.each do |assertion| expectation = case assertion when /^assert/ then assertion.sub(/^assert/, pos_prefix.to_s) when /^refute/ then assertion.sub(/^refute/, neg_prefix.to_s) end next unless expectation next if expectation =~ skip_re regexp, replacement = map.find { |re, _| expectation =~ re } expectation.sub! regexp, replacement if replacement next if expectations.include? expectation args = [assertion, expectation].map(&:to_sym).map(&:inspect) args << :reverse if expectation =~ dont_flip_re puts puts "##" puts "# :method: #{expectation}" puts "# See Minitest::Assertions##{assertion}" puts puts "infect_an_assertion #{args.join ", "}" end end task :bugs do sh "for f in bug*.rb ; do echo $f; echo; #{Gem.ruby} -Ilib $f && rm $f ; done" end # vim: syntax=Ruby PKu]9(  8minitest-5.13.0/test/minitest/test_minitest_benchmark.rbnu[require "minitest/autorun" require "minitest/benchmark" ## # Used to verify data: # http://www.wolframalpha.com/examples/RegressionAnalysis.html class TestMinitestBenchmark < Minitest::Test def test_cls_bench_exp assert_equal [2, 4, 8, 16, 32], Minitest::Benchmark.bench_exp(2, 32, 2) end def test_cls_bench_linear assert_equal [2, 4, 6, 8, 10], Minitest::Benchmark.bench_linear(2, 10, 2) end def test_cls_runnable_methods assert_equal [], Minitest::Benchmark.runnable_methods c = Class.new(Minitest::Benchmark) do def bench_blah end end assert_equal ["bench_blah"], c.runnable_methods end def test_cls_bench_range assert_equal [1, 10, 100, 1_000, 10_000], Minitest::Benchmark.bench_range end def test_fit_exponential_clean x = [1.0, 2.0, 3.0, 4.0, 5.0] y = x.map { |n| 1.1 * Math.exp(2.1 * n) } assert_fit :exponential, x, y, 1.0, 1.1, 2.1 end def test_fit_exponential_noisy x = [1.0, 1.9, 2.6, 3.4, 5.0] y = [12, 10, 8.2, 6.9, 5.9] # verified with Numbers and R assert_fit :exponential, x, y, 0.95, 13.81148, -0.1820 end def test_fit_logarithmic_clean x = [1.0, 2.0, 3.0, 4.0, 5.0] y = x.map { |n| 1.1 + 2.1 * Math.log(n) } assert_fit :logarithmic, x, y, 1.0, 1.1, 2.1 end def test_fit_logarithmic_noisy x = [1.0, 2.0, 3.0, 4.0, 5.0] # Generated with # y = x.map { |n| jitter = 0.999 + 0.002 * rand; (Math.log(n) ) * jitter } y = [0.0, 0.6935, 1.0995, 1.3873, 1.6097] assert_fit :logarithmic, x, y, 0.95, 0, 1 end def test_fit_constant_clean x = (1..5).to_a y = [5.0, 5.0, 5.0, 5.0, 5.0] assert_fit :linear, x, y, nil, 5.0, 0 end def test_fit_constant_noisy x = (1..5).to_a y = [1.0, 1.2, 1.0, 0.8, 1.0] # verified in numbers and R assert_fit :linear, x, y, nil, 1.12, -0.04 end def test_fit_linear_clean # y = m * x + b where m = 2.2, b = 3.1 x = (1..5).to_a y = x.map { |n| 2.2 * n + 3.1 } assert_fit :linear, x, y, 1.0, 3.1, 2.2 end def test_fit_linear_noisy x = [ 60, 61, 62, 63, 65] y = [3.1, 3.6, 3.8, 4.0, 4.1] # verified in numbers and R assert_fit :linear, x, y, 0.8315, -7.9635, 0.1878 end def test_fit_power_clean # y = A x ** B, where B = b and A = e ** a # if, A = 1, B = 2, then x = [1.0, 2.0, 3.0, 4.0, 5.0] y = [1.0, 4.0, 9.0, 16.0, 25.0] assert_fit :power, x, y, 1.0, 1.0, 2.0 end def test_fit_power_noisy # from www.engr.uidaho.edu/thompson/courses/ME330/lecture/least_squares.html x = [10, 12, 15, 17, 20, 22, 25, 27, 30, 32, 35] y = [95, 105, 125, 141, 173, 200, 253, 298, 385, 459, 602] # verified in numbers assert_fit :power, x, y, 0.90, 2.6217, 1.4556 # income to % of households below income amount # http://library.wolfram.com/infocenter/Conferences/6461/PowerLaws.nb x = [15_000, 25_000, 35_000, 50_000, 75_000, 100_000] y = [0.154, 0.283, 0.402, 0.55, 0.733, 0.843] # verified in numbers assert_fit :power, x, y, 0.96, 3.119e-5, 0.8959 end def assert_fit msg, x, y, fit, exp_a, exp_b bench = Minitest::Benchmark.new :blah a, b, rr = bench.send "fit_#{msg}", x, y assert_operator rr, :>=, fit if fit assert_in_delta exp_a, a assert_in_delta exp_b, b end end describe "my class Bench" do klass = self it "should provide bench methods" do klass.must_respond_to :bench end end PKu]+ɃɃ9minitest-5.13.0/test/minitest/test_minitest_assertions.rbnu[# encoding: UTF-8 require "minitest/autorun" if defined? Encoding then e = Encoding.default_external if e != Encoding::UTF_8 then warn "" warn "" warn "NOTE: External encoding #{e} is not UTF-8. Tests WILL fail." warn " Run tests with `RUBYOPT=-Eutf-8 rake` to avoid errors." warn "" warn "" end end SomeError = Class.new Exception unless defined? MyModule then module MyModule; end class AnError < StandardError; include MyModule; end end class TestMinitestAssertions < Minitest::Test # do not call parallelize_me! - teardown accesses @tc._assertions # which is not threadsafe. Nearly every method in here is an # assertion test so it isn't worth splitting it out further. RUBY18 = !defined? Encoding class DummyTest include Minitest::Assertions # include Minitest::Reportable # TODO: why do I really need this? attr_accessor :assertions, :failure def initialize self.assertions = 0 self.failure = nil end end def setup super Minitest::Test.reset @tc = DummyTest.new @zomg = "zomg ponies!" # TODO: const @assertion_count = 1 end def teardown assert_equal(@assertion_count, @tc.assertions, "expected #{@assertion_count} assertions to be fired during the test, not #{@tc.assertions}") end def assert_deprecated name dep = /DEPRECATED: #{name}. From #{__FILE__}:\d+(?::.*)?/ dep = "" if $-w.nil? assert_output nil, dep do yield end end def assert_triggered expected, klass = Minitest::Assertion e = assert_raises klass do yield end msg = e.message.sub(/(---Backtrace---).*/m, '\1') msg.gsub!(/\(oid=[-0-9]+\)/, "(oid=N)") msg.gsub!(/(\d\.\d{6})\d+/, '\1xxx') # normalize: ruby version, impl, platform assert_msg = Regexp === expected ? :assert_match : :assert_equal self.send assert_msg, expected, msg end def clean s s.gsub(/^ {6,10}/, "") end def non_verbose orig_verbose = $VERBOSE $VERBOSE = false yield ensure $VERBOSE = orig_verbose end def test_assert @assertion_count = 2 @tc.assert_equal true, @tc.assert(true), "returns true on success" end def test_assert__triggered assert_triggered "Expected false to be truthy." do @tc.assert false end end def test_assert__triggered_message assert_triggered @zomg do @tc.assert false, @zomg end end def test_assert__triggered_lambda assert_triggered "whoops" do @tc.assert false, lambda { "whoops" } end end def test_assert_empty @assertion_count = 2 @tc.assert_empty [] end def test_assert_empty_triggered @assertion_count = 2 assert_triggered "Expected [1] to be empty." do @tc.assert_empty [1] end end def test_assert_equal @tc.assert_equal 1, 1 end def test_assert_equal_different_collection_array_hex_invisible object1 = Object.new object2 = Object.new msg = "No visible difference in the Array#inspect output. You should look at the implementation of #== on Array or its members. [#]".gsub(/^ +/, "") assert_triggered msg do @tc.assert_equal [object1], [object2] end end def test_assert_equal_different_collection_hash_hex_invisible h1, h2 = {}, {} h1[1] = Object.new h2[1] = Object.new msg = "No visible difference in the Hash#inspect output. You should look at the implementation of #== on Hash or its members. {1=>#}".gsub(/^ +/, "") assert_triggered msg do @tc.assert_equal h1, h2 end end def test_assert_equal_different_diff_deactivated without_diff do assert_triggered util_msg("haha" * 10, "blah" * 10) do o1 = "haha" * 10 o2 = "blah" * 10 @tc.assert_equal o1, o2 end end end def test_assert_equal_different_message assert_triggered "whoops.\nExpected: 1\n Actual: 2" do @tc.assert_equal 1, 2, message { "whoops" } end end def test_assert_equal_different_lambda assert_triggered "whoops.\nExpected: 1\n Actual: 2" do @tc.assert_equal 1, 2, lambda { "whoops" } end end def test_assert_equal_different_hex c = Class.new do def initialize s; @name = s; end end o1 = c.new "a" o2 = c.new "b" msg = clean <<-EOS --- expected +++ actual @@ -1 +1 @@ -#<#:0xXXXXXX @name=\"a\"> +#<#:0xXXXXXX @name=\"b\"> EOS assert_triggered msg do @tc.assert_equal o1, o2 end end def test_assert_equal_different_hex_invisible o1 = Object.new o2 = Object.new msg = "No visible difference in the Object#inspect output. You should look at the implementation of #== on Object or its members. #".gsub(/^ +/, "") assert_triggered msg do @tc.assert_equal o1, o2 end end def test_assert_equal_different_long msg = "--- expected +++ actual @@ -1 +1 @@ -\"hahahahahahahahahahahahahahahahahahahaha\" +\"blahblahblahblahblahblahblahblahblahblah\" ".gsub(/^ +/, "") assert_triggered msg do o1 = "haha" * 10 o2 = "blah" * 10 @tc.assert_equal o1, o2 end end def test_assert_equal_different_long_invisible msg = "No visible difference in the String#inspect output. You should look at the implementation of #== on String or its members. \"blahblahblahblahblahblahblahblahblahblah\"".gsub(/^ +/, "") assert_triggered msg do o1 = "blah" * 10 o2 = "blah" * 10 def o1.== _ false end @tc.assert_equal o1, o2 end end def test_assert_equal_different_long_msg msg = "message. --- expected +++ actual @@ -1 +1 @@ -\"hahahahahahahahahahahahahahahahahahahaha\" +\"blahblahblahblahblahblahblahblahblahblah\" ".gsub(/^ +/, "") assert_triggered msg do o1 = "haha" * 10 o2 = "blah" * 10 @tc.assert_equal o1, o2, "message" end end def test_assert_equal_different_short assert_triggered util_msg(1, 2) do @tc.assert_equal 1, 2 end end def test_assert_equal_different_short_msg assert_triggered util_msg(1, 2, "message") do @tc.assert_equal 1, 2, "message" end end def test_assert_equal_different_short_multiline msg = "--- expected\n+++ actual\n@@ -1,2 +1,2 @@\n \"a\n-b\"\n+c\"\n" assert_triggered msg do @tc.assert_equal "a\nb", "a\nc" end end def test_assert_equal_does_not_allow_lhs_nil if Minitest::VERSION =~ /^6/ then warn "Time to strip the MT5 test" @assertion_count += 1 assert_triggered(/Use assert_nil if expecting nil/) do @tc.assert_equal nil, nil end else err_re = /Use assert_nil if expecting nil from .*test_minitest_\w+.rb/ err_re = "" if $-w.nil? assert_output "", err_re do @tc.assert_equal nil, nil end end end def test_assert_equal_does_not_allow_lhs_nil_triggered assert_triggered "Expected: nil\n Actual: false" do @tc.assert_equal nil, false end end def test_assert_equal_string_bug791 exp = <<-'EOF'.gsub(/^ {10}/, "") # note single quotes --- expected +++ actual @@ -1,2 +1 @@ -"\\n -" +"\\\" EOF exp = "Expected: \"\\\\n\"\n Actual: \"\\\\\"" assert_triggered exp do @tc.assert_equal "\\n", "\\" end end def test_assert_equal_string_both_escaped_unescaped_newlines msg = <<-EOM.gsub(/^ {10}/, "") --- expected +++ actual @@ -1,2 +1 @@ -\"A\\n -B\" +\"A\\n\\\\nB\" EOM assert_triggered msg do exp = "A\\nB" act = "A\n\\nB" @tc.assert_equal exp, act end end def test_assert_equal_string_encodings msg = <<-EOM.gsub(/^ {10}/, "") --- expected +++ actual @@ -1,3 +1,3 @@ -# encoding: UTF-8 -# valid: false +# encoding: ASCII-8BIT +# valid: true "bad-utf8-\\xF1.txt" EOM assert_triggered msg do x = "bad-utf8-\xF1.txt" y = x.dup.force_encoding "binary" # TODO: switch to .b when 1.9 dropped @tc.assert_equal x, y end end unless RUBY18 def test_assert_equal_string_encodings_both_different msg = <<-EOM.gsub(/^ {10}/, "") --- expected +++ actual @@ -1,3 +1,3 @@ -# encoding: US-ASCII -# valid: false +# encoding: ASCII-8BIT +# valid: true "bad-utf8-\\xF1.txt" EOM assert_triggered msg do x = "bad-utf8-\xF1.txt".force_encoding "ASCII" y = x.dup.force_encoding "binary" # TODO: switch to .b when 1.9 dropped @tc.assert_equal x, y end end unless RUBY18 def test_assert_equal_unescape_newlines msg = <<-'EOM'.gsub(/^ {10}/, "") # NOTE single quotes on heredoc --- expected +++ actual @@ -1,2 +1,2 @@ -"hello +"hello\n world" EOM assert_triggered msg do exp = "hello\nworld" act = 'hello\nworld' # notice single quotes @tc.assert_equal exp, act end end def test_assert_in_delta @tc.assert_in_delta 0.0, 1.0 / 1000, 0.1 end def test_assert_in_delta_triggered x = "1.0e-06" assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}." do @tc.assert_in_delta 0.0, 1.0 / 1000, 0.000001 end end def test_assert_in_epsilon @assertion_count = 10 @tc.assert_in_epsilon 10_000, 9991 @tc.assert_in_epsilon 9991, 10_000 @tc.assert_in_epsilon 1.0, 1.001 @tc.assert_in_epsilon 1.001, 1.0 @tc.assert_in_epsilon 10_000, 9999.1, 0.0001 @tc.assert_in_epsilon 9999.1, 10_000, 0.0001 @tc.assert_in_epsilon 1.0, 1.0001, 0.0001 @tc.assert_in_epsilon 1.0001, 1.0, 0.0001 @tc.assert_in_epsilon(-1, -1) @tc.assert_in_epsilon(-10_000, -9991) end def test_assert_in_epsilon_triggered assert_triggered "Expected |10000 - 9990| (10) to be <= 9.99." do @tc.assert_in_epsilon 10_000, 9990 end end def test_assert_in_epsilon_triggered_negative_case x = (RUBY18 and not maglev?) ? "0.1" : "0.100000xxx" y = "0.1" assert_triggered "Expected |-1.1 - -1| (#{x}) to be <= #{y}." do @tc.assert_in_epsilon(-1.1, -1, 0.1) end end def test_assert_includes @assertion_count = 2 @tc.assert_includes [true], true end def test_assert_includes_triggered @assertion_count = 3 e = @tc.assert_raises Minitest::Assertion do @tc.assert_includes [true], false end expected = "Expected [true] to include false." assert_equal expected, e.message end def test_assert_instance_of @tc.assert_instance_of String, "blah" end def test_assert_instance_of_triggered assert_triggered 'Expected "blah" to be an instance of Array, not String.' do @tc.assert_instance_of Array, "blah" end end def test_assert_kind_of @tc.assert_kind_of String, "blah" end def test_assert_kind_of_triggered assert_triggered 'Expected "blah" to be a kind of Array, not String.' do @tc.assert_kind_of Array, "blah" end end def test_assert_match @assertion_count = 2 @tc.assert_match(/\w+/, "blah blah blah") end def test_assert_match_matchee_to_str @assertion_count = 2 obj = Object.new def obj.to_str; "blah" end @tc.assert_match "blah", obj end def test_assert_match_matcher_object @assertion_count = 2 pattern = Object.new def pattern.=~ _; true end @tc.assert_match pattern, 5 end def test_assert_match_object_triggered @assertion_count = 2 pattern = Object.new def pattern.=~ _; false end def pattern.inspect; "[Object]" end assert_triggered "Expected [Object] to match 5." do @tc.assert_match pattern, 5 end end def test_assert_match_triggered @assertion_count = 2 assert_triggered 'Expected /\d+/ to match "blah blah blah".' do @tc.assert_match(/\d+/, "blah blah blah") end end def test_assert_nil @tc.assert_nil nil end def test_assert_nil_triggered assert_triggered "Expected 42 to be nil." do @tc.assert_nil 42 end end def test_assert_operator @tc.assert_operator 2, :>, 1 end def test_assert_operator_bad_object bad = Object.new def bad.== _; true end @tc.assert_operator bad, :equal?, bad end def test_assert_operator_triggered assert_triggered "Expected 2 to be < 1." do @tc.assert_operator 2, :<, 1 end end def test_assert_output_both @assertion_count = 2 @tc.assert_output "yay", "blah" do print "yay" $stderr.print "blah" end end def test_assert_output_both_regexps @assertion_count = 4 @tc.assert_output(/y.y/, /bl.h/) do print "yay" $stderr.print "blah" end end def test_assert_output_err @tc.assert_output nil, "blah" do $stderr.print "blah" end end def test_assert_output_neither @assertion_count = 0 @tc.assert_output do # do nothing end end def test_assert_output_out @tc.assert_output "blah" do print "blah" end end def test_assert_output_triggered_both assert_triggered util_msg("blah", "blah blah", "In stderr") do @tc.assert_output "yay", "blah" do print "boo" $stderr.print "blah blah" end end end def test_assert_output_triggered_err assert_triggered util_msg("blah", "blah blah", "In stderr") do @tc.assert_output nil, "blah" do $stderr.print "blah blah" end end end def test_assert_output_triggered_out assert_triggered util_msg("blah", "blah blah", "In stdout") do @tc.assert_output "blah" do print "blah blah" end end end def test_assert_output_without_block assert_triggered "assert_output requires a block to capture output." do @tc.assert_output "blah" end end def test_assert_predicate @tc.assert_predicate "", :empty? end def test_assert_predicate_triggered assert_triggered 'Expected "blah" to be empty?.' do @tc.assert_predicate "blah", :empty? end end def test_assert_raises @tc.assert_raises RuntimeError do raise "blah" end end def test_assert_raises_default @tc.assert_raises do raise StandardError, "blah" end end def test_assert_raises_default_triggered e = assert_raises Minitest::Assertion do @tc.assert_raises do raise SomeError, "blah" end end expected = clean <<-EOM.chomp [StandardError] exception expected, not Class: Message: <\"blah\"> ---Backtrace--- FILE:LINE:in \`test_assert_raises_default_triggered\' --------------- EOM actual = e.message.gsub(/^.+:\d+/, "FILE:LINE") actual.gsub!(/block \(\d+ levels\) in /, "") if RUBY_VERSION >= "1.9.0" assert_equal expected, actual end def test_assert_raises_exit @tc.assert_raises SystemExit do exit 1 end end def test_assert_raises_module @tc.assert_raises MyModule do raise AnError end end def test_assert_raises_signals @tc.assert_raises SignalException do raise SignalException, :INT end end ## # *sigh* This is quite an odd scenario, but it is from real (albeit # ugly) test code in ruby-core: # http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=29259 def test_assert_raises_skip @assertion_count = 0 assert_triggered "skipped", Minitest::Skip do @tc.assert_raises ArgumentError do begin raise "blah" rescue skip "skipped" end end end end def test_assert_raises_subclass @tc.assert_raises StandardError do raise AnError end end def test_assert_raises_subclass_triggered e = assert_raises Minitest::Assertion do @tc.assert_raises SomeError do raise AnError, "some message" end end expected = clean <<-EOM [SomeError] exception expected, not Class: Message: <\"some message\"> ---Backtrace--- FILE:LINE:in \`test_assert_raises_subclass_triggered\' --------------- EOM actual = e.message.gsub(/^.+:\d+/, "FILE:LINE") actual.gsub!(/block \(\d+ levels\) in /, "") if RUBY_VERSION >= "1.9.0" assert_equal expected.chomp, actual end def test_assert_raises_triggered_different e = assert_raises Minitest::Assertion do @tc.assert_raises RuntimeError do raise SyntaxError, "icky" end end expected = clean <<-EOM.chomp [RuntimeError] exception expected, not Class: Message: <\"icky\"> ---Backtrace--- FILE:LINE:in \`test_assert_raises_triggered_different\' --------------- EOM actual = e.message.gsub(/^.+:\d+/, "FILE:LINE") actual.gsub!(/block \(\d+ levels\) in /, "") if RUBY_VERSION >= "1.9.0" assert_equal expected, actual end def test_assert_raises_triggered_different_msg e = assert_raises Minitest::Assertion do @tc.assert_raises RuntimeError, "XXX" do raise SyntaxError, "icky" end end expected = clean <<-EOM XXX. [RuntimeError] exception expected, not Class: Message: <\"icky\"> ---Backtrace--- FILE:LINE:in \`test_assert_raises_triggered_different_msg\' --------------- EOM actual = e.message.gsub(/^.+:\d+/, "FILE:LINE") actual.gsub!(/block \(\d+ levels\) in /, "") if RUBY_VERSION >= "1.9.0" assert_equal expected.chomp, actual end def test_assert_raises_triggered_none e = assert_raises Minitest::Assertion do @tc.assert_raises Minitest::Assertion do # do nothing end end expected = "Minitest::Assertion expected but nothing was raised." assert_equal expected, e.message end def test_assert_raises_triggered_none_msg e = assert_raises Minitest::Assertion do @tc.assert_raises Minitest::Assertion, "XXX" do # do nothing end end expected = "XXX.\nMinitest::Assertion expected but nothing was raised." assert_equal expected, e.message end def test_assert_raises_without_block assert_triggered "assert_raises requires a block to capture errors." do @tc.assert_raises StandardError end end def test_assert_respond_to @tc.assert_respond_to "blah", :empty? end def test_assert_respond_to_triggered assert_triggered 'Expected "blah" (String) to respond to #rawr!.' do @tc.assert_respond_to "blah", :rawr! end end def test_assert_same @assertion_count = 3 o = "blah" @tc.assert_same 1, 1 @tc.assert_same :blah, :blah @tc.assert_same o, o end def test_assert_same_triggered @assertion_count = 2 assert_triggered "Expected 2 (oid=N) to be the same as 1 (oid=N)." do @tc.assert_same 1, 2 end s1 = "blah" s2 = "blah" assert_triggered 'Expected "blah" (oid=N) to be the same as "blah" (oid=N).' do @tc.assert_same s1, s2 end end def test_assert_send assert_deprecated :assert_send do @tc.assert_send [1, :<, 2] end end def test_assert_send_bad assert_deprecated :assert_send do assert_triggered "Expected 1.>(*[2]) to return true." do @tc.assert_send [1, :>, 2] end end end def test_assert_silent @assertion_count = 2 @tc.assert_silent do # do nothing end end def test_assert_silent_triggered_err assert_triggered util_msg("", "blah blah", "In stderr") do @tc.assert_silent do $stderr.print "blah blah" end end end def test_assert_silent_triggered_out @assertion_count = 2 assert_triggered util_msg("", "blah blah", "In stdout") do @tc.assert_silent do print "blah blah" end end end def test_assert_throws @tc.assert_throws :blah do throw :blah end end def test_assert_throws_argument_exception @tc.assert_raises ArgumentError do @tc.assert_throws :blah do raise ArgumentError end end end def test_assert_throws_different assert_triggered "Expected :blah to have been thrown, not :not_blah." do @tc.assert_throws :blah do throw :not_blah end end end def test_assert_throws_name_error @tc.assert_raises NameError do @tc.assert_throws :blah do raise NameError end end end def test_assert_throws_unthrown assert_triggered "Expected :blah to have been thrown." do @tc.assert_throws :blah do # do nothing end end end def test_assert_path_exists @tc.assert_path_exists __FILE__ end def test_assert_path_exists_triggered assert_triggered "Expected path 'blah' to exist." do @tc.assert_path_exists "blah" end end def test_capture_io @assertion_count = 0 non_verbose do out, err = capture_io do puts "hi" $stderr.puts "bye!" end assert_equal "hi\n", out assert_equal "bye!\n", err end end def test_capture_subprocess_io @assertion_count = 0 non_verbose do out, err = capture_subprocess_io do system("echo hi") system("echo bye! 1>&2") end assert_equal "hi\n", out assert_equal "bye!", err.strip end end def test_class_asserts_match_refutes @assertion_count = 0 methods = Minitest::Assertions.public_instance_methods methods.map!(&:to_s) if Symbol === methods.first # These don't have corresponding refutes _on purpose_. They're # useless and will never be added, so don't bother. ignores = %w[assert_output assert_raises assert_send assert_silent assert_throws assert_mock] # These are test/unit methods. I'm not actually sure why they're still here ignores += %w[assert_no_match assert_not_equal assert_not_nil assert_not_same assert_nothing_raised assert_nothing_thrown assert_raise] asserts = methods.grep(/^assert/).sort - ignores refutes = methods.grep(/^refute/).sort - ignores assert_empty refutes.map { |n| n.sub(/^refute/, "assert") } - asserts assert_empty asserts.map { |n| n.sub(/^assert/, "refute") } - refutes end def test_delta_consistency @assertion_count = 2 @tc.assert_in_delta 0, 1, 1 assert_triggered "Expected |0 - 1| (1) to not be <= 1." do @tc.refute_in_delta 0, 1, 1 end end def test_epsilon_consistency @assertion_count = 2 @tc.assert_in_epsilon 1.0, 1.001 msg = "Expected |1.0 - 1.001| (0.000999xxx) to not be <= 0.001." assert_triggered msg do @tc.refute_in_epsilon 1.0, 1.001 end end def test_fail_after t = Time.now y, m, d = t.year, t.month, t.day assert_silent do @tc.fail_after y, m, d+1, "remove the deprecations" end assert_triggered "remove the deprecations" do @tc.fail_after y, m, d, "remove the deprecations" end end def test_flunk assert_triggered "Epic Fail!" do @tc.flunk end end def test_flunk_message assert_triggered @zomg do @tc.flunk @zomg end end def test_pass @tc.pass end def test_refute @assertion_count = 2 @tc.assert_equal false, @tc.refute(false), "returns false on success" end def test_refute_empty @assertion_count = 2 @tc.refute_empty [1] end def test_refute_empty_triggered @assertion_count = 2 assert_triggered "Expected [] to not be empty." do @tc.refute_empty [] end end def test_refute_equal @tc.refute_equal "blah", "yay" end def test_refute_equal_triggered assert_triggered 'Expected "blah" to not be equal to "blah".' do @tc.refute_equal "blah", "blah" end end def test_refute_in_delta @tc.refute_in_delta 0.0, 1.0 / 1000, 0.000001 end def test_refute_in_delta_triggered x = "0.1" assert_triggered "Expected |0.0 - 0.001| (0.001) to not be <= #{x}." do @tc.refute_in_delta 0.0, 1.0 / 1000, 0.1 end end def test_refute_in_epsilon @tc.refute_in_epsilon 10_000, 9990-1 end def test_refute_in_epsilon_triggered assert_triggered "Expected |10000 - 9990| (10) to not be <= 10.0." do @tc.refute_in_epsilon 10_000, 9990 flunk end end def test_refute_includes @assertion_count = 2 @tc.refute_includes [true], false end def test_refute_includes_triggered @assertion_count = 3 e = @tc.assert_raises Minitest::Assertion do @tc.refute_includes [true], true end expected = "Expected [true] to not include true." assert_equal expected, e.message end def test_refute_instance_of @tc.refute_instance_of Array, "blah" end def test_refute_instance_of_triggered assert_triggered 'Expected "blah" to not be an instance of String.' do @tc.refute_instance_of String, "blah" end end def test_refute_kind_of @tc.refute_kind_of Array, "blah" end def test_refute_kind_of_triggered assert_triggered 'Expected "blah" to not be a kind of String.' do @tc.refute_kind_of String, "blah" end end def test_refute_match @assertion_count = 2 @tc.refute_match(/\d+/, "blah blah blah") end def test_refute_match_matcher_object @assertion_count = 2 pattern = Object.new def pattern.=~ _; false end @tc.refute_match pattern, 5 end def test_refute_match_object_triggered @assertion_count = 2 pattern = Object.new def pattern.=~ _; true end def pattern.inspect; "[Object]" end assert_triggered "Expected [Object] to not match 5." do @tc.refute_match pattern, 5 end end def test_refute_match_triggered @assertion_count = 2 assert_triggered 'Expected /\w+/ to not match "blah blah blah".' do @tc.refute_match(/\w+/, "blah blah blah") end end def test_refute_nil @tc.refute_nil 42 end def test_refute_nil_triggered assert_triggered "Expected nil to not be nil." do @tc.refute_nil nil end end def test_refute_operator @tc.refute_operator 2, :<, 1 end def test_refute_operator_bad_object bad = Object.new def bad.== _; true end @tc.refute_operator true, :equal?, bad end def test_refute_operator_triggered assert_triggered "Expected 2 to not be > 1." do @tc.refute_operator 2, :>, 1 end end def test_refute_predicate @tc.refute_predicate "42", :empty? end def test_refute_predicate_triggered assert_triggered 'Expected "" to not be empty?.' do @tc.refute_predicate "", :empty? end end def test_refute_respond_to @tc.refute_respond_to "blah", :rawr! end def test_refute_respond_to_triggered assert_triggered 'Expected "blah" to not respond to empty?.' do @tc.refute_respond_to "blah", :empty? end end def test_refute_same @tc.refute_same 1, 2 end def test_refute_same_triggered assert_triggered "Expected 1 (oid=N) to not be the same as 1 (oid=N)." do @tc.refute_same 1, 1 end end def test_refute_path_exists @tc.refute_path_exists "blah" end def test_refute_path_exists_triggered assert_triggered "Expected path '#{__FILE__}' to not exist." do @tc.refute_path_exists __FILE__ end end def test_skip @assertion_count = 0 assert_triggered "haha!", Minitest::Skip do @tc.skip "haha!" end end def test_skip_until @assertion_count = 0 t = Time.now y, m, d = t.year, t.month, t.day assert_output "", /Stale skip_until \"not yet\" at .*?:\d+$/ do @tc.skip_until y, m, d, "not yet" end assert_triggered "not ready yet", Minitest::Skip do @tc.skip_until y, m, d+1, "not ready yet" end end def util_msg exp, act, msg = nil s = "Expected: #{exp.inspect}\n Actual: #{act.inspect}" s = "#{msg}.\n#{s}" if msg s end def without_diff old_diff = Minitest::Assertions.diff Minitest::Assertions.diff = nil yield ensure Minitest::Assertions.diff = old_diff end end class TestMinitestAssertionHelpers < Minitest::Test def assert_mu_pp exp, input, raw = false act = mu_pp input if String === input && !raw then assert_equal "\"#{exp}\"", act else assert_equal exp, act end end def assert_mu_pp_for_diff exp, input, raw = false act = mu_pp_for_diff input if String === input && !raw then assert_equal "\"#{exp}\"", act else assert_equal exp, act end end def test_diff_equal msg = "No visible difference in the String#inspect output. You should look at the implementation of #== on String or its members. \"blahblahblahblahblahblahblahblahblahblah\"".gsub(/^ +/, "") o1 = "blah" * 10 o2 = "blah" * 10 def o1.== _ false end assert_equal msg, diff(o1, o2) end def test_diff_str_mixed msg = <<-'EOM'.gsub(/^ {10}/, "") # NOTE single quotes on heredoc --- expected +++ actual @@ -1 +1 @@ -"A\\n\nB" +"A\n\\nB" EOM exp = "A\\n\nB" act = "A\n\\nB" assert_equal msg, diff(exp, act) end def test_diff_str_multiline msg = <<-'EOM'.gsub(/^ {10}/, "") # NOTE single quotes on heredoc --- expected +++ actual @@ -1,2 +1,2 @@ "A -B" +C" EOM exp = "A\nB" act = "A\nC" assert_equal msg, diff(exp, act) end def test_diff_str_simple msg = <<-'EOM'.gsub(/^ {10}/, "").chomp # NOTE single quotes on heredoc Expected: "A" Actual: "B" EOM exp = "A" act = "B" assert_equal msg, diff(exp, act) end def test_message assert_equal "blah2.", message { "blah2" }.call assert_equal "blah2.", message("") { "blah2" }.call assert_equal "blah1.\nblah2.", message(:blah1) { "blah2" }.call assert_equal "blah1.\nblah2.", message("blah1") { "blah2" }.call message = proc { "blah1" } assert_equal "blah1.\nblah2.", message(message) { "blah2" }.call message = message { "blah1" } assert_equal "blah1.\nblah2.", message(message) { "blah2" }.call end def test_message_deferred var = nil msg = message { var = "blah" } assert_nil var msg.call assert_equal "blah", var end def test_mu_pp assert_mu_pp 42.inspect, 42 assert_mu_pp %w[a b c].inspect, %w[a b c] assert_mu_pp "A B", "A B" assert_mu_pp "A\\nB", "A\nB" assert_mu_pp "A\\\\nB", 'A\nB' # notice single quotes end def test_mu_pp_for_diff assert_mu_pp_for_diff "#", Object.new assert_mu_pp_for_diff "A B", "A B" assert_mu_pp_for_diff [1, 2, 3].inspect, [1, 2, 3] assert_mu_pp_for_diff "A\nB", "A\nB" end def test_mu_pp_for_diff_str_bad_encoding str = "\666".force_encoding Encoding::UTF_8 exp = "# encoding: UTF-8\n# valid: false\n\"\\xB6\"" assert_mu_pp_for_diff exp, str, :raw end def test_mu_pp_for_diff_str_bad_encoding_both str = "\666A\\n\nB".force_encoding Encoding::UTF_8 exp = "# encoding: UTF-8\n# valid: false\n\"\\xB6A\\\\n\\nB\"" assert_mu_pp_for_diff exp, str, :raw end def test_mu_pp_for_diff_str_encoding str = "A\nB".b exp = "# encoding: ASCII-8BIT\n# valid: true\n\"A\nB\"" assert_mu_pp_for_diff exp, str, :raw end def test_mu_pp_for_diff_str_encoding_both str = "A\\n\nB".b exp = "# encoding: ASCII-8BIT\n# valid: true\n\"A\\\\n\\nB\"" assert_mu_pp_for_diff exp, str, :raw end def test_mu_pp_for_diff_str_nerd assert_mu_pp_for_diff "A\\nB\\\\nC", "A\nB\\nC" assert_mu_pp_for_diff "\\nB\\\\nC", "\nB\\nC" assert_mu_pp_for_diff "\\nB\\\\n", "\nB\\n" assert_mu_pp_for_diff "\\n\\\\n", "\n\\n" assert_mu_pp_for_diff "\\\\n\\n", "\\n\n" assert_mu_pp_for_diff "\\\\nB\\n", "\\nB\n" assert_mu_pp_for_diff "\\\\nB\\nC", "\\nB\nC" assert_mu_pp_for_diff "A\\\\n\\nB", "A\\n\nB" assert_mu_pp_for_diff "A\\n\\\\nB", "A\n\\nB" assert_mu_pp_for_diff "\\\\n\\n", "\\n\n" assert_mu_pp_for_diff "\\n\\\\n", "\n\\n" end def test_mu_pp_for_diff_str_normal assert_mu_pp_for_diff "", "" assert_mu_pp_for_diff "A\\n\n", "A\\n" assert_mu_pp_for_diff "A\\n\nB", "A\\nB" assert_mu_pp_for_diff "A\n", "A\n" assert_mu_pp_for_diff "A\nB", "A\nB" assert_mu_pp_for_diff "\\n\n", "\\n" assert_mu_pp_for_diff "\n", "\n" assert_mu_pp_for_diff "\\n\nA", "\\nA" assert_mu_pp_for_diff "\nA", "\nA" end def test_mu_pp_str_bad_encoding str = "\666".force_encoding Encoding::UTF_8 exp = "# encoding: UTF-8\n# valid: false\n\"\\xB6\"" assert_mu_pp exp, str, :raw end def test_mu_pp_str_encoding str = "A\nB".b exp = "# encoding: ASCII-8BIT\n# valid: true\n\"A\\nB\"" assert_mu_pp exp, str, :raw end def test_mu_pp_str_immutable printer = Class.new { extend Minitest::Assertions } str = "test".freeze assert_equal '"test"', printer.mu_pp(str) end end PKu]`#*ii7minitest-5.13.0/test/minitest/test_minitest_reporter.rbnu[require "minitest/autorun" require "minitest/metametameta" class Runnable def woot assert true end end class TestMinitestReporter < MetaMetaMetaTestCase attr_accessor :r, :io def new_composite_reporter reporter = Minitest::CompositeReporter.new reporter << Minitest::SummaryReporter.new(self.io) reporter << Minitest::ProgressReporter.new(self.io) def reporter.first reporters.first end def reporter.results first.results end def reporter.count first.count end def reporter.assertions first.assertions end reporter end def setup self.io = StringIO.new("") self.r = new_composite_reporter end def error_test unless defined? @et then @et = Minitest::Test.new(:woot) @et.failures << Minitest::UnexpectedError.new(begin raise "no" rescue => e e end) @et = Minitest::Result.from @et end @et end def fail_test unless defined? @ft then @ft = Minitest::Test.new(:woot) @ft.failures << begin raise Minitest::Assertion, "boo" rescue Minitest::Assertion => e e end @ft = Minitest::Result.from @ft end @ft end def passing_test @pt ||= Minitest::Result.from Minitest::Test.new(:woot) end def skip_test unless defined? @st then @st = Minitest::Test.new(:woot) @st.failures << begin raise Minitest::Skip rescue Minitest::Assertion => e e end @st = Minitest::Result.from @st end @st end def test_to_s r.record passing_test r.record fail_test assert_match "woot", r.first.to_s end def test_passed_eh_empty assert_predicate r, :passed? end def test_passed_eh_failure r.results << fail_test refute_predicate r, :passed? end SKIP_MSG = "\n\nYou have skipped tests. Run with --verbose for details." def test_passed_eh_error r.start r.results << error_test refute_predicate r, :passed? r.report refute_match SKIP_MSG, io.string end def test_passed_eh_skipped r.start r.results << skip_test assert r.passed? restore_env do r.report end assert_match SKIP_MSG, io.string end def test_passed_eh_skipped_verbose r.first.options[:verbose] = true r.start r.results << skip_test assert r.passed? r.report refute_match SKIP_MSG, io.string end def test_start r.start exp = "Run options: \n\n# Running:\n\n" assert_equal exp, io.string end def test_record_pass r.record passing_test assert_equal ".", io.string assert_empty r.results assert_equal 1, r.count assert_equal 0, r.assertions end def test_record_fail fail_test = self.fail_test r.record fail_test assert_equal "F", io.string assert_equal [fail_test], r.results assert_equal 1, r.count assert_equal 0, r.assertions end def test_record_error error_test = self.error_test r.record error_test assert_equal "E", io.string assert_equal [error_test], r.results assert_equal 1, r.count assert_equal 0, r.assertions end def test_record_skip skip_test = self.skip_test r.record skip_test assert_equal "S", io.string assert_equal [skip_test], r.results assert_equal 1, r.count assert_equal 0, r.assertions end def test_report_empty r.start r.report exp = clean <<-EOM Run options: # Running: Finished in 0.00 0 runs, 0 assertions, 0 failures, 0 errors, 0 skips EOM assert_equal exp, normalize_output(io.string) end def test_report_passing r.start r.record passing_test r.report exp = clean <<-EOM Run options: # Running: . Finished in 0.00 1 runs, 0 assertions, 0 failures, 0 errors, 0 skips EOM assert_equal exp, normalize_output(io.string) end def test_report_failure r.start r.record fail_test r.report exp = clean <<-EOM Run options: # Running: F Finished in 0.00 1) Failure: Minitest::Test#woot [FILE:LINE]: boo 1 runs, 0 assertions, 1 failures, 0 errors, 0 skips EOM assert_equal exp, normalize_output(io.string) end def test_report_error r.start r.record error_test r.report exp = clean <<-EOM Run options: # Running: E Finished in 0.00 1) Error: Minitest::Test#woot: RuntimeError: no FILE:LINE:in `error_test' FILE:LINE:in `test_report_error' 1 runs, 0 assertions, 0 failures, 1 errors, 0 skips EOM assert_equal exp, normalize_output(io.string) end def test_report_skipped r.start r.record skip_test restore_env do r.report end exp = clean <<-EOM Run options: # Running: S Finished in 0.00 1 runs, 0 assertions, 0 failures, 0 errors, 1 skips You have skipped tests. Run with --verbose for details. EOM assert_equal exp, normalize_output(io.string) end end PKu]m1i\i\3minitest-5.13.0/test/minitest/test_minitest_test.rbnu[# encoding: UTF-8 require "pathname" require "minitest/metametameta" if defined? Encoding then e = Encoding.default_external if e != Encoding::UTF_8 then warn "" warn "" warn "NOTE: External encoding #{e} is not UTF-8. Tests WILL fail." warn " Run tests with `RUBYOPT=-Eutf-8 rake` to avoid errors." warn "" warn "" end end class Minitest::Runnable def whatever # faked for testing assert true end end class TestMinitestUnit < MetaMetaMetaTestCase parallelize_me! pwd = Pathname.new File.expand_path Dir.pwd basedir = Pathname.new(File.expand_path "lib/minitest") + "mini" basedir = basedir.relative_path_from(pwd).to_s MINITEST_BASE_DIR = basedir[/\A\./] ? basedir : "./#{basedir}" BT_MIDDLE = ["#{MINITEST_BASE_DIR}/test.rb:161:in `each'", "#{MINITEST_BASE_DIR}/test.rb:158:in `each'", "#{MINITEST_BASE_DIR}/test.rb:139:in `run'", "#{MINITEST_BASE_DIR}/test.rb:106:in `run'"] def test_filter_backtrace # this is a semi-lame mix of relative paths. # I cheated by making the autotest parts not have ./ bt = (["lib/autotest.rb:571:in `add_exception'", "test/test_autotest.rb:62:in `test_add_exception'", "#{MINITEST_BASE_DIR}/test.rb:165:in `__send__'"] + BT_MIDDLE + ["#{MINITEST_BASE_DIR}/test.rb:29", "test/test_autotest.rb:422"]) bt = util_expand_bt bt ex = ["lib/autotest.rb:571:in `add_exception'", "test/test_autotest.rb:62:in `test_add_exception'"] ex = util_expand_bt ex fu = Minitest.filter_backtrace(bt) assert_equal ex, fu end def test_filter_backtrace_all_unit bt = (["#{MINITEST_BASE_DIR}/test.rb:165:in `__send__'"] + BT_MIDDLE + ["#{MINITEST_BASE_DIR}/test.rb:29"]) ex = bt.clone fu = Minitest.filter_backtrace(bt) assert_equal ex, fu end def test_filter_backtrace_unit_starts bt = (["#{MINITEST_BASE_DIR}/test.rb:165:in `__send__'"] + BT_MIDDLE + ["#{MINITEST_BASE_DIR}/mini/test.rb:29", "-e:1"]) bt = util_expand_bt bt ex = ["-e:1"] fu = Minitest.filter_backtrace bt assert_equal ex, fu end # def test_default_runner_is_minitest_unit # assert_instance_of Minitest::Unit, Minitest::Unit.runner # end def test_infectious_binary_encoding @tu = Class.new FakeNamedTest do def test_this_is_not_ascii_assertion assert_equal "ЁЁЁ", "ёёё" end def test_this_is_non_ascii_failure_message fail 'ЁЁЁ'.force_encoding('ASCII-8BIT') end end expected = clean <<-EOM EF Finished in 0.00 1) Error: FakeNamedTestXX#test_this_is_non_ascii_failure_message: RuntimeError: ЁЁЁ FILE:LINE:in `test_this_is_non_ascii_failure_message' 2) Failure: FakeNamedTestXX#test_this_is_not_ascii_assertion [FILE:LINE]: Expected: \"ЁЁЁ\" Actual: \"ёёё\" 2 runs, 1 assertions, 1 failures, 1 errors, 0 skips EOM assert_report expected end def test_passed_eh_teardown_good test_class = Class.new FakeNamedTest do def teardown; assert true; end def test_omg; assert true; end end test = test_class.new :test_omg test.run refute_predicate test, :error? assert_predicate test, :passed? refute_predicate test, :skipped? end def test_passed_eh_teardown_skipped test_class = Class.new FakeNamedTest do def teardown; assert true; end def test_omg; skip "bork"; end end test = test_class.new :test_omg test.run refute_predicate test, :error? refute_predicate test, :passed? assert_predicate test, :skipped? end def test_passed_eh_teardown_flunked test_class = Class.new FakeNamedTest do def teardown; flunk; end def test_omg; assert true; end end test = test_class.new :test_omg test.run refute_predicate test, :error? refute_predicate test, :passed? refute_predicate test, :skipped? end def util_expand_bt bt if RUBY_VERSION >= "1.9.0" then bt.map { |f| (f =~ /^\./) ? File.expand_path(f) : f } else bt end end end class TestMinitestUnitInherited < MetaMetaMetaTestCase def with_overridden_include Class.class_eval do def inherited_with_hacks _klass throw :inherited_hook end alias inherited_without_hacks inherited alias inherited inherited_with_hacks alias IGNORE_ME! inherited # 1.8 bug. god I love venture bros end yield ensure Class.class_eval do alias inherited inherited_without_hacks undef_method :inherited_with_hacks undef_method :inherited_without_hacks end refute_respond_to Class, :inherited_with_hacks refute_respond_to Class, :inherited_without_hacks end def test_inherited_hook_plays_nice_with_others with_overridden_include do assert_throws :inherited_hook do Class.new FakeNamedTest end end end end class TestMinitestRunner < MetaMetaMetaTestCase # do not parallelize this suite... it just can't handle it. def test_class_runnables @assertion_count = 0 tc = Class.new(Minitest::Test) assert_equal 1, Minitest::Test.runnables.size assert_equal [tc], Minitest::Test.runnables end def test_run_test @tu = Class.new FakeNamedTest do attr_reader :foo def run @foo = "hi mom!" r = super @foo = "okay" r end def test_something assert_equal "hi mom!", foo end end expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected end def test_run_error @tu = Class.new FakeNamedTest do def test_something assert true end def test_error raise "unhandled exception" end end expected = clean <<-EOM E. Finished in 0.00 1) Error: FakeNamedTestXX#test_error: RuntimeError: unhandled exception FILE:LINE:in \`test_error\' 2 runs, 1 assertions, 0 failures, 1 errors, 0 skips EOM assert_report expected end def test_run_error_teardown @tu = Class.new FakeNamedTest do def test_something assert true end def teardown raise "unhandled exception" end end expected = clean <<-EOM E Finished in 0.00 1) Error: FakeNamedTestXX#test_something: RuntimeError: unhandled exception FILE:LINE:in \`teardown\' 1 runs, 1 assertions, 0 failures, 1 errors, 0 skips EOM assert_report expected end def test_run_failing setup_basic_tu expected = clean <<-EOM F. Finished in 0.00 1) Failure: FakeNamedTestXX#test_failure [FILE:LINE]: Expected false to be truthy. 2 runs, 2 assertions, 1 failures, 0 errors, 0 skips EOM assert_report expected end def setup_basic_tu @tu = Class.new FakeNamedTest do def test_something assert true end def test_failure assert false end end end def test_run_failing_filtered setup_basic_tu expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected, %w[--name /some|thing/ --seed 42] end def assert_filtering filter, name, expected, a = false args = %W[--#{filter} #{name} --seed 42] alpha = Class.new FakeNamedTest do define_method :test_something do assert a end end Object.const_set(:Alpha, alpha) beta = Class.new FakeNamedTest do define_method :test_something do assert true end end Object.const_set(:Beta, beta) @tus = [alpha, beta] assert_report expected, args ensure Object.send :remove_const, :Alpha Object.send :remove_const, :Beta end def test_run_filtered_including_suite_name expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "name", "/Beta#test_something/", expected end def test_run_filtered_including_suite_name_string expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "name", "Beta#test_something", expected end def test_run_filtered_string_method_only expected = clean <<-EOM .. Finished in 0.00 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "name", "test_something", expected, :pass end def test_run_failing_excluded setup_basic_tu expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected, %w[--exclude /failure/ --seed 42] end def test_run_filtered_excluding_suite_name expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "exclude", "/Alpha#test_something/", expected end def test_run_filtered_excluding_suite_name_string expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "exclude", "Alpha#test_something", expected end def test_run_filtered_excluding_string_method_only expected = clean <<-EOM Finished in 0.00 0 runs, 0 assertions, 0 failures, 0 errors, 0 skips EOM assert_filtering "exclude", "test_something", expected, :pass end def test_run_passing @tu = Class.new FakeNamedTest do def test_something assert true end end expected = clean <<-EOM . Finished in 0.00 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected end def test_run_skip @tu = Class.new FakeNamedTest do def test_something assert true end def test_skip skip "not yet" end end expected = clean <<-EOM S. Finished in 0.00 2 runs, 1 assertions, 0 failures, 0 errors, 1 skips You have skipped tests. Run with --verbose for details. EOM restore_env do assert_report expected end end def test_run_skip_verbose @tu = Class.new FakeNamedTest do def test_something assert true end def test_skip skip "not yet" end end expected = clean <<-EOM FakeNamedTestXX#test_skip = 0.00 s = S FakeNamedTestXX#test_something = 0.00 s = . Finished in 0.00 1) Skipped: FakeNamedTestXX#test_skip [FILE:LINE]: not yet 2 runs, 1 assertions, 0 failures, 0 errors, 1 skips EOM assert_report expected, %w[--seed 42 --verbose] end def test_run_with_other_runner @tu = Class.new FakeNamedTest do def self.run reporter, options = {} @reporter = reporter before_my_suite super end def self.name; "wacky!" end def self.before_my_suite @reporter.io.puts "Running #{self.name} tests" @@foo = 1 end def test_something assert_equal 1, @@foo end def test_something_else assert_equal 1, @@foo end end expected = clean <<-EOM Running wacky! tests .. Finished in 0.00 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips EOM assert_report expected end require "monitor" class Latch def initialize count = 1 @count = count @lock = Monitor.new @cv = @lock.new_cond end def release @lock.synchronize do @count -= 1 if @count > 0 @cv.broadcast if @count == 0 end end def await @lock.synchronize { @cv.wait_while { @count > 0 } } end end def test_run_parallel test_count = 2 test_latch = Latch.new test_count wait_latch = Latch.new test_count main_latch = Latch.new thread = Thread.new { Thread.current.abort_on_exception = true # This latch waits until both test latches have been released. Both # latches can't be released unless done in separate threads because # `main_latch` keeps the test method from finishing. test_latch.await main_latch.release } @tu = Class.new FakeNamedTest do parallelize_me! test_count.times do |i| define_method :"test_wait_on_main_thread_#{i}" do test_latch.release # This latch blocks until the "main thread" releases it. The main # thread can't release this latch until both test latches have # been released. This forces the latches to be released in separate # threads. main_latch.await assert true end end end expected = clean <<-EOM .. Finished in 0.00 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips EOM assert_report(expected) do |reporter| reporter.extend(Module.new { define_method("record") do |result| super(result) wait_latch.release end define_method("report") do wait_latch.await super() end }) end assert thread.join end end class TestMinitestUnitOrder < MetaMetaMetaTestCase # do not parallelize this suite... it just can't handle it. def test_before_setup call_order = [] @tu = Class.new FakeNamedTest do define_method :setup do super() call_order << :setup end define_method :before_setup do call_order << :before_setup end def test_omg; assert true; end end run_tu_with_fresh_reporter expected = [:before_setup, :setup] assert_equal expected, call_order end def test_after_teardown call_order = [] @tu = Class.new FakeNamedTest do define_method :teardown do super() call_order << :teardown end define_method :after_teardown do call_order << :after_teardown end def test_omg; assert true; end end run_tu_with_fresh_reporter expected = [:teardown, :after_teardown] assert_equal expected, call_order end def test_all_teardowns_are_guaranteed_to_run call_order = [] @tu = Class.new FakeNamedTest do define_method :after_teardown do super() call_order << :after_teardown raise end define_method :teardown do super() call_order << :teardown raise end define_method :before_teardown do super() call_order << :before_teardown raise end def test_omg; assert true; end end run_tu_with_fresh_reporter expected = [:before_teardown, :teardown, :after_teardown] assert_equal expected, call_order end def test_setup_and_teardown_survive_inheritance call_order = [] @tu = Class.new FakeNamedTest do define_method :setup do call_order << :setup_method end define_method :teardown do call_order << :teardown_method end define_method :test_something do call_order << :test end end run_tu_with_fresh_reporter @tu = Class.new @tu run_tu_with_fresh_reporter # Once for the parent class, once for the child expected = [:setup_method, :test, :teardown_method] * 2 assert_equal expected, call_order end end class TestMinitestRunnable < Minitest::Test def setup_marshal klass tc = klass.new "whatever" tc.assertions = 42 tc.failures << "a failure" yield tc if block_given? def tc.setup @blah = "blah" end tc.setup @tc = Minitest::Result.from tc end def assert_marshal expected_ivars new_tc = Marshal.load Marshal.dump @tc ivars = new_tc.instance_variables.map(&:to_s).sort assert_equal expected_ivars, ivars assert_equal "whatever", new_tc.name assert_equal 42, new_tc.assertions assert_equal ["a failure"], new_tc.failures yield new_tc if block_given? end def test_marshal setup_marshal Minitest::Runnable assert_marshal %w[@NAME @assertions @failures @klass @source_location @time] end def test_spec_marshal klass = describe("whatever") { it("passes") { assert true } } rm = klass.runnable_methods.first # Run the test @tc = klass.new(rm).run assert_kind_of Minitest::Result, @tc # Pass it over the wire over_the_wire = Marshal.load Marshal.dump @tc assert_equal @tc.time, over_the_wire.time assert_equal @tc.name, over_the_wire.name assert_equal @tc.assertions, over_the_wire.assertions assert_equal @tc.failures, over_the_wire.failures assert_equal @tc.klass, over_the_wire.klass end end class TestMinitestTest < TestMinitestRunnable def test_dup setup_marshal Minitest::Test do |tc| tc.time = 3.14 end assert_marshal %w[@NAME @assertions @failures @klass @source_location @time] do |new_tc| assert_in_epsilon 3.14, new_tc.time end end end class TestMinitestUnitTestCase < Minitest::Test # do not call parallelize_me! - teardown accesses @tc._assertions # which is not threadsafe. Nearly every method in here is an # assertion test so it isn't worth splitting it out further. RUBY18 = !defined? Encoding def setup super Minitest::Test.reset @tc = Minitest::Test.new "fake tc" @zomg = "zomg ponies!" @assertion_count = 1 end def teardown assert_equal(@assertion_count, @tc.assertions, "expected #{@assertion_count} assertions to be fired during the test, not #{@tc.assertions}") if @tc.passed? end def non_verbose orig_verbose = $VERBOSE $VERBOSE = false yield ensure $VERBOSE = orig_verbose end def test_runnable_methods_random @assertion_count = 0 sample_test_case = Class.new FakeNamedTest do def self.test_order; :random; end def test_test1; assert "does not matter" end def test_test2; assert "does not matter" end def test_test3; assert "does not matter" end end srand 42 expected = %w[test_test2 test_test1 test_test3] assert_equal expected, sample_test_case.runnable_methods end def test_runnable_methods_sorted @assertion_count = 0 sample_test_case = Class.new FakeNamedTest do def self.test_order; :sorted end def test_test3; assert "does not matter" end def test_test2; assert "does not matter" end def test_test1; assert "does not matter" end end expected = %w[test_test1 test_test2 test_test3] assert_equal expected, sample_test_case.runnable_methods end def test_i_suck_and_my_tests_are_order_dependent_bang_sets_test_order_alpha @assertion_count = 0 shitty_test_case = Class.new FakeNamedTest shitty_test_case.i_suck_and_my_tests_are_order_dependent! assert_equal :alpha, shitty_test_case.test_order end def test_i_suck_and_my_tests_are_order_dependent_bang_does_not_warn @assertion_count = 0 shitty_test_case = Class.new FakeNamedTest def shitty_test_case.test_order; :lol end assert_silent do shitty_test_case.i_suck_and_my_tests_are_order_dependent! end end def test_autorun_does_not_affect_fork_success_status @assertion_count = 0 skip "windows doesn't have skip" unless Process.respond_to?(:fork) Process.waitpid(fork {}) assert_equal true, $?.success? end def test_autorun_does_not_affect_fork_exit_status @assertion_count = 0 skip "windows doesn't have skip" unless Process.respond_to?(:fork) Process.waitpid(fork { exit 42 }) assert_equal 42, $?.exitstatus end end class TestMinitestGuard < Minitest::Test parallelize_me! def test_mri_eh assert self.class.mri? "ruby blah" assert self.mri? "ruby blah" end def test_jruby_eh assert self.class.jruby? "java" assert self.jruby? "java" end def test_rubinius_eh assert_output "", /DEPRECATED/ do assert self.class.rubinius? "rbx" end assert_output "", /DEPRECATED/ do assert self.rubinius? "rbx" end end def test_maglev_eh assert_output "", /DEPRECATED/ do assert self.class.maglev? "maglev" end assert_output "", /DEPRECATED/ do assert self.maglev? "maglev" end end def test_osx_eh assert self.class.osx? "darwin" assert self.osx? "darwin" end def test_windows_eh assert self.class.windows? "mswin" assert self.windows? "mswin" end end class TestMinitestUnitRecording < MetaMetaMetaTestCase # do not parallelize this suite... it just can't handle it. def assert_run_record *expected, &block @tu = Class.new FakeNamedTest, &block run_tu_with_fresh_reporter recorded = first_reporter.results.map(&:failures).flatten.map { |f| f.error.class } assert_equal expected, recorded end def test_run_with_bogus_reporter # https://github.com/seattlerb/minitest/issues/659 # TODO: remove test for minitest 6 @tu = Class.new FakeNamedTest do def test_method assert true end end bogus_reporter = Class.new do # doesn't subclass AbstractReporter def start; @success = false; end # def prerecord klass, name; end # doesn't define full API def record result; @success = true; end def report; end def passed?; end def results; end def success?; @success; end end.new self.reporter = Minitest::CompositeReporter.new reporter << bogus_reporter Minitest::Runnable.runnables.delete @tu @tu.run reporter, {} assert_predicate bogus_reporter, :success? end def test_record_passing assert_run_record do def test_method assert true end end end def test_record_failing assert_run_record Minitest::Assertion do def test_method assert false end end end def test_record_error assert_run_record RuntimeError do def test_method raise "unhandled exception" end end end def test_record_error_teardown assert_run_record RuntimeError do def test_method assert true end def teardown raise "unhandled exception" end end end def test_record_error_in_test_and_teardown assert_run_record AnError, RuntimeError do def test_method raise AnError end def teardown raise "unhandled exception" end end end def test_to_s_error_in_test_and_teardown @tu = Class.new FakeNamedTest do def test_method raise AnError end def teardown raise "unhandled exception" end end run_tu_with_fresh_reporter exp = clean " Error: FakeNamedTestXX#test_method: AnError: AnError FILE:LINE:in `test_method' Error: FakeNamedTestXX#test_method: RuntimeError: unhandled exception FILE:LINE:in `teardown' " assert_equal exp.strip, normalize_output(first_reporter.results.first.to_s).strip end def test_record_skip assert_run_record Minitest::Skip do def test_method skip "not yet" end end end end PKu]lJlJ3minitest-5.13.0/test/minitest/test_minitest_mock.rbnu[require "minitest/autorun" class TestMinitestMock < Minitest::Test parallelize_me! def setup @mock = Minitest::Mock.new.expect(:foo, nil) @mock.expect(:meaning_of_life, 42) end def test_create_stub_method assert_nil @mock.foo end def test_allow_return_value_specification assert_equal 42, @mock.meaning_of_life end def test_blow_up_if_not_called @mock.foo util_verify_bad "expected meaning_of_life() => 42" end def test_not_blow_up_if_everything_called @mock.foo @mock.meaning_of_life assert_mock @mock end def test_allow_expectations_to_be_added_after_creation @mock.expect(:bar, true) assert @mock.bar end def test_not_verify_if_new_expected_method_is_not_called @mock.foo @mock.meaning_of_life @mock.expect(:bar, true) util_verify_bad "expected bar() => true" end def test_blow_up_on_wrong_number_of_arguments @mock.foo @mock.meaning_of_life @mock.expect(:sum, 3, [1, 2]) e = assert_raises ArgumentError do @mock.sum end assert_equal "mocked method :sum expects 2 arguments, got 0", e.message end def test_return_mock_does_not_raise retval = Minitest::Mock.new mock = Minitest::Mock.new mock.expect(:foo, retval) mock.foo assert_mock mock end def test_mock_args_does_not_raise arg = Minitest::Mock.new mock = Minitest::Mock.new mock.expect(:foo, nil, [arg]) mock.foo(arg) assert_mock mock end def test_set_expectation_on_special_methods mock = Minitest::Mock.new mock.expect :object_id, "received object_id" assert_equal "received object_id", mock.object_id mock.expect :respond_to_missing?, "received respond_to_missing?" assert_equal "received respond_to_missing?", mock.respond_to_missing? mock.expect :===, "received ===" assert_equal "received ===", mock.=== mock.expect :inspect, "received inspect" assert_equal "received inspect", mock.inspect mock.expect :to_s, "received to_s" assert_equal "received to_s", mock.to_s mock.expect :public_send, "received public_send" assert_equal "received public_send", mock.public_send mock.expect :send, "received send" assert_equal "received send", mock.send assert_mock mock end def test_expectations_can_be_satisfied_via_send @mock.send :foo @mock.send :meaning_of_life assert_mock @mock end def test_expectations_can_be_satisfied_via_public_send skip "Doesn't run on 1.8" if RUBY_VERSION < "1.9" @mock.public_send :foo @mock.public_send :meaning_of_life assert_mock @mock end def test_blow_up_on_wrong_arguments @mock.foo @mock.meaning_of_life @mock.expect(:sum, 3, [1, 2]) e = assert_raises MockExpectationError do @mock.sum(2, 4) end exp = "mocked method :sum called with unexpected arguments [2, 4]" assert_equal exp, e.message end def test_expect_with_non_array_args e = assert_raises ArgumentError do @mock.expect :blah, 3, false end assert_equal "args must be an array", e.message end def test_respond_appropriately assert @mock.respond_to?(:foo) assert @mock.respond_to?(:foo, true) assert @mock.respond_to?("foo") assert !@mock.respond_to?(:bar) end def test_no_method_error_on_unexpected_methods e = assert_raises NoMethodError do @mock.bar end expected = "unmocked method :bar, expected one of [:foo, :meaning_of_life]" assert_equal expected, e.message end def test_assign_per_mock_return_values a = Minitest::Mock.new b = Minitest::Mock.new a.expect(:foo, :a) b.expect(:foo, :b) assert_equal :a, a.foo assert_equal :b, b.foo end def test_do_not_create_stub_method_on_new_mocks a = Minitest::Mock.new a.expect(:foo, :a) assert !Minitest::Mock.new.respond_to?(:foo) end def test_mock_is_a_blank_slate @mock.expect :kind_of?, true, [String] @mock.expect :==, true, [1] assert @mock.kind_of?(String), "didn't mock :kind_of\?" assert @mock == 1, "didn't mock :==" end def test_verify_allows_called_args_to_be_loosely_specified mock = Minitest::Mock.new mock.expect :loose_expectation, true, [Integer] mock.loose_expectation 1 assert_mock mock end def test_verify_raises_with_strict_args mock = Minitest::Mock.new mock.expect :strict_expectation, true, [2] e = assert_raises MockExpectationError do mock.strict_expectation 1 end exp = "mocked method :strict_expectation called with unexpected arguments [1]" assert_equal exp, e.message end def test_method_missing_empty mock = Minitest::Mock.new mock.expect :a, nil mock.a e = assert_raises MockExpectationError do mock.a end assert_equal "No more expects available for :a: []", e.message end def test_same_method_expects_are_verified_when_all_called mock = Minitest::Mock.new mock.expect :foo, nil, [:bar] mock.expect :foo, nil, [:baz] mock.foo :bar mock.foo :baz assert_mock mock end def test_same_method_expects_blow_up_when_not_all_called mock = Minitest::Mock.new mock.expect :foo, nil, [:bar] mock.expect :foo, nil, [:baz] mock.foo :bar e = assert_raises(MockExpectationError) { mock.verify } exp = "expected foo(:baz) => nil, got [foo(:bar) => nil]" assert_equal exp, e.message end def test_same_method_expects_with_same_args_blow_up_when_not_all_called mock = Minitest::Mock.new mock.expect :foo, nil, [:bar] mock.expect :foo, nil, [:bar] mock.foo :bar e = assert_raises(MockExpectationError) { mock.verify } exp = "expected foo(:bar) => nil, got [foo(:bar) => nil]" assert_equal exp, e.message end def test_verify_passes_when_mock_block_returns_true mock = Minitest::Mock.new mock.expect :foo, nil do true end mock.foo assert_mock mock end def test_mock_block_is_passed_function_params arg1, arg2, arg3 = :bar, [1, 2, 3], { :a => "a" } mock = Minitest::Mock.new mock.expect :foo, nil do |a1, a2, a3| a1 == arg1 && a2 == arg2 && a3 == arg3 end mock.foo arg1, arg2, arg3 assert_mock mock end def test_mock_block_is_passed_function_block mock = Minitest::Mock.new block = proc { "bar" } mock.expect :foo, nil do |arg, &blk| arg == "foo" && blk == block end mock.foo "foo", &block assert_mock mock end def test_verify_fails_when_mock_block_returns_false mock = Minitest::Mock.new mock.expect :foo, nil do false end e = assert_raises(MockExpectationError) { mock.foo } exp = "mocked method :foo failed block w/ []" assert_equal exp, e.message end def test_mock_block_throws_if_args_passed mock = Minitest::Mock.new e = assert_raises(ArgumentError) do mock.expect :foo, nil, [:a, :b, :c] do true end end exp = "args ignored when block given" assert_equal exp, e.message end def test_mock_returns_retval_when_called_with_block mock = Minitest::Mock.new mock.expect(:foo, 32) do true end rs = mock.foo assert_equal rs, 32 end def util_verify_bad exp e = assert_raises MockExpectationError do @mock.verify end assert_equal exp, e.message end def test_mock_called_via_send mock = Minitest::Mock.new mock.expect(:foo, true) mock.send :foo assert_mock mock end def test_mock_called_via___send__ mock = Minitest::Mock.new mock.expect(:foo, true) mock.__send__ :foo assert_mock mock end def test_mock_called_via_send_with_args mock = Minitest::Mock.new mock.expect(:foo, true, [1, 2, 3]) mock.send(:foo, 1, 2, 3) assert_mock mock end end require "minitest/metametameta" class TestMinitestStub < Minitest::Test # Do not parallelize since we're calling stub on class methods def setup super Minitest::Test.reset @tc = Minitest::Test.new "fake tc" @assertion_count = 1 end def teardown super assert_equal @assertion_count, @tc.assertions if self.passed? end class Time def self.now 24 end end def assert_stub val_or_callable @assertion_count += 1 t = Time.now.to_i Time.stub :now, val_or_callable do @tc.assert_equal 42, Time.now end @tc.assert_operator Time.now.to_i, :>=, t end def test_stub_private_module_method @assertion_count += 1 t0 = Time.now self.stub :sleep, nil do @tc.assert_nil sleep(10) end @tc.assert_operator Time.now - t0, :<=, 1 end def test_stub_private_module_method_indirect @assertion_count += 1 fail_clapper = Class.new do def fail_clap raise :clap end end.new fail_clapper.stub :raise, nil do |safe_clapper| @tc.assert_equal :clap, safe_clapper.fail_clap # either form works @tc.assert_equal :clap, fail_clapper.fail_clap # yay closures end end def test_stub_public_module_method Math.stub :log10, :stubbed do @tc.assert_equal :stubbed, Math.log10(1000) end end def test_stub_value assert_stub 42 end def test_stub_block assert_stub lambda { 42 } end def test_stub_block_args @assertion_count += 1 t = Time.now.to_i Time.stub :now, lambda { |n| n * 2 } do @tc.assert_equal 42, Time.now(21) end @tc.assert_operator Time.now.to_i, :>=, t end def test_stub_callable obj = Object.new def obj.call 42 end assert_stub obj end def test_stub_yield_self obj = "foo" val = obj.stub :to_s, "bar" do |s| s.to_s end @tc.assert_equal "bar", val end def test_dynamic_method @assertion_count = 2 dynamic = Class.new do def self.respond_to? meth meth == :found end def self.method_missing meth, *args, &block if meth == :found false else super end end end val = dynamic.stub(:found, true) do |s| s.found end @tc.assert_equal true, val @tc.assert_equal false, dynamic.found end def test_stub_NameError e = @tc.assert_raises NameError do Time.stub :nope_nope_nope, 42 do # do nothing end end exp = /undefined method `nope_nope_nope' for( class)? `#{self.class}::Time'/ assert_match exp, e.message end def test_mock_with_yield mock = Minitest::Mock.new mock.expect(:write, true) do true end rs = nil File.stub :open, true, mock do File.open "foo.txt", "r" do |f| rs = f.write end end @tc.assert_equal true, rs end alias test_stub_value__old test_stub_value # TODO: remove/rename ## Permutation Sets: # [:value, :lambda] # [:*, :block, :block_call] # [:**, :block_args] # # Where: # # :value = a normal value # :lambda = callable or lambda # :* = no block # :block = normal block # :block_call = :lambda invokes the block (N/A for :value) # :** = no args # :args = args passed to stub ## Permutations # [:call, :*, :**] =>5 callable+block FIX: CALL BOTH (bug) # [:call, :*, :**] =>6 callable # [:lambda, :*, :**] => lambda result # [:lambda, :*, :args] => lambda result NO ARGS # [:lambda, :block, :**] =>5 lambda result FIX: CALL BOTH (bug) # [:lambda, :block, :**] =>6 lambda result # [:lambda, :block, :args] =>5 lambda result FIX: CALL BOTH (bug) # [:lambda, :block, :args] =>6 lambda result # [:lambda, :block, :args] =>7 raise ArgumentError # [:lambda, :block_call, :**] =>5 lambda FIX: BUG!-not passed block to lambda # [:lambda, :block_call, :**] =>6 lambda+block result # [:lambda, :block_call, :args] =>5 lambda FIX: BUG!-not passed block to lambda # [:lambda, :block_call, :args] =>6 lambda+block result # [:value, :*, :**] => value # [:value, :*, :args] => value, ignore args # [:value, :block, :**] =>5 value, call block # [:value, :block, :**] =>6 value # [:value, :block, :args] =>5 value, call block w/ args # [:value, :block, :args] =>6 value, call block w/ args, deprecated # [:value, :block, :args] =>7 raise ArgumentError # [:value, :block_call, :**] => N/A # [:value, :block_call, :args] => N/A class Bar def call puts "hi" end end class Foo def self.blocking yield end end class Thingy def self.identity arg arg end end def test_stub_callable_block_5 # from tenderlove @assertion_count += 1 Foo.stub5 :blocking, Bar.new do @tc.assert_output "hi\n", "" do Foo.blocking do @tc.flunk "shouldn't ever hit this" end end end end def test_stub_callable_block_6 # from tenderlove skip_stub6 @assertion_count += 1 Foo.stub6 :blocking, Bar.new do @tc.assert_output "hi\n", "" do Foo.blocking do @tc.flunk "shouldn't ever hit this" end end end end def test_stub_lambda Thread.stub :new, lambda { 21+21 } do @tc.assert_equal 42, Thread.new end end def test_stub_lambda_args Thread.stub :new, lambda { 21+21 }, :wtf do @tc.assert_equal 42, Thread.new end end def test_stub_lambda_block_5 Thread.stub5 :new, lambda { 21+21 } do result = Thread.new do @tc.flunk "shouldn't ever hit this" end @tc.assert_equal 42, result end end def test_stub_lambda_block_6 skip_stub6 Thread.stub6 :new, lambda { 21+21 } do result = Thread.new do @tc.flunk "shouldn't ever hit this" end @tc.assert_equal 42, result end end def test_stub_lambda_block_args_5 @assertion_count += 1 Thingy.stub5 :identity, lambda { |y| @tc.assert_equal :nope, y; 21+21 }, :WTF? do result = Thingy.identity :nope do |x| @tc.flunk "shouldn't reach this" end @tc.assert_equal 42, result end end def test_stub_lambda_block_args_6 skip_stub6 @assertion_count += 1 Thingy.stub6 :identity, lambda { |y| @tc.assert_equal :nope, y; 21+21 }, :WTF? do result = Thingy.identity :nope do |x| @tc.flunk "shouldn't reach this" end @tc.assert_equal 42, result end end def test_stub_lambda_block_args_6_2 skip_stub6 @tc.assert_raises ArgumentError do Thingy.stub6_2 :identity, lambda { |y| :__not_run__ }, :WTF? do # doesn't matter end end end def test_stub_lambda_block_call_5 @assertion_count += 1 rs = nil io = StringIO.new "", "w" File.stub5 :open, lambda { |p, m, &blk| blk and blk.call io } do File.open "foo.txt", "r" do |f| rs = f && f.write("woot") end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_lambda_block_call_6 skip_stub6 @assertion_count += 1 rs = nil io = StringIO.new "", "w" File.stub6 :open, lambda { |p, m, &blk| blk.call io } do File.open "foo.txt", "r" do |f| rs = f.write("woot") end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_lambda_block_call_args_5 @assertion_count += 1 rs = nil io = StringIO.new "", "w" File.stub5(:open, lambda { |p, m, &blk| blk and blk.call io }, :WTF?) do File.open "foo.txt", "r" do |f| rs = f.write("woot") end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_lambda_block_call_args_6 skip_stub6 @assertion_count += 1 rs = nil io = StringIO.new "", "w" File.stub6(:open, lambda { |p, m, &blk| blk.call io }, :WTF?) do File.open "foo.txt", "r" do |f| rs = f.write("woot") end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_lambda_block_call_args_6_2 skip_stub6 @assertion_count += 2 rs = nil io = StringIO.new "", "w" @tc.assert_raises ArgumentError do File.stub6_2(:open, lambda { |p, m, &blk| blk.call io }, :WTF?) do File.open "foo.txt", "r" do |f| rs = f.write("woot") end end end @tc.assert_nil rs @tc.assert_equal "", io.string end def test_stub_value Thread.stub :new, 42 do result = Thread.new @tc.assert_equal 42, result end end def test_stub_value_args Thread.stub :new, 42, :WTF? do result = Thread.new @tc.assert_equal 42, result end end def test_stub_value_block_5 @assertion_count += 1 Thread.stub5 :new, 42 do result = Thread.new do @tc.assert true end @tc.assert_equal 42, result end end def test_stub_value_block_6 skip_stub6 Thread.stub6 :new, 42 do result = Thread.new do @tc.flunk "shouldn't hit this" end @tc.assert_equal 42, result end end def test_stub_value_block_args_5 @assertion_count += 2 rs = nil io = StringIO.new "", "w" File.stub5 :open, :value, io do result = File.open "foo.txt", "r" do |f| rs = f.write("woot") end @tc.assert_equal :value, result end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_value_block_args_5__break_if_not_passed e = @tc.assert_raises NoMethodError do File.stub5 :open, :return_value do # intentionally bad setup w/ no args File.open "foo.txt", "r" do |f| f.write "woot" end end end exp = "undefined method `write' for nil:NilClass" assert_equal exp, e.message end def test_stub_value_block_args_6 skip_stub6 @assertion_count += 2 rs = nil io = StringIO.new "", "w" assert_deprecated do File.stub6 :open, :value, io do result = File.open "foo.txt", "r" do |f| rs = f.write("woot") end @tc.assert_equal :value, result end end @tc.assert_equal 4, rs @tc.assert_equal "woot", io.string end def test_stub_value_block_args_6_2 skip_stub6 @assertion_count += 2 rs = nil io = StringIO.new "", "w" @tc.assert_raises ArgumentError do File.stub6_2 :open, :value, io do result = File.open "foo.txt", "r" do |f| @tc.flunk "shouldn't hit this" end @tc.assert_equal :value, result end end @tc.assert_nil rs @tc.assert_equal "", io.string end def assert_deprecated re = /deprecated/ assert_output "", re do yield end end def skip_stub6 skip "not yet" unless STUB6 end end STUB6 = ENV["STUB6"] if STUB6 then require "minitest/mock6" if STUB6 else class Object alias stub5 stub alias stub6 stub end end PKu]O -minitest-5.13.0/test/minitest/metametameta.rbnu[require "tempfile" require "stringio" require "minitest/autorun" class Minitest::Test def clean s s.gsub(/^ {6}/, "") end end class FakeNamedTest < Minitest::Test @@count = 0 def self.name @fake_name ||= begin @@count += 1 "FakeNamedTest%02d" % @@count end end end module MyModule; end class AnError < StandardError; include MyModule; end class MetaMetaMetaTestCase < Minitest::Test attr_accessor :reporter, :output, :tu def with_stderr err old = $stderr $stderr = err yield ensure $stderr = old end def run_tu_with_fresh_reporter flags = %w[--seed 42] options = Minitest.process_args flags @output = StringIO.new("".encode('UTF-8')) self.reporter = Minitest::CompositeReporter.new reporter << Minitest::SummaryReporter.new(@output, options) reporter << Minitest::ProgressReporter.new(@output, options) with_stderr @output do reporter.start yield(reporter) if block_given? @tus ||= [@tu] @tus.each do |tu| Minitest::Runnable.runnables.delete tu tu.run reporter, options end reporter.report end end def first_reporter reporter.reporters.first end def assert_report expected, flags = %w[--seed 42], &block header = clean <<-EOM Run options: #{flags.map { |s| s =~ /\|/ ? s.inspect : s }.join " "} # Running: EOM run_tu_with_fresh_reporter flags, &block output = normalize_output @output.string.dup assert_equal header + expected, output end def normalize_output output output.sub!(/Finished in .*/, "Finished in 0.00") output.sub!(/Loaded suite .*/, "Loaded suite blah") output.gsub!(/FakeNamedTest\d+/, "FakeNamedTestXX") output.gsub!(/ = \d+.\d\d s = /, " = 0.00 s = ") output.gsub!(/0x[A-Fa-f0-9]+/, "0xXXX") output.gsub!(/ +$/, "") if windows? then output.gsub!(/\[(?:[A-Za-z]:)?[^\]:]+:\d+\]/, "[FILE:LINE]") output.gsub!(/^(\s+)(?:[A-Za-z]:)?[^:]+:\d+:in/, '\1FILE:LINE:in') else output.gsub!(/\[[^\]:]+:\d+\]/, "[FILE:LINE]") output.gsub!(/^(\s+)[^:]+:\d+:in/, '\1FILE:LINE:in') end output.gsub!(/( at )[^:]+:\d+/, '\1[FILE:LINE]') output end def restore_env old_value = ENV["MT_NO_SKIP_MSG"] ENV.delete "MT_NO_SKIP_MSG" yield ensure ENV["MT_NO_SKIP_MSG"] = old_value end def setup super srand 42 Minitest::Test.reset @tu = nil end end PKu]8*k*k3minitest-5.13.0/test/minitest/test_minitest_spec.rbnu[# encoding: utf-8 require "minitest/metametameta" require "stringio" class MiniSpecA < Minitest::Spec; end class MiniSpecB < Minitest::Test; extend Minitest::Spec::DSL; end class MiniSpecC < MiniSpecB; end class NamedExampleA < MiniSpecA; end class NamedExampleB < MiniSpecB; end class NamedExampleC < MiniSpecC; end class ExampleA; end class ExampleB < ExampleA; end describe Minitest::Spec do # helps to deal with 2.4 deprecation of Fixnum for Integer Int = 1.class # do not parallelize this suite... it just can"t handle it. def assert_triggered expected = "blah", klass = Minitest::Assertion @assertion_count += 1 e = assert_raises(klass) do yield end msg = e.message.sub(/(---Backtrace---).*/m, '\1') msg.gsub!(/\(oid=[-0-9]+\)/, "(oid=N)") msg.gsub!(/(\d\.\d{6})\d+/, '\1xxx') # normalize: ruby version, impl, platform msg.gsub!(/:0x[Xa-fA-F0-9]{4,}[ @].+?>/, ":0xXXXXXX@PATH>") if expected @assertion_count += 1 case expected when String then assert_equal expected, msg when Regexp then @assertion_count += 1 assert_match expected, msg else flunk "Unknown: #{expected.inspect}" end end end before do @assertion_count = 4 end after do _(self.assertions).must_equal @assertion_count if passed? and not skipped? end it "needs to be able to catch a Minitest::Assertion exception" do @assertion_count = 1 assert_triggered "Expected 1 to not be equal to 1." do _(1).wont_equal 1 end end it "needs to check for file existence" do @assertion_count = 3 _(_(__FILE__).path_must_exist).must_equal true assert_triggered "Expected path 'blah' to exist." do _("blah").path_must_exist end end it "needs to check for file non-existence" do @assertion_count = 3 _(_("blah").path_wont_exist).must_equal false assert_triggered "Expected path '#{__FILE__}' to not exist." do _(__FILE__).path_wont_exist end end it "needs to be sensible about must_include order" do @assertion_count += 3 # must_include is 2 assertions _(_([1, 2, 3]).must_include(2)).must_equal true assert_triggered "Expected [1, 2, 3] to include 5." do _([1, 2, 3]).must_include 5 end assert_triggered "msg.\nExpected [1, 2, 3] to include 5." do _([1, 2, 3]).must_include 5, "msg" end end it "needs to be sensible about wont_include order" do @assertion_count += 3 # wont_include is 2 assertions _(_([1, 2, 3]).wont_include(5)).must_equal false assert_triggered "Expected [1, 2, 3] to not include 2." do _([1, 2, 3]).wont_include 2 end assert_triggered "msg.\nExpected [1, 2, 3] to not include 2." do _([1, 2, 3]).wont_include 2, "msg" end end it "needs to catch an expected exception" do @assertion_count = 2 expect { raise "blah" }.must_raise RuntimeError expect { raise Minitest::Assertion }.must_raise Minitest::Assertion end it "needs to catch an unexpected exception" do @assertion_count -= 2 # no positive msg = <<-EOM.gsub(/^ {6}/, "").chomp [RuntimeError] exception expected, not Class: Message: <"woot"> ---Backtrace--- EOM assert_triggered msg do expect { raise StandardError, "woot" }.must_raise RuntimeError end assert_triggered "msg.\n#{msg}" do expect { raise StandardError, "woot" }.must_raise RuntimeError, "msg" end end it "needs to ensure silence" do @assertion_count -= 1 # no msg @assertion_count += 2 # assert_output is 2 assertions _(expect {}.must_be_silent).must_equal true assert_triggered "In stdout.\nExpected: \"\"\n Actual: \"xxx\"" do expect { print "xxx" }.must_be_silent end end it "needs to have all methods named well" do skip "N/A" if ENV["MT_NO_EXPECTATIONS"] @assertion_count = 2 methods = Minitest::Expectations.public_instance_methods.grep(/must|wont/) methods.map!(&:to_s) if Symbol === methods.first musts, wonts = methods.sort.partition { |m| m =~ /must/ } expected_musts = %w[must_be must_be_close_to must_be_empty must_be_instance_of must_be_kind_of must_be_nil must_be_same_as must_be_silent must_be_within_delta must_be_within_epsilon must_equal must_include must_match must_output must_raise must_respond_to must_throw path_must_exist] bad = %w[not raise throw send output be_silent] expected_wonts = expected_musts.map { |m| m.sub(/must/, "wont") }.sort expected_wonts.reject! { |m| m =~ /wont_#{Regexp.union(*bad)}/ } _(musts).must_equal expected_musts _(wonts).must_equal expected_wonts end it "needs to raise if an expected exception is not raised" do @assertion_count -= 2 # no positive test assert_triggered "RuntimeError expected but nothing was raised." do expect { 42 }.must_raise RuntimeError end assert_triggered "msg.\nRuntimeError expected but nothing was raised." do expect { 42 }.must_raise RuntimeError, "msg" end end it "needs to verify binary messages" do _(_(42).wont_be(:<, 24)).must_equal false assert_triggered "Expected 24 to not be < 42." do _(24).wont_be :<, 42 end assert_triggered "msg.\nExpected 24 to not be < 42." do _(24).wont_be :<, 42, "msg" end end it "needs to verify emptyness" do @assertion_count += 3 # empty is 2 assertions _(_([]).must_be_empty).must_equal true assert_triggered "Expected [42] to be empty." do _([42]).must_be_empty end assert_triggered "msg.\nExpected [42] to be empty." do _([42]).must_be_empty "msg" end end it "needs to verify equality" do @assertion_count += 1 _(_(6 * 7).must_equal(42)).must_equal true assert_triggered "Expected: 42\n Actual: 54" do _(6 * 9).must_equal 42 end assert_triggered "msg.\nExpected: 42\n Actual: 54" do _(6 * 9).must_equal 42, "msg" end assert_triggered(/^-42\n\+#\n/) do _(proc { 42 }).must_equal 42 # proc isn't called, so expectation fails end end it "needs to warn on equality with nil" do @assertion_count += 1 # extra test out, err = capture_io do _(_(nil).must_equal(nil)).must_equal true end exp = "DEPRECATED: Use assert_nil if expecting nil from #{__FILE__}:#{__LINE__-3}. " \ "This will fail in Minitest 6.\n" exp = "" if $-w.nil? assert_empty out assert_equal exp, err end it "needs to verify floats outside a delta" do @assertion_count += 1 # extra test _(_(24).wont_be_close_to(42)).must_equal false assert_triggered "Expected |42 - 42.0| (0.0) to not be <= 0.001." do _(6 * 7.0).wont_be_close_to 42 end x = "1.0e-05" assert_triggered "Expected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_close_to 42, 0.00001 end assert_triggered "msg.\nExpected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_close_to 42, 0.00001, "msg" end end it "needs to verify floats outside an epsilon" do @assertion_count += 1 # extra test _(_(24).wont_be_within_epsilon(42)).must_equal false x = "0.042" assert_triggered "Expected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_within_epsilon 42 end x = "0.00042" assert_triggered "Expected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_within_epsilon 42, 0.00001 end assert_triggered "msg.\nExpected |42 - 42.0| (0.0) to not be <= #{x}." do _(6 * 7.0).wont_be_within_epsilon 42, 0.00001, "msg" end end it "needs to verify floats within a delta" do @assertion_count += 1 # extra test _(_(6.0 * 7).must_be_close_to(42.0)).must_equal true assert_triggered "Expected |0.0 - 0.01| (0.01) to be <= 0.001." do _(1.0 / 100).must_be_close_to 0.0 end x = "1.0e-06" assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}." do _(1.0 / 1000).must_be_close_to 0.0, 0.000001 end assert_triggered "msg.\nExpected |0.0 - 0.001| (0.001) to be <= #{x}." do _(1.0 / 1000).must_be_close_to 0.0, 0.000001, "msg" end end it "needs to verify floats within an epsilon" do @assertion_count += 1 # extra test _(_(6.0 * 7).must_be_within_epsilon(42.0)).must_equal true assert_triggered "Expected |0.0 - 0.01| (0.01) to be <= 0.0." do _(1.0 / 100).must_be_within_epsilon 0.0 end assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= 0.0." do _(1.0 / 1000).must_be_within_epsilon 0.0, 0.000001 end assert_triggered "msg.\nExpected |0.0 - 0.001| (0.001) to be <= 0.0." do _(1.0 / 1000).must_be_within_epsilon 0.0, 0.000001, "msg" end end it "needs to verify identity" do _(_(1).must_be_same_as(1)).must_equal true assert_triggered "Expected 1 (oid=N) to be the same as 2 (oid=N)." do _(1).must_be_same_as 2 end assert_triggered "msg.\nExpected 1 (oid=N) to be the same as 2 (oid=N)." do _(1).must_be_same_as 2, "msg" end end it "needs to verify inequality" do @assertion_count += 2 _(_(42).wont_equal(6 * 9)).must_equal false _(_(proc {}).wont_equal(42)).must_equal false assert_triggered "Expected 1 to not be equal to 1." do _(1).wont_equal 1 end assert_triggered "msg.\nExpected 1 to not be equal to 1." do _(1).wont_equal 1, "msg" end end it "needs to verify instances of a class" do _(_(42).wont_be_instance_of(String)).must_equal false assert_triggered "Expected 42 to not be a kind of #{Int.name}." do _(42).wont_be_kind_of Int end assert_triggered "msg.\nExpected 42 to not be an instance of #{Int.name}." do _(42).wont_be_instance_of Int, "msg" end end it "needs to verify kinds of a class" do @assertion_count += 2 _(_(42).wont_be_kind_of(String)).must_equal false _(_(proc {}).wont_be_kind_of(String)).must_equal false assert_triggered "Expected 42 to not be a kind of #{Int.name}." do _(42).wont_be_kind_of Int end assert_triggered "msg.\nExpected 42 to not be a kind of #{Int.name}." do _(42).wont_be_kind_of Int, "msg" end end it "needs to verify kinds of objects" do @assertion_count += 3 # extra test _(_(6 * 7).must_be_kind_of(Int)).must_equal true _(_(6 * 7).must_be_kind_of(Numeric)).must_equal true assert_triggered "Expected 42 to be a kind of String, not #{Int.name}." do _(6 * 7).must_be_kind_of String end assert_triggered "msg.\nExpected 42 to be a kind of String, not #{Int.name}." do _(6 * 7).must_be_kind_of String, "msg" end exp = "Expected # to be a kind of String, not Proc." assert_triggered exp do _(proc {}).must_be_kind_of String end end it "needs to verify mismatch" do @assertion_count += 3 # match is 2 _(_("blah").wont_match(/\d+/)).must_equal false assert_triggered "Expected /\\w+/ to not match \"blah\"." do _("blah").wont_match(/\w+/) end assert_triggered "msg.\nExpected /\\w+/ to not match \"blah\"." do _("blah").wont_match(/\w+/, "msg") end end it "needs to verify nil" do _(_(nil).must_be_nil).must_equal true assert_triggered "Expected 42 to be nil." do _(42).must_be_nil end assert_triggered "msg.\nExpected 42 to be nil." do _(42).must_be_nil "msg" end end it "needs to verify non-emptyness" do @assertion_count += 3 # empty is 2 assertions _(_(["some item"]).wont_be_empty).must_equal false assert_triggered "Expected [] to not be empty." do _([]).wont_be_empty end assert_triggered "msg.\nExpected [] to not be empty." do _([]).wont_be_empty "msg" end end it "needs to verify non-identity" do _(_(1).wont_be_same_as(2)).must_equal false assert_triggered "Expected 1 (oid=N) to not be the same as 1 (oid=N)." do _(1).wont_be_same_as 1 end assert_triggered "msg.\nExpected 1 (oid=N) to not be the same as 1 (oid=N)." do _(1).wont_be_same_as 1, "msg" end end it "needs to verify non-nil" do _(_(42).wont_be_nil).must_equal false assert_triggered "Expected nil to not be nil." do _(nil).wont_be_nil end assert_triggered "msg.\nExpected nil to not be nil." do _(nil).wont_be_nil "msg" end end it "needs to verify objects not responding to a message" do _(_("").wont_respond_to(:woot!)).must_equal false assert_triggered "Expected \"\" to not respond to to_s." do _("").wont_respond_to :to_s end assert_triggered "msg.\nExpected \"\" to not respond to to_s." do _("").wont_respond_to :to_s, "msg" end end it "needs to verify output in stderr" do @assertion_count -= 1 # no msg _(expect { $stderr.print "blah" }.must_output(nil, "blah")).must_equal true assert_triggered "In stderr.\nExpected: \"blah\"\n Actual: \"xxx\"" do expect { $stderr.print "xxx" }.must_output(nil, "blah") end end it "needs to verify output in stdout" do @assertion_count -= 1 # no msg _(expect { print "blah" }.must_output("blah")).must_equal true assert_triggered "In stdout.\nExpected: \"blah\"\n Actual: \"xxx\"" do expect { print "xxx" }.must_output("blah") end end it "needs to verify regexp matches" do @assertion_count += 3 # must_match is 2 assertions _(_("blah").must_match(/\w+/)).must_equal true assert_triggered "Expected /\\d+/ to match \"blah\"." do _("blah").must_match(/\d+/) end assert_triggered "msg.\nExpected /\\d+/ to match \"blah\"." do _("blah").must_match(/\d+/, "msg") end end describe "expect" do before do @assertion_count -= 3 end it "can use expect" do _(1 + 1).must_equal 2 end it "can use expect with a lambda" do _ { raise "blah" }.must_raise RuntimeError end it "can use expect in a thread" do Thread.new { _(1 + 1).must_equal 2 }.join end it "can NOT use must_equal in a thread. It must use expect in a thread" do skip "N/A" if ENV["MT_NO_EXPECTATIONS"] assert_raises RuntimeError do capture_io do Thread.new { (1 + 1).must_equal 2 }.join end end end it "fails gracefully when expectation used outside of `it`" do skip "N/A" if ENV["MT_NO_EXPECTATIONS"] @assertion_count += 1 e = assert_raises RuntimeError do capture_io do Thread.new { # forces ctx to be nil describe("woot") do (1 + 1).must_equal 2 end }.join end end assert_equal "Calling #must_equal outside of test.", e.message end it "deprecates expectation used without _" do skip "N/A" if ENV["MT_NO_EXPECTATIONS"] @assertion_count += 3 exp = /DEPRECATED: global use of must_equal from/ assert_output "", exp do (1 + 1).must_equal 2 end end end it "needs to verify throw" do @assertion_count += 2 # 2 extra tests _(expect { throw :blah }.must_throw(:blah)).must_equal true assert_triggered "Expected :blah to have been thrown." do expect {}.must_throw :blah end assert_triggered "Expected :blah to have been thrown, not :xxx." do expect { throw :xxx }.must_throw :blah end assert_triggered "msg.\nExpected :blah to have been thrown." do expect {}.must_throw :blah, "msg" end assert_triggered "msg.\nExpected :blah to have been thrown, not :xxx." do expect { throw :xxx }.must_throw :blah, "msg" end end it "needs to verify types of objects" do _(_(6 * 7).must_be_instance_of(Int)).must_equal true exp = "Expected 42 to be an instance of String, not #{Int.name}." assert_triggered exp do _(6 * 7).must_be_instance_of String end assert_triggered "msg.\n#{exp}" do _(6 * 7).must_be_instance_of String, "msg" end end it "needs to verify using any (negative) predicate" do @assertion_count -= 1 # doesn"t take a message _(_("blah").wont_be(:empty?)).must_equal false assert_triggered "Expected \"\" to not be empty?." do _("").wont_be :empty? end end it "needs to verify using any binary operator" do @assertion_count -= 1 # no msg _(_(41).must_be(:<, 42)).must_equal true assert_triggered "Expected 42 to be < 41." do _(42).must_be(:<, 41) end end it "needs to verify using any predicate" do @assertion_count -= 1 # no msg _(_("").must_be(:empty?)).must_equal true assert_triggered "Expected \"blah\" to be empty?." do _("blah").must_be :empty? end end it "needs to verify using respond_to" do _(_(42).must_respond_to(:+)).must_equal true assert_triggered "Expected 42 (#{Int.name}) to respond to #clear." do _(42).must_respond_to :clear end assert_triggered "msg.\nExpected 42 (#{Int.name}) to respond to #clear." do _(42).must_respond_to :clear, "msg" end end end describe Minitest::Spec, :let do i_suck_and_my_tests_are_order_dependent! def _count $let_count ||= 0 end let :count do $let_count += 1 $let_count end it "is evaluated once per example" do _(_count).must_equal 0 _(count).must_equal 1 _(count).must_equal 1 _(_count).must_equal 1 end it "is REALLY evaluated once per example" do _(_count).must_equal 1 _(count).must_equal 2 _(count).must_equal 2 _(_count).must_equal 2 end it 'raises an error if the name begins with "test"' do expect { self.class.let(:test_value) { true } }.must_raise ArgumentError end it "raises an error if the name shadows a normal instance method" do expect { self.class.let(:message) { true } }.must_raise ArgumentError end it "doesn't raise an error if it is just another let" do v = proc do describe :outer do let(:bar) describe :inner do let(:bar) end end :good end.call _(v).must_equal :good end it "procs come after dont_flip" do p = proc {} assert_respond_to p, :call _(p).must_respond_to :call end end describe Minitest::Spec, :subject do attr_reader :subject_evaluation_count subject do @subject_evaluation_count ||= 0 @subject_evaluation_count += 1 @subject_evaluation_count end it "is evaluated once per example" do _(subject).must_equal 1 _(subject).must_equal 1 _(subject_evaluation_count).must_equal 1 end end class TestMetaStatic < Minitest::Test def test_children Minitest::Spec.children.clear # prevents parallel run y = z = nil x = describe "top-level thingy" do y = describe "first thingy" do end it "top-level-it" do end z = describe "second thingy" do end end assert_equal [x], Minitest::Spec.children assert_equal [y, z], x.children assert_equal [], y.children assert_equal [], z.children end def test_it_wont_remove_existing_child_test_methods Minitest::Spec.children.clear # prevents parallel run inner = nil outer = describe "outer" do inner = describe "inner" do it do assert true end end it do assert true end end assert_equal 1, outer.public_instance_methods.grep(/^test_/).count assert_equal 1, inner.public_instance_methods.grep(/^test_/).count end def test_it_wont_add_test_methods_to_children Minitest::Spec.children.clear # prevents parallel run inner = nil outer = describe "outer" do inner = describe "inner" do end it do assert true end end assert_equal 1, outer.public_instance_methods.grep(/^test_/).count assert_equal 0, inner.public_instance_methods.grep(/^test_/).count end end class TestMeta < MetaMetaMetaTestCase # do not call parallelize_me! here because specs use register_spec_type globally def util_structure y = z = nil before_list = [] after_list = [] x = describe "top-level thingy" do before { before_list << 1 } after { after_list << 1 } it "top-level-it" do end y = describe "inner thingy" do before { before_list << 2 } after { after_list << 2 } it "inner-it" do end z = describe "very inner thingy" do before { before_list << 3 } after { after_list << 3 } it "inner-it" do end it { } # ignore me specify { } # anonymous it end end end return x, y, z, before_list, after_list end def test_register_spec_type original_types = Minitest::Spec::TYPES.dup assert_includes Minitest::Spec::TYPES, [//, Minitest::Spec] Minitest::Spec.register_spec_type(/woot/, TestMeta) p = lambda do |_| true end Minitest::Spec.register_spec_type TestMeta, &p keys = Minitest::Spec::TYPES.map(&:first) assert_includes keys, /woot/ assert_includes keys, p ensure Minitest::Spec::TYPES.replace original_types end def test_spec_type original_types = Minitest::Spec::TYPES.dup Minitest::Spec.register_spec_type(/A$/, MiniSpecA) Minitest::Spec.register_spec_type MiniSpecB do |desc| desc.superclass == ExampleA end Minitest::Spec.register_spec_type MiniSpecC do |_desc, *addl| addl.include? :woot end assert_equal MiniSpecA, Minitest::Spec.spec_type(ExampleA) assert_equal MiniSpecB, Minitest::Spec.spec_type(ExampleB) assert_equal MiniSpecC, Minitest::Spec.spec_type(ExampleB, :woot) ensure Minitest::Spec::TYPES.replace original_types end def test_bug_dsl_expectations spec_class = Class.new MiniSpecB do it "should work" do _(0).must_equal 0 end end test_name = spec_class.instance_methods.sort.grep(/test/).first spec = spec_class.new test_name result = spec.run assert spec.passed? assert result.passed? assert_equal 1, result.assertions end def test_name spec_a = describe ExampleA do; end spec_b = describe ExampleB, :random_method do; end spec_c = describe ExampleB, :random_method, :addl_context do; end assert_equal "ExampleA", spec_a.name assert_equal "ExampleB::random_method", spec_b.name assert_equal "ExampleB::random_method::addl_context", spec_c.name end def test_name2 assert_equal "NamedExampleA", NamedExampleA.name assert_equal "NamedExampleB", NamedExampleB.name assert_equal "NamedExampleC", NamedExampleC.name spec_a = describe ExampleA do; end spec_b = describe ExampleB, :random_method do; end assert_equal "ExampleA", spec_a.name assert_equal "ExampleB::random_method", spec_b.name end def test_structure x, y, z, * = util_structure assert_equal "top-level thingy", x.to_s assert_equal "top-level thingy::inner thingy", y.to_s assert_equal "top-level thingy::inner thingy::very inner thingy", z.to_s assert_equal "top-level thingy", x.desc assert_equal "inner thingy", y.desc assert_equal "very inner thingy", z.desc top_methods = %w[setup teardown test_0001_top-level-it] inner_methods1 = %w[setup teardown test_0001_inner-it] inner_methods2 = inner_methods1 + %w[test_0002_anonymous test_0003_anonymous] assert_equal top_methods, x.instance_methods(false).sort.map(&:to_s) assert_equal inner_methods1, y.instance_methods(false).sort.map(&:to_s) assert_equal inner_methods2, z.instance_methods(false).sort.map(&:to_s) end def test_structure_postfix_it z = nil y = describe "outer" do # NOT here, below the inner-describe! # it "inner-it" do end z = describe "inner" do it "inner-it" do end end # defined AFTER inner describe means we'll try to wipe out the inner-it it "inner-it" do end end assert_equal %w[test_0001_inner-it], y.instance_methods(false).map(&:to_s) assert_equal %w[test_0001_inner-it], z.instance_methods(false).map(&:to_s) end def test_setup_teardown_behavior _, _, z, before_list, after_list = util_structure @tu = z run_tu_with_fresh_reporter size = z.runnable_methods.size assert_equal [1, 2, 3] * size, before_list assert_equal [3, 2, 1] * size, after_list end def test_describe_first_structure x1 = x2 = y = z = nil x = describe "top-level thingy" do y = describe "first thingy" do end x1 = it "top level it" do end x2 = it "не латинские &いった α, β, γ, δ, ε hello!!! world" do end z = describe "second thingy" do end end test_methods = ["test_0001_top level it", "test_0002_не латинские &いった α, β, γ, δ, ε hello!!! world", ].sort assert_equal test_methods, [x1, x2] assert_equal test_methods, x.instance_methods.grep(/^test/).map(&:to_s).sort assert_equal [], y.instance_methods.grep(/^test/) assert_equal [], z.instance_methods.grep(/^test/) end def test_structure_subclasses z = nil x = Class.new Minitest::Spec do def xyz; end end y = Class.new x do z = describe("inner") { } end assert_respond_to x.new(nil), "xyz" assert_respond_to y.new(nil), "xyz" assert_respond_to z.new(nil), "xyz" end end class TestSpecInTestCase < MetaMetaMetaTestCase def setup super Thread.current[:current_spec] = self @tc = self @assertion_count = 2 end def assert_triggered expected, klass = Minitest::Assertion @assertion_count += 1 e = assert_raises klass do yield end msg = e.message.sub(/(---Backtrace---).*/m, "\1") msg.gsub!(/\(oid=[-0-9]+\)/, "(oid=N)") assert_equal expected, msg end def teardown msg = "expected #{@assertion_count} assertions, not #{@tc.assertions}" assert_equal @assertion_count, @tc.assertions, msg end def test_expectation @tc.assert_equal true, _(1).must_equal(1) end def test_expectation_triggered assert_triggered "Expected: 2\n Actual: 1" do _(1).must_equal 2 end end include Minitest::Spec::DSL::InstanceMethods def test_expectation_with_a_message assert_triggered "woot.\nExpected: 2\n Actual: 1" do _(1).must_equal 2, "woot" end end end class ValueMonadTest < Minitest::Test attr_accessor :struct def setup @struct = { :_ => "a", :value => "b", :expect => "c" } def @struct.method_missing k # think openstruct self[k] end end def test_value_monad_method assert_equal "a", struct._ end def test_value_monad_value_alias assert_equal "b", struct.value end def test_value_monad_expect_alias assert_equal "c", struct.expect end end PKu]ފ`o`ominitest-5.13.0/README.rdocnu[= minitest/{test,spec,mock,benchmark} home :: https://github.com/seattlerb/minitest bugs :: https://github.com/seattlerb/minitest/issues rdoc :: http://docs.seattlerb.org/minitest vim :: https://github.com/sunaku/vim-ruby-minitest emacs:: https://github.com/arthurnn/minitest-emacs == DESCRIPTION: minitest provides a complete suite of testing facilities supporting TDD, BDD, mocking, and benchmarking. "I had a class with Jim Weirich on testing last week and we were allowed to choose our testing frameworks. Kirk Haines and I were paired up and we cracked open the code for a few test frameworks... I MUST say that minitest is *very* readable / understandable compared to the 'other two' options we looked at. Nicely done and thank you for helping us keep our mental sanity." -- Wayne E. Seguin minitest/test is a small and incredibly fast unit testing framework. It provides a rich set of assertions to make your tests clean and readable. minitest/spec is a functionally complete spec engine. It hooks onto minitest/test and seamlessly bridges test assertions over to spec expectations. minitest/benchmark is an awesome way to assert the performance of your algorithms in a repeatable manner. Now you can assert that your newb co-worker doesn't replace your linear algorithm with an exponential one! minitest/mock by Steven Baker, is a beautifully tiny mock (and stub) object framework. minitest/pride shows pride in testing and adds coloring to your test output. I guess it is an example of how to write IO pipes too. :P minitest/test is meant to have a clean implementation for language implementors that need a minimal set of methods to bootstrap a working test suite. For example, there is no magic involved for test-case discovery. "Again, I can't praise enough the idea of a testing/specing framework that I can actually read in full in one sitting!" -- Piotr Szotkowski Comparing to rspec: rspec is a testing DSL. minitest is ruby. -- Adam Hawkins, "Bow Before MiniTest" minitest doesn't reinvent anything that ruby already provides, like: classes, modules, inheritance, methods. This means you only have to learn ruby to use minitest and all of your regular OO practices like extract-method refactorings still apply. == FEATURES/PROBLEMS: * minitest/autorun - the easy and explicit way to run all your tests. * minitest/test - a very fast, simple, and clean test system. * minitest/spec - a very fast, simple, and clean spec system. * minitest/mock - a simple and clean mock/stub system. * minitest/benchmark - an awesome way to assert your algorithm's performance. * minitest/pride - show your pride in testing! * Incredibly small and fast runner, but no bells and whistles. * Written by squishy human beings. Software can never be perfect. We will all eventually die. == RATIONALE: See design_rationale.rb to see how specs and tests work in minitest. == SYNOPSIS: Given that you'd like to test the following class: class Meme def i_can_has_cheezburger? "OHAI!" end def will_it_blend? "YES!" end end === Unit tests Define your tests as methods beginning with +test_+. require "minitest/autorun" class TestMeme < Minitest::Test def setup @meme = Meme.new end def test_that_kitty_can_eat assert_equal "OHAI!", @meme.i_can_has_cheezburger? end def test_that_it_will_not_blend refute_match /^no/i, @meme.will_it_blend? end def test_that_will_be_skipped skip "test this later" end end === Specs require "minitest/autorun" describe Meme do before do @meme = Meme.new end describe "when asked about cheeseburgers" do it "must respond positively" do _(@meme.i_can_has_cheezburger?).must_equal "OHAI!" end end describe "when asked about blending possibilities" do it "won't say no" do _(@meme.will_it_blend?).wont_match /^no/i end end end For matchers support check out: * https://github.com/wojtekmach/minitest-matchers * https://github.com/rmm5t/minitest-matchers_vaccine === Benchmarks Add benchmarks to your tests. # optionally run benchmarks, good for CI-only work! require "minitest/benchmark" if ENV["BENCH"] class TestMeme < Minitest::Benchmark # Override self.bench_range or default range is [1, 10, 100, 1_000, 10_000] def bench_my_algorithm assert_performance_linear 0.9999 do |n| # n is a range value @obj.my_algorithm(n) end end end Or add them to your specs. If you make benchmarks optional, you'll need to wrap your benchmarks in a conditional since the methods won't be defined. In minitest 5, the describe name needs to match /Bench(mark)?$/. describe "Meme Benchmark" do if ENV["BENCH"] then bench_performance_linear "my_algorithm", 0.9999 do |n| 100.times do @obj.my_algorithm(n) end end end end outputs something like: # Running benchmarks: TestBlah 100 1000 10000 bench_my_algorithm 0.006167 0.079279 0.786993 bench_other_algorithm 0.061679 0.792797 7.869932 Output is tab-delimited to make it easy to paste into a spreadsheet. === Mocks Mocks and stubs defined using terminology by Fowler & Meszaros at http://www.martinfowler.com/bliki/TestDouble.html: "Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting." class MemeAsker def initialize(meme) @meme = meme end def ask(question) method = question.tr(" ", "_") + "?" @meme.__send__(method) end end require "minitest/autorun" describe MemeAsker, :ask do describe "when passed an unpunctuated question" do it "should invoke the appropriate predicate method on the meme" do @meme = Minitest::Mock.new @meme_asker = MemeAsker.new @meme @meme.expect :will_it_blend?, :return_value @meme_asker.ask "will it blend" @meme.verify end end end ==== Multi-threading and Mocks Minitest mocks do not support multi-threading. If it works, fine, if it doesn't you can use regular ruby patterns and facilities like local variables. Here's an example of asserting that code inside a thread is run: def test_called_inside_thread called = false pr = Proc.new { called = true } thread = Thread.new(&pr) thread.join assert called, "proc not called" end === Stubs Mocks and stubs are defined using terminology by Fowler & Meszaros at http://www.martinfowler.com/bliki/TestDouble.html: "Stubs provide canned answers to calls made during the test". Minitest's stub method overrides a single method for the duration of the block. def test_stale_eh obj_under_test = Something.new refute obj_under_test.stale? Time.stub :now, Time.at(0) do # stub goes away once the block is done assert obj_under_test.stale? end end A note on stubbing: In order to stub a method, the method must actually exist prior to stubbing. Use a singleton method to create a new non-existing method: def obj_under_test.fake_method ... end === Running Your Tests Ideally, you'll use a rake task to run your tests, either piecemeal or all at once. Both rake and rails ship with rake tasks for running your tests. BUT! You don't have to: % ruby -Ilib:test test/minitest/test_minitest_test.rb Run options: --seed 37685 # Running: ...................................................................... (etc) Finished in 0.107130s, 1446.8403 runs/s, 2959.0217 assertions/s. 155 runs, 317 assertions, 0 failures, 0 errors, 0 skips There are runtime options available, both from minitest itself, and also provided via plugins. To see them, simply run with +--help+: % ruby -Ilib:test test/minitest/test_minitest_test.rb --help minitest options: -h, --help Display this help. -s, --seed SEED Sets random seed. Also via env. Eg: SEED=n rake -v, --verbose Verbose. Show progress processing files. -n, --name PATTERN Filter run on /regexp/ or string. -e, --exclude PATTERN Exclude /regexp/ or string from run. Known extensions: pride, autotest -p, --pride Pride. Show your testing pride! -a, --autotest Connect to autotest server. You can set up a rake task to run all your tests by adding this to your Rakefile: require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList["test/**/test_*.rb"] end task :default => :test == Writing Extensions To define a plugin, add a file named minitest/XXX_plugin.rb to your project/gem. That file must be discoverable via ruby's LOAD_PATH (via rubygems or otherwise). Minitest will find and require that file using Gem.find_files. It will then try to call +plugin_XXX_init+ during startup. The option processor will also try to call +plugin_XXX_options+ passing the OptionParser instance and the current options hash. This lets you register your own command-line options. Here's a totally bogus example: # minitest/bogus_plugin.rb: module Minitest def self.plugin_bogus_options(opts, options) opts.on "--myci", "Report results to my CI" do options[:myci] = true options[:myci_addr] = get_myci_addr options[:myci_port] = get_myci_port end end def self.plugin_bogus_init(options) self.reporter << MyCI.new(options) if options[:myci] end end === Adding custom reporters Minitest uses composite reporter to output test results using multiple reporter instances. You can add new reporters to the composite during the init_plugins phase. As we saw in +plugin_bogus_init+ above, you simply add your reporter instance to the composite via <<. +AbstractReporter+ defines the API for reporters. You may subclass it and override any method you want to achieve your desired behavior. start :: Called when the run has started. record :: Called for each result, passed or otherwise. report :: Called at the end of the run. passed? :: Called to see if you detected any problems. Using our example above, here is how we might implement MyCI: # minitest/bogus_plugin.rb module Minitest class MyCI < AbstractReporter attr_accessor :results, :addr, :port def initialize options self.results = [] self.addr = options[:myci_addr] self.port = options[:myci_port] end def record result self.results << result end def report CI.connect(addr, port).send_results self.results end end # code from above... end == FAQ === How to test SimpleDelegates? The following implementation and test: class Worker < SimpleDelegator def work end end describe Worker do before do @worker = Worker.new(Object.new) end it "must respond to work" do _(@worker).must_respond_to :work end end outputs a failure: 1) Failure: Worker#test_0001_must respond to work [bug11.rb:16]: Expected # (Object) to respond to #work. Worker is a SimpleDelegate which in 1.9+ is a subclass of BasicObject. Expectations are put on Object (one level down) so the Worker (SimpleDelegate) hits +method_missing+ and delegates down to the +Object.new+ instance. That object doesn't respond to work so the test fails. You can bypass SimpleDelegate#method_missing by extending the worker with Minitest::Expectations. You can either do that in your setup at the instance level, like: before do @worker = Worker.new(Object.new) @worker.extend Minitest::Expectations end or you can extend the Worker class (within the test file!), like: class Worker include ::Minitest::Expectations end === How to share code across test classes? Use a module. That's exactly what they're for: module UsefulStuff def useful_method # ... end end describe Blah do include UsefulStuff def test_whatever # useful_method available here end end Remember, +describe+ simply creates test classes. It's just ruby at the end of the day and all your normal Good Ruby Rules (tm) apply. If you want to extend your test using setup/teardown via a module, just make sure you ALWAYS call super. before/after automatically call super for you, so make sure you don't do it twice. === How to run code before a group of tests? Use a constant with begin...end like this: describe Blah do SETUP = begin # ... this runs once when describe Blah starts end # ... end This can be useful for expensive initializations or sharing state. Remember, this is just ruby code, so you need to make sure this technique and sharing state doesn't interfere with your tests. === Why am I seeing uninitialized constant MiniTest::Test (NameError)? Are you running the test with Bundler (e.g. via bundle exec )? If so, in order to require minitest, you must first add the gem 'minitest' to your Gemfile and run +bundle+. Once it's installed, you should be able to require minitest and run your tests. == Prominent Projects using Minitest: * arel * journey * mime-types * nokogiri * rails (active_support et al) * rake * rdoc * ...and of course, everything from seattle.rb... == Developing Minitest: Minitest requires {Hoe}[https://rubygems.org/gems/hoe]. === Minitest's own tests require UTF-8 external encoding. This is a common problem in Windows, where the default external Encoding is often CP850, but can affect any platform. Minitest can run test suites using any Encoding, but to run Minitest's own tests you must have a default external Encoding of UTF-8. If your encoding is wrong, you'll see errors like: --- expected +++ actual @@ -1,2 +1,3 @@ # encoding: UTF-8 -"Expected /\\w+/ to not match \"blah blah blah\"." +"Expected /\\w+/ to not match # encoding: UTF-8 +\"blah blah blah\"." To check your current encoding, run: ruby -e 'puts Encoding.default_external' If your output is something other than UTF-8, you can set the RUBYOPTS env variable to a value of '-Eutf-8'. Something like: RUBYOPT='-Eutf-8' ruby -e 'puts Encoding.default_external' Check your OS/shell documentation for the precise syntax (the above will not work on a basic Windows CMD prompt, look for the SET command). Once you've got it successfully outputing UTF-8, use the same setting when running rake in Minitest. === Minitest's own tests require GNU (or similar) diff. This is also a problem primarily affecting Windows developers. PowerShell has a command called diff, but it is not suitable for use with Minitest. If you see failures like either of these, you are probably missing diff tool: 4) Failure: TestMinitestUnitTestCase#test_assert_equal_different_long [D:/ruby/seattlerb/minitest/test/minitest/test_minitest_test.rb:936]: Expected: "--- expected\n+++ actual\n@@ -1 +1 @@\n-\"hahahahahahahahahahahahahahahahahahahaha\"\n+\"blahblahblahblahblahblahblahblahblahblah\"\n" Actual: "Expected: \"hahahahahahahahahahahahahahahahahahahaha\"\n Actual: \"blahblahblahblahblahblahblahblahblahblah\"" 5) Failure: TestMinitestUnitTestCase#test_assert_equal_different_collection_hash_hex_invisible [D:/ruby/seattlerb/minitest/test/minitest/test_minitest_test.rb:845]: Expected: "No visible difference in the Hash#inspect output.\nYou should look at the implementation of #== on Hash or its members.\n {1=>#}" Actual: "Expected: {1=>#}\n Actual: {1=>#}" If you use Cygwin or MSYS2 or similar there are packages that include a GNU diff for Windows. If you don't, you can download GNU diffutils from http://gnuwin32.sourceforge.net/packages/diffutils.htm (make sure to add it to your PATH). You can make sure it's installed and path is configured properly with: diff.exe -v There are multiple lines of output, the first should be something like: diff (GNU diffutils) 2.8.1 If you are using PowerShell make sure you run diff.exe, not just diff, which will invoke the PowerShell built in function. == Known Extensions: capybara_minitest_spec :: Bridge between Capybara RSpec matchers and Minitest::Spec expectations (e.g. page.must_have_content("Title")). color_pound_spec_reporter :: Test names print Ruby Object types in color with your Minitest Spec style tests. minispec-metadata :: Metadata for describe/it blocks & CLI tag filter. E.g. it "requires JS driver", js: true do & ruby test.rb --tag js runs tests tagged :js. minispec-rails :: Minimal support to use Spec style in Rails 5+. mini-apivore :: for swagger based automated API testing. minitest-around :: Around block for minitest. An alternative to setup/teardown dance. minitest-assert_errors :: Adds Minitest assertions to test for errors raised or not raised by Minitest itself. minitest-autotest :: autotest is a continuous testing facility meant to be used during development. minitest-bacon :: minitest-bacon extends minitest with bacon-like functionality. minitest-bang :: Adds support for RSpec-style let! to immediately invoke let statements before each test. minitest-bisect :: Helps you isolate and debug random test failures. minitest-blink1_reporter :: Display test results with a Blink1. minitest-capistrano :: Assertions and expectations for testing Capistrano recipes. minitest-capybara :: Capybara matchers support for minitest unit and spec. minitest-chef-handler :: Run Minitest suites as Chef report handlers minitest-ci :: CI reporter plugin for Minitest. minitest-context :: Defines contexts for code reuse in Minitest specs that share common expectations. minitest-debugger :: Wraps assert so failed assertions drop into the ruby debugger. minitest-display :: Patches Minitest to allow for an easily configurable output. minitest-documentation :: Minimal documentation format inspired by rspec's. minitest-doc_reporter :: Detailed output inspired by rspec's documentation format. minitest-emoji :: Print out emoji for your test passes, fails, and skips. minitest-english :: Semantically symmetric aliases for assertions and expectations. minitest-excludes :: Clean API for excluding certain tests you don't want to run under certain conditions. minitest-fail-fast :: Reimplements RSpec's "fail fast" feature minitest-filecontent :: Support unit tests with expectation results in files. Differing results will be stored again in files. minitest-filesystem :: Adds assertion and expectation to help testing filesystem contents. minitest-firemock :: Makes your Minitest mocks more resilient. minitest-focus :: Focus on one test at a time. minitest-gcstats :: A minitest plugin that adds a report of the top tests by number of objects allocated. minitest-global_expectations:: Support minitest expectation methods for all objects minitest-great_expectations :: Generally useful additions to minitest's assertions and expectations. minitest-growl :: Test notifier for minitest via growl. minitest-happy :: GLOBALLY ACTIVATE MINITEST PRIDE! RAWR! minitest-have_tag :: Adds Minitest assertions to test for the existence of HTML tags, including contents, within a provided string. minitest-hooks :: Around and before_all/after_all/around_all hooks minitest-hyper :: Pretty, single-page HTML reports for your Minitest runs minitest-implicit-subject :: Implicit declaration of the test subject. minitest-instrument :: Instrument ActiveSupport::Notifications when test method is executed. minitest-instrument-db :: Store information about speed of test execution provided by minitest-instrument in database. minitest-junit :: JUnit-style XML reporter for minitest. minitest-keyword :: Use Minitest assertions with keyword arguments. minitest-libnotify :: Test notifier for minitest via libnotify. minitest-line :: Run test at line number. minitest-logger :: Define assert_log and enable minitest to test log messages. Supports Logger and Log4r::Logger. minitest-macruby :: Provides extensions to minitest for macruby UI testing. minitest-matchers :: Adds support for RSpec-style matchers to minitest. minitest-matchers_vaccine :: Adds assertions that adhere to the matcher spec, but without any expectation infections. minitest-metadata :: Annotate tests with metadata (key-value). minitest-mock_expectations :: Provides method call assertions for minitest. minitest-mongoid :: Mongoid assertion matchers for Minitest. minitest-must_not :: Provides must_not as an alias for wont in Minitest. minitest-optional_retry :: Automatically retry failed test to help with flakiness. minitest-osx :: Reporter for the Mac OS X notification center. minitest-parallel_fork :: Fork-based parallelization minitest-parallel-db :: Run tests in parallel with a single database. minitest-power_assert :: PowerAssert for Minitest. minitest-predicates :: Adds support for .predicate? methods. minitest-profile :: List the 10 slowest tests in your suite. minitest-rails :: Minitest integration for Rails 3.x. minitest-rails-capybara :: Capybara integration for Minitest::Rails. minitest-reporters :: Create customizable Minitest output formats. minitest-rg :: Colored red/green output for Minitest. minitest-rspec_mocks :: Use RSpec Mocks with Minitest. minitest-server :: minitest-server provides a client/server setup with your minitest process, allowing your test run to send its results directly to a handler. minitest-sequel :: Minitest assertions to speed-up development and testing of Ruby Sequel database setups. minitest-shared_description :: Support for shared specs and shared spec subclasses minitest-should_syntax :: RSpec-style x.should == y assertions for Minitest. minitest-shouldify :: Adding all manner of shoulds to Minitest (bad idea) minitest-snail :: Print a list of tests that take too long minitest-spec-context :: Provides rspec-ish context method to Minitest::Spec. minitest-spec-expect :: Expect syntax for Minitest::Spec (e.g. expect(sequences).to_include :celery_man). minitest-spec-magic :: Minitest::Spec extensions for Rails and beyond. minitest-spec-rails :: Drop in Minitest::Spec superclass for ActiveSupport::TestCase. minitest-sprint :: Runs (Get it? It's fast!) your tests and makes it easier to rerun individual failures. minitest-stately :: Find leaking state between tests minitest-stub_any_instance :: Stub any instance of a method on the given class for the duration of a block. minitest-stub-const :: Stub constants for the duration of a block. minitest-tags :: Add tags for minitest. minitest-unordered :: Adds a new assertion to minitest for checking the contents of a collection, ignoring element order. minitest-vcr :: Automatic cassette managment with Minitest::Spec and VCR. minitest_owrapper :: Get tests results as a TestResult object. minitest_should :: Shoulda style syntax for minitest test::unit. minitest_tu_shim :: Bridges between test/unit and minitest. mongoid-minitest :: Minitest matchers for Mongoid. mutant-minitest :: Minitest integration for mutant. pry-rescue :: A pry plugin w/ minitest support. See pry-rescue/minitest.rb. rspec2minitest :: Easily translate any RSpec matchers to Minitest assertions and expectations. == Unknown Extensions: Authors... Please send me a pull request with a description of your minitest extension. * assay-minitest * detroit-minitest * em-minitest-spec * flexmock-minitest * guard-minitest * guard-minitest-decisiv * minitest-activemodel * minitest-ar-assertions * minitest-capybara-unit * minitest-colorer * minitest-deluxe * minitest-extra-assertions * minitest-rails-shoulda * minitest-spec * minitest-spec-should * minitest-sugar * spork-minitest == Minitest related goods * minitest/pride fabric: http://www.spoonflower.com/fabric/3928730-again-by-katie_allen == REQUIREMENTS: * Ruby 2.3+. No magic is involved. I hope. == INSTALL: sudo gem install minitest On 1.9, you already have it. To get newer candy you can still install the gem, and then requiring "minitest/autorun" should automatically pull it in. If not, you'll need to do it yourself: gem "minitest" # ensures you"re using the gem, and not the built-in MT require "minitest/autorun" # ... usual testing stuffs ... DO NOTE: There is a serious problem with the way that ruby 1.9/2.0 packages their own gems. They install a gem specification file, but don't install the gem contents in the gem path. This messes up Gem.find_files and many other things (gem which, gem contents, etc). Just install minitest as a gem for real and you'll be happier. == LICENSE: (The MIT License) Copyright (c) Ryan Davis, seattle.rb Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PKu].`.`minitest-5.13.0/lib/minitest.rbnu[require "optparse" require "thread" require "mutex_m" require "minitest/parallel" require "stringio" ## # :include: README.rdoc module Minitest VERSION = "5.13.0" # :nodoc: ENCS = "".respond_to? :encoding # :nodoc: @@installed_at_exit ||= false @@after_run = [] @extensions = [] mc = (class << self; self; end) ## # Parallel test executor mc.send :attr_accessor, :parallel_executor warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"] n_threads = (ENV["MT_CPU"] || ENV["N"] || 2).to_i self.parallel_executor = Parallel::Executor.new n_threads ## # Filter object for backtraces. mc.send :attr_accessor, :backtrace_filter ## # Reporter object to be used for all runs. # # NOTE: This accessor is only available during setup, not during runs. mc.send :attr_accessor, :reporter ## # Names of known extension plugins. mc.send :attr_accessor, :extensions ## # The signal to use for dumping information to STDERR. Defaults to "INFO". mc.send :attr_accessor, :info_signal self.info_signal = "INFO" ## # Registers Minitest to run at process exit def self.autorun at_exit { next if $! and not ($!.kind_of? SystemExit and $!.success?) exit_code = nil pid = Process.pid at_exit { next if Process.pid != pid @@after_run.reverse_each(&:call) exit exit_code || false } exit_code = Minitest.run ARGV } unless @@installed_at_exit @@installed_at_exit = true end ## # A simple hook allowing you to run a block of code after everything # is done running. Eg: # # Minitest.after_run { p $debugging_info } def self.after_run &block @@after_run << block end def self.init_plugins options # :nodoc: self.extensions.each do |name| msg = "plugin_#{name}_init" send msg, options if self.respond_to? msg end end def self.load_plugins # :nodoc: return unless self.extensions.empty? seen = {} require "rubygems" unless defined? Gem Gem.find_files("minitest/*_plugin.rb").each do |plugin_path| name = File.basename plugin_path, "_plugin.rb" next if seen[name] seen[name] = true require plugin_path self.extensions << name end end ## # This is the top-level run method. Everything starts from here. It # tells each Runnable sub-class to run, and each of those are # responsible for doing whatever they do. # # The overall structure of a run looks like this: # # Minitest.autorun # Minitest.run(args) # Minitest.__run(reporter, options) # Runnable.runnables.each # runnable.run(reporter, options) # self.runnable_methods.each # self.run_one_method(self, runnable_method, reporter) # Minitest.run_one_method(klass, runnable_method) # klass.new(runnable_method).run def self.run args = [] self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"] options = process_args args reporter = CompositeReporter.new reporter << SummaryReporter.new(options[:io], options) reporter << ProgressReporter.new(options[:io], options) self.reporter = reporter # this makes it available to plugins self.init_plugins options self.reporter = nil # runnables shouldn't depend on the reporter, ever self.parallel_executor.start if parallel_executor.respond_to?(:start) reporter.start begin __run reporter, options rescue Interrupt warn "Interrupted. Exiting..." end self.parallel_executor.shutdown reporter.report reporter.passed? end ## # Internal run method. Responsible for telling all Runnable # sub-classes to run. def self.__run reporter, options suites = Runnable.runnables.reject { |s| s.runnable_methods.empty? }.shuffle parallel, serial = suites.partition { |s| s.test_order == :parallel } # If we run the parallel tests before the serial tests, the parallel tests # could run in parallel with the serial tests. This would be bad because # the serial tests won't lock around Reporter#record. Run the serial tests # first, so that after they complete, the parallel tests will lock when # recording results. serial.map { |suite| suite.run reporter, options } + parallel.map { |suite| suite.run reporter, options } end def self.process_args args = [] # :nodoc: options = { :io => $stdout, } orig_args = args.dup OptionParser.new do |opts| opts.banner = "minitest options:" opts.version = Minitest::VERSION opts.on "-h", "--help", "Display this help." do puts opts exit end opts.on "--no-plugins", "Bypass minitest plugin auto-loading (or set $MT_NO_PLUGINS)." desc = "Sets random seed. Also via env. Eg: SEED=n rake" opts.on "-s", "--seed SEED", Integer, desc do |m| options[:seed] = m.to_i end opts.on "-v", "--verbose", "Verbose. Show progress processing files." do options[:verbose] = true end opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a| options[:filter] = a end opts.on "-e", "--exclude PATTERN", "Exclude /regexp/ or string from run." do |a| options[:exclude] = a end unless extensions.empty? opts.separator "" opts.separator "Known extensions: #{extensions.join(", ")}" extensions.each do |meth| msg = "plugin_#{meth}_options" send msg, opts, options if self.respond_to?(msg) end end begin opts.parse! args rescue OptionParser::InvalidOption => e puts puts e puts puts opts exit 1 end orig_args -= args end unless options[:seed] then srand options[:seed] = (ENV["SEED"] || srand).to_i % 0xFFFF orig_args << "--seed" << options[:seed].to_s end srand options[:seed] options[:args] = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " " options end def self.filter_backtrace bt # :nodoc: backtrace_filter.filter bt end ## # Represents anything "runnable", like Test, Spec, Benchmark, or # whatever you can dream up. # # Subclasses of this are automatically registered and available in # Runnable.runnables. class Runnable ## # Number of assertions executed in this run. attr_accessor :assertions ## # An assertion raised during the run, if any. attr_accessor :failures ## # The time it took to run. attr_accessor :time def time_it # :nodoc: t0 = Minitest.clock_time yield ensure self.time = Minitest.clock_time - t0 end ## # Name of the run. def name @NAME end ## # Set the name of the run. def name= o @NAME = o end ## # Returns all instance methods matching the pattern +re+. def self.methods_matching re public_instance_methods(true).grep(re).map(&:to_s) end def self.reset # :nodoc: @@runnables = [] end reset ## # Responsible for running all runnable methods in a given class, # each in its own instance. Each instance is passed to the # reporter to record. def self.run reporter, options = {} filter = options[:filter] || "/./" filter = Regexp.new $1 if filter.is_a?(String) && filter =~ %r%/(.*)/% filtered_methods = self.runnable_methods.find_all { |m| filter === m || filter === "#{self}##{m}" } exclude = options[:exclude] exclude = Regexp.new $1 if exclude =~ %r%/(.*)/% filtered_methods.delete_if { |m| exclude === m || exclude === "#{self}##{m}" } return if filtered_methods.empty? with_info_handler reporter do filtered_methods.each do |method_name| run_one_method self, method_name, reporter end end end ## # Runs a single method and has the reporter record the result. # This was considered internal API but is factored out of run so # that subclasses can specialize the running of an individual # test. See Minitest::ParallelTest::ClassMethods for an example. def self.run_one_method klass, method_name, reporter reporter.prerecord klass, method_name reporter.record Minitest.run_one_method(klass, method_name) end def self.with_info_handler reporter, &block # :nodoc: handler = lambda do unless reporter.passed? then warn "Current results:" warn "" warn reporter.reporters.first warn "" end end on_signal ::Minitest.info_signal, handler, &block end SIGNALS = Signal.list # :nodoc: def self.on_signal name, action # :nodoc: supported = SIGNALS[name] old_trap = trap name do old_trap.call if old_trap.respond_to? :call action.call end if supported yield ensure trap name, old_trap if supported end ## # Each subclass of Runnable is responsible for overriding this # method to return all runnable methods. See #methods_matching. def self.runnable_methods raise NotImplementedError, "subclass responsibility" end ## # Returns all subclasses of Runnable. def self.runnables @@runnables end @@marshal_dump_warned = false def marshal_dump # :nodoc: unless @@marshal_dump_warned then warn ["Minitest::Runnable#marshal_dump is deprecated.", "You might be violating internals. From", caller.first].join " " @@marshal_dump_warned = true end [self.name, self.failures, self.assertions, self.time] end def marshal_load ary # :nodoc: self.name, self.failures, self.assertions, self.time = ary end def failure # :nodoc: self.failures.first end def initialize name # :nodoc: self.name = name self.failures = [] self.assertions = 0 end ## # Runs a single method. Needs to return self. def run raise NotImplementedError, "subclass responsibility" end ## # Did this run pass? # # Note: skipped runs are not considered passing, but they don't # cause the process to exit non-zero. def passed? raise NotImplementedError, "subclass responsibility" end ## # Returns a single character string to print based on the result # of the run. One of ".", "F", # "E" or "S". def result_code raise NotImplementedError, "subclass responsibility" end ## # Was this run skipped? See #passed? for more information. def skipped? raise NotImplementedError, "subclass responsibility" end end ## # Shared code for anything that can get passed to a Reporter. See # Minitest::Test & Minitest::Result. module Reportable ## # Did this run pass? # # Note: skipped runs are not considered passing, but they don't # cause the process to exit non-zero. def passed? not self.failure end ## # The location identifier of this test. Depends on a method # existing called class_name. def location loc = " [#{self.failure.location}]" unless passed? or error? "#{self.class_name}##{self.name}#{loc}" end def class_name # :nodoc: raise NotImplementedError, "subclass responsibility" end ## # Returns ".", "F", or "E" based on the result of the run. def result_code self.failure and self.failure.result_code or "." end ## # Was this run skipped? def skipped? self.failure and Skip === self.failure end ## # Did this run error? def error? self.failures.any? { |f| UnexpectedError === f } end end ## # This represents a test result in a clean way that can be # marshalled over a wire. Tests can do anything they want to the # test instance and can create conditions that cause Marshal.dump to # blow up. By using Result.from(a_test) you can be reasonably sure # that the test result can be marshalled. class Result < Runnable include Minitest::Reportable undef_method :marshal_dump undef_method :marshal_load ## # The class name of the test result. attr_accessor :klass ## # The location of the test method. attr_accessor :source_location ## # Create a new test result from a Runnable instance. def self.from runnable o = runnable r = self.new o.name r.klass = o.class.name r.assertions = o.assertions r.failures = o.failures.dup r.time = o.time r.source_location = o.method(o.name).source_location rescue ["unknown", -1] r end def class_name # :nodoc: self.klass # for Minitest::Reportable end def to_s # :nodoc: return location if passed? and not skipped? failures.map { |failure| "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n" }.join "\n" end end ## # Defines the API for Reporters. Subclass this and override whatever # you want. Go nuts. class AbstractReporter include Mutex_m ## # Starts reporting on the run. def start end ## # About to start running a test. This allows a reporter to show # that it is starting or that we are in the middle of a test run. def prerecord klass, name end ## # Output and record the result of the test. Call # {result#result_code}[rdoc-ref:Runnable#result_code] to get the # result character string. Stores the result of the run if the run # did not pass. def record result end ## # Outputs the summary of the run. def report end ## # Did this run pass? def passed? true end end class Reporter < AbstractReporter # :nodoc: ## # The IO used to report. attr_accessor :io ## # Command-line options for this run. attr_accessor :options def initialize io = $stdout, options = {} # :nodoc: super() self.io = io self.options = options end end ## # A very simple reporter that prints the "dots" during the run. # # This is added to the top-level CompositeReporter at the start of # the run. If you want to change the output of minitest via a # plugin, pull this out of the composite and replace it with your # own. class ProgressReporter < Reporter def prerecord klass, name #:nodoc: if options[:verbose] then io.print "%s#%s = " % [klass.name, name] io.flush end end def record result # :nodoc: io.print "%.2f s = " % [result.time] if options[:verbose] io.print result.result_code io.puts if options[:verbose] end end ## # A reporter that gathers statistics about a test run. Does not do # any IO because meant to be used as a parent class for a reporter # that does. # # If you want to create an entirely different type of output (eg, # CI, HTML, etc), this is the place to start. # # Example: # # class JenkinsCIReporter < StatisticsReporter # def report # super # Needed to calculate some statistics # # print " 30 characters. # 3. or: Strings are equal to each other (but maybe different encodings?). # 4. and: we found a diff executable. def things_to_diff exp, act expect = mu_pp_for_diff exp butwas = mu_pp_for_diff act e1, e2 = expect.include?("\n"), expect.include?("\\n") b1, b2 = butwas.include?("\n"), butwas.include?("\\n") need_to_diff = (e1 ^ e2 || b1 ^ b2 || expect.size > 30 || butwas.size > 30 || expect == butwas) && Minitest::Assertions.diff need_to_diff && [expect, butwas] end ## # This returns a human-readable version of +obj+. By default # #inspect is called. You can override this to use #pretty_inspect # if you want. # # See Minitest::Test.make_my_diffs_pretty! def mu_pp obj s = obj.inspect if defined? Encoding then s = s.encode Encoding.default_external if String === obj && (obj.encoding != Encoding.default_external || !obj.valid_encoding?) then enc = "# encoding: #{obj.encoding}" val = "# valid: #{obj.valid_encoding?}" s = "#{enc}\n#{val}\n#{s}" end end s end ## # This returns a diff-able more human-readable version of +obj+. # This differs from the regular mu_pp because it expands escaped # newlines and makes hex-values (like object_ids) generic. This # uses mu_pp to do the first pass and then cleans it up. def mu_pp_for_diff obj str = mu_pp obj # both '\n' & '\\n' (_after_ mu_pp (aka inspect)) single = !!str.match(/(?exp == act
    printing the difference between # the two, if possible. # # If there is no visible difference but the assertion fails, you # should suspect that your #== is buggy, or your inspect output is # missing crucial details. For nicer structural diffing, set # Minitest::Test.make_my_diffs_pretty! # # For floats use assert_in_delta. # # See also: Minitest::Assertions.diff def assert_equal exp, act, msg = nil msg = message(msg, E) { diff exp, act } result = assert exp == act, msg if nil == exp then if Minitest::VERSION =~ /^6/ then refute_nil exp, "Use assert_nil if expecting nil." else where = Minitest.filter_backtrace(caller).first where = where.split(/:in /, 2).first # clean up noise warn "DEPRECATED: Use assert_nil if expecting nil from #{where}. This will fail in Minitest 6." end end result end ## # For comparing Floats. Fails unless +exp+ and +act+ are within +delta+ # of each other. # # assert_in_delta Math::PI, (22.0 / 7.0), 0.01 def assert_in_delta exp, act, delta = 0.001, msg = nil n = (exp - act).abs msg = message(msg) { "Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}" } assert delta >= n, msg end ## # For comparing Floats. Fails unless +exp+ and +act+ have a relative # error less than +epsilon+. def assert_in_epsilon exp, act, epsilon = 0.001, msg = nil assert_in_delta exp, act, [exp.abs, act.abs].min * epsilon, msg end ## # Fails unless +collection+ includes +obj+. def assert_includes collection, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" } assert_respond_to collection, :include? assert collection.include?(obj), msg end ## # Fails unless +obj+ is an instance of +cls+. def assert_instance_of cls, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}" } assert obj.instance_of?(cls), msg end ## # Fails unless +obj+ is a kind of +cls+. def assert_kind_of cls, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" } assert obj.kind_of?(cls), msg end ## # Fails unless +matcher+ =~ +obj+. def assert_match matcher, obj, msg = nil msg = message(msg) { "Expected #{mu_pp matcher} to match #{mu_pp obj}" } assert_respond_to matcher, :"=~" matcher = Regexp.new Regexp.escape matcher if String === matcher assert matcher =~ obj, msg end ## # Fails unless +obj+ is nil def assert_nil obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" } assert obj.nil?, msg end ## # For testing with binary operators. Eg: # # assert_operator 5, :<=, 4 def assert_operator o1, op, o2 = UNDEFINED, msg = nil return assert_predicate o1, op, msg if UNDEFINED == o2 msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" } assert o1.__send__(op, o2), msg end ## # Fails if stdout or stderr do not output the expected results. # Pass in nil if you don't care about that streams output. Pass in # "" if you require it to be silent. Pass in a regexp if you want # to pattern match. # # assert_output(/hey/) { method_with_output } # # NOTE: this uses #capture_io, not #capture_subprocess_io. # # See also: #assert_silent def assert_output stdout = nil, stderr = nil flunk "assert_output requires a block to capture output." unless block_given? out, err = capture_io do yield end err_msg = Regexp === stderr ? :assert_match : :assert_equal if stderr out_msg = Regexp === stdout ? :assert_match : :assert_equal if stdout y = send err_msg, stderr, err, "In stderr" if err_msg x = send out_msg, stdout, out, "In stdout" if out_msg (!stdout || x) && (!stderr || y) end ## # Fails unless +path+ exists. def assert_path_exists path, msg = nil msg = message(msg) { "Expected path '#{path}' to exist" } assert File.exist?(path), msg end ## # For testing with predicates. Eg: # # assert_predicate str, :empty? # # This is really meant for specs and is front-ended by assert_operator: # # str.must_be :empty? def assert_predicate o1, op, msg = nil msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op}" } assert o1.__send__(op), msg end ## # Fails unless the block raises one of +exp+. Returns the # exception matched so you can check the message, attributes, etc. # # +exp+ takes an optional message on the end to help explain # failures and defaults to StandardError if no exception class is # passed. Eg: # # assert_raises(CustomError) { method_with_custom_error } # # With custom error message: # # assert_raises(CustomError, 'This should have raised CustomError') { method_with_custom_error } # # Using the returned object: # # error = assert_raises(CustomError) do # raise CustomError, 'This is really bad' # end # # assert_equal 'This is really bad', error.message def assert_raises *exp flunk "assert_raises requires a block to capture errors." unless block_given? msg = "#{exp.pop}.\n" if String === exp.last exp << StandardError if exp.empty? begin yield rescue *exp => e pass # count assertion return e rescue Minitest::Skip, Minitest::Assertion # don't count assertion raise rescue SignalException, SystemExit raise rescue Exception => e flunk proc { exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not") } end exp = exp.first if exp.size == 1 flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised." end ## # Fails unless +obj+ responds to +meth+. def assert_respond_to obj, meth, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}" } assert obj.respond_to?(meth), msg end ## # Fails unless +exp+ and +act+ are #equal? def assert_same exp, act, msg = nil msg = message(msg) { data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id] "Expected %s (oid=%d) to be the same as %s (oid=%d)" % data } assert exp.equal?(act), msg end ## # +send_ary+ is a receiver, message and arguments. # # Fails unless the call returns a true value def assert_send send_ary, m = nil where = Minitest.filter_backtrace(caller).first where = where.split(/:in /, 2).first # clean up noise warn "DEPRECATED: assert_send. From #{where}" recv, msg, *args = send_ary m = message(m) { "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" } assert recv.__send__(msg, *args), m end ## # Fails if the block outputs anything to stderr or stdout. # # See also: #assert_output def assert_silent assert_output "", "" do yield end end ## # Fails unless the block throws +sym+ def assert_throws sym, msg = nil default = "Expected #{mu_pp(sym)} to have been thrown" caught = true catch(sym) do begin yield rescue ThreadError => e # wtf?!? 1.8 + threads == suck default += ", not \:#{e.message[/uncaught throw \`(\w+?)\'/, 1]}" rescue ArgumentError => e # 1.9 exception raise e unless e.message.include?("uncaught throw") default += ", not #{e.message.split(/ /).last}" rescue NameError => e # 1.8 exception raise e unless e.name == sym default += ", not #{e.name.inspect}" end caught = false end assert caught, message(msg) { default } end ## # Captures $stdout and $stderr into strings: # # out, err = capture_io do # puts "Some info" # warn "You did a bad thing" # end # # assert_match %r%info%, out # assert_match %r%bad%, err # # NOTE: For efficiency, this method uses StringIO and does not # capture IO for subprocesses. Use #capture_subprocess_io for # that. def capture_io _synchronize do begin captured_stdout, captured_stderr = StringIO.new, StringIO.new orig_stdout, orig_stderr = $stdout, $stderr $stdout, $stderr = captured_stdout, captured_stderr yield return captured_stdout.string, captured_stderr.string ensure $stdout = orig_stdout $stderr = orig_stderr end end end ## # Captures $stdout and $stderr into strings, using Tempfile to # ensure that subprocess IO is captured as well. # # out, err = capture_subprocess_io do # system "echo Some info" # system "echo You did a bad thing 1>&2" # end # # assert_match %r%info%, out # assert_match %r%bad%, err # # NOTE: This method is approximately 10x slower than #capture_io so # only use it when you need to test the output of a subprocess. def capture_subprocess_io _synchronize do begin require "tempfile" captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err") orig_stdout, orig_stderr = $stdout.dup, $stderr.dup $stdout.reopen captured_stdout $stderr.reopen captured_stderr yield $stdout.rewind $stderr.rewind return captured_stdout.read, captured_stderr.read ensure captured_stdout.unlink captured_stderr.unlink $stdout.reopen orig_stdout $stderr.reopen orig_stderr end end end ## # Returns details for exception +e+ def exception_details e, msg [ "#{msg}", "Class: <#{e.class}>", "Message: <#{e.message.inspect}>", "---Backtrace---", "#{Minitest.filter_backtrace(e.backtrace).join("\n")}", "---------------", ].join "\n" end ## # Fails after a given date (in the local time zone). This allows # you to put time-bombs in your tests if you need to keep # something around until a later date lest you forget about it. def fail_after y,m,d,msg flunk msg if Time.now > Time.local(y, m, d) end ## # Fails with +msg+. def flunk msg = nil msg ||= "Epic Fail!" assert false, msg end ## # Returns a proc that will output +msg+ along with the default message. def message msg = nil, ending = nil, &default proc { msg = msg.call.chomp(".") if Proc === msg custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty? "#{custom_message}#{default.call}#{ending || "."}" } end ## # used for counting assertions def pass _msg = nil assert true end ## # Fails if +test+ is truthy. def refute test, msg = nil msg ||= message { "Expected #{mu_pp(test)} to not be truthy" } not assert !test, msg end ## # Fails if +obj+ is empty. def refute_empty obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not be empty" } assert_respond_to obj, :empty? refute obj.empty?, msg end ## # Fails if exp == act. # # For floats use refute_in_delta. def refute_equal exp, act, msg = nil msg = message(msg) { "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}" } refute exp == act, msg end ## # For comparing Floats. Fails if +exp+ is within +delta+ of +act+. # # refute_in_delta Math::PI, (22.0 / 7.0) def refute_in_delta exp, act, delta = 0.001, msg = nil n = (exp - act).abs msg = message(msg) { "Expected |#{exp} - #{act}| (#{n}) to not be <= #{delta}" } refute delta >= n, msg end ## # For comparing Floats. Fails if +exp+ and +act+ have a relative error # less than +epsilon+. def refute_in_epsilon a, b, epsilon = 0.001, msg = nil refute_in_delta a, b, a * epsilon, msg end ## # Fails if +collection+ includes +obj+. def refute_includes collection, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}" } assert_respond_to collection, :include? refute collection.include?(obj), msg end ## # Fails if +obj+ is an instance of +cls+. def refute_instance_of cls, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not be an instance of #{cls}" } refute obj.instance_of?(cls), msg end ## # Fails if +obj+ is a kind of +cls+. def refute_kind_of cls, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" } refute obj.kind_of?(cls), msg end ## # Fails if +matcher+ =~ +obj+. def refute_match matcher, obj, msg = nil msg = message(msg) { "Expected #{mu_pp matcher} to not match #{mu_pp obj}" } assert_respond_to matcher, :"=~" matcher = Regexp.new Regexp.escape matcher if String === matcher refute matcher =~ obj, msg end ## # Fails if +obj+ is nil. def refute_nil obj, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" } refute obj.nil?, msg end ## # Fails if +o1+ is not +op+ +o2+. Eg: # # refute_operator 1, :>, 2 #=> pass # refute_operator 1, :<, 2 #=> fail def refute_operator o1, op, o2 = UNDEFINED, msg = nil return refute_predicate o1, op, msg if UNDEFINED == o2 msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}" } refute o1.__send__(op, o2), msg end ## # Fails if +path+ exists. def refute_path_exists path, msg = nil msg = message(msg) { "Expected path '#{path}' to not exist" } refute File.exist?(path), msg end ## # For testing with predicates. # # refute_predicate str, :empty? # # This is really meant for specs and is front-ended by refute_operator: # # str.wont_be :empty? def refute_predicate o1, op, msg = nil msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op}" } refute o1.__send__(op), msg end ## # Fails if +obj+ responds to the message +meth+. def refute_respond_to obj, meth, msg = nil msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" } refute obj.respond_to?(meth), msg end ## # Fails if +exp+ is the same (by object identity) as +act+. def refute_same exp, act, msg = nil msg = message(msg) { data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id] "Expected %s (oid=%d) to not be the same as %s (oid=%d)" % data } refute exp.equal?(act), msg end ## # Skips the current run. If run in verbose-mode, the skipped run # gets listed at the end of the run but doesn't cause a failure # exit code. def skip msg = nil, bt = caller msg ||= "Skipped, no message given" @skip = true raise Minitest::Skip, msg, bt end ## # Skips the current run until a given date (in the local time # zone). This allows you to put some fixes on hold until a later # date, but still holds you accountable and prevents you from # forgetting it. def skip_until y,m,d,msg skip msg if Time.now < Time.local(y, m, d) where = caller.first.split(/:/, 3).first(2).join ":" warn "Stale skip_until %p at %s" % [msg, where] end ## # Was this testcase skipped? Meant for #teardown. def skipped? defined?(@skip) and @skip end end end PKu]+**$minitest-5.13.0/lib/minitest/test.rbnu[require "minitest" unless defined? Minitest::Runnable module Minitest ## # Subclass Test to create your own tests. Typically you'll want a # Test subclass per implementation class. # # See Minitest::Assertions class Test < Runnable require "minitest/assertions" include Minitest::Assertions include Minitest::Reportable def class_name # :nodoc: self.class.name # for Minitest::Reportable end PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, SystemExit] # :nodoc: # :stopdoc: class << self; attr_accessor :io_lock; end self.io_lock = Mutex.new # :startdoc: ## # Call this at the top of your tests when you absolutely # positively need to have ordered tests. In doing so, you're # admitting that you suck and your tests are weak. def self.i_suck_and_my_tests_are_order_dependent! class << self undef_method :test_order if method_defined? :test_order define_method :test_order do :alpha end end end ## # Make diffs for this Test use #pretty_inspect so that diff # in assert_equal can have more details. NOTE: this is much slower # than the regular inspect but much more usable for complex # objects. def self.make_my_diffs_pretty! require "pp" define_method :mu_pp, &:pretty_inspect end ## # Call this at the top of your tests when you want to run your # tests in parallel. In doing so, you're admitting that you rule # and your tests are awesome. def self.parallelize_me! include Minitest::Parallel::Test extend Minitest::Parallel::Test::ClassMethods end ## # Returns all instance methods starting with "test_". Based on # #test_order, the methods are either sorted, randomized # (default), or run in parallel. def self.runnable_methods methods = methods_matching(/^test_/) case self.test_order when :random, :parallel then max = methods.size methods.sort.sort_by { rand max } when :alpha, :sorted then methods.sort else raise "Unknown test_order: #{self.test_order.inspect}" end end ## # Defines the order to run tests (:random by default). Override # this or use a convenience method to change it for your tests. def self.test_order :random end TEARDOWN_METHODS = %w[ before_teardown teardown after_teardown ] # :nodoc: ## # Runs a single test with setup/teardown hooks. def run with_info_handler do time_it do capture_exceptions do before_setup; setup; after_setup self.send self.name end TEARDOWN_METHODS.each do |hook| capture_exceptions do self.send hook end end end end Result.from self # per contract end ## # Provides before/after hooks for setup and teardown. These are # meant for library writers, NOT for regular test authors. See # #before_setup for an example. module LifecycleHooks ## # Runs before every test, before setup. This hook is meant for # libraries to extend minitest. It is not meant to be used by # test developers. # # As a simplistic example: # # module MyMinitestPlugin # def before_setup # super # # ... stuff to do before setup is run # end # # def after_setup # # ... stuff to do after setup is run # super # end # # def before_teardown # super # # ... stuff to do before teardown is run # end # # def after_teardown # # ... stuff to do after teardown is run # super # end # end # # class MiniTest::Test # include MyMinitestPlugin # end def before_setup; end ## # Runs before every test. Use this to set up before each test # run. def setup; end ## # Runs before every test, after setup. This hook is meant for # libraries to extend minitest. It is not meant to be used by # test developers. # # See #before_setup for an example. def after_setup; end ## # Runs after every test, before teardown. This hook is meant for # libraries to extend minitest. It is not meant to be used by # test developers. # # See #before_setup for an example. def before_teardown; end ## # Runs after every test. Use this to clean up after each test # run. def teardown; end ## # Runs after every test, after teardown. This hook is meant for # libraries to extend minitest. It is not meant to be used by # test developers. # # See #before_setup for an example. def after_teardown; end end # LifecycleHooks def capture_exceptions # :nodoc: yield rescue *PASSTHROUGH_EXCEPTIONS raise rescue Assertion => e self.failures << e rescue Exception => e self.failures << UnexpectedError.new(e) end def with_info_handler &block # :nodoc: t0 = Minitest.clock_time handler = lambda do warn "\nCurrent: %s#%s %.2fs" % [self.class, self.name, Minitest.clock_time - t0] end self.class.on_signal ::Minitest.info_signal, handler, &block end include LifecycleHooks include Guard extend Guard end # Test end require "minitest/unit" unless defined?(MiniTest) # compatibility layer only PKu] 00)minitest-5.13.0/lib/minitest/benchmark.rbnu[require "minitest/test" require "minitest/spec" module Minitest ## # Subclass Benchmark to create your own benchmark runs. Methods # starting with "bench_" get executed on a per-class. # # See Minitest::Assertions class Benchmark < Test def self.io # :nodoc: @io end def io # :nodoc: self.class.io end def self.run reporter, options = {} # :nodoc: @io = reporter.io super end def self.runnable_methods # :nodoc: methods_matching(/^bench_/) end ## # Returns a set of ranges stepped exponentially from +min+ to # +max+ by powers of +base+. Eg: # # bench_exp(2, 16, 2) # => [2, 4, 8, 16] def self.bench_exp min, max, base = 10 min = (Math.log10(min) / Math.log10(base)).to_i max = (Math.log10(max) / Math.log10(base)).to_i (min..max).map { |m| base ** m }.to_a end ## # Returns a set of ranges stepped linearly from +min+ to +max+ by # +step+. Eg: # # bench_linear(20, 40, 10) # => [20, 30, 40] def self.bench_linear min, max, step = 10 (min..max).step(step).to_a rescue LocalJumpError # 1.8.6 r = []; (min..max).step(step) { |n| r << n }; r end ## # Specifies the ranges used for benchmarking for that class. # Defaults to exponential growth from 1 to 10k by powers of 10. # Override if you need different ranges for your benchmarks. # # See also: ::bench_exp and ::bench_linear. def self.bench_range bench_exp 1, 10_000 end ## # Runs the given +work+, gathering the times of each run. Range # and times are then passed to a given +validation+ proc. Outputs # the benchmark name and times in tab-separated format, making it # easy to paste into a spreadsheet for graphing or further # analysis. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # validation = proc { |x, y| ... } # assert_performance validation do |n| # @obj.algorithm(n) # end # end def assert_performance validation, &work range = self.class.bench_range io.print "#{self.name}" times = [] range.each do |x| GC.start t0 = Minitest.clock_time instance_exec(x, &work) t = Minitest.clock_time - t0 io.print "\t%9.6f" % t times << t end io.puts validation[range, times] end ## # Runs the given +work+ and asserts that the times gathered fit to # match a constant rate (eg, linear slope == 0) within a given # +threshold+. Note: because we're testing for a slope of 0, R^2 # is not a good determining factor for the fit, so the threshold # is applied against the slope itself. As such, you probably want # to tighten it from the default. # # See https://www.graphpad.com/guides/prism/8/curve-fitting/reg_intepretingnonlinr2.htm # for more details. # # Fit is calculated by #fit_linear. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_constant 0.9999 do |n| # @obj.algorithm(n) # end # end def assert_performance_constant threshold = 0.99, &work validation = proc do |range, times| a, b, rr = fit_linear range, times assert_in_delta 0, b, 1 - threshold [a, b, rr] end assert_performance validation, &work end ## # Runs the given +work+ and asserts that the times gathered fit to # match a exponential curve within a given error +threshold+. # # Fit is calculated by #fit_exponential. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_exponential 0.9999 do |n| # @obj.algorithm(n) # end # end def assert_performance_exponential threshold = 0.99, &work assert_performance validation_for_fit(:exponential, threshold), &work end ## # Runs the given +work+ and asserts that the times gathered fit to # match a logarithmic curve within a given error +threshold+. # # Fit is calculated by #fit_logarithmic. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_logarithmic 0.9999 do |n| # @obj.algorithm(n) # end # end def assert_performance_logarithmic threshold = 0.99, &work assert_performance validation_for_fit(:logarithmic, threshold), &work end ## # Runs the given +work+ and asserts that the times gathered fit to # match a straight line within a given error +threshold+. # # Fit is calculated by #fit_linear. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_linear 0.9999 do |n| # @obj.algorithm(n) # end # end def assert_performance_linear threshold = 0.99, &work assert_performance validation_for_fit(:linear, threshold), &work end ## # Runs the given +work+ and asserts that the times gathered curve # fit to match a power curve within a given error +threshold+. # # Fit is calculated by #fit_power. # # Ranges are specified by ::bench_range. # # Eg: # # def bench_algorithm # assert_performance_power 0.9999 do |x| # @obj.algorithm # end # end def assert_performance_power threshold = 0.99, &work assert_performance validation_for_fit(:power, threshold), &work end ## # Takes an array of x/y pairs and calculates the general R^2 value. # # See: http://en.wikipedia.org/wiki/Coefficient_of_determination def fit_error xys y_bar = sigma(xys) { |_, y| y } / xys.size.to_f ss_tot = sigma(xys) { |_, y| (y - y_bar) ** 2 } ss_err = sigma(xys) { |x, y| (yield(x) - y) ** 2 } 1 - (ss_err / ss_tot) end ## # To fit a functional form: y = ae^(bx). # # Takes x and y values and returns [a, b, r^2]. # # See: http://mathworld.wolfram.com/LeastSquaresFittingExponential.html def fit_exponential xs, ys n = xs.size xys = xs.zip(ys) sxlny = sigma(xys) { |x, y| x * Math.log(y) } slny = sigma(xys) { |_, y| Math.log(y) } sx2 = sigma(xys) { |x, _| x * x } sx = sigma xs c = n * sx2 - sx ** 2 a = (slny * sx2 - sx * sxlny) / c b = ( n * sxlny - sx * slny ) / c return Math.exp(a), b, fit_error(xys) { |x| Math.exp(a + b * x) } end ## # To fit a functional form: y = a + b*ln(x). # # Takes x and y values and returns [a, b, r^2]. # # See: http://mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html def fit_logarithmic xs, ys n = xs.size xys = xs.zip(ys) slnx2 = sigma(xys) { |x, _| Math.log(x) ** 2 } slnx = sigma(xys) { |x, _| Math.log(x) } sylnx = sigma(xys) { |x, y| y * Math.log(x) } sy = sigma(xys) { |_, y| y } c = n * slnx2 - slnx ** 2 b = ( n * sylnx - sy * slnx ) / c a = (sy - b * slnx) / n return a, b, fit_error(xys) { |x| a + b * Math.log(x) } end ## # Fits the functional form: a + bx. # # Takes x and y values and returns [a, b, r^2]. # # See: http://mathworld.wolfram.com/LeastSquaresFitting.html def fit_linear xs, ys n = xs.size xys = xs.zip(ys) sx = sigma xs sy = sigma ys sx2 = sigma(xs) { |x| x ** 2 } sxy = sigma(xys) { |x, y| x * y } c = n * sx2 - sx**2 a = (sy * sx2 - sx * sxy) / c b = ( n * sxy - sx * sy ) / c return a, b, fit_error(xys) { |x| a + b * x } end ## # To fit a functional form: y = ax^b. # # Takes x and y values and returns [a, b, r^2]. # # See: http://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html def fit_power xs, ys n = xs.size xys = xs.zip(ys) slnxlny = sigma(xys) { |x, y| Math.log(x) * Math.log(y) } slnx = sigma(xs) { |x | Math.log(x) } slny = sigma(ys) { | y| Math.log(y) } slnx2 = sigma(xs) { |x | Math.log(x) ** 2 } b = (n * slnxlny - slnx * slny) / (n * slnx2 - slnx ** 2) a = (slny - b * slnx) / n return Math.exp(a), b, fit_error(xys) { |x| (Math.exp(a) * (x ** b)) } end ## # Enumerates over +enum+ mapping +block+ if given, returning the # sum of the result. Eg: # # sigma([1, 2, 3]) # => 1 + 2 + 3 => 6 # sigma([1, 2, 3]) { |n| n ** 2 } # => 1 + 4 + 9 => 14 def sigma enum, &block enum = enum.map(&block) if block enum.inject { |sum, n| sum + n } end ## # Returns a proc that calls the specified fit method and asserts # that the error is within a tolerable threshold. def validation_for_fit msg, threshold proc do |range, times| a, b, rr = send "fit_#{msg}", range, times assert_operator rr, :>=, threshold [a, b, rr] end end end end module Minitest ## # The spec version of Minitest::Benchmark. class BenchSpec < Benchmark extend Minitest::Spec::DSL ## # This is used to define a new benchmark method. You usually don't # use this directly and is intended for those needing to write new # performance curve fits (eg: you need a specific polynomial fit). # # See ::bench_performance_linear for an example of how to use this. def self.bench name, &block define_method "bench_#{name.gsub(/\W+/, "_")}", &block end ## # Specifies the ranges used for benchmarking for that class. # # bench_range do # bench_exp(2, 16, 2) # end # # See Minitest::Benchmark#bench_range for more details. def self.bench_range &block return super unless block meta = (class << self; self; end) meta.send :define_method, "bench_range", &block end ## # Create a benchmark that verifies that the performance is linear. # # describe "my class Bench" do # bench_performance_linear "fast_algorithm", 0.9999 do |n| # @obj.fast_algorithm(n) # end # end def self.bench_performance_linear name, threshold = 0.99, &work bench name do assert_performance_linear threshold, &work end end ## # Create a benchmark that verifies that the performance is constant. # # describe "my class Bench" do # bench_performance_constant "zoom_algorithm!" do |n| # @obj.zoom_algorithm!(n) # end # end def self.bench_performance_constant name, threshold = 0.99, &work bench name do assert_performance_constant threshold, &work end end ## # Create a benchmark that verifies that the performance is exponential. # # describe "my class Bench" do # bench_performance_exponential "algorithm" do |n| # @obj.algorithm(n) # end # end def self.bench_performance_exponential name, threshold = 0.99, &work bench name do assert_performance_exponential threshold, &work end end ## # Create a benchmark that verifies that the performance is logarithmic. # # describe "my class Bench" do # bench_performance_logarithmic "algorithm" do |n| # @obj.algorithm(n) # end # end def self.bench_performance_logarithmic name, threshold = 0.99, &work bench name do assert_performance_logarithmic threshold, &work end end ## # Create a benchmark that verifies that the performance is power. # # describe "my class Bench" do # bench_performance_power "algorithm" do |n| # @obj.algorithm(n) # end # end def self.bench_performance_power name, threshold = 0.99, &work bench name do assert_performance_power threshold, &work end end end Minitest::Spec.register_spec_type(/Bench(mark)?$/, Minitest::BenchSpec) end PKu]y$minitest-5.13.0/lib/minitest/unit.rbnu[# :stopdoc: unless defined?(Minitest) then # all of this crap is just to avoid circular requires and is only # needed if a user requires "minitest/unit" directly instead of # "minitest/autorun", so we also warn from = caller.reject { |s| s =~ /rubygems/ }.join("\n ") warn "Warning: you should require 'minitest/autorun' instead." warn %(Warning: or add 'gem "minitest"' before 'require "minitest/autorun"') warn "From:\n #{from}" module Minitest; end MiniTest = Minitest # prevents minitest.rb from requiring back to us require "minitest" end MiniTest = Minitest unless defined?(MiniTest) module Minitest class Unit VERSION = Minitest::VERSION class TestCase < Minitest::Test def self.inherited klass # :nodoc: from = caller.first warn "MiniTest::Unit::TestCase is now Minitest::Test. From #{from}" super end end def self.autorun # :nodoc: from = caller.first warn "MiniTest::Unit.autorun is now Minitest.autorun. From #{from}" Minitest.autorun end def self.after_tests &b # :nodoc: from = caller.first warn "MiniTest::Unit.after_tests is now Minitest.after_run. From #{from}" Minitest.after_run(&b) end end end # :startdoc: PKu]/w[NN$minitest-5.13.0/lib/minitest/mock.rbnu[class MockExpectationError < StandardError; end # :nodoc: module Minitest # :nodoc: ## # A simple and clean mock object framework. # # All mock objects are an instance of Mock class Mock alias :__respond_to? :respond_to? overridden_methods = %w[ === class inspect instance_eval instance_variables object_id public_send respond_to_missing? send to_s ] instance_methods.each do |m| undef_method m unless overridden_methods.include?(m.to_s) || m =~ /^__/ end overridden_methods.map(&:to_sym).each do |method_id| define_method method_id do |*args, &b| if @expected_calls.key? method_id then method_missing(method_id, *args, &b) else super(*args, &b) end end end def initialize delegator = nil # :nodoc: @delegator = delegator @expected_calls = Hash.new { |calls, name| calls[name] = [] } @actual_calls = Hash.new { |calls, name| calls[name] = [] } end ## # Expect that method +name+ is called, optionally with +args+ or a # +blk+, and returns +retval+. # # @mock.expect(:meaning_of_life, 42) # @mock.meaning_of_life # => 42 # # @mock.expect(:do_something_with, true, [some_obj, true]) # @mock.do_something_with(some_obj, true) # => true # # @mock.expect(:do_something_else, true) do |a1, a2| # a1 == "buggs" && a2 == :bunny # end # # +args+ is compared to the expected args using case equality (ie, the # '===' operator), allowing for less specific expectations. # # @mock.expect(:uses_any_string, true, [String]) # @mock.uses_any_string("foo") # => true # @mock.verify # => true # # @mock.expect(:uses_one_string, true, ["foo"]) # @mock.uses_one_string("bar") # => raises MockExpectationError # # If a method will be called multiple times, specify a new expect for each one. # They will be used in the order you define them. # # @mock.expect(:ordinal_increment, 'first') # @mock.expect(:ordinal_increment, 'second') # # @mock.ordinal_increment # => 'first' # @mock.ordinal_increment # => 'second' # @mock.ordinal_increment # => raises MockExpectationError "No more expects available for :ordinal_increment" # def expect name, retval, args = [], &blk name = name.to_sym if block_given? raise ArgumentError, "args ignored when block given" unless args.empty? @expected_calls[name] << { :retval => retval, :block => blk } else raise ArgumentError, "args must be an array" unless Array === args @expected_calls[name] << { :retval => retval, :args => args } end self end def __call name, data # :nodoc: case data when Hash then "#{name}(#{data[:args].inspect[1..-2]}) => #{data[:retval].inspect}" else data.map { |d| __call name, d }.join ", " end end ## # Verify that all methods were called as expected. Raises # +MockExpectationError+ if the mock object was not called as # expected. def verify @expected_calls.each do |name, expected| actual = @actual_calls.fetch(name, nil) raise MockExpectationError, "expected #{__call name, expected[0]}" unless actual raise MockExpectationError, "expected #{__call name, expected[actual.size]}, got [#{__call name, actual}]" if actual.size < expected.size end true end def method_missing sym, *args, &block # :nodoc: unless @expected_calls.key?(sym) then if @delegator && @delegator.respond_to?(sym) return @delegator.public_send(sym, *args, &block) else raise NoMethodError, "unmocked method %p, expected one of %p" % [sym, @expected_calls.keys.sort_by(&:to_s)] end end index = @actual_calls[sym].length expected_call = @expected_calls[sym][index] unless expected_call then raise MockExpectationError, "No more expects available for %p: %p" % [sym, args] end expected_args, retval, val_block = expected_call.values_at(:args, :retval, :block) if val_block then # keep "verify" happy @actual_calls[sym] << expected_call raise MockExpectationError, "mocked method %p failed block w/ %p" % [sym, args] unless val_block.call(*args, &block) return retval end if expected_args.size != args.size then raise ArgumentError, "mocked method %p expects %d arguments, got %d" % [sym, expected_args.size, args.size] end zipped_args = expected_args.zip(args) fully_matched = zipped_args.all? { |mod, a| mod === a or mod == a } unless fully_matched then raise MockExpectationError, "mocked method %p called with unexpected arguments %p" % [sym, args] end @actual_calls[sym] << { :retval => retval, :args => zipped_args.map! { |mod, a| mod === a ? mod : a }, } retval end def respond_to? sym, include_private = false # :nodoc: return true if @expected_calls.key? sym.to_sym return true if @delegator && @delegator.respond_to?(sym, include_private) __respond_to?(sym, include_private) end end end module Minitest::Assertions ## # Assert that the mock verifies correctly. def assert_mock mock assert mock.verify end end ## # Object extensions for Minitest::Mock. class Object ## # Add a temporary stubbed method replacing +name+ for the duration # of the +block+. If +val_or_callable+ responds to #call, then it # returns the result of calling it, otherwise returns the value # as-is. If stubbed method yields a block, +block_args+ will be # passed along. Cleans up the stub at the end of the +block+. The # method +name+ must exist before stubbing. # # def test_stale_eh # obj_under_test = Something.new # refute obj_under_test.stale? # # Time.stub :now, Time.at(0) do # assert obj_under_test.stale? # end # end # def stub name, val_or_callable, *block_args new_name = "__minitest_stub__#{name}" metaclass = class << self; self; end if respond_to? name and not methods.map(&:to_s).include? name.to_s then metaclass.send :define_method, name do |*args| super(*args) end end metaclass.send :alias_method, new_name, name metaclass.send :define_method, name do |*args, &blk| if val_or_callable.respond_to? :call then val_or_callable.call(*args, &blk) else blk.call(*block_args) if blk val_or_callable end end yield self ensure metaclass.send :undef_method, name metaclass.send :alias_method, name, new_name metaclass.send :undef_method, new_name end end PKu]_cGG(minitest-5.13.0/lib/minitest/parallel.rbnu[module Minitest module Parallel #:nodoc: ## # The engine used to run multiple tests in parallel. class Executor ## # The size of the pool of workers. attr_reader :size ## # Create a parallel test executor of with +size+ workers. def initialize size @size = size @queue = Queue.new @pool = nil end ## # Start the executor def start @pool = size.times.map { Thread.new(@queue) do |queue| Thread.current.abort_on_exception = true while (job = queue.pop) klass, method, reporter = job reporter.synchronize { reporter.prerecord klass, method } result = Minitest.run_one_method klass, method reporter.synchronize { reporter.record result } end end } end ## # Add a job to the queue def << work; @queue << work; end ## # Shuts down the pool of workers by signalling them to quit and # waiting for them all to finish what they're currently working # on. def shutdown size.times { @queue << nil } @pool.each(&:join) end end module Test # :nodoc: def _synchronize; Minitest::Test.io_lock.synchronize { yield }; end # :nodoc: module ClassMethods # :nodoc: def run_one_method klass, method_name, reporter Minitest.parallel_executor << [klass, method_name, reporter] end def test_order :parallel end end end end end PKu]oz$minitest-5.13.0/lib/minitest/hell.rbnu[require "minitest/parallel" class Minitest::Test parallelize_me! end begin require "minitest/proveit" rescue LoadError warn "NOTE: `gem install minitest-proveit` for even more hellish tests" end PKu]9M M ,minitest-5.13.0/lib/minitest/pride_plugin.rbnu[require "minitest" module Minitest def self.plugin_pride_options opts, _options # :nodoc: opts.on "-p", "--pride", "Pride. Show your testing pride!" do PrideIO.pride! end end def self.plugin_pride_init options # :nodoc: if PrideIO.pride? then klass = ENV["TERM"] =~ /^xterm|-256color$/ ? PrideLOL : PrideIO io = klass.new options[:io] self.reporter.reporters.grep(Minitest::Reporter).each do |rep| rep.io = io if rep.io.tty? end end end ## # Show your testing pride! class PrideIO ## # Activate the pride plugin. Called from both -p option and minitest/pride def self.pride! @pride = true end ## # Are we showing our testing pride? def self.pride? @pride ||= false end # Start an escape sequence ESC = "\e[" # End the escape sequence NND = "#{ESC}0m" # The IO we're going to pipe through. attr_reader :io def initialize io # :nodoc: @io = io # stolen from /System/Library/Perl/5.10.0/Term/ANSIColor.pm # also reference http://en.wikipedia.org/wiki/ANSI_escape_code @colors ||= (31..36).to_a @size = @colors.size @index = 0 end ## # Wrap print to colorize the output. def print o case o when "." then io.print pride o when "E", "F" then io.print "#{ESC}41m#{ESC}37m#{o}#{NND}" when "S" then io.print pride o else io.print o end end def puts *o # :nodoc: o.map! { |s| s.to_s.sub(/Finished/) { @index = 0 "Fabulous run".split(//).map { |c| pride(c) }.join } } io.puts(*o) end ## # Color a string. def pride string string = "*" if string == "." c = @colors[@index % @size] @index += 1 "#{ESC}#{c}m#{string}#{NND}" end def method_missing msg, *args # :nodoc: io.send(msg, *args) end end ## # If you thought the PrideIO was colorful... # # (Inspired by lolcat, but with clean math) class PrideLOL < PrideIO PI_3 = Math::PI / 3 # :nodoc: def initialize io # :nodoc: # walk red, green, and blue around a circle separated by equal thirds. # # To visualize, type this into wolfram-alpha: # # plot (3*sin(x)+3), (3*sin(x+2*pi/3)+3), (3*sin(x+4*pi/3)+3) # 6 has wide pretty gradients. 3 == lolcat, about half the width @colors = (0...(6 * 7)).map { |n| n *= 1.0 / 6 r = (3 * Math.sin(n ) + 3).to_i g = (3 * Math.sin(n + 2 * PI_3) + 3).to_i b = (3 * Math.sin(n + 4 * PI_3) + 3).to_i # Then we take rgb and encode them in a single number using base 6. # For some mysterious reason, we add 16... to clear the bottom 4 bits? # Yes... they're ugly. 36 * r + 6 * g + b + 16 } super end ## # Make the string even more colorful. Damnit. def pride string c = @colors[@index % @size] @index += 1 "#{ESC}38;5;#{c}m#{string}#{NND}" end end end PKu]T,minitest-5.13.0/lib/minitest/expectations.rbnu[## # It's where you hide your "assertions". # # Please note, because of the way that expectations are implemented, # all expectations (eg must_equal) are dependent upon a thread local # variable +:current_spec+. If your specs rely on mixing threads into # the specs themselves, you're better off using assertions or the new # _(value) wrapper. For example: # # it "should still work in threads" do # my_threaded_thingy do # (1+1).must_equal 2 # bad # assert_equal 2, 1+1 # good # _(1 + 1).must_equal 2 # good # value(1 + 1).must_equal 2 # good, also #expect # end # end module Minitest::Expectations ## # See Minitest::Assertions#assert_empty. # # collection.must_be_empty # # :method: must_be_empty infect_an_assertion :assert_empty, :must_be_empty, :unary ## # See Minitest::Assertions#assert_equal # # a.must_equal b # # :method: must_equal infect_an_assertion :assert_equal, :must_equal ## # See Minitest::Assertions#assert_in_delta # # n.must_be_close_to m [, delta] # # :method: must_be_close_to infect_an_assertion :assert_in_delta, :must_be_close_to alias :must_be_within_delta :must_be_close_to # :nodoc: ## # See Minitest::Assertions#assert_in_epsilon # # n.must_be_within_epsilon m [, epsilon] # # :method: must_be_within_epsilon infect_an_assertion :assert_in_epsilon, :must_be_within_epsilon ## # See Minitest::Assertions#assert_includes # # collection.must_include obj # # :method: must_include infect_an_assertion :assert_includes, :must_include, :reverse ## # See Minitest::Assertions#assert_instance_of # # obj.must_be_instance_of klass # # :method: must_be_instance_of infect_an_assertion :assert_instance_of, :must_be_instance_of ## # See Minitest::Assertions#assert_kind_of # # obj.must_be_kind_of mod # # :method: must_be_kind_of infect_an_assertion :assert_kind_of, :must_be_kind_of ## # See Minitest::Assertions#assert_match # # a.must_match b # # :method: must_match infect_an_assertion :assert_match, :must_match ## # See Minitest::Assertions#assert_nil # # obj.must_be_nil # # :method: must_be_nil infect_an_assertion :assert_nil, :must_be_nil, :unary ## # See Minitest::Assertions#assert_operator # # n.must_be :<=, 42 # # This can also do predicates: # # str.must_be :empty? # # :method: must_be infect_an_assertion :assert_operator, :must_be, :reverse ## # See Minitest::Assertions#assert_output # # proc { ... }.must_output out_or_nil [, err] # # :method: must_output infect_an_assertion :assert_output, :must_output, :block ## # See Minitest::Assertions#assert_raises # # proc { ... }.must_raise exception # # :method: must_raise infect_an_assertion :assert_raises, :must_raise, :block ## # See Minitest::Assertions#assert_respond_to # # obj.must_respond_to msg # # :method: must_respond_to infect_an_assertion :assert_respond_to, :must_respond_to, :reverse ## # See Minitest::Assertions#assert_same # # a.must_be_same_as b # # :method: must_be_same_as infect_an_assertion :assert_same, :must_be_same_as ## # See Minitest::Assertions#assert_silent # # proc { ... }.must_be_silent # # :method: must_be_silent infect_an_assertion :assert_silent, :must_be_silent, :block ## # See Minitest::Assertions#assert_throws # # proc { ... }.must_throw sym # # :method: must_throw infect_an_assertion :assert_throws, :must_throw, :block ## # See Minitest::Assertions#assert_path_exists # # _(some_path).path_must_exist # # :method: path_must_exist infect_an_assertion :assert_path_exists, :path_must_exist, :unary ## # See Minitest::Assertions#refute_path_exists # # _(some_path).path_wont_exist # # :method: path_wont_exist infect_an_assertion :refute_path_exists, :path_wont_exist, :unary ## # See Minitest::Assertions#refute_empty # # collection.wont_be_empty # # :method: wont_be_empty infect_an_assertion :refute_empty, :wont_be_empty, :unary ## # See Minitest::Assertions#refute_equal # # a.wont_equal b # # :method: wont_equal infect_an_assertion :refute_equal, :wont_equal ## # See Minitest::Assertions#refute_in_delta # # n.wont_be_close_to m [, delta] # # :method: wont_be_close_to infect_an_assertion :refute_in_delta, :wont_be_close_to alias :wont_be_within_delta :wont_be_close_to # :nodoc: ## # See Minitest::Assertions#refute_in_epsilon # # n.wont_be_within_epsilon m [, epsilon] # # :method: wont_be_within_epsilon infect_an_assertion :refute_in_epsilon, :wont_be_within_epsilon ## # See Minitest::Assertions#refute_includes # # collection.wont_include obj # # :method: wont_include infect_an_assertion :refute_includes, :wont_include, :reverse ## # See Minitest::Assertions#refute_instance_of # # obj.wont_be_instance_of klass # # :method: wont_be_instance_of infect_an_assertion :refute_instance_of, :wont_be_instance_of ## # See Minitest::Assertions#refute_kind_of # # obj.wont_be_kind_of mod # # :method: wont_be_kind_of infect_an_assertion :refute_kind_of, :wont_be_kind_of ## # See Minitest::Assertions#refute_match # # a.wont_match b # # :method: wont_match infect_an_assertion :refute_match, :wont_match ## # See Minitest::Assertions#refute_nil # # obj.wont_be_nil # # :method: wont_be_nil infect_an_assertion :refute_nil, :wont_be_nil, :unary ## # See Minitest::Assertions#refute_operator # # n.wont_be :<=, 42 # # This can also do predicates: # # str.wont_be :empty? # # :method: wont_be infect_an_assertion :refute_operator, :wont_be, :reverse ## # See Minitest::Assertions#refute_respond_to # # obj.wont_respond_to msg # # :method: wont_respond_to infect_an_assertion :refute_respond_to, :wont_respond_to, :reverse ## # See Minitest::Assertions#refute_same # # a.wont_be_same_as b # # :method: wont_be_same_as infect_an_assertion :refute_same, :wont_be_same_as end PKu]I'minitest-5.13.0/lib/minitest/autorun.rbnu[begin require "rubygems" gem "minitest" rescue Gem::LoadError # do nothing end require "minitest" require "minitest/spec" require "minitest/mock" require "minitest/hell" if ENV["MT_HELL"] Minitest.autorun PKu]^ѿ##$minitest-5.13.0/lib/minitest/spec.rbnu[require "minitest/test" class Module # :nodoc: def infect_an_assertion meth, new_name, dont_flip = false # :nodoc: block = dont_flip == :block dont_flip = false if block # warn "%-22p -> %p %p" % [meth, new_name, dont_flip] self.class_eval <<-EOM, __FILE__, __LINE__ + 1 def #{new_name} *args where = Minitest.filter_backtrace(caller).first where = where.split(/:in /, 2).first # clean up noise warn "DEPRECATED: global use of #{new_name} from #\{where}. Use _(obj).#{new_name} instead. This will fail in Minitest 6." Minitest::Expectation.new(self, Minitest::Spec.current).#{new_name}(*args) end EOM Minitest::Expectation.class_eval <<-EOM, __FILE__, __LINE__ + 1 def #{new_name} *args raise "Calling ##{new_name} outside of test." unless ctx case when #{!!dont_flip} then ctx.#{meth}(target, *args) when #{block} && Proc === target then ctx.#{meth}(*args, &target) else ctx.#{meth}(args.first, target, *args[1..-1]) end end EOM end end Minitest::Expectation = Struct.new :target, :ctx # :nodoc: ## # Kernel extensions for minitest module Kernel ## # Describe a series of expectations for a given target +desc+. # # Defines a test class subclassing from either Minitest::Spec or # from the surrounding describe's class. The surrounding class may # subclass Minitest::Spec manually in order to easily share code: # # class MySpec < Minitest::Spec # # ... shared code ... # end # # class TestStuff < MySpec # it "does stuff" do # # shared code available here # end # describe "inner stuff" do # it "still does stuff" do # # ...and here # end # end # end # # For more information on getting started with writing specs, see: # # http://www.rubyinside.com/a-minitestspec-tutorial-elegant-spec-style-testing-that-comes-with-ruby-5354.html # # For some suggestions on how to improve your specs, try: # # http://betterspecs.org # # but do note that several items there are debatable or specific to # rspec. # # For more information about expectations, see Minitest::Expectations. def describe desc, *additional_desc, &block # :doc: stack = Minitest::Spec.describe_stack name = [stack.last, desc, *additional_desc].compact.join("::") sclas = stack.last || if Class === self && kind_of?(Minitest::Spec::DSL) then self else Minitest::Spec.spec_type desc, *additional_desc end cls = sclas.create name, desc stack.push cls cls.class_eval(&block) stack.pop cls end private :describe end ## # Minitest::Spec -- The faster, better, less-magical spec framework! # # For a list of expectations, see Minitest::Expectations. class Minitest::Spec < Minitest::Test def self.current # :nodoc: Thread.current[:current_spec] end def initialize name # :nodoc: super Thread.current[:current_spec] = self end ## # Oh look! A Minitest::Spec::DSL module! Eat your heart out DHH. module DSL ## # Contains pairs of matchers and Spec classes to be used to # calculate the superclass of a top-level describe. This allows for # automatically customizable spec types. # # See: register_spec_type and spec_type TYPES = [[//, Minitest::Spec]] ## # Register a new type of spec that matches the spec's description. # This method can take either a Regexp and a spec class or a spec # class and a block that takes the description and returns true if # it matches. # # Eg: # # register_spec_type(/Controller$/, Minitest::Spec::Rails) # # or: # # register_spec_type(Minitest::Spec::RailsModel) do |desc| # desc.superclass == ActiveRecord::Base # end def register_spec_type *args, &block if block then matcher, klass = block, args.first else matcher, klass = *args end TYPES.unshift [matcher, klass] end ## # Figure out the spec class to use based on a spec's description. Eg: # # spec_type("BlahController") # => Minitest::Spec::Rails def spec_type desc, *additional TYPES.find { |matcher, _klass| if matcher.respond_to? :call then matcher.call desc, *additional else matcher === desc.to_s end }.last end def describe_stack # :nodoc: Thread.current[:describe_stack] ||= [] end def children # :nodoc: @children ||= [] end def nuke_test_methods! # :nodoc: self.public_instance_methods.grep(/^test_/).each do |name| self.send :undef_method, name end end ## # Define a 'before' action. Inherits the way normal methods should. # # NOTE: +type+ is ignored and is only there to make porting easier. # # Equivalent to Minitest::Test#setup. def before _type = nil, &block define_method :setup do super() self.instance_eval(&block) end end ## # Define an 'after' action. Inherits the way normal methods should. # # NOTE: +type+ is ignored and is only there to make porting easier. # # Equivalent to Minitest::Test#teardown. def after _type = nil, &block define_method :teardown do self.instance_eval(&block) super() end end ## # Define an expectation with name +desc+. Name gets morphed to a # proper test method name. For some freakish reason, people who # write specs don't like class inheritance, so this goes way out of # its way to make sure that expectations aren't inherited. # # This is also aliased to #specify and doesn't require a +desc+ arg. # # Hint: If you _do_ want inheritance, use minitest/test. You can mix # and match between assertions and expectations as much as you want. def it desc = "anonymous", &block block ||= proc { skip "(no tests defined)" } @specs ||= 0 @specs += 1 name = "test_%04d_%s" % [ @specs, desc ] undef_klasses = self.children.reject { |c| c.public_method_defined? name } define_method name, &block undef_klasses.each do |undef_klass| undef_klass.send :undef_method, name end name end ## # Essentially, define an accessor for +name+ with +block+. # # Why use let instead of def? I honestly don't know. def let name, &block name = name.to_s pre, post = "let '#{name}' cannot ", ". Please use another name." methods = Minitest::Spec.instance_methods.map(&:to_s) - %w[subject] raise ArgumentError, "#{pre}begin with 'test'#{post}" if name =~ /\Atest/ raise ArgumentError, "#{pre}override a method in Minitest::Spec#{post}" if methods.include? name define_method name do @_memoized ||= {} @_memoized.fetch(name) { |k| @_memoized[k] = instance_eval(&block) } end end ## # Another lazy man's accessor generator. Made even more lazy by # setting the name for you to +subject+. def subject &block let :subject, &block end def create name, desc # :nodoc: cls = Class.new(self) do @name = name @desc = desc nuke_test_methods! end children << cls cls end def name # :nodoc: defined?(@name) ? @name : super end def to_s # :nodoc: name # Can't alias due to 1.8.7, not sure why end attr_reader :desc # :nodoc: alias :specify :it ## # Rdoc... why are you so dumb? module InstanceMethods ## # Takes a value or a block and returns a value monad that has # all of Expectations methods available to it. # # _(1 + 1).must_equal 2 # # And for blocks: # # _ { 1 + "1" }.must_raise TypeError # # This method of expectation-based testing is preferable to # straight-expectation methods (on Object) because it stores its # test context, bypassing our hacky use of thread-local variables. # # NOTE: At some point, the methods on Object will be deprecated # and then removed. # # It is also aliased to #value and #expect for your aesthetic # pleasure: # # _(1 + 1).must_equal 2 # value(1 + 1).must_equal 2 # expect(1 + 1).must_equal 2 def _ value = nil, &block Minitest::Expectation.new block || value, self end alias value _ alias expect _ def before_setup # :nodoc: super Thread.current[:current_spec] = self end end def self.extended obj # :nodoc: obj.send :include, InstanceMethods end end extend DSL TYPES = DSL::TYPES # :nodoc: end require "minitest/expectations" class Object # :nodoc: include Minitest::Expectations unless ENV["MT_NO_EXPECTATIONS"] end PKu]Lj)p#minitest-5.13.0/lib/hoe/minitest.rbnu[# :stopdoc: class Hoe end module Hoe::Minitest def minitest? self.name == "minitest" end def initialize_minitest unless minitest? then dir = "../../minitest/dev/lib" Hoe.add_include_dirs dir if File.directory? dir end gem "minitest" require "minitest" version = Minitest::VERSION.split(/\./).first(2).join(".") dependency "minitest", "~> #{version}", :development unless minitest? or ENV["MT_NO_ISOLATE"] end def define_minitest_tasks self.testlib = :minitest # make sure we use the gemmed minitest on 1.9 self.test_prelude = 'gem "minitest"' unless minitest? or ENV["MT_NO_ISOLATE"] end end PKu]\minitest-5.13.0/History.rdocnu[=== 5.13.0 / 2019-10-29 * 9 minor enhancements: * Added Minitest::Guard#osx? * Added examples to documentation for assert_raises. (lxxxvi) * Added expectations #path_must_exist and #path_wont_exist. Not thrilled with the names. * Added fail_after(year, month, day, msg) to allow time-bombing after a deadline. * Added skip_until(year, month, day, msg) to allow deferring until a deadline. * Deprecated Minitest::Guard#maglev? * Deprecated Minitest::Guard#rubinius? * Finally added assert_path_exists and refute_path_exists. (deivid-rodriguez) * Refactored and pulled Assertions#things_to_diff out of #diff. (BurdetteLamar) * 3 bug fixes: * Fix autorun bug that affects fork exit status in tests. (dylanahsmith/jhawthorn) * Improved documentation for _/value/expect, especially for blocks. (svoop) * Support new Proc#to_s format. (ko1) === 5.12.2 / 2019-09-28 * 1 bug fix: * After chatting w/ @y-yagi and others, decided to lower support to include ruby 2.2. === 5.12.1 / 2019-09-28 * 1 minor enhancement: * Added documentation for Reporter classes. (sshaw) * 3 bug fixes: * Avoid using 'match?' to support older ruby versions. (y-yagi) * Fixed broken link to reference on goodness-of-fit testing. (havenwood) * Update requirements in readme and Rakefile/hoe spec. === 5.12.0 / 2019-09-22 * 8 minor enhancements: * Added a descriptive error if assert_output or assert_raises called without a block. (okuramasafumi) * Changed mu_pp_for_diff to make having both \n and \\n easier to debug. * Deprecated $N for specifying number of parallel test runners. Use MT_CPU. * Deprecated use of global expectations. To be removed from MT6. * Extended Assertions#mu_pp to encoding validity output for strings to improve diffs. * Extended Assertions#mu_pp to output encoding and validity if invalid to improve diffs. * Extended Assertions#mu_pp_for_diff to make escaped newlines more obvious in diffs. * Fail gracefully when expectation used outside of `it`. * 3 bug fixes: * Check `option[:filter]` klass before match. Fixes 2.6 warning. (y-yagi) * Fixed Assertions#diff from recalculating if set to nil * Fixed spec section of readme to not use deprecated global expectations. (CheezItMan) === 5.11.3 / 2018-01-26 * 1 bug fix: * Pushed #error? up to Reportable module. (composerinteralia) === 5.11.2 / 2018-01-25 * 1 minor enhancement: * Reversed Test < Result. Back to < Runnable and using Reportable for shared code. * 2 bug fixes: * Fixed Result#location for instances of Test. (alexisbernard) * Fixed deprecation message for Runnable#marshal_dump. (y-yagi) === 5.11.1 / 2018-01-02 * 1 bug fix: * Fixed Result (a superclass of Test) overriding Runnable's name accessors. (y-yagi, MSP-Greg) === 5.11.0 / 2018-01-01 * 2 major enhancements: * Added Minitest::Result and Minitest::Result.from(runnable). * Changed Minitest::Test to subclass Result and refactored methods up. * 7 minor enhancements: * Added --no-plugins and MT_NO_PLUGINS to bypass MT plugin autoloading. Helps with bad actors installed globally. * Added bench_performance_{logarithmic,power} for spec-style benchmarks. (rickhull) * Added deprecation warning for Runnable#marshal_dump. * Minitest.run_one_method now checks for instance of Result, not exact same class. * Minitest::Test.run returns a Result version of self, not self. * ProgressReporter#prerecord now explicitly prints klass.name. Allows for fakers. * 4 bug fixes: * Object.stub no longer calls the passed block if stubbed with a callable. * Object.stub now passes blocks down to the callable result. * Pushed Minitest::Test#time & #time_it up to Runnable. * Test nil equality directly in assert_equal. Fixes #679. (voxik) === 5.11.0b1 / 2017-12-20 * 2 major enhancements: * Added Minitest::Result and Minitest::Result.from(runnable). * Changed Minitest::Test to subclass Result and refactored methods up. * 6 minor enhancements: * Added --no-plugins and MT_NO_PLUGINS to bypass MT plugin autoloading. Helps with bad actors installed globally. * Added bench_performance_{logarithmic,power} for spec-style benchmarks. (rickhull) * Minitest.run_one_method now checks for instance of Result, not exact same class. * Minitest::Test.run returns a Result version of self, not self. * ProgressReporter#prerecord now explicitly prints klass.name. Allows for fakers. * Removed Runnable.marshal_dump/load. * 4 bug fixes: * Object.stub no longer calls the passed block if stubbed with a callable. * Object.stub now passes blocks down to the callable result. * Pushed Minitest::Test#time & #time_it up to Runnable. * Test nil equality directly in assert_equal. Fixes #679. (voxik) === 5.10.3 / 2017-07-21 * 1 minor enhancement: * Extended documentation for Mock#expect for multiple calls to mock object. (insti) * 2 bug fixes: * Finished off missing doco. * Fixed verbose output on parallelize_me! classes. (chanks) === 5.10.2 / 2017-05-09 * 1 minor enhancement: * Added suggestion in minitest/hell to install minitest/proveit. * 7 bug fixes: * Expand MT6 to Minitest 6. (xaviershay) * Fixed location of assert_send deprecation. (rab) * Fixed location of nil assert_equal deprecation to work with expectations. (jeremyevans) * Fixed minitest/hell to use parallelize_me! (azul) * Made deprecation use warn so -W0 will silence it. * Workaround for rdoc nodoc generation bug that totally f'd up minitest doco. (Paxa) * Write aggregated_results directly to the IO object to avoid mixed encoding errors. (tenderlove) === 5.10.1 / 2016-12-01 * 1 bug fix: * Added a hack/kludge to deal with missing #prerecord on reporters that aren't properly subclassing AbstractReporter (I'm looking at you minitest-reporters) === 5.10.0 / 2016-11-30 * 1 major enhancement: * Deprecated ruby 1.8, 1.9, possibly 2.0, assert_send, & old MiniTest namespace. * 3 minor enhancements: * Warn if assert_equal expects a nil. This will fail in minitest 6+. (tenderlove) * Added AbstractReporter#prerecord and extended ProgressReporter and CompositeReporter to use it. * Minor optimization: remove runnables with no runnable methods before run. * 3 bug fixes: * Fix assert_throw rescuing any NameError and ArgumentError. (waldyr) * Clean up (most of the) last remaining vestiges of minitest/unit. * 2.4: removed deprecation warnings when referring to Fixnum. === 5.9.1 / 2016-09-25 * 2 bug fixes: * Re-release to refresh gem certificate signing. ugh. * Fixed hoe/minitest to not augment load path if we're actually testing minitest. === 5.9.0 / 2016-05-16 * 8 minor enhancements: * Added Minitest.info_signal accessors to customize signal for test run info. (nate) * Added assert_mock to make it more clear that you're testing w/ them. * Added negative filter by test name. (utilum) * Added warning to README that 1.8 and 1.9 support will be dropped in minitest 6. * Automatically activate minitest/hell if $MT_HELL is defined. * Improved default error messages for assert and refute. (bhenderson) * minitest/hell now tries to require minitest/proveit * mu_pp for strings prints out non-standard encodings to improve assert_equal diffs. * 1 bug fix: * Removed Interrupt from PASSTHROUGH_EXCEPTIONS (already handled). (waldyr) === 5.8.5 / 2016-09-25 * 2 bug fixes: * Re-release to refresh gem certificate signing. ugh. * Fixed hoe/minitest to not augment load path if we're actually testing minitest. === 5.8.4 / 2016-01-21 * 1 bug fix: * Allow Minitest::Assertion to pass through assert_raises so inner failures are dealt with first. === 5.8.3 / 2015-11-17 * 1 minor enhancement: * Added extra note about mocks and threads to readme. (zamith) * 1 bug fix: * Fixed bug in Mock#verify. (pithub/zamith) === 5.8.2 / 2015-10-26 * 1 bug fix: * Fixed using parallelize_me! and capture_io (or any locking io). (arlt/tenderlove) === 5.8.1 / 2015-09-23 * 1 minor enhancement: * Refactor assert_raises to be cleaner and to pass SystemExit and SignalException. (bhenderson) === 5.8.0 / 2015-08-06 * 2 minor enhancements: * Add optional delegation mechanism to extend object with a mock. (zamith) * Return early if there are no filtered methods. (jeremyevans) * 1 bug fix: * Don't extend io with pride if io is not a tty. (toy) === 5.7.0 / 2015-05-27 * 1 major enhancement: * assert_raises now matches subclasses of the expected exception types. (jeremyevans) * 3 minor enhancements: * Added :block type for minitest/spec's #infect_an_assertion. (jeremyevans) * Inline verification error messages in minitest/mock for GC performance. (zamith) * assert_raises defaults to RuntimeError if not specified. (jeremyevans) * 4 bug fixes: * Added 'class' to minitest/mock's overridden_methods list. (zamith) * Added file/line to infect_an_assertion's class_eval call. (jeremyevans) * Cleared UnexpectedError's mesg w/ generic string. * Fixed non-proc-oriented expectations when used on proc target. (jeremyevans) === 5.6.1 / 2015-04-27 * 2 bug fixes: * Added Minitest.clock_time and switched all Time.now to it. (tenderlove) * Moved Minitest::Expectations#_ into Minitest::Spec::DSL. === 5.6.0 / 2015-04-13 * 4 major enhancements: * Added Minitest::Expectation value monad. * Added Minitest::Expectations#_ that returns an Expectation. Aliased to value. * All expectations are added to Minitest::Expectation. * At some point, the methods on Object will be deprecated and then removed. * 4 minor enhancements: * Added a note about bundle exec pitfall in ruby 2.2+. (searls) * Lazily start the parallel executor. (tenderlove) * Make mocks more debugger-friendly (edward) * Print out the current test run on interrupt. (riffraff) * 3 bug fixes: * Fix failing test under Windows. (kimhmadsen) * Record mocked calls before they happen so mocks can raise exceptions easier (tho I'm not a fan). (corecode) * Tried to clarify mocks vs stubs terminology better. (kkirsche) === 5.5.1 / 2015-01-09 * 1 bug fix: * Fixed doco problems. (zzak) === 5.5.0 / 2014-12-12 // mri 2.2.0 (as a real gem) * 1 minor enhancement: * Allow seed to be given via ENV for rake test loader sadness: eg rake SEED=42. === 5.4.3 / 2014-11-11 * 2 bug fixes: * Clarified requirements for ruby are now 1.8.7 or better. * Force encode error output in case mal-encoded exception is raised. (jasonrclark) === 5.4.2 / 2014-09-26 * 2 minor enhancements: * Extract teardown method list. * Thanks to minitest-gcstats got a 5-10% speedup via reduced GC! === 5.4.1 / 2014-08-28 * 1 bug fix: * Fixed specs hidden by nesting/ordering bug (blowmage/apotonick) === 5.4.0 / 2014-07-07 * 2 minor enhancements: * Kernel#describe extended to splat additional_desc. * Spec#spec_type extended to take a splat of additional items, passed to matcher procs. * 1 bug fix: * minitest/spec should require minitest/test, not minitest/unit. (doudou) === 5.3.5 / 2014-06-17 * 1 minor enhancement: * Spit and polish (mostly spit). === 5.3.4 / 2014-05-15 * 1 minor enhancement: * Test classes are randomized before running. (judofyr) === 5.3.3 / 2014-04-14 * 1 bug fix: * Fixed using expectations w/ DSL in Test class w/o describe. (blowmage+others) === 5.3.2 / 2014-04-02 * 1 bug fix: * Fixed doco on Assertions.assertions. (xaviershay) === 5.3.1 / 2014-03-14 * 1 minor enhancement: * Modified verbage on bad 'let' names to be more helpful. (Archytaus) * 1 bug fix: * Fixed 2 cases still using MiniTest. (mikesea) === 5.3.0 / 2014-02-25 * 1 minor enhancement: * Mocked methods can take a block to verify state. Seattle.rb 12 bday present from ernie! Thanks!! === 5.2.3 / 2014-02-10 * 1 bug fix: * Fixed Spec#let check to allow overriding of other lets. (mvz) === 5.2.2 / 2014-01-22 * 1 minor enhancement: * Spec#let raises ArgumentError if you override _any_ instance method (except subject). (rynr) * 1 bug fix: * Fixed up benchmark spec doco and added a test to demonstrate. (bhenderson) === 5.2.1 / 2014-01-07 * 1 bug fix: * Properly deal with horrible mix of runtime load errors + other at_exit handlers. (dougo/chqr) === 5.2.0 / 2013-12-13 * 1 minor enhancement: * Change expectations to allow calling most on procs (but not calling the proc). (bhenderson+others) === 5.1.0 / 2013-12-05 * 1 minor enhancement: * Use a Queue for scheduling parallel tests. (tenderlove) * 1 bug fix: * Fixed misspelling in doco. (amatsuda) === 5.0.8 / 2013-09-20 * 1 bug fix: * Fixed siginfo handler by rearranging reporters and fixing to_s. (tenderlove) === 5.0.7 / 2013-09-05 * 2 minor enhancements: * Added clarification about the use of thread local variables in expectations. (jemc) * Added extra message about skipped tests, if any. Disable globally with $MT_NO_SKIP_MSG. * 2 bug fixes: * Only require minitest, not minitest/autorun in pride_plugin. (judofyr) * Require rubygems in load_plugins in case you're not using minitest/autorun. === 5.0.6 / 2013-06-28 * 3 minor enhancements: * Allow stub to pass args to blocks. (swindsor) * Improved warning message about minitest/autorun to address 1.9's minitest/autorun. * Made minitest/test require minitest as needed. For lib writers. (erikh) * 1 bug fix: * Fixed missing require in minitest/test. (erikh) === 4.7.5 / 2013-06-21 // mri 2.1.1 * 2 bug fixes: * Fix Spec#describe_stack to be thread local. * Fix multithreaded test failures by defining Time local to mock test namespace === 5.0.5 / 2013-06-20 * 6 bug fixes: * DOH! Fixed the rest of the new casing on Minitest. (splattael) * Fixed typo on minitest/mock rdoc. (mrgilman/guiceolin) * Make Spec::DSL.describe_stack thread local to avoid failing on my own tests. * Make a fake Time.now local to the tests so they won't interfere with real reporter timings. * Make everything mockable by wrapping all 'special' methods in a smarter wrapper. (bestie) * Raise ArgumentError if let name starts with 'test'. (johnmaxwell) === 5.0.4 / 2013-06-07 * 5 minor enhancements: * Added AbstractReporter, defining required Reporter API to quack properly. * Added doco for writing reporters. * Refactored Reporter into ProgressReporter and SummaryReporter. (idea: phiggins, code:me+scotch) * Refactored SummaryReporter pushing up to StatisticsReporter. (phiggins) * Removed Reporter#run_and_report... cleaner, but doesn't "fit" in the API. === 5.0.3 / 2013-05-29 * 4 minor enhancements: * Added Runnable.with_info_handler and Runnable.on_signal. * Moved io.sync restore to Reporter#run_and_report. * Refactored inner loop of Reporter#report to #to_s. Callable for status updates. * Restored MT4's mid-run report (^t). (tenderlove). === 5.0.2 / 2013-05-20 * 3 bug fixes: * Gem.find_files is smarter than I remember... cause I wrote it that way. *sigh* I'm getting old. * Pride wasn't doing puts through its #io. (tmiller/tenderlove) * Replaced Runnable#dup and Test#dup with marshal_dump/load. Too many problems cropping up on untested rails code. (tenderlove/rubys) === 5.0.1 / 2013-05-14 * 2 bug fixes: * Documented Assertions' need for @assertions to be defined by the includer. * Only load one plugin version per name. Tries for latest. === 5.0.0 / 2013-05-10 Oh god... here we go... Minitest 5: * 4 deaths in the family: * MiniTest.runner is dead. No more manager objects. * MiniTest::Unit#record is dead. Use a Reporter instance instead. * MiniTest::Unit._run_* is dead. Runnable things are responsible for their own runs. * MiniTest::Unit.output is dead. No more centralized IO. * 12 major (oft incompatible) changes: * Renamed MiniTest to Minitest. Your pinkies will thank me. (aliased to MiniTest) * Removed MiniTest::Unit entirely. No more manager objects. * Added Minitest::Runnable. Everything minitest can run subclasses this. * Renamed MiniTest::Unit::TestCase to Minitest::Test (subclassing Runnable). * Added Minitest::Benchmark. * Your benchmarks need to move to their own subclass. * Benchmarks using the spec DSL have to have "Bench" somewhere in their describe. * MiniTest::Unit.after_tests moved to Minitest.after_tests * MiniTest::Unit.autorun is now Minitest.autorun. Just require minitest/autorun pls. * Removed ParallelEach#grep since it isn't used anywhere. * Renamed Runnable#__name__ to Runnable#name (but uses @NAME internally). * Runnable#run needs to return self. Allows for swapping of results as needed. * 8 minor moves: * Moved Assertions module to minitest/assertions.rb * Moved Expectations module to minitest/expectations.rb * Moved Test to minitest/test.rb * Moved everything else in minitest/unit.rb to minitest.rb * minitest/unit.rb is now just a small (user-test only) compatibility layer. * Moved most of minitest/pride into minitest/pride_plugin. * minitest/pride now just activates pride. * Moved ParallelEach under Minitest. * 9 additions: * Added a plugin system that can extend command-line options. * Added Minitest.extensions. * Added Minitest.reporter (only available during startup). * Added Minitest.run(args). This is the very top of any Minitest run. * Added Minitest::Reporter. Everything minitest can report goes through here. * Minitest.reporter is a composite so you can add your own. * Added Minitest::CompositeReporter. Much easier to extend with your own reporters. * Added UnexpectedError, an Assertion subclass, to wrap up errors. * Minitest::Test#run is now freakin' beautiful. 47 -> 17 loc * 11 other: * Removed Object.infect_with_assertions (it was already dead code). * Runnables are responsible for knowing their result_code (eg "." or "F"). * Minitest.autorun now returns boolean, not exit code. * Added FAQ entry for extending via modules. (phiggins) * Implement Runnable#dup to cleanse state back to test results. Helps with serialization. pair:tenderlove * Moved ParallelEach under Minitest. * Runnable#run needs to return self. Allows for swapping of results as needed. * Minitest.init_plugins passes down options. * Minitest.load_plugins only loads once. * Fixed minitest/pride to work with rake test loader again. (tmiller) * Added count/size to ParallelEach to fix use w/in stdlib's test/unit. :( (btaitelb) * 5 voodoo: * Removed mutex from minitest.rb (phiggins) * Removed mutex from test.rb (phiggins) * Removed Minitest::Reporter.synchronize (phiggins) * Removed Minitest::Test.synchronize (phiggins) * Upon loading minitest/parallel_each, record, capture_io and capture_subprocess_io are doped with synchronization code. (phiggins) === 4.7.4 / 2013-05-01 This is probably the last release of the 4.x series. It will be merged to ruby and will be put into maintenance mode there. I'm not set in stone on this, but at this point further development of minitest (5+) will be gem-only. It is just too hard to work w/in ruby-core w/ test-unit compatibility holding minitest development back. * 2 minor enhancements: * Added count/size to ParallelEach to fix use w/in stdlib's test/unit. :( (btaitelb) * Allow disabling of info_signal handler in runner. (erikh) === 4.7.3 / 2013-04-20 * 1 bug fix: * Reverted stubbing of module methods change. Stub the user, not the impl. (ab9/tyabe) === 4.7.2 / 2013-04-18 * 2 bug fixes: * Fixed inconsistency in refute_in_delta/epsilon. I double negatived my logic. (nettsundere) * Fixed stubbing of module methods (eg Kernel#sleep). (steveklabnik) === 4.7.1 / 2013-04-09 * 1 minor enhancement: * Added FAQ section to README * 1 bug fix: * Fixed bug where guard runs tests bypassing minitest/autorun and an ivar isn't set right. (darrencauthon) === 4.7.0 / 2013-03-18 * 1 major enhancement: * Refactored MiniTest::Spec into MiniTest::Spec::DSL. * 1 bug fix: * Removed $DEBUG handler that detected when test/unit and minitest were both loaded. (tenderlove) === 4.6.2 / 2013-02-27 * 1 minor enhancement: * Change error output to match Class#method, making it easier to use -n filter. === 4.6.1 / 2013-02-14 * 1 bug fix: * Fixed an option processing bug caused by test/unit's irresponsibly convoluted code. (floehopper) === 4.6.0 / 2013-02-07 * 3 major enhancements: * Removed ::reset_setup_teardown_hooks * Removed the long deprecated assert_block * Removed the long deprecated lifecycle hooks: add_(setup|teardown)_hook * 1 minor enhancement: * Allow filtering tests by suite name as well as test name. (lazyatom) * 2 bug fixes: * Made hex handling (eg object_ids) in mu_pp_for_diff more specific. (maxim) * nodoc top-level module. (zzak) === 4.5.0 / 2013-01-22 * 1 major enhancement: * Rearranged minitest/unit.rb so NO parallelization code is loaded/used until you opt-in. * 4 minor enhancements: * Added TestCase#skipped? for teardown guards * Added maglev? guard * Document that record can be sent twice if teardown fails or errors (randycoulman) * Errors in teardown are now recorded. (randycoulman) * 3 bug fixes: * Added hacks and skips to get clean test runs on maglev * Modified float tests for maglev float output differences. Not sure this is right. Not sure I care. * Test for existance of diff.exe instead of assuming they have devkit. (blowmage/Cumbayah) === 4.4.0 / 2013-01-07 * 3 minor enhancements: * Added fit_logarithic and assert_performance_logarithmic. (ktheory) * Merge processed options so others can mess with defaults. (tenderlove) * TestCase#message can now take another proc to defer custom message cost. (ordinaryzelig/bhenderson) * 1 bug fix: * TestCase#passed? now true if test is skipped. (qanhd) === 4.3.3 / 2012-12-06 * 1 bug fix: * Updated information about stubbing. (daviddavis) === 4.3.2 / 2012-11-27 // mri 2.0.0 * 1 minor enhancement: * Improved assert_equals error message to point you at #== of member objects. (kcurtin) === 4.3.1 / 2012-11-23 * 1 bug fix: * Moved test_children to serial testcase to prevent random failures. === 4.3.0 / 2012-11-17 * 4 minor enhancements: * Allow #autorun to run even if loaded with other test libs that call exit. (sunaku) * Do not include Expectations in Object if $MT_NO_EXPECTATIONS is set (experimental?) * Gave some much needed love to assert_raises. * Mock#expect can take a block to custom-validate args. (gmoothart) === 4.2.0 / 2012-11-02 * 4 major enhancements: * Added minitest/hell - run all your tests through the ringer! * Added support for :parallel test_order to run test cases in parallel. * Removed last_error and refactored runner code to be threadsafe. * _run_suites now runs suites in parallel if they opt-in. * 4 minor enhancements: * Added TestCase#synchronize * Added TestCase.make_my_diffs_pretty! * Added TestCase.parallelize_me! * Lock on capture_io for thread safety (tenderlove) === 4.1.0 / 2012-10-05 * 2 minor enhancements: * Added skip example to readme. (dissolved) * Extracted backtrace filter to object. (tenderlove) * 1 bug fix: * OMG I'm so dumb. Fixed access to deprecated hook class methods. I hate ruby modules. (route) === 4.0.0 / 2012-09-28 * 1 major enhancement: * The names of a privately-used undocumented constants are Super Important™. * 1 minor enhancement: * Support stubbing methods that would be handled via method_missing. (jhsu) * 3 bug fixes: * Add include_private param to MiniTest::Mock#respond_to? (rf-) * Fixed use of minitest/pride with --help. (zw963) * Made 'No visible difference.' message more clear. (ckrailo) === 3.5.0 / 2012-09-21 * 1 minor enhancement: * Added #capture_subprocess_io. (route) === 3.4.0 / 2012-09-05 * 2 minor enhancements: * assert_output can now take regexps for expected values. (suggested by stomar) * Clarified that ruby 1.9/2.0's phony gems cause serious confusion for rubygems. === 3.3.0 / 2012-07-26 * 1 major enhancement: * Deprecated add_(setup|teardown)_hook in favor of (before|after)_(setup|teardown) [2013-01-01] * 4 minor enhancements: * Refactored deprecated hook system into a module. * Refactored lifecycle hooks into a module. * Removed after_setup/before_teardown + run_X_hooks from Spec. * Spec#before/after now do a simple define_method and call super. DUR. * 2 bug fixes: * Fixed #passed? when used against a test that called flunk. (floehopper) * Fixed rdoc bug preventing doco for some expectations. (stomar). === 3.2.0 / 2012-06-26 * 1 minor enhancement: * Stubs now yield self. (peterhellberg) * 1 bug fix: * Fixed verbose test that only fails when run in verbose mode. mmmm irony. === 3.1.0 / 2012-06-13 * 2 minor enhancements: * Removed LONG deprecated Unit.out accessor * Removed generated method name munging from minitest/spec. (ordinaryzelig/tenderlove) === 3.0.1 / 2012-05-24 * 1 bug fix: * I'm a dumbass and refactored into Mock#call. Renamed to #__call so you can mock #call. (mschuerig) === 3.0.0 / 2012-05-08 * 3 major enhancements: * Added Object#stub (in minitest/mock.rb). * Mock#expect mocks are used in the order they're given. * Mock#verify now strictly compares against expect calls. * 3 minor enhancements: * Added caller to deprecation message. * Mock error messages are much prettier. * Removed String check for RHS of assert/refute_match. This lets #to_str work properly. * 1 bug fix: * Support drive letter on Windows. Patch provided from MRI by Usaku NAKAMURA. (ayumin) === 2.12.1 / 2012-04-10 * 1 minor enhancement: * Added ruby releases to History.txt to make it easier to see what you're missing * 1 bug fix: * Rolled my own deprecate msg to allow MT to work with rubygems < 1.7 === 2.12.0 / 2012-04-03 * 4 minor enhancements: * ::it returns test method name (wojtekmach) * Added #record method to runner so runner subclasses can cleanly gather data. * Added Minitest alias for MiniTest because even I forget. * Deprecated assert_block!! Yay!!! * 1 bug fix: * Fixed warning in i_suck_and_my_tests_are_order_dependent! (phiggins) === 2.11.4 / 2012-03-20 * 2 minor enhancements: * Updated known extensions * You got your unicode in my tests! You got your tests in my unicode! (fl00r) * 1 bug fix: * Fixed MiniTest::Mock example in the readme. (conradwt) === 2.11.3 / 2012-02-29 * 2 bug fixes: * Clarified that assert_raises returns the exception for further testing * Fixed assert_in_epsilon when both args are negative. (tamc) === 2.11.2 / 2012-02-14 * 1 minor enhancement: * Display failures/errors on SIGINFO. (tenderlove) * 1 bug fix: * Fixed MiniTest::Unit.after_tests for Ruby 1.9.3. (ysbaddaden) === 2.11.1 / 2012-02-01 * 3 bug fixes: * Improved description for --name argument. (drd) * Ensure Mock#expect's expected args is an Array. (mperham) * Ensure Mock#verify verifies multiple expects of the same method. (chastell) === 2.11.0 / 2012-01-25 * 2 minor enhancements: * Added before / after hooks for setup and teardown. (tenderlove) * Pushed run_setup_hooks down to Spec. (tenderlove) === 2.10.1 / 2012-01-17 * 1 bug fix: * Fixed stupid 1.9 path handling grumble grumble. (graaff) === 2.10.0 / 2011-12-20 * 3 minor enhancements: * Added specs for must/wont be_empty/respond_to/be_kind_of and others. * Added tests for assert/refute predicate. * Split minitest/excludes.rb out to its own gem. * 1 bug fix: * Fixed must_be_empty and wont_be_empty argument handling. (mrsimo) === 2.9.1 / 2011-12-13 * 4 minor enhancements: * Added a ton of tests on spec error message output. * Cleaned up consistency of msg handling on unary expectations. * Improved error messages on assert/refute_in_delta. * infect_an_assertion no longer checks arity and better handles args. * 1 bug fix: * Fixed error message on specs when 2+ args and custom message provided. (chastell) === 2.9.0 / 2011-12-07 * 4 minor enhancements: * Added TestCase.exclude and load_excludes for programmatic filtering of tests. * Added guard methods so you can cleanly skip based on platform/impl * Holy crap! 100% doco! `rdoc -C` ftw * Switch assert_output to test stderr before stdout to possibly improve debugging === 2.8.1 / 2011-11-17 * 1 bug fix: * Ugh. 1.9's test/unit violates my internals. Added const_missing. === 2.8.0 / 2011-11-08 * 2 minor enhancements: * Add a method so that code can be run around a particular test case (tenderlove) * Turn off backtrace filtering if we're running inside a ruby checkout. (drbrain) * 2 bug fixes: * Fixed 2 typos and 2 doc glitches. (splattael) * Remove unused block arguments to avoid creating Proc objects. (k-tsj) === 2.7.0 / 2011-10-25 * 2 minor enhancements: * Include failed values in the expected arg output in MockExpectationError. (nono) * Make minitest/pride work with other 256 color capable terms. (sunaku) * 2 bug fixes: * Clarified the documentation of minitest/benchmark (eregon) * Fixed using expectations in regular unit tests. (sunaku) === 2.6.2 / 2011-10-19 * 1 minor enhancement: * Added link to vim bundle. (sunaku) * 2 bug fixes: * Force gem activation in hoe minitest plugin * Support RUBY_VERSION='2.0.0' (nagachika) === 2.6.1 / 2011-09-27 * 2 bug fixes: * Alias Spec.name from Spec.to_s so it works when @name is nil (nathany) * Fixed assert and refute_operator where second object has a bad == method. === 2.6.0 / 2011-09-13 * 2 minor enhancements: * Added specify alias for it and made desc optional. * Spec#must_be and #wont_be can be used with predicates (metaskills) * 1 bug fix: * Fixed Mock.respond_to?(var) to work with strings. (holli) === 2.5.1 / 2011-08-27 // ruby 1.9.3: p0, p125, p34579 * 2 minor enhancements: * Added gem activation for minitest in minitest/autoload to help out 1.9 users * Extended Spec.register_spec_type to allow for procs instead of just regexps. === 2.5.0 / 2011-08-18 * 4 minor enhancements: * Added 2 more arguments against rspec: let & subject in 9 loc! (emmanuel/luis) * Added TestCase.i_suck_and_my_tests_are_order_dependent! * Extended describe to take an optional method name (2 line change!). (emmanuel) * Refactored and extended minitest/pride to do full 256 color support. (lolcat) * 1 bug fix: * Doc fixes. (chastell) === 2.4.0 / 2011-08-09 * 4 minor enhancements: * Added simple examples for all expectations. * Improved Mock error output when args mismatch. * Moved all expectations from Object to MiniTest::Expectations. * infect_with_assertions has been removed due to excessive clever * 4 bug fixes: * Fix Assertions#mu_pp to deal with immutable encoded strings. (ferrous26) * Fix minitest/pride for MacRuby (ferrous26) * Made error output less fancy so it is more readable * Mock shouldn't undef === and inspect. (dgraham) === 2.3.1 / 2011-06-22 * 1 bug fix: * Fixed minitest hoe plugin to be a spermy dep and not depend on itself. === 2.3.0 / 2011-06-15 * 5 minor enhancements: * Add setup and teardown hooks to MiniTest::TestCase. (phiggins) * Added nicer error messages for MiniTest::Mock. (phiggins) * Allow for less specific expected arguments in Mock. (bhenderson/phiggins) * Made MiniTest::Mock a blank slate. (phiggins) * Refactored minitest/spec to use the hooks instead of define_inheritable_method. (phiggins) * 2 bug fixes: * Fixed TestCase's inherited hook. (dchelimsky/phiggins/jamis, the 'good' neighbor) * MiniTest::Assertions#refute_empty should use mu_pp in the default message. (whatthejeff) === 2.2.2 / 2011-06-01 * 2 bug fixes: * Got rid of the trailing period in message for assert_equal. (tenderlove) * Windows needs more flushing. (Akio Tajima) === 2.2.1 / 2011-05-31 * 1 bug fix: * My _ONE_ non-rubygems-using minitest user goes to Seattle.rb! === 2.2.0 / 2011-05-29 * 6 minor enhancements: * assert_equal (and must_equal) now tries to diff output where it makes sense. * Added Assertions#diff(exp, act) to be used by assert_equal. * Added Assertions#mu_pp_for_diff * Added Assertions.diff and diff= * Moved minitest hoe-plugin from hoe-seattlerb. (erikh) * Skipped tests only output details in verbose mode. (tenderlove+zenspider=xoxo) === 2.1.0 / 2011-04-11 * 5 minor enhancements: * Added MiniTest::Spec.register_spec_type(matcher, klass) and spec_type(desc) * Added ability for specs to share code via subclassing of Spec. (metaskills) * Clarified (or tried to) bench_performance_linear's use of threshold. * MiniTest::Unit.runner=(runner) provides an easy way of creating custom test runners for specialized needs. (justinweiss) * Reverse order of inheritance in teardowns of specs. (deepfryed) * 3 bug fixes: * FINALLY fixed problems of inheriting specs in describe/it/describe scenario. (MGPalmer) * Fixed a new warning in 1.9.3. * Fixed assert_block's message handling. (nobu) === 2.0.2 / 2010-12-24 * 1 minor enhancement: * Completed doco on minitest/benchmark for specs. * 1 bug fix: * Benchmarks in specs that didn't call bench_range would die. (zzak). === 2.0.1 / 2010-12-15 * 4 minor enhancements: * Do not filter backtrace if $DEBUG * Exit autorun via nested at_exit handler, in case other libs call exit * Make options accesor lazy. * Split printing of test name and its time. (nurse) * 1 bug fix: * Fix bug when ^T is hit before runner start === 2.0.0 / 2010-11-11 * 3 major enhancements: * Added minitest/benchmark! Assert your performance! YAY! * Refactored runner to allow for more extensibility. See minitest/benchmark. * This makes the runner backwards incompatible in some ways! * 9 minor enhancements: * Added MiniTest::Unit.after_tests { ... } * Improved output by adding test rates and a more sortable verbose format * Improved readme based on feedback from others * Added io method to TestCase. If used, it'll supplant '.EF' output. * Refactored IO in MiniTest::Unit. * Refactored _run_anything to _run_suite to make it easier to wrap (ngauthier) * Spec class names are now the unmunged descriptions (btakita) * YAY for not having redundant rdoc/readmes! * Help output is now generated from the flags you passed straight up. * 4 bug fixes: * Fixed scoping issue on minitest/mock (srbaker/prosperity) * Fixed some of the assertion default messages * Fixes autorun when on windows with ruby install on different drive (larsch) * Fixed rdoc output bug in spec.rb === 1.7.2 / 2010-09-23 * 3 bug fixes: * Fixed doco for expectations and Spec. * Fixed test_capture_io on 1.9.3+ (sora_h) * assert_raises now lets MiniTest::Skip through. (shyouhei) === 1.7.1 / 2010-09-01 * 1 bug fix: * 1.9.2 fixes for spec tests === 1.7.0 / 2010-07-15 * 5 minor enhancements: * Added assert_output (mapped to must_output). * Added assert_silent (mapped to must_be_silent). * Added examples to readme (Mike Dalessio) * Added options output at the top of the run, for fatal run debugging (tenderlove) * Spec's describe method returns created class === 1.6.0 / 2010-03-27 // ruby 1.9.2-p290 * 10 minor enhancements: * Added --seed argument so you can reproduce a random order for debugging. * Added documentation for assertions * Added more rdoc and tons of :nodoc: * Added output to give you all the options you need to reproduce that run. * Added proper argument parsing to minitest. * Added unique serial # to spec names so order can be preserved (needs tests). (phrogz) * Empty 'it' fails with default msg. (phrogz) * Remove previous method on expect to remove 1.9 warnings * Spec#it is now order-proof wrt subclasses/nested describes. * assert_same error message now reports in decimal, eg: oid=123. (mattkent) * 2 bug fixes: * Fixed message on refute_same to be consistent with assert_same. * Fixed method randomization to be stable for testing. === 1.5.0 / 2010-01-06 * 4 minor enhancements: * Added ability to specify what assertions should have their args flipped. * Don't flip arguments on *include and *respond_to assertions. * Refactored Module.infect_an_assertion from Module.infect_with_assertions. * before/after :all now bitches and acts like :each * 3 bug fixes: * Nested describes now map to nested test classes to avoid namespace collision. * Using undef_method instead of remove_method to clean out inherited specs. * assert_raises was ignoring passed in message. === 1.4.2 / 2009-06-25 * 1 bug fix: * Fixed info handler for systems that don't have siginfo. === 1.4.1 / 2009-06-23 * 1 major enhancement: * Handle ^C and other fatal exceptions by failing * 1 minor enhancement: * Added something to catch mixed use of test/unit and minitest if $DEBUG * 1 bug fix: * Added SIGINFO handler for finding slow tests without verbose === 1.4.0 / 2009-06-18 * 5 minor enhancement: * Added clarification doco. * Added specs and mocks to autorun. * Changed spec test class creation to be non-destructive. * Updated rakefile for new hoe capabilities. * describes are nestable (via subclass). before/after/def inherits, specs don't. * 3 bug fixes: * Fixed location on must/wont. * Switched to __name__ to avoid common ivar name. * Fixed indentation in test file (1.9). === 1.3.1 / 2009-01-20 // ruby 1.9.1-p431 * 1 minor enhancement: * Added miniunit/autorun.rb as replacement for test/unit.rb's autorun. * 16 bug fixes: * 1.9 test fixes. * Bug fixes from nobu and akira for really odd scenarios. They run ruby funny. * Fixed (assert|refute)_match's argument order. * Fixed LocalJumpError in autorun if exception thrown before at_exit. * Fixed assert_in_delta (should be >=, not >). * Fixed assert_raises to match Modules. * Fixed capture_io to not dup IOs. * Fixed indentation of capture_io for ruby 1.9 warning. * Fixed location to deal better with custom assertions and load paths. (Yuki) * Fixed order of (must|wont)_include in MiniTest::Spec. * Fixed skip's backtrace. * Got arg order wrong in *_match in tests, message wrong as a result. * Made describe private. For some reason I thought that an attribute of Kernel. * Removed disable_autorun method, added autorun.rb instead. * assert_match escapes if passed string for pattern. * instance_of? is different from ===, use instance_of. === 1.3.0 / 2008-10-09 * 2 major enhancements: * renamed to minitest and pulled out test/unit compatibility. * mini/test.rb is now minitest/unit.rb, everything else maps directly. * 12 minor enhancements: * assert_match now checks that act can call =~ and converts exp to a regexp only if needed. * Added assert_send... seems useless to me tho. * message now forces to string... ruby-core likes to pass classes and arrays :( * Added -v handling and switched to @verbose from $DEBUG. * Verbose output now includes test class name and adds a sortable running time! * Switched message generation into procs for message deferment. * Added skip and renamed fail to flunk. * Improved output failure messages for assert_instance_of, assert_kind_of * Improved output for assert_respond_to, assert_same. * at_exit now exits false instead of errors+failures. * Made the tests happier and more readable imhfo. * Switched index(s) == 0 to rindex(s, 0) on nobu's suggestion. Faster. * 5 bug fixes: * 1.9: Added encoding normalization in mu_pp. * 1.9: Fixed backtrace filtering (BTs are expanded now) * Added back exception_details to assert_raises. DOH. * Fixed shadowed variable in mock.rb * Fixed stupid muscle memory message bug in assert_send. === 1.2.1 / 2008-06-10 * 7 minor enhancements: * Added deprecations everywhere in test/unit. * Added test_order to TestCase. :random on mini, :sorted on test/unit (for now). * Big cleanup in test/unit for rails. Thanks Jeremy Kemper! * Minor readability cleanup. * Pushed setup/run/teardown down to testcase allowing specialized testcases. * Removed pp. Tests run 2x faster. :/ * Renamed deprecation methods and moved to test/unit/deprecate.rb. === 1.2.0 / 2008-06-09 * 2 major enhancements: * Added Mini::Spec. * Added Mini::Mock. Thanks Steven Baker!! * 23 minor enhancements: * Added bin/use_miniunit to make it easy to test out miniunit. * Added -n filtering, thanks to Phil Hagelberg! * Added args argument to #run, takes ARGV from at_exit. * Added test name output if $DEBUG. * Added a refute (was deny) for every assert. * Added capture_io and a bunch of nice assertions from zentest. * Added deprecation mechanism for assert_no/not methods to test/unit/assertions. * Added pp output when available. * Added tests for all assertions. Pretty much maxed out coverage. * Added tests to verify consistency and good naming. * Aliased and deprecated all ugly assertions. * Cleaned out test/unit. Moved autorun there. * Code cleanup to make extensions easier. Thanks Chad! * Got spec args reversed in all but a couple assertions. Much more readable. * Improved error messages across the board. Adds your message to the default. * Moved into Mini namespace, renamed to Mini::Test and Mini::Spec. * Pulled the assertions into their own module... * Removed as much code as I could while still maintaining full functionality. * Moved filter_backtrace into MiniTest. * Removed MiniTest::Unit::run. Unnecessary. * Removed location_of_failure. Unnecessary. * Rewrote test/unit's filter_backtrace. Flog from 37.0 to 18.1 * Removed assert_send. Google says it is never used. * Renamed MiniTest::Unit.autotest to #run. * Renamed deny to refute. * Rewrote some ugly/confusing default assertion messages. * assert_in_delta now defaults to 0.001 precision. Makes specs prettier. * 9 bug fixes: * Fixed assert_raises to raise outside of the inner-begin/rescue. * Fixed for ruby 1.9 and rubinius. * No longer exits 0 if exception in code PRE-test run causes early exit. * Removed implementors method list from mini/test.rb - too stale. * assert_nothing_raised takes a class as an arg. wtf? STUPID * ".EF" output is now unbuffered. * Bunch of changes to get working with rails... UGH. * Added stupid hacks to deal with rails not requiring their dependencies. * Now bitch loudly if someone defines one of my classes instead of requiring. * Fixed infect method to work better on 1.9. * Fixed all shadowed variable warnings in 1.9. === 1.1.0 / 2007-11-08 * 4 major enhancements: * Finished writing all missing assertions. * Output matches original test/unit. * Documented every method needed by language implementor. * Fully switched over to self-testing setup. * 2 minor enhancements: * Added deny (assert ! test), our favorite extension to test/unit. * Added .autotest and fairly complete unit tests. (thanks Chad for help here) === 1.0.0 / 2006-10-30 * 1 major enhancement * Birthday! PKu]5~~#minitest-5.13.0/design_rationale.rbnu[# Specs: # Equivalent Unit Tests: ############################################################################### describe Thingy do # class TestThingy < Minitest::Test before do # def setup do_some_setup # super end # do_some_setup # end it "should do the first thing" do # 1.must_equal 1 # def test_first_thing end # assert_equal 1, 1 # end describe SubThingy do # end before do # do_more_setup # class TestSubThingy < TestThingy end # def setup # super it "should do the second thing" do # do_more_setup 2.must_equal 2 # end end # end # def test_second_thing end # assert_equal 2, 2 # end # end ############################################################################### # runs 2 specs # runs 3 tests ############################################################################### # The specs generate: class ThingySpec < Minitest::Spec def setup super do_some_setup end def test_should_do_the_first_thing assert_equal 1, 1 end end class SubThingySpec < ThingySpec def setup super do_more_setup end # because only setup/teardown is inherited, not specs remove_method :test_should_do_the_first_thing def test_should_do_the_second_thing assert_equal 2, 2 end end PKu]:n&5&5test-unit-3.3.4/PSFLnu[This is the official license for the Python 2.5 release: A. HISTORY OF THE SOFTWARE ========================== Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands as a successor of a language called ABC. Guido remains Python's principal author, although it includes many contributions from others. In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) in Reston, Virginia where he released several versions of the software. In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations (now Zope Corporation, see http://www.zope.com). In 2001, the Python Software Foundation (PSF, see http://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation is a sponsoring member of the PSF. All Python releases are Open Source (see http://www.opensource.org for the Open Source Definition). Historically, most, but not all, Python releases have also been GPL-compatible; the table below summarizes the various releases. Release Derived Year Owner GPL- from compatible? (1) 0.9.0 thru 1.2 1991-1995 CWI yes 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes 1.6 1.5.2 2000 CNRI no 2.0 1.6 2000 BeOpen.com no 1.6.1 1.6 2001 CNRI yes (2) 2.1 2.0+1.6.1 2001 PSF no 2.0.1 2.0+1.6.1 2001 PSF yes 2.1.1 2.1+2.0.1 2001 PSF yes 2.2 2.1.1 2001 PSF yes 2.1.2 2.1.1 2002 PSF yes 2.1.3 2.1.2 2002 PSF yes 2.2.1 2.2 2002 PSF yes 2.2.2 2.2.1 2002 PSF yes 2.2.3 2.2.2 2003 PSF yes 2.3 2.2.2 2002-2003 PSF yes 2.3.1 2.3 2002-2003 PSF yes 2.3.2 2.3.1 2002-2003 PSF yes 2.3.3 2.3.2 2002-2003 PSF yes 2.3.4 2.3.3 2004 PSF yes 2.3.5 2.3.4 2005 PSF yes 2.4 2.3 2004 PSF yes 2.4.1 2.4 2005 PSF yes 2.4.2 2.4.1 2005 PSF yes 2.4.3 2.4.2 2006 PSF yes 2.5 2.4 2006 PSF yes Footnotes: (1) GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't. (2) According to Richard Stallman, 1.6.1 is not GPL-compatible, because its license has a choice of law clause. According to CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 is "not incompatible" with the GPL. Thanks to the many outside volunteers who have worked under Guido's direction to make these releases possible. B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON =============================================================== PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python. 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 ------------------------------------------- BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization ("Licensee") accessing and otherwise using this software in source or binary form and its associated documentation ("the Software"). 2. Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee. 3. BeOpen is making the Software available to Licensee on an "AS IS" basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 5. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the "BeOpen Python" logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page. 7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement. CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 --------------------------------------- 1. This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 ("CNRI"), and the Individual or Organization ("Licensee") accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) 1995-2001 Corporation for National Research Initiatives; All Rights Reserved" are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): "Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the Internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the Internet using the following URL: http://hdl.handle.net/1895.22/1013". 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1. 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By clicking on the "ACCEPT" button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement. ACCEPT CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 -------------------------------------------------- Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. PKu]FNFFtest-unit-3.3.4/GPLnu[ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. PKu]~""test-unit-3.3.4/Rakefilenu[# -*- ruby -*- # # Copyright (C) 2008-2017 Kouhei Sutou # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Encoding.default_internal = "UTF-8" if defined?(Encoding.default_internal) # TODO: Remove me when we drop Ruby 1.9 support. unless "".respond_to?(:b) class String def b dup.force_encoding("ASCII-8BIT") end end end require "erb" require "yaml" require "rubygems" require "rake/clean" require "yard" require "bundler/gem_helper" require "packnga" task :default => :test base_dir = File.dirname(__FILE__) html_base_dir = File.join(base_dir, "doc", "html") helper = Bundler::GemHelper.new(base_dir) def helper.version_tag version end helper.install spec = helper.gemspec document_task = Packnga::DocumentTask.new(spec) do |task| task.original_language = "en" task.translate_languages = ["ja"] end Packnga::ReleaseTask.new(spec) do |task| test_unit_github_io_dir_candidates = [ "../../www/test-unit.github.io", ] test_unit_github_io_dir = test_unit_github_io_dir_candidates.find do |dir| File.directory?(dir) end task.index_html_dir = test_unit_github_io_dir end def rake(*arguments) ruby($0, *arguments) end namespace :html do desc "Publish HTML to Web site." task :publish do # FIXME Do nothing for now #rsync_to_rubyforge(spec, "#{html_base_dir}/", "") end end task :test do ruby("test/run-test.rb") end PKu]s  (test-unit-3.3.4/test/util/test-output.rbnu[require 'test/unit' class TestUnitOutput < Test::Unit::TestCase def test_capture_output assert_equal(["stdout\n", "stderr\n"], capture_output do puts("stdout") warn("stderr") end) end end PKu]cʪ1test-unit-3.3.4/test/util/test_backtracefilter.rbnu[require 'test/unit' require 'test/unit/util/backtracefilter' module Test::Unit::Util class TestBacktraceFilter < Test::Unit::TestCase include BacktraceFilter def test_filter_backtrace backtrace = [%q{C:\some\old\path/test/unit/assertions.rb:44:in 'assert'}, %q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}, %q{C:\some\old\path/test/unit/testcase.rb:44:in 'send'}, %q{C:\some\old\path\test\unit\testcase.rb:44:in 'run'}, %q{C:\some\old\path\test\unit.rb:44:in 'run'}, %q{tc_thing.rb:3}] assert_equal(backtrace[1..2], filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Should filter out all TestUnit-specific lines") backtrace = [%q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}, %q{tc_thing.rb:3}] assert_equal(backtrace, filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Shouldn't filter too much") backtrace = [%q{C:\some\old\path/test/unit/assertions.rb:44:in 'assert'}, %q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}, %q{tc_thing.rb:3}] assert_equal(backtrace[1..3], filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Should filter out all TestUnit-specific lines") backtrace = [%q{C:\some\old\path/test/unit/assertions.rb:44:in 'assert'}, %q{C:\some\old\path/test/unit/testcase.rb:44:in 'send'}, %q{C:\some\old\path\test\unit\testcase.rb:44:in 'run'}, %q{C:\some\old\path\test\unit.rb:44:in 'run'}] assert_equal(backtrace, filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Should filter out all TestUnit-specific lines") end def test_nil_backtrace assert_equal(["No backtrace"], filter_backtrace(nil)) end def test_power_assert_backtrace omit('test for power_assert') unless defined?(PowerAssert) blk = Proc.new {caller.find {|i| /power_assert.*in \`start\'/ =~ i}} PowerAssert.start(blk) do |pa| backtrace = [pa.yield, %q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}] assert_equal(backtrace[1..2], filter_backtrace(backtrace)) end end end end PKu]`+O,test-unit-3.3.4/test/util/test_observable.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/observable' module Test module Unit module Util class TC_Observable < TestCase class TF_Observable include Observable end def setup @observable = TF_Observable.new end def test_simple_observation assert_raises(ArgumentError, "add_listener should throw an exception if no callback is supplied") do @observable.add_listener(:property, "a") end heard = false callback = proc { heard = true } assert_equal("a", @observable.add_listener(:property, "a", &callback), "add_listener should return the listener that was added") count = 0 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(1, count, "notify_listeners should have returned the number of listeners that were notified") assert(heard, "Should have heard the property changed") heard = false assert_equal(callback, @observable.remove_listener(:property, "a"), "remove_listener should return the callback") count = 1 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(0, count, "notify_listeners should have returned the number of listeners that were notified") assert(!heard, "Should not have heard the property change") end def test_value_observation value = nil @observable.add_listener(:property, "a") do |passed_value| value = passed_value end count = 0 @observable.instance_eval do count = notify_listeners(:property, "stuff") end assert_equal(1, count, "Should have update the correct number of listeners") assert_equal("stuff", value, "Should have received the value as an argument to the listener") end def test_multiple_value_observation values = [] @observable.add_listener(:property, "a") do |first_value, second_value| values = [first_value, second_value] end count = 0 @observable.instance_eval do count = notify_listeners(:property, "stuff", "more stuff") end assert_equal(1, count, "Should have update the correct number of listeners") assert_equal(["stuff", "more stuff"], values, "Should have received the value as an argument to the listener") end def test_add_remove_with_default_listener assert_raises(ArgumentError, "add_listener should throw an exception if no callback is supplied") do @observable.add_listener(:property) end heard = false callback = proc { heard = true } assert_equal(callback, @observable.add_listener(:property, &callback), "add_listener should return the listener that was added") count = 0 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(1, count, "notify_listeners should have returned the number of listeners that were notified") assert(heard, "Should have heard the property changed") heard = false assert_equal(callback, @observable.remove_listener(:property, callback), "remove_listener should return the callback") count = 1 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(0, count, "notify_listeners should have returned the number of listeners that were notified") assert(!heard, "Should not have heard the property change") end end end end end PKu]-test-unit-3.3.4/test/util/test_procwrapper.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/util/procwrapper' module Test module Unit module Util class TC_ProcWrapper < TestCase def munge_proc(&a_proc) return a_proc end def setup @original = proc {} @munged = munge_proc(&@original) @wrapped_original = ProcWrapper.new(@original) @wrapped_munged = ProcWrapper.new(@munged) end def test_wrapping assert_same(@original, @wrapped_original.to_proc, "The wrapper should return what was wrapped") end def test_hashing assert_equal(@wrapped_original.hash, @wrapped_munged.hash, "The original and munged should have the same hash when wrapped") assert_equal(@wrapped_original, @wrapped_munged, "The wrappers should be equivalent") a_hash = {@wrapped_original => @original} assert(a_hash[@wrapped_original], "Should be able to access the wrapper in the hash") assert_equal(a_hash[@wrapped_original], @original, "Should be able to access the wrapper in the hash") end end end end end PKu]^&15test-unit-3.3.4/test/util/test-method-owner-finder.rbnu[require 'test/unit' require 'test/unit/util/method-owner-finder' class TestUnitMethodOwnerFinder < Test::Unit::TestCase def test_find assert_equal(Exception, find(RuntimeError.new, :inspect)) assert_equal(Exception, find(Exception.new, :inspect)) anonymous_class = Class.new do end assert_equal(Kernel, find(anonymous_class.new, :inspect)) anonymous_parent_class = Class.new do def inspect super + " by anonymous parent class" end end anonymous_sub_class = Class.new(anonymous_parent_class) do end assert_equal(anonymous_parent_class, find(anonymous_sub_class.new, :inspect)) anonymous_module = Module.new do def inspect super + " by anonymous module" end end anonymous_include_class = Class.new do include anonymous_module end assert_equal(anonymous_module, find(anonymous_include_class.new, :inspect)) end private def find(object, method_name) Test::Unit::Util::MethodOwnerFinder.find(object, method_name) end end PKu]z}J J (test-unit-3.3.4/test/test-test-result.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/testcase' require 'test/unit/testresult' module Test module Unit class TC_TestResult < TestCase def setup @my_result = TestResult.new @my_result.add_assertion() @failure = "failure" @my_result.add_failure(@failure) @error = "error" @my_result.add_error(@error) end def test_result_changed_notification called1 = false @my_result.add_listener(TestResult::CHANGED) do |result| assert_equal(@my_result, result) called1 = true end @my_result.add_assertion assert_true(called1) called1, called2 = false, false @my_result.add_listener(TestResult::CHANGED) do |result| assert_equal(@my_result, result) called2 = true end @my_result.add_assertion assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_failure("") assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_error("") assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_run assert_equal([true, true], [called1, called2]) end def test_fault_notification called1 = false fault = "fault" @my_result.add_listener(TestResult::FAULT) do |passed_fault| assert_equal(fault, passed_fault) called1 = true end @my_result.add_assertion assert_false(called1) @my_result.add_failure(fault) assert_true(called1) called1, called2 = false, false @my_result.add_listener(TestResult::FAULT) do |passed_fault| assert_equal(fault, passed_fault) called2 = true end @my_result.add_assertion assert_equal([false, false], [called1, called2]) called1, called2 = false, false @my_result.add_failure(fault) assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_error(fault) assert_equal([true, true], [called1, called2]) called1, called2 = false, false @my_result.add_run assert_equal([false, false], [called1, called2]) end def test_passed? result = TestResult.new assert_true(result.passed?) result.add_assertion assert_true(result.passed?) result.add_run assert_true(result.passed?) result.add_failure("") assert_false(result.passed?) result = TestResult.new result.add_error("") assert_false(result.passed?) end def test_faults assert_equal([@failure, @error], @my_result.faults) notification = "notification" @my_result.add_notification(notification) assert_equal([@failure, @error, notification], @my_result.faults) end end end end PKu]( DD(test-unit-3.3.4/test/fixtures/header.tsvnu[label expected target empty string true "" plain string false hello PKu]DD(test-unit-3.3.4/test/fixtures/header.csvnu[label,expected,target empty string,true,"" plain string,false,hello PKu]cm..+test-unit-3.3.4/test/fixtures/no-header.csvnu[empty string,true,"" plain string,false,hello PKu]? "..+test-unit-3.3.4/test/fixtures/no-header.tsvnu[empty string true "" plain string false hello PKu]_CC.test-unit-3.3.4/test/fixtures/header-label.csvnu[label,expected,label upper case,HELLO,HELLO lower case,Hello,hello PKu]*CC.test-unit-3.3.4/test/fixtures/header-label.tsvnu[label expected label upper case HELLO HELLO lower case Hello hello PKu]:bOO&test-unit-3.3.4/test/fixtures/plus.csvnu[label,expected,augend,addend positive positive,4,3,1 positive negative,-1,1,-2 PKu]D)test-unit-3.3.4/test/test-notification.rbnu[require 'test/unit' require 'testunit-test-util' class TestUnitNotification < Test::Unit::TestCase include TestUnitTestUtil class TestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end def test_notify notify("1st notify") notify("2nd notify. Reach here.") end end def test_notify result = _run_test("test_notify") assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, " \ "0 omissions, 2 notifications", result.to_s) assert_fault_messages(["1st notify", "2nd notify. Reach here."], result.notifications) end private def _run_test(name) super(TestCase, name) end end PKu]\҃P  %test-unit-3.3.4/test/test-priority.rbnu[require 'test/unit' class TestUnitPriority < Test::Unit::TestCase class TestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end priority :must def test_must assert(true) end def test_must_inherited assert(true) end priority :important def test_important assert(true) end def test_important_inherited assert(true) end priority :high def test_high assert(true) end def test_high_inherited assert(true) end priority :normal def test_normal assert(true) end def test_normal_inherited assert(true) end priority :low def test_low assert(true) end def test_low_inherited assert(true) end priority :never def test_never assert(true) end def test_never_inherited assert(true) end end def test_priority_must assert_priority("must", 1.0, 0.0001) end def test_priority_important assert_priority("important", 0.9, 0.09) end def test_priority_high assert_priority("high", 0.70, 0.1) end def test_priority_normal assert_priority("normal", 0.5, 0.1) end def test_priority_low assert_priority("low", 0.25, 0.1) end def test_priority_never assert_priority("never", 0.0, 0.0001) end def assert_priority(priority, expected, delta) assert_need_to_run("test_#{priority}", expected, delta) assert_need_to_run("test_#{priority}_inherited", expected, delta) end def assert_need_to_run(test_name, expected, delta) test = TestCase.new(test_name) n = 1000 n_need_to_run = 0 n.times do |i| n_need_to_run += 1 if Test::Unit::Priority::Checker.need_to_run?(test) end assert_in_delta(expected, n_need_to_run.to_f / n, delta) end class TestClassName < self def test_colon assert_escaped_name("Test_colon__colon_Priority", "Test::Priority") end def test_space assert_escaped_name("test_priority", "test priority") end def test_slash assert_escaped_name("test_priority", "test/priority") end def test_back_slash assert_escaped_name("test_priority", "test\/priority") end def test_question assert_escaped_name("#question.predicate", "#question?") end def test_exclamation assert_escaped_name("#exclamation.destructive", "#exclamation!") end def test_equal assert_escaped_name("#equal.equal", "#equal=") end def assert_escaped_name(expected, class_name) checker = Checker.new(nil) escaped_class_name = checker.send(:escape_class_name, class_name) assert_equal(expected, escaped_class_name) end end class TestFileName < self class SpecialNameTestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end def test_question? end def test_exclamation! end def test_equal= end test "have space" do end end def test_question assert_escaped_name("test_colon__#question.predicate_case", "test: #question? case") end def test_exclamation assert_escaped_name("test_colon__#exclamation.destructive_case", "test: #exclamation! case") end def test_equal assert_escaped_name("test_colon__#equal.equal_case", "test: #equal= case") end def assert_escaped_name(expected, test_method_name) checker = Checker.new(SpecialNameTestCase.new(test_method_name)) passed_file = checker.send(:passed_file) method_name_component = File.basename(File.dirname(passed_file)) assert_equal(expected, method_name_component) end end end PKu]52"test-unit-3.3.4/test/test-error.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' module Test module Unit class TC_Error < TestCase TF_Exception = Struct.new('TF_Exception', :message, :backtrace) def test_display ex = TF_Exception.new("message1\nmessage2", ['line1', 'line2']) e = Error.new("name", ex) assert_equal("name: #{TF_Exception.name}: message1", e.short_display) assert_equal(< :accessor}, test_for_accessor_category.attributes) test_for_bug_1234 = TestStack.new("test_bug_1234") assert_equal({"bug" => 1234}, test_for_bug_1234.attributes) test_no_attributes = TestStack.new("test_no_attributes") assert_equal({}, test_no_attributes.attributes) end def test_callback changed_attributes = [] observer = Proc.new do |test_case, key, old_value, value, method_name| changed_attributes << [test_case, key, old_value, value, method_name] end test_case = Class.new(TestStack) do register_attribute_observer(:bug, &observer) attribute("bug", 9876, "test_bug_1234") attribute(:description, "Test for peek", "test_peek") attribute(:bug, 29, "test_peek") end assert_equal([ [test_case, "bug", 1234, 9876, "test_bug_1234"], [test_case, "bug", nil, 29, "test_peek"], ], changed_attributes) end def test_attributes_with_prepended_module omit("Module#prepend is needed") unless Module.respond_to?(:prepend, true) test_case = Class.new(TestStack) do prepend Module.new end assert_equal({ "category" => :accessor, }, test_case.attributes("test_peek")) end class TestDescription < self def test_decoration_style test_case = Class.new(TestStack) do description "Test for push" def test_push end end test_push = test_case.new("test_push") assert_equal({"description" => "Test for push"}, test_push.attributes) end def test_explicit_test_name_style test_case = Class.new(TestStack) do def test_push end description "Test for push", :test_push end test_push = test_case.new("test_push") assert_equal({"description" => "Test for push"}, test_push.attributes) end end end PKu]d$test-unit-3.3.4/test/test-pending.rbnu[require 'test/unit' require 'testunit-test-util' class TestUnitPending < Test::Unit::TestCase include TestUnitTestUtil class TestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end def test_pend pend("1st pend") pend("2nd pend. Should not be reached here.") assert(true, "Should not be reached here too.") end def test_pend_with_failure_in_block pend("Wait a minute") do raise "Not implemented yet" end assert(true, "Reached here.") end def test_pend_with_no_failure_in_block pend("Wait a minute") do "Nothing raised" end assert(true, "Not reached here.") end end def test_pend test = nil result = _run_test("test_pend") {|t| test = t} assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 1 pendings, " \ "0 omissions, 0 notifications", result.to_s) assert_fault_messages(["1st pend"], result.pendings) assert_true(test.interrupted?) end def test_pend_with_failure_in_block test = nil result = _run_test("test_pend_with_failure_in_block") {|t| test = t} assert_equal("1 tests, 1 assertions, 0 failures, 0 errors, 1 pendings, " \ "0 omissions, 0 notifications", result.to_s) assert_fault_messages(["Wait a minute"], result.pendings) assert_false(test.interrupted?) end def test_pend_with_no_failure_in_block test = nil result = _run_test("test_pend_with_no_failure_in_block") {|t| test = t} assert_equal("1 tests, 1 assertions, 1 failures, 0 errors, 0 pendings, " \ "0 omissions, 0 notifications", result.to_s) assert_fault_messages(["Pending block should not be passed: Wait a minute."], result.failures) assert_true(test.interrupted?) end private def _run_test(name, &block) super(TestCase, name, &block) end end PKu]ad  /test-unit-3.3.4/test/test-test-suite-creator.rbnu[require "test/unit" module Test module Unit class TestTestSuiteCreator < TestCase def collect_test_names(test_case) creator = TestSuiteCreator.new(test_case) creator.send(:collect_test_names) end class TestStandalone < self def setup @test_case = Class.new(TestCase) do def test_in_test_case end end end def test_collect_test_names assert_equal(["test_in_test_case"], collect_test_names(@test_case)) end end class TestInherited < self def setup @parent_test_case = Class.new(TestCase) do def test_in_parent end end @child_test_case = Class.new(@parent_test_case) do def test_in_child end end end def test_collect_test_names assert_equal(["test_in_child"], collect_test_names(@child_test_case)) end end class TestModule < self def setup test_module = Module.new do def test_in_module end end @test_case = Class.new(TestCase) do include test_module def test_in_test_case end end end def test_collect_test_names assert_equal(["test_in_module", "test_in_test_case"].sort, collect_test_names(@test_case).sort) end end class TestInheritedModule < self def setup parent_test_module = Module.new do def test_in_module_in_parent end end child_test_module = Module.new do def test_in_module_in_child end end @parent_test_case = Class.new(TestCase) do include parent_test_module def test_in_parent end end @child_test_case = Class.new(@parent_test_case) do include child_test_module def test_in_child end end end def test_collect_test_names assert_equal(["test_in_child", "test_in_module_in_child"].sort, collect_test_names(@child_test_case).sort) end end end end end PKu]sEv v )test-unit-3.3.4/test/test-color-scheme.rbnu[class TestUnitColorScheme < Test::Unit::TestCase def test_register inverted_scheme_spec = { "success" => {:name => "red"}, "failure" => {:name => "green"}, } Test::Unit::ColorScheme["inverted"] = inverted_scheme_spec assert_equal({ "success" => color("red"), "failure" => color("green"), }, Test::Unit::ColorScheme["inverted"].to_hash) end def test_new_with_colors scheme = Test::Unit::ColorScheme.new(:success => color("blue"), "failure" => color("green", :underline => true)) assert_equal({ "success" => color("blue"), "failure" => color("green", :underline => true), }, scheme.to_hash) end def test_new_with_spec scheme = Test::Unit::ColorScheme.new(:success => { :name => "blue", :bold => true }, "failure" => {:name => "green"}) assert_equal({ "success" => color("blue", :bold => true), "failure" => color("green"), }, scheme.to_hash) end private def color(name, options={}) Test::Unit::Color.new(name, options) end class TestFor8Colors < self def setup @original_term, ENV["TERM"] = ENV["TERM"], nil @original_color_term, ENV["COLORTERM"] = ENV["COLORTERM"], nil ENV["TERM"] = "xterm" end def teardown ENV["TERM"] = @original_term ENV["COLORTERM"] = @original_color_term end def test_default expected_schema_keys = [ "pass", "pass-marker", "failure", "failure-marker", "pending", "pending-marker", "omission", "omission-marker", "notification", "notification-marker", "error", "error-marker", "case", "suite", "diff-inserted-tag", "diff-deleted-tag", "diff-difference-tag", "diff-inserted", "diff-deleted", ] assert_equal(expected_schema_keys.sort, Test::Unit::ColorScheme.default.to_hash.keys.sort) end end end PKu]7C1test-unit-3.3.4/test/collector/test-descendant.rbnu[require 'test/unit' require 'test/unit/collector/descendant' class TestUnitCollectorDescendant < Test::Unit::TestCase def setup @previous_descendants = Test::Unit::TestCase::DESCENDANTS.dup Test::Unit::TestCase::DESCENDANTS.clear end def teardown Test::Unit::TestCase::DESCENDANTS.replace(@previous_descendants) end private def assert_collect(expected, *collect_args) collector = Test::Unit::Collector::Descendant.new yield(collector) if block_given? assert_equal(expected, collector.send(:collect, *collect_args)) end def default_name Test::Unit::Collector::Descendant::NAME end def empty_suite(name=nil) Test::Unit::TestSuite.new(name || default_name) end class TestCollect < self def setup super @test_case1 = Class.new(Test::Unit::TestCase) do self.test_order = :alphabetic def self.name "test-case1" end def test_1 end def test_2 end end @test_case2 = Class.new(Test::Unit::TestCase) do self.test_order = :alphabetic def self.name "test-case2" end def test_0 end end @no_test_case = Class.new do def self.name "no-test-case" end def test_4 end end end def test_basic assert_collect(full_suite("name"), "name") assert_collect(full_suite("name"), "name") do |collector| collector.filter = [] end end def test_filtered assert_collect(empty_suite) do |collector| collector.filter = Proc.new {false} end assert_collect(full_suite) do |collector| collector.filter = Proc.new {true} end assert_collect(full_suite) do |collector| collector.filter = Proc.new {nil} end assert_collect(empty_suite) do |collector| collector.filter = [Proc.new {false}, Proc.new {true}] end assert_collect(empty_suite) do |collector| collector.filter = [Proc.new {true}, Proc.new {false}] end assert_collect(empty_suite) do |collector| collector.filter = [Proc.new {nil}, Proc.new {false}] end assert_collect(full_suite) do |collector| collector.filter = [Proc.new {nil}, Proc.new {true}] end expected = empty_suite suite1 = Test::Unit::TestSuite.new(@test_case1.name) suite1 << @test_case1.new("test_1") suite2 = Test::Unit::TestSuite.new(@test_case2.name) suite2 << @test_case2.new("test_0") expected << suite1 << suite2 assert_collect(expected) do |collector| collector.filter = Proc.new do |test| ['test_1', 'test_0'].include?(test.method_name) end end suite1 = Test::Unit::TestSuite.new(@test_case1.name) suite1 << @test_case1.new("test_1") suite2 = Test::Unit::TestSuite.new(@test_case2.name) suite2 << @test_case2.new("test_0") assert_collect(empty_suite) do |collector| filters = [Proc.new {|test| test.method_name == 'test_1' ? true : nil}, Proc.new {|test| test.method_name == 'test_0' ? true : nil}, Proc.new {false}] collector.filter = filters end end private def full_suite(name=nil) sub_suite1 = Test::Unit::TestSuite.new(@test_case1.name) sub_suite1 << @test_case1.new('test_1') sub_suite1 << @test_case1.new('test_2') sub_suite2 = Test::Unit::TestSuite.new(@test_case2.name) sub_suite2 << @test_case2.new('test_0') suite = empty_suite(name) suite << sub_suite1 suite << sub_suite2 suite end end class TestModule < self def test_included_in_child tests = Module.new do def test_in_module end end parent_test_case = Class.new(Test::Unit::TestCase) do class << self def name "Parent" end end end child_test_case = Class.new(parent_test_case) do include tests class << self def name "Child" end end end child_suite = Test::Unit::TestSuite.new(child_test_case.name) child_suite << child_test_case.new("test_in_module") parent_suite = Test::Unit::TestSuite.new(parent_test_case.name) parent_suite << child_suite suite = empty_suite("all") suite << parent_suite assert_collect(suite, "all") end end end PKu]a66+test-unit-3.3.4/test/collector/test-load.rbnu[require 'tmpdir' require 'pathname' require 'test/unit' require 'test/unit/collector/load' class TestUnitCollectorLoad < Test::Unit::TestCase def setup @previous_descendants = Test::Unit::TestCase::DESCENDANTS.dup Test::Unit::TestCase::DESCENDANTS.clear @temporary_test_cases_module_name = "TempTestCases" ::Object.const_set(@temporary_test_cases_module_name, Module.new) @test_dir = Pathname(Dir.tmpdir) + "test-unit" @extra_test_dir = Pathname(Dir.tmpdir) + "test-unit-extra" ensure_clean_directory(@test_dir) ensure_clean_directory(@extra_test_dir) end setup def setup_top_level_test_cases @test_case1_base_name = "test_case1.rb" @test_case1 = @test_dir + @test_case1_base_name @test_case2 = @test_dir + "test_case2.rb" @no_load_test_case3 = @test_dir + "case3.rb" @test_case1.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class TestCase1 < Test::Unit::TestCase def test1_1 end def test1_2 end end end EOT end @test_case2.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class TestCase2 < Test::Unit::TestCase def test2 end end end EOT end @no_load_test_case3.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class NoLoadTestCase3 < Test::Unit::TestCase def test3 end end end EOT end end setup def setup_sub_level_test_cases @sub_test_dir = @test_dir + "sub" @sub_test_dir.mkpath @sub_test_case1 = @sub_test_dir + @test_case1_base_name @sub_test_case4 = @sub_test_dir + "test_case4.rb" @no_load_sub_test_case5 = @sub_test_dir + "case5.rb" @sub_test_case6 = @sub_test_dir + "test_case6.rb" @sub_test_case1.open("w") do |test_case| test_case.puts(<<-TEST_CASE) module #{@temporary_test_cases_module_name} class SubTestCase1 < Test::Unit::TestCase def test1_1 end def test1_2 end end end TEST_CASE end @sub_test_case4.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubTestCase4 < Test::Unit::TestCase def test4_1 end def test4_2 end end end EOT end @no_load_sub_test_case5.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class NoLoadSubTestCase5 < Test::Unit::TestCase def test5_1 end def test5_2 end end end EOT end @sub_test_case6.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubTestCase6 < Test::Unit::TestCase def test6 end end end EOT end end setup def setup_sub_level_test_cases2 @sub2_test_dir = @test_dir + "sub2" @sub2_test_dir.mkpath @no_load_sub2_test_case7 = @sub2_test_dir + "case7.rb" @sub2_test_case8 = @sub2_test_dir + "test_case8.rb" @sub2_test_case9 = @sub2_test_dir + "test_case9.rb" @no_load_sub2_test_case7.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class NoLoadSub2TestCase7 < Test::Unit::TestCase def test7_1 end def test7_2 end end end EOT end @sub2_test_case8.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class Sub2TestCase8 < Test::Unit::TestCase def test8_1 end def test8_2 end end end EOT end @sub2_test_case9.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class Sub2TestCase9 < Test::Unit::TestCase def test9 end end end EOT end end setup def setup_svn_test_cases @svn_test_dir = @test_dir + ".svn" @svn_test_dir.mkpath @svn_test_case10 = @svn_test_dir + "test_case10.rb" @svn_test_case10.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SvnTestCase10 < Test::Unit::TestCase def test7 end end end EOT end end setup def setup_sub_cvs_test_cases @sub_cvs_test_dir = @sub_test_dir + "CVS" @sub_cvs_test_dir.mkpath @sub_cvs_test_case11 = @sub_cvs_test_dir + "test_case11.rb" @sub_cvs_test_case11.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubCVSTestCase11 < Test::Unit::TestCase def test11 end end end EOT end end setup def setup_sub_git_test_cases @sub_git_test_dir = @sub_test_dir + ".git" @sub_git_test_dir.mkpath @sub_git_test_case11 = @sub_git_test_dir + "test_case11.rb" @sub_git_test_case11.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubGitTestCase11 < Test::Unit::TestCase def test11 end end end EOT end end setup def setup_extra_top_level_test_cases @test_cases12 = @extra_test_dir + "test_cases12.rb" @test_cases12.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class TestCase121 < Test::Unit::TestCase def test121_1 end def test121_2 end end class TestCase122 < Test::Unit::TestCase def test122_1 end def test122_2 end end end EOT end end setup def setup_sub_level_extra_test_cases @sub_extra_test_dir = @extra_test_dir + "sub" @sub_extra_test_dir.mkpath @cases13_test = @sub_extra_test_dir + "13cases_test.rb" @cases13_test.open("w") do |test_case| test_case.puts(<<-EOT) module #{@temporary_test_cases_module_name} class SubTestCase13 < Test::Unit::TestCase def test13_1 end def test13_2 end end end EOT end end def teardown @test_dir.rmtree if @test_dir.exist? ::Object.send(:remove_const, @temporary_test_cases_module_name) Test::Unit::TestCase::DESCENDANTS.replace(@previous_descendants) end def test_simple_collect assert_collect([:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("SubTestCase4")}, [:test, {:name => "test4_1"}], [:test, {:name => "test4_2"}]], [:suite, {:name => _test_case_name("SubTestCase6")}, [:test, {:name => "test6"}]]], @sub_test_dir.to_s) end def test_simple_collect_test_suffix assert_collect([:suite, {:name => @extra_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("TestCase121")}, [:test, {:name => "test121_1"}], [:test, {:name => "test121_2"}]], [:suite, {:name => _test_case_name("TestCase122")}, [:test, {:name => "test122_1"}], [:test, {:name => "test122_2"}]], [:suite, {:name => @sub_extra_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase13")}, [:test, {:name => "test13_1"}], [:test, {:name => "test13_2"}]]]], @extra_test_dir.to_s) end def test_multilevel_collect assert_collect([:suite, {:name => "."}, [:suite, {:name => _test_case_name("TestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("TestCase2")}, [:test, {:name => "test2"}]], [:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("SubTestCase4")}, [:test, {:name => "test4_1"}], [:test, {:name => "test4_2"}]], [:suite, {:name => _test_case_name("SubTestCase6")}, [:test, {:name => "test6"}]]], [:suite, {:name => @sub2_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("Sub2TestCase8")}, [:test, {:name => "test8_1"}], [:test, {:name => "test8_2"}]], [:suite, {:name => _test_case_name("Sub2TestCase9")}, [:test, {:name => "test9"}]]]]) end def test_collect_file assert_collect([:suite, {:name => _test_case_name("TestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], @test_case1.to_s) end def test_collect_file_no_pattern_match_file_name assert_collect([:suite, {:name => _test_case_name("NoLoadSubTestCase5")}, [:test, {:name => "test5_1"}], [:test, {:name => "test5_2"}]], @no_load_sub_test_case5.to_s) end def test_collect_file_test_cases assert_collect([:suite, {:name => "[#{@test_cases12}]"}, [:suite, {:name => _test_case_name("TestCase121")}, [:test, {:name => "test121_1"}], [:test, {:name => "test121_2"}]], [:suite, {:name => _test_case_name("TestCase122")}, [:test, {:name => "test122_1"}], [:test, {:name => "test122_2"}]]], @test_cases12.to_s) end def test_collect_files assert_collect([:suite, {:name => "[#{@test_case1}, #{@test_case2}]"}, [:suite, {:name => _test_case_name("TestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("TestCase2")}, [:test, {:name => "test2"}]]], @test_case1.to_s, @test_case2.to_s) end def test_nil_pattern assert_collect([:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("NoLoadSubTestCase5")}, [:test, {:name => "test5_1"}], [:test, {:name => "test5_2"}]], [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("SubTestCase4")}, [:test, {:name => "test4_1"}], [:test, {:name => "test4_2"}]], [:suite, {:name => _test_case_name("SubTestCase6")}, [:test, {:name => "test6"}]]], @sub_test_dir.to_s) do |collector| collector.patterns.clear end end def test_filtering assert_collect([:suite, {:name => "."}, [:suite, {:name => _test_case_name("TestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]]]]) do |collector| collector.filter = Proc.new do |test| !/\Atest1/.match(test.method_name).nil? end end end def test_collect_multi test_dirs = [@sub_test_dir.to_s, @sub2_test_dir.to_s] assert_collect([:suite, {:name => "[#{test_dirs.join(', ')}]"}, [:suite, {:name => @sub_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("SubTestCase1")}, [:test, {:name => "test1_1"}], [:test, {:name => "test1_2"}]], [:suite, {:name => _test_case_name("SubTestCase4")}, [:test, {:name => "test4_1"}], [:test, {:name => "test4_2"}]], [:suite, {:name => _test_case_name("SubTestCase6")}, [:test, {:name => "test6"}]]], [:suite, {:name => @sub2_test_dir.basename.to_s}, [:suite, {:name => _test_case_name("Sub2TestCase8")}, [:test, {:name => "test8_1"}], [:test, {:name => "test8_2"}]], [:suite, {:name => _test_case_name("Sub2TestCase9")}, [:test, {:name => "test9"}]]]], *test_dirs) end private def assert_collect(expected, *collect_args) keep_required_files do Dir.chdir(@test_dir.to_s) do collector = Test::Unit::Collector::Load.new yield(collector) if block_given? actual = inspect_test_object(collector.send(:collect, *collect_args)) assert_equal(expected, actual) end end end def ensure_clean_directory(directory) directory.rmtree if directory.exist? directory.mkpath end def keep_required_files required_files = $".dup yield ensure $".replace(required_files) end def _test_case_name(test_case_class_name) "#{@temporary_test_cases_module_name}::#{test_case_class_name}" end def inspect_test_object(test_object) return nil if test_object.nil? case test_object when Test::Unit::TestSuite sub_tests = test_object.tests.collect do |test| inspect_test_object(test) end.sort_by do |type, attributes, *children| attributes[:name] end [:suite, {:name => test_object.name}, *sub_tests] when Test::Unit::TestCase [:test, {:name => test_object.method_name}] else raise "unexpected test object: #{test_object.inspect}" end end end PKu])***test-unit-3.3.4/test/collector/test_dir.rbnu[require 'test/unit' require 'test/unit/collector/dir' require 'pp' module Test module Unit module Collector class TestDir < TestCase class FileSystem class Directory def initialize(name, fs, parent=self, &block) @name = name @fs = fs @parent = parent @contents = {'.' => self, '..' => parent} instance_eval(&block) if(block) end def file(name, contents) @contents[name] = contents end def dir(name, &block) @contents[name] = self.class.new(name, @fs, self, &block) end def entries @contents.keys end def directory?(name) return true if(name.nil? || name.empty?) return false unless(@contents.include?(name)) @contents[name].kind_of?(self.class) end def file?(name) return false unless(@contents.include?(name)) !directory?(name) end def exist?(name) @contents.include?(name) end def [](name) raise Errno::ENOENT, name unless(@contents.include?(name)) @contents[name] end def path_to(name=nil) if(!name) @parent.path_to(@name) elsif(@parent == self) @fs.join('/', name) else @fs.join(@parent.path_to(@name), name) end end end class ObjectSpace def initialize @objects = [] end def each_object(klass, &block) @objects.find_all{|o| o.kind_of?(klass)}.each(&block) end def <<(object) @objects << object end end attr_reader :object_space def initialize(&block) @root = Directory.new('/', self, &block) @pwd = @root @object_space = ObjectSpace.new @required = [] end def entries(dir) e = find(dir) require_directory(dir) e.entries end def directory?(name) return true if (base = basename(name)) == '/' e = find(dirname(name)) return false unless(e) e.directory?(base) end def find(path) if(/\A\// =~ path) thing = @root else thing = @pwd end path.scan(/[^\/]+/) do |e| break thing = false unless(thing.kind_of?(Directory)) thing = thing[e] end thing end def dirname(name) if (name = name.tr_s('/', '/')) == '/' name else name[%r"\A.+(?=/[^/]+/?\z)|\A/"] || "." end end def basename(name) name[%r"(\A/|[^/]+)/*\z", 1] end def split(name) [dirname(name), basename(name)] end def join(*parts) parts.join('/').gsub(%r{/+}, '/') end def file?(name) e = find(dirname(name)) return false unless(e) e.file?(basename(name)) end def pwd @pwd.path_to end def chdir(to) e = find(to) require_directory(to) @pwd = e end def expand_path(path, base = nil) until /\A\// =~ path base ||= pwd path = join(base, path) base = nil end path.gsub!(%r"(?:/\.)+(?=/)", '') nil while path.sub!(%r"/(?!\.\./)[^/]+/\.\.(?=/)", '') path.sub!(%r"\A(?:/\.\.)+(?=/)", '') path.sub!(%r"(?:\A(/)|/)\.\.?\z", '\1') path end def require_directory(path) raise Errno::ENOTDIR, path unless(directory?(path)) end def require(file) return false if(@required.include?(file)) begin e = find(file) rescue Errno::ENOENT => e if(/\.rb\Z/ =~ file) raise LoadError, file end e = find(file + '.rb') end @required << file @object_space << e true rescue Errno::ENOENT raise LoadError, file end end def test_dir inner_dir = nil dirs = FileSystem::Directory.new('/', nil) do file 'a', nil inner_dir = dir 'b' end assert_equal(inner_dir, dirs['b']) end def test_fs fs = FileSystem.new do file 'a', nil dir 'b' end assert_equal(['.', '..', 'a', 'b'].sort, fs.entries('/').sort) assert(fs.directory?('/')) assert(!fs.directory?('/a')) assert(!fs.directory?('/bogus')) assert(fs.file?('/a')) assert(!fs.file?('/')) assert(!fs.file?('/bogus')) assert(fs.directory?('/b')) assert(fs.file?('a')) assert(fs.directory?('b')) end def test_fs_sub fs = FileSystem.new do dir 'a' do file 'b', nil dir 'c' do file 'd', nil end end end assert(fs.file?('/a/b')) assert(!fs.file?('/a/b/c/d')) assert(fs.file?('/a/c/d')) end def test_fs_pwd fs = FileSystem.new do file 'a', nil dir 'b' do file 'c', nil dir 'd' do file 'e', nil end end end assert_equal('/', fs.pwd) assert_raises(Errno::ENOENT) do fs.chdir('bogus') end assert_raises(Errno::ENOTDIR) do fs.chdir('a') end fs.chdir('b') assert_equal('/b', fs.pwd) fs.chdir('d') assert_equal('/b/d', fs.pwd) fs.chdir('..') assert_equal('/b', fs.pwd) fs.chdir('..') assert_equal('/', fs.pwd) end def test_fs_entries fs = FileSystem.new do file 'a', nil dir 'b' do file 'c', nil file 'd', nil end file 'e', nil dir 'f' do file 'g', nil dir 'h' do file 'i', nil end end end assert_equal(['.', '..', 'a', 'b', 'e', 'f'], fs.entries('/').sort) assert_equal(['.', '..', 'a', 'b', 'e', 'f'], fs.entries('.').sort) assert_equal(['.', '..', 'a', 'b', 'e', 'f'], fs.entries('b/..').sort) assert_equal(['.', '..', 'c', 'd'], fs.entries('b').sort) assert_raises(Errno::ENOENT) do fs.entries('z') end assert_raises(Errno::ENOTDIR) do fs.entries('a') end fs.chdir('f') assert_equal(['.', '..', 'i'], fs.entries('h').sort) end class TestClass1 end class TestClass2 end def test_fs_require fs = FileSystem.new do file 'test_class1.rb', TestClass1 dir 'dir' do file 'test_class2.rb', TestClass2 end end c = [] fs.object_space.each_object(Class) do |o| c << o end assert_equal([], c) assert_raises(LoadError) do fs.require('bogus') end assert(fs.require('test_class1.rb')) assert(!fs.require('test_class1.rb')) c = [] fs.object_space.each_object(Class) do |o| c << o end assert_equal([TestClass1], c) fs.require('dir/test_class2') c = [] fs.object_space.each_object(Class) do |o| c << o end assert_equal([TestClass1, TestClass2], c) c = [] fs.object_space.each_object(Time) do |o| c << o end assert_equal([], c) end def setup @t1 = t1 = create_test(1) @t2 = t2 = create_test(2) @t3 = t3 = create_test(3) @t4 = t4 = create_test(4) @t5 = t5 = create_test(5) @t6 = t6 = create_test(6) fs = FileSystem.new do file 'test_1.rb', t1 file 'test_2.rb', t2 dir 'd1' do file 'test_3.rb', t3 end file 't4.rb', t4 dir 'd2' do file 'test_5', t5 file 'test_6.rb', Time end file 't6.rb', t6 end fs.require('t6') @c = Dir.new(fs, fs, fs.object_space, fs) end def create_test(name) t = Class.new(TestCase) t.class_eval <<-EOC self.test_order = :alphabetic def self.name "T\#{#{name}}" end def test_#{name}a end def test_#{name}b end EOC t end def test_simple_collect expected = TestSuite.new('d1') expected << (@t3.suite) assert_equal(expected, @c.collect('d1')) end def test_multilevel_collect expected = TestSuite.new('.') expected << @t1.suite << @t2.suite expected << (TestSuite.new('d1') << @t3.suite) assert_equal(expected, @c.collect) end def test_collect_file expected = TestSuite.new('test_1.rb') expected << @t1.suite assert_equal(expected, @c.collect('test_1.rb')) expected = TestSuite.new('t4.rb') expected << @t4.suite assert_equal(expected, @c.collect('t4.rb')) end def test_nil_pattern expected = TestSuite.new('d2') expected << @t5.suite @c.pattern.clear assert_equal(expected, @c.collect('d2')) end def test_filtering expected = TestSuite.new('.') expected << @t1.suite @c.filter = proc{|t| t.method_name == 'test_1a' || t.method_name == 'test_1b'} assert_equal(expected, @c.collect) end def test_collect_multi expected = TestSuite.new('[d1, d2]') expected << (TestSuite.new('d1') << @t3.suite) expected << (TestSuite.new('d2') << @t5.suite) @c.pattern.replace([/\btest_/]) assert_equal(expected, @c.collect('d1', 'd2')) end end end end end PKu]2\ 2test-unit-3.3.4/test/collector/test_objectspace.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/collector/objectspace' module Test module Unit module Collector class TC_ObjectSpace < TestCase def setup @tc1 = Class.new(TestCase) do self.test_order = :alphabetic def self.name "tc_1" end def test_1 end def test_2 end end @tc2 = Class.new(TestCase) do self.test_order = :alphabetic def self.name "tc_2" end def test_0 end end @no_tc = Class.new do def test_4 end end @object_space = {Class => [@tc1, @tc2, @no_tc], String => ['']} def @object_space.each_object(type) self[type].each{|item| yield(item) } end @c = ObjectSpace.new(@object_space) end def full_suite(name=ObjectSpace::NAME) expected = TestSuite.new(name) expected << (TestSuite.new(@tc1.name) << @tc1.new('test_1') << @tc1.new('test_2')) expected << (TestSuite.new(@tc2.name) << @tc2.new('test_0')) end def empty_suite TestSuite.new(ObjectSpace::NAME) end def test_basic_collection assert_equal(full_suite("name"), @c.collect("name")) @c.filter = [] assert_equal(full_suite("name"), @c.collect("name")) end def test_filtered_collection @c.filter = proc{false} assert_equal(empty_suite, @c.collect) @c.filter = proc{true} assert_equal(full_suite, @c.collect) @c.filter = proc{nil} assert_equal(full_suite, @c.collect) @c.filter = [proc{false}, proc{true}] assert_equal(empty_suite, @c.collect) @c.filter = [proc{true}, proc{false}] assert_equal(empty_suite, @c.collect) @c.filter = [proc{nil}, proc{false}] assert_equal(empty_suite, @c.collect) @c.filter = [proc{nil}, proc{true}] assert_equal(full_suite, @c.collect) expected = TestSuite.new(ObjectSpace::NAME) expected << (TestSuite.new(@tc1.name) << @tc1.new('test_1')) expected << (TestSuite.new(@tc2.name) << @tc2.new('test_0')) @c.filter = proc{|test| ['test_1', 'test_0'].include?(test.method_name)} assert_equal(expected, @c.collect) expected = TestSuite.new(ObjectSpace::NAME) TestSuite.new(@tc1.name) << @tc1.new('test_1') TestSuite.new(@tc2.name) << @tc2.new('test_0') @c.filter = [proc{|t| t.method_name == 'test_1' ? true : nil}, proc{|t| t.method_name == 'test_0' ? true : nil}, proc{false}] assert_equal(empty_suite, @c.collect) end end end end end PKu]ӪU'test-unit-3.3.4/test/test-test-suite.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' module Test module Unit class TestTestSuite < TestCase def setup @testcase1 = Class.new(TestCase) do def test_succeed1 assert_block { true } end def test_fail assert_block { false } end end @testcase2 = Class.new(TestCase) do def test_succeed2 assert_block { true } end def test_error raise end end end def test_add s = TestSuite.new assert_equal(s, s << self.class.new("test_add")) end def test_delete s = TestSuite.new t1 = self.class.new("test_delete") s << t1 t2 = self.class.new("test_add") s << t2 assert_equal(t1, s.delete(t1)) assert_nil(s.delete(t1)) assert_equal(TestSuite.new << t2, s) end def test_delete_tests suite = TestSuite.new test1 = self.class.new("test_delete_1") suite << test1 test2 = self.class.new("test_delete_2") suite << test2 test3 = self.class.new("test_add") suite << test3 suite.delete_tests([test1, test2]) assert_equal(1, suite.size) assert_equal(TestSuite.new << test3, suite) end def test_size suite = TestSuite.new suite2 = TestSuite.new suite2 << self.class.new("test_size") suite << suite2 suite << self.class.new("test_size") assert_equal(2, suite.size, "The count should be correct") end def test_run progress = [] @testcase1.test_order = :alphabetic suite = @testcase1.suite tests = suite.tests.dup result = TestResult.new suite.run(result) { |*values| progress << values } assert_equal(2, result.run_count, "Should have had four test runs") assert_equal(1, result.failure_count, "Should have had one test failure") assert_equal(0, result.error_count, "Should have had one test error") assert_equal([[TestSuite::STARTED, suite.name], [TestSuite::STARTED_OBJECT, suite], [TestCase::STARTED, "test_fail(#{suite.name})"], [TestCase::STARTED_OBJECT, tests[0]], [TestCase::FINISHED, "test_fail(#{suite.name})"], [TestCase::FINISHED_OBJECT, tests[0]], [TestCase::STARTED, "test_succeed1(#{suite.name})"], [TestCase::STARTED_OBJECT, tests[1]], [TestCase::FINISHED, "test_succeed1(#{suite.name})"], [TestCase::FINISHED_OBJECT, tests[1]], [TestSuite::FINISHED, suite.name], [TestSuite::FINISHED_OBJECT, suite]], progress, "Should have had the correct progress") suite = TestSuite.new suite << @testcase1.suite suite << @testcase2.suite result = TestResult.new progress = [] suite.run(result) { |*values| progress << values } assert_equal(4, result.run_count, "Should have had four test runs") assert_equal(1, result.failure_count, "Should have had one test failure") assert_equal(1, result.error_count, "Should have had one test error") assert_equal(28, progress.size, "Should have had the correct number of progress calls") end def test_empty? assert(TestSuite.new.empty?, "A new test suite should be empty?") assert(!@testcase2.suite.empty?, "A test suite with tests should not be empty") end def test_equality suite1 = TestSuite.new suite2 = TestSuite.new assert_equal(suite1, suite2) assert_equal(suite2, suite1) suite1 = TestSuite.new('name') assert_not_equal(suite1, suite2) assert_not_equal(suite2, suite1) suite2 = TestSuite.new('name') assert_equal(suite1, suite2) assert_equal(suite2, suite1) suite1 << 'test' assert_not_equal(suite1, suite2) assert_not_equal(suite2, suite1) suite2 << 'test' assert_equal(suite1, suite2) assert_equal(suite2, suite1) suite2 = Object.new class << suite2 def name 'name' end def tests ['test'] end end assert_not_equal(suite1, suite2) assert_not_equal(suite2, suite1) assert_not_equal(suite1, Object.new) assert_not_equal(Object.new, suite1) end end end end PKu]U_m77$test-unit-3.3.4/test/test-failure.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/failure' module Test::Unit class TestFailure < TestCase def test_display f = Failure.new("name", [%q{location:1 in 'l'}], "message1\nmessage2") assert_equal("name: message1", f.short_display) assert_equal(< # # License: Ruby's require "test-unit" require "test/unit/fault-location-detector" require "testunit-test-util" class TestFaultLocationDetector < Test::Unit::TestCase include TestUnitTestUtil def setup @fetcher = Test::Unit::CodeSnippetFetcher.new end private def run_test_case(test_case) suite = test_case.suite result = Test::Unit::TestResult.new suite.run(result) {} result.faults[0] end def assert_detect(fault, target_line_number) detector = Test::Unit::FaultLocationDetector.new(fault, @fetcher) expected_backtrace_entries_until_detected = [] fault.location.each do |backtrace_entry| expected_backtrace_entries_until_detected << backtrace_entry _, line_number, = detector.split_backtrace_entry(backtrace_entry) break if target_line_number == line_number end actual_backtrace_entries_until_detected = [] fault.location.each do |backtrace_entry| actual_backtrace_entries_until_detected << backtrace_entry break if detector.target?(backtrace_entry) end assert_equal(expected_backtrace_entries_until_detected, actual_backtrace_entries_until_detected) end module AlwaysFailAssertion private def assert_always_failed assert_true(false) end end class TestSourceLocation < self setup def setup_check_source_location unless lambda {}.respond_to?(:source_location) omit("Need Proc#source_location") end end def test_detected target_line_number = nil test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion test "failed" do target_line_number = __LINE__; assert_always_failed end end fault = run_test_case(test_case) assert_detect(fault, target_line_number) end class TestOneLine < self def test_brace target_line_number = nil test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion test("failed") {target_line_number = __LINE__; assert_always_failed} def other_method # body end end fault = run_test_case(test_case) assert_detect(fault, target_line_number) end def test_do_end target_line_number = nil test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion test "failed" do target_line_number = __LINE__; assert_always_failed; end def other_method # body end end fault = run_test_case(test_case) assert_detect(fault, target_line_number) end end end class TestMethodName < self def test_detected test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion class << self def target_line_number @@target_line_number end def target_line_number=(line_number) @@target_line_number = line_number end end def test_failed self.class.target_line_number = __LINE__; assert_always_failed end end fault = run_test_case(test_case) assert_detect(fault, test_case.target_line_number) end end class TestInBlock < self def test_in_block test_case = Class.new(Test::Unit::TestCase) do include AlwaysFailAssertion class << self def target_line_number @@target_line_number end def target_line_number=(line_number) @@target_line_number = line_number end end def run_yield yield end def test_failed run_yield do self.class.target_line_number = __LINE__; assert_always_failed end end end fault = run_test_case(test_case) assert_detect(fault, test_case.target_line_number) end end end PKu]G-44!test-unit-3.3.4/test/test-data.rbnu[require "testunit-test-util" class TestData < Test::Unit::TestCase class Calc def initialize end def plus(augend, addend) augend + addend end end class TestCalc < Test::Unit::TestCase @@testing = false class << self def testing=(testing) @@testing = testing end end def valid? @@testing end def setup @calc = Calc.new end class TestDataSet < TestCalc data("positive positive" => {:expected => 4, :augend => 3, :addend => 1}, "positive negative" => {:expected => -1, :augend => 1, :addend => -2}) def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end end class TestNData < TestCalc data("positive positive", {:expected => 4, :augend => 3, :addend => 1}) data("positive negative", {:expected => -1, :augend => 1, :addend => -2}) def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end end class TestDynamicDataSet < TestCalc DATA_PROC = lambda do data_set = {} data_set["positive positive"] = { :expected => 3, :augend => 1, :addend => 2 } data_set["positive negative"] = { :expected => -1, :augend => 1, :addend => -2 } data_set end data(&DATA_PROC) def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end end class TestLoadDataSet < TestCalc extend TestUnitTestUtil load_data(fixture_file_path("plus.csv")) def test_plus(data) assert_equal(data["expected"], @calc.plus(data["augend"], data["addend"])) end end class TestSuperclass < TestCalc data("positive positive" => {:expected => 4, :augend => 3, :addend => 1}, "positive negative" => {:expected => -1, :augend => 1, :addend => -2}) def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end class TestNormalTestInSubclass < self def test_plus assert_equal(2, @calc.plus(1, 1)) end end end class TestMethod < TestCalc def data_test_plus { "positive positive" => {:expected => 4, :augend => 3, :addend => 1}, "positive negative" => {:expected => -1, :augend => 1, :addend => -2}, } end def test_plus(data) assert_equal(data[:expected], @calc.plus(data[:augend], data[:addend])) end end class TestPatterns < TestCalc data(:x, [-1, 1, 0]) data(:y, [-100, 100]) data(:z, ["a", "b", "c"]) def test_use_data(data) end end class TestPatternsKeep < TestCalc data(:x, [-1, 1, 0], keep: true) data(:y, [-100, 100]) data(:z, ["a", "b", "c"], keep: true) def test_use_data(data) end def test_use_data_keep(data) end end class TestPatternsGroup < TestCalc data(:a, [-1, 1, 0], group: 1) data(:b, [:a, :b], group: 1) data(:x, [2, 9], group: :z) data(:y, ["a", "b", "c"], group: :z) def test_use_data(data) end end end def setup TestCalc.testing = true end def teardown TestCalc.testing = false end def test_data_no_arguments_without_block assert_raise(ArgumentError) do self.class.data end end data("data set", { :test_case => TestCalc::TestDataSet, :data_sets => [ { "positive positive" => { :expected => 4, :augend => 3, :addend => 1, }, "positive negative" => { :expected => -1, :augend => 1, :addend => -2, }, }, ], }) data("n-data", { :test_case => TestCalc::TestNData, :data_sets => [ { "positive positive" => { :expected => 4, :augend => 3, :addend => 1, }, }, { "positive negative" => { :expected => -1, :augend => 1, :addend => -2, }, }, ], }) data("dynamic-data-set", { :test_case => TestCalc::TestDynamicDataSet, :data_sets => [TestCalc::TestDynamicDataSet::DATA_PROC], }) data("load-data-set", { :test_case => TestCalc::TestLoadDataSet, :data_sets => [ { "positive positive" => { "expected" => 4, "augend" => 3, "addend" => 1, }, }, { "positive negative" => { "expected" => -1, "augend" => 1, "addend" => -2, }, }, ], }) def test_data(data) test_plus = data[:test_case].new("test_plus") data_sets = Test::Unit::DataSets.new data[:data_sets].each do |data_set| data_sets.add(data_set) end assert_equal(data_sets, test_plus[:data]) end def test_data_patterns test = TestCalc::TestPatterns.new("test_use_data") data_sets = Test::Unit::DataSets.new data_sets << [:x, [-1, 1, 0]] data_sets << [:y, [-100, 100]] data_sets << [:z, ["a", "b", "c"]] assert_equal(data_sets, test[:data]) end def test_data_patterns_keep test = TestCalc::TestPatternsKeep.new("test_use_data_keep") data_sets = Test::Unit::DataSets.new data_sets.add([:x, [-1, 1, 0]], {keep: true}) data_sets.add([:z, ["a", "b", "c"]], {keep: true}) assert_equal(data_sets, test[:data]) end data("data set" => TestCalc::TestDataSet, "n-data" => TestCalc::TestNData, "dynamic-data-set" => TestCalc::TestDynamicDataSet, "load-data-set" => TestCalc::TestLoadDataSet) def test_suite(test_case) suite = test_case.suite assert_equal(["test_plus[positive negative](#{test_case.name})", "test_plus[positive positive](#{test_case.name})"], suite.tests.collect {|test| test.name}.sort) end def test_suite_patterns test_case = TestCalc::TestPatterns suite = test_case.suite assert_equal([ "test_use_data[x: -1, y: -100, z: \"a\"](#{test_case.name})", "test_use_data[x: -1, y: -100, z: \"b\"](#{test_case.name})", "test_use_data[x: -1, y: -100, z: \"c\"](#{test_case.name})", "test_use_data[x: -1, y: 100, z: \"a\"](#{test_case.name})", "test_use_data[x: -1, y: 100, z: \"b\"](#{test_case.name})", "test_use_data[x: -1, y: 100, z: \"c\"](#{test_case.name})", "test_use_data[x: 0, y: -100, z: \"a\"](#{test_case.name})", "test_use_data[x: 0, y: -100, z: \"b\"](#{test_case.name})", "test_use_data[x: 0, y: -100, z: \"c\"](#{test_case.name})", "test_use_data[x: 0, y: 100, z: \"a\"](#{test_case.name})", "test_use_data[x: 0, y: 100, z: \"b\"](#{test_case.name})", "test_use_data[x: 0, y: 100, z: \"c\"](#{test_case.name})", "test_use_data[x: 1, y: -100, z: \"a\"](#{test_case.name})", "test_use_data[x: 1, y: -100, z: \"b\"](#{test_case.name})", "test_use_data[x: 1, y: -100, z: \"c\"](#{test_case.name})", "test_use_data[x: 1, y: 100, z: \"a\"](#{test_case.name})", "test_use_data[x: 1, y: 100, z: \"b\"](#{test_case.name})", "test_use_data[x: 1, y: 100, z: \"c\"](#{test_case.name})", ], suite.tests.collect {|test| test.name}.sort) end def test_suite_patterns_group test_case = TestCalc::TestPatternsGroup suite = test_case.suite assert_equal([ "test_use_data[group: 1, a: -1, b: :a](#{test_case.name})", "test_use_data[group: 1, a: -1, b: :b](#{test_case.name})", "test_use_data[group: 1, a: 0, b: :a](#{test_case.name})", "test_use_data[group: 1, a: 0, b: :b](#{test_case.name})", "test_use_data[group: 1, a: 1, b: :a](#{test_case.name})", "test_use_data[group: 1, a: 1, b: :b](#{test_case.name})", "test_use_data[group: :z, x: 2, y: \"a\"](#{test_case.name})", "test_use_data[group: :z, x: 2, y: \"b\"](#{test_case.name})", "test_use_data[group: :z, x: 2, y: \"c\"](#{test_case.name})", "test_use_data[group: :z, x: 9, y: \"a\"](#{test_case.name})", "test_use_data[group: :z, x: 9, y: \"b\"](#{test_case.name})", "test_use_data[group: :z, x: 9, y: \"c\"](#{test_case.name})", ], suite.tests.collect {|test| test.name}.sort) end data("data set" => TestCalc::TestDataSet, "n-data" => TestCalc::TestNData, "dynamic-data-set" => TestCalc::TestDynamicDataSet, "load-data-set" => TestCalc::TestLoadDataSet, "superclass" => TestCalc::TestSuperclass, "method" => TestCalc::TestMethod) def test_run(test_case) result = _run_test(test_case) assert_equal("2 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, " \ "0 omissions, 0 notifications", result.to_s) end def test_run_normal_test_in_subclass result = _run_test(TestCalc::TestSuperclass::TestNormalTestInSubclass) assert_equal("1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, " \ "0 omissions, 0 notifications", result.to_s) end data("data set" => TestCalc::TestDataSet, "n-data" => TestCalc::TestNData, "dynamic-data-set" => TestCalc::TestDynamicDataSet, "load-data-set" => TestCalc::TestLoadDataSet) def test_equal(test_case) suite = test_case.suite positive_positive_test = suite.tests.find do |test| test.data_label == "positive positive" end suite.tests.delete(positive_positive_test) assert_equal(["test_plus[positive negative](#{test_case.name})"], suite.tests.collect {|test| test.name}.sort) end data("true" => {:expected => true, :target => "true"}, "false" => {:expected => false, :target => "false"}, "integer" => {:expected => 1, :target => "1"}, "float" => {:expected => 1.5, :target => "1.5"}, "string" => {:expected => "hello", :target => "hello"}) def test_normalize_value(data) loader = Test::Unit::Data::ClassMethods::Loader.new(self) assert_equal(data[:expected], loader.__send__(:normalize_value, data[:target])) end def _run_test(test_case) result = Test::Unit::TestResult.new test = test_case.suite yield(test) if block_given? test.run(result) {} result end class TestLoadData < Test::Unit::TestCase include TestUnitTestUtil def test_invalid_csv_file_name garbage = "X" file_name = "data.csv#{garbage}" assert_raise(ArgumentError, "unsupported file format: <#{file_name}>") do self.class.load_data(file_name) end end class TestFileFormat < self def setup self.class.current_attribute(:data).clear end class TestHeader < self data("csv" => "header.csv", "tsv" => "header.tsv") def test_normal(file_name) self.class.load_data(fixture_file_path(file_name)) data_sets = Test::Unit::DataSets.new data_sets << { "empty string" => { "expected" => true, "target" => "" } } data_sets << { "plain string" => { "expected" => false, "target" => "hello" } } assert_equal(data_sets, self.class.current_attribute(:data)[:value]) end data("csv" => "header-label.csv", "tsv" => "header-label.tsv") def test_label(file_name) self.class.load_data(fixture_file_path(file_name)) data_sets = Test::Unit::DataSets.new data_sets << { "upper case" => { "expected" => "HELLO", "label" => "HELLO" } } data_sets << { "lower case" => { "expected" => "Hello", "label" => "hello" } } assert_equal(data_sets, self.class.current_attribute(:data)[:value]) end end data("csv" => "no-header.csv", "tsv" => "no-header.tsv") def test_without_header(file_name) self.class.load_data(fixture_file_path(file_name)) data_sets = Test::Unit::DataSets.new data_sets << {"empty string" => [true, ""]} data_sets << {"plain string" => [false, "hello"]} assert_equal(data_sets, self.class.current_attribute(:data)[:value]) end end end end PKu]J  )test-unit-3.3.4/test/test-code-snippet.rbnu[# coding: utf-8 require "test-unit" require "testunit-test-util" class TestCodeSnippet < Test::Unit::TestCase include TestUnitTestUtil class TestJRuby < self def test_error_inside_jruby jruby_only_test backtrace = backtrace_from_jruby no_rb_entries = backtrace.find_all do |(file, _, _)| File.extname(file) != ".rb" end fetcher = Test::Unit::CodeSnippetFetcher.new snippets = no_rb_entries.collect do |(file, line, _)| fetcher.fetch(file, line) end assert_equal([[]] * no_rb_entries.size, snippets) end private def backtrace_from_jruby begin java.util.Vector.new(-1) rescue Exception $@.collect do |entry| entry.split(/:/, 3) end else flunk("failed to raise an exception from JRuby.") end end end class TestDefaultExternal < self def suppress_warning verbose = $VERBOSE begin $VERBOSE = false yield ensure $VERBOSE = verbose end end def setup suppress_warning do @default_external = Encoding.default_external end @fetcher = Test::Unit::CodeSnippetFetcher.new end def teardown suppress_warning do Encoding.default_external = @default_external end end def test_windows_31j source = Tempfile.new(["test-code-snippet", ".rb"]) source.puts(<<-SOURCE) puts("あいうえお") SOURCE source.flush suppress_warning do Encoding.default_external = "Windows-31J" end assert_equal([ [1, "puts(\"あいうえお\")", {:target_line? => false}], ], @fetcher.fetch(source.path, 0)) end end end PKu]w22"test-unit-3.3.4/test/test-color.rbnu[class TestUnitColor < Test::Unit::TestCase def test_color_escape_sequence assert_escape_sequence(["31"], color("red")) assert_escape_sequence(["32", "1"], color("green", :bold => true)) assert_escape_sequence(["0"], color("reset")) assert_escape_sequence(["45"], color("magenta", :background => true)) end def test_mix_color_escape_sequence assert_escape_sequence(["34", "1"], mix_color([color("blue"), color("none", :bold => true)])) assert_escape_sequence(["34", "1", "4"], mix_color([color("blue"), color("none", :bold => true)]) + color("none", :underline => true)) assert_escape_sequence(["34", "1", "4"], color("blue") + color("none", :bold => true) + color("none", :underline => true)) end def test_equal red = color("red") red_bold = color("red", :bold => true) assert_operator(red, :==, red) assert_not_equal(red, nil) assert_equal(red, color("red")) assert_not_equal(red, red_bold) end private def color(name, options={}) Test::Unit::Color.new(name, options) end def mix_color(colors) Test::Unit::MixColor.new(colors) end def assert_escape_sequence(expected, color) assert_equal(expected, color.sequence) assert_match(/\e\[(?:\d+;)*\d+m/, color.escape_sequence) assert_equal(expected, color.escape_sequence[2..-2].split(";")) end end PKu]20~,*test-unit-3.3.4/test/testunit-test-util.rbnu[require "tempfile" module TestUnitTestUtil private def jruby? RUBY_PLATFORM == "java" end def jruby_only_test if jruby? require "java" else omit("test for JRuby") end end def assert_fault_messages(expected, faults) assert_equal(expected, faults.collect {|fault| fault.message}) end def _run_test(test_case, name) result = Test::Unit::TestResult.new test = test_case.new(name) yield(test) if block_given? test.run(result) {} result end def fixture_file_path(file_name) base_dir = File.dirname(__FILE__) File.join(base_dir, "fixtures", file_name) end end PKu]:QQ&test-unit-3.3.4/test/test-test-case.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2008-2014 Kouhei Sutou # Copyright:: Copyright (c) 2011 Haruka Yoshihara # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott # License:: Ruby license. require 'test/unit' module Test module Unit class TestTestCase < TestCase self.test_order = :random def test_creation test_case = Class.new(TestCase) do def test_with_arguments(arg1, arg2) end end test = test_case.new(:test_with_arguments) check("Should have caught an invalid test when there are arguments", !test.valid?) test = test_case.new(:non_existent_test) check("Should have caught an invalid test when the method does not exist", !test.valid?) end def setup @tc_failure_error = Class.new(TestCase) do def test_failure assert_block("failure") do false end end def test_error 1 / 0 end def test_nested_failure nested end def nested assert_block("nested") do false end end def return_passed? return passed? end end def @tc_failure_error.name "TC_FailureError" end end def jruby_backtrace_entry?(entry) entry.start_with?("org/jruby/") end def rubinius_backtrace_entry?(entry) entry.start_with?("kernel/") end def normalize_location(location) filtered_location = location.reject do |entry| jruby_backtrace_entry?(entry) or rubinius_backtrace_entry?(entry) end filtered_location.collect do |entry| entry.sub(/:\d+:/, ":0:") end end def test_add_failed_assertion test_case = @tc_failure_error.new(:test_failure) assert do test_case.passed? end result = TestResult.new faults = [] result.add_listener(TestResult::FAULT) do |fault| faults << fault end progress = [] test_case.run(result) do |*arguments| progress << arguments end fault_details = faults.collect do |fault| { :class => fault.class, :message => fault.message, :test_name => fault.test_name, :location => normalize_location(fault.location), } end assert_equal([ { :class => Failure, :message => "failure", :test_name => "test_failure(TC_FailureError)", :location => [ "#{__FILE__}:0:in `test_failure'", "#{__FILE__}:0:in `#{__method__}'", ], }, ], fault_details) assert do not test_case.passed? end assert_equal([ [TestCase::STARTED, test_case.name], [TestCase::STARTED_OBJECT, test_case], [TestCase::FINISHED, test_case.name], [TestCase::FINISHED_OBJECT, test_case], ], progress) end def test_add_failure_nested test_case = @tc_failure_error.new(:test_nested_failure) assert do test_case.passed? end result = TestResult.new faults = [] result.add_listener(TestResult::FAULT) do |fault| faults << fault end test_case.run(result) do end fault_details = faults.collect do |fault| { :class => fault.class, :message => fault.message, :test_name => fault.test_name, :location => normalize_location(fault.location), } end assert_equal([ { :class => Failure, :message => "nested", :test_name => "test_nested_failure(TC_FailureError)", :location => [ "#{__FILE__}:0:in `nested'", "#{__FILE__}:0:in `test_nested_failure'", "#{__FILE__}:0:in `#{__method__}'", ], }, ], fault_details) assert do not test_case.passed? end end def jruby? defined?(JRUBY_VERSION) end def rubinius? false # TODO end def cruby? (not jruby?) and (not rubinius?) end def test_add_error test_case = @tc_failure_error.new(:test_error) assert do test_case.passed? end result = TestResult.new faults = [] result.add_listener(TestResult::FAULT) do |fault| faults << fault end test_case.run(result) do end fault_details = faults.collect do |fault| { :class => fault.class, :message => fault.message, :test_name => fault.test_name, :location => normalize_location(fault.location), } end location = [] location << "#{__FILE__}:0:in `/'" if cruby? location << "#{__FILE__}:0:in `test_error'" location << "#{__FILE__}:0:in `#{__method__}'" assert_equal([ { :class => Error, :message => "ZeroDivisionError: divided by 0", :test_name => "test_error(TC_FailureError)", :location => location, }, ], fault_details) assert do not test_case.passed? end end def test_no_tests suite = TestCase.suite check("Should have a test suite", suite.instance_of?(TestSuite)) check("Should have one test", suite.size == 1) check("Should have the default test", suite.tests.first.name == "default_test(Test::Unit::TestCase)") result = TestResult.new suite.run(result) {} check("Should have had one test run", result.run_count == 1) check("Should have had one test failure", result.failure_count == 1) check("Should have had no errors", result.error_count == 0) end def test_suite tc = Class.new(TestCase) do def test_succeed assert_block {true} end def test_fail assert_block {false} end def test_error 1/0 end def dont_run assert_block {true} end def test_dont_run(argument) assert_block {true} end def test assert_block {true} end end suite = tc.suite check("Should have a test suite", suite.instance_of?(TestSuite)) check("Should have three tests", suite.size == 3) result = TestResult.new suite.run(result) {} check("Should have had three test runs", result.run_count == 3) check("Should have had one test failure", result.failure_count == 1) check("Should have had one test error", result.error_count == 1) end def test_setup_teardown tc = Class.new(TestCase) do attr_reader(:setup_called, :teardown_called) def initialize(test) super(test) @setup_called = false @teardown_called = false end def setup @setup_called = true end def teardown @teardown_called = true end def test_succeed assert_block {true} end def test_fail assert_block {false} end def test_error raise "Error!" end end result = TestResult.new test = tc.new(:test_succeed) test.run(result) {} check("Should have called setup the correct number of times", test.setup_called) check("Should have called teardown the correct number of times", test.teardown_called) test = tc.new(:test_fail) test.run(result) {} check("Should have called setup the correct number of times", test.setup_called) check("Should have called teardown the correct number of times", test.teardown_called) test = tc.new(:test_error) test.run(result) {} check("Should have called setup the correct number of times", test.setup_called) check("Should have called teardown the correct number of times", test.teardown_called) check("Should have had two test runs", result.run_count == 3) check("Should have had a test failure", result.failure_count == 1) check("Should have had a test error", result.error_count == 1) end def test_assertion_failed_not_called tc = Class.new(TestCase) do def test_thing raise AssertionFailedError.new end end suite = tc.suite check("Should have one test", suite.size == 1) result = TestResult.new suite.run(result) {} check("Should have had one test run", result.run_count == 1) check("Should have had one assertion failure", result.failure_count == 1) check("Should not have any assertion errors but had #{result.error_count}", result.error_count == 0) end def test_equality tc1 = Class.new(TestCase) do def test_1 end def test_2 end end tc2 = Class.new(TestCase) do def test_1 end end test1 = tc1.new('test_1') test2 = tc1.new('test_1') check("Should be equal", test1 == test2) check("Should be equal", test2 == test1) test1 = tc1.new('test_2') check("Should not be equal", test1 != test2) check("Should not be equal", test2 != test1) test2 = tc1.new('test_2') check("Should be equal", test1 == test2) check("Should be equal", test2 == test1) test1 = tc1.new('test_1') test2 = tc2.new('test_1') check("Should not be equal", test1 != test2) check("Should not be equal", test2 != test1) check("Should not be equal", test1 != Object.new) check("Should not be equal", Object.new != test1) end def test_re_raise_exception test_case = Class.new(TestCase) do def test_raise_interrupt raise Interrupt, "from test" end end test = test_case.new("test_raise_interrupt") begin test.run(TestResult.new) {} check("Should not be reached", false) rescue Exception check("Interrupt exception should be re-raised", $!.class == Interrupt) end end def test_timeout_error test_case = Class.new(TestCase) do def test_raise_timeout_error require "timeout" raise Timeout::Error end end test_suite = test_case.suite result = TestResult.new begin test_suite.run(result) {} check("Timeout::Error should be handled as error", result.error_count == 1) rescue Exception check("Timeout::Error should not be passed through: #{$!}", false) end end def test_interrupted test_case = Class.new(TestCase) do def test_fail flunk end def test_nothing end end failed_test = test_case.new(:test_fail) failed_test.run(TestResult.new) {} check("Should be interrupted", failed_test.interrupted?) success_test = test_case.new(:test_nothing) success_test.run(TestResult.new) {} check("Should not be interrupted", !success_test.interrupted?) end def test_inherited_test_should_be_ignored test_case = Class.new(TestCase) do def test_nothing end end sub_test_case = Class.new(test_case) do def test_fail flunk end end test = test_case.new("test_nothing") assert_predicate(test, :valid?) test = sub_test_case.new("test_fail") assert_predicate(test, :valid?) test = sub_test_case.new("test_nothing") assert_not_predicate(test, :valid?) end def test_mixin_test_should_not_be_ignored test_module = Module.new do def test_nothing end end test_case = Class.new(Test::Unit::TestCase) do include test_module def test_fail flunk end end assert_nothing_thrown do test_case.new("test_nothing") end assert_nothing_thrown do test_case.new("test_fail") end end def test_defined_order test_case = Class.new(Test::Unit::TestCase) do def test_z end def test_1 end def test_a end end test_case.test_order = :defined assert_equal(["test_z", "test_1", "test_a"], test_case.suite.tests.collect {|test| test.method_name}) end def test_declarative_style test_case = Class.new(Test::Unit::TestCase) do test "declarative style test definition" do end test "include parenthesis" do end test "1 + 2 = 3" do end end test_case.test_order = :defined assert_equal(["test: declarative style test definition", "test: include parenthesis", "test: 1 + 2 = 3"], test_case.suite.tests.collect {|test| test.method_name}) assert_equal(["declarative style test definition", "include parenthesis", "1 + 2 = 3"], test_case.suite.tests.collect {|test| test.description}) end def test_test_mark test_case = Class.new(Test::Unit::TestCase) do test def my_test_method end end test_case.test_order = :defined assert_equal(["my_test_method"], test_case.suite.tests.collect {|test| test.method_name}) end def test_redefine_method test_case = Class.new(Test::Unit::TestCase) do self.test_order = :alphabetic def test_name end alias_method :test_name2, :test_name def test_name end end suite = test_case.suite assert_equal(["test_name", "test_name2"], suite.tests.collect {|test| test.method_name}) result = TestResult.new suite.run(result) {} assert_equal("2 tests, 0 assertions, 0 failures, " + "0 errors, 0 pendings, 0 omissions, 1 notifications", result.summary) end def test_data_driven_test test_case = Class.new(TestCase) do def test_with_data(data) end end test = test_case.new("test_with_data") assert_not_predicate(test, :valid?) test.assign_test_data("label1", :test_data1) assert_predicate(test, :valid?) end def test_data_driven_test_without_parameter test_case = Class.new(TestCase) do data("label" => "value") def test_without_parameter assert_equal("value", data) end end suite = test_case.suite assert_equal(["test_without_parameter"], suite.tests.collect {|test| test.method_name}) result = TestResult.new suite.run(result) {} assert_equal("1 tests, 1 assertions, 0 failures, " + "0 errors, 0 pendings, 0 omissions, 0 notifications", result.summary) end private def check(message, passed) add_assertion raise AssertionFailedError.new(message) unless passed end class TestTestDefined < self class TestNoQuery < self def test_no_test test_case = Class.new(TestCase) do end assert_false(test_case.test_defined?({})) end def test_have_def_style_test test_case = Class.new(TestCase) do def test_nothing end end assert_true(test_case.test_defined?({})) end def test_have_method_style_test test_case = Class.new(TestCase) do test "nothing" do end end assert_true(test_case.test_defined?({})) end end class TestPath < self class TestDefStyle < self def test_base_name test_case = Class.new(TestCase) do def test_nothing end end base_name = File.basename(__FILE__) assert_true(test_case.test_defined?(:path => base_name)) end def test_absolute_path test_case = Class.new(TestCase) do def test_nothing end end assert_true(test_case.test_defined?(:path => __FILE__)) end def test_not_match test_case = Class.new(TestCase) do def test_nothing end end assert_false(test_case.test_defined?(:path => "nonexistent.rb")) end end class TestMethodStyle < self def test_base_name test_case = Class.new(TestCase) do test "nothing" do end end base_name = File.basename(__FILE__) assert_true(test_case.test_defined?(:path => base_name)) end def test_absolute_path test_case = Class.new(TestCase) do test "nothing" do end end assert_true(test_case.test_defined?(:path => __FILE__)) end def test_not_match test_case = Class.new(TestCase) do test "nothing" do end end assert_false(test_case.test_defined?(:path => "nonexistent.rb")) end end end class TestLine < self class TestDefStyle < self def test_before line_before = nil test_case = Class.new(TestCase) do line_before = __LINE__ def test_nothing end end assert_false(test_case.test_defined?(:line => line_before)) end def test_def line_def = nil test_case = Class.new(TestCase) do line_def = __LINE__; def test_nothing end end assert_true(test_case.test_defined?(:line => line_def)) end def test_after line_after = nil test_case = Class.new(TestCase) do def test_nothing end line_after = __LINE__ end assert_true(test_case.test_defined?(:line => line_after)) end def test_child child_test_case = nil line_child = nil parent_test_case = Class.new(TestCase) do test "parent" do end child_test_case = Class.new(self) do line_child = __LINE__; test "child" do end end end assert_equal([ false, true, ], [ parent_test_case.test_defined?(:line => line_child), child_test_case.test_defined?(:line => line_child), ]) end end class TestMethodStyle < self def test_before line_before = nil test_case = Class.new(TestCase) do line_before = __LINE__ test "nothing" do end end assert_false(test_case.test_defined?(:line => line_before)) end def test_method line_method = nil test_case = Class.new(TestCase) do line_method = __LINE__; test "nothing" do end end assert_true(test_case.test_defined?(:line => line_method)) end def test_after line_after = nil test_case = Class.new(TestCase) do test "nothing" do end line_after = __LINE__ end assert_true(test_case.test_defined?(:line => line_after)) end def test_child child_test_case = nil line_child = nil parent_test_case = Class.new(TestCase) do test "parent" do end child_test_case = Class.new(self) do line_child = __LINE__; test "child" do end end end assert_equal([ false, true, ], [ parent_test_case.test_defined?(:line => line_child), child_test_case.test_defined?(:line => line_child), ]) end def test_with_setup line = nil test_case = Class.new(TestCase) do setup do end line = __LINE__; test "with setup" do end end assert do test_case.test_defined?(:line => line, :method_name => "test: with setup") end end end end class TestMethodName < self class TestDefStyle < self def test_match test_case = Class.new(TestCase) do def test_nothing end end query = {:method_name => "test_nothing"} assert_true(test_case.test_defined?(query)) end def test_not_match test_case = Class.new(TestCase) do def test_nothing end end query = {:method_name => "test_nonexistent"} assert_false(test_case.test_defined?(query)) end end class TestMethodStyle < self def test_match test_case = Class.new(TestCase) do test "nothing" do end end query = {:method_name => "test: nothing"} assert_true(test_case.test_defined?(query)) end def test_not_match test_case = Class.new(TestCase) do test "nothing" do end end query = {:method_name => "test: nonexistent"} assert_false(test_case.test_defined?(query)) end end end class TestCombine < self class TestDefStyle < self def test_line_middle line_middle = nil test_case = Class.new(TestCase) do def test_before end line_middle = __LINE__ def test_after end end query = { :path => __FILE__, :line => line_middle, :method_name => "test_before", } assert_true(test_case.test_defined?(query)) end def test_line_after_def line_after_def = nil test_case = Class.new(TestCase) do def test_before end line_after_def = __LINE__; def test_after end end query = { :path => __FILE__, :line => line_after_def, :method_name => "test_before", } assert_false(test_case.test_defined?(query)) end end class TestMethodStyle < self def test_line_middle line_middle = nil test_case = Class.new(TestCase) do test "before" do end line_middle = __LINE__ test "after" do end end query = { :path => __FILE__, :line => line_middle, :method_name => "test: before", } assert_true(test_case.test_defined?(query)) end def test_line_after_method line_after_method = nil test_case = Class.new(TestCase) do test "before" do end line_after_method = __LINE__; test "after" do end end query = { :path => __FILE__, :line => line_after_method, :method_name => "test: before", } assert_false(test_case.test_defined?(query)) end end end end class TestSubTestCase < self class TestName < self def test_anonymous test_case = Class.new(TestCase) sub_test_case = test_case.sub_test_case("sub test case") do end assert_equal("sub test case", sub_test_case.name) end def test_named test_case = Class.new(TestCase) def test_case.name "ParentTestCase" end sub_test_case = test_case.sub_test_case("sub test case") do end assert_equal("ParentTestCase::sub test case", sub_test_case.name) end end def test_suite test_case = Class.new(TestCase) sub_test_case = test_case.sub_test_case("sub test case") do def test_nothing end end test_method_names = sub_test_case.suite.tests.collect do |test| test.method_name end assert_equal(["test_nothing"], test_method_names) end def test_duplicated_name test_case = Class.new(TestCase) do def test_nothing end end sub_test_case = test_case.sub_test_case("sub test case") do def test_nothing end end test_method_names = test_case.suite.tests.collect do |test| test.method_name end sub_test_method_names = sub_test_case.suite.tests.collect do |test| test.method_name end assert_equal([ ["test_nothing"], ["test_nothing"], ], [ test_method_names, sub_test_method_names, ]) end end class TestStartupShutdown < self class TestOrder < self module CallLogger def called @@called ||= [] end end def call_order(test_case) test_case.called.clear test_suite = test_case.suite test_suite.run(TestResult.new) {} test_case.called end class TestNoInheritance < self def setup @test_case = Class.new(TestCase) do extend CallLogger class << self def startup called << :startup end def shutdown called << :shutdown end end def setup self.class.called << :setup end def teardown self.class.called << :teardown end def test1 end def test2 end end end def test_call_order assert_equal([ :startup, :setup, :teardown, :setup, :teardown, :shutdown, ], call_order(@test_case)) end end class TestInheritance < self def setup @original_descendants = TestCase::DESCENDANTS.dup TestCase::DESCENDANTS.clear @parent_test_case = Class.new(TestCase) do extend CallLogger self.test_order = :alphabetic class << self def startup called << :startup_parent end def shutdown called << :shutdown_parent end end def setup self.class.called << :setup_parent end def teardown self.class.called << :teardown_parent end def test1_parent self.class.called << :test1_parent end def test2_parent self.class.called << :test2_parent end end @child_test_case = Class.new(@parent_test_case) do class << self def startup called << :startup_child end def shutdown called << :shutdown_child end end def setup self.class.called << :setup_child end def teardown self.class.called << :teardown_child end def test1_child self.class.called << :test1_child end def test2_child self.class.called << :test2_child end end end def teardown TestCase::DESCENDANTS.replace(@original_descendants) end def test_call_order collector = Collector::Descendant.new test_suite = collector.collect test_suite.run(TestResult.new) {} called = @parent_test_case.called assert_equal([ :startup_parent, :setup_parent, :test1_parent, :teardown_parent, :setup_parent, :test2_parent, :teardown_parent, :startup_child, :setup_child, :test1_child, :teardown_child, :setup_child, :test2_child, :teardown_child, :shutdown_child, :shutdown_parent, ], called) end end end class TestError < self def run_test_case(test_case) test_suite = test_case.suite result = TestResult.new test_suite.run(result) {} result end def error_count(test_case) run_test_case(test_case).error_count end def test_on_startup test_case = Class.new(TestCase) do class << self def startup raise "from startup" end end def test_nothing end end assert_equal(1, error_count(test_case)) end def test_pass_through_on_startup test_case = Class.new(TestCase) do class << self def startup raise Interrupt, "from startup" end end def test_nothing end end assert_raise(Interrupt) do run_test_case(test_case) end end def test_on_shutdown test_case = Class.new(TestCase) do class << self def shutdown raise "from shutdown" end end def test_nothing end end assert_equal(1, error_count(test_case)) end def test_pass_through_on_shutdown test_case = Class.new(TestCase) do class << self def shutdown raise Interrupt, "from shutdown" end end def test_nothing end end assert_raise(Interrupt) do run_test_case(test_case) end end def test_pass_through_in_test test_case = Class.new(TestCase) do @called = [] class << self def called @called end def startup @called << :startup end def shutdown @called << :shutdown end end def test_error raise Interrupt, "from test" end end assert_raise(Interrupt) do run_test_case(test_case) end assert_equal([:startup, :shutdown], test_case.called) end class TestName < self def test_no_data test_case = Class.new(TestCase) do class << self def name "TestCase" end end def test_nothing end end test = test_case.new("test_nothing") assert_equal("test_nothing(TestCase)", test.name) end def test_data test_case = Class.new(TestCase) do class << self def name "TestCase" end end def test_nothing end end test = test_case.new("test_nothing") test.assign_test_data("(nil)", nil) assert_equal("test_nothing[(nil)](TestCase)", test.name) end end class TestLocalName < self def test_no_data test_case = Class.new(TestCase) do class << self def name "TestCase" end end def test_nothing end end test = test_case.new("test_nothing") assert_equal("test_nothing", test.local_name) end def test_data test_case = Class.new(TestCase) do class << self def name "TestCase" end end def test_nothing end end test = test_case.new("test_nothing") test.assign_test_data("(nil)", nil) assert_equal("test_nothing[(nil)]", test.local_name) end end end end end end end PKu])N'test-unit-3.3.4/test/test-assertions.rbnu[# -*- coding: utf-8 -*- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # Copyright (c) 2009-2014 Kouhei Sutou. All rights reserved. # License:: Ruby license. require 'test/unit' require "testunit-test-util" module Test module Unit module AssertionCheckable include TestUnitTestUtil private def check(value, message="") add_assertion raise AssertionFailedError.new(message) unless value end def check_assertions(expect_fail, options={}) expected_message = options[:expected_message] actual_message_normalizer = options[:actual_message_normalizer] return_value_expected = options[:return_value_expected] @actual_assertion_count = 0 failed = true actual_message = nil @catch_assertions = true return_value = nil begin return_value = yield failed = false rescue AssertionFailedError => error return_value = error actual_message = error.message end @catch_assertions = false if expect_fail message = "Should have failed, but didn't" else message = "Should not have failed, but did with message\n" + "<#{actual_message}>" end check(expect_fail == failed, message) message = "Should have made one assertion but made\n" + "<#{@actual_assertion_count}>" check(1 == @actual_assertion_count, message) if expect_fail if actual_message_normalizer actual_message = actual_message_normalizer.call(actual_message) end case expected_message when String check(expected_message == actual_message, "Should have the correct message.\n" + "<#{expected_message.inspect}> expected but was\n" + "<#{actual_message.inspect}>") when Regexp check(expected_message =~ actual_message, "The message should match correctly.\n" + " expected to match\n" + "<#{actual_message.inspect}>") else check(false, "Incorrect expected message type in assert_nothing_failed") end else case return_value_expected when :dont_care # do nothing when true check(!return_value.nil?, "Should return a value") else check(return_value.nil?, "Should not return a value but returned <#{return_value}>") end end return_value end def check_nothing_fails(return_value_expected=false, &proc) check_assertions(false, {:expected_message => nil, :return_value_expected => return_value_expected}, &proc) end def check_fail(expected_message, options={}, &proc) check_assertions(true, options.merge(:expected_message => expected_message), &proc) end def check_fail_exception(expected_message, options={}, &proc) normalizer = lambda do |actual_message| actual_message.gsub(/(^[^:\n]+:\d+:.+\n?)+\z/, "") end check_assertions(true, options.merge(:expected_message => expected_message, :actual_message_normalizer => normalizer), &proc) end def inspect_tag(tag) tag.inspect end def add_failure(message, location=caller, options=nil) unless @catch_assertions super end end def add_assertion if @catch_assertions @actual_assertion_count += 1 else super end end end class TestAssertions < TestCase include AssertionCheckable class TestAssertBlock < self def test_pass_without_message check_nothing_fails { assert_block {true} } end def test_pass_with_message check_nothing_fails { assert_block("successful assert_block") {true} } end def test_failure_without_message check_fail("assert_block failed.") { assert_block {false} } end def test_failure_with_message check_fail("failed assert_block") { assert_block("failed assert_block") {false} } end end class TestAssertEqual < self class TestSuccess < self def test_without_message check_nothing_fails { assert_equal("string1", "string1") } end def test_with_message check_nothing_fails { assert_equal("string1", "string1", "successful assert_equal") } end end class TestFailure < self def test_without_message message = <<-EOM.chomp <"string1"> expected but was <"string2">. diff: - string1 ? ^ + string2 ? ^ EOM check_fail(message) { assert_equal("string1", "string2") } end def test_with_message message = <<-EOM.chomp failed assert_equal. <"string1"> expected but was <"string2">. diff: - string1 ? ^ + string2 ? ^ EOM check_fail(message) { assert_equal("string1", "string2", "failed assert_equal") } end def test_with_message_proc message = <<-EOM.chomp failed assert_equal. <"string1"> expected but was <"string2">. diff: - string1 ? ^ + string2 ? ^ EOM check_fail(message) do assert_equal("string1", "string2", lambda {"failed assert_equal"}) end end end class TestSystemMessage < self def test_different_type message = <<-EOM.chomp <"111111"> expected but was <111111>. diff: - "111111" ? - - + 111111 EOM check_fail(message) do assert_equal("111111", 111111) end end def test_long_line expected = ["0123456789", "1123456789", "2123456789", "3123456789", "4123456789", "5123456789", "6123456789", "7123456789", "8123456789"].join actual = ["0000000000", "1123456789", "2123456789", "3123456789", "4123456789", "5123456789", "6123456789", "7123456789", "8123456789"].join message = <<-EOM.chomp <"#{expected}"> expected but was <"#{actual}">. diff: - #{expected} ? ^^^^^^^^^ + #{actual} ? ^^^^^^^^^ folded diff: - 012345678911234567892123456789312345678941234567895123456789612345678971234567 ? ^^^^^^^^^ + 000000000011234567892123456789312345678941234567895123456789612345678971234567 ? ^^^^^^^^^ 898123456789 EOM check_fail(message) do assert_equal(expected, actual) end end def test_too_small_difference message = <<-EOM.chomp <1> expected but was <2>. EOM check_fail(message) do assert_equal(1, 2) end end def test_same_inspected_objects same_inspected_class = Class.new do def inspect "inspected" end end object1 = same_inspected_class.new object2 = same_inspected_class.new message = <<-EOM.chomp expected but was . EOM check_fail(message) do assert_equal(object1, object2) end end def test_multi_lines_result message = <<-EOM.chomp <#{AssertionMessage.convert("a\nb")}> expected but was <#{AssertionMessage.convert("x")}>. diff: + x - a - b EOM check_fail(message) do assert_equal("a\nb", "x") end end def test_large_string message = <<-EOM.chomp <#{AssertionMessage.convert("a\n" + "x" * 997)}> expected but was <#{AssertionMessage.convert("x")}>. diff: + x - a - #{"x" * 997} folded diff: + x - a #{(["- " + ("x" * 78)] * 12).join("\n")} - #{"x" * 61} EOM check_fail(message) do assert_equal("a\n" + "x" * 997, "x") end message = <<-EOM.chomp <#{AssertionMessage.convert("a\n" + "x" * 998)}> expected but was <#{AssertionMessage.convert("x")}>. EOM check_fail(message) do assert_equal("a\n" + "x" * 998, "x") end end def test_max_diff_target_string_size key = "TEST_UNIT_MAX_DIFF_TARGET_STRING_SIZE" before_value = ENV[key] ENV[key] = "100" begin message = <<-EOM.chomp <#{AssertionMessage.convert("a\n" + "x" * 97)}> expected but was <#{AssertionMessage.convert("x")}>. diff: + x - a - #{"x" * 97} folded diff: + x - a #{(["- " + ("x" * 78)]).join("\n")} - #{"x" * 19} EOM check_fail(message) do assert_equal("a\n" + "x" * 97, "x") end message = <<-EOM.chomp <#{AssertionMessage.convert("a\n" + "x" * 98)}> expected but was <#{AssertionMessage.convert("x")}>. EOM check_fail(message) do assert_equal("a\n" + "x" * 98, "x") end ensure ENV[key] = before_value end end def test_different_encoding utf8_string = "こんにちは" unless utf8_string.respond_to?(:force_encoding) omit("encoding test is for Ruby >= 1.9") end ascii_8bit_string = utf8_string.dup.force_encoding("ascii-8bit") message = <<-EOM.chomp <#{utf8_string.inspect}>("UTF-8") expected but was <#{ascii_8bit_string.inspect}>("ASCII-8BIT"). EOM check_fail(message) do assert_equal(utf8_string, ascii_8bit_string) end end def test_different_hash designers = { "Ruby" => "Matz", "Lisp" => "John McCarthy", } categories = { "LL" => ["Ruby", "Python"], "Heavy" => ["C", "C++"], } message = <<-EOM.chomp <{"Lisp"=>"John McCarthy", "Ruby"=>"Matz"}> expected but was <{"Heavy"=>["C", "C++"], "LL"=>["Ruby", "Python"]}>. EOM check_fail(message) do assert_equal(designers, categories) end end def test_recursive_hash alice = {"name" => "Alice"} bob = {"name" => "Bob"} alice["followers"] = [bob] bob["followers"] = [alice] message = <<-EOM.chomp <{"followers"=>[{"followers"=>[{...}], "name"=>"Bob"}], "name"=>"Alice"}> expected but was <{"followers"=>[{"followers"=>[{...}], "name"=>"Alice"}], "name"=>"Bob"}>. diff: - {"followers"=>[{"followers"=>[{...}], "name"=>"Bob"}], "name"=>"Alice"} ? ----------------- + {"followers"=>[{"followers"=>[{...}], "name"=>"Alice"}], "name"=>"Bob"} ? +++++++++++++++++ EOM check_fail(message) do assert_equal(alice, bob) end end def test_numeric numeric_family_class = Class.new(Numeric) do def inspect "inspect is called" end def to_s "to_s is called" end end numeric = numeric_family_class.new message = <<-MESSAGE.chomp expected but was <"must be failed">. MESSAGE check_fail(message) do assert_equal(numeric, "must be failed") end end end end def test_assert_raise_success return_value = nil check_nothing_fails(true) do return_value = assert_raise(RuntimeError) do raise "Error" end end check(return_value.kind_of?(Exception), "Should have returned the exception " + "from a successful assert_raise") check(return_value.message == "Error", "Should have returned the correct exception " + "from a successful assert_raise") check_nothing_fails(true) do assert_raise(ArgumentError, "successful assert_raise") do raise ArgumentError.new("Error") end end check_nothing_fails(true) do assert_raise(RuntimeError) do raise "Error" end end check_nothing_fails(true) do assert_raise(RuntimeError, "successful assert_raise") do raise "Error" end end check_nothing_fails(true) do assert_raise do raise Exception, "Any exception" end end end def test_assert_raise_fail check_fail(" exception was expected but none was thrown.") do assert_raise(RuntimeError) do 1 + 1 end end message = <<-EOM.chomp failed assert_raise. exception expected but was )>. EOM check_fail_exception(message) do assert_raise(ArgumentError, "failed assert_raise") do raise "Error" end end message = <<-EOM must be a subclass of Exception, an object of Exception subclasses or a Module. EOM check_fail(message.chomp) do assert_nothing_raised(Object) do 1 + 1 end end end def test_assert_raise_module exceptions = [ArgumentError, TypeError] modules = [Math, Comparable] rescues = exceptions + modules exceptions.each do |exc| return_value = nil check_nothing_fails(true) do return_value = assert_raise(*rescues) do raise exc, "Error" end end check(return_value.instance_of?(exc), "Should have returned #{exc} but was #{return_value.class}") check(return_value.message == "Error", "Should have returned the correct exception " + "from a successful assert_raise") end modules.each do |mod| return_value = nil check_nothing_fails(true) do return_value = assert_raise(*rescues) do raise Exception.new("Error").extend(mod) end end check(mod === return_value, "Should have returned #{mod}") check(return_value.message == "Error", "Should have returned the correct exception " + "from a successful assert_raise") end check_fail("<[ArgumentError, TypeError, Math, Comparable]> exception " + "was expected but none was thrown.") do assert_raise(*rescues) do 1 + 1 end end message = <<-EOM.chomp failed assert_raise. <[ArgumentError, TypeError]> exception expected but was )>. EOM check_fail_exception(message) do assert_raise(ArgumentError, TypeError, "failed assert_raise") do raise "Error" end end end def test_assert_raise_instance return_value = nil check_nothing_fails(true) do return_value = assert_raise(RuntimeError.new("Error")) do raise "Error" end end check(return_value.kind_of?(Exception), "Should have returned the exception " + "from a successful assert_raise") check(return_value.message == "Error", "Should have returned the correct exception " + "from a successful assert_raise") message = <<-EOM.chomp )> exception expected but was )>. diff: - RuntimeError() ? ^^^ + RuntimeError() ? ^^^^^ EOM check_fail_exception(message) do return_value = assert_raise(RuntimeError.new("XXX")) do raise "Error" end end different_error_class = Class.new(StandardError) message = <<-EOM.chomp <#{different_error_class.inspect}()> exception expected but was )>. EOM check_fail_exception(message) do assert_raise(different_error_class.new("Error")) do raise "Error" end end different_error = different_error_class.new("Error") def different_error.inspect "DifferentError: \"Error\"" end message = <<-EOM.chomp exception expected but was )>. EOM check_fail_exception(message) do assert_raise(different_error) do raise "Error" end end check_nothing_fails(true) do assert_raise(different_error_class.new("Error"), RuntimeError.new("Error"), RuntimeError.new("XXX")) do raise "Error" end end end def test_assert_raise_jruby omit("For JRuby") unless Object.const_defined?(:Java) exception = Java::JavaLang::StringIndexOutOfBoundsException return_value = nil check_nothing_fails(true) do return_value = assert_raise(exception) do Java::JavaLang::String.new("abc").char_at(4) end end check(return_value.instance_of?(exception), "Should have returned #{exception} but was #{return_value.class}") end def test_assert_instance_of check_nothing_fails { assert_instance_of(String, "string") } check_nothing_fails { assert_instance_of(String, "string", "successful assert_instance_of") } check_nothing_fails { assert_instance_of(String, "string", "successful assert_instance_of") } check_fail(%Q{<"string"> was expected to be instance_of?\n but was\n.}) { assert_instance_of(Hash, "string") } check_fail(%Q{failed assert_instance_of.\n<"string"> was expected to be instance_of?\n but was\n.}) { assert_instance_of(Hash, "string", "failed assert_instance_of") } check_nothing_fails do assert_instance_of([Class, NilClass], Array) end check_fail(%Q{<"string"> was expected to be instance_of?\n[, ] but was\n.}) do assert_instance_of([Class, NilClass], "string") end check_fail(%Q{ was expected to be instance_of?\n[, ] but was\n.}) do assert_instance_of([Module, NilClass], Array) end end def test_assert_not_instance_of check_nothing_fails { assert_not_instance_of(NilClass, "string") } check_nothing_fails { assert_not_instance_of(NilClass, "string", "successful assert_instance_of") } check_fail(%Q{<"string"> was expected to not be instance_of?\n but was.}) { assert_not_instance_of(String, "string") } check_fail(%Q{failed assert.\n<"string"> was expected to not be instance_of?\n but was.}) { assert_not_instance_of(String, "string", "failed assert") } check_nothing_fails do assert_not_instance_of([Module, NilClass], Array) end check_fail(%Q{ was expected to not be instance_of?\n[, ] but was.}) do assert_not_instance_of([Class, NilClass], Array) end check_fail(%Q{<"str"> was expected to not be instance_of?\n[, ] but was.}) do assert_not_instance_of([Numeric, String], 'str') end end def test_assert_nil check_nothing_fails { assert_nil(nil) } check_nothing_fails { assert_nil(nil, "successful assert_nil") } check_nothing_fails { assert_nil(nil, "successful assert_nil") } check_fail(%Q{<"string"> was expected to be nil.}) { assert_nil("string") } check_fail(%Q{failed assert_nil.\n<"string"> was expected to be nil.}) { assert_nil("string", "failed assert_nil") } end def test_assert_not_nil check_nothing_fails{assert_not_nil(false)} check_nothing_fails{assert_not_nil(false, "message")} check_fail(" was expected to not be nil."){assert_not_nil(nil)} check_fail("message.\n was expected to not be nil.") {assert_not_nil(nil, "message")} end def test_assert_kind_of check_nothing_fails { assert_kind_of(Module, Array) } check_nothing_fails { assert_kind_of(Object, "string", "successful assert_kind_of") } check_nothing_fails { assert_kind_of(String, "string", "successful assert_kind_of") } check_nothing_fails { assert_kind_of(Comparable, 1) } check_fail(%Q{<"string"> was expected to be kind_of?\n but was\n.}) { assert_kind_of(Class, "string") } check_fail(%Q{failed assert_kind_of.\n<"string"> was expected to be kind_of?\n but was\n.}) { assert_kind_of(Class, "string", "failed assert_kind_of") } check_nothing_fails do assert_kind_of([Class, NilClass], Array) end check_fail(%Q{<"string"> was expected to be kind_of?\n[, ] but was\n.}) do assert_kind_of([Class, NilClass], "string") end end def test_assert_not_kind_of check_nothing_fails { assert_not_kind_of(Class, 42) } check_nothing_fails { assert_not_kind_of(Symbol, "string", "successful assert_not_kind_of") } check_nothing_fails { assert_not_kind_of(Integer, 1.1) } check_fail(%Q{<1> was expected to not be kind_of?\n but was.}) { assert_not_kind_of(Integer, 1) } check_fail(%Q{failed assert_not_kind_of.\n<"string"> was expected to not be kind_of?\n but was.}) { assert_not_kind_of(String, "string", "failed assert_not_kind_of") } check_nothing_fails do assert_not_kind_of([String, NilClass], 100) end check_fail(%Q{ was expected to not be kind_of?\n[, ] but was.}) do assert_not_kind_of([Class, NilClass], Array) end end def test_assert_match check_nothing_fails { assert_match(/strin./, "string") } check_nothing_fails { assert_match("strin", "string") } check_nothing_fails { assert_match(/strin./, "string", "successful assert_match") } check_nothing_fails { assert_match(/strin./, "string", "successful assert_match") } check_fail(%Q{ was expected to be =~\n<"string">.}) { assert_match(/slin./, "string") } check_fail(%Q{ was expected to be =~\n<"string">.}) { assert_match("strin.", "string") } check_fail(%Q{failed assert_match.\n was expected to be =~\n<"string">.}) { assert_match(/slin./, "string", "failed assert_match") } end def test_assert_same thing = "thing" check_nothing_fails { assert_same(thing, thing) } check_nothing_fails { assert_same(thing, thing, "successful assert_same") } check_nothing_fails { assert_same(thing, thing, "successful assert_same") } thing2 = thing.dup check_fail(%Q{<"thing">\nwith id <#{thing.__id__}> was expected to be equal? to\n<"thing">\nwith id <#{thing2.__id__}>.}) { assert_same(thing, thing2) } check_fail(%Q{failed assert_same.\n<"thing">\nwith id <#{thing.__id__}> was expected to be equal? to\n<"thing">\nwith id <#{thing2.__id__}>.}) { assert_same(thing, thing2, "failed assert_same") } end def test_assert_nothing_raised check_nothing_fails(:dont_care) { assert_nothing_raised { 1 + 1 } } check_nothing_fails(:dont_care) { assert_nothing_raised("successful assert_nothing_raised") { 1 + 1 } } check_nothing_fails(:dont_care) { assert_nothing_raised("successful assert_nothing_raised") { 1 + 1 } } check_nothing_fails(:dont_care) { begin assert_nothing_raised(RuntimeError, StandardError, Comparable, "successful assert_nothing_raised") { raise ZeroDivisionError.new("ArgumentError") } rescue ZeroDivisionError end } expected_message = " must be a subclass of Exception, " + "an object of Exception subclasses or a Module." check_fail(expected_message) { assert_nothing_raised(Object) { 1 + 1 } } expected_message = <<-EOM.chomp Exception raised: RuntimeError() EOM check_fail_exception(expected_message) { assert_nothing_raised { raise "Error" } } expected_message = <<-EOM.chomp failed assert_nothing_raised. Exception raised: RuntimeError() EOM check_fail_exception(expected_message) { assert_nothing_raised("failed assert_nothing_raised") { raise "Error" } } expected_message = <<-EOM.chomp Exception raised: RuntimeError() EOM check_fail_exception(expected_message) { assert_nothing_raised(StandardError, RuntimeError) { raise "Error" } } check_fail("Failure.") do assert_nothing_raised do flunk("Failure") end end end def test_flunk check_fail("Flunked.") { flunk } check_fail("flunk message.") { flunk("flunk message") } end def test_assert_not_same thing = "thing" thing2 = thing.dup check_nothing_fails { assert_not_same(thing, thing2) } check_nothing_fails { assert_not_same(thing, thing2, "message") } check_fail(%Q{<"thing">\nwith id <#{thing.__id__}> was expected to not be equal? to\n<"thing">\nwith id <#{thing.__id__}>.}) { assert_not_same(thing, thing) } check_fail(%Q{message.\n<"thing">\nwith id <#{thing.__id__}> was expected to not be equal? to\n<"thing">\nwith id <#{thing.__id__}>.}) { assert_not_same(thing, thing, "message") } end def test_assert_not_equal check_nothing_fails { assert_not_equal("string1", "string2") } check_nothing_fails { assert_not_equal("string1", "string2", "message") } check_fail(%Q{<"string"> was expected to be != to\n<"string">.}) { assert_not_equal("string", "string") } check_fail(%Q{message.\n<"string"> was expected to be != to\n<"string">.}) { assert_not_equal("string", "string", "message") } end def test_assert_not_match_pass check_nothing_fails do assert_not_match(/sling/, "string") end end def test_assert_not_match_pass_with_message check_nothing_fails do assert_not_match(/sling/, "string", "message") end end def test_assert_not_match_fail_not_regexp check_fail(" in assert_not_match(, ...) " + "should be a Regexp.\n" + "<\"asdf\"> was expected to be instance_of?\n" + " but was\n" + ".") do assert_not_match("asdf", "asdf") end end def test_assert_not_match_fail_match check_fail(" was expected to not match\n" + "<\"string\">.") do assert_not_match(/string/, "string") end end def test_assert_not_match_fail_match_with_message check_fail("message.\n" + " was expected to not match\n" + "<\"string\">.") do assert_not_match(/string/, "string", "message") end end def test_assert_no_match check_nothing_fails{assert_no_match(/sling/, "string")} check_nothing_fails{assert_no_match(/sling/, "string", "message")} check_fail(%Q{The first argument to assert_no_match should be a Regexp.\n<"asdf"> was expected to be instance_of?\n but was\n.}) do assert_no_match("asdf", "asdf") end check_fail(%Q{ was expected to not match\n<"string">.}) do assert_no_match(/string/, "string") end check_fail(%Q{message.\n was expected to not match\n<"string">.}) do assert_no_match(/string/, "string", "message") end end def test_assert_throw check_nothing_fails do assert_throw(:thing, "message") do throw :thing end end tag = :thing2 check_fail("message.\n" + "<:thing> was expected to be thrown but\n" + "<#{inspect_tag(tag)}> was thrown.") do assert_throw(:thing, "message") do throw :thing2 end end check_fail("message.\n" + "<:thing> should have been thrown.") do assert_throw(:thing, "message") do 1 + 1 end end end def test_assert_nothing_thrown check_nothing_fails do assert_nothing_thrown("message") do 1 + 1 end end tag = :thing inspected = inspect_tag(tag) check_fail("message.\n" + "<#{inspected}> was thrown when nothing was expected.") do assert_nothing_thrown("message") do throw tag end end end def test_assert_operator check_nothing_fails { assert_operator("thing", :==, "thing", "message") } check_fail(%Q{<0.15>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to?(:to_str).}) do assert_operator("thing", 0.15, "thing") end check_fail(%Q{message.\n<"thing1"> was expected to be\n==\n<"thing2">.}) { assert_operator("thing1", :==, "thing2", "message") } end def test_assert_not_operator check_nothing_fails { assert_not_operator("thing", :==, "Thing", "message") } check_fail(%Q{<42>\ngiven as the operator for #assert_not_operator must be a Symbol or #respond_to?(:to_str).}) do assert_not_operator("thing", 42, "message") end check_fail(%Q{message.\n<0> was expected to not be\n==\n<0.0>.}) { assert_not_operator(0, :==, 0.0, "message") } end def test_assert_respond_to check_nothing_fails { assert_respond_to("thing", :to_s, "message") } check_nothing_fails { assert_respond_to("thing", "to_s", "message") } check_fail("<0.15>.kind_of?(Symbol) or\n" + "<0.15>.respond_to?(:to_str) expected") { assert_respond_to("thing", 0.15) } check_fail("message.\n" + "<:symbol>.respond_to?(:nonexistence) expected\n" + "(Class: )") { assert_respond_to(:symbol, :nonexistence, "message") } end def test_assert_not_respond_to_pass_symbol check_nothing_fails do assert_not_respond_to("thing", :nonexistent, "message") end end def test_assert_not_respond_to_pass_string check_nothing_fails do assert_not_respond_to("thing", :nonexistent, "message") end end def test_assert_not_respond_to_fail_number check_fail("<0.15>.kind_of?(Symbol) or\n" + "<0.15>.respond_to?(:to_str) expected") do assert_respond_to("thing", 0.15) end end def tset_assert_not_respond_to_fail_existence check_fail("message.\n" + "!<:symbol>.respond_to?(:to_s) expected\n" + "(Class: )") do assert_respond_to(:symbol, :to_s, "message") end end def test_assert_send object = Object.new class << object private def return_argument(argument, bogus) return argument end end check_nothing_fails do assert_send([object, :return_argument, true, "bogus"], "message") end inspected_object = AssertionMessage.convert(object) expected_message = <<-EOM message. <#{inspected_object}> was expected to respond to with a true value but was . EOM check_fail(expected_message.chomp) do assert_send([object, :return_argument, false, "bogus"], "message") end end def test_condition_invariant object = Object.new def object.inspect @changed = true end def object.==(other) @changed ||= false return (!@changed) end check_nothing_fails do assert_equal(object, object, "message") end end def test_assert_boolean check_nothing_fails do assert_boolean(true) end check_nothing_fails do assert_boolean(false) end check_fail(" or expected but was\n<1>") do assert_boolean(1) end check_fail(" or expected but was\n") do assert_boolean(nil) end check_fail("message.\n or expected but was\n<\"XXX\">") do assert_boolean("XXX", "message") end end def test_assert_true check_nothing_fails do assert_true(true) end check_fail(" expected but was\n") do assert_true(false) end check_fail(" expected but was\n<1>") do assert_true(1) end exception = check_fail("message.\n expected but was\n") do assert_true(nil, "message") end assert_equal("message", exception.user_message) end def test_assert_false check_nothing_fails do assert_false(false) end check_fail(" expected but was\n") do assert_false(true) end check_fail(" expected but was\n") do assert_false(nil) end check_fail("message.\n expected but was\n<:false>") do assert_false(:false, "message") end end def test_assert_compare check_nothing_fails do assert_compare(1.4, "<", 10.0) end check_nothing_fails do assert_compare(2, "<=", 2) end check_nothing_fails do assert_compare(14, ">=", 10.0) end check_nothing_fails do assert_compare(14, ">", 13.9) end expected_message = <<-EOM <15> < <10> should be true <15> was expected to be less than <10>. EOM check_fail(expected_message.chomp) do assert_compare(15, "<", 10) end expected_message = <<-EOM <15> <= <10> should be true <15> was expected to be less than or equal to <10>. EOM check_fail(expected_message.chomp) do assert_compare(15, "<=", 10) end expected_message = <<-EOM <10> > <15> should be true <10> was expected to be greater than <15>. EOM check_fail(expected_message.chomp) do assert_compare(10, ">", 15) end expected_message = <<-EOM <10> >= <15> should be true <10> was expected to be greater than or equal to <15>. EOM check_fail(expected_message.chomp) do assert_compare(10, ">=", 15) end end def test_assert_fail_assertion check_nothing_fails do assert_fail_assertion do flunk end end check_fail("Failed assertion was expected.") do assert_fail_assertion do end end end def test_assert_raise_message check_nothing_fails do assert_raise_message("Raise!") do raise "Raise!" end end check_nothing_fails do assert_raise_message("Raise!") do raise Exception, "Raise!" end end check_nothing_fails do assert_raise_message(/raise/i) do raise "Raise!" end end expected_message = <<-EOM <"Expected message"> exception message expected but was <"Actual message">. EOM check_fail(expected_message.chomp) do assert_raise_message("Expected message") do raise "Actual message" end end expected_message = <<-EOM <"Expected message"> exception message was expected but none was thrown. EOM check_fail(expected_message.chomp) do assert_raise_message("Expected message") do end end end def test_assert_raise_kind_of check_nothing_fails(true) do assert_raise_kind_of(SystemCallError) do raise Errno::EACCES end end expected_message = <<-EOM.chomp family exception expected but was )>. EOM check_fail_exception(expected_message) do assert_raise_kind_of(SystemCallError) do raise RuntimeError, "XXX" end end end def test_assert_const_defined check_nothing_fails do assert_const_defined(Test, :Unit) end check_nothing_fails do assert_const_defined(Test, "Unit") end check_fail(".const_defined?(<:Nonexistence>) expected.") do assert_const_defined(Test, :Nonexistence) end end def test_assert_not_const_defined check_nothing_fails do assert_not_const_defined(Test, :Nonexistence) end check_fail("!.const_defined?(<:Unit>) expected.") do assert_not_const_defined(Test, :Unit) end check_fail("!.const_defined?(<\"Unit\">) expected.") do assert_not_const_defined(Test, "Unit") end end def test_assert_predicate check_nothing_fails do assert_predicate([], :empty?) end check_fail("<[1]>.empty? is true value expected but was\n") do assert_predicate([1], :empty?) end check_fail("<[1]>.respond_to?(:nonexistent?) expected\n" + "(Class: )") do assert_predicate([1], :nonexistent?) end end def test_assert_not_predicate check_nothing_fails do assert_not_predicate([1], :empty?) end check_fail("<[]>.empty? is false value expected but was\n") do assert_not_predicate([], :empty?) end check_fail("<[]>.respond_to?(:nonexistent?) expected\n" + "(Class: )") do assert_not_predicate([], :nonexistent?) end end def test_assert_alias_method object = Object.new class << object def original_method end alias_method :alias_method, :original_method def other end end check_nothing_fails do assert_alias_method(object, :alias_method, :original_method) end check_nothing_fails do assert_alias_method(object, :original_method, :alias_method) end check_fail("<#{object.method(:other).inspect}> is alias of\n" + "<#{object.method(:original_method).inspect}> expected") do assert_alias_method(object, :other, :original_method) end inspected_object = AssertionMessage.convert(object) check_fail("<#{inspected_object}>.nonexistent doesn't exist\n" + "(Class: )") do assert_alias_method(object, :nonexistent, :original_method) end check_fail("<#{inspected_object}>.nonexistent doesn't exist\n" + "(Class: )") do assert_alias_method(object, :alias_method, :nonexistent) end end def test_assert_path_exist check_nothing_fails do assert_path_exist(__FILE__) end nonexistent_file = __FILE__ + ".nonexistent" check_fail("<#{nonexistent_file.inspect}> was expected to exist") do assert_path_exist(nonexistent_file) end end def test_assert_path_not_exist nonexistent_file = __FILE__ + ".nonexistent" check_nothing_fails do assert_path_not_exist(nonexistent_file) end check_fail("<#{__FILE__.inspect}> was expected to not exist") do assert_path_not_exist(__FILE__) end end end class TestAssert < TestCase include AssertionCheckable def test_pass check_nothing_fails do assert(true) end end def test_pass_neither_false_or_nil check_nothing_fails do assert("a") end end def test_pass_with_message check_nothing_fails do assert(true, "successful assert") end end def test_pass_block check_nothing_fails do assert do true end end end def test_fail_nil check_fail(" is not true.") do assert(nil) end end def test_fail_false check_fail(" is not true.") do assert(false) end end def test_fail_false_with_message check_fail("failed assert.\n" + " is not true.") do assert(false, "failed assert") end end def test_fail_with_assertion_message check_fail("user message.\n" + "placeholder <:in> message") do assert(false, build_message("user message", "placeholder message", :in)) end end def test_fail_block check_fail(//) do assert do 0.odd? end end end def test_error_invalid_message_true check_fail("assertion message must be String, Proc or " + "Test::Unit::Assertions::AssertionMessage: " + "()") do begin assert(true, true) rescue ArgumentError raise AssertionFailedError, $!.message end end end def test_error_wrong_number_of_arguments check_fail("wrong number of arguments (0 for 1..2)") do begin assert rescue ArgumentError raise AssertionFailedError, $!.message end end end class TestBlock < self def test_with_message if defined?(PowerAssert) system_message = <<-MESSAGE.chomp 1.to_s == "2" | | | false "1" MESSAGE else system_message = " is not true." end check_fail("user message.\n#{system_message}") do assert("user message") do 1.to_s == "2" end end end end end class TestRefute < TestCase include AssertionCheckable class TestPass < self def test_nil check_nothing_fails do refute(nil) end end def test_false check_nothing_fails do refute(false) end end def test_with_message check_nothing_fails do refute(nil, "successful refute") end end end class TestFailure < self def test_true check_fail(" is neither nil or false.") do refute(true) end end def test_with_message check_fail("failed refute.\n" + " is neither nil or false.") do refute(true, "failed refute") end end def test_fail_with_assertion_message check_fail("user message.\n" + "placeholder <:in> message") do refute(true, build_message("user message", "placeholder message", :in)) end end def test_error_invalid_message_true check_fail("assertion message must be String, Proc or " + "Test::Unit::Assertions::AssertionMessage: " + "()") do begin refute(true, false) rescue ArgumentError raise AssertionFailedError, $!.message end end end end end class TestAssertInDelta < TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_in_delta(1.4, 1.4, 0) end end def test_pass_without_delta check_nothing_fails do assert_in_delta(1.401, 1.402) end end def test_pass_with_message check_nothing_fails do assert_in_delta(0.5, 0.4, 0.1, "message") end end def test_pass_float_like_object check_nothing_fails do float_thing = Object.new def float_thing.to_f 0.2 end assert_in_delta(0.1, float_thing, 0.1) end end def test_pass_string_expected check_nothing_fails do assert_in_delta("0.5", 0.4, 0.1) end end def test_fail_with_message check_fail("message.\n" + "<0.5> -/+ <0.05> was expected to include\n" + "<0.4>.\n" + "\n" + "Relation:\n" + "<<0.4> < <0.5>-<0.05>[0.45] <= <0.5>+<0.05>[0.55]>") do assert_in_delta(0.5, 0.4, 0.05, "message") end end def test_fail_because_not_float_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The arguments must respond to to_f; " + "the first float did not.\n" + "<#{inspected_object}>.respond_to?(:to_f) expected\n" + "(Class: )") do assert_in_delta(object, 0.4, 0.1) end end def test_fail_because_negaitve_delta check_fail("The delta should not be negative.\n" + "<-0.1> was expected to be\n>=\n<0.0>.") do assert_in_delta(0.5, 0.4, -0.1, "message") end end def test_fail_without_delta check_fail("<1.402> -/+ <0.001> was expected to include\n" + "<1.404>.\n" + "\n" + "Relation:\n" + "<" + "<1.402>-<0.001>[#{1.402 - 0.001}] <= " + "<1.402>+<0.001>[#{1.402 + 0.001}] < " + "<1.404>" + ">") do assert_in_delta(1.402, 1.404) end end end class TestAssertNotInDelta < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_in_delta(1.42, 1.44, 0.01) end end def test_pass_without_delta check_nothing_fails do assert_not_in_delta(1.402, 1.404) end end def test_pass_with_message check_nothing_fails do assert_not_in_delta(0.5, 0.4, 0.09, "message") end end def test_pass_float_like_object check_nothing_fails do float_thing = Object.new def float_thing.to_f 0.2 end assert_not_in_delta(0.1, float_thing, 0.09) end end def test_pass_string_epxected check_nothing_fails do assert_not_in_delta("0.5", 0.4, 0.09) end end def test_fail check_fail("<1.4> -/+ <0.11> was expected to not include\n" + "<1.5>.\n" + "\n" + "Relation:\n" + "<" + "<1.4>-<0.11>[#{1.4 - 0.11}] <= " + "<1.5> <= " + "<1.4>+<0.11>[#{1.4 + 0.11}]" + ">") do assert_not_in_delta(1.4, 1.5, 0.11) end end def test_fail_without_delta check_fail("<1.402> -/+ <0.001> was expected to not include\n" + "<1.4021>.\n" + "\n" + "Relation:\n" + "<" + "<1.402>-<0.001>[#{1.402 - 0.001}] <= " + "<1.4021> <= " + "<1.402>+<0.001>[#{1.402 + 0.001}]" + ">") do assert_not_in_delta(1.402, 1.4021) end end def test_fail_with_message check_fail("message.\n" + "<0.5> -/+ <0.11> was expected to not include\n" + "<0.4>.\n" + "\n" + "Relation:\n" + "<" + "<0.5>-<0.11>[0.39] <= " + "<0.4> <= " + "<0.5>+<0.11>[0.61]" + ">") do assert_not_in_delta(0.5, 0.4, 0.11, "message") end end def test_fail_because_not_float_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The arguments must respond to to_f; " + "the first float did not.\n" + "<#{inspected_object}>.respond_to?(:to_f) expected\n" + "(Class: )") do assert_not_in_delta(object, 0.4, 0.1) end end def test_fail_because_negaitve_delta check_fail("The delta should not be negative.\n" + "<-0.11> was expected to be\n>=\n<0.0>.") do assert_not_in_delta(0.5, 0.4, -0.11, "message") end end end class TestAssertInEpsilon < TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_in_epsilon(10000, 9000, 0.1) end end def test_pass_without_epsilon check_nothing_fails do assert_in_epsilon(10000, 9991) end end def test_pass_with_message check_nothing_fails do assert_in_epsilon(10000, 9000, 0.1, "message") end end def test_pass_float_like_object check_nothing_fails do float_thing = Object.new def float_thing.to_f 9000.0 end assert_in_epsilon(10000, float_thing, 0.1) end end def test_pass_string_expected check_nothing_fails do assert_in_epsilon("10000", 9000, 0.1) end end def test_pass_zero_expected check_nothing_fails do assert_in_epsilon(0, 0.00000001) end end def test_pass_minus_expected check_nothing_fails do assert_in_epsilon(-1, -1) end end def test_fail_with_message check_fail("message.\n" + "<10000> -/+ (<10000> * <0.1>)[1000.0] " + "was expected to include\n" + "<8999>.\n" + "\n" + "Relation:\n" + "<" + "<8999> < " + "<10000>-(<10000>*<0.1>)[9000.0] <= " + "<10000>+(<10000>*<0.1>)[11000.0]" + ">") do assert_in_epsilon(10000, 8999, 0.1, "message") end end def test_fail_because_not_float_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The arguments must respond to to_f; " + "the first float did not.\n" + "<#{inspected_object}>.respond_to?(:to_f) expected\n" + "(Class: )") do assert_in_epsilon(object, 9000, 0.1) end end def test_fail_because_negaitve_epsilon check_fail("The epsilon should not be negative.\n" + "<-0.1> was expected to be\n>=\n<0.0>.") do assert_in_epsilon(10000, 9000, -0.1, "message") end end def test_fail_without_epsilon check_fail("<10000> -/+ (<10000> * <0.001>)[10.0] " + "was expected to include\n" + "<10011>.\n" + "\n" + "Relation:\n" + "<" + "<10000>-(<10000>*<0.001>)[9990.0] <= " + "<10000>+(<10000>*<0.001>)[10010.0] < " + "<10011>" + ">") do assert_in_epsilon(10000, 10011) end end end class TestAssertNotInEpsilon < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_in_epsilon(10000, 8999, 0.1) end end def test_pass_without_epsilon check_nothing_fails do assert_not_in_epsilon(10000, 9989) end end def test_pass_with_message check_nothing_fails do assert_not_in_epsilon(10000, 8999, 0.1, "message") end end def test_pass_float_like_object check_nothing_fails do float_thing = Object.new def float_thing.to_f 8999.0 end assert_not_in_epsilon(10000, float_thing, 0.1) end end def test_pass_string_epxected check_nothing_fails do assert_not_in_epsilon("10000", 8999, 0.1) end end def test_fail check_fail("<10000> -/+ (<10000> * <0.1>)[1000.0] " + "was expected to not include\n" + "<9000>.\n" + "\n" + "Relation:\n" + "<" + "<10000>-(<10000>*<0.1>)[9000.0] <= " + "<9000> <= " + "<10000>+(<10000>*<0.1>)[11000.0]" + ">") do assert_not_in_epsilon(10000, 9000, 0.1) end end def test_fail_without_epsilon check_fail("<10000> -/+ (<10000> * <0.001>)[10.0] " + "was expected to not include\n" + "<9990>.\n" + "\n" + "Relation:\n" + "<" + "<10000>-(<10000>*<0.001>)[9990.0] <= " + "<9990> <= " + "<10000>+(<10000>*<0.001>)[10010.0]" + ">") do assert_not_in_epsilon(10000, 9990) end end def test_fail_with_message check_fail("message.\n" + "<10000> -/+ (<10000> * <0.1>)[1000.0] " + "was expected to not include\n" + "<9000>.\n" + "\n" + "Relation:\n" + "<" + "<10000>-(<10000>*<0.1>)[9000.0] <= " + "<9000> <= " + "<10000>+(<10000>*<0.1>)[11000.0]" + ">") do assert_not_in_epsilon(10000, 9000, 0.1, "message") end end def test_fail_because_not_float_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The arguments must respond to to_f; " + "the first float did not.\n" + "<#{inspected_object}>.respond_to?(:to_f) expected\n" + "(Class: )") do assert_not_in_epsilon(object, 9000, 0.1) end end def test_fail_because_negaitve_epsilon check_fail("The epsilon should not be negative.\n" + "<-0.1> was expected to be\n>=\n<0.0>.") do assert_not_in_epsilon(10000, 9000, -0.1, "message") end end end class TestAssertInclude < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_include([1, 2, 3], 1) end end def test_pass_with_message check_nothing_fails do assert_include([1, 2, 3], 1, "message") end end def test_fail check_fail("<[1, 2, 3]> was expected to include\n" + "<4>.") do assert_include([1, 2, 3], 4) end end def test_fail_with_message check_fail("message.\n" + "<[1, 2, 3]> was expected to include\n" + "<4>.") do assert_include([1, 2, 3], 4, "message") end end def test_fail_because_not_collection_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The collection must respond to :include?.\n" + "<#{inspected_object}>.respond_to?(:include?) expected\n" + "(Class: )") do assert_include(object, 1) end end end class TestAssertNotInclude < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_include([1, 2, 3], 5) end end def test_pass_with_message check_nothing_fails do assert_not_include([1, 2, 3], 5, "message") end end def test_fail check_fail("<[1, 2, 3]> was expected to not include\n" + "<2>.") do assert_not_include([1, 2, 3], 2) end end def test_fail_with_message check_fail("message.\n" + "<[1, 2, 3]> was expected to not include\n" + "<2>.") do assert_not_include([1, 2, 3], 2, "message") end end def test_fail_because_not_collection_like_object object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The collection must respond to :include?.\n" + "<#{inspected_object}>.respond_to?(:include?) expected\n" + "(Class: )") do assert_not_include(object, 1) end end end class TestAssertEmpty < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_empty([]) end end def test_pass_with_message check_nothing_fails do assert_empty([], "message") end end def test_fail check_fail("<[1]> was expected to be empty.") do assert_empty([1]) end end def test_fail_with_message check_fail("message.\n" + "<[1]> was expected to be empty.") do assert_empty([1], "message") end end def test_fail_because_no_empty_method object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The object must respond to :empty?.\n" + "<#{inspected_object}>.respond_to?(:empty?) expected\n" + "(Class: )") do assert_empty(object) end end end class TestAssertNotEmpty < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_empty([1]) end end def test_pass_with_message check_nothing_fails do assert_not_empty([1], "message") end end def test_fail check_fail("<[]> was expected to not be empty.") do assert_not_empty([]) end end def test_fail_with_message check_fail("message.\n" + "<[]> was expected to not be empty.") do assert_not_empty([], "message") end end def test_fail_because_no_empty_method object = Object.new inspected_object = AssertionMessage.convert(object) check_fail("The object must respond to :empty?.\n" + "<#{inspected_object}>.respond_to?(:empty?) expected\n" + "(Class: )") do assert_not_empty(object) end end end class TestAssertNotSend < Test::Unit::TestCase include AssertionCheckable def test_pass check_nothing_fails do assert_not_send([[1, 2], :member?, 4], "message") end end def test_fail expected_message = <<-EOM message. <[1, 2]> was expected to respond to with not a true value but was . EOM check_fail(expected_message.chomp) do assert_not_send([[1, 2], :member?, 2], "message") end end end class TestTemplate < Test::Unit::TestCase def test_incompatible_encoding_by_diff need_encoding assert_raise(AssertionFailedError) do assert_equal("UTF-8の日本語\n" * 3, ("Shift_JISの日本語\n" * 3).force_encoding("ASCII-8BIT")) end end private def need_encoding omit("need Encoding") unless Object.const_defined?(:Encoding) end end end end PKu]kVV$test-unit-3.3.4/test/test-fixture.rbnu[class TestUnitFixture < Test::Unit::TestCase module EmptyModule end class TestSetup < self def test_without_option expected_setup_calls = [:setup, :custom_setup_method0, :custom_setup_callback0, :custom_setup_method1, :custom_setup_callback1, :custom_setup_method3, :custom_setup_callback3] test_case = assert_setup(expected_setup_calls, []) assert_inherited_setup(expected_setup_calls, test_case) assert_inherited_setup([:setup], nil) assert_called_fixtures(expected_setup_calls, test_case) end def test_with_before_option expected_setup_calls = [:custom_setup_callback3, :custom_setup_method3, :custom_setup_method0, :custom_setup_callback0, :custom_setup_method1, :custom_setup_callback1, :setup] test_case = assert_setup(expected_setup_calls, [[{:before => :append}], [{:before => :append}], [{:before => :prepend}], [{:before => :prepend}]]) assert_inherited_setup(expected_setup_calls, test_case) assert_inherited_setup([:setup], nil) assert_called_fixtures(expected_setup_calls, test_case) end def test_with_after_option expected_setup_calls = [:setup, :custom_setup_callback3, :custom_setup_method3, :custom_setup_method0, :custom_setup_callback0, :custom_setup_method1, :custom_setup_callback1] test_case = assert_setup(expected_setup_calls, [[{:after => :append}], [{:after => :append}], [{:after => :prepend}], [{:after => :prepend}]]) assert_inherited_setup(expected_setup_calls, test_case) assert_inherited_setup([:setup], nil) assert_called_fixtures(expected_setup_calls, test_case) end def test_with_invalid_option assert_invalid_setup_option(:unknown => true) assert_invalid_setup_option(:before => :unknown) assert_invalid_setup_option(:after => :unknown) end def test_with_option_to_inherited expected_setup_calls = [:setup] test_case = assert_setup(expected_setup_calls, nil) assert_inherited_setup([:setup, :custom_setup_method0, :custom_setup_callback0, :custom_setup_method1, :custom_setup_callback1, :custom_setup_method3, :custom_setup_callback3], test_case, []) assert_inherited_setup([:setup], nil) assert_called_fixtures(expected_setup_calls, test_case) end private def assert_setup_customizable(expected, parent, options) test_case = Class.new(parent || Test::Unit::TestCase) do yield(self, :before) if block_given? def called_ids @called_ids ||= [] end def called(id) called_ids << id end def setup called(:setup) end setup(*(options[0] || [])) if options def custom_setup_method0 called(:custom_setup_method0) end if options setup(*(options[0] || [])) do called(:custom_setup_callback0) end end def custom_setup_method1 called(:custom_setup_method1) end setup(*[:custom_setup_method1, *(options[1] || [])]) if options if options setup(*(options[1] || [])) do called(:custom_setup_callback1) end end setup(*(options[2] || [])) if options def custom_setup_method2 called(:custom_setup_method2) end unregister_setup(:custom_setup_method2) if options if options callback = lambda do called(:custom_setup_callback2) end setup(*(options[2] || []), &callback) unregister_setup(callback) end setup(*(options[3] || [])) if options def custom_setup_method3 called(:custom_setup_method3) end if options setup(*(options[3] || [])) do called(:custom_setup_callback3) end end def test_nothing end yield(self, :after) if block_given? end assert_called_fixtures(expected, test_case) test_case end def assert_setup(expected, options) _test_case = assert_setup_customizable(expected, nil, options) assert_setup_customizable(expected, nil, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end _test_case end def assert_inherited_setup(expected, parent, options=nil) _test_case = assert_setup_customizable(expected, parent, options) assert_setup_customizable(expected, parent, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end _test_case end def assert_invalid_setup_option(option) assert_invalid_option(:setup, option) end end class TestCleanup < self def test_without_option expected_cleanup_calls = [:custom_cleanup_callback3, :custom_cleanup_method3, :custom_cleanup_callback1, :custom_cleanup_method1, :custom_cleanup_callback0, :custom_cleanup_method0, :cleanup] test_case = assert_cleanup(expected_cleanup_calls, []) assert_inherited_cleanup(expected_cleanup_calls, test_case) assert_inherited_cleanup([:cleanup], nil) assert_called_fixtures(expected_cleanup_calls, test_case) end def test_with_before_option expected_cleanup_calls = [:custom_cleanup_callback3, :custom_cleanup_method3, :custom_cleanup_method0, :custom_cleanup_callback0, :custom_cleanup_method1, :custom_cleanup_callback1, :cleanup] test_case = assert_cleanup(expected_cleanup_calls, [[{:before => :append}], [{:before => :append}], [{:before => :prepend}], [{:before => :prepend}]]) assert_inherited_cleanup(expected_cleanup_calls, test_case) assert_inherited_cleanup([:cleanup], nil) assert_called_fixtures(expected_cleanup_calls, test_case) end def test_with_after_option expected_cleanup_calls = [:cleanup, :custom_cleanup_callback3, :custom_cleanup_method3, :custom_cleanup_method0, :custom_cleanup_callback0, :custom_cleanup_method1, :custom_cleanup_callback1] test_case = assert_cleanup(expected_cleanup_calls, [[{:after => :append}], [{:after => :append}], [{:after => :prepend}], [{:after => :prepend}]]) assert_inherited_cleanup(expected_cleanup_calls, test_case) assert_inherited_cleanup([:cleanup], nil) assert_called_fixtures(expected_cleanup_calls, test_case) end def test_with_invalid_option assert_invalid_cleanup_option(:unknown => true) assert_invalid_cleanup_option(:before => :unknown) assert_invalid_cleanup_option(:after => :unknown) end def test_with_option_to_inherited expected_cleanup_calls = [:cleanup] test_case = assert_cleanup(expected_cleanup_calls, nil) assert_inherited_cleanup([:custom_cleanup_callback3, :custom_cleanup_method3, :custom_cleanup_callback1, :custom_cleanup_method1, :custom_cleanup_callback0, :custom_cleanup_method0, :cleanup], test_case, []) assert_inherited_cleanup([:cleanup], nil) assert_called_fixtures(expected_cleanup_calls, test_case) end def test_with_exception test_case = Class.new(Test::Unit::TestCase) do def called_ids @called_ids ||= [] end def called(id) called_ids << id end def cleanup called(:cleanup) raise "cleanup" end cleanup def custom_cleanup_method0 called(:custom_cleanup_method0) raise "custom_cleanup_method0" end cleanup do called(:custom_cleanup_callback0) raise "custom_cleanup_callback0" end cleanup def custom_cleanup_method1 called(:custom_cleanup_method1) raise "custom_cleanup_method1" end cleanup do called(:custom_cleanup_callback1) raise "custom_cleanup_callback1" end def test_nothing end end assert_called_fixtures([:custom_cleanup_callback1], test_case) end private def assert_cleanup_customizable(expected, parent, options) test_case = Class.new(parent || Test::Unit::TestCase) do yield(self, :before) if block_given? def called_ids @called_ids ||= [] end def called(id) called_ids << id end def cleanup called(:cleanup) end cleanup(*(options[0] || [])) if options def custom_cleanup_method0 called(:custom_cleanup_method0) end if options cleanup(*(options[0] || [])) do called(:custom_cleanup_callback0) end end def custom_cleanup_method1 called(:custom_cleanup_method1) end cleanup(*[:custom_cleanup_method1, *(options[1] || [])]) if options if options cleanup(*(options[1] || [])) do called(:custom_cleanup_callback1) end end cleanup(*(options[2] || [])) if options def custom_cleanup_method2 called(:custom_cleanup_method2) end unregister_cleanup(:custom_cleanup_method2) if options if options callback = lambda do called(:custom_cleanup_callback2) end cleanup(*(options[2] || []), &callback) unregister_cleanup(callback) end cleanup(*(options[3] || [])) if options def custom_cleanup_method3 called(:custom_cleanup_method3) end if options cleanup(*(options[3] || [])) do called(:custom_cleanup_callback3) end end def test_nothing end yield(self, :after) if block_given? end assert_called_fixtures(expected, test_case) test_case end def assert_cleanup(expected, options) assert_cleanup_customizable(expected, nil, options) assert_cleanup_customizable(expected, nil, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end end def assert_inherited_cleanup(expected, parent, options=nil) assert_cleanup_customizable(expected, parent, options) assert_cleanup_customizable(expected, parent, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end end def assert_invalid_cleanup_option(option) assert_invalid_option(:cleanup, option) end end class TestTeardown < self def test_without_option expected_teardown_calls = [:custom_teardown_callback3, :custom_teardown_method3, :custom_teardown_callback1, :custom_teardown_method1, :custom_teardown_callback0, :custom_teardown_method0, :teardown] test_case = assert_teardown(expected_teardown_calls, []) assert_inherited_teardown(expected_teardown_calls, test_case) assert_inherited_teardown([:teardown], nil) assert_called_fixtures(expected_teardown_calls, test_case) end def test_with_before_option expected_teardown_calls = [:custom_teardown_callback3, :custom_teardown_method3, :custom_teardown_method0, :custom_teardown_callback0, :custom_teardown_method1, :custom_teardown_callback1, :teardown] test_case = assert_teardown(expected_teardown_calls, [[{:before => :append}], [{:before => :append}], [{:before => :prepend}], [{:before => :prepend}]]) assert_inherited_teardown(expected_teardown_calls, test_case) assert_inherited_teardown([:teardown], nil) assert_called_fixtures(expected_teardown_calls, test_case) end def test_with_after_option expected_teardown_calls = [:teardown, :custom_teardown_callback3, :custom_teardown_method3, :custom_teardown_method0, :custom_teardown_callback0, :custom_teardown_method1, :custom_teardown_callback1] test_case = assert_teardown(expected_teardown_calls, [[{:after => :append}], [{:after => :append}], [{:after => :prepend}], [{:after => :prepend}]]) assert_inherited_teardown(expected_teardown_calls, test_case) assert_inherited_teardown([:teardown], nil) assert_called_fixtures(expected_teardown_calls, test_case) end def test_with_invalid_option assert_invalid_teardown_option(:unknown => true) assert_invalid_teardown_option(:before => :unknown) assert_invalid_teardown_option(:after => :unknown) end def test_with_option_to_inherited expected_teardown_calls = [:teardown] test_case = assert_teardown(expected_teardown_calls, nil) assert_inherited_teardown([:custom_teardown_callback3, :custom_teardown_method3, :custom_teardown_callback1, :custom_teardown_method1, :custom_teardown_callback0, :custom_teardown_method0, :teardown], test_case, []) assert_inherited_teardown([:teardown], nil) assert_called_fixtures(expected_teardown_calls, test_case) end def test_with_exception test_case = Class.new(Test::Unit::TestCase) do def called_ids @called_ids ||= [] end def called(id) called_ids << id end def teardown called(:teardown) raise "teardown" end teardown def custom_teardown_method0 called(:custom_teardown_method0) raise "custom_teardown_method0" end teardown do called(:custom_teardown_callback0) raise "custom_teardown_callback0" end teardown def custom_teardown_method1 called(:custom_teardown_method1) raise "custom_teardown_method1" end teardown do called(:custom_teardown_callback1) raise "custom_teardown_callback1" end def test_nothing end end assert_called_fixtures([:custom_teardown_callback1, :custom_teardown_method1, :custom_teardown_callback0, :custom_teardown_method0, :teardown], test_case) end def test_nested called = [] parent_test_case = Class.new(Test::Unit::TestCase) do teardown do called << :parent end end child_test_case = Class.new(parent_test_case) do teardown do called << :child end def test_nothing end end run_test_nothing(child_test_case) assert_equal([:child, :parent], called) end def test_setup_with_block test_case = Class.new(Test::Unit::TestCase) do def called_ids @called_ids ||= [] end def called(id) called_ids << id end setup def setup1 called(:setup1) begin yield called(:setup1_after_yield) ensure called(:setup1_teardown) end end setup def setup2 called(:setup2) begin yield called(:setup2_after_yield) ensure called(:setup2_teardown) end end def teardown called(:teardown) end def test_nothing called(:test) flunk called(:test_after_failure) end end assert_called_fixtures([ :setup1, :setup2, :test, :setup2_teardown, :setup1_teardown, :teardown, ], test_case) end private def assert_teardown_customizable(expected, parent, options) test_case = Class.new(parent || Test::Unit::TestCase) do yield(self, :before) if block_given? def called_ids @called_ids ||= [] end def called(id) called_ids << id end def teardown called(:teardown) end teardown(*(options[0] || [])) if options def custom_teardown_method0 called(:custom_teardown_method0) end if options teardown(*(options[0] || [])) do called(:custom_teardown_callback0) end end def custom_teardown_method1 called(:custom_teardown_method1) end teardown(*[:custom_teardown_method1, *(options[1] || [])]) if options if options teardown(*(options[1] || [])) do called(:custom_teardown_callback1) end end teardown(*(options[2] || [])) if options def custom_teardown_method2 called(:custom_teardown_method2) end unregister_teardown(:custom_teardown_method2) if options if options callback = lambda do called(:custom_teardown_callback2) end teardown(*(options[2] || []), &callback) unregister_teardown(callback) end teardown(*(options[3] || [])) if options def custom_teardown_method3 called(:custom_teardown_method3) end if options teardown(*(options[3] || [])) do called(:custom_teardown_callback3) end end def test_nothing end yield(self, :after) if block_given? end assert_called_fixtures(expected, test_case) test_case end def assert_teardown(expected, options) assert_teardown_customizable(expected, nil, options) assert_teardown_customizable(expected, nil, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end end def assert_inherited_teardown(expected, parent, options=nil) assert_teardown_customizable(expected, parent, options) assert_teardown_customizable(expected, parent, options) do |test_case, tag| test_case.send(:include, EmptyModule) if tag == :before end end def assert_invalid_teardown_option(option) assert_invalid_option(:teardown, option) end end private def run_test_nothing(test_case) test = test_case.new("test_nothing") test.run(Test::Unit::TestResult.new) {} test end def assert_called_fixtures(expected, test_case) test = run_test_nothing(test_case) assert_equal(expected, test.called_ids) end def assert_invalid_option(fixture_type, option) exception = assert_raise(ArgumentError) do Class.new(Test::Unit::TestCase) do def test_nothing end send(fixture_type, option) def fixture end end end assert_equal("must be {:before => :prepend}, {:before => :append}, " + "{:after => :prepend} or {:after => :append}" + ": #{option.inspect}", exception.message) end end PKu]?"= = %test-unit-3.3.4/test/test-omission.rbnu[require 'test/unit' require 'testunit-test-util' class TestUnitOmission < Test::Unit::TestCase include TestUnitTestUtil class TestCase < Test::Unit::TestCase class << self def suite Test::Unit::TestSuite.new(name) end end def test_omit omit("1st omit") omit("2nd omit. Should not be reached here.") assert(true, "Should not be reached here too.") end def test_omit_with_condition omit_if(false, "Never omit.") omit_unless(true, "Never omit too.") omit_if(true, "Should omit.") omit("The last omit. Should not be reached here.") end def test_omit_with_block omit("Omit block") do flunk("Should not be reached here.") end assert(true, "Should be reached here.") end def test_omit_with_block_and_condition omit_if(false, "Never omit.") do assert(true, "Should be reached here.") end omit_if(true, "Should omit.") do flunk("Never reached here.") end assert(true, "Should be reached here too.") end end def test_omit result = _run_test("test_omit") assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, " \ "1 omissions, 0 notifications", result.to_s) assert_fault_messages(["1st omit"], result.omissions) end def test_omit_with_condition result = _run_test("test_omit_with_condition") assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, " \ "1 omissions, 0 notifications", result.to_s) assert_fault_messages(["Should omit."], result.omissions) end def test_omit_with_block result = _run_test("test_omit_with_block") assert_equal("1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, " \ "1 omissions, 0 notifications", result.to_s) assert_fault_messages(["Omit block"], result.omissions) end def test_omit_with_condition_and_block result = _run_test("test_omit_with_block_and_condition") assert_equal("1 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, " \ "1 omissions, 0 notifications", result.to_s) assert_fault_messages(["Should omit."], result.omissions) end private def _run_test(name) super(TestCase, name) end end PKu]q$G;H;H!test-unit-3.3.4/test/test-diff.rbnu[class TestUnitDiff < Test::Unit::TestCase def test_binary_search_ranges assert_found_binary_search_ranges(5, [1..2, 4..5, 7..9]) assert_not_found_binary_search_ranges(3, [1..2, 4..5, 7..9]) end def test_to_indexes assert_to_indexes({"abc def" => [0, 2], "abc" => [1]}, ["abc def", "abc", "abc def"]) assert_to_indexes({?a => [0, 3], ?b => [1], ?c => [2], ?d => [4]}, "abcad") assert_to_indexes({ ?1 => [0, 35], ?t => [2, 5, 16], ?e => [3, 14, 31, 38], ?s => [4, 6, 12, 13, 20, 32, 44], ?, => [7, 21, 33], ?0 => [9, 23], ?a => [11, 26], ?r => [15, 30], ?i => [17, 27, 41], ?o => [18], ?n => [19, 39, 42], ?f => [25], ?l => [28], ?u => [29], ?p => [37], ?d => [40], ?g => [43], }, "1 tests, 0 assertions, 0 failures, 1 pendings") do |x| x == " "[0] end end def test_longest_match assert_longest_match([0, 1, 3], %w(b c d), %w(a b c d x y z), 0, 2, 0, 7) assert_longest_match([1, 2, 2], %w(b c d), %w(a b c d x y z), 1, 2, 0, 6) assert_longest_match([0, 0, 0], %w(a b), %w(c), 0, 1, 0, 0) assert_longest_match([1, 0, 2], %w(q a b x c d), %w(a b y c d f), 0, 5, 0, 5) assert_longest_match([4, 3, 2], %w(q a b x c d), %w(a b y c d f), 3, 5, 2, 5) assert_longest_match([1, 0, 2], "qabxcd", "abycdf", 0, 5, 0, 5) assert_longest_match([0, 0, 1], "efg", "eg", 0, 2, 0, 1) assert_longest_match([2, 1, 1], "efg", "eg", 1, 2, 1, 1) end def test_longest_match_with_junk_predicate assert_longest_match([0, 4, 5], " abcd", "abcd abcd", 0, 4, 0, 8) assert_longest_match([1, 0, 4], " abcd", "abcd abcd", 0, 4, 0, 8) do |x| x == ' '[0] end end def test_matches assert_matches([[0, 0, 2], [3, 2, 2]], %w(a b x c d), %w(a b c d)) assert_matches([[1, 0, 2], [4, 3, 2]], %w(q a b x c d), %w(a b y c d f)) assert_matches([[1, 0, 2], [4, 3, 2]], "qabxcd", "abycdf") assert_matches([[0, 0, 1], [2, 1, 1]], "efg", "eg") end def test_matches_with_junk_predicate assert_matches([[0, 0, 23], [24, 24, 11], [36, 36, 9]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") assert_matches([[0, 0, 1], [1, 1, 8], [9, 9, 1], [10, 10, 13], [24, 24, 11], [36, 36, 9]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") do |x| x == " "[0] end end def test_blocks assert_blocks([[0, 0, 2], [3, 2, 2], [5, 4, 0]], %w(a b x c d), %w(a b c d)) assert_blocks([[1, 0, 2], [4, 3, 2], [6, 6, 0]], %w(q a b x c d), %w(a b y c d f)) assert_blocks([[1, 0, 2], [4, 3, 2], [6, 6, 0]], "qabxcd", "abycdf") assert_blocks([[0, 0, 1], [2, 1, 1], [3, 2, 0]], "efg", "eg") end def test_blocks_with_junk_predicate assert_blocks([[0, 0, 23], [24, 24, 11], [36, 36, 9], [45, 45, 0]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") do |x| x == " "[0] end end def test_operations assert_operations([], %w(), %w()) assert_operations([[:delete, 0, 1, 0, 0], [:equal, 1, 3, 0, 2], [:replace, 3, 4, 2, 3], [:equal, 4, 6, 3, 5], [:insert, 6, 6, 5, 6]], %w(q a b x c d), %w(a b y c d f)) assert_operations([[:delete, 0, 1, 0, 0], [:equal, 1, 3, 0, 2], [:replace, 3, 4, 2, 3], [:equal, 4, 6, 3, 5], [:insert, 6, 6, 5, 6]], "qabxcd", "abycdf") assert_operations([[:equal, 0, 23, 0, 23], [:replace, 23, 24, 23, 24], [:equal, 24, 35, 24, 35], [:replace, 35, 36, 35, 36], [:equal, 36, 45, 36, 45]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") assert_operations([[:equal, 0, 23, 0, 23], [:replace, 23, 24, 23, 24], [:equal, 24, 35, 24, 35], [:replace, 35, 36, 35, 36], [:equal, 36, 45, 36, 45]], "1 tests, 0 assertions, 1 failures, 0 pendings", "1 tests, 0 assertions, 0 failures, 1 pendings") do |x| x == " "[0] end end def test_grouped_operations assert_grouped_operations([[[:equal, 0, 0, 0, 0]]], %w(), %w()) assert_grouped_operations([[[:equal, 0, 3, 0, 3]]], %w(a b c), %w(a b c)) assert_grouped_operations([[[:equal, 0, 1, 0, 1], [:replace, 1, 2, 1, 2], [:equal, 2, 5, 2, 5]], [[:equal, 8, 11, 8, 11], [:replace, 11, 12, 11, 12], [:equal, 12, 13, 12, 13], [:delete, 13, 16, 13, 13], [:equal, 16, 17, 13, 14], [:replace, 17, 18, 14, 15], [:equal, 18, 20, 15, 17]]], %w(1 2 3 4 5 6 7 8 9 a b c d e f g h i j k), %w(1 i 3 4 5 6 7 8 9 a b cX d h iX j k)) end def test_ratio assert_ratio(0.75, "abcd", "bcde") assert_ratio(0.80, "efg", "eg") end def test_1_length_readable_diff differ = Test::Unit::Diff::ReadableDiffer.new(["0"], ["1"]) def differ.cut_off_ratio 0 end def differ.default_ratio 0 end assert_equal("- 0\n" + "? ^\n" + "+ 1\n" + "? ^", differ.diff.join("\n")) end def test_same_contents_readable_diff assert_readable_diff(" aaa", ["aaa"], ["aaa"]) assert_readable_diff(" aaa\n" \ " bbb", ["aaa", "bbb"], ["aaa", "bbb"]) end def test_deleted_readable_diff assert_readable_diff(" aaa\n" \ "- bbb", ["aaa", "bbb"], ["aaa"]) assert_readable_diff(" aaa\n" \ "- bbb\n" \ "- ccc\n" \ "- ddd", ["aaa", "bbb", "ccc", "ddd"], ["aaa"]) end def test_inserted_readable_diff assert_readable_diff(" aaa\n" \ "+ bbb\n" \ "+ ccc\n" \ "+ ddd", ["aaa"], ["aaa", "bbb", "ccc", "ddd"]) end def test_replace_readable_diff assert_readable_diff(" aaa\n" \ "- bbb\n" \ "+ BbB\n" \ " ccc\n" \ "- ddd\n" \ "- efg\n" \ "? -\n" \ "+ eg", ["aaa", "bbb", "ccc", "ddd", "efg"], ["aaa", "BbB", "ccc", "eg"]) assert_readable_diff("- abcd xyz abc\n" \ "? -\n" \ "+ abcd abcd xyz abc\n" \ "? +++++", [" abcd xyz abc"], ["abcd abcd xyz abc"]) end def test_difference_readable_diff assert_readable_diff("- 1 tests, 0 assertions, 1 failures, 0 pendings\n" \ "? ^ ^\n" \ "+ 1 tests, 0 assertions, 0 failures, 1 pendings\n" \ "? ^ ^", ["1 tests, 0 assertions, 1 failures, 0 pendings"], ["1 tests, 0 assertions, 0 failures, 1 pendings"]) end def test_complex_readable_diff assert_readable_diff(" aaa\n" \ "- bbb\n" \ "- ccc\n" \ "+ \n" \ "+ # \n" \ " ddd", ["aaa", "bbb", "ccc", "ddd"], ["aaa", "", " # ", "ddd"]) assert_readable_diff("- one1\n" \ "? ^\n" \ "+ ore1\n" \ "? ^\n" \ "- two2\n" \ "- three3\n" \ "? - -\n" \ "+ tree\n" \ "+ emu", ["one1", "two2", "three3"], ["ore1", "tree", "emu"]) end def test_empty_readable_diff assert_readable_diff("", [""], [""]) end def test_unified_diff assert_unified_diff("", ["one", "two", "three"], ["one", "two", "three"], "content 1", "content 2") assert_unified_diff("--- Original Sat Jan 26 23:30:50 1991\n" \ "+++ Current Fri Jun 06 10:20:52 2003\n" \ "@@ -1,4 +1,4 @@\n" \ "+zero\n" \ " one\n" \ "-two\n" \ "-three\n" \ "+tree\n" \ " four", ["one", "two", "three", "four"], ["zero", "one", "tree", "four"], "Original Sat Jan 26 23:30:50 1991", "Current Fri Jun 06 10:20:52 2003", :show_context => false) from = File.read(__FILE__).split(/\n/) to = from.dup target_line = __LINE__ to[target_line - 1, 1] = [] context = " def test_unified_diff" summary = "@@ -#{target_line - 3},7 +#{target_line - 3},6 @@ #{context}" assert_unified_diff((["--- revision 10", "+++ revision 11", summary] + from[target_line - 4, 3].collect {|line| " #{line}"} + ["-#{from[target_line - 1]}"] + from[target_line, 3].collect {|line| " #{line}"} ).join("\n"), from, to, "revision 10", "revision 11") end def test_empty_unified_diff assert_unified_diff("", [""], [""], "From", "To") assert_unified_diff("", [], [], "From", "To") end def test_diff_lines assert_diff_lines(["- ddd", "- efg", "? -", "+ eg"], ["aaa", "bbb", "ccc", "ddd", "efg"], ["aaa", "BbB", "ccc", "eg"], 3, 5, 3, 4) end def test_diff_line assert_diff_line(["- abcDefghiJkl", "? ^ ^ ^", "+ abcdefGhijkl", "? ^ ^ ^"], "abcDefghiJkl", "abcdefGhijkl") assert_diff_line(["- bcDefghiJklx", "? ^ ^ ^ -", "+ abcdefGhijkl", "? + ^ ^ ^"], "bcDefghiJklx", "abcdefGhijkl") end def test_empty_diff_line assert_diff_line(["- ", "+ "], "", "") end def test_format_diff_point assert_format_diff_point(["- \tabcDefghiJkl", "? \t ^ ^ ^", "+ \t\tabcdefGhijkl", "? \t ^ ^ ^"], "\tabcDefghiJkl", "\t\tabcdefGhijkl", " ^ ^ ^ ", "+ ^ ^ ^ ") assert_format_diff_point(["- efg", "? ^", "+ eg"], "efg", "eg", " ^", "") end def test_interesting_line from = ["class X", " def find(x=0)", " body", " end", "end"] to = ["def xxx", " raise 'not call me'", "end"] assert_interesting_line(" def find(x=0)", from, to, 2, 1) assert_interesting_line("def xxx", from, to, 2, 0) assert_interesting_line("class X", from, to, 0, 0) end private def assert_found_binary_search_ranges(numeric, ranges) assert_true(Test::Unit::Diff::UTF8Line.send(:binary_search_ranges, numeric, ranges)) end def assert_not_found_binary_search_ranges(numeric, ranges) assert_false(Test::Unit::Diff::UTF8Line.send(:binary_search_ranges, numeric, ranges)) end def assert_to_indexes(expected, to, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new([""], to, &junk_predicate) assert_equal(expected, matcher.instance_variable_get("@to_indexes")) end def assert_find_best_match_position(expected, from, to, from_start, from_end, to_start, to_end, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.send(:find_best_match_position, from_start, from_end, to_start, to_end)) end def assert_longest_match(expected, from, to, from_start, from_end, to_start, to_end, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.longest_match(from_start, from_end, to_start, to_end)) end def assert_matches(expected, from, to, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.send(:matches)) end def assert_blocks(expected, from, to, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.blocks) end def assert_operations(expected, from, to, &junk_predicate) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to, &junk_predicate) assert_equal(expected, matcher.operations) end def assert_grouped_operations(expected, from, to) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to) assert_equal(expected, matcher.grouped_operations) end def assert_ratio(expected, from, to) matcher = Test::Unit::Diff::SequenceMatcher.new(from, to) assert_in_delta(expected, 0.001, matcher.ratio) end def assert_readable_diff(expected, from, to) assert_equal(expected, Test::Unit::Diff.readable(from.join("\n"), to.join("\n"))) end def assert_unified_diff(expected, from, to, from_label, to_label, options={}) options = options.merge(:from_label => from_label, :to_label => to_label) assert_equal(expected, Test::Unit::Diff.unified(from.join("\n"), to.join("\n"), options)) end def assert_diff_lines(expected, from, to, from_start, from_end, to_start, to_end) differ = Test::Unit::Diff::ReadableDiffer.new(from, to) result = [] differ.instance_variable_set("@result", result) differ.send(:diff_lines, from_start, from_end, to_start, to_end) assert_equal(expected, result) end def assert_diff_line(expected, from_line, to_line) differ = Test::Unit::Diff::ReadableDiffer.new([""], [""]) result = [] differ.instance_variable_set("@result", result) differ.send(:diff_line, from_line, to_line) assert_equal(expected, result) end def assert_format_diff_point(expected, from_line, to_line, from_tags, to_tags) differ = Test::Unit::Diff::ReadableDiffer.new([""], [""]) result = [] differ.instance_variable_set("@result", result) differ.send(:format_diff_point, from_line, to_line, from_tags, to_tags) assert_equal(expected, result) end def assert_interesting_line(expected, from, to, from_start, to_start) differ = Test::Unit::Diff::UnifiedDiffer.new(from, to) assert_equal(expected, differ.send(:find_interesting_line, from_start, to_start, :define_line?)) end end PKu]X_.test-unit-3.3.4/test/test-attribute-matcher.rbnu[require 'test/unit' require 'testunit-test-util' class TestAttributeMatcher < Test::Unit::TestCase include TestUnitTestUtil def setup @test = {} @matcher = Test::Unit::AttributeMatcher.new(@test) end def test_nonexistent assert_false(@matcher.match?("nonexistent")) end def test_existent @test[:existent] = true assert_true(@matcher.match?("existent")) end def test_and @test[:slow] = true @test[:important] = true assert_true(@matcher.match?("important and slow")) end def test_complex @test[:tags] = [:slow, :web] @test[:bug] = "2929" assert_true(@matcher.match?("tags.include?(:web) or bug == '29'")) end def test_exception assert_raise(NoMethodError) do @matcher.match?("nonexistent > 100") end end end PKu]Fill test-unit-3.3.4/test/run-test.rbnu[#!/usr/bin/env ruby $VERBOSE = true $KCODE = "utf8" unless "".respond_to?(:encoding) base_dir = File.expand_path(File.join(File.dirname(__FILE__), "..")) lib_dir = File.join(base_dir, "lib") test_dir = File.join(base_dir, "test") $LOAD_PATH.unshift(lib_dir) require 'test/unit' test_unit_notify_base_dir = File.join(base_dir, "..", "test-unit-notify") test_unit_notify_base_dir = File.expand_path(test_unit_notify_base_dir) if File.exist?(test_unit_notify_base_dir) $LOAD_PATH.unshift(File.join(test_unit_notify_base_dir, "lib")) require 'test/unit/notify' end exit Test::Unit::AutoRunner.run(true, test_dir) PKu]7w00/test-unit-3.3.4/test/ui/test_testrunmediator.rbnu[require 'test/unit/ui/testrunnermediator' class TestUnitUIMediator < Test::Unit::TestCase def test_run_suite_with_interrupt_exception test_case = Class.new(Test::Unit::TestCase) do def test_raise_interrupt raise Interrupt, "from test" end end mediator = Test::Unit::UI::TestRunnerMediator.new(test_case.suite) finished = false mediator.add_listener(Test::Unit::UI::TestRunnerMediator::FINISHED) do finished = true end assert_raise(Interrupt) do mediator.run end assert(finished) end end PKu]f*k test-unit-3.3.4/README.mdnu[# test-unit [![](https://badge.fury.io/rb/test-unit.svg)](http://badge.fury.io/rb/test-unit) [![](https://travis-ci.org/test-unit/test-unit.svg?branch=master)](https://travis-ci.org/test-unit/test-unit) * http://test-unit.github.io/ * https://github.com/test-unit/test-unit ## Description An xUnit family unit testing framework for Ruby. test-unit (Test::Unit) is unit testing framework for Ruby, based on xUnit principles. These were originally designed by Kent Beck, creator of extreme programming software development methodology, for Smalltalk's SUnit. It allows writing tests, checking results and automated testing in Ruby. ## Features * test-unit 1.2.3 is the original test-unit, taken straight from the ruby distribution. It is being distributed as a gem to allow tool builders to use it as a stand-alone package. (The test framework in ruby is going to radically change very soon). * test-unit will be improved actively and may break compatiblity with test-unit 1.2.3. (We will not hope it if it isn't needed.) * Some features exist as separated gems like GUI test runner. (Tk, GTK+ and Fox) test-unit-full gem package provides for installing all test-unit related gems easily. ## How To * [How To](https://github.com/test-unit/test-unit/blob/master/doc/text/how-to.md) (link for GitHub) * {file:doc/text/how-to.md How To} (link for YARD) ## Install
    % sudo gem install test-unit
    
    If you want to use full test-unit features:
    % sudo gem install test-unit-full
    
    ## License (The Ruby License) This software is distributed under the same terms as ruby. Exception: * lib/test/unit/diff.rb is a triple license of the Ruby license, PSF license and LGPLv2.1 or later. * lib/test-unit.rb is a dual license of the Ruby license and LGPLv2.1 or later. ## Authors ### Active * Kouhei Sutou: The current maintainer * Haruka Yoshihara: Data driven test supports. ### Inactive * Nathaniel Talbott: The original author * Ryan Davis: The second maintainer ### Images * Mayu & Co.: kinotan icons ## Thanks * Daniel Berger: Suggestions and bug reports. * Designing Patterns: Suggestions. * Erik Hollensbe: Suggestions and bug reports. * Bill Lear: A suggestion. * Diego Pettenò: A bug report. * Angelo Lakra: A bug report. * Mike Pomraning: A bug report. * David MARCHALAND: Suggestions and bug reports. * Andrew Grimm: A bug report. * Champak Ch: A bug report. * Florian Frank: A bug report. * grafi-tt: Bug fixes and reports. * Jeremy Stephens: A bug report. * Hans de Graaff: Bug reports. * James Mead: A bug report. * Marc Seeger (Acquia): A bug report. * boutil: A bug report. * Vladislav Rassokhin: A bug report. PKu]>X"Vggtest-unit-3.3.4/LGPLnu[ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! PKu]vm test-unit-3.3.4/COPYINGnu[test-unit is copyrighted free software by Kouhei Sutou , Ryan Davis and Nathaniel Talbott . You can redistribute it and/or modify it under either the terms of the GPL version 2 (see the file GPL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Exceptions ---------- * lib/test/unit/diff.rb: This license, PSF license and/or LGPLv2.1 or later * lib/test-unit.rb: This license and/or LGPLv2.1 or later PKu]oc$test-unit-3.3.4/sample/test_adder.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require_relative 'adder' class TestAdder < Test::Unit::TestCase def setup @adder = Adder.new(5) end def test_add assert_equal(7, @adder.add(2), "Should have added correctly") end def teardown @adder = nil end end PKu]c: test-unit-3.3.4/sample/adder.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. class Adder def initialize(number) @number = number end def add(number) @number + number end end PKu]d@)test-unit-3.3.4/sample/test_subtracter.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require_relative 'subtracter' class TestSubtracter < Test::Unit::TestCase def setup @subtracter = Subtracter.new(5) end def test_subtract assert_equal(3, @subtracter.subtract(2), "Should have subtracted correctly") end def teardown @subtracter = nil end end PKu]/jj#test-unit-3.3.4/sample/test_user.rbnu[# nested test case example. require 'test/unit' class UserTest < Test::Unit::TestCase def setup @user = "me" end def test_full_name assert_equal("me", @user) end class ProfileTest < UserTest setup def setup_profile @user += ": profile" end def test_has_profile assert_match(/: profile/, @user) end end end PKu]Z$test-unit-3.3.4/sample/subtracter.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. class Subtracter def initialize(number) @number = number end def subtract(number) @number - number end end PKu]$yӱ"test-unit-3.3.4/doc/text/how-to.mdnu[# How To ## Run all tests To make it easy to run all your tests, you can add a `run_test.rb` script to your `test` directory. A simple example might look like: base_dir = File.expand_path(File.join(File.dirname(__FILE__), "..")) lib_dir = File.join(base_dir, "lib") test_dir = File.join(base_dir, "test") $LOAD_PATH.unshift(lib_dir) require 'test/unit' exit Test::Unit::AutoRunner.run(true, test_dir) Then it's easy to run tests via the command line with, $ ruby test/run_test.rb ## Change test runner via the command line The output format can be changed via the command line with the `--runner` option. Simply tack it to the end: ruby test/run_test.rb --runner tap ## Configure test-unit per-project Test::Unit reads `test-unit.yml` or `.test-unit.yml` in the current working directory as Test::Unit's configuration file. It can contain the following settings: * color scheme definitions * test runner to be used * test runner options * test collector to be used Except color scheme definitions, all of them can be specified by command line option. Here are sample color scheme definitions: color_schemes: inverted: success: name: red bold: true failure: name: green bold: true other_scheme: ... Here are the syntax of color scheme definitions: color_schemes: SCHEME_NAME: EVENT_NAME: name: COLOR_NAME intensity: BOOLEAN bold: BOOLEAN italic: BOOLEAN underline: BOOLEAN ... ... | Definition | Description | |-------------|------------------------------| | SCHEME_NAME | the name of the color scheme | | EVENT_NAME | success, failure, pending, omission, notification, error | | COLOR_NAME | black, red, green, yellow, blue, magenta, cyan, white | | BOOLEAN | true or false | You can use the above 'inverted' color scheme with the following configuration: runner: console console_options: color_scheme: inverted color_schemes: inverted: success: name: red bold: true failure: name: green bold: true PKu]@J? test-unit-3.3.4/doc/text/news.mdnu[# News ## 3.3.4 - 2019-09-30 {#version-3-3-4} ### Improvements * Converted markup format to Markdown from RDoc. [GitHub#164][Patch by OGAWA KenIchi] * test: Stopped to depend on `Time#inspect` format. [GitHub#165][Reported by Benoit Daloze] ### Thanks * OGAWA KenIchi * Benoit Daloze ## 3.3.3 - 2019-05-10 {#version-3-3-3} ### Fixed * Fixed a bug that priority mode with test case name that uses special characters such as `?` can't be used on Windows. ## 3.3.2 - 2019-04-11 {#version-3-3-2} ### Fixes * Fixed a bug that `Test::Unit::Collector::Load` doesn't load test files under sub directories when these files have the same base name as test files in upper directories. [Reported by Kenta Murata] ### Thanks * Kenta Murata ## 3.3.1 - 2019-03-27 {#version-3-3-1} ### Improvements * Added support for `Test::Unit::AssertionFailedError#user_message` for not only `assert_equal` and `assert_raise` but also all assertions. [GitHub#162][Reported by xgraffm] ### Thanks * xgraffm ## 3.3.0 - 2019-01-23 {#version-3-3-0} ### Improvements * Added support for auto test run when all tests are defined in modules. * Added support for defining methods to test case class in multiple threads. [GitHub#159][Reported by Charles Oliver Nutter] * Suppressed warnings on Ruby 2.5. [GitHub#160][Reported by Daniel Berger] * Suppressed warnings on Ruby 2.7. ### Fixes * Fixed a code snippet fetch failure when source code isn't UTF-8 and the default external encoding is set to not UTF-8. [GitHub#161][Reported by masa kunikata] ### Thanks * Charles Oliver Nutter * Daniel Berger * masa kunikata ## 3.2.9 - 2018-12-01 {#version-3-2-9} ### Improvements * Added support for data generation by method. `data_#{test_name}` is called to generate data for `test_name` test. * Added support for data matrix generation. Example: ```ruby data(:a, [0, 1, 2]) data(:b, [:x, :y]) def test_data(data) end ``` This example generates the following data matrix: * label: `"a: 0, b: :x"`, data: `{a: 0, b: :x}` * label: `"a: 0, b: :y"`, data: `{a: 0, b: :y}` * label: `"a: 1, b: :x"`, data: `{a: 1, b: :x}` * label: `"a: 1, b: :y"`, data: `{a: 1, b: :y}` * label: `"a: 2, b: :x"`, data: `{a: 2, b: :x}` * label: `"a: 2, b: :y"`, data: `{a: 2, b: :y}` * Added `Test::Unit::TestCase#data` that returns the current data. * Added support for using test method that doesn't have no parameters as data driven test. Example: ```ruby data("label", :value) def test_data # Available since this release p data # :value end ``` * Added support for `:keep` option to `Test::Unit::TestCase.data`. * Added support for `:group` option to `Test::Unit::TestCase.data`. It's useful to generate multiple data matrix groups. ```ruby # Group1 data(:a, [0, 1, 2], group: :g1) data(:b, [:x, :y], group: :g1) # Group2 data(:a, [:x, :y], group: :g2) data(:c, [-1, -2], group: :g2) def test_data(data) end ``` This example generates the following data matrix: * label: `"group: :g1, a: 0, b: :x"`, data: `{a: 0, b: :x}` * label: `"group: :g1, a: 0, b: :y"`, data: `{a: 0, b: :y}` * label: `"group: :g1, a: 1, b: :x"`, data: `{a: 1, b: :x}` * label: `"group: :g1, a: 1, b: :y"`, data: `{a: 1, b: :y}` * label: `"group: :g1, a: 2, b: :x"`, data: `{a: 2, b: :x}` * label: `"group: :g1, a: 2, b: :y"`, data: `{a: 2, b: :y}` * label: `"group: :g2, a: :x, b: -1"`, data: `{a: :x, b: -1}` * label: `"group: :g2, a: :x, b: -2"`, data: `{a: :x, b: -2}` * label: `"group: :g2, a: :y, b: -1"`, data: `{a: :y, b: -1}` * label: `"group: :g2, a: :y, b: -2"`, data: `{a: :y, b: -2}` ## 3.2.8 - 2018-05-13 {#version-3-2-8} ### Improvements * [UI][console]: Changed to put code snippet before backtrace on reverse mode. ## 3.2.7 - 2017-12-12 {#version-3-2-7} ### Improvements * Added source code link to gemspec. [GitHub#157][Patch by Grey Baker] * Changed to use SVG image for badges in README. [GitHub#158][Patch by Olle Jonsson] * [UI][console]: Added `--reverse-output` option to output fault details in reverse like Ruby 2.5. It's enabled by default only for tty output. ### Fixes * Fixed a typo. [GitHub#156][Patch by masa kunikata] * [UI][console]: Fixed a bug that broken align in verbose mode. ### Thanks * masa kunikata * Grey Baker * Olle Jonsson ## 3.2.6 - 2017-09-21 {#version-3-2-6} ### Improvements * Changed test file require failure to error from omission. [GitHub#154][Patch by naofumi-fujii] ### Thanks * naofumi-fujii ## 3.2.5 - 2017-06-24 {#version-3-2-5} ### Improvements * Supported `--enable-frozen-string-literal` `ruby` option. [GitHub#149][Reported by Pat Allan] ### Thanks * Pat Allan ## 3.2.4 - 2017-05-23 {#version-3-2-4} ### Improvements * Updated tests for Ruby 2.4. [GitHUb#136][Patch by Kazuki Tsujimoto] * Supported power\_assert 1.0.0. [GitHub#137][Patch by Kazuki Tsujimoto] * Added the getting started document. [GitHub#139][GitHub#141][Patch by Hiroyuki Sato] * Added the document for `attribute`. [GitHub#143][Patch by Fumiaki MATSUSHIMA] * Improved a link for GitHub. [GitHub#144][Patch by rochefort] * Updated `.travis.yml`. [GitHub#145][Patch by Jun Aruga] ### Fixes * Fixed a contributor name. [GitHub#131][Patch by Akira Matsuda] * Fixed typos in document. [GitHub#132][Patch by Akira Matsuda] * Fixed typos in document. [GitHub#134][Patch by Yuji Yaginuma] * Fixed a bug that data label with "(" isn't supported. [GitHub#135][Reported by Kazuki Tsujimoto] * Fixed assertion message in English. [GitHub#133][Reported by Khalil Fazal] * Fixed a typo in typo fix. [GitHub#138][Patch by kami] * Fixed a bug that target location finder may return wrong location. [GitHub#146][Patch by Yuki Ito] * Fixed a bug that `--no-show-detail-immediately` raises an error. [GitHub#147][Reported by MSP-Greg] ### Thanks * Akira Matsuda * Yuji Yaginuma * Kazuki Tsujimoto * Khalil Fazal * kami * Hiroyuki Sato * Fumiaki MATSUSHIMA * rochefort * Jun Aruga * Yuki Ito * MSP-Greg ## 3.2.3 - 2016-11-25 {#version-3-2-3} ### Fixes * Fixed a bug that `--order` isn't applied. [GitHub#129][Reported by Vít Ondruch] ### Thanks * Vít Ondruch ## 3.2.2 - 2016-11-02 {#version-3-2-2} ### Improvements * Improved Travis CI configuration. [GitHub#123][Patch by Ryunosuke Sato] * Supported Java native exception. [GitHub#126][Reported by Bob Saveland] ### Fixes * doc: Fixed markup. [GitHub#127][Patch by Tomohiro Hashidate] * Fixed a bug that `--location=LINE` may not detect a test when fixtures are defined before any tests: 1 class MyTestCase < Test::Unit::TestCase 2 setup do 3 end 4 5 test "xxx" do 6 end 7 end `--location=5` couldn't find the `xxx` test. [Reported by Ryota Sasabe] ### Thanks * Ryunosuke Sato * Tomohiro Hashidate * Bob Saveland * Ryota Sasabe ## 3.2.1 - 2016-07-19 {#version-3-2-1} ### Improvements * Clarified lib/test/unit/diff.rb license. It's a triple license of the Ruby license, PSF license and LGPLv2.1 or later. [Reported by Luisa Pace] * Reported norification when data driven test doesn't have parameter. [GitHub#122][Reported by Satoshi "Moris" Tagomori] ### Thanks * Luisa Pace * Satoshi "Moris" Tagomori ## 3.2.0 - 2016-06-12 {#version-3-2-0} ### Improvements * Supported rxvt family terminals as color available terminals. [GitHub#121][Reported by Ippei Kishida] ### Thanks * Ippei Kishida ## 3.1.9 - 2016-05-20 {#version-3-1-9} ### Fixes * Fixed conflict with test-unit-power_assert. [GitHub#120][Patch by Kazuki Tsujimoto] * Fixed a bug that path in `$LOAD_PATH` may be removed. ### Thanks * Kazuki Tsujimoto ## 3.1.8 - 2016-03-19 {#version-3-1-8} ### Improvements * Added `--stop-on-failure` command line option. With this option, running test suite is stopped immediately when one test is failed or an error is raised in one test. ## 3.1.7 - 2016-01-17 {#version-3-1-7} ### Fixes * Added a missing require. ## 3.1.6 - 2016-01-17 {#version-3-1-6} It's a Ruby on Rails integration improvement release. ### Improvements * Filtered backtrace of power\_assert. [GitHub#114] * Improved performance to retrieve test defined location. * Improved performance to run fixtures in a test. * Supported running a test by `yield` in `setup`: Before: def setup @file = File.open("x") end def teardown @file.close end After: def setup File.open("x") do |file| @file = file yield end end * Added `--default-test-path` option that specifies the default path that has tests. * Made auto runner registration more lazily. Auto runner isn't registered automatically until user defines a test. In the previous releases, auto runner is registered automatically when user defines a test case. * Supported specifying a test by location in command line. For example, the following command line runs a test that is defined in /tmp/test_a.rb at line 10: % ruby -r test-unit -e run_test /tmp/test_a.rb:10 ### Fixes * Fixed a bug that test isn't ran. The test has the same name as data driven test that is defined in parent test case. [GitHub#115] ## 3.1.5 - 2015-10-09 {#version-3-1-5} It's a Rack integration improvement release. ### Improvements * Renamed experimental top-level `run` method to `run_test` method because `run` is conflicted with Rack. [GitHub#32][GitHub:basecamp/pow#303] [Reported by Yevhen Viktorov] ### Thanks * Yevhen Viktorov ## 3.1.4 - 2015-09-26 {#version-3-1-4} It's a minor improvement release. ### Improvements * Updated sample code. [GitHub#109][Patch by takiy33] * Updated .travis.yml. [GitHub#110][Patch by takiy33] * document: Added table header in how to document. [GitHub#111][Patch by takiy33] * Removed duplicated code. [GitHub#112][Patch by takiy33] * Removed needless encoding conversion in fetching code snippet. [GitHub#113][Patch by NARUSE, Yui] ### Thanks * takiy33 * NARUSE, Yui ## 3.1.3 - 2015-07-26 {#version-3-1-3} It's a bug fix release. ### Improvements * Removed unused `TODO` file. [GitHub#108][Patch by takiy33] ### Fixes * `--location`: Fixed a bug that `--location LINE` doesn't work when test script is specified as relative path. [Reported by TOMITA Masahiro] The following doesn't work: % ruby ./test.rb --location 10 The following works: % ruby test.rb --location 10 ### Thanks * takiy33 * TOMITA Masahiro ## 3.1.2 - 2015-06-09 {#version-3-1-2} It's command line option improvements fix release. ### Improvements * `--location`: Made path match rule more strict. [Suggested by kimura wataru] * Before: * If test defined path ends with the specified path, the test is matched. * After: * If base name of test defined path equals to the specified path, the test is matched. * If relative path of test defined path equals to the specified path, the test is matched. * If the specified path is absolute path and test defined path equals to the specified path, the test is matched. * `--pattern`: If the option is specified, the default patterns aren't used. In the earlier versions, both the default patterns and the specified patterns are used. [Suggested by kimura wataru] ### Thanks * kimura wataru ## 3.1.1 - 2015-05-29 {#version-3-1-1} It's a bug fix release. ### Fixes * Fixed a bug that `--location` detects tests not only in sub test case but also parent test case. [GitHub#105][Reported by wanabe] ### Thanks * wanabe ## 3.1.0 - 2015-05-28 {#version-3-1-0} It's a bug fix release. ### Improvements * [ui][console] Removed needless new line. ### Fixes * Fixed a bug that priority mode can't be used on Windows. [GitHub#95][Reported by Daniel Berger] * Fixed a homepage URL RubyGems spec. [GitHub#96][Patch by Masayoshi Takahashi] supported.) [GitHub#89][Patch by Aaron Stone] * Fixed a bug that shutdown hook isn't called when pass throw exception such as `Interrupt` is raised. [GitHub#98][Reported by jeremiahishere.] * Fixed typos in documents. [GitHub#100][Reported by scivola] [GitHub#102][GitHub#103][Patch by Masafumi Yokoyama] * Fixed a bug that the same name test isn't executed in sub test case. [GitHub#104][Reported by wanabe] ### Thanks * Daniel Berger * Masayoshi Takahashi * jeremiahishere * scivola * Masafumi Yokoyama * wanabe ## 3.0.9 - 2014-12-31 {#version-3-0-9} It's a release that improves colors. ### Improvements * Added a work around for Ruby 1.8. (Note: Ruby 1.8 isn't supported.) [GitHub#89][Patch by Aaron Stone] * Supported colorized output on Windows. [GitHub#90][Patch by usa] * Improved colorized output. http://www.a-k-r.org/d/2014-12.html#a2014_12_27_1 [Suggested by Tanaka Akira] ### Thanks * Aaron Stone * usa * Tanaka Akira ## 3.0.8 - 2014-12-12 {#version-3-0-8} It's a release that supports Ruby 2.2.0 preview2. ### Improvements * Added a link for YARD in README. [GitHub:test-unit.github.io#2][Reported by sunnyone] * Added description about "/PATTERN/" style value in auto runner usage. [GitHub#86][Suggested by sunnyone] * Supported Ruby 2.2.0 preview2 in `assert_throw` and `assert_nothing_thrown`. ### Fixes * Fixed a bug that error report is failed when source encoding and locale encoding are different. [GitHub#87][Reported by scivola] ### Thanks * sunnyone * scivola ## 3.0.7 - 2014-11-14 {#version-3-0-7} It's a minor update release. ### Fixes * Fixed a bug that teardown blocks aren't called with sub class to parent class order. [GitHub#85][Reported by TOMITA Masahiro] ### Thanks * TOMITA Masahiro ## 3.0.6 - 2014-11-09 {#version-3-0-6} It's a minor update release. ### Improvements * Improved code snippet location. [GitHub#84][Patch by Yuki Kurihara] ### Thanks * Yuki Kurihara ## 3.0.5 - 2014-11-08 {#version-3-0-5} It's a minor update release. ### Fixes * Fixed a bug that startup/shutdown of parent test case isn't called when the test case includes one or more modules. [GitHub#83][Reported by Chadderton Odwazny] ### Thanks * Chadderton Odwazny ## 3.0.4 - 2014-11-01 {#version-3-0-4} It's a minor update release. ### Improvements * Stopped to remove JRuby and Rubinius internal backtrace entries from backtrace on failure/error. [GitHub#82][Patch by Charles Oliver Nutter] ### Thanks * Charles Oliver Nutter ## 3.0.3 - 2014-10-29 {#version-3-0-3} It's a minor update release. ### Improvements * Improved `Test::Unit::TestCase.test` performance. 100 times faster. * Supported `Proc` for user message. [Sugested by Nobuyoshi Nakada] ### Fixes * Fixed markup in document. [GitHub#81][Patch by Masafumi Yokoyama] ### Thanks * Masafumi Yokoyama * Nobuyoshi Nakada ## 3.0.2 - 2014-10-15 {#version-3-0-2} It's a minor update release. ### Improvements * Supported broken `==` implementation. `==` implementation should be fixed but it's not work of test-unit. :< [GitHub#71][Reported by Emily] * [UI][console]: Accepted no message failure. [GitHub#66][Reported by Brian Tatnall] * Updated gem description. [GitHub#74][Patch by Vít Ondruch] * Updated GPL text. [GitHub#78][Patch by Vít Ondruch] ### Fixes * Removed needless executable bit from README file. [GitHub#79][Patch by Vít Ondruch] ### Thanks * Emily * Brian Tatnall * Vít Ondruch ## 3.0.1 - 2014-08-05 {#version-3-0-1} It's a minor update release. ### Improvements * Improved Ruby 1.8.7 support. Note that we don't support Ruby 1.8.7 actively. We just support if its support is painless. [GitHub#71][Patch by estolfo] ### Thanks * estolfo ## 3.0.0 - 2014-08-03 {#version-3-0-0} It's Power Assert supported release! ### Improvements * Improved Rubinius support. [Ryo Onodera] * Updated RR repository link. [GitHub#56][Patch by Kenichi Kamiya] * Added some minitest compatible assertions. We don't recommend using these assertions. They are just for migrating from minitest. [GitHub#57][Patch by Karol Bucek] * {Test::Unit::Assertions#refute} * {Test::Unit::Assertions#refute_predicate} * {Test::Unit::Assertions#refute_empty} * {Test::Unit::Assertions#assert_not_includes} * {Test::Unit::Assertions#refute_includes} * {Test::Unit::Assertions#assert_not_instance_of} * {Test::Unit::Assertions#refute_instance_of} * {Test::Unit::Assertions#assert_not_kind_of} * {Test::Unit::Assertions#refute_kind_of} * {Test::Unit::Assertions#assert_not_operator} * {Test::Unit::Assertions#refute_operator} * Improved code readability. [Suggested by Kenichi Kamiya] * Made license field in RubyGems parseable. [GitHub#60][Patch by Michael Grosser] * Improved test case match feature by `--testcase` and `--ignore-testcase` options. They also checks parent class names. * Made inspected representation of Numeric objects especially BigDecimal more readable. [GitHub#64][Reported by Byron Appelt] * Added badges for Traivs CI and RubyGems. [GitHub#65][Patch by Byron Appelt] * Supported Power Assert. You can use Power Assert with {Test::Unit::Assertions#assert} with block. See method document for details. We recommend using Power Assert for predicate method checks. For example, we recommend Power Assert rather than {Test::Unit::Assertions#assert_true}, {Test::Unit::Assertions#assert_predicate} and so on. We don't recommend using Power Assert for equality check assertion. {Test::Unit::Assertions#assert_equal} should be used for the case. [Kazuki Tsujimoto] ### Fixes * Fixed a bug that test case defined by block has wrong location. [GitHub#58][Patch by Narihiro Nakamura] * Fixed a bug that test methods defined in included modules in super-class are also collected. [GitHub#62][GitHub#63][Patch by Karol Bucek] ### Thanks * Ryo Onodera * Kenichi Kamiya * Karol Bucek * Narihiro Nakamura * Michael Grosser * Byron Appelt * Kazuki Tsujimoto ## 2.5.5 - 2013-05-18 {#version-2-5-5} It's Ruby 2.0.0 supported release! ### Improvements * Supported Ruby 2.0.0. [GitHub#54] [Reported by mtasaka] * Accepted screen-256color TERM as 256 colors available environment. [GitHub#55] [Reported by Tom Miller] ### Fixes * Fixed a typo in document. [GitHub#53] [Patch by Baptiste Fontaine] * Fixed a bug in {Test::Unit::Assertions#assert_in_epsilon}. It doesn't work as expected if expected value is negative value. [Ruby Bug #8317] [Reported by Nobuhiro IMAI] ### Thanks * Baptiste Fontaine * mtasaka * Tom Miller * Nobuhiro IMAI ## 2.5.4 - 2013-01-23 {#version-2-5-4} It's a bug fix release. ### Improvements * Added documents for data driven test functionality. * Added TSV support for data driven test functionality. * Support tag inspection on JRuby. ### Fixes * Fixed a bug. It is too slow to filter tests when there are many tests. [GitHub#46] * Accept anonymous test suite. [GitHub:#49] [Reported by Matthew Rudy Jacobs] ### Thanks * Matthew Rudy Jacobs ## 2.5.3 - 2012-11-28 {#version-2-5-3} It's a release for minitest compatibility and bug fix. ### Improvements * Supported diff in invalid encoding. * Added some assersion methods just for minitest compatibility. Added methods are assert_includes(), refute_*() and refute(). If you are test-unit user, please don't use them. [GitHub#40] [Suggested by Michael Grosser] * Added --attribute option to select target tests by attribute. [test-unit-users-en:00098] [Suggested by Piotr Nestorow] ### Fixes * Allowed use of test for inheritance in ActionController::TestCase. [GitHub#42] [Patch by David Rasch] * Ensured evaluating at_exit block in top level. In IRB context, exit() specifies irb_exit(). [test-unit-users-en:00089] [Reported by Daniel Berger] * Fixed a bug that decoration style description is ignored. "decoration style description" are using description method above "def test_name" or with Symbol specifying test_name. [GitHub#45] [Reported by Piotr Nestorow] ### Thanks * Michael Grosser * David Rasch * Daniel Berger * Piotr Nestorow ## 2.5.2 - 2012-08-29 {#version-2-5-2} It's an improvement release for tmtms. `--location` is a similar feature to `--line_number` in RSpec. `sub_test_case` is a similar feature to `context` in shoulda-context and RSpec. ### Improvements * Cleaned up tests. [GitHub#34] [Patch by Michael Grosser] * Added missing background color for 8 color environment. * Added workaround for NetBeans. [GitHub#38] [Reported by Marc Cooper] * Added `--location` command line option that selects target tests by test defined location. * Created sub test suite for each subclassed test case. * [ui][console] Supported nested test suites. * Added {Test::Unit.at_start} and {Test::Unit.at_exit} hooks that are run before/after all tests are run. [Good hook name is suggested by kdmsnr] * Improved code snippet target on failure. Test method is always used for code snippet target. [GitHub#39] [Suggested by Michael Grosser] * Added {Test::Unit::TestCase.sub_test_case} that creates sub test case. The sub test case name isn't limited Ruby's constant name rule. You can specify the sub test case name in free form. ### Thanks * Michael Grosser * Marc Cooper * kdmsnr ## 2.5.1 - 2012-07-05 {#version-2-5-1} It's a bug fix release. ### Improvements * Supported installing from GitHub. [GitHub#29] [Suggested by Michael Grosser] * Supported ActiveSupport::TestCase. [GitHub#30] [Reported by Michael Grosser] * [ui][console] Improved multiline falut message display. ### Fixes * [ui][console] Fixed a bug that expected and actual values are empty. [GitHub#31][GitHub#33] [Reported by Kendall Buchanan][Reported by Mathieu Martin] [Hinted by Michael Grosser] * Fixed a bug that .gemspec can't be loaded on LANG=C. [RubyForge#29595] [Reported by Jean-Denis Koeck] ### Thanks * Michael Grosser * Kendall Buchanan * Mathieu Martin * Jean-Denis Koeck ## 2.5.0 - 2012-06-06 {#version-2-5-0} It's a bug fix release. ### Fixes * Fixed a backward incompatibility of `TestUnitMediator#run_suite` introduced in 2.4.9. [GitHub#28] [Reported by Vladislav Rassokhin] ### Thanks * Vladislav Rassokhin ## 2.4.9 - 2012-06-03 {#version-2-4-9} It's a bug fix release. ### Improvements * `Test::Unit.run?` -> `Test::Unit::AutoRunner.need_auto_run?`. `Test::Unit.run?` is marked as deprecated but it is still available. * [experimental] Added top level "run" method for `"ruby -rtest-unit -e run test/test_*.rb"`. Is this API OK or dirty? * Made failure output more readable on no color mode. * Supported showing ASCII-8BIT diff in failure message. * [ui][console] Supported `ENV["TERM"] == "xterm-256color"` as color available terminal. [GitHub#26] [Reported by Michael Grosser] * [ui][console] Supported "-256color" suffix `ENV["TERM"]` terminal as 256 color supported terminal. ### Fixes * Fixed a bug that `--workdir` doesn't work. * Consumed processed command line parameters in `ARGV` as `--help` says. [RubyForge#29554] [Reported by Bob Saveland] * Added missing `require "test/unit/diff"`. [GitHub#25] [Reported by Stephan Kulow] ### Thanks * Bob Saveland * Stephan Kulow * Michael Grosser ## 2.4.8 - 2012-3-6 {#version-2-4-8} It's a bug fix release. ### Improvements * Delayed at_exit registration until Test::Unit is used. [GitHub:#21] [Reported by Jason Lunn] * Added workaround for test-spec. [GitHub:#22] [Reported by Cédric Boutillier] ### Fixes * Fixed an error on code snippet display on JRuby. [GitHub:#19][GitHub:#20] [Reported by Jørgen P. Tjernø][Patch by Junegunn Choi] ### Thanks * Jørgen P. Tjernø * Junegunn Choi * Jason Lunn ## 2.4.7 - 2012-2-10 {#version-2-4-7} It's a code snippet improvement release. ### Improvements * Supported code snippet display on all faults. ## 2.4.6 - 2012-2-9 {#version-2-4-6} It's a TAP runner separated release. ### Improvements * Moved TAP runner to test-unit-runner-tap gem from test-unit gem. * Supported code snippet display on failure. ## 2.4.5 - 2012-1-16 {#version-2-4-5} It's a failure message readability improvement release. ### Improvements * Removed needless information from exception inspected text on failure. It's for easy to read. * Supported custom inspector. ## 2.4.4 - 2012-1-2 {#version-2-4-4} It's a Rails integration improved release. ### Improvements * [ui][console] Don't break progress display when a test is failed. * [ui][console] Added markers betwen a failure detail message in progress to improve visibility. * [travis] Dropped Ruby 1.8.6 as a test target. [GitHub:#13] [Patch by Josh Kalderimis] * Supported expected value == 0 case in assert_in_epsilon. [RubyForge#29485] [Reported by Syver Enstad] * Supported a block style setup/teardown/cleanup. ### Thanks * Josh Kalderimis * Syver Enstad ## 2.4.3 - 2011-12-11 {#version-2-4-3} ### Improvements * Improved SimpleCov integration by stopping to modify `ARGV` in auto runner. [GitHub:#12] [Reported by Nikos Dimitrakopoulos] * Improved JRuby integration by removing JRuby internal backtrace. ### Thanks * Nikos Dimitrakopoulos ## 2.4.2 - 2011-11-26 {#version-2-4-2} ### Improvements * `--name` supported data label. ## 2.4.1 - 2011-11-09 ### Improvements * Accepted AssertionMessage as assertion's user message. It is used in assert_select in actionpack. [Reported by David Heath] ### Fixes * Fixed test failure on LANG=C. #11 [Reported by boutil] * Suppress warnings on Ruby 1.9.2. ### Thanks * boutil * David Heath ## 2.4.0 - 2011-09-18 ### Improvements * Supported Travis CI. #5 [Suggested by James Mead] * Added Gemfile. #6 [Suggested by James Mead] * [ui][console] Supported notification in show-detail-immediately. * [ui][console] enable --show-detail-immediately by default. * [ui] Added --max-diff-target-string-size option. * [ui][console] Supported 256 colors. ### Fixes * Added missing fixture file. #7 [Reported by grafi-tt] * [ui][console] Added missing the last newline for progress level. * Supported correct backtrace for redefined notification. * Don't handle Timeout::Error as pass through exception on Ruby 1.8. #8 [Reported by Marc Seeger (Acquia)] ### Thanks * James Mead * grafi-tt * Marc Seeger (Acquia) ## 2.3.2 - 2011-08-15 A bug fix release. ### Improvements * [ui][console] Added some newlines to improve readability. ### Fixes * [ui][console] Worked --verbose again. * Re-supported Ruby 1.8.6. [Reported by James Mead] ### Thanks * James Mead ## 2.3.1 - 2011-08-06 {#version-2-3-1} Output improvement release! ### Improvements * [ui][console] Outputs omissions and notifications in short. * [ui][console] Added "important-only" verbose level. * Intelligence diff supports recursive references. * [rubyforge #29325] Supported Ruby Enterprise Edition. [Reported by Hans de Graaff] * [rubyforge #29326] Supported JRuby. [Reported by Hans de Graaff] * Added --show-detail-immediately option that shows fault details when a fault is occurred. ### Fixes * [pull request #1] Fixed a problem that load collector can't load a test file on Ruby 1.9. [Patch by grafi-tt] * [issue #3] Fixed a problem that implicit method name override by declarative style test definition. [Reported by Jeremy Stephens] ### Thanks * grafi-tt * Jeremy Stephens * Hans de Graaff ## 2.3.0 / 2011-04-17 * 13 enhancements * improve Hash key sorting for diff. * [#28928] support any characters in declarative style description. [Daniel Berger] * add Error#location and make #backtrace deprecated. * make TestCase#passed? public. * add result finished and pass assertion notifications. * add TestSuite#passed? public. * add XML test runner. * add --output-file-descriptor option. * measure elapsed time for each test. * add --collector option. * support test driven test. [Haruka Yoshihara] * add cleanup hook it runs between after test and before teardown. * support recursive collection sort for diff. * Thanks * Daniel Berger * Haruka Yoshihara ## 2.2.0 / 2011-02-14 * 22 enhancements * [#28808] accept String as delta for assert_in_delta. [Daniel Berger] * [test-unit-users-en:00035] make GC-able finished tests. [Daniel Berger] * use also COLUMNS environment variable to guess terminal width. * make delta for assert_in_delta optional. [Nobuyoshi Nakada] * add assert_not_respond_to. [Nobuyoshi Nakada] * add assert_not_match. assert_no_match is deprecated. [Nobuyoshi Nakada] * add assert_not_in_delta. [Nobuyoshi Nakada] * add assert_in_epsilon. [Nobuyoshi Nakada] * add assert_not_in_epsilon. [Nobuyoshi Nakada] * add assert_include. [Nobuyoshi Nakada] * add assert_not_include. [Nobuyoshi Nakada] * add assert_empty. [Nobuyoshi Nakada] * add assert_not_empty. [Nobuyoshi Nakada] * notify require failed paths. * validate message value for assert. * show throughputs at the last. * support not ASCII compatible string diff. * support colorized diff on encoding different string. * normalize entry order of Hash for readable diff. * add --ignore-name option. * add --ignore-testcase option. * add assert_not_send. * Thanks * Daniel Berger * Nobuyoshi Nakada ## 2.1.2 / 2010-11-25 * 1 enhancement * support auto runner prepare hook. ## 2.1.1 / 2010-07-29 * 1 bug fix * [test-unit-users-en:00026] re-work tap runner. [Daniel Berger] * Thanks * Daniel Berger === 2.1.0 / 2010-07-17 * 1 bug fix * [#28267] global config file ignored [Daniel Berger] * Thanks * Daniel Berger ## 2.0.8 / 2010-06-02 * 5 major enchancements * collect *_test.rb and *-test.rb files as test files. * [#28181] improve assert_in_delta message. [Suggested by David MARCHALAND] * show string encoding in assert_equal failure message if they are different. * change default color scheme: * success: green back + white * failure: red back + white * add capture_output. * 2 bug fixes * fix a bug that console runner on verbose mode causes an error for long test name (>= 61). * [#28093] Autorunner ignores all files in a directory named test by default [Reported by Florian Frank] * Thanks * Florian Frank * David MARCHALAND ## 2.0.7 / 2010-03-09 * 4 major enhancements * detect redefined test methods. * [INTERFACE IMCOMPATIBLE] multiple --name and --testcase options narrow down targets instead of adding targets. * [#27764] accept custom test_order for each test case. [Suggested by David MARCHALAND] * [#27790] ignore omitted tests from 'n% passed' report. [Suggested by Daniel Berger] * 2 minor enchancements * [#27832] ignore .git directory. [Suggested by Daniel Berger] * [#27792] require 'fileutils' and 'tmpdir' lazily for non-priority mode users. [Suggested by David MARCHALAND] * 2 bug fixes * [#27892] modify processed arguments array destructively. [Reported by Bob Saveland] * work without HOME environment variable. [Reported by Champak Ch] * Thanks * David MARCHALAND * Daniel Berger * Bob Saveland * Champak Ch ## 2.0.6 / 2010-01-09 * 3 major enhancements * [#27380] Declarative syntax? [Daniel Berger] support declarative syntax: test "test description in natural language" do ... end * support test description: description "test description in natural language" def test_my_test ... end * make max diff target string size customizable by TEST_UNIT_MAX_DIFF_TARGET_STRING_SIZE environment variable. * 2 bug fixes * [#27374] omit_if unexpected behavior [David MARCHALAND] * fix a bug that tests in sub directories aren't load with --basedir. [Daniel Berger] * Thanks * David MARCHALAND * Daniel Berger ## 2.0.5 / 2009-10-18 * 1 bug fixes * [#27314] fix diff may raise an exception. [Erik Hollensbe] * Thanks * Erik Hollensbe ## 2.0.4 / 2009-10-17 * 4 major enhancements * use ~/.test-unit.yml as global configuration file. * add TAP runner. (--runner tap) * support colorized diff: http://test-unit.github.io/color-diff.png * add Test::Unit::AutoRunner.default_runner= to specify default test runner. * 4 minor enhancements * improve verbose mode output format. (use indent) * support `NOT_PASS_THROUGH_EXCEPTIONS`. * support arguments option in `#{runner}_options`. * TC_ -> Test in sample test case name. * 1 bug fixes * [#27195] test-unit-2.0.3 + ruby-1.9.1 cannot properly test DelegateClass subclasses [Mike Pomraning] * Thanks * Mike Pomraning ## 2.0.3 / 2009-07-19 * 6 major enhancements * add assert_predicate. * add assert_not_predicate. * [#24210] assert_kind_of supports an array of classes or modules. [Daniel Berger] * assert_instance_of supports an array of classes or modules. * add --default-priority option. * [#26627] add --order option. [Daniel Berger] * 4 minor enhancements * use yellow foreground + black background for error. * don't show diff for long string. * accept "*term-color" TERM environment as colorizable terminal. (e.g. Apple's Terminal) * [#26268] add a workaround for test-spec's after_all. [Angelo Lakra] * 1 bug fix * [#23586] re-support ruby 1.9.1. [Diego Pettenò] * Thanks * Diego Pettenò * Daniel Berger * Angelo Lakra ## 2.0.2 / 2008-12-21 * 2 major enhancements * re-support ruby 1.8.5. * improve exception object comparison. * 3 bug fixes * [#22723]: collector fails on anonymous classes * [#22986]: Test names with '?' blow up on Windows * [#22988]: don't create .test-result on non-priority mode. * Thanks * Erik Hollensbe * Daniel Berger * Bill Lear ## 2.0.1 / 2008-11-09 * 19 major enhancements * support ruby 1.9.1. * add run_test method to be extensible. * improve priority-mode auto off. * improve startup/shutdown RDoc. [Daniel Berger] * add assert_compare. [#20851] [Designing Patterns] * add assert_fail_assertion. [#20851] [Designing Patterns] * add assert_raise_message. [#20851] [Designing Patterns] * support folded diff. * add assert_raise_kind_of. [Daniel Berger] * ingore inherited test for nested test case. * add assert_const_defined. * add assert_not_const_defined. * support assert_raise with an exception object. * support assert_raise with no arguments that asserts any exception is raised. [#22602] [Daniel Berger] * support folded dot progress. * add --progress-row-max option. * support color scheme customize. * support configuration file. (YAML) * recognize test-XXX.rb files as test files not only test_XXX.rb * Thanks * Daniel Berger * Designing Patterns ## 2.0.0 / 2008-06-18 * 15 major enhancements * support startup/shutdown. (test case level setup/teardown) * support multiple setup/teardown. * support pending. * support omission. * support notification. * support colorize. * support diff. * support test attribute. * add assert_boolean. * add assert_true. * add assert_false. * add --priority-mode option. * don't use ObjectSpace to collect test cases. * make more customizable. (additional options, exception handling and so on) * improve Emacs integration. * 4 major changes * remove GTK+1 support. * split GTK+ runner as another gem. * split FOX runner as another gem. * split Tk runner as another gem. ## 1.2.3 / 2008-02-25 * 1 major enhancement * Birthday (as a gem)! PKu]p+test-unit-3.3.4/doc/text/getting-started.mdnu[## 1. First step of the `test-unit` Let's getting start `test-unit`. This document creates an example gem package called `sample` with the `test-unit` testing framework. ## 2. Install bundler and test-unit. * First, install the `bundler` gem for generating gem template. * Second, install the `test-unit` itself. ~~~ !!!plain gem install bundler gem install test-unit ~~~ The `gem list` command output installed packages. You will find the following lines. ~~~ !!!plain gem list ... bundler (1.14.6) ... test-unit (3.2.3) ~~~ ## 3. Create gem template. Next, create a gem template using `bundler` command. This command generates package skeleton with a testing framework. However, this command can't generate test templates for `test-unit`. So, First create gem template with the `minitest` testing framework. (It's similar to `unit-test`). After that, replace some files for `test-unit`. The `bundle gem -t minitest sample` command will generate the following files. ~~~ !!!plain . |-- Gemfile |-- README.md |-- Rakefile |-- bin | |-- console | `-- setup |-- lib | |-- sample | | `-- version.rb | `-- sample.rb |-- sample.gemspec # <- Modify `-- test |-- sample_test.rb # <- Modify `-- test_helper.rb # <- Modify ~~~ ## 4. Edit files for `test-unit` ### 4.1. Edit gemspec Edit `sample.gemspec` like the below. Replace `minitest` line to `test-unit`. Before ~~~ !!!ruby spec.add_development_dependency "minitest", "~> 5.0" ~~~ After ~~~ !!!ruby spec.add_development_dependency "test-unit", "~> 3.2.3" ~~~ ### 4.2. Edit `test/test_helper.rb` Next, edit the `test/test_helper.rb` file. Before ~~~ !!!ruby $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'sample' require 'minitest/autorun' # <-- Modify this line. ~~~ After ~~~ !!!ruby $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'sample' require 'test/unit' # <-- After modification. ~~~ ### 4.3 Rakefile (No edit) This file doesn't need to modify. The output is the below. ~~~ !!!ruby require "bundler/gem_tasks" require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList['test/**/*_test.rb'] end task :default => :test ~~~ ### 4.4 Edit `test/sample_test.rb` The bundler generate the file `test/sample_test.rb`. This file originally templates for `minitest`. Let's modify this file for `test-unit` before ~~~ !!!ruby require 'test_helper' class SampleTest < Minitest::Test # <- Modify here def test_that_it_has_a_version_number refute_nil ::Sample::VERSION end def test_it_does_something_useful assert false end end ~~~ After ~~~ !!!ruby require 'test_helper' class SampleTest < Test::Unit::TestCase # <- After modification def test_that_it_has_a_version_number refute_nil ::Sample::VERSION end def test_it_does_something_useful assert false end end ~~~ ## 5. Execute test. The `rake test` command execute test scenarios in the `test` directory. Now it tries to two tests. One will success the other one fails. ~~~ !!!plain rake test Loaded suite /path/to/ruby/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/rake_test_loader Started F ================================================================================ Failure: is not true. test_it_does_something_useful(SampleTest) /path/to/sample/test/sample_test.rb:9:in `test_it_does_something_useful' 6: end 7: 8: def test_it_does_something_useful => 9: assert false 10: end 11: end ================================================================================ . Finished in 0.011521 seconds. -------------------------------------------------------------------------------- 2 tests, 2 assertions, 1 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 50% passed -------------------------------------------------------------------------------- 173.60 tests/s, 173.60 assertions/s rake aborted! Command failed with status (1) Tasks: TOP => test (See full trace by running task with --trace) ~~~ ## 6. Create original tests. Let's create your original tests with the following rules. * Create a test file in the `test` directory. * The file needs suffix `xxx_test.rb`. * You can put test file into the subdirectory like `test/sub`. Example directory layout. ~~~ !!!plain test |-- sample_test.rb |-- sub | `-- sample2_test.rb `-- test_helper.rb ~~~ Example test file in the sub directory. ~~~ !!!ruby require 'test_helper' module Sub class Sample2Test < Test::Unit::TestCase def test_that_it_has_a_version_number refute_nil ::Sample::VERSION end def test_it_does_something_useful assert false end end end ~~~ ## 7. For more inforomation Let's read the official document. * [test-unit](http://test-unit.github.io/index.html) PKu]w5test-unit-3.3.4/lib/test/unit/code-snippet-fetcher.rbnu[module Test module Unit class CodeSnippetFetcher def initialize @sources = {} end def fetch(path, line, options={}) n_context_line = options[:n_context_line] || 3 lines = source(path) return [] if lines.nil? min_line = [line - n_context_line, 1].max max_line = [line + n_context_line, lines.length].min window = min_line..max_line window.collect do |n| attributes = {:target_line? => (n == line)} [n, lines[n - 1].chomp, attributes] end end def source(path) @sources[path] ||= read_source(path) end private def read_source(path) return nil unless File.exist?(path) lines = [] File.open(path, "rb") do |file| first_line = file.gets break if first_line.nil? encoding = detect_encoding(first_line) || Encoding::UTF_8 first_line.force_encoding(encoding) file.set_encoding(encoding) lines << first_line lines.concat(file.readlines) end lines end def detect_encoding(first_line) return nil unless first_line.respond_to?(:ascii_only?) return nil unless first_line.ascii_only? if /\b(?:en)?coding[:=]\s*([a-z\d_-]+)/i =~ first_line begin Encoding.find($1) rescue ArgumentError nil end else nil end end end end end PKu]C9 9 0test-unit-3.3.4/lib/test/unit/util/observable.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/procwrapper' module Test module Unit module Util # This is a utility class that allows anything mixing # it in to notify a set of listeners about interesting # events. module Observable # We use this for defaults since nil might mean something NOTHING = "NOTHING/#{__id__}" # Adds the passed proc as a listener on the # channel indicated by channel_name. listener_key # is used to remove the listener later; if none is # specified, the proc itself is used. # # Whatever is used as the listener_key is # returned, making it very easy to use the proc # itself as the listener_key: # # listener = add_listener("Channel") { ... } # remove_listener("Channel", listener) def add_listener(channel_name, listener_key=NOTHING, &listener) # :yields: value unless(block_given?) raise ArgumentError.new("No callback was passed as a listener") end key = listener_key if (listener_key == NOTHING) listener_key = listener key = ProcWrapper.new(listener) end channels[channel_name] ||= {} channels[channel_name][key] = listener return listener_key end # Removes the listener indicated by listener_key # from the channel indicated by # channel_name. Returns the registered proc, or # nil if none was found. def remove_listener(channel_name, listener_key) channel = channels[channel_name] return nil unless (channel) key = listener_key if (listener_key.instance_of?(Proc)) key = ProcWrapper.new(listener_key) end if (channel.has_key?(key)) return channel.delete(key) end return nil end # Calls all the procs registered on the channel # indicated by channel_name. If value is # specified, it is passed in to the procs, # otherwise they are called with no arguments. # #-- # # Perhaps this should be private? Would it ever # make sense for an external class to call this # method directly? def notify_listeners(channel_name, *arguments) channel = channels[channel_name] return 0 unless (channel) listeners = channel.values listeners.each { |listener| listener.call(*arguments) } return listeners.size end private def channels @channels ||= {} return @channels end end end end end PKu]̭,test-unit-3.3.4/lib/test/unit/util/output.rbnu[module Test module Unit module Util module Output ## # Returns output for standard output and standard # error as string. # # Example: # # capture_output do # puts("stdout") # warn("stderr") # end # -> ["stdout\n", "stderr\n"] def capture_output require 'stringio' output = StringIO.new error = StringIO.new stdout_save, stderr_save = $stdout, $stderr $stdout, $stderr = output, error begin yield [output.string, error.string] ensure $stdout, $stderr = stdout_save, stderr_save end end end end end end PKu]S<9test-unit-3.3.4/lib/test/unit/util/method-owner-finder.rbnu[module Test module Unit module Util module MethodOwnerFinder module_function def find(object, method_name) method = object.method(method_name) return method.owner if method.respond_to?(:owner) if /\((.+?)\)\#/ =~ method.to_s owner_name = $1 if /\A#\MM1test-unit-3.3.4/lib/test/unit/util/procwrapper.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit module Util # Allows the storage of a Proc passed through '&' in a # hash. # # Note: this may be inefficient, since the hash being # used is not necessarily very good. In Observable, # efficiency is not too important, since the hash is # only accessed when adding and removing listeners, # not when notifying. class ProcWrapper # Creates a new wrapper for a_proc. def initialize(a_proc) @a_proc = a_proc @hash = a_proc.inspect.sub(/^(#<#{a_proc.class}:)/){''}.sub(/(>)$/){''}.hex end def hash return @hash end def ==(other) case(other) when ProcWrapper return @a_proc == other.to_proc else return super end end alias :eql? :== def to_proc return @a_proc end end end end end PKu]005test-unit-3.3.4/lib/test/unit/util/backtracefilter.rbnu[begin require 'power_assert' rescue LoadError, SyntaxError end module Test module Unit module Util module BacktraceFilter TESTUNIT_FILE_SEPARATORS = %r{[\\/:]} TESTUNIT_PREFIX = __FILE__.split(TESTUNIT_FILE_SEPARATORS)[0..-3] TESTUNIT_RB_FILE = /\.rb\Z/ POWERASSERT_PREFIX = defined?(::PowerAssert) ? ::PowerAssert.method(:start).source_location[0].split(TESTUNIT_FILE_SEPARATORS)[0..-2] : nil module_function def filter_backtrace(backtrace, prefix=nil) return ["No backtrace"] unless backtrace return backtrace if ENV["TEST_UNIT_ALL_BACKTRACE"] if prefix split_prefixes = [prefix.split(TESTUNIT_FILE_SEPARATORS)] else split_prefixes = [TESTUNIT_PREFIX, POWERASSERT_PREFIX].compact end test_unit_internal_p = lambda do |entry| components = entry.split(TESTUNIT_FILE_SEPARATORS) split_prefixes.any? do |split_prefix| split_entry = components[0, split_prefix.size] next false unless split_entry[0..-2] == split_prefix[0..-2] split_entry[-1].sub(TESTUNIT_RB_FILE, '') == split_prefix[-1] end end in_user_code = false new_backtrace = backtrace.reverse.reject do |entry| if test_unit_internal_p.call(entry) in_user_code = true true else not in_user_code end end.reverse if new_backtrace.empty? new_backtrace = backtrace.reject do |entry| test_unit_internal_p.call(entry) end new_backtrace = backtrace if new_backtrace.empty? end new_backtrace end end end end end PKu]9'ee%test-unit-3.3.4/lib/test/unit/diff.rbnu[# port of Python's difflib. # # Copyright (c) 2001-2008 Python Software Foundation; All Rights Reserved # Copyright (c) 2008-2011 Kouhei Sutou; All Rights Reserved # # It is free software, and is distributed under the Ruby license, the # PSF license and/or LGPLv2.1 or later. See the COPYING file, the PSFL # file and the LGPL file. module Test module Unit module Diff class SequenceMatcher def initialize(from, to, &junk_predicate) @from = from @to = to @junk_predicate = junk_predicate update_to_indexes end def longest_match(from_start, from_end, to_start, to_end) best_info = find_best_match_position(from_start, from_end, to_start, to_end) unless @junks.empty? args = [from_start, from_end, to_start, to_end] best_info = adjust_best_info_with_junk_predicate(false, best_info, *args) best_info = adjust_best_info_with_junk_predicate(true, best_info, *args) end best_info end def blocks @blocks ||= compute_blocks end def operations @operations ||= compute_operations end def grouped_operations(context_size=nil) context_size ||= 3 _operations = operations.dup _operations = [[:equal, 0, 0, 0, 0]] if _operations.empty? expand_edge_equal_operations!(_operations, context_size) group_window = context_size * 2 groups = [] group = [] _operations.each do |tag, from_start, from_end, to_start, to_end| if tag == :equal and from_end - from_start > group_window group << [tag, from_start, [from_end, from_start + context_size].min, to_start, [to_end, to_start + context_size].min] groups << group group = [] from_start = [from_start, from_end - context_size].max to_start = [to_start, to_end - context_size].max end group << [tag, from_start, from_end, to_start, to_end] end groups << group unless group.empty? groups end def ratio @ratio ||= compute_ratio end private def update_to_indexes @to_indexes = {} @junks = {} if @to.is_a?(String) each = " "[0].is_a?(Integer) ? :each_byte : :each_char else each = :each end i = 0 @to.__send__(each) do |item| @to_indexes[item] ||= [] @to_indexes[item] << i i += 1 end return if @junk_predicate.nil? @to_indexes = @to_indexes.reject do |key, value| junk = @junk_predicate.call(key) @junks[key] = true if junk junk end end def find_best_match_position(from_start, from_end, to_start, to_end) best_from, best_to, best_size = from_start, to_start, 0 sizes = {} from_start.upto(from_end) do |from_index| _sizes = {} (@to_indexes[@from[from_index]] || []).each do |to_index| next if to_index < to_start break if to_index > to_end size = _sizes[to_index] = (sizes[to_index - 1] || 0) + 1 if size > best_size best_from = from_index - size + 1 best_to = to_index - size + 1 best_size = size end end sizes = _sizes end [best_from, best_to, best_size] end def adjust_best_info_with_junk_predicate(should_junk, best_info, from_start, from_end, to_start, to_end) best_from, best_to, best_size = best_info while best_from > from_start and best_to > to_start and (should_junk ? @junks.has_key?(@to[best_to - 1]) : !@junks.has_key?(@to[best_to - 1])) and @from[best_from - 1] == @to[best_to - 1] best_from -= 1 best_to -= 1 best_size += 1 end while best_from + best_size < from_end and best_to + best_size < to_end and (should_junk ? @junks.has_key?(@to[best_to + best_size]) : !@junks.has_key?(@to[best_to + best_size])) and @from[best_from + best_size] == @to[best_to + best_size] best_size += 1 end [best_from, best_to, best_size] end def matches @matches ||= compute_matches end def compute_matches matches = [] queue = [[0, @from.size, 0, @to.size]] until queue.empty? from_start, from_end, to_start, to_end = queue.pop match = longest_match(from_start, from_end - 1, to_start, to_end - 1) match_from_index, match_to_index, size = match unless size.zero? if from_start < match_from_index and to_start < match_to_index queue.push([from_start, match_from_index, to_start, match_to_index]) end matches << match if match_from_index + size < from_end and match_to_index + size < to_end queue.push([match_from_index + size, from_end, match_to_index + size, to_end]) end end end matches.sort_by do |(from_index, _, _)| from_index end end def compute_blocks blocks = [] current_from_index = current_to_index = current_size = 0 matches.each do |from_index, to_index, size| if current_from_index + current_size == from_index and current_to_index + current_size == to_index current_size += size else unless current_size.zero? blocks << [current_from_index, current_to_index, current_size] end current_from_index = from_index current_to_index = to_index current_size = size end end unless current_size.zero? blocks << [current_from_index, current_to_index, current_size] end blocks << [@from.size, @to.size, 0] blocks end def compute_operations from_index = to_index = 0 operations = [] blocks.each do |match_from_index, match_to_index, size| tag = determine_tag(from_index, to_index, match_from_index, match_to_index) if tag != :equal operations << [tag, from_index, match_from_index, to_index, match_to_index] end from_index, to_index = match_from_index + size, match_to_index + size if size > 0 operations << [:equal, match_from_index, from_index, match_to_index, to_index] end end operations end def compute_ratio matches = blocks.inject(0) {|result, block| result + block[-1]} length = @from.length + @to.length if length.zero? 1.0 else 2.0 * matches / length end end def determine_tag(from_index, to_index, match_from_index, match_to_index) if from_index < match_from_index and to_index < match_to_index :replace elsif from_index < match_from_index :delete elsif to_index < match_to_index :insert else :equal end end def expand_edge_equal_operations!(_operations, context_size) tag, from_start, from_end, to_start, to_end = _operations[0] if tag == :equal _operations[0] = [tag, [from_start, from_end - context_size].max, from_end, [to_start, to_end - context_size].max, to_end] end tag, from_start, from_end, to_start, to_end = _operations[-1] if tag == :equal _operations[-1] = [tag, from_start, [from_end, from_start + context_size].min, to_start, [to_end, to_start + context_size].min] end end end class Differ def initialize(from, to) @from = from @to = to end private def tag(mark, contents) contents.collect {|content| mark + content} end end class UTF8Line class << self # from http://unicode.org/reports/tr11/ WIDE_CHARACTERS = [0x1100..0x1159, 0x115F..0x115F, 0x2329..0x232A, 0x2E80..0x2E99, 0x2E9B..0x2EF3, 0x2F00..0x2FD5, 0x2FF0..0x2FFB, 0x3000..0x303E, 0x3041..0x3096, 0x3099..0x30FF, 0x3105..0x312D, 0x3131..0x318E, 0x3190..0x31B7, 0x31C0..0x31E3, 0x31F0..0x321E, 0x3220..0x3243, 0x3250..0x32FE, 0x3300..0x4DB5, 0x4E00..0x9FC3, 0xA000..0xA48C, 0xA490..0xA4C6, 0xAC00..0xD7A3, 0xF900..0xFA2D, 0xFA30..0xFA6A, 0xFA70..0xFAD9, 0xFE10..0xFE19, 0xFE30..0xFE52, 0xFE54..0xFE66, 0xFE68..0xFE6B, 0xFF01..0xFF60, 0xFFE0..0xFFE6, 0x20000..0x2FFFD, 0x30000..0x3FFFD, ] AMBIGUOUS = [0x00A1..0x00A1, 0x00A4..0x00A4, 0x00A7..0x00A8, 0x00AA..0x00AA, 0x00AD..0x00AE, 0x00B0..0x00B4, 0x00B6..0x00BA, 0x00BC..0x00BF, 0x00C6..0x00C6, 0x00D0..0x00D0, 0x00D7..0x00D8, 0x00DE..0x00E1, 0x00E6..0x00E6, 0x00E8..0x00EA, 0x00EC..0x00ED, 0x00F0..0x00F0, 0x00F2..0x00F3, 0x00F7..0x00FA, 0x00FC..0x00FC, 0x00FE..0x00FE, 0x0101..0x0101, 0x0111..0x0111, 0x0113..0x0113, 0x011B..0x011B, 0x0126..0x0127, 0x012B..0x012B, 0x0131..0x0133, 0x0138..0x0138, 0x013F..0x0142, 0x0144..0x0144, 0x0148..0x014B, 0x014D..0x014D, 0x0152..0x0153, 0x0166..0x0167, 0x016B..0x016B, 0x01CE..0x01CE, 0x01D0..0x01D0, 0x01D2..0x01D2, 0x01D4..0x01D4, 0x01D6..0x01D6, 0x01D8..0x01D8, 0x01DA..0x01DA, 0x01DC..0x01DC, 0x0251..0x0251, 0x0261..0x0261, 0x02C4..0x02C4, 0x02C7..0x02C7, 0x02C9..0x02CB, 0x02CD..0x02CD, 0x02D0..0x02D0, 0x02D8..0x02DB, 0x02DD..0x02DD, 0x02DF..0x02DF, 0x0300..0x036F, 0x0391..0x03A1, 0x03A3..0x03A9, 0x03B1..0x03C1, 0x03C3..0x03C9, 0x0401..0x0401, 0x0410..0x044F, 0x0451..0x0451, 0x2010..0x2010, 0x2013..0x2016, 0x2018..0x2019, 0x201C..0x201D, 0x2020..0x2022, 0x2024..0x2027, 0x2030..0x2030, 0x2032..0x2033, 0x2035..0x2035, 0x203B..0x203B, 0x203E..0x203E, 0x2074..0x2074, 0x207F..0x207F, 0x2081..0x2084, 0x20AC..0x20AC, 0x2103..0x2103, 0x2105..0x2105, 0x2109..0x2109, 0x2113..0x2113, 0x2116..0x2116, 0x2121..0x2122, 0x2126..0x2126, 0x212B..0x212B, 0x2153..0x2154, 0x215B..0x215E, 0x2160..0x216B, 0x2170..0x2179, 0x2190..0x2199, 0x21B8..0x21B9, 0x21D2..0x21D2, 0x21D4..0x21D4, 0x21E7..0x21E7, 0x2200..0x2200, 0x2202..0x2203, 0x2207..0x2208, 0x220B..0x220B, 0x220F..0x220F, 0x2211..0x2211, 0x2215..0x2215, 0x221A..0x221A, 0x221D..0x2220, 0x2223..0x2223, 0x2225..0x2225, 0x2227..0x222C, 0x222E..0x222E, 0x2234..0x2237, 0x223C..0x223D, 0x2248..0x2248, 0x224C..0x224C, 0x2252..0x2252, 0x2260..0x2261, 0x2264..0x2267, 0x226A..0x226B, 0x226E..0x226F, 0x2282..0x2283, 0x2286..0x2287, 0x2295..0x2295, 0x2299..0x2299, 0x22A5..0x22A5, 0x22BF..0x22BF, 0x2312..0x2312, 0x2460..0x24E9, 0x24EB..0x254B, 0x2550..0x2573, 0x2580..0x258F, 0x2592..0x2595, 0x25A0..0x25A1, 0x25A3..0x25A9, 0x25B2..0x25B3, 0x25B6..0x25B7, 0x25BC..0x25BD, 0x25C0..0x25C1, 0x25C6..0x25C8, 0x25CB..0x25CB, 0x25CE..0x25D1, 0x25E2..0x25E5, 0x25EF..0x25EF, 0x2605..0x2606, 0x2609..0x2609, 0x260E..0x260F, 0x2614..0x2615, 0x261C..0x261C, 0x261E..0x261E, 0x2640..0x2640, 0x2642..0x2642, 0x2660..0x2661, 0x2663..0x2665, 0x2667..0x266A, 0x266C..0x266D, 0x266F..0x266F, 0x273D..0x273D, 0x2776..0x277F, 0xE000..0xF8FF, 0xFE00..0xFE0F, 0xFFFD..0xFFFD, 0xE0100..0xE01EF, 0xF0000..0xFFFFD, 0x100000..0x10FFFD, ] def wide_character?(character) binary_search_ranges(character, WIDE_CHARACTERS) or binary_search_ranges(character, AMBIGUOUS) end private def binary_search_ranges(character, ranges) if ranges.size.zero? false elsif ranges.size == 1 ranges[0].include?(character) else half = ranges.size / 2 range = ranges[half] if range.include?(character) true elsif character < range.begin binary_search_ranges(character, ranges[0...half]) else binary_search_ranges(character, ranges[(half + 1)..-1]) end end end end def initialize(line) @line = line @characters = @line.unpack("U*") end def [](*args) result = @characters[*args] if result.respond_to?(:pack) result.pack("U*") else result end end def each(&block) @characters.each(&block) end def size @characters.size end def to_s @line end def compute_width(start, _end) width = 0 start.upto(_end - 1) do |i| if self.class.wide_character?(@characters[i]) width += 2 else width += 1 end end width end end class ReadableDiffer < Differ def diff(options={}) @result = [] operations.each do |tag, from_start, from_end, to_start, to_end| case tag when :replace diff_lines(from_start, from_end, to_start, to_end) when :delete tag_deleted(@from[from_start...from_end]) when :insert tag_inserted(@to[to_start...to_end]) when :equal tag_equal(@from[from_start...from_end]) else raise "unknown tag: #{tag}" end end @result end private def operations @operations ||= nil if @operations.nil? matcher = SequenceMatcher.new(@from, @to) @operations = matcher.operations end @operations end def default_ratio 0.74 end def cut_off_ratio 0.75 end def tag(mark, contents) contents.each do |content| @result << (mark + content) end end def tag_deleted(contents) tag("- ", contents) end def tag_inserted(contents) tag("+ ", contents) end def tag_equal(contents) tag(" ", contents) end def tag_difference(contents) tag("? ", contents) end def find_diff_line_info(from_start, from_end, to_start, to_end) best_ratio = default_ratio from_equal_index = to_equal_index = nil from_best_index = to_best_index = nil to_start.upto(to_end - 1) do |to_index| from_start.upto(from_end - 1) do |from_index| if @from[from_index] == @to[to_index] from_equal_index ||= from_index to_equal_index ||= to_index next end matcher = SequenceMatcher.new(@from[from_index], @to[to_index], &method(:space_character?)) if matcher.ratio > best_ratio best_ratio = matcher.ratio from_best_index = from_index to_best_index = to_index end end end [best_ratio, from_equal_index, to_equal_index, from_best_index, to_best_index] end def diff_lines(from_start, from_end, to_start, to_end) info = find_diff_line_info(from_start, from_end, to_start, to_end) best_ratio, from_equal_index, to_equal_index, *info = info from_best_index, to_best_index = info from_best_index ||= from_start to_best_index ||= to_start if best_ratio < cut_off_ratio if from_equal_index.nil? if to_end - to_start < from_end - from_start tag_inserted(@to[to_start...to_end]) tag_deleted(@from[from_start...from_end]) else tag_deleted(@from[from_start...from_end]) tag_inserted(@to[to_start...to_end]) end return end from_best_index = from_equal_index to_best_index = to_equal_index best_ratio = 1.0 end _diff_lines(from_start, from_best_index, to_start, to_best_index) diff_line(@from[from_best_index], @to[to_best_index]) _diff_lines(from_best_index + 1, from_end, to_best_index + 1, to_end) end def _diff_lines(from_start, from_end, to_start, to_end) if from_start < from_end if to_start < to_end diff_lines(from_start, from_end, to_start, to_end) else tag_deleted(@from[from_start...from_end]) end else tag_inserted(@to[to_start...to_end]) end end def line_operations(from_line, to_line) if !from_line.respond_to?(:force_encoding) and $KCODE == "UTF8" from_line = UTF8Line.new(from_line) to_line = UTF8Line.new(to_line) end matcher = SequenceMatcher.new(from_line, to_line, &method(:space_character?)) [from_line, to_line, matcher.operations] end def compute_width(line, start, _end) if line.respond_to?(:encoding) and Encoding.compatible?(Encoding::UTF_8, line.encoding) utf8_line = line[start..._end].encode(Encoding::UTF_8) width = 0 utf8_line.each_codepoint do |unicode_codepoint| if UTF8Line.wide_character?(unicode_codepoint) width += 2 else width += 1 end end width elsif line.is_a?(UTF8Line) line.compute_width(start, _end) else _end - start end end def diff_line(from_line, to_line) from_tags = "" to_tags = "" from_line, to_line, _operations = line_operations(from_line, to_line) _operations.each do |tag, from_start, from_end, to_start, to_end| from_width = compute_width(from_line, from_start, from_end) to_width = compute_width(to_line, to_start, to_end) case tag when :replace from_tags += "^" * from_width to_tags += "^" * to_width when :delete from_tags += "-" * from_width when :insert to_tags += "+" * to_width when :equal from_tags += " " * from_width to_tags += " " * to_width else raise "unknown tag: #{tag}" end end format_diff_point(from_line, to_line, from_tags, to_tags) end def format_diff_point(from_line, to_line, from_tags, to_tags) common = [n_leading_characters(from_line, ?\t), n_leading_characters(to_line, ?\t)].min common = [common, n_leading_characters(from_tags[0, common], " "[0])].min from_tags = from_tags[common..-1].rstrip to_tags = to_tags[common..-1].rstrip tag_deleted([from_line]) unless from_tags.empty? tag_difference(["#{"\t" * common}#{from_tags}"]) end tag_inserted([to_line]) unless to_tags.empty? tag_difference(["#{"\t" * common}#{to_tags}"]) end end def n_leading_characters(string, character) n = 0 while string[n] == character n += 1 end n end def space_character?(character) [" "[0], "\t"[0]].include?(character) end end class UnifiedDiffer < Differ def diff(options={}) groups = SequenceMatcher.new(@from, @to).grouped_operations return [] if groups.empty? return [] if same_content?(groups) show_context = options[:show_context] show_context = true if show_context.nil? result = ["--- #{options[:from_label]}".rstrip, "+++ #{options[:to_label]}".rstrip] groups.each do |operations| result << format_summary(operations, show_context) operations.each do |args| operation_tag, from_start, from_end, to_start, to_end = args case operation_tag when :replace result.concat(tag("-", @from[from_start...from_end])) result.concat(tag("+", @to[to_start...to_end])) when :delete result.concat(tag("-", @from[from_start...from_end])) when :insert result.concat(tag("+", @to[to_start...to_end])) when :equal result.concat(tag(" ", @from[from_start...from_end])) end end end result end private def same_content?(groups) return false if groups.size != 1 group = groups[0] return false if group.size != 1 tag, from_start, from_end, to_start, to_end = group[0] tag == :equal and [from_start, from_end] == [to_start, to_end] end def format_summary(operations, show_context) _, first_from_start, _, first_to_start, _ = operations[0] _, _, last_from_end, _, last_to_end = operations[-1] summary = "@@ -%d,%d +%d,%d @@" % [first_from_start + 1, last_from_end - first_from_start, first_to_start + 1, last_to_end - first_to_start,] if show_context interesting_line = find_interesting_line(first_from_start, first_to_start, :define_line?) summary << " #{interesting_line}" if interesting_line end summary end def find_interesting_line(from_start, to_start, predicate) from_index = from_start to_index = to_start while from_index >= 0 or to_index >= 0 [@from[from_index], @to[to_index]].each do |line| return line if line and __send__(predicate, line) end from_index -= 1 to_index -= 1 end nil end def define_line?(line) /\A(?:[_a-zA-Z$]|\s*(?:class|module|def)\b)/ =~ line end end module_function def need_fold?(diff) /^[-+].{79}/ =~ diff end def fold(string) string.split(/\r?\n/).collect do |line| line.gsub(/(.{78})/, "\\1\n") end.join("\n") end def folded_readable(from, to, options={}) readable(fold(from), fold(to), options) end def readable(from, to, options={}) diff(ReadableDiffer, from, to, options) end def unified(from, to, options={}) diff(UnifiedDiffer, from, to, options) end def diff(differ_class, from, to, options={}) if from.respond_to?(:valid_encoding?) and not from.valid_encoding? from = from.dup.force_encoding("ASCII-8BIT") end if to.respond_to?(:valid_encoding?) and not to.valid_encoding? to = to.dup.force_encoding("ASCII-8BIT") end differ = differ_class.new(from.split(/\r?\n/), to.split(/\r?\n/)) lines = differ.diff(options) if Object.const_defined?(:EncodingError) begin lines.join("\n") rescue EncodingError lines.collect {|line| line.force_encoding("ASCII-8BIT")}.join("\n") end else lines.join("\n") end end end end end PKu]*6r &test-unit-3.3.4/lib/test/unit/color.rbnu[module Test module Unit class Color class Error < StandardError end class ParseError < Error end class << self def parse_256_color(string) case string when /\A([0-5])([0-5])([0-5])\z/ red, green, blue = $1, $2, $3 red.to_i * 36 + green.to_i * 6 + blue.to_i + 16 else message = "must be 'RGB' format and R, G and B " + "are in 0-5: #{string.inspect}" raise ParseError, message end end end NAMES = ["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"] attr_reader :name def initialize(name, options={}) @name = name if options.has_key?(:foreground) if options[:foreground].nil? @background = false else @background = !options[:foreground] end else @background = options[:background] end @intensity = options[:intensity] @bold = options[:bold] @italic = options[:italic] @underline = options[:underline] end def foreground? not background? end def background? @background end def intensity? @intensity end def bold? @bold end def italic? @italic end def underline? @underline end def ==(other) self.class === other and [name, background?, intensity?, bold?, italic?, underline?] == [other.name, other.background?, other.intensity?, other.bold?, other.italic?, other.underline?] end def sequence sequence = [] if @name == "none" elsif @name == "reset" sequence << "0" else if NAMES.include?(@name) color_parameter = foreground? ? 3 : 4 color_parameter += 6 if intensity? color = NAMES.index(@name) sequence << "#{color_parameter}#{color}" else sequence << (foreground? ? "38" : "48") sequence << "5" sequence << self.class.parse_256_color(@name).to_s end end sequence << "1" if bold? sequence << "3" if italic? sequence << "4" if underline? sequence end def escape_sequence "\e[#{sequence.join(';')}m" end def +(other) MixColor.new([self, other]) end end class MixColor attr_reader :colors def initialize(colors) @colors = colors end def sequence @colors.inject([]) do |result, color| result + color.sequence end end def escape_sequence "\e[#{sequence.join(';')}m" end def +(other) self.class.new([self, other]) end def ==(other) self.class === other and colors == other.colors end end end end PKu]U<l *test-unit-3.3.4/lib/test/unit/data-sets.rbnu[module Test module Unit class DataSets def initialize @variables = [] @procs = [] @value_sets = [] end def add(data_set, options=nil) options ||= {} if data_set.respond_to?(:call) @procs << [data_set, options] elsif data_set.is_a?(Array) @variables << [data_set, options] else @value_sets << [data_set, options] end end def <<(data_set) add(data_set) end def keep new_data_sets = self.class.new all_data_sets = Enumerator.new do |yielder| block = lambda do |(data_set, options)| yielder << [data_set, options] end @procs.each(&block) @variables.each(&block) @value_sets.each(&block) end all_data_sets.each do |data_set, options| next if options.nil? next unless options[:keep] new_data_sets.add(data_set, options) end new_data_sets end def each variables = @variables value_sets = @value_sets @procs.each do |proc, options| data_set = proc.call case data_set when Array variables += [[data_set, options]] else value_sets += [[data_set, options]] end end value_sets.each do |values, _options| values.each do |label, data| yield(label, data) end end each_pattern(variables) do |label, data| yield(label, data) end end def ==(other) @variables == other.instance_variable_get(:@variables) and @procs == other.instance_variable_get(:@procs) and @value_sets == other.instance_variable_get(:@value_sets) end def eql?(other) self == other end def hash [@variables, @procs, @value_sets].hash end private def each_pattern(variables) grouped_variables = variables.group_by do |_, options| options[:group] end grouped_variables.each do |group, group_variables| each_raw_pattern(group_variables) do |cell| label = String.new label << "group: #{group.inspect}" unless group.nil? data = {} cell.each do |variable, pattern| label << ", " unless label.empty? label << "#{variable}: #{pattern.inspect}" data[variable] = pattern end yield(label, data) end end end def each_raw_pattern(variables, &block) return if variables.empty? sorted_variables = variables.sort_by do |(variable, _), _| variable end all_patterns = sorted_variables.collect do |(variable, patterns), _| patterns.collect do |pattern| [variable, pattern] end end all_patterns[0].product(*all_patterns[1..-1], &block) end end end end PKu]q((+test-unit-3.3.4/lib/test/unit/assertions.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # Copyright (c) 2009-2013 Kouhei Sutou. All rights reserved. # License:: Ruby license. require 'test/unit/assertion-failed-error' require 'test/unit/util/backtracefilter' require 'test/unit/util/method-owner-finder' require 'test/unit/diff' begin require 'power_assert' rescue LoadError, SyntaxError end module Test module Unit ## # Test::Unit::Assertions contains the standard Test::Unit assertions. # Assertions is included in Test::Unit::TestCase. # # To include it in your own code and use its functionality, you simply # need to rescue Test::Unit::AssertionFailedError. Additionally you may # override add_assertion to get notified whenever an assertion is made. # # Notes: # # * The message to each assertion, if given, will be propagated with the # failure. # * It is easy to add your own assertions based on assert_block(). # # @example Example Custom Assertion # # def deny(boolean, message=nil) # message = build_message(message, ' is not false or nil.', boolean) # assert_block(message) do # not boolean # end # end module Assertions ## # The assertion upon which all other assertions are based. Passes if the # block yields true. # # @example # assert_block "Couldn't do the thing" do # do_the_thing # end def assert_block(message="assert_block failed.") _wrap_assertion do if (! yield) options = {} if message.respond_to?(:user_message) options[:user_message] = message.user_message end raise AssertionFailedError.new(message.to_s, options) end end end # @private NOT_SPECIFIED = Object.new # @overload assert(object, message=nil) # # Asserts that `object` is not false nor nil. # # Normally, you don't need to use this assertion. Use more # specific assertions such as #assert_equal and # #assert_include. # # @example Pass patterns # assert(true) # => pass # assert([1, 2].include?(1)) # => pass # # @example Failure patterns # assert(nil) # => failure # assert(false) # => failure # assert([1, 2].include?(5)) # => failure # # @param [Object] object The check target. # @param [String] message The additional user message. It is # showed when the assertion is failed. # @return [void] # # @overload assert(message=nil) {} # # Asserts that the givens block returns not false nor nil. # # This style uses Power Assert. It means that you can see each # object values in method chains on failure. See the following # example about Power Assert. # # @example Power Assert # coins = [1, 5, 50] # target_coin = 10 # assert do # coins.include?(target_coin) # end # # => # # coins.include?(target_coin) # # | | | # # | | 10 # # | false # # [1, 5, 50] # # We recommend you to use Power Assert for predicate method # checks rather than existing assertions such as # #assert_include and #assert_predicate. Power Assert shows # useful message for debugging. # # We don't recommend you use Power Assert for equality # check. You should use #assert_equal for the case. Because # #assert_equal shows more useful message for debugging. # # @example Pass patterns # assert {true} # => pass # assert {[1, 2].include?(1)} # => pass # # @example Failure patterns # assert {nil} # => failure # assert {false} # => failure # assert {[1, 2].include?(5)} # => failure # # @param [String] message The additional user message. It is # showed when the assertion is failed. # @yield [] Given no parameters to the block. # @yieldreturn [Object] The checked object. # @return [void] def assert(object=NOT_SPECIFIED, message=nil, &block) _wrap_assertion do have_object = !NOT_SPECIFIED.equal?(object) if block message = object if have_object if defined?(PowerAssert) PowerAssert.start(block, :assertion_method => __callee__) do |pa| pa_message = AssertionMessage.delayed_literal(&pa.message_proc) assertion_message = build_message(message, "?", pa_message) assert_block(assertion_message) do pa.yield end end else assert(yield, message) end else unless have_object raise ArgumentError, "wrong number of arguments (0 for 1..2)" end assertion_message = nil case message when nil, String, Proc when AssertionMessage assertion_message = message else error_message = "assertion message must be String, Proc or " error_message += "#{AssertionMessage}: " error_message += "<#{message.inspect}>(<#{message.class}>)" raise ArgumentError, error_message, filter_backtrace(caller) end assertion_message ||= build_message(message, " is not true.", object) assert_block(assertion_message) do object end end end end # Asserts that `object` is false or nil. # # @note Just for minitest compatibility. :< # # @param [Object] object The object to be asserted. # @return [void] # # @example Pass patterns # refute(false) # => pass # refute(nil) # => pass # # @example Failure patterns # refute(true) # => failure # refute("string") # => failure # # @since 2.5.3 def refute(object, message=nil) _wrap_assertion do assertion_message = nil case message when nil, String, Proc when AssertionMessage assertion_message = message else error_message = "assertion message must be String, Proc or " error_message += "#{AssertionMessage}: " error_message += "<#{message.inspect}>(<#{message.class}>)" raise ArgumentError, error_message, filter_backtrace(caller) end assert_block("refute should not be called with a block.") do !block_given? end assertion_message ||= build_message(message, " is neither nil or false.", object) assert_block(assertion_message) do not object end end end ## # Passes if `expected` == `actual`. # # Note that the ordering of arguments is important, since a helpful # error message is generated when this one fails that tells you the # values of expected and actual. # # @example # assert_equal 'MY STRING', 'my string'.upcase def assert_equal(expected, actual, message=nil) diff = AssertionMessage.delayed_diff(expected, actual) if expected.respond_to?(:encoding) and actual.respond_to?(:encoding) and expected.encoding != actual.encoding format = <(?) expected but was (?).? EOT full_message = build_message(message, format, expected, expected.encoding.name, actual, actual.encoding.name, diff) else full_message = build_message(message, < expected but was .? EOT end begin assert_block(full_message) { expected == actual } rescue AssertionFailedError => failure _set_failed_information(failure, expected, actual) raise failure # For JRuby. :< end end ## # Passes if the block raises one of the expected # exceptions. When an expected exception is an Exception # object, passes if expected_exception == actual_exception. # # @example # assert_raise(RuntimeError, LoadError) do # raise 'Boom!!!' # end # -> pass # # assert_raise do # raise Exception, 'Any exception should be raised!!!' # end # -> pass # # assert_raise(RuntimeError.new("XXX")) {raise "XXX"} # -> pass # assert_raise(MyError.new("XXX")) {raise "XXX"} # -> fail # assert_raise(RuntimeError.new("ZZZ")) {raise "XXX"} # -> fail def assert_raise(*args, &block) assert_expected_exception = Proc.new do |*_args| message, assert_exception_helper, actual_exception = _args expected = assert_exception_helper.expected_exceptions diff = AssertionMessage.delayed_diff(expected, actual_exception) full_message = build_message(message, " exception expected but was\n.?", expected, actual_exception, diff) begin assert_block(full_message) do expected == [] or assert_exception_helper.expected?(actual_exception) end rescue AssertionFailedError => failure _set_failed_information(failure, expected, actual_exception) raise failure # For JRuby. :< end end _assert_raise(assert_expected_exception, *args, &block) end # Just for minitest compatibility. :< alias_method :assert_raises, :assert_raise ## # Passes if the block raises one of the given # exceptions or sub exceptions of the given exceptions. # # @example # assert_raise_kind_of(SystemCallError) do # raise Errno::EACCES # end def assert_raise_kind_of(*args, &block) assert_expected_exception = Proc.new do |*_args| message, assert_exception_helper, actual_exception = _args expected = assert_exception_helper.expected_exceptions full_message = build_message(message, " family exception expected " + "but was\n.", expected, actual_exception) assert_block(full_message) do assert_exception_helper.expected?(actual_exception, :kind_of?) end end _assert_raise(assert_expected_exception, *args, &block) end ## # Passes if `object`.instance_of?(`klass`). When `klass` is # an array of classes, it passes if any class # satisfies +object.instance_of?(class). # # @example # assert_instance_of(String, 'foo') # -> pass # assert_instance_of([Fixnum, NilClass], 100) # -> pass # assert_instance_of([Numeric, NilClass], 100) # -> fail def assert_instance_of(klass, object, message=nil) _wrap_assertion do if klass.is_a?(Array) klasses = klass else klasses = [klass] end assert_block("The first parameter to assert_instance_of should be " + "a Class or an Array of Class.") do klasses.all? {|k| k.is_a?(Class)} end klass_message = AssertionMessage.maybe_container(klass) do |value| "<#{value}>" end full_message = build_message(message, < was expected to be instance_of\\? ? but was . EOT assert_block(full_message) do klasses.any? {|k| object.instance_of?(k)} end end end ## # Passes if `object`.instance_of?(`klass`) does not hold. # When `klass` is an array of classes, it passes if no class # satisfies +object.instance_of?(class). # # @example # assert_not_instance_of(String, 100) # -> pass # assert_not_instance_of([Fixnum, NilClass], '100') # -> pass # assert_not_instance_of([Numeric, NilClass], 100) # -> fail # # @since 3.0.0 def assert_not_instance_of(klass, object, message=nil) _wrap_assertion do if klass.is_a?(Array) klasses = klass else klasses = [klass] end assert_block("The first parameter to assert_not_instance_of should be " + "a Class or an Array of Class.") do klasses.all? {|k| k.is_a?(Class)} end klass_message = AssertionMessage.maybe_container(klass) do |value| "<#{value}>" end full_message = build_message(message, " was expected to not be instance_of\\?\n" + "? but was.", object, klass_message) assert_block(full_message) do klasses.none? {|k| object.instance_of?(k)} end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_instance_of, :assert_not_instance_of ## # Passes if `object` is nil. # # @example # assert_nil [1, 2].uniq! def assert_nil(object, message=nil) full_message = build_message(message, < was expected to be nil. EOT assert_block(full_message) { object.nil? } end ## # Passes if `object`.kind_of?(`klass`). When `klass` is # an array of classes or modules, it passes if any # class or module satisfies +object.kind_of?(class_or_module). # # @example # assert_kind_of(Object, 'foo') # -> pass # assert_kind_of([Fixnum, NilClass], 100) # -> pass # assert_kind_of([Fixnum, NilClass], "string") # -> fail def assert_kind_of(klass, object, message=nil) _wrap_assertion do if klass.is_a?(Array) klasses = klass else klasses = [klass] end assert_block("The first parameter to assert_kind_of should be " + "a kind_of Module or an Array of a kind_of Module.") do klasses.all? {|k| k.kind_of?(Module)} end klass_message = AssertionMessage.maybe_container(klass) do |value| "<#{value}>" end full_message = build_message(message, " was expected to be kind_of\\?\n" + "? but was\n" + ".", object, klass_message, object.class) assert_block(full_message) do klasses.any? {|k| object.kind_of?(k)} end end end ## # Passes if `object`.kind_of?(`klass`) does not hold. # When `klass` is an array of classes or modules, it passes only if all # classes (and modules) do not satisfy +object.kind_of?(class_or_module). # # @example # assert_not_kind_of(Fixnum, 'foo') # -> pass # assert_not_kind_of([Fixnum, NilClass], '0') # -> pass # assert_not_kind_of([Fixnum, NilClass], 100) # -> fail # # @since 3.0.0 def assert_not_kind_of(klass, object, message=nil) _wrap_assertion do if klass.is_a?(Array) klasses = klass else klasses = [klass] end assert_block("The first parameter to assert_not_kind_of should be " + "a kind_of Module or an Array of a kind_of Module.") do klasses.all? {|k| k.kind_of?(Module)} end klass_message = AssertionMessage.maybe_container(klass) do |value| "<#{value}>" end full_message = build_message(message, " was expected to not be kind_of\\?\n" + "? but was.", object, klass_message) assert_block(full_message) do klasses.none? {|k| object.kind_of?(k)} end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_kind_of, :assert_not_kind_of ## # Passes if `object` .respond_to? `method` # # @example # assert_respond_to 'bugbear', :slice def assert_respond_to(object, method, message=nil) _wrap_assertion do full_message = build_message(message, ".kind_of\\?(Symbol) or\n" + ".respond_to\\?(:to_str) expected", method, method) assert_block(full_message) do method.kind_of?(Symbol) or method.respond_to?(:to_str) end full_message = build_message(message, ".respond_to\\?(?) expected\n" + "(Class: )", object, method, object.class) assert_block(full_message) {object.respond_to?(method)} end end ## # Passes if `object` does not .respond_to? `method`. # # @example # assert_not_respond_to('bugbear', :nonexistence) # -> pass # assert_not_respond_to('bugbear', :size) # -> fail def assert_not_respond_to(object, method, message=nil) _wrap_assertion do full_message = build_message(message, ".kind_of\\?(Symbol) or\n" + ".respond_to\\?(:to_str) expected", method, method) assert_block(full_message) do method.kind_of?(Symbol) or method.respond_to?(:to_str) end full_message = build_message(message, "!.respond_to\\?(?) expected\n" + "(Class: )", object, method, object.class) assert_block(full_message) {!object.respond_to?(method)} end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_respond_to, :assert_not_respond_to ## # Passes if `pattern` =~ `string`. # # @example # assert_match(/\d+/, 'five, 6, seven') def assert_match(pattern, string, message=nil) _wrap_assertion do pattern = case(pattern) when String Regexp.new(Regexp.escape(pattern)) else pattern end full_message = build_message(message, " was expected to be =~\n.", pattern, string) assert_block(full_message) { pattern =~ string } end end ## # Passes if `actual` .equal? `expected` (i.e. they are the same # instance). # # @example # o = Object.new # assert_same o, o def assert_same(expected, actual, message=nil) full_message = build_message(message, < with id was expected to be equal\\? to with id . EOT assert_block(full_message) { actual.equal?(expected) } end ## # Compares the `object1` with `object2` using `operator`. # # Passes if object1.__send__(operator, object2) is true. # # @example # assert_operator 5, :>=, 4 def assert_operator(object1, operator, object2, message=nil) _wrap_assertion do full_message = build_message(nil, "\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator) assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)} full_message = build_message(message, < was expected to be ? . EOT assert_block(full_message) { object1.__send__(operator, object2) } end end ## # Compares the `object1` with `object2` using `operator`. # # Passes if object1.__send__(operator, object2) is not true. # # @example # assert_not_operator(5, :<, 4) # => pass # assert_not_operator(5, :>, 4) # => fail # # @since 3.0.0 def assert_not_operator(object1, operator, object2, message=nil) _wrap_assertion do full_message = build_message(nil, "\ngiven as the operator for #assert_not_operator must be a Symbol or #respond_to\\?(:to_str).", operator) assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)} full_message = build_message(message, < was expected to not be ? . EOT assert_block(full_message) { ! object1.__send__(operator, object2) } end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_operator, :assert_not_operator ## # Passes if block does not raise an exception. # # @example # assert_nothing_raised do # [1, 2].uniq # end def assert_nothing_raised(*args) _wrap_assertion do if args.last.is_a?(String) message = args.pop else message = "" end assert_exception_helper = AssertExceptionHelper.new(self, args) begin yield rescue Exception => e if ((args.empty? && !e.instance_of?(AssertionFailedError)) || assert_exception_helper.expected?(e)) failure_message = build_message(message, "Exception raised:\n?", e) assert_block(failure_message) {false} else raise end end end end ## # Flunk always fails. # # @example # flunk 'Not done testing yet.' def flunk(message="Flunked") assert_block(build_message(message)){false} end ## # Passes if ! `actual` .equal? `expected` # # @example # assert_not_same Object.new, Object.new def assert_not_same(expected, actual, message=nil) full_message = build_message(message, < with id was expected to not be equal\\? to with id . EOT assert_block(full_message) { !actual.equal?(expected) } end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_same, :assert_not_same ## # Passes if `expected` != `actual` # # @example # assert_not_equal 'some string', 5 def assert_not_equal(expected, actual, message=nil) full_message = build_message(message, " was expected to be != to\n.", expected, actual) assert_block(full_message) { expected != actual } end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_equal, :assert_not_equal ## # Passes if ! `object` .nil? # # @example # assert_not_nil '1 two 3'.sub!(/two/, '2') def assert_not_nil(object, message=nil) full_message = build_message(message, " was expected to not be nil.", object) assert_block(full_message){!object.nil?} end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_nil, :assert_not_nil ## # Passes if `regexp` !~ `string` # # @example # assert_not_match(/two/, 'one 2 three') # -> pass # assert_not_match(/three/, 'one 2 three') # -> fail def assert_not_match(regexp, string, message=nil) _wrap_assertion do assert_instance_of(Regexp, regexp, " in assert_not_match(, ...) " + "should be a Regexp.") full_message = build_message(message, " was expected to not match\n.", regexp, string) assert_block(full_message) { regexp !~ string } end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_match, :assert_not_match ## # Deprecated. Use #assert_not_match instead. # # Passes if `regexp` !~ `string` # # @example # assert_no_match(/two/, 'one 2 three') # -> pass # assert_no_match(/three/, 'one 2 three') # -> fail def assert_no_match(regexp, string, message="") _wrap_assertion do assert_instance_of(Regexp, regexp, "The first argument to assert_no_match " + "should be a Regexp.") assert_not_match(regexp, string, message) end end # @private class ThrowTagExtractor @@have_uncaught_throw_error = const_defined?(:UncaughtThrowError) UncaughtThrowPatterns = { NameError => /^uncaught throw `(.+)'$/, ArgumentError => /^uncaught throw (`.+'|.+)$/, ThreadError => /^uncaught throw `(.+)' in thread /, } def initialize(error) @error = error end def extract_tag tag = nil if @@have_uncaught_throw_error return nil unless @error.is_a?(UncaughtThrowError) tag = @error.tag else pattern = UncaughtThrowPatterns[@error.class] return nil if pattern.nil? return nil unless pattern =~ @error.message tag = $1 end normalize_tag(tag) end private def normalize_tag(tag) case tag when /\A:/ tag[1..-1].intern when /\A`(.+)'\z/ $1.intern when String tag.intern else tag end end end ## # Passes if the block throws `expected_object` # # @example # assert_throw(:done) do # throw(:done) # end def assert_throw(expected_object, message=nil, &proc) _wrap_assertion do begin catch([]) {} rescue TypeError assert_instance_of(Symbol, expected_object, "assert_throws expects the symbol that should be thrown for its first argument") end assert_block("Should have passed a block to assert_throw.") do block_given? end caught = true begin catch(expected_object) do proc.call caught = false end full_message = build_message(message, " should have been thrown.", expected_object) assert_block(full_message) {caught} rescue => error extractor = ThrowTagExtractor.new(error) tag = extractor.extract_tag raise if tag.nil? full_message = build_message(message, " was expected to be thrown but\n" + " was thrown.", expected_object, tag) flunk(full_message) end end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :assert_throws, :assert_throw ## # Passes if block does not throw anything. # # @example # assert_nothing_thrown do # [1, 2].uniq # end def assert_nothing_thrown(message=nil, &proc) _wrap_assertion do assert(block_given?, "Should have passed a block to assert_nothing_thrown") begin proc.call rescue => error extractor = ThrowTagExtractor.new(error) tag = extractor.extract_tag raise if tag.nil? full_message = build_message(message, " was thrown when nothing was expected", tag) flunk(full_message) end assert(true, "Expected nothing to be thrown") end end ## # Passes if `expected_float` and `actual_float` are equal # within `delta` tolerance. # # @example # assert_in_delta 0.05, (50000.0 / 10**6), 0.00001 def assert_in_delta(expected_float, actual_float, delta=0.001, message="") _wrap_assertion do _assert_in_delta_validate_arguments(expected_float, actual_float, delta) full_message = _assert_in_delta_message(expected_float, actual_float, delta, message) assert_block(full_message) do (expected_float.to_f - actual_float.to_f).abs <= delta.to_f end end end ## # Passes if `expected_float` and `actual_float` are # not equal within `delta` tolerance. # # @example # assert_not_in_delta(0.05, (50000.0 / 10**6), 0.00002) # -> pass # assert_not_in_delta(0.05, (50000.0 / 10**6), 0.00001) # -> fail def assert_not_in_delta(expected_float, actual_float, delta=0.001, message="") _wrap_assertion do _assert_in_delta_validate_arguments(expected_float, actual_float, delta) full_message = _assert_in_delta_message(expected_float, actual_float, delta, message, :negative_assertion => true) assert_block(full_message) do (expected_float.to_f - actual_float.to_f).abs > delta.to_f end end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :refute_in_delta, :assert_not_in_delta private def _assert_in_delta_validate_arguments(expected_float, actual_float, delta) { expected_float => "first float", actual_float => "second float", delta => "delta" }.each do |float, name| assert_respond_to(float, :to_f, "The arguments must respond to to_f; " + "the #{name} did not") end delta = delta.to_f assert_operator(delta, :>=, 0.0, "The delta should not be negative") end def _assert_in_delta_message(expected_float, actual_float, delta, message, options={}) if options[:negative_assertion] format = <<-EOT -/+ was expected to not include . EOT else format = <<-EOT -/+ was expected to include . EOT end arguments = [expected_float, delta, actual_float] normalized_expected = expected_float.to_f normalized_actual = actual_float.to_f normalized_delta = delta.to_f relation_format = nil relation_arguments = nil if normalized_actual < normalized_expected - normalized_delta relation_format = "< < -[?] <= +[?]>" relation_arguments = [actual_float, expected_float, delta, normalized_expected - normalized_delta, expected_float, delta, normalized_expected + normalized_delta] elsif normalized_actual <= normalized_expected + normalized_delta relation_format = "<-[?] <= <= +[?]>" relation_arguments = [expected_float, delta, normalized_expected - normalized_delta, actual_float, expected_float, delta, normalized_expected + normalized_delta] else relation_format = "<-[?] <= +[?] < >" relation_arguments = [expected_float, delta, normalized_expected - normalized_delta, expected_float, delta, normalized_expected + normalized_delta, actual_float] end if relation_format format += <<-EOT Relation: #{relation_format} EOT arguments.concat(relation_arguments) end build_message(message, format, *arguments) end public ## # Passes if `expected_float` and `actual_float` are equal # within `epsilon` relative error of `expected_float`. # # @example # assert_in_epsilon(10000.0, 9900.0, 0.1) # -> pass # assert_in_epsilon(10000.0, 9899.0, 0.1) # -> fail def assert_in_epsilon(expected_float, actual_float, epsilon=0.001, message="") _wrap_assertion do _assert_in_epsilon_validate_arguments(expected_float, actual_float, epsilon) full_message = _assert_in_epsilon_message(expected_float, actual_float, epsilon, message) assert_block(full_message) do normalized_expected_float = expected_float.to_f if normalized_expected_float.zero? delta = epsilon.to_f ** 2 else delta = normalized_expected_float * epsilon.to_f end delta = delta.abs (normalized_expected_float - actual_float.to_f).abs <= delta end end end ## # Passes if `expected_float` and `actual_float` are # not equal within `epsilon` relative error of # `expected_float`. # # @example # assert_not_in_epsilon(10000.0, 9900.0, 0.1) # -> fail # assert_not_in_epsilon(10000.0, 9899.0, 0.1) # -> pass def assert_not_in_epsilon(expected_float, actual_float, epsilon=0.001, message="") _wrap_assertion do _assert_in_epsilon_validate_arguments(expected_float, actual_float, epsilon) full_message = _assert_in_epsilon_message(expected_float, actual_float, epsilon, message, :negative_assertion => true) assert_block(full_message) do normalized_expected_float = expected_float.to_f delta = normalized_expected_float * epsilon.to_f (normalized_expected_float - actual_float.to_f).abs > delta end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_in_epsilon, :assert_not_in_epsilon private def _assert_in_epsilon_validate_arguments(expected_float, actual_float, epsilon) { expected_float => "first float", actual_float => "second float", epsilon => "epsilon" }.each do |float, name| assert_respond_to(float, :to_f, "The arguments must respond to to_f; " + "the #{name} did not") end epsilon = epsilon.to_f assert_operator(epsilon, :>=, 0.0, "The epsilon should not be negative") end def _assert_in_epsilon_message(expected_float, actual_float, epsilon, message, options={}) normalized_expected = expected_float.to_f normalized_actual = actual_float.to_f normalized_epsilon = epsilon.to_f delta = normalized_expected * normalized_epsilon if options[:negative_assertion] format = <<-EOT -/+ ( * )[?] was expected to not include . EOT else format = <<-EOT -/+ ( * )[?] was expected to include . EOT end arguments = [expected_float, expected_float, epsilon, delta, actual_float] relation_format = nil relation_arguments = nil if normalized_actual < normalized_expected - delta relation_format = "< < -(*)[?] <= +(*)[?]>" relation_arguments = [actual_float, expected_float, expected_float, epsilon, normalized_expected - delta, expected_float, expected_float, epsilon, normalized_expected + delta] elsif normalized_actual <= normalized_expected + delta relation_format = "<-(*)[?] <= <= +(*)[?]>" relation_arguments = [expected_float, expected_float, epsilon, normalized_expected - delta, actual_float, expected_float, expected_float, epsilon, normalized_expected + delta] else relation_format = "<-(*)[?] <= +(*)[?] < >" relation_arguments = [expected_float, expected_float, epsilon, normalized_expected - delta, expected_float, expected_float, epsilon, normalized_expected + delta, actual_float] end if relation_format format += <<-EOT Relation: #{relation_format} EOT arguments.concat(relation_arguments) end build_message(message, format, *arguments) end public ## # Passes if the method send returns a true value. # # `send_array` is composed of: # * A receiver # * A method # * Arguments to the method # # @example # assert_send([[1, 2], :member?, 1]) # -> pass # assert_send([[1, 2], :member?, 4]) # -> fail def assert_send(send_array, message=nil) _wrap_assertion do assert_instance_of(Array, send_array, "assert_send requires an array " + "of send information") assert_operator(send_array.size, :>=, 2, "assert_send requires at least a receiver " + "and a message name") format = < was expected to respond to with a true value but was . EOT receiver, message_name, *arguments = send_array result = nil full_message = build_message(message, format, receiver, AssertionMessage.literal(message_name.to_s), arguments, AssertionMessage.delayed_literal {result}) assert_block(full_message) do result = receiver.__send__(message_name, *arguments) result end end end ## # Passes if the method send doesn't return a true value. # # `send_array` is composed of: # * A receiver # * A method # * Arguments to the method # # @example # assert_not_send([[1, 2], :member?, 1]) # -> fail # assert_not_send([[1, 2], :member?, 4]) # -> pass def assert_not_send(send_array, message=nil) _wrap_assertion do assert_instance_of(Array, send_array, "assert_not_send requires an array " + "of send information") assert_operator(send_array.size, :>=, 2, "assert_not_send requires at least a receiver " + "and a message name") format = < was expected to respond to with not a true value but was . EOT receiver, message_name, *arguments = send_array result = nil full_message = build_message(message, format, receiver, AssertionMessage.literal(message_name.to_s), arguments, AssertionMessage.delayed_literal {result}) assert_block(full_message) do result = receiver.__send__(message_name, *arguments) not result end end end ## # Passes if `actual` is a boolean value. # # @example # assert_boolean(true) # -> pass # assert_boolean(nil) # -> fail def assert_boolean(actual, message=nil) _wrap_assertion do assert_block(build_message(message, " or expected but was\n", actual)) do [true, false].include?(actual) end end end ## # Passes if `actual` is true. # # @example # assert_true(true) # -> pass # assert_true(:true) # -> fail def assert_true(actual, message=nil) _wrap_assertion do assert_block(build_message(message, " expected but was\n", actual)) do actual == true end end end ## # Passes if `actual` is false. # # @example # assert_false(false) # -> pass # assert_false(nil) # -> fail def assert_false(actual, message=nil) _wrap_assertion do assert_block(build_message(message, " expected but was\n", actual)) do actual == false end end end ## # Passes if expression "`expected` `operator` # `actual`" is true. # # @example # assert_compare(1, "<", 10) # -> pass # assert_compare(1, ">=", 10) # -> fail def assert_compare(expected, operator, actual, message=nil) _wrap_assertion do assert_send([["<", "<=", ">", ">="], :include?, operator.to_s]) case operator.to_s when "<" operator_description = "less than" when "<=" operator_description = "less than or equal to" when ">" operator_description = "greater than" when ">=" operator_description = "greater than or equal to" end template = <<-EOT #{operator} should be true was expected to be #{operator_description} . EOT full_message = build_message(message, template, expected, actual, expected, actual) assert_block(full_message) do expected.__send__(operator, actual) end end end ## # Passes if assertion is failed in block. # # @example # assert_fail_assertion {assert_equal("A", "B")} # -> pass # assert_fail_assertion {assert_equal("A", "A")} # -> fail def assert_fail_assertion(message=nil) _wrap_assertion do full_message = build_message(message, "Failed assertion was expected.") assert_block(full_message) do begin yield false rescue AssertionFailedError true end end end end ## # Passes if an exception is raised in block and its # message is `expected`. # # @example # assert_raise_message("exception") {raise "exception"} # -> pass # assert_raise_message(/exc/i) {raise "exception"} # -> pass # assert_raise_message("exception") {raise "EXCEPTION"} # -> fail # assert_raise_message("exception") {} # -> fail def assert_raise_message(expected, message=nil) _wrap_assertion do full_message = build_message(message, " exception message was expected " + "but none was thrown.", expected) exception = nil assert_block(full_message) do begin yield false rescue Exception => exception true end end actual = exception.message diff = AssertionMessage.delayed_diff(expected, actual) full_message = build_message(message, " exception message expected but was\n" + ".?", expected, actual, diff) assert_block(full_message) do if expected.is_a?(Regexp) expected =~ actual else expected == actual end end end end ## # Passes if `object`.const_defined?(`constant_name`) # # @example # assert_const_defined(Test, :Unit) # -> pass # assert_const_defined(Object, :Nonexistent) # -> fail def assert_const_defined(object, constant_name, message=nil) _wrap_assertion do full_message = build_message(message, ".const_defined\\?() expected.", object, constant_name) assert_block(full_message) do object.const_defined?(constant_name) end end end ## # Passes if !`object`.const_defined?(`constant_name`) # # @example # assert_not_const_defined(Object, :Nonexistent) # -> pass # assert_not_const_defined(Test, :Unit) # -> fail def assert_not_const_defined(object, constant_name, message=nil) _wrap_assertion do full_message = build_message(message, "!.const_defined\\?() expected.", object, constant_name) assert_block(full_message) do !object.const_defined?(constant_name) end end end ## # Passes if `object`.`predicate` is _true_. # # @example # assert_predicate([], :empty?) # -> pass # assert_predicate([1], :empty?) # -> fail def assert_predicate(object, predicate, message=nil) _wrap_assertion do assert_respond_to(object, predicate, message) actual = object.__send__(predicate) full_message = build_message(message, ".? is true value expected but was\n" + "", object, AssertionMessage.literal(predicate), actual) assert_block(full_message) do actual end end end ## # Passes if `object`.`predicate` is not _true_. # # @example # assert_not_predicate([1], :empty?) # -> pass # assert_not_predicate([], :empty?) # -> fail def assert_not_predicate(object, predicate, message=nil) _wrap_assertion do assert_respond_to(object, predicate, message) actual = object.__send__(predicate) full_message = build_message(message, ".? is false value expected but was\n" + "", object, AssertionMessage.literal(predicate), actual) assert_block(full_message) do not actual end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_predicate, :assert_not_predicate ## # Passes if `object`#`alias_name` is an alias method of # `object`#`original_name`. # # @example # assert_alias_method([], :length, :size) # -> pass # assert_alias_method([], :size, :length) # -> pass # assert_alias_method([], :each, :size) # -> fail def assert_alias_method(object, alias_name, original_name, message=nil) _wrap_assertion do find_method_failure_message = Proc.new do |method_name| build_message(message, ".? doesn't exist\n" + "(Class: )", object, AssertionMessage.literal(method_name), object.class) end alias_method = original_method = nil assert_block(find_method_failure_message.call(alias_name)) do begin alias_method = object.method(alias_name) true rescue NameError false end end assert_block(find_method_failure_message.call(original_name)) do begin original_method = object.method(original_name) true rescue NameError false end end full_message = build_message(message, " is alias of\n" + " expected", alias_method, original_method) assert_block(full_message) do alias_method == original_method end end end ## # Passes if `path` exists. # # @example # assert_path_exist("/tmp") # -> pass # assert_path_exist("/bin/sh") # -> pass # assert_path_exist("/nonexistent") # -> fail def assert_path_exist(path, message=nil) _wrap_assertion do failure_message = build_message(message, " was expected to exist", path) assert_block(failure_message) do File.exist?(path) end end end ## # Passes if `path` doesn't exist. # # @example # assert_path_not_exist("/nonexistent") # -> pass # assert_path_not_exist("/tmp") # -> fail # assert_path_not_exist("/bin/sh") # -> fail def assert_path_not_exist(path, message=nil) _wrap_assertion do failure_message = build_message(message, " was expected to not exist", path) assert_block(failure_message) do not File.exist?(path) end end end ## # Passes if `collection` includes `object`. # # @example # assert_include([1, 10], 1) # -> pass # assert_include(1..10, 5) # -> pass # assert_include([1, 10], 5) # -> fail # assert_include(1..10, 20) # -> fail def assert_include(collection, object, message=nil) _wrap_assertion do assert_respond_to(collection, :include?, "The collection must respond to :include?.") full_message = build_message(message, " was expected to include\n.", collection, object) assert_block(full_message) do collection.include?(object) end end end # Just for minitest compatibility. :< # # @since 2.5.3 alias_method :assert_includes, :assert_include ## # Passes if `collection` doesn't include `object`. # # @example # assert_not_include([1, 10], 5) # -> pass # assert_not_include(1..10, 20) # -> pass # assert_not_include([1, 10], 1) # -> fail # assert_not_include(1..10, 5) # -> fail def assert_not_include(collection, object, message=nil) _wrap_assertion do assert_respond_to(collection, :include?, "The collection must respond to :include?.") full_message = build_message(message, " was expected to not include\n.", collection, object) assert_block(full_message) do not collection.include?(object) end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :assert_not_includes, :assert_not_include # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_includes, :assert_not_include ## # Passes if `object` is empty. # # @example # assert_empty("") # -> pass # assert_empty([]) # -> pass # assert_empty({}) # -> pass # assert_empty(" ") # -> fail # assert_empty([nil]) # -> fail # assert_empty({1 => 2}) # -> fail def assert_empty(object, message=nil) _wrap_assertion do assert_respond_to(object, :empty?, "The object must respond to :empty?.") full_message = build_message(message, " was expected to be empty.", object) assert_block(full_message) do object.empty? end end end ## # Passes if `object` is not empty. # # @example # assert_not_empty(" ") # -> pass # assert_not_empty([nil]) # -> pass # assert_not_empty({1 => 2}) # -> pass # assert_not_empty("") # -> fail # assert_not_empty([]) # -> fail # assert_not_empty({}) # -> fail def assert_not_empty(object, message=nil) _wrap_assertion do assert_respond_to(object, :empty?, "The object must respond to :empty?.") full_message = build_message(message, " was expected to not be empty.", object) assert_block(full_message) do not object.empty? end end end # Just for minitest compatibility. :< # # @since 3.0.0 alias_method :refute_empty, :assert_not_empty ## # Builds a failure message. `user_message` is added before the # `template` and `arguments` replaces the '?'s positionally in # the template. def build_message(user_message, template=nil, *arguments) template &&= template.chomp return AssertionMessage.new(user_message, template, arguments) end private def _wrap_assertion(&block) @_assertion_wrapped ||= false if @_assertion_wrapped block.call else @_assertion_wrapped = true begin add_assertion block.call ensure @_assertion_wrapped = false end end end public # Called whenever an assertion is made. Define this in classes # that include Test::Unit::Assertions to record assertion # counts. # # This is a public API for developers who extend test-unit. # # @return [void] def add_assertion end ## # Select whether or not to use the pretty-printer. If this option is set # to false before any assertions are made, pp.rb will not be required. def self.use_pp=(value) AssertionMessage.use_pp = value end private def _assert_raise(assert_expected_exception, *args, &block) _wrap_assertion do if args.last.is_a?(String) message = args.pop else message = "" end assert_exception_helper = AssertExceptionHelper.new(self, args) expected = assert_exception_helper.expected_exceptions actual_exception = nil full_message = build_message(message, " exception was expected " + "but none was thrown.", expected) assert_block(full_message) do begin yield false rescue Exception => actual_exception true end end assert_expected_exception.call(message, assert_exception_helper, actual_exception) actual_exception end end def _set_failed_information(failure, expected, actual) failure.expected = expected failure.actual = actual failure.inspected_expected = AssertionMessage.convert(expected) failure.inspected_actual = AssertionMessage.convert(actual) end class AssertionMessage @use_pp = true class << self attr_accessor :use_pp def literal(value) Literal.new(value) end def delayed_literal(&block) DelayedLiteral.new(block) end def maybe_container(value, &formatter) MaybeContainer.new(value, &formatter) end MAX_DIFF_TARGET_STRING_SIZE = 1000 def max_diff_target_string_size return @@max_diff_target_string_size if @@max_diff_target_string_size size = ENV["TEST_UNIT_MAX_DIFF_TARGET_STRING_SIZE"] if size begin size = Integer(size) rescue ArgumentError size = nil end end size || MAX_DIFF_TARGET_STRING_SIZE end @@max_diff_target_string_size = nil def max_diff_target_string_size=(size) @@max_diff_target_string_size = size end def diff_target_string?(string) if string.respond_to?(:bytesize) string.bytesize < max_diff_target_string_size else string.size < max_diff_target_string_size end end def ensure_diffable_string(string) if string.respond_to?(:encoding) and !string.encoding.ascii_compatible? string = string.dup.force_encoding("ASCII-8BIT") end string end def prepare_for_diff(from, to) if !from.is_a?(String) or !to.is_a?(String) from = convert(from) to = convert(to) end if diff_target_string?(from) and diff_target_string?(to) from = ensure_diffable_string(from) to = ensure_diffable_string(to) [from, to] else [nil, nil] end end def delayed_diff(from, to) delayed_literal do from, to = prepare_for_diff(from, to) diff = "" if from.nil? or to.nil? diff ||= Diff.readable(from, to) if /^[-+]/ !~ diff diff = "" elsif /^[ ?]/ =~ diff or /(?:.*\n){2,}/ =~ diff diff = "\n\ndiff:\n#{diff}" else diff = "" end if Diff.need_fold?(diff) folded_diff = Diff.folded_readable(from, to) diff += "\n\nfolded diff:\n#{folded_diff}" end diff end end def convert(object) if object.is_a?(Exception) object = AssertExceptionHelper::WrappedException.new(object) end inspector = Inspector.new(object) if use_pp begin require "pp" unless defined?(PP) begin return PP.pp(inspector, String.new).chomp rescue NameError end rescue LoadError self.use_pp = false end end inspector.inspect end end class Inspector include Comparable class << self def cached_new(object, inspected_objects) inspected_objects[object.object_id] ||= new(object, inspected_objects) end @@inspector_classes = [] def inspector_classes @@inspector_classes end def register_inspector_class(inspector_class) @@inspector_classes << inspector_class end def unregister_inspector_class(inspector_class) @@inspector_classes.delete(inspector_class) end end attr_reader :object def initialize(object, inspected_objects={}) @inspected_objects = inspected_objects @object = object @inspected_objects[@object.object_id] = self @inspect_target = inspect_target end alias_method :native_inspect, :inspect def inspect @inspect_target.inspect end def pretty_print(q) @inspect_target.pretty_print(q) end def pretty_print_cycle(q) @inspect_target.pretty_print_cycle(q) end def <=>(other) if other.is_a?(self.class) @object <=> other.object else @object <=> other end end private def inspect_target self.class.inspector_classes.each do |inspector_class| if inspector_class.target?(@object) return inspector_class.new(@object, @inspected_objects) end end @object end end class NumericInspector Inspector.register_inspector_class(self) class << self def target?(object) object.is_a?(Numeric) end end def initialize(numeric, inspected_objects) @inspected_objects = inspected_objects @numeric = numeric end def inspect @numeric.to_s end def pretty_print(q) q.text(@numeric.to_s) end def pretty_print_cycle(q) q.text(@numeric.to_s) end end class HashInspector Inspector.register_inspector_class(self) class << self def target?(object) object.is_a?(Hash) or ENV.equal?(object) end end def initialize(hash, inspected_objects) @inspected_objects = inspected_objects @hash = {} hash.each do |key, value| key = Inspector.cached_new(key, @inspected_objects) value = Inspector.cached_new(value, @inspected_objects) @hash[key] = value end end def inspect @hash.inspect end def pretty_print(q) q.group(1, '{', '}') do q.seplist(self, nil, :each_pair) do |k, v| q.group do q.pp(k) q.text('=>') q.group(1) do q.breakable('') q.pp(v) end end end end end def pretty_print_cycle(q) @hash.pretty_print_cycle(q) end def each_pair keys = @hash.keys begin keys = keys.sort # FIXME: more cleverly rescue ArgumentError end keys.each do |key| yield(key, @hash[key]) end end end class ArrayInspector Inspector.register_inspector_class(self) class << self def target?(object) object.is_a?(Array) end end def initialize(array, inspected_objects) @inspected_objects = inspected_objects @array = array.collect do |element| Inspector.cached_new(element, @inspected_objects) end end def inspect @array.inspect end def pretty_print(q) q.group(1, '[', ']') do q.seplist(self) do |v| q.pp(v) end end end def pretty_print_cycle(q) @array.pretty_print_cycle(q) end def each(&block) @array.each(&block) end end class Literal def initialize(value) @value = value end def inspect @value.to_s end end class DelayedLiteral def initialize(value) @value = value end def inspect @value.call.to_s end end class MaybeContainer def initialize(value, &formatter) @value = value @formatter = formatter end def inspect if @value.is_a?(Array) values = @value.collect do |value| @formatter.call(AssertionMessage.convert(value)) end "[#{values.join(', ')}]" else @formatter.call(AssertionMessage.convert(@value)) end end end class Template def self.create(string) parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : []) self.new(parts) end attr_reader :count def initialize(parts) @parts = parts @count = parts.find_all{|e| e == '?'}.size end def result(parameters) raise "The number of parameters does not match the number of substitutions." if(parameters.size != count) params = parameters.dup expanded_template = "" @parts.each do |part| if part == '?' param = params.shift if Object.const_defined?(:Encoding) expanded_template += concatenatable(param, expanded_template.encoding) else expanded_template += param end else expanded_template += part.gsub(/\\\?/m, '?') end end expanded_template end private def concatenatable(text, encoding) if Encoding.compatible?(text, encoding) text else text.dup.force_encoding(encoding) end end end include Util::BacktraceFilter def initialize(user_message, template_string, parameters) @user_message = user_message @template_string = template_string @parameters = parameters end def convert(object) self.class.convert(object) end def template @template ||= Template.create(@template_string) end def user_message return nil unless @user_message message = @user_message message = message.call if message.respond_to?(:call) message.to_s end def to_s message_parts = [] head = user_message if head and not head.empty? message_parts << add_period(head) end tail = template.result(@parameters.collect{|e| convert(e)}) message_parts << tail unless(tail.empty?) message_parts.join("\n") end private def add_period(string) (string =~ /\.\Z/ ? string : string + '.') end end class AssertExceptionHelper class WrappedException attr_reader :exception def initialize(exception) @exception = exception end def inspect if default_inspect? "#{@exception.class.inspect}(<#{@exception.message}>)" else @exception.inspect end end def method_missing(name, *args, &block) @exception.__send__(name, *args, &block) end private def default_inspect? inspect_method = @exception.method(:inspect) if inspect_method.respond_to?(:owner) and inspect_method.owner == Exception true else default_inspect_method = Exception.instance_method(:inspect) default_inspect_method.bind(@exception).call == @exception.inspect end end end def initialize(test_case, expected_exceptions) @test_case = test_case @expected_exceptions = expected_exceptions @expected_classes, @expected_modules, @expected_objects = split_expected_exceptions(expected_exceptions) end def expected_exceptions exceptions = @expected_exceptions.collect do |exception| if exception.is_a?(Exception) WrappedException.new(exception) else exception end end if exceptions.size == 1 exceptions[0] else exceptions end end def expected?(actual_exception, equality=nil) equality ||= :instance_of? expected_class?(actual_exception, equality) or expected_module?(actual_exception) or expected_object?(actual_exception) end private def split_expected_exceptions(expected_exceptions) exception_modules = [] exception_objects = [] exception_classes = [] expected_exceptions.each do |exception_type| if exception_type.instance_of?(Module) exception_modules << exception_type elsif exception_object?(exception_type) exception_objects << exception_type elsif exception_class?(exception_type) exception_classes << exception_type else full_message = @test_case.__send__(:build_message, nil, " must be " + "a subclass of Exception, " + "an object of Exception subclasses " + "or a Module", exception_type) @test_case.flunk(full_message) end end [exception_classes, exception_modules, exception_objects] end def exception_object?(exception_type) return true if exception_type.is_a?(Exception) if Object.const_defined?(:Java) return true if exception_type.is_a?(Java::JavaLang::Throwable) end false end def exception_class?(exception_type) return true if exception_type <= Exception if Object.const_defined?(:Java) return true if exception_type <= Java::JavaLang::Throwable end false end def expected_class?(actual_exception, equality) @expected_classes.any? do |expected_class| actual_exception.__send__(equality, expected_class) end end def expected_module?(actual_exception) @expected_modules.any? do |expected_module| actual_exception.is_a?(expected_module) end end def expected_object?(actual_exception) @expected_objects.any? do |expected_object| expected_object == actual_exception or fallback_exception_object_equal(expected_object, actual_exception) end end def fallback_exception_object_equal(expected_object, actual_exception) owner = Util::MethodOwnerFinder.find(expected_object, :==) if owner == Kernel or owner == Exception expected_object.class == actual_exception.class and expected_object.message == actual_exception.message else false end end end # :startdoc: end end end PKu] +test-unit-3.3.4/lib/test/unit/testresult.rbnu[#-- # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/observable' require 'test/unit/failure' require 'test/unit/error' require 'test/unit/omission' require 'test/unit/pending' require 'test/unit/notification' module Test module Unit module NullResultContainerInitializer private def initialize_containers end end # Collects Test::Unit::Failure and Test::Unit::Error so that # they can be displayed to the user. To this end, observers # can be added to it, allowing the dynamic updating of, say, a # UI. class TestResult include Util::Observable include NullResultContainerInitializer include TestResultFailureSupport include TestResultErrorSupport include TestResultPendingSupport include TestResultOmissionSupport include TestResultNotificationSupport FINISHED = name + "::FINISHED" CHANGED = name + "::CHANGED" PASS_ASSERTION = name + "::PASS_ASSERTION" FAULT = name + "::FAULT" attr_reader :run_count, :pass_count, :assertion_count, :faults attr_accessor :stop_tag # Constructs a new, empty TestResult. def initialize @run_count, @pass_count, @assertion_count = 0, 0, 0 @summary_generators = [] @problem_checkers = [] @faults = [] @stop_tag = nil initialize_containers end # Records a test run. def add_run @run_count += 1 notify_listeners(FINISHED, self) notify_changed end def add_pass @pass_count += 1 end # Records an individual assertion. def add_assertion @assertion_count += 1 notify_listeners(PASS_ASSERTION, self) notify_changed end # Returns a string contain the recorded runs, assertions, # failures and errors in this TestResult. def summary ["#{run_count} tests", "#{assertion_count} assertions", *@summary_generators.collect {|generator| __send__(generator)}].join(", ") end # Returnes a string that shows result status. def status if passed? if pending_count > 0 "pending" elsif omission_count > 0 "omission" elsif notification_count > 0 "notification" else "pass" end elsif error_count > 0 "error" elsif failure_count > 0 "failure" end end def stop throw @stop_tag end def to_s summary end # Returns whether or not this TestResult represents # successful completion. def passed? @problem_checkers.all? {|checker| not __send__(checker)} end def pass_percentage n_tests = @run_count - omission_count if n_tests.zero? 0 else 100.0 * (@pass_count / n_tests.to_f) end end private def notify_changed notify_listeners(CHANGED, self) end def notify_fault(fault) @faults << fault notify_listeners(FAULT, fault) end end end end PKu]Uį(test-unit-3.3.4/lib/test/unit/pending.rbnu[require 'test/unit/util/backtracefilter' module Test module Unit class Pending include Util::BacktraceFilter attr_reader :test_name, :location, :message attr_reader :method_name SINGLE_CHARACTER = 'P' LABEL = "Pending" # Creates a new Pending with the given location and # message. def initialize(test_name, location, message, options={}) @test_name = test_name @location = location @message = message @method_name = options[:method_name] end # Returns a single character representation of a pending. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns a brief version of the error description. def short_display "#{@test_name}: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace = filter_backtrace(location).join("\n") "#{label}: #{@message}\n#{@test_name}\n#{backtrace}" end # Overridden to return long_display. def to_s long_display end def critical? true end end class PendedError < StandardError end module TestCasePendingSupport class << self def included(base) base.class_eval do include PendingHandler end end end # Marks the test or part of the test is pending. # # Example: # # def test_pending # pend # # Not reached here # end # # def test_pending_with_here # pend do # # Ran here # # Fails if the block doesn't raise any error. # # Because it means the block is passed unexpectedly. # end # # Reached here # end def pend(message=nil, &block) message ||= "pended." if block_given? pending = nil begin yield rescue Exception pending = Pending.new(name, filter_backtrace(caller), message, :method_name => @method_name) add_pending(pending) end unless pending flunk("Pending block should not be passed: #{message}") end else raise PendedError.new(message) end end private def add_pending(pending) problem_occurred current_result.add_pending(pending) end end module PendingHandler class << self def included(base) base.exception_handler(:handle_pended_error) end end private def handle_pended_error(exception) return false unless exception.is_a?(PendedError) pending = Pending.new(name, filter_backtrace(exception.backtrace), exception.message, :method_name => @method_name) add_pending(pending) true end end module TestResultPendingSupport attr_reader :pendings # Records a Test::Unit::Pending. def add_pending(pending) @pendings << pending notify_fault(pending) notify_changed end # Returns the number of pendings this TestResult has # recorded. def pending_count @pendings.size end private def initialize_containers super @pendings = [] @summary_generators << :pending_summary end def pending_summary "#{pending_count} pendings" end end end end PKu]Dddd)test-unit-3.3.4/lib/test/unit/omission.rbnu[require 'test/unit/util/backtracefilter' module Test module Unit class Omission include Util::BacktraceFilter attr_reader :test_name, :location, :message attr_reader :method_name SINGLE_CHARACTER = 'O' LABEL = "Omission" # Creates a new Omission with the given location and # message. def initialize(test_name, location, message, options={}) @test_name = test_name @location = location @message = message @method_name = options[:method_name] end # Returns a single character representation of a omission. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns a brief version of the error description. def short_display "#{@test_name}: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace = filter_backtrace(location).join("\n") "#{label}: #{@message}\n#{@test_name}\n#{backtrace}" end # Overridden to return long_display. def to_s long_display end def critical? true end end class OmittedError < StandardError end module TestCaseOmissionSupport class << self def included(base) base.class_eval do include OmissionHandler end end end # Omit the test or part of the test. # # Example: # # def test_omission # omit # # Not reached here # end # # def test_omission_with_here # omit do # # Not ran here # end # # Reached here # end def omit(message=nil, &block) message ||= "omitted." if block_given? omission = Omission.new(name, filter_backtrace(caller), message, :method_name => @method_name) add_omission(omission) else raise OmittedError.new(message) end end # Omit the test or part of the test if _condition_ is # true. # # Example: # # def test_omission # omit_if("".empty?) # # Not reached here # end # # def test_omission_with_here # omit_if(true) do # # Not ran here # end # omit_if(false) do # # Reached here # end # # Reached here too # end def omit_if(condition, *args, &block) if condition omit(*args, &block) else block.call if block end end # Omit the test or part of the test if _condition_ is # not true. # # Example: # # def test_omission # omit_unless("string".empty?) # # Not reached here # end # # def test_omission_with_here # omit_unless(true) do # # Reached here # end # omit_unless(false) do # # Not ran here # end # # Reached here too # end def omit_unless(condition, *args, &block) if condition block.call if block else omit(*args, &block) end end private def add_omission(omission) current_result.add_omission(omission) end end module OmissionHandler class << self def included(base) base.exception_handler(:handle_omitted_error) end end private def handle_omitted_error(exception) return false unless exception.is_a?(OmittedError) omission = Omission.new(name, filter_backtrace(exception.backtrace), exception.message, :method_name => @method_name) add_omission(omission) true end end module TestResultOmissionSupport attr_reader :omissions # Records a Test::Unit::Omission. def add_omission(omission) @omissions << omission notify_fault(omission) notify_changed end # Returns the number of omissions this TestResult has # recorded. def omission_count @omissions.size end private def initialize_containers super @omissions = [] @summary_generators << :omission_summary end def omission_summary "#{omission_count} omissions" end end end end PKu]soo&test-unit-3.3.4/lib/test/unit/error.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/backtracefilter' module Test module Unit # Encapsulates an error in a test. Created by # Test::Unit::TestCase when it rescues an exception thrown # during the processing of a test. class Error include Util::BacktraceFilter attr_reader :test_name, :exception attr_reader :method_name SINGLE_CHARACTER = 'E' LABEL = "Error" # Creates a new Error with the given test_name and # exception. def initialize(test_name, exception, options={}) @test_name = test_name @exception = exception @method_name = options[:method_name] end # Returns a single character representation of an error. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns the message associated with the error. def message "#{@exception.class.name}: #{@exception.message}" end # Returns a brief version of the error description. def short_display "#@test_name: #{message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace_display = location.join("\n ") "#{label}:\n#@test_name:\n#{message}\n #{backtrace_display}" end def location @location ||= filter_backtrace(@exception.backtrace) end alias_method :backtrace, :location # Deprecated # Overridden to return long_display. def to_s long_display end def critical? true end end module ErrorHandler class << self def included(base) base.exception_handler(:handle_all_exception) end end NOT_PASS_THROUGH_EXCEPTIONS = [] NOT_PASS_THROUGH_EXCEPTION_NAMES = ["Timeout::Error"] PASS_THROUGH_EXCEPTIONS = [ NoMemoryError, SignalException, Interrupt, SystemExit, ] PASS_THROUGH_EXCEPTION_NAMES = [] private def handle_all_exception(exception) return false if pass_through_exception?(exception) problem_occurred add_error(exception) true end def pass_through_exception?(exception) case exception when *NOT_PASS_THROUGH_EXCEPTIONS return false end case exception.class.name when *NOT_PASS_THROUGH_EXCEPTION_NAMES return false end case exception when *PASS_THROUGH_EXCEPTIONS return true end case exception.class.name when *PASS_THROUGH_EXCEPTION_NAMES return true end false end def add_error(exception) error = Error.new(name, exception, :method_name => @method_name) current_result.add_error(error) end end module TestResultErrorSupport attr_reader :errors # Records a Test::Unit::Error. def add_error(error) @errors << error notify_fault(error) notify_changed end # Returns the number of errors this TestResult has # recorded. def error_count @errors.size end def error_occurred? not @errors.empty? end private def initialize_containers super @errors = [] @summary_generators << :error_summary @problem_checkers << :error_occurred? end def error_summary "#{error_count} errors" end end end end PKu] /44*test-unit-3.3.4/lib/test/unit/testsuite.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # Copyright:: Copyright (c) 2008-2011 Kouhei Sutou. All rights reserved. # License:: Ruby license. require 'test/unit/error' module Test module Unit # A collection of tests which can be #run. # # Note: It is easy to confuse a TestSuite instance with # something that has a static suite method; I know because _I_ # have trouble keeping them straight. Think of something that # has a suite method as simply providing a way to get a # meaningful TestSuite instance. class TestSuite attr_reader :name, :tests, :test_case, :start_time, :elapsed_time # Test suite that has higher priority is ran prior to # test suites that have lower priority. attr_accessor :priority STARTED = name + "::STARTED" STARTED_OBJECT = name + "::STARTED::OBJECT" FINISHED = name + "::FINISHED" FINISHED_OBJECT = name + "::FINISHED::OBJECT" # Creates a new TestSuite with the given name. def initialize(name="Unnamed TestSuite", test_case=nil) @name = name @tests = [] @test_case = test_case @n_tests = 0 @priority = 0 @start_time = nil @elapsed_time = nil @passed = true end # Runs the tests and/or suites contained in this # TestSuite. def run(result, &progress_block) @start_time = Time.now yield(STARTED, name) yield(STARTED_OBJECT, self) run_startup(result) while test = @tests.shift @n_tests += test.size run_test(test, result, &progress_block) @passed = false unless test.passed? end ensure begin run_shutdown(result) ensure @elapsed_time = Time.now - @start_time yield(FINISHED, name) yield(FINISHED_OBJECT, self) end end # Adds the test to the suite. def <<(test) @tests << test self end def delete(test) @tests.delete(test) end def delete_tests(tests) @tests -= tests end # Retuns the rolled up number of tests in this suite; # i.e. if the suite contains other suites, it counts the # tests within those suites, not the suites themselves. def size total_size = @n_tests @tests.each { |test| total_size += test.size } total_size end def empty? size.zero? end # Overridden to return the name given the suite at # creation. def to_s @name end # It's handy to be able to compare TestSuite instances. def ==(other) return false unless(other.kind_of?(self.class)) return false unless(@name == other.name) @tests == other.tests end def passed? @passed end private def run_startup(result) return if @test_case.nil? or !@test_case.respond_to?(:startup) begin @test_case.startup rescue Exception raise unless handle_exception($!, result) end end def run_test(test, result) finished_is_yielded = false finished_object_is_yielded = false previous_event_name = nil test.run(result) do |event_name, *args| case previous_event_name when Test::Unit::TestCase::STARTED if event_name != Test::Unit::TestCase::STARTED_OBJECT yield(Test::Unit::TestCase::STARTED_OBJECT, test) end when Test::Unit::TestCase::FINISHED if event_name != Test::Unit::TestCase::FINISHED_OBJECT yield(Test::Unit::TestCase::FINISHED_OBJECT, test) end finished_object_is_yielded = true end case event_name when Test::Unit::TestCase::STARTED finished_is_yielded = false finished_object_is_yielded = false when Test::Unit::TestCase::FINISHED finished_is_yielded = true end previous_event_name = event_name yield(event_name, *args) end if finished_is_yielded and not finished_object_is_yielded yield(Test::Unit::TestCase::FINISHED_OBJECT, test) end end def run_shutdown(result) return if @test_case.nil? or !@test_case.respond_to?(:shutdown) begin @test_case.shutdown rescue Exception raise unless handle_exception($!, result) end end def handle_exception(exception, result) case exception when *ErrorHandler::PASS_THROUGH_EXCEPTIONS false else result.add_error(Error.new(@test_case.name, exception)) @passed = false true end end end end end PKu]*test-unit-3.3.4/lib/test/unit/attribute.rbnu[module Test module Unit module Attribute class StringifyKeyHash < Hash class << self def stringify(object) object.to_s end end def key?(key) super(self.class.stringify(key)) end def [](key) super(self.class.stringify(key)) end def []=(key, value) super(self.class.stringify(key), value) end end class << self def included(base) base.extend(BaseClassMethods) base.extend(ClassMethods) end end module BaseClassMethods def attributes_table {} end end module ClassMethods def method_added(name) super return unless defined?(@current_attributes) attributes = {} kept_attributes = StringifyKeyHash.new @current_attributes.each do |attribute_name, attribute| attributes[attribute_name] = attribute[:value] if attribute[:keep] keep_hook = attribute[:keep_hook] attribute = keep_hook.call(attribute) if keep_hook kept_attributes[attribute_name] = attribute end end set_attributes(name, attributes) @current_attributes = kept_attributes end # Set an attribute to test methods. # # @overload attribute(name, value) # @example # attribute :speed, :slow # def test_my_slow_method # self[:speed] # => :slow # end # # @param [Object] name the attribute name # @param [Object] value the attribute value # @return [void] # # @overload attribute(name, value, *method_names) # @example # def test_my_slow_method1 # self[:speed] # => :slow # end # # attribute :speed, :slow, :test_my_slow_method1, :test_my_slow_method2 # # def test_my_slow_method2 # self[:speed] # => :slow # end # # @param [Object] name the attribute name # @param [Object] value the attribute value # @param [Array] method_names the test method names set the attribute # @return [void] # # @overload attribute(name, value, options) # @example # attribute :speed, :slow, keep: true # def test_my_slow_method1 # self[:speed] # => :slow # end # # def test_my_slow_method2 # self[:speed] # => :slow # end # # @param [Object] name the attribute name # @param [Object] value the attribute value # @option options [Boolean] :keep whether or not to set attribute to following test methods # @return [void] # # @overload attribute(name, value, options, *method_names) # @example # def test_my_slow_method1 # self[:speed] # => :slow # end # # # There are no valid options for now. # attribute :speed, :slow, {}, :test_my_slow_method1 # # def test_my_slow_method2 # self[:speed] # => nil # end # # @param [Object] name the attribute name # @param [Object] value the attribute value # @param [Hash] options ignored # @param [Array] method_names the test method names set the attribute # @return [void] def attribute(name, value, options={}, *method_names) unless options.is_a?(Hash) method_names << options options = {} end if method_names.empty? current_attributes[name] = options.merge(:value => value) else method_names.each do |method_name| set_attributes(method_name, {name => value}) end end end def current_attributes @current_attributes ||= StringifyKeyHash.new end def current_attribute(name) current_attributes[name] || StringifyKeyHash.new end def attributes_table @attributes_table ||= StringifyKeyHash.new super.merge(@attributes_table) end def set_attributes(method_name, new_attributes) return if new_attributes.empty? @attributes_table ||= StringifyKeyHash.new @attributes_table[method_name] ||= StringifyKeyHash.new current_attributes = @attributes_table[method_name] new_attributes.each do |key, value| observers = attribute_observers(key) || [] observers.each do |observer| observer.call(self, StringifyKeyHash.stringify(key), (attributes(method_name) || {})[key], value, method_name) end current_attributes[key] = value end end def attributes(method_name) attributes = attributes_table[method_name] ancestors.each do |ancestor| next if ancestor == self if ancestor.is_a?(Class) and ancestor < Test::Unit::Attribute parent_attributes = ancestor.attributes(method_name) if attributes attributes = (parent_attributes || {}).merge(attributes) else attributes = parent_attributes end break end end attributes || StringifyKeyHash.new end def find_attribute(method_name, name, options={}) recursive_p = options[:recursive] recursive_p = true if recursive_p.nil? @attributes_table ||= StringifyKeyHash.new if @attributes_table.key?(method_name) attributes = @attributes_table[method_name] if attributes.key?(name) return attributes[name] end end return nil unless recursive_p return nil if self == TestCase @cached_parent_test_case ||= ancestors.find do |ancestor| ancestor != self and ancestor.is_a?(Class) and ancestor < Test::Unit::Attribute end @cached_parent_test_case.find_attribute(method_name, name, options) end @@attribute_observers = StringifyKeyHash.new def register_attribute_observer(attribute_name, observer=nil, &block) observer ||= Proc.new(&block) @@attribute_observers[attribute_name] ||= [] @@attribute_observers[attribute_name] << observer end def attribute_observers(attribute_name) @@attribute_observers[attribute_name] end end def attributes self.class.attributes(@method_name) || StringifyKeyHash.new end def [](name) self.class.find_attribute(@method_name, name) end end end end PKu] ,E)test-unit-3.3.4/lib/test/unit/priority.rbnu[require "fileutils" module Test module Unit module Priority class << self def included(base) base.extend(ClassMethods) base.class_eval do setup :priority_setup, :before => :prepend teardown :priority_teardown, :after => :append end end @@enabled = false def enabled? @@enabled end def enable require "fileutils" require "tmpdir" @@enabled = true end def disable @@enabled = false end @@default = :normal def default @@default || :normal end def default=(default) @@default = default end def available_values Checker.available_priorities end end class Checker class << self def have_priority?(name) singleton_class = (class << self; self; end) singleton_class.method_defined?(priority_check_method_name(name)) end def need_to_run?(test) priority = test[:priority] || Priority.default if have_priority?(priority) __send__(priority_check_method_name(priority), test) else true end end def available_priorities methods(false).collect do |name| /\Arun_priority_(.+)\?\z/ =~ name.to_s $1 end.compact end def run_priority_must?(test) true end def run_priority_important?(test) rand > 0.1 end def run_priority_high?(test) rand > 0.3 end def run_priority_normal?(test) rand > 0.5 end def run_priority_low?(test) rand > 0.75 end def run_priority_never?(test) false end private def priority_check_method_name(priority_name) "run_priority_#{priority_name}?" end end attr_reader :test def initialize(test) @test = test end def setup FileUtils.rm_f(passed_file) end def teardown if @test.__send__(:passed?) FileUtils.touch(passed_file) else FileUtils.rm_f(passed_file) end end def need_to_run? !previous_test_success? or self.class.need_to_run?(@test) end private def previous_test_success? File.exist?(passed_file) end def result_dir components = [ ".test-result", escape_class_name(@test.class.name || "AnonymousTestCase"), escaped_method_name, ] parent_directories = [File.dirname($0), Dir.pwd] if Process.respond_to?(:uid) parent_directories << File.join(Dir.tmpdir, Process.uid.to_s) end parent_directories.each do |parent_directory| dir = File.expand_path(File.join(parent_directory, *components)) begin FileUtils.mkdir_p(dir) return dir rescue Errno::EACCES end end raise Errno::EACCES, parent_directories.join(", ") end def passed_file File.join(result_dir, "passed") end def escape_class_name(class_name) escape_name(class_name) end def escaped_method_name escape_name(@test.method_name.to_s) end def escape_name(name) name.gsub(/(?:[: \/!?=])/) do |matched| case matched when ":" "_colon_" when " ", "/" "_" when "!" ".destructive" when "?" ".predicate" when "=" ".equal" end end end end module ClassMethods def priority(name, *tests) unless Checker.have_priority?(name) raise ArgumentError, "unknown priority: #{name}" end attribute(:priority, name, {:keep => true}, *tests) end end def priority_setup return unless Priority.enabled? Checker.new(self).setup end def priority_teardown return unless Priority.enabled? Checker.new(self).teardown end end end end PKu]R!\c\c)test-unit-3.3.4/lib/test/unit/testcase.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: # * Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # * Copyright (c) 2008-2012 Kouhei Sutou # License:: Ruby license. require 'test/unit/attribute' require 'test/unit/fixture' require 'test/unit/exception-handler' require 'test/unit/assertions' require 'test/unit/failure' require 'test/unit/error' require 'test/unit/pending' require 'test/unit/omission' require 'test/unit/notification' require 'test/unit/priority' require 'test/unit/data' require 'test/unit/testsuite' require 'test/unit/test-suite-creator' require 'test/unit/assertion-failed-error' require 'test/unit/auto-runner-loader' require 'test/unit/util/backtracefilter' require 'test/unit/util/output' require 'test/unit/util/method-owner-finder' module Test module Unit # Ties everything together. If you subclass and add your own # test methods, it takes care of making them into tests and # wrapping those tests into a suite. It also does the # nitty-gritty of actually running an individual test and # collecting its results into a Test::Unit::TestResult object. # # You can run two hooks before/after a TestCase run. # # Example: # # class TestMyClass < Test::Unit::TestCase # class << self # def startup # ... # end # # def shutdown # ... # end # end # # def setup # ... # end # # def cleanup # ... # end # # def teardown # ... # end # # def test_my_method1 # ... # end # # def test_my_method2 # ... # end # end # # Here is a call order: # # 1. startup # 1. setup # 1. test_my_method1 # 1. cleanup # 1. teardown # 1. setup # 1. test_my_method2 # 1. cleanup # 1. teardown # 1. shutdown # # You can set an attribute to each test. # # Example: # # class TestMyClass < Test::Unit::TestCase # attribute :speed, :fast # def test_my_fast_method # # You can get the attribute via `self[]` # self[:speed] # => :fast # ... # end # # attribute :speed, :slow # def test_my_slow_method # self[:speed] # => :slow # ... # end # end class TestCase include Attribute include Fixture include ExceptionHandler include ErrorHandler include FailureHandler include TestCasePendingSupport include TestCaseOmissionSupport include TestCaseNotificationSupport include Priority include Data include Assertions include Util::BacktraceFilter include Util::Output STARTED = name + "::STARTED" # :nodoc: FINISHED = name + "::FINISHED" # :nodoc: STARTED_OBJECT = name + "::STARTED::OBJECT" # :nodoc: FINISHED_OBJECT = name + "::FINISHED::OBJECT" # :nodoc: DESCENDANTS = [] # :nodoc: AVAILABLE_ORDERS = [:alphabetic, :random, :defined] # :nodoc: class << self def inherited(sub_class) # :nodoc: DESCENDANTS << sub_class super end def include(*modules, &block) # :nodoc: super modules.each do |mod| mod.public_instance_methods(false).each do |method_name| AutoRunnerLoader.check(self, method_name.to_s) end end end @@added_method_names = {} def method_added(name) # :nodoc: super added_method_names = (@@added_method_names[self] ||= {}) stringified_name = name.to_s if added_method_names.key?(stringified_name) attribute(:redefined, {:backtrace => caller}, {}, stringified_name) end source_location = find_attribute(stringified_name, :source_location) if source_location path, line = source_location elsif respond_to?(:caller_locations, true) location = caller_locations(1, 1)[0] path = location.absolute_path || location.path line = location.lineno else # TODO: Remove me when Ruby 1.9 support is dropped path, line, = caller[0].split(/:(\d+)/, 2) line = line.to_i if line end location = { :method_name => stringified_name, :path => File.expand_path(path), :line => line, } add_method_location(location) added_method_names[stringified_name] = true AutoRunnerLoader.check(self, stringified_name) end def added_method_names # :nodoc: (@@added_method_names[self] ||= {}).keys end # Rolls up all of the test* methods in the fixture into # one suite, creating a new instance of the fixture for # each method. def suite suite_creator = TestSuiteCreator.new(self) suite_creator.create end # Called before every test case runs. Can be used # to set up fixture information used in test case # scope. # # Here is an example test case: # # class TestMyClass < Test::Unit::TestCase # class << self # def startup # ... # end # end # # def setup # ... # end # # def test_my_class1 # ... # end # # def test_my_class2 # ... # end # end # # Here is a call order: # # * startup # * setup # * test_my_class1 (or test_my_class2) # * setup # * test_my_class2 (or test_my_class1) # # Note that you should not assume test order. Tests # should be worked in any order. def startup end # Called after every test case runs. Can be used to tear # down fixture information used in test case scope. # # Here is an example test case: # # class TestMyClass < Test::Unit::TestCase # class << self # def shutdown # ... # end # end # # def teardown # ... # end # # def test_my_class1 # ... # end # # def test_my_class2 # ... # end # end # # Here is a call order: # # * test_my_class1 (or test_my_class2) # * teardown # * test_my_class2 (or test_my_class1) # * teardown # * shutdown # # Note that you should not assume test order. Tests # should be worked in any order. def shutdown end @@test_orders = {} # Returns the current test order. This returns # `:alphabetic` by default. def test_order ancestors.each do |ancestor| order = @@test_orders[ancestor] return order if order end AVAILABLE_ORDERS.first end # Sets the current test order. # # Here are the available _order_: # # :alphabetic # : Default. Tests are sorted in alphabetic order. # # :random # : Tests are sorted in random order. # # :defined # : Tests are sorted in defined order. def test_order=(order) @@test_orders[self] = order end # Defines a test in declarative syntax or marks # following method as a test method. # # In declarative syntax usage, the following two # test definitions are the almost same: # # description "register user" # def test_register_user # ... # end # # test "register user" do # ... # end # # In test method mark usage, the "my_test_method" is # treated as a test method: # # test # def my_test_method # assert_equal("call me", ...) # end def test(*test_description_or_targets, &block) if block_given? test_description = test_description_or_targets.first if test_description.nil? raise ArgumentError, "test description is missing" end n_arguments = test_description_or_targets.size if n_arguments > 1 message = "wrong number of arguments (#{n_arguments} for 1)" raise ArgumentError, message end method_name = "test: #{test_description}" description(test_description, method_name) attribute(:test, true, {}, method_name) if block.respond_to?(:source_location) attribute(:source_location, block.source_location, {}, method_name) end define_method(method_name, &block) else targets = test_description_or_targets attribute(:test, true, {}, *targets) targets.each do |target| AutoRunnerLoader.check(self, target) end end end # Describes a test. # # The following example associates "register a # normal user" description with "test_register" # test. # # description "register a normal user" # def test_register # ... # end def description(value, target=nil) targets = [target].compact attribute(:description, value, {}, *targets) end # Defines a sub test case. # # This is a syntax sugar. The both of the following codes are # the same in meaning: # # Standard: # # class TestParent < Test::Unit::TestCase # class TestChild < self # def test_in_child # end # end # end # # Syntax sugar: # # class TestParent < Test::Unit::TestCase # sub_test_case("TestChild") do # def test_in_child # end # end # end # # The difference of them are the following: # # * Test case created by {sub_test_case} is an anonymous class. # So you can't refer the test case by name. # * The class name of class style must follow # constant naming rule in Ruby. But the name of test case # created by {sub_test_case} doesn't need to follow the rule. # For example, you can use a space in name such as "child test". # # @param name [String] The name of newly created sub test case. # @yield # The block is evaluated under the newly created sub test # case class context. # @return [Test::Unit::TestCase] Created sub test case class. def sub_test_case(name, &block) parent_test_case = self sub_test_case = Class.new(self) do singleton_class = class << self; self; end singleton_class.__send__(:define_method, :name) do [parent_test_case.name, name].compact.join("::") end end sub_test_case.class_eval(&block) sub_test_case end # Checks whether a test that is matched the query is # defined. # # @option query [String] :path (nil) # the path where a test is defined in. # @option query [Numeric] :line (nil) # the line number where a test is defined at. # @option query [String] :method_name (nil) # the method name for a test. def test_defined?(query) locations = find_locations(query) not locations.empty? end def find_locations(query) query_path = query[:path] query_line = query[:line] query_method_name = query[:method_name] available_locations = target_method_locations(query_path) if query_line available_locations = available_locations.sort_by do |location| -location[:line] end available_location = available_locations.find do |location| query_line >= location[:line] end return [] if available_location.nil? return [] if available_location[:test_case] != self available_locations = [available_location] end if query_method_name available_location = available_locations.find do |location| location[:test_case] == self and query_method_name == location[:method_name] end return [] if available_location.nil? available_locations = [available_location] end available_locations end private # @private @@method_locations = {} # @private @@method_location_mutex = Mutex.new # @private def method_locations @@method_locations[self] ||= [] end # @private def add_method_location(location) @@method_location_mutex.synchronize do method_locations << location end end # @private def target_method_locations(path) @@method_location_mutex.synchronize do if path.nil? self_location = method_locations.first path = self_location[:path] if self_location end return [] if path.nil? target_locations = [] @@method_locations.each do |test_case, locations| locations.each do |location| absolete_path = File.expand_path(path) location_path = location[:path] location_basename = File.basename(location_path) if location_path == absolete_path or location_basename == path target_locations << location.merge(:test_case => test_case) end end end target_locations end end end attr_reader :method_name # Creates a new instance of the fixture for running the # test represented by test_method_name. def initialize(test_method_name) @method_name = test_method_name @internal_data = InternalData.new end # Assigns test data to the test. It is used in internal. def assign_test_data(label, data) # :nodoc: @internal_data.assign_test_data(label, data) end # Returns the test is valid test. It is used in internal. def valid? # :nodoc: return false unless respond_to?(@method_name) test_method = method(@method_name) unless @internal_data.have_test_data? return false unless test_method.arity <= 0 end owner = Util::MethodOwnerFinder.find(self, @method_name) if owner.class != Module and self.class != owner return false end true end # Runs the individual test method represented by this # instance of the fixture, collecting statistics, failures # and errors in result. def run(result) begin @_result = result @internal_data.test_started yield(STARTED, name) yield(STARTED_OBJECT, self) processed_exception_in_setup = false begin catch do |tag| run_setup do begin run_test run_cleanup add_pass rescue Exception @internal_data.interrupted unless handle_exception($!) processed_exception_in_setup = true raise end throw(tag) end end end rescue Exception if processed_exception_in_setup raise else @internal_data.interrupted raise unless handle_exception($!) end ensure begin run_teardown rescue Exception raise unless handle_exception($!) end end @internal_data.test_finished result.add_run yield(FINISHED, name) yield(FINISHED_OBJECT, self) ensure # @_result = nil # For test-spec's after_all :< end end # Called before every test method runs. Can be used # to set up fixture information. # # You can add additional setup tasks by the following # code: # # class TestMyClass < Test::Unit::TestCase # def setup # ... # end # # setup # def my_setup1 # ... # end # # setup do # ... # setup callback1 # end # # setup # def my_setup2 # ... # end # # setup do # ... # setup callback2 # end # # def test_my_class # ... # end # end # # Here is a call order: # # * setup # * my_setup1 # * setup callback1 # * my_setup2 # * setup callback2 # * test_my_class def setup end # Called after every test method runs but the test # method isn't marked as 'passed'. Can be used to # clean up and/or verify tested condition. # e.g. Can be used to verify mock. # # You can add additional cleanup tasks by the following # code: # # class TestMyClass < Test::Unit::TestCase # def cleanup # ... # end # # cleanup # def my_cleanup1 # ... # end # # cleanup do # ... # cleanup callback1 # end # # cleanup # def my_cleanup2 # ... # end # # cleanup do # ... # cleanup callback2 # end # # def test_my_class # ... # end # end # # Here is a call order: # # * test_my_class # * cleanup callback2 # * my_cleanup2 # * cleanup callback1 # * my_cleanup1 # * cleanup def cleanup end # Called after every test method runs. Can be used to tear # down fixture information. # # You can add additional teardown tasks by the following # code: # # class TestMyClass < Test::Unit::TestCase # def teardown # ... # end # # teardown # def my_teardown1 # ... # end # # teardown do # ... # teardown callback1 # end # # teardown # def my_teardown2 # ... # end # # teardown do # ... # teardown callback2 # end # # def test_my_class # ... # end # end # # Here is a call order: # # * test_my_class # * teardown callback2 # * my_teardown2 # * teardown callback1 # * my_teardown1 # * teardown def teardown end def default_test flunk("No tests were specified") end def size 1 end # Returns a label of test data for the test. If the # test isn't associated with any test data, it returns # `nil`. def data_label @internal_data.test_data_label end # Returns test data for the test. If the test isn't associated # with any test data, it returns `nil`. def data @internal_data.test_data end # Returns a human-readable name for the specific test that # this instance of TestCase represents. def name "#{local_name}(#{self.class.name})" end # Returns a human-readable name for the specific test that this # instance of TestCase represents. # # `#local_name` doesn't include class name. `#name` includes # class name. def local_name if @internal_data.have_test_data? "#{@method_name}[#{data_label}]" else @method_name.to_s end end # Returns a description for the test. A description # will be associated by Test::Unit::TestCase.test or # Test::Unit::TestCase.description. # # Returns a name for the test for no description test. def description self[:description] || name end # Overridden to return #name. def to_s name end # It's handy to be able to compare TestCase instances. def ==(other) return false unless other.kind_of?(self.class) return false unless @method_name == other.method_name return false unless data_label == other.data_label self.class == other.class end # Returns a Time at the test was started. def start_time @internal_data.start_time end # Returns elapsed time for the test was ran. def elapsed_time @internal_data.elapsed_time end # Returns whether the test is interrupted. def interrupted? @internal_data.interrupted? end # Returns whether this individual test passed or # not. Primarily for use in teardown so that artifacts # can be left behind if the test fails. def passed? @internal_data.passed? end # Notify that a problem is occurred in the test. It means that # the test is a failed test. If any failed tests exist in test # suites, the test process exits with failure exit status. # # This is a public API for developers who extend test-unit. # # @return [void] def problem_occurred @internal_data.problem_occurred end # Notify that the test is passed. Normally, it is not needed # because #run calls it automatically. If you want to override # #run, it is not a good idea. Please contact test-unit # developers. We will help you without your custom #run. For # example, we may add a new hook in #run. # # This is a public API for developers who extend test-unit. # # @return [void] def add_pass current_result.add_pass end private def current_result @_result end def run_test signature = "#{self.class}\##{@method_name}" redefined_info = self[:redefined] if redefined_info notify("<#{signature}> was redefined", :backtrace => redefined_info[:backtrace]) end if @internal_data.have_test_data? test_method = method(@method_name) arity = test_method.arity if arity.zero? __send__(@method_name) else __send__(@method_name, @internal_data.test_data) end else __send__(@method_name) end end def handle_exception(exception) self.class.exception_handlers.each do |handler| if handler.respond_to?(:call) handled = handler.call(self, exception) else handled = __send__(handler, exception) end return true if handled end false end def add_assertion current_result.add_assertion end class InternalData attr_reader :start_time, :elapsed_time attr_reader :test_data_label, :test_data def initialize @start_time = nil @elapsed_time = nil @passed = true @interrupted = false @test_data_label = nil @test_data = nil end def passed? @passed end def interrupted? @interrupted end def assign_test_data(label, data) @test_data_label = label @test_data = data end def have_test_data? not @test_data_label.nil? end def test_started @start_time = Time.now end def test_finished @elapsed_time = Time.now - @start_time end def problem_occurred @passed = false end def interrupted @interrupted = true end end end end end PKu]7test-unit-3.3.4/lib/test/unit/assertion-failed-error.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # Thrown by Test::Unit::Assertions when an assertion fails. class AssertionFailedError < StandardError attr_accessor :expected, :actual, :user_message attr_accessor :inspected_expected, :inspected_actual def initialize(message=nil, options=nil) options ||= {} @expected = options[:expected] @actual = options[:actual] @inspected_expected = options[:inspected_expected] @inspected_actual = options[:inspected_actual] @user_message = options[:user_message] super(message) end end end end PKu]\c3x x -test-unit-3.3.4/lib/test/unit/notification.rbnu[require 'test/unit/util/backtracefilter' module Test module Unit class Notification include Util::BacktraceFilter attr_reader :test_name, :location, :message attr_reader :method_name SINGLE_CHARACTER = 'N' LABEL = "Notification" # Creates a new Notification with the given location and # message. def initialize(test_name, location, message, options={}) @test_name = test_name @location = location @message = message @method_name = options[:method_name] end # Returns a single character representation of a notification. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns a brief version of the error description. def short_display "#{@test_name}: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace = filter_backtrace(location).join("\n") "#{label}: #{@message}\n#{@test_name}\n#{backtrace}" end # Overridden to return long_display. def to_s long_display end def critical? false end end class NotifiedError < StandardError end module TestCaseNotificationSupport class << self def included(base) base.class_eval do include NotificationHandler end end end # Notify some information. # # Example: # # def test_notification # notify("I'm here!") # # Reached here # notify("Special!") if special_case? # # Reached here too # end # # options: # # :backtrace override backtrace. def notify(message, options={}, &block) backtrace = filter_backtrace(options[:backtrace] || caller) notification = Notification.new(name, backtrace, message, :method_name => @method_name) add_notification(notification) end private def add_notification(notification) current_result.add_notification(notification) end end module NotificationHandler class << self def included(base) base.exception_handler(:handle_notified_error) end end private def handle_notified_error(exception) return false unless exception.is_a?(NotifiedError) notification = Notification.new(name, filter_backtrace(exception.backtrace), exception.message) add_notification(notification) true end end module TestResultNotificationSupport attr_reader :notifications # Records a Test::Unit::Notification. def add_notification(notification) @notifications << notification notify_fault(notification) notify_changed end # Returns the number of notifications this TestResult has # recorded. def notification_count @notifications.size end private def initialize_containers super @notifications = [] @summary_generators << :notification_summary end def notification_summary "#{notification_count} notifications" end end end end PKu](::(test-unit-3.3.4/lib/test/unit/version.rbnu[module Test module Unit VERSION = "3.3.4" end end PKu]FJ:AA+test-unit-3.3.4/lib/test/unit/autorunner.rbnu[require "English" require "test/unit/color-scheme" require "test/unit/priority" require "test/unit/attribute-matcher" require "test/unit/testcase" require "optparse" module Test module Unit class AutoRunner RUNNERS = {} COLLECTORS = {} ADDITIONAL_OPTIONS = [] PREPARE_HOOKS = [] class << self def register_runner(id, runner_builder=nil, &block) runner_builder ||= Proc.new(&block) RUNNERS[id] = runner_builder RUNNERS[id.to_s] = runner_builder end def runner(id) RUNNERS[id.to_s] end @@default_runner = nil def default_runner runner(@@default_runner) end def default_runner=(id) @@default_runner = id end def register_collector(id, collector_builder=nil, &block) collector_builder ||= Proc.new(&block) COLLECTORS[id] = collector_builder COLLECTORS[id.to_s] = collector_builder end def collector(id) COLLECTORS[id.to_s] end def register_color_scheme(id, scheme) ColorScheme[id] = scheme end def setup_option(option_builder=nil, &block) option_builder ||= Proc.new(&block) ADDITIONAL_OPTIONS << option_builder end def prepare(hook=nil, &block) hook ||= Proc.new(&block) PREPARE_HOOKS << hook end def run(force_standalone=false, default_dir=nil, argv=ARGV, &block) r = new(force_standalone || standalone?, &block) r.base = default_dir r.prepare r.process_args(argv) r.run end def standalone? return false unless("-e" == $0) ObjectSpace.each_object(Class) do |klass| return false if(klass < TestCase) end true end @@need_auto_run = true def need_auto_run? @@need_auto_run end def need_auto_run=(need) @@need_auto_run = need end end register_collector(:descendant) do |auto_runner| require "test/unit/collector/descendant" collector = Collector::Descendant.new collector.filter = auto_runner.filters collector.collect($0.sub(/\.rb\Z/, "")) end register_collector(:load) do |auto_runner| require "test/unit/collector/load" collector = Collector::Load.new unless auto_runner.pattern.empty? collector.patterns.replace(auto_runner.pattern) end unless auto_runner.exclude.empty? collector.excludes.replace(auto_runner.exclude) end collector.base = auto_runner.base collector.default_test_paths = auto_runner.default_test_paths collector.filter = auto_runner.filters collector.collect(*auto_runner.to_run) end # JUST TEST! # register_collector(:xml) do |auto_runner| # require "test/unit/collector/xml" # collector = Collector::XML.new # collector.filter = auto_runner.filters # collector.collect(auto_runner.to_run[0]) # end # deprecated register_collector(:object_space) do |auto_runner| require "test/unit/collector/objectspace" c = Collector::ObjectSpace.new c.filter = auto_runner.filters c.collect($0.sub(/\.rb\Z/, "")) end # deprecated register_collector(:dir) do |auto_runner| require "test/unit/collector/dir" c = Collector::Dir.new c.filter = auto_runner.filters unless auto_runner.pattern.empty? c.pattern.replace(auto_runner.pattern) end unless auto_runner.exclude.empty? c.exclude.replace(auto_runner.exclude) end c.base = auto_runner.base $:.push(auto_runner.base) if auto_runner.base c.collect(*(auto_runner.to_run.empty? ? ["."] : auto_runner.to_run)) end attr_reader :suite, :runner_options attr_accessor :filters, :to_run attr_accessor :default_test_paths attr_accessor :pattern, :exclude, :base, :workdir attr_accessor :color_scheme, :listeners attr_writer :stop_on_failure attr_writer :runner, :collector def initialize(standalone) @standalone = standalone @runner = default_runner @collector = default_collector @filters = [] @to_run = [] @default_test_paths = [] @color_scheme = ColorScheme.default @runner_options = {} @default_arguments = [] @workdir = nil @listeners = [] @stop_on_failure = false config_file = "test-unit.yml" if File.exist?(config_file) load_config(config_file) else load_global_config end yield(self) if block_given? end def stop_on_failure? @stop_on_failure end def prepare PREPARE_HOOKS.each do |handler| handler.call(self) end end def process_args(args=ARGV) begin args.unshift(*@default_arguments) options.order!(args) {|arg| add_test_path(arg)} rescue OptionParser::ParseError => e puts e puts options exit(false) end not @to_run.empty? end def options @options ||= OptionParser.new do |o| o.banner = "Test::Unit automatic runner." o.banner += "\nUsage: #{$0} [options] [-- untouched arguments]" o.on("-r", "--runner=RUNNER", RUNNERS, "Use the given RUNNER.", "(" + keyword_display(RUNNERS) + ")") do |r| @runner = r end o.on("--collector=COLLECTOR", COLLECTORS, "Use the given COLLECTOR.", "(" + keyword_display(COLLECTORS) + ")") do |collector| @collector = collector end if (@standalone) o.on("-b", "--basedir=DIR", "Base directory of test suites.") do |b| @base = b end o.on("-w", "--workdir=DIR", "Working directory to run tests.") do |w| @workdir = w end o.on("--default-test-path=PATH", "Add PATH to the default test paths.", "The PATH is used when user doesn't specify any test path.", "You can specify this option multiple times.") do |path| @default_test_paths << path end o.on("-a", "--add=TORUN", Array, "Add TORUN to the list of things to run;", "can be a file or a directory.") do |paths| paths.each do |path| add_test_path(path) end end @pattern = [] o.on("-p", "--pattern=PATTERN", Regexp, "Match files to collect against PATTERN.") do |e| @pattern << e end @exclude = [] o.on("-x", "--exclude=PATTERN", Regexp, "Ignore files to collect against PATTERN.") do |e| @exclude << e end end o.on("-n", "--name=NAME", String, "Runs tests matching NAME.", "Use '/PATTERN/' for NAME to use regular expression.") do |name| name = (%r{\A/(.*)/\Z} =~ name ? Regexp.new($1) : name) @filters << lambda do |test| return true if name === test.method_name return true if name === test.local_name false end end o.on("--ignore-name=NAME", String, "Ignores tests matching NAME.", "Use '/PATTERN/' for NAME to use regular expression.") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) case n when Regexp @filters << proc {|t| n =~ t.method_name ? false : true} else @filters << proc {|t| n != t.method_name} end end o.on("-t", "--testcase=TESTCASE", String, "Runs tests in TestCases matching TESTCASE.", "Use '/PATTERN/' for TESTCASE to use regular expression.") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) @filters << lambda do |test| match_test_case_name(test, n) end end o.on("--ignore-testcase=TESTCASE", String, "Ignores tests in TestCases matching TESTCASE.", "Use '/PATTERN/' for TESTCASE to use regular expression.") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) @filters << lambda do |test| not match_test_case_name(test, n) end end o.on("--location=LOCATION", String, "Runs tests that defined in LOCATION.", "LOCATION is one of PATH:LINE, PATH or LINE") do |location| if /\A\d+\z/ =~ location path = nil line = location.to_i else path, line, = location.split(/:(\d+)/, 2) line = line.to_i unless line.nil? end add_location_filter(path, line) end o.on("--attribute=EXPRESSION", String, "Runs tests that matches EXPRESSION.", "EXPRESSION is evaluated as Ruby's expression.", "Test attribute name can be used with no receiver in EXPRESSION.", "EXPRESSION examples:", " !slow", " tag == 'important' and !slow") do |expression| @filters << lambda do |test| matcher = AttributeMatcher.new(test) matcher.match?(expression) end end priority_filter = Proc.new do |test| if @filters == [priority_filter] Priority::Checker.new(test).need_to_run? else nil end end o.on("--[no-]priority-mode", "Runs some tests based on their priority.") do |priority_mode| if priority_mode Priority.enable @filters |= [priority_filter] else Priority.disable @filters -= [priority_filter] end end o.on("--default-priority=PRIORITY", Priority.available_values, "Uses PRIORITY as default priority", "(#{keyword_display(Priority.available_values)})") do |priority| Priority.default = priority end o.on("-I", "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]", "Appends directory list to $LOAD_PATH.") do |dirs| $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR)) end color_schemes = ColorScheme.all o.on("--color-scheme=SCHEME", color_schemes, "Use SCHEME as color scheme.", "(#{keyword_display(color_schemes)})") do |scheme| @color_scheme = scheme end o.on("--config=FILE", "Use YAML fomat FILE content as configuration file.") do |file| load_config(file) end o.on("--order=ORDER", TestCase::AVAILABLE_ORDERS, "Run tests in a test case in ORDER order.", "(#{keyword_display(TestCase::AVAILABLE_ORDERS)})") do |order| TestCase.test_order = order end assertion_message_class = Test::Unit::Assertions::AssertionMessage o.on("--max-diff-target-string-size=SIZE", Integer, "Shows diff if both expected result string size and " + "actual result string size are " + "less than or equal SIZE in bytes.", "(#{assertion_message_class.max_diff_target_string_size})") do |size| assertion_message_class.max_diff_target_string_size = size end o.on("--[no-]stop-on-failure", "Stops immediately on the first non success test", "(#{@stop_on_failure})") do |boolean| @stop_on_failure = boolean end ADDITIONAL_OPTIONS.each do |option_builder| option_builder.call(self, o) end o.on("--", "Stop processing options so that the", "remaining options will be passed to the", "test."){o.terminate} o.on("-h", "--help", "Display this help."){puts o; exit} o.on_tail o.on_tail("Deprecated options:") o.on_tail("--console", "Console runner (use --runner).") do warn("Deprecated option (--console).") @runner = self.class.runner(:console) end if RUNNERS[:fox] o.on_tail("--fox", "Fox runner (use --runner).") do warn("Deprecated option (--fox).") @runner = self.class.runner(:fox) end end o.on_tail end end def keyword_display(keywords) keywords = keywords.collect do |keyword, _| keyword.to_s end.uniq.sort i = 0 keywords.collect do |keyword| if (i > 0 and keyword[0] == keywords[i - 1][0]) or ((i < keywords.size - 1) and (keyword[0] == keywords[i + 1][0])) n = 2 else n = 1 end i += 1 keyword.sub(/^(.{#{n}})([A-Za-z]+)(?=\w*$)/, '\\1[\\2]') end.join(", ") end def run self.class.need_auto_run = false suite = @collector[self] return false if suite.nil? return true if suite.empty? runner = @runner[self] return false if runner.nil? @runner_options[:color_scheme] ||= @color_scheme @runner_options[:listeners] ||= [] @runner_options[:listeners].concat(@listeners) if @stop_on_failure @runner_options[:listeners] << StopOnFailureListener.new end change_work_directory do runner.run(suite, @runner_options).passed? end end def load_config(file) require "yaml" config = YAML.load(File.read(file)) runner_name = config["runner"] @runner = self.class.runner(runner_name) || @runner @collector = self.class.collector(config["collector"]) || @collector (config["color_schemes"] || {}).each do |name, options| ColorScheme[name] = options end runner_options = {} (config["#{runner_name}_options"] || {}).each do |key, value| key = key.to_sym value = ColorScheme[value] if key == :color_scheme if key == :arguments @default_arguments.concat(value.split) else runner_options[key.to_sym] = value end end @runner_options = @runner_options.merge(runner_options) end private def default_runner runner = self.class.default_runner if ENV["EMACS"] == "t" runner ||= self.class.runner(:emacs) else runner ||= self.class.runner(:console) end runner end def default_collector self.class.collector(@standalone ? :load : :descendant) end def global_config_file File.expand_path("~/.test-unit.yml") rescue ArgumentError nil end def load_global_config file = global_config_file load_config(file) if file and File.exist?(file) end def change_work_directory(&block) if @workdir Dir.chdir(@workdir, &block) else yield end end def match_test_case_name(test, pattern) test.class.ancestors.each do |test_class| break if test_class == TestCase return true if pattern === test_class.name end false end def add_test_path(path) if /:(\d+)\z/ =~ path line = $1.to_i path = $PREMATCH add_location_filter(path, line) end @to_run << path end def add_location_filter(path, line) @filters << lambda do |test| test.class.test_defined?(:path => path, :line => line, :method_name => test.method_name) end end class StopOnFailureListener def attach_to_mediator(mediator) mediator.add_listener(TestResult::FINISHED) do |result| result.stop unless result.passed? end end end end end end require "test/unit/runner/console" require "test/unit/runner/emacs" require "test/unit/runner/xml" PKu]n$$(test-unit-3.3.4/lib/test/unit/fixture.rbnu[module Test module Unit module Fixture class << self def included(base) base.extend(ClassMethods) [:setup, :cleanup, :teardown].each do |type| observer = lambda do |test_case, _, _, value, callback| if value.nil? test_case.fixture[type].unregister(callback) else test_case.fixture[type].register(callback, value) end end base.register_attribute_observer(type, &observer) end end end class Fixture attr_reader :setup attr_reader :cleanup attr_reader :teardown def initialize(test_case) @test_case = test_case @setup = HookPoint.new(@test_case, :setup, :after => :append) @cleanup = HookPoint.new(@test_case, :cleanup, :before => :prepend) @teardown = HookPoint.new(@test_case, :teardown, :before => :prepend) @cached_before_callbacks = {} @cached_after_callbacks = {} end def [](type) case type when :setup @setup when :cleanup @cleanup when :teardown @teardown end end def before_callbacks(type) @cached_before_callbacks[type] ||= collect_before_callbacks(type) end def after_callbacks(type) @cached_after_callbacks[type] ||= collect_after_callbacks(type) end private def target_test_cases @cached_target_test_cases ||= collect_target_test_cases end def collect_before_callbacks(type) prepend_callbacks = [] append_callbacks = [] target_test_cases.each do |ancestor| prepend_callbacks << ancestor.fixture[type].before_prepend_callbacks append_callbacks << ancestor.fixture[type].before_append_callbacks end merge_callbacks(prepend_callbacks, append_callbacks) end def collect_after_callbacks(type) prepend_callbacks = [] append_callbacks = [] target_test_cases.each do |ancestor| prepend_callbacks << ancestor.fixture[type].after_prepend_callbacks append_callbacks << ancestor.fixture[type].after_append_callbacks end merge_callbacks(prepend_callbacks, append_callbacks) end def collect_target_test_cases ancestors = @test_case.ancestors base_index = ancestors.index(::Test::Unit::Fixture) interested_ancestors = ancestors[0, base_index].find_all do |ancestor| ancestor.is_a?(Class) end interested_ancestors.reverse end def merge_callbacks(prepend_callbacks, append_callbacks) all_callbacks = [] prepend_callbacks.reverse_each do |callbacks| all_callbacks.concat(callbacks) end append_callbacks.each do |callbacks| all_callbacks.concat(callbacks) end all_callbacks end end class HookPoint def initialize(test_case, type, default_options) @test_case = test_case @type = type @default_options = default_options @before_prepend_callbacks = [] @before_append_callbacks = [] @after_prepend_callbacks = [] @after_append_callbacks = [] @unregistered_callbacks = [] end def register(method_name_or_callback, options=nil) options ||= {} unless valid_register_options?(options) message = "must be {:before => :prepend}, " + "{:before => :append}, {:after => :prepend} or " + "{:after => :append}: #{options.inspect}" raise ArgumentError, message end if options.empty? options = @default_options end before_how = options[:before] after_how = options[:after] if method_name_or_callback.respond_to?(:call) callback = method_name_or_callback method_name = callback_method_name(callback) @test_case.attribute(:source_location, callback.source_location, method_name) @test_case.__send__(:define_method, method_name, &callback) else method_name = method_name_or_callback end add_callback(method_name, before_how, after_how) end def unregister(method_name_or_callback) if method_name_or_callback.respond_to?(:call) callback = method_name_or_callback method_name = callback_method_name(callback) else method_name = method_name_or_callback end @unregistered_callbacks << method_name end def before_prepend_callbacks @before_prepend_callbacks - @unregistered_callbacks end def before_append_callbacks @before_append_callbacks - @unregistered_callbacks end def after_prepend_callbacks @after_prepend_callbacks - @unregistered_callbacks end def after_append_callbacks @after_append_callbacks - @unregistered_callbacks end private def valid_register_options?(options) return true if options.empty? return false if options.size > 1 key = options.keys.first [:before, :after].include?(key) and [:prepend, :append].include?(options[key]) end def callback_method_name(callback) "#{@type}_#{callback.object_id}" end def add_callback(method_name_or_callback, before_how, after_how) case before_how when :prepend @before_prepend_callbacks = [method_name_or_callback] | @before_prepend_callbacks when :append @before_append_callbacks |= [method_name_or_callback] else case after_how when :prepend @after_prepend_callbacks = [method_name_or_callback] | @after_prepend_callbacks when :append @after_append_callbacks |= [method_name_or_callback] end end end end module ClassMethods def fixture @fixture ||= Fixture.new(self) end def setup(*method_names, &callback) register_fixture(:setup, *method_names, &callback) end def unregister_setup(*method_names_or_callbacks) unregister_fixture(:setup, *method_names_or_callbacks) end def cleanup(*method_names, &callback) register_fixture(:cleanup, *method_names, &callback) end def unregister_cleanup(*method_names_or_callbacks) unregister_fixture(:cleanup, *method_names_or_callbacks) end def teardown(*method_names, &callback) register_fixture(:teardown, *method_names, &callback) end def unregister_teardown(*method_names_or_callbacks) unregister_fixture(:teardown, *method_names_or_callbacks) end private def register_fixture(fixture, *method_names, &callback) options = {} options = method_names.pop if method_names.last.is_a?(Hash) callbacks = method_names callbacks << callback if callback attribute(fixture, options, *callbacks) end def unregister_fixture(fixture, *method_names_or_callbacks) attribute(fixture, nil, *method_names_or_callbacks) end end private def run_fixture(type, options={}, &block) fixtures = [ self.class.fixture.before_callbacks(type), type, self.class.fixture.after_callbacks(type), ].flatten if block runner = create_fixtures_runner(fixtures, options, &block) runner.call else fixtures.each do |method_name| run_fixture_callback(method_name, options) end end end def create_fixtures_runner(fixtures, options, &block) if fixtures.empty? block else last_fixture = fixtures.pop create_fixtures_runner(fixtures, options) do block_is_called = false run_fixture_callback(last_fixture, options) do block_is_called = true block.call end block.call unless block_is_called end end end def run_fixture_callback(method_name, options, &block) return unless respond_to?(method_name, true) begin __send__(method_name, &block) rescue Exception raise unless options[:handle_exception] raise unless handle_exception($!) end end def run_setup(&block) run_fixture(:setup, &block) end def run_cleanup run_fixture(:cleanup) end def run_teardown run_fixture(:teardown, :handle_exception => true) end end end end PKu]l /test-unit-3.3.4/lib/test/unit/runner/console.rbnu[# Copyright (C) 2008-2017 Kouhei Sutou # # License: Ruby OR LGPL-2.1+ # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA module Test module Unit AutoRunner.register_runner(:console) do |auto_runner| require 'test/unit/ui/console/testrunner' Test::Unit::UI::Console::TestRunner end AutoRunner.setup_option do |auto_runner, opts| require 'test/unit/ui/console/outputlevel' output_levels = [ ["silent", UI::Console::OutputLevel::SILENT], ["progress", UI::Console::OutputLevel::PROGRESS_ONLY], ["important-only", UI::Console::OutputLevel::IMPORTANT_FAULTS_ONLY], ["normal", UI::Console::OutputLevel::NORMAL], ["verbose", UI::Console::OutputLevel::VERBOSE], ] opts.on('-v', '--verbose=[LEVEL]', output_levels, "Set the output level (default is verbose).", "(#{auto_runner.keyword_display(output_levels)})") do |level| level ||= output_levels.assoc("verbose")[1] auto_runner.runner_options[:output_level] = level end use_color_options = [ [:auto, :auto], ["-", false], ["no", false], ["false", false], ["+", true], ["yes", true], ["true", true], ] opts.on("--[no-]use-color=[auto]", use_color_options, "Uses color output", "(default is auto)") do |use_color| case use_color when nil use_color = true when :auto use_color = nil end auto_runner.runner_options[:use_color] = use_color end opts.on("--progress-row-max=MAX", Integer, "Uses MAX as max terminal width for progress mark", "(default is auto)") do |max| auto_runner.runner_options[:progress_row_max] = max end opts.on("--no-show-detail-immediately", "Shows not passed test details immediately.", "(default is yes)") do |boolean| auto_runner.runner_options[:show_detail_immediately] = boolean end opts.on("--[no-]reverse-output", "Shows fault details in reverse.", "(default is yes for tty output, no otherwise)") do |boolean| auto_runner.runner_options[:reverse_output] = boolean end end end end PKu]qo+test-unit-3.3.4/lib/test/unit/runner/xml.rbnu[module Test module Unit AutoRunner.register_runner(:xml) do |auto_runner| require 'test/unit/ui/xml/testrunner' Test::Unit::UI::XML::TestRunner end AutoRunner.setup_option do |auto_runner, opts| opts.on("--output-file-descriptor=FD", Integer, "Outputs to file descriptor FD") do |fd| auto_runner.runner_options[:output_file_descriptor] = fd end end end end PKu]l-test-unit-3.3.4/lib/test/unit/runner/emacs.rbnu[module Test module Unit AutoRunner.register_runner(:emacs) do |auto_runner| require 'test/unit/ui/emacs/testrunner' Test::Unit::UI::Emacs::TestRunner end end end PKu] {:x => 1, :y => "a"} # # => {:x => 1, :y => "b"} # # => {:x => 2, :y => "a"} # # => {:x => 2, :y => "b"} # # => {:x => 3, :y => "a"} # # => {:x => 3, :y => "b"} # end # # Generates test matrix from variable and patterns pairs. # # @overload data(data_set, options={}) # @param [Hash] data_set specify test data as a Hash that # key is test label and value is test data. # @param [Hash] options specify options. # @option options [Boolean] :keep whether or not to use # this data in the following test methods # # @example data(data_set) # data("empty string" => [true, ""], # "plain string" => [false, "hello"]) # def test_empty?(data) # expected, target = data # assert_equal(expected, target.empty?) # end # # @overload data(options={}, &block) # @param [Hash] options specify options. # @option options [Boolean] :keep whether or not to use # this data in the following test methods # @yieldreturn [Hash] return test data set # as a Hash that key is test label and value is test data. # # @example data(&block) # data do # data_set = {} # data_set["empty string"] = [true, ""] # data_set["plain string"] = [false, "hello"] # data_set # end # def test_empty?(data) # expected, target = data # assert_equal(expected, target.empty?) # end # # @overload data(options={}, &block) # @param [Hash] options specify options. # @option options [Boolean] :keep whether or not to use # this data in the following test methods # @yieldreturn [Array] return test data set # as an Array of variable and patterns. # # @example data(&block) # data do # patterns = 3.times.to_a # [:x, patterns] # end # data do # patterns = [] # character = "a" # 2.times.each do # patterns << character # character = character.succ # end # [:y, patterns] # end # def test_patterns(data) # # 3 * 2 times executed # # 3: the number of patterns of :x # # 2: the number of patterns of :y # p data # # => {:x => 0, :y => "a"} # # => {:x => 0, :y => "b"} # # => {:x => 1, :y => "a"} # # => {:x => 1, :y => "b"} # # => {:x => 2, :y => "a"} # # => {:x => 2, :y => "b"} # end # # Generates test matrix from variable and patterns pairs. # def data(*arguments, &block) options = nil n_arguments = arguments.size case n_arguments when 0 raise ArgumentError, "no block is given" unless block_given? data_set = block when 1 if block_given? data_set = block options = arguments[1] else data_set = arguments[0] end when 2 case arguments[0] when String data_set = {arguments[0] => arguments[1]} when Hash data_set = arguments[0] options = arguments[1] else variable = arguments[0] patterns = arguments[1] data_set = [variable, patterns] end when 3 case arguments[0] when String data_set = {arguments[0] => arguments[1]} options = arguments[2] else variable = arguments[0] patterns = arguments[1] data_set = [variable, patterns] options = arguments[2] end else message = "wrong number arguments(#{n_arguments} for 0..3)" raise ArgumentError, message end options ||= {} data_sets = current_attribute(:data)[:value] || DataSets.new data_sets.add(data_set, options) if options[:keep] keep_hook = lambda do |attr| attr.merge(value: attr[:value].keep) end options = options.merge(keep_hook: keep_hook) end attribute(:data, data_sets, options) end # This method provides Data-Driven-Test functionality. # # Load test data from the file. This is shorthand to load # test data from file. If you want to load complex file, you # can use {#data} with block. # # @param [String] file_name full path to test data file. # File format is automatically detected from filename extension. # @raise [ArgumentError] if `file_name` is not supported file format. # @see Loader#load # # @example Load data from CSV file # load_data("/path/to/test-data.csv") # def test_empty?(data) # assert_equal(data["expected"], data["target"].empty?) # end # def load_data(file_name) loader = Loader.new(self) loader.load(file_name) end class Loader # @api private def initialize(test_case) @test_case = test_case end # Load data from file. # # @param [String] file_name full path to test data file. # File format is automatically detected from filename extension. # @raise [ArgumentError] if `file_name` is not supported file format. # @see #load_csv # @see #load_tsv # @api private def load(file_name) case File.extname(file_name).downcase when ".csv" load_csv(file_name) when ".tsv" load_tsv(file_name) else raise ArgumentError, "unsupported file format: <#{file_name}>" end end # Load data from CSV file. # # There are 2 types of CSV file as following examples. # First, there is a header on first row and it's first column is "label". # Another, there is no header in the file. # # @example Load data from CSV file with header # # test-data.csv: # # label,expected,target # # empty string,true,"" # # plain string,false,hello # # # load_data("/path/to/test-data.csv") # def test_empty?(data) # assert_equal(data["expected"], data["target"].empty?) # end # # @example Load data from CSV file without header # # test-data-without-header.csv: # # empty string,true,"" # # plain string,false,hello # # # load_data("/path/to/test-data-without-header.csv") # def test_empty?(data) # expected, target = data # assert_equal(expected, target.empty?) # end # # @api private def load_csv(file_name) require 'csv' first_row = true header = nil CSV.foreach(file_name) do |row| if first_row first_row = false if row.first == "label" header = row[1..-1] next end end set_test_data(header, row) end end # Load data from TSV file. # # There are 2 types of TSV file as following examples. # First, there is a header on first row and it's first column is "label". # Another, there is no header in the file. # # @example Load data from TSV file with header # # test-data.tsv: # # label expected target # # empty string true "" # # plain string false hello # # # load_data("/path/to/test-data.tsv") # def test_empty?(data) # assert_equal(data["expected"], data["target"].empty?) # end # # @example Load data from TSV file without header # # test-data-without-header.tsv: # # empty string true "" # # plain string false hello # # # load_data("/path/to/test-data-without-header.tsv") # def test_empty?(data) # expected, target = data # assert_equal(expected, target.empty?) # end # # @api private def load_tsv(file_name) require "csv" if CSV.const_defined?(:VERSION) first_row = true header = nil CSV.foreach(file_name, :col_sep => "\t") do |row| if first_row first_row = false if row.first == "label" header = row[1..-1] next end end set_test_data(header, row) end else # for old CSV library first_row = true header = nil CSV.open(file_name, "r", "\t") do |row| if first_row first_row = false if row.first == "label" header = row[1..-1] next end end set_test_data(header, row) end end end private def normalize_value(value) return true if value == "true" return false if value == "false" begin Integer(value) rescue ArgumentError begin Float(value) rescue ArgumentError value end end end def set_test_data(header, row) label = row.shift if header data = {} header.each_with_index do |key, i| data[key] = normalize_value(row[i]) end else data = row.collect do |cell| normalize_value(cell) end end @test_case.data(label, data) end end end end end end PKu]z|{{3test-unit-3.3.4/lib/test/unit/auto-runner-loader.rbnu[require "test/unit/test-suite-creator" module Test module Unit module AutoRunnerLoader @loaded = false class << self def check(test_case, method_name) return if @loaded return unless TestSuiteCreator.test_method?(test_case, method_name) require "test/unit" @loaded = true end end end end end PKu]xpp5test-unit-3.3.4/lib/test/unit/collector/descendant.rbnu[require 'test/unit/collector' module Test module Unit module Collector class Descendant include Collector NAME = 'collected from the subclasses of TestCase' def collect(name=NAME) suite = TestSuite.new(name) add_test_cases(suite, TestCase::DESCENDANTS) suite end end end end end PKu]W"DD.test-unit-3.3.4/lib/test/unit/collector/xml.rbnu[#-- # # Author:: Kouhei Sutou # Copyright:: # * Copyright (c) 2011 Kouhei Sutou # License:: Ruby license. # just test!!! don't use it yet!!! require 'test/unit/collector' require 'rexml/document' require 'rexml/streamlistener' module Test module Unit module Collector class XML include Collector def collect(xml_log_path) listener = Listener.new File.open(xml_log_path) do |xml_log| parser = REXML::Parsers::StreamParser.new(xml_log, listener) parser.parse end suite = TestSuite.new("tests in #{xml_log_path}") suites = listener.test_suites sort(suites).each {|s| add_suite(suite, s)} suite end class Listener include REXML::StreamListener attr_reader :test_suites def initialize @ns_stack = [{"xml" => :xml}] @tag_stack = [["", :root]] @text_stack = [''] @state_stack = [:root] @values = {} @test_suites = [] end def tag_start(name, attributes) @text_stack.push('') ns = @ns_stack.last.dup attrs = {} attributes.each do |n, v| if /\Axmlns(?:\z|:)/ =~ n ns[$POSTMATCH] = v else attrs[n] = v end end @ns_stack.push(ns) _parent_tag = parent_tag prefix, local = split_name(name) uri = _ns(ns, prefix) @tag_stack.push([uri, local]) state = next_state(@state_stack.last, uri, local) @state_stack.push(state) @values = {} case state when :test_suite, :test_case # do nothing when :test @n_pass_assertions = 0 if _parent_tag == "start-test" when :backtrace @backtrace = [] @values_backup = @values end end def tag_end(name) state = @state_stack.pop text = @text_stack.pop uri, local = @tag_stack.pop no_action_states = [:root, :stream] case state when *no_action_states # do nothing when :test_suite test_suite_end when :complete_test_case @test_suites.last << @test_case.suite when :test_case test_case_end when :result @result = @values when :test test_end when :pass_assertion @n_pass_assertions += 1 when :backtrace @values = @values_backup @values["backtrace"] = @backtrace when :entry file = @values['file'] line = @values['line'] info = @values['info'] @backtrace << "#{file}:#{line}: #{info}" @values = {} else local = normalize_local(local) @values[local] = text end @ns_stack.pop end def text(data) @text_stack.last << data end private def _ns(ns, prefix) ns.fetch(prefix, "") end NAME_SPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/ def split_name(name) name =~ NAME_SPLIT [$1 || '', $2] end STATE_TABLE = { :root => [:stream], :stream => [:ready_test_suite, :start_test_suite, :ready_test_case, :start_test_case, :start_test, :pass_assertion, :test_result, :complete_test, :complete_test_case, :complete_test_suite, :success], :ready_test_suite => [:n_tests], :start_test_suite => [:test_suite], :ready_test_case => [:test_case, :n_tests], :start_test_case => [:test_case], :start_test => [:test], :pass_assertion => [:test], :complete_test => [:test, :success], :complete_test_case => [:test_case, :elapsed, :success], :complete_test_suite => [:test_suite, :success], :test_suite => [:start_time, :elapsed], :test_case => [:name, :start_time, :elapsed], :test => [:name, :start_time, :elapsed], :test_result => [:test, :result], :result => [:test_case, :test, :status, :backtrace, :detail], :backtrace => [:entry], :entry => [:file, :line, :info], } def next_state(current_state, uri, local) local = normalize_local(local) valid_elements = STATE_TABLE[current_state] if valid_elements.nil? raise "unexpected element: #{current_path}" end next_state = local.to_sym unless valid_elements.include?(next_state) raise "unexpected element: #{current_path}" end next_state end def current_path locals = @tag_stack.collect do |uri, local| local end ["", *locals].join("/") end def normalize_local(local) local.gsub(/-/, "_") end def parent_tag @tag_stack.last[1] end def test_suite_end return unless parent_tag == "start-test-suite" suite = TestSuite.new ["start_time", "elapsed_time", "n_tests"].each do |key| if @values.has_key?(key) suite.instance_variable_set("@#{key}", @values[key]) end end @test_suites << suite end def test_case_end return unless parent_tag == "start-test-case" name = @values["name"] @test_case = Class.new(TestCase) do define_method(:name) do name end end end def test_end return unless parent_tag == "complete-test" name = @values["name"] n_pass_assertions = @n_pass_assertions result = @result @test_case.module_eval do test define_method(name) do n_pass_assertions.times do add_assertion end case result["status"] when "omission" add_omission(Omission.new(name, result["backtrace"], result["detail"])) end end end end end end end end end PKu]> /test-unit-3.3.4/lib/test/unit/collector/load.rbnu[require 'pathname' require 'test/unit/testsuite' require 'test/unit/collector' module Test module Unit module Collector class Load include Collector attr_reader :patterns, :excludes, :base attr_reader :default_test_paths def initialize super @system_excludes = [/~\z/, /\A\.\#/] @system_directory_excludes = [/\A(?:CVS|\.svn|\.git)\z/] @patterns = [/\Atest[_\-].+\.rb\z/m, /[_\-]test\.rb\z/] @excludes = [] @base = nil @default_test_paths = [] @require_failed_infos = [] end def base=(base) base = Pathname(base) unless base.nil? @base = base end def default_test_paths=(paths) @default_test_paths = paths.collect do |path| Pathname(path) end end def collect(*froms) add_load_path(@base) do froms = @default_test_paths if froms.empty? froms = ["."] if froms.empty? test_suites = [] already_gathered = find_test_cases froms.each do |from| from = resolve_path(from) if from.directory? test_suite = collect_recursive(from, already_gathered) test_suites << test_suite unless test_suite.tests.empty? else collect_file(from, test_suites, already_gathered) end end add_require_failed_test_suite(test_suites) if test_suites.size > 1 test_suite = TestSuite.new("[#{froms.join(', ')}]") sort(test_suites).each do |sub_test_suite| test_suite << sub_test_suite end else test_suite = test_suites.first end test_suite end end def find_test_cases(ignore=[]) test_cases = [] TestCase::DESCENDANTS.each do |test_case| test_cases << test_case unless ignore.include?(test_case) end ignore.concat(test_cases) test_cases end private def collect_recursive(path, already_gathered) sub_test_suites = [] if path.directory? directories, files = path.children.partition do |child| child.directory? end files.each do |child| next if excluded_file?(child.basename.to_s) collect_file(child, sub_test_suites, already_gathered) end directories.each do |child| next if excluded_directory?(child.basename.to_s) sub_test_suite = collect_recursive(child, already_gathered) sub_test_suites << sub_test_suite unless sub_test_suite.empty? end else unless excluded_file?(path.basename.to_s) collect_file(path, sub_test_suites, already_gathered) end end test_suite = TestSuite.new(path.basename.to_s) sort(sub_test_suites).each do |sub_test_suite| test_suite << sub_test_suite end test_suite end def collect_file(path, test_suites, already_gathered) @program_file ||= File.expand_path($0) expanded_path = path.expand_path return if @program_file == expanded_path.to_s add_load_path(expanded_path.dirname) do begin require(expanded_path.to_s) rescue LoadError @require_failed_infos << {:path => expanded_path, :exception => $!} end add_test_cases(test_suites, find_test_cases(already_gathered)) end end def resolve_path(path) if @base @base + path else Pathname(path) end end def add_load_path(path) return yield if path.nil? path = path.to_s begin $LOAD_PATH.unshift(path) yield ensure index = $LOAD_PATH.index(path) $LOAD_PATH.delete_at(index) if index end end def excluded_directory?(base) @system_directory_excludes.any? {|pattern| pattern =~ base} end def excluded_file?(base) return true if @system_excludes.any? {|pattern| pattern =~ base} patterns = @patterns || [] unless patterns.empty? return true unless patterns.any? {|pattern| pattern =~ base} end excludes = @excludes || [] unless excludes.empty? return true if excludes.any? {|pattern| pattern =~ base} end false end def add_require_failed_test_suite(test_suites) return if @require_failed_infos.empty? require_failed_infos = @require_failed_infos require_failed_errors = Class.new(Test::Unit::TestCase) require_failed_errors.class_eval do class << self def name "RequireFailedErrors" end end require_failed_infos.each do |info| path = info[:path] normalized_path = path.to_s.gsub(/[^a-z0-9\_]+/i, '_') normalized_path = normalized_path.gsub(/\A_+/, '') exception = info[:exception] define_method("test_require_#{normalized_path}") do raise(exception.class, "failed to load <#{path}>: #{exception.message}", exception.backtrace) end end def priority 100 end end add_suite(test_suites, require_failed_errors.suite) end end end end end PKu]Q$ .test-unit-3.3.4/lib/test/unit/collector/dir.rbnu[require 'test/unit/testsuite' require 'test/unit/collector' module Test module Unit module Collector class Dir include Collector attr_reader :pattern, :exclude attr_accessor :base def initialize(dir=::Dir, file=::File, object_space=::ObjectSpace, req=nil) super() @dir = dir @file = file @object_space = object_space @req = req @pattern = [/\btest_.*\.rb\Z/m] @exclude = [] @base = nil end def collect(*from) basedir = @base $:.push(basedir) if basedir if(from.empty?) recursive_collect('.', find_test_cases) elsif(from.size == 1) recursive_collect(from.first, find_test_cases) else suites = [] from.each do |f| suite = recursive_collect(f, find_test_cases) suites << suite unless(suite.tests.empty?) end suite = TestSuite.new("[#{from.join(', ')}]") sort(suites).each{|s| suite << s} suite end ensure $:.delete_at($:.rindex(basedir)) if basedir end def find_test_cases(ignore=[]) cases = [] @object_space.each_object(Class) do |c| cases << c if(c < TestCase && !ignore.include?(c)) end ignore.concat(cases) cases end def recursive_collect(name, already_gathered) sub_suites = [] path = realdir(name) if @file.directory?(path) dir_name = name unless name == '.' @dir.entries(path).each do |e| next if(e == '.' || e == '..') e_name = dir_name ? @file.join(dir_name, e) : e if @file.directory?(realdir(e_name)) next if /\A(?:CVS|\.svn|\.git)\z/ =~ e sub_suite = recursive_collect(e_name, already_gathered) sub_suites << sub_suite unless(sub_suite.empty?) else next if /~\z/ =~ e_name or /\A\.\#/ =~ e if @pattern and !@pattern.empty? next unless @pattern.any? {|pat| pat =~ e_name} end if @exclude and !@exclude.empty? next if @exclude.any? {|pat| pat =~ e_name} end collect_file(e_name, sub_suites, already_gathered) end end else collect_file(name, sub_suites, already_gathered) end suite = TestSuite.new(@file.basename(name)) sort(sub_suites).each{|s| suite << s} suite end def collect_file(name, suites, already_gathered) dir = @file.dirname(@file.expand_path(name, @base)) $:.unshift(dir) if(@req) @req.require(name) else require(name) end find_test_cases(already_gathered).each{|t| add_suite(suites, t.suite)} ensure $:.delete_at($:.rindex(dir)) if(dir) end def realdir(path) if @base @file.join(@base, path) else path end end end end end end PKu]>6test-unit-3.3.4/lib/test/unit/collector/objectspace.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/collector' module Test module Unit module Collector class ObjectSpace include Collector NAME = 'collected from the ObjectSpace' def initialize(source=::ObjectSpace) super() @source = source end def collect(name=NAME) suite = TestSuite.new(name) sub_suites = [] @source.each_object(Class) do |klass| if(Test::Unit::TestCase > klass) add_suite(sub_suites, klass.suite) end end sort(sub_suites).each{|s| suite << s} suite end end end end end PKu]], 8test-unit-3.3.4/lib/test/unit/fault-location-detector.rbnu[# Copyright (C) 2012 Kouhei Sutou # # License: Ruby's require "English" module Test module Unit class FaultLocationDetector def initialize(fault, code_snippet_fetcher) @fault = fault @code_snippet_fetcher = code_snippet_fetcher extract_fault_information end def split_backtrace_entry(entry) match_data = /\A(.+):(\d+)(?::(.*))?\z/.match(entry) return nil if match_data.nil? file, line_number, context = match_data.to_a[1..-1] line_number = line_number.to_i if /\Ain `(.+?)'/ =~ context method_name = $1 if /\Ablock (?:\(.+?\) )?in / =~ method_name method_name = $POSTMATCH end else method_name = nil end [file, line_number, context, method_name] end def target?(backtrace_entry) file, line_number, context, method_name = split_backtrace_entry(backtrace_entry) _ = context return false if file.nil? if @fault_source_location target_source_location?(file, line_number, method_name) elsif @fault_method_name target_method?(method_name) else true end end private def target_source_location?(file, line_number, method_name) fault_file, fault_line_number = @fault_source_location return false unless file.end_with?(fault_file) return false if line_number < fault_line_number lines = @code_snippet_fetcher.source(file) return false if lines.nil? base_indent_level = nil fault_line_number.step(lines.size) do |current_line_number| line = lines[current_line_number - 1] current_indent_level = guess_indent_level(line) base_indent_level ||= current_indent_level return true if current_line_number == line_number if current_line_number == fault_line_number break if /(?:\send|\})\s*$/ =~ line else break if current_indent_level == base_indent_level end end false end def target_method?(method_name) @fault_method_name == method_name end def guess_indent_level(line) if /\A(\s*)/ =~ line $1.sub(/\t/, " " * 8).count(" ") else 0 end end def extract_fault_information if @fault.respond_to?(:source_location) @fault_source_location = @fault.source_location else @fault_source_location = nil end if @fault.respond_to?(:method_name) @fault_method_name = @fault.method_name else @fault_method_name = nil end end end end end PKu]j V 2test-unit-3.3.4/lib/test/unit/exception-handler.rbnu[module Test module Unit module ExceptionHandler @@exception_handlers = [] class << self def exception_handlers @@exception_handlers end def included(base) base.extend(ClassMethods) observer = Proc.new do |test_case, _, _, value, method_name| if value @@exception_handlers.unshift(method_name) else @@exception_handlers.delete(method_name) end end base.register_attribute_observer(:exception_handler, &observer) end end module ClassMethods def exception_handlers ExceptionHandler.exception_handlers end # @overload exception_handler(method_name) # Add an exception handler method. # # @param method_name [Symbol] # The method name that handles exception raised in tests. # @return [void] # # @overload exception_handler(&callback) # Add an exception handler. # # @yield [test, exception] # Gives the test and the exception. # @yieldparam test [Test::Unit::TestCase] # The test where the exception is raised. # @yieldparam exception [Exception] # The exception that is raised in running the test. # @yieldreturn [Boolean] # Whether the handler handles the exception or not. # The handler must return _true_ if the handler handles # test exception, _false_ otherwise. # @return [void] # # This is a public API for developers who extend test-unit. def exception_handler(*method_name_or_handlers, &block) if block_given? exception_handlers.unshift(block) else method_name_or_handlers.each do |method_name_or_handler| if method_name_or_handler.respond_to?(:call) handler = method_name_or_handler exception_handlers.unshift(handler) else method_name = method_name_or_handler attribute(:exception_handler, true, {}, method_name) end end end end def unregister_exception_handler(*method_name_or_handlers) method_name_or_handlers.each do |method_name_or_handler| if method_name_or_handler.respond_to?(:call) handler = method_name_or_handler exception_handlers.delete(handler) else method_name = method_name_or_handler attribute(:exception_handler, false, {}, method_name) end end end end end end end PKu]"zz-test-unit-3.3.4/lib/test/unit/color-scheme.rbnu[require 'test/unit/color' module Test module Unit class ColorScheme include Enumerable class << self def default if available_colors == 256 default_for_256_colors else default_for_8_colors end end @@default_for_8_colors = nil def default_for_8_colors @@default_for_8_colors ||= new("pass" => Color.new("green", :background => true) + Color.new("white", :bold => true), "pass-marker" => Color.new("green", :bold => true), "failure" => Color.new("red", :background => true) + Color.new("white", :bold => true), "failure-marker" => Color.new("red"), "pending" => Color.new("magenta", :background => true) + Color.new("white", :bold => true), "pending-marker" => Color.new("magenta"), "omission" => Color.new("blue", :background => true) + Color.new("white", :bold => true), "omission-marker" => Color.new("blue"), "notification" => Color.new("cyan", :background => true) + Color.new("white", :bold => true), "notification-marker" => Color.new("cyan"), "error" => Color.new("black", :background => true) + Color.new("yellow", :bold => true), "error-marker" => Color.new("yellow"), "case" => Color.new("blue", :background => true) + Color.new("white", :bold => true), "suite" => Color.new("green", :background => true) + Color.new("white", :bold => true), "diff-inserted-tag" => Color.new("red", :background => true) + Color.new("black", :bold => true), "diff-deleted-tag" => Color.new("green", :background => true) + Color.new("black", :bold => true), "diff-difference-tag" => Color.new("cyan", :background => true) + Color.new("white", :bold => true), "diff-inserted" => Color.new("red", :background => true) + Color.new("white", :bold => true), "diff-deleted" => Color.new("green", :background => true) + Color.new("white", :bold => true)) end @@default_for_256_colors = nil def default_for_256_colors @@default_for_256_colors ||= new("pass" => Color.new("030", :background => true) + Color.new("555", :bold => true), "pass-marker" => Color.new("050", :bold => true), "failure" => Color.new("300", :background => true) + Color.new("555", :bold => true), "failure-marker" => Color.new("500"), "pending" => Color.new("303", :background => true) + Color.new("555", :bold => true), "pending-marker" => Color.new("303"), "omission" => Color.new("001", :background => true) + Color.new("555", :bold => true), "omission-marker" => Color.new("001"), "notification" => Color.new("011", :background => true) + Color.new("555", :bold => true), "notification-marker" => Color.new("011"), "error" => Color.new("000", :background => true) + Color.new("550", :bold => true), "error-marker" => Color.new("550"), "case" => Color.new("220", :background => true) + Color.new("555", :bold => true), "suite" => Color.new("110", :background => true) + Color.new("555", :bold => true), "diff-inserted-tag" => Color.new("500", :background => true) + Color.new("000", :bold => true), "diff-deleted-tag" => Color.new("050", :background => true) + Color.new("000", :bold => true), "diff-difference-tag" => Color.new("005", :background => true) + Color.new("555", :bold => true), "diff-inserted" => Color.new("300", :background => true) + Color.new("555", :bold => true), "diff-deleted" => Color.new("030", :background => true) + Color.new("555", :bold => true)) end @@schemes = {} def all @@schemes.merge("default" => default) end def [](id) @@schemes[id.to_s] end def []=(id, scheme_or_spec) if scheme_or_spec.is_a?(self) scheme = scheme_or_spec else scheme = new(scheme_or_spec) end @@schemes[id.to_s] = scheme end def available_colors guess_available_colors_from_vte_version_env || guess_available_colors_from_colorterm_env || guess_available_colors_from_term_env || 8 end private def guess_available_colors_from_vte_version_env vte_version = ENV["VTE_VERSION"] return nil if vte_version.nil? major = 0 minor = 13 micro = 0 packed_version = major * 10000 + minor * 100 + micro if vte_version.to_i >= packed_version 256 else 8 end end def guess_available_colors_from_colorterm_env case ENV["COLORTERM"] when "gnome-terminal", "xfce4-terminal" 256 else nil end end def guess_available_colors_from_term_env case ENV["TERM"] when /-256color\z/ 256 else nil end end end def initialize(scheme_spec) @scheme = {} scheme_spec.each do |key, color_spec| self[key] = color_spec end end def [](name) @scheme[name.to_s] end def []=(name, color_spec) @scheme[name.to_s] = make_color(color_spec) end def each(&block) @scheme.each(&block) end def to_hash hash = {} @scheme.each do |key, color| hash[key] = color end hash end private def make_color(color_spec) if color_spec.is_a?(Color) or color_spec.is_a?(MixColor) color_spec else color_name = nil normalized_color_spec = {} color_spec.each do |key, value| key = key.to_sym if key == :name color_name = value else normalized_color_spec[key] = value end end Color.new(color_name, normalized_color_spec) end end end end end PKu]= = 3test-unit-3.3.4/lib/test/unit/test-suite-creator.rbnu[#-- # # Author:: Kouhei Sutou # Copyright:: # * Copyright (c) 2011 Kouhei Sutou # License:: Ruby license. require "test/unit/data-sets" module Test module Unit class TestSuiteCreator # :nodoc: class << self def test_method?(test_case, method_name) /\Atest./ =~ method_name.to_s or test_case.find_attribute(method_name, :test) end end def initialize(test_case) @test_case = test_case end def create suite = TestSuite.new(@test_case.name, @test_case) collect_test_names.each do |test_name| data_sets = extract_data_sets(test_name) if data_sets data_sets.each do |label, data| append_test(suite, test_name) do |test| test.assign_test_data(label, data) end end else append_test(suite, test_name) end end append_test(suite, "default_test") if suite.empty? suite end private def extract_data_sets(test_name) data_sets = @test_case.find_attribute(test_name, :data, :recursive => false) data_method_name = "data_#{test_name}" test = @test_case.new(test_name) if test.respond_to?(data_method_name) data_method = test.method(data_method_name) if data_method.arity <= 0 data_sets ||= DataSets.new data_sets << data_method end end data_sets end def append_test(suite, test_name) test = @test_case.new(test_name) yield(test) if block_given? suite << test if test.valid? end def collect_test_names methods = @test_case.public_instance_methods(true) super_test_case = @test_case.superclass methods -= super_test_case.public_instance_methods(true) methods |= @test_case.public_instance_methods(false) method_names = methods.collect(&:to_s) test_names = method_names.find_all do |method_name| self.class.test_method?(@test_case, method_name) end __send__("sort_test_names_in_#{@test_case.test_order}_order", test_names) end def sort_test_names_in_alphabetic_order(test_names) test_names.sort end def sort_test_names_in_random_order(test_names) test_names.sort_by {rand(test_names.size)} end def sort_test_names_in_defined_order(test_names) added_method_names = @test_case.added_method_names test_names.sort do |test1, test2| test1_defined_order = added_method_names.index(test1) test2_defined_order = added_method_names.index(test2) if test1_defined_order and test2_defined_order test1_defined_order <=> test2_defined_order elsif test1_defined_order 1 elsif test2_defined_order -1 else test1 <=> test2 end end end end end end PKu]H~XX(test-unit-3.3.4/lib/test/unit/failure.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # Encapsulates a test failure. Created by Test::Unit::TestCase # when an assertion fails. class Failure attr_reader :test_name, :location, :message attr_reader :method_name, :source_location attr_reader :expected, :actual, :user_message attr_reader :inspected_expected, :inspected_actual SINGLE_CHARACTER = 'F' LABEL = "Failure" # Creates a new Failure with the given location and # message. def initialize(test_name, location, message, options={}) @test_name = test_name @location = location @message = message @method_name = options[:method_name] @source_location = options[:source_location] @expected = options[:expected] @actual = options[:actual] @inspected_expected = options[:inspected_expected] @inspected_actual = options[:inspected_actual] @user_message = options[:user_message] end # Returns a single character representation of a failure. def single_character_display SINGLE_CHARACTER end def label LABEL end # Returns a brief version of the error description. def short_display "#@test_name: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display if location.size == 1 location_display = location[0].sub(/\A(.+:\d+).*/, ' [\\1]') else location_display = "\n [#{location.join("\n ")}]" end "#{label}:\n#@test_name#{location_display}:\n#@message" end # Overridden to return long_display. def to_s long_display end def critical? true end def diff @diff ||= compute_diff end private def compute_diff Assertions::AssertionMessage.delayed_diff(@expected, @actual).inspect end end module FailureHandler class << self def included(base) base.exception_handler(:handle_assertion_failed_error) end end # Report a failure. # # This is a public API for developers who extend test-unit. # # @param message [String] The description about the failure. # @param backtrace [Array] The backtrace for the failure. # @option options [Object] :expected # The expected value of the assertion. # @option options [Object] :actual # The actual value of the assertion. # @option options [String] :inspected_expected # The inspected expected value of the assertion. # It is used for diff between expected and actual of the failure. # @option options [String] :inspected_actual # The inspected actual value of the assertion. # It is used for diff between expected and actual of the failure. # @option options [String] :user_message # The message of the assertion from user. # @option options [String] :method_name (@method_name) # The method name of the test. # @option options [Array] :source_location # The location where the test is defined. It is the same # format as Proc#source_location. That is, it's an array of # path and and line number where the test definition is # started. # @return [void] def add_failure(message, backtrace, options={}) default_options = { :method_name => @method_name, :source_location => self[:source_location], } failure = Failure.new(name, filter_backtrace(backtrace), message, default_options.merge(options)) current_result.add_failure(failure) end private def handle_assertion_failed_error(exception) return false unless exception.is_a?(AssertionFailedError) problem_occurred add_failure(exception.message, exception.backtrace, :expected => exception.expected, :actual => exception.actual, :inspected_expected => exception.inspected_expected, :inspected_actual => exception.inspected_actual, :user_message => exception.user_message) true end end module TestResultFailureSupport attr_reader :failures # Records a Test::Unit::Failure. def add_failure(failure) @failures << failure notify_fault(failure) notify_changed end # Returns the number of failures this TestResult has # recorded. def failure_count @failures.size end def failure_occurred? not @failures.empty? end private def initialize_containers super @failures = [] @summary_generators << :failure_summary @problem_checkers << :failure_occurred? end def failure_summary "#{failure_count} failures" end end end end PKu]xZZ4test-unit-3.3.4/lib/test/unit/ui/emacs/testrunner.rbnu[require 'test/unit/ui/console/testrunner' module Test module Unit module UI module Emacs class TestRunner < Console::TestRunner private def output_setup_end end def output_started end def format_fault(fault) return super unless fault.respond_to?(:label) format_method_name = "format_fault_#{fault.label.downcase}" if respond_to?(format_method_name, true) __send__(format_method_name, fault) else super end end def format_fault_failure(failure) if failure.location.size == 1 location = failure.location[0] location_display = location.sub(/\A(.+:\d+).*/, ' [\\1]') else location_display = "\n" + failure.location.join("\n") end result = "#{failure.label}:\n" result += "#{failure.test_name}#{location_display}:\n" result += failure.message result end def format_fault_error(error) result = "#{error.label}:\n" result += "#{error.test_name}:\n" result += "#{error.message}\n" result += error.backtrace.join("\n") result end end end end end end PKu]u$$7test-unit-3.3.4/lib/test/unit/ui/testrunnerutilities.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit module UI # Provides some utilities common to most, if not all, # TestRunners. # #-- # # Perhaps there ought to be a TestRunner superclass? There # seems to be a decent amount of shared code between test # runners. module TestRunnerUtilities # Creates a new TestRunner and runs the suite. def run(suite, options={}) return new(suite, options).start end # Takes care of the ARGV parsing and suite # determination necessary for running one of the # TestRunners from the command line. def start_command_line_test if ARGV.empty? puts "You should supply the name of a test suite file to the runner" exit end require ARGV[0].gsub(/.+::/, '') new(eval(ARGV[0])).start end end end end end PKu]d2test-unit-3.3.4/lib/test/unit/ui/xml/testrunner.rbnu[#-- # # Author:: Kouhei Sutou # Copyright:: # * Copyright (c) 2011 Kouhei Sutou # License:: Ruby license. require 'erb' require 'time' require 'test/unit/ui/testrunner' require 'test/unit/ui/testrunnermediator' module Test module Unit module UI module XML # Runs a Test::Unit::TestSuite and outputs XML. class TestRunner < UI::TestRunner include ERB::Util # Creates a new TestRunner for running the passed # suite. :output option specifies where runner # output should go to; defaults to STDOUT. def initialize(suite, options={}) super @output = @options[:output] || STDOUT if @options[:output_file_descriptor] @output = IO.new(@options[:output_file_descriptor], "w") end @already_outputted = false @indent = 0 @top_level = true @current_test = nil @current_test_suite = nil @already_outputted = false end private def attach_to_mediator @mediator.add_listener(TestResult::PASS_ASSERTION, &method(:result_pass_assertion)) @mediator.add_listener(TestResult::FAULT, &method(:result_fault)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) @mediator.add_listener(TestCase::STARTED_OBJECT, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED_OBJECT, &method(:test_finished)) @mediator.add_listener(TestSuite::STARTED_OBJECT, &method(:test_suite_started)) @mediator.add_listener(TestSuite::FINISHED_OBJECT, &method(:test_suite_finished)) end def result_pass_assertion(result) open_tag("pass-assertion") do output_test(@current_test) end end def result_fault(fault) open_tag("test-result") do open_tag("result") do output_test_suite(@current_test_suite) output_test(@current_test) open_tag("backtrace") do fault.location.each do |entry| file, line, info = entry.split(/:/, 3) open_tag("entry") do add_content("file", file) add_content("line", line) add_content("info", info) end end end if fault.respond_to?(:expected) add_content("expected", fault.expected) end if fault.respond_to?(:actual) add_content("actual", fault.actual) end add_content("detail", fault.message) add_content("status", fault.label.downcase) end end @already_outputted = true if fault.critical? end def started(result) @result = result output_started end def output_started open_tag("stream") end def finished(elapsed_time) add_content("success", @result.passed?) close_tag("stream") end def test_started(test) @already_outputted = false @current_test = test open_tag("start-test") do output_test(test) end end def test_finished(test) unless @already_outputted open_tag("test-result") do output_test(test) open_tag("result") do output_test_suite(@current_test_suite) output_test(test) add_content("status", "success") end end end open_tag("complete-test") do output_test(test) add_content("success", test.passed?) end @current_test = nil end def test_suite_started(suite) @current_test_suite = suite if suite.test_case.nil? open_tag("ready-test-suite") do add_content("n-tests", suite.size) end open_tag("start-test-suite") do output_test_suite(suite) end else open_tag("ready-test-case") do output_test_suite(suite) add_content("n-tests", suite.size) end open_tag("start-test-case") do output_test_suite(suite) end end end def test_suite_finished(suite) if suite.test_case.nil? open_tag("complete-test-suite") do output_test_suite(suite) add_content("success", suite.passed?) end else open_tag("complete-test-case") do output_test_suite(suite) add_content("success", suite.passed?) end end @current_test_suite = nil end def indent " " * @indent end def open_tag(name) @output.puts("#{indent}<#{name}>") @indent += 2 if block_given? yield close_tag(name) end end def add_content(name, content) return if content.nil? case content when Time content = content.iso8601 end @output.puts("#{indent}<#{name}>#{h(content)}") end def close_tag(name) @indent -= 2 @output.puts("#{indent}") end def output_test(test) open_tag("test") do add_content("name", test.method_name) add_content("start-time", test.start_time) add_content("elapsed", test.elapsed_time) end end def output_test_suite(test_suite) test_case = test_suite.test_case if test_case.nil? open_tag("test-suite") do add_content("name", test_suite.name) add_content("start-time", test_suite.start_time) add_content("elapsed", test_suite.elapsed_time) end else open_tag("test-case") do add_content("name", test_suite.name) add_content("start-time", test_suite.start_time) add_content("elapsed", test_suite.elapsed_time) end end end end end end end end PKu]l~7test-unit-3.3.4/lib/test/unit/ui/console/outputlevel.rbnu[module Test module Unit module UI module Console module OutputLevel SILENT = 0 PROGRESS_ONLY = 1 IMPORTANT_FAULTS_ONLY = 2 NORMAL = 3 VERBOSE = 4 end end end end end PKu]!=(__6test-unit-3.3.4/lib/test/unit/ui/console/testrunner.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: # * Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # * Copyright (c) 2008-2017 Kouhei Sutou # License:: Ruby license. begin require 'io/console' rescue LoadError end require 'test/unit/color-scheme' require 'test/unit/code-snippet-fetcher' require 'test/unit/fault-location-detector' require 'test/unit/diff' require 'test/unit/ui/testrunner' require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/console/outputlevel' module Test module Unit module UI module Console # Runs a Test::Unit::TestSuite on the console. class TestRunner < UI::TestRunner include OutputLevel # Creates a new TestRunner for running the passed # suite. If quiet_mode is true, the output while # running is limited to progress dots, errors and # failures, and the final result. io specifies # where runner output should go to; defaults to # STDOUT. def initialize(suite, options={}) super @output_level = @options[:output_level] || NORMAL @output = @options[:output] || STDOUT @use_color = @options[:use_color] @use_color = guess_color_availability if @use_color.nil? @color_scheme = @options[:color_scheme] || ColorScheme.default @reset_color = Color.new("reset") @progress_row = 0 @progress_row_max = @options[:progress_row_max] @progress_row_max ||= guess_progress_row_max @show_detail_immediately = @options[:show_detail_immediately] @show_detail_immediately = true if @show_detail_immediately.nil? @reverse_output = @options[:reverse_output] @reverse_output = @output.tty? if @reverse_output.nil? @already_outputted = false @indent = 0 @top_level = true @current_output_level = NORMAL @faults = [] @code_snippet_fetcher = CodeSnippetFetcher.new @test_suites = [] end private def change_output_level(level) old_output_level = @current_output_level @current_output_level = level yield @current_output_level = old_output_level end def setup_mediator super output_setup_end end def output_setup_end suite_name = @suite.to_s suite_name = @suite.name if @suite.kind_of?(Module) output("Loaded suite #{suite_name}") end def attach_to_mediator @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) @mediator.add_listener(TestCase::STARTED_OBJECT, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED_OBJECT, &method(:test_finished)) @mediator.add_listener(TestSuite::STARTED_OBJECT, &method(:test_suite_started)) @mediator.add_listener(TestSuite::FINISHED_OBJECT, &method(:test_suite_finished)) end def add_fault(fault) @faults << fault output_progress(fault.single_character_display, fault_marker_color(fault)) output_progress_in_detail(fault) if @show_detail_immediately @already_outputted = true if fault.critical? end def started(result) @result = result output_started end def output_started output("Started") end def finished(elapsed_time) unless @show_detail_immediately nl if output?(NORMAL) and !output?(VERBOSE) output_faults end nl(PROGRESS_ONLY) change_output_level(IMPORTANT_FAULTS_ONLY) do output_statistics(elapsed_time) end end def output_faults categorized_faults = categorize_faults change_output_level(IMPORTANT_FAULTS_ONLY) do output_faults_in_detail(categorized_faults[:need_detail_faults]) end output_faults_in_short("Omissions", Omission, categorized_faults[:omissions]) output_faults_in_short("Notifications", Notification, categorized_faults[:notifications]) end def max_digit(max_number) (Math.log10(max_number) + 1).truncate end def output_faults_in_detail(faults) return if faults.nil? digit = max_digit(faults.size) faults.each_with_index do |fault, index| nl output_single("%#{digit}d) " % (index + 1)) output_fault_in_detail(fault) end end def output_faults_in_short(label, fault_class, faults) return if faults.nil? digit = max_digit(faults.size) nl output_single(label, fault_class_color(fault_class)) output(":") faults.each_with_index do |fault, index| output_single("%#{digit}d) " % (index + 1)) output_fault_in_short(fault) end end def categorize_faults faults = {} @faults.each do |fault| category = categorize_fault(fault) faults[category] ||= [] faults[category] << fault end faults end def categorize_fault(fault) case fault when Omission :omissions when Notification :notifications else :need_detail_faults end end def output_fault_in_detail(fault) if fault.is_a?(Failure) and fault.inspected_expected and fault.inspected_actual if @reverse_output output_fault_backtrace(fault) output_failure_message(fault) output_single("#{fault.label}: ") output(fault.test_name, fault_color(fault)) else output_single("#{fault.label}: ") output(fault.test_name, fault_color(fault)) output_fault_backtrace(fault) output_failure_message(fault) end else if @reverse_output output_fault_backtrace(fault) output_single("#{fault.label}: ") output_single(fault.test_name, fault_color(fault)) output_fault_message(fault) else output_single("#{fault.label}: ") output_single(fault.test_name, fault_color(fault)) output_fault_message(fault) output_fault_backtrace(fault) end end end def output_fault_message(fault) message = fault.message return if message.nil? if message.include?("\n") output(":") message.each_line do |line| output(" #{line.chomp}") end else output(": #{message}") end end def output_fault_backtrace(fault) detector = FaultLocationDetector.new(fault, @code_snippet_fetcher) backtrace = fault.location # workaround for test-spec. :< # see also GitHub:#22 backtrace ||= [] code_snippet_backtrace_index = nil code_snippet_lines = nil backtrace.each_with_index do |entry, i| next unless detector.target?(entry) file, line_number, = detector.split_backtrace_entry(entry) lines = fetch_code_snippet(file, line_number) unless lines.empty? code_snippet_backtrace_index = i code_snippet_lines = lines break end end if @reverse_output backtrace.each_with_index.reverse_each do |entry, i| if i == code_snippet_backtrace_index output_code_snippet(code_snippet_lines, fault_color(fault)) end output(entry) end else backtrace.each_with_index do |entry, i| output(entry) if i == code_snippet_backtrace_index output_code_snippet(code_snippet_lines, fault_color(fault)) end end end end def fetch_code_snippet(file, line_number) @code_snippet_fetcher.fetch(file, line_number) end def output_code_snippet(lines, target_line_color=nil) max_n = lines.collect {|n, line, attributes| n}.max digits = (Math.log10(max_n) + 1).truncate lines.each do |n, line, attributes| if attributes[:target_line?] line_color = target_line_color current_line_mark = "=>" else line_color = nil current_line_mark = "" end output(" %2s %*d: %s" % [current_line_mark, digits, n, line], line_color) end end def output_failure_message(failure) if failure.expected.respond_to?(:encoding) and failure.actual.respond_to?(:encoding) and failure.expected.encoding != failure.actual.encoding need_encoding = true else need_encoding = false end output(failure.user_message) if failure.user_message output_single("<") output_single(failure.inspected_expected, color("pass")) output_single(">") if need_encoding output_single("(") output_single(failure.expected.encoding.name, color("pass")) output_single(")") end output(" expected but was") output_single("<") output_single(failure.inspected_actual, color("failure")) output_single(">") if need_encoding output_single("(") output_single(failure.actual.encoding.name, color("failure")) output_single(")") end output("") from, to = prepare_for_diff(failure.expected, failure.actual) if from and to if need_encoding unless from.valid_encoding? from = from.dup.force_encoding("ASCII-8BIT") end unless to.valid_encoding? to = to.dup.force_encoding("ASCII-8BIT") end end from_lines = from.split(/\r?\n/) to_lines = to.split(/\r?\n/) if need_encoding from_lines << "" to_lines << "" from_lines << "Encoding: #{failure.expected.encoding.name}" to_lines << "Encoding: #{failure.actual.encoding.name}" end differ = ColorizedReadableDiffer.new(from_lines, to_lines, self) if differ.need_diff? output("") output("diff:") differ.diff end end end def output_fault_in_short(fault) if @reverse_output output(fault.location.first) output_single("#{fault.label}: ") output_single(fault.message, fault_color(fault)) output(" [#{fault.test_name}]") else output_single("#{fault.label}: ") output_single(fault.message, fault_color(fault)) output(" [#{fault.test_name}]") output(fault.location.first) end end def format_fault(fault) fault.long_display end def output_statistics(elapsed_time) output("Finished in #{elapsed_time} seconds.") output_summary_marker output(@result) output("%g%% passed" % @result.pass_percentage) unless elapsed_time.zero? output_summary_marker test_throughput = @result.run_count / elapsed_time assertion_throughput = @result.assertion_count / elapsed_time throughput = [ "%.2f tests/s" % test_throughput, "%.2f assertions/s" % assertion_throughput, ] output(throughput.join(", ")) end end def output_summary_marker if @progress_row_max > 0 output("-" * @progress_row_max, summary_marker_color) else nl end end def test_started(test) return unless output?(VERBOSE) tab_width = 8 name = test.local_name separator = ":" left_used = indent.size + name.size + separator.size right_space = tab_width * 2 left_space = @progress_row_max - right_space if (left_used % tab_width).zero? left_space -= left_used n_tabs = 0 else left_space -= ((left_used / tab_width) + 1) * tab_width n_tabs = 1 end n_tabs += [left_space, 0].max / tab_width tab_stop = "\t" * n_tabs output_single("#{indent}#{name}#{separator}#{tab_stop}", nil, VERBOSE) @test_start = Time.now end def test_finished(test) unless @already_outputted output_progress(".", color("pass-marker")) end @already_outputted = false return unless output?(VERBOSE) output(": (%f)" % (Time.now - @test_start), nil, VERBOSE) end def suite_name(prefix, suite) name = suite.name if name.nil? "(anonymous)" else name.sub(/\A#{Regexp.escape(prefix)}/, "") end end def test_suite_started(suite) last_test_suite = @test_suites.last @test_suites << suite if @top_level @top_level = false return end output_single(indent, nil, VERBOSE) if suite.test_case.nil? _color = color("suite") else _color = color("case") end prefix = "#{last_test_suite.name}::" output_single(suite_name(prefix, suite), _color, VERBOSE) output(": ", nil, VERBOSE) @indent += 2 end def test_suite_finished(suite) @indent -= 2 @test_suites.pop end def indent if output?(VERBOSE) " " * @indent else "" end end def nl(level=nil) output("", nil, level) end def output(something, color=nil, level=nil) return unless output?(level) output_single(something, color, level) @output.puts end def output_single(something, color=nil, level=nil) return false unless output?(level) if @use_color and color something = "%s%s%s" % [color.escape_sequence, something, @reset_color.escape_sequence] end @output.write(something) @output.flush true end def output_progress(mark, color=nil) if output_single(mark, color, PROGRESS_ONLY) return unless @progress_row_max > 0 @progress_row += mark.size if @progress_row >= @progress_row_max nl unless @output_level == VERBOSE @progress_row = 0 end end end def output_progress_in_detail_marker(fault) if @progress_row_max > 0 output("=" * @progress_row_max) else nl end end def output_progress_in_detail(fault) return if @output_level == SILENT nl output_progress_in_detail_marker(fault) if categorize_fault(fault) == :need_detail_faults output_fault_in_detail(fault) else output_fault_in_short(fault) end output_progress_in_detail_marker(fault) @progress_row = 0 end def output?(level) (level || @current_output_level) <= @output_level end def color(name) _color = @color_scheme[name] _color ||= @color_scheme["success"] if name == "pass" _color ||= ColorScheme.default[name] _color end def fault_class_color_name(fault_class) fault_class.name.split(/::/).last.downcase end def fault_class_color(fault_class) color(fault_class_color_name(fault_class)) end def fault_color(fault) fault_class_color(fault.class) end def fault_marker_color(fault) color("#{fault_class_color_name(fault.class)}-marker") end def summary_marker_color color("#{@result.status}-marker") end def guess_color_availability return false unless @output.tty? return true if windows? and ruby_2_0_or_later? case ENV["TERM"] when /(?:term|screen)(?:-(?:256)?color)?\z/ true when /\Arxvt/ true else return true if ENV["EMACS"] == "t" false end end def windows? /mswin|mingw/ === RUBY_PLATFORM end def ruby_2_0_or_later? RUBY_VERSION >= "2.0.0" end def guess_progress_row_max term_width = guess_term_width if term_width.zero? if ENV["EMACS"] == "t" -1 else 79 end else term_width end end def guess_term_width guess_term_width_from_io || guess_term_width_from_env || 0 end def guess_term_width_from_io if @output.respond_to?(:winsize) begin @output.winsize[1] rescue SystemCallError nil end else nil end end def guess_term_width_from_env env = ENV["COLUMNS"] || ENV["TERM_WIDTH"] return nil if env.nil? begin Integer(env) rescue ArgumentError nil end end end class ColorizedReadableDiffer < Diff::ReadableDiffer def initialize(from, to, runner) @runner = runner super(from, to) end def need_diff?(options={}) return false if one_line_all_change? operations.each do |tag,| return true if [:replace, :equal].include?(tag) end false end private def one_line_all_change? return false if operations.size != 1 tag, from_start, from_end, to_start, to_end = operations.first return false if tag != :replace return false if [from_start, from_end] != [0, 1] return false if [from_start, from_end] != [to_start, to_end] _, _, _line_operations = line_operations(@from.first, @to.first) _line_operations.size == 1 end def output_single(something, color=nil) @runner.__send__(:output_single, something, color) end def output(something, color=nil) @runner.__send__(:output, something, color) end def color(name) @runner.__send__(:color, name) end def cut_off_ratio 0 end def default_ratio 0 end def tag(mark, color_name, contents) _color = color(color_name) contents.each do |content| output_single(mark, _color) output_single(" ") output(content) end end def tag_deleted(contents) tag("-", "diff-deleted-tag", contents) end def tag_inserted(contents) tag("+", "diff-inserted-tag", contents) end def tag_equal(contents) tag(" ", "normal", contents) end def tag_difference(contents) tag("?", "diff-difference-tag", contents) end def diff_line(from_line, to_line) to_operations = [] from_line, to_line, _operations = line_operations(from_line, to_line) no_replace = true _operations.each do |tag,| if tag == :replace no_replace = false break end end output_single("?", color("diff-difference-tag")) output_single(" ") _operations.each do |tag, from_start, from_end, to_start, to_end| from_width = compute_width(from_line, from_start, from_end) to_width = compute_width(to_line, to_start, to_end) case tag when :replace output_single(from_line[from_start...from_end], color("diff-deleted")) if (from_width < to_width) output_single(" " * (to_width - from_width)) end to_operations << Proc.new do output_single(to_line[to_start...to_end], color("diff-inserted")) if (to_width < from_width) output_single(" " * (from_width - to_width)) end end when :delete output_single(from_line[from_start...from_end], color("diff-deleted")) unless no_replace to_operations << Proc.new {output_single(" " * from_width)} end when :insert if no_replace output_single(to_line[to_start...to_end], color("diff-inserted")) else output_single(" " * to_width) to_operations << Proc.new do output_single(to_line[to_start...to_end], color("diff-inserted")) end end when :equal output_single(from_line[from_start...from_end]) unless no_replace to_operations << Proc.new {output_single(" " * to_width)} end else raise "unknown tag: #{tag}" end end output("") unless to_operations.empty? output_single("?", color("diff-difference-tag")) output_single(" ") to_operations.each do |operation| operation.call end output("") end end end end end end end PKu]޸.test-unit-3.3.4/lib/test/unit/ui/testrunner.rbnu[require 'test/unit/ui/testrunnerutilities' module Test module Unit module UI class TestRunner extend TestRunnerUtilities attr_reader :listeners def initialize(suite, options={}) if suite.respond_to?(:suite) @suite = suite.suite else @suite = suite end @options = options @listeners = @options[:listeners] || [] end # Begins the test run. def start setup_mediator attach_to_mediator attach_listeners start_mediator end private def setup_mediator @mediator = TestRunnerMediator.new(@suite) end def attach_listeners @listeners.each do |listener| listener.attach_to_mediator(@mediator) end end def start_mediator @mediator.run end def diff_target_string?(string) Assertions::AssertionMessage.diff_target_string?(string) end def prepare_for_diff(from, to) Assertions::AssertionMessage.prepare_for_diff(from, to) end end end end end PKu]N N 6test-unit-3.3.4/lib/test/unit/ui/testrunnermediator.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/observable' require 'test/unit/testresult' module Test module Unit module UI # Provides an interface to write any given UI against, # hopefully making it easy to write new UIs. class TestRunnerMediator RESET = name + "::RESET" STARTED = name + "::STARTED" FINISHED = name + "::FINISHED" include Util::Observable # Creates a new TestRunnerMediator initialized to run # the passed suite. def initialize(suite) @suite = suite end # Runs the suite the TestRunnerMediator was created # with. def run AutoRunner.need_auto_run = false result = create_result Test::Unit.run_at_start_hooks start_time = Time.now begin catch do |stop_tag| result.stop_tag = stop_tag with_listener(result) do notify_listeners(RESET, @suite.size) notify_listeners(STARTED, result) run_suite(result) end end ensure elapsed_time = Time.now - start_time notify_listeners(FINISHED, elapsed_time) end Test::Unit.run_at_exit_hooks result end # Just for backward compatibility for NetBeans. # NetBeans should not use monkey patching. NetBeans # should use runner change public API. # # See GitHub#38 # https://github.com/test-unit/test-unit/issues/38 def run_suite(result=nil) if result.nil? run else @suite.run(result) do |channel, value| notify_listeners(channel, value) end end end private # A factory method to create the result the mediator # should run with. Can be overridden by subclasses if # one wants to use a different result. def create_result TestResult.new end def measure_time begin_time = Time.now yield Time.now - begin_time end def with_listener(result) finished_listener = result.add_listener(TestResult::FINISHED) do |*args| notify_listeners(TestResult::FINISHED, *args) end changed_listener = result.add_listener(TestResult::CHANGED) do |*args| notify_listeners(TestResult::CHANGED, *args) end pass_assertion_listener = result.add_listener(TestResult::PASS_ASSERTION) do |*args| notify_listeners(TestResult::PASS_ASSERTION, *args) end fault_listener = result.add_listener(TestResult::FAULT) do |*args| notify_listeners(TestResult::FAULT, *args) end begin yield ensure result.remove_listener(TestResult::FAULT, fault_listener) result.remove_listener(TestResult::CHANGED, changed_listener) result.remove_listener(TestResult::FINISHED, finished_listener) result.remove_listener(TestResult::PASS_ASSERTION, pass_assertion_listener) end end end end end end PKu]KE::*test-unit-3.3.4/lib/test/unit/collector.rbnu[module Test module Unit module Collector def initialize @filters = [] end def filter=(filters) @filters = case(filters) when Proc [filters] when Array filters end end def add_suite(destination, suite) to_delete = suite.tests.find_all do |test| test.is_a?(TestCase) and !include?(test) end suite.delete_tests(to_delete) destination << suite unless suite.empty? end def add_test_cases(suite, test_cases) children_map = {} test_cases.each do |test_case| ancestor_classes = test_case.ancestors.find_all do |ancestor| ancestor.is_a?(Class) end parent = ancestor_classes[1] children_map[parent] ||= [] children_map[parent] << test_case end root_test_cases = children_map.keys - test_cases root_test_cases.each do |root_test_case| add_test_case(suite, root_test_case, children_map) end end def include?(test) return true if(@filters.empty?) @filters.each do |filter| return false if filter[test] == false end true end def sort(suites) suites.sort_by do |suite| [suite.priority, suite.name || suite.to_s] end end private def add_test_case(suite, test_case, children_map) children = children_map[test_case] return if children.nil? sub_suites = [] children.each do |child| sub_suite = child.suite add_test_case(sub_suite, child, children_map) add_suite(sub_suites, sub_suite) end sort(sub_suites).each do |sub_suite| suite << sub_suite end end end end end PKu]Vݯ2test-unit-3.3.4/lib/test/unit/attribute-matcher.rbnu[module Test module Unit class AttributeMatcher def initialize(test) @test = test end def match?(expression) matched = instance_eval(expression) if matched.nil? false else matched end end def method_missing(name, *args) if args.empty? @test[name] else super end end end end end PKu]-K@K@ test-unit-3.3.4/lib/test/unit.rbnu[require 'test/unit/testcase' require 'test/unit/autorunner' module Test # :nodoc: # # # Test::Unit - Ruby Unit Testing Framework # # ## Introduction # # Unit testing is making waves all over the place, largely due to the # fact that it is a core practice of XP. While XP is great, unit testing # has been around for a long time and has always been a good idea. One # of the keys to good unit testing, though, is not just writing tests, # but having tests. What's the difference? Well, if you just _write_ a # test and throw it away, you have no guarantee that something won't # change later which breaks your code. If, on the other hand, you _have_ # tests (obviously you have to write them first), and run them as often # as possible, you slowly build up a wall of things that cannot break # without you immediately knowing about it. This is when unit testing # hits its peak usefulness. # # Enter Test::Unit, a framework for unit testing in Ruby, helping you to # design, debug and evaluate your code by making it easy to write and # have tests for it. # # # ## Notes # # Test::Unit has grown out of and superceded Lapidary. # # # ## Feedback # # I like (and do my best to practice) XP, so I value early releases, # user feedback, and clean, simple, expressive code. There is always # room for improvement in everything I do, and Test::Unit is no # exception. Please, let me know what you think of Test::Unit as it # stands, and what you'd like to see expanded/changed/improved/etc. If # you find a bug, let me know ASAP; one good way to let me know what the # bug is is to submit a new test that catches it :-) Also, I'd love to # hear about any successes you have with Test::Unit, and any # documentation you might add will be greatly appreciated. My contact # info is below. # # # ## Contact Information # # A lot of discussion happens about Ruby in general on the ruby-talk # mailing list (http://www.ruby-lang.org/en/ml.html), and you can ask # any questions you might have there. I monitor the list, as do many # other helpful Rubyists, and you're sure to get a quick answer. Of # course, you're also welcome to email me (Nathaniel Talbott) directly # at mailto:testunit@talbott.ws, and I'll do my best to help you out. # # # ## Credits # # I'd like to thank... # # Matz, for a great language! # # Masaki Suketa, for his work on RubyUnit, which filled a vital need in # the Ruby world for a very long time. I'm also grateful for his help in # polishing Test::Unit and getting the RubyUnit compatibility layer # right. His graciousness in allowing Test::Unit to supercede RubyUnit # continues to be a challenge to me to be more willing to defer my own # rights. # # Ken McKinlay, for his interest and work on unit testing, and for his # willingness to dialog about it. He was also a great help in pointing # out some of the holes in the RubyUnit compatibility layer. # # Dave Thomas, for the original idea that led to the extremely simple # "require 'test/unit'", plus his code to improve it even more by # allowing the selection of tests from the command-line. Also, without # RDoc, the documentation for Test::Unit would stink a lot more than it # does now. # # Everyone who's helped out with bug reports, feature ideas, # encouragement to continue, etc. It's a real privilege to be a part of # the Ruby community. # # The guys at RoleModel Software, for putting up with me repeating, "But # this would be so much easier in Ruby!" whenever we're coding in Java. # # My Creator, for giving me life, and giving it more abundantly. # # # ## License # # Test::Unit is copyright (c) 2000-2003 Nathaniel Talbott. It is free # software, and is distributed under the Ruby license. See the COPYING # file. # # Exception: lib/test/unit/diff.rb is copyright (c) # 2008-2010 Kouhei Sutou and 2001-2008 Python Software # Foundation. It is free software, and is distributed # under the Ruby license and/or the PSF license. See the # COPYING file and PSFL file. # # ## Warranty # # This software is provided "as is" and without any express or # implied warranties, including, without limitation, the implied # warranties of merchantibility and fitness for a particular # purpose. # # # ## Author # # Nathaniel Talbott. # Copyright (c) 2000-2003, Nathaniel Talbott # # ---- # # # Usage # # The general idea behind unit testing is that you write a _test_ # _method_ that makes certain _assertions_ about your code, working # against a _test_ _fixture_. A bunch of these _test_ _methods_ are # bundled up into a _test_ _suite_ and can be run any time the # developer wants. The results of a run are gathered in a _test_ # _result_ and displayed to the user through some UI. So, lets break # this down and see how Test::Unit provides each of these necessary # pieces. # # # ## Assertions # # These are the heart of the framework. Think of an assertion as a # statement of expected outcome, i.e. "I assert that x should be equal # to y". If, when the assertion is executed, it turns out to be # correct, nothing happens, and life is good. If, on the other hand, # your assertion turns out to be false, an error is propagated with # pertinent information so that you can go back and make your # assertion succeed, and, once again, life is good. For an explanation # of the current assertions, see Test::Unit::Assertions. # # # ## Test Method & Test Fixture # # Obviously, these assertions have to be called within a context that # knows about them and can do something meaningful with their # pass/fail value. Also, it's handy to collect a bunch of related # tests, each test represented by a method, into a common test class # that knows how to run them. The tests will be in a separate class # from the code they're testing for a couple of reasons. First of all, # it allows your code to stay uncluttered with test code, making it # easier to maintain. Second, it allows the tests to be stripped out # for deployment, since they're really there for you, the developer, # and your users don't need them. Third, and most importantly, it # allows you to set up a common test fixture for your tests to run # against. # # What's a test fixture? Well, tests do not live in a vacuum; rather, # they're run against the code they are testing. Often, a collection # of tests will run against a common set of data, also called a # fixture. If they're all bundled into the same test class, they can # all share the setting up and tearing down of that data, eliminating # unnecessary duplication and making it much easier to add related # tests. # # Test::Unit::TestCase wraps up a collection of test methods together # and allows you to easily set up and tear down the same test fixture # for each test. This is done by overriding #setup and/or #teardown, # which will be called before and after each test method that is # run. The TestCase also knows how to collect the results of your # assertions into a Test::Unit::TestResult, which can then be reported # back to you... but I'm getting ahead of myself. To write a test, # follow these steps: # # * Make sure Test::Unit is in your library path. # * require 'test/unit' in your test script. # * Create a class that subclasses Test::Unit::TestCase. # * Add a method that begins with "test" to your class. # * Make assertions in your test method. # * Optionally define #setup and/or #teardown to set up and/or tear # down your common test fixture. # * You can now run your test as you would any other Ruby # script... try it and see! # # A really simple test might look like this (#setup and #teardown are # commented out to indicate that they are completely optional): # # require 'test/unit' # # class MyTest < Test::Unit::TestCase # # def setup # # end # # # def teardown # # end # # def test_fail # assert(false, 'Assertion was false.') # end # end # # # ## Test Runners # # So, now you have this great test class, but you still # need a way to run it and view any failures that occur # during the run. There are some test runner; console test # runner, GTK+ test runner and so on. The console test # runner is automatically invoked for you if you require # 'test/unit' and simply run the file. To use another # runner simply set default test runner ID to # Test::Unit::AutoRunner: # # require 'test/unit' # Test::Unit::AutoRunner.default_runner = "gtk2" # # ## Test Suite # # As more and more unit tests accumulate for a given project, it # becomes a real drag running them one at a time, and it also # introduces the potential to overlook a failing test because you # forget to run it. Suddenly it becomes very handy that the # TestRunners can take any object that returns a Test::Unit::TestSuite # in response to a suite method. The TestSuite can, in turn, contain # other TestSuites or individual tests (typically created by a # TestCase). In other words, you can easily wrap up a group of # TestCases and TestSuites. # # Test::Unit does a little bit more for you, by wrapping # these up automatically when you require # 'test/unit'. What does this mean? It means you could # write the above test case like this instead: # # require 'test/unit' # require 'test_myfirsttests' # require 'test_moretestsbyme' # require 'test_anothersetoftests' # # Test::Unit is smart enough to find all the test cases existing in # the ObjectSpace and wrap them up into a suite for you. It then runs # the dynamic suite using the console TestRunner. # # # ## Configuration file # # Test::Unit reads 'test-unit.yml' in the current working # directory as Test::Unit's configuration file. It can # contain the following configurations: # # * color scheme definitions # * test runner to be used # * test runner options # * test collector to be used # # Except color scheme definitions, all of them are # specified by command line option. # # Here are sample color scheme definitions: # # color_schemes: # inverted: # success: # name: red # bold: true # failure: # name: green # bold: true # other_scheme: # ... # # Here are the syntax of color scheme definitions: # # color_schemes: # SCHEME_NAME: # EVENT_NAME: # name: COLOR_NAME # intensity: BOOLEAN # bold: BOOLEAN # italic: BOOLEAN # underline: BOOLEAN # ... # ... # # SCHEME_NAME # : the name of the color scheme # # EVENT_NAME # : one of [success, failure, pending, omission, notification, error] # # COLOR_NAME # : one of [black, red, green, yellow, blue, magenta, cyan, white] # # BOOLEAN # : true or false # # You can use the above 'inverted' color scheme with the # following configuration: # # runner: console # console_options: # color_scheme: inverted # color_schemes: # inverted: # success: # name: red # bold: true # failure: # name: green # bold: true # # ## Questions? # # I'd really like to get feedback from all levels of Ruby # practitioners about typos, grammatical errors, unclear statements, # missing points, etc., in this document (or any other). # module Unit class << self # Set true when Test::Unit has run. If set to true Test::Unit # will not automatically run at exit. # # @deprecated Use Test::Unit::AutoRunner.need_auto_run= instead. def run=(have_run) AutoRunner.need_auto_run = (not have_run) end # Already tests have run? # # @deprecated Use Test::Unit::AutoRunner.need_auto_run? instead. def run? not AutoRunner.need_auto_run? end # @api private @@at_start_hooks = [] # Regsiter a hook that is run before running tests. # To register multiple hooks, call this method multiple times. # # Here is an example test case: # # Test::Unit.at_start do # # ... # end # # class TestMyClass1 < Test::Unit::TestCase # class << self # def startup # # ... # end # end # # def setup # # ... # end # # def test_my_class1 # # ... # end # # def test_my_class2 # # ... # end # end # # class TestMyClass2 < Test::Unit::TestCase # class << self # def startup # # ... # end # end # # def setup # # ... # end # # def test_my_class1 # # ... # end # # def test_my_class2 # # ... # end # end # # Here is a call order: # # * at_start # * TestMyClass1.startup # * TestMyClass1#setup # * TestMyClass1#test_my_class1 # * TestMyClass1#setup # * TestMyClass1#test_my_class2 # * TestMyClass2#setup # * TestMyClass2#test_my_class1 # * TestMyClass2#setup # * TestMyClass2#test_my_class2 # # @example # Test::Unit.at_start do # puts "Start!" # end # # @yield A block that is run before running tests. # @yieldreturn [void] # @return [void] # # @since 2.5.2 def at_start(&hook) @@at_start_hooks << hook end # @api private def run_at_start_hooks @@at_start_hooks.each do |hook| hook.call end end # @api private @@at_exit_hooks = [] # Regsiter a hook that is run after running tests. # To register multiple hooks, call this method multiple times. # # Here is an example test case: # # Test::Unit.at_exit do # # ... # end # # class TestMyClass1 < Test::Unit::TestCase # class << self # def shutdown # # ... # end # end # # def teardown # # ... # end # # def test_my_class1 # # ... # end # # def test_my_class2 # # ... # end # end # # class TestMyClass2 < Test::Unit::TestCase # class << self # def shutdown # # ... # end # end # # def teardown # # ... # end # # def test_my_class1 # # ... # end # # def test_my_class2 # # ... # end # end # # Here is a call order: # # * TestMyClass1#test_my_class1 # * TestMyClass1#teardown # * TestMyClass1#test_my_class2 # * TestMyClass1#teardown # * TestMyClass1.shutdown # * TestMyClass2#test_my_class1 # * TestMyClass2#teardown # * TestMyClass2#test_my_class2 # * TestMyClass2#teardown # * TestMyClass2.shutdown # * at_exit # # @example # Test::Unit.at_exit do # puts "Exit!" # end # # @yield A block that is run after running tests. # @yieldreturn [void] # @return [void] # # @since 2.5.2 def at_exit(&hook) @@at_exit_hooks << hook end # @api private def run_at_exit_hooks @@at_exit_hooks.each do |hook| hook.call end end end end end Module.new do at_exit do if $!.nil? and Test::Unit::AutoRunner.need_auto_run? exit Test::Unit::AutoRunner.run end end end PKu] O test-unit-3.3.4/lib/test-unit.rbnu[# Copyright (C) 2012-2015 Kouhei Sutou # # License: Ruby's or LGPLv2.1 or later # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA module Test module Unit autoload :TestCase, "test/unit/testcase" autoload :AutoRunner, "test/unit/autorunner" end end unless respond_to?(:run_test, true) # experimental. It is for "ruby -rtest-unit -e run_test test/test_*.rb". # Is this API OK or dirty? def run_test self.class.send(:undef_method, :run_test) require "test/unit" end end PKu]json-2.3.0/lib/json.rbnu[#frozen_string_literal: false require 'json/common' ## # = JavaScript Object Notation (JSON) # # JSON is a lightweight data-interchange format. It is easy for us # humans to read and write. Plus, equally simple for machines to generate or parse. # JSON is completely language agnostic, making it the ideal interchange format. # # Built on two universally available structures: # 1. A collection of name/value pairs. Often referred to as an _object_, hash table, record, struct, keyed list, or associative array. # 2. An ordered list of values. More commonly called an _array_, vector, sequence or list. # # To read more about JSON visit: http://json.org # # == Parsing JSON # # To parse a JSON string received by another application or generated within # your existing application: # # require 'json' # # my_hash = JSON.parse('{"hello": "goodbye"}') # puts my_hash["hello"] => "goodbye" # # Notice the extra quotes '' around the hash notation. Ruby expects # the argument to be a string and can't convert objects like a hash or array. # # Ruby converts your string into a hash # # == Generating JSON # # Creating a JSON string for communication or serialization is # just as simple. # # require 'json' # # my_hash = {:hello => "goodbye"} # puts JSON.generate(my_hash) => "{\"hello\":\"goodbye\"}" # # Or an alternative way: # # require 'json' # puts {:hello => "goodbye"}.to_json => "{\"hello\":\"goodbye\"}" # # JSON.generate only allows objects or arrays to be converted # to JSON syntax. to_json, however, accepts many Ruby classes # even though it acts only as a method for serialization: # # require 'json' # # 1.to_json => "1" # module JSON require 'json/version' begin require 'json/ext' rescue LoadError require 'json/pure' end end PKu]oaa%json-2.3.0/lib/json/add/bigdecimal.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end defined?(::BigDecimal) or require 'bigdecimal' class BigDecimal # Import a JSON Marshalled object. # # method used for JSON marshalling support. def self.json_create(object) BigDecimal._load object['b'] end # Marshal the object to JSON. # # method used for JSON marshalling support. def as_json(*) { JSON.create_id => self.class.name, 'b' => _dump, } end # return the JSON value def to_json(*args) as_json.to_json(*args) end end PKu]&a\\json-2.3.0/lib/json/add/core.rbnu[#frozen_string_literal: false # This file requires the implementations of ruby core's custom objects for # serialisation/deserialisation. require 'json/add/date' require 'json/add/date_time' require 'json/add/exception' require 'json/add/range' require 'json/add/regexp' require 'json/add/struct' require 'json/add/symbol' require 'json/add/time' PKu]@9%!json-2.3.0/lib/json/add/regexp.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Regexp # Deserializes JSON string by constructing new Regexp object with source # s (Regexp or String) and options o serialized by # to_json def self.json_create(object) new(object['s'], object['o']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'o' => options, 's' => source, } end # Stores class name (Regexp) with options o and source s # (Regexp or String) as JSON string def to_json(*args) as_json.to_json(*args) end end PKu]ff!json-2.3.0/lib/json/add/symbol.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Symbol # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 's' => to_s, } end # Stores class name (Symbol) with String representation of Symbol as a JSON string. def to_json(*a) as_json.to_json(*a) end # Deserializes JSON string by converting the string value stored in the object to a Symbol def self.json_create(o) o['s'].to_sym end end PKu]m"json-2.3.0/lib/json/add/ostruct.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end require 'ostruct' class OpenStruct # Deserializes JSON string by constructing new Struct object with values # t serialized by to_json. def self.json_create(object) new(object['t'] || object[:t]) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) klass = self.class.name klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!" { JSON.create_id => klass, 't' => table, } end # Stores class name (OpenStruct) with this struct's values t as a # JSON string. def to_json(*args) as_json.to_json(*args) end end PKu]V#json-2.3.0/lib/json/add/rational.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end defined?(::Rational) or require 'rational' class Rational # Deserializes JSON string by converting numerator value n, # denominator value d, to a Rational object. def self.json_create(object) Rational(object['n'], object['d']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'n' => numerator, 'd' => denominator, } end # Stores class name (Rational) along with numerator value n and denominator value d as JSON string def to_json(*args) as_json.to_json(*args) end end PKu]&"json-2.3.0/lib/json/add/complex.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end defined?(::Complex) or require 'complex' class Complex # Deserializes JSON string by converting Real value r, imaginary # value i, to a Complex object. def self.json_create(object) Complex(object['r'], object['i']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'r' => real, 'i' => imag, } end # Stores class name (Complex) along with real value r and imaginary value i as JSON string def to_json(*args) as_json.to_json(*args) end end PKu]k$json-2.3.0/lib/json/add/exception.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Exception # Deserializes JSON string by constructing new Exception object with message # m and backtrace b serialized with to_json def self.json_create(object) result = new(object['m']) result.set_backtrace object['b'] result end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'm' => message, 'b' => backtrace, } end # Stores class name (Exception) with message m and backtrace array # b as JSON string def to_json(*args) as_json.to_json(*args) end end PKu]!!json-2.3.0/lib/json/add/set.rbnu[unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end defined?(::Set) or require 'set' class Set # Import a JSON Marshalled object. # # method used for JSON marshalling support. def self.json_create(object) new object['a'] end # Marshal the object to JSON. # # method used for JSON marshalling support. def as_json(*) { JSON.create_id => self.class.name, 'a' => to_a, } end # return the JSON value def to_json(*args) as_json.to_json(*args) end end PKu]Jjson-2.3.0/lib/json/add/time.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Time # Deserializes JSON string by converting time since epoch to Time def self.json_create(object) if usec = object.delete('u') # used to be tv_usec -> tv_nsec object['n'] = usec * 1000 end if method_defined?(:tv_nsec) at(object['s'], Rational(object['n'], 1000)) else at(object['s'], object['n'] / 1000) end end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) nanoseconds = [ tv_usec * 1000 ] respond_to?(:tv_nsec) and nanoseconds << tv_nsec nanoseconds = nanoseconds.max { JSON.create_id => self.class.name, 's' => tv_sec, 'n' => nanoseconds, } end # Stores class name (Time) with number of seconds since epoch and number of # microseconds for Time as JSON string def to_json(*args) as_json.to_json(*args) end end PKu]mqqjson-2.3.0/lib/json/add/date.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end require 'date' class Date # Deserializes JSON string by converting Julian year y, month # m, day d and Day of Calendar Reform sg to Date. def self.json_create(object) civil(*object.values_at('y', 'm', 'd', 'sg')) end alias start sg unless method_defined?(:start) # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'y' => year, 'm' => month, 'd' => day, 'sg' => start, } end # Stores class name (Date) with Julian year y, month m, day # d and Day of Calendar Reform sg as JSON string def to_json(*args) as_json.to_json(*args) end end PKu]1+Ǔ00$json-2.3.0/lib/json/add/date_time.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end require 'date' class DateTime # Deserializes JSON string by converting year y, month m, # day d, hour H, minute M, second S, # offset of and Day of Calendar Reform sg to DateTime. def self.json_create(object) args = object.values_at('y', 'm', 'd', 'H', 'M', 'S') of_a, of_b = object['of'].split('/') if of_b and of_b != '0' args << Rational(of_a.to_i, of_b.to_i) else args << of_a end args << object['sg'] civil(*args) end alias start sg unless method_defined?(:start) # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'y' => year, 'm' => month, 'd' => day, 'H' => hour, 'M' => min, 'S' => sec, 'of' => offset.to_s, 'sg' => start, } end # Stores class name (DateTime) with Julian year y, month m, # day d, hour H, minute M, second S, # offset of and Day of Calendar Reform sg as JSON string def to_json(*args) as_json.to_json(*args) end end PKu]a json-2.3.0/lib/json/add/range.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Range # Deserializes JSON string by constructing new Range object with arguments # a serialized by to_json. def self.json_create(object) new(*object['a']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) { JSON.create_id => self.class.name, 'a' => [ first, last, exclude_end? ] } end # Stores class name (Range) with JSON array of arguments a which # include first (integer), last (integer), and # exclude_end? (boolean) as JSON string. def to_json(*args) as_json.to_json(*args) end end PKu]%!json-2.3.0/lib/json/add/struct.rbnu[#frozen_string_literal: false unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED require 'json' end class Struct # Deserializes JSON string by constructing new Struct object with values # v serialized by to_json. def self.json_create(object) new(*object['v']) end # Returns a hash, that will be turned into a JSON object and represent this # object. def as_json(*) klass = self.class.name klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!" { JSON.create_id => klass, 'v' => values, } end # Stores class name (Struct) with Struct values v as a JSON string. # Only named structs are supported. def to_json(*args) as_json.to_json(*args) end end PKu]Ht..json-2.3.0/lib/json/version.rbnu[# frozen_string_literal: false module JSON # JSON version VERSION = '2.3.0' VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc: VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc: VERSION_MINOR = VERSION_ARRAY[1] # :nodoc: VERSION_BUILD = VERSION_ARRAY[2] # :nodoc: end PKu];;json-2.3.0/lib/json/common.rbnu[#frozen_string_literal: false require 'json/version' require 'json/generic_object' module JSON class << self # If _object_ is string-like, parse the string and return the parsed # result as a Ruby data structure. Otherwise generate a JSON text from the # Ruby data structure object and return it. # # The _opts_ argument is passed through to generate/parse respectively. # See generate and parse for their documentation. def [](object, opts = {}) if object.respond_to? :to_str JSON.parse(object.to_str, opts) else JSON.generate(object, opts) end end # Returns the JSON parser class that is used by JSON. This is either # JSON::Ext::Parser or JSON::Pure::Parser. attr_reader :parser # Set the JSON parser class _parser_ to be used by JSON. def parser=(parser) # :nodoc: @parser = parser remove_const :Parser if const_defined?(:Parser, false) const_set :Parser, parser end # Return the constant located at _path_. The format of _path_ has to be # either ::A::B::C or A::B::C. In any case, A has to be located at the top # level (absolute namespace path?). If there doesn't exist a constant at # the given path, an ArgumentError is raised. def deep_const_get(path) # :nodoc: path.to_s.split(/::/).inject(Object) do |p, c| case when c.empty? then p when p.const_defined?(c, true) then p.const_get(c) else begin p.const_missing(c) rescue NameError => e raise ArgumentError, "can't get const #{path}: #{e}" end end end end # Set the module _generator_ to be used by JSON. def generator=(generator) # :nodoc: old, $VERBOSE = $VERBOSE, nil @generator = generator generator_methods = generator::GeneratorMethods for const in generator_methods.constants klass = deep_const_get(const) modul = generator_methods.const_get(const) klass.class_eval do instance_methods(false).each do |m| m.to_s == 'to_json' and remove_method m end include modul end end self.state = generator::State const_set :State, self.state const_set :SAFE_STATE_PROTOTYPE, State.new const_set :FAST_STATE_PROTOTYPE, State.new( :indent => '', :space => '', :object_nl => "", :array_nl => "", :max_nesting => false ) const_set :PRETTY_STATE_PROTOTYPE, State.new( :indent => ' ', :space => ' ', :object_nl => "\n", :array_nl => "\n" ) ensure $VERBOSE = old end # Returns the JSON generator module that is used by JSON. This is # either JSON::Ext::Generator or JSON::Pure::Generator. attr_reader :generator # Returns the JSON generator state class that is used by JSON. This is # either JSON::Ext::Generator::State or JSON::Pure::Generator::State. attr_accessor :state # This is create identifier, which is used to decide if the _json_create_ # hook of a class should be called. It defaults to 'json_class'. attr_accessor :create_id end self.create_id = 'json_class' NaN = 0.0/0 Infinity = 1.0/0 MinusInfinity = -Infinity # The base exception for JSON errors. class JSONError < StandardError def self.wrap(exception) obj = new("Wrapped(#{exception.class}): #{exception.message.inspect}") obj.set_backtrace exception.backtrace obj end end # This exception is raised if a parser error occurs. class ParserError < JSONError; end # This exception is raised if the nesting of parsed data structures is too # deep. class NestingError < ParserError; end # :stopdoc: class CircularDatastructure < NestingError; end # :startdoc: # This exception is raised if a generator or unparser error occurs. class GeneratorError < JSONError; end # For backwards compatibility UnparserError = GeneratorError # This exception is raised if the required unicode support is missing on the # system. Usually this means that the iconv library is not installed. class MissingUnicodeSupport < JSONError; end module_function # Parse the JSON document _source_ into a Ruby data structure and return it. # # _opts_ can have the following # keys: # * *max_nesting*: The maximum depth of nesting allowed in the parsed data # structures. Disable depth checking with :max_nesting => false. It # defaults to 100. # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in # defiance of RFC 7159 to be parsed by the Parser. This option defaults # to false. # * *symbolize_names*: If set to true, returns symbols for the names # (keys) in a JSON object. Otherwise strings are returned. Strings are # the default. # * *create_additions*: If set to false, the Parser doesn't create # additions even if a matching class and create_id was found. This option # defaults to false. # * *object_class*: Defaults to Hash # * *array_class*: Defaults to Array def parse(source, opts = {}) Parser.new(source, **(opts||{})).parse end # Parse the JSON document _source_ into a Ruby data structure and return it. # The bang version of the parse method defaults to the more dangerous values # for the _opts_ hash, so be sure only to parse trusted _source_ documents. # # _opts_ can have the following keys: # * *max_nesting*: The maximum depth of nesting allowed in the parsed data # structures. Enable depth checking with :max_nesting => anInteger. The # parse! methods defaults to not doing max depth checking: This can be # dangerous if someone wants to fill up your stack. # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in # defiance of RFC 7159 to be parsed by the Parser. This option defaults # to true. # * *create_additions*: If set to false, the Parser doesn't create # additions even if a matching class and create_id was found. This option # defaults to false. def parse!(source, opts = {}) opts = { :max_nesting => false, :allow_nan => true }.merge(opts) Parser.new(source, **(opts||{})).parse end # Generate a JSON document from the Ruby data structure _obj_ and return # it. _state_ is * a JSON::State object, # * or a Hash like object (responding to to_hash), # * an object convertible into a hash by a to_h method, # that is used as or to configure a State object. # # It defaults to a state object, that creates the shortest possible JSON text # in one line, checks for circular data structures and doesn't allow NaN, # Infinity, and -Infinity. # # A _state_ hash can have the following keys: # * *indent*: a string used to indent levels (default: ''), # * *space*: a string that is put after, a : or , delimiter (default: ''), # * *space_before*: a string that is put before a : pair delimiter (default: ''), # * *object_nl*: a string that is put at the end of a JSON object (default: ''), # * *array_nl*: a string that is put at the end of a JSON array (default: ''), # * *allow_nan*: true if NaN, Infinity, and -Infinity should be # generated, otherwise an exception is thrown if these values are # encountered. This options defaults to false. # * *max_nesting*: The maximum depth of nesting allowed in the data # structures from which JSON is to be generated. Disable depth checking # with :max_nesting => false, it defaults to 100. # # See also the fast_generate for the fastest creation method with the least # amount of sanity checks, and the pretty_generate method for some # defaults for pretty output. def generate(obj, opts = nil) if State === opts state, opts = opts, nil else state = SAFE_STATE_PROTOTYPE.dup end if opts if opts.respond_to? :to_hash opts = opts.to_hash elsif opts.respond_to? :to_h opts = opts.to_h else raise TypeError, "can't convert #{opts.class} into Hash" end state = state.configure(opts) end state.generate(obj) end # :stopdoc: # I want to deprecate these later, so I'll first be silent about them, and # later delete them. alias unparse generate module_function :unparse # :startdoc: # Generate a JSON document from the Ruby data structure _obj_ and return it. # This method disables the checks for circles in Ruby objects. # # *WARNING*: Be careful not to pass any Ruby data structures with circles as # _obj_ argument because this will cause JSON to go into an infinite loop. def fast_generate(obj, opts = nil) if State === opts state, opts = opts, nil else state = FAST_STATE_PROTOTYPE.dup end if opts if opts.respond_to? :to_hash opts = opts.to_hash elsif opts.respond_to? :to_h opts = opts.to_h else raise TypeError, "can't convert #{opts.class} into Hash" end state.configure(opts) end state.generate(obj) end # :stopdoc: # I want to deprecate these later, so I'll first be silent about them, and later delete them. alias fast_unparse fast_generate module_function :fast_unparse # :startdoc: # Generate a JSON document from the Ruby data structure _obj_ and return it. # The returned document is a prettier form of the document returned by # #unparse. # # The _opts_ argument can be used to configure the generator. See the # generate method for a more detailed explanation. def pretty_generate(obj, opts = nil) if State === opts state, opts = opts, nil else state = PRETTY_STATE_PROTOTYPE.dup end if opts if opts.respond_to? :to_hash opts = opts.to_hash elsif opts.respond_to? :to_h opts = opts.to_h else raise TypeError, "can't convert #{opts.class} into Hash" end state.configure(opts) end state.generate(obj) end # :stopdoc: # I want to deprecate these later, so I'll first be silent about them, and later delete them. alias pretty_unparse pretty_generate module_function :pretty_unparse # :startdoc: class << self # The global default options for the JSON.load method: # :max_nesting: false # :allow_nan: true # :allow_blank: true attr_accessor :load_default_options end self.load_default_options = { :max_nesting => false, :allow_nan => true, :allow_blank => true, :create_additions => true, } # Load a ruby data structure from a JSON _source_ and return it. A source can # either be a string-like object, an IO-like object, or an object responding # to the read method. If _proc_ was given, it will be called with any nested # Ruby object as an argument recursively in depth first order. To modify the # default options pass in the optional _options_ argument as well. # # BEWARE: This method is meant to serialise data from trusted user input, # like from your own database server or clients under your control, it could # be dangerous to allow untrusted users to pass JSON sources into it. The # default options for the parser can be changed via the load_default_options # method. # # This method is part of the implementation of the load/dump interface of # Marshal and YAML. def load(source, proc = nil, options = {}) opts = load_default_options.merge options if source.respond_to? :to_str source = source.to_str elsif source.respond_to? :to_io source = source.to_io.read elsif source.respond_to?(:read) source = source.read end if opts[:allow_blank] && (source.nil? || source.empty?) source = 'null' end result = parse(source, opts) recurse_proc(result, &proc) if proc result end # Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_ def recurse_proc(result, &proc) case result when Array result.each { |x| recurse_proc x, &proc } proc.call result when Hash result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc } proc.call result else proc.call result end end alias restore load module_function :restore class << self # The global default options for the JSON.dump method: # :max_nesting: false # :allow_nan: true # :allow_blank: true attr_accessor :dump_default_options end self.dump_default_options = { :max_nesting => false, :allow_nan => true, } # Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns # the result. # # If anIO (an IO-like object or an object that responds to the write method) # was given, the resulting JSON is written to it. # # If the number of nested arrays or objects exceeds _limit_, an ArgumentError # exception is raised. This argument is similar (but not exactly the # same!) to the _limit_ argument in Marshal.dump. # # The default options for the generator can be changed via the # dump_default_options method. # # This method is part of the implementation of the load/dump interface of # Marshal and YAML. def dump(obj, anIO = nil, limit = nil) if anIO and limit.nil? anIO = anIO.to_io if anIO.respond_to?(:to_io) unless anIO.respond_to?(:write) limit = anIO anIO = nil end end opts = JSON.dump_default_options opts = opts.merge(:max_nesting => limit) if limit result = generate(obj, opts) if anIO anIO.write result anIO else result end rescue JSON::NestingError raise ArgumentError, "exceed depth limit" end # Encodes string using Ruby's _String.encode_ def self.iconv(to, from, string) string.encode(to, from) end end module ::Kernel private # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in # one line. def j(*objs) objs.each do |obj| puts JSON::generate(obj, :allow_nan => true, :max_nesting => false) end nil end # Outputs _objs_ to STDOUT as JSON strings in a pretty format, with # indentation and over many lines. def jj(*objs) objs.each do |obj| puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false) end nil end # If _object_ is string-like, parse the string and return the parsed result as # a Ruby data structure. Otherwise, generate a JSON text from the Ruby data # structure object and return it. # # The _opts_ argument is passed through to generate/parse respectively. See # generate and parse for their documentation. def JSON(object, *args) if object.respond_to? :to_str JSON.parse(object.to_str, args.first) else JSON.generate(object, args.first) end end end # Extends any Class to include _json_creatable?_ method. class ::Class # Returns true if this class can be used to create an instance # from a serialised JSON string. The class has to implement a class # method _json_create_ that expects a hash as first parameter. The hash # should include the required data. def json_creatable? respond_to?(:json_create) end end PKu]1zjson-2.3.0/lib/json/ext.rbnu[require 'json/common' module JSON # This module holds all the modules/classes that implement JSON's # functionality as C extensions. module Ext require 'json/ext/parser' require 'json/ext/generator' $DEBUG and warn "Using Ext extension for JSON." JSON.parser = Parser JSON.generator = Generator end JSON_LOADED = true unless defined?(::JSON::JSON_LOADED) end PKu]E”%json-2.3.0/lib/json/generic_object.rbnu[#frozen_string_literal: false require 'ostruct' module JSON class GenericObject < OpenStruct class << self alias [] new def json_creatable? @json_creatable end attr_writer :json_creatable def json_create(data) data = data.dup data.delete JSON.create_id self[data] end def from_hash(object) case when object.respond_to?(:to_hash) result = new object.to_hash.each do |key, value| result[key] = from_hash(value) end result when object.respond_to?(:to_ary) object.to_ary.map { |a| from_hash(a) } else object end end def load(source, proc = nil, opts = {}) result = ::JSON.load(source, proc, opts.merge(:object_class => self)) result.nil? ? new : result end def dump(obj, *args) ::JSON.dump(obj, *args) end end self.json_creatable = false def to_hash table end def [](name) __send__(name) end unless method_defined?(:[]) def []=(name, value) __send__("#{name}=", value) end unless method_defined?(:[]=) def |(other) self.class[other.to_hash.merge(to_hash)] end def as_json(*) { JSON.create_id => self.class.name }.merge to_hash end def to_json(*a) as_json.to_json(*a) end end end PKu]%Bqqpower_assert-1.1.7/LEGALnu[LEGAL NOTICE INFORMATION ------------------------ All the files in this distribution are written by the author. PKu]Vpower_assert-1.1.7/Gemfilenu[source "http://rubygems.org" gemspec # https://github.com/redmine/redmine/blob/3.0.4/Gemfile#L101 local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local") if File.exist?(local_gemfile) eval_gemfile local_gemfile end PKu]Xpower_assert-1.1.7/Rakefilenu[require "bundler/gem_tasks" require "rake/testtask" task :default => :test Rake::TestTask.new(:test) do |t| # helper(simplecov) must be required before loading power_assert helper_path = File.realpath("test/test_helper.rb") t.ruby_opts = ["-w", "-r#{helper_path}"] t.test_files = FileList["test/**/*_test.rb"].exclude do |i| begin next false unless defined?(RubyVM) RubyVM::InstructionSequence.compile(File.read(i)) false rescue SyntaxError true end end end # ruby/ruby:test/pathname/test_pathname.rb def has_symlink? begin File.symlink("", "") rescue NotImplementedError, Errno::EACCES return false rescue Errno::ENOENT end return true end SYMLINK_DIRS = ["lib", "test"] task :before_script do if ENV["TEST_SYMLINK"] == "yes" and has_symlink? SYMLINK_DIRS.each do |d| File.rename(d, ".#{d}") File.symlink(".#{d}", d) end end end task :after_script do SYMLINK_DIRS.each do |d| if File.symlink?(d) and File.directory?(".#{d}") File.unlink(d) File.rename(".#{d}", d) end unless File.directory?(d) raise "#{d} should be directory" end end end desc "Run the benchmark suite" task :benchmark do Dir.glob("benchmark/bm_*.rb").each do |f| load(f) end end PKu]*Dpower_assert-1.1.7/BSDLnu[Copyright (C) 2014 Kazuki Tsujimoto Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PKu]|m# # power_assert-1.1.7/README.rdocnu[= power_assert == About Power Assert for Ruby. Power Assert shows each value of variables and method calls in the expression. It is useful for testing, providing which value wasn't correct when the condition is not satisfied. Failure: assert { 3.times.to_a.include?(3) } | | | | | false | [0, 1, 2] # == Related Projects In general, you don't need to use this library directly. Use following test frameworks or extensions instead. * {test-unit}[https://github.com/test-unit/test-unit](>= 3.0.0) * {Document}[http://test-unit.github.io/test-unit/en/Test/Unit/Assertions.html#assert-instance_method] * {minitest-power_assert}[https://github.com/hsbt/minitest-power_assert] * {rspec-power_assert}[https://github.com/joker1007/rspec-power_assert] * {pry-power_assert}[https://github.com/yui-knk/pry-power_assert] * {pry-byebug-power_assert}[https://github.com/k-tsj/pry-byebug-power_assert] * {power_p}[https://github.com/k-tsj/power_p] == Requirement * CRuby 2.0.0 or later == Reference * {Power Assert in Ruby (at RubyKaigi 2014) // Speaker Deck}[https://speakerdeck.com/k_tsj/power-assert-in-ruby] == Known Limitations * Expressions must be put in one line. Expressions with folded long lines produce nothing report, e.g.: assert do # reported func(foo: 0123456789, bar: "abcdefg") end assert do # won't be reported func(foo: 0123456789, bar: "abcdefg") end * Expressions must have one or more method call. Expressions with no method call produce nothing report, e.g.: val = false assert do # reported val == true end assert do # won't be reported val end * Returned values from accessor methods, method missing, or "super" produce nothing report, e.g: class Foo attr_accessor :val end foo = Foo.new foo.val = false assert do # reported (only the value of "foo" and the literal "true") foo.val == true end assert do # won't be reported foo.val end * Expressions should not have conditional branches. Expressions with such conditional codes may produce nothing report, e.g.: condition = true expected = false actual = true assert do # this will fail but nothing reported condition ? expected == actual : expected == actual end == Travis Build Status {}[http://travis-ci.org/k-tsj/power_assert] PKu] b power_assert-1.1.7/COPYINGnu[Copyright (C) 2014 Kazuki Tsujimoto You can redistribute it and/or modify it under either the terms of the 2-clause BSDL (see the file BSDL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. PKu]mޮ 'power_assert-1.1.7/power_assert.gemspecnu[# -*- encoding: utf-8 -*- # stub: power_assert 1.1.7 ruby lib Gem::Specification.new do |s| s.name = "power_assert".freeze s.version = "1.1.7" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kazuki Tsujimoto".freeze] s.bindir = "exe".freeze s.date = "2020-03-22" s.description = "Power Assert for Ruby. Power Assert shows each value of variables and method calls in the expression. It is useful for testing, providing which value wasn't correct when the condition is not satisfied.".freeze s.email = ["kazuki@callcc.net".freeze] s.extra_rdoc_files = ["README.rdoc".freeze] s.files = [".gitignore".freeze, ".travis.yml".freeze, "BSDL".freeze, "COPYING".freeze, "Gemfile".freeze, "LEGAL".freeze, "README.rdoc".freeze, "Rakefile".freeze, "bin/console".freeze, "bin/setup".freeze, "lib/power_assert.rb".freeze, "lib/power_assert/colorize.rb".freeze, "lib/power_assert/configuration.rb".freeze, "lib/power_assert/context.rb".freeze, "lib/power_assert/enable_tracepoint_events.rb".freeze, "lib/power_assert/inspector.rb".freeze, "lib/power_assert/parser.rb".freeze, "lib/power_assert/version.rb".freeze, "power_assert.gemspec".freeze] s.homepage = "https://github.com/k-tsj/power_assert".freeze s.licenses = ["2-clause BSDL".freeze, "Ruby's".freeze] s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] s.rubygems_version = "3.3.5".freeze s.summary = "Power Assert for Ruby".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PKu]t/;JJpower_assert-1.1.7/bin/setupnu[#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install PKu]9\power_assert-1.1.7/bin/consolenu[#!/usr/bin/env ruby require 'bundler/setup' require 'power_assert' begin require 'pry' Pry rescue LoadError require 'irb' IRB end.start PKu]»1.power_assert-1.1.7/lib/power_assert/context.rbnu[require 'power_assert/configuration' require 'power_assert/enable_tracepoint_events' require 'power_assert/inspector' require 'power_assert/parser' module PowerAssert class Context Value = Struct.new(:name, :value, :lineno, :column, :display_offset) def initialize(base_caller_length) @fired = false @target_thread = Thread.current method_id_set = nil @return_values = [] trace_alias_method = PowerAssert.configuration._trace_alias_method @trace_return = TracePoint.new(:return, :c_return) do |tp| begin unless method_id_set next unless Thread.current == @target_thread method_id_set = @parser.method_id_set end method_id = SUPPORT_ALIAS_METHOD ? tp.callee_id : trace_alias_method && tp.event == :return ? tp.binding.eval('::Kernel.__callee__') : tp.method_id next if ! method_id_set[method_id] next if tp.event == :c_return and not (@parser.lineno == tp.lineno and @parser.path == tp.path) locs = PowerAssert.app_caller_locations diff = locs.length - base_caller_length if (tp.event == :c_return && diff == 1 || tp.event == :return && diff <= 2) and Thread.current == @target_thread idx = -(base_caller_length + 1) if @parser.path == locs[idx].path and @parser.lineno == locs[idx].lineno val = PowerAssert.configuration.lazy_inspection ? tp.return_value : InspectedValue.new(SafeInspectable.new(tp.return_value).inspect) @return_values << Value[method_id.to_s, val, locs[idx].lineno, nil] end end rescue Exception => e warn "power_assert: [BUG] Failed to trace: #{e.class}: #{e.message}" if e.respond_to?(:full_message) warn e.full_message.gsub(/^/, 'power_assert: ') end end end end def message raise 'call #yield or #enable at first' unless fired? @message ||= build_assertion_message(@parser, @return_values).freeze end def message_proc -> { message } end private def fired? @fired end def build_assertion_message(parser, return_values) if PowerAssert.configuration._colorize_message line = Pry::Code.new(parser.line).highlighted else line = parser.line end path = detect_path(parser, return_values) return line unless path c2d = column2display_offset(parser.line) return_values, methods_in_path = find_all_identified_calls(return_values, path) return_values.zip(methods_in_path) do |i, j| unless i.name == j.name warn "power_assert: [BUG] Failed to get column: #{i.name}" return line end i.display_offset = c2d[j.column] end refs_in_path = path.find_all {|i| i.type == :ref } ref_values = refs_in_path.map {|i| Value[i.name, parser.binding.eval(i.name), parser.lineno, i.column, c2d[i.column]] } vals = (return_values + ref_values).find_all(&:display_offset).sort_by(&:display_offset).reverse return line if vals.empty? fmt = (0..vals[0].display_offset).map do |i| if vals.find {|v| v.display_offset == i } "%<#{i}>s" else line[i] == "\t" ? "\t" : ' ' end end.join lines = [] lines << line.chomp lines << sprintf(fmt, vals.each_with_object({}) {|v, h| h[v.display_offset.to_s.to_sym] = '|' }).chomp vals.each do |i| inspected_val = SafeInspectable.new(Formatter.new(i.value, i.display_offset)).inspect inspected_val.each_line do |l| map_to = vals.each_with_object({}) do |j, h| h[j.display_offset.to_s.to_sym] = [l, '|', ' '][i.display_offset <=> j.display_offset] end lines << encoding_safe_rstrip(sprintf(fmt, map_to)) end end lines.join("\n") end def detect_path(parser, return_values) return parser.call_paths.flatten.uniq if parser.method_id_set.empty? all_paths = parser.call_paths return_value_names = return_values.map(&:name) uniq_calls = uniq_calls(all_paths) uniq_call = return_value_names.find {|i| uniq_calls.include?(i) } detected_paths = all_paths.find_all do |path| method_names = path.find_all {|ident| ident.type == :method }.map(&:name) break [path] if uniq_call and method_names.include?(uniq_call) return_value_names == method_names end return nil unless detected_paths.length == 1 detected_paths[0] end def uniq_calls(paths) all_calls = enum_count_by(paths.map {|path| path.find_all {|ident| ident.type == :method }.map(&:name).uniq }.flatten) {|i| i } all_calls.find_all {|_, call_count| call_count == 1 }.map {|name, _| name } end def find_all_identified_calls(return_values, path) return_value_num_of_calls = enum_count_by(return_values, &:name) path_num_of_calls = enum_count_by(path.find_all {|ident| ident.type == :method }, &:name) identified_calls = return_value_num_of_calls.find_all {|name, num| path_num_of_calls[name] == num }.map(&:first) [ return_values.find_all {|val| identified_calls.include?(val.name) }, path.find_all {|ident| ident.type == :method and identified_calls.include?(ident.name) } ] end def enum_count_by(enum, &blk) Hash[enum.group_by(&blk).map{|k, v| [k, v.length] }] end def encoding_safe_rstrip(str) str.rstrip rescue ArgumentError, Encoding::CompatibilityError enc = str.encoding if enc.ascii_compatible? str.b.rstrip.force_encoding(enc) else str end end def column2display_offset(str) display_offset = 0 str.each_char.with_object([]) do |c, r| c.bytesize.times do r << display_offset end display_offset += c.ascii_only? ? 1 : 2 # FIXME end end end private_constant :Context class BlockContext < Context def initialize(assertion_proc_or_source, assertion_method, source_binding) super(0) if assertion_proc_or_source.respond_to?(:to_proc) @assertion_proc = assertion_proc_or_source.to_proc line = nil else @assertion_proc = source_binding.eval "Proc.new {#{assertion_proc_or_source}}" line = assertion_proc_or_source end @parser = Parser::DUMMY @trace_call = TracePoint.new(:call, :c_call) do if PowerAssert.app_context? and Thread.current == @target_thread @trace_call.disable locs = PowerAssert.app_caller_locations path = locs.last.path lineno = locs.last.lineno if File.exist?(path) line ||= File.open(path) {|fp| fp.each_line.drop(lineno - 1).first } end if line @parser = Parser.new(line, path, lineno, @assertion_proc.binding, assertion_method.to_s, @assertion_proc) end end end end def yield @fired = true invoke_yield(&@assertion_proc) end private def invoke_yield @trace_return.enable do @trace_call.enable do yield end end end end private_constant :BlockContext class TraceContext < Context def initialize(binding) target_frame, *base = PowerAssert.app_caller_locations super(base.length) path = target_frame.path lineno = target_frame.lineno if File.exist?(path) line = File.open(path) {|fp| fp.each_line.drop(lineno - 1).first } @parser = Parser.new(line, path, lineno, binding) else @parser = Parser::DUMMY end end def enable @fired = true @trace_return.enable end def disable @trace_return.disable end def enabled? @trace_return.enabled? end end private_constant :TraceContext end PKu]g^-power_assert-1.1.7/lib/power_assert/parser.rbnu[require 'ripper' module PowerAssert class Parser Ident = Struct.new(:type, :name, :column) attr_reader :line, :path, :lineno, :binding def initialize(line, path, lineno, binding, assertion_method_name = nil, assertion_proc = nil) @line = line @line_for_parsing = (valid_syntax?(line) ? line : slice_expression(line)).b @path = path @lineno = lineno @binding = binding @proc_local_variables = binding.eval('local_variables').map(&:to_s) @assertion_method_name = assertion_method_name @assertion_proc = assertion_proc end def idents @idents ||= extract_idents(Ripper.sexp(@line_for_parsing)) end def call_paths collect_paths(idents).uniq end def method_id_set methods = idents.flatten.find_all {|i| i.type == :method } @method_id_set ||= methods.map(&:name).map(&:to_sym).each_with_object({}) {|i, h| h[i] = true } end private def valid_syntax?(str) return true unless defined?(RubyVM) begin verbose, $VERBOSE = $VERBOSE, nil RubyVM::InstructionSequence.compile(str) true rescue SyntaxError false ensure $VERBOSE = verbose end end def slice_expression(str) str = str.chomp str.sub!(/\A\s*(?:if|unless|elsif|case|while|until) /) {|i| ' ' * i.length } str.sub!(/\A\s*(?:\}|\]|end)?\./) {|i| ' ' * i.length } str.sub!(/[\{\.\\]\z/, '') str.sub!(/(?:&&|\|\|)\z/, '') str.sub!(/ (?:do|and|or)\z/, '') str end class Branch < Array end AND_OR_OPS = %i(and or && ||) # # Returns idents as graph structure. # # +--c--b--+ # extract_idents(Ripper.sexp('a&.b(c).d')) #=> a--+ +--d # +--------+ # def extract_idents(sexp) tag, * = sexp case tag when :arg_paren, :assoc_splat, :fcall, :hash, :method_add_block, :string_literal, :return extract_idents(sexp[1]) when :assign, :massign extract_idents(sexp[2]) when :opassign _, _, (_, op_name, (_, op_column)), s0 = sexp extract_idents(s0) + [Ident[:method, op_name.sub(/=\z/, ''), op_column]] when :dyna_symbol if sexp[1][0].kind_of?(Symbol) # sexp[1] can be [:string_content, [..]] while parsing { "a": 1 } extract_idents(sexp[1]) else sexp[1].flat_map {|s| extract_idents(s) } end when :assoclist_from_args, :bare_assoc_hash, :paren, :string_embexpr, :regexp_literal, :xstring_literal sexp[1].flat_map {|s| extract_idents(s) } when :command [sexp[2], sexp[1]].flat_map {|s| extract_idents(s) } when :assoc_new, :dot2, :dot3, :string_content sexp[1..-1].flat_map {|s| extract_idents(s) } when :unary handle_columnless_ident([], sexp[1], extract_idents(sexp[2])) when :binary op = sexp[2] if AND_OR_OPS.include?(op) extract_idents(sexp[1]) + [Branch[extract_idents(sexp[3]), []]] else handle_columnless_ident(extract_idents(sexp[1]), op, extract_idents(sexp[3])) end when :call _, recv, (op_sym, op_name, _), method = sexp with_safe_op = ((op_sym == :@op and op_name == '&.') or op_sym == :"&.") if method == :call handle_columnless_ident(extract_idents(recv), :call, [], with_safe_op) else extract_idents(recv) + (with_safe_op ? [Branch[extract_idents(method), []]] : extract_idents(method)) end when :array sexp[1] ? sexp[1].flat_map {|s| extract_idents(s) } : [] when :command_call [sexp[1], sexp[4], sexp[3]].flat_map {|s| extract_idents(s) } when :aref handle_columnless_ident(extract_idents(sexp[1]), :[], extract_idents(sexp[2])) when :method_add_arg idents = extract_idents(sexp[1]) if idents.empty? # idents may be empty(e.g. ->{}.()) extract_idents(sexp[2]) else if idents[-1].kind_of?(Branch) and idents[-1][1].empty? # Safe navigation operator is used. See :call clause also. idents[0..-2] + [Branch[extract_idents(sexp[2]) + idents[-1][0], []]] else idents[0..-2] + extract_idents(sexp[2]) + [idents[-1]] end end when :args_add_block _, (tag, ss0, *ss1), _ = sexp if tag == :args_add_star (ss0 + ss1).flat_map {|s| extract_idents(s) } else sexp[1].flat_map {|s| extract_idents(s) } end when :vcall _, (tag, name, (_, column)) = sexp if tag == :@ident [Ident[@proc_local_variables.include?(name) ? :ref : :method, name, column]] else [] end when :program _, ((tag0, (tag1, (tag2, (tag3, mname, _)), _), (tag4, _, ss))) = sexp if tag0 == :method_add_block and tag1 == :method_add_arg and tag2 == :fcall and (tag3 == :@ident or tag3 == :@const) and mname == @assertion_method_name and (tag4 == :brace_block or tag4 == :do_block) ss.flat_map {|s| extract_idents(s) } else _, (s0, *) = sexp extract_idents(s0) end when :ifop _, s0, s1, s2 = sexp [*extract_idents(s0), Branch[extract_idents(s1), extract_idents(s2)]] when :if, :unless _, s0, ss0, (_, ss1) = sexp [*extract_idents(s0), Branch[ss0.flat_map {|s| extract_idents(s) }, ss1 ? ss1.flat_map {|s| extract_idents(s) } : []]] when :if_mod, :unless_mod _, s0, s1 = sexp [*extract_idents(s0), Branch[extract_idents(s1), []]] when :var_ref, :var_field _, (tag, ref_name, (_, column)) = sexp case tag when :@kw if ref_name == 'self' [Ident[:ref, 'self', column]] else [] end when :@ident, :@const, :@cvar, :@ivar, :@gvar [Ident[:ref, ref_name, column]] else [] end when :@ident, :@const, :@op _, method_name, (_, column) = sexp [Ident[:method, method_name, column]] else [] end end def str_indices(str, re, offset, limit) idx = str.index(re, offset) if idx and idx <= limit [idx, *str_indices(str, re, idx + 1, limit)] else [] end end MID2SRCTXT = { :[] => '[', :+@ => '+', :-@ => '-', :call => '(' } def handle_columnless_ident(left_idents, mid, right_idents, with_safe_op = false) left_max = left_idents.flatten.max_by(&:column) right_min = right_idents.flatten.min_by(&:column) bg = left_max ? left_max.column + left_max.name.length : 0 ed = right_min ? right_min.column - 1 : @line_for_parsing.length - 1 mname = mid.to_s srctxt = MID2SRCTXT[mid] || mname re = / #{'\b' if /\A\w/ =~ srctxt} #{Regexp.escape(srctxt)} #{'\b' if /\w\z/ =~ srctxt} /x indices = str_indices(@line_for_parsing, re, bg, ed) if indices.length == 1 or !(right_idents.empty? and left_idents.empty?) ident = Ident[:method, mname, right_idents.empty? ? indices.first : indices.last] left_idents + right_idents + (with_safe_op ? [Branch[[ident], []]] : [ident]) else left_idents + right_idents end end def collect_paths(idents, prefixes = [[]], index = 0) if index < idents.length node = idents[index] if node.kind_of?(Branch) prefixes = node.flat_map {|n| collect_paths(n, prefixes, 0) } else prefixes = prefixes.map {|prefix| prefix + [node] } end collect_paths(idents, prefixes, index + 1) else prefixes end end class DummyParser < Parser def initialize super('', nil, nil, TOPLEVEL_BINDING) end def idents [] end def call_paths [] end end DUMMY = DummyParser.new end private_constant :Parser end PKu]S/++.power_assert-1.1.7/lib/power_assert/version.rbnu[module PowerAssert VERSION = "1.1.7" end PKu]!/power_assert-1.1.7/lib/power_assert/colorize.rbnu[warn 'power_assert/colorize is experimental' require 'power_assert/configuration' PowerAssert.configure do |c| c.lazy_inspection = true c._colorize_message = true c._use_pp = true end PKu]{%}}WW4power_assert-1.1.7/lib/power_assert/configuration.rbnu[module PowerAssert class << self def configuration @configuration ||= Configuration[false, false, true, false, false] end def configure yield configuration end end SUPPORT_ALIAS_METHOD = TracePoint.public_method_defined?(:callee_id) private_constant :SUPPORT_ALIAS_METHOD class Configuration < Struct.new(:lazy_inspection, :_trace_alias_method, :_redefinition, :_colorize_message, :_use_pp) def _trace_alias_method=(bool) super if SUPPORT_ALIAS_METHOD warn 'power_assert: _trace_alias_method option is obsolete. You no longer have to set it.' end end def _colorize_message=(bool) if bool require 'pry' end super end def lazy_inspection=(bool) unless bool raise 'lazy_inspection option must be enabled when using pp' if _use_pp end super end def _use_pp=(bool) if bool raise 'lazy_inspection option must be enabled when using pp' unless lazy_inspection require 'pp' end super end end private_constant :Configuration end PKu]^-  ?power_assert-1.1.7/lib/power_assert/enable_tracepoint_events.rbnu[require 'power_assert/configuration' if defined?(RubyVM) if PowerAssert.configuration._redefinition if RUBY_VERSION == '2.3.2' warn 'power_assert: It is strongly recommended that you use Ruby 2.3.3 or later which fixes regression on 2.3.2.' warn 'power_assert: See https://www.ruby-lang.org/en/news/2016/11/21/ruby-2-3-3-released/ for more details.' end verbose = $VERBOSE begin $VERBOSE = nil module PowerAssert # set redefined flag basic_classes = [ Fixnum, Float, String, Array, Hash, Bignum, Symbol, Time, Regexp, NilClass, TrueClass, FalseClass ] basic_operators = [ :+, :-, :*, :/, :%, :==, :===, :<, :<=, :<<, :[], :[]=, :length, :size, :empty?, :succ, :>, :>=, :!, :!=, :=~, :freeze, :-@, :max, :min, :nil? ] bug11182 = Class.new do def fixed? true end end refine bug11182 do def fixed? end end _ = Class.new(bug11182) do alias _fixed? fixed? protected :_fixed? end if (bug11182.new.fixed? rescue false) basic_classes.each do |klass| basic_operators.each do |bop| if klass.public_method_defined?(bop) refine(klass) do define_method(bop) {} end end end end else # workaround for https://bugs.ruby-lang.org/issues/11182 basic_classes.each do |klass| basic_operators.each do |bop| if klass.public_method_defined?(bop) klass.ancestors.find {|i| i.instance_methods(false).index(bop) }.module_eval do public bop end end end end refine Symbol do def == end end end # bypass check_cfunc refine BasicObject do def ! end def == end end refine Module do def == end end end ensure $VERBOSE = verbose end end # disable optimization RubyVM::InstructionSequence.compile_option = { specialized_instruction: false } end PKu]G0power_assert-1.1.7/lib/power_assert/inspector.rbnu[require 'power_assert/configuration' module PowerAssert class InspectedValue def initialize(value) @value = value end def inspect @value end end private_constant :InspectedValue class SafeInspectable def initialize(value) @value = value end def inspect inspected = @value.inspect if Encoding.compatible?(Encoding.default_external, inspected) inspected else begin "#{inspected.encode(Encoding.default_external)}(#{inspected.encoding})" rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError inspected.force_encoding(Encoding.default_external) end end rescue => e "InspectionFailure: #{e.class}: #{e.message.each_line.first}" end end private_constant :SafeInspectable class Formatter def initialize(value, indent) @value = value @indent = indent end def inspect if PowerAssert.configuration._colorize_message if PowerAssert.configuration._use_pp width = [(defined?(Pry::Terminal) ? Pry::Terminal.width! : Pry.new(output: StringIO.new).output.width) - 1 - @indent, 10].max Pry::ColorPrinter.pp(@value, '', width) else Pry::Code.new(@value.inspect).highlighted end else if PowerAssert.configuration._use_pp PP.pp(@value, '') else @value.inspect end end end end private_constant :Formatter end PKu]O3e: &power_assert-1.1.7/lib/power_assert.rbnu[# power_assert.rb # # Copyright (C) 2014 Kazuki Tsujimoto begin unless defined?(Byebug) captured = false TracePoint.new(:return, :c_return) do |tp| captured = true unless tp.binding and tp.return_value raise '' end end.enable { __id__ } raise '' unless captured end rescue raise LoadError, 'Fully compatible TracePoint API required' end require 'power_assert/version' require 'power_assert/configuration' require 'power_assert/context' module PowerAssert POWER_ASSERT_LIB_DIR = File.dirname(caller_locations(1, 1).first.path) INTERNAL_LIB_DIRS = {PowerAssert => POWER_ASSERT_LIB_DIR} private_constant :POWER_ASSERT_LIB_DIR, :INTERNAL_LIB_DIRS # For backward compatibility IGNORED_LIB_DIRS = INTERNAL_LIB_DIRS private_constant :IGNORED_LIB_DIRS if respond_to?(:deprecate_constant) deprecate_constant :IGNORED_LIB_DIRS end class << self def start(assertion_proc_or_source, assertion_method: nil, source_binding: TOPLEVEL_BINDING) if respond_to?(:clear_global_method_cache, true) clear_global_method_cache end yield BlockContext.new(assertion_proc_or_source, assertion_method, source_binding) end def trace(frame) begin raise 'Byebug is not started yet' unless Byebug.started? rescue NameError raise "PowerAssert.#{__method__} requires Byebug" end ctx = TraceContext.new(frame._binding) ctx.enable ctx end def app_caller_locations caller_locations.drop_while {|i| internal_file?(i.path) }.take_while {|i| ! internal_file?(i.path) } end def app_context? top_frame = caller_locations.drop_while {|i| i.path.start_with?(POWER_ASSERT_LIB_DIR) }.first top_frame and ! internal_file?(top_frame.path) end private def internal_file?(file) setup_internal_lib_dir(Byebug, :attach, 2) if defined?(Byebug) setup_internal_lib_dir(PryByebug, :start_with_pry_byebug, 2, Pry) if defined?(PryByebug) INTERNAL_LIB_DIRS.find do |_, dir| file.start_with?(dir) end end def setup_internal_lib_dir(lib, mid, depth, lib_obj = lib) unless INTERNAL_LIB_DIRS.key?(lib) INTERNAL_LIB_DIRS[lib] = lib_dir(lib_obj, mid, depth) end rescue NameError end def lib_dir(obj, mid, depth) File.expand_path('../' * depth, obj.method(mid).source_location[0]) end if defined?(RubyVM) CLEAR_CACHE_ISEQ = RubyVM::InstructionSequence.compile('using PowerAssert.const_get(:Empty)') private_constant :CLEAR_CACHE_ISEQ def clear_global_method_cache CLEAR_CACHE_ISEQ.eval end end end module Empty end private_constant :Empty end PKu] xmlrpc-0.3.0/LICENSE.txtnu[Ruby is copyrighted free software by Yukihiro Matsumoto . You can redistribute it and/or modify it under either the terms of the 2-clause BSDL (see the file BSDL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. PKu]K''xmlrpc-0.3.0/Gemfilenu[source 'https://rubygems.org' gemspec PKu]Yxmlrpc-0.3.0/xmlrpc.gemspecnu[# -*- encoding: utf-8 -*- # stub: xmlrpc 0.3.0 ruby lib Gem::Specification.new do |s| s.name = "xmlrpc".freeze s.version = "0.3.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["SHIBATA Hiroshi".freeze] s.bindir = "exe".freeze s.date = "2017-02-16" s.description = "XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP.".freeze s.email = ["hsbt@ruby-lang.org".freeze] s.files = [".gitignore".freeze, ".travis.yml".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "bin/console".freeze, "bin/setup".freeze, "lib/xmlrpc.rb".freeze, "lib/xmlrpc/base64.rb".freeze, "lib/xmlrpc/client.rb".freeze, "lib/xmlrpc/config.rb".freeze, "lib/xmlrpc/create.rb".freeze, "lib/xmlrpc/datetime.rb".freeze, "lib/xmlrpc/marshal.rb".freeze, "lib/xmlrpc/parser.rb".freeze, "lib/xmlrpc/server.rb".freeze, "lib/xmlrpc/utils.rb".freeze, "xmlrpc.gemspec".freeze] s.homepage = "https://github.com/ruby/xmlrpc".freeze s.licenses = ["Ruby".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3".freeze) s.rubygems_version = "3.3.5".freeze s.summary = "XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PKu]\Wxmlrpc-0.3.0/Rakefilenu[require "bundler/gem_tasks" require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList['test/**/test_*.rb'] end task :default => :test PKu]ixmlrpc-0.3.0/README.mdnu[# XMLRPC [![Build Status](https://travis-ci.org/ruby/xmlrpc.svg?branch=master)](https://travis-ci.org/ruby/xmlrpc) ## Overview XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP. It is defined at http://www.xmlrpc.com. XMLRPC allows you to create simple distributed computing solutions that span computer languages. Its distinctive feature is its simplicity compared to other approaches like SOAP and CORBA. The Ruby standard library package 'xmlrpc' enables you to create a server that implements remote procedures and a client that calls them. Very little code is required to achieve either of these. ## Installation Add this line to your application's Gemfile: ```ruby gem 'xmlrpc' ``` And then execute: $ bundle Or install it yourself as: $ gem install xmlrpc ## Example Try the following code. It calls a standard demonstration remote procedure. ```ruby require 'xmlrpc/client' require 'pp' server = XMLRPC::Client.new2("http://xmlrpc-c.sourceforge.net/api/sample.php") result = server.call("sample.sumAndDifference", 5, 3) pp result ``` ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/xmlrpc. ## License Released under the same term of license as Ruby. PKu]xmlrpc-0.3.0/bin/setupnu[#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install # Do any other automated setup that you need to do here PKu]N=KKxmlrpc-0.3.0/bin/consolenu[#!/usr/bin/env ruby require "bundler/setup" require "xmlrpc" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start PKu]Xxmlrpc-0.3.0/lib/xmlrpc.rbnu[# frozen_string_literal: false # == Author and Copyright # # Copyright (C) 2001-2004 by Michael Neumann (mailto:mneumann@ntecs.de) # # Released under the same term of license as Ruby. # # == Overview # # XMLRPC is a lightweight protocol that enables remote procedure calls over # HTTP. It is defined at http://www.xmlrpc.com. # # XMLRPC allows you to create simple distributed computing solutions that span # computer languages. Its distinctive feature is its simplicity compared to # other approaches like SOAP and CORBA. # # The Ruby standard library package 'xmlrpc' enables you to create a server that # implements remote procedures and a client that calls them. Very little code # is required to achieve either of these. # # == Example # # Try the following code. It calls a standard demonstration remote procedure. # # require 'xmlrpc/client' # require 'pp' # # server = XMLRPC::Client.new2("http://xmlrpc-c.sourceforge.net/api/sample.php") # result = server.call("sample.sumAndDifference", 5, 3) # pp result # # == Documentation # # See http://www.ntecs.de/ruby/xmlrpc4r/. There is plenty of detail there to # use the client and implement a server. # # == Features of XMLRPC for Ruby # # * Extensions # * Introspection # * multiCall # * optionally nil values and integers larger than 32 Bit # # * Server # * Standalone XML-RPC server # * CGI-based (works with FastCGI) # * Apache mod_ruby server # * WEBrick servlet # # * Client # * synchronous/asynchronous calls # * Basic HTTP-401 Authentication # * HTTPS protocol (SSL) # # * Parsers # * REXML (XMLParser::REXMLStreamParser) # * Not compiled (pure ruby) # * See ruby standard library # * libxml (LibXMLStreamParser) # * Compiled # * See https://rubygems.org/gems/libxml-ruby/ # # * General # * possible to choose between XMLParser module (Expat wrapper) and REXML (pure Ruby) parsers # * Marshalling Ruby objects to Hashes and reconstruct them later from a Hash # * SandStorm component architecture XMLRPC::Client interface # # == Howto # # === Client # # require "xmlrpc/client" # # # Make an object to represent the XML-RPC server. # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # # # Call the remote server and get our result # result = server.call("sample.sumAndDifference", 5, 3) # # sum = result["sum"] # difference = result["difference"] # # puts "Sum: #{sum}, Difference: #{difference}" # # === XMLRPC::Client with XML-RPC fault-structure handling # # There are two possible ways, of handling a fault-structure: # # ==== by catching a XMLRPC::FaultException exception # # require "xmlrpc/client" # # # Make an object to represent the XML-RPC server. # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # # begin # # Call the remote server and get our result # result = server.call("sample.sumAndDifference", 5, 3) # # sum = result["sum"] # difference = result["difference"] # # puts "Sum: #{sum}, Difference: #{difference}" # # rescue XMLRPC::FaultException => e # puts "Error: " # puts e.faultCode # puts e.faultString # end # # ==== by calling "call2" which returns a boolean # # require "xmlrpc/client" # # # Make an object to represent the XML-RPC server. # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # # # Call the remote server and get our result # ok, result = server.call2("sample.sumAndDifference", 5, 3) # # if ok # sum = result["sum"] # difference = result["difference"] # # puts "Sum: #{sum}, Difference: #{difference}" # else # puts "Error: " # puts result.faultCode # puts result.faultString # end # # === Using XMLRPC::Client::Proxy # # You can create a Proxy object onto which you can call methods. This way it # looks nicer. Both forms, _call_ and _call2_ are supported through _proxy_ and # _proxy2_. You can additionally give arguments to the Proxy, which will be # given to each XML-RPC call using that Proxy. # # require "xmlrpc/client" # # # Make an object to represent the XML-RPC server. # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # # # Create a Proxy object # sample = server.proxy("sample") # # # Call the remote server and get our result # result = sample.sumAndDifference(5,3) # # sum = result["sum"] # difference = result["difference"] # # puts "Sum: #{sum}, Difference: #{difference}" # # === CGI-based server using XMLRPC::CGIServer # # There are also two ways to define handler, the first is # like C/PHP, the second like Java, of course both ways # can be mixed: # # ==== C/PHP-like (handler functions) # # require "xmlrpc/server" # # s = XMLRPC::CGIServer.new # # s.add_handler("sample.sumAndDifference") do |a,b| # { "sum" => a + b, "difference" => a - b } # end # # s.serve # # ==== Java-like (handler classes) # # require "xmlrpc/server" # # s = XMLRPC::CGIServer.new # # class MyHandler # def sumAndDifference(a, b) # { "sum" => a + b, "difference" => a - b } # end # end # # # NOTE: Security Hole (read below)!!! # s.add_handler("sample", MyHandler.new) # s.serve # # # To return a fault-structure you have to raise an XMLRPC::FaultException e.g.: # # raise XMLRPC::FaultException.new(3, "division by Zero") # # ===== Security Note # # From Brian Candler: # # Above code sample has an extremely nasty security hole, in that you can now call # any method of 'MyHandler' remotely, including methods inherited from Object # and Kernel! For example, in the client code, you can use # # puts server.call("sample.send","`","ls") # # (backtick being the method name for running system processes). Needless to # say, 'ls' can be replaced with something else. # # The version which binds proc objects (or the version presented below in the next section) # doesn't have this problem, but people may be tempted to use the second version because it's # so nice and 'Rubyesque'. I think it needs a big red disclaimer. # # # From Michael: # # A solution is to undef insecure methods or to use # XMLRPC::Service::PublicInstanceMethodsInterface as shown below: # # class MyHandler # def sumAndDifference(a, b) # { "sum" => a + b, "difference" => a - b } # end # end # # # ... server initialization ... # # s.add_handler(XMLRPC::iPIMethods("sample"), MyHandler.new) # # # ... # # This adds only public instance methods explicitly declared in class MyHandler # (and not those inherited from any other class). # # ==== With interface declarations # # Code sample from the book Ruby Developer's Guide: # # require "xmlrpc/server" # # class Num # INTERFACE = XMLRPC::interface("num") { # meth 'int add(int, int)', 'Add two numbers', 'add' # meth 'int div(int, int)', 'Divide two numbers' # } # # def add(a, b) a + b end # def div(a, b) a / b end # end # # # s = XMLRPC::CGIServer.new # s.add_handler(Num::INTERFACE, Num.new) # s.serve # # === Standalone XMLRPC::Server # # Same as CGI-based server, the only difference being # # server = XMLRPC::CGIServer.new # # must be changed to # # server = XMLRPC::Server.new(8080) # # if you want a server listening on port 8080. # The rest is the same. # # === Choosing a different XMLParser or XMLWriter # # The examples above all use the default parser (which is now since 1.8 # XMLParser::REXMLStreamParser) and a default XMLRPC::XMLWriter. # If you want to use a different XMLParser, then you have to call the # ParserWriterChooseMixin#set_parser method of XMLRPC::Client instances # or instances of subclasses of XMLRPC::BasicServer or by editing # xmlrpc/config.rb. # # XMLRPC::Client Example: # # # ... # server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # server.set_parser(XMLRPC::XMLParser::XMLParser.new) # # ... # # XMLRPC::Server Example: # # # ... # s = XMLRPC::CGIServer.new # s.set_parser(XMLRPC::XMLParser::XMLParser.new) # # ... # # # You can change the XML-writer by calling method ParserWriterChooseMixin#set_writer. module XMLRPC VERSION = "0.3.0" end PKu]Gea a #xmlrpc-0.3.0/lib/xmlrpc/datetime.rbnu[# frozen_string_literal: false # # xmlrpc/datetime.rb # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # Released under the same term of license as Ruby. # require "date" module XMLRPC # :nodoc: # This class is important to handle XMLRPC +dateTime.iso8601+ values, # correctly, because normal UNIX-dates, ie: Date, only handle dates # from year 1970 on, and ruby's native Time class handles dates without the # time component. # # XMLRPC::DateTime is able to store a XMLRPC +dateTime.iso8601+ value correctly. class DateTime # Return the value of the specified date/time component. attr_reader :year, :month, :day, :hour, :min, :sec # Set +value+ as the new date/time component. # # Raises ArgumentError if the given +value+ is out of range, or in the case # of XMLRPC::DateTime#year= if +value+ is not of type Integer. def year=(value) raise ArgumentError, "date/time out of range" unless value.is_a? Integer @year = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 1 and 12. def month=(value) raise ArgumentError, "date/time out of range" unless (1..12).include? value @month = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 1 and 31. def day=(value) raise ArgumentError, "date/time out of range" unless (1..31).include? value @day = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 0 and 24. def hour=(value) raise ArgumentError, "date/time out of range" unless (0..24).include? value @hour = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 0 and 59. def min=(value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @min = value end # Set +value+ as the new date/time component. # # Raises an ArgumentError if the given +value+ isn't between 0 and 59. def sec=(value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @sec = value end # Alias for XMLRPC::DateTime#month. alias mon month # Alias for XMLRPC::DateTime#month=. alias mon= month= # Creates a new XMLRPC::DateTime instance with the # parameters +year+, +month+, +day+ as date and # +hour+, +min+, +sec+ as time. # # Raises an ArgumentError if a parameter is out of range, # or if +year+ is not of the Integer type. def initialize(year, month, day, hour, min, sec) self.year, self.month, self.day = year, month, day self.hour, self.min, self.sec = hour, min, sec end # Return a Time object of the date/time which represents +self+. # # The timezone used is GMT. def to_time Time.gm(*to_a) end # Return a Date object of the date which represents +self+. # # The Date object do _not_ contain the time component (only date). def to_date Date.new(*to_a[0,3]) end # Returns all date/time components in an array. # # Returns +[year, month, day, hour, min, sec]+. def to_a [@year, @month, @day, @hour, @min, @sec] end # Returns whether or not all date/time components are an array. def ==(o) self.to_a == Array(o) rescue false end end end # module XMLRPC =begin = History $Id$ =end PKu]-KKKK!xmlrpc-0.3.0/lib/xmlrpc/client.rbnu[# frozen_string_literal: false # xmlrpc/client.rb # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # Released under the same term of license as Ruby. # # History # $Id$ # require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" # ParserWriterChooseMixin require "net/http" require "uri" module XMLRPC # :nodoc: # Provides remote procedure calls to a XML-RPC server. # # After setting the connection-parameters with XMLRPC::Client.new which # creates a new XMLRPC::Client instance, you can execute a remote procedure # by sending the XMLRPC::Client#call or XMLRPC::Client#call2 # message to this new instance. # # The given parameters indicate which method to call on the remote-side and # of course the parameters for the remote procedure. # # require "xmlrpc/client" # # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) # begin # param = server.call("michael.add", 4, 5) # puts "4 + 5 = #{param}" # rescue XMLRPC::FaultException => e # puts "Error:" # puts e.faultCode # puts e.faultString # end # # or # # require "xmlrpc/client" # # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) # ok, param = server.call2("michael.add", 4, 5) # if ok then # puts "4 + 5 = #{param}" # else # puts "Error:" # puts param.faultCode # puts param.faultString # end class Client USER_AGENT = "XMLRPC::Client (Ruby #{RUBY_VERSION})" include ParserWriterChooseMixin include ParseContentType # Creates an object which represents the remote XML-RPC server on the # given +host+. If the server is CGI-based, +path+ is the # path to the CGI-script, which will be called, otherwise (in the # case of a standalone server) +path+ should be "/RPC2". # +port+ is the port on which the XML-RPC server listens. # # If +proxy_host+ is given, then a proxy server listening at # +proxy_host+ is used. +proxy_port+ is the port of the # proxy server. # # Default values for +host+, +path+ and +port+ are 'localhost', '/RPC2' and # '80' respectively using SSL '443'. # # If +user+ and +password+ are given, each time a request is sent, # an Authorization header is sent. Currently only Basic Authentication is # implemented, no Digest. # # If +use_ssl+ is set to +true+, communication over SSL is enabled. # # Parameter +timeout+ is the time to wait for a XML-RPC response, defaults to 30. def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=nil, timeout=nil) @http_header_extra = nil @http_last_response = nil @cookie = nil @host = host || "localhost" @path = path || "/RPC2" @proxy_host = proxy_host @proxy_port = proxy_port @proxy_host ||= 'localhost' if @proxy_port != nil @proxy_port ||= 8080 if @proxy_host != nil @use_ssl = use_ssl || false @timeout = timeout || 30 if use_ssl require "net/https" @port = port || 443 else @port = port || 80 end @user, @password = user, password set_auth # convert ports to integers @port = @port.to_i if @port != nil @proxy_port = @proxy_port.to_i if @proxy_port != nil # HTTP object for synchronous calls @http = net_http(@host, @port, @proxy_host, @proxy_port) @http.use_ssl = @use_ssl if @use_ssl @http.read_timeout = @timeout @http.open_timeout = @timeout @parser = nil @create = nil end class << self # Creates an object which represents the remote XML-RPC server at the # given +uri+. The URI should have a host, port, path, user and password. # Example: https://user:password@host:port/path # # Raises an ArgumentError if the +uri+ is invalid, # or if the protocol isn't http or https. # # If a +proxy+ is given it should be in the form of "host:port". # # The optional +timeout+ defaults to 30 seconds. def new2(uri, proxy=nil, timeout=nil) begin url = URI(uri) rescue URI::InvalidURIError => e raise ArgumentError, e.message, e.backtrace end unless URI::HTTP === url raise ArgumentError, "Wrong protocol specified. Only http or https allowed!" end proto = url.scheme user = url.user passwd = url.password host = url.host port = url.port path = url.path.empty? ? nil : url.request_uri proxy_host, proxy_port = (proxy || "").split(":") proxy_port = proxy_port.to_i if proxy_port self.new(host, path, port, proxy_host, proxy_port, user, passwd, (proto == "https"), timeout) end alias new_from_uri new2 # Receives a Hash and calls XMLRPC::Client.new # with the corresponding values. # # The +hash+ parameter has following case-insensitive keys: # * host # * path # * port # * proxy_host # * proxy_port # * user # * password # * use_ssl # * timeout def new3(hash={}) # convert all keys into lowercase strings h = {} hash.each { |k,v| h[k.to_s.downcase] = v } self.new(h['host'], h['path'], h['port'], h['proxy_host'], h['proxy_port'], h['user'], h['password'], h['use_ssl'], h['timeout']) end alias new_from_hash new3 end # Returns the Net::HTTP object for the client. If you want to # change HTTP client options except header, cookie, timeout, # user and password, use Net::HTTP directly. # # Since 2.1.0. attr_reader :http # Add additional HTTP headers to the request attr_accessor :http_header_extra # Returns the Net::HTTPResponse object of the last RPC. attr_reader :http_last_response # Get and set the HTTP Cookie header. attr_accessor :cookie # Return the corresponding attributes. attr_reader :timeout, :user, :password # Sets the Net::HTTP#read_timeout and Net::HTTP#open_timeout to # +new_timeout+ def timeout=(new_timeout) @timeout = new_timeout @http.read_timeout = @timeout @http.open_timeout = @timeout end # Changes the user for the Basic Authentication header to +new_user+ def user=(new_user) @user = new_user set_auth end # Changes the password for the Basic Authentication header to # +new_password+ def password=(new_password) @password = new_password set_auth end # Invokes the method named +method+ with the parameters given by # +args+ on the XML-RPC server. # # The +method+ parameter is converted into a String and should # be a valid XML-RPC method-name. # # Each parameter of +args+ must be of one of the following types, # where Hash, Struct and Array can contain any of these listed _types_: # # * Integer # * TrueClass, FalseClass, +true+, +false+ # * String, Symbol # * Float # * Hash, Struct # * Array # * Date, Time, XMLRPC::DateTime # * XMLRPC::Base64 # * A Ruby object which class includes XMLRPC::Marshallable # (only if Config::ENABLE_MARSHALLING is +true+). # That object is converted into a hash, with one additional key/value # pair ___class___ which contains the class name # for restoring that object later. # # The method returns the return-value from the Remote Procedure Call. # # The type of the return-value is one of the types shown above. # # An Integer is only allowed when it fits in 32-bit. A XML-RPC # +dateTime.iso8601+ type is always returned as a XMLRPC::DateTime object. # Struct is never returned, only a Hash, the same for a Symbol, where as a # String is always returned. XMLRPC::Base64 is returned as a String from # xmlrpc4r version 1.6.1 on. # # If the remote procedure returned a fault-structure, then a # XMLRPC::FaultException exception is raised, which has two accessor-methods # +faultCode+ an Integer, and +faultString+ a String. def call(method, *args) ok, param = call2(method, *args) if ok param else raise param end end # The difference between this method and XMLRPC::Client#call is, that # this method will NOT raise a XMLRPC::FaultException exception. # # The method returns an array of two values. The first value indicates if # the second value is +true+ or an XMLRPC::FaultException. # # Both are explained in XMLRPC::Client#call. # # Simple to remember: The "2" in "call2" denotes the number of values it returns. def call2(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, false) parser().parseMethodResponse(data) end # Similar to XMLRPC::Client#call, however can be called concurrently and # use a new connection for each request. In contrast to the corresponding # method without the +_async+ suffix, which use connect-alive (one # connection for all requests). # # Note, that you have to use Thread to call these methods concurrently. # The following example calls two methods concurrently: # # Thread.new { # p client.call_async("michael.add", 4, 5) # } # # Thread.new { # p client.call_async("michael.div", 7, 9) # } # def call_async(method, *args) ok, param = call2_async(method, *args) if ok param else raise param end end # Same as XMLRPC::Client#call2, but can be called concurrently. # # See also XMLRPC::Client#call_async def call2_async(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, true) parser().parseMethodResponse(data) end # You can use this method to execute several methods on a XMLRPC server # which support the multi-call extension. # # s.multicall( # ['michael.add', 3, 4], # ['michael.sub', 4, 5] # ) # # => [7, -1] def multicall(*methods) ok, params = multicall2(*methods) if ok params else raise params end end # Same as XMLRPC::Client#multicall, but returns two parameters instead of # raising an XMLRPC::FaultException. # # See XMLRPC::Client#call2 def multicall2(*methods) gen_multicall(methods, false) end # Similar to XMLRPC::Client#multicall, however can be called concurrently and # use a new connection for each request. In contrast to the corresponding # method without the +_async+ suffix, which use connect-alive (one # connection for all requests). # # Note, that you have to use Thread to call these methods concurrently. # The following example calls two methods concurrently: # # Thread.new { # p client.multicall_async("michael.add", 4, 5) # } # # Thread.new { # p client.multicall_async("michael.div", 7, 9) # } # def multicall_async(*methods) ok, params = multicall2_async(*methods) if ok params else raise params end end # Same as XMLRPC::Client#multicall2, but can be called concurrently. # # See also XMLRPC::Client#multicall_async def multicall2_async(*methods) gen_multicall(methods, true) end # Returns an object of class XMLRPC::Client::Proxy, initialized with # +prefix+ and +args+. # # A proxy object returned by this method behaves like XMLRPC::Client#call, # i.e. a call on that object will raise a XMLRPC::FaultException when a # fault-structure is returned by that call. def proxy(prefix=nil, *args) Proxy.new(self, prefix, args, :call) end # Almost the same like XMLRPC::Client#proxy only that a call on the returned # XMLRPC::Client::Proxy object will return two parameters. # # See XMLRPC::Client#call2 def proxy2(prefix=nil, *args) Proxy.new(self, prefix, args, :call2) end # Similar to XMLRPC::Client#proxy, however can be called concurrently and # use a new connection for each request. In contrast to the corresponding # method without the +_async+ suffix, which use connect-alive (one # connection for all requests). # # Note, that you have to use Thread to call these methods concurrently. # The following example calls two methods concurrently: # # Thread.new { # p client.proxy_async("michael.add", 4, 5) # } # # Thread.new { # p client.proxy_async("michael.div", 7, 9) # } # def proxy_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call_async) end # Same as XMLRPC::Client#proxy2, but can be called concurrently. # # See also XMLRPC::Client#proxy_async def proxy2_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call2_async) end private def net_http(host, port, proxy_host, proxy_port) Net::HTTP.new host, port, proxy_host, proxy_port end def dup_net_http http = net_http(@http.address, @http.port, @http.proxy_address, @http.proxy_port) http.proxy_user = @http.proxy_user http.proxy_pass = @http.proxy_pass if @http.use_ssl? http.use_ssl = true Net::HTTP::SSL_ATTRIBUTES.each do |attribute| http.__send__("#{attribute}=", @http.__send__(attribute)) end end http.read_timeout = @http.read_timeout http.open_timeout = @http.open_timeout http end def set_auth if @user.nil? @auth = nil else a = "#@user" a << ":#@password" if @password != nil @auth = "Basic " + [a].pack("m0") end end def do_rpc(request, async=false) header = { "User-Agent" => USER_AGENT, "Content-Type" => "text/xml; charset=utf-8", "Content-Length" => request.bytesize.to_s, "Connection" => (async ? "close" : "keep-alive") } header["Cookie"] = @cookie if @cookie header.update(@http_header_extra) if @http_header_extra if @auth != nil # add authorization header header["Authorization"] = @auth end resp = nil @http_last_response = nil if async # use a new HTTP object for each call http = dup_net_http # post request http.start { resp = http.request_post(@path, request, header) } else # reuse the HTTP object for each call => connection alive is possible # we must start connection explicitly first time so that http.request # does not assume that we don't want keepalive @http.start if not @http.started? # post request resp = @http.request_post(@path, request, header) end @http_last_response = resp data = resp.body if resp.code == "401" # Authorization Required raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}" elsif resp.code[0,1] != "2" raise "HTTP-Error: #{resp.code} #{resp.message}" end # assume text/xml on instances where Content-Type header is not set ct_expected = resp["Content-Type"] || 'text/xml' ct = parse_content_type(ct_expected).first if ct != "text/xml" if ct == "text/html" raise "Wrong content-type (received '#{ct}' but expected 'text/xml'): \n#{data}" else raise "Wrong content-type (received '#{ct}' but expected 'text/xml')" end end expected = resp["Content-Length"] || "" if data.nil? or data.bytesize == 0 raise "Wrong size. Was #{data.bytesize}, should be #{expected}" end parse_set_cookies(resp.get_fields("Set-Cookie")) return data end def parse_set_cookies(set_cookies) return if set_cookies.nil? return if set_cookies.empty? require 'webrick/cookie' pairs = {} set_cookies.each do |set_cookie| cookie = WEBrick::Cookie.parse_set_cookie(set_cookie) pairs.delete(cookie.name) pairs[cookie.name] = cookie.value end cookies = pairs.collect do |name, value| WEBrick::Cookie.new(name, value).to_s end @cookie = cookies.join("; ") end def gen_multicall(methods=[], async=false) meth = :call2 meth = :call2_async if async ok, params = self.send(meth, "system.multicall", methods.collect {|m| {'methodName' => m[0], 'params' => m[1..-1]} } ) if ok params = params.collect do |param| if param.is_a? Array param[0] elsif param.is_a? Hash XMLRPC::FaultException.new(param["faultCode"], param["faultString"]) else raise "Wrong multicall return value" end end end return ok, params end # XML-RPC calls look nicer! # # You can call any method onto objects of that class - the object handles # XMLRPC::Client::Proxy#method_missing and will forward the method call to # a XML-RPC server. # # Don't use this class directly, instead use the public instance method # XMLRPC::Client#proxy or XMLRPC::Client#proxy2. # # require "xmlrpc/client" # # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) # # michael = server.proxy("michael") # michael2 = server.proxy("michael", 4) # # # both calls should return the same value '9'. # p michael.add(4,5) # p michael2.add(5) class Proxy # Creates an object which provides XMLRPC::Client::Proxy#method_missing. # # The given +server+ must be an instance of XMLRPC::Client, which is the # XML-RPC server to be used for a XML-RPC call. # # +prefix+ and +delim+ will be prepended to the method name called onto this object. # # An optional parameter +meth+ is the method to use for a RPC. # It can be either, call, call2, call_async, call2_async # # +args+ are arguments which are automatically given to every XML-RPC # call before being provided through +method_missing+. def initialize(server, prefix, args=[], meth=:call, delim=".") @server = server @prefix = prefix ? prefix + delim : "" @args = args @meth = meth end # Every method call is forwarded to the XML-RPC server defined in # XMLRPC::Client::Proxy#new. # # Note: Inherited methods from class Object cannot be used as XML-RPC # names, because they get around +method_missing+. def method_missing(mid, *args) pre = @prefix + mid.to_s arg = @args + args @server.send(@meth, pre, *arg) end end # class Proxy end # class Client end # module XMLRPC PKu]z[W(O(O!xmlrpc-0.3.0/lib/xmlrpc/server.rbnu[# frozen_string_literal: false # xmlrpc/server.rb # Copyright (C) 2001, 2002, 2003, 2005 by Michael Neumann (mneumann@ntecs.de) # # Released under the same term of license as Ruby. require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" # ParserWriterChooseMixin module XMLRPC # :nodoc: # This is the base class for all XML-RPC server-types (CGI, standalone). # You can add handler and set a default handler. # Do not use this server, as this is/should be an abstract class. # # === How the method to call is found # The arity (number of accepted arguments) of a handler (method or Proc # object) is compared to the given arguments submitted by the client for a # RPC, or Remote Procedure Call. # # A handler is only called if it accepts the number of arguments, otherwise # the search for another handler will go on. When at the end no handler was # found, the default_handler, XMLRPC::BasicServer#set_default_handler will be # called. # # With this technique it is possible to do overloading by number of parameters, but # only for Proc handler, because you cannot define two methods of the same name in # the same class. class BasicServer include ParserWriterChooseMixin include ParseContentType ERR_METHOD_MISSING = 1 ERR_UNCAUGHT_EXCEPTION = 2 ERR_MC_WRONG_PARAM = 3 ERR_MC_MISSING_PARAMS = 4 ERR_MC_MISSING_METHNAME = 5 ERR_MC_RECURSIVE_CALL = 6 ERR_MC_WRONG_PARAM_PARAMS = 7 ERR_MC_EXPECTED_STRUCT = 8 # Creates a new XMLRPC::BasicServer instance, which should not be # done, because XMLRPC::BasicServer is an abstract class. This # method should be called from a subclass indirectly by a +super+ call # in the initialize method. # # The parameter +class_delim+ is used by add_handler, see # XMLRPC::BasicServer#add_handler, when an object is added as a handler, to # delimit the object-prefix and the method-name. def initialize(class_delim=".") @handler = [] @default_handler = nil @service_hook = nil @class_delim = class_delim @create = nil @parser = nil add_multicall if Config::ENABLE_MULTICALL add_introspection if Config::ENABLE_INTROSPECTION end # Adds +aBlock+ to the list of handlers, with +name+ as the name of # the method. # # Parameters +signature+ and +help+ are used by the Introspection method if # specified, where +signature+ is either an Array containing strings each # representing a type of it's signature (the first is the return value) or # an Array of Arrays if the method has multiple signatures. # # Value type-names are "int, boolean, double, string, dateTime.iso8601, # base64, array, struct". # # Parameter +help+ is a String with information about how to call this method etc. # # When a method fails, it can tell the client by throwing an # XMLRPC::FaultException like in this example: # # s.add_handler("michael.div") do |a,b| # if b == 0 # raise XMLRPC::FaultException.new(1, "division by zero") # else # a / b # end # end # # In the case of b==0 the client gets an object back of type # XMLRPC::FaultException that has a +faultCode+ and +faultString+ field. # # This is the second form of (()). # To add an object write: # # server.add_handler("michael", MyHandlerClass.new) # # All public methods of MyHandlerClass are accessible to # the XML-RPC clients by michael."name of method". This is # where the +class_delim+ in XMLRPC::BasicServer.new plays it's role, a # XML-RPC method-name is defined by +prefix+ + +class_delim+ + "name # of method". # # The third form of +add_handler is to use XMLRPC::Service::Interface to # generate an object, which represents an interface (with signature and # help text) for a handler class. # # The +interface+ parameter must be an instance of XMLRPC::Service::Interface. # Adds all methods of +obj+ which are defined in the +interface+ to the server. # # This is the recommended way of adding services to a server! def add_handler(prefix, obj_or_signature=nil, help=nil, &block) if block_given? # proc-handler @handler << [prefix, block, obj_or_signature, help] else if prefix.kind_of? String # class-handler raise ArgumentError, "Expected non-nil value" if obj_or_signature.nil? @handler << [prefix + @class_delim, obj_or_signature] elsif prefix.kind_of? XMLRPC::Service::BasicInterface # class-handler with interface # add all methods @handler += prefix.get_methods(obj_or_signature, @class_delim) else raise ArgumentError, "Wrong type for parameter 'prefix'" end end self end # Returns the service-hook, which is called on each service request (RPC) # unless it's +nil+. def get_service_hook @service_hook end # A service-hook is called for each service request (RPC). # # You can use a service-hook for example to wrap existing methods and catch # exceptions of them or convert values to values recognized by XMLRPC. # # You can disable it by passing +nil+ as the +handler+ parameter. # # The service-hook is called with a Proc object along with any parameters. # # An example: # # server.set_service_hook {|obj, *args| # begin # ret = obj.call(*args) # call the original service-method # # could convert the return value # rescue # # rescue exceptions # end # } # def set_service_hook(&handler) @service_hook = handler self end # Returns the default-handler, which is called when no handler for # a method-name is found. # # It is either a Proc object or +nil+. def get_default_handler @default_handler end # Sets +handler+ as the default-handler, which is called when # no handler for a method-name is found. # # +handler+ is a code-block. # # The default-handler is called with the (XML-RPC) method-name as first # argument, and the other arguments are the parameters given by the # client-call. # # If no block is specified the default of XMLRPC::BasicServer is # used, which raises a XMLRPC::FaultException saying "method missing". def set_default_handler(&handler) @default_handler = handler self end # Adds the multi-call handler "system.multicall". def add_multicall add_handler("system.multicall", %w(array array), "Multicall Extension") do |arrStructs| unless arrStructs.is_a? Array raise XMLRPC::FaultException.new(ERR_MC_WRONG_PARAM, "system.multicall expects an array") end arrStructs.collect {|call| if call.is_a? Hash methodName = call["methodName"] params = call["params"] if params.nil? multicall_fault(ERR_MC_MISSING_PARAMS, "Missing params") elsif methodName.nil? multicall_fault(ERR_MC_MISSING_METHNAME, "Missing methodName") else if methodName == "system.multicall" multicall_fault(ERR_MC_RECURSIVE_CALL, "Recursive system.multicall forbidden") else unless params.is_a? Array multicall_fault(ERR_MC_WRONG_PARAM_PARAMS, "Parameter params have to be an Array") else ok, val = call_method(methodName, *params) if ok # correct return value [val] else # exception multicall_fault(val.faultCode, val.faultString) end end end end else multicall_fault(ERR_MC_EXPECTED_STRUCT, "system.multicall expected struct") end } end # end add_handler self end # Adds the introspection handlers "system.listMethods", # "system.methodSignature" and # "system.methodHelp", where only the first one works. def add_introspection add_handler("system.listMethods",%w(array), "List methods available on this XML-RPC server") do methods = [] @handler.each do |name, obj| if obj.kind_of? Proc methods << name else obj.class.public_instance_methods(false).each do |meth| methods << "#{name}#{meth}" end end end methods end add_handler("system.methodSignature", %w(array string), "Returns method signature") do |meth| sigs = [] @handler.each do |name, obj, sig| if obj.kind_of? Proc and sig != nil and name == meth if sig[0].kind_of? Array # sig contains multiple signatures, e.g. [["array"], ["array", "string"]] sig.each {|s| sigs << s} else # sig is a single signature, e.g. ["array"] sigs << sig end end end sigs.uniq! || sigs # remove eventually duplicated signatures end add_handler("system.methodHelp", %w(string string), "Returns help on using this method") do |meth| help = nil @handler.each do |name, obj, sig, hlp| if obj.kind_of? Proc and name == meth help = hlp break end end help || "" end self end def process(data) method, params = parser().parseMethodCall(data) handle(method, *params) end private def multicall_fault(nr, str) {"faultCode" => nr, "faultString" => str} end def dispatch(methodname, *args) for name, obj in @handler if obj.kind_of? Proc next unless methodname == name else next unless methodname =~ /^#{name}(.+)$/ next unless obj.respond_to? $1 obj = obj.method($1) end if check_arity(obj, args.size) if @service_hook.nil? return obj.call(*args) else return @service_hook.call(obj, *args) end end end if @default_handler.nil? raise XMLRPC::FaultException.new(ERR_METHOD_MISSING, "Method #{methodname} missing or wrong number of parameters!") else @default_handler.call(methodname, *args) end end # Returns +true+, if the arity of +obj+ matches +n_args+ def check_arity(obj, n_args) ary = obj.arity if ary >= 0 n_args == ary else n_args >= (ary+1).abs end end def call_method(methodname, *args) begin [true, dispatch(methodname, *args)] rescue XMLRPC::FaultException => e [false, e] rescue Exception => e [false, XMLRPC::FaultException.new(ERR_UNCAUGHT_EXCEPTION, "Uncaught exception #{e.message} in method #{methodname}")] end end def handle(methodname, *args) create().methodResponse(*call_method(methodname, *args)) end end # Implements a CGI-based XML-RPC server. # # require "xmlrpc/server" # # s = XMLRPC::CGIServer.new # # s.add_handler("michael.add") do |a,b| # a + b # end # # s.add_handler("michael.div") do |a,b| # if b == 0 # raise XMLRPC::FaultException.new(1, "division by zero") # else # a / b # end # end # # s.set_default_handler do |name, *args| # raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + # " or wrong number of parameters!") # end # # s.serve # # # Note: Make sure that you don't write to standard-output in a # handler, or in any other part of your program, this would cause a CGI-based # server to fail! class CGIServer < BasicServer @@obj = nil # Creates a new XMLRPC::CGIServer instance. # # All parameters given are by-passed to XMLRPC::BasicServer.new. # # You can only create one XMLRPC::CGIServer instance, because more # than one makes no sense. def CGIServer.new(*a) @@obj = super(*a) if @@obj.nil? @@obj end def initialize(*a) super(*a) end # Call this after you have added all you handlers to the server. # # This method processes a XML-RPC method call and sends the answer # back to the client. def serve catch(:exit_serve) { length = ENV['CONTENT_LENGTH'].to_i http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST" http_error(400, "Bad Request") unless parse_content_type(ENV['CONTENT_TYPE']).first == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? $stdin.binmode if $stdin.respond_to? :binmode data = $stdin.read(length) http_error(400, "Bad Request") if data.nil? or data.bytesize != length http_write(process(data), "Content-type" => "text/xml; charset=utf-8") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

    #{err}

    Unexpected error occurred while processing XML-RPC request!

    MSGEND http_write(msg, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.bytesize.to_s str = "" h.each {|key, value| str << "#{key}: #{value}\r\n"} str << "\r\n#{body}" print str end end # Implements a XML-RPC server, which works with Apache mod_ruby. # # Use it in the same way as XMLRPC::CGIServer! class ModRubyServer < BasicServer # Creates a new XMLRPC::ModRubyServer instance. # # All parameters given are by-passed to XMLRPC::BasicServer.new. def initialize(*a) @ap = Apache::request super(*a) end # Call this after you have added all you handlers to the server. # # This method processes a XML-RPC method call and sends the answer # back to the client. def serve catch(:exit_serve) { header = {} @ap.headers_in.each {|key, value| header[key.capitalize] = value} length = header['Content-length'].to_i http_error(405, "Method Not Allowed") unless @ap.request_method == "POST" http_error(400, "Bad Request") unless parse_content_type(header['Content-type']).first == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? @ap.binmode data = @ap.read(length) http_error(400, "Bad Request") if data.nil? or data.bytesize != length http_write(process(data), 200, "Content-type" => "text/xml; charset=utf-8") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

    #{err}

    Unexpected error occurred while processing XML-RPC request!

    MSGEND http_write(msg, status, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, status, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.bytesize.to_s h.each {|key, value| @ap.headers_out[key] = value } @ap.content_type = h["Content-type"] @ap.status = status.to_i @ap.send_http_header @ap.print body end end class WEBrickServlet < BasicServer; end # forward declaration # Implements a standalone XML-RPC server. The method XMLRPC::Server#serve is # left if a SIGHUP is sent to the program. # # require "xmlrpc/server" # # s = XMLRPC::Server.new(8080) # # s.add_handler("michael.add") do |a,b| # a + b # end # # s.add_handler("michael.div") do |a,b| # if b == 0 # raise XMLRPC::FaultException.new(1, "division by zero") # else # a / b # end # end # # s.set_default_handler do |name, *args| # raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + # " or wrong number of parameters!") # end # # s.serve class Server < WEBrickServlet # Creates a new XMLRPC::Server instance, which is a XML-RPC server # listening on the given +port+ and accepts requests for the given +host+, # which is +localhost+ by default. # # The server is not started, to start it you have to call # XMLRPC::Server#serve. # # The optional +audit+ and +debug+ parameters are obsolete! # # All additionally provided parameters in *a are by-passed to # XMLRPC::BasicServer.new. def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a) super(*a) require 'webrick' @server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections, :Logger => WEBrick::Log.new(stdlog)) @server.mount("/", self) end # Call this after you have added all you handlers to the server. # This method starts the server to listen for XML-RPC requests and answer them. def serve signals = %w[INT TERM HUP] & Signal.list.keys signals.each { |signal| trap(signal) { @server.shutdown } } @server.start end # Stops and shuts the server down. def shutdown @server.shutdown end end # Implements a servlet for use with WEBrick, a pure Ruby (HTTP) server # framework. # # require "webrick" # require "xmlrpc/server" # # s = XMLRPC::WEBrickServlet.new # s.add_handler("michael.add") do |a,b| # a + b # end # # s.add_handler("michael.div") do |a,b| # if b == 0 # raise XMLRPC::FaultException.new(1, "division by zero") # else # a / b # end # end # # s.set_default_handler do |name, *args| # raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + # " or wrong number of parameters!") # end # # httpserver = WEBrick::HTTPServer.new(:Port => 8080) # httpserver.mount("/RPC2", s) # trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows # httpserver.start class WEBrickServlet < BasicServer def initialize(*a) super require "webrick/httpstatus" @valid_ip = nil end # Deprecated from WEBrick/1.2.2, but does not break anything. def require_path_info? false end def get_instance(config, *options) # TODO: set config & options self end # Specifies the valid IP addresses that are allowed to connect to the server. # # Each IP is either a String or a Regexp. def set_valid_ip(*ip_addr) if ip_addr.size == 1 and ip_addr[0].nil? @valid_ip = nil else @valid_ip = ip_addr end end # Return the valid IP addresses that are allowed to connect to the server. # # See also, XMLRPC::Server#set_valid_ip def get_valid_ip @valid_ip end def service(request, response) if @valid_ip raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip } end if request.request_method != "POST" raise WEBrick::HTTPStatus::MethodNotAllowed, "unsupported method `#{request.request_method}'." end if parse_content_type(request['Content-type']).first != "text/xml" raise WEBrick::HTTPStatus::BadRequest end length = (request['Content-length'] || 0).to_i raise WEBrick::HTTPStatus::LengthRequired unless length > 0 data = request.body if data.nil? or data.bytesize != length raise WEBrick::HTTPStatus::BadRequest end resp = process(data) if resp.nil? or resp.bytesize <= 0 raise WEBrick::HTTPStatus::InternalServerError end response.status = 200 response['Content-Length'] = resp.bytesize response['Content-Type'] = "text/xml; charset=utf-8" response.body = resp end end end # module XMLRPC =begin = History $Id$ =end PKu] T==!xmlrpc-0.3.0/lib/xmlrpc/parser.rbnu[# frozen_string_literal: false # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "date" require "xmlrpc/base64" require "xmlrpc/datetime" module XMLRPC # :nodoc: # Raised when the remote procedure returns a fault-structure, which has two # accessor-methods +faultCode+ an Integer, and +faultString+ a String. class FaultException < StandardError attr_reader :faultCode, :faultString # Creates a new XMLRPC::FaultException instance. # # +faultString+ is passed to StandardError as the +msg+ of the Exception. def initialize(faultCode, faultString) @faultCode = faultCode @faultString = faultString super(@faultString) end # The +faultCode+ and +faultString+ of the exception in a Hash. def to_h {"faultCode" => @faultCode, "faultString" => @faultString} end end # Helper class used to convert types. module Convert # Converts a String to an Integer # # See also String.to_i def self.int(str) str.to_i end # Converts a String to +true+ or +false+ # # Raises an exception if +str+ is not +0+ or +1+ def self.boolean(str) case str when "0" then false when "1" then true else raise "RPC-value of type boolean is wrong" end end # Converts a String to a Float # # See also String.to_f def self.double(str) str.to_f end # Converts a the given +str+ to a +dateTime.iso8601+ formatted date. # # Raises an exception if the String isn't in +dateTime.iso8601+ format. # # See also, XMLRPC::DateTime def self.dateTime(str) case str when /^(-?\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(?:Z|([+-])(\d\d):?(\d\d))?$/ a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} if $7 ofs = $8.to_i*3600 + $9.to_i*60 ofs = -ofs if $7=='+' utc = Time.utc(*a) + ofs a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ] end XMLRPC::DateTime.new(*a) when /^(-?\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(Z|([+-]\d\d):(\d\d))?$/ a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} if a[0] < 70 a[0] += 2000 else a[0] += 1900 end if $7 ofs = $8.to_i*3600 + $9.to_i*60 ofs = -ofs if $7=='+' utc = Time.utc(*a) + ofs a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ] end XMLRPC::DateTime.new(*a) else raise "wrong dateTime.iso8601 format " + str end end # Decodes the given +str+ using XMLRPC::Base64.decode def self.base64(str) XMLRPC::Base64.decode(str) end # Converts the given +hash+ to a marshalled object. # # Returns the given +hash+ if an exception occurs. def self.struct(hash) # convert to marshalled object klass = hash["___class___"] if klass.nil? or Config::ENABLE_MARSHALLING == false hash else begin mod = Module klass.split("::").each {|const| mod = mod.const_get(const.strip)} obj = mod.allocate hash.delete "___class___" hash.each {|key, value| obj.instance_variable_set("@#{ key }", value) if key =~ /^([a-zA-Z_]\w*)$/ } obj rescue hash end end end # Converts the given +hash+ to an XMLRPC::FaultException object by passing # the +faultCode+ and +faultString+ attributes of the Hash to # XMLRPC::FaultException.new # # Raises an Exception if the given +hash+ doesn't meet the requirements. # Those requirements being: # * 2 keys # * 'faultCode' key is an Integer # * 'faultString' key is a String def self.fault(hash) if hash.kind_of? Hash and hash.size == 2 and hash.has_key? "faultCode" and hash.has_key? "faultString" and hash["faultCode"].kind_of? Integer and hash["faultString"].kind_of? String XMLRPC::FaultException.new(hash["faultCode"], hash["faultString"]) else raise "wrong fault-structure: #{hash.inspect}" end end end # module Convert # Parser for XML-RPC call and response module XMLParser class AbstractTreeParser def parseMethodResponse(str) methodResponse_document(createCleanedTree(str)) end def parseMethodCall(str) methodCall_document(createCleanedTree(str)) end private # Removes all whitespaces but in the tags i4, i8, int, boolean.... # and all comments def removeWhitespacesAndComments(node) remove = [] childs = node.childNodes.to_a childs.each do |nd| case _nodeType(nd) when :TEXT # TODO: add nil? unless %w(i4 i8 int boolean string double dateTime.iso8601 base64).include? node.nodeName if node.nodeName == "value" if not node.childNodes.to_a.detect {|n| _nodeType(n) == :ELEMENT}.nil? remove << nd if nd.nodeValue.strip == "" end else remove << nd if nd.nodeValue.strip == "" end end when :COMMENT remove << nd else removeWhitespacesAndComments(nd) end end remove.each { |i| node.removeChild(i) } end def nodeMustBe(node, name) cmp = case name when Array name.include?(node.nodeName) when String name == node.nodeName else raise "error" end if not cmp then raise "wrong xml-rpc (name)" end node end # Returns, when successfully the only child-node def hasOnlyOneChild(node, name=nil) if node.childNodes.to_a.size != 1 raise "wrong xml-rpc (size)" end if name != nil then nodeMustBe(node.firstChild, name) end end def assert(b) if not b then raise "assert-fail" end end # The node `node` has empty string or string def text_zero_one(node) nodes = node.childNodes.to_a.size if nodes == 1 text(node.firstChild) elsif nodes == 0 "" else raise "wrong xml-rpc (size)" end end def integer(node) #TODO: check string for float because to_i returnsa # 0 when wrong string nodeMustBe(node, %w(i4 i8 int)) hasOnlyOneChild(node) Convert.int(text(node.firstChild)) end def boolean(node) nodeMustBe(node, "boolean") hasOnlyOneChild(node) Convert.boolean(text(node.firstChild)) end def v_nil(node) nodeMustBe(node, "nil") assert( node.childNodes.to_a.size == 0 ) nil end def string(node) nodeMustBe(node, "string") text_zero_one(node) end def double(node) #TODO: check string for float because to_f returnsa # 0.0 when wrong string nodeMustBe(node, "double") hasOnlyOneChild(node) Convert.double(text(node.firstChild)) end def dateTime(node) nodeMustBe(node, "dateTime.iso8601") hasOnlyOneChild(node) Convert.dateTime( text(node.firstChild) ) end def base64(node) nodeMustBe(node, "base64") #hasOnlyOneChild(node) Convert.base64(text_zero_one(node)) end def member(node) nodeMustBe(node, "member") assert( node.childNodes.to_a.size == 2 ) [ name(node[0]), value(node[1]) ] end def name(node) nodeMustBe(node, "name") #hasOnlyOneChild(node) text_zero_one(node) end def array(node) nodeMustBe(node, "array") hasOnlyOneChild(node, "data") data(node.firstChild) end def data(node) nodeMustBe(node, "data") node.childNodes.to_a.collect do |val| value(val) end end def param(node) nodeMustBe(node, "param") hasOnlyOneChild(node, "value") value(node.firstChild) end def methodResponse(node) nodeMustBe(node, "methodResponse") hasOnlyOneChild(node, %w(params fault)) child = node.firstChild case child.nodeName when "params" [ true, params(child,false) ] when "fault" [ false, fault(child) ] else raise "unexpected error" end end def methodName(node) nodeMustBe(node, "methodName") hasOnlyOneChild(node) text(node.firstChild) end def params(node, call=true) nodeMustBe(node, "params") if call node.childNodes.to_a.collect do |n| param(n) end else # response (only one param) hasOnlyOneChild(node) param(node.firstChild) end end def fault(node) nodeMustBe(node, "fault") hasOnlyOneChild(node, "value") f = value(node.firstChild) Convert.fault(f) end # _nodeType is defined in the subclass def text(node) assert( _nodeType(node) == :TEXT ) assert( node.hasChildNodes == false ) assert( node.nodeValue != nil ) node.nodeValue.to_s end def struct(node) nodeMustBe(node, "struct") hash = {} node.childNodes.to_a.each do |me| n, v = member(me) hash[n] = v end Convert.struct(hash) end def value(node) nodeMustBe(node, "value") nodes = node.childNodes.to_a.size if nodes == 0 return "" elsif nodes > 1 raise "wrong xml-rpc (size)" end child = node.firstChild case _nodeType(child) when :TEXT text_zero_one(node) when :ELEMENT case child.nodeName when "i4", "i8", "int" then integer(child) when "boolean" then boolean(child) when "string" then string(child) when "double" then double(child) when "dateTime.iso8601" then dateTime(child) when "base64" then base64(child) when "struct" then struct(child) when "array" then array(child) when "nil" if Config::ENABLE_NIL_PARSER v_nil(child) else raise "wrong/unknown XML-RPC type 'nil'" end else raise "wrong/unknown XML-RPC type" end else raise "wrong type of node" end end def methodCall(node) nodeMustBe(node, "methodCall") assert( (1..2).include?( node.childNodes.to_a.size ) ) name = methodName(node[0]) if node.childNodes.to_a.size == 2 then pa = params(node[1]) else # no parameters given pa = [] end [name, pa] end end # module TreeParserMixin class AbstractStreamParser def parseMethodResponse(str) parser = @parser_class.new parser.parse(str) raise "No valid method response!" if parser.method_name != nil if parser.fault != nil # is a fault structure [false, parser.fault] else # is a normal return value raise "Missing return value!" if parser.params.size == 0 raise "Too many return values. Only one allowed!" if parser.params.size > 1 [true, parser.params[0]] end end def parseMethodCall(str) parser = @parser_class.new parser.parse(str) raise "No valid method call - missing method name!" if parser.method_name.nil? [parser.method_name, parser.params] end end module StreamParserMixin attr_reader :params attr_reader :method_name attr_reader :fault def initialize(*a) super(*a) @params = [] @values = [] @val_stack = [] @names = [] @name = [] @structs = [] @struct = {} @method_name = nil @fault = nil @data = nil end def startElement(name, attrs=[]) @data = nil case name when "value" @value = nil when "nil" raise "wrong/unknown XML-RPC type 'nil'" unless Config::ENABLE_NIL_PARSER @value = :nil when "array" @val_stack << @values @values = [] when "struct" @names << @name @name = [] @structs << @struct @struct = {} end end def endElement(name) @data ||= "" case name when "string" @value = @data when "i4", "i8", "int" @value = Convert.int(@data) when "boolean" @value = Convert.boolean(@data) when "double" @value = Convert.double(@data) when "dateTime.iso8601" @value = Convert.dateTime(@data) when "base64" @value = Convert.base64(@data) when "value" @value = @data if @value.nil? @values << (@value == :nil ? nil : @value) when "array" @value = @values @values = @val_stack.pop when "struct" @value = Convert.struct(@struct) @name = @names.pop @struct = @structs.pop when "name" @name[0] = @data when "member" @struct[@name[0]] = @values.pop when "param" @params << @values[0] @values = [] when "fault" @fault = Convert.fault(@values[0]) when "methodName" @method_name = @data end @data = nil end def character(data) if @data @data << data else @data = data end end end # module StreamParserMixin class REXMLStreamParser < AbstractStreamParser def initialize require "rexml/document" @parser_class = StreamListener end class StreamListener include StreamParserMixin alias :tag_start :startElement alias :tag_end :endElement alias :text :character alias :cdata :character def method_missing(*a) # ignore end def parse(str) REXML::Document.parse_stream(str, self) end end end class LibXMLStreamParser < AbstractStreamParser def initialize require 'libxml' @parser_class = LibXMLStreamListener end class LibXMLStreamListener include StreamParserMixin def on_start_element_ns(name, attributes, prefix, uri, namespaces) startElement(name) end def on_end_element_ns(name, prefix, uri) endElement(name) end alias :on_characters :character alias :on_cdata_block :character def method_missing(*a) end def parse(str) parser = LibXML::XML::SaxParser.string(str) parser.callbacks = self parser.parse() end end end Classes = [REXMLStreamParser, LibXMLStreamParser] # yields an instance of each installed parser def self.each_installed_parser XMLRPC::XMLParser::Classes.each do |klass| begin yield klass.new rescue LoadError end end end end # module XMLParser end # module XMLRPC PKu]HB xmlrpc-0.3.0/lib/xmlrpc/utils.rbnu[# frozen_string_literal: false # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # module XMLRPC # :nodoc: # This module enables a user-class to be marshalled # by XML-RPC for Ruby into a Hash, with one additional # key/value pair ___class___ => ClassName # module Marshallable end # Defines ParserWriterChooseMixin, which makes it possible to choose a # different XMLWriter and/or XMLParser then the default one. # # The Mixin is used in client.rb (class XMLRPC::Client) # and server.rb (class XMLRPC::BasicServer) module ParserWriterChooseMixin # Sets the XMLWriter to use for generating XML output. # # Should be an instance of a class from module XMLRPC::XMLWriter. # # If this method is not called, then XMLRPC::Config::DEFAULT_WRITER is used. def set_writer(writer) @create = Create.new(writer) self end # Sets the XMLParser to use for parsing XML documents. # # Should be an instance of a class from module XMLRPC::XMLParser. # # If this method is not called, then XMLRPC::Config::DEFAULT_PARSER is used. def set_parser(parser) @parser = parser self end private def create # if set_writer was not already called then call it now if @create.nil? then set_writer(Config::DEFAULT_WRITER.new) end @create end def parser # if set_parser was not already called then call it now if @parser.nil? then set_parser(Config::DEFAULT_PARSER.new) end @parser end end # module ParserWriterChooseMixin module Service # Base class for XMLRPC::Service::Interface definitions, used # by XMLRPC::BasicServer#add_handler class BasicInterface attr_reader :prefix, :methods def initialize(prefix) @prefix = prefix @methods = [] end def add_method(sig, help=nil, meth_name=nil) mname = nil sig = [sig] if sig.kind_of? String sig = sig.collect do |s| name, si = parse_sig(s) raise "Wrong signatures!" if mname != nil and name != mname mname = name si end @methods << [mname, meth_name || mname, sig, help] end private def parse_sig(sig) # sig is a String if sig =~ /^\s*(\w+)\s+([^(]+)(\(([^)]*)\))?\s*$/ params = [$1] name = $2.strip $4.split(",").each {|i| params << i.strip} if $4 != nil return name, params else raise "Syntax error in signature" end end end # class BasicInterface # # Class which wraps a XMLRPC::Service::Interface definition, used # by XMLRPC::BasicServer#add_handler # class Interface < BasicInterface def initialize(prefix, &p) raise "No interface specified" if p.nil? super(prefix) instance_eval(&p) end def get_methods(obj, delim=".") prefix = @prefix + delim @methods.collect { |name, meth, sig, help| [prefix + name.to_s, obj.method(meth).to_proc, sig, help] } end private def meth(*a) add_method(*a) end end # class Interface class PublicInstanceMethodsInterface < BasicInterface def initialize(prefix) super(prefix) end def get_methods(obj, delim=".") prefix = @prefix + delim obj.class.public_instance_methods(false).collect { |name| [prefix + name.to_s, obj.method(name).to_proc, nil, nil] } end end end # module Service # # Short-form to create a XMLRPC::Service::Interface # def self.interface(prefix, &p) Service::Interface.new(prefix, &p) end # Short-cut for creating a XMLRPC::Service::PublicInstanceMethodsInterface def self.iPIMethods(prefix) Service::PublicInstanceMethodsInterface.new(prefix) end module ParseContentType def parse_content_type(str) a, *b = str.split(";") return a.strip.downcase, *b end end end # module XMLRPC PKu]*#!xmlrpc-0.3.0/lib/xmlrpc/create.rbnu[# frozen_string_literal: false # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "date" require "xmlrpc/base64" module XMLRPC # :nodoc: module XMLWriter class Abstract def ele(name, *children) element(name, nil, *children) end def tag(name, txt) element(name, nil, text(txt)) end end class Simple < Abstract def document_to_str(doc) doc end def document(*params) params.join("") end def pi(name, *params) "" end def element(name, attrs, *children) raise "attributes not yet implemented" unless attrs.nil? if children.empty? "<#{name}/>" else "<#{name}>" + children.join("") + "" end end def text(txt) cleaned = txt.dup cleaned.gsub!(/&/, '&') cleaned.gsub!(//, '>') cleaned end end # class Simple class XMLParser < Abstract def initialize require "xmltreebuilder" end def document_to_str(doc) doc.to_s end def document(*params) XML::SimpleTree::Document.new(*params) end def pi(name, *params) XML::SimpleTree::ProcessingInstruction.new(name, *params) end def element(name, attrs, *children) XML::SimpleTree::Element.new(name, attrs, *children) end def text(txt) XML::SimpleTree::Text.new(txt) end end # class XMLParser Classes = [Simple, XMLParser] # yields an instance of each installed XML writer def self.each_installed_writer XMLRPC::XMLWriter::Classes.each do |klass| begin yield klass.new rescue LoadError end end end end # module XMLWriter # Creates XML-RPC call/response documents # class Create def initialize(xml_writer = nil) @writer = xml_writer || Config::DEFAULT_WRITER.new end def methodCall(name, *params) name = name.to_s if name !~ /[a-zA-Z0-9_.:\/]+/ raise ArgumentError, "Wrong XML-RPC method-name" end parameter = params.collect do |param| @writer.ele("param", conv2value(param)) end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodCall", @writer.tag("methodName", name), @writer.ele("params", *parameter) ) ) @writer.document_to_str(tree) + "\n" end # # Generates a XML-RPC methodResponse document # # When +is_ret+ is +false+ then the +params+ array must # contain only one element, which is a structure # of a fault return-value. # # When +is_ret+ is +true+ then a normal # return-value of all the given +params+ is created. # def methodResponse(is_ret, *params) if is_ret resp = params.collect do |param| @writer.ele("param", conv2value(param)) end resp = [@writer.ele("params", *resp)] else if params.size != 1 or params[0] === XMLRPC::FaultException raise ArgumentError, "no valid fault-structure given" end resp = @writer.ele("fault", conv2value(params[0].to_h)) end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodResponse", resp) ) @writer.document_to_str(tree) + "\n" end private # # Converts a Ruby object into a XML-RPC tag # def conv2value(param) # :doc: val = case param when Integer # XML-RPC's int is 32bit int if Config::ENABLE_BIGINT @writer.tag("i4", param.to_s) else if param >= -(2**31) and param <= (2**31-1) @writer.tag("i4", param.to_s) else raise "Integer is too big! Must be signed 32-bit integer!" end end when TrueClass, FalseClass @writer.tag("boolean", param ? "1" : "0") when Symbol @writer.tag("string", param.to_s) when String @writer.tag("string", param) when NilClass if Config::ENABLE_NIL_CREATE @writer.ele("nil") else raise "Wrong type NilClass. Not allowed!" end when Float raise "Wrong value #{param}. Not allowed!" unless param.finite? @writer.tag("double", param.to_s) when Struct h = param.members.collect do |key| value = param[key] @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Hash # TODO: can a Hash be empty? h = param.collect do |key, value| @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Array # TODO: can an Array be empty? a = param.collect {|v| conv2value(v) } @writer.ele("array", @writer.ele("data", *a) ) when Time, Date, ::DateTime @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S")) when XMLRPC::DateTime @writer.tag("dateTime.iso8601", format("%.4d%02d%02dT%02d:%02d:%02d", *param.to_a)) when XMLRPC::Base64 @writer.tag("base64", param.encoded) else if Config::ENABLE_MARSHALLING and param.class.included_modules.include? XMLRPC::Marshallable # convert Ruby object into Hash ret = {"___class___" => param.class.name} param.instance_variables.each {|v| name = v[1..-1] val = param.instance_variable_get(v) if val.nil? ret[name] = val if Config::ENABLE_NIL_CREATE else ret[name] = val end } return conv2value(ret) else ok, pa = wrong_type(param) if ok return conv2value(pa) else raise "Wrong type!" end end end @writer.ele("value", val) end def wrong_type(value) false end end # class Create end # module XMLRPC PKu]N W"xmlrpc-0.3.0/lib/xmlrpc/marshal.rbnu[# frozen_string_literal: false # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" module XMLRPC # :nodoc: # Marshalling of XMLRPC::Create#methodCall and XMLRPC::Create#methodResponse class Marshal include ParserWriterChooseMixin class << self def dump_call( methodName, *params ) new.dump_call( methodName, *params ) end def dump_response( param ) new.dump_response( param ) end def load_call( stringOrReadable ) new.load_call( stringOrReadable ) end def load_response( stringOrReadable ) new.load_response( stringOrReadable ) end alias dump dump_response alias load load_response end # class self def initialize( parser = nil, writer = nil ) set_parser( parser ) set_writer( writer ) end def dump_call( methodName, *params ) create.methodCall( methodName, *params ) end def dump_response( param ) create.methodResponse( ! param.kind_of?( XMLRPC::FaultException ) , param ) end # Returns [ methodname, params ] def load_call( stringOrReadable ) parser.parseMethodCall( stringOrReadable ) end # Returns +paramOrFault+ def load_response( stringOrReadable ) parser.parseMethodResponse( stringOrReadable )[1] end end # class Marshal end PKu]T!xmlrpc-0.3.0/lib/xmlrpc/base64.rbnu[# frozen_string_literal: false # # xmlrpc/base64.rb # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # Released under the same term of license as Ruby. module XMLRPC # :nodoc: # This class is necessary for 'xmlrpc4r' to determine that a string should # be transmitted base64-encoded and not as a raw-string. # # You can use XMLRPC::Base64 on the client and server-side as a # parameter and/or return-value. class Base64 # Creates a new XMLRPC::Base64 instance with string +str+ as the # internal string. When +state+ is +:dec+ it assumes that the # string +str+ is not in base64 format (perhaps already decoded), # otherwise if +state+ is +:enc+ it decodes +str+ # and stores it as the internal string. def initialize(str, state = :dec) case state when :enc @str = Base64.decode(str) when :dec @str = str else raise ArgumentError, "wrong argument; either :enc or :dec" end end # Returns the decoded internal string. def decoded @str end # Returns the base64 encoded internal string. def encoded Base64.encode(@str) end # Decodes string +str+ with base64 and returns that value. def Base64.decode(str) str.gsub(/\s+/, "").unpack("m")[0] end # Encodes string +str+ with base64 and returns that value. def Base64.encode(str) [str].pack("m") end end end # module XMLRPC =begin = History $Id$ =end PKu]799!xmlrpc-0.3.0/lib/xmlrpc/config.rbnu[# frozen_string_literal: false # # $Id$ # Configuration file for XML-RPC for Ruby # module XMLRPC # :nodoc: module Config # or XMLWriter::XMLParser DEFAULT_WRITER = XMLWriter::Simple # === Available parsers # # * XMLParser::REXMLStreamParser # * XMLParser::LibXMLStreamParser DEFAULT_PARSER = XMLParser::REXMLStreamParser # enable tag ENABLE_NIL_CREATE = false ENABLE_NIL_PARSER = false # allows integers greater than 32-bit if +true+ ENABLE_BIGINT = false # enable marshalling Ruby objects which include XMLRPC::Marshallable ENABLE_MARSHALLING = true # enable multiCall extension by default ENABLE_MULTICALL = false # enable Introspection extension by default ENABLE_INTROSPECTION = false end end PKu],'bigdecimal-2.0.0/lib/bigdecimal/math.rbnu[# frozen_string_literal: false require 'bigdecimal' # #-- # Contents: # sqrt(x, prec) # sin (x, prec) # cos (x, prec) # atan(x, prec) Note: |x|<1, x=0.9999 may not converge. # PI (prec) # E (prec) == exp(1.0,prec) # # where: # x ... BigDecimal number to be computed. # |x| must be small enough to get convergence. # prec ... Number of digits to be obtained. #++ # # Provides mathematical functions. # # Example: # # require "bigdecimal/math" # # include BigMath # # a = BigDecimal((PI(100)/2).to_s) # puts sin(a,100) # => 0.99999999999999999999......e0 # module BigMath module_function # call-seq: # sqrt(decimal, numeric) -> BigDecimal # # Computes the square root of +decimal+ to the specified number of digits of # precision, +numeric+. # # BigMath.sqrt(BigDecimal('2'), 16).to_s # #=> "0.1414213562373095048801688724e1" # def sqrt(x, prec) x.sqrt(prec) end # call-seq: # sin(decimal, numeric) -> BigDecimal # # Computes the sine of +decimal+ to the specified number of digits of # precision, +numeric+. # # If +decimal+ is Infinity or NaN, returns NaN. # # BigMath.sin(BigMath.PI(5)/4, 5).to_s # #=> "0.70710678118654752440082036563292800375e0" # def sin(x, prec) raise ArgumentError, "Zero or negative precision for sin" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") two = BigDecimal("2") x = -x if neg = x < 0 if x > (twopi = two * BigMath.PI(prec)) if x > 30 x %= twopi else x -= twopi while x > twopi end end x1 = x x2 = x.mult(x,n) sign = 1 y = x d = y i = one z = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig sign = -sign x1 = x2.mult(x1,n) i += two z *= (i-one) * i d = sign * x1.div(z,m) y += d end neg ? -y : y end # call-seq: # cos(decimal, numeric) -> BigDecimal # # Computes the cosine of +decimal+ to the specified number of digits of # precision, +numeric+. # # If +decimal+ is Infinity or NaN, returns NaN. # # BigMath.cos(BigMath.PI(4), 16).to_s # #=> "-0.999999999999999999999999999999856613163740061349e0" # def cos(x, prec) raise ArgumentError, "Zero or negative precision for cos" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") two = BigDecimal("2") x = -x if x < 0 if x > (twopi = two * BigMath.PI(prec)) if x > 30 x %= twopi else x -= twopi while x > twopi end end x1 = one x2 = x.mult(x,n) sign = 1 y = one d = y i = BigDecimal("0") z = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig sign = -sign x1 = x2.mult(x1,n) i += two z *= (i-one) * i d = sign * x1.div(z,m) y += d end y end # call-seq: # atan(decimal, numeric) -> BigDecimal # # Computes the arctangent of +decimal+ to the specified number of digits of # precision, +numeric+. # # If +decimal+ is NaN, returns NaN. # # BigMath.atan(BigDecimal('-1'), 16).to_s # #=> "-0.785398163397448309615660845819878471907514682065e0" # def atan(x, prec) raise ArgumentError, "Zero or negative precision for atan" if prec <= 0 return BigDecimal("NaN") if x.nan? pi = PI(prec) x = -x if neg = x < 0 return pi.div(neg ? -2 : 2, prec) if x.infinite? return pi / (neg ? -4 : 4) if x.round(prec) == 1 x = BigDecimal("1").div(x, prec) if inv = x > 1 x = (-1 + sqrt(1 + x**2, prec))/x if dbl = x > 0.5 n = prec + BigDecimal.double_fig y = x d = y t = x r = BigDecimal("3") x2 = x.mult(x,n) while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = -t.mult(x2,n) d = t.div(r,m) y += d r += 2 end y *= 2 if dbl y = pi / 2 - y if inv y = -y if neg y end # call-seq: # PI(numeric) -> BigDecimal # # Computes the value of pi to the specified number of digits of precision, # +numeric+. # # BigMath.PI(10).to_s # #=> "0.3141592653589793238462643388813853786957412e1" # def PI(prec) raise ArgumentError, "Zero or negative precision for PI" if prec <= 0 n = prec + BigDecimal.double_fig zero = BigDecimal("0") one = BigDecimal("1") two = BigDecimal("2") m25 = BigDecimal("-0.04") m57121 = BigDecimal("-57121") pi = zero d = one k = one t = BigDecimal("-80") while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = t*m25 d = t.div(k,m) k = k+two pi = pi + d end d = one k = one t = BigDecimal("956") while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = t.div(m57121,n) d = t.div(k,m) pi = pi + d k = k+two end pi end # call-seq: # E(numeric) -> BigDecimal # # Computes e (the base of natural logarithms) to the specified number of # digits of precision, +numeric+. # # BigMath.E(10).to_s # #=> "0.271828182845904523536028752390026306410273e1" # def E(prec) raise ArgumentError, "Zero or negative precision for E" if prec <= 0 BigMath.exp(1, prec) end end PKu]; <]]+bigdecimal-2.0.0/lib/bigdecimal/jacobian.rbnu[# frozen_string_literal: false require 'bigdecimal' # require 'bigdecimal/jacobian' # # Provides methods to compute the Jacobian matrix of a set of equations at a # point x. In the methods below: # # f is an Object which is used to compute the Jacobian matrix of the equations. # It must provide the following methods: # # f.values(x):: returns the values of all functions at x # # f.zero:: returns 0.0 # f.one:: returns 1.0 # f.two:: returns 2.0 # f.ten:: returns 10.0 # # f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. # # x is the point at which to compute the Jacobian. # # fx is f.values(x). # module Jacobian module_function # Determines the equality of two numbers by comparing to zero, or using the epsilon value def isEqual(a,b,zero=0.0,e=1.0e-8) aa = a.abs bb = b.abs if aa == zero && bb == zero then true else if ((a-b)/(aa+bb)).abs < e then true else false end end end # Computes the derivative of f[i] at x[i]. # fx is the value of f at x. def dfdxi(f,fx,x,i) nRetry = 0 n = x.size xSave = x[i] ok = 0 ratio = f.ten*f.ten*f.ten dx = x[i].abs/ratio dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps) dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps) until ok>0 do deriv = [] nRetry += 1 if nRetry > 100 raise "Singular Jacobian matrix. No change at x[" + i.to_s + "]" end dx = dx*f.two x[i] += dx fxNew = f.values(x) for j in 0...n do if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then ok += 1 deriv <<= (fxNew[j]-fx[j])/dx else deriv <<= f.zero end end x[i] = xSave end deriv end # Computes the Jacobian of f at x. fx is the value of f at x. def jacobian(f,fx,x) n = x.size dfdx = Array.new(n*n) for i in 0...n do df = dfdxi(f,fx,x,i) for j in 0...n do dfdx[j*n+i] = df[j] end end dfdx end end PKu]ь)bigdecimal-2.0.0/lib/bigdecimal/ludcmp.rbnu[# frozen_string_literal: false require 'bigdecimal' # # Solves a*x = b for x, using LU decomposition. # module LUSolve module_function # Performs LU decomposition of the n by n matrix a. def ludecomp(a,n,zero=0,one=1) prec = BigDecimal.limit(nil) ps = [] scales = [] for i in 0...n do # pick up largest(abs. val.) element in each row. ps <<= i nrmrow = zero ixn = i*n for j in 0...n do biggst = a[ixn+j].abs nrmrow = biggst if biggst>nrmrow end if nrmrow>zero then scales <<= one.div(nrmrow,prec) else raise "Singular matrix" end end n1 = n - 1 for k in 0...n1 do # Gaussian elimination with partial pivoting. biggst = zero; for i in k...n do size = a[ps[i]*n+k].abs*scales[ps[i]] if size>biggst then biggst = size pividx = i end end raise "Singular matrix" if biggst<=zero if pividx!=k then j = ps[k] ps[k] = ps[pividx] ps[pividx] = j end pivot = a[ps[k]*n+k] for i in (k+1)...n do psin = ps[i]*n a[psin+k] = mult = a[psin+k].div(pivot,prec) if mult!=zero then pskn = ps[k]*n for j in (k+1)...n do a[psin+j] -= mult.mult(a[pskn+j],prec) end end end end raise "Singular matrix" if a[ps[n1]*n+n1] == zero ps end # Solves a*x = b for x, using LU decomposition. # # a is a matrix, b is a constant vector, x is the solution vector. # # ps is the pivot, a vector which indicates the permutation of rows performed # during LU decomposition. def lusolve(a,b,ps,zero=0.0) prec = BigDecimal.limit(nil) n = ps.size x = [] for i in 0...n do dot = zero psin = ps[i]*n for j in 0...i do dot = a[psin+j].mult(x[j],prec) + dot end x <<= b[ps[i]] - dot end (n-1).downto(0) do |i| dot = zero psin = ps[i]*n for j in (i+1)...n do dot = a[psin+j].mult(x[j],prec) + dot end x[i] = (x[i]-dot).div(a[psin+i],prec) end x end end PKu]h"AZZ)bigdecimal-2.0.0/lib/bigdecimal/newton.rbnu[# frozen_string_literal: false require "bigdecimal/ludcmp" require "bigdecimal/jacobian" # # newton.rb # # Solves the nonlinear algebraic equation system f = 0 by Newton's method. # This program is not dependent on BigDecimal. # # To call: # n = nlsolve(f,x) # where n is the number of iterations required, # x is the initial value vector # f is an Object which is used to compute the values of the equations to be solved. # It must provide the following methods: # # f.values(x):: returns the values of all functions at x # # f.zero:: returns 0.0 # f.one:: returns 1.0 # f.two:: returns 2.0 # f.ten:: returns 10.0 # # f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. # # On exit, x is the solution vector. # module Newton include LUSolve include Jacobian module_function def norm(fv,zero=0.0) # :nodoc: s = zero n = fv.size for i in 0...n do s += fv[i]*fv[i] end s end # See also Newton def nlsolve(f,x) nRetry = 0 n = x.size f0 = f.values(x) zero = f.zero one = f.one two = f.two p5 = one/two d = norm(f0,zero) minfact = f.ten*f.ten*f.ten minfact = one/minfact e = f.eps while d >= e do nRetry += 1 # Not yet converged. => Compute Jacobian matrix dfdx = jacobian(f,f0,x) # Solve dfdx*dx = -f0 to estimate dx dx = lusolve(dfdx,f0,ludecomp(dfdx,n,zero,one),zero) fact = two xs = x.dup begin fact *= p5 if fact < minfact then raise "Failed to reduce function values." end for i in 0...n do x[i] = xs[i] - dx[i]*fact end f0 = f.values(x) dn = norm(f0,zero) end while(dn>=d) d = dn end nRetry end end PKu]< 'bigdecimal-2.0.0/lib/bigdecimal/util.rbnu[# frozen_string_literal: false # #-- # bigdecimal/util extends various native classes to provide the #to_d method, # and provides BigDecimal#to_d and BigDecimal#to_digits. #++ require 'bigdecimal' class Integer < Numeric # call-seq: # int.to_d -> bigdecimal # # Returns the value of +int+ as a BigDecimal. # # require 'bigdecimal' # require 'bigdecimal/util' # # 42.to_d # => 0.42e2 # # See also BigDecimal::new. # def to_d BigDecimal(self) end end class Float < Numeric # call-seq: # float.to_d -> bigdecimal # float.to_d(precision) -> bigdecimal # # Returns the value of +float+ as a BigDecimal. # The +precision+ parameter is used to determine the number of # significant digits for the result (the default is Float::DIG). # # require 'bigdecimal' # require 'bigdecimal/util' # # 0.5.to_d # => 0.5e0 # 1.234.to_d(2) # => 0.12e1 # # See also BigDecimal::new. # def to_d(precision=Float::DIG) BigDecimal(self, precision) end end class String # call-seq: # str.to_d -> bigdecimal # # Returns the result of interpreting leading characters in +str+ # as a BigDecimal. # # require 'bigdecimal' # require 'bigdecimal/util' # # "0.5".to_d # => 0.5e0 # "123.45e1".to_d # => 0.12345e4 # "45.67 degrees".to_d # => 0.4567e2 # # See also BigDecimal::new. # def to_d BigDecimal.interpret_loosely(self) end end class BigDecimal < Numeric # call-seq: # a.to_digits -> string # # Converts a BigDecimal to a String of the form "nnnnnn.mmm". # This method is deprecated; use BigDecimal#to_s("F") instead. # # require 'bigdecimal/util' # # d = BigDecimal("3.14") # d.to_digits # => "3.14" # def to_digits if self.nan? || self.infinite? || self.zero? self.to_s else i = self.to_i.to_s _,f,_,z = self.frac.split i + "." + ("0"*(-z)) + f end end # call-seq: # a.to_d -> bigdecimal # # Returns self. # # require 'bigdecimal/util' # # d = BigDecimal("3.14") # d.to_d # => 0.314e1 # def to_d self end end class Rational < Numeric # call-seq: # rat.to_d(precision) -> bigdecimal # # Returns the value as a BigDecimal. # # The required +precision+ parameter is used to determine the number of # significant digits for the result. # # require 'bigdecimal' # require 'bigdecimal/util' # # Rational(22, 7).to_d(3) # => 0.314e1 # # See also BigDecimal::new. # def to_d(precision) BigDecimal(self, precision) end end class NilClass # call-seq: # nil.to_d -> bigdecimal # # Returns nil represented as a BigDecimal. # # require 'bigdecimal' # require 'bigdecimal/util' # # nil.to_d # => 0.0 # def to_d BigDecimal(0) end end PKu]Wrake-13.0.1/MIT-LICENSEnu[Copyright (c) Jim Weirich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PKu]/Irake-13.0.1/Gemfilenu[source "https://rubygems.org" gemspec group :development do gem "bundler" gem "minitest" gem "coveralls" gem "rubocop" end PKu]Irake-13.0.1/exe/rakenuȯ#!/usr/bin/ruby #-- # Copyright (c) 2003, 2004, 2005, 2006, 2007 Jim Weirich # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. #++ require "rake" Rake.application.run PKu]VQOrake-13.0.1/Rakefilenu[# Rakefile for rake -*- ruby -*- # Copyright 2003, 2004, 2005 by Jim Weirich (jim@weirichhouse.org) # All rights reserved. # This file may be distributed under an MIT style license. See # MIT-LICENSE for details. lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) begin require "bundler/gem_tasks" rescue LoadError end require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.verbose = true t.test_files = FileList["test/**/test_*.rb"] end require "rdoc/task" RDoc::Task.new do |doc| doc.main = "README.rdoc" doc.title = "Rake -- Ruby Make" doc.rdoc_files = FileList.new %w[lib MIT-LICENSE doc/**/*.rdoc *.rdoc] doc.rdoc_dir = "html" end task ghpages: :rdoc do %x[git checkout gh-pages] require "fileutils" FileUtils.rm_rf "/tmp/html" FileUtils.mv "html", "/tmp" FileUtils.rm_rf "*" FileUtils.cp_r Dir.glob("/tmp/html/*"), "." end task default: :test PKu]orake-13.0.1/README.rdocnu[= RAKE -- Ruby Make home :: https://github.com/ruby/rake bugs :: https://github.com/ruby/rake/issues docs :: https://ruby.github.io/rake == Description Rake is a Make-like program implemented in Ruby. Tasks and dependencies are specified in standard Ruby syntax. Rake has the following features: * Rakefiles (rake's version of Makefiles) are completely defined in standard Ruby syntax. No XML files to edit. No quirky Makefile syntax to worry about (is that a tab or a space?) * Users can specify tasks with prerequisites. * Rake supports rule patterns to synthesize implicit tasks. * Flexible FileLists that act like arrays but know about manipulating file names and paths. * A library of prepackaged tasks to make building rakefiles easier. For example, tasks for building tarballs. (Formerly tasks for building RDoc, Gems, and publishing to FTP were included in rake but they're now available in RDoc, RubyGems, and rake-contrib respectively.) * Supports parallel execution of tasks. == Installation === Gem Installation Download and install rake with the following. gem install rake == Usage === Simple Example First, you must write a "Rakefile" file which contains the build rules. Here's a simple example: task default: %w[test] task :test do ruby "test/unittest.rb" end This Rakefile has two tasks: * A task named "test", which -- upon invocation -- will run a unit test file in Ruby. * A task named "default". This task does nothing by itself, but it has exactly one dependency, namely the "test" task. Invoking the "default" task will cause Rake to invoke the "test" task as well. Running the "rake" command without any options will cause it to run the "default" task in the Rakefile: % ls Rakefile test/ % rake (in /home/some_user/Projects/rake) ruby test/unittest.rb ....unit test output here... Type "rake --help" for all available options. == Resources === Rake Information * {Rake command-line}[link:doc/command_line_usage.rdoc] * {Writing Rakefiles}[link:doc/rakefile.rdoc] * The original {Rake announcement}[link:doc/rational.rdoc] * Rake {glossary}[link:doc/glossary.rdoc] === Presentations and Articles about Rake * Avdi Grimm's rake series: 1. {Rake Basics}[http://devblog.avdi.org/2014/04/21/rake-part-1-basics/] 2. {Rake File Lists}[http://devblog.avdi.org/2014/04/22/rake-part-2-file-lists/] 3. {Rake Rules}[http://devblog.avdi.org/2014/04/23/rake-part-3-rules/] 4. {Rake Pathmap}[http://devblog.avdi.org/2014/04/24/rake-part-4-pathmap/] 5. {File Operations}[http://devblog.avdi.org/2014/04/25/rake-part-5-file-operations/] 6. {Clean and Clobber}[http://devblog.avdi.org/2014/04/28/rake-part-6-clean-and-clobber/] 7. {MultiTask}[http://devblog.avdi.org/2014/04/29/rake-part-7-multitask/] * {Jim Weirich's 2003 RubyConf presentation}[http://web.archive.org/web/20140221123354/http://onestepback.org/articles/buildingwithrake/] * Martin Fowler's article on Rake: http://martinfowler.com/articles/rake.html == Other Make Re-envisionings ... Rake is a late entry in the make replacement field. Here are links to other projects with similar (and not so similar) goals. * http://directory.fsf.org/wiki/Bras -- Bras, one of earliest implementations of "make in a scripting language". * http://www.a-a-p.org -- Make in Python * http://ant.apache.org -- The Ant project * http://search.cpan.org/search?query=PerlBuildSystem -- The Perl Build System * http://www.rubydoc.info/gems/rant/0.5.7/frames -- Rant, another Ruby make tool. == Credits [Jim Weirich] Who originally created Rake. [Ryan Dlugosz] For the initial conversation that sparked Rake. [Nobuyoshi Nakada ] For the initial patch for rule support. [Tilman Sauerbeck ] For the recursive rule patch. [Eric Hodel] For aid in maintaining rake. [Hiroshi SHIBATA] Maintainer of Rake 10.X and Rake 11.X == License Rake is available under an MIT-style license. :include: MIT-LICENSE --- = Other stuff Author:: Jim Weirich Requires:: Ruby 2.0.0 or later License:: Copyright Jim Weirich. Released under an MIT-style license. See the MIT-LICENSE file included in the distribution. == Warranty This software is provided "as is" and without any express or implied warranties, including, without limitation, the implied warranties of merchantability and fitness for a particular purpose. == Historical Rake was originally created by Jim Weirich, who unfortunately passed away in February 2014. This repository was originally hosted at {github.com/jimweirich/rake}[https://github.com/jimweirich/rake/], however with his passing, has been moved to {ruby/rake}[https://github.com/ruby/rake]. You can view Jim's last commit here: https://github.com/jimweirich/rake/tree/336559f28f55bce418e2ebcc0a57548dcbac4025 You can {read more about Jim}[https://en.wikipedia.org/wiki/Jim_Weirich] at Wikipedia. Thank you for this great tool, Jim. We'll remember you. PKu]vrake-13.0.1/rake.gemspecnu[# -*- encoding: utf-8 -*- # stub: rake 13.0.1 ruby lib Gem::Specification.new do |s| s.name = "rake".freeze s.version = "13.0.1" s.required_rubygems_version = Gem::Requirement.new(">= 1.3.2".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "bug_tracker_uri" => "https://github.com/ruby/rake/issues", "changelog_uri" => "https://github.com/ruby/rake/blob/v13.0.1/History.rdoc", "documentation_uri" => "https://ruby.github.io/rake", "source_code_uri" => "https://github.com/ruby/rake/tree/v13.0.1" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Hiroshi SHIBATA".freeze, "Eric Hodel".freeze, "Jim Weirich".freeze] s.bindir = "exe".freeze s.date = "2019-11-12" s.description = "Rake is a Make-like program implemented in Ruby. Tasks and dependencies are\nspecified in standard Ruby syntax.\nRake has the following features:\n * Rakefiles (rake's version of Makefiles) are completely defined in standard Ruby syntax.\n No XML files to edit. No quirky Makefile syntax to worry about (is that a tab or a space?)\n * Users can specify tasks with prerequisites.\n * Rake supports rule patterns to synthesize implicit tasks.\n * Flexible FileLists that act like arrays but know about manipulating file names and paths.\n * Supports parallel execution of tasks.\n".freeze s.email = ["hsbt@ruby-lang.org".freeze, "drbrain@segment7.net".freeze, "".freeze] s.executables = ["rake".freeze] s.files = [".github/workflows/macos.yml".freeze, ".github/workflows/ubuntu-rvm.yml".freeze, ".github/workflows/ubuntu.yml".freeze, ".github/workflows/windows.yml".freeze, "CONTRIBUTING.rdoc".freeze, "Gemfile".freeze, "History.rdoc".freeze, "MIT-LICENSE".freeze, "README.rdoc".freeze, "Rakefile".freeze, "bin/bundle".freeze, "bin/console".freeze, "bin/rake".freeze, "bin/rdoc".freeze, "bin/rubocop".freeze, "bin/setup".freeze, "doc/command_line_usage.rdoc".freeze, "doc/example/Rakefile1".freeze, "doc/example/Rakefile2".freeze, "doc/example/a.c".freeze, "doc/example/b.c".freeze, "doc/example/main.c".freeze, "doc/glossary.rdoc".freeze, "doc/jamis.rb".freeze, "doc/proto_rake.rdoc".freeze, "doc/rake.1".freeze, "doc/rakefile.rdoc".freeze, "doc/rational.rdoc".freeze, "exe/rake".freeze, "lib/rake.rb".freeze, "lib/rake/application.rb".freeze, "lib/rake/backtrace.rb".freeze, "lib/rake/clean.rb".freeze, "lib/rake/cloneable.rb".freeze, "lib/rake/cpu_counter.rb".freeze, "lib/rake/default_loader.rb".freeze, "lib/rake/dsl_definition.rb".freeze, "lib/rake/early_time.rb".freeze, "lib/rake/ext/core.rb".freeze, "lib/rake/ext/string.rb".freeze, "lib/rake/file_creation_task.rb".freeze, "lib/rake/file_list.rb".freeze, "lib/rake/file_task.rb".freeze, "lib/rake/file_utils.rb".freeze, "lib/rake/file_utils_ext.rb".freeze, "lib/rake/invocation_chain.rb".freeze, "lib/rake/invocation_exception_mixin.rb".freeze, "lib/rake/late_time.rb".freeze, "lib/rake/linked_list.rb".freeze, "lib/rake/loaders/makefile.rb".freeze, "lib/rake/multi_task.rb".freeze, "lib/rake/name_space.rb".freeze, "lib/rake/packagetask.rb".freeze, "lib/rake/phony.rb".freeze, "lib/rake/private_reader.rb".freeze, "lib/rake/promise.rb".freeze, "lib/rake/pseudo_status.rb".freeze, "lib/rake/rake_module.rb".freeze, "lib/rake/rake_test_loader.rb".freeze, "lib/rake/rule_recursion_overflow_error.rb".freeze, "lib/rake/scope.rb".freeze, "lib/rake/task.rb".freeze, "lib/rake/task_argument_error.rb".freeze, "lib/rake/task_arguments.rb".freeze, "lib/rake/task_manager.rb".freeze, "lib/rake/tasklib.rb".freeze, "lib/rake/testtask.rb".freeze, "lib/rake/thread_history_display.rb".freeze, "lib/rake/thread_pool.rb".freeze, "lib/rake/trace_output.rb".freeze, "lib/rake/version.rb".freeze, "lib/rake/win32.rb".freeze, "rake.gemspec".freeze] s.homepage = "https://github.com/ruby/rake".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.2".freeze) s.rubygems_version = "3.3.5".freeze s.summary = "Rake is a Make-like program implemented in Ruby".freeze end PKu]?qFF'rake-13.0.1/doc/command_line_usage.rdocnu[= Rake Command Line Usage Rake is invoked from the command line using: % rake [options ...] [VAR=VALUE ...] [targets ...] Options are: [name=value] Set the environment variable name to value during the execution of the rake command. You can access the value by using ENV['name']. [--all (-A)] Used in combination with the -T and -D options, will force those options to show all the tasks, even the ones without comments. [--backtrace{=_output_} (-n)] Enable a full backtrace (i.e. like --trace, but without the task tracing details). The _output_ parameter is optional, but if specified it controls where the backtrace output is sent. If _output_ is stdout, then backtrace output is directed to standard output. If _output_ is stderr, or if it is missing, then the backtrace output is sent to standard error. [--comments] Used in combination with the -W options to force the output to contain commented options only. This is the reverse of --all. [--describe _pattern_ (-D)] Describe the tasks (matching optional PATTERN), then exit. [--dry-run (-n)] Do a dry run. Print the tasks invoked and executed, but do not actually execute any of the actions. [--execute _code_ (-e)] Execute some Ruby code and exit. [--execute-print _code_ (-p)] Execute some Ruby code, print the result, and exit. [--execute-continue _code_ (-E)] Execute some Ruby code, then continue with normal task processing. [--help (-H)] Display some help text and exit. [--jobs _number_ (-j)] Specifies the maximum number of concurrent threads allowed. Rake will allocate threads as needed up to this maximum number. If omitted, Rake will attempt to estimate the number of CPUs on the system and add 4 to that number. The concurrent threads are used to execute the multitask prerequisites. Also see the -m option which turns all tasks into multitasks. Sample values: (no -j) : Allow up to (# of CPUs + 4) number of threads --jobs : Allow unlimited number of threads --jobs=1 : Allow only one thread (the main thread) --jobs=16 : Allow up to 16 concurrent threads [--job-stats _level_] Display job statistics at the completion of the run. By default, this will display the requested number of active threads (from the -j options) and the maximum number of threads in play at any given time. If the optional _level_ is history, then a complete trace of task history will be displayed on standard output. [--libdir _directory_ (-I)] Add _directory_ to the list of directories searched for require. [--multitask (-m)] Treat all tasks as multitasks. ('make/drake' semantics) [--nosearch (-N)] Do not search for a Rakefile in parent directories. [--prereqs (-P)] Display a list of all tasks and their immediate prerequisites. [--quiet (-q)] Do not echo commands from FileUtils. [--rakefile _filename_ (-f)] Use _filename_ as the name of the rakefile. The default rakefile names are +rakefile+ and +Rakefile+ (with +rakefile+ taking precedence). If the rakefile is not found in the current directory, +rake+ will search parent directories for a match. The directory where the Rakefile is found will become the current directory for the actions executed in the Rakefile. [--rakelibdir _rakelibdir_ (-R)] Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib') [--require _name_ (-r)] Require _name_ before executing the Rakefile. [--rules] Trace the rules resolution. [--silent (-s)] Like --quiet, but also suppresses the 'in directory' announcement. [--suppress-backtrace _pattern_ ] Line matching the regular expression _pattern_ will be removed from the backtrace output. Note that the --backtrace option is the full backtrace without these lines suppressed. [--system (-g)] Use the system wide (global) rakefiles. The project Rakefile is ignored. By default, the system wide rakefiles are used only if no project Rakefile is found. On Unix-like system, the system wide rake files are located in $HOME/.rake. On a windows system they are stored in $APPDATA/Rake. [--no-system (-G)] Use the project level Rakefile, ignoring the system-wide (global) rakefiles. [--tasks pattern (-T)] Display a list of the major tasks and their comments. Comments are defined using the "desc" command. If a pattern is given, then only tasks matching the pattern are displayed. [--trace{=_output_} (-t)] Turn on invoke/execute tracing. Also enable full backtrace on errors. The _output_ parameter is optional, but if specified it controls where the trace output is sent. If _output_ is stdout, then trace output is directed to standard output. If _output_ is stderr, or if it is missing, then trace output is sent to standard error. [--verbose (-v)] Echo the Sys commands to standard output. [--version (-V)] Display the program version and exit. [--where pattern (-W)] Display tasks that match pattern and the file and line number where the task is defined. By default this option will display all tasks, not just the tasks that have descriptions. [--no-deprecation-warnings (-X)] Do not display the deprecation warnings. In addition, any command line option of the form VAR=VALUE will be added to the environment hash ENV and may be tested in the Rakefile. PKu]@u,u,rake-13.0.1/doc/jamis.rbnu[# frozen_string_literal: true module RDoc module Page FONTS = "\"Bitstream Vera Sans\", Verdana, Arial, Helvetica, sans-serif" STYLE = < pre { padding: 0.5em; border: 1px dotted black; background: #FFE; } CSS XHTML_PREAMBLE = %{ } HEADER = XHTML_PREAMBLE + < %title% ENDHEADER FILE_PAGE = <
    File
    %short_name%
    Path: %full_path% IF:cvsurl  (CVS) ENDIF:cvsurl
    Modified: %dtm_modified%

    HTML ################################################################### CLASS_PAGE = < %classmod%
    %full_name% IF:parent ENDIF:parent
    In: START:infiles HREF:full_path_url:full_path: IF:cvsurl  (CVS) ENDIF:cvsurl END:infiles
    Parent: IF:par_url ENDIF:par_url %parent% IF:par_url ENDIF:par_url
    HTML ################################################################### METHOD_LIST = < IF:diagram
    %diagram%
    ENDIF:diagram IF:description
    %description%
    ENDIF:description IF:requires
    Required Files
      START:requires
    • HREF:aref:name:
    • END:requires
    ENDIF:requires IF:toc
    Contents
    ENDIF:toc IF:methods
    Methods
      START:methods
    • HREF:aref:name:
    • END:methods
    ENDIF:methods IF:includes
    Included Modules
      START:includes
    • HREF:aref:name:
    • END:includes
    ENDIF:includes START:sections IF:sectitle IF:seccomment
    %seccomment%
    ENDIF:seccomment ENDIF:sectitle IF:classlist
    Classes and Modules
    %classlist% ENDIF:classlist IF:constants
    Constants
    START:constants IF:desc ENDIF:desc END:constants
    %name% = %value%
      %desc%
    ENDIF:constants IF:attributes
    Attributes
    START:attributes END:attributes
    IF:rw [%rw%] ENDIF:rw %name% %a_desc%
    ENDIF:attributes IF:method_list START:method_list IF:methods
    %type% %category% methods
    START:methods
    IF:callseq %callseq% ENDIF:callseq IFNOT:callseq %name%%params% ENDIF:callseq IF:codeurl [ source ] ENDIF:codeurl
    IF:m_desc
    %m_desc%
    ENDIF:m_desc IF:aka
    This method is also aliased as START:aka %name% END:aka
    ENDIF:aka IF:sourcecode
    %sourcecode%
    
    ENDIF:sourcecode
    END:methods ENDIF:methods END:method_list ENDIF:method_list END:sections HTML FOOTER = < ENDFOOTER BODY = HEADER + <
    #{METHOD_LIST}
    #{FOOTER} ENDBODY ########################## Source code ########################## SRC_PAGE = XHTML_PREAMBLE + < %title%
    %code%
    HTML ########################## Index ################################ FR_INDEX_BODY = <
    START:entries %name%
    END:entries
    HTML CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = XHTML_PREAMBLE + < %title% IF:inline_source ENDIF:inline_source IFNOT:inline_source ENDIF:inline_source <body bgcolor="white"> Click <a href="html/index.html">here</a> for a non-frames version of this page. </body> HTML end end PKu]Oq AArake-13.0.1/doc/example/a.cnu[#include void a() { printf ("In function a\n"); } PKu]۸ !rake-13.0.1/doc/example/Rakefile1nu[# Example Rakefile -*- ruby -*- task :default => [:main] file "a.o" => ["a.c"] do |t| src = t.name.sub(/\.o$/, '.c') sh "gcc #{src} -c -o #{t.name}" end file "b.o" => ["b.c"] do |t| src = t.name.sub(/\.o$/, '.c') sh "gcc #{src} -c -o #{t.name}" end file "main.o" => ["main.c"] do |t| src = t.name.sub(/\.o$/, '.c') sh "gcc #{src} -c -o #{t.name}" end OBJFILES = ["a.o", "b.o", "main.o"] task :obj => OBJFILES file "main" => OBJFILES do |t| sh "gcc -o #{t.name} main.o a.o b.o" end task :clean do rm_f FileList['*.o'] Dir['*~'].each { |fn| rm_f fn } end task :clobber => [:clean] do rm_f "main" end task :run => ["main"] do sh "./main" end PKu]AArake-13.0.1/doc/example/b.cnu[#include void b() { printf ("In function b\n"); } PKu]";WW!rake-13.0.1/doc/example/Rakefile2nu[# Example Rakefile -*- ruby -*- # Using the power of Ruby task :default => [:main] def ext(fn, newext) fn.sub(/\.[^.]+$/, newext) end SRCFILES = Dir['*.c'] OBJFILES = SRCFILES.collect { |fn| ext(fn,".o") } OBJFILES.each do |objfile| srcfile = ext(objfile, ".c") file objfile => [srcfile] do |t| sh "gcc #{srcfile} -c -o #{t.name}" end end file "main" => OBJFILES do |t| sh "gcc -o #{t.name} main.o a.o b.o" end task :clean do rm_f FileList['*.o'] Dir['*~'].each { |fn| rm_f fn } end task :clobber => [:clean] do rm_f "main" end task :run => ["main"] do sh "./main" end PKu]_bggrake-13.0.1/doc/example/main.cnu[#include extern void a(); extern void b(); int main () { a(); b(); return 0; } PKu]PPrake-13.0.1/doc/rakefile.rdocnu[= Rakefile Format First of all, there is no special format for a Rakefile. A Rakefile contains executable Ruby code. Anything legal in a ruby script is allowed in a Rakefile. Now that we understand there is no special syntax in a Rakefile, there are some conventions that are used in a Rakefile that are a little unusual in a typical Ruby program. Since a Rakefile is tailored to specifying tasks and actions, the idioms used in a Rakefile are designed to support that. So, what goes into a Rakefile? == Tasks Tasks are the main unit of work in a Rakefile. Tasks have a name (usually given as a symbol or a string), a list of prerequisites (more symbols or strings) and a list of actions (given as a block). === Simple Tasks A task is declared by using the +task+ method. +task+ takes a single parameter that is the name of the task. task :name === Tasks with Prerequisites Any prerequisites are given as a list (enclosed in square brackets) following the name and an arrow (=>). task name: [:prereq1, :prereq2] *NOTE:* Although this syntax looks a little funky, it is legal Ruby. We are constructing a hash where the key is :name and the value for that key is the list of prerequisites. It is equivalent to the following ... hash = Hash.new hash[:name] = [:prereq1, :prereq2] task(hash) You can also use strings for task names and prerequisites, rake doesn't care. This is the same task definition: task 'name' => %w[prereq1 prereq2] As is this: task name: %w[prereq1 prereq2] We'll prefer this style for regular tasks with prerequisites throughout the rest of the document. Using an array of strings for the prerequisites means you will need to make fewer changes if you need to move tasks into namespaces or perform other refactorings. === Tasks with Actions Actions are defined by passing a block to the +task+ method. Any Ruby code can be placed in the block. The block may reference the task object via the block parameter. task name: [:prereq1, :prereq2] do |t| # actions (may reference t) end === Multiple Definitions A task may be specified more than once. Each specification adds its prerequisites and actions to the existing definition. This allows one part of a rakefile to specify the actions and a different rakefile (perhaps separately generated) to specify the dependencies. For example, the following is equivalent to the single task specification given above. task :name task name: :prereq1 task name: %w[prereq2] task :name do |t| # actions end == File Tasks Some tasks are designed to create a file from one or more other files. Tasks that generate these files may be skipped if the file already exists. File tasks are used to specify file creation tasks. File tasks are declared using the +file+ method (instead of the +task+ method). In addition, file tasks are usually named with a string rather than a symbol. The following file task creates a executable program (named +prog+) given two object files named +a.o+ and +b.o+. The tasks for creating +a.o+ and +b.o+ are not shown. file "prog" => ["a.o", "b.o"] do |t| sh "cc -o #{t.name} #{t.prerequisites.join(' ')}" end == Directory Tasks It is common to need to create directories upon demand. The +directory+ convenience method is a short-hand for creating a FileTask that creates the directory. For example, the following declaration ... directory "testdata/examples/doc" is equivalent to ... file "testdata" do |t| mkdir t.name end file "testdata/examples" => ["testdata"] do |t| mkdir t.name end file "testdata/examples/doc" => ["testdata/examples"] do |t| mkdir t.name end The +directory+ method does not accept prerequisites or actions, but both prerequisites and actions can be added later. For example ... directory "testdata" file "testdata" => ["otherdata"] file "testdata" do cp Dir["standard_data/*.data"], "testdata" end == Tasks with Parallel Prerequisites Rake allows parallel execution of prerequisites using the following syntax: multitask copy_files: %w[copy_src copy_doc copy_bin] do puts "All Copies Complete" end In this example, +copy_files+ is a normal rake task. Its actions are executed whenever all of its prerequisites are done. The big difference is that the prerequisites (+copy_src+, +copy_bin+ and +copy_doc+) are executed in parallel. Each of the prerequisites are run in their own Ruby thread, possibly allowing faster overall runtime. === Secondary Prerequisites If any of the primary prerequisites of a multitask have common secondary prerequisites, all of the primary/parallel prerequisites will wait until the common prerequisites have been run. For example, if the copy_xxx tasks have the following prerequisites: task copy_src: :prep_for_copy task copy_bin: :prep_for_copy task copy_doc: :prep_for_copy Then the +prep_for_copy+ task is run before starting all the copies in parallel. Once +prep_for_copy+ is complete, +copy_src+, +copy_bin+, and +copy_doc+ are all run in parallel. Note that +prep_for_copy+ is run only once, even though it is referenced in multiple threads. === Thread Safety The Rake internal data structures are thread-safe with respect to the multitask parallel execution, so there is no need for the user to do extra synchronization for Rake's benefit. However, if there are user data structures shared between the parallel prerequisites, the user must do whatever is necessary to prevent race conditions. == Tasks with Arguments Prior to version 0.8.0, rake was only able to handle command line arguments of the form NAME=VALUE that were passed into Rake via the ENV hash. Many folks had asked for some kind of simple command line arguments, perhaps using "--" to separate regular task names from argument values on the command line. The problem is that there was no easy way to associate positional arguments on the command line with different tasks. Suppose both tasks :a and :b expect a command line argument: does the first value go with :a? What if :b is run first? Should it then get the first command line argument. Rake 0.8.0 solves this problem by explicitly passing values directly to the tasks that need them. For example, if I had a release task that required a version number, I could say: rake release[0.8.2] And the string "0.8.2" will be passed to the :release task. Multiple arguments can be passed by separating them with a comma, for example: rake name[john,doe] Just a few words of caution. The rake task name and its arguments need to be a single command line argument to rake. This generally means no spaces. If spaces are needed, then the entire name + argument string should be quoted. Something like this: rake "name[billy bob, smith]" (Quoting rules vary between operating systems and shells, so make sure you consult the proper docs for your OS/shell). === Tasks that Expect Parameters Parameters are only given to tasks that are setup to expect them. In order to handle named parameters, the task declaration syntax for tasks has been extended slightly. For example, a task that needs a first name and last name might be declared as: task :name, [:first_name, :last_name] The first argument is still the name of the task (:name in this case). The next two arguments are the names of the parameters expected by :name in an array (:first_name and :last_name in the example). To access the values of the parameters, the block defining the task behaviour can now accept a second parameter: task :name, [:first_name, :last_name] do |t, args| puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end The first argument of the block "t" is always bound to the current task object. The second argument "args" is an open-struct like object that allows access to the task arguments. Extra command line arguments to a task are ignored. If you wish to specify default values for the arguments, you can use the with_defaults method in the task body. Here is the above example where we specify default values for the first and last names: task :name, [:first_name, :last_name] do |t, args| args.with_defaults(:first_name => "John", :last_name => "Dough") puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end === Tasks that Expect Parameters and Have Prerequisites Tasks that use parameters have a slightly different format for prerequisites. Use the arrow notation to indicate the prerequisites for tasks with arguments. For example: task :name, [:first_name, :last_name] => [:pre_name] do |t, args| args.with_defaults(:first_name => "John", :last_name => "Dough") puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end === Tasks that take Variable-length Parameters Tasks that need to handle a list of values as a parameter can use the extras method of the args variable. This allows for tasks that can loop over a variable number of values, and its compatible with named parameters as well: task :email, [:message] do |t, args| mail = Mail.new(args.message) recipients = args.extras recipients.each do |target| mail.send_to(target) end end There is also the convenience method to_a that returns all parameters in the sequential order they were given, including those associated with named parameters. === Deprecated Task Parameters Format There is an older format for declaring task parameters that omitted the task argument array and used the :needs keyword to introduce the dependencies. That format is still supported for compatibility, but is not recommended for use. The older format may be dropped in future versions of rake. == Accessing Task Programmatically Sometimes it is useful to manipulate tasks programmatically in a Rakefile. To find a task object use Rake::Task.[]. === Programmatic Task Example For example, the following Rakefile defines two tasks. The :doit task simply prints a simple "DONE" message. The :dont class will lookup the doit class and remove (clear) all of its prerequisites and actions. task :doit do puts "DONE" end task :dont do Rake::Task[:doit].clear end Running this example: $ rake doit (in /Users/jim/working/git/rake/x) DONE $ rake dont doit (in /Users/jim/working/git/rake/x) $ The ability to programmatically manipulate tasks gives rake very powerful meta-programming capabilities w.r.t. task execution, but should be used with caution. == Rules When a file is named as a prerequisite, but does not have a file task defined for it, Rake will attempt to synthesize a task by looking at a list of rules supplied in the Rakefile. Suppose we were trying to invoke task "mycode.o", but no task is defined for it. But the rakefile has a rule that look like this ... rule '.o' => ['.c'] do |t| sh "cc #{t.source} -c -o #{t.name}" end This rule will synthesize any task that ends in ".o". It has a prerequisite a source file with an extension of ".c" must exist. If Rake is able to find a file named "mycode.c", it will automatically create a task that builds "mycode.o" from "mycode.c". If the file "mycode.c" does not exist, rake will attempt to recursively synthesize a rule for it. When a task is synthesized from a rule, the +source+ attribute of the task is set to the matching source file. This allows us to write rules with actions that reference the source file. === Advanced Rules Any regular expression may be used as the rule pattern. Additionally, a proc may be used to calculate the name of the source file. This allows for complex patterns and sources. The following rule is equivalent to the example above. rule( /\.o$/ => [ proc {|task_name| task_name.sub(/\.[^.]+$/, '.c') } ]) do |t| sh "cc #{t.source} -c -o #{t.name}" end *NOTE:* Because of a _quirk_ in Ruby syntax, parenthesis are required on *rule* when the first argument is a regular expression. The following rule might be used for Java files ... rule '.class' => [ proc { |tn| tn.sub(/\.class$/, '.java').sub(/^classes\//, 'src/') } ] do |t| java_compile(t.source, t.name) end *NOTE:* +java_compile+ is a hypothetical method that invokes the java compiler. == Importing Dependencies Any ruby file (including other rakefiles) can be included with a standard Ruby +require+ command. The rules and declarations in the required file are just added to the definitions already accumulated. Because the files are loaded _before_ the rake targets are evaluated, the loaded files must be "ready to go" when the rake command is invoked. This makes generated dependency files difficult to use. By the time rake gets around to updating the dependencies file, it is too late to load it. The +import+ command addresses this by specifying a file to be loaded _after_ the main rakefile is loaded, but _before_ any targets on the command line are invoked. In addition, if the file name matches an explicit task, that task is invoked before loading the file. This allows dependency files to be generated and used in a single rake command invocation. Example: require 'rake/loaders/makefile' file ".depends.mf" => [SRC_LIST] do |t| sh "makedepend -f- -- #{CFLAGS} -- #{t.prerequisites} > #{t.name}" end import ".depends.mf" If ".depends" does not exist, or is out of date w.r.t. the source files, a new ".depends" file is generated using +makedepend+ before loading. == Comments Standard Ruby comments (beginning with "#") can be used anywhere it is legal in Ruby source code, including comments for tasks and rules. However, if you wish a task to be described using the "-T" switch, then you need to use the +desc+ command to describe the task. Example: desc "Create a distribution package" task package: %w[ ... ] do ... end The "-T" switch (or "--tasks" if you like to spell things out) will display a list of tasks that have a description. If you use +desc+ to describe your major tasks, you have a semi-automatic way of generating a summary of your Rake file. $ rake -T (in /home/.../rake) rake clean # Remove any temporary products. rake clobber # Remove any generated file. rake clobber_rdoc # Remove rdoc products rake contrib_test # Run tests for contrib_test rake default # Default Task rake install # Install the application rake lines # Count lines in the main rake file rake rdoc # Build the rdoc HTML Files rake rerdoc # Force a rebuild of the RDOC files rake test # Run tests rake testall # Run all test targets Only tasks with descriptions will be displayed with the "-T" switch. Use "-P" (or "--prereqs") to get a list of all tasks and their prerequisites. == Namespaces As projects grow (and along with it, the number of tasks), it is common for task names to begin to clash. For example, if you might have a main program and a set of sample programs built by a single Rakefile. By placing the tasks related to the main program in one namespace, and the tasks for building the sample programs in a different namespace, the task names will not interfere with each other. For example: namespace "main" do task :build do # Build the main program end end namespace "samples" do task :build do # Build the sample programs end end task build: %w[main:build samples:build] Referencing a task in a separate namespace can be achieved by prefixing the task name with the namespace and a colon (e.g. "main:build" refers to the :build task in the +main+ namespace). Nested namespaces are supported. Note that the name given in the +task+ command is always the unadorned task name without any namespace prefixes. The +task+ command always defines a task in the current namespace. === FileTasks File task names are not scoped by the namespace command. Since the name of a file task is the name of an actual file in the file system, it makes little sense to include file task names in name space. Directory tasks (created by the +directory+ command) are a type of file task and are also not affected by namespaces. === Name Resolution When looking up a task name, rake will start with the current namespace and attempt to find the name there. If it fails to find a name in the current namespace, it will search the parent namespaces until a match is found (or an error occurs if there is no match). The "rake" namespace is a special implicit namespace that refers to the toplevel names. If a task name begins with a "^" character, the name resolution will start in the parent namespace. Multiple "^" characters are allowed. Here is an example file with multiple :run tasks and how various names resolve in different locations. task :run namespace "one" do task :run namespace "two" do task :run # :run => "one:two:run" # "two:run" => "one:two:run" # "one:two:run" => "one:two:run" # "one:run" => "one:run" # "^run" => "one:run" # "^^run" => "rake:run" (the top level task) # "rake:run" => "rake:run" (the top level task) end # :run => "one:run" # "two:run" => "one:two:run" # "^run" => "rake:run" end # :run => "rake:run" # "one:run" => "one:run" # "one:two:run" => "one:two:run" == FileLists FileLists are the way Rake manages lists of files. You can treat a FileList as an array of strings for the most part, but FileLists support some additional operations. === Creating a FileList Creating a file list is easy. Just give it the list of file names: fl = FileList['file1.rb', file2.rb'] Or give it a glob pattern: fl = FileList['*.rb'] == Odds and Ends === do/end versus { } Blocks may be specified with either a +do+/+end+ pair, or with curly braces in Ruby. We _strongly_ recommend using +do+/+end+ to specify the actions for tasks and rules. Because the rakefile idiom tends to leave off parentheses on the task/file/rule methods, unusual ambiguities can arise when using curly braces. For example, suppose that the method +object_files+ returns a list of object files in a project. Now we use +object_files+ as the prerequisites in a rule specified with actions in curly braces. # DON'T DO THIS! file "prog" => object_files { # Actions are expected here (but it doesn't work)! } Because curly braces have a higher precedence than +do+/+end+, the block is associated with the +object_files+ method rather than the +file+ method. This is the proper way to specify the task ... # THIS IS FINE file "prog" => object_files do # Actions go here end == Rakefile Path When issuing the +rake+ command in a terminal, Rake will look for a Rakefile in the current directory. If a Rakefile is not found, it will search parent directories until one is found. For example, if a Rakefile resides in the +project/+ directory, moving deeper into the project's directory tree will not have an adverse effect on rake tasks: $ pwd /home/user/project $ cd lib/foo/bar $ pwd /home/user/project/lib/foo/bar $ rake run_pwd /home/user/project As far as rake is concerned, all tasks are run from the directory in which the Rakefile resides. === Multiple Rake Files Not all tasks need to be included in a single Rakefile. Additional rake files (with the file extension "+.rake+") may be placed in +rakelib+ directory located at the top level of a project (i.e. the same directory that contains the main +Rakefile+). Also, rails projects may include additional rake files in the +lib/tasks+ directory. === Clean and Clobber Tasks Through require 'rake/clean' Rake provides +clean+ and +clobber+ tasks: +clean+ :: Clean up the project by deleting scratch files and backup files. Add files to the +CLEAN+ FileList to have the +clean+ target handle them. +clobber+ :: Clobber all generated and non-source files in a project. The task depends on +clean+, so all the +CLEAN+ files will be deleted as well as files in the +CLOBBER+ FileList. The intent of this task is to return a project to its pristine, just unpacked state. You can add file names or glob patterns to both the +CLEAN+ and +CLOBBER+ lists. === Phony Task The phony task can be used as a dependency to allow file-based tasks to use non-file-based-tasks as prerequisites without forcing them to rebuild. You can require 'rake/phony' to add the +phony+ task. ---- == See * README.rdoc -- Main documentation for Rake. PKu]) rake-13.0.1/doc/proto_rake.rdocnu[= Original Prototype Rake This is the original 100 line prototype rake program. --- #!/usr/bin/env ruby require 'ftools' class Task TASKS = Hash.new attr_reader :prerequisites def initialize(task_name) @name = task_name @prerequisites = [] @actions = [] end def enhance(deps=nil, &block) @prerequisites |= deps if deps @actions << block if block_given? self end def name @name.to_s end def invoke @prerequisites.each { |n| Task[n].invoke } execute if needed? end def execute return if @triggered @triggered = true @actions.collect { |act| result = act.call(self) }.last end def needed? true end def timestamp Time.now end class << self def [](task_name) TASKS[intern(task_name)] or fail "Don't know how to rake #{task_name}" end def define_task(args, &block) case args when Hash fail "Too Many Target Names: #{args.keys.join(' ')}" if args.size > 1 fail "No Task Name Given" if args.size < 1 task_name = args.keys[0] deps = args[task_name] else task_name = args deps = [] end deps = deps.collect {|d| intern(d) } get(task_name).enhance(deps, &block) end def get(task_name) name = intern(task_name) TASKS[name] ||= self.new(name) end def intern(task_name) (Symbol === task_name) ? task_name : task_name.intern end end end class FileTask < Task def needed? return true unless File.exist?(name) latest_prereq = @prerequisites.collect{|n| Task[n].timestamp}.max return false if latest_prereq.nil? timestamp < latest_prereq end def timestamp File.new(name.to_s).mtime end end def task(args, &block) Task.define_task(args, &block) end def file(args, &block) FileTask.define_task(args, &block) end def sys(cmd) puts cmd system(cmd) or fail "Command Failed: [#{cmd}]" end def rake begin here = Dir.pwd while ! File.exist?("Rakefile") Dir.chdir("..") fail "No Rakefile found" if Dir.pwd == here here = Dir.pwd end puts "(in #{Dir.pwd})" load "./Rakefile" ARGV.push("default") if ARGV.size == 0 ARGV.each { |task_name| Task[task_name].invoke } rescue Exception => ex puts "rake aborted ... #{ex.message}" puts ex.backtrace.find {|str| str =~ /Rakefile/ } || "" end end if __FILE__ == $0 then rake end PKu]v3HHrake-13.0.1/doc/rational.rdocnu[= Why rake? Ok, let me state from the beginning that I never intended to write this code. I'm not convinced it is useful, and I'm not convinced anyone would even be interested in it. All I can say is that Why's onion truck must by been passing through the Ohio valley. What am I talking about? ... A Ruby version of Make. See, I can sense you cringing already, and I agree. The world certainly doesn't need yet another reworking of the "make" program. I mean, we already have "ant". Isn't that enough? It started yesterday. I was helping a coworker fix a problem in one of the Makefiles we use in our project. Not a particularly tough problem, but during the course of the conversation I began lamenting some of the shortcomings of make. In particular, in one of my makefiles I wanted to determine the name of a file dynamically and had to resort to some simple scripting (in Ruby) to make it work. "Wouldn't it be nice if you could just use Ruby inside a Makefile" I said. My coworker (a recent convert to Ruby) agreed, but wondered what it would look like. So I sketched the following on the whiteboard... "What if you could specify the make tasks in Ruby, like this ..." task "build" do java_compile(...args, etc ...) end "The task function would register "build" as a target to be made, and the block would be the action executed whenever the build system determined that it was time to do the build target." We agreed that would be cool, but writing make from scratch would be WAY too much work. And that was the end of that! ... Except I couldn't get the thought out of my head. What exactly would be needed to make the about syntax work as a make file? Hmmm, you would need to register the tasks, you need some way of specifying dependencies between tasks, and some way of kicking off the process. Hey! What if we did ... and fifteen minutes later I had a working prototype of Ruby make, complete with dependencies and actions. I showed the code to my coworker and we had a good laugh. It was just about a page worth of code that reproduced an amazing amount of the functionality of make. We were both truly stunned with the power of Ruby. But it didn't do everything make did. In particular, it didn't have timestamp based file dependencies (where a file is rebuilt if any of its prerequisite files have a later timestamp). Obviously THAT would be a pain to add and so Ruby Make would remain an interesting experiment. ... Except as I walked back to my desk, I started thinking about what file based dependencies would really need. Rats! I was hooked again, and by adding a new class and two new methods, file/timestamp dependencies were implemented. Ok, now I was really hooked. Last night (during CSI!) I massaged the code and cleaned it up a bit. The result is a bare-bones replacement for make in exactly 100 lines of code. For the curious, you can see it at ... * doc/proto_rake.rdoc Oh, about the name. When I wrote the example Ruby Make task on my whiteboard, my coworker exclaimed "Oh! I have the perfect name: Rake ... Get it? Ruby-Make. Rake!" He said he envisioned the tasks as leaves and Rake would clean them up ... or something like that. Anyways, the name stuck. Some quick examples ... A simple task to delete backup files ... task :clean do Dir['*~'].each {|fn| rm fn rescue nil} end Note that task names are symbols (they are slightly easier to type than quoted strings ... but you may use quoted string if you would rather). Rake makes the methods of the FileUtils module directly available, so we take advantage of the rm command. Also note the use of "rescue nil" to trap and ignore errors in the rm command. To run it, just type "rake clean". Rake will automatically find a Rakefile in the current directory (or above!) and will invoke the targets named on the command line. If there are no targets explicitly named, rake will invoke the task "default". Here's another task with dependencies ... task :clobber => [:clean] do rm_r "tempdir" end Task :clobber depends upon task :clean, so :clean will be run before :clobber is executed. Files are specified by using the "file" command. It is similar to the task command, except that the task name represents a file, and the task will be run only if the file doesn't exist, or if its modification time is earlier than any of its prerequisites. Here is a file based dependency that will compile "hello.cc" to "hello.o". file "hello.cc" file "hello.o" => ["hello.cc"] do |t| srcfile = t.name.sub(/\.o$/, ".cc") sh %{g++ #{srcfile} -c -o #{t.name}} end I normally specify file tasks with string (rather than symbols). Some file names can't be represented by symbols. Plus it makes the distinction between them more clear to the casual reader. Currently writing a task for each and every file in the project would be tedious at best. I envision a set of libraries to make this job easier. For instance, perhaps something like this ... require 'rake/ctools' Dir['*.c'].each do |fn| c_source_file(fn) end where "c_source_file" will create all the tasks need to compile all the C source files in a directory. Any number of useful libraries could be created for rake. That's it. There's no documentation (other than whats in this message). Does this sound interesting to anyone? If so, I'll continue to clean it up and write it up and publish it on RAA. Otherwise, I'll leave it as an interesting exercise and a tribute to the power of Ruby. Why /might/ rake be interesting to Ruby programmers. I don't know, perhaps ... * No weird make syntax (only weird Ruby syntax :-) * No need to edit or read XML (a la ant) * Platform independent build scripts. * Will run anywhere Ruby exists, so no need to have "make" installed. If you stay away from the "sys" command and use things like 'ftools', you can have a perfectly platform independent build script. Also rake is only 100 lines of code, so it can easily be packaged along with the rest of your code. So ... Sorry for the long rambling message. Like I said, I never intended to write this code at all. PKu]'S{rake-13.0.1/doc/glossary.rdocnu[= Glossary action :: Code to be executed in order to perform a task. Actions in a Rakefile are specified in a code block. (Usually delimited by +do+/+end+ pairs.) execute :: When a task is executed, all of its actions are performed in the order they were defined. Note that, unlike invoke, execute always executes the actions (without invoking or executing the prerequisites). file task (Rake::FileTask) :: A file task is a task whose purpose is to create a file (which has the same name as the task). When invoked, a file task will only execute if one or more of the following conditions are true. 1. The associated file does not exist. 2. A prerequisite has a later time stamp than the existing file. Because normal Tasks always have the current time as timestamp, a FileTask that has a normal Task prerequisite will always execute. invoke :: When a task is invoked, first we check to see if it has been invoked before. If it has been, then nothing else is done. If this is the first time it has been invoked, then we invoke each of its prerequisites. Finally, we check to see if we need to execute the actions of this task by calling Rake::Task#needed?. If the task is needed, we execute its actions. NOTE: Prerequisites are still invoked even if the task is not needed. prerequisites :: Every task has a (possibly empty) set of prerequisites. A prerequisite P to Task T is itself a task that must be invoked before Task T. rule :: A rule is a recipe for synthesizing a task when no task is explicitly defined. Rules generally synthesize file tasks. task (Rake::Task) :: The basic unit of work in a Rakefile. A task has a name, a set of prerequisites, and a list of actions to be performed. PKu]Xrake-13.0.1/bin/rdocnu[#!/usr/bin/env ruby # frozen_string_literal: true # # This file was generated by Bundler. # # The application 'rdoc' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath) bundle_binstub = File.expand_path("../bundle", __FILE__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") end end require "rubygems" require "bundler/setup" load Gem.bin_path("rdoc", "rdoc") PKu]Yrake-13.0.1/bin/rakenu[#!/usr/bin/env ruby # frozen_string_literal: true # # This file was generated by Bundler. # # The application 'rake' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath) bundle_binstub = File.expand_path("../bundle", __FILE__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") end end require "rubygems" require "bundler/setup" load Gem.bin_path("rake", "rake") PKu]|u%rake-13.0.1/bin/rubocopnu[#!/usr/bin/env ruby # frozen_string_literal: true # # This file was generated by Bundler. # # The application 'rubocop' is installed as part of a gem, and # this file is here to facilitate running it. # require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath) bundle_binstub = File.expand_path("../bundle", __FILE__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") end end require "rubygems" require "bundler/setup" load Gem.bin_path("rubocop", "rubocop") PKu]t/;JJrake-13.0.1/bin/setupnu[#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install PKu]r WUUrake-13.0.1/bin/consolenu[#!/usr/bin/env ruby require "bundler/setup" require "rake" require "irb" IRB.start PKu]>h  rake-13.0.1/bin/bundlenu[#!/usr/bin/env ruby # frozen_string_literal: true # # This file was generated by Bundler. # # The application 'bundle' is installed as part of a gem, and # this file is here to facilitate running it. # require "rubygems" m = Module.new do module_function def invoked_as_script? File.expand_path($0) == File.expand_path(__FILE__) end def env_var_version ENV["BUNDLER_VERSION"] end def cli_arg_version return unless invoked_as_script? # don't want to hijack other binstubs return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` bundler_version = nil update_index = nil ARGV.each_with_index do |a, i| if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN bundler_version = a end next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ bundler_version = $1 || ">= 0.a" update_index = i end bundler_version end def gemfile gemfile = ENV["BUNDLE_GEMFILE"] return gemfile if gemfile && !gemfile.empty? File.expand_path("../../Gemfile", __FILE__) end def lockfile lockfile = case File.basename(gemfile) when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) else "#{gemfile}.lock" end File.expand_path(lockfile) end def lockfile_version return unless File.file?(lockfile) lockfile_contents = File.read(lockfile) return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ Regexp.last_match(1) end def bundler_version @bundler_version ||= begin env_var_version || cli_arg_version || lockfile_version || "#{Gem::Requirement.default}.a" end end def load_bundler! ENV["BUNDLE_GEMFILE"] ||= gemfile # must dup string for RG < 1.8 compatibility activate_bundler(bundler_version.dup) end def activate_bundler(bundler_version) if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0") bundler_version = "< 2" end gem_error = activation_error_handling do gem "bundler", bundler_version end return if gem_error.nil? require_error = activation_error_handling do require "bundler/version" end return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION)) warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`" exit 42 end def activation_error_handling yield nil rescue StandardError, LoadError => e e end end m.load_bundler! if m.invoked_as_script? load Gem.bin_path("bundler", "bundle") end PKu]R  #rake-13.0.1/lib/rake/linked_list.rbnu[# frozen_string_literal: true module Rake # Polylithic linked list structure used to implement several data # structures in Rake. class LinkedList include Enumerable attr_reader :head, :tail # Polymorphically add a new element to the head of a list. The # type of head node will be the same list type as the tail. def conj(item) self.class.cons(item, self) end # Is the list empty? # .make guards against a list being empty making any instantiated LinkedList # object not empty by default # You should consider overriding this method if you implement your own .make method def empty? false end # Lists are structurally equivalent. def ==(other) current = self while !current.empty? && !other.empty? return false if current.head != other.head current = current.tail other = other.tail end current.empty? && other.empty? end # Convert to string: LL(item, item...) def to_s items = map(&:to_s).join(", ") "LL(#{items})" end # Same as +to_s+, but with inspected items. def inspect items = map(&:inspect).join(", ") "LL(#{items})" end # For each item in the list. def each current = self while !current.empty? yield(current.head) current = current.tail end self end # Make a list out of the given arguments. This method is # polymorphic def self.make(*args) # return an EmptyLinkedList if there are no arguments return empty if !args || args.empty? # build a LinkedList by starting at the tail and iterating # through each argument # inject takes an EmptyLinkedList to start args.reverse.inject(empty) do |list, item| list = cons(item, list) list # return the newly created list for each item in the block end end # Cons a new head onto the tail list. def self.cons(head, tail) new(head, tail) end # The standard empty list class for the given LinkedList class. def self.empty self::EMPTY end protected def initialize(head, tail=EMPTY) @head = head @tail = tail end # Represent an empty list, using the Null Object Pattern. # # When inheriting from the LinkedList class, you should implement # a type specific Empty class as well. Make sure you set the class # instance variable @parent to the associated list class (this # allows conj, cons and make to work polymorphically). class EmptyLinkedList < LinkedList @parent = LinkedList def initialize end def empty? true end def self.cons(head, tail) @parent.cons(head, tail) end end EMPTY = EmptyLinkedList.new end end PKu]2bb(rake-13.0.1/lib/rake/loaders/makefile.rbnu[# frozen_string_literal: true module Rake # Makefile loader to be used with the import file loader. Use this to # import dependencies from make dependency tools: # # require 'rake/loaders/makefile' # # file ".depends.mf" => [SRC_LIST] do |t| # sh "makedepend -f- -- #{CFLAGS} -- #{t.prerequisites} > #{t.name}" # end # # import ".depends.mf" # # See {Importing Dependencies}[link:doc/rakefile_rdoc.html#label-Importing+Dependencies] # for further details. class MakefileLoader include Rake::DSL SPACE_MARK = "\0" # :nodoc: # Load the makefile dependencies in +fn+. def load(fn) # :nodoc: lines = File.read fn lines.gsub!(/\\ /, SPACE_MARK) lines.gsub!(/#[^\n]*\n/m, "") lines.gsub!(/\\\n/, " ") lines.each_line do |line| process_line(line) end end private # Process one logical line of makefile data. def process_line(line) # :nodoc: file_tasks, args = line.split(":", 2) return if args.nil? dependents = args.split.map { |d| respace(d) } file_tasks.scan(/\S+/) do |file_task| file_task = respace(file_task) file file_task => dependents end end def respace(str) # :nodoc: str.tr SPACE_MARK, " " end end # Install the handler Rake.application.add_loader("mf", MakefileLoader.new) end PKu]u rake-13.0.1/lib/rake/ext/core.rbnu[# frozen_string_literal: true class Module # Check for an existing method in the current class before extending. If # the method already exists, then a warning is printed and the extension is # not added. Otherwise the block is yielded and any definitions in the # block will take effect. # # Usage: # # class String # rake_extension("xyz") do # def xyz # ... # end # end # end # def rake_extension(method) # :nodoc: if method_defined?(method) $stderr.puts "WARNING: Possible conflict with Rake extension: " + "#{self}##{method} already exists" else yield end end end PKu]yOurr"rake-13.0.1/lib/rake/ext/string.rbnu[# frozen_string_literal: true require "rake/ext/core" class String rake_extension("ext") do # Replace the file extension with +newext+. If there is no extension on # the string, append the new extension to the end. If the new extension # is not given, or is the empty string, remove any existing extension. # # +ext+ is a user added method for the String class. # # This String extension comes from Rake def ext(newext="") return self.dup if [".", ".."].include? self if newext != "" newext = "." + newext unless newext =~ /^\./ end self.chomp(File.extname(self)) << newext end end rake_extension("pathmap") do # Explode a path into individual components. Used by +pathmap+. # # This String extension comes from Rake def pathmap_explode head, tail = File.split(self) return [self] if head == self return [tail] if head == "." || tail == "/" return [head, tail] if head == "/" return head.pathmap_explode + [tail] end protected :pathmap_explode # Extract a partial path from the path. Include +n+ directories from the # front end (left hand side) if +n+ is positive. Include |+n+| # directories from the back end (right hand side) if +n+ is negative. # # This String extension comes from Rake def pathmap_partial(n) dirs = File.dirname(self).pathmap_explode partial_dirs = if n > 0 dirs[0...n] elsif n < 0 dirs.reverse[0...-n].reverse else "." end File.join(partial_dirs) end protected :pathmap_partial # Perform the pathmap replacement operations on the given path. The # patterns take the form 'pat1,rep1;pat2,rep2...'. # # This String extension comes from Rake def pathmap_replace(patterns, &block) result = self patterns.split(";").each do |pair| pattern, replacement = pair.split(",") pattern = Regexp.new(pattern) if replacement == "*" && block_given? result = result.sub(pattern, &block) elsif replacement result = result.sub(pattern, replacement) else result = result.sub(pattern, "") end end result end protected :pathmap_replace # Map the path according to the given specification. The specification # controls the details of the mapping. The following special patterns are # recognized: # # %p :: The complete path. # %f :: The base file name of the path, with its file extension, # but without any directories. # %n :: The file name of the path without its file extension. # %d :: The directory list of the path. # %x :: The file extension of the path. An empty string if there # is no extension. # %X :: Everything *but* the file extension. # %s :: The alternate file separator if defined, otherwise use # # the standard file separator. # %% :: A percent sign. # # The %d specifier can also have a numeric prefix (e.g. '%2d'). # If the number is positive, only return (up to) +n+ directories in the # path, starting from the left hand side. If +n+ is negative, return (up # to) +n+ directories from the right hand side of the path. # # Examples: # # 'a/b/c/d/file.txt'.pathmap("%2d") => 'a/b' # 'a/b/c/d/file.txt'.pathmap("%-2d") => 'c/d' # # Also the %d, %p, %f, %n, # %x, and %X operators can take a pattern/replacement # argument to perform simple string substitutions on a particular part of # the path. The pattern and replacement are separated by a comma and are # enclosed by curly braces. The replacement spec comes after the % # character but before the operator letter. (e.g. "%{old,new}d"). # Multiple replacement specs should be separated by semi-colons (e.g. # "%{old,new;src,bin}d"). # # Regular expressions may be used for the pattern, and back refs may be # used in the replacement text. Curly braces, commas and semi-colons are # excluded from both the pattern and replacement text (let's keep parsing # reasonable). # # For example: # # "src/org/onestepback/proj/A.java".pathmap("%{^src,class}X.class") # # returns: # # "class/org/onestepback/proj/A.class" # # If the replacement text is '*', then a block may be provided to perform # some arbitrary calculation for the replacement. # # For example: # # "/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext| # ext.downcase # } # # Returns: # # "/path/to/file.txt" # # This String extension comes from Rake def pathmap(spec=nil, &block) return self if spec.nil? result = "".dup spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag| case frag when "%f" result << File.basename(self) when "%n" result << File.basename(self).ext when "%d" result << File.dirname(self) when "%x" result << File.extname(self) when "%X" result << self.ext when "%p" result << self when "%s" result << (File::ALT_SEPARATOR || File::SEPARATOR) when "%-" # do nothing when "%%" result << "%" when /%(-?\d+)d/ result << pathmap_partial($1.to_i) when /^%\{([^}]*)\}(\d*[dpfnxX])/ patterns, operator = $1, $2 result << pathmap("%" + operator).pathmap_replace(patterns, &block) when /^%/ fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'" else result << frag end end result end end end PKu].*C}}rake-13.0.1/lib/rake/phony.rbnu[# frozen_string_literal: true # Defines a :phony task that you can use as a dependency. This allows # file-based tasks to use non-file-based tasks as prerequisites # without forcing them to rebuild. # # See FileTask#out_of_date? and Task#timestamp for more info. require "rake" task :phony Rake::Task[:phony].tap do |task| def task.timestamp # :nodoc: Time.at 0 end end PKu]?{Hrr"rake-13.0.1/lib/rake/early_time.rbnu[# frozen_string_literal: true module Rake # EarlyTime is a fake timestamp that occurs _before_ any other time value. class EarlyTime include Comparable include Singleton ## # The EarlyTime always comes before +other+! def <=>(other) -1 end def to_s # :nodoc: "" end end EARLY = EarlyTime.instance end PKu]n#+rake-13.0.1/lib/rake/task_argument_error.rbnu[# frozen_string_literal: true module Rake # Error indicating an ill-formed task declaration. class TaskArgumentError < ArgumentError end end PKu]QGrake-13.0.1/lib/rake/clean.rbnu[# frozen_string_literal: true # The 'rake/clean' file defines two file lists (CLEAN and CLOBBER) and # two rake tasks (:clean and :clobber). # # [:clean] Clean up the project by deleting scratch files and backup # files. Add files to the CLEAN file list to have the :clean # target handle them. # # [:clobber] Clobber all generated and non-source files in a project. # The task depends on :clean, so all the clean files will # be deleted as well as files in the CLOBBER file list. # The intent of this task is to return a project to its # pristine, just unpacked state. require "rake" # :stopdoc: module Rake module Cleaner extend FileUtils module_function def cleanup_files(file_names) file_names.each do |file_name| cleanup(file_name) end end def cleanup(file_name, **opts) begin opts = { verbose: Rake.application.options.trace }.merge(opts) rm_r file_name, **opts rescue StandardError => ex puts "Failed to remove #{file_name}: #{ex}" unless file_already_gone?(file_name) end end def file_already_gone?(file_name) return false if File.exist?(file_name) path = file_name prev = nil while path = File.dirname(path) return false if cant_be_deleted?(path) break if [prev, "."].include?(path) prev = path end true end private_class_method :file_already_gone? def cant_be_deleted?(path_name) File.exist?(path_name) && (!File.readable?(path_name) || !File.executable?(path_name)) end private_class_method :cant_be_deleted? end end CLEAN = ::Rake::FileList["**/*~", "**/*.bak", "**/core"] CLEAN.clear_exclude.exclude { |fn| fn.pathmap("%f").downcase == "core" && File.directory?(fn) } desc "Remove any temporary products." task :clean do Rake::Cleaner.cleanup_files(CLEAN) end CLOBBER = ::Rake::FileList.new desc "Remove any generated files." task clobber: [:clean] do Rake::Cleaner.cleanup_files(CLOBBER) end PKu]d11!rake-13.0.1/lib/rake/file_list.rbnu[# frozen_string_literal: true require "rake/cloneable" require "rake/file_utils_ext" require "rake/ext/string" module Rake ## # A FileList is essentially an array with a few helper methods defined to # make file manipulation a bit easier. # # FileLists are lazy. When given a list of glob patterns for possible files # to be included in the file list, instead of searching the file structures # to find the files, a FileList holds the pattern for latter use. # # This allows us to define a number of FileList to match any number of # files, but only search out the actual files when then FileList itself is # actually used. The key is that the first time an element of the # FileList/Array is requested, the pending patterns are resolved into a real # list of file names. # class FileList include Cloneable # == Method Delegation # # The lazy evaluation magic of FileLists happens by implementing all the # array specific methods to call +resolve+ before delegating the heavy # lifting to an embedded array object (@items). # # In addition, there are two kinds of delegation calls. The regular kind # delegates to the @items array and returns the result directly. Well, # almost directly. It checks if the returned value is the @items object # itself, and if so will return the FileList object instead. # # The second kind of delegation call is used in methods that normally # return a new Array object. We want to capture the return value of these # methods and wrap them in a new FileList object. We enumerate these # methods in the +SPECIAL_RETURN+ list below. # List of array methods (that are not in +Object+) that need to be # delegated. ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map(&:to_s) # List of additional methods that must be delegated. MUST_DEFINE = %w[inspect <=>] # List of methods that should not be delegated here (we define special # versions of them explicitly below). MUST_NOT_DEFINE = %w[to_a to_ary partition * <<] # List of delegated methods that return new array values which need # wrapping. SPECIAL_RETURN = %w[ map collect sort sort_by select find_all reject grep compact flatten uniq values_at + - & | ] DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).map(&:to_s).sort.uniq # Now do the delegation. DELEGATING_METHODS.each do |sym| if SPECIAL_RETURN.include?(sym) ln = __LINE__ + 1 class_eval %{ def #{sym}(*args, &block) resolve result = @items.send(:#{sym}, *args, &block) self.class.new.import(result) end }, __FILE__, ln else ln = __LINE__ + 1 class_eval %{ def #{sym}(*args, &block) resolve result = @items.send(:#{sym}, *args, &block) result.object_id == @items.object_id ? self : result end }, __FILE__, ln end end GLOB_PATTERN = %r{[*?\[\{]} # Create a file list from the globbable patterns given. If you wish to # perform multiple includes or excludes at object build time, use the # "yield self" pattern. # # Example: # file_list = FileList.new('lib/**/*.rb', 'test/test*.rb') # # pkg_files = FileList.new('lib/**/*') do |fl| # fl.exclude(/\bCVS\b/) # end # def initialize(*patterns) @pending_add = [] @pending = false @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup @exclude_procs = DEFAULT_IGNORE_PROCS.dup @items = [] patterns.each { |pattern| include(pattern) } yield self if block_given? end # Add file names defined by glob patterns to the file list. If an array # is given, add each element of the array. # # Example: # file_list.include("*.java", "*.cfg") # file_list.include %w( math.c lib.h *.o ) # def include(*filenames) # TODO: check for pending filenames.each do |fn| if fn.respond_to? :to_ary include(*fn.to_ary) else @pending_add << Rake.from_pathname(fn) end end @pending = true self end alias :add :include # Register a list of file name patterns that should be excluded from the # list. Patterns may be regular expressions, glob patterns or regular # strings. In addition, a block given to exclude will remove entries that # return true when given to the block. # # Note that glob patterns are expanded against the file system. If a file # is explicitly added to a file list, but does not exist in the file # system, then an glob pattern in the exclude list will not exclude the # file. # # Examples: # FileList['a.c', 'b.c'].exclude("a.c") => ['b.c'] # FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c'] # # If "a.c" is a file, then ... # FileList['a.c', 'b.c'].exclude("a.*") => ['b.c'] # # If "a.c" is not a file, then ... # FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c'] # def exclude(*patterns, &block) patterns.each do |pat| if pat.respond_to? :to_ary exclude(*pat.to_ary) else @exclude_patterns << Rake.from_pathname(pat) end end @exclude_procs << block if block_given? resolve_exclude unless @pending self end # Clear all the exclude patterns so that we exclude nothing. def clear_exclude @exclude_patterns = [] @exclude_procs = [] self end # A FileList is equal through array equality. def ==(array) to_ary == array end # Return the internal array object. def to_a resolve @items end # Return the internal array object. def to_ary to_a end # Lie about our class. def is_a?(klass) klass == Array || super(klass) end alias kind_of? is_a? # Redefine * to return either a string or a new file list. def *(other) result = @items * other case result when Array self.class.new.import(result) else result end end def <<(obj) resolve @items << Rake.from_pathname(obj) self end # Resolve all the pending adds now. def resolve if @pending @pending = false @pending_add.each do |fn| resolve_add(fn) end @pending_add = [] resolve_exclude end self end def resolve_add(fn) # :nodoc: case fn when GLOB_PATTERN add_matching(fn) else self << fn end end private :resolve_add def resolve_exclude # :nodoc: reject! { |fn| excluded_from_list?(fn) } self end private :resolve_exclude # Return a new FileList with the results of running +sub+ against each # element of the original list. # # Example: # FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o'] # def sub(pat, rep) inject(self.class.new) { |res, fn| res << fn.sub(pat, rep) } end # Return a new FileList with the results of running +gsub+ against each # element of the original list. # # Example: # FileList['lib/test/file', 'x/y'].gsub(/\//, "\\") # => ['lib\\test\\file', 'x\\y'] # def gsub(pat, rep) inject(self.class.new) { |res, fn| res << fn.gsub(pat, rep) } end # Same as +sub+ except that the original file list is modified. def sub!(pat, rep) each_with_index { |fn, i| self[i] = fn.sub(pat, rep) } self end # Same as +gsub+ except that the original file list is modified. def gsub!(pat, rep) each_with_index { |fn, i| self[i] = fn.gsub(pat, rep) } self end # Apply the pathmap spec to each of the included file names, returning a # new file list with the modified paths. (See String#pathmap for # details.) def pathmap(spec=nil, &block) collect { |fn| fn.pathmap(spec, &block) } end # Return a new FileList with String#ext method applied to # each member of the array. # # This method is a shortcut for: # # array.collect { |item| item.ext(newext) } # # +ext+ is a user added method for the Array class. def ext(newext="") collect { |fn| fn.ext(newext) } end # Grep each of the files in the filelist using the given pattern. If a # block is given, call the block on each matching line, passing the file # name, line number, and the matching line of text. If no block is given, # a standard emacs style file:linenumber:line message will be printed to # standard out. Returns the number of matched items. def egrep(pattern, *options) matched = 0 each do |fn| begin File.open(fn, "r", *options) do |inf| count = 0 inf.each do |line| count += 1 if pattern.match(line) matched += 1 if block_given? yield fn, count, line else puts "#{fn}:#{count}:#{line}" end end end end rescue StandardError => ex $stderr.puts "Error while processing '#{fn}': #{ex}" end end matched end # Return a new file list that only contains file names from the current # file list that exist on the file system. def existing select { |fn| File.exist?(fn) }.uniq end # Modify the current file list so that it contains only file name that # exist on the file system. def existing! resolve @items = @items.select { |fn| File.exist?(fn) }.uniq self end # FileList version of partition. Needed because the nested arrays should # be FileLists in this version. def partition(&block) # :nodoc: resolve result = @items.partition(&block) [ self.class.new.import(result[0]), self.class.new.import(result[1]), ] end # Convert a FileList to a string by joining all elements with a space. def to_s resolve self.join(" ") end # Add matching glob patterns. def add_matching(pattern) self.class.glob(pattern).each do |fn| self << fn unless excluded_from_list?(fn) end end private :add_matching # Should the given file name be excluded from the list? # # NOTE: This method was formerly named "exclude?", but Rails # introduced an exclude? method as an array method and setup a # conflict with file list. We renamed the method to avoid # confusion. If you were using "FileList#exclude?" in your user # code, you will need to update. def excluded_from_list?(fn) return true if @exclude_patterns.any? do |pat| case pat when Regexp fn =~ pat when GLOB_PATTERN flags = File::FNM_PATHNAME # Ruby <= 1.9.3 does not support File::FNM_EXTGLOB flags |= File::FNM_EXTGLOB if defined? File::FNM_EXTGLOB File.fnmatch?(pat, fn, flags) else fn == pat end end @exclude_procs.any? { |p| p.call(fn) } end DEFAULT_IGNORE_PATTERNS = [ /(^|[\/\\])CVS([\/\\]|$)/, /(^|[\/\\])\.svn([\/\\]|$)/, /\.bak$/, /~$/ ] DEFAULT_IGNORE_PROCS = [ proc { |fn| fn =~ /(^|[\/\\])core$/ && !File.directory?(fn) } ] def import(array) # :nodoc: @items = array self end class << self # Create a new file list including the files listed. Similar to: # # FileList.new(*args) def [](*args) new(*args) end # Get a sorted list of files matching the pattern. This method # should be preferred to Dir[pattern] and Dir.glob(pattern) because # the files returned are guaranteed to be sorted. def glob(pattern, *args) Dir.glob(pattern, *args).sort end end end end module Rake class << self # Yield each file or directory component. def each_dir_parent(dir) # :nodoc: old_length = nil while dir != "." && dir.length != old_length yield(dir) old_length = dir.length dir = File.dirname(dir) end end # Convert Pathname and Pathname-like objects to strings; # leave everything else alone def from_pathname(path) # :nodoc: path = path.to_path if path.respond_to?(:to_path) path = path.to_str if path.respond_to?(:to_str) path end end end # module Rake PKu]F- &rake-13.0.1/lib/rake/dsl_definition.rbnu[# frozen_string_literal: true # Rake DSL functions. require "rake/file_utils_ext" module Rake ## # DSL is a module that provides #task, #desc, #namespace, etc. Use this # when you'd like to use rake outside the top level scope. # # For a Rakefile you run from the command line this module is automatically # included. module DSL #-- # Include the FileUtils file manipulation functions in the top # level module, but mark them private so that they don't # unintentionally define methods on other objects. #++ include FileUtilsExt private(*FileUtils.instance_methods(false)) private(*FileUtilsExt.instance_methods(false)) private # :call-seq: # task(task_name) # task(task_name: dependencies) # task(task_name, arguments => dependencies) # # Declare a basic task. The +task_name+ is always the first argument. If # the task name contains a ":" it is defined in that namespace. # # The +dependencies+ may be a single task name or an Array of task names. # The +argument+ (a single name) or +arguments+ (an Array of names) define # the arguments provided to the task. # # The task, argument and dependency names may be either symbols or # strings. # # A task with a single dependency: # # task clobber: %w[clean] do # rm_rf "html" # end # # A task with an argument and a dependency: # # task :package, [:version] => :test do |t, args| # # ... # end # # To invoke this task from the command line: # # $ rake package[1.2.3] # def task(*args, &block) # :doc: Rake::Task.define_task(*args, &block) end # Declare a file task. # # Example: # file "config.cfg" => ["config.template"] do # open("config.cfg", "w") do |outfile| # open("config.template") do |infile| # while line = infile.gets # outfile.puts line # end # end # end # end # def file(*args, &block) # :doc: Rake::FileTask.define_task(*args, &block) end # Declare a file creation task. # (Mainly used for the directory command). def file_create(*args, &block) Rake::FileCreationTask.define_task(*args, &block) end # Declare a set of files tasks to create the given directories on # demand. # # Example: # directory "testdata/doc" # def directory(*args, &block) # :doc: result = file_create(*args, &block) dir, _ = *Rake.application.resolve_args(args) dir = Rake.from_pathname(dir) Rake.each_dir_parent(dir) do |d| file_create d do |t| mkdir_p t.name unless File.exist?(t.name) end end result end # Declare a task that performs its prerequisites in # parallel. Multitasks does *not* guarantee that its prerequisites # will execute in any given order (which is obvious when you think # about it) # # Example: # multitask deploy: %w[deploy_gem deploy_rdoc] # def multitask(*args, &block) # :doc: Rake::MultiTask.define_task(*args, &block) end # Create a new rake namespace and use it for evaluating the given # block. Returns a NameSpace object that can be used to lookup # tasks defined in the namespace. # # Example: # # ns = namespace "nested" do # # the "nested:run" task # task :run # end # task_run = ns[:run] # find :run in the given namespace. # # Tasks can also be defined in a namespace by using a ":" in the task # name: # # task "nested:test" do # # ... # end # def namespace(name=nil, &block) # :doc: name = name.to_s if name.kind_of?(Symbol) name = name.to_str if name.respond_to?(:to_str) unless name.kind_of?(String) || name.nil? raise ArgumentError, "Expected a String or Symbol for a namespace name" end Rake.application.in_namespace(name, &block) end # Declare a rule for auto-tasks. # # Example: # rule '.o' => '.c' do |t| # sh 'cc', '-o', t.name, t.source # end # def rule(*args, &block) # :doc: Rake::Task.create_rule(*args, &block) end # Describes the next rake task. Duplicate descriptions are discarded. # Descriptions are shown with rake -T (up to the first # sentence) and rake -D (the entire description). # # Example: # desc "Run the Unit Tests" # task test: [:build] # # ... run tests # end # def desc(description) # :doc: Rake.application.last_description = description end # Import the partial Rakefiles +fn+. Imported files are loaded # _after_ the current file is completely loaded. This allows the # import statement to appear anywhere in the importing file, and yet # allowing the imported files to depend on objects defined in the # importing file. # # A common use of the import statement is to include files # containing dependency declarations. # # See also the --rakelibdir command line option. # # Example: # import ".depend", "my_rules" # def import(*fns) # :doc: fns.each do |fn| Rake.application.add_import(fn) end end end extend FileUtilsExt end # Extend the main object with the DSL commands. This allows top-level # calls to task, etc. to work from a Rakefile without polluting the # object inheritance tree. self.extend Rake::DSL PKu]!rake-13.0.1/lib/rake/cloneable.rbnu[# frozen_string_literal: true module Rake ## # Mixin for creating easily cloned objects. module Cloneable # :nodoc: # The hook that is invoked by 'clone' and 'dup' methods. def initialize_copy(source) super source.instance_variables.each do |var| src_value = source.instance_variable_get(var) value = src_value.clone rescue src_value instance_variable_set(var, value) end end end end PKu];YII"rake-13.0.1/lib/rake/file_utils.rbnu[# frozen_string_literal: true require "rbconfig" require "fileutils" #-- # This a FileUtils extension that defines several additional commands to be # added to the FileUtils utility functions. module FileUtils # Path to the currently running Ruby program RUBY = ENV["RUBY"] || File.join( RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"] + RbConfig::CONFIG["EXEEXT"]). sub(/.*\s.*/m, '"\&"') # Run the system command +cmd+. If multiple arguments are given the command # is run directly (without the shell, same semantics as Kernel::exec and # Kernel::system). # # It is recommended you use the multiple argument form over interpolating # user input for both usability and security reasons. With the multiple # argument form you can easily process files with spaces or other shell # reserved characters in them. With the multiple argument form your rake # tasks are not vulnerable to users providing an argument like # ; rm # -rf /. # # If a block is given, upon command completion the block is called with an # OK flag (true on a zero exit status) and a Process::Status object. # Without a block a RuntimeError is raised when the command exits non-zero. # # Examples: # # sh 'ls -ltr' # # sh 'ls', 'file with spaces' # # # check exit status after command runs # sh %{grep pattern file} do |ok, res| # if !ok # puts "pattern not found (status = #{res.exitstatus})" # end # end # def sh(*cmd, &block) options = (Hash === cmd.last) ? cmd.pop : {} shell_runner = block_given? ? block : create_shell_runner(cmd) set_verbose_option(options) verbose = options.delete :verbose noop = options.delete(:noop) || Rake::FileUtilsExt.nowrite_flag Rake.rake_output_message sh_show_command cmd if verbose unless noop res = (Hash === cmd.last) ? system(*cmd) : system(*cmd, options) status = $? status = Rake::PseudoStatus.new(1) if !res && status.nil? shell_runner.call(res, status) end end def create_shell_runner(cmd) # :nodoc: show_command = sh_show_command cmd show_command = show_command[0, 42] + "..." unless $trace lambda do |ok, status| ok or fail "Command failed with status (#{status.exitstatus}): " + "[#{show_command}]" end end private :create_shell_runner def sh_show_command(cmd) # :nodoc: cmd = cmd.dup if Hash === cmd.first env = cmd.first env = env.map { |name, value| "#{name}=#{value}" }.join " " cmd[0] = env end cmd.join " " end private :sh_show_command def set_verbose_option(options) # :nodoc: unless options.key? :verbose options[:verbose] = (Rake::FileUtilsExt.verbose_flag == Rake::FileUtilsExt::DEFAULT) || Rake::FileUtilsExt.verbose_flag end end private :set_verbose_option # Run a Ruby interpreter with the given arguments. # # Example: # ruby %{-pe '$_.upcase!' 1 sh(RUBY, *args, **options, &block) else sh("#{RUBY} #{args.first}", **options, &block) end end LN_SUPPORTED = [true] # Attempt to do a normal file link, but fall back to a copy if the link # fails. def safe_ln(*args, **options) if LN_SUPPORTED[0] begin return options.empty? ? ln(*args) : ln(*args, **options) rescue StandardError, NotImplementedError LN_SUPPORTED[0] = false end end options.empty? ? cp(*args) : cp(*args, **options) end # Split a file path into individual directory names. # # Example: # split_all("a/b/c") => ['a', 'b', 'c'] # def split_all(path) head, tail = File.split(path) return [tail] if head == "." || tail == "/" return [head, tail] if head == "/" return split_all(head) + [tail] end end PKu]rake-13.0.1/lib/rake/scope.rbnu[# frozen_string_literal: true module Rake class Scope < LinkedList # :nodoc: all # Path for the scope. def path map(&:to_s).reverse.join(":") end # Path for the scope + the named path. def path_with_task_name(task_name) "#{path}:#{task_name}" end # Trim +n+ innermost scope levels from the scope. In no case will # this trim beyond the toplevel scope. def trim(n) result = self while n > 0 && !result.empty? result = result.tail n -= 1 end result end # Scope lists always end with an EmptyScope object. See Null # Object Pattern) class EmptyScope < EmptyLinkedList @parent = Scope def path "" end def path_with_task_name(task_name) task_name end end # Singleton null object for an empty scope. EMPTY = EmptyScope.new end end PKu]sZZ&rake-13.0.1/lib/rake/file_utils_ext.rbnu[# frozen_string_literal: true require "rake/file_utils" module Rake # # FileUtilsExt provides a custom version of the FileUtils methods # that respond to the verbose and nowrite # commands. # module FileUtilsExt include FileUtils class << self attr_accessor :verbose_flag, :nowrite_flag end DEFAULT = Object.new FileUtilsExt.verbose_flag = DEFAULT FileUtilsExt.nowrite_flag = false FileUtils.commands.each do |name| opts = FileUtils.options_of name default_options = [] if opts.include?("verbose") default_options << "verbose: FileUtilsExt.verbose_flag" end if opts.include?("noop") default_options << "noop: FileUtilsExt.nowrite_flag" end next if default_options.empty? module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args, **options, &block) super(*args, #{default_options.join(', ')}, **options, &block) end EOS end # Get/set the verbose flag controlling output from the FileUtils # utilities. If verbose is true, then the utility method is # echoed to standard output. # # Examples: # verbose # return the current value of the # # verbose flag # verbose(v) # set the verbose flag to _v_. # verbose(v) { code } # Execute code with the verbose flag set # # temporarily to _v_. Return to the # # original value when code is done. def verbose(value=nil) oldvalue = FileUtilsExt.verbose_flag FileUtilsExt.verbose_flag = value unless value.nil? if block_given? begin yield ensure FileUtilsExt.verbose_flag = oldvalue end end FileUtilsExt.verbose_flag end # Get/set the nowrite flag controlling output from the FileUtils # utilities. If verbose is true, then the utility method is # echoed to standard output. # # Examples: # nowrite # return the current value of the # # nowrite flag # nowrite(v) # set the nowrite flag to _v_. # nowrite(v) { code } # Execute code with the nowrite flag set # # temporarily to _v_. Return to the # # original value when code is done. def nowrite(value=nil) oldvalue = FileUtilsExt.nowrite_flag FileUtilsExt.nowrite_flag = value unless value.nil? if block_given? begin yield ensure FileUtilsExt.nowrite_flag = oldvalue end end oldvalue end # Use this function to prevent potentially destructive ruby code # from running when the :nowrite flag is set. # # Example: # # when_writing("Building Project") do # project.build # end # # The following code will build the project under normal # conditions. If the nowrite(true) flag is set, then the example # will print: # # DRYRUN: Building Project # # instead of actually building the project. # def when_writing(msg=nil) if FileUtilsExt.nowrite_flag $stderr.puts "DRYRUN: #{msg}" if msg else yield end end # Send the message to the default rake output (which is $stderr). def rake_output_message(message) $stderr.puts(message) end # Check that the options do not contain options not listed in # +optdecl+. An ArgumentError exception is thrown if non-declared # options are found. def rake_check_options(options, *optdecl) h = options.dup optdecl.each do |name| h.delete name end raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty? end extend self end end PKu])lq(#rake-13.0.1/lib/rake/packagetask.rbnu[# frozen_string_literal: true # Define a package task library to aid in the definition of # redistributable package files. require "rake" require "rake/tasklib" module Rake # Create a packaging task that will package the project into # distributable files (e.g zip archive or tar files). # # The PackageTask will create the following targets: # # +:package+ :: # Create all the requested package files. # # +:clobber_package+ :: # Delete all the package files. This target is automatically # added to the main clobber target. # # +:repackage+ :: # Rebuild the package files from scratch, even if they are not out # of date. # # "package_dir/name-version.tgz" :: # Create a gzipped tar package (if need_tar is true). # # "package_dir/name-version.tar.gz" :: # Create a gzipped tar package (if need_tar_gz is true). # # "package_dir/name-version.tar.bz2" :: # Create a bzip2'd tar package (if need_tar_bz2 is true). # # "package_dir/name-version.zip" :: # Create a zip package archive (if need_zip is true). # # Example: # # Rake::PackageTask.new("rake", "1.2.3") do |p| # p.need_tar = true # p.package_files.include("lib/**/*.rb") # end # class PackageTask < TaskLib # Name of the package (from the GEM Spec). attr_accessor :name # Version of the package (e.g. '1.3.2'). attr_accessor :version # Directory used to store the package files (default is 'pkg'). attr_accessor :package_dir # True if a gzipped tar file (tgz) should be produced (default is # false). attr_accessor :need_tar # True if a gzipped tar file (tar.gz) should be produced (default # is false). attr_accessor :need_tar_gz # True if a bzip2'd tar file (tar.bz2) should be produced (default # is false). attr_accessor :need_tar_bz2 # True if a xz'd tar file (tar.xz) should be produced (default is false) attr_accessor :need_tar_xz # True if a zip file should be produced (default is false) attr_accessor :need_zip # List of files to be included in the package. attr_accessor :package_files # Tar command for gzipped or bzip2ed archives. The default is 'tar'. attr_accessor :tar_command # Zip command for zipped archives. The default is 'zip'. attr_accessor :zip_command # True if parent directory should be omited (default is false) attr_accessor :without_parent_dir # Create a Package Task with the given name and version. Use +:noversion+ # as the version to build a package without a version or to provide a # fully-versioned package name. def initialize(name=nil, version=nil) init(name, version) yield self if block_given? define unless name.nil? end # Initialization that bypasses the "yield self" and "define" step. def init(name, version) @name = name @version = version @package_files = Rake::FileList.new @package_dir = "pkg" @need_tar = false @need_tar_gz = false @need_tar_bz2 = false @need_tar_xz = false @need_zip = false @tar_command = "tar" @zip_command = "zip" @without_parent_dir = false end # Create the tasks defined by this task library. def define fail "Version required (or :noversion)" if @version.nil? @version = nil if :noversion == @version desc "Build all the packages" task :package desc "Force a rebuild of the package files" task repackage: [:clobber_package, :package] desc "Remove package products" task :clobber_package do rm_r package_dir rescue nil end task clobber: [:clobber_package] [ [need_tar, tgz_file, "z"], [need_tar_gz, tar_gz_file, "z"], [need_tar_bz2, tar_bz2_file, "j"], [need_tar_xz, tar_xz_file, "J"] ].each do |need, file, flag| if need task package: ["#{package_dir}/#{file}"] file "#{package_dir}/#{file}" => [package_dir_path] + package_files do chdir(working_dir) { sh @tar_command, "#{flag}cvf", file, target_dir } mv "#{package_dir_path}/#{target_dir}", package_dir if without_parent_dir end end end if need_zip task package: ["#{package_dir}/#{zip_file}"] file "#{package_dir}/#{zip_file}" => [package_dir_path] + package_files do chdir(working_dir) { sh @zip_command, "-r", zip_file, target_dir } mv "#{package_dir_path}/#{zip_file}", package_dir if without_parent_dir end end directory package_dir_path => @package_files do @package_files.each do |fn| f = File.join(package_dir_path, fn) fdir = File.dirname(f) mkdir_p(fdir) unless File.exist?(fdir) if File.directory?(fn) mkdir_p(f) else rm_f f safe_ln(fn, f) end end end self end # The name of this package def package_name @version ? "#{@name}-#{@version}" : @name end # The directory this package will be built in def package_dir_path "#{package_dir}/#{package_name}" end # The package name with .tgz added def tgz_file "#{package_name}.tgz" end # The package name with .tar.gz added def tar_gz_file "#{package_name}.tar.gz" end # The package name with .tar.bz2 added def tar_bz2_file "#{package_name}.tar.bz2" end # The package name with .tar.xz added def tar_xz_file "#{package_name}.tar.xz" end # The package name with .zip added def zip_file "#{package_name}.zip" end def working_dir without_parent_dir ? package_dir_path : package_dir end # target directory relative to working_dir def target_dir without_parent_dir ? "." : package_name end end end PKu]4Tc#rake-13.0.1/lib/rake/thread_pool.rbnu[# frozen_string_literal: true require "set" require "rake/promise" module Rake class ThreadPool # :nodoc: all # Creates a ThreadPool object. The +thread_count+ parameter is the size # of the pool. def initialize(thread_count) @max_active_threads = [thread_count, 0].max @threads = Set.new @threads_mon = Monitor.new @queue = Queue.new @join_cond = @threads_mon.new_cond @history_start_time = nil @history = [] @history_mon = Monitor.new @total_threads_in_play = 0 end # Creates a future executed by the +ThreadPool+. # # The args are passed to the block when executing (similarly to # Thread#new) The return value is an object representing # a future which has been created and added to the queue in the # pool. Sending #value to the object will sleep the # current thread until the future is finished and will return the # result (or raise an exception thrown from the future) def future(*args, &block) promise = Promise.new(args, &block) promise.recorder = lambda { |*stats| stat(*stats) } @queue.enq promise stat :queued, item_id: promise.object_id start_thread promise end # Waits until the queue of futures is empty and all threads have exited. def join @threads_mon.synchronize do begin stat :joining @join_cond.wait unless @threads.empty? stat :joined rescue Exception => e stat :joined $stderr.puts e $stderr.print "Queue contains #{@queue.size} items. " + "Thread pool contains #{@threads.count} threads\n" $stderr.print "Current Thread #{Thread.current} status = " + "#{Thread.current.status}\n" $stderr.puts e.backtrace.join("\n") @threads.each do |t| $stderr.print "Thread #{t} status = #{t.status}\n" $stderr.puts t.backtrace.join("\n") end raise e end end end # Enable the gathering of history events. def gather_history #:nodoc: @history_start_time = Time.now if @history_start_time.nil? end # Return a array of history events for the thread pool. # # History gathering must be enabled to be able to see the events # (see #gather_history). Best to call this when the job is # complete (i.e. after ThreadPool#join is called). def history # :nodoc: @history_mon.synchronize { @history.dup }. sort_by { |i| i[:time] }. each { |i| i[:time] -= @history_start_time } end # Return a hash of always collected statistics for the thread pool. def statistics # :nodoc: { total_threads_in_play: @total_threads_in_play, max_active_threads: @max_active_threads, } end private # processes one item on the queue. Returns true if there was an # item to process, false if there was no item def process_queue_item #:nodoc: return false if @queue.empty? # Even though we just asked if the queue was empty, it # still could have had an item which by this statement # is now gone. For this reason we pass true to Queue#deq # because we will sleep indefinitely if it is empty. promise = @queue.deq(true) stat :dequeued, item_id: promise.object_id promise.work return true rescue ThreadError # this means the queue is empty false end def safe_thread_count @threads_mon.synchronize do @threads.count end end def start_thread # :nodoc: @threads_mon.synchronize do next unless @threads.count < @max_active_threads t = Thread.new do begin while safe_thread_count <= @max_active_threads break unless process_queue_item end ensure @threads_mon.synchronize do @threads.delete Thread.current stat :ended, thread_count: @threads.count @join_cond.broadcast if @threads.empty? end end end @threads << t stat( :spawned, new_thread: t.object_id, thread_count: @threads.count) @total_threads_in_play = @threads.count if @threads.count > @total_threads_in_play end end def stat(event, data=nil) # :nodoc: return if @history_start_time.nil? info = { event: event, data: data, time: Time.now, thread: Thread.current.object_id, } @history_mon.synchronize { @history << info } end # for testing only def __queue__ # :nodoc: @queue end end end PKu]n rake-13.0.1/lib/rake/version.rbnu[# frozen_string_literal: true module Rake VERSION = "13.0.1" module Version # :nodoc: all MAJOR, MINOR, BUILD, *OTHER = Rake::VERSION.split "." NUMBERS = [MAJOR, MINOR, BUILD, *OTHER] end end PKu]^  rake-13.0.1/lib/rake/promise.rbnu[# frozen_string_literal: true module Rake # A Promise object represents a promise to do work (a chore) in the # future. The promise is created with a block and a list of # arguments for the block. Calling value will return the value of # the promised chore. # # Used by ThreadPool. # class Promise # :nodoc: all NOT_SET = Object.new.freeze # :nodoc: attr_accessor :recorder # Create a promise to do the chore specified by the block. def initialize(args, &block) @mutex = Mutex.new @result = NOT_SET @error = NOT_SET @args = args @block = block end # Return the value of this promise. # # If the promised chore is not yet complete, then do the work # synchronously. We will wait. def value unless complete? stat :sleeping_on, item_id: object_id @mutex.synchronize do stat :has_lock_on, item_id: object_id chore stat :releasing_lock_on, item_id: object_id end end error? ? raise(@error) : @result end # If no one else is working this promise, go ahead and do the chore. def work stat :attempting_lock_on, item_id: object_id if @mutex.try_lock stat :has_lock_on, item_id: object_id chore stat :releasing_lock_on, item_id: object_id @mutex.unlock else stat :bailed_on, item_id: object_id end end private # Perform the chore promised def chore if complete? stat :found_completed, item_id: object_id return end stat :will_execute, item_id: object_id begin @result = @block.call(*@args) rescue Exception => e @error = e end stat :did_execute, item_id: object_id discard end # Do we have a result for the promise def result? !@result.equal?(NOT_SET) end # Did the promise throw an error def error? !@error.equal?(NOT_SET) end # Are we done with the promise def complete? result? || error? end # free up these items for the GC def discard @args = nil @block = nil end # Record execution statistics if there is a recorder def stat(*args) @recorder.call(*args) if @recorder end end end PKu]YY"rake-13.0.1/lib/rake/multi_task.rbnu[# frozen_string_literal: true module Rake # Same as a regular task, but the immediate prerequisites are done in # parallel using Ruby threads. # class MultiTask < Task private def invoke_prerequisites(task_args, invocation_chain) # :nodoc: invoke_prerequisites_concurrently(task_args, invocation_chain) end end end PKu]jrake-13.0.1/lib/rake/win32.rbnu[# frozen_string_literal: true require "rbconfig" module Rake # Win 32 interface methods for Rake. Windows specific functionality # will be placed here to collect that knowledge in one spot. module Win32 # :nodoc: all # Error indicating a problem in locating the home directory on a # Win32 system. class Win32HomeError < RuntimeError end class << self # True if running on a windows system. def windows? RbConfig::CONFIG["host_os"] =~ %r!(msdos|mswin|djgpp|mingw|[Ww]indows)! end # The standard directory containing system wide rake files on # Win 32 systems. Try the following environment variables (in # order): # # * HOME # * HOMEDRIVE + HOMEPATH # * APPDATA # * USERPROFILE # # If the above are not defined, the return nil. def win32_system_dir #:nodoc: win32_shared_path = ENV["HOME"] if win32_shared_path.nil? && ENV["HOMEDRIVE"] && ENV["HOMEPATH"] win32_shared_path = ENV["HOMEDRIVE"] + ENV["HOMEPATH"] end win32_shared_path ||= ENV["APPDATA"] win32_shared_path ||= ENV["USERPROFILE"] raise Win32HomeError, "Unable to determine home path environment variable." if win32_shared_path.nil? or win32_shared_path.empty? normalize(File.join(win32_shared_path, "Rake")) end # Normalize a win32 path so that the slashes are all forward slashes. def normalize(path) path.gsub(/\\/, "/") end end end end PKu]Ӭs~~5rake-13.0.1/lib/rake/rule_recursion_overflow_error.rbnu[# frozen_string_literal: true module Rake # Error indicating a recursion overflow error in task selection. class RuleRecursionOverflowError < StandardError def initialize(*args) super @targets = [] end def add_target(target) @targets << target end def message super + ": [" + @targets.reverse.join(" => ") + "]" end end end PKu]0ZR&rake-13.0.1/lib/rake/private_reader.rbnu[# frozen_string_literal: true module Rake # Include PrivateReader to use +private_reader+. module PrivateReader # :nodoc: all def self.included(base) base.extend(ClassMethods) end module ClassMethods # Declare a list of private accessors def private_reader(*names) attr_reader(*names) private(*names) end end end end PKu]2rake-13.0.1/lib/rake/invocation_exception_mixin.rbnu[# frozen_string_literal: true module Rake module InvocationExceptionMixin # Return the invocation chain (list of Rake tasks) that were in # effect when this exception was detected by rake. May be null if # no tasks were active. def chain @rake_invocation_chain ||= nil end # Set the invocation chain in effect when this exception was # detected. def chain=(value) @rake_invocation_chain = value end end end PKu]R22rake-13.0.1/lib/rake/task.rbnu[# frozen_string_literal: true require "rake/invocation_exception_mixin" module Rake ## # A Task is the basic unit of work in a Rakefile. Tasks have associated # actions (possibly more than one) and a list of prerequisites. When # invoked, a task will first ensure that all of its prerequisites have an # opportunity to run and then it will execute its own actions. # # Tasks are not usually created directly using the new method, but rather # use the +file+ and +task+ convenience methods. # class Task # List of prerequisites for a task. attr_reader :prerequisites alias prereqs prerequisites # List of order only prerequisites for a task. attr_reader :order_only_prerequisites # List of actions attached to a task. attr_reader :actions # Application owning this task. attr_accessor :application # Array of nested namespaces names used for task lookup by this task. attr_reader :scope # File/Line locations of each of the task definitions for this # task (only valid if the task was defined with the detect # location option set). attr_reader :locations # Has this task already been invoked? Already invoked tasks # will be skipped unless you reenable them. attr_reader :already_invoked # Return task name def to_s name end def inspect # :nodoc: "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>" end # List of sources for task. attr_writer :sources def sources if defined?(@sources) @sources else prerequisites end end # List of prerequisite tasks def prerequisite_tasks (prerequisites + order_only_prerequisites).map { |pre| lookup_prerequisite(pre) } end def lookup_prerequisite(prerequisite_name) # :nodoc: scoped_prerequisite_task = application[prerequisite_name, @scope] if scoped_prerequisite_task == self unscoped_prerequisite_task = application[prerequisite_name] end unscoped_prerequisite_task || scoped_prerequisite_task end private :lookup_prerequisite # List of all unique prerequisite tasks including prerequisite tasks' # prerequisites. # Includes self when cyclic dependencies are found. def all_prerequisite_tasks seen = {} collect_prerequisites(seen) seen.values end def collect_prerequisites(seen) # :nodoc: prerequisite_tasks.each do |pre| next if seen[pre.name] seen[pre.name] = pre pre.collect_prerequisites(seen) end end protected :collect_prerequisites # First source from a rule (nil if no sources) def source sources.first end # Create a task named +task_name+ with no actions or prerequisites. Use # +enhance+ to add actions and prerequisites. def initialize(task_name, app) @name = task_name.to_s @prerequisites = [] @actions = [] @already_invoked = false @comments = [] @lock = Monitor.new @application = app @scope = app.current_scope @arg_names = nil @locations = [] @invocation_exception = nil @order_only_prerequisites = [] end # Enhance a task with prerequisites or actions. Returns self. def enhance(deps=nil, &block) @prerequisites |= deps if deps @actions << block if block_given? self end # Name of the task, including any namespace qualifiers. def name @name.to_s end # Name of task with argument list description. def name_with_args # :nodoc: if arg_description "#{name}#{arg_description}" else name end end # Argument description (nil if none). def arg_description # :nodoc: @arg_names ? "[#{arg_names.join(',')}]" : nil end # Name of arguments for this task. def arg_names @arg_names || [] end # Reenable the task, allowing its tasks to be executed if the task # is invoked again. def reenable @already_invoked = false @invocation_exception = nil end # Clear the existing prerequisites, actions, comments, and arguments of a rake task. def clear clear_prerequisites clear_actions clear_comments clear_args self end # Clear the existing prerequisites of a rake task. def clear_prerequisites prerequisites.clear self end # Clear the existing actions on a rake task. def clear_actions actions.clear self end # Clear the existing comments on a rake task. def clear_comments @comments = [] self end # Clear the existing arguments on a rake task. def clear_args @arg_names = nil self end # Invoke the task if it is needed. Prerequisites are invoked first. def invoke(*args) task_args = TaskArguments.new(arg_names, args) invoke_with_call_chain(task_args, InvocationChain::EMPTY) end # Same as invoke, but explicitly pass a call chain to detect # circular dependencies. # # If multiple tasks depend on this # one in parallel, they will all fail if the first execution of # this task fails. def invoke_with_call_chain(task_args, invocation_chain) new_chain = Rake::InvocationChain.append(self, invocation_chain) @lock.synchronize do begin if application.options.trace application.trace "** Invoke #{name} #{format_trace_flags}" end if @already_invoked if @invocation_exception if application.options.trace application.trace "** Previous invocation of #{name} failed #{format_trace_flags}" end raise @invocation_exception else return end end @already_invoked = true invoke_prerequisites(task_args, new_chain) execute(task_args) if needed? rescue Exception => ex add_chain_to(ex, new_chain) @invocation_exception = ex raise ex end end end protected :invoke_with_call_chain def add_chain_to(exception, new_chain) # :nodoc: exception.extend(InvocationExceptionMixin) unless exception.respond_to?(:chain) exception.chain = new_chain if exception.chain.nil? end private :add_chain_to # Invoke all the prerequisites of a task. def invoke_prerequisites(task_args, invocation_chain) # :nodoc: if application.options.always_multitask invoke_prerequisites_concurrently(task_args, invocation_chain) else prerequisite_tasks.each { |p| prereq_args = task_args.new_scope(p.arg_names) p.invoke_with_call_chain(prereq_args, invocation_chain) } end end # Invoke all the prerequisites of a task in parallel. def invoke_prerequisites_concurrently(task_args, invocation_chain)# :nodoc: futures = prerequisite_tasks.map do |p| prereq_args = task_args.new_scope(p.arg_names) application.thread_pool.future(p) do |r| r.invoke_with_call_chain(prereq_args, invocation_chain) end end # Iterate in reverse to improve performance related to thread waiting and switching futures.reverse_each(&:value) end # Format the trace flags for display. def format_trace_flags flags = [] flags << "first_time" unless @already_invoked flags << "not_needed" unless needed? flags.empty? ? "" : "(" + flags.join(", ") + ")" end private :format_trace_flags # Execute the actions associated with this task. def execute(args=nil) args ||= EMPTY_TASK_ARGS if application.options.dryrun application.trace "** Execute (dry run) #{name}" return end application.trace "** Execute #{name}" if application.options.trace application.enhance_with_matching_rule(name) if @actions.empty? if opts = Hash.try_convert(args) and !opts.empty? @actions.each { |act| act.call(self, args, **opts)} else @actions.each { |act| act.call(self, args)} end end # Is this task needed? def needed? true end # Timestamp for this task. Basic tasks return the current time for their # time stamp. Other tasks can be more sophisticated. def timestamp Time.now end # Add a description to the task. The description can consist of an option # argument list (enclosed brackets) and an optional comment. def add_description(description) return unless description comment = description.strip add_comment(comment) if comment && !comment.empty? end def comment=(comment) # :nodoc: add_comment(comment) end def add_comment(comment) # :nodoc: return if comment.nil? @comments << comment unless @comments.include?(comment) end private :add_comment # Full collection of comments. Multiple comments are separated by # newlines. def full_comment transform_comments("\n") end # First line (or sentence) of all comments. Multiple comments are # separated by a "/". def comment transform_comments(" / ") { |c| first_sentence(c) } end # Transform the list of comments as specified by the block and # join with the separator. def transform_comments(separator, &block) if @comments.empty? nil else block ||= lambda { |c| c } @comments.map(&block).join(separator) end end private :transform_comments # Get the first sentence in a string. The sentence is terminated # by the first period, exclamation mark, or the end of the line. # Decimal points do not count as periods. def first_sentence(string) string.split(/(?<=\w)(\.|!)[ \t]|(\.$|!)|\n/).first end private :first_sentence # Set the names of the arguments for this task. +args+ should be # an array of symbols, one for each argument name. def set_arg_names(args) @arg_names = args.map(&:to_sym) end # Return a string describing the internal state of a task. Useful for # debugging. def investigation result = "------------------------------\n".dup result << "Investigating #{name}\n" result << "class: #{self.class}\n" result << "task needed: #{needed?}\n" result << "timestamp: #{timestamp}\n" result << "pre-requisites: \n" prereqs = prerequisite_tasks prereqs.sort! { |a, b| a.timestamp <=> b.timestamp } prereqs.each do |p| result << "--#{p.name} (#{p.timestamp})\n" end latest_prereq = prerequisite_tasks.map(&:timestamp).max result << "latest-prerequisite time: #{latest_prereq}\n" result << "................................\n\n" return result end # Format dependencies parameter to pass to task. def self.format_deps(deps) deps = [deps] unless deps.respond_to?(:to_ary) deps.map { |d| Rake.from_pathname(d).to_s } end # Add order only dependencies. def |(deps) @order_only_prerequisites |= Task.format_deps(deps) - @prerequisites self end # ---------------------------------------------------------------- # Rake Module Methods # class << self # Clear the task list. This cause rake to immediately forget all the # tasks that have been assigned. (Normally used in the unit tests.) def clear Rake.application.clear end # List of all defined tasks. def tasks Rake.application.tasks end # Return a task with the given name. If the task is not currently # known, try to synthesize one from the defined rules. If no rules are # found, but an existing file matches the task name, assume it is a file # task with no dependencies or actions. def [](task_name) Rake.application[task_name] end # TRUE if the task name is already defined. def task_defined?(task_name) Rake.application.lookup(task_name) != nil end # Define a task given +args+ and an option block. If a rule with the # given name already exists, the prerequisites and actions are added to # the existing task. Returns the defined task. def define_task(*args, &block) Rake.application.define_task(self, *args, &block) end # Define a rule for synthesizing tasks. def create_rule(*args, &block) Rake.application.create_rule(*args, &block) end # Apply the scope to the task name according to the rules for # this kind of task. Generic tasks will accept the scope as # part of the name. def scope_name(scope, task_name) scope.path_with_task_name(task_name) end end # class << Rake::Task end # class Rake::Task end PKu]i  &rake-13.0.1/lib/rake/default_loader.rbnu[# frozen_string_literal: true module Rake # Default Rakefile loader used by +import+. class DefaultLoader ## # Loads a rakefile into the current application from +fn+ def load(fn) Rake.load_rakefile(File.expand_path(fn)) end end end PKu]l??$rake-13.0.1/lib/rake/trace_output.rbnu[# frozen_string_literal: true module Rake module TraceOutput # :nodoc: all # Write trace output to output stream +out+. # # The write is done as a single IO call (to print) to lessen the # chance that the trace output is interrupted by other tasks also # producing output. def trace_on(out, *strings) sep = $\ || "\n" if strings.empty? output = sep else output = strings.map { |s| next if s.nil? s.end_with?(sep) ? s : s + sep }.join end out.print(output) end end end PKu]I!rake-13.0.1/lib/rake/file_task.rbnu[# frozen_string_literal: true require "rake/task" require "rake/early_time" module Rake # A FileTask is a task that includes time based dependencies. If any of a # FileTask's prerequisites have a timestamp that is later than the file # represented by this task, then the file must be rebuilt (using the # supplied actions). # class FileTask < Task # Is this file task needed? Yes if it doesn't exist, or if its time stamp # is out of date. def needed? !File.exist?(name) || out_of_date?(timestamp) || @application.options.build_all end # Time stamp for file task. def timestamp if File.exist?(name) File.mtime(name.to_s) else Rake::LATE end end private # Are there any prerequisites with a later time than the given time stamp? def out_of_date?(stamp) all_prerequisite_tasks.any? { |prereq| prereq_task = application[prereq, @scope] if prereq_task.instance_of?(Rake::FileTask) prereq_task.timestamp > stamp || @application.options.build_all else prereq_task.timestamp > stamp end } end # ---------------------------------------------------------------- # Task class methods. # class << self # Apply the scope to the task name according to the rules for this kind # of task. File based tasks ignore the scope when creating the name. def scope_name(scope, task_name) Rake.from_pathname(task_name) end end end end PKu]p,۞ rake-13.0.1/lib/rake/testtask.rbnu[# frozen_string_literal: true require "rake" require "rake/tasklib" module Rake # Create a task that runs a set of tests. # # Example: # require "rake/testtask" # # Rake::TestTask.new do |t| # t.libs << "test" # t.test_files = FileList['test/test*.rb'] # t.verbose = true # end # # If rake is invoked with a "TEST=filename" command line option, # then the list of test files will be overridden to include only the # filename specified on the command line. This provides an easy way # to run just one test. # # If rake is invoked with a "TESTOPTS=options" command line option, # then the given options are passed to the test process after a # '--'. This allows Test::Unit options to be passed to the test # suite. # # Examples: # # rake test # run tests normally # rake test TEST=just_one_file.rb # run just one test file. # rake test TESTOPTS="-v" # run in verbose mode # rake test TESTOPTS="--runner=fox" # use the fox test runner # class TestTask < TaskLib # Name of test task. (default is :test) attr_accessor :name # List of directories added to $LOAD_PATH before running the # tests. (default is 'lib') attr_accessor :libs # True if verbose test output desired. (default is false) attr_accessor :verbose # Test options passed to the test suite. An explicit # TESTOPTS=opts on the command line will override this. (default # is NONE) attr_accessor :options # Request that the tests be run with the warning flag set. # E.g. warning=true implies "ruby -w" used to run the tests. # (default is true) attr_accessor :warning # Glob pattern to match test files. (default is 'test/test*.rb') attr_accessor :pattern # Style of test loader to use. Options are: # # * :rake -- Rake provided test loading script (default). # * :testrb -- Ruby provided test loading script. # * :direct -- Load tests using command line loader. # attr_accessor :loader # Array of command line options to pass to ruby when running test loader. attr_accessor :ruby_opts # Description of the test task. (default is 'Run tests') attr_accessor :description # Task prerequisites. attr_accessor :deps # Explicitly define the list of test files to be included in a # test. +list+ is expected to be an array of file names (a # FileList is acceptable). If both +pattern+ and +test_files+ are # used, then the list of test files is the union of the two. def test_files=(list) @test_files = list end # Create a testing task. def initialize(name=:test) @name = name @libs = ["lib"] @pattern = nil @options = nil @test_files = nil @verbose = false @warning = true @loader = :rake @ruby_opts = [] @description = "Run tests" + (@name == :test ? "" : " for #{@name}") @deps = [] if @name.is_a?(Hash) @deps = @name.values.first @name = @name.keys.first end yield self if block_given? @pattern = "test/test*.rb" if @pattern.nil? && @test_files.nil? define end # Create the tasks defined by this task lib. def define desc @description task @name => Array(deps) do FileUtilsExt.verbose(@verbose) do puts "Use TESTOPTS=\"--verbose\" to pass --verbose" \ ", etc. to runners." if ARGV.include? "--verbose" args = "#{ruby_opts_string} #{run_code} " + "#{file_list_string} #{option_list}" ruby args do |ok, status| if !ok && status.respond_to?(:signaled?) && status.signaled? raise SignalException.new(status.termsig) elsif !ok status = "Command failed with status (#{status.exitstatus})" details = ": [ruby #{args}]" message = if Rake.application.options.trace or @verbose status + details else status end fail message end end end end self end def option_list # :nodoc: (ENV["TESTOPTS"] || ENV["TESTOPT"] || ENV["TEST_OPTS"] || ENV["TEST_OPT"] || @options || "") end def ruby_opts_string # :nodoc: opts = @ruby_opts.dup opts.unshift("-I\"#{lib_path}\"") unless @libs.empty? opts.unshift("-w") if @warning opts.join(" ") end def lib_path # :nodoc: @libs.join(File::PATH_SEPARATOR) end def file_list_string # :nodoc: file_list.map { |fn| "\"#{fn}\"" }.join(" ") end def file_list # :nodoc: if ENV["TEST"] FileList[ENV["TEST"]] else result = [] result += @test_files.to_a if @test_files result += FileList[@pattern].to_a if @pattern result end end def ruby_version # :nodoc: RUBY_VERSION end def run_code # :nodoc: case @loader when :direct "-e \"ARGV.each{|f| require f}\"" when :testrb "-S testrb" when :rake "#{rake_include_arg} \"#{rake_loader}\"" end end def rake_loader # :nodoc: find_file("rake/rake_test_loader") or fail "unable to find rake test loader" end def find_file(fn) # :nodoc: $LOAD_PATH.each do |path| file_path = File.join(path, "#{fn}.rb") return file_path if File.exist? file_path end nil end def rake_include_arg # :nodoc: spec = Gem.loaded_specs["rake"] if spec.respond_to?(:default_gem?) && spec.default_gem? "" else "-I\"#{rake_lib_dir}\"" end end def rake_lib_dir # :nodoc: find_dir("rake") or fail "unable to find rake lib" end def find_dir(fn) # :nodoc: $LOAD_PATH.each do |path| file_path = File.join(path, "#{fn}.rb") return path if File.exist? file_path end nil end end end PKu]lD"rake-13.0.1/lib/rake/name_space.rbnu[# frozen_string_literal: true ## # The NameSpace class will lookup task names in the scope defined by a # +namespace+ command. class Rake::NameSpace ## # Create a namespace lookup object using the given task manager # and the list of scopes. def initialize(task_manager, scope_list) @task_manager = task_manager @scope = scope_list.dup end ## # Lookup a task named +name+ in the namespace. def [](name) @task_manager.lookup(name, @scope) end ## # The scope of the namespace (a LinkedList) def scope @scope.dup end ## # Return the list of tasks defined in this and nested namespaces. def tasks @task_manager.tasks_in_scope(@scope) end end PKu]m.rake-13.0.1/lib/rake/thread_history_display.rbnu[# frozen_string_literal: true require "rake/private_reader" module Rake class ThreadHistoryDisplay # :nodoc: all include Rake::PrivateReader private_reader :stats, :items, :threads def initialize(stats) @stats = stats @items = { _seq_: 1 } @threads = { _seq_: "A" } end def show puts "Job History:" stats.each do |stat| stat[:data] ||= {} rename(stat, :thread, threads) rename(stat[:data], :item_id, items) rename(stat[:data], :new_thread, threads) rename(stat[:data], :deleted_thread, threads) printf("%8d %2s %-20s %s\n", (stat[:time] * 1_000_000).round, stat[:thread], stat[:event], stat[:data].map do |k, v| "#{k}:#{v}" end.join(" ")) end end private def rename(hash, key, renames) if hash && hash[key] original = hash[key] value = renames[original] unless value value = renames[:_seq_] renames[:_seq_] = renames[:_seq_].succ renames[original] = value end hash[key] = value end end end end PKu]Jሀ!rake-13.0.1/lib/rake/backtrace.rbnu[# frozen_string_literal: true module Rake module Backtrace # :nodoc: all SYS_KEYS = RbConfig::CONFIG.keys.grep(/(?:[a-z]prefix|libdir)\z/) SYS_PATHS = RbConfig::CONFIG.values_at(*SYS_KEYS).uniq + [ File.join(File.dirname(__FILE__), "..") ] SUPPRESSED_PATHS = SYS_PATHS. map { |s| s.tr("\\", "/") }. map { |f| File.expand_path(f) }. reject { |s| s.nil? || s =~ /^ *$/ } SUPPRESSED_PATHS_RE = SUPPRESSED_PATHS.map { |f| Regexp.quote(f) }.join("|") SUPPRESSED_PATHS_RE << "|^org\\/jruby\\/\\w+\\.java" if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == "jruby" SUPPRESS_PATTERN = %r!(\A(#{SUPPRESSED_PATHS_RE})|bin/rake:\d+)!i def self.collapse(backtrace) pattern = Rake.application.options.suppress_backtrace_pattern || SUPPRESS_PATTERN backtrace.reject { |elem| elem =~ pattern } end end end PKu]H bb#rake-13.0.1/lib/rake/application.rbnu[# frozen_string_literal: true require "optparse" require "rake/task_manager" require "rake/file_list" require "rake/thread_pool" require "rake/thread_history_display" require "rake/trace_output" require "rake/win32" module Rake CommandLineOptionError = Class.new(StandardError) ## # Rake main application object. When invoking +rake+ from the # command line, a Rake::Application object is created and run. class Application include TaskManager include TraceOutput # The name of the application (typically 'rake') attr_reader :name # The original directory where rake was invoked. attr_reader :original_dir # Name of the actual rakefile used. attr_reader :rakefile # Number of columns on the terminal attr_accessor :terminal_columns # List of the top level task names (task names from the command line). attr_reader :top_level_tasks # Override the detected TTY output state (mostly for testing) attr_writer :tty_output DEFAULT_RAKEFILES = [ "rakefile", "Rakefile", "rakefile.rb", "Rakefile.rb" ].freeze # Initialize a Rake::Application object. def initialize super @name = "rake" @rakefiles = DEFAULT_RAKEFILES.dup @rakefile = nil @pending_imports = [] @imported = [] @loaders = {} @default_loader = Rake::DefaultLoader.new @original_dir = Dir.pwd @top_level_tasks = [] add_loader("rb", DefaultLoader.new) add_loader("rf", DefaultLoader.new) add_loader("rake", DefaultLoader.new) @tty_output = STDOUT.tty? @terminal_columns = ENV["RAKE_COLUMNS"].to_i set_default_options end # Run the Rake application. The run method performs the following # three steps: # # * Initialize the command line options (+init+). # * Define the tasks (+load_rakefile+). # * Run the top level tasks (+top_level+). # # If you wish to build a custom rake command, you should call # +init+ on your application. Then define any tasks. Finally, # call +top_level+ to run your top level tasks. def run(argv = ARGV) standard_exception_handling do init "rake", argv load_rakefile top_level end end # Initialize the command line parameters and app name. def init(app_name="rake", argv = ARGV) standard_exception_handling do @name = app_name begin args = handle_options argv rescue ArgumentError # Backward compatibility for capistrano args = handle_options end collect_command_line_tasks(args) end end # Find the rakefile and then load it and any pending imports. def load_rakefile standard_exception_handling do raw_load_rakefile end end # Run the top level tasks of a Rake application. def top_level run_with_threads do if options.show_tasks display_tasks_and_comments elsif options.show_prereqs display_prerequisites else top_level_tasks.each { |task_name| invoke_task(task_name) } end end end # Run the given block with the thread startup and shutdown. def run_with_threads thread_pool.gather_history if options.job_stats == :history yield thread_pool.join if options.job_stats stats = thread_pool.statistics puts "Maximum active threads: #{stats[:max_active_threads]} + main" puts "Total threads in play: #{stats[:total_threads_in_play]} + main" end ThreadHistoryDisplay.new(thread_pool.history).show if options.job_stats == :history end # Add a loader to handle imported files ending in the extension # +ext+. def add_loader(ext, loader) ext = ".#{ext}" unless ext =~ /^\./ @loaders[ext] = loader end # Application options from the command line def options @options ||= OpenStruct.new end # Return the thread pool used for multithreaded processing. def thread_pool # :nodoc: @thread_pool ||= ThreadPool.new(options.thread_pool_size || Rake.suggested_thread_count-1) end # internal ---------------------------------------------------------------- # Invokes a task with arguments that are extracted from +task_string+ def invoke_task(task_string) # :nodoc: name, args = parse_task_string(task_string) t = self[name] t.invoke(*args) end def parse_task_string(string) # :nodoc: /^([^\[]+)(?:\[(.*)\])$/ =~ string.to_s name = $1 remaining_args = $2 return string, [] unless name return name, [] if remaining_args.empty? args = [] begin /\s*((?:[^\\,]|\\.)*?)\s*(?:,\s*(.*))?$/ =~ remaining_args remaining_args = $2 args << $1.gsub(/\\(.)/, '\1') end while remaining_args return name, args end # Provide standard exception handling for the given block. def standard_exception_handling # :nodoc: yield rescue SystemExit # Exit silently with current status raise rescue OptionParser::InvalidOption => ex $stderr.puts ex.message exit(false) rescue Exception => ex # Exit with error message display_error_message(ex) exit_because_of_exception(ex) end # Exit the program because of an unhandled exception. # (may be overridden by subclasses) def exit_because_of_exception(ex) # :nodoc: exit(false) end # Display the error message that caused the exception. def display_error_message(ex) # :nodoc: trace "#{name} aborted!" display_exception_details(ex) trace "Tasks: #{ex.chain}" if has_chain?(ex) trace "(See full trace by running task with --trace)" unless options.backtrace end def display_exception_details(ex) # :nodoc: display_exception_details_seen << ex display_exception_message_details(ex) display_exception_backtrace(ex) display_cause_details(ex.cause) if has_cause?(ex) end def display_cause_details(ex) # :nodoc: return if display_exception_details_seen.include? ex trace "\nCaused by:" display_exception_details(ex) end def display_exception_details_seen # :nodoc: Thread.current[:rake_display_exception_details_seen] ||= [] end def has_cause?(ex) # :nodoc: ex.respond_to?(:cause) && ex.cause end def display_exception_message_details(ex) # :nodoc: if ex.instance_of?(RuntimeError) trace ex.message else trace "#{ex.class.name}: #{ex.message}" end end def display_exception_backtrace(ex) # :nodoc: if options.backtrace trace ex.backtrace.join("\n") else trace Backtrace.collapse(ex.backtrace).join("\n") end end # Warn about deprecated usage. # # Example: # Rake.application.deprecate("import", "Rake.import", caller.first) # def deprecate(old_usage, new_usage, call_site) # :nodoc: unless options.ignore_deprecate $stderr.puts "WARNING: '#{old_usage}' is deprecated. " + "Please use '#{new_usage}' instead.\n" + " at #{call_site}" end end # Does the exception have a task invocation chain? def has_chain?(exception) # :nodoc: exception.respond_to?(:chain) && exception.chain end private :has_chain? # True if one of the files in RAKEFILES is in the current directory. # If a match is found, it is copied into @rakefile. def have_rakefile # :nodoc: @rakefiles.each do |fn| if File.exist?(fn) others = FileList.glob(fn, File::FNM_CASEFOLD) return others.size == 1 ? others.first : fn elsif fn == "" return fn end end return nil end # True if we are outputting to TTY, false otherwise def tty_output? # :nodoc: @tty_output end # We will truncate output if we are outputting to a TTY or if we've been # given an explicit column width to honor def truncate_output? # :nodoc: tty_output? || @terminal_columns.nonzero? end # Display the tasks and comments. def display_tasks_and_comments # :nodoc: displayable_tasks = tasks.select { |t| (options.show_all_tasks || t.comment) && t.name =~ options.show_task_pattern } case options.show_tasks when :tasks width = displayable_tasks.map { |t| t.name_with_args.length }.max || 10 if truncate_output? max_column = terminal_width - name.size - width - 7 else max_column = nil end displayable_tasks.each do |t| printf("#{name} %-#{width}s # %s\n", t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment) end when :describe displayable_tasks.each do |t| puts "#{name} #{t.name_with_args}" comment = t.full_comment || "" comment.split("\n").each do |line| puts " #{line}" end puts end when :lines displayable_tasks.each do |t| t.locations.each do |loc| printf "#{name} %-30s %s\n", t.name_with_args, loc end end else fail "Unknown show task mode: '#{options.show_tasks}'" end end def terminal_width # :nodoc: if @terminal_columns.nonzero? result = @terminal_columns else result = unix? ? dynamic_width : 80 end (result < 10) ? 80 : result rescue 80 end # Calculate the dynamic width of the def dynamic_width # :nodoc: @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput) end def dynamic_width_stty # :nodoc: %x{stty size 2>/dev/null}.split[1].to_i end def dynamic_width_tput # :nodoc: %x{tput cols 2>/dev/null}.to_i end def unix? # :nodoc: RbConfig::CONFIG["host_os"] =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i end def windows? # :nodoc: Win32.windows? end def truncate(string, width) # :nodoc: if string.nil? "" elsif string.length <= width string else (string[0, width - 3] || "") + "..." end end # Display the tasks and prerequisites def display_prerequisites # :nodoc: tasks.each do |t| puts "#{name} #{t.name}" t.prerequisites.each { |pre| puts " #{pre}" } end end def trace(*strings) # :nodoc: options.trace_output ||= $stderr trace_on(options.trace_output, *strings) end def sort_options(options) # :nodoc: options.sort_by { |opt| opt.select { |o| o.is_a?(String) && o =~ /^-/ }.map(&:downcase).sort.reverse } end private :sort_options # A list of all the standard options used in rake, suitable for # passing to OptionParser. def standard_rake_options # :nodoc: sort_options( [ ["--all", "-A", "Show all tasks, even uncommented ones (in combination with -T or -D)", lambda { |value| options.show_all_tasks = value } ], ["--backtrace=[OUT]", "Enable full backtrace. OUT can be stderr (default) or stdout.", lambda { |value| options.backtrace = true select_trace_output(options, "backtrace", value) } ], ["--build-all", "-B", "Build all prerequisites, including those which are up-to-date.", lambda { |value| options.build_all = true } ], ["--comments", "Show commented tasks only", lambda { |value| options.show_all_tasks = !value } ], ["--describe", "-D [PATTERN]", "Describe the tasks (matching optional PATTERN), then exit.", lambda { |value| select_tasks_to_show(options, :describe, value) } ], ["--dry-run", "-n", "Do a dry run without executing actions.", lambda { |value| Rake.verbose(true) Rake.nowrite(true) options.dryrun = true options.trace = true } ], ["--execute", "-e CODE", "Execute some Ruby code and exit.", lambda { |value| eval(value) exit } ], ["--execute-print", "-p CODE", "Execute some Ruby code, print the result, then exit.", lambda { |value| puts eval(value) exit } ], ["--execute-continue", "-E CODE", "Execute some Ruby code, " + "then continue with normal task processing.", lambda { |value| eval(value) } ], ["--jobs", "-j [NUMBER]", "Specifies the maximum number of tasks to execute in parallel. " + "(default is number of CPU cores + 4)", lambda { |value| if value.nil? || value == "" value = Float::INFINITY elsif value =~ /^\d+$/ value = value.to_i else value = Rake.suggested_thread_count end value = 1 if value < 1 options.thread_pool_size = value - 1 } ], ["--job-stats [LEVEL]", "Display job statistics. " + "LEVEL=history displays a complete job list", lambda { |value| if value =~ /^history/i options.job_stats = :history else options.job_stats = true end } ], ["--libdir", "-I LIBDIR", "Include LIBDIR in the search path for required modules.", lambda { |value| $:.push(value) } ], ["--multitask", "-m", "Treat all tasks as multitasks.", lambda { |value| options.always_multitask = true } ], ["--no-search", "--nosearch", "-N", "Do not search parent directories for the Rakefile.", lambda { |value| options.nosearch = true } ], ["--prereqs", "-P", "Display the tasks and dependencies, then exit.", lambda { |value| options.show_prereqs = true } ], ["--quiet", "-q", "Do not log messages to standard output.", lambda { |value| Rake.verbose(false) } ], ["--rakefile", "-f [FILENAME]", "Use FILENAME as the rakefile to search for.", lambda { |value| value ||= "" @rakefiles.clear @rakefiles << value } ], ["--rakelibdir", "--rakelib", "-R RAKELIBDIR", "Auto-import any .rake files in RAKELIBDIR. " + "(default is 'rakelib')", lambda { |value| options.rakelib = value.split(File::PATH_SEPARATOR) } ], ["--require", "-r MODULE", "Require MODULE before executing rakefile.", lambda { |value| begin require value rescue LoadError => ex begin rake_require value rescue LoadError raise ex end end } ], ["--rules", "Trace the rules resolution.", lambda { |value| options.trace_rules = true } ], ["--silent", "-s", "Like --quiet, but also suppresses the " + "'in directory' announcement.", lambda { |value| Rake.verbose(false) options.silent = true } ], ["--suppress-backtrace PATTERN", "Suppress backtrace lines matching regexp PATTERN. " + "Ignored if --trace is on.", lambda { |value| options.suppress_backtrace_pattern = Regexp.new(value) } ], ["--system", "-g", "Using system wide (global) rakefiles " + "(usually '~/.rake/*.rake').", lambda { |value| options.load_system = true } ], ["--no-system", "--nosystem", "-G", "Use standard project Rakefile search paths, " + "ignore system wide rakefiles.", lambda { |value| options.ignore_system = true } ], ["--tasks", "-T [PATTERN]", "Display the tasks (matching optional PATTERN) " + "with descriptions, then exit. " + "-AT combination displays all of tasks contained no description.", lambda { |value| select_tasks_to_show(options, :tasks, value) } ], ["--trace=[OUT]", "-t", "Turn on invoke/execute tracing, enable full backtrace. " + "OUT can be stderr (default) or stdout.", lambda { |value| options.trace = true options.backtrace = true select_trace_output(options, "trace", value) Rake.verbose(true) } ], ["--verbose", "-v", "Log message to standard output.", lambda { |value| Rake.verbose(true) } ], ["--version", "-V", "Display the program version.", lambda { |value| puts "rake, version #{Rake::VERSION}" exit } ], ["--where", "-W [PATTERN]", "Describe the tasks (matching optional PATTERN), then exit.", lambda { |value| select_tasks_to_show(options, :lines, value) options.show_all_tasks = true } ], ["--no-deprecation-warnings", "-X", "Disable the deprecation warnings.", lambda { |value| options.ignore_deprecate = true } ], ]) end def select_tasks_to_show(options, show_tasks, value) # :nodoc: options.show_tasks = show_tasks options.show_task_pattern = Regexp.new(value || "") Rake::TaskManager.record_task_metadata = true end private :select_tasks_to_show def select_trace_output(options, trace_option, value) # :nodoc: value = value.strip unless value.nil? case value when "stdout" options.trace_output = $stdout when "stderr", nil options.trace_output = $stderr else fail CommandLineOptionError, "Unrecognized --#{trace_option} option '#{value}'" end end private :select_trace_output # Read and handle the command line options. Returns the command line # arguments that we didn't understand, which should (in theory) be just # task names and env vars. def handle_options(argv) # :nodoc: set_default_options OptionParser.new do |opts| opts.banner = "#{Rake.application.name} [-f rakefile] {options} targets..." opts.separator "" opts.separator "Options are ..." opts.on_tail("-h", "--help", "-H", "Display this help message.") do puts opts exit end standard_rake_options.each { |args| opts.on(*args) } opts.environment("RAKEOPT") end.parse(argv) end # Similar to the regular Ruby +require+ command, but will check # for *.rake files in addition to *.rb files. def rake_require(file_name, paths=$LOAD_PATH, loaded=$") # :nodoc: fn = file_name + ".rake" return false if loaded.include?(fn) paths.each do |path| full_path = File.join(path, fn) if File.exist?(full_path) Rake.load_rakefile(full_path) loaded << fn return true end end fail LoadError, "Can't find #{file_name}" end def find_rakefile_location # :nodoc: here = Dir.pwd until (fn = have_rakefile) Dir.chdir("..") return nil if Dir.pwd == here || options.nosearch here = Dir.pwd end [fn, here] ensure Dir.chdir(Rake.original_dir) end def print_rakefile_directory(location) # :nodoc: $stderr.puts "(in #{Dir.pwd})" unless options.silent or original_dir == location end def raw_load_rakefile # :nodoc: rakefile, location = find_rakefile_location if (!options.ignore_system) && (options.load_system || rakefile.nil?) && system_dir && File.directory?(system_dir) print_rakefile_directory(location) glob("#{system_dir}/*.rake") do |name| add_import name end else fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" if rakefile.nil? @rakefile = rakefile Dir.chdir(location) print_rakefile_directory(location) Rake.load_rakefile(File.expand_path(@rakefile)) if @rakefile && @rakefile != "" options.rakelib.each do |rlib| glob("#{rlib}/*.rake") do |name| add_import name end end end load_imports end def glob(path, &block) # :nodoc: FileList.glob(path.tr("\\", "/")).each(&block) end private :glob # The directory path containing the system wide rakefiles. def system_dir # :nodoc: @system_dir ||= begin if ENV["RAKE_SYSTEM"] ENV["RAKE_SYSTEM"] else standard_system_dir end end end # The standard directory containing system wide rake files. if Win32.windows? def standard_system_dir #:nodoc: Win32.win32_system_dir end else def standard_system_dir #:nodoc: File.join(File.expand_path("~"), ".rake") end end private :standard_system_dir # Collect the list of tasks on the command line. If no tasks are # given, return a list containing only the default task. # Environmental assignments are processed at this time as well. # # `args` is the list of arguments to peruse to get the list of tasks. # It should be the command line that was given to rake, less any # recognised command-line options, which OptionParser.parse will # have taken care of already. def collect_command_line_tasks(args) # :nodoc: @top_level_tasks = [] args.each do |arg| if arg =~ /^(\w+)=(.*)$/m ENV[$1] = $2 else @top_level_tasks << arg unless arg =~ /^-/ end end @top_level_tasks.push(default_task_name) if @top_level_tasks.empty? end # Default task name ("default"). # (May be overridden by subclasses) def default_task_name # :nodoc: "default" end # Add a file to the list of files to be imported. def add_import(fn) # :nodoc: @pending_imports << fn end # Load the pending list of imported files. def load_imports # :nodoc: while fn = @pending_imports.shift next if @imported.member?(fn) fn_task = lookup(fn) and fn_task.invoke ext = File.extname(fn) loader = @loaders[ext] || @default_loader loader.load(fn) if fn_task = lookup(fn) and fn_task.needed? fn_task.reenable fn_task.invoke loader.load(fn) end @imported << fn end end def rakefile_location(backtrace=caller) # :nodoc: backtrace.map { |t| t[/([^:]+):/, 1] } re = /^#{@rakefile}$/ re = /#{re.source}/i if windows? backtrace.find { |str| str =~ re } || "" end def set_default_options # :nodoc: options.always_multitask = false options.backtrace = false options.build_all = false options.dryrun = false options.ignore_deprecate = false options.ignore_system = false options.job_stats = false options.load_system = false options.nosearch = false options.rakelib = %w[rakelib] options.show_all_tasks = false options.show_prereqs = false options.show_task_pattern = nil options.show_tasks = nil options.silent = false options.suppress_backtrace_pattern = nil options.thread_pool_size = Rake.suggested_thread_count options.trace = false options.trace_output = $stderr options.trace_rules = false end end end PKu]Q#rake-13.0.1/lib/rake/rake_module.rbnu[# frozen_string_literal: true require "rake/application" module Rake class << self # Current Rake Application def application @application ||= Rake::Application.new end # Set the current Rake application object. def application=(app) @application = app end def suggested_thread_count # :nodoc: @cpu_count ||= Rake::CpuCounter.count @cpu_count + 4 end # Return the original directory where the Rake application was started. def original_dir application.original_dir end # Load a rakefile. def load_rakefile(path) load(path) end # Add files to the rakelib list def add_rakelib(*files) application.options.rakelib ||= [] application.options.rakelib.concat(files) end # Make +block_application+ the default rake application inside a block so # you can load rakefiles into a different application. # # This is useful when you want to run rake tasks inside a library without # running rake in a sub-shell. # # Example: # # Dir.chdir 'other/directory' # # other_rake = Rake.with_application do |rake| # rake.load_rakefile # end # # puts other_rake.tasks def with_application(block_application = Rake::Application.new) orig_application = Rake.application Rake.application = block_application yield block_application block_application ensure Rake.application = orig_application end end end PKu]-x= ( ($rake-13.0.1/lib/rake/task_manager.rbnu[# frozen_string_literal: true module Rake # The TaskManager module is a mixin for managing tasks. module TaskManager # Track the last comment made in the Rakefile. attr_accessor :last_description def initialize # :nodoc: super @tasks = Hash.new @rules = Array.new @scope = Scope.make @last_description = nil end def create_rule(*args, &block) # :nodoc: pattern, args, deps, order_only = resolve_args(args) pattern = Regexp.new(Regexp.quote(pattern) + "$") if String === pattern @rules << [pattern, args, deps, order_only, block] end def define_task(task_class, *args, &block) # :nodoc: task_name, arg_names, deps, order_only = resolve_args(args) original_scope = @scope if String === task_name and not task_class.ancestors.include? Rake::FileTask task_name, *definition_scope = *(task_name.split(":").reverse) @scope = Scope.make(*(definition_scope + @scope.to_a)) end task_name = task_class.scope_name(@scope, task_name) task = intern(task_class, task_name) task.set_arg_names(arg_names) unless arg_names.empty? if Rake::TaskManager.record_task_metadata add_location(task) task.add_description(get_description(task)) end task.enhance(Task.format_deps(deps), &block) task | order_only unless order_only.nil? task ensure @scope = original_scope end # Lookup a task. Return an existing task if found, otherwise # create a task of the current type. def intern(task_class, task_name) @tasks[task_name.to_s] ||= task_class.new(task_name, self) end # Find a matching task for +task_name+. def [](task_name, scopes=nil) task_name = task_name.to_s self.lookup(task_name, scopes) or enhance_with_matching_rule(task_name) or synthesize_file_task(task_name) or fail generate_message_for_undefined_task(task_name) end def generate_message_for_undefined_task(task_name) message = "Don't know how to build task '#{task_name}' "\ "(See the list of available tasks with `#{Rake.application.name} --tasks`)" message + generate_did_you_mean_suggestions(task_name) end def generate_did_you_mean_suggestions(task_name) return "" unless defined?(::DidYouMean::SpellChecker) suggestions = ::DidYouMean::SpellChecker.new(dictionary: @tasks.keys).correct(task_name.to_s) if ::DidYouMean.respond_to?(:formatter)# did_you_mean v1.2.0 or later ::DidYouMean.formatter.message_for(suggestions) elsif defined?(::DidYouMean::Formatter) # before did_you_mean v1.2.0 ::DidYouMean::Formatter.new(suggestions).to_s else "" end end def synthesize_file_task(task_name) # :nodoc: return nil unless File.exist?(task_name) define_task(Rake::FileTask, task_name) end # Resolve the arguments for a task/rule. Returns a tuple of # [task_name, arg_name_list, prerequisites, order_only_prerequisites]. def resolve_args(args) if args.last.is_a?(Hash) deps = args.pop resolve_args_with_dependencies(args, deps) else resolve_args_without_dependencies(args) end end # Resolve task arguments for a task or rule when there are no # dependencies declared. # # The patterns recognized by this argument resolving function are: # # task :t # task :t, [:a] # def resolve_args_without_dependencies(args) task_name = args.shift if args.size == 1 && args.first.respond_to?(:to_ary) arg_names = args.first.to_ary else arg_names = args end [task_name, arg_names, [], nil] end private :resolve_args_without_dependencies # Resolve task arguments for a task or rule when there are # dependencies declared. # # The patterns recognized by this argument resolving function are: # # task :t, order_only: [:e] # task :t => [:d] # task :t => [:d], order_only: [:e] # task :t, [a] => [:d] # task :t, [a] => [:d], order_only: [:e] # def resolve_args_with_dependencies(args, hash) # :nodoc: fail "Task Argument Error" if hash.size != 1 && (hash.size != 2 || !hash.key?(:order_only)) order_only = hash.delete(:order_only) key, value = hash.map { |k, v| [k, v] }.first if args.empty? task_name = key arg_names = [] deps = value || [] else task_name = args.shift arg_names = key || args.shift|| [] deps = value || [] end deps = [deps] unless deps.respond_to?(:to_ary) [task_name, arg_names, deps, order_only] end private :resolve_args_with_dependencies # If a rule can be found that matches the task name, enhance the # task with the prerequisites and actions from the rule. Set the # source attribute of the task appropriately for the rule. Return # the enhanced task or nil of no rule was found. def enhance_with_matching_rule(task_name, level=0) fail Rake::RuleRecursionOverflowError, "Rule Recursion Too Deep" if level >= 16 @rules.each do |pattern, args, extensions, order_only, block| if pattern && pattern.match(task_name) task = attempt_rule(task_name, pattern, args, extensions, block, level) task | order_only unless order_only.nil? return task if task end end nil rescue Rake::RuleRecursionOverflowError => ex ex.add_target(task_name) fail ex end # List of all defined tasks in this application. def tasks @tasks.values.sort_by { |t| t.name } end # List of all the tasks defined in the given scope (and its # sub-scopes). def tasks_in_scope(scope) prefix = scope.path tasks.select { |t| /^#{prefix}:/ =~ t.name } end # Clear all tasks in this application. def clear @tasks.clear @rules.clear end # Lookup a task, using scope and the scope hints in the task name. # This method performs straight lookups without trying to # synthesize file tasks or rules. Special scope names (e.g. '^') # are recognized. If no scope argument is supplied, use the # current scope. Return nil if the task cannot be found. def lookup(task_name, initial_scope=nil) initial_scope ||= @scope task_name = task_name.to_s if task_name =~ /^rake:/ scopes = Scope.make task_name = task_name.sub(/^rake:/, "") elsif task_name =~ /^(\^+)/ scopes = initial_scope.trim($1.size) task_name = task_name.sub(/^(\^+)/, "") else scopes = initial_scope end lookup_in_scope(task_name, scopes) end # Lookup the task name def lookup_in_scope(name, scope) loop do tn = scope.path_with_task_name(name) task = @tasks[tn] return task if task break if scope.empty? scope = scope.tail end nil end private :lookup_in_scope # Return the list of scope names currently active in the task # manager. def current_scope @scope end # Evaluate the block in a nested namespace named +name+. Create # an anonymous namespace if +name+ is nil. def in_namespace(name) name ||= generate_name @scope = Scope.new(name, @scope) ns = NameSpace.new(self, @scope) yield(ns) ns ensure @scope = @scope.tail end private # Add a location to the locations field of the given task. def add_location(task) loc = find_location task.locations << loc if loc task end # Find the location that called into the dsl layer. def find_location locations = caller i = 0 while locations[i] return locations[i + 1] if locations[i] =~ /rake\/dsl_definition.rb/ i += 1 end nil end # Generate an anonymous namespace name. def generate_name @seed ||= 0 @seed += 1 "_anon_#{@seed}" end def trace_rule(level, message) # :nodoc: options.trace_output.puts "#{" " * level}#{message}" if Rake.application.options.trace_rules end # Attempt to create a rule given the list of prerequisites. def attempt_rule(task_name, task_pattern, args, extensions, block, level) sources = make_sources(task_name, task_pattern, extensions) prereqs = sources.map { |source| trace_rule level, "Attempting Rule #{task_name} => #{source}" if File.exist?(source) || Rake::Task.task_defined?(source) trace_rule level, "(#{task_name} => #{source} ... EXIST)" source elsif parent = enhance_with_matching_rule(source, level + 1) trace_rule level, "(#{task_name} => #{source} ... ENHANCE)" parent.name else trace_rule level, "(#{task_name} => #{source} ... FAIL)" return nil end } task = FileTask.define_task(task_name, { args => prereqs }, &block) task.sources = prereqs task end # Make a list of sources from the list of file name extensions / # translation procs. def make_sources(task_name, task_pattern, extensions) result = extensions.map { |ext| case ext when /%/ task_name.pathmap(ext) when %r{/} ext when /^\./ source = task_name.sub(task_pattern, ext) source == ext ? task_name.ext(ext) : source when String ext when Proc, Method if ext.arity == 1 ext.call(task_name) else ext.call end else fail "Don't know how to handle rule dependent: #{ext.inspect}" end } result.flatten end # Return the current description, clearing it in the process. def get_description(task) desc = @last_description @last_description = nil desc end class << self attr_accessor :record_task_metadata # :nodoc: TaskManager.record_task_metadata = false end end end PKu]~y &rake-13.0.1/lib/rake/task_arguments.rbnu[# frozen_string_literal: true module Rake ## # TaskArguments manage the arguments passed to a task. # class TaskArguments include Enumerable # Argument names attr_reader :names # Create a TaskArgument object with a list of argument +names+ and a set # of associated +values+. +parent+ is the parent argument object. def initialize(names, values, parent=nil) @names = names @parent = parent @hash = {} @values = values names.each_with_index { |name, i| next if values[i].nil? || values[i] == "" @hash[name.to_sym] = values[i] } end # Retrieve the complete array of sequential values def to_a @values.dup end # Retrieve the list of values not associated with named arguments def extras @values[@names.length..-1] || [] end # Create a new argument scope using the prerequisite argument # names. def new_scope(names) values = names.map { |n| self[n] } self.class.new(names, values + extras, self) end # Find an argument value by name or index. def [](index) lookup(index.to_sym) end # Specify a hash of default values for task arguments. Use the # defaults only if there is no specific value for the given # argument. def with_defaults(defaults) @hash = defaults.merge(@hash) end # Enumerates the arguments and their values def each(&block) @hash.each(&block) end # Extracts the argument values at +keys+ def values_at(*keys) keys.map { |k| lookup(k) } end # Returns the value of the given argument via method_missing def method_missing(sym, *args) lookup(sym.to_sym) end # Returns a Hash of arguments and their values def to_hash @hash.dup end def to_s # :nodoc: inspect end def inspect # :nodoc: inspection = @hash.map do |k,v| "#{k.to_s}: #{v.to_s}" end.join(", ") "#<#{self.class} #{inspection}>" end # Returns true if +key+ is one of the arguments def has_key?(key) @hash.has_key?(key) end alias key? has_key? def fetch(*args, &block) @hash.fetch(*args, &block) end protected def lookup(name) # :nodoc: if @hash.has_key?(name) @hash[name] elsif @parent @parent.lookup(name) end end end EMPTY_TASK_ARGS = TaskArguments.new([], []) # :nodoc: end PKu]K%rake-13.0.1/lib/rake/pseudo_status.rbnu[# frozen_string_literal: true module Rake ## # Exit status class for times the system just gives us a nil. class PseudoStatus # :nodoc: all attr_reader :exitstatus def initialize(code=0) @exitstatus = code end def to_i @exitstatus << 8 end def >>(n) to_i >> n end def stopped? false end def exited? true end end end PKu]M M #rake-13.0.1/lib/rake/cpu_counter.rbnu[# frozen_string_literal: true module Rake # Based on a script at: # http://stackoverflow.com/questions/891537/ruby-detect-number-of-cpus-installed class CpuCounter # :nodoc: all def self.count new.count_with_default end def count_with_default(default=4) count || default rescue StandardError default end begin require "etc" rescue LoadError else if Etc.respond_to?(:nprocessors) def count return Etc.nprocessors end end end end end unless Rake::CpuCounter.method_defined?(:count) Rake::CpuCounter.class_eval <<-'end;', __FILE__, __LINE__+1 require 'rbconfig' def count if RUBY_PLATFORM == 'java' count_via_java_runtime else case RbConfig::CONFIG['host_os'] when /linux/ count_via_cpuinfo when /darwin|bsd/ count_via_sysctl when /mswin|mingw/ count_via_win32 else # Try everything count_via_win32 || count_via_sysctl || count_via_cpuinfo end end end def count_via_java_runtime Java::Java.lang.Runtime.getRuntime.availableProcessors rescue StandardError nil end def count_via_win32 require 'win32ole' wmi = WIN32OLE.connect("winmgmts://") cpu = wmi.ExecQuery("select NumberOfCores from Win32_Processor") # TODO count hyper-threaded in this cpu.to_enum.first.NumberOfCores rescue StandardError, LoadError nil end def count_via_cpuinfo open('/proc/cpuinfo') { |f| f.readlines }.grep(/processor/).size rescue StandardError nil end def count_via_sysctl run 'sysctl', '-n', 'hw.ncpu' end def run(command, *args) cmd = resolve_command(command) if cmd IO.popen [cmd, *args] do |io| io.read.to_i end else nil end end def resolve_command(command) look_for_command("/usr/sbin", command) || look_for_command("/sbin", command) || in_path_command(command) end def look_for_command(dir, command) path = File.join(dir, command) File.exist?(path) ? path : nil end def in_path_command(command) IO.popen ['which', command] do |io| io.eof? ? nil : command end end end; end PKu]''!rake-13.0.1/lib/rake/late_time.rbnu[# frozen_string_literal: true module Rake # LateTime is a fake timestamp that occurs _after_ any other time value. class LateTime include Comparable include Singleton def <=>(other) 1 end def to_s "" end end LATE = LateTime.instance end PKu](rake-13.0.1/lib/rake/rake_test_loader.rbnu[# frozen_string_literal: true require "rake" # Load the test files from the command line. argv = ARGV.select do |argument| begin case argument when /^-/ then argument when /\*/ then FileList[argument].to_a.each do |file| require File.expand_path file end false else require File.expand_path argument false end rescue LoadError => e raise unless e.path abort "\nFile does not exist: #{e.path}\n\n" end end ARGV.replace argv PKu]K\(rake-13.0.1/lib/rake/invocation_chain.rbnu[# frozen_string_literal: true module Rake # InvocationChain tracks the chain of task invocations to detect # circular dependencies. class InvocationChain < LinkedList # Is the invocation already in the chain? def member?(invocation) head == invocation || tail.member?(invocation) end # Append an invocation to the chain of invocations. It is an error # if the invocation already listed. def append(invocation) if member?(invocation) fail RuntimeError, "Circular dependency detected: #{to_s} => #{invocation}" end conj(invocation) end # Convert to string, ie: TOP => invocation => invocation def to_s "#{prefix}#{head}" end # Class level append. def self.append(invocation, chain) chain.append(invocation) end private def prefix "#{tail} => " end # Null object for an empty chain. class EmptyInvocationChain < LinkedList::EmptyLinkedList @parent = InvocationChain def member?(obj) false end def append(invocation) conj(invocation) end def to_s "TOP" end end EMPTY = EmptyInvocationChain.new end end PKu]E.rake-13.0.1/lib/rake/tasklib.rbnu[# frozen_string_literal: true require "rake" module Rake # Base class for Task Libraries. class TaskLib include Cloneable include Rake::DSL end end PKu]l*rake-13.0.1/lib/rake/file_creation_task.rbnu[# frozen_string_literal: true require "rake/file_task" require "rake/early_time" module Rake # A FileCreationTask is a file task that when used as a dependency will be # needed if and only if the file has not been created. Once created, it is # not re-triggered if any of its dependencies are newer, nor does trigger # any rebuilds of tasks that depend on it whenever it is updated. # class FileCreationTask < FileTask # Is this file task needed? Yes if it doesn't exist. def needed? !File.exist?(name) end # Time stamp for file creation task. This time stamp is earlier # than any other time stamp. def timestamp Rake::EARLY end end end PKu]Q=rrrake-13.0.1/lib/rake.rbnu[# frozen_string_literal: true #-- # Copyright 2003-2010 by Jim Weirich (jim.weirich@gmail.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. #++ module Rake; end require "rake/version" require "rbconfig" require "fileutils" require "singleton" require "monitor" require "optparse" require "ostruct" require "rake/ext/string" require "rake/win32" require "rake/linked_list" require "rake/cpu_counter" require "rake/scope" require "rake/task_argument_error" require "rake/rule_recursion_overflow_error" require "rake/rake_module" require "rake/trace_output" require "rake/pseudo_status" require "rake/task_arguments" require "rake/invocation_chain" require "rake/task" require "rake/file_task" require "rake/file_creation_task" require "rake/multi_task" require "rake/dsl_definition" require "rake/file_utils_ext" require "rake/file_list" require "rake/default_loader" require "rake/early_time" require "rake/late_time" require "rake/name_space" require "rake/task_manager" require "rake/application" require "rake/backtrace" $trace = false # :stopdoc: # # Some top level Constants. FileList = Rake::FileList RakeFileUtils = Rake::FileUtilsExt PKu]A urake-13.0.1/History.rdocnu[=== 13.0.1 ==== Bug fixes * Fixed bug: Reenabled task raises previous exception on second invokation Pull Request #271 by thorsteneckel * Fix an incorrectly resolved arg pattern Pull Request #327 by mjbellantoni === 13.0.0 ==== Enhancements * Follows recent changes on keyword arguments in ruby 2.7. Pull Request #326 by nobu * Make `PackageTask` be able to omit parent directory while packing files Pull Request #310 by tonytonyjan * Add order only dependency Pull Request #269 by take-cheeze ==== Compatibility changes * Drop old ruby versions(< 2.2) === 12.3.3 ==== Bug fixes * Use the application's name in error message if a task is not found. Pull Request #303 by tmatilai ==== Enhancements: * Use File.open explicitly. === 12.3.2 ==== Bug fixes * Fixed test fails caused by 2.6 warnings. Pull Request #297 by hsbt ==== Enhancements: * Rdoc improvements. Pull Request #293 by colby-swandale * Improve multitask performance. Pull Request #273 by jsm * Add alias `prereqs`. Pull Request #268 by take-cheeze === 12.3.1 ==== Bug fixes * Support did_you_mean >= v1.2.0 which has a breaking change on formatters. Pull request #262 by FUJI Goro. ==== Enhancements: * Don't run task if it depends on already invoked but failed task. Pull request #252 by Gonzalo Rodriguez. * Make space trimming consistent for all task arguments. Pull request #259 by Gonzalo Rodriguez. * Removes duplicated inclusion of Rake::DSL in tests. Pull request #254 by Gonzalo Rodriguez. * Re-raise a LoadError that didn't come from require in the test loader. Pull request #250 by Dylan Thacker-Smith. === 12.3.0 ==== Compatibility Changes * Bump `required_ruby_version` to Ruby 2.0.0. Rake has already removed support for Ruby 1.9.x. ==== Enhancements: * Support `test-bundled-gems` task on ruby core. === 12.2.1 ==== Bug fixes * Fixed to break Capistrano::Application on capistrano3. === 12.2.0 ==== Enhancements: * Make rake easier to use as a library Pull request #211 by @drbrain * Fix quadratic performance in FileTask#out_of_date? Pull request #224 by @doudou * Clarify output when printing nested exception traces Pull request #232 by @urbanautomaton ==== Bug fixes * Account for a file that match 2 or more patterns. Pull request #231 by @styd === 12.1.0 ==== Enhancements: * Added did_you_mean feature for invalid rake task. Pull request #221 by @xtina-starr * Enabled to dependency chained by extensions. Pull request #39 by Petr Skocik. * Make all of string literals to frozen objects on Ruby 2.4 or later. ==== Bug fixes * Typo fixes in rakefile.rdoc. Pull request #180 by Yuta Kurotaki. * Fix unexpected behavior of file task with dryrun option. Pull request #183 by @aycabta. * Make LoadError from running tests more obvious. Pull request #195 by Eric Hodel. * Fix unexpected TypeError with hash style option. Pull request #202 by Kuniaki IGARASHI. === 12.0.0 ==== Compatibility Changes * Removed arguments on clear #157 by Jesse Bowes * Removed `rake/contrib` packages. These are extracted to `rake-contrib` gem. * Removed deprecated method named `last\_comment`. ==== Enhancements: * Re-use trace option on `cleanup` task. #164 by Brian Henderson * Actions adore keyword arguments #174 by Josh Cheek * Rake::TaskArguments#key? alias of #has_key? #175 by Paul Annesley === 11.3.0 / 2016-09-20 ==== Enhancements: * Remove to reference `Fixnum` constant. Pull request #160 by nobu === 11.2.2 / 2016-06-12 ==== Bug fixes * Fix unexpected behavior with multiple dependencies on Rake::TestTask === 11.2.1 / 2016-06-12 ==== Bug fixes * Fix regression of dependencies handling on Rake::TestTask. Report #139 === 11.2.0 / 2016-06-11 ==== Bug fixes * Fix unexpected cut-out behavior on task description using triple dots and exclamation. Report #106 from Stephan Kämper and Pull request #134 by Lee * Fix empty argument assignment with `with_defaults` option. Pull request #135 by bakunyo * Ignore to use `hwprefs` on Darwin platform. Use sysctl now. Report #128 ==== Enhancements * Spawn options for sh Pull equest #138 by Eric Hodel. * Allow to specify dependencies(prerequisites) for Rake::TestTask Pull request #117 by Tim Maslyuchenko * Use Bundler task instead of hoe for gem release. * Remove explicitly load to rubygems for Ruby 1.8. * Unify to declare `Rake::VERSION`. * Support xz format for PackageTask. === 11.1.2 / 2016-03-28 ==== Bug fixes * Remove `-W` option when Rake::TestTask#verbose enabled. It's misunderstanding specification change with Rake 11. Partly revert #67 === 11.1.1 / 2016-03-14 ==== Bug fixes * Use `-W` instead of `--verbose` when Rake::TestTask#verbose enabled. JRuby doesn't have `--verbose` option. === 11.1.0 / 2016-03-11 ==== Compatibility Changes * Revert to remove `last\_comment`. It will remove Rake 12. === 11.0.1 / 2016-03-09 ==== Bug fixes * Fixed packaging manifest. === 11.0.0 / 2016-03-09 ==== Bug fixes * Correctly handle bad encoding in exception messages. Pull request #113 by Tomer Brisker * Fix verbose option at TestTask. Pull request #67 by Mike Blumtritt ==== Enhancements * Make FileList#exclude more analogous to FileList#include. * Use IO.open instead of Open3.popen3 for CPU counter. * Make Rake::Task#already_invoked publicly accessible. Pull request #93 by Joe Rafaniello * Lookup prerequisites with same name outside of scope instead of matching self. Pull request #96 by Sandy Vanderbleek * Make FileList#pathmap behave like String#pathmap. Pull request #61 by Daniel Tamai * Add fetch method to task arguments. Pull request #12 by Chris Keathley * Use ruby warnings by default. Pull request #97 by Harold Giménez ==== Compatibility Changes * Removed to support Ruby 1.8.x * Removed constant named `RAKEVERSION` * Removed Rake::AltSystem * Removed Rake::RubyForgePublisher * Removed Rake::TaskManager#last\_comment. Use last\_description. * Removed Rake::TaskLib#paste * Removed Top-level SshDirPublisher, SshFreshDirPublisher, SshFilePublisher and CompositePublisher from lib/rake/contrib/publisher.rb * Removed "rake/runtest.rb" === 10.5.0 / 2016-01-13 ==== Enhancements * Removed monkey patching for Ruby 1.8. Pull request #46 by Pablo Herrero. * Inheritance class of Rake::FileList returns always self class. Pull request #74 by Thomas Scholz === 10.4.2 / 2014-12-02 ==== Bug fixes * Rake no longer edits ARGV. This allows you to re-exec rake from a rake task. Pull requset #9 by Matt Palmer. * Documented how Rake::DSL#desc handles sentences in task descriptions. Issue #7 by Raza Sayed. * Fixed test error on 1.9.3 with legacy RubyGems. Issue #8 by Matt Palmer. * Deleted duplicated History entry. Pull request #10 by Yuji Yamamoto. === 10.4.1 / 2014-12-01 ==== Bug fixes * Reverted fix for #277 as it caused numerous issues for rake users. rails/spring issue #366 by Gustavo Dutra. === 10.4.0 / 2014-11-22 ==== Enhancements * Upgraded to minitest 5. Pull request #292 by Teo Ljungberg. * Added support for Pathname in rake tasks. Pull request #271 by Randy Coulman. * Rake now ignores falsy dependencies which allows for easier programmatic creation of tasks. Pull request #273 by Manav. * Rake no longer edits ARGV. This allows you to re-exec rake from a rake task. Issue #277 by Matt Palmer. * Etc.nprocessors is used for counting the number of CPUs. ==== Bug fixes * Updated rake manpage. Issue #283 by Nathan Long, pull request #291 by skittleys. * Add Rake::LATE to allow rebuilding of files that depend on deleted files. Bug #286, pull request #287 by David Grayson. * Fix relinking of files when repackaging. Bug #276 by Muenze. * Fixed some typos. Pull request #280 by Jed Northridge. * Try counting CPUs via cpuinfo if host_os was not matched. Pull request #282 by Edouard B. === 10.3.2 / 2014-05-15 ==== Bug fixes * Rake no longer infinitely loops when showing exception causes that refer to each other. Bug #272 by Chris Bandy. * Fixed documentation typos. Bug #275 by Jake Worth. === 10.3.1 / 2014-04-17 ==== Bug fixes * Really stop reporting an error when cleaning already-deleted files. Pull request #269 by Randy Coulman * Fixed infinite loop when cleaning already-deleted files on windows. === 10.3 / 2014-04-15 ==== Enhancements * Added --build-all option to rake which treats all file prerequisites as out-of-date. Pull request #254 by Andrew Gilbert. * Added Rake::NameSpace#scope. Issue #263 by Jon San Miguel. ==== Bug fixes * Suppress org.jruby package files in rake error messages for JRuby users. Issue #213 by Charles Nutter. * Fixed typo, removed extra "h". Pull request #267 by Hsing-Hui Hsu. * Rake no longer reports an error when cleaning already-deleted files. Pull request #266 by Randy Coulman. * Consume stderr while determining CPU count to avoid hang. Issue #268 by Albert Sun. === 10.2.2 / 2014-03-27 ==== Bug fixes * Restored Ruby 1.8.7 compatibility === 10.2.1 / 2014-03-25 ==== Bug fixes * File tasks including a ':' are now top-level tasks again. Issue #262 by Josh Holtrop. * Use sysctl for CPU count for all BSDs. Pull request #261 by Joshua Stein. * Fixed CPU detection for unknown platforms. === 10.2.0 / 2014-03-24 ==== Enhancements * Rake now requires Ruby 1.9 or newer. For me, this is a breaking change, but it seems that Jim planned to release it with Rake 10.2. See also pull request #247 by Philip Arndt. * Rake now allows you to declare tasks under a namespace like: task 'a:b' do ... end Pull request #232 by Judson Lester. * Task#source defaults to the first prerequisite in non-rule tasks. Pull request #215 by Avdi Grimm. * Rake now automatically rebuilds and reloads imported files. Pull request #209 by Randy Coulman. * The rake task arguments can contain escaped commas. Pull request #214 by Filip Hrbek. * Rake now prints the exception class on errors. Patch #251 by David Cornu. ==== Bug fixes * Fixed typos. Pull request #256 by Valera Rozuvan, #250 via Jake Worth, #260 by Zachary Scott. * Fixed documentation for calling tasks with arguments. Pull request #235 by John Varghese. * Clarified `rake -f` usage message. Pull request #252 by Marco Pfatschbacher. * Fixed a test failure on windows. Pull request #231 by Hiroshi Shirosaki. * Fixed corrupted rake.1.gz. Pull request #225 by Michel Boaventura. * Fixed bug in can\_detect\_signals? in test. Patch from #243 by Alexey Borzenkov. === 10.1.1 * Use http://github.com/jimweirich/rake instead of http://rake.rubyforge.org for canonical project url. === 10.1.0 ==== Changes ===== New Features * Add support for variable length task argument lists. If more actual arguments are supplied than named arguments, then the extra arguments values will be in args.extras. * Application name is not displayed in the help banner. (Previously "rake" was hardcoded, now rake-based applications can display their own names). ===== Bug Fixes Bug fixes include: * Fix backtrace suppression issues. * Rules now explicit get task arguments passed to them. * Rename FileList#exclude? to FileList#exclude\_from\_list? to avoid conflict with new Rails method. * Clean / Clobber tasks now report failure to remove files. * Plus heaps of internal code cleanup. ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Michael Nikitochkin (general code cleanup) * Vipul A M (general code cleanup) * Dennis Bell (variable length task argument lists) * Jacob Swanner (rules arguments) * Rafael Rosa Fu (documentation typo) * Stuart Nelson (install.rb fixes) * Lee Hambley (application name in help banner) -- Jim Weirich === 10.0.3 "Jim, when will Rake reach version 1.0?" Over the past several years I've been asked that question at conferences, panels and over twitter. Due to historical reasons (or maybe just plain laziness) Rake has (incorrectly) been treating the second digit of the version as the major release number. So in my head Rake was already at version 9. Well, it's time to fix things. This next version of Rake drops old, crufty, backwards compatibility hacks such as top level constants, DSL methods defined in Object and numerous other features that are just no longer desired. It's also time to drop the leading zero from the version number as well and call this new version of rake what it really is: Version 10. So, welcome to Rake 10.0! Rake 10 is actually feature identical to the latest version of Rake 9 (that would be the version spelled 0.9.3), *except* that Rake 10 drops all the sundry deprecated features that have accumulated over the years. If your Rakefile is up to date and current with all the new features of Rake 10, you are ready to go. If your Rakefile still uses a few deprecated feeatures, feel free to use Rake 9 (0.9.3) with the same feature set. Just be aware that future features will be in Rake 10 family line. ==== Changes As mentioned above, there are no new features in Rake 10. However, there are a number of features missing: * Classic namespaces are now gone. Rake is no longer able to reflect the options settings in the global variables ($rakefile, $show\_tasks, $show\_prereqs, $trace, $dryrun and $silent). The --classic-namespace option is no longer supported. * Global constants are no longer supported. This includes Task, FileTask, FileCreationTask and RakeApp). The constant missing hook to warn about using global rake constants has been removed. * The Rake DSL methods (task, file, directory, etc) are in their own module (Rake::DSL). The stub versions of these methods (that printed warnings) in Object have been removed. However, the DSL methods are added to the top-level main object. Since main is not in the inheritance tree, the presence of the DSL methods in main should be low impact on other libraries. If you want to use the Rake DSL commands from your own code, just include Rake::DSL into your own classes and modules. * The deprecated syntax for task arguments (the one using :needs) has been removed. * The --reduce-compat flag has been removed (it's not needed anymore). * The deprecated rake/sys.rb library has been removed. * The deprecated rake/rdoctask.rb library has been removed. RDoc supplies its own rake task now. * The deprecated rake/gempackagetask.rb library has been removed. Gem supplies its own package task now. There is one small behavioral change: * Non-file tasks now always report the current time as their time stamp. This is different from the previous behavior where non-file tasks reported current time only if there were no prerequisites, and the max prerequisite timestamp otherwise. This lead to inconsistent and surprising behavior when adding prerequisites to tasks that in turn were prequisites to file tasks. The new behavior is more consistent and predictable. ==== Changes (from 0.9.3, 0.9.4, 0.9.5) Since Rake 10 includes the changes from the last version of Rake 9, we'll repeat the changes for versions 0.9.3 through 0.9.5 here. ===== New Features (in 0.9.3) * Multitask tasks now use a thread pool. Use -j to limit the number of available threads. * Use -m to turn regular tasks into multitasks (use at your own risk). * You can now do "Rake.add_rakelib 'dir'" in your Rakefile to programatically add rake task libraries. * You can specific backtrace suppression patterns (see --suppress-backtrace) * Directory tasks can now take prerequisites and actions * Use --backtrace to request a full backtrace without the task trace. * You can say "--backtrace=stdout" and "--trace=stdout" to route trace output to standard output rather than standard error. * Optional 'phony' target (enable with 'require 'rake/phony'") for special purpose builds. * Task#clear now clears task comments as well as actions and prerequisites. Task#clear_comment will specifically target comments. * The --all option will force -T and -D to consider all the tasks, with and without descriptions. ===== Bug Fixes (in 0.9.3) * Semi-colons in windows rakefile paths now work. * Improved Control-C support when invoking multiple test suites. * egrep method now reads files in text mode (better support for Windows) * Better deprecation line number reporting. * The -W option now works with all tasks, whether they have a description or not. * File globs in rake should not be sorted alphabetically, independent of file system and platform. * Numerous internal improvements. * Documentation typos and fixes. ===== Bug Fixes (in 0.9.4) * Exit status with failing tests is not correctly set to non-zero. * Simplified syntax for phony task (for older versions of RDoc). * Stand alone FileList usage gets glob function (without loading in extra dependencies) ===== Bug Fixes (in 0.9.5) * --trace and --backtrace no longer swallow following task names. ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 10.0.2 ==== Changes ===== Bug Fixes * --trace and --backtrace no longer swallow following task names. ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 10.0.1 ==== Changes ===== Bug Fixes * Exit status with failing tests is not correctly set to non-zero. * Simplified syntax for phony task (for older versions of RDoc). * Stand alone FileList usage gets glob function (without loading in extra dependencies) ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 10.0.0 "Jim, when will Rake reach version 1.0?" Over the past several years I've been asked that question at conferences, panels and over twitter. Due to historical reasons (or maybe just plain laziness) Rake has (incorrectly) been treating the second digit of the version as the major release number. So in my head Rake was already at version 9. Well, it's time to fix things. This next version of Rake drops old, crufty, backwards compatibility hacks such as top level constants, DSL methods defined in Object and numerous other features that are just no longer desired. It's also time to drop the leading zero from the version number as well and call this new version of rake what it really is: Version 10. So, welcome to Rake 10.0! Rake 10 is actually feature identical to the latest version of Rake 9 (that would be the version spelled 0.9.3), *except* that Rake 10 drops all the sundry deprecated features that have accumulated over the years. If your Rakefile is up to date and current with all the new features of Rake 10, you are ready to go. If your Rakefile still uses a few deprecated feeatures, feel free to use Rake 9 (0.9.3) with the same feature set. Just be aware that future features will be in Rake 10 family line. ==== Changes in 10.0 As mentioned above, there are no new features in Rake 10. However, there are a number of features missing: * Classic namespaces are now gone. Rake is no longer able to reflect the options settings in the global variables ($rakefile, $show\_tasks, $show\_prereqs, $trace, $dryrun and $silent). The --classic-namespace option is no longer supported. * Global constants are no longer supported. This includes Task, FileTask, FileCreationTask and RakeApp). The constant missing hook to warn about using global rake constants has been removed. * The Rake DSL methods (task, file, directory, etc) are in their own module (Rake::DSL). The stub versions of these methods (that printed warnings) in Object have been removed. However, the DSL methods are added to the top-level main object. Since main is not in the inheritance tree, the presence of the DSL methods in main should be low impact on other libraries. If you want to use the Rake DSL commands from your own code, just include Rake::DSL into your own classes and modules. * The deprecated syntax for task arguments (the one using :needs) has been removed. * The --reduce-compat flag has been removed (it's not needed anymore). * The deprecated rake/sys.rb library has been removed. * The deprecated rake/rdoctask.rb library has been removed. RDoc supplies its own rake task now. * The deprecated rake/gempackagetask.rb library has been removed. Gem supplies its own package task now. There is one small behavioral change: * Non-file tasks now always report the current time as their time stamp. This is different from the previous behavior where non-file tasks reported current time only if there were no prerequisites, and the max prerequisite timestamp otherwise. This lead to inconsistent and surprising behavior when adding prerequisites to tasks that in turn were prequisites to file tasks. The new behavior is more consistent and predictable. ==== Changes (from 0.9.3) Since Rake 10 includes the changes from the last version of Rake 9, we'll repeat the changes for version 0.9.3 here. ===== New Features * Multitask tasks now use a thread pool. Use -j to limit the number of available threads. * Use -m to turn regular tasks into multitasks (use at your own risk). * You can now do "Rake.add_rakelib 'dir'" in your Rakefile to programatically add rake task libraries. * You can specific backtrace suppression patterns (see --suppress-backtrace) * Directory tasks can now take prerequisites and actions * Use --backtrace to request a full backtrace without the task trace. * You can say "--backtrace=stdout" and "--trace=stdout" to route trace output to standard output rather than standard error. * Optional 'phony' target (enable with 'require 'rake/phony'") for special purpose builds. * Task#clear now clears task comments as well as actions and prerequisites. Task#clear_comment will specifically target comments. * The --all option will force -T and -D to consider all the tasks, with and without descriptions. ===== Bug Fixes * Semi-colons in windows rakefile paths now work. * Improved Control-C support when invoking multiple test suites. * egrep method now reads files in text mode (better support for Windows) * Better deprecation line number reporting. * The -W option now works with all tasks, whether they have a description or not. * File globs in rake should not be sorted alphabetically, independent of file system and platform. * Numerous internal improvements. * Documentation typos and fixes. ==== Thanks As usual, it was input from users that drove a lot of these changes. The following people contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 0.9.6 Rake version 0.9.6 contains a number of fixes mainly for merging Rake into the Ruby source tree and fixing tests. ==== Changes ===== Bug Fixes (0.9.6) * Better trace output when using a multi-threaded Rakefile. * Arg parsing is now consistent for tasks and multitasks. * Skip exit code test in versions of Ruby that don't support it well. Changes for better integration with the Ruby source tree: * Fix version literal for Ruby source tree build. * Better loading of libraries for testing in Ruby build. * Use the ruby version provided by Ruby's tests. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 0.9.5 Rake version 0.9.5 contains a number of bug fixes. ==== Changes ===== Bug Fixes (0.9.5) * --trace and --backtrace no longer swallow following task names. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 0.9.4 Rake version 0.9.4 contains a number of bug fixes. ==== Changes ===== Bug Fixes (0.9.4) * Exit status with failing tests is not correctly set to non-zero. * Simplified syntax for phony task (for older versions of RDoc). * Stand alone FileList usage gets glob function (without loading in extra dependencies) ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === 0.9.3 Rake version 0.9.3 contains some new, backwards compatible features and a number of bug fixes. ==== Changes ===== New Features * Multitask tasks now use a thread pool. Use -j to limit the number of available threads. * Use -m to turn regular tasks into multitasks (use at your own risk). * You can now do "Rake.add_rakelib 'dir'" in your Rakefile to programatically add rake task libraries. * You can specific backtrace suppression patterns (see --suppress-backtrace) * Directory tasks can now take prerequisites and actions * Use --backtrace to request a full backtrace without the task trace. * You can say "--backtrace=stdout" and "--trace=stdout" to route trace output to standard output rather than standard error. * Optional 'phony' target (enable with 'require 'rake/phony'") for special purpose builds. * Task#clear now clears task comments as well as actions and prerequisites. Task#clear_comment will specifically target comments. * The --all option will force -T and -D to consider all the tasks, with and without descriptions. ===== Bug Fixes * Semi-colons in windows rakefile paths now work. * Improved Control-C support when invoking multiple test suites. * egrep method now reads files in text mode (better support for Windows) * Better deprecation line number reporting. * The -W option now works with all tasks, whether they have a description or not. * File globs in rake should not be sorted alphabetically, independent of file system and platform. * Numerous internal improvements. * Documentation typos and fixes. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Aaron Patterson * Dylan Smith * Jo Liss * Jonas Pfenniger * Kazuki Tsujimoto * Michael Bishop * Michael Elufimov * NAKAMURA Usaku * Ryan Davis * Sam Grönblom * Sam Phippen * Sergio Wong * Tay Ray Chuan * grosser * quix Also, many thanks to Eric Hodel for assisting with getting this release out the door. -- Jim Weirich === Rake 0.9.2.2 Rake version 0.9.2.2 is mainly bug fixes. ==== Changes * The rake test loader now removes arguments it has processed. Issue #51 * Rake::TaskArguments now responds to #values\_at * RakeFileUtils.verbose_flag = nil silences output the same as 0.8.7 * Rake tests are now directory-independent * Rake tests are no longer require flexmock * Commands constant is no longer polluting top level namespace. * Show only the interesting portion of the backtrace by default (James M. Lawrence). * Added --reduce-compat option to remove backward compatible DSL hacks (James M. Lawrence). ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence (quix) * Roger Pack * Cezary Baginski * Sean Scot August Moon * R.T. Lechow * Alex Chaffee * James Tucker * Matthias Lüdtke * Santiago Pastorino Also, bit thanks to Eric Hodel for assisting with getting this release out the door (where "assisting" includes, but is not by any means limited to, "pushing" me to get it done). -- Jim Weirich === 0.9.2 Rake version 0.9.2 has a few small fixes. See below for details. ==== Changes * Support for Ruby 1.8.6 was fixed. * Global DSL warnings now honor --no-deprecate ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence (quix) * Roger Pack * Cezary Baginski * Sean Scot August Moon * R.T. Lechow * Alex Chaffee * James Tucker * Matthias Lüdtke * Santiago Pastorino Also, bit thanks to Eric Hodel for assisting with getting this release out the door (where "assisting" includes, but is not by any means limited to, "pushing" me to get it done). -- Jim Weirich === 0.9.1 Rake version 0.9.1 has a number of bug fixes and enhancments (see below for more details). Additionally, the internals have be slightly restructured and improved. ==== Changes Rake 0.9.1 adds back the global DSL methods, but with deprecation messages. This allows Rake 0.9.1 to be used with older rakefiles with warning messages. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence (quix) * Roger Pack * Cezary Baginski * Sean Scot August Moon * R.T. Lechow * Alex Chaffee * James Tucker * Matthias Lüdtke * Santiago Pastorino Also, bit thanks to Eric Hodel for assisting with getting this release out the door (where "assisting" includes, but is not by any means limited to, "pushing" me to get it done). -- Jim Weirich === 0.9.0 Rake version 0.9.0 has a number of bug fixes and enhancments (see below for more details). Additionally, the internals have be slightly restructured and improved. ==== Changes ===== New Features / Enhancements / Bug Fixes in Version 0.9.0 * Rake now warns when the deprecated :needs syntax used (and suggests the proper syntax in the warning). * Moved Rake DSL commands to top level ruby object 'main'. Rake DSL commands are no longer private methods in Object. (Suggested by James M. Lawrence/quix) * Rake now uses case-insensitive comparisons to find the Rakefile on Windows. Based on patch by Roger Pack. * Rake now requires (instead of loads) files in the test task. Patch by Cezary Baginski. * Fixed typos. Patches by Sean Scot August Moon and R.T. Lechow. * Rake now prints the Rakefile directory only when it's different from the current directory. Patch by Alex Chaffee. * Improved rakefile_location discovery on Windows. Patch by James Tucker. * Rake now recognizes "Windows Server" as a windows system. Patch by Matthias Lüdtke * Rake::RDocTask is deprecated. Use RDoc::Task from RDoc 2.4.2+ (require 'rdoc/task') * Rake::GemPackageTask is deprecated. Use Gem::PackageTask (require 'rubygems/package\_task') * Rake now outputs various messages to $stderr instead of $stdout. * Rake no longer emits warnings for Config. Patch by Santiago Pastorino. * Removed Rake's DSL methods from the top level scope. If you need to call 'task :xzy' in your code, include Rake::DSL into your class, or put the code in a Rake::DSL.environment do ... end block. * Split rake.rb into individual files. * Support for the --where (-W) flag for showing where a task is defined. * Fixed quoting in test task. (http://onestepback.org/redmine/issues/show/44, http://www.pivotaltracker.com/story/show/1223138) * Fixed the silent option parsing problem. (http://onestepback.org/redmine/issues/show/47) * Fixed :verbose=>false flag on sh and ruby commands. * Rake command line options may be given by default in a RAKEOPT environment variable. * Errors in Rake will now display the task invocation chain in effect at the time of the error. * Accepted change by warnickr to not expand test patterns in shell (allowing more files in the test suite). * Fixed that file tasks did not perform prereq lookups in scope (Redmine #57). ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence (quix) * Roger Pack * Cezary Baginski * Sean Scot August Moon * R.T. Lechow * Alex Chaffee * James Tucker * Matthias Lüdtke * Santiago Pastorino Also, bit thanks to Eric Hodel for assisting with getting this release out the door (where "assisting" includes, but is not by any means limited to, "pushing" me to get it done). -- Jim Weirich === 0.8.7 Rake version 0.8.5 introduced greatly improved support for executing commands on Windows. The "sh" command now has the same semantics on Windows that it has on Unix based platforms. Rake version 0.8.6 includes minor fixes the the RDoc generation. Rake version 0.8.7 includes a minor fix for JRuby running on windows. ==== Changes ===== New Features / Enhancements in Version 0.8.5 * Improved implementation of the Rake system command for Windows. (patch from James M. Lawrence/quix) * Support for Ruby 1.9's improved system command. (patch from James M. Lawrence/quix) * Rake now includes the configured extension when invoking an executable (Config::CONFIG['EXEEXT]) ===== Bug Fixes in Version 0.8.5 * Environment variable keys are now correctly cased (it matters in some implementations). ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Charles Nutter -- Jim Weirich === 0.8.6 Rake version 0.8.5 introduced greatly improved support for executing commands on Windows. The "sh" command now has the same semantics on Windows that it has on Unix based platforms. Rake version 0.8.5 includes minor fixes the the RDoc generation. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence/quix * Luis Lavena -- Jim Weirich === 0.8.5 Rake version 0.8.5 is a new release of Rake with greatly improved support for executing commands on Windows. The "sh" command now has the same semantics on Windows that it has on Unix based platforms. ==== Changes ===== New Features / Enhancements in Version 0.8.5 * Improved implementation of the Rake system command for Windows. (patch from James M. Lawrence/quix) * Support for Ruby 1.9's improved system command. (patch from James M. Lawrence/quix) * Rake now includes the configured extension when invoking an executable (Config::CONFIG['EXEEXT]) ===== Bug Fixes in Version 0.8.5 * Environment variable keys are now correctly cased (it matters in some implementations). ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence/quix * Luis Lavena -- Jim Weirich === 0.8.4 Rake version 0.8.4 is a bug-fix release of rake. NOTE: The version of Rake that comes with Ruby 1.9 has diverged slightly from the core Rake code base. Rake 0.8.4 will work with Ruby 1.9, but is not a strict upgrade for the Rake that comes with Ruby 1.9. A (near) future release of Rake will unify those two codebases. ==== Letter Writing Campaign Thanks to Aaron Patterson (@tenderlove) and Eric Hodel (@drbrain) for their encouraging support in organizing a letter writing campaign to lobby for the "Warning Free" release of rake 0.8.4. A special callout goes to Jonathan D. Lord, Sr (Dr. Wingnut) whose postcard was the first to actually reach me. (see http://tenderlovemaking.com/2009/02/26/we-need-a-new-version-of-rake/ for details) ==== Changes ===== New Features / Enhancements in Version 0.8.4 * Case is preserved on rakefile names. (patch from James M. Lawrence/quix) * Improved Rakefile case insensitivity testing (patch from Luis Lavena). * Windows system dir search order is now: HOME, HOMEDRIVE + HOMEPATH, APPDATA, USERPROFILE (patch from Luis Lavena) * MingGW is now recognized as a windows platform. (patch from Luis Lavena) ===== Bug Fixes in Version 0.8.4 * Removed reference to manage_gem to fix the warning produced by the gem package task. * Fixed stray ARGV option problem that was interfering with Test::Unit::Runner. (patch from Pivotal Labs) ===== Infrastructure Improvements in Version 0.8.4 * Numerous fixes to the windows test suite (patch from Luis Lavena). * Improved Rakefile case insensitivity testing (patch from Luis Lavena). * Better support for windows paths in the test task (patch from Simon Chiang/bahuvrihi) ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James M. Lawrence/quix * Luis Lavena * Pivotal Labs * Simon Chiang/bahuvrihi -- Jim Weirich === 0.8.3 Rake version 0.8.3 is a bug-fix release of rake. ==== Changes ===== Bug Fixes in Version 0.8.3 * Enhanced the system directory detection in windows. We now check HOMEDRIVE/HOMEPATH and USERPROFILE if APPDATA isn't found. (Patch supplied by James Tucker). Rake no long aborts if it can't find the directory. * Added fix to handle ruby installations in directories with spaces in their name. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Edwin Pratomo * Gavin Stark * Adam Q. Salter * Adam Majer * Emanuel Indermühle * Ittay Dror * Bheeshmar Redheendran (for spending an afternoon with me debugging windows issues) -- Jim Weirich === 0.8.2 Rake version 0.8.2 is a new release of rake that includes a number of new features and numerous bug fixes. ==== Changes ===== New Features in Version 0.8.2 * Switched from getoptlong to optparse (patches supplied by Edwin Pratomo). * The -T option will now attempt to dynamically sense the size of the terminal. The -T output will only self-truncate if the output is a tty. However, if RAKE_COLUMNS is explicitly set, it will be honored in any case. (Patch provided by Gavin Stark). * The following public methods have been added to rake task objects: * task.clear -- Clear both the prerequisites and actions of the target rake task. * task.clear_prerequisites -- Clear all the existing prerequisites from the target rake task. * task.clear_actions -- Clear all the existing actions from the target rake task. * task.reenable -- Re-enable a task, allowing its actions to be executed again if the task is invoked. * Changed RDoc test task to have no default template. This makes it easier for the tempate to pick up the template from the environment. * Default values for task arguments can easily be specified with the :with_defaults method. (Idea for default argument merging supplied by (Adam Q. Salter) ===== Bug Fixes in Version 0.8.2 * Fixed bug in package task so that it will include the subdir directory in the package for testing. (Bug found by Adam Majer) * Fixed filename dependency order bug in test\_inspect\_pending and test\_to\_s\_pending. (Bug found by Adam Majer) * Fixed check for file utils options to make them immune to the symbol/string differences. (Patch supplied by Edwin Pratomo) * Fixed bug with rules involving multiple source, where only the first dependency of a rule has any effect (Patch supplied by Emanuel Indermühle) * FileList#clone and FileList#dup have better sematics w.r.t. taint and freeze. * Changed from using Mutex to Monitor. Evidently Mutex causes thread join errors when Ruby is compiled with -disable-pthreads. (Patch supplied by Ittay Dror) * Fixed bug in makefile parser that had problems with extra spaces in file task names. (Patch supplied by Ittay Dror) ==== Other changes in Version 0.8.2 * Added ENV var to rake's own Rakefile to prevent OS X from including extended attribute junk in the rake package tar file. (Bug found by Adam Majer) * Added a performance patch for reading large makefile dependency files. (Patch supplied by Ittay Dror) ==== Task Argument Examples Prior to version 0.8.0, rake was only able to handle command line arguments of the form NAME=VALUE that were passed into Rake via the ENV hash. Many folks had asked for some kind of simple command line arguments, perhaps using "--" to separate regular task names from argument values on the command line. The problem is that there was no easy way to associate positional arguments on the command line with different tasks. Suppose both tasks :a and :b expect a command line argument: does the first value go with :a? What if :b is run first? Should it then get the first command line argument. Rake 0.8.0 solves this problem by explicitly passing values directly to the tasks that need them. For example, if I had a release task that required a version number, I could say: rake release[0.8.2] And the string "0.8.2" will be passed to the :release task. Multiple arguments can be passed by separating them with a comma, for example: rake name[john,doe] Just a few words of caution. The rake task name and its arguments need to be a single command line argument to rake. This generally means no spaces. If spaces are needed, then the entire rake + argument string should be quoted. Something like this: rake "name[billy bob, smith]" (Quoting rules vary between operating systems and shells, so make sure you consult the proper docs for your OS/shell). ===== Tasks that Expect Parameters Parameters are only given to tasks that are setup to expect them. In order to handle named parameters, the task declaration syntax for tasks has been extended slightly. For example, a task that needs a first name and last name might be declared as: task :name, :first_name, :last_name The first argument is still the name of the task (:name in this case). The next to argumements are the names of the parameters expected by :name (:first_name and :last_name in the example). To access the values of the parameters, the block defining the task behaviour can now accept a second parameter: task :name, :first_name, :last_name do |t, args| puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end The first argument of the block "t" is always bound to the current task object. The second argument "args" is an open-struct like object that allows access to the task arguments. Extra command line arguments to a task are ignored. Missing command line arguments are given the nil value. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Edwin Pratomo * Gavin Stark * Adam Q. Salter * Adam Majer * Emanuel Indermühle * Ittay Dror * Bheeshmar Redheendran (for spending an afternoon with me debugging windows issues) -- Jim Weirich === 0.8.0/0.8.1 Rake version 0.8.0 is a new release of rake that includes serveral new features. ==== Changes ===== New Features in Version 0.8.0 * Tasks can now receive command line parameters. See the examples below for more details. * Comments are limited to 80 columns on output, but full comments can be seen by using the -D parameter. (feature suggested by Jamis Buck). * Explicit exit(n) calls will now set the exit status to n. (patch provided by Stephen Touset). * Rake is now compatible with Ruby 1.9. Version 0.8.1 is a minor update that includes additional Ruby 1.9 compatibility fixes. ==== Task Argument Examples Prior to version 0.8.0, rake was only able to handle command line arguments of the form NAME=VALUE that were passed into Rake via the ENV hash. Many folks had asked for some kind of simple command line arguments, perhaps using "--" to separate regular task names from argument values on the command line. The problem is that there was no easy way to associate positional arguments on the command line with different tasks. Suppose both tasks :a and :b expect a command line argument: does the first value go with :a? What if :b is run first? Should it then get the first command line argument. Rake 0.8.0 solves this problem by explicitly passing values directly to the tasks that need them. For example, if I had a release task that required a version number, I could say: rake release[0.8.0] And the string "0.8.0" will be passed to the :release task. Multiple arguments can be passed by separating them with a comma, for example: rake name[john,doe] Just a few words of caution. The rake task name and its arguments need to be a single command line argument to rake. This generally means no spaces. If spaces are needed, then the entire rake + argument string should be quoted. Something like this: rake "name[billy bob, smith]" (Quoting rules vary between operating systems and shells, so make sure you consult the proper docs for your OS/shell). ===== Tasks that Expect Parameters Parameters are only given to tasks that are setup to expect them. In order to handle named parameters, the task declaration syntax for tasks has been extended slightly. For example, a task that needs a first name and last name might be declared as: task :name, :first_name, :last_name The first argument is still the name of the task (:name in this case). The next to argumements are the names of the parameters expected by :name (:first_name and :last_name in the example). To access the values of the parameters, the block defining the task behaviour can now accept a second parameter: task :name, :first_name, :last_name do |t, args| puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end The first argument of the block "t" is always bound to the current task object. The second argument "args" is an open-struct like object that allows access to the task arguments. Extra command line arguments to a task are ignored. Missing command line arguments are given the nil value. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Jamis Buck (for comment formatting suggestions) * Stephen Touset (for exit status patch). -- Jim Weirich === 0.7.3 Rake version 0.7.3 is a minor release that includes some refactoring to better support custom Rake applications. ==== Changes ===== New Features in Version 0.7.3 * Added the +init+ and +top_level+ methods to make the creation of custom Rake applications a bit easier. E.g. gem 'rake', ">= 0.7.3" require 'rake' Rake.application.init('myrake') task :default do something_interesting end Rake.application.top_level ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... -- Jim Weirich === 0.7.2 Version 0.7.2 supplies a bug fix and a few minor enhancements. In particular, the new version fixes an incompatibility with the soon to be released Ruby 1.8.6. We strongly recommend upgrading to Rake 0.7.2 in order to be compatible with the new version of Ruby. ==== Changes ===== Bug Fixes in 0.7.2 There are quite a number of bug fixes in the new 0.7.2 version of Rake: * Removed dependency on internal fu_xxx functions from FileUtils. * Error messages are now send to stderr rather than stdout (from Payton Quackenbush). * Better error handling on invalid command line arguments (from Payton Quackenbush). * Fixed some bugs where the application object was going to the global appliation instead of using its own data. * Fixed the method name leak from FileUtils (bug found by Glenn Vanderburg). * Added test for noop, bad_option and verbose flags to sh command. * Added a description to the gem task in GemPackageTask. * Fixed a bug when rules have multiple prerequisites (patch by Joel VanderWerf) * Added the handful of RakeFileUtils to the private method as well. ===== New Features in 0.7.2 The following new features are available in Rake version 0.7.2: * Added square and curly bracket patterns to FileList#include (Tilman Sauerbeck). * FileLists can now pass a block to FileList#exclude to exclude files based on calculated values. * Added plain filename support to rule dependents (suggested by Nobu Nakada). * Added pathmap support to rule dependents. In other words, if a pathmap format (beginning with a '%') is given as a Rake rule dependent, then the name of the depend will be the name of the target with the pathmap format applied. * Added a 'tasks' method to a namespace to get a list of tasks associated with the namespace. * Added tar_command and zip_command options to the Package task. * The clean task will no longer delete 'core' if it is a directory. ===== Internal Rake Improvements The following changes will are mainly internal improvements and refactorings and have little effect on the end user. But they may be of interest to the general public. * Added rcov task and updated unit testing for better code coverage. * Added a 'shame' task to the Rakefile. * Added rake_extension to handle detection of extension collisions. * Added a protected 'require "rubygems"' to test/test_application to unbreak cruisecontrol.rb. * Removed rake\_dup. Now we just simply rescue a bad dup. * Refactored the FileList reject logic to remove duplication. * Removed if \_\_FILE\_\_ at the end of the rake.rb file. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Payton Quackenbush -- For several error handling improvements. * Glenn Vanderburg -- For finding and fixing the method name leak from FileUtils. * Joel VanderWerf -- for finding and fixing a bug in the handling of multiple prerequisites. * Tilman Sauerbeck -- For some enhancing FileList to support more advanced file globbing. * Nobu Nakada -- For suggesting plain file name support to rule dependents. -- Jim Weirich === 0.7.1 Version 0.7.1 supplies a bug fix and a few minor enhancements. ==== Changes ===== Bug Fixes in 0.7.1 * Changes in the exception reported for the FileUtils.ln caused safe_ln to fail with a NotImplementedError. Rake 0.7.1 will now catch that error or any StandardError and properly fall back to using +cp+. ===== New Features in 0.7.1 * You can filter the results of the --task option by supplying an optional regular expression. This allows the user to easily find a particular task name in a long list of possible names. * Transforming procs in a rule may now return a list of prerequisites. This allows more flexible rule formation. * FileList and String now support a +pathmap+ melthod that makes the transforming paths a bit easier. See the API docs for +pathmap+ for details. * The -f option without a value will disable the search for a Rakefile. This allows the Rakefile to be defined entirely in a library (and loaded with the -r option). The current working directory is not changed when this is done. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * James Britt and Assaph Mehr for reporting and helping to debug the safe_ln issue. -- Jim Weirich === 0.7.0 These changes for Rake have been brewing for a long time. Here they are, I hope you enjoy them. ==== Changes ===== New Features * Name space support for task names (see below). * Prerequisites can be executed in parallel (see below). * Added safe_ln support for openAFS (via Ludvig Omholt). * RDoc defaults to internal (in-process) invocation. The old behavior is still available by setting the +external+ flag to true. * Rakefiles are now loaded with the expanded path to prevent accidental pollution from the Ruby load path. * Task objects my now be used in prerequisite lists directly. * Task objects (in addition to task names) may now be included in the prerequisite list of a task. * Internals cleanup and refactoring. ===== Bug Fixes * Compatibility fixes for Ruby 1.8.4 FileUtils changes. ===== Namespaces Tasks can now be nested inside their own namespaces. Tasks within one namespace will not accidentally interfer with tasks named in a different namespace. For example: namespace "main" do task :build do # Build the main program end end namespace "samples" do task :build do # Build the sample programs end end task :build_all => ["main:build", "samples:build"] Even though both tasks are named :build, they are separate tasks in their own namespaces. The :build_all task (defined in the toplevel namespace) references both build tasks in its prerequisites. You may invoke each of the individual build tasks with the following commands: rake main:build rake samples:build Or invoke both via the :build_all command: rake build_all Namespaces may be nested arbitrarily. Since the name of file tasks correspond to the name of a file in the external file system, FileTasks are not affected by the namespaces. See the Rakefile format documentation (in the Rake API documents) for more information. ===== Parallel Tasks Sometimes you have several tasks that can be executed in parallel. By specifying these tasks as prerequisites to a +multitask+ task. In the following example the tasks copy\_src, copy\_doc and copy\_bin will all execute in parallel in their own thread. multitask :copy_files => [:copy_src, :copy_doc, :copy_bin] do puts "All Copies Complete" end ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Doug Young (inspiration for the parallel task) * David Heinemeier Hansson (for --trace message enhancement and for pushing for namespace support). * Ludvig Omholt (for the openAFS fix) -- Jim Weirich === 0.6.1 * Rebuilt 0.6.0 gem without signing. === 0.6.0 Its time for some long requested enhancements and lots of bug fixes ... And a whole new web page. ==== New Web Page The primary documentation for rake has moved from the RubyForge based wiki to its own Hieraki based web site. Constant spam on the wiki made it a difficult to keep clean. The new site will be easier to update and organize. Check out the new documentation at: http://docs.rubyrake.org We will be adding new documentation to the site as time goes on. In addition to the new docs page, make sure you check out Martin Fowlers article on rake at http://martinfowler.com/articles/rake.html ==== Changes ===== New Features * Multiple prerequisites on Rake rules now allowed. However, keep the following in mind: 1. All the prerequisites of a rule must be available before a rule is triggered, where "enabled" means (a) an existing file, (b) a defined rule, or (c) another rule which also must be trigger-able. 2. Rules are checked in order of definition, so it is important to order your rules properly. If a file can be created by two different rules, put the more specific rule first (otherwise the more general rule will trigger first and the specific one will never be triggered). 3. The source method now returns the name of the first prerequisite listed in the rule. sources returns the names of all the rule prerequisites, ordered as they are defined in the rule. If the task has other prerequisites not defined in the rule (but defined in an explicit task definition), then they will _not_ be included in the sources list. * FileLists may now use the egrep command. This popular enhancement is now a core part of the FileList object. If you want to get a list of all your to-dos, fixmes and TBD comments, add the following to your Rakefile. desc "Look for TODO and FIXME tags in the code" task :todo do FileList['**/*.rb'].egrep /#.*(FIXME|TODO|TBD)/ end * The investigation method was added to task object to dump out some important values. This makes it a bit easier to debug Rake tasks. For example, if you are having problems with a particular task, just print it out: task :huh do puts Rake::Task['huh'].investigation end * The Rake::TestTask class now supports a "ruby\_opts" option to pass arbitrary ruby options to a test subprocess. ===== Some Incompatibilities * When using the ruby command to start a Ruby subprocess, the Ruby interpreter that is currently running rake is used by default. This makes it easier to use rake in an environment with multiple ruby installation. (Previously, the first ruby command found in the PATH was used). If you wish to chose a different Ruby interpreter, you can explicitly choose the interpreter via the sh command. * The major rake classes (Task, FileTask, FileCreationTask, RakeApp) have been moved out of the toplevel scope and are now accessible as Rake::Task, Rake::FileTask, Rake::FileCreationTask and Rake::Application. If your Rakefile directly references any one of these tasks, you may: 1. Update your Rakefile to use the new classnames 2. Use the --classic-namespace option on the rake command to get the old behavior, 3. Add require 'rake/classic_namespace' to the Rakefile to get the old behavior. rake will print a rather annoying warning whenever a deprecated class name is referenced without enabling classic namespace. ===== Bug Fixes * Several unit tests and functional tests were fixed to run better under windows. * Directory tasks are now a specialized version of a File task. A directory task will only be triggered if it doesn't exist. It will not be triggered if it is out of date w.r.t. any of its prerequisites. * Fixed a bug in the Rake::GemPackageTask class so that the gem now properly contains the platform name. * Fixed a bug where a prerequisite on a file task would cause an exception if the prerequisite did not exist. ==== Thanks As usual, it was input from users that drove a alot of these changes. The following people either contributed patches, made suggestions or made otherwise helpful comments. Thanks to ... * Greg Fast (better ruby_opt test options) * Kelly Felkins (requested by better namespace support) * Martin Fowler (suggested Task.investigation) * Stuart Jansen (send initial patch for multiple prerequisites). * Masao Mutch (better support for non-ruby Gem platforms) * Philipp Neubeck (patch for file task exception fix) -- Jim Weirich === 0.5.4 Time for some minor bug fixes and small enhancements ==== Changes Here are the changes for version 0.5.4 ... * Added double quotes to the test runner. This allows the location of the tests (and runner) to be in a directory path that contains spaces (e.g. "C:/Program Files/ruby/bin"). * Added .svn to default ignore list. Now subversion project metadata is automatically ignored by Rake's FileList. * Updated FileList#include to support nested arrays and filelists. FileLists are flat lists of file names. Using a FileList in an include will flatten out the nested file names. == Thanks As usual, it was input from users that drove a alot of these changes. Thanks to ... * Tilman Sauerbeck for the nested FileList suggestion. * Josh Knowles for pointing out the spaces in directory name problem. -- Jim Weirich === 0.5.3 Although it has only been two weeks since the last release, we have enough updates to the Rake program to make it time for another release. ==== Changes Here are the changes for version 0.5.3 ... * FileLists have been extensively changed so that they mimic the behavior of real arrays even more closely. In particular, operations on FileLists that return a new collection (e.g. collect, reject) will now return a FileList rather than an array. In addition, several places where FileLists were not properly expanded before use have been fixed. * A method (+ext+) to simplify the handling of file extensions was added to String and to Array. * The 'testrb' script in test/unit tends to silently swallow syntax errors in test suites. Because of that, the default test loader is now a rake-provided script. You can still use 'testrb' by setting the loader flag in the test task to :testrb. (See the API documents for TestTask for all the loader flag values). * FileUtil methods (e.g. cp, mv, install) are now declared to be private. This will cut down on the interference with user defined methods of the same name. * Fixed the verbose flag in the TestTask so that the test code is controlled by the flag. Also shortened up some failure messages. (Thanks to Tobias Luetke for the suggestion). * Rules will now properly detect a task that can generate a source file. Previously rules would only consider source files that were already present. * Added an +import+ command that allows Rake to dynamically import dependendencies into a running Rake session. The +import+ command can run tasks to update the dependency file before loading them. Dependency files can be in rake or make format, allowing rake to work with tools designed to generate dependencies for make. ==== Thanks As usual, it was input from users that drove a alot of these changes. Thanks to ... * Brian Gernhardt for the rules fix (especially for the patience to explain the problem to me until I got what he was talking about). * Stefan Lang for pointing out problems in the dark corners of the FileList implementation. * Alexey Verkhovsky pointing out the silently swallows syntax errors in tests. * Tobias Luetke for beautifying the test task output. * Sam Roberts for some of the ideas behind dependency loading. -- Jim Weirich === 0.5.0 It has been a long time in coming, but we finally have a new version of Rake available. ==== Changes * Fixed documentation that was lacking the Rake module name (Tilman Sauerbeck). * Added tar.gz and tar.bz2 support to package task (Tilman Sauerbeck). * Recursive rules are now supported (Tilman Sauerbeck). * Added warning option for the Test Task (requested by Eric Hodel). * The jamis rdoc template is only used if it exists. * Added fix for Ruby 1.8.2 test/unit and rails problem. * Added contributed rake man file (Jani Monoses). * Added Brian Candler's fix for problems in --trace and --dry-run mode. ==== Thanks Lots of people provided input to this release. Thanks to Tilman Sauerbeck for numerous patches, documentation fixes and suggestions. And for also pushing me to get this release out. Also, thanks to Brian Candler for the finding and fixing --trace/dry-run fix. That was an obscure bug. Also to Eric Hodel for some good suggestions. -- Jim Weirich === 0.4.15 ==== Changes Version 0.4.15 is a bug fix update for the Ruby 1.8.2 compatibility changes. This release includes: * Fixed a bug that prevented the TESTOPTS flag from working with the revised for 1.8.2 test task. * Updated the docs on --trace to indicate that it also enables a full backtrace on errors. * Several fixes for new warnings generated. ==== Mini-Roadmap I will continue to issue Rake updates in the 0.4.xx series as new Ruby-1.8.2 issues become manifest. Once the codebase stabilizes, I will release a 0.5.0 version incorporating all the changes. If you are not using Ruby-1.8.2 and wish to avoid version churn, I recommend staying with a release prior to Rake-0.4.14. === 0.4.14 Version 0.4.14 is a compatibility fix to allow Rake's test task to work under Ruby 1.8.2. A change in the Test::Unit autorun feature prevented Rake from running any tests. This release fixes the problem. Rake 0.4.14 is the recommended release for anyone using Ruby 1.8.2. === 0.4.13 * Fixed the dry-run flag so it is operating again. * Multiple arguments to sh and ruby commands will not be interpreted by the shell (patch provided by Jonathan Paisley). === 0.4.12 * Added --silent (-s) to suppress the (in directory) rake message. === 0.4.11 * Changed the "don't know how to rake" message (finally) * Changes references to a literal "Rakefile" to reference the global variable $rakefile (which contains the actual name of the rakefile). === 0.4.10 * Added block support to the "sh" command, allowing users to take special actions on the result of the system call. E.g. sh "shell_command" do |ok, res| puts "Program returned #{res.exitstatus}" if ! ok end === 0.4.9 * Switched to Jamis Buck's RDoc template. * Removed autorequire from Rake's gem spec. This prevents the Rake libraries from loading while using rails. === 0.4.8 * Added support for .rb versions of Rakefile. * Removed \\\n's from test task. * Fixed Ruby 1.9 compatibility issue with FileList. === 0.4.7 * Fixed problem in FileList that caused Ruby 1.9 to go into infinite recursion. Since to_a was removed from Object, it does not need to added back into the list of methods to rewrite in FileList. (Thanks to Kent Sibilev for pointing this out). === 0.4.6 * Removed test version of ln in FileUtils that prevented safe_ln from using ln. === 0.4.5 * Upgraded comments in TestTask. * FileList to_s and inspect now automatically resolve pending changes. * FileList#exclude properly returns the FileList. === 0.4.4 * Fixed initialization problem with @comment. * Now using multi -r technique in TestTask. Switch Rakefile back to using the built-in test task macros because the rake runtime is no longer needed. * Added 'TEST=filename' and 'TESTOPTS=options' to the Test Task macros. * Allow a +test_files+ attribute in test tasks. This allows more flexibility in specifying test files. === 0.4.3 * Fixed Comment leakage. === 0.4.2 * Added safe_ln that falls back to a copy if a file link is not supported. * Package builder now uses safe\_ln. === 0.4.1 * Task comments are now additive, combined with "/". * Works with (soon to be released) rubygems 0.6.2 (or 0.7.0) === 0.4.0 * FileList now uses deferred loading. The file system is not searched until the first call that needs the file names. * VAR=VALUE options are now accepted on the command line and are treated like environment variables. The values may be tested in a Rakefile by referencing ENV['VAR']. * File.mtime is now used (instead of File.new().mtime). === 0.3.2.x * Removed some hidden dependencies on rubygems. Tests now will test gems only if they are installed. * Removed Sys from some example files. I believe that is that last reference to Sys outside of the contrib area. * Updated all copyright notices to include 2004. === 0.3.2 * GEM Installation now works with the application stub. === 0.3.1 * FileLists now automatically ignore CVS, .bak, ! * GEM Installation now works. === 0.3.0 Promoted 0.2.10. === 0.2.10 General * Added title to Rake's rdocs * Contrib packages are no longer included in the documentation. RDoc Issues * Removed default for the '--main' option * Fixed rendering of the rdoc options * Fixed clean/clobber confusion with rerdoc * 'title' attribute added Package Task Library Issues * Version (or explicit :noversion) is required. * +package_file+ attribute is now writable FileList Issues * Dropped bang version of exclude. Now using ant-like include/exclude semantics. * Enabled the "yield self" idiom in FileList#initialize. === 0.2.9 This version contains numerous changes as the RubyConf.new(2003) presentation was being prepared. The changes include: * The monolithic rubyapp task library is in the process of being dropped in favor of lighter weight task libraries. === 0.2.7 * Added "desc" for task descriptions. * -T will now display tasks with descriptions. * -P will display tasks and prerequisites. * Dropped the Sys module in favor of the 1.8.x FileUtils module. Sys is still supported in the contrib area. === 0.2.6 * Moved to RubyForge === 0.2.5 * Switched to standard ruby app builder. * Added no_match option to file matcher. === 0.2.4 * Fixed indir, which neglected to actually change directories. === 0.2.3 * Added rake module for a help target * Added 'for\_files' to Sys * Added a $rakefile constant * Added test for selecting proper rule with multiple targets. PKu]U&rake-13.0.1/CONTRIBUTING.rdocnu[= Source Repository Rake is currently hosted at github. The github web page is https://github.com/ruby/rake . The public git clone URL is https://github.com/ruby/rake.git = Running the Rake Test Suite If you wish to run the unit and functional tests that come with Rake: * +cd+ into the top project directory of rake. * Install gem dependency using bundler: $ bundle install # Install bundler, minitest and rdoc * Run the test suite $ rake = Rubocop Rake uses Rubocop to enforce a consistent style on new changes being proposed. You can check your code with Rubocop using: $ ./bin/rubocop = Issues and Bug Reports Feel free to submit commits or feature requests. If you send a patch, remember to update the corresponding unit tests. In fact, I prefer new feature to be submitted in the form of new unit tests. For other information, feel free to ask on the ruby-talk mailing list. If you have found a bug in rake please try with the latest version of rake before filing an issue. Also check History.rdoc for bug fixes that may have addressed your issue. When submitting pull requests please check the rake Travis-CI page for test failures: https://travis-ci.org/ruby/rake PKu]mǯ racc-1.4.16/bin/raccnuȯ#!/usr/bin/ruby # # $Id$ # # Copyright (c) 1999-2006 Minero Aoki # # This program is free software. # You can distribute/modify this program under the same terms of ruby. # see the file "COPYING". require 'racc/static' require 'optparse' def main output = nil debug_parser = false make_logfile = false logfilename = nil make_executable = false rubypath = nil embed_runtime = false debug_flags = Racc::DebugFlags.new line_convert = true line_convert_all = false omit_action_call = true superclass = nil check_only = false verbose = false profiler = RaccProfiler.new(false) parser = OptionParser.new parser.banner = "Usage: #{File.basename($0)} [options] " parser.on('-o', '--output-file=PATH', 'output file name [.tab.rb]') {|name| output = name } parser.on('-t', '--debug', 'Outputs debugging parser.') {|fl| debug_parser = fl } parser.on('-g', 'Equivalent to -t (obsolete).') {|fl| $stderr.puts "racc -g is obsolete. Use racc -t instead." if $VERBOSE debug_parser = fl } parser.on('-v', '--verbose', 'Creates .output log file.') {|fl| make_logfile = fl } parser.on('-O', '--log-file=PATH', 'Log file name [.output]') {|path| make_logfile = true logfilename = path } parser.on('-e', '--executable [RUBYPATH]', 'Makes executable parser.') {|path| executable = true rubypath = (path == 'ruby' ? nil : path) } parser.on('-E', '--embedded', "Embeds Racc runtime in output.") { embed_runtime = true } parser.on('--line-convert-all', 'Converts line numbers of user codes.') { line_convert_all = true } parser.on('-l', '--no-line-convert', 'Never convert line numbers.') { line_convert = false line_convert_all = false } parser.on('-a', '--no-omit-actions', 'Never omit actions.') { omit_action_call = false } parser.on('--superclass=CLASSNAME', 'Uses CLASSNAME instead of Racc::Parser.') {|name| superclass = name } parser.on('--runtime=FEATURE', "Uses FEATURE instead of 'racc/parser'") {|feat| runtime = feature } parser.on('-C', '--check-only', 'Checks syntax and quit immediately.') {|fl| check_only = fl } parser.on('-S', '--output-status', 'Outputs internal status time to time.') { verbose = true } parser.on('-P', 'Enables generator profile') { profiler = RaccProfiler.new(true) } parser.on('-D flags', "Flags for Racc debugging (do not use).") {|flags| debug_flags = Racc::DebugFlags.parse_option_string(flags) } #parser.on('--no-extensions', 'Run Racc without any Ruby extension.') { # Racc.const_set :Racc_No_Extentions, true #} parser.on('--version', 'Prints version and quit.') { puts "racc version #{Racc::Version}" exit 0 } parser.on('--runtime-version', 'Prints runtime version and quit.') { printf "racc runtime version %s (rev. %s); %s\n", Racc::Parser::Racc_Runtime_Version, Racc::Parser::Racc_Runtime_Revision, if Racc::Parser.racc_runtime_type == 'ruby' sprintf('ruby core version %s (rev. %s)', Racc::Parser::Racc_Runtime_Core_Version_R, Racc::Parser::Racc_Runtime_Core_Revision_R) else sprintf('c core version %s (rev. %s)', Racc::Parser::Racc_Runtime_Core_Version_C, Racc::Parser::Racc_Runtime_Core_Revision_C) end exit 0 } parser.on('--copyright', 'Prints copyright and quit.') { puts Racc::Copyright exit 0 } parser.on('--help', 'Prints this message and quit.') { puts parser.help exit 1 } begin parser.parse! rescue OptionParser::ParseError => err $stderr.puts err.message $stderr.puts parser.help exit 1 end if ARGV.empty? $stderr.puts 'no input' exit 1 end if ARGV.size > 1 $stderr.puts 'too many input' exit 1 end input = ARGV[0] begin $stderr.puts 'Parsing grammar file...' if verbose result = profiler.section('parse') { parser = Racc::GrammarFileParser.new(debug_flags) parser.parse(File.read(input), File.basename(input)) } if check_only $stderr.puts 'syntax ok' exit 0 end $stderr.puts 'Generating LALR states...' if verbose states = profiler.section('nfa') { Racc::States.new(result.grammar).nfa } $stderr.puts "Resolving #{states.size} states..." if verbose profiler.section('dfa') { states.dfa } $stderr.puts 'Creating parser file...' if verbose params = result.params.dup # Overwrites parameters given by a grammar file with command line options. params.superclass = superclass if superclass params.omit_action_call = true if omit_action_call # From command line option if make_executable params.make_executable = true params.interpreter = rubypath end params.debug_parser = debug_parser params.convert_line = line_convert params.convert_line_all = line_convert_all params.embed_runtime = embed_runtime profiler.section('generation') { generator = Racc::ParserFileGenerator.new(states, params) generator.generate_parser_file(output || make_filename(input, '.tab.rb')) } if make_logfile profiler.section('logging') { $stderr.puts 'Creating log file...' if verbose logfilename ||= make_filename(output || File.basename(input), '.output') File.open(logfilename, 'w') {|f| Racc::LogFileGenerator.new(states, debug_flags).output f } } end if debug_flags.status_logging log_useless states.grammar log_conflict states else report_useless states.grammar report_conflict states end profiler.report rescue Racc::Error, Errno::ENOENT, Errno::EPERM => err raise if $DEBUG or debug_flags.any? lineno = err.message.slice(/\A\d+:/).to_s $stderr.puts "#{File.basename $0}: #{input}:#{lineno} #{err.message.strip}" exit 1 end end def make_filename(path, suffix) path.sub(/(?:\..*?)?\z/, suffix) end def report_conflict(states) if states.should_report_srconflict? $stderr.puts "#{states.n_srconflicts} shift/reduce conflicts" end if states.rrconflict_exist? $stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts" end end def log_conflict(states) logging('w') {|f| f.puts "ex#{states.grammar.n_expected_srconflicts}" if states.should_report_srconflict? f.puts "sr#{states.n_srconflicts}" end if states.rrconflict_exist? f.puts "rr#{states.n_rrconflicts}" end } end def report_useless(grammar) if grammar.useless_nonterminal_exist? $stderr.puts "#{grammar.n_useless_nonterminals} useless nonterminals" end if grammar.useless_rule_exist? $stderr.puts "#{grammar.n_useless_rules} useless rules" end if grammar.start.useless? $stderr.puts 'fatal: start symbol does not derive any sentence' end end def log_useless(grammar) logging('a') {|f| if grammar.useless_nonterminal_exist? f.puts "un#{grammar.n_useless_nonterminals}" end if grammar.useless_rule_exist? f.puts "ur#{grammar.n_useless_rules}" end } end def logging(mode, &block) File.open("log/#{File.basename(ARGV[0])}", mode, &block) end class RaccProfiler def initialize(really) @really = really @log = [] unless ::Process.respond_to?(:times) # Ruby 1.6 @class = ::Time else @class = ::Process end end def section(name) if @really t1 = @class.times.utime result = yield t2 = @class.times.utime @log.push [name, t2 - t1] result else yield end end def report return unless @really f = $stderr total = cumulative_time() f.puts '--task-----------+--sec------+---%-' @log.each do |name, time| f.printf "%-19s %s %3d%%\n", name, pjust(time,4,4), (time/total*100).to_i end f.puts '-----------------+-----------+-----' f.printf "%-20s%s\n", 'total', pjust(total,4,4) end private def cumulative_time t = @log.inject(0) {|sum, (name, time)| sum + time } t == 0 ? 0.01 : t end def pjust(num, i, j) m = /(\d+)(\.\d+)?/.match(num.to_s) str = m[1].rjust(i) str.concat m[2].ljust(j+1)[0,j+1] if m[2] str end end main PKu]*ruby-lsapi-5.6/ext/lsapi/.sitearchdir.timenu[PKu]Y//#ruby-lsapi-5.6/ext/lsapi/lsapilib.hnu[/* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _LSAPILIB_H_ #define _LSAPILIB_H_ #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif #include "lsapidef.h" #include #include #include struct LSAPI_key_value_pair { char * pKey; char * pValue; int keyLen; int valLen; }; struct lsapi_child_status; #define LSAPI_MAX_RESP_HEADERS 1000 typedef struct lsapi_request { int m_fdListen; int m_fd; long m_lLastActive; long m_lReqBegin; char * m_pReqBuf; int m_reqBufSize; char * m_pRespBuf; char * m_pRespBufEnd; char * m_pRespBufPos; char * m_pRespHeaderBuf; char * m_pRespHeaderBufEnd; char * m_pRespHeaderBufPos; struct lsapi_child_status * child_status; struct iovec * m_pIovec; struct iovec * m_pIovecEnd; struct iovec * m_pIovecCur; struct iovec * m_pIovecToWrite; struct lsapi_packet_header * m_respPktHeaderEnd; struct lsapi_req_header * m_pHeader; struct LSAPI_key_value_pair * m_pEnvList; struct LSAPI_key_value_pair * m_pSpecialEnvList; int m_envListSize; int m_specialEnvListSize; struct lsapi_http_header_index * m_pHeaderIndex; struct lsapi_header_offset * m_pUnknownHeader; char * m_pScriptFile; char * m_pScriptName; char * m_pQueryString; char * m_pHttpHeader; char * m_pRequestMethod; int m_totalLen; int m_reqState; off_t m_reqBodyLen; off_t m_reqBodyRead; int m_bufProcessed; int m_bufRead; struct lsapi_packet_header m_respPktHeader[5]; struct lsapi_resp_header m_respHeader; short m_respHeaderLen[LSAPI_MAX_RESP_HEADERS]; void * m_pAppData; }LSAPI_Request; extern LSAPI_Request g_req; /* return: >0 continue, ==0 stop, -1 failed */ typedef int (*LSAPI_CB_EnvHandler )( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ); int LSAPI_Init(void); void LSAPI_Stop(void); int LSAPI_Is_Listen_r( LSAPI_Request * pReq); int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ); int LSAPI_Accept_r( LSAPI_Request * pReq ); void LSAPI_Reset_r( LSAPI_Request * pReq ); int LSAPI_Finish_r( LSAPI_Request * pReq ); int LSAPI_Release_r( LSAPI_Request * pReq ); char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ); int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ); char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ); ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t len ); int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ); int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF ); int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ); ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len ); ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size ); ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len ); int LSAPI_Flush_r( LSAPI_Request * pReq ); int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len ); int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName, const char * pHeaderValue ); int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders, const char * pBody, int bodyLen ); static inline int LSAPI_SetRespStatus_r( LSAPI_Request * pReq, int code ) { if ( !pReq ) return -1; pReq->m_respHeader.m_respInfo.m_status = code; return 0; } static inline int LSAPI_SetAppData_r( LSAPI_Request * pReq, void * data ) { if ( !pReq ) return -1; pReq->m_pAppData = data; return 0; } static inline void * LSAPI_GetAppData_r( LSAPI_Request * pReq ) { if ( !pReq ) return NULL; return pReq->m_pAppData; } static inline char * LSAPI_GetQueryString_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pQueryString; return NULL; } static inline char * LSAPI_GetScriptFileName_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pScriptFile; return NULL; } static inline char * LSAPI_GetScriptName_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_pScriptName; return NULL; } static inline char * LSAPI_GetRequestMethod_r( LSAPI_Request * pReq) { if ( pReq ) return pReq->m_pRequestMethod; return NULL; } static inline off_t LSAPI_GetReqBodyLen_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_reqBodyLen; return -1; } static inline off_t LSAPI_GetReqBodyRemain_r( LSAPI_Request * pReq ) { if ( pReq ) return pReq->m_reqBodyLen - pReq->m_reqBodyRead; return -1; } int LSAPI_End_Response_r(LSAPI_Request * pReq); int LSAPI_Is_Listen(void); static inline int LSAPI_Accept( void ) { return LSAPI_Accept_r( &g_req ); } static inline int LSAPI_Finish(void) { return LSAPI_Finish_r( &g_req ); } static inline char * LSAPI_GetHeader( int headerIndex ) { return LSAPI_GetHeader_r( &g_req, headerIndex ); } static inline int LSAPI_ForeachHeader( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachHeader_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachOrgHeader( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachOrgHeader_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachEnv( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachEnv_r( &g_req, fn, arg ); } static inline int LSAPI_ForeachSpecialEnv( LSAPI_CB_EnvHandler fn, void * arg ) { return LSAPI_ForeachSpecialEnv_r( &g_req, fn, arg ); } static inline char * LSAPI_GetEnv( const char * name ) { return LSAPI_GetEnv_r( &g_req, name ); } static inline char * LSAPI_GetQueryString(void) { return LSAPI_GetQueryString_r( &g_req ); } static inline char * LSAPI_GetScriptFileName(void) { return LSAPI_GetScriptFileName_r( &g_req ); } static inline char * LSAPI_GetScriptName(void) { return LSAPI_GetScriptName_r( &g_req ); } static inline char * LSAPI_GetRequestMethod(void) { return LSAPI_GetRequestMethod_r( &g_req ); } static inline off_t LSAPI_GetReqBodyLen(void) { return LSAPI_GetReqBodyLen_r( &g_req ); } static inline off_t LSAPI_GetReqBodyRemain(void) { return LSAPI_GetReqBodyRemain_r( &g_req ); } static inline ssize_t LSAPI_ReadReqBody( char * pBuf, size_t len ) { return LSAPI_ReadReqBody_r( &g_req, pBuf, len ); } static inline int LSAPI_ReqBodyGetChar(void) { return LSAPI_ReqBodyGetChar_r( &g_req ); } static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF ) { return LSAPI_ReqBodyGetLine_r( &g_req, pBuf, len, getLF ); } static inline int LSAPI_FinalizeRespHeaders(void) { return LSAPI_FinalizeRespHeaders_r( &g_req ); } static inline ssize_t LSAPI_Write( const char * pBuf, ssize_t len ) { return LSAPI_Write_r( &g_req, pBuf, len ); } static inline ssize_t LSAPI_sendfile( int fdIn, off_t* off, size_t size ) { return LSAPI_sendfile_r(&g_req, fdIn, off, size ); } static inline ssize_t LSAPI_Write_Stderr( const char * pBuf, ssize_t len ) { return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); } static inline int LSAPI_Flush(void) { return LSAPI_Flush_r( &g_req ); } static inline int LSAPI_AppendRespHeader( char * pBuf, int len ) { return LSAPI_AppendRespHeader_r( &g_req, pBuf, len ); } static inline int LSAPI_SetRespStatus( int code ) { return LSAPI_SetRespStatus_r( &g_req, code ); } static inline int LSAPI_ErrResponse( int code, const char ** pRespHeaders, const char * pBody, int bodyLen ) { return LSAPI_ErrResponse_r( &g_req, code, pRespHeaders, pBody, bodyLen ); } static inline int LSAPI_End_Response(void) { return LSAPI_End_Response_r( &g_req ); } int LSAPI_IsRunning(void); int LSAPI_CreateListenSock( const char * pBind, int backlog ); typedef int (*fn_select_t)( int, fd_set *, fd_set *, fd_set *, struct timeval * ); int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ); void LSAPI_Set_Server_fd( int fd ); int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ); void LSAPI_No_Check_ppid(void); void LSAPI_Set_Max_Reqs( int reqs ); void LSAPI_Set_Max_Idle( int secs ); void LSAPI_Set_Max_Children( int maxChildren ); void LSAPI_Set_Max_Idle_Children( int maxIdleChld ); void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ); void LSAPI_Set_Max_Process_Time( int secs ); int LSAPI_Init_Env_Parameters( fn_select_t fp ); void LSAPI_Set_Slow_Req_Msecs( int msecs ); int LSAPI_Get_Slow_Req_Msecs(void); int LSAPI_is_suEXEC_Daemon(void); int LSAPI_Set_Restored_Parent_Pid(int pid); typedef void (*LSAPI_On_Timer_pf)(int *forked_child_pid); void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf); int LSAPI_Inc_Req_Processed(int cnt); int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq); int LSAPI_Postfork_Child(LSAPI_Request * pReq); int LSAPI_Postfork_Parent(LSAPI_Request * pReq); #define LSAPI_LOG_LEVEL_BITS 0xff #define LSAPI_LOG_FLAG_NONE 0 #define LSAPI_LOG_FLAG_DEBUG 1 #define LSAPI_LOG_FLAG_INFO 2 #define LSAPI_LOG_FLAG_NOTICE 3 #define LSAPI_LOG_FLAG_WARN 4 #define LSAPI_LOG_FLAG_ERROR 5 #define LSAPI_LOG_FLAG_CRIT 6 #define LSAPI_LOG_FLAG_FATAL 7 #define LSAPI_LOG_TIMESTAMP_BITS (0xff00) #define LSAPI_LOG_TIMESTAMP_FULL (0x100) #define LSAPI_LOG_TIMESTAMP_HMS (0x200) #define LSAPI_LOG_TIMESTAMP_STDERR (0x400) #define LSAPI_LOG_PID (0x10000) void LSAPI_Log(int flag, const char * fmt, ...) #if __GNUC__ __attribute__((format(printf, 2, 3))) #endif ; #if defined (c_plusplus) || defined (__cplusplus) } #endif #endif PKu]7Zw#ruby-lsapi-5.6/ext/lsapi/extconf.rbnu[require 'mkmf' dir_config( 'lsapi' ) if ( have_library( "socket" )) have_library( "nsl" ) end if RUBY_VERSION =~ /1.9/ then $CPPFLAGS += " -DRUBY_19" end if RUBY_VERSION =~ /2/ then $CPPFLAGS += " -DRUBY_2" end create_makefile( "lsapi" ) PKu]dCR[R[!ruby-lsapi-5.6/ext/lsapi/lsruby.cnu[ #include "ruby.h" #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 #include "util.h" #else #include #include #endif #include "lsapilib.h" #include #include #include #include #include #include #include #include #include #ifndef RUBY_API_VERSION_CODE #define RUBY_API_VERSION_CODE (RUBY_API_VERSION_MAJOR*10000+RUBY_API_VERSION_MINOR*100+RUBY_API_VERSION_TEENY) #endif /* RUBY_EXTERN VALUE ruby_errinfo; */ RUBY_EXTERN VALUE rb_stdin; RUBY_EXTERN VALUE rb_stdout; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 RUBY_EXTERN VALUE rb_defout; #endif static VALUE orig_stdin; static VALUE orig_stdout; static VALUE orig_stderr; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 static VALUE orig_defout; #endif static VALUE orig_env; static VALUE env_copy; static VALUE lsapi_env; static int MAX_BODYBUF_LENGTH = (10 * 1024 * 1024); #if RUBY_API_VERSION_CODE >= 20700 # if defined rb_tainted_str_new # undef rb_tainted_str_new # endif # define rb_tainted_str_new(p,l) rb_str_new((p),(l)) #endif /* static VALUE lsapi_objrefs; */ typedef struct lsapi_data { LSAPI_Request * req; VALUE env; ssize_t (* fn_write)( LSAPI_Request *, const char * , size_t ); }lsapi_data; static VALUE cLSAPI; static VALUE s_req = Qnil; static lsapi_data * s_req_data; static VALUE s_req_stderr = Qnil; static lsapi_data * s_stderr_data; static pid_t s_pid = 0; typedef struct lsapi_body { char *bodyBuf; //we put small one into memory, otherwise, into a memory mapping file, and we still use the bodyBuf to access this mapping int bodyLen; //expected length got form content-length int bodyCurrentLen; //current length by read() readBodyToReqBuf int curPos; }lsapi_body; static lsapi_body s_body; static char sTempFile[1024] = {0}; /* * static void lsapi_ruby_setenv(const char *name, const char *value) * { * if (!name) return; * * if (value && *value) * ruby_setenv(name, value); * else * ruby_unsetenv(name); } * * */ static void lsapi_mark( lsapi_data * data ) { rb_gc_mark( data->env ); } /* * static void lsapi_free_data( lsapi_data * data ) * { * free( data ); } * * */ static int add_env_rails( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { char * p; int len; /* Fixup some environment variables for rails */ switch( *pKey ) { case 'Q': if ( strcmp( pKey, "QUERY_STRING" ) == 0 ) { if ( !*pValue ) return 1; } break; case 'R': if (( *(pKey+8) == 'U' )&&( strcmp( pKey, "REQUEST_URI" ) == 0 )) { p = strchr( pValue, '?' ); if ( p ) { len = valLen - ( p - pValue ) - 1; /* * valLen = p - pValue; *p++ = 0; */ } else { p = (char *)pValue + valLen; len = 0; } rb_hash_aset( lsapi_env,rb_tainted_str_new("PATH_INFO", 9), rb_tainted_str_new(pValue, p - pValue)); rb_hash_aset( lsapi_env,rb_tainted_str_new("REQUEST_PATH", 12), rb_tainted_str_new(pValue, p - pValue)); if ( *p == '?' ) ++p; rb_hash_aset( lsapi_env,rb_tainted_str_new("QUERY_STRING", 12), rb_tainted_str_new(p, len)); } break; case 'S': if ( strcmp( pKey, "SCRIPT_NAME" ) == 0 ) { pValue = "/"; valLen = 1; } break; case 'P': if ( strcmp( pKey, "PATH_INFO" ) == 0 ) return 1; default: break; } /* lsapi_ruby_setenv(pKey, pValue ); */ rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen), rb_tainted_str_new(pValue, valLen)); return 1; } static int add_env_no_fix( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen), rb_tainted_str_new(pValue, valLen)); return 1; } typedef int (*fn_add_env)( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ); fn_add_env s_fn_add_env = add_env_no_fix; static void clear_env() { /* rb_funcall( lsapi_env, rb_intern( "clear" ), 0 ); */ rb_funcall( lsapi_env, rb_intern( "replace" ), 1, env_copy ); } static void setup_cgi_env( lsapi_data * data ) { clear_env(); LSAPI_ForeachHeader_r( data->req, s_fn_add_env, data ); LSAPI_ForeachEnv_r( data->req, s_fn_add_env, data ); } static VALUE lsapi_s_accept( VALUE self ) { int pid; if ( LSAPI_Prefork_Accept_r( &g_req ) == -1 ) return Qnil; else { if (s_body.bodyBuf != NULL) free (s_body.bodyBuf); s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; pid = getpid(); if ( pid != s_pid ) { s_pid = pid; rb_funcall( Qnil, rb_intern( "srand" ), 0 ); } setup_cgi_env( s_req_data ); return s_req; } } static VALUE lsapi_s_accept_new_conn(VALUE self) { if (LSAPI_Accept_Before_Fork(&g_req) == -1 ) return Qnil; else return s_req; } static VALUE lsapi_s_postfork_child(VALUE self) { LSAPI_Postfork_Child(&g_req); return s_req; } static VALUE lsapi_s_postfork_parent(VALUE self) { LSAPI_Postfork_Parent(&g_req); return s_req; } /* * static int chdir_file( const char * pFile ) * { * char * p = strrchr( pFile, '/' ); * int ret; * if ( !p ) * return -1; *p = 0; ret = chdir( pFile ); *p = '/'; return ret; } */ static VALUE lsapi_eval_string_wrap(VALUE self, VALUE str) { #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4) { Check_Type(str, T_STRING); } else #endif { SafeStringValue(str); } return rb_eval_string_wrap(StringValuePtr(str), NULL); } static VALUE lsapi_process( VALUE self ) { /* lsapi_data *data; const char * pScriptPath; Data_Get_Struct(self,lsapi_data, data); pScriptPath = LSAPI_GetScriptFileName_r( data->req ); */ /* * if ( chdir_file( pScriptPath ) == -1 ) * { * lsapi_send_error( 404 ); * } * rb_load_file( pScriptPath ); */ return Qnil; } static VALUE lsapi_putc(VALUE self, VALUE c) { char ch = NUM2CHR(c); lsapi_data *data; Data_Get_Struct(self,lsapi_data, data); if ( (*data->fn_write)( data->req, &ch, 1 ) == 1 ) return c; else return INT2NUM( EOF ); } static VALUE lsapi_write( VALUE self, VALUE str ) { lsapi_data *data; int len; Data_Get_Struct(self,lsapi_data, data); /* len = LSAPI_Write_r( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); */ if (TYPE(str) != T_STRING) str = rb_obj_as_string(str); len = (*data->fn_write)( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); return INT2NUM( len ); } static VALUE lsapi_print( int argc, VALUE *argv, VALUE out ) { int i; VALUE line; /* if no argument given, print `$_' */ if (argc == 0) { argc = 1; line = rb_lastline_get(); argv = &line; } for (i = 0; i0) { lsapi_write(out, rb_output_fs); } switch (TYPE(argv[i])) { case T_NIL: lsapi_write(out, rb_str_new2("nil")); break; default: lsapi_write(out, argv[i]); break; } } if (!NIL_P(rb_output_rs)) { lsapi_write(out, rb_output_rs); } return Qnil; } static VALUE lsapi_printf(int argc, VALUE *argv, VALUE out) { lsapi_write(out, rb_f_sprintf(argc, argv)); return Qnil; } static VALUE lsapi_puts _((int, VALUE*, VALUE)); #if RUBY_API_VERSION_CODE >= 10900 static VALUE lsapi_puts_ary(VALUE ary, VALUE out, int recur ) { VALUE tmp; long i; if (recur) { tmp = rb_str_new2("[...]"); rb_io_puts(1, &tmp, out); return Qnil; } for (i=0; i= 10900 rb_exec_recursive(lsapi_puts_ary, argv[i], out); #else rb_protect_inspect(lsapi_puts_ary, argv[i], out); #endif continue; default: line = argv[i]; break; } line = rb_obj_as_string(line); lsapi_write(out, line); if (*( RSTRING_PTR(line) + RSTRING_LEN(line) - 1 ) != '\n') { lsapi_write(out, rb_default_rs); } } return Qnil; } static VALUE lsapi_addstr(VALUE out, VALUE str) { lsapi_write(out, str); return out; } static VALUE lsapi_flush( VALUE self ) { /* * lsapi_data *data; * Data_Get_Struct(self,lsapi_data, data); */ LSAPI_Flush_r( &g_req ); return Qnil; } static VALUE lsapi_getc( VALUE self ) { int ch; /* * lsapi_data *data; * Data_Get_Struct(self,lsapi_data, data); */ #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif ch = LSAPI_ReqBodyGetChar_r( &g_req ); if ( ch == EOF ) return Qnil; return INT2NUM( ch ); } static inline int isBodyWriteToFile() { return ((s_body.bodyLen >= MAX_BODYBUF_LENGTH)? (1): (0)); } //create a temp file and open it, if failed, fd = -1 static inline int createTempFile() { int fd = -1; char *sfn = strdup(sTempFile); if ((fd = mkstemp(sfn)) == -1) { fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); } else unlink(sfn); free(sfn); return fd; } //return 1 if error occured! //if already created, always OK (0) static int createBodyBuf() { int fd = -1; if (s_body.bodyLen == -1) { s_body.bodyLen = LSAPI_GetReqBodyLen_r(&g_req); //Error if get a zeor length, should not happen if (s_body.bodyLen < 0) { //Wrong bode length will be treated as 0 s_body.bodyLen = 0; } if (s_body.bodyLen > 0) { if (isBodyWriteToFile()) { //create file mapping fd = createTempFile(); if (fd == -1) { return 1; } if (ftruncate(fd, s_body.bodyLen) == 0) { perror("ftruncate() failed. \n"); close(fd); return 1; } s_body.bodyBuf = mmap(NULL, s_body.bodyLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (s_body.bodyBuf == MAP_FAILED) { perror("File mapping failed. \n"); close(fd); return 1; } close(fd); //close since needn't it anymore } else { s_body.bodyBuf = (char *)calloc(s_body.bodyLen, sizeof(char)); if (s_body.bodyBuf == NULL) { perror("Memory calloc error"); return 1; } } } } return 0; } static inline int isAllBodyRead() { return (s_body.bodyCurrentLen < s_body.bodyLen)? 0 : 1; } static inline int isEofBodyBuf() { return (s_body.curPos < s_body.bodyLen) ? 0 : 1; } //try to read length as times pagesize (such as 8KB * N) static int readBodyBuf(const int needRead) { const int blockSize = 8192; char *buff = s_body.bodyBuf + s_body.bodyCurrentLen; int nRead; int readMore = (needRead + blockSize -1) / blockSize * blockSize; int remain = LSAPI_GetReqBodyRemain_r( &g_req ); //Only when not enough left, needReadChange will be changed!!! if (remain < readMore) readMore = remain; if ( readMore <= 0 ) return 0; nRead = LSAPI_ReadReqBody_r(&g_req, buff, readMore); if ( nRead > 0 ) s_body.bodyCurrentLen += nRead; return nRead; } static VALUE lsapi_gets( VALUE self ) { VALUE str; const int blkSize = 4096; int n; char *p = NULL; #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif if (createBodyBuf() == 1) { return Qnil; } //comment: while((p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1)) == NULL) { if (isAllBodyRead() == 1) break; //read one page and check, then reply readBodyBuf(blkSize); } p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1); if (p != NULL) n = p - s_body.bodyBuf - s_body.curPos + 1; else n = s_body.bodyCurrentLen - s_body.curPos; str = rb_str_buf_new( n ); #if RUBY_API_VERSION_CODE < 20700 OBJ_TAINT(str); #endif if (n > 0) { rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n ); s_body.curPos += n; } return str; } static VALUE lsapi_read(int argc, VALUE *argv, VALUE self) { VALUE str; int n; int needRead; int nRead; #if RUBY_API_VERSION_CODE < 20700 if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); } #endif if (createBodyBuf() == 1) { return Qnil; } //we need to consider these 4 cases: //1, need all data since argc == 0, we may have all data 2, or not //3, need a length of data (argv >= 1), we may have enough data already read, 4, or not if (argc == 0) n = s_body.bodyLen - s_body.curPos; else { n = NUM2INT(argv[0]); //request that length from currentpos if (n < 0) return Qnil; if (n > s_body.bodyLen - s_body.curPos) n = s_body.bodyLen - s_body.curPos; } needRead = s_body.curPos + n - s_body.bodyCurrentLen; if (needRead < 0) needRead = 0; str = rb_str_buf_new( n ); #if RUBY_API_VERSION_CODE < 20700 OBJ_TAINT(str); #endif if (n == 0) return str; //copy already have part first if (n - needRead != 0) { rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n - needRead); s_body.curPos += (n - needRead); } if (needRead > 0) { //try to read needRead, but may be less (changed) when read the end of the data nRead = readBodyBuf(needRead); if (nRead > 0) { n = ((nRead < needRead) ? nRead : needRead); rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n ); s_body.curPos += n; } } return str; } static VALUE lsapi_rewind(VALUE self) { s_body.curPos = 0; return self; } static VALUE lsapi_each(VALUE self) { VALUE str; lsapi_rewind(self); while(isEofBodyBuf() != 1) { str = lsapi_gets(self); rb_yield(str); } return self; } static VALUE lsapi_eof(VALUE self) { return (LSAPI_GetReqBodyRemain_r( &g_req ) <= 0) ? Qtrue : Qfalse; } static VALUE lsapi_binmode(VALUE self) { return self; } static VALUE lsapi_isatty(VALUE self) { return Qfalse; } static VALUE lsapi_sync(VALUE self) { return Qfalse; } static VALUE lsapi_setsync(VALUE self,VALUE sync) { return Qfalse; } static VALUE lsapi_close(VALUE self) { LSAPI_Flush_r( &g_req ); if (isBodyWriteToFile()) { //msync(s_body.bodyBuf, s_body.bodyLen, MS_SYNC); //sleep(5); munmap(s_body.bodyBuf, s_body.bodyLen); } else free(s_body.bodyBuf); s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; //Should the temp be deleted here?! return Qnil; } static VALUE lsapi_reopen( int argc, VALUE *argv, VALUE self) { VALUE orig_verbose; if ( self == s_req_stderr ) { /* constant silence hack */ orig_verbose = (VALUE)ruby_verbose; ruby_verbose = Qnil; rb_define_global_const("STDERR", orig_stderr); ruby_verbose = (VALUE)orig_verbose; return rb_funcall2( orig_stderr, rb_intern( "reopen" ), argc, argv ); } return self; } static void readMaxBodyBufLength() { int n; const char *p = getenv( "LSAPI_MAX_BODYBUF_LENGTH" ); if ( p ) { n = atoi( p ); if (n > 0) { if (strstr(p, "M") || strstr(p, "m")) MAX_BODYBUF_LENGTH = n * 1024 * 1024; else if (strstr(p, "K") || strstr(p, "k")) MAX_BODYBUF_LENGTH = n * 1024; else MAX_BODYBUF_LENGTH = n; } } } static void readTempFileTemplate() { const char *p = getenv( "LSAPI_TEMPFILE" ); if (p == NULL || strlen(p) > 1024 - 7) p = "/tmp/lsapi.XXXXXX"; strcpy(sTempFile, p); if (strlen(p) <= 6 || strcmp(p + (strlen(p) - 6), "XXXXXX") != 0) strcat(sTempFile, ".XXXXXX"); } static void initBodyBuf() { s_body.bodyBuf = NULL; s_body.bodyLen = -1; s_body.bodyCurrentLen = 0; s_body.curPos = 0; } void Init_lsapi() { VALUE orig_verbose; char * p; int prefork = 0; LSAPI_Init(); initBodyBuf(); readMaxBodyBufLength(); readTempFileTemplate(); p = getenv("LSAPI_CHILDREN"); if (p && atoi(p) > 1) prefork = 1; #ifdef rb_thread_select LSAPI_Init_Env_Parameters( rb_thread_select ); #else LSAPI_Init_Env_Parameters( select ); #endif s_pid = getpid(); p = getenv( "RACK_ROOT" ); if ( p ) { if ( chdir( p ) == -1 ) perror( "chdir()" ); } if ( p || getenv( "RACK_ENV" ) ) s_fn_add_env = add_env_rails; orig_stdin = rb_stdin; orig_stdout = rb_stdout; orig_stderr = rb_stderr; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 orig_defout = rb_defout; #endif orig_env = rb_const_get( rb_cObject, rb_intern("ENV") ); env_copy = rb_funcall( orig_env, rb_intern( "to_hash" ), 0 ); /* tell the garbage collector it is a global variable, do not recycle it. */ rb_global_variable(&env_copy); rb_hash_aset( env_copy,rb_tainted_str_new("GATEWAY_Irewindable_input.rbNTERFACE", 17), rb_tainted_str_new("CGI/1.2", 7)); rb_define_global_function("eval_string_wrap", lsapi_eval_string_wrap, 1); cLSAPI = rb_define_class("LSAPI", rb_cObject); rb_define_singleton_method(cLSAPI, "accept", lsapi_s_accept, 0); if (prefork) { rb_define_singleton_method(cLSAPI, "accept_new_connection", lsapi_s_accept_new_conn, 0); rb_define_singleton_method(cLSAPI, "postfork_child", lsapi_s_postfork_child, 0); rb_define_singleton_method(cLSAPI, "postfork_parent", lsapi_s_postfork_parent, 0); } rb_define_method(cLSAPI, "process", lsapi_process, 0 ); /* rb_define_method(cLSAPI, "initialize", lsapi_initialize, 0); */ rb_define_method(cLSAPI, "putc", lsapi_putc, 1); rb_define_method(cLSAPI, "write", lsapi_write, 1); rb_define_method(cLSAPI, "print", lsapi_print, -1); rb_define_method(cLSAPI, "printf", lsapi_printf, -1); rb_define_method(cLSAPI, "puts", lsapi_puts, -1); rb_define_method(cLSAPI, "<<", lsapi_addstr, 1); rb_define_method(cLSAPI, "flush", lsapi_flush, 0); rb_define_method(cLSAPI, "getc", lsapi_getc, 0); /* rb_define_method(cLSAPI, "ungetc", lsapi_ungetc, 1); */ rb_define_method(cLSAPI, "gets", lsapi_gets, 0); //TEST: adding readline function to make irb happy? /*rb_define_method(cLSAPI, "readline", lsapi_gets, 0); */ rb_define_method(cLSAPI, "read", lsapi_read, -1); rb_define_method(cLSAPI, "rewind", lsapi_rewind, 0); rb_define_method(cLSAPI, "each", lsapi_each, 0); rb_define_method(cLSAPI, "eof", lsapi_eof, 0); rb_define_method(cLSAPI, "eof?", lsapi_eof, 0); rb_define_method(cLSAPI, "close", lsapi_close, 0); /* rb_define_method(cLSAPI, "closed?", lsapi_closed, 0); */ rb_define_method(cLSAPI, "binmode", lsapi_binmode, 0); rb_define_method(cLSAPI, "isatty", lsapi_isatty, 0); rb_define_method(cLSAPI, "tty?", lsapi_isatty, 0); rb_define_method(cLSAPI, "sync", lsapi_sync, 0); rb_define_method(cLSAPI, "sync=", lsapi_setsync, 1); rb_define_method(cLSAPI, "reopen", lsapi_reopen, -1 ); s_req = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_req_data ); s_req_data->req = &g_req; s_req_data->fn_write = LSAPI_Write_r; rb_stdin = rb_stdout = s_req; #if defined( RUBY_VERSION_CODE ) && RUBY_VERSION_CODE < 180 rb_defout = s_req; #endif rb_global_variable(&s_req ); s_req_stderr = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_stderr_data ); s_stderr_data->req = &g_req; s_stderr_data->fn_write = LSAPI_Write_Stderr_r; rb_stderr = s_req_stderr; rb_global_variable(&s_req_stderr ); /* constant silence hack */ orig_verbose = (VALUE)ruby_verbose; ruby_verbose = Qnil; lsapi_env = rb_hash_new(); clear_env(); /* redefine ENV using a hash table, should be faster than char **environment */ rb_define_global_const("ENV", lsapi_env); rb_define_global_const("STDERR", rb_stderr); ruby_verbose = (VALUE)orig_verbose; return; } PKu]W q,,#ruby-lsapi-5.6/ext/lsapi/lsapidef.hnu[/* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _LSAPIDEF_H_ #define _LSAPIDEF_H_ #include #if defined (c_plusplus) || defined (__cplusplus) extern "C" { #endif enum { H_ACCEPT = 0, H_ACC_CHARSET, H_ACC_ENCODING, H_ACC_LANG, H_AUTHORIZATION, H_CONNECTION, H_CONTENT_TYPE, H_CONTENT_LENGTH, H_COOKIE, H_COOKIE2, H_HOST, H_PRAGMA, H_REFERER, H_USERAGENT, H_CACHE_CTRL, H_IF_MODIFIED_SINCE, H_IF_MATCH, H_IF_NO_MATCH, H_IF_RANGE, H_IF_UNMOD_SINCE, H_KEEP_ALIVE, H_RANGE, H_X_FORWARDED_FOR, H_VIA, H_TRANSFER_ENCODING }; #define LSAPI_SOCK_FILENO 0 #define LSAPI_VERSION_B0 'L' #define LSAPI_VERSION_B1 'S' /* Values for m_flag in lsapi_packet_header */ #define LSAPI_ENDIAN_LITTLE 0 #define LSAPI_ENDIAN_BIG 1 #define LSAPI_ENDIAN_BIT 1 #if defined(__i386__)||defined( __x86_64 )||defined( __x86_64__ ) #define LSAPI_ENDIAN LSAPI_ENDIAN_LITTLE #else #define LSAPI_ENDIAN LSAPI_ENDIAN_BIG #endif /* Values for m_type in lsapi_packet_header */ #define LSAPI_BEGIN_REQUEST 1 #define LSAPI_ABORT_REQUEST 2 #define LSAPI_RESP_HEADER 3 #define LSAPI_RESP_STREAM 4 #define LSAPI_RESP_END 5 #define LSAPI_STDERR_STREAM 6 #define LSAPI_REQ_RECEIVED 7 #define LSAPI_CONN_CLOSE 8 #define LSAPI_INTERNAL_ERROR 9 #define LSAPI_MAX_HEADER_LEN 65535 #define LSAPI_MAX_DATA_PACKET_LEN 16384 #define LSAPI_RESP_HTTP_HEADER_MAX 32768 #define LSAPI_PACKET_HEADER_LEN 8 struct lsapi_packet_header { char m_versionB0; /* LSAPI protocol version */ char m_versionB1; char m_type; char m_flag; union { int32_t m_iLen; /* include this header */ char m_bytes[4]; }m_packetLen; }; /* LSAPI request header packet 1. struct lsapi_req_header 2. struct lsapi_http_header_index 3. lsapi_header_offset * unknownHeaders 4. org http request header 5. request body if available */ struct lsapi_req_header { struct lsapi_packet_header m_pktHeader; int32_t m_httpHeaderLen; int32_t m_reqBodyLen; int32_t m_scriptFileOff; /* path to the script file. */ int32_t m_scriptNameOff; /* decrypted URI, without pathinfo, */ int32_t m_queryStringOff; /* Query string inside env */ int32_t m_requestMethodOff; int32_t m_cntUnknownHeaders; int32_t m_cntEnv; int32_t m_cntSpecialEnv; } ; struct lsapi_http_header_index { uint16_t m_headerLen[H_TRANSFER_ENCODING+1]; int32_t m_headerOff[H_TRANSFER_ENCODING+1]; } ; struct lsapi_header_offset { int32_t nameOff; int32_t nameLen; int32_t valueOff; int32_t valueLen; } ; struct lsapi_resp_info { int32_t m_cntHeaders; int32_t m_status; }; struct lsapi_resp_header { struct lsapi_packet_header m_pktHeader; struct lsapi_resp_info m_respInfo; }; #if defined (c_plusplus) || defined (__cplusplus) } #endif #endif PKu]ւg/((#ruby-lsapi-5.6/ext/lsapi/lsapilib.onu[ELF>@@=< 02/3.4-5ff.ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=DÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH=1tIH=HcH5HH[ÉD1?H=HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHtHHtHHtH{@Ht1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDHu48u uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=HcB$HH@H,H9rZf.HH9vGH3LuHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L=L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$)H8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L LfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH L$DIH Ic LEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcUff.AWAVAUATUSHXHt$ HT$dH%(H$H1HIH1E1L-HL%HHHcHcT4t/HHAAtIL{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eHthILM)MUI9t HtDL+t$HL[]A\A]A^A_DM@@M)(IHt$HLHk8f.HAVLAUIATIUSHu\H߉AD${LǃLSHu0{L[L]A\A]A^[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIHLc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAMt$PHLIFID$PA:I|$PMD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHAI\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1HL$Aߺu#DHuDo߻D HDeOAkDH}An}NHtff.USHdH%(H$1HHu/HH$dH3%(uHĘ[]@1H=tAUATA'USH'DNuDH@AHHHHtH-ƉljUDk HDcEufH H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0ALJt` A1LHcIHIGAo IuID%D-B(AA1IcH4IILI 9HqH= IJDB(9xHqH= XIJB($AD$IKAzHL$;MbfoLt$ LAoL$AT$Ml$)$ LLHL$LHLLH$ID$H$I3L$H1H D$$Dl$EDDl$H=IHIDMH=t"LDLŃP|$Et$A9uHt$DŃ5$A?D5t AH5LHtHHf)#AH51H@H51LH 1HIH51H51D%DD$H=IHtZEW7E1111H=H51E|$M2;|$E1H5LuI}Ń1H5LKfD=-ED$AIFH51HH)H5H11H5L 1H5LA#LH H1H5Laff.AVAUATUSHdH%(H$1D$ HH ;1Ll$Ld$Lt$ Hkl{ul;LLD$CHHt@HHt{1f|$=u|H4tH舴Hd1H$dH3 %(u}HĠ[]A\A]A^D {H5Hfы{LA;ff.AWAVAUATUSHD=dH%(H$1ExHH-H};DH-Ht 1HEDEH$L|$PDcA:E1AfD EDEtHHt @fLH1HIcDHD$PHD$XA ?)ѺHH D9#11A|$MHD9#HHt @D9#AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$LH$LHHD$@AHLDŽ$hH$H$LHHD$0PH$LHHD$8+H$`L HHD$(H$ LHHD$HADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%EHHt H=1IL9t<1ձL5EDu EME1VHLH1HHc}}LD$LHD$PHD$X ?)ѺH1H T`1 8Ht$(1ҿ x=_5tHHt @f,D9# DCHHt@HHtDc1DN ={H5HHHt*HHB(@HHt@HH@8B-DAD9M==H HtDHHt A9HHtD҉T$$DE ~:E~5T$$AAAuDE UM D9vHAHtDH51D$0 H=T$fD}蠩C1mH|$IH|$HT$Ht$161E Mt AMgMg{E1CHt$1ҿH=f;>fDD$$0d T$$WH=T$T$fDD#AfDRDEBHH29{H5H{wH=H=0MAH… H{HH=Ht$1ҿHL=HHHtH11L=AGHHt{1蝦D-EuHHt!E9~;t Ht$@1ҿL$Ht$01ҿHt$H1ҿHt$81ҿHt$(1ҿ kHLSH$$L$H=%,H=QHHt*fC1CD$CCT$HC(HC fD=ff.@H,LSLSLSLS GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realignAnonymous mmap() failedlocalhost%02d:%02d:%02d [%s] [UID:%d][%d] %.*syesnosystem()%s, errno: %d (%s) /dev/nulllibpthread.sopthread_atforkHTTP_[UID:%d][%d] %s:%s: %s LSAPI: jail() failure./etc/Can't set signalsaccept() failedLSAPI_STDERR_LOGPHP_LSAPI_MAX_REQUESTSLSAPI_MAX_REQSLSAPI_KEEP_LISTENLSAPI_AVOID_FORKLSAPI_ACCEPT_NOTIFYLSAPI_SLOW_REQ_MSECSLSAPI_ALLOW_CORE_DUMPLSAPI_MAX_IDLEPHP_LSAPI_CHILDRENLSAPI_CHILDRENLSAPI_EXTRA_CHILDRENLSAPI_MAX_IDLE_CHILDRENLSAPI_PGRP_MAX_IDLELSAPI_MAX_PROCESS_TIMELSAPI_PPID_NO_CHECKLSAPI_MAX_BUSY_WORKERLSAPI_DUMP_DEBUG_INFOnobodyLSAPI_DEFAULT_UIDLSAPI_DEFAULT_GIDLSAPI_SECRETLSAPI_LVE_ENABLELVE_ENABLEliblve.so.0lve_is_availablelve_instance_initlve_destroylve_enterlve_leavejailLSAPI_PHP_LSAPI_PHPRC=packetLen < 0 packetLen > %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGINFONOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveRangeX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

    Resource Limit Is Reached

    The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
              ^ d/4-//// %-/Ga '9 (_intG )@/G G @ @ G @ G     G  `@ A C $E (J 0NL8PX@[+H\+X]+hj$xp4G- - N1 ooGGXa&& E18: ;1?A B C1GOI JK1 OQ RS TU1ac Ed EC^&e&g1 Y[ E]ah 1l5no 1tfv Ew x@ Cp3&5&<&Db_rtL&VO&i&p&y5G1$ +& ( * 0 { f|HCIRT Cv&"7&$ R  E+v"&T.1 4 c G@4HH//-Gldy"m - 911; CmGFy<d(eGfI@I@IEIE"1 36 |7 |8 |9 | : |(; |0< |8= |@@ |HA |PB |XD `F hHpItJ xM9NNO Q Y [ \ ] ^ E_ `b g+J  G J J  G4'  < ' ' '   T h4I ' T X@!      !!"! ! ! ""F " E" #!X@$  i0%9"# # # 4  G  "&4 &6 &7  < |"0'1 '3 |'4 |'6 '7 '8 |'9 | ': |(jtm8(, ( ( ( (  ( (((( ( ((0|< G'), ') ')'), ') ')H*! B@,H      !"#$%&'()*+,-./0123456789:;<<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'-$|'-2 '-7 '-; .U.m.4/"/*/!B@/) !)./23\^bgl00/{C/&/ &/ -&/ =-G=GMG"/h/ 4M'/h'/h"// ///-GK/,/ ///M/K0050708090: 0; F 0<0= | 0>( ,"n11 1 GkB@2,     C2q&2s9&2t"2k2m 2n 2o 2p 2u",22 2 92 9 2 92 92 92 92 9 2 9$2 9("222 4G9G"22 92 92 92 9 "2G2 92 9"2o2"2"/" / 1 | 2 | 3  4 k : < = ? @ B| C  E|( F|0 G|8 I|@ J|H K|P L!VX O ` P h Q p R x T'\ V'b W'h X'h Y' Z' \'n ]'t _| `| a| b| c| d e f g h iL k'zL m'G(L n'8L oE "0pVr s uhvwxz{ |(vGa=G q' s w9   EM X9    $EM x7=RH H"XOYbufP =Q YinRG-G?]!NB@j~            9     H  H  H  |      l "G * ^GN G t N  t G M>CQ L L @  J l E m  9    9#!  9 9 #! @! !9Z! #!  g!F!9! ! |'  ! m!        # # *"G&%" K "  K@ V#          ( 0 8M " z# V# @      #  -     H! x$2cnt!U$2pid'U  : YO%2buf'#!U#in>74r"4TsUs]4U T 4UsT  [5m4UsT 5UsT ,5UsT Q5UsT v5UsT 5U ʳY5U YU ;W6%;O";#;Y2x6k%2w~}׳6U2T~QwY7U 9Y,7U YK7U Yj7U Y7U Y7U ;Y7U Y7U <ytY,8U YK8U G<Yw8U ;Y8U ;Y8U <Y8U Q;Y'9U YF9U ^9Us<Y9U Y9U Q;{X9TvQ | $0.MX] ":!p], _ ":3:=GE `: E- G % :!p%) %2| %= ' :len( end) |:=G ;i pw!)p7 2;env ! )del! D TD ( ;*$U(;**U(<*'U(G<*&U(v<*$U(<*"U( <*U( =   H  -5+fd ret    ~ Et;=   5 >__d U| $ &585> 8! O EOOOOw PyPz%P{2P|?P~LPYPfPsPPPPtPtPuPvNPP p?P>QT?Q?U  y @y!y 9C@7@Ä*UvT|Q@T7@U}C AUAT|Qt7"AU}CGAU?T|QtClAU2T|QtCAU:T|QtCAU3T|Qt3AU OAU0KQ BU|[%BUV3KBT}Q0R0XtC|BU:TtQ0BU T BU [WVBUu7BUthCUtTAtDCU0TtQtLtCU2TtQCU  CU CU  DU 8DU tiDU2TtQ03DU0T0Q DT0LCDUATtQ0CEU?TtQ0C8EU3TtQ0C\EU2TtQ0CEU:TtQ0EU QU  ?yj"FQy-?y+Qy+y #/ y+y #  yy*T Q8ly 9G~y+y yy*T Q8zqQGUsOhGU03GU|TvQ0R0X[WGU|GU|T0Q HU LGHUs?Ãsx_HUsHUs?ÃsqpHUsOHU0M M M .5+ O 4 P 4Q }R E} S retT  V z#EactX ~;I   5I__d ;1J  #JU T7VJU|CJUATvQ 7JU|CJU?TvQ CJU2TvQ CKU:TvQ C@KU3TvQ 3[KU OrKU0KQKU}[KUV3KT|Q0R0XC LUAT Q0C2LU?T Q0C[LU3T Q0CLU2T Q0CLU:T Q0LU T LU [W )MU HMU gMU VMUu> @N > +5+5N C 4OU0L pO  *5+  y6 GOy!y@ 7NÄ 9O*UsTwQ@3OU0T0Q OT0LQ: Q : @z# ; 95+act=  =  = % = / >  >  ?  @ retA pidB  C 4 D 4 E  F E H  I FP   FQ__d )  D/ 1T+ : 6R  ,        %RU T   F lY  *  5 =X~ret pfd YSYUUTsZqYUsTv88 Z 8 ' 8 @ : Zp; | < |res=  = , > ? ZG -[  6[  Gret fd  D  ZT1Q0ZUsT2Q1[UsT1Q2RDX4?[UsTvQ} ][UsT|L,[Uv 8 [  /5+  B!len LF[ch )   ^  05+  C  ,   len ;\ch ;\ch 57]  U|  x]TTQ~  ]T}Qv]UvU} t^* 25+U- Ä F^  05+#fn !#arg ,E@p_QTRQt Fp_ t )5+#fnu !#argu ,E@p_QTRQ6a s` a 6h#nb #fnb (#argb 3E d #hrete qX} b  ,5+#fn !#arg ,Ei len! " |ret# $ ;Zb7 Z}p8 | 9 | : | ;  < &t < -t5(achK % O Fa__cO 9 ̋F 1b݋r}U~T}#X|3bUv3$|"T v2$}"X|$_d /5+#fn!#arg,Ei len  |ret  _d~5c |  &t -tEdUwQ R E=dUwT| $ &Q R 3QdXvA"pd=G d2v1'U2v27T|'f (5+ ; #h #h['ff$Ff$9fSf^fNkfelfwfffffUffUff9RU|Ts3$"RU|q|f q-5+ q@is t |)p | |  &t -t)ch) )__c8< -g </5+ <B!len<O >  ?p@ A - B -retC iovDg E  gGh $5+ret n .ph6$)CP]qTshhUshUs?Ãs^(iNi*'5+U "\  -Ä -j +5+ 5#offBj N "\ jÄg5jUs*RjT~Q8Z^yjTTQQRR^8 - k (5+ ;!lenH "\  p! " - # - $ - %  - l .5+ ;| Hlen -    l$UvQ|-o ʊlۊ@U~TvQsln -5+ :| G THlen -  -  |  |  |p |  >n#nTQsTQsmo no% ooU~jUT:Qs]mo -5++moo%ooUs o .5+  len -|Sp*+5+U 5off yJqp y&5+(nYp n%5+-`t}$qKzq K*5+h-qUsgEqUseqUs?Ãs^Us-r -%5+hqUsgqUsqpqUs^Ft %5+=X~ElenF ~~ ?yPsQy-?y+Qy+y / y+y   yy*T Q8zqhsUssT0sT|Q}sT0xsUssUv?ÃsqptUs8tT6Q1R~X4 yt*(5+Ut@FtU %w (5+#fd2  `Tu}$q  uvT Y' >vk%'w~~׳/vUvT~Q~ HveY'U T2ʳvU vUsT vUvT1wU0wT0( Sw2cb;*UD Tx EۄwU=T ۄxU:T ;xUIT1WxU2T1t{xU T0xU T1T A y A%5+lenC D 4/y!fd4) 6 /y?yG+^y!fd+,s y!fd5 y!fd 7y!fd.!pktN\ *z *5+ 4   |  | Wz 65+ D z D.5+uidF gidG H I J#h K#hiL 1 >{ 1.5+ 2|!len2 2+| 26 4 5>{-N{G { '5+!uid3L!gid>@ Prv pw! { 6 | +5+#uid7L#pwL!ret  Tw3o|UQTs|U T Q|Xs}|UvT Q0 $} ,5+!uid8L) ret  r} -5+r} } }G}=G#4}6{  {,5+ {? {R} ":_n~ i~ ~$zUvT Q1R X rf~U|Tv*~U2DrJ [ J%stLSfdM ) zrc+   )uid  -5+  i ) &t -t7 O 35+i F2bp|) &t -t7v /5+pb7 )Hp |b6t Y t4h tB*u! Q u#| w#h x xh!fdh j=XlenkF R ف R<ف SH S+ U#hh> >>\ >L)bF62 G 235+ 2=p4 |vTv$ Ă $+5+!n$5p&  05+ :  | i!fd 2i < Gret  n  -!fd' 2E!len?ret -7 у 35+ !fdret 6 U#fd# +val UsT3Q0@UUT47wф wJ\ x&!lenx0tR :A  A A2EsaC~CWUvT0Qs7oUsCUvTsQ0:8 υ2sig8!U:3 2sig3 Uu (7   .mUs@U T QURTvvwxfmt'PVbuf Tvyp |z Eap  u5VtvEuVtm u{iևzU|T Q1R X \i/XzU|T Q1R X õuUsT0ϵUsTu +۵T1Q}Ru\i-zUsTdQ1R X Yv3$" izUsTdQ1R X  > [[OT1Q X|rW  :5+ D.|ʊ|."-" "E"%.k|6kkk.\|`\\.>E>E>>.'E̋'E''.EG.8 18.did d<P.A]__sA]__nAAP.%|Ռ%%|sz' 8n n8i i8 B  BS.)s))PW11W"m"m,moooo-o ʊۊ@U~TvQ|,aq$ÃSу G$% L8Us+ $Ã, )6CP]UvQ|,Ot  OfT0,YYYYY}YYY}Y}YYG g)U|TsQ N ʑ)UvT|Ql  UsT0Q: ` T}q ̋ ݋ Uv 6\ SG) U|T:51U|T )OU}T]AzU}T0Q}R}NU|[U},UUUUQUQVV[UC ה$UUUUVVNVV+VU T|QgU TvQ3VUu,flEfggg,g9gDgQg^gkgxgf< ggf%g,g9gDgQg^gkgxg e6)CP]qTwQ2R} Z ÄgU~U~?Ã~*7U2T~,9= ::п `:b :}:r::_:: , 2sUwT 9 %ɌUsT|Q јTvQ0 3:g 6E:R:HGeY'UsT AQ UsڙUvT2LUvU2T1}U0T Qs9 ]  :% :}U0T QU,jjjjjjjjjkQk j jjjjjjjjkk S $Ä? cUTQvg{UsgUs^,[[[[}[ [$[$[>[,[>[3g[U|- TvQs,Y8YYYYYYYQYY@tUUTT,{X!#XXX-{X XXX՞U@T1[UU,x xxx oO/ʊ  ۊ@UsTvQ| xA hxxx߁1V۠O  o@iš%8ʊۊ@U}T|Qv yn yyzz~zA %Aˁ+5R %5ˁvT v $ &33$A %Aˁ+5R %5ˁvT v $ &33$  wODO X]%j v v[ v v v6 v vȦ v-vS K$% >#)&+v %O23@ v  v ڨ$ v $-v $*z1 ԩ"?o363A* @ 'n* A * A B1B( 1 : ; 9 I8 41B11 4: ;9 I 1RBUX YW  : ;9 IB 4: ;9 IB : ;9 I I: ; 9 I4: ;9 I1RBX YW .?<n: ; 9 4: ;9 I4: ;9 IBI41 U.: ;9 'I : ; 9 I!I/ .?: ;9 'I@B4: ; 9 I41 : ;9 I8 .?<n: ;9 I!: ;9 I" : ; 9 #: ;9 IB$1% & : ; 9 I'4: ; 9 I?<(.?: ;9 '@B) *: ;9 I+1RBX YW ,.1@B-1RBUX YW ..?: ; 9 'I 4/$ > 0(1 : ; 9 2: ;9 I34&I5 6.: ;9 'I@B7.: ;9 ' 8.?: ;9 'I 9'I:.: ;9 '@B; U<7I=!I/> 1?1B@B1A.?<n: ; B> I: ; 9 C : ; 9 D.?: ;9 'I@BE4: ;9 IF G5IH4: ;9 I?<I : ; I8 J<K : ;9 L : ; 9 I8M: ;9 IN 1UO 1PQ41 R'S1X YW T.?: ;9 '@BU 1UV4: ; 9 IW.: ; 9 'I X> I: ; 9 Y : ; 9 I8 ZB1[1UX YW \1RBX Y W ]: ; 9 I^% _$ > ` a : ; 9 b : ; 9 Ic'd&eIf : ; g: ; 9 h!i(j : ; 9 k : ; 9 l4G: ; 9 m'InB1o.?: ;9 'I@Bp4: ;9 I qrBs.: ;9 'I t.: ;9 ' u.: ;9 I v.?: ; 9 '@Bw: ; 9 IBx: ; 9 IBy4: ; 9 IBz4: ; 9 IB{1RBUX Y W |4: ; 9 I}1UX YW ~.?<n.?<n: ;9 6ddqd T)TuPPP(PPsPPKP[P"R+RRJQ^Q5Q5<v <Q{ PTt _X ~XX[TiT2TAXX[P[aQxT4T@PP{P{t XRr t;# $  %!r"p;# $  %!r"u?[gRSRbRHRQRR {RTKTiQX%vXvzr TiTTQq Ru .Q2QHQ+Q4QQoQQ;QQXP iR~Rv FRFW{ _Rz QK$KU$KKVKKUKIKTIKKSKK|hKKTK.KP.KPKQpKuKQuK}K?p K$KQ$KLKUpK}KU3KFK q 3KFK03KFKUQKpK8QKpK0QKpK\pKyK 7p yK}KQpK~K0pK}KUKK@KKUKKSKKVKKXKK0KKSKK|hJlJUlJJ]JJUJJ]JJUJJUJ0JT0JJSJJTJJTJJSJJTJJs@JJSJJSJJQJJ^JJQJJQJJ^JJ^7JTJPWJZJp?ZJaJPaJtJ\tJJPJJ_lJJUJJ | v"|JJ_|JJSJJTJJT|JJUJJ | v"JJ@JJSJJTJJs@JJ}JJ ~ JJQJJ\JJu`IIUII\IIUII\`IITIIT`IIQIIVIIvxIIVIIV`IIRII^IIRII^`IIXII]IIXII]dIITdIIUP@c@Uc@CVCrDUrDEVE.EU.EeEVeElFUlF;GV;GTIU@@P@@P@@P@APA0AS0ACAPVAiAP}AAPAAPAAPABP$B7BPKB^BPrBBPBBPBBPrDDSDDPDEPEEPEESlFFPDDsp"1DDP@@P@@PjApAPAAPAA0AAPBBPDDPDD0.E4EP:EQEP~@A0A!AP$AC\rDDPDD\DD0DD\DE0EE\lFF\FF0FH\H@I\EITI\@@P@@PAAPAAS5ACAP[AiAPAAPAAPBBP)B7BPPB^BPwBBPBBPBBPFGP"G,GP'CQCPE#EP HQHPFFPG!GP;GPGPPGTGUTGGVHHVHHQHHVI;IVEITIVFFPG!GPDGPGPPGTGUTGGVHHVHHQHHVI;IVEITIVWGpGPpGGSHHSI%IS%I6IP6I@ISEITISDGWG0DGPGPPGTGUTGWGV`GeG}eGpGQpGqG}`GpGPpGqGSGG@GG GGS]CtCP{C}C0G HP H HPfCtCPHHPHIS]>,?0,?C?]p;u<0<<P<=]=>]>,?0,?C?]p;u<0u<`=}=>}>>T>>}>,?0,?,?},?C?0p;u<0u<@=V@=V=PV==V==P=>V>>V>,?0,?0?V>?C?0p;`=S=:?S<< s $ &<<U=>0Z>c>0c>{>^{>>~>>~~>>~: ;U ;/;S/;0;U;;P99U9:S::U::S::U9S:\::S::@::6::W::4:: ::H4U4U U $$6U404^^ $^$6040000T9r0? $0404_\_\mm_ $_$60404K\KV\V\ $V$60SS 6S]] 6]USUSUST.V.T  wS  P ' S' W v(d r Pr x S     p`# p`# <$ c ~`# <$d x ~`# <$ vv" P c ^d x ^  \  0  P  S89P8:9QP+ PQQ + Q # 0 # 0 # P  U s U ) P) > S> k Pk n Sn r Pr s S 7L7UL77U 7H7TH7w7Vw7x7Tx77VM7Z7Px77P55U56V6?6U?66V66U66V66U56T6?6T?6F6TF66\66T66T66\66T66P66P66\T6g6Pg66S66UF66]66n2(3U(34\44U223T23(4V(404T044T223Q234]44Q63Y3PY3c3pc3t3Pt3~3^33p33P33S34P4,4,4h4L3p3Qp3~3R33Q33R3 4T 4 4tp 44T414^4(4V(404T0414T404|I4R4QR4S4VI4R4TR4S4]I4R4|_(l(Pl(v(u_(v(3_(l(ul(v(P''U''U''U''T''Q''T''T''Q''R''Q''QP''U''U''UP''T''Q''T''TP''Q''R''Q''Q0`U`SSU0`T`^TT0`Q`VQVQQ0`R`]R]RRD\~1$~"3$U"T $ &33$U"\~1$~"3$U"T $ &33$U"\`iP{P0%%U%&S&&}&+'U+'9'}9'@'U@'E'U0%%T%&_&9'}9'@'T@'E'}0%%Q%9'|9'@'Q@'E'|%%V%%vb%%0%%p 9'@'0%%Q&&Q%%P&&Pb%%0%%^%%~%&^&'}+'9'}9'@'0c&u&}u&&]&&}&&}&&]+'9'}K&&_+'9'_c&&S+'9'SK&X&V_&u&Vu&&}&&t&&T&&}#+'9'V%'\+'9'\&&P&'}+'9'}&&V&&v8$8&2$p"&& v8$8&2$p"c&c&5c&c& c&c&^#|$U|$$U$$U$ %U %%U%$%U#w#Tw#$S$$T$%S%%T%$%T#w#Qw#$V$$Q$%V% %Q %%V%%Q%$%Q##P##p$$0$$0$$^$%^<#w#0##r ##t %%0##Q$$q$!$qpI$Y$RY$m$q %%qp$$P$$P$%P<#w#0w##\##|#,$\,$_$|_$$\$%\ %%\%%0$!$T3$m$T %%T%%q`$!$X>$B$RB$$X %%X#$P %%P#$Y %%Y !U!7!S7!p!wp!{!{!!U!!S!*"w*""U""w !T uF!q!S!!S!!s""S""P""P{!!|I"o"|o""P{!!VD""V""v""V{!!_I""_{!!}D"d"}{!!]""]{!!^""^o""q2$u"""q2$u"o""v8$8&2$u"""v8$8&2$u"""v8$8&2$u"((U(=)S=)>)U>)Q)UQ)b)Sb))U()0) )P!)&) &)<)P>))0(( uu@()Q>)Q) uu@b)|) uu@()P( )s ))T))s()s()Pt u T p p# p`# tp# Q P 4 T2D2UD22S22~~22U22S22~~22U22U2D2TD22V22T22T22T22V22T22T2D2QD22]22Q22Q22Q22]22Q22Q2D2RD22\22R22R22R22\22R22R2)2u)22^22U#22^22U#22uU2Z2|Z2u2PU2u24U2u2^`U< ]< H UH b ]b k U`T< VH b V`Q5 SH [ S[ ^ sp^ b SP}q $ &}} $ &P\H b PP0< \H b \P\V 0 SH H S 0 VH H V 0 ^H H ^ PH b P  S  V  ^ZUZ^UH^H\UQTQ]TH]H\TZQZHQH\QZRZ\RH\H\RlSHS?ZSZ_H_HRSP\QTQZ]ZVUVVUHVH\TT__PPSS__UVU(4^(3 p $ &37 s $ &USUSUUSss $ &0yTyTMYQYn t2$x"#4nyRU)S)*UUPU0//U/0S0 0U 0#0S#0)0U./U/[/S[/\/U\/a/Ua/o/So/u/UWWUWXSXXUXYSYYUYPYSPYUYUY#YsY#YsY#YsY0Y Y#Ys U S"U"rSrU'T'V"]V]_P_rVrTdlP3  303}@3}S?LPL}\V]d2]d 3JP,2,U2,h,Vh,k,Uk,,V,<,T<,j,\j,k,Tk,,\,G,QG,,Q-,H,0H,L,Pk,,P,,R+:+U:++\++U++\+:+T:++^++T++^+:+Q:+V+SV++Q++P++p $  $-(q++ q++  U uh U T T q Rq w Rw y Ry R q Zw Z 0  [  p * X- q [q 0 0 T t  u|#- 4 T4 7 pD W T^ b tb q u|#q 00 C UC n Sn p Up w S0 G TG o Vo w TH _ P_ i sp u P U S U S U U S T V T V T V P P P0_U_VUV07T7\T\@JUJrVrvQvwU@UTUcScvRvwT@UV}U}V.U.VU@T|]|}T}.].5T5]v\S} S R.:v:\S\S P}Pv  \c c c\SWRWXuSWQWX]SWs} }d}S dUS.  (s U  S  U  S $ U$ * U Q$ * Q P ) P) * u t $ & P  \  \ T  V  V  ^  ^ P ] $ P \ V ^G P P U V U VU T _ T _T Q \ Q \Q R ^ R z^zRR P S %P%XSXdPdS R ] ]R U SS(S T VT9V 4}4]}*\kPS(P(QS*S04^0QTPThSsS'<'<S',},<\l\UvFQSs0s0s}Q | Q|V\dUdU}P_U_/0/LPLn__UdSPnSSPSdnPPQQRX))U)*^**U**U**U**U))T)*~**T**~**T**~))Q))w)*Q**Q**Q**Q**Q))Q))w)*Q))T)*~))U)*^**S)*~*`*_`*v*v**_&*f*Qf****}x**Qj**]**P{**P**]{**2{**w{**~{**P**]{**2D*T*qT*j*PD*j*6D*j*\,-U--V-T.UT..V..Q..U..U..V..U..V..U,- T.q. .. .. .. ,-W--ST.q.S..S..S..S,-U-{-V{--ST.q.S..U..V..S..V,V-0V-h-U..0r--P..P- - - -W{--_--\{--S{-- -.S*.T.S..S--P--V*.;.P;.T.V..P..V-- A--Sq..V..Q..U000U01S11U11S11U11S000T0111T1111T1111T11000Q00V01Q11Q11V11Q11V00V01Q11Q11V01111101S11S11S00]0 1T 11x1b1Tn11T11T01V11V000F1^F1R1rpR11^11^0-1_-151x511_11_0b1Yq11Y11Y11Y00R11R11 @00400T11V1111_45U5%5U%5/5U/55\55U55\55U45T5%5T%5F5TF55V55T55V55T45Q5%5Q%5P5QP55Q55Q55S55s55}%55S55}55S55P55st"%575P75F5st"1F5f5vs"1K5`5T`5b5tpb5f5Tq55Sq55Vq55|7 7U 77U77U7 7T 77T77T77U78U88U88U77T78V88T88V88T88V77Q78]88Q88]88Q88]77Q78]88Q88]88]77T78V88T88V88V77U7^8\88\K LU LWL_WLLULP_P$PU$POW_OWTWUTWW_LLP,LWL\LL\,LWLVLLV,LWLSLLS=LGLPLLP,L=L\,L=LV,L=LSLP_OPOW_TWW_qMMPLPSOPDUS\UOWSTWWSLL1LLPLLQ8MqMV8MqM\.MqM]NMXMPqMMP8MNMV8MNM\8MNM]MPSOP,RS\UUSV0VSW/WSMP_OP,R_\UU_V0V_W/W_MM p1OPQ p1MP\OP,R\\UU\V0V\W/W\MNVMNMNMNVMNMNMNPNONVNONNON!NONV!NON!NON8NONPyOO_RiR_RDU_\UV_5VV_4WOW_TWW_yOO#R,R#\UhU#yO{O0{OOPOOpOOPOOROPQ_OPQPOPkPpOPQpSPkPQkPyPp kPQp oPyPQyPPpyPQp}PPQPPpPPpPQp PPpPPpPQp PPpPPpPQpPPQPPpPPp PQp PPp!PPp$PQp$ PPp%PPp(PQp(PPQPPp)QEQPEQIQp"Q'Qp1$q""Q.Qp1$q"3QEQQ3QEQQ6QEQRiQQPQQppQRPpQRQQQPQQppQQPQRppQQRQQRQQRQQR\UU_iUUPvRRVvRR_RRPRU_UV_5VV_4WOW_TWW_RDS\DSGSPGSSwST\UU\UU0UU\RKS]KSSPSS~ST]UU]TUPRU0UV05VV04WOW0TWW0R SZ SSzhUUzhUU0 SSZUUZRRpRSXUUX_SS__SSz|_SSRSS~_SSz_SSzSS\SS}pSS@SS SS]TT0UV05VV0VV04WJW0TWW0WW0T T~UUP8VXV\VVVTT_UV_5VV_VV_4WJW_TWW_WW_^TpTPyTTPTTPTTPUUPUVVAVXVPiVVPVVPVVPVVVVVP4WIWPWWPWWVT2TP2TT]UUP5V@VP@VXV]XVzV0VV]VV]VVPTWW] TT_UU_XVzV_VV_TWW_ T3T 3T;TPTWgWPhWW_UUHUU0UU U4UU4UU4UUDU U4UPJP P$PU$PJP_.PJPP,d       9>ACFQxx| *)SX 05:@nOh"'3"'3TY}O[]dRV] 0 P P  0 P P {!!!"""{!!""`"h"p""""`"h"""%'0'9'.&5&B&G&c&c&_(e(l(v(((() )))* **`*f*{**D*D*I*Q*;+>+c+n+q++,,,-X.x.....,,- --.0.X...0111110000U2U2`2j2D3c3k3~333334%4,41464<4I4S455+5555q5w5{55777 8 888888s:}:::s:}:::::::::O<T<<<<<=>`>>@@@@BQC E0EFH HXHHHI;IEITIFGHHI;IEITIDGGHHI;IEITIQCChEpFH HXHHHIhEEXHHHIEpFHHdIdIxII_JJJJ|J|JJJJJJJJJJJJJJJpKpKuKwKyK~KKKKKKKKK,LWLLL0LWLLLWL\LL POPiSiSUUUUOWTWWMPOP,R\UUV5VW4WyOyOOOOP\PaPdPhPkP\PaPdPhPkPrPvPyPrPvPyPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQQQQQQQQQQQQQQQQQQQQQQQRiSiSUUV5VV4W@WEWOWTW`WcWWUSeSiSiSiSSSSUS_S_SeSiSiSiSSSSiSqSSSSSTTUV8VV4W@WEWOWTW`WcWWTTTTUUUV8VV4W@WEWOWTW`WcWW T;TUUTW`WcWW T;TTW`WcWWUUUUUDUYYYYY0YYYZ ZUZaZZZ@[]^_`_`8`` aHaaa0bstruct_FILE.hFILE.hstdio.hsys_errlist.hresource.hstruct_iovec.hsocket.hsocket_type.hsockaddr.htime.hpwd.hstruct_tm.htime.hunistd.hctype.hconfname.hgetopt_core.hstdint-uintn.hin.hnetdb.hun.hlsapidef.hstring.hresource.hdlfcn.hsocket.herrno.hselect2.hsched.hmman.hsendfile.huio.hstrings.hinet.hwait.hprctl.hgrp.h KK.K5J/I#KK1 0 z zJ Z " OJJ = ...v <K gfJ.T2KxJ.n=@<YDw<<=:/;<;/u;=IK=H</փ-K-=>:X-=;=0:/;=I<//sf=H</[G-K-=18=;=0:X;=-/I=;/?Gf-K-=I<-=;=-/e=-/t0//-</-</-</-<///-<///-J=t=Y-</ȑ-</J>Xtu-=ttu;/K-=-/X-/t;/gK-=Y-=;=J;=/K-=-/X;/u-=ttu-=K;</f;=;/fu-=t.V>,>t;=/.K-=-/t-=-//-/-X.I</t.W=-/0,0,<.W=-/t/t;=;/H ># K# = l Z< < h u$I$K="IY<IJ =$J$<=;"<J = vXF.L L = /d f.L u /O7@p$tik<=<>V L a$f mX Xm< .>m<X N1+ pk " kJJ k.XX"~K k  [ X O(kX  < kX  b>= E<>:<Y<; = vk<q R< !l   l<lz/ f X< Kffkv ~*~ X$ rJ~ # .?f h ~~<  .<1 ~) < ~t)X ~<= jtt        Z-JJXft X L!s gf  fF J Y Y :"foXXXJlt0 hd/ L. XN6g J yi< X$   Z  4tKK  ;:|". < Z IY6t(f+K"JMX"X< mJ< & AJX0J XXXV$J)I!4f<9X!Jh  .$r.XX`KJ Jt5<uY"J q<% 3$x.`XYBW[$g   F x \ *2. F^ \t;:j KK-uYIX Ki+JJK2KKu\/ u  u  (tX |  x(9?JL6J9xX<u1tu6,XJK,@g L,K /sJK u XQy  X KEW \ g x. < %  /s u Z ptt  /t.X  o tK !f J/ kt Zs gY  Z Y g Y  #!xwJKxJK K!JK sJ  s< ! KJ9J!JK!s  f K =J YYt YYt YYJ YY<xK t<YL ,<W ue [A<v v .KXe#!CJ;Cg K E dX ` x DNK$ JG MY<," g <    =  &> t u X   Y r< f Kr  < r rJ huJL |   fX.X  ]u u<   Z = = y<kJK,&J"Irt &s=r< !rff  "yJD!IK L%; K%H K KKK.7 .XB#I1u#J Q  F Z  KNJ U  X  hJ.$ .Xhr / X L*~Jf-S. LKI u YZ .HJ K Y)%fX80JJ )X%<XX$%4HJL<0YBL=;B=Vv<)/Mt z0<6u  zt/  L4K"vI4H =" @"F %#K%W Yz Q*uJf  uJ K mJJ .I  <vJ uMF =0J u) Y%#K,K"9 =& =X YsJY FX:JJ Z L N*<xX<JX>tJ e < 7/t  L4K xH4 = K *vJfJ  uJ  Y.W mJt mX K t Km \x JYKWiX<JJz NS =;0WX Y)? K  LeJf<Ki*_8tK )^ ~tf<_K z.` ztf< XKJZfv*=gJ Z AK=%, =%H KM, tY,Lho!(fot(= -K l X|K<x < o.K Ms f sf tJt    Z 93JJM _< . jy 93JJ Kw ' K"f/ s XM X X mXL  f   yr rX' =P Yr J:h6t YGu  uf>= . f  K  ^tj  !tJ<   jF % =%H K  Z7)K LK)8 K! K 2%o = K%: K2 GK  _X#< ]< <& Y ZX [f<Ȃ _Xy q   KK&,N>:hZs"  [sf  "Ui Xi g Y .. - sX ... K fh00< =  h+< Y  u<   Y Jz   . L+< g  /.  L g J JK*X.X v6= Y; u/ Xl f? lJXY lf"Kl "K8G8=P.4XK%      J.Jp<J*<X v6= Y;. / Xl f lJXY"=8G8= I/..c<<jBz<  sX&`" f [Z M   L  Y 0 U= =Y K ^f 4I gYK$/ fY L y^ /K-%]  K+/X>0XX<uj Yv Xg Y IgZ$Hv&L<X(.= /.u.Z .fJOwX(WuO=.ft"<*w  <K t Y /?N&tuKK  h g G] t Y t YtM   t  Y IgYJvYY g r Y >v t YK, <Y ._ho<x }KYWJtbXK X 9    ft "u ; <u WY rXu WY X"0", XX LXJ<f?JfjK t Y*=K t ,=K t 0=K t .=K t Y,=KgjKK 2K zt/ Y Z  c    Zc  cf  Zc <<   a,<  Zci  Zc x    Zc w X     c       Yc  v    Yc  v    Zc  w    Yc  v  Z [    Zc   g     Yb  f }r       g {  g1J }  <1-u-).K.X UJ.< Z .)J KIK XxK +zz< O=>;g< 0:>< Y6 2 _< < Z    \_<   _X<   _ @ /        J       f :v ZYw Yu    Zv  .X t   tXI/ /    u ~ft  Zr> Z J  z  X/X < zX   tX /  `ggWK>X u ~X~ }XYX |X |<Y ^  X ./ XR XUJ Y   h.eX> tYvtYK   M U -/](tq $~Zv <Qyt/Z t   t Z*(t N   bX J| < y  !#J Y  Z+KZ)=1K- M< <Y v.u. }Jt ZY< gJ f"<  /  np < }2NX)     ~ |X}Y"Xg![qg!p'Y>tYK&CXK%.ZY&i fYp<x u   Zv X w ~9}5Xl t.Z7j.+"<g7/W5K/I Mu_Kg\K _SC_THREAD_SPORADIC_SERVERpthread_atfork_functotalLSAPI_Set_Max_Process_Timelsapi_parent_dead__fxstatparseContentLenFromHeaderugidLen_SC_2_SW_DEVm_pScriptFileLSAPI_Stopsi_addr_lsb_unused2_SC_TIMERSm_iReqCounter_fileno_SC_SHELL_SC_MEMORY_PROTECTION_SC_SCHAR_MAX__pathtm_secH_AUTHORIZATION_SC_THREAD_SAFE_FUNCTIONS_SC_UCHAR_MAXmax_lenfreeaddrinfogid_tverifyHeader_SC_C_LANG_SUPPORTm_pIovecEndstrcpy__uint8_tIPPROTO_TPpw_uidwaitpidHTTP_HEADER_LEN_SC_TTY_NAME_MAX_SC_PASS_MAXLSAPI_ErrResponse_rsi_uidm_bytes_SC_2_PBS_TRACKfp_lve_destroym_pHeader_IO_buf_end__RLIM_NLIMITS_SC_SELECT_shortbufrlimitsockaddr_insa_family_tSOCK_DCCP_SC_BC_STRING_MAX_ISpunctis_enough_free_meminet_addr_SC_TRACE_INHERITinit_lve_exnewSizem_tmStartliblvesetgroups_SC_SEMAPHORES_SC_EQUIV_CLASS_MAXread__environ_sigpollsa_datauint16_t__builtin_memmoveai_protocol_valuem_pChildrenStatusCurIPPROTO_UDPoverflow_arg_areatime_tsin_zero_SC_DEVICE_SPECIFICin_port_t_flagsachMD5_SC_THREAD_THREADS_MAXerror_msg_SC_LEVEL3_CACHE_SIZE_SC_TRACEreg_save_areacalloc_archm_respPktHeaderg_running__off_t_addr_bndlsapi_cleanupachHeaderNamest_size_SC_THREAD_PROCESS_SHAREDallocateBuf_SC_JOB_CONTROLgetppidtm_isdstswapIntEndianlsapi_check_child_statussignal_locks_max_idle_secslsapi_set_nblockenvirons_schedule_notifysetUID_LVE_SC_NL_NMAX__RLIMIT_NPROCRLIMIT_DATApServeratoluint32_tinitgroups_SC_POLLm_pHttpHeader_SC_V6_ILP32_OFF32_SC_TRACE_SYS_MAXm_pScriptName__builtin_va_listst_blksizeRLIMIT_NOFILEm_pEnvList_SC_BASE_sigchldLSAPI_Set_Max_Idle_Childrenint32_t_SC_LONG_BITfixEndianLSAPI_GetEnv_r_upper__fmtsa_familym_specialEnvListSizepw_passwd_SC_CLOCK_SELECTIONmasklsapi_resp_infosigaction__RLIMIT_RTTIME_SC_V7_LPBIG_OFFBIGbodyLeftfcntllastTime_SC_AIO_LISTIO_MAXLSAPI_Init_Prefork_ServerpErr1pErr2st_gidm_cntHeaderss_notify_scheduledm_envListSizeacceptinggettimeofdaypBufai_addrm_iAvoidForks_secret_timerlsapi_MD5Context__syscall_slong_t__builtin_memset_SC_FILE_SYSTEMsa_restorerm_pChildrenStatusEnd_IO_write_endtype_SC_SCHAR_MIN_SC_LINE_MAXLSAPI_SetRespStatus_rlsapi_MD5_CTX__resst_nlinks_addr_SC_TZNAME_MAX__va_list_tag_syscallst_ctimnameLen__builtin___snprintf_chkLSAPI_Postfork_Child_SC_2_VERSIONfree_SC_2_PBS_CHECKPOINTIPPROTO_MPLS__sigset_tm_requestMethodOffm_tmWaitBeginreadSecretreadReq__tznameatoig_initedgetaddrinfovalLens_acklsapi_jailLVE__d0_SC_LEVEL4_CACHE_ASSOClsapi_MD5Final_SC_NL_LANGMAXdoAddrInfo__stack_chk_failmemcpy_killcurSizeRLIMIT_STACKIPPROTO_IPIPdlopenbacklogsin_family_SC_LEVEL1_ICACHE_ASSOCpIovrlim_maxm_iKillSentm_fdListen_SC_AIO_PRIO_DELTA_MAXvalidateHeadersst_atimm_statusm_reqBodyLensig_numoptargSOCK_RAWsnprintfold_int_SC_2_C_BINDs_enable_lve__clock_tparseRequestIPPROTO_RAWstrdupbufLen_SC_PRIORITY_SCHEDULING_SC_SS_REPL_MAXsys_errlistsival_ptrpStderrLogsetpgid__uid_tdaylightsi_stimeoptoptLSAPI_ReqBodyGetChar_rpKeysun_family__uint16_t_SC_FSYNCsin_portgetpeernameLSAPI_is_suEXEC_DaemonLSAPI_Is_Listen_rLSAPI_End_Response_r_SC_FILE_ATTRIBUTESsetreuidserverAddr_SC_NZEROm_pQueryString__gnuc_va_list_SC_2_C_DEV_chainpContentLen_call_addrEnvForeachnewfdm_iServerMaxIdleSOCK_NONBLOCKusleepSOCK_RDM_SC_SYMLOOP_MAXsockaddr_un_ISblankunsigned charIPPROTO_MAX_SC_MQ_OPEN_MAXSOCK_DGRAMm_tmReqBegin__fd_mask__blkcnt_tlsapi_enterLVE__builtin_calloc_IO_lock_tLSAPI_Is_ListenIPPROTO_COMPLSAPI_key_value_pairlsapi_check_pathLSAPI_ForeachHeader_rpHeaderName/builddir/build/BUILD/opt/alt/ruby27/share/gems/gems/ruby-lsapi-5.6/ext/lsapi_SC_SEM_NSEMS_MAX_SC_USHRT_MAXLSAPI_FinalizeRespHeaders_r__read_alias__fdelt_chkshouldFixEndianpBody_SC_STREAM_MAX_SC_ASYNCHRONOUS_IOserverMaxIdle__open_alias_SC_READER_WRITER_LOCKS_SC_CPUTIME__getcwd_alias_SC_2_PBS_LOCATE_SC_DEVICE_IOsa_flagspVecgeteuid_SC_SIGNALS__ctype_b_loc_SC_V7_ILP32_OFFBIGstatusoff_tchild_statuss_notified_pids_max_reqsH_X_FORWARDED_FORs_pid_dump_debug_info_ISalpha__fprintf_chktm_zone__mode_tm_queryStringOff_SC_V7_LP64_OFF64_SC_NPROCESSORS_CONF__RLIMIT_SIGPENDINGfdInlsapi_changeUGidtv_usec_SC_XOPEN_XCU_VERSIONold_childold_termLSAPI_sendfile_rlsapi_lve_erroraccept_SC_MEMLOCKallocateRespHeaderBuf_ISprintsched_yieldpMessages_liblvepValueH_CONTENT_LENGTHm_tmLastCheckPoint__vfprintf_chk_ISalnum_SC_SEM_VALUE_MAXs_req_processedstrtollopen_SC_XOPEN_XPG2_SC_XOPEN_XPG3_SC_XOPEN_XPG4LSAPI_STATE_CONNECTED_IO_write_ptr_SC_REALTIME_SIGNALSsystemlsapi_packet_headerIPPROTO_ENCAP_ISspacelsapi_suexec_authgetLFg_prefork_serverva_list__suseconds_treqsexitLSAPI_CreateListenSock2__rlim_ts_ignore_pid__RLIMIT_MEMLOCKpCurpHeaderValue__sizesizes_slow_req_msecslsapi_init_children_statusgetuidFILEH_COOKIELSAPI_ParseSockAddrdlsympthread_lib_SC_PII_INTERNET_DGRAM_SC_SINGLE_PROCESSbyteReversedump_debug_infoLSAPI_Accept_Before_Fork_SC_SHRT_MAX_ISxdigit_SC_RAW_SOCKETSfp_lve_enterLSAPI_AppendRespHeader_rsize_tH_CONNECTIONLSAPI_GetHeader_r_SC_MULTI_PROCESSs_stderr_log_pathm_statefp_lve_instance_init_SC_BC_BASE_MAXH_CONTENT_TYPELSAPI_STATE_ACCEPTING_SC_RTSIG_MAX_SC_NETWORKINGachCmdH_ACCEPT_SC_GETGR_R_SIZE_MAXperrorcompareValueLocation_SC_THREAD_ATTR_STACKADDR_SC_LEVEL2_CACHE_ASSOC_SC_IOV_MAX_SC_TRACE_EVENT_NAME_MAX_SC_PII_INTERNETIPPROTO_IGMPpServerAddrlsapi_acceptlsapi_initLVE_IO_save_baseLSAPI_Release_riovecold_usr1maxIdleChldsocklen_tm_iMaxChildren_SC_2_UPEai_canonnameIPPROTO_IPV6_SC_DELAYTIMER_MAXpw_dirsa_mask__sigval_tLSAPI_Set_Extra_Childrens_restored_ppidsin6_flowinfototalLenm_pid_SC_SYSTEM_DATABASElsapi_prefork_server_acceptm_pIovecToWritecodem_respHeaderLen_wide_dataH_IF_MATCHai_family__nlink_tsi_addrst_inost_modeLSAPI_IsRunning_SC_T_IOV_MAXCGI_HEADER_LENIPPROTO_DCCP__in6_usysconfGetHeaderVarH_ACC_CHARSET__stream_SC_XOPEN_STREAMSm_iMaxIdleChildrensendfile_IScntrlm_reqBufSizelsapi_child_statusprctlallocateEnvList_ISupperpStatuserr_nosival_intsi_codem_pReqBufwait_timestrcasecmpH_IF_UNMOD_SINCEpw_name_SC_TRACE_USER_EVENT_MAX__socklen_tsend_notification_pktlsapi_requestpKeyEndcurTimefprintflsapi_writev__ssize_t__srclsapi_closepChrootH_IF_RANGEtimespecnameOff__u6_addr8strerror__RLIMIT_RSSavoidForkm_packetLenLSAPI_ReadReqBody_rIPPROTO_MPTCP_SC_2_FORT_RUNbindfp_lve_leave__valin6_addr_SC_ADVISORY_INFOpacketLen__timezone__ctype_toupper_locsin6_addr_SC_TIMER_MAXpBufCur_SC_THREADSunset_lsapi_envs__sighandler_t_SC_USER_GROUPS_RLSAPI_Set_Server_fdLSAPI_CreateListenSock__RLIMIT_LOCKSm_respPktHeaderEndLSAPI_On_Timer_pfLSAPI_Set_Max_Reqs_SC_UINT_MAXst_uids_conn_close_pktLSAPI_Postfork_ParentpEndpktTypelsapilib.cset_skip_write_SC_TRACE_NAME_MAX_lowers_busy_workers_SC_THREAD_DESTRUCTOR_ITERATIONSm_flagmemsetlevelstderrm_pHeaderIndexnameidle_SC_CHILD_MAXlsapi_reopen_stderr2_IO_save_endtm_min__nptrLSAPI_InitLSAPI_Request_SC_V6_LP64_OFF64flag_SC_NGROUPS_MAXm_bufProcessedfixHeaderIndexEndianstdoutfp_offsetlsapi_MD5TransformLSAPI_Write_Stderr_r__time_t_SC_THREAD_ROBUST_PRIO_INHERITgp_offset_padLSAPI_ForeachOrgHeader_rsigaddsetLSAPI_Inc_Req_Processedm_httpHeaderLendyingrealpathtm_yday_SC_SSIZE_MAX_SC_PII_OSI_CLTS_SC_SYSTEM_DATABASE_RmsecspAuth_SC_LEVEL1_DCACHE_SIZEkeyLenextraChildrenLSAPI_Flush_rshort unsigned intrlim_cursigned charLSAPI_Reset_rs_lveold_ppidLSAPI_CB_EnvHandler_valueLen__blksize_t_SC_STREAMSSOCK_STREAMdigestpBufEnd_SC_PAGESIZE_SC_THREAD_PRIORITY_SCHEDULINGcountsi_pidIPPROTO_MTPs_stop_SC_CHARCLASS_NAME_MAXlsapi_header_offsetstrchrvfprintfsetgid_boundstm_wday__off64_t__fd__lenachBuf_sigsys_IO_read_base_SC_XBS5_ILP32_OFFBIGsend_req_received_notification_offsetIPPROTO_EGPLSAPI_reset_server_statesockaddrsigset_ts_defaultGids_keep_listenersecsm_cntUnknownHeadersreadfdsai_addrlenlongsopterr_SC_DEVICE_SPECIFIC_RLSAPI_Set_Restored_Parent_Pidpw_gecos_modem_iExtraChildrenLSAPI_No_Check_ppid_SC_PIPE_IO_write_base_SC_XOPEN_CRYPTvalueLenm_respInfotz_dsttime_SC_PHYS_PAGESlsapi_enable_core_dumpH_CACHE_CTRLH_COOKIE2_SC_ATEXIT_MAX__desttm_monclose_SC_SHRT_MIN_SC_FIFObitstimeH_USERAGENTs_min_avail_pages_SC_USER_GROUPSm_lLastActiveLSAPI_ForeachEnv_rlong intSOCK_PACKETsa_sigactionnotify_req_received_SC_XBS5_ILP32_OFF32dumps_worker_status_IO_marker__builtin_strncpys_ppidtm_yearlimitmax_children_SC_2_PBS_MESSAGEm_pRespBufEndtimevalorig_masktmCur_SC_XOPEN_REALTIME_THREADSfp_lve_is_availablepAddrs_defaultUidm_pChildrenStatus__fds_bits_SC_SPIN_LOCKSLSAPI_Set_Server_Max_Idle_Secswritem_bufRead_SC_SPORADIC_SERVERlsapi_close_connectionuint8_t_SC_LEVEL1_DCACHE_LINESIZE__sigaction_handlerlsapi_signal_SC_PRIORITIZED_IOin_addrSOCK_SEQPACKET__pid_t_IO_codecvt_SC_GETPW_R_SIZE_MAXpUgidheadershints_SC_XOPEN_VERSIONH_RANGE_SC_BC_SCALE_MAX_SC_2_C_VERSIONdup2strtolg_reqlong doubleparseEnvai_socktype_SC_THREAD_KEYS_MAXiov_len_SC_LEVEL4_CACHE_LINESIZEfd_setlsapi_MD5Init_SC_NL_TEXTMAXnonblocklong unsigned intlsapi_req_header_SC_LOGIN_NAME_MAXfind_child_statusIPPROTO_PIM_SC_XBS5_LP64_OFF64_SC_SPAWNmaxChildrennewlensi_statussigemptyset_pkeym_headerOff__RLIMIT_OFILEHTTP_HEADERS_SC_2_PBSs_proc_group_timer_cbpw_gid__errno_location_SC_XBS5_LPBIG_OFFBIG_SC_WORD_BITchar_SC_2_PBS_ACCOUNTINGm_pSpecialEnvListsin6_scope_idstdin_SC_AIO_MAX__oflag_SC_2_CHAR_TERMresolved_path_SC_LEVEL1_ICACHE_LINESIZE_IO_buf_baseai_flagsrealloc_SC_XOPEN_SHM__dev_t_SC_XOPEN_ENH_I18Nold_quitRLIMIT_CPU__glibc_reserved_IO_read_end_SC_ULONG_MAX_SC_TYPED_MEMORY_OBJECTS_SC_TIMEOUTS_SC_LEVEL2_CACHE_SIZEfinal_SC_XOPEN_UNIXm_pRespBufPos_IO_FILEin_addr_tm_fdH_HOST_IO_wide_datacookiestrlentzname_sifields_SC_LEVEL2_CACHE_LINESIZE__u6_addr16s_pidIPPROTO_AHLSAPI_ReqBodyGetLine_rtm_hoursetsidFlush_RespBuf_r_SC_THREAD_STACK_MINisPipe_SC_PII_OSI_Mm_respHeaders_global_counterRLIMIT_AS_SC_NL_MSGMAXsi_signom_pAppData__RLIMIT_MSGQUEUEachAddrm_inProcess_SC_THREAD_ROBUST_PRIO_PROTECT_ISgraph_lsapi_prefork_servertm_mdaypIntegerlsapi_siguser1__pad0_SC_BC_DIM_MAX__pad5_SC_LEVEL1_DCACHE_ASSOCmallocs_dump_debug_infos_avail_pages__u6_addr32_headerInfom_typesi_errnofinish_closelistensigno_SC_XOPEN_REALTIME_markersLSAPI_InitRequest_SC_SAVED_IDSpBindm_scriptFileOff_SC_INT_MAXsi_bands_log_level_namess_skip_writeH_VIAmemccpy_codecvtforkIPPROTO_ESPm_pRespHeaderBufEnd_SC_TRACE_LOGgetpwnamtimeout_SC_THREAD_PRIO_PROTECTg_fnSelectRLIMIT_FSIZE__builtin_memcpyst_rdevlsapi_http_header_indexpEnv_SC_OPEN_MAXst_devssize_tdlerrorheaderIndex_SC_UIO_MAXIOVLSAPI_Logm_pRespHeaderBuf__int32_tH_PRAGMA__uint32_tqsortpSecretFile__RLIMIT_NLIMITS__daylightIPPROTO_RSVPstrncpyH_REFERERIPPROTO_UDPLITESOCK_CLOEXECLSAPI_Set_Slow_Req_MsecsLSAPI_Prefork_Accept_r_sys_siglisthandler_SC_CHAR_MAXLSAPI_Get_ppid_ISlowerpEnvEndsigprocmaskm_pUnknownHeadergetpwuidm_reqState_SC_PII_XTIpRespHeadersleftkillGNU C17 8.5.0 20210514 (Red Hat 8.5.0-28) -mtune=generic -m64 -march=x86-64 -g -O2 -fPIC -fexceptions -fstack-protector-strong -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection=full -fplugin=gcc-annobinm_pRespBufm_iCurChildrensocketLSAPI_Write_r_SC_PII_OSI_COTSm_totalLenpasswdm_pIovecs_stderr_is_pipefstat__snprintf_chk_SC_PII_SOCKET__gid_tlsapi_sigpipe_SC_V6_LPBIG_OFFBIG_SC_MQ_PRIO_MAXgetcwdH_TRANSFER_ENCODINGH_IF_MODIFIED_SINCE__bsxai_nexts_enable_core_dump_SC_TRACE_EVENT_FILTERnodelaysin6_family__resolved_freeres_buf_sigfaultm_iChildrenMaxIdleTime_SC_THREAD_CPUTIMEsi_utimetv_sec_SC_VERSIONm_cntSpecialEnv_SC_C_LANG_SUPPORT_Rlong long unsigned intmemmovesa_handlersin_addr_cur_columnlsapi_load_lve_libtoWriteuid_t_SC_PIIsi_fd_SC_MAPPED_FILES_SC_LEVEL4_CACHE_SIZEIPPROTO_BEETPHfp_lve_jail_SC_2_FORT_DEVIPPROTO_IPm_pRespHeaderBufPosst_blockslsapi_initSuEXEC__bswap_16getpid__buf_SC_2_LOCALEDEFm_cntEnvlocaltime_r_SC_LEVEL1_ICACHE_SIZEreadBodyToReqBuftm_gmtoffIPPROTO_PUP_namesigval_IO_backup_baseH_KEEP_ALIVE_IO_read_ptr_SC_CHAR_BITLSAPI_Register_Pgrp_Timer_Callbackmd5ctx__socket_type__nbytes_nameLengetenv_freeres_list__aps_max_busy_workersIPPROTO_ETHERNETH_IF_NO_MATCHpEnvListrlim_tlsapi_readsun_pathtimezoneCGI_HEADERSsi_overrun__bswap_32pReq_SC_INT_MINlsapi_MD5Update_SC_RE_DUP_MAX_SC_PII_INTERNET_STREAMachBodyachPeerheader_SC_THREAD_ATTR_STACKSIZEfull_path_old_offset_SC_SIGQUEUE_MAXsiginfo_t_SC_FD_MGMTexpect_connected_SC_SYNCHRONIZED_IOLSAPI_STATE_IDLEvalueOffsighandler_t_SC_V7_ILP32_OFF32skipunlinksend_conn_close_notificationoptinds_accept_notifywritevH_ACC_LANG_SC_EXPR_NEST_MAX_SC_LEVEL3_CACHE_LINESIZElong long intm_pktHeaderin6addr_loopbackports_accepting_workersIPPROTO_IDP_flags2lsapi_prefork_serverallocateIovec_SC_MESSAGE_PASSING__ch_SC_REGEX_VERSIONm_iLenLSAPI_Set_Max_Children__d1setuidtv_nsecm_scriptNameOfflsapi_perror_SC_FILE_LOCKING_SC_AVPHYS_PAGES_SC_MB_LEN_MAXpHeader_ISdigitsockaddr_in6IPPROTO_SCTP_SC_PII_OSI_SC_ARG_MAX__ino_tsetsockopt_SC_MEMLOCK_RANGELSAPI_Finish_r_SC_SHARED_MEMORY_OBJECTSlsapi_resp_headersys_nerrin6addr_anym_pRequestMethodachError_SC_CHAR_MIN__realpath_chkiov_basem_lReqBegins_uids_total_pagespw_shell__namem_versionB0m_versionB1IPPROTO_GRE_SC_XOPEN_LEGACY_SC_NL_ARGMAXRLIMIT_COREsi_tidtobekilled_SC_THREAD_PRIO_INHERIT_SC_LEVEL3_CACHE_ASSOC_SC_NPROCESSORS_ONLNm_headerLenexpect_acceptingm_pIovecCurfdListenLSAPI_Init_Env_Parametersaddr_len_SC_HOST_NAME_MAXIPPROTO_TCPLSAPI_AppendRespHeader2_r_SC_COLL_WEIGHTS_MAX_SC_MONOTONIC_CLOCK__rlimit_resourcem_reqBodyReadLSAPI_Set_Max_Idle_SC_CLK_TCKLSAPI_ForeachSpecialEnv_rlsapi_buildPacketHeaderLSAPI_perror_r_SC_NL_SETMAXunsigned int_SC_BARRIERSbodyLenpBeginLSAPI_Accept_rwait_secslsapi_reopen_stderrstrcmpst_mtim__statbuf__RLIMIT_NICEfn_select_tshort intlsapi_notify_pidsi_sigvalsetrlimit_vtable_offsetaddrinfo_SC_IPV6mmapIPPROTO_ICMPlsapi_sigchild_SC_REGEXPlsapi_schedule_notifyLSAPI_Get_Slow_Req_Msecs_SC_V6_ILP32_OFFBIGstatmemchrtz_minuteswestsys_siglistH_ACC_ENCODINGsin6_portm_iMaxReqProcessTime__RLIMIT_RTPRIOGCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-28)GNUzRx 0D LXsEIB E(A0z (A BBBI A (D BBBA  @YGJB B(A0A80F(B DBb0BFC G  AABK Hk(\GADJ n AAA 4UAGK R CAG L JCG AG] AJ t C KFLBBE A(H0H (D BBBD  (D BBBA PXvFB A(D0D (A BBBB L(A BBBA$aAAD XAAHBBB B(A0A8D@N 8C0A(B BBBH $ OAf Q C E H@HYBBB A(D0J 0A(A BBBF xFEA C(G   (A ABBD M I c A  E M A k E E E E H V HFBB B(A0A8D`` 8A0A(B BBBD lT+BBB B(A0D8JYHPC Mi 8A0A(B BBBE LTMDd6BBB B(A0A8DP 8A0A(B BBBG  8J0H(G DBBK $,7EFF IIOTh|  4FAA G>  AABG EO D  A  (Y<JEDXS l]Ph H XAHlFBB B(A0A8LP 8A0A(B BBBH < FBB A(A0 (D BBBI i`0FBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH L$FBB A(A0H Q D 0A(A BBBH LFBB B(A0A8G 8A0A(B BBBF 4FHF\$pnCXJLlFBB B(A0A8DA 8A0A(B BBBA `BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0L BMD GL  AABA < =BAA G L@I@U  AABG $ TWEHG ag H SH FBB B(A0A8DPS 8D0A(B BBBF TX bIE D(C0P (F BBBM Q(H BBBAH FBB B(A0A8DP 8A0A(B BBBA T CBA A(G0` (A ABBD  (C ABBA J8T -FBD D(D@T (A ABBB  ( lECGF AAI L !cBG A(D0 (A ABBE XD0 4 ZH 10\ pFAA G@7  AABF  @LsL FBB B(A0A8G 8A0A(B BBBG   $ 8 L ` t     <  FBA K(G (A ABBG <FEE D(D0M (C BBBB X(HlFBH E(A0E8I@ 8A0A(B BBBE (FED ABH BBB B(A0A8G 8A0A(B BBBJ D0FBB A(A0G 0A(A BBBF Lx FBB B(A0A8G  8A0A(B BBBA    1 -  E2a~345.IWul -- "0s-Je s z )Y)2L0Yz+ k + w 0 Gw : X Ui s  s    x 5 P _ s(0x *  * # N0 al |  O& - =h9Y9 @ $@O e` rU+66 %  7 6S wm w   l      4 f   x    ]  '  ; ]\ m{ m     *+ *L k    \ \" k C k b    "   " $%@ `d0$%UE'xdE'''''D(m())* *+7+F+c,~, 0,.,=.u/*7u/[)0})011224C4k55667!7G7k78d X 8 8+8S:9y:9q9P q9: #h 3 (B:g0;0;H?   @  H?'^?GR^?tk?k????,?V?~???@,@T@z @+@+@?@?@;K@WK@TI ) p h d ` P H @# 80 X6TIYIzIJJJJ K(K?WTK \(b $o(|WUYUYZd Zd>qdiqdd!#$&()+2345671828F"KO(pRP [oy#)/5;AG8MXSY_ekqw+}=Nbw*@V %]+o17=CpIO@U[Tahgtms8yp6&(P,-./0) >Mcmy 1   " / 9 @C R a h v      @7      ! !'! #S!3!8!C!RK!@ Q!X!^!` p!p!Y!J!!0S!]!l!!!` "p i" %","@"#$Y"_"0%u"P'F"'F"'"(")l""""# #.#/1#00?#2P#Y#2s#z#4#5-#####7# 7l#7! $$$!$85$8ZN$@91a$9pv$:@$$0;$$$$P?$`? $p?%?%?:%?V%?u%@ % @ %0@%@@ %P@ %%%%&&& &`I4&I(B&JR&Ka&j&q&{&&&&&W&`Y &&&`d&d '.annobin_lsapilib.c.annobin_lsapilib.c_end.annobin_lsapilib.c.hot.annobin_lsapilib.c_end.hot.annobin_lsapilib.c.unlikely.annobin_lsapilib.c_end.unlikely.annobin_lsapilib.c.startup.annobin_lsapilib.c_end.startup.annobin_lsapilib.c.exit.annobin_lsapilib.c_end.exit.annobin_lsapi_sigpipe.start.annobin_lsapi_sigpipe.endlsapi_sigpipe.annobin_lsapi_siguser1.start.annobin_lsapi_siguser1.endlsapi_siguser1g_running.annobin_compareValueLocation.start.annobin_compareValueLocation.end.annobin_EnvForeach.start.annobin_EnvForeach.endEnvForeach.annobin_lsapi_cleanup.start.annobin_lsapi_cleanup.endlsapi_cleanups_stop.annobin_set_skip_write.start.annobin_set_skip_write.ends_skip_write.annobin_lsapi_MD5Transform.start.annobin_lsapi_MD5Transform.endlsapi_MD5Transform.annobin_lsapi_signal.start.annobin_lsapi_signal.endlsapi_signal.annobin_find_child_status.start.annobin_find_child_status.endfind_child_statusg_prefork_server.annobin_allocateRespHeaderBuf.start.annobin_allocateRespHeaderBuf.endallocateRespHeaderBuf.annobin_lsapi_set_nblock.start.annobin_lsapi_set_nblock.endlsapi_set_nblock.annobin_lsapi_accept.start.annobin_lsapi_accept.endlsapi_accept.annobin_parseEnv.start.annobin_parseEnv.endparseEnv.annobin_lsapi_init_children_status.start.annobin_lsapi_init_children_status.endlsapi_init_children_statuss_busy_workerss_accepting_workerss_avail_pagess_global_counter.annobin_readBodyToReqBuf.part.2.start.annobin_readBodyToReqBuf.part.2.endreadBodyToReqBuf.part.2.annobin_lsapi_close_connection.isra.4.start.annobin_lsapi_close_connection.isra.4.endlsapi_close_connection.isra.4s_worker_status.annobin_lsapi_writev.part.6.start.annobin_lsapi_writev.part.6.endlsapi_writev.part.6.annobin_lsapi_parent_dead.start.annobin_lsapi_parent_dead.endlsapi_parent_deads_ppids_restored_ppid.annobin_LSAPI_ParseSockAddr.part.13.start.annobin_LSAPI_ParseSockAddr.part.13.endLSAPI_ParseSockAddr.part.13.annobin_LSAPI_Log.start.annobin_LSAPI_Log.ends_stderr_is_pipes_log_level_namess_pid.annobin_lsapi_sigchild.start.annobin_lsapi_sigchild.endlsapi_sigchilds_pid_dump_debug_infos_ignore_pid.annobin_dump_debug_info.start.annobin_dump_debug_info.end.annobin_lsapi_check_child_status.start.annobin_lsapi_check_child_status.endlsapi_check_child_statuss_max_idle_secss_dump_debug_info.annobin_lsapi_perror.start.annobin_lsapi_perror.end.annobin_LSAPI_is_suEXEC_Daemon.start.annobin_LSAPI_is_suEXEC_Daemon.ends_uids_secret.annobin_LSAPI_Stop.start.annobin_LSAPI_Stop.end.annobin_LSAPI_IsRunning.start.annobin_LSAPI_IsRunning.end.annobin_LSAPI_Register_Pgrp_Timer_Callback.start.annobin_LSAPI_Register_Pgrp_Timer_Callback.ends_proc_group_timer_cb.annobin_LSAPI_InitRequest.start.annobin_LSAPI_InitRequest.end.annobin_LSAPI_Init.start.annobin_LSAPI_Init.endg_initedpthread_atfork_func.annobin_LSAPI_Is_Listen_r.start.annobin_LSAPI_Is_Listen_r.end.annobin_LSAPI_Is_Listen.start.annobin_LSAPI_Is_Listen.end.annobin_LSAPI_Reset_r.start.annobin_LSAPI_Reset_r.end.annobin_LSAPI_Release_r.start.annobin_LSAPI_Release_r.end.annobin_LSAPI_GetHeader_r.start.annobin_LSAPI_GetHeader_r.end.annobin_LSAPI_ReqBodyGetChar_r.start.annobin_LSAPI_ReqBodyGetChar_r.end.annobin_LSAPI_ReqBodyGetLine_r.start.annobin_LSAPI_ReqBodyGetLine_r.end.annobin_LSAPI_ReadReqBody_r.start.annobin_LSAPI_ReadReqBody_r.end.annobin_Flush_RespBuf_r.start.annobin_Flush_RespBuf_r.end.annobin_LSAPI_GetEnv_r.start.annobin_LSAPI_GetEnv_r.endCGI_HEADERS.annobin_LSAPI_ForeachOrgHeader_r.start.annobin_LSAPI_ForeachOrgHeader_r.endHTTP_HEADERSHTTP_HEADER_LEN.annobin_LSAPI_ForeachHeader_r.start.annobin_LSAPI_ForeachHeader_r.endCGI_HEADER_LEN.annobin_LSAPI_ForeachEnv_r.start.annobin_LSAPI_ForeachEnv_r.end.annobin_LSAPI_ForeachSpecialEnv_r.start.annobin_LSAPI_ForeachSpecialEnv_r.end.annobin_LSAPI_FinalizeRespHeaders_r.start.annobin_LSAPI_FinalizeRespHeaders_r.end.annobin_LSAPI_Flush_r.start.annobin_LSAPI_Flush_r.end.annobin_LSAPI_Write_Stderr_r.start.annobin_LSAPI_Write_Stderr_r.ends_stderr_log_path.annobin_LSAPI_perror_r.start.annobin_LSAPI_perror_r.endLSAPI_perror_r.annobin_lsapi_jailLVE.start.annobin_lsapi_jailLVE.endlsapi_jailLVEfp_lve_jail.annobin_lsapi_reopen_stderr.start.annobin_lsapi_reopen_stderr.endlsapi_reopen_stderr.annobin_LSAPI_Finish_r.start.annobin_LSAPI_Finish_r.endfinish_close.annobin_LSAPI_End_Response_r.start.annobin_LSAPI_End_Response_r.end.annobin_LSAPI_Write_r.start.annobin_LSAPI_Write_r.end.annobin_LSAPI_sendfile_r.start.annobin_LSAPI_sendfile_r.end.annobin_LSAPI_AppendRespHeader2_r.start.annobin_LSAPI_AppendRespHeader2_r.end.annobin_LSAPI_AppendRespHeader_r.start.annobin_LSAPI_AppendRespHeader_r.end.annobin_LSAPI_CreateListenSock2.start.annobin_LSAPI_CreateListenSock2.end.annobin_LSAPI_ParseSockAddr.start.annobin_LSAPI_ParseSockAddr.end.annobin_LSAPI_CreateListenSock.start.annobin_LSAPI_CreateListenSock.end.annobin_LSAPI_Init_Prefork_Server.start.annobin_LSAPI_Init_Prefork_Server.ends_max_busy_workersg_fnSelects_total_pages.annobin_LSAPI_Set_Server_fd.start.annobin_LSAPI_Set_Server_fd.end.annobin_LSAPI_reset_server_state.start.annobin_LSAPI_reset_server_state.end.annobin_is_enough_free_mem.start.annobin_is_enough_free_mem.ends_min_avail_pages.annobin_LSAPI_Postfork_Child.start.annobin_LSAPI_Postfork_Child.ends_req_processeds_keep_listeners_notified_pid.annobin_LSAPI_Postfork_Parent.start.annobin_LSAPI_Postfork_Parent.end.annobin_LSAPI_Accept_Before_Fork.start.annobin_LSAPI_Accept_Before_Fork.endold_childold_termold_intold_usr1old_quit.annobin_LSAPI_Set_Max_Reqs.start.annobin_LSAPI_Set_Max_Reqs.ends_max_reqs.annobin_LSAPI_Set_Max_Idle.start.annobin_LSAPI_Set_Max_Idle.end.annobin_LSAPI_Set_Max_Children.start.annobin_LSAPI_Set_Max_Children.end.annobin_LSAPI_Set_Extra_Children.start.annobin_LSAPI_Set_Extra_Children.end.annobin_LSAPI_Set_Max_Process_Time.start.annobin_LSAPI_Set_Max_Process_Time.end.annobin_LSAPI_Set_Max_Idle_Children.start.annobin_LSAPI_Set_Max_Idle_Children.end.annobin_LSAPI_Set_Server_Max_Idle_Secs.start.annobin_LSAPI_Set_Server_Max_Idle_Secs.end.annobin_LSAPI_Set_Slow_Req_Msecs.start.annobin_LSAPI_Set_Slow_Req_Msecs.ends_slow_req_msecs.annobin_LSAPI_Get_Slow_Req_Msecs.start.annobin_LSAPI_Get_Slow_Req_Msecs.end.annobin_LSAPI_No_Check_ppid.start.annobin_LSAPI_No_Check_ppid.end.annobin_LSAPI_Get_ppid.start.annobin_LSAPI_Get_ppid.end.annobin_LSAPI_Init_Env_Parameters.start.annobin_LSAPI_Init_Env_Parameters.ends_accept_notifys_enable_core_dumps_defaultUids_defaultGids_enable_lves_liblvefp_lve_is_availablefp_lve_instance_initfp_lve_enters_lve.annobin_LSAPI_ErrResponse_r.start.annobin_LSAPI_ErrResponse_r.end.annobin_lsapi_MD5Init.start.annobin_lsapi_MD5Init.end.annobin_lsapi_MD5Update.start.annobin_lsapi_MD5Update.end.annobin_lsapi_MD5Final.start.annobin_lsapi_MD5Final.end.annobin_readReq.start.annobin_readReq.endreadReqs_ackachBody.7025headers.7024.annobin_LSAPI_Accept_r.start.annobin_LSAPI_Accept_r.end.annobin_LSAPI_Prefork_Accept_r.start.annobin_LSAPI_Prefork_Accept_r.ends_conn_close_pkt.annobin_LSAPI_Set_Restored_Parent_Pid.start.annobin_LSAPI_Set_Restored_Parent_Pid.end.annobin_LSAPI_Inc_Req_Processed.start.annobin_LSAPI_Inc_Req_Processed.end.LC0.LC1.LC4.LC5.LC6.LC3.LC2.LC7.LC8.LC9.LC10.LC11.LC12.LC13.LC14.LC15.LC16.LC17.LC18.LC19.LC20.LC21.LC22.LC23.LC24.LC25.LC26.LC27.LC31.LC32.LC30.LC29.LC33.LC34.LC36.LC37.LC38.LC39.LC40.LC41.LC42.LC44.LC45.LC46.LC47.LC48.LC49.LC50.LC51.LC59.LC69.LC70.LC71.LC43.LC35.LC61.LC62.LC63.LC64.LC65.LC66.LC67.LC68.LC52.LC53.LC54.LC60.LC58.LC57.LC55.LC56.LC87.LC76.LC77.LC78.LC72.LC79.LC80.LC86.LC74.LC84.LC83.LC73.LC75.LC82.LC81.LC85.LC92.LC91.LC88.LC90.LC89.text.group.text.hot.group.text.unlikely.group.text.startup.group.text.exit.groupcompareValueLocationset_skip_write_GLOBAL_OFFSET_TABLE_sigactionsigemptyset__stack_chk_failreallocfcntlsetsockoptmmapmemsetsetsidread__errno_locationwritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkstrdupLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamenvirondlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectd \D   h o    2 9 H $O ,T g -o    h C M X h c z  h  h h a 8g.J5*T/0 *1%>Kw235R4Y5`6v\  "X 3/8M7`io89p3:?K_;<Rf=h{d h t8~KW>`i{h*$?*/?@GNw*"  ( h !A`!!!a"j#<q#\p$*}$$*$ %%%&A'((Y)))b***7+A+N+BW+_+}+C++++D,,{,D,,E,,h -n---F----.8.?.N.Y.~.G...H./*/ L/T/i/// /0_1111Q2v22/33-4O4|5N6h66666666I7W7777` 7` 77888#8-828<8G8T {8889'9G9$Q9L f9T 99999999999p:*:#:<:d G:Z:` d:h::::#:::: ;!;H;;;;;;|;;<<<<,<9<V<x<t<\ <<<$< :=S=e=o=}=|====<====>/>I6>@> F>w> > >>J>?K ??L#?D?Y?f?w?????@&@6@F@_@M@@@N@@@O@@@d @P@A'AQ,A@AFA%MARRAfAmAtASyAAhATAAAAAUAAAVA BBBW B4B;BBBXGB[BbBiBYnBBBBZBBB[BBB` B\BBBBhC` C\C]#C2Cd?CdEC`TC^YCqCwC\ChC*ChC_C`CazD` DDL D DbDDcE%E`1ENEUE*\EpEduEELEeEEDEE\EfEEgE<EEhEEiF4 FFjF%F,,FTGFkLFSFTXF_FPFFFFFlFFFdGm GG(G`/Gn4GQGmGG|GGGGdG`HoHH\"Hd,H`6H`DH\ZHXyHLHpHHHH<HTHHhHHDHXIh IIq+Ir7IAIKIsIIIIJJzK9LDLOLh JMUMdMh M4NOtOPuP*P.RhDR%JR$]R#}RRdR`RvSwmS|S!S"S"S# T$TT/T4GT+uT%T&T'TlThTTMTUU|*U$1UGUxSUeU}U(UyUUzUUdU`U$UTU)V{V V|,V=V%eV%V}V*V~V[VdV`V$VWW+W9WPWYWyWWW WWXh BXUXhXX$XXh XY$ YGYQYxYYYYYYYYh #Zh 3Z?ZeZ ZZZp[[[[[\C\\\t\\ \\\$] ^]u]]]]^^4^d B^$X^$]^s^^^^^_d __c +_D_c__ _ _ __I__ ` `%`\`k`-|`.```.``` a,aJ5abaqa` aa` aaaaaaabbh 3bK8bGbXb.gbpbvb{bbbbbbpb*bbbd bc` ch$cCcTcecvcccccc#ccLccd dd9dKdVdfdldd, s|2J +$,PX---D-Lpx 08)dl)))+ $,+ P+ Xw + w w  w   s D Ls ps x s   x  x 0x 8* dx l* *  *   $ ,PX99 9 D 9L p x       0 8 6d l 6 6 w 6 w w $ w, P X         D L p x     ]  ]0 ]8 md ]l m m  m   $,PX****DLpx\\\k \ k 0k 8 dk l  " ""$%$",$%P$%XE'$%E'E''E''''D'L'p'x('(()( )0)8*d)l**+*++,$+,,P,X.,..u/.u/u/)0Du/L)0p)0x1)01121 20284d2l4454556$5,6P6X767777778D7L8p8x8888:98 :90:98q9d:9lq9q9:q9::0;$:,0;P0;XH?0;H?H?^?H?^?^?k?D^?Lk?pk?x?k????? ?0?8?d?l??????@$?,@P@X@@@@+@@+@+@?@D+@L?@p?@xK@?@K@K@TIK@ TI0TI8IdTIlIIJIJJJ$ J, JP JX K J K K W K W!W!UYD!WL!UYp!UYx!Zd!UY!Zd!Zd!qd"Zd "qd0"qd8"dd"qdl"d % & ' (]CC C(X 01CC3C9C> CE(CJ0CP8CU@C[HCbPCqXC`ChCpCxCCCCCCCCCCCC+C4CHCSCYCiCm C(C0C8C@CHCPCXC`ChCpC!xC+C7CDCTCgC~CCCCCCCC  $+ $ $) #0 $8 < $YC $ 7J $"$Q $uV $d $7n $ z $* $* $! $% $ $e- $@4 $' $ $q $  $# $' " $. $E: $oM $Y $ e $q $ $F% $a $ $+ $ $4 $ $5 $  $+( $/  $ $ $n $  $, $9 $o.F $3T $U8a $[*n ${ $ $ $ $j $j( $)* $ $  $/ $  $j7  $ $.&5 $A $rM $/b $p $F  $* $!0 $ $  $$ $! $ $s5 $.1 $7( $!5 $B $7Y $!f $s $$ $f. $  $ $ $y $$ $ $ $} $f)( $/? $ L $Y $Qp $w| $  $ $9 $2. $M $ $' $( $ $j( $&, $18 $^ $.j $! $ $" $ $h $$ $`+ $p8 $2 $.. $b*: $^F $!S $o.` $n $z  $2" $# $  $ $ $m $ $ $< $&( $5 $E0B $?&O $\ $i $v $E $% $I $ $(0 $ $) $  $ $'3 $1 $. $7 $o, $9 $F $)S $` $0m $%.z $( $ $ $ $ $g! $# $& $g $%& $ 2 $J> $4Z $ f $6x $#&~ $ * $ $. $g5 $  $ $$ $' $t $ $C $h $' $|7 $8 $ $* $U $0 $y $l $  $, $49 $#G $S $0e $k $b q $ w $ } $# $ $! $#+ $ $ $! $ $V $1 $a8 $- ( $ -5 $@B $O $\ $ %i $v $ $5 $ $ $S' $J( $ $! $ $ $ $0 $= $ I $*U $a $&m $ y $1 $C $44 $j $6 $ $N* $ $ $ $6) $ $X $ $ $" $ 2 $  $/ $  $S4 $ $R3 $$ $t4* $10 $%6 $ < $B $R H $-N $v.T $Z $` $mf $wl $1r $x $^~ $q( $k# $ $V6 $* $2 $f $e1 $; $  $  $  $W/ $O $ $/ $/ $+ $V- $G $(4 $ $d $~* $" $t1 $K  $-& $, $'2 $8 $> $5D $J $(#P $E$V $\ $b $#h $r'n $t $z $1 $ $5 $) $ $S $5 $8  $3 $u  $ $Q# $ $& $  $& $% $% $|# $ $ $ $ $R0  $u+ $4 $Z) $I1" $f( $9%. $34 $ : $@ $ F $XL $R $ X $O^ $d $L&j $p $Y5v $ | $' $h $6 $ $ $=! $ $v$ $#% $H5 $) $! $ $7 $0 $ $. $ $. $S. $Z $ $ $1 $  $ $Y  $3 $$ $k6* $0 $b6 $< $B $="H $8N $k3T $Z $~` $$f ${"l $r $ux $~ $s& $Z& $  $ $$ $K% $I $! $  $  $ $$  $ $A8 $ ${- $6 $2 $- $ $) $/ $b  $% $ $( $"  $&& $ , $'2 $8 $5> $2D $&/J $ P $#V $7\ $b $F2h $n $At $z $p  $. $ $ $H $y $N $ ( $  $2 $ $  $" $^ $ $& $" $9 $f/? $7E $XK $; Q $06W $] $0c $i $3o $u $8{ $ $* $<5 $) $1' $( $  $A $F  $ $ $' $(N $v[ $En $4z $2 $ $W  $  $. $ $4 $. $8 $X $ $r%- $7; $%I $W $#e $ys $q $ $ $- $#  $  $1 $ $b  $|8 $2 $% $" $n( $;. $4 $k : $&@ $*F $ +L $ R $^ X $-^ $d $0j $p $/v $80| $c# $ $) $- $}3 $ $ $$5 $05 $( $6 $! $4$ $2  $- $ : $J)G $3T $0a $Q n $U{ $/ $. $1* $5 $$ $R $ $ $02 $  $- $q: $ H $4U $2b $" r $#w $  $  $4 $6 $  $ $  $& $  $4 $ $ $," $!/ $&< $*I $)V $q/c $p $'-} $ $5 $ $R $? $% $`% $ $ $Q $+  $ $& $ 3 $@ $4M $-Z $+g $ t $6 $ $q" $W $' $ $' $ $o $ $  $( $A" $/ $d < $m I $L $ $# $ $7+ $eO $i $  $ $2 $ $} $ $W! $  $gl $ $!1: $HGP $+']f $s| $@h  $( $ $ $) $ $,5 $3BK $'X0a $0nd w $/ $0- $`  $5X  $ P  $(( # $09 $$Fx_ $"1l  $) $$@ $` $n) $92 $- p $5 l( $"6 h? $3M dV $ d `m $ r $ X $+ P $! H $I @ $0*! $8!8[! $c! $K/!0! $2!)! $K! $~! $!(! $ !(" $" +" $(9"B" $(P" $0^" $0l" $z" $" $*"" $4(" $&" $" $" $," $" $ # $<.# $8# $,# $ ":# $H# $0W# $/3d# $Vr# # $## $"## $4## $## $&## $ $@ $ $$"$ $0$9$ $CF$ $R$dy$ $$`d$ $$ $ $ $$$ 1$ - % % j % ~$% R3% 7% pF% hJ% @V% $ ^%Ku% $% % % X% P% $% % % ( % " %3K%3K% s % q %  &  &  &  &QK$&QKA&  E&  N&  R&  [& 8 _& 6 i&pKs& " & _ & [ &  &  &  &  &~K&K& "`&  &  &  &  & M & K 'K ' "' r !' p *'  .'  7'  ;'  A'QK_'K' $U1'J'  '  '  '  ' h ' \ '  '  ' "@ ( ( (dJD(|JN( "p_( c( l( p( y( @}( <(J(J(J( "( ( ( ( ) )  )J/)J9) "J) $N)  W) d[) bd) h) m)J{)J) $#)I) $u) $|) $ *`I"* $D1.* 2* 7* $C* G* L* $+X* \\* Ra* $m* q* v* $'7* <* 4*dI* "* * * * *I*I*I+IB+ $5N+P@p+ t+ + + + + + + + $+ + +pF+ $!+F ,@,@3, 7, <,@Y,@c, " t, 6x, 4},@,A,A, ], Y,A,5A,5A- - -DA:-[AD-[Aa- e- j-jA-A-A- - -A-A-A- - .A!.B+.BH. )L. 'Q.Bn.)Bx.)B. N. L.8B.PB.PB. s. q._B/wB/wB// 3/ 8/BU/B_/B|/ / /B/B/B/ / /B/B/ " 0 " 0  0 0 E 0 ?)0 " 60 :0 C0FM0Fj0 rn0 ps0F0G0G0 0 0"G0DG0 " 0 0 1 " 1 1 r 1DG*1DGG1 K1 T1 AX1 ;]1UG1`G1`G1 1 1 1 1qG1G1G 2 2 2 A2 ?%2 o)2 m.2GE2U2Gm2H2H2;I2]2F2C]2G3Co 38G3C&3'C73CVG3QCQ3 "@ ^3 "@ g3 k3 t3fC~3fC3 3 3uC3hE3 " 3H3  3 3H 4H#4I84yEM4C^4Ey4C4E4E4 " 4 " 4 Z4 V4E4C4E4C5E#5C-5FH5CR5"Fm5Cw5PF5]5\F5H5]C5C5 H5C5C5C6C*6 .6 760DL6 P6 \6Ff6F6 4 6 2 6F6F6F6@6C7@7@#7C-7@B7C+L7@a7C=k70A7CN7VA7Cb7qA7}A7Cw7A7C7A8A8A#8C-8AB8CL8BY8$Bn8Cx8?B8KB8C8fB8rB8C8B8B8C8B 9B9C*(9B=9C@G9D_9Dl9D9C9E9C95E9RE9`E9EI9 $O7: $14: $xF: $1S: $ a: $ ~: $&: $]: $%: $/; $3; $+?;@@R; $Z;0@m; $(8y; @; $0+;@; $; $L";?; $; $B;? < $< $5!<?8< $PH< $/P<?g< $=w< $3<p?< $$< $6<`?< $P< $w<P?< $}= \ = X = $I+=`Y-= $D19=  ==  M= !!Q= !b= !f= !k= $E7w= ="{= /"= $i= $)= "= $ = $3=aZ= "= "=iZ >(_ > $,> #0> #:>@[D> "U> ($Y> $b> ($f> $o> $s> $x> "> %> %> 0&> &> 5'> +'> '> '> (> '> I)> /))? "A?]Z? W*^? S*c?]u?`_? *? *?_?_?_?c? "? +? +? "@c@ " @ +$@ +-@ +1@ +:@  ,>@ ,H@cR@co@ 1,s@ /,|@ W,@ U,@ },@ {,@c@c@E[@t[@[ A[#A[HA[mA"\AG\A\A` A\A\A\B\&Bb]LBy]YB]}B_B]B_B@`BS`B``Bo`C`EC`RC`_C`C`C]CaC9aCCCaC](CaCaD]D$J>2Ju;?J;WJ;wJJ;J;JJ<J@J!< KK=<7KAK<RK` \K<sK<K<K<K>=KW=Ks=K L=$L3L=ML\L=vL@L=LL:>L]LD>L>L> M> MC*M??MCIM'?^M]hM5?MH?M $M:M $D1M 2M  2M ;M $M a2M _2M;N%;N $N95N $D1AN 2EN 2JN $!VN 3ZN 3cN:mN " ~N *3N (3N " N:N " N O3N M3N u3N s3N 3N 3N:N "P N 3N 3O 3O 3O 4O 4O:'O:HO9UO9bO9oO:OO::O:O:O:O $O $O $D1 P $P $&&P $ 3P $@P $MP $ZP $E7P $(P $P $iP $)P $P $!P $ P $3Q $Q $Q@91Q $9QLQ $TQkQ $!wQ G4{Q 94Q $eQ 4Q 4Q $z5Q o5Q c5Q $Q 6Q 5Q $Q 6Q 6Q $Q ^7Q X7Q $Q 7Q 7QCR]P&RO=R[R]eR|RR R]RR $RR $R 8R 7S $!S 8S 8S $,S6SSS 8WS 8`S  9dS  9mS 69qS 29vSS]S S3S<SdS]pTm&T>TUTjTCRtTT $T T $T y9T o9T $T 9T 9T $!T :T :T U U ;$U ;-U B;1U @;:U j;>U f;CU dU UX Us UCU $7U $U $U $1V $5V $V $ ,V $R!;V $CV8ZV $fV ;jV ;oV ${V ;V ;V $X$VV $V ;V ;V $V *<V $<V V W u< W s<W <W <"W <&W <-W $5WLW $\W $qhW W $5W <W <W .=W "=W $.W $1W Xl 0Xs NX $VX8|X $DX $!X $X $,X 7X $D)X =X =X $O X =X =Y $v Y X>#Y T>5YM7TY[7rY7Y $%Y $D)Y $ "Y $'Y $Y $K#Y $ Y $3Z $"Z59Z $eEZ >IZ >NZ $O ZZ J?^Z :?oZ @sZ ?Z P@Z J@Z $Z $6Z @Z @ZR6Zl6Z6[6@[6^[6k[6x[6[6[ $[ $D1[ $[ $$[ $<6 \2"\ $D1.\ @2\ @7\ $C\ /AG\ 'AL\ $X\ A\\ Aa\ $m\ Aq\ Av\ $ \ LB\ FB\ B\ B\ "P \ B\ B\ " \ (C\ $C\3\ $$\ dC] ^C]4]4)] " :] C>] CG] CK] CT] +DX] )D]]14}]I4] " ] TD] PD] D] D] D] D]S4]33]3^ $^'&^ $D19^_(C^ "P^ DT^ D]^ )Ea^ 'Ej^ QEn^ MEu^ $6^'^ $D1^ E^ E^ E^ E^ KF^ CF^'^ $ ^P'_ $D1"_ F&_ F6_ G:_ FK_ kGO_ cGT_'q_ $ }_0_ $I*_ G_ G_ 6H_ .H_ H_ H_ 5I_ )I_ $_ I_ I` J ` J`{ ` $ ,`0%C` $D1O` JS` Jc` Kg` Kx` L|` L` lL` hL` L` L` $4` L` L` 9M` 5M` $` }M` oM` "@` $ a &Na Na $ !a N%a N*a $6a N:a N?a $6Ka 4OOa &OTa $`a Oda Oia $ua Pya P~ax&a cPa aPa&a $a Pa Pa&ac&a "pb Pb Pb Qb P(b /Q,b -Q2b&[b%bE'b $|b#b $D1b ^Qb RQb Qb Qb Rb }Rc JSc >Sc Sc S!c $4-c NT1c BTBc TFc TKc $Wc 5U[c #U`c $C#rc#c $ c Uc Uc $6c cVc [Vc $c Vc Vc $c Vc Vc$cd$4d>d$Rd$%qd $}d d $}d d $D1d EWd 3Wd $`d  Xd  Xd $/7 e 4Xe 0Xe $$e "`;e "`De rXHe lXQe XUe X^e "ke Xoe Xxe RY|e JYe Ye Ye Ye Ye *Ze &Ze dZe `Ze "e Ze Ze "e Ze Zee"e!fd!(f $U:f $D1Gf $`_f $4xf $ f $f $6f $f $f $f $0f $D1g $ g $1-g $Eg $Rg $fyg $z g $Kg(g $D1g e[g Y[g [g [g o\g g\g(h "h \h \(h ],h ]5h h]9h f]>h "Lh ]Ph ]Zh)qh(h!)h])h $b'hp h $D1h $3h ]h ]h $Q i T^ i R^i i " *i y^.i w^7i ^;i ^Di ^Hi ^Oi $[i2ri $D1~i ^i ^i $|i _i _i y`i i`i $i 7ai 'ai $3i ai aiU2i " i bi bj b j bj bj bjU26jz2Sj2zj2j $,j $D1j $j $3j $j $Q j $.k $k $Y2!k $--k`Dk $D1Pk cTk  cYk $ek cik cnk $Q zk c~k ck ddk Xdk $/k  ek ekk "k nek jek ek ekl l "l e!l e*l f.l f7l Af;l =f@l "Il {fMl wfVl `l }l fl fl fl fl fl fl l! l $<'ll $D1m *gm  g m $m gm gm $Q *m h.m h3m $P?m thCm jhTm hXm h]m $+im (imm  irm $~m im im $m im im $m jm jm jm jmm " m km km Tkm Pkm kn kn$nCn(Mn(jn knn ksn(n ln kn4nn $ nn $D1n Tln Hloo+o l/o l4oNo mRo mWono $/o $D1o $o $ o0o $D1o $r*o ;mo 7mo zmo tmp $p(p $D14p m8p m=pJpWpdp&rp $zpp $D1p #np npp "p qnp onp np np $D p/q $D1 q nq nq/.q/Fq/fq!0{q $e4q.q $D1q Doq 8oq#/qP/qX/qm/ r $67rW,r $D18r os(QsWisXsFXsXsXsXsXtXtKY9tUYGt $2 St`jt $D1zt $ tpttt $$)tt $D1t Eqt ;qt qu qu $ u Mru Kru(u "9u rr=u prFu rJu rYu3cu "@tu rxu ru ru ru "@u  su  su<uuu Esu Csu v0vCv]Mv "^v jsbv hskv sov stvdvCovvv=vOwmw&w $_0.wTw $ `wsw ${ww $ww "w $?w sw swwwwx xz $D1z $ { $=#{ $${ $01{ $O{ $]a{ $D1{ ${ $~{ $I*{ $ {,{ $D1{ s| s| Pt| Ht&| t*| t;| t?| tD| $U|H,p|,|]|,|C|,| $ | $D1 } $&%} $7} $D1D} $C#R}[} $1i} } $6}+} $D1} Yu} Qu} $^} u} u} $d} %v} v} $4~ uv~ qv#~q+-~ ">~ vB~ vK~ vO~ vY~+~C~;+~E+~[+~c+~+~+~+ $ $ $r 6 $*\ ${ $. $  $D1 $f $ $ $ $D14 $A $P $s^ $D1w $ $R( $# ̀ $0؀ w܀ w $ jw fw $/7 $ w w $+& x*  x/ $6; Sx? GxD $ P xT xZ $'x $1 $ $0 $& $́ $ $x $3 $ $&0 = $D1I yM yR $^ Fzb @zq zu zzH $D3 $D1ł $ׂ $D1 $ $ $ $q* $7 $fQ $+p $1 $ $"ă $D1҃ $ $2  , z0 z5 $$A {E {V &|Z  |_  $6 $3 $S҄ $G ܄ $"0 $) w| o| $m+ | |5`Xp $[(Ѕ $m-؅ $P $3@, $"8 E}< =}A $M }Q }VVnwC[ $*@ $ʆ ~Ά  ~ކ ~ ~ \ H $D 6 0.0eo "P     ܀ ڀ̇]ۇcc   / - W U$NC"YBvOS " ~ z ˆ ˈ ψ ԈX # , G0 E9 n= lBjC2~ "    ĉ ȉ ͉C8 " "#  , P0 N5)KCF\iw $s $D1 $ $- $/ $ˊ $>܊ $ $/ $0 $+ $  $* $7 $H $ T $a $=r $ ~ $f3 $ $. $ $ $͋ $ ދ $ $ $ $m $p $, $0? $P $p\ $j $ $ $ $5 $.֌ $ $ $  $ $A-( $5 $r7I $Z $f $%t $91 $- $/ $- ύ Ӎ t܍   H B "    ' @+ <0 "09 |= vF P m Džq Ņz ~     Ŏ0 @ @  6 4!G 9Q Lw Vw v c Y ߆ Ն [ Q ه ͇ŏ mɏ aҏ ֏  e+5 "`BPgy [ S   & Đ Ȑ    X R''$ ( 1 ʋ5 ȋ> B G<lv " , * S Q z vϑFّ "  Nx "1 ٌ5 ׌> B K (O $Yc "Pt ex a   ͍ ˍ "˒ ϒ ؒ ܒ  k (C2P{9ؓ Cܓ ? " "$ ( |1 V5 J> B ؏K vO pX "e i r v {z”ؔ)      ?# 1T)^){  ޒ 5 1 q m)  ɕ ԓ͕ ̓֕ <ڕ 4   Ô {* " * . 7 ";  D HH FQ nU lZ " h l u Εy ̕~*D* "p Ö ̖ 0Ж .ٖ Vݖ T)**8*J,e i y|, "  y     "̗ MЗ Gٗ ݗ - "@ ԙ ҙ   -7{-A{-^ #b k ^o \t{-  -r-Ҙ].ߘ..- "p  # "p, 0 9-C-` d m q v---<.ۙC.R..%]X;x.Ex.b ٛf ӛkx..]8.00ך 1ۚ % ɜ   "0, "= 0A (J N W [ ` "i Bm 6v ɟz ş    {   J D0ƛ "ܛ    11 " + / 8 /< -A1dc1|114 `Ü R̜  М ٜ ݜ  " / # 5# ' 1>5J FN @Sg5lq5v "P      ޥ5ǝ7   ] W7=7X \ e i r v 7 " ? 5   3 -7֞8'868@88(KC G |P <T :b,Ll "} c _   ת Ӫ "   0L0Lݟ I G n l  =L!HL4L> " O S X " a e n 2r *{LL    LѠ ۬ՠ ٬8M8M   % #! J% H*@M? qC mL@MV@Ms w  έ ̭  NMYMʡMԡ "     "    ^ T'M1MN ϯR ͯ[ _ h l qMMM D B i gȢ ̢ ѢM  MNN< ް@ ܰI M V +Z )_Ny!N!N S Q x v  !Nԣ ȱأ Ʊݣ8NyO " " ' "0 4 = A JO_ @c >l ep c|OPOP  OP Ť ΤOPؤ "0 Գ ҳ "0   "  kP! "p2 G6 E; "pD nH lQ U `yPj "{   "  ߴ  P "ĥ Cȥ Aͥ "֥ jڥ h  P "`   "` ޵# ܵ, 0 ;PE "V +Z )_ "h Rl Pu {y wP "   " ۶ ٶ ¦ ͦPצ "` ( & "` O M v tP "- 1 6 "? ÷C L P ]Q{Q ' #"Q a _ç ǧ Ч3Qڧ3Q  3Q ݸ ۸ " .bQC +G %P xT v]Qg "x |  " ۹ ׹  Q "0¨ "0Ш :Ԩ 8ߨQ "p "p _ ]Q" "0 "> B P\UZ\Uw { \U κ ̺iUUթpNN P)C30VQC6[/Wu]vRvR   ê ȪvRݪ = ;R R "' j+ `0 "9 = ٻF J ~S W ` (d m q z  ~  E ?_S "p    ɫ ߾ͫ ۾֫ ګ  C = "S " " & / 3 < @ FS^SSSǬTѬ "`       6 ( "  ( *, 5U? "U Y b "t xx rhWhW  hW­W 3T&hW=]RU\UuVV] TϮ\TyTTT6UNAV[iVhVCVVCɯVJWC W"C3T@T[CeUrU]8U]pİUΰU     6 4U ". d2 b;UE " R V _UiU  UU   ñ ȱ5Uٱ(P CTWU2C< WVC&m Pw P * ( T P P ò Ȳ.P߲TW $= $ $. $g $& $& $7 $7 $# $#( $, $ 4 $b8 $bA $>E $M $ Q $ Z $0^ $0g $)k $)s $w $ $m $m $H $H $9 $9 $j* $j* $ $ $ ³ $ ˳ $(ϳ $(س $ ܳ $ $% $% $ $ $ $ $ $  $ $ $/" $/+ $k"/ $k"8 $$< $$D $H $P $ T $ \ $M` $Mi $m $u $+y $+ $) $) $[' $[' $ $ $+ $+ $G- $ $ ô $ ̴ $д $ٴ $7ݴ $7 $ $ $H4 $H4 $, $, $" $" $^ $^! $(% $(- $^21 $^2: $> $F $*J $*S $c7W $c7_ $c $k $Z8o $Z8w $%{ $% $# $# $v $v $ $ $ $ĵ $ȵ $е $/Ե $/ܵ $_ $_ $ $ $2 $2 $+ $r! $  $* $" $* $f. $f6 $$: $$B $ F $ O $eS $e\ $` $h $l $t $-x $: $4 $4 $) $) $J $J $J $ $ $ $ $ȶ $̶ $Զ $+ض $+ $v $v $ $ $3 $3 $ $T+'-(- 38]QCp(sCovC]C",C2C85CF ʿI(   4H \00L`0     \ 0  $L@ X0@Xl`p,@\0p` p 4 #0%8P'L'`'t()+P , , . / 00\ 2 2 4X 5 7  7 7$ 88 8L @9` 9 : 0; P? `?( p?< ?P ?d ?x ? @  @ 0@ @@ P@`I\IpJKK4W|`Y`dd.symtab.strtab.shstrtab.rela.text.data.bss.rela.gnu.build.attributes.text.hot.rela.gnu.build.attributes.hot.text.unlikely.rela.gnu.build.attributes.unlikely.text.startup.rela.gnu.build.attributes.startup.text.exit.rela.gnu.build.attributes.exit.rodata.str1.1.rodata.str1.8.rodata.rela.data.rel.local.rela.data.rel.rela.data.rel.ro.local.rela.debug_info.debug_abbrev.rela.debug_loc.rela.debug_aranges.debug_ranges.rela.debug_line.debug_str.comment.text.hot.zzz.text.unlikely.zzz.text.startup.zzz.text.exit.zzz.note.GNU-stack.note.gnu.property.rela.eh_frame.groupP@:PT:Pl:P:P: d@@A@G:&`ep ,n 6nt"1@ : LT[TV@P0: u((@0:@0:ЖЖ@0:22/"D /`8 *@:D?@:S N@p:kf@(\:!wa-i@ :$/0@0:& 0`lJR@H:)0}807.eeueLe eeeeee.h FA@((:8x4; ('PWPKu]k##!ruby-lsapi-5.6/ext/lsapi/Makefilenu[ SHELL = /bin/sh # V=0 quiet, V=1 verbose. other values don't work. V = 1 Q1 = $(V:1=) Q = $(Q1:0=@) ECHO1 = $(V:1=@ :) ECHO = $(ECHO1:0=@ echo) NULLCMD = : #### Start of system configuration section. #### srcdir = . topdir = /opt/alt/ruby27/include hdrdir = $(topdir) arch_hdrdir = /opt/alt/ruby27/include PATH_SEPARATOR = : VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby prefix = $(DESTDIR)/opt/alt/ruby27 rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) rubyarchprefix = $(DESTDIR)/opt/alt/ruby27/lib64/ruby rubylibprefix = $(exec_prefix)/share/ruby exec_prefix = $(DESTDIR)/opt/alt/ruby27 vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby rubyarchhdrdir = $(DESTDIR)/opt/alt/ruby27/include vendorhdrdir = $(rubyhdrdir)/vendor_ruby sitehdrdir = $(rubyhdrdir)/site_ruby rubyhdrdir = $(DESTDIR)/opt/alt/ruby27/include rubygemsdir = $(DESTDIR)/opt/alt/ruby27/share/rubygems vendorarchdir = $(DESTDIR)/opt/alt/ruby27/lib64/ruby/vendor_ruby vendorlibdir = $(vendordir) vendordir = $(DESTDIR)/opt/alt/ruby27/share/ruby/vendor_ruby sitearchdir = $(DESTDIR)./.gem.20260423-2006031-v30xda sitelibdir = $(DESTDIR)./.gem.20260423-2006031-v30xda sitedir = $(DESTDIR)/opt/alt/ruby27/share/ruby/site_ruby rubyarchdir = $(rubyarchprefix) rubylibdir = $(rubylibprefix) sitearchincludedir = $(includedir)/$(sitearch) archincludedir = $(includedir)/$(arch) sitearchlibdir = $(libdir)/$(sitearch) archlibdir = $(DESTDIR)/opt/alt/ruby27/lib64 ridir = $(datarootdir)/$(RI_BASE_NAME) mandir = $(DESTDIR)/opt/alt/ruby27/share/man localedir = $(datarootdir)/locale libdir = $(exec_prefix)/lib64 psdir = $(docdir) pdfdir = $(docdir) dvidir = $(docdir) htmldir = $(docdir) infodir = $(DESTDIR)/opt/alt/ruby27/share/info docdir = $(datarootdir)/doc/$(PACKAGE) oldincludedir = $(DESTDIR)/usr/include includedir = $(DESTDIR)/opt/alt/ruby27/include localstatedir = $(DESTDIR)/var sharedstatedir = $(DESTDIR)/var/lib sysconfdir = $(DESTDIR)/etc datadir = $(DESTDIR)/opt/alt/ruby27/share datarootdir = $(prefix)/share libexecdir = $(DESTDIR)/opt/alt/ruby27/libexec sbindir = $(DESTDIR)/opt/alt/ruby27/sbin bindir = $(exec_prefix)/bin archdir = $(rubyarchdir) CC_WRAPPER = CC = gcc CXX = g++ LIBRUBY = $(LIBRUBY_SO) LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a LIBRUBYARG_SHARED = -Wl,-rpath,$(archlibdir) -L$(archlibdir) -l$(RUBY_SO_NAME) LIBRUBYARG_STATIC = -Wl,-rpath,$(archlibdir) -L$(archlibdir) -l$(RUBY_SO_NAME)-static $(MAINLIBS) empty = OUTFLAG = -o $(empty) COUTFLAG = -o $(empty) CSRCFLAG = $(empty) RUBY_EXTCONF_H = cflags = $(optflags) $(debugflags) $(warnflags) cxxflags = optflags = -O3 debugflags = -ggdb3 warnflags = -Wall -Wextra -Wdeprecated-declarations -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable cppflags = CCDLFLAGS = -fPIC CFLAGS = $(CCDLFLAGS) -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection $(ARCH_FLAG) INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) DEFS = CPPFLAGS = $(DEFS) $(cppflags) -DRUBY_2 CXXFLAGS = $(CCDLFLAGS) -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection $(ARCH_FLAG) ldflags = -L. -L/opt/alt/ruby27/lib64 -Wl,-rpath=/opt/alt/ruby27/lib64 -fstack-protector-strong -rdynamic -Wl,-export-dynamic dldflags = -L/opt/alt/ruby27/lib64 -Wl,-rpath=/opt/alt/ruby27/lib64 ARCH_FLAG = -m64 DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) LDSHARED = $(CC) -shared LDSHAREDXX = $(CXX) -shared AR = ar EXEEXT = RUBY_INSTALL_NAME = $(RUBY_BASE_NAME) RUBY_SO_NAME = ruby RUBYW_INSTALL_NAME = RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version_dir_name) RUBYW_BASE_NAME = rubyw RUBY_BASE_NAME = ruby arch = x86_64-linux sitearch = $(arch) ruby_version = 2.7.0 ruby = $(bindir)/$(RUBY_BASE_NAME) RUBY = $(ruby) BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME) ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h RM = rm -f RM_RF = $(RUBY) -run -e rm -- -rf RMDIRS = rmdir --ignore-fail-on-non-empty -p MAKEDIRS = /usr/bin/mkdir -p INSTALL = /usr/bin/install -c INSTALL_PROG = $(INSTALL) -m 0755 INSTALL_DATA = $(INSTALL) -m 644 COPY = cp TOUCH = exit > #### End of system configuration section. #### preload = libpath = . $(archlibdir) LIBPATH = -L. -L$(archlibdir) -Wl,-rpath,$(archlibdir) DEFFILE = CLEANFILES = mkmf.log DISTCLEANFILES = DISTCLEANDIRS = extout = extout_prefix = target_prefix = LOCAL_LIBS = LIBS = $(LIBRUBYARG_SHARED) -lm -lc ORIG_SRCS = lsapilib.c lsruby.c SRCS = $(ORIG_SRCS) OBJS = lsapilib.o lsruby.o HDRS = $(srcdir)/lsapidef.h $(srcdir)/lsapilib.h LOCAL_HDRS = TARGET = lsapi TARGET_NAME = lsapi TARGET_ENTRY = Init_$(TARGET_NAME) DLLIB = $(TARGET).so EXTSTATIC = STATIC_LIB = TIMESTAMP_DIR = . BINDIR = $(bindir) RUBYCOMMONDIR = $(sitedir)$(target_prefix) RUBYLIBDIR = $(sitelibdir)$(target_prefix) RUBYARCHDIR = $(sitearchdir)$(target_prefix) HDRDIR = $(rubyhdrdir)/ruby$(target_prefix) ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix) TARGET_SO_DIR = TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) CLEANLIBS = $(TARGET_SO) CLEANOBJS = *.o *.bak all: $(DLLIB) static: $(STATIC_LIB) .PHONY: all install static install-so install-rb .PHONY: clean clean-so clean-static clean-rb clean-static:: clean-rb-default:: clean-rb:: clean-so:: clean: clean-so clean-static clean-rb-default clean-rb -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time distclean-rb-default:: distclean-rb:: distclean-so:: distclean-static:: distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true realclean: distclean install: install-so install-rb install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.time $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) clean-static:: -$(Q)$(RM) $(STATIC_LIB) install-rb: pre-install-rb do-install-rb install-rb-default install-rb-default: pre-install-rb-default do-install-rb-default pre-install-rb: Makefile pre-install-rb-default: Makefile do-install-rb: do-install-rb-default: pre-install-rb-default: @$(NULLCMD) $(TIMESTAMP_DIR)/.sitearchdir.time: $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) $(Q) $(TOUCH) $@ site-install: site-install-so site-install-rb site-install-so: install-so site-install-rb: install-rb .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S .cc.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cc.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .mm.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .mm.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .cxx.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cxx.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .cpp.o: $(ECHO) compiling $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .cpp.S: $(ECHO) translating $(<) $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .c.o: $(ECHO) compiling $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .c.S: $(ECHO) translating $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< .m.o: $(ECHO) compiling $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< .m.S: $(ECHO) translating $(<) $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< $(TARGET_SO): $(OBJS) Makefile $(ECHO) linking shared-object $(DLLIB) -$(Q)$(RM) $(@) $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) $(OBJS): $(HDRS) $(ruby_headers) PKu] 3O8aa#ruby-lsapi-5.6/ext/lsapi/lsapilib.cnu[//#define LSAPI_DEBUG /* Copyright (c) 2002-2018, Lite Speed Technologies Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Lite Speed Technologies Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lsapilib.h" #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #include #endif #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #include #endif #include #ifndef uint32 #define uint32 uint32_t #endif struct lsapi_MD5Context { uint32 buf[4]; uint32 bits[2]; unsigned char in[64]; }; void lsapi_MD5Init(struct lsapi_MD5Context *context); void lsapi_MD5Update(struct lsapi_MD5Context *context, unsigned char const *buf, unsigned len); void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *context); /* * This is needed to make RSAREF happy on some MS-DOS compilers. */ typedef struct lsapi_MD5Context lsapi_MD5_CTX; #define LSAPI_ST_REQ_HEADER 1 #define LSAPI_ST_REQ_BODY 2 #define LSAPI_ST_RESP_HEADER 4 #define LSAPI_ST_RESP_BODY 8 #define LSAPI_ST_BACKGROUND 16 #define LSAPI_RESP_BUF_SIZE 8192 #define LSAPI_INIT_RESP_HEADER_LEN 4096 enum { LSAPI_STATE_IDLE, LSAPI_STATE_CONNECTED, LSAPI_STATE_ACCEPTING, }; typedef struct lsapi_child_status { int m_pid; long m_tmStart; volatile short m_iKillSent; volatile char m_inProcess; volatile char m_state; volatile int m_iReqCounter; volatile long m_tmWaitBegin; volatile long m_tmReqBegin; volatile long m_tmLastCheckPoint; } lsapi_child_status; static lsapi_child_status * s_worker_status = NULL; static int g_inited = 0; static int g_running = 1; static int s_ppid; static int s_restored_ppid = 0; static int s_pid = 0; static int s_slow_req_msecs = 0; static int s_keep_listener = 1; static int s_dump_debug_info = 0; static int s_pid_dump_debug_info = 0; static int s_req_processed = 0; static int s_skip_write = 0; static int (*pthread_atfork_func)(void (*prepare)(void), void (*parent)(void), void (*child)(void)) = NULL; static int *s_busy_workers = NULL; static int *s_accepting_workers = NULL; static int *s_global_counter = &s_req_processed; static int s_max_busy_workers = -1; static char *s_stderr_log_path = NULL; static int s_stderr_is_pipe = 0; static int s_ignore_pid = -1; static size_t s_total_pages = 1; static size_t s_min_avail_pages = 256 * 1024; static size_t *s_avail_pages = &s_total_pages; LSAPI_Request g_req = { .m_fdListen = -1, .m_fd = -1 }; static char s_secret[24]; static LSAPI_On_Timer_pf s_proc_group_timer_cb = NULL; void Flush_RespBuf_r( LSAPI_Request * pReq ); static int lsapi_reopen_stderr(const char *p); static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] = { "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHORIZATION", "HTTP_CONNECTION", "CONTENT_TYPE", "CONTENT_LENGTH", "HTTP_COOKIE", "HTTP_COOKIE2", "HTTP_HOST", "HTTP_PRAGMA", "HTTP_REFERER", "HTTP_USER_AGENT", "HTTP_CACHE_CONTROL", "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH", "HTTP_IF_NONE_MATCH", "HTTP_IF_RANGE", "HTTP_IF_UNMODIFIED_SINCE", "HTTP_KEEP_ALIVE", "HTTP_RANGE", "HTTP_X_FORWARDED_FOR", "HTTP_VIA", "HTTP_TRANSFER_ENCODING" }; static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] = { 11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18, 22, 13, 18, 13, 24, 15, 10, 20, 8, 22 }; static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] = { "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Authorization", "Connection", "Content-Type", "Content-Length", "Cookie", "Cookie2", "Host", "Pragma", "Referer", "User-Agent", "Cache-Control", "If-Modified-Since", "If-Match", "If-None-Match", "If-Range", "If-Unmodified-Since", "Keep-Alive", "Range", "X-Forwarded-For", "Via", "Transfer-Encoding" }; static int HTTP_HEADER_LEN[H_TRANSFER_ENCODING+1] = { 6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, //user-agent 13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17 }; static const char *s_log_level_names[8] = { "", "DEBUG","INFO", "NOTICE", "WARN", "ERROR", "CRIT", "FATAL" }; void LSAPI_Log(int flag, const char * fmt, ...) { char buf[1024]; char *p = buf; if ((flag & LSAPI_LOG_TIMESTAMP_BITS) && !(s_stderr_is_pipe)) { struct timeval tv; struct tm tm; gettimeofday(&tv, NULL); localtime_r(&tv.tv_sec, &tm); if (flag & LSAPI_LOG_TIMESTAMP_FULL) { p += snprintf(p, 1024, "%04d-%02d-%02d %02d:%02d:%02d.%06d ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)tv.tv_usec); } else if (flag & LSAPI_LOG_TIMESTAMP_HMS) { p += snprintf(p, 1024, "%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec); } } int level = flag & LSAPI_LOG_LEVEL_BITS; if (level && level <= LSAPI_LOG_FLAG_FATAL) { p += snprintf(p, 100, "[%s] ", s_log_level_names[level]); } if (flag & LSAPI_LOG_PID) { p += snprintf(p, 100, "[UID:%d][%d] ", getuid(), s_pid); } if (p > buf) fprintf(stderr, "%.*s", (int)(p - buf), buf); va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #ifdef LSAPI_DEBUG #define DBGLOG_FLAG (LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_FLAG_DEBUG|LSAPI_LOG_PID) #define lsapi_dbg(...) LSAPI_Log(DBGLOG_FLAG, __VA_ARGS__) #else #define lsapi_dbg(...) #endif #define lsapi_log(...) LSAPI_Log(LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_PID, __VA_ARGS__) void lsapi_perror(const char * pMessage, int err_no) { lsapi_log("%s, errno: %d (%s)\n", pMessage, err_no, strerror(err_no)); } static int lsapi_parent_dead() { // Return non-zero if the parent is dead. 0 if still alive. if (!s_ppid) { // not checking, so not dead return(0); } if (s_restored_ppid) { if (kill(s_restored_ppid,0) == -1) { if (errno == EPERM) { return(0); // no permission, but it's still there. } return(1); // Dead } return(0); // it worked, so it's not dead } return(s_ppid != getppid()); } static void lsapi_sigpipe( int sig ) { } static void lsapi_siguser1( int sig ) { g_running = 0; } #ifndef sighandler_t typedef void (*sighandler_t)(int); #endif static void lsapi_signal(int signo, sighandler_t handler) { struct sigaction sa; sigaction(signo, NULL, &sa); if (sa.sa_handler == SIG_DFL) { sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; sigaction(signo, &sa, NULL); } } static int s_enable_core_dump = 0; static void lsapi_enable_core_dump(void) { #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) int mib[2]; size_t len; #if !defined(__OpenBSD__) len = 2; if ( sysctlnametomib("kern.sugid_coredump", mib, &len) == 0 ) { len = sizeof(s_enable_core_dump); if (sysctl(mib, 2, NULL, 0, &s_enable_core_dump, len) == -1) perror( "sysctl: Failed to set 'kern.sugid_coredump', " "core dump may not be available!"); } #else int set = 3; len = sizeof(set); mib[0] = CTL_KERN; mib[1] = KERN_NOSUIDCOREDUMP; if (sysctl(mib, 2, NULL, 0, &set, len) == 0) { s_enable_core_dump = 1; } #endif #endif #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if (prctl(PR_SET_DUMPABLE, s_enable_core_dump,0,0,0) == -1) perror( "prctl: Failed to set dumpable, " "core dump may not be available!"); #endif } static inline void lsapi_buildPacketHeader( struct lsapi_packet_header * pHeader, char type, int len ) { pHeader->m_versionB0 = LSAPI_VERSION_B0; /* LSAPI protocol version */ pHeader->m_versionB1 = LSAPI_VERSION_B1; pHeader->m_type = type; pHeader->m_flag = LSAPI_ENDIAN; pHeader->m_packetLen.m_iLen = len; } static int lsapi_set_nblock( int fd, int nonblock ) { int val = fcntl( fd, F_GETFL, 0 ); if ( nonblock ) { if (!( val & O_NONBLOCK )) { return fcntl( fd, F_SETFL, val | O_NONBLOCK ); } } else { if ( val & O_NONBLOCK ) { return fcntl( fd, F_SETFL, val &(~O_NONBLOCK) ); } } return 0; } static int lsapi_close( int fd ) { int ret; while( 1 ) { ret = close( fd ); if (( ret == -1 )&&( errno == EINTR )&&(g_running)) continue; return ret; } } static void lsapi_close_connection(LSAPI_Request *pReq) { if (pReq->m_fd == -1) return; lsapi_close(pReq->m_fd); pReq->m_fd = -1; if (s_busy_workers) __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST); if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_IDLE, __ATOMIC_SEQ_CST); } static inline ssize_t lsapi_read( int fd, void * pBuf, size_t len ) { ssize_t ret; while( 1 ) { ret = read( fd, (char *)pBuf, len ); if (( ret == -1 )&&( errno == EINTR )&&(g_running)) continue; return ret; } } /* static int lsapi_write( int fd, const void * pBuf, int len ) { int ret; const char * pCur; const char * pEnd; if ( len == 0 ) return 0; pCur = (const char *)pBuf; pEnd = pCur + len; while( g_running && (pCur < pEnd) ) { ret = write( fd, pCur, pEnd - pCur ); if ( ret >= 0) pCur += ret; else if (( ret == -1 )&&( errno != EINTR )) return ret; } return pCur - (const char *)pBuf; } */ static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen ) { int ret; int left = totalLen; int n = count; if (s_skip_write) return totalLen; while(( left > 0 )&&g_running ) { ret = writev( fd, *pVec, n ); if ( ret > 0 ) { left -= ret; if (( left <= 0)||( !g_running )) return totalLen - left; while( ret > 0 ) { if ( (*pVec)->iov_len <= (unsigned int )ret ) { ret -= (*pVec)->iov_len; ++(*pVec); } else { (*pVec)->iov_base = (char *)(*pVec)->iov_base + ret; (*pVec)->iov_len -= ret; break; } } } else if ( ret == -1 ) { if ( errno == EAGAIN ) { if ( totalLen - left > 0 ) return totalLen - left; else return -1; } else if ( errno != EINTR ) return ret; } } return totalLen - left; } /* static int getTotalLen( struct iovec * pVec, int count ) { struct iovec * pEnd = pVec + count; int total = 0; while( pVec < pEnd ) { total += pVec->iov_len; ++pVec; } return total; } */ static inline int allocateBuf( LSAPI_Request * pReq, int size ) { char * pBuf = (char *)realloc( pReq->m_pReqBuf, size ); if ( pBuf ) { pReq->m_pReqBuf = pBuf; pReq->m_reqBufSize = size; pReq->m_pHeader = (struct lsapi_req_header *)pReq->m_pReqBuf; return 0; } return -1; } static int allocateIovec( LSAPI_Request * pReq, int n ) { struct iovec * p = (struct iovec *)realloc( pReq->m_pIovec, sizeof(struct iovec) * n ); if ( !p ) return -1; pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec ); pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec ); pReq->m_pIovec = p; pReq->m_pIovecEnd = p + n; return 0; } static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size ) { char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size ); if ( !p ) return -1; pReq->m_pRespHeaderBufPos = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf ); pReq->m_pRespHeaderBuf = p; pReq->m_pRespHeaderBufEnd = p + size; return 0; } static inline int verifyHeader( struct lsapi_packet_header * pHeader, char pktType ) { if (( LSAPI_VERSION_B0 != pHeader->m_versionB0 )|| ( LSAPI_VERSION_B1 != pHeader->m_versionB1 )|| ( pktType != pHeader->m_type )) return -1; if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT )) { register char b; b = pHeader->m_packetLen.m_bytes[0]; pHeader->m_packetLen.m_bytes[0] = pHeader->m_packetLen.m_bytes[3]; pHeader->m_packetLen.m_bytes[3] = b; b = pHeader->m_packetLen.m_bytes[1]; pHeader->m_packetLen.m_bytes[1] = pHeader->m_packetLen.m_bytes[2]; pHeader->m_packetLen.m_bytes[2] = b; } return pHeader->m_packetLen.m_iLen; } static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList, int *curSize, int newSize ) { struct LSAPI_key_value_pair * pBuf; if ( *curSize >= newSize ) return 0; if ( newSize > 8192 ) return -1; pBuf = (struct LSAPI_key_value_pair *)realloc( *pEnvList, newSize * sizeof(struct LSAPI_key_value_pair) ); if ( pBuf ) { *pEnvList = pBuf; *curSize = newSize; return 0; } else return -1; } static inline int isPipe( int fd ) { char achPeer[128]; socklen_t len = 128; if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&& ( errno == ENOTCONN )) return 0; else return 1; } static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count, char **pBegin, char * pEnd ) { struct LSAPI_key_value_pair * pEnvEnd; int keyLen = 0, valLen = 0; if ( count > 8192 ) return -1; pEnvEnd = pEnvList + count; while( pEnvList != pEnvEnd ) { if ( pEnd - *pBegin < 4 ) return -1; keyLen = *((unsigned char *)((*pBegin)++)); keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++)); valLen = *((unsigned char *)((*pBegin)++)); valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++)); if ( *pBegin + keyLen + valLen > pEnd ) return -1; if (( !keyLen )||( !valLen )) return -1; pEnvList->pKey = *pBegin; *pBegin += keyLen; pEnvList->pValue = *pBegin; *pBegin += valLen; pEnvList->keyLen = keyLen - 1; pEnvList->valLen = valLen - 1; ++pEnvList; } if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 ) return -1; *pBegin += 4; return 0; } static inline void swapIntEndian( int * pInteger ) { char * p = (char *)pInteger; register char b; b = p[0]; p[0] = p[3]; p[3] = b; b = p[1]; p[1] = p[2]; p[2] = b; } static inline void fixEndian( LSAPI_Request * pReq ) { struct lsapi_req_header *p= pReq->m_pHeader; swapIntEndian( &p->m_httpHeaderLen ); swapIntEndian( &p->m_reqBodyLen ); swapIntEndian( &p->m_scriptFileOff ); swapIntEndian( &p->m_scriptNameOff ); swapIntEndian( &p->m_queryStringOff ); swapIntEndian( &p->m_requestMethodOff ); swapIntEndian( &p->m_cntUnknownHeaders ); swapIntEndian( &p->m_cntEnv ); swapIntEndian( &p->m_cntSpecialEnv ); } static void fixHeaderIndexEndian( LSAPI_Request * pReq ) { int i; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { register char b; char * p = (char *)(&pReq->m_pHeaderIndex->m_headerLen[i]); b = p[0]; p[0] = p[1]; p[1] = b; swapIntEndian( &pReq->m_pHeaderIndex->m_headerOff[i] ); } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { swapIntEndian( &pCur->nameOff ); swapIntEndian( &pCur->nameLen ); swapIntEndian( &pCur->valueOff ); swapIntEndian( &pCur->valueLen ); ++pCur; } } } static int validateHeaders( LSAPI_Request * pReq ) { int totalLen = pReq->m_pHeader->m_httpHeaderLen; int i; for(i = 0; i < H_TRANSFER_ENCODING; ++i) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { if (pReq->m_pHeaderIndex->m_headerOff[i] > totalLen || pReq->m_pHeaderIndex->m_headerLen[i] + pReq->m_pHeaderIndex->m_headerOff[i] > totalLen) return -1; } } if (pReq->m_pHeader->m_cntUnknownHeaders > 0) { struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { if (pCur->nameOff > totalLen || pCur->nameOff + pCur->nameLen > totalLen || pCur->valueOff > totalLen || pCur->valueOff + pCur->valueLen > totalLen) return -1; ++pCur; } } return 0; } static uid_t s_uid = 0; static uid_t s_defaultUid; //web server need set this static gid_t s_defaultGid; #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #define LSAPI_LVE_DISABLED 0 #define LSAPI_LVE_ENABLED 1 #define LSAPI_CAGEFS_ENABLED 2 #define LSAPI_CAGEFS_NO_SUEXEC 3 struct liblve; static int s_enable_lve = LSAPI_LVE_DISABLED; static struct liblve * s_lve = NULL; static void *s_liblve; static int (*fp_lve_is_available)(void) = NULL; static int (*fp_lve_instance_init)(struct liblve *) = NULL; static int (*fp_lve_destroy)(struct liblve *) = NULL; static int (*fp_lve_enter)(struct liblve *, uint32_t, int32_t, int32_t, uint32_t *) = NULL; static int (*fp_lve_leave)(struct liblve *, uint32_t *) = NULL; static int (*fp_lve_jail)( struct passwd *, char *) = NULL; static int lsapi_load_lve_lib(void) { s_liblve = dlopen("liblve.so.0", RTLD_NOW | RTLD_GLOBAL); if (s_liblve) { fp_lve_is_available = dlsym(s_liblve, "lve_is_available"); if (dlerror() == NULL) { if ( !(*fp_lve_is_available)() ) { int uid = getuid(); if ( uid ) { if (setreuid( s_uid, uid )) {}; if ( !(*fp_lve_is_available)() ) s_enable_lve = 0; if (setreuid( uid, s_uid )) {}; } } } } else { s_enable_lve = LSAPI_LVE_DISABLED; } return (s_liblve)? 0 : -1; } static int init_lve_ex(void) { int rc; if ( !s_liblve ) return -1; fp_lve_instance_init = dlsym(s_liblve, "lve_instance_init"); fp_lve_destroy = dlsym(s_liblve, "lve_destroy"); fp_lve_enter = dlsym(s_liblve, "lve_enter"); fp_lve_leave = dlsym(s_liblve, "lve_leave"); if ( s_enable_lve >= LSAPI_CAGEFS_ENABLED ) fp_lve_jail = dlsym(s_liblve, "jail" ); if ( s_lve == NULL ) { rc = (*fp_lve_instance_init)(NULL); s_lve = malloc(rc); } rc = (*fp_lve_instance_init)(s_lve); if (rc != 0) { perror( "LSAPI: Unable to initialize LVE" ); free( s_lve ); s_lve = NULL; return -1; } return 0; } #endif static int readSecret( const char * pSecretFile ) { struct stat st; int fd = open( pSecretFile, O_RDONLY , 0600 ); if ( fd == -1 ) { lsapi_log("LSAPI: failed to open secret file: %s!\n", pSecretFile ); return -1; } if ( fstat( fd, &st ) == -1 ) { lsapi_log("LSAPI: failed to check state of file: %s!\n", pSecretFile ); close( fd ); return -1; } /* if ( st.st_uid != s_uid ) { lsapi_log("LSAPI: file owner check failure: %s!\n", pSecretFile ); close( fd ); return -1; } */ if ( st.st_mode & 0077 ) { lsapi_log("LSAPI: file permission check failure: %s\n", pSecretFile ); close( fd ); return -1; } if ( read( fd, s_secret, 16 ) < 16 ) { lsapi_log("LSAPI: failed to read secret from secret file: %s\n", pSecretFile ); close( fd ); return -1; } close( fd ); return 0; } int LSAPI_is_suEXEC_Daemon(void) { if (( !s_uid )&&( s_secret[0] )) return 1; else return 0; } static int LSAPI_perror_r( LSAPI_Request * pReq, const char * pErr1, const char *pErr2 ) { char achError[4096]; int n = snprintf(achError, sizeof(achError), "[UID:%d][%d] %s:%s: %s\n", getuid(), getpid(), pErr1, (pErr2)?pErr2:"", strerror(errno)); if (n > (int)sizeof(achError)) n = sizeof(achError); if ( pReq ) LSAPI_Write_Stderr_r( pReq, achError, n ); else if (write( STDERR_FILENO, achError, n )) {}; return 0; } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) static int lsapi_lve_error( LSAPI_Request * pReq ) { static const char * headers[] = { "Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0", "Pragma: no-cache", "Retry-After: 60", "Content-Type: text/html", NULL }; static const char achBody[] = "\n" "\n508 Resource Limit Is Reached\n" "\n" "

    Resource Limit Is Reached

    \n" "The website is temporarily unable to service your request as it exceeded resource limit.\n" "Please try again later.\n" "
    \n" "\n"; LSAPI_ErrResponse_r( pReq, 508, headers, achBody, sizeof( achBody ) - 1 ); return 0; } static int lsapi_enterLVE( LSAPI_Request * pReq, uid_t uid ) { if ( s_lve && uid ) //root user should not do that { uint32_t cookie; int ret = -1; ret = (*fp_lve_enter)(s_lve, uid, -1, -1, &cookie); if ( ret < 0 ) { //lsapi_log("enter LVE (%d) : result: %d !\n", uid, ret ); LSAPI_perror_r(pReq, "LSAPI: lve_enter() failure, reached resource limit.", NULL ); lsapi_lve_error( pReq ); return -1; } } return 0; } static int lsapi_jailLVE( LSAPI_Request * pReq, uid_t uid, struct passwd * pw ) { int ret = 0; char error_msg[1024] = ""; ret = (*fp_lve_jail)( pw, error_msg ); if ( ret < 0 ) { lsapi_log("LSAPI: LVE jail(%d) result: %d, error: %s !\n", uid, ret, error_msg ); LSAPI_perror_r( pReq, "LSAPI: jail() failure.", NULL ); return -1; } return ret; } static int lsapi_initLVE(void) { const char * pEnv; if ( (pEnv = getenv( "LSAPI_LVE_ENABLE" ))!= NULL ) { s_enable_lve = atol( pEnv ); pEnv = NULL; } else if ( (pEnv = getenv( "LVE_ENABLE" ))!= NULL ) { s_enable_lve = atol( pEnv ); pEnv = NULL; } if ( s_enable_lve && !s_uid ) { lsapi_load_lve_lib(); if ( s_enable_lve ) { return init_lve_ex(); } } return 0; } #endif static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * pChroot) { int rv; struct passwd * pw; pw = getpwuid( uid ); #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if ( s_lve ) { if( lsapi_enterLVE( pReq, uid ) == -1 ) return -1; if ( pw && fp_lve_jail) { rv = lsapi_jailLVE( pReq, uid, pw ); if ( rv == -1 ) return -1; if (( rv == 1 )&&(s_enable_lve == LSAPI_CAGEFS_NO_SUEXEC )) //this mode only use cageFS, does not use suEXEC { uid = s_defaultUid; gid = s_defaultGid; pw = getpwuid( uid ); } } } #endif //if ( !uid || !gid ) //do not allow root //{ // return -1; //} #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) if ( s_enable_core_dump ) lsapi_enable_core_dump(); #endif rv = setgid(gid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setgid()", NULL); return -1; } if ( pw && (pw->pw_gid == gid )) { rv = initgroups( pw->pw_name, gid ); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: initgroups()", NULL); return -1; } } else { rv = setgroups(1, &gid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setgroups()", NULL); } } if ( pChroot ) { rv = chroot( pChroot ); if ( rv == -1 ) { LSAPI_perror_r(pReq, "LSAPI: chroot()", NULL); return -1; } } rv = setuid(uid); if (rv == -1) { LSAPI_perror_r(pReq, "LSAPI: setuid()", NULL); return -1; } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) if ( s_enable_core_dump ) lsapi_enable_core_dump(); #endif return 0; } static int lsapi_suexec_auth( LSAPI_Request *pReq, char * pAuth, int len, char * pUgid, int ugidLen ) { lsapi_MD5_CTX md5ctx; unsigned char achMD5[16]; if ( len < 32 ) return -1; memmove( achMD5, pAuth + 16, 16 ); memmove( pAuth + 16, s_secret, 16 ); lsapi_MD5Init( &md5ctx ); lsapi_MD5Update( &md5ctx, (unsigned char *)pAuth, 32 ); lsapi_MD5Update( &md5ctx, (unsigned char *)pUgid, 8 ); lsapi_MD5Final( (unsigned char *)pAuth + 16, &md5ctx); if ( memcmp( achMD5, pAuth + 16, 16 ) == 0 ) return 0; return 1; } static int lsapi_changeUGid( LSAPI_Request * pReq ) { int uid = s_defaultUid; int gid = s_defaultGid; const char *pStderrLog; const char *pChroot = NULL; struct LSAPI_key_value_pair * pEnv; struct LSAPI_key_value_pair * pAuth; int i; if ( s_uid ) return 0; //with special ID 0x00 //authenticate the suEXEC request; //first one should be MD5( nonce + lscgid secret ) //remember to clear the secret after verification //it should be set at the end of special env i = pReq->m_pHeader->m_cntSpecialEnv - 1; if ( i >= 0 ) { pEnv = pReq->m_pSpecialEnvList + i; if (( *pEnv->pKey == '\000' )&& ( strcmp( pEnv->pKey+1, "SUEXEC_AUTH" ) == 0 )) { --pReq->m_pHeader->m_cntSpecialEnv; pAuth = pEnv--; if (( *pEnv->pKey == '\000' )&& ( strcmp( pEnv->pKey+1, "SUEXEC_UGID" ) == 0 )) { --pReq->m_pHeader->m_cntSpecialEnv; uid = *(uint32_t *)pEnv->pValue; gid = *(((uint32_t *)pEnv->pValue) + 1 ); //lsapi_log("LSAPI: SUEXEC_UGID set UID: %d, GID: %d\n", uid, gid ); } else { lsapi_log("LSAPI: missing SUEXEC_UGID env, use default user!\n" ); pEnv = NULL; } if ( pEnv&& lsapi_suexec_auth( pReq, pAuth->pValue, pAuth->valLen, pEnv->pValue, pEnv->valLen ) == 0 ) { //read UID, GID from specialEnv } else { //authentication error lsapi_log("LSAPI: SUEXEC_AUTH authentication failed, use default user!\n" ); uid = 0; } } else { //lsapi_log("LSAPI: no SUEXEC_AUTH env, use default user!\n" ); } } if ( !uid ) { uid = s_defaultUid; gid = s_defaultGid; } //change uid if ( setUID_LVE( pReq, uid, gid, pChroot ) == -1 ) { return -1; } s_uid = uid; if ( pReq->m_fdListen != -1 ) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } pStderrLog = LSAPI_GetEnv_r( pReq, "LSAPI_STDERR_LOG"); if (pStderrLog) lsapi_reopen_stderr(pStderrLog); return 0; } static int parseContentLenFromHeader(LSAPI_Request * pReq) { const char * pContentLen = LSAPI_GetHeader_r( pReq, H_CONTENT_LENGTH ); if ( pContentLen ) pReq->m_reqBodyLen = strtoll( pContentLen, NULL, 10 ); return 0; } static int parseRequest( LSAPI_Request * pReq, int totalLen ) { int shouldFixEndian; char * pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header ); char * pEnd = pReq->m_pReqBuf + totalLen; shouldFixEndian = ( LSAPI_ENDIAN != ( pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) ); if ( shouldFixEndian ) { fixEndian( pReq ); } if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&& allocateEnvList( &pReq->m_pSpecialEnvList, &pReq->m_specialEnvListSize, pReq->m_pHeader->m_cntSpecialEnv ) == -1 ) return -1; if ( (pReq->m_envListSize < pReq->m_pHeader->m_cntEnv )&& allocateEnvList( &pReq->m_pEnvList, &pReq->m_envListSize, pReq->m_pHeader->m_cntEnv ) == -1 ) return -1; if ( parseEnv( pReq->m_pSpecialEnvList, pReq->m_pHeader->m_cntSpecialEnv, &pBegin, pEnd ) == -1 ) return -1; if ( parseEnv( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, &pBegin, pEnd ) == -1 ) return -1; if (pReq->m_pHeader->m_scriptFileOff < 0 || pReq->m_pHeader->m_scriptFileOff >= totalLen || pReq->m_pHeader->m_scriptNameOff < 0 || pReq->m_pHeader->m_scriptNameOff >= totalLen || pReq->m_pHeader->m_queryStringOff < 0 || pReq->m_pHeader->m_queryStringOff >= totalLen || pReq->m_pHeader->m_requestMethodOff < 0 || pReq->m_pHeader->m_requestMethodOff >= totalLen) { lsapi_log("Bad request header - ERROR#1\n"); return -1; } pReq->m_pScriptFile = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptFileOff; pReq->m_pScriptName = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff; pReq->m_pQueryString = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff; pReq->m_pRequestMethod = pReq->m_pReqBuf + pReq->m_pHeader->m_requestMethodOff; pBegin = pReq->m_pReqBuf + (( pBegin - pReq->m_pReqBuf + 7 ) & (~0x7)); pReq->m_pHeaderIndex = ( struct lsapi_http_header_index * )pBegin; pBegin += sizeof( struct lsapi_http_header_index ); pReq->m_pUnknownHeader = (struct lsapi_header_offset *)pBegin; pBegin += sizeof( struct lsapi_header_offset) * pReq->m_pHeader->m_cntUnknownHeaders; pReq->m_pHttpHeader = pBegin; pBegin += pReq->m_pHeader->m_httpHeaderLen; if ( pBegin != pEnd ) { lsapi_log("Request header does match total size, total: %d, " "real: %ld\n", totalLen, pBegin - pReq->m_pReqBuf ); return -1; } if ( shouldFixEndian ) { fixHeaderIndexEndian( pReq ); } if (validateHeaders(pReq) == -1) { lsapi_log("Bad request header - ERROR#2\n"); return -1; } pReq->m_reqBodyLen = pReq->m_pHeader->m_reqBodyLen; if ( pReq->m_reqBodyLen == -2 ) { parseContentLenFromHeader(pReq); } return 0; } //OPTIMIZATION static char s_accept_notify = 0; static char s_schedule_notify = 0; static char s_notify_scheduled = 0; static char s_notified_pid = 0; static struct lsapi_packet_header s_ack = {'L', 'S', LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; static struct lsapi_packet_header s_conn_close_pkt = {'L', 'S', LSAPI_CONN_CLOSE, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; static inline int send_notification_pkt( int fd, struct lsapi_packet_header *pkt ) { if ( write( fd, pkt, LSAPI_PACKET_HEADER_LEN ) < LSAPI_PACKET_HEADER_LEN ) return -1; return 0; } static inline int send_req_received_notification( int fd ) { return send_notification_pkt(fd, &s_ack); } static inline int send_conn_close_notification( int fd ) { return send_notification_pkt(fd, &s_conn_close_pkt); } //static void lsapi_sigalarm( int sig ) //{ // if ( s_notify_scheduled ) // { // s_notify_scheduled = 0; // if ( g_req.m_fd != -1 ) // write_req_received_notification( g_req.m_fd ); // } //} static inline int lsapi_schedule_notify(void) { if ( !s_notify_scheduled ) { alarm( 2 ); s_notify_scheduled = 1; } return 0; } static inline int notify_req_received( int fd ) { if ( s_schedule_notify ) return lsapi_schedule_notify(); return send_req_received_notification( fd ); } static inline int lsapi_notify_pid( int fd ) { char achBuf[16]; lsapi_buildPacketHeader( (struct lsapi_packet_header *)achBuf, LSAPI_STDERR_STREAM, 8 + LSAPI_PACKET_HEADER_LEN ); memmove( &achBuf[8], "\0PID", 4 ); *((int *)&achBuf[12]) = getpid(); if ( write( fd, achBuf, 16 ) < 16 ) return -1; return 0; } static int readReq( LSAPI_Request * pReq ) { int len; int packetLen; if ( !pReq ) return -1; if ( pReq->m_reqBufSize < 8192 ) { if ( allocateBuf( pReq, 8192 ) == -1 ) return -1; } while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN ) { len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize ); if ( len <= 0 ) return -1; pReq->m_bufRead += len; } pReq->m_reqState = LSAPI_ST_REQ_HEADER; packetLen = verifyHeader( &pReq->m_pHeader->m_pktHeader, LSAPI_BEGIN_REQUEST ); if ( packetLen < 0 ) { lsapi_log("packetLen < 0\n"); return -1; } if ( packetLen > LSAPI_MAX_HEADER_LEN ) { lsapi_log("packetLen > %d\n", LSAPI_MAX_HEADER_LEN ); return -1; } if ( packetLen + 1024 > pReq->m_reqBufSize ) { if ( allocateBuf( pReq, packetLen + 1024 ) == -1 ) return -1; } while( packetLen > pReq->m_bufRead ) { len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, packetLen - pReq->m_bufRead ); if ( len <= 0 ) return -1; pReq->m_bufRead += len; } if ( parseRequest( pReq, packetLen ) < 0 ) { lsapi_log("ParseRequest error\n"); return -1; } pReq->m_reqState = LSAPI_ST_REQ_BODY | LSAPI_ST_RESP_HEADER; if ( !s_uid ) { if ( lsapi_changeUGid( pReq ) ) return -1; memset(s_secret, 0, sizeof(s_secret)); } pReq->m_bufProcessed = packetLen; //OPTIMIZATION if ( !s_accept_notify && !s_notified_pid ) return notify_req_received( pReq->m_fd ); else { s_notified_pid = 0; return 0; } } int LSAPI_Init(void) { if ( !g_inited ) { s_uid = geteuid(); s_secret[0] = 0; lsapi_signal(SIGPIPE, lsapi_sigpipe); lsapi_signal(SIGUSR1, lsapi_siguser1); #if defined(SIGXFSZ) && defined(SIG_IGN) signal(SIGXFSZ, SIG_IGN); #endif /* let STDOUT function as STDERR, just in case writing to STDOUT directly */ dup2( 2, 1 ); if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 ) return -1; g_inited = 1; s_ppid = getppid(); void *pthread_lib = dlopen("libpthread.so", RTLD_LAZY); if (pthread_lib) pthread_atfork_func = dlsym(pthread_lib, "pthread_atfork"); } return 0; } void LSAPI_Stop(void) { g_running = 0; } int LSAPI_IsRunning(void) { return g_running; } void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf cb) { s_proc_group_timer_cb = cb; } int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ) { int newfd; if ( !pReq ) return -1; memset( pReq, 0, sizeof( LSAPI_Request ) ); if ( allocateIovec( pReq, 16 ) == -1 ) return -1; pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE ); if ( !pReq->m_pRespBuf ) return -1; pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5]; if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 ) return -1; if ( fd == STDIN_FILENO ) { fd = dup( fd ); newfd = open( "/dev/null", O_RDWR ); dup2( newfd, STDIN_FILENO ); } if ( isPipe( fd ) ) { pReq->m_fdListen = -1; pReq->m_fd = fd; } else { pReq->m_fdListen = fd; pReq->m_fd = -1; lsapi_set_nblock( fd, 1 ); } return 0; } int LSAPI_Is_Listen( void ) { return LSAPI_Is_Listen_r( &g_req ); } int LSAPI_Is_Listen_r( LSAPI_Request * pReq) { return pReq->m_fdListen != -1; } int LSAPI_Accept_r( LSAPI_Request * pReq ) { char achPeer[128]; socklen_t len; int nodelay = 1; if ( !pReq ) return -1; if ( LSAPI_Finish_r( pReq ) == -1 ) return -1; lsapi_set_nblock( pReq->m_fdListen , 0 ); while( g_running ) { if ( pReq->m_fd == -1 ) { if ( pReq->m_fdListen != -1) { len = sizeof( achPeer ); pReq->m_fd = accept( pReq->m_fdListen, (struct sockaddr *)&achPeer, &len ); if ( pReq->m_fd == -1 ) { if (( errno == EINTR )||( errno == EAGAIN)) continue; else return -1; } else { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd , 0 ); if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); } //init_conn_key( pReq->m_fd ); //OPTIMIZATION if ( s_accept_notify ) if ( notify_req_received( pReq->m_fd ) == -1 ) return -1; } } else return -1; } if ( !readReq( pReq ) ) break; //abort(); lsapi_close_connection(pReq); LSAPI_Reset_r( pReq ); } return 0; } static struct lsapi_packet_header finish_close[2] = { {'L', 'S', LSAPI_RESP_END, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }, {'L', 'S', LSAPI_CONN_CLOSE, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} } }; int LSAPI_Finish_r( LSAPI_Request * pReq ) { /* finish req body */ if ( !pReq ) return -1; if (pReq->m_reqState) { if ( pReq->m_fd != -1 ) { if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } pReq->m_pIovecCur->iov_base = (void *)finish_close; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; LSAPI_Flush_r( pReq ); } LSAPI_Reset_r( pReq ); } return 0; } int LSAPI_End_Response_r(LSAPI_Request * pReq) { if (!pReq) return -1; if (pReq->m_reqState & LSAPI_ST_BACKGROUND) return 0; if (pReq->m_reqState) { if ( pReq->m_fd != -1 ) { if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { if ( pReq->m_pRespHeaderBufPos <= pReq->m_pRespHeaderBuf ) return 0; LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } pReq->m_pIovecCur->iov_base = (void *)finish_close; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN << 1; pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN << 1; ++pReq->m_pIovecCur; LSAPI_Flush_r( pReq ); lsapi_close_connection(pReq); } pReq->m_reqState |= LSAPI_ST_BACKGROUND; } return 0; } void LSAPI_Reset_r( LSAPI_Request * pReq ) { pReq->m_pRespBufPos = pReq->m_pRespBuf; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; pReq->m_pRespHeaderBufPos = pReq->m_pRespHeaderBuf; memset( &pReq->m_pHeaderIndex, 0, (char *)(pReq->m_respHeaderLen) - (char *)&pReq->m_pHeaderIndex ); } int LSAPI_Release_r( LSAPI_Request * pReq ) { if ( pReq->m_pReqBuf ) free( pReq->m_pReqBuf ); if ( pReq->m_pSpecialEnvList ) free( pReq->m_pSpecialEnvList ); if ( pReq->m_pEnvList ) free( pReq->m_pEnvList ); if ( pReq->m_pRespHeaderBuf ) free( pReq->m_pRespHeaderBuf ); return 0; } char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ) { int off; if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) ) return NULL; off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ]; if ( !off ) return NULL; if ( *(pReq->m_pHttpHeader + off + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) ) { *( pReq->m_pHttpHeader + off + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0; } return pReq->m_pHttpHeader + off; } static int readBodyToReqBuf( LSAPI_Request * pReq ) { off_t bodyLeft; ssize_t len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len > 0 ) return len; pReq->m_bufRead = pReq->m_bufProcessed = pReq->m_pHeader->m_pktHeader.m_packetLen.m_iLen; bodyLeft = pReq->m_reqBodyLen - pReq->m_reqBodyRead; len = pReq->m_reqBufSize - pReq->m_bufRead; if ( len < 0 ) return -1; if ( len > bodyLeft ) len = bodyLeft; len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, len ); if ( len > 0 ) pReq->m_bufRead += len; return len; } int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ) { if (!pReq || (pReq->m_fd ==-1) ) return EOF; if ( pReq->m_bufProcessed >= pReq->m_bufRead ) { if ( readBodyToReqBuf( pReq ) <= 0 ) return EOF; } ++pReq->m_reqBodyRead; return (unsigned char)*(pReq->m_pReqBuf + pReq->m_bufProcessed++); } int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF ) { ssize_t len; ssize_t left; char * pBufEnd = pBuf + bufLen - 1; char * pBufCur = pBuf; char * pCur; char * p; if (!pReq || pReq->m_fd == -1 || !pBuf || !getLF) return -1; *getLF = 0; while( (left = pBufEnd - pBufCur ) > 0 ) { len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len <= 0 ) { if ( (len = readBodyToReqBuf( pReq )) <= 0 ) { *getLF = 1; break; } } if ( len > left ) len = left; pCur = pReq->m_pReqBuf + pReq->m_bufProcessed; p = memchr( pCur, '\n', len ); if ( p ) len = p - pCur + 1; memmove( pBufCur, pCur, len ); pBufCur += len; pReq->m_bufProcessed += len; pReq->m_reqBodyRead += len; if ( p ) { *getLF = 1; break; } } *pBufCur = 0; return pBufCur - pBuf; } ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen ) { ssize_t len; off_t total; /* char *pOldBuf = pBuf; */ if (!pReq || pReq->m_fd == -1 || !pBuf || (ssize_t)bufLen < 0) return -1; total = pReq->m_reqBodyLen - pReq->m_reqBodyRead; if ( total <= 0 ) return 0; if ( total < (ssize_t)bufLen ) bufLen = total; total = 0; len = pReq->m_bufRead - pReq->m_bufProcessed; if ( len > 0 ) { if ( len > (ssize_t)bufLen ) len = bufLen; memmove( pBuf, pReq->m_pReqBuf + pReq->m_bufProcessed, len ); pReq->m_bufProcessed += len; total += len; pBuf += len; bufLen -= len; } while( bufLen > 0 ) { len = lsapi_read( pReq->m_fd, pBuf, bufLen ); if ( len > 0 ) { total += len; pBuf += len; bufLen -= len; } else if ( len <= 0 ) { if ( !total) return -1; break; } } pReq->m_reqBodyRead += total; return total; } ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len ) { struct lsapi_packet_header * pHeader; const char * pEnd; const char * p; ssize_t bufLen; ssize_t toWrite; ssize_t packetLen; int skip = 0; if (!pReq || !pBuf) return -1; if (pReq->m_reqState & LSAPI_ST_BACKGROUND) return len; if (pReq->m_fd == -1) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); /* if ( *pBuf == '\r' ) { ++skip; } if ( *pBuf == '\n' ) { ++skip; } */ } pReq->m_reqState |= LSAPI_ST_RESP_BODY; if ( ((ssize_t)len - skip) < pReq->m_pRespBufEnd - pReq->m_pRespBufPos ) { memmove( pReq->m_pRespBufPos, pBuf + skip, len - skip ); pReq->m_pRespBufPos += len - skip; return len; } pHeader = pReq->m_respPktHeader; p = pBuf + skip; pEnd = pBuf + len; bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; while( ( toWrite = pEnd - p ) > 0 ) { packetLen = toWrite + bufLen; if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { packetLen = LSAPI_MAX_DATA_PACKET_LEN; toWrite = packetLen - bufLen; } lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, packetLen + LSAPI_PACKET_HEADER_LEN ); pReq->m_totalLen += packetLen + LSAPI_PACKET_HEADER_LEN; pReq->m_pIovecCur->iov_base = (void *)pHeader; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; ++pHeader; if ( bufLen > 0 ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; pReq->m_pIovecCur->iov_len = bufLen; pReq->m_pRespBufPos = pReq->m_pRespBuf; ++pReq->m_pIovecCur; bufLen = 0; } pReq->m_pIovecCur->iov_base = (void *)p; pReq->m_pIovecCur->iov_len = toWrite; ++pReq->m_pIovecCur; p += toWrite; if ( pHeader >= pReq->m_respPktHeaderEnd - 1) { if ( LSAPI_Flush_r( pReq ) == -1 ) return -1; pHeader = pReq->m_respPktHeader; } } if ( pHeader != pReq->m_respPktHeader ) if ( LSAPI_Flush_r( pReq ) == -1 ) return -1; return p - pBuf; } #if defined(__FreeBSD__ ) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t written; ret = sendfile( fdIn, fdOut, *off, size, NULL, &written, 0 ); if ( written > 0 ) { ret = written; *off += ret; } return ret; } #endif #if defined(__OpenBSD__) || defined(__NetBSD__) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t written = 0; const size_t bufsiz = 16384; unsigned char in[bufsiz] = {0}; if (lseek(fdIn, *off, SEEK_SET) == -1) { return -1; } while (size > 0) { size_t tor = size > sizeof(in) ? sizeof(in) : size; ssize_t c = read(fdIn, in, tor); if (c <= 0) { goto end; } ssize_t w = write(fdOut, in, c); if (w > 0) written += w; if (w != c) { goto end; } size -= c; } end: *off += written; return 0; } #endif #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size ) { ssize_t ret; off_t len = size; ret = sendfile( fdIn, fdOut, *off, &len, NULL, 0 ); if (( ret == 0 )&&( len > 0 )) { ret = len; *off += len; } return ret; } #endif #if defined(sun) || defined(__sun) #include ssize_t gsendfile( int fdOut, int fdIn, off_t *off, size_t size ) { int n = 0 ; sendfilevec_t vec[1]; vec[n].sfv_fd = fdIn; vec[n].sfv_flag = 0; vec[n].sfv_off = *off; vec[n].sfv_len = size; ++n; size_t written; ssize_t ret = sendfilev( fdOut, vec, n, &written ); if (( !ret )||( errno == EAGAIN )) ret = written; if ( ret > 0 ) *off += ret; return ret; } #endif #if defined(linux) || defined(__linux) || defined(__linux__) || \ defined(__gnu_linux__) #include #define gsendfile sendfile #endif #if defined(HPUX) ssize_t gsendfile( int fdOut, int fdIn, off_t * off, size_t size ) { return sendfile( fdOut, fdIn, off, size, NULL, 0 ); } #endif ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size ) { struct lsapi_packet_header * pHeader = pReq->m_respPktHeader; if ( !pReq || (pReq->m_fd == -1) || fdIn == -1 ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } pReq->m_reqState |= LSAPI_ST_RESP_BODY; LSAPI_Flush_r(pReq); lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, size + LSAPI_PACKET_HEADER_LEN ); if (write(pReq->m_fd, (const char *) pHeader, LSAPI_PACKET_HEADER_LEN ) != LSAPI_PACKET_HEADER_LEN) return -1; return gsendfile( pReq->m_fd, fdIn, off, size ); } void Flush_RespBuf_r( LSAPI_Request * pReq ) { struct lsapi_packet_header * pHeader = pReq->m_respPktHeader; int bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; pReq->m_reqState |= LSAPI_ST_RESP_BODY; lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, bufLen + LSAPI_PACKET_HEADER_LEN ); pReq->m_totalLen += bufLen + LSAPI_PACKET_HEADER_LEN; pReq->m_pIovecCur->iov_base = (void *)pHeader; pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; ++pReq->m_pIovecCur; ++pHeader; if ( bufLen > 0 ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; pReq->m_pIovecCur->iov_len = bufLen; pReq->m_pRespBufPos = pReq->m_pRespBuf; ++pReq->m_pIovecCur; bufLen = 0; } } int LSAPI_Flush_r( LSAPI_Request * pReq ) { int ret = 0; int n; if ( !pReq ) return -1; n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf )) return 0; if ( pReq->m_fd == -1 ) { pReq->m_pRespBufPos = pReq->m_pRespBuf; pReq->m_totalLen = 0; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; return -1; } if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { LSAPI_FinalizeRespHeaders_r( pReq ); } if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { Flush_RespBuf_r( pReq ); } n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; if ( n > 0 ) { ret = lsapi_writev( pReq->m_fd, &pReq->m_pIovecToWrite, n, pReq->m_totalLen ); if ( ret < pReq->m_totalLen ) { lsapi_close_connection(pReq); ret = -1; } pReq->m_totalLen = 0; pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; } return ret; } ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len ) { struct lsapi_packet_header header; const char * pEnd; const char * p; ssize_t packetLen; ssize_t totalLen; int ret; struct iovec iov[2]; struct iovec *pIov; if ( !pReq ) return -1; if (s_stderr_log_path || pReq->m_fd == -1 || pReq->m_fd == pReq->m_fdListen) return write( 2, pBuf, len ); if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { LSAPI_Flush_r( pReq ); } p = pBuf; pEnd = pBuf + len; while( ( packetLen = pEnd - p ) > 0 ) { if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { packetLen = LSAPI_MAX_DATA_PACKET_LEN; } lsapi_buildPacketHeader( &header, LSAPI_STDERR_STREAM, packetLen + LSAPI_PACKET_HEADER_LEN ); totalLen = packetLen + LSAPI_PACKET_HEADER_LEN; iov[0].iov_base = (void *)&header; iov[0].iov_len = LSAPI_PACKET_HEADER_LEN; iov[1].iov_base = (void *)p; iov[1].iov_len = packetLen; p += packetLen; pIov = iov; ret = lsapi_writev( pReq->m_fd, &pIov, 2, totalLen ); if ( ret < totalLen ) { lsapi_close_connection(pReq); ret = -1; } } return p - pBuf; } static char * GetHeaderVar( LSAPI_Request * pReq, const char * name ) { int i; char * pValue; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { if ( strcmp( name, CGI_HEADERS[i] ) == 0 ) { pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; if ( *(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) != '\0') { *(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) = '\0'; } return pValue; } } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { const char *p; char *pKey; char *pKeyEnd; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; pKeyEnd = pKey + keyLen; p = &name[5]; while(( pKey < pKeyEnd )&&( *p )) { char ch = toupper( *pKey ); if ((ch != *p )||(( *p == '_' )&&( ch != '-'))) break; ++p; ++pKey; } if (( pKey == pKeyEnd )&& (!*p )) { pValue = pReq->m_pHttpHeader + pCur->valueOff; if ( *(pValue + pCur->valueLen) != '\0') { *(pValue + pCur->valueLen) = '\0'; } return pValue; } ++pCur; } } return NULL; } char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ) { struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList; struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv; if ( !pReq || !name ) return NULL; if ( strncmp( name, "HTTP_", 5 ) == 0 ) { return GetHeaderVar( pReq, name ); } while( pBegin < pEnd ) { if ( strcmp( name, pBegin->pKey ) == 0 ) return pBegin->pValue; ++pBegin; } return NULL; } struct _headerInfo { const char * _name; int _nameLen; const char * _value; int _valueLen; }; int compareValueLocation(const void * v1, const void *v2 ) { return ((const struct _headerInfo *)v1)->_value - ((const struct _headerInfo *)v2)->_value; } int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { int i; int len = 0; char * pValue; int ret; int count = 0; struct _headerInfo headers[512]; if ( !pReq || !fn ) return -1; if ( !pReq->m_pHeaderIndex ) return 0; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { len = pReq->m_pHeaderIndex->m_headerLen[i]; pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; *(pValue + len ) = 0; headers[count]._name = HTTP_HEADERS[i]; headers[count]._nameLen = HTTP_HEADER_LEN[i]; headers[count]._value = pValue; headers[count]._valueLen = len; ++count; //ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i], // pValue, len, arg ); //if ( ret <= 0 ) // return ret; } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { char *pKey; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; *(pKey + keyLen ) = 0; pValue = pReq->m_pHttpHeader + pCur->valueOff; *(pValue + pCur->valueLen ) = 0; headers[count]._name = pKey; headers[count]._nameLen = keyLen; headers[count]._value = pValue; headers[count]._valueLen = pCur->valueLen; ++count; if ( count == 512 ) break; //ret = (*fn)( pKey, keyLen, // pValue, pCur->valueLen, arg ); //if ( ret <= 0 ) // return ret; ++pCur; } } qsort( headers, count, sizeof( struct _headerInfo ), compareValueLocation ); for( i = 0; i < count; ++i ) { ret = (*fn)( headers[i]._name, headers[i]._nameLen, headers[i]._value, headers[i]._valueLen, arg ); if ( ret <= 0 ) return ret; } return count; } int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { int i; int len = 0; char * pValue; int ret; int count = 0; if ( !pReq || !fn ) return -1; for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { len = pReq->m_pHeaderIndex->m_headerLen[i]; pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; *(pValue + len ) = 0; ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i], pValue, len, arg ); ++count; if ( ret <= 0 ) return ret; } } if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { char achHeaderName[256]; char *p; char *pKey; char *pKeyEnd ; int keyLen; struct lsapi_header_offset * pCur, *pEnd; pCur = pReq->m_pUnknownHeader; pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; while( pCur < pEnd ) { pKey = pReq->m_pHttpHeader + pCur->nameOff; keyLen = pCur->nameLen; if ( keyLen > 250 ) keyLen = 250; pKeyEnd = pKey + keyLen; memcpy( achHeaderName, "HTTP_", 5 ); p = &achHeaderName[5]; while( pKey < pKeyEnd ) { char ch = *pKey++; if ( ch == '-' ) *p++ = '_'; else *p++ = toupper( ch ); } *p = 0; keyLen += 5; pValue = pReq->m_pHttpHeader + pCur->valueOff; *(pValue + pCur->valueLen ) = 0; ret = (*fn)( achHeaderName, keyLen, pValue, pCur->valueLen, arg ); if ( ret <= 0 ) return ret; ++pCur; } } return count + pReq->m_pHeader->m_cntUnknownHeaders; } static int EnvForeach( struct LSAPI_key_value_pair * pEnv, int n, LSAPI_CB_EnvHandler fn, void * arg ) { struct LSAPI_key_value_pair * pEnd = pEnv + n; int ret; if ( !pEnv || !fn ) return -1; while( pEnv < pEnd ) { ret = (*fn)( pEnv->pKey, pEnv->keyLen, pEnv->pValue, pEnv->valLen, arg ); if ( ret <= 0 ) return ret; ++pEnv; } return n; } int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { if ( !pReq || !fn ) return -1; if ( pReq->m_pHeader->m_cntEnv > 0 ) { return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, fn, arg ); } return 0; } int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, LSAPI_CB_EnvHandler fn, void * arg ) { if ( !pReq || !fn ) return -1; if ( pReq->m_pHeader->m_cntSpecialEnv > 0 ) { return EnvForeach( pReq->m_pSpecialEnvList, pReq->m_pHeader->m_cntSpecialEnv, fn, arg ); } return 0; } int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ) { if ( !pReq || !pReq->m_pIovec ) return -1; if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) ) return 0; pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER; if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf ) { pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf; pReq->m_pIovecCur->iov_len = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf; pReq->m_totalLen += pReq->m_pIovecCur->iov_len; ++pReq->m_pIovecCur; } pReq->m_pIovec->iov_len = sizeof( struct lsapi_resp_header) + pReq->m_respHeader.m_respInfo.m_cntHeaders * sizeof( short ); pReq->m_totalLen += pReq->m_pIovec->iov_len; lsapi_buildPacketHeader( &pReq->m_respHeader.m_pktHeader, LSAPI_RESP_HEADER, pReq->m_totalLen ); pReq->m_pIovec->iov_base = (void *)&pReq->m_respHeader; pReq->m_pIovecToWrite = pReq->m_pIovec; return 0; } int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName, const char * pHeaderValue ) { int nameLen, valLen, len; if ( !pReq || !pHeaderName || !pHeaderValue ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) return -1; if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) return -1; nameLen = strlen( pHeaderName ); valLen = strlen( pHeaderValue ); if ( nameLen == 0 ) return -1; while( nameLen > 0 ) { char ch = *(pHeaderName + nameLen - 1 ); if (( ch == '\n' )||( ch == '\r' )) --nameLen; else break; } if ( nameLen <= 0 ) return 0; while( valLen > 0 ) { char ch = *(pHeaderValue + valLen - 1 ); if (( ch == '\n' )||( ch == '\r' )) --valLen; else break; } len = nameLen + valLen + 1; if ( len > LSAPI_RESP_HTTP_HEADER_MAX ) return -1; if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) { int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf; newlen -= newlen % 4096; if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) return -1; } memmove( pReq->m_pRespHeaderBufPos, pHeaderName, nameLen ); pReq->m_pRespHeaderBufPos += nameLen; *pReq->m_pRespHeaderBufPos++ = ':'; memmove( pReq->m_pRespHeaderBufPos, pHeaderValue, valLen ); pReq->m_pRespHeaderBufPos += valLen; *pReq->m_pRespHeaderBufPos++ = 0; ++len; /* add one byte padding for \0 */ pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len; ++pReq->m_respHeader.m_respInfo.m_cntHeaders; return 0; } int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len ) { if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX ) return -1; if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) return -1; if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) return -1; while( len > 0 ) { char ch = *(pBuf + len - 1 ); if (( ch == '\n' )||( ch == '\r' )) --len; else break; } if ( len <= 0 ) return 0; if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) { int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf; newlen -= newlen % 4096; if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) return -1; } memmove( pReq->m_pRespHeaderBufPos, pBuf, len ); pReq->m_pRespHeaderBufPos += len; *pReq->m_pRespHeaderBufPos++ = 0; ++len; /* add one byte padding for \0 */ pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len; ++pReq->m_respHeader.m_respInfo.m_cntHeaders; return 0; } int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog ) { int ret; int fd; int flag = 1; int addr_len; switch( pServerAddr->sa_family ) { case AF_INET: addr_len = 16; break; case AF_INET6: addr_len = sizeof( struct sockaddr_in6 ); break; case AF_UNIX: addr_len = sizeof( struct sockaddr_un ); unlink( ((struct sockaddr_un *)pServerAddr)->sun_path ); break; default: return -1; } fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 ); if ( fd == -1 ) return -1; fcntl( fd, F_SETFD, FD_CLOEXEC ); if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char *)( &flag ), sizeof(flag)) == 0) { ret = bind( fd, pServerAddr, addr_len ); if ( !ret ) { ret = listen( fd, backlog ); if ( !ret ) return fd; } } ret = errno; close(fd); errno = ret; return -1; } int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr ) { char achAddr[256]; char * p = achAddr; char * pEnd; struct addrinfo *res, hints; int doAddrInfo = 0; int port; if ( !pBind ) return -1; while( isspace( *pBind ) ) ++pBind; strncpy(achAddr, pBind, 255); achAddr[255] = 0; switch( *p ) { case '/': pAddr->sa_family = AF_UNIX; strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p, sizeof(((struct sockaddr_un *)pAddr)->sun_path) ); return 0; case '[': pAddr->sa_family = AF_INET6; ++p; pEnd = strchr( p, ']' ); if ( !pEnd ) return -1; *pEnd++ = 0; if ( *p == '*' ) { strcpy( achAddr, "::" ); p = achAddr; } doAddrInfo = 1; break; default: pAddr->sa_family = AF_INET; pEnd = strchr( p, ':' ); if ( !pEnd ) return -1; *pEnd++ = 0; doAddrInfo = 0; if ( *p == '*' ) { ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY); } else if (!strcasecmp( p, "localhost" ) ) ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK ); else { #ifdef HAVE_INET_PTON if (!inet_pton(AF_INET, p, &((struct sockaddr_in *)pAddr)->sin_addr)) #else ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p ); if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST) #endif { doAddrInfo = 1; } } break; } if ( *pEnd == ':' ) ++pEnd; port = atoi( pEnd ); if (( port <= 0 )||( port > 65535 )) return -1; if ( doAddrInfo ) { memset(&hints, 0, sizeof(hints)); hints.ai_family = pAddr->sa_family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if ( getaddrinfo(p, NULL, &hints, &res) ) { return -1; } memcpy(pAddr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); } if ( pAddr->sa_family == AF_INET ) ((struct sockaddr_in *)pAddr)->sin_port = htons( port ); else ((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port ); return 0; } int LSAPI_CreateListenSock( const char * pBind, int backlog ) { char serverAddr[128]; int ret; int fd = -1; ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr ); if ( !ret ) { fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog ); } return fd; } static fn_select_t g_fnSelect = select; typedef struct _lsapi_prefork_server { int m_fd; int m_iMaxChildren; int m_iExtraChildren; int m_iCurChildren; int m_iMaxIdleChildren; int m_iServerMaxIdle; int m_iChildrenMaxIdleTime; int m_iMaxReqProcessTime; int m_iAvoidFork; lsapi_child_status * m_pChildrenStatus; lsapi_child_status * m_pChildrenStatusCur; lsapi_child_status * m_pChildrenStatusEnd; }lsapi_prefork_server; static lsapi_prefork_server * g_prefork_server = NULL; int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ) { if ( g_prefork_server ) return 0; if ( max_children <= 1 ) return -1; if ( max_children >= 10000) max_children = 10000; if (s_max_busy_workers == 0) s_max_busy_workers = max_children / 2 + 1; g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) ); if ( !g_prefork_server ) return -1; memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) ); if ( fp != NULL ) g_fnSelect = fp; s_ppid = getppid(); s_pid = getpid(); setpgid( s_pid, s_pid ); #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) s_total_pages = sysconf(_SC_PHYS_PAGES); #endif g_prefork_server->m_iAvoidFork = avoidFork; g_prefork_server->m_iMaxChildren = max_children; g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ; g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3); if ( g_prefork_server->m_iMaxIdleChildren == 0 ) g_prefork_server->m_iMaxIdleChildren = 1; g_prefork_server->m_iChildrenMaxIdleTime = 300; g_prefork_server->m_iMaxReqProcessTime = 3600; setsid(); return 0; } void LSAPI_Set_Server_fd( int fd ) { if( g_prefork_server ) g_prefork_server->m_fd = fd; } static int lsapi_accept( int fdListen ) { int fd; int nodelay = 1; socklen_t len; char achPeer[128]; len = sizeof( achPeer ); fd = accept( fdListen, (struct sockaddr *)&achPeer, &len ); if ( fd != -1 ) { if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); } //OPTIMIZATION //if ( s_accept_notify ) // notify_req_received( fd ); } return fd; } static unsigned int s_max_reqs = UINT_MAX; static int s_max_idle_secs = 300; static int s_stop; static void lsapi_cleanup(int signal) { s_stop = signal; } static lsapi_child_status * find_child_status( int pid ) { lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd; while( pStatus < pEnd ) { if ( pStatus->m_pid == pid ) { if (pid == 0) { memset(pStatus, 0, sizeof( *pStatus ) ); pStatus->m_pid = -1; } if ( pStatus + 1 > g_prefork_server->m_pChildrenStatusCur ) g_prefork_server->m_pChildrenStatusCur = pStatus + 1; return pStatus; } ++pStatus; } return NULL; } void LSAPI_reset_server_state( void ) { /* Reset child status */ g_prefork_server->m_iCurChildren = 0; lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd; while( pStatus < pEnd ) { pStatus->m_pid = 0; ++pStatus; } if (s_busy_workers) __atomic_store_n(s_busy_workers, 0, __ATOMIC_SEQ_CST); if (s_accepting_workers) __atomic_store_n(s_accepting_workers, 0, __ATOMIC_SEQ_CST); } static void lsapi_sigchild( int signal ) { int status, pid; char expect_connected = LSAPI_STATE_CONNECTED; char expect_accepting = LSAPI_STATE_ACCEPTING; lsapi_child_status * child_status; if (g_prefork_server == NULL) return; while( 1 ) { pid = waitpid( -1, &status, WNOHANG|WUNTRACED ); if ( pid <= 0 ) { break; } if ( WIFSIGNALED( status )) { int sig_num = WTERMSIG( status ); #ifdef WCOREDUMP const char * dump = WCOREDUMP( status ) ? "yes" : "no"; #else const char * dump = "unknown"; #endif lsapi_log("Child process with pid: %d was killed by signal: " "%d, core dumped: %s\n", pid, sig_num, dump ); } if ( pid == s_pid_dump_debug_info ) { pid = 0; continue; } if ( pid == s_ignore_pid ) { pid = 0; s_ignore_pid = -1; continue; } child_status = find_child_status( pid ); if ( child_status ) { if (__atomic_compare_exchange_n(&child_status->m_state, &expect_connected, LSAPI_STATE_IDLE, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { if (s_busy_workers) __atomic_fetch_sub(s_busy_workers, 1, __ATOMIC_SEQ_CST); } else if (__atomic_compare_exchange_n(&child_status->m_state, &expect_accepting, LSAPI_STATE_IDLE, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { if (s_accepting_workers) __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST); } child_status->m_pid = 0; --g_prefork_server->m_iCurChildren; } } while(( g_prefork_server->m_pChildrenStatusCur > g_prefork_server->m_pChildrenStatus ) &&( g_prefork_server->m_pChildrenStatusCur[-1].m_pid == 0 )) --g_prefork_server->m_pChildrenStatusCur; } static int lsapi_init_children_status(void) { char * pBuf; int size = 4096; int max_children; if (g_prefork_server->m_pChildrenStatus) return 0; max_children = g_prefork_server->m_iMaxChildren + g_prefork_server->m_iExtraChildren; size = max_children * sizeof( lsapi_child_status ) * 2 + 3 * sizeof(int); size = (size + 4095) / 4096 * 4096; pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0 ); if ( pBuf == MAP_FAILED ) { perror( "Anonymous mmap() failed" ); return -1; } memset( pBuf, 0, size ); g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf; g_prefork_server->m_pChildrenStatusCur = (lsapi_child_status *)pBuf; g_prefork_server->m_pChildrenStatusEnd = (lsapi_child_status *)pBuf + max_children; s_busy_workers = (int *)g_prefork_server->m_pChildrenStatusEnd; s_accepting_workers = s_busy_workers + 1; s_global_counter = s_accepting_workers + 1; s_avail_pages = (size_t *)(s_global_counter + 1); setsid(); return 0; } static void dump_debug_info( lsapi_child_status * pStatus, long tmCur ) { char achCmd[1024]; if ( s_pid_dump_debug_info ) { if ( kill( s_pid_dump_debug_info, 0 ) == 0 ) return; } lsapi_log("Possible runaway process, UID: %d, PPID: %d, PID: %d, " "reqCount: %d, process time: %ld, checkpoint time: %ld, start " "time: %ld\n", getuid(), getppid(), pStatus->m_pid, pStatus->m_iReqCounter, tmCur - pStatus->m_tmReqBegin, tmCur - pStatus->m_tmLastCheckPoint, tmCur - pStatus->m_tmStart ); s_pid_dump_debug_info = fork(); if (s_pid_dump_debug_info == 0) { snprintf( achCmd, 1024, "gdb --batch -ex \"attach %d\" -ex \"set height 0\" " "-ex \"bt\" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2", pStatus->m_pid, pStatus->m_pid ); if ( system( achCmd ) == -1 ) perror( "system()" ); exit( 0 ); } } static void lsapi_check_child_status( long tmCur ) { int idle = 0; int tobekilled; int dying = 0; int count = 0; lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusCur; while( pStatus < pEnd ) { tobekilled = 0; if ( pStatus->m_pid != 0 && pStatus->m_pid != -1) { ++count; if ( !pStatus->m_inProcess ) { if (g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren || idle > g_prefork_server->m_iMaxIdleChildren) { ++pStatus->m_iKillSent; //tobekilled = SIGUSR1; } else { if (s_max_idle_secs> 0 && tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5) { ++pStatus->m_iKillSent; //tobekilled = SIGUSR1; } } if (!pStatus->m_iKillSent) ++idle; } else { if (tmCur - pStatus->m_tmReqBegin > g_prefork_server->m_iMaxReqProcessTime) { if ((pStatus->m_iKillSent % 5) == 0 && s_dump_debug_info) dump_debug_info( pStatus, tmCur ); if ( pStatus->m_iKillSent > 5 ) { tobekilled = SIGKILL; lsapi_log("Force killing runaway process PID: %d" " with SIGKILL\n", pStatus->m_pid ); } else { tobekilled = SIGTERM; lsapi_log("Killing runaway process PID: %d with " "SIGTERM\n", pStatus->m_pid ); } } } if ( tobekilled ) { if (( kill( pStatus->m_pid, tobekilled ) == -1 ) && ( errno == ESRCH )) { pStatus->m_pid = 0; --count; } else { ++pStatus->m_iKillSent; ++dying; } } } ++pStatus; } if ( abs( g_prefork_server->m_iCurChildren - count ) > 1 ) { lsapi_log("Children tracking is wrong: Cur Children: %d," " count: %d, idle: %d, dying: %d\n", g_prefork_server->m_iCurChildren, count, idle, dying ); } } //static int lsapi_all_children_must_die(void) //{ // int maxWait; // int sec =0; // g_prefork_server->m_iMaxReqProcessTime = 10; // g_prefork_server->m_iMaxIdleChildren = -1; // maxWait = 15; // // while( g_prefork_server->m_iCurChildren && (sec < maxWait) ) // { // lsapi_check_child_status(time(NULL)); // sleep( 1 ); // sec++; // } // if ( g_prefork_server->m_iCurChildren != 0 ) // kill( -getpgrp(), SIGKILL ); // return 0; //} void set_skip_write(void) { s_skip_write = 1; } int is_enough_free_mem(void) { #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) //minimum 1GB or 10% available free memory return (*s_avail_pages > s_min_avail_pages || (*s_avail_pages * 10) / s_total_pages > 0); #endif return 1; } static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Request * pReq ) { struct sigaction act, old_term, old_quit, old_int, old_usr1, old_child; lsapi_child_status * child_status; int wait_secs = 0; int ret = 0; int pid; time_t lastTime = 0; time_t curTime = 0; fd_set readfds; struct timeval timeout; sigset_t mask; sigset_t orig_mask; lsapi_init_children_status(); act.sa_flags = 0; act.sa_handler = lsapi_sigchild; sigemptyset(&(act.sa_mask)); if( sigaction( SIGCHLD, &act, &old_child ) ) { perror( "Can't set signal handler for SIGCHILD" ); return -1; } /* Set up handler to kill children upon exit */ act.sa_flags = 0; act.sa_handler = lsapi_cleanup; sigemptyset(&(act.sa_mask)); if( sigaction( SIGTERM, &act, &old_term ) || sigaction( SIGINT, &act, &old_int ) || sigaction( SIGUSR1, &act, &old_usr1 ) || sigaction( SIGQUIT, &act, &old_quit )) { perror( "Can't set signals" ); return -1; } while( !s_stop ) { if (s_proc_group_timer_cb != NULL) { s_proc_group_timer_cb(&s_ignore_pid); } curTime = time( NULL ); if (curTime != lastTime ) { lastTime = curTime; if (lsapi_parent_dead()) break; lsapi_check_child_status(curTime ); if (pServer->m_iServerMaxIdle) { if ( pServer->m_iCurChildren <= 0 ) { ++wait_secs; if ( wait_secs > pServer->m_iServerMaxIdle ) return -1; } else wait_secs = 0; } } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) *s_avail_pages = sysconf(_SC_AVPHYS_PAGES); // lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n", // s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages); #endif FD_ZERO( &readfds ); FD_SET( pServer->m_fd, &readfds ); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout); if (ret == 1 ) { int accepting = 0; if (s_accepting_workers) accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST); if (pServer->m_iCurChildren > 0 && accepting > 0) { usleep(400); while(accepting-- > 0) sched_yield(); continue; } } else if ( ret == -1 ) { if ( errno == EINTR ) continue; /* perror( "select()" ); */ break; } else { continue; } if (pServer->m_iCurChildren >= pServer->m_iMaxChildren + pServer->m_iExtraChildren) { lsapi_log("Reached max children process limit: %d, extra: %d," " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n", pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren, s_busy_workers ? *s_busy_workers : -1 ); usleep( 100000 ); continue; } pReq->m_fd = lsapi_accept( pServer->m_fd ); if ( pReq->m_fd != -1 ) { wait_secs = 0; child_status = find_child_status( 0 ); sigemptyset( &mask ); sigaddset( &mask, SIGCHLD ); if ( sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0 ) { perror( "sigprocmask(SIG_BLOCK) to block SIGCHLD" ); } pid = fork(); if ( !pid ) { setsid(); if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK in child" ); g_prefork_server = NULL; s_ppid = getppid(); s_pid = getpid(); s_req_processed = 0; s_proc_group_timer_cb = NULL; s_worker_status = child_status; if (pthread_atfork_func) (*pthread_atfork_func)(NULL, NULL, set_skip_write); __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd, 0 ); //keep it open if busy_count is used. if (!s_keep_listener && s_busy_workers && *s_busy_workers > (pServer->m_iMaxChildren >> 1)) s_keep_listener = 1; if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem()) && pReq->m_fdListen != -1 ) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } /* don't catch our signals */ sigaction( SIGCHLD, &old_child, 0 ); sigaction( SIGTERM, &old_term, 0 ); sigaction( SIGQUIT, &old_quit, 0 ); sigaction( SIGINT, &old_int, 0 ); sigaction( SIGUSR1, &old_usr1, 0 ); //init_conn_key( pReq->m_fd ); lsapi_notify_pid( pReq->m_fd ); s_notified_pid = 1; //if ( s_accept_notify ) // return notify_req_received( pReq->m_fd ); return 0; } else if ( pid == -1 ) { lsapi_perror("fork() failed, please increase process limit", errno); if (child_status) child_status->m_pid = 0; } else { ++pServer->m_iCurChildren; if ( child_status ) { child_status->m_pid = pid; child_status->m_tmWaitBegin = curTime; child_status->m_tmStart = curTime; } } close( pReq->m_fd ); pReq->m_fd = -1; if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK" ); } else { if (( errno == EINTR )||( errno == EAGAIN)) continue; lsapi_perror("accept() failed", errno); return -1; } } sigaction( SIGUSR1, &old_usr1, 0 ); //kill( -getpgrp(), SIGUSR1 ); //lsapi_all_children_must_die(); /* Sorry, children ;-) */ return -1; } static struct sigaction old_term, old_quit, old_int, old_usr1, old_child; int LSAPI_Postfork_Child(LSAPI_Request * pReq) { int max_children = g_prefork_server->m_iMaxChildren; s_pid = getpid(); __atomic_store_n(&pReq->child_status->m_pid, s_pid, __ATOMIC_SEQ_CST); s_worker_status = pReq->child_status; setsid(); g_prefork_server = NULL; s_ppid = getppid(); s_req_processed = 0; s_proc_group_timer_cb = NULL; if (pthread_atfork_func) (*pthread_atfork_func)(NULL, NULL, set_skip_write); __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_add_fetch(s_busy_workers, 1, __ATOMIC_SEQ_CST); lsapi_set_nblock( pReq->m_fd, 0 ); //keep it open if busy_count is used. if (!s_keep_listener && s_busy_workers && *s_busy_workers > (max_children >> 1)) s_keep_listener = 1; if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem()) && pReq->m_fdListen != -1 ) { close(pReq->m_fdListen); pReq->m_fdListen = -1; } //init_conn_key( pReq->m_fd ); lsapi_notify_pid(pReq->m_fd); s_notified_pid = 1; //if ( s_accept_notify ) // return notify_req_received( pReq->m_fd ); return 0; } int LSAPI_Postfork_Parent(LSAPI_Request * pReq) { ++g_prefork_server->m_iCurChildren; if (pReq->child_status) { time_t curTime = time( NULL ); pReq->child_status->m_tmWaitBegin = curTime; pReq->child_status->m_tmStart = curTime; } close(pReq->m_fd); pReq->m_fd = -1; return 0; } int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq) { time_t lastTime = 0; time_t curTime = 0; fd_set readfds; struct timeval timeout; int wait_secs = 0; int ret = 0; lsapi_prefork_server * pServer = g_prefork_server; struct sigaction act; lsapi_init_children_status(); act.sa_flags = 0; act.sa_handler = lsapi_sigchild; sigemptyset(&(act.sa_mask)); if (sigaction(SIGCHLD, &act, &old_child)) { perror( "Can't set signal handler for SIGCHILD" ); return -1; } /* Set up handler to kill children upon exit */ act.sa_flags = 0; act.sa_handler = lsapi_cleanup; sigemptyset(&(act.sa_mask)); if (sigaction(SIGTERM, &act, &old_term) || sigaction(SIGINT, &act, &old_int ) || sigaction(SIGUSR1, &act, &old_usr1) || sigaction(SIGQUIT, &act, &old_quit)) { perror( "Can't set signals" ); return -1; } s_stop = 0; pReq->m_reqState = 0; while(!s_stop) { if (s_proc_group_timer_cb != NULL) { s_proc_group_timer_cb(&s_ignore_pid); } curTime = time(NULL); if (curTime != lastTime) { lastTime = curTime; if (lsapi_parent_dead()) break; lsapi_check_child_status(curTime); if (pServer->m_iServerMaxIdle) { if (pServer->m_iCurChildren <= 0) { ++wait_secs; if ( wait_secs > pServer->m_iServerMaxIdle ) return -1; } else wait_secs = 0; } } #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) *s_avail_pages = sysconf(_SC_AVPHYS_PAGES); // lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n", // s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages); #endif FD_ZERO(&readfds); FD_SET(pServer->m_fd, &readfds); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout); if (ret == 1 ) { int accepting = 0; if (s_accepting_workers) accepting = __atomic_load_n(s_accepting_workers, __ATOMIC_SEQ_CST); if (pServer->m_iCurChildren > 0 && accepting > 0) { usleep( 400); while(accepting-- > 0) sched_yield(); continue; } } else if (ret == -1) { if (errno == EINTR) continue; /* perror( "select()" ); */ break; } else { continue; } if (pServer->m_iCurChildren >= pServer->m_iMaxChildren + pServer->m_iExtraChildren) { lsapi_log("Reached max children process limit: %d, extra: %d," " current: %d, busy: %d, please increase LSAPI_CHILDREN.\n", pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren, s_busy_workers ? *s_busy_workers : -1); usleep(100000); continue; } pReq->m_fd = lsapi_accept(pServer->m_fd); if (pReq->m_fd != -1) { wait_secs = 0; pReq->child_status = find_child_status(0); ret = 0; break; } else { if ((errno == EINTR) || (errno == EAGAIN)) continue; lsapi_perror("accept() failed", errno); ret = -1; break; } } sigaction(SIGCHLD, &old_child, 0); sigaction(SIGTERM, &old_term, 0); sigaction(SIGQUIT, &old_quit, 0); sigaction(SIGINT, &old_int, 0); sigaction(SIGUSR1, &old_usr1, 0); return ret; } int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ) { int fd; int ret; int wait_secs; fd_set readfds; struct timeval timeout; if (s_skip_write) return -1; LSAPI_Finish_r( pReq ); if ( g_prefork_server ) { if ( g_prefork_server->m_fd != -1 ) if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 ) return -1; } else if (s_req_processed > 0 && s_max_busy_workers > 0 && s_busy_workers) { ret = __atomic_load_n(s_busy_workers, __ATOMIC_SEQ_CST); if (ret >= s_max_busy_workers) { send_conn_close_notification(pReq->m_fd); lsapi_close_connection(pReq); } } if ( (unsigned int)s_req_processed > s_max_reqs ) return -1; if ( s_worker_status ) { s_worker_status->m_tmWaitBegin = time( NULL ); } while( g_running ) { if ( pReq->m_fd != -1 ) { fd = pReq->m_fd; } else if ( pReq->m_fdListen != -1 ) fd = pReq->m_fdListen; else { break; } wait_secs = 0; while( 1 ) { if ( !g_running ) return -1; if (s_req_processed && s_worker_status && s_worker_status->m_iKillSent) return -1; FD_ZERO( &readfds ); FD_SET( fd, &readfds ); timeout.tv_sec = 1; timeout.tv_usec = 0; if (fd == pReq->m_fdListen) { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_ACCEPTING, __ATOMIC_SEQ_CST); if (s_accepting_workers) __atomic_fetch_add(s_accepting_workers, 1, __ATOMIC_SEQ_CST); } ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout); if (fd == pReq->m_fdListen) { if (s_accepting_workers) __atomic_fetch_sub(s_accepting_workers, 1, __ATOMIC_SEQ_CST); if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_IDLE, __ATOMIC_SEQ_CST); } if ( ret == 0 ) { if ( s_worker_status ) { s_worker_status->m_inProcess = 0; if (fd == pReq->m_fdListen) { if (s_keep_listener == 0 || !is_enough_free_mem()) return -1; if (s_keep_listener == 1) { int wait_time = 10; if (s_busy_workers) wait_time += *s_busy_workers * 10; if (s_accepting_workers) wait_time >>= (*s_accepting_workers); if (wait_secs >= wait_time) return -1; } } } ++wait_secs; if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs )) return -1; if ( lsapi_parent_dead() ) return -1; } else if ( ret == -1 ) { if ( errno == EINTR ) continue; else return -1; } else if ( ret >= 1 ) { if (s_req_processed && s_worker_status && s_worker_status->m_iKillSent) return -1; if ( fd == pReq->m_fdListen ) { pReq->m_fd = lsapi_accept( pReq->m_fdListen ); if ( pReq->m_fd != -1 ) { if (s_worker_status) __atomic_store_n(&s_worker_status->m_state, LSAPI_STATE_CONNECTED, __ATOMIC_SEQ_CST); if (s_busy_workers) __atomic_fetch_add(s_busy_workers, 1, __ATOMIC_SEQ_CST); fd = pReq->m_fd; lsapi_set_nblock( fd, 0 ); //init_conn_key( pReq->m_fd ); if (!s_keep_listener) { close( pReq->m_fdListen ); pReq->m_fdListen = -1; } if ( s_accept_notify ) if ( notify_req_received( pReq->m_fd ) == -1 ) return -1; } else { if (( errno == EINTR )||( errno == EAGAIN)) continue; lsapi_perror( "lsapi_accept() error", errno ); return -1; } } else break; } } if ( !readReq( pReq ) ) { if ( s_worker_status ) { s_worker_status->m_iKillSent = 0; s_worker_status->m_inProcess = 1; ++s_worker_status->m_iReqCounter; s_worker_status->m_tmReqBegin = s_worker_status->m_tmLastCheckPoint = time(NULL); } ++s_req_processed; return 0; } lsapi_close_connection(pReq); LSAPI_Reset_r( pReq ); } return -1; } void LSAPI_Set_Max_Reqs( int reqs ) { s_max_reqs = reqs - 1; } void LSAPI_Set_Max_Idle( int secs ) { s_max_idle_secs = secs; } void LSAPI_Set_Max_Children( int maxChildren ) { if ( g_prefork_server ) g_prefork_server->m_iMaxChildren = maxChildren; } void LSAPI_Set_Extra_Children( int extraChildren ) { if (( g_prefork_server )&&( extraChildren >= 0 )) g_prefork_server->m_iExtraChildren = extraChildren; } void LSAPI_Set_Max_Process_Time( int secs ) { if (( g_prefork_server )&&( secs > 0 )) g_prefork_server->m_iMaxReqProcessTime = secs; } void LSAPI_Set_Max_Idle_Children( int maxIdleChld ) { if (( g_prefork_server )&&( maxIdleChld > 0 )) g_prefork_server->m_iMaxIdleChildren = maxIdleChld; } void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ) { if ( g_prefork_server ) g_prefork_server->m_iServerMaxIdle = serverMaxIdle; } void LSAPI_Set_Slow_Req_Msecs( int msecs ) { s_slow_req_msecs = msecs; } int LSAPI_Get_Slow_Req_Msecs(void) { return s_slow_req_msecs; } void LSAPI_No_Check_ppid(void) { s_ppid = 0; } int LSAPI_Get_ppid(void) { return(s_ppid); } #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #include #else extern char ** environ; #endif static void unset_lsapi_envs(void) { char **env; #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) env = *_NSGetEnviron(); #else env = environ; #endif while( env != NULL && *env != NULL ) { if (!strncmp(*env, "LSAPI_", 6) || !strncmp( *env, "PHP_LSAPI_", 10 ) || (!strncmp( *env, "PHPRC=", 6 )&&(!s_uid))) { char ** del = env; do *del = del[1]; while( *del++ ); } else ++env; } } static int lsapi_initSuEXEC(void) { int i; struct passwd * pw; s_defaultUid = 0; s_defaultGid = 0; if ( s_uid == 0 ) { const char * p = getenv( "LSAPI_DEFAULT_UID" ); if ( p ) { i = atoi( p ); if ( i > 0 ) s_defaultUid = i; } p = getenv( "LSAPI_DEFAULT_GID" ); if ( p ) { i = atoi( p ); if ( i > 0 ) s_defaultGid = i; } p = getenv( "LSAPI_SECRET" ); if (( !p )||( readSecret(p) == -1 )) return -1; if ( g_prefork_server ) { if ( g_prefork_server->m_iMaxChildren < 100 ) g_prefork_server->m_iMaxChildren = 100; if ( g_prefork_server->m_iExtraChildren < 1000 ) g_prefork_server->m_iExtraChildren = 1000; } } if ( !s_defaultUid || !s_defaultGid ) { pw = getpwnam( "nobody" ); if ( pw ) { if ( !s_defaultUid ) s_defaultUid = pw->pw_uid; if ( !s_defaultGid ) s_defaultGid = pw->pw_gid; } else { if ( !s_defaultUid ) s_defaultUid = 10000; if ( !s_defaultGid ) s_defaultGid = 10000; } } return 0; } static int lsapi_check_path(const char *p, char *final, int max_len) { char resolved_path[PATH_MAX+1]; int len = 0; char *end; if (*p != '/') { if (getcwd(final, max_len) == NULL) return -1; len = strlen(final); *(final + len) = '/'; ++len; } end = memccpy(&final[len], p, '\0', PATH_MAX - len); if (!end) { errno = EINVAL; return -1; } p = final; if (realpath(p, resolved_path) == NULL && errno != ENOENT && errno != EACCES) return -1; if (strncmp(resolved_path, "/etc/", 5) == 0) { errno = EPERM; return -1; } return 0; } static int lsapi_reopen_stderr2(const char *full_path) { int newfd = open(full_path, O_WRONLY | O_CREAT | O_APPEND, 0644); if (newfd == -1) { LSAPI_perror_r(NULL, "Failed to open custom stderr log", full_path); return -1; } if (newfd != 2) { dup2(newfd, 2); close(newfd); dup2(2, 1); } if (s_stderr_log_path && full_path != s_stderr_log_path) { free(s_stderr_log_path); s_stderr_log_path = NULL; } s_stderr_log_path = strdup(full_path); return 0; } static int lsapi_reopen_stderr(const char *p) { char full_path[PATH_MAX]; if (s_uid == 0) return -1; if (lsapi_check_path(p, full_path, PATH_MAX) == -1) { LSAPI_perror_r(NULL, "Invalid custom stderr log path", p); return -1; } return lsapi_reopen_stderr2(full_path); } int LSAPI_Init_Env_Parameters( fn_select_t fp ) { const char *p; char ch; int n; int avoidFork = 0; p = getenv("LSAPI_STDERR_LOG"); if (p) { lsapi_reopen_stderr(p); } if (!s_stderr_log_path) s_stderr_is_pipe = isPipe(STDERR_FILENO); p = getenv( "PHP_LSAPI_MAX_REQUESTS" ); if ( !p ) p = getenv( "LSAPI_MAX_REQS" ); if ( p ) { n = atoi( p ); if ( n > 0 ) LSAPI_Set_Max_Reqs( n ); } p = getenv( "LSAPI_KEEP_LISTEN" ); if ( p ) { n = atoi( p ); s_keep_listener = n; } p = getenv( "LSAPI_AVOID_FORK" ); if ( p ) { avoidFork = atoi( p ); if (avoidFork) { s_keep_listener = 2; ch = *(p + strlen(p) - 1); if ( ch == 'G' || ch == 'g' ) avoidFork *= 1024 * 1024 * 1024; else if ( ch == 'M' || ch == 'm' ) avoidFork *= 1024 * 1024; if (avoidFork >= 1024 * 10240) s_min_avail_pages = avoidFork / 4096; } } p = getenv( "LSAPI_ACCEPT_NOTIFY" ); if ( p ) { s_accept_notify = atoi( p ); } p = getenv( "LSAPI_SLOW_REQ_MSECS" ); if ( p ) { n = atoi( p ); LSAPI_Set_Slow_Req_Msecs( n ); } #if defined( RLIMIT_CORE ) p = getenv( "LSAPI_ALLOW_CORE_DUMP" ); if ( !p ) { struct rlimit limit = { 0, 0 }; setrlimit( RLIMIT_CORE, &limit ); } else s_enable_core_dump = 1; #endif p = getenv( "LSAPI_MAX_IDLE" ); if ( p ) { n = atoi( p ); LSAPI_Set_Max_Idle( n ); } if ( LSAPI_Is_Listen() ) { n = 0; p = getenv( "PHP_LSAPI_CHILDREN" ); if ( !p ) p = getenv( "LSAPI_CHILDREN" ); if ( p ) n = atoi( p ); if ( n > 1 ) { LSAPI_Init_Prefork_Server( n, fp, avoidFork != 0 ); LSAPI_Set_Server_fd( g_req.m_fdListen ); } p = getenv( "LSAPI_EXTRA_CHILDREN" ); if ( p ) LSAPI_Set_Extra_Children( atoi( p ) ); p = getenv( "LSAPI_MAX_IDLE_CHILDREN" ); if ( p ) LSAPI_Set_Max_Idle_Children( atoi( p ) ); p = getenv( "LSAPI_PGRP_MAX_IDLE" ); if ( p ) { LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) ); } p = getenv( "LSAPI_MAX_PROCESS_TIME" ); if ( p ) LSAPI_Set_Max_Process_Time( atoi( p ) ); if ( getenv( "LSAPI_PPID_NO_CHECK" ) ) { LSAPI_No_Check_ppid(); } p = getenv("LSAPI_MAX_BUSY_WORKER"); if (p) { n = atoi(p); s_max_busy_workers = n; if (n >= 0) LSAPI_No_Check_ppid(); } p = getenv( "LSAPI_DUMP_DEBUG_INFO" ); if ( p ) s_dump_debug_info = atoi( p ); if ( lsapi_initSuEXEC() == -1 ) return -1; #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) lsapi_initLVE(); #endif } unset_lsapi_envs(); return 0; } int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders, const char * pBody, int bodyLen ) { LSAPI_SetRespStatus_r( pReq, code ); if ( pRespHeaders ) { while( *pRespHeaders ) { LSAPI_AppendRespHeader_r( pReq, *pRespHeaders, strlen( *pRespHeaders ) ); ++pRespHeaders; } } if ( pBody &&( bodyLen > 0 )) { LSAPI_Write_r( pReq, pBody, bodyLen ); } LSAPI_Finish_r( pReq ); return 0; } static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]); /* * Note: this code is harmless on little-endian machines. */ static void byteReverse(unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void lsapi_MD5Init(struct lsapi_MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void lsapi_MD5Update(struct lsapi_MD5Context *ctx, unsigned char const *buf, unsigned len) { register uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memmove(p, buf, len); return; } memmove(p, buf, t); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memmove(ctx->in, buf, 64); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memmove(ctx->in, buf, len); } /* * Final wrap-up - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *ctx) { unsigned int count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1]; lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memmove(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } int LSAPI_Set_Restored_Parent_Pid(int pid) { int old_ppid = s_ppid; s_restored_ppid = pid; return old_ppid; } int LSAPI_Inc_Req_Processed(int cnt) { return __atomic_add_fetch(s_global_counter, cnt, __ATOMIC_SEQ_CST); } PKu]33!ruby-lsapi-5.6/ext/lsapi/lsapi.sonuȯELF>S@@,@8 @ P P !P ! h h !h !888$$ Std PtdpppQtdRtdP P !P !GNU2Hv`t+ƚ_C H‚3@(L`qCSlP*fRn}'3qѮl>&Sɶ ܮʼnSO`[is|&߱RD/y7řkՊ eY&09=By:%/=ejOzJ6'l#mNULCB1{!\$O#W23S=apbU06aD7jp#7ĴDIΊ=\4yݾCEкQuo rSѮIo|q%h6 󝵛 ' =qX[ u  f ! ysO[ |  [7 P + k & !\  2LRT s ? + q ux >A  # -r cH  "./  " "$7x n, 9  A 9 4, 2( F"Xf E  L r PG  {F pD Ѓ  K 5 ti~ @ z! b `. 8! ] 0Z\ e n  v 1 p Y ` o@  и @rl yj U @| - q]   m pY n  5 @o Pw$ }l! s U pT E 0u qS m7 mT 0(  p    {F 0qJ Ѝp @! |I   `  !b g P @@$ '! pl 6 n  P @!__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizecompareValueLocationset_skip_writesigactionsigemptyset__stack_chk_failreallocfcntlacceptsetsockoptmmapmemsetsetsidread__errno_locationclosewritevkillgetppid__ctype_b_locstrncpystrchrstrcasecmpstrtolgetaddrinfomemcpyfreeaddrinfoinet_addrLSAPI_Log__vfprintf_chk__snprintf_chkgetuid__fprintf_chkgettimeofdaylocaltime_rwaitpidforksystemexitlsapi_perrorstrerrorLSAPI_is_suEXEC_DaemonLSAPI_StopLSAPI_IsRunningLSAPI_Register_Pgrp_Timer_CallbackLSAPI_InitRequestmallocgetpeernamedup2LSAPI_Initgeteuidsignalg_reqdlopendlsymLSAPI_Is_Listen_rLSAPI_Is_ListenLSAPI_Reset_rLSAPI_Release_rfreeLSAPI_GetHeader_rLSAPI_ReqBodyGetChar_rLSAPI_ReqBodyGetLine_rmemchrmemmoveLSAPI_ReadReqBody_rFlush_RespBuf_rLSAPI_GetEnv_rstrcmp__ctype_toupper_locLSAPI_ForeachOrgHeader_rqsortLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rLSAPI_ForeachSpecialEnv_rLSAPI_FinalizeRespHeaders_rLSAPI_Flush_rLSAPI_Write_Stderr_rgetpidgetcwdmemccpy__realpath_chkLSAPI_Finish_rLSAPI_End_Response_rLSAPI_Write_rLSAPI_sendfile_rsendfileLSAPI_AppendRespHeader2_rstrlenLSAPI_AppendRespHeader_rLSAPI_CreateListenSock2socketbindlistenunlinkLSAPI_ParseSockAddrLSAPI_CreateListenSockLSAPI_Init_Prefork_ServercallocsetpgidsysconfLSAPI_Set_Server_fdLSAPI_reset_server_stateis_enough_free_memLSAPI_Postfork_ChildLSAPI_Postfork_ParenttimeLSAPI_Accept_Before_Fork__fdelt_chkusleepsched_yieldLSAPI_Set_Max_ReqsLSAPI_Set_Max_IdleLSAPI_Set_Max_ChildrenLSAPI_Set_Extra_ChildrenLSAPI_Set_Max_Process_TimeLSAPI_Set_Max_Idle_ChildrenLSAPI_Set_Server_Max_Idle_SecsLSAPI_Set_Slow_Req_MsecsLSAPI_Get_Slow_Req_MsecsLSAPI_No_Check_ppidLSAPI_Get_ppidLSAPI_Init_Env_Parametersgetenvgetpwnamdlerrorsetrlimit__fxstatsetreuidLSAPI_ErrResponse_rlsapi_MD5Initlsapi_MD5Updatelsapi_MD5FinalgetpwuidsetgidsetgroupssetuidstrtollprctlinitgroupsLSAPI_Accept_rLSAPI_Prefork_Accept_rsigaddsetsigprocmaskLSAPI_Set_Restored_Parent_PidLSAPI_Inc_Req_Processedselectrb_str_newrb_hash_asetrb_funcallvrb_intern2rb_gc_markmunmaprb_check_typerb_obj_as_stringrb_f_sprintfs_fn_add_envrb_string_valuerb_string_value_ptrrb_eval_string_wraprb_str_new_staticrb_ruby_verbose_ptrrb_define_global_construby_strdupmkstempftruncaterb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_exec_recursiverb_default_rsrb_output_fsrb_output_rsrb_lastline_getInit_lsapichdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocrb_stdoutrb_stdinrb_hash_new__memcpy_chkrb_define_global_functionrb_define_methodrb_define_singleton_methodlibruby.so.2.7libm.so.6libc.so.6__environ_edata__bss_start_endGLIBC_2.14GLIBC_2.15GLIBC_2.4GLIBC_2.3.4GLIBC_2.2.5GLIBC_2.3/opt/alt/ruby27/lib64 ) 4 ii ? ti I ui U ii a P !@TX !T` !` ! ! ! !A ! ! !# !) !. !4 !; !J !Z !j !x ! ! ! ! ! ! !( !0 !8 !@ !H !P !X ! ` !!h !p !,x !< !@ !R !^ !r ! ! ! ! ! ! ! ! ! !  ! !' !: !Q( !_0 !r8 !@ !H !P !X !` !!!!!!!!$#!8!X!`!h!p!x!!!!!2!!<!H!J!R!V!V!W!!!m!{!!! !(!0!8!@!H!P!X!`!h!p! x! ! ! ! !!!!!!!!!!!!!!!!! !(!0!8!@!H!P!X! `!"h!#p!x!$!%!&!!'!(!!)!!!!*!+!,!-!!!!!.!/ !0(!0!18!@!H!3P!4X!5`!6h!7p!8x!9!;!=!>!?!@!!A!B!C!D!E!F!!G!!I!K!L!M!N !O(!0!P8!Q@!H!SP!X!T`!Uh!Xp!Yx!Z![!\!]!^!!_!`!!a!b!c!d!e!f!g!h!i!!j!k !l(!0!8!n@!oH!pP!qX!r`!h!sp!tx!u!w!x!y!z!|!!}!~!!!!!!!!!!!! !(!0!8!@!H!P!HH9 HtH5 % hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhq% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D% D% D% D% DH= H H9tH Ht H=y H5r H)HHH?HHtH HtfD=5 u+UH=ڻ Ht H=> d ]wff.^ ÐHGH+FHcAVIH@AUATL$USHtQHHtIHIL9r 0HI9v'KHSMsH;Յ[]A\A]A^[D]A\A]A^øff.f=n D ÐO AWDD_AVAUATUSD6^nAxj׋G3G D!3G V\$ЋW^$DD1\$!3WAʋN Fp $E‰L$A1A1DD^ !D1G;νD\$DEDVDT$A!A1EE|A 1AD!E1DD*ƇGD1D!A1A1DDN DL$E F0D!DnA1D1DGFEDf Dd$D^(A!A1EEؘiA 1AD!1DDDʋ^0D1D!A1DE [D 1!D1DDN,A1DL$G\EA!Df8A1ED"kA 1AD!1DDN4EqDD1!1DE CyD 1!D1DDV<1G!I!1DDD$ Eb%1!1DDD$E@@1!1DDD$ EQZ^&1!1DE6Ƕ1!1DD]/։ 1!1DESD1!1DE ؉ 1!1DDD$E01!1DDD$ E!1!1DE7É1!1DDD$ E 1!1DDD$A0ZEAA1A!A1AA㩉A AD1!1t$DD1!A ogD1 1D!FL*1DD$Ή1AA!B9A1DD$A AD1D$qDD11‹D$ 0"amD1G 81Ɖ11DDD$ ED꾤11DDD$AKAA1A5`KA1AЉApA 1AD1D1D1A ~(D 1G'111DDD$ A0AA1A1AЋT$A2A1D1֋T$ 9ىDD11D11C|A A1A1AD$A0eVĉA1D1AD")Dt$ D D1A *CDG# 1  1DD9Ή 1DDY[e\$  1DE Dt$ щ1DE3}D\$  1DDD$E] 1DEO~oA AD 1DE ,DT$ A1ADE6CDt$ AN 1A~SADEAA A1A5:ADA AD 1Љ3*\$D D1DFӆ[ ]A\A]A^ 1։ 1DƉA4A_ OW GOW ATI1USHdH%(H$1HHH<$t)H$dH3%(u TH= 1XtIٲ tH=a -HcH5`HEHv [ÉD1?H= `HW(Hw`HLJHHLJ0HHWHVHWHWHWHWH)81HSHHHt:HHt)HHtH{@Ht 1[fDHtGwBLHcAT4t/HcApHHH€:t HH1ff.fHtPtJSHcH;}HSHH[~ Hcи[ÃAWAVAUATUSHZHHHD$H:GH%HIHIIILfDA)HcHL9HcIOIvI HLHtML)HLHXHHAIA$D)EH[]A\A]A^A_LHHHAL|$II)AM?DLLHcH~A-H1|v@AVAUATUSHIHHHHHH+E1HH9HcHO؋)HH~)H9HwHHNHHIELL)Ht6Eu@HHDjHu48u P uMt-M[L]A\A]A^H~IHH)uIDHO(HW8HLJLSH)ʍBHGpH0HpH@Hwp~HcHHH HPHO8HGpAWAVAUATUSHHHT$HHH<$IH=)\HcB$HH@H,H9rZf.HH9vGH3LluHCH[]A\A]A^A_HD$L9IM9f.1H[]A\A]A^A_H$1L= L@Al4tI4LHHuHD$HcP 1~H $HLMtM9sHH$ID$HD$@IcMIcmH,$L| L9)A\$){H8HD$'-t _HHI9tHU:t8IcU IcEH$H€:H $HcHcAVHH€:@AVAUATUSL$HH $L9uHdH%(H$@1HHHHHHE1L  LgfHHcHcT4t7 qHM HIcAHL EHT DT t HHuHHcP HHL L9IcIHLfHH I9HcHHc0AHLcP IHcHHBDBHJH H2JAuH  L$DIH Ic LEtaE1@AI E9~CAMIUIAuI}ӅH$@dH3%(u6H@[]A\A]A^D1@IcUL{8IHC0L)H9>Lt$L+{(LA@LLfIM)MK H@σLSLCpNIHDI0HI@HKpM~HC(MxIH E1I@HC8HL1HMLIHHKpH9eHmthILM)MUI9t HItDL+t$HL[]A\A]A^A_DM@@M)(KIHt$HLHk8f.HAVLAUIATIUSHu\H߉{AD${LǃLSHu0{L[L]A\A]A^k[H]A\A]A^Hff.AWAVAUATUSHHHHD$ 0xIHIH Lc\CHcT t u(HDLcLH t tLÅ~6HcAT t u#H@Å~ALH t tE<AG=I|$PHHTI9T$Hs7HI+t$@L2%))I|$PLHHcAMt$PHLIFID$PA:I|$P}MD$PII@ID$PAIc$0fET8HЃA$0D$ H[]A\A]A^A_D$ ff.H HB=0AUATUSHcHfDA< t< uH؅uH[]A\A]IHPHHDI9D$Hs3HI+t$@L2%))tQI|$PHHAPI\$PHCID$PIc$0fET8HЃA$0H1[]A\A]øSDAUATAUHSH?dH%(HD$1D$ff t1fHL$dH3 %(H[]A\A]ÐA1ҾÃtʼnǺ1HL$Aߺؿu#DH'uD o߻D HZDeOAkDH}An}NcHtff.USHdH%(H$1HHu/HH$dH3%(uHĘ[]Կ@1H= tAUATA'USH 'DNuD H@AHH. HHtH- tʖ iƉlj JUDk H DcEuD蟹jf.H=z>H=G 11H\$HCX= f= DH Htxff.H HtxxHu Ht~xHU Ht~xH5 Htxff.=Ǝ D D Ð DAUATUHH=@=SH8dH%(H$(1mHtH H= H==FHE1 H边H= =Ht 1H薹 H=<HHt 1HmIAąWE1H=<Ht 1H< H=<蚳HtHǺ 1菳H=<sH H=<THtHǺ 1иYH=< H1 H蘸OH=f<HtHǺ 1oH=T<̲HtHǺ 1H1H=E<襲HtHǺ 1!H=2<~HtHǺ 1òH="<WHt]H= <AHt 1H轷 _H=<Ht 1H菷 D~ p b EH=;H=B u P5 5+ H=;蓱H 1H  …t Hw HHHHDƊ L;L ;L;C HLt@HֹL€D t%HtAHHt9HLuHfDHJHHJHuHHu1ۉH$(dH3%(H8[]A\A]fD H趲D1 sAHc讲L% HH a裮Åt= @b u l 5r `HH5=uHH5=1u HH5=Fff.AVIAUEATIUHSHt4Hu!(fDHH褭HLwH]HuMtEL[1]A\A]A^ÐIcLLH#EgHGHHܺvT2HGAWAVAAUIATUHoSH1HGO@ƉWDW?t;AĉDHH|@D)A9rhAGt4LLDHL9A?vWEfAIIIH޺@HH@ HLL9uA?DLHH[]A\A]A^A_ܱIATLfUHSFH?LHz?)ƒw=t19rLHfCAD$AD$ ID$071)2HCHLHCP?o H{1HMHHCPH)KXH[]A\ff.fAWAVAUATUSHdH%(H$1Ht^ IAfMcg IoA_@LHCHuMX8u =)~ uٽH$dH3 %( HĨ[]A\A]A^A_f~AAuIALJf8LS|xr@tPHf@HPXN MgA;G ZA9~uEo)HHcIHLD2Hu$G85} uAMgA9ID$,HD$HcIIDhAh(A9}A /HcIH4@HeHAIIh$A9}A HcIH4@HHAIIHl$p(ILHIILp$hMIc@o9gIcP[9SIcpG9?IcH39+IHHHHIHT$IIc@ H)IHHIHHHIHIIcHIHHHD$I9E1DL4t9dfH "H IGAG IPH f@ f@ HHP P H HPPHHPPHHPPHHPPf@f@f@HH#PP H H'P#P$H$H+P'P(f@f@!f@%H(P+f@)I1 fDIHcȋL4t#fBIHT4 rfB@2JHHuMIcP IHHH9pH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@ppHH@pHH9wMApIbIc@ IH0J| ALJt`{ { A{ 1LHcϩIHIGAo IuID%{ D-{ B(AA1IcH4IILI 9HqH=- IJDB(9xHqH=, XIJB($AD$IKAzHL$;Mbfo{ Lt$ LAoL$AT$Ml$)$踪 LL8HL$LH#LLH$ID$H$I3L$H1H D$$Dl$EDDl$H=Tz IHIDz MH=y t"LDLŃP|$臨Et$A9uHt$螤D=Ń5y $A?D5y t @AH5(L*HtHHy f)wy #AH5 l 1KH@H5Z*1YLH 1H菤IH5D21H5i21D%x x DD$4H=x IHtZEW7E1111H=u2H5)1耨E|$迦M2;|$藦E1H5)LuI}觧Ń1H5q)LKfD=w -w w ED$AIFH5(1覧HH)H5x0H1聧1H5(L 1H50LA#LH s2H s 解1H5(Laff.AVAUATUSHdH%(H$1D$ HH ;1Ll$Ld$Lt$ Hklbr {ul;LLD$CHv Ht@HTv Ht{1f|$=u u|H4tH舴H`q d1H$dH3 %(u}HĠ[]A\A]A^D賜 {H5h \Hfы{LA; ff.AWAVAUATUSHD=Tu dH%(H$1ExH@H-t H}u ;Ng DH-%u Ht 1aHEDp EH$L|$PDcA:E1AfD Up EDt EtHt Ht @fLH1HIc臝DHD$PHD$XA ?)ѺHH D9#11A|$MH p D9#H%t Ht @D9#%f AD91葳fH$dH34%(' H[]A\A]A^A_KL$HDŽ$hMl$H$L̞H$LHHD$@迚AHLDŽ$hH$腞H$LHHD$0xPH$LHHD$8S+H$`L HHD$(.H$ LHHD$H ADžHD$PE1Ll$`HD$H$HD$H$`HD$fD%q EHq Ht H=m 1蔞IL9t<1ձL5EDu EME1VFHm LH1HHc}՚}LD$LHD$PHD$X ?)ѺH1H T`1fm  '8Ht$(1ҿ 轘x=_5 q tH&q Ht @f,D9# DCHp Ht@Hp HtDc1DN @l =o {H5b HHAp Ht*Hqp HB(@HQp Ht@Ho H@˖8B-DAD9M=rk 譟=Vk Ho HtDHpo Ht A9HQo HtD҉T$$DE ~:E~5WT$$A˙A輙AuDE UM D9vHn AHtDH5j&1ƞD$藕0 H=O gT$fD}蠩C1mH|$IH|$HT$Ht$1萔61E Mt AMgMg{E1cCHt$1ҿ;H=t(Gf;)>fDD$$菔0d T$$WH=cT$WT$fDD#AfDnm RDh EBH;m H29h {H5_ ДH{wH='f̓H=M'0讖MAH… H{H\h H=JHt$1ҿ贒Hk rl L=rl Xl H5l 7l Hk HtHlX 11L=7l AGHk Ht{1蝦D-g EuHk Ht!E9~jg hk ;t Ht$@1ҿL$ Ht$01ҿHt$H1ҿHt$81ҿ֒Ht$(1ҿ ŒkHLSH$*&$ޒL$踒ij j H=?"J%˚,H=$"QHj Ht*fC1CD$CCT$HC(HC j fD=~j |j ff.@H5f f.ffDn Hff.HV HH+HHODH1f1fATIHUSHchHcLHZH=#n HH[]A\ff.HH5i dH%(HD$1Hm H$Ht-H=m HHD$dH3%(u&H@H=0&跘HHi ffDHSHH=aU 謏HfHH=AU 茏Hc5 m ;5d H=l |6Hl Hl l HfD蛎f?IH=T HH+9M1~+HHcHc5yl H5fl 聐~cl Hfff.@HH=aT |tHHHDHff.UHSH H6Hm t]uaHHHtT؃tJ tEHH؉уu5HM u@HHpH}HH[]HD@HuHߎHMH tHPHpfSHCH[ff.SHSHH[ÐHH=1S LH}b HHH=S \H]b HHH=R 輑tH3b HHUSHH=R :H=uj HtKH`j H\j Zj 腍9Wj t H5e Hj Ht[11ҿ}1H4j ?H-Q H;HHu艔HuH;HjHka HH[]fH="HH}e SHH\$Ht$HH-1HH[ff.fAWAVAUAATIUSHHH=Z 1HH5"H=Z 1HH5H=Z 1HH5H=kZ 1HH5΂H=OZ 1HH5t貂H=3Z 1HH5^薂H=Z 1HH5JzH=Y 1HH55^H=Y 1HH5BH=Y H_H5#H=Y H H5~L%A H=~Y HLH-kA H A H=P HP HP HJH*H4Y H5A HH@ H[H=Y LH H @ H=RP HP HGP HJH*HS{H(K{HoHX 1H5X H= H3H= {H(H[]A\A]@HPHH=ET HwH3T H.XXXXXXH(Ht+H=uH=X 1HH5蜀H=W 1HH5耀H=W 1HH5dH=4ׂHHUS HW H=诂HH5S H=$ZH=xH>JfDmH{HfKHu{Ht -wN OkHU{Hu-ZN 2HHAnonymous mmap() failedlocalhost%02d:%02d:%02d [%s] [UID:%d][%d] %.*syesnosystem()%s, errno: %d (%s) /dev/nulllibpthread.sopthread_atforkHTTP_[UID:%d][%d] %s:%s: %s LSAPI: jail() failure./etc/Can't set signalsaccept() failedLSAPI_STDERR_LOGPHP_LSAPI_MAX_REQUESTSLSAPI_MAX_REQSLSAPI_KEEP_LISTENLSAPI_AVOID_FORKLSAPI_ACCEPT_NOTIFYLSAPI_SLOW_REQ_MSECSLSAPI_ALLOW_CORE_DUMPLSAPI_MAX_IDLEPHP_LSAPI_CHILDRENLSAPI_EXTRA_CHILDRENLSAPI_MAX_IDLE_CHILDRENLSAPI_PGRP_MAX_IDLELSAPI_MAX_PROCESS_TIMELSAPI_PPID_NO_CHECKLSAPI_MAX_BUSY_WORKERLSAPI_DUMP_DEBUG_INFOnobodyLSAPI_DEFAULT_UIDLSAPI_DEFAULT_GIDLSAPI_SECRETLSAPI_LVE_ENABLEliblve.so.0lve_is_availablelve_instance_initlve_destroylve_enterlve_leavejailPHP_LSAPI_PHPRC=packetLen < 0 packetLen > %d Bad request header - ERROR#1 ParseRequest error SUEXEC_AUTHSUEXEC_UGIDLSAPI: setgid()LSAPI: initgroups()LSAPI: setgroups()LSAPI: setuid()Bad request header - ERROR#2 lsapi_accept() errorPragma: no-cacheRetry-After: 60Content-Type: text/htmlDEBUGNOTICEWARNERRORCRITFATALAcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationConnectionContent-TypeContent-LengthCookieCookie2HostPragmaRefererUser-AgentCache-ControlIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveX-Forwarded-ForViaTransfer-EncodingHTTP_ACCEPTHTTP_ACCEPT_CHARSETHTTP_ACCEPT_ENCODINGHTTP_ACCEPT_LANGUAGEHTTP_AUTHORIZATIONHTTP_CONNECTIONCONTENT_TYPECONTENT_LENGTHHTTP_COOKIEHTTP_COOKIE2HTTP_HOSTHTTP_PRAGMAHTTP_REFERERHTTP_USER_AGENTHTTP_CACHE_CONTROLHTTP_IF_MODIFIED_SINCEHTTP_IF_MATCHHTTP_IF_NONE_MATCHHTTP_IF_RANGEHTTP_IF_UNMODIFIED_SINCEHTTP_KEEP_ALIVEHTTP_RANGEHTTP_X_FORWARDED_FORHTTP_VIAHTTP_TRANSFER_ENCODING%04d-%02d-%02d %02d:%02d:%02d.%06d Child process with pid: %d was killed by signal: %d, core dumped: %s Possible runaway process, UID: %d, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld gdb --batch -ex "attach %d" -ex "set height 0" -ex "bt" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2Force killing runaway process PID: %d with SIGKILL Killing runaway process PID: %d with SIGTERM Children tracking is wrong: Cur Children: %d, count: %d, idle: %d, dying: %d LSAPI: LVE jail(%d) result: %d, error: %s ! Invalid custom stderr log pathFailed to open custom stderr logCan't set signal handler for SIGCHILDReached max children process limit: %d, extra: %d, current: %d, busy: %d, please increase LSAPI_CHILDREN. LSAPI: failed to open secret file: %s! LSAPI: failed to check state of file: %s! LSAPI: file permission check failure: %s LSAPI: failed to read secret from secret file: %s LSAPI: Unable to initialize LVERequest header does match total size, total: %d, real: %ld LSAPI: missing SUEXEC_UGID env, use default user! LSAPI: SUEXEC_AUTH authentication failed, use default user! LSAPI: lve_enter() failure, reached resource limit.prctl: Failed to set dumpable, core dump may not be available!sigprocmask(SIG_BLOCK) to block SIGCHLDsigprocmask( SIG_SETMASK ) to restore SIGMASK in childfork() failed, please increase process limitsigprocmask( SIG_SETMASK ) to restore SIGMASKCache-Control: private, no-cache, no-store, must-revalidate, max-age=0PID 508 Resource Limit Is Reached

    Resource Limit Is Reached

    The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.
              replacesrandQUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMESTDERRreopenftruncate() failed. File mapping failed. Memory calloc error[...]nilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXRACK_ROOTchdir()to_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXX;{\f(q@qTrhr|rrrz8zl{`{{`|p},`~|pDl ,x P `x p @$ P8 `L ` | p Џ @ P@ T  0X l Й p p p Р ` 0| xpDX l`Ь0 @4PHp\pб 0@<|T@@`,@Th|` 80X @`0PPd@$8d zRx $X FJ w?:*3$"Dpb \mpmm LmsEIB E(A0z (A BBBI A (D BBBA m m@mYGJB B(A0A80F(B DBb0TtBFC G  AABK ,uk(uGADJ n AAA 4uUAGK R CAG L JCG uAG] AJ $Pvt C KFLH  AABG hEO D  A @ Th Y|XJEDS ؄]Ph H XAHlFBB B(A0A8LP 8A0A(B BBBH <8 FBB A(A0 (D BBBI \i`pdFBB B(A0A8DP~ 8A0A(B BBBA k 8A0A(B BBBH L $FBB A(A0H Q D 0A(A BBBH L$FBB B(A0A8G 8A0A(B BBBF tЌF FH$ԍnCXJLlFBB B(A0A8DA 8A0A(B BBBA `( ̏BBB B(A0A8G I K I L N N w 8A0A(B BBBI 0 hBMD GL  AABA < =BAA G L@I@U  AABG $ TWEHG ( Lag H SHL ؓFBB B(A0A8DPS 8D0A(B BBBF T \bIE D(C0P (F BBBM Q(H BBBAH ԕFBB B(A0A8DP 8A0A(B BBBA T< hCBA A(G0` (A ABBD  (C ABBA J8 0-FBD D(D@T (A ABBB  $( 0lECGF AAI L t!cBG A(D0 (A ABBE XD0` Tt `Z 10 ؚpFAA G@7  AABF  @LsL 8FBB B(A0A8G 8A0A(B BBBG < P  d x   $ 0 <  8  40 <, FBA K(G (A ABBG <XFEE D(D0M (C BBBB <(HXFBH E(A0E8I@ 8A0A(B BBBE (FED ABH$ BBB B(A0A8G 8A0A(B BBBJ Dp4FBB A(A0G 0A(A BBBF L FBB B(A0A8G  8A0A(B BBBA LX4` H\\h+p|(xBFGA kFBzD O E  HU gHQ G <XaydT2HW I I(tEDL ] CAJ TELXEY\ HWd HWl-Hd( EAD  DAJ LH3ED hAHlhFBB E(D0C8GPm 8F0A(B BBBG ,<ZAD J ABL 4oAD  AAK pP \ 4FDA D(F0` (D ABBB j (D ABBE l(G DBBDBBI B(A0A8D@8D0A(B BBB\*HP H IlUKI8FBA D(D@ (A ABBE @t(TpEDG0 AAI HPFBB A(A0 (F BBBH {(F BBB@OFBB A(D0D@  0A(A BBBJ 8$KFBA A(D0 (A ABBE GNU@TT` !A#).4;JZjx !,<@R^r ':Q_r   k `> P !X !o` !.0&p o%oo$oDh !>>>>>>>?? ?0?@?P?`?p?????????@@ @0@@@P@`@p@@@@@@@@@AA A0A@APA`ApAAAAAAAAABB B0B@BPB`BpBBBBBBBBBCC C0C@CPC`CpCCCCCCCCCDD D0D@DPD`DpDDDDDDDDDEE E0E@EPE`EpEEEEEEEEEFF F0F@FPF`FpFFFFFFFFFGG G0G@GPG`GpGGGGGGGGGHH H0H@HPH`HpHHHHHHHHHI,LSLSLSLS!$#!GA$3a1`> GA$3p1113PTGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1113GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYPTGA+GLIBCXX_ASSERTIONSlsapi.so-5.6-3.el8.x86_64.debugԬ67zXZִF!t/wE]?Eh=ڊ2N뺉 ͕  (<φ5+#Sݠ`SNܓmA亍oLо3!pU]Ҍp1du~ ܡʎIq7sWMR-n8'QepFm@W^%%SKLd%58"] Dz0Nbv#8Rl G6hJ:tO~g4:YkrvX j2YL֠CS+gH< Ȅ5L`þ/鹌bځh̝t ljG穓I|x&[vE-i7hߠeȢ|SKPFYsEsceؚA'waj3ukқ rWC/! . N5:|Ė e7U$S ͐AO~I&3²c3vipHtjs4,acj'poapĤiGosa6عi^i뻪Ns(Fj]̚0?SB֋7cy ĜD[DГ?JA'&V rP05e-@c.(kto>4l 2'ezULvo-bVXߌn<@3~<'=b E1UXor+ǫ2g;&gA8L̵bOpW|}()*EPaJGz^"[3:ճ96Lɒ7L |1hE=Z_*/k1OLSO5=Y孽d e[8_uG _c 46`4+O(l|r\Fʚ=d,q0܁\mɮ- 8ءP724LJ)Q㘺 / ߗ-[Vq2kbT} t䛢iYzR>7'A<>2,X+:G@wA>+Bb Lwd{-{iJրd}aMM6uEG=rb+Ϛq/-bǿ_׸Q>[~kl S{v.ofT[oR#`GT1/[ ~zѓܹTo.aߓoh;0=1=G걟Wg7/c,D`+!kl?5*NMr5-mpI/P4H$T]sk_RZlKZU9aqu&x5U B')CAB&_\7"PHMiưrT+Hœ$f!\/+CM54#E բ$^*AU&\-rrߖ0ZcK-z-r!YݶOZznʊ̳mn+@&ZfQ WjF;^O4vAr-W9O3M\F @ƏIh-ƒPY{X9v[jۦi?6oq WUA {4Хԉ7I2 gWfp "OQEAVy\g(9dNC_/r {i0BiK_v(~oOES?A.6)D;bKvzY?<'ϱgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``p( 0 8o$$Eo%%pT0&0&p^B..h`>`>c>> nII wSSK}} p ppXXL P !P X !X ` !`  h !h X!X!X`!` @!@ 'a@\#$"#+1PKu]gy!ruby-lsapi-5.6/ext/lsapi/lsruby.onu[ELF>@@98 ,.+/*0)1fDHff.HHH+HHODH1f1fATIHUSHcHcLHH=HH[]A\ff.HH5dH%(HD$1HH$Ht-H=HHD$dH3%(u&H@H=HHfDHHH=HfHH=Hc5;5H=|6HHHfDf?IH=HH+9M1~+HHcHc5H5~Hfff.@HH=tHHHDHff.UHSH HHm t]uaHHHtT؃tJ tEHH؉уu5HM u@HHpH}HH[]HD@HuHHMH tHPHpfSHCH[ff.SHHH[ÐHH=HHHH=HHHH=tHHHUSHH=H=HtHH9t H5Ht[11ҿ1H?H-H;HHuHuH;HHHH[]fH=HHSHH\$Ht$HH1HH[ff.fAWAVAUAATIUSHHJfDmHHfKHHt -OkHHu-2 GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realign GA$3p1113GA$running gcc 8.5.0 20210514GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobin GA*GOW*GA*GA+stack_clashGA*cf_protection GA*FORTIFYGA+GLIBCXX_ASSERTIONSGA*GA!GA+omit_frame_pointerGA*GA!stack_realignreplacesrand/QUERY_STRINGREQUEST_URIPATH_INFOREQUEST_PATHSCRIPT_NAMESTDERRreopen%s: %s ftruncate() failed. File mapping failed. Memory calloc error [...]nilLSAPI_MAX_BODYBUF_LENGTHLSAPI_TEMPFILEXXXXXXLSAPI_CHILDRENRACK_ROOTchdir()ENVto_hashCGI/1.2eval_string_wrapLSAPIacceptaccept_new_connectionpostfork_childpostfork_parentprocessputcwriteprintprintfputs<<flushgetcgetsreadrewindeacheofeof?closebinmodeisattytty?syncsync=RACK_ENVGATEWAY_Irewindable_input.rbNTERFACE/tmp/lsapi.XXXXXF 9%I'P(int)@ 9 1 3 6  7  8  9 : ( ; 0 < 8 = @ @ H A P B X D` Fh Hp It J x MP NW O Q Y [ \ ] ^ G _ - ` b  +  9  9 ? M     UJ U   U a}^q!$2 7 ;  f9:IDg9@4 @b     I  @`  @ @ @x@v#w :xF@@  :@5   Z :len ptr aux5Zary  9(as@2 W$Flen aux%2ptr&F'Wary( F 9(as)(sA tu L v L w G L !GA "L ::::::::::::::::::::::::::::::::::::::::::::::::: : : : : ::::::::::::::::::: :!:":#:%:&:':(:*:,:,:,(:G:H:I:J:K::  9 7 89:;<=>#@,     $q=%s%t k m n  o  p  u ,  =                $  ( D D  T4 T 9 d 9                "= " 4 6 7  /k 1 2  3  4 & : < = ? @ B C E( F0 G8 I@ JH KP L!X O` Ph Qp Rx T' V' W' X' Y' Z' \' ]' _ ` a b c d e f g h i'k''m'('n'8'oG    G  -=)d = 9 j(9qks)?!!!!!G-.P  W  c  9 c A W   F*WTQQ  )4?JU`Akv$  !{$$% $% 4% D 4 9 D 9 T 9 o  Too I 9  9@+":+#:,$: ,(: ,*: ,,: ,.  9-req;-env<: =)!!!->Q,@: ,B: ,C ,E: +F,G~  Iy K L M NO7,Qy  (9,R  .  /4K$06 :1p7 08 23Z*K 4C5U 5T320[6[$0[23[K 4C5U 5T74C5Q05R02`0 :4C5TH5Q 5R|20:4C5TH5Q 5R|7 %:8-%<9:;%:F%8/: :;A:4C5Us5T05Q:<CY5U <Cw5Us5TM<C5Us5Tm<C5Us5TK4C5Us5Tk8%=9:!%8:(^;":;:4C5U 5Ts5Qv5R =9* ;9;9<C5U 4C5Us8/:@;A:4C5T05Q:> D<C@5U >D>$D<Cy5U >1D>>D<KD5U <XD5U 5T7<XD5U 5TA<eD5Q}??5U 5T 5Q1<rD^5U ?5T 5Q 5R0?5T 5Q 5R0?5T 5Q 5R1? 5T 5Q 5R1?@ 5T 5Q 5R ?n 5T 5Q 5R ? 5T 5Q 5R ? 5T 5Q 5R1? 5T 5Q 5R0?#!5T 5Q 5R0?P!5T 5Q 5R0?~!5T 5Q 5R ?!5T 5Q 5R0?!5T 5Q 5R0?"5T 5Q 5R0?2"5T 5Q 5R0?_"5T 5Q 5R0?"5T 5Q 5R0?"5T 5Q 5R0?"5T 5Q 5R0?#5T 5Q 5R0?@#5T 5Q 5R1?n#5T 5Q 5R <KD#5U <KD#5U >D>D>D>b4<D#5U <D$5U >D?X$5T 5Q 5R0?$5T 5Q 5R0?$5T 5Q 5R0<D$5U 4C5U  F$@%$A- B" -%Cp$B R%Cn CpD:%E E-E9:6 :F3 *K G:g4&H :Iw+ >D>D>DG:v&J":UJ-:TK:&E:D:&E!:G:&J":UG:+C'J:UL8 M8G:Ua(H:1str :=a( ';s(7+ 8)S(;*9N*:+*N8*:C*<>D(O*s>,+>DD:(E!:Gy:4)HyHy*Hy6:1str{ :1n| 0} 0~ 89 w);9>D>D>,+<D)5Us $ &<O*)5U|< E)5U}5Qs $ &4 E5U}5Q| $ &DJ:O*EJ :CstrL :6MCnN CpO G5 a+H5"P7 08 09 0: 6; 88;+M8>EQ0Q+R K+Cfd Rw+Cfd Csfn QG:2+H :1ch >%EG:%,H!:>DG:,Sout!:Sstr,:4/5Us5TTD:,EE*Tout6:Ci 6 :Dl:2-Taryl#:Toutl.:El7Ctmpn :Cio Gc:-HcHc,Soutc8:<1E-5UU5TT4/5UsG?:O/H?H?,Sout?8:1iA 3B :@8'9Qv.;99<XD.5U~5T3</.5Uv</.5Uv</.5Uv</.5Uv>>E>KEU3:0H3!:Sstr3-:051len6 897/;94TE5Uv5T<8'99 /;994aE5UsG':K1H':Sc'+:Vch) W0*8G9)0;Y9W9f;9<D05Us>D89+$1;94TE5Uv5T<?=15TW5Q1>KEG: ~1J#:UG:32H+:Sstr7:<nE15Us<{E15Us4E5T0X: S2Y,:>EX: 2Y+:>EX:-2Y,:>EX:H4Y$:Zpid 23[ + $[ 23, K 4C5U 5T54C5U85Q05R0\H4 4;U4>b4<E 45Qs4E5Qs>E>D>$D] b4^)_ z52 5`,*5``24,K 4C5U 5T74C5Q15Rw>KE F*5 95X B6Y)Y3YHYTaarg#G<E55UQ5T R $ &<E55U|5Ts $ &4eD5QvXk B8Yk(Yk2YkGYkSaargl"GZpn bleno <E65U|5T~<E65Us5Tv $ &<eD75Q|<E175U|5T?<EQ75U|5T<XDu75U 5T9<eD75Qw<E75U|5T<XD75U 5T<<eD75Qw<E 85U5T}<XD-85U 5T<4eD5Q}ca 8Ya&dEe8^?e8^<D8Ta:f !:D 9Ta$:Dy'9Tay:D?G9Tobj?:Dae9Txa:D:9Tx:EECDG9Tobj:D9Tx:g:^^g\/:^\^\hiO:Eigdz:^d!^d<ija(:ks(Uj&:k&UjR%;;d%;q%;~%N%WR%;~%;q%;d%9:%l%;4C5U 5T6>D>D<D;5U >DmC5QU5RTj,+>n>+=86<M8Iw+8,+ >9:>+8K+=9:]+:i+8O: =;l:;`:4F5T15Q 5Rs<F7=5U <FO=5Us<,Fg=5Us<D=5Us>9F>EF4D5Us<RF=5Uv5Ts<_F=5U05Ts5Q35R15Xv5Y0<kF>5Uv<D6>5U <kFN>5Uv<Dm>5U 4kF5Uv<xF>5T14D5U j)?:*N+*:8*:C*;*I+_ <O*E?5U <Fx?5U|"5Tv5Q 5R1<D?5Uv4 E5U|5Qvj)*@;*N*o+*N8*pC*>,+m>O*Uj,;B;,;,; -q-@:&-8 9w@;9=e9y@;9;9;w94F5Us88yZA;8988 DA;84F5Us=,'l B;,; -;,r'q-@N&-<XDA5U 5T54F5U15Tw5Qv<F-B5U15Tw5Qv>KEj,PC;,;,;,N,N,s,qCM,M,M,9:,:,8'9B;99<FC5U 5Qs>aE</>C5Us5T~</VC5Us4XD5U|5T34/5Usttetutwvw/tmp/lsapi.XXXXXXvw .XXXXXXtu{tnttt tttt7ttt0t t  uuL t3 ttttt$u uttxtRttVtWtcttt}uut^tutuZ u Dt t9 u% tt u9ta ttqw lsruby.ctttYt% : ; 9 I$ >  $ > &I I7I I !I/  : ; 9  : ; 9 I8 : ; 9 <4: ; 9 I?<!4: ;9 I?<: ; 9 I> I: ;9 ( (((   : ;9  : ;9 I8  : ;9  : ;9 I : ;9  : ;9 I8  : ;9 I : ;9 I 8 '!I": ;9 I#> I: ; 9 $ : ; 9 % : ; 9 I& : ; 9 ' : ; 9 I8(!I/)'I* : ;9 +4: ; 9 I,4: ; 9 I- : ; 9 I8 .4: ; 9 I?/.?: ;9 @B04: ;9 IB14: ;9 IB2 U34: ;9 I415B64: ;9 I71RB UX YW 81RB UX YW 9 U:41B;1B<1=1RB X YW >1?@!I/ A.: ;9 B.: ;9 C4: ;9 ID.: ;9 'I E: ;9 IF G.: ;9 'I@BH: ;9 IBI1RB X YW J: ;9 IK.: ;9 'IL1RB X YW M1N41O1BP4: ;9 IQ.: ;9 I R.: ;9 I S: ;9 IBT: ;9 IU.: ;9 'I@BV4: ;9 IW1RB UX YW X.: ; 9 'I@BY: ; 9 IBZ4: ; 9 IB[4: ; 9 IB\1RB UX Y W ].: ; 9 ' ^: ; 9 I_.: ; 9 @B`4: ; 9 I a: ; 9 IBb4: ; 9 I c.: ; 9 '@BdB1e.: ; 9 'I f.?: ;9 '<g.?: ; 9 'I 4h.?: ;9 'I ij.1@Bk1l 1UmB1n41 o41p41 q41r s1UX YW t.?<n: ;9 u.?<n: ; 9 v.?<n: ; w6x.?<nOVOTpqPPqP0uVT0V0T0?0T0?0nPP PPSSPS,8P8HSHcTSSH\TpSH\ Tp vv vPUU U  S  P U U  S  P S  S      0  0 U S D UD g Sg u Uu  S U S U T V D TD a Va u Tu  V T V T Q Q P  ] + P+ C ]C D P ] S  SW u P \ v| v| $0 $+(  v $0 $+( ? v $0 $+( v $0 $+(  P PL V Uu | U U u@aUN $ &"^a $ &"O^PNQ^aQpUUPPpUU`lUlqSqrP`lTlrTUUTTQSQPUwwUw1PT]wTTWPQpVpwQwQV{0S8=S0 s $ &3$}") s $ &3$}"UVWUTS,AS&V,WV+PUVS,9S0 U V U V0 S TS S T S PP S TS S S S S U VU3UTUUUUU U!U!UkPP0000SU\UTSTQQRRXX@USSSS@TVTTVTVT_V@Q\3Q3\JQJ_\@{R{]R]RG]G^ R Z]Z_^@XX3X3XJXJ_X7PPP_JTPT__`hUhmU`USQUS`TVRTV`QQQQVRTVSQUS\\rV * Vg q  q V@Y YiPiV * V* 4 P4 VRVPVyS* q SN q U Z pZ ^ UR n Pn \ PD } S  P6 > P * U U T UT S U S U  U T TT V T V T  V T QT Q Q  QT ] } ] ]T _ S Sd  d  y  yd l Sl  S Sv  S S U  U Q  Q T  V1U1.U.:U:PU1T1.T.=T=PT1Q1SQ.S.AQACSCPQ10UP^P.^1_UU,8U 8U/09szsz@ @r0 g < K N _ L W x  X _ l  v  P 08_0cXH\\cXpv@` 0@ $@LnW /opt/alt/ruby27/include/ruby/usr/include/bits/usr/include/usr/lib/gcc/x86_64-redhat-linux/8/include/usr/include/bits/types/usr/include/sys/usr/include/netinetlsruby.clsapilib.hruby.hstdio2.hstdlib.hstring_fortified.hstddef.htypes.hstruct_FILE.hFILE.hstdio.hsys_errlist.htypes.hstdint-intn.hstdint-uintn.hunistd.hgetopt_core.hmath.hintern.hversion.hlsapidef.htime.hstruct_iovec.herrno.hsockaddr.hsocket.hin.hsignal.hstring.hmman.hutil.h  JK?K| #t>iK>KK{KY;./*X **}( // RX} t     0Yf q\:>X. t" u t/u* uZ ^  %gfu Z3 X |t |< tXX uKt  .t.  X  f. f *8u t  X    o.@5< t-< ti JJ [X &JiX V  L( ff&X< u9= t; K1 tQJ/f J L 2  =t<UMtUX&<< ` 0z X .    =Yl  rX[wt Z " h   m grtX  h fY:g< KXfKY sbXtv  SY|X |X<   L/$ eX< z < zt yt5Y|X |.X z  Z rh Y   *xp*suqwZ7Mt -uDXZ;467954644584236:8648: "u{ wt JvI ;tZvpJuI==[X=XvXuv0X>f~z t gz t ` X p((* uv #G< Y(%[$ rb_mWaitWritable_sys_errlistm_pScriptFileRUBY_Qnilrb_eNoMemError_unused2_filenorb_cMethodrb_obj_wb_unprotectrb_eSyntaxErrorm_cntUnknownHeadersH_AUTHORIZATIONsockaddr_isoblockSizem_pIovecEndstrcpym_pRespBufPosRUBY_FL_EXIVAR__uint8_tdmarkRUBY_DATA_FUNCm_pktHeaderrb_eIOErrorm_bytesm_pHeaderrb_data_object_get_shortbufsockaddr_inrb_cFilerb_eSignalunlinklsapi_dataRUBY_T_ARRAYrb_eKeyErroradd_env_rails__environlsapi_addstrsa_datauint16_tm_totalLensin_zeroRUBY_FL_UNTRUSTEDrb_eZeroDivErrorin_port_t_flagslsapi_getscallocm_respPktHeader__off_tcreateTempFiledfreeRUBY_T_IMEMOrb_global_variable_lockROBJECT_EMBED_LEN_MAXRUBY_T_UNDEFrb_cStringrb_eEOFErroratoim_pHttpHeaderLSAPI_GetReqBodyRemain_rm_pScriptNamerb_mKernelm_pEnvListrb_output_fsint32_t__fmtsa_familym_specialEnvListSizerb_cModulesockaddr_ns__u6_addr8RUBY_T_FALSEruby_robject_flagsrb_cIntegerRUBY_T_FILE_IO_write_endm_iLensockaddrrb_cTrueClasss_addrRUBY_FL_USER0RUBY_FL_USER1RUBY_FL_USER2RUBY_FL_USER3RUBY_FL_USER4RUBY_FL_USER5RUBY_FL_USER6RUBY_FL_USER7RUBY_FL_USER8RUBY_FL_USER9nameLenLSAPI_Postfork_Childfreerb_fsm_requestMethodOffRUBY_T_COMPLEXdata_struct_objrb_eEncCompatErrorruby_special_constsvalLenRSTRING_EMBED_LEN_SHIFT__stack_chk_failruby_rarray_flagsruby_descriptionsin_familyRStringm_fdListenMAX_BODYBUF_LENGTHlsapi_bodym_statusm_reqBodyLenrb_eNameErroroptargneedReadrb_eRegexpErrorrb_cBasicObjectRUBY_T_STRUCTrb_cRationalrb_cFloatrb_cClassrb_cStatsys_errlistin_addr_tbasicRUBY_QtrueLSAPI_ReqBodyGetChar_rpKey__uint16_tsin_portRUBY_T_STRINGrb_cContrb_cFalseClassm_flagRARRAY_EMBED_LEN_SHIFTreadMaxBodyBufLengthm_pQueryString_chainRUBY_T_MODULErb_eArgErrorrb_eInterruptrecurrb_funcallvRUBY_FL_SINGLETONsockaddr_ununsigned charcapanReadm_cntSpecialEnv_IO_lock_tRUBY_T_ZOMBIEfloatLSAPI_key_value_pairLSAPI_ForeachHeader_r/builddir/build/BUILD/opt/alt/ruby27/share/gems/gems/ruby-lsapi-5.6/ext/lsapirb_stderrlsapi_eachm_cntHeadersrb_str_catbodyBufRARRAY_EMBED_LEN_MAXRUBY_T_FIXNUMrb_eSecurityErrorisEofBodyBuflsapi_processlsapi_flushRARRAY_EMBED_FLAGROBJECT_EMBEDoff_tchild_statusRUBY_SYMBOL_FLAGrb_mComparableH_X_FORWARDED_FOR__fprintf_chkm_queryStringOffRUBY_FLONUM_FLAGrb_stdoutruby_rstring_flagsH_CONTENT_LENGTHrb_cTimeruby_engine_IO_write_ptrrb_output_rsROBJECT_ENUM_ENDlsapi_packet_headerLSAPI_ReadReqBody_rrb_eFatallsapi_http_header_indexrb_funcall_argcsTempFilerb_funcall_argsclosesharedlsapi_printfRUBY_T_OBJECTFILEH_COOKIEs_fn_add_envmunmapRSTRING_EMBED_LEN_MAXbodyCurrentLenLSAPI_Accept_Before_Forkrb_cNumerics_req_stderrrb_cHashsize_trb_array_const_ptrH_CONNECTIONrb_rsuint8_tH_CONTENT_TYPERArraylsapi_markm_headerLenRUBY_ELTS_SHAREDperrorlsapi_envruby_release_daterb_cDirsetup_cgi_env_IO_save_baseioveclsapi_eofrb_array_const_ptr_transientenvironlsapi_child_statusreadTempFileTemplaterb_str_newsockaddr_x25rb_eLoadErrorsin6_flowinfom_pIovecToWriteorig_stderrm_respHeaderLen_wide_dataH_IF_MATCHRUBY_FL_PROMOTED0RUBY_FL_PROMOTED1__in6_uH_ACC_CHARSETruby_versionorig_stdout__streamsigngamruby_copyrightm_reqBufSizerb_eExceptionrb_yieldadd_env_no_fixRUBY_T_FLOATRUBY_T_CLASSrb_cDataftruncateruby_fl_typelsapi_requestrb_cComplexfprintfrb_check_typeRUBY_T_HASHsyncRUBY_T_NODEchdir__ssize_t__srcrb_mErrnolsapi_closeH_IF_RANGEnameOffruby_api_versionstrerrorsa_family_tm_packetLenreadMoreRUBY_FL_WB_PROTECTEDin6_addrisBodyWriteToFilelinesin6_addrrb_mWaitReadablelsapi_setsyncm_respPktHeaderEndRUBY_FL_TAINTLSAPI_Postfork_Parentfn_add_envlsapi_printrb_eSystemCallErrorrb_intern2stderrm_pHeaderIndexprogram_invocation_short_namerb_cUnboundMethodrb_f_sprintf_IO_save_endrb_const_get__nptrLSAPI_InitLSAPI_Requestrb_eScriptErrorfn_writelsapi_syncm_bufProcessedstdoutreadBodyBufoptoptlsapi_reopenrb_mGCrb_eIndexErrorm_httpHeaderLencurPosH_IF_NO_MATCHlsapi_s_acceptpreforkRUBY_T_DATAbuffssizetypekeyLenRUBY_FL_DUPPED__builtin_strchrLSAPI_Flush_rshort unsigned intsigned charrb_array_lentz_dsttimefilenamelsruby.clsapi_header_offset__off64_tsockaddr_eon_IO_read_base_offsetm_pIovecrb_string_value_ptrrb_eFloatDomainError_IO_buf_endm_respInfoopterrlsapi_puts_ary_modeblkSize_IO_write_basevalueLenInit_lsapirb_eStandardErrorrb_cSymbolrb_argv0H_CACHE_CTRLH_COOKIE2__destrb_cMatchrb_cEncodinglsapi_isattyH_USERAGENTRARRAY_EMBED_LEN_MASKLSAPI_ForeachEnv_rlong intRUBY_T_NONErb_mProcessrb_mFileTestremain_IO_markerrb_cEnumeratorm_pRespBufEnd__builtin___memcpy_chkrb_io_putslsapi_s_postfork_childrb_define_global_constrb_obj_as_stringm_bufReadin_addruint32_tsockaddr_in6__pid_t_IO_codecvtrb_funcall_nargsH_RANGERDatastrtolg_reqlong doublerb_cRangeiov_lenlsapi_resp_inforb_cObjectlong unsigned intlsapi_req_headerRVALUE_EMBED_LEN_MAXrb_gc_markinitBodyBufruby_strdupm_headerOffrb_eNotImpError__errno_locationlsapi_s_postfork_parentcharsockaddr_inarpm_pSpecialEnvListsin6_scope_idrb_cIORSTRING_ENUM_ENDstdinsin_addrRUBY_T_BIGNUM_IO_buf_baseRSTRING_NOEMBEDRUBY_T_RATIONALRUBY_FL_PROMOTEDs_bodyrb_eTypeErrorRBasicrb_eNoMethodError_IO_read_endRUBY_T_ICLASSrb_num2intcLSAPIRUBY_SPECIAL_SHIFT_IO_FILEH_IF_UNMOD_SINCEm_fdRUBY_T_SYMBOLH_HOSTrb_num2char_inline_IO_wide_datastrlen__u6_addr16s_pidselfrb_eSystemExitisAllBodyReadm_respHeaderrb_cThreadRUBY_FL_SEEN_OBJ_IDm_envListSizem_pAppDataruby_platformsockaddr_ax25RSTRING_FSTRrb_eThreadError__pad5rb_str_new_staticshared_root__u6_addr32rb_cNilClassm_type_markersrb_stdinrb_eStopIterationm_scriptFileOffRUBY_FL_USHIFTklassrb_define_classH_VIA_codecvtm_pRespHeaderBufEndH_PRAGMARUBY_FL_FINALIZErb_cRandomdoublemkstemplsapi_putcargcssize_tstrcatlsapi_writelsapi_putsorig_stdinRUBY_FIXNUM_FLAGargvRARRAY_ENUM_ENDrb_eRuntimeErrorm_pRespHeaderBuf__int32_trb_cProc__uint32_tRUBY_IMMEDIATE_MASKrb_hash_asetdataH_REFERERrb_cStructLSAPI_Prefork_Accept_rheap_sys_siglistRARRAY_TRANSIENT_FLAGm_pUnknownHeaderrb_typem_reqStateRUBY_T_NILRUBY_T_MOVEDrb_eSysStackErrorGNU C17 8.5.0 20210514 (Red Hat 8.5.0-28) -mtune=generic -m64 -march=x86-64 -g -O2 -fPIC -fexceptions -fstack-protector-strong -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection=full -fplugin=gcc-annobinm_pRespBufrb_num2int_inlineprogram_invocation_namerb_cArrayrb_eEncodingErrorrb_ruby_verbose_ptrrb_cBindingrb_intern_id_cacheH_TRANSFER_ENCODINGH_IF_MODIFIED_SINCErb_ary_detransientRUBY_FL_USER10RUBY_FL_USER11RUBY_FL_USER12RUBY_FL_USER13RUBY_FL_USER14RUBY_FL_USER15RUBY_FL_USER16RUBY_FL_USER17RUBY_FL_USER18RUBY_FL_USER19_freeres_bufRUBY_T_MATCHlong long unsigned intpid_t_cur_columnlsapi_rewinds_reqrb_eRangeErrorm_pRespHeaderBufPoss_stderr_datarb_eval_string_wrapgetpidm_cntEnvRUBY_T_MASKrb_lastline_getcreateBodyBuf_IO_backup_baseH_KEEP_ALIVE__memcpy_chk_IO_read_ptrrb_eMathDomainErrorrb_fix2intLSAPI_GetReqBodyLen_rrb_gc_writebarrier_unprotectrb_exec_recursivegetenv_freeres_listrb_eLocalJumpError_sys_nerrlsapi_readtimezonepReqlsapi_getcrb_hash_newclear_envrb_cRegexplsapi_binmode_old_offsetstrchrm_pReqBufrb_cNameErrorMesgvalueOffoptindH_ACC_LANGlong long intin6addr_loopback_flags2VALUErb_mMathRUBY_T_TRUEmemmemsin6_familysockaddr_atruby_value_typem_scriptNameOffH_ACCEPTm_lLastActiverb_eNoMatchingPatternErrorlsapi_resp_headersys_nerrin6addr_anym_pRequestMethods_req_dataiov_basem_lReqBeginruby_rvalue_flagsm_versionB0m_versionB1rb_str_buf_newRUBY_FLONUM_MASKruby_patchlevelRUBY_T_REGEXPm_pIovecCurLSAPI_Init_Env_Parametersorig_envm_reqBodyReadRUBY_Qundeflsapi_s_accept_new_connrb_eFrozenErrorsockaddr_dlRSTRING_EMBED_LEN_MASKRUBY_FL_FREEZEunsigned intbodyLensockaddr_ipxrb_default_rsshort intrb_string_value_vtable_offsetpValueenv_copymmaporig_verboserb_data_object_zallocrb_mEnumerableRUBY_Qfalseflagstz_minuteswestsys_siglistH_ACC_ENCODINGsin6_portlsapi_eval_string_wrapGCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-28)GNUzRx  0D+Xl(BFGA kFBzD O E  HUgHQ G $ayd<2HW I I(\EDL ] CAJ ELEY HW HW-Hd(EAD  DAJ 43ED hAHTFBB E(D0C8GPm 8F0A(B BBBG ,ZAD J ABL 4oAD  AAK pP \4FDA D(F0` (D ABBB j (D ABBE l(G DBBDhBBI B(A0A8D@8D0A(B BBB*HP H IUKI8FBA D(D@ (A ABBE ((<EDG0 AAI HhPFBB A(A0 (F BBBH {(F BBB@OFBB A(D0D@  0A(A BBBJ 8KFBA A(D0 (A ABBE   - )  ?.Yt/01 5 C _"y @"[0+[h` h)wCpPwmB pZz# < xEZ_mw` mpg0aIaUaop2WWr`r1KX   #J o-  X  ` 3D3[3x_@_`  3 N\ @f   4      '  *2  L  d  Uo     '   '   ' 0 2  L Pd Po P  PO          h "$%'./0123-4# ( - @2 )7 < 3A F K LP SU [ ba Zg xm s y           $ * f n s y             ! ' - 3 9 ? E 1K GQ VW ] c i u    ()*+,        & 4 ; @ T k y        /?Sgn% %0;BKhsK",7DWg}   .annobin_lsruby.c.annobin_lsruby.c_end.annobin_lsruby.c.hot.annobin_lsruby.c_end.hot.annobin_lsruby.c.unlikely.annobin_lsruby.c_end.unlikely.annobin_lsruby.c.startup.annobin_lsruby.c_end.startup.annobin_lsruby.c.exit.annobin_lsruby.c_end.exit.annobin_lsapi_process.start.annobin_lsapi_process.endlsapi_process.annobin_lsapi_rewind.start.annobin_lsapi_rewind.endlsapi_rewinds_body.annobin_lsapi_eof.start.annobin_lsapi_eof.endlsapi_eof.annobin_lsapi_binmode.start.annobin_lsapi_binmode.endlsapi_binmode.annobin_lsapi_isatty.start.annobin_lsapi_isatty.endlsapi_isatty.annobin_lsapi_setsync.start.annobin_lsapi_setsync.endlsapi_setsync.annobin_add_env_no_fix.start.annobin_add_env_no_fix.endadd_env_no_fixlsapi_env.annobin_clear_env.start.annobin_clear_env.endclear_envrb_intern_id_cache.15416env_copy.annobin_lsapi_mark.start.annobin_lsapi_mark.endlsapi_mark.annobin_lsapi_flush.start.annobin_lsapi_flush.endlsapi_flush.annobin_lsapi_close.start.annobin_lsapi_close.endlsapi_closeMAX_BODYBUF_LENGTH.annobin_readBodyBuf.start.annobin_readBodyBuf.endreadBodyBuf.annobin_lsapi_getc.start.annobin_lsapi_getc.endlsapi_getc.annobin_lsapi_write.start.annobin_lsapi_write.endlsapi_write.annobin_lsapi_addstr.start.annobin_lsapi_addstr.endlsapi_addstr.annobin_lsapi_printf.start.annobin_lsapi_printf.endlsapi_printf.annobin_lsapi_s_postfork_parent.start.annobin_lsapi_s_postfork_parent.endlsapi_s_postfork_parents_req.annobin_lsapi_s_postfork_child.start.annobin_lsapi_s_postfork_child.endlsapi_s_postfork_child.annobin_lsapi_s_accept_new_conn.start.annobin_lsapi_s_accept_new_conn.endlsapi_s_accept_new_conn.annobin_lsapi_s_accept.start.annobin_lsapi_s_accept.endlsapi_s_accepts_pidrb_intern_id_cache.15429s_req_data.annobin_lsapi_eval_string_wrap.start.annobin_lsapi_eval_string_wrap.endlsapi_eval_string_wrap.annobin_add_env_rails.start.annobin_add_env_rails.endadd_env_rails.annobin_lsapi_reopen.start.annobin_lsapi_reopen.endlsapi_reopens_req_stderrorig_stderrrb_intern_id_cache.15593.annobin_createBodyBuf.start.annobin_createBodyBuf.endcreateBodyBufsTempFile.annobin_lsapi_read.start.annobin_lsapi_read.endlsapi_read.annobin_lsapi_gets.part.2.start.annobin_lsapi_gets.part.2.endlsapi_gets.part.2.annobin_lsapi_gets.start.annobin_lsapi_gets.endlsapi_gets.annobin_lsapi_each.start.annobin_lsapi_each.endlsapi_each.annobin_lsapi_puts_ary.start.annobin_lsapi_puts_ary.endlsapi_puts_ary.annobin_lsapi_sync.start.annobin_lsapi_sync.endlsapi_sync.annobin_lsapi_putc.start.annobin_lsapi_putc.endlsapi_putc.annobin_lsapi_puts.start.annobin_lsapi_puts.endlsapi_puts.annobin_lsapi_print.start.annobin_lsapi_print.endlsapi_print.annobin_Init_lsapi.start.annobin_Init_lsapi.endrb_intern_id_cache.15609rb_intern_id_cache.15614orig_envcLSAPI.LC0.LC1.LC7.LC5.LC4.LC6.LC3.LC2.LC8.LC9.LC13.LC11.LC10.LC12.LC14.LC15.LC16.LC17.LC18.LC55.LC20.LC21.LC25.LC26.LC27.LC28.LC29.LC33.LC34.LC35.LC36.LC37.LC38.LC39.LC40.LC41.LC42.LC43.LC44.LC45.LC46.LC47.LC48.LC49.LC50.LC51.LC52.LC53.LC23.LC19.LC30.LC31.LC32.LC24.LC22.LC54.text.group.text.hot.group.text.unlikely.group.text.startup.group.text.exit.group_GLOBAL_OFFSET_TABLE_g_reqrb_str_newrb_hash_asetrb_funcallvrb_intern2__stack_chk_failrb_gc_markLSAPI_Flush_rmunmapfreeLSAPI_ReadReqBody_rLSAPI_ReqBodyGetChar_rrb_check_typerb_obj_as_stringrb_f_sprintfLSAPI_Postfork_ParentLSAPI_Postfork_ChildLSAPI_Accept_Before_ForkLSAPI_Prefork_Accept_rgetpids_fn_add_envLSAPI_ForeachHeader_rLSAPI_ForeachEnv_rrb_string_valuerb_string_value_ptrrb_eval_string_wrapstrchrrb_str_new_staticrb_ruby_verbose_ptrrb_define_global_construby_strdupmkstempunlinkftruncatemmapcallocperror__errno_locationstrerror__fprintf_chkrb_str_buf_newrb_str_catrb_num2intrb_fix2intmemmemrb_yieldrb_gc_writebarrier_unprotectrb_io_putsrb_ary_detransientrb_exec_recursiverb_default_rsrb_output_fsrb_output_rsrb_lastline_getInit_lsapiLSAPI_InitgetenvstrtolstrlenselectLSAPI_Init_Env_Parameterschdirrb_stderrrb_cObjectrb_const_getrb_global_variablerb_define_classrb_data_object_zallocLSAPI_Write_rrb_stdoutrb_stdinLSAPI_Write_Stderr_rrb_hash_new__memcpy_chkrb_define_global_functionrb_define_methodrb_define_singleton_methodH7*ltl@EOV{**D <8DH*?HF<KUH{*=****"7<AH8XD^HgmTv|T\*)~l0\hq|lllAg  C* D6 C<HSf nuD  <  < @    1 8 G Q *[ c t y    D L H  L <( . LS ] Lc Dy  L <  L < D H  L2 K Y Lc <k q L D H  D Lh           &v*3**@* "8DH#$ %#5%QXL_<fm#$*&'T#(**)** +|,3t:t?,KP\dktv5-d7d6d6d6&d9>6EdX]6ddw|6d6d6d6d6d 6d%*61dAF6Md]b6idy~6d6d6d6d6d 6d$)60dCH6O*Vdj.q*x*/\*0*1,d.*2, 3l"l).8=Bg<l4y<d7d7d7 %/6|HMWch{#  i  $, P X" ""["[[hD[Lhphxwhwww 08dlZZZm$Z,mPmXmaDLapaxaW W0W8rdWlrrr$,PX     D  L p x 3  3 3 _ 3 _0 _8 d _l        $  ,  P  X            D  L  p  x     '   ' 0 ' 8  d ' l   P  P P $P,PX     W Z ) . < 0C L S Z -_ m r B~ q   B w  R     ' 4 A N H [ h 9u  >  `  8  N    * L  + 8 E R _ l y E   G   ,   ' Q3 ? [ g #s           y     d" `) . { ; W j p v ,| z  )     +       V /  /   +     V -  & l, 2 )8 > _D @ J P RV 8\ 6c v |   1  f  7     l       + 9 G U  ! * "3 1< @E ON ^W m` |j q x    {  S y   c    F   2 # , @ ,M   B     p    ) ?= ,J       % Y3 S ` m z q b  x     % k  # d0 = ( J W d mq b~    x V J  $ p { ' 4 A gN [ h u F  3   4 X  k    + J8 E R _ Ol y 7 r  ~   6    E  u" / b< I V uc p } A      V Q # Y /  ; G S &_ k <  K K       "    g     Z     x   p     % 1 '> t K X e 1r |  B   | \ ;    - 7 * 7 e cr  c     s }   8  F* f7 =D 9Q ^ l z J  T    6   `    # 0 = =J W $d /q ~   5          " |' l4 BA N 2\ uj x   L      @ SL X d q +~      V  7 M' "4 R ` n |       U         a  A U b C u      f   c @x& 3p< UIR }y . } h  ` |  " M/X8 hE R _ H l z h w@ @ [   ) N  # A' ;, 8 < A `J X aQr1       F B  )10 % 1 5 ~:nP`a `j v z `  P P      @ <;P1Z x    vH    ' 7+ 30pA@cvlv    )19v 0  "q71AN[p1z CxT1 hz$11@U1$_p1*}1f1n0 #1s  B$ 1y1 PA aR 1_ o  1   1 `  1 p !1!p$!5!1B! Q!b!1o! !.!1!!J!1! !f!1!0""1$"03"D"1Q"`"q"1~"`""1"p""1"p""1# #-%#12#A#LR#1S_#`o#########2#1$A$1L$F,$=$11J$Y$j$1Gw$$ $1V$$l$1$$1%  % s% .% S% ke% r% :% S% N% %% l %% S% % %% &&'&5& A&X& Sg& ; w& 7& S& & S& r&`& S& R &0 ' S'4('4D' P' g' Ss' ?w' 9' ' ' ' ' ' ' ' ' ' @' ' ( @( :( 6"( z&( v+( E( T( b( t( S( -( ( ( ( ( :( ( ( S( h( d( ( ) 7) / ) ) ) !) 1-) ` 1) \ :)L C) T) X) ])W j)} x) ) ) ), ) * * S,* P* X\*s* * * * * * ) * % * 1* * * * * * ** +O+ I+ g-+ RL+ Jx+ + F+p+ S+ + + 7 + 3 ++ d+p, S, q , m ,&, 2,`U, Y, j, n, s,m, , , :, ,  - 3- ?-V- b- : f- 6 k- :w- w {- s - - --- f-P- -  -  . :. \ . R #. '. 6. R:. J?. S.\. m. q. w....8.U.// /2/ S>/ B/ S/ ZW/ T\/ h/ l/ }/ / // / / /// / @/ </A0 00 '0 S30 ~70 vF0 J0 ^0 j0 Fn0 Dw0P 0 0 o0 i0 0 00 0 0 0 0 0 `1 1  1 %1 >1 L1 VX1o1 S1 11 S1 01 ,1 k1 i11#1-2 222 S=2 A2 F2T2 P_2v2 S2 2 22 22 S2 2 22 22 S 3 I 3 E3 !3 &3 0/3 :3 >3 C3 O3 Z3 ^3 c3 pl3 y3331333 3 63 433 4!4&.4E;4kI4 0 V4 c4 ]j44 4 4 4 4 @4 44I414 5Z05 ;5R5 =]5 _a5 Yf5 q5 u5 z5 95 5 5 5 >5 :5 {5 w5566  6@76 =B6 F6 K6 V6 ?Z6 -_6 9j6 n6 s6 ~6 6 6 y6 m6 6 6667427`R7ug71)v77771377 881.8C8 J8`a8 l8 lp8 hu8m8 8 A8 8 A8 8 8 \ 9 9(9 H9 f9 a9 Q9 9 99 A9 9 q9 \ : : q#: \ 0: B: P:  a: r m: %::p:`: : : +: !: :  ;; "; &; /; 3; <; @; ~E; N; R; [; d;u;1S;;;;1L;;;<<;<.D<.]<@f< Ps< P|< '< <@< < < < < < <N < < f< d< < <_ =1Z=L.=@8=WP=jh=r=5 =< =g ==>> ->1b7># O>} d>1xn> >>>1> > > > > > E> A? }? {? ? -? F?6 j?1y?O ?o ? ? ? ? ? @ /@ 3@ <@ @@ vI@  M@  ^@ y b@ q k@ t@ p@ @ @d @d @ !@ !@ Y!@ U!@ !@ !@l @l @ A !A !A !Av *A ;A !?A !EA _A hA A 2"A ."A o"A k"A "A "A A A1A B .B @B[B "_B "hB T#lB L#uB #yB #B B B a$B _$B $B $BB B %B $BzC C!C?CWCrCBC C C C C [C [C C C C C C C }C .C :D : D D D ID I%D &)D &2D L 6D L ?D CD LD lPD lYD ]D fD jD sD wD D D D QD QD gD gD  D  D D D + D + D D D D D D D D E E  E E E E &E &*E &2E 6E ?E BCE BLE PE UE ! YE ! bE ~fE ~oE sE |E E E E E EE EE kE kE W E W E {E {E E E E E E E E E hE hF  F F F  F $F -F v1F v:F >F FF JF SF WF `F IdF IlF pF yF +}F +F F F F F F F EF EF F  C  CJ@f@ C@< LM @k L| @y1Z(! F@! F f 4H0\`pp`p (@p`` 8X@`  l    , @0 lP.symtab.strtab.shstrtab.rela.text.data.bss.rela.gnu.build.attributes.text.hot.rela.gnu.build.attributes.hot.text.unlikely.rela.gnu.build.attributes.unlikely.text.startup.rela.gnu.build.attributes.startup.text.exit.rela.gnu.build.attributes.exit.rodata.str1.1.rodata.str1.8.rela.data.rel.local.rodata.cst16.rela.debug_info.debug_abbrev.rela.debug_loc.rela.debug_aranges.debug_ranges.rela.debug_line.debug_str.comment.text.hot.zzz.text.unlikely.zzz.text.startup.zzz.text.exit.zzz.note.GNU-stack.note.gnu.property.rela.eh_frame.group/@6/T6/l6/6/6 @h8"6&, 61@6 6 Lt'[t'V@C06 uH)H)@C06++@C06,,@ D062.20%'0"@PD670J0FE@hDx6Vw/i~8%d@86 y+0t@06"[@H6%00.uL   %0 @`064@7 P6PKu]whf:ruby-lsapi-5.6/lsapi.gemspecnu[Gem::Specification.new do |s| s.name = %q{ruby-lsapi} s.version = "5.6" s.date = %q{2024-01-22} s.description = "This is a ruby extension for fast communication with LiteSpeed Web Server." s.summary = %q{A ruby extension for fast communication with LiteSpeed Web Server.} s.has_rdoc = false s.authors = ["LiteSpeed Technologies Inc."] s.email = "info@litespeedtech.com" s.homepage = "http://www.litespeedtech.com/" s.rubyforge_project = "ruby-lsapi" s.files = ["lsapi.gemspec", "README", "examples", "examples/testlsapi.rb", "examples/lsapi_with_cgi.rb", "ext", "ext/lsapi", "ext/lsapi/extconf.rb", "ext/lsapi/lsapidef.h", "ext/lsapi/lsapilib.c", "ext/lsapi/lsapilib.h", "ext/lsapi/lsruby.c", "rails", "rails/dispatch.lsapi", "scripts", "scripts/lsruby_runner.rb", "setup.rb"] s.extra_rdoc_files = ["README"] s.extensions << "ext/lsapi/extconf.rb" s.require_paths << "lib" end PKu]^wͱruby-lsapi-5.6/READMEnu[ lsapi - LSAPI extension for Ruby ================================ INSTALL ------- $ ruby setup.rb config $ ruby setup.rb setup # ruby setup.rb install USAGE ----- General CGI scripts ^^^^^^^^^^^^^^^^^^^ The most efficient way to use LSAPI interface is to modify your CGI scripts. You need to add the following code to your CGI scripts: require 'lsapi' while LSAPI.accept != nil ... end There is no need to change the way that how CGI environment variables are being accessed in your scripts. You can find some examples under examples/ folder. Ruby Script Runner ^^^^^^^^^^^^^^^^^^ If you don't want to change your existing Ruby CGI code, you can use our Ruby script runner under scripts/ folder. You need to configure lsruby_runner.rb as a LSAPI application, then add a script handler for "rb" suffix. Rails dispatcher ^^^^^^^^^^^^^^^^ With Ruby LSAPI, we proudly provide a optimum platform for Rails application deployment. Ruby LSAPI has the following advantages over other solutions. * Easy configuration, deploy a Rails application only take a few clicks with our Rails easy configuration * Fast startup, the expensive Rails framework initialization only takes place once when multiple processes need to be started * Resource efficience, ruby processes can be started on demand, idle process will be stop. To use LSAPI with Ruby on Rails, please check out our toturial http://www.litespeedtech.com/support/wiki/doku.php There are a few environment variables that can be tweaked to tune ruby LSAPI process. * LSAPI_CHILDREN (default: 0) LSAPI_CHILDREN controls the maximum number of children processes can be started by the first ruby process started by web server. When set to <=1, the first ruby process will handle request by itself, without starting any child process. When LSAPI_CHILDREN is >1, the LSAPI application is stared in "Self Managed Mode", which will start children processes based on demand. With Rails easy configuration, LSAPI_CHILDREN is set to the value of "Max Connections" by web server, no need to set it explicitly. Usually, there is no need to set value of LSAPI_CHILDREN over 100 in most server environment. * LSAPI_AVOID_FORK (default: 0) LSAPI_AVOID_FORK specifies the policy of the internal process manager in "Self Managed Mode". When set to 0, the internal process manager will stop and start children process on demand to save system resource. This is preferred in a shared hosting environment. When set to 1, the internal process manager will try to avoid freqently stopping and starting children process. This might be preferred in a dedicate hosting environment. * LSAPI_EXTRA_CHILDREN (default: 1/3 of LSAPI_CHILDREN or 0) LSAPI_EXTRA_CHILDREN controls the maximum number of extra children processes can be started when some or all existing children processes are in malfunctioning state. Total number of children processes will be reduced to LSAPI_CHILDREN level as soon as service is back to normal. When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is 0. * LSAPI_MAX_REQS (default value: 10000) LSAPI_MAX_REQS specifies the maximum number of requests each child process will handle before it exits automatically. This parameter can help reducing memory usage when there are memory leaks in the application. * LSAPI_MAX_IDLE (default value: 300 seconds) In Self Managed Mode, LSAPI_MAX_IDLE controls how long a idle child process will wait for a new request before exit. This option help releasing system resources taken by idle processes. * LSAPI_MAX_IDLE_CHILDREN (default value: 1/3 of LSAPI_CHILDREN or LSAPI_CHILDREN) In Self Managed Mode, LSAI_MAX_IDLE_CHILDREN controls how many idle children processes are allowed. Excessive idle children processes will be killed by the parent process. When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is LSAPI_CHILDREN. * LSAPI_MAX_PROCESS_TIME (default value: 300 seconds) In Self Managed Mode, LSAPI_MAX_PROCESS_TIME controls the maximum processing time allowed when processing a request. If a child process can not finish processing of a request in the given time period, it will be killed by the parent process. This option can help getting rid of dead or runaway child process. * LSAPI_PGRP_MAX_IDLE (default value: FOREVER ) In Self Managed Mode, LSAPI_PGRP_MAX_IDLE controls how long the parent process will wait before exiting when there is no child process. This option help releasing system resources taken by an idle parent process. * LSAPI_PPID_NO_CHECK By default a LSAPI application check the existence of its parent process and exits automatically if the parent process died. This is to reduce orphan process when web server is restarted. However, it is desireable to disable this feature, such as when a LSAPI process was started manually from command line. LSAPI_PPID_NO_CHECK should be set when you want to disable the checking of existence of parent process. License ------- LSAPI library code is under BSD license LSAPI ruby extension code is under Ruby license * (()) (Japanese) * (()) (English) Copyright --------- Copyright (C) 2006 Lite Speed Technologies Inc. PKu]j2#ruby-lsapi-5.6/rails/dispatch.lsapinuȯ#!/opt/alt/ruby27/bin/ruby if GC.respond_to?(:copy_on_write_friendly=) GC.copy_on_write_friendly = true end require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) # If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: # "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired require "dispatcher" require "lsapi" while LSAPI.accept != nil Dispatcher.dispatch end PKu]MM'ruby-lsapi-5.6/scripts/lsruby_runner.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' class CodeCache def [](filename) mtime = File.mtime( filename ) entry = @cache[filename]; if entry != nil return entry end code = compile(filename) #entry = CodeEntry.new( filename, mtime, code ) @cache[filename] = code return code end private def initialize @cache = {} end def compile(filename) open(filename) do |f| s = f.read s.untaint binding = eval_string_wrap("binding") return eval(format("Proc.new {\n%s\n}", s), binding, filename, 0) end end end $count = 0; $cache = CodeCache.new while true $req = LSAPI.accept break if $req == nil filename = ENV['SCRIPT_FILENAME'] filename.untaint filename =~ %r{^(\/.*?)\/*([^\/]+)$} path = $1 Dir.chdir( path ) #load( filename, true ) code = $cache[filename] code.call end class CodeEntry public :path, :name, :mtime, :opcode def initizlize( filename, mtime, opcode ) filename =~ %r{^(\/.*?)\/*([^\/]+)$} @path = $1 @name = $2 @mtime = mtime @opcode = opcode end end PKu]##BBruby-lsapi-5.6/setup.rbnu[# # setup.rb # # Copyright (c) 2000-2005 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU LGPL, Lesser General Public License version 2.1. # unless Enumerable.method_defined?(:map) # Ruby 1.4.6 module Enumerable alias map collect end end unless File.respond_to?(:read) # Ruby 1.6 def File.read(fname) open(fname) {|f| return f.read } end end unless Errno.const_defined?(:ENOTEMPTY) # Windows? module Errno class ENOTEMPTY # We do not raise this exception, implementation is not needed. end end end def File.binread(fname) open(fname, 'rb') {|f| return f.read } end # for corrupted Windows' stat(2) def File.dir?(path) File.directory?((path[-1,1] == '/') ? path : path + '/') end class ConfigTable include Enumerable def initialize(rbconfig) @rbconfig = rbconfig @items = [] @table = {} # options @install_prefix = nil @config_opt = nil @verbose = true @no_harm = false end attr_accessor :install_prefix attr_accessor :config_opt attr_writer :verbose def verbose? @verbose end attr_writer :no_harm def no_harm? @no_harm end def [](key) lookup(key).resolve(self) end def []=(key, val) lookup(key).set val end def names @items.map {|i| i.name } end def each(&block) @items.each(&block) end def key?(name) @table.key?(name) end def lookup(name) @table[name] or setup_rb_error "no such config item: #{name}" end def add(item) @items.push item @table[item.name] = item end def remove(name) item = lookup(name) @items.delete_if {|i| i.name == name } @table.delete_if {|name, i| i.name == name } item end def load_script(path, inst = nil) if File.file?(path) MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path end end def savefile '.config' end def load_savefile begin File.foreach(savefile()) do |line| k, v = *line.split(/=/, 2) self[k] = v.strip end rescue Errno::ENOENT setup_rb_error $!.message + "\n#{File.basename($0)} config first" end end def save @items.each {|i| i.value } File.open(savefile(), 'w') {|f| @items.each do |i| f.printf "%s=%s\n", i.name, i.value if i.value? and i.value end } end def load_standard_entries standard_entries(@rbconfig).each do |ent| add ent end end def standard_entries(rbconfig) c = rbconfig rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) major = c['MAJOR'].to_i minor = c['MINOR'].to_i teeny = c['TEENY'].to_i version = "#{major}.#{minor}" # ruby ver. >= 1.4.4? newpath_p = ((major >= 2) or ((major == 1) and ((minor >= 5) or ((minor == 4) and (teeny >= 4))))) if c['rubylibdir'] # V > 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = c['rubylibdir'] librubyverarch = c['archdir'] siteruby = c['sitedir'] siterubyver = c['sitelibdir'] siterubyverarch = c['sitearchdir'] elsif newpath_p # 1.4.4 <= V <= 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = c['sitedir'] siterubyver = "$siteruby/#{version}" siterubyverarch = "$siterubyver/#{c['arch']}" else # V < 1.4.4 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" siterubyver = siteruby siterubyverarch = "$siterubyver/#{c['arch']}" end parameterize = lambda {|path| path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') } if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } makeprog = arg.sub(/'/, '').split(/=/, 2)[1] else makeprog = 'make' end [ ExecItem.new('installdirs', 'std/site/home', 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ {|val, table| case val when 'std' table['rbdir'] = '$librubyver' table['sodir'] = '$librubyverarch' when 'site' table['rbdir'] = '$siterubyver' table['sodir'] = '$siterubyverarch' when 'home' setup_rb_error '$HOME was not set' unless ENV['HOME'] table['prefix'] = ENV['HOME'] table['rbdir'] = '$libdir/ruby' table['sodir'] = '$libdir/ruby' end }, PathItem.new('prefix', 'path', c['prefix'], 'path prefix of target environment'), PathItem.new('bindir', 'path', parameterize.call(c['bindir']), 'the directory for commands'), PathItem.new('libdir', 'path', parameterize.call(c['libdir']), 'the directory for libraries'), PathItem.new('datadir', 'path', parameterize.call(c['datadir']), 'the directory for shared data'), PathItem.new('mandir', 'path', parameterize.call(c['mandir']), 'the directory for man pages'), PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), 'the directory for system configuration files'), PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), 'the directory for local state data'), PathItem.new('libruby', 'path', libruby, 'the directory for ruby libraries'), PathItem.new('librubyver', 'path', librubyver, 'the directory for standard ruby libraries'), PathItem.new('librubyverarch', 'path', librubyverarch, 'the directory for standard ruby extensions'), PathItem.new('siteruby', 'path', siteruby, 'the directory for version-independent aux ruby libraries'), PathItem.new('siterubyver', 'path', siterubyver, 'the directory for aux ruby libraries'), PathItem.new('siterubyverarch', 'path', siterubyverarch, 'the directory for aux ruby binaries'), PathItem.new('rbdir', 'path', '$siterubyver', 'the directory for ruby scripts'), PathItem.new('sodir', 'path', '$siterubyverarch', 'the directory for ruby extentions'), PathItem.new('rubypath', 'path', rubypath, 'the path to set to #! line'), ProgramItem.new('rubyprog', 'name', rubypath, 'the ruby program using for installation'), ProgramItem.new('makeprog', 'name', makeprog, 'the make program to compile ruby extentions'), SelectItem.new('shebang', 'all/ruby/never', 'ruby', 'shebang line (#!) editing mode'), BoolItem.new('without-ext', 'yes/no', 'no', 'does not compile/install ruby extentions') ] end private :standard_entries def load_multipackage_entries multipackage_entries().each do |ent| add ent end end def multipackage_entries [ PackageSelectionItem.new('with', 'name,name...', '', 'ALL', 'package names that you want to install'), PackageSelectionItem.new('without', 'name,name...', '', 'NONE', 'package names that you do not want to install') ] end private :multipackage_entries ALIASES = { 'std-ruby' => 'librubyver', 'stdruby' => 'librubyver', 'rubylibdir' => 'librubyver', 'archdir' => 'librubyverarch', 'site-ruby-common' => 'siteruby', # For backward compatibility 'site-ruby' => 'siterubyver', # For backward compatibility 'bin-dir' => 'bindir', 'bin-dir' => 'bindir', 'rb-dir' => 'rbdir', 'so-dir' => 'sodir', 'data-dir' => 'datadir', 'ruby-path' => 'rubypath', 'ruby-prog' => 'rubyprog', 'ruby' => 'rubyprog', 'make-prog' => 'makeprog', 'make' => 'makeprog' } def fixup ALIASES.each do |ali, name| @table[ali] = @table[name] end @items.freeze @table.freeze @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ end def parse_opt(opt) m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" m.to_a[1,2] end def dllext @rbconfig['DLEXT'] end def value_config?(name) lookup(name).value? end class Item def initialize(name, template, default, desc) @name = name.freeze @template = template @value = default @default = default @description = desc end attr_reader :name attr_reader :description attr_accessor :default alias help_default default def help_opt "--#{@name}=#{@template}" end def value? true end def value @value end def resolve(table) @value.gsub(%r<\$([^/]+)>) { table[$1] } end def set(val) @value = check(val) end private def check(val) setup_rb_error "config: --#{name} requires argument" unless val val end end class BoolItem < Item def config_type 'bool' end def help_opt "--#{@name}" end private def check(val) return 'yes' unless val case val when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' else setup_rb_error "config: --#{@name} accepts only yes/no for argument" end end end class PathItem < Item def config_type 'path' end private def check(path) setup_rb_error "config: --#{@name} requires argument" unless path path[0,1] == '$' ? path : File.expand_path(path) end end class ProgramItem < Item def config_type 'program' end end class SelectItem < Item def initialize(name, selection, default, desc) super @ok = selection.split('/') end def config_type 'select' end private def check(val) unless @ok.include?(val.strip) setup_rb_error "config: use --#{@name}=#{@template} (#{val})" end val.strip end end class ExecItem < Item def initialize(name, selection, desc, &block) super name, selection, nil, desc @ok = selection.split('/') @action = block end def config_type 'exec' end def value? false end def resolve(table) setup_rb_error "$#{name()} wrongly used as option value" end undef set def evaluate(val, table) v = val.strip.downcase unless @ok.include?(v) setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" end @action.call v, table end end class PackageSelectionItem < Item def initialize(name, template, default, help_default, desc) super name, template, default, desc @help_default = help_default end attr_reader :help_default def config_type 'package' end private def check(val) unless File.dir?("packages/#{val}") setup_rb_error "config: no such package: #{val}" end val end end class MetaConfigEnvironment def initialize(config, installer) @config = config @installer = installer end def config_names @config.names end def config?(name) @config.key?(name) end def bool_config?(name) @config.lookup(name).config_type == 'bool' end def path_config?(name) @config.lookup(name).config_type == 'path' end def value_config?(name) @config.lookup(name).config_type != 'exec' end def add_config(item) @config.add item end def add_bool_config(name, default, desc) @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) end def add_path_config(name, default, desc) @config.add PathItem.new(name, 'path', default, desc) end def set_config_default(name, default) @config.lookup(name).default = default end def remove_config(name) @config.remove(name) end # For only multipackage def packages raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer @installer.packages end # For only multipackage def declare_packages(list) raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer @installer.packages = list end end end # class ConfigTable # This module requires: #verbose?, #no_harm? module FileOperations def mkdir_p(dirname, prefix = nil) dirname = prefix + File.expand_path(dirname) if prefix $stderr.puts "mkdir -p #{dirname}" if verbose? return if no_harm? # Does not check '/', it's too abnormal. dirs = File.expand_path(dirname).split(%r<(?=/)>) if /\A[a-z]:\z/i =~ dirs[0] disk = dirs.shift dirs[0] = disk + dirs[0] end dirs.each_index do |idx| path = dirs[0..idx].join('') Dir.mkdir path unless File.dir?(path) end end def rm_f(path) $stderr.puts "rm -f #{path}" if verbose? return if no_harm? force_remove_file path end def rm_rf(path) $stderr.puts "rm -rf #{path}" if verbose? return if no_harm? remove_tree path end def remove_tree(path) if File.symlink?(path) remove_file path elsif File.dir?(path) remove_tree0 path else force_remove_file path end end def remove_tree0(path) Dir.foreach(path) do |ent| next if ent == '.' next if ent == '..' entpath = "#{path}/#{ent}" if File.symlink?(entpath) remove_file entpath elsif File.dir?(entpath) remove_tree0 entpath else force_remove_file entpath end end begin Dir.rmdir path rescue Errno::ENOTEMPTY # directory may not be empty end end def move_file(src, dest) force_remove_file dest begin File.rename src, dest rescue File.open(dest, 'wb') {|f| f.write File.binread(src) } File.chmod File.stat(src).mode, dest File.unlink src end end def force_remove_file(path) begin remove_file path rescue end end def remove_file(path) File.chmod 0777, path File.unlink path end def install(from, dest, mode, prefix = nil) $stderr.puts "install #{from} #{dest}" if verbose? return if no_harm? realdest = prefix ? prefix + File.expand_path(dest) : dest realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) str = File.binread(from) if diff?(str, realdest) verbose_off { rm_f realdest if File.exist?(realdest) } File.open(realdest, 'wb') {|f| f.write str } File.chmod mode, realdest File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| if prefix f.puts realdest.sub(prefix, '') else f.puts realdest end } end end def diff?(new_content, path) return true unless File.exist?(path) new_content != File.binread(path) end def command(*args) $stderr.puts args.join(' ') if verbose? system(*args) or raise RuntimeError, "system(#{args.map{|a| a.inspect }.join(' ')}) failed" end def ruby(*args) command config('rubyprog'), *args end def make(task = nil) command(*[config('makeprog'), task].compact) end def extdir?(dir) File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") end def files_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.file?("#{dir}/#{ent}") } } end DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) def directories_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT } end end # This module requires: #srcdir_root, #objdir_root, #relpath module HookScriptAPI def get_config(key) @config[key] end alias config get_config # obsolete: use metaconfig to change configuration def set_config(key, val) @config[key] = val end # # srcdir/objdir (works only in the package directory) # def curr_srcdir "#{srcdir_root()}/#{relpath()}" end def curr_objdir "#{objdir_root()}/#{relpath()}" end def srcfile(path) "#{curr_srcdir()}/#{path}" end def srcexist?(path) File.exist?(srcfile(path)) end def srcdirectory?(path) File.dir?(srcfile(path)) end def srcfile?(path) File.file?(srcfile(path)) end def srcentries(path = '.') Dir.open("#{curr_srcdir()}/#{path}") {|d| return d.to_a - %w(. ..) } end def srcfiles(path = '.') srcentries(path).select {|fname| File.file?(File.join(curr_srcdir(), path, fname)) } end def srcdirectories(path = '.') srcentries(path).select {|fname| File.dir?(File.join(curr_srcdir(), path, fname)) } end end class ToplevelInstaller Version = '3.4.1' Copyright = 'Copyright (c) 2000-2005 Minero Aoki' TASKS = [ [ 'all', 'do config, setup, then install' ], [ 'config', 'saves your configurations' ], [ 'show', 'shows current configuration' ], [ 'setup', 'compiles ruby extentions and others' ], [ 'install', 'installs files' ], [ 'test', 'run all tests in test/' ], [ 'clean', "does `make clean' for each extention" ], [ 'distclean',"does `make distclean' for each extention" ] ] def ToplevelInstaller.invoke config = ConfigTable.new(load_rbconfig()) config.load_standard_entries config.load_multipackage_entries if multipackage? config.fixup klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) klass.new(File.dirname($0), config).invoke end def ToplevelInstaller.multipackage? File.dir?(File.dirname($0) + '/packages') end def ToplevelInstaller.load_rbconfig if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } ARGV.delete(arg) load File.expand_path(arg.split(/=/, 2)[1]) $".push 'rbconfig.rb' else require 'rbconfig' end ::Config::CONFIG end def initialize(ardir_root, config) @ardir = File.expand_path(ardir_root) @config = config # cache @valid_task_re = nil end def config(key) @config[key] end def inspect "#<#{self.class} #{__id__()}>" end def invoke run_metaconfigs case task = parsearg_global() when nil, 'all' parsearg_config init_installers exec_config exec_setup exec_install else case task when 'config', 'test' ; when 'clean', 'distclean' @config.load_savefile if File.exist?(@config.savefile) else @config.load_savefile end __send__ "parsearg_#{task}" init_installers __send__ "exec_#{task}" end end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig" end def init_installers @installer = Installer.new(@config, @ardir, File.expand_path('.')) end # # Hook Script API bases # def srcdir_root @ardir end def objdir_root '.' end def relpath '.' end # # Option Parsing # def parsearg_global while arg = ARGV.shift case arg when /\A\w+\z/ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) return arg when '-q', '--quiet' @config.verbose = false when '--verbose' @config.verbose = true when '--help' print_usage $stdout exit 0 when '--version' puts "#{File.basename($0)} version #{Version}" exit 0 when '--copyright' puts Copyright exit 0 else setup_rb_error "unknown global option '#{arg}'" end end nil end def valid_task?(t) valid_task_re() =~ t end def valid_task_re @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ end def parsearg_no_options unless ARGV.empty? task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" end end alias parsearg_show parsearg_no_options alias parsearg_setup parsearg_no_options alias parsearg_test parsearg_no_options alias parsearg_clean parsearg_no_options alias parsearg_distclean parsearg_no_options def parsearg_config evalopt = [] set = [] @config.config_opt = [] while i = ARGV.shift if /\A--?\z/ =~ i @config.config_opt = ARGV.dup break end name, value = *@config.parse_opt(i) if @config.value_config?(name) @config[name] = value else evalopt.push [name, value] end set.push name end evalopt.each do |name, value| @config.lookup(name).evaluate value, @config end # Check if configuration is valid set.each do |n| @config[n] if @config.value_config?(n) end end def parsearg_install @config.no_harm = false @config.install_prefix = '' while a = ARGV.shift case a when '--no-harm' @config.no_harm = true when /\A--prefix=/ path = a.split(/=/, 2)[1] path = File.expand_path(path) unless path[0,1] == '/' @config.install_prefix = path else setup_rb_error "install: unknown option #{a}" end end end def print_usage(out) out.puts 'Typical Installation Procedure:' out.puts " $ ruby #{File.basename $0} config" out.puts " $ ruby #{File.basename $0} setup" out.puts " # ruby #{File.basename $0} install (may require root privilege)" out.puts out.puts 'Detailed Usage:' out.puts " ruby #{File.basename $0} " out.puts " ruby #{File.basename $0} [] []" fmt = " %-24s %s\n" out.puts out.puts 'Global options:' out.printf fmt, '-q,--quiet', 'suppress message outputs' out.printf fmt, ' --verbose', 'output messages verbosely' out.printf fmt, ' --help', 'print this message' out.printf fmt, ' --version', 'print version and quit' out.printf fmt, ' --copyright', 'print copyright and quit' out.puts out.puts 'Tasks:' TASKS.each do |name, desc| out.printf fmt, name, desc end fmt = " %-24s %s [%s]\n" out.puts out.puts 'Options for CONFIG or ALL:' @config.each do |item| out.printf fmt, item.help_opt, item.description, item.help_default end out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" out.puts out.puts 'Options for INSTALL:' out.printf fmt, '--no-harm', 'only display what to do if given', 'off' out.printf fmt, '--prefix=path', 'install path prefix', '' out.puts end # # Task Handlers # def exec_config @installer.exec_config @config.save # must be final end def exec_setup @installer.exec_setup end def exec_install @installer.exec_install end def exec_test @installer.exec_test end def exec_show @config.each do |i| printf "%-20s %s\n", i.name, i.value if i.value? end end def exec_clean @installer.exec_clean end def exec_distclean @installer.exec_distclean end end # class ToplevelInstaller class ToplevelInstallerMulti < ToplevelInstaller include FileOperations def initialize(ardir_root, config) super @packages = directories_of("#{@ardir}/packages") raise 'no package exists' if @packages.empty? @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig", self @packages.each do |name| @config.load_script "#{@ardir}/packages/#{name}/metaconfig" end end attr_reader :packages def packages=(list) raise 'package list is empty' if list.empty? list.each do |name| raise "directory packages/#{name} does not exist"\ unless File.dir?("#{@ardir}/packages/#{name}") end @packages = list end def init_installers @installers = {} @packages.each do |pack| @installers[pack] = Installer.new(@config, "#{@ardir}/packages/#{pack}", "packages/#{pack}") end with = extract_selection(config('with')) without = extract_selection(config('without')) @selected = @installers.keys.select {|name| (with.empty? or with.include?(name)) \ and not without.include?(name) } end def extract_selection(list) a = list.split(/,/) a.each do |name| setup_rb_error "no such package: #{name}" unless @installers.key?(name) end a end def print_usage(f) super f.puts 'Inluded packages:' f.puts ' ' + @packages.sort.join(' ') f.puts end # # Task Handlers # def exec_config run_hook 'pre-config' each_selected_installers {|inst| inst.exec_config } run_hook 'post-config' @config.save # must be final end def exec_setup run_hook 'pre-setup' each_selected_installers {|inst| inst.exec_setup } run_hook 'post-setup' end def exec_install run_hook 'pre-install' each_selected_installers {|inst| inst.exec_install } run_hook 'post-install' end def exec_test run_hook 'pre-test' each_selected_installers {|inst| inst.exec_test } run_hook 'post-test' end def exec_clean rm_f @config.savefile run_hook 'pre-clean' each_selected_installers {|inst| inst.exec_clean } run_hook 'post-clean' end def exec_distclean rm_f @config.savefile run_hook 'pre-distclean' each_selected_installers {|inst| inst.exec_distclean } run_hook 'post-distclean' end # # lib # def each_selected_installers Dir.mkdir 'packages' unless File.dir?('packages') @selected.each do |pack| $stderr.puts "Processing the package `#{pack}' ..." if verbose? Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") Dir.chdir "packages/#{pack}" yield @installers[pack] Dir.chdir '../..' end end def run_hook(id) @root_installer.run_hook id end # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end end # class ToplevelInstallerMulti class Installer FILETYPES = %w( bin lib ext data conf man ) include FileOperations include HookScriptAPI def initialize(config, srcroot, objroot) @config = config @srcdir = File.expand_path(srcroot) @objdir = File.expand_path(objroot) @currdir = '.' end def inspect "#<#{self.class} #{File.basename(@srcdir)}>" end def noop(rel) end # # Hook Script API base methods # def srcdir_root @srcdir end def objdir_root @objdir end def relpath @currdir end # # Config Access # # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end def verbose_off begin save, @config.verbose = @config.verbose?, false yield ensure @config.verbose = save end end # # TASK config # def exec_config exec_task_traverse 'config' end alias config_dir_bin noop alias config_dir_lib noop def config_dir_ext(rel) extconf if extdir?(curr_srcdir()) end alias config_dir_data noop alias config_dir_conf noop alias config_dir_man noop def extconf ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt end # # TASK setup # def exec_setup exec_task_traverse 'setup' end def setup_dir_bin(rel) files_of(curr_srcdir()).each do |fname| update_shebang_line "#{curr_srcdir()}/#{fname}" end end alias setup_dir_lib noop def setup_dir_ext(rel) make if extdir?(curr_srcdir()) end alias setup_dir_data noop alias setup_dir_conf noop alias setup_dir_man noop def update_shebang_line(path) return if no_harm? return if config('shebang') == 'never' old = Shebang.load(path) if old $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 new = new_shebang(old) return if new.to_s == old.to_s else return unless config('shebang') == 'all' new = Shebang.new(config('rubypath')) end $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? open_atomic_writer(path) {|output| File.open(path, 'rb') {|f| f.gets if old # discard output.puts new.to_s output.print f.read } } end def new_shebang(old) if /\Aruby/ =~ File.basename(old.cmd) Shebang.new(config('rubypath'), old.args) elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' Shebang.new(config('rubypath'), old.args[1..-1]) else return old unless config('shebang') == 'all' Shebang.new(config('rubypath')) end end def open_atomic_writer(path, &block) tmpfile = File.basename(path) + '.tmp' begin File.open(tmpfile, 'wb', &block) File.rename tmpfile, File.basename(path) ensure File.unlink tmpfile if File.exist?(tmpfile) end end class Shebang def Shebang.load(path) line = nil File.open(path) {|f| line = f.gets } return nil unless /\A#!/ =~ line parse(line) end def Shebang.parse(line) cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') new(cmd, args) end def initialize(cmd, args = []) @cmd = cmd @args = args end attr_reader :cmd attr_reader :args def to_s "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") end end # # TASK install # def exec_install rm_f 'InstalledFiles' exec_task_traverse 'install' end def install_dir_bin(rel) install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 end def install_dir_lib(rel) install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 end def install_dir_ext(rel) return unless extdir?(curr_srcdir()) install_files rubyextentions('.'), "#{config('sodir')}/#{File.dirname(rel)}", 0555 end def install_dir_data(rel) install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 end def install_dir_conf(rel) # FIXME: should not remove current config files # (rename previous file to .old/.org) install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 end def install_dir_man(rel) install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 end def install_files(list, dest, mode) mkdir_p dest, @config.install_prefix list.each do |fname| install fname, dest, mode, @config.install_prefix end end def libfiles glob_reject(%w(*.y *.output), targetfiles()) end def rubyextentions(dir) ents = glob_select("*.#{@config.dllext}", targetfiles()) if ents.empty? setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" end ents end def targetfiles mapdir(existfiles() - hookfiles()) end def mapdir(ents) ents.map {|ent| if File.exist?(ent) then ent # objdir else "#{curr_srcdir()}/#{ent}" # srcdir end } end # picked up many entries from cvs-1.11.1/src/ignore.c JUNK_FILES = %w( core RCSLOG tags TAGS .make.state .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$ *.org *.in .* ) def existfiles glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) end def hookfiles %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| %w( config setup install clean ).map {|t| sprintf(fmt, t) } }.flatten end def glob_select(pat, ents) re = globs2re([pat]) ents.select {|ent| re =~ ent } end def glob_reject(pats, ents) re = globs2re(pats) ents.reject {|ent| re =~ ent } end GLOB2REGEX = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' } def globs2re(pats) /\A(?:#{ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') })\z/ end # # TASK test # TESTDIR = 'test' def exec_test unless File.directory?('test') $stderr.puts 'no test in this package' if verbose? return end $stderr.puts 'Running tests...' if verbose? begin require 'test/unit' rescue LoadError setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' end runner = Test::Unit::AutoRunner.new(true) runner.to_run << TESTDIR runner.run end # # TASK clean # def exec_clean exec_task_traverse 'clean' rm_f @config.savefile rm_f 'InstalledFiles' end alias clean_dir_bin noop alias clean_dir_lib noop alias clean_dir_data noop alias clean_dir_conf noop alias clean_dir_man noop def clean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'clean' if File.file?('Makefile') end # # TASK distclean # def exec_distclean exec_task_traverse 'distclean' rm_f @config.savefile rm_f 'InstalledFiles' end alias distclean_dir_bin noop alias distclean_dir_lib noop def distclean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'distclean' if File.file?('Makefile') end alias distclean_dir_data noop alias distclean_dir_conf noop alias distclean_dir_man noop # # Traversing # def exec_task_traverse(task) run_hook "pre-#{task}" FILETYPES.each do |type| if type == 'ext' and config('without-ext') == 'yes' $stderr.puts 'skipping ext/* by user option' if verbose? next end traverse task, type, "#{task}_dir_#{type}" end run_hook "post-#{task}" end def traverse(task, rel, mid) dive_into(rel) { run_hook "pre-#{task}" __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') directories_of(curr_srcdir()).each do |d| traverse task, "#{rel}/#{d}", mid end run_hook "post-#{task}" } end def dive_into(rel) return unless File.dir?("#{@srcdir}/#{rel}") dir = File.basename(rel) Dir.mkdir dir unless File.dir?(dir) prevdir = Dir.pwd Dir.chdir dir $stderr.puts '---> ' + rel if verbose? @currdir = rel yield Dir.chdir prevdir $stderr.puts '<--- ' + rel if verbose? @currdir = File.dirname(rel) end def run_hook(id) path = [ "#{curr_srcdir()}/#{id}", "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } return unless path begin instance_eval File.read(path), path, 1 rescue raise if $DEBUG setup_rb_error "hook #{path} failed:\n" + $!.message end end end # class Installer class SetupError < StandardError; end def setup_rb_error(msg) raise SetupError, msg end if $0 == __FILE__ begin ToplevelInstaller.invoke rescue SetupError raise if $DEBUG $stderr.puts $!.message $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." exit 1 end end PKu]*  $ruby-lsapi-5.6/examples/testlsapi.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' $count = 0; while LSAPI.accept != nil print "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\nHello World! \##{$count}
    \r\n" ENV.each_pair {|key, value| print "#{key} is #{value}
    \r\n" } $count = $count + 1 end PKu])ruby-lsapi-5.6/examples/lsapi_with_cgi.rbnuȯ#!/opt/alt/ruby27/bin/ruby require 'lsapi' require 'cgi' while LSAPI.accept != nil cgi = CGI.new name = cgi['name'] puts cgi.header puts "Hello #{name}!
    " if name puts "You are from #{cgi.remote_addr}
    " end PKu]L'io-console-0.5.6/lib/io/console/size.rbnu[# frozen_string_literal: false # fallback to console window size def IO.default_console_size [ ENV["LINES"].to_i.nonzero? || 25, ENV["COLUMNS"].to_i.nonzero? || 80, ] end begin require 'io/console' rescue LoadError class << IO alias console_size default_console_size end else # returns console window size def IO.console_size console.winsize rescue NoMethodError default_console_size end end PKu]B^openssl-2.1.4/lib/openssl/bn.rbnu[# frozen_string_literal: false #-- # # = Ruby-space definitions that completes C-space funcs for BN # # = Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2002 Michal Rokos # All rights reserved. # # = Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ module OpenSSL class BN include Comparable def pretty_print(q) q.object_group(self) { q.text ' ' q.text to_i.to_s } end end # BN end # OpenSSL ## #-- # Add double dispatch to Integer #++ class Integer # Casts an Integer as an OpenSSL::BN # # See `man bn` for more info. def to_bn OpenSSL::BN::new(self) end end # Integer PKu]w+D#openssl-2.1.4/lib/openssl/cipher.rbnu[# frozen_string_literal: false #-- # = Ruby-space predefined Cipher subclasses # # = Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2002 Michal Rokos # All rights reserved. # # = Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ module OpenSSL class Cipher %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name| klass = Class.new(Cipher){ define_method(:initialize){|*args| cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" } super(cipher_name.downcase) } } const_set(name, klass) } %w(128 192 256).each{|keylen| klass = Class.new(Cipher){ define_method(:initialize){|mode = "CBC"| super("aes-#{keylen}-#{mode}".downcase) } } const_set("AES#{keylen}", klass) } # call-seq: # cipher.random_key -> key # # Generate a random key with OpenSSL::Random.random_bytes and sets it to # the cipher, and returns it. # # You must call #encrypt or #decrypt before calling this method. def random_key str = OpenSSL::Random.random_bytes(self.key_len) self.key = str end # call-seq: # cipher.random_iv -> iv # # Generate a random IV with OpenSSL::Random.random_bytes and sets it to the # cipher, and returns it. # # You must call #encrypt or #decrypt before calling this method. def random_iv str = OpenSSL::Random.random_bytes(self.iv_len) self.iv = str end # Deprecated. # # This class is only provided for backwards compatibility. # Use OpenSSL::Cipher. class Cipher < Cipher; end deprecate_constant :Cipher end # Cipher end # OpenSSL PKu]̒O?? openssl-2.1.4/lib/openssl/ssl.rbnu[# frozen_string_literal: false =begin = Info 'OpenSSL for Ruby 2' project Copyright (C) 2001 GOTOU YUUZOU All rights reserved. = Licence This program is licensed under the same licence as Ruby. (See the file 'LICENCE'.) =end require "openssl/buffering" require "io/nonblock" require "ipaddr" module OpenSSL module SSL class SSLContext DEFAULT_PARAMS = { # :nodoc: :min_version => OpenSSL::SSL::TLS1_VERSION, :verify_mode => OpenSSL::SSL::VERIFY_PEER, :verify_hostname => true, :options => -> { opts = OpenSSL::SSL::OP_ALL opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS opts |= OpenSSL::SSL::OP_NO_COMPRESSION opts }.call } if defined?(OpenSSL::PKey::DH) DEFAULT_2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_ -----BEGIN DH PARAMETERS----- MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6 YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3 1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD 7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg== -----END DH PARAMETERS----- _end_of_pem_ private_constant :DEFAULT_2048 DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc: warn "using default DH parameters." if $VERBOSE DEFAULT_2048 } end if !(OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL") && OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000) DEFAULT_PARAMS.merge!( ciphers: %w{ ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-DSS-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-DSS-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA DHE-DSS-AES128-SHA256 DHE-DSS-AES256-SHA256 DHE-DSS-AES128-SHA DHE-DSS-AES256-SHA AES128-GCM-SHA256 AES256-GCM-SHA384 AES128-SHA256 AES256-SHA256 AES128-SHA AES256-SHA }.join(":"), ) end DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc: DEFAULT_CERT_STORE.set_default_paths DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL # A callback invoked when DH parameters are required. # # The callback is invoked with the Session for the key exchange, an # flag indicating the use of an export cipher and the keylength # required. # # The callback must return an OpenSSL::PKey::DH instance of the correct # key length. attr_accessor :tmp_dh_callback # A callback invoked at connect time to distinguish between multiple # server names. # # The callback is invoked with an SSLSocket and a server name. The # callback must return an SSLContext for the server name or nil. attr_accessor :servername_cb # call-seq: # SSLContext.new -> ctx # SSLContext.new(:TLSv1) -> ctx # SSLContext.new("SSLv23") -> ctx # # Creates a new SSL context. # # If an argument is given, #ssl_version= is called with the value. Note # that this form is deprecated. New applications should use #min_version= # and #max_version= as necessary. def initialize(version = nil) self.options |= OpenSSL::SSL::OP_ALL self.ssl_version = version if version end ## # call-seq: # ctx.set_params(params = {}) -> params # # Sets saner defaults optimized for the use with HTTP-like protocols. # # If a Hash _params_ is given, the parameters are overridden with it. # The keys in _params_ must be assignment methods on SSLContext. # # If the verify_mode is not VERIFY_NONE and ca_file, ca_path and # cert_store are not set then the system default certificate store is # used. def set_params(params={}) params = DEFAULT_PARAMS.merge(params) self.options = params.delete(:options) # set before min_version/max_version params.each{|name, value| self.__send__("#{name}=", value) } if self.verify_mode != OpenSSL::SSL::VERIFY_NONE unless self.ca_file or self.ca_path or self.cert_store self.cert_store = DEFAULT_CERT_STORE end end return params end # call-seq: # ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION # ctx.min_version = :TLS1_2 # ctx.min_version = nil # # Sets the lower bound on the supported SSL/TLS protocol version. The # version may be specified by an integer constant named # OpenSSL::SSL::*_VERSION, a Symbol, or +nil+ which means "any version". # # Be careful that you don't overwrite OpenSSL::SSL::OP_NO_{SSL,TLS}v* # options by #options= once you have called #min_version= or # #max_version=. # # === Example # ctx = OpenSSL::SSL::SSLContext.new # ctx.min_version = OpenSSL::SSL::TLS1_1_VERSION # ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION # # sock = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx) # sock.connect # Initiates a connection using either TLS 1.1 or TLS 1.2 def min_version=(version) set_minmax_proto_version(version, @max_proto_version ||= nil) @min_proto_version = version end # call-seq: # ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION # ctx.max_version = :TLS1_2 # ctx.max_version = nil # # Sets the upper bound of the supported SSL/TLS protocol version. See # #min_version= for the possible values. def max_version=(version) set_minmax_proto_version(@min_proto_version ||= nil, version) @max_proto_version = version end # call-seq: # ctx.ssl_version = :TLSv1 # ctx.ssl_version = "SSLv23" # # Sets the SSL/TLS protocol version for the context. This forces # connections to use only the specified protocol version. This is # deprecated and only provided for backwards compatibility. Use # #min_version= and #max_version= instead. # # === History # As the name hints, this used to call the SSL_CTX_set_ssl_version() # function which sets the SSL method used for connections created from # the context. As of Ruby/OpenSSL 2.1, this accessor method is # implemented to call #min_version= and #max_version= instead. def ssl_version=(meth) meth = meth.to_s if meth.is_a?(Symbol) if /(?_client|_server)\z/ =~ meth meth = $` if $VERBOSE warn "#{caller(1, 1)[0]}: method type #{type.inspect} is ignored" end end version = METHODS_MAP[meth.intern] or raise ArgumentError, "unknown SSL method `%s'" % meth set_minmax_proto_version(version, version) @min_proto_version = @max_proto_version = version end METHODS_MAP = { SSLv23: 0, SSLv2: OpenSSL::SSL::SSL2_VERSION, SSLv3: OpenSSL::SSL::SSL3_VERSION, TLSv1: OpenSSL::SSL::TLS1_VERSION, TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION, TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION, }.freeze private_constant :METHODS_MAP # The list of available SSL/TLS methods. This constant is only provided # for backwards compatibility. METHODS = METHODS_MAP.flat_map { |name,| [name, :"#{name}_client", :"#{name}_server"] }.freeze deprecate_constant :METHODS end module SocketForwarder def addr to_io.addr end def peeraddr to_io.peeraddr end def setsockopt(level, optname, optval) to_io.setsockopt(level, optname, optval) end def getsockopt(level, optname) to_io.getsockopt(level, optname) end def fcntl(*args) to_io.fcntl(*args) end def closed? to_io.closed? end def do_not_reverse_lookup=(flag) to_io.do_not_reverse_lookup = flag end end def verify_certificate_identity(cert, hostname) should_verify_common_name = true cert.extensions.each{|ext| next if ext.oid != "subjectAltName" ostr = OpenSSL::ASN1.decode(ext.to_der).value.last sequence = OpenSSL::ASN1.decode(ostr.value) sequence.value.each{|san| case san.tag when 2 # dNSName in GeneralName (RFC5280) should_verify_common_name = false return true if verify_hostname(hostname, san.value) when 7 # iPAddress in GeneralName (RFC5280) should_verify_common_name = false if san.value.size == 4 || san.value.size == 16 begin return true if san.value == IPAddr.new(hostname).hton rescue IPAddr::InvalidAddressError end end end } } if should_verify_common_name cert.subject.to_a.each{|oid, value| if oid == "CN" return true if verify_hostname(hostname, value) end } end return false end module_function :verify_certificate_identity def verify_hostname(hostname, san) # :nodoc: # RFC 5280, IA5String is limited to the set of ASCII characters return false unless san.ascii_only? return false unless hostname.ascii_only? # See RFC 6125, section 6.4.1 # Matching is case-insensitive. san_parts = san.downcase.split(".") # TODO: this behavior should probably be more strict return san == hostname if san_parts.size < 2 # Matching is case-insensitive. host_parts = hostname.downcase.split(".") # RFC 6125, section 6.4.3, subitem 2. # If the wildcard character is the only character of the left-most # label in the presented identifier, the client SHOULD NOT compare # against anything but the left-most label of the reference # identifier (e.g., *.example.com would match foo.example.com but # not bar.foo.example.com or example.com). return false unless san_parts.size == host_parts.size # RFC 6125, section 6.4.3, subitem 1. # The client SHOULD NOT attempt to match a presented identifier in # which the wildcard character comprises a label other than the # left-most label (e.g., do not match bar.*.example.net). return false unless verify_wildcard(host_parts.shift, san_parts.shift) san_parts.join(".") == host_parts.join(".") end module_function :verify_hostname def verify_wildcard(domain_component, san_component) # :nodoc: parts = san_component.split("*", -1) return false if parts.size > 2 return san_component == domain_component if parts.size == 1 # RFC 6125, section 6.4.3, subitem 3. # The client SHOULD NOT attempt to match a presented identifier # where the wildcard character is embedded within an A-label or # U-label of an internationalized domain name. return false if domain_component.start_with?("xn--") && san_component != "*" parts[0].length + parts[1].length < domain_component.length && domain_component.start_with?(parts[0]) && domain_component.end_with?(parts[1]) end module_function :verify_wildcard class SSLSocket include Buffering include SocketForwarder attr_reader :hostname # The underlying IO object. attr_reader :io alias :to_io :io # The SSLContext object used in this connection. attr_reader :context # Whether to close the underlying socket as well, when the SSL/TLS # connection is shut down. This defaults to +false+. attr_accessor :sync_close # call-seq: # ssl.sysclose => nil # # Sends "close notify" to the peer and tries to shut down the SSL # connection gracefully. # # If sync_close is set to +true+, the underlying IO is also closed. def sysclose return if closed? stop io.close if sync_close end # call-seq: # ssl.post_connection_check(hostname) -> true # # Perform hostname verification following RFC 6125. # # This method MUST be called after calling #connect to ensure that the # hostname of a remote peer has been verified. def post_connection_check(hostname) if peer_cert.nil? msg = "Peer verification enabled, but no certificate received." if using_anon_cipher? msg += " Anonymous cipher suite #{cipher[0]} was negotiated. " \ "Anonymous suites must be disabled to use peer verification." end raise SSLError, msg end unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname) raise SSLError, "hostname \"#{hostname}\" does not match the server certificate" end return true end # call-seq: # ssl.session -> aSession # # Returns the SSLSession object currently used, or nil if the session is # not established. def session SSL::Session.new(self) rescue SSL::Session::SessionError nil end private def using_anon_cipher? ctx = OpenSSL::SSL::SSLContext.new ctx.ciphers = "aNULL" ctx.ciphers.include?(cipher) end def client_cert_cb @context.client_cert_cb end def tmp_dh_callback @context.tmp_dh_callback || OpenSSL::SSL::SSLContext::DEFAULT_TMP_DH_CALLBACK end def tmp_ecdh_callback @context.tmp_ecdh_callback end def session_new_cb @context.session_new_cb end def session_get_cb @context.session_get_cb end end ## # SSLServer represents a TCP/IP server socket with Secure Sockets Layer. class SSLServer include SocketForwarder # When true then #accept works exactly the same as TCPServer#accept attr_accessor :start_immediately # Creates a new instance of SSLServer. # * _srv_ is an instance of TCPServer. # * _ctx_ is an instance of OpenSSL::SSL::SSLContext. def initialize(svr, ctx) @svr = svr @ctx = ctx unless ctx.session_id_context # see #6137 - session id may not exceed 32 bytes prng = ::Random.new($0.hash) session_id = prng.bytes(16).unpack('H*')[0] @ctx.session_id_context = session_id end @start_immediately = true end # Returns the TCPServer passed to the SSLServer when initialized. def to_io @svr end # See TCPServer#listen for details. def listen(backlog=5) @svr.listen(backlog) end # See BasicSocket#shutdown for details. def shutdown(how=Socket::SHUT_RDWR) @svr.shutdown(how) end # Works similar to TCPServer#accept. def accept # Socket#accept returns [socket, addrinfo]. # TCPServer#accept returns a socket. # The following comma strips addrinfo. sock, = @svr.accept begin ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) ssl.sync_close = true ssl.accept if @start_immediately ssl rescue Exception => ex if ssl ssl.close else sock.close end raise ex end end # See IO#close for details. def close @svr.close end end end end PKu]S:_CC!openssl-2.1.4/lib/openssl/x509.rbnu[# frozen_string_literal: false #-- # = Ruby-space definitions that completes C-space funcs for X509 and subclasses # # = Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2002 Michal Rokos # All rights reserved. # # = Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ module OpenSSL module X509 class ExtensionFactory def create_extension(*arg) if arg.size > 1 create_ext(*arg) else send("create_ext_from_"+arg[0].class.name.downcase, arg[0]) end end def create_ext_from_array(ary) raise ExtensionError, "unexpected array form" if ary.size > 3 create_ext(ary[0], ary[1], ary[2]) end def create_ext_from_string(str) # "oid = critical, value" oid, value = str.split(/=/, 2) oid.strip! value.strip! create_ext(oid, value) end def create_ext_from_hash(hash) create_ext(hash["oid"], hash["value"], hash["critical"]) end end class Extension def ==(other) return false unless Extension === other to_der == other.to_der end def to_s # "oid = critical, value" str = self.oid str << " = " str << "critical, " if self.critical? str << self.value.gsub(/\n/, ", ") end def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false} {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?} end def to_a [ self.oid, self.value, self.critical? ] end end class Name module RFC2253DN Special = ',=+<>#;' HexChar = /[0-9a-fA-F]/ HexPair = /#{HexChar}#{HexChar}/ HexString = /#{HexPair}+/ Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/ StringChar = /[^\\"#{Special}]/ QuoteChar = /[^\\"]/ AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/ AttributeValue = / (?!["#])((?:#{StringChar}|#{Pair})*)| \#(#{HexString})| "((?:#{QuoteChar}|#{Pair})*)" /x TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/ module_function def expand_pair(str) return nil unless str return str.gsub(Pair){ pair = $& case pair.size when 2 then pair[1,1] when 3 then Integer("0x#{pair[1,2]}").chr else raise OpenSSL::X509::NameError, "invalid pair: #{str}" end } end def expand_hexstring(str) return nil unless str der = str.gsub(HexPair){$&.to_i(16).chr } a1 = OpenSSL::ASN1.decode(der) return a1.value, a1.tag end def expand_value(str1, str2, str3) value = expand_pair(str1) value, tag = expand_hexstring(str2) unless value value = expand_pair(str3) unless value return value, tag end def scan(dn) str = dn ary = [] while true if md = TypeAndValue.match(str) remain = md.post_match type = md[1] value, tag = expand_value(md[2], md[3], md[4]) rescue nil if value type_and_value = [type, value] type_and_value.push(tag) if tag ary.unshift(type_and_value) if remain.length > 2 && remain[0] == ?, str = remain[1..-1] next elsif remain.length > 2 && remain[0] == ?+ raise OpenSSL::X509::NameError, "multi-valued RDN is not supported: #{dn}" elsif remain.empty? break end end end msg_dn = dn[0, dn.length - str.length] + " =>" + str raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}" end return ary end end class << self def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE) ary = OpenSSL::X509::Name::RFC2253DN.scan(str) self.new(ary, template) end def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE) if str.start_with?("/") # /A=B/C=D format ary = str[1..-1].split("/").map { |i| i.split("=", 2) } else # Comma-separated ary = str.split(",").map { |i| i.strip.split("=", 2) } end self.new(ary, template) end alias parse parse_openssl end def pretty_print(q) q.object_group(self) { q.text ' ' q.text to_s(OpenSSL::X509::Name::RFC2253) } end end class Attribute def ==(other) return false unless Attribute === other to_der == other.to_der end end class StoreContext def cleanup warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE end end class Certificate def pretty_print(q) q.object_group(self) { q.breakable q.text 'subject='; q.pp self.subject; q.text ','; q.breakable q.text 'issuer='; q.pp self.issuer; q.text ','; q.breakable q.text 'serial='; q.pp self.serial; q.text ','; q.breakable q.text 'not_before='; q.pp self.not_before; q.text ','; q.breakable q.text 'not_after='; q.pp self.not_after } end end class CRL def ==(other) return false unless CRL === other to_der == other.to_der end end class Revoked def ==(other) return false unless Revoked === other to_der == other.to_der end end class Request def ==(other) return false unless Request === other to_der == other.to_der end end end end PKu]I1!openssl-2.1.4/lib/openssl/pkey.rbnu[# frozen_string_literal: false #-- # Ruby/OpenSSL Project # Copyright (C) 2017 Ruby/OpenSSL Project Authors #++ module OpenSSL::PKey if defined?(EC) class EC::Point # :call-seq: # point.to_bn([conversion_form]) -> OpenSSL::BN # # Returns the octet string representation of the EC point as an instance of # OpenSSL::BN. # # If _conversion_form_ is not given, the _point_conversion_form_ attribute # set to the group is used. # # See #to_octet_string for more information. def to_bn(conversion_form = group.point_conversion_form) OpenSSL::BN.new(to_octet_string(conversion_form), 2) end end end end PKu]Mff"openssl-2.1.4/lib/openssl/pkcs5.rbnu[# frozen_string_literal: false #-- # Ruby/OpenSSL Project # Copyright (C) 2017 Ruby/OpenSSL Project Authors #++ module OpenSSL module PKCS5 module_function # OpenSSL::PKCS5.pbkdf2_hmac has been renamed to OpenSSL::KDF.pbkdf2_hmac. # This method is provided for backwards compatibility. def pbkdf2_hmac(pass, salt, iter, keylen, digest) OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter, length: keylen, hash: digest) end def pbkdf2_hmac_sha1(pass, salt, iter, keylen) pbkdf2_hmac(pass, salt, iter, keylen, "sha1") end end end PKu]d Ҽ&&&openssl-2.1.4/lib/openssl/buffering.rbnu[# coding: binary # frozen_string_literal: false #-- #= Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2001 GOTOU YUUZOU # All rights reserved. # #= Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ ## # OpenSSL IO buffering mix-in module. # # This module allows an OpenSSL::SSL::SSLSocket to behave like an IO. # # You typically won't use this module directly, you can see it implemented in # OpenSSL::SSL::SSLSocket. module OpenSSL::Buffering include Enumerable ## # The "sync mode" of the SSLSocket. # # See IO#sync for full details. attr_accessor :sync ## # Default size to read from or write to the SSLSocket for buffer operations. BLOCK_SIZE = 1024*16 ## # Creates an instance of OpenSSL's buffering IO module. def initialize(*) super @eof = false @rbuffer = "" @sync = @io.sync end # # for reading. # private ## # Fills the buffer from the underlying SSLSocket def fill_rbuff begin @rbuffer << self.sysread(BLOCK_SIZE) rescue Errno::EAGAIN retry rescue EOFError @eof = true end end ## # Consumes _size_ bytes from the buffer def consume_rbuff(size=nil) if @rbuffer.empty? nil else size = @rbuffer.size unless size ret = @rbuffer[0, size] @rbuffer[0, size] = "" ret end end public ## # Reads _size_ bytes from the stream. If _buf_ is provided it must # reference a string which will receive the data. # # See IO#read for full details. def read(size=nil, buf=nil) if size == 0 if buf buf.clear return buf else return "" end end until @eof break if size && size <= @rbuffer.size fill_rbuff end ret = consume_rbuff(size) || "" if buf buf.replace(ret) ret = buf end (size && ret.empty?) ? nil : ret end ## # Reads at most _maxlen_ bytes from the stream. If _buf_ is provided it # must reference a string which will receive the data. # # See IO#readpartial for full details. def readpartial(maxlen, buf=nil) if maxlen == 0 if buf buf.clear return buf else return "" end end if @rbuffer.empty? begin return sysread(maxlen, buf) rescue Errno::EAGAIN retry end end ret = consume_rbuff(maxlen) if buf buf.replace(ret) ret = buf end ret end ## # Reads at most _maxlen_ bytes in the non-blocking manner. # # When no data can be read without blocking it raises # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable. # # IO::WaitReadable means SSL needs to read internally so read_nonblock # should be called again when the underlying IO is readable. # # IO::WaitWritable means SSL needs to write internally so read_nonblock # should be called again after the underlying IO is writable. # # OpenSSL::Buffering#read_nonblock needs two rescue clause as follows: # # # emulates blocking read (readpartial). # begin # result = ssl.read_nonblock(maxlen) # rescue IO::WaitReadable # IO.select([io]) # retry # rescue IO::WaitWritable # IO.select(nil, [io]) # retry # end # # Note that one reason that read_nonblock writes to the underlying IO is # when the peer requests a new TLS/SSL handshake. See openssl the FAQ for # more details. http://www.openssl.org/support/faq.html # # By specifying a keyword argument _exception_ to +false+, you can indicate # that read_nonblock should not raise an IO::Wait*able exception, but # return the symbol +:wait_writable+ or +:wait_readable+ instead. At EOF, # it will return +nil+ instead of raising EOFError. def read_nonblock(maxlen, buf=nil, exception: true) if maxlen == 0 if buf buf.clear return buf else return "" end end if @rbuffer.empty? return sysread_nonblock(maxlen, buf, exception: exception) end ret = consume_rbuff(maxlen) if buf buf.replace(ret) ret = buf end ret end ## # Reads the next "line" from the stream. Lines are separated by _eol_. If # _limit_ is provided the result will not be longer than the given number of # bytes. # # _eol_ may be a String or Regexp. # # Unlike IO#gets the line read will not be assigned to +$_+. # # Unlike IO#gets the separator must be provided if a limit is provided. def gets(eol=$/, limit=nil) idx = @rbuffer.index(eol) until @eof break if idx fill_rbuff idx = @rbuffer.index(eol) end if eol.is_a?(Regexp) size = idx ? idx+$&.size : nil else size = idx ? idx+eol.size : nil end if size && limit && limit >= 0 size = [size, limit].min end consume_rbuff(size) end ## # Executes the block for every line in the stream where lines are separated # by _eol_. # # See also #gets def each(eol=$/) while line = self.gets(eol) yield line end end alias each_line each ## # Reads lines from the stream which are separated by _eol_. # # See also #gets def readlines(eol=$/) ary = [] while line = self.gets(eol) ary << line end ary end ## # Reads a line from the stream which is separated by _eol_. # # Raises EOFError if at end of file. def readline(eol=$/) raise EOFError if eof? gets(eol) end ## # Reads one character from the stream. Returns nil if called at end of # file. def getc read(1) end ## # Calls the given block once for each byte in the stream. def each_byte # :yields: byte while c = getc yield(c.ord) end end ## # Reads a one-character string from the stream. Raises an EOFError at end # of file. def readchar raise EOFError if eof? getc end ## # Pushes character _c_ back onto the stream such that a subsequent buffered # character read will return it. # # Unlike IO#getc multiple bytes may be pushed back onto the stream. # # Has no effect on unbuffered reads (such as #sysread). def ungetc(c) @rbuffer[0,0] = c.chr end ## # Returns true if the stream is at file which means there is no more data to # be read. def eof? fill_rbuff if !@eof && @rbuffer.empty? @eof && @rbuffer.empty? end alias eof eof? # # for writing. # private ## # Writes _s_ to the buffer. When the buffer is full or #sync is true the # buffer is flushed to the underlying socket. def do_write(s) @wbuffer = "" unless defined? @wbuffer @wbuffer << s @wbuffer.force_encoding(Encoding::BINARY) @sync ||= false if @sync or @wbuffer.size > BLOCK_SIZE until @wbuffer.empty? begin nwrote = syswrite(@wbuffer) rescue Errno::EAGAIN retry end @wbuffer[0, nwrote] = "" end end end public ## # Writes _s_ to the stream. If the argument is not a String it will be # converted using +.to_s+ method. Returns the number of bytes written. def write(*s) s.inject(0) do |written, str| do_write(str) written + str.bytesize end end ## # Writes _s_ in the non-blocking manner. # # If there is buffered data, it is flushed first. This may block. # # write_nonblock returns number of bytes written to the SSL connection. # # When no data can be written without blocking it raises # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable. # # IO::WaitReadable means SSL needs to read internally so write_nonblock # should be called again after the underlying IO is readable. # # IO::WaitWritable means SSL needs to write internally so write_nonblock # should be called again after underlying IO is writable. # # So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows. # # # emulates blocking write. # begin # result = ssl.write_nonblock(str) # rescue IO::WaitReadable # IO.select([io]) # retry # rescue IO::WaitWritable # IO.select(nil, [io]) # retry # end # # Note that one reason that write_nonblock reads from the underlying IO # is when the peer requests a new TLS/SSL handshake. See the openssl FAQ # for more details. http://www.openssl.org/support/faq.html # # By specifying a keyword argument _exception_ to +false+, you can indicate # that write_nonblock should not raise an IO::Wait*able exception, but # return the symbol +:wait_writable+ or +:wait_readable+ instead. def write_nonblock(s, exception: true) flush syswrite_nonblock(s, exception: exception) end ## # Writes _s_ to the stream. _s_ will be converted to a String using # +.to_s+ method. def <<(s) do_write(s) self end ## # Writes _args_ to the stream along with a record separator. # # See IO#puts for full details. def puts(*args) s = "" if args.empty? s << "\n" end args.each{|arg| s << arg.to_s s.sub!(/(? = Licence This program is licensed under the same licence as Ruby. (See the file 'LICENCE'.) =end require 'stringio' module OpenSSL ## # = OpenSSL::Config # # Configuration for the openssl library. # # Many system's installation of openssl library will depend on your system # configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for # the location of the file for your host. # # See also http://www.openssl.org/docs/apps/config.html class Config include Enumerable class << self ## # Parses a given _string_ as a blob that contains configuration for # OpenSSL. # # If the source of the IO is a file, then consider using #parse_config. def parse(string) c = new() parse_config(StringIO.new(string)).each do |section, hash| c[section] = hash end c end ## # load is an alias to ::new alias load new ## # Parses the configuration data read from _io_, see also #parse. # # Raises a ConfigError on invalid configuration data. def parse_config(io) begin parse_config_lines(io) rescue ConfigError => e e.message.replace("error in line #{io.lineno}: " + e.message) raise end end def get_key_string(data, section, key) # :nodoc: if v = data[section] && data[section][key] return v elsif section == 'ENV' if v = ENV[key] return v end end if v = data['default'] && data['default'][key] return v end end private def parse_config_lines(io) section = 'default' data = {section => {}} io_stack = [io] while definition = get_definition(io_stack) definition = clear_comments(definition) next if definition.empty? case definition when /\A\[/ if /\[([^\]]*)\]/ =~ definition section = $1.strip data[section] ||= {} else raise ConfigError, "missing close square bracket" end when /\A\.include (\s*=\s*)?(.+)\z/ path = $2 if File.directory?(path) files = Dir.glob(File.join(path, "*.{cnf,conf}"), File::FNM_EXTGLOB) else files = [path] end files.each do |filename| begin io_stack << StringIO.new(File.read(filename)) rescue raise ConfigError, "could not include file '%s'" % filename end end when /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ if $2 section = $1 key = $2 else key = $1 end value = unescape_value(data, section, $3) (data[section] ||= {})[key] = value.strip else raise ConfigError, "missing equal sign" end end data end # escape with backslash QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/ # escape with backslash and doubled dq QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/ # escaped char map ESCAPE_MAP = { "r" => "\r", "n" => "\n", "b" => "\b", "t" => "\t", } def unescape_value(data, section, value) scanned = [] while m = value.match(/['"\\$]/) scanned << m.pre_match c = m[0] value = m.post_match case c when "'" if m = value.match(QUOTE_REGEXP_SQ) scanned << m[1].gsub(/\\(.)/, '\\1') value = m.post_match else break end when '"' if m = value.match(QUOTE_REGEXP_DQ) scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1') value = m.post_match else break end when "\\" c = value.slice!(0, 1) scanned << (ESCAPE_MAP[c] || c) when "$" ref, value = extract_reference(value) refsec = section if ref.index('::') refsec, ref = ref.split('::', 2) end if v = get_key_string(data, refsec, ref) scanned << v else raise ConfigError, "variable has no value" end else raise 'must not reaced' end end scanned << value scanned.join end def extract_reference(value) rest = '' if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/) value = m[1] || m[2] rest = m.post_match elsif [?(, ?{].include?(value[0]) raise ConfigError, "no close brace" end if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/) return m[0], m.post_match + rest else raise end end def clear_comments(line) # FCOMMENT if m = line.match(/\A([\t\n\f ]*);.*\z/) return m[1] end # COMMENT scanned = [] while m = line.match(/[#'"\\]/) scanned << m.pre_match c = m[0] line = m.post_match case c when '#' line = nil break when "'", '"' regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ scanned << c if m = line.match(regexp) scanned << m[0] line = m.post_match else scanned << line line = nil break end when "\\" scanned << c scanned << line.slice!(0, 1) else raise 'must not reaced' end end scanned << line scanned.join end def get_definition(io_stack) if line = get_line(io_stack) while /[^\\]\\\z/ =~ line if extra = get_line(io_stack) line += extra else break end end return line.strip end end def get_line(io_stack) while io = io_stack.last if line = io.gets return line.gsub(/[\r\n]*/, '') end io_stack.pop end end end ## # Creates an instance of OpenSSL's configuration class. # # This can be used in contexts like OpenSSL::X509::ExtensionFactory.config= # # If the optional _filename_ parameter is provided, then it is read in and # parsed via #parse_config. # # This can raise IO exceptions based on the access, or availability of the # file. A ConfigError exception may be raised depending on the validity of # the data being configured. # def initialize(filename = nil) @data = {} if filename File.open(filename.to_s) do |file| Config.parse_config(file).each do |section, hash| self[section] = hash end end end end ## # Gets the value of _key_ from the given _section_ # # Given the following configurating file being loaded: # # config = OpenSSL::Config.load('foo.cnf') # #=> # # puts config.to_s # #=> [ default ] # # foo=bar # # You can get a specific value from the config if you know the _section_ # and _key_ like so: # # config.get_value('default','foo') # #=> "bar" # def get_value(section, key) if section.nil? raise TypeError.new('nil not allowed') end section = 'default' if section.empty? get_key_string(section, key) end ## # # *Deprecated* # # Use #get_value instead def value(arg1, arg2 = nil) # :nodoc: warn('Config#value is deprecated; use Config#get_value') if arg2.nil? section, key = 'default', arg1 else section, key = arg1, arg2 end section ||= 'default' section = 'default' if section.empty? get_key_string(section, key) end ## # Set the target _key_ with a given _value_ under a specific _section_. # # Given the following configurating file being loaded: # # config = OpenSSL::Config.load('foo.cnf') # #=> # # puts config.to_s # #=> [ default ] # # foo=bar # # You can set the value of _foo_ under the _default_ section to a new # value: # # config.add_value('default', 'foo', 'buzz') # #=> "buzz" # puts config.to_s # #=> [ default ] # # foo=buzz # def add_value(section, key, value) check_modify (@data[section] ||= {})[key] = value end ## # Get a specific _section_ from the current configuration # # Given the following configurating file being loaded: # # config = OpenSSL::Config.load('foo.cnf') # #=> # # puts config.to_s # #=> [ default ] # # foo=bar # # You can get a hash of the specific section like so: # # config['default'] # #=> {"foo"=>"bar"} # def [](section) @data[section] || {} end ## # Deprecated # # Use #[] instead def section(name) # :nodoc: warn('Config#section is deprecated; use Config#[]') @data[name] || {} end ## # Sets a specific _section_ name with a Hash _pairs_. # # Given the following configuration being created: # # config = OpenSSL::Config.new # #=> # # config['default'] = {"foo"=>"bar","baz"=>"buz"} # #=> {"foo"=>"bar", "baz"=>"buz"} # puts config.to_s # #=> [ default ] # # foo=bar # # baz=buz # # It's important to note that this will essentially merge any of the keys # in _pairs_ with the existing _section_. For example: # # config['default'] # #=> {"foo"=>"bar", "baz"=>"buz"} # config['default'] = {"foo" => "changed"} # #=> {"foo"=>"changed"} # config['default'] # #=> {"foo"=>"changed", "baz"=>"buz"} # def []=(section, pairs) check_modify @data[section] ||= {} pairs.each do |key, value| self.add_value(section, key, value) end end ## # Get the names of all sections in the current configuration def sections @data.keys end ## # Get the parsable form of the current configuration # # Given the following configuration being created: # # config = OpenSSL::Config.new # #=> # # config['default'] = {"foo"=>"bar","baz"=>"buz"} # #=> {"foo"=>"bar", "baz"=>"buz"} # puts config.to_s # #=> [ default ] # # foo=bar # # baz=buz # # You can parse get the serialized configuration using #to_s and then parse # it later: # # serialized_config = config.to_s # # much later... # new_config = OpenSSL::Config.parse(serialized_config) # #=> # # puts new_config # #=> [ default ] # foo=bar # baz=buz # def to_s ary = [] @data.keys.sort.each do |section| ary << "[ #{section} ]\n" @data[section].keys.each do |key| ary << "#{key}=#{@data[section][key]}\n" end ary << "\n" end ary.join end ## # For a block. # # Receive the section and its pairs for the current configuration. # # config.each do |section, key, value| # # ... # end # def each @data.each do |section, hash| hash.each do |key, value| yield [section, key, value] end end end ## # String representation of this configuration object, including the class # name and its sections. def inspect "#<#{self.class.name} sections=#{sections.inspect}>" end protected def data # :nodoc: @data end private def initialize_copy(other) @data = other.data.dup end def check_modify raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen? end def get_key_string(section, key) Config.get_key_string(@data, section, key) end end end PKu]#openssl-2.1.4/lib/openssl/digest.rbnu[# frozen_string_literal: false #-- # = Ruby-space predefined Digest subclasses # # = Info # 'OpenSSL for Ruby 2' project # Copyright (C) 2002 Michal Rokos # All rights reserved. # # = Licence # This program is licensed under the same licence as Ruby. # (See the file 'LICENCE'.) #++ module OpenSSL class Digest alg = %w(MD2 MD4 MD5 MDC2 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512) if OPENSSL_VERSION_NUMBER < 0x10100000 alg += %w(DSS DSS1 SHA) end # Return the hash value computed with _name_ Digest. _name_ is either the # long name or short name of a supported digest algorithm. # # === Examples # # OpenSSL::Digest.digest("SHA256", "abc") # # which is equivalent to: # # OpenSSL::Digest::SHA256.digest("abc") def self.digest(name, data) super(data, name) end alg.each{|name| klass = Class.new(self) { define_method(:initialize, ->(data = nil) {super(name, data)}) } singleton = (class << klass; self; end) singleton.class_eval{ define_method(:digest){|data| new.digest(data) } define_method(:hexdigest){|data| new.hexdigest(data) } } const_set(name, klass) } # Deprecated. # # This class is only provided for backwards compatibility. # Use OpenSSL::Digest instead. class Digest < Digest; end # :nodoc: deprecate_constant :Digest end # Digest # Returns a Digest subclass by _name_ # # require 'openssl' # # OpenSSL::Digest("MD5") # # => OpenSSL::Digest::MD5 # # Digest("Foo") # # => NameError: wrong constant name Foo def Digest(name) OpenSSL::Digest.const_get(name) end module_function :Digest end # OpenSSL PKu]>)openssl-2.1.4/lib/openssl.rbnu[# frozen_string_literal: false =begin = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licensed under the same licence as Ruby. (See the file 'LICENCE'.) =end require 'openssl.so' require 'openssl/bn' require 'openssl/pkey' require 'openssl/cipher' require 'openssl/config' require 'openssl/digest' require 'openssl/x509' require 'openssl/ssl' require 'openssl/pkcs5' PKu] net-telnet-0.2.0/LICENSE.txtnu[Ruby is copyrighted free software by Yukihiro Matsumoto . You can redistribute it and/or modify it under either the terms of the 2-clause BSDL (see the file BSDL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. PKu]V__net-telnet-0.2.0/Gemfilenu[source 'https://rubygems.org' # Specify your gem's dependencies in net-telnet.gemspec gemspec PKu]Znn#net-telnet-0.2.0/net-telnet.gemspecnu[# -*- encoding: utf-8 -*- # stub: net-telnet 0.2.0 ruby lib Gem::Specification.new do |s| s.name = "net-telnet".freeze s.version = "0.2.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["SHIBATA Hiroshi".freeze] s.bindir = "exe".freeze s.date = "2018-07-25" s.description = "Provides telnet client functionality.".freeze s.email = ["hsbt@ruby-lang.org".freeze] s.files = [".gitignore".freeze, ".travis.yml".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "bin/console".freeze, "bin/setup".freeze, "lib/net-telnet.rb".freeze, "lib/net/telnet.rb".freeze, "lib/net/telnet/version.rb".freeze, "net-telnet.gemspec".freeze] s.homepage = "https://github.com/ruby/net-telnet".freeze s.licenses = ["ruby".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.3.5".freeze s.summary = "Provides telnet client functionality.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end PKu]77net-telnet-0.2.0/Rakefilenu[require "bundler/gem_tasks" require 'rake/testtask' Rake::TestTask.new do |t| t.libs << "test" t.test_files = FileList['test/test_*.rb'] end task(default: :test) PKu]ɷ׽F F net-telnet-0.2.0/README.mdnu[# Net::Telnet [![Build Status](https://travis-ci.org/ruby/net-telnet.svg?branch=master)](https://travis-ci.org/ruby/net-telnet) Provides telnet client functionality. This class also has, through delegation, all the methods of a socket object (by default, a **TCPSocket**, but can be set by the **Proxy** option to ```new()```). This provides methods such as ```close()``` to end the session and ```sysread()``` to read data directly from the host, instead of via the ```waitfor()``` mechanism. Note that if you do use ```sysread()``` directly when in telnet mode, you should probably pass the output through ```preprocess()``` to extract telnet command sequences. ## Installation Add this line to your application's Gemfile: ```ruby gem 'net-telnet' ``` And then execute: $ bundle Or install it yourself as: $ gem install net-telnet ## Usage ### Log in and send a command, echoing all output to stdout ```ruby localhost = Net::Telnet::new("Host" => "localhost", "Timeout" => 10, "Prompt" => /[$%#>] \z/n) localhost.login("username", "password") { |c| print c } localhost.cmd("command") { |c| print c } localhost.close ``` ### Check a POP server to see if you have mail ```ruby pop = Net::Telnet::new("Host" => "your_destination_host_here", "Port" => 110, "Telnetmode" => false, "Prompt" => /^\+OK/n) pop.cmd("user " + "your_username_here") { |c| print c } pop.cmd("pass " + "your_password_here") { |c| print c } pop.cmd("list") { |c| print c } ``` ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing 1. Fork it ( https://github.com/ruby/net-telnet/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request PKu]Gssnet-telnet-0.2.0/bin/setupnu[#!/bin/bash set -euo pipefail IFS=$'\n\t' bundle install # Do any other automated setup that you need to do here PKu]V?OOnet-telnet-0.2.0/bin/consolenu[#!/usr/bin/env ruby require "bundler/setup" require "net/telnet" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start PKu]]8HH"net-telnet-0.2.0/lib/net/telnet.rbnu[# = net/telnet.rb - Simple Telnet Client Library # # Author:: Wakou Aoyama # Documentation:: William Webber and Wakou Aoyama # # This file holds the class Net::Telnet, which provides client-side # telnet functionality. # # For documentation, see Net::Telnet. # require "net/protocol" require "English" module Net # # == Net::Telnet # # Provides telnet client functionality. # # This class also has, through delegation, all the methods of a # socket object (by default, a +TCPSocket+, but can be set by the # +Proxy+ option to new()). This provides methods such as # close() to end the session and sysread() to read # data directly from the host, instead of via the waitfor() # mechanism. Note that if you do use sysread() directly # when in telnet mode, you should probably pass the output through # preprocess() to extract telnet command sequences. # # == Overview # # The telnet protocol allows a client to login remotely to a user # account on a server and execute commands via a shell. The equivalent # is done by creating a Net::Telnet class with the +Host+ option # set to your host, calling #login() with your user and password, # issuing one or more #cmd() calls, and then calling #close() # to end the session. The #waitfor(), #print(), #puts(), and # #write() methods, which #cmd() is implemented on top of, are # only needed if you are doing something more complicated. # # A Net::Telnet object can also be used to connect to non-telnet # services, such as SMTP or HTTP. In this case, you normally # want to provide the +Port+ option to specify the port to # connect to, and set the +Telnetmode+ option to false to prevent # the client from attempting to interpret telnet command sequences. # Generally, #login() will not work with other protocols, and you # have to handle authentication yourself. # # For some protocols, it will be possible to specify the +Prompt+ # option once when you create the Telnet object and use #cmd() calls; # for others, you will have to specify the response sequence to # look for as the Match option to every #cmd() call, or call # #puts() and #waitfor() directly; for yet others, you will have # to use #sysread() instead of #waitfor() and parse server # responses yourself. # # It is worth noting that when you create a new Net::Telnet object, # you can supply a proxy IO channel via the Proxy option. This # can be used to attach the Telnet object to other Telnet objects, # to already open sockets, or to any read-write IO object. This # can be useful, for instance, for setting up a test fixture for # unit testing. # # == Examples # # === Log in and send a command, echoing all output to stdout # # localhost = Net::Telnet::new("Host" => "localhost", # "Timeout" => 10, # "Prompt" => /[$%#>] \z/n) # localhost.login("username", "password") { |c| print c } # localhost.cmd("command") { |c| print c } # localhost.close # # # === Check a POP server to see if you have mail # # pop = Net::Telnet::new("Host" => "your_destination_host_here", # "Port" => 110, # "Telnetmode" => false, # "Prompt" => /^\+OK/n) # pop.cmd("user " + "your_username_here") { |c| print c } # pop.cmd("pass " + "your_password_here") { |c| print c } # pop.cmd("list") { |c| print c } # # == References # # There are a large number of RFCs relevant to the Telnet protocol. # RFCs 854-861 define the base protocol. For a complete listing # of relevant RFCs, see # http://www.omnifarious.org/~hopper/technical/telnet-rfc.html # class Telnet # :stopdoc: IAC = 255.chr # "\377" # "\xff" # interpret as command DONT = 254.chr # "\376" # "\xfe" # you are not to use option DO = 253.chr # "\375" # "\xfd" # please, you use option WONT = 252.chr # "\374" # "\xfc" # I won't use option WILL = 251.chr # "\373" # "\xfb" # I will use option SB = 250.chr # "\372" # "\xfa" # interpret as subnegotiation GA = 249.chr # "\371" # "\xf9" # you may reverse the line EL = 248.chr # "\370" # "\xf8" # erase the current line EC = 247.chr # "\367" # "\xf7" # erase the current character AYT = 246.chr # "\366" # "\xf6" # are you there AO = 245.chr # "\365" # "\xf5" # abort output--but let prog finish IP = 244.chr # "\364" # "\xf4" # interrupt process--permanently BREAK = 243.chr # "\363" # "\xf3" # break DM = 242.chr # "\362" # "\xf2" # data mark--for connect. cleaning NOP = 241.chr # "\361" # "\xf1" # nop SE = 240.chr # "\360" # "\xf0" # end sub negotiation EOR = 239.chr # "\357" # "\xef" # end of record (transparent mode) ABORT = 238.chr # "\356" # "\xee" # Abort process SUSP = 237.chr # "\355" # "\xed" # Suspend process EOF = 236.chr # "\354" # "\xec" # End of file SYNCH = 242.chr # "\362" # "\xf2" # for telfunc calls OPT_BINARY = 0.chr # "\000" # "\x00" # Binary Transmission OPT_ECHO = 1.chr # "\001" # "\x01" # Echo OPT_RCP = 2.chr # "\002" # "\x02" # Reconnection OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead OPT_NAMS = 4.chr # "\004" # "\x04" # Approx Message Size Negotiation OPT_STATUS = 5.chr # "\005" # "\x05" # Status OPT_TM = 6.chr # "\006" # "\x06" # Timing Mark OPT_RCTE = 7.chr # "\a" # "\x07" # Remote Controlled Trans and Echo OPT_NAOL = 8.chr # "\010" # "\x08" # Output Line Width OPT_NAOP = 9.chr # "\t" # "\x09" # Output Page Size OPT_NAOCRD = 10.chr # "\n" # "\x0a" # Output Carriage-Return Disposition OPT_NAOHTS = 11.chr # "\v" # "\x0b" # Output Horizontal Tab Stops OPT_NAOHTD = 12.chr # "\f" # "\x0c" # Output Horizontal Tab Disposition OPT_NAOFFD = 13.chr # "\r" # "\x0d" # Output Formfeed Disposition OPT_NAOVTS = 14.chr # "\016" # "\x0e" # Output Vertical Tabstops OPT_NAOVTD = 15.chr # "\017" # "\x0f" # Output Vertical Tab Disposition OPT_NAOLFD = 16.chr # "\020" # "\x10" # Output Linefeed Disposition OPT_XASCII = 17.chr # "\021" # "\x11" # Extended ASCII OPT_LOGOUT = 18.chr # "\022" # "\x12" # Logout OPT_BM = 19.chr # "\023" # "\x13" # Byte Macro OPT_DET = 20.chr # "\024" # "\x14" # Data Entry Terminal OPT_SUPDUP = 21.chr # "\025" # "\x15" # SUPDUP OPT_SUPDUPOUTPUT = 22.chr # "\026" # "\x16" # SUPDUP Output OPT_SNDLOC = 23.chr # "\027" # "\x17" # Send Location OPT_TTYPE = 24.chr # "\030" # "\x18" # Terminal Type OPT_EOR = 25.chr # "\031" # "\x19" # End of Record OPT_TUID = 26.chr # "\032" # "\x1a" # TACACS User Identification OPT_OUTMRK = 27.chr # "\e" # "\x1b" # Output Marking OPT_TTYLOC = 28.chr # "\034" # "\x1c" # Terminal Location Number OPT_3270REGIME = 29.chr # "\035" # "\x1d" # Telnet 3270 Regime OPT_X3PAD = 30.chr # "\036" # "\x1e" # X.3 PAD OPT_NAWS = 31.chr # "\037" # "\x1f" # Negotiate About Window Size OPT_TSPEED = 32.chr # " " # "\x20" # Terminal Speed OPT_LFLOW = 33.chr # "!" # "\x21" # Remote Flow Control OPT_LINEMODE = 34.chr # "\"" # "\x22" # Linemode OPT_XDISPLOC = 35.chr # "#" # "\x23" # X Display Location OPT_OLD_ENVIRON = 36.chr # "$" # "\x24" # Environment Option OPT_AUTHENTICATION = 37.chr # "%" # "\x25" # Authentication Option OPT_ENCRYPT = 38.chr # "&" # "\x26" # Encryption Option OPT_NEW_ENVIRON = 39.chr # "'" # "\x27" # New Environment Option OPT_EXOPL = 255.chr # "\377" # "\xff" # Extended-Options-List NULL = "\000" CR = "\015" LF = "\012" EOL = CR + LF REVISION = '$Id$' # :startdoc: # # Creates a new Net::Telnet object. # # Attempts to connect to the host (unless the Proxy option is # provided: see below). If a block is provided, it is yielded # status messages on the attempt to connect to the server, of # the form: # # Trying localhost... # Connected to localhost. # # +options+ is a hash of options. The following example lists # all options and their default values. # # host = Net::Telnet::new( # "Host" => "localhost", # default: "localhost" # "Port" => 23, # default: 23 # "Binmode" => false, # default: false # "Output_log" => "output_log", # default: nil (no output) # "Dump_log" => "dump_log", # default: nil (no output) # "Prompt" => /[$%#>] \z/n, # default: /[$%#>] \z/n # "Telnetmode" => true, # default: true # "Timeout" => 10, # default: 10 # # if ignore timeout then set "Timeout" to false. # "Waittime" => 0, # default: 0 # "Proxy" => proxy # default: nil # # proxy is Net::Telnet or IO object # ) # # The options have the following meanings: # # Host:: the hostname or IP address of the host to connect to, as a String. # Defaults to "localhost". # # Port:: the port to connect to. Defaults to 23. # # Binmode:: if false (the default), newline substitution is performed. # Outgoing LF is # converted to CRLF, and incoming CRLF is converted to LF. If # true, this substitution is not performed. This value can # also be set with the #binmode() method. The # outgoing conversion only applies to the #puts() and #print() # methods, not the #write() method. The precise nature of # the newline conversion is also affected by the telnet options # SGA and BIN. # # Output_log:: the name of the file to write connection status messages # and all received traffic to. In the case of a proper # Telnet session, this will include the client input as # echoed by the host; otherwise, it only includes server # responses. Output is appended verbatim to this file. # By default, no output log is kept. # # Dump_log:: as for Output_log, except that output is written in hexdump # format (16 bytes per line as hex pairs, followed by their # printable equivalent), with connection status messages # preceded by '#', sent traffic preceded by '>', and # received traffic preceded by '<'. By default, not dump log # is kept. # # Prompt:: a regular expression matching the host's command-line prompt # sequence. This is needed by the Telnet class to determine # when the output from a command has finished and the host is # ready to receive a new command. By default, this regular # expression is /[$%#>] \z/n. # # Telnetmode:: a boolean value, true by default. In telnet mode, # traffic received from the host is parsed for special # command sequences, and these sequences are escaped # in outgoing traffic sent using #puts() or #print() # (but not #write()). If you are using the Net::Telnet # object to connect to a non-telnet service (such as # SMTP or POP), this should be set to "false" to prevent # undesired data corruption. This value can also be set # by the #telnetmode() method. # # Timeout:: the number of seconds to wait before timing out both the # initial attempt to connect to host (in this constructor), # which raises a Net::OpenTimeout, and all attempts to read data # from the host, which raises a Net::ReadTimeout (in #waitfor(), # #cmd(), and #login()). The default value is 10 seconds. # You can disable the timeout by setting this value to false. # In this case, the connect attempt will eventually timeout # on the underlying connect(2) socket call with an # Errno::ETIMEDOUT error (but generally only after a few # minutes), but other attempts to read data from the host # will hang indefinitely if no data is forthcoming. # # Waittime:: the amount of time to wait after seeing what looks like a # prompt (that is, received data that matches the Prompt # option regular expression) to see if more data arrives. # If more data does arrive in this time, Net::Telnet assumes # that what it saw was not really a prompt. This is to try to # avoid false matches, but it can also lead to missing real # prompts (if, for instance, a background process writes to # the terminal soon after the prompt is displayed). By # default, set to 0, meaning not to wait for more data. # # Proxy:: a proxy object to used instead of opening a direct connection # to the host. Must be either another Net::Telnet object or # an IO object. If it is another Net::Telnet object, this # instance will use that one's socket for communication. If an # IO object, it is used directly for communication. Any other # kind of object will cause an error to be raised. # def initialize(options) # :yield: mesg @options = options @options["Host"] = "localhost" unless @options.has_key?("Host") @options["Port"] = 23 unless @options.has_key?("Port") @options["Prompt"] = /[$%#>] \z/n unless @options.has_key?("Prompt") @options["Timeout"] = 10 unless @options.has_key?("Timeout") @options["Waittime"] = 0 unless @options.has_key?("Waittime") unless @options.has_key?("Binmode") @options["Binmode"] = false else unless (true == @options["Binmode"] or false == @options["Binmode"]) raise ArgumentError, "Binmode option must be true or false" end end unless @options.has_key?("Telnetmode") @options["Telnetmode"] = true else unless (true == @options["Telnetmode"] or false == @options["Telnetmode"]) raise ArgumentError, "Telnetmode option must be true or false" end end @telnet_option = { "SGA" => false, "BINARY" => false } if @options.has_key?("Output_log") @log = File.open(@options["Output_log"], 'a+') @log.sync = true @log.binmode end if @options.has_key?("Dump_log") @dumplog = File.open(@options["Dump_log"], 'a+') @dumplog.sync = true @dumplog.binmode def @dumplog.log_dump(dir, x) # :nodoc: len = x.length addr = 0 offset = 0 while 0 < len if len < 16 line = x[offset, len] else line = x[offset, 16] end hexvals = line.unpack('H*')[0] hexvals += ' ' * (32 - hexvals.length) hexvals = format("%s %s %s %s " * 4, *hexvals.unpack('a2' * 16)) line = line.gsub(/[\000-\037\177-\377]/n, '.') printf "%s 0x%5.5x: %s%s\n", dir, addr, hexvals, line addr += 16 offset += 16 len -= 16 end print "\n" end end if @options.has_key?("Proxy") if @options["Proxy"].kind_of?(Net::Telnet) @sock = @options["Proxy"].sock elsif @options["Proxy"].kind_of?(IO) @sock = @options["Proxy"] else raise "Error: Proxy must be an instance of Net::Telnet or IO." end else message = "Trying " + @options["Host"] + "...\n" yield(message) if block_given? @log.write(message) if @options.has_key?("Output_log") @dumplog.log_dump('#', message) if @options.has_key?("Dump_log") begin if @options["Timeout"] == false @sock = TCPSocket.open(@options["Host"], @options["Port"]) else Timeout.timeout(@options["Timeout"], Net::OpenTimeout) do @sock = TCPSocket.open(@options["Host"], @options["Port"]) end end rescue Net::OpenTimeout raise Net::OpenTimeout, "timed out while opening a connection to the host" rescue @log.write($ERROR_INFO.to_s + "\n") if @options.has_key?("Output_log") @dumplog.log_dump('#', $ERROR_INFO.to_s + "\n") if @options.has_key?("Dump_log") raise end @sock.sync = true @sock.binmode message = "Connected to " + @options["Host"] + ".\n" yield(message) if block_given? @log.write(message) if @options.has_key?("Output_log") @dumplog.log_dump('#', message) if @options.has_key?("Dump_log") end end # initialize # The socket the Telnet object is using. Note that this object becomes # a delegate of the Telnet object, so normally you invoke its methods # directly on the Telnet object. attr_reader :sock # Set telnet command interpretation on (+mode+ == true) or off # (+mode+ == false), or return the current value (+mode+ not # provided). It should be on for true telnet sessions, off if # using Net::Telnet to connect to a non-telnet service such # as SMTP. def telnetmode(mode = nil) case mode when nil @options["Telnetmode"] when true, false @options["Telnetmode"] = mode else raise ArgumentError, "argument must be true or false, or missing" end end # Turn telnet command interpretation on (true) or off (false). It # should be on for true telnet sessions, off if using Net::Telnet # to connect to a non-telnet service such as SMTP. def telnetmode=(mode) if (true == mode or false == mode) @options["Telnetmode"] = mode else raise ArgumentError, "argument must be true or false" end end # Turn newline conversion on (+mode+ == false) or off (+mode+ == true), # or return the current value (+mode+ is not specified). def binmode(mode = nil) case mode when nil @options["Binmode"] when true, false @options["Binmode"] = mode else raise ArgumentError, "argument must be true or false" end end # Turn newline conversion on (false) or off (true). def binmode=(mode) if (true == mode or false == mode) @options["Binmode"] = mode else raise ArgumentError, "argument must be true or false" end end # Preprocess received data from the host. # # Performs newline conversion and detects telnet command sequences. # Called automatically by #waitfor(). You should only use this # method yourself if you have read input directly using sysread() # or similar, and even then only if in telnet mode. def preprocess(string) # combine CR+NULL into CR string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"] # combine EOL into "\n" string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"] # remove NULL string = string.gsub(/#{NULL}/no, '') unless @options["Binmode"] string.gsub(/#{IAC}( [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]| [#{DO}#{DONT}#{WILL}#{WONT}] [#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}]| #{SB}[^#{IAC}]*#{IAC}#{SE} )/xno) do if IAC == $1 # handle escaped IAC characters IAC elsif AYT == $1 # respond to "IAC AYT" (are you there) self.write("nobody here but us pigeons" + EOL) '' elsif DO[0] == $1[0] # respond to "IAC DO x" if OPT_BINARY[0] == $1[1] @telnet_option["BINARY"] = true self.write(IAC + WILL + OPT_BINARY) else self.write(IAC + WONT + $1[1..1]) end '' elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x" self.write(IAC + WONT + $1[1..1]) '' elsif WILL[0] == $1[0] # respond to "IAC WILL x" if OPT_BINARY[0] == $1[1] self.write(IAC + DO + OPT_BINARY) elsif OPT_ECHO[0] == $1[1] self.write(IAC + DO + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = true self.write(IAC + DO + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' elsif WONT[0] == $1[0] # respond to "IAC WON'T x" if OPT_ECHO[0] == $1[1] self.write(IAC + DONT + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = false self.write(IAC + DONT + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' else '' end end end # preprocess # Read data from the host until a certain sequence is matched. # # If a block is given, the received data will be yielded as it # is read in (not necessarily all in one go), or nil if EOF # occurs before any data is received. Whether a block is given # or not, all data read will be returned in a single string, or again # nil if EOF occurs before any data is received. Note that # received data includes the matched sequence we were looking for. # # +options+ can be either a regular expression or a hash of options. # If a regular expression, this specifies the data to wait for. # If a hash, this can specify the following options: # # Match:: a regular expression, specifying the data to wait for. # Prompt:: as for Match; used only if Match is not specified. # String:: as for Match, except a string that will be converted # into a regular expression. Used only if Match and # Prompt are not specified. # Timeout:: the number of seconds to wait for data from the host # before raising a Timeout::Error. If set to false, # no timeout will occur. If not specified, the # Timeout option value specified when this instance # was created will be used, or, failing that, the # default value of 10 seconds. # Waittime:: the number of seconds to wait after matching against # the input data to see if more data arrives. If more # data arrives within this time, we will judge ourselves # not to have matched successfully, and will continue # trying to match. If not specified, the Waittime option # value specified when this instance was created will be # used, or, failing that, the default value of 0 seconds, # which means not to wait for more input. # FailEOF:: if true, when the remote end closes the connection then an # EOFError will be raised. Otherwise, defaults to the old # behaviour that the function will return whatever data # has been received already, or nil if nothing was received. # def waitfor(options) # :yield: recvdata time_out = @options["Timeout"] waittime = @options["Waittime"] fail_eof = @options["FailEOF"] if options.kind_of?(Hash) prompt = if options.has_key?("Match") options["Match"] elsif options.has_key?("Prompt") options["Prompt"] elsif options.has_key?("String") Regexp.new( Regexp.quote(options["String"]) ) end time_out = options["Timeout"] if options.has_key?("Timeout") waittime = options["Waittime"] if options.has_key?("Waittime") fail_eof = options["FailEOF"] if options.has_key?("FailEOF") else prompt = options end if time_out == false time_out = nil end line = '' buf = '' rest = '' until(prompt === line and not @sock.wait_readable(waittime)) unless @sock.wait_readable(time_out) raise Net::ReadTimeout, "timed out while waiting for more data" end begin c = @sock.readpartial(1024 * 1024) @dumplog.log_dump('<', c) if @options.has_key?("Dump_log") if @options["Telnetmode"] c = rest + c if Integer(c.rindex(/#{IAC}#{SE}/no) || 0) < Integer(c.rindex(/#{IAC}#{SB}/no) || 0) buf = preprocess(c[0 ... c.rindex(/#{IAC}#{SB}/no)]) rest = c[c.rindex(/#{IAC}#{SB}/no) .. -1] elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) || c.rindex(/\r\z/no) buf = preprocess(c[0 ... pt]) rest = c[pt .. -1] else buf = preprocess(c) rest = '' end else # Not Telnetmode. # # We cannot use preprocess() on this data, because that # method makes some Telnetmode-specific assumptions. buf = rest + c rest = '' unless @options["Binmode"] if pt = buf.rindex(/\r\z/no) buf = buf[0 ... pt] rest = buf[pt .. -1] end buf.gsub!(/#{EOL}/no, "\n") end end @log.print(buf) if @options.has_key?("Output_log") line += buf yield buf if block_given? rescue EOFError # End of file reached raise if fail_eof if line == '' line = nil yield nil if block_given? end break end end line end # Write +string+ to the host. # # Does not perform any conversions on +string+. Will log +string+ to the # dumplog, if the Dump_log option is set. def write(string) length = string.length while 0 < length @sock.wait_writable @dumplog.log_dump('>', string[-length..-1]) if @options.has_key?("Dump_log") length -= @sock.syswrite(string[-length..-1]) end end # Sends a string to the host. # # This does _not_ automatically append a newline to the string. Embedded # newlines may be converted and telnet command sequences escaped # depending upon the values of telnetmode, binmode, and telnet options # set by the host. def print(string) string = string.gsub(/#{IAC}/no, IAC + IAC) if @options["Telnetmode"] if @options["Binmode"] self.write(string) else if @telnet_option["BINARY"] and @telnet_option["SGA"] # IAC WILL SGA IAC DO BIN send EOL --> CR self.write(string.gsub(/\n/n, CR)) elsif @telnet_option["SGA"] # IAC WILL SGA send EOL --> CR+NULL self.write(string.gsub(/\n/n, CR + NULL)) else # NONE send EOL --> CR+LF self.write(string.gsub(/\n/n, EOL)) end end end # Sends a string to the host. # # Same as #print(), but appends a newline to the string. def puts(string) self.print(string + "\n") end # Send a command to the host. # # More exactly, sends a string to the host, and reads in all received # data until is sees the prompt or other matched sequence. # # If a block is given, the received data will be yielded to it as # it is read in. Whether a block is given or not, the received data # will be return as a string. Note that the received data includes # the prompt and in most cases the host's echo of our command. # # +options+ is either a String, specified the string or command to # send to the host; or it is a hash of options. If a hash, the # following options can be specified: # # String:: the command or other string to send to the host. # Match:: a regular expression, the sequence to look for in # the received data before returning. If not specified, # the Prompt option value specified when this instance # was created will be used, or, failing that, the default # prompt of /[$%#>] \z/n. # Timeout:: the seconds to wait for data from the host before raising # a Timeout error. If not specified, the Timeout option # value specified when this instance was created will be # used, or, failing that, the default value of 10 seconds. # # The command or other string will have the newline sequence appended # to it. def cmd(options) # :yield: recvdata match = @options["Prompt"] time_out = @options["Timeout"] fail_eof = @options["FailEOF"] if options.kind_of?(Hash) string = options["String"] match = options["Match"] if options.has_key?("Match") time_out = options["Timeout"] if options.has_key?("Timeout") fail_eof = options["FailEOF"] if options.has_key?("FailEOF") else string = options end self.puts(string) if block_given? waitfor({"Prompt" => match, "Timeout" => time_out, "FailEOF" => fail_eof}){|c| yield c } else waitfor({"Prompt" => match, "Timeout" => time_out, "FailEOF" => fail_eof}) end end # Login to the host with a given username and password. # # The username and password can either be provided as two string # arguments in that order, or as a hash with keys "Name" and # "Password". # # This method looks for the strings "login" and "Password" from the # host to determine when to send the username and password. If the # login sequence does not follow this pattern (for instance, you # are connecting to a service other than telnet), you will need # to handle login yourself. # # The password can be omitted, either by only # provided one String argument, which will be used as the username, # or by providing a has that has no "Password" key. In this case, # the method will not look for the "Password:" prompt; if it is # sent, it will have to be dealt with by later calls. # # The method returns all data received during the login process from # the host, including the echoed username but not the password (which # the host should not echo). If a block is passed in, this received # data is also yielded to the block as it is received. def login(options, password = nil) # :yield: recvdata login_prompt = /[Ll]ogin[: ]*\z/n password_prompt = /[Pp]ass(?:word|phrase)[: ]*\z/n if options.kind_of?(Hash) username = options["Name"] password = options["Password"] login_prompt = options["LoginPrompt"] if options["LoginPrompt"] password_prompt = options["PasswordPrompt"] if options["PasswordPrompt"] else username = options end if block_given? line = waitfor(login_prompt){|c| yield c } if password line += cmd({"String" => username, "Match" => password_prompt}){|c| yield c } line += cmd(password){|c| yield c } else line += cmd(username){|c| yield c } end else line = waitfor(login_prompt) if password line += cmd({"String" => username, "Match" => password_prompt}) line += cmd(password) else line += cmd(username) end end line end # Closes the connection def close @sock.close end end # class Telnet end # module Net PKu]>7C::*net-telnet-0.2.0/lib/net/telnet/version.rbnu[module Net class Telnet VERSION = "0.2.0" end end PKu][J¼"net-telnet-0.2.0/lib/net-telnet.rbnu[require 'net/telnet' PKu]$(QTTpsych-3.1.0/lib/psych.rbnu[# frozen_string_literal: true require 'psych/versions' case RUBY_ENGINE when 'jruby' require 'psych_jars' if JRuby::Util.respond_to?(:load_ext) JRuby::Util.load_ext('org.jruby.ext.psych.PsychLibrary') else require 'java'; require 'jruby' org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false) end else require 'psych.so' end require 'psych/nodes' require 'psych/streaming' require 'psych/visitors' require 'psych/handler' require 'psych/tree_builder' require 'psych/parser' require 'psych/omap' require 'psych/set' require 'psych/coder' require 'psych/core_ext' require 'psych/stream' require 'psych/json/tree_builder' require 'psych/json/stream' require 'psych/handlers/document_stream' require 'psych/class_loader' ### # = Overview # # Psych is a YAML parser and emitter. # Psych leverages libyaml [Home page: https://pyyaml.org/wiki/LibYAML] # or [HG repo: https://bitbucket.org/xi/libyaml] for its YAML parsing # and emitting capabilities. In addition to wrapping libyaml, Psych also # knows how to serialize and de-serialize most Ruby objects to and from # the YAML format. # # = I NEED TO PARSE OR EMIT YAML RIGHT NOW! # # # Parse some YAML # Psych.load("--- foo") # => "foo" # # # Emit some YAML # Psych.dump("foo") # => "--- foo\n...\n" # { :a => 'b'}.to_yaml # => "---\n:a: b\n" # # Got more time on your hands? Keep on reading! # # == YAML Parsing # # Psych provides a range of interfaces for parsing a YAML document ranging from # low level to high level, depending on your parsing needs. At the lowest # level, is an event based parser. Mid level is access to the raw YAML AST, # and at the highest level is the ability to unmarshal YAML to Ruby objects. # # == YAML Emitting # # Psych provides a range of interfaces ranging from low to high level for # producing YAML documents. Very similar to the YAML parsing interfaces, Psych # provides at the lowest level, an event based system, mid-level is building # a YAML AST, and the highest level is converting a Ruby object straight to # a YAML document. # # == High-level API # # === Parsing # # The high level YAML parser provided by Psych simply takes YAML as input and # returns a Ruby data structure. For information on using the high level parser # see Psych.load # # ==== Reading from a string # # Psych.load("--- a") # => 'a' # Psych.load("---\n - a\n - b") # => ['a', 'b'] # # ==== Reading from a file # # Psych.load_file("database.yml") # # ==== Exception handling # # begin # # The second argument changes only the exception contents # Psych.parse("--- `", "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # === Emitting # # The high level emitter has the easiest interface. Psych simply takes a Ruby # data structure and converts it to a YAML document. See Psych.dump for more # information on dumping a Ruby data structure. # # ==== Writing to a string # # # Dump an array, get back a YAML string # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" # # # Dump an array to an IO object # Psych.dump(['a', 'b'], StringIO.new) # => # # # # Dump an array with indentation set # Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n" # # # Dump an array to an IO with indentation set # Psych.dump(['a', ['b']], StringIO.new, :indentation => 3) # # ==== Writing to a file # # Currently there is no direct API for dumping Ruby structure to file: # # File.open('database.yml', 'w') do |file| # file.write(Psych.dump(['a', 'b'])) # end # # == Mid-level API # # === Parsing # # Psych provides access to an AST produced from parsing a YAML document. This # tree is built using the Psych::Parser and Psych::TreeBuilder. The AST can # be examined and manipulated freely. Please see Psych::parse_stream, # Psych::Nodes, and Psych::Nodes::Node for more information on dealing with # YAML syntax trees. # # ==== Reading from a string # # # Returns Psych::Nodes::Stream # Psych.parse_stream("---\n - a\n - b") # # # Returns Psych::Nodes::Document # Psych.parse("---\n - a\n - b") # # ==== Reading from a file # # # Returns Psych::Nodes::Stream # Psych.parse_stream(File.read('database.yml')) # # # Returns Psych::Nodes::Document # Psych.parse_file('database.yml') # # ==== Exception handling # # begin # # The second argument changes only the exception contents # Psych.parse("--- `", "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # === Emitting # # At the mid level is building an AST. This AST is exactly the same as the AST # used when parsing a YAML document. Users can build an AST by hand and the # AST knows how to emit itself as a YAML document. See Psych::Nodes, # Psych::Nodes::Node, and Psych::TreeBuilder for more information on building # a YAML AST. # # ==== Writing to a string # # # We need Psych::Nodes::Stream (not Psych::Nodes::Document) # stream = Psych.parse_stream("---\n - a\n - b") # # stream.to_yaml # => "---\n- a\n- b\n" # # ==== Writing to a file # # # We need Psych::Nodes::Stream (not Psych::Nodes::Document) # stream = Psych.parse_stream(File.read('database.yml')) # # File.open('database.yml', 'w') do |file| # file.write(stream.to_yaml) # end # # == Low-level API # # === Parsing # # The lowest level parser should be used when the YAML input is already known, # and the developer does not want to pay the price of building an AST or # automatic detection and conversion to Ruby objects. See Psych::Parser for # more information on using the event based parser. # # ==== Reading to Psych::Nodes::Stream structure # # parser = Psych::Parser.new(TreeBuilder.new) # => # # parser = Psych.parser # it's an alias for the above # # parser.parse("---\n - a\n - b") # => # # parser.handler # => # # parser.handler.root # => # # # ==== Receiving an events stream # # recorder = Psych::Handlers::Recorder.new # parser = Psych::Parser.new(recorder) # # parser.parse("---\n - a\n - b") # recorder.events # => [list of [event, args] lists] # # event is one of: Psych::Handler::EVENTS # # args are the arguments passed to the event # # === Emitting # # The lowest level emitter is an event based system. Events are sent to a # Psych::Emitter object. That object knows how to convert the events to a YAML # document. This interface should be used when document format is known in # advance or speed is a concern. See Psych::Emitter for more information. # # ==== Writing to a Ruby structure # # Psych.parser.parse("--- a") # => # # # parser.handler.first # => # # parser.handler.first.to_ruby # => ["a"] # # parser.handler.root.first # => # # parser.handler.root.first.to_ruby # => "a" # # # You can instantiate an Emitter manually # Psych::Visitors::ToRuby.new.accept(parser.handler.root.first) # # => "a" module Psych # The version of libyaml Psych is using LIBYAML_VERSION = Psych.libyaml_version.join '.' # Deprecation guard NOT_GIVEN = Object.new private_constant :NOT_GIVEN ### # Load +yaml+ in to a Ruby data structure. If multiple documents are # provided, the object contained in the first document will be returned. # +filename+ will be used in the exception message if any exception # is raised while parsing. If +yaml+ is empty, it returns # the specified +fallback+ return value, which defaults to +false+. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. # # Example: # # Psych.load("--- a") # => 'a' # Psych.load("---\n - a\n - b") # => ['a', 'b'] # # begin # Psych.load("--- `", filename: "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # When the optional +symbolize_names+ keyword argument is set to a # true value, returns symbols for keys in Hash objects (default: strings). # # Psych.load("---\n foo: bar") # => {"foo"=>"bar"} # Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} # # Raises a TypeError when `yaml` parameter is NilClass # # NOTE: This method *should not* be used to parse untrusted documents, such as # YAML documents that are supplied via user input. Instead, please use the # safe_load method. # def self.load yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: false, symbolize_names: false if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load is deprecated. Use keyword argument like Psych.load(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end result = parse(yaml, filename: filename) return fallback unless result result = result.to_ruby if result symbolize_names!(result) if symbolize_names result end ### # Safely load the yaml string in +yaml+. By default, only the following # classes are allowed to be deserialized: # # * TrueClass # * FalseClass # * NilClass # * Numeric # * String # * Array # * Hash # # Recursive data structures are not allowed by default. Arbitrary classes # can be allowed by adding those classes to the +permitted_classes+ keyword argument. They are # additive. For example, to allow Date deserialization: # # Psych.safe_load(yaml, permitted_classes: [Date]) # # Now the Date class can be loaded in addition to the classes listed above. # # Aliases can be explicitly allowed by changing the +aliases+ keyword argument. # For example: # # x = [] # x << x # yaml = Psych.dump x # Psych.safe_load yaml # => raises an exception # Psych.safe_load yaml, aliases: true # => loads the aliases # # A Psych::DisallowedClass exception will be raised if the yaml contains a # class that isn't in the +permitted_classes+ list. # # A Psych::BadAlias exception will be raised if the yaml contains aliases # but the +aliases+ keyword argument is set to false. # # +filename+ will be used in the exception message if any exception is raised # while parsing. # # When the optional +symbolize_names+ keyword argument is set to a # true value, returns symbols for keys in Hash objects (default: strings). # # Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"} # Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} # def self.safe_load yaml, legacy_permitted_classes = NOT_GIVEN, legacy_permitted_symbols = NOT_GIVEN, legacy_aliases = NOT_GIVEN, legacy_filename = NOT_GIVEN, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false if legacy_permitted_classes != NOT_GIVEN warn_with_uplevel 'Passing permitted_classes with the 2nd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_classes: ...) instead.', uplevel: 1 if $VERBOSE permitted_classes = legacy_permitted_classes end if legacy_permitted_symbols != NOT_GIVEN warn_with_uplevel 'Passing permitted_symbols with the 3rd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_symbols: ...) instead.', uplevel: 1 if $VERBOSE permitted_symbols = legacy_permitted_symbols end if legacy_aliases != NOT_GIVEN warn_with_uplevel 'Passing aliases with the 4th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, aliases: ...) instead.', uplevel: 1 if $VERBOSE aliases = legacy_aliases end if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 5th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end result = parse(yaml, filename: filename) return fallback unless result class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s), permitted_symbols.map(&:to_s)) scanner = ScalarScanner.new class_loader visitor = if aliases Visitors::ToRuby.new scanner, class_loader else Visitors::NoAliasRuby.new scanner, class_loader end result = visitor.accept result symbolize_names!(result) if symbolize_names result end ### # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Document. # +filename+ is used in the exception message if a Psych::SyntaxError is # raised. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. # # Example: # # Psych.parse("---\n - a\n - b") # => # # # begin # Psych.parse("--- `", filename: "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # See Psych::Nodes for more information about YAML AST. def self.parse yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: NOT_GIVEN if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse is deprecated. Use keyword argument like Psych.parse(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end parse_stream(yaml, filename: filename) do |node| return node end if fallback != NOT_GIVEN warn_with_uplevel 'Passing the `fallback` keyword argument of Psych.parse is deprecated.', uplevel: 1 if $VERBOSE fallback else false end end ### # Parse a file at +filename+. Returns the Psych::Nodes::Document. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. def self.parse_file filename, fallback: false result = File.open filename, 'r:bom|utf-8' do |f| parse f, filename: filename end result || fallback end ### # Returns a default parser def self.parser Psych::Parser.new(TreeBuilder.new) end ### # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Stream. # This method can handle multiple YAML documents contained in +yaml+. # +filename+ is used in the exception message if a Psych::SyntaxError is # raised. # # If a block is given, a Psych::Nodes::Document node will be yielded to the # block as it's being parsed. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. # # Example: # # Psych.parse_stream("---\n - a\n - b") # => # # # Psych.parse_stream("--- a\n--- b") do |node| # node # => # # end # # begin # Psych.parse_stream("--- `", filename: "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' # ex.message # => "(file.txt): found character that cannot start any token" # end # # Raises a TypeError when NilClass is passed. # # See Psych::Nodes for more information about YAML AST. def self.parse_stream yaml, legacy_filename = NOT_GIVEN, filename: nil, &block if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse_stream is deprecated. Use keyword argument like Psych.parse_stream(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end if block_given? parser = Psych::Parser.new(Handlers::DocumentStream.new(&block)) parser.parse yaml, filename else parser = self.parser parser.parse yaml, filename parser.handler.root end end ### # call-seq: # Psych.dump(o) -> string of yaml # Psych.dump(o, options) -> string of yaml # Psych.dump(o, io) -> io object passed in # Psych.dump(o, io, options) -> io object passed in # # Dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in # to control the output format. If an IO object is passed in, the YAML will # be dumped to that IO object. # # Currently supported options are: # # [:indentation] Number of space characters used to indent. # Acceptable value should be in 0..9 range, # otherwise option is ignored. # # Default: 2. # [:line_width] Max character to wrap line at. # # Default: 0 (meaning "wrap at 81"). # [:canonical] Write "canonical" YAML form (very verbose, yet # strictly formal). # # Default: false. # [:header] Write %YAML [version] at the beginning of document. # # Default: false. # # Example: # # # Dump an array, get back a YAML string # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" # # # Dump an array to an IO object # Psych.dump(['a', 'b'], StringIO.new) # => # # # # Dump an array with indentation set # Psych.dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n" # # # Dump an array to an IO with indentation set # Psych.dump(['a', ['b']], StringIO.new, indentation: 3) def self.dump o, io = nil, options = {} if Hash === io options = io io = nil end visitor = Psych::Visitors::YAMLTree.create options visitor << o visitor.tree.yaml io, options end ### # Dump a list of objects as separate documents to a document stream. # # Example: # # Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n" def self.dump_stream *objects visitor = Psych::Visitors::YAMLTree.create({}) objects.each do |o| visitor << o end visitor.tree.yaml end ### # Dump Ruby +object+ to a JSON string. def self.to_json object visitor = Psych::Visitors::JSONTree.create visitor << object visitor.tree.yaml end ### # Load multiple documents given in +yaml+. Returns the parsed documents # as a list. If a block is given, each document will be converted to Ruby # and passed to the block during parsing # # Example: # # Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] # # list = [] # Psych.load_stream("--- foo\n...\n--- bar\n...") do |ruby| # list << ruby # end # list # => ['foo', 'bar'] # def self.load_stream yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: [] if legacy_filename != NOT_GIVEN warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load_stream is deprecated. Use keyword argument like Psych.load_stream(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE filename = legacy_filename end result = if block_given? parse_stream(yaml, filename: filename) do |node| yield node.to_ruby end else parse_stream(yaml, filename: filename).children.map(&:to_ruby) end return fallback if result.is_a?(Array) && result.empty? result end ### # Load the document contained in +filename+. Returns the yaml contained in # +filename+ as a Ruby object, or if the file is empty, it returns # the specified +fallback+ return value, which defaults to +false+. def self.load_file filename, fallback: false File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename: filename, fallback: fallback } end # :stopdoc: @domain_types = {} def self.add_domain_type domain, type_tag, &block key = ['tag', domain, type_tag].join ':' @domain_types[key] = [key, block] @domain_types["tag:#{type_tag}"] = [key, block] end def self.add_builtin_type type_tag, &block domain = 'yaml.org,2002' key = ['tag', domain, type_tag].join ':' @domain_types[key] = [key, block] end def self.remove_type type_tag @domain_types.delete type_tag end @load_tags = {} @dump_tags = {} def self.add_tag tag, klass @load_tags[tag] = klass.name @dump_tags[klass] = tag end def self.symbolize_names!(result) case result when Hash result.keys.each do |key| result[key.to_sym] = symbolize_names!(result.delete(key)) end when Array result.map! { |r| symbolize_names!(r) } end result end private_class_method :symbolize_names! # Workaround for emulating `warn '...', uplevel: 1` in Ruby 2.4 or lower. def self.warn_with_uplevel(message, uplevel: 1) at = parse_caller(caller[uplevel]).join(':') warn "#{at}: #{message}" end def self.parse_caller(at) if /^(.+?):(\d+)(?::in `.*')?/ =~ at file = $1 line = $2.to_i [file, line] end end private_class_method :warn_with_uplevel, :parse_caller class << self attr_accessor :load_tags attr_accessor :dump_tags attr_accessor :domain_types end # :startdoc: end PKu]H'psych-3.1.0/lib/psych/scalar_scanner.rbnu[# frozen_string_literal: true require 'strscan' module Psych ### # Scan scalars for built in types class ScalarScanner # Taken from http://yaml.org/type/timestamp.html TIME = /^-?\d{4}-\d{1,2}-\d{1,2}(?:[Tt]|\s+)\d{1,2}:\d\d:\d\d(?:\.\d*)?(?:\s*(?:Z|[-+]\d{1,2}:?(?:\d\d)?))?$/ # Taken from http://yaml.org/type/float.html FLOAT = /^(?:[-+]?([0-9][0-9_,]*)?\.[0-9]*([eE][-+][0-9]+)?(?# base 10) |[-+]?\.(inf|Inf|INF)(?# infinity) |\.(nan|NaN|NAN)(?# not a number))$/x # Taken from http://yaml.org/type/int.html INTEGER = /^(?:[-+]?0b[0-1_,]+ (?# base 2) |[-+]?0[0-7_,]+ (?# base 8) |[-+]?(?:0|[1-9][0-9_,]*) (?# base 10) |[-+]?0x[0-9a-fA-F_,]+ (?# base 16))$/x attr_reader :class_loader # Create a new scanner def initialize class_loader @symbol_cache = {} @class_loader = class_loader end # Tokenize +string+ returning the Ruby object def tokenize string return nil if string.empty? return @symbol_cache[string] if @symbol_cache.key?(string) # Check for a String type, being careful not to get caught by hash keys, hex values, and # special floats (e.g., -.inf). if string.match?(/^[^\d\.:-]?[A-Za-z_\s!@#\$%\^&\*\(\)\{\}\<\>\|\/\\~;=]+/) || string.match?(/\n/) return string if string.length > 5 if string.match?(/^[^ytonf~]/i) string elsif string == '~' || string.match?(/^null$/i) nil elsif string.match?(/^(yes|true|on)$/i) true elsif string.match?(/^(no|false|off)$/i) false else string end elsif string.match?(TIME) begin parse_time string rescue ArgumentError string end elsif string.match?(/^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/) require 'date' begin class_loader.date.strptime(string, '%Y-%m-%d') rescue ArgumentError string end elsif string.match?(/^\.inf$/i) Float::INFINITY elsif string.match?(/^-\.inf$/i) -Float::INFINITY elsif string.match?(/^\.nan$/i) Float::NAN elsif string.match?(/^:./) if string =~ /^:(["'])(.*)\1/ @symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, '')) else @symbol_cache[string] = class_loader.symbolize(string.sub(/^:/, '')) end elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}$/) i = 0 string.split(':').each_with_index do |n,e| i += (n.to_i * 60 ** (e - 2).abs) end i elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}\.[0-9_]*$/) i = 0 string.split(':').each_with_index do |n,e| i += (n.to_f * 60 ** (e - 2).abs) end i elsif string.match?(FLOAT) if string.match?(/\A[-+]?\.\Z/) string else Float(string.gsub(/[,_]|\.([Ee]|$)/, '\1')) end elsif string.match?(INTEGER) parse_int string else string end end ### # Parse and return an int from +string+ def parse_int string Integer(string.gsub(/[,]/, '')) end ### # Parse and return a Time from +string+ def parse_time string klass = class_loader.load 'Time' date, time = *(string.split(/[ tT]/, 2)) (yy, m, dd) = date.match(/^(-?\d{4})-(\d{1,2})-(\d{1,2})/).captures.map { |x| x.to_i } md = time.match(/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/) (hh, mm, ss) = md[1].split(':').map { |x| x.to_i } us = (md[2] ? Rational("0.#{md[2]}") : 0) * 1000000 time = klass.utc(yy, m, dd, hh, mm, ss, us) return time if 'Z' == md[3] return klass.at(time.to_i, us) unless md[3] tz = md[3].match(/^([+\-]?\d{1,2})\:?(\d{1,2})?$/)[1..-1].compact.map { |digit| Integer(digit, 10) } offset = tz.first * 3600 if offset < 0 offset -= ((tz[1] || 0) * 60) else offset += ((tz[1] || 0) * 60) end klass.new(yy, m, dd, hh, mm, ss+us/(1_000_000r), offset) end end end PKu]KKpsych-3.1.0/lib/psych/omap.rbnu[# frozen_string_literal: true module Psych class Omap < ::Hash end end PKu] [psych-3.1.0/lib/psych/parser.rbnu[# frozen_string_literal: true module Psych ### # YAML event parser class. This class parses a YAML document and calls # events on the handler that is passed to the constructor. The events can # be used for things such as constructing a YAML AST or deserializing YAML # documents. It can even be fed back to Psych::Emitter to emit the same # document that was parsed. # # See Psych::Handler for documentation on the events that Psych::Parser emits. # # Here is an example that prints out ever scalar found in a YAML document: # # # Handler for detecting scalar values # class ScalarHandler < Psych::Handler # def scalar value, anchor, tag, plain, quoted, style # puts value # end # end # # parser = Psych::Parser.new(ScalarHandler.new) # parser.parse(yaml_document) # # Here is an example that feeds the parser back in to Psych::Emitter. The # YAML document is read from STDIN and written back out to STDERR: # # parser = Psych::Parser.new(Psych::Emitter.new($stderr)) # parser.parse($stdin) # # Psych uses Psych::Parser in combination with Psych::TreeBuilder to # construct an AST of the parsed YAML document. class Parser class Mark < Struct.new(:index, :line, :column) end # The handler on which events will be called attr_accessor :handler # Set the encoding for this parser to +encoding+ attr_writer :external_encoding ### # Creates a new Psych::Parser instance with +handler+. YAML events will # be called on +handler+. See Psych::Parser for more details. def initialize handler = Handler.new @handler = handler @external_encoding = ANY end end end PKu]`[ psych-3.1.0/lib/psych/handler.rbnu[# frozen_string_literal: true module Psych ### # Psych::Handler is an abstract base class that defines the events used # when dealing with Psych::Parser. Clients who want to use Psych::Parser # should implement a class that inherits from Psych::Handler and define # events that they can handle. # # Psych::Handler defines all events that Psych::Parser can possibly send to # event handlers. # # See Psych::Parser for more details class Handler ### # Configuration options for dumping YAML. class DumperOptions attr_accessor :line_width, :indentation, :canonical def initialize @line_width = 0 @indentation = 2 @canonical = false end end # Default dumping options OPTIONS = DumperOptions.new # Events that a Handler should respond to. EVENTS = [ :alias, :empty, :end_document, :end_mapping, :end_sequence, :end_stream, :scalar, :start_document, :start_mapping, :start_sequence, :start_stream ] ### # Called with +encoding+ when the YAML stream starts. This method is # called once per stream. A stream may contain multiple documents. # # See the constants in Psych::Parser for the possible values of +encoding+. def start_stream encoding end ### # Called when the document starts with the declared +version+, # +tag_directives+, if the document is +implicit+. # # +version+ will be an array of integers indicating the YAML version being # dealt with, +tag_directives+ is a list of tuples indicating the prefix # and suffix of each tag, and +implicit+ is a boolean indicating whether # the document is started implicitly. # # === Example # # Given the following YAML: # # %YAML 1.1 # %TAG ! tag:tenderlovemaking.com,2009: # --- !squee # # The parameters for start_document must be this: # # version # => [1, 1] # tag_directives # => [["!", "tag:tenderlovemaking.com,2009:"]] # implicit # => false def start_document version, tag_directives, implicit end ### # Called with the document ends. +implicit+ is a boolean value indicating # whether or not the document has an implicit ending. # # === Example # # Given the following YAML: # # --- # hello world # # +implicit+ will be true. Given this YAML: # # --- # hello world # ... # # +implicit+ will be false. def end_document implicit end ### # Called when an alias is found to +anchor+. +anchor+ will be the name # of the anchor found. # # === Example # # Here we have an example of an array that references itself in YAML: # # --- &ponies # - first element # - *ponies # # &ponies is the anchor, *ponies is the alias. In this case, alias is # called with "ponies". def alias anchor end ### # Called when a scalar +value+ is found. The scalar may have an # +anchor+, a +tag+, be implicitly +plain+ or implicitly +quoted+ # # +value+ is the string value of the scalar # +anchor+ is an associated anchor or nil # +tag+ is an associated tag or nil # +plain+ is a boolean value # +quoted+ is a boolean value # +style+ is an integer idicating the string style # # See the constants in Psych::Nodes::Scalar for the possible values of # +style+ # # === Example # # Here is a YAML document that exercises most of the possible ways this # method can be called: # # --- # - !str "foo" # - &anchor fun # - many # lines # - | # many # newlines # # The above YAML document contains a list with four strings. Here are # the parameters sent to this method in the same order: # # # value anchor tag plain quoted style # ["foo", nil, "!str", false, false, 3 ] # ["fun", "anchor", nil, true, false, 1 ] # ["many lines", nil, nil, true, false, 1 ] # ["many\nnewlines\n", nil, nil, false, true, 4 ] # def scalar value, anchor, tag, plain, quoted, style end ### # Called when a sequence is started. # # +anchor+ is the anchor associated with the sequence or nil. # +tag+ is the tag associated with the sequence or nil. # +implicit+ a boolean indicating whether or not the sequence was implicitly # started. # +style+ is an integer indicating the list style. # # See the constants in Psych::Nodes::Sequence for the possible values of # +style+. # # === Example # # Here is a YAML document that exercises most of the possible ways this # method can be called: # # --- # - !!seq [ # a # ] # - &pewpew # - b # # The above YAML document consists of three lists, an outer list that # contains two inner lists. Here is a matrix of the parameters sent # to represent these lists: # # # anchor tag implicit style # [nil, nil, true, 1 ] # [nil, "tag:yaml.org,2002:seq", false, 2 ] # ["pewpew", nil, true, 1 ] def start_sequence anchor, tag, implicit, style end ### # Called when a sequence ends. def end_sequence end ### # Called when a map starts. # # +anchor+ is the anchor associated with the map or +nil+. # +tag+ is the tag associated with the map or +nil+. # +implicit+ is a boolean indicating whether or not the map was implicitly # started. # +style+ is an integer indicating the mapping style. # # See the constants in Psych::Nodes::Mapping for the possible values of # +style+. # # === Example # # Here is a YAML document that exercises most of the possible ways this # method can be called: # # --- # k: !!map { hello: world } # v: &pewpew # hello: world # # The above YAML document consists of three maps, an outer map that contains # two inner maps. Below is a matrix of the parameters sent in order to # represent these three maps: # # # anchor tag implicit style # [nil, nil, true, 1 ] # [nil, "tag:yaml.org,2002:map", false, 2 ] # ["pewpew", nil, true, 1 ] def start_mapping anchor, tag, implicit, style end ### # Called when a map ends def end_mapping end ### # Called when an empty event happens. (Which, as far as I can tell, is # never). def empty end ### # Called when the YAML stream ends def end_stream end ### # Called before each event with line/column information. def event_location(start_line, start_column, end_line, end_column) end ### # Is this handler a streaming handler? def streaming? false end end end PKu] %psych-3.1.0/lib/psych/tree_builder.rbnu[# frozen_string_literal: true require 'psych/handler' module Psych ### # This class works in conjunction with Psych::Parser to build an in-memory # parse tree that represents a YAML document. # # == Example # # parser = Psych::Parser.new Psych::TreeBuilder.new # parser.parse('--- foo') # tree = parser.handler.root # # See Psych::Handler for documentation on the event methods used in this # class. class TreeBuilder < Psych::Handler # Returns the root node for the built tree attr_reader :root # Create a new TreeBuilder instance def initialize @stack = [] @last = nil @root = nil @start_line = nil @start_column = nil @end_line = nil @end_column = nil end def event_location(start_line, start_column, end_line, end_column) @start_line = start_line @start_column = start_column @end_line = end_line @end_column = end_column end %w{ Sequence Mapping }.each do |node| class_eval %{ def start_#{node.downcase}(anchor, tag, implicit, style) n = Nodes::#{node}.new(anchor, tag, implicit, style) set_start_location(n) @last.children << n push n end def end_#{node.downcase} n = pop set_end_location(n) n end } end ### # Handles start_document events with +version+, +tag_directives+, # and +implicit+ styling. # # See Psych::Handler#start_document def start_document version, tag_directives, implicit n = Nodes::Document.new version, tag_directives, implicit set_start_location(n) @last.children << n push n end ### # Handles end_document events with +version+, +tag_directives+, # and +implicit+ styling. # # See Psych::Handler#start_document def end_document implicit_end = !streaming? @last.implicit_end = implicit_end n = pop set_end_location(n) n end def start_stream encoding @root = Nodes::Stream.new(encoding) set_start_location(@root) push @root end def end_stream n = pop set_end_location(n) n end def scalar value, anchor, tag, plain, quoted, style s = Nodes::Scalar.new(value,anchor,tag,plain,quoted,style) set_location(s) @last.children << s s end def alias anchor a = Nodes::Alias.new(anchor) set_location(a) @last.children << a a end private def push value @stack.push value @last = value end def pop x = @stack.pop @last = @stack.last x end def set_location(node) set_start_location(node) set_end_location(node) end def set_start_location(node) node.start_line = @start_line node.start_column = @start_column end def set_end_location(node) node.end_line = @end_line node.end_column = @end_column end end end PKu]"psych-3.1.0/lib/psych/exception.rbnu[# frozen_string_literal: true module Psych class Exception < RuntimeError end class BadAlias < Exception end class DisallowedClass < Exception def initialize klass_name super "Tried to load unspecified class: #{klass_name}" end end end PKu]*JJpsych-3.1.0/lib/psych/set.rbnu[# frozen_string_literal: true module Psych class Set < ::Hash end end PKu]PKK+psych-3.1.0/lib/psych/visitors/json_tree.rbnu[# frozen_string_literal: true require 'psych/json/ruby_events' module Psych module Visitors class JSONTree < YAMLTree include Psych::JSON::RubyEvents def self.create options = {} emitter = Psych::JSON::TreeBuilder.new class_loader = ClassLoader.new ss = ScalarScanner.new class_loader new(emitter, ss, options) end def accept target if target.respond_to?(:encode_with) dump_coder target else send(@dispatch_cache[target.class], target) end end end end end PKu]R(rr-psych-3.1.0/lib/psych/visitors/depth_first.rbnu[# frozen_string_literal: true module Psych module Visitors class DepthFirst < Psych::Visitors::Visitor def initialize block @block = block end private def nary o o.children.each { |x| visit x } @block.call o end alias :visit_Psych_Nodes_Stream :nary alias :visit_Psych_Nodes_Document :nary alias :visit_Psych_Nodes_Sequence :nary alias :visit_Psych_Nodes_Mapping :nary def terminal o @block.call o end alias :visit_Psych_Nodes_Scalar :terminal alias :visit_Psych_Nodes_Alias :terminal end end end PKu]#<#<+psych-3.1.0/lib/psych/visitors/yaml_tree.rbnu[# frozen_string_literal: true require 'psych/tree_builder' require 'psych/scalar_scanner' require 'psych/class_loader' module Psych module Visitors ### # YAMLTree builds a YAML ast given a Ruby object. For example: # # builder = Psych::Visitors::YAMLTree.new # builder << { :foo => 'bar' } # builder.tree # => # v } @emitter.end_sequence end def visit_Encoding o tag = "!ruby/encoding" @emitter.scalar o.name, nil, tag, false, false, Nodes::Scalar::ANY end def visit_Object o tag = Psych.dump_tags[o.class] unless tag klass = o.class == Object ? nil : o.class.name tag = ['!ruby/object', klass].compact.join(':') end map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) register(o, map) dump_ivars o @emitter.end_mapping end alias :visit_Delegator :visit_Object def visit_Struct o tag = ['!ruby/struct', o.class.name].compact.join(':') register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) o.members.each do |member| @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY accept o[member] end dump_ivars o @emitter.end_mapping end def visit_Exception o dump_exception o, private_iv_get(o, 'mesg') end def visit_NameError o dump_exception o, o.message.to_s end def visit_Regexp o register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY) end def visit_DateTime o formatted = if o.offset.zero? o.strftime("%Y-%m-%d %H:%M:%S.%9N Z".freeze) else o.strftime("%Y-%m-%d %H:%M:%S.%9N %:z".freeze) end tag = '!ruby/object:DateTime' register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY) end def visit_Time o formatted = format_time o register o, @emitter.scalar(formatted, nil, nil, true, false, Nodes::Scalar::ANY) end def visit_Rational o register o, @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK) [ 'denominator', o.denominator.to_s, 'numerator', o.numerator.to_s ].each do |m| @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY end @emitter.end_mapping end def visit_Complex o register o, @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK) ['real', o.real.to_s, 'image', o.imag.to_s].each do |m| @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY end @emitter.end_mapping end def visit_Integer o @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY end alias :visit_TrueClass :visit_Integer alias :visit_FalseClass :visit_Integer alias :visit_Date :visit_Integer def visit_Float o if o.nan? @emitter.scalar '.nan', nil, nil, true, false, Nodes::Scalar::ANY elsif o.infinite? @emitter.scalar((o.infinite? > 0 ? '.inf' : '-.inf'), nil, nil, true, false, Nodes::Scalar::ANY) else @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY end end def visit_BigDecimal o @emitter.scalar o._dump, nil, '!ruby/object:BigDecimal', false, false, Nodes::Scalar::ANY end def visit_String o plain = true quote = true style = Nodes::Scalar::PLAIN tag = nil if binary?(o) o = [o].pack('m0') tag = '!binary' # FIXME: change to below when syck is removed #tag = 'tag:yaml.org,2002:binary' style = Nodes::Scalar::LITERAL plain = false quote = false elsif o =~ /\n(?!\Z)/ # match \n except blank line at the end of string style = Nodes::Scalar::LITERAL elsif o == '<<' style = Nodes::Scalar::SINGLE_QUOTED tag = 'tag:yaml.org,2002:str' plain = false quote = false elsif @line_width && o.length > @line_width style = Nodes::Scalar::FOLDED elsif o =~ /^[^[:word:]][^"]*$/ style = Nodes::Scalar::DOUBLE_QUOTED elsif not String === @ss.tokenize(o) or /\A0[0-7]*[89]/ =~ o style = Nodes::Scalar::SINGLE_QUOTED end is_primitive = o.class == ::String ivars = is_primitive ? [] : o.instance_variables if ivars.empty? unless is_primitive tag = "!ruby/string:#{o.class}" plain = false quote = false end @emitter.scalar o, nil, tag, plain, quote, style else maptag = '!ruby/string'.dup maptag << ":#{o.class}" unless o.class == ::String register o, @emitter.start_mapping(nil, maptag, false, Nodes::Mapping::BLOCK) @emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY @emitter.scalar o, nil, tag, plain, quote, style dump_ivars o @emitter.end_mapping end end def visit_Module o raise TypeError, "can't dump anonymous module: #{o}" unless o.name register o, @emitter.scalar(o.name, nil, '!ruby/module', false, false, Nodes::Scalar::SINGLE_QUOTED) end def visit_Class o raise TypeError, "can't dump anonymous class: #{o}" unless o.name register o, @emitter.scalar(o.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED) end def visit_Range o register o, @emitter.start_mapping(nil, '!ruby/range', false, Nodes::Mapping::BLOCK) ['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m| accept m end @emitter.end_mapping end def visit_Hash o if o.class == ::Hash register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK)) o.each do |k,v| accept k accept v end @emitter.end_mapping else visit_hash_subclass o end end def visit_Psych_Set o register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK)) o.each do |k,v| accept k accept v end @emitter.end_mapping end def visit_Array o if o.class == ::Array visit_Enumerator o else visit_array_subclass o end end def visit_Enumerator o register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) o.each { |c| accept c } @emitter.end_sequence end def visit_NilClass o @emitter.scalar('', nil, 'tag:yaml.org,2002:null', true, false, Nodes::Scalar::ANY) end def visit_Symbol o if o.empty? @emitter.scalar "", nil, '!ruby/symbol', false, false, Nodes::Scalar::ANY else @emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY end end def visit_BasicObject o tag = Psych.dump_tags[o.class] tag ||= "!ruby/marshalable:#{o.class.name}" map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) register(o, map) o.marshal_dump.each(&method(:accept)) @emitter.end_mapping end private def binary? string string.encoding == Encoding::ASCII_8BIT && !string.ascii_only? end def visit_array_subclass o tag = "!ruby/array:#{o.class}" ivars = o.instance_variables if ivars.empty? node = @emitter.start_sequence(nil, tag, false, Nodes::Sequence::BLOCK) register o, node o.each { |c| accept c } @emitter.end_sequence else node = @emitter.start_mapping(nil, tag, false, Nodes::Sequence::BLOCK) register o, node # Dump the internal list accept 'internal' @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) o.each { |c| accept c } @emitter.end_sequence # Dump the ivars accept 'ivars' @emitter.start_mapping(nil, nil, true, Nodes::Sequence::BLOCK) ivars.each do |ivar| accept ivar accept o.instance_variable_get ivar end @emitter.end_mapping @emitter.end_mapping end end def visit_hash_subclass o ivars = o.instance_variables if ivars.any? tag = "!ruby/hash-with-ivars:#{o.class}" node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) register(o, node) # Dump the ivars accept 'ivars' @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK o.instance_variables.each do |ivar| accept ivar accept o.instance_variable_get ivar end @emitter.end_mapping # Dump the elements accept 'elements' @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK o.each do |k,v| accept k accept v end @emitter.end_mapping @emitter.end_mapping else tag = "!ruby/hash:#{o.class}" node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) register(o, node) o.each do |k,v| accept k accept v end @emitter.end_mapping end end def dump_list o end def dump_exception o, msg tag = ['!ruby/exception', o.class.name].join ':' @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK if msg @emitter.scalar 'message', nil, nil, true, false, Nodes::Scalar::ANY accept msg end @emitter.scalar 'backtrace', nil, nil, true, false, Nodes::Scalar::ANY accept o.backtrace dump_ivars o @emitter.end_mapping end def format_time time if time.utc? time.strftime("%Y-%m-%d %H:%M:%S.%9N Z") else time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z") end end def register target, yaml_obj @st.register target, yaml_obj yaml_obj end def dump_coder o @coders << o tag = Psych.dump_tags[o.class] unless tag klass = o.class == Object ? nil : o.class.name tag = ['!ruby/object', klass].compact.join(':') end c = Psych::Coder.new(tag) o.encode_with(c) emit_coder c, o end def emit_coder c, o case c.type when :scalar @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, Nodes::Scalar::ANY when :seq @emitter.start_sequence nil, c.tag, c.tag.nil?, Nodes::Sequence::BLOCK c.seq.each do |thing| accept thing end @emitter.end_sequence when :map register o, @emitter.start_mapping(nil, c.tag, c.implicit, c.style) c.map.each do |k,v| accept k accept v end @emitter.end_mapping when :object accept c.object end end def dump_ivars target target.instance_variables.each do |iv| @emitter.scalar("#{iv.to_s.sub(/^@/, '')}", nil, nil, true, false, Nodes::Scalar::ANY) accept target.instance_variable_get(iv) end end end end end PKu]6*4gg)psych-3.1.0/lib/psych/visitors/visitor.rbnu[# frozen_string_literal: true module Psych module Visitors class Visitor def accept target visit target end private DISPATCH = Hash.new do |hash, klass| hash[klass] = "visit_#{klass.name.gsub('::', '_')}" end def visit target send DISPATCH[target.class], target end end end end PKu]Sܶ..)psych-3.1.0/lib/psych/visitors/to_ruby.rbnu[# frozen_string_literal: true require 'psych/scalar_scanner' require 'psych/class_loader' require 'psych/exception' unless defined?(Regexp::NOENCODING) Regexp::NOENCODING = 32 end module Psych module Visitors ### # This class walks a YAML AST, converting each node to Ruby class ToRuby < Psych::Visitors::Visitor def self.create class_loader = ClassLoader.new scanner = ScalarScanner.new class_loader new(scanner, class_loader) end attr_reader :class_loader def initialize ss, class_loader super() @st = {} @ss = ss @domain_types = Psych.domain_types @class_loader = class_loader end def accept target result = super return result if @domain_types.empty? || !target.tag key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:') key = "tag:#{key}" unless key =~ /^(?:tag:|x-private)/ if @domain_types.key? key value, block = @domain_types[key] return block.call value, result end result end def deserialize o if klass = resolve_class(Psych.load_tags[o.tag]) instance = klass.allocate if instance.respond_to?(:init_with) coder = Psych::Coder.new(o.tag) coder.scalar = o.value instance.init_with coder end return instance end return o.value if o.quoted return @ss.tokenize(o.value) unless o.tag case o.tag when '!binary', 'tag:yaml.org,2002:binary' o.value.unpack('m').first when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str' klass = resolve_class($1) if klass klass.allocate.replace o.value else o.value end when '!ruby/object:BigDecimal' require 'bigdecimal' unless defined? BigDecimal class_loader.big_decimal._load o.value when "!ruby/object:DateTime" class_loader.date_time require 'date' unless defined? DateTime @ss.parse_time(o.value).to_datetime when '!ruby/encoding' ::Encoding.find o.value when "!ruby/object:Complex" class_loader.complex Complex(o.value) when "!ruby/object:Rational" class_loader.rational Rational(o.value) when "!ruby/class", "!ruby/module" resolve_class o.value when "tag:yaml.org,2002:float", "!float" Float(@ss.tokenize(o.value)) when "!ruby/regexp" klass = class_loader.regexp o.value =~ /^\/(.*)\/([mixn]*)$/m source = $1 options = 0 lang = nil ($2 || '').split('').each do |option| case option when 'x' then options |= Regexp::EXTENDED when 'i' then options |= Regexp::IGNORECASE when 'm' then options |= Regexp::MULTILINE when 'n' then options |= Regexp::NOENCODING else lang = option end end klass.new(*[source, options, lang].compact) when "!ruby/range" klass = class_loader.range args = o.value.split(/([.]{2,3})/, 2).map { |s| accept Nodes::Scalar.new(s) } args.push(args.delete_at(1) == '...') klass.new(*args) when /^!ruby\/sym(bol)?:?(.*)?$/ class_loader.symbolize o.value else @ss.tokenize o.value end end private :deserialize def visit_Psych_Nodes_Scalar o register o, deserialize(o) end def visit_Psych_Nodes_Sequence o if klass = resolve_class(Psych.load_tags[o.tag]) instance = klass.allocate if instance.respond_to?(:init_with) coder = Psych::Coder.new(o.tag) coder.seq = o.children.map { |c| accept c } instance.init_with coder end return instance end case o.tag when nil register_empty(o) when '!omap', 'tag:yaml.org,2002:omap' map = register(o, Psych::Omap.new) o.children.each { |a| map[accept(a.children.first)] = accept a.children.last } map when /^!(?:seq|ruby\/array):(.*)$/ klass = resolve_class($1) list = register(o, klass.allocate) o.children.each { |c| list.push accept c } list else register_empty(o) end end def visit_Psych_Nodes_Mapping o if Psych.load_tags[o.tag] return revive(resolve_class(Psych.load_tags[o.tag]), o) end return revive_hash(register(o, {}), o) unless o.tag case o.tag when /^!ruby\/struct:?(.*)?$/ klass = resolve_class($1) if $1 if klass s = register(o, klass.allocate) members = {} struct_members = s.members.map { |x| class_loader.symbolize x } o.children.each_slice(2) do |k,v| member = accept(k) value = accept(v) if struct_members.include?(class_loader.symbolize(member)) s.send("#{member}=", value) else members[member.to_s.sub(/^@/, '')] = value end end init_with(s, members, o) else klass = class_loader.struct members = o.children.map { |c| accept c } h = Hash[*members] s = klass.new(*h.map { |k,v| class_loader.symbolize k }).new(*h.map { |k,v| v }) register(o, s) s end when /^!ruby\/object:?(.*)?$/ name = $1 || 'Object' if name == 'Complex' class_loader.complex h = Hash[*o.children.map { |c| accept c }] register o, Complex(h['real'], h['image']) elsif name == 'Rational' class_loader.rational h = Hash[*o.children.map { |c| accept c }] register o, Rational(h['numerator'], h['denominator']) elsif name == 'Hash' revive_hash(register(o, {}), o) else obj = revive((resolve_class(name) || class_loader.object), o) obj end when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str' klass = resolve_class($1) members = {} string = nil o.children.each_slice(2) do |k,v| key = accept k value = accept v if key == 'str' if klass string = klass.allocate.replace value else string = value end register(o, string) else members[key] = value end end init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o) when /^!ruby\/array:(.*)$/ klass = resolve_class($1) list = register(o, klass.allocate) members = Hash[o.children.map { |c| accept c }.each_slice(2).to_a] list.replace members['internal'] members['ivars'].each do |ivar, v| list.instance_variable_set ivar, v end list when '!ruby/range' klass = class_loader.range h = Hash[*o.children.map { |c| accept c }] register o, klass.new(h['begin'], h['end'], h['excl']) when /^!ruby\/exception:?(.*)?$/ h = Hash[*o.children.map { |c| accept c }] e = build_exception((resolve_class($1) || class_loader.exception), h.delete('message')) e.set_backtrace h.delete('backtrace') if h.key? 'backtrace' init_with(e, h, o) when '!set', 'tag:yaml.org,2002:set' set = class_loader.psych_set.new @st[o.anchor] = set if o.anchor o.children.each_slice(2) do |k,v| set[accept(k)] = accept(v) end set when /^!ruby\/hash-with-ivars(?::(.*))?$/ hash = $1 ? resolve_class($1).allocate : {} register o, hash o.children.each_slice(2) do |key, value| case key.value when 'elements' revive_hash hash, value when 'ivars' value.children.each_slice(2) do |k,v| hash.instance_variable_set accept(k), accept(v) end end end hash when /^!map:(.*)$/, /^!ruby\/hash:(.*)$/ revive_hash register(o, resolve_class($1).allocate), o when '!omap', 'tag:yaml.org,2002:omap' map = register(o, class_loader.psych_omap.new) o.children.each_slice(2) do |l,r| map[accept(l)] = accept r end map when /^!ruby\/marshalable:(.*)$/ name = $1 klass = resolve_class(name) obj = register(o, klass.allocate) if obj.respond_to?(:init_with) init_with(obj, revive_hash({}, o), o) elsif obj.respond_to?(:marshal_load) marshal_data = o.children.map(&method(:accept)) obj.marshal_load(marshal_data) obj else raise ArgumentError, "Cannot deserialize #{name}" end else revive_hash(register(o, {}), o) end end def visit_Psych_Nodes_Document o accept o.root end def visit_Psych_Nodes_Stream o o.children.map { |c| accept c } end def visit_Psych_Nodes_Alias o @st.fetch(o.anchor) { raise BadAlias, "Unknown alias: #{o.anchor}" } end private def register node, object @st[node.anchor] = object if node.anchor object end def register_empty object list = register(object, []) object.children.each { |c| list.push accept c } list end SHOVEL = '<<' def revive_hash hash, o o.children.each_slice(2) { |k,v| key = deduplicate(accept(k)) val = accept(v) if key == SHOVEL && k.tag != "tag:yaml.org,2002:str" case v when Nodes::Alias, Nodes::Mapping begin hash.merge! val rescue TypeError hash[key] = val end when Nodes::Sequence begin h = {} val.reverse_each do |value| h.merge! value end hash.merge! h rescue TypeError hash[key] = val end else hash[key] = val end else hash[key] = val end } hash end if RUBY_VERSION < '2.7' def deduplicate key if key.is_a?(String) -(key.untaint) else key end end else def deduplicate key if key.is_a?(String) -key else key end end end def merge_key hash, key, val end def revive klass, node s = register(node, klass.allocate) init_with(s, revive_hash({}, node), node) end def init_with o, h, node c = Psych::Coder.new(node.tag) c.map = h if o.respond_to?(:init_with) o.init_with c else h.each { |k,v| o.instance_variable_set(:"@#{k}", v) } end o end # Convert +klassname+ to a Class def resolve_class klassname class_loader.load klassname end end class NoAliasRuby < ToRuby def visit_Psych_Nodes_Alias o raise BadAlias, "Unknown alias: #{o.anchor}" end end end end PKu]Z)psych-3.1.0/lib/psych/visitors/emitter.rbnu[# frozen_string_literal: true module Psych module Visitors class Emitter < Psych::Visitors::Visitor def initialize io, options = {} opts = [:indentation, :canonical, :line_width].find_all { |opt| options.key?(opt) } if opts.empty? @handler = Psych::Emitter.new io else du = Handler::DumperOptions.new opts.each { |option| du.send :"#{option}=", options[option] } @handler = Psych::Emitter.new io, du end end def visit_Psych_Nodes_Stream o @handler.start_stream o.encoding o.children.each { |c| accept c } @handler.end_stream end def visit_Psych_Nodes_Document o @handler.start_document o.version, o.tag_directives, o.implicit o.children.each { |c| accept c } @handler.end_document o.implicit_end end def visit_Psych_Nodes_Scalar o @handler.scalar o.value, o.anchor, o.tag, o.plain, o.quoted, o.style end def visit_Psych_Nodes_Sequence o @handler.start_sequence o.anchor, o.tag, o.implicit, o.style o.children.each { |c| accept c } @handler.end_sequence end def visit_Psych_Nodes_Mapping o @handler.start_mapping o.anchor, o.tag, o.implicit, o.style o.children.each { |c| accept c } @handler.end_mapping end def visit_Psych_Nodes_Alias o @handler.alias o.anchor end end end end PKu]fk k psych-3.1.0/lib/psych/nodes.rbnu[# frozen_string_literal: true require 'psych/nodes/node' require 'psych/nodes/stream' require 'psych/nodes/document' require 'psych/nodes/sequence' require 'psych/nodes/scalar' require 'psych/nodes/mapping' require 'psych/nodes/alias' module Psych ### # = Overview # # When using Psych.load to deserialize a YAML document, the document is # translated to an intermediary AST. That intermediary AST is then # translated in to a Ruby object graph. # # In the opposite direction, when using Psych.dump, the Ruby object graph is # translated to an intermediary AST which is then converted to a YAML # document. # # Psych::Nodes contains all of the classes that make up the nodes of a YAML # AST. You can manually build an AST and use one of the visitors (see # Psych::Visitors) to convert that AST to either a YAML document or to a # Ruby object graph. # # Here is an example of building an AST that represents a list with one # scalar: # # # Create our nodes # stream = Psych::Nodes::Stream.new # doc = Psych::Nodes::Document.new # seq = Psych::Nodes::Sequence.new # scalar = Psych::Nodes::Scalar.new('foo') # # # Build up our tree # stream.children << doc # doc.children << seq # seq.children << scalar # # The stream is the root of the tree. We can then convert the tree to YAML: # # stream.to_yaml => "---\n- foo\n" # # Or convert it to Ruby: # # stream.to_ruby => [["foo"]] # # == YAML AST Requirements # # A valid YAML AST *must* have one Psych::Nodes::Stream at the root. A # Psych::Nodes::Stream node must have 1 or more Psych::Nodes::Document nodes # as children. # # Psych::Nodes::Document nodes must have one and *only* one child. That child # may be one of: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar # # Psych::Nodes::Sequence and Psych::Nodes::Mapping nodes may have many # children, but Psych::Nodes::Mapping nodes should have an even number of # children. # # All of these are valid children for Psych::Nodes::Sequence and # Psych::Nodes::Mapping nodes: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar # * Psych::Nodes::Alias # # Psych::Nodes::Scalar and Psych::Nodes::Alias are both terminal nodes and # should not have any children. module Nodes end end PKu]'Kpsych-3.1.0/lib/psych/y.rbnu[# frozen_string_literal: true module Kernel ### # An alias for Psych.dump_stream meant to be used with IRB. def y *objects puts Psych.dump_stream(*objects) end private :y end PKu]%!psych-3.1.0/lib/psych/versions.rbnu[ # frozen_string_literal: true module Psych # The version of Psych you are using VERSION = '3.1.0' unless defined?(::Psych::VERSION) if RUBY_ENGINE == 'jruby' DEFAULT_SNAKEYAML_VERSION = '1.23'.freeze end end PKu]rpsych-3.1.0/lib/psych/stream.rbnu[# frozen_string_literal: true module Psych ### # Psych::Stream is a streaming YAML emitter. It will not buffer your YAML, # but send it straight to an IO. # # Here is an example use: # # stream = Psych::Stream.new($stdout) # stream.start # stream.push({:foo => 'bar'}) # stream.finish # # YAML will be immediately emitted to $stdout with no buffering. # # Psych::Stream#start will take a block and ensure that Psych::Stream#finish # is called, so you can do this form: # # stream = Psych::Stream.new($stdout) # stream.start do |em| # em.push(:foo => 'bar') # end # class Stream < Psych::Visitors::YAMLTree class Emitter < Psych::Emitter # :nodoc: def end_document implicit_end = !streaming? super end def streaming? true end end include Psych::Streaming extend Psych::Streaming::ClassMethods end end PKu]&3*II%psych-3.1.0/lib/psych/syntax_error.rbnu[# frozen_string_literal: true require 'psych/exception' module Psych class SyntaxError < Psych::Exception attr_reader :file, :line, :column, :offset, :problem, :context def initialize file, line, col, offset, problem, context err = [problem, context].compact.join ' ' filename = file || '' message = "(%s): %s at line %d column %d" % [filename, err, line, col] @file = file @line = line @column = col @offset = offset @problem = problem @context = context super(message) end end end PKu]y2K"psych-3.1.0/lib/psych/streaming.rbnu[# frozen_string_literal: true module Psych module Streaming module ClassMethods ### # Create a new streaming emitter. Emitter will print to +io+. See # Psych::Stream for an example. def new io emitter = const_get(:Emitter).new(io) class_loader = ClassLoader.new ss = ScalarScanner.new class_loader super(emitter, ss, {}) end end ### # Start streaming using +encoding+ def start encoding = Nodes::Stream::UTF8 super.tap { yield self if block_given? } ensure finish if block_given? end private def register target, obj end end end PKu]ӻ!psych-3.1.0/lib/psych/visitors.rbnu[# frozen_string_literal: true require 'psych/visitors/visitor' require 'psych/visitors/to_ruby' require 'psych/visitors/emitter' require 'psych/visitors/yaml_tree' require 'psych/visitors/json_tree' require 'psych/visitors/depth_first' PKu]oe %psych-3.1.0/lib/psych/class_loader.rbnu[# frozen_string_literal: true require 'psych/omap' require 'psych/set' module Psych class ClassLoader # :nodoc: BIG_DECIMAL = 'BigDecimal' COMPLEX = 'Complex' DATE = 'Date' DATE_TIME = 'DateTime' EXCEPTION = 'Exception' OBJECT = 'Object' PSYCH_OMAP = 'Psych::Omap' PSYCH_SET = 'Psych::Set' RANGE = 'Range' RATIONAL = 'Rational' REGEXP = 'Regexp' STRUCT = 'Struct' SYMBOL = 'Symbol' def initialize @cache = CACHE.dup end def load klassname return nil if !klassname || klassname.empty? find klassname end def symbolize sym symbol sym.to_sym end constants.each do |const| konst = const_get const define_method(const.to_s.downcase) do load konst end end private def find klassname @cache[klassname] ||= resolve(klassname) end def resolve klassname name = klassname retried = false begin path2class(name) rescue ArgumentError, NameError => ex unless retried name = "Struct::#{name}" retried = ex retry end raise retried end end CACHE = Hash[constants.map { |const| val = const_get const begin [val, ::Object.const_get(val)] rescue nil end }.compact] class Restricted < ClassLoader def initialize classes, symbols @classes = classes @symbols = symbols super() end def symbolize sym return super if @symbols.empty? if @symbols.include? sym super else raise DisallowedClass, 'Symbol' end end private def find klassname if @classes.include? klassname super else raise DisallowedClass, klassname end end end end end PKu]|uu*psych-3.1.0/lib/psych/handlers/recorder.rbnu[# frozen_string_literal: true require 'psych/handler' module Psych module Handlers ### # This handler will capture an event and record the event. Recorder events # are available vial Psych::Handlers::Recorder#events. # # For example: # # recorder = Psych::Handlers::Recorder.new # parser = Psych::Parser.new recorder # parser.parse '--- foo' # # recorder.events # => [list of events] # # # Replay the events # # emitter = Psych::Emitter.new $stdout # recorder.events.each do |m, args| # emitter.send m, *args # end class Recorder < Psych::Handler attr_reader :events def initialize @events = [] super end EVENTS.each do |event| define_method event do |*args| @events << [event, args] end end end end end PKu]}1psych-3.1.0/lib/psych/handlers/document_stream.rbnu[# frozen_string_literal: true require 'psych/tree_builder' module Psych module Handlers class DocumentStream < Psych::TreeBuilder # :nodoc: def initialize &block super @block = block end def start_document version, tag_directives, implicit n = Nodes::Document.new version, tag_directives, implicit push n end def end_document implicit_end = !streaming? @last.implicit_end = implicit_end @block.call pop end end end end PKu](Cee*psych-3.1.0/lib/psych/json/tree_builder.rbnu[# frozen_string_literal: true require 'psych/json/yaml_events' module Psych module JSON ### # Psych::JSON::TreeBuilder is an event based AST builder. Events are sent # to an instance of Psych::JSON::TreeBuilder and a JSON AST is constructed. class TreeBuilder < Psych::TreeBuilder include Psych::JSON::YAMLEvents end end end PKu]  )psych-3.1.0/lib/psych/json/yaml_events.rbnu[# frozen_string_literal: true module Psych module JSON module YAMLEvents # :nodoc: def start_document version, tag_directives, implicit super(version, tag_directives, !streaming?) end def end_document implicit_end = !streaming? super(implicit_end) end def start_mapping anchor, tag, implicit, style super(anchor, nil, true, Nodes::Mapping::FLOW) end def start_sequence anchor, tag, implicit, style super(anchor, nil, true, Nodes::Sequence::FLOW) end def scalar value, anchor, tag, plain, quoted, style if "tag:yaml.org,2002:null" == tag super('null', nil, nil, true, false, Nodes::Scalar::PLAIN) else super end end end end end PKu] Ej$psych-3.1.0/lib/psych/json/stream.rbnu[# frozen_string_literal: true require 'psych/json/ruby_events' require 'psych/json/yaml_events' module Psych module JSON class Stream < Psych::Visitors::JSONTree include Psych::JSON::RubyEvents include Psych::Streaming extend Psych::Streaming::ClassMethods class Emitter < Psych::Stream::Emitter # :nodoc: include Psych::JSON::YAMLEvents end end end end PKu])psych-3.1.0/lib/psych/json/ruby_events.rbnu[# frozen_string_literal: true module Psych module JSON module RubyEvents # :nodoc: def visit_Time o formatted = format_time o @emitter.scalar formatted, nil, nil, false, true, Nodes::Scalar::DOUBLE_QUOTED end def visit_DateTime o visit_Time o.to_time end def visit_String o @emitter.scalar o.to_s, nil, nil, false, true, Nodes::Scalar::DOUBLE_QUOTED end alias :visit_Symbol :visit_String end end end PKu]u>22psych-3.1.0/lib/psych/coder.rbnu[# frozen_string_literal: true module Psych ### # If an object defines +encode_with+, then an instance of Psych::Coder will # be passed to the method when the object is being serialized. The Coder # automatically assumes a Psych::Nodes::Mapping is being emitted. Other # objects like Sequence and Scalar may be emitted if +seq=+ or +scalar=+ are # called, respectively. class Coder attr_accessor :tag, :style, :implicit, :object attr_reader :type, :seq def initialize tag @map = {} @seq = [] @implicit = false @type = :map @tag = tag @style = Psych::Nodes::Mapping::BLOCK @scalar = nil @object = nil end def scalar *args if args.length > 0 warn "#{caller[0]}: Coder#scalar(a,b,c) is deprecated" if $VERBOSE @tag, @scalar, _ = args @type = :scalar end @scalar end # Emit a map. The coder will be yielded to the block. def map tag = @tag, style = @style @tag = tag @style = style yield self if block_given? @map end # Emit a scalar with +value+ and +tag+ def represent_scalar tag, value self.tag = tag self.scalar = value end # Emit a sequence with +list+ and +tag+ def represent_seq tag, list @tag = tag self.seq = list end # Emit a sequence with +map+ and +tag+ def represent_map tag, map @tag = tag self.map = map end # Emit an arbitrary object +obj+ and +tag+ def represent_object tag, obj @tag = tag @type = :object @object = obj end # Emit a scalar with +value+ def scalar= value @type = :scalar @scalar = value end # Emit a map with +value+ def map= map @type = :map @map = map end def []= k, v @type = :map @map[k] = v end alias :add :[]= def [] k @type = :map @map[k] end # Emit a sequence of +list+ def seq= list @type = :seq @seq = list end end end PKu]"+  #psych-3.1.0/lib/psych/nodes/node.rbnu[# frozen_string_literal: true require 'stringio' require 'psych/class_loader' require 'psych/scalar_scanner' module Psych module Nodes ### # The base class for any Node in a YAML parse tree. This class should # never be instantiated. class Node include Enumerable # The children of this node attr_reader :children # An associated tag attr_reader :tag # The line number where this node start attr_accessor :start_line # The column number where this node start attr_accessor :start_column # The line number where this node ends attr_accessor :end_line # The column number where this node ends attr_accessor :end_column # Create a new Psych::Nodes::Node def initialize @children = [] end ### # Iterate over each node in the tree. Yields each node to +block+ depth # first. def each &block return enum_for :each unless block_given? Visitors::DepthFirst.new(block).accept self end ### # Convert this node to Ruby. # # See also Psych::Visitors::ToRuby def to_ruby Visitors::ToRuby.create.accept(self) end alias :transform :to_ruby ### # Convert this node to YAML. # # See also Psych::Visitors::Emitter def yaml io = nil, options = {} real_io = io || StringIO.new(''.encode('utf-8')) Visitors::Emitter.new(real_io, options).accept self return real_io.string unless io io end alias :to_yaml :yaml def alias?; false; end def document?; false; end def mapping?; false; end def scalar?; false; end def sequence?; false; end def stream?; false; end end end end PKu]믍!!'psych-3.1.0/lib/psych/nodes/sequence.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This class represents a # {YAML sequence}[http://yaml.org/spec/1.1/#sequence/syntax]. # # A YAML sequence is basically a list, and looks like this: # # %YAML 1.1 # --- # - I am # - a Sequence # # A YAML sequence may have an anchor like this: # # %YAML 1.1 # --- # &A [ # "This sequence", # "has an anchor" # ] # # A YAML sequence may also have a tag like this: # # %YAML 1.1 # --- # !!seq [ # "This sequence", # "has a tag" # ] # # This class represents a sequence in a YAML document. A # Psych::Nodes::Sequence node may have 0 or more children. Valid children # for this node are: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar # * Psych::Nodes::Alias class Sequence < Psych::Nodes::Node # Any Styles, emitter chooses ANY = 0 # Block style sequence BLOCK = 1 # Flow style sequence FLOW = 2 # The anchor for this sequence (if any) attr_accessor :anchor # The tag name for this sequence (if any) attr_accessor :tag # Is this sequence started implicitly? attr_accessor :implicit # The sequence style used attr_accessor :style ### # Create a new object representing a YAML sequence. # # +anchor+ is the anchor associated with the sequence or nil. # +tag+ is the tag associated with the sequence or nil. # +implicit+ a boolean indicating whether or not the sequence was # implicitly started. # +style+ is an integer indicating the list style. # # See Psych::Handler#start_sequence def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK super() @anchor = anchor @tag = tag @implicit = implicit @style = style end def sequence?; true; end end end end PKu]ɉ  $psych-3.1.0/lib/psych/nodes/alias.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This class represents a {YAML Alias}[http://yaml.org/spec/1.1/#alias]. # It points to an +anchor+. # # A Psych::Nodes::Alias is a terminal node and may have no children. class Alias < Psych::Nodes::Node # The anchor this alias links to attr_accessor :anchor # Create a new Alias that points to an +anchor+ def initialize anchor @anchor = anchor end def alias?; true; end end end end PKu])))&psych-3.1.0/lib/psych/nodes/mapping.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This class represents a {YAML Mapping}[http://yaml.org/spec/1.1/#mapping]. # # A Psych::Nodes::Mapping node may have 0 or more children, but must have # an even number of children. Here are the valid children a # Psych::Nodes::Mapping node may have: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar # * Psych::Nodes::Alias class Mapping < Psych::Nodes::Node # Any Map Style ANY = 0 # Block Map Style BLOCK = 1 # Flow Map Style FLOW = 2 # The optional anchor for this mapping attr_accessor :anchor # The optional tag for this mapping attr_accessor :tag # Is this an implicit mapping? attr_accessor :implicit # The style of this mapping attr_accessor :style ### # Create a new Psych::Nodes::Mapping object. # # +anchor+ is the anchor associated with the map or +nil+. # +tag+ is the tag associated with the map or +nil+. # +implicit+ is a boolean indicating whether or not the map was implicitly # started. # +style+ is an integer indicating the mapping style. # # == See Also # See also Psych::Handler#start_mapping def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK super() @anchor = anchor @tag = tag @implicit = implicit @style = style end def mapping?; true; end end end end PKu]Ϧ[%psych-3.1.0/lib/psych/nodes/stream.rbnu[# frozen_string_literal: true module Psych module Nodes ### # Represents a YAML stream. This is the root node for any YAML parse # tree. This node must have one or more child nodes. The only valid # child node for a Psych::Nodes::Stream node is Psych::Nodes::Document. class Stream < Psych::Nodes::Node # Encodings supported by Psych (and libyaml) # Any encoding ANY = Psych::Parser::ANY # UTF-8 encoding UTF8 = Psych::Parser::UTF8 # UTF-16LE encoding UTF16LE = Psych::Parser::UTF16LE # UTF-16BE encoding UTF16BE = Psych::Parser::UTF16BE # The encoding used for this stream attr_accessor :encoding ### # Create a new Psych::Nodes::Stream node with an +encoding+ that # defaults to Psych::Nodes::Stream::UTF8. # # See also Psych::Handler#start_stream def initialize encoding = UTF8 super() @encoding = encoding end def stream?; true; end end end end PKu](%%psych-3.1.0/lib/psych/nodes/scalar.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This class represents a {YAML Scalar}[http://yaml.org/spec/1.1/#id858081]. # # This node type is a terminal node and should not have any children. class Scalar < Psych::Nodes::Node # Any style scalar, the emitter chooses ANY = 0 # Plain scalar style PLAIN = 1 # Single quoted style SINGLE_QUOTED = 2 # Double quoted style DOUBLE_QUOTED = 3 # Literal style LITERAL = 4 # Folded style FOLDED = 5 # The scalar value attr_accessor :value # The anchor value (if there is one) attr_accessor :anchor # The tag value (if there is one) attr_accessor :tag # Is this a plain scalar? attr_accessor :plain # Is this scalar quoted? attr_accessor :quoted # The style of this scalar attr_accessor :style ### # Create a new Psych::Nodes::Scalar object. # # +value+ is the string value of the scalar # +anchor+ is an associated anchor or nil # +tag+ is an associated tag or nil # +plain+ is a boolean value # +quoted+ is a boolean value # +style+ is an integer idicating the string style # # == See Also # # See also Psych::Handler#scalar def initialize value, anchor = nil, tag = nil, plain = true, quoted = false, style = ANY @value = value @anchor = anchor @tag = tag @plain = plain @quoted = quoted @style = style end def scalar?; true; end end end end PKu]AA'psych-3.1.0/lib/psych/nodes/document.rbnu[# frozen_string_literal: true module Psych module Nodes ### # This represents a YAML Document. This node must be a child of # Psych::Nodes::Stream. A Psych::Nodes::Document must have one child, # and that child may be one of the following: # # * Psych::Nodes::Sequence # * Psych::Nodes::Mapping # * Psych::Nodes::Scalar class Document < Psych::Nodes::Node # The version of the YAML document attr_accessor :version # A list of tag directives for this document attr_accessor :tag_directives # Was this document implicitly created? attr_accessor :implicit # Is the end of the document implicit? attr_accessor :implicit_end ### # Create a new Psych::Nodes::Document object. # # +version+ is a list indicating the YAML version. # +tags_directives+ is a list of tag directive declarations # +implicit+ is a flag indicating whether the document will be implicitly # started. # # == Example: # This creates a YAML document object that represents a YAML 1.1 document # with one tag directive, and has an implicit start: # # Psych::Nodes::Document.new( # [1,1], # [["!", "tag:tenderlovemaking.com,2009:"]], # true # ) # # == See Also # See also Psych::Handler#start_document def initialize version = [], tag_directives = [], implicit = false super() @version = version @tag_directives = tag_directives @implicit = implicit @implicit_end = true end ### # Returns the root node. A Document may only have one root node: # http://yaml.org/spec/1.1/#id898031 def root children.first end def document?; true; end end end end PKu]Rzgg!psych-3.1.0/lib/psych/core_ext.rbnu[# frozen_string_literal: true class Object def self.yaml_tag url Psych.add_tag(url, self) end ### # call-seq: to_yaml(options = {}) # # Convert an object to YAML. See Psych.dump for more information on the # available +options+. def to_yaml options = {} Psych.dump self, options end end if defined?(::IRB) require 'psych/y' end PK!<]Ms C C#ruby/bigdecimal-1.3.4/bigdecimal.sonuȯPK!<][``sCruby/psych-3.0.2/psych.sonuȯPK!<]v8O8O#ruby/io-console-0.4.6/io/console.sonuȯPK!<]АА%ruby/json-2.1.0/json/ext/generator.sonuȯPK!<]5>Jnn"̥ruby/json-2.1.0/json/ext/parser.sonuȯPK!<] PPruby/openssl-2.1.2/openssl.sonuȯPKm]n Cruby/ruby-lsapi-5.5/gem_make.outnu[PKm][1ruby/ruby-lsapi-5.5/mkmf.lognu[PKm]& ruby/ruby-lsapi-5.5/gem.build_completenu[PKm]7?P.P. ruby/ruby-lsapi-5.5/lsapi.sonuȯPKm]ó@@%0 ruby/json-2.3.0/json/ext/generator.sonuȯPKm]`u{@q@q"4 ruby/json-2.3.0/json/ext/parser.sonuȯPKm]}X{HVHV#5 ruby/bigdecimal-2.0.0/bigdecimal.sonuȯPKm]bM   a ruby/ruby-lsapi-5.6/gem_make.outnu[PKm][1 ruby/ruby-lsapi-5.6/mkmf.lognu[PKm]&ј ruby/ruby-lsapi-5.6/gem.build_completenu[PKm]sP.P.' ruby/ruby-lsapi-5.6/lsapi.sonuȯPKm]/ss# ruby/io-console-0.5.6/io/console.sonuȯPKm]Q//&;ruby/openssl-2.1.4/openssl.sonuȯPKm]_HJkruby/psych-3.1.0/psych.sonuȯPKҖ]#ruby/debug-1.6.3/gem.build_completenu[PKҖ]cr_PH@H@Oruby/debug-1.6.3/debug/debug.sonuȯPKҖ]!0ruby/rbs-2.7.0/gem.build_completenu[PKҖ]uPP71ruby/rbs-2.7.0/rbs_extension.sonuȯPKҖ]\0p0p$ruby/io-console-0.5.11/io/console.sonuȯPKҖ])Zhruby/io-console-0.5.11/gem.build_completenu[PKҖ]#hruby/psych-4.0.4/gem.build_completenu[PKҖ]Wiruby/psych-4.0.4/psych.sonuȯPKҖ](ruby/bigdecimal-3.1.1/gem.build_completenu[PKҖ]9@@#Oruby/bigdecimal-3.1.1/bigdecimal.sonuȯPKҖ]"ruby/json-2.6.1/gem.build_completenu[PKҖ]6%4ruby/json-2.6.1/json/ext/generator.sonuȯPKҖ]<~~"3ruby/json-2.6.1/json/ext/parser.sonuȯPK ]zyB%specifications/ruby-lsapi-5.5.gemspecnu[PK ]ׂii$specifications/openssl-2.1.4.gemspecnu[PK ]26>)Nspecifications/power_assert-1.1.7.gemspecnu[PK ]lй%specifications/ruby-lsapi-5.6.gemspecnu[PK ]&߻ "specifications/psych-3.1.0.gemspecnu[PK ]Ք!specifications/json-2.3.0.gemspecnu[PK ]ş߽#specifications/rdoc-6.2.1.1.gemspecnu[PK ]K'))%specifications/bundler-2.2.24.gemspecnu[PK ]rii#specifications/xmlrpc-0.3.0.gemspecnu[PK ]]!'#specifications/io-console-0.5.6.gemspecnu[PK ]WB&'specifications/test-unit-3.3.4.gemspecnu[PK ]v-#/specifications/rackup-2.1.0.gemspecnu[PK ]a'87specifications/net-telnet-0.2.0.gemspecnu[PK ]]K+=specifications/default/matrix-0.2.0.gemspecnu[PK ]Rn n (ABspecifications/default/rss-0.2.8.gemspecnu[PK ]ʂ?ii-Lspecifications/default/stringio-0.1.0.gemspecnu[PK ]e..,Pspecifications/default/strscan-1.0.3.gemspecnu[PK ]7}-WVspecifications/default/observer-0.1.0.gemspecnu[PK ]+|00+uZspecifications/default/ipaddr-1.2.2.gemspecnu[PK ]&kff*`specifications/default/open3-0.1.0.gemspecnu[PK ]'ei*cspecifications/default/fcntl-1.0.0.gemspecnu[PK ]N;oo+ispecifications/default/logger-1.4.2.gemspecnu[PK ] /+ypspecifications/default/pstore-0.1.0.gemspecnu[PK ]8o-atspecifications/default/net-smtp-0.1.0.gemspecnu[PK ]z..1oxspecifications/default/readline-ext-0.1.0.gemspecnu[PK ]i>*~specifications/default/cgi-0.1.0.2.gemspecnu[PK ]D ,uspecifications/default/webrick-1.6.1.gemspecnu[PK ]KE9 9 ,specifications/default/rexml-3.2.3.1.gemspecnu[PK ]0yy/Dspecifications/default/getoptlong-0.1.0.gemspecnu[PK ]2,specifications/default/ostruct-0.2.0.gemspecnu[PK ]V)specifications/default/zlib-1.1.0.gemspecnu[PK ]vTH,specifications/default/mutex_m-0.1.0.gemspecnu[PK ].iAzz)=specifications/default/date-3.0.3.gemspecnu[PK ],5{{+specifications/default/reline-0.1.5.gemspecnu[PK ]@F1specifications/default/did_you_mean-1.4.0.gemspecnu[PK ]9b_+specifications/default/fiddle-1.0.0.gemspecnu[PK ]N+specifications/default/uri-0.10.0.2.gemspecnu[PK ]C-specifications/default/delegate-0.1.0.gemspecnu[PK ]nSS0specifications/default/forwardable-1.3.1.gemspecnu[PK ])pspecifications/default/yaml-0.1.0.gemspecnu[PK ]^\^^)vspecifications/default/gdbm-2.1.0.gemspecnu[PK ]xx,-specifications/default/net-pop-0.1.0.gemspecnu[PK ]~V6*specifications/default/prime-0.1.1.gemspecnu[PK ]+Q.specifications/default/singleton-0.1.0.gemspecnu[PK ]'1O;.specifications/default/fileutils-1.4.1.gemspecnu[PK ] -specifications/default/readline-0.0.2.gemspecnu[PK ]E(9specifications/default/etc-1.1.0.gemspecnu[PK ]N(specifications/default/csv-3.1.2.gemspecnu[PK ]V.specifications/default/benchmark-0.1.0.gemspecnu[PK ]+specifications/default/tracer-0.1.0.gemspecnu[PK ]248 8 *F specifications/default/racc-1.4.16.gemspecnu[PK ]R  (specifications/default/dbm-1.1.0.gemspecnu[PK ]Y(();specifications/default/sdbm-1.0.0.gemspecnu[PK ]~,!specifications/default/timeout-0.1.0.gemspecnu[PK ]43g:\\"%specifications/rake-13.0.1.gemspecnu[PK ]lzz!z-specifications/rack-3.0.8.gemspecnu[PK ] 'E6specifications/bigdecimal-2.0.0.gemspecnu[PK ] څ&=specifications/minitest-5.13.0.gemspecnu[PK ]`C# sPspecifications/irb-1.2.6.gemspecnu[PK ]=w_Zgems/irb-1.2.6/exe/irbnuȯPK ]SkkW[gems/irb-1.2.6/lib/irb.rbnu[PK ])C=C=!sgems/irb-1.2.6/lib/irb/context.rbnu[PK ]*\gems/irb-1.2.6/lib/irb/help.rbnu[PK ],9Yk"gems/irb-1.2.6/lib/irb/lc/error.rbnu[PK ]\`90jgems/irb-1.2.6/lib/irb/lc/ja/encoding_aliases.rbnu[PK ].%gems/irb-1.2.6/lib/irb/lc/ja/error.rbnu[PK ]Ȇ@Dj j )gems/irb-1.2.6/lib/irb/lc/ja/help-messagenu[PK ]o]&!gems/irb-1.2.6/lib/irb/lc/help-messagenu[PK ]ᣟ##&)gems/irb-1.2.6/lib/irb/input-method.rbnu[PK ]C5vl$Mgems/irb-1.2.6/lib/irb/ext/tracer.rbnu[PK ]yr| | $"Vgems/irb-1.2.6/lib/irb/ext/loader.rbnu[PK ]](  'bgems/irb-1.2.6/lib/irb/ext/change-ws.rbnu[PK ] *Rggems/irb-1.2.6/lib/irb/ext/save-history.rbnu[PK ]uI':ugems/irb-1.2.6/lib/irb/ext/multi-irb.rbnu[PK ]N9(Ngems/irb-1.2.6/lib/irb/ext/use-loader.rbnu[PK ]fcI(igems/irb-1.2.6/lib/irb/ext/workspaces.rbnu[PK ]ɼ%gems/irb-1.2.6/lib/irb/ext/history.rbnu[PK ]:?cBcB"gems/irb-1.2.6/lib/irb/ruby-lex.rbnu[PK ]wpgems/irb-1.2.6/lib/irb/color.rbnu[PK ]yk/AA gems/irb-1.2.6/lib/irb/locale.rbnu[PK ]pp$E"gems/irb-1.2.6/lib/irb/easter-egg.rbnu[PK ]fɁc"c" 1gems/irb-1.2.6/lib/irb/init.rbnu[PK ]I I #Sgems/irb-1.2.6/lib/irb/ruby_logo.aanu[PK ]O"V]gems/irb-1.2.6/lib/irb/cmd/help.rbnu[PK ]#o"-agems/irb-1.2.6/lib/irb/cmd/load.rbnu[PK ]Q~~"Mfgems/irb-1.2.6/lib/irb/cmd/fork.rbnu[PK ]j$"igems/irb-1.2.6/lib/irb/cmd/chws.rbnu[PK ])ڏ!!!kgems/irb-1.2.6/lib/irb/cmd/nop.rbnu[PK ]z$mgems/irb-1.2.6/lib/irb/cmd/pushws.rbnu[PK ]I]]$pgems/irb-1.2.6/lib/irb/cmd/subirb.rbnu[PK ]{A5//"sgems/irb-1.2.6/lib/irb/cmd/info.rbnu[PK ]t]vgems/irb-1.2.6/lib/irb/xmp.rbnu[PK ]c&Ćgems/irb-1.2.6/lib/irb/src_encoding.rbnu[PK ]h((!gems/irb-1.2.6/lib/irb/version.rbnu[PK ]Ɨ]%%$&gems/irb-1.2.6/lib/irb/completion.rbnu[PK ]DKC#Sgems/irb-1.2.6/lib/irb/workspace.rbnu[PK ]ǀgems/irb-1.2.6/lib/irb/frame.rbnu[PK ]&/(((gems/irb-1.2.6/lib/irb/extend-command.rbnu[PK ] ['gems/irb-1.2.6/lib/irb/ws-for-case-2.rbnu[PK ] V2 'gems/irb-1.2.6/lib/irb/output-method.rbnu[PK ]q#gems/irb-1.2.6/lib/irb/inspector.rbnu[PK ][$gems/irb-1.2.6/lib/irb/magic-file.rbnu[PK ]cp."gems/irb-1.2.6/lib/irb/notifier.rbnu[PK ]D\\# 2gems/bundler-2.2.24/libexec/bundlernuȯPK ]ʏM"2gems/bundler-2.2.24/libexec/bundlenuȯPK ]^ ^^"7gems/bundler-2.2.24/lib/bundler.rbnu[PK ]tJT T )gems/bundler-2.2.24/lib/bundler/source.rbnu[PK ]${9gems/bundler-2.2.24/lib/bundler/endpoint_specification.rbnu[PK ]١"2)2)*gems/bundler-2.2.24/lib/bundler/runtime.rbnu[PK ]P54gems/bundler-2.2.24/lib/bundler/lazy_specification.rbnu[PK ]eo}O}O&gems/bundler-2.2.24/lib/bundler/dsl.rbnu[PK ]eAss-= gems/bundler-2.2.24/lib/bundler/capistrano.rbnu[PK ]V1A gems/bundler-2.2.24/lib/bundler/match_platform.rbnu[PK ] .XX-D gems/bundler-2.2.24/lib/bundler/definition.rbnu[PK ]W|%i gems/bundler-2.2.24/lib/bundler/ui.rbnu[PK ]HT9 gems/bundler-2.2.24/lib/bundler/rubygems_gem_installer.rbnu[PK ]_l__2 gems/bundler-2.2.24/lib/bundler/vendored_tmpdir.rbnu[PK ]65k gems/bundler-2.2.24/lib/bundler/lockfile_generator.rbnu[PK ]xsn}*}*) gems/bundler-2.2.24/lib/bundler/plugin.rbnu[PK ]h&(7_!gems/bundler-2.2.24/lib/bundler/remote_specification.rbnu[PK ] F2Y!gems/bundler-2.2.24/lib/bundler/lockfile_parser.rbnu[PK ]x9:!gems/bundler-2.2.24/lib/bundler/uri_credentials_filter.rbnu[PK ]--1@!gems/bundler-2.2.24/lib/bundler/shared_helpers.rbnu[PK ]-)+m!gems/bundler-2.2.24/lib/bundler/ruby_dsl.rbnu[PK ]zrr&p!gems/bundler-2.2.24/lib/bundler/cli.rbnu[PK ]!6n n 2 "gems/bundler-2.2.24/lib/bundler/yaml_serializer.rbnu[PK ]X33+~"gems/bundler-2.2.24/lib/bundler/settings.rbnu[PK ](|{ { 5G"gems/bundler-2.2.24/lib/bundler/stub_specification.rbnu[PK ]e MgS"gems/bundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool.rbnu[PK ]\?66Ua"gems/bundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rbnu[PK ]q.YY\b"gems/bundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rbnu[PK ]y<22Yzi"gems/bundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rbnu[PK ]홇C5{"gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor.rbnu[PK ]>/}"gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser.rbnu[PK ]LuvvC'~"gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/rake_compat.rbnu[PK ]ɗc ="gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/error.rbnu[PK ]#I`i#i#=b"gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/group.rbnu[PK ]1UyXXC8"gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/color.rbnu[PK ].B"gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/html.rbnu[PK ]699C "gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/basic.rbnu[PK ];?<#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/command.rbnu[PK ]ᡇ++F/+#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/nested_context.rbnu[PK ]_-[IIB,#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/invocation.rbnu[PK ]5,,?E#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/version.rbnu[PK ]8]&F#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rbnu[PK ]dq=77L2O#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rbnu[PK ]Yt}}IV#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rbnu[PK ]))?Y#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions.rbnu[PK ]``<#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/base.rbnu[PK ]P?% % =&#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell.rbnu[PK ](_b'b'>#gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/runner.rbnu[PK ]aqE$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/option.rbnu[PK ]llH($gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/arguments.rbnu[PK ]i G|;$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/argument.rbnu[PK ]$IJ;;FB$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/options.rbnu[PK ]V]P]$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rbnu[PK ]s mmK)l$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/create_link.rbnu[PK ],;  It$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/directory.rbnu[PK ]te) ) K$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/create_file.rbnu[PK ]Iq3q3Q7$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rbnu[PK ]O&O)$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rbnu[PK ]jU#U#<$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/util.rbnu[PK ]q@q@7e$gems/bundler-2.2.24/lib/bundler/vendor/thor/lib/thor.rbnu[PK ]C}mmU=:%gems/bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rbnu[PK ]6lffg%gems/bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rbnu[PK ]hO8Z%gems/bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rbnu[PK ](ц`%gems/bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rbnu[PK ]t//A%gems/bundler-2.2.24/lib/bundler/vendor/fileutils/lib/fileutils.rbnu[PK ]OU0 5}&gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri.rbnu[PK ]M0 0 <&gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/mailto.rbnu[PK ]M}:&gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/file.rbnu[PK ]]F֖֖=.&gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/generic.rbnu[PK ]wL{{:qL'gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ldap.rbnu[PK ]I;Vd'gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ldaps.rbnu[PK ] %%9f'gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ftp.rbnu[PK ]3=m'gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/version.rbnu[PK ]*@QQ<y'gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/common.rbnu[PK ] :'gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/http.rbnu[PK ]="__;'gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/https.rbnu[PK ]#TΉQQD'gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rbnu[PK ]ٍ2G2GDi'gems/bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rbnu[PK ] II;F(gems/bundler-2.2.24/lib/bundler/vendor/tmpdir/lib/tmpdir.rbnu[PK ]lHYYAX(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo.rbnu[PK ]ԻHHYZ(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rbnu[PK ]:ʘ!f^o(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rbnu[PK ]XAcc]u(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rbnu[PK ].mVV|(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rbnu[PK ]@G{Y (gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rbnu[PK ]5 V0(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rbnu[PK ]D""^Ւ(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rbnu[PK ] ?=WW^(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rbnu[PK ]DNjoogj(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rbnu[PK ]cOu((Gp(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/state.rbnu[PK ]U#||H(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/errors.rbnu[PK ]~J(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rbnu[PK ] R(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rbnu[PK ]ۦ b(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rbnu[PK ]9DD??\(gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rbnu[PK ]+4L)gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rbnu[PK ]!gpt[[` )gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rbnu[PK ]=L)gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rbnu[PK ]."N͢)gems/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rbnu[PK ]}X,ʣ)gems/bundler-2.2.24/lib/bundler/gem_tasks.rbnu[PK ] D##.)gems/bundler-2.2.24/lib/bundler/source/path.rbnu[PK ]uR!xx81)gems/bundler-2.2.24/lib/bundler/source/path/installer.rbnu[PK ].۬2)gems/bundler-2.2.24/lib/bundler/source/metadata.rbnu[PK ]gYGG2)gems/bundler-2.2.24/lib/bundler/source/rubygems.rbnu[PK ]:U''9 *gems/bundler-2.2.24/lib/bundler/source/rubygems/remote.rbnu[PK ]ƨ'1#*gems/bundler-2.2.24/lib/bundler/source/gemspec.rbnu[PK ] E//<%*gems/bundler-2.2.24/lib/bundler/source/rubygems_aggregate.rbnu[PK ]Ƌ}(}(--*gems/bundler-2.2.24/lib/bundler/source/git.rbnu[PK ])g@##7V*gems/bundler-2.2.24/lib/bundler/source/git/git_proxy.rbnu[PK ]ƣZ+z*gems/bundler-2.2.24/lib/bundler/spec_set.rbnu[PK ]4f++7*gems/bundler-2.2.24/lib/bundler/gem_version_promoter.rbnu[PK ]Tee5*gems/bundler-2.2.24/lib/bundler/vendored_molinillo.rbnu[PK ]z]EE7t*gems/bundler-2.2.24/lib/bundler/rubygems_integration.rbnu[PK ] X6**gems/bundler-2.2.24/lib/bundler/version.rbnu[PK ]#/*gems/bundler-2.2.24/lib/bundler/current_ruby.rbnu[PK ])PY\\6*gems/bundler-2.2.24/lib/bundler/similarity_detector.rbnu[PK ]6e$ll,+gems/bundler-2.2.24/lib/bundler/deprecate.rbnu[PK ]|YY/z+gems/bundler-2.2.24/lib/bundler/vendored_uri.rbnu[PK ]یYY72+gems/bundler-2.2.24/lib/bundler/compact_index_client.rbnu[PK ]j[] ] )+gems/bundler-2.2.24/lib/bundler/worker.rbnu[PK ]<, , 5!+gems/bundler-2.2.24/lib/bundler/settings/validator.rbnu[PK ]h =9.+gems/bundler-2.2.24/lib/bundler/compact_index_client/cache.rbnu[PK ]CXjBv9+gems/bundler-2.2.24/lib/bundler/compact_index_client/gem_parser.rbnu[PK ]q cc?=+gems/bundler-2.2.24/lib/bundler/compact_index_client/updater.rbnu[PK ]Hu""(UL+gems/bundler-2.2.24/lib/bundler/setup.rbnu[PK ]hFF/O+gems/bundler-2.2.24/lib/bundler/psyched_yaml.rbnu[PK ]hc8tR+gems/bundler-2.2.24/lib/bundler/environment_preserver.rbnu[PK ]I~] <zZ+gems/bundler-2.2.24/lib/bundler/templates/Executable.bundlernu[PK ]MGf+gems/bundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/newgem.c.ttnu[PK ]?GNh+gems/bundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/newgem.h.ttnu[PK ]95ffIvi+gems/bundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/extconf.rb.ttnu[PK ]7##BUj+gems/bundler-2.2.24/lib/bundler/templates/newgem/newgem.gemspec.ttnu[PK ]!5c| | =q+gems/bundler-2.2.24/lib/bundler/templates/newgem/README.md.ttnu[PK ]+<{+gems/bundler-2.2.24/lib/bundler/templates/newgem/Rakefile.ttnu[PK ]~~>+gems/bundler-2.2.24/lib/bundler/templates/newgem/travis.yml.ttnu[PK ]Ҧ+G+gems/bundler-2.2.24/lib/bundler/templates/newgem/spec/spec_helper.rb.ttnu[PK ]32 G+gems/bundler-2.2.24/lib/bundler/templates/newgem/spec/newgem_spec.rb.ttnu[PK ]rə;}+gems/bundler-2.2.24/lib/bundler/templates/newgem/Gemfile.ttnu[PK ]z??>+gems/bundler-2.2.24/lib/bundler/templates/newgem/exe/newgem.ttnu[PK ]lq5598+gems/bundler-2.2.24/lib/bundler/templates/newgem/rspec.ttnu[PK ]G>JQև+gems/bundler-2.2.24/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.ttnu[PK ]q{33Q+gems/bundler-2.2.24/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.ttnu[PK ]M-nP+gems/bundler-2.2.24/lib/bundler/templates/newgem/test/minitest/test_helper.rb.ttnu[PK ]-P+gems/bundler-2.2.24/lib/bundler/templates/newgem/test/minitest/newgem_test.rb.ttnu[PK ]/++?Q+gems/bundler-2.2.24/lib/bundler/templates/newgem/rubocop.yml.ttnu[PK ]v@@M+gems/bundler-2.2.24/lib/bundler/templates/newgem/github/workflows/main.yml.ttnu[PK ]g2=+gems/bundler-2.2.24/lib/bundler/templates/newgem/gitignore.ttnu[PK ]44.A+gems/bundler-2.2.24/lib/bundler/templates/newgem/gitlab-ci.yml.ttnu[PK ]!5PP@+gems/bundler-2.2.24/lib/bundler/templates/newgem/CHANGELOG.md.ttnu[PK ]QQ?ϓ+gems/bundler-2.2.24/lib/bundler/templates/newgem/LICENSE.txt.ttnu[PK ]_ccF+gems/bundler-2.2.24/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.ttnu[PK ]eە?h+gems/bundler-2.2.24/lib/bundler/templates/newgem/bin/console.ttnu[PK ]=c+gems/bundler-2.2.24/lib/bundler/templates/newgem/bin/setup.ttnu[PK ]^6)g&&GS+gems/bundler-2.2.24/lib/bundler/templates/newgem/circleci/config.yml.ttnu[PK ]I+gems/bundler-2.2.24/lib/bundler/templates/newgem/lib/newgem/version.rb.ttnu[PK ]Br==A+gems/bundler-2.2.24/lib/bundler/templates/newgem/lib/newgem.rb.ttnu[PK ]”}Ñ40+gems/bundler-2.2.24/lib/bundler/templates/Executablenu[PK ]t1%+gems/bundler-2.2.24/lib/bundler/templates/Gemfilenu[PK ]{?+gems/bundler-2.2.24/lib/bundler/templates/Executable.standalonenu[PK ]Ba71X+gems/bundler-2.2.24/lib/bundler/templates/gems.rbnu[PK ]9rQ' ' )_+gems/bundler-2.2.24/lib/bundler/inline.rbnu[PK ]4%%++gems/bundler-2.2.24/lib/bundler/injector.rbnu[PK ] G,+gems/bundler-2.2.24/lib/bundler/dep_proxy.rbnu[PK ]\'++gems/bundler-2.2.24/lib/bundler/vlad.rbnu[PK ]oJ)V+gems/bundler-2.2.24/lib/bundler/errors.rbnu[PK ]Ǵ0\ ,gems/bundler-2.2.24/lib/bundler/vendored_thor.rbnu[PK ]p2Ǥ,p ,gems/bundler-2.2.24/lib/bundler/constants.rbnu[PK ]88. ,gems/bundler-2.2.24/lib/bundler/cli/console.rbnu[PK ],6,gems/bundler-2.2.24/lib/bundler/cli/check.rbnu[PK ]j+,gems/bundler-2.2.24/lib/bundler/cli/show.rbnu[PK ]`K+,gems/bundler-2.2.24/lib/bundler/cli/lock.rbnu[PK ])``,&,gems/bundler-2.2.24/lib/bundler/cli/clean.rbnu[PK ]m/Ċ+),gems/bundler-2.2.24/lib/bundler/cli/init.rbnu[PK ]Ak-m.,gems/bundler-2.2.24/lib/bundler/cli/plugin.rbnu[PK ]N  +5,gems/bundler-2.2.24/lib/bundler/cli/exec.rbnu[PK ]|jj,@,gems/bundler-2.2.24/lib/bundler/cli/cache.rbnu[PK ]%4/D,gems/bundler-2.2.24/lib/bundler/cli/platform.rbnu[PK ]22*J,gems/bundler-2.2.24/lib/bundler/cli/gem.rbnu[PK ]lqOww-},gems/bundler-2.2.24/lib/bundler/cli/inject.rbnu[PK ];.>>*,gems/bundler-2.2.24/lib/bundler/cli/viz.rbnu[PK ]V9+),gems/bundler-2.2.24/lib/bundler/cli/fund.rbnu[PK ]-,gems/bundler-2.2.24/lib/bundler/cli/common.rbnu[PK ]RR+{,gems/bundler-2.2.24/lib/bundler/cli/list.rbnu[PK ]+(,gems/bundler-2.2.24/lib/bundler/cli/open.rbnu[PK ]lww-T,gems/bundler-2.2.24/lib/bundler/cli/remove.rbnu[PK ] -(,gems/bundler-2.2.24/lib/bundler/cli/doctor.rbnu[PK ],-Q,gems/bundler-2.2.24/lib/bundler/cli/update.rbnu[PK ]="$"$/,gems/bundler-2.2.24/lib/bundler/cli/outdated.rbnu[PK ]w#w#.,gems/bundler-2.2.24/lib/bundler/cli/install.rbnu[PK ]3LT/-gems/bundler-2.2.24/lib/bundler/cli/pristine.rbnu[PK ]Ʊe}}--gems/bundler-2.2.24/lib/bundler/cli/config.rbnu[PK ]RL*7-gems/bundler-2.2.24/lib/bundler/cli/add.rbnu[PK ]u),=-gems/bundler-2.2.24/lib/bundler/cli/issue.rbnu[PK ]"G/LC-gems/bundler-2.2.24/lib/bundler/cli/binstubs.rbnu[PK ]W{ { +J-gems/bundler-2.2.24/lib/bundler/cli/info.rbnu[PK ]?z-uU-gems/bundler-2.2.24/lib/bundler/gem_helper.rbnu[PK ]`f<<+\s-gems/bundler-2.2.24/lib/bundler/resolver.rbnu[PK ]ω~%%-M-gems/bundler-2.2.24/lib/bundler/dependency.rbnu[PK ]N˾/-gems/bundler-2.2.24/lib/bundler/process_lock.rbnu[PK ]h --gems/bundler-2.2.24/lib/bundler/deployment.rbnu[PK ]aXeXX2-gems/bundler-2.2.24/lib/bundler/friendly_errors.rbnu[PK ]^cc.-gems/bundler-2.2.24/lib/bundler/gem_helpers.rbnu[PK ]a! :-gems/bundler-2.2.24/lib/bundler/installer/gem_installer.rbnu[PK ]y?.gems/bundler-2.2.24/lib/bundler/installer/parallel_installer.rbnu[PK ]{sEjj7=.gems/bundler-2.2.24/lib/bundler/installer/standalone.rbnu[PK ]3dMM3(.gems/bundler-2.2.24/lib/bundler/man/bundle-remove.1nu[PK ])&LYY7+.gems/bundler-2.2.24/lib/bundler/man/bundle-check.1.ronnnu[PK ](V5~/.gems/bundler-2.2.24/lib/bundler/man/bundle-viz.1.ronnnu[PK ];767633.gems/bundler-2.2.24/lib/bundler/man/bundle-update.1nu[PK ]MM0;j.gems/bundler-2.2.24/lib/bundler/man/bundle-viz.1nu[PK ]l47n.gems/bundler-2.2.24/lib/bundler/man/bundle-clean.1.ronnnu[PK ]k  73q.gems/bundler-2.2.24/lib/bundler/man/bundle-cache.1.ronnnu[PK ]&0}.gems/bundler-2.2.24/lib/bundler/man/bundle-add.1nu[PK ]H1G.gems/bundler-2.2.24/lib/bundler/man/bundle-show.1nu[PK ]B5UU8V.gems/bundler-2.2.24/lib/bundler/man/bundle-inject.1.ronnnu[PK ]$3.gems/bundler-2.2.24/lib/bundler/man/bundle-doctor.1nu[PK ]9IG 6.gems/bundler-2.2.24/lib/bundler/man/bundle-lock.1.ronnnu[PK ]Iߚ :B.gems/bundler-2.2.24/lib/bundler/man/bundle-outdated.1.ronnnu[PK ]1~:.gems/bundler-2.2.24/lib/bundler/man/bundle-binstubs.1.ronnnu[PK ]UM 2w.gems/bundler-2.2.24/lib/bundler/man/bundle-cache.1nu[PK ]5.gems/bundler-2.2.24/lib/bundler/man/bundle-outdated.1nu[PK ]N-,.gems/bundler-2.2.24/lib/bundler/man/bundle.1nu[PK ]|)$J$J8C.gems/bundler-2.2.24/lib/bundler/man/bundle-config.1.ronnnu[PK ]ms s 1#/gems/bundler-2.2.24/lib/bundler/man/bundle-lock.1nu[PK ]m20/gems/bundler-2.2.24/lib/bundler/man/bundle-check.1nu[PK ]\'iTT64/gems/bundler-2.2.24/lib/bundler/man/bundle-show.1.ronnnu[PK ]˱[y87/gems/bundler-2.2.24/lib/bundler/man/bundle-remove.1.ronnnu[PK ]h6:/gems/bundler-2.2.24/lib/bundler/man/bundle-init.1.ronnnu[PK ]+B+B9>/gems/bundler-2.2.24/lib/bundler/man/bundle-install.1.ronnnu[PK ]^ ;ff1h/gems/bundler-2.2.24/lib/bundler/man/bundle-exec.1nu[PK ]qq6//gems/bundler-2.2.24/lib/bundler/man/bundle-info.1.ronnnu[PK ]Ag885/gems/bundler-2.2.24/lib/bundler/man/bundle-platform.1nu[PK ]QdUU-/gems/bundler-2.2.24/lib/bundler/man/gemfile.5nu[PK ]n½1/gems/bundler-2.2.24/lib/bundler/man/bundle-info.1nu[PK ]6H8/gems/bundler-2.2.24/lib/bundler/man/bundle-doctor.1.ronnnu[PK ]8XX2/gems/bundler-2.2.24/lib/bundler/man/bundle-clean.1nu[PK ]Y|LL50gems/bundler-2.2.24/lib/bundler/man/bundle-binstubs.1nu[PK ]V#6Z 0gems/bundler-2.2.24/lib/bundler/man/bundle-list.1.ronnnu[PK ]#s: 0gems/bundler-2.2.24/lib/bundler/man/bundle-pristine.1.ronnnu[PK ]C..50gems/bundler-2.2.24/lib/bundler/man/bundle-gem.1.ronnnu[PK ]^-0"0gems/bundler-2.2.24/lib/bundler/man/bundle-gem.1nu[PK ]56 40gems/bundler-2.2.24/lib/bundler/man/bundle-open.1.ronnnu[PK ]P~||6)60gems/bundler-2.2.24/lib/bundler/man/bundle-exec.1.ronnnu[PK ]w,w118 N0gems/bundler-2.2.24/lib/bundler/man/bundle-update.1.ronnnu[PK ]|=3T0gems/bundler-2.2.24/lib/bundler/man/bundle-inject.1nu[PK ],10gems/bundler-2.2.24/lib/bundler/man/bundle-list.1nu[PK ]8EDFDF40gems/bundler-2.2.24/lib/bundler/man/bundle-install.1nu[PK ]-N-N2_0gems/bundler-2.2.24/lib/bundler/man/gemfile.5.ronnnu[PK ]>^gH H 11gems/bundler-2.2.24/lib/bundler/man/bundle.1.ronnnu[PK ]2P331)1gems/bundler-2.2.24/lib/bundler/man/bundle-init.1nu[PK ]ߕ}}:+.1gems/bundler-2.2.24/lib/bundler/man/bundle-platform.1.ronnnu[PK ]j531gems/bundler-2.2.24/lib/bundler/man/bundle-pristine.1nu[PK ]'uw^5:1gems/bundler-2.2.24/lib/bundler/man/bundle-add.1.ronnnu[PK ]?OAA1C?1gems/bundler-2.2.24/lib/bundler/man/bundle-open.1nu[PK ]"&YxSS3A1gems/bundler-2.2.24/lib/bundler/man/bundle-config.1nu[PK ]uw-w-,1gems/bundler-2.2.24/lib/bundler/installer.rbnu[PK ]Vw81gems/bundler-2.2.24/lib/bundler/fetcher/compact_index.rbnu[PK ]L;8 51gems/bundler-2.2.24/lib/bundler/fetcher/dependency.rbnu[PK ]/1gems/bundler-2.2.24/lib/bundler/fetcher/base.rbnu[PK ],dd091gems/bundler-2.2.24/lib/bundler/fetcher/index.rbnu[PK ]]Y Y 51gems/bundler-2.2.24/lib/bundler/fetcher/downloader.rbnu[PK ]+(1gems/bundler-2.2.24/lib/bundler/index.rbnu[PK ]PCm/2gems/bundler-2.2.24/lib/bundler/ruby_version.rbnu[PK ]ؤ-""-!2gems/bundler-2.2.24/lib/bundler/source_map.rbnu[PK ]0/(2gems/bundler-2.2.24/lib/bundler/rubygems_ext.rbnu[PK ]i *  &B2gems/bundler-2.2.24/lib/bundler/env.rbnu[PK ]Piy@ @ 6V2gems/bundler-2.2.24/lib/bundler/resolver/spec_group.rbnu[PK ]B$hHH)d2gems/bundler-2.2.24/lib/bundler/mirror.rbnu[PK ]"x-+|2gems/bundler-2.2.24/lib/bundler/plugin/dsl.rbnu[PK ]ӃnDD0Q2gems/bundler-2.2.24/lib/bundler/plugin/events.rbnu[PK ]6P P -2gems/bundler-2.2.24/lib/bundler/plugin/api.rbnu[PK ] g..42gems/bundler-2.2.24/lib/bundler/plugin/api/source.rbnu[PK ]A<2gems/bundler-2.2.24/lib/bundler/plugin/installer/rubygems.rbnu[PK ]ߛ"Maa7X2gems/bundler-2.2.24/lib/bundler/plugin/installer/git.rbnu[PK ]{׳ 3 2gems/bundler-2.2.24/lib/bundler/plugin/installer.rbnu[PK ]./2gems/bundler-2.2.24/lib/bundler/plugin/index.rbnu[PK ]ΦAA52gems/bundler-2.2.24/lib/bundler/plugin/source_list.rbnu[PK ]wz,,*2gems/bundler-2.2.24/lib/bundler/fetcher.rbnu[PK ]•n.!3gems/bundler-2.2.24/lib/bundler/source_list.rbnu[PK ]wj51<3gems/bundler-2.2.24/lib/bundler/build_metadata.rbnu[PK ][567B3gems/bundler-2.2.24/lib/bundler/vendored_persistent.rbnu[PK ][  ,_H3gems/bundler-2.2.24/lib/bundler/ui/silent.rbnu[PK ]K66.L3gems/bundler-2.2.24/lib/bundler/ui/rg_proxy.rbnu[PK ]Xȷr r +\N3gems/bundler-2.2.24/lib/bundler/ui/shell.rbnu[PK ]unuu()\3gems/bundler-2.2.24/lib/bundler/retry.rbnu[PK ]0ee5b3gems/bundler-2.2.24/lib/bundler/vendored_fileutils.rbnu[PK ]'/c3gems/bundler-2.2.24/lib/bundler/feature_flag.rbnu[PK ]O ɧ*k3gems/bundler-2.2.24/lib/bundler/gemdeps.rbnu[PK ]-L001m3gems/bundler-2.2.24/lib/bundler/version_ranges.rbnu[PK ]3,(w}3gems/bundler-2.2.24/lib/bundler/graph.rbnu[PK ]YE[hɑ3gems/rdoc-6.2.1.1/exe/rdocnuȯPK ]ֳs3gems/rdoc-6.2.1.1/exe/rinuȯPK ]u`x`x%3gems/rdoc-6.2.1.1/lib/rdoc/context.rbnu[PK ]FvEE n4gems/rdoc-6.2.1.1/lib/rdoc/rd.rbnu[PK ]533$4gems/rdoc-6.2.1.1/lib/rdoc/parser.rbnu[PK ]m|`":4gems/rdoc-6.2.1.1/lib/rdoc/i18n.rbnu[PK ]H"--';4gems/rdoc-6.2.1.1/lib/rdoc/top_level.rbnu[PK ]󈗢+ R4gems/rdoc-6.2.1.1/lib/rdoc/normal_module.rbnu[PK ]|y* X4gems/rdoc-6.2.1.1/lib/rdoc/single_class.rbnu[PK ]Ԣ&&(Z4gems/rdoc-6.2.1.1/lib/rdoc/any_method.rbnu[PK ]c7%v4gems/rdoc-6.2.1.1/lib/rdoc/comment.rbnu[PK ]VU} } +׍4gems/rdoc-6.2.1.1/lib/rdoc/known_classes.rbnu[PK ]HLf*q0q0%4gems/rdoc-6.2.1.1/lib/rdoc/servlet.rbnu[PK ]58)u4gems/rdoc-6.2.1.1/lib/rdoc/erb_partial.rbnu[PK ]p-}}#^4gems/rdoc-6.2.1.1/lib/rdoc/alias.rbnu[PK ]epC0).4gems/rdoc-6.2.1.1/lib/rdoc/meta_method.rbnu[PK ]/%4gems/rdoc-6.2.1.1/lib/rdoc/include.rbnu[PK ]oc# 4gems/rdoc-6.2.1.1/lib/rdoc/erbio.rbnu[PK ]&“%4gems/rdoc-6.2.1.1/lib/rdoc/require.rbnu[PK ]W,*4gems/rdoc-6.2.1.1/lib/rdoc/normal_class.rbnu[PK ]- % %)4gems/rdoc-6.2.1.1/lib/rdoc/code_object.rbnu[PK ]#SpSp$a 5gems/rdoc-6.2.1.1/lib/rdoc/markup.rbnu[PK ]ʘw  /}5gems/rdoc-6.2.1.1/lib/rdoc/markup/to_tt_only.rbnu[PK ][nA##-5gems/rdoc-6.2.1.1/lib/rdoc/markup/verbatim.rbnu[PK ]eM45gems/rdoc-6.2.1.1/lib/rdoc/markup/to_html_snippet.rbnu[PK ]N_0B5gems/rdoc-6.2.1.1/lib/rdoc/markup/block_quote.rbnu[PK ]tԇ/5gems/rdoc-6.2.1.1/lib/rdoc/markup/blank_line.rbnu[PK ]<88+5gems/rdoc-6.2.1.1/lib/rdoc/markup/parser.rbnu[PK ]V,l5gems/rdoc-6.2.1.1/lib/rdoc/markup/to_test.rbnu[PK ]fQ`66,V5gems/rdoc-6.2.1.1/lib/rdoc/markup/to_ansi.rbnu[PK ]d.5gems/rdoc-6.2.1.1/lib/rdoc/markup/paragraph.rbnu[PK ]$$535gems/rdoc-6.2.1.1/lib/rdoc/markup/to_html_crossref.rbnu[PK ]Q,6gems/rdoc-6.2.1.1/lib/rdoc/markup/to_rdoc.rbnu[PK ]C"==,6gems/rdoc-6.2.1.1/lib/rdoc/markup/include.rbnu[PK ]-Ǘ.46gems/rdoc-6.2.1.1/lib/rdoc/markup/formatter.rbnu[PK ]|4[36gems/rdoc-6.2.1.1/lib/rdoc/markup/regexp_handling.rbnu[PK ]ߦo166gems/rdoc-6.2.1.1/lib/rdoc/markup/attr_changer.rbnu[PK ]|"",86gems/rdoc-6.2.1.1/lib/rdoc/markup/to_html.rbnu[PK ]FVV-[6gems/rdoc-6.2.1.1/lib/rdoc/markup/to_label.rbnu[PK ]<.Fc6gems/rdoc-6.2.1.1/lib/rdoc/markup/attr_span.rbnu[PK ]ua1*e6gems/rdoc-6.2.1.1/lib/rdoc/markup/to_bs.rbnu[PK ]y /l6gems/rdoc-6.2.1.1/lib/rdoc/markup/hard_break.rbnu[PK ] 7>?9n6gems/rdoc-6.2.1.1/lib/rdoc/markup/to_table_of_contents.rbnu[PK ]f !r r 6u6gems/rdoc-6.2.1.1/lib/rdoc/markup/attribute_manager.rbnu[PK ]6WG!G!06gems/rdoc-6.2.1.1/lib/rdoc/markup/pre_process.rbnu[PK ]ھ/A6gems/rdoc-6.2.1.1/lib/rdoc/markup/attributes.rbnu[PK ]6%Vee86gems/rdoc-6.2.1.1/lib/rdoc/markup/to_joined_paragraph.rbnu[PK ]ԄEE)j6gems/rdoc-6.2.1.1/lib/rdoc/markup/list.rbnu[PK ]fcr.6gems/rdoc-6.2.1.1/lib/rdoc/markup/list_item.rbnu[PK ]Т7@6gems/rdoc-6.2.1.1/lib/rdoc/markup/indented_paragraph.rbnu[PK ];;)16gems/rdoc-6.2.1.1/lib/rdoc/markup/rule.rbnu[PK ]M(6gems/rdoc-6.2.1.1/lib/rdoc/markup/raw.rbnu[PK ]p,6gems/rdoc-6.2.1.1/lib/rdoc/markup/heading.rbnu[PK ]WY -Q6gems/rdoc-6.2.1.1/lib/rdoc/markup/document.rbnu[PK ] t{ll0F6gems/rdoc-6.2.1.1/lib/rdoc/markup/to_markdown.rbnu[PK ]Vnrr*6gems/rdoc-6.2.1.1/lib/rdoc/ri/formatter.rbnu[PK ] qh&6gems/rdoc-6.2.1.1/lib/rdoc/ri/paths.rbnu[PK ]tUU&47gems/rdoc-6.2.1.1/lib/rdoc/ri/store.rbnu[PK ]L!66%7gems/rdoc-6.2.1.1/lib/rdoc/ri/task.rbnu[PK ]yy'j7gems/rdoc-6.2.1.1/lib/rdoc/ri/driver.rbnu[PK ]y&:7gems/rdoc-6.2.1.1/lib/rdoc/encoding.rbnu[PK ]$7gems/rdoc-6.2.1.1/lib/rdoc/extend.rbnu[PK ] =MM%7gems/rdoc-6.2.1.1/lib/rdoc/version.rbnu[PK ]g**.7gems/rdoc-6.2.1.1/lib/rdoc/code_objects.rbnu[PK ]bb]]&7gems/rdoc-6.2.1.1/lib/rdoc/constant.rbnu[PK ]I#$#$)7gems/rdoc-6.2.1.1/lib/rdoc/method_attr.rbnu[PK ]OG!!/N7gems/rdoc-6.2.1.1/lib/rdoc/markdown/entities.rbnu[PK ]LRh$h$/8gems/rdoc-6.2.1.1/lib/rdoc/markdown/literals.rbnu[PK ]FMYY#8gems/rdoc-6.2.1.1/lib/rdoc/store.rbnu[PK ]]'F9gems/rdoc-6.2.1.1/lib/rdoc/rd/inline.rbnu[PK ]kXX-L9gems/rdoc-6.2.1.1/lib/rdoc/rd/block_parser.rbnu[PK ]M<}}.9gems/rdoc-6.2.1.1/lib/rdoc/rd/inline_parser.rbnu[PK ]x"#:gems/rdoc-6.2.1.1/lib/rdoc/task.rbnu[PK ]刊--'B:gems/rdoc-6.2.1.1/lib/rdoc/generator.rbnu[PK ]Ȅ(8J:gems/rdoc-6.2.1.1/lib/rdoc/anon_class.rbnu[PK ]  #  ",;gems/rdoc-6.2.1.1/lib/rdoc/attr.rbnu[PK ]KzVf f )<;gems/rdoc-6.2.1.1/lib/rdoc/i18n/locale.rbnu[PK ]S2 'E;gems/rdoc-6.2.1.1/lib/rdoc/i18n/text.rbnu[PK ]>"Q;gems/rdoc-6.2.1.1/lib/rdoc/text.rbnu[PK ]at))#o;gems/rdoc-6.2.1.1/lib/rdoc/stats.rbnu[PK ] )ә;gems/rdoc-6.2.1.1/lib/rdoc/parser/ruby.rbnu[PK ]:ܶ'<gems/rdoc-6.2.1.1/lib/rdoc/parser/rd.rbnu[PK ]Og. <gems/rdoc-6.2.1.1/lib/rdoc/parser/changelog.rbnu[PK ]4QՆ / <gems/rdoc-6.2.1.1/lib/rdoc/parser/ruby_tools.rbnu[PK ]9GG&<gems/rdoc-6.2.1.1/lib/rdoc/parser/c.rbnu[PK ]U+3=gems/rdoc-6.2.1.1/lib/rdoc/parser/simple.rbnu[PK ]733)9=gems/rdoc-6.2.1.1/lib/rdoc/parser/text.rbnu[PK ]_A-4;=gems/rdoc-6.2.1.1/lib/rdoc/parser/markdown.rbnu[PK ] />>5k==gems/rdoc-6.2.1.1/lib/rdoc/parser/ripper_state_lex.rbnu[PK ]mh fEE&|=gems/rdoc-6.2.1.1/lib/rdoc/markdown.rbnu[PK ]WnYY qqK*Jgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttfnu[PK ]NqoLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/table_of_contents.rhtmlnu[PK ]~3FFKuLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtmlnu[PK ]̸QQOwLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtmlnu[PK ]*fLgyLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtmlnu[PK ]-Wt|Lgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtmlnu[PK ]A-N~Lgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtmlnu[PK ]MLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtmlnu[PK ]` eA&Lgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/page.rhtmlnu[PK ])oHHO>Lgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/wrench_orange.pngnu[PK ](VVQLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/page_white_text.pngnu[PK ]R7LܚLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/brick_link.pngnu[PK ]#۸PPFTLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/ruby.pngnu[PK ]=kTLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.pngnu[PK ]QRoLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gifnu[PK ]SELgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/bug.pngnu[PK ]7 FjLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/zoom.pngnu[PK ]CCJUUILgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/package.pngnu[PK ]ErrFbLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/date.pngnu[PK ]"55RJLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/page_white_width.pngnu[PK ]bbHLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/wrench.pngnu[PK ]PHLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/delete.pngnu[PK ]Os~ELgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/add.pngnu[PK ]=VUpLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.pngnu[PK ]AaaMLgems/rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/transparent.pngnu[PK ]== |Pgems/rack-3.0.8/lib/rack/lock.rbnu[PK ]/{{( Pgems/rack-3.0.8/lib/rack/mock_request.rbnu[PK ]gG&ܙPgems/rack-3.0.8/lib/rack/media_type.rbnu[PK ]/˟Pgems/rack-3.0.8/lib/rack/auth/digest/request.rbnu[PK ]+GPgems/rack-3.0.8/lib/rack/auth/digest/md5.rbnu[PK ]-Pgems/rack-3.0.8/lib/rack/auth/digest/nonce.rbnu[PK ].9Pgems/rack-3.0.8/lib/rack/auth/digest/params.rbnu[PK ],UU1Pgems/rack-3.0.8/lib/rack/auth/abstract/request.rbnu[PK ]lGRR1jPgems/rack-3.0.8/lib/rack/auth/abstract/handler.rbnu[PK ]&Pgems/rack-3.0.8/lib/rack/auth/basic.rbnu[PK ]  '$Pgems/rack-3.0.8/lib/rack/auth/digest.rbnu[PK ]>Sf?"?"#Pgems/rack-3.0.8/lib/rack/builder.rbnu[PK ]O~%Pgems/rack-3.0.8/lib/rack/recursive.rbnu[PK ]ӎ cTcT!Pgems/rack-3.0.8/lib/rack/utils.rbnu[PK ]&44,>EQgems/rack-3.0.8/lib/rack/multipart/parser.rbnu[PK ]l /czQgems/rack-3.0.8/lib/rack/multipart/generator.rbnu[PK ]N$$3Qgems/rack-3.0.8/lib/rack/multipart/uploaded_file.rbnu[PK ] Cx x )Qgems/rack-3.0.8/lib/rack/common_logger.rbnu[PK ]YYd  +Qgems/rack-3.0.8/lib/rack/tempfile_reaper.rbnu[PK ]Kbx  $EQgems/rack-3.0.8/lib/rack/reloader.rbnu[PK ]&{!{!(Qgems/rack-3.0.8/lib/rack/query_parser.rbnu[PK ]U``"%Qgems/rack-3.0.8/lib/rack/multipart.rbnu[PK ]|Х!Qgems/rack-3.0.8/lib/rack/files.rbnu[PK ]44"xQgems/rack-3.0.8/lib/rack/events.rbnu[PK ]A%Qgems/rack-3.0.8/lib/rack/directory.rbnu[PK ]iZ&&*kRgems/rack-3.0.8/lib/rack/content_length.rbnu[PK ]ɸHO#Rgems/rack-3.0.8/lib/rack/version.rbnu[PK ]R  )Rgems/rack-3.0.8/lib/rack/mock_response.rbnu[PK ]Y488$p%Rgems/rack-3.0.8/lib/rack/sendfile.rbnu[PK ]dP";Rgems/rack-3.0.8/lib/rack/logger.rbnu[PK ]M}Y?? =Rgems/rack-3.0.8/lib/rack/mock.rbnu[PK ]K?33&{>Rgems/rack-3.0.8/lib/rack/body_proxy.rbnu[PK ]ю "DRgems/rack-3.0.8/lib/rack/static.rbnu[PK ]VMVww U\Rgems/rack-3.0.8/lib/rack/etag.rbnu[PK ];~ ~ ,dRgems/rack-3.0.8/lib/rack/rewindable_input.rbnu[PK ]$**$pRgems/rack-3.0.8/lib/rack/response.rbnu[PK ]3+/Rgems/rack-3.0.8/lib/rack/method_override.rbnu[PK ]@j %RRgems/rack-3.0.8/lib/rack/constants.rbnu[PK ]Oi #Rgems/rack-3.0.8/lib/rack/headers.rbnu[PK ]ѝo   Rgems/rack-3.0.8/lib/rack/head.rbnu[PK ]՝[[ Rgems/rack-3.0.8/lib/rack/lint.rbnuȯPK ]|| +KSgems/rack-3.0.8/lib/rack/conditional_get.rbnu[PK ]N4q( XSgems/rack-3.0.8/lib/rack/content_type.rbnu[PK ]dNN'[Sgems/rack-3.0.8/lib/rack/show_status.rbnu[PK ]?6/ iSgems/rack-3.0.8/lib/rack/mime.rbnu[PK ]i\"Sgems/rack-3.0.8/lib/rack/config.rbnu[PK ]Y  #Sgems/rack-3.0.8/lib/rack/cascade.rbnu[PK ]_l'Sgems/rack-3.0.8/lib/rack/null_logger.rbnu[PK ]/#Sgems/ruby-lsapi-5.5/ext/lsapi/.sitearchdir.timenu[PK ]Y//(Sgems/ruby-lsapi-5.5/ext/lsapi/lsapilib.hnu[PK ]7Zw(-Tgems/ruby-lsapi-5.5/ext/lsapi/extconf.rbnu[PK ].ZZ&+/Tgems/ruby-lsapi-5.5/ext/lsapi/lsruby.cnu[PK ]W q,,(.Tgems/ruby-lsapi-5.5/ext/lsapi/lsapidef.hnu[PK ](((Tgems/ruby-lsapi-5.5/ext/lsapi/lsapilib.onu[PK ]]z.##&Ygems/ruby-lsapi-5.5/ext/lsapi/Makefilenu[PK ] 3O8aa(Ygems/ruby-lsapi-5.5/ext/lsapi/lsapilib.cnu[PK ]Mr33&[gems/ruby-lsapi-5.5/ext/lsapi/lsapi.sonuȯPK ].c|&\gems/ruby-lsapi-5.5/ext/lsapi/lsruby.onu[PK ]lΉ!Q^gems/ruby-lsapi-5.5/lsapi.gemspecnu[PK ]^wͱ+^gems/ruby-lsapi-5.5/READMEnu[PK ]j2(&^gems/ruby-lsapi-5.5/rails/dispatch.lsapinuȯPK ]MM,v^gems/ruby-lsapi-5.5/scripts/lsruby_runner.rbnuȯPK ]##BB^gems/ruby-lsapi-5.5/setup.rbnu[PK ]*  )y_gems/ruby-lsapi-5.5/examples/testlsapi.rbnuȯPK ].{_gems/ruby-lsapi-5.5/examples/lsapi_with_cgi.rbnuȯPK ]!^|_gems/minitest-5.13.0/Manifest.txtnu[PK ]S`D_gems/minitest-5.13.0/Rakefilenu[PK ]9(  =z_gems/minitest-5.13.0/test/minitest/test_minitest_benchmark.rbnu[PK ]+ɃɃ>f_gems/minitest-5.13.0/test/minitest/test_minitest_assertions.rbnu[PK ]`#*ii<`gems/minitest-5.13.0/test/minitest/test_minitest_reporter.rbnu[PK ]m1i\i\8r/`gems/minitest-5.13.0/test/minitest/test_minitest_test.rbnu[PK ]lJlJ8C`gems/minitest-5.13.0/test/minitest/test_minitest_mock.rbnu[PK ]O 2`gems/minitest-5.13.0/test/minitest/metametameta.rbnu[PK ]8*k*k8L`gems/minitest-5.13.0/test/minitest/test_minitest_spec.rbnu[PK ]ފ`o`o Lagems/minitest-5.13.0/README.rdocnu[PK ].`.`$agems/minitest-5.13.0/lib/minitest.rbnu[PK ]lrR^CC*bgems/minitest-5.13.0/lib/minitest/pride.rbnu[PK ]*UU/bgems/minitest-5.13.0/lib/minitest/assertions.rbnu[PK ]+**)sbgems/minitest-5.13.0/lib/minitest/test.rbnu[PK ] 00.bgems/minitest-5.13.0/lib/minitest/benchmark.rbnu[PK ]y)bgems/minitest-5.13.0/lib/minitest/unit.rbnu[PK ]/w[NN)׿bgems/minitest-5.13.0/lib/minitest/mock.rbnu[PK ]_cGG-~bgems/minitest-5.13.0/lib/minitest/parallel.rbnu[PK ]oz)"bgems/minitest-5.13.0/lib/minitest/hell.rbnu[PK ]9M M 1Fbgems/minitest-5.13.0/lib/minitest/pride_plugin.rbnu[PK ]T1bgems/minitest-5.13.0/lib/minitest/expectations.rbnu[PK ]I,cgems/minitest-5.13.0/lib/minitest/autorun.rbnu[PK ]^ѿ##) cgems/minitest-5.13.0/lib/minitest/spec.rbnu[PK ]Lj)p(2.cgems/minitest-5.13.0/lib/hoe/minitest.rbnu[PK ]\!-1cgems/minitest-5.13.0/History.rdocnu[PK ]5~~(cgems/minitest-5.13.0/design_rationale.rbnu[PK ]:n&5&5ocgems/test-unit-3.3.4/PSFLnu[PK ]FNFFdgems/test-unit-3.3.4/GPLnu[PK ]~""]dgems/test-unit-3.3.4/Rakefilenu[PK ]s  -Afdgems/test-unit-3.3.4/test/util/test-output.rbnu[PK ]cʪ6gdgems/test-unit-3.3.4/test/util/test_backtracefilter.rbnu[PK ]`+O1pdgems/test-unit-3.3.4/test/util/test_observable.rbnu[PK ]2ǀdgems/test-unit-3.3.4/test/util/test_procwrapper.rbnu[PK ]^&1:"dgems/test-unit-3.3.4/test/util/test-method-owner-finder.rbnu[PK ]z}J J -dgems/test-unit-3.3.4/test/test-test-result.rbnu[PK ]( DD-Edgems/test-unit-3.3.4/test/fixtures/header.tsvnu[PK ]DD-dgems/test-unit-3.3.4/test/fixtures/header.csvnu[PK ]cm..0dgems/test-unit-3.3.4/test/fixtures/no-header.csvnu[PK ]? "..0dgems/test-unit-3.3.4/test/fixtures/no-header.tsvnu[PK ]_CC3dgems/test-unit-3.3.4/test/fixtures/header-label.csvnu[PK ]*CC3Idgems/test-unit-3.3.4/test/fixtures/header-label.tsvnu[PK ]:bOO+dgems/test-unit-3.3.4/test/fixtures/plus.csvnu[PK ]D.dgems/test-unit-3.3.4/test/test-notification.rbnu[PK ]\҃P  *dgems/test-unit-3.3.4/test/test-priority.rbnu[PK ]52'rdgems/test-unit-3.3.4/test/test-error.rbnu[PK ]H.Mdgems/test-unit-3.3.4/test/test-emacs-runner.rbnu[PK ] +dgems/test-unit-3.3.4/test/test-attribute.rbnu[PK ]d)dgems/test-unit-3.3.4/test/test-pending.rbnu[PK ]ad  4dgems/test-unit-3.3.4/test/test-test-suite-creator.rbnu[PK ]sEv v .8dgems/test-unit-3.3.4/test/test-color-scheme.rbnu[PK ]7C6 dgems/test-unit-3.3.4/test/collector/test-descendant.rbnu[PK ]a660dgems/test-unit-3.3.4/test/collector/test-load.rbnu[PK ])**/Q)egems/test-unit-3.3.4/test/collector/test_dir.rbnu[PK ]2\ 7Tegems/test-unit-3.3.4/test/collector/test_objectspace.rbnu[PK ]ӪU,`egems/test-unit-3.3.4/test/test-test-suite.rbnu[PK ]U_m77)segems/test-unit-3.3.4/test/test-failure.rbnu[PK ]+4\9owegems/test-unit-3.3.4/test/test-fault-location-detector.rbnu[PK ]G-44&egems/test-unit-3.3.4/test/test-data.rbnu[PK ]J  .egems/test-unit-3.3.4/test/test-code-snippet.rbnu[PK ]w22'egems/test-unit-3.3.4/test/test-color.rbnu[PK ]20~,/egems/test-unit-3.3.4/test/testunit-test-util.rbnu[PK ]:QQ+pegems/test-unit-3.3.4/test/test-test-case.rbnu[PK ])N,^fgems/test-unit-3.3.4/test/test-assertions.rbnu[PK ]kVV)nVggems/test-unit-3.3.4/test/test-fixture.rbnu[PK ]?"= = *ggems/test-unit-3.3.4/test/test-omission.rbnu[PK ]q$G;H;H&(ggems/test-unit-3.3.4/test/test-diff.rbnu[PK ]X_3ggems/test-unit-3.3.4/test/test-attribute-matcher.rbnu[PK ]Fill%:hgems/test-unit-3.3.4/test/run-test.rbnu[PK ]7w004hgems/test-unit-3.3.4/test/ui/test_testrunmediator.rbnu[PK ]f*k hgems/test-unit-3.3.4/README.mdnu[PK ]>X"Vggahgems/test-unit-3.3.4/LGPLnu[PK ]vm L{hgems/test-unit-3.3.4/COPYINGnu[PK ]oc)\hgems/test-unit-3.3.4/sample/test_adder.rbnu[PK ]c: $@hgems/test-unit-3.3.4/sample/adder.rbnu[PK ]d@.hgems/test-unit-3.3.4/sample/test_subtracter.rbnu[PK ]/jj(hgems/test-unit-3.3.4/sample/test_user.rbnu[PK ]Z)ehgems/test-unit-3.3.4/sample/subtracter.rbnu[PK ]$yӱ'hgems/test-unit-3.3.4/doc/text/how-to.mdnu[PK ]@J?%ȗhgems/test-unit-3.3.4/doc/text/news.mdnu[PK ]p0!'igems/test-unit-3.3.4/doc/text/getting-started.mdnu[PK ]w:e:igems/test-unit-3.3.4/lib/test/unit/code-snippet-fetcher.rbnu[PK ]C9 9 5@igems/test-unit-3.3.4/lib/test/unit/util/observable.rbnu[PK ]̭1KLigems/test-unit-3.3.4/lib/test/unit/util/output.rbnu[PK ]S<>Oigems/test-unit-3.3.4/lib/test/unit/util/method-owner-finder.rbnu[PK ]>\MM6Rigems/test-unit-3.3.4/lib/test/unit/util/procwrapper.rbnu[PK ]00:Wigems/test-unit-3.3.4/lib/test/unit/util/backtracefilter.rbnu[PK ]9'ee*6_igems/test-unit-3.3.4/lib/test/unit/diff.rbnu[PK ]*6r +Cigems/test-unit-3.3.4/lib/test/unit/color.rbnu[PK ]U<l /ligems/test-unit-3.3.4/lib/test/unit/data-sets.rbnu[PK ]q((0igems/test-unit-3.3.4/lib/test/unit/assertions.rbnu[PK ] 0kgems/test-unit-3.3.4/lib/test/unit/testresult.rbnu[PK ]Uį-/kgems/test-unit-3.3.4/lib/test/unit/pending.rbnu[PK ]Dddd.#kgems/test-unit-3.3.4/lib/test/unit/omission.rbnu[PK ]soo+5kgems/test-unit-3.3.4/lib/test/unit/error.rbnu[PK ] /44/Dkgems/test-unit-3.3.4/lib/test/unit/testsuite.rbnu[PK ]/>Xkgems/test-unit-3.3.4/lib/test/unit/attribute.rbnu[PK ] ,E.tkgems/test-unit-3.3.4/lib/test/unit/priority.rbnu[PK ]R!\c\c.kgems/test-unit-3.3.4/lib/test/unit/testcase.rbnu[PK ]<kgems/test-unit-3.3.4/lib/test/unit/assertion-failed-error.rbnu[PK ]\c3x x 2kgems/test-unit-3.3.4/lib/test/unit/notification.rbnu[PK ](::-kgems/test-unit-3.3.4/lib/test/unit/version.rbnu[PK ]FJ:AA0ekgems/test-unit-3.3.4/lib/test/unit/autorunner.rbnu[PK ]n$$->lgems/test-unit-3.3.4/lib/test/unit/fixture.rbnu[PK ]l 4&clgems/test-unit-3.3.4/lib/test/unit/runner/console.rbnu[PK ]qo0Oolgems/test-unit-3.3.4/lib/test/unit/runner/xml.rbnu[PK ]l2Wqlgems/test-unit-3.3.4/lib/test/unit/runner/emacs.rbnu[PK ] 4"lgems/test-unit-3.3.4/lib/test/unit/collector/load.rbnu[PK ]Q$ 3slgems/test-unit-3.3.4/lib/test/unit/collector/dir.rbnu[PK ]>;lgems/test-unit-3.3.4/lib/test/unit/collector/objectspace.rbnu[PK ]], = lgems/test-unit-3.3.4/lib/test/unit/fault-location-detector.rbnu[PK ]j V 7olgems/test-unit-3.3.4/lib/test/unit/exception-handler.rbnu[PK ]"zz2mgems/test-unit-3.3.4/lib/test/unit/color-scheme.rbnu[PK ]= = 8{!mgems/test-unit-3.3.4/lib/test/unit/test-suite-creator.rbnu[PK ]H~XX- .mgems/test-unit-3.3.4/lib/test/unit/failure.rbnu[PK ]xZZ9Bmgems/test-unit-3.3.4/lib/test/unit/ui/emacs/testrunner.rbnu[PK ]u$$<Hmgems/test-unit-3.3.4/lib/test/unit/ui/testrunnerutilities.rbnu[PK ]d7(Mmgems/test-unit-3.3.4/lib/test/unit/ui/xml/testrunner.rbnu[PK ]l~<|imgems/test-unit-3.3.4/lib/test/unit/ui/console/outputlevel.rbnu[PK ]!=(__;jmgems/test-unit-3.3.4/lib/test/unit/ui/console/testrunner.rbnu[PK ]޸3.mgems/test-unit-3.3.4/lib/test/unit/ui/testrunner.rbnu[PK ]N N ;6mgems/test-unit-3.3.4/lib/test/unit/ui/testrunnermediator.rbnu[PK ]KE::/mgems/test-unit-3.3.4/lib/test/unit/collector.rbnu[PK ]Vݯ7mgems/test-unit-3.3.4/lib/test/unit/attribute-matcher.rbnu[PK ]-K@K@%mgems/test-unit-3.3.4/lib/test/unit.rbnu[PK ] O%>(ngems/test-unit-3.3.4/lib/test-unit.rbnu[PK ]B-ngems/json-2.3.0/lib/json.rbnu[PK ]oaa*4ngems/json-2.3.0/lib/json/add/bigdecimal.rbnu[PK ]&a\\$Y7ngems/json-2.3.0/lib/json/add/core.rbnu[PK ]@9%& 9ngems/json-2.3.0/lib/json/add/regexp.rbnu[PK ]ff&bh  4qgems/rake-13.0.1/bin/bundlenu[PK ]R  (qgems/rake-13.0.1/lib/rake/linked_list.rbnu[PK ]2bb-qgems/rake-13.0.1/lib/rake/loaders/makefile.rbnu[PK ]u%qgems/rake-13.0.1/lib/rake/ext/core.rbnu[PK ]yOurr'qgems/rake-13.0.1/lib/rake/ext/string.rbnu[PK ].*C}}"} rgems/rake-13.0.1/lib/rake/phony.rbnu[PK ]?{Hrr'Lrgems/rake-13.0.1/lib/rake/early_time.rbnu[PK ]n#0rgems/rake-13.0.1/lib/rake/task_argument_error.rbnu[PK ]QG" rgems/rake-13.0.1/lib/rake/clean.rbnu[PK ]d11&yrgems/rake-13.0.1/lib/rake/file_list.rbnu[PK ]F- +Lrgems/rake-13.0.1/lib/rake/dsl_definition.rbnu[PK ]&brgems/rake-13.0.1/lib/rake/cloneable.rbnu[PK ];YII'drgems/rake-13.0.1/lib/rake/file_utils.rbnu[PK ]"trgems/rake-13.0.1/lib/rake/scope.rbnu[PK ]sZZ+qxrgems/rake-13.0.1/lib/rake/file_utils_ext.rbnu[PK ])lq((&rgems/rake-13.0.1/lib/rake/packagetask.rbnu[PK ]4Tc(rgems/rake-13.0.1/lib/rake/thread_pool.rbnu[PK ]n $rgems/rake-13.0.1/lib/rake/version.rbnu[PK ]^  $rgems/rake-13.0.1/lib/rake/promise.rbnu[PK ]YY'-rgems/rake-13.0.1/lib/rake/multi_task.rbnu[PK ]j"ݿrgems/rake-13.0.1/lib/rake/win32.rbnu[PK ]Ӭs~~:?rgems/rake-13.0.1/lib/rake/rule_recursion_overflow_error.rbnu[PK ]0ZR+'rgems/rake-13.0.1/lib/rake/private_reader.rbnu[PK ]7 rgems/rake-13.0.1/lib/rake/invocation_exception_mixin.rbnu[PK ]R22!@rgems/rake-13.0.1/lib/rake/task.rbnu[PK ]i  +rgems/rake-13.0.1/lib/rake/default_loader.rbnu[PK ]l??)sgems/rake-13.0.1/lib/rake/trace_output.rbnu[PK ]I&sgems/rake-13.0.1/lib/rake/file_task.rbnu[PK ]p,۞% sgems/rake-13.0.1/lib/rake/testtask.rbnu[PK ]lD',"sgems/rake-13.0.1/lib/rake/name_space.rbnu[PK ]m3A%sgems/rake-13.0.1/lib/rake/thread_history_display.rbnu[PK ]Jሀ&(*sgems/rake-13.0.1/lib/rake/backtrace.rbnu[PK ]H bb(-sgems/rake-13.0.1/lib/rake/application.rbnu[PK ]Q(qsgems/rake-13.0.1/lib/rake/rake_module.rbnu[PK ]-x= ( ()sgems/rake-13.0.1/lib/rake/task_manager.rbnu[PK ]~y +&sgems/rake-13.0.1/lib/rake/task_arguments.rbnu[PK ]K*%sgems/rake-13.0.1/lib/rake/pseudo_status.rbnu[PK ]M M (sgems/rake-13.0.1/lib/rake/cpu_counter.rbnu[PK ]''&sgems/rake-13.0.1/lib/rake/late_time.rbnu[PK ]-6sgems/rake-13.0.1/lib/rake/rake_test_loader.rbnu[PK ]K\-sgems/rake-13.0.1/lib/rake/invocation_chain.rbnu[PK ]E.$sgems/rake-13.0.1/lib/rake/tasklib.rbnu[PK ]l/sgems/rake-13.0.1/lib/rake/file_creation_task.rbnu[PK ]Q=rrsgems/rake-13.0.1/lib/rake.rbnu[PK ]A uxsgems/rake-13.0.1/History.rdocnu[PK ]U&"iugems/rake-13.0.1/CONTRIBUTING.rdocnu[PK ]mǯ rugems/racc-1.4.16/bin/raccnuȯPK ]/(ugems/ruby-lsapi-5.6/ext/lsapi/.sitearchdir.timenu[PK ]Y//((ugems/ruby-lsapi-5.6/ext/lsapi/lsapilib.hnu[PK ]7Zw(BYugems/ruby-lsapi-5.6/ext/lsapi/extconf.rbnu[PK ]dCR[R[&Zugems/ruby-lsapi-5.6/ext/lsapi/lsruby.cnu[PK ]W q,,(>ugems/ruby-lsapi-5.6/ext/lsapi/lsapidef.hnu[PK ]ւg/(((ugems/ruby-lsapi-5.6/ext/lsapi/lsapilib.onu[PK ]k##&zgems/ruby-lsapi-5.6/ext/lsapi/Makefilenu[PK ] 3O8aa({gems/ruby-lsapi-5.6/ext/lsapi/lsapilib.cnu[PK ]33&|gems/ruby-lsapi-5.6/ext/lsapi/lsapi.sonuȯPK ]gy&~gems/ruby-lsapi-5.6/ext/lsapi/lsruby.onu[PK ]whf:!Agems/ruby-lsapi-5.6/lsapi.gemspecnu[PK ]^wͱgems/ruby-lsapi-5.6/READMEnu[PK ]j2(gems/ruby-lsapi-5.6/rails/dispatch.lsapinuȯPK ]MM,fgems/ruby-lsapi-5.6/scripts/lsruby_runner.rbnuȯPK ]##BBgems/ruby-lsapi-5.6/setup.rbnu[PK ]*  )gems/ruby-lsapi-5.6/examples/testlsapi.rbnuȯPK ].gems/ruby-lsapi-5.6/examples/lsapi_with_cgi.rbnuȯPK ]L,Ngems/io-console-0.5.6/lib/io/console/size.rbnu[PK ]B^$Ygems/openssl-2.1.4/lib/openssl/bn.rbnu[PK ]w+D(qgems/openssl-2.1.4/lib/openssl/cipher.rbnu[PK ]̒O??%gems/openssl-2.1.4/lib/openssl/ssl.rbnu[PK ]S:_CC&gems/openssl-2.1.4/lib/openssl/x509.rbnu[PK ]I1&s gems/openssl-2.1.4/lib/openssl/pkey.rbnu[PK ]Mff'`gems/openssl-2.1.4/lib/openssl/pkcs5.rbnu[PK ]d Ҽ&&+gems/openssl-2.1.4/lib/openssl/buffering.rbnu[PK ]ӡv85252(49gems/openssl-2.1.4/lib/openssl/config.rbnu[PK ](kgems/openssl-2.1.4/lib/openssl/digest.rbnu[PK ]>)!rgems/openssl-2.1.4/lib/openssl.rbnu[PK ] !ugems/net-telnet-0.2.0/LICENSE.txtnu[PK ]V__2gems/net-telnet-0.2.0/Gemfilenu[PK ]Znn(gems/net-telnet-0.2.0/net-telnet.gemspecnu[PK ]77gems/net-telnet-0.2.0/Rakefilenu[PK ]ɷ׽F F gems/net-telnet-0.2.0/README.mdnu[PK ]Gss/gems/net-telnet-0.2.0/bin/setupnu[PK ]V?OO!gems/net-telnet-0.2.0/bin/consolenu[PK ]]8HH'gems/net-telnet-0.2.0/lib/net/telnet.rbnu[PK ]>7C::/0gems/net-telnet-0.2.0/lib/net/telnet/version.rbnu[PK ][J¼'gems/net-telnet-0.2.0/lib/net-telnet.rbnu[PK ]$(QTT5gems/psych-3.1.0/lib/psych.rbnu[PK ]H,Xigems/psych-3.1.0/lib/psych/scalar_scanner.rbnu[PK ]KK"?zgems/psych-3.1.0/lib/psych/omap.rbnu[PK ] [$zgems/psych-3.1.0/lib/psych/parser.rbnu[PK ]`[%߁gems/psych-3.1.0/lib/psych/handler.rbnu[PK ] *gems/psych-3.1.0/lib/psych/tree_builder.rbnu[PK ]'Egems/psych-3.1.0/lib/psych/exception.rbnu[PK ]*JJ!gems/psych-3.1.0/lib/psych/set.rbnu[PK ]PKK0?gems/psych-3.1.0/lib/psych/visitors/json_tree.rbnu[PK ]R(rr2ꯂgems/psych-3.1.0/lib/psych/visitors/depth_first.rbnu[PK ]#<#<0gems/psych-3.1.0/lib/psych/visitors/yaml_tree.rbnu[PK ]6*4gg.Agems/psych-3.1.0/lib/psych/visitors/visitor.rbnu[PK ]Sܶ...gems/psych-3.1.0/lib/psych/visitors/to_ruby.rbnu[PK ]Z. gems/psych-3.1.0/lib/psych/visitors/emitter.rbnu[PK ]fk k #B&gems/psych-3.1.0/lib/psych/nodes.rbnu[PK ]'K0gems/psych-3.1.0/lib/psych/y.rbnu[PK ]%& 1gems/psych-3.1.0/lib/psych/versions.rbnu[PK ]r$A2gems/psych-3.1.0/lib/psych/stream.rbnu[PK ]&3*II*06gems/psych-3.1.0/lib/psych/syntax_error.rbnu[PK ]y2K'8gems/psych-3.1.0/lib/psych/streaming.rbnu[PK ]ӻ&;gems/psych-3.1.0/lib/psych/visitors.rbnu[PK ]oe *=gems/psych-3.1.0/lib/psych/class_loader.rbnu[PK ]|uu/Egems/psych-3.1.0/lib/psych/handlers/recorder.rbnu[PK ]}6Hgems/psych-3.1.0/lib/psych/handlers/document_stream.rbnu[PK ](Cee/DKgems/psych-3.1.0/lib/psych/json/tree_builder.rbnu[PK ]  .Mgems/psych-3.1.0/lib/psych/json/yaml_events.rbnu[PK ] Ej)qPgems/psych-3.1.0/lib/psych/json/stream.rbnu[PK ].`Rgems/psych-3.1.0/lib/psych/json/ruby_events.rbnu[PK ]u>22#Tgems/psych-3.1.0/lib/psych/coder.rbnu[PK ]"+  (+]gems/psych-3.1.0/lib/psych/nodes/node.rbnu[PK ]믍!!,dgems/psych-3.1.0/lib/psych/nodes/sequence.rbnu[PK ]ɉ  ) mgems/psych-3.1.0/lib/psych/nodes/alias.rbnu[PK ])))+qogems/psych-3.1.0/lib/psych/nodes/mapping.rbnu[PK ]Ϧ[*ugems/psych-3.1.0/lib/psych/nodes/stream.rbnu[PK ](%*Pzgems/psych-3.1.0/lib/psych/nodes/scalar.rbnu[PK ]AA,-gems/psych-3.1.0/lib/psych/nodes/document.rbnu[PK ]Rzgg&ʈgems/psych-3.1.0/lib/psych/core_ext.rbnu[PK ]I>>cache/rackup-2.1.0.gemnu[PK ]"ȃcache/rack-3.0.8.gemnu[PK ]a]qcache/ruby-lsapi-5.5.gemnu[PK ]'AY=cache/ruby-lsapi-5.6.gemnu[PKu]=w irb-1.2.6/exe/irbnuȯPKu]Skk irb-1.2.6/lib/irb.rbnu[PKu])C=C=virb-1.2.6/lib/irb/context.rbnu[PKu]*\:irb-1.2.6/lib/irb/help.rbnu[PKu],9Yk@irb-1.2.6/lib/irb/lc/error.rbnu[PKu]\`9+irb-1.2.6/lib/irb/lc/ja/encoding_aliases.rbnu[PKu]. irb-1.2.6/lib/irb/lc/ja/error.rbnu[PKu]Ȇ@Dj j $ Ƈirb-1.2.6/lib/irb/lc/ja/help-messagenu[PKu]o]!Їirb-1.2.6/lib/irb/lc/help-messagenu[PKu]ᣟ##!؇irb-1.2.6/lib/irb/input-method.rbnu[PKu]C5vlirb-1.2.6/lib/irb/ext/tracer.rbnu[PKu]yr| | -irb-1.2.6/lib/irb/ext/loader.rbnu[PKu]](  "irb-1.2.6/lib/irb/ext/change-ws.rbnu[PKu] %Sirb-1.2.6/lib/irb/ext/save-history.rbnu[PKu]uI"6$irb-1.2.6/lib/irb/ext/multi-irb.rbnu[PKu]N9#E>irb-1.2.6/lib/irb/ext/use-loader.rbnu[PKu]fcI#[Firb-1.2.6/lib/irb/ext/workspaces.rbnu[PKu]ɼ Lirb-1.2.6/lib/irb/ext/history.rbnu[PKu]:?cBcB[irb-1.2.6/lib/irb/ruby-lex.rbnu[PKu]wSirb-1.2.6/lib/irb/color.rbnu[PKu]yk/AAirb-1.2.6/lib/irb/locale.rbnu[PKu]ppшirb-1.2.6/lib/irb/easter-egg.rbnu[PKu]fɁc"c"߈irb-1.2.6/lib/irb/init.rbnu[PKu]I I irb-1.2.6/lib/irb/ruby_logo.aanu[PKu]O irb-1.2.6/lib/irb/cmd/help.rbnu[PKu]#oirb-1.2.6/lib/irb/cmd/load.rbnu[PKu]Q~~ irb-1.2.6/lib/irb/cmd/fork.rbnu[PKu]j$irb-1.2.6/lib/irb/cmd/chws.rbnu[PKu])ڏ!!>irb-1.2.6/lib/irb/cmd/nop.rbnu[PKu]zirb-1.2.6/lib/irb/cmd/pushws.rbnu[PKu]I]]irb-1.2.6/lib/irb/cmd/subirb.rbnu[PKu]{A5//"irb-1.2.6/lib/irb/cmd/info.rbnu[PKu]t$irb-1.2.6/lib/irb/xmp.rbnu[PKu]c!a5irb-1.2.6/lib/irb/src_encoding.rbnu[PKu]h((E6irb-1.2.6/lib/irb/version.rbnu[PKu]Ɨ]%%7irb-1.2.6/lib/irb/completion.rbnu[PKu]DKC]irb-1.2.6/lib/irb/workspace.rbnu[PKu]ǀ sirb-1.2.6/lib/irb/frame.rbnu[PKu]&/((#;{irb-1.2.6/lib/irb/extend-command.rbnu[PKu] ["irb-1.2.6/lib/irb/ws-for-case-2.rbnu[PKu] V2 ";irb-1.2.6/lib/irb/output-method.rbnu[PKu]qNirb-1.2.6/lib/irb/inspector.rbnu[PKu][Eirb-1.2.6/lib/irb/magic-file.rbnu[PKu]cp.4Éirb-1.2.6/lib/irb/notifier.rbnu[PKu]D\\rbundler-2.2.24/libexec/bundlernuȯPKu]ʏMbundler-2.2.24/libexec/bundlenuȯPKu]^ ^^Dbundler-2.2.24/lib/bundler.rbnu[PKu]tJT T $EEbundler-2.2.24/lib/bundler/source.rbnu[PKu]${4Qbundler-2.2.24/lib/bundler/endpoint_specification.rbnu[PKu]١"2)2)%abundler-2.2.24/lib/bundler/runtime.rbnu[PKu]P0|bundler-2.2.24/lib/bundler/lazy_specification.rbnu[PKu]eo}O}O!_bundler-2.2.24/lib/bundler/dsl.rbnu[PKu]eAss(-bundler-2.2.24/lib/bundler/capistrano.rbnu[PKu]V,bundler-2.2.24/lib/bundler/match_platform.rbnu[PKu] .XX(bundler-2.2.24/lib/bundler/definition.rbnu[PKu]W| tbundler-2.2.24/lib/bundler/ui.rbnu[PKu]HT4ubundler-2.2.24/lib/bundler/rubygems_gem_installer.rbnu[PKu]_l__-χbundler-2.2.24/lib/bundler/vendored_tmpdir.rbnu[PKu]60bundler-2.2.24/lib/bundler/lockfile_generator.rbnu[PKu]xsn}*}*$bundler-2.2.24/lib/bundler/plugin.rbnu[PKu]h&(2ubundler-2.2.24/lib/bundler/remote_specification.rbnu[PKu] F-jˋbundler-2.2.24/lib/bundler/lockfile_parser.rbnu[PKu]x4bundler-2.2.24/lib/bundler/uri_credentials_filter.rbnu[PKu]--,!bundler-2.2.24/lib/bundler/shared_helpers.rbnu[PKu]-)&bundler-2.2.24/lib/bundler/ruby_dsl.rbnu[PKu]zrr!bundler-2.2.24/lib/bundler/cli.rbnu[PKu]!6n n -bundler-2.2.24/lib/bundler/yaml_serializer.rbnu[PKu]X33&qbundler-2.2.24/lib/bundler/settings.rbnu[PKu](|{ { 0ubundler-2.2.24/lib/bundler/stub_specification.rbnu[PKu]e HPbundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool.rbnu[PKu]\?66Pbundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rbnu[PKu]q.YYWtbundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rbnu[PKu]y<22TTbundler-2.2.24/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rbnu[PKu]홇> )bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor.rbnu[PKu]9*bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser.rbnu[PKu]Luvv>+bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/rake_compat.rbnu[PKu]ɗc 84bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/error.rbnu[PKu]#I`i#i#8#Bbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/group.rbnu[PKu]1UyXX>ebundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/color.rbnu[PKu].=ybundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/html.rbnu[PKu]699>bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell/basic.rbnu[PKu];:ōbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/command.rbnu[PKu]ᡇ++A؍bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/nested_context.rbnu[PKu]_-[II=sڍbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/invocation.rbnu[PKu]5,,:)bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/version.rbnu[PKu]8Xbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rbnu[PKu]dq=77Gbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rbnu[PKu]Yt}}Dtbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rbnu[PKu])):ebundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions.rbnu[PKu]``71bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/base.rbnu[PKu]P?% % 8bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/shell.rbnu[PKu](_b'b'93bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/runner.rbnu[PKu]aq@Îbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/option.rbnu[PKu]llC ֎bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/arguments.rbnu[PKu]i Bbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/argument.rbnu[PKu]$IJ;;A^bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/parser/options.rbnu[PKu]V]K bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rbnu[PKu]s mmFbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/create_link.rbnu[PKu],;  Di!bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/directory.rbnu[PKu]te) ) F0bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/create_file.rbnu[PKu]Iq3q3L=bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rbnu[PKu]O&Jrqbundler-2.2.24/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rbnu[PKu]jU#U#7肏bundler-2.2.24/lib/bundler/vendor/thor/lib/thor/util.rbnu[PKu]q@q@2bundler-2.2.24/lib/bundler/vendor/thor/lib/thor.rbnu[PKu]C}mmPwbundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rbnu[PKu]6lffbUbundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rbnu[PKu]hO8U\bundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rbnu[PKu](ц[abundler-2.2.24/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rbnu[PKu]t//<ebundler-2.2.24/lib/bundler/vendor/fileutils/lib/fileutils.rbnu[PKu]OU0 0*bundler-2.2.24/lib/bundler/vendor/uri/lib/uri.rbnu[PKu]M0 0 78bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/mailto.rbnu[PKu]M}56Ybundler-2.2.24/lib/bundler/vendor/uri/lib/uri/file.rbnu[PKu]]F֖֖8@bbundler-2.2.24/lib/bundler/vendor/uri/lib/uri/generic.rbnu[PKu]wL{{5~bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ldap.rbnu[PKu]I6^bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ldaps.rbnu[PKu] %%4bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/ftp.rbnu[PKu]38k1bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/version.rbnu[PKu]*@QQ7r2bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/common.rbnu[PKu] 5bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/http.rbnu[PKu]="__6Ɏbundler-2.2.24/lib/bundler/vendor/uri/lib/uri/https.rbnu[PKu]#TΉQQ?bundler-2.2.24/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rbnu[PKu]ٍ2G2G?Nbundler-2.2.24/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rbnu[PKu] II6bundler-2.2.24/lib/bundler/vendor/tmpdir/lib/tmpdir.rbnu[PKu]lHYY<bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo.rbnu[PKu]ԻHHTcbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rbnu[PKu]:ʘ!a/bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rbnu[PKu]XAccX"bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rbnu[PKu].mVQ)bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rbnu[PKu]@G{T,bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rbnu[PKu]5 Q0bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rbnu[PKu]D""Y?bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rbnu[PKu] ?=WWY8Gbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rbnu[PKu]DNjoobLbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rbnu[PKu]cOu((BTbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/state.rbnu[PKu]U#||C[bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/errors.rbnu[PKu]~Esbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rbnu[PKu] M6zbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rbnu[PKu]ۦ ]8bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rbnu[PKu]9DD??WSbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rbnu[PKu]+4Gbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rbnu[PKu]!gpt[[[[bundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rbnu[PKu]=GAȓbundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rbnu[PKu]."IIObundler-2.2.24/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rbnu[PKu]}X'APbundler-2.2.24/lib/bundler/gem_tasks.rbnu[PKu] D##)"Qbundler-2.2.24/lib/bundler/source/path.rbnu[PKu]uR!xx3pbundler-2.2.24/lib/bundler/source/path/installer.rbnu[PKu].۬-yybundler-2.2.24/lib/bundler/source/metadata.rbnu[PKu]gYGG-bundler-2.2.24/lib/bundler/source/rubygems.rbnu[PKu]:U''4hȔbundler-2.2.24/lib/bundler/source/rubygems/remote.rbnu[PKu]ƨ',ϔbundler-2.2.24/lib/bundler/source/gemspec.rbnu[PKu] E//7mєbundler-2.2.24/lib/bundler/source/rubygems_aggregate.rbnu[PKu]Ƌ}(}((ڔbundler-2.2.24/lib/bundler/source/git.rbnu[PKu])g@##2bundler-2.2.24/lib/bundler/source/git/git_proxy.rbnu[PKu]ƣZ&'bundler-2.2.24/lib/bundler/spec_set.rbnu[PKu]4f++2X=bundler-2.2.24/lib/bundler/gem_version_promoter.rbnu[PKu]Tee0Wbundler-2.2.24/lib/bundler/vendored_molinillo.rbnu[PKu]z]EE2Xbundler-2.2.24/lib/bundler/rubygems_integration.rbnu[PKu] X6%)bundler-2.2.24/lib/bundler/version.rbnu[PKu]#*2bundler-2.2.24/lib/bundler/current_ruby.rbnu[PKu])PY\\1bundler-2.2.24/lib/bundler/similarity_detector.rbnu[PKu]6e$ll'ԯbundler-2.2.24/lib/bundler/deprecate.rbnu[PKu]|YY*bundler-2.2.24/lib/bundler/vendored_uri.rbnu[PKu]یYY2Jbundler-2.2.24/lib/bundler/compact_index_client.rbnu[PKu]j[] ] $Õbundler-2.2.24/lib/bundler/worker.rbnu[PKu]<, , 0͕bundler-2.2.24/lib/bundler/settings/validator.rbnu[PKu]h 8Bڕbundler-2.2.24/lib/bundler/compact_index_client/cache.rbnu[PKu]CXj=zbundler-2.2.24/lib/bundler/compact_index_client/gem_parser.rbnu[PKu]q cc:bundler-2.2.24/lib/bundler/compact_index_client/updater.rbnu[PKu]Hu""#Obundler-2.2.24/lib/bundler/setup.rbnu[PKu]hFF*bundler-2.2.24/lib/bundler/psyched_yaml.rbnu[PKu]hc3dbundler-2.2.24/lib/bundler/environment_preserver.rbnu[PKu]I~] 7ebundler-2.2.24/lib/bundler/templates/Executable.bundlernu[PKu]MBbundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/newgem.c.ttnu[PKu]?B/bundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/newgem.h.ttnu[PKu]95ffDRbundler-2.2.24/lib/bundler/templates/newgem/ext/newgem/extconf.rb.ttnu[PKu]7##=,bundler-2.2.24/lib/bundler/templates/newgem/newgem.gemspec.ttnu[PKu]!5c| | 8bundler-2.2.24/lib/bundler/templates/newgem/README.md.ttnu[PKu]+7'bundler-2.2.24/lib/bundler/templates/newgem/Rakefile.ttnu[PKu]~~9+bundler-2.2.24/lib/bundler/templates/newgem/travis.yml.ttnu[PKu]Ҧ+B,bundler-2.2.24/lib/bundler/templates/newgem/spec/spec_helper.rb.ttnu[PKu]32 B.bundler-2.2.24/lib/bundler/templates/newgem/spec/newgem_spec.rb.ttnu[PKu]rə660bundler-2.2.24/lib/bundler/templates/newgem/Gemfile.ttnu[PKu]z??9?2bundler-2.2.24/lib/bundler/templates/newgem/exe/newgem.ttnu[PKu]lq5542bundler-2.2.24/lib/bundler/templates/newgem/rspec.ttnu[PKu]G>JL3bundler-2.2.24/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.ttnu[PKu]q{33L4bundler-2.2.24/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.ttnu[PKu]M-nK@6bundler-2.2.24/lib/bundler/templates/newgem/test/minitest/test_helper.rb.ttnu[PKu]-KW7bundler-2.2.24/lib/bundler/templates/newgem/test/minitest/newgem_test.rb.ttnu[PKu]/++:8bundler-2.2.24/lib/bundler/templates/newgem/rubocop.yml.ttnu[PKu]v@@H|:bundler-2.2.24/lib/bundler/templates/newgem/github/workflows/main.yml.ttnu[PKu]g284<bundler-2.2.24/lib/bundler/templates/newgem/gitignore.ttnu[PKu]44.<=bundler-2.2.24/lib/bundler/templates/newgem/gitlab-ci.yml.ttnu[PKu]!5PP;>bundler-2.2.24/lib/bundler/templates/newgem/CHANGELOG.md.ttnu[PKu]QQ:L?bundler-2.2.24/lib/bundler/templates/newgem/LICENSE.txt.ttnu[PKu]_ccADbundler-2.2.24/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.ttnu[PKu]eە:Xbundler-2.2.24/lib/bundler/templates/newgem/bin/console.ttnu[PKu]8Zbundler-2.2.24/lib/bundler/templates/newgem/bin/setup.ttnu[PKu]^6)g&&B[bundler-2.2.24/lib/bundler/templates/newgem/circleci/config.yml.ttnu[PKu]DT]bundler-2.2.24/lib/bundler/templates/newgem/lib/newgem/version.rb.ttnu[PKu]Br==<^bundler-2.2.24/lib/bundler/templates/newgem/lib/newgem.rb.ttnu[PKu]”}Ñ/abundler-2.2.24/lib/bundler/templates/Executablenu[PKu]t,zebundler-2.2.24/lib/bundler/templates/Gemfilenu[PKu]{:ifbundler-2.2.24/lib/bundler/templates/Executable.standalonenu[PKu]Ba7,hbundler-2.2.24/lib/bundler/templates/gems.rbnu[PKu]9rQ' ' $ibundler-2.2.24/lib/bundler/inline.rbnu[PKu]4%%& ubundler-2.2.24/lib/bundler/injector.rbnu[PKu] G'Jbundler-2.2.24/lib/bundler/dep_proxy.rbnu[PKu]\"bbundler-2.2.24/lib/bundler/vlad.rbnu[PKu]oJ$bundler-2.2.24/lib/bundler/errors.rbnu[PKu]Ǵ+bundler-2.2.24/lib/bundler/vendored_thor.rbnu[PKu]p2Ǥ'bundler-2.2.24/lib/bundler/constants.rbnu[PKu]88)öbundler-2.2.24/lib/bundler/cli/console.rbnu[PKu]'Tbundler-2.2.24/lib/bundler/cli/check.rbnu[PKu]j&bundler-2.2.24/lib/bundler/cli/show.rbnu[PKu]`K&ʖbundler-2.2.24/lib/bundler/cli/lock.rbnu[PKu])``'іbundler-2.2.24/lib/bundler/cli/clean.rbnu[PKu]m/Ċ&Ԗbundler-2.2.24/lib/bundler/cli/init.rbnu[PKu]Ak(rٖbundler-2.2.24/lib/bundler/cli/plugin.rbnu[PKu]N  &bundler-2.2.24/lib/bundler/cli/exec.rbnu[PKu]|jj'bundler-2.2.24/lib/bundler/cli/cache.rbnu[PKu]%4*bundler-2.2.24/lib/bundler/cli/platform.rbnu[PKu]22%bundler-2.2.24/lib/bundler/cli/gem.rbnu[PKu]lqOww((bundler-2.2.24/lib/bundler/cli/inject.rbnu[PKu];.>>%x1bundler-2.2.24/lib/bundler/cli/viz.rbnu[PKu]V9& 6bundler-2.2.24/lib/bundler/cli/fund.rbnu[PKu](9bundler-2.2.24/lib/bundler/cli/common.rbnu[PKu]RR&SLbundler-2.2.24/lib/bundler/cli/list.rbnu[PKu]&Sbundler-2.2.24/lib/bundler/cli/open.rbnu[PKu]lww("Xbundler-2.2.24/lib/bundler/cli/remove.rbnu[PKu] (Ybundler-2.2.24/lib/bundler/cli/doctor.rbnu[PKu],(kbundler-2.2.24/lib/bundler/cli/update.rbnu[PKu]="$"$*N{bundler-2.2.24/lib/bundler/cli/outdated.rbnu[PKu]w#w#)ʟbundler-2.2.24/lib/bundler/cli/install.rbnu[PKu]3LT*×bundler-2.2.24/lib/bundler/cli/pristine.rbnu[PKu]Ʊe}}(ʗbundler-2.2.24/lib/bundler/cli/config.rbnu[PKu]RL%Vbundler-2.2.24/lib/bundler/cli/add.rbnu[PKu]u)'bundler-2.2.24/lib/bundler/cli/issue.rbnu[PKu]"G*bundler-2.2.24/lib/bundler/cli/binstubs.rbnu[PKu]W{ { &;bundler-2.2.24/lib/bundler/cli/info.rbnu[PKu]?z( bundler-2.2.24/lib/bundler/gem_helper.rbnu[PKu]`f<<&bundler-2.2.24/lib/bundler/resolver.rbnu[PKu]ω~%%(Zbundler-2.2.24/lib/bundler/dependency.rbnu[PKu]N˾*Wnbundler-2.2.24/lib/bundler/process_lock.rbnu[PKu]h (oqbundler-2.2.24/lib/bundler/deployment.rbnu[PKu]aXeXX-~bundler-2.2.24/lib/bundler/friendly_errors.rbnu[PKu]^cc)Abundler-2.2.24/lib/bundler/gem_helpers.rbnu[PKu]a! 5bundler-2.2.24/lib/bundler/installer/gem_installer.rbnu[PKu]y:Tbundler-2.2.24/lib/bundler/installer/parallel_installer.rbnu[PKu]{sEjj2ɘbundler-2.2.24/lib/bundler/installer/standalone.rbnu[PKu]3dMM.sҘbundler-2.2.24/lib/bundler/man/bundle-remove.1nu[PKu])&LYY2֘bundler-2.2.24/lib/bundler/man/bundle-check.1.ronnnu[PKu](V0٘bundler-2.2.24/lib/bundler/man/bundle-viz.1.ronnnu[PKu];7676.ݘbundler-2.2.24/lib/bundler/man/bundle-update.1nu[PKu]MM+bundler-2.2.24/lib/bundler/man/bundle-viz.1nu[PKu]l424bundler-2.2.24/lib/bundler/man/bundle-clean.1.ronnnu[PKu]k  2zbundler-2.2.24/lib/bundler/man/bundle-cache.1.ronnnu[PKu]&+['bundler-2.2.24/lib/bundler/man/bundle-add.1nu[PKu]H,-bundler-2.2.24/lib/bundler/man/bundle-show.1nu[PKu]B5UU30bundler-2.2.24/lib/bundler/man/bundle-inject.1.ronnnu[PKu]$.F3bundler-2.2.24/lib/bundler/man/bundle-doctor.1nu[PKu]9IG 1-8bundler-2.2.24/lib/bundler/man/bundle-lock.1.ronnnu[PKu]Iߚ 5kDbundler-2.2.24/lib/bundler/man/bundle-outdated.1.ronnnu[PKu]1~5Rbundler-2.2.24/lib/bundler/man/bundle-binstubs.1.ronnnu[PKu]UM -Xbundler-2.2.24/lib/bundler/man/bundle-cache.1nu[PKu]0ebundler-2.2.24/lib/bundler/man/bundle-outdated.1nu[PKu]N-'tbundler-2.2.24/lib/bundler/man/bundle.1nu[PKu]|)$J$J3Sbundler-2.2.24/lib/bundler/man/bundle-config.1.ronnnu[PKu]ms s ,͙bundler-2.2.24/lib/bundler/man/bundle-lock.1nu[PKu]m-ڙbundler-2.2.24/lib/bundler/man/bundle-check.1nu[PKu]\'iTT1ޙbundler-2.2.24/lib/bundler/man/bundle-show.1.ronnnu[PKu]˱[y3}bundler-2.2.24/lib/bundler/man/bundle-remove.1.ronnnu[PKu]h1bundler-2.2.24/lib/bundler/man/bundle-init.1.ronnnu[PKu]+B+B4bundler-2.2.24/lib/bundler/man/bundle-install.1.ronnnu[PKu]^ ;ff,U+bundler-2.2.24/lib/bundler/man/bundle-exec.1nu[PKu]qq1Fbundler-2.2.24/lib/bundler/man/bundle-info.1.ronnnu[PKu]Ag880Gbundler-2.2.24/lib/bundler/man/bundle-platform.1nu[PKu]QdUU(Mbundler-2.2.24/lib/bundler/man/gemfile.5nu[PKu]n½,sbundler-2.2.24/lib/bundler/man/bundle-info.1nu[PKu]6H3bundler-2.2.24/lib/bundler/man/bundle-doctor.1.ronnnu[PKu]8XX-bundler-2.2.24/lib/bundler/man/bundle-clean.1nu[PKu]Y|LL0sbundler-2.2.24/lib/bundler/man/bundle-binstubs.1nu[PKu]V#1bundler-2.2.24/lib/bundler/man/bundle-list.1.ronnnu[PKu]#s5bundler-2.2.24/lib/bundler/man/bundle-pristine.1.ronnnu[PKu]C..0̼bundler-2.2.24/lib/bundler/man/bundle-gem.1.ronnnu[PKu]^-+Z̚bundler-2.2.24/lib/bundler/man/bundle-gem.1nu[PKu]51ݚbundler-2.2.24/lib/bundler/man/bundle-open.1.ronnnu[PKu]P~||1ߚbundler-2.2.24/lib/bundler/man/bundle-exec.1.ronnnu[PKu]w,w113bundler-2.2.24/lib/bundler/man/bundle-update.1.ronnnu[PKu]|=.)bundler-2.2.24/lib/bundler/man/bundle-inject.1nu[PKu],,2-bundler-2.2.24/lib/bundler/man/bundle-list.1nu[PKu]8EDFDF/O1bundler-2.2.24/lib/bundler/man/bundle-install.1nu[PKu]-N-N-wbundler-2.2.24/lib/bundler/man/gemfile.5.ronnnu[PKu]>^gH H ,|ƛbundler-2.2.24/lib/bundler/man/bundle.1.ronnnu[PKu]2P33, ӛbundler-2.2.24/lib/bundler/man/bundle-init.1nu[PKu]ߕ}}5כbundler-2.2.24/lib/bundler/man/bundle-platform.1.ronnnu[PKu]j0ܛbundler-2.2.24/lib/bundler/man/bundle-pristine.1nu[PKu]'uw^0{bundler-2.2.24/lib/bundler/man/bundle-add.1.ronnnu[PKu]?OAA,bundler-2.2.24/lib/bundler/man/bundle-open.1nu[PKu]"&YxSS.Ubundler-2.2.24/lib/bundler/man/bundle-config.1nu[PKu]uw-w-']?bundler-2.2.24/lib/bundler/installer.rbnu[PKu]Vw3+mbundler-2.2.24/lib/bundler/fetcher/compact_index.rbnu[PKu]L;8 0ebundler-2.2.24/lib/bundler/fetcher/dependency.rbnu[PKu]*[bundler-2.2.24/lib/bundler/fetcher/base.rbnu[PKu],dd+bundler-2.2.24/lib/bundler/fetcher/index.rbnu[PKu]]Y Y 0Obundler-2.2.24/lib/bundler/fetcher/downloader.rbnu[PKu]+#bundler-2.2.24/lib/bundler/index.rbnu[PKu]PCm*0bundler-2.2.24/lib/bundler/ruby_version.rbnu[PKu]ؤ-""(Vʜbundler-2.2.24/lib/bundler/source_map.rbnu[PKu]0*ќbundler-2.2.24/lib/bundler/rubygems_ext.rbnu[PKu]i *  !bundler-2.2.24/lib/bundler/env.rbnu[PKu]Piy@ @ 1bundler-2.2.24/lib/bundler/resolver/spec_group.rbnu[PKu]B$hHH$ bundler-2.2.24/lib/bundler/mirror.rbnu[PKu]"x(U%bundler-2.2.24/lib/bundler/plugin/dsl.rbnu[PKu]ӃnDD+v,bundler-2.2.24/lib/bundler/plugin/events.rbnu[PKu]6P P (5bundler-2.2.24/lib/bundler/plugin/api.rbnu[PKu] g../@bundler-2.2.24/lib/bundler/plugin/api/source.rbnu[PKu]A7pbundler-2.2.24/lib/bundler/plugin/installer/rubygems.rbnu[PKu]ߛ"Maa2irbundler-2.2.24/lib/bundler/plugin/installer/git.rbnu[PKu]{׳ .,vbundler-2.2.24/lib/bundler/plugin/installer.rbnu[PKu].*bundler-2.2.24/lib/bundler/plugin/index.rbnu[PKu]ΦAA0bundler-2.2.24/lib/bundler/plugin/source_list.rbnu[PKu]wz,,%bundler-2.2.24/lib/bundler/fetcher.rbnu[PKu]•n)ʝbundler-2.2.24/lib/bundler/source_list.rbnu[PKu]wj5,bundler-2.2.24/lib/bundler/build_metadata.rbnu[PKu][51%bundler-2.2.24/lib/bundler/vendored_persistent.rbnu[PKu][  'Hbundler-2.2.24/lib/bundler/ui/silent.rbnu[PKu]K66)bundler-2.2.24/lib/bundler/ui/rg_proxy.rbnu[PKu]Xȷr r &;bundler-2.2.24/lib/bundler/ui/shell.rbnu[PKu]unuu#bundler-2.2.24/lib/bundler/retry.rbnu[PKu]0ee0 bundler-2.2.24/lib/bundler/vendored_fileutils.rbnu[PKu]'* bundler-2.2.24/lib/bundler/feature_flag.rbnu[PKu]O ɧ%bundler-2.2.24/lib/bundler/gemdeps.rbnu[PKu]-L00,bundler-2.2.24/lib/bundler/version_ranges.rbnu[PKu]3,#8&bundler-2.2.24/lib/bundler/graph.rbnu[PKu]YE[h:rdoc-6.2.1.1/exe/rdocnuȯPKu]ֳsp>rdoc-6.2.1.1/exe/rinuȯPKu]u`x`x k?rdoc-6.2.1.1/lib/rdoc/context.rbnu[PKu]FvEErdoc-6.2.1.1/lib/rdoc/rd.rbnu[PKu]533ƞrdoc-6.2.1.1/lib/rdoc/parser.rbnu[PKu]m|`-rdoc-6.2.1.1/lib/rdoc/i18n.rbnu[PKu]H"--"$rdoc-6.2.1.1/lib/rdoc/top_level.rbnu[PKu]󈗢&rdoc-6.2.1.1/lib/rdoc/normal_module.rbnu[PKu]|y%rdoc-6.2.1.1/lib/rdoc/single_class.rbnu[PKu]Ԣ&&#rdoc-6.2.1.1/lib/rdoc/any_method.rbnu[PKu]c7 rdoc-6.2.1.1/lib/rdoc/comment.rbnu[PKu]VU} } &\6rdoc-6.2.1.1/lib/rdoc/known_classes.rbnu[PKu]HLf*q0q0 /Ardoc-6.2.1.1/lib/rdoc/servlet.rbnu[PKu]58$qrdoc-6.2.1.1/lib/rdoc/erb_partial.rbnu[PKu]p-}}srdoc-6.2.1.1/lib/rdoc/alias.rbnu[PKu]epC0$|rdoc-6.2.1.1/lib/rdoc/meta_method.rbnu[PKu]/ t}rdoc-6.2.1.1/lib/rdoc/include.rbnu[PKu]ocp~rdoc-6.2.1.1/lib/rdoc/erbio.rbnu[PKu]&“ drdoc-6.2.1.1/lib/rdoc/require.rbnu[PKu]W,%yrdoc-6.2.1.1/lib/rdoc/normal_class.rbnu[PKu]- % %$Urdoc-6.2.1.1/lib/rdoc/code_object.rbnu[PKu]#SpSprdoc-6.2.1.1/lib/rdoc/markup.rbnu[PKu]ʘw  *V%rdoc-6.2.1.1/lib/rdoc/markup/to_tt_only.rbnu[PKu][nA##(.rdoc-6.2.1.1/lib/rdoc/markup/verbatim.rbnu[PKu]eM/I4rdoc-6.2.1.1/lib/rdoc/markup/to_html_snippet.rbnu[PKu]N_+Jrdoc-6.2.1.1/lib/rdoc/markup/block_quote.rbnu[PKu]tԇ*Krdoc-6.2.1.1/lib/rdoc/markup/blank_line.rbnu[PKu]<88&Mrdoc-6.2.1.1/lib/rdoc/markup/parser.rbnu[PKu]V'rdoc-6.2.1.1/lib/rdoc/markup/to_test.rbnu[PKu]fQ`66'rdoc-6.2.1.1/lib/rdoc/markup/to_ansi.rbnu[PKu]d)rdoc-6.2.1.1/lib/rdoc/markup/paragraph.rbnu[PKu]$$0Trdoc-6.2.1.1/lib/rdoc/markup/to_html_crossref.rbnu[PKu]Q'بrdoc-6.2.1.1/lib/rdoc/markup/to_rdoc.rbnu[PKu]C"=='rdoc-6.2.1.1/lib/rdoc/markup/include.rbnu[PKu]-Ǘ)FŠrdoc-6.2.1.1/lib/rdoc/markup/formatter.rbnu[PKu]|/h۠rdoc-6.2.1.1/lib/rdoc/markup/regexp_handling.rbnu[PKu]ߦo,ޠrdoc-6.2.1.1/lib/rdoc/markup/attr_changer.rbnu[PKu]|""'rdoc-6.2.1.1/lib/rdoc/markup/to_html.rbnu[PKu]FVV(rdoc-6.2.1.1/lib/rdoc/markup/to_label.rbnu[PKu]<)? rdoc-6.2.1.1/lib/rdoc/markup/attr_span.rbnu[PKu]ua1% rdoc-6.2.1.1/lib/rdoc/markup/to_bs.rbnu[PKu]y *trdoc-6.2.1.1/lib/rdoc/markup/hard_break.rbnu[PKu] 7>?4rdoc-6.2.1.1/lib/rdoc/markup/to_table_of_contents.rbnu[PKu]f !r r 1rdoc-6.2.1.1/lib/rdoc/markup/attribute_manager.rbnu[PKu]6WG!G!+z>rdoc-6.2.1.1/lib/rdoc/markup/pre_process.rbnu[PKu]ھ*`rdoc-6.2.1.1/lib/rdoc/markup/attributes.rbnu[PKu]6%Vee3serdoc-6.2.1.1/lib/rdoc/markup/to_joined_paragraph.rbnu[PKu]ԄEE$;jrdoc-6.2.1.1/lib/rdoc/markup/list.rbnu[PKu]fcr)qrdoc-6.2.1.1/lib/rdoc/markup/list_item.rbnu[PKu]Т2yrdoc-6.2.1.1/lib/rdoc/markup/indented_paragraph.rbnu[PKu];;$|rdoc-6.2.1.1/lib/rdoc/markup/rule.rbnu[PKu]M#~rdoc-6.2.1.1/lib/rdoc/markup/raw.rbnu[PKu]p'rdoc-6.2.1.1/lib/rdoc/markup/heading.rbnu[PKu]WY (rdoc-6.2.1.1/lib/rdoc/markup/document.rbnu[PKu] t{ll+rdoc-6.2.1.1/lib/rdoc/markup/to_markdown.rbnu[PKu]Vnrr%rdoc-6.2.1.1/lib/rdoc/ri/formatter.rbnu[PKu] qh!rdoc-6.2.1.1/lib/rdoc/ri/paths.rbnu[PKu]tUU!Ӹrdoc-6.2.1.1/lib/rdoc/ri/store.rbnu[PKu]L!66 yrdoc-6.2.1.1/lib/rdoc/ri/task.rbnu[PKu]yy"rdoc-6.2.1.1/lib/rdoc/ri/driver.rbnu[PKu]y!Qrdoc-6.2.1.1/lib/rdoc/encoding.rbnu[PKu]ardoc-6.2.1.1/lib/rdoc/extend.rbnu[PKu] =MM brdoc-6.2.1.1/lib/rdoc/version.rbnu[PKu]g*%brdoc-6.2.1.1/lib/rdoc/code_objects.rbnu[PKu]bb]]!crdoc-6.2.1.1/lib/rdoc/constant.rbnu[PKu]I#$#$$Irrdoc-6.2.1.1/lib/rdoc/method_attr.rbnu[PKu]OG!!*rdoc-6.2.1.1/lib/rdoc/markdown/entities.rbnu[PKu]LRh$h$*;ordoc-6.2.1.1/lib/rdoc/markdown/literals.rbnu[PKu]FMYYrdoc-6.2.1.1/lib/rdoc/store.rbnu[PKu]]" rdoc-6.2.1.1/lib/rdoc/rd/inline.rbnu[PKu]kXX(rdoc-6.2.1.1/lib/rdoc/rd/block_parser.rbnu[PKu]M<}})Mrdoc-6.2.1.1/lib/rdoc/rd/inline_parser.rbnu[PKu]xˤrdoc-6.2.1.1/lib/rdoc/task.rbnu[PKu]刊--"rdoc-6.2.1.1/lib/rdoc/generator.rbnu[PKu]Ȅ#rdoc-6.2.1.1/lib/rdoc/anon_class.rbnu[PKu]  rdoc-6.2.1.1/lib/rdoc/mixin.rbnu[PKu]s(rdoc-6.2.1.1/lib/rdoc/context/section.rbnu[PKu]e3 %rdoc-6.2.1.1/lib/rdoc/token_stream.rbnu[PKu]vTDODO%rdoc-6.2.1.1/lib/rdoc/class_module.rbnu[PKu]V*6*6Wnrdoc-6.2.1.1/lib/rdoc/rdoc.rbnu[PKu]v}&Τrdoc-6.2.1.1/lib/rdoc/rubygems_hook.rbnu[PKu]ʥ9e rdoc-6.2.1.1/lib/rdoc/tom_doc.rbnu[PKu] [>  ӥrdoc-6.2.1.1/lib/rdoc/attr.rbnu[PKu]KzVf f $1rdoc-6.2.1.1/lib/rdoc/i18n/locale.rbnu[PKu]S2 "rdoc-6.2.1.1/lib/rdoc/i18n/text.rbnu[PKu]>rdoc-6.2.1.1/lib/rdoc/text.rbnu[PKu]at))rdoc-6.2.1.1/lib/rdoc/stats.rbnu[PKu] $@rdoc-6.2.1.1/lib/rdoc/parser/ruby.rbnu[PKu]:ܶ"+rdoc-6.2.1.1/lib/rdoc/parser/rd.rbnu[PKu]Og) -rdoc-6.2.1.1/lib/rdoc/parser/changelog.rbnu[PKu]4QՆ *Ardoc-6.2.1.1/lib/rdoc/parser/ruby_tools.rbnu[PKu]9GG!Krdoc-6.2.1.1/lib/rdoc/parser/c.rbnu[PKu]U&ڧrdoc-6.2.1.1/lib/rdoc/parser/simple.rbnu[PKu]733$rdoc-6.2.1.1/lib/rdoc/parser/text.rbnu[PKu]_A(rdoc-6.2.1.1/lib/rdoc/parser/markdown.rbnu[PKu] />>0Lrdoc-6.2.1.1/lib/rdoc/parser/ripper_state_lex.rbnu[PKu]mh fEE!}#rdoc-6.2.1.1/lib/rdoc/markdown.rbnu[PKu]WnYYrdoc-6.2.1.1/lib/rdoc/ri.rbnu[PKu]+Zq{q{  rdoc-6.2.1.1/lib/rdoc/options.rbnu[PKu]R5%xrdoc-6.2.1.1/lib/rdoc/ghost_method.rbnu[PKu]#@@$]rdoc-6.2.1.1/lib/rdoc/stats/quiet.rbnu[PKu] &rdoc-6.2.1.1/lib/rdoc/stats/verbose.rbnu[PKu]9)-$00%;rdoc-6.2.1.1/lib/rdoc/stats/normal.rbnu[PKu]+<ߐ<<Irdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtmlnu[PKu]JiHurdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtmlnu[PKu] NNNIrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtmlnu[PKu] y=lrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_head.rhtmlnu[PKu]C..=rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/class.rhtmlnu[PKu]3^^?rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_footer.rhtmlnu[PKu]13 3 @굮rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/js/darkfish.jsnu[PKu]  >rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/js/search.jsnu[PKu] [::=̮rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/index.rhtmlnu[PKu]qqGήrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtmlnu[PKu];9Iv?Юrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/css/fonts.cssnu[PKu]V&&>rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/css/rdoc.cssnu[PKu].u  Hrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtmlnu[PKu]޹Krdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtmlnu[PKu]=Irdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtmlnu[PKu]䍒TtTtNrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/fonts/Lato-RegularItalic.ttfnu[PKu]5  Nrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttfnu[PKu]ZooLRrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/fonts/Lato-LightItalic.ttfnu[PKu]՞wwHrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/fonts/Lato-Regular.ttfnu[PKu]׫  Qrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttfnu[PKu]>qqFrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttfnu[PKu]Irdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/table_of_contents.rhtmlnu[PKu]~3FFF!rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtmlnu[PKu]̸QQJrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtmlnu[PKu]*fGrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtmlnu[PKu]-R"rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtmlnu[PKu]A-I %rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtmlnu[PKu]HE&rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtmlnu[PKu]` e<S(rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/page.rhtmlnu[PKu])oHHJH<rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/wrench_orange.pngnu[PKu](VVL ?rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/page_white_text.pngnu[PKu]R7G@rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/brick_link.pngnu[PKu]#۸PPAODrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/ruby.pngnu[PKu]=kOGrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.pngnu[PKu]QM`Hrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gifnu[PKu]S@_rdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/bug.pngnu[PKu]7 AQcrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/zoom.pngnu[PKu]CCJUUDvfrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/package.pngnu[PKu]ErrA?jrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/date.pngnu[PKu]"55M"mrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/page_white_width.pngnu[PKu]bbCnrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/wrench.pngnu[PKu]PCqrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/delete.pngnu[PKu]Os~@trdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/add.pngnu[PKu]=VP4xrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.pngnu[PKu]AaaHyrdoc-6.2.1.1/lib/rdoc/generator/template/darkfish/images/transparent.pngnu[PKu]==d&rack-3.0.8/lib/rack/lock.rbnu[PKu]/{{#(rack-3.0.8/lib/rack/mock_request.rbnu[PKu]gG!>rack-3.0.8/lib/rack/media_type.rbnu[PKu]*Drack-3.0.8/lib/rack/auth/digest/request.rbnu[PKu]&Erack-3.0.8/lib/rack/auth/digest/md5.rbnu[PKu](Erack-3.0.8/lib/rack/auth/digest/nonce.rbnu[PKu])Frack-3.0.8/lib/rack/auth/digest/params.rbnu[PKu],UU,yFrack-3.0.8/lib/rack/auth/abstract/request.rbnu[PKu]lGRR,*Jrack-3.0.8/lib/rack/auth/abstract/handler.rbnu[PKu]!Mrack-3.0.8/lib/rack/auth/basic.rbnu[PKu]  "Rrack-3.0.8/lib/rack/auth/digest.rbnu[PKu]>Sf?"?"6krack-3.0.8/lib/rack/builder.rbnu[PKu]O~ Írack-3.0.8/lib/rack/recursive.rbnu[PKu]ӎ cTcT1rack-3.0.8/lib/rack/utils.rbnu[PKu]&44'rack-3.0.8/lib/rack/multipart/parser.rbnu[PKu]l *rack-3.0.8/lib/rack/multipart/generator.rbnu[PKu]N$$. )rack-3.0.8/lib/rack/multipart/uploaded_file.rbnu[PKu] Cx x $.rack-3.0.8/lib/rack/common_logger.rbnu[PKu]YYd  &n;rack-3.0.8/lib/rack/tempfile_reaper.rbnu[PKu]Kbx  >rack-3.0.8/lib/rack/reloader.rbnu[PKu]&{!{!#4Krack-3.0.8/lib/rack/query_parser.rbnu[PKu]U``" mrack-3.0.8/lib/rack/multipart.rbnu[PKu]|Хqrack-3.0.8/lib/rack/files.rbnu[PKu]44툼rack-3.0.8/lib/rack/events.rbnu[PKu]A nrack-3.0.8/lib/rack/directory.rbnu[PKu]iZ&&%ִrack-3.0.8/lib/rack/content_length.rbnu[PKu]ɸHOQrack-3.0.8/lib/rack/version.rbnu[PKu]R  $]rack-3.0.8/lib/rack/mock_response.rbnu[PKu]Y488ɼrack-3.0.8/lib/rack/sendfile.rbnu[PKu]dPSrack-3.0.8/lib/rack/logger.rbnu[PKu]M}Y??>rack-3.0.8/lib/rack/mock.rbnu[PKu]K?33!rack-3.0.8/lib/rack/body_proxy.rbnu[PKu]ю Lrack-3.0.8/lib/rack/static.rbnu[PKu]VMVwwrack-3.0.8/lib/rack/etag.rbnu[PKu];~ ~ 'Zrack-3.0.8/lib/rack/rewindable_input.rbnu[PKu]$**/rack-3.0.8/lib/rack/response.rbnu[PKu]3&c@rack-3.0.8/lib/rack/method_override.rbnu[PKu]@j Frack-3.0.8/lib/rack/constants.rbnu[PKu]Oi Prack-3.0.8/lib/rack/headers.rbnu[PKu]ѝo  \rack-3.0.8/lib/rack/head.rbnu[PKu]՝[[/_rack-3.0.8/lib/rack/lint.rbnuȯPKu]|| &rack-3.0.8/lib/rack/conditional_get.rbnu[PKu]N4q# rack-3.0.8/lib/rack/content_type.rbnu[PKu]dNN"*rack-3.0.8/lib/rack/show_status.rbnu[PKu]?6/ rack-3.0.8/lib/rack/mime.rbnu[PKu]i\֐rack-3.0.8/lib/rack/config.rbnu[PKu]Y  rack-3.0.8/lib/rack/cascade.rbnu[PKu]_l" rack-3.0.8/lib/rack/null_logger.rbnu[PKu]*ruby-lsapi-5.5/ext/lsapi/.sitearchdir.timenu[PKu]Y//#uruby-lsapi-5.5/ext/lsapi/lsapilib.hnu[PKu]7Zw#Ѿruby-lsapi-5.5/ext/lsapi/extconf.rbnu[PKu].ZZ!Ӿruby-lsapi-5.5/ext/lsapi/lsruby.cnu[PKu]W q,,#.ruby-lsapi-5.5/ext/lsapi/lsapidef.hnu[PKu]((#@ruby-lsapi-5.5/ext/lsapi/lsapilib.onu[PKu]]z.##!iruby-lsapi-5.5/ext/lsapi/Makefilenu[PKu] 3O8aa#ٍruby-lsapi-5.5/ext/lsapi/lsapilib.cnu[PKu]Mr33!_ruby-lsapi-5.5/ext/lsapi/lsapi.sonuȯPKu].c|!ruby-lsapi-5.5/ext/lsapi/lsruby.onu[PKu]lΉoruby-lsapi-5.5/lsapi.gemspecnu[PKu]^wͱrruby-lsapi-5.5/READMEnu[PKu]j2#ruby-lsapi-5.5/rails/dispatch.lsapinuȯPKu]MM'-ruby-lsapi-5.5/scripts/lsruby_runner.rbnuȯPKu]##BBяruby-lsapi-5.5/setup.rbnu[PKu]*  $Zruby-lsapi-5.5/examples/testlsapi.rbnuȯPKu])ruby-lsapi-5.5/examples/lsapi_with_cgi.rbnuȯPKu] minitest-5.13.0/Manifest.txtnu[PKu]S`"minitest-5.13.0/Rakefilenu[PKu]9(  8+minitest-5.13.0/test/minitest/test_minitest_benchmark.rbnu[PKu]+ɃɃ98minitest-5.13.0/test/minitest/test_minitest_assertions.rbnu[PKu]`#*ii7,minitest-5.13.0/test/minitest/test_minitest_reporter.rbnu[PKu]m1i\i\3minitest-5.13.0/test/minitest/test_minitest_test.rbnu[PKu]lJlJ3/minitest-5.13.0/test/minitest/test_minitest_mock.rbnu[PKu]O -zminitest-5.13.0/test/minitest/metametameta.rbnu[PKu]8*k*k3DŽminitest-5.13.0/test/minitest/test_minitest_spec.rbnu[PKu]ފ`o`oTminitest-5.13.0/README.rdocnu[PKu].`.`_minitest-5.13.0/lib/minitest.rbnu[PKu]lrR^CC%|minitest-5.13.0/lib/minitest/pride.rbnu[PKu]*UU*minitest-5.13.0/lib/minitest/assertions.rbnu[PKu]+**$minitest-5.13.0/lib/minitest/test.rbnu[PKu] 00)u-minitest-5.13.0/lib/minitest/benchmark.rbnu[PKu]y$]minitest-5.13.0/lib/minitest/unit.rbnu[PKu]/w[NN$*cminitest-5.13.0/lib/minitest/mock.rbnu[PKu]_cGG(~minitest-5.13.0/lib/minitest/parallel.rbnu[PKu]oz$kminitest-5.13.0/lib/minitest/hell.rbnu[PKu]9M M ,minitest-5.13.0/lib/minitest/pride_plugin.rbnu[PKu]T,3minitest-5.13.0/lib/minitest/expectations.rbnu[PKu]I'minitest-5.13.0/lib/minitest/autorun.rbnu[PKu]^ѿ##$Dminitest-5.13.0/lib/minitest/spec.rbnu[PKu]Lj)p#bminitest-5.13.0/lib/hoe/minitest.rbnu[PKu]\Xminitest-5.13.0/History.rdocnu[PKu]5~~#|minitest-5.13.0/design_rationale.rbnu[PKu]:n&5&5test-unit-3.3.4/PSFLnu[PKu]FNFFtest-unit-3.3.4/GPLnu[PKu]~""test-unit-3.3.4/Rakefilenu[PKu]s  (S test-unit-3.3.4/test/util/test-output.rbnu[PKu]cʪ1 test-unit-3.3.4/test/util/test_backtracefilter.rbnu[PKu]`+O,test-unit-3.3.4/test/util/test_observable.rbnu[PKu]-#test-unit-3.3.4/test/util/test_procwrapper.rbnu[PKu]^&15 )test-unit-3.3.4/test/util/test-method-owner-finder.rbnu[PKu]z}J J (-test-unit-3.3.4/test/test-test-result.rbnu[PKu]( DD(9:test-unit-3.3.4/test/fixtures/header.tsvnu[PKu]DD(:test-unit-3.3.4/test/fixtures/header.csvnu[PKu]cm..+q;test-unit-3.3.4/test/fixtures/no-header.csvnu[PKu]? "..+;test-unit-3.3.4/test/fixtures/no-header.tsvnu[PKu]_CC.<test-unit-3.3.4/test/fixtures/header-label.csvnu[PKu]*CC.$=test-unit-3.3.4/test/fixtures/header-label.tsvnu[PKu]:bOO&=test-unit-3.3.4/test/fixtures/plus.csvnu[PKu]D)j>test-unit-3.3.4/test/test-notification.rbnu[PKu]\҃P  %Atest-unit-3.3.4/test/test-priority.rbnu[PKu]52"9Qtest-unit-3.3.4/test/test-error.rbnu[PKu]H)Ttest-unit-3.3.4/test/test-emacs-runner.rbnu[PKu] &[[test-unit-3.3.4/test/test-attribute.rbnu[PKu]d$Xgtest-unit-3.3.4/test/test-pending.rbnu[PKu]ad  /otest-unit-3.3.4/test/test-test-suite-creator.rbnu[PKu]sEv v )xtest-unit-3.3.4/test/test-color-scheme.rbnu[PKu]7C1test-unit-3.3.4/test/collector/test-descendant.rbnu[PKu]a66+test-unit-3.3.4/test/collector/test-load.rbnu[PKu])***test-unit-3.3.4/test/collector/test_dir.rbnu[PKu]2\ 2!test-unit-3.3.4/test/collector/test_objectspace.rbnu[PKu]ӪU'btest-unit-3.3.4/test/test-test-suite.rbnu[PKu]U_m77$otest-unit-3.3.4/test/test-failure.rbnu[PKu]+4\4test-unit-3.3.4/test/test-fault-location-detector.rbnu[PKu]G-44!*test-unit-3.3.4/test/test-data.rbnu[PKu]J  )!_test-unit-3.3.4/test/test-code-snippet.rbnu[PKu]w22"ftest-unit-3.3.4/test/test-color.rbnu[PKu]20~,*mtest-unit-3.3.4/test/testunit-test-util.rbnu[PKu]:QQ&otest-unit-3.3.4/test/test-test-case.rbnu[PKu])N'test-unit-3.3.4/test/test-assertions.rbnu[PKu]kVV$test-unit-3.3.4/test/test-fixture.rbnu[PKu]?"= = %Otest-unit-3.3.4/test/test-omission.rbnu[PKu]q$G;H;H!Ytest-unit-3.3.4/test/test-diff.rbnu[PKu]X_.test-unit-3.3.4/test/test-attribute-matcher.rbnu[PKu]Fill test-unit-3.3.4/test/run-test.rbnu[PKu]7w00/Jtest-unit-3.3.4/test/ui/test_testrunmediator.rbnu[PKu]f*k ٪test-unit-3.3.4/README.mdnu[PKu]>X"Vggtest-unit-3.3.4/LGPLnu[PKu]vm test-unit-3.3.4/COPYINGnu[PKu]oc$(test-unit-3.3.4/sample/test_adder.rbnu[PKu]c: v*test-unit-3.3.4/sample/adder.rbnu[PKu]d@)+test-unit-3.3.4/sample/test_subtracter.rbnu[PKu]/jj#-test-unit-3.3.4/sample/test_user.rbnu[PKu]Z$/test-unit-3.3.4/sample/subtracter.rbnu[PKu]$yӱ"0test-unit-3.3.4/doc/text/how-to.mdnu[PKu]@J? 9test-unit-3.3.4/doc/text/news.mdnu[PKu]p+9test-unit-3.3.4/doc/text/getting-started.mdnu[PKu]w5xtest-unit-3.3.4/lib/test/unit/code-snippet-fetcher.rbnu[PKu]C9 9 0test-unit-3.3.4/lib/test/unit/util/observable.rbnu[PKu]̭,Ttest-unit-3.3.4/lib/test/unit/util/output.rbnu[PKu]S<9test-unit-3.3.4/lib/test/unit/util/method-owner-finder.rbnu[PKu]>\MM1test-unit-3.3.4/lib/test/unit/util/procwrapper.rbnu[PKu]005test-unit-3.3.4/lib/test/unit/util/backtracefilter.rbnu[PKu]9'ee%+test-unit-3.3.4/lib/test/unit/diff.rbnu[PKu]*6r &3gtest-unit-3.3.4/lib/test/unit/color.rbnu[PKu]U<l *Wstest-unit-3.3.4/lib/test/unit/data-sets.rbnu[PKu]q((+test-unit-3.3.4/lib/test/unit/assertions.rbnu[PKu] +test-unit-3.3.4/lib/test/unit/testresult.rbnu[PKu]Uį( test-unit-3.3.4/lib/test/unit/pending.rbnu[PKu]Dddd)test-unit-3.3.4/lib/test/unit/omission.rbnu[PKu]soo&test-unit-3.3.4/lib/test/unit/error.rbnu[PKu] /44*xtest-unit-3.3.4/lib/test/unit/testsuite.rbnu[PKu]*test-unit-3.3.4/lib/test/unit/attribute.rbnu[PKu] ,E)test-unit-3.3.4/lib/test/unit/priority.rbnu[PKu]R!\c\c)(test-unit-3.3.4/lib/test/unit/testcase.rbnu[PKu]7Utest-unit-3.3.4/lib/test/unit/assertion-failed-error.rbnu[PKu]\c3x x -test-unit-3.3.4/lib/test/unit/notification.rbnu[PKu](::(}test-unit-3.3.4/lib/test/unit/version.rbnu[PKu]FJ:AA+test-unit-3.3.4/lib/test/unit/autorunner.rbnu[PKu]n$$(Otest-unit-3.3.4/lib/test/unit/fixture.rbnu[PKu]l /test-unit-3.3.4/lib/test/unit/runner/console.rbnu[PKu]qo+test-unit-3.3.4/lib/test/unit/runner/xml.rbnu[PKu]l-test-unit-3.3.4/lib/test/unit/runner/emacs.rbnu[PKu] /gtest-unit-3.3.4/lib/test/unit/collector/load.rbnu[PKu]Q$ .~test-unit-3.3.4/lib/test/unit/collector/dir.rbnu[PKu]>6test-unit-3.3.4/lib/test/unit/collector/objectspace.rbnu[PKu]], 8test-unit-3.3.4/lib/test/unit/fault-location-detector.rbnu[PKu]j V 2ؚtest-unit-3.3.4/lib/test/unit/exception-handler.rbnu[PKu]"zz-test-unit-3.3.4/lib/test/unit/color-scheme.rbnu[PKu]= = 3test-unit-3.3.4/lib/test/unit/test-suite-creator.rbnu[PKu]H~XX(ztest-unit-3.3.4/lib/test/unit/failure.rbnu[PKu]xZZ4*test-unit-3.3.4/lib/test/unit/ui/emacs/testrunner.rbnu[PKu]u$$7test-unit-3.3.4/lib/test/unit/ui/testrunnerutilities.rbnu[PKu]d2stest-unit-3.3.4/lib/test/unit/ui/xml/testrunner.rbnu[PKu]l~7 test-unit-3.3.4/lib/test/unit/ui/console/outputlevel.rbnu[PKu]!=(__6) test-unit-3.3.4/lib/test/unit/ui/console/testrunner.rbnu[PKu]޸.jltest-unit-3.3.4/lib/test/unit/ui/testrunner.rbnu[PKu]N N 6mqtest-unit-3.3.4/lib/test/unit/ui/testrunnermediator.rbnu[PKu]KE::*!test-unit-3.3.4/lib/test/unit/collector.rbnu[PKu]Vݯ2test-unit-3.3.4/lib/test/unit/attribute-matcher.rbnu[PKu]-K@K@ ƈtest-unit-3.3.4/lib/test/unit.rbnu[PKu] O atest-unit-3.3.4/lib/test-unit.rbnu[PKu]`json-2.3.0/lib/json.rbnu[PKu]oaa%json-2.3.0/lib/json/add/bigdecimal.rbnu[PKu]&a\\mjson-2.3.0/lib/json/add/core.rbnu[PKu]@9%!json-2.3.0/lib/json/add/regexp.rbnu[PKu]ff!ljson-2.3.0/lib/json/add/symbol.rbnu[PKu]m"#json-2.3.0/lib/json/add/ostruct.rbnu[PKu]V#json-2.3.0/lib/json/add/rational.rbnu[PKu]&"json-2.3.0/lib/json/add/complex.rbnu[PKu]k$Fjson-2.3.0/lib/json/add/exception.rbnu[PKu]!!json-2.3.0/lib/json/add/set.rbnu[PKu]J(json-2.3.0/lib/json/add/time.rbnu[PKu]mqqojson-2.3.0/lib/json/add/date.rbnu[PKu]1+Ǔ00$/json-2.3.0/lib/json/add/date_time.rbnu[PKu]a json-2.3.0/lib/json/add/range.rbnu[PKu]%!json-2.3.0/lib/json/add/struct.rbnu[PKu]Ht..xjson-2.3.0/lib/json/version.rbnu[PKu];;json-2.3.0/lib/json/common.rbnu[PKu]1z=Bjson-2.3.0/lib/json/ext.rbnu[PKu]E”%Djson-2.3.0/lib/json/generic_object.rbnu[PKu]%BqqIpower_assert-1.1.7/LEGALnu[PKu]VJpower_assert-1.1.7/Gemfilenu[PKu]XKpower_assert-1.1.7/Rakefilenu[PKu]*D3Qpower_assert-1.1.7/BSDLnu[PKu]|m# # _Vpower_assert-1.1.7/README.rdocnu[PKu] b `power_assert-1.1.7/COPYINGnu[PKu]mޮ 'jpower_assert-1.1.7/power_assert.gemspecnu[PKu]t/;JJtpower_assert-1.1.7/bin/setupnu[PKu]9\Vupower_assert-1.1.7/bin/consolenu[PKu]»1.6vpower_assert-1.1.7/lib/power_assert/context.rbnu[PKu]g^-<power_assert-1.1.7/lib/power_assert/parser.rbnu[PKu]S/++.power_assert-1.1.7/lib/power_assert/version.rbnu[PKu]!/ power_assert-1.1.7/lib/power_assert/colorize.rbnu[PKu]{%}}WW4,power_assert-1.1.7/lib/power_assert/configuration.rbnu[PKu]^-  ?power_assert-1.1.7/lib/power_assert/enable_tracepoint_events.rbnu[PKu]G0[power_assert-1.1.7/lib/power_assert/inspector.rbnu[PKu]O3e: &power_assert-1.1.7/lib/power_assert.rbnu[PKu] xmlrpc-0.3.0/LICENSE.txtnu[PKu]K''xmlrpc-0.3.0/Gemfilenu[PKu]Y xmlrpc-0.3.0/xmlrpc.gemspecnu[PKu]\Wxmlrpc-0.3.0/Rakefilenu[PKu]ixmlrpc-0.3.0/README.mdnu[PKu]xmlrpc-0.3.0/bin/setupnu[PKu]N=KKxmlrpc-0.3.0/bin/consolenu[PKu]XExmlrpc-0.3.0/lib/xmlrpc.rbnu[PKu]Gea a #xmlrpc-0.3.0/lib/xmlrpc/datetime.rbnu[PKu]-KKKK!:"xmlrpc-0.3.0/lib/xmlrpc/client.rbnu[PKu]z[W(O(O!mxmlrpc-0.3.0/lib/xmlrpc/server.rbnu[PKu] T==!Oxmlrpc-0.3.0/lib/xmlrpc/parser.rbnu[PKu]HB mxmlrpc-0.3.0/lib/xmlrpc/utils.rbnu[PKu]*#!Y xmlrpc-0.3.0/lib/xmlrpc/create.rbnu[PKu]N W"%xmlrpc-0.3.0/lib/xmlrpc/marshal.rbnu[PKu]T!+xmlrpc-0.3.0/lib/xmlrpc/base64.rbnu[PKu]799!1xmlrpc-0.3.0/lib/xmlrpc/config.rbnu[PKu],'#5bigdecimal-2.0.0/lib/bigdecimal/math.rbnu[PKu]; <]]+Lbigdecimal-2.0.0/lib/bigdecimal/jacobian.rbnu[PKu]ь)Tbigdecimal-2.0.0/lib/bigdecimal/ludcmp.rbnu[PKu]h"AZZ)]bigdecimal-2.0.0/lib/bigdecimal/newton.rbnu[PKu]< 'Xebigdecimal-2.0.0/lib/bigdecimal/util.rbnu[PKu]Weqrake-13.0.1/MIT-LICENSEnu[PKu]/Iurake-13.0.1/Gemfilenu[PKu]Ivrake-13.0.1/exe/rakenuȯPKu]VQOm{rake-13.0.1/Rakefilenu[PKu]ovrake-13.0.1/README.rdocnu[PKu]vrake-13.0.1/rake.gemspecnu[PKu]?qFF'rake-13.0.1/doc/command_line_usage.rdocnu[PKu]@u,u,Jrake-13.0.1/doc/jamis.rbnu[PKu]Oq AArake-13.0.1/doc/example/a.cnu[PKu]۸ !rake-13.0.1/doc/example/Rakefile1nu[PKu]AArake-13.0.1/doc/example/b.cnu[PKu]";WW!rake-13.0.1/doc/example/Rakefile2nu[PKu]_bggrake-13.0.1/doc/example/main.cnu[PKu]PPkrake-13.0.1/doc/rakefile.rdocnu[PKu]) @rake-13.0.1/doc/proto_rake.rdocnu[PKu]v3HHJrake-13.0.1/doc/rational.rdocnu[PKu]'S{Ecrake-13.0.1/doc/glossary.rdocnu[PKu]Xjrake-13.0.1/bin/rdocnu[PKu]Ymrake-13.0.1/bin/rakenu[PKu]|u%4qrake-13.0.1/bin/rubocopnu[PKu]t/;JJtrake-13.0.1/bin/setupnu[PKu]r WUU&urake-13.0.1/bin/consolenu[PKu]>h  urake-13.0.1/bin/bundlenu[PKu]R  #!rake-13.0.1/lib/rake/linked_list.rbnu[PKu]2bb(rake-13.0.1/lib/rake/loaders/makefile.rbnu[PKu]u Brake-13.0.1/lib/rake/ext/core.rbnu[PKu]yOurr".rake-13.0.1/lib/rake/ext/string.rbnu[PKu].*C}}rake-13.0.1/lib/rake/phony.rbnu[PKu]?{Hrr"rake-13.0.1/lib/rake/early_time.rbnu[PKu]n#+rake-13.0.1/lib/rake/task_argument_error.rbnu[PKu]QGprake-13.0.1/lib/rake/clean.rbnu[PKu]d11!ڹrake-13.0.1/lib/rake/file_list.rbnu[PKu]F- &rake-13.0.1/lib/rake/dsl_definition.rbnu[PKu]!>rake-13.0.1/lib/rake/cloneable.rbnu[PKu];YII"Orake-13.0.1/lib/rake/file_utils.rbnu[PKu]rake-13.0.1/lib/rake/scope.rbnu[PKu]sZZ&rake-13.0.1/lib/rake/file_utils_ext.rbnu[PKu])lq(#i'rake-13.0.1/lib/rake/packagetask.rbnu[PKu]4Tc#?rake-13.0.1/lib/rake/thread_pool.rbnu[PKu]n Rrake-13.0.1/lib/rake/version.rbnu[PKu]^  Srake-13.0.1/lib/rake/promise.rbnu[PKu]YY"\]rake-13.0.1/lib/rake/multi_task.rbnu[PKu]j_rake-13.0.1/lib/rake/win32.rbnu[PKu]Ӭs~~5derake-13.0.1/lib/rake/rule_recursion_overflow_error.rbnu[PKu]0ZR&Ggrake-13.0.1/lib/rake/private_reader.rbnu[PKu]2'irake-13.0.1/lib/rake/invocation_exception_mixin.rbnu[PKu]R22Vkrake-13.0.1/lib/rake/task.rbnu[PKu]i  &rake-13.0.1/lib/rake/default_loader.rbnu[PKu]l??$rake-13.0.1/lib/rake/trace_output.rbnu[PKu]I!rake-13.0.1/lib/rake/file_task.rbnu[PKu]p,۞ ۨrake-13.0.1/lib/rake/testtask.rbnu[PKu]lD")rake-13.0.1/lib/rake/name_space.rbnu[PKu]m.9rake-13.0.1/lib/rake/thread_history_display.rbnu[PKu]Jሀ!rake-13.0.1/lib/rake/backtrace.rbnu[PKu]H bb#rake-13.0.1/lib/rake/application.rbnu[PKu]Q#Z/rake-13.0.1/lib/rake/rake_module.rbnu[PKu]-x= ( ($5rake-13.0.1/lib/rake/task_manager.rbnu[PKu]~y &^rake-13.0.1/lib/rake/task_arguments.rbnu[PKu]K%grake-13.0.1/lib/rake/pseudo_status.rbnu[PKu]M M #irake-13.0.1/lib/rake/cpu_counter.rbnu[PKu]''!srake-13.0.1/lib/rake/late_time.rbnu[PKu](urake-13.0.1/lib/rake/rake_test_loader.rbnu[PKu]K\(Rwrake-13.0.1/lib/rake/invocation_chain.rbnu[PKu]E.h|rake-13.0.1/lib/rake/tasklib.rbnu[PKu]l*\}rake-13.0.1/lib/rake/file_creation_task.rbnu[PKu]Q=rrqrake-13.0.1/lib/rake.rbnu[PKu]A u*rake-13.0.1/History.rdocnu[PKu]U&rake-13.0.1/CONTRIBUTING.rdocnu[PKu]mǯ racc-1.4.16/bin/raccnuȯPKu]*1ruby-lsapi-5.6/ext/lsapi/.sitearchdir.timenu[PKu]Y//#ruby-lsapi-5.6/ext/lsapi/lsapilib.hnu[PKu]7Zw#ruby-lsapi-5.6/ext/lsapi/extconf.rbnu[PKu]dCR[R[!*ruby-lsapi-5.6/ext/lsapi/lsruby.cnu[PKu]W q,,#Truby-lsapi-5.6/ext/lsapi/lsapidef.hnu[PKu]ւg/((#Lgruby-lsapi-5.6/ext/lsapi/lsapilib.onu[PKu]k##!ruby-lsapi-5.6/ext/lsapi/Makefilenu[PKu] 3O8aa#ruby-lsapi-5.6/ext/lsapi/lsapilib.cnu[PKu]33!Hruby-lsapi-5.6/ext/lsapi/lsapi.sonuȯPKu]gy!Yruby-lsapi-5.6/ext/lsapi/lsruby.onu[PKu]whf:ruby-lsapi-5.6/lsapi.gemspecnu[PKu]^wͱruby-lsapi-5.6/READMEnu[PKu]j2#}ruby-lsapi-5.6/rails/dispatch.lsapinuȯPKu]MM'ȱruby-lsapi-5.6/scripts/lsruby_runner.rbnuȯPKu]##BBlruby-lsapi-5.6/setup.rbnu[PKu]*  $Cruby-lsapi-5.6/examples/testlsapi.rbnuȯPKu])TEruby-lsapi-5.6/examples/lsapi_with_cgi.rbnuȯPKu]L'Fio-console-0.5.6/lib/io/console/size.rbnu[PKu]B^Hopenssl-2.1.4/lib/openssl/bn.rbnu[PKu]w+D#Kopenssl-2.1.4/lib/openssl/cipher.rbnu[PKu]̒O?? Ropenssl-2.1.4/lib/openssl/ssl.rbnu[PKu]S:_CC!openssl-2.1.4/lib/openssl/x509.rbnu[PKu]I1!openssl-2.1.4/lib/openssl/pkey.rbnu[PKu]Mff"openssl-2.1.4/lib/openssl/pkcs5.rbnu[PKu]d Ҽ&&&Hopenssl-2.1.4/lib/openssl/buffering.rbnu[PKu]ӡv85252#Zopenssl-2.1.4/lib/openssl/config.rbnu[PKu]# openssl-2.1.4/lib/openssl/digest.rbnu[PKu]>)openssl-2.1.4/lib/openssl.rbnu[PKu] 0net-telnet-0.2.0/LICENSE.txtnu[PKu]V__Dnet-telnet-0.2.0/Gemfilenu[PKu]Znn#net-telnet-0.2.0/net-telnet.gemspecnu[PKu]77$net-telnet-0.2.0/Rakefilenu[PKu]ɷ׽F F %net-telnet-0.2.0/README.mdnu[PKu]Gss-/net-telnet-0.2.0/bin/setupnu[PKu]V?OO/net-telnet-0.2.0/bin/consolenu[PKu]]8HH"1net-telnet-0.2.0/lib/net/telnet.rbnu[PKu]>7C::*net-telnet-0.2.0/lib/net/telnet/version.rbnu[PKu][J¼"net-telnet-0.2.0/lib/net-telnet.rbnu[PKu]$(QTTpsych-3.1.0/lib/psych.rbnu[PKu]H'8psych-3.1.0/lib/psych/scalar_scanner.rbnu[PKu]KKpsych-3.1.0/lib/psych/omap.rbnu[PKu] [psych-3.1.0/lib/psych/parser.rbnu[PKu]`[ psych-3.1.0/lib/psych/handler.rbnu[PKu] %<psych-3.1.0/lib/psych/tree_builder.rbnu[PKu]" Ipsych-3.1.0/lib/psych/exception.rbnu[PKu]*JJfJpsych-3.1.0/lib/psych/set.rbnu[PKu]PKK+Jpsych-3.1.0/lib/psych/visitors/json_tree.rbnu[PKu]R(rr-Mpsych-3.1.0/lib/psych/visitors/depth_first.rbnu[PKu]#<#<+qPpsych-3.1.0/lib/psych/visitors/yaml_tree.rbnu[PKu]6*4gg)psych-3.1.0/lib/psych/visitors/visitor.rbnu[PKu]Sܶ..)psych-3.1.0/lib/psych/visitors/to_ruby.rbnu[PKu]Z)psych-3.1.0/lib/psych/visitors/emitter.rbnu[PKu]fk k psych-3.1.0/lib/psych/nodes.rbnu[PKu]'Kpsych-3.1.0/lib/psych/y.rbnu[PKu]%!psych-3.1.0/lib/psych/versions.rbnu[PKu]rpsych-3.1.0/lib/psych/stream.rbnu[PKu]&3*II%psych-3.1.0/lib/psych/syntax_error.rbnu[PKu]y2K"Ypsych-3.1.0/lib/psych/streaming.rbnu[PKu]ӻ!Fpsych-3.1.0/lib/psych/visitors.rbnu[PKu]oe %psych-3.1.0/lib/psych/class_loader.rbnu[PKu]|uu*{psych-3.1.0/lib/psych/handlers/recorder.rbnu[PKu]}1Jpsych-3.1.0/lib/psych/handlers/document_stream.rbnu[PKu](Cee*psych-3.1.0/lib/psych/json/tree_builder.rbnu[PKu]  )ppsych-3.1.0/lib/psych/json/yaml_events.rbnu[PKu] Ej$psych-3.1.0/lib/psych/json/stream.rbnu[PKu])psych-3.1.0/lib/psych/json/ruby_events.rbnu[PKu]u>22psych-3.1.0/lib/psych/coder.rbnu[PKu]"+  #psych-3.1.0/lib/psych/nodes/node.rbnu[PKu]믍!!'psych-3.1.0/lib/psych/nodes/sequence.rbnu[PKu]ɉ  $W psych-3.1.0/lib/psych/nodes/alias.rbnu[PKu])))& psych-3.1.0/lib/psych/nodes/mapping.rbnu[PKu]Ϧ[%5psych-3.1.0/lib/psych/nodes/stream.rbnu[PKu](%%psych-3.1.0/lib/psych/nodes/scalar.rbnu[PKu]AA'cpsych-3.1.0/lib/psych/nodes/document.rbnu[PKu]Rzgg!%psych-3.1.0/lib/psych/core_ext.rbnu[PK<'