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

HOME


Mini Shell 1.0
DIR:/proc/self/root/opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/heapy/
Upload File :
Current File : //proc/self/root/opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/heapy/Remote.py
"""
    Support remote access to a Python interpreter.
"""

from guppy.etc import cmd
from guppy import hpy
from guppy.heapy import heapyc, Target
from guppy.heapy.RemoteConstants import *
from guppy.heapy.Console import Console
from guppy.sets import mutbitset

import atexit
import io
import queue
import select
import socket
import sys
import time
import _thread
import threading
import traceback


class SocketClosed(Exception):
    pass


class IsolatedCaller:
    # Isolates the target interpreter from us
    # when the _hiding_tag_ is set to the _hiding_tag_ of our hp.
    # A solution of a problem discussed in notes Nov 8-9 2005.
    # Note feb 3 2006: The class in the Target instance must be used.

    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwds):
        return self.func(*args, **kwds)


class QueueWithReadline(queue.Queue):
    def readline(self, size=-1):
        # Make sure we are interruptible
        # in case we get a keyboard interrupt.
        # Not a very elegant way but the 'only' there is?
        while 1:
            try:
                return self.get(timeout=0.5)
            except queue.Empty:
                continue


class InterruptableSocket:
    def __init__(self, backing):
        self._backing = backing
        self.fileno = self._backing.fileno
        self.close = self._backing.close
        self.readable = self._backing.readable
        self.writable = self._backing.writable
        self.seekable = self._backing.seekable

    @property
    def closed(self):
        return self._backing.closed

    def read(self, size=-1):
        while not select.select([self], [], [], 0.5)[0]:
            pass

        return self._backing.read(size)


class NotiInput:
    def __init__(self, input, output):
        self.input = input
        self.output = output

    def read(self, size=-1):
        # This may return less data than what was requested
        return self.readline(size)

    def readline(self, size=-1):
        self.output.write(READLINE)
        return self.input.readline(size)


class Annex(cmd.Cmd):
    address_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM
    use_rawinput = 0
    prompt = '<Annex> '

    def __init__(self, target, port=None):
        cmd.Cmd.__init__(self)
        if port is None:
            port = HEAPYPORT
        self.server_address = (LOCALHOST, port)
        self.target = target
        target.close = target.sys.modules['guppy.heapy.Remote'].IsolatedCaller(
        # target.close = IsolatedCaller(
            self.asynch_close)
        self.socket = None
        self.isclosed = 0
        self.closelock = _thread.allocate_lock()

        self.intlocals = {
        }
        self.do_reset('')

    def asynch_close(self):
        # This may be called asynchronously
        # by some other thread than the current (annex) thread.
        # So I need to protect for a possible race condition.
        # It is NOT enough with just an atomic test-and-set here
        # since we need to wait during the time a close initiated
        # from another thread is in progress, before exiting.

        self.closelock.acquire()

        try:
            if not self.isclosed:
                self.isclosed = 1
                self.disconnect()
        finally:
            self.closelock.release()

        while hasattr(self, 'th') and self.th.is_alive():
            time.sleep(0.5)

    def connect(self):
        self.socket = socket.socket(self.address_family,
                                    self.socket_type)
        while not self.isclosed:
            try:
                self.socket.connect(self.server_address)
            except SystemExit:
                raise
            except socket.error:
                if self.isclosed:
                    raise
                time.sleep(2)
            else:
                break
        else:
            return

        self.stdout = io.TextIOWrapper(
            self.socket.makefile('wb', buffering=0),
            encoding='utf-8', write_through=True)
        self.stdin = NotiInput(io.TextIOWrapper(
            InterruptableSocket(self.socket.makefile('rb', buffering=0)),
            encoding='utf-8', write_through=True), self.stdout)
        self.stderr = sys.stderr

        self.start_ki_thread()

        cmd.Cmd.__init__(self, stdin=self.stdin, stdout=self.stdout)

    def start_ki_thread(self):
        # Start a thread that can generates keyboard interrupr
        # Inserts a spy thread between old stdin and a new stdin

        queue = QueueWithReadline()
        ostdin = self.stdin

        self.stdin = NotiInput(input=queue,
                               output=ostdin.output)

        socket = self.socket

        def run():
            try:
                while socket is self.socket:
                    line = ostdin.input.readline()
                    if not line:
                        break
                    if line == KEYBOARDINTERRUPT:
                        if socket is self.socket:
                            heapyc.set_async_exc(self.target.annex_thread,
                                                 KeyboardInterrupt)
                    else:
                        queue.put(line)
            finally:
                if socket is self.socket:
                    heapyc.set_async_exc(self.target.annex_thread,
                                         SocketClosed)

        self.th = threading.Thread(target=run,
                                   args=())
        self.th._hiding_tag_ = self.intlocals['hp']._hiding_tag_

        self.th.start()

    def disconnect(self):
        sock = self.socket
        if sock is None:
            return
        self.socket = None
        try:
            sock.send(DONE)
        except Exception:
            pass
        try:
            sock.shutdown(socket.SHUT_RDWR)
        except Exception:
            pass
        try:
            sock.close()
        except Exception:
            pass
        sys.last_traceback = None

    def do_close(self, arg):
        self.asynch_close()
        return 1

    def help_close(self):
        print("""close
-----
Close and disable this remote connection completely.  It can then not
be reopened other than by some command from within the target process.

Normally you shouldn't need to use this command, because you can
return to the Monitor via other commands (<Ctrl-C> or .) keeping the
connection open.

But it might be useful when you want to get rid of the remote control
interpreter and thread, if it uses too much memory or disturbs the
target process in some other way.""", file=self.stdout)

    do_h = cmd.Cmd.do_help

    def help_h(self):
        print("""h(elp)
-----
Without argument, print the list of available commands.
With a command name as argument, print help about that command.""", file=self.stdout)

    help_help = help_h

    def do_int(self, arg):
        # XXX We should really stop other tasks while we use changed stdio files
        # but that seems to be hard to do
        # so this is ok for some practical purposes.
        # --- new note May 8 2005:
        # --- and doesn't matter since we are in a different interpreter -
        # --- so there is no XXX issue ?
        ostdin = sys.stdin
        ostdout = sys.stdout
        ostderr = sys.stderr

        try:
            sys.stdin = self.stdin
            sys.stdout = self.stdout
            sys.stderr = self.stdout

            con = Console(stdin=sys.stdin, stdout=sys.stdout,
                          locals=self.intlocals)
            con.interact(
                "Remote interactive console. To return to Annex, type %r." %
                con.EOF_key_sequence)

        finally:
            sys.stdin = ostdin
            sys.stdout = ostdout
            sys.stderr = ostderr

    def help_int(self):
        print("""int
-----
Interactive console.
Bring up a Python console in the Remote Control interpreter.

This console will initially have access to a heapy constructor, named
hpy, and a ready-made instance, named hp, and the target (see also the
reset command).  Other things may be imported as needed.

After returning to the Annex (by q) or to the Monitor (by . or
<Ctrl-C>), the data in the interactive console will remain there - and
will be available till the next time the console is entered.  But the
data may be cleared and reset to the initial state - a new heapy
instance will be created - by the 'reset' command of Annex.

It should be noted that the interpreter thread under investigation is
executing in parallell with the remote control interpreter. So there
may be some problems to do with that if both are executing at the same
time. This has to be dealt with for each case specifically.""", file=self.stdout)

    _bname = 'a1e55f5dc4c9f708311e9f97b8098cd3'

    def do_isolatest(self, arg):
        hp = self.intlocals['hp']

        a = []
        self._a = a
        b = []
        self.intlocals[self._bname] = b
        # to make __builtins__ exist if it did not already
        eval('0', self.intlocals)

        testobjects = [a,
                       b,
                       self.intlocals['__builtins__'],
                       self.intlocals,
                       hp]

        h = hp.heap()
        if hp.iso(*testobjects) & h:
            print('Isolation test failed.', file=self.stdout)
            for i, v in enumerate(testobjects):
                if hp.iso(v) & h:
                    print(
                        '-- Shortest Path(s) to testobjects[%d] --' % i, file=self.stdout)
                    print(hp.iso(v).shpaths, file=self.stdout)
        else:
            print('Isolation test succeeded.', file=self.stdout)

        del self._a
        del self.intlocals[self._bname]

    def help_isolatest(self):
        print("""isolatest
----------
Isolation test.

Test that the target interpreter heap view is isolated from the data
in the remote control interpreter. Data introduced here, eg in the
interactive console, should not be seen in the heap as reported by
hp.heap() etc. This is achieved by setting hp to not follow the
calling interpreter root.  However, this isolation may become broken.
This test is intended to diagnose this problem. The test checks that
none of a number of test objects is visible in the target heap
view. If the test failed, it will show the shortest path(s) to each of
the test objects that was visible.""", file=self.stdout)

    def do_q(self, arg):
        print('To return to Monitor, type <Ctrl-C> or .', file=self.stdout)
        print("To close this connection ('permanently'), type close", file=self.stdout)

    def help_q(self):
        print("""q
-----
Quit.

This doesn't currently do anything except printing a message.  (I
thought it would be too confusing to have a q (quit) command from the
Annex, when there was a similarly named command in the Monitor.)""", file=self.stdout)

    def do_reset(self, arg):
        self.intlocals.clear()
        self.intlocals.update(
            {'hpy': self.hpy,
             'hp': self.hpy(),
             'target': self.target
             })
        # Set shorthand h, it is so commonly used
        # and the instance name now used in README example etc
        self.intlocals['h'] = self.intlocals['hp']

    def help_reset(self):
        print("""reset
-----
Reset things to an initial state.

This resets the state of the interactive console data only, for now.
It is reinitialized to contain the following:

hpy     --- from guppy import hpy
hp      --- hp = hpy()
target  --- a reference to some data in the target interpreter
h       --- h = hp; h is a shorthand for hp

(The hpy function is modified here from the normal one so
it sets some options to make it be concerned with the target
interpreter heap under investigation rather than the current one.)
""", file=self.stdout)

    def do_stat(self, arg):
        print("Target overview", file=self.stdout)
        print("------------------------------------", file=self.stdout)
        print("target.sys.executable   = %s" %
              self.target.sys.executable, file=self.stdout)
        print("target.sys.argv         = %s" %
              self.target.sys.argv, file=self.stdout)
        print("target.wd               = %s" %
              self.target.wd, file=self.stdout)
        print("target.pid              = %d" %
              self.target.pid, file=self.stdout)
        print("------------------------------------", file=self.stdout)

    def help_stat(self):
        print("""stat
-----
Print an overview status table, with data from the target interpreter.

In the table, sys.executable and sys.argv means the current values of
those attributes in the sys module of the target interpreter. The row
labeled target.wd is the working directory of the target interpreter,
at the time the Remote Control interpreter was started (the actual
working directory may have changed since that time). The row labeled
target.pid is the process id of the target interpreter.

""", file=self.stdout)

    def hpy(self, *args, **kwds):
        from guppy import hpy
        hp = hpy(*args, **kwds)
        hp.View.is_hiding_calling_interpreter = 1
        hp.View.target = self.target
        self.target._hiding_tag_ = hp._hiding_tag_
        self.target.close._hiding_tag_ = hp._hiding_tag_
        hp.reprefix = 'hp.'
        return hp

    def run(self):
        try:
            while not self.isclosed:
                self.connect()
                if not self.isclosed:
                    self.do_stat('')
                    while 1:
                        try:
                            self.cmdloop()
                        except SocketClosed:
                            break
                        except Exception:
                            try:
                                traceback.print_exc(file=self.stdout)
                            except Exception:
                                traceback.print_exc(file=sys.stdout)
                                break
                            continue
                self.disconnect()
        finally:
            # Make sure the thread/interpreter can't terminate
            # without the annex being closed,
            # and that we WAIT if someone else is being closing us.
            self.asynch_close()


def on():
    # Start a remote monitoring enabling thread,
    # unless I am that thread myself.
    global annex_thread, target
    if annex_thread is not None:
        return
    if getattr(sys, '_is_guppy_heapy_remote_interpreter_', 0):
        return
    start_annex = """\
# Set a flag to stop recursion when importing site
# in case sitecustomize tries to do Remote.on()
import sys
sys._is_guppy_heapy_remote_interpreter_ = 1
import site
from guppy.heapy import Remote
Remote.Annex(target).run()
"""
    target = Target.Target()
    annex_thread = heapyc.interpreter(start_annex, {'target': target})
    target.annex_thread = annex_thread


def off():
    global annex_thread, target
    if annex_thread is None:
        return
    for i in range(10):
        try:
            close = target.close
        except AttributeError:
            # It may not have been initiated yet.
            # wait and repeat
            time.sleep(0.05)
        else:
            close()
            break
    else:
        raise

    heapyc.set_async_exc(annex_thread, SystemExit)

    while True:
        if not hasattr(heapyc.RootState, 't%d_async_exc' % annex_thread):
            break
        else:
            time.sleep(0.05)

    annex_thread = target = None


annex_thread = None
target = None

atexit.register(off)