pax_global_header00006660000000000000000000000064152235276760014531gustar00rootroot0000000000000052 comment=e4234aab65db2057e6446f19350dcd54bae264bd byobu-7.15/000077500000000000000000000000001522352767600126055ustar00rootroot00000000000000byobu-7.15/.bzrignore000066400000000000000000000017651522352767600146200ustar00rootroot00000000000000# generic autoconf excludes Makefile Makefile.in /aclocal.m4 /autom4te.cache /config.log /config.status /configure /install-sh /missing # generated from .in /etc/profile.d/Z97-byobu.sh /usr/bin/byobu /usr/bin/byobu-config /usr/bin/byobu-ctrl-a /usr/bin/byobu-disable /usr/bin/byobu-disable-prompt /usr/bin/byobu-enable /usr/bin/byobu-enable-prompt /usr/bin/byobu-export /usr/bin/byobu-janitor /usr/bin/byobu-launch /usr/bin/byobu-launcher /usr/bin/byobu-launcher-install /usr/bin/byobu-launcher-uninstall /usr/bin/byobu-layout /usr/bin/byobu-prompt /usr/bin/byobu-quiet /usr/bin/byobu-reconnect-sockets /usr/bin/byobu-select-backend /usr/bin/byobu-select-profile /usr/bin/byobu-select-session /usr/bin/byobu-shell /usr/bin/byobu-silent /usr/bin/byobu-status /usr/bin/byobu-status-detail /usr/bin/byobu-ugraph /usr/bin/byobu-ulevel /usr/lib/byobu/include/config.py /usr/lib/byobu/include/dirs /usr/lib/byobu/include/toggle-utf8 /usr/share/byobu/tests/byobu-time-notifications # produced tarballs /byobu-*.tar.gz byobu-7.15/.gitattributes000066400000000000000000000003361522352767600155020ustar00rootroot00000000000000.claude export-ignore .github export-ignore .maintainer export-ignore mobile/generate_screenshots.py export-ignore mobile/screenshots export-ignore byobu-7.15/.gitignore000066400000000000000000000001201522352767600145660ustar00rootroot00000000000000.venv __pycache__ mobile/build/ mobile/dist/ mobile/trustmux.egg-info/ /debian/ byobu-7.15/Applications/000077500000000000000000000000001522352767600152335ustar00rootroot00000000000000byobu-7.15/Applications/Byobu.app/000077500000000000000000000000001522352767600170725ustar00rootroot00000000000000byobu-7.15/Applications/Byobu.app/Contents/000077500000000000000000000000001522352767600206675ustar00rootroot00000000000000byobu-7.15/Applications/Byobu.app/Contents/Info.plist000066400000000000000000000105711522352767600226430ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleDocumentTypes CFBundleTypeExtensions command tool sh screen tmux CFBundleTypeIconFile Byobu.icns CFBundleTypeName Terminal scripts CFBundleTypeRole Editor CFBundleTypeName Folders CFBundleTypeOSTypes fold CFBundleTypeRole Editor CFBundleExecutable Byobu CFBundleGetInfoString 1.0.0 CFBundleHelpBookFolder Byobu Help CFBundleHelpBookName Byobu Help CFBundleIconFile Byobu.icns CFBundleIcons CFBundlePrimaryIcon CFBundleIconFiles Byobu.icns Icon-72.png Icon-Small-50.png Icon-Small.png Icon@2x.png Icon.png Icon@2x.png iTunesArtwork CFBundleInfoDictionaryVersion 6.0 CFBundleName Byobu CFBundleIdentifier co.byobu CFBundlePackageType APPL CFBundleShortVersionString 1.0.0 CFBundleSignature ITRM CFBundleURLTypes CFBundleURLName http URL CFBundleURLSchemes http CFBundleURLName https URL CFBundleURLSchemes https CFBundleURLName ftp URL CFBundleURLSchemes ftp CFBundleURLName file URL CFBundleURLSchemes file CFBundleURLName gopher URL CFBundleURLSchemes gopher CFBundleURLName mailto URL CFBundleURLSchemes mailto CFBundleURLName news URL CFBundleURLSchemes news CFBundleURLName nntp URL CFBundleURLSchemes nntp CFBundleURLName ssh URL CFBundleURLSchemes ssh CFBundleURLName telnet URL CFBundleURLSchemes telnet CFBundleURLName wais URL CFBundleURLSchemes wais CFBundleURLName whois URL CFBundleURLSchemes whois CFBundleURLName x-man-page URL CFBundleURLSchemes x-man-page CFBundleVersion 1.0.0 NSAppleScriptEnabled YES NSExtensions NSMainNibFile MainMenu NSPrincipalClass ByobuApplication SUPublicDSAKeyFile dsa_pub.pem byobu-7.15/Applications/Byobu.app/Contents/MacOS/000077500000000000000000000000001522352767600216315ustar00rootroot00000000000000byobu-7.15/Applications/Byobu.app/Contents/MacOS/Byobu000066400000000000000000000023071522352767600226360ustar00rootroot00000000000000#!/bin/sh # # Byobu - wrapper script for Mac OS X Application Launcher # Copyright (C) 2012-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . set -e if [ -x /Applications/iTerm.app/Contents/MacOS/iTerm ]; then if [ -x /usr/local/bin/byobu ]; then exec /Applications/iTerm.app/Contents/MacOS/iTerm /usr/local/bin/byobu else echo "You should install byobu into /usr/local" 1>&2 echo "HINT: brew install byobu" 1>&2 exit 1 fi else echo "You should install iTerm2 into your /Applications" 1>&2 echo "HINT: http://www.iterm2.com" 1>&2 exit 1 fi byobu-7.15/Applications/Byobu.app/Contents/PkgInfo000066400000000000000000000000111522352767600221370ustar00rootroot00000000000000APPLBYOB byobu-7.15/Applications/Byobu.app/Contents/Resources/000077500000000000000000000000001522352767600226415ustar00rootroot00000000000000byobu-7.15/Applications/Byobu.app/Contents/Resources/Byobu.icns000066400000000000000000005017541522352767600246130ustar00rootroot00000000000000icnsic09 jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2d#Creator: JasPer Version 1.900.1R \@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP ߆"&y(yUjk,A0d;\[v4bm)BY(,*D+s70{]aCh w]f#Rf^ci?jJSJX@`ZaΏچA^mT# ڊ_$K {g 8Ox<78 "-i`i,&RjM2_{hEIq:]({b: ֚O?*EKB1TSo=l'߆=w XP|zY#!(0N.%9_ 3Y99CxwA\Moh΋MCr ]-z-YcDˑdxH%"**-;@ G ΘkkML_iry %&.*bl\ѓSj)ݜk04~ԟ\| DfmsP9xֳ@|*]-`j^k;ŵ)xL O߆r >D貴%P,Su %-U\ #t`ġ՜odܢƊs'ThʆT4 '"NIԚv_ruM{~*6B #먜 F_ =ab|Y283t!aJ5 >a-YH9yWP lN tFחfVE%[hf nPZ ߆ Ɇ8}r&1k(t}o% 4Cd"lz4i 8 [ [꜆aAzʙPTxF6jF OEӬ.]5_Pp;7zy@SʚA͜jn|xwiG\u/8.oEzfUd &oSzٔJPꑍ yr[QdT]A`TV0L/Ȭ[w/I']ߝ~wmfFǪm]gc@SMb Q7Usm>0@kd/\mTotx~7 ZE30{ 7 j==f4 K8釁q{cg~LiK]"hmbfa{` SRB@Y2 LJHfṤT&I|Z7>G7 #+!{"Q3o8IyI&%B 2@}ŏnwVPwe{r(ZOX+뻃PǵH誗%F2GƋWlA;PΉ!y!6. ÎtN{O ` dϪDR c|o V ;::? 9'q9uwir"8"RB$4%ۊI֎*GVngZt*_F>i;i/)c& {u6`rOR\ߣ^GU޻i 9X_lve+yZF҆O{(>4Eɡ% }n{+v'y,WlڸA}7 'ެ>%xM" +Ғb$7)ZY:uv!YFRͅX=cB| ;RUk%VqN!㻡R,l54QNIG29 $8_A zmJޱq6_*2k@@.HrN)zr%uY#irkoJ:i \A .(ԗzE"$ZR=/Ϭ>R" % n 'ӳM Vf.]Et0)i:"ʱI2ofDd@﹛(7WbJu47XBM0wc\Yt*EuA m,U3gFbǭ$@Tw|bp@kZNB#š=BHޤhU)gOCo"CS8$;~w 1> t|%LnrYC?22?9QQP? DcQomPn97YQJ ]lx+Ep?ϓS*<  !n`Ė|D]܁Ω>R#4G=ݖT%{Qzc=gێ`6ZmƠ`;fRٺ"DS$f+RDXX< c,b}iдpgL侐3[+`fqPwߨ"XqtP6rCRSIѴ5  􌗵_J*bYrS5 ~!@"5Lh[Ł_trmo"Xo Xug厹5oX?E=sOȥ|,*;bo+ov}brvԛoF^BB:ϔPbQ-R.-1Z^y/=xq6.>!pY2vѮ(pzcc9;e[Da#l]9F"kȵW^E6i0{{X LjȨ=ܥ?Á'#va7e\_R ݋3!wtsnʑCݍe)7ڪtʾMIn4 D$"wdM+jW̿;~v]RTa,<>]S/E|j^q>XUVg' _ۄ>rr86c ʀFzx?kzHoEh3G8_P8dpR6JHA%`a(o |{sX Jy;0\~{B1wW8;`ߐ 4@K d[X$qGGj;duJQ/p”е3e#$E 1\(yGNTؐ  U⋲Uʭ]U+¬ks,#^W1BU< ]-'L ,DOk_ y7>PY²ݾ"qks-_N{c!/Wi/#o[e8au˭È9zڼOIiؾ29esډ7p6+iб'>8]*oaOz&4G:$pKkϐ|z琜%ŷgU.(n>t끙oh.f%.Wf9%1pko:bC;XVo ùwߟbִghʉݱxr#*Õ{=U#{LzGѼP8^ew52RJp߉pQ[P9/^-P G,x/i&ؓVjykpN!? NGdD0+?=æ sOSq%(_̋ .,K()+3y>6n~ weOfF-}i~ lĆuCe >,wDFX>@ 2H]-q]*r(1Jv4RIa~&i.1ku0B~9ֽh-Xc)NSX~Ơ\SjċduS`[a' C¢ۙ '>44079bM( X'q MsyrɥeD{3+K{(S7i0m=0o%z@:Lۥ2^VHFѮ*TwmWZ}^%TDֲ5xH {J^2ǡb*78س&R{;вw89Mq‡t #W-|aŪ&pr9h/ɰ$6v=M"ùqԸ=0zJ&i NcDY:J#ב}XJUq(ǩA2U mln9>VMprd sdwT@|5cz30n{A ͓&~Sљ05lM7wR5/ QQY;vU8M!xqϑފ/u'dcOf`SQ+GS-_*={^] B9:$8eg I pŠW}g= Ĝ6J-E.*ztWgv_id_L}!A4GT#!laͅ{*Qql:h{{DT)_\žoU8{݈@f*.eMV&rȻa ҿͩt&kHL"-~Dcݶ®`ZmWPxfbZk\j9t?07 >R (>/ܬ, n&=nS![T+5!#o/CPGxI)NR-Y˜UtnYB;*N;آR{8KƾjhmALo)kjьh#%XFI6: ieS_CG"}6Sp{uz Kx QpÞ0I*e5F hU$P `E|bRch[ *Kq`]Lߟe7ó]ӄʾ =v7pY/4ȏi]<+cjBߖܚL4=S ,C /ςU$iUGL_Tu8@'0ID8Goy %%U SRmb-ҍϷk,.g jih꘿K&eHc'L ieB]Ձ5fAN,(6G^І.@qT=4(_;G0/v X/`ӕFVjP;qꩼ3WU ִZ[APڶPVӘ:MPʱA4D 7w {A]x%r~|S|5w?&0]DॷQC۪ۛ脜xC[oNJ0~Nt Iz&\EKNŀYX@xXb["JΦlSuH W>*Y + %VJbGʏ?o+#˼>rSu)[ ]kicp 䤮K t YoQ"e't|ץJ)*(GҿG4| sYٗ滑Ip<ѭ;gЇ{Q ]qZsԎĽN-lHM"&nC"voj&HfY֌L%:5 W)!rm<2r˨tV ۸m&&>L|ݨt#"т\֙,(o#ͣ^uH)A!~xkFGfuE#85͟F9LZ3,v-LKQ~ȼJZb}=.[d* (?@<{֦!Dq i%5]w1!-fbpxP=\q"5fg5=]/VGatO7~-dq6iA(њ|dǮ9edvE;.?Ń"<m}TD@Ktpk<׊!De8ͧ{fXxM$?Sn٠,YR8XCOٳ̕;YeF 5$F@Lp6{H˦jEИDxuG= c hiW|ĀR9+U 쾾KȄ!P%6nE-w9|/#>V8nC I:kϰ'lmZsqDW W4He :Bk%dAz4UhG7wa +сߡs~΅֕vQP}V2DI|-pgU}gHɂUnwi-7US1A,2\Mz"jAMUuŠb3 gА & hL8z~R:rw$!5m_}h.oi2r%qunO2[Ƅ%4Ahi6>B NsqUb ?K_3b G]VOҜ߆]~å)h7eM-^&7 !l OWVXȺ-ۈOtcx_cp-s(3Bqh}ٽETj&3-V#Io}8CNj# d㥻A;p…]&t;".zA5anTr K5*zN%EMexķ@&*6]{Dqw\arGT-oe фyFCzN폲P@l!hY"/x2*iL L˚4#dvx;t|Jy(ByvR0.*+MSo82ۦrT { :l DzoZIE4:@Zj,2R_&j0Izn yf_{>y7GƷH;ΞX9ZSO"M gXy@-$: NQ5=O([a8AyU| Ϛoq qWïK? vw 1Zpc rϞVr`Ww]稷ZV،hh4Q׌DY7gq``Jo-mԵ&t]m$sWF1 N SLLЃ}o~{x-@qyy[PaWigRz{s1,_&e/N(\v LUn8LSvS]B,J[Z(,z>`ass#5wBO%.%cseAMx S8L9 "KFhRrsO(S='гj Z0]k*#6fvZYS6% #ߑm0^;ߔ(x0ۦw $ͫ;+2ɥߕv)ge /(pJ|X nq+KVdb*nµ&)pՐw~U-+<>5<{HJgUZvO228δXh5Z[InYtpEtU 7>̗ ! zq[$~ƳMRݨYvTIJR;䍐ޤlFJ4{[6ꈂ8k E9Wc)Z߇Ty[ޯ?ǃ/pԺ6lV6[N+]ɭQ "NK ~wGS؏Lp7U W nOWQhHϛ^V! q:бc%I V.")MY'&A (U3S#]k^ςbiZ8x_h1c ',~C栃? v"`VZO/RK'5̻`Sva&bb FS:MGP :1HbUJj]I  M K9^D`ZHi=ONj,T&`[,rapt2GcN˕*}Ct -E]/GІFO5-H&t^͛YȠBf:-6\زBX gSİ*NNQ3rR`CWxe\LH n3W )G)L}pCiѻTB;hZ6 IaP sH,2w\;% YA\@!eKg.F*\v.uөutJ68r"e$[~y%ЄwZ)x!5fHA6;Ƥ8fH՞-%=OfZFϘ?T? )Y ~aFn xoc)8EVdz= EtKvȐI 5QQ#:+<DsrI%QU]K9FnO}GXlx˔(lU^gxzqGH{O:Kࠄ٢zW3rڐm|Mk!f+՜;FZbg#V?>Zv4F-Xiah9Zt_WNyM$A;G& .6CL&Z*,f bp\"-eDB@) oG=)^6g q lzZ(,ΰ=:[RH} ^̌Mw}Nq,{d[c^|k|8=+,f»q`le9-ԭ6: ̒W 5t*V9kdm[+:ߙfErӫ.fnrG/!Ak#R$k|ݿΟ]T{"H7 +AYTr7žHnjִzE1{ͻa(F8qҳݳB"i+eJ۔x,v(uNd;ﻥ b4cP CfS«6o~gƟ5QYU`2W ~zo* L#y92[vn~mf@]S$D ;:Ht&IEӡ vWt`@wsfBrJV6ٵ 8u,OA ~  J7LSUs( #-r˜'Vz-k8:N^vCU?᥺cpX&= #n9` % fG>FC^E͇?,2 t8m^cޔHAb ft!UT1/+=lɒ y1YoIEa1KV e[t0{ #Gi͝g,s,5#@ 31aJL9So#h;U1a2HL>){_ 9t__l>b-Y^.AoTr1i-"C^unƊ+4sʗL6*B7[rdJ:@Bo d0r}N)v*BѲxPtx'W8 "! I6ڋ2Yifo6qEx1O%[ߓ擦:ه̘x.A^*эX=n!49^~ [IvHrl2e".1$3%`%3epVWqm njk {8U  \[Ŵ,M s];S Xl PƷUUQNE:]DIS H {BD c^`kVm_)+EO߃%v+S|l)?/)lXU©{~6Z۶2]`Su.:I^ygyz ,qzCFbMPL*5c>_z¿i~T#O)y4pQ~9&*;H[)~*3Bv[3[{gUlē4—ڵi>B^eM(m1Qf^phìCbw5?+*<\u&m~k\O4dv >(\wSeK(j.z2\6Τ(e=^ɚ C6DD]/Bx#m l]%6& ?ɩ:8ah+`8Y\/:60Vo"U{~=H.tkKWˀ!q ?,?^S/m( lIA3kDSt_LO \t6~ẦAF_QJ9cG4| 8*cr"WP5&jj3*L襷>W/{Mgw:c>&=a28hph:&HQD +/ :u O[bgNf9e4i6whH,ݢMpjA"rQ}.W[MRJW.;l:*;B Z!D1('rcK z@A*Pכ?&W#]5ƸiٶUcdA0=mF(KדW4n=Zwg0^2.=ǍLvdNOAl3hv_VSKKLb멟J?E%c,CFNi²/j*o/b^w8z| MJ pޠr,<-Zh~ܕp2;g$ʚ;E~Xy+}<ױsPP@;;J]A#kAIF24b1H$AKoi Ew_Qrx,1ٍ@/ա o{_ŷ,|,{Sr)/>(1j54+zE*tǤ$GCxfۃ+)@ q2w(J-ϟa[6.qń]P)/^X|0U j#ocE6] ,:/I/!41r9Dug"ǿDih͎04TDцcJ yFxBuu Td\=h;-Mا aqU1]14֨oJ2,v]&z YpZd1h4MчE@3SW%wZϭ>U4W[> ).5T$,o1|KGTm"Demobi)I#8%0n~\Nt,YB$ ˆO(s$ C0+/フGF_b:>|腅mN$.#Ne'*L 5`Dih+!A/24HYU\3LKDf.R:L d!ڈwɵ(% ':q#V)&3)NcCdӠYӜmT#]"%# t:cgʡ `l/|D y[(TCz>թ[Hs۹*}Yh->RP]Ʊ;|+7t" WY񍻓܀A wci'ߦI\ͳ+=paR*FOiu0sJZ Sxeu矱Wp<9Qm`t*>jV$'^AVu9&OkSH1&l(h4A?[;;"iѲjdmǺS sRyKɴa mt1Q}h5+2x@:ͱX_8 |u&IA_KwByg.ƍeL-x)Rҟ\SQ]!e“n%M\z.R?>$_~>^'iI *AlE%vk7 ڸ?ѠLVj*>}gΞw KФAQJtv\ v6) O쨋J&z:8:.v鳂8V$ Ql _Y&Wx9!Ğ"ī<:9pPS CIuabhnQkb% :F$u7`EH[,rx؛)ޘl.MxӨ҄ľh;wIn- ]ֲxH>r\[jS)DJL^6lu(q70d bGWBoo{jȴg($XƢ,NYg(4G -Q)B9LڰPY_a8`e[1Epl #ϭ@9Qq^.|iOr0pSld>?: @~yNf=}5.GZ*lܞxj, DxsI4#r3sA7=y&D"l<ד$2Lbg$ŔZ"6eU`l# ~E82U=󘍽z>1CJ*P{u=t Z1*lz ޠ`|]'؈X>\`wK2ؔ9FׁYpX׆֋/Bu= 0CIbՋV< ^!cS22~A"ai靼ef-X⇝; tSzq#7UwRfԣL42-5wp}3A q$p &52QU (h{A uCc[2I鄉"|Oj*l^;Lݨz=MMGZfǽfl ^d6!ek0Ť{4wtT1VQ'C?oiG,PӋ['<P_Xǣ-@nEBE+5adsF|=6 $v '\ߑ<mAG El*g j=' #:D Gm]%[ PTW#aZY9漸Bi!zf° t6]cS4L1Mb Vd=#pAS5 Qʮ  \- ]fws[f);K6:S{)f>K#A5M笽`)skbz ũ∔r',۱ğsYz+(4i`3*ksُţ|)3FB';koA3LRjhSHO)'wW8haQn3%q)t;d؞_wͷqΖ D[2xɸ vgO(swaDc* 9,d5(s/ǟ{g PBFNOWن(VνDZ"TpebMzrȵp }*aqE0Ԭ_H$ފ%Vԁ<Яd%"'`$33s16 ZJ^&@(684Ό%m%pZ>P(y/W&Ģ$lQྜi,sOuSg=TJ|)LluS|QOg->Θ-_L&](}' ˢv=r30E[?q캻@ :%:q$[^8!ﶮ:G#`4F^AˮN8fO1P'҃{4VǞЕ'uBھ"?-6-!h Nkj/2n~!$5/ʪa=h-!1; .(&茿?r=@@c8kuʞ*7 HÐ0BS+A$,os7!ՉBKrY#ݯPVtz}R`/K7X*b!mGQR}pA\#φ\ISlcMvAH<_rS;O6XaVg!!A78f~М_fTZ_G :<[Bu!W~,*dasU>Uxk3(m׭l(C!R*no7Pjrğ@S PH ^aF$P1YQ-e+L5\t^v!#~ ܶ%n@&t@9QC$Tp/ 1.7Pd*MnNdr* A!_Vj >Xu\p '=Y]{ߛiVrD_qq6=̵)E4w<a .޿CFݒg^v%ۧ.=_K/UJWH&}~J}V4L Hxy2JSt;/+!_OYt>u]uV n@oXLyt<8M1sRc9}pn_QQqؼSlyP{G!s} Kӄ+s_:j^{8mޙ8xegRذu9Ŗ 99i@;7tfGH{ XNm {wܧjr4 9[oĶEےb/gTƦbK-˪Lr>Aɛ wEHoCӤPޛ ?-u w)>i<6H9]ƫ#osRWݹ }>X}c%PzЩa)u8BJ8k~1t5Ğ%-d3v jkp/*5f/B(jxG\&fܘY"^\g`pǚj^ eB) iV'ysj ?#_hے2rvv*O(0eH#}_ ׃|EF?Sd %vwCL$[݋ QsRIڙU貙O][x/b+Wo )LPau^)xV#Xnn^SzJ棓 MgYNyJVIᯟŹ:хJ{}uƭP"k ;\RMX$lK6^V#Pc swƑ5js˅^8:LE ;jKuuyB?~fUaW/"lŏ%XEɪ%s4UɔTMxWʾ0{8D4ZI%r1b b-ziwPہI[vli ʀMoIq@a>Xvbcazٲ{)^Q 8-ŭ oTW>V5~:AeX,ో>L QEIeR|B,$/!5O ,a`ԕubVT#NK ?K%7lo=jlܦp/g((bVGۮ J4uDcBA<ׂ@B8FKd \V5%`SUiB'e 41: r^I\d'~y#k0(# D'lvK[eGg>>H"UM~_5g T`Y㖭=JO^ؽ++Pe0l+_yr9jZG67D=bSڹHP>"C 'ZOV9K9/L{0q<}fR`b.T}|¤tmfιw`%R*B*y./B'EkGN)c 'Ej# 'B6ݫ1eo0 K1y#j]%a&С|SԖ}g-s-a?? <آ$,I|Zn1y?ض,HBD4ܞ6M .@gvzYl+S 8؊ӝU>2a1(RY- Rstt>cy5KPPg0lѰ~K^tYbM8(`;s'SٮAAdQ!E m#b(h#@$/"\7?)B%̺<ϩ>Jv?IuGzq-50`96V*ߴJprjU<ìr] 1AO2ea| b%QǪE"FU`%S;94\6u VzrZO%z0!0%w6# ް)y.ճ,ixe~4&H~Op)#L6.,"9{eB;&E (bS,ovVw5?NRǞŨ8&-R6(&;zum^,%>F 60A5Rj)Z4M⃥7QheVڒ|..b^`=*`E"MqobTAM+-K7*4x7>"ۈ+1šP]D~T1*Hfcr`_/Cduݙx֗fB5e&<8,4M!δߴ@ 9Ē0T *o,>Л6&Y1Wwn)YϿ[1ס+_ 5XJ"S)x6@r~Gjgր>.eZ-5#!BhUd)GLvhw8:TaCd-$jq,FqetZ+( UȆ :ix 3IuF9S&҂4Y,?#|*K%Ů F D`qo-dI"ԁW@\PzMXЍBc8%:Hr<fqV`%17'Ev$?0TD}dO| BqA1`t,޸R%(sMmN뒊~k:q[J@b+N]:6O\c.zBW!3C6kQ*"~Msk|qN/֌pф~G2tULUh (h?c6}Ȥ֕5-YU/nDکiD)UdBm1Vm3ƕؼlܪa2߳/nik)geB"$"f)LdӽIYxo2̧SUv ß`|c9\d 42P~a#WS $Lt!yZw~"+o1t@i[#](KBMCiw-3XzKN6Ge ԋ&;5# Œq#_57BLs>H:taO0ٷ!@2X ^i27yb2$ qŃq^.*PߩbW#<DžƠt5pU5tFAL yW1r8WD, ?0p{1OCM"/Hֱ 5+N=s"OuDDPӕGP?&ld1I3b!vW,S$ዄmC_i~908簂 Eq4"INl)fE,.4h cV|X{+, YQ`pC}ʶfe[Ii3'N *XN$Ӹ7lt!\,o( i*0 |(0Kcu!sl9bz:$#d, h]\^1 ?QAgʁ-CY=%Y[/7f55@";(LQEAX6?$o <a`7 W]IGL?ikodi T2P2,4@828r5Y sAsZhcoDRΐ٘.lP);B|zu~)t&峗juKz|F=|XۄA WѲ?{B0/SmC Ϩhߧe?q8}B= Oapp@!x%$?~奃*OSLBZMc1QwV#FUl#L9WB2Kt<4?dx'4$iG]"?sS5 #ܽ"O^RR{ruf"3kYp"} q=͉U 5)R:do)!^]DyqmۜW&@iR :/MBAHfY/)X(#XU %z֖SΒϊPB74x}ektɿ:+FxbAFb ] cE2$bO].P pdDS%vAfw5 @Mmɋ dLlA h# -\Rc^#-ϞTW lTmN ..mk24'hAk|ጣ(:t# - 1BXEنQ{;3'vH9HXJ ÔEN]X%\኿"` =uoaʱ$*/S€*Y% 9>%W<>Ur1^F7뫴̔uk|]R\)HϷÍ-a"Ǒ *y(f&],W*a",vhGd>'&{IҸ}|+bGjW(0N WZWDXDU:t8"ͻJ{̍؂=ͪ .rf'viޙy7v}L``cmE1MeCRCN?d+Gc!0굢Q`ߛWju>"ߣC2o<˚ƶ,qHdS4/ema dѰWTcHm D&6nS u2t9CE:LD vp$qX8־hC2fXbX`t0*c(%3jng"JW\D~ݥ;L1M=S!b>q~ !Ջ⨡xtU4  BzφOMɋg`# 6T v%D\)ӹD3hYuQO G*07NG3R\Wg =mc rͮ>=]wVƧJ7?ܒp S9v}u$\qyn3N1$g>FCZ]2%W5+v#m0{B9݂,竉zJ\epc {>+fdȪCS7iʓ3A"G*ئYF^<@f7eL4 NNU7(Ĭu-l6EP_'uyED,oߙQ$)2Ec]&WDolbSτF[A@1(J8Oq]j5TsTm ,o^!dFeN[q@ 6L)8KH*_ 86h? ׮Ӗ@뷴(9 (U^3*ʼ ]Gכ('konyb):V͊+Z3!s~T)h- }^j_&ctyv^11%hg\68b,I F=+v׮ch%gfq8R KaȎw e \ն^/;p׽_D]CAUy$Mb|&+Mc)%_%NuRG$!21nx Drz`H=`,Ϣh`E:. Sy!:Wt!u#^!&s_]d!']Wu1yyO9;!1UiK7C{7B8dH4ҪҤ1+Q~x⹓vA߯|B&Z6~R$E®/B8~Ba+CCD'=ph6HrF2UVG?X}RSJe`./eQ/l!9:]^/Nb wşJ9)G,u0_8J7y(b_gfҧq0!"7Ɵ)-[7YU邕E!KNzB_<v$#"EGm֟n0ӧ0cS4gBU2 %g3!3#yKstȭCS=5ld1F#!yKh-͒>fV %ᚤ 0H*ыlq[# :Y6+uWMsZ-4\G\̂e2`C!W(V븒V{΄ll%0TfǴLQ^F7A`}}~9Zw U+4b:\B>_(K :ބ#F8{lǚDҕx!%4 ^GXXjy5Mkؖ<*PIfrfl7ns*0Q`S9$Rܧ9[vz!~cU^ցFװK.#s%?"An\[H9Jbd/kC WcfQp1G~CyYLH x2S⒰# k)CBS ;F1$Ĵт)t""3 =TilDwl˄Z7]םhO9& =aWͱa.7 2myty]aԧ*]b:nSgt$J B:67 ~v Kb|b)RHA$?E< rBd;{ZbTQ64ȦMۮbvWuJagI@"rFI! %Ay|G Q6''9;&x)$ Gւ~p})[6` ) \67Fj6nCvlkXau2˴c0DBd8&Tfw\><[Dl*맭IæF+g"D-dqJ۹)F2@7/1Py)o#*7a팢Su L!Mv惡"Fif}껝Kٞ۵V?p7Cc2W11u;hTi V$~'D{ z^D~gI||*7G,Io}֡zJf?MR%9dWռЁ2?/c7 &{K$DL:,9gsH ;p>gS vA\N~TTRA]h.\@4[{Zkca>wM(B H/i#-Е\SO-ǔTџ^x"QV)Bd26e "=a>޷ekCnLoD#nm {85*94QU4@D3SD|l'nhрzb Cfk`[m:S2d]Ŷv63TU;&)S-PD1V=~T`j# 'y|eE&[45{駯WGb9Ia^2P׉$g;`(l˸3Kff,INĚ^Xdixavi5Qy^f%c+SxKf۱7/EXR}55lfcn@F kЙָDZP^nͯ@@ ˖f"lp?h (=ϊ3Hݣ^?i7ڃd/6|6,6c ğl;!sYe ?#u8"3[Zv8~ǐe@k0̈фEjBLJDq' g]x= 5u ː(ULGwbWI:o$"m3zg-"-oL랱'kJ|HI0[AC-byOǶ7•=2nI4X=&̜Ǧ6?;ؼDŗZM$574$A 7Y t9b{]i*P9\$Ci d,18uJ@g)y\E%ل;6 Q7-=ˆَcMBgJu"*YHL829*eDa8B\QAd&FP-D%2pW2D7y Dl;ը~ }Epij^OYk`\ɞa **1u<^6h;6٣.4b,A2ShW^Uqy\@W!l2c6bޮ5*Qi]ODkq%SL)Bz:tt!gO2Z.t[-~r çCe"1l Zs^˫]M3yļE_Խ<BT3ۍ4[*.#U*քR`eoD.7/j*0PmfuNqMJ{q0*y[̹nF`Nծ8UQ:uf"ޟoj1o^_g0г`ÀSI[IXe2 mCΣY#Uƃ+{-<"OG޼| !Fܪ'4IT+nt+rj)9zS2RQ0 r6ϖA 5*\uM`եx54IBrEx']#r`m8u :N0feZD}k؛B !WRguKr< b'Z̨)CyL!@רqǰ}Ɠ U9/×z{c+}^9d!iXM"l&m=2 GlZTT|ahM\0S`j~#^66f x&:fk`_Uu=[*-?\(? E=1GQYf{09H-gp<͠Ǣ3]P5 Hz&w[ 1N xq5)ss,j.Z*,!-v}1W7ҝѧ!u/R> ٷ;^ĺ;"G|7H&-~&2QP(3' o?]G fmP o!AublG8q?X "CU }wy(J9D=j,E\e’z#k\C ,WHWߒ#<%aHgz%5d{%_In6J.Lv#tk-q!iD:2]] )DTBNec? ;a5dL]ѯ6̫cFb[#XZqY C0+;ffj6*oTtKXT~t~ 3!)q= 8QIX|oSg@ryeDݱ* (|b"Ԟߋ2,޿tyas@PtDt[S OSJ"_#㺵}pMOL,28.[@{S9mV(n@r:=HbRsw;=Tsd pHh/>_C6[;f9Bz_t-T*:p !zgVô)=]t"/#} fq"%{v0 X:FY|'M1M=GtM{c|: fqƓ'f-ʓiu Č- )}cvǐO±;23S3b5M蒓 q"xh;/?4x%]y&_iP`訲BBU24H@8@h}`^Z8.S*W[.ŧ@z' !ֆa*?XD#oj Qhޜrɢlc2%'XadoN5(ÅJ ?F) } 3 E^ďToHJڍ6UGZ{ [-_ m1=L V<;EE~ןC@jT0 am^K}!c՗pp]1rj:OюS3IH)A Mw"@X6MxUw[oӦ8W67xvMYJ D\2<7e' jz2pf̓~T;EetUZŪ %d\ۢcԶq^lc>)b!).0l8׼uLq`mpg&M9B`R9TˍXI+:)6녁{=t>GMڃz43".-sgpD8$Z&b˝}ffgRX̕Q ixZ\8c͘"D>g j ^|^}MO3iyB-gH*cƎ3%Ƃ cԘm0Tʶ=O<4}Tݏ(l:d7ak'yỂ`,flhȏ4n{A\y]BTIzoLfq#kI3Dߌ2S~7{_+Z1k ׍ t: Px`-7a* @.d[;,g󠫐d&֢G^Om4 czsz~_ (Kj00ԅ>Կ k*,EVv{$Vʓ8W4L_ԖkB-x2 5sϪ/T?bd;@p ilDAs};Ele"7l1T<{xJqǀs wRpn-kHMJRS6d^ U\EfSP4v Yb<Qwߠ.m ҇XrX[)t5iuzѰrbR);>!Wxtל)SK1<`}L;՗&b-(/ ZtEy@Y! A*+[Y5 Va2&4/xY|fk!m*ђO'4oa%` p Č]D^miqdDڒ/Qnnv}..OP7qa[d)9z0\Ƶ0͕m?m*!h¢K7ÄmvWqT~dH#m3"7P"\yF,_ =Z+ntHdw<j`,M0“!zP*U*퍭fk$g  ?\ϝo5KQbA?#4iVfe I3#gӣ-,MmoȺx!%g[B2mUFtw\܁Z[XZ=CZoo ~A_]Vm~z[990s;i!1^HMj RdPCPP[cQf݌=WNH׃]h{44rщzObx+xNdXЕXxʔV2D^(90 9T~8;C|fM)oI̐[ %3i WQLYG.rx6Kn̵J l f9Ҁ 4a~G <ʄ,vMJ# A~Kfj,مh!hDcs9`V>ZiZ76ZQX9f6p=n(Ӗ\c -4<Ó;HFCy)F f5~M㹟G)ϟgEfYO:^| @-KzD%pN]2L JwmhY6"@l: 3j 3ڶgu+ÔwDnY섁4O*hf31O|a:ۻN~1$[{Q]K/Ǔ/ӽG߼O-ַddJcl҇=scx}]ޫU]:@n$"JzL?.\uKZL5:QUآѮcu˓@ y7tKe TvIQW :J.W3GD-tl+Wn*wnvXNBĬ%o.NcK:6e,\jo#: KO.{3߉  Hh$j͹fVNK7#MB:鹿 ,EBŌVښpP:/>~cɗ/<4U^Ί1MK/L*i| $yl慊FP.yլzuloO8rlf+Kd,ENrX_f!ȧ񟃧93ƺiۡ/V;)'z$PaǾ\v(m|ŞѦqYdĥQAJ>z߸6p;Dc\n͘XB/뤕W\\y새 c]^"s0Fsc]b*x/X2Oc<49C:p5sB`6\u75Q| ]d'2hb7?8[MSL?I5O.h\~kAq/YأO{y*F:e5Ɍzʒ]z褳H6x':2[k V#>;" {74Srzw/&zc *b|W ~d yv4Q7MH%HNHd\~~Q$cl5k`JOXGZo2â=Q֬.D̘*OhfwR,~@E4ns#7FG3-F/S1Xe*jkAz&'b:{cմZLgj]Cb4KZ  O]J8THs0nb 3l`|n)9%fgh=7 CG ڱuh$s5QhЃj;z&cD'ݯONm QF(P"5'FC>\"td'3Ѡc%)w|洢{ړBEezY˿!Vh&0nQRT!$~*Os)-?X.D;ǹ9qt L8 ekj vY^.B1v@z{FDTTtNpmNc0AexG X!+@b$ 0)輥 0c]A%AHu"+5t,O+$}>zaǃ|P 88HNE `eѯEpeXutnopSY{ }Y0*f^ +FrtFS  HEφtc=x^hAJ" L˃&~2|/fxP>ws/am NSxckxM(m ߾U*SQ5݉קv)h8l?+b#9Ƒ՜CZt\>`7?:TIjƙ9}Xe1  ($~Na / c.{@Tj{oP-D#kQ2T1;kSpbm]ɼCF~qCA)"L7~}x=y$+4f%_>!"& yĥ#Bc&4`U!X`im @m~U]3Njl%|;UdБCkgx.j̧^304ʦ}fff'#guNX*aJ p$ *''+;TA+t}N?Q ^b*]{>oU5_x'у_7' ؐgpfw3)U.ܑvA0x]|/:aDH8o |UwxL!)W~繯BХta vU"yO q a {$oc"[wĺ_];Ϭu.'kP ̟چ4>nk]pMWS4nJ+m"T܌5Wc=k5}?cVGClE)'*>Q6B|Kl&A#a0xbQ^Cb1Ui WUTcY}g`|ͼg* LEc9\+o>}*|Rgo%%'NOc/PSN .`E5 ΠKUrdB_kS[U>LHm)|jx|L"AfNf;;N5038/奺B3lpN, `S %)h(rLkkLHsj Wgm5)ϭiqzf\l]0a4$-h jOh/`/Jsgtë"1Hf(5 {9_& k=T7s 1܂2wgO V"qÞ^nx!H2ɅÒX:i($zan e~5 SՅ%/<0N=NeiSF(ՈkJjQ(xYaZ'CgǺ)(ScrR`뉍=L?7p"\=ѯ F& "e{(;O;ϐ"#Fqk]5QS7MtD5jkBnU3N1E6}$y2pU>*6G1xK)<Tl; -,|ʰ?>>eς'cA}MC:iz gFuԧ?~P( Dzto ԩ ַ TfK|c1oPԧ%T,vxd`TR4PFtLd6бh@օ<@}?oP h鑚?n.Jm&_qE=2Je9YԦ E4?ʐvF]Q L ecp,2ᡀYd$H' ALx.'~ o_A۹5+ pG_P _FWc2 }E?ķ&mbիIMZ1_8Mn##YEғ1 ``:/T<65nH^I*s U#;j G1S-qc8w\ ~ h]ΞGYME w$OZ=*]eNpW]'5Fss)#p&T2+؎,Įul_^v91x&RnT':ـNpE a6c _zz);BR;ɿm_[V^)2{[ixX`kx?E/}|u:VW+rLGyhR'> g{vQs?P5 9L]t\3c`NgkP7!&'ǭVnЧ>fYbSҦd/oT\3L.Ã#WjQR1eyw)1:tXuZں)϶ w2YSjxƆLxp+uULOZ۵iQ=TR,F=K-h `viB?X)B uBt&4CQ,pɮ8p=sc/< Yv~WBs"!{D :O43>zk (?7ɌoAݛ%T<ሲ3J3[{T]ʾXή~Gvs%C>̹r{icCb ;YvƍUzs>{͒>X5*s>@sTG\ΨUTG%aa~"Ӽ-'GQ (ΕBd_5DlNt 0ai#2.wmq9!鳽lII0['3AT +ܸôjXa,h)86d0I7gS!) ,`bUAF^Oo,ʏ8KPRWQs @]55ʞrb9UɠG(LQz#XЁ@,nSPLU6 G }'黉s?h #^f̆xB;qZ_LJr93+z~7+8Q$mbH V&YFi6b4W"z6$Y1_'uSW>U`TZO/7Q#ӑK,?a8Dߊ D-KwVpu |kԌXGW^N -bo<~eչ;2e,cwTz-g>h /I ͯ&/J!&6.EС^$"3%QjlmWcC%k'+~2óCI@c-zWd'3iG86s#SwoS*UPd45eYth$6`y@v%! Q3ȯl":f.H*?*r"I/T'zõ =C~ ?QDPv;Kv:+h#'{j[IP<~r?N-=h${j+iF"zVzv_kxYdҧǑUyaK`Ip9S~vpg* l@(akj}W $EwbO1|D:L6ySg!Oq.qV8y1B Ovs<@Skif`ƗbDL&#\(1(Y ^Y)M'áYhFVcc]uA\mVsrWˌ##R9ʬY\w 6{a9 5 h:ޔ!GUéVSqkq246n3QXo;^׏P\k/pr-`i.ԾJ-oHw4Z5U/9ҳr:7e趍ӌx'8Y)<-(*7ܤ)EhGml@SP y(Ëc2.]Q`eF)&mk+YK-8Rp-u|gG,.|_ssnRǿ\VBM.z(HC[f6nCBTѡm)@'N-O?^/6 \ ՠTb*QyKobWfcY<|pF$`80U}'X4d0u{ =ezbQ7TWCugVvDwҝ|3^qId|~JJfd˪PO4H~,5f+礘\Dr8V"+ ޶N}O8_$PxjNwp!ui1GѴǭsf'>Th ҁ-2ClSU#,S5{f?>gw,)9H}o 05=tH~U=zH_$T {}l)zJ9*!>a`FMD7S_5qr_28bZڀ К}ߡU!(Ѿu}Qs@A חnhWcFuT[!-"}Mf&oqp%Z2nA?!Kˮ+_slW~E,MC ,菱-@dȧ\^9̀M%]UlM7 '  i޸H~bsGVqBٍvb.M 壧7fo,47AG`uHZႆhX?! LXQm}C$G?м=0+jk~0k!A:>a+]3OOwyMi/XyJ}Np%HO9[óUB;ev({TC+_5KpB(lĄakGWdS]$dԄ5XLC']5PCغv`oI֋X{= ǹ'brRIТ˼ E(>gyGgmwd+<͠E YYZsLl@Y裙|qZL< 25 @྅P)zD2{=^ k;o8€Fi4Ai:Z%odh /:rge E6 FozJ%"h)7_v|o?6J}ڸfncO8H4 ji -g~?] #`YZO{i @8wS=2NL/eyay`5҇۸~ vY3[mՍ`T S.2e*U5XXoH1B2YPOF?whEcFS$,,P\ xmPc}}Y9N+΋1]޳9̹ym̵'_ 4޶!EC%SA:N:g`dI-hv38NNt4(pv欠Յ[D᏾m#Ɯ͹qT'&VJym*%큍#mLԫsa>nA[ ]&z>g_[_dJ w1i_B鈪'& /E-*X "l(l#;2!zSjM`)'t#RF=vuYHk?> =[vw;߼nRLR (GsڧXLR|= jg)BhD25(Vff^@RÊ[_J_ɽ7ot_dN]6Q瀓BP{I2˹GK`>lLTl>H(֕ CGlXF'&&o'osp g-r,x 1|]w0`нw6's^9k 5}GVAqP#;}`ynCb \ܯ1!xfV{}F@U+VAF]Ɓ<}%E0(֙]b:1|FSv#sqoYN v,Xыw{:&wš i+Pe4/`xQצb'_Se+t7[0Dq(Ynb4'a@m:W(m^T1̋rhFE\L'3os.kKвՈ_ĸ RP7noc;~hzz_Ξe1hIcHV"߫j (LyM?iS!hiek`.CUuRu[u5So=~"Z3߼{:X,fDa,/#+[Q7%3=,ۡԅ֏/G9;L@Ua<~I+Mc88XTт>~쮵vK/qk%ޙ˭}sĭ?jbFT`E(5k~"Z7y6S(+G2weg?Es r #xܧVqX> ?#Ih0g'k m˫s.&Sj^ 3S _`{ MIK5c?W5]HmHL#>F0urdQM']R5[P>4 /&&MqAwpb~~ m@ {G#. FNIiHaB_Z|k0ax9/N@t ToYY YQָā DЌߋbAMć/2;)Yw, BBv3P%2]bSoJEol>_._+CDZ0 «GWbbS۹4XaU1QJ8mCvpf Xl|)h@Ezw$+p9)})<ű1߱f P* ;o `/ bü? Rf}<3$ioL8S>:hGz/Mlzr㗴,7[7$6_JtǯA"sa$+k Awd>DqR>Ep?yT RୠwBЈRx +D~] FƥD xҐt% FuUF!H',HZG8)ENnӈx QMP獤06Ggq$vIV:gTW>*Eb*ޱ߉dlEa&ގOt V]ae=I'ݘǪnBA'rU}gN>rVP"uL=PR"iԲQ6%kN7<9 vV<؉>y?=CHc] }j3ݽvn DW>z:W\I Dkϳ.{ˎPɞ}f֨?b4͢]ig/< xbEzʑz8wu@vg!5=$3Er`:-pxgdh*"6RNo~E\B.v偖BIg ;Ө&賫{XfᒹKhnjCFύjڬb v0GV EaIMg*6CH]D *O6cE"{i%tL?hK5z}^nOll=T4RePZ{ؙ8n@_cX{Q."i ұ{ :twAv m`<$:%j0LD#R8h(޽W6lg(>r`I|^Y3sm5іC%X{碠 ޝwjPCMrSŒAlpf)Nw z ۰nD<- HY(~+CQԴA )4UYm.k)u83jrqnwa~zIl8I-K!b+D20͙3؋\*rR{) )lL985. d%b6 Y*d7`%7}~Pb%LTZi1{Bz3Y`Z=i I=ʹmv\͝u ,.yE{P@('fgeK6}DhIcމ,\@s o^Ǫ65.w'P >6OXt3X{IԴ@.Ǖj"503BU9}X:\]ءlm-:ǎigLDC+<8A~.љ,K]Erof魃h40ZdVz?k/PaBĩ }Wb.3?ljP. : 8Kzi 7ɽ>Q:4!axGS%J+1=“ ͫvаyhmaP&y5tJc^J%WelW, uœ C_ eKo C }-i8#{UHS t1@L. iUq~m&F(,D]dSAsa9$TNJINd'tDMQ5N(~1Gw 7 A$?I+>#/QuiaH'T[ȿ m6H wF${ܒs_,: ĈOSۨ/d\/4PyOr4)G fҢy 'pcDȃR[Jqe%y{XtW:P}5F,,+G¬8F /|Sm3L.&ҏ *\jJjTI,El DCGVprVŤjI6}RT ?&Q9[*Oc;0S-bQqn QC'"!"feifEnN I15[ V#2hPj;ag8]a9GZ4[ZSh0هt3cYr${zAŴi)ʇvHW](]%k"99;rXv;•"ўZe /p>Im D)޾ֲPEćG&n,QsJ> W٪z6%R I:홀vy2|x t2um0-w*öeWdYZh} ;% \r6WGʏښ #B^8(ʛ3hQz%CX(ݻ/f<0NUQ^ˆ (nWӟMI`SGaӋ)!KX'e! 8]7d c拠5"@؁vrEx/wT'U  @;)'RDz <]sO!S>oBUjK2!ƹ d :ڊR<ʆpN%\դ#^:8q/zT|>φa4V޸7~? }*mVTIJc-wqMgk0L$Au 6!$ft=RcCqbgr69~Z3 NP_%CzڊGp"-M[K \pp$Sst6Йt~f`Hkbe @DguǾ^܊ o]n;|Fs9~#GVB71a{a7Lk4v`yv{5C`D5ftQ] R) UCޒ[LXϑ9(s6u! a[V_yL/ bDX+ :\n%uHݣt5:Mm *BqcG<1_ H__ȝ &kȾ]tjBh z%j|fXE갮yFs)SQ(:UG:~`tXB=Ώ5-䔁&xn ܤWΌ.o=sRA*v>Wzk~/D7F;Eee*MA_`=E١`ZUt,TeTӔjeޒ`+-NI:G l`~ qCjQ`6; 3/a'Gf]%i6>0 ~hy%#ogvE[͚T*j!'TT*a."eزd¼o DH1Z,c,~!=zdvɌՠ&,?pi;T3` ns6u_FNSpXXuhe[qjMqڠX3]ީKS)O @vmqdmrbauuǵ<ρoS|KD2&=o8 6̬* P*6RTZ@N]沠&@(>bV F*hgb"rdVJ4:{ mŵ /(UtN*Ÿ$YUTqO&[btcu "HOJ-QW3iK P=Ƅ|rro\Mk:C!:RVF]yt5ޞbv}?LVb[ѥD6y(ӉQݛj=Lޣf @V:U.&ByJkc{<˖i\%,\ ,V3n < [HLI|Y}OSLRX'h[sRƩ/Йm6ia0ByL nٴY؇5NJ3W_LA'-L n{ҐwQ!Hw sf`z(>QqZFm[i!<0sM Mw\F"A9o81Md ]hL8a"Q>uD.;aZfXY,gMHf@Upcml2:x jfkCʹcTcuQs'턛:"B7=`7պ.m5JQbu:䈍}R~ܖ/05?s%eC| #P1d=ٿyst73}S\c};FH~ -0"v1_X43q=/f1RTԱ;݃@nrR,E:|۶wD#.9i Au~8Dӧdج$Z`f5hn⯄ɆhTL2]r`c^Mk׮"I"|va蝝[/H8q#3QX{5zfFQ/FX 5m<]ҿ>G3؞f=rp|-gYzUxrqjc5M=&]# 1&' NQ,jNjgɿ zm%efx=rm]0- {" "4HL>&ځnb& 73z'3OJ8K/[HL,w08/;}[Oé'JGhnJSp8RTXȿEAn5:*A¨8J8"'}bYD{'d#jFUyN'qY?Rڷp %7^;(WǢ柲!9sКāsfH1f` _ZޖS@m6X]*mH6톳O>llZ: [z2csmSHwZ'gtj~d*W*8w[l>.逺nŒS@l$GB=s\,7o@IT=A¡ 1J0D=$& Fk\&cNFxkS ~F2C $lC "韛O о\m5 4YXI4[=m6HUJ Uͽ,D05?$2]n9.l[%Wy)=8)B}OCq! *W,('ugQMC^[ހ|wl4 Τa7D_cԂ3)R ZPHB򞠞|ޥSRpyU@?'>RwlnP_uyPbR_'&ѿuznrI980 T9~!Vow֭\tB:-bO1&Zns7WT51z8In}2=p?>]]\ }Hnҷ Uσ-M;+:'}@lTmcf Lr )Td>~G"bgåն jfSg?B_((0כ\bEc `VbJkWy-?[\WHw7r8)zJ)ߵ ($ aWU+hښ׀KMя?צ:sw^SLtd̃[)װ#jFx M#:\f]l 2.WAo/ ^72w1mp ?O?}X2ZYGsbRa9'5ۦ-DL7ًE@bpag̤_'"g!m,`7|z($L~,Xh@ulTt}aK5 ٭J׉emh':u"~:/qe BA9$Y8 I\tEvP9II:Fk6pAe.v&, -}e6.>664`\gU;¿,l=KtFT+rݘ\q)jVOW6o%sU"n_,U+*ug Q9L)훇YSNuXvԗCo%N,ɗiWC8MO~v] h<Ѳ77($4]PɌS϶t3EKNVlU񵼿]ٞQoB.#=r#W⡰L(X G rdnl eqf$BBbe]!M&{$켌rؓkzuwʸs'ӏK!g(9pO #aQn Zz*I[1b[٪Pf 2 ; JAi"k\*Լ.5+ގ9d^5d4;כ KujPF!ϬE ޓ\y 6[kKA*6j 9K*uUOUe>f-]ZI{r*zYѐW/oWrYayPlp3H\iVWkb׏G^gBI;ePTE~9G俕px]s <5ѥz]^/ѝ,HGH+#q8Ä偼ALCont1cxzF$v!G8/Yd 42j}E%M}>g_[YI2NsD/Lwjl(. ]SwyW.f?u'{f '#̲Q!m 1 +ni4@K~Z^j 5u=W B,Ȅ,[%xJG5SipXv[X*{ȶ 0rl4{ėshS)sƎr"p>;mcj|q3*[`)J;g!&t.-|W[4c]1}Tͣ1@}$9DhiPf?Qz!Gq)G=*4lصE=l+ UM[/FF ^٣wLrʬLgtk)&n.˽P66/{O *֢ɻt4ؾyru sEޯ16z=~t.]g/u*~Tpn7򭘣/GۡexRoC(iyz%@AۋGI(EujL.VDTŋAPܢ U'lzY!.;H6^i˦ 0:#،@/N|,"/ؿl ۰_ܫuI{|4$R,\dŒ^[lR/Y8'u `;5W loJMmUWd=,`m' eHH2R D+;)bAnR3wTZus y0ߥ|۶#_z" Ah{Qъ׻谮H=RrmR[,FdRֻW Wr?d]j 0Q$ˮ+`;1{!v6-w%AcJ[9Ը? )&h :Mey0ÇEktHu}יXncȬS-"5¨~2mLNJD9=K U- ƼQ?DHRst1'$cm)wZC+EV4ݒ`ctg<]Fu&*Iؖ$9ѐ(fv<dGҐ7AǒKEU+˵ kmQeU8e$KA"d1gaa\@vu~FgtPZ!Ȇ刋|Se#75a[!kJȉU\]*@rǙZA(m ʿՌ5O4EzHn,Z 0 Lؔ2w;8lSZMtVĜ(l&$0?} eLe)M' 4O.ܘ_KQzbߒP4J"#.LiBcpC9ffKLپ$:wplզ5W9~KG/5Cg0(p3O`2~,kW]x;<%z.pqXH^DEbJo~-U"vfZTOΕb';Gɖj Y k=\QFb3nzE e B `%#mԾN8{V#FbQ́/8TRMKX`}]QݥLҍŽKwp9LP7NAYx\5ex\u{(W0>/e{9aCsmSKޫEۍ@c!C=u},zs|otDzV_U-ifj 1qrjzM#q@sx5$ :y2X 6 &ySbٽ+oҺ;92&n?N8#=YL՛Tzmy &{Wq( {5A]<4y֓7pmWppX)DFw(*SӑT"L4ecI>u[KX-oZgF0ĸ~ K$;S\zSbZ˓o cW(AL@0& M۳M/QFz^Ů|[lW&VJym/_\41Oћ3T[aq$?'OC1 ^7a*sjCPzަysɺ8)Lj+ Ӕ$W aG-D ^.sDͣw6h c>s}͚j֕_~{VO4bHĔaTa005  -Z:SŢ!ڭμ"V+xy1i4Q=ɛ6tq@ M{b!)qWt=Wgjx.߈Gלu*wI|+ ^:k:}8 W?]}b/YuJ%Td(5GB-⌯W#!&$୶+w$=J+G8tw&]ZmK7%h;Sߔf B6B&<`VYhoXe;U*V 㱻LB*ScnӌgֵsT4Կd_Fb ֟T\?`LXP"nSbnēp$#=3C4zI-lv>W>}ŰyqFгr%ָC a%'Gl"'G{F 2A>n4KQ0ro^V_fe{5^tΕO_Wڔ0آ0?w߱m" ;`qIPTF9_NJaRL4 h;*vЍ昜$ؕH|NA 0&ZIF_7 `ٷ1<䄅o/SrAkBo+QA:.}7gWB62@R5rSam;i.>U:Q*K6ca_éBju!:;x77X :`a,\ ?LUɸyAy__#Ю*b,)[jb@MW[\7dsM%&?u`'}֡"2@=mk*\w/W./28g6D9&I䴠BI'8XHHyv'ZF>D8Te_):"*FERkJ 4mh3bP.d0[ apfYs/5[ėt]x[{d;/H cIdD2Kbd/g+GPD ܻ~EG!'C-A,4cI}p]t#ǥŸ]"Uv}N " \c݉ZiHz]^sekT-`aI\6/UId#ž>Os6t?"rL<%)gH;!0Ja+>Ef1'^g*pwfw ;kOTt.~:b`ȉhMQ$:\@VZ=/ݲf@ݷ`QՓrK]o2>x }sO|7|3 ڶHXî֣r4?CoQBh`l=(cm';g<<*]ObW`#12ur8a ur (ZLsǒkLyOTVٿ7+/ԝ'e@6C"-otAI T?`Jzy `EcbRÚn7`YȏcB!bE=KKx؛V>Ȍ@ _\MĶjmP'QZuE7aIfmwCo6r6rGT&eEzKHLVL^=붔͇_Iۖmb*pӼS 1>`D xip̠Z~iC>j\/O\ ќ@APT@Wa+o1BY1']LR5`C0n~> Oqc@xN-H̋k(׬Y.`FY.!j;>Ī 1: v)`@5KÃVUִkn_oߟ(  qv3~ICluʈR@EEʄɽ6bFXbᵚ)Jb0(V&|Bj?>d57ʄ / .JBl-aϮ)dfŗ-.{ˎPɞ}f֨?j@Z%Ȭ4eWYVsk$_zV6f"ǩA@C!;k>oqRQ_G hRKCYlהD.zUQT vg^c2bv_Vcc|}-;۬a 2ꂥU\i 4h{8PV 4V\$yFx7>jۇtg[Z/Mc>qRco'4K`^H4}j!|KoɋR@Hh tf^Ț) $XZOF#ImV_غBnTj+po0Ulw_Gc ,AklT|1 ʂGӌ K)Z^`Z׬4dbziNӯr}-Y?63Jb+cq] A6#\[=PRj4M)V<ȓG-<1yVtofݘ7{E*rZyn0 FEYR༔Qͻ/%*gs6'#v%#\]xT吃_bY\mi\].!n :"\_6X7Sl9}R?iH1ۖh1gQM ٲ0h+ݕ2V΃aYX*whζI#V*z0Sfahp>$EfxQ=T\x+ |؏ت.du׬2AzRDe{Q |IbSZncSR10W5>:OŊ!@\uT<-P?LXa4GO( I{Z'ǝD iD}hP#l/Ca] KW'*Q ?6i:P!60C[ܯc^켆eZi[-R  =,bo|.j*s/`7o!w h|['l\@`@Vh:u;+ yz4!hZV7|k)u83jrqnwa~zIl8I*{%O7w/7:f1nR,nh^Z& -odA2mHD2xXճ-P,}il~u/2䞩 yBC%f;9%2UpeR<m^E$2+ʣr1/ZF^հdl9JR/`5 !„*w?NXqa` Fvr~ M$BA:^Ue#T?ٌ ^ς"{Dƈ: AТ%v1j%T!`WVY qdk8\[S=%PNA[<~ek3ZL;êx+kL>$Xh2ntAt3 eSJ>+0EGxrw@s31hgc7-YW)q8xb GVN 71{ݢA Եp-͚;O`basȎ=:.S!sRVTI+>#/QuiaH'T[ȿ iVPȈF.;Rq d!=ѿ8B'džf\?҇QCǩ 4 e_fC@3¡-Z)PY0I`޵d2 ;bhxwer(PS7@G#ࢢ쀍2:'m'![Cdt-4vdgde$' )ۄmJXMGSP -#ٚ3O6pSoeI4y1N9a9lEtjpn{7SaME<ʇk> 3%c%.BwiTTWĖ=(-f!:q&C%qRa@Qջ z$q,p8c @lVMX r%mYIh!kQaE]A8 [}wWJ8/qT3ȤmI+z`$;gPsuY:gW5^%IMӔ>b0&$=|):8q/zT|>φa4V޸7ív-97E}䝮P:g `z<{]e]+M?ޤTIA< 6 m`0QDrSm?"h(=¼ WAN?0 ,֎ nbOӘ%a#;C\Tt/,k੼_h>؎ $3jV(J@ ˾@9̙"A5EIZyoXLE_~g~`p*;Ϭ#9&'طWN2]>[xYX/cjzK.r{_6 /!f88 0Bxi)SCZeMͻ#96LX|2 ?Y Xi1s&h> {*_yVTGs4ouu݋6K֪kzy '#O.X~]*&3nYk[iۺro.n[9ZY!fao5gOdiFǖYS`+Kh%BdoIQK ][K !s'VI̅%<Ăk Xf 툽5VEm3Q3ۭuF`' BDC dU1mGYzR>L$1$wzTX^)(k=.EY~6ڇ89/!4Jy>Y[3Ka_ո;^mU`jseyphXy7`_@TH[l=Fp嗵 [WGR3nٔowu;nGv'y\NK=8oYo{<-g,Ti1ڊ:4@GW$aS^6gQCnX E2IDJx CVhj'{V6hC=[[\dDDR<;QbQUMKBX2oǪ&n =4\@t-EE߂Gx>/8Fg+iVzyNuL捔OC%~{/e"!%qN'* 4fqOܿ-r.L %۾Cl{E'&Oi6:}$6xc5߼ ˧w/hK"fzP'۱3FJh5Ev`/`J,D),2ʌg̽+^MjFc!i~-lUp=,ϮJbwXPR~{yuy1-s-NiMgZ6٩/qP^) ς]yB2mw+Bwk u#$Pl6SPĆpP;*hjɸg-23 YYVޖdD>E )nMd)s".c[77Y\KQ бݑj#*2!7f-y=nߌGYQP@ݸ+6t I2nõ020 0l:ȱ5f^9lxv_kG22Oñ*daHfNb["~ 1הi q>Vr rkI2ALYtMF/!0OM`Z%׾2*Vmh}'x+C2k)? -w Tb1` )xQUӽD#  n\Bgjb+l.@cR%$`Rz|.D\Yڌ ZY 7A5Fw+Z}iJ$s{\ꉐӲqA:GЯ*V狍8Ӈ_вrhIΰ#v i53&.5qX^/Ioʟ3*fZ.N#R5 v !@-<‹>Xs+gm[=[Mzqʹ(T#¸zD|ۙr9TB*z+RLpM @"=8 #ʦW?x;jXݣO Юn25l;9 ٳ*6mwwnz@&4vdAH, (9Hm'ה73=_ވu ٫81bl\SbDuDMiRa+tSKk3J/VRSpagݼ2(T#~fH*mk5S(KrBۥbx#w9KlEl^[ .=hH# $8H ˿mXyay7cHB9L0a)=&" (<ʾ߄Oחkӻof,U_Fvw3KL}# u Ym6"J+3?ȱUҕczṼ FرNxʝ ^Ĉ~ϼ/og5èQT܂xBeƳb[3J8k`"s[}kECz3 v* .~vd$QE:E|Ww{VO eh<"?@;& Eɩ?xx|/q  Z?iiYd{y5Vdֵ)ulgA\R~l$Oik%勅{ X9H™ZF?bkUR1v$Lg|sui%h>&wAVӻ\׋CEH)T0wZۼ]{{G.TΒbF{w7Vwv]{al HL˵#pO3Oc:qzURpE6 $L0@[F3$xS/d}*bE+''u5Iz57<\)fc|7J dIª_ɯMipAl?n'eHh^AѺYHXMEc/Qdm>G8}V!0M[s.(ԬjZr:F{ |"1'_z֏\Ah^]ш\ueD揧U:Ћ^M)E87H49.le=#MVKD[ӣE¤>8|fM_J,k8u8e9+tšw/,qx%ěp [/#h7ˌLvqmxFNukCu#0"LA+WO/>|[O9mc_W+'r.Vv("*^[.?&X<% BpB3$`:KyJ0!LzGBat_q?~ݳ/gro OMkk+WB~ 3zoUxN:j{|\JT#™PQ|m-L`Ip~DoT$}ЎVWcJ?IT7!>S([u)Xv /B^ߍ n͛1jK_jĽc,Am3AVOjѣR:J&CK:О\8֓X0M/'S n@ZXK\t6`g;dz1o}̅+i\3Pg|8тI{}/{ "*&n[F B*y#F.LOgt\4!8R>Uqy4b"zڳa/婟W]E*-5 J˧-y؆8tMjedC c|^pR͉_^0Ѣ ?:oF_*Mplo&c& Kv+)Gn>?[Q7m{_e*͇eJ>x!BI4k֣Me{$2PJB͹,u2sS !e18;?HDwzxHM߇2 ;o͚d/ԲU"_SeS<ж Ywcϔy9;tcu~z pv8YLnzj{V~ RѦ nI(l /r![\m㿓"ٌbLG`Qbs~BC?4+FTAUR Hd ]c\+{-uHFY&?{H  Qvt*FQ^'e-mA80:k7T9Gj Psc\>EI @Nnepav S5tr AO+'H\T?qAG\[ޕ-$؅\G.-`Q:@T62n~K !!Ғȯ`Yn^ft_F~-,W&k>mMuX5!nqA%:?c#^H_;GbڿEI Ei(* Q(du5g-CݏqwXy3邒KKdXҍ-mA PAcVs(bVNXӝ*=oPmYhoXcm^*=볐ބ5nMHMݠ 6ec^֢-efe]2Vt# {OqDQ]#:Rl9KKUQ0pBO7d5^L4&]nrAbĞ4CK6o`HHN|o9nyU][+E&VG&evL8dr+;˼@^Ki 1^GwA޿dT k5"?XSH}OD6q=TO uM/P.h)y`֋ēUN />(Sѯx!~W\0$8nVKL\=MAV -vuZbZ(K lE=4E] R4ΞV@q=%_-:LoD=[YihvfbO#΁ilhs%~h#"%Gc;˖`"CW`p̈I"\hA/mIoņ4x28&3{0 Xi?+́T@HՂzg1>5@m5-DCϕ0ەl JT`CF8YÓ39eڭ*f]G_2轆_q V޿$>lIcfSEL9k dCvQm#_Dlj<IWƂgL;42g ȕ:Eco4{1;ήf\ǯ #iovo"Crڒ2@Sz[!곬F  { a'{I>XC> 33h۞\Tn"Z3L쇗OgG#osWJ+As륓,/$1SRMkl05J 6]jq*x+sQ TZXV/}"XR: `Y1iϾNim1 ?zXOR?9yv|WnG"G$8T1# By|LM> ~o&KAjSv<ތl.,]^OX#~j6oI択HkHTߍӵ:x]Sw[nluہ'QMkTWrhu0ҧcd=`EyUdLq``$ގ`?^CC~c5q(w}1Ql_T5%(G;!CAVe BPSirJ7Ei_2/}1-1\ L°c M5 $Mha"MQjf77s&ioZd^ $ºkA+ .9 oq6׷t ulp?(.:94ah>|TpxInVik) KrQzV@u;%sZoՃGO}| 4qNZ pxqrJH'= t䯩Mb8L+\{S"3WcER ǭ_ëg`{V[7N﹭%CI{"4&WF qj>4(vZ d9U(.>58wG7lMJ^jءɮAJ$q(AP2^&K`r8qz(A)@NuBaL|Ep6A$;%W#=5JV]Xk[Z>͉}D0d$oeɱ&$fjO'(nL8NѼ"eU,’>,3QAs}gQa zAWs|pN@3ooUT"/˲ yY!lVg֙[:GI/35^6aa>l:TFTᕧc[:D4!i]ߘ}O8(sxWq:yhU*fJW_Cx'L.C4.Lߔ:܂^6(UG_qX:E<yYL4Ğo\yRKӷAE&hU*6Hq>TMCPЀރaqϩs:=Ux!sXnd9S*`tlnQOF17Gu2cÕ:Df팻t?waR;*=8hif&OO<,YR^~liyS IԥphB+/s|;b8oc$U9^δG*_AwN?KbH53 -vC0*.yVC! A_pXVcn3(*D# FXcW`F"huPGr|jAcWn:N%IKGPq3/jJζR~ULDCgzyet\U4HĘ>ڬjcL-Bƌ6{+O É2& "׃mH.cQX0?Fo* 5a-$DѴ*t=k~J.~$UUJ2^!=Oz.ĨCCwGI!vs+ fTP;=E]\-@v;2R"3鏁 vj{f6{.pv<86"T>}BTؖYj[s<a 3q? ʐ2YV"xT"h9 B])lQ˜^%c]x Kz/P[#z|)]<I W?<(|>+!D2nI C'd 4jM{_DW/*e6p_{66|"3-ϻSw $(?Τ 9f`z0ʻ𒱆"ͧlgyq ui?-v,!g>_Yb0[>%6a7g3/p JosPQznP5PDio,2H0mf$\zx?mXʸ1g L*JI;|o Ƴ;m6(hTr=qF?rη#^k?^˙|]tǣ@/)0ظ\>ȅOO> Ž#o7>Yj}' lе}Da$\#} "b/ǡz`z8yLŧN&*#ׅWK`{!> #D(w*qr}.7Oq~ BZ<`,r ]8tX qYtfURNq'3Qʮ8&_x0)ooVB.࿻8|\oA>rk#](-JGCR$BCjt!#}Z8U' bo v jZ@^>>DpV%pNa7&]4ٵݻ3 A-*kE/h{-*d zJ<ޙ-#ɉC\SQFcL R1"Uj9cCt8E+=\chVZʜmA r`${%o2SQDMD"DρM6ه;Bm NmrMjB~vΎ鬒)OSfr罭?LPf")N"J ^hzسD[x;]ʿ7M̨5"U}C [bا@nL!fi& &BN5ra7O?>J :a_?[aqV糄Bߡ<X)aLUKxmt'cvOJjhY5:!y] 5S&ɨB[d;Eʂ,ĢeA|6" O@hve-VhJ<}FWp=e|&[j9Dp1ٽTL_=+kUay5p8I]E:N4>q #s0)2WԶ=[1eiB%l~}ƛl 3%u>в^njKzU#{\E2PH7ɪ½Zj1L+M-ǹED.6%ir~"ZAKP1ӻwsv~# RD1PVF˘K;,J:U, O{*PKcD鑞`ԏEcg5$ [1+Mkjܟ.}f,Z?Ӑ.TQfWpznik~@ 5u  7Gu3;z_ipp?LӾވs5j5n]}_okۧ~\n mpn?nno]7-Kz (Σg9y3 &}jU"$5{@Pb+Z{ s*k$O~9Ѧ|E¶4[xFDbf_Q '.yAd-2L־mX`S{iM7HW=(_ɧ4x*|"cgέ=mu8"*#C eZM{r- ,aVV+kn-UYhijwwt; IU[3nL"?AlE ?|6cYDaHiQJ,Ro;03L/-  &A(8SbU'Q}ϣ#@w *⦭ݤOnMO5QcpJ>JP$~Ro ] c :ceZ .wZfC* 5PE}6~lDBMwAJy@S{u@`wTOF53S=lyؾ΢O`$L]j3  "#.>c @1G%8#qZ5} .e{KSbE[IZ* yt' yBs=pϓ!_@hCG'4d?V3?DEXv`p۠-?D"ۉVy.@l' 5-UTDuq?Ӟ0ӪF\j%:J2C jzQxl4K޸CyMNc1$k9wFb#Qeo- "rp`*XC% pͱX_)N/QF/9?|5A}hvŧdR<hD.Xe1~s_XfWy.˿M@N eSN$6Ǡb^^QD"Reg ~JRB|Ć| . -͗maC(h@XAxϣqL CuZ;J_/dwQ'v@Lilemc'%)5?]̅͟l{q%j ,vntºŹ\d,@e?r"XɇYe2&he!,ԘБZTuZߕ_&RM׻G$ߘI|z[=YivFAG_VTЩ)z&3:@'!8.esc41̗id8ML0P·__1_nЎfyQ jKnXzE>^U#:u7 ]\ M)/*2~'dC0y2 nTc|*hbz;}w|HwIbl %ҰԠ=z*WUL `#!FuA0ZA&K9UUDiG!&<#K;xY8NZH2}yA91E XiŸ_$p& ][uY*J7r(MO|3/ɷxC<Hk?0B๯,7) /]$" LaO1A)(0ī1Uf<^ oS96S-eW5|Z _(`z_{^/|O9.b>{cG]UA*1!V!$q_CR趤hȿbyib0;Xty5- iszp^jc6 &o;T A0J8:*V%4c>Y@<#؀=zׇ\')Ne|hSd0 G8At-N; Vgu~x[ BJ/#p;hdQzyS/ Hz|JEN~O!\di>ҸMw7j1T 8}l~e;.iBq(Q Tո! oa!yD}a/]֣|-s)XA7F:\v>2M_j%)L!]F&>^j袳XX#j8U#Y }/: iRva̕tkM>:\}2smELqgj x3WVWV$hdhR*&cQݝm)[#z7)؁d76[a\vigi0RSHXn 57(/G ( OhE ҫ Qa$;DD2W|z7)9\oDE)( . DJU qUڲi*^ҋ6<WDW>BlnV XUo øPWY.ai#JKU?{51tū>+y4,hDCr\ ?5( z3grbZxiP+3ǣ`qAҀ)·|bhۻD$::`#DBf`7XqKnG^N}ѱђ4ų (yuTfkb<[Yd޻c?Z2ān`TH%:03j6{<$a^2ඉkJX[w E\m@!1!Ni{/,4 `}JuGqF&<\ Ę<9blV{ L`,j71Sr6NryE?!ĘAM%*"Fn$ q?xd  {g،Q:YwZȲjNzv3W;jn+pKBP"e=Po*BzvsJ+i}.e&Xwd0c-tSZ@P 0חS7ߺ#'Q?0#0a[9Pe"[Qr)7kMI W&ßFx1JX#b\]D9Mbw.vS 0atĦOr b #4DnAǢKx%/+y[.J돏*Cu *L_0-b 1˺|[S'x4km]K/4WǴFj7˥]L_ >ԓKSZCnDL$ x5G55V)񢂗6H>sPLFQ-)%ѝM䣏)%9%DP HU ^IRuaAPH[2Xv@/aD!n5L":@;-+ n&1L^QӅ@t+|.6BZW?2/v(lc͢tTU(!Lelƒdw'GW5^mPs@L@-`T& D DLۡR{ZT(6+G@p)Ws^Q|? By_A͘N W4JOSj:e9gELPC߬:߬;&xza-U(ӈ̑f]W N= n|?PڢbhI;kV\tެ"-*(J^s%p&p,|M}l4WؕńC 03~9KeI>*6IR'*Mۤ߷N-!QV&^EK6~VjyեHΎU܀Z\ |@a2go],u%'s}W@O% 2&ʓΩuVe^VD|ωc.5U.)>>?ZrW&b#S~lLW%NrcD lʃf| 6"`0co;()Udy`V:CY 4)-9toC$ W2L uVd:5sYKcUX³>4}\ʋ.DDEbгjED!MtIIqC5?MlWVQ9}%{ˮ~NqTߤ2^xeMo0M9X xN6 ?u4Х[6yuE-Y/Ѕߟ j@j-2U\epGUBX4Wp |͍6I)//1E+bB0,}IB,q7]) m |Mx$m-HՅ ._5'M绢Pd6׳E0!Z ] $$cICg`pQANo꥖F{ebuwbN“n=hG>hYa04I[|:]{3 3M$ñKcl:%T4^(?X=Л,6"Yu| =aW|C˗J^a "_Ai'kᶾ CR #$ZFe&8F8JGCɕވŀy4Ԕy4f{x3 p{~>vk4LR|Ƅ)q;A>C y UhvK,P0g`u> vv [ _@a~u(2' ˽7_bvC!|MqD4z齋RQYJ*޾\WIP<+A>R5?z#[1n6\Zf/inQ:NR,晹ϐrr ^?nS <…f?&8>Fd(jwgDqIȷRXMòPJ0˝V9|Jȩ"& ExDnQG|P?#I7E BW|]BJąѕV`|PG뽸A1/@u" &> rC6E,=/Eφ [.jEIZoєiRd Y!뢋KB/Ѥފmsd́?k2#ۡ;ML)vU*H2ĭ}d#^¸3(:Nq.X B$%YY96SHE?n6671Otס7!`CT1rN#v}P<50Y:}!Oa\@JeX̓^/ v]d}dT5\BrXIL0W'yP\E;a۔8R`? 8E kt֪1SB,h1|u "=x$؆oY:2vlOSd5G6dd.@d+?eaYyϡ5f<賅x,8K?ɴ eScHstLkJOte hvɋsC'&"!B<#@T;C{j1BPnhI"R5Zb]bx0Uh]R7[v'FR #Y]NKϮ$F9 e'kɍ9}O*\J=ь$₩`\DXXhFKKIyү3OYOʼ'ӭL.B>Lpk>@b`ermufxa1+1pC]STȲֆMK]#|JuFIGh ,RFܚ\NVEԘ%^naf/M;)6Yt;(JtlP,wTV o}Ý1arS,QfJ$^[ӽzۯo7>!'(e@fU⾾m8򿚠 6jSxeXn."JKiw/.٥ 8jt\xΛR8B:^aP( b1o^rVkT*i,A^m=8s$+>o*>n 4罶B020aHhsIQY)b [r2^(ZBCM HXn.Y~MP݁;(1Uc b6`d?mdo^Om!gsS?0|14H:wZgv } ǫ#PDL+DK1{|CLV|/f;,IUG\BWLQ4N=yxˍ񧬀3p7Lplk*">; r|U">D*l땪ao0Np-V@Z4Rlըbo>%@۽,~zO mU% sӽRI9\&Pwg7}6sONi 'd5X8P2;;brH3Q{ɒV>.vof,3AikD?UCTs3o'4S8;UNR^+#?k}7K7S?8t3gO_KR,3{IIGXQ] ľA4UgЮ _Q59<kF3Bd䀠t<Çҙ;ޢc~z9\<>&XxJq=rkT5UI}>\1oi6{L{;7> iLe4NR~d\f9ųwNd\~rCu)6ϝp]S״_2$}vmmP>~Y"Q*~2ZuµkQޠ-?!Xd`y4} &Ag1R͐kydSCk 6U# 5AAՂ>kbv˪-'1JVb[d٘$"xɉbY5V_m7hջ#M[:1aqc (ߢSIrav&8Y.'\MOs IKsZ-ym-XDMQWx׵U8Ng?J\~`mִJ "X݅᯷4rz[ 5%؋ms;+ɼK Un9d|BYo|h$9GEsVlȨ ozc^2R:*К+VXjY*ҙA4g5I;n NOL\ߊՁMC-XI͊f\PpdEi'LL0Nf<[XSn3/( Q5ܼ7B h1.#*at!ꪼ1qIʞ)#K@olҸ'whdĪTn m]r5a4[S_:X`CSV#t_(3Ohp;lkD8o,}3WVw82y[:DWYb̉haW?Vw0yՒQiR'y'U|xΥOxm]P<qϹ8ZKvCP, pw),75(}`D%Xr;Dō5,>C>tJT޺񤰆 A:⹥;fFEU] %ox}i{K㧉`*q~"~?T{cdJd+ >^q-xͬ1g ?v<"04]`-p-#U,dKPVsy*00,~"*mjPݦ1+ޭi*|r#_*}uAܺQ ʘ=,kYZ'GRĂsA?xgMϠLߙ7?˫p6l i@xwIn-ET\40 Ľ"Ja?t2|1V,siޏc,` 'Q[?}|^5lԏ5W92t1adSqy%$T9|𘫟2z}5ۿl -Uc#Ƚǩc; !Gҁ)'iz߽l/ \"IltFY sC(Pq+X'q#`-D#]L壡],Bw wxߑne" ./<+'wgEޗg9 !quB(s|O*%J8H̃ܒ?:(;u5-vuy ,^Rb`kV^{s?gON19 ^х&%gcT` px ƸrtRܖ{835ehE{Ik }n!DKl$E=M|Yk\?!W+XjS+%mv)%ͱNڑ6KAs{D>0yQj/Z715[)y1/bϻBAVŀ7/1'4؊6đzI(p u_  !Ap*yQ=TKf\eV vq<"+`Ψy2$-5lCyZ %EeބͳI+5*!I5?x rw7OSE WmIL>8vmNGqYzDEͱ$ɐ#/dȯmG<k/Nb8^3:ced4l F l|YD=+|guy$N\){ ȢCqU@MYy0bHNƃ̬a< 5Y9 =^Ky '>/CO }vFVڙ H}BNpI+G}K-Md┒VIY f7=,b{~U[E/$u.+;Uz==W.bBKC44LD9qEY-J[ayÒĎ{!@:{ɺ AK |_c&݌ }<1wC{>Ej^`"qT3S~$Hڿ]/nLnK~ %"9bWAe UpW͞>,fE7=L6+)r-\`/:Z'V;wg =*TLWzL֕hpx!H=Pv!G՘VwBM)L.妡Š„,&k>X0l( $gtr/1*K|6X(\i.cD̔"򧶹)Gl*p;UP{+aJMpң\k 3x9#cu<'Y T_|q4h K׫bV=w$k䲦D*L 4,TK`*8S+\a<2I:Bf{{Cs 1IDȲ,IGy03SNr;TAj_e٨7{,X g -h홝q hY ƶ'L_: ;cVB'C?B[& >nXPic;. '~VALBbJ]&,a: u]Kp8:&݈6M׷vI83}2e)^~dR'+ ^yfz\LpE~" +F~\Zy*%O{iiQ {%KJ" nIVN<7P]#))U=_ȏ+j)&4C=xRZZita_Z32cg }-*㯰HٗN_.iTǹ%X&u;XNnPCl?/y@# _zH﨤 *qf Hso~]8v;8E ?aG"Ǔ) 3/"CoW_10/oh?-]\[ct%J݌uh("ŽyE*"o'x&h}2(S^p%L8Eqzn/g |9gS: 202xYcZV,2F2n=33%s UDT=q~i&AxV&"IBdj8т-0J<*rϘi}of4T:V8+ݬ/Q6T1;4W6PuDj^MgViArصQކ>o{I3۫rXl]Iuth̙ N⥉Z VJM-f.Hv!{Wh͞ɺQ{\~s^̸+۸ew*yv3 kk.#*ynbSYlm+ictd ,ʤHjaY.-tGʇg`@\vŘ ($v׻T9B}'3mz~VaAIkL: #_qg \7@O c@/H7iX81AdS L5əP8qz9D5>ۂ}43G!>OGFH'$^QD 4df!r0稅"?hiOƗ1'뼘81!k$}S=/%D}+˝ (B=?Vw8$? SX MY6qDn_"] I6 H2TI4d6$FrGk?fJUXAKG: ^ſef3S~w^E»ɕ6E2tC84՛moVJ$Z@a38)D/V{OWQ<$` (⊌ շbԽW21>q.*U=p`MJDG I_1./= о¶~ gO:Pdg_ŦT ɵ?XOIia@>\:!<但I* jҼ/x9y0)00R)zњ'R3j!݃Q;VArZ_LagL<_He`yZL v?z0'HԜ +A:x2󌹢D2: P*b{C6۶[< ]ѷ.C뺮L#7BoZl,.l`v&fc$q"i+Pգ.(.VF+J~txГ<=Xa=زn{q6*LbS|o׿aQ"pX,vh-H:܆Ʃ ZQNmU*!h/dZ&a'1k$!F7oDuG;"$: /ِH+{|T`|k|xF*P¢v- [`]FYL|걉^I+`glg/8"S G􅤦xVSU{v-?U],1Ɏ&l1htcbWtYxBm [ jf;%"FB}?<,Ye{h dl|ֱKHEZ`K. 6/"W鹚Z1 x#Z/DKU1z|Z5ot:+m'kgB{T&: _rHuN+Ⱦma;F~:6}mV ( Q;M"q8tu$*$ѱrJtm6:&72&0BL`Ap,*todwH)&ЦǶ6oN5aKVN{Z&GI4!V1QY'Gc N}s8Δ>ajf%u<S<!سx _㈭ <8@J !k2g͂o ҈yHu;0 6eѩ}Qn YWu[Q 4`㭙|1v/"OI<~Y.aQü:/8+s 8f_K|k#0NSOe˝բQꮙ_R L;+~꒑ʤo#ylN.K l[=~@4%?.գ2_XnMf 5Y<-(DK_Vx"'w ԱSD3PmFx~TL)0^'اaGOm EW9,;|0n/p\/ֱZ2-еFƫW:²Na* VT?pa@H6i$'E-?k7wSV#Vi|&0G'W?&`QQr,!),o\R̹25RJCѭ16uD~\gLX+/xMĊ͊Uy-}x v\ ċuVjb"R|!4< !'33م(GQţ#?F@eO6c$eqm}'C3rDGz:yc`Lj]R=;g$M]}`r,ۙ(oAz/z,eBnY;a622yDq q}2Kݸf0p#nRuͅ_]3>"[Wt7#ZmbøN]LXf`OUSh~x0P QP_ +<6ۼE+L]`nPB)I}9i[A6T k ZI.!5Kv=UM[K6*܅cD/\Mͽ7"6:0ۋl+ZR BlS:섓$u FWԹ:e-m6H_/Yn4r_B9 i:ϟN_ ~E H±K L0|$z$Oևڲ2D)(`OCNXgOIFJo?sڑ?ˤg3_|aWEpf*`xQ0Y\)QD0=y^KI2cfk,RL#7qGŴsy+vnJHo:X d5rffZH(} 4(5qYvR]ۥŲipdmTn"5ZN@νFZDPDj""/N*1Th-Ai6EK-2 Q_ |];1f~ e5 %<7%Jjv'89T,]۷ ʊ+7? ò6ez+<戟s= 4>'u* 9-Jfe$$lIMuer/JͲKNgs1qi%Xd\RJʒƎ ~R7Ȗ`.r~*;_ĀgȢvGSQ>(ϻ-Sd? ]G\>g|*LʆxDcY\\Cv=a&> B:=:TU!P󐥠^p'= P7C!nOYUEuGcVNNӰ'3>O&{JvˋE2g/F |͆m֡98 /I#Ae4@obPͶNP"K-doLVxk8Z%u/**ZIp@Q8$6ڤ1NS|o@ p_>3QU#'{}9D@p>bTƼ-jKR>,%YA7-1d_;(i32B &@1Q9NlfZK;oL;~,. xʍW֨ (KfPa_P> qPA*7%RAwdCf[,la/%*!!ɤU}WiI6xb%{&Ȼ>c/R.gDNZ.I!eŜ,*دSU.3^lyV:VD==SzFoTqӌ0 Zhsf ~k+o]Gy/~{-8O\W0 |֣母-pUK"Bw%wT Ä3L8 zf\eGi6An,//Е0XJ"`K/Ƞb_Ζ;j}+qofQV*|OLy~{TKyjDSw)z./(o̢wd{\˵3Z\5KoaH)}Dgm;cT}nK}$A \=|]`P@/h k=)}*@׷sN#9ɘe< ::gv%.Ue/SST j"m$gq)NSXЃ?󛁝d~ՃKiCϐ- 4: 5!ׅ/yû9"%6j9RUZ J <-IN1S&Y Vb&EAqH%!fv>Sȶd-BH҈ o-n਽\cBr3d=CBV* 7Ovyo{EFq>RF}TS?нEfP tƚMd$)HH޿rbסM?#E3AЂp~hriewe>(9x`dE*U,D^e*ܲ)]a )b~@6|vaŠqh+ {nuPbsXbcy6.u4"2-:RT~C-+(^L)vSW5>5V{>ʶLk&8i6Ru~:olmocéqn_n6?k5o}}}_om۪g}QoC7gk?Fpֻz޿/On_5kΣFN͎&r'fvע𬋅W75F0_`s߾mNîU .`:nSe5 SFm*SĖwgi8L:^ysD*`;*>e4ˆѨqV@p7-kNjY*kI)L'W87؉ $v'Sx pD='CV{_JΥt V7<}ΤH5^,:W0v D_yaA9@6zghI`nN{Scg?"`E Y*pQ 7 J '1MYPB~ش(t8#Q 㾬n磶WWطԴ⦭ݤOnRf2 LJIx%`$'oO bu>O| y}8%uzw<ꥐ] j|&`8i3ybC4u44U#'u?Ϳ ~݌XȓN Dוx~\ 1 U]9t2ڗd^Z%Ty>G\鰼 uhrZ(=b)zFr.ĩ-O$>)83=8sG%]$/BxX-ؘcf; D췷*mXq`:lhotL$8b1 E4k%?4D T!/#rUoPWUH`,VS)2kpҼ=7jLXQ-W|t"[H}C13 S<;{a 7iX=jk\2L yW`ev"Z3vPRVPBoٟwzJ y . TZ.˙p9ЇqU] kcOL|sobT#C  43Scz+kWF<9%X+7 zB{5ӭװ.O}>Wv`VƸs1; U+|'rnَ| g1#JۃЗm lD ()j=+/}CArgNJXHBFˮO=%]}^#l4͞@!}؀L ʔc`k*/t^׶5L-g|y~=j 6<&x/L(O8E3z)Q9I\KN97¯Da_%.`z/&a!*4 dzYr"0+O{+/5Z*zyS鉚aL,v3ռAŒ{V&DŸsy׸F #DZ= cfGK.h>ufs)R,Eۍ{ 9_!^[.h"HG-_嬍0SX᭡:V!Q L0^޵ 72E%}YӳqX\WV_6h34J\ _T>9zv) LThd{y@1hqZ(.fnu 2NI~K44KvY=J .mg9j4׭}L8ݷڣ*]Эx I"Zw{Ea3c$+L6/s_z+ᦰ,}t'&Ĕʠ,+,2TvuB` qBXGb1?1TzELbmBEU9J>744ta$nHR';z3IUB d, Gv2_̆K`O5?QғBoˆ wR@) ;b#g`P#+nP3x3[X2=jcڤ#a HyeNUQ`6tmR,4]~Xh!{L9Z|_xl%~@Vt|M e?cE䜰w~3K*c\Tkf')ba\1ўLSfП޽=HK L/ZfB9|4kH,+\[HROL7[-6'/ ~Cm qY|5'>Or0U(4"^ gQ򐊩q 5C챵k*62͎9 EXTAKSx"|*1Oi[̉7";ÊAbƤ-g'#\ec1WAkO;?c6 %{gKʋHå,Ћr2Bbc7c `HSG'C# $?o%erA>YŝV\({FH䖖,OZpI jTĈDL+) v~m4"Ѐ %ciO2}=D@QQ_*h"2 A!]c䕊:>Yc Ew;݀A֨hNC|sGRk"&F^ؒ[b ]D1w1ߔэvm-ܪHZdC p'InRВ남@sFÀ.>.L2يx i mѽ 0pl ҚՔ%G~ =B,8EF)p L_'WTI{Z\is#PT#і{ykuxƇN`E4_5~%ќr$2f2  4ԫRC \B~ F! ҰY~YDB[xbQX=@żD{䚆jk Ka~72ɯ]CmN;OOņ4W?H78sOI0 c:d.&0v7roS$_?L4*`F@[,"zS ZPXi{sUF8x9(,;6TcVkpMdS/}NwY{&綪']ޠq]v!+ M,y[<0 ~"PKSx^t-7 jw]AB[Nٲ:r'D@L]DX{w!ڕJ>hv~Y$^gbsCpIu 0뇸qnmdY+/EpQ5n}|' }Y 6 a 큈J Y0u~{_ $-BAkߨ a& icN59GJqiƴqOpY3'>.Z.C!@1&s|yM¯Ll#=Y~zj(l3|*3=&X8bOd,i%8QY\N_E:'ZYy_*d~]?},ba͚ 2mOVOCqϽQ).:+No*Yr(':K_%#x&fgozy׿&NEK1mt8İ8Va(?-Ac^_^9GZ"iC@Aʄ;rtcΎšY;DTl4׸mW@cL}GbiS\_ L0C-G3lT)32PSᑈ9CgV$bmLUn_ $kӳh?2.,ξСYE֠+ׯ+ϑ,;JEeRJq0`b-Ӟ)iMaӮxd~5yfm43F7ů)6O/K m Zaۆ+bc &veߙzsQKP3Gz8Ne{} .1` TUvU28kN _}~S"^׋Y#c2H!ΈȄqD9e J,h ͳIڳʡ->3_JK$_ߧ;3 ?ՁRE(*LJc$Θ,~7+V ΢1~@̅cߵL̡Wqo^T(݊_!F3D /u8@UHօ\1ju 뽸A1/@WXa~nOSopn='DG=e")] BI:Nw概-==D 8V:t%o0Àfi|͊uu\0о*ܳt9 ^PDкTg v}#ῴ3 咜Jvk\q0RVX'vSOt3?nB2, (+[^S_U$.3mL<Œ׹Z&6H ;0ZМ|+-/]fWgݻ! ٧E\D%uj(* v 92×8+O32'#D8ب]T̍ZoYV_a ;܈-GQ ؼ>[9߭3PR$#}ؗgcl HBM<9tZD@'6Q(`ۛ_-b-xР B+ w8]$66Zjp7.H4,~ 'A0hn/K0o dPcYx;| U~wę3*WZ|CFtj1k| ^|Q}حQq!ۀG)CJq;C{ry*(bAt@u\n-m)JKeZLCsoƚ $4҄vsbhZd>Zsw,(,@u; E,Ƹ_K?{9LaAR17=~z j?p8# {,#7j it_BFU-$lZ$6 “N%evvA/2ϋa1/8LQ(۾,<Ev3@zQ0@@ )HHaz\ESΩ p7@*ՙgDJ&[%V!&hѶ 1\|zR$ mѝ<{ ,H9E6N> sIqZ5SSoHr=12LMW&9/j͙im=+Ryi349[ǚC݄ vǜSO2&?R8 g qq֔YNTYD>3CV*jn˰//ƃQ#ڜ[G Յ`r<~KЃxYyt$J(Ч5^J0/aQ ()=J3LJ І6xv-2Hvm&M $ 6J$؇o=, ̓|zJ@Ъvc?wItQu HJ4Q[E k UƖ˰XL/nR+YZ03o"תO%a\䝛 jPH Y./a~ m,q3݌;vtb27YAa Ua%aƼnn틌E [4 g 8_X4($$/D?, ryNۥ v~OscZ<:$N~Z9W^yCZ8 !̃XTŹ; cC8*`%³ǠIU'`ay/ɬK_.I, 3CoUhrcT5O\8I#w.I>BhǁBUI݃` iY*ˋ)^G[R̬\P76uz,lis}DeDa'Cb6ᲆJ@(.)εX8BP4! % #D~)XA<08)0<.)Đ&p9$R9;KQ]fq+|ӏ.:-( O 郆R]'-97u{:dHb; r| lq)k3WTwH^o{f'<[7 ?IWQ{SH<r_M/>*U8audU3^~K#tzĒ!Xc-HsZ++奪7"NH4?ح!'&4XLGf! +&~H.)N4ބ0ʈw|.#j2b@ X^8pFLW9]{0$Bs{ElEyU8no%,@1yӣmfhGkl*p+UgЏm1u8o>;:Za"خ}li/nk oV3{Zp?pxH^;ZdÊm f';hj5Th 6ɿ`å!Dwv, ٓE*RjIx1yX ֔7J =^jF^1f8ùJ >1[84Y ͔Z~jt#jr 1pQorvyoSoU3UhS;5'mBD,?ypEGA"1=?CQ=(Rra:l(l9 ߂^%!VF0j:Ȑ;:Ewd)Bm% fKۑSٞ}T#>"S=3U|*3 <ҪjrpbNkF-⒴svZy"=dp $RJyK%dFybO_+<+QC,l1o^0WW$!KM{럹3AqHb_Vƌyý3~^h17C>{M7'-JQH3*Yw(=nՉwsv&!cuC嚒ؐ dhSOT|b$-=% H?YYfQfwW%:/ JvoB~4I*W+S\QC R<&3pӈgj1؄%p@ kr .sW.H8l'ӢhYl?^2X,|^GMesK3GnfbUIj<ѸQ((MtQH^NyZ;t{Bq5Q%"P!lf29UܲcۄD5Ѐ T< b:˪ŸJl|)OH[ yWg.mSڈH6jX0&՜"6)#SI"(^ r [O%'B~&3BGLvwD62HA`!?- vl6軑q R,sކV!థJr%.BԈU.s̔0d:#2ct͗!gW3 oj<!d&",F_`zP1K;6>qbH>9qʨw9 Cg^s07T;BNh)$h ^R%Sz z|A.+LD'HJbSmTlL*][]JN6C|# Z/7)@|y_CEr`m>)u.Fn2Br TU lɩ"ʨI{ ħ xs#kӅDlmZ,rBC]\d*`zR@}>Nd o8cA k ŭF$wt1_ٹ 0(5c b4lH**;݃ӫ!._wYS*xvkqAqëeYco>zr=K~RkѓƱt(᭩0ɘ>4Rxu!5ļp7֓8 w!{`ctl/{5=T*o #2ׅ`aHR 3!J2u?Hc+sϵrdR[M]~,4;ՆߵaٻxԖr/VQ›΋wdvXZ|ԐS:֘wA?W\!xF-X`Ɓ\p3mK M~%'tQ\EhD:纊 VXI).͎GHAa~yYb&csPکZ9/}I4Ԥ I>(zLΠXa$ j}#2"|.hBPT*vټ/҅ p\&.pl(t2q^ϖQqJdeȎ$)a7Q6 ˼g&K}d9&F)MU>?O)]@{Ig G[0K6?MМW<1))^'*Â&C68֝>8Hoie=Z12R8.:x (ǍMM~ȟ*iB΋'(T8Ku> DTsBWTwD—P-/: mdfn^dք\.^~&yd!dYgV1gĽa~J%G$ҍWͣn{niVz:iI;tb9h.WPgY[Y FQ\j'xFj=)-N3t` [.Hz I\4t?7X%Ieƪ&lŧXbq53N+Wm?1?.d=ϕM-B pdB)Vp;S.?rCM:ԃ2vQ_:kzc"NPӓ5/.tף7Js3wLTXs}%iVFndrM867"~s\|EopHY8ǣIӝv$mGk aN#T7%2. FU#m ˋlug.i$GvѾD;qzN+ ڒYP8Si 2L X(~ MJ½)Ąě)> ,_YPznG`=>v|  psDd0_K$2 _~<L c,|4_ @JyTuwСVî6ӧzX I7 L4{*x&\n*`$Vr ۀV BFֺo1*"Ryxo8S~?SKTwW|qT2թrTI6Jl6|q<V &d(xtD3q$蟺j-}1J'Z0]j3E*uhgVƘφX[dF="쟵|gl[e&4{L`cQ[}$ *aSG:e(?OIW0ݔW߃39xvv/QUg>@/;GhR~4TU6{ugOz^ K[{L(/~hVF=/Ɣ{m 2:("GxhϧdR"QR_5 v.*3<=kD?Hڥ(/{$ OURkiƓg)[dcAun0X8z en  u=#:yl)?EmD,9geoO3EW` ۈFcD !oo-B2ٰ=K{(/M*t a7<+e?_^52b*vvU:L8:%f!IfVb*i/N Ϛ/b!L~hg_` yU_P6 >4(iMFah)]*"3V yJ ,0.Q{b1;{;z)l"[]}u -~~ı\ij,%7Cٖw{O QΡO=pKN5ﮗM<2\P-)l(AءV^yݯ# w$)Ud9p~~Y ,3z1>Ekr)Ov9w&xCxw N5)@?CD^oGID7v. 6:u |XKyv'aS_Z eجxxch[џX=ɀyB;N'5~~)|چxXa:sjq ޅ]6KzN~6_ 2ysfCvYHFL>A g]Q^zOгe#ƀMe?*1تiop9߁}?F>g3SG6L%4,_()Y3rtsXk㶸xz3r>3W9V.mʽsԣ{ (a kwΚ/ *lez[?/6:ج2H~\Oٮc`EP?Ad1 HpLyή-t ]}zLk8>dmڴ0.=#/Tr(ِ_+DDjO.fMVh+7ϫ=j ׭3i lg+tWMu\:?f؎n%|AspXRpW9j 7o-pu\I'M@ .}߶؉r (=r~q)QJ#_\У\$uB(yL|zr բAP;h0;Y g\\)UHdVŸa)0dKW LUX|X%PZ0.)ɭKx%’HbS$8?o ]+fyݬI2 k<ANBcn$\a |?t&gxk^1C\?WQX=8(IC;wUl}>>0_pq[:`{ZgD${ j1v@2b|l9X'|zu (k婆ʼT["fv*C;w.!|_AIkL:7%N G(]::?G.oc[Z:d5/7Q59#ZUo퀅x*t,Dty?hS-A,;7i=rz81kClLɱ@exn6e0Ki7CoA ~ GFH'$^QD 4dۦm6,/',:$:4_xL76xÛ;_%}VGթ3 YG {d瓅!"w{jo63`Dʝ8S0c2 L#b쟵lӚqL bt5<1/wIue6IC˸E:ሱl+p[v.}`PQx?8f})F!z p{ґŞHv̆݇V{OWDb9(5&1LM8P5a? >mY6]c i*z B +VӱGs,r@ u91-S&p%r\Cȧure$\5~@:ЅQE2u}ǥ=.Hs%گD' bRKN+{zԿ'?:RS*I.i2zo%\_'7O3>΢4Zܢn$ UGhoS@% 3ptnR~C*i{抹YU37=a -͙2/} FH1A?1[P,%,ۍOPłkxxä|9u @3z*u4ǀǤHh#VSEbeڳ R -^WÉ]yT;=Z=3 IwSOÏb"с{ !c+ <4Dia9!XWwjl!h((mHHi^ 3/-݉G9 kf.>k bEk퓡BҰǼP)_#?h˂v"'8@c\қ3V1$=#z ,wiǓ=^ûї?\a;B5 lImonCo(`wͨ;<8[[Pqj-׾Rs]%FU$ZHT/Btxn-S=b4 0J_-zd22<6mGҵfWzB-{fMXuAE2'%' ,~w|29Esq/<E<PF4kiW)'Hm/xwrO͒V,EaZroce"Ɉ%-%ӹ!PBɬ?'@ҽjs @ڸ]xNZ;{W ϙʦIZCض,2%^%sMquOH찑|-u%d{ 6rFB:#|jj*(8nՉ'nkp)Oʅi%UZkhNE,ar RDc}L⎙X9G$] b$v|uWFXO~A%hxgD !j.֌7R4x+ai€[X;5:cϤh*kb!mӸN2A;CO\Sh'(g\شb&W_pςw_ښE\>| e3S`E7H$evx`_W$p/O6ғԄ4<1m~[u38#P.M|j̃cu|M=[CВ"A.t%\~=HO`?Bwֽ-W12vfo(dGɸ:3ɿmݍU!q h7Tq,Y.y*KȚG]L6"O%XvⵅkEoj`z-茺S-רgVAMëAQ9 += {1Vh-+o8j&:VjU [y<6K(M˼k`42 Qcr" X [ mDd3&~F@ yhqlYPpbD/lRV2mڡEǁ٧$2}#U6UѾܛ疄}z s?>֗?)fPQH u*mԀԾ| BMM-UA^;r$i1QJAr 4Zچ&Sr9&䉷Tȭ;~nBeh'mrz@5KZ%c>{:{$5dA@#l@)9Vz]Ziaa3EAX;}F˹Y 9㬦j4СL(p3`1.Sy !hH"CYH*W 6m&t2 d۷Oi` IQ#n }zzShӐ56뷃+]F1|Skn4}9Bf4^Ff]1 aGΎ{1n%fGdpx Tucq;[Wņd]i J?3܁$O]PuÈIWKh̽{`c5p-4cS8~\G1Le"\PN:Blg^:";=l)}i 941)0?'a pꂋ=sx3tSu]H_Do"f|šqT(Ip;M]sN[0!IZ-qakΟԵbzaj7i/9 :I6/%%~d#,pTlW~Na~bqmyN.K%#4J^ A|3-XV 3"LR:rgBgG7wW7T+ $o1J1Y]K-O$Î\:&԰pBZH'l} (0t`gO*_M\R*{nLrSā+Ĥ`dNEb9 qu"qZMlpQ*Ӓqr'O1bV4E+EDUˑ+L\ܗ{\+-Ce\R#+"k~ToA)6dRȂMa`oS OdODBOU}vgwBeCm;!s\C ->G." ${'aLH3:m)ɀjfՠI9"wGE~_,s !&dof iu%JV*&9:t5ֱRMU0o&;A=.xK L9-v\=n%\УN'HǕ'}Lv[qq/-6>σ fXDo\9SDEP ]ۮKRʨE9}9ʃ1Xtد^pr X{WF'Z`CܾOC7x-@gDD2HTF#62mWg+%!>] v%qrclp#9/_ bO9%@ jTB -3JҔe,T1ϮJD{tkBE9[v%H2٩D5*O f_0EMt) y+LEpCJ̷B~#F(fP$F(oyes8FpzTBzB9SXg:nr Avr9d@O筷JinItP1! ̙;B\#w XfW Ik&0:u `~1Ȉ$)6-#hkbԆbIqF7!)xI`MW\d^Z7!tK}i v.ƾ5c/3/P gE eMľxɏV՚<´-44G=k[&gԗE-Sk"!0d-SОUZJPc }_]W*yW`1.7ʍ*C)V(5u76uM;F?aۼ<&}}5aoѽ}_nۨNzwxn?|R޲/o\N}](ֿΣFN͎&rHFk-knxP(17i[il[ )7z!K_3?7IbN>6" z.%惡zXbU9 HYl"ӱ%.}Th8W9C>lnq H+_>A_+l GM _L5+)Za}:rƛ\bO @K#t&Gy4,\i]q48ԟȍEAǬ9GҼS6K{50T)Z@H@ǁ 7"p\Wpu# po2Bou3:Wx5< p_``M;kJm⦭ݤOnzB "[FO%fDrK9&-l\khr(c&;LΟ,NGLj4+1D)Bρ^Hd,1s'*sf<13(: :=UT wXI*|&3aԙDu)##=d ƹSsC-W^|w<{R.ܠ%ad-3 ˭К 3n1ʧ󎴾.Nl>W5̡8 .}7pȬtʼE췷*mXq\CK|HH@y!c%pY;lm{{2dQeXMjlljd~n$BW]R,,^3rc 8I} 1_#{27/_- vOm_3^@O,PVHmx5ܣRiDܙa⒐wŽL89q1+fTt%|Z񘺮)4.sϊ>,U7tB4uΰ)Jgg5M{~SztP=+|'rn忕S F O_x9|}+d P%G2b5ة2W/}&ntQ(X)*vz#QR\x%؈صPHbmF-qoǼ 4IEG9:@J:Rr:m8Cz&ԭc&ElxrНt\Q(XVUohDK$>|~CAE_\kFž"],nY" B8neڐ(y&B'>= 1Q֮cgG LkP,>\6XUN?KV筁+w0<戸FTfaݤhGM/[@xgʸFO/- :O݁6 n 4_Z0dڋy`A%ir/ e~exBJC?c\B8NjI6?J%2Q`f{QeǪWY;j)KÄ|["bniZ>pNTW;9@V3LE4!`'~[ӖnZJڳ-WWd! ERg?11ezYøԂ&DԸ C\1Lހ<Mo4I(VV}?5FmD'3tL*LZZfbq)tR+<5* <{6DY1SWSφ2P}!S-~>q [q,YK!,MיrGïU)Tpr[}U)Fj}C"Caė!uY'ofl2:SI趰qu4-W:Nj Zx0E@-lqN0'@GN1o |k<\^4i ԍ Q0ȉiYӏ"L! p, b`YϭnCH -B9%xarETbvS <0:Jf=v!}m CFr&H) gy_Y^z:fی ˋz#~ё2&z J;3Q*LkʹT>Lxcl:gK_-T *w5KϿ qS_jP<>zQ\fvgGRFԟ?~Wxlch鵉<9K>u_O!Vkl#R*TDG~c^w!@!+<l8ޟ,ldT :ŽCI{\vvS&* rрk͝)d=.ڎ2T}A'߶nUAΞb6Fr1,r&DSQV/xJC' /$ +z۞j0X+, dVq)Ɛ~7%VFqDsF\RYaz4j=L2:RVh ZyXIoDN*c\[)Zrc:F/Qώg]~$,Q;EgXݵ,;易S+(W֤u-"`Efq[dlP lԥ_\}+ĪDʔ̩pE6G|vƢq_[WY40ﴀvEVd!t_vXz}Qb9䄨,M:nX73e~hHW<"?<gIO [vR噪q mw -CT1ʼC5;x0(lLf/ {rBt6ߡ4d} v`6$rmXX!G19_j>y)bUb#IW_^S=oK6H K:,O!Vܜ[xގA j |gHmvc}>pR2.pѢm]_X]tl Oȋ3P7>* K^KHs!VilROSş h69O<"O M(ȡp_3e?ǨMB;VMG*_fkt5Ozvȯ \}0\[\::rb|/QiwLGAo{ɸ,+܌~߸ |}v/ 4cwC\t}pIOvgD.x5y-?'8Y]$|J{ e@BK;{rA*1meWa؋a_nxУH#_h#u+ށG& ?N6ݨ>U; @=)rnLXx!POĬk_!Z9ٳsPg=Qd_s]A(C34ơI>v`,5'_7%@"Ezo_oU!QΗrmb,.3w8!!ك#v a Ԣ ?_%Ғ$;dzʖqH;jn+pń> ڦN,-lϐp2gȁp[ƚFq ǖ~ McTAu&3&Z;qz%"L5 0RxٔEqT{ffn;epv\8u|/vRkȡܭNqRh؁^6brw%31W*|y%,}Yd#dn*&@ЪKxH1Qɴq 0?Gts'aƘx8xx͒%_Ѣ CkYpOgƔ¢v+ "t'$TNW.}0\(5{hDW4P)io sKY_tb؆H_{H ]#]FnM9 EMg ScV)t_Vb0p ے}v} P@0m c-{dna)|1{Z´˱\x$xS:S9e!D{1$ʮK9=i1lh$E`p3o)m&4̻Ï&QJV6z{<p335GWy2_CH2x.i -' tfq,!SE8!xЍ4 d}T/}_lYmO`vk ֡ Sw`׃M1&9"SiH"KLm7PU*> p /W 1Ƀl=+*K%Jh6O :XŚDUL~=uln|T+OG#R>hrX3U֓xP^-*(dOQe)]r#rFq= aFP91dtWt-7 ćԓ~̶b]u{f8)'4(YF^8AQz&@Ls!d?Tޤ:(L6Дcy쪲H껑l:/flx`r(GJpSBIkpSV]$=N`E8}Y3\QmrYhB(B<r`q9>i ԍx G3Jz,Y;Z@vnUzcPhA&91#1ϱ Bovrq--`pS(..+)tZ-Y6mtu?C`x2@)`xQ|7>E֡mۋk@]xSqb*sbw`1؏VquR֚+"l 3趩\02޷?n&gq1?F^1FHxXHHl'otkRֻn `qcoMW0`^Q=Z U&.F֋qeËæܛ 6Ibky 4oXa*wWޖ`JqD{+Y w2 BMbıP!s-Iڐ"ZzZ ܷ KvF#L5c gs usHvBWCГN] W]7L'N*A֔-G PNm!v^>KF(F?N!L}h}HQK3.0Zq_ZxK܂?z YvMXTX &g3V{Q`-.38ɨ=XcT!@Nu|aUtRimb?$LQZC~^FʄO j$X$C q)V׺ӭP\1/Fa'ײX&>((COSOcU^h8.6 lDw"TRҙnm3&<' a+ۊq+2;c-УZ޿trҠFm^u EMkXjf Ip*c =1& oكiWԑ\D9Ge9GօWPO<Ōx ^OZ륩<n=pT^>D4 c*k$(p2m0wērG 5<~/5JEו$]Y @Efh?x%G+G(/1yؖ~F|u"e4 T9/tS-04.!< *mL;Oz| S (jKrɳ FՏb27YAVXjko3uca~;׷jҀe# ȨeVT:eab6t.}p({-s͍5)\< 6FKa<0svTpiq^S5 ?宇 ,C'>1iO:WNg32_Pe،W{h9p1w#*Ľ@9৐[gޓɔIʞ>Qɛh$]7Ƈ6?o+CE.Df|"hB9i-Z#C\|`3^ Lʤ 0O/GcC5f@εX8BP4! % #D~)XAOG21fу"qA]o3C_3p7Lplk*">; r| Q1*DO:䷋:Nhsd{7~l8_3IPj U 틆>~ a9% %WKCk =ڳW*B650X؜Koץ@W2#͓G\x@OQ-=,C/>=G0tz6 _9m~un`3L<@1W8WΤZtq~ ~.;_t]$29 7cVgF|@1߰9M|mv4 N _A9 ,s)իfyùŒ)Jv˧9 22"@+F4{OMPrZIܫ%`GMu-mj)ŒC,P GpջvuH. + 6ʱdvo&c}c1h%S!~pԄb? R==-)e*. (,hD}դ<%=ꬑ;#S Y|#B;rF%~q :I6'!"ʡ8R.8G ep=ֵ{`0xmY:e.H5 G\1^ >|a^VGf%o̯Uk=Y#!s4`.I q4)Pf?Om^C)41.t;Yj؜Y@$(8- P5"]ZYn`$rRIh~hPK7 \ԮegF 7EJFH7U ,M0L Q245̜?c! !Bsdup A@3ɦCZP#tMst-xH2fb0/Ǫփk8M+4PW ,gzF K&L:O @şV`tXrdu꽐yE*(I([P @'91Hfa46@6]WEA 侕ĩO~ @D #͑g1 c~Q81O-~ny&nX^I;W0!Tْ#>b76'uɼ eLaZ{?fp图rF޴SK܈㶑_Ʊ+M] Roa\_ӣRBV0`5R:XF67[aVsom@k#D@^è n[1w5x!}J,({X0B";\3L}0[9^Zɒe﫷ͮյM̉XSCC')1,}]я"LOD-!Ph H%}{z_'לR,(+יMt/Yϕo?LT$Q ƵO0+6d ZÂ*0k.(qUf,YYJ_ s*;2cPOOn"jnaEʑ}Wj@vQS_Ymo3~3r7AZO)Ol~i!^; HTJJcөֵP@d3٩ajw監f&r0VADrt\$Qͯb\VOseP?ɽ/NHf4#,@r*|#K TP=BR=u}ră8[){{%,H uTMٺ]BB{HF |mڰ[I:XyӜ5}R<&"$Ԡj7)C6ad xU]VÁIN١28 ovq1 35Dv~1a6ѬE>;FS`m9n' =- -3si_r7ngWBARW/k/갊<Ȕ)Z$5w ?x_?  07H",P؁y ?_LJf ~uz1/kϜFG)5A;h(42٭੖5-٣ ?1`4ͺT=o/k675v>\."mwqCܛLR46@$7#b6h.^-bf|q)B~dk!n&Nu$ҬÛr;Ƙɫqk[idP^pYmԥ8V,4HO4l} j.ܨze~X9 r:enCt(_<-&Q WlVT3E#fۢy~G\+fBRǨ\}n3a>/?)&BJ]d9hXލ[]d[se?0JZE,U)^Xɞ)-s4"-\[O{밑an  ? =¶laW֡_MBi}=G^WƬp]˷dPvEUӮy#XQh\OMu2؏Uι" ?BtCʤK꺌 q=\rHͶáesxY*[4)=;LLIh>B\"Ս ԗpjw&GJ>G+vϕejB&`7Sْ5j}Ŭ"ޥQ@v*] Lj> 2P,̥(, kɯ=,\ c]"`lhQ}0<5f}[zwW)t[fIO99ܑ'^+ޝ<$"P!(w.ّ̯b_ 2,NvVUJ }GE ѳ Yfj{H#Y`{z78 *ʲ!E.A0=x⨇Q)U482t+ᓟa9a@6hAvtaՙ{ੇ/0>Gդqkaф40EmȭH}TnMLG- a#Un3ǽ"=Uڨ)Ę}V3\~"T</ H9fkuc|=g bTWb鉅 9M0 5rta/߄2qǩ5+4 $}3=E/{b:<>4ru߅:&uΆ: wEVtQQ< tyҕ"Ll_k ttH(tP?J@4Xm2$dHUآM)Ҷ"y3ަ2uqaD(Bʴ(#4߬UT-^5@]eB~z5AqZ*eO,ii@w1#˜[Է+i˫|=#a;#9v- t jo:vK1qEWQŢ' NL4Uy~@%Z eجxxch[џ`*&70xwP Dc|`-b!"kvW(3Q+82 ֘M#*sZ PfA,WNڽxYN-KKiUrۖ81)0%\F(Fh7'wl '̶V調@mP{;_[||b$"IQ5;ضCꆕ͹έh u=W vbqI:b%lReBYR_/k}P!@jߗ7Lh%oSY[mRr'ٌyD%*G;)*R њS?þ}&Cj͓]P*6rc?VIy,U>5~U^@>La Mڻu)id0?8$ ?SU u2!ǵ>Jܹk,3~JnAIkL:Tꞓd6\ [dMX+>!ʠO "ii }@@99g$ Ĩȗ@o^"yT[r뗕J6=f&*WBkYX$_ y) ‰"Đ@ lC*shOO{2Y ;85 lt+"Shڄk n&9SV& >]Y< FđUO>AQߠӪzZ 1]iy:MJI㫐,X09@;XCQio<72 d(NN՞HT]Ŋ>t!9eRd.Xy 4nU%I (dQj4Ɖ^q󵺡#]@dosGl24ٸ⿒UuTO x^^#w`fK kL8C|w+Ng&;Qw$J!}νΣ 7X@u|tv>^I) evRh&(AՂ9̮:P3L;isdQVCf؜q7bŊW=o#ЄwjۿbAלnpEZ9%[`M%8cIhaZhdiܚ`!:exD0F Ұnm#q(N0B&'v2?DCy<L),ܢ }8||jXV:Pkw9\3t0^hVĒp"eGY̮ye3D])ڤ"8muYspD:Ls۱ߌz^dCV3>g!Ģ_Vg+1AUOKM%,brLiх*>h~_S/=$u 5B[QPߋ<}Zذg Vb[{&CyF17 MfJG 5؎j~Lft뷮ϑH#`aSzX8/?N I ~:1:<$ߺtBaxtOϏzl2곺}a5RuWyv ;uKǤ_>cU?SOQm£öQ\=g˓~QFl&ȿVQ2v}/'H\3tQ )2ON |Tւ(x;)8gmt4Jgl~lS,sՏ<^UbAj¸y} ԌEo*5uRGb c!*L%WpD=n %9Ff4z@37|ӊ@{Vm)Xy!*;V1XvucE:jt#RDlf8,'>cLɗFءejA4.AY^[! Lz{|@4MUف5r~&kpje׃=)Fc$ޘ!PRNd}ΞwR\m`([SeI*Z,X;@lsԺ>9ތ"rsuG$="""hq2x{$mn_hD ^F|NXY/PQy"dL"f+U&QIh=yp*tK_| .hhe%T $S~b7cCq,5ênAD{T1ȋ:9h9S'S =ʥ0b$S>WjIцzDXkA"Qua]uZUlRs,h^!!aitZWcĴ<+Tf)"-Եcra)N #B?NH6cF :E֋rj<Š|>Bjobj3{H,>N^A INxf^}Oq>PO|k/0']MN>(F/f:vl>v \G!>1|zh(ۅ# +2MUvma%e*'yjk&ëWأA_a>%H>4K7 pJfrK@;'\ ]:F EwyFj< Yf LdurZ~ sz'Z ơ|qB/={3T^#- 8 $J{ sˬ[`l~Ni䚨cÈ%̂yX%n@|K4:w[0GW`sN\A}9ikPvћ#P s`O$ Hh9\T+}ψ$`3j^h-*͊]r3m&ũu.aqTg 'c d(N?q|(urdU0\XXk,VkUgLNj|2$u FWԹ:2N46jGKڣbx]*]^C&MҞ!-<ǣhQ1R~i]XP ЫI=uNȶfTzژ'y5FBĘcBV ,8F{Ssl^͇ \F?T'uJkVC z_`, 6lX e~Vil)6N{E[i6CPlp&mDi]Ntaoȁy0ePa{F[/,ϝHJpY8q>XG] Z8(DFm Mt$-R'3xsQɱp;vK)mERK^3Ol= l?Rs?*p}.CqAw]h:|*Jk(SzG_|φ /R1 +4lEцxʍW֨ (KfPVƈ¬vB(iM&LK n<-٠htUV}L (t20I6xbu|ˆjy̓ LjCkӭF}otQ ,*A|r: q,KC 82+#[߰9țFwS"q88ȪnD1͕?Ѷjx?9*i0]u˘– Y;{agq#&CƟ?PaĎA[?wmi>9e BܕgN婅@yį}#%nVؗjd>;uE/R vuX?\N}5{'j];G:/Bs; 9"+[ۺ$CŠHzQ* =ݎJ lhmp.(ÖT(8 ֊?Ulsc9rLBhPǜ% aQZBWDn;Z<)4PfhXI6AfzN9T3Z(ۆ'Qn@V'Uo/eyY{eo b|qdq\, D?մ rq ݐH,kzZ }K^M2|*ֻ0K)>΀$j؁yF*eRF{6,,?ԣU+|]= .\/+Y59pjO2Osr!aDx)GgF 1A#[,i0_A]G~bo>x|82^Ԉ p(lyY\?$E/ﺥ5{fw^5)GYH% "Ӓپ"}A{]xzZ%C0".M;gD QHF 6 aZZHKeF9D%@gR)cUY"?XcY7RXJMzC>fQޗs .e4LUe/~[ F^ <1.ceB`mmfkx[y!b w_L*bвc6J^=$hU1u%ByXC‰ !Iۄ)JMihOne5r`zT<ǟ]+ SӍ*3obth?\呪O~M 쮘ΟdZV^eÉl\.F0[Z.RUE_NAs-W@ =BY`QI\X\7 3y΂RQifsiM.{AK olcn ]Wݰѻ!/HTmD$rW bpq%dɰrMÐ;kɔWI -W#_sa/TXN/lmv,!c4qLR%^jV6 ,~zZ y'/7-f P T}pis,"MEJͮkc7b' ;Ld*éKJ:?t6j41? `^sI` :lڇL8;ۂR9[i 1ƺ[YQmڝkŕ;aLof:ϰ5kuS:!KPpAjQ49Jvr}k)n)ep*L*8kƞw%Ek7B_m{Ղ@>:m:Yn.N?^9,LUiom|v$vt&Vc}H_gU10]A:ggGv|W5C rZT>ڶLh݃g$Y4j!Su0޲OZa}B\ 9ҹM?Jpb"ŕ 1'H3+0%Ha,^?vg@g`^?%3$ =%k} sBUYe_w%&^pZ.Cy j Dz"iMGM9#DzYEL0rq0u\Vж̵'d4a]Fzչ,&qsXsJdYܺ]n+ p=g_#.3ݘO1h%6>r~^$cb[2\| ^^$B< s]My)Hrʤɰ1[OP<'p+OF.`TAoUVlM#)y}[j$W z,H-nNЮ&+C `::.zEDfNzQ0;ŝ:Bo+Q଒"J]'ĵ"r>%pvu%[o/M1&ZL-L\.W.F32M(s Un1q %jΆ6!6 O t0* Sz_H]rLn&Dr\K_K3FŲM7FLnq$t'E. wd"4hJ|p \*%*CW8c_s(Dk tijbN 9SdXT(ͱe("&u6&3Ojhͦ1 *w }L:pDCPWl1EmXee^/y #"զu-.J(ڣYWrђ܋IhYl`bs הi %8T J𠽢S4PUJ->T@c='!bl6W Ue(:L̍_]yZHQЊ\h?بB{mQO`a Lv `(E(^ :\bL9xz} #ޟ) ̠0̦/IR@$PSds"##Aנ 8p{u(Z7i#5zϾXxW9=ZD̓~dw0–lIBՕSQU 3 6 _P^;2&8#:sGmAB=,I!s'IAcP7_+bDxۦȊ,/o‡7[DD6}x?B#EP ~iqQ/ ,&4GxR%⊅6̑̋(eNҏp4ʮjbVf,`wlEZ+gkrr&\ƶ5BCr _eJٓn#cUTdeY0)N >#K[%pd *bw9O_ AMa揋A~c`ϙF|gfB%נnyߊϫXK.ۏ(˓ e- mTSyր#PHdmWWpLgxf\xOO6[䛮9w Ư@൷UGtB # wg%J`<  fݘ, (3WW)Yy_g U !AHM0- ( @0 +=I[͚ 060;uG=|Cz?4ˢ̖Q{}47wwe( /B6b s*O[0`;G*+A)1q" HGI42J7k][ WBCN=(;xuJƦ!O$u5< ]˱7ߦ'3S&ExT5n@Y4Vuc\BRudb#PFf k: bYK w[w#G@A^p)(L X"Ke`0npr׽F|X0FCoRQO˾nUӼdţU/ΒN2٪=ߝ$prR/zT۾gc ;,z5f@/]a>m tYXHo/%'>hԬ#΁ΟH*9 LgEW78f/[٠c&gŭ-+yas o/Ajf9I'>1~b<82z=oecP),"ƽߒw`εpSŪ)DKO \>UwrM@&F= 7b^ # Iia<_#a:4 0UP_j]u/v݅80Tۨ銑-%CƒG%dQ\]`?*N#VDӣ!:BgkΦ;7V`LzQ(?,X7oTs?T،Ld󃱣IgQf,i~#8sGYx.n?|?Qo ?Tn6މtڵo=L@&FH90aJ6Ȏ;kQL=:F+gf7@̊⒖bXUu@hH ~&Q>=\a#aԫ: ,y F{=ܻ%汁G\&(%uBгω<9:gWt> Pw$CR=!06pH:ʏ@9r-ui>Y*>,깺IG?37ܐK9ϼfУv꘠Ю>F3 9WKY$q褅2[+%<3eF{eXerc)wNJUC֒qV@۩>^=4|!'C`ϵ肆*b%)`Ə"?:hv^/5||Fw)k<~fؘܳ2ɢ +ZEo.*7k~Xq9 kEx^ -%O|5wVn2< iSv ]ML_r/' II&VGcM;tў@4u @[ I=6s=@t[fq? S9S*uPa^n/ U|=oGu639F l.vP9~ ̙Og zj^wU7; otL= ",SsYKPmMEll< 9^wP.SNWR0X 5ljIsZQ'CcUzk{ 3!>5 ~`Ӊ"Bqm]z3d)wъpEiBHcD2e`LxShڦH|л&]RI n'?|ᥘ픳/rcjEO^7?p쥦wPLc `g9FMLBBI8pabQuMW+5P E)gEv&S}9 *Øk\)tbp8]6ǂOʁ(* qAU` 5 |F?)LK^&1 _u9DQ.J̀zHEy'Y{L;^ hcO8=Hu;,_gWTĺRUDc>sg3:Khk+ t?\mHl}D6 ajQj(m"@S020m*u:R::J.#ÓkEh4Åh/E"=wMnCߢzxK Sg skTXh-pgU6 &So_۷8r[&wC]e&a TRr{C3P}leAH"8lqκRp\<P X.S#NvP=$m1z͒Z"v]Ϧu"=jTcpLxR!Qnް&~qKոB+J kdVk&OѢʏP`A@2+nScf/v2plNnwQ[;1:B`HWmOn2e_T'MPо,]{۱EWS\ Z 186U̩+ , t؀Ti|qZ+^&lZD_i L2\D'W-ʆ`2,A^aOeX'_s^:0 bd f9 xrjfE0A!>j4Ƞ7Vmup\>(T*-9#LLg7[k+ʛxξ4hh lA8Ä|.} ~&!X %n%2AoC/H\PMn^\GCE(݉+M 4hf|M`tZT!<# Gjw4f?{-Zb3ؐbU#8fl/j[\IO:Jd&qK$ 𬦆t/>}jE\\l͙5 [NKNcRLô ˔QEa]شZB]2n; ]BmXm@f^oבuUx=k/T(qzVJ1{K͟ Ps6* `n냒Wl"x=|/v@Xaz#hPnKBSkSa+qJ!Oo Dyh1G{VH%؁7@C#mF+y" -lU"0c*a 5Yҵ5mgBY'+7xMNVf^"KfeG@/rbJA-;X|aq60Po]YyX0祗]>uL̂0O%* uA $sZ: IRߏb58ҜjF& P_dT=y!DjG]lCrl,!!nod6ã@學 mc:?s6DK0{nMgk zYXJH]tz ι!qtR֎4 _g\c*hF9 $ռ+kv޻mrM'':ޭ1  F@0( C"MUo0g ӋY#}Nu"py6? zMVJL+L`f OKdYIE]>Ng2ZM<Ϫ.mAil/[7ȶ_\#뀞f!zy>3s`/R5Ui,GEE” !U%:o25Q|ZETǿ}σQniE'*[O*UoYk=i:=ioFR*M}H.]F ˆa@eeE9H%3KlQVV_0e׊2u۹5"hu:]~OZs~ǒB\Y;oϚεj=nsNv \\̪ _27ter&Ю&ڏpu/!a$!\:e[3Z4 }zVP:m U=<@@B",׫Ȼ=yKTMu듹.D>$]% <$o/kq&d7u|ψnY>ũy\Mctчi {eQaD-p oĶ3].ؔn%h(Û AƈHDXSaQ:+Cݮ?uP*׋rM&sV7%B]mady 7'SN5 iq?ٿ G3ryO{h-ji&Oz]K CP#[fRR$ѷ>^Lh 5xԣ]ND eCsVZָVSQUvwڡHS UJ 7Gt f/V$YSo"7'i^fߵ.,KZGHqk~+~Q,=5pbK,/n໗AǀTQif5T Ryb2P?J+!4 TL|~sr!DW)zt~˻!֕n M6=j@|afndqD{UFu!Ʒ!]*A5# {rVqA%-&` Vg]RB$){C2'vo-YM,xD"Klg[-RQ1$c5 |s WhE󁞷#%֑/̰˘6yB.߀vdtąaAow"17Zm2帼U}+Ó;Qބ37 Дp%lv:vmtաzVJvl]<Ѵ3D1fCƶ17#$ȉ|PTb"APS$t2ܧD1%8HL:Q`i]uy!&kjf#%3p?\WP@Wԇs-@>Ч)U-:0GR Ά<Z1ƣǿE8Ǿt%6SqnΎP5n7f,xDW$!) b}e˂|42$!2B$1s/oț%G1~ArXUѐl3G>~ocw>pU2\ :C@9>$I|tJRwxj]4f1-a`dvCo1ՕX'%JL♓tҶn{2Y>'4zA :mĵ@[3#1 jg&zXg\ˮjN_rH?Aؚ_A6kJ7ȣ;!P-_J+52j<릻HΉ5ko@~PV$[?P7z2+G8FI55Dc=_Sk51p8X໧cH1cNQ[rǴ^xKbG8\=VoD/y8m7m)+竟* V'- 9ыtq %fG`g -"߳(4fC"*ڛϋf:9XOhmun] i>' ۹xۑ ;+DAC引xdZf/rl9$pZTD1JBEe֋mi%=JYV6WÈy%R03_^c$&b ʣnZsf3/yzkn!3E PgHZÚ"(%b/&Y[lh4裂lڬF:G]uXp>~mH$8O9 VpDuԇA.~U9g5LvԚ;A1+VWa,LȌ]H_mR.zD0)6S11uF3Qo ,Tzvd DPGi\}aG&~gt{@/5i>ck]dmrՔPM(:ݪp[UH DЃt()|{ &+=y(öC_(9l,[!'@;V1RT΍K"g4l \AMFRoM4d@4>0>{Xҡv72sLBO""`zP,y׵nH Iգb]_nfF@ (ՍSj^z,8#)#3,"-M]o")1Ր0uvdֺ0,oNXTCw{?&Zxj&=͵>c<M۶f:nH9#.FQ{\ Gys_gګ Ѽ}90$d%K^M}_}Ek| :aYa]<)[ѼŪ{eEVO~E,]/'46m |pfZs$6 - `,_Q/>K(S @zb| Vwd9^Q)#ԥ\J^\A,MfI AiqgP,EuJdLxo ^\Z8?C=NgbCyӼ!V&r*;23i͖GP .J%^h;Ua!\^WCHRY W?[M FIOc~:byobu-7.15/Applications/Byobu.app/Contents/Resources/Icon-72.png000066400000000000000000000161511522352767600244710ustar00rootroot00000000000000PNG  IHDRHHUG zTXtRaw profile type exifxڥi# >7q=]=9ǟ3psH1Vbw|o$ۃ{[?bb_?x7zzo 1dGb޶: PCχfPgm୽/?q" x*/᳾ى'n&Y|)TK54t߇6˪f=MX/G/՟ɲQel֒޼ͷSg85'KI4HĨċue N# ɾ*/?,2R^3pwn9' )(eZ媵)E4Q2djhZ6hUѦ]^z!sQ>mc9s2larʫd>nm{y)9gyJ^ ]; YjbԺ ?JϿ2ϬqT^sFrMd\=:{bOfϜ,LUHf9)r ޔ's+o?[ 3s/oʷN֎ ~T4rʣIV>82km{o]aDnp;;lE>d7_wɵT9+ ؊9f3Xm-4K/nDxzxg6ln3@6K}I6yYF:X) {l𧥵; 3!FNlfYpӭlkmĠ\r8eON}6+qn]*ڄ1!bku;>{YHi'4Zk\6GU(\|=y >L>%R\ ,iT#asXL#P]}G˄tmK}ȯy2˺Omi0=iY|9 u/A)BPKͶqXq]S3-'iOg ^;R;oAD0CɛAB PЉ4BDm8m3|&l#"=l-cmNt7N|O|t4fń !N8DJ>l.l#Q$r 2u 8't;>C{DD.= Db.`@rpYyw( |}#]轂 9Ja&¼YAPb %zQ:RuwbmKgr`V7VֻzV<7-0e|xXcz#e%\t"bVWL<au_Kqߎ"(Hܽ:,R УCOi J edP?b7u* 9M+A=  3SJ7M0.XCdxU]#JnjqS@ o1儑J l0mR@FG8Ů= ߅j0yr@NN&mRSj%:C_1߸I/(:M.CQ\'^e6*y9fZ:nD3 P8kcF$7-ym>gZ4G >@`Ghf AY~)*l⩙ӣQ;Be1%^En+#r -,ݪ4, Hc5{}OXAAqY\tu`. d)jhae9[eod;0u})x1R =`€z%9cfmF;˳}bwcn@ͧBuehQuw}5s-Lih?hlia񃲱k<)hj UЦm]VF3PKJ9+xt\:#F2f+HRi%Y JD;kp\lo`iPsK؟ZHVf/W*QMgC 7ZsBIT|dIDATx\iXS~OB"D(uTGP)/REEu(j5V,T)HUOjE,*X8ZǢE 2$9!Idׯgge=N?'@'mѱNXo[t3<2V'Ǯ9BO&3@w@FB=CnDYO(]#Ɗe`*kKP(Tbt!IIxriEPi4Yk'յȻo3qv1! 7|_SF|O;}b q$1s>Oi!I y;eP%e}?yRoN(pcV{iMX2] pv$pMj1醴,Hb^FU{RŚg]jL`H7Ŧb8v}03ץ :+$e7 p;|p_~>#='A).AHq z~:ץ OlL+ow]zYU!}@KPh_V>ڊ@ìŸ݁i:IVдٻ/i'@DZDeU<az3>{Χ qٚgUy]h$bC|(lA027׫`Ejɮk#'sGA̪b&֖2!@ i\"Ez#tZ# M2=đ ). yf ,Y.$7\\S .>8C>+3)QheK GJzcZ J @cQG~InpOv &KN~ץG!^{p .ioܳòAQF\3_6<6:7 ({ٯ}gTm瑜V$dמgo^%7urm,ĭCp %(so-t1lNjk)Dy_ @X[ҷsb<%s',=8Cql_U( \JM2EZ׽j$0w"FEwzP 53!rȽ8lRJ8p^snȪ97ʼ=x~SN\Pz@$> {U^Sn/{/[(cV6+wW#!b޲`DTԩճ:!u"%8V _T@lBVQUkd7zHj[u,g'f#ݛ(iж( jA'7KKX߫ "!ʾ.r\Ef|?%~t0^ew<4š͂O{ꭆ amq1^d<ނLL>NQIkd}.&ٲԄԥވ^OloNW|39S&($|j֐6պ'&O +m,o4 935F(폊jDgl2UT+ǯjId9\7B3Ę&FzȠْC[̤ܧir jzj{pfz وXꁙabPR3,)9icߟ-nm׭rRt6IRv7_y&I/At+ٲSXI`tqN (oE3@}w׷%cH؎pIDN,&KsK'X*1{@G5N_TZ-FPi$@,ٰ'YzObφ_^ʚb4*xCgߎÒ@e0$UT7U:4kܓSW.kOօ K6릃>mY|wD?R9FPؽHv7,uU:N|B=25S_xYYo>a١YlɵAo; "KrS{ IRgRm ;A7eWlۻ?M'oϾ]T z-<$X},Vks#lU;kAn5\y4iêK*EI!+t*NDž&d@LVf5 /G/IƐ_K[?}+[qG2x\ 8]YKشcVMܬ@2-#AO&4tzQIENDB`byobu-7.15/Applications/Byobu.app/Contents/Resources/Icon-Small-50.png000066400000000000000000000105321522352767600255300ustar00rootroot00000000000000PNG  IHDR22?zTXtRaw profile type exifxڥm D>A x~!7ko=R$D&2y?dTmn,ߟ2~~ &q(w~5P~{K@5Mm[Ω|"ߝg1n;)nw _s$]/b?^;MWJ?>.+]ַDzq"?]-/\NNiAuLRClb"Ons^uyiBQ!8` Fnxbwηęy fa0y _yώ[B}|q! A+&c7G!Uy+b[xN9,m޿UVɤs!@CRQ͛ s-oQwf͟hHhJZڪáE6u:X}LͬJMּ6xuuݻ{A[o{c0`agu٦>ǂ>.]y]nm{9Pԣϱӎ~F(QCâG5*?5B-HOԸ|a* .:_̒K"w1K=S R/6[)H֐ cOq+rυD9 ߠaOޜB2D[zoe}8c[X(i%$UfJ<1xQc4BN(B_5ʡkI%bڱ UkxPXQ)uj8SSKcxΪ6.}~QnDtsyn9MZjlxqJNY3by;O#f1.Yۮu4':lHԧo6ݔa~4yO( 2lB^I]KE%P: c=T(ř]]V8nRv !/tt0F>"R${G"Ƣr 7EWe(sƯ57Dy6Jb&_U͜g7}O(jd1b;ӥiPIDyy4THܷWSt=yh0E:m]UhO'`6[[OS/GQataPPX>R/3d\Bzs]1xZJilGzf]ݪ#p"60dN>}]m.%DFD.* ""[eZ5ѵ e!'p&Ɯt `9LWY^&s;P[^(.'*G-=z2](yC*ɌY} 1=պ|.;D{*ǚP,܋ҡVdEo6Wl4(FnS lh9Tj;`ŝe^HҭayJdG<%$ks5l@%m*|Nqt[ 9܅̸,5/ 8=>PDV"v[THrX_{~1lVt aԣ(AI~*R1ѩ:Qaԕo6䈜@*~o86R u/EWX} 20Fd9\Sbr`Qyi=c]Sd]JmؘA8Rp@*h2{K'H2|%W^{sU/,s*QT>C~Asmf׺!$#E9Y@#xӠ=Q^c'~6F,M#@ޠBR&l/N*,CD ]d{d!ʼn⾭BiZz9\{qz7}: =ln: WWTqI4_X-]̤IFS1RbB\[⸝l.N%FVTLiN`Ha3UVoljd75`YWjhA:5+%aM{qDӹv3cjy9e[Ѣ].$: ]eCΊ9wzN|~ 3B єT`CsBIT|dIDAThZkTSWy KѡP"i%(:f K0t j|TFjGg&)L%SUG[-#e,Z(1Hk|keܳ{w}>'Ir:{6LD!E#?l& hlKpuo[~ֆKy l s9hymF>gu<`'.GBë?# +)P2A|S7|[@*kؖ;Dck_5$Fߙ帔`}{sцs%BvA>xKqo4>[BxB:9OA`L& ;ϚH0Xefw{RGIdq+@g1qWڴ F+(r{0[\?v]7g?cM%qJe۫C2Am^2+Q 66cu5z_/Ոס ]͋UO7Sd>X}'ȃN 6/VQp>M0>ҧ"权8]{SnH%Hx|ε6/VT4t\fCc)u۰yhS ǖoOQ00^'i|PIENDB`byobu-7.15/Applications/Byobu.app/Contents/Resources/Icon-Small.png000066400000000000000000000045201522352767600253060ustar00rootroot00000000000000PNG  IHDRVgzTXtRaw profile type exifxڥk& {Y%Ydp3L2S sĵ}_qI6R.J5Umt~])ry=_i߾Hoc VTCixA4.}s]ML;a62ѳPG [c^U|} %8#qZDdP;Ԓvu&38nyj89 $AZN%jr9{.9r݋֊TrRJZZXA2j5r_^KZkkٰjotS{ko4QF:i3<}ζdAVb6\۶wٱn[߷_@MިԙW>Qczi/;$%="+N͔k,-Ѽ%.O?M+rׁ"v6Ob/ކZuY2d<_, q~LMIDd'7|TayyuμS>j|,G>_nZe:Ƕ^گ%uUe:ɣzlsyVl3Ƽ z/&2mDf"χ+EԒFe HTxc * B^ɿn6]7=4ja}0ÒmDAu6քXAom{Ռ.7m\cjP!tWׅȔǼd̻|7wc"YtځM] dfo"$ h 0̈FI Y{jqW=I'ZCPVBkՖ'tĎ椸m;%d(GMᘂ2P}u ԟI_uZ%*Ȏ 5ٰ(/|6Gյkk+K%Cf K !9zĂV{˽x.9Q+8-4'rXILд!Q OTVCZcvsNGwFlAn9 TdMu?%;fep%jɠH~(=kdAb4 lF>Täz 45sBIT|dcIDATHŖmHSQƟIdH/`D$~j,Y$[N"0ޤ3QʖEX-b+RfٻC5JvN{w^Lýs̠Xtg  )*?@ٻg3'l?=?lB:ʔ2r`Dx/jqv# b@Ęz mD@W×<>,koD\N+N9P/R`z:1'hjۧ\sȗn4O!-:Nr&3T, )Tb7ShHgt) #Ǿ ӬL5:NЮv$ZjsԔܠ/j&gЎ`(NfS|%;8/] ſ˽lL[նpu@e7"X "-hGd U5 }G`2n`t=)T(bޤ7B2idI`geaudNKQ@B;T+ݟ ΙB[{GO"pwכ/KGv٧tJkeXYא}Wh)84vX;ǩF/R740ʔ5/B9/}x +5qmme:Fzv@o@qKMgt)CÂg7I] 39tҴgzo` KI1 -Wo-D(\0o߮[qڡ]ysrVuFd+b{e;fNU:gpm7M9}.unŇ~ qNwIENDB`byobu-7.15/Applications/Byobu.app/Contents/Resources/Icon-Small@2x.png000066400000000000000000000127171522352767600256670ustar00rootroot00000000000000PNG  IHDR::J( zTXtRaw profile type exifxڥkr6k\ UY|TLR]vj"q8sx+S[7WuɁ~.~2?sJSr4ǁ__~?P~5P~|갞귁k[UMJɇNɟT25=NTͬs$C_| w[?ZJʿ/3v0?^.S۹?']ַBgO|]y|\Ķ^PgUs񟁸RPyw~}FMjPtq<$SԐ*[#=pqUɝϜ9+=/%r] ,bk.>ws1K0\W+F/.L~s H|h[fc3Uyp-\Y<1)@TJE9w i4%Y.5/f`cW.ﵹy< $Z%VhjphjkM[oFZ>T5Ku[}Zj036GkCG6ƘgNFLYyUW[5t՛w7>weݶm=tiӏqf(QF'j%߿jZ~qA.f x@|1K&,*Zfb%M\RߐG=Zw{.t'r/nip`4w#GXNbi9Nk{tw?bOw=nKaښ1BZH1i S[ծ;% $G. ó:AJsGdD=4z;2=Q.{v+~ i٘w3ef1;Vw= ra-5wug=6V . YaeƼR9'byfi<˹AHmp%;t ℝC no5Tq#[]Amh!zm|lՃuEIW~3a4 1hЊHRɊ"0Fqtm8'JA+̫_ p{]ڱleSeZة _Q^ha@Q6Md[$yp3\s3!T2\#AydsU&sp-G)BRXC޼{QK~E?P͵^'^}Z XvK8'l2l!42i^:\(E Ő7lnLgڏ[/ﶫUpU{o/5ik,#QBLm@Ǔ'x, J> ˉ!H٭htb͹_<աbhB9y14%@ӌTPs~i[̥>d YR/$;h{ 717 -mm/'fe ŝzwlLH7a+gIJY-ҟSbёܠRl~rFsP!fK[]t.,t&I٘/Jh.CO )>̔ΑerFs6xN3P+E:Gוh+{յY7sZVuh8 uMyU2I[X:'Hw8:t،C`St*[ 'b:\QYZN CDlCnɎ5E< _g<\t[ON]vΞ Րh-M$\5\deK}'[j{iOπ%$Ə*0]:`nKcW"Ub 2AOS&ѥb.*+;+֎RZU-fVͲbv̸拽Yn]aAH:nASA 梷i-z|"]! $"m4d|[;<Ńm7eI_sBIT|d IDATh[{TT30޿w'Ѩ a8 6`BYm*D3R~1}/>a)UY.9 c鼛P<=;u-,}`F-6)"v5 _Va,⤝_#k3zx!={6+wEPf%}Up Sڦcѧ#xV]DkY5g;@$waiƬS5z1`I'wZ7Tްmjn;e#0 qܶr1,njDz~u0zOASHw D=냗07zm9e|QD(s|&y_?0ֆ 2>7l OV|}n<^j5i̜x}^oݴwܤL:Dk`eaxVΣ+p·8>@8a Nf˾]7fT%ϽKՄ?2s>-%c}rǎ3\ƅ苎(9=Yi޻̞ Sfą=[{(vvŜKԴ̍O捷|= ln&e2&x`${I9/Vn.dVxĦ`l pѩ=VDaŀ~('TjP?]Fq^0gDxώh^BSvc6|:mB;Ii]ޭ%%IG9VO=$?!8ih^$ 6:~;DD5ԖΚv"YKnm[rTGxp\0DX0Ztii2艆RCBcU,l$q|+Kn]fg]FAۖ_ =`ݎ[ua {*i1I`(w:ɞ&ݖg0:'3TrHRF67>T:iIR&03w<5>s[W}?Ttg΁P\+dBW6kclZA8J7e Ct^%#tW*UU?Nb.m{}xm6CDX\Bnw탈#P(Uk xhIwp^k%ͱ"m٨""ȖkRչ~upp G1yǣ$kݔ*9` &jQت9W]s{sﲷWκSDPgp\@60]#DK6;>¸1伄q_Ə^Ɖ@nq-ߨo6,:.[~tϷjFj疊>}E$.,:('d*::C*;:I0eCof#CB5ҝ7ֳ_*;MNi.J3v!cɿ t9elXPR:Dϗ]YL( <|+~D'f} vUM# Ӟw*e|bѿU@'c=lkQWvIENDB`byobu-7.15/Applications/Byobu.app/Contents/Resources/Icon.png000066400000000000000000000125471522352767600242500ustar00rootroot00000000000000PNG  IHDR99 zTXtRaw profile type exifxڥa$)| I $zv=+ɲܭٮ #2"sWisI9Y|??5X^|T>O8~gS6}_Sn]k]RH9t|&Is}pMÉ,1[)_K 9ƎbRRX|?ǫ۹w̻o.;_~^:ko.3B*/Οr߷tC O.-zs͞gO>ΛirJ糔 PqnH/V Ewu 1k.}yd\Z2}o@F=̫.L#` *h(`3KvB`+\|~*V&CԜZ͍v(L!͜FZdLT6#z>{m9&J6&jkMڴP٤էik٥׮G>:t c ӊ ڧ֬09ydٞ3,Yujl }vݺ{lӋWWo}<@S>~Ʊ3/\rnڝ?Q_-@-V^5|^0H`bf.Yf ]Ij`9J}\V*rO@"aEӅQ$tIk~Zdt&gQݫ׭ ]}.H:mi\sskܙUAm;n6Aڤ:y+sX[ P8ZoWKcy*}uSͽ A򶚑)[SY4={c>lZWkBeŷkj7:jҀ١OIwwvvBVkw-MoTʹ#k bmgAV;-ܮΚhmX02F/VV_ U`2e 'w1ը,}<Xg٩B3|3T:{F+t>+tSJv&lsa.J܎y0ͬRwGWƸSx^̪#*F咥I7pT|o?~&^721WI[i:dj[ u0}tMc^nrm{k:3%CL&9z *s*zq9PHy^ !=MKj5L[u_tkv/#;=xfMa>"'bYP*-"A&b[|**K!yh}N DhNFu&9"/fԂPHt؃I05zp" :H 8EV7@U=+)(yK|f#S;12I 3zrXr.1Ih6,F5\H9O7QC9=3 3;Pg M'J^9̻py - 9'F:x4$m]ژÐ,('?Y*Y0V:(Iƹ/X5ecl36RdRCZ cK[`BE|h5i&Lq&KDI>aʀ7gi׳0r6P*lYWbme7s5c͠ NT"4C5ԕYD-I #"Q6ۙd-mzp)! fRM4:ܡW{›:= ۸`ȊMMe]lg/[rִYK9)u % |1/3yN}D#7PNu"!p5),s8S L*Y),? grJ"Z#@n7/n,z<\,< –b"gkEdA'lD|<>?^*Je=)0@gm]/)6r2-`7]4dxL@>lh9Z̍V*6?.y_ DOd2Aekڱ**ٿ (Tw?;kblDDRygAAS %8}@+ (&I{RƹQ} ]Ad,FfUx+II07i bgkJt8g17:ꯓ~9I%D[VFe09R`r3LVj*-YH0ʢڲJOdgzDs$|Πi;8DgVΈ_h+p ߏدCNzcL&'H7m:V.Wm5գ2\ʿ~'XK0չ4&cڠBon+ 17ӵW$YmwPI4HRfv]MIhd` &'f09Afa!͍sm>MUg17z>,ϝM_vݚEnwgM]V/Q.++\pbn$m PnG?l%: `H`|7Gsf@a>쟾Tn`rm= V\zyОBmyF.w5I7)`rzGWy[nk[Dk'ۃb 2w[([F1bQF忿mX̺J}^ 1nHspV@m&d z drM!U}آhߖB}W[&tYUDYl7Je_zL4vHL!,]D HVw Y,zɼ252_6Rse*S┛Zo[L!ѯ)sG"^cjWF')IHk@TL$!.}]$'ȉ̝,2uxò6l|q lsqw#>ҫ7:{Û7HaC >vfH"~O$? ;=)34% iU[tPԡJ$Dᜱ"@~ ceurG% ҒD2`G6%yG?Ӑ=9}UPexԚ 0z[e2]V/\B ^ *`@)L #C̋_hhK$Q3SFg~ ՞ɴ9(I+0w|| f /ѵe᫆T?$e2A2DkR=yQv1ܼQKs}ZlUʛ5v^ok1G8ła!sQ %µ0ypPȴk'r3}gOkP CBvp<ʣi*sݭb&Ο_"MxzFR/m^ IENDB`byobu-7.15/Applications/Byobu.app/Contents/Resources/Icon@2x.png000066400000000000000000000334101522352767600246120ustar00rootroot00000000000000PNG  IHDRrr݅}zTXtRaw profile type exifxڥiv9vc^f,9ށ")5V Fbxr+[O.J/zaϗOϥr>-x]o>?ol5?_M "W}[@kɥTZe|0҉3Yb}ܸGиėF ]!n߯3~ݷV~^BbuoUfo"1dGb޶:,o_~aݻ۽ݐF*[y?F.WWo}}ΫEil(n%6:;ͲŲR8`ҵkaT${:EaD{Z|3o` f;7׽j#F򲠼 ]rI˗Y!fOVur/SV(1wf1I/!jF  [)L2`9"CT{>$2c8HVJrQC#ǜr%rϣĒ\ɥZnƚjjŖZnAkC`_zc0`QfiYfm9ʫkN;nqPJ'N9ϸڍ7|˭~ϬW Y)Wf~W/ WeʙoRP3]6?b:򵟹WQ\I1of)u̽Y"2BG¬q tvaQuV֜|K`I|EN]3-xdI>9Xݲzura9ue,/')Zk?%?#; حRd,:EB| yZ ya^v춰J2: 1 \+Uj]LMcJB /^Z~$!°rqN3S$m\- z(P Mlij 22u3miyhy,ŸA zBa6u Ƥ^.&Cg)ߕ{SAx#ӻ7 4255}v: 8Ns~-Y[RRu: Qt턒C-$a[Y/nikE^ :wZ`(JH|6ֲW=e6PkPD{'u΀w'fXNgA̘*wlԲJ0met#sm3 u'vwԑSʌLϾW(LҺ5שc|5 l?ݟ4-v> ` |HBMrzj>K덺g@cW0ӺuSaٖkH XlU(LL{wu.gP#!,DMT(<ۊtvgQ,-SLeYE跉B@g>Nh'@{ qȎ>n䢲vdl69EHRԻєf{ZCKlMY$ $s‚@D$-aMVg(ܞۙVֺ"eFT&c=@5zjV5fjڱLZSHݟÅj;YS F9\sl PT zHZ(Uʓ΁"ȽyOHaIٜiͰS7+f/w=?A&΁r: oMǶxDsLd'T]vlfj ₧ @"z//*9SQ#Ϡ8NdqfnzƋ1 G=NBV !ǀ¡QvsBh557i#ݖQ&4J5>UIB |q3`ɀgJGT*0ZAb@{ޡbF+ alRj_Ca0`_7_R/<3C>451#MxjbPo1hY,=beȈ#"9B` =!r9~y ZƉh-z.LSCr"%[([R{i ?fӆ@RbeĊ]Vda9kdm/MjдB1!s KQ;(I?#{D8y~@X' WwuT]ȋ7SPCPfnt2I?PJ0T*/`gL93.ݚM:tAHmy8ˆ(iGtCt:B[ܩH+$'>.`l#(lXPA{MzB:ҭ]F 8 Mez%ǯ<@lPJ%cD(. J%aE@eV%i 2ѺAjJ,,thR셭XBrixil(:ݤFeP(d.!.J%R v "yhjolMJ$3ѣ#=A,Hqr0-h jd LS'Ŋ{wi4|`S;"l,\xC`Y;0d,#JBNdPg=-BU$`=8FrR#*H?;:1Oz?xQ1INB5D1" Amu#DLr NHKX u&ʬD}BE%@"6 ACB􈺘._HPʋwPH(ChE$CO$҂ @pɃ~?0,bA.DWAugp{1p&`?آ$mwH6:躢dA;"%Io0_=Oc4/xO𿭫63clz8y0 8P=9^Q$@ːX v LB5'١wBf]}6jž 41D5D1mDE{VrޠE5Ii^ <*xTbub`ebhk&#'.TEA]jCh ҩF"N=9"F~eۮc! bhK`H:ŸPΪMe;Y:.azf\rpxp#q2#"Ш.LrNbZ[x"2{h\$N[p>\*ȍy9IC!=ݾ+c.d5;72lf̜Fy s Dn@#P8*:?b0>Rznp[BСkGK2+Ծu8ur%v3Vx]9.GxU`X"FT7X LZCGWB?tT6=I@\AG(:MgI 1z7 cu^2e$%<(!GMx "M oIKb,Hc(vxC^iJݒ _(AHY!D \ oH`C;#Jh!}Jh vs `L:o頣ނhV\i vZ$P \p W y@P NNs^5O:Kvx!QE,UFIstgу z1Cei1ytѶ> 1# 1 8kZ]`s!!dER smcAWFE."H-4շ{N"ܻDگuUqU-~Nh?> 74:h9U qJ`< "M kIQ(o EyTY*ٓFC0S),;5I(F 6'GꎻR)"YJ=k㴎,FLGJ Ej2Y)bDcnZA #pr/ruL$e] W \1 C6UC4ǖA67`$Xt(Ie)v=z ʟ{ :i#E.CzŽzGc]d^#-5Ԟ"g.Mb:LQ/="NzU r?-nVj/Y *6$UgK9_|KA^ 9k.oCFPKM'D hTs@'?n+.:Y{}P%)t@ HQ!8LG3Ib @%GTC b6Ig.aEg 8FNFO,l0ZH=b4M=Khyr:rLA#U0?3^wUG$h#s$}CAܪS!GyP egw^D=sZ O2A@ĘtHBֈ7d}ߠT: {N|INcTЫ1+HpgHBD >栜I@Qz@@7HVfz9:2O @!r|:P>x @jWXM˜Mј}> ݹWF3 4g|g襽3~kcgmYU0p ZSu:Py3J٠w60Դn=ƾ+H}R02.vm[e^9VNe V]! z%x Ѵw%^/)ӷ-vëښϺ8fg}->0VQBJT'Fp;@t#|j5%W#F59Ǽ^}mpAՐD.6YAjЈRy_[gPSRU4:j:(SzZ}՘V:5S8eNjr`DOsuZuXM HzS7$X]+m8UW-k+?%(۽l_ iHs9<;PE~lN,譞XTAV B7w$ ;?65v5wHW]m;zgE5]րTˣe"4k$N{e;.^/>7cFvOoU,$k ΦNNpl{PTm=UC1RM?V\XKV_2F4ig/[;_+D~grڎK$kO/ߎ$9\VxX*op@V:h4H Pcq *rCg7<{ǫ7W}λW\kx=SiHaNy%E۱?+5A=EQ8g0NBւ/;7 m ]SҼ!kivo nt0ZD﹠@L>p/ڤRϷAҬp =ͲѿTx4R ܾi34ap%%Z;%t3q/`OPկ3 f @)"ء+Dq+ xUt2SH{G:2o,Ur"T;9% i~\{u?oէ,'I{ =S47? Ãad5:s>GPG8di~6nNN~d tLG:PSbE[/~05 <=Bp(kP0)Y*gZ 'tCx@0VQY_3t-3l[3rfnIp/D)TjiCaITLKCVxHy+#|J_~۲wiO%uք+/Hq E[B\kV$fn)|'~I"k4EA hʼ?ڽ>UaGR2Ľyu$!(lvGPBAeAI^=FQ+Y(dY S=Hh渘YLzy3h闉KNmK7Yu3s u?p½[)L eskI6o/lWJ Ef_:"-߽G; ;7--LJE oSإ~LzgSq(͡wbvbnam;z\!%Wz}V-f9ܧӫߓ#|*sJ54h~ &W{iij%)WR[=(!J+u`i ۷J y9_v \rCWG/h7ihZ,o N'M G:r8[53}ԺV'UqyrkSC}yӑSM!|26.cG,~WV=' 3e52^ YyUr&n.r#yRR-8iSx%h5<})'%d˯ ţ-~E=Vfسr:S`:o?FgR_'n7 ;us=unWvf> +Y 0joYY$I8oإKX Q2P -mUU=hdDߩ^` /Kzr!]q r 4]S% uMx؆7uy0&#}.ux+*YzDM=!;kڽp+5|g?xk\Jf'Ր t\Ja`c$#Ŭ,y'`iҥ)#`X, mML+PdVi@Ȫw/-]vɿ& dйLvm睰.2#h"=[wVI`ҥyZnçoT(VmWj8 é~ӅZ.aY&%_OKÂ͡0Agۖ)LnfZ;ms]*YUۗ&)U_GSQwۗW`7=M "EbbȄt9P~;'Dᨿq]tAKXBcמM3b˂py72%{,]ʖlL(wAFVneԞ#DnQ\?<+w,|o2~ tB!D\u9¤\zwΓdPQ^:bCcoAԠ9un`IVt1˃pR /@VW"%:idT eQs=m+s=iΈj4?WcՐB*e@Ӡ3 ~;_cco sa! wg]f4`>"%;ݟ=f vRG'd 'PI֞p!Et c}[-K&D0_]۵M ;ͱr%V$ 2?$|i]m-UjuҬd7P0MD#hk6L^|afl Qi~/ n3r~´Ɇŕ8Ԥ5$;T|_k'R=PI^ml@XU<%4"HhܜwuJaJK44쎥i4v"(:Z:WܖŪyįvO gIh|h4cḿs7 +,cO~dKhDu(cZF*V̮ YD?7`5֬u:FJsv$KH :WlԭMnVM6񸛶F*!HymҢ -㽥/hSIk,UI~o )ȵ?Tl)`ѥ* FJc̏} 4zduo~MIaT'^6 -tF( 1BH ]mʯ+ UM+--`0uzkv!5"'7r8C2V3Ԗ~[wɮj|A*ߍ R#$%!;`t$"hqthZ! O& &zLp]UhyyY"442uێKW()F#}#λSPxIpao"I+,)W{W_X; >#}mU$me{m'=+x<ĬmiiHBvSF/ȳ ZhutLֈ\RS[[rKM`wٵ.SEgw"zOYO:rxRqŢeFn+f6y7%ʅ:M+$ BQ |}#]Bp"tyGY9]P}=_2{zTʳ+zAJȺu0{LV]XR[+*EnQJQ)}GCǐ oUP-PDx28SẌn0MtqaͪӄRk%}x "Q{<x ב֖$IA XU;$sg9 їZt*}!:=،Pqנ xxM&hiihan KSCXPh} ~ Q0σjGBP9EK;+hOss}+IܜɖwmxnGJZgyL( ^m 4٭|iG{-a7 I 3S}gӬ &xym.yťzl/ŦCѵC$ v% :TfKPfMӛ5sQ\#|V+ČqȊ uXq٨İpE&W]v~2\mq}_nߊWzwA;뱣v RN!#+O xz@ڷU,wù{>1j6?Aٲj sXSBcf {݃]ř$۝EƉ@AZYȗgU&Ђ"4!Վ`_C 3>:Z?45{O_>Xʙ LfR'!EٽPtZa Q8gDpq[+5<"+WGڲ60*?j $9Ŗ%,C'F'=Ai "N`oSk(,SlFA!ih! 4ף`Wsu*4iA(fS{d1ckͺ,ɛyJC$.wWk(, Zܫ!_<ڡNz^NPR jN#xvߍk&)^mvԍ6FJI;錶& 8bfV|\^Zɒo&N]zۼr&GG^'(\ 5?TcobUg Ui\ʓ ;Z AGڂuL737\T;A)TX*#*x/3q:.Rޣ l1t_GFy]G:a2w)T{j;".Y00]u@7$LVZr KPTkS.ȁ S4ckalP6Ѧ| >C$ g_~ɛEe,#.ޭ#7q`:*(5W޹$"5?h'#PIDATXAFgaj$2)*ȷug?ȳHkUh](E$:^t`B#sQ(MFU sinNwΓŚ :K|oPѣk(P*d` 7-o 0To|/# RIENDB`byobu-7.15/Applications/Byobu.app/Contents/Resources/iTunesArtwork000066400000000000000000001614231522352767600254140ustar00rootroot00000000000000PNG  IHDRxsBIT|d pHYsK3RtEXtSoftwarewww.inkscape.org< IDATxwx[{%kY{q7(3aJ tЖ2BZ({IHL'v^?l-YJ8E:c[I@ "z@ 2C@ D @ d  @ 8@!@ "A@ q2C@ DB_ DaX%< m>h#IrdI@C̀Z0 [ ܼeV.L$Iu"d D`Fl(y Xt.P´100p$I[G1@ /`F,8}KNՂ#a9I%Z#"BA@a8d6}.0nu` 356"n&ZE )$KND @ao}nu1 =oDD#(09$ w'M>8K4R-2x~؜ $A@ %MyK4Dx yIR-2Z 6s9gb0 'Py `7|/K2fa|0`FTGT|Q80570$iw"`&Kn%\"v`tGVD,j(R@2X@ ބYC"0L7.p`Z)@ LӞkch3af1GB DKNÝll4y$IbK0-m aFPT@(@#3!_< X"0 !ɰ[mvłD\ew

@p27-єhiEWY#Ф;:e+TF0sU[x:3Zyzg9Q060(x$ɡ@Oa´6xq6 `t1z@P aL6dn`1!cJ$r1*# Re9:QN;"YS$<+-w`Ly ;1+Ok6 &dsH}6" ̣`  ޓMșŌQLlpgm$8i"$fJueDmi! e3{=X"Hpb=#ZVyJoRk6d6En ʻ GAӉ 0/BbF6 a:1)ڛԄ>mI&IbmN(L!҈e\,nNA%CIħʩ!; )tqPxSZO4 0Xyzg0y6}V%2 ><<0l7FIx?0,oH|˒<٩R 3X]QC$Kgiq)X2 xMVfFψ74NxjoJk-+OgE2A0 SF ä>[l5E*e 9QNԖIbRo: GC/HTѮ.KzkiC^8'TFޤS&Fg EXlqk,DG`]øR cJ +=ƦPijCR3% 0-~ a+EHҕkkJtyL`03 Xd8kU`wyc6gaRmtי1 AbEY)3Yls* !tEVa L9x*qA%B]ZX"% 2DinQ]Mf%ǭ͠ӑ H+JR%)^蔞?_Zo+O?":BxfB^z/ )nIUə( ô\E pXI΃A9%B"M6ϟs)q/qX,MѮ,M$̌a5p\QyJ#JktR?5\&Y)RJ.:t¤Z0ҀBEӅ @̣njf? q@$Hd !ז5%9DinP(j4͚V7<>2ĘCwt Re"H-t`BIȤF'50:F4Ԁي)ᆸq4OKYmnzQJTeYz /B*p2: x8% -iqCA3L9¬:paD7 D.'SYDuI@S8W! :: W2[,߳vfc 3fPpXDϐ*M$2"'MFg 5%9:>K g#h1q l&k"E„J{.0@;#1r *fk7+J!<- -e58MXQyVo:/XPj[x1W>7M-L!Ӊe@;!&)"'<~!8RHLBbwQ%q88hҢ8,-yZ m#yT"j%!*XL:%An!IF'02bXĨ)U^bɒD"-IDdHL9Q-!rӒbZ Dh 2b  Y"djJr<=&2K职@#A9"M&&SYAl$'ոCD,@P0 1ǁ4(]$`;`lJQ+adR J-p% ti2,'eDUQvYAAٟ "`2萝*T*$I”FSW{n~ϙ!W]* A8.MƢ yAaعUEY^Dz4kPWp#R$`-UZp CJ8DPy@!DHA-4C"(™<yTJDS(X !GZ,@!D ՠDD0@D-  (!F8ғjWZyR/vٜ LZ"{!BZf@0b x: #;W9LUpz9cNqEzSmkR^k4B@( a j- ?>{b2t4Up񟽳\T\=t.uCƝaph(A1e}_?E.im!6a j%邾v]dѩ|x)k  xX#-Nz^; ?%k=j8ԝB\юt@@e@Y?(u*TR9_tyF%l!@DǿʣzNM8sF#$@D!!hwLRNvTQ "nA!`X7Q=89!(2Pa?Ikrt.@5шݿ(2 U tȾzUs%$\P4J|ьӅ<DX@93Ux֬m?v~}_ 0h@-(@NO.w9\m\v'I+cg uD-( |+afipZpF_\t2+:9Rqo`/z0໫*9w,*` ?еY %@D+BuHiH2Ow%IN`R#fgw~\`CVLÐZl'Ė)ew2#y"6k uW(  "QIn%q"E7+tf.U}vFh[}uWm |, Ϛs}Mwporq bBn[ԍU4qlOl;Y]{VLr8S*$0Pj pb:Up]af4D$z$t;"yF PD͆MV8-v?iӨX#;Ijx"v= a j2BőTgVROδqrŸ x#f{_ Ȃ<͓P=P~Pzt,Mn'|h v@pDdc@DDŽnREq/clv'gW|qr {-Sxt!5-bW Y|FÐ[ A),MXIq/#Ts&[0~ݓMV&,$9H E"bmx ÐFܝ/Qfk~pu%@B@ !b N$5DXoW,vt C5B  !fQKQ)QoLJ{_S;EW#EqPr"@D  ܂б{G7e2h;X "ݎnrT{.|߬L"{jk ] _^;Qc0Yqť-7^X<:=mXD]oUi*FR62l*$]ļP?D$AǑ[$jX#ۜVG`Fl,8Rs_{?ُ.\,&j6Ue>acnG/T8UsKP$XϘb-~V,`v>PI8BT}T C~&ܵsB /n`gK25K%s/$4>7["q}%Uw%j$k"@9Yvs+z^ކG.}+^sD\e7ʏ޶e[.uM[ O7<{]뽭ժ6I~i^D'PG@D$AC9G6O!_$[DQg*i3Y&se.4^8cPi7qY':&#=}]ͫvn~ve "(C'`44 tx>4|f\iapce=7t'iW*ϟX"*"*AJY*hS56 ~Ca O1QyIjYs!@Dt@ǁCҧ?Si; ë++,$2f@Y*)`*xy M2~wu}EL<7q(`@D@L7iNz#Xw:]`6qDQ!.JR@fl1e DD<xlu;_:Z;iLAhT aZY[@V" g+ !" @PM4y&=O_濺,uwo>% :i$ ́tD!D@CD5c5} j}A玫*[X>6iy yqH]ӈX wikUg/_PgAIug-4$'b[)""@POdkK+\iqݲD?tW´J{4p@ <HH;xm}`ÈL*`Kϐ?#qj1~wQ@Ow&ޗ&r߶>'Et GO)zmY1W.;J vDY@\' >/ 6tcPK! 6b ADb~貆.E19BC;7v*Ic]E;n}r A'*ڱsG3.$>,*(Ƽ=FM@ӓoA竟!\!"i@"[?wj`x'^]$ֵ- :qed ަ1IS6&c4 t)-wo~+F4~vt{-<' .Ԣ&K?|pJD8A!`x}<7NU,vw wk6vL1Vuh ?IF#~uB@NS2iBʆNHZYF|H{mP|U`uqq\>M~ O E3떥i½6`#NHPhtMB5nq9?x"ec׹iuk_N+n̹r㩚n?E"~Ggs>)ԔX$`eL1+CBL"SS:"<^ ?q? t}bKMe?#d DDKUtG_=^zucVr\}hǺ3DnjG:n!Ih#KZQJ\Ƞ/TOkZǛc~'FyDHi\3Oigt Y+i2PKc1"˃8tFT,҅oYl549`\.9"Rc[N<8: oH o}u97˼Ok7+}nJg[Wd]~gEÓz/T<&g7ty y!3s"$ gҡmw+uBglw1g҈cYƀX\1-"ށW>8iО0zV>t !+%>f8Np"AqǛ! Ps݆cZq\y3ڮ7B(2UFփSƬHWv3jу k@x(0Y/?} ڞEz oAo0_7Q:/ڪ&{eyaɼ8椕(+FiWԁ56 -E~wU;p ϧUC~$>>?Ap汗t6Y_X c@8_| SyV-W!!YMlw3kzY`׆ .2!(l} 7(;N Z~?}Eß y wRt63 u(:}qliWw+* py˶{vUw(GUUokOVmaX'.Y3I:ePM@#wm Xin5q),gX9Re^Y [b4e!An؅/?Nĸ@,$I?ޮ/|r$7*z1# `ɤzaX}7^%}>*|)z]-ҹ)RAկo>[rU}?Ԑ \<&j+zX+G1jsXwcr~HuB+?D퀩 z`t=e= ذ@'T\ia;W‘Ӓ=-MquWWwYZc4:U&.Ű|#S`bKFTd(D~`03HͰBQjeioo^F((F@vU!~ Ҫ"P6tR`896*|>-M}Ҿ@΃=\.œht;my6F+g]xw+S 0"BK"l`-ݏ4dv{lk =;|%MP<ly4˗5]!chC3)PK3 cZeR/" \,ONJ%N%JR6qR9\vB~` ?=6}*i2qaA\CpSn`4VپyH`U*N:O֕Ԯ O$ur /Y{fUYjL`8=  m. R޶ ҶT^C'VNӓ& #ugI^S פP:_X1 i,],/}[Έ;Xs3Y)B_HFuwm. f$i7N|ݼ7| H CFC}A\`W?3kcSnziaAT7aP6t qInt;`nR MR!d{`Ge@A^G>ϼRBnSDKc>ST&ֵ-LFl$Ý+i[vO{ՕUsF "[+ހ0`Kϯ`l,f̂3~M8L`.B{ rRkOk\X~fo}> 8aD!?x#7?JP5܈=?&f\M| 9QBc_ul&soz&UQ( M=W.:|х`.r\^ jJ4Շik| $Vl|b3-MY6wm8mvƙ?w#~[.+opWcȗm[B5KG)OƜ4=xR$I00IQCDbtj쀄N=sBiB)m|eտl CD|tݖ$6-o=YhU>O8 wϋ`B6aAܽ,žcV$( 6u8p'Ĕ>zq*q Ԙ =%B[(Y=۝tH' <.6! h%OnLb2 '1m jAR&jf n8I_kxRe"`pcc`\10.ybɚʂL՚uuq f' & Bؔ5: )FՂ\ (n\)CWlI7!r9x样ZzFd9 \6^a V%usXĢᥥwȋ*Q S g%#UQVB)ݱ{qIC I98bc4tU ( _V^D{:e^D g+ߵytayrpCeJ+"m\,H)髹S 'jөl;U3ʁ<잭t$=\;XMcDd[dZ~xG[ BޟEuS]!'Ua_B!;~|GαI (8.{h§?#,r[auK󇼴$s띋O n}jF<u/OT}~o;677Lit?rO?rLXL߹C0v1p&Ruļ+d;agmBw?]gIԴ-;l}@5P6?s" E0 Fo;Fq\ 4&)2灴<P@o^=1rCU#Y<ߗ궾-ruKa% )+?>~汗Q<זޱ@W\Õ@|~WForHI"0 ½H$DbօIVYc.t/_P7quV;:Rҕ}N)@0 ΤCږZHRpP޸XsO$N$-ĥ:dq(̦q,˅Ɣ UJ GRɠӜw]wavՄ{mLů.>nיyWmn 4kUe_[p~ۻݟ.MV.]>t ŵr10(74uԇzY~z@ua7iug&|69]6;ԃnX܅,'-ڶR5 ˈn8&t2NspSS,(yJRdYAor }ּ<\pJs *;7/XZ<%xsOTa嚛8$׸8VV?޸ĪM'F)IZ1 MĕK3ecSuWM{ oMZ2$dZ1jrG߯t>bn.!PR; 1 bA@aTDO@K.;˛ms~5 Ua%iR#rq7:^cmcvlB`7Zһ8ӘҞV8<m\.XxFwbM%2vUypO^akvS=7t5Վ&jV $ey wJǕZ.tp9,;rLv9,Gs8a!s|r}_hq/Lq׎;XHLCUfIcsJ?<$IUBs$Wиan8ؕt^<tk򂠚L=qDPIbq+p¢"|2\ДZvڔV H6ఘಙ.eY>qX>H = {ÃE3Ŵ[W\ ?kX÷)h4&rÀZm-IPDo4d|Ap9ibaҟLle_\L!WRap**5B~_N-6bc߱f2AwM =R!nA %I1J& JRcJPf:6C.q޾$[=p颬]3SS2% F ydD ;S 3TCȟ|ԭҹ0/]l ȣ0Av29 5 *Vۗ`E009M5}e}׏lOvik->HͿ/OpTgʼnYDba 0@\?Hp8R"7|hMFkq;BA.|3 һ67_RaMeʐr8ϩ@LJK8[ 7)ZCQ/KAGTU@&,Q_{aʲwN>zM{j?Wḋ4UoNYTvq2 ɣԬ804Ejsto7~p;vLlW2˶jKS7V)X a0 3)^ALOW r0UЯJ$+RÚ b@x%H8 ny\Xe) kBE=? (I/-ɼ?|9}aLT6uKRt)k* ;F {Á2m0oj8:w%*X['8xkH}4E`B$Kb>=),d "'c*pNj _-/2``ЁŠֹsϙ :f,|>3A)P(Ԟ].n-.^Uv[1ˡ3>'pٶкϧ/L%YMfq-#qoV?ۻThϚjsm,6&x U IDATrr1א*B}~z8Kbqqk ( H &P<ˁi93c&n>͛S1,`yQkώ4V*6>?:5`sM 0Urm91S8;%$wrGW?+KLYMgE \vw0Y8g{ek뼺5-1 Ue"MNt\>;E ,?q8jWLqXPC0 LjtaX?ꓵS]vE#/|TґEç3M Ӣ K\S˹TM=AY6`(rwH.d0-5o>t嗑iɬDdr8~e{V}R~z/eHF~͋spv< á$!XWQ w9c\Borc6{Jz=޽^mε5M<%E;vgV~3O]C>yiC%NR]&5&C/U5vMfrX6,Q/ nj~b߷KR`wXbh@-*NvD^RXm4`w˚f>5.z%6{fk)Kt:@I*ʂ兙koÍ]pe6:5)6v/ _ֳ00~LLHqkf+:vUOv 2(x !'U _ ܘn;51~h]XƟP[숗Jm}r WBњjPb^ 0m:8LV`KMo18XN*aPSȤu߿[6ջ-Kd1{si{k)3Ə4$dPp1vQqv&|t;4L-Kk+1Ұ38( G.ք"co_Ƴ9^g~|}MsC`۴rBV tƾPd6;?Smx,H ) 4n[ٗm !3|}4BA@Nkl;[?Y*4C7lLxŏMVLukyk3JrF Cq0L\3}x`%&E%9Tr\$i]oSmG.O֞MG],C2bQG!%=/R | | e["hKC@oMkl\Q!cfyY:x}Otc?Tݽ|EǪX7Ede2=>dDWw coǠ8T I"ʳK$@ĺ}2jK?/ҧrLf?|m~`idJYzu4cy>89<ÈBjԈ=lh#3\!`wDn$ {}OvҬ* ~}=8{YL}_o|}'}^lkf)@5L?0 V>tFG:J1+g&OKro%*Yuާ6X:cyodJTwdK F+ǖ>;YxۖnKQKEE%':u7 z!{ sN91_Cc`GC"0Ob3z>+J(;N/|Txce}ET%W=Ó%߻CӄJ4g2$*W|yoc4'۝syڱK׎L3x'<۝8UV9+=ӃҿU_Y i֞yKz ;5Ue'-{$ (HU_W{WTzҀn!a7;mye;dws=X.g'^60THTQMAyL'ñf,ME-XXa5 ˝jQ7cFwQqMRE{cW/<)K- xo|)C.b C ix_\]`8q#K&+ lT̫u>yr!WNtcAܓ\]{Fk\CôQGs6Sؐp*i\Cjϙ;^9t|.EH|0_Z\C掷L , B w;`[$3^6g: W_2{lE0st}~HpBC^[>zTޘTj/S֖5wZ*ȼZiO oP֒OOY`ӝ]>lKAC.w\~S@σWZ]Ňkl(tݰ7{,v-[t f( OpSz?:DzoL]©' `-"d;o:p.Snof',,7lǃy˕ڇg%ʭ2婟fHxj\у 1Pq-.^b:=^rEmEK*u~ߋF} |tP0Hy8'.CcgTٯcb BU6?"~`6Λ?!e15,U4r{n0鷵pARgTP ؕs̳ak5_+uht.#9q+ۓ#S5 qoWk85a@4^738[gB¯}\JK_7#rR}9+'V2pti WPk|q+&4X{DF;`*d Q$,~ 4$u{3AѮ 6ϔJv;t6 F~:` 50gyv8s+owY xi<"c!O|[jVQCxBGיN|З6GrtyܣJ'F/|sc11n^~ nkn:o?FjVNB}%_sנz_&4](\k !@:5 #MrG{~.\PIq}{A'P5ضdQ> '=!hڨƮeێµ{/" o3g?A,U9vHǸ,zT(dMP.?0? "9xj\I]- ν+5BfvH00st2K2T4j$A:73kݞhCOaXP$sm&q׉)" Dv#sJznQl'lk\"zKwuEdk[+2rBm: oLX=ywg^:4Nt4r%p=]\owz;dk$m6Mwj+L&]q?69"zC:a_fXIM3,x'7he@SO\ ]K+FD?m aqHz/@EմTlJʮ`jp=nt?OW`11![C`rZ<#PC,EIA>t:oy>`Iq/=CczAi+j\S3}tr{G53dM휎rWqU3 EQ]l34y&}pRL+4Hjq' ,ƶnP(PQwz0 7 <] \M(@~ I0U,Uj c@6sܓ hZC)LY@*͠t6,5UOe+nſN/ liL;=$W#%[d!Ϲ壮DH:]@P`RNzٌZ.uWp.1uZ!!; Wt?O !SCDR8l&->&kj6YEP*, ax &BrTIk# [CjI ̃J||R 뢾.;j x4? &ԧ>wtt:>]!|`sUŇ|BƵ:, S KW2޿?M `Hky\NrWv4Q_rqh;F (T`zkHJ8G.CfrC[Jl-Of2kL+H2`t ?_kU*]!cFyk3FWN6m<祑_GOmM0NcM&`0hG=}Jzw< ɀй| s0aO^ ^p-.@ym <C Aa!Tqsj3D׵pyWbD7'arN ɃZ}ay hnN|ł{ҪgJt@cp r%5MٝXiRBG^@d3 D/ NNCg0) nh5ӵr^]> =M? @{w_$q]|˹U=}_/aoTXˆ@oTՍmu{3Cx 0tA0 0 1 )|K=sڅSYL GS֖{Co>NI/ ߧV_I\6Ce3tB}1S GC>0 bW hlvd=1Z;寷3 ˆp\AFKk;Yr¯`ξOK]>r8^{ e=qC`7FHܰ73ܵ_C78_O_O -&_l֘TLO]x MKVa!A3+Y^]IJI1|*P_? =؟@ ibmk`4 # 5f(3j 4uA}k4uACk4uAC['(O)TpߤTX4u$8a1#RǏ1Զ3] \w92Ѕ cƠaֲrθ*)̮UWK4ۻit*vlY>˨qu͇GL|G BRh! |.p/51:> AF^d@'ݝ!ivBC[u8ȆVxa4pل"F]wG'Ge^4dGt\::+޻Oe >+玫kl8'.:] %5H"a">@{a^syt/M-P IDAT4_,;I 9?Yܝ,>k5hl놆.(o}g@5#z^j+lթaA\9 V(*ns&pPCFz^ `Eێ\ 5a o7#3T[9fn:p.Z'k(>Oh]n"X ([ L}= F%EBj\|A1!WO>0 n`3t-㘳wW3/8vCIj|yr*?F*BۜM,?8%jzFMJijyWFd#ƠS 6mqE=4GRL!})!%:<]HcC'@IMJ0׵ҙZ!<zw44蠮w~uBLHyrLbZfיt0 lq)3AMoo6VT~Yn |wU@B$t꿯|~xD, #q{7!{~X'^* }g󠲡^|x:8 L"L`q˽^^ܡ /1vHk~ofł2_nK`1#9^ؤf* v@ ^ RRMAT^E?g e܁J,wBٶb6ϟ4NS&P|. ĒLjH":4 _9g|ɜq)H e44 G h^1g\3B;dˡ ~ԏ! D*iT@2ذ~ `BDE}ʶ ^ޭ7:Dx09-~@{ECњڻB>.MA>pʍ LImhZllҤr+环H m]?/(3PԭbB]&qD>p~5 p`º7j"g[Aanjyjaۆfb09MҚ;-͉ϽಘW*og ۏe$kNhUsv/N Tw QC̲~O< q\G К] 7ݥpo`k3rH \X|y؛KhcYP//*ЃJ7wt 5jq; xw87W+ slYEΛ 5 1lѽ#'`+4wewՒbnNW*mJj{!L^p XÒ!&ׄ{BKV!}; {mѱ4f@o~qPhXZ/~^Z:B26*5C$t԰/ twA>z&=U Q?fm?O\SqR=#j^]>qOj?aB~jKJ8 jCU{NCܪ9r3>F'GA|4#7 3F't[JfkXxg'z ^0V?Lvjzb3F8,)} )feW\j)"tFa$p2p <Z j\ȵpAJM>|ި2:^=g2(-y@`-batM)zEi@co8 xj?ᣓWWdҮS9y<^"3&վ|vO9`ir^ێ s\6bl?v .zອǯ́ v1& ^>{l`y6yf!Ih<P|ʼn'm&ܝRJEJmT<sgzNSᏰ _` K,r=djqLxi }:@u Z:eϳʄ;qwHyfT6Dž4NU4:kZVtsZ,*}hjmT  YX ak12c4kΛ0\=t o鄗ŕ=TjCc䰘?Uj ZI%D# <|Ѧ#D4l 9Q-}Z LI-]6"?)2>~+M.Söe Fvl@\aܛU. D9㥯ſ=2bm89Wj͒B7GҒ=m@< Fhށ8%X`=]᱄8;_7xFN&tlĆk\l"_.l^I)šuw$SEr3 oЊ{q Fgch4} ^n0t&\e8CAf 'Uȇs?{\, 4g_fT5KP`fo]!- ߨjp6'Ll!}$G}t~Y~b X0h y_|zHj)S/80~NO@SL .ZT62sA!HLL7kt)膚PNck},0?`8,y/wd9@PJMJHw! ^XB>!ފLL`_m4{{wNxlDo8] gn@~i-8hu:o_+U4.۶[ښ "GTP^}cEΓu^* 1enbD@xY,@Zk!Hxg/6:-|8յ1M%)TpZ .'ȹBLun$Dt2ֺt dqL͊9n,1B  l|.}t>l>t%4nl nBbW+p1jgl*G\q94Qxg²:B܄|//͎ň@VY(`) _n=2ʆVXVXtH t? lbBȕHKMWtzuۺ~J#gz BVhB`x\(|CNh|Lv;Rd6|j)8sxap|>H]0 `rZ%Y7RB}I >wE.0d=`}Eu&q *ls0 xf {2Ҩ8ݜabjLLB`_Z#STխ=.i͠]VQ8i󓢂$&l& ili@|AKr &##`RZ<$Fdʆ6UKGr<\}p4^.Ddݬndžf{Ak,@&&>nĄP( 76_|/ oM+Y7CoG$6ԿWW(gvF;F! }\|x?ôQk $r`zF2|bE0-# \棹C$x #nT5fd 34:_^0XUhs!t<:DyÏщa #aDB0-KO}ićO?.~Ij\NtZgNi;H@V(!T Ю0<>z<]t0:9^$r%ů.v^ x,Pieu_Ԋ=nS ,$Ą{g=o9 e20"!&%܊UQ0",& ćwW5se:H@~C}"s#!&ء ٧Fbthm>,3ޜUƄt8-+\)žC`h<<=>{!d?N׽\6AˤϻN'|Ǒ0)b&njhun0Ar!l@"@0yDBg=-Iǜˊzcp< <ӠR`C*R#ѐR@"@cHˮB҆G.DE<잸0j;\ |3vA@/Y>ΤhpPR0Dž5Z;EBb[c0(0Zk3aW}N P{c_ٵ V.K,JTk Იw܄9 @0t8nQ);!LPU1!d׵|w]Zc[7!=CaTu-zAT4Ċdz)q  XbCɮ%\޺7h$tĤSq/+z QI ?A:al @2¶a^~$:sۻ%|1ZI76a]P^.ק@B?@mЯ%Ja,,=.b[]-1މ 5w"_ol&C,];Fſ>P(<9\fԃyggeӁs" `h|͹'ףM,8,uXG Ggf@ &8 xvO$SMI1{$5=ݜ{00 L/@0Z+yi_[1;ɠ`u:8bYk^:{\J7@1S"Yc}+\6=Qڛ%I R5D4<^G Ց!"$ /;9JsH:j5=>zz!R#hq:T] yƄʲ.ٹgJdJcWY;΋XW!_%^@PIHp("|doe/sެ^޺abo568BA(l&CS!?A־ ! jX%r.xu[R_Z;6]:WOdlo`FȉY U׬{ceNbD͝+]7c D/:)tH@J<[m`czqE={3SϡI9AǿZ`JzB5ٹ=2SUXl)B  a`rZ)ٹ2ӎecod wCb{"nc-_|xzy1Ɣj }/y"\{3YH@ բgukLϧi>ZCI>h)@2 @P`rZG岙 R;pu{PG i8LIOم<.ّoW ҊHG (iAJzb軗f8d* y-CYAG (CH`SƇH~myPJvnVa>ܘ"S()/JH@!SU|Dd{zw.A~H)Y R#AsnjlU/7j}:έou] m])ہdp{6\[;4&܆.G[?gMRM!@C;Y ]vmlJt=ٹ>m՛Մ{8@P=nFO}hJs{ _1"3+9d^H@Xhf@7V-]2mMd\f]$2#?a& iT3LʧN~bB #Qk6KEƑUH@X9 ͅHh3F7lU\Ǿql;O{RT{%@@ IDAT 1{\JO,a3I}qc_7*B¢pp$ ic"@C󋲝x.}gxLQ?EQdaBTUC *eY~9S$咙{3ɏ71Uj )FԐq̍ %*GVfzwRAQ:\gԵPIy(s:MPnsDK,*V]sVguQ "fM(PcՕpty=Prf;sfTG;bKOe{dΜg_Y{ [+Z2XuMHYUXl}!Uu- TtF:tIlYֵWY 4@$3z1ju8nXp{CPOەj֬v_YcS 4Ltj4 =}'DW9Gy' 2>u]X^uP)`b,=npBe@Kf̀NqPe!A%3?<2-z8pɚD&{n TSOLxnb6O~~&T)4~52--8!@ ,:2Z{{O_GۮTuA1N>t#95uכLtWa9׷'4D64;l; b;X^g$r<3RۥN.6T?b+YrGC[Cøs}{±z aQ<\+WE1ZG\*ܑs@:zW'%ʻ >xn3 $nC4Pa58M ] QT8\{,J3 e'{OV;p7Ǻ I Mf  a+F&F4V`lX`o>xrdzC%u!TמS3hw}Ewh:x/֬Jc=n*˙+x}FkWZZ%@Z-2kz 89+fNn6GǵlX]0bQT]{dXV7M[37q[~R7~ 11߱tdj5dk#&OBH!vW .&kJk:9gB=ʩS{зg";O,^|jۼ?}H3"HV3gJZ̒H%Z@ `q<~1D%-BL%z]YG!MԏC^4%i}3ۗth#{MImg~\KbM Z8Bq~D6u;?w{B-J*l{Pr<ʱn}b+g+=q;nX!P+os^sCjrT)%7lFk= h&Kg!4E!NR(n~/|UM>"rbX}&Z{kPgD3_Ndlj&0=>ᗨZ/l#_;[һ%J.ꈿϔ%v:ݔ]2wsUj8'oT !}LN' 'plݞ3H `#$6-)h:.>ףV*-Gڙ3LHq¥"T|;jC} 2hM<mdzFXjم2N0 yqށtx Sޜy:}r̎7t:9VGrʆnyD7̵v/6_ ZrYo ap,1Cjuu{΄wGx nݓiZɱgb#I#S_Lʹʕ;/Q0uDrM= il/8I 2ԁJYcl&'Wu$f#v+G|~'rvsKpW@cuu=>^RIcHk݅dTBhd*L4 MiYHjl`  '=f_ft/ZC_733@Cfݩ-GT+tS[sO׈&n<\&IvB}Etuhj.kj)=LMŚYT: TT<g5/懨Z# \0e!̏SGSG{bI 'P: Wk4%>Ttf>$C6 [MSOdTd\0iϵd~qQstKj)16@inA-V_EԭlnJ*è5: /&S?Mȑ}K "Tb 9L=,yA%ȞPOň%a"sd0+/|s*5F3)MsLhY@\oaAP MjθJsߧG]9^$r#3oXOL̥ljs_5 4[ *^ M &)}ꊷ ^x'< `FFxڕLb_0u 33:ڜŚ̀@bl֘ʫ%5DzLNpIZyTG$<5 :Mb֐Y͝E /EN;˔q<<E.YDSkjXD*RffYS a'FbB|;nV7mR)1[(a` &Uf"-t(?9YL==+%dգ& ֛u&vc05.M IWRޜ! \%)t?;qw4ި`&;QJz=dt83@,U1^̰ ^Nݟ?=R| wfౌ> 2hj2{0M74}S{!ϥ.t7-%xvϭf%@Pߗ0`^]p\26ܵƶr?O%4l0KF*VQ\6Z3%~url{^m yJe[#N?4/4]둏hE-.Һ.g\]E(nٛ QN8DTip Y6"ׁsD k#ޛT׉Hcc5m3!oKy7ʍfϷeF۹'5)ed฾UKδ_h`d.mn~]`Ŕ:@y+$`AfZ\ ke]R +猭=p6/Tg.z{*]|JoVξs>ѐP4ݒqEO&Q2zM]cuXt wr,ҔȒ nq+%k- 0?nBzbjۚGm8P0nje0R'NOl^^nZ#jjF{µBI&ЃJ!.VFtݝ3ҨDkn?#;OϼZ ZdBB%{MeNt=yA"@p&ؘDd~M+Avvf1)7gK۫2:ٟ]|8,1C7)]Pj+:lQiE#S3"aW0Խ)})` !P(%ŇCsQ1X=oB٫%:e ]9g\AGIJk;m4K[bmzM}[gMws!h*O,QilspqykZ$w1[ӴL'N7˩5`ZUKtvbPv@ZGcy4vKKgKi r { =mn fy?n'k8|='L^-JKܡQɇ&wܛdQ-GC{p^Dɸ̎ʲ4r?Ëu*v{b)OTi`R}a }ttBOM44 8S|9"li(TqSA~Y-v9Hh 9ů5 8`!so2|Vfx:syZʆnay%-&S\xigI-c]zvoZ]i Z( <#92'8~ \!-SsNm]ᥥ3`H$*d *k˂hn$0vn;W[G"W1op?]GïQq 9Y#獍l=T8{ѩߝgLLu"@XO`> 2;@"W;#X<-_vRft1tNG~j5hȵG~zp2"*掍lVuJY5C|#hj^o?5!5Ss1\PLhu:S +dzFR=g%]")OP!Ky& aZ|]Īm s}8B͚# |y$DTliϭҩ)$.m xeGU$T6Y{ V>uŻWҩWHTkRU Ojٝ,RNH ^qCHqxQecx$sFo6A"k9 P^`px)4l.E R}y!" ŤkUj^7vX5x]lDž/" \8זƆKU 8v=͇ۍ3wldQa-DSGn_lW>R;b"ld> |x]\ VkBEsq٠c er\ҖNP
5JQm6;-/u09Ueg[$ȸ^T_sœRyyXYښNqL!9xu, ~&p&>@tX0a'^ 8cE?=9J˵f"OOQ >[!WW 7bkQrzӥmŸ&U4j4@|frլ1qd\2 jz7b(2M2c^[9$+m$?6]vyրR}g'CNj<-m.g2[)?ɋPa|[ʩ0(s]*-l)Xӳk--u_^X}]Ԋg'G*==S%A[&U5)d\/6\iVjՌbP)n~_d4מDin8!?h߁w^Ҩ >v6{z8>MѾ~,vsqj_P_ NtIpɋPXݤ$e⏏oZ5mtwmG*#%-]BoSq wrRqgz*kc߸aZVPɱrl&+0~2ѧb#Z"i kYQN̎Ϲlih > 8u LP}k'뛿.,68rv 2wbFꥹ?a^c0Z}>u|`:B-}hT'f١,yYRm2I#nZ5%3Jkwl9=]׬9]2QŷSra5yAbf̫KYG)KZ Ȭ6 0*3U !GɉvHoSL `qŁ#{-56T5MjuUۺ#Ab4Ai)0RyDΠGJGn 1x͞O8W^߸G'X5,ͩk&.iXs̺Kb9}DZLh ZVgRxlSM(KkUqsFVM$aљh'esC.nS29? @,,3vj6Eo *TP)D~c nB=PO1 @#7ti. B<:xPDldf]p_Pywn$X}Ӝgoy 1NLj9~"zuFMk?ڴ QaM;XQyЇ[vIȦ E!,KoSrQ9#\+Xӿ]ߛYm}uǭ>[&I,1ĚF빃G`.@{߃aI3?Aswh$?*"ޝjSzˉ랼01Z`l6;S?%mjۤ(m &uϽ7̨=q"jkO),Բ5)='#6KgTáʓAd\/96XvܑUcSÝ-ze,ueG_ߢ1 O?ܽBb`` 'VAyq5MUH#  L*}0n,Z7w~l\cz=*g$^[;:9֡H]Nj|{ai]_fDZQ*#sRnz4d)2 ~;q 4idgImuCФ0T/<1h)/GzKҫ v HERk C*nm^Zufbkoн(#Ⱥ^N8@" q_=@e8x#P+7Vh>\͇ !ll:.0u₴C}{+|EÐz!jWbFJrԚ?ê+_m͟GԷ.TlXO#Ӆ[8îG*ۺt.OztEQs:47.+:'Ok_:ϑ3t P\qvC?PA^Ǚ8S9kWAN_q}.V6WV8l;z6&bz2"V"uESFȞTgKGu-5n;{ӎcڛLeV0~ɿR-: aG^M_G+:ϫ0 F%1?*5.maSۨLf\"PG#e{%~Zw8YQC4vM@c3!nTRxFL_o&r߲ӲS<ޖhPΏi\uz gĵߵdZ턌DT~㡛UdhR>yߨͻF8slK6tב?zL8LP]^0 F1?:96;1(T ._~j+aK-ܤ5,~27[VW^a'y__[ acȻ.2( zc'?p;Mț\ov,fW8 zt-7;& ǤყnXQңEeѮ*&:Ŵ` Wu$Ke׭.̥ՆiLjU^lضULT\) ֲrAzuRHO5%NJݝwATqܴ57ΨujwMRܜl9XmvU'*Ș ӫc%e*=/1z^Su]4@Β;yѢ.^bhgԬ&_/p "@7 ,:_Gv()EڈP)?nsN]kCMR;{_f,;;etKŁ 6u(HٲqǢ)Րaen}7l~񨭇H;Zjv(<{jt)5P`iVrLi쑳e12[~FmFRzd#ҩg/%s5CXˣΫITj.WӨ kC^76>^6>f't6[Og%èGonqn_x1C)J5ACL8*2}}~ShFƳ4so_8pqFo~xcE ZҨQ#ZV/VkL~ 3W/mZi?6@Pp6)v;_:y**+9sǧ'^d8|]lٻ\I'9j~=X3&A51!=qPi AޱXfʿ vˆQ9=Bd|:4.ELM5`3O[# &V;kq_JG[dJmG*5-.e~z3HږvZnT tL%T$ҨBi`(*<4idKL|})*B\+)#aڈ_l\C7Aܒip-0[8F=~+Bxf<_rބ#b i\Ү ͕.{ҨP[XkhQbc.p~mGy+# VK$LˮsFoVHıݟrAg *"SS Jj[k?Y7.$: !edu&\6DQl3'~I0סY p ep?.VTMo^ LqN*R@ # fS~|$Ll-0^&/~kJkpN^rK_NxEL"NJʃyBzAB&0z76\l|gJG cr\xלϔW5jS+B9,%BޙE5T C:j:*~ }8;ᖾJi> '~ NKf0)G#2.=A5OۜPJC!^YLadBm#-T;obf&-u?LmR e9͏Wb-r# npFJU ꦎ0\,T tO`~ ՞j j6:ub!#Xh @ wNK[߃='qTɰij H&fq`nl}觌3%uFS8O`UKՒU`Mpwi`"|63ƌjWCVJg<_^Z y*# T8XmTL7-R"T tl&-Jf+ 57+u} WxFBܢ)p2?r6w?f4^xH rZ6gŴ}]ٴCЙ$7&f>&בk[unڑR6>ٌgZR" 8E{↶?TXhF_E{:/-VjC[S\<7b,:=;i">A`xapAĴl8XFs]ޙ;;>wגPG[܉l.˴pUK5 |ݞ!<~.^z `4]"Tv*&hN᳉N96q͍3knzJ9ͤYfm^Z@ Kg 7Қ'0]RgbtbżKs;!O9[Vh˞Nva,UO!ϱ>uš1~ӎ)*Ԏ|f1PIfkب{/8u)vjVrgք-{#G7w\aͳvO<6oz"ײQR+`q,Fl :BGbY)qw.Z;yݎz8fsqv|J}c|l ꁞ,i{p{J)4C7ߛf.,RlKZ6R˦猍u. M`?PU=ŁvGҟ z>FOJnZ}]n]J\g\f m]w6Hꌅq#Oݱ tj;Om)ɖ='I8Fj%[P<: ';ä?؈ ^mW`ϯ^Z% }LB.i71a܆a4gz䇝'-lݺj%Ӳ o39v;y׉f˧vBSjlDFej^Y8c$;P PV̛sԺ!B9u+Mi=?Rj9~ОIag\\FN}g-%[2-KvLi\9a]"] &@kPIFyiMv椶cָv*6 BeЧKQ CJ7LSjin=S̱#3ǎT-sNns2Gp9 @ Z@Ca@ 1~]CZ+r#&럺}aYfRv8GDĢ&K #pc @VQ;S[:f/mؿLjgqwkJmAeRolXҰ;"cinaö#1ێ NY1|bFcVt}LjzP?Mq2MhhSsb DlQ XQh7 2&+,M.79dv9uߏzP\. IDAT:?&5㳵al MN]q:u&LV2ߗ/%!grklsDcw GB\Øfـ4f?ʄ<6:*ŵ MQEG7vh>S=6g;7l!SbT]>}q;ͱhtd.݁Zg)_qpl ^Yx]nN_Zc&޷v>[>i=|gP'@$P8t]u9Fm>Z$!z‡v̙I` 3~ϕc$='P&ӟXUǂL(&YQf4**/56o_h_ F>l\0MuћTyz<Lb8G@EǩKݭ_hpUߙ![u~ }s4j8`[mY"@u}k4w9}͟y6`4qfŜ>Мp[x<>;?XBh - n$F)Ⱦ&'BL]*-J~MiOMާI\Oq9` d_SG蚇Δ~15!=No[0?OZ*;L/թ4y샅bOq

t :Qǘ` C5  eШgpÌSѳo)OyoO'XN|ɣF .೧,A@;VsFCE7 @M̮q ;ɇO,>y}S>Af]sÌ?,h,/5e4*F EΞ٧JvJl@Bo_,uҪܜӯ*/Jp5,qrc+.5z#ͻN]94Bz%!FgƎ 5Ɔ tơ3Xjtf3SyAV - J{~_H]sجz?b.qVJCwЉLIࣟպST /] 3(T( Ϲ!Rg&׷/>}rwql%R`v<|)uI7ϭwșgJCC6.9ML,}AYVCORHEz9pM;M?ˠSQ -x~2NX)vє[ 5+(&ɣF~B4 柘A@JZ~s״AyC@-4sTRLg'nŻ{Ew~iFd}J|  R(7U=oU\9O3yAC5(W읋+z[ZoR(!`5o?؜Q끉vPɢ_>f=qo̪u붜h2D^+Wy3M_0Q:d)dxxC! ևnSJ:obպ'o+o/ݰmD.O8cK#3n@xrb>(tD_k4olʟ_Ba@Lew[q 69vg t g^zFiTRf". nDZowe\? WQ 6E xO]A48i\D(W}-sRz 0C'Yg^-J16d`fbgx6@g[6-B )f)_y~}*Ai#bzz.Fr?{Ьo藺qe înBe2̼XßLڡcF*&vHi=dpCRZrdS_$߃X틋g&:dȇ7Qg t(j`2$3I5lU~ZhThAq*~L8Tmoٲ.-JV3jqtmc^ނTP%^NGg >0P Fbrzʇ?Iv"@q A<)5.XEwq_zCcB=36 @KB`˲Ǧq'[{Lg=6kP!tgWI=a@Yzϛf]c|f"@T ;T Mc} JF{ u|?f!Z@nZRۺGgz57~! CI6b5ni%kCHdxHT_p F8qű/}}|͎5BH>bi d%5:gxw$Lv'Zaqq@dء^Ss NJ(u%]wsFmM|ѳpe~VMYT[;uAg켋"wϛ鍄8\!,h x vâ{`z /yY;歌fx옮9`&ZNIn. |"e"@nË %~1Ѫ?80d(84#Y?1-+ʙן)k[m]:&c&eU( ޅFo?8ӊ(pǷ6uȽouCyPE :AC˲cq&JxShL'?>8j;i?;7hx%S?xl!#ZF_Q莱y)w%h Aa/<."Z~SG6ߴ6ZP _ DA_x״EGƤJyѢƤ5oԚ}fP# dX LsN]7-8q/_ _G75@KȰB-19'i4 _^>R⎱ % Y1gdӛqF-̗>6=b1`.@H7M%C*pƦ4-/@wn ,V2Ha㋋:y5i?`o}3[F@( +! ayV8s15Ia=6w!LȰN`0^)<-iuqvT ~ߴ e:>C|ۻg 1>vS0ܡf;Sjhb߭.aDp21:LIWItaEaѵݻ &M6:תf??=<ܐ;©%-tBXJ  hCsg?;J7Zeu?NPu$X! U&dž+3b񑡄+ ҎP<2E2lԔ6oS1be+,Vv*{WO24ˡEm5..픶NeP[2tl4Eq!h2UNSKKPqX  NHky~>>8EJ8ˁэj[L/(^w-<J/;jqGg01+$ m.]8p VG*SbÕIq 1jA&7/\j'- Yb!۫2,_dСP߄ѣ@8uZx.L924H# Q&F)GJY)i *> H/ :cάrZHE&-UMʰ{5띇fO &|"Xl%ag4[媻wݓ|k5q#̨nn;\Xzb!O+b$̤帴Hi׼q!'<}pN x mZZ{`o*߻2LȔޟc1q2&E3y Fzr^bT#` rV ںT/Ln 3-Yhm,ٲ+ XFqbeRDHR09>A`|Z?'ȴAQ_tMw ,tOM=fZ aaՁ(k`ڨvyHLcDH# V&D)S"TG*ǦKQ!"Qgdž to~wr2A|ج<&)fL-4x j~[.ZUC ;-ShcYƠ$@ܛpwv8;8atHkqX`bU6*$O\8A62T Q&DFG*S9#5d8)I0׭VkiYu*Nmԡviy2ץ6j#O3:3`qBdM^%߻B]- #8{7q 1*T+ rR㕙#bPdJ=]j#) lRhLlV,ll¶Xƍܶ+kq38L 0`zXT~Y t"TE"DpuZB&+9V#q8-2-Iav S}7*֙Zõ9#(8n0TM mGPC}coaƅޑzj]osxl$Xi%jidzDl&3)FӨ^gڰv IauJ=Ki`حg"כZ7Xzm0YY8T @w@dp~c#DRO=Y(?k 0[*8 m}?OP!BV,PGԱMBt:%.B3jD:1Zr!jo[#S]\kb&VOtF ;yܖȾ0 B)&G|al+$zTd"t%T$ЄQa"MuS)`R{UzsW4wCEN_;PJ BwpX  Wܱt5p9%?Rb꡺D>Є9#(@$ ,+DBw0;0oomhCM}'t^GȁA~`868`{Oj q AsTs w*0;8+t7C];@wqo WAAo! F(@AA @(@AA @(@AA @(@AA @(@AA @(@A=wW-IENDB`byobu-7.15/COPYING000066400000000000000000001043741522352767600136510ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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. But first, please read . byobu-7.15/Makefile.am000066400000000000000000000013671522352767600146500ustar00rootroot00000000000000if ENABLE_TRUSTMUX TRUSTMUX_SUBDIR = mobile else TRUSTMUX_SUBDIR = endif SUBDIRS = etc/byobu \ etc/profile.d \ usr/share/byobu/desktop \ usr/share/byobu/keybindings \ usr/share/byobu/pixmaps \ usr/share/byobu/pixmaps/highcontrast \ usr/share/byobu/profiles \ usr/share/byobu/status \ usr/share/byobu/tests \ usr/share/byobu/windows \ usr/share/dbus-1/services \ usr/share/doc/byobu \ usr/lib/byobu \ usr/lib/byobu/include \ usr/share/man/man1 \ usr/share/sounds/byobu \ usr/bin \ $(TRUSTMUX_SUBDIR) # mobile/ is always distributed so `make dist` is complete regardless of # whether --disable-trustmux was passed at configure time. DIST_SUBDIRS = $(SUBDIRS) mobile distclean-local: rm -rf mobile/build mobile/dist mobile/trustmux.egg-info byobu-7.15/README.md000066400000000000000000000052041522352767600140650ustar00rootroot00000000000000Byobu is a GPLv3 open source text-based window manager and terminal multiplexer. It was originally designed to provide elegant enhancements to the otherwise functional, plain, practical GNU Screen, for the Ubuntu server distribution. Byobu now includes an enhanced profiles, convenient keybindings, configuration utilities, and toggle-able system status notifications for both the GNU Screen window manager and the more modern Tmux terminal multiplexer, and works on most Linux, BSD, and Mac distributions. For more information about this package, please visit: https://byobu.org If *Byobu* is not packaged for your Linux or UNIX OS, or if you do not have administrative privileges in order to install Byobu, you may be able to install locally, using the following instructions... ### INSTALLATION 1. If you want to pull the source from the upstream git: `git clone https://github.com/dustinkirkland/byobu.git byobu-src` `cd byobu-src` 2. Or download the latest officially released version from: https://github.com/dustinkirkland/byobu 3. Extract: `tar zxvf byobu*.tar.gz && cd byobu*` 4. Generate the configure script (if it doesn't exist): `./autogen.sh` Note: GitHub release tarballs require this step. Official release tarballs from Launchpad already include `./configure` and can skip this step. 5. Configure: `./configure --prefix="$HOME/byobu"` ***OPTIONAL*** : You may use python from your environment, rather than from your distro ***echo "export BYOBU_PYTHON='/usr/bin/env python'" >> $HOME/.bashrc*** 6. Build: `make` 7. Install: `make install` 8. Update your `PATH` and `BYOBU_PREFIX` environment variables `echo "export PATH=$HOME/byobu/bin:$PATH" >> $HOME/.bashrc` `. $HOME/.bashrc` 9. Run: `byobu` > Note that you will need to have a few dependencies installed: * tmux >= 1.5 and screen * python-newt (if you want to use Byobu's configuration utility) * gsed (if your sed implementation doesn't support -i) ### CONTRIBUTION You may contribute to Byobu by forking the project on Github: $ git clone https://github.com/dustinkirkland/byobu.git You commit changes locally, and then propose a merge in Launchpad (ideally), or submit a pull request on Github (less ideally). As for coding standards, please use tabs, rather than spaces. Thanks! ### AUTHORS * Primary: Dustin Kirkland * Emeritus: Nick Barcet , Raphaël Pinson , Derek Carter ### LICENSE: https://github.com/dustinkirkland/byobu/blob/master/COPYING Dustin Kirkland 2023-11-22 byobu-7.15/autogen.sh000077500000000000000000000002041522352767600146020ustar00rootroot00000000000000#!/bin/sh set -e autoreconf -fiv cat << EOF The byobu build system is now prepared. To build here, run: ./configure make EOF byobu-7.15/byobu.txt000066400000000000000000001164111522352767600144720ustar00rootroot00000000000000 .'@@@@@@@@@@@#',` .'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#',` ,@#;. .;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;,` .@@@@@@@@@@@@+:` `;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;,` #@@@@@@@@@@@@@@@@@@@@@#',` `;@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;@@@@@.:'#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+;. +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+:. `:#@@@@@@@@@@@@@@@@@@@@@@@@@@@#;.``````@@@@@````````````.:'#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@',` `:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@'.`````````````@@@@@````````````````````````.:'#@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@.....:'#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;. :+@@@@@@@@@@@@@@@@@@@@@@@@@@@@',````````````````````@@@@@````````````````````````````````````.:'#@@@@@@@@@@@@@@@@ +@@@@..............,;+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+:` ,+@@@@@@@@@@@@@@@@@@@@@@@@@@@@+,```````````````````````````@@@@@````````````````````````````````````````````````,:'#@@@@ '@@@@........................:'#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+,``````````````````````````````````@@@@@````````````````````````````````````````````````````@@@@ '@@@@..................................;+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+:`````````````````````````````````````````@@@@@````````````````````````````````````````````````````@@@@ '@@@@...........................................,;#@@@@@@@@@@@@@@@@@@@@@@@@@@+:````````````````````````````````````````````````@@@@@````````````````````````````````````````````````````@@@@ ;@@@@.....................................................:'#@@@@@@@@@#:```````````````````````````````````````````````````````@@@@@````````````````````````````````````````````````````@@@@ ;@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@````````````````````````````````````````````````````@@@@ ;@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@````````````````````````````````````````````````````@@@@ ;@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@````````````````````.:,`````````````````````````````@@@@ :@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@``````````````````.++++++```````````````````````````@@@@ :@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@``````````````````++++++++`````````````````````````.@@@@ :@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@`````````````````,++++++++`````````````````````````.@@@@ :@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@``````````````````++++++++`````````````````````````.@@@@ ,@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@``````````````````:++++++``````````````````````````.@@@@ ,@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@`````````.+++,``````:';.```````````````````````````.@@@@ ,@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@````````+++++++````````.```````````````````````````.@@@@ .@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@```````;++++++++`````.++```````````````````````````,@@@@ .@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@```````+++++++++````,++#+``````````````````````````,@@@@ .@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@```````+++++++++```;++++```````````````````````````,@@@@ .@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@```````+++++++++``++++'````````````````````````````:@@@@ `@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@```````.+++++++:`+#++:`````````````````````````````:@@@@ `@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@````````.+++++,`++++.`+++'`````````````````````````:@@@@ `@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@``````````````.++++``+++++,````````````````````````;@@@@ `@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@`````````````,++#+```++++++````````````````````````;@@@@ `@@@@...........................................................@@@@@``````````````````````````````````````````````````````````@@@@@````````````;++++```.++++++````````````````````````'@@@@ `@@@@..........................................................,@@@@@``````````````````````````````````````````````````````````@@@@@```````````'+++'`````++++++````````````````````````'@@@@ @@@@................;':.......................................,@@@@@``````````````````````````````````````````````````````````@@@@@``````````++++;``````+++++`````````````````````````'@@@@ @@@@..............++++++,.....................................,@@@@@``````````````````````````````````````````````````````````@@@@@`````````++++,````````+++,`````````````````````````+@@@@ @@@@.............;+++++++.....................................,@@@@@````;.````````````````````````````````````````````````````@@@@@````````++++.``````````````````````````````````````+@@@@ @@@@.............++++++++.....................................,@@@@@```+++;```````````````````````````````````````````````````@@@@@``````.++#+````````````````````````````````````````+@@@@ @@@@..............+++++++.....................................,@@@@@``;++++```;+++++++````````````````````````````````````````@@@@@`````:++++`````````````````````````````````````````#@@@@ @@@@...............++++'....;++',.............................,@@@@@``+++++,`++++++++++```````````````````````````````````````@@@@@````'++++``````````````````````````````````````````#@@@@ @@@@.........+++++........++++++++,...........................,@@@@@``+++++'`++++++++++;``````````````````````````````````````@@@@@```++++;```````````````````````````````````````````#@@@# @@@@........+++++++......++++++++++...........................,@@@@@``++++++`,+++++++++```````````````````````````````````````@@@@@``++++,````````````````````````````````````````````@@@@# @@@@........+++++++,.....++++++++++,..........................,@@@@@``+++++;```;+++++.````````````````````````````````````````@@@@@`++++.`````````````````````````````````````````````@@@@# @@@@.......+++++++++.....++++++++++...........................,@@@@@``+++++```````````````````````````````````````````````````@@@@@++#+````````````````````:'',```````````````````````@@@@# @@@@.......+++++++++.:++:.;+++++++............................,@@@@@``.++++`````..````````````````````````````````````````````@@@@@+#+```````````````````;++++++:`````````````````````@@@@+ @@@@.......+++++++++.+++......................................:@@@@@```'++`````++++```````````````````````````````````````````@@@@@++```````````````````;++++++++:````````````````````@@@@+ @@@@.......+++++++++.+++......................................:@@@@@``````````:+++++``````````````````````````````````````````@@@@@'````````````````````++++++++++````````````````````@@@@+ @@@@.......:+++++++;.+++......................................:@@@@@`````'+'``++++++``````````````````````````````````````````@@@@@````````````````````.++++++++++````````````````````@@@@' @@@@........+++++++.,++;......................................:@@@@@`````+++++;+++++`````````````````````````````````````````+@@@@@`````````````````````++++++++++````````````````````@@@@' @@@@.........+++++..'++.......................................:@@@@@`````++++'`++++,````````.;,`````````````````````````````++@@@@@`````````````````````++++++++++```````,;,``````````@@@@; @@@@..........:+;...+++.......................................:@@@@@````.++++```;'`````````+++++``````````````````````````,++#@@@@@`````````````````````.++++++++``````.+++++.````````@@@@; @@@@................+++.......................................:@@@@@````+++++```````.:````+++++++````````````````````````;++++@@@@@```````````````````````++++++```````+++++++````````@@@@: @@@@................+++.......................................:@@@@@````+++++``````++++'``+++++++```````````````````````++++'`@@@@@```````````````````````````````````'+++++++:```````@@@@: @@@@...............:++:.......................................:@@@@@````++++;`````:+++++``+++++++````````,++++++++';:,.++++:``@@@@@```````````````````````````````,;``+++++++++```````@@@@: @@@@...............+++........................................:@@@@@```,#+++``````++++++,`+++++++````````.++++++++++++++++.```@@@@@````````````````````````.:+++++++,`'+++++++:```````@@@@, @@@@...............+++........................................:@@@@@```+++++``````'+++++.`;+++++'````````.+++++++++++#+++`````@@@@@``````````````````:'+++++++++++++,``+++++++````````@@@@, @@@@...............+++;'++++++++++++++++,.....................:@@@@@```+++++```````+++++```;+++'`````````.++:```````.,:'``````@@@@@````````````````.++++++++++++++++,``,+++++.````````@@@@. @@@@..............,+++++++++++++++++++++++....................:@@@@@```++++;````````+++```````````````````++;`````.```````````@@@@@```````````````'+++++++++++++++++.````:;,``````````@@@@. @@@@..............'+++++++++++++++++++++++++..................;@@@@@``,++++`````````````+`````````````````++;```.++++`````````@@@@@`````````````.+#++++#+++++;,```````````````````````@@@@. @@@@..............::,...................++++++................;@@@@@``+++++````````````+++``:++'``````````++'```+++++'````````@@@@@````````````'+++++++,``````````````````````````````@@@@` @@@@.....................................,++++++..............;@@@@@``+++++```````````++++`++++++.````````++'``,++++++````````@@@@@``````````.+#+++#+.``````````````'++,``````````````@@@@` @@@@.......................................:+++++'............;@@@@@``+++#:``````````++#+`'+++++++````````++'``;++++++````````@@@@@`````````'+++++++```````````````+++++.`````````````@@@@ @@@@..................:;:....................;+#+#+;..........;@@@@@`:++++`````````.++#+``++++++++````````+++``,++++++````````@@@@@```````.+#+++#+.````````````````++++++`````````````@@@@ @@@@...............'+++++++'...................'+++#+:........;@@@@@`+++++````````,++++```;+++++++````````+++```+++++;````````@@@@@``````'+++++++``````````````````++++++`````````````@@@@ @@@@..............+++++++++++....................'+++++,......;@@@@@`+++++```````:+++'`````++++++.````````+++````++++``++++```@@@@@````.+++++#+,```````````````````++++++`````````````@@@@ @@@@..............+++++++++++......................++++++.....;@@@@@`+++#:``````'+++'```````.++;``````````+++`````````++++++``@@@@@```'+++++++`````````````````````+++++.`````````````@@@@ @@@@........+++...+++++++++++........................++++++...;@@@@@:++++``````'+++;``````````````````````+++````:++``++++++``@@@@@``+++++#+,```````````````````````'++.``````````````@@@@ @@@@.......+++++...+++++++++...........................++++++.;@@@@@+++++`````++++:```````````````````````+++``,++++.`'++++:``@@@@@;+++++++```````````````````````````````````````````@@@@ @@@@.......+++++....:+++++:.............................,+++++#@@@@@+++++````+#++.````````````````````````+++.+++++#+``'++;```@@@@@++++++,````````````````````````````````````````````@@@@ @@@@.......+++++,.:+':....................................:+++#@@@@@++++,```++++.`````````````````````````+++++++++'``````````@@@@@+++++``````````````````````````````````````````````@@@@ @@@@.......+++++,.+++++++++:................................;+#@@@@@++++```++++```````````````````````````++++++++``++++.`````@@@@@+++,```````````````````````````````````````````````@@@@ @@@@.......+++++..++++++++++'.................................+@@@@@++++``++++``````````````````````````'+++++++````+++++````;@@@@@++`````````````````````````````````````````````````@@@@ @@@@,......;++++..++++#+++++++................................'@@@@@++++`++#+`````````````````````````:+++++++.`````:+++````++@@@@@,``````````````````````````````````````````````````@@@@ @@@@,.......;+'.......:'+++++++...............................'@@@@@+++:++#+````````````````````````,+++++++:`````````````:+++@@@@@```````````````````````````````````````````````````@@@@ @@@@,.............;++'....;+++++:.............................'@@@@@+++++++```````````````````````.+++++#+;``````````````+++++@@@@@```````````````````````````````````````````````````@@@@ @@@@,...........'+++++++....++++++............................'@@@@@++++++```````````````````````+++++++'``````````````:++++++@@@@@```````````````````````````````````````````````````@@@@ @@@@:..........++++++++++....+#++#+...........................'@@@@@++++'``````````````````````++++++++```````````````+++++++:@@@@@```````````````````````````````````````````````````@@@@ @@@@:..........++++++++++;....'+++++..........................'@@@@@+++;``````````````````````'++++++```````````````:+++++++``@@@@@```````````````````````````````````````````````````@@@@ @@@@:..........+++++++++++.....:+++++;........................'@@@@@++;```````````````````````.++++.```````````````+++++++:```@@@@@```````````````````````````````````````````````````@@@@ @@@@:..........++++++++++;.......++++++.......................'@@@@@++;````````````````````````++++``````````````:+++++++`````@@@@@```````````````````````````````````````````````````@@@@ @@@@:..........++++++++++.........++++#+......................'@@@@@++;````````````````````````++++`````````````+++++++:``````@@@@@```````````````````````````````````````````````````@@@@ @@@@;...........++++++++...........'+++++,....................'@@@@@++'````````````````````````;+++```````````,+++++++````````@@@@@```````````````````````````````````````````````````@@@@ @@@@;.............'+++,.............,+++++'...................#@@@@@++'`````````````````````````+++;`````````+++++++;`````````@@@@@``````````````````````````````````````````````````.@@@@ @@@@;.................................++++++...............:++#@@@@@+++`````````````````````````++++````````+#+++++```````````@@@@@``````````````````````````````````````````````````.@@@@ @@@@;..................................++++++............+++++@@@@@@+++`````````````````````````++++```````;+++++;````````````@@@@@``````````````````````````````````````````````````.@@@@ @@@@'...................................'+++++,.......;+++++++@@@@@@+++`````````````````````````;+++``````.+++++``````````````@@@@@``````````````````````````````````````````````````.@@@@ @@@@'....................................,+++++'...,+++++++#+++@@@@@+++``````````````````````````+++;`````+++++```````````````@@@@@``````````````````````````````````````````````````.@@@@ @@@@'......................................+#++++'+++++++++;..+@@@@@+++``````````````````````````++++````+++++.```````````````@@@@@``````````````````````````````````````````````````.@@@@ @@@@'.......................................+++++++++++++.....+@@@@@+++``````````````````````````++++```+++++;````````````````@@@@@``````````````````````````````````````````````````,@@@@ @@@@'........................................;++++++++:.......+@@@@@++++`````````````````````````:+++.`+#++++`````````````````@@@@@``````````````````````````````````````````````````,@@@@ @@@@+..........................................++++'..........+@@@@@+++++.````````````````````````+++';+++++``````````````````@@@@@``````````````````````````````````````````````````,@@@@ @@@@+...........................................+,............+@@@@@++++++.```````````````````````+++++++++```````````````````@@@@@``````````````````````````````````````````````````:@@@@ @@@@+.........................................................+@@@@@.++++++:``````````````````````++++++++````````````````````@@@@@``````````````````````````````````````````````````:@@@@ @@@@+.........................................................+@@@@@``++++++;`````````````````````:#+++++.````````````````````@@@@@``````````````````````````````````````````````````:@@@@ @@@@#.........................................................+@@@@@```++++++'`````````````````````+++++;`````````````````````@@@@@``````````````````````````````````````````````````;@@@@ @@@@#.........................................................#@@@@@````+++++++```````````````````+#++++``````````````````````@@@@@``````````````````````````````````````````````````;@@@@ @@@@#.........................................................#@@@@@`````+#+++++`````````````````;+++++```````````````````````@@@@@``````````````````````````````````````````````````'@@@@ @@@@#.........................................................#@@@@@``````+++++#+```````````````.+++++````````````````````````@@@@@``````````````````````````````````````````````````'@@@@ @@@@#.........................................................#@@@@@```````+++++++``````````````+++++`````````````````````````@@@@@``````````````````````````````````````````````````'@@@@ @@@@#.........................................................#@@@@@````````'++++++````````````+++++.`````````````````````````@@@@@``````````````````````````````````````````````````+@@@@ @@@@@.........................................................#@@@@@`````````'++++++``````````+++++;``````````````````````````@@@@@``````````````````````````````````````````````````+@@@@ #@@@@.........................................................#@@@@@``````````;++++++````````+#++++```````````````````````````@@@@@``````````````````````````````````````````````````+@@@@ #@@@@.........................................................#@@@@@```````````,++++++.`````;+++++````````````````````````````@@@@@``````````````````````````````````````````````````#@@@@ #@@@@.........................................................#@@@@@````````````.++++++,```.+++++`````````````````````````````@@@@@``````````````````````````````````````````````````#@@@@ +@@@@.........................................................#@@@@@`````````````.++++++:``+++++``````````````````````````````@@@@@``````````````````````````````````````````````````#@@@# +@@@@.........................................................#@@@@@```````````````++++++;+++++.``````````````````````````````@@@@@``````````````````````````````````````````````````@@@@# +@@@@.........................................................#@@@@@````````````````++++++++++;```````````````````````````````@@@@@``````````````````````````````````````````````````@@@@# +@@@@.........................................................#@@@@@`````````````````+++++++++````````````````````````````````@@@@@``````````````````````````````````````````````````@@@@# '@@@@.........................................................@@@@@@``````````````````+#+++++`````````````````````````````````@@@@@``````````````````````````````````````````````````@@@@+ '@@@@.........................................................@@@@@@```````````````````++++++,````````````````````````````````@@@@@``````````````````````````````````````````````````@@@@+ '@@@@.........................................................@@@@@@````````````````````++++++````````````````````````````````@@@@@`````````````````;+++'````````````````````````````@@@@+ '@@@@.........................................................@@@@@@`````````````````````+++++.```````````````````````````````@@@@@````````````````+++++++```````````````````````````@@@@' ;@@@@.........................................................@@@@@@``````````````````````+++++```````````````````````````````@@@@@```````````````+++++++++``````````````````````````@@@@' ;@@@@.........................................................@@@@@@``````````````````````+++++```````````````````````````````@@@@@```````++++:```+++++++++``````````````````````````@@@@; ;@@@@.........................................................@@@@@@```````````````````````+++++``````````````````````````````@@@@@`````.++++++'``+++++++++``````````````````````````@@@@; :@@@@.........................................................@@@@@@```````````````````````+++++``````````````````````````````@@@@@`````++++++++``'++++++++``````;+;`````````````````@@@@; :@@@@.........................................................@@@@@@```````````````````````.+++++`````````````````````````````@@@@@`````++++++++;``+++++++`````:+++++:```````````````@@@@: :@@@@.........................................................@@@@@@````````````````````````+++++`````````````````````````````@@@@@`````++++++++;```.+++.`````,+++++++.``````````````@@@@: :@@@@.........................................................@@@@@@````````````````````````,++++'````````````````````````````@@@@@`````++++++++.`;:``````````+++++++++``````````````@@@@, ,@@@@.........................................................@@@@@@`````````````````````````+++++````````````````````````````@@@@@`````:+++++++`+++.````````.+++++++++``````````````@@@@, ,@@@@.........................................................@@@@@@`````````````````````````:++++'```````````````````````````@@@@@``````;+++++`+++++````````;+++++++++:`````````````@@@@. ,@@@@.........................................................@@@@@@``````````````````````````+++++```````````````````````````@@@@@````````..``++++++.```````'+++++++++;`````````````@@@@. ,@@@@.........................................................@@@@@@``````````````````````````;#++#;``````````````````````````@@@@@``````````.++++++`````````:+++++++++:`````````````@@@@. .@@@@.........................................................@@@@@@```````````````````````````+++++``````````````````````````@@@@@`````````:++++#+```````````+++++++++``````````````@@@@` .@@@@.........................................................@@@@@@```````````````````````````'++++:`````````````````````````@@@@@````````'+++++++++'````````+++++++++``````````````@@@@` .@@@@.........'+++;...........................................@@@@@@````````````````````````````+++++`````````````````````````@@@@@```````++++++':++++````````.+++++++```````````````@@@@ `@@@@........+++++++..........................................@@@@@@````````````````````````````'++++,````````````````````````@@@@@``````++++++:`,++++`````````.+++++.```````````````@@@@ `@@@@.......+++++++++.........................................@@@@@@`````````````````````````````+++++````````````````````````@@@@@`````++++++.```;++,```````````.:.`````````````````@@@@ `@@@@.......+++++++++.........................................@@@@@@`````````````````````````````+++++.```````````````````````@@@@@```.++++#+``````````````````''````````````````````@@@@ `@@@@.......++++++++;.........................................@@@@@@``````````````````````````````+++++```````````````````````@@@@@``;++++++`````````````````++++`````.,,.```````````@@@@ `@@@@........++++++'...............................,:;'+++++'.@@@@@@``````````````````````````````+++++.``````````````````````@@@@@`'++++++````````````````++++++'``;++++++'`````````@@@@ `@@@@..........:':.................,:;'++++++++++++#++++++++++@@@@@@```````````````````````````````+++++``````````````````````@@@@@++++++;```````````````+++++++++`++++++++++````````@@@@ `@@@@..............,:;''++++++++++++++++++++++++++++++++++++++@@@@@@```````````````````````````````+++++``````````````````````@@@@@+++++,``````````````+++++++++:``++++++++++````````@@@@ @@@@...........++++++++++++++++++++++++++++++++++++++++++++++@@@@@@`````````````````````````````,+++++++`````````````````````@@@@@++++``````````````+++++++++:````++++++++++````````@@@@ @@@@...........+++++++++++++++++++++++++++++++++++';:,....'++@@@@@@```````````````````````````:+++++++++`````````````````````@@@@@+#+`````````````+++++++++:``````++++++++++````````@@@@ @@@@...........+++++++++++++++++++';:,.....................;+@@@@@@`````````````````````````'+#++++#+++++````````````````````@@@@@++````````````+++++++++:````.````'++++++'`````````@@@@ @@@@....,;:....+++';:,......................................,@@@@@@```````````````````````+++++++++;+++++,``````````````````+@@@@@'```````````+++++++++:```.+++++`````,,````````````@@@@ @@@@...+++++;................................................@@@@@@+````````````````````+++++++++:``,++++++:```````````````+#@@@@@``````````+++++++++,`````+++++++``````````````````@@@@ @@@@..+++++++......'+++;.....................................@@@@@@++.```````````````.+++++++++.`````++++++++;````````````+++@@@@@````````+++++++++,``````.+++++++``````````````````@@@@ @@@@..+++++++'...,+++++++....................................@@@@@@+++:````````````:+++++++++````````:+++++++#+'````````.++++@@@@@`````.+++++++++,`````````+++++++``````````````````@@@@ @@@@..+++++++'...+++++++++...................................@@@@@@++++'`````````;++++++#++````````````++++++++++'`````:++++#@@@@@```.+++++++++,```````````.+++++```````````````````@@@@ @@@@..+++++++....+++++++++...................................@@@@@@++++++``````'++++++++'````````````````'++++++++++``'++++++@@@@@`.+++++++++,``````````````````````````````````````@@@@ @@@@...+++++.....+++++++++...................................@@@@@@`++++++```+++++++++;``````````````````.+++#+++++++++++++;`@@@@@+++++++++.````````````````````````````````````````@@@@ @@@@..............+++++++....................................@@@@@@``+++++++++++++++,```````````````````'++#+;++++++++++++,``@@@@@+++++++.``````````````````````````````````````````@@@@ @@@@................;':......................................@@@@@@```++++++++++++.````````````````````+#+++```:++++++++++.``@@@@@+++++.````````````````````````````````````````````@@@@ @@@@.........................................................@@@@@@````;++++++++`````````````````````:++++:``````:+++++++++++@@@@@+++.``````````````````````````````````````````````@@@@ @@@@.........................................................@@@@@@`````.++#+'``````````````````````+++++``````````,+++++++++@@@@@+.```````````````````````````````````````````````.@@@@ @@@@.........................................................@@@@@@```````+;``````````````````````.++++'`````````````.+++++++@@@@@`````````````````````````````````````````````````.@@@@ @@@@.........................................................@@@@@@``````````````````````````````'++#+``````````````````+++++@@@@@`````````````````````````````````````````````````.@@@@ @@@@.........................................................@@@@@@`````````````::``````````````+++++`````````````````````+++@@@@@:````````````````````````````````````````````````.@@@@ @@@@.........................................................@@@@@@```````````++++++``````````;++++,````````````````````````+@@@@@+'```````````````````````````````````````````````.@@@@ @@@@.........................................................@@@@@@``````````'+++++++````````+++++```````````````````````````@@@@@+++``````````````````````````````````````````````.@@@@ @@@@.........................................................@@@@@@``````````++++++++``````,++++;````````````````````````````@@@@@++#+`````````````````````````````````````````````,@@@@ @@@@.........................................................@@@@@@``````````++++++++`````+++#+``````````````````````````````@@@@@+++++````````````````````````````````````````````,@@@@ @@@@.........................................................@@@@@@``````````++++++++```.++++'```````````````````````````````@@@@@++++++,``````````````````````````````````````````,@@@@ @@@@.........................................................@@@@@@``````````.++++++;``'++++.````````````````````````````````@@@@@;++++++;`````````````````````````````````````````:@@@@ @@@@.........................................................@@@@@@```````````.++++:``+++++``````````````````````````````````@@@@@`,+++++++````````````````````````````````````````:@@@@ @@@@.........................................................@@@@@@``````````````````++++:```````````````````````````````````@@@@@``.+++++++```````````````````````````````````````:@@@@ @@@@.........................................................@@@@@@``````````````````'++``++.````````````````````````````````@@@@@````+#+++++``````````````````````````````````````;@@@@ @@@@.........................................................@@@@@@```````````````````'``'+++````````````````````````````````@@@@@`````+++++++.````````````````````````````````````;@@@@ @@@@.........................................................@@@@@@``````````````````````++++,```````````````````````````````@@@@@``````'++++++:```````````````````````````````````;@@@@ @@@@.........................................................@@@@@@`````````````.++++.```++++'```````````````````````````````@@@@@```````:++++++'``````````````````````````````````'@@@@ @@@@.........................................................@@@@@@`````````````++++++```++++'```````````````````````````````@@@@@````````.+++++++`````````````````````````````````'@@@@ @@@@.........................................................@@@@@@````````````:++++++;``++++:```````````````````````````````@@@@@``````````+++++#+````````````````````````````````+@@@@ @@@@.........................................................@@@@@@`````````````++++++```++++````````````````````````````````@@@@@```````````+++++++.``````````````````````````````+@@@@ @@@@.........................................................@@@@@@`````````````.++++.````++:````````````````````````````````@@@@@````````````+++++++,`````````````````````````````+@@@@ @@@@.........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@`````````````;++++++;````````````````````````````#@@@@ @@@@.........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@``````````````,+++++++```````````````````````````#@@@@ @@@@.........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@````````````````+++++#+``````````````````````````#@@@# @@@@.........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@`````````````````+#+++++`````````````````````````@@@@# @@@@,........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@``````````````````+++++++.```````````````````````@@@@# @@@@,........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@```````````````````'++++++:``````````````````````@@@@# @@@@,........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@````````````````````,++++++'`````````````````````@@@@# @@@@,........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@`````````````````````.+++++++````````````````````@@@@+ @@@@:........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@```````````````````````+++++++```````````````````@@@@+ @@@@:........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@````````````````````````+++++++.`````````````````@@@@' @@@@:........................................................@@@@@@``````````````````````````````````````````````````````````@@@@@`````````````````````````'++++++,````````````````@@@@' @@@@:...................................................:+@@@@@@@@@@#;.``````````````````````````````````````````````````````@@@@@``````````````````````````;++++++'```````````````@@@@; @@@@:..........................................:'@@@@@@@@@@@@@@@@@@@@@@@@@@#;.```````````````````````````````````````````````@@@@@```````````````````````````.+++++++``````````````@@@@; @@@@;.................................,;#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;.````````````````````````````````````````@@@@@`````````````````````````````++++++:`````````````@@@@; @@@@;.........................;+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;.`````````````````````````````````@@@@@``````````````````````````````++++'``````````````@@@@: @@@@;................:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;. ,+@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;.``````````````````````````@@@@@```````````````````````````````+++```````````````@@@@: @@@@;.......,;#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+, ,+@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;.```````````````````@@@@@````````````````````````````````;````.,;'#@@@@@@@@@@@, @@@@++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+:` ,+@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;.````````````@@@@@````````````````````````.,:'#@@@@@@@@@@@@@@@@@@@@@@@@, @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;. ,+@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;.`````@@@@@```````````.,:'#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@+, ,+@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@:'#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@' @@@@@@@@@@@@@@@+:` ,+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#':. @@@@@#;. ,+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#':. ,+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#':. ,+@@@@@@@@@#':. byobu-7.15/configure.ac000066400000000000000000000045721522352767600151030ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.61]) AC_INIT([byobu], [7.15], [https://byobu.org]) AC_CONFIG_SRCDIR([usr/bin/byobu.in]) AM_INIT_AUTOMAKE([foreign]) AC_PROG_LN_S # Checks for programs. # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. # Trustmux — mobile companion daemon. Enabled by default; pass # --disable-trustmux to skip installing the daemon, CLIs, and PWA assets # (e.g. for a minimal byobu install without a Python tornado runtime dep). AC_ARG_ENABLE([trustmux], [AS_HELP_STRING([--disable-trustmux], [do not install the Trustmux mobile companion daemon @<:@default=enabled@:>@])], [enable_trustmux=$enableval], [enable_trustmux=yes]) AM_CONDITIONAL([ENABLE_TRUSTMUX], [test "x$enable_trustmux" = "xyes"]) AC_OUTPUT(Makefile \ mobile/Makefile \ etc/byobu/Makefile \ etc/profile.d/Makefile \ etc/profile.d/Z97-byobu.sh \ usr/bin/byobu \ usr/bin/byobu-config \ usr/bin/byobu-ctrl-a \ usr/bin/byobu-disable \ usr/bin/byobu-disable-prompt \ usr/bin/byobu-enable \ usr/bin/byobu-enable-prompt \ usr/bin/byobu-export \ usr/bin/byobu-janitor \ usr/bin/byobu-launch \ usr/bin/byobu-launcher \ usr/bin/byobu-launcher-install \ usr/bin/byobu-launcher-uninstall \ usr/bin/byobu-layout \ usr/bin/byobu-prompt \ usr/bin/byobu-quiet \ usr/bin/byobu-reconnect-sockets \ usr/bin/byobu-select-backend \ usr/bin/byobu-select-profile \ usr/bin/byobu-select-session \ usr/bin/byobu-shell \ usr/bin/byobu-silent \ usr/bin/byobu-status \ usr/bin/byobu-status-detail \ usr/bin/byobu-ugraph \ usr/bin/byobu-ulevel \ usr/lib/byobu/include/config.py \ usr/lib/byobu/include/dirs \ usr/lib/byobu/include/toggle-utf8 \ usr/share/byobu/tests/byobu-time-notifications \ usr/share/byobu/desktop/Makefile \ usr/share/byobu/keybindings/Makefile \ usr/share/byobu/pixmaps/Makefile \ usr/share/byobu/pixmaps/highcontrast/Makefile \ usr/share/byobu/profiles/Makefile \ usr/share/byobu/status/Makefile \ usr/share/byobu/tests/Makefile \ usr/share/byobu/windows/Makefile \ usr/share/dbus-1/services/Makefile \ usr/share/doc/byobu/Makefile \ usr/lib/byobu/Makefile \ usr/lib/byobu/include/Makefile \ usr/share/sounds/byobu/Makefile \ usr/share/man/man1/Makefile usr/bin/Makefile) byobu-7.15/etc/000077500000000000000000000000001522352767600133605ustar00rootroot00000000000000byobu-7.15/etc/byobu/000077500000000000000000000000001522352767600145005ustar00rootroot00000000000000byobu-7.15/etc/byobu/Makefile.am000066400000000000000000000001031522352767600165260ustar00rootroot00000000000000etcdir = @sysconfdir@/@PACKAGE@/ dist_etc_DATA = backend socketdir byobu-7.15/etc/byobu/backend000066400000000000000000000003401522352767600160070ustar00rootroot00000000000000# BYOBU_BACKEND can currently be "screen" or "tmux" # Override this on a per-user basis by editing "$BYOBU_CONFIG_DIR/backend" # or by launching either "byobu-screen" or "byobu-tmux" instead of "byobu". BYOBU_BACKEND="tmux" byobu-7.15/etc/byobu/socketdir000066400000000000000000000007101522352767600164100ustar00rootroot00000000000000# Set the location of the socket directory that byobu will use. # On Debian/Ubuntu systems, this is in /var/run/screen, but on # other distros, it might be elsewhere, such as /tmp/screens # depending on your compilation. # # This file will be sourced by both shell scripts and python code, # so please ensure that: # * the variable name is SOCKETDIR # * there is no space around the "=" # * and that the path value is quoted SOCKETDIR="/var/run/screen" byobu-7.15/etc/profile.d/000077500000000000000000000000001522352767600152425ustar00rootroot00000000000000byobu-7.15/etc/profile.d/Makefile.am000066400000000000000000000000701522352767600172730ustar00rootroot00000000000000etcdir = @sysconfdir@/profile.d etc_DATA = Z97-byobu.sh byobu-7.15/etc/profile.d/Z97-byobu.sh.in000066400000000000000000000030551522352767600177150ustar00rootroot00000000000000# Z97-byobu.sh - allow any user to opt into auto-launching byobu # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . # Allow any user to opt into auto-launching byobu by setting LC_BYOBU=1 # Apologies for borrowing the LC_BYOBU namespace, but: # a) it's reasonable to assume that no one else is using LC_BYOBU # b) LC_* is sent and receieved by most /etc/ssh/ssh*_config if [ -r "@prefix@/bin/byobu-launch" ]; then if [ "$LC_BYOBU" = "0" ]; then true elif [ "$LC_BYOBU" = "1" ]; then . @prefix@/bin/byobu-launch elif [ -e "/etc/byobu/autolaunch" ]; then . @prefix@/bin/byobu-launch elif [ "$LC_TERMTYPE" = "byobu" ]; then . @prefix@/bin/byobu-launch elif [ "$LC_TERMTYPE" = "byobu-screen" ]; then export BYOBU_BACKEND="screen" . @prefix@/bin/byobu-launch elif [ "$LC_TERMTYPE" = "byobu-tmux" ]; then export BYOBU_BACKEND="tmux" . @prefix@/bin/byobu-launch fi fi # vi: syntax=sh ts=4 noexpandtab byobu-7.15/experimental/000077500000000000000000000000001522352767600153025ustar00rootroot00000000000000byobu-7.15/experimental/byobu-classroom000077500000000000000000000105761522352767600203610ustar00rootroot00000000000000#!/bin/sh -e # # byobu-classroom - set up a byobu-classroom shared screen session, # with one writer and many guest readers # # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" . "/usr/lib/$PKG/include/shutil" usage() { echo echo "Usage: $0 [HOSTUSER [GUESTUSER]]" echo echo "If HOSTUSER is unspecified, \$SUDO_USER [$SUDO_USER] is used." echo "If GUESTUSER is unspecified, 'guest' is used." echo } [ -n "${1}" ] && HOSTUSER="${1}" || HOSTUSER="$SUDO_USER" [ -n "${2}" ] && GUESTUSER="${2}" || GUESTUSER="guest" # Ensure that our host user exists while ! id "$HOSTUSER" >/dev/null 2>&1; do error "Host user does not exist" id "$HOSTUSER" usage exit 1 done # Ensure that there is not already a guest user while id "$GUESTUSER" >/dev/null 2>&1; do echo info "To operate in classroom mode, we must create the [$GUESTUSER] user." info "There is already a [$GUESTUSER] user on this system." echo echo "Do you want to permanently delete the [$GUESTUSER] user now? [y/N]: " c=$(head -n1) case "$c" in y|Y) deluser --force --remove-home "$GUESTUSER" info "[$GUESTUSER] user deleted" ;; *) error "[$GUESTUSER] user still exists" id "$GUESTUSER" ;; esac done # Ensure that our new guest exists while ! id "$GUESTUSER" >/dev/null 2>&1; do echo info "To operate in classroom mode, we must create the [$GUESTUSER] user." echo echo "Do you want to create the [$GUESTUSER] user now? [y/N]: " c=$(head -n1) case "$c" in y|Y) # Hardcode password to "guest" cryptpw="ubXWbZ4Ffn.mg" useradd -m -s /bin/bash -p "$cryptpw" "$GUESTUSER" touch "/home/$GUESTUSER/.screenrc" chown -R root:root /home/$GUESTUSER info "Guest user created" ;; *) error "[$GUESTUSER] user does not exist" id "$GUESTUSER" ;; esac done # Ensure the correct permissions on screen binary screen=$(which screen) while [ $(stat -c%a "$screen") != "6755" ]; do echo ls -alF "$screen" info "To operate in classroom mode, $screen must have 6755 permissions." printf "Do you want to set this now? [y/N]: " c=$(head -n1) case "$c" in y|Y) dpkg-statoverride --add root root 6755 "$screen" info "Updated $screen" echo info "To revert this later, run:" info " sudo dpkg-statoverride --remove $screen" ;; *) error "Incorrect permissions on $screen" ls -alF "$screen" ;; esac done # Ensure correct permissions on screen's run directory service screen-cleanup start # Ensure that SSH configuration is correct while [ $(grep -c "#byobu-classrom" /etc/ssh/sshd_config) != "4" ]; do echo info "To operate in classroom mode, SSH must:" info " a) have password authentication enabled" info " b) disable TCP Forwarding" info " c) force the guest user's login command" echo printf "Do you want to set these now? [y/N]: " c=$(head -n1) case "$c" in y|Y) $BYOBU_SED_INLINE -e '/#byobu-classroom/d' /etc/ssh/sshd_config || true echo " PasswordAuthentication yes #byobu-classroom AllowTcpForwarding no #byobu-classroom Match User $GUESTUSER #byobu-classroom ForceCommand exec screen -x $HOSTUSER/byobu-classroom #byobu-classroom " >> /etc/ssh/sshd_config echo info "To revert this later, run:" info " sudo sed -i -e '/#byobu-classroom/d' /etc/ssh/sshd_config" ;; *) error "Incorrect sshd configuration" ;; esac done service ssh restart # Launch the session detached su -l $HOSTUSER -c 'byobu -c /usr/share/byobu/profiles/classroom -d -m -S byobu-classroom -t shell bash' info "Byobu classroom setup successfully!" echo info "Please tell your guests to:" info " ssh -C $GUESTUSER@$(hostname)" info "with password=guest" echo info "As the host, you should connect with:" info " ssh -C $HOSTUSER@$(hostname)" info "to control the session" echo # vi: syntax=sh ts=4 noexpandtab byobu-7.15/homebrew/000077500000000000000000000000001522352767600144155ustar00rootroot00000000000000byobu-7.15/homebrew/Formula/000077500000000000000000000000001522352767600160225ustar00rootroot00000000000000byobu-7.15/homebrew/Formula/byobu.rb000066400000000000000000000026751522352767600175010ustar00rootroot00000000000000class Byobu < Formula desc "Text-based window manager and terminal multiplexer" homepage "https://github.com/dustinkirkland/byobu" url "https://github.com/dustinkirkland/byobu/archive/refs/tags/7.10.tar.gz" sha256 "441d8da91d4b944cb3b3bf859272409365098af7b14c14cbf05675a9c76fd15f" version "7.10" license "GPL-3.0-only" head "https://github.com/dustinkirkland/byobu.git", branch: "master" depends_on "autoconf" => :build depends_on "automake" => :build depends_on "newt" depends_on "tmux" on_macos do depends_on "coreutils" depends_on "gettext" end conflicts_with "ctail", because: "both install `ctail` binaries" def install system "autoreconf", "--force", "--install", "--verbose" system "./configure", *std_configure_args system "make" ENV.deparallelize { system "make", "install" } byobu_python = Formula["newt"].deps .find { |d| d.name.match?(/^python@\d\.\d+$/) } .to_formula .libexec/"bin/python" lib.glob("byobu/include/*.py").each do |script| byobu_script = "byobu-#{script.basename(".py")}" libexec.install(bin/byobu_script) (bin/byobu_script).write_env_script(libexec/byobu_script, BYOBU_PYTHON: byobu_python) end end test do system bin/"byobu-status" assert_match "open terminal failed", shell_output("#{bin}/byobu-select-session 2>&1", 1) end end byobu-7.15/homebrew/Formula/trustmux.rb000066400000000000000000000042301522352767600202610ustar00rootroot00000000000000class Trustmux < Formula include Language::Python::Virtualenv desc "Monitor and interact with tmux/Byobu sessions from your phone" homepage "https://trustmux.app" url "https://files.pythonhosted.org/packages/fd/d7/2950498369e93cbd301fe8d528efe3a5c248d263164c1ac69fc9d950a11e/trustmux-7.0.tar.gz" sha256 "61bb6de895226595d9a99936f41965b3421e55b826474f572b5aefabbab969e9" version "7.0" license "GPL-3.0-or-later" head "https://github.com/dustinkirkland/byobu.git", branch: "master" depends_on "python@3.12" depends_on "tmux" depends_on "rust" => :build # required to compile cryptography's Rust extension resource "tornado" do url "https://files.pythonhosted.org/packages/50/57/6d7303a77ae439d9189108f76c0c4fd89ee5e2cc8387bffb55232565c4ed/tornado-6.5.6.tar.gz" sha256 "9a365179fe8ff6b8766f602c0f67c185d778193e9bdd828b19f0b6ed7764177d" end resource "pycparser" do url "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz" sha256 "600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29" end resource "cffi" do url "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz" sha256 "44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529" end resource "cryptography" do url "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz" sha256 "266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a" end def install virtualenv_install_with_resources end test do # Daemon is not running — status exits 0 and prints "not running" assert_match "trustmux not running", shell_output("#{bin}/trustmux status") # --help should work without a running daemon assert_match "usage:", shell_output("#{bin}/trustmux --help") # Regression: cryptography must be importable in the bundled venv (GH: #113) system libexec/"bin/python3", "-c", "from cryptography.hazmat.primitives.asymmetric import ec; ec.generate_private_key(ec.SECP256R1())" end end byobu-7.15/mobile/000077500000000000000000000000001522352767600140545ustar00rootroot00000000000000byobu-7.15/mobile/Makefile.am000066400000000000000000000053341522352767600161150ustar00rootroot00000000000000# Trustmux — mobile companion daemon for byobu/tmux. # # The wrappers in $(bindir) import the trustmux Python package from a fixed # location (trustmuxpydir), so we install the modules to a flat directory # tree rather than into Python's site-packages. This keeps autotools-based # installs decoupled from any system Python's site-packages layout, and # matches what downstream distro packaging has historically done. # # A parallel pip/PyPI distribution is built from this same source via # pyproject.toml; the two installation paths are independent. # Use $(prefix)/lib explicitly rather than $(libdir) so that Debian # multiarch builds (libdir=/usr/lib/x86_64-linux-gnu) still land Python # modules in the arch-independent /usr/lib/trustmux that the wrappers # expect — matching the historical Debian layout. trustmuxpydir = $(prefix)/lib/trustmux trustmuxmoddir = $(trustmuxpydir)/trustmux dist_trustmuxmod_DATA = \ trustmux/__init__.py \ trustmux/__main__.py \ trustmux/_daemon.py \ trustmux/_ctl.py \ trustmux/_pair.py \ trustmux/_unpair.py \ trustmux/_enable.py \ trustmux/_disable.py trustmuxstaticdir = $(datadir)/trustmux/static dist_trustmuxstatic_DATA = \ trustmux/static/index.html \ trustmux/static/app.js \ trustmux/static/sw.js \ trustmux/static/trustmux.svg \ trustmux/static/trustmux-logo.svg trustmuxiconsdir = $(datadir)/trustmux/static/icons dist_trustmuxicons_DATA = \ trustmux/static/icons/icon-192.png \ trustmux/static/icons/icon-512.png dist_man1_MANS = \ man/man1/trustmux.1 \ man/man1/trustmuxd.1 # Generated wrappers — sed-substitute @trustmuxpydir@ at build time so # the path resolves to the actual configure --prefix. Using Make rules # rather than AC_CONFIG_FILES because $(libdir) is only fully expanded # at Make time, not configure time. WRAPPERS = \ trustmux \ trustmuxd bin_SCRIPTS = $(WRAPPERS:%=%.gen) bashcompdir = $(datadir)/bash-completion/completions dist_bashcomp_DATA = bash-completion/trustmux EXTRA_DIST = \ trustmux.in \ trustmuxd.in \ bash-completion/trustmux \ pyproject.toml \ requirements.txt \ uv.lock \ README.md \ generate_screenshots.py \ tests/__init__.py \ tests/test_ctl.py \ tests/test_daemon.py \ tests/test_daemon_extended.py CLEANFILES = $(WRAPPERS:%=%.gen) do_subst = sed -e 's|@trustmuxpydir[@]|$(trustmuxpydir)|g' %.gen: %.in Makefile $(do_subst) < $(srcdir)/$*.in > $@ chmod +x $@ # Install with the right names (strip the .gen suffix) and rename # trustmux-daemon → trustmux to match Debian's historical layout, where # /usr/bin/trustmux is the user-facing entry point for the daemon. install-exec-hook: cd $(DESTDIR)$(bindir) && \ for w in $(WRAPPERS); do \ mv $$w.gen $$w; \ done uninstall-hook: cd $(DESTDIR)$(bindir) && rm -f $(WRAPPERS) byobu-7.15/mobile/README.md000066400000000000000000000062711522352767600153410ustar00rootroot00000000000000# Trustmux A mobile companion for [tmux](https://github.com/tmux/tmux) / [Byobu](https://byobu.org) sessions. Run a lightweight daemon on your workstation; monitor and interact with your terminal sessions from your phone over your Tailscale network. No relay server — terminal data stays between your devices. Works with **plain tmux** and with **byobu**. Byobu users get the live status bar chips; plain tmux users get everything else. Two tiers: - **Free** — PWA. Install one icon per machine directly from the browser. - **Paid** — Native Flutter app with full ANSI colors, multi-machine management, and biometric auth. --- ## Requirements - tmux (byobu optional but recommended) - Python 3.10+ - [Tailscale](https://tailscale.com) installed, running, and connected --- ## Install ### Homebrew (macOS / Linux) ```bash brew tap dustinkirkland/trustmux brew install trustmux trustmux enable # configure tailscale serve + start daemon trustmux pair # generate pairing code; enter on phone ``` ### pip (PyPI) ```bash pip install trustmux trustmux enable trustmux pair ``` ### Debian / Ubuntu (.deb) Trustmux is bundled with byobu — installing byobu brings trustmux along: ```bash sudo apt install byobu trustmux enable trustmux pair ``` Or with the PPA for the latest release: ```bash sudo add-apt-repository ppa:dustinkirkland/byobu sudo apt install byobu trustmux enable trustmux pair ``` --- ## Daily use ```bash trustmux start # start daemon trustmux stop # stop daemon trustmux restart # restart daemon trustmux status # show URL and running status trustmux log # tail the daemon log trustmux pair # generate a pairing code for a new device trustmux unpair # list paired devices and remove them ``` --- ## Setup from source ```bash cd mobile/ python3 -m venv .venv .venv/bin/pip install -r requirements.txt trustmux enable trustmux pair ``` --- ## Configuration | Path | Purpose | |---|---| | `~/.config/trustmux/tokens.json` | Paired device session tokens (mode 0600) | | `~/.config/trustmux/trustmux.sock` | Admin Unix socket (mode 0600) | | `~/.config/trustmux/trustmux.log` | Daemon log (mode 0600) | | `~/.config/trustmux/machines.json` | Optional: sibling machines for the machine selector | ### Multiple machines ```json [ { "name": "work", "url": "https://work-machine.tail1234.ts.net" }, { "name": "personal", "url": "https://personal.tail1234.ts.net" } ] ``` --- ## Security - Daemon binds to `127.0.0.1:7432` only — not reachable from the network - All traffic encrypted by Tailscale WireGuard; HTTPS via `tailscale serve` - No relay server — terminal data never leaves your Tailscale mesh - Pairing codes: 6-digit, 5-minute TTL, single-use, max 10 attempts - Session tokens: 256-bit random, stored at mode 0600 --- ## Tests ```bash cd mobile/ python3 -m unittest tests.test_daemon -v ``` --- ## Troubleshooting **502 Bad Gateway** — tailscale serve is running but daemon isn't: `trustmux start` **"Serve not enabled"** — visit the URL printed by `tailscale serve --bg 7432` **Phone can't reach URL** — ensure Tailscale is active on the phone **Need to re-pair** — run `trustmux pair` and enter the new code on the device byobu-7.15/mobile/bash-completion/000077500000000000000000000000001522352767600171405ustar00rootroot00000000000000byobu-7.15/mobile/bash-completion/trustmux000066400000000000000000000011311522352767600207720ustar00rootroot00000000000000# bash completion for trustmux(1) _trustmux() { local cur prev words cword _init_completion || return local subcommands="setup start start-local start-direct stop restart status log enable disable pair unpair" if [[ $cword -eq 1 ]]; then COMPREPLY=($(compgen -W "$subcommands" -- "$cur")) return fi case "${words[1]}" in setup) COMPREPLY=($(compgen -W "--quiet" -- "$cur")) ;; start|start-local|start-direct|stop|restart|status|log|enable|disable|pair|unpair) ;; esac } complete -F _trustmux trustmux byobu-7.15/mobile/man/000077500000000000000000000000001522352767600146275ustar00rootroot00000000000000byobu-7.15/mobile/man/man1/000077500000000000000000000000001522352767600154635ustar00rootroot00000000000000byobu-7.15/mobile/man/man1/trustmux.1000066400000000000000000000110571522352767600174640ustar00rootroot00000000000000.TH TRUSTMUX 1 "2026-06-09" "trustmux" "User Commands" .SH NAME trustmux \- manage the Trustmux daemon .SH SYNOPSIS .B trustmux .I COMMAND .RI [ options ] .SH DESCRIPTION .B trustmux is the single command-line interface for the Trustmux daemon — a lightweight server that lets you monitor and interact with your tmux/Byobu sessions from a phone browser over your Tailscale network. .PP All operations are subcommands of .BR trustmux : initial setup, starting and stopping the daemon, login-hook management, and device pairing. .SH COMMANDS .SS "Daemon lifecycle" .TP .B setup One-time setup: verify Tailscale is installed and connected, then configure .B tailscale serve for HTTPS on port 7432. .TP .B start Start the daemon in HTTPS mode via .B tailscale serve (default, recommended). .TP .B start\-local Start the daemon bound to 127.0.0.1 only, for access via an SSH port-forward. No TLS certificate is generated; the tunnel provides encryption. .TP .B start\-direct Start the daemon with a self-signed TLS certificate, binding on all interfaces for LAN/direct access without Tailscale. .TP .B stop Send SIGTERM to the running daemon. Tailscale serve configuration is left in place. .TP .B restart Stop then start the daemon in HTTPS mode. .TP .B status Show whether the daemon is running and the URL to connect to. .TP .B log Tail the daemon log at .IR ~/.config/trustmux/trustmux.log . .SS "Login hook" .TP .B enable Run first-time setup if needed, start the daemon, and install a hook in the user's shell login file .RI ( ~/.profile , .IR ~/.bash_profile , or .IR ~/.zprofile ) so the daemon starts automatically on each login. .TP .B disable Stop the running daemon and remove the login hook so the daemon no longer starts automatically. Paired device tokens are preserved. .SS "Device pairing" .TP .B pair Ask the running daemon to generate a one-time 6-digit pairing code (valid for 3 minutes) and display it along with the URL your phone should open. If .BR qrencode (1) is installed, a QR code is printed for one-scan pairing. The screen is cleared on the next keypress to keep the pairing URL out of the terminal scroll-back. .TP .B unpair List all currently paired devices (IP address, browser label, and pairing time) and offer an interactive menu to remove one or all of them. .SH OPTIONS .TP .B setup \-\-quiet Suppress the "Next steps" output after a successful setup. .SH FILES .TP .I ~/.config/trustmux/trustmux.log Daemon log file. .TP .I ~/.config/trustmux/trustmux.pid PID file written at daemon startup. .TP .I ~/.config/trustmux/trustmux.sock Admin Unix socket used by .B pair and .BR unpair . .TP .I ~/.config/trustmux/tokens.json Paired device session tokens (mode 0600). .TP .I ~/.config/trustmux/machines.json Optional: sibling machine list for the in-app machine selector. .SH EXAMPLES Typical first-time setup: .PP .RS .nf trustmux setup trustmux enable trustmux pair .fi .RE .PP Daily use: .PP .RS .nf trustmux status trustmux restart trustmux log .fi .RE .SH SECURITY .SS "Pairing code" The one-time pairing code is a 6-digit decimal value drawn from .BR secrets.randbelow (1,000,000), giving 1,000,000 possible values. The code is valid for 3 minutes. After three incorrect guesses the code is immediately invalidated and a new one must be generated with .BR "trustmux pair" . The hard 3-attempt lockout makes brute-force infeasible: an attacker has a 0.0003% chance of success per pairing window, and each new window requires the machine owner to run .B trustmux pair again. An incorrect guess also incurs a 0.5-second artificial delay. .SS "Session tokens" After a successful pairing the daemon issues a 256-bit URL-safe session token .RB ( secrets.token_urlsafe (32)) stored in .I ~/.config/trustmux/tokens.json (mode 0600) and delivered to the browser as an .BR httponly , .B SameSite=Strict cookie. Tokens are validated with a constant-time comparison to prevent timing attacks. Sessions expire after 90 days of inactivity and can be revoked at any time with .BR "trustmux unpair" . .SS "Network exposure" In the default .B start mode the daemon binds only to the Tailscale IP (100.x.x.x), so the pairing endpoint is unreachable from the public internet or from other local-network devices. In .B start\-direct mode the daemon binds on all interfaces; the pairing-code and session-token protections above remain in force, but the network attack surface is broader. In .B start\-local mode the daemon binds to 127.0.0.1 only and is accessible solely through an explicit SSH port-forward. .SH SEE ALSO .BR trustmuxd (1), .BR tailscale (1), .BR tmux (1), .BR byobu (1) .SH AUTHOR Dustin Kirkland byobu-7.15/mobile/man/man1/trustmuxd.1000066400000000000000000000041131522352767600176230ustar00rootroot00000000000000.TH TRUSTMUXD 1 "2026-05-28" "trustmux" "User Commands" .SH NAME trustmuxd \- Trustmux daemon (mobile companion for tmux/Byobu sessions) .SH SYNOPSIS .B trustmuxd [\fB\-\-host\fP \fIADDR\fP] [\fB\-\-port\fP \fIPORT\fP] [\fB\-\-https\fP] [\fB\-\-self\-signed\fP] [\fB\-\-version\fP] .SH DESCRIPTION .B trustmuxd is a lightweight daemon that serves a mobile-optimised web interface for monitoring and interacting with tmux and Byobu sessions over your Tailscale private network. .PP The daemon serves a Progressive Web App (PWA) over HTTPS. In the default mode it binds to the Tailscale interface and relies on .BR "tailscale serve" for TLS termination. In direct mode (\fB\-\-self\-signed\fP) it generates a self-signed ECDSA certificate and binds directly on the network interface. .PP Authentication uses 6-digit one-time pairing codes (generated with .BR trustmux\-pair (1)) and permanent per-device session tokens stored in .IR ~/.config/trustmux/tokens.json . .PP In normal use, the daemon is managed via .BR trustmux (1) rather than being invoked directly. .SH OPTIONS .TP .BI \-\-host " ADDR" Bind address (default: Tailscale IP, or 127.0.0.1 with \fB\-\-https\fP). .TP .BI \-\-port " PORT" TCP port to listen on (default: 7432). .TP .B \-\-https HTTPS mode: trust proxy headers and set Secure cookie flag. Use with \fBtailscale serve\fP. .TP .B \-\-self\-signed Generate a self-signed ECDSA P-256 TLS certificate for direct HTTPS access without Tailscale. .TP .B \-\-version Print version and exit. .SH FILES .TP .I ~/.config/trustmux/tokens.json Persistent session tokens (mode 0600). .TP .I ~/.config/trustmux/trustmux.sock Admin Unix socket (mode 0600) used by .BR trustmux\-pair (1) and .BR trustmux\-unpair (1). .TP .I ~/.config/trustmux/cert.pem Self-signed TLS certificate (mode 0644), created on first \fB\-\-self\-signed\fP start. .TP .I ~/.config/trustmux/key.pem TLS private key (mode 0600). .SH SEE ALSO .BR trustmux (1), .BR trustmux\-pair (1), .BR trustmux\-unpair (1), .BR trustmux\-enable (1), .BR trustmux\-disable (1), .BR byobu (1), .BR tmux (1) .SH AUTHOR Dustin Kirkland byobu-7.15/mobile/pyproject.toml000066400000000000000000000024541522352767600167750ustar00rootroot00000000000000[build-system] requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] name = "trustmux" version = "7.15" description = "Monitor and interact with tmux/Byobu sessions from your phone" readme = "README.md" license = {text = "GPL-3.0-or-later"} authors = [{name = "Dustin Kirkland", email = "dustin.kirkland@gmail.com"}] requires-python = ">=3.9" dependencies = ["tornado>=6.5.7", "cryptography>=43.0"] keywords = ["tmux", "byobu", "terminal", "mobile", "pwa"] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Programming Language :: Python :: 3", "Topic :: Terminals :: Terminal Emulators/X Terminals", ] [project.urls] Homepage = "https://trustmux.app" Repository = "https://github.com/dustinkirkland/byobu" Issues = "https://github.com/dustinkirkland/byobu/issues" [project.scripts] trustmux = "trustmux._ctl:main" trustmuxd = "trustmux._daemon:main" [tool.setuptools.packages.find] where = ["."] include = ["trustmux*"] [tool.setuptools.package-data] trustmux = [ "static/index.html", "static/app.js", "static/sw.js", "static/trustmux.svg", "static/trustmux-logo.svg", "static/icons/icon-192.png", "static/icons/icon-512.png", ] byobu-7.15/mobile/requirements.txt000066400000000000000000000000251522352767600173350ustar00rootroot00000000000000tornado cryptography byobu-7.15/mobile/tests/000077500000000000000000000000001522352767600152165ustar00rootroot00000000000000byobu-7.15/mobile/tests/__init__.py000066400000000000000000000000001522352767600173150ustar00rootroot00000000000000byobu-7.15/mobile/tests/test_ctl.py000066400000000000000000000703731522352767600174230ustar00rootroot00000000000000"""Tests for trustmux._ctl, _enable, _disable.""" import json import os import signal import sys import tempfile import unittest from pathlib import Path from unittest.mock import MagicMock, call, patch sys.path.insert(0, str(Path(__file__).parent.parent)) import trustmux._ctl as ctl import trustmux._enable as enable import trustmux._disable as disable # --------------------------------------------------------------------------- # _pid() # --------------------------------------------------------------------------- class TestPid(unittest.TestCase): def test_lsof_returns_pid(self): with patch('trustmux._ctl.subprocess.check_output', return_value='1234\n'): self.assertEqual(ctl._pid(), 1234) def test_lsof_multiple_lines_uses_first(self): with patch('trustmux._ctl.subprocess.check_output', return_value='1234\n5678\n'): self.assertEqual(ctl._pid(), 1234) def _mock_pidfile(self, exists=False, content=''): m = MagicMock() m.exists.return_value = exists m.read_text.return_value = content return m def test_lsof_empty_output_falls_back_to_pidfile(self): with patch('trustmux._ctl.subprocess.check_output', return_value=''): with patch('trustmux._ctl.PIDFILE', self._mock_pidfile(exists=False)): self.assertIsNone(ctl._pid()) def test_lsof_not_found_falls_back_to_pidfile(self): with patch('trustmux._ctl.subprocess.check_output', side_effect=FileNotFoundError): with patch('trustmux._ctl.PIDFILE', self._mock_pidfile(exists=False)): self.assertIsNone(ctl._pid()) def test_pidfile_fallback_live_process(self): import subprocess with patch('trustmux._ctl.subprocess.check_output', side_effect=subprocess.CalledProcessError(1, 'lsof')): with patch('trustmux._ctl.PIDFILE', self._mock_pidfile(exists=True, content='9999\n')): with patch('trustmux._ctl.os.kill', return_value=None): self.assertEqual(ctl._pid(), 9999) def test_pidfile_fallback_dead_process(self): import subprocess with patch('trustmux._ctl.subprocess.check_output', side_effect=subprocess.CalledProcessError(1, 'lsof')): with patch('trustmux._ctl.PIDFILE', self._mock_pidfile(exists=True, content='9999\n')): with patch('trustmux._ctl.os.kill', side_effect=ProcessLookupError): self.assertIsNone(ctl._pid()) def test_pidfile_fallback_invalid_content(self): import subprocess with patch('trustmux._ctl.subprocess.check_output', side_effect=subprocess.CalledProcessError(1, 'lsof')): with patch('trustmux._ctl.PIDFILE', self._mock_pidfile(exists=True, content='not-a-pid\n')): self.assertIsNone(ctl._pid()) # --------------------------------------------------------------------------- # _ts_host() # --------------------------------------------------------------------------- class TestTsHost(unittest.TestCase): def _ts_json(self, dns='engawa.ts.net.'): return json.dumps({'Self': {'DNSName': dns}}) def test_returns_name_without_trailing_dot(self): with patch('trustmux._ctl.subprocess.check_output', return_value=self._ts_json()): self.assertEqual(ctl._ts_host(), 'engawa.ts.net') def test_empty_when_no_self_key(self): with patch('trustmux._ctl.subprocess.check_output', return_value=json.dumps({})): self.assertEqual(ctl._ts_host(), '') def test_empty_on_subprocess_error(self): import subprocess with patch('trustmux._ctl.subprocess.check_output', side_effect=subprocess.CalledProcessError(1, 'tailscale')): self.assertEqual(ctl._ts_host(), '') def test_empty_when_tailscale_not_found(self): with patch('trustmux._ctl.subprocess.check_output', side_effect=FileNotFoundError): self.assertEqual(ctl._ts_host(), '') # --------------------------------------------------------------------------- # _check_tls() — GH #113: missing cryptography in bundled Homebrew venv # --------------------------------------------------------------------------- class TestCheckTls(unittest.TestCase): @unittest.skipUnless( __import__('importlib.util', fromlist=['find_spec']).find_spec('cryptography') is not None, 'cryptography not installed in this venv', ) def test_returns_true_when_cryptography_present(self): self.assertTrue(ctl._check_tls()) def test_returns_false_and_prints_sys_executable_when_import_fails(self): # Simulate a Homebrew bundled-venv install where cryptography is absent # (GH #113). Shadow the module so the local `from cryptography...` # import inside _check_tls raises ImportError. import io buf = io.StringIO() with patch.dict(sys.modules, { 'cryptography.hazmat.primitives.asymmetric': None, }): with patch('trustmux._ctl.sys.stderr', buf): result = ctl._check_tls() self.assertFalse(result) output = buf.getvalue() self.assertIn(sys.executable, output) self.assertIn("cryptography", output) # Must NOT suggest bare 'pip' — that targets the wrong interpreter # in Homebrew's bundled-venv installs (regression: GH #113). for line in output.splitlines(): if "pip" in line and "cryptography" in line: self.assertNotRegex(line, r'^\s+pip ') # --------------------------------------------------------------------------- # _ensure_ts_serve() # --------------------------------------------------------------------------- class TestEnsureTsServe(unittest.TestCase): def test_already_configured(self): port_str = f':{ctl.PORT}' with patch('trustmux._ctl.subprocess.check_output', return_value=f'https/tcp/0:443 → {port_str}\n'): with patch('trustmux._ctl.subprocess.run') as mock_run: result = ctl._ensure_ts_serve() self.assertTrue(result) mock_run.assert_not_called() def test_configures_on_first_attempt(self): with patch('trustmux._ctl.subprocess.check_output', return_value='no matching port\n'): with patch('trustmux._ctl.subprocess.run') as mock_run: mock_run.return_value = MagicMock(returncode=0) result = ctl._ensure_ts_serve() self.assertTrue(result) def test_prints_error_and_returns_false_when_serve_fails(self): import subprocess as sp with patch('trustmux._ctl.subprocess.check_output', return_value='nothing'): with patch('trustmux._ctl.subprocess.run', side_effect=sp.CalledProcessError(1, 'tailscale')) as mock_run: result = ctl._ensure_ts_serve() self.assertFalse(result) # Must never auto-run sudo for call in mock_run.call_args_list: self.assertNotIn('sudo', call.args[0]) def test_returns_false_when_all_attempts_fail(self): import subprocess as sp with patch('trustmux._ctl.subprocess.check_output', return_value='nothing'): with patch('trustmux._ctl.subprocess.run', side_effect=sp.CalledProcessError(1, 'tailscale')): result = ctl._ensure_ts_serve() self.assertFalse(result) # --------------------------------------------------------------------------- # cmd_setup() # --------------------------------------------------------------------------- class TestCmdSetup(unittest.TestCase): def _patch_ok(self): return { 'trustmux._ctl.subprocess.run': MagicMock(return_value=MagicMock(returncode=0)), 'trustmux._ctl._ts_host': MagicMock(return_value='engawa.ts.net'), 'trustmux._ctl._ensure_ts_serve': MagicMock(return_value=True), } def test_returns_1_when_package_not_importable(self): with patch.dict('sys.modules', {'trustmux._daemon': None}): with patch('builtins.__import__', side_effect=ImportError): # patch the import inside cmd_setup pass # Simpler: patch the import inside the function import builtins real_import = builtins.__import__ def fake_import(name, *a, **kw): if name == 'trustmux._daemon': raise ImportError return real_import(name, *a, **kw) with patch('builtins.__import__', side_effect=fake_import): result = ctl.cmd_setup() self.assertEqual(result, 1) def test_returns_1_when_tailscale_missing(self): import subprocess as sp with patch('trustmux._ctl._ts_host', return_value='engawa.ts.net'): with patch('trustmux._ctl._ensure_ts_serve', return_value=True): with patch('trustmux._ctl.subprocess.run', side_effect=FileNotFoundError): result = ctl.cmd_setup() self.assertEqual(result, 1) def test_returns_1_when_tailscale_not_connected(self): with patch('trustmux._ctl.subprocess.run'): with patch('trustmux._ctl._ts_host', return_value=''): with patch('trustmux._ctl._ensure_ts_serve', return_value=True): result = ctl.cmd_setup() self.assertEqual(result, 1) def test_returns_1_when_ts_serve_fails(self): with patch('trustmux._ctl.subprocess.run'): with patch('trustmux._ctl._ts_host', return_value='engawa.ts.net'): with patch('trustmux._ctl._ensure_ts_serve', return_value=False): result = ctl.cmd_setup() self.assertEqual(result, 1) def test_returns_0_on_success(self): with patch('trustmux._ctl.subprocess.run'): with patch('trustmux._ctl._ts_host', return_value='engawa.ts.net'): with patch('trustmux._ctl._ensure_ts_serve', return_value=True): result = ctl.cmd_setup() self.assertEqual(result, 0) def test_quiet_suppresses_next_steps(self): with patch('trustmux._ctl.subprocess.run'): with patch('trustmux._ctl._ts_host', return_value='engawa.ts.net'): with patch('trustmux._ctl._ensure_ts_serve', return_value=True): with patch('builtins.print') as mock_print: ctl.cmd_setup(quiet=True) printed = ' '.join(str(c) for c in mock_print.call_args_list) self.assertNotIn('Next steps', printed) # --------------------------------------------------------------------------- # cmd_start() # --------------------------------------------------------------------------- class TestCmdStart(unittest.TestCase): def test_returns_1_when_already_running(self): with patch('trustmux._ctl._pid', return_value=1234): self.assertEqual(ctl.cmd_start(), 1) def test_returns_1_when_tailscale_missing(self): with patch('trustmux._ctl._pid', return_value=None): with patch('trustmux._ctl._check_tmux', return_value=True): with patch('trustmux._ctl._check_tls', return_value=True): with patch('trustmux._ctl.subprocess.run', side_effect=FileNotFoundError): self.assertEqual(ctl.cmd_start('serve'), 1) def test_returns_1_when_no_tailscale_host(self): with patch('trustmux._ctl._pid', return_value=None): with patch('trustmux._ctl._check_tmux', return_value=True): with patch('trustmux._ctl._check_tls', return_value=True): with patch('trustmux._ctl.subprocess.run'): with patch('trustmux._ctl._ts_host', return_value=''): self.assertEqual(ctl.cmd_start('serve'), 1) def test_returns_1_when_ts_serve_fails(self): with patch('trustmux._ctl._pid', return_value=None): with patch('trustmux._ctl._check_tmux', return_value=True): with patch('trustmux._ctl._check_tls', return_value=True): with patch('trustmux._ctl.subprocess.run'): with patch('trustmux._ctl._ts_host', return_value='engawa.ts.net'): with patch('trustmux._ctl._ensure_ts_serve', return_value=False): self.assertEqual(ctl.cmd_start('serve'), 1) def test_serve_mode_success(self): with patch('trustmux._ctl._pid', return_value=None): with patch('trustmux._ctl._check_tmux', return_value=True): with patch('trustmux._ctl._check_tls', return_value=True): with patch('trustmux._ctl.subprocess.run'): with patch('trustmux._ctl._ts_host', return_value='engawa.ts.net'): with patch('trustmux._ctl._ensure_ts_serve', return_value=True): with patch('trustmux._ctl._launch', return_value=5678): self.assertEqual(ctl.cmd_start('serve'), 0) def test_start_local_success(self): with patch('trustmux._ctl._pid', return_value=None): with patch('trustmux._ctl._launch', return_value=5678): self.assertEqual(ctl.cmd_start('start-local'), 0) def test_start_direct_success(self): with patch('trustmux._ctl._pid', return_value=None): with patch('trustmux._ctl._check_tmux', return_value=True): with patch('trustmux._ctl._check_tls', return_value=True): with patch('trustmux._ctl._launch', return_value=5678): self.assertEqual(ctl.cmd_start('start-direct'), 0) def test_returns_1_when_launch_fails(self): with patch('trustmux._ctl._pid', return_value=None): with patch('trustmux._ctl._check_tmux', return_value=True): with patch('trustmux._ctl._check_tls', return_value=True): with patch('trustmux._ctl.subprocess.run'): with patch('trustmux._ctl._ts_host', return_value='engawa.ts.net'): with patch('trustmux._ctl._ensure_ts_serve', return_value=True): with patch('trustmux._ctl._launch', return_value=None): self.assertEqual(ctl.cmd_start('serve'), 1) def test_unknown_mode_returns_1(self): with patch('trustmux._ctl._pid', return_value=None): self.assertEqual(ctl.cmd_start('bogus'), 1) # --------------------------------------------------------------------------- # cmd_stop() # --------------------------------------------------------------------------- class TestCmdStop(unittest.TestCase): def _mock_pidfile(self, exists=False, content=''): m = MagicMock() m.exists.return_value = exists m.read_text.return_value = content return m def test_not_running_returns_0(self): with patch('trustmux._ctl._pid', return_value=None): with patch('trustmux._ctl.PIDFILE', self._mock_pidfile(exists=False)): self.assertEqual(ctl.cmd_stop(), 0) def test_kills_process_and_removes_pidfile(self): with patch('trustmux._ctl._pid', return_value=4321): with patch('trustmux._ctl.PIDFILE', self._mock_pidfile(exists=True, content='4321')): with patch('trustmux._ctl.os.kill') as mock_kill: result = ctl.cmd_stop() self.assertEqual(result, 0) mock_kill.assert_called_once_with(4321, signal.SIGTERM) def test_pidfile_mismatch_refuses_to_kill(self): with patch('trustmux._ctl._pid', return_value=4321): with patch('trustmux._ctl.PIDFILE', self._mock_pidfile(exists=True, content='9999')): with patch('trustmux._ctl.os.kill') as mock_kill: result = ctl.cmd_stop() self.assertEqual(result, 1) mock_kill.assert_not_called() def test_no_pidfile_still_kills(self): with patch('trustmux._ctl._pid', return_value=4321): with patch('trustmux._ctl.PIDFILE', self._mock_pidfile(exists=False)): with patch('trustmux._ctl.os.kill') as mock_kill: result = ctl.cmd_stop() self.assertEqual(result, 0) mock_kill.assert_called_once_with(4321, signal.SIGTERM) # --------------------------------------------------------------------------- # cmd_status() # --------------------------------------------------------------------------- class TestCmdStatus(unittest.TestCase): def test_not_running(self): with patch('trustmux._ctl._pid', return_value=None): with patch('builtins.print') as mock_print: result = ctl.cmd_status() self.assertEqual(result, 0) mock_print.assert_called_once_with('trustmux not running') def test_running_with_tailscale_serve(self): port_str = f':{ctl.PORT}' with patch('trustmux._ctl._pid', return_value=1234): with patch('trustmux._ctl.subprocess.check_output', return_value=f'something {port_str} here'): with patch('trustmux._ctl._ts_host', return_value='engawa.ts.net'): with patch('builtins.print') as mock_print: result = ctl.cmd_status() self.assertEqual(result, 0) printed = ' '.join(str(c) for c in mock_print.call_args_list) self.assertIn('https://engawa.ts.net', printed) def test_running_direct_http(self): import subprocess as sp with patch('trustmux._ctl._pid', return_value=1234): with patch('trustmux._ctl.subprocess.check_output', side_effect=[sp.CalledProcessError(1, 'ts'), '100.64.0.1\n']): with patch('builtins.print') as mock_print: result = ctl.cmd_status() self.assertEqual(result, 0) printed = ' '.join(str(c) for c in mock_print.call_args_list) self.assertIn('direct HTTP', printed) # --------------------------------------------------------------------------- # _install_hook() — enable # --------------------------------------------------------------------------- class TestInstallHook(unittest.TestCase): def test_no_op_when_file_missing(self): with tempfile.TemporaryDirectory() as td: dest = Path(td) / 'nonexistent' enable._install_hook(dest) self.assertFalse(dest.exists()) def test_adds_hook_to_existing_file(self): with tempfile.NamedTemporaryFile(mode='w', suffix='.profile', delete=False) as f: f.write('# existing content\n') fpath = Path(f.name) try: enable._install_hook(fpath) content = fpath.read_text() self.assertIn('trustmux start', content) self.assertIn('# existing content', content) finally: fpath.unlink() def test_idempotent_does_not_duplicate_hook(self): with tempfile.NamedTemporaryFile(mode='w', suffix='.profile', delete=False) as f: f.write('trustmux start 2>/dev/null || true\n') fpath = Path(f.name) try: enable._install_hook(fpath) enable._install_hook(fpath) content = fpath.read_text() self.assertEqual(content.count('trustmux start'), 1) finally: fpath.unlink() # --------------------------------------------------------------------------- # _remove_hook() — disable # --------------------------------------------------------------------------- class TestRemoveHook(unittest.TestCase): def test_no_op_when_file_missing(self): with tempfile.TemporaryDirectory() as td: dest = Path(td) / 'nonexistent' disable._remove_hook(dest) # must not raise def test_removes_hook_lines(self): with tempfile.NamedTemporaryFile(mode='w', suffix='.profile', delete=False) as f: f.write('# preamble\ntrustmux start 2>/dev/null || true\n# after\n') fpath = Path(f.name) try: disable._remove_hook(fpath) content = fpath.read_text() self.assertNotIn('trustmux start 2>/dev/null', content) self.assertIn('# preamble', content) self.assertIn('# after', content) finally: fpath.unlink() def test_no_change_when_hook_absent(self): original = '# just a comment\nexport PATH=$PATH:/usr/local/bin\n' with tempfile.NamedTemporaryFile(mode='w', suffix='.profile', delete=False) as f: f.write(original) fpath = Path(f.name) try: disable._remove_hook(fpath) self.assertEqual(fpath.read_text(), original) finally: fpath.unlink() def test_no_op_on_non_writable_file(self): with tempfile.NamedTemporaryFile(mode='w', suffix='.profile', delete=False) as f: f.write('trustmux start\n') fpath = Path(f.name) try: with patch('trustmux._disable.os.access', return_value=False): disable._remove_hook(fpath) self.assertIn('trustmux start', fpath.read_text()) finally: fpath.unlink() # --------------------------------------------------------------------------- # enable.main() and disable.main() — integration-level # --------------------------------------------------------------------------- class TestEnableMain(unittest.TestCase): def test_exits_1_when_setup_fails(self): with patch('trustmux._enable.cmd_setup', return_value=1): with self.assertRaises(SystemExit) as cm: enable.main() self.assertEqual(cm.exception.code, 1) def test_runs_through_on_success(self): with patch('trustmux._enable.cmd_setup', return_value=0): with patch('trustmux._enable.cmd_start', return_value=0): with patch('trustmux._enable._LOGIN_FILES', []): with patch('trustmux._enable.TOKENS_FILE') as tf: tf.exists.return_value = True tf.stat.return_value = MagicMock(st_size=100) enable.main() # should not raise class TestDisableMain(unittest.TestCase): def test_runs_without_error(self): with patch('trustmux._disable.cmd_stop', return_value=0): with patch('trustmux._disable._LOGIN_FILES', []): disable.main() # should not raise # --------------------------------------------------------------------------- # _peer_acl_allows_tcp() — tailnet ACL preflight # --------------------------------------------------------------------------- def _netmap(rules, self_addrs=("100.93.98.28/32",)): """Build a minimal netmap JSON blob for the ACL preflight tests.""" nm = {"PacketFilter": rules} if self_addrs is not None: nm["SelfNode"] = {"Addresses": list(self_addrs)} return json.dumps(nm) class TestPeerAclAllowsTcp(unittest.TestCase): def _patch_netmap(self, output): return patch('trustmux._ctl.subprocess.check_output', return_value=output) def test_rule_allows_port_and_proto(self): rules = [{ "IPProto": [6], "Dsts": [{"Net": "100.93.98.28/32", "Ports": {"First": 443, "Last": 443}}], }] with self._patch_netmap(_netmap(rules)): self.assertTrue(ctl._peer_acl_allows_tcp(443)) def test_rule_allows_port_range(self): rules = [{ "IPProto": [6], "Dsts": [{"Net": "100.93.98.28/32", "Ports": {"First": 1, "Last": 65535}}], }] with self._patch_netmap(_netmap(rules)): self.assertTrue(ctl._peer_acl_allows_tcp(443)) def test_empty_iproto_means_all_protocols(self): rules = [{ "IPProto": [], "Dsts": [{"Net": "100.93.98.28/32", "Ports": {"First": 443, "Last": 443}}], }] with self._patch_netmap(_netmap(rules)): self.assertTrue(ctl._peer_acl_allows_tcp(443)) def test_no_rule_covers_port(self): rules = [{ "IPProto": [6], "Dsts": [{"Net": "100.93.98.28/32", "Ports": {"First": 22, "Last": 22}}], }] with self._patch_netmap(_netmap(rules)): self.assertFalse(ctl._peer_acl_allows_tcp(443)) def test_wrong_protocol_rejected(self): rules = [{ "IPProto": [17], # UDP only "Dsts": [{"Net": "100.93.98.28/32", "Ports": {"First": 443, "Last": 443}}], }] with self._patch_netmap(_netmap(rules)): self.assertFalse(ctl._peer_acl_allows_tcp(443)) def test_rule_for_different_device_rejected(self): rules = [{ "IPProto": [6], "Dsts": [{"Net": "100.64.0.99/32", "Ports": {"First": 443, "Last": 443}}], }] with self._patch_netmap(_netmap(rules)): self.assertFalse(ctl._peer_acl_allows_tcp(443)) def test_cidr_rule_covers_device_ip(self): # CIDR block that contains the device — default autogroup:member ACL # uses 100.64.0.0/10 rather than a per-host /32. rules = [{ "IPProto": [6], "Dsts": [{"Net": "100.64.0.0/10", "Ports": {"First": 443, "Last": 443}}], }] with self._patch_netmap(_netmap(rules)): # device is 100.93.98.28 self.assertTrue(ctl._peer_acl_allows_tcp(443)) def test_cidr_rule_does_not_cover_device_ip(self): rules = [{ "IPProto": [6], "Dsts": [{"Net": "10.0.0.0/8", "Ports": {"First": 443, "Last": 443}}], }] with self._patch_netmap(_netmap(rules)): self.assertFalse(ctl._peer_acl_allows_tcp(443)) def test_accepts_match_when_self_ips_unknown(self): # If SelfNode.Addresses is absent, fall back to "any net" matching so # we don't false-positive a warning. rules = [{ "IPProto": [6], "Dsts": [{"Net": "100.64.0.99/32", "Ports": {"First": 443, "Last": 443}}], }] nm = json.dumps({"PacketFilter": rules}) with patch('trustmux._ctl.subprocess.check_output', return_value=nm): self.assertTrue(ctl._peer_acl_allows_tcp(443)) def test_tailscale_missing_returns_none(self): with patch('trustmux._ctl.subprocess.check_output', side_effect=FileNotFoundError): self.assertIsNone(ctl._peer_acl_allows_tcp(443)) def test_malformed_json_returns_none(self): with patch('trustmux._ctl.subprocess.check_output', return_value='not json'): self.assertIsNone(ctl._peer_acl_allows_tcp(443)) def test_missing_packet_filter_returns_none(self): with patch('trustmux._ctl.subprocess.check_output', return_value='{}'): self.assertIsNone(ctl._peer_acl_allows_tcp(443)) # --------------------------------------------------------------------------- # warn_if_peer_blocked() # --------------------------------------------------------------------------- class TestWarnIfPeerBlocked(unittest.TestCase): def test_silent_when_reachable(self): import io buf = io.StringIO() with patch('trustmux._ctl._peer_acl_allows_tcp', return_value=True): ctl.warn_if_peer_blocked(443, stream=buf) self.assertEqual(buf.getvalue(), "") def test_silent_when_unknown(self): import io buf = io.StringIO() with patch('trustmux._ctl._peer_acl_allows_tcp', return_value=None): ctl.warn_if_peer_blocked(443, stream=buf) self.assertEqual(buf.getvalue(), "") def test_warns_when_blocked(self): import io buf = io.StringIO() with patch('trustmux._ctl._peer_acl_allows_tcp', return_value=False): ctl.warn_if_peer_blocked(443, stream=buf) msg = buf.getvalue() self.assertIn("warning", msg) self.assertIn("tcp:443", msg) self.assertIn("ERR_NETWORK_CHANGED", msg) # Mentions both ACL formats so users on either can self-serve. self.assertIn("grants", msg) self.assertIn("acls", msg) if __name__ == '__main__': unittest.main() byobu-7.15/mobile/tests/test_daemon.py000066400000000000000000000371771522352767600201110ustar00rootroot00000000000000"""Tests for Trustmux daemon — runs locally with stdlib unittest + tornado.""" import json import os import sys import tempfile import time import unittest from pathlib import Path from unittest.mock import patch, MagicMock sys.path.insert(0, str(Path(__file__).parent.parent)) import trustmux._daemon as bm from tornado.testing import AsyncHTTPTestCase # --------------------------------------------------------------------------- # ANSI stripping # --------------------------------------------------------------------------- class TestStripAnsi(unittest.TestCase): def test_removes_sgr_color(self): self.assertEqual(bm.strip_ansi('\x1b[31mred\x1b[0m'), 'red') def test_removes_bold(self): self.assertEqual(bm.strip_ansi('\x1b[1mbold\x1b[m'), 'bold') def test_removes_cursor_movement(self): self.assertEqual(bm.strip_ansi('\x1b[2J\x1b[H'), '') def test_removes_osc_window_title(self): self.assertEqual(bm.strip_ansi('\x1b]0;title\x07text'), 'text') def test_removes_carriage_return(self): self.assertEqual(bm.strip_ansi('hello\rworld'), 'helloworld') def test_passthrough_plain_text(self): self.assertEqual(bm.strip_ansi('hello world'), 'hello world') def test_passthrough_newlines(self): self.assertEqual(bm.strip_ansi('line1\nline2'), 'line1\nline2') def test_complex_prompt(self): # Typical byobu status chip: color + text + reset result = bm.strip_ansi('\x1b[48;5;24m\x1b[38;5;255m uptime \x1b[0m') self.assertEqual(result.strip(), 'uptime') # --------------------------------------------------------------------------- # tmux ID validation # --------------------------------------------------------------------------- class TestValidTmuxId(unittest.TestCase): def test_valid_session_ids(self): self.assertTrue(bm._valid_tmux_id('$0')) self.assertTrue(bm._valid_tmux_id('$123')) def test_valid_window_ids(self): self.assertTrue(bm._valid_tmux_id('@0')) self.assertTrue(bm._valid_tmux_id('@99')) def test_valid_pane_ids(self): self.assertTrue(bm._valid_tmux_id('%0')) self.assertTrue(bm._valid_tmux_id('%42')) def test_rejects_empty(self): self.assertFalse(bm._valid_tmux_id('')) def test_rejects_bare_digits(self): self.assertFalse(bm._valid_tmux_id('0')) self.assertFalse(bm._valid_tmux_id('123')) def test_rejects_wrong_sigil(self): self.assertFalse(bm._valid_tmux_id('!0')) self.assertFalse(bm._valid_tmux_id('#1')) def test_rejects_no_digits(self): self.assertFalse(bm._valid_tmux_id('$')) self.assertFalse(bm._valid_tmux_id('@')) self.assertFalse(bm._valid_tmux_id('%')) def test_rejects_alpha_suffix(self): self.assertFalse(bm._valid_tmux_id('$abc')) self.assertFalse(bm._valid_tmux_id('@1a')) # --------------------------------------------------------------------------- # tmux output parsing # --------------------------------------------------------------------------- class TestTmuxListPanes(unittest.TestCase): def _run(self, output): with patch.object(bm, '_tmux', return_value=output): return bm.tmux_list_panes('@0') def test_parses_two_panes(self): out = '%0\t0\t1\tbash\t1234\t0\n%1\t1\t0\tvim\t5678\t1\n' panes = self._run(out) self.assertEqual(len(panes), 2) self.assertEqual(panes[0], {'id': '%0', 'index': 0, 'active': True, 'command': 'bash', 'dead': False}) self.assertEqual(panes[1], {'id': '%1', 'index': 1, 'active': False, 'command': 'vim', 'dead': True}) def test_empty_output(self): self.assertEqual(self._run(''), []) def test_skips_malformed_lines(self): out = 'garbage\n%0\t0\t1\tbash\t123\n' panes = self._run(out) self.assertEqual(len(panes), 1) self.assertEqual(panes[0]['id'], '%0') def test_active_flag_parsing(self): out = '%5\t0\t1\tzsh\t999\n' panes = self._run(out) self.assertTrue(panes[0]['active']) out = '%5\t0\t0\tzsh\t999\n' panes = self._run(out) self.assertFalse(panes[0]['active']) class TestTmuxListWindows(unittest.TestCase): def test_parses_windows_with_panes(self): window_output = '@0\t0\tmain\t1\n@1\t1\twork\t0\n' pane_output = '%0\t0\t1\tbash\t111\n' call_count = 0 def fake_tmux(*args): nonlocal call_count call_count += 1 if 'list-windows' in args: return window_output return pane_output # both window pane lists with patch.object(bm, '_tmux', side_effect=fake_tmux): windows = bm.tmux_list_windows('$0') self.assertEqual(len(windows), 2) self.assertEqual(windows[0]['id'], '@0') self.assertEqual(windows[0]['index'], 0) self.assertTrue(windows[0]['active']) self.assertFalse(windows[1]['active']) def test_empty_output(self): with patch.object(bm, '_tmux', return_value=''): windows = bm.tmux_list_windows('$0') self.assertEqual(windows, []) # --------------------------------------------------------------------------- # Byobu status config parsing # --------------------------------------------------------------------------- class TestReadByobuStatusConfig(unittest.TestCase): def test_defaults_when_no_config_exists(self): with tempfile.TemporaryDirectory() as tmpdir: with patch.object(Path, 'home', return_value=Path(tmpdir)): left, right = bm._read_byobu_status_config() # Defaults should contain expected chips self.assertIn('session', left) self.assertIn('time', right) def test_parses_tmux_left_and_right(self): with tempfile.TemporaryDirectory() as tmpdir: cfg_dir = Path(tmpdir) / '.config' / 'byobu' cfg_dir.mkdir(parents=True) (cfg_dir / 'status').write_text( 'tmux_left="logo session"\n' 'tmux_right="uptime time"\n' ) with patch.object(Path, 'home', return_value=Path(tmpdir)): left, right = bm._read_byobu_status_config() self.assertEqual(left, ['logo', 'session']) self.assertEqual(right, ['uptime', 'time']) def test_ignores_commented_lines(self): with tempfile.TemporaryDirectory() as tmpdir: cfg_dir = Path(tmpdir) / '.config' / 'byobu' cfg_dir.mkdir(parents=True) (cfg_dir / 'status').write_text( '#tmux_right="this should be ignored"\n' 'tmux_left="session"\n' ) with patch.object(Path, 'home', return_value=Path(tmpdir)): left, right = bm._read_byobu_status_config() self.assertEqual(left, ['session']) # right should be the default self.assertIn('time', right) def test_strips_quotes(self): with tempfile.TemporaryDirectory() as tmpdir: cfg_dir = Path(tmpdir) / '.config' / 'byobu' cfg_dir.mkdir(parents=True) (cfg_dir / 'status').write_text('tmux_left="logo session uptime"\n') with patch.object(Path, 'home', return_value=Path(tmpdir)): left, _ = bm._read_byobu_status_config() self.assertEqual(left, ['logo', 'session', 'uptime']) # --------------------------------------------------------------------------- # Pair code generation # --------------------------------------------------------------------------- class TestPairCode(unittest.TestCase): def test_code_is_six_digits(self): code = bm._generate_pair_code() self.assertRegex(code, r'^\d{6}$') def test_code_sets_expiry(self): before = time.monotonic() bm._generate_pair_code() self.assertGreater(bm._pair_code_mono_expiry, before) def test_code_resets_attempts(self): bm._pair_attempts = 5 bm._generate_pair_code() self.assertEqual(bm._pair_attempts, 0) def tearDown(self): bm._pair_code = '' bm._pair_code_expiry = 0.0 bm._pair_code_mono_expiry = 0.0 bm._pair_attempts = 0 # --------------------------------------------------------------------------- # HTTP handler tests (Tornado test client — no network needed) # --------------------------------------------------------------------------- def _add_session(token='test_tok_abc'): bm._sessions[token] = {'ip': '127.0.0.1', 'paired_at': time.time(), 'label': 'test'} return token def _clear_sessions(): bm._sessions.clear() class TestPingHandler(AsyncHTTPTestCase): def get_app(self): return bm._make_app() def setUp(self): super().setUp() _clear_sessions() bm._pair_code = '' def tearDown(self): _clear_sessions() super().tearDown() def test_unauthenticated_returns_401(self): resp = self.fetch('/ping') self.assertEqual(resp.code, 401) self.assertFalse(json.loads(resp.body)['auth']) def test_authenticated_via_cookie_returns_200(self): tok = _add_session() resp = self.fetch('/ping', headers={'Cookie': f'trustmux_session={tok}'}) self.assertEqual(resp.code, 200) data = json.loads(resp.body) self.assertTrue(data['auth']) self.assertIn('hostname', data) def test_query_param_token_not_accepted(self): tok = _add_session() resp = self.fetch(f'/ping?token={tok}') self.assertEqual(resp.code, 401) def test_wrong_token_returns_401(self): _add_session('correct_token') resp = self.fetch('/ping', headers={'Cookie': 'trustmux_session=wrong_token'}) self.assertEqual(resp.code, 401) class TestPairHandler(AsyncHTTPTestCase): def get_app(self): return bm._make_app() def setUp(self): super().setUp() _clear_sessions() bm._pair_code = '' bm._pair_attempts = 0 bm._pair_code_mono_expiry = 0.0 def tearDown(self): bm._pair_code = '' bm._pair_attempts = 0 bm._pair_code_mono_expiry = 0.0 _clear_sessions() super().tearDown() def _post(self, body): return self.fetch('/pair', method='POST', body=json.dumps(body), headers={'Content-Type': 'application/json'}) def test_no_active_code_returns_403(self): resp = self._post({'code': '123456'}) self.assertEqual(resp.code, 403) def test_expired_code_returns_403(self): bm._pair_code = '123456' bm._pair_code_mono_expiry = time.monotonic() - 1 # already expired resp = self._post({'code': '123456'}) self.assertEqual(resp.code, 403) self.assertEqual(bm._pair_code, '') # code cleared def test_wrong_code_returns_403_and_increments_attempts(self): bm._pair_code = '999999' bm._pair_code_mono_expiry = time.monotonic() + 300 resp = self._post({'code': '000000'}) self.assertEqual(resp.code, 403) self.assertEqual(bm._pair_attempts, 1) def test_valid_code_returns_200_and_sets_cookie(self): code = bm._generate_pair_code() with patch('trustmux._daemon._save_tokens'): resp = self._post({'code': code}) self.assertEqual(resp.code, 200) self.assertTrue(json.loads(resp.body).get('ok')) self.assertIn('trustmux_session', resp.headers.get('Set-Cookie', '')) # Code consumed — one-time use self.assertEqual(bm._pair_code, '') def test_valid_code_with_dashes(self): code = bm._generate_pair_code() dashed = f'{code[:3]}-{code[3:]}' with patch('trustmux._daemon._save_tokens'): resp = self._post({'code': dashed}) self.assertEqual(resp.code, 200) def test_too_many_attempts_returns_429(self): bm._pair_code = '111111' bm._pair_code_mono_expiry = time.monotonic() + 300 bm._pair_attempts = bm._MAX_PAIR_ATTEMPTS resp = self._post({'code': '111111'}) self.assertEqual(resp.code, 429) def test_invalid_json_returns_400(self): bm._pair_code = '123456' bm._pair_code_mono_expiry = time.monotonic() + 300 resp = self.fetch('/pair', method='POST', body='not-json', headers={'Content-Type': 'application/json'}) self.assertEqual(resp.code, 400) def test_request_too_large_returns_413(self): bm._pair_code = '123456' bm._pair_code_mono_expiry = time.monotonic() + 300 resp = self.fetch('/pair', method='POST', body='x' * 2000, headers={'Content-Type': 'application/json'}) self.assertEqual(resp.code, 413) class TestManifestHandler(AsyncHTTPTestCase): def get_app(self): return bm._make_app() def test_manifest_contains_hostname(self): import socket resp = self.fetch('/manifest.json') self.assertEqual(resp.code, 200) data = json.loads(resp.body) hostname = socket.gethostname().split('.')[0] self.assertIn(hostname, data['name']) self.assertEqual(data['short_name'], hostname) def test_manifest_has_required_fields(self): resp = self.fetch('/manifest.json') data = json.loads(resp.body) for field in ('name', 'short_name', 'start_url', 'display', 'icons'): self.assertIn(field, data, f'missing field: {field}') def test_manifest_no_cache(self): resp = self.fetch('/manifest.json') self.assertIn('no-cache', resp.headers.get('Cache-Control', '')) class TestStatusHandler(AsyncHTTPTestCase): def get_app(self): return bm._make_app() def setUp(self): super().setUp() _clear_sessions() def tearDown(self): _clear_sessions() super().tearDown() def test_unauthenticated_returns_401(self): resp = self.fetch('/status') self.assertEqual(resp.code, 401) def test_authenticated_returns_dict_with_left_right(self): tok = _add_session() with patch('trustmux._daemon.read_byobu_status', return_value={'left': [], 'right': []}): resp = self.fetch('/status', headers={'Cookie': f'trustmux_session={tok}'}) self.assertEqual(resp.code, 200) data = json.loads(resp.body) self.assertIn('left', data) self.assertIn('right', data) # --------------------------------------------------------------------------- # tmux_capture_pane ANSI flag # --------------------------------------------------------------------------- class TestCapturePaneAnsiFlag(unittest.TestCase): def test_plain_strips_ansi(self): colored = '\x1b[31mhello\x1b[0m' with patch.object(bm, '_tmux', return_value=colored): result = bm.tmux_capture_pane('%0', ansi=False) self.assertEqual(result, 'hello') def test_ansi_true_passes_through(self): colored = '\x1b[31mhello\x1b[0m' with patch.object(bm, '_tmux', return_value=colored): result = bm.tmux_capture_pane('%0', ansi=True) self.assertEqual(result, colored) def test_ansi_true_passes_e_flag(self): captured_args = [] def fake_tmux(*args): captured_args.extend(args) return '' with patch.object(bm, '_tmux', side_effect=fake_tmux): bm.tmux_capture_pane('%0', ansi=True) self.assertIn('-e', captured_args) def test_ansi_false_omits_e_flag(self): captured_args = [] def fake_tmux(*args): captured_args.extend(args) return '' with patch.object(bm, '_tmux', side_effect=fake_tmux): bm.tmux_capture_pane('%0', ansi=False) self.assertNotIn('-e', captured_args) if __name__ == '__main__': unittest.main(verbosity=2) byobu-7.15/mobile/tests/test_daemon_extended.py000066400000000000000000001044571522352767600217650ustar00rootroot00000000000000"""Extended test suite for Trustmux daemon. Covers: token persistence, security headers, static handlers, MachinesHandler, tmux list/write ops, byobu status chips, admin socket protocol, WebSocket handler. """ import asyncio import json import os import sys import tempfile import time import unittest from pathlib import Path from unittest.mock import patch, MagicMock, AsyncMock sys.path.insert(0, str(Path(__file__).parent.parent)) import trustmux._daemon as bm from tornado.testing import AsyncHTTPTestCase, gen_test from tornado.websocket import websocket_connect from tornado.httpclient import HTTPRequest from tornado.httputil import HTTPHeaders # --------------------------------------------------------------------------- # Helpers shared across test classes # --------------------------------------------------------------------------- def _add_session(token='tok_ext_test'): bm._sessions[token] = { 'ip': '127.0.0.1', 'paired_at': time.time(), 'label': 'test-agent/1.0', } return token def _clear_sessions(): bm._sessions.clear() # --------------------------------------------------------------------------- # Token persistence # --------------------------------------------------------------------------- class TestTokenPersistence(unittest.TestCase): def setUp(self): _clear_sessions() self._tmpdir = tempfile.TemporaryDirectory() self._orig_config = bm.CONFIG_DIR self._orig_tokens = bm.TOKENS_FILE bm.CONFIG_DIR = Path(self._tmpdir.name) / 'trustmux' bm.TOKENS_FILE = bm.CONFIG_DIR / 'tokens.json' def tearDown(self): _clear_sessions() bm.CONFIG_DIR = self._orig_config bm.TOKENS_FILE = self._orig_tokens self._tmpdir.cleanup() def _write_tokens(self, data): bm.CONFIG_DIR.mkdir(parents=True) bm.TOKENS_FILE.write_text(json.dumps(data)) def test_load_missing_file_is_no_op(self): bm._load_tokens() self.assertEqual(bm._sessions, {}) def test_load_valid_tokens(self): self._write_tokens({'mytoken': {'ip': '1.2.3.4', 'paired_at': time.time(), 'label': 'x'}}) bm._load_tokens() self.assertIn('mytoken', bm._sessions) self.assertEqual(bm._sessions['mytoken']['ip'], '1.2.3.4') def test_load_skips_malformed_records(self): self._write_tokens({ 'good': {'ip': '1.1.1.1', 'paired_at': time.time(), 'label': ''}, 'bad_str': 'not-a-dict', 'bad_missing': {'label': 'no ip or paired_at'}, }) bm._load_tokens() self.assertIn('good', bm._sessions) self.assertNotIn('bad_str', bm._sessions) self.assertNotIn('bad_missing', bm._sessions) def test_load_corrupt_json_does_not_raise(self): bm.CONFIG_DIR.mkdir(parents=True) bm.TOKENS_FILE.write_text('not json!!!') bm._load_tokens() self.assertEqual(bm._sessions, {}) def test_load_wrong_root_type_ignored(self): self._write_tokens([1, 2, 3]) bm._load_tokens() self.assertEqual(bm._sessions, {}) def test_save_creates_tokens_file(self): bm._sessions['tok123'] = {'ip': '9.9.9.9', 'paired_at': time.time(), 'label': 'y'} bm._save_tokens() self.assertTrue(bm.TOKENS_FILE.exists()) data = json.loads(bm.TOKENS_FILE.read_text()) self.assertIn('tok123', data) self.assertEqual(data['tok123']['ip'], '9.9.9.9') def test_save_file_mode_600(self): bm._sessions['tok456'] = {'ip': '1.1.1.1', 'paired_at': time.time(), 'label': ''} bm._save_tokens() mode = oct(bm.TOKENS_FILE.stat().st_mode)[-3:] self.assertEqual(mode, '600') def test_save_and_reload_roundtrip(self): bm._sessions['roundtrip'] = {'ip': '5.5.5.5', 'paired_at': time.time(), 'label': 'rt'} bm._save_tokens() _clear_sessions() bm._load_tokens() self.assertIn('roundtrip', bm._sessions) def test_valid_session_token_true_for_known(self): bm._sessions['abc123'] = {'ip': '1.1.1.1', 'paired_at': time.time(), 'label': ''} self.assertTrue(bm._valid_session_token('abc123')) def test_valid_session_token_false_for_unknown(self): self.assertFalse(bm._valid_session_token('nosuchtoken')) def test_valid_session_token_false_for_empty(self): self.assertFalse(bm._valid_session_token('')) # --------------------------------------------------------------------------- # Security headers — present on all endpoints # --------------------------------------------------------------------------- class TestSecurityHeaders(AsyncHTTPTestCase): def get_app(self): return bm._make_app() def setUp(self): super().setUp() _clear_sessions() def tearDown(self): _clear_sessions() super().tearDown() def _assert_security_headers(self, resp): h = resp.headers self.assertIn('DENY', h.get('X-Frame-Options', ''), 'X-Frame-Options missing') csp = h.get('Content-Security-Policy', '') self.assertIn('default-src', csp, 'CSP missing') self.assertNotIn("'unsafe-inline'", csp.split('script-src')[1].split(';')[0] if 'script-src' in csp else '', 'script-src must not allow unsafe-inline') self.assertIn('no-referrer', h.get('Referrer-Policy', ''), 'Referrer-Policy missing') self.assertIn('nosniff', h.get('X-Content-Type-Options', ''), 'X-Content-Type-Options missing') def test_ping_has_security_headers(self): self._assert_security_headers(self.fetch('/ping')) def test_manifest_has_security_headers(self): self._assert_security_headers(self.fetch('/manifest.json')) def test_status_has_security_headers(self): self._assert_security_headers(self.fetch('/status')) def test_pair_post_has_security_headers(self): bm._pair_code = '123456' bm._pair_code_mono_expiry = time.monotonic() + 300 resp = self.fetch('/pair', method='POST', body='{}', headers={'Content-Type': 'application/json'}) self._assert_security_headers(resp) bm._pair_code = '' # --------------------------------------------------------------------------- # Static file handlers # --------------------------------------------------------------------------- class TestStaticHandlers(AsyncHTTPTestCase): def get_app(self): return bm._make_app() def test_index_content_type_html(self): resp = self.fetch('/') self.assertEqual(resp.code, 200) self.assertIn('text/html', resp.headers.get('Content-Type', '')) def test_service_worker_no_cache(self): resp = self.fetch('/sw.js') self.assertEqual(resp.code, 200) self.assertIn('no-cache', resp.headers.get('Cache-Control', '')) def test_service_worker_content_type_js(self): resp = self.fetch('/sw.js') self.assertIn('javascript', resp.headers.get('Content-Type', '')) def test_svg_content_type(self): resp = self.fetch('/trustmux.svg') self.assertEqual(resp.code, 200) self.assertIn('svg', resp.headers.get('Content-Type', '')) def test_svg_has_cache_header(self): resp = self.fetch('/trustmux.svg') self.assertIn('max-age', resp.headers.get('Cache-Control', '')) def test_icon_invalid_name_returns_404(self): resp = self.fetch('/icons/nonexistent_icon_99999.png') self.assertEqual(resp.code, 404) def test_icon_path_traversal_blocked(self): resp = self.fetch('/icons/../trustmux.svg') # Tornado routing won't match this; should 404 self.assertIn(resp.code, (404, 400)) def test_icon_name_with_illegal_chars_returns_404(self): resp = self.fetch('/icons/foo;bar.png') self.assertEqual(resp.code, 404) def test_icon_existing_returns_200(self): resp = self.fetch('/icons/icon-192.png') self.assertEqual(resp.code, 200) self.assertEqual(resp.headers.get('Content-Type'), 'image/png') def test_icon_cache_header(self): resp = self.fetch('/icons/icon-192.png') self.assertIn('no-cache', resp.headers.get('Cache-Control', '')) def test_app_js_returns_200_with_js_content_type(self): resp = self.fetch('/app.js') self.assertEqual(resp.code, 200) self.assertIn('javascript', resp.headers.get('Content-Type', '')) def test_app_js_no_cache(self): resp = self.fetch('/app.js') self.assertIn('no-cache', resp.headers.get('Cache-Control', '')) def test_app_js_contains_strict_mode(self): resp = self.fetch('/app.js') self.assertIn(b"'use strict'", resp.body) # --------------------------------------------------------------------------- # MachinesHandler # --------------------------------------------------------------------------- class TestMachinesHandler(AsyncHTTPTestCase): def get_app(self): return bm._make_app() def setUp(self): super().setUp() self._tmpdir = tempfile.TemporaryDirectory() self._orig = bm.MACHINES_FILE bm.MACHINES_FILE = Path(self._tmpdir.name) / 'machines.json' # Create a valid session token for auth-required requests self._auth_token = 'test_machines_token' bm._sessions[self._auth_token] = {'ip': '127.0.0.1', 'paired_at': time.time(), 'label': 'test'} def tearDown(self): bm._sessions.pop(self._auth_token, None) bm.MACHINES_FILE = self._orig self._tmpdir.cleanup() super().tearDown() def _auth_fetch(self, path): return self.fetch(path, headers={'Cookie': f'trustmux_session={self._auth_token}'}) def test_no_file_returns_only_current(self): resp = self._auth_fetch('/machines') self.assertEqual(resp.code, 200) data = json.loads(resp.body) self.assertEqual(len(data), 1) self.assertTrue(data[0]['current']) def test_with_siblings_returns_all(self): siblings = [ {'name': 'work', 'url': 'https://work.ts.net'}, {'name': 'home', 'url': 'https://home.ts.net'}, ] bm.MACHINES_FILE.write_text(json.dumps(siblings)) resp = self._auth_fetch('/machines') data = json.loads(resp.body) self.assertEqual(len(data), 3) urls = [m['url'] for m in data] self.assertIn('https://work.ts.net', urls) def test_malformed_entry_skipped(self): siblings = [ {'name': 'good', 'url': 'https://good.ts.net'}, {'missing_url': True}, ] bm.MACHINES_FILE.write_text(json.dumps(siblings)) resp = self._auth_fetch('/machines') data = json.loads(resp.body) # Only current + 'good'; malformed entry absent self.assertEqual(len(data), 2) def test_non_list_json_returns_current_only(self): bm.MACHINES_FILE.write_text(json.dumps({'not': 'a list'})) resp = self._auth_fetch('/machines') data = json.loads(resp.body) self.assertEqual(len(data), 1) def test_corrupt_json_returns_500(self): bm.MACHINES_FILE.write_text('not valid json!!!') resp = self._auth_fetch('/machines') self.assertEqual(resp.code, 500) def test_corrupt_json_error_is_generic(self): bm.MACHINES_FILE.write_text('not valid json!!!') resp = self._auth_fetch('/machines') data = json.loads(resp.body) self.assertEqual(data.get('error'), 'internal error') def test_javascript_url_in_machines_file_is_filtered(self): siblings = [ {'name': 'good', 'url': 'https://good.ts.net'}, {'name': 'evil', 'url': 'javascript:alert(1)'}, ] bm.MACHINES_FILE.write_text(json.dumps(siblings)) resp = self._auth_fetch('/machines') data = json.loads(resp.body) urls = [m['url'] for m in data] self.assertNotIn('javascript:alert(1)', urls) self.assertIn('https://good.ts.net', urls) def test_unauthenticated_returns_401(self): resp = self.fetch('/machines') self.assertEqual(resp.code, 401) # --------------------------------------------------------------------------- # tmux_list_sessions parsing # --------------------------------------------------------------------------- class TestTmuxListSessions(unittest.TestCase): def _run(self, sess_output): def fake_tmux(*args): if 'list-sessions' in args: return sess_output if 'list-windows' in args: return '@0\t0\tmain\t1\n' return '%0\t0\t1\tbash\t123\n' with patch.object(bm, '_tmux', side_effect=fake_tmux): return bm.tmux_list_sessions() def test_parses_attached_session(self): sessions = self._run('$0\tmysession\t1\n') self.assertEqual(len(sessions), 1) self.assertEqual(sessions[0]['id'], '$0') self.assertEqual(sessions[0]['name'], 'mysession') self.assertTrue(sessions[0]['attached']) def test_parses_detached_session(self): sessions = self._run('$1\twork\t0\n') self.assertFalse(sessions[0]['attached']) def test_multiple_sessions(self): sessions = self._run('$0\ta\t1\n$1\tb\t0\n') self.assertEqual(len(sessions), 2) def test_empty_output(self): self.assertEqual(self._run(''), []) def test_session_has_windows_list(self): sessions = self._run('$0\tmain\t1\n') self.assertIn('windows', sessions[0]) self.assertIsInstance(sessions[0]['windows'], list) # --------------------------------------------------------------------------- # tmux write operations # --------------------------------------------------------------------------- class TestTmuxWriteOps(unittest.TestCase): def _capture(self, fn, *args, **kwargs): calls = [] with patch.object(bm, '_tmux', side_effect=lambda *a: calls.append(a) or ''), \ patch('time.sleep'): fn(*args, **kwargs) return calls def test_new_session_args(self): calls = self._capture(bm.tmux_new_session, 'mysession') self.assertEqual(len(calls), 1) self.assertIn('new-session', calls[0]) self.assertIn('-d', calls[0]) self.assertIn('-s', calls[0]) self.assertIn('mysession', calls[0]) def test_new_window_with_name(self): calls = self._capture(bm.tmux_new_window, '$0', 'vim') self.assertIn('new-window', calls[0]) self.assertIn('-n', calls[0]) self.assertIn('vim', calls[0]) def test_new_window_without_name_omits_n_flag(self): calls = self._capture(bm.tmux_new_window, '$0', '') self.assertIn('new-window', calls[0]) self.assertNotIn('-n', calls[0]) def test_new_pane_calls_split_window(self): calls = self._capture(bm.tmux_new_pane, '@1') self.assertIn('split-window', calls[0]) self.assertIn('@1', calls[0]) def test_send_keys_with_enter_makes_two_calls(self): calls = self._capture(bm.tmux_send_keys, '%0', 'ls', True) self.assertEqual(len(calls), 2) self.assertIn('ls', calls[0]) self.assertIn('Enter', calls[1]) def test_send_keys_without_enter_makes_one_call(self): calls = self._capture(bm.tmux_send_keys, '%0', 'ls', False) self.assertEqual(len(calls), 1) self.assertIn('ls', calls[0]) def test_send_keys_uses_literal_flag(self): calls = self._capture(bm.tmux_send_keys, '%0', 'my text', False) self.assertIn('-l', calls[0]) def test_send_keys_literal_with_enter_settles_before_enter(self): # Paste-burst-detecting TUIs (e.g. Codex CLI) swallow an Enter that # arrives immediately after a literal paste as a newline instead of # submit — regression test for GH #115. with patch.object(bm, '_tmux', return_value=''), patch('time.sleep') as mock_sleep: bm.tmux_send_keys('%0', 'ls', True, True) mock_sleep.assert_called_once_with(bm._PASTE_BURST_SETTLE) def test_send_keys_non_literal_with_enter_does_not_settle(self): with patch.object(bm, '_tmux', return_value=''), patch('time.sleep') as mock_sleep: bm.tmux_send_keys('%0', 'Enter', True, False) mock_sleep.assert_not_called() # --------------------------------------------------------------------------- # Byobu status — _first_attr # --------------------------------------------------------------------------- class TestFirstAttr(unittest.TestCase): def test_extracts_bg(self): self.assertEqual(bm._first_attr('#[bg=blue,fg=white]text', 'bg='), 'blue') def test_extracts_fg(self): self.assertEqual(bm._first_attr('#[bg=black,fg=brightwhite]text', 'fg='), 'brightwhite') def test_no_match_returns_none(self): self.assertIsNone(bm._first_attr('plain text', 'bg=')) def test_empty_attr_value_returns_none(self): self.assertIsNone(bm._first_attr('#[bg=]text', 'bg=')) def test_first_block_wins(self): self.assertEqual(bm._first_attr('#[bg=red]#[bg=blue]', 'bg='), 'red') def test_no_attr_blocks_returns_none(self): self.assertIsNone(bm._first_attr('', 'bg=')) # --------------------------------------------------------------------------- # Byobu status — _make_chip # --------------------------------------------------------------------------- class TestMakeChip(unittest.TestCase): def setUp(self): self._tmpdir = tempfile.TemporaryDirectory() self._shm = Path(self._tmpdir.name) self._status_dir = self._shm / 'status.tmux' self._status_dir.mkdir() def tearDown(self): self._tmpdir.cleanup() def _write_chip(self, name, content): (self._status_dir / name).write_text(content) def test_logo_returns_chip_when_file_exists(self): self._write_chip('logo', '#[default]#[fg=colour255,bg=colour202] u #[default]') chip = bm._make_chip('logo', self._shm) self.assertIsNotNone(chip) self.assertEqual(chip['label'], 'logo') self.assertEqual(chip['text'], 'u') self.assertEqual(chip['bg'], '#ff5f00') # colour202 = Ubuntu orange self.assertEqual(chip['color'], '#eeeeee') # light text on dark bg def test_logo_returns_none_when_file_missing(self): self.assertIsNone(bm._make_chip('logo', self._shm)) def test_colour256_cube_maps_correctly(self): self.assertEqual(bm._colour256_to_css('colour202'), '#ff5f00') self.assertEqual(bm._colour256_to_css('colour255'), '#eeeeee') self.assertEqual(bm._colour256_to_css('colour16'), '#000000') def test_colour256_greyscale_maps_correctly(self): self.assertEqual(bm._colour256_to_css('colour232'), '#080808') self.assertEqual(bm._colour256_to_css('colour244'), '#808080') def test_colour256_chip_uses_correct_css(self): self._write_chip('logo', '#[fg=colour255,bg=colour202] u ') chip = bm._make_chip('logo', self._shm) self.assertEqual(chip['bg'], '#ff5f00') def test_missing_status_dir_returns_none(self): shm2 = Path(self._tmpdir.name + '_2') shm2.mkdir() self.assertIsNone(bm._make_chip('uptime', shm2)) def test_missing_chip_file_returns_none(self): self.assertIsNone(bm._make_chip('nonexistent', self._shm)) def test_all_whitespace_chip_returns_none(self): self._write_chip('blank', '#[bg=blue] #[fg=white]') self.assertIsNone(bm._make_chip('blank', self._shm)) def test_valid_chip_returns_dict(self): self._write_chip('uptime', '#[bg=blue,fg=white] 5 days #[default]') chip = bm._make_chip('uptime', self._shm) self.assertIsNotNone(chip) self.assertEqual(chip['label'], 'uptime') self.assertIn('5', chip['text']) self.assertIn('bg', chip) self.assertIn('color', chip) self.assertIn('text', chip) def test_named_color_maps_to_css_hex(self): self._write_chip('time', '#[bg=cyan] 12:00 ') chip = bm._make_chip('time', self._shm) self.assertEqual(chip['bg'], bm._BG['cyan']) def test_css_hex_color_passes_through(self): self._write_chip('date', '#[bg=#ff00ff] Mon ') chip = bm._make_chip('date', self._shm) self.assertEqual(chip['bg'], '#ff00ff') def test_light_bg_gives_dark_text(self): self._write_chip('load', '#[bg=brightwhite] 1.2 ') chip = bm._make_chip('load', self._shm) self.assertEqual(chip['color'], '#111111') def test_dark_bg_gives_light_text(self): self._write_chip('mem', '#[bg=black] 512M ') chip = bm._make_chip('mem', self._shm) self.assertEqual(chip['color'], '#eeeeee') def test_unknown_color_uses_fallback(self): self._write_chip('cpu', '#[bg=unknowncolor] 50% ') chip = bm._make_chip('cpu', self._shm) self.assertEqual(chip['bg'], '#2d2d2d') # --------------------------------------------------------------------------- # Byobu status — read_byobu_status integration # --------------------------------------------------------------------------- class TestReadByobuStatus(unittest.TestCase): def setUp(self): self._tmpdir = tempfile.TemporaryDirectory() self._shm = Path(self._tmpdir.name) status_dir = self._shm / 'status.tmux' status_dir.mkdir() (status_dir / 'uptime').write_text('#[bg=blue] 1 day ') (status_dir / 'time').write_text('#[bg=cyan] 12:00 ') def tearDown(self): self._tmpdir.cleanup() def test_returns_chips_when_shm_present(self): with patch.object(bm, '_byobu_shm', return_value=self._shm): with patch.object(bm, '_read_byobu_status_config', return_value=(['uptime'], ['time'])): result = bm.read_byobu_status() self.assertEqual(len(result['left']), 1) self.assertEqual(len(result['right']), 1) self.assertEqual(result['left'][0]['label'], 'uptime') self.assertEqual(result['right'][0]['label'], 'time') def test_empty_when_no_shm(self): with patch.object(bm, '_byobu_shm', return_value=None): result = bm.read_byobu_status() self.assertEqual(result['left'], []) self.assertEqual(result['right'], []) def test_logo_chip_included_when_file_present(self): status_dir = self._shm / 'status.tmux' (status_dir / 'logo').write_text('#[fg=colour255,bg=colour202] u ') with patch.object(bm, '_byobu_shm', return_value=self._shm): with patch.object(bm, '_read_byobu_status_config', return_value=(['logo', 'uptime'], [])): result = bm.read_byobu_status() labels = [c['label'] for c in result['left']] self.assertIn('logo', labels) self.assertIn('uptime', labels) def test_missing_chip_file_skipped(self): with patch.object(bm, '_byobu_shm', return_value=self._shm): with patch.object(bm, '_read_byobu_status_config', return_value=(['nonexistent_chip'], [])): result = bm.read_byobu_status() self.assertEqual(result['left'], []) # --------------------------------------------------------------------------- # Admin Unix socket protocol # --------------------------------------------------------------------------- class TestAdminSocket(unittest.IsolatedAsyncioTestCase): def setUp(self): _clear_sessions() bm._pair_code = '' bm._pair_attempts = 0 bm._pair_code_mono_expiry = 0.0 def tearDown(self): _clear_sessions() bm._pair_code = '' bm._pair_attempts = 0 bm._pair_code_mono_expiry = 0.0 async def _call(self, payload) -> dict: """Drive _handle_admin with mock reader/writer; return parsed response.""" line = json.dumps(payload).encode() + b'\n' reader = asyncio.StreamReader() reader.feed_data(line) reader.feed_eof() written = [] writer = MagicMock() writer.write = lambda data: written.append(data) writer.drain = AsyncMock() writer.close = MagicMock() writer.wait_closed = AsyncMock() await bm._handle_admin(reader, writer) return json.loads(b''.join(written).decode().strip()) async def _call_raw(self, raw_bytes: bytes) -> dict: reader = asyncio.StreamReader() reader.feed_data(raw_bytes) reader.feed_eof() written = [] writer = MagicMock() writer.write = lambda data: written.append(data) writer.drain = AsyncMock() writer.close = MagicMock() writer.wait_closed = AsyncMock() await bm._handle_admin(reader, writer) return json.loads(b''.join(written).decode().strip()) async def test_pair_generate_returns_code(self): with patch.object(bm, '_print_pair_code'): resp = await self._call({'action': 'pair_generate'}) self.assertIn('code', resp) self.assertIn('-', resp['code']) self.assertEqual(len(resp['code']), 7) # XXX-XXX self.assertIn('expires_in', resp) self.assertTrue(bm._pair_code) async def test_sessions_list_empty(self): resp = await self._call({'action': 'sessions_list'}) self.assertIsInstance(resp, list) self.assertEqual(len(resp), 0) async def test_sessions_list_populated(self): _add_session('tok_abcdef_123456') resp = await self._call({'action': 'sessions_list'}) self.assertIsInstance(resp, list) self.assertEqual(len(resp), 1) entry = resp[0] self.assertIn('ip', entry) self.assertIn('paired_at', entry) self.assertIn('token', entry) self.assertIn('token_full', entry) # abbreviated token ends with … self.assertTrue(entry['token'].endswith('…')) async def test_sessions_delete_all(self): _add_session('tok1') _add_session('tok2') with patch.object(bm, '_save_tokens'): resp = await self._call({'action': 'sessions_delete', 'token': None}) self.assertTrue(resp.get('ok')) self.assertEqual(resp.get('removed'), 2) self.assertEqual(len(bm._sessions), 0) async def test_sessions_delete_specific(self): _add_session('tok_gone') _add_session('tok_kept') with patch.object(bm, '_save_tokens'): resp = await self._call({'action': 'sessions_delete', 'token': 'tok_gone'}) self.assertTrue(resp.get('ok')) self.assertNotIn('tok_gone', bm._sessions) self.assertIn('tok_kept', bm._sessions) async def test_sessions_delete_not_found(self): resp = await self._call({'action': 'sessions_delete', 'token': 'nosuchtoken'}) self.assertIn('error', resp) async def test_sessions_delete_empty_token_errors(self): resp = await self._call({'action': 'sessions_delete', 'token': ''}) self.assertIn('error', resp) async def test_unknown_action_returns_error(self): resp = await self._call({'action': 'do_something_impossible'}) self.assertIn('error', resp) async def test_bad_json_returns_error(self): resp = await self._call_raw(b'not valid json\n') self.assertIn('error', resp) async def test_non_dict_json_returns_error(self): resp = await self._call([1, 2, 3]) self.assertIn('error', resp) # --------------------------------------------------------------------------- # WebSocket handler # --------------------------------------------------------------------------- class TestWsHandler(AsyncHTTPTestCase): def get_app(self): return bm._make_app() def setUp(self): super().setUp() _clear_sessions() bm._pair_code = '' def tearDown(self): _clear_sessions() super().tearDown() def _ws_req(self, token=None): url = f'ws://localhost:{self.get_http_port()}/ws' if token: headers = HTTPHeaders({'Cookie': f'trustmux_session={token}'}) return HTTPRequest(url, headers=headers) return url @gen_test(timeout=5) async def test_invalid_token_closes_connection(self): conn = await websocket_connect(self._ws_req(token='badtoken')) msg = await conn.read_message() self.assertIsNone(msg) @gen_test(timeout=5) async def test_valid_token_receives_initial_sessions(self): tok = _add_session('ws_tok_init') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) msg = await conn.read_message() data = json.loads(msg) self.assertEqual(data['type'], 'sessions') conn.close() @gen_test(timeout=5) async def test_list_sessions_returns_sessions(self): tok = _add_session('ws_tok_ls') fake = [{'id': '$0', 'name': 'main', 'attached': True, 'windows': []}] with patch.object(bm, 'tmux_list_sessions', return_value=fake): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() await conn.write_message(json.dumps({'type': 'list_sessions'})) resp = await conn.read_message() data = json.loads(resp) self.assertEqual(data['type'], 'sessions') self.assertEqual(data['data'], fake) conn.close() @gen_test(timeout=5) async def test_invalid_json_returns_error(self): tok = _add_session('ws_tok_json') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() await conn.write_message('not valid json {{{') resp = await conn.read_message() data = json.loads(resp) self.assertEqual(data['type'], 'error') self.assertIn('invalid JSON', data['message']) conn.close() @gen_test(timeout=5) async def test_oversized_message_returns_error(self): tok = _add_session('ws_tok_size') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() await conn.write_message('x' * 20_000) resp = await conn.read_message() data = json.loads(resp) self.assertEqual(data['type'], 'error') self.assertIn('too large', data['message']) conn.close() @gen_test(timeout=5) async def test_subscribe_invalid_pane_id_returns_error(self): tok = _add_session('ws_tok_sub') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() await conn.write_message(json.dumps({'type': 'subscribe', 'pane_id': 'notvalid'})) resp = await conn.read_message() data = json.loads(resp) self.assertEqual(data['type'], 'error') conn.close() @gen_test(timeout=5) async def test_send_keys_invalid_pane_id_returns_error(self): tok = _add_session('ws_tok_sk') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() await conn.write_message(json.dumps( {'type': 'send_keys', 'pane_id': 'bad', 'keys': 'ls'})) resp = await conn.read_message() data = json.loads(resp) self.assertEqual(data['type'], 'error') conn.close() @gen_test(timeout=5) async def test_new_session_empty_name_returns_error(self): tok = _add_session('ws_tok_ns') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() await conn.write_message(json.dumps({'type': 'new_session', 'name': ''})) resp = await conn.read_message() data = json.loads(resp) self.assertEqual(data['type'], 'error') conn.close() @gen_test(timeout=5) async def test_new_window_invalid_session_id_returns_error(self): tok = _add_session('ws_tok_nw') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() await conn.write_message(json.dumps( {'type': 'new_window', 'session_id': 'notvalid'})) resp = await conn.read_message() data = json.loads(resp) self.assertEqual(data['type'], 'error') conn.close() @gen_test(timeout=5) async def test_new_pane_invalid_window_id_returns_error(self): tok = _add_session('ws_tok_np') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() await conn.write_message(json.dumps( {'type': 'new_pane', 'window_id': 'notvalid'})) resp = await conn.read_message() data = json.loads(resp) self.assertEqual(data['type'], 'error') conn.close() @gen_test(timeout=5) async def test_non_dict_json_returns_error(self): tok = _add_session('ws_tok_nd') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() await conn.write_message(json.dumps([1, 2, 3])) resp = await conn.read_message() data = json.loads(resp) self.assertEqual(data['type'], 'error') conn.close() @gen_test(timeout=10) async def test_rate_limit_triggers_error(self): tok = _add_session('ws_tok_rate') with patch.object(bm, 'tmux_list_sessions', return_value=[]): conn = await websocket_connect(self._ws_req(token=tok)) await conn.read_message() # Flood with messages exceeding the per-second rate limit burst = bm._WS_RATE_LIMIT + 5 for _ in range(burst): await conn.write_message(json.dumps({'type': 'list_sessions'})) rate_errors = [] for _ in range(burst): resp = await conn.read_message() if resp is None: break d = json.loads(resp) if d.get('type') == 'error' and 'rate' in d.get('message', '').lower(): rate_errors.append(d) break self.assertGreater(len(rate_errors), 0, 'Expected at least one rate-limit error') conn.close() if __name__ == '__main__': unittest.main(verbosity=2) byobu-7.15/mobile/trustmux.in000066400000000000000000000007561522352767600163270ustar00rootroot00000000000000#!/usr/bin/env python3 """trustmux — manage the Trustmux daemon.""" import sys import os # When run from the dev tree, the package is in a sibling trustmux/ dir. # When installed by autotools, fall back to the configure-time trustmuxpydir. _here = os.path.dirname(os.path.abspath(__file__)) if os.path.isdir(os.path.join(_here, "trustmux")): sys.path.insert(0, _here) else: sys.path.insert(0, "@trustmuxpydir@") from trustmux._ctl import main if __name__ == "__main__": main() byobu-7.15/mobile/trustmux/000077500000000000000000000000001522352767600157675ustar00rootroot00000000000000byobu-7.15/mobile/trustmux/__init__.py000066400000000000000000000001231522352767600200740ustar00rootroot00000000000000"""Trustmux — mobile companion for Byobu/tmux sessions.""" __version__ = "7.15" byobu-7.15/mobile/trustmux/__main__.py000066400000000000000000000001111522352767600200520ustar00rootroot00000000000000from trustmux._daemon import main if __name__ == "__main__": main() byobu-7.15/mobile/trustmux/_ctl.py000066400000000000000000000447371522352767600173010ustar00rootroot00000000000000"""trustmux — manage the Trustmux daemon.""" import argparse import ipaddress import json import os import shutil import signal import socket import subprocess import sys import time from pathlib import Path PORT = 7432 SERVE_PORT = 443 # tailscale serve terminates TLS on :443 CONFIG_DIR = Path.home() / ".config" / "trustmux" LOGFILE = CONFIG_DIR / "trustmux.log" PIDFILE = CONFIG_DIR / "trustmux.pid" TOKENS_FILE = CONFIG_DIR / "tokens.json" def _check_tmux() -> bool: """Hard-error if tmux is absent; warn if no sessions exist. Returns False on hard error.""" if not shutil.which("tmux") and not shutil.which("byobu"): print("", file=sys.stderr) print("Error: tmux is not installed — trustmux requires tmux to attach to sessions.", file=sys.stderr) print(" Install tmux: https://github.com/tmux/tmux/wiki/Installing", file=sys.stderr) print(" Install Byobu: https://byobu.org", file=sys.stderr) print("", file=sys.stderr) return False try: out = subprocess.check_output( ["tmux", "list-sessions", "-F", "#{session_name}"], stderr=subprocess.DEVNULL, text=True, timeout=3, ).strip() sessions = [s for s in out.splitlines() if s] except (FileNotFoundError, subprocess.CalledProcessError): sessions = [] if not sessions: print("", file=sys.stderr) print("Warning: no tmux sessions found — trustmux will start but has nothing to attach to.", file=sys.stderr) print(" Start a session first: tmux new-session", file=sys.stderr) print(" Or launch Byobu: byobu", file=sys.stderr) print("", file=sys.stderr) return True def _check_tls() -> bool: """Return True if TLS cert generation is available, False (with message) if not.""" try: from cryptography.hazmat.primitives.asymmetric import ec ec.generate_private_key(ec.SECP256R1()) return True except Exception as e: print("", file=sys.stderr) print("Error: TLS support is unavailable — trustmux refuses to start without encryption.", file=sys.stderr) print(f" ({e})", file=sys.stderr) print("", file=sys.stderr) print("The 'cryptography' package is required. Fix with:", file=sys.stderr) print(f" {sys.executable} -m pip install --upgrade cryptography", file=sys.stderr) print("", file=sys.stderr) return False def _ensure_dir() -> None: CONFIG_DIR.mkdir(mode=0o700, parents=True, exist_ok=True) LOGFILE.touch() LOGFILE.chmod(0o600) def _pid() -> int | None: """Return PID of process listening on PORT, or None.""" try: out = subprocess.check_output( ["lsof", f"-ti:{PORT}"], stderr=subprocess.DEVNULL, text=True ).strip() if out: return int(out.splitlines()[0]) except (FileNotFoundError, subprocess.CalledProcessError, ValueError): pass # Fallback: check PIDFILE if PIDFILE.exists(): try: pid = int(PIDFILE.read_text().strip()) os.kill(pid, 0) return pid except (ValueError, ProcessLookupError, PermissionError, OSError): pass return None def _ts_host() -> str: """Return Tailscale DNS name, or empty string.""" try: out = subprocess.check_output( ["tailscale", "status", "--json"], stderr=subprocess.DEVNULL, timeout=5, text=True, ) return json.loads(out).get("Self", {}).get("DNSName", "").rstrip(".") except Exception: return "" def _peer_acl_allows_tcp(port: int = SERVE_PORT) -> bool | None: """Check whether the current tailnet ACL permits peer devices to reach this node on tcp:. Returns True if at least one packet-filter rule allows it, False if no rule does, or None if the check could not be performed (no tailscale binary, unexpected netmap shape, etc.) — callers should treat None as "no warning." """ try: out = subprocess.check_output( ["tailscale", "debug", "netmap"], stderr=subprocess.DEVNULL, timeout=3, text=True, ) nm = json.loads(out) except Exception: return None self_ips: set[str] = set() for cidr in (nm.get("SelfNode") or {}).get("Addresses") or []: self_ips.add(cidr.split("/")[0]) rules = nm.get("PacketFilter") if not rules: return None for r in rules: protos = r.get("IPProto") or [] # Empty IPProto means "any protocol" in Tailscale's filter format. if protos and 6 not in protos: continue for dst in r.get("Dsts") or []: ports = dst.get("Ports") or {} first, last = ports.get("First"), ports.get("Last") if first is None or last is None: continue if not (first <= port <= last): continue if self_ips: try: net = ipaddress.ip_network(dst.get("Net", ""), strict=False) if not any(ipaddress.ip_address(ip) in net for ip in self_ips): continue except ValueError: continue return True return False def warn_if_peer_blocked(port: int = SERVE_PORT, stream=sys.stderr) -> None: """Print an actionable warning if peer access to tcp: appears to be blocked by the tailnet ACL. Silent when the check passes or cannot run. Without this warning, an ACL that omits the serve port produces a confusing failure mode: the daemon and `tailscale serve` are healthy, `curl` from the same host succeeds (loopback bypasses ACL evaluation), but peer browsers see ERR_NETWORK_CHANGED or "Site cannot be reached" because tailscaled silently drops the incoming TCP with no RST. """ if _peer_acl_allows_tcp(port) is not False: return print("", file=stream) print(f"warning: your tailnet ACL does not appear to allow tcp:{port} to this device.", file=stream) print( " Peer devices will silently fail to connect; browsers show", file=stream) print( " ERR_NETWORK_CHANGED or 'site cannot be reached.'", file=stream) print( "", file=stream) print( " Edit your tailnet policy at:", file=stream) print( " https://login.tailscale.com/admin/acls/file", file=stream) print( "", file=stream) print( " For the newer 'grants' format, add:", file=stream) print( "", file=stream) print( ' { "src": ["autogroup:member"],', file=stream) print( ' "dst": [""],', file=stream) print(f' "ip": ["tcp:{port}"] }}', file=stream) print( "", file=stream) print( " For the legacy 'acls' format, add:", file=stream) print( "", file=stream) print( ' { "action": "accept",', file=stream) print( ' "src": ["autogroup:member"],', file=stream) print(f' "dst": [":{port}"] }}', file=stream) print( "", file=stream) def _ensure_ts_serve() -> bool: """Configure tailscale serve for PORT. Returns True on success.""" try: out = subprocess.check_output( ["tailscale", "serve", "status"], stderr=subprocess.DEVNULL, text=True, ) if f":{PORT}" in out: print(f"✓ tailscale serve already configured for port {PORT}") return True except Exception: pass print(f"Enabling tailscale serve (HTTPS → localhost:{PORT})...") try: subprocess.run( ["tailscale", "serve", "--bg", str(PORT)], check=True, stderr=subprocess.DEVNULL, ) print("✓ tailscale serve configured") return True except (FileNotFoundError, subprocess.CalledProcessError): pass user = os.environ.get("USER", "") print("", file=sys.stderr) print("Error: could not configure tailscale serve.", file=sys.stderr) print("Your user needs Tailscale operator permission (one-time setup). Run:", file=sys.stderr) print(f" sudo tailscale set --operator={user}", file=sys.stderr) print(f" tailscale serve --bg {PORT}", file=sys.stderr) print("Then re-run: trustmux start", file=sys.stderr) return False def _launch(extra_args: list[str]) -> int | None: """Launch daemon as a detached background process. Returns PID or None.""" _ensure_dir() # Ensure the package directory is on the subprocess's Python path so that # `python3 -m trustmux` resolves correctly regardless of how Python was # invoked (e.g. bare /usr/bin/python3 from a .deb shim). pkg_parent = str(Path(__file__).parent.parent) env = os.environ.copy() existing = env.get("PYTHONPATH", "") env["PYTHONPATH"] = f"{pkg_parent}:{existing}" if existing else pkg_parent with LOGFILE.open("a") as log: proc = subprocess.Popen( [sys.executable, "-m", "trustmux", "--port", str(PORT)] + extra_args, stdout=log, stderr=log, stdin=subprocess.DEVNULL, start_new_session=True, env=env, ) PIDFILE.write_text(str(proc.pid)) time.sleep(0.5) return _pid() def cmd_setup(quiet: bool = False) -> int: print("=== trustmux setup ===\n") # Verify package is importable try: import trustmux._daemon # noqa: F401 print("✓ trustmux package available") except ImportError: print("Error: trustmux package not importable. Install with: pip install trustmux", file=sys.stderr) return 1 # Tailscale presence try: subprocess.run(["tailscale", "--version"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except (FileNotFoundError, subprocess.CalledProcessError): print("\nError: tailscale not found in PATH.", file=sys.stderr) print("Install from https://tailscale.com/download, connect, then re-run.", file=sys.stderr) return 1 ts_host = _ts_host() if not ts_host: print("\nError: Tailscale installed but not connected.", file=sys.stderr) print("Run 'tailscale up', then re-run setup.", file=sys.stderr) return 1 print(f"✓ Tailscale connected as {ts_host}") if not _ensure_ts_serve(): return 1 warn_if_peer_blocked() if not quiet: print("\nSetup complete. Next steps:\n") print(" 1. Start the daemon: trustmux start") print(" 2. Generate pairing code: trustmux pair") print(f" 3. Open on your phone: https://{ts_host}") return 0 def cmd_start(mode: str = "serve") -> int: p = _pid() if p: print(f"trustmux already running (pid {p})") return 1 if mode == "serve": if not _check_tmux(): return 1 if not _check_tls(): return 1 try: subprocess.run(["tailscale", "--version"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except (FileNotFoundError, subprocess.CalledProcessError): print("Error: tailscale not found.", file=sys.stderr) print("Install: https://tailscale.com/docs/install/linux", file=sys.stderr) print("Or use 'start-direct' for self-signed HTTPS without Tailscale.", file=sys.stderr) return 1 ts_host = _ts_host() if not ts_host: print("Error: cannot determine Tailscale hostname (is tailscale up?)", file=sys.stderr) return 1 if not _ensure_ts_serve(): return 1 print("Starting trustmux (HTTPS mode)...") pid = _launch(["--host", "127.0.0.1", "--https"]) ok = pid is not None if ok: print(f"trustmux started (pid {pid})") print(f"Connect: https://{ts_host}") elif mode == "start-local": print("Starting trustmux (loopback only — SSH tunnel access)...") pid = _launch(["--host", "127.0.0.1"]) ok = pid is not None if ok: fqdn = socket.getfqdn() print(f"trustmux started (pid {pid})") print(f"Access via SSH tunnel: ssh -L {PORT}:localhost:{PORT} user@{fqdn}") print(f"Then open: http://localhost:{PORT}") elif mode == "start-direct": if not _check_tmux(): return 1 if not _check_tls(): return 1 print("Starting trustmux (direct HTTPS — self-signed cert)...") pid = _launch(["--host", "0.0.0.0", "--self-signed"]) ok = pid is not None if ok: try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) local_ip = s.getsockname()[0] s.close() except Exception: local_ip = "localhost" print(f"trustmux started (pid {pid})") print(f"Connect: https://{local_ip}:{PORT}") print(f" (browser will warn about self-signed cert — click through to proceed)") else: print(f"Unknown mode: {mode}", file=sys.stderr) return 1 if not ok: print(f"trustmux failed to start — check {LOGFILE}") return 1 return 0 def cmd_stop() -> int: p = _pid() if not p: print("trustmux not running") PIDFILE.unlink(missing_ok=True) return 0 if PIDFILE.exists(): try: file_pid = int(PIDFILE.read_text().strip()) if file_pid != p: print(f"Error: pid {p} owns port {PORT} but PIDFILE contains {file_pid}.", file=sys.stderr) print(f"Refusing to kill. Remove {PIDFILE} manually if trustmux is truly stopped.", file=sys.stderr) return 1 except ValueError: pass os.kill(p, signal.SIGTERM) print(f"trustmux stopped (pid {p})") PIDFILE.unlink(missing_ok=True) return 0 def cmd_status() -> int: p = _pid() if not p: print("trustmux not running") return 0 print(f"trustmux running (pid {p}) — port {PORT}") try: out = subprocess.check_output( ["tailscale", "serve", "status"], stderr=subprocess.DEVNULL, text=True, ) if f":{PORT}" in out: ts_host = _ts_host() if ts_host: print(f"Connect: https://{ts_host}") return 0 except Exception: pass try: ts_ip = subprocess.check_output( ["tailscale", "ip", "-4"], stderr=subprocess.DEVNULL, text=True, ).strip() except Exception: ts_ip = "localhost" print(f"Connect: http://{ts_ip}:{PORT} (direct HTTP)") return 0 def cmd_log() -> int: _ensure_dir() try: subprocess.run(["tail", "-f", str(LOGFILE)]) except KeyboardInterrupt: pass return 0 def _refuse_root() -> None: """Abort if running as root (e.g. via sudo). Running as root causes three distinct failure modes: 1. Path.home() resolves to /root/, so PIDFILE/CONFIG_DIR point to root's home; the PID-mismatch safety check in cmd_stop() is silently bypassed because the user's PIDFILE is invisible to root. 2. `tailscale serve` runs as root and creates a conflicting serve config, clobbering the user-level config and wedging tailscale. 3. The daemon relaunches owned by root, creating a privilege-escalation risk and making the user-level `trustmux stop/status` inoperative. """ if os.geteuid() == 0: sudo_user = os.environ.get("SUDO_USER", "") hint = f" Run as your normal user: sudo -u {sudo_user} trustmux ..." if sudo_user else "" if not hint: hint = " Drop sudo and run as your normal user account." print("Error: trustmux must not be run as root (or via sudo).", file=sys.stderr) print(hint, file=sys.stderr) print(" Running as root breaks tailscale serve config and daemon ownership.", file=sys.stderr) sys.exit(1) def main() -> None: _refuse_root() parser = argparse.ArgumentParser( prog="trustmux", description="Manage the Trustmux daemon", epilog="To remove tailscale serve config: tailscale serve reset", ) sub = parser.add_subparsers(dest="cmd") p_setup = sub.add_parser("setup", help="One-time setup: verify install, configure tailscale serve") p_setup.add_argument("--quiet", action="store_true", help="Suppress next-steps output") sub.add_parser("start", help="Start daemon via tailscale serve (HTTPS — default)") sub.add_parser("serve", help=argparse.SUPPRESS) # alias sub.add_parser("start-local", help="Start daemon loopback-only for SSH tunnel access") sub.add_parser("start-direct", help="Start daemon direct HTTPS (self-signed cert, no Tailscale)") sub.add_parser("stop", help="Stop daemon (tailscale serve config persists)") sub.add_parser("restart", help="Restart daemon") sub.add_parser("status", help="Show running status and URL") sub.add_parser("log", help="Tail the log file") sub.add_parser("enable", help="Start daemon and install login hook for automatic start") sub.add_parser("disable", help="Stop daemon and remove login hook") sub.add_parser("pair", help="Generate a one-time pairing code for a new device") sub.add_parser("unpair", help="List paired devices and revoke tokens") args = parser.parse_args() if not args.cmd: parser.print_help() sys.exit(1) cmd = args.cmd if cmd == "setup": sys.exit(cmd_setup(quiet=args.quiet)) elif cmd in ("start", "serve"): sys.exit(cmd_start("serve")) elif cmd == "start-local": sys.exit(cmd_start("start-local")) elif cmd == "start-direct": sys.exit(cmd_start("start-direct")) elif cmd == "stop": sys.exit(cmd_stop()) elif cmd == "restart": cmd_stop() time.sleep(0.5) sys.exit(cmd_start("serve")) elif cmd == "status": sys.exit(cmd_status()) elif cmd == "log": sys.exit(cmd_log()) elif cmd == "enable": from trustmux._enable import main as _run_enable _run_enable() elif cmd == "disable": from trustmux._disable import main as _run_disable _run_disable() elif cmd == "pair": from trustmux._pair import main as _run_pair _run_pair() elif cmd == "unpair": from trustmux._unpair import main as _run_unpair _run_unpair() if __name__ == "__main__": main() byobu-7.15/mobile/trustmux/_daemon.py000066400000000000000000001424441522352767600177540ustar00rootroot00000000000000#!/usr/bin/env python3 """Trustmux daemon — mobile companion for Byobu/tmux sessions.""" import argparse import asyncio import base64 from datetime import datetime import getpass import glob import hmac import json import os import re import secrets import socket import subprocess import sys import time from pathlib import Path import tornado.httpserver import tornado.web import tornado.websocket def _resolve_version() -> str: import subprocess as _sp # Prefer the full Debian package version (e.g. 7.14-1~local1) when # installed via .deb — gives the exact build including local iterators. try: v = _sp.check_output( ["dpkg-query", "-W", "-f=${Version}", "byobu"], stderr=_sp.DEVNULL, text=True, ).strip() if v: return v except Exception: pass # pip / PyPI install: metadata carries the tag version (e.g. 7.14rc1). try: from importlib.metadata import version as _pkg_version return _pkg_version("trustmux") except Exception: pass # Dev tree fallback. from trustmux import __version__ return __version__ _DAEMON_VERSION = _resolve_version() # --------------------------------------------------------------------------- # Pairing & session state # --------------------------------------------------------------------------- _pair_code: str = "" _pair_code_expiry: float = 0.0 # wall-clock time, for human display only _pair_code_mono_expiry: float = 0.0 # monotonic time, for expiry check _pair_attempts: int = 0 _MAX_PAIR_ATTEMPTS: int = 3 _PAIR_CODE_TTL: int = 60 # 60 seconds — keep the window tight _TOKEN_EXPIRY_DAYS: int = 90 # sessions expire after 90 days of inactivity _sessions: dict[str, dict] = {} # token → {ip, paired_at, label, last_used} _ws_clients: dict[str, set] = {} # token → set[WsHandler] — closed on unpair _https_mode: bool = False # set by --https; enables Secure cookie CONFIG_DIR = Path.home() / ".config" / "trustmux" TOKENS_FILE = CONFIG_DIR / "tokens.json" ADMIN_SOCK = CONFIG_DIR / "trustmux.sock" MACHINES_FILE = CONFIG_DIR / "machines.json" _INSTALLED_STATIC = Path("/usr/share/trustmux/static") _DEV_STATIC = Path(__file__).parent / "static" STATIC = _INSTALLED_STATIC if _INSTALLED_STATIC.is_dir() else _DEV_STATIC def _get_server_tz() -> str: try: with open("/etc/timezone") as _f: return _f.read().strip() except Exception: return "UTC" _SERVER_TZ = _get_server_tz() def _load_tokens() -> None: if not TOKENS_FILE.exists(): return try: data = json.loads(TOKENS_FILE.read_text()) if not isinstance(data, dict): raise ValueError("expected a JSON object") expiry_cutoff = time.time() - _TOKEN_EXPIRY_DAYS * 86400 valid = { t: s for t, s in data.items() if isinstance(t, str) and isinstance(s, dict) and "ip" in s and "paired_at" in s and float(s.get("last_used", s["paired_at"])) > expiry_cutoff } expired = sum( 1 for t, s in data.items() if isinstance(t, str) and isinstance(s, dict) and "paired_at" in s and float(s.get("last_used", s["paired_at"])) <= expiry_cutoff ) malformed = len(data) - len(valid) - expired if expired: print(f"Info: expired {expired} stale session(s) from {TOKENS_FILE}", flush=True) if malformed: print(f"Warning: skipped {malformed} malformed record(s) in {TOKENS_FILE}", flush=True) _sessions.update(valid) except Exception as e: print(f"Warning: could not load {TOKENS_FILE}: {e} — all sessions lost", flush=True) def _save_tokens() -> None: CONFIG_DIR.mkdir(parents=True, exist_ok=True, mode=0o700) CONFIG_DIR.chmod(0o700) tmp = TOKENS_FILE.with_suffix(".tmp") fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) try: with os.fdopen(fd, "w") as f: json.dump(_sessions, f, indent=2) except Exception: tmp.unlink(missing_ok=True) raise os.replace(tmp, TOKENS_FILE) def _generate_pair_code() -> str: global _pair_code, _pair_code_expiry, _pair_code_mono_expiry, _pair_attempts _pair_code = f"{secrets.randbelow(1000000):06d}" _pair_code_expiry = time.time() + _PAIR_CODE_TTL _pair_code_mono_expiry = time.monotonic() + _PAIR_CODE_TTL _pair_attempts = 0 return _pair_code def _print_pair_code() -> None: fmt = f"{_pair_code[:3]}-{_pair_code[3:]}" expiry = datetime.fromtimestamp(_pair_code_expiry).strftime("%H:%M:%S") bar = "═" * 50 print(f"\n{bar}") print(f" Trustmux pairing code: {fmt} (expires {expiry})") print(f"{bar}\n", flush=True) def _valid_session_token(token: str) -> bool: if not token: return False token_bytes = token.encode() expiry_cutoff = time.time() - _TOKEN_EXPIRY_DAYS * 86400 for k, s in _sessions.items(): if hmac.compare_digest(token_bytes, k.encode()): if float(s.get("last_used", s.get("paired_at", 0))) <= expiry_cutoff: return False s["last_used"] = time.time() return True return False # --------------------------------------------------------------------------- # Tailscale IP detection # --------------------------------------------------------------------------- _IPV4_RE = re.compile(r'^\d{1,3}(?:\.\d{1,3}){3}$') def _tailscale_ip() -> str | None: try: r = subprocess.run(["tailscale", "ip", "-4"], capture_output=True, text=True, timeout=3) if r.returncode == 0: ip = r.stdout.strip().splitlines()[0].strip() if _IPV4_RE.match(ip): return ip except Exception: pass try: r = subprocess.run(["ip", "-4", "addr", "show", "tailscale0"], capture_output=True, text=True, timeout=3) m = re.search(r"inet (\d+\.\d+\.\d+\.\d+)", r.stdout) if m and _IPV4_RE.match(m.group(1)): return m.group(1) except Exception: pass return None # --------------------------------------------------------------------------- # ANSI stripping # --------------------------------------------------------------------------- ANSI_RE = re.compile( r'\x1b\[[0-9;]*[mGKHFJABCDsuhrPX@L]' r'|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)' r'|\x1b[()][AB012]' r'|\x1b[MDEHO78=>]' r'|\r' ) def strip_ansi(text: str) -> str: return ANSI_RE.sub('', text) def _smarter_pane_name(pane_pid_str: str, fallback: str) -> str: """Walk /proc tree from pane_pid to find the leaf foreground process name. tmux's pane_current_command only sees the direct child of the shell (e.g. 'sh' when running a shell-script wrapper like 'claude'). Reading /proc//task//children lets us follow the chain down to the real foreground process without spawning extra subprocesses. """ try: pid = int(pane_pid_str) except (ValueError, TypeError): return fallback seen: set[int] = set() for _ in range(6): if pid in seen: break seen.add(pid) try: children = Path(f"/proc/{pid}/task/{pid}/children").read_text().split() except OSError: break if not children: try: name = Path(f"/proc/{pid}/comm").read_text().strip() return name or fallback except OSError: break try: pid = int(children[0]) except (ValueError, IndexError): break return fallback # --------------------------------------------------------------------------- # tmux interface — thin wrappers around the tmux CLI # --------------------------------------------------------------------------- def _tmux(*args) -> str: result = subprocess.run( ["tmux"] + list(args), capture_output=True, text=True, timeout=5 ) return result.stdout def tmux_list_sessions() -> list[dict]: raw = _tmux("list-sessions", "-F", "#{session_id}\t#{session_name}\t#{session_attached}") sessions = [] for line in raw.splitlines(): parts = line.split("\t") if len(parts) < 2: continue sid, name = parts[0], parts[1] attached = parts[2] == "1" if len(parts) > 2 else False sessions.append({ "id": sid, "name": name, "attached": attached, "windows": tmux_list_windows(sid), }) return sessions def tmux_list_windows(session_id: str) -> list[dict]: raw = _tmux("list-windows", "-t", session_id, "-F", "#{window_id}\t#{window_index}\t#{window_name}\t#{window_active}") windows = [] for line in raw.splitlines(): parts = line.split("\t") if len(parts) < 4: continue wid, idx, name, active = parts[0], parts[1], parts[2], parts[3] try: index = int(idx) except ValueError: continue windows.append({ "id": wid, "index": index, "name": name, "active": active == "1", "panes": tmux_list_panes(wid), }) return windows def tmux_list_panes(window_id: str) -> list[dict]: raw = _tmux("list-panes", "-t", window_id, "-F", "#{pane_id}\t#{pane_index}\t#{pane_active}\t#{pane_current_command}\t#{pane_pid}\t#{pane_dead}") panes = [] for line in raw.splitlines(): parts = line.split("\t") if len(parts) < 3: continue pane_id_str = parts[0] try: idx = int(parts[1]) except ValueError: continue active = parts[2] == "1" cmd = parts[3] if len(parts) > 3 else "" pid_str = parts[4] if len(parts) > 4 else "" dead = parts[5] == "1" if len(parts) > 5 else False if not dead and pid_str: cmd = _smarter_pane_name(pid_str, cmd) panes.append({ "id": pane_id_str, "index": idx, "active": active, "command": cmd, "dead": dead, }) return panes def tmux_capture_pane(pane_id: str, history_lines: int = 200, ansi: bool = False) -> str: if ansi: raw = _tmux("capture-pane", "-t", pane_id, "-p", "-e", "-S", f"-{history_lines}") else: raw = _tmux("capture-pane", "-t", pane_id, "-p", "-S", f"-{history_lines}") raw = strip_ansi(raw) return raw def tmux_new_session(name: str) -> None: _tmux("new-session", "-d", "-s", name) def tmux_new_window(session_id: str, name: str = "") -> None: args = ["new-window", "-t", session_id] if name: args += ["-n", name] _tmux(*args) def tmux_new_pane(window_id: str) -> None: _tmux("split-window", "-t", window_id) def tmux_kill_pane(pane_id: str) -> None: _tmux("kill-pane", "-t", pane_id) def tmux_kill_window(window_id: str) -> None: _tmux("kill-window", "-t", window_id) def tmux_kill_session(session_id: str) -> None: _tmux("kill-session", "-t", session_id) # `send-keys -l` delivers the whole literal string as one paste-like burst. # Some TUIs (e.g. Codex CLI) detect paste-like input by inter-keystroke # timing and, for a short window afterward, treat Enter as a newline inside # the paste rather than submit — sending Enter immediately lands inside that # window, so Enter is silently swallowed. Codex's window is 120ms; settle # past it before sending Enter. https://github.com/dustinkirkland/byobu/issues/115 _PASTE_BURST_SETTLE = 0.15 def tmux_send_keys(pane_id: str, keys: str, enter: bool = True, literal: bool = True) -> None: if literal: _tmux("send-keys", "-t", pane_id, "-l", keys) else: _tmux("send-keys", "-t", pane_id, keys) if enter: if literal: time.sleep(_PASTE_BURST_SETTLE) _tmux("send-keys", "-t", pane_id, "Enter") def tmux_rename_window(window_id: str, name: str) -> None: _tmux("rename-window", "-t", window_id, name) def tmux_rename_session(session_id: str, name: str) -> None: _tmux("rename-session", "-t", session_id, name) # --------------------------------------------------------------------------- # Byobu status line — reads pre-computed cache from /dev/shm # --------------------------------------------------------------------------- _BG = { "black": "#1e1e1e", "red": "#b03030", "green": "#2a7a2a", "yellow": "#8a8000", "blue": "#2050b0", "magenta": "#7a2a7a", "cyan": "#1a7070", "white": "#8a9090", "brightblack": "#484848", "brightred": "#cc4444", "brightgreen": "#44bb44", "brightyellow": "#cccc00", "brightblue": "#4466cc", "brightmagenta": "#bb44bb", "brightcyan": "#44bbbb", "brightwhite": "#dddddd", } _LIGHT_BG = {"white", "brightwhite", "brightgreen", "brightyellow", "brightcyan", "brightblue"} def _colour256_to_css(name: str) -> str | None: """Convert a tmux colour 256-color name to a CSS hex string.""" if not name.startswith("colour"): return None try: n = int(name[6:]) except ValueError: return None if 16 <= n <= 231: # 6×6×6 RGB cube n -= 16 levels = (0, 95, 135, 175, 215, 255) r, g, b = levels[n // 36], levels[(n % 36) // 6], levels[n % 6] return f"#{r:02x}{g:02x}{b:02x}" if 232 <= n <= 255: # grayscale ramp v = 8 + (n - 232) * 10 return f"#{v:02x}{v:02x}{v:02x}" return None _TMUX_ATTR = re.compile(r"#\[[^\]]*\]") _CSS_HEX_RE = re.compile(r"^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$") def _first_attr(content: str, prefix: str) -> str | None: for m in _TMUX_ATTR.finditer(content): inner = m.group(0)[2:-1] for part in inner.split(","): part = part.strip() if part.startswith(prefix): val = part[len(prefix):] return val if val else None return None def _byobu_shm() -> Path | None: user = getpass.getuser() uid = os.getuid() for hit in sorted(glob.glob(f"/dev/shm/byobu-{user}-*")): try: if os.stat(hit).st_uid == uid: return Path(hit) except OSError: continue return None def _read_byobu_status_config() -> tuple[list[str], list[str]]: """Parse user's byobu status config; return (left_metrics, right_metrics).""" left_raw = "logo release session" right_raw = "uptime load_average cpu_count cpu_freq memory disk date time" for path in [ Path.home() / ".config" / "byobu" / "status", Path.home() / ".byobu" / "status", Path("/usr/share/byobu/status/status"), ]: if not path.exists(): continue try: for line in path.read_text().splitlines(): line = line.strip() if line.startswith("tmux_left="): left_raw = line.split("=", 1)[1].strip().strip('"') elif line.startswith("tmux_right=") and not line.startswith("#"): right_raw = line.split("=", 1)[1].strip().strip('"') break except OSError: continue def _parse(raw: str) -> list[str]: return [m for m in raw.split() if m and not m.startswith("#")] return _parse(left_raw), _parse(right_raw) def _make_chip(name: str, shm: Path) -> dict | None: if not _BYOBU_METRIC_RE.match(name): return None status_dir = shm / "status.tmux" if not status_dir.is_dir(): return None fpath = status_dir / name if not fpath.exists(): return None try: raw = fpath.read_text() except OSError: return None text = _TMUX_ATTR.sub("", raw).strip() text = re.sub(r'([KMGT])(\d)', r'\1 \2', text) if not text: return None bg_name = _first_attr(raw, "bg=") if bg_name and _CSS_HEX_RE.match(bg_name): bg_css = bg_name elif bg_name and bg_name.startswith("colour"): bg_css = _colour256_to_css(bg_name) or "#2d2d2d" else: bg_css = _BG.get(bg_name or "", "#2d2d2d") text_css = "#111111" if bg_name in _LIGHT_BG else "#eeeeee" return {"label": name, "text": text, "bg": bg_css, "color": text_css} def read_byobu_status() -> dict: shm = _byobu_shm() left_names, right_names = _read_byobu_status_config() def _chips(names: list[str]) -> list[dict]: if not shm: return [] return [c for name in names if (c := _make_chip(name, shm))] return {"left": _chips(left_names), "right": _chips(right_names)} # --------------------------------------------------------------------------- # Tornado HTTP handlers # --------------------------------------------------------------------------- _CSP = ( "default-src 'self'; " "script-src 'self'; " "style-src 'unsafe-inline'; " "connect-src 'self'; " "img-src 'self'" ) class BaseHandler(tornado.web.RequestHandler): """All handlers inherit this for security headers.""" def set_default_headers(self): self.set_header("X-Content-Type-Options", "nosniff") self.set_header("X-Frame-Options", "DENY") self.set_header("Content-Security-Policy", _CSP) self.set_header("Referrer-Policy", "no-referrer") self.set_header("Permissions-Policy", "camera=(), microphone=(), geolocation=()") if _https_mode: self.set_header("Strict-Transport-Security", "max-age=31536000; includeSubDomains") def json(self, obj: object, status: int = 200): self.set_status(status) self.set_header("Content-Type", "application/json") self.finish(json.dumps(obj)) class BaseAuthHandler(BaseHandler): """Protected handlers inherit this; unauthenticated requests get 401.""" def set_default_headers(self): super().set_default_headers() self.set_header("Cache-Control", "no-store") def prepare(self): token = self.get_cookie("trustmux_session") or "" if not _valid_session_token(token): self.json({"error": "unauthorized"}, 401) # ── public endpoints ───────────────────────────────────────────────────────── class IndexHandler(BaseHandler): async def get(self): content = await asyncio.to_thread((STATIC / "index.html").read_text) self.set_header("Content-Type", "text/html; charset=utf-8") self.finish(content) class SvgHandler(BaseHandler): async def get(self): content = await asyncio.to_thread((STATIC / "trustmux.svg").read_bytes) self.set_header("Content-Type", "image/svg+xml") self.set_header("Cache-Control", "max-age=86400") self.finish(content) class ManifestHandler(BaseHandler): def get(self): hostname = socket.gethostname().split('.')[0] manifest = { "name": f"Trustmux · {hostname}", "short_name": hostname, "description": "Monitor and interact with your tmux/Byobu sessions from your phone.", "start_url": "/", "display": "standalone", "background_color": "#141414", "theme_color": "#141414", "icons": [ {"src": "/icons/icon-192.png?v=3", "sizes": "192x192", "type": "image/png", "purpose": "any"}, {"src": "/icons/icon-512.png?v=3", "sizes": "512x512", "type": "image/png", "purpose": "any maskable"}, ], } self.set_header("Content-Type", "application/manifest+json") self.set_header("Cache-Control", "no-cache") self.finish(json.dumps(manifest)) class ServiceWorkerHandler(BaseHandler): async def get(self): content = await asyncio.to_thread((STATIC / "sw.js").read_bytes) self.set_header("Content-Type", "application/javascript") # Service workers must not be cached — browser re-checks on every load. self.set_header("Cache-Control", "no-cache") self.finish(content) class AppJsHandler(BaseHandler): async def get(self): content = await asyncio.to_thread((STATIC / "app.js").read_bytes) self.set_header("Content-Type", "application/javascript") self.set_header("Cache-Control", "no-cache") self.finish(content) class IconHandler(BaseHandler): async def get(self, filename: str): if not re.match(r'^[\w\-]+\.png$', filename): return self.json({"error": "not found"}, 404) path = STATIC / "icons" / filename if not path.exists(): return self.json({"error": "not found"}, 404) content = await asyncio.to_thread(path.read_bytes) self.set_header("Content-Type", "image/png") self.set_header("Cache-Control", "no-cache") self.finish(content) class PingHandler(BaseHandler): def get(self): self.set_header("Cache-Control", "no-store") token = self.get_cookie("trustmux_session") or "" if _valid_session_token(token): self.json({"auth": True, "hostname": socket.gethostname(), "version": _DAEMON_VERSION}) else: self.json({"auth": False}, 401) class PairHandler(BaseHandler): async def post(self): global _pair_attempts, _pair_code, _pair_code_expiry, _pair_code_mono_expiry if not _pair_code: return self.json({"error": "no pairing code active — run trustmux-pair"}, 403) if time.monotonic() > _pair_code_mono_expiry: _pair_code = "" return self.json({"error": "pairing code expired — run trustmux-pair again"}, 403) if _pair_attempts >= _MAX_PAIR_ATTEMPTS: return self.json({"error": "too many attempts — run trustmux-pair again"}, 429) body_bytes = self.request.body if len(body_bytes) > 1024: return self.json({"error": "request too large"}, 413) try: body = json.loads(body_bytes) except json.JSONDecodeError: return self.json({"error": "invalid JSON"}, 400) if not isinstance(body, dict): return self.json({"error": "invalid JSON"}, 400) code = re.sub(r"\D", "", body.get("code", "")) if code != _pair_code: _pair_attempts += 1 left = _MAX_PAIR_ATTEMPTS - _pair_attempts await asyncio.sleep(0.5) # slow brute-force attempts return self.json({"error": f"wrong code — {left} attempts left"}, 403) # Valid — issue permanent session token; invalidate code (one device per code) token = secrets.token_urlsafe(32) label = self.request.headers.get("User-Agent", "")[:120] ip = self.request.remote_ip # respects xheaders automatically now = time.time() _sessions[token] = { "ip": ip, "paired_at": now, "last_used": now, "label": label, } await asyncio.to_thread(_save_tokens) _pair_code = "" _pair_code_expiry = 0.0 _pair_code_mono_expiry = 0.0 _pair_attempts = 0 print(f"✓ Trustmux: device paired ({ip})", flush=True) self.set_cookie( "trustmux_session", token, expires_days=_TOKEN_EXPIRY_DAYS, httponly=True, samesite="Strict", secure=_https_mode, ) self.json({"ok": True}) class MachinesHandler(BaseAuthHandler): async def get(self): try: current_url = f"{self.request.protocol}://{self.request.host}" siblings = [] if MACHINES_FILE.exists(): raw = json.loads(await asyncio.to_thread(MACHINES_FILE.read_text)) if isinstance(raw, list): siblings = [s for s in raw if isinstance(s, dict) and "name" in s and "url" in s and re.match(r'^https://', s["url"])] result = [{"name": "this machine", "url": current_url, "current": True}] + [ {"name": s["name"], "url": s["url"].rstrip("/"), "current": False} for s in siblings ] for s in siblings: if s.get("url", "").rstrip("/") == current_url.rstrip("/"): result[0]["name"] = s["name"] break self.json(result) except Exception: self.json({"error": "internal error"}, 500) # ── protected endpoints ─────────────────────────────────────────────────────── class StatusHandler(BaseAuthHandler): async def get(self): chips = await asyncio.to_thread(read_byobu_status) self.json(chips) # --------------------------------------------------------------------------- # WebSocket handler # --------------------------------------------------------------------------- _MAX_HISTORY_LINES = 10_000 _TMUX_ID_RE = re.compile(r"^[$@%]\d+$") _WS_RATE_WINDOW = 1.0 # seconds _WS_RATE_LIMIT = 20 # max messages per window def _valid_tmux_id(s: str) -> bool: return bool(s and _TMUX_ID_RE.match(s)) _TMUX_NAME_BAD = re.compile(r'[:.@%\n\r]') _BYOBU_METRIC_RE = re.compile(r'^[a-zA-Z0-9_]+$') def _valid_tmux_name(s: str) -> bool: return bool(s) and not _TMUX_NAME_BAD.search(s) class WsHandler(tornado.websocket.WebSocketHandler): """One WebSocket connection per browser tab. check_origin() is intentionally left at Tornado's default, which requires Origin == Host. This is a security measure against cross-site WebSocket hijacking and is correct for our setup in all modes. """ async def get(self, *args, **kwargs): # Chrome uses HTTP/2 for HTTPS connections. HTTP/2 WebSocket (RFC 8441) # uses CONNECT + :protocol:websocket and omits Sec-WebSocket-Key. # Tailscale serve translates H2→H1.1 but doesn't generate the missing # key, causing Tornado to reject the handshake with 400. Inject it here. hdrs = self.request.headers if not hdrs.get("Sec-WebSocket-Key"): hdrs["Sec-WebSocket-Key"] = base64.b64encode(os.urandom(16)).decode() if not hdrs.get("Upgrade"): hdrs["Upgrade"] = "websocket" if "upgrade" not in hdrs.get("Connection", "").lower(): hdrs["Connection"] = "Upgrade" await super().get(*args, **kwargs) def open(self): self._stream_task: asyncio.Task | None = None self._topo_task: asyncio.Task | None = None self._auth_timer: asyncio.Task | None = None self._rate_window_start = time.monotonic() self._rate_count = 0 token = self.get_cookie("trustmux_session") or "" if token: # Cookie present: accept if valid, reject immediately if not if _valid_session_token(token): self._token = token self._authenticated = True self._start_streams() else: self.close(4401, "unauthorized") else: # No cookie: native client authenticates via first-message auth frame self._token = None self._authenticated = False self._auth_timer = asyncio.ensure_future(self._auth_timeout()) def _start_streams(self): _ws_clients.setdefault(self._token, set()).add(self) asyncio.ensure_future(self._send_sessions()) self._topo_task = asyncio.ensure_future(self._poll_topology()) async def _auth_timeout(self): await asyncio.sleep(10) if not getattr(self, "_authenticated", False): self.close(4401, "authentication timeout") def on_message(self, raw): asyncio.ensure_future(self._handle(raw)) def on_close(self): token = getattr(self, "_token", None) if token and token in _ws_clients: _ws_clients[token].discard(self) if not _ws_clients[token]: del _ws_clients[token] if getattr(self, "_stream_task", None): self._stream_task.cancel() if getattr(self, "_topo_task", None): self._topo_task.cancel() if getattr(self, "_auth_timer", None): self._auth_timer.cancel() def _send(self, obj: dict): try: obj["server_ts"] = int(time.time() * 1000) obj["server_tz"] = _SERVER_TZ obj["server_tz_offset_s"] = int(datetime.now().astimezone().utcoffset().total_seconds()) self.write_message(json.dumps(obj)) except tornado.websocket.WebSocketClosedError: pass async def _send_sessions(self): sessions = await asyncio.to_thread(tmux_list_sessions) self._send({"type": "sessions", "data": sessions}) async def _poll_topology(self): try: sessions = await asyncio.to_thread(tmux_list_sessions) last = json.dumps(sessions, sort_keys=True) except Exception: last = None while True: await asyncio.sleep(2) try: sessions = await asyncio.to_thread(tmux_list_sessions) key = json.dumps(sessions, sort_keys=True) if key != last: last = key self._send({"type": "sessions", "data": sessions}) except asyncio.CancelledError: raise except Exception: pass async def _stream_pane(self, pane_id: str, history_lines: int, ansi: bool = False): try: content = await asyncio.to_thread(tmux_capture_pane, pane_id, history_lines, ansi) self._send({"type": "snapshot", "pane_id": pane_id, "data": content}) last = content while True: await asyncio.sleep(0.5) content = await asyncio.to_thread(tmux_capture_pane, pane_id, history_lines, ansi) if content != last: self._send({"type": "update", "pane_id": pane_id, "data": content}) last = content except asyncio.CancelledError: raise except Exception: self._send({"type": "error", "message": "pane stream error"}) async def _handle(self, raw: str): # Handle unauthenticated state — expect auth message first if not getattr(self, "_authenticated", False): try: msg = json.loads(raw) if isinstance(msg, dict) and msg.get("type") == "auth": token = str(msg.get("token", "")) if _valid_session_token(token): if self._auth_timer: self._auth_timer.cancel() self._auth_timer = None self._token = token self._authenticated = True self._start_streams() return except Exception: pass self.close(4401, "unauthorized") return # Re-check token on every message — catches revocation mid-session if not _valid_session_token(getattr(self, "_token", "")): self.close(4401, "unauthorized") return # Rate limiting: fixed window, per connection now = time.monotonic() if now - self._rate_window_start >= _WS_RATE_WINDOW: self._rate_window_start = now self._rate_count = 0 self._rate_count += 1 if self._rate_count > _WS_RATE_LIMIT: self._send({"type": "error", "message": "rate limit exceeded"}) return if len(raw) > 16_384: self._send({"type": "error", "message": "message too large"}) return try: msg = json.loads(raw) except json.JSONDecodeError: self._send({"type": "error", "message": "invalid JSON"}) return finally: del raw # drop the raw WebSocket frame as early as possible if not isinstance(msg, dict): self._send({"type": "error", "message": "invalid JSON"}) return mtype = msg.get("type") try: if mtype == "list_sessions": sessions = await asyncio.to_thread(tmux_list_sessions) self._send({"type": "sessions", "data": sessions}) elif mtype == "subscribe": pane_id = msg.get("pane_id", "") if not _valid_tmux_id(pane_id): self._send({"type": "error", "message": "invalid pane_id"}) else: try: lines = max(1, min(int(msg.get("lines", 300)), _MAX_HISTORY_LINES)) except (ValueError, TypeError): lines = 300 ansi = bool(msg.get("ansi", False)) if self._stream_task: self._stream_task.cancel() await asyncio.gather(self._stream_task, return_exceptions=True) self._stream_task = asyncio.ensure_future( self._stream_pane(pane_id, lines, ansi) ) elif mtype == "new_session": name = str(msg.get("name", "")).strip()[:128] if not name: self._send({"type": "error", "message": "session name required"}) elif not _valid_tmux_name(name): self._send({"type": "error", "message": "invalid session name"}) else: await asyncio.to_thread(tmux_new_session, name) sessions_list = await asyncio.to_thread(tmux_list_sessions) new_id = next((s["id"] for s in sessions_list if s["name"] == name), None) self._send({"type": "sessions", "data": sessions_list, "new_session": new_id}) elif mtype == "new_window": sid = msg.get("session_id", "") if not _valid_tmux_id(sid): self._send({"type": "error", "message": "invalid session_id"}) else: name = str(msg.get("name", "")).strip()[:128] if name and not _valid_tmux_name(name): self._send({"type": "error", "message": "invalid window name"}) return await asyncio.to_thread(tmux_new_window, sid, name) sessions_list = await asyncio.to_thread(tmux_list_sessions) # Find the newly created pane: last window (highest index) in this session new_pane_id = None for s in sessions_list: if s["id"] == sid and s.get("windows"): last_win = max(s["windows"], key=lambda w: w["index"]) if last_win.get("panes"): new_pane_id = last_win["panes"][0]["id"] break self._send({"type": "sessions", "data": sessions_list, "new_pane": new_pane_id}) elif mtype == "new_pane": wid = msg.get("window_id", "") if not _valid_tmux_id(wid): self._send({"type": "error", "message": "invalid window_id"}) else: # Snapshot pane IDs before split to identify the new one panes_before = {p["id"] for p in await asyncio.to_thread(tmux_list_panes, wid)} await asyncio.to_thread(tmux_new_pane, wid) sessions_list = await asyncio.to_thread(tmux_list_sessions) new_pane_id = None for s in sessions_list: for w in s.get("windows", []): if w["id"] == wid: for p in w.get("panes", []): if p["id"] not in panes_before: new_pane_id = p["id"] break self._send({"type": "sessions", "data": sessions_list, "new_pane": new_pane_id}) elif mtype == "kill_pane": pane_id = msg.get("pane_id", "") if not _valid_tmux_id(pane_id): self._send({"type": "error", "message": "invalid pane_id"}) else: await asyncio.to_thread(tmux_kill_pane, pane_id) sessions_list = await asyncio.to_thread(tmux_list_sessions) self._send({"type": "sessions", "data": sessions_list}) elif mtype == "kill_window": wid = msg.get("window_id", "") if not _valid_tmux_id(wid): self._send({"type": "error", "message": "invalid window_id"}) else: await asyncio.to_thread(tmux_kill_window, wid) sessions_list = await asyncio.to_thread(tmux_list_sessions) self._send({"type": "sessions", "data": sessions_list}) elif mtype == "kill_session": sid = msg.get("session_id", "") if not _valid_tmux_id(sid): self._send({"type": "error", "message": "invalid session_id"}) else: await asyncio.to_thread(tmux_kill_session, sid) sessions_list = await asyncio.to_thread(tmux_list_sessions) self._send({"type": "sessions", "data": sessions_list}) elif mtype == "send_keys": pane_id = msg.get("pane_id", "") if not _valid_tmux_id(pane_id): self._send({"type": "error", "message": "invalid pane_id"}) else: keys = str(msg.get("keys", ""))[:4096] enter = bool(msg.get("enter", True)) literal = bool(msg.get("literal", True)) await asyncio.to_thread(tmux_send_keys, pane_id, keys, enter, literal) del keys # release sensitive content as early as possible elif mtype == "rename_window": wid = msg.get("window_id", "") if not _valid_tmux_id(wid): self._send({"type": "error", "message": "invalid window_id"}) else: name = str(msg.get("name", "")).strip()[:128] if not name or not _valid_tmux_name(name): self._send({"type": "error", "message": "invalid window name"}) else: await asyncio.to_thread(tmux_rename_window, wid, name) sessions_list = await asyncio.to_thread(tmux_list_sessions) self._send({"type": "sessions", "data": sessions_list}) elif mtype == "rename_session": sid = msg.get("session_id", "") if not _valid_tmux_id(sid): self._send({"type": "error", "message": "invalid session_id"}) else: name = str(msg.get("name", "")).strip()[:128] if not name or not _valid_tmux_name(name): self._send({"type": "error", "message": "invalid session name"}) else: await asyncio.to_thread(tmux_rename_session, sid, name) sessions_list = await asyncio.to_thread(tmux_list_sessions) self._send({"type": "sessions", "data": sessions_list}) except Exception: self._send({"type": "error", "message": "command failed"}) # --------------------------------------------------------------------------- # Admin Unix socket — trustmux-pair / trustmux-unpair only # Socket is 0o600; only the owning user can connect. # No TCP exposure: management traffic never touches the network. # --------------------------------------------------------------------------- async def _handle_admin(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None: try: raw = await asyncio.wait_for(reader.readuntil(b"\n"), timeout=5.0) cmd = json.loads(raw) except Exception: writer.write(b'{"error":"bad request"}\n') await writer.drain() writer.close() await writer.wait_closed() return if not isinstance(cmd, dict): writer.write(b'{"error":"bad request"}\n') await writer.drain() writer.close() await writer.wait_closed() return try: action = cmd.get("action", "") if action == "pair_generate": code = _generate_pair_code() _print_pair_code() resp: object = {"code": f"{code[:3]}-{code[3:]}", "expires_in": _PAIR_CODE_TTL} elif action == "sessions_list": resp = [ { "token": t[:8] + "…", "token_full": t, "ip": s["ip"], "paired_at": datetime.fromtimestamp(float(s["paired_at"])).strftime("%Y-%m-%d %H:%M:%S"), "label": s.get("label", ""), } for t, s in _sessions.items() ] elif action == "sessions_delete": token = cmd.get("token") # None = clear all; non-empty string = specific token if token is None: tokens_to_evict = list(_sessions.keys()) count = len(_sessions) _sessions.clear() _save_tokens() for t in tokens_to_evict: for ws in list(_ws_clients.get(t, [])): ws.close(4401, "unauthorized") resp = {"ok": True, "removed": count} elif token: if token in _sessions: del _sessions[token] _save_tokens() for ws in list(_ws_clients.get(token, [])): ws.close(4401, "unauthorized") resp = {"ok": True} else: resp = {"error": "session not found"} else: resp = {"error": "token must be null (clear all) or a non-empty string"} else: resp = {"error": f"unknown action: {action!r}"} writer.write(json.dumps(resp).encode() + b"\n") except Exception: writer.write(b'{"error":"internal error"}\n') finally: await writer.drain() writer.close() await writer.wait_closed() async def _run_admin_server() -> None: if ADMIN_SOCK.exists(): ADMIN_SOCK.unlink() old_mask = os.umask(0o177) # socket created with mode 0o600 try: server = await asyncio.start_unix_server(_handle_admin, path=str(ADMIN_SOCK)) finally: os.umask(old_mask) ADMIN_SOCK.chmod(0o600) # belt and suspenders try: async with server: await server.serve_forever() finally: ADMIN_SOCK.unlink(missing_ok=True) # --------------------------------------------------------------------------- # Application wiring # --------------------------------------------------------------------------- def _make_app() -> tornado.web.Application: return tornado.web.Application([ (r"/", IndexHandler), (r"/trustmux\.svg", SvgHandler), (r"/manifest\.json", ManifestHandler), (r"/sw\.js", ServiceWorkerHandler), (r"/app\.js", AppJsHandler), (r"/icons/(.+)", IconHandler), (r"/ping", PingHandler), (r"/pair", PairHandler), (r"/machines", MachinesHandler), (r"/status", StatusHandler), (r"/ws", WsHandler), ]) # --------------------------------------------------------------------------- # Entry point # --------------------------------------------------------------------------- def _ensure_self_signed_cert(lan_ip: str) -> tuple: """Generate a self-signed TLS cert for lan_ip. Returns (cert_path, ssl_ctx).""" import ssl as _ssl import ipaddress as _ipaddress import datetime as _datetime from cryptography import x509 as _x509 from cryptography.x509.oid import NameOID as _NameOID from cryptography.hazmat.primitives import hashes as _hashes, serialization as _ser from cryptography.hazmat.primitives.asymmetric import ec as _ec cert = CONFIG_DIR / "cert.pem" key = CONFIG_DIR / "key.pem" CONFIG_DIR.mkdir(mode=0o700, parents=True, exist_ok=True) san_parts = [f"IP:{lan_ip}", "IP:127.0.0.1", "DNS:localhost"] fqdn = socket.getfqdn() if fqdn and fqdn not in ("localhost", lan_ip): san_parts.append(f"DNS:{fqdn}") hostname = socket.gethostname().split(".")[0] if hostname and hostname not in ("localhost",): san_parts.append(f"DNS:{hostname}") ts_ip = _tailscale_ip() if ts_ip and ts_ip != lan_ip: san_parts.append(f"IP:{ts_ip}") try: private_key = _ec.generate_private_key(_ec.SECP256R1()) san_list = [] for part in san_parts: if part.startswith("IP:"): san_list.append(_x509.IPAddress(_ipaddress.ip_address(part[3:]))) elif part.startswith("DNS:"): san_list.append(_x509.DNSName(part[4:])) subject = issuer = _x509.Name([ _x509.NameAttribute(_NameOID.COMMON_NAME, "trustmux"), ]) now = _datetime.datetime.now(_datetime.timezone.utc) cert_obj = ( _x509.CertificateBuilder() .subject_name(subject) .issuer_name(issuer) .public_key(private_key.public_key()) .serial_number(_x509.random_serial_number()) .not_valid_before(now) .not_valid_after(now + _datetime.timedelta(days=3650)) .add_extension(_x509.SubjectAlternativeName(san_list), critical=False) .sign(private_key, _hashes.SHA256()) ) key.write_bytes(private_key.private_bytes( encoding=_ser.Encoding.PEM, format=_ser.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=_ser.NoEncryption(), )) cert.write_bytes(cert_obj.public_bytes(_ser.Encoding.PEM)) cert.chmod(0o644) key.chmod(0o600) except Exception as e: print(f"Error: TLS cert generation failed ({e})", flush=True) print(f"Trustmux refuses to start without encryption. Install 'cryptography': {sys.executable} -m pip install --upgrade cryptography", flush=True) sys.exit(1) ctx = _ssl.SSLContext(_ssl.PROTOCOL_TLS_SERVER) ctx.minimum_version = _ssl.TLSVersion.TLSv1_3 ctx.load_cert_chain(str(cert), str(key)) print(f"Trustmux: self-signed TLS cert generated for {lan_ip}", flush=True) return cert, ctx async def _amain(host: str, port: int, https: bool, ssl_ctx=None) -> None: global _https_mode _https_mode = https or ssl_ctx is not None app = _make_app() # xheaders=True: trust X-Forwarded-For/Proto from tailscale serve proxy. # Only set in --https mode; in direct mode leave False to prevent spoofing. server = tornado.httpserver.HTTPServer(app, xheaders=https, ssl_options=ssl_ctx, max_body_size=65536) server.listen(port, address=host) admin_task = asyncio.create_task(_run_admin_server()) try: await asyncio.Event().wait() # run until cancelled (Ctrl-C / SIGTERM) finally: admin_task.cancel() try: await admin_task except asyncio.CancelledError: pass server.stop() def main(): from importlib.metadata import version as _pkg_version, PackageNotFoundError try: _version = _pkg_version("trustmux") except PackageNotFoundError: _version = "dev" parser = argparse.ArgumentParser(description="Trustmux daemon") parser.add_argument("--version", action="version", version=f"trustmux {_version}") parser.add_argument("--host", default=None, help="Bind address (default: Tailscale IP; 127.0.0.1 with --https)") parser.add_argument("--port", type=int, default=7432, help="Port (default: 7432)") parser.add_argument("--https", action="store_true", help="HTTPS mode: Secure cookie + trust proxy headers (use with tailscale serve)") parser.add_argument("--self-signed", action="store_true", help="Generate a self-signed TLS cert for direct HTTPS without Tailscale") args = parser.parse_args() _load_tokens() host = args.host if not host: if args.https: host = "127.0.0.1" print("Trustmux: HTTPS mode — binding to localhost (tailscale serve proxy)") else: host = _tailscale_ip() if host: print(f"Trustmux: binding to Tailscale IP {host}") else: host = "127.0.0.1" print("Trustmux: Tailscale not found, binding to localhost only") ssl_ctx = None if args.self_signed: lan_ip = host if host not in ("0.0.0.0", None) else _tailscale_ip() or "127.0.0.1" try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) lan_ip = s.getsockname()[0] s.close() except Exception: pass _, ssl_ctx = _ensure_self_signed_cert(lan_ip) scheme = "https" if (args.https or ssl_ctx) else "http" print(f"Trustmux daemon on {scheme}://{host}:{args.port} — run 'trustmux-pair' to pair a device.", flush=True) asyncio.run(_amain(host, args.port, args.https, ssl_ctx)) if __name__ == "__main__": main() byobu-7.15/mobile/trustmux/_disable.py000066400000000000000000000020401522352767600200770ustar00rootroot00000000000000"""trustmux disable — stop Trustmux daemon and remove login hook.""" import os from pathlib import Path from trustmux._ctl import cmd_stop _LOGIN_FILES = [ Path.home() / ".profile", Path.home() / ".bash_profile", Path.home() / ".bash_login", Path.home() / ".zprofile", ] def _remove_hook(dest: Path) -> None: if not dest.exists() or not os.access(dest, os.W_OK): return lines = dest.read_text().splitlines(keepends=True) filtered = [l for l in lines if "trustmux-ctl" not in l and "trustmux start 2>/dev/null" not in l] if len(filtered) < len(lines): dest.write_text("".join(filtered)) def main() -> None: for f in _LOGIN_FILES: _remove_hook(f) cmd_stop() print() print("Trustmux daemon stopped. It will no longer start automatically at login.") print() print("Paired device tokens are preserved in ~/.config/trustmux/tokens.json.") print() print("To re-enable later, run:") print(" trustmux enable") print() if __name__ == "__main__": main() byobu-7.15/mobile/trustmux/_enable.py000066400000000000000000000031071522352767600177270ustar00rootroot00000000000000"""trustmux enable — start Trustmux daemon and enable it at login.""" import os import sys from pathlib import Path from trustmux._ctl import TOKENS_FILE, cmd_setup, cmd_start _HOOK = "trustmux start 2>/dev/null || true\n" _LOGIN_FILES = [ Path.home() / ".profile", Path.home() / ".bash_profile", Path.home() / ".bash_login", ] if "zsh" in os.environ.get("SHELL", ""): _LOGIN_FILES.append(Path.home() / ".zprofile") def _install_hook(dest: Path) -> None: if not dest.exists(): return text = dest.read_text() if _HOOK in text or "trustmux-ctl" in text: return with dest.open("a") as f: f.write(f"\n{_HOOK}") def main() -> None: if cmd_setup(quiet=True) != 0: print("\nFirst-time setup did not complete. Fix the issue above, then re-run:") print(" trustmux enable") sys.exit(1) for f in _LOGIN_FILES: _install_hook(f) started = cmd_start("serve") == 0 print() if started: print("Trustmux daemon started and will launch automatically at each login.") else: print("Trustmux daemon is already running and will launch automatically at each login.") print() if not TOKENS_FILE.exists() or TOKENS_FILE.stat().st_size == 0: print("Next step — pair your phone:") print(" trustmux pair") print() print("Open the URL printed above in your phone's browser, enter the code, and tap Pair.") print() print("To stop and disable later, run:") print(" trustmux disable") print() if __name__ == "__main__": main() byobu-7.15/mobile/trustmux/_pair.py000066400000000000000000000074431522352767600174430ustar00rootroot00000000000000"""trustmux-pair — generate a one-time pairing code for a new device.""" import json import os import shutil import socket import subprocess import sys import termios import tty from pathlib import Path from trustmux._ctl import warn_if_peer_blocked SOCK = Path.home() / ".config" / "trustmux" / "trustmux.sock" def admin(cmd: dict) -> object: if not SOCK.exists(): print("Error: Trustmux daemon not running (socket not found)", file=sys.stderr) sys.exit(1) with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s: try: s.connect(str(SOCK)) except OSError as e: print(f"Error: cannot connect to Trustmux daemon: {e}", file=sys.stderr) sys.exit(1) s.sendall(json.dumps(cmd).encode() + b"\n") s.shutdown(socket.SHUT_WR) s.settimeout(10) chunks = [] try: while True: chunk = s.recv(4096) if not chunk: break chunks.append(chunk) except OSError as e: print(f"Error: timeout waiting for daemon response: {e}", file=sys.stderr) sys.exit(1) try: return json.loads(b"".join(chunks)) except json.JSONDecodeError as e: print(f"Error: malformed response from daemon: {e}", file=sys.stderr) sys.exit(1) def _ts_url() -> str: """Return the HTTPS URL from tailscale serve, or empty string if unavailable.""" try: out = subprocess.check_output( ["tailscale", "status", "--json"], stderr=subprocess.DEVNULL, timeout=5 ) d = json.loads(out) name = d.get("Self", {}).get("DNSName", "").rstrip(".") if name: return f"https://{name}/" except Exception: pass return "" def _direct_url(port: int = 7432) -> str: """Return a best-effort LAN URL when Tailscale is unavailable.""" try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) ip = s.getsockname()[0] s.close() return f"https://{ip}:{port}/" except Exception: return f"https://localhost:{port}/" def _print_qr(url: str) -> None: """Print a QR code for url using qrencode if available, else skip.""" if shutil.which("qrencode"): try: subprocess.run( ["qrencode", "-t", "ANSIUTF8", "-m", "2", url], check=True ) return except Exception: pass # qrcode Python library fallback try: import qrcode # type: ignore qr = qrcode.QRCode(border=1) qr.add_data(url) qr.make(fit=True) qr.print_ascii(invert=True) except ImportError: pass def _wait_and_clear() -> None: """Wait for a keypress, then clear the screen.""" if not sys.stdin.isatty(): return print(" [ press any key to clear ]") fd = sys.stdin.fileno() old = termios.tcgetattr(fd) try: tty.setraw(fd) sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSADRAIN, old) print("\033[2J\033[H", end="", flush=True) def main(): data = admin({"action": "pair_generate"}) if not isinstance(data, dict) or "error" in data: print(f"Error: {data.get('error', data)}", file=sys.stderr) sys.exit(1) code = data["code"] mins = data["expires_in"] // 60 url = _ts_url() or _direct_url() pair_url = f"{url}#{code.replace('-', '')}" bar = "═" * 52 print(f"\n{bar}") print(f" Trustmux pairing code: {code} (valid {mins} min)") print(f" Connect: {pair_url}") print(f"{bar}\n") warn_if_peer_blocked() _print_qr(pair_url) print() _wait_and_clear() if __name__ == "__main__": main() byobu-7.15/mobile/trustmux/_unpair.py000066400000000000000000000060411522352767600177770ustar00rootroot00000000000000"""trustmux-unpair — list and remove paired devices.""" import json import socket import sys from pathlib import Path SOCK = Path.home() / ".config" / "trustmux" / "trustmux.sock" def admin(cmd: dict) -> object: if not SOCK.exists(): print("Error: Trustmux daemon not running (socket not found)", file=sys.stderr) sys.exit(1) with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s: try: s.connect(str(SOCK)) except OSError as e: print(f"Error: cannot connect to Trustmux daemon: {e}", file=sys.stderr) sys.exit(1) s.sendall(json.dumps(cmd).encode() + b"\n") s.shutdown(socket.SHUT_WR) s.settimeout(10) chunks = [] try: while True: chunk = s.recv(4096) if not chunk: break chunks.append(chunk) except OSError as e: print(f"Error: timeout waiting for daemon response: {e}", file=sys.stderr) sys.exit(1) try: return json.loads(b"".join(chunks)) except json.JSONDecodeError as e: print(f"Error: malformed response from daemon: {e}", file=sys.stderr) sys.exit(1) def _ua_short(label: str) -> str: if not label: return "unknown" for keyword in ("Mobile", "Chrome", "Firefox", "Safari"): if keyword in label: return keyword return label[:30] def main(): sessions = admin({"action": "sessions_list"}) if not isinstance(sessions, list): print(f"Error: {sessions}", file=sys.stderr) sys.exit(1) if not sessions: print("No paired clients.") return print() print("Paired clients:") print() for i, s in enumerate(sessions, 1): ua = _ua_short(s.get("label", "")) print(f" {i}. {s['ip']:<20} {ua:<12} paired: {s['paired_at']}") print() print(" A Remove all") print(" Q Quit") print() try: choice = input(f"Select [1-{len(sessions)} / A / Q]: ").strip() except (KeyboardInterrupt, EOFError): print("\nCancelled.") return if not choice or choice.upper() == "Q": print("Cancelled.") elif choice.upper() == "A": result = admin({"action": "sessions_delete"}) if isinstance(result, dict) and result.get("ok"): print(f"Removed {result.get('removed', 0)} paired client(s).") else: print(f"Error: {result}", file=sys.stderr) sys.exit(1) elif choice.isdigit() and 1 <= int(choice) <= len(sessions): idx = int(choice) - 1 token = sessions[idx]["token_full"] ip = sessions[idx]["ip"] result = admin({"action": "sessions_delete", "token": token}) if isinstance(result, dict) and result.get("ok"): print(f"Client {ip} unpaired.") else: print(f"Error: {result}", file=sys.stderr) sys.exit(1) else: print("Invalid selection.") sys.exit(1) if __name__ == "__main__": main() byobu-7.15/mobile/trustmux/static/000077500000000000000000000000001522352767600172565ustar00rootroot00000000000000byobu-7.15/mobile/trustmux/static/app.js000066400000000000000000001174241522352767600204050ustar00rootroot00000000000000'use strict'; // ── state ────────────────────────────────────────────────────────────────── let ws = null; let sessions = []; let currentPane = null; let currentSessionId = null; let currentWindowId = null; let forcedSessionId = null; // set after creating a new session let forcedPaneId = null; // set after creating a new window (specific pane to navigate to) let _scrollTopOnNextSnapshot = false; // scroll to top instead of bottom on next snapshot let statusInterval = null; // ── pane snapshot cache (in-memory only — never persisted) ──────────────── // Stores the last-rendered HTML + scroll position for each pane so that // switching back to a pane is instant while the fresh snapshot loads. const _paneCache = new Map(); const _PANE_CACHE_MAX = 50; // ── offline / connectivity helpers ──────────────────────────────────────── let _serverVersion = null; let _offlineCountdownTimer = null; let _offlineRetryTimer = null; const OFFLINE_RETRY_SECS = 8; // auto-retry interval while offline screen is shown /** True if the current host looks like a Tailscale address. */ function isTailscaleHost() { const h = location.hostname; // Tailscale CGNAT range: 100.64.0.0/10 → 100.64.x.x – 100.127.x.x const m = h.match(/^100\.(\d+)\./); if (m && +m[1] >= 64 && +m[1] <= 127) return true; // MagicDNS: *.ts.net or *.taile*.net if (/\.ts\.net$/.test(h) || /\.taile[a-z0-9-]*\.net$/.test(h)) return true; return false; } // ── biometric lock ───────────────────────────────────────────────────────── // Uses WebAuthn platform authenticator (fingerprint/face/PIN) as an // idle/background lock — not a replacement for server-side auth. const LOCK_IDLE_MS = 5 * 60 * 1000; // lock after 5 min inactivity const LOCK_HIDDEN_MS = 30 * 1000; // lock if backgrounded > 30s let _lockEnabled = localStorage.getItem('lock-enabled'); // 'true'/'false'/null let _lockCredId = localStorage.getItem('lock-cred-id'); // base64url let _lockTimer = null; let _hiddenAt = 0; let _isLocked = false; let _skipThisSession = false; function _b64uEncode(buf) { return btoa(String.fromCharCode(...new Uint8Array(buf))) .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); } function _b64uDecode(s) { s = s.replace(/-/g, '+').replace(/_/g, '/'); const pad = s.length % 4; if (pad) s += '='.repeat(4 - pad); return Uint8Array.from(atob(s), c => c.charCodeAt(0)); } function _webauthnAvailable() { return window.isSecureContext && typeof PublicKeyCredential !== 'undefined'; } function resetLockTimer() { clearTimeout(_lockTimer); if (_lockEnabled === 'true' && _lockCredId) { _lockTimer = setTimeout(lockApp, LOCK_IDLE_MS); } } async function _registerCredential() { const cred = await navigator.credentials.create({ publicKey: { challenge: crypto.getRandomValues(new Uint8Array(32)), rp: { id: location.hostname, name: 'Trustmux' }, user: { id: crypto.getRandomValues(new Uint8Array(16)), name: 'user', displayName: 'Trustmux User', }, pubKeyCredParams: [ { type: 'public-key', alg: -7 }, { type: 'public-key', alg: -257 }, ], authenticatorSelection: { authenticatorAttachment: 'platform', userVerification: 'required', residentKey: 'discouraged', }, timeout: 60000, }, }); return _b64uEncode(cred.rawId); } async function _verifyCredential() { await navigator.credentials.get({ publicKey: { challenge: crypto.getRandomValues(new Uint8Array(32)), rpId: location.hostname, allowCredentials: [{ id: _b64uDecode(_lockCredId), type: 'public-key' }], userVerification: 'required', timeout: 60000, }, }); } function lockApp() { if (_isLocked) return; _isLocked = true; clearTimeout(_lockTimer); document.getElementById('lock-overlay').style.display = 'flex'; } function unlockApp() { _isLocked = false; document.getElementById('lock-overlay').style.display = 'none'; resetLockTimer(); } function maybeOfferBiometric() { if (!_webauthnAvailable()) return; if (_lockEnabled !== null) return; if (_skipThisSession) return; document.getElementById('bio-setup-overlay').style.display = 'flex'; } // Activity events reset the idle lock timer ['touchstart', 'keydown', 'mousedown'].forEach(ev => document.addEventListener(ev, () => { if (_lockEnabled === 'true' && !_isLocked) resetLockTimer(); }, { passive: true }) ); // Lock when app returns from background (if gone > LOCK_HIDDEN_MS) document.addEventListener('visibilitychange', () => { if (_lockEnabled !== 'true') return; if (document.hidden) { _hiddenAt = Date.now(); } else { if (_hiddenAt && Date.now() - _hiddenAt >= LOCK_HIDDEN_MS) lockApp(); _hiddenAt = 0; } }); // ── DOM refs ─────────────────────────────────────────────────────────────── const pairOverlay = document.getElementById('pair-overlay'); const pairCodeInput = document.getElementById('pair-code'); const pairBtn = document.getElementById('pair-btn'); const pairError = document.getElementById('pair-error'); const xyzLabel = document.getElementById('xyz-label'); const output = document.getElementById('output'); const statusbar = document.getElementById('statusbar'); const statusText = document.getElementById('status-text'); const cmdInput = document.getElementById('cmd'); const pwdInput = document.getElementById('pwd'); const btnSend = document.getElementById('btn-send'); const btnKbdMode = document.getElementById('btn-kbd-mode'); const machineSelect = document.getElementById('machine-select'); const btnInstall = document.getElementById('btn-install'); const iosInstallTip = document.getElementById('ios-install-tip'); const hostnameDisplay = document.getElementById('hostname-display'); function setHostnameDisplay(name) { hostnameDisplay.textContent = '🖥️ ' + name; } const headerClock = document.getElementById('header-clock'); const appVersion = document.getElementById('app-version'); const statuslineLeft = document.getElementById('statusline-left'); const statuslineRight = document.getElementById('statusline-right'); const ctxOverlay = document.getElementById('ctx-overlay'); const ctxRenameLabel = document.getElementById('ctx-rename-label'); const ctxRenameInput = document.getElementById('ctx-rename-input'); const ctxCancel = document.getElementById('ctx-cancel'); const ctxName = document.getElementById('ctx-name'); const createOverlay = document.getElementById('create-overlay'); const createMain = document.getElementById('create-main'); const createNameForm = document.getElementById('create-name-form'); const createNameLabel = document.getElementById('create-name-label'); const createNameInput = document.getElementById('create-name-input'); const btnPrev = document.getElementById('btn-prev'); const btnNext = document.getElementById('btn-next'); const btnEscape = document.getElementById('btn-escape'); const escapePopup = document.getElementById('escape-popup'); // offline overlay elements const offlineOverlay = document.getElementById('offline-overlay'); const offlineHost = document.getElementById('offline-host'); const offlineTailscaleHint = document.getElementById('offline-tailscale-hint'); const offlineRetryBtn = document.getElementById('offline-retry-btn'); const offlineCountdown = document.getElementById('offline-countdown'); function showOfflineScreen() { offlineHost.textContent = location.host; if (isTailscaleHost()) { offlineTailscaleHint.classList.add('visible'); } else { offlineTailscaleHint.classList.remove('visible'); } offlineOverlay.classList.add('visible'); _startOfflineCountdown(); } function hideOfflineScreen() { offlineOverlay.classList.remove('visible'); _clearOfflineTimers(); } function _clearOfflineTimers() { if (_offlineCountdownTimer) { clearInterval(_offlineCountdownTimer); _offlineCountdownTimer = null; } if (_offlineRetryTimer) { clearTimeout(_offlineRetryTimer); _offlineRetryTimer = null; } offlineCountdown.textContent = ''; } function _startOfflineCountdown() { _clearOfflineTimers(); let secs = OFFLINE_RETRY_SECS; offlineCountdown.textContent = `Auto-retry in ${secs}s`; _offlineCountdownTimer = setInterval(() => { secs--; if (secs > 0) { offlineCountdown.textContent = `Auto-retry in ${secs}s`; } else { clearInterval(_offlineCountdownTimer); _offlineCountdownTimer = null; offlineCountdown.textContent = 'Retrying…'; } }, 1000); _offlineRetryTimer = setTimeout(() => { offlineCountdown.textContent = 'Retrying…'; init(); }, OFFLINE_RETRY_SECS * 1000); } offlineRetryBtn.addEventListener('click', () => { offlineCountdown.textContent = 'Retrying…'; _clearOfflineTimers(); init(); }); // ── pane names (user-defined, stored in localStorage) ───────────────────── // Key is scoped to the server hostname so names don't bleed across machines. function _paneKey(paneId) { return `pane-name:${location.hostname}:${paneId}`; } function getPaneName(paneId, fallback) { return localStorage.getItem(_paneKey(paneId)) || fallback; } function setPaneName(paneId, name) { if (name) localStorage.setItem(_paneKey(paneId), name); else localStorage.removeItem(_paneKey(paneId)); } // ── last-viewed pane (persisted so reopening the PWA restores context) ──── function _lastPaneKey() { return `last-pane:${location.hostname}`; } function _saveLastPane(paneId) { localStorage.setItem(_lastPaneKey(), paneId); } function _loadLastPane() { return localStorage.getItem(_lastPaneKey()); } // ── keyboard mode per pane (persisted so context switches restore correctly) ─ function _kbdModeKey(paneId) { return `kbd-mode:${location.hostname}:${paneId}`; } function _getKbdMode(paneId) { const v = localStorage.getItem(_kbdModeKey(paneId)); return v !== null ? parseInt(v, 10) : 0; } function _saveKbdMode(paneId, mode) { localStorage.setItem(_kbdModeKey(paneId), mode); } // ── status ───────────────────────────────────────────────────────────────── function setStatus(msg, cls) { statusText.textContent = msg; statusbar.className = cls || ''; } // ── WebSocket ────────────────────────────────────────────────────────────── function connect() { const proto = location.protocol === 'https:' ? 'wss:' : 'ws:'; ws = new WebSocket(`${proto}//${location.host}/ws`); ws.onopen = () => { setStatus('connected', 'connected'); startClock(); send({ type: 'list_sessions' }); if (currentPane) send({ type: 'subscribe', pane_id: currentPane, lines: 300, ansi: true }); }; ws.onclose = (evt) => { stopClock(); if (evt.code === 4401) { showPairScreen(); return; } setStatus('disconnected — reconnecting…', 'error'); setTimeout(connect, 3000); }; ws.onerror = () => setStatus('connection error', 'error'); ws.onmessage = (evt) => { let msg; try { msg = JSON.parse(evt.data); } catch { return; } if (msg.server_ts) _serverOffset = msg.server_ts - Date.now(); if (msg.server_tz) _serverTz = msg.server_tz; if (msg.type === 'sessions') { sessions = msg.data || []; if (msg.new_session) forcedSessionId = msg.new_session; if (msg.new_pane) forcedPaneId = msg.new_pane; rebuildPaneTree(); } else if (msg.type === 'snapshot') { if (msg.pane_id === currentPane) { const forceTop = _scrollTopOnNextSnapshot; if (forceTop) _scrollTopOnNextSnapshot = false; const atBottom = output.scrollHeight - output.scrollTop <= output.clientHeight + 60; renderOutput(msg.data, !forceTop && atBottom); if (forceTop) output.scrollTop = 0; } } else if (msg.type === 'update') { if (msg.pane_id !== currentPane) return; const atBottom = output.scrollHeight - output.scrollTop <= output.clientHeight + 60; renderOutput(msg.data, atBottom); } else if (msg.type === 'error') { setStatus(`error: ${msg.message}`, 'error'); } }; } function send(obj) { if (ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(obj)); } // ── xyz label ───────────────────────────────────────────────────────────── function activePaneXYZ() { const list = flatPaneList(); if (!currentPane || list.length === 0) return '-/-'; const idx = list.findIndex(e => e.paneId === currentPane); return idx < 0 ? '-/-' : `${idx + 1}/${list.length}`; } function updateXYZLabel() { xyzLabel.textContent = activePaneXYZ(); } // ── pane navigation ─────────────────────────────────────────────────────── function rebuildPaneTree() { const forced = forcedSessionId; const forcedPane = forcedPaneId; if (forced) forcedSessionId = null; if (forcedPane) forcedPaneId = null; let autoFromForced = null; let autoFromForcedPane = null; let autoFirst = null; let prevTarget = null; let savedTarget = null; const savedPaneId = _loadLastPane(); for (const s of sessions) { for (const w of (s.windows || [])) { for (const p of (w.panes || [])) { if (!p.dead) { const entry = { sessionId: s.id, windowId: w.id, paneId: p.id }; if (forced === s.id && !autoFromForced) autoFromForced = entry; if (forcedPane === p.id) autoFromForcedPane = entry; if (!autoFirst) autoFirst = entry; if (p.id === currentPane) prevTarget = entry; if (savedPaneId && p.id === savedPaneId) savedTarget = entry; } } } } // Prefer exact forced pane (new window), then current pane, then forced session, // then last-viewed pane restored from localStorage, then first available pane. const target = autoFromForcedPane ?? prevTarget ?? autoFromForced ?? savedTarget ?? autoFirst ?? null; // Scroll to top when navigating to a freshly created window/session if (autoFromForcedPane && autoFromForcedPane !== prevTarget) _scrollTopOnNextSnapshot = true; if (!target) { currentSessionId = null; currentWindowId = null; currentPane = null; cmdInput.disabled = true; pwdInput.disabled = true; btnSend.disabled = true; updateXYZLabel(); updateContextName(); return; } if (target.paneId !== currentPane) { navigateTo(target.sessionId, target.windowId, target.paneId); } else { updateXYZLabel(); updateContextName(); } } function navigateTo(sessionId, windowId, paneId) { // Save departing pane's rendered content + scroll position + keyboard mode. if (currentPane && output.innerHTML) { _paneCache.set(currentPane, { html: output.innerHTML, scrollTop: output.scrollTop }); if (_paneCache.size > _PANE_CACHE_MAX) _paneCache.delete(_paneCache.keys().next().value); } if (currentPane) _saveKbdMode(currentPane, kbdMode); currentSessionId = sessionId; currentWindowId = windowId; currentPane = paneId; _saveLastPane(paneId); // Restore keyboard mode for the arriving pane. kbdMode = _getKbdMode(paneId); applyKbdMode(); cmdInput.disabled = false; pwdInput.disabled = false; btnSend.disabled = false; output.className = ''; const cached = _paneCache.get(paneId); if (cached) { output.innerHTML = cached.html; output.scrollTop = cached.scrollTop; } else { output.textContent = 'loading…'; } send({ type: 'subscribe', pane_id: paneId, lines: 300, ansi: true }); updateXYZLabel(); updateContextName(); } // ── context name (custom label or command fallback) ─────────────────────── function updateContextName() { if (!currentPane) { ctxName.textContent = ''; return; } const custom = getPaneName(currentPane, ''); ctxName.textContent = '🪟 ' + (custom || currentPaneCommand() || 'shell'); } // ── output rendering ─────────────────────────────────────────────────────── function scrollOutputToBottom() { requestAnimationFrame(() => { output.scrollTop = output.scrollHeight; }); } // Convert ANSI SGR escape codes to HTML spans. // Handles: 16/256/truecolor fg+bg, bold, italic, underline. Other sequences discarded. function ansiToHtml(text) { const C16 = [ '#1e1e1e','#cc0000','#4e9a06','#c4a000','#3465a4','#75507b','#06989a','#d3d7cf', '#555753','#ef2929','#8ae234','#fce94f','#729fcf','#ad7fa8','#34e2e2','#eeeeec', ]; function c256(n) { if (n < 16) return C16[n]; if (n < 232) { const i = n - 16, lv = [0, 95, 135, 175, 215, 255]; return `rgb(${lv[~~(i/36)]},${lv[~~((i%36)/6)]},${lv[i%6]})`; } const v = 8 + (n - 232) * 10; return `rgb(${v},${v},${v})`; } function _rgb(r, g, b) { const ok = v => Number.isInteger(v) && v >= 0 && v <= 255; return (ok(r) && ok(g) && ok(b)) ? `rgb(${r},${g},${b})` : null; } let fg = null, bg = null, bold = false, italic = false, ul = false; let spanCss = null, out = ''; function css() { const p = []; if (fg) p.push(`color:${fg}`); if (bg) p.push(`background:${bg}`); if (bold) p.push('font-weight:bold'); if (italic) p.push('font-style:italic'); if (ul) p.push('text-decoration:underline'); return p.join(';'); } function emit(s) { if (!s) return; const c = css(); if (c !== spanCss) { if (spanCss !== null) out += ''; if (c) out += ``; spanCss = c || null; } out += s.replace(/&/g, '&').replace(//g, '>'); } function sgr(ps) { let i = 0; while (i < ps.length) { const p = ps[i]; if (!p) { fg = bg = null; bold = italic = ul = false; } else if (p === 1) bold = true; else if (p === 3) italic = true; else if (p === 4) ul = true; else if (p === 22) bold = false; else if (p === 23) italic = false; else if (p === 24) ul = false; else if (p >= 30 && p <= 37) fg = C16[p - 30]; else if (p === 38 && ps[i+1] === 5) { fg = c256(ps[i+2]); i += 2; } else if (p === 38 && ps[i+1] === 2) { fg = _rgb(ps[i+2],ps[i+3],ps[i+4]); i += 4; } else if (p === 39) fg = null; else if (p >= 40 && p <= 47) bg = C16[p - 40]; else if (p === 48 && ps[i+1] === 5) { bg = c256(ps[i+2]); i += 2; } else if (p === 48 && ps[i+1] === 2) { bg = _rgb(ps[i+2],ps[i+3],ps[i+4]); i += 4; } else if (p === 49) bg = null; else if (p >= 90 && p <= 97) fg = C16[p - 82]; else if (p >= 100 && p <= 107) bg = C16[p - 92]; i++; } } const TOK = /([^\x1b]+)|\x1b(?:\[([0-9;]*)([A-Za-z])|\][^\x07\x1b]*(?:\x07|\x1b\\)|(.))/g; for (const m of text.matchAll(TOK)) { if (m[1]) emit(m[1]); else if (m[3] === 'm') sgr(m[2] ? m[2].split(';').map(Number) : [0]); } if (spanCss !== null) out += ''; return out; } function renderOutput(text, scrollToBottom) { output.className = ''; output.innerHTML = ansiToHtml(text); if (scrollToBottom) scrollOutputToBottom(); } // ── send keys ───────────────────────────────────────────────────────────── function activeInput() { return kbdMode === 2 ? pwdInput : cmdInput; } function sendKeys() { const inp = activeInput(); const keys = inp.value; if (!keys || !currentPane) return; send({ type: 'send_keys', pane_id: currentPane, keys, enter: true }); inp.value = ''; if (inp === cmdInput) { cmdInput.style.height = 'auto'; } } // ── events ───────────────────────────────────────────────────────────────── xyzLabel.addEventListener('click', () => send({ type: 'list_sessions' })); cmdInput.addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendKeys(); } }); cmdInput.addEventListener('input', () => { cmdInput.style.height = 'auto'; cmdInput.style.height = Math.min(cmdInput.scrollHeight, 160) + 'px'; }); pwdInput.addEventListener('keydown', e => { if (e.key === 'Enter') { e.preventDefault(); sendKeys(); } }); btnSend.addEventListener('click', sendKeys); // ── keyboard mode toggle ($_ / Aa / **) ─────────────────────────────────── // 0 = terminal ($_) no spell-check, no autocorrect // 1 = text (Aa) spell-check + autocorrect on // 2 = password (**) type="password" input — keyboard does not learn text let kbdMode = 0; function applyKbdMode() { const inPwd = kbdMode === 2; cmdInput.style.display = inPwd ? 'none' : ''; pwdInput.style.display = inPwd ? 'block' : 'none'; if (kbdMode === 1) { cmdInput.setAttribute('spellcheck', 'true'); cmdInput.setAttribute('autocorrect', 'on'); cmdInput.setAttribute('autocapitalize', 'sentences'); output.style.whiteSpace = 'pre-wrap'; btnKbdMode.textContent = 'Aa'; btnKbdMode.title = 'Text mode — tap for terminal mode'; btnKbdMode.style.color = 'var(--accent)'; } else if (kbdMode === 0) { cmdInput.setAttribute('spellcheck', 'false'); cmdInput.setAttribute('autocorrect', 'off'); cmdInput.setAttribute('autocapitalize', 'none'); output.style.whiteSpace = 'pre'; btnKbdMode.textContent = '$_'; btnKbdMode.title = 'Terminal mode — tap to enable spell check'; btnKbdMode.style.color = ''; } else { output.style.whiteSpace = 'pre'; btnKbdMode.textContent = '**'; btnKbdMode.title = 'Password mode — keyboard will not learn this text'; btnKbdMode.style.color = 'var(--accent)'; } scrollOutputToBottom(); } btnKbdMode.addEventListener('click', () => { kbdMode = (kbdMode + 1) % 3; if (currentPane) _saveKbdMode(currentPane, kbdMode); applyKbdMode(); // blur + refocus so Android keyboard re-evaluates input type/spellcheck const inp = activeInput(); inp.blur(); setTimeout(() => inp.focus(), 50); }); // ── escape / ctrl-c popup ───────────────────────────────────────────────── function showEscapePopup() { const rect = btnEscape.getBoundingClientRect(); escapePopup.style.display = 'flex'; escapePopup.style.right = (window.innerWidth - rect.right) + 'px'; escapePopup.style.bottom = (window.innerHeight - rect.top + 8) + 'px'; } function hideEscapePopup() { escapePopup.style.display = 'none'; } btnEscape.addEventListener('click', e => { e.stopPropagation(); escapePopup.style.display === 'none' ? showEscapePopup() : hideEscapePopup(); }); document.getElementById('escape-popup-esc').addEventListener('click', () => { if (currentPane) send({ type: 'send_keys', pane_id: currentPane, keys: 'Escape', enter: false, literal: false }); hideEscapePopup(); }); document.getElementById('escape-popup-ctrlc').addEventListener('click', () => { if (currentPane) send({ type: 'send_keys', pane_id: currentPane, keys: 'C-c', enter: false, literal: false }); hideEscapePopup(); }); document.addEventListener('click', () => hideEscapePopup()); document.addEventListener('touchstart', e => { if (!escapePopup.contains(e.target) && e.target !== btnEscape) hideEscapePopup(); }, { passive: true }); // ── pane list — all live panes across all windows and sessions ──────────── // Deduplicated by pane ID: byobu exposes the same windows/panes under multiple // sessions (linked windows / multi-client attach), so skip any already seen. function flatPaneList() { const list = []; const seen = new Set(); for (const s of sessions) { for (const w of (s.windows || [])) { for (const p of (w.panes || [])) { if (!p.dead && !seen.has(p.id)) { seen.add(p.id); list.push({ sessionId: s.id, windowId: w.id, paneId: p.id }); } } } } return list; } function navigateRelative(delta) { const list = flatPaneList(); if (list.length < 2) return; const idx = list.findIndex(e => e.paneId === currentPane); const next = list[((idx < 0 ? 0 : idx) + delta + list.length) % list.length]; navigateTo(next.sessionId, next.windowId, next.paneId); } // ── touch swipe tracking (used for swipe nav) ───────────────────────────── let _touchX = 0, _touchY = 0; output.addEventListener('touchstart', e => { _touchX = e.touches[0].clientX; _touchY = e.touches[0].clientY; }, { passive: true }); btnPrev.addEventListener('click', () => navigateRelative(-1)); btnNext.addEventListener('click', () => navigateRelative(1)); document.getElementById('btn-create').addEventListener('click', showCreateOverlay); // ── rename overlay (tap name label in header) ───────────────────────────── let _pendingRenameId = null; function currentPaneCommand() { if (!currentPane) return ''; for (const s of sessions) { for (const w of (s.windows || [])) { for (const p of (w.panes || [])) { if (p.id === currentPane) return p.command || ''; } } } return ''; } function showRenameOverlay() { if (!currentPane) return; _pendingRenameId = currentPane; const custom = getPaneName(currentPane, ''); const cmd = currentPaneCommand(); ctxRenameLabel.textContent = custom ? `Rename "${custom}":` : `Name this context (${cmd || 'shell'}):`; ctxRenameInput.value = custom; ctxOverlay.style.display = 'flex'; setTimeout(() => { ctxRenameInput.focus(); ctxRenameInput.select(); }, 80); } function hideRenameOverlay() { ctxOverlay.style.display = 'none'; _pendingRenameId = null; } ctxName.addEventListener('click', showRenameOverlay); ctxCancel.addEventListener('click', hideRenameOverlay); ctxOverlay.addEventListener('click', e => { if (e.target === ctxOverlay) hideRenameOverlay(); }); function submitRename() { if (!_pendingRenameId) return; const name = ctxRenameInput.value.trim(); setPaneName(_pendingRenameId, name); hideRenameOverlay(); updateContextName(); } document.getElementById('ctx-rename-confirm').addEventListener('click', submitRename); ctxRenameInput.addEventListener('keydown', e => { if (e.key === 'Enter') submitRename(); }); // ── create overlay (+ button) ───────────────────────────────────────────── let _createType = null; // 'pane' | 'window' | 'session' function showCreateOverlay() { createMain.style.display = ''; createNameForm.style.display = 'none'; createNameInput.value = ''; createOverlay.style.display = 'flex'; } function hideCreateOverlay() { createOverlay.style.display = 'none'; _createType = null; } function showCreateNameForm(type) { _createType = type; createNameLabel.textContent = type === 'session' ? 'New session name:' : `New ${type} name (optional):`; createNameInput.placeholder = type === 'session' ? 'e.g. work' : 'optional'; createMain.style.display = 'none'; createNameForm.style.display = ''; setTimeout(() => createNameInput.focus(), 80); } createOverlay.addEventListener('click', e => { if (e.target === createOverlay) hideCreateOverlay(); }); document.getElementById('create-cancel').addEventListener('click', hideCreateOverlay); document.getElementById('create-name-back').addEventListener('click', () => { createNameForm.style.display = 'none'; createMain.style.display = ''; _createType = null; }); document.getElementById('create-pane').addEventListener('click', () => { if (currentWindowId) send({ type: 'new_pane', window_id: currentWindowId }); hideCreateOverlay(); }); document.getElementById('create-window').addEventListener('click', () => showCreateNameForm('window')); document.getElementById('create-session').addEventListener('click', () => showCreateNameForm('session')); function submitCreate() { const name = createNameInput.value.trim(); if (_createType === 'session') { if (!name) { createNameInput.focus(); return; } send({ type: 'new_session', name }); } else if (_createType === 'window') { if (currentSessionId) send({ type: 'new_window', session_id: currentSessionId, name }); } hideCreateOverlay(); } document.getElementById('create-name-confirm').addEventListener('click', submitCreate); createNameInput.addEventListener('keydown', e => { if (e.key === 'Enter') submitCreate(); }); // ── status bar clock (only ticks when connected — frozen clock = disconnected) ─ let _clockInterval = null; let _serverOffset = 0; // ms: server clock minus browser clock let _serverTz = 'UTC'; // IANA timezone of the host machine function startClock() { if (_clockInterval) return; function tick() { const now = new Date(Date.now() + _serverOffset); const opts = { timeZone: _serverTz }; const date = new Intl.DateTimeFormat('en-US', {...opts, month:'short', day:'numeric'}).format(now); const time = new Intl.DateTimeFormat('en-US', {...opts, hour:'2-digit', minute:'2-digit', second:'2-digit', hour12:false}).format(now); headerClock.textContent = `${date} ${time}`; } tick(); _clockInterval = setInterval(tick, 1000); } function stopClock() { if (_clockInterval) { clearInterval(_clockInterval); _clockInterval = null; } } // ── byobu status line ───────────────────────────────────────────────────── function makeChip(c) { const el = document.createElement('span'); el.className = 'chip'; el.textContent = c.text; el.title = c.label; el.style.background = c.bg; el.style.color = c.color; return el; } async function fetchByobuStatus() { try { const data = await fetch('/status').then(r => r.json()); const left = data.left || []; const right = data.right || []; statuslineLeft.innerHTML = ''; statuslineRight.innerHTML = ''; left.forEach(c => statuslineLeft.appendChild(makeChip(c))); right.forEach(c => statuslineRight.appendChild(makeChip(c))); } catch { /* byobu not running */ } } function startStatusPolling() { if (!statusInterval) { fetchByobuStatus(); statusInterval = setInterval(fetchByobuStatus, 10000); } } // ── pairing screen ───────────────────────────────────────────────────────── function showPairScreen() { pairOverlay.style.display = 'flex'; pairCodeInput.value = ''; pairError.textContent = ''; if (statusInterval) { clearInterval(statusInterval); statusInterval = null; } const autoCode = (window.location.hash.slice(1) || '').replace(/\D/g, '').slice(0, 6); if (autoCode && /^\d{6}$/.test(autoCode)) { pairCodeInput.value = `${autoCode.slice(0,3)}-${autoCode.slice(3)}`; setTimeout(submitPair, 400); } else { setTimeout(() => pairCodeInput.focus(), 80); } } function hidePairScreen() { pairOverlay.style.display = 'none'; if (window.location.hash) { history.replaceState(null, '', window.location.pathname + window.location.search); } } pairCodeInput.addEventListener('input', () => { let digits = pairCodeInput.value.replace(/\D/g, '').slice(0, 6); pairCodeInput.value = digits.length > 3 ? `${digits.slice(0,3)}-${digits.slice(3)}` : digits; }); pairCodeInput.addEventListener('keydown', e => { if (e.key === 'Enter') submitPair(); }); pairBtn.addEventListener('click', submitPair); async function submitPair() { const code = pairCodeInput.value; if (!code) return; pairBtn.disabled = true; pairError.textContent = ''; try { const r = await fetch('/pair', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ code }), }); const data = await r.json(); if (r.ok) { hidePairScreen(); applyHostname(); connect(); startStatusPolling(); maybeOfferBiometric(); resetLockTimer(); } else { pairError.textContent = data.error ?? 'Pairing failed.'; pairCodeInput.value = ''; pairCodeInput.focus(); } } catch { pairError.textContent = 'Network error — is the daemon running?'; } finally { pairBtn.disabled = false; } } // ── PWA install prompt ──────────────────────────────────────────────────── const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent); const isStandalone = window.matchMedia('(display-mode: standalone)').matches || navigator.standalone === true; let deferredInstallPrompt = null; // Show install button OR context name in the center slot — never both. function _syncCenterSlot() { const showInstall = btnInstall.style.display !== 'none'; ctxName.style.display = showInstall ? 'none' : ''; } if (!isStandalone) { if (isIOS) { // iOS Safari: no beforeinstallprompt — show button that explains manual steps. btnInstall.style.display = ''; _syncCenterSlot(); btnInstall.addEventListener('click', () => { iosInstallTip.style.display = ''; }); document.getElementById('close-tip').addEventListener('click', () => { iosInstallTip.style.display = 'none'; }); } else { // Android/Chrome: capture the prompt and fire it on button click. window.addEventListener('beforeinstallprompt', e => { e.preventDefault(); deferredInstallPrompt = e; btnInstall.style.display = ''; _syncCenterSlot(); }); btnInstall.addEventListener('click', async () => { if (!deferredInstallPrompt) return; deferredInstallPrompt.prompt(); const { outcome } = await deferredInstallPrompt.userChoice; deferredInstallPrompt = null; btnInstall.style.display = 'none'; _syncCenterSlot(); }); window.addEventListener('appinstalled', () => { btnInstall.style.display = 'none'; deferredInstallPrompt = null; _syncCenterSlot(); }); } } // ── machine selector ────────────────────────────────────────────────────── async function loadMachines() { try { const machines = await fetch('/machines').then(r => r.json()); if (!Array.isArray(machines) || machines.length < 2) return; machineSelect.innerHTML = ''; machines.forEach(m => { const o = document.createElement('option'); o.value = m.url; o.textContent = m.current ? m.name + ' ✓' : m.name; if (m.current) o.selected = true; machineSelect.appendChild(o); }); machineSelect.style.display = ''; } catch { /* /machines not configured — selector stays hidden */ } } machineSelect.addEventListener('change', () => { const url = machineSelect.value; if (url && /^https?:\/\//.test(url)) window.location.href = url; }); let _swRegistration = null; appVersion.addEventListener('click', async () => { if (_swRegistration) await _swRegistration.update().catch(() => {}); location.reload(); }); function applyVersion(v) { if (!v) return; const isUpdate = _serverVersion && v !== _serverVersion; appVersion.textContent = isUpdate ? 'v' + v + ' ⟳' : 'v' + v; appVersion.title = isUpdate ? 'Server updated — tap to reload' : 'Tap to reload / check for updates'; appVersion.classList.toggle('update-available', !!isUpdate); if (!isUpdate) _serverVersion = v; } async function applyHostname() { try { const data = await fetch('/ping').then(r => r.json()); if (data.hostname) setHostnameDisplay(data.hostname); if (data.version) applyVersion(data.version); } catch { /* ignore */ } } // ── biometric button wiring ─────────────────────────────────────────────── document.getElementById('bio-enable-btn').addEventListener('click', async () => { const btn = document.getElementById('bio-enable-btn'); btn.disabled = true; try { const credId = await _registerCredential(); _lockCredId = credId; _lockEnabled = 'true'; localStorage.setItem('lock-enabled', 'true'); localStorage.setItem('lock-cred-id', credId); document.getElementById('bio-setup-overlay').style.display = 'none'; resetLockTimer(); } catch { btn.disabled = false; } }); document.getElementById('bio-skip-btn').addEventListener('click', () => { _skipThisSession = true; document.getElementById('bio-setup-overlay').style.display = 'none'; }); document.getElementById('bio-never-btn').addEventListener('click', () => { _lockEnabled = 'false'; localStorage.setItem('lock-enabled', 'false'); document.getElementById('bio-setup-overlay').style.display = 'none'; }); document.getElementById('lock-unlock-btn').addEventListener('click', async () => { const btn = document.getElementById('lock-unlock-btn'); btn.disabled = true; try { await _verifyCredential(); unlockApp(); } catch { // stay locked — user dismissed or biometric failed } finally { btn.disabled = false; } }); // ── keyboard-aware viewport (visualViewport) ─────────────────────────────── // iOS/Android don't resize the layout viewport when the on-screen keyboard // opens — they resize the *visual* viewport and, on iOS Safari, also scroll // the page to bring the focused input into view. #app's `position:fixed; // inset:0` is pinned to the layout viewport, so it drifts out of sync: the // header scrolls off the top and dead space appears at the bottom. Re-pin // #app to the current visual viewport on every change (keyboard open/close, // resize, orientation) and cancel any page-level scroll iOS applies. const appEl = document.getElementById('app'); function syncViewportToKeyboard() { const vv = window.visualViewport; if (!vv) return; appEl.style.height = vv.height + 'px'; appEl.style.top = vv.offsetTop + 'px'; window.scrollTo(0, 0); } if (window.visualViewport) { window.visualViewport.addEventListener('resize', syncViewportToKeyboard); window.visualViewport.addEventListener('scroll', syncViewportToKeyboard); syncViewportToKeyboard(); } // ── init: check auth, then connect or show pair screen ──────────────────── async function init() { setStatus('connecting…', 'connecting'); try { const r = await fetch('/ping'); const data = await r.json(); if (r.ok) { if (data.hostname) setHostnameDisplay(data.hostname); if (data.version) applyVersion(data.version); hideOfflineScreen(); hidePairScreen(); connect(); startStatusPolling(); loadMachines(); if (_lockEnabled === 'true' && _lockCredId) { lockApp(); } else { maybeOfferBiometric(); resetLockTimer(); } } else { hideOfflineScreen(); showPairScreen(); } } catch { showOfflineScreen(); } } init(); if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js').then(r => { _swRegistration = r; }); } byobu-7.15/mobile/trustmux/static/icons/000077500000000000000000000000001522352767600203715ustar00rootroot00000000000000byobu-7.15/mobile/trustmux/static/icons/icon-192.png000066400000000000000000000077661522352767600223600ustar00rootroot00000000000000PNG  IHDRRlIDATx{Tǿw;;]vJvڪhBVZ+bښUijI}4M"iiѢ}hLkUDLDb@WQc[\a;sǼcfvg${g9s9        As:r޾YiRI~MeͲ]K߮eޡʹovM_}Ygb3Vf9}nػ!6-wgzN/B훍r爭8k̚ Kw`4şږ5Eo>34[i:&kT:A| 9< WiU?u$Z"TV:t{L@sA(ꑕM2 . m"H?9+V~ѡ+M@ oK:ϭ/sLPxxHf `݀Rb|~kfVh mnV[)DiO~,ʈ+'-t#Sc>4 ;A()S!ݾf,Х$&É#aԏ=7 ̝D9Ne"r4>( &~7x9~>GG(TV[+reGUpCHy%-S (%=O %:LPUF7u*]{J*62K)~sW"2b&/q}e}܄b!T :T&؄Y cLpWuBݐ3ߋOVT{N}$*H*Qc{Q(R{f.t xe\Of\NAr! r*ٟWPƟJ( i J(ҕ~|H[Q E?ɍ ?Yi E(~0|Z>*= 2{Γe ;Yi E)~1 ,,d z R{{>q@I_Nf4EvP(!?D$#~Yo&~IX'N (~<%r(&oJkZ,2ݫ)ӿ/#Bs$|TRcbt 6Zl ^<͂g[O(~IX/oxF`8d8* ϸ2۬A@6@?q@}VdMJ_T#Ɉ^|b"ڄ:{N{=wsm{eS 3U.ԡ sظF5bܶ}]PNֿ{8q !jpD%ҡşxK:0p$#8o_Hb.BduҮw Bl 8;^dE:>qʧ!r@o*~ dMK"g؄%'7 5[VEDe46^vN7?u[lкA`LjYc8{Kܐ`44 !Fi^ߞ<@ %ěwtu@κC!?df23Um~T0jK5| ` Vj#p񆚼{YfE~A(~ /HJef2!?aPy}:+aTo5DH_S{%T 2PZzRn aN.ȝkًbf e 3)Rze |>{n |Z,n #%Qx [O/({׎o[fF߄-G供?BQ!$pY6W}Ih} s![~AD;#0`33q*5? vJE8R~gMyVd(к-(y_*DB供2Rd`R[?DÂ~eh}ђC3 '|q}1PJ$_!*P8ZO?F=4~m)j~mO!]=lÐ`ʞ6}~na6D~v=c W¹zu[_ɢak qe^?#.#׬G7Bi-N?!R Z<ى_=[Hw\8BQ2ENO4H=PSyCBC1:Aa1 3xX:I}Y FBv?0s}?>1E|tV' vG~Iڲ/U{yPe!¸2p47pDg^,m17#69'} U&~Iq> f/m~zC0Q*\rC;#R(~_߇u|]ܴvq|],oWuaD眏[Dl¸nQݏQ\*U&- 0oFaKCk T~ W'pKЎE~㈆O??BЯ]_\ڃK$qB?j2?Ѕڟ<-*Cyя-U@*/z} .E Jz*Q h^9\RY`7+l;2.y˫;YB7p7m۷i<&C2_"-h.kYBnDٍPua ӎ&bpi2Pua:G`g@) `A|}ߏ]X)k_.K #yAT0NO&)wdXGgF,F9dPNTpB鐊`k&WX[x0r7O;p0W2H [l( y#"@<;_NmoYh,d`|. R=B Ϩ xZ2l46LEUI %bdȈ;mo DQ=qJ(Vd`en7 F ),iy23p@m@Z%@zFЋ_K RxP<if2aP/*~"~CZd} ̄BQ9~&r![祥@4Y5P@9Y ",T{>l`=*z8e4% q}@fzf.t{6}BH3;WЋ_  23B@:)~, ,,HĕRȒHoA*~1X\B.v2ߓ 3A%P(DTc'ذ~T8OnT7 _v*&ږ߽* P@O9UY Ea{ RqܾLKQ݋f;P,m6Ŀf4d&@)FR.y+ 4mw:4G:2tkG; &|d|Ѧ/4rlbK J dNq\>rf*U:edc@m?b? yG># 'r_3Q 2eb@_ 2ĿtMvYѴ/:2.30K̠jdоB.4@$I .J3Lmג5?s4v17ִ-gs]HҲlV鶙gؗXu:>@6-ͱ ŵiX"qb[1xKi_{@?bAAAAAAAAbOi,IENDB`byobu-7.15/mobile/trustmux/static/icons/icon-512.png000066400000000000000000000252441522352767600223430ustar00rootroot00000000000000PNG  IHDRx*kIDATx{\uTuW_tBHnN Qr3; }tg]uefGa& $\I$@H:K/UTSyC_Wթ{NUu@{p_s+C k baKfECj^.gb?9.X``Gxm WL@D,I 4~z z~G`Y{,# 8w]0dzvl^H~KI"1|Mr +8`Qpbn+b/Q9Z1ÌQG,"Vnx, <`IW.DюͫgC)90wYT?wqǵ0XDHml+[E@m;Zkp[2i E]q9"u (G6M_e?l`0# 1(u~y8Rm5?Ob0G.`0 J{RVͩ|!`PƑ?_"a@Jb?do&%8zđ?wŊ(2 @KTI)D W!Α?;IK9X{ H !<`<[ÑMuO0"2b= jşCG4po$.n;i { ^@wAq |g/gٱeJPb@K `&o4B-5ʈ??~".`P=/[AEVԉ?'eg,oƟ!A 67 ?"D?; f 43xDDB&F-P!o #I *? f1XA`o67qϛ0h"o gp C= ğǟC- ?~#1 FcPB@,+?, |5%rM4?^aM* Je\)/+y:Gz$5-v޼I{Wro;$a}Cr .{/y 8/H=%Rzb)-=H=Ȧ4G*ͩ߃Aɯ,mk7IM:i[H' j4EBH#O#$R> )zО Zi_=^bYe}@C;8R;x |R^6_{55]R:v]"""A,O,K+c: q;Dv]qTX6)?D6HCIg%~ *OJC2yA elL/z`1g `sO:Bz O^ V 0X]Qϧj/@s=~2x+*$~%??5,+| Ki d g+2JgNV1h@+ ]_Ӥx¡RӤ}nJʽ]}u2x'z^Qϐ@g) m픮O|RJUR2uYpF~*44EFw%XN|I)y)Nv]vSF1hOUN|+O7TJJɮ/m7@O Ci{aCLQ^j/{ r9""93^7(`)mP@M 155 S:^:{=9vYs8`GŽWo:(ai$#|EޭxE=,o_DRM~my/2o2/"^Eo@y b<ķ %qc#xɽ#m޷_ 8@Aw -i[ O]j 4ĉ8tq6t"uiuwۓgw^Km}T/X51nEDڞ[.=KzPSR>㚏q;"" [$voߣxoHgN# ?0HJge6=gJ˥s{-:kWHTPx`UCO=L|--,0a52&vKvoguC j[0oI~kZiF#'eQ:h,UT?sTgL^Ă@*fKel)|?I5R3Rxy v p w/" J ?]_Rb uK#RE (?"߼ RM 0Dw#2x R>xRӞI$utt}+BE22[G>!ժNOm?]|S8`-aLh/#1N4v2xq|@P@qJHT8cȎkʁCmcP]^FJG.?OzR3} JaSǭ_j/#q.Blꈿd5úoS|f Je$ɱk6,Pu\?%aR7x[ʋmQ?+=ڢC?5?]r |D?iHn;}Ϳi/YA#K_)3qwD ?u Z3Z˯Uh/'1q8[{- BO//;"&%ꐝ}H.{%P7XZZS<}R!Ao Dr7l^F]yJZ`o_~i{".?e P9'ZMğgp@7!utsHOs)R>|Aj,"61h?D5k]2{7˴o _@T:ba?HIb'$-WLKZgK秲]o"oW7K׏MeC@>%߾ܛnuC/@v^ulkR\~Sgķ{W~@s8`7J~/H%,i/kB , ˿zL#&q?Re\O;w]DZ=/|H۪W&`73d)#=2p)2KǤWOho_ ޶4eY(@J-qK%OKJoW̩\J/MeAo3 ?dDvwljiEi{Ui{iH,HoYNN{~*0;@ &*:ei{qnJ[$m z%||)sO9Z))^70( mR>bX4MU! ,*פ5-IgR׏~@7*˯KUtS,"~ CݛEUz9wm"pmi{A}KHN~&۟h/ü7|c:mF= VLvw2kߗ`AF, )eWn+q#V.y ڈ*UH/j'<@S3 $(ʴ(^L:uH`B{W[iY8z,~[4ĉ;I]lH 폿(=vޠ/XE֯3o_/""ŲyR <)fIcp%.(J wH/z4vZ,~o^mOwK?-H񔣥(k&' pJvm}G{5^cͅlW6J.säÇ>/ȳQt^ɿ{d+^6EYXuoH~{%%H%R:fT/zd~)tmyG{9y>%YXAo|z[iR^6_Hy|,'93Z:Œ=Nڞ\#h@Age] {-ʂRY0Ws~3ꑰ[©]NTB0P`[۰YnoHۚDJ4~< ;"=t:ۗ% }G7(m/OxG+;8%_HhuƉ0hb( ^'8kp䟆 U[ ZIyoKb'IW0Z{0X4b'a爃6!5A*Ko8Bc'#ogWTo0D)W  )6og'.֋[] :b+H@Og3} J x`w/Gv7L HC=| e3F?x[`o1_U ~!1A[`eAQE"n`P+$| *` 1Ͼ<`DG1 Ȳp_1*XNy2I8[` ; 0XRs'fpX Y4 ?D?OaF;@1-QN @{L EmE^Mϫp@GEmcPCw{Qm;whxg>o gDp@*I8[`; E?o`͘{ ,v#f6@+Ɵ8 8o67q N5 ? 0h!2!NI8@O- J?_70( 2"^g ZtoG7@?Z<ϑ?D+f1 (, C873:D?4E$\A%fg Xtc5u.86o NǟKM n ԋiZ W0(4G=`Dϼl:5 D>]L".bPFx;@sF Zy||?D?ȟS)0`Y4~Mi5͢+W?ѿ VՉ@K3ĥ-<`so[;{D0'bso 51/ȬV,OsE`~6[<|ϑӘƌ>M;_Z񑴖:Ɵ{x :.E{.c/0Ag]_jkxnZ|ʦѿM =gh c Gk4`s͞uCdM&C@z8ڴ%=uïaLdѿm8-ƻߘo%\qrkʲs߭L`/k/+g[wޢ̾o?\ f_ Ɵ`pߣ"r I"O}~&G08b3×} *{x&n#Íj4ԛ~85e /y_p1{&g&((}٭l@387gOEqQ腁/"ﵜ haxs&ـp6usF_ 2?J(2eRj>&7+DDde'5, /BQ7Gd݄o60 HqczdG_n-߮\hqzjxhEosWGD蟧 r jwݗ4ZrYs6nk^zsI6|x^G;Ă;/=?+K nA{{Wv0?;3f @coJ_Ҏşg7xF-e]͇o_{{Wv(?3n-k 3_}Ŀ* ""G W_oj{S#,y}dpĿֈKչls';p IkmGTF?G#Aٞa7&5Ru.8DqpgmpE\7M?dXAun}IENDB`byobu-7.15/mobile/trustmux/static/index.html000066400000000000000000000534251522352767600212640ustar00rootroot00000000000000 Trustmux

Trustmux

⚠ Can't reach server

The server is not responding.
Check that the daemon is running.

Tailscale not connected?
This address is on your Tailnet.
Open the Tailscale app and connect,
then tap Retry.

connecting…
Select a pane above.
byobu-7.15/mobile/trustmux/static/sw.js000066400000000000000000000027271522352767600202550ustar00rootroot00000000000000'use strict'; const CACHE = 'trustmux-v7'; // Only truly static assets are cached — icons and logo never change between // releases and are safe to serve from cache indefinitely. // index.html and app.js are intentionally excluded: they change with every // release and must always be fetched fresh so updates are visible immediately // without any cache-busting dance. The server is always local/Tailscale, so // there is no latency cost to fetching them from the network. const SHELL = ['/trustmux.svg', '/icons/icon-192.png?v=3', '/icons/icon-512.png?v=3']; // These are always fetched from the network — never cache. const NETWORK_ONLY = ['/ws', '/pair', '/ping', '/status', '/machines', '/', '/app.js', '/manifest.json']; self.addEventListener('install', e => { e.waitUntil( caches.open(CACHE).then(c => c.addAll(SHELL)) ); self.skipWaiting(); }); self.addEventListener('activate', e => { e.waitUntil( caches.keys().then(keys => Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k))) ) ); self.clients.claim(); }); self.addEventListener('fetch', e => { const url = new URL(e.request.url); // Pass API endpoints, main HTML, and JS straight to the network. if (NETWORK_ONLY.some(p => url.pathname === p || url.pathname.startsWith(p))) return; // Cache-first only for the truly static assets listed in SHELL. e.respondWith( caches.match(e.request).then(cached => cached || fetch(e.request)) ); }); byobu-7.15/mobile/trustmux/static/trustmux-logo.svg000066400000000000000000000031231522352767600226470ustar00rootroot00000000000000 $ trustmux byobu-7.15/mobile/trustmux/static/trustmux.svg000066400000000000000000000026661522352767600217240ustar00rootroot00000000000000 $ byobu-7.15/mobile/trustmuxd.in000066400000000000000000000007471522352767600164730ustar00rootroot00000000000000#!/usr/bin/env python3 """trustmuxd — Trustmux daemon.""" import sys import os # When run from the dev tree, the package is in a sibling trustmux/ dir. # When installed by autotools, fall back to the configure-time trustmuxpydir. _here = os.path.dirname(os.path.abspath(__file__)) if os.path.isdir(os.path.join(_here, "trustmux")): sys.path.insert(0, _here) else: sys.path.insert(0, "@trustmuxpydir@") from trustmux._daemon import main if __name__ == "__main__": main() byobu-7.15/mobile/uv.lock000066400000000000000000000066661522352767600153760ustar00rootroot00000000000000version = 1 revision = 3 requires-python = ">=3.9" [[package]] name = "tornado" version = "6.5.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/50/57/6d7303a77ae439d9189108f76c0c4fd89ee5e2cc8387bffb55232565c4ed/tornado-6.5.6.tar.gz", hash = "sha256:9a365179fe8ff6b8766f602c0f67c185d778193e9bdd828b19f0b6ed7764177d", size = 518139, upload-time = "2026-05-27T15:35:54.646Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1b/0d/b4f481e18c5a51864e6d12b9a05ecf72919696680b747c958c3fc1f4fbae/tornado-6.5.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:65fcfaafb079435c2c19dc9e07c0f1cf0fa9051759ed0a7d0a3ba7ea7f64919c", size = 447737, upload-time = "2026-05-27T15:35:38.122Z" }, { url = "https://files.pythonhosted.org/packages/9e/9c/5430c39fcab1144d35860f457b15e9c08b4bc7ac86764354204e983d6183/tornado-6.5.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:38bc01b4acacded2de63ae78023548e41ebe6fbed3ec05a796d7ae3ad893887e", size = 445899, upload-time = "2026-05-27T15:35:40.519Z" }, { url = "https://files.pythonhosted.org/packages/8b/79/fa7e14a2f939c807a8d30619b4eb604eab219601b78792516ebe22d40cf9/tornado-6.5.6-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b942e6a137fda31ff54bf8e6e2c8d1c37f1f50583f3ed53fb840b53b9601d104", size = 448964, upload-time = "2026-05-27T15:35:42.106Z" }, { url = "https://files.pythonhosted.org/packages/a7/71/bd67d5f5199f937dafe03a49a37989f60f600ff6fef34c79412a829d97bd/tornado-6.5.6-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8666946e70171b8c3f1fc9b7876fac492e84822c4c7f3746f4e8f8bc9ac92a79", size = 449935, upload-time = "2026-05-27T15:35:43.906Z" }, { url = "https://files.pythonhosted.org/packages/cc/a4/c24388c9cf5b3c3a513b56a158af9f23092c9a2810d789e294310797df21/tornado-6.5.6-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1c34cfab7ad6d104f052f55de06d39bbafc5885cfeb4da688803308dbcfa90b7", size = 449767, upload-time = "2026-05-27T15:35:45.793Z" }, { url = "https://files.pythonhosted.org/packages/a5/eb/6a07ad550c3f7b37244bd0becdf293ec3d3e961783d8b720a97df50de1b2/tornado-6.5.6-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:385f35e4e22fb52551dfcda4cdc8c30c61c2c001aef5ddad99cdfe116952efd3", size = 449174, upload-time = "2026-05-27T15:35:47.485Z" }, { url = "https://files.pythonhosted.org/packages/bb/84/3469e098dccdb6763130e06aacd786bb4363fca7b590a55c101ddf34ed30/tornado-6.5.6-cp39-abi3-win32.whl", hash = "sha256:db475f1b67b2809b10bb16264829087724ca8d24fe4ed47f7b8675cae453ef86", size = 450230, upload-time = "2026-05-27T15:35:49.322Z" }, { url = "https://files.pythonhosted.org/packages/d2/3c/273a04e0b9dd9016f1685cca0c1c8795a71ac88a34a8c889a0b443483226/tornado-6.5.6-cp39-abi3-win_amd64.whl", hash = "sha256:6739bf1e8eb09230f1280ddbd3236f0309db70f2c551a8dbc40f62babdf82f79", size = 450667, upload-time = "2026-05-27T15:35:51.194Z" }, { url = "https://files.pythonhosted.org/packages/02/98/0cffe22a224f60c5fb1e3aa0b76f9da2e1ca78b0e9545e3d077c68ce60a7/tornado-6.5.6-cp39-abi3-win_arm64.whl", hash = "sha256:2543597b24a695d72338a9a77818362d72387c03ae173f1f169eadc5c91466ac", size = 449690, upload-time = "2026-05-27T15:35:52.902Z" }, ] [[package]] name = "trustmux" version = "7.1.0" source = { editable = "." } dependencies = [ { name = "tornado" }, ] [package.metadata] requires-dist = [{ name = "tornado", specifier = ">=6.0" }] byobu-7.15/po/000077500000000000000000000000001522352767600132235ustar00rootroot00000000000000byobu-7.15/po/POTFILES.Python000066400000000000000000000002031522352767600156460ustar00rootroot00000000000000# List of source files containing translatable Python strings. # Please keep this file sorted alphabetically. usr/bin/byobu-config byobu-7.15/po/POTFILES.Shell000066400000000000000000000002571522352767600154450ustar00rootroot00000000000000# List of source files containing translatable sh strings. # Please keep this file sorted alphabetically. usr/lib/byobu/menu usr/bin/byobu-export usr/bin/byobu-select-profile byobu-7.15/po/bg.po000066400000000000000000000124231522352767600141550ustar00rootroot00000000000000# Bulgarian translation for screen-profiles # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the screen-profiles package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: screen-profiles\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-10-11 14:34-0500\n" "PO-Revision-Date: 2009-10-11 20:45+0000\n" "Last-Translator: Dustin Kirkland \n" "Language-Team: Bulgarian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-10-12 07:06+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:30 byobu-config:129 byobu-config:400 byobu-config:408 msgid "Menu" msgstr "Меню" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Избор" #: byobu-export:171 msgid "File exists" msgstr "Файлът съществува" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Премахване на файл? [y/n] " #: byobu-export:199 msgid "Select a color: " msgstr "Изберете цвят: " #: byobu-export:237 msgid "Profile" msgstr "Профил" #: byobu-export:238 msgid "Archive" msgstr "Архив" #: byobu-export:240 msgid "Extract the archive in your home directory on the target system." msgstr "" "Разархивирайте архива във вашата домашна директория на желаната система" #: byobu-select-profile:49 msgid "Error:" msgstr "Грешка:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " файлът съществува, но не е symlink" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Избиране на screen профил " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "ГРЕШКА: Невалидна селекция" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Ако използвате настройката по подразбиране за бързите клавиши натиснете\\" "n за да активирате тези промени.\\n\\n В противен случай затворете тази " "сесия и започнете нова." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Стартирайте \"byobu\" за да активирате" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu ще стартира при логин (изключи)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "" #: byobu-config:89 msgid "Help" msgstr "Помощ" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Променете цвета на Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "" #: byobu-config:92 msgid "Change keybinding set" msgstr "Промяна на клавишните комбинации" #: byobu-config:93 msgid "Change escape sequence" msgstr "" #: byobu-config:94 msgid "Create new windows" msgstr "" #: byobu-config:95 msgid "Manage default windows" msgstr "" #: byobu-config:99 byobu-config:486 msgid " Byobu Configuration Menu" msgstr "" #: byobu-config:110 msgid "Okay" msgstr "ОК" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:334 byobu-config:375 byobu-config:448 msgid "Cancel" msgstr "Отказ" #: byobu-config:130 msgid "Byobu Help" msgstr "" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:334 #: byobu-config:375 byobu-config:448 msgid "Apply" msgstr "Приложи" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Кой профил бихте желали да ползвате?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Коя клавишна комбинация ще ползвате?" #: byobu-config:175 msgid "Title: " msgstr "Заглавие: " #: byobu-config:177 msgid "Command: " msgstr "Команда: " #: byobu-config:179 msgid "Presets: " msgstr "Предварителни настройки: " #: byobu-config:193 msgid "Add to default windows" msgstr "Добавяне към прозорците по подразбиране" #: byobu-config:197 msgid "Create new window(s):" msgstr "" #: byobu-config:335 msgid "Toggle status notifications:" msgstr "" #: byobu-config:367 msgid "Windows:" msgstr "Прозорци:" #: byobu-config:377 msgid "Select window(s) to create by default:" msgstr "Избор на прозорец за създаване по подразбиране" #: byobu-config:397 msgid "Byobu will be launched automatically next time you login." msgstr "" #: byobu-config:405 msgid "Byobu will not be used next time you login." msgstr "" #: byobu-config:407 msgid "Message" msgstr "Съобщение" #: byobu-config:447 msgid "Escape key: ctrl-" msgstr "" #: byobu-config:450 msgid "Change escape sequence:" msgstr "" #: byobu-config:487 msgid "/ between elements | selects | exits" msgstr "" byobu-7.15/po/byobu.pot000066400000000000000000000073401522352767600150730ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "" #: byobu-export:171 msgid "File exists" msgstr "" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "" #: byobu-export:199 msgid "Select a color: " msgstr "" #: byobu-export:240 msgid "Profile" msgstr "" #: byobu-export:241 msgid "Archive" msgstr "" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "" #: byobu-select-profile:49 msgid "Error:" msgstr "" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr "" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "" #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "" #: byobu-config:89 msgid "Help" msgstr "" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "" #: byobu-config:91 msgid "Toggle status notifications" msgstr "" #: byobu-config:92 msgid "Change keybinding set" msgstr "" #: byobu-config:93 msgid "Change escape sequence" msgstr "" #: byobu-config:94 msgid "Create new windows" msgstr "" #: byobu-config:95 msgid "Manage default windows" msgstr "" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr "" #: byobu-config:110 msgid "Okay" msgstr "" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "" #: byobu-config:130 msgid "Byobu Help" msgstr "" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "" #: byobu-config:175 msgid "Title: " msgstr "" #: byobu-config:177 msgid "Command: " msgstr "" #: byobu-config:179 msgid "Presets: " msgstr "" #: byobu-config:193 msgid "Add to default windows" msgstr "" #: byobu-config:197 msgid "Create new window(s):" msgstr "" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "" #: byobu-config:368 msgid "Windows:" msgstr "" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "" #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "" #: byobu-config:408 msgid "Message" msgstr "" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "" #: byobu-config:451 msgid "Change escape sequence:" msgstr "" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "" byobu-7.15/po/cs.po000066400000000000000000000115551522352767600141770ustar00rootroot00000000000000# Czech translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2010-03-05 10:38+0000\n" "Last-Translator: Konki \n" "Language-Team: Czech \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-03-06 05:11+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Nabídka" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Zvolit" #: byobu-export:171 msgid "File exists" msgstr "Soubor existuje" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Odstranit soubor? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Vyberte barvu: " #: byobu-export:240 msgid "Profile" msgstr "Profil" #: byobu-export:241 msgid "Archive" msgstr "Archiv" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "Extrahujte archiv ve Vašem domovském adresáři v cílovém systému." #: byobu-select-profile:49 msgid "Error:" msgstr "Chyba:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " soubor existuje, ale není to symbolický odkaz" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Vyberte profil zobrazení: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "CHYBA: Neplatný výběr" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Pokud používáte výchozí klávesové zkratky, stiskněte\\n pro aktivaci " "těchto změn.\\n\\nJinak, ukončete toto sezení a začne nové." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Spusťte \"byobu\" pro aktivaci" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "" #: byobu-config:89 msgid "Help" msgstr "Nápověda" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Změna barev Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Upozornění stavu" #: byobu-config:92 msgid "Change keybinding set" msgstr "Změnit klávesové zkratky" #: byobu-config:93 msgid "Change escape sequence" msgstr "Změnit sekvenci escape" #: byobu-config:94 msgid "Create new windows" msgstr "Vytvořit nová okna" #: byobu-config:95 msgid "Manage default windows" msgstr "Spravovat výchozí okna" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Nabídka nastavení Byobu" #: byobu-config:110 msgid "Okay" msgstr "Ok" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Ukončit" #: byobu-config:130 msgid "Byobu Help" msgstr "Nápověda Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Použít" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Který profil byste chtěli použít?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Které klávesové zkratky byste chtěli použít?" #: byobu-config:175 msgid "Title: " msgstr "Název: " #: byobu-config:177 msgid "Command: " msgstr "Příkaz: " #: byobu-config:179 msgid "Presets: " msgstr "Předvolby: " #: byobu-config:193 msgid "Add to default windows" msgstr "Přidat do výchozích oken" #: byobu-config:197 msgid "Create new window(s):" msgstr "Vytvořit nová okna:" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Přepínač stavu oznámení:" #: byobu-config:368 msgid "Windows:" msgstr "Okna:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Vyberte okna pro výchozí vytvoření:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu bude použito po přihlášení." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "Byobu nebude použito po přihlášení." #: byobu-config:408 msgid "Message" msgstr "Zpráva" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Změňte sekvenci escape:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "/ mezi elementy | vybere | ukončí" byobu-7.15/po/de.po000066400000000000000000000121061522352767600141530ustar00rootroot00000000000000# German translation for screen-profiles # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the screen-profiles package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: screen-profiles\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-10-11 14:34-0500\n" "PO-Revision-Date: 2009-11-09 22:53+0000\n" "Last-Translator: BBO \n" "Language-Team: German \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-11-10 11:39+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:30 byobu-config:129 byobu-config:400 byobu-config:408 msgid "Menu" msgstr "Menü" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Auswählen" #: byobu-export:171 msgid "File exists" msgstr "Datei existiert bereits" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Lösche Datei? [j/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Wähle eine Farbe: " #: byobu-export:237 msgid "Profile" msgstr "Profil" #: byobu-export:238 msgid "Archive" msgstr "Archiv" #: byobu-export:240 msgid "Extract the archive in your home directory on the target system." msgstr "Archiv im Home Verzeichnis auf dem Zielsystem extrahieren" #: byobu-select-profile:49 msgid "Error:" msgstr "Fehler:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " Datei existiert, ist aber keine symbolische Verknüpfung" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Wählen Sie ein Bildschirmprofil aus: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "FEHLER: ungültige Auswahl" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Wenn sie die standard Tastenkombinationen benutzen\\ndrücken sie um die " "Änderungen zu aktivieren.\\n\\nAnderenfalls verlassen sie diese screen " "Sitzung und starten\\nsie eine neue." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "\"byobu\" eingeben um zu starten" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu startet beim einloggen (ausschalten)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu startet nicht beim einloggen (einschalten)" #: byobu-config:89 msgid "Help" msgstr "Hilfe" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Farben ändern" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Statusmeldungen ändern" #: byobu-config:92 msgid "Change keybinding set" msgstr "Tastaurbelegung wechseln" #: byobu-config:93 msgid "Change escape sequence" msgstr "Escape-Folge ändern" #: byobu-config:94 msgid "Create new windows" msgstr "neues Fenster erstellen" #: byobu-config:95 msgid "Manage default windows" msgstr "Standardfenster verwalten" #: byobu-config:99 byobu-config:486 msgid " Byobu Configuration Menu" msgstr " Byobu Konfiguration" #: byobu-config:110 msgid "Okay" msgstr "Ok" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:334 byobu-config:375 byobu-config:448 msgid "Cancel" msgstr "Abbrechen" #: byobu-config:130 msgid "Byobu Help" msgstr "Byobu Hilfe" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:334 #: byobu-config:375 byobu-config:448 msgid "Apply" msgstr "Übernehmen" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Welches Profil möchten Sie nutzen?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Welche Tastenbelegung würden Sie gerne benutzen?" #: byobu-config:175 msgid "Title: " msgstr "Titel: " #: byobu-config:177 msgid "Command: " msgstr "Befehl: " #: byobu-config:179 msgid "Presets: " msgstr "Voreinstellungen: " #: byobu-config:193 msgid "Add to default windows" msgstr "Hinzufügen zu Standardfenstern" #: byobu-config:197 msgid "Create new window(s):" msgstr "Neue(s) Fenster erstellen:" #: byobu-config:335 msgid "Toggle status notifications:" msgstr "Benachrichtigungen ein/aus schalten" #: byobu-config:367 msgid "Windows:" msgstr "Fenster:" #: byobu-config:377 msgid "Select window(s) to create by default:" msgstr "Wähle Fenster die immer erstellt werden:" #: byobu-config:397 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu wird beim nächsten Einloggen automatisch gestartet." #: byobu-config:405 msgid "Byobu will not be used next time you login." msgstr "Byobu wird beim nächsten Einloggen nicht genutzt." #: byobu-config:407 msgid "Message" msgstr "Nachricht" #: byobu-config:447 msgid "Escape key: ctrl-" msgstr "Escape-Taste: Strg-" #: byobu-config:450 msgid "Change escape sequence:" msgstr "Menü" #: byobu-config:487 msgid "/ between elements | selects | exits" msgstr "" "/ zwischen den Elementen| auswählen | Ende" byobu-7.15/po/en_GB.po000066400000000000000000000117531522352767600145440ustar00rootroot00000000000000# English (United Kingdom) translation for screen-profiles # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the screen-profiles package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: screen-profiles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2009-09-16 07:18+0000\n" "Last-Translator: Dave Walker \n" "Language-Team: English (United Kingdom) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-09-23 11:08+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Menu" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Choose" #: byobu-export:171 msgid "File exists" msgstr "File exists" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Remove file? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Select a colour: " #: byobu-export:240 msgid "Profile" msgstr "Profile" #: byobu-export:241 msgid "Archive" msgstr "Archive" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "Extract the archive in your home directory on the target system." #: byobu-select-profile:49 msgid "Error:" msgstr "Error:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " file exists, but is not a symlink" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Select a screen profile: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "ERROR: Invalid selection" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Run \"byobu\" to activate" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu currently launches at login (toggle off)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu currently does not launch at login (toggle on)" #: byobu-config:89 msgid "Help" msgstr "Help" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Change Byobu's colours" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Toggle status notifications" #: byobu-config:92 msgid "Change keybinding set" msgstr "Change keybinding set" #: byobu-config:93 msgid "Change escape sequence" msgstr "Change escape sequence" #: byobu-config:94 msgid "Create new windows" msgstr "Create new windows" #: byobu-config:95 msgid "Manage default windows" msgstr "Manage default windows" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Byobu Configuration Menu" #: byobu-config:110 msgid "Okay" msgstr "Okay" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Cancel" #: byobu-config:130 msgid "Byobu Help" msgstr "Byobu Help" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Apply" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Which profile would you like to use?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Which set of keybindings would you like to use?" #: byobu-config:175 msgid "Title: " msgstr "Title: " #: byobu-config:177 msgid "Command: " msgstr "Command: " #: byobu-config:179 msgid "Presets: " msgstr "Presets: " #: byobu-config:193 msgid "Add to default windows" msgstr "Add to default windows" #: byobu-config:197 msgid "Create new window(s):" msgstr "Create new window(s):" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Toggle status notifications:" #: byobu-config:368 msgid "Windows:" msgstr "Windows:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Select window(s) to create by default:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu will be launched automatically next time you login." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "Byobu will not be used next time you login." #: byobu-config:408 msgid "Message" msgstr "Message" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "Escape key: ctrl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Change escape sequence:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "/ between elements | selects | exits" byobu-7.15/po/es.po000066400000000000000000000122631522352767600141760ustar00rootroot00000000000000# Byobu # Copyright (C) 2008-2014 Dustin Kirkland # This file is distributed under the same license as the Byobu package. # Nicolas Valcarcel , 2008. # msgid "" msgstr "" "Project-Id-Version: 1.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-10-11 14:34-0500\n" "PO-Revision-Date: 2009-10-11 20:45+0000\n" "Last-Translator: oscrp \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-10-12 07:06+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:30 byobu-config:129 byobu-config:400 byobu-config:408 msgid "Menu" msgstr "Menú" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Elección" #: byobu-export:171 msgid "File exists" msgstr "El archivo ya existe" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "¿Eliminar archivo? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Seleccionar un color: " #: byobu-export:237 msgid "Profile" msgstr "Perfil" #: byobu-export:238 msgid "Archive" msgstr "Archivador" #: byobu-export:240 msgid "Extract the archive in your home directory on the target system." msgstr "" "Extraiga el archivador en su directorio personal del sistema objetivo." #: byobu-select-profile:49 msgid "Error:" msgstr "Error:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " el archivo existe, pero no es un vínculo simbólico" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Seleccione un perfil de pantalla: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "ERROR: Selección inválida" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Si estás usando el conjunto por defecto de atajos de teclado, presiona\\n " " para activar estos cambios. \\n\\n De no ser así, sal de esta sesión de " "\"screen\" y inicia otra nueva." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Ejecute «byobu» para activar" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu actualmente se lanza en el inicio (cambiar)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu actualmente no se lanza en el inicio (cambiar)" #: byobu-config:89 msgid "Help" msgstr "Ayuda" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Cambiar el tema de Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Activar/desactivar notificaciones" #: byobu-config:92 msgid "Change keybinding set" msgstr "Cambiar el conjunto de atajos de teclado" #: byobu-config:93 msgid "Change escape sequence" msgstr "Cambiar la secuencia de escape" #: byobu-config:94 msgid "Create new windows" msgstr "Crear nuevas ventanas" #: byobu-config:95 msgid "Manage default windows" msgstr "Gestionar ventanas predeterminadas" #: byobu-config:99 byobu-config:486 msgid " Byobu Configuration Menu" msgstr " Menú de configuración Byobu" #: byobu-config:110 msgid "Okay" msgstr "Aceptar" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:334 byobu-config:375 byobu-config:448 msgid "Cancel" msgstr "Cancelar" #: byobu-config:130 msgid "Byobu Help" msgstr "Ayuda de Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:334 #: byobu-config:375 byobu-config:448 msgid "Apply" msgstr "Aplicar" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "¿Qué perfil desea usar?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "¿Qué conjunto de atajos de teclado desea usar?" #: byobu-config:175 msgid "Title: " msgstr "Título: " #: byobu-config:177 msgid "Command: " msgstr "Comando: " #: byobu-config:179 msgid "Presets: " msgstr "Preajustes: " #: byobu-config:193 msgid "Add to default windows" msgstr "Añadir a las ventanas por defecto" #: byobu-config:197 msgid "Create new window(s):" msgstr "Crear ventana(s) nueva(s):" #: byobu-config:335 msgid "Toggle status notifications:" msgstr "Activar/Desactivar notificaciónes:" #: byobu-config:367 msgid "Windows:" msgstr "Ventanas:" #: byobu-config:377 msgid "Select window(s) to create by default:" msgstr "Seleccionar ventana(s) para crear por defecto:" #: byobu-config:397 msgid "Byobu will be launched automatically next time you login." msgstr "" "Byobu se lanzará automáticamente la próxima vez que inicie su sesión." #: byobu-config:405 msgid "Byobu will not be used next time you login." msgstr "Byobu no se iniciará la próxima vez que se identifique." #: byobu-config:407 msgid "Message" msgstr "Mensaje" #: byobu-config:447 msgid "Escape key: ctrl-" msgstr "Tecla de escape: ctrl-" #: byobu-config:450 msgid "Change escape sequence:" msgstr "Cambiar la secuencia de escape:" #: byobu-config:487 msgid "/ between elements | selects | exits" msgstr "" "/ entre los elementos | seleccione | salir" #~ msgid "recommended" #~ msgstr "recomendado" byobu-7.15/po/fr.po000066400000000000000000000125271522352767600142010ustar00rootroot00000000000000# Byobu # Copyright (C) 2008-2014 Dustin Kirkland # This file is distributed under the same license as the Byobu package. # Nicolas Barcet , 2008. # msgid "" msgstr "" "Project-Id-Version: 1.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-10-11 14:34-0500\n" "PO-Revision-Date: 2009-10-11 20:45+0000\n" "Last-Translator: Pierre Slamich \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-10-12 07:06+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: byobu-select-profile:49 msgid "Error:" msgstr "Erreur :" #: bin/menu:30 byobu-config:129 byobu-config:400 byobu-config:408 msgid "Menu" msgstr "Menu" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Choisir" #: byobu-export:171 msgid "File exists" msgstr "Le fichier existe." #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Supprimer le fichier? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Choisissez une couleur : " #: byobu-export:237 msgid "Profile" msgstr "Profil" #: byobu-export:238 msgid "Archive" msgstr "Archive" #: byobu-export:240 msgid "Extract the archive in your home directory on the target system." msgstr "" "Décompressez l'archive dans votre répertoire personnel (home) sur le système " "cible." #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr "Le fichier existe, mais n'est pas un lien symbolique" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Sélectionnez un profil screen : " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "ERREUR : Sélection invalide" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Si vous utilisez la configuration par défaut des raccourcis clavier, appuyez " "sur\\n pour activer ces changements.\\n\\nSinon, quittez cette session " "screen et commencez-en une nouvelle." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Exécutez \"byobu\" pour activer" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu se lance actuellement à la connexion (désactiver)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu ne se lance actuellement pas à la connexion (activer)" #: byobu-config:89 msgid "Help" msgstr "Aide" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Changer les couleurs de Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Changer les notifications d'état" #: byobu-config:92 msgid "Change keybinding set" msgstr "Changer d'ensemble de raccourcis clavier" #: byobu-config:93 msgid "Change escape sequence" msgstr "Changer la séquence d'échappement" #: byobu-config:94 msgid "Create new windows" msgstr "Créer de nouvelles fenêtres" #: byobu-config:95 msgid "Manage default windows" msgstr "Gérer les fenêtres par défaut" #: byobu-config:99 byobu-config:486 msgid " Byobu Configuration Menu" msgstr " Menu de Configuration de Byobu" #: byobu-config:110 msgid "Okay" msgstr "Ok" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:334 byobu-config:375 byobu-config:448 msgid "Cancel" msgstr "Annuler" #: byobu-config:130 msgid "Byobu Help" msgstr "Aide de Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:334 #: byobu-config:375 byobu-config:448 msgid "Apply" msgstr "Appliquer" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Quel profil voudriez-vous utiliser ?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Quel ensemble de raccourcis clavier voudriez-vous utiliser ?" #: byobu-config:175 msgid "Title: " msgstr "Titre : " #: byobu-config:177 msgid "Command: " msgstr "Commande : " #: byobu-config:179 msgid "Presets: " msgstr "Réglages prédéfinis : " #: byobu-config:193 msgid "Add to default windows" msgstr "Ajouter aux fenêtres par défaut" #: byobu-config:197 msgid "Create new window(s):" msgstr "Créer de nouvelle(s) fenêtre(s) :" #: byobu-config:335 msgid "Toggle status notifications:" msgstr "Changer les notifications d'état :" #: byobu-config:367 msgid "Windows:" msgstr "Fenêtres :" #: byobu-config:377 msgid "Select window(s) to create by default:" msgstr "Sélectionner la(les) fenêtre(s) à créer par défaut :" #: byobu-config:397 msgid "Byobu will be launched automatically next time you login." msgstr "" "Byobu sera lancé automatiquement la prochaine fois que vous vous connecterez." #: byobu-config:405 msgid "Byobu will not be used next time you login." msgstr "" "Byobu ne sera pas lancé la prochaine fois que vous vous connecterez." #: byobu-config:407 msgid "Message" msgstr "Message" #: byobu-config:447 msgid "Escape key: ctrl-" msgstr "Séquence d'échappement : ctrl-" #: byobu-config:450 msgid "Change escape sequence:" msgstr "Changer la séquence d'échappement :" #: byobu-config:487 msgid "/ between elements | selects | exits" msgstr "" "/ entre les éléments | sélectionne | quitte" #~ msgid "recommended" #~ msgstr "recommandé" byobu-7.15/po/hu.po000066400000000000000000000123061522352767600142010ustar00rootroot00000000000000# Hungarian translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2010-03-03 11:48+0000\n" "Last-Translator: Muszela Balázs \n" "Language-Team: Hungarian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-03-04 04:53+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Menü" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Kiválasztás" #: byobu-export:171 msgid "File exists" msgstr "A fájl már létezik" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Eltávolítsam a fájlt? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Válasszon egy színt: " #: byobu-export:240 msgid "Profile" msgstr "Profil" #: byobu-export:241 msgid "Archive" msgstr "Archív" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "A fájlt a célrendszeren levő saját könyvtárába csomagolja ki." #: byobu-select-profile:49 msgid "Error:" msgstr "Hiba:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " fájl létezik, de nem symlink" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Válasszon egy profilt: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "HIBA: Érvénytelen választás" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Az alapértelmezett billentyűkombinációk használatakor az\\n-tel lehet a " "változtatásokat menteni.\\n\\nEllenkező esetben lépjen ki a munkamenetből, " "és indítson újat." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Az aktiváláshoz adja ki a „byobu” parancsot" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "A Byobu jelenleg bejelentkezéskor indul (kikapcsolás)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "A Byobu jelenleg nem indul bejelentkezéskor (bekapcsolás)" #: byobu-config:89 msgid "Help" msgstr "Súgó" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "A Byobu színeinek megváltoztatása" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Állapotértesítések átállítása" #: byobu-config:92 msgid "Change keybinding set" msgstr "Billentyűkombinációk módosítása" #: byobu-config:93 msgid "Change escape sequence" msgstr "Escape-sorozat módosítása" #: byobu-config:94 msgid "Create new windows" msgstr "Új ablakok nyitása" #: byobu-config:95 msgid "Manage default windows" msgstr "Alapértelmezett ablakok kezelése" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Byobu beállítómenü" #: byobu-config:110 msgid "Okay" msgstr "Rendben" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Mégsem" #: byobu-config:130 msgid "Byobu Help" msgstr "Byobu súgó" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Alkalmaz" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Melyik profilt szeretné használni?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Mely billentyűkombinációkat szeretné használni?" #: byobu-config:175 msgid "Title: " msgstr "Cím: " #: byobu-config:177 msgid "Command: " msgstr "Parancs: " #: byobu-config:179 msgid "Presets: " msgstr "Beállítások: " #: byobu-config:193 msgid "Add to default windows" msgstr "Hozzáadás az alapértelmezett ablakokhoz" #: byobu-config:197 msgid "Create new window(s):" msgstr "Új ablak(ok) létrehozása:" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Állapotértesítések átállítása:" #: byobu-config:368 msgid "Windows:" msgstr "Ablakok:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Válassza ki az alapértelmezésben létrehozandó ablakokat:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "A következő bejelentkezéskor a Byobu automatikusan elindul." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "A következő bejelentkezéskor a Byobu nem indul el." #: byobu-config:408 msgid "Message" msgstr "Üzenet" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "Escape billentyű: ctrl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Escape-sorozat módosítása:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "/ elemek között | kiválasztás | kilépés" byobu-7.15/po/id.po000066400000000000000000000117151522352767600141640ustar00rootroot00000000000000# Indonesian translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2009-08-17 21:09+0000\n" "Last-Translator: Andika Triwidada \n" "Language-Team: Indonesian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-09-23 11:08+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Menu" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Pilih" #: byobu-export:171 msgid "File exists" msgstr "Berkas telah ada" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Hapus berkas? [y/T] " #: byobu-export:199 msgid "Select a color: " msgstr "Pilih warna: " #: byobu-export:240 msgid "Profile" msgstr "Profil" #: byobu-export:241 msgid "Archive" msgstr "Arsip" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "Ekstrak arsip di direktori rumah anda pada sistem target." #: byobu-select-profile:49 msgid "Error:" msgstr "Kesalahan:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " berkas ada, tapi bukan symlink" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Pilih profil screen: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "KESALAHAN: Pilihan tak valid" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Bila anda memakai tatanan bawaan keybinding, tekan\\n untuk mengaktifkan " "perubahan ini.\\n\\nJika tidak, keluar dari sesi screen ini dan mulailah " "yang baru." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Jalankan \"byobu\" untuk mengaktifkan" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu kini diluncurkan saat login (toggle mati)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu kini tidak diluncurkan saat login (toggle nyala)" #: byobu-config:89 msgid "Help" msgstr "Bantuan" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Ubah warna Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Toggle pemberitahuan status" #: byobu-config:92 msgid "Change keybinding set" msgstr "Ubah tatanan keybinding" #: byobu-config:93 msgid "Change escape sequence" msgstr "Ubah urutan escape" #: byobu-config:94 msgid "Create new windows" msgstr "Buat jendela baru" #: byobu-config:95 msgid "Manage default windows" msgstr "Kelola jendela bawaan" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Menu Konfigurasi Byobu" #: byobu-config:110 msgid "Okay" msgstr "Ok" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Batal" #: byobu-config:130 msgid "Byobu Help" msgstr "Bantuan Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Terapkan" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Profil mana yang akan anda pakai?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Tatanan keybinding mana yang ingin anda pakai?" #: byobu-config:175 msgid "Title: " msgstr "Judul: " #: byobu-config:177 msgid "Command: " msgstr "Perintah: " #: byobu-config:179 msgid "Presets: " msgstr "Pratata: " #: byobu-config:193 msgid "Add to default windows" msgstr "Tambahkan ke jendela bawaan" #: byobu-config:197 msgid "Create new window(s):" msgstr "Buat jendela baru:" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Toggle pemberitahuan status:" #: byobu-config:368 msgid "Windows:" msgstr "Jendela:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Pilih jendela yang akan dibuat secara default" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu akan diluncurkan secara otomatis saat anda login berikutnya." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "Byobu tidak akan dipakai ketika anda login berikutnya." #: byobu-config:408 msgid "Message" msgstr "Pesan" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "Kunci escape: ctrl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Ubah urutan escape:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "/ antar elemen | pilih | keluar" byobu-7.15/po/is.po000066400000000000000000000120151522352767600141750ustar00rootroot00000000000000# Icelandic translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2009-12-11 12:49+0000\n" "Last-Translator: Baldur \n" "Language-Team: Icelandic \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-12-12 04:43+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Valmynd" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Velja" #: byobu-export:171 msgid "File exists" msgstr "Skráin er þegar til" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Viltu fjarlægja skrána? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Veldu lit: " #: byobu-export:240 msgid "Profile" msgstr "Útlit" #: byobu-export:241 msgid "Archive" msgstr "Skráasafn" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "Afþjappa skráasafninu í heimamöppunni á kerfinu sem er valið." #: byobu-select-profile:49 msgid "Error:" msgstr "Villa:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " skrá er til en er ekki sýndartengill" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Veltu útlit: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "VILLA: Ógilt val" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Þú getur virkjað breytingar með því að ýta á \\n\r\n" "ef þú notar venjulega flýtilykla.\\n\\n\r\n" "\r\n" "Annars skaltu hætta og byrja aftur." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Keyrðu „byobu“ til að ræsa" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu opnast við innskráningu (ekki láta Byobu opnast)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu opnast ekki við innskráningu (láta Byobu opnast)" #: byobu-config:89 msgid "Help" msgstr "Aðstoð" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Breyta litasamsetningunni í Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Breyta stöðutilkynningum" #: byobu-config:92 msgid "Change keybinding set" msgstr "Breyta flýtilyklunum" #: byobu-config:93 msgid "Change escape sequence" msgstr "Breyta lausarrununni" #: byobu-config:94 msgid "Create new windows" msgstr "Búa til nýja glugga" #: byobu-config:95 msgid "Manage default windows" msgstr "Sjá um venjulega glugga" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Stillingarvalmynd Byobu" #: byobu-config:110 msgid "Okay" msgstr "Í lagi" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Hætta við" #: byobu-config:130 msgid "Byobu Help" msgstr "Byobu aðstoð" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Nota" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Hvaða útlit viltu nota?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Hvaða flýtilykla viltu nota?" #: byobu-config:175 msgid "Title: " msgstr "Nafn: " #: byobu-config:177 msgid "Command: " msgstr "Skipun: " #: byobu-config:179 msgid "Presets: " msgstr "Stillingar: " #: byobu-config:193 msgid "Add to default windows" msgstr "Bæta við sjálfgefna glugga" #: byobu-config:197 msgid "Create new window(s):" msgstr "Búa til nýja glugga:" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Breyta stöðutilkynningum:" #: byobu-config:368 msgid "Windows:" msgstr "Gluggar:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Veldu þá glugga sem á að búa til sjálfkrafa:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu fer í gang þegar þú skráir þig inn næst." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "Byobu fer ekki í gang þegar þú skráir þig inn næst." #: byobu-config:408 msgid "Message" msgstr "Skilaboð" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "Lausnarlykill: ctrl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Breyta lausnarrununni:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "/ fer á milli hluta | velur | hættir" byobu-7.15/po/it.po000066400000000000000000000121511522352767600141770ustar00rootroot00000000000000# Italian translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2010-04-04 19:04+0000\n" "Last-Translator: Milo Casagrande \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-04-05 03:54+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Menù" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Scegliere" #: byobu-export:171 msgid "File exists" msgstr "Il file esiste già" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Rimuovere il file? [s/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Selezionare un colore: " #: byobu-export:240 msgid "Profile" msgstr "Profilo" #: byobu-export:241 msgid "Archive" msgstr "Archivio" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "" "Estrarre l'archivio nella directory personale sul sistema di destinazione." #: byobu-select-profile:49 msgid "Error:" msgstr "Errore:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " il file esiste già, ma non è un collegamento simbolico" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Selezionare un profilo di \"screen\": " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "Errore: selezione non valida" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Se viene usata l'associazione dei tasti predefinita, premere\\n per " "rendere attivi queste modifiche.\\nAltrimenti uscire da questa sessione e " "iniziarne una nuova." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Eseguire \"byobu\" per attivare" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu attualmente si avvia all'accesso (disabilitare)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu attualmente non si avvia all'accesso (abilitare)" #: byobu-config:89 msgid "Help" msgstr "Aiuto" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Cambiare i colori" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Abilitare notifiche di stato" #: byobu-config:92 msgid "Change keybinding set" msgstr "Modificare associazioni dei tasti" #: byobu-config:93 msgid "Change escape sequence" msgstr "Modificare la sequenza di escape" #: byobu-config:94 msgid "Create new windows" msgstr "Creare nuove finestre" #: byobu-config:95 msgid "Manage default windows" msgstr "Gestire finestre predefinite" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Menù di configurazione di Byobu" #: byobu-config:110 msgid "Okay" msgstr "OK" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Annulla" #: byobu-config:130 msgid "Byobu Help" msgstr "Aiuto di Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Applica" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Quale profilo usare?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Quale associazione di tasti utilizzare?" #: byobu-config:175 msgid "Title: " msgstr "Titolo: " #: byobu-config:177 msgid "Command: " msgstr "Comando: " #: byobu-config:179 msgid "Presets: " msgstr "Preselezioni: " #: byobu-config:193 msgid "Add to default windows" msgstr "Aggiungere alle finestre predefinite" #: byobu-config:197 msgid "Create new window(s):" msgstr "Creare nuove finestre:" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Abilitare notifiche di stato:" #: byobu-config:368 msgid "Windows:" msgstr "Finestre:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Selezionare una o più finestre da creare:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "Il programma sarà avviato automaticamente al prossimo accesso." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "Il programma non verrà utilizzato al prossimo accesso." #: byobu-config:408 msgid "Message" msgstr "Messaggio" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "Comando d'uscita: Ctrl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Cambiare sequenza d'uscita:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "/ Muove tra elementi | Seleziona | Esce" byobu-7.15/po/ja.po000066400000000000000000000107571522352767600141670ustar00rootroot00000000000000# Japanese translation for screen-profiles # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the screen-profiles package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: screen-profiles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2009-09-16 07:43+0000\n" "Last-Translator: Fumihito YOSHIDA \n" "Language-Team: Japanese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-09-23 11:08+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "" #: byobu-export:171 msgid "File exists" msgstr "" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "" #: byobu-export:199 msgid "Select a color: " msgstr "" #: byobu-export:240 msgid "Profile" msgstr "" #: byobu-export:241 msgid "Archive" msgstr "" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "" #: byobu-select-profile:49 msgid "Error:" msgstr "エラー:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " ファイルが存在しますが, シンボリックリンクではありません" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "スクリーンプロファイルを選択してください: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "" #: byobu-config:89 msgid "Help" msgstr "ヘルプ" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "" #: byobu-config:91 msgid "Toggle status notifications" msgstr "" #: byobu-config:92 msgid "Change keybinding set" msgstr "キー割り当て表の変更" #: byobu-config:93 msgid "Change escape sequence" msgstr "エスケープシーケンスの変更" #: byobu-config:94 msgid "Create new windows" msgstr "" #: byobu-config:95 msgid "Manage default windows" msgstr "標準ウィンドウの管理" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr "" #: byobu-config:110 msgid "Okay" msgstr "了解" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "取消" #: byobu-config:130 msgid "Byobu Help" msgstr "" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "適用" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "どのプロファイルを使いますか?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "どのキー割り当てを使いますか?" #: byobu-config:175 msgid "Title: " msgstr "タイトル: " #: byobu-config:177 msgid "Command: " msgstr "コマンド: " #: byobu-config:179 msgid "Presets: " msgstr "プリセット: " #: byobu-config:193 msgid "Add to default windows" msgstr "標準ウィンドウに追加" #: byobu-config:197 msgid "Create new window(s):" msgstr "新しいウィンドウを作成する:" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "" #: byobu-config:368 msgid "Windows:" msgstr "ウィンドウ:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "標準で作成するウィンドウを選択してください:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "" #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "" #: byobu-config:408 msgid "Message" msgstr "メッセージ" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "エスケープキー: ctrl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "エスケープシーケンスを変更する:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "" byobu-7.15/po/ka.po000066400000000000000000000162611522352767600141640ustar00rootroot00000000000000# Georgian translation for byobu. # Copyright (C) 2026 byobu's authors. # This file is distributed under the same license as the byobu package. # Temuri Doghonadze , 2026. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2026-06-08 15:11+0200\n" "Last-Translator: Temuri Doghonadze \n" "Language-Team: Georgian <(nothing)>\n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.9\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "მენიუ" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "აირჩიეთ" #: byobu-export:171 msgid "File exists" msgstr "ფაილი უკვე არსებობს" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "წავშალო ფაილი? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "აირჩიეთ ფერი: " #: byobu-export:240 msgid "Profile" msgstr "პროფილი" #: byobu-export:241 msgid "Archive" msgstr "არქივი" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "გახსენით არქივი თქვენს საწყის საქაღალდეში სამიზნე სისტემაზე." #: byobu-select-profile:49 msgid "Error:" msgstr "შეცდომა:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " ფაილი არსებობს, მაგრამ სიმბმული არაა" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "აირჩიეთ ეკრანის პროფილი: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "შეცდომა: არასწორი მონიშვნა" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "თუ იყენებთ კლავიატურის მალსახმობების ნაგულისხმევ ნაკრებს, დააჭირეთ \\n-" "ს, რომ გაააქტიუროთ ეს ცვლილებები.\\n\\nსხვა შემთხვევაში გადით ეკრანი " "სესიიდან და ახალი გაუშვით." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "გასააქტიურებლად გაუშვით \"byobu\"" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu ამჟამად ეშვება სისტემაში შესვლისას (გადართვა გამორთავს)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu ამჟამად შესვლისას არ გაეშვება (ჩართვა)" #: byobu-config:89 msgid "Help" msgstr "დახმარება" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Byobu-ის ფერების შეცვლა" #: byobu-config:91 msgid "Toggle status notifications" msgstr "სტატუსის გაფრთხილებების გადართვა" #: byobu-config:92 msgid "Change keybinding set" msgstr "კლავიატურის მალსახმობების ნაკრების შეცვლა" #: byobu-config:93 msgid "Change escape sequence" msgstr "სპეციალური მიმდევრობის შეცვლა" #: byobu-config:94 msgid "Create new windows" msgstr "ახალი ფანჯრების შექმნა" #: byobu-config:95 msgid "Manage default windows" msgstr "ნაგულისხმევი ფანჯრების მართვა" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Byobu-ის კონფიგურაციის მენიუ" #: byobu-config:110 msgid "Okay" msgstr "დიახ" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "გაუქმება" #: byobu-config:130 msgid "Byobu Help" msgstr "Byobu-ის დახმარება" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "გადატარება" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "რომელი პროფილის გამოყენება გსურთ?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "რომელი კლავიატურის მალსახმობების ნაკრების გამოყენება გსურთ?" #: byobu-config:175 msgid "Title: " msgstr "სათაური: " #: byobu-config:177 msgid "Command: " msgstr "ბრძანება: " #: byobu-config:179 msgid "Presets: " msgstr "პრესეტები: " #: byobu-config:193 msgid "Add to default windows" msgstr "ჩამატება ნაგულისხმევ ფანჯრებში" #: byobu-config:197 msgid "Create new window(s):" msgstr "ახალი ფანჯრების შექმნა:" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "სტატუსის გაფრთხილებების გადართვა:" #: byobu-config:368 msgid "Windows:" msgstr "ფანჯრები:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "აირჩიეთ ფანჯრები, რომლებიც გნებავთ, ნაგულისხმევად შეიქმნას:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu ავტომატურად გაეშვება შემდეგ ჯერზე, როცა სისტემაში შეხვალთ." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "Byobu არ იქნება გამოყენებული, როცა შემდეგ ჯერზე შეხვალთ სისტემაში." #: byobu-config:408 msgid "Message" msgstr "შეტყობინება" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "ღილაკი Escape: ctrl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "სპეციალური მიმდევრობის შეცვლა:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "/ ელემენტებს შორის | მონიშნავს | გავა" byobu-7.15/po/la.po000066400000000000000000000076701522352767600141710ustar00rootroot00000000000000# Latin translation for screen-profiles # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the screen-profiles package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: screen-profiles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2010-01-03 04:50+0000\n" "Last-Translator: Philipp Kleinhenz \n" "Language-Team: Latin \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-01-04 04:39+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "" #: byobu-export:171 msgid "File exists" msgstr "" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "" #: byobu-export:199 msgid "Select a color: " msgstr "" #: byobu-export:240 msgid "Profile" msgstr "" #: byobu-export:241 msgid "Archive" msgstr "" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "" #: byobu-select-profile:49 msgid "Error:" msgstr "" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr "" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "" #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "" #: byobu-config:89 msgid "Help" msgstr "Auxilium" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "" #: byobu-config:91 msgid "Toggle status notifications" msgstr "" #: byobu-config:92 msgid "Change keybinding set" msgstr "Mutare clavis congeries" #: byobu-config:93 msgid "Change escape sequence" msgstr "Mutare fuga" #: byobu-config:94 msgid "Create new windows" msgstr "" #: byobu-config:95 msgid "Manage default windows" msgstr "Administrare fenestrae" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr "" #: byobu-config:110 msgid "Okay" msgstr "" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Abrogare" #: byobu-config:130 msgid "Byobu Help" msgstr "" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Applicare" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "" #: byobu-config:175 msgid "Title: " msgstr "" #: byobu-config:177 msgid "Command: " msgstr "imperium: " #: byobu-config:179 msgid "Presets: " msgstr "" #: byobu-config:193 msgid "Add to default windows" msgstr "" #: byobu-config:197 msgid "Create new window(s):" msgstr "" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "" #: byobu-config:368 msgid "Windows:" msgstr "" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "" #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "" #: byobu-config:408 msgid "Message" msgstr "epistula" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "" #: byobu-config:451 msgid "Change escape sequence:" msgstr "" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "" byobu-7.15/po/lt.po000066400000000000000000000106131522352767600142030ustar00rootroot00000000000000# Lithuanian translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-10-11 14:34-0500\n" "PO-Revision-Date: 2009-11-20 20:00+0000\n" "Last-Translator: Povilas Balzaravičius aka Pawka \n" "Language-Team: Lithuanian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-11-21 04:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:30 byobu-config:129 byobu-config:400 byobu-config:408 msgid "Menu" msgstr "Meniu" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Pasirinkti" #: byobu-export:171 msgid "File exists" msgstr "Failas egzistuoja" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Šalinti failą? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Pakeisti spalvą " #: byobu-export:237 msgid "Profile" msgstr "Profilis" #: byobu-export:238 msgid "Archive" msgstr "Archyvas" #: byobu-export:240 msgid "Extract the archive in your home directory on the target system." msgstr "" #: byobu-select-profile:49 msgid "Error:" msgstr "Klaida:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr "" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "" #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "KLAIDA: Klaidingas pasirinkimas" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Paleiskite \"byobu\", kad aktyvuotumėte" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu startuos vartotojui prisijungus (paspauskite, kad išjungti)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byoby nestartuos prisijungus vartotojui (paspauskite, kad įjungti)" #: byobu-config:89 msgid "Help" msgstr "Pagalba" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Pakeisti Byobu spalvas" #: byobu-config:91 msgid "Toggle status notifications" msgstr "" #: byobu-config:92 msgid "Change keybinding set" msgstr "" #: byobu-config:93 msgid "Change escape sequence" msgstr "" #: byobu-config:94 msgid "Create new windows" msgstr "Sukurti naujus langus" #: byobu-config:95 msgid "Manage default windows" msgstr "" #: byobu-config:99 byobu-config:486 msgid " Byobu Configuration Menu" msgstr "" #: byobu-config:110 msgid "Okay" msgstr "Gerai" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:334 byobu-config:375 byobu-config:448 msgid "Cancel" msgstr "Atsisakyti" #: byobu-config:130 msgid "Byobu Help" msgstr "Byobu pagalba" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:334 #: byobu-config:375 byobu-config:448 msgid "Apply" msgstr "Pritaikyti" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Kurį profilį norite naudoti?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Kurį klavišų kombinacijų rinkinį norite naudoti?" #: byobu-config:175 msgid "Title: " msgstr "Pavadinimas: " #: byobu-config:177 msgid "Command: " msgstr "Komanda: " #: byobu-config:179 msgid "Presets: " msgstr "" #: byobu-config:193 msgid "Add to default windows" msgstr "" #: byobu-config:197 msgid "Create new window(s):" msgstr "Sukurti naują langą(-us):" #: byobu-config:335 msgid "Toggle status notifications:" msgstr "" #: byobu-config:367 msgid "Windows:" msgstr "Langai:" #: byobu-config:377 msgid "Select window(s) to create by default:" msgstr "" #: byobu-config:397 msgid "Byobu will be launched automatically next time you login." msgstr "" #: byobu-config:405 msgid "Byobu will not be used next time you login." msgstr "" #: byobu-config:407 msgid "Message" msgstr "Pranešimas" #: byobu-config:447 msgid "Escape key: ctrl-" msgstr "" #: byobu-config:450 msgid "Change escape sequence:" msgstr "" #: byobu-config:487 msgid "/ between elements | selects | exits" msgstr "" byobu-7.15/po/nl.po000066400000000000000000000120111522352767600141670ustar00rootroot00000000000000# Dutch translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2010-01-12 14:33+0000\n" "Last-Translator: cumulus007 \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-01-13 04:51+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Menu" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Kiezen" #: byobu-export:171 msgid "File exists" msgstr "Bestand bestaat al" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Bestand verwijderen? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Kies een kleur: " #: byobu-export:240 msgid "Profile" msgstr "Profiel" #: byobu-export:241 msgid "Archive" msgstr "Archief" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "Pak het archief uit in uw persoonlijke map op het doelsysteem." #: byobu-select-profile:49 msgid "Error:" msgstr "Fout:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " het bestand bestaat, maar het is geen symlink" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Kies een schermprofiel: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "FOUT: ongeldige selectie" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Alsu de standaard sneltoetsen gebruikt, druk dan op \\n om deze " "wijzigingen in te schakelen.\\n\\nSluit anders deze sessie af en start een " "nieuwe." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Voer \"byobu\" uit om te activeren" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu start momenteel bij aanmelden (uitschakelen)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu start momenteel niet bij aanmelden (inschakelen)" #: byobu-config:89 msgid "Help" msgstr "Hulp" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Byobu's kleuren wijzigen" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Statusmeldingen aan/uit" #: byobu-config:92 msgid "Change keybinding set" msgstr "Sneltoetsen wijzigen" #: byobu-config:93 msgid "Change escape sequence" msgstr "Uitlogvolgorde aanpassen" #: byobu-config:94 msgid "Create new windows" msgstr "Nieuwe vensters aanmaken" #: byobu-config:95 msgid "Manage default windows" msgstr "Standaardvensters beheren" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Byobu instellen" #: byobu-config:110 msgid "Okay" msgstr "OK" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Annuleren" #: byobu-config:130 msgid "Byobu Help" msgstr "Byobu Help" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Toepassen" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Welk profiel wilt u gebruiken?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Welke sneltoetsen wilt u gebruiken?" #: byobu-config:175 msgid "Title: " msgstr "Titel: " #: byobu-config:177 msgid "Command: " msgstr "Opdracht: " #: byobu-config:179 msgid "Presets: " msgstr "Instellingen: " #: byobu-config:193 msgid "Add to default windows" msgstr "Toevoegen aan de standaardvensters" #: byobu-config:197 msgid "Create new window(s):" msgstr "Nieuw(e) venster(s) aanmaken" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Status meldingen aan/uit:" #: byobu-config:368 msgid "Windows:" msgstr "Vensters:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Kies venster(s) die standaard aangemaakt worden:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu zal automatisch starten bij de volgende keer dat u inlogt." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "Byobu zal niet gebruikt worden bij de volgende keer dat u inlogt." #: byobu-config:408 msgid "Message" msgstr "Bericht" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "Escape-toets: ctrl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Escape-volgorde aanpassen:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "" "/ tussen elementen | selecteert | sluit af" byobu-7.15/po/pt.po000066400000000000000000000122301522352767600142040ustar00rootroot00000000000000# Portuguese translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2010-04-05 13:21+0000\n" "Last-Translator: Tiago Silva \n" "Language-Team: Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-04-06 04:02+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Menu" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Seleccionar" #: byobu-export:171 msgid "File exists" msgstr "O ficheiro existe" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Remover ficheiro? [y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Seleccionar uma cor: " #: byobu-export:240 msgid "Profile" msgstr "Perfil" #: byobu-export:241 msgid "Archive" msgstr "Arquivo" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "Extraia o arquivo no seu directório pessoal no sistema de destino." #: byobu-select-profile:49 msgid "Error:" msgstr "Erro:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " o ficheiro existe, mas não é uma ligação simbólica" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Seleccionar um perfil do screen: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "ERRO: Selecção inválida" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Se está a usar o mapeamento de teclas por defeito, pressione\\n para " "activas as alterações.\\n\\nCaso contrário, abandone esta sessão do screen e " "inicie uma nova." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Execute \"byobu\" para activar" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "O Byobu é iniciado a quando do login (desactivar)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "O Byobu não é iniciado a quando do login (activar)" #: byobu-config:89 msgid "Help" msgstr "Ajuda" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Alterar o esquema de cores do Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Activar as notificações de estado" #: byobu-config:92 msgid "Change keybinding set" msgstr "Alterar o mapeamento de teclas" #: byobu-config:93 msgid "Change escape sequence" msgstr "Altere a sequência de escape" #: byobu-config:94 msgid "Create new windows" msgstr "Criar novas janelas" #: byobu-config:95 msgid "Manage default windows" msgstr "Gerir janelas por defeito" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Menu de configuração do Byobu" #: byobu-config:110 msgid "Okay" msgstr "Ok" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Cancelar" #: byobu-config:130 msgid "Byobu Help" msgstr "Ajuda do Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Aplicar" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Qual o perfil que deseja utilizar?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Qual o mapeamento de teclas que deseja utilizar?" #: byobu-config:175 msgid "Title: " msgstr "Título: " #: byobu-config:177 msgid "Command: " msgstr "Comando: " #: byobu-config:179 msgid "Presets: " msgstr "Pré-definições: " #: byobu-config:193 msgid "Add to default windows" msgstr "Adicionar às janelas por defeito" #: byobu-config:197 msgid "Create new window(s):" msgstr "Criar nova(s) janela(s):" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Activar notificações de estado:" #: byobu-config:368 msgid "Windows:" msgstr "Janelas:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Seleccionar a(s) janela(s) a criar por defeito:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "" "O Byobu vai ser iniciado automaticamente da próxima vez que efectuar login." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "O Byobu não vai ser utilizado da próxima vez que efectuar login." #: byobu-config:408 msgid "Message" msgstr "Mensagem" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "Tecla de escape: ctrl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Altere a sequência de escape:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "" "/ navega pelos elementos | selecciona | sai" byobu-7.15/po/pt_BR.po000066400000000000000000000116021522352767600145710ustar00rootroot00000000000000# Brazilian Portuguese translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2010-02-19 16:58+0000\n" "Last-Translator: alms21 \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-02-20 04:44+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Menu" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Escolher" #: byobu-export:171 msgid "File exists" msgstr "O arquivo já existe" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Remover arquivo? [s/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Selecione a cor: " #: byobu-export:240 msgid "Profile" msgstr "Perfil" #: byobu-export:241 msgid "Archive" msgstr "Arquivo" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "Extrair o arquivo na pasta pessoal como alvo do sistema." #: byobu-select-profile:49 msgid "Error:" msgstr "Erro:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr "" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "" #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "Erro: Seleção inválida" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Execute \"byobu\" para ativar" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu atualmente é executado ao logar (tornar desligado)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu atualmente não é executado ao logar (tornar ligado)" #: byobu-config:89 msgid "Help" msgstr "Ajuda" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Alterar cores do Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Alternar notificações de estado" #: byobu-config:92 msgid "Change keybinding set" msgstr "Alterar o conjunto de teclas de atalho" #: byobu-config:93 msgid "Change escape sequence" msgstr "Alterar sequência de escape" #: byobu-config:94 msgid "Create new windows" msgstr "Criar novas janelas" #: byobu-config:95 msgid "Manage default windows" msgstr "Gerenciar janelas padrões" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Configuração de menus Byobu" #: byobu-config:110 msgid "Okay" msgstr "Ok" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Cancelar" #: byobu-config:130 msgid "Byobu Help" msgstr "Ajuda Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Aplicar" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Qual o perfil que você gostaria de usar?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Qual conjunto de teclas de atalho você deseja utilizar?" #: byobu-config:175 msgid "Title: " msgstr "Título: " #: byobu-config:177 msgid "Command: " msgstr "Comando: " #: byobu-config:179 msgid "Presets: " msgstr "Pré-definições: " #: byobu-config:193 msgid "Add to default windows" msgstr "Adicionar as janelas padrões" #: byobu-config:197 msgid "Create new window(s):" msgstr "Criar nova janela(s):" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Alternar notificações de estado:" #: byobu-config:368 msgid "Windows:" msgstr "Janelas:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Selecione a janela(s) para criar por padrão:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu será executado automaticamente na próxima vez que você logar." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "Byobu não será usado na próxima vez que você logar." #: byobu-config:408 msgid "Message" msgstr "Mensagem" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "Tecla de escape: crtl-" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Alterar sequência de escape:" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "/ entre elementos | seleciona | finaliza" byobu-7.15/po/ru.po000066400000000000000000000141721522352767600142160ustar00rootroot00000000000000# translation of ru.po to # translation of byobu.po to # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # byobu , 2009. msgid "" msgstr "" "Project-Id-Version: ru\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2010-03-19 15:50+0000\n" "Last-Translator: Vadim Rutkovsky \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-03-20 04:48+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Меню" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Выбор" #: byobu-export:171 msgid "File exists" msgstr "Файл уже существует" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Удалить файл? (да/нет) " #: byobu-export:199 msgid "Select a color: " msgstr "Выберите цвет: " #: byobu-export:240 msgid "Profile" msgstr "Профиль" #: byobu-export:241 msgid "Archive" msgstr "" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "Распакуйте архив в ваш домашний раздел в целевой системе." #: byobu-select-profile:49 msgid "Error:" msgstr "Ошибка:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " файл существует, но это не симлинк" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Выберите профиль: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "ОШИБКА: неверный выбор" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Если Вы хотите использовать стандартный набор сочетаний клавиш, нажмите \\" "n для активации изменений.\\n\\nВ противном случае, выйдите из сессии и " "запустите еще одну." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Запустите \"byobu\" для активации" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu запускается при входе в систему (выключить)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu не запускается при входе в систему (включить)" #: byobu-config:89 msgid "Help" msgstr "Помощь" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Изменить цвета Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Переключатель состояния уведомлений" #: byobu-config:92 msgid "Change keybinding set" msgstr "Изменить привязки клавиш" #: byobu-config:93 msgid "Change escape sequence" msgstr "Изменение Escape-последовательности" #: byobu-config:94 msgid "Create new windows" msgstr "Создать новые окна" #: byobu-config:95 msgid "Manage default windows" msgstr "Управление окном по умолчанию" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Конфигурационное меню Byobu" #: byobu-config:110 msgid "Okay" msgstr "Ok" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "Отмена" #: byobu-config:130 msgid "Byobu Help" msgstr "Помощь Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Применить" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Какой профайл вы желаете использовать?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Какой набор привязок к клавишам хотели бы Вы использовать?" #: byobu-config:175 msgid "Title: " msgstr "Заголовок: " #: byobu-config:177 msgid "Command: " msgstr "Команда: " #: byobu-config:179 msgid "Presets: " msgstr "Задает: " #: byobu-config:193 msgid "Add to default windows" msgstr "Добавьте к окнам значения по умолчанию" #: byobu-config:197 msgid "Create new window(s):" msgstr "создать новое окно(а)" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "Переключатель состояния уведомлений:" #: byobu-config:368 msgid "Windows:" msgstr "Окно:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Выберите окно(на), чтобы создать по умолчанию:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu будет автоматически запущен при вашем следующем входе." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "Byobu не будет использоваться при следующем входе в систему." #: byobu-config:408 msgid "Message" msgstr "Сообщение" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "" #: byobu-config:451 msgid "Change escape sequence:" msgstr "Изменить Escape-последовательность" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "/ между элементами | выбор | выход" #~ msgid "Remove screen by default at login" #~ msgstr "Убрать screen из загрузки по умолчанию" #~ msgid "Exit" #~ msgstr "Выход" byobu-7.15/po/sv.po000066400000000000000000000120041522352767600142100ustar00rootroot00000000000000# Swedish translation for byobu # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2009. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-10-11 14:34-0500\n" "PO-Revision-Date: 2009-10-11 20:46+0000\n" "Last-Translator: Dustin Kirkland \n" "Language-Team: Swedish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-10-12 07:06+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:30 byobu-config:129 byobu-config:400 byobu-config:408 msgid "Menu" msgstr "Meny" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Välj" #: byobu-export:171 msgid "File exists" msgstr "Filen existerar" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Ta bort filen? [j/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Välj en färg: " #: byobu-export:237 msgid "Profile" msgstr "Profil" #: byobu-export:238 msgid "Archive" msgstr "Arkiv" #: byobu-export:240 msgid "Extract the archive in your home directory on the target system." msgstr "Extrahera arkivet i din hemkatalog på målsystemet." #: byobu-select-profile:49 msgid "Error:" msgstr "Fel:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " filen finns men är inte en symbolisk länk" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Välj en screen-profil: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "FEL: Ogiltigt val" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Om du använder standarduppsättningen för tangentbindningar,\\ntryck för " "att aktivera dessa ändringar.\\n\\nOm inte, avsluta denna screen-session och " "starta en ny." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Kör \"byobu\" för att aktivera" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu startas vid inloggning (inaktivera)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu startas inte vid inloggning (aktivera)" #: byobu-config:89 msgid "Help" msgstr "Hjälp" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Ändra Byobus färger" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Växla statusnotifieringar" #: byobu-config:92 msgid "Change keybinding set" msgstr "Ändra tangentbindningar" #: byobu-config:93 msgid "Change escape sequence" msgstr "Ändra escape-sekvens" #: byobu-config:94 msgid "Create new windows" msgstr "Skapa nya fönster" #: byobu-config:95 msgid "Manage default windows" msgstr "Hantera standardfönster" #: byobu-config:99 byobu-config:486 msgid " Byobu Configuration Menu" msgstr " Konfigurationsmeny för Byobu" #: byobu-config:110 msgid "Okay" msgstr "Okej" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:334 byobu-config:375 byobu-config:448 msgid "Cancel" msgstr "Avbryt" #: byobu-config:130 msgid "Byobu Help" msgstr "Hjälp för Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:334 #: byobu-config:375 byobu-config:448 msgid "Apply" msgstr "Verkställ" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Vilken profil vill du använda?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Vilken uppsättning tangentbindningar vill du använda?" #: byobu-config:175 msgid "Title: " msgstr "Titel: " #: byobu-config:177 msgid "Command: " msgstr "Kommando: " #: byobu-config:179 msgid "Presets: " msgstr "Förval: " #: byobu-config:193 msgid "Add to default windows" msgstr "Lägg till i standardfönster" #: byobu-config:197 msgid "Create new window(s):" msgstr "Skapa nya fönster:" #: byobu-config:335 msgid "Toggle status notifications:" msgstr "Växla statusnotifieringar:" #: byobu-config:367 msgid "Windows:" msgstr "Fönster:" #: byobu-config:377 msgid "Select window(s) to create by default:" msgstr "Välj fönster att skapa som standard:" #: byobu-config:397 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu kommer att startas automatiskt nästa gång du loggar in." #: byobu-config:405 msgid "Byobu will not be used next time you login." msgstr "Byobu kommer inte att användas nästa gång du loggar in." #: byobu-config:407 msgid "Message" msgstr "Meddelande" #: byobu-config:447 msgid "Escape key: ctrl-" msgstr "Escape-tangent: ctrl-" #: byobu-config:450 msgid "Change escape sequence:" msgstr "Ändra escape-sekvens:" #: byobu-config:487 msgid "/ between elements | selects | exits" msgstr "/ mellan element | väljer | avslutar" byobu-7.15/po/tr.po000066400000000000000000000114131522352767600142100ustar00rootroot00000000000000# Turkish translation for byobu # Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010 # This file is distributed under the same license as the byobu package. # FIRST AUTHOR , 2010. # msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-11-23 20:48-0600\n" "PO-Revision-Date: 2010-03-21 13:24+0000\n" "Last-Translator: Fethican Coşkuner \n" "Language-Team: Turkish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2010-03-22 04:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:34 byobu-config:129 byobu-config:401 byobu-config:409 msgid "Menu" msgstr "Menü" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Seç" #: byobu-export:171 msgid "File exists" msgstr "Dosya mevcut" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Dosyayı sil? [e/H] " #: byobu-export:199 msgid "Select a color: " msgstr "Bir renk seçin: " #: byobu-export:240 msgid "Profile" msgstr "Profil" #: byobu-export:241 msgid "Archive" msgstr "Arşiv" #: byobu-export:243 msgid "Extract the archive in your home directory on the target system." msgstr "" #: byobu-select-profile:49 msgid "Error:" msgstr "Hata:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " dosya mevcut fakat sembolik link değil" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Bir screen profili seçiniz: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "HATA: Geçersiz seçim" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Eğer ön tanımlı klavye kısayollarını kullanıyorsanız, değişiklikleri\\n " "etkinleştirmek için 'e basınız.\\n\\nAksi taktirde, bu screen " "oturumundan çıkarak yeni bir tane başlatınız." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Byobu varsayılan olarak girişte başlar (başlamayı devredışı bırak)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Byobu varsayılan olarak girişte başlamaz (başlamayı etkinleştir)" #: byobu-config:89 msgid "Help" msgstr "Yardım" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Byobu'nun renklerini değiştir" #: byobu-config:91 msgid "Toggle status notifications" msgstr "" #: byobu-config:92 msgid "Change keybinding set" msgstr "Klavye kısayollarını değiştir" #: byobu-config:93 msgid "Change escape sequence" msgstr "" #: byobu-config:94 msgid "Create new windows" msgstr "Yeni pencere yarat" #: byobu-config:95 msgid "Manage default windows" msgstr "Varsayılan pencereleri yönet" #: byobu-config:99 byobu-config:487 msgid " Byobu Configuration Menu" msgstr " Byobu Ayar Menüsü" #: byobu-config:110 msgid "Okay" msgstr "Tamam" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:335 byobu-config:376 byobu-config:449 msgid "Cancel" msgstr "İptal" #: byobu-config:130 msgid "Byobu Help" msgstr "Byobu Yardım" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:335 #: byobu-config:376 byobu-config:449 msgid "Apply" msgstr "Uygula" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Hangi profili kullanmak istersiniz?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "" #: byobu-config:175 msgid "Title: " msgstr "Başlık: " #: byobu-config:177 msgid "Command: " msgstr "Komut: " #: byobu-config:179 msgid "Presets: " msgstr "" #: byobu-config:193 msgid "Add to default windows" msgstr "Öntanımlı pencerelere akle" #: byobu-config:197 msgid "Create new window(s):" msgstr "Yeni pencere(ler) yarat:" #: byobu-config:336 msgid "Toggle status notifications:" msgstr "" #: byobu-config:368 msgid "Windows:" msgstr "Pencereler:" #: byobu-config:378 msgid "Select window(s) to create by default:" msgstr "Öntanımlı olarak yaratılacak pencereleri seçiniz:" #: byobu-config:398 msgid "Byobu will be launched automatically next time you login." msgstr "" "Byobu bir dahaki sefere giriş yaptığınızda otomatik olarak başlatılacak." #: byobu-config:406 msgid "Byobu will not be used next time you login." msgstr "" #: byobu-config:408 msgid "Message" msgstr "Mesaj" #: byobu-config:448 msgid "Escape key: ctrl-" msgstr "" #: byobu-config:451 msgid "Change escape sequence:" msgstr "" #: byobu-config:488 msgid "/ between elements | selects | exits" msgstr "" byobu-7.15/po/uk.po000066400000000000000000000140361522352767600142060ustar00rootroot00000000000000# Ukrainian translation for byobu # This file is distributed under the same license as the byobu package. # # Yuri Chornoivan , 2009. msgid "" msgstr "" "Project-Id-Version: byobu\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2009-10-11 14:34-0500\n" "PO-Revision-Date: 2009-11-11 16:45+0000\n" "Last-Translator: yurchor \n" "Language-Team: Ukrainian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2009-11-12 04:55+0000\n" "X-Generator: Launchpad (build Unknown)\n" #: bin/menu:30 byobu-config:129 byobu-config:400 byobu-config:408 msgid "Menu" msgstr "Меню" #: byobu-export:68 byobu-export:71 byobu-select-profile:104 #: byobu-select-profile:107 msgid "Choose" msgstr "Вибрати" #: byobu-export:171 msgid "File exists" msgstr "Файл вже існує" #: byobu-export:172 msgid "Remove file? [y/N] " msgstr "Вилучити файл? [т/Н - y/N] " #: byobu-export:199 msgid "Select a color: " msgstr "Оберіть колір: " #: byobu-export:237 msgid "Profile" msgstr "Профіль" #: byobu-export:238 msgid "Archive" msgstr "Архів" #: byobu-export:240 msgid "Extract the archive in your home directory on the target system." msgstr "Видобути архів до вашого домашнього каталогу на системі призначення." #: byobu-select-profile:49 msgid "Error:" msgstr "Помилка:" #: byobu-select-profile:49 msgid " file exists, but is not a symlink" msgstr " файл вже існує, але не є символічним посиланням" #: byobu-select-profile:80 msgid "Select a screen profile: " msgstr "Оберіть профіль екрана: " #: byobu-select-profile:97 msgid "ERROR: Invalid selection" msgstr "Помилка: некоректний вибір" #: byobu-select-profile:134 msgid "" "If you are using the default set of keybindings, press\\n to activate " "these changes.\\n\\nOtherwise, exit this screen session and start a new one." msgstr "" "Якщо ви користуєтеся типовим набором клавіатурних скорочень, натисніть\\" "n, щоб задіяти ці зміни.\\n\\nКрім того, ви можете завершити екранний " "сеанс і розпочати новий." #: byobu-select-profile:136 msgid "Run \"byobu\" to activate" msgstr "Віддайте команду «byobu», щоб задіяти" #: byobu-config:83 msgid "Byobu currently launches at login (toggle off)" msgstr "Зараз byobu запускається при вході (вимкнути)" #: byobu-config:85 msgid "Byobu currently does not launch at login (toggle on)" msgstr "Зараз byobu не запускається при вході (увімкнути)" #: byobu-config:89 msgid "Help" msgstr "Довідка" #: byobu-config:90 msgid "Change Byobu's colors" msgstr "Змінити кольори Byobu" #: byobu-config:91 msgid "Toggle status notifications" msgstr "Увімкнути або вимкнути сповіщення" #: byobu-config:92 msgid "Change keybinding set" msgstr "Змінити набір скорочень" #: byobu-config:93 msgid "Change escape sequence" msgstr "Змінити керівну послідовність" #: byobu-config:94 msgid "Create new windows" msgstr "Створити вікна" #: byobu-config:95 msgid "Manage default windows" msgstr "Керування типовими вікнами" #: byobu-config:99 byobu-config:486 msgid " Byobu Configuration Menu" msgstr " Меню налаштування Byobu" #: byobu-config:110 msgid "Okay" msgstr "Гаразд" #: byobu-config:110 byobu-config:144 byobu-config:161 byobu-config:195 #: byobu-config:334 byobu-config:375 byobu-config:448 msgid "Cancel" msgstr "Скасувати" #: byobu-config:130 msgid "Byobu Help" msgstr "Довідка Byobu" #: byobu-config:144 byobu-config:161 byobu-config:195 byobu-config:334 #: byobu-config:375 byobu-config:448 msgid "Apply" msgstr "Застосувати" #: byobu-config:146 msgid "Which profile would you like to use?" msgstr "Яким з профілів би бажаєте скористатися?" #: byobu-config:162 msgid "Which set of keybindings would you like to use?" msgstr "Який з наборів клавіатурних скорочень ви бажаєте використовувати?" #: byobu-config:175 msgid "Title: " msgstr "Назва: " #: byobu-config:177 msgid "Command: " msgstr "Команда: " #: byobu-config:179 msgid "Presets: " msgstr "Шаблони: " #: byobu-config:193 msgid "Add to default windows" msgstr "Додати до типових вікон" #: byobu-config:197 msgid "Create new window(s):" msgstr "Створити вікна:" #: byobu-config:335 msgid "Toggle status notifications:" msgstr "Увімкнути або вимкнути сповіщення:" #: byobu-config:367 msgid "Windows:" msgstr "Вікна:" #: byobu-config:377 msgid "Select window(s) to create by default:" msgstr "Оберіть вікна, які слід створити:" #: byobu-config:397 msgid "Byobu will be launched automatically next time you login." msgstr "Byobu буде автоматично запущено під час наступного входу до системи." #: byobu-config:405 msgid "Byobu will not be used next time you login." msgstr "Byobu не буде використано під час наступного входу до системи." #: byobu-config:407 msgid "Message" msgstr "Повідомлення" #: byobu-config:447 msgid "Escape key: ctrl-" msgstr "Керівна клавіша: ctrl-" #: byobu-config:450 msgid "Change escape sequence:" msgstr "Змінити керівну послідовність:" #: byobu-config:487 msgid "/ between elements | selects | exits" msgstr "" "/ між елементами | обирає | завершує роботу" byobu-7.15/rpm/000077500000000000000000000000001522352767600134035ustar00rootroot00000000000000byobu-7.15/rpm/byobu.spec000066400000000000000000000122201522352767600153740ustar00rootroot00000000000000%global _iconstheme hicolor %global _iconsbasedir %{_datadir}/icons/%{_iconstheme} %global _iconsscaldir %{_iconsbasedir}/scalable/apps %global trustmuxlibdir %{_prefix}/lib/trustmux Name: byobu Version: 7.11 Release: 1%{?dist} Summary: Light-weight, configurable window manager built upon GNU screen License: GPL-3.0-only URL: https://github.com/dustinkirkland/byobu Source0: %{url}/archive/refs/tags/%{version}.tar.gz#/%{name}-%{version}.tar.gz # Default windows examples (Fedora-specific) Source1: fedoracommon BuildArch: noarch BuildRequires: automake BuildRequires: desktop-file-utils BuildRequires: make BuildRequires: gettext BuildRequires: python3-devel Requires: bc Requires: gettext Requires: newt Requires: openssl Requires: python3-cryptography Requires: python3-newt Requires: python3-tornado Requires: screen Requires: tmux %description Byobu is a Japanese term for decorative, multi-panel screens that serve as folding room dividers. As an open source project, Byobu is an elegant enhancement of the otherwise functional, plain, practical GNU Screen. Byobu includes an enhanced profile and configuration utilities for the GNU screen window manager, such as toggle-able system status notifications. %prep %autosetup # remove swap file rm -f usr/bin/.byobu-status-print.swp # fix path for lib directory in scripts grep -rl '{BYOBU_PREFIX}/lib/' . | xargs sed -i "s#{BYOBU_PREFIX}/lib/#{BYOBU_PREFIX}/libexec/#g" grep -rl 'BYOBU_PREFIX/lib' . | xargs sed -i "s#BYOBU_PREFIX/lib/#BYOBU_PREFIX/libexec/#g" # fix path for correct directory in /usr/share sed -i "s#DOC = BYOBU_PREFIX + '/share/doc/' + PKG#DOC='%{_docdir}/%{name}'#g" usr/lib/byobu/include/config.py.in # set default fedora windows cp -p %{SOURCE1} usr/share/byobu/windows/common # fix path from lib to libexec by modified Makefile.am and in sed -i "s#/lib/#/libexec/#g" usr/lib/byobu/Makefile.am sed -i "s#/lib/#/libexec/#g" usr/lib/byobu/include/Makefile.am %build export BYOBU_PYTHON=%{__python3} autoreconf -fiv %configure %make_build %install %make_install # remove apport which is not available in fedora rm %{buildroot}%{_libexecdir}/%{name}/apport sed -i 's#status\[\"apport\"\]=0##g' %{buildroot}%{_bindir}/byobu-config # install translations manually as the Makefile doesn't do it for po in po/*.po do lang=${po#po/} lang=${lang%.po} mkdir -p %{buildroot}%{_datadir}/locale/${lang}/LC_MESSAGES/ msgfmt ${po} -o %{buildroot}%{_datadir}/locale/${lang}/LC_MESSAGES/%{name}.mo done %find_lang %{name} # use the old xterm .desktop style for while cp -a usr/share/%{name}/desktop/%{name}.desktop.old usr/share/%{name}/desktop/%{name}.desktop desktop-file-install usr/share/%{name}/desktop/%{name}.desktop --dir %{buildroot}%{_datadir}/applications # remove vigpg rm %{buildroot}%{_bindir}/vigpg rm %{buildroot}%{_mandir}/man1/vigpg.1* # add icon into /usr/share/icons/hicolor/scalable/apps/ from /usr/share/byobu/pixmaps/byobu.svg install -D -p -m 0644 usr/share/byobu/pixmaps/byobu.svg %{buildroot}%{_iconsscaldir}/%{name}.svg # fix shebangs find %{buildroot}%{_bindir} -type f ! -xtype l | while read -r f; do grep -Iq python "$f" && %py3_shebang_fix "$f" done find %{buildroot}%{_libexecdir}/%{name} -type f ! -xtype l | while read -r f; do grep -Iq python "$f" && %py3_shebang_fix "$f" done %py3_shebang_fix %{buildroot}%{trustmuxlibdir}/trustmux/_daemon.py # install README.md manually to the doc dir install -d %{buildroot}%{_docdir}/%{name} cp -p README.md %{buildroot}%{_docdir}/%{name}/ # remove empty profile.d rm -rf %{buildroot}%{_sysconfdir}/profile.d %check desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop %files -f %{name}.lang %license COPYING %{_docdir}/%{name}/ %{_bindir}/%{name}* %{_bindir}/col1 %{_bindir}/ctail %{_bindir}/manifest %{_bindir}/purge-old-kernels %{_bindir}/wifi-status %{_datadir}/%{name}/ %{_datadir}/applications/%{name}.desktop %{_datadir}/sounds/%{name}/ %{_datadir}/dbus-1/services/us.kirkland.terminals.byobu.service %{_iconsscaldir}/%{name}.svg %{_mandir}/man1/%{name}*.1* %{_mandir}/man1/col1.1* %{_mandir}/man1/ctail.1* %{_mandir}/man1/manifest.1* %{_mandir}/man1/purge-old-kernels.1* %{_mandir}/man1/wifi-status.1* %{_libexecdir}/%{name}/ %config(noreplace) %{_sysconfdir}/%{name}/ # trustmux files %{_bindir}/trustmux %{_bindir}/trustmuxd %{trustmuxlibdir}/trustmux/__init__.py %{trustmuxlibdir}/trustmux/__main__.py %{trustmuxlibdir}/trustmux/_ctl.py %{trustmuxlibdir}/trustmux/_daemon.py %{trustmuxlibdir}/trustmux/_disable.py %{trustmuxlibdir}/trustmux/_enable.py %{trustmuxlibdir}/trustmux/_pair.py %{trustmuxlibdir}/trustmux/_unpair.py %{_datadir}/bash-completion/completions/trustmux %{_mandir}/man1/trustmux.1.gz %{_mandir}/man1/trustmuxd.1.gz %{_datadir}/trustmux/static/app.js %{_datadir}/trustmux/static/index.html %{_datadir}/trustmux/static/sw.js %{_datadir}/trustmux/static/trustmux-logo.svg %{_datadir}/trustmux/static/trustmux.svg %{_datadir}/trustmux/static/icons/icon-192.png %{_datadir}/trustmux/static/icons/icon-512.png %changelog * Wed Jun 10 2026 Dustin Kirkland - 7.11-1 - Update to 7.11; add trustmux files; import spec from Fedora dist-git (maintained by Filipe Rosset ) byobu-7.15/rpm/fedoracommon000066400000000000000000000001351522352767600157760ustar00rootroot00000000000000# Default windows examples #screen -t top top #screen -t web w3m #screen -t shell motd+shell byobu-7.15/testing/000077500000000000000000000000001522352767600142625ustar00rootroot00000000000000byobu-7.15/testing/docker/000077500000000000000000000000001522352767600155315ustar00rootroot00000000000000byobu-7.15/testing/docker/DOCKER-TESTING.md000066400000000000000000000044571522352767600201470ustar00rootroot00000000000000# Byobu 6.14 Docker Test Containers Both test containers are ready! ## Quick Launch Commands ### Ubuntu 24.04 Container ```bash docker run -it --rm byobu-ubuntu:6.14 ``` ### Wolfi/Chainguard Container ```bash docker run -it --rm byobu-wolfi:6.14 ``` ## What's Been Tested This byobu 6.14 build includes: ### 10 PRs Merged: - PR #68: stderr fix for prompt runtime - PR #63: expr syntax error fix - PR #64: help screen LESS variable fix - PR #67: README typo fix - PR #70: version management with autoconf - PR #55: home directory ownership test - PR #42: systemd support - PR #36: OpenDNS with wget fallback - PR #74: Oracle Linux logo - PR #69: automake dist directives ### 6 Issues Fixed: - Issue #83: byobu -v now works - Issue #75: no permission denied outside byobu - Issue #72: git:// → https:// in README - Issue #73: Arch Linux updates detection - Issue #80: prompt runtime display (closed) - Issue #84: multiline editing (closed) ## Testing Inside Containers Once inside a container, test these features: ### Basic Functionality ```bash # Check version byobu -v # Launch byobu byobu # Inside byobu, test: # - F2: Create new window # - F3/F4: Navigate windows # - F6: Detach from session # - F9: Configuration menu # - Ctrl+a d: Detach (alternative) ``` ### Test Specific Fixes **Issue #83 - Version command:** ```bash byobu -v # Should display: byobu version 6.14 ``` **Issue #75 - No permission errors:** ```bash # Exit byobu and run commands exit ls # Should not see "Permission denied" errors ``` **Issue #68 - Prompt runtime:** ```bash # Inside byobu, commands should show runtime like [0.002s] # And NOT cause line wrapping issues ``` **Help screen:** ```bash # Press F1 or Shift+F1 # Help should display and not disappear ``` ## Container Details ### Ubuntu 24.04 Container - Base: ubuntu:24.04 - User: testuser - Shell: /bin/bash - Byobu: Auto-enabled on login ### Wolfi/Chainguard Container - Base: cgr.dev/chainguard/wolfi-base:latest - User: nonroot - Shell: /bin/bash - Byobu: Installed, ready to launch ## Rebuilding If you need to rebuild the containers: ```bash # Ubuntu docker build -t byobu-ubuntu:6.14 -f Dockerfile.ubuntu . # Wolfi docker build -t byobu-wolfi:6.14 -f Dockerfile.wolfi . ``` ## Clean Up Remove test containers when done: ```bash docker rmi byobu-ubuntu:6.14 byobu-wolfi:6.14 ``` byobu-7.15/testing/docker/Dockerfile.ubuntu000066400000000000000000000011641522352767600210460ustar00rootroot00000000000000FROM ubuntu:24.04 # Install dependencies RUN apt-get update && apt-get install -y \ tmux \ screen \ git \ automake \ autoconf \ make \ gcc \ gawk \ python3 \ && rm -rf /var/lib/apt/lists/* # Copy byobu source COPY . /tmp/byobu-src WORKDIR /tmp/byobu-src # Build and install RUN ./autogen.sh && \ ./configure --prefix=/usr --sysconfdir=/etc && \ make && \ make install # Create a test user RUN useradd -m -s /bin/bash testuser # Set up byobu for test user USER testuser WORKDIR /home/testuser # Enable byobu by default RUN byobu-launcher-install CMD ["/bin/bash", "-l"] byobu-7.15/testing/docker/Dockerfile.wolfi000066400000000000000000000011221522352767600206360ustar00rootroot00000000000000FROM cgr.dev/chainguard/wolfi-base:latest # Install dependencies RUN apk add --no-cache \ tmux \ bash \ git \ automake \ autoconf \ make \ gawk \ python-3 \ coreutils \ grep \ sed # Copy byobu source COPY . /tmp/byobu-src WORKDIR /tmp/byobu-src # Build and install RUN ./autogen.sh && \ ./configure --prefix=/usr --sysconfdir=/etc && \ make && \ make install # Create a test user (Wolfi/Chainguard uses nonroot by default) USER nonroot WORKDIR /home/nonroot # Enable byobu RUN byobu-launcher-install || true CMD ["/bin/bash", "-l"] byobu-7.15/testing/docker/README.md000066400000000000000000000034621522352767600170150ustar00rootroot00000000000000# Byobu Docker Testing This directory contains Docker configurations for testing byobu across different platforms. ## Files - `Dockerfile.ubuntu` - Ubuntu 24.04 test container - `Dockerfile.wolfi` - Wolfi/Chainguard test container - `test-containers.sh` - Helper script to build and run containers - `DOCKER-TESTING.md` - Detailed testing documentation ## Quick Start ### Build Both Images From the repository root: ```bash # Ubuntu 24.04 docker build -t byobu-ubuntu:6.14 -f testing/docker/Dockerfile.ubuntu . # Wolfi/Chainguard docker build -t byobu-wolfi:6.14 -f testing/docker/Dockerfile.wolfi . ``` Or use the helper script: ```bash cd testing/docker ./test-containers.sh ``` ### Run Containers **Ubuntu 24.04:** ```bash docker run -it --rm byobu-ubuntu:6.14 ``` **Wolfi/Chainguard:** ```bash docker run -it --rm byobu-wolfi:6.14 ``` ## What's Tested These containers build and install byobu 6.14 from source, including: - All merged PRs (10 total) - All fixed issues (6 total) - Full build process verification - Runtime functionality testing ## Testing Checklist Inside each container: 1. **Version check**: `byobu -v` 2. **Launch**: `byobu` 3. **Key bindings**: F2, F3, F4, F6, F9 4. **Help screen**: F1 (should not disappear) 5. **Prompt runtime**: Should show command execution time 6. **No errors**: Exit byobu and verify no permission errors See `DOCKER-TESTING.md` for complete testing instructions. ## Container Specifications ### Ubuntu 24.04 - Base image: `ubuntu:24.04` - User: `testuser` (non-root) - Shell: `/bin/bash` - Byobu: Auto-enabled on login ### Wolfi/Chainguard - Base image: `cgr.dev/chainguard/wolfi-base:latest` - User: `nonroot` - Shell: `/bin/bash` - Byobu: Installed, manual launch ## Clean Up Remove test images when done: ```bash docker rmi byobu-ubuntu:6.14 byobu-wolfi:6.14 ``` byobu-7.15/testing/docker/test-containers.sh000077500000000000000000000020451522352767600212130ustar00rootroot00000000000000#!/bin/bash # Byobu 6.14 Container Test Script echo "Byobu 6.14 Test Containers" echo "============================" echo "" # Check if images exist if ! docker image inspect byobu-ubuntu:6.14 >/dev/null 2>&1; then echo "⚠️ Ubuntu image not found. Building..." docker build -t byobu-ubuntu:6.14 -f Dockerfile.ubuntu . fi if ! docker image inspect byobu-wolfi:6.14 >/dev/null 2>&1; then echo "⚠️ Wolfi image not found. Building..." docker build -t byobu-wolfi:6.14 -f Dockerfile.wolfi . fi echo "" echo "✅ Docker images ready!" echo "" echo "Launch Commands:" echo "================" echo "" echo "Ubuntu 24.04 Container:" echo " docker run -it --rm byobu-ubuntu:6.14" echo "" echo "Wolfi/Chainguard Container:" echo " docker run -it --rm byobu-wolfi:6.14" echo "" echo "Test Byobu Inside Container:" echo " 1. Run: byobu" echo " 2. Check version: byobu -v" echo " 3. Test features:" echo " - F2 = new window" echo " - F3/F4 = navigate windows" echo " - F6 = detach" echo " - F9 = configuration menu" echo "" byobu-7.15/usr/000077500000000000000000000000001522352767600134165ustar00rootroot00000000000000byobu-7.15/usr/bin/000077500000000000000000000000001522352767600141665ustar00rootroot00000000000000byobu-7.15/usr/bin/Makefile.am000066400000000000000000000012731522352767600162250ustar00rootroot00000000000000dist_bin_SCRIPTS = byobu byobu-config byobu-ctrl-a byobu-disable byobu-disable-prompt byobu-enable byobu-enable-prompt byobu-export byobu-janitor byobu-keybindings byobu-launch byobu-launcher byobu-launcher-install byobu-launcher-uninstall byobu-layout byobu-prompt byobu-quiet byobu-reconnect-sockets byobu-select-backend byobu-select-profile byobu-select-session byobu-silent byobu-status byobu-status-detail byobu-shell byobu-ugraph byobu-ulevel col1 ctail wifi-status vigpg manifest purge-old-kernels install-exec-hook: cd $(DESTDIR)$(bindir) && rm -f byobu-screen && $(LN_S) byobu byobu-screen cd $(DESTDIR)$(bindir) && rm -f byobu-tmux && $(LN_S) byobu byobu-tmux byobu-7.15/usr/bin/byobu-config.in000077500000000000000000000017501522352767600171070ustar00rootroot00000000000000#!/bin/sh -e # # byobu-config - interactive byobu configuration wrapper script # Copyright (C) 2013-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" ${BYOBU_PYTHON} "${BYOBU_PREFIX}/lib/${PKG}/include/config.py" byobu-7.15/usr/bin/byobu-ctrl-a.in000077500000000000000000000112521522352767600170220ustar00rootroot00000000000000#!/bin/sh # # byobu-ctrl-a - set the ctrl-a behavior # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . Usage() { cat </dev/null | grep -qs "^bind-key\s\+[^a]\s\+send-prefix"; then bind_to="emacs" fi ;; esac case "${1}" in -h|--help) Usage; exit 0;; screen) bind_to="screen";; emacs) bind_to="emacs";; "") :;; *) { Usage printf "%s\n" "Bad argument $1"; } 1>&2; exit 1;; esac if [ "${2}" ]; then KEY=$(printf "$2" | $BYOBU_SED 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/') key=$(printf "$2" | $BYOBU_SED 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/') else KEY="A" key="a" fi while [ -z "$bind_to" ]; do echo echo "Configure Byobu's ctrl-a behavior..." echo echo "When you press ctrl-a in Byobu, do you want it to operate in:" echo " (1) Screen mode (GNU Screen's default escape sequence)" echo " (2) Emacs mode (go to beginning of line)" echo echo "Note that:" echo " - F12 also operates as an escape in Byobu" echo " - You can press F9 and choose your escape character" echo " - You can run 'byobu-ctrl-a' at any time to change your selection" echo printf "Select [1 or 2]: " s=$(head -n1) echo case "$s" in 1) bind_to="screen"; break;; 2) bind_to="emacs"; break;; esac done case "$bind_to" in emacs) case "$BYOBU_BACKEND" in screen) $BYOBU_SED_INLINE -e "/^register x /d" -e "/^bindkey /d" -e "/^escape /d" "$keybindings" echo "bindkey \"^${KEY}\"" >> "$keybindings" $BYOBU_BACKEND -X at 0 source "$BYOBU_CONFIG_DIR/profile" ;; tmux) $BYOBU_SED_INLINE -e "/^set -g prefix/d" -e "/ send-prefix/d" -e "/^unbind-key -n C-${key}/d" "$keybindings" echo "set -g prefix F12" >> "$keybindings" echo "unbind-key -n C-${key}" >> "$keybindings" $BYOBU_BACKEND source "$BYOBU_PREFIX/share/byobu/profiles/tmuxrc" 2>/dev/null ;; esac echo "INFO: ctrl-a will now operate in emacs mode" ;; screen) case "$BYOBU_BACKEND" in screen) $BYOBU_SED_INLINE -e "/^register x /d" -e "/^bindkey \"^\"/d" -e "/^escape /d" "$keybindings" echo "bindkey \"^${KEY}\"" >> "$keybindings" echo "escape \"^${KEY}${key}\"" >> "$keybindings" echo "register x \"^${KEY}\"" >> "$keybindings" $BYOBU_BACKEND -X at 0 source "$BYOBU_CONFIG_DIR/profile" ;; tmux) $BYOBU_SED_INLINE -e "/^set -g prefix/d" -e "/ send-prefix/d" -e "/^unbind-key -n C-${key}/d" "$keybindings" echo "unbind-key -n C-${key}" >> "$keybindings" if $BYOBU_BACKEND -V | grep " 1.5"; then # tmux 1.5 supports a list of prefixes echo "set -g prefix ^${KEY},F12" >> "$keybindings" else # tmux 1.6 and above supports prefix and prefix2 echo "set -g prefix ^${KEY}" >> "$keybindings" echo "set -g prefix2 F12" >> "$keybindings" fi echo "bind ${key} send-prefix" >> "$keybindings" $BYOBU_BACKEND source "$BYOBU_PREFIX/share/byobu/profiles/tmuxrc" 2>/dev/null ;; esac echo "INFO: ctrl-a will now operate in GNU Screen mode" ;; *) echo "Error: bad value for binding: $bind_to" ;; esac if [ -z "${2}" ]; then echo "To modify this behavior again later, run 'byobu-ctrl-a'" echo fi # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-disable-prompt.in000077500000000000000000000025011522352767600205570ustar00rootroot00000000000000#!/bin/sh -e # # byobu-disable-prompt # Copyright (C) 2013-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" [ -w "$HOME/.bashrc" ] || exit 1 $BYOBU_SED_INLINE -e "/#byobu-prompt#$/d" "$HOME/.bashrc" if [ "$1" != "--no-reload" ]; then if [ -n "$TMUX" ] && [ "$SHELL" = "/bin/bash" ]; then tmux send-keys " . ~/.bashrc" \; send-keys Enter else echo echo "You will need to reload your shell configuration for this to take effect..." echo " . ~/.bashrc" echo fi fi # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-disable.in000077500000000000000000000024231522352767600172430ustar00rootroot00000000000000#!/bin/sh -e # # byobu-disable: disable byobu at login # Copyright (C) 2010 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" byobu-launcher-uninstall echo echo "The Byobu window manager will no longer be launched automatically at login." echo echo "To re-enable this behavior later, just run:" echo " byobu-enable" echo # If we're in a byobu session, let's exit that too case "$STY" in *byobu) $BYOBU_BACKEND -X at 0 quit ;; esac # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-enable-prompt.in000077500000000000000000000026611522352767600204110ustar00rootroot00000000000000#!/bin/sh -e # # byobu-enable-prompt # Copyright (C) 2013-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . [ "$SHELL" = "/bin/bash" ] || exit 1 PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" prompt="${BYOBU_CONFIG_DIR}/prompt" printf ". ${BYOBU_PREFIX}/share/${PKG}/profiles/bashrc #byobu-prompt#\n" > "$prompt" $PKG-disable-prompt --no-reload "$1" || true printf "[ -r $prompt ] && . $prompt #byobu-prompt#\n" >> "$HOME/.bashrc" if [ -n "$TMUX" ]; then tmux send-keys " . ~/.bashrc" \; send-keys Enter else echo echo "You will need to reload your shell configuration for this to take effect..." echo " . ~/.bashrc" echo fi # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-enable.in000077500000000000000000000022421522352767600170650ustar00rootroot00000000000000#!/bin/sh -e # # byobu-enable: enable launch byobu at login # Copyright (C) 2010 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" byobu-launcher-install echo echo "The Byobu window manager will be launched automatically at each text login." echo echo "To disable this behavior later, just run:" echo " byobu-disable" echo # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-export.in000077500000000000000000000026211522352767600171610ustar00rootroot00000000000000#!/bin/sh -e # # byobu-export # Copyright (C) 2008-2010 Canonical Ltd. # Copyright (C) 2023 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" if eval $BYOBU_TEST gettext >/dev/null 2>&1; then command=gettext else command=echo fi $command " The byobu-export utility is now deprecated. To install byobu on a system for which byobu is not packaged, or where you are not the root user, simply: * Download the latest release (>= 3.0) from: https://github.com/dustinkirkland/byobu * And follow the instructions in the README " # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-janitor.in000077500000000000000000000176001522352767600173110ustar00rootroot00000000000000#!/bin/sh -e # # byobu-janitor - a collection of byobu tasks that ensure a clean # environtment and smooth upgrades # # Copyright (C) 2009 Canonical Ltd. # Copyright (C) 2024 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" # Ensure that all updates get run immediately rm -rf "$BYOBU_RUN_DIR/.last.$BYOBU_BACKEND" # Ensure that we re-check metadata service rm -f "$BYOBU_CONFIG_DIR/.metadata_available" "$BYOBU_RUN_DIR/.metadata_available" 2>/dev/null || true # Exit immediately, if we're not forced, and there is no reload flag FLAG="$BYOBU_RUN_DIR/reload-required" if [ "$1" != "--force" ] && [ ! -e "$FLAG" ]; then exit 0 fi # Set the rest of the variables DEFAULT_PROFILE="light" PROFILE="$BYOBU_CONFIG_DIR/profile" # Create byobu-exchange buffer file, with secure permissions, if it doesn't exist if ! [ -e "$BYOBU_RUN_DIR/printscreen" ]; then if eval $BYOBU_TEST install >/dev/null 2>&1; then install -m 600 /dev/null "$BYOBU_RUN_DIR/printscreen" else cp /dev/null "$BYOBU_RUN_DIR/printscreen" chmod 600 "$BYOBU_RUN_DIR/printscreen" fi fi # Affects: users who launched using sudo, such that their config dir # is not writable by them if [ -d "$BYOBU_CONFIG_DIR" ] && [ ! -w "$BYOBU_CONFIG_DIR" ]; then echo "ERROR: [$BYOBU_CONFIG_DIR] is not writable by the current user" 1>&2 exit 1 fi # Affects: Upgrades from <= byobu 4.30 # Clear out old style status configuration if ! grep -qs "^screen_upper_left=" "$BYOBU_CONFIG_DIR/status"; then rm -f "$BYOBU_CONFIG_DIR/status" "$BYOBU_CONFIG_DIR/statusrc" fi # NOTE: Older version of Screen have an arbitrary limit of only being able # to change colors 16 times in this 'hardstatus string'. # Also committed in Upstream git, but not yet released. # * http://savannah.gnu.org/bugs/?22146 # If we could reliably tell if we had a patched screen, we'd do so here... MC=0 # Affects: First runs with no configuration # Seed the configuration # Setup initial local user configuration [ -r "$BYOBU_CONFIG_DIR/color" ] || printf "BACKGROUND=k\nFOREGROUND=w\nMONOCHROME=$MC" > "$BYOBU_CONFIG_DIR/color" [ -r "$BYOBU_CONFIG_DIR/color.tmux" ] || sed -e "s/^#.*//" -e "/^\s*$/d" -e "s/^export //" "$BYOBU_PREFIX/lib/$PKG/include/colors" > "$BYOBU_CONFIG_DIR/color.tmux" # Affects: tmux 3.6 rejects \#RRGGBB hex escape — strip the backslash (GH: #105) # Skip sed -i if color.tmux is a symlink — sed -i replaces symlinks with regular files (GH: #112) [ -L "$BYOBU_CONFIG_DIR/color.tmux" ] || sed -i 's/="\\#/="#/g' "$BYOBU_CONFIG_DIR/color.tmux" 2>/dev/null || true [ -r "$BYOBU_CONFIG_DIR/datetime.tmux" ] || printf 'BYOBU_DATE="%%Y-%%m-%%d "\nBYOBU_TIME="%%H:%%M:%%S"\n' > "$BYOBU_CONFIG_DIR/datetime.tmux" [ -r "$BYOBU_CONFIG_DIR/profile" ] || echo "source \$BYOBU_PREFIX/share/$PKG/profiles/common" > "$BYOBU_CONFIG_DIR/profile" [ -r "$BYOBU_CONFIG_DIR/profile.tmux" ] || echo "source \$BYOBU_PREFIX/share/$PKG/profiles/tmux" > "$BYOBU_CONFIG_DIR/profile.tmux" [ -r "$BYOBU_CONFIG_DIR/keybindings" ] || echo "source \$BYOBU_PREFIX/share/$PKG/keybindings/common" > "$BYOBU_CONFIG_DIR/keybindings" [ -r "$BYOBU_CONFIG_DIR/keybindings.tmux" ] || touch "$BYOBU_CONFIG_DIR/keybindings.tmux" [ -r "$BYOBU_CONFIG_DIR/windows" ] || touch "$BYOBU_CONFIG_DIR/windows" [ -r "$BYOBU_CONFIG_DIR/windows.tmux" ] || touch "$BYOBU_CONFIG_DIR/windows.tmux" [ -r "$BYOBU_CONFIG_DIR/backend" ] || echo "BYOBU_BACKEND=$BYOBU_BACKEND" > "$BYOBU_CONFIG_DIR/backend" [ -r "$BYOBU_CONFIG_DIR/.screenrc" ] || touch "$BYOBU_CONFIG_DIR/.screenrc" [ -r "$BYOBU_CONFIG_DIR/.tmux.conf" ] || touch "$BYOBU_CONFIG_DIR/.tmux.conf" # BYOBU_SHELL_ARGS: if set in statusrc, write a shellinit.tmux that overrides # tmux's default-command so new windows/panes start with those args (e.g. # --login to source /etc/profile.d). LP: #1618516 [ -r "$BYOBU_CONFIG_DIR/statusrc" ] && . "$BYOBU_CONFIG_DIR/statusrc" 2>/dev/null || true _shellinit="$BYOBU_CONFIG_DIR/shellinit.tmux" if [ -n "$BYOBU_SHELL_ARGS" ]; then printf 'set -g default-command "exec $SHELL %s"\n' "$BYOBU_SHELL_ARGS" > "$_shellinit" else [ -f "$_shellinit" ] || touch "$_shellinit" fi unset _shellinit for f in status statusrc; do if [ ! -r "$BYOBU_CONFIG_DIR/$f" ]; then # Copy from skeleton, if possible cp -f "$BYOBU_PREFIX/share/$PKG/status/$f" "$BYOBU_CONFIG_DIR/$f" # If we're running in Wolfi for the first time, cycle to the 2nd status [ "$f" = "status" ] && [ "$BYOBU_DISTRO" = "Wolfi" ] && $BYOBU_PREFIX/lib/byobu/include/cycle-status fi done # Affects: Upgrades from <= byobu-2.70 that autolaunch # Update the byobu-launch line, if necessary if grep -qs " $PKG-launch$" "$HOME"/.profile; then $PKG-launcher-install fi # Affects: Upgrades from <= byobu-2.78 which might have "motd+shell" # in their window list; update this to just "shell" if grep -qs "motd+shell" "$BYOBU_CONFIG_DIR/windows"; then $BYOBU_SED_INLINE -e "s/motd+shell/shell/g" "$($BYOBU_READLINK -f $BYOBU_CONFIG_DIR/windows)" || true fi # Affects: Upgrades from <= byobu 4.3, remove ec2_rates rm -f "$BYOBU_CONFIG_DIR/ec2_rates" # Affects: Upgrades from <= byobu 4.4, update "shell" -> "byobu-shell" if grep -qs " shell$" "$BYOBU_CONFIG_DIR/windows"; then $BYOBU_SED_INLINE -e "s/ shell$/ $PKG-shell/g" "$($BYOBU_READLINK -f $BYOBU_CONFIG_DIR/windows)" || true fi # Affects: Upgrades from <= byobu 4.22 killall -u $USER byobu-statusd >/dev/null 2>&1 || true # Clean up flag (new and old) rm -f "$FLAG" "/var/run/screen/S-$USER/$PKG.reload-required" # Affects: Upgrades from <= byobu 5.50, install byobu prompt if using stock bashrc if [ -r /etc/skel/.bashrc ] && [ -r "$HOME/.bashrc" ] && [ -w "$HOME/.bashrc" ] && \ ! (grep -qs "#byobu-prompt#$" "$HOME/.bashrc") && ! [ -e "$BYOBU_CONFIG_DIR/prompt" ]; then if eval $BYOBU_TEST diff >/dev/null 2>&1; then if diff /etc/skel/.bashrc "$HOME/.bashrc" >/dev/null 2>&1; then printf "[ -r $BYOBU_CONFIG_DIR/prompt ] && . $BYOBU_CONFIG_DIR/prompt #byobu-prompt#\n" >> "$HOME/.bashrc" fi elif eval $BYOBU_TEST md5sum >/dev/null 2>&1; then if [ "$(cat /etc/skel/.bashrc | md5sum)" = "$(cat $HOME/.bashrc | md5sum)" ]; then printf "[ -r $BYOBU_CONFIG_DIR/prompt ] && . $BYOBU_CONFIG_DIR/prompt #byobu-prompt#\n" >> "$HOME/.bashrc" fi fi fi [ -r "$BYOBU_CONFIG_DIR/prompt" ] || printf "[ -r ${BYOBU_PREFIX}/share/${PKG}/profiles/bashrc ] && . ${BYOBU_PREFIX}/share/${PKG}/profiles/bashrc #byobu-prompt#\n" > "$BYOBU_CONFIG_DIR/prompt" # Affects: New Wolfi installs -- add colorized prompt to local .profile if [ "$BYOBU_DISTRO" = "Wolfi" ]; then # Wolfi defaults to "ash", which uses .profile if ! (grep -qs "#byobu-prompt#$" "$HOME/.profile"); then printf "[ -r $BYOBU_CONFIG_DIR/prompt ] && . $BYOBU_CONFIG_DIR/prompt #byobu-prompt#\n" >> "$HOME/.profile" fi # Wolfi also has bash, which uses .bashrc if ! (grep -qs "#byobu-prompt#$" "$HOME/.bashrc"); then printf "[ -r $BYOBU_CONFIG_DIR/prompt ] && . $BYOBU_CONFIG_DIR/prompt #byobu-prompt#\n" >> "$HOME/.bashrc" fi fi # Affects: Upgrades from <= byobu 5.126, clear out ec2/rcs cost statuses rm -f "$BYOBU_RUN_DIR"/cache.tmux/ec2_cost* "$BYOBU_RUN_DIR"/cache.tmux/rcs_cost* "$BYOBU_RUN_DIR"/status.tmux/ec2_cost* "$BYOBU_RUN_DIR"/status.tmux/rcs_cost* # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-keybindings000077500000000000000000000027421522352767600175450ustar00rootroot00000000000000#!/bin/sh # # byobu-keybindings - toggle on/off the Byobu f-key shortcuts # Copyright (C) 2013-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . case "$BYOBU_BACKEND" in "tmux") enabled=$(tmux list-keys | grep "f-keys.tmux.disable ;") if [ -n "$enabled" ]; then tmux source "$BYOBU_PREFIX/share/byobu/keybindings/f-keys.tmux.disable" echo "Byobu keybindings: [OFF]" else tmux source "$BYOBU_PREFIX/share/byobu/keybindings/f-keys.tmux" echo "Byobu keybindings: [ON]" fi ;; "screen") if [ -n "$STY" ]; then flag="$BYOBU_RUN_DIR/.${STY}__f-keys_disabled" if [ -e "$flag" ]; then screen -X -S $STY at "*" eval 'process x' 'process e' rm -f "$flag" echo "Byobu keybindings: [ON]" else screen -X -S $STY at "*" eval 'process x' 'process d' touch "$flag" echo "Byobu keybindings: [OFF]" fi fi ;; esac byobu-7.15/usr/bin/byobu-launch.in000077500000000000000000000066411522352767600171200ustar00rootroot00000000000000#!/bin/bash -e # # byobu-launch - call the launcher if we're in an interactive shell # Note: Uses decimal sleep (0.1) which requires bash # Copyright (C) 2010 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . # 1) Prevent recursion, and multiple sourcing of profiles with the BYOBU_SOURCED_PROFILE environment variable. # 2) Respect environment variables (LC_BYOBU and BYOBU_DISABLE) passable over SSH to disable # Byobu launch. This puts that configurability on the SSH client, # in addition to the server. # To use over SSH, your /etc/ssh/sshd_config and /etc/ssh/ssh_config # must pass this variable with AcceptEnv and SendEnv. # Note that LC_* are passed by default on Debian/Ubuntu, we'll optionally # support LC_BYOBU=0 # And in your local bashrc: # $HOME/.bashrc: export LC_BYOBU=0 # or edit your sshd_config, ssh_config, and set: # $HOME/.bashrc: export BYOBU_DISABLE=1 _tty=$(tty) if [ "${_tty#/dev/ttyS}" != "$_tty" ] && [ "${_tty#/dev/ttyAMA}" != "$_tty" ]; then # Don't autolaunch byobu on serial consoles # You can certainly run 'byobu' manually, though echo echo "INFO: Disabling auto-launch of Byobu on this serial console" echo "INFO: You can still run 'byobu' manually at the command line" echo elif [ "$BYOBU_SOURCED_PROFILE" != "1" ] && [ "$LC_BYOBU" != "0" ] && [ "$BYOBU_DISABLE" != "1" ] && [ -O "$HOME" ] && [ -z "$TMUX" ]; then unset _tty BYOBU_SOURCED_PROFILE=1 PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" # Ensure that autolaunch is not explicitly disabled if [ ! -r "$BYOBU_CONFIG_DIR/disable-autolaunch" ]; then case "$-" in *i*) # Attempt to merge shell history across sessions/windows (works with some exceptions) for i in shopt setopt; do if eval $BYOBU_TEST $i >/dev/null; then case $i in shopt) $i -s histappend || true ;; setopt) $i appendhistory || true ;; esac fi done [ -n "$PROMPT_COMMAND" ] && PROMPT_COMMAND="history -a;history -r;$PROMPT_COMMAND" || PROMPT_COMMAND="history -a;history -r" # Source profile, if necessary [ -z "$_byobu_sourced" ] && [ -r "$HOME/.profile" ] && . "$HOME/.profile" if byobu-launcher "$@" ; then # Wait very briefly for the no-logout flag to get written? # Brief sleep prevents race condition with Shift-F6 detach (requires bash) sleep 0.1 if [ -e "$BYOBU_CONFIG_DIR/no-logout-on-detach" ] || [ -e "$BYOBU_RUN_DIR/no-logout" ]; then # The user does not want to logout on byobu detach rm -f "$BYOBU_RUN_DIR/no-logout" # Remove one-time no-logout flag, if it exists true else exit 0 fi fi ;; esac fi fi unset _tty true # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-launcher-install.in000077500000000000000000000056101522352767600211060ustar00rootroot00000000000000#!/bin/sh -e # # byobu-launcher-install # Copyright (C) 2008 Canonical Ltd. # # Authors: Nick Barcet # Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" FLAG="$BYOBU_CONFIG_DIR/no-logout-on-detach" LOGOUT_ON_DETACH=1 for i in $@; do case "$i" in -n|--no-logout) LOGOUT_ON_DETACH=0 ;; esac done update_flag() { if [ "$LOGOUT_ON_DETACH" = "1" ]; then rm -f "$FLAG" else touch "$FLAG" fi } install_launcher() { $PKG-launcher-uninstall "$1" || true printf "_byobu_sourced=1 . ${BYOBU_PREFIX}/bin/byobu-launch 2>/dev/null || true\n" >> "$1" } install_launcher_fish() { $PKG-launcher-uninstall "$1" || true printf "if not set -q VSCODE_CWD; " >> "$1" printf " status --is-login; and status --is-interactive; and exec byobu-launcher;" >> "$1" printf "end" >> "$1" } # Sanitize the environment $PKG-launcher-uninstall || true # Handle bourne shells, if not set globally in /etc/profile.d if [ ! -h "/etc/profile.d/Z97-$PKG.sh" ]; then # Install in $HOME/.profile unconditionally install_launcher "$HOME/.profile" # Now, install in any shell-specific profiles, if they exist # This list may grow to support other shells for i in ".bash_profile" ".bash_login"; do if [ -w "$HOME/$i" ]; then install_launcher "$HOME/$i" fi done fi # Install in zprofile if default shell is zsh case "$SHELL" in *zsh) install_launcher "$HOME/.zprofile" ;; esac # Also install in .bashrc / .zshrc so byobu auto-starts in non-login # interactive shells used by Alacritty, kitty, st, terminology, etc. # byobu-launch already guards against nested launches and non-interactive # shells, so this is safe. LP: #1840728 case "$SHELL" in *bash) [ -w "$HOME/.bashrc" ] && install_launcher "$HOME/.bashrc" ;; *zsh) [ -w "$HOME/.zshrc" ] && install_launcher "$HOME/.zshrc" ;; esac # Handle fish shell if [ -d "$HOME/.config/fish" ]; then install_launcher_fish "$HOME/.config/fish/config.fish" fi # Hush login, since we will handle motd printing touch "$HOME"/.hushlogin rm -f "$BYOBU_CONFIG_DIR/disable-autolaunch" # Update the logout/nologout flag update_flag # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-launcher-uninstall.in000077500000000000000000000030461522352767600214520ustar00rootroot00000000000000#!/bin/sh -e # # byobu-launcher-uninstall # Copyright (C) 2008 Canonical Ltd. # # Authors: Nick Barcet # Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" remove_launcher() { dest=$1 if [ -w "$dest" ]; then # keep any comments, and remove lines invoking byobu: $BYOBU_SED_INLINE -e '/^\s*#/n' -e "/\b$PKG-launch/d" -e "/\bscreen-launch/d" "$dest" fi } if [ -f "$1" ]; then remove_launcher "$1" else for i in ".profile" ".bashrc" ".bash_profile" ".bash_login" ".zprofile" ".zshrc" ".config/fish/config.fish"; do remove_launcher "$HOME/$i" done fi mkdir -p "$BYOBU_CONFIG_DIR" touch "$BYOBU_CONFIG_DIR/disable-autolaunch" # install disabled motd printing; re-enable rm -f "$HOME"/.hushlogin # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-launcher.in000077500000000000000000000043451522352767600174460ustar00rootroot00000000000000#!/bin/sh -e # # byobu-launcher - conditionally launch byobu # Copyright (C) 2010 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" # Bad things happen if you run byobu, but you don't own your $HOME # ie, rather than "sudo byobu", you must run "sudo -H byobu" if [ -O "$HOME" ]; then [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" if [ -e "$BYOBU_CONFIG_DIR/disable-autolaunch" ]; then false elif [ -n "$TMUX" ]; then # Already in a tmux session (e.g., from Fish shell or manual tmux) # Prevent nested tmux sessions which cause "sessions should be nested with care" errors echo "INFO: Byobu auto-launch disabled: already running in a tmux session" 1>&2 echo "INFO: If you want to use Byobu, exit tmux first and run 'byobu' manually" 1>&2 false else case "$TERM" in *screen*) # Handle nesting if [ -n "$SSH_CONNECTION" ] && [ "$(printf "$SSH_CONNECTION" | awk '{print $1}')" != "$(printf "$SSH_CONNECTION" | awk '{print $3}')" ]; then # Safeguard against ssh-ing into ourself, which causes an infinite loop exec $BYOBU_PREFIX/bin/byobu "$@" else echo "INFO: Disabling auto-launch of Byobu in this SSH connection, to avoid a potential infinite loop" 1>&2 echo "INFO: You can still run 'byobu' manually at the command line, if you know what you're doing" 1>&2 true fi ;; dumb) # Dumb terminal, don't launch false ;; *) exec $BYOBU_PREFIX/bin/byobu "$@" ;; esac fi fi false # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-layout.in000077500000000000000000000066301522352767600171610ustar00rootroot00000000000000#!/bin/sh -e # # layout: save and restore byobu layouts # Copyright (C) 2011-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" # Get the layouts directory DIR="$BYOBU_CONFIG_DIR/layouts" mkdir -p "$DIR" PRESETS="even-horizontal even-vertical main-horizontal main-vertical tiled" current_panes=$(tmux list-panes | wc -l) list_layouts() { echo echo "Byobu Saved Layouts" local count=0 i= desc= p= for i in $PRESETS "$DIR"/*; do desc=${i##*/} count=$(expr $count + 1) [ -f "$i" ] && p=$(head -n1 "$i") [ -n "$p" ] && p=" ($p splits)" echo " $count. $desc$p" done echo _RET="$count" } case "$1" in "save") layout=$(tmux list-windows | grep "(active)$" | sed -e "s/.*\[layout //" -e "s/\] .*(active)$//") panes=$(tmux list-panes | wc -l) if [ -n "$2" ]; then name="$2" elif name=$(tmux show-buffer 2>/dev/null) && [ -n "$name" ]; then : # name read from tmux paste buffer (set by C-S-F8 keybinding) else echo echo "Restore layout with , save a layout with " while true; do list_layouts echo -n "Enter a unique name to save this layout: " name=$(head -n1) valid=1 for i in $PRESETS "$DIR"/*; do i=${i##*/} if [ "$i" = "$name" ]; then valid=0 fi done [ "$valid" = "1" ] && break done fi printf "$panes\n$layout\n" > "$BYOBU_CONFIG_DIR/layouts/$name" ;; "restore") if [ -n "$2" ]; then # Layout selected on the command line name="$2" else # List the saved layouts, prompt the user to select one list_layouts count="$_RET" while true; do echo -n "Select a layout to restore [1-$count]: " selected=$(head -n1) if [ -n "$selected" ] && [ $selected -le $count ] && [ $selected -ge 1 ]; then break fi done count=0 for i in $PRESETS "$DIR"/*; do count=$(expr $count + 1) if [ $count -eq $selected ]; then name=$(basename "$i") break fi done fi # Get the details of the selected layout panes= layout= if [ -f "$DIR/$name" ]; then panes=$(head -n1 "$DIR/$name") layout=$(tail -n1 "$DIR/$name") else if [ $current_panes -eq 1 ]; then panes=4 else panes=0 fi layout="$name" fi # Create panes if nececessary to restore the layout while [ $(tmux list-panes | wc -l) -lt $panes ]; do tmux split-window tmux select-layout tiled done # Finally, restore the layout and refresh tmux select-layout "$layout" tmux source "$BYOBU_PREFIX/share/byobu/profiles/tmuxrc" ;; list) list_layouts exit 0 ;; *) echo "ERROR: Invalid argument, try [save|restore|list]" 2>&1 exit 1 ;; esac byobu-7.15/usr/bin/byobu-prompt.in000077500000000000000000000022101522352767600171530ustar00rootroot00000000000000#!/bin/sh -e # # byobu-prompt # Copyright (C) 2013-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" echo echo -n "Do you want to enable Byobu's bash color prompt? [Y/n]: " answer=$(head -n1) echo case "$answer" in "n"|"N") exec byobu-disable-prompt ;; *) exec byobu-enable-prompt esac # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-quiet.in000077500000000000000000000026061522352767600167720ustar00rootroot00000000000000#!/bin/sh # # byobu-quiet - disable the hardstatus and all indicators # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" FLAG="$BYOBU_CONFIG_DIR/status.disable" # Clean up environment $BYOBU_SED_INLINE "/hardstatus/d" "$BYOBU_CONFIG_DIR/keybindings" || true if [ "$1" = "--undo" ]; then rm -f "$FLAG" else touch "$FLAG" # BUG: Need to make this dynamic and following status="$USER@$(hostname)" echo "hardstatus lastline '$status'" >> "$BYOBU_CONFIG_DIR/keybindings" fi $BYOBU_BACKEND -X at 0 source "$BYOBU_CONFIG_DIR/profile" # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-reconnect-sockets.in000077500000000000000000000070731522352767600212770ustar00rootroot00000000000000#!/bin/sh # # byobu-reconnect-sockets - source this file to re-establish # GPG_AGENT_INFO and DBUS_SESSION_BUS_ADDRESS, # useful when reconnecting to an existing # byobu session. # # Copyright (C) 2009 Canonical Ltd. # Copyright (C) 2012-2014 Dustin Kirkland # # Authors: Dustin Kirkland # Ryan C. Thompson # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" case "$-" in *i*) # Interactive shell — sourced normally ;; *) # Non-interactive. Allow when BYOBU_BACKEND is already set in the # environment (e.g. fish users sourcing via the bass shim). # Refuse only when there is no sign of a running byobu context, # which most likely means the script is being executed directly. if [ -z "$BYOBU_BACKEND" ]; then echo 2>&1 echo "ERROR: You must source this file, rather than execute it." 2>&1 echo " . $0" 2>&1 echo 2>&1 exit 1 fi ;; esac export_and_send () { var="$1" value="$(eval "echo \$$var")" export "$var" case $BYOBU_BACKEND in tmux) tmux setenv "$var" "$value" ;; screen) screen -X setenv "$var" "$value" ;; esac } screen_update () { # Ensure that screen's environment variables/values get propagated here # Enable word splitting for zsh: [ "x$ZSH_VERSION" != x ] && setopt local_options sh_word_split tempfile=$(mktemp -q ${BYOBU_RUN_DIR}/sockets-XXXXXXXX) && { for var in $VARS_TO_UPDATE; do screen sh -c "echo export $var=\$$var >> \"$tempfile\"" done . "$tempfile" rm -f "$tempfile" } } tmux_update () { # Ensure that tmux's environment variables/values get propagated here # Enable word splitting for zsh: [ "x$ZSH_VERSION" != x ] && setopt local_options sh_word_split for var in $VARS_TO_UPDATE; do expr="$(tmux showenv | grep "^$var=")" if [ -n "$expr" ]; then export "$expr" fi done } # Pull environment variables/values from backend and update/export here VARS_TO_UPDATE="DISPLAY DBUS_SESSION_BUS_ADDRESS SESSION_MANAGER GPG_AGENT_INFO XDG_SESSION_COOKIE XDG_SESSION_PATH GNOME_KEYRING_CONTROL GNOME_KEYRING_PID GPG_AGENT_INFO SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID WINDOWID UPSTART_JOB UPSTART_EVENTS UPSTART_SESSION UPSTART_INSTANCE" case $BYOBU_BACKEND in tmux) tmux_update ;; screen) screen_update ;; esac # Establish gpg-agent socket, helps when reconnecting to a detached session newest "$HOME/.gnupg/gpg-agent-info-*" && . "$_RET" && export_and_send GPG_AGENT_INFO # Reconnect dbus, source the most recently touched session-bus # Sorry, ls -t is needed here, to sort by time newest "$HOME/.dbus/session-bus/*" && . "$_RET" [ -r "$BYOBU_RUN_DIR/sockets" ] && . "$BYOBU_RUN_DIR/sockets" export_and_send DBUS_SESSION_BUS_ADDRESS export_and_send SESSION_MANAGER # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-screen000077700000000000000000000000001522352767600175442byobuustar00rootroot00000000000000byobu-7.15/usr/bin/byobu-select-backend.in000077500000000000000000000026601522352767600205070ustar00rootroot00000000000000#!/bin/sh -e # # byobu-select-backend # Copyright (C) 2011-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" usage () { cat < "$BYOBU_CONFIG_DIR/backend" byobu-7.15/usr/bin/byobu-select-profile.in000077500000000000000000000121221522352767600205520ustar00rootroot00000000000000#!/bin/sh -e # # byobu-select-profile # Copyright (C) 2008 Canonical Ltd. # # Authors: Dustin Kirkland # Nick Barcet # # 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, version 3 of the License. # # 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, see . # If you change any strings, please generate localization information with: # ./debian/rules get-po PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" TEXTDOMAIN="$PKG" COLORS="default_light \ default_dark \ white \ black \ grey \ dark_grey \ light_grey \ blue \ light_blue \ cyan \ light_cyan \ green \ light_green \ purple \ light_purple \ red \ light_red \ yellow \ brown" # Find a hash utility for i in md5sum md5 sha512sum sha256sum sha1sum shasum shasum5.12 shasum5.10; do if eval $BYOBU_TEST $i >/dev/null 2>&1; then HASH="$i" break fi done usage () { cat < $FILE touch "$BYOBU_RUN_DIR/reload-required" $BYOBU_BACKEND -X at 0 source "$BYOBU_CONFIG_DIR/profile" } get_contrast() { # See section 2.2: http://www.w3.org/TR/AERT#color-contrast local awk="awk" if eval $BYOBU_TEST gawk >/dev/null 2>&1; then awk="gawk" fi local hex="$(echo "$1" | sed -e 's/^[\\#]*//' -e "s/\(..\)\(..\)\(..\)/\1 \2 \3/")" local bright=$(echo $hex | $awk --non-decimal-data '{printf "%0.0f",(("0x"$1)*299+("0x"$2)*587+("0x"$3)*114)/1000}') if [ $bright -ge 130 ]; then _RET="black" else _RET="white" fi } setcolor_tmux() { if [ "$BYOBU_BACKEND" != "tmux" ]; then echo "WARNING: This functionality is only supported in Byobu with the tmux backend" 1>&2 fi dark="$1" get_contrast "$dark" light="$_RET" accent="magenta" highlight="red" monochrome="0" printf "BYOBU_DARK=\"$dark\"\nBYOBU_LIGHT=$light\nBYOBU_ACCENT=$accent\nBYOBU_HIGHLIGHT=$highlight\nMONOCHROME=$MONOCHROME" > "$FILE".tmux tmux source "$BYOBU_PREFIX/share/byobu/profiles/tmuxrc" } if [ $# -eq 0 ]; then usage else while true; do case "$1" in -b|--background) setcolor_screen "background" "$2" shift 2 ;; -f|--foreground) setcolor_screen "foreground" "$2" shift 2 ;; -h|--hostname) color=$(hostname | $HASH | head -c 6) setcolor_tmux "#$color" shift break ;; -i|--ip) [ -r "$BYOBU_CONFIG_DIR/statusrc" ] && . "$BYOBU_CONFIG_DIR/statusrc" . $BYOBU_PREFIX/lib/$PKG/ip_address color=$(__ip_address t| $HASH | head -c 6) setcolor_tmux "#$color" shift break ;; -l|--list) listprofiles shift break ;; -r|--random) color=$(head -c 10 /dev/urandom | $HASH | head -c 6) setcolor_tmux "#$color" shift break ;; *) usage exit 1 ;; --) shift break ;; esac [ $# -eq 0 ] && break done fi exit 0 # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-select-session.in000077500000000000000000000017701522352767600206040ustar00rootroot00000000000000#!/bin/sh -e # # byobu-select-session - interactive session select wrapper script # Copyright (C) 2013-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" exec ${BYOBU_PYTHON} "${BYOBU_PREFIX}/lib/${PKG}/include/select-session.py" byobu-7.15/usr/bin/byobu-shell.in000077500000000000000000000041321522352767600167460ustar00rootroot00000000000000#!/bin/sh # # byobu-shell: display the MOTD and launch the default shell # Copyright (C) 2008 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" FLAG="$BYOBU_CONFIG_DIR/.welcome-displayed" # Find a MOTD, seems that they're moving around for i in /etc/motd /run/motd.dynamic /run/motd; do [ -r $i ] && [ ! -e "$HOME"/.hushlogin ] && cat $i && break done if [ ! -e "$FLAG" ]; then echo echo "Welcome to the light, powerful, text window manager, Byobu." echo "You can toggle the launch of Byobu at login with:" echo " 'byobu-disable' and 'byobu-enable'" echo echo "For tips, tricks, and more information, see:" echo " * https://byobu.org" echo touch "$FLAG" fi # Use a login shell (-l) so that profiles are sourced and PS1 is colourised. # Exceptions: # fish - "status --is-login" triggers autostart, causing an infinite loop (LP#2064030) # zsh - .zshrc commonly guards against login context with [[ -o login ]] && return, # which silently skips interactive config; drop -l so the first window matches # default-command 'exec $SHELL' used for all subsequent windows (GH: #104) if [ -n "$SHELL" ] && [ -x "$SHELL" ]; then case "$SHELL" in */fish|*/zsh) exec "$SHELL" ;; *) exec "$SHELL" -l ;; esac else exec /bin/sh -l fi # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-silent.in000077500000000000000000000024361522352767600171420ustar00rootroot00000000000000#!/bin/sh # # byobu-silence - disable the hardstatus, all indicators, and the window list # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" FLAG="$BYOBU_CONFIG_DIR/status.disable" # Clean up environment $BYOBU_SED_INLINE "/caption/d" "$BYOBU_CONFIG_DIR/keybindings" || true if [ "$1" = "--undo" ]; then rm -f "$FLAG" else touch "$FLAG" echo "caption splitonly ''" >> "$BYOBU_CONFIG_DIR/keybindings" fi exec byobu-quiet "$@" # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-status-detail.in000077500000000000000000000022731522352767600204260ustar00rootroot00000000000000#!/bin/sh # # byobu-status-detail # Copyright (C) 2008 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" if which vim >/dev/null && `vim --version | grep -q +folding`; then byobu-status --detail | vim -c "set foldmethod=indent" -c "set foldminlines=0" -c "set foldnestmax=1" -c "set foldcolumn=2" -R - else byobu-status --detail | $BYOBU_PAGER fi # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/byobu-status.in000077500000000000000000000140321522352767600171620ustar00rootroot00000000000000#!/bin/sh # # byobu-status: byobu's cached status gathering # # Copyright (C) 2011-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" # Make sure status is not disabled [ -f "$BYOBU_CONFIG_DIR/status.disable" ] && exit 0 # Clean and create cache directories [ -d "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND" ] || mkdir -p "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND" [ -d "$BYOBU_RUN_DIR/.last.$BYOBU_BACKEND" ] || mkdir -p "$BYOBU_RUN_DIR/.last.$BYOBU_BACKEND" # Source configurations . "${BYOBU_PREFIX}/lib/${PKG}/include/icons" for i in "${BYOBU_PREFIX}/share/$PKG/status/status" "${BYOBU_PREFIX}/share/$PKG/status/statusrc" "$BYOBU_CONFIG_DIR/status" "$BYOBU_CONFIG_DIR/statusrc" "$BYOBU_CONFIG_DIR/color" "$BYOBU_CONFIG_DIR/color.tmux"; do [ -r "$i" ] && . "$i" done [ -r "$BYOBU_CONFIG_DIR/datetime.tmux" ] && . "$BYOBU_CONFIG_DIR/datetime.tmux" case "$BYOBU_BACKEND" in screen) # Reload profile, if necessary if [ -e "/var/run/screen/S-$USER/$PKG.reload-required" ] || [ -e "$BYOBU_RUN_DIR/reload-required" ]; then if [ -r "$BYOBU_CONFIG_DIR/profile" ]; then # If the forced janitorial steps succeed, try a profile reload byobu-janitor --force && screen -X at 0 source "$BYOBU_CONFIG_DIR/profile" >/dev/null 2>&1 fi fi ;; tmux) # Fix status printing for small terminal sizes in tmux width=$(tmux list-windows -F "#{session_width}") if [ -r "$BYOBU_RUN_DIR/width" ]; then read w_last < $BYOBU_RUN_DIR/width 2>/dev/null 1>&2 else w_last=0 fi for w in $width; do if [ "$w" != "$w_last" ]; then # go through cat due to possible tmux/epoll bug tmux set -g status-left-length $(($w*1/4)) | cat >/dev/null 2>&1 tmux set -g status-right-length $(($w*3/4)) | cat >/dev/null 2>&1 printf "$w" > $BYOBU_RUN_DIR/width break fi done ;; esac # Get the current timestamp get_now; NOW=${_RET} get_status() { local cachepath="$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/$1" local lastpath="$BYOBU_RUN_DIR/.last.$BYOBU_BACKEND/$1" local lastrun=0 [ -r "$lastpath" ] && read lastrun < "$lastpath" case "$1" in ip_address4) local IPV6=0 local function="ip_address" ;; ip_address6) local IPV6=1 local function="ip_address" ;; *) local function="$1" ;; esac status_freq "$function" local expiry=$(($lastrun+$_RET)) find_script "$function" && . "${_RET}" # Update cache now, if necessary if [ $NOW -ge $expiry ] || [ "$lastrun" = "0" ]; then "__$function" > "$cachepath".new fi # Check if we have data in the cache if [ -s "$cachepath".new ]; then # Looks like we have an updated cache, use it mv -f "$cachepath".new "$cachepath" printf "%s" "$NOW" > "$lastpath" IFS= read line < "$cachepath"; printf "%s" "$line" elif [ -s "$cachepath" ]; then # New cache is empty, but we have data from our last run, use it IFS= read line < "$cachepath"; printf "%s" "$line" fi } case "$1" in *left|*right) eval items="\$$1" for i in $items; do if [ "$BYOBU_BACKEND" = "tmux" ]; then case "$i" in \#date) if [ -n "$BYOBU_DATE" ]; then $BYOBU_SED_INLINE -e "/BYOBU_DATE=/d" "$BYOBU_CONFIG_DIR/datetime.tmux" printf "%s\n" 'BYOBU_DATE=' >> "$BYOBU_CONFIG_DIR/datetime.tmux" touch "$BYOBU_RUN_DIR/reload-required" continue fi ;; \#time) if [ -n "$BYOBU_TIME" ]; then $BYOBU_SED_INLINE -e "/BYOBU_TIME=/d" "$BYOBU_CONFIG_DIR/datetime.tmux" printf "%s\n" 'BYOBU_TIME=' >> "$BYOBU_CONFIG_DIR/datetime.tmux" touch "$BYOBU_RUN_DIR/reload-required" continue fi ;; date) if [ -z "$BYOBU_DATE" ]; then $BYOBU_SED_INLINE -e "/BYOBU_DATE=/d" "$BYOBU_CONFIG_DIR/datetime.tmux" printf "%s\n" 'BYOBU_DATE="%Y-%m-%d "' >> "$BYOBU_CONFIG_DIR/datetime.tmux" touch "$BYOBU_RUN_DIR/reload-required" continue fi ;; time) _byobu_time_fmt="%H:%M:%S" [ "${TIME_SECONDS:-1}" = "0" ] && _byobu_time_fmt="%H:%M" if [ "$BYOBU_TIME" != "$_byobu_time_fmt" ]; then $BYOBU_SED_INLINE -e "/BYOBU_TIME=/d" "$BYOBU_CONFIG_DIR/datetime.tmux" printf 'BYOBU_TIME="%s"\n' "$_byobu_time_fmt" >> "$BYOBU_CONFIG_DIR/datetime.tmux" touch "$BYOBU_RUN_DIR/reload-required" fi unset _byobu_time_fmt continue ;; esac fi case "$i" in \#*) continue ;; esac get_status "$i" done ;; --detail) VER= if eval $BYOBU_TEST dpkg-query >/dev/null; then VER=$(set -- $(dpkg-query --show $PKG); printf "%s\n" "$2") fi printf "$PKG-$VER Detailed Status Navigation\n" if eval $BYOBU_TEST vim >/dev/null && `vim --version | grep -q +folding`; then printf " Expand all - zr\t\tCollapse all - zm\n Expand one - zo\t\tCollapse one - zc\n\n" fi for i in "$BYOBU_PREFIX/lib/$PKG"/*; do [ -f "$i" ] || continue i=${i##*/} case "$i" in include|menu|notify_osd|time_binary) continue ;; esac find_script "$i" && . "${_RET}" short=$(eval "__${i}" | $BYOBU_SED -e 's/^\s*//' -e 's/\s*$//' -e 's/.{[^}]*}//g') detail=$(eval "__${i}_detail" 2>/dev/null | $BYOBU_SED -e '/^$/d' -e 's/^/\t/g') printf "%s\n\t(%s)\n" "$short" "$i" [ -n "$detail" ] && printf "%s\n" "$detail" done ;; color) [ -z "$FOREGROUND" ] && FOREGROUND="w" [ -z "$BACKGROUND" ] && BACKGROUND="k" printf "$ESC{= $BACKGROUND$FOREGROUND}" ;; esac byobu-7.15/usr/bin/byobu-tmux000077700000000000000000000000001522352767600172622byobuustar00rootroot00000000000000byobu-7.15/usr/bin/byobu-ugraph.in000077500000000000000000000111031522352767600171210ustar00rootroot00000000000000#!/bin/bash #--------------------------------------------------------------------- # Script to display a byobu notification "history graph". # # Designed to work with the wonderful byobu(1) but can be run # stand-alone. #--------------------------------------------------------------------- # # Copyright (C) 2011 Canonical Ltd. # # Author: James Hunt # # 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, version 3 of the License. # # 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, see . # #--------------------------------------------------------------------- PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" script_name=${0##*/} min_default=0 max_default=100 points_default=5 theme_default=vbars_8 newline="\n" rotate=y error() { msg="$*" echo "ERROR: $msg" >&2 } die() { error "$*" exit 1 } usage() { cat < : File to read data points from. (only required if no command specified). -h : Show this help. -m : Minimum value (default=$min_default). -n : Supress output of newline character. -p : Specify number of data points in graph (default=$points_default). -r : Do not rotate file (default is to rotate). Option implies file should not be written to so a command cannot follow script options in this case. -t : 'byobu-ulevel' theme to use (default=$theme_default). -x : Maximum value (default=$max_default). Examples: Using $script_name to run a command, rotate log and display graph. Here we specify a command to display available memory. Trailing echo adds a required newline Note no filename specified. $script_name "(@prefix@/lib/byobu/mem_used | sed -e 's/% //g';echo)" Using $script_name just to rotate log and display the graph file=/tmp/load.dat awk '{ print \$1}' /proc/loadavg >> \$file # Note: we need to specify what we consider to be a "reasonable" maximum load $script_name -m 3.0 -f \$file Notes: - If you specify 'command', care must be taken with shell quoting to avoid expansion prior to this script running the command. - If '-r' is not specified, the file will be rotated such that at most lines are retained on each invocation of this script. EOT } get_data() { needed_lines=$points if [ ! -f $file ] then return fi lines=$(wc -l $file|awk '{print $1}') if [ $lines -lt $needed_lines ] then # insufficient data return fi bytes=$(<${file}) bytes=$(echo "$bytes"|tail -n ${needed_lines}) [ $lines -eq $needed_lines -o $rotate = n ] && echo "$bytes" && return # rotate tmp=`tempfile` echo "$bytes" > $tmp mv $tmp $file echo "$bytes" } while getopts "f:hm:np:rt:x:" opt do case "$opt" in f) file="$OPTARG" ;; h) usage exit 0 ;; m) min=$OPTARG ;; n) newline= ;; p) points=$OPTARG ;; r) rotate=n ;; t) theme="$OPTARG" ;; x) max=$OPTARG ;; esac done shift $[$OPTIND-1] cmd="$@" [ -z "$theme" ] && theme=$theme_default if [ -z "$cmd" ] then if [ -z "$file" ] then error "must specify file" usage exit 1 fi fi if [ -z "$file" ] then # we could go cryptic+safe by calling tempfile(1), but that then # makes it very difficult to find in case of need. file=/tmp/${USER}-${script_name}-$$.dat fi [ -z "$min" ] && min=$min_default [ -z "$max" ] && max=$max_default [ -z "$points" ] && points=$points_default if [ ! -z "$cmd" ] then if [ $rotate = n ] then error "cannot write to file if rotate disabled" usage exit 1 fi eval "$cmd >>$file" fi data=$(get_data) [ -z "$data" ] && printf "%*.s${newline}" $points && exit 0 for datum in $data do byobu-ulevel -n -m $min -x $max -p -c $datum -t $theme done byobu-7.15/usr/bin/byobu-ulevel.in000077500000000000000000000273041522352767600171410ustar00rootroot00000000000000#!/bin/bash #--------------------------------------------------------------------- # Script to display unicode characters representing the level of # some indicator. # # Designed to work with the wonderful byobu(1) but can be run # stand-alone. #--------------------------------------------------------------------- # # Copyright (C) 2011 Canonical Ltd. # # Author: James Hunt # # 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, version 3 of the License. # # 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, see . # #--------------------------------------------------------------------- #------------------------------ # Themes with 2 values. # # Two-value themes are handled differently to other n-value types of # theme: the first array entry in each theme is generally some unfilled # glyph, denoting an "off" value and the second value is the filled # version of the unfilled glyph and denotes an "on" value. Note that # you can always change the ordering of these values using the 'invert' # command-line option. PKG="byobu" [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" circles_2=(○ ●) diamonds_2=(◇ ◆) flags_2=(⚐ ⚑) hearts_2=(♡ ♥) squares_2=(◻ ◼) squares_small_2=(◽ ◾) stars_2=(☆ ★) faces_2=(☹ ☺) #------------------------------ # Themes with 4 values. vdots_thick_4=(⣀ ⣤ ⣶ ⣿) vdots_thin_4=(⢀ ⢠ ⢰ ⢸) fractions_4=(¼ ½ ¾ ¹) quadrants_4=(◔ ◑ ◕ ●) shades_4=(░ ▒ ▓ █) #------------------------------ # Themes with 5 values. circles_5=(◦ ○ ◎ ◉ ●) #------------------------------ # Themes with 6 values. dice_6=(⚀ ⚁ ⚂ ⚃ ⚄ ⚅) #------------------------------ # Themes with 8 values. hbars_8=(▏ ▎ ▍ ▌ ▋ ▊ ▉ █) vbars_8=(▁ ▂ ▃ ▄ ▅ ▆ ▇ █) #------------------------------ # Themes with 10 values. circle_number_10=(➀ ➁ ➂ ➃ ➄ ➅ ➆ ➇ ➈ ➉) solid_numbers_a_10=(➊ ➋ ➌ ➍ ➎ ➏ ➐ ➑ ➒ ➓) solid_numbers_b_10=(❶ ❷ ❸ ❹ ❺ ❻ ❼ ❽ ❾ ❿) #------------------------------ # XXX: remember to update if you add new themes above! theme_list=\ ( 'circles_2 diamonds_2 flags_2 hearts_2 squares_2 squares_small_2 stars_2' 'vdots_thick_4 vdots_thin_4 fractions_4 quadrants_4 shades_4' 'circles_5' 'dice_6' 'hbars_8 vbars_8' 'circle_number_10 solid_numbers_a_10 solid_numbers_b_10' ) #------------------------------ default_decimal_places=2 a11y=n a11y_variable=BYOBU_A11Y debug_enabled=n newline= list=n quiet=n invert=n reverse=n script_name=${0##*/} min_default=0 max_default=100 width_default=5 zero_as_space=n theme_default=vbars_8 permissive=n debug() { msg="$*" [ $debug_enabled = y ] && echo "DEBUG: $msg" } error() { msg="$*" echo "ERROR: $msg" >&2 } die() { error "$*" exit 1 } check_a11y() { eval result="\$$a11y_variable" [ ! -z "$result" ] && a11y=y } # return 1 if expression specified is true (no return if false) bc_test() { expr="$*" echo $(echo "if ( $expr ) { print \"1\" }"|bc -l) } assert() { expr="$1" str="$2" debug "assert: expr='$expr'" ret=$(bc_test "$expr") [ ! -z "$ret" ] && return die "$str" } usage() { cat < $script_name [options] $script_name Options: -a : Accessibility mode: only output ASCII. (Also enabled if variable '$a11y_variable' set). -b : Display current value as space if zero, rather than lowest 'value' of theme. -c : Current value of your indicator. -d : Enable debug output. -e : Number of decimal places to use for accessibility mode (default=$default_decimal_places). -h : Show this help. -i : Invert colour scheme (rating themes only). -l : List available themes. If '-t' also specified, show all values for specified theme. -m : Minimum value (default=$min_default). -n : Supress output of newline character. -p : Permissive mode - if current value out of bounds, set it to the nearest bound (min or max). -q : Suppress messages (requires '-t'). -r : Reverse 'direction' of display (rating theme only). -t : Name of theme (default=$theme_default). -u : Specify a user theme (2 or more values). -w : Width of rating theme (default=$width_default). -x : Maximum value (default=$max_default). Examples: # Display character representing 27% using default theme. $script_name 27 # As above. $script_name -c 27 # Example showing floating-point and negative values. $script_name -c 1.100001 -m -5.00234 -x 2.71828 -t dice_6 # Use accessibility mode to display a percentage value # (rounded to nearest percentage) $script_name -m -22.613 -x 5.00212 -c 0.10203 -a -e 0 # Display value using a "rating theme" (displayed left-to-right). $script_name -c 83 -t stars_2 # Display right-to-left inverted "rating theme". $script_name -c 60 -t diamonds_2 -ri # Display all glyphs in 'solid_numbers_a_10' theme. $script_name -l -t solid_numbers_a_10 # Display a user-specified rating theme 10 glyphs wide. $script_name -c 666.321 -m -273.15 -x 1370 -u "· ☢" -w 10 # A multi-element user theme (this prints 'e'). $script_name -c 50 -u "a b c d e f g h i j" Notes: - Arguments of type "" denote an integer value, whereas arguments of type "" denotes either an integer or a floating-point number. - The final '_' in a theme name denotes the number of glyphs in it. - "Rating themes" are those with only 2 values. - The argument to '-u' must contain space-delimited characters. EOT } # this is horribly inefficient - we should probably do some clever # tricks using printf formats to avoid the silly while loop. # Additionally, it is rather similar to show_theme_entry() but was split # out from that in a vain attempt to make the overall logic clearer :) show_rating_theme() { theme="$1" min="$2" max="$3" current="$4" percent="$5" if [ $invert = n ] then on=1 off=0 else on=0 off=1 fi debug "width=$width" debug "percent=$percent" percent_per_glyph=$(echo "scale=4;100/${width}"|bc -l) assert "$percent_per_glyph > 1.0" "width ($width) too great" debug "percent_per_glyph=$percent_per_glyph" debug "glyph_count=$glyph_count" g=$percent_per_glyph i=0 value="" while [ $i -lt $width ] do if [ ! -z "$(bc_test "$g <= $percent")" ] then eval content="\${$theme[${on}]}" else eval content="\${$theme[${off}]}" fi if [ $reverse = n ] then value="${value}${content}" else value="${content}${value}" fi g=$(echo "$g + $percent_per_glyph"|bc -l) i=$((i + 1)) done echo $newline "$value" } show_theme_entry() { theme="$1" min="$2" max="$3" current="$4" debug "theme=$theme" debug "min=$min" debug "max=$max" debug "current=$current" range=$(echo "($max - $min)"|bc -l) quotient=$(echo "scale=4;((${current} - ${min})/${range})"|bc -l) percent=$(echo "$quotient * 100"|bc -l) glyph_count=$(echo $theme|awk -F\_ '{print $NF}') debug "range=$range" debug "quotient=$quotient" debug "percent=$percent" debug "glyph_count=$glyph_count" # just ASCII please if [ $a11y = y ] then [ -z "$decimal_places" ] && decimal_places=$default_decimal_places val=$(printf "%.*f" "$decimal_places" "$percent") echo $newline "$val" return fi if [ $glyph_count -eq 2 ] then show_rating_theme "$theme" "$min" "$max" "$current" "$percent" return fi percent_per_glyph=$(echo "100/$glyph_count"|bc -l) debug "percent_per_glyph=$percent_per_glyph" assert "$percent_per_glyph > 1.0" "width ($width) too great" # with this scheme, assuming current value is 0-100 and theme has 10 # elements: # # current glyph from theme # # 0-19 1st # 20-29 2nd # 30-39 3rd # : # 90-99 9th # 100 10th i=$(echo|awk \ -v quotient=$quotient \ -v glyph_count=$glyph_count \ '{ x= int( (quotient * glyph_count) ) - 1; x = (x > (glyph_count-1) ? (glyph_count-1) : x); if ( x < 0 ) x = 0; printf("%d", x); }') debug "index=$i" eval content="\${$theme[$i]}" [ ! -z "$(bc_test "$current == 0")" -a $zero_as_space = y ] && content=' ' echo $newline "$content" return } list_theme() { theme="$1" eval content="\${$theme[@]}" echo for c in $content do printf "$c " done echo -e "\n" } list_themes() { for entry in ${theme_list[@]} do for arg in "$entry" do echo "$arg" done done } theme_valid() { theme="$1" [ -z "`list_themes|grep "^${theme}$"`" ] && return 1 return 0 } check_a11y # XXX: the seemingly pointless 'tr' calls translate unicode dashes (look # closely!) into ASCII dashes. This is required since 'bc' borks on # unicode and it is easy to mistakenly pass unicode dashes if you paste # characters from another application, such as a web-browser. while getopts "abc:de:hilm:npqrt:u:w:x:" opt do case "$opt" in a) a11y=y ;; b) zero_as_space=y ;; c) current=$(echo $OPTARG|tr '−' '-') ;; d) debug_enabled=y ;; e) decimal_places=$OPTARG ;; h) usage exit 0 ;; i) invert=y ;; l) list=y ;; m) min=$(echo $OPTARG|tr '−' '-') ;; n) newline=-n ;; p) permissive=y ;; q) quiet=y ;; r) reverse=y ;; t) theme=$OPTARG ;; u) user_theme="$OPTARG" ;; w) width=$OPTARG ;; x) max=$(echo $OPTARG|tr '−' '-') ;; esac done shift $[$OPTIND-1] if [ ! -z "$user_theme" ] then elements=$(echo "$user_theme"|awk '{print NF}') assert "$elements >= 2" "user themes need >= 2 values" # create new theme name="_user_${elements}" eval "$name=($user_theme)" # add it to list theme_list=("${theme_list[@]}" $name) [ -z "$theme" ] && theme=$name fi if [ "$list" = y ] then if [ -z "$theme" ] then list_themes && exit 0 else theme_valid "$theme" || die "invalid theme: $theme" [ "$quiet" = n ] && echo "Listing theme '$theme'" list_theme $theme && exit 0 fi fi [ -z "$min" ] && min=$min_default [ -z "$max" ] && max=$max_default [ -z "$width" ] && width=$width_default assert "$min <= $max" "minimum ($min) > maximum ($max)" assert "$min != $max" "minimum ($min) == maximum" [ -z "$current" -a ! -z "$1" ] && current="$1" if [ -z "$current" ] then error "must specify current value" usage exit 1 fi if [ $permissive = n ] then assert "$current >= $min" "current ($current) < minimum ($min)" assert "$current <= $max" "current ($current) > maximum ($max)" else [ ! -z "$(bc_test "$current < $min")" ] && current=$min [ ! -z "$(bc_test "$current > $max")" ] && current=$max fi [ -z "$theme" ] && theme=$theme_default theme_valid "$theme" || die "invalid theme: $theme" show_theme_entry $theme $min $max $current exit 0 byobu-7.15/usr/bin/byobu.in000077500000000000000000000233661522352767600156530ustar00rootroot00000000000000#!/bin/sh -e # # byobu - wrapper script # Copyright (C) 2008-2009 Canonical Ltd. # Copyright (C) 2008-2024 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . VERSION=@VERSION@ PKG="byobu" # All sorts of things go wrong if you don't own your $HOME dir. # This happens under sudo, if you don't use the -H option; Byobu will # create a bunch of files in your $HOME which will be owned by root. if [ ! -O "$HOME" ] && [ ! -O "$HOME/.profile" ]; then echo "Cannot run $PKG because [$USER] does not own [$HOME] or [$HOME/.profile]" 1>&2 if [ -n "$SUDO_USER" ]; then echo "To run $PKG under sudo, you MUST use 'sudo -H'" 1>&2 fi exit 1 fi # If we're in a busybox/ash shell (or shell is undefined), # and a full bash shell is available, then please let's use bash in byobu. # Other shells are supported, but your mileage may vary... if [ "$SHELL" = "/bin/ash" ] || [ "$SHELL" = "ash" ] || [ -z "$SHELL" ]; then [ -x "/bin/bash" ] && export SHELL="/bin/bash" fi # Source local byobu config if [ -r "$HOME/.byoburc" ]; then # Ensure that this configuration is usable . "$HOME/.byoburc" || mv -f "$HOME/.byoburc" "$HOME/.byoburc".orig fi if [ -z "${BYOBU_PREFIX}" ]; then # Find and export the installation location prefix greadlink -f . >/dev/null 2>&1 && export BYOBU_READLINK="greadlink" || export BYOBU_READLINK="readlink" prefix="$(dirname $(dirname $($BYOBU_READLINK -f $0)))" if [ "$prefix" != "@prefix@" ]; then echo "export BYOBU_PREFIX='$prefix'" >> "$HOME/.byoburc" . "$HOME/.byoburc" fi fi export BYOBU_CHARMAP=$(locale charmap) [ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc" [ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX . "${BYOBU_PREFIX}/lib/${PKG}/include/common" # Override backend if we can determine intentions from argv[0] [ -r "$BYOBU_CONFIG_DIR/backend" ] && . "$BYOBU_CONFIG_DIR/backend" case "$0" in *byobu-screen) BYOBU_BACKEND="screen" ;; *byobu-tmux) BYOBU_BACKEND="tmux" ;; esac # At this point, we're sure BYOBU_BACKEND is properly defined export BYOBU_BACKEND # Store the parent tty if eval $BYOBU_TEST tty >/dev/null 2>&1; then export BYOBU_TTY=$(tty) else export BYOBU_TTY=$(readlink /proc/$$/fd/0) fi # Get the default window name [ -n "$BYOBU_WINDOW_NAME" ] || BYOBU_WINDOW_NAME=- # Add a version argument for debugging purposes, enter manpage for help if [ "$#" = "1" ]; then case "$1" in -v|--version) echo "$PKG version $VERSION" if eval $BYOBU_TEST bash >/dev/null 2>&1; then # Check ulimits u=$(bash -c "ulimit -n") [ "$u" = "unlimited" ] || [ $u -ge 15 ] || echo "WARNING: ulimit -n is too low" 1>&2 u=$(bash -c "ulimit -u") [ "$u" = "unlimited" ] || [ $u -ge 1600 ] || echo "WARNING: ulimit -u is too low" 1>&2 fi exec $BYOBU_BACKEND $BYOBU_ARG_VERSION exit 0 ;; -h|--help) exec man $PKG ;; esac fi # Check if we're being autolaunched, and this user explicitly does not want it. if [ "$0" = "/etc/profile.d/Z97-$PKG.sh" ] && [ -r "$BYOBU_CONFIG_DIR/disable-autolaunch" ]; then exit 0 fi # Sanitize the environment byobu-janitor --force # Set the window title if this is a TTY if [ -t 1 ]; then [ -r "$BYOBU_CONFIG_DIR/statusrc" ] && . "$BYOBU_CONFIG_DIR/statusrc" . $BYOBU_PREFIX/lib/$PKG/ip_address if [ -n "$BYOBU_ALT_TITLE" ]; then _byobu_title="$BYOBU_ALT_TITLE" else _byobu_title="${USER}@$(hostname 2>/dev/null || cat /proc/sys/kernel/hostname 2>/dev/null) ($(__ip_address t)) - ${PKG}" fi [ -n "$BYOBU_NO_TITLE" ] || printf '\033]0;%s\007' "$_byobu_title" fi # Drop a symlink to the ssh socket in $HOME, since we can ensure that exists. # Include hostname in the name so NFS-shared homes don't stomp each other. if [ -S "$SSH_AUTH_SOCK" ] && [ ! -h "$SSH_AUTH_SOCK" ]; then _byobu_agent="$BYOBU_CONFIG_DIR/.ssh-agent-$(hostname -s 2>/dev/null || hostname 2>/dev/null || cat /proc/sys/kernel/hostname 2>/dev/null)" ln -sf "$SSH_AUTH_SOCK" "$_byobu_agent" export SSH_AUTH_SOCK="$_byobu_agent" unset _byobu_agent fi # Fallback terminfo [ -z "$BYOBU_DEFAULT_TERM" ] && BYOBU_DEFAULT_TERM="screen" # Color terminfo to use, if possible # Prefer tmux-256color over screen-256color for the tmux backend: screen-256color # defines smso=\E[3m (standout = italic escape code) with no sitm, causing tmux # to map italic requests to standout mode which renders as reverse video on the # outer terminal. tmux-256color correctly separates smso=\E[7m and sitm=\E[3m. if [ -z "$BYOBU_COLOR_TERM" ]; then if [ "$BYOBU_BACKEND" = "tmux" ] && infocmp tmux-256color >/dev/null 2>&1; then BYOBU_COLOR_TERM="tmux-256color" else BYOBU_COLOR_TERM="screen-256color" fi fi # Check if our terminfo supports 256 colors CAN_SHOW_COLORS= if eval $BYOBU_TEST tput >/dev/null 2>&1; then if [ "$(tput colors 2>/dev/null || echo 0)" = "256" ]; then CAN_SHOW_COLORS=1 fi fi # Check if the color terminfo is available HAS_COLOR_TERM= if eval $BYOBU_TEST infocmp >/dev/null 2>&1; then if infocmp "$BYOBU_COLOR_TERM" >/dev/null 2>&1; then HAS_COLOR_TERM=1 fi fi case $BYOBU_BACKEND in tmux) # Use 256 colors if possible if [ -n "$CAN_SHOW_COLORS" ] || [ "$COLORTERM" = "gnome-terminal" ] || [ "$TERM" = "xterm" ] || [ "$TERM" = "xterm-256color" ] || [ "$TERM" = "screen" ]; then [ -z "$SCREEN_TERM" ] && SCREEN_TERM="-2" fi if [ -z "$BYOBU_TERM" ]; then if [ -n "$SCREEN_TERM" -a -n "$HAS_COLOR_TERM" ]; then BYOBU_TERM="$BYOBU_COLOR_TERM" else BYOBU_TERM="$BYOBU_DEFAULT_TERM" fi fi BYOBU_PROFILE="-f $BYOBU_PREFIX/share/$PKG/profiles/tmuxrc" # Set default window, unless user has overriden if egrep -qs "default-command|default-shell" $BYOBU_CONFIG_DIR/.tmux.conf >/dev/null 2>&1; then DEFAULT_WINDOW= else DEFAULT_WINDOW="new-session -n $BYOBU_WINDOW_NAME ${BYOBU_PREFIX}/bin/byobu-shell" fi sessions=$($BYOBU_BACKEND list-sessions 2>/dev/null) || true CUSTOM_WINDOW_SET=0 if [ -s "$BYOBU_CONFIG_DIR/windows.tmux.$BYOBU_WINDOWS" ]; then CUSTOM_WINDOW_SET=1 BYOBU_WINDOWS="$BYOBU_CONFIG_DIR/windows.tmux.$BYOBU_WINDOWS" elif [ -s "$BYOBU_CONFIG_DIR/windows.tmux" ]; then CUSTOM_WINDOW_SET=1 BYOBU_WINDOWS="$BYOBU_CONFIG_DIR/windows.tmux" fi ;; screen) # Allow override of default window list, with BYOBU_WINDOWS environment variable CUSTOM_WINDOW_SET=0 if [ -s "$BYOBU_WINDOWS" ]; then CUSTOM_WINDOW_SET=1 elif [ -s "$BYOBU_CONFIG_DIR/windows.$BYOBU_WINDOWS" ]; then CUSTOM_WINDOW_SET=1 BYOBU_WINDOWS="$BYOBU_CONFIG_DIR/windows.$BYOBU_WINDOWS" elif [ "$#" = "0" ]; then BYOBU_WINDOWS="$BYOBU_CONFIG_DIR/windows" else BYOBU_WINDOWS="/dev/null" fi export BYOBU_WINDOWS # Launch shell, unless the user has default windows set to launch uncommented_lines < "$BYOBU_WINDOWS" && DEFAULT_WINDOW= || DEFAULT_WINDOW="${BYOBU_PREFIX}/bin/byobu-shell" # Use 256 colors if possible if [ -z "$BYOBU_TERM" ]; then if [ -n "$CAN_SHOW_COLORS" -a -n "$HAS_COLOR_TERM" ]; then BYOBU_TERM="$BYOBU_COLOR_TERM" else BYOBU_TERM="$BYOBU_DEFAULT_TERM" fi fi SCREEN_TERM="-T $BYOBU_TERM" # Some users want to maintain separate configurations # if they use both GNU Screen and byobu on the same system if [ -r "$BYOBU_CONFIG_DIR/.screenrc" ]; then BYOBU_PROFILE="-c $BYOBU_PREFIX/share/$PKG/profiles/byoburc" else BYOBU_PROFILE="-c $BYOBU_PREFIX/share/$PKG/profiles/screenrc" fi BYOBU_SESSION_NAME="-S $PKG" # Zero out $BYOBU_SESSION_NAME if user has specified a session name for i in "$@"; do case $i in -*r*|-*d*|-*D*|-*S*|-ls|-list) BYOBU_SESSION_NAME= ;; esac done sessions=$($BYOBU_BACKEND -wipe 2>/dev/null) || true ;; esac export BYOBU_TERM # Save session info [ -n "$DBUS_SESSION_BUS_ADDRESS" ] && printf "DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS\n" > "$BYOBU_RUN_DIR/sockets" [ -n "$SESSION_MANAGER" ] && printf "SESSION_MANAGER=$SESSION_MANAGER\n" >> "$BYOBU_RUN_DIR/sockets" # Preflight: if no tmux server is running yet, validate the config so any # syntax error is shown to the user rather than swallowed by exec. LP: #1960236 if [ "$BYOBU_BACKEND" = "tmux" ] && ! tmux list-sessions >/dev/null 2>&1; then _byobu_tmux_err=$(tmux start-server 2>&1 >/dev/null) || true if [ -n "$_byobu_tmux_err" ]; then printf "byobu: tmux configuration error:\n%s\n" "$_byobu_tmux_err" >&2 exit 1 fi unset _byobu_tmux_err fi # Now let's execute the backend! if [ "$#" = "0" ]; then if [ "$CUSTOM_WINDOW_SET" = "1" ]; then # Start new custom window set session case $BYOBU_BACKEND in tmux) exec tmux -u $SCREEN_TERM $BYOBU_PROFILE $(cat "$BYOBU_WINDOWS") ;; screen) exec screen $SCREEN_TERM $BYOBU_SESSION_NAME $BYOBU_PROFILE ;; esac else case "$sessions" in *\(*\)*) # Select and attach to an existing session exec byobu-select-session ;; *) # Start new default session case $BYOBU_BACKEND in tmux) exec tmux -u $SCREEN_TERM $BYOBU_PROFILE $DEFAULT_WINDOW ;; screen) exec screen $SCREEN_TERM $BYOBU_SESSION_NAME $BYOBU_PROFILE $DEFAULT_WINDOW ;; esac ;; esac fi else # Launch with command line args case $BYOBU_BACKEND in tmux) exec tmux -u $SCREEN_TERM $BYOBU_PROFILE "$@" ;; screen) exec screen $SCREEN_TERM $BYOBU_SESSION_NAME $BYOBU_PROFILE "$@" ;; esac fi # vi: syntax=sh ts=4 noexpandtab byobu-7.15/usr/bin/col1000077500000000000000000000017031522352767600147530ustar00rootroot00000000000000#!/bin/sh -e # # col1..col9 - handy hack to print a column from standard in # # Copyright (C) 2010 Dustin Kirkland # # Authors: # Dustin Kirkland # # 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 3 of the License. # # 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, see . if [ $# -gt 0 ]; then ifs='-F'"$1" shift || true else ifs="-F " fi b=$(basename $0) awk "$ifs" '{print $'${b#col}'}' "$@" byobu-7.15/usr/bin/ctail000077500000000000000000000017001522352767600152060ustar00rootroot00000000000000#!/bin/sh # # ctail - colorize and follow a log file # # Copyright (C) 2012 Dustin Kirkland # # Authors: # Dustin Kirkland # # 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, version 3 of the License. # # 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, see . if which ccze >/dev/null 2>&1; then tail -F "$@" | ccze -A else echo "ERROR: ccze not found, hint..." 1>&2 echo " sudo apt-get install ccze" 2>&1 exit 1 fi byobu-7.15/usr/bin/manifest000077500000000000000000000036261522352767600157310ustar00rootroot00000000000000#!/bin/sh # # manifest - import/export a list of packages # Copyright (C) 2016 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . set -e if ! command -v pastebinit >/dev/null 2>&1; then echo "ERROR: pastebinit not found. Hint:" 1>&2 echo " sudo apt install pastebinit" 1>&2 exit 1 fi export_packages() { if [ "$OBJECT" = "-" ]; then dpkg -l elif echo "$OBJECT" | grep -qs ".*://.*"; then dpkg -l | gzip -9 | base64 | pastebinit -b "${OBJECT##*/}" else dpkg -l > "$OBJECT" fi } import_packages() { if [ "$OBJECT" = "-" ]; then sudo apt install $(cat /dev/stdin | grep "^ii\s" | col2) elif echo "$OBJECT" | grep -qs ".*://.*"; then sudo apt install $(wget -q -O- "$OBJECT" | grep -A 999999999 '
' | grep -B 999999999 "^
" | sed -e "s/.*
//" -e "s/^<\/pre>.*//" | base64 -d | gunzip | grep "^ii\s" | col2)
	else
		sudo apt install $(cat "$OBJECT" | grep "^ii\s" | col2)
	fi
}

usage() {
	cat <
#
#    Authors: Dustin Kirkland 
#             Kees Cook 
#
#    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, version 3 of the License.
#
#    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, see .

# apt autoremove supposedly works correctly now.
#
# Thus, we're deprecating the functionality previously found
# in purge-old-kernels.
#
# If you still have old kernels lying around after this, please
# file a bug against apt: https://bugs.launchpad.net/ubuntu/+source/apt/+filebug

echo "WARNING: purge-old-kernels is deprecated and will be removed in a future release." >&2
echo "         Use 'sudo apt autoremove' instead to remove old kernel packages." >&2
echo "" >&2

sudo apt-get $@ autoremove
byobu-7.15/usr/bin/tmpfsffs000077500000000000000000000020651522352767600157470ustar00rootroot00000000000000#!/bin/sh
#
#    tmpfsffs - setup /tmp on tmpfs, for faster seeks
#    Copyright (C) 2016 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .


set -e

if grep -qs "^tmpfs[[:space:]]/tmp[[:space:]]tmpfs" /etc/fstab; then
	echo "SUCCESS: /tmp is already a tmpfs"
else
	echo "tmpfs /tmp tmpfs rw,nosuid,nodev,noexec" >> /etc/fstab
	dir=$(mktemp -d "/dev/shm/tmp.XXXXXXXXXXXX")
	mv /tmp/* /tmp/.* "$dir/"
	mount -a
	mv "$dir/"* "$dir/."* /tmp/
fi
byobu-7.15/usr/bin/vigpg000077500000000000000000000051201522352767600152260ustar00rootroot00000000000000#!/bin/sh
#
#    vigpg - edit an encrypted file
#    Copyright (C) 2010-2015 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .


set -e

# Create a temporary workspace, in memory
# Note that this unfortunately is not mlock(2)-able
cleartext_file=$(mktemp /dev/shm/.vigpg-XXXXXXXXXXXX)

# Ensure that we always remove the cleartext_file on any exit
trap "shred -f ${cleartext_file} ${cleartext_file}.gpg 2>/dev/null || true" EXIT HUP INT QUIT TERM

# Encrypted file from argv
encrypted_file="$1"

# Define our bail out function
error() {
	# Log to stderr
	echo "ERROR: $1" 1>&2
	# Remove our cleartext files, just in case the trap misses them somehow
	rm -f "$cleartext_file" "$cleartext_file".gpg
	# Exit non-zero to note the error condition
	exit 1
}

if ! which gpg >/dev/null 2>&1; then
	echo "ERROR: gpg not found, hint..." 1>&2
	echo "  sudo apt-get install gnupg" 2>&1
	exit 1
fi

# Try to decrypt the target file
if [ -e "$encrypted_file" ]; then
	rm -f "$cleartext_file"
	gpg -o "$cleartext_file" -d "$encrypted_file" 		|| error "Unable to decrypt target"
fi

# Grab a checksum of the cleartext data before modification
before=$(sha512sum "$cleartext_file")

# Open the target cleartext file in your editor of choice
# It's up to this editor to save the file, if edited
sensible-editor "$cleartext_file"				|| error "Unable to edit target"

# Calculate a checksum afterward, to dectect modification
after=$(sha512sum "$cleartext_file")

if [ "$before" != "$after" ]; then
	# File was modified, so we need to re-encrypt and overwrite our previous file
	run-one-until-success gpg --default-recipient-self -s -e "$cleartext_file"	 	|| error "Unable to re-encrypt target"
	cat "$cleartext_file".gpg > "$1"				|| error "Unable to write new encrypted file"
	echo
	echo "Successfully encrypted update file [$encrypted_file]"
else
	# File was not modified, so do not re-encrypt/overwrite
	echo
	echo "The encrypted file was not modified [$encrypted_file]"
fi
rm -f "$cleartext_file" "$cleartext_file".gpg
byobu-7.15/usr/bin/whats-my-public-ip000066400000000000000000000001731522352767600175450ustar00rootroot00000000000000#!/bin/sh

#wget http://ipinfo.io/ip -qO -

curl -s checkip.dyndns.org | sed -e 's/.*Current IP Address: //' -e 's/<.*$//'
byobu-7.15/usr/bin/wifi-status000077500000000000000000000044231522352767600163760ustar00rootroot00000000000000#!/bin/sh
#
#    wifi-status - monitor a wireless network connection
#
#    Copyright (C) 2003-2014 Dustin Kirkland 
#
#    Authors:
#        Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

trap "pkill -f -9 wifi-status >/dev/null 2>&1; exit 0" EXIT HUP INT QUIT TERM

if [ -z "$1" ]; then
	dev=$(iw dev|grep Interface|awk '{print $2}')
else
	dev="$1"
fi

router=$(ip route show|head -n 1|awk '{print $3}')

# Allow users to override the connectivity ping target in statusrc
[ -r "$HOME/.byobu/statusrc" ] && . "$HOME/.byobu/statusrc" 2>/dev/null || true
WIFI_PING_TARGET="${WIFI_PING_TARGET:-8.8.8.8}"

if [ -z "$TMUX" ]; then
	watch -n1 "iw $dev info; ip addr show $dev; ip route; echo; (journalctl -b --no-pager -q | grep -i $dev | tail -n 10 | sort -r); echo; ping -I $dev -c 1 $WIFI_PING_TARGET"
else
	# Note that the speedometer item will silently fail, if the speedometer command is not found;  I don't want byobu to depend on speedometer, but it can suggest it
	tmux new-window -n wifi-status "watch -c iw $dev info \| ccze -A" \; \
		split-window -t wifi-status -v "watch -c ip addr show $dev \| ccze -A" \; \
		split-window -t wifi-status -v "watch -c ip route \| ccze -A" \; \
		split-window -t wifi-status -h "ping -I $dev $router" \; \
		split-window -t wifi-status -v "watch -c journalctl -b --no-pager -q \| grep -i $dev \| tail -n 10 \| sort -r \| ccze -A" \; \
		split-window -t wifi-status -h "ping -I $dev $WIFI_PING_TARGET" \; \
		split-window -t wifi-status -v "speedometer -t $dev -r $dev" \; \
		select-layout -t wifi-status tiled
fi

while true; do
	if [ $(tmux list-panes -t wifi-status | wc -l) -lt 5 ]; then
		tmux kill-window -t wifi-status
		exit 0
	fi
	sleep 1
done
byobu-7.15/usr/lib/000077500000000000000000000000001522352767600141645ustar00rootroot00000000000000byobu-7.15/usr/lib/byobu/000077500000000000000000000000001522352767600153045ustar00rootroot00000000000000byobu-7.15/usr/lib/byobu/Makefile.am000066400000000000000000000006351522352767600173440ustar00rootroot00000000000000libdirdir = $(prefix)/lib/@PACKAGE@
dist_libdir_SCRIPTS = apport  arch  battery  cpu_count  cpu_freq  cpu_temp  color  custom  date  disk  disk_io  distro  entropy  fan_speed  hostname  ip_address  load_average  logo  mail  memory  menu  network  packages  processes  raid  reboot_required  release  services  session  swap  time  time_binary time_utc trash updates_available  uptime  users  whoami  wifi_quality
byobu-7.15/usr/lib/byobu/apport000077500000000000000000000030071522352767600165370ustar00rootroot00000000000000#!/bin/sh -e
#
#    apport: note if there are crash dumps available for apporting
#
#    Copyright (C) 2009 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__apport_detail() {
	for i in /var/crash/*.crash; do
		if [ -f "$i" ]; then
			printf "\nTo file bugs on the existing crash reports, run:\n"
			which apport-cli >/dev/null || printf "  sudo apt-get install apport\n"
			for i in /var/crash/*.crash; do
				printf "  apport-cli $i\n"
			done
			printf "\nTo clear the pending reports:\n"
			printf "  rm -f /var/crash/*.crash\n\n"
			return
		fi
	done
	printf "No pending crash reports\n"
}

__apport() {
	# Print {!} if a /var/crash/*.crash file exists
	for i in /var/crash/*.crash; do
		if [ -f "$i" ]; then
			color y k; printf "{!}"; color --
			return
		fi
	done
	rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/apport"*
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/arch000077500000000000000000000016241522352767600161520ustar00rootroot00000000000000#!/bin/sh -e
#
#    arch: print the machine architecture
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__arch_detail() {
	uname -a
}

__arch() {
	printf "%s " $(uname -m)
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/battery000077500000000000000000000137211522352767600167100ustar00rootroot00000000000000#!/bin/sh -e
#
#    battery: print the state of the battery
#
#    Copyright (C) 2009 Raphaël Pinson.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Raphaël Pinson 
#             Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__battery_detail() {
	local bat
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		apm 2>/dev/null || true
		return
	fi
	for bat in /proc/acpi/battery/*; do
		cat "$bat/info"
		cat "$bat/state"
	done
	# FIXME: do the same thing with the /sys interface
	if eval $BYOBU_TEST /usr/bin/upower >/dev/null 2>&1; then
		dev=$(upower -e | grep devices/ups | head -1)
		[ -n "$dev" ] && upower -i "$dev"
	fi
}

__battery() {
	local bat line present sign state percent full rem color bcolor dev BATTERY_STATUS
	# Linux support
	present=""; full="0"; rem="0"; state=""
	# OpenBSD support via apm(8)
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ] && eval $BYOBU_TEST apm >/dev/null 2>&1; then
		local apm_pct apm_ac
		apm_pct=$(apm -l 2>/dev/null)
		apm_ac=$(apm -a 2>/dev/null)
		if [ -n "$apm_pct" ] && [ "$apm_pct" != "255" ]; then
			rem="$apm_pct"
			full="100"
			present="1"
			case "$apm_ac" in
				0) state="discharging" ;;
				1) state="charging" ;;
				2) state="charged" ;;
				*) state="unknown" ;;
			esac
		fi
	fi
	if [ -z "$present" ]; then
	for bat in $BATTERY /sys/class/power_supply/* /proc/acpi/battery/*; do
		case "$bat" in
			/sys/*)
				if [ -r "$bat/uevent" ]; then
					TMP_FILE=$(mktemp) || continue
					trap 'rm -f "$TMP_FILE"' EXIT INT TERM
					sed 's/=/="/; s/$/"/' < "$bat/uevent" > "$TMP_FILE"
					. "$TMP_FILE"
					rm -f "$TMP_FILE"
					trap - EXIT INT TERM
					case "$POWER_SUPPLY_NAME" in AC|ac|Ac|aC) continue ;; esac
					present="$POWER_SUPPLY_PRESENT"
					# Some use "CHARGE", others use "ENERGY", still others "CAPACITY"
					[ -n "$POWER_SUPPLY_CHARGE_FULL" ] && full=$((POWER_SUPPLY_CHARGE_FULL+full))
					[ -n "$POWER_SUPPLY_ENERGY_FULL" ] && full=$((POWER_SUPPLY_ENERGY_FULL+full))
					[ -n "$POWER_SUPPLY_CHARGE_NOW" ] && rem=$((POWER_SUPPLY_CHARGE_NOW+rem))
					[ -n "$POWER_SUPPLY_ENERGY_NOW" ] && rem=$((POWER_SUPPLY_ENERGY_NOW+rem))
					if [ -n "$POWER_SUPPLY_CAPACITY" ] && [ ! -n "$POWER_SUPPLY_ENERGY_NOW" ] && [ ! -n "$POWER_SUPPLY_CHARGE_NOW" ]; then
						rem="$POWER_SUPPLY_CAPACITY" && full="100"
					fi
					[ "$POWER_SUPPLY_STATUS" != "Unknown" ] && state="$POWER_SUPPLY_STATUS"
				fi
			;;
			/proc/*)
				[ -f "$bat/info" ] || continue
				while read line; do
					set -- ${line}
					case "$line" in
						present:*)
							# make sure that this battery is present
							[ "$2" = "no" ] && continue 2
							present="$2";;
					   	last\ full\ capacity:*) full="$4";;
					esac
					[ -n "$present" -a -n "$full" ] && break
				done < "${bat}/info"
				while read line; do
					set -- ${line}
					case "$line" in
						remaining\ capacity:*) rem="$3";;
						charging\ state:*) state="$3";;
					esac
					[ -n "$rem" -a -n "$state" ] && break
				done < "$bat/state"
				[ -n "$full" ] && [ -n "$rem" ] && [ -n "$state" ] && break
			;;
		esac
	done
	# upower fallback if /proc and /sys didn't work, e.g., with an APC UPS via USB HID
	if [ $full -eq 0 ] && [ $rem -eq 0 ] && [ -z "$present" ] && [ -z "$state" ]; then
		if eval $BYOBU_TEST /usr/bin/upower >/dev/null 2>&1; then
			dev=$(upower -e | grep devices/ups | head -1)
			if [ -n "$dev" ]; then
				BATTERY_STATUS=$(upower -i "$dev")
				full="100"
				present=$(printf "%s" "$BATTERY_STATUS" | awk '/present/ { print $2}')
				rem=$(printf "%s" "$BATTERY_STATUS" | awk '/percentage/ { gsub(/[^0-9]/, "", $2); print $2}')
				state=$(printf "%s" "$BATTERY_STATUS" | awk '/state/ { print $2}')
			fi
		fi
	fi
	# Mac OS X support
	if eval $BYOBU_TEST /usr/sbin/ioreg >/dev/null 2>&1; then
		# MacOS support
		local key
		for key in CurrentCapacity MaxCapacity ExternalChargeCapable FullyCharged; do
			line=$(/usr/sbin/ioreg -n AppleSmartBattery -w0 | grep -w $key | sed -e 's/|//g' | awk '{ print $3 }')
			case "$key" in
				CurrentCapacity) rem="$line";;
				MaxCapacity) full="$line";;
				ExternalChargeCapable)
					if [ "${line}" = "Yes" ]; then
						state="charging"
					elif [ "${line}" = "No" ]; then
						state="discharging"
					fi
				;;
				FullyCharged)
					if [ "${line}" = "Yes" ]; then
						state="charged"
					fi
				;;
			esac
		done
	fi
	fi  # end non-OpenBSD block
	# Android Termux support
	if eval $BYOBU_TEST termux-battery-status -h >/dev/null 2>&1; then
		BATTERY_STATUS=$(termux-battery-status)
		full=100
		rem=$(printf "%s" "$BATTERY_STATUS" | awk '/percentage/ { gsub(/[,]/,""); print $2}')
		state=$(printf "%s" "$BATTERY_STATUS" | awk '/status/ { gsub(/[",]/,""); print $2}')
	fi
	if [ $rem -ge 0 ] && [ $full -gt 0 ]; then
		percent=$(((100*$rem)/$full))
		if [ "$percent" -lt 33 ]; then
			color="R w"
			bcolor="b R w"
		elif [ "$percent" -lt 67 ]; then
			color="Y k"
			bcolor="b Y k"
		else
			color="G k"
			bcolor="b G k"
		fi
		percent="${percent}${PCT}"
		# Convert state to lower case
		state=$(printf "%s" "$state" | $BYOBU_SED 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/')
		case $state in
			charging) sign="+" ;;
			discharging) sign="-" ;;
			charged|unknown|full|fully-charged) sign="=" ;;
			*) sign="$state" ;;
		esac
		if [ -z "$percent" ]; then
			rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/battery"*
			return
		fi
		color $bcolor; printf "%s" "$percent"; color -; color $color; printf "%s" "$sign"; color --
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/color000077500000000000000000000020451522352767600163510ustar00rootroot00000000000000#!/bin/sh -e
#
#    color: print the background/foreground color escape codes
#
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__color_detail() {
	true
}

__color() {
	[ -z "$FOREGROUND" ] && FOREGROUND="w"
	[ -z "$BACKGROUND" ] && BACKGROUND="k"
	case "$BYOBU_BACKEND" in
		tmux)
			true
		;;
		screen)
			printf "\005{= $BACKGROUND$FOREGROUND}"
		;;
	esac
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/cpu_count000077500000000000000000000023151522352767600172320ustar00rootroot00000000000000#!/bin/sh -e
#
#    cpu_count: count cpu's on a systems
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__cpu_count_detail() {
	if [ -r /proc/cpuinfo ]; then
		grep -i "^model name" /proc/cpuinfo
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		sysctl -n hw.model 2>/dev/null
	fi
}

__cpu_count() {
	local c
	c=$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpuonline 2>/dev/null || grep -ci "^processor" /proc/cpuinfo 2>/dev/null || echo 1)
	[ "$c" = "1" ] || printf "%sx" "$c"
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/cpu_freq000077500000000000000000000047101522352767600170400ustar00rootroot00000000000000#!/bin/sh -e
#
#    cpu_freq: calculate current cpu frequency
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__cpu_freq_detail() {
	if [ -r /proc/cpuinfo ]; then
		cat /proc/cpuinfo
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		sysctl hw.cpuspeed hw.setperf 2>/dev/null
	fi
}

__cpu_freq() {
	local hz freq count
	if [ -r "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]; then
		read hz < /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
		fpdiv $hz "1000000" 1 # 1Ghz
		freq="$_RET"
	elif [ -r "/proc/cpuinfo" ]; then
		if egrep -q -s -i -m 1 "^cpu MHz|^clock" /proc/cpuinfo; then
			freq=$(egrep -i -m 1 "^cpu MHz|^clock" /proc/cpuinfo | awk -F"[:.]" '{ printf "%01.1f", $2 / 1000 }')
		else
			# Must scale frequency by number of processors, if counting bogomips
			count=$(getconf _NPROCESSORS_ONLN 2>/dev/null || grep -ci "^processor" /proc/cpuinfo)
			freq=$(egrep -i -m 1 "^bogomips" /proc/cpuinfo | awk -F"[:.]" '{ print $2 }')
			freq=$(printf "%s %s" "$freq" "$count" | awk '{printf "%01.1f\n", $1/$2/1000}')
			# If bogomips returns 0 (e.g., Ampere Altra processors), fall back to dmidecode
			if [ "$freq" = "0.0" ] && eval $BYOBU_TEST dmidecode >/dev/null 2>&1; then
				freq=$(dmidecode -t processor 2>/dev/null | awk -F': ' '/Current Speed:/ { print $2; exit }' | awk '{ printf "%01.1f", $1 / 1000 }')
			fi
		fi
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ] && hz=$(sysctl -n hw.cpuspeed 2>/dev/null) && [ -n "$hz" ]; then
		# OpenBSD: hw.cpuspeed is in MHz
		fpdiv "$hz" "1000" 1
		freq="$_RET"
	elif hz=$(sysctl -n hw.cpufrequency 2>/dev/null) && [ -n "$hz" ]; then
		fpdiv "$hz" "1000000000" 1 # 1Ghz
		freq="$_RET"
	fi
	[ -n "$freq" ] || return
	color b c W; printf "%s" "$freq"; color -; color c W; printf "%s" "$ICON_GHz"; color --
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/cpu_temp000077500000000000000000000051741522352767600170550ustar00rootroot00000000000000#!/bin/sh -e
#
#    cpu_temp: cpu temperature
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__cpu_temp_detail() {
	local i
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		sysctl hw.sensors 2>/dev/null | grep -i temp
		return
	fi
	for i in $MONITORED_TEMP /sys/class/hwmon/hwmon*/device/temp*_input /sys/class/hwmon/hwmon*/temp*_input /proc/acpi/ibm/thermal /proc/acpi/thermal_zone/*/temperature /sys/class/thermal/thermal_zone*/temp; do
		[ -r "$i" ] || continue
		printf "%s\n" "$i:"
		cat "$i"/*
	done
}

__cpu_temp() {
	local i t unit
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# OpenBSD: read CPU temperature from hw.sensors
		# Match CPU temp sensors: cpu (Intel coretemp), km/ksmn (AMD),
		# inteldrm, or acpitz as fallback
		t=$(sysctl hw.sensors 2>/dev/null | awk '
			/(cpu|km|ksmn|inteldrm)[0-9]*\.temp[0-9]/ {
				split($0,a,"="); split(a[2],b," "); v=int(b[1])
				if (v>0) { print v; exit }
			}
			/acpitz[0-9]*\.temp[0-9]/ {
				if (!f) { split($0,a,"="); split(a[2],b," "); f=int(b[1]) }
			}
			END { if (f) print f }
		')
		if [ -n "$t" ] && [ "$t" -gt 0 ] 2>/dev/null; then
			unit="$ICON_C"
			if [ "$TEMP" = "F" ]; then
				t=$(($t*9/5 + 32))
				unit="$ICON_F"
			fi
			color b k Y; printf "%s" "$t"; color -; color k Y; printf "%s" "$unit"; color --
		fi
		return
	fi
	for i in $MONITORED_TEMP /sys/class/hwmon/hwmon*/device/temp*_input /sys/class/hwmon/hwmon*/temp*_input /proc/acpi/ibm/thermal /proc/acpi/thermal_zone/*/temperature /sys/class/thermal/thermal_zone*/temp; do
		case "$i" in
			*temp*_input|*thermal_zone*/temp)
				[ -s "$i" ] && read t < "$i" && t=$(($t/1000))
			;;
			*)
				[ -s "$i" ] && t=$($BYOBU_SED -e "s/^[^0-9]\+//" -e "s/\s.*$//" "$i")
			;;
		esac
		if [ -n "$t" ] && [ "$t" -gt 0 ]; then
			unit="$ICON_C"
			if [ "$TEMP" = "F" ]; then
				t=$(($t*9/5 + 32))
				unit="$ICON_F"
			fi
			color b k Y; printf "%s" "$t"; color -; color k Y; printf "%s" "$unit"; color --
			break
		fi
	done
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/custom000077500000000000000000000036431522352767600165520ustar00rootroot00000000000000#!/bin/sh -e
#
#    custom: run the user's custom status scripts
#
#    Copyright (C) 2009 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__custom_detail() {
	return
}

__custom() {
	local cache="$BYOBU_RUN_DIR/cache.$BYOBU_BACKEND/custom"
	local i= output=
	for i in "$BYOBU_CONFIG_DIR/bin/"[0-9]*_*; do
		# Loop over custom scripts
		# Ensure executable
		[ -x "$i" ] || continue
		# Ignore vim backup files ending in ~
		case "$i" in
			*~) continue ;;
		esac
		local now="$(date +%s)"
		local script=${i##*/}
		local freq=${script%%_*}
		freq=${freq#0}
		local lastrun=
		[ -r "$cache.$script.last" ] && read lastrun < "$cache.$script.last" || lastrun=0
		local expiration=$(($lastrun+$freq))
		if [ $now -ge $expiration ]; then
			"$i" > "$cache.$script" 2>/dev/null
			printf "%s\n" "${now}" > "$cache.$script.last"
		fi
		readfile < "$cache.$script"
		local str="${_RET}"
		[ -n "$str" ] || continue
		case "$str" in
			*"$ESC{"*)
				# User has formatted the colors
				output="$output$(printf "$str")"
			;;
			*)
				# Default coloring
				output="$output$str "
			;;
		esac
	done
	if [ -z "$output" ]; then
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/custom"*
		return
	fi
	printf "$output" | $BYOBU_SED ':a;N;$!ba;s/\n//g'
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/date000077500000000000000000000017361522352767600161560ustar00rootroot00000000000000#!/bin/sh -e
#
#    date: print the date in YYYY-MM-DD format
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__date_detail() {
	date
}

__date() {
	case "$BYOBU_BACKEND" in
		screen)
			color none; printf "\005Y-\005m-\005d"; color --
		;;
	esac
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/disk000077500000000000000000000036231522352767600161700ustar00rootroot00000000000000#!/bin/sh -e
#
#    disk: print the current disk space and usage
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__disk_detail() {
	df -h
}

__disk() {
	local out="" MP="" size="" pct="" unit=""
	# Default to /, but let users override
	[ -z "$MONITORED_DISK" ] && MP="/" || MP="$MONITORED_DISK"
	case $MP in
		/dev/*)
			if [ -r /proc/mounts ]; then
				MP=$(awk '$1 == m { print $2; exit(0); }' "m=$MP" /proc/mounts)
			else
				MP=$(mount | awk -v m="$MP" '$1 == m { print $3; exit(0); }')
			fi
		;;
	esac
	# this could be done faster with 'stat --file-system --format'
	# but then we'd have to do blocks -> human units ourselves
	out=$(df -h "$MP" 2>/dev/null | awk 'END { printf("%s %s", $2, $5); }')
	set -- ${out}
	size=${1}; pct=${2};
	unit=${size#${size%?}} # get the unit (last char)
	size=${size%?}; # take the unit off
	pct=${pct%?}; # take off the '%'
	case "$unit" in
		k*|K*) unit="$ICON_KB" ;;
		m*|M*) unit="$ICON_MB" ;;
		g*|G*) unit="$ICON_GB" ;;
		t*|T*) unit="$ICON_TB" ;;
	esac
	[ -n "$size" ] || return
	color b m W; printf "%s" "$size"; color -; color m W; printf "%s" "$unit"; color -;
	color b m W; printf "%s" "$pct";  color -; color m W; printf "%s" "$PCT"; color --;
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/disk_io000077500000000000000000000123441522352767600166570ustar00rootroot00000000000000#!/bin/sh -e
#
#    disk_io: calculate the disk io rate
#
#    Copyright (C) 2010 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__disk_io_detail() {
	if eval $BYOBU_TEST iostat >/dev/null; then
		iostat -d -m -h
	else
		printf "%s\n" "Please install iostat if you want detailed information on your disk throughput"
	fi
}


getdisk() {
	local t=""
	if [ -L "${1}" ]; then
		t=$($BYOBU_READLINK -f "$1")
	else
		t="$1"
	fi
	t="${t##*/}"
	# If it's already a block device, use it as-is
	if [ -h "/sys/block/$t" ]; then
		_RET="$t"
	else
		# Strip partition number (trailing digits)
		rtrim "$t" "0-9"
		t="$_RET"
		# For NVMe (nvme0n1p2), MMC (mmcblk0p2), etc., also strip the 'p'
		# that precedes the partition number. If it ends with 'p' after
		# removing digits, it's likely this naming scheme.
		case "$t" in
			*p) _RET="${t%p}" ;;
			*) _RET="$t" ;;
		esac
	fi
}

__disk_io_openbsd() {
	local mount_point disk part kb xfr t2 t1 cache x1 x2 rate symbol unit
	[ -z "$MONITORED_DISK" ] && mount_point="/" || mount_point="$MONITORED_DISK"
	[ -n "$DISK_IO_THRESHOLD" ] || DISK_IO_THRESHOLD=50
	# Find the disk device for the mount point (e.g., /dev/sd0a -> sd0)
	part=$(mount | awk -v mp="$mount_point" '$3 == mp { print $1; exit }')
	[ -n "$part" ] || return
	disk="${part##*/}"
	# Strip partition letter (sd0a -> sd0)
	disk="${disk%[a-p]}"
	# Parse iostat -DI for cumulative KB transferred for this disk
	# Output format: disk_name  KB  xfr  time
	local iostat_line
	iostat_line=$(iostat -DI 2>/dev/null | awk -v d="$disk" '$1 == d { print $2; exit }')
	[ -n "$iostat_line" ] || return
	# iostat -DI gives total KB transferred (read+write combined)
	x2="$iostat_line"
	[ -n "$x2" ] || return
	cache="$BYOBU_RUN_DIR/cache.$BYOBU_BACKEND/disk.io"
	t2=$(date +%s)
	t1=$(stat -f %m "$cache" 2>/dev/null) || t1=0
	x1=0
	[ -r "$cache" ] && read x1 < "$cache"
	printf "%s" "$x2" > "$cache"
	if [ "$t2" -le "$t1" ] || [ "$t1" -eq 0 ]; then
		return
	fi
	rate=$(( (x2 - x1) / (t2 - t1) ))
	[ "$rate" -lt 0 ] && rate=0
	if [ "$rate" -lt "$DISK_IO_THRESHOLD" ]; then
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/disk_io"*
		return
	fi
	# Combined read+write from iostat; show both direction symbols
	symbol="${ICON_RD}${ICON_WR}"
	if [ "$rate" -gt 1048576 ]; then
		unit="GB/s"
		fpdiv "$rate" 1048576 0
		rate=${_RET}
	elif [ "$rate" -gt 1024 ]; then
		unit="MB/s"
		fpdiv "$rate" 1024 0
		rate=${_RET}
	else
		unit="kB/s"
	fi
	if [ -z "$rate" ] || [ "$rate" = "0" ]; then
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/disk_io"*
	else
		color b M W; printf "%s%s" "$symbol" "$rate"; color -; color M W; printf "%s" "$unit"; color --
	fi
}

__disk_io() {
	local part= i=
	# OpenBSD: use iostat -DI instead of /sys/block
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		__disk_io_openbsd
		return
	fi
	# Default to disk providing /, but let users override with MONITORED_DISK
	[ -z "$MONITORED_DISK" ] && mount_point="/" ||  mount_point="$MONITORED_DISK"
	# By default, we won't bug the user with the display of disk throughput
	# below DISK_IO_THRESHOLD in kB/s; override in $BYOBU_CONFIG_DIR/status
	[ -n "$DISK_IO_THRESHOLD" ] || DISK_IO_THRESHOLD=50
	case "$mount_point" in
		/dev/*) part="${mount_point}";;
		*) part=$(awk '$2 == mp { print $1 ; exit(0); }' "mp=$mount_point" /etc/mtab);;
	esac
	[ -e "$part" ] || return
	getdisk "$part"
	local disk=${_RET}
	local t2=$(date +%s) t1=
	local over_threshold=0
	for i in "read" "write"; do
		local cache="$BYOBU_RUN_DIR/cache.$BYOBU_BACKEND/disk.$i"
		t1=$(stat -c %Y "$cache") 2>/dev/null || t1=0
		local unit="kB/s"
		local rate=0 x1=0 x2=0 symbol= unit=
		if [ $t2 -le $t1 ]; then
			rate=0
		else
			[ -r "$cache" ] && read x1 < "$cache"
			local a1= a2= a3= a4= a5= a6= a7= a8= a9= a10=
			read a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 other < "/sys/block/$disk/stat"
			if [ "$i" = "read" ]; then
				symbol="$ICON_RD"
				[ -n "$a3" ] && x2="$a3" || x2=0
			else
				symbol="$ICON_WR"
				[ -n "$a7" ] && x2="$a7" || x2=0
			fi
			printf "%s\n" "$x2" > "$cache"
			rate=$((($x2 - $x1) / ($t2 - $t1) * 512 / 1024))
			if [ "$rate" -lt 0 ]; then
				rate=0
			elif [ "$rate" -gt 1048576 ]; then
				unit="GB/s"
				fpdiv "$rate" 1048576 0
				rate=${_RET}
			elif [ "$rate" -gt 1024 ]; then
				unit="MB/s"
				fpdiv "$rate" 1024 0
				rate=${_RET}
			else
				unit="kB/s"
			fi
		fi
		if [ -n "$rate" ] && [ "$rate" != "0" ] && [ $rate -ge $DISK_IO_THRESHOLD ]; then
			over_threshold=1
			color b M W; printf "%s%s" "$symbol" "$rate"; color -; color M W; printf "%s" "$unit"; color --
		fi
	done
	if [ "$over_threshold" = "0" ]; then
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/disk_io"*
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/distro000077500000000000000000000020441522352767600165360ustar00rootroot00000000000000#!/bin/sh -e
#
#    distro: grab the distro/os
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__distro_detail() {
	lsb_release -a 2>/dev/null
}

__distro() {
	local DISTRO="${DISTRO}"
	if [ -n "$DISTRO" ]; then
		# user defined
		true
	else
		DISTRO="$BYOBU_DISTRO"
	fi
	color bold2; printf "%s" "$DISTRO"; color --
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/entropy000077500000000000000000000024671522352767600167430ustar00rootroot00000000000000#!/bin/sh -e
#
#    entropy: system entropy
#
#    Copyright (C) 2011-2014 Dustin Kirkland 
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__entropy_detail() {
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		printf "%s\n" "OpenBSD uses arc4random(3) -- always seeded, no pool metric."
	else
		cat /proc/sys/kernel/random/entropy_avail 2>/dev/null
	fi
}

__entropy() {
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# OpenBSD uses arc4random(3); entropy is always sufficient
		return
	elif [ -r /proc/sys/kernel/random/entropy_avail ]; then
		local e=$(cat /proc/sys/kernel/random/entropy_avail)
		[ -n "$e" ] || return
		color K Y; printf "e%s" "$e"; color --
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/fan_speed000077500000000000000000000052241522352767600171610ustar00rootroot00000000000000#!/bin/sh -e
#
#    fan_speed: speed of the cpu or case fan
#
#    Copyright (C) 2009 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__fan_speed_detail() {
	# Nothing interesting to say here about fan speed
	return
}

__fan_speed() {
	local i="" speed=0
	# OpenBSD: read fan speed from hw.sensors
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		speed=$(sysctl hw.sensors 2>/dev/null | awk -F'=' '/fan[0-9]/ { print $2+0; exit }')
		if [ -n "$speed" ] && [ "$speed" -gt 0 ] 2>/dev/null; then
			color bold1; printf "%s" "$speed"; color -; color none; printf "rpm"; color --
			return 0
		fi
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/fan_speed"*
		return 0
	fi
	# Let's check a few different probes for fan speed
	# This seems to cover most of them:
	for i in $FAN /sys/class/hwmon/*/*/fan1_input /sys/class/hwmon/*/device/hwmon/*/fan1_input; do
		[ -f "$i" ] || continue
		read speed < "$i"
		if [ -n "$speed" ]; then
			if [ "$speed" -gt 0 ]; then
				color bold1; printf "%s" "$speed"; color -; color none; printf "rpm"; color --
				return 0
			else
				# Fan is at 0 RPM, clear any cached values
				rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/fan_speed"*
				return 0
			fi
		fi
	done

	# But others (e.g. Dell Inspirons) seem to be here:
	if [ -r /proc/i8k ]; then
		local line=""
		read line < /proc/i8k
		set -- $line
		for speed in $7 $8; do
			if [ -n "$speed" ]; then
				if [ "$speed" -gt 0 ]; then
					# I8K_FAN_MULT defaults to 30 (buggy BIOS workaround?),
					# use `modprobe i8k fan_mult=1` to disable if unneeded,
					# resulting in nonsensical speeds
					[ "$speed" -gt 10000 ] && speed=$((${speed} / 30))
					color bold1; printf "%s" "$speed"; color -; color none; printf "rpm"; color --
					return 0
				else
					# Fan is at 0 RPM, clear any cached values
					rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/fan_speed"*
					return 0
				fi
			fi
		done
	fi
	# No fan found or couldn't read speed, clear cache
	rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/fan_speed"*
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/hostname000077500000000000000000000031341522352767600170510ustar00rootroot00000000000000#!/bin/bash -e
#
#    hostname: report a host's name
#    Note: Uses decimal sleep (0.02) which requires bash
#
#    Copyright (C) 2008-2011 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__hostname_detail() {
	hostname -f 2>/dev/null
}

__hostname() {
	local h=
	if eval $BYOBU_TEST hostname >/dev/null 2>&1; then
		h=$(hostname -s 2>/dev/null || hostname)
	elif [ -r /proc/sys/kernel/hostname ]; then
		read h < /proc/sys/kernel/hostname
	fi
	if metadata_available; then
		local cache="$BYOBU_RUN_DIR/cache.$BYOBU_BACKEND/hostname"
		# Background a retrieval of our public hostname
		timeout 0.2 wget -q -O- http://169.254.169.254/latest/meta-data/public-hostname "$cache" 2>/dev/null &
		# Brief sleep allows background wget to complete for immediate display (requires bash)
		sleep 0.02
		[ -s "$cache" ] && read h < "$cache"
	fi
	[ -n "$h" ] || return
	color bold2; printf "%s" "$h"; color --
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/include/000077500000000000000000000000001522352767600167275ustar00rootroot00000000000000byobu-7.15/usr/lib/byobu/include/Makefile.am000066400000000000000000000004361522352767600207660ustar00rootroot00000000000000inclibdirdir = $(prefix)/lib/@PACKAGE@/include
dist_inclibdir_SCRIPTS = common colors config.py constants cycle-status dirs icons mondrian notify_osd shutil select-session.py tmux-detach-all-but-current-client tmux-send-command-to-all-panes tmux-send-command-to-all-windows toggle-utf8
byobu-7.15/usr/lib/byobu/include/colors000066400000000000000000000020251522352767600201520ustar00rootroot00000000000000#!/bin/sh
#
#    colors: some color values needed by all library status scripts
#
#    Copyright (C) 2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

# Default colors
# Inspired by http://design.ubuntu.com/brand/colour-palette

# Cool grey
export BYOBU_DARK="#333333"

# Warm white
export BYOBU_LIGHT="#EEEEEE"

# Aubergine
export BYOBU_ACCENT="#75507B"

# Ubuntu orange
export BYOBU_HIGHLIGHT="#DD4814"
byobu-7.15/usr/lib/byobu/include/common000077500000000000000000000041401522352767600201440ustar00rootroot00000000000000#!/bin/sh
#
#    common: common stuff sourced by all scripts
#
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

if [ -z "${BYOBU_INCLUDED_LIBS}" ]; then
	# Needed to set up $BYOBU_CONFIG_DIR
	. "${BYOBU_PREFIX}/lib/${PKG}/include/dirs"

	# Find command/type/which
	for BYOBU_TEST in "command -v" "type" "which"; do
		eval $BYOBU_TEST ls >/dev/null 2>&1 && break || true
	done

	# If the backend is already set (eg. running `byobu-tmux`), do nothing.
	if [ -z "${BYOBU_BACKEND}" ]; then
		[ -r "/etc/$PKG/backend" ] && . "/etc/$PKG/backend"
		[ -r "$BYOBU_CONFIG_DIR/backend" ] && . "$BYOBU_CONFIG_DIR/backend"
		# Just in case there's no config file at all
		if [ -z "${BYOBU_BACKEND}" ]; then
			# New byobu configuration, default to tmux
			if eval $BYOBU_TEST tmux >/dev/null; then
				BYOBU_BACKEND="tmux"
			elif eval $BYOBU_TEST screen >/dev/null; then
				BYOBU_BACKEND="screen"
			else
				printf "%s\n" "ERROR: $PKG won't work without tmux or screen installed" 1>&2
			fi
		fi
  	fi

	# Creating backend cache
	[ -d "$BYOBU_RUN_DIR/cache.$BYOBU_BACKEND" ] || mkdir -p "$BYOBU_RUN_DIR/cache.$BYOBU_BACKEND"

	. "${BYOBU_PREFIX}/lib/${PKG}/include/shutil"
	. "${BYOBU_PREFIX}/lib/${PKG}/include/constants"
	get_distro || true
	export BYOBU_DISTRO="$_RET"
	BYOBU_INCLUDED_LIBS=1
fi

case "$1" in
	-v|--version) [ "$(basename $0)" != "byobu" ] && exec byobu -v ;;
	-h|--help) exec man $(basename $0) ;;
esac
# Workaround: ending with esac breaks stdout, so add a no-op
true
byobu-7.15/usr/lib/byobu/include/config.py.in000077500000000000000000000247361522352767600211720ustar00rootroot00000000000000#!/usr/bin/env python3
#
#    config.py
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2008-2014 Dustin Kirkland 

#
#    Authors: Nick Barcet 
#             Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

# If you change any strings, please generate localization information with:
#       ./debian/rules get-po

from __future__ import print_function
import sys
import os
import os.path
import time
import string
import subprocess
import gettext
import glob


def error(msg):
	print("ERROR: %s" % msg)
	sys.exit(1)


try:
	import snack
	from snack import *
except Exception:
	error("Could not import the python snack module")


PKG = "byobu"
HOME = os.getenv("HOME")
USER = os.getenv("USER")
BYOBU_CONFIG_DIR = os.getenv("BYOBU_CONFIG_DIR", HOME + "/.byobu")
BYOBU_RUN_DIR = os.getenv("BYOBU_RUN_DIR", HOME + "/.cache/byobu")
BYOBU_BACKEND = os.getenv("BYOBU_BACKEND", "tmux")
BYOBU_SOCKETDIR = os.getenv("SOCKETDIR", "/var/run/screen")
BYOBU_PREFIX = os.getenv("BYOBU_PREFIX", "@prefix@")
SHARE = BYOBU_PREFIX + '/share/' + PKG
DOC = BYOBU_PREFIX + '/share/doc/' + PKG
if not os.path.exists(SHARE):
	SHARE = BYOBU_CONFIG_DIR + "/" + SHARE
if not os.path.exists(DOC):
	DOC = BYOBU_PREFIX + '/share/doc/packages/' + PKG
if not os.path.exists(DOC):
	DOC = BYOBU_CONFIG_DIR + "/" + DOC
DEF_ESC = "A"
RELOAD = "If you are using the default set of keybindings, press\n or  to activate these changes.\n\nOtherwise, exit this session and start a new one."
RELOAD_FLAG = "%s/reload-required" % (BYOBU_RUN_DIR)
ESC = ''
snack.hotkeys[ESC] = ord(ESC)
snack.hotkeys[ord(ESC)] = ESC
gettext.bindtextdomain(PKG, SHARE + '/po')
gettext.textdomain(PKG)
_ = gettext.gettext


def ioctl_GWINSZ(fd):
	# Discover terminal width
	try:
		import fcntl
		import termios
		import struct
		import os
		cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
	except Exception:
		return None
	return cr


def reload_required():
	try:
		if not os.path.exists(BYOBU_CONFIG_DIR):
			# 493 (decimal) is 0755 (octal)
			# Use decimal for portability across all python versions
			os.makedirs(BYOBU_CONFIG_DIR, 493)
		f = open(RELOAD_FLAG, 'w')
		f.close()
		if BYOBU_BACKEND == "screen":
			subprocess.call([BYOBU_BACKEND, "-X", "at", "0", "source", "%s/profile" % BYOBU_CONFIG_DIR])
	except Exception:
		True


def terminal_size():
	# decide on some terminal size
	cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
	# try open fds
	if not cr:
		# ...then ctty
		try:
			fd = os.open(os.ctermid(), os.O_RDONLY)
			cr = ioctl_GWINSZ(fd)
			os.close(fd)
		except Exception:
			pass
	if not cr:
		# env vars or finally defaults
		try:
			cr = (env['LINES'], env['COLUMNS'])
		except Exception:
			cr = (25, 80)
	# reverse rows, cols
	return int(cr[1] - 5), int(cr[0] - 5)


def menu(snackScreen, size, isInstalled):
	if isInstalled:
		installtext = _("Byobu currently launches at login (toggle off)")
	else:
		installtext = _("Byobu currently does not launch at login (toggle on)")
	li = Listbox(height=6, width=60, returnExit=1)
	li.append(_("Help -- Quick Start Guide"), 1)
	li.append(_("Toggle status notifications"), 2)
	li.append(_("Change escape sequence"), 3)
	li.append(installtext, 4)
	bb = ButtonBar(snackScreen, (("Exit", "exit", ESC),), compact=1)
	g = GridForm(snackScreen, _(" Byobu Configuration Menu"), 1, 2)
	g.add(li, 0, 0, padding=(4, 2, 4, 2))
	g.add(bb, 0, 1, padding=(1, 1, 0, 0))
	if bb.buttonPressed(g.runOnce()) == "exit":
		return 0
	else:
		return li.current()


def messagebox(snackScreen, width, height, title, text, scroll=0, buttons=((_("Okay"), "okay"), (_("Cancel"), "cancel", ESC))):
	t = Textbox(width, height, text, scroll=scroll)
	bb = ButtonBar(snackScreen, buttons, compact=1)
	g = GridForm(snackScreen, title, 1, 2)
	g.add(t, 0, 0, padding=(0, 0, 0, 0))
	g.add(bb, 0, 1, padding=(1, 1, 0, 0))
	return bb.buttonPressed(g.runOnce())


def help(snackScreen, size):
	f = open(DOC + '/help.' + BYOBU_BACKEND + '.txt')
	text = f.read()
	f.close()
	text = text.replace("", getesckey(), 1)
	t = Textbox(67, 16, text, scroll=1, wrap=1)
	bb = ButtonBar(snackScreen, ((_("Menu"), "menu", ESC),), compact=1)
	g = GridForm(snackScreen, _("Byobu Help"), 2, 4)
	g.add(t, 1, 0)
	g.add(bb, 1, 1, padding=(1, 1, 0, 0))
	button = bb.buttonPressed(g.runOnce())
	return 100


def readstatus():
	status = {}
	glo = {}
	loc = {}
	for f in [SHARE + '/status/status', BYOBU_CONFIG_DIR + '/status']:
		if os.path.exists(f):
			try:
				exec(open(f).read(), glo, loc)
			except Exception:
				error("Invalid configuration [%s]" % f)
			if BYOBU_BACKEND == "tmux":
				items = "%s %s" % (loc["tmux_left"], loc["tmux_right"])
			else:
				items = "%s %s %s %s" % (loc["screen_upper_left"], loc["screen_upper_right"], loc["screen_lower_left"], loc["screen_lower_right"])
			for i in items.split():
				if i.startswith("#"):
					i = i.replace("#", "")
					status[i] = "0"
				else:
					status[i] = "1"
	li = []
	keys = list(status.keys())
	for i in sorted(keys):
		window = [int(status[i]), i]
		li.append(window)
	return li


def genstatusstring(s, status):
	new = ""
	glo = {}
	loc = {}
	exec(open(SHARE + '/status/status').read(), glo, loc)
	for i in loc[s].split():
		if i.startswith("#"):
			i = i.replace("#", "")
		if status[i] == 1:
			new += " " + i
		else:
			new += " #" + i
	return new


def writestatus(items):
	status = {}
	path = BYOBU_CONFIG_DIR + '/status'
	for i in items:
		status[i[1]] = i[0]
	for key in ["tmux_left", "tmux_right", "screen_upper_left", "screen_upper_right", "screen_lower_left", "screen_lower_right"]:
		if key.startswith(BYOBU_BACKEND):
			try:
				f = open(path, "r")
			except Exception:
				f = open(SHARE + '/status/status', "r")
			lines = f.readlines()
			f.close()
			try:
				f = open(path, "w")
			except Exception:
				f = open(path, "a+")
			for l in lines:
				if l.startswith("%s=" % key):
					val = genstatusstring(key, status)
					f.write("%s=\"%s\"\n" % (key, val))
				else:
					f.write(l)
			f.close


def togglestatus(snackScreen, size):
	itemlist = readstatus()
	rl = Label("")
	r = CheckboxTree(12, scroll=1)
	count = 0
	for item in itemlist:
		if item[0] != -1:
			r.append(item[1], count, selected=item[0])
		count = count + 1
	bb = ButtonBar(snackScreen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact=1)
	g = GridForm(snackScreen, _("Toggle status notifications"), 2, 4)
	g.add(rl, 0, 0, anchorLeft=1, anchorTop=1, padding=(4, 0, 0, 1))
	g.add(r, 1, 0)
	g.add(bb, 1, 1, padding=(4, 1, 0, 0))
	if bb.buttonPressed(g.runOnce()) != "cancel":
		count = 0
		for item in itemlist:
			if item[0] != -1:
				item[0] = r.getEntryValue(count)[1]
			count = count + 1
		writestatus(itemlist)
		reload_required()
	return 100


def install(snackScreen, size, isInstalled):
	out = ""
	if isInstalled:
		if subprocess.call(["byobu-launcher-uninstall"]) == 0:
			out = _("Byobu will not be launched next time you login.")
		button = messagebox(snackScreen, 60, 2, _("Message"), out, buttons=((_("Menu"), )))
		return 101
	else:
		if subprocess.call(["byobu-launcher-install"]) == 0:
			out = _("Byobu will be launched automatically next time you login.")
		button = messagebox(snackScreen, 60, 2, "Message", out, buttons=((_("Menu"), )))
		return 100


def appendtofile(p, s):
	f = open(p, 'a')
	try:
		f.write(s)
	except IOError:
		f.close()
		return
	f.close()
	return


def getesckey():
	line = ""
	if BYOBU_BACKEND == "tmux":
		path = BYOBU_CONFIG_DIR + '/keybindings.tmux'
		if os.path.exists(path):
			for l in open(path):
				if l.startswith("set -g prefix "):
					line = l
		else:
			return DEF_ESC
	else:
		path = BYOBU_CONFIG_DIR + '/keybindings'
		if os.path.exists(path):
			for l in open(path):
				if l.startswith("escape "):
					line = l
		else:
			return DEF_ESC
	if line == "":
		return DEF_ESC
	esc = line[line.find('^') + 1]
	if esc == "`":
		esc = " "
	return esc


def setesckey(key):
	if key.isalpha():
		# throw away outputs in order that the view isn't broken
		nullf = open(os.devnull, "w")
		subprocess.call(["byobu-ctrl-a", "screen", key], stdout=nullf)
		nullf.close()


def chgesc(snackScreen, size):
	esc = Entry(2, text=getesckey(), returnExit=1)
	escl = Label(_("Escape key: ctrl-"))
	bb = ButtonBar(snackScreen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact=1)
	g = GridForm(snackScreen, _("Change escape sequence"), 2, 4)
	g.add(escl, 0, 0, anchorLeft=1, padding=(1, 0, 0, 1))
	g.add(esc, 1, 0, anchorLeft=1)
	g.add(bb, 1, 1)
	g.setTimer(100)
	loop = 1
	while loop:
		which = g.run()
		if which == "TIMER":
			val = esc.value()
			if len(val) > 1:
				esc.set(val[1])
			# Ensure that escape sequence is not \ or /
			if val == '/' or val == '\\':
				esc.set(DEF_ESC)
			# Ensure that the escape sequence is not set to a number
			try:
				dummy = int(esc.value())
				esc.set(DEF_ESC)
			except Exception:
				# do nothing
				dummy = "foo"
		else:
			loop = 0
	snackScreen.popWindow()
	button = bb.buttonPressed(which)
	if button != "cancel":
		setesckey(esc.value())
		reload_required()
		if button == "exit":
			return 0
	return 100


def autolaunch():
	if os.path.exists(BYOBU_CONFIG_DIR + "/disable-autolaunch"):
		return 0
	try:
		for line in open("%s/.profile" % HOME):
			if "byobu-launch" in line:
				return 1
	except Exception:
		return 0
	if os.path.exists("/etc/profile.d/Z97-%s.sh" % PKG):
		return 1
	return 0


def main():
	"""This is the main loop of our utility"""
	size = terminal_size()
	snackScreen = SnackScreen()
	snackScreen.drawRootText(1, 0, _('Byobu Configuration Menu'))
	snackScreen.pushHelpLine(_(' between elements |  selects |  exits'))
	isInstalled = autolaunch()
	tag = 100
	while tag > 0:
		tag = menu(snackScreen, size, isInstalled)
		if tag == 1:
			tag = help(snackScreen, size)
		elif tag == 2:
			tag = togglestatus(snackScreen, size)
		elif tag == 3:
			tag = chgesc(snackScreen, size)
		elif tag == 4:
			tag = install(snackScreen, size, isInstalled)
			isInstalled = autolaunch()
	snackScreen.finish()
	sys.exit(0)


if __name__ == "__main__":
	main()
byobu-7.15/usr/lib/byobu/include/constants000077500000000000000000000065611522352767600207010ustar00rootroot00000000000000#!/bin/sh
#
#    constants: some constant values needed by all library status scripts
#
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

PKG="byobu"

. "${BYOBU_PREFIX}/lib/${PKG}/include/icons"
. "${BYOBU_PREFIX}/lib/${PKG}/include/colors"

PCT="%"

# Some shell(s) don't set the USER environment value (looking at you, ash)
[ -z "$USER" ] && export USER=$(whoami)

# Support two different backends (screen/tmux)
if [ -z "$BYOBU_BACKEND" ]; then
	[ -r "/etc/byobu/backend" ] && . "/etc/byobu/backend"
	[ -r "$BYOBU_CONFIG_DIR/backend" ] && . "$BYOBU_CONFIG_DIR/backend"
fi
case "$BYOBU_BACKEND" in
	tmux)
		export BYOBU_BACKEND
		BYOBU_ARG_VERSION="-V"
		ESC=
	;;
	screen)
		export BYOBU_BACKEND
		BYOBU_ARG_VERSION="-v"
		ESC="\005"
	;;
esac

# MacOS Support
eval $BYOBU_TEST gsed >/dev/null 2>&1 && export BYOBU_SED="gsed" || export BYOBU_SED="sed"
eval $BYOBU_TEST greadlink >/dev/null 2>&1 && export BYOBU_READLINK="greadlink" || export BYOBU_READLINK="readlink"
eval $BYOBU_TEST sensible-pager >/dev/null 2>&1 && export BYOBU_PAGER="sensible-pager" || export BYOBU_PAGER="less"
eval $BYOBU_TEST sensible-editor >/dev/null 2>&1 && export BYOBU_EDITOR="sensible-editor" || export BYOBU_EDITOR="$EDITOR"
eval $BYOBU_TEST "$BYOBU_EDITOR" >/dev/null 2>&1 || export BYOBU_EDITOR="vim"


# Cache the OS name to avoid repeated uname forks in status scripts.
# uname is POSIX-mandated and present on all supported platforms.
[ -z "$BYOBU_OSTYPE" ] && export BYOBU_OSTYPE=$(uname -s 2>/dev/null)

# Check sed's follow-symlinks feature
$BYOBU_SED --follow-symlinks "s///" /dev/null 2>/dev/null && export BYOBU_SED_INLINE="$BYOBU_SED -i --follow-symlinks" || export BYOBU_SED_INLINE="$BYOBU_SED -i"

# Determine if we have ulimit support
eval $BYOBU_TEST ulimit >/dev/null 2>&1 && export BYOBU_ULIMIT="ulimit" || export BYOBU_ULIMIT="false"

# Find a suitable python interpreter, if undefined.
# Cache the result in $BYOBU_CONFIG_DIR so each status-bar subprocess
# (run fresh by tmux every few seconds) does not re-import snack on NFS
# or slow filesystems.  LP: #2076905
if [ -z "$BYOBU_PYTHON" ]; then
	_byobu_python_cache="${BYOBU_CONFIG_DIR:-$HOME/.byobu}/.python_cache"
	if [ -f "$_byobu_python_cache" ]; then
		IFS= read -r BYOBU_PYTHON < "$_byobu_python_cache" 2>/dev/null || true
		export BYOBU_PYTHON
	else
		if python3 -c "import snack" >/dev/null 2>&1; then
			export BYOBU_PYTHON="python3"
		elif python2 -c "import snack" >/dev/null 2>&1; then
			export BYOBU_PYTHON="python2"
		elif python -c "import snack" >/dev/null 2>&1; then
			export BYOBU_PYTHON="python"
		fi
		printf "%s\n" "$BYOBU_PYTHON" > "$_byobu_python_cache" 2>/dev/null || true
	fi
	unset _byobu_python_cache
fi

export BYOBU_WINDOW_NAME="-"
export BYOBU_DATE="%Y-%m-%d "
export BYOBU_TIME="%H:%M:%S"
byobu-7.15/usr/lib/byobu/include/cycle-status000077500000000000000000000025711522352767600213020ustar00rootroot00000000000000#!/bin/sh
#
#    cycle-status: cycle the status bar through multiple configurations
#
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .


# Find line number of the enabled tmux_right
current=$(grep -n "^tmux_right=" "$BYOBU_CONFIG_DIR/status" | awk -F: '{print $1}' | tail -n1)

# Find next line number to enable
all=$(grep -n "tmux_right=" "$BYOBU_CONFIG_DIR/status" | awk -F: '{print $1}')
next=
for i in $all $all; do
	if [ "$next" = "flagged" ]; then
		next="$i"
		break
	elif [ "$i" = "$current" ]; then
		next="flagged"
	fi
done

# Disable all
$BYOBU_SED_INLINE -e "s/^tmux_right=/#tmux_right=/" "$BYOBU_CONFIG_DIR/status"

# Enable the next one
$BYOBU_SED_INLINE -e "${next}s/^#tmux_right=/tmux_right=/" "$BYOBU_CONFIG_DIR/status"
byobu-7.15/usr/lib/byobu/include/dirs.in000077500000000000000000000047351522352767600202340ustar00rootroot00000000000000#!/bin/sh
#
#    dirs: some dirs needed by all library status scripts
#
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

PKG="byobu"

# Some users build and install byobu themselves, rather than from a distro
[ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc"
[ -n "$BYOBU_PREFIX" ] || BYOBU_PREFIX="@prefix@"

# Create and export the user configuration directory
# BYOBU_CONFIG_DIR if set, ~/.byobu if it exists, otherwise XDG_CONFIG_HOME/byobu
if [ -z "$BYOBU_CONFIG_DIR" ]; then
	if [ -d "$HOME/.$PKG" ]; then
		export BYOBU_CONFIG_DIR="$HOME/.$PKG"
	else
		_xdg="${XDG_CONFIG_HOME:-"$HOME"/.config}"
		# Spec says XDG_CONFIG_HOME must not be world-readable
		[ -d "$_xdg" ] || mkdir -p -m 700 "$_xdg"
		export BYOBU_CONFIG_DIR="$_xdg/$PKG"
		unset _xdg
	fi
fi
[ -d "$BYOBU_CONFIG_DIR/bin" ] || mkdir -p "$BYOBU_CONFIG_DIR/bin"

# Grab the global, then local socket directory
[ -r "/etc/$PKG/socketdir" ] && . "/etc/$PKG/socketdir"
[ -r "$BYOBU_CONFIG_DIR/socketdir" ] && . "$BYOBU_CONFIG_DIR/socketdir"

# Create and export the runtime cache directory
if [ -d /dev/shm ] && [ -w /dev/shm ]; then
	# Use shm for performance, if possible
	for i in /dev/shm/$PKG-$USER-*; do
		if [ -d "$i" ] && [ -O "$i" ]; then
			export BYOBU_RUN_DIR="$i"
			break
		fi
	done
	# Still empty, make a new one
	if [ ! -d "$BYOBU_RUN_DIR" ] || [ ! -O "$BYOBU_RUN_DIR" ]; then
		export BYOBU_RUN_DIR=$(mktemp -d /dev/shm/$PKG-$USER-XXXXXXXX)
	fi
fi
if [ ! -d "$BYOBU_RUN_DIR" ] || [ ! -O "$BYOBU_RUN_DIR" ] || [ ! -w "$BYOBU_RUN_DIR" ]; then
	# For distros that don't have a /dev/shm, use local disk
	if [ -n "$XDG_CACHE_HOME" ]; then
		# Use XDG, as some users insist on such nonsense :-)
		export BYOBU_RUN_DIR="$XDG_CACHE_HOME/$PKG"
	else
		# But if not, we'll use a cache directory
		export BYOBU_RUN_DIR="$HOME/.cache/$PKG"
	fi
	mkdir -p "$BYOBU_RUN_DIR" 2>/dev/null || true
fi
byobu-7.15/usr/lib/byobu/include/icons000077500000000000000000000037371522352767600200020ustar00rootroot00000000000000#!/bin/sh
#
#    icons: some icon characters for status scripts
#
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

PKG="byobu"

# UTF-8 support in the hardstatus is coming one day in Screen
if [ "$BYOBU_BACKEND" = "tmux" ] && [ "$BYOBU_CHARMAP" = "UTF-8" ]; then
	#ICON_C="℃"
	#ICON_F="℉"
	ICON_C="C"
	ICON_F="F"
	ICON_RD="◂"
	ICON_WR="▸"
	ICON_MAIL="⍌"
	ICON_UP="▴"
	ICON_DN="▾"
	ICON_TRASH="♸"
	ICON_WIFI=
	ICON_REBOOT="${ICON_REBOOT:-⟳}"
	ICON_UPDATES="${ICON_UPDATES:-!}"
	ICON_UPGRADE="${ICON_UPGRADE:-⚠}"
	ICON_SECURITY="${ICON_SECURITY:-‼}"
	#ICON_KB="㎅"
	#ICON_MB="㎆"
	#ICON_GB="㎇"
	ICON_KB="K"
	ICON_MB="M"
	ICON_GB="G"
	ICON_TB="T"
	#ICON_KHz="㎑"
	#ICON_MHz="㎒"
	#ICON_GHz="㎓"
	ICON_KHz="KHz"
	ICON_MHz="MHz"
	ICON_GHz="GHz"
	#ICON_MBPS="㏔㎰"
	ICON_MBPS="Mb"
	ICON_SESSION="〣"
	ICON_LIVEPATCHED="🗹 "
else
	# Only use 0-127 ANSI: http://ascii-table.com/ascii.php
	ICON_C="C"
	ICON_F="F"
	ICON_RD="<"
	ICON_WR=">"
	ICON_MAIL="[M]"
	ICON_UP="^"
	ICON_DN="v"
	ICON_TRASH="T"
	ICON_WIFI=
	ICON_REBOOT="${ICON_REBOOT:-(R)}"
	ICON_UPDATES="${ICON_UPDATES:-!}"
	ICON_UPGRADE="${ICON_UPGRADE:-/!\\\\}"
	ICON_SECURITY="${ICON_SECURITY:-!!}"
	ICON_KB="KB"
	ICON_MB="MB"
	ICON_GB="GB"
	ICON_TB="TB"
	ICON_KHz="kHz"
	ICON_MHz="MHz"
	ICON_GHz="GHz"
	ICON_MBPS="Mbps"
	ICON_SESSION="|"
	ICON_LIVEPATCHED="[/]"
fi
byobu-7.15/usr/lib/byobu/include/mondrian000077500000000000000000000107641522352767600204740ustar00rootroot00000000000000#!/bin/bash
# N.B.: Use bash for $RANDOM
#
#    mondrian: randomly generate some Modrian art in tmux
#
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

trap "tput reset" EXIT HUP INT QUIT TERM KILL ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM

# Special mode, argv[1]="color", paint the screen
if [ "$1" = "color" ] && [ -n "$2" ]; then
	i=0
	out=
	sleep 0.2
	count=$(stty size | awk '{print $1*$2}')
	perl -e "print color 'reset'; printf \"\x1b[48;5;${2}m%${count}s\", \" \";";
	head -n1
	tmux kill-window -t mondrian
	exit 0
fi

get_random_direction() {
	if [ $((RANDOM % 2)) -eq 0 ]; then
		echo "-v"
	else
		echo "-h"
	fi
}

get_random_numbers() {
	local max="$1" R=0 B=0 Y=0
	R=$((RANDOM % max + 1))
	B=$((RANDOM % max + 1))
	Y=$((RANDOM % max + 1))
	while [ "$B" = "$R" ] || [ "$B" = "$Y" ]; do
		B=$((RANDOM % max + 1))
	done
	while [ "$Y" = "$R" ] || [ "$Y" = "$B" ]; do
		Y=$((RANDOM % max + 1))
	done
	_RET="$R $B $Y"
}

red_color=196
yellow_color=226
blue_color=57
white_color=231

tmux kill-window -t mondrian
tmux new-window -n mondrian "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	set-option -g pane-active-border-style bg=colour231 \; \
	set-option -g pane-active-border-style fg=black \; \
	set-option -g pane-border-style bg=colour231 \; \
	set-option -g pane-border-style fg=black \; \
	split-window $(get_random_direction) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 2)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 3)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 4)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $red_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 5)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 6)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $yellow_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 7)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 8)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $blue_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 9)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 9)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 10)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 11)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 12)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 13)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 14)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 15)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 16)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 17)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 18)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 19)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \
	split-window $(get_random_direction) -t $((RANDOM % 20)) "$BYOBU_PREFIX/lib/byobu/include/mondrian color $white_color" \; \

exit 0
byobu-7.15/usr/lib/byobu/include/notify_osd000077500000000000000000000033661522352767600210420ustar00rootroot00000000000000#!/usr/bin/perl
#
#    notify_osd: perform some string manipulation on notify-osd messages
#                 and then send to the screen message window
#    Copyright (C) 2010 Canonical Ltd.
#
#    Authors: Dustin Kirkland 
#             with help from Mathias Gug 
#
#    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, version 3 of the License.
#
#    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, see .

$/ = "\n\n";
$PKG = "byobu";
$sleep = 5;
while () {
	# Ensure that the notify_osd indicator is enabled
	my $skip = 0;
	open(F, "<$ENV{BYOBU_CONFIG_DIR}/status");
	foreach my $i () {
		if ($i =~ /notify_osd=0/) {
			$skip = 1;
		}
	}
	close(F);
	if ($skip == 1) {
		next;
	}
	$msg = $_;
	$msg =~ s/\[[^,]*, //;		# strip the leading "[timestamp, "
	$msg =~ s/\] /: /;		# replace the " ] " following the indicator name, with ":"
	$msg =~ s/\s+/ /g;		# collapse multi-whitespace into one
	$msg =~ s/\s+$//g;		# strip trailing whitespace
	$msg =~ s/^\s+//g;		# strip leading whitespace
	system("/usr/bin/screen", "-X", "-S", "$ARGV[0]", "at", "*", "msgwait", "$sleep");
	system("/usr/bin/screen", "-X", "-S", "$ARGV[0]", "at", "*", "echo", "[$msg]");
	sleep($sleep);
	system("/usr/bin/screen", "-X", "-S", "$ARGV[0]", "at", "*", "msgwait", "0");
}
byobu-7.15/usr/lib/byobu/include/select-session.py000077500000000000000000000152221522352767600222460ustar00rootroot00000000000000#!/usr/bin/env python3
#
#    select-session.py
#    Copyright (C) 2010 Canonical Ltd.
#    Copyright (C) 2012-2014 Dustin Kirkland 
#
#    Authors: Dustin Kirkland 
#             Ryan C. Thompson 
#
#    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, version 3 of the License.
#
#    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, see .


import os
import re
import sys
import subprocess
try:
	# For Python3, try and import input from builtins
	from builtins import input
except Exception:
	# But fall back to using the default input
	True


PKG = "byobu"
SHELL = os.getenv("SHELL", "/bin/bash")
HOME = os.getenv("HOME")
BYOBU_CONFIG_DIR = os.getenv("BYOBU_CONFIG_DIR", HOME + "/.byobu")
BYOBU_BACKEND = os.getenv("BYOBU_BACKEND", "tmux")
choice = -1
sessions = []
text = []
reuse_sessions = os.path.exists("%s/.reuse-session" % (BYOBU_CONFIG_DIR))

BYOBU_UPDATE_ENVVARS = ["DISPLAY", "DBUS_SESSION_BUS_ADDRESS", "SESSION_MANAGER", "GPG_AGENT_INFO", "XDG_SESSION_COOKIE", "XDG_SESSION_PATH", "GNOME_KEYRING_CONTROL", "GNOME_KEYRING_PID", "GPG_AGENT_INFO", "SSH_ASKPASS", "SSH_AUTH_SOCK", "SSH_AGENT_PID", "WINDOWID", "UPSTART_JOB", "UPSTART_EVENTS", "UPSTART_SESSION", "UPSTART_INSTANCE"]


def get_sessions():
	sessions = []
	i = 0
	output = False
	if BYOBU_BACKEND == "screen":
		try:
			output = subprocess.Popen(["screen", "-ls"], stdout=subprocess.PIPE).communicate()[0]
		except subprocess.CalledProcessError as cpe:
			# screen -ls seems to always return 1
			if cpe.returncode != 1:
				raise
			else:
				output = cpe.output
		if sys.stdout.encoding is None:
			output = output.decode("UTF-8")
		else:
			output = output.decode(sys.stdout.encoding)
		if output:
			for s in output.splitlines():
				s = re.sub(r'\s+', ' ', s)
				# Ignore hidden sessions (named sessions that start with a "." or a "_")
				if s and s != " " and (s.find(" ") == 0 and len(s) > 1 and s.count("..") == 0 and s.count("._") == 0):
					text.append("screen: %s" % s.strip())
					items = s.split(" ")
					sessions.append("screen____%s" % items[1])
					i += 1
	if BYOBU_BACKEND == "tmux":
		output = subprocess.Popen(["tmux", "list-sessions"], stdout=subprocess.PIPE).communicate()[0]
		if sys.stdout.encoding is None:
			output = output.decode("UTF-8")
		else:
			output = output.decode(sys.stdout.encoding)
		if output:
			for s in output.splitlines():
				# Ignore hidden sessions (named sessions that start with a "_")
				if s and not s.startswith("_"):
					text.append("tmux: %s" % s.strip())
					sessions.append("tmux____%s" % s.split(":")[0])
					i += 1
	return sessions


def cull_zombies(session_name):
	# When using tmux session groups, closing a client will leave
	# unattached "zombie" sessions that will never be reattached.
	# Search for and kill any unattached hidden sessions in the same group
	if BYOBU_BACKEND == "tmux":
		output = subprocess.Popen(["tmux", "list-sessions"], stdout=subprocess.PIPE).communicate()[0]
		if sys.stdout.encoding is None:
			output = output.decode("UTF-8")
		else:
			output = output.decode(sys.stdout.encoding)
		if not output:
			return

		# Find the master session to extract the group name. We use
		# the group number to be extra sure the right session is getting
		# killed. We don't want to accidentally kill the wrong one
		pattern = "^%s:.+\\((group [^\\)]+)\\).*$" % session_name
		master = re.search(pattern, output, re.MULTILINE)
		if not master:
			return

		# Kill all the matching hidden & unattached sessions
		pattern = "^_%s-\\d+:.+\\(%s\\)$" % (session_name, master.group(1))
		for s in re.findall(pattern, output, re.MULTILINE):
			subprocess.Popen(["tmux", "kill-session", "-t", s.split(":")[0]])


def update_environment(session):
	backend, session_name = session.split("____", 2)
	for var in BYOBU_UPDATE_ENVVARS:
		value = os.getenv(var)
		if value:
			if backend == "tmux":
				cmd = ["tmux", "setenv", "-t", session_name, var, value]
			else:
				cmd = ["screen", "-S", session_name, "-X", "setenv", var, value]
			subprocess.call(cmd, stdout=open(os.devnull, "w"))


def attach_session(session):
	update_environment(session)
	backend, session_name = session.split("____", 2)
	cull_zombies(session_name)
	# must use the binary, not the wrapper!
	if backend == "tmux":
		if reuse_sessions:
			os.execvp("tmux", ["tmux", "-u", "attach", "-t", session_name])
		else:
			os.execvp("tmux", ["tmux", "-u", "new-session", "-t", session_name, ";", "set-option", "destroy-unattached"])
	else:
		os.execvp("screen", ["screen", "-AOxRR", session_name])


sessions = get_sessions()

show_shell = os.path.exists("%s/.always-select" % (BYOBU_CONFIG_DIR))
if len(sessions) > 1 or show_shell:
	sessions.append("NEW")
	text.append("Create a new Byobu session (%s)" % BYOBU_BACKEND)
	sessions.append("SHELL")
	text.append("Run a shell without Byobu (%s)" % SHELL)

if len(sessions) > 1:
	sys.stdout.write("\nByobu sessions...\n\n")
	tries = 0
	while tries < 3:
		i = 1
		for s in text:
			sys.stdout.write("  %d. %s\n" % (i, s))
			i += 1
		try:
			try:
				user_input = input("\nChoose 1-%d [1]: " % (i - 1))
			except Exception:
				user_input = ""
			if not user_input or user_input == "":
				choice = 1
				break
			try:
				choice = int(user_input)
			except Exception:
				choice = int(eval(user_input))
			if choice >= 1 and choice < i:
				break
			else:
				tries += 1
				choice = -1
				sys.stderr.write("\nERROR: Invalid input\n")
		except KeyboardInterrupt:
			sys.stdout.write("\n")
			sys.exit(0)
		except Exception:
			if choice == "" or choice == -1:
				choice = 1
				break
			tries += 1
			choice = -1
			sys.stderr.write("\nERROR: Invalid input\n")
elif len(sessions) == 1:
	# Auto-select the only session
	choice = 1

if choice >= 1:
	if sessions[choice - 1] == "NEW":
		# Create a new session
		if BYOBU_BACKEND == "tmux":
			os.execvp("byobu", ["byobu", "new-session", SHELL])
		else:
			os.execvp("byobu", ["byobu", SHELL])
	elif sessions[choice - 1] == "SHELL":
		os.execvp(SHELL, [SHELL])
	else:
		# Attach to the chosen session; must use the binary, not the wrapper!
		attach_session(sessions[choice - 1])

# No valid selection, default to the youngest session, create if necessary
if BYOBU_BACKEND == "tmux":
	os.execvp("tmux", ["tmux"])
else:
	os.execvp("screen", ["screen", "-AOxRR"])
byobu-7.15/usr/lib/byobu/include/shutil000077500000000000000000000222361522352767600201720ustar00rootroot00000000000000#!/bin/bash
#
#    shutil: some shared utilities used by all status scripts
#    Note: Uses decimal sleep (0.02) which requires bash
#
#    Copyright (C) 2011-2023 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#             Scott Moser 
#
#    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, version 3 of the License.
#
#    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, see .

# Define colors
color_screen() {
	ESC="\005"
	case "$1" in
		"") return 0 ;;
		-)   printf "$ESC{-}" ;;
		--)   printf "$ESC{-} " ;;
		esc)    printf "$ESC" ;;
		bold1)  printf "$ESC{=b }" || printf "$ESC{= }" ;;
		bold2)  printf "$ESC{+b }" || printf "$ESC{= }" ;;
		none)   printf "$ESC{= }" ;;
		invert) printf "$ESC{=r }" ;;
		*)
			local attr fg bg
			case $# in
				2)
					attr= ; fg=$1 ; bg=$2
				;;
				3)
					attr=$1 ; fg=$2 ; bg=$3
				;;
			esac
			if [ "$MONOCHROME" = "1" ]; then
				fg=
				bg=
			fi
			printf "$ESC{=$attr $fg$bg}"
		;;
	esac
}

color_map() {
	case "$1" in
		"k") _RET="black" ;;
		"r") _RET="red" ;;
		"g") _RET="green" ;;
		"y") _RET="yellow" ;;
		"b") _RET="blue" ;;
		"m") _RET="magenta" ;;
		"c") _RET="cyan" ;;
		"w") _RET="white" ;;
		"d") _RET="black" ;;
		"K") _RET="brightblack" ;;
		"R") _RET="brightred" ;;
		"G") _RET="brightgreen" ;;
		"Y") _RET="brightyellow" ;;
		"B") _RET="brightblue" ;;
		"M") _RET="brightmagenta" ;;
		"C") _RET="brightcyan" ;;
		"W") _RET="brightwhite" ;;
		*) _RET="$1" ;;
	esac
}

attr_map() {
	case "$1" in
		"d") _RET=,dim ;;
		"u") _RET=,underscore ;;
		"b") _RET=,bold ;;
		"r") _RET=,reverse ;;
		"s") _RET=,standout ;;
		"B") _RET=,blinking ;;
		"h") _RET=,hidden ;;
		"i") _RET=,italics ;;
		*) _RET= ;;
	esac
}

color_tmux() {
	local back fore attr
	case "$1" in
		"") return 0 ;;
		-)      printf "#[default]#[fg=$BYOBU_LIGHT,bg=$BYOBU_DARK]" ;;
		--)     printf "#[default]#[fg=$BYOBU_LIGHT]#[bg=$BYOBU_DARK] " ;;
		esc)    printf "" ;;
		bold*)  printf "#[default]#[fg=bold]" ;;
		none)   printf "#[default]#[fg=$BYOBU_LIGHT,bg=$BYOBU_DARK]" ;;
		invert) printf "#[default]#[reverse]" ;;
		*)
			if [ "$#" = "2" ]; then
				color_map "$1"; back="$_RET"
				color_map "$2"; fore="$_RET"
			else
				attr_map "$1";  attr="$_RET"
				color_map "$2"; back="$_RET"
				color_map "$3"; fore="$_RET"
			fi
			[ "$MONOCHROME" = "1" ] && printf "#[default]" || printf "#[default]#[fg=$fore$attr,bg=$back]"
		;;
	esac
}

color() {
	case "$BYOBU_BACKEND" in
		tmux)
			color_tmux "$@"
		;;
		screen)
			color_screen "$@"
		;;
	esac
}

# uncommented_lines(char=#)
# does the standard input have lines that do not start with 'char'?
uncommented_lines() {
	local line chr="${1:-#}"
	while read line; do
		[ "${line#${chr}}" = "${line}" ] && return 0;
	done
	return 1
}

# newest(file,file,file..)
# return the newest file in the list
newest() {
	local c="$1" i
	for i in "$@"; do [ "$i" -nt "$c" ] && c="$i"; done
	[ -e "$c" ] && _RET="$c"
}

error() {
	printf "%s\n" "ERROR: " "$@" 1>&2
}

fail() {
	[ $# -eq 0 ] || error "$@"; exit 1;
}

find_script() {
	# Allow for local status scripts
	if [ -x "$BYOBU_CONFIG_DIR/bin/$1" ]; then
		_RET="$BYOBU_CONFIG_DIR/bin/$1"
	elif [ -x "$BYOBU_PREFIX/lib/$PKG/$1" ]; then
		_RET="$BYOBU_PREFIX/lib/$PKG/$1"
	elif [ -x "$BYOBU_PREFIX/libexec/$PKG/$1" ]; then
		_RET="$BYOBU_PREFIX/libexec/$PKG/$1"
	else
		_RET="/dev/null"
	fi
}

# divide 2 integers and return a floating point number
# third argument indicates how many digits after the decimal
fpdiv() {
	local a=$1 b=$2 pres=${3:-3}
	local i=0 mp="10" whole="" part="" chunk="" n=0
	while i=$(($i+1)) && [ $i -le $pres ]; do
		mp="${mp}0"
		chunk="${chunk}?"
	done

	n=$(((${mp}*${a})/${b}))

	# round up if necessary
	[ $((($n-5)/10)) = $(($n/10)) ] && n=$(($n+5))

	# drop the last digit, which was only there for rounding
	n=${n%?}
	whole=${n%${chunk}}
	part=${n#${whole}}
	_RET=${whole:-0}${part:+.${part}}
	return
}

# rtrim(string,chars)
rtrim() {
	local tab=' ' cr="
"
	local cur="${1}" set="[${2:- ${tab}${cr}}]" n=""
	while n=${cur%${set}} && [ "$n" != "$cur" ]; do cur=${n}; done
	_RET=${cur}
}

readfile() {
	local c="" r="" cr="
"
	OIFS="$IFS"; IFS="";
	while read c; do
		r="$r${cr}$c"
	done
	IFS=$OIFS
	_RET=${r}
	return 0
}

metadata_available() {
	# This is really ugly.  We need a reliable, fast way of determining
	# if a metadata service is available, that does NOT slow down non-ec2
	# machines.
	local x=0 cache="$BYOBU_CONFIG_DIR/.metadata_available"
	# First, check the cache
	if [ -s "$cache" ]; then
		# Metadata is non-empty, so we have metadata available
		x=1
	else
		# Must seed the cache
		if [ -e /etc/ec2_version ] || [ -e /usr/sbin/update-grub-legacy-ec2 ]; then
			# This *looks* like a machine with metadata, so background a potentially slow check
			timeout 1 wget -q -O- --tries=1 http://169.254.169.254 "$cache" 2>/dev/null &
			# Brief sleep for cold-start metadata detection (requires bash)
			sleep 0.02
			[ -s "$cache" ] && x=1
		fi
	fi
	[ "$x" = "1" ]
}

status_freq() {
# Define status frequencies
#   Use prime number intervals, to decrease collisions, which
#   yields some less expensive status updates.
#   ~86000 ~1 day
#   ~600   ~10 minutes
#   ~180   ~3 minutes
#   ~60    ~1 minute
	case "$1" in
		apport)		_RET=67 ;;
		arch)		_RET=9999991 ;;
		battery)	_RET=61 ;;
		color)		_RET=9999991 ;;
		cpu_count)	_RET=5 ;;
		cpu_freq)	_RET=2 ;;
		cpu_temp)	_RET=19 ;;
		custom)		_RET=5 ;;
		date)		_RET=9999991 ;;
		disk)		_RET=13 ;;
		disk_io)	_RET=3 ;;
		distro)		_RET=9999991 ;;
		entropy)	_RET=5 ;;
		fan_speed)	_RET=23 ;;
		hostname)	_RET=607 ;;
		ip_address)	_RET=127 ;;
		load_average)	_RET=2 ;;
		logo)		_RET=9999991 ;;
		mail)		_RET=5 ;;
		memory)		_RET=13 ;;
		menu)		_RET=9999991 ;;
		network)	_RET=3 ;;
		notify_osd)	_RET=9999991 ;;
		packages)	_RET=211 ;;
		processes)	_RET=7 ;;
		raid)		_RET=59 ;;
		reboot_required) _RET=5 ;;
		release)	_RET=599 ;;
		services)	_RET=53 ;;
		session)	_RET=9999991 ;;
		swap)		_RET=19 ;;
		time)		_RET=9999991 ;;
		time_binary)	_RET=23 ;;
		time_utc)	_RET=11 ;;
		trash)		_RET=9999991 ;;
		updates_available) _RET=7 ;;
		uptime)		_RET=29 ;;
		users)		_RET=11 ;;
		whoami)		_RET=86029 ;;
		wifi_quality)	_RET=17 ;;
		*)		_RET=9999991 ;;
	esac
}

get_now() {
	if [ -r /proc/uptime ]; then
		# return the integer part of the first item in /proc/uptime
		local s c
		read s c < /proc/uptime
		_RET=${s%.*}
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# Cache kern.boottime since it is constant
		if [ -z "$_BYOBU_BOOTTIME" ]; then
			_BYOBU_BOOTTIME=$(sysctl -n kern.boottime 2>/dev/null)
		fi
		if [ -n "$_BYOBU_BOOTTIME" ]; then
			_RET=$(( $(date +%s) - _BYOBU_BOOTTIME ))
		else
			_RET=$(date +%s)
		fi
	else
		_RET=$(date +%s);
	fi
}

get_network_interface() {
        if [ -n "$MONITORED_NETWORK" ]; then
		# Manual override
                _RET="$MONITORED_NETWORK"
        elif [ -e /proc/net/route ]; then
		# Linux systems, read route and interface from procfs
		local Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
		while read Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT; do
			[ "$Mask" = "00000000" ] && break
		done < /proc/net/route
		_RET="$Iface"
	elif eval $BYOBU_TEST route >/dev/null 2>&1; then
		# BSD/macOS: use route to find the default interface
		_RET=$(route -n get default 2>/dev/null | awk '/interface:/ { print $2 }')
	elif [ -x "/sbin/route" ]; then
		_RET=$(/sbin/route -n get default 2>/dev/null | awk '/interface:/ { print $2 }')
	fi
}

get_distro() {
	local distro="${DISTRO}"
	if [ -n "$DISTRO" ]; then
		# user defined
		true
	elif [ -r "/etc/os-release" ]; then
		distro=$(. /etc/os-release && echo "$NAME")
		case "$distro" in
			Debian*)
				[ -r /etc/lsb-release ] && distro=$(. /etc/lsb-release && [ -n "$GOOGLE_ID" ] && echo "gLinux" || echo "Debian")
			;;
			*)
				# assume first field is what we want
				distro="${distro%% *}";
			;;
		esac
	elif [ -r "/etc/issue" ]; then
		# lsb_release is *really* slow;  try to use /etc/issue first
		local issue
		IFS="" read issue < /etc/issue
		case "$issue" in
			Ubuntu*)
				distro="Ubuntu";
			;;
			Debian*)
				distro="Debian"
			;;
			Red\ Hat\ Enterprise*)
				distro="RHEL"
			;;
			*)
				# assume first field is what we want
				distro="${issue%% *}";
			;;
		esac
	elif eval $BYOBU_TEST lsb_release >/dev/null 2>&1; then
		# If lsb_release is available, use it
		local r=$(lsb_release -s -d)
		case "$r" in
			Ubuntu*)
				# Use the -d if an Ubuntu LTS
				distro="Ubuntu"
			;;
			*)
				# But for other distros the description
				# is too long, so build from -i and -r
				distro=$(lsb_release -s -i)
			;;
		esac
	elif eval $BYOBU_TEST sw_vers >/dev/null 2>&1; then
		distro="$(sw_vers -productName)"
	elif eval $BYOBU_TEST uname >/dev/null 2>&1; then
		distro="$BYOBU_OSTYPE"
	else
		distro="Byobu"
	fi
	_RET="$distro"
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/include/tmux-detach-all-but-current-client000077500000000000000000000030731522352767600253750ustar00rootroot00000000000000#!/bin/sh
#
#    tmux-detach-all-but-current-client
#    Copyright (C) 2013-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

a1=
a2=
tty1=
tty2=
# List all clients, ordered by most recent activity descending
for c in $(tmux list-clients -F "#{client_activity}___#{client_tty}" | sort -n -r); do
	if [ -z "$a1" ]; then
		a1=${c%%___*}
		tty1=${c##*___}
	elif [ -z "$a2" ]; then
		a2=${c%%___*}
		tty2=${c##*___}
	fi
	if [ -n "$a1" ] && [ -n "$a2" ]; then
		if [ "$a1" = "$a2" ]; then
			# Activity timestamps match in top 2 attached clients
			# Let's not detach anyone here!
			tmux display-message "Multiple active attached clients detected, refusing to detach" >/dev/null 2>&1
		elif [ -n "$tty1" ]; then
			# Detach all but the current client, iterating across each
			# Tempting to use detach-client -a -t here, but there's a bug
			# in there, keeping that from working properly
			tmux detach-client -t "$tty2" >/dev/null 2>&1
			a2=
		fi
	fi
done
byobu-7.15/usr/lib/byobu/include/tmux-send-command-to-all-panes000077500000000000000000000025441522352767600245140ustar00rootroot00000000000000#!/bin/sh
#
#    tmux-send-command-to-all-panes
#    Copyright (C) 2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

# Read command from the tmux paste buffer (set by the S-F9 keybinding via
# set-buffer "%%").  This avoids shell-quoting the user's text entirely,
# so single quotes, dollar signs, and semicolons all pass through correctly.
# Fall back to $@ for callers that still pass the command as arguments.
if [ $# -gt 0 ]; then
	_cmd="$*"
else
	_cmd=$(tmux show-buffer 2>/dev/null) || true
fi
[ -z "$_cmd" ] && exit 0
w=$(tmux list-windows | grep "\*" | awk -F: '{print $1}')
for p in $(tmux list-panes | $BYOBU_SED -e "s/:.*//"); do
	tmux send-keys -l -t $w.$p "$_cmd" || true
	tmux send-keys -t $w.$p Enter || true
done
unset _cmd
byobu-7.15/usr/lib/byobu/include/tmux-send-command-to-all-windows000077500000000000000000000017621522352767600251010ustar00rootroot00000000000000#!/bin/sh
#
#    tmux-send-command-to-all-windows
#    Copyright (C) 2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

if [ $# -gt 0 ]; then
	_cmd="$*"
else
	_cmd=$(tmux show-buffer 2>/dev/null) || true
fi
[ -z "$_cmd" ] && exit 0
for w in $(tmux list-windows | $BYOBU_SED -e "s/:.*//"); do
	tmux send-keys -l -t :$w "$_cmd"
	tmux send-keys -t :$w Enter
done
unset _cmd
byobu-7.15/usr/lib/byobu/include/toggle-utf8.in000077500000000000000000000033571522352767600214370ustar00rootroot00000000000000#!/bin/sh -e
#
#    toggle-utf8
#    Copyright (C) 2013-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

PKG="byobu"
[ -r "$HOME/.byoburc" ] && . "$HOME/.byoburc"
[ -z "${BYOBU_PREFIX}" ] && export BYOBU_PREFIX="@prefix@" || export BYOBU_PREFIX
. "${BYOBU_PREFIX}/lib/${PKG}/include/common"
[ -r "$BYOBU_CONFIG_DIR/statusrc" ] && . "$BYOBU_CONFIG_DIR/statusrc"

if [ "$BYOBU_CHARMAP" = "UTF-8" ]; then
	if grep -qs "^BYOBU_CHARMAP=" $BYOBU_CONFIG_DIR/statusrc 2>/dev/null; then
		$BYOBU_SED_INLINE -e "s/^BYOBU_CHARMAP=.*/BYOBU_CHARMAP=x/" $BYOBU_CONFIG_DIR/statusrc
	else
		echo "BYOBU_CHARMAP=x" >> $BYOBU_CONFIG_DIR/statusrc
	fi
	export BYOBU_CHARMAP=x
else
	if grep -qs "^BYOBU_CHARMAP=" $BYOBU_CONFIG_DIR/statusrc 2>/dev/null; then
		$BYOBU_SED_INLINE -e "s/^BYOBU_CHARMAP=.*/BYOBU_CHARMAP=UTF-8/" $BYOBU_CONFIG_DIR/statusrc
	else
		echo "BYOBU_CHARMAP=UTF-8" >> $BYOBU_CONFIG_DIR/statusrc
	fi
	export BYOBU_CHARMAP=UTF-8
fi
if [ -n "$TMUX" ]; then
	RC_FILE=$(echo "$SHELL" | $BYOBU_SED "s:.*/::")
	tmux send-keys " export BYOBU_CHARMAP=$BYOBU_CHARMAP ; . ~/.${RC_FILE}rc" \; send-keys Enter
fi

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/ip_address000077500000000000000000000105441522352767600173530ustar00rootroot00000000000000#!/bin/bash -e
#
#    ip_address: report a host's ip address
#    Note: Uses decimal sleep (0.02, 0.1) which requires bash
#
#    Copyright (C) 2008-2011 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__ip_address_detail() {
	if [ -x /sbin/ip ]; then
		/sbin/ip -4 addr list
		/sbin/ip -6 addr list
	fi
}

__ip_address() {
	local interface ipaddr cache="$BYOBU_RUN_DIR/cache.$BYOBU_BACKEND/ip_address"
	# Allow interface overrides in $BYOBU_CONFIG_DIR/statusrc
	if [ -n "$MONITORED_NETWORK" ]; then
		interface="$MONITORED_NETWORK"
	else
		case "$IPV6" in
			1|true|yes)
				if [ -r /proc/net/ipv6_route ]; then
					interface=$(awk '$10 != "lo" { iface=$10 ; }; END { print iface; }' /proc/net/ipv6_route)
				else
					get_network_interface; interface="$_RET"
				fi
			;;
			*) get_network_interface; interface="$_RET";;
		esac
	fi
	case "$IPV6" in
		1|true|yes)
			if [ "$IP_EXTERNAL" = "1" ]; then
				# Background an update
				timeout 1 wget -q -O- http://v6.ipv6-test.com/api/myip.php "$cache" 2>/dev/null &
				# Brief sleep for cold-start display optimization (requires bash)
				sleep 0.02
			else
				# Background an update
				if [ -x /sbin/ip ]; then
					LC_ALL=C /sbin/ip -6 addr list dev "$interface" scope global "$cache" 2>/dev/null &
				elif eval $BYOBU_TEST ifconfig >/dev/null 2>&1; then
					LC_ALL=c ifconfig "$interface" | grep "inet6 " | awk '{print $2}' | sed -e "s/%.*//" >"$cache" 2>/dev/null &

				fi
			fi
			[ -s "$cache" ] && read ipaddr < "$cache"
			# Print 'None' if we have no global address
			[ -z "$ipaddr" ] && ipaddr="None"
			ipaddr=${ipaddr#* inet6 }
			ipaddr=${ipaddr%%/*}
		;;
		*)
			if [ "$IP_EXTERNAL" = "1" ]; then
				if [ -n "$EXTERNAL_IP_SOURCE" ]; then
					# User-specified URL (e.g. https://api.ipify.org). LP: #1869483
					timeout 1 wget -q -O- "$EXTERNAL_IP_SOURCE" "$cache" 2>/dev/null &
					sleep 0.02
				elif command -v dig >/dev/null 2>&1; then
					# Try dig with OpenDNS first (faster), fall back to wget
					timeout 1 dig +short myip.opendns.com @resolver1.opendns.com /dev/null | tr -d '\n' >"$cache" &
					# Brief sleep for cold-start display optimization (requires bash)
					sleep 0.1
				fi
				# Fall back to wget if primary source didn't work
				if [ ! -s "$cache" ]; then
					timeout 1 wget -q -O- http://v4.ipv6-test.com/api/myip.php "$cache" 2>/dev/null &
					# Brief sleep for cold-start display optimization (requires bash)
					sleep 0.02
				fi
				[ -s "$cache" ] && read ipaddr < "$cache"
			elif metadata_available; then
				# We're in EC2, so get our public IP address
				timeout 0.2 wget -q -O- http://169.254.169.254/latest/meta-data/public-ipv4 "$cache" 2>/dev/null &
				# Brief sleep for cold-start display optimization (requires bash)
				sleep 0.02
				[ -s "$cache" ] && read ipaddr < "$cache"
			else
				if [ -x /sbin/ip ]; then
					# 'ip route get' reports the preferred source for outbound
					# traffic without needing to guess the interface. LP: #2015819
					ipaddr=$(LC_ALL=C /sbin/ip route get 1.1.1.1 2>/dev/null | \
						awk '/src/{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1); exit}}')
					# Fall back to interface-based detection (no default route, VPN, etc.)
					if [ -z "$ipaddr" ]; then
						ipaddr=$(LC_ALL=C /sbin/ip -4 addr list dev "$interface" scope global 2>/dev/null)
						ipaddr=${ipaddr#* inet }
						ipaddr=${ipaddr%%/*}
					fi
				elif eval $BYOBU_TEST ifconfig >/dev/null 2>&1; then
					ipaddr=$(ifconfig "$interface" | grep "inet " | awk '{print $2}')
				fi
			fi
		;;
	esac
	if [ -n "$ipaddr" ]; then
		if [ "$1" = "t" ]; then
			printf "%s" "$ipaddr"
		else
			color b w k; printf "%s" "$ipaddr"; color --
		fi
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/load_average000077500000000000000000000031461522352767600176470ustar00rootroot00000000000000#!/bin/sh
#
#    load_average: grab the current load average
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__load_average_detail() {
	if [ -r /proc/loadavg ]; then
		cat /proc/loadavg
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		sysctl -n vm.loadavg 2>/dev/null
	else
		uptime
	fi
}

__load_average() {
	if [ -r "/proc/loadavg" ]; then
		read one five fifteen other < /proc/loadavg
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# vm.loadavg returns "{ x.xx y.yy z.zz }" -- fields 2,3,4 are the averages
		read -r one five fifteen </dev/null | awk '{print $2, $3, $4}')
EOF
	else
		one=$(uptime | sed -e "s/.*://" | awk '{print $1}')
	fi
	[ -n "$one" ] || return
	if [ "${LOAD_AVERAGES:-1}" = "3" ] && [ -n "$five" ] && [ -n "$fifteen" ]; then
		color Y k; printf "%s %s %s" "$one" "$five" "$fifteen"; color --
	else
		color Y k; printf "%s" "$one"; color --
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/logo000077500000000000000000000116761522352767600162050ustar00rootroot00000000000000#!/bin/sh -e
#
#    logo: determine which logo to use
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2023 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__logo_detail() {
	MARKUP="false"
	__logo
}

__logo() {
	local logo=
	if [ -n "$LOGO" ]; then
		# Allow users to define their own logo in $BYOBU_CONFIG_DIR/status
		printf "%s" "$LOGO"
		return
	fi
	local distro="$(printf "%s" "$BYOBU_DISTRO" | $BYOBU_SED 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/')"
	case "$distro" in
		*ubuntu*)
			if $MARKUP; then
				if [ "$BYOBU_BACKEND" = "tmux" ] && [ "$BYOBU_CHARMAP" = "UTF-8" ]; then
					if [ ! "$VTE_CJK_WIDTH" = "1" ] && [ !  "$VTE_CJK_WIDTH" = "wide" ] ; then
						# color "colour202" "colour255" ; printf " u "; color -
						# Ubuntu's logo doesn't display anywhere, except for on Ubuntu itself, which has the Ubuntu font with the logo
						# which breaks when you ssh into Ubuntu from elsewhere (Windows, Debian, Mac)
						color "colour202" "colour255" ; printf " u "; color -
					else
						color m W; printf " u "; color -
					fi
				else
					color m W; printf " u "; color -
				fi
			else
				printf " u "
			fi
		;;
		*alpine*)
			logo=" /\\\\\\\\ "
			$MARKUP && printf "$(color b b W)%s$(color -)" "$logo" || printf "$logo"
		;;
		*altlinux*)
			logo="alt"
			$MARKUP && printf "$(color Y k)%s$(color -)" "$logo" || printf "$logo"
		;;
	 	*arch*)
			logo=" A "
			$MARKUP && printf "$(color b w b)%s$(color -)" "$logo" || printf "$logo"
		;;
		*centos*)
			if [ "$BYOBU_BACKEND" = "tmux" ] && [ "$BYOBU_CHARMAP" = "UTF-8" ]; then
				logo="※ "
				$MARKUP && printf "$(color w m)※ $(color -)" || printf "$logo"
			else
				$MARKUP && printf "$(color g w)*$(color -)$(color m w)*$(color -)$(color y w)*$(color -)$(color b w)*$(color -)" || printf "$logo"
			fi
		;;
		*debian*)
			logo=" @ "
			$MARKUP && printf "$(color w r)%s$(color -)" "$logo" || printf "$logo"
		;;
		*fedora*)
			logo=" f "
			$MARKUP && printf "$(color b w)%s$(color -)" "$logo" || printf "$logo"
		;;
		*foresight*)
			logo="<@>"
			$MARKUP && printf "$(color b W g)%s$(color -)" "$logo" || printf "$logo"
		;;
		*gentoo*)
			logo=" > "
			$MARKUP && printf "$(color b c w)%s$(color -)" "$logo" || printf "$logo"
		;;
		*glinux*)
			logo=" G "
			# Green: 3cba54=71, Yellow: f4c20d=214, Red: db3236=167, Blue: 4885ed=69
			$MARKUP && printf "$(color colour0 colour69)██$(color colour0 colour167)■$(color colour0 colour214)■$(color colour0 colour69)▄$(color colour0 colour71)█$(color colour0 colour167)■$(color -)" || printf "$logo"
		;;
		*mac*|*darwin*)
			if [ "$BYOBU_BACKEND" = "tmux" ] && [ "$BYOBU_CHARMAP" = "UTF-8" ]; then
				# The Apple option character
				#logo=" ⌘  "
				# The Apple logo -- only visible from Mac terminals
				logo="  "
			else
				logo=" X "
			fi
			$MARKUP && printf "$(color w k)%s$(color -)" "$logo" || printf "$logo"
		;;
		*mandriva*)
			logo=" (* "
			$MARKUP && printf "$(color b k c) ($(color -)$(color b k y)*$(color -) " || printf "$logo"
		;;
		*mint*)
			logo=" lm "
			$MARKUP && printf "$(color g w)$logo$(color -)$(color g w)$(color -) " || printf "$logo"
		;;
		*openwrt*)
			logo="OWrt"
			$MARKUP && printf "$(color b colour66 W)%s$(color -)" "$logo" || printf "$logo"
		;;
		*oracle*)
			logo=" O "
			$MARKUP && printf "$(color b r w)%s$(color -)" "$logo" || printf "$logo"
		;;
		*raspbian*)
			logo=" @ "
			$MARKUP && printf "$(color colour125 colour15)%s$(color -)" "$logo" || printf "$logo"
		;;
		*red*hat*|*rhel*)
			logo=" RH "
			$MARKUP && printf "$(color R k)%s$(color -)" "$logo" || printf "$logo"
		;;
		*rockhopper*)
			logo="palm"
			$MARKUP && printf "$(color k w)%s$(color -)" "$logo" || printf "$logo"
		;;
		*slackware*)
			logo=".S "
			$MARKUP && printf "$(color u B k)%s$(color -)" "$logo" || printf "$logo"
		;;
		*suse*)
			logo="SUSE"
			$MARKUP && printf "$(color W g)%s$(color -)" "$logo" || printf "$logo"
		;;
		*wolfi*)
			logo=" * "
			$MARKUP && printf "$(color m W)%s$(color -)" "$logo" || printf "$logo"
		;;
		*xandros*)
			logo=" X "
			$MARKUP && printf "$(color W r)%s$(color -)" "$logo" || printf "$logo"
		;;
		*)
			if [ "$BYOBU_BACKEND" = "tmux" ] && [ "$BYOBU_CHARMAP" = "UTF-8" ]; then
				logo="〣"
			else
				logo="[B]"
			fi
			$MARKUP && printf "$(color b k W)%s$(color -)" "$logo" || printf " $logo "
		;;
	esac
	printf " "
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/mail000077500000000000000000000024711522352767600161600ustar00rootroot00000000000000#!/bin/sh -e
#
#    mail: notify the user if they have system mail
#
#    Copyright (C) 2009 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

MAILFILE="/var/spool/mail/$USER"

__mail_detail() {
	[ ! -d "$MAILFILE" ] && [ -s "$MAILFILE" ] && ls -alF "$MAILFILE" 2>&1
	[ -d "$MAILFILE/new" ] && ls -AlF "$MAILFILE/new" 2>&1
}

__mail() {
	if [ -f "$MAILFILE" ] && [ -s "$MAILFILE" ]; then
		 color b; printf "%s" "$ICON_MAIL"; color --
	elif [ -d "$MAILFILE/new" ] && "$(ls -A "$MAILFILE/new" 2>/dev/null)"; then
		 color b; printf "%s" "$ICON_MAIL"; color --
	else
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/mail"*
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/memory000077500000000000000000000101101522352767600165330ustar00rootroot00000000000000#!/bin/sh -e
#
#    mem_available: grab the current memory and usage
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__memory_detail() {
	if eval $BYOBU_TEST free >/dev/null 2>&1; then
		free
	else
		vmstat
	fi
}

__memory() {
	local free="" total="" available="" buffers="" cached=""
	local kb_main_used=0 buffers_plus_cached=0 fo_buffers=0 fo_cached=0
	if [ -r /proc/meminfo ]; then
		while read tok val unit; do
			case "$tok" in
				MemTotal:)     total=${val};;
				MemFree:)      free=${val};;
				MemAvailable:) available=${val};;
				Buffers:)      buffers=${val};;
				Cached:)       cached=${val};;
			esac
			# MemAvailable (Linux 3.14+) appears before Buffers/Cached;
			# break early once we have total + available for efficiency.
			[ -n "${total}" -a -n "${available}" ] && break;
		done < /proc/meminfo
	elif [ "$BYOBU_OSTYPE" = "FreeBSD" ]; then
		# FreeBSD support
		page_size=$(sysctl -n vm.stats.vm.v_page_size)
		page_count=$(sysctl -n vm.stats.vm.v_page_count)
		free_count=$(sysctl -n vm.stats.vm.v_free_count)
		cache_count=$(sysctl -n vm.stats.vm.v_cache_count)
		inactive_count=$(sysctl -n vm.stats.vm.v_inactive_count)
		total=$(((${page_size} * ${page_count}) / 1024))
		free=$(((${page_size} * (${free_count} + ${cache_count} + ${inactive_count})) / 1024))
		buffers=0
		cached=0
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# OpenBSD support: use sysctl and vmstat
		local physmem pagesize free_pages inactive_pages
		physmem=$(sysctl -n hw.physmem 2>/dev/null)
		[ -n "$physmem" ] || return
		total=$((physmem / 1024))
		pagesize=$(sysctl -n hw.pagesize 2>/dev/null)
		# Count both free and inactive pages as available memory
		free_pages=$(vmstat -s 2>/dev/null | awk '/pages free$/ { f=$1 } /pages inactive$/ { i=$1 } END { print f+0, i+0 }')
		if [ -n "$free_pages" ] && [ -n "$pagesize" ]; then
			set -- $free_pages
			free=$(( (${1:-0} + ${2:-0}) * pagesize / 1024 ))
		else
			free=0
		fi
		buffers=0
		cached=0
	elif eval $BYOBU_TEST vm_stat >/dev/null 2>&1; then
		# MacOS support
		# calculation borrowed from http://apple.stackexchange.com/a/48195/18857
		free_blocks=$(vm_stat | grep free | awk '{ print $3 }' | sed -e 's/\.//')
		inactive_blocks=$(vm_stat | grep inactive | awk '{ print $3 }' | sed -e 's/\.//')
		speculative_blocks=$(vm_stat | grep speculative | awk '{ print $3 }' | sed -e 's/\.//')
		free=$((($free_blocks+speculative_blocks)*4))
		inactive=$(($inactive_blocks*4))
		total=$((($free+$inactive)))
		buffers=0
		cached=0
	fi
	if [ -n "$available" ]; then
		# MemAvailable accounts for reclaimable slab memory in addition
		# to free + buffers + cached; matches what 'free -h' reports.
		fo_buffers=$(($total - $available))
	else
		kb_main_used=$(($total-$free))
		buffers_plus_cached=$(($buffers+$cached))
		fo_buffers=$(($kb_main_used - $buffers_plus_cached))
	fi
        fpdiv $((100*${fo_buffers})) "${total}" 0;
        usage=${_RET}
	if [ $total -ge 1048576 ]; then
		fpdiv "$total" 1048567 1
		total=${_RET}
		unit="$ICON_GB"
	elif [ $total -ge 1024 ]; then
		fpdiv "$total" 1024 0
		total=${_RET}
		unit="$ICON_MB"
	else
		unit="$ICON_KB"
	fi
	if [ $usage -gt 90 ]; then
		# Change foreground to yellow, if usage over 90%
		fg="Y"
	else
		fg="W"
	fi
	[ -n "$total" ] || return
	color b g W; printf "%s" "$total"; color -; color g W; printf "%s" "$unit"; color -; color b g "$fg"; printf "%s" "$usage"; color -; color g "$fg"; printf "%s" "$PCT"; color --
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/menu000077500000000000000000000031631522352767600162010ustar00rootroot00000000000000#!/bin/sh -e
#
#    menu: display the menu text
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland 
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__menu_detail() {
	return
}

__menu() {
	local bindings esc key text
	[ -r "$BYOBU_CONFIG_DIR/keybindings" ] && bindings="$BYOBU_CONFIG_DIR/keybindings" || bindings="$BYOBU_CONFIG_DIR/.screenrc"
	if grep -qs "^source.*screen-escape-keys$" $bindings 2>/dev/null || grep -qs "^source.*f-keys.screen.disable$" $bindings 2>/dev/null || [ "$1" = "--disable-f-keys" ]; then
		# Get the second to last byte from the "escape" option
		esc=`grep "^escape" $bindings | tail -c 3 | head -c 1`
		[ -n "$esc" ] && key="^$esc-@" || key="^a-@"
	elif grep -qs "^source.*none$" $bindings 2>/dev/null; then
		key="byobu-config"
	else
		key="F9"
	fi
	text=$(gettext "Menu" 2>/dev/null) || text="Menu"
	color k w; printf "%s:<" "$text"; color -; color b k w; printf "%s" "$key"; color k w; printf ">"
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/network000077500000000000000000000100311522352767600167160ustar00rootroot00000000000000#!/bin/sh -e
#
#    network: calculate the network up/down rates
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__network_detail() {
	get_network_interface; local interface="$_RET"
	if [ -x /sbin/ip ]; then
		LC_ALL=C /sbin/ip addr show "$interface" | $BYOBU_SED 's/\s*$//'
	else
		ifconfig "$interface" 2>/dev/null
	fi
}

__network() {
	get_network_interface; local interface="$_RET"
	local x1=0 x2=0 have_cache= i= t= unit= symbol= cache= rate=
	status_freq network
	t="$_RET"
	# By default, we won't bug the user with the display of network traffic
	# below NETWORK_THRESHOLD in kbps; override in $BYOBU_CONFIG_DIR/status
	[ -n "$NETWORK_THRESHOLD" ] || NETWORK_THRESHOLD=20
	# OpenBSD: cache netstat output once for both directions
	local _netstat_out=""
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		_netstat_out=$(netstat -ibn 2>/dev/null)
	fi
	for i in up down; do
		unit="kb"
		case $i in
			up) symbol="$ICON_UP" ;;
			down) symbol="$ICON_DN" ;;
		esac
		cache="$BYOBU_RUN_DIR/cache.$BYOBU_BACKEND/network.$i"
		if [ -r "$cache" ]; then
			read x1 < "$cache"
			have_cache=1
		else
			x1=0
			have_cache=0
		fi
		if [ -n "$_netstat_out" ]; then
			# OpenBSD netstat -ibn columns:
			# Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll
			local nb
			if [ "$i" = "up" ]; then
				nb=$(printf '%s\n' "$_netstat_out" | awk -v iface="$interface" '$1 == iface && $4 ~ /:/ { print $10; exit }')
			else
				nb=$(printf '%s\n' "$_netstat_out" | awk -v iface="$interface" '$1 == iface && $4 ~ /:/ { print $7; exit }')
			fi
			[ -n "$nb" ] && x2="$nb" || x2=0
			printf "%s" "$x2" > "$cache"
			[ "${t:-0}" -gt 0 ] 2>/dev/null || continue
			[ "$have_cache" -eq 1 ] || continue
		else
			local iface rbytes rpackets rerrs rdrop rfifo rframe rcompressed rmulticast tbytes tpackets terrs tdrop tfifo tcolls tcarrier tcompressed
			cat /proc/net/dev > "$cache".dev
			while read iface rbytes rpackets rerrs rdrop rfifo rframe rcompressed rmulticast tbytes tpackets terrs tdrop tfifo tcolls tcarrier tcompressed; do
				case "$iface" in
					${interface}:)
						[ "$i" = "up" ] && x2=${tbytes} || x2=${rbytes}
						break;
					;;
					${interface}:*)
						# Interface and tbytes got munged together
						[ "$i" = "up" ] && x2=${rmulticast##*:} || x2=${iface##*:}
						break;
					;;
				esac
			done < "$cache".dev
			printf "%s" "$x2" > "$cache"
			[ "$have_cache" -eq 1 ] || continue
		fi
		rate=$((8*($x2 - $x1) / $t / 1024))  # in kbps
		[ "$rate" -lt 0 ] && rate=0
		if [ $rate -gt $NETWORK_THRESHOLD ]; then
			case "$NETWORK_UNITS" in
				bytes)
					rate=$(($rate/8))
					if [ "$rate" -gt 1048576 ]; then
						fpdiv "$rate" 1048576 1
						rate=${_RET}
						unit="GB/s"
					elif [ "$rate" -gt 1024 ]; then
						fpdiv "$rate" 1024 1
						rate=${_RET}
						unit="MB/s"
					else
						unit="kB/s"
					fi
				;;
				*)
					# Default to bps
					# Why 1000 and not 1024?  http://en.wikipedia.org/wiki/Data_rate_units
					if [ "$rate" -gt 1000000 ]; then
						fpdiv "$rate" 1000000 1
						rate=${_RET}
						unit="Gb"
					elif [ "$rate" -gt 1000 ]; then
						fpdiv "$rate" 1000 1
						rate=${_RET}
						unit="Mb"
					fi
				;;
			esac
			[ -n "$rate" ] || continue
			color b m w; printf "%s%s" "$symbol" "$rate"; color -; color m w; printf "%s" "$unit"; color --
		else
			rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/network"*
		fi
	done
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/notify_osd000077500000000000000000000024721522352767600174140ustar00rootroot00000000000000#!/bin/sh -e
#
#    notify_osd: print notify-osd messages in the notification buffer
#
#    Copyright (C) 2010 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#             with help from Mathias Gug 
#
#    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, version 3 of the License.
#
#    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, see .

NOTIFY_OSD_LOG="$HOME"/.cache/notify-osd.log

__notify_osd_detail() {
	cat "$NOTIFY_OSD_LOG" || true
}

__notify_osd() {
	# This line operates basically as a daemon, watching the notify-osd log file,
	# processing new messages and sending them to the session
	CMD="tail --pid $PPID -n 0 -F $NOTIFY_OSD_LOG"
	pkill -f "$CMD" || true
	$CMD | $BYOBU_PREFIX/lib/byobu/include/notify_osd "$PPID" &
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/packages000077500000000000000000000027471522352767600170220ustar00rootroot00000000000000#!/bin/sh -e
#
#    packages: count the number of packages installed
#
#    Copyright (C) 2023 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__packages_detail() {
	if eval $BYOBU_TEST dpkg >/dev/null 2>&1; then
		dpkg -l | grep ^ii
	fi
	if eval $BYOBU_TEST snap >/dev/null 2>&1; then
		snap list
	fi
	if eval $BYOBU_TEST apk >/dev/null 2>&1; then
		apk info
	fi
	return
}

__packages() {
	local packages=0
	if eval $BYOBU_TEST dpkg >/dev/null 2>&1; then
		count=$(dpkg -l | grep -c ^ii)
		packages=$((packages+count))
	fi
	if eval $BYOBU_TEST snap >/dev/null 2>&1; then
		count=$(snap list | grep -c -v "^Name\s")
		packages=$((packages+count))
	fi
	if eval $BYOBU_TEST apk >/dev/null 2>&1; then
		count=$(apk info | wc -l)
		packages=$((packages+count))
	fi
	[ -n "$packages" ] || return
	color w y; printf "[%s]" "$count"; color --;

}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/processes000077500000000000000000000022311522352767600172360ustar00rootroot00000000000000#!/bin/sh -e
#
#    processes: report number of running processes
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__processes_detail() {
	ps -ej 2>/dev/null || ps -ax 2>/dev/null
}

__processes() {
	local count=
	if [ -r /proc ]; then
		count=$(ls -d /proc/[0-9]* 2>/dev/null | wc -l)
	else
		count=$(($(ps -ef | wc -l) - 1))
	fi
	[ -n "$count" ] || return
	color b y w; printf "%s" "$count"; color -; color y w; printf "&"; color --
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/raid000077500000000000000000000034451522352767600161570ustar00rootroot00000000000000#!/bin/sh -e
#
#    raid: notify raid events, failures and syncing
#
#    Copyright (C) 2010 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__raid_detail() {
	if [ -r /proc/mdstat ]; then
		cat /proc/mdstat
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# OpenBSD uses bioctl(8) for RAID
		bioctl softraid0 2>/dev/null || true
	else
		true
	fi
}

__raid() {
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# OpenBSD: check softraid status via bioctl
		if bioctl softraid0 2>/dev/null | grep -qE 'Degraded|Failed|Rebuild'; then
			color B w r; printf "%s" "RAID"; color --
		fi
		return
	fi
	[ -r /proc/mdstat ] || return
	while read line; do
		local p msg
		# Errors in your raid
		case "$line" in
			*\ blocks\ *\[*_*\])
				[ -z "${msg}" ] && msg="RAID"
			;;
			*%*)
				p="${line%%\%*}${PCT}"; p=${p##* };
				[ -z "$msg" ] && msg="RAID"
				msg="$msg,$p"
			;;
		esac
	done < /proc/mdstat
	if [ -n "$msg" ]; then
		color B w r; printf "%s" "$msg"; color --
	elif [ -e "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/raid" ]; then
		# Clear out cached raid message
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/raid"*
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/reboot_required000077500000000000000000000042361522352767600204310ustar00rootroot00000000000000#!/bin/sh -e
#
#    reboot_required: determine if a reboot is required
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

REBOOT_FLAG="/var/run/reboot-required"
RELOAD_FLAG="$BYOBU_RUN_DIR/reload-required"
POWERNAP_FLAG="/var/run/powernap/powersave"
UNATTENDED_UPGRADE_FLAG="/var/run/unattended-upgrades.pid"

__reboot_required_detail() {
		[ -e "$REBOOT_FLAG" ] && ls -alF "$REBOOT_FLAG" 2>&1
		[ -e "$RELOAD_FLAG" ] && ls -alF "$RELOAD_FLAG" 2>&1
		[ -e "$POWERNAP_FLAG" ] && ls -alF "$POWERNAP_FLAG" 2>&1
		[ -e "$POWERNAP_FLAG" ] && cat "$POWERNAP_FLAG" 2>&1
}

__reboot_required() {
	local status="$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/reboot_required"
	local livepatched=0
	if [ -e "$UNATTENDED_UPGRADE_FLAG" ]; then
		color b R W; printf "$ICON_UPGRADE "; color --;
	fi
	while read line; do
		set -- ${line}
		case "$line" in
			kpatch_livepatch_*)
				color k G; printf "$ICON_LIVEPATCHED"; color -;
				livepatched=1
				break
			;;
		esac
	done < /proc/modules
	if [ -e "$REBOOT_FLAG" ]; then
		if [ "$livepatched" = "1" ]; then
			color k G; printf "$ICON_REBOOT"; color --;
		else
			color b k R; printf "$ICON_REBOOT"; color --;
		fi
	fi
	if [ -e "$RELOAD_FLAG" ]; then
		color b W; printf "<"; color -; color b b W; printf "F5"; color -; color b W; printf ">"; color -; printf " "
	elif [ -s "$status" ]; then
		rm -f "$status"
	fi
	if [ -e "$POWERNAP_FLAG" ]; then
		color b W; printf ".zZ"; color --
	elif [ -s "$status" ]; then
		rm -f "$status"
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/release000077500000000000000000000037371522352767600166640ustar00rootroot00000000000000#!/bin/sh -e
#
#    release: grab the os/distro release version
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2023 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__release_detail() {
	lsb_release -a 2>/dev/null
}

__release() {
	local RELEASE="${RELEASE}"
	if [ -n "$RELEASE" ]; then
		# user defined
		true
	elif [ "$BYOBU_DISTRO" = "Wolfi" ]; then
		# Wolfi, and perhaps other distroless distros don't really have release versions
		RELEASE="Wolfi"
	elif [ -r "/etc/os-release" ]; then
		# lsb_release is *really* slow;  try to use /etc/os-release
		RELEASE=$(. /etc/os-release && echo "$VERSION_ID")
	elif [ -r "/etc/issue" ]; then
		# next try /etc/issue first
		local issue
		read issue < /etc/issue
		case "$issue" in
			Ubuntu*)
				set -- $issue;
				RELEASE="$2";
			;;
			Debian*)
				local ver
				read ver < /etc/debian_version
				RELEASE="$ver"
			;;
		esac
	elif eval $BYOBU_TEST sw_vers >/dev/null 2>&1; then
		RELEASE="$(sw_vers -productVersion)"
	fi
	if [ -z "$RELEASE" ] && eval $BYOBU_TEST lsb_release >/dev/null 2>&1; then
		# If lsb_release is available, use it
		RELEASE=$(lsb_release -s -r)
	fi
	if [ -n "$RELEASE_ABBREVIATED" ] && [ $RELEASE_ABBREVIATED -gt 0 ]; then
		color bold2; printf "%.${RELEASE_ABBREVIATED}s" "$RELEASE"; color --
	else
		color bold2; printf "%s" "$RELEASE"; color --
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/services000077500000000000000000000044021522352767600170550ustar00rootroot00000000000000#!/bin/sh -e
#
#    services: show what services are running on this server (configurable)
#
#    Copyright (C) 2009 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__services_detail() {
	return
}

service_running() {
	if [ -f "/sbin/service" ]; then
		# Use systemd
		case "$(/sbin/service $1 status 2>/dev/null)" in
			*running*)
				true
			;;
			*)
				false
			;;
		esac
	elif [ -f "/etc/init/$1.conf" ]; then
		# Use upstart
		case "$(status $1 2>/dev/null)" in
			*running*)
				true
			;;
			*)
				false
			;;
		esac
	elif [ -f "/etc/init.d/$1" ]; then
		# Fall back to sysvinit
		/etc/init.d/$1 status >/dev/null 2>&1
	else
		false
	fi
}

__services() {
	local services="$SERVICES"
	# Users can define a list of services to monitor in $BYOBU_CONFIG_DIR/status
	if [ -z "$services" ]; then
		if [ -f "/etc/eucalyptus/eucalyptus.conf" ]; then
			# If the user has not defined any services, but this system is a
			# UEC system, default to the list of Ubuntu Enterprise Cloud Services
			services="eucalyptus-cloud|CLC eucalyptus-walrus|WC eucalyptus-cc|CC eucalyptus-sc|SC eucalyptus-nc|NC"
		fi
	fi
	output=
	for i in $services; do
		service=${i%|*}
		nick=${i#*|}
		case "$service" in
			eucalyptus-nc)
				if service_running $service; then
					# This is a node controller, determine VM usage
					. /etc/eucalyptus/eucalyptus.conf
					count=$(pgrep -c -f /usr/bin/kvm || true)
					output="$output,NC:$count"
				fi
			;;
			*)
				service_running $service && output="$output,$nick"
			;;
		esac
	done
	[ -n "$output" ] || return
	color w c; printf "%s" ${output#,}; color --
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/session000077500000000000000000000024511522352767600167170ustar00rootroot00000000000000#!/bin/sh -e
#
#    session: tmux session name
#
#    Copyright (C) 2013-2014 Dustin Kirkland 
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__session_detail() {
	tmux list-sessions
}

__session() {
	# Note: This will only work in byobu-tmux
	case "$BYOBU_BACKEND" in
		tmux)
			local count=$(tmux list-sessions 2>/dev/null | grep -v "^_" | wc -l)
			if [ $count -gt 1 ]; then
				color u W k; printf "${ICON_SESSION}#S"; color --
			else
				echo
			fi
		;;
		screen)
			local count=$(screen -ls | grep "^\s\+.*)$" | wc -l)
			if [ $count -gt 1 ]; then
				color u W k; printf "${ICON_SESSION}%S"; color --
			else
				echo
			fi
		;;
	esac
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/swap000077500000000000000000000044021522352767600162040ustar00rootroot00000000000000#!/bin/sh -e
#
#    mem_swap: show the current swap available and used
#
#    Copyright (C) 2010 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__swap_detail() {
	if [ -r /proc/meminfo ]; then
		cat /proc/meminfo
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		swapctl -l 2>/dev/null
	fi
}

__swap() {
	local stotal="" sfree="" name="" val="" unit="" mem="" f="";
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# OpenBSD: use swapctl -sk for summary in kB
		local swapline sused
		swapline=$(swapctl -sk 2>/dev/null | tail -1)
		if [ -n "$swapline" ]; then
			# swapctl -sk Total line: "Total:    %"
			set -- $swapline
			stotal="${2:-0}"
			sused="${3:-0}"
			sfree=$(($stotal - $sused))
		fi
	elif [ -r /proc/meminfo ]; then
		while read name val unit; do
			if [ "$name" = "SwapTotal:" ]; then
				stotal="$val"
			elif [ "$name" = "SwapFree:" ]; then
				sfree="$val"
			else
				continue
			fi
			[ -n "$stotal" -a -n "$sfree" ] && break;
		done < /proc/meminfo
	fi
	if [ "${stotal:-0}" = "0" ]; then
		printf ""
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/swap"
	else
		mem=${stotal}
		f=$(((100*($stotal-$sfree))/$stotal))
		if [ $mem -ge 1048576 ]; then
		fpdiv "${mem}" 1048576 1
			mem=${_RET}
			unit="$ICON_GB"
		elif [ $mem -ge 1024 ]; then
			fpdiv "${mem}" 1024 0
			mem=${_RET}
			unit="$ICON_MB"
		else
			mem="$mem"
			unit="$ICON_KB"
		fi
		[ -n "$mem" ] || return
		color b G k; printf "s%s" "$mem"; color -; color G k; printf "%s" "$unit"; color -;
		color b G k; printf "%s" "$f"; color -; color G k; printf "%s" "$PCT"; color --
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/time000077500000000000000000000020711522352767600161700ustar00rootroot00000000000000#!/bin/sh -e
#
#    time: print the time in HH:MM:SS format
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__time_detail() {
	date
}

__time() {
	local secs=1
	[ -n "$TIME_SECONDS" ] && secs=$TIME_SECONDS
	case "$BYOBU_BACKEND" in
		screen)
			format="\0050c"
			[ "$secs" != "0" ] && format="$format:\005s"
			printf $format
		;;
	esac
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/time_binary000077500000000000000000000102661522352767600175410ustar00rootroot00000000000000#!/bin/bash -e
#---------------------------------------------------------------------
# Script to display a "binary clock" using unicode characters from the
# braille block.
#
# Designed to work with the wonderful byobu(1) but can be run
# stand-alone.
#---------------------------------------------------------------------
#
# Copyright (C) 2011 Canonical Ltd.
#
# Author: James Hunt 
#
# 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, version 3 of the License.
#
# 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, see .
#
#---------------------------------------------------------------------

script_name=${0##*/}

# Selected Unicode Braille characters:
#
#  0x2800, 0x2880, 0x2820, 0x28a0, 0x2810, 0x2890, 0x2830, 0x28b0, 0x2808, 0x2888,
#  0x2840, 0x28c0, 0x2860, 0x28e0, 0x2850, 0x28d0, 0x2870, 0x28f0, 0x2848, 0x28c8,
#  0x2804, 0x2884, 0x2824, 0x28a4, 0x2814, 0x2894, 0x2834, 0x28b4, 0x280c, 0x288c,
#  0x2844, 0x28c4, 0x2864, 0x28e4, 0x2854, 0x28d4, 0x287b, 0x28f4, 0x284c, 0x28cc,
#  0x2802, 0x2882, 0x2822, 0x28a2, 0x2812, 0x2892, 0x2832, 0x28b2, 0x280a, 0x288a,
#  0x2842, 0x28c2, 0x2862, 0x28e2, 0x2852, 0x28d2, 0x2872, 0x28f2, 0x284a, 0x28ca,
#  0x2806, 0x2886
#
# Index of this array is 0-61 with character returned being
# "two column" binary representation of a time segment.
#
binary=(⠀ ⢀ ⠠ ⢠ ⠐ ⢐ ⠰ ⢰ ⠈ ⢈ \
         ⡀ ⣀ ⡠ ⣠ ⡐ ⣐ ⡰ ⣰ ⡈ ⣈ \
         ⠄ ⢄ ⠤ ⢤ ⠔ ⢔ ⠴ ⢴ ⠌ ⢌ \
         ⡄ ⣄ ⡤ ⣤ ⡔ ⣔ ⡻ ⣴ ⡌ ⣌ \
         ⠂ ⢂ ⠢ ⢢ ⠒ ⢒ ⠲ ⢲ ⠊ ⢊ \
         ⡂ ⣂ ⡢ ⣢ ⡒ ⣒ ⡲ ⣲ ⡊ ⣊ ⠆ ⢆)

usage()
{
cat <   : Specify separator between hours and minutes
              (and seconds if not disabled).
 -u         : Display alphabetics in upper-case (hex mode only).
 -x         : Disable time in hexadecimal (base 16).
 -z         : Disable display of seconds.

EOT
}

suppress_seconds=n
clock_type=binary
format=std
ending=""
uppercase=n
leading_zeros=n

while getopts "bhlmnos:uxz" opt
do
  case "$opt" in
    b) 
      clock_type=binary
    ;;

    h) 
      usage
      exit 0
    ;;

    l) 
      leading_zeros=y
    ;;

    m) 
      format=mil
    ;;

    n) 
      ending=
    ;;

    o) 
      clock_type=oct
    ;;

    s) 
      sep=$OPTARG
    ;;

    u)
      uppercase=y
    ;;

    x) 
      clock_type=hex
    ;;

    z) 
      suppress_seconds=y
    ;;
  esac
done

if [ -z "$clock_type" ]
then
  printf "%s\n" "ERROR: must specify clock type"
  exit 1
fi

shift $[$OPTIND-1]

# get current time, handling 12-hour or 24-hour
if [ $format = std ]
then
  hrs_format=%l
else
  hrs_format=%k
fi

time=($(date "+${hrs_format} %M %S"))
h=$(printf ${time[0]})
m=$(printf ${time[1]})
s=$(printf ${time[2]})

if [ $clock_type = binary ]
then
  [ $suppress_seconds = n ] && seconds="${sep}${binary[10#$s]}"
  display_time="${binary[10#$h]}${sep}${binary[10#$m]}${seconds}${ending}"
else
  if [ $clock_type = hex ]
  then
    conversion=x
    [ $uppercase = y ] && conversion=X
  else
    conversion=o
  fi
  precision=
  [ $leading_zeros = y ] && precision=.2
  base_format=%2${precision}${conversion}

  hh=$(printf "$base_format" $h)
  hm=$(printf "$base_format" $m)
  [ "$suppress_seconds" = n ] && hs="${sep}$(printf "$base_format" $s)"
  display_time="${hh}${sep}${hm}${hs}${ending}"
fi

color k w
printf "%s" "$display_time"
color --
byobu-7.15/usr/lib/byobu/time_utc000077500000000000000000000017001522352767600170410ustar00rootroot00000000000000#!/bin/sh -e
#
#    time_utc: print UTC time in HH:MM
#
#    Copyright (C) 2010 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__time_utc_detail() {
	date -u
}

__time_utc() {
	d=$(date -u +%H:%M)
	color invert; printf "%sUTC" "$d"; color --
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/trash000077500000000000000000000022071522352767600163540ustar00rootroot00000000000000#!/bin/sh -e
#
#    trash: show icon (and optionally count) if entries in trash.
#
#    Copyright (C) 2011 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: James Hunt 
#             Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

TRASH_DIR="$HOME/.local/share/Trash/files"

__trash_detail() {
	find "$TRASH_DIR"
}

__trash() {
	local count
	[ -d "$TRASH_DIR" ] || return
	count=$(ls $dir|wc -l)
	[ "$count" = "0" ] && return
	printf "%s[%s]" "$ICON_TRASH" "$count"
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/updates_available000077500000000000000000000156261522352767600207110ustar00rootroot00000000000000#!/bin/sh -e
#
#    updates_available: calculate and cache the number of updates available
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2023 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

___print_updates() {
	local u= s=
	read u s < "$1"
	if [ -n "$u" ]; then
		if [ "$u" -gt 0 ]; then
			color b r W; printf "%d" "$u"; color -; color r W
			if [ -n "$s" ] && [ "$s" -gt 0 ]; then
				printf "$ICON_SECURITY"
			else
				printf "$ICON_UPDATES"
			fi
			color --
		elif [ "$u" = "0" ] && [ -e "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/updates_available" ]; then
			# Clear out byobu's status cache
			rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/updates_available"*
		fi
	fi
}

___update_cache() {
	local mycache=$1 flock="$1.lock"
	# Now we actually have to do hard computational work to calculate updates.
	# Let's try to be "nice" about it:
	renice 10 $$ >/dev/null 2>&1 || true
	ionice -c3 -p $$ >/dev/null 2>&1 || true
	# These are very computationally intensive processes.
	# Background this work, have it write to the cache files,
	# and let the next cache check pick up the results.
	# Ensure that no more than one of these run at a given time
	if [ -x /usr/lib/update-notifier/apt-check ]; then
		# If apt-check binary exists, use it
		flock -xn "$flock" sh -c "(/usr/lib/update-notifier/apt-check 2>&1 | awk '-F;' 'END { print \$1, \$2 }' >\"${mycache}-x\" 2>/dev/null ; mv \"${mycache}-x\" \"$mycache\")" &
	elif eval $BYOBU_TEST apt >/dev/null; then
		# 'apt list --upgradeable' is ~2x faster than 'apt-get -s upgrade'
		# and available on apt 1.1+ (Ubuntu 16.04+, Debian 9+).
		# Each upgradeable-package line contains a '/' between name and suite.
		flock -xn "$flock" sh -c "(apt list --upgradeable 2>/dev/null | grep -c '/' >\"${mycache}-x\" 2>/dev/null ; mv \"${mycache}-x\" \"$mycache\")" &
	elif eval $BYOBU_TEST apt-get >/dev/null; then
		# Fallback for systems with apt-get but not apt (very old Debian)
		flock -xn "$flock" apt-get -s -o Debug::NoLocking=true upgrade | grep -c ^Inst >$mycache 2>/dev/null &
	elif eval $BYOBU_TEST pkcon >/dev/null; then
		# use packagekit to show list of packages
		LC_ALL=C flock -xn "$flock" pkcon get-updates -p | awk '/^Results:$/ { start=NR }; /^Security/ { security++ }; END { if (!/There are no updates available at this time./) { print NR-start, security }}' > "$mycache" 2>/dev/null &
	elif eval $BYOBU_TEST zypper >/dev/null; then
		# If zypper exists, use it
		flock -xn "$flock" zypper --no-refresh lu --best-effort | grep -c 'v |' >$mycache 2>/dev/null &
	elif eval $BYOBU_TEST yum >/dev/null; then
		# If yum exists, use it
		# TODO: We need a better way of counting updates available from a RH expert
		flock -xn "$flock" yum list updates -q | grep -vc "Updated Packages" >$mycache 2>/dev/null &
	elif eval $BYOBU_TEST pacman >/dev/null; then
		# If pacman (Archlinux) exists, use it
		LC_ALL=C flock -xn "$flock" pacman -Sup | grep -vc "^\(::\| \)" >$mycache 2>/dev/null &
	elif eval $BYOBU_TEST opkg >/dev/null; then
		# If opkg (OpenWrt) exists, use it, also background if flock exists
		if eval $BYOBU_TEST flock >/dev/null; then
			flock -xn "$flock" opkg list-upgradable | wc -l >$mycache 2>/dev/null &
		else
			opkg list-upgradable | wc -l >$mycache &
		fi
	elif eval $BYOBU_TEST brew >/dev/null; then
		# If homebrew (Mac OSX) exists, use it, also background if flock exists
		if eval $BYOBU_TEST flock >/dev/null; then
			flock -xn "$flock" brew outdated | wc -l >$mycache 2>/dev/null &
		else
			brew outdated | wc -l >$mycache &
		fi
	elif eval $BYOBU_TEST apk >/dev/null; then
		# Wolfi updates are cheap (~1s); so update cache every time
		apk update 2>&1 >/dev/null
		apk upgrade --simulate | grep -c " Upgrading " >$mycache 2>/dev/null &
	elif eval $BYOBU_TEST dnf >/dev/null; then
		# If dnf exists, use it
		flock -xn "$flock" dnf list --upgrades -q -y | grep -vc "Available Upgrades" >$mycache 2>/dev/null &
	fi
}

___update_needed() {
	# Checks if we need to update the cache.
	# TODO: add more distro
	local mycache=$1
	# The cache doesn't exist: create it
	[ ! -e "$mycache" ] && return 0
	if eval $BYOBU_TEST apt-get >/dev/null; then
		# Debian/ubuntu
		d0=$(($(stat -c %Y $mycache 2>/dev/null)-5))
		d1=$(stat -c %Y /var/lib/apt)
		d2=$(stat -c %Y /var/lib/apt/lists)
		d3=$(stat -c %Y /var/log/dpkg.log)
		now=$(date +%s)
		delta=$(($now-$d0))
		if [ $d0 -lt 0 ] || [ $d0 -lt $d1 ] || [ $d0 -lt $d2 ] || [ $d0 -lt $d3 ] || [ 3605 -lt $delta ] ; then
			return 0
		else
			return 1
		fi
	elif [ -e "/var/lib/PackageKit/transactions.db" ]; then
		[ "/var/lib/PackageKit/transactions.db" -nt "$mycache" ]
		return $?
	elif eval $BYOBU_TEST pacman >/dev/null; then
		# Archlinux
		local db
		for db in /var/lib/pacman/sync/*.db; do
			[ "$db" -nt "$mycache" ] && return 0
		done
		# Also check if packages were actually installed
		[ -f "/var/log/pacman.log" ] && [ "/var/log/pacman.log" -nt "$mycache" ] && return 0
		return 1
	elif eval $BYOBU_TEST opkg >/dev/null; then
		# OpenWrt
		[ ! -e /var/lock/opkg.lock ] || return 1
		if [ -d /var/opkg-lists ]; then
			[ /var/opkg-lists -nt "$mycache" ]
			return $?
		else
			local u s
			read u s < "$mycache"
			[ "$u" -gt 0 ]
			return $?
		fi
	elif eval $BYOBU_TEST brew >/dev/null; then
		# Mac OSX
		# check if any new versions have been installed since
		# we last cached. this may not recognize formulae
		# installed with HEAD
		for f in $(brew --prefix)/Cellar/*; do
			[ "$f" -nt "$mycache" ] && return 0
		done
		# nothing new has been installed, so check wether the
		# formulae database was updated
		[ "$(brew --prefix)/Library/Formula" -nt "$mycache" ]
		return $?
	elif [ -e "/var/cache/dnf/packages.db" ]; then
		[ "/var/cache/dnf/packages.db" -nt "$mycache" ]
		return $?
	fi
	return 1
}

__updates_available_detail() {
	if eval $BYOBU_TEST apt >/dev/null; then
		local detail=`apt list --upgradeable 2>/dev/null`
		if [ "$1" = "--detail" ]; then
			printf "$detail"
		else
			local short=`printf "%s" "$detail" | grep -c ^Inst`
			printf "$short"
		fi
	fi
}

__updates_available() {
	local mycache="$BYOBU_RUN_DIR/cache.$BYOBU_BACKEND/updates-available"
	# If mycache is present, use it
	[ -r $mycache ] && ___print_updates "$mycache"
	# If we really need to do so (mycache doesn't exist, or the package database has changed),
	# background an update now
	___update_needed "$mycache" && ___update_cache "$mycache"
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/uptime000077500000000000000000000035161522352767600165420ustar00rootroot00000000000000#!/bin/sh -e
#
#    uptime: condensed uptime of the machine
#
#    Copyright (C) 2009 Raphaël Pinson.
#    Copyright (C) 2009 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Raphaël Pinson 
#             Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__uptime_detail() {
	uptime
}

__uptime() {
	local u= idle= str=
	if [ -r /proc/uptime ]; then
		read u idle < /proc/uptime
		u=${u%.*}
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# OpenBSD: kern.boottime is epoch seconds directly
		local bt
		bt=$(sysctl -n kern.boottime 2>/dev/null)
		[ -n "$bt" ] && u=$(($(date +%s) - bt))
	elif [ -x /usr/sbin/sysctl ]; then
		# MacOS support
		u=$(/usr/sbin/sysctl -n kern.boottime | cut -f4 -d' ' | cut -d',' -f1)
		u=$(($(date +%s) - $u))
	fi
	if [ "$u" ]; then
		if [ "$u" -gt 86400 ]; then
			str="$(($u / 86400))d$((($u % 86400) / 3600))h"
		elif [ "$u" -gt 3600 ]; then
			str="$(($u / 3600))h$((($u % 3600) / 60))m"
		elif [ "$u" -gt 60 ]; then
			str="$(($u / 60))m"
		else
			str="${u}s"
		fi
	else
		# Last ditch hack
		str=$(uptime | sed -e "s/.* up *//" -e "s/ *days, */d/" -e "s/:/h/" -e "s/,.*/m/")
	fi
	[ -n "$str" ] || return
	color w b; printf "%s" "${str}"; color --
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/users000077500000000000000000000033641522352767600164010ustar00rootroot00000000000000#!/bin/sh -e
#
#    users: print the number of remote users on the machine
#
#    Copyright (C) 2009 Raphaël Pinson.
#    Copyright (C) 2009 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Raphaël Pinson 
#             Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

__users_detail() {
	ps -ef 2>/dev/null | grep "sshd:.*@" | grep -v grep
}

__users() {
	local count=0 sign=
	# tmux interprets # as a special character, so ## is needed for a literal #
	# screen displays # literally, so only one # is needed
	case "$BYOBU_BACKEND" in
		tmux) sign="##" ;;
		*) sign="#" ;;
	esac
	if [ "$USERS_DISTINCT" = "1" ]; then
		count=$(pgrep -fl 'sshd:.*@' | cut -f3 -d\ | cut -f1 -d@ | sort -u | wc -l)
	else
		# Note: we'd like to use pgrep -c, however, this isn't available in
		# busybox and some distro's pgrep (and it doesn't exit non-zero).
		count=$(pgrep -f "^sshd:.*@|^/usr/sbin/sshd -i" | wc -l) || return
	fi
	if [ $count -gt 0 ]; then
		color b w r; printf "%d" "$count"; color -; color w r; printf "%s" "$sign"; color --
	else
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/users"*
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/whoami000077500000000000000000000024121522352767600165150ustar00rootroot00000000000000#!/bin/sh -e
#
#    whoami: report current logged in user
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

___get_user() {
	if eval $BYOBU_TEST whoami >/dev/null 2>&1; then
		whoami
	elif eval $BYOBU_TEST id >/dev/null 2>&1; then
		id -un
	fi
}

__whoami_detail() {
	local user=$(___get_user)
	[ -n "$user" ] || return
	if eval $BYOBU_TEST getent >/dev/null 2>&1; then
		getent -- passwd "$user"
	else
		grep "^$user:" /etc/passwd
	fi
}

__whoami() {
	local user=$(___get_user)
	[ -n "$user" ] || return
	color bold2; printf "%s@" "$user"; color -
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/lib/byobu/wifi_quality000077500000000000000000000075431522352767600177510ustar00rootroot00000000000000#!/bin/sh -e
#
#    wifi_quality: display wifi signal quality
#
#    Copyright (C) 2008 Canonical Ltd.
#    Copyright (C) 2011-2014 Dustin Kirkland
#
#    Authors: Dustin Kirkland 
#
#    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, version 3 of the License.
#
#    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, see .

___get_dev_list() {
	if [ -n "$MONITORED_NETWORK" ]; then
		echo "$MONITORED_NETWORK"
	elif [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		# OpenBSD: list wireless interfaces by known driver prefixes.
		# Update this list when new wireless drivers are added to OpenBSD.
		# See: man 4 iwx, man 4 iwm, etc. in the OpenBSD kernel source.
		for _if in $(ifconfig 2>/dev/null | grep '^[a-z]' | cut -d: -f1); do
			case "$_if" in
				iwn*|iwm*|iwx*|athn*|ath*|rum*|run*|urtwn*|rtwn*) echo "$_if" ;;
			esac
		done
	else
		iw dev | grep Interface | cut -f2 -d\ 
	fi
}

__wifi_quality_detail() {
	if eval $BYOBU_TEST iw >/dev/null 2>&1; then
		local dev
		for dev in $(___get_dev_list); do
			iw dev "$dev" info
			iw dev "$dev" link
			echo
		done
	elif eval $BYOBU_TEST iwconfig >/dev/null 2>&1; then
		iwconfig 2>/dev/null
	fi
}

__wifi_quality() {
	local out bitrate quality
	# OpenBSD: parse ifconfig for signal strength
	if [ "$BYOBU_OSTYPE" = "OpenBSD" ]; then
		local dev sig
		for dev in $(___get_dev_list); do
			sig=$(ifconfig "$dev" 2>/dev/null | awk '/ [0-9-]+dBm/ { for(i=1;i<=NF;i++) if ($i ~ /dBm$/) { gsub(/dBm/,"",$i); print $i; exit } }')
			if [ -n "$sig" ]; then
				# Convert dBm to quality percentage
				quality=$(( (sig + 110) * 100 / 70 ))
				[ "$quality" -gt 100 ] && quality=100
				[ "$quality" -lt 0 ] && quality=0
				bitrate=$(ifconfig "$dev" 2>/dev/null | awk '/media:.*Mb/ { for(i=1;i<=NF;i++) if ($i ~ /Mb/) { gsub(/Mb.*/,"",$i); print $i; exit } }')
				[ -n "$bitrate" ] || bitrate=0
				break
			fi
		done
	fi
	if [ -z "$quality" ] && eval $BYOBU_TEST iwconfig >/dev/null 2>&1; then
		# iwconfig is expected to output lines like:
		#    Bit Rate=54 Mb/s   Tx-Power=15 dBm
		#    Link Quality=60/70  Signal level=-50 dBm
		# the awk below tokenizes the output and prints shell evalable results
		out=`iwconfig "$MONITORED_NETWORK" 2>/dev/null |
			awk '$0 ~ /[ ]*Link Quality./ {
			    sub(/.*=/,"",$2); split($2,a,"/");
			    printf "quality=%.0f\n", 100*a[1]/a[2] };
			    $0 ~ /[ ]*Bit Rate/ { sub(/.*[:=]/,"",$2); printf("bitrate=%.1f\n", $2+0); }
			    '`
		eval "$out"
	elif eval $BYOBU_TEST iw >/dev/null 2>&1; then
		local dev
		for dev in $(___get_dev_list); do
			# iw is expected to output lines like:
			#     signal: -50 dBm
			#     rx bitrate: 216.0 MBit/s MCS 13 40MHz
			# signal to quality: https://superuser.com/a/1360447
			out=`iw dev "$dev" link 2>/dev/null |
				awk '$0 ~ /^\s*signal:/ { a = 100 * ($2 + 110) / 70;
				    printf "quality=%.0f\n", (a > 100) ? 100 : ((a < 0) ? 0 : a); }
				    $0 ~ /^\s*rx bitrate:/ { printf "bitrate=%.1f\n", $3+0; }
				    '`
			eval "$out"
			[ -z "$bitrate" ] || [ -z "$quality" ] || break
		done
	fi
	[ -n "$bitrate" ] || bitrate=0
	[ -n "$quality" ] || quality=0
	if [ "$bitrate" -gt 0 ] && [ "$quality" -gt 0 ]; then
		printf "${ICON_WIFI}"; color b C k; printf "%s" "$bitrate"; color -; color C k; printf "%s" "$ICON_MBPS"; color -; color b C k; printf "%s" "$quality"; color -; color C k; printf "%s" "$PCT"; color --
	else
		rm -f "$BYOBU_RUN_DIR/status.$BYOBU_BACKEND/wifi_quality"*
	fi
}

# vi: syntax=sh ts=4 noexpandtab
byobu-7.15/usr/share/000077500000000000000000000000001522352767600145205ustar00rootroot00000000000000byobu-7.15/usr/share/appdata/000077500000000000000000000000001522352767600161325ustar00rootroot00000000000000byobu-7.15/usr/share/appdata/byobu.appdata.xml000066400000000000000000000027571522352767600214200ustar00rootroot00000000000000


 byobu.desktop
 GPL-3
 GPL-3
 Byobu
 Text window manager, shell multiplexer, integrated DevOps environment
 
  

Byobu is a GPLv3 open source text-based window manager and terminal multiplexer. It was originally designed to provide elegant enhancements to the otherwise functional, plain, practical GNU Screen, for the Ubuntu server distribution. Byobu now includes an enhanced profiles, convenient keybindings, configuration utilities, and toggle-able system status notifications for both the GNU Screen window manager and the more modern Tmux terminal multiplexer, and works on most Linux, BSD, and Mac distributions.

Using Byobu, you can quickly create and move between different windows over a single SSH connection or TTY terminal, split each of those windows into multiple panes, monitor dozens of important statistics about your system, detach and reattach to sessions later while your programs continue to run in the background.

https://byobu.org/img/screenshot.png https://byobu.org kirkland@byobu.org Byobu
byobu-7.15/usr/share/byobu/000077500000000000000000000000001522352767600156405ustar00rootroot00000000000000byobu-7.15/usr/share/byobu/desktop/000077500000000000000000000000001522352767600173115ustar00rootroot00000000000000byobu-7.15/usr/share/byobu/desktop/Makefile.am000066400000000000000000000001361522352767600213450ustar00rootroot00000000000000desktopdir = $(datadir)/@PACKAGE@/desktop dist_desktop_DATA = byobu.desktop byobu.desktop.old byobu-7.15/usr/share/byobu/desktop/byobu.desktop000066400000000000000000000005321522352767600220240ustar00rootroot00000000000000[Desktop Entry] Name=Byobu Terminal Comment=Advanced Command Line and Text Window Manager Icon=byobu Exec=gnome-terminal --app-id us.kirkland.terminals.byobu --class=us.kirkland.terminals.byobu -- byobu Type=Application Categories=GNOME;GTK;System;Utility;TerminalEmulator; StartupWMClass=us.kirkland.terminals.byobu X-GNOME-Gettext-Domain=byobu byobu-7.15/usr/share/byobu/desktop/byobu.desktop.old000066400000000000000000000003421522352767600226000ustar00rootroot00000000000000[Desktop Entry] Name=Byobu Terminal Comment=Advanced Command Line and Text Window Manager Icon=byobu Exec=env TERM=xterm-256color byobu Terminal=true Type=Application Categories=GNOME;GTK;Utility; X-GNOME-Gettext-Domain=byobu byobu-7.15/usr/share/byobu/keybindings/000077500000000000000000000000001522352767600201465ustar00rootroot00000000000000byobu-7.15/usr/share/byobu/keybindings/Makefile.am000066400000000000000000000003341522352767600222020ustar00rootroot00000000000000keybindingsdir = $(datadir)/@PACKAGE@/keybindings dist_keybindings_DATA = common f-keys f-keys.screen f-keys.screen.disable f-keys.tmux f-keys.tmux.disable mouse.tmux.disable mouse.tmux.enable none tmux-screen-keys.conf byobu-7.15/usr/share/byobu/keybindings/common000066400000000000000000000001761522352767600213650ustar00rootroot00000000000000source $BYOBU_PREFIX/share/byobu/keybindings/f-keys.screen.disable source $BYOBU_PREFIX/share/byobu/keybindings/f-keys.screen byobu-7.15/usr/share/byobu/keybindings/f-keys000066400000000000000000000000731522352767600212670ustar00rootroot00000000000000source $BYOBU_PREFIX/share/byobu/keybindings/f-keys.screen byobu-7.15/usr/share/byobu/keybindings/f-keys.screen000066400000000000000000000135111522352767600225460ustar00rootroot00000000000000############################################################################### # Byobu f-key keybindings # This configuration profile is intended to provide a useful # keybindings using the keyboard's f-keys # # Copyright (C) 2008-2014 Dustin Kirkland # Nick Barcet # # 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, version 3 of the License. # # 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, see . ############################################################################### # Byobu's escape key is ASCII Dec:94, Hex:5E, Oct:136, Char: ctrl-^ -- ctrl-caret # which is bound to F12 escape ^^^^ register x "^^" # | Goes with the F12 definition # F-keys seem to work well in both gnome-terminal and tty consoles bindkey -k k1 $BYOBU_BACKEND -t config 0 byobu-config # F1 | Configuration (along with F9) # | since F1 = Help in gnome-terminal bindkey "^[O1;2P" $BYOBU_BACKEND -t help 0 $BYOBU_PAGER $BYOBU_PREFIX/share/doc/byobu/help.screen.txt # shift-F1 | help bindkey -k k2 $BYOBU_BACKEND # F2 | Create new window bindkey "^[O1;5Q" eval 'split -v' 'focus down' 'next' 'focus up' 'layout save byobu' 'layout autosave' 'screen' # ctrl-F2 | vertical split bindkey "^[O1;2Q" eval 'split' 'focus down' 'next' 'focus up' 'layout save byobu' 'layout autosave' 'screen' # shift-F2 | horizontal split # No ctrl-shift-F2 (new session) in Screen bindkey -k k3 eval 'prev' 'fit' # F3 | Previous Window bindkey -k k4 eval 'next' 'fit' # F4 | Next Window bindkey "^[[1;3D" eval 'prev' 'fit' # alt-left | Previous Window bindkey "^[[1;3C" eval 'next' 'fit' # alt-right | Next Window # No alt-up (previous session) in Screen # No alt-down (next session) in Screen bindkey "^[O1;2R" focus up # shift-F3 | focus up bindkey "^[O1;2S" focus down # shift-F4 | focus down bindkey "^[[1;2A" focus up # shift-up | focus up bindkey "^[[1;2B" focus down # shift-up | focus down bindkey "^[[1;2D" focus up # shift-left | focus up bindkey "^[[1;2C" focus down # shift-right | focus down # No ctrl-shift-F3 (move pane) in Screen # No ctrl-shift-F4 (move pane) in Screen bindkey "^[[1;4A" resize +1 # shift-alt-up | resize +1 bindkey "^[[1;4B" resize -1 # shift-alt-down | resize -1 bindkey "^[[1;4D" resize -1 # shift-alt-left | resize -1 bindkey "^[[1;4C" resize +1 # shift-alt-right | resize +1 register r ":source $BYOBU_CONFIG_DIR/profile^M" # | Goes with F5 definition bindkey -k k5 eval 'process x' 'process r' # F5 | Reload profile bindkey "^[[15;5~" eval 'process x' 'process r' 'stuff ". $BYOBU_PREFIX/bin/byobu-reconnect-sockets^M"' # ctrl-F5 | reconnect gpg/ssh/x sockets bindkey "^[[15;6~" $BYOBU_BACKEND -t color 0 byobu-select-profile # ctrl-shift-F5 | choose a background color bindkey "^[[15;2~" only # shift-F5 | kill all splits bindkey "^[[31~" only # shift-F5 | kill all splits bindkey -k k6 detach # F6 | Detach from this session bindkey "^[[17;2~" eval 'exec touch $BYOBU_RUN_DIR/no-logout' 'detach' # shift-F6 | detach, but don't logout bindkey "^[[32~" eval 'exec touch $BYOBU_RUN_DIR/no-logout' 'detach' # shift-F6 | detach, but don't logout bindkey "^[[17;5~" remove # ctrl-F6 | kill this split # ctrl-F6 | sadly, does not work in tty :-( bindkey -k k7 copy # F7 | Enter copy/scrollback mode register p "^[[5~" bindkey "^[[5;3~" eval 'msgwait 0' 'msgminwait 0' 'copy' 'process p' 'msgwait 1' 'echo "Byobu scrollback mode (alt-pgup / alt-pgdown)"' # alt-pageup | scrollback register n "^[[6~" bindkey "^[[6;3~" eval 'msgwait 0' 'msgminwait 0' 'copy' 'process n' 'msgwait 1' 'echo "Byobu scrollback mode (alt-pgup / alt-pgdown)"' # alt-pagedn | scrollback register t "A^[OH^k^h" # | Goes with the F8 definition bindkey -k k8 eval 'process x' 'process t' # F8 | Re-title a window register u ":sessionname " # | Goes with the Ctrl-F8 definition bindkey "^[[19;5~" eval 'process x' 'process u' # Ctrl-F8 | Re-title a session # No alt-shift-F8 (restore layout) in Screen # No ctrl-shift-F8 (save layout) in Screen bindkey -k k9 $BYOBU_BACKEND -t config 0 byobu-config # F9 | Configuration register s "[g G$>^h" # Goes with Shift-F7 and F12 ~ definition bindkey "^[[18;2~" eval 'process x' 'process s' 'exec $BYOBU_SED_INLINE -e "/./,/^$/!d" $BYOBU_RUN_DIR/printscreen' '$BYOBU_BACKEND -t PRINTSCREEN $BYOBU_EDITOR $BYOBU_RUN_DIR/printscreen' # Shift-F7 | write the buffer to file, open in a new window # F10 | 'toolbar' in gnome-terminal # F11 | 'Full Screen' in gnome-terminal # No alt-F11 (break pane) in Screen # No ctrl-F11 (join pane) in Screen # No shift-F11 (join pane) in Screen bindkey -k F2 process x # F12 | Byobu's escape key bind $ $BYOBU_BACKEND -t status 0 byobu-status-detail # F12 $ | show detailed status bind @ $BYOBU_BACKEND -t config 0 byobu-config # F12 @ | Configuration bind R process r # F12 R | Reload profile bind ~ eval 'process x' 'process s' 'exec $BYOBU_SED_INLINE -e "/./,/^$/!d" $BYOBU_RUN_DIR/printscreen' '$BYOBU_BACKEND -t PRINTSCREEN $BYOBU_EDITOR $BYOBU_RUN_DIR/printscreen' # F12 ~ | write the buffer to file, open in a new window register d ":source $BYOBU_PREFIX/share/byobu/keybindings/f-keys.screen.disable^M" bind ! eval 'process x' 'process d' 'backtick 111 9999999 9999999 byobu-status menu --disable-f-keys' # F12 ! | toggle on/off f-keys bindkey "^A" $BYOBU_BACKEND -t ctrl-a byobu-ctrl-a byobu-7.15/usr/share/byobu/keybindings/f-keys.screen.disable000066400000000000000000000052061522352767600241520ustar00rootroot00000000000000############################################################################### # Disable Byobu's f-key keybindings, define a set using Screen's escape # sequence. # # Copyright (C) 2009-2014 Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### # This file disables the f-key bindings, but retains the # keybindings that use Screen's built-in escape sequence # Default Screen escape escape ^Aa register x "^A" # Use the following sequences for byobu functionality # SEQUENCE ACTION F-Key equivalent # ctrl-a-c Create a new window F2 # ctrl-a-p Previous window F3 # ctrl-a-n Next window F4 # ctrl-a-R Reload profile F5 register r ":source $BYOBU_CONFIG_DIR/profile^M" bind R eval 'process x' 'process r' # ctrl-a-d Detach from this session F6 # ctrl-a-[ Enter copy/scrollback mode F7 # ctrl-a-A Re-title a window F8 # ctrl-a-@ Configuration F9 bind @ $BYOBU_BACKEND -t config 0 byobu-config # ctrl-a-$ Show detailed status bind $ $BYOBU_BACKEND -t status 0 byobu-status-detail # ctrl-a-! Toggle f-key keybindings on register e ":source $BYOBU_PREFIX/share/byobu/keybindings/f-keys.screen^M" bind ! eval 'process x' 'process e' 'backtick 111 9999999 9999999 byobu-status menu' # Disable the f-key bindings bindkey -k k1 bindkey "^[O1;2P" bindkey -k k2 bindkey "^[O1;5Q" bindkey "^[O1;2Q" bindkey -k k3 bindkey -k k4 bindkey "^[[1;3D" bindkey "^[[1;3C" bindkey "^[O1;2R" bindkey "^[O1;2S" bindkey "^[[1;2A" bindkey "^[[1;2B" bindkey "^[[1;2D" bindkey "^[[1;2C" bindkey "^[[1;4A" bindkey "^[[1;4B" bindkey "^[[1;4D" bindkey "^[[1;4C" bindkey -k k5 bindkey "^[[15;5~" bindkey "^[[15;6~" bindkey "^[[15;2~" bindkey "^[[31~" bindkey -k k6 bindkey "^[[17;2~" bindkey "^[[32~" bindkey "^[[17;5~" bindkey -k k7 bindkey "^[[18;2~" bindkey "^[[5;3~" bindkey "^[[6;3~" bindkey -k k8 bindkey "^[[19;5~" bindkey -k k9 bindkey -k F2 byobu-7.15/usr/share/byobu/keybindings/f-keys.tmux000066400000000000000000000112201522352767600222570ustar00rootroot00000000000000############################################################################### # byobu's tmux f-key keybindings # # Copyright (C) 2011-2024 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### # Add F12 to the prefix list set -g prefix F12 # Clear the slate source $BYOBU_PREFIX/share/byobu/keybindings/f-keys.tmux.disable # Byobu's Keybindings # Documented in: $BYOBU_PREFIX/share/doc/byobu/help.tmux.txt bind-key -n F1 new-window -n help "sh -c 'LESS=\"\" $BYOBU_PAGER $BYOBU_PREFIX/share/doc/byobu/help.tmux.txt'" bind-key -n S-F1 new-window -n help "sh -c 'LESS=\"\" $BYOBU_PAGER $BYOBU_PREFIX/share/doc/byobu/help.tmux.txt'" bind-key -n F2 new-window -c "#{pane_current_path}" bind-key -n C-F2 display-panes \; split-window -h -c "#{pane_current_path}" bind-key -n S-F2 display-panes \; split-window -v -c "#{pane_current_path}" bind-key -n C-S-F2 new-session bind-key -n F3 previous-window bind-key -n F4 next-window bind-key -n M-Left previous-window bind-key -n M-Right next-window bind-key -n M-Up switch-client -p bind-key -n M-Down switch-client -n bind-key -n S-F3 display-panes \; select-pane -t :.- bind-key -n S-F4 display-panes \; select-pane -t :.+ bind-key -n S-Up display-panes \; select-pane -U bind-key -n S-Down display-panes \; select-pane -D bind-key -n S-Left display-panes \; select-pane -L bind-key -n S-Right display-panes \; select-pane -R bind-key -n C-F3 display-panes \; swap-pane -s :. -t :.- \; select-pane -t :.- bind-key -n C-F4 display-panes \; swap-pane -s :. -t :.+ \; select-pane -t :.+ bind-key -n C-S-F3 swap-window -t :-1 -d bind-key -n C-S-F4 swap-window -t :+1 -d bind-key -n M-S-Up resize-pane -U bind-key -n M-S-Down resize-pane -D bind-key -n M-S-Left resize-pane -L bind-key -n M-S-Right resize-pane -R bind-key -n F5 source $BYOBU_PREFIX/share/byobu/profiles/tmuxrc bind-key -n M-F5 run-shell '$BYOBU_PREFIX/lib/byobu/include/toggle-utf8' \; source $BYOBU_PREFIX/share/byobu/profiles/tmuxrc bind-key -n S-F5 new-window "$BYOBU_PREFIX/lib/byobu/include/cycle-status" \; source $BYOBU_PREFIX/share/byobu/profiles/tmuxrc bind-key -n C-F5 send-keys ". $BYOBU_PREFIX/bin/byobu-reconnect-sockets" \; send-keys Enter bind-key -n C-S-F5 new-window -d "byobu-select-profile -r" bind-key -n F6 detach bind-key -n M-F6 run-shell '$BYOBU_PREFIX/lib/byobu/include/tmux-detach-all-but-current-client' bind-key -n S-F6 run-shell 'exec touch $BYOBU_RUN_DIR/no-logout' \; detach bind-key -n C-F6 kill-pane bind-key -n F7 copy-mode bind-key -n S-F7 capture-pane -S -32768 \; save-buffer "$BYOBU_RUN_DIR/printscreen" \; delete-buffer \; new-window -n "PRINTSCREEN" "$BYOBU_EDITOR $BYOBU_RUN_DIR/printscreen" bind-key -n M-NPage copy-mode \; send-keys NPage bind-key -n M-PPage copy-mode \; send-keys PPage bind-key -n F8 command-prompt -p "(rename-window) " "rename-window \"%%\"" bind-key -n C-F8 command-prompt -p "(rename-session) " "rename-session \"%%\"" bind-key -n S-F8 next-layout bind-key -n M-S-F8 new-window "byobu-layout restore; clear; $SHELL" bind-key -n C-S-F8 command-prompt -p "Save byobu layout as:" "set-buffer \"%%\" ; run-shell \"byobu-layout save\"" bind-key -n F9 new-window -n config byobu-config bind-key -n S-F9 command-prompt -p "Send command to all panes:" "set-buffer \"%%\" ; run-shell \"$BYOBU_PREFIX/lib/byobu/include/tmux-send-command-to-all-panes\"" bind-key -n C-F9 command-prompt -p "Send command to all windows:" "set-buffer \"%%\" ; run-shell \"$BYOBU_PREFIX/lib/byobu/include/tmux-send-command-to-all-windows\"" bind-key -n M-F9 display-panes \; setw synchronize-panes bind-key -n M-F11 break-pane bind-key -n C-F11 join-pane -h -s :. -t :-1 bind-key -n S-F11 resize-pane -Z bind-key -n S-F12 source $BYOBU_PREFIX/share/byobu/keybindings/f-keys.tmux.disable \; display-message "Byobu F-keys: DISABLED" bind-key -n C-S-F12 new-window $BYOBU_PREFIX/lib/byobu/include/mondrian bind-key -n M-F12 source $BYOBU_PREFIX/share/byobu/keybindings/mouse.tmux.enable bind-key -n M-IC paste-buffer bind-key -n C-a new-window -n "ctrl-a" "byobu-ctrl-a" byobu-7.15/usr/share/byobu/keybindings/f-keys.tmux.disable000066400000000000000000000045211522352767600236670ustar00rootroot00000000000000############################################################################### # disable byobu's tmux f-key keybindings # # Copyright (C) 2011-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### # Undo Byobu's Keybindings unbind-key -n F1 unbind-key -n S-F1 unbind-key -n F2 unbind-key -n C-F2 unbind-key -n S-F2 unbind-key -n C-S-F2 unbind-key -n F3 unbind-key -n F4 unbind-key -n C-Up unbind-key -n C-Down unbind-key -n C-Left unbind-key -n C-Right unbind-key -n C-S-Left unbind-key -n C-S-Right unbind-key -n C-S-Up unbind-key -n C-S-Down unbind-key -n S-F3 unbind-key -n S-F4 unbind-key -n S-Up unbind-key -n S-Down unbind-key -n S-Left unbind-key -n S-Right unbind-key -n C-F3 unbind-key -n C-F4 unbind-key -n C-S-F3 unbind-key -n C-S-F4 unbind-key -n M-Up unbind-key -n M-Down unbind-key -n M-Left unbind-key -n M-Right unbind-key -n S-M-Up unbind-key -n S-M-Down unbind-key -n S-M-Left unbind-key -n S-M-Right unbind-key -n F5 unbind-key -n M-F5 unbind-key -n S-F5 unbind-key -n C-F5 unbind-key -n C-S-F5 unbind-key -n F6 unbind-key -n M-F6 unbind-key -n S-F6 unbind-key -n C-F6 unbind-key -n F7 unbind-key -n S-F7 unbind-key -n M-NPage unbind-key -n M-PPage unbind-key -n F8 unbind-key -n C-F8 unbind-key -n C-S-F8 unbind-key -n M-S-F8 unbind-key -n S-F8 unbind-key -n F9 unbind-key -n M-F9 unbind-key -n S-F9 unbind-key -n C-F9 unbind-key -n M-F11 unbind-key -n C-F11 unbind-key -n S-F11 bind-key -n S-F12 source $BYOBU_PREFIX/share/byobu/keybindings/f-keys.tmux \; source $BYOBU_CONFIG_DIR/keybindings.tmux \; display-message "Byobu F-keys: ENABLED" unbind-key -n M-F12 unbind-key -n C-S-F12 unbind-key -n M-IC unbind-key -n C-a byobu-7.15/usr/share/byobu/keybindings/mouse.tmux.disable000066400000000000000000000004211522352767600236140ustar00rootroot00000000000000set -g mouse on run-shell 'sed -i "/^set -g mouse /d" "$BYOBU_CONFIG_DIR/.tmux.conf" 2>/dev/null; printf "set -g mouse on\n" >> "$BYOBU_CONFIG_DIR/.tmux.conf"' bind-key -n M-F12 source $BYOBU_PREFIX/share/byobu/keybindings/mouse.tmux.enable \; display-message "Mouse: OFF" byobu-7.15/usr/share/byobu/keybindings/mouse.tmux.enable000066400000000000000000000004231522352767600234410ustar00rootroot00000000000000set -g mouse off run-shell 'sed -i "/^set -g mouse /d" "$BYOBU_CONFIG_DIR/.tmux.conf" 2>/dev/null; printf "set -g mouse off\n" >> "$BYOBU_CONFIG_DIR/.tmux.conf"' bind-key -n M-F12 source $BYOBU_PREFIX/share/byobu/keybindings/mouse.tmux.disable \; display-message "Mouse: ON" byobu-7.15/usr/share/byobu/keybindings/none000066400000000000000000000000771522352767600210340ustar00rootroot00000000000000# This is intended to be a completely empty set of keybindings byobu-7.15/usr/share/byobu/keybindings/tmux-screen-keys.conf000066400000000000000000000035131522352767600242420ustar00rootroot00000000000000# tmux-screen-keys.conf # # By Nicholas Marriott. Public domain. # Updated by Dustin Kirkland. # # This configuration file binds many of the common GNU screen key bindings to # appropriate tmux key bindings. Note that for some key bindings there is no # tmux analogue and also that this set omits binding some commands available in # tmux but not in screen. # # Note this is only a selection of key bindings and they are in addition to the # normal tmux key bindings. This is intended as an example not as to be used # as-is. # Set the prefix to ^A. unbind C-b set -g prefix ^A bind a send-prefix # Bind appropriate commands similar to screen. # lockscreen ^X x unbind ^X bind ^X lock-server unbind x bind x lock-server # screen ^C c unbind ^C bind ^C new-window -c "#{pane_current_path}" unbind c bind c new-window -c "#{pane_current_path}" # detach ^D d unbind ^D bind ^D detach # displays * unbind * bind * list-clients # next ^@ ^N sp n unbind ^@ bind ^@ next-window unbind ^N bind ^N next-window unbind " " bind " " next-window unbind n bind n next-window # title A unbind A bind A command-prompt "rename-window %%" # other ^A unbind ^A bind ^A last-window # prev ^H ^P p ^? unbind ^H bind ^H previous-window unbind ^P bind ^P previous-window unbind p bind p previous-window unbind BSpace bind BSpace previous-window # windows ^W w unbind ^W bind ^W list-windows unbind w bind w list-windows # quit \ unbind '\' bind '\' confirm-before "kill-server" # kill K k unbind K bind K confirm-before "kill-window" unbind k bind k confirm-before "kill-window" # redisplay ^L l unbind ^L bind ^L refresh-client unbind l bind l refresh-client # split -v | unbind | bind | split-window -c "#{pane_current_path}" # :kB: focus up unbind Tab bind Tab select-pane -t:.+ unbind BTab bind BTab select-pane -t:.- # " windowlist -b unbind '"' bind '"' choose-window byobu-7.15/usr/share/byobu/pixmaps/000077500000000000000000000000001522352767600173215ustar00rootroot00000000000000byobu-7.15/usr/share/byobu/pixmaps/Makefile.am000066400000000000000000000006371522352767600213630ustar00rootroot00000000000000pixmapsdir = $(datadir)/@PACKAGE@/pixmaps dist_pixmaps_DATA = \ byobu.14.png \ byobu.192.png \ byobu.64.png \ byobu_backup.svg \ byobu-banner.svg \ byobu.png \ byobu.svg byobu-7.15/usr/share/byobu/pixmaps/byobu-banner.svg000066400000000000000000001203701522352767600224300ustar00rootroot00000000000000 image/svg+xml Byobu byobu-7.15/usr/share/byobu/pixmaps/byobu.14.png000066400000000000000000000014521522352767600213740ustar00rootroot00000000000000PNG  IHDRH-sBIT|d pHYsjitEXtSoftwarewww.inkscape.org<IDAT(UIhq$&NڪcjikhzpT/='Aŋŋ^TPqiӌӘK&4σS?(YxHjD3 R"m//K Ba :3ytlWa5Ur'wN9qH\\., &a=,l˿Gct  %Ih L`Q.`Zup}ɢ6_CD$:ևtv9#EV2"rΙڣ;c&$t@ˉ ltaq8k͹6&.2v^ށ֌w# VUKE*d{+E,vaw1#=X(GJ,$bnoi>\Prw‘I^f+sJ R-mFb~3DR01[VChbEniO0L ua@f8WoK!-cU]y9Y2WF/G"钒 ӳN[o3ˁ[PdI9st<=_ʦٷ3 )hwsswG uj8[vbUԾ]5OIENDB`byobu-7.15/usr/share/byobu/pixmaps/byobu.192.png000066400000000000000000000522071522352767600214670ustar00rootroot00000000000000PNG  IHDRRlsBIT|d pHYs s s=tEXtSoftwarewww.inkscape.org< IDATxwx?ۓ{B] (bX~UŎ"( HC@'nؐ%m7`<BU’ ʫ))a”UQZQMIi%EUTQvF@< ig&@W*SK J+/lJ7.,CܑaFNmNdccOQ@/@ž  hAQa&B G, pP,#,؏`vSSY’ ~+),.'j"R^ĀLTpI #%4!_Za6q ˪6]MhsX7`" s. &"؈0b#C #6"@$bkkh'i8;yE6QTRAIYeՔUQTRAiE}oR,O7n Dð>ۨSXZINQ9_RA~I%y%c.֖H.C Gld(Fa" dRiwqLE!pU8p&&"JBRvmF#>,S$%.,˫),"J+kz6L*^1ޑĄ4|1!8;ٝyt j,L,Bݕ6冟bC(,j &INQ*; Z {xI Ea8oڂ9Cl  ˑJĄxm]umE7!E-˹bJ+kZ-kخ\غ8 B-Eu}Xg)L`?[kqӝ {0`ŖdMQl'@[)_GZ)/Mi7&#ך>zZӿwY4J :=̞G l{:Zkjssh[OY×Pq{q2@[Df[h>h* ӎpvOKU d/#9@"4Վu n!sK2@G6YW"V8>`..2KR"C!qUpߩ/@"'bt5sQ;v]\W 0{vpH~k >DB't)slb Ns;Ҵ Q |ߍ`_]s%)5'wU2oZ>p [ #I8Az:'ŒؐԅhJ*lWF問aI cDV11P {XծL̢j~NEcǞ Ga^2Y`|O?S Թ}ղU,KޘTJP^}nd2 ǖav%:vA @=?%tB'߱FsE33`OuSѫ6:ef^\xQx~Wu9B_ΑqU-9R23: dBp'ՠFd!r7wA @iG¢r^tL5g9׬m-S9zKX֝pX9E~]j ["_`l'l ybaCF|F f _7ô+iRӳy?R<΃I|76G^'cj@=v?s^Jp% YsF=ID]D•3zJ$?[;<ߑJ2L^=LwKBk~b{iB+̿_8m;DMTJq^w5Dn nK-FScTvpهmPSqv=&c <mBȼ</] ى;h[_QEQD2󒏨13`d[t2 ™ %Lǟ[+xrobK9l}%_P"lN!.eZL[ '/wz;LBpTkms~*1vT w6T$>Clwalf7&gލ3b ?3o҃8_0ǻ| a'{lyĆq0|]k"~h&Hg3ΈW6+u/70^a'nnn ?kMުhkun 6m-8fGLU9agNJNU^0n1Z^+tr-6Oa8uʺ+PYV4ACSZi`Z.   |z."')%t">j/%n fCQX^"~K*VGc߱<;T99klU%.r 6 -W}lso'Ɉdj@F9)#)(\DvIzY)95:FR7<#ȼ<w^ڇ^Sω7?be+-v ns]}vMxe笎=`-m*bnCǾ;_fuLVdϭQ=chN$2[ɫCdF"< j{EhUTcl8^LX3xOmk5:5"E?:٫66.=aP9&wh_KFƤ_L*hξʫÜ| u-B &nfU%cOkMt v|q+ǽrЎSJ-`Wj*%nė1|dtngK:Js;RFY.F]Rg2Tg ЩH |.?KkkuG#9"yq\0)*i2vNh0LqX#H^m C/}޳z?w!/PVIzBU^ĆwFk~rܚl*?b't4<֊)ilVWy9̜<^cNRe2 ]tuW\ \ΦrzOkR[wfOo Ex},jj)+",HDdmˏb"J,5Ԛz&;r,.gEm |H%0ov3MK38[pyšVEkG# hEH"$"$ZNz)n r ^P/`W`2jg-2j2 J8|ʫiPF?;;m.@$ [']Du2(>5E9rH?F[+k(*Gz/ hR[ sl{J$b$F1b9 $jEj*B5R bZXVb.N\w~o=a!6aTTԐGZNi99WPUBC|q9*jhlP~AW&㧵1Φ=Ң?NjW\\r0*Jzj*5zZ"7 zFȵiUtǒOh xQ1neIHxM@(07s3TJg4#EH"{nFRUQJ*jEY[֠C̫.ˣlֺP=t FwsֵRY5*zg&pپh@#wo*!.:b_z18b5J\kv&=%S5 瀶i1D"ZiZ9F#Á"PAQ{)ͳ)FuR*k=p8 W&uwat-;a4ٟȹӭ/1NHyA@L @"wFfȐH bd1"^B#HbD"@Ӱ' 5 8PξOәڧs'Ҟ\T1&oP^fH`Ĝ_? ME%N>^@(t8LR"#20 Zei.غR)_y[ٟ%Q F;v:&Y'Jڅ  TNHq}B &_om@,"r "v,: G䄳T3Nr1 RX\T,6wYД*5_Ύ3 Jee.90b(׏"J*(6U?T0w68xӟNdޫ^DՒlUg˝9WTK$"D8@}U _@Wk29"^gʊI:pU4Oݨm}ɤ*3f@Syi}y Mʳ1%eҿ_A^B+H 09mn$fDlO Luv@հ 3޼ԿꘜV_Y鷖Pv4a$>/Nd t<=\x_QTV'k7r %'Le Sԅ9:ԗC8@g@I`)i{%F3y _޽N5Ifs$4ή+1gg Fk@E%HyW2@eZwŜ"4kxf>CS ;zɰ`lyfM%ïhSDBn6Y^fP{|t@K**kxc8,Sy Y}5| ];K{uyK\q:]AkTsx-&.a]ˢ— >kG K&s+ΓeJY:yynxU#Y'ְ':~݇@$yEv޾ nIe&HkÍ_ _ C~hN5~;H|[Mf_kRӰRs Cke.qITi2-Sѷ1UΣ6qtu $ pC":^V9ʲ}8dd ZD)hZY5 YQȉة̿ż2-:} WC+gh'6n!oB+*m"IcZb4֦ !zhEx}tN˟|JnRۧ[wmOOz {c45gΞåߑyHg_@[4F#ڪj j ^}?oWa05]{uhO9 ɸŅslP++D8A~а絛%iR~0I`)j;y2;wLT"f1̹b?nÆS'>G9T~MO2c@\Q,kZ}+]߿FSj~ޟnbUI.4l;?~4jg8v z;b%6^3? c^X5G=*\'DfܙSC },^C,8@l[+>r] q:a%N@B>x%F0o,2+=j(s Nee#E|Q*oRW&B֯Vwc?e.5L;;nQm ]-N?cIv%ScH"zO%10cWPu,nqQ11%jBR%cwmcu%X]Zi~hD]ZK?}- g IDAT*P̙! !WsxדWR?q0ihߑNEGطރ@RV^-bUT2 3㵻o}u.p4y)1%+ g&GoKXJg! J3E,5.&wVK*/]t7g8yR#cu)s @rڙ$O|ծkyb4$Xv,s}=ywޭex:V*P@74bBL<;=Ahdἳq"Bj}&t&?j!8q5:&Auy6]31 KQ+[>/F/ d7/-KEt#. P9M)6FC$[LVV 4R㢦EMAC,H/lm 7g)=`>.,EAF%=\)k;WٌLCDB33{?4!z %-ɺXf S4:u:&"0-tjjx/H/oY`0r,9McߥhI^u zN<'ow?f2xrsDPTkPJɪ)VPVZeS\2Eդ|ksg_1/wc:qӤ E$6(u\[2<}c.dJ*#Is@/2ǣZD&$އn٩KGx&\BbBK)w}_|*g(o=>̍ ?8?<)EEJ&58A8sAԕV qR!"6=V3-DPEU~\[w,ZM2.R>3WLH}iSi xo8>ˁ4ꥦ'WWЇx!;>^[(k-Pa9 {rv'mS̒?;גvNpW/sap>ݺ P;iYp:;GfM -7`ȱLz0y -xخj ?]#S^Hx;+C֪Xl?޸-^Dd&5 ؓTdrU6h*j87\ LHl?/ ')wW#2j2,;hg5΢?47C&wUP>EAI,0 / bpu,ͺqÆv=Gx&UnD*yyCN]{ V`x'KW#r2 |nv9Nϙ|)7nMd"]*澄~_HH.D+JdΕn$DpUbGq6[bLxћ- */H]$p;-v#P7TbU2P"hX}5n\?c>AlH8Z }Y4q"B;'q0#QzVD^⣚4< 3+Y!.tTOrf0 I;JOc@(k'ڄ hd:JXJ}Phz4# ڤ}Ip,cUuj^s#~E%:2yÏi2 ЩԈNx{I?wc;!k(~nFF;n{u6(l}wPF пw1*S!b*;kLW_3JEDװ -cgx;-y ]m0Њ!1#2e"Hᾓ $xą~Sv|n^~U89"Pi-2x;U*I3/qB=ZM/#h%z *K16 s;L#Kt"e'25r?<צbZl8,$ד o›:tY?2){ 6}l>CQF]/@{," ! h;E\kRZGS%Y6+֓Ք.̓qxi=;2İPZ(S*u I'r23goޮ3مe,ݹYv'-CkLq`af'\I' ֭0"fbp[pvXH4tCjD{bX(>[{U?, >-cѝ7ZQx%KXLz5B(1GzO> D )aOqnn|2%/6ʾXSVa|1yv㋇͟d} F#˻Ry _7=OJr^Kk{D-p $-vC`(VZJxul=Q`2Mk.:mӣw)\rbzlNVaUQj3P Wq7U&֋UH\u ãcy1癏o@z LʢTxԒ('=3uj5O.k#kH{>:+W)%ƺ0-W$1,Wb])mdžI:1( ̝AD:p˘ Y4O%װa^ugpaDHS#1ۻ8c'qرŠ7PmcZa|<26y"ӧ*7jPWJʇ~P<]eqQv3(,U$D0p 7_a,ն---@"/w>[p'~]Úc;п"@nz4}ڑ~wW˨mp.dx7Y6}; X;B@6ldeR4> iCyGۻB8pr EpL@3ypb",|2os 1 J~A {i<2O?~MlE1_o}MiYCx'qu;^tB$8bcڰ\;jP*-MD jV$=rӮ`lךd1x|^7oDY.텮-tRu;s&O]/&`"?cr)3:2:S%Fg%0_d=l}kW ߗ!zDϚC~;rB'@4>w,bjU `!+\})^C/2.(Z<#^߯ͤ.@qО;~En(WusX?C Fqi936G'a5>3/!);\vVTKtw_dNX*ԒYē.Aj O-"?Nt-PGj@tm A5Ҧr}X&#oβ5}FPtWq0sb&]c =r (;@{>L>텭IWS Vj"W/Ni iڶ)YᷛoFAQIkVm֭KX( tYn@WW>@Sw}}ctFBDaY޿6I=V14tT w,A;6dsw["ObsgM!#n?~fSFϤzc5>@{;=`>g]Ƙ$ B51\]ˁXx-vi/z!̎%[BWnjO_6ƨ7LS8goX[9oa㘻06GKv)@58AqA15d2& A`fnsw_}}9j9Л Mf?v*,h,V̸vsٚ Gi,3^T_mע 귾NÙEZhŨ7tXd D3z905vz#Kє<9^puQ02?U{ $funO:}z^TMq9ʌ@ERlc'9N?rB u=?L=rR悰,6+~BCT>@(k`>]|g49pepth^ HTUS/2Ł'm BaED@nϝű3LN[E"֩ԜW3IYcEߎ l̨^3gs,| %b{>_.[Żۗz\D[m^v em?D+8tF/}ܣ7H$zR9JMwN{h"Bm>/bO(ʌoj4RvVpXf8] ̹Kaґ?˗Ͻ{w=/c~}@(ZdQrL.^}iD;qώ[Gtl ԃ92E/C1%tVgrw[#kr Yⳇ\o;%Hʹmhgi[vkzB̾EMeM~,҇Rx/XqXRa<l"]6 #![/7_#. PO}_#g0KSկW$::Q\ϩ;u^i.5GLtQ-cW# ~5oWYG"'Y6ǖh$lvu| w q `çq\t\ -Ps=s6Iep8$ge6a,G?=9ۘa83\ܣy-)?rfZO›J>OfނUC;5 :8g8j( {;+؎~# w}"Tq"楇@,bz*qSy6 %{CʡUdO`Ezv}KkkTH&bʼn}mNr*0~g+x{vh. U_(^z1S2us3ocۈ[&`pj pK@jh4)t1_Ⱦ j[$bި ˬv>bRH5ihd\B#e5K;AW{RRgƒXvUCiVJ́DGt߶j4{߮Z),Tڒ:=r$.m aOmPj v_Ne랙xmVJ]Om: JZjUJ%J*U*UuQC.  ~$%_~T~Znx[+Vl"(Jw.[܇uOk09@3Cxaڟsnf*R2ѩԸq8t<%SSRSӂuj4Z-ZOGgԣшuԉQQ zb=ZA#H.hָvU,߱s~PUs,g4Wmdvƥ4O(j wuȶ}i&N*9^DGE.Uټ#/2P[AS\/Vb3cEDٛt(7ӕ]4pu\j&bVIJEREM :=FԀFVA)PXׂuBrt,۝JL:}g.3xMut˒ce^\Fuayd *j0ٲI,NE |yr ccQvEoMi%).e'n9>}Oq6p=J +pW -B$:bVBJ**#@U|j%{S ln>޳NE,n듵/D" g4fMn`0i!~ٰ.kA $н5ɆϵMm=S#B'ÉvQUUD'BjtBn!IH "D!B@D(Y*A!wO^. ]K3CpUKz68s#E8zE h0Ry?rg}I[-.zj.F9ևl0huI&3'oFũ!p"&8!$,M.C .&•L,Ya|uDm7Ԣiq>5#{߶`0y߭4qGϣi;% )!L՛t 4r5܈kzǖl>a9/n.rtznϊ;H -*U@?H|h&TfrwNiZp|Fcpe/RWLtTyH<\q s@|drz,~1P*hl(;1:A^12K[sq+''Pt@m ZuqD`VƉeBgl%;1GT24x`xV h_s&Ϳ,bDtz69²[HrL@(#-n$|0i6s3աg魷Nq}҂vkx^G]dߋ2DkD07\E؁Lb|u;UΣOoJۨQl:=Qs`lF0>U('7LXpӻo,;kQ*LۣRr?̞IDATb[V}5H  E"Dwdmp$%&%81$^<,̷ORPq)T5[Q@XCbg0se9pl%ۧT0j9i^1,s a!uU<E&Bhbh"^Ǧݬ޵9Wh301yE0xV)Yҋ>^ǕLcr?xy&8_@͜]רtջ3&m͢_! 0o >`ӿvr0 ~wcnʸՋ)DiM{z]Ð}Fѹ7*` ghDD"aE\`C(] dQĎļP~;۶r*=>E>Z6^QlXil޽Y)rܱd$=:3Lz["RM;P2h9`6~b c昉C}Р@V/xڽrmR q/*?jr;Ʈ*1wQsOrK7~NxMd?s{cu㓸h:;$$-w3Gn~>Ζq@`X( KU8v"]t- \{wLxaZ fR;@B}9z2>UwgIcHѧ+;kZS{$K]_V0ϗEsa[uCaAlviϢg;iRLK1@Ĵ> FB&ۋ v:γ?s<8@g37WWtV7~s-4FweÒLR?Of{v=Gu(T="c̩o'DQ F0zNOCHE=eHM#L&W>V"qbY4~5^Lpns).;?xR&~lXt(茾//-Ey:p< bM%&1/{9qbR+8*)cΞI`V F0>=q 4m+qsw!Wt79\̬ J$LjOٜ9K{^ʋUl?7'P(X2 dW"F0k'FLѸk3!U/q 3'Ϭo2̩$L ]s^zuբ=kc},]5Ak7xGtO~`#KKeɼ~zt5,6~̯d 3MFXScnl!:t` CkOv,@%>qj[`sOp̀|[ xkkAz#(QTΑkhOq?1s3̒>MÉk bG!$;_opU :SP{h\=6á< eݻq=G]Mmt:;6mYvkl8tkG9v/053=˟VC߶Weh|wNY6>Zďp_9`lh@OpkCAp}899hdȻ}q,74Ÿo~Mhd;TV9w/9HqC/7#}EoN:|ѠfAm_4ܿFW4 N+vOp#QrIV -K,[%Y{:xDs3ܲYJHPw>_8׵g"*ua \VΝU9X26KZ'rr )sȐ+˹/F۸ /_嚁G#CB OxyJYl>+2/r2|B+g_HEKX4u2c";vd*4f)HV!VeJrTb깜tIwvBdhjmhx Tzb\DŠ3g8LC.%yҿ¹fk[ nY*$5`ujY NBEBً׌U GdA .~̙2sl pX)O)zDǨrT 1Pu(UYRG֡TPhty/lRL`ئIK>kT,nH8|gr{SeȑQ)z:T06ML[&m ְZsR:I[F=g5NGx֤sU$*$4D}$4CqVe-+T4tǠVZ+}R6ڍ:ȶe6k^̭2 <[ՠz[OՎ;vرcǎ;vi?;]2IENDB`byobu-7.15/usr/share/byobu/pixmaps/byobu.64.png000066400000000000000000000127271522352767600214100ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|d pHYs&&otEXtSoftwarewww.inkscape.org<TIDATxy|TUǿow$aBddD@EGYF@fEe "* (He' Ⱦl$=黼?:I'!2'=UuT!op:]-AXu= %x(&XeCUU=VAZP"+,zfg/s@hʵZ1G,I3?2\H&@A ^QMHR/w96>.ڭ]L[>+LьXhXPDnI/ &Ph.ʊ 0FDQ,A/o<L܎;zw pG_@/bEESh!"TUN/JUUnnrld>.F.&RnC|Lb" mTOrFOo7=tcA1ɌTDބTı34Pn/hE aD;;zBV)0`glg2 K 1Ubt1B|t$1GGЦu+& mZ—m6X`u*(j^Ec>@|Sʡ/ݚ0nF)sxj$`_j Pȸafрʁ92 $FmL@V{h5ThpMP\YEcĆF丁o\dtdYF@me@3kU54/,_˩96z>b>"n ґ$ @@v)-yݥ8I He dA@Og (ͩG3cOl ;On0{#I2BC@p,scnyu6vH̊ї&ySofr' 5AjuNc~]!& odp?c)*p"vbJoS;Cm'XXŤ#j>0/v'= I4@@J{)3j-|u7w#ПK%]ֆi=I֞C}ȕUh=yo5PsyOՕG5 ٮ&P-\ݼ.ѳ*s QDTUE@;" .zK"gD& &߬bf ګ^1FTwpJ lMgk,/Uf,zEӚ4h6M~)]Ξg=Mc()`ـitkۮs /̯2,}~-I28@E Q$͙@y;١:TaG9Hg L/B3^ j\VJN=ПJ"\p+RHU 8 apm_LP:t.=o`gB__CR zSy\5 hˑti9z`}UVx?}BZt~UY9~PZQ̭ 3!^A9b>o0˲švs0/2=R>a2"sU NM΃/0wonhvCtvu99*VZR'+#Q%eJTL_RR{ZQ΃cwK'+8dfΔ]cj<ՇHtKU32Ч}$IU^+4ȡr,`o'`™<6 I& ٛYr`szMĴTш"ퟟV,ťT)\^㽛;Ӿ|lRN3x@Qj٦re{ڻ3?xLT{Qab^ЍO>!5= Κ.dUOBΝ_VX?~S>yG׋|vefWYv3fC 2ӵa$r#(}y{ҪgGnŶ!+i/QTIV i;x Nz~omN7\·ciY^ Yd8@- 4=^{=@M_M"d8 /m)E}A#qRhJnf?'/Y͵ĵd,#?NN0 ,+ȊH n' U G ˿-DrZsKT$Mqe E ~1aMy-Cg3%}Ї*ϲh &\8pϼϴ1ojX\e_ ɐ ׸?/]_yG)+G-ݽ~kP<>g?2{l p>@\Yiֺu54+u<>p~%Eߔx>,̓hxEsť Wۘ'_xy|*ƚo?L>귈.(55 64UuL҇/X K6{9:Atk}lR>\fT09ؕ w,{I6X8qu3B&ЬPl/:t+g',zytY] @mj(|cy'倞d-1SXYJbb%r%rai%g%|}0{<䴍|߅|sCz>/7rrX{rG@FCt ߳Z hT $37g_ʋ;Z|hiP}ߑTE6U--`=.P\^@fU>[^BXӓ{ٚ^OcrQ$ RTZdD_$'N:5g&|[y]}@s&E햖+*<C!("6\MFHZ o9.7nߡt hvDw7 'j0[aӄ(zu3B$td۰W2v]iml尳, 8f]pV aø,cf_EVǹ%u49ƣ˻(xzz<~Y[cwzh 3Q vCT3ȍjNg"+Dfz5# :sq8`l]LA\T1FִDP5 B}wc&}&k%M͎FvFs Yy&nk$3Hf[9zVA3gtZHdUYJeET Ɋ )U%m%E!>&pt:ꡑe>< ?B "Ŝ8{A(Fs6~̂,uew&Yr%-33uz<9yΜ<ihުP@#8:,CoVC[|-ߗADLR@xП!' :ކ桏L&HLhI}Q0?)ЎdeN)&Ę """pG |RJ6W&L"%LQL*0R?z_[D{&6`@0("MDDDD?=tʅF0- Ԅ """أP+@h?Q&L" """`>yͅ=ß4h6οG Qd+‘?6) #M?2"DDDDꗇ#K|OƇЛ'0`HX_B) E?`ʄInL'7ޫ`\DdO?S0 R9Wш&f<l7"RU Ԛ8O|@8wh@3Mj?KHBa"`Gh0 UQJ89 $h?I6q+DDDDc?<@ VȈ( /J€JM x@탿`tp#2EDDD{S.4"Q 4jI|{PZK:(`A>E$ @ <;d*H b`> (`{)L0/y L$@ dօ4} 'hD:o7@qEA& " YwOE0^R #W_`\DDTMCOY>"Co&ٯ#ɁC0,WCDD>qDŽbZdApQS+C5Q3Fg x@qQb`NX + F/v%"iWt"""? oo W+?߃S"OF DD", EQĠc#A}\< mfnt:؎;ntX$qj8ZuO0G:pz/O8 D/ Q2(‘*CAFE9()DEIͪrTl߿Tx $!=5 驡pjwbs ݅[':]ڝubuOW@D# 67F*Z;?4U%^M7>nKm&K4p (6*E ^ÃB̫* Cl$Mih@a^ Bڿ ÉVlvNXl# V=L ngʄ6>%(6#B&DD1(K; ^A~E?z4%3(?E͎B ß h8`;a`9a:`;D u.O gzUE8NfmCoGDLwدRda~uE xgR:ijh &$g AOo?,C mhzp@ Å& T}xCX(nL;H ))Gǯ8^(&ϯ8<ȟ; q!WSĄ8熴WO:Xl q x=(+ 9&/8fcQ<>8L;X>~51~̤c{soJ4cÃHJTG.)JfNrb<QYZ^-ý ,v':,C.tX:\@< `)^)M+Hfp!nx?v?yD36z_QRyʋ\mT!%))I */ i~,h/je€b<?A(Stmb8^&#\URAps*ٹ$||NqFe ?7[ffC #TXN|>g(/QLNÉ!r *E8%C `~usB[.E*4d$i(U`u qxSuMXR(` (P(1yF]B#%^q*qdPxD!1(ǯ8<ȯ()DyqALek(Y(4 3Ӑ>trjw^:bs{"D '8 hLd@v'Z{!M&~94sFE9c 2vLid!'+8h3p .p?ˠb4cuDDd - W W8ąI$@_@Xd5 z= r`ެ ̯.GEI!ʊ,T-Og z<\:WC9\ڇVGuga턳Gpmآt@HYih鰣@-vY;dv:hH:&$ O Wmk 61$ce `  CY$aˠ#?wahFW.p8>glPD/>35 Kgb qz`BN{mN6wډf>!Eds&3^ñ 45z%~)rQ4jW04'?П]Q ?fqJET awtb ): >*w1(NGAv:O2p$ j[:jqlklDzÉV:h<7ޛc>KOMƼ2U#>Τtx1M)hLFÔ* ptv0hzO !po209p9 0IjqƥIp2'Zvt@N(Vn)HOIB`qwu'pR P5AwoRB[v-X$txoD(2<;П]QD#ggD|?a0zæ0hi+Wb: @s S&8"I0+T"inlήe&M6t!0i53lw/djMQh0(?gL= (ZV)ɕ#^N(Q^> Åk'x߳wYDh1ų9&igqt։&mN4hW?ho3]& eA/ 4h|fh0Ũ*+AUy1f|O°)E ;3 ٙi=L (d,U<>Av$AKpr_Qdo@ȉT+JBף(U~UY1J I>ɏ%"RGؘ2z0vFŹ(ΝsWo@Ł@PlbC"1t:-J QUVYeE./961p& * j[:okl( c+JtxD "5*bQ7QQ;7`t@'= =ȯ()ļY{UHIJT:<"Q@DP9NBv0운aS ]lb8mcΩDjrQ"R +Z V0&>&M!LFT5+jWR:<"\BTӘN )n*X&&y%(/.9 UH-GL@/D~)XR>&#} ,h20(LHNDD`Z@VA hp"R GL@.HDF&DDj#_@Qc8b2@DFRVh+T.Q$a@"R VDD`"" "raL R"uLLZDs^ "0@D$[#S߂Zv?yCJL9HD2**xe'"*6k_=?5ܶ/b@Q }Rm5#h qX@DN "bb2vyz]7L8vSSl>a*-d?`4%Ѽ 1M E٧p-"R٦&17<2ܝ]a=yl@J̿>~YXAы∙e(°b|r ¾y^w?k˹]䞼 KqIU3Dab\IL*LpW92ͼf>>&y)Ds VM~ׇ-W݃w> I _&"=N?6|-pU$a5>mt(RM9DDW zYaׇ-}JB* q8 "[=tGcoϣT a8 @T;vCKU: RV ""(Q 鈈TSeߺW]t"G/DY!eMmwELmu*O " d|"[-q@p 8* LDE9|FDj$K&dcHOV:STSQ(Ɛ\I C a8bpO"0 C-@^,V:d8I{"f +(~DtAr2"&QAvP)``Dc#}lØԬK΂FS: RDD  `t%hՙI*/DET: RGL@@DFQ>e#"5b :eKV:#h z,*JB* qLhRL]C䞴R0Fh4X|/lґ @1SX@DOYW[ehtZz}(C4,g(JGB*UaX@Dj)Mk4`C7)>!+;[@ qX@D17DD~LNF?^y+;3d=w8ce=/EhWbr" JyMDIWu(88d^xuO{Pع 1Ptɪ]%+2NDKq I/ڬmlٍ^H>&_<Ӓƴd,̺l=^|ΰ?ma-}+P$a8b"7,%"5mmN?=q0qX6YG-DީG# [h'e5co.u] >5>6&!k"d^h{@Ub^ߋ /Obͩ?G۟o?։>5^ۅH@T&"MY@DjMqg\Iܓ= mX{T|B$S5 IDAT+V)D"iQ Z]ξݵSkun[+a<%nFH)jawۯhM9ףݦhdm ~r_pu`]Pc83 @DDD4V`UVLwm3^{J@$ïBKvCUNqԈM[U7_P36vHʣ_ uvw= WwQ$c8LQ̋Q""90 v`ӕw;V:qY؎}aI|fϷϋMQ="yJ\ /MG_KaLj_s!n>]{;Sz!ڵxU'}H}X +(ƄO ᧘6:4a%yqc{&Gf ThڕwVkO"E/+XE% "5){{RTu6Yņ] lDx5AJ-@C5/>lRc8 {Q""Y}aLI\ow#'Vօ _-0g,IkرSi Y 8>򎚈"+b>䍬Xl%^=:у/VDkH 5 J; \|Rd]@(vI$"R9r*üf!LMŽ7~({ӝԏ3gz>l\R၇_/E 72Dezxzй}aLuv!ǵ;qŶgtc݊Lޫ #f kN'W<W:}PZӻDDc(3@SS\"X=a?fm}+ni8L/hηcǼ&W$,VG{gP) y<^ & "q*%"R, NihS:iih l?|}Tcy;BYԚ{j𓋾O=:R8` E 6$"kg̲vdOF;?ڈǞ|3>ާ}^Z uy:9dUWK8F~L';2*"=j|EDy?ŔyRO=]q$ynFK%`%Ӆ-_Oʚ |2\3<$ j ҇QDD@ϔQ: ){œw#~wG  mظ.-7U 5 =drOB@ ]J2Eqy~~݆C/=82ޑ4vW2Fw/fԚ,|%(V' /DD~3JD$ h5X~0e+ʸ/s℟u{u>l^T_#i0_!+ ''%0<=}!O4S()1gQ,7- G&;枴 oly>5qI)AjtG)r-YihE[V8bssD)C PpH*/  ŮhPCSHE8?㋋wg Xg}wOzy]+Ԣ/V֔#Օ}b 4\箧`h *z`۸ g{ ̻HS4.=^/+D2DӔY@S@i p ? = mQ~Xpӥ:tXXoE'wa ^0<ǁ_4$f#:>ٌY?=shܯbW7TCVQLQDDɒKn21ېe\E|AC͸7رaimH,{2TuV_ϸAW]t#ũ G>x; )jHi(t(e-"R#0>cjV=tVvVB٧/7Mw Ngw>65V@?82@g?~r71~ Sg۴ kLa^z1S"ND)oFDqw}~ox9>mњ~ Cաq&\}`q_x?9LKnű/(+.f +(B(7D>\ 8]~=TL_; `bNGǢo t|> ?n3+Gh},Ue32Rp4)X ϓ`c?r|DӸ < ᧐֠Gљ'̓峭mލΚ}ih]!>? )ːl2^%-`>6 ޓ0Kkѓ04f[ˑH ^VpC=L>m5V/zR7WD"iQ?ӒQPot` nW IO)'ZԆGniַnOupk{MXo.?&aK I?=`ЄE/V' W H@VQ"mi2$46gN,hO;3+ja zqj3 2n{=:wzS8Nxb + lq ,/`Wu B)7ah}#io_;:8S{j| epb"2Me?%QPNR~ >F=sn3 m  9s `sɈ~yV,xzarb)ۦ>Ԍ"YK U0@D $IK >hb:2C`belOOKﯾHSeף{=wNP/D WP{Ѓ{x7֭80ê-G Krq?,kkt|U xbr"Ґ(&'ŝ>=wbZ ]XYS5WĄ ^9IBS{M8䓸@ M$&&›l"R#6TFSKnitXsY.}u3+U48q鏾N7lN;p@ qyY≙ "%"cuw=݂x=YH5 ֐Qޘ }5ϾW/Q|=Dt){~R+c4>"""9MߣaztdC#i0o!J''__yfw=cie(B(1)Tq xkdLw~ 6-3/1^-(C%%`{^n&nbl^kPv5=?)≙e(Bp""?Y5wmr9WWwW_Ԕ4MGB~*>U]1b VDD~\ t>'} _>`͋`Kz OEKPؖ===7\}1* h4X~蛿B{TSea@PXwc;jymk 9~o;_,9(=8!!T "e 3?ƽ ޛ0 Kjѓ8AVl+G#_iqn"df5p0faSs+l5$%o);=Q^&bV2$aos'l?Z_n~]y7x&t4h م?]y B n>bdQnRUTgo)'#,3e@ڂʰ"_WDmIy݃Xw+ ؾn>&tշz^"2DD~l8f3! j6KLıc V↫/FBiWGJ|{jb}H[X(D*jH <^>|Yz۬;5fX7DD۶ n㣰ڜK,غ^]{|sR {dFg~r&t:5 Bc3 3V`JO[c}' sEH*+2y@݉}NyVSH1J\4`Qx7&F®9-h( !^yc6/f8Z>7!BӢo{_E?q[z=2Zoo]T:2 xQǛ/էMf V2C!RL>"" 79t͕$ //&`GÖdC#i`oJ3&\YaY :| | > \o70рL$W@gjT+b}+Y g) "Y@S%OA bZCbَ2d[Sk.FvzMh7cS?&V'f /B2jz t(Ƹ=JAH¾mvchDbqrYl#~]]}g{_}vWr6.E`cjkz/_~u>&x%Qlcxbo!Lm6]=@1I dn8Kkw"p4d.Yf"~\h7p_Fk{l'j6/͙*`?+qُN֘I &F|>XP: =8c+ s~mx'IB'_ٗc WBWß"RX_`ypul/`wu ?yX:HGFs: }JC&:^>U⮄>~ØTW}k𝈢:3}ֶf->ޥG|>xE|zJD){]kv vm_ޘe9' 7{! W0حnG֛щ?ۀuީ_W,_[@dDb$IxOq?^{u^סdUch$ -¼}%'%' KP@<1S$&FN J@H܆W{x˗[wLDdPj">x-0 a̟ޫm(k ؞;n甅;lU3sҡ=c Yw"Bj:9c5.N\f@vuOo?}p;]|>hzOJ>>xfL->ysص.`{WR?6.E_\Dk܀+jʑJ>"&2TE{*qqW р9eQ*@&_]@֢*d("T:{''zǷ|`K4]ݰo]K {J 'JiUjŸyNWwBvi _-˷A \V66)D"@<1M ʿs"<*U]uC R2=އ`w}?= ya9c&Ծ:ZLӞz[P| jNS_ IDATZDqd9?QUo܅z nw8@e;WtL,[o{jqN5h&^2&e`HNAPd-FI+H1j4݃^rl <p匎ág{=-anz|n7oQyQv7낿(E*oO<Q>mњ~ Cաi| \y.TJPI@  qUud/tK#R)P[B{MxbIB~PXCۚJCzT{$%p*dt.wԊy/Aj*&'oFKe?wB^&N97)ݑz2rw;׀Wjܟ%_D$Z64㺛Fm}`5|ޙc6T!V+χdkDxU h;Ul 8Vlm =VCN:t5f;mpwCI19OC\VL)HDRI>R>Ff)ʅzm; 5AX#*řFtҵf |JVQk)vTV\tN?uuC&!{?+VpR䬜O/XkZ|e^q.K³uf?,!t/v}yIŹ^:G/@ `LaBQ ԇl{2\Ml]s!}iOH5BV=f}O+a&P4A8 W]qV,QO#gh$i@o /ws_=v7N cR6 f!{ht-;7aǼKB[P7$>'ig>4o9u7dFݛ@!(9Z~m(u @_[읲sρI?:Pw?)y OLP:"Ue +$Wl4xyqlAihw 'ㆫ/Fb+!f Jo;F[S?׾nSPxrTuVt.QBWWmAضmAh@Rq.2T"sq2BrY4!5۰勺Qg嘡yhm`[f**{ ; dްSxuνed3H5_2a{(:$C!R9?| 6VLƻqi-߷uXVC(^|Cy ]S~Ս7>Aݛ"%XT凷y;Bg>1)^~5zCx݃B16'v=*=7Q}Y@3!myu5]|ܸw5  O@8u:qO`]K^l\R 1=B+V 'ڷxa<$ijO\X Ap[@&Ihl+w`y|'cH,ȞyL!hx3Tsv`ǃ/ϱ"cA!QSk` >t5"m^_2+yH5"if3niXSs;Q3^]{4g"V֔%?鏾 4׈hz<"30 >S +b۽υoЃݏMq@|Nz)b/ S[\ |tɟWӔ"j{oo1'| (ɓ5wCoϣg̴ vW@ 3aɮ#rk4sI8Sf#M],Th"& $a/`_Whu>|pMpjv=X#b?gΧ qIeV~w:` cu['>gq+eD>uMG$LXfO %skvhl,Q07rOX _%$ nyG[;ewgAH>]{?Z>ެt(r"Z+<]4svLꂝ{*$W)j $Ix^ $xt>lZ\USI{0o_!4HNͿ1[pZQx@bDX`Ce=瀣 ]WcM mk)ƌ]3à?l ~N^7\)c4biF,WJAs3xC/_i_8͚^-VԔ)piL喟cnu#b<Ux {xSsY{;?1KϠC} IZ #8!g򿏅_? U?k-W#u, Rg㨮lomՋe۲ 1tӓK BKB)$0Z:6`c-HVd;?vV"N<vfgsHd7|[s)F6l_QFjv#/т"<۟ј p i xU۰OC3o`,6C!: @ȅT>s^qEaw( O0{nW~ 8Tߛb·`Sl3ip®3i8O;8v4܈-a@ Xh)#㤕ȻS70Sx7ߤcWelݒT/@wd^~uՈA@986[?PATGhbs"8]?d' $q#y n~!u#u#&lߍov`eHTI 0!rO\K 7o!Ĩzm\y_ {*Z(?j,_kjqӥP*M 1HnKeYx<,hZz7B@l=',d PRlͣh i!J# B'Oo@9rl}05t~0+  ,ÀV* jAA@kL(qEP&@ H{n}1<0<-k6tsʀK!wqם ?j( >! a-a=!*#Mrя XZC~&L-'@L&c*21غ/'8IO&=i 6&@{݇y u]!]+# jr@y&4n<}@ \B/[UؼWBk{5 skh;)]&v(CqjJ%<s(DiALH0 9ܢu`ג&X*r,*@␎^A$&"+!<hkt~w;ɝs CqOY9' $a/V`(@0hƞ8tV/֪_~\)2UJ?gfM/Ot?!DC& $_v ĸA@+HkU-mzL}kWLYG :zJy8yi\9UJé{UjSboo\ ~0TM9 ^!Aqڍ.o'A=U@15\IvE͓kN޿\=8M4 ~=(Z^$\PHAo9gc=!uQ6w'Z̛a&-nxŗ)92L F&sP&vy]Jd0 @}a/8?3-Li=7\L%D__nGf uϾMkw7 6.O*)Nβv<Ƨu߷gq3z0`O?=Z)G= !a~p替vɂsHh?Bסʋy6@>Hx(uE]p2Py0ӿZį 瞹@ !a;݆#OK9g{3gm$҄G9$P&";$v33Cnƴ,S` P@WP3i8C~k*촠'Wmw1' ԥeXpH]Z&v(`_9^lU2j(d=ڏ-;0xv0+d*% q+.DʊJd]uZ 1aIWCaQM;8 kQWx7Jm_;0toxZ" $!%(2V1w abNɦ{hCV [{lRB,v  B#ѳ0[-O$8O_K0^2 ~3ŠB WDz`=C<2,mc9։Gp`\N{}~6I6KHsd{ArR3 BϏpJL #GZ咻"&Gj%n{%\};WȠ'Ҡ[~r-/cc^tnBp Ze }ek*jq'zw9hp#:7m ZMcC U,w||˸qM2,O SAf4ZBoVsW,(½w\ VL4?T?a;Wk$$-pT/5ȂJ$ ୸+-O:'ת{j䞽`YZ0p C-i鄹 .J2Sa3gDby @FٝOc?=1V- 8yóV yNy5~k^TI@ "-7aXeUP9kO^eĬT t~b|Çp;*|DD sB WG_@,b8an[|cCQsO2Ya sYlPFWq:{?Atu 2!'$f8y"sPvK݆7Pg"R_1ލ8g5zNO*G<ܓTEҋOe%&T,G;?KRk[7vG~dR_'G@2 3E*sBRcÉξ!g ( U$ mYk]V$Ի_Z[pXCh~:7mEc#j`jnŶR.!#PК 8\R2?-< \PH%i38B~smK'<^ׁ $L*H@%8 `u,ͽX[aǝ!S Q)X8{GfR?­+!a .o7jb\{ˎ_3v[ :&0j"i/)k2a~[-vo{!0R:S 1T?#(I JU_Wf1 @ ]>,[&/t IDATJeEX%(.̇,րuMtf44COH"T?<|2SK юFõb@\J`(V,2N爴L׮v@WְeήN UjQuhTQtDB07=/b1G1 XG$Gv6C (c(dJr^}!v(~rs´նtJX Ó%iIqHN 0aE Cvu6&Jra)*(?'hͿ/c;p 1b7Q?&^|*QY,+?rԷ:r*^)"[ADIt ΤƮ{n5(/R3 ECL3Stl,v V .D H:8*%Qk}9##bQͲ,fhKZUH#e@=TNlv7|%p됞 P&A0}@ ̜T{V]X%QIY̅.R@ (ELT"`X ZS @Xhk`,=YZZڲF'zz,`@ҐJ|y[?z~^6F6:|nbk E!\QǜR@r/{v5E CoνRȡx ғ$EJX4O~ @ZRӐsJQcr|54M&<48 RRO E@%M0b\O2Ƀ6%IR{E GqCDCs+gg[Lڋ78m!D~2 (+YJyP0Ŏ8+sA .sZDandCtlmK'g{(@I{2TZ5 BTv{pHĶS wW?Nghza7rCT9ѳ}7vW˱0V;X\:5qxNX&!aYoC·܃ZЛ2=!vz 膋wb6T^-vSp[]`nha3BFMz2t+G ĕǔ2cJ'Jj)8`]Fơr,Z^|jL?#/'B ߗv}S _)䑻0\ۀ 7?YAEז{E(<ԁa+.~څ]M6Xzˤ-G,a\/â]h}g7{h'vاNOB'#3a( ba %ިqPktYiX[X^1<,:/UM]{|0W_J ڃhap)NB+Rz?:[燐s^uUõK&Z~Eq -AB4`2Y>C#vU6|XcnSߝْ "vˢQ[07eh_42N[;B* poh\S_?b怴\ęo~Fh++8: g,XakSaƏh!gdۋK/jp Obu?k)o-j&Ŋw>->ɿ7~} |yɏan"anՋ{y|+uۗǞ!XƬk5X;m7߿{|*?Eצ|Qe,v8Rz( QcqX}x8}ԔmH( l(->ir̔ąY~@ b9peb۪uV(+ zƾmvmbC?3eo۱mE}HCU!7pb_%DE_ ?@P8u,{既O_1n7$L m*S~Mؾ6u ;? zl\V*bӿ*1Np 'ikG68Ն=?,0W]]@Q@l B!V4+T$uMp-:ƣp mw@aC_YE9rכ%Ͻ/:{Kilo7 sk۲q@>.g%8DZNfF'#%8F}-8-n?âqIfCh|}%b;$0~J ,]V޽ > bL`Ґg2ΊZ8hs# NIBʋ_:/;6~fGKoW A ڋ?=2uY\rړ6߷LF@Kg/ߦ<x%LJÒ'~y?}n=ףP Hk'[1F0P̛P&,n,xZ RIinë`kQ)k$+BB(ƒjCCsĶYg0 gY4C uto  N.{I҆W=s#Ma7BR g>KZ`,##.,09ō'Xx!H=}(1p%L8>XuOpD(5yWOL#1,oŴV4>JZP£dV$@L1ؕPۥF|5'bXptH w`Q.A!to9 ,? [C#wg| [wz<1m:TC!W‡_|T2Sь QCJOIN܊lu(!=(:}-еqwz330U&"i'W@cL)u#GZ/-o|ۮ%?Xx itfn `O'Շ8I'ghNW,#úf4`5j_õ|t} ľ:6m% nwg]p[ZJK 4-,.w߂I6> JM!*2Tk[mp q@4h rTrҡ/Ȃ&+:{pp 盽H?uءL Q ?%n#zc*bܪ"Vuv5K!@$Aҩun? m*+szwh b@a<ԳhliL`we3ϴ: BgʤW.ĽOPR0wrė @P" ˢkn&@PxYY3dw( e]OQKDdA˱Ʉ` ib_ExÉov_'Կ6#tz^K[\&3} QAK[;yY pk;2P:3V@>n^piU?EOFMJajhn/v~! a$fM?@?gf' * "CvuM/i,*p g@$>ea>*i6$VFH|q3v쩂Z^N^^NBA&:YUvnΕu ;pMSuc=O@'^ _k!$,p2O᯼$@HF-cG4/Ҽ,"bqJ"8ĝ[ta0O& r`0[w坏xmw`/~<898QHDuoI`)@d4B@!7#xzi\'N)D(H96o> .&`d32(\2(.뱟cpЈ C#3ۢhzf`,q0$[Q9w0݋.b!tZaiQCt ( Fw::Շ>wZ? קQH5MBbJYƦʡ.7F @F:l"ʡ<9Y&C`t|@o&d*%TI p Up'[.>x:n ΰlb'I I"$ ddLuwBt*}| yKPrta+84; 'Kp*Y cI3PM2Pw&4ȼ2;sA{&'M/%ΘT(-"A4x 3b흽]Cgw<~W5OҌt~L=>j'^3rLz5E(#Œ =}bHGDF4|?iq9vW Mh$.(P?PnW]r7\ʐ3hbDy%rӱbqZC% ܤR7߀V,gl(0(p\)v 6uYPgvO5ˉXL|B+fƴa! 7dBWp,[)# aDk-o0W Q>(k˱񄵫Ǭ.uRԽQ&mRC+@L܉Xh4'1 K<,!Q,=]K3{nAIQxHAH}C^tt菠ʥpNuvX5Xu0$7fY aQqE$jK<($o278dQ^F taHU&KhJhyPa]s03(, l2!nڷO<8\0sN;˸>|Kꥄ[[]r7%4f{oGfF>)3\lgmh;փt:<4 5:aa8a8`8#2F ex!uB|CBa& #Z΃Si>Y'5-2OЎ!HS `BR"gZ4'n^>+#dxF-5vW"nk4V>f~Δ&${O{3nu6#Bġr܏vԮY!01xJC Q ?]H`(={4A.᭲B_`:В IDAT:1Pu(6\?+7^-v3B#= TO%ά}Sjמ )Ip ]`7GW{=tg bѕ|Jf=l>ߒ50ϓtQ )Nƍm?M Q#Wl U*%J}٢y S.2!E5=l]|1G +% F,5jާp%g~')`d!{@>dn/•/>7vbHp=9j?0LF5:`9&j-Z;yt ~2tKPGB@Ha!%.`B`SYiF 2P}g/)ztUY],+.ҮMH (+ c\d|ΨqgJ](Bᜉɯz\h]K&F_3p`nߚLNB?GK<&tt.Jf&|JRsQrǕz\ |O~1D ,<)H`&ԶuV_L"#fI=,^ Fp\xdEj7NRE9h'M, 81 މݿz爦'v(cܷ @9+߳PP9P9g<`)(>K&0>B2QКop7ca)^(,cott+ru, RO|I\<w6 E跻T B0 aط;p2nX .'\. N 'jâ0' Ɣx?'H}C^ R ELBе;6:c .;軟TK{3R(dzhsMSR,SI7Y05gd,Fz/;ǘƌH|4PH \w]<uJfLoMQ~ѽe/NBNjFPD (mxu`Gb`Om8]q';]. l.7lȮ6]q֪ \~*$5'#Dh{l)5j(.O?NEg ff yYŌYug05c/4 rE&ւbL_*UbV<]Kxq瞺L,~VQc~J=dzF00,rP>;P`͆v"E^[1qD0З4 j,Iݠ( yM X}^,āw"LJSrz(<2ؠϾ5NyCI-ZDŽ\߬urmlt\)*~3oh|a( _ ~J djV`(_a0's2=2NN.o;mttIc+NmlbwÝ<4 xӅ?oۏK8N\O=+!QmIn?wUqqhe^>)xc CL U teXwP%GL&EQ7*H@7B>&Kg"jj-n:q4oEegm6L4`+0[qÁtږv`a-hg.xMʰ4 F#sC` F6M{=niϨ345M{F͛(@mW99I&/WkW,MhR4l2Z^,b{Sxh:XvzZGFeГuF$.Fo@ɍW2#\(L&kSKd)ZZBJu:]be"ajøqډpҪeDam~{ T/hE] XGA}+z>9vOsM9+[тa-JSۺ?@iם")Rl7tS ë3iFMXTV2xq37rʊJ,/I  ~*}}Rʊn-/9cZD r "`.@ mxN}/VXtd?27 U5EU=>>sW bFP`D#@mK'[/,-u矈¬|x5e%qqȤӡt-$|ú_Y?oo50ڃ#E]h%cP Z: z :zbү+C`Ggw&xɘwչkO0D ,@H0F3$BMؚd'% F܎{jZQTY׭1EڒO̦v}c ɕ$3mٝ2XPy$q?[~ {o޹X_A\A㐺8AƓ2 /G` C c6gx،^z;PU Ze4vVVU}]pC[2k  e2^C'#e7@X@Dj;8ۃq :ӇЕ:$7e@"b[UZU^D6 b! ϩp?C!+L~ZF87Pgp̪ƘʇX?ag`9 q]vtms)/ȁLy&9I_}&?.4%Ϊ܏MWeȖ%+ύ5Q%ţQp`v ?S1[ urPtP&@Bĕ䃢co((D[Rl6Zaih7"-E-霚jG[c΃83V@főѲU}ȷ?<-^K%QQJJ?=7^coc 1W].ɉ[4!Z)(Agq/ѽu'C#S2$Gik͒v,T 46Y۝7jA+Fk +%hCY et5_kSBk): t%!=5 ٙP+ VՋzJ ~LIta4)-%"sӠ=l5=xMi<.h -#w-C12{КՏt䷥p2'lډϾƥgu'.R. pEPDC@Am}ĶMU^- ",A{ѻc/(C#puf#t,0O ce&.KXƍ}_'豃5/"gXE}JD_Ny/MQfQ_ЍnR&ZX ZrҀk5?&|:ƌdf$#Ә̌3iLF0Bh8wTXL'<$fL8cCNdpz- n rF؄^^Ǯ w?=!uAץp-9(n@N{gd6sWb튅`5F8uAn7 )BQ#8euDso{kkm])peY0n7')L-1x`z0X|ϾƢ_ނ/n)=D h`2WoLyo0oڡ2[f_B.GFF$?#etoLF1q H~J (->A ŀbm7 =zl2>A桼^ƻ䣓R';=89.ա;.(kCSnJ0v'po|w܍k׭EȃHTx C#axғ"59 ԰ |yoxm'%RD,¯#2 @禭X›LN_зk?VQ &F{㹗0^,Q_ U#myiBJr2)0 ;sr5s  ,<)H 5^ b17;z7Ѧ=HݽWW'VtXb)'#+GsА "?΁-H֢k[~(7OĢy9 DC-jan/1!-D%|>?/`x{gp6a&( .qF:MN΄f!V)ELtf|4: @&@? J^\S@$>\nωfd.og.o݇8d l/v{ p9,R}GD.ckE3lPM:/r0 Q5Z45A' mG8h01;?qÕ3 QREdW6)Ótku}xvӛ(,)#ot\&5m`?9q<|6ܽz\%dFsQXh``6Ag2K!Ci $jjc1 w?xK~|BPfA'_š_Z!zțr1oS z?`@/ Ke NFHjՇoCAEtYȴd,&y َ} k72 tvuA@\ZC6虈P vH8x7 X{ Hh;m1Y. t-h?WծEsyJΜ6 Y,KѰP80 (CJ~8u@Ys @^a|ڇgeX+JAC2U2B|Wp<,2AoIvclHѐx[Kt:q#Ճe`"ұ/[2`x,.u6Ҡf>hL]pX8@T</t2%oߙ]Wǧ__N[fORA¬Ea&yE[~Tm><܋L%3%T䍙Yi(j˵k@Ab-Z_)YD:ٍ_Ď_`Ld [_d,#~݃E"?_9QǓlu+iDEd4 o ,Am?sgNG`R|'-M'wH201\E V~áKwy5ZOG`fGƷ5Wa;A:NЀE+Jb\ B\e_(5+5+%cSPp/T 8hXy3yl4}nG 0l q.U Qr &5^p"kERb&o W͉@rW_@3]#h  n4Iw\_78Lrrqh]H{QDac9074zmE@uPzG㳯bY#?Iv;OS _t=oN Zϣ#=U0tj@`| CtpeD) U@Al&ΡB< IDAT|Sϋ}8eN&Xl9Vv5^7~6fg~FecLd({q~SPiqLơ"|8:5țENFiLM q.U QrHBf5^x7ڹ6uh@3@cYWg7 .O [@ VgJƇ,frtU94wWѣEGA S==a86Rz 06F Fs(LE tH nhѪP5Ѡ `2fv*LO\|s}*7Fц&j;85 ruIj7EZ\]7ѡR)ZZ~^0l89.\҆7)>b5ص7MC?ۀ*t Suq( Nuw`۔%Ġq]b<=Qa1upA2#m}G[#͚{$Y-}RŹVI7kuqB(L+7/<>zGනkKPRx(|J:Ǡ} p߹ gQf<Nܴ8d&GPN>{ (XLH[P'W4.^A?Υ*!#BnoY?ލp9v.Mld@LeBX NXA< ɶؾ{?鸖GNz%zev!GiT0Luʜ1I2o:]Mi¨X0P8d  !`zǵ˭ Al|/s#˄ LBlr4\!ÆnDTDƧZ;<8|$&f3}#JEr[F}Qzm\xRߊy޻`2fv*LO\|s} 7Fц&&;85 ruM#j7EZ\]7ѡR7wZժ:t1nkal&GlqOrUڔ nGZQIbpCzjCΙnǺ4ټLOOcTX{ ea.AASU}%no\N][T[khr}Z[(Mڑ0:L0P!~Ocmlٗg]U/B[Cz.e ~, Cꨘ&:AP4QނVdgh o!Bna[ÛXs\O/XsTy wn`4`[SH;8Ve%NP }xHrxt6QD{_8|/gyJ0pX =]LhL'7<}?5ˮt>^|&kVW3f֟i…]*ed ,a稬1yŅ\0c{w{oۦ?|mKJt.{|<]Yiv$( }z&ʃ^'AEd3j1F mqSP bV\2,ɸcl}'BmGYU[=:j#Փ&'N达~8_ptEҍsJ $b}!D8mqw߁/ qi kXVs,@gvb܏ƟAhL.w=hB<49gklF{'F#68bC ͚ YOs{dWv`;PX\eq5@)*\jEJ PYOY` v%zJ`o!wӧ &_BmB"@!ߺ+}ǑKXtl+ DyTF@ҎzY"j%VJ2 .V&33Xd@qG qJ@Q`mF`zx;@RE:^/@kRSvh m|bΗ$A# N#LGo5d <$h.)9/lġ5ksm n?ŶϞ`QƇ5Sfhz _}qQHo5V]pF}]3xO11(iD#YE1 NRW&<6(gpOLP(d i8 a6l0!Şq T7b랣( 4pQ/JbYovÌʈB"V#~q 6˛y]0 Z^`y߱q:S;ҦƓ/fq uVt3 SD.A 3~B(W:FoCӯ'|Ko3jOO*,994bb48gǓ"ql_`귽[=. -']V e~7ЁVpZ:((8"?Iex lEE ҋYnZ2Y\œc{&)nSj묒K :5ز'<'- 苸{*#-6c~<S$A(6}A#PXXYfF`/x4< fx,~?9n.8Q[J[JC6=cVvN,u$Z~U WᤒIcz o|w> ]y!űRTF86!L4\ ?#&*5S؅oB$8b?K 5z+.c*0"yF9}W ޜDʆINܴ8Xd>1КhD+,YWЏsJQ6&Y?ލ+䕩Ft0h4B`vc@px* K_#?4 O*zmN? gbI;^p ~08`$3ӱdLw>,$xIm |И#B8tݗfR:8Sߌ3%'\7^G7,/?ZAc!f'+8A[WB*0)6PRj~̆s0 \3;i)H(hOS+qjz%|-]e57EecWGqߥ$S6 /x߯C7؃0*):6fo{׀)ff.'7H=2_oA8I1M boSM2pUf v|?z!QXhe bT:բ-X5@"B|-yS[ÛXs\rK0񐌸XP/s6ҳ2tZ:l0q.PhXwaVht:XEM;g> p} =$`eGf;qRѠXk9;u{ASkx)σ8- 1Pe IDATjp=̮|/;PH{q_ sw<~4=䀳nFYt[-DP?6{##]26sKdTw/8!˳2DrRxSR3hr L |<]Yiv$(y g"<uTD66, hv) 1b+eA ; ' *xf2X:b_7t.fO05ٻLޏ_O:1 gZ%4¾Q$3"~NaݫdwB0UZOE0ic8La+B]7/!Ɖ3 C4 o4Y3!͚ 0tkmh .l`}5rr%~ׂ09]]=xs\_/j#\/NR,4 K;VLy|-][r'>t6U2J(@7[)ކ}N6X/Gvn|! 5b4\k֛0ju_Dᵄq Va뮣(Q%.#.AIL:l741̨h*J)"j% ]ވ?|ܲd&gM{fٸ`9r!}mxghGO!*Yֿ b+@Yx1%3 .+@~Jl4Bmc3LZ:0<0\R6MTH&[n FvuGڱ;k¡vGn "/Iڬ+!͢ j*?AОSam#'7=>  m a6Pu745u~Kku"0E>Sw-U(Ort(6=rNT=P5>&i'Jr7L(mRъjbNۇwebQF2.dbK ]K@(q螎ߏ_{HMa{"Z`1n|]ЙL(x"Ϻd20Rw{`CPW/_Xg߽^\u^Ά%|v2oݍnZQM._!GDmYt=R]26{`8ޓ8vߠs!'Xe.KFـ߃چH8~1 tWՏډ_4v2hr_?FU,ujE5k{k@Ab-Z_)hٍ_Ď_`Lqjʓ v>:uJCsMO/(&ov"7ƺ$$V#JD:,⹍A)S R . hhCGm^ti,sGen]O:4`ܥ.M/xNZꐗTcx`wa)x.AxK8 hUMN'?4~'{33\v S80.]MM# ;YDpYF+T*| `U= [D[H/^P\I LŚk"8p|m<+V DhH$T.CX4Zg::ɒ q oz=DHH ix|=pN/g`i08R[߄/ۅSgGIMraI&g,A#P01ᑎ/3wE֘bbcRށwGG-,Tֆ: x`T<3Ǔ,9Ŷn{I^{}8x9OTt|5Q'rbzT` . @{ߣ _ݍ|/kLf0~Y̤ GK:]"#_.rqd疑tl+ DyyAm F@ҎzY"j%VJ/Ip/qL1Vd%l3d UKǺ:َ}Gyߩxe{QWΧ(d9ӱ1\ګշ08p7z;Hs (jBmb}]:7;1'cE`c$B/B_8lEq"e+#=uGuQ@WITL;Ԟ,KJ& e_sɽUN %HF,űB=b?d7T{˝0Y6[Flsu.#HZ[11̨h*J)"j%`7z#' pX9/l؏ZO\(avvėF!9};Bz&Iק#onZq vKyv)k GjEF#=ϿL id025"U7ǟ~Ūpa+-v"O d;\jH+dCPP3Ћ\`'z 濵ѮkS'p/B޾G!E&T(H9^p+rTP6w 0t,2$JE+bdP4I[wÞL,Lc Mi/&#-7"223hF m5k/xoH~9U6t|؆D:݁Wsɜ)<B0A-~=Z, :ZeэX?AJbq.ұfA3vj"B^G~jw+(ǖw]MV46v!&qr ]2\26J\S%C'\:Fb6G!:ߨ,y<s\GW`SwEE)F!-. om ~/?E0yD-D֩4uBlt<P0U-CL6i`˶YܹlL )K>jRdj mHǵ<=r+zI#4nL&:dep)6^_@R5Fi'Jbov(hk.,bǞJӏItk ȗKjqQק;OGX<=TP;2.Yt[ ?}~2RxהxIIlT r1$&/e`Pw(^يDz+CC!|\OOb@07-8SGfpK#yV?(i&WЏsJ_Z_Y?ލp9v. z~^c_|mg6xqp6Ƨ9*ǵA nGZQޖ߇T*6 h Wؚ)R5`#|6:d*w!sO_CX~|H1pſ"9 -σɷϰ]w> ,U>Z,撱)((FRx)P{sI0nʘO~D7?/Xboqw.vd2pT,=ٹ)hf쏚PuJHB$-;e5"-. 뮛P&4N!91{h>oΑwiq:ʦMxI%c50P]cv9n7 !b ,puwd}z:J: KVS;thnmǓ/V[ 4L- $H\t$z e1Jw=o6 |}7jt36TD6rOCBYHai(WhJ  ͞)ߍiv9R4v~Ff#UYtj)(J\S \Yn`Ҙ&tW֡[ـ&5}nwj``6abf/7@>a2d oT0hÌ((ITHu('DH:shkPhWohÌʈfB"Vɳv㆟3@Rskj+ wo(iDEd&:G"AJKN<.3ʕ]FbP-^OЀze1Mq]cױ_!#_ͼ{t._勠T `뙈"N2✃$by*,m`(#xCB#@W-> WΟQPP R`6^Z; -"g$E!Ab(!4H%h)19_=NY,!jG6~"}\ kAKrR,_ \:C|-S W!@,rN\c.d(.zl t-Y݅fuE3 *#$AbO-i4,ӧcOt˦4 JE*#f^t~_`w:lH6T8V$4ljM,ӱIo] o)sXa8\0-OҘF4H;l7ACh?*Y*V,&V\}%n^>w) N`??,3&̠L=kJ<3 ϶qUMm6 QjF\oK/DpߕbHE|5w od3pUf vr?9>`ƟahV(.k+ |=4f1x=Ͼ1$gqzZM ~|d[?Gpϝ`5W:O? ;-!9 Jt0; DGTqez65? u{설klA۟o~DIG@,BXLl&naV-2P 0)M\6ؾ{؉E[i̅6A#6w8[τ@]1v @`jh4AUe{/A"J07-16ߗq TPl$p61*9!\.vߦ/.?{VujY,y{Yd2C $!Ah(RZ 0 6 #0ę%ɲdÉmY-Gl?ս(HW>xXS`rC!> UVcL#v8 < <<-~+.GTЩT\ÆkgcâHu$p?F&D!BHJT$B7cPgömM6 K(o W\vj4Q'x퐄i=ɃBٍ?l5FP4f1Rk%:bUXl1жpx]AZ;yo=YoO"FfE&۬ass0 P g=@!yL wkA7!4EC#C#ӹF6Z>D=>^ h} jDH[h1TKq-K q g( `VN2{_G;I{abhT^1:g %}_6XK84jkD[kSBl4x;H-^;/:oqJV?ƞŢp¹ظf9Acw"_=He˯moQ\ ^o_d$& g qvj>=ahF,k2@e}ՀPg>(`D(mT%5ȶ刋q `Q,>Ԛ ES`Y`(jE;j)Eemx/T؆aeaaZqۭ7HY)P0{\d7[9nsR Q Yؼn5b"|mEa ڏvvRn$n\?o0j BVEm?k%"YaBAaB@p{ :SH-w0X5b18-Ex@D ?oXSǖ$ƪ+c9t _t:L`qrOрx&O(@b\CVI/Bބ5.c9F6&Μ?xrj䅦i9q|Ze/EC)GU zf4|UE@a? +=8vuMS+M2a&C1pSm\h}D9@ wH srJ Ckհ<:Y`p*)IpqQ%a`{10B_r\,]0~{ +r ਵ RZqSʆVoށ`#͢QPGsIWY{\96f'i2>exPUSoxkɭH El՝"QplZ sfLq:6zYmZdx]8_QV FʂUe4r8XJ~> ̔#P⮟7d|f#p0yPb}\@UI2tk1|\1MsjL FDyUXyt$7<8/dH=ׁN3/qɩG{zyy& B%WcƵ^!&x x=8u RZl\46nqXtż1goDK3K(MpbĻ| TQ<9ѐKJ=wEl4g`$Uo@HXeosO1ϳ|ïmTkp:+nCU8:E R.ٶ1GDDžVgR&xH(~:x~lqjj-oD=|< tp +p%c\=a)cv{:-) `Jv}kE]k\>wK7"]{"k Y"]mߋa㆕W`ղ. (<3%^ @R G4njj z2ܞF.rR/|߬ ^C[5ESV"Dvl<# :ԉ [g3\Xz\x0q|wv3:U24F*sGFeBlY87Yq؜%0+ A1F~&4~<:㞖ٱi.; 1~@x.@/H dܺpPfmc 9=B= \mAaj?ҫ"k-&3^jp+(>;J%G P3vNf]=MxϰgVZ'@;!EV2j.چ3:.Ɉ~G{Zm$1qͨkG]llf^nEaΌ)شn$̫f|?,߂v^7jHqˮ'k U6:(Nila QA̓8l6V/_+ YaBaz\ tZ:"h˯:@Jҁ#׌ @@ZkKj-bZq#k.8o+ '/7Vo6[⇟WzQ0zu L)e.ӽw"/񖃄mc''_\¢݉6Ƃ٢>ҫ#a#kIu''02=X΋8zihr5c^;u804Mc?c{[gM R!hBxx `0ނ&ZQ,iۘy>ܑsl)6i^ Ϸ\܃#*_@@;v[!36FXO&Fׇ`T8t(!q i F?ahƷ?ƛ}^u̶, ѝ'D>v?9@:3L ,ƾNw\o~q8li1vhuɻ!!mC&WB*M1 F`n-P=~:tᷰ,(ʒBAVy4Xd&|zug"+@ x7AB쿲[SImWT(l[Xt: F.3Y/ҫ"*8JǖH8x^{cmAe uf^ { 0i<9OoZ*CqV4:}}. + F$RS )ޅ.4.WXX/68҉f(Ikҿ9eƮQ ÎJkAJa'_^?^hnpb֙$i릗\wnFjqyh6h h(P$pw1g`EDd޾`@"MwL&3Z;. tt|UdMDBySq:i^L/Jofhax  k` ZoXp:Q%`֙$_y=na% jև{PTZaxG-Pzkd#.VŸej1ٝLt^}#{4VV_ֿ6@p1D) FDɀ˷h}C'Z>xs2ӛ耼x$T8<S[Kerxf7vl\y)NA 8xHD(73r89]a_s3&Z9S`׸dCG_|~:jOOe &[#8?k]^ּ(Uj36T^fI ܸqp%n(<C r ʊtף ZږtzuMfP68|p<"C!/: A LWhk <.ݼQxӃ0],rKc-@Iz,#׌)5HjCZudWoo}5W@)2a.EGcb!@e;1`j Ԣ%]~~.A.=݂kۢZd97: rFj)"*^R/\[n\A:OއJc5Nhv"u#AJ @!/AsZRzeckP!, 8'e EtOz /NգD](ķGÔ8p}ԷtMO]  o+@ّu(Vw0#ӊ H.g.>ե%xz_8O~ 6+lQ߆:3*#?ܙӰe*Hˆphxq c* Yp.@/nnz;POh=M0M]eu({KE!yH\u!N_>;9߿xKTIT-Hz(D[ GWazQcpﳻȶ qja8=lG Z9cSmD BfjKJf ~(MH>01 *ҦEdbH{т[AY4P\0D@ <(<3%^hQ>; `OS;J^݃"H߲¨0$S7?s1t2JRܺt82SJb?ٍlXҝ@;jR{kR}ҫ"āx툏r: Ӆx=hl)M]Ljo[ Z Iغa5dg02DA?NS0k `g``+LzTl`!k$,j?_W!εNy8lp-Rc$xBvy480q8[pD F<~T5Ȱu#4At(9;PhBQtt ȨDbu/"<ONyVhQyPmf!!I aV&X:\Bp9$FWP%uH覴{}@  Dh oem$6-Eoop]?=!/= O/\v:G>!*]x6Սؾ]arG850^7e0|$m{  Z"=س{|0l?T&$Q0RM@L{^kA( A8]T^.qQׁʤVƲB4i5EF@ Qxb$^= /: mQ+(+ϻ* wӃ<3&: 2:{:9eVLx#f͕vNO@ L 8f% di̩d IDATxw^}~_~m36umC"dTD¿ǎ?3b5 fdW7xfcQ)"9ݑRaڍ2 X,4qRfGDǙrO/!d=OcD=6-#>*/}x &M!F/eIr,(̒+PhPJ&3^{4z׉0^C(X=3%<_1o6߾ ,00_ާ{mjÁoc?[Hwwm"!6'gKEBa5NS@ciNyESHlEjM]@p fRpX &qG{x}/@$}/;0d*NաG4Jӊcd:Ul[01m&a֙$>Vˮ|#1[ )?EKmYZ$ BÌP냴DwOIfI`ȳD=|Z]EQ03|s^H`D9,2.8]qJ ܌ُB00^cAY/G`@-sMSv܍6/E^ZSs&p44|:Vk-Ɩ<*+)[|*;j6C-bAb}va!bܼv7 EȎPR^6Ze6ǤQ }z|_p? ~%(<Q\ _E= s!SRw\%߬Ƈ7BX/L@M|;*[@;qlz52"/heϯ|[ګf:V\-s~JX, ݺIEݟő}eZ0%fYo Ar]k_K"<i} (ʒ2֩"6?cjv A$C  QxfL7`Ayz.ݐ΁ $,M ."/-z- \vN(IkZCVEtl`èo=gPC;_y@p]0wT,r |ԮGCEJ+d)Pm FJ>z{(+k./=d&exշis>)- gÐZ#DBf,lݰ'&"f4:7N)'nߟ@\;o~Gnu5 &\MFa[ӹuNKVrD/J@t V9m$U `|>F!4||;_~w}E>FT&M1I{ ҫ#l$fayذf)āGc߁eJ!3nAPu qx% a21_?]fJۮ@Wxz._m׵l7_xqMP냹'SQوIWeGfV`jq+ums;>~:Lˈwje=KCY=xR<0 ^}#ͿcAm\;jȨV)ز~#%?Q)[݉'HCV-bm'[KJaF(@Gb%c1QȹgK+ȶx_}f!@%@yJS- 'kQAjm/{unn.nf&y!#KHRk ?lGt٘w( .$jDe 37~>ҫ"a?[7AFj#OT # |!Z^EY3 j}W m@glM p`E_ c05o 0 <F~{ 9w@~l$DŽc;_G;/;KS4JӚ "46BxgT5ލ!~?xxh "q!V1Q<yheW_O1Z柯"V1(;ёl^M'~cϿ Ͳ6cQraaPUGXPn,xwB @YMm所M3r xMǛ_J:pi8[eƩ9Z$]!0AuNJ m#@ oeY("RfOIcރC+#0AnfU X!BeYk Ar渿W^믹lq&Wس;Fh U16X+lMoAXp`xG~fck @hOm߀|=~8Q?qq٩d5A-wj_/ϪĔX;psޛ)NAxsmf!0rk42o}KeS%iM.1tnRk#\?}ᚙ`_IGBqlֶXptF%J  Ц_[˧g85aus <ʹJt|`Ќ–u0cjK64WvNdsE҅fZ6bZYٯf[֭kD!׆_ ! L >\;OdWw"rظg"Jg` ,*8fL N!>5Wz ;Rn]~=iVobFxh0$a=`Yhg?v׶`M6Sf|6 M3W>q[cc iɸ-.- %c0S0og9H ? r@Qub3D mb8 _ý?Ams;޲%RJ DZ{]Z_}$ʫ`0qG9srC[,Og03S[ X^$!6ݹ ьʑ@QxfJ,d/pZ:ٱ@N+HhPkKE%ljj}=N/|69އ>tI`5 )c%RMFVVlmֶw?wegnXl1ݲKL T@+ < "q^ư$Do$qsNB8̙ȬJ5Mm87Uo} 0F^#)PJ|A4=t /:fLwg`ZQ<ŃgVDƖqc^@  )&f+EM= q5|ٶ[5њcb!(/s.:>_vqϧ`\L m@lfY9py0N7vC[Qf:x"l.[G$s6s.L67I߼ C]8_L8ҷ,2(j&b%xoxhKCJ3993zS/Vgi{M݆k':0t$ŠOyc6 =B4}%RUuh ;hw?}zoQiܡ5^`cQ-_t (<1#,eyL@٘{mfgf%7"VbüP9х_Wz˙ عMma$th rT !H[g\VїghlOx&?@ d0"!SӐu^Sn_i s݄SR}u<9fs{qdVM[6{=/&Z3T@<&'Cc/P+kz6~f)-(Z^>368:]x^J<;l  %H%P!O/e$r{}xxxR|}v} YXz|Q`kBZWE"!\3osn,4Hʡ6" IVZ28Lgʃz@St7ʹe._xC Kl}fJm^$1gYXZlX}=QṥxL<<Q8ԇb4nϞ^$,_m2\EQq,d$F]Tk%HCL^=KϢftk[ @[h(*Z-A!oIRQZѧ4j}sxj䚡D54@٭B`?ck6>:ոmAU qp;vX8F62FE; %)ɽo3TX~2(nCS<$)!O۬'91xf5.V 1D*h(qtF%4ѓ% 1Mp= jcH)C0 M(.e }_xl625mCXxܶ֟Ţfٵx?Ŕ@ auc @QȺ}5fNpe+Ŭ݉)26 p qN 63V"άD{j ?>G8x.IQI08|Q8[\j5nf[P֌ <Z!~[ׯM"PkHN&Nc!} 2tZ:f=.ʲP)X)DqFz,fR0UG@ހ' L8a(@}|ԇt@Ee٫(tu7vBcfJ21)µWm7 sdMRB!?嗳8hZ:=߰ u#⮛;.\9ɷBjï3~vtR/E4|Mxx2SBއP.R0Yp8HM⾀2_DžPcS4fJ-J! 8%ś8r4{P5VI2u8e;l3 )$6a!qfd? !L6@oJ \0~=Op!¨0L{h3|qϛtd&FnFzBxN"D>l=CT8:j?:5Mر=T6:=UJh͊&5C@u@q)Pv'_|f |J!OCR柢(,r> %`P0y!醫 -DWz,F&Y\"MA=yJ/FB޽}#u@3r0l"RZPάDnI,";*<Ǹ{5rFSs\[=+< W=qrظkH࿟ㅛ ESȬBJF|Ll #? i F *dmఽI308q{ưgk3O0IJP F4˯%ef}iQW;#^yCn- 6,W"C^i Zz~pU uj_?@ qqf _kf!YJey=ԍm:ۦIIdGGoIbO6cdl$Do|N個,~=|Ϋw/@/Łg;|xx27S҉NjR5}ڋ=Jw %BNFJ/T^ηh(5P)B Qp$gJڻYYX4dI`N6VPZ1f i8q { {! b\oo`4xBB,O/eR+ lSܿ Rq6CZNGfU"0jfعغ  NAM?.'Q%m }lHJV ? @_;hlᩗge0Ea*?=JRXdbm\ _>'dO .  cvo3S73g@ \2"~ X{L+#̳H^_~Y(ո>=Xanl}~a6a5H4Pcx,PhijF;5D~ cH\v*f/ ݉<6Š0,DYy ^ e|$FnP5> " { IDAT`\¢QeY v=V9v0PtЩR|wa_GS4A=F!cwܸHB+ {&;q1 Ow5k+)mby[.>&OZ|V5ev#X?^Ԏ;wK15-Ω9& Mm p?R=̶=DiAjlNc Fe  D!r8\ }C`ﷇ_SZվ+ ̛nH4!];!]< #/v&#ȶIHC<´xv4)iτjVqF3lZ6kAp JpR:kF"i֎^|{27 nJLk`[أ3HmwQi%V.%kcťxOƚ",He[oeӧtNo=]@ ga( sw%`4 Ԝu)Wki{5ؾa>\.z0ى",DξRn!XUȑP1Gqflw46䋯Y*5(hᬱ㯺 ]>g&ؼ~B) (< Q߈%BP Rq**\"PlT&#ۖ#24ȩ9+re@{j /=Y(M1$@nV:~W}}郔=u )뻯h{uk@zrS˽dj eyu\ [oœ\2x(;! B B}7s㾽<9&4G(FtkqdV%!D1֫>e ff%95xd| ?qKF o=83C||bJʽ.`2_Ec`c)s﹐WfϞ;lΙ t,̘.qoY~97?60|,]B792pM(Vk }5W@&fVfЯJfYXϋA~F yYVwm:4XPTZW,qz]շ?DQiENvcԚ pr,!cgaDy |4H <6OǙz2}-WK4>=XLoY 8|ߟ8_Ac]0q&@@R=H 8(ё4*8& @^_CQie5 Fx\x$a_G^I,TcsfLoo ";gN.cH B0S@ Դ8p-Ǜ{Q4-bTɭGWlGh WGC~aځ~AI }=gsL(7K%p$Sx.3%03;V|=O'#͹O#3+j@хV swPiC/~%v74E-TSpp^ R[{9 R@#7˶XmX{Jc O?+`W9zVg<xwBt ྛ 5N?߼e]ng49ܚ&jR+AJuz~{?2l^6l0-8UZ F jz4F)͛\Oܞ-@L Hb l}@ai9nro03r0\"8&vPoY+v@ YHa ,?Qax򭯠P HcZt^=zNȶ)*In-,Msju2?QC'F43-h W1RE5~cį1=^OJ}DB$F^<a|=B4|@UM=zu:y8use_6_>˃p(@ ɦC  L\2⃛c5`މTȝ7jUJErJ)?.*F6cф#*> {vEiZ3/Aa nf"1tKGt}t bp>EvPfWlmcaX?YV.F6@ $D@ \"vZ(>=X?3p0l"*[QFW#JdG#e`کT?o^k/qm6|k~:]i#׌0%b::& P HYPo(L_wHdJϗ{ JnA_oQ@t{Rk$LLD s3s66V[ٌ4,-p,l5jDрɎ>u+EWwBG60 x?H nRHK!EM ":"/Jok^UC,fߞ=Yk[du33j/nO7\9Q܎g[{ȟshBur+Z"U H$E!jL=feIAсJ<)xmLMU%-Qݮ DɁR̟5y ^,F{2\{Fѣ X.nH%f KN'^Y *Zp.D~):>_ k>t_HgMKG游AFa[;Nz@:٤0ɡE@ԉ2{9W}1'wx~-;6i%7#-e}@DJ.'4녉,<}xOƣhj[^UkEghfIUtՍW">*\>l]م!>WԎSJӕ`x4i51:)X0k2Κ6&/Z =%`$e20)'Ph5!τao Nt"#PS׈ֶDGEx\;`Y;l"$E_^ 6ڃ{0oxOFLgX/}%7auGq\iӰ爯;wD\2?aCe'/ bj[PT'= v5ǫ8h".y`7O@o>CAq:ӏ`vDa7F&;N/Cniҫc]+x_ BGe;N4u&=Ea\CCw̟6̞))i=(9-s` &?o^{=qt{Ȉ&Z]:޳W'jOMo$3 NJϛ8Kn'HIP+d&,xƧ&>BO?2A9f:&ԡ=S@8!{MjCMRa\1@Ԅh,LEh٣qU C/x!d!(Ќ޾cגP@İ#z;]׉={cO_{2`8)WwAkWKHIP+RiC0xMDgXiz8vYQXS0QЎqm^ `G!1Br#`3+Ņs =)kk-CvυKh0zycۮbC-ft /Wĩs=xknmCCS3cӳ;xٗNIߞ_$)`F4?(Ќ/P$P!G@]rA%F⩻~g__ovr0o{6J&բ64=YWXu"5 Duf\b;=~ 7"\О :'y3%F8NXaw8`{ρ|\;Q=ʛ}=x7P}];_q)LFT;D!u\}2>JDp:E90ȳ@T"g0a^7 3S} u=VP@7)\Ķ">q-a '91@M;tvwg~{nVtʟ˨EJ4Eע0?. "ȳD%^Pqqxeq 'ES+كeHBrC?Ԝ1|:.ɶwǟŪ$ɑ/JONBXh{Qm!Da؁ae8CQ=,wjR=Ok ä/LP U듯D Щ}'DÑ?!-1&IX#;qΖ L!)pIȮ?5!7\y6^yXK?!Uч߄n<%}#Xym$N)]F](htvtv~QЈ'$=‚I'1$M;!C&)@DJ MT\-FMǖ*捣0)- f\qPp8rV,x-Z~;S=GR$(A}KTx!\ya}p^&1)Dh6c݋/e*d|C Y;-mɳ@T!] 0َݚ8 SnKr^سXS;w(YIlHKq48. "='ڡBOX QIoSsoxú1xĶ*l5"2m,khigW/ނ<[eKlCQ~jCk_;U<3҂9zpl;,(:}}Iz4v!dV"Vk0kTq"R,7 SaiLxH V\{,Ii21UKA^q?[[߈ǟ{YaAI-fK&`{7i Mmf\%F?CSk=)!cQm0 1)uQ9}\0'dz@|-TWX6b,*CEDgw~?WDE!)>C7PKP?fkn`ޮtXS=%cM&b[O9 QKsHaPR꣐\@kc~sdy>! {5ͅ;зO7|,]|3J#S'OvGh55J&^z ?:`w^%C9w0Q't/R%z7 "CcKDyM+|NpÕg#73 OcXܥ9 ®*s oGr}b[C%kOrq)z9mOft`kAf#%վq.tu?^@izbJݎi`tx!, O\î8:̪XIoZt- y72!AD>cw=5c[0x_P$5Fhz~p`3c".=97jC #Z>;="1^r0}iU"R?f6 ]jB4z˒` /] gK IDATVߊ_|<%7ScDyULmWaCOc䟰 i{;@ݎ_nII^vJ/n\q4:ʬ!g_LHŏ.Ƶ1so£KfdZQԺMFAIiCGK}p8K[mC#=5u|S 趑M {~D% "ZvI "\4٩xe0Q0! fbluZT7 M5`iXو%CfKk;=XgY'N'*F5Gr|މ*y3s;лVk?zfY$Mp9y+?]H)vm B9@Dڤ.ɮmՎ 1w{Bz٪9Iv;ּ'|ק$ f1o%Ƕa5+H)P+ȯQ*]s9nNa1(AnRX2p ;I :i@KTǵbhG]b y(Z6DWԼs[$ie#5L1CTX KpooËcdĄ qP }_f" @In >;w/vUy?`@ I|l4~uϙ1,Pc*[8._@_Сpw#d/pgFGEg_ExR)I Jj 4q/#n$_1!;SR]3bZ+My55}'BæD3.Z VFi&4e\< ɉ 8L> ASuDRVI XmC||^C,q@!yvLlK)X ϙ"R + "+j\Nws.DŽ I{zM M((XҬFI{u]?oFzR@B9!3Ks'dcL'mMzP+ȯh&44$ ӧL'5F8z _p8&545bkQVY1IjO7]Jv mR&@{^"R+'O w "r͵UKcI{\se4 ϶i3 [utva'{Y$ye%K&BeYNr}R Y,/iB FXr .Zp=3sa&. ES+л'o~<lھS1I>N]Fa='2X>y4J{Б],z,rI{hvH޲zSSlM/bmxI;^r,vL )O N6q:ҷk `W_A3au6- Ka ڜN5zY$y&\@DJad,/i/?^7`ΎlD2fw[ 7p&";xw}ϟ$% *"u%B,f71KnkcrHDJa .DQl8.<[a2Cv=fB|sT~lYu;s^|@:;!bJ&3wepBB\,Vy+ y*I^L>fO%"'H|-Ԝxh t?:ؓ(YƴذIϿ6'Imv?2Z\m6}'Tu)`O:L@3V D'k/ywP$57gAױ({&WfkdDK.Ii3H)PL%"mPi)HLO*M:&Ci&i/9p+y FOGGv(MqRd cOimDWTw1Xj92R%Yqߟ* eQQ<i͒#Xhhjⓤ]%ǿ%iMlCYQf@"R +'O $" ax쾻;>[Ҟ\9ep0^ԌEeuǤamhϿ,o$C,fL?)?wB6߼IFU)h ag H|ฐ I㏆cNiB7މ8РI8\&˘tz=~wP4Ng wgxS|l4V F&P@!@},`i86 0c9$!SӀ<[U` 8uk}?,2& p^F]cͮwbǴ xv/$8#7h6_.FxhG}0bo8'DD2^W]z=+swd#jⓞiĶ_~~wfvYƤS7NIߝW>;6i%7#=u}p"R + "+c% |Ob1cve5[ `εX?OeLr3?~!D|p`:ʌsA 7bnQ";e# ls?^y]Y$'1񟼌D@ X us[$mFwf!Eu=!Vl.,%_?^6. "@} "7s Khv:DRc,c`H?+ -C|D71Ou""`Y "({ 2.kXI{Ve&L S'bה*T'JU`himc*MR>*8@Dڤ.]cBV=& 8~ db J%u Xz-=OL')3 D>*x'"mכА`<.L2I>!;dzÙ7'ʣ^j90񟔠$%VO@@DFVZgH0(,V6cj'wtva'{Y OJa )g 'H&h0bŒ[pт%AS U6MC~Zq.YeL߯Dt wP^r ӑR}O^Ɇ-Gaf<i'[z;O@DVh:?7Ob)n6jcuT~LO$bͪHMgU!dI(Ok@CSm%d?)W1@} "·P%QQS380s% MXZTVyL _x%"Z ߀(p:y'"QʤDB;P'i?Y;3a8!TΛҏbZXhщ{~$.eL1DN -V)rioBG& ^̓G`NQLYƭJiΩp%=^(*'˘Ja?i DQs8'I)7D=`z' $]A#V,6ubr k?V?;|e,cʍE  "+ A ?=bm962nkTn۱{|!˘rb?iw "%ȸ aD=̵W\n!,߈E9e̎^l.<>&"[xweSL'՜"-& ".[x.VqdMѦYmԼ'ĊͅK'x!j;e $"%ȸ ao w " U`,U7p:\fwޡCL$6E2f_6brjDy1to9_Igmb?-hDE q Xj9$Yq|0 N]SP*i?\VעWp"Rp`diP^.DŽ I{zM Apz@DLAiV+VE}{ L'("R+C . "-R#_㑕waIq (,΀!Wlľ u8!MͭXZUV{3Urے6&q"Rp`+e6`Ř?@9E0 d2{&WAi!S'mVA>^r ӑR%˘&A[EҾ-x1`=iPdWD~ "P]ycͪetDS"2N1mhL}K<ijO5WQDr" Q/-e֬ZXI$L,MepkƵIKGBGWR+?"$@DJ`vȳ =iԆX AVNDur+*Ra{&8#@uBCNI"q 퐩D=j*vDW`BV=& 8w(meoBz8ϊeBe4! " mxd]>e}\C$ 3whk6D""VhL! CifsV-] $qaS ӀvǶbR49Oœ"R3Ko-`4b-hْ )ʆjTB,fL/I$N⛙Oڢ^{K4Koqʷk,z,rI{hv =mz΀N;oѠщDX[A-?N2g9TfgH& fň U|΄D3dfDExFـ~FT{5\@DJp@3Y "QS'JXplꎟdtzڕ0E!.s8@DJ.!^Hx:͙1 AfWޡC $7D>~Jt\~%NR "%cߔI}wK Ȩup丩{cyJ@ ". " YXrJsÄ#=n@}BϾDweOV_+ɈHJÚUˑ$iϮǔ)Dň:jZ/>0 g +HT IDATx_"f2ϖEcFq:tN-p8Q Z>7p) "?!AX}(ϓ Ǭ]0^+1] >C "%@;X@D~7) ^̓G`NQL!>9zGқ$~vMߣRf@!HXr" N/^;n I{xWF"-hpu`÷[:7H௻xYl" 5Lc[;AOa!xw]!3oezm&Dtc,si52" ބ\{ 4W߄變~#`rGxg۾] CXW Ygx"oPb^X[Ѱ~>ۊ" sp6/XΔfhq@% " b ws5 6 `1{gV9+㔥4g4cCPhr;DJhٸ-wc@O@w8qIav " --Aj;t(ܓĦK{ Z*|/iݾ\~|?DMc wek&Z` 5&rM&b=w 4$զs ^hiG%moy(QmW'66ރq~K|O2;Pze+D|//]Ȥ- ' di:IXj9%Kڳ+<۩s3[ʿi9X "K(\0,8{Xp Ȩ_نvױnúO6x/`t|jưaS4Hvn " u(>$yɵW\՝Z pO ϑ&'^|Wz/h( CI5n@kڧ1lݨji3Ko-DB\,*p:xܯ%M>+>?K4R})pڔ}Ψ~v z5%D7TY@{)RS":zkpՈ?k ጔa s'y\-NhΚ=Iq@Ķyo]|;\LJ*P X~ ?oۻqD LNpW`SQ'<,V2}S9=zNG۰p32d<#yf} 12Vh S-4pH>s *ҽ?=VkC:UrTx/љeJn *eC:T^̙33'} 12CZS =f+=>,Ψ`(__~}+^=|~OQK[ppD=0nI*&:Ο:9S8qK%EJJ\{R;-o7NOBޣ0ɻ>)C1u+6;_Y//^޿?b]{Ethz=?K/F]Z} o[ {u?xOSY?$_uQ$ *spbc~MZ=HV;_`/$(qmg 'k4̴L˛:6 RyGx/Z#{\]f%:XY`9i2EϜ>|^.9 }b.Pl|OUZ DV:3E "6$_y82:eM)svȫ%aWF;Ϛ#P }u5'gy61sfW}?ߊUSl3}+Xڧs \N@IM$7t3x_Jt^ 0yG98g13wgts`y=s 0Ůe@ؤgKMjOaDD +5_$9Ϊ_YSu5?Bt΂ b/_FU0~;zOD_^STicۭ (b׊ߠ?K;@S\@D~L$S2U5ǒC,fķ1ӣ~:` GpoE{pZL$`lLR&y҂cgpZrn>rn>Vt=n@oMVػUB2#(9 )0zFKD2OcH. ڧ@\@D~A5_gW[VEp `W~ E(P}rҘlydF̬%G1ɜappg 3OcX='8lgA?Z` u*XO z=wم8uDJ^kTC>a;{<_xfW[>aoF՛> cN""@@?~g>"\1m<&&NQ>Wx/1 AMDsU5Xqooƭ%r>+;7i9TU2>jo&>vd2/i˪_މױ(x{ݧKM ه^PCTcOAӘ-2U?^"ۘ@J 4ϑeVy`3:P:v:E!ן荥K0}e DW ߝNxO<4ٍO, =ISD\iR44"S߲Kt[q3yoEQ8u_ _oA[g[ I+ 0~u Y3G'`R$ar8Nm“Ͽշ{Y=QDg\0Vh w "1zF$",3u,8dVzܯlC]fq䟔F)9*uziomm]ocI{GfFOǽ3Z3K+9i4~USX_j,1(r-iw ]}_)u0  لgBg8iY-+% 2 Sg6J>r);>mXX!Vhl1 F Ň$ sf2Pԏ8wٿ~K!'5HdP iO܉Sm?G^~TJOT(?ly{ > 9vt;ih3E __DDc%I }R:-@zm 6˓dH X|D#W.Gwf(?I~u)~ Ou\mNy8St5P[Hā)7{ Սt+sv} dMo9D1Ԑ2.3MqlzE{oWhc]j˗(р[32:L}VdjIo_~zCNҀɎeS'bJX}~W tPc T2ȁ"'_0rUH3wx~[P.Gak~4d.8d;_^m{-K!N  !PC e{ݖeIVû+W4#~'{cytϹs}*R_uEA 7`oVG!  *jwZd">XC,LBjp  Tdr s{^m굍T&~&{N౉ Qؤ T^Is-՛v"AxB/ e̜ ޷#m%Qacw OT޻x/sTU89V{~6LK*icN^kv570lFPsv}D@ 6@\gHMrňU=o]D tA&ʚZs{^)|(1G1WH s*c1ÜFmsӟ{tzsQU *h-=ݡ/9Yr;@('!js엍I#\tD@&eFa@Vp5!@< 3B,E(Uuquq)$sl{/o|M}m4IŰ rˍbL:hM0m|`VzQEvq'%l<R?y(G~# @%gNApP{qT}0BtW#/Kډ8seUnK_Hvś~ CvA4 ttڬ,(['͓' kx!A+T !O|I_(gRH@ p VhmBH%,36ƀ &,8EQD@pWn_~YEvYn;P?gXՒc]#Op1lI WI 1uJM̛Ip IDAT/V}hIvAwcPknKO` g1xuqڸAfІ[K1| vB$ w,FGN,!m8(8' PRAJl/5ΣxH+shP|m;nN%h?gC[qdl>Jz< q` Nal-6ʶ 28m8 =@ D@+ϥIv!58E sa445=/V?=VW>CIY m: G"f'[w&5ZlR\6b&pR{"! `#;_2ՂI1EdC&Ⱥ.cgzGMɶ n1j0r#D=H @Q5{bUQ4vGr= ԑф{=/ l_kO;@u8ಈl81Uw"0lDvr|>ݻ>t+'f8Mpl<=@ X~#ZmCQzݰXnK2Ǖ&V "H`Ѽ ̭1†$*m3"fXM,ju P Ԥ:_$VE$IּM!hhh!nja#X4{&Zy[T#t8=6sNLjPՅÃ"-%zAs BId( jb$,1ۼCY(jMC%kp5"zB (!pE,VͿ?Xq͘@]@)]sbh5kqq`%(7.;"50:/!-rxVz"^|*8ۨv G cM P.$b$.GV@w\%(r -WHM4& p쁙^AZj!}Il}M!2e=/?#ʗƟ/xfV F` OfO;jـUt]a7[Pv8 >_3"9'#B`2fp@Vp5 Çey%*(=:U"z/ 5X(k೯9%7KL]&fBf͛ZkT?vgysx&GWB m! A! $kAN96:eifEU-N߇<0-xڽq@zQy>>Bxd%~}|Ϩ?z*ù>fd.O>r fی^# C 6؉s@|x<,[46Q]PL?yV7'%<&wυux/_˴ #GsxW0Zc5QS X'CTC4:歊iDVq d6j~Q .\AYnL] @YE-|[ki㵪& )]~Vd`TZQNQEgE|l,&\ّ 1ǃ/KFPV2b۔n6'\kL L ͨړcQw l*8Aܴ3<>W '@a¹N@zŧPkαU@)gO~h&ip9 p"71&/ J6>(+/<}7mE+=Lakz_.bNL2Ptl\ Q^5L ( _pHjid(RNEs e`[XQxI^K/fOmFCc۩dDaM 4pgTkYҶ%9{2 ː$PlqVZ|…Ak`t&FKu`ִx [r<ڝ~'c>"0ϏA>C +z!A}v*=z ɦ&\FlY&NsB@P[ѥnk8P޼y RL|M-4*"ƝP?Nsy<X>?;cL7˹S#q9Y36 *kBe="G"f·[w&5tG>91o!o\Hb~tع0 YYߗ! n+J7B_Ṫ}Z?&,  AA ̙>GVf U6v{^#'.Oo} g{!H/YoTG ě!=h2c"~TIBPC#+1/翟x@&y8i_@Kq#e(I@)z gp囍lA %l~F<6a5GjydԨ l޹y jx lO;h_Ċc Q}'*c <<|b<Эzc>y/YeZC_ DAo#<>fbƮB5cL79lW).>Yc~&HEfiܶt>xmDre$D6 Q^o޹FsҔt:#^8G2Ș4[G0 C/'hQ&O݋s&kޤl&SfFKEzi4m<:* {1xSHuV=5⃘s'1Isy|G `"8+كaϗgR8(ZT QF?P6X[Z{G"E3#ur"ElBG}m3D}^>  B_ H/U<^ Vf)jmLse̞6ORU;nAڸM١lKI.x<n]4>cp ~A xn4 skK+D!J#B2( !l\u;Qp(RRŶ }m›Uok=Y/*L"īPּ|]\[g0uhm&& ƍ2 rCdeF  cic"? ST\O #jpDQ1`;p%Ԩ1}DE ? tWJVܳdkXI?fIܶtuzIx@Q ]%zv |1HmhKqҊcur.%)KOh;I{4xCOqnƗ0+H`&JئvlD ܇ g{9HEyU[Xe1!jvkU3P$ >w gm3x󷰸o=$187>sZESH/p"tnCyXq?ut ;- 'd' WPHmġAl@ 0|XYr{^G86˦nK60=v^y󫛜Z.cW$y?lH:ӣ6;~ϾZ{[lz:Bo tWQ0$3cYǞyuƛqt(|ܬν+а3E rd$mF>m"' Xp.m,}OS4o^nw_lw?!*"TCbU8ƞI*px<ܱ|&}VÃ86^{sZ.Ȅs^L_ , /5<Amh/gی^!?}f~%o -hjiCGj"Gsy^ mے{JˑBTi[?~tgUnFb*LP@VI 2bhRv54l6;:UuijD79 az_Ohjc׾\,7[fz M<qp e3 Vڭ}VW  D"ƒy3icnk8PXOj[n^&>\#u>F\L Ÿ0q=f}xw]:-AFVC㯡FDK(Hw.YQp@P qY,/ֱmJ2 1f 'Yf9m<91|^DLc2[g)t𦂎7h mEQȖ.;G֊FE=M:9sBWP2`I , R@ @ $:ʔ8e&AT[$\ x j`KQ$Z6K=ydQalA (2̟5k6( ,fQEjy6Uߺ-Cwm3!0# հX{Z2jSN1 3ҝ9Yx;!JGNLaj-6;_pXļek5ihA{ r B!Bf |`DOq .&Sb!&$<:$=AIH[>m3Ncj4d "$"Xki_*NCre$CGq׊ qfwJ_vaqe ;Dk1b 6z- ';\(.c4u1lv-z{0= Rըp MkjW=pgsnlv9U;9| s6^E٫(r-D ;#b`a"#Aɱ'q`7Y6ljj\6F! B7l#Jߊ¯\yk|HA+dx>y(gr|=f0|>!,-=a⦍~ XĶ)Blv,h5ҝwә::fM03XQg?[n㳻D@}aVRl}-]Bm@So *i-F䦒#4Vbb#+܌U,Vwڿ_7Z7`ٜ4 ʩ/6 r.K 0MLtGOv>R#^t܌&Ī M&l޵w޺m {]n+Tw6le ۢ |8`ڸ*:/?s[+P1رm:}kFch+@WbL^ `͆5uTT-Jq|QA_R91' 𽢔DMuR*P\нT3òs @gԙkxa4'jf5(͒ =VE;tFl~v=&ij4xFu[Ղ`BZUuJGw[pͯ`7s'5#co59DNaۜ>A3E}$~l%RN~AdQaH[><w9h'UF@Ƞ4Ul-DM< E=_LA9{ fz`+73DuL 2 FK\J+-\M,F$ bաitk^ud3tJZeu-1#ݶTC!8_W6rS:" 1*/ו*7HJPgEt064cCس?E)PjBaj-tL*8zUbbapΛevy/}s:cmi_ƶ)Bp)|3)bgaXn7 >鮈O!ptxwEbq.h=x<V.?9^jU#܊G5_Lv~&AR]|oRp5ڽc' A*dg\ŝh~aڗ剿&2jXH/F\mM'  0sHܶl"Cnz?ar8*WPEݴ&D8Ibűхȹڶ~{/"Uj@^hm0"+l[ӄ mNVQi9]كܶ 8.GU{jDj0B DVzQ93b^ی [aޮOk^ '=9"3f"<<B[RZ]7\ަ]4P Qk~n>tNS[%#49'ΞGyU c{Ebh[(50lBt2xFZ= ^TUc}8t}O"NۦckR X(k_.`܉X<d. s부>Fjp#?:Owם\xR'`]8{ |elB;JQr8zv<背O. na̹4HM"CGnD"\s)TkQQʜR7)YHB.Ţyx$(sogAHn&`'!EڿMpwt7KE6W$J57( .b杸x54-(J6l%IGA`=+oAtd8ck/nq5el4l6?rkByek| 1(N.] q Hln-;w2pc V B>x fNm~Fiy-~YO]vǷI f- Jd ѵ$ÒypeF@݌BfmB܄EQI!څoyܕ.BWJP>&ؾ 6؃f؄vkQ^qr"-v?;-Bh0%QNY;x8mcVDV!ZEGrP*#Kq:O< iln=a^\QZT̂jU#kd} E_hcąD Ũ3#>.%˸GYE-~Yr/uWkQ҉xYE]Jr,;ObLAIB㹮S|[g/䪛I\@QtJ2qI DW'5\*B&B&lCYxs3qjx ^JYS.?(-ڭ;qhn(҄:T4We 9e\2rg7yO>rcҠ?CC'wx\o:PAI}`d u%-B*{ͮGV 'ዄHxݏ65\P\L HHL }% X!Pwe/E Y8;umC z]py(JQCjVut3TumEZ lݽ+g(BR @hcR!з͓' obW; +f~>w&p2^5kR];J,]8 L`sCI3K^_iR_E2ۯ7L yH—; m|Kŵu? @8Áܼ y6\+*q} D MV/[5)jgoۃfA,&m|x gOc2BoJG3Ec`AmX,ⱇcn W˰nAn:.iqGE0gXvȓb0gp7AycH‚1/ApO@܄(H(B ;bb<wz( REq@lj YÖ]i>8lo@I]}0EM+fN̛1\MðI (EfzKϕRxK*4I$ BX\d- 'c̱L݈=~y]"W)0?CDM<ā' r3q6 uQJn-}J˱an?zV-F$iP;'R7(Lè)?o؊iƀ'*Ya`4( =axwz_W.߷l(KGq6/KyS☛3 :* KOYc!p[Ν)ũ߽ }C5e$F4$Qa=_! 'L Ii\"P7=M^/b' wV{EP%PH%PʤmIII!}qoNN@6G$U80orT\XI@ PN5[v.lAQJ^` R:Wlms*jwcGv7v2JRnjhwnT]Qi/MQpϤA.;y+́wr]8\?^.97tNw{ }KwVp6KyWҀ*PlEfC'n.TV׺Pۈ:MYQ@&ekR4:Zr[(P\ac6n'c`2yO\!Wiq|>~}",3kv EQ8}V݇bקfE)u(kQIq(u:Naʴx!@&W~;@EVo |\ ݐp: M(>66^h>}q^/ |D,B&uw~S)TAyyS/3ZĪ=o#,GSu(VAlm9 EHOIN78{ h5hTHċO݃e7Sj>UN2,(JCE;buK!3LNf`!9͎6ʻf`(P$G2(9oa9aAH{`)X sCs[!N__C40#bD͆@:! n/+hܤuʤ@*4"h("=R}8XbVN)tirOTB{>TvaVR,< Wvpku(N@:KR}B]ltp:ĭJU{Ol,9Rnt}m{H?pҸx⑕5vA X~?**.1,(LQ2ǟĪp:IMfbA.%9;|V<`0v. AɈ[8@XR Z K}z-e@ BA*ʔ86x& AA{O4XS(""; Ð0s4ь2~h+x|^8x<6g,Taxm0\[4[ BGr@nwЉSXeJ]^C(ԨPR -lKwI/F6kr Ċs1b`x<&۲y҄@BtT4QhmmAf|Xq̙%f Hpk Bq8(Xm7m&*^xDx<\:w(z>TVi\^cYPV輸v>"^ izjn_6 G `Tv?p݁o@S5UHC_AyRL(nsLOm12`Bњ(^ʺO!z d>3FJrqk4"}3;' ĘxyL&3v? v5vZ$i`y7֦+ie\^#1y(,_<ץ Uj6ʸ:KUX:EN&b쩸ukL&3+8}6nYS &=2m ݘ>ygb cf~Tոv[fQ˕v>"^ ٵ㟑ۗXg}U^TL-ú&6^*Xgbpe]'z Eu<'n(Kl9(+˖Lkg$}&b&dQ=_L`@gSPr/8<-2ًNsUJWCli ( 7mGmO=)2Áܼ Xi'.vy]]d J5N!-rG0w$#5 KIgpL0{vZk{yOEjy*#w'Ϟɳ18++ؑ9lܾ_Pb> *P碎7xC͎cպUSP²_Rm,M:~klA0߰mJ@p)ˮ9|N&|mϟ WD #$c4([8:c gfSe6TTSQ50zC}{ 냑^BXk ?ǘl,?ó߾t9NDQRlo`Ypi@5H+rl_7+tƌnwoƖ?{yG[ĐKİ6x{'5YM̶Y6iӑ8I&N4N$Nv6YB 4~c0󟯮=q>9.;Yvή!G^M׬ ğo"/W44= aۋ`kVh~ڇa> 1DEW>$Y߈#/}UAg p찵[@g2APPlu( 9d_V~EDقallxiGMI:X=AC6 ra}+L&; W>!N#G{u2Rև <*'k T"l Yb< a֎|J.^q9bB=kSM!6{`h 3"E:qSN'Wi8\Lٽ{؂!6PnfɗSh\g7l34^V&U&tWi p.O@Dj"G!rH3&@aE*dTBwlll2|6!ZĶ=nx uB(Nfm $ ۃaWS'`9 "݋u Y-2flRꡐX빇YY~6`N>͜ w^zoMنS9U`QN/ N hlxN ߌdjnP MO}wBP=4/WQG/+H @&P`AU `TGE7ې`%~f5OfI.TliìkYk},~$G qXH&fKS(a kO'͉+ih bؕN[ J"q!U߲y7*IMLic HQ{_E-S1oTS\!;+ ucec:PF\wWN}’0gAqo Z\)㌸0o>Ӂ̉;, 6Dc!OVaD-tyb` ='q 4l6?(m[:pyFp8v\:gR} ԎP8Q|,Իg+=@0>Ujd7s@?P \*vdmin b>C z X2L^ջ HSb o3 iZ69zz  fO32xZ;> 7W+ף,ųU#؅A46yN"ϊdBV}e&Opt^lRh ~HOPPm+.hYgO_s2c >`m4([i$!1 E-Nv1S/Z=hŬ3  A Ĕ@$ӁS9U,L->n06?~ǐ"'Mظ}/9vI ta`j!Sxnq3}ϛ0AxI\XhE^-Zm#*Bc)볱fNfC"pCSs neUZfQ|jEonGy{Z<(Kq\ r!? pג&cjZyf}N} &UY0a?.sB-V_xU0,ZS[va t<'<(3A!\+ 2Ia=Q(;fLAXhptܹh.>cPkDL'4Lh 2e&е[mA?Q߇Ð03Pݴl8 ~+ <__!Y|HGG'vz L X *AWq讗aASF!?! -P`poz0 CgQ gW|I9`paZilj dTB7-VɳٜiGM\WX38mUbb0y(U0/bcDx]Ӷ=ؼs[m#GK2-MAE.CF WxkǐIQ86N`Ŋw>'ΔouHZC}v1 =Mmؾ6m+Qꯋngs-*L ]fYrezpEd`ǯ)G״~=/+4: \Q>]h k yTB duҜV+]p}E=ޙyꡎ7óۀDFdfL;΅ *"Ȉp%4N&soB*4|QPK ES\:ހ F$Ut:zfrTan8zҥzZfT%)I$Cl$EH !JHsgbr_EX2v?7mwSlM\d_"RTUz` 77bc:P%CЀ:RZ}qϛE Єo1 bPidPIjetxhtҺR\yV.RbGyN L; g 87apwԯH{.d^Ј5%AXi1wT8 f]Ļq^V-UO*gjՆ#ySkGOA`w怗J+8q\4FR6%RRԢ; 8U\Ǽ1oV4]ԅ,\*Ć+8nAwBo@u=t46Ǻ-p4̙בE'OWjp9^)ӡ4֧S-B9S3ϫ` ?m9]N4/ס%+%j u9l`ضfL{Gon͆q9%>xf\OFaW]h4DFfq[&:YoB#^OI 3A©⻟@p‘R+hE4_Ӌ<Ň`T&yYH( $:Q(έ@d #Pg(d>H_JLgWPid"V&yN340Y\-VAc܂m{x4c:`Z!Ub>p̞6KςH8uoQ M\VrFL-&5FT̥  Nl{cHSkg8wɵ-Ċ#mҫ$Ht_='^{u7b"sԺVR1Fz|acƴ(\4Q$O t Mljs`+_%';AL|û_pJ+“Rk1Cx6Yо@$M/JaR'xڹuN9V<%.:l޵st%9J8V&4G]%2"gN{` gP p#AT#Db1(OR{#6G*n!Ea۱q;rpoB!uZ=\[D3Jt2};ȾzשF,&KrGN߈u`ρ7tg#EKMo!f?3҂i ptf(%P Qw?-^(i-#^Ac0#А4]z}L#apگ}O",lS#8= =$"م:w钋=\ QPt oo"Eի{z(\0& GfF*g o؎gJ\>'4 uGAo!5xoF05*e:ȕ1t)88{'#w,[<CR{e?:ހ Ck|:ce!8 5Y/>=J/ MkڏCGy\7:NQ!KD6"]Q !<Es&''.PpG#~^}v=09gzD8,A KY Uu]ƟLé*ZPW!4^yTZ +$%>p8(:qtD$"Z$4!E%߰!(\8 9ÉI'Z6c# iNjQ'io0YPk4za;q;Qo@Lp_,1M!เp|y#DJ@>O-Io.kMn5Ah\4"R@TDED{GO>natQȶ\;:YvYa kw3"oVkv(O^9q33B!գ=].rm:rstl{ޱ%x6 ̵5[y8YzŐz\W!O]!o|Oavl 54FqC8FyC\KCw/Qo PtFTʴP !hJr=a<,3 N@hgPQw?&^w^+JR yh?׍N_'ɋS€.W8Z21Q_}0ZY-S6[,+Kd>ݣdeǝ=N;|Y2:P1滛@L^LD)J1VWKF*|:椹'5wlBW|݉X#$PU0x,;$B/)A]O @/W#4g%̺yB4jƼ(¤Aޒ}`I?a`AUuq L-gs@_$z Grˑ[w(BVמ{[;UVVa8rں"ڡHҡ^S3om Y-BBM}X;Ĭ)xV؄> .Voĥؘ}6ɲ^ "@ğU(<*zQ3*NF]Aƈ/=sQqSp@ЀJ.J!HSH~(/ƺ%! .Iз/)#!DvhPDj"\{0G7~$`< P0 Z15%L8S9l (\d4!}N'Ϟ-pJy׉ZHQbJ]$z9eX`6&NZY|kL,;F]L4!碴;p;NF  P_Te BۺHL+>Q\gf#8V!i^i|ic8Jl"Ŀ!D6G1gF`H 0 v{߫LC^@(ێ@J;Q= A$/ o1p੿ރ|jSTA {ZXŊ_&&Oǩ*@wm8>^K~/1&g։E'nNTk=^AwVE0KN@l\)>]YXpMl|-|5}k J^4+$+.=\ eHAUt2 4FD6ƴo&)cJp]bOg XLVtyvZT% eV%AdgcT$w,yp#7(@[఑\0S RWm:Lm[kVƋ&0; ᩠Gb?_Fͷ?}E%Ǥ_T =/-Nlھ&n6x;s4G!E)FX\&iP`GU+'Pu;QZ Tos6F^Hq;Ȩ\)**VD' >q#qQȾZ Fw.݋jW?{"%jSp1 HSpT̚ 6;B(i?m_OD`~j-OWK:it:g 翿A9IrQ*:IUR=ZCu> ߺcvv5ʲ1 "Y-yG.4Q0gȀG݁5`O[LaW%BxRM4Ź߷Xq$KdnA+*t [|: <(EF|x.s{=ʐv8fkmt$S }Fp${q/Eq23R<#Uj|a.v 9h ^zq*hW+ޭ`w218\_!F$A4'Dj *bQ "(0 ns"7ׅ}M0TU @B_}Pz;v/ xp>I~rdHwxU8q9`I'q*G怬.sXHthh"I_DHQF]ψ .#ndjGFщnՋq>k7qHv{-3=/>0bD@j>5a6_\](ňGNabh.GH g_`tgc8p)Cx oa$ݰd0pO,+Hx ^xaܿk7Et]/!n!2m &N,̜:<IC\}$Ҫ$=2Ibs4L_.I_܂D OKgV0^RZXb' <%{hd!} n}t:w)cfcػ8(KL0t$jHQgƬqǼE-Nglض)Th zu-HQ^ q1bG.Ou1"!~>[?m݅' l Csx;*Њ vcX/]aʄHG0IC|]Rb9D;alC] $4NdS9:mv V( \'z"M{b >EeB6.J|do8V&d"$D9Ipt,5 |~sZw?jq'͉Jez8i,,d_LP?|.p9=VzCTD8w)\4væ]{a2J#ZB0$T$P+ig7f\ZTE 7LĨOķk7b99ubzUB4 ]J$ċpg4LJ@ R1/}Bg1F?BҟZn$3#JT*cmTNUЎ8 i :H"ǜ񁜙?N'v;ϿVg@qƨVˉnEp~~1ntO ?,-]…s_nֺE)2*%#0ȦJh@uq(*wzV~nYSx |BɳPW3ۆ!*b,Y4S&ğ@2H ,8@p8 gQ/a/p5spOWD Y(zSeR,;S'n?~_<{&ZNw eqj 9Æ'P{`n>ϜGOaO[׺3YԪH/t'jbH7#2Cńk7㧭14,]0MQs5_n3*԰Xkx{'`$'@G\w7c9VƟ2v9dji4`tp詳翿AuwƲBFM>w͡ȹ uK,&[KDq>1E'bMPk\`"RdI:t]{:iVmt b‘Z%Adnق7m]0{D,]0p,>onvQ t q()zKbpI ~Qw(€_Cp_"|ju9 AG΅$sP`s@3STGq,L/ \p>aX7cǾn(RZ4 Uȫndi^գ&$B1ihLcgJm(W\a+H:$=~vq j*FW/Ŋb PSltHkZXIaْ|xs(k:kD|k 2dH &vY&plD W*b*7iDE^凘ȹ&W):Fâ9`1= N1#1~H\*vs.0tĐUPӈ^h^hByU b-6ɿC|,ACBi IT;Y$'v)\ @ Txwx뽕PvFgatv,~ءHVك_@;cNddip [nP Woz!2L H6'q̌T,Hť |aN\ty\UGA#iDL0MfDԪHt4̠-Ċ-4F8+|dH"E)s.OIJ%1*'#A<ax n?ExݏWęk怑!x<}hn!E%B6 4K4@#d.\)w{Mo v'/&BwQ;!w}~113=xY(۲pYМ] u[PR-?B~.Ik;hu2Y81Xgj+X='iXZ0sԟ@.(Bߧ ן V>ε0t*JԨinNJhgc? gcLh9th7b[ٝ(ɪ>k Ⱦ趻r/)|s IS`VqC8&Tȴ/yAy\+ P׭$FD;=/˰p:82/ ~R@jT.LwA_^3duNJWRk]:pȐ'G!v3>;/:>ڄLfwtnty2^~QJD2b%x_~.wVk9>D |4FR6%Ɯ`a#v_ MO’E1fPA  QwO F #MDB9\)F}Ks@DjxfsND8J.^}?;Á:T%N\\HB s :̟*Pm!"?x7c>ڏ U1)h 3JԐ?,9ա?Aw?&d @S~ۯp.3c5sp*[ Lj!SE1T,/z =c6 jvB[N Z!q #ŧAfuGp̟]Malro!i(zQ! ܡIg '?0! AXp8I@ EpX9`x NTNAru45B7ƈhv>OM6Bߨc/PTwUjNN9,d_L!Ic$``n>fOn.4.焘,GJ$= bo°C!xw?-D@ Li6^5cǹVƟJ1 a04]0nT6htBtbˮXZtt*@̼g`jzH C`B(r8(y3'ccqi.,]2URT ؘcjْ| lˍ@ -TP N i|>/cQ?NؑQp62l{܂N&2j`cy`*M@BÇ' }`daNd̚6 ďCָñ21<re z( =s3@@p@ hZ{H'/~S./BqX2&b%DHO?>/M&L;. Aw I b`N~|:i0u|.N97lEie9N] (:XM^/@|@pcH >#23>BMm= ,4gNŢ9p&_,V+ؾkV SNwhN1H!2i<^zQȤ>{B0v=%Pr9 ;*QkDL/oA v2`d @+^G1u|1iLW*b*h.t'uP$A΅$D6h(_S6+8G!6W*m8y3A"VZI*eZ,FwH@|@p@t É7m굛^Woz!2KaB *?0Fꓸ+CRŧTkm8t IC|]뢠7BESD @Q UO 0z\ W^q~h#X6]N@\}knjij=p~Xc&t!glؾDG6F]#Vz IDATP)B+j(ۃ(@a@CvO/AkpۆsЊVRp-,l6 ]H#~$F m{y>XQMSp3*dZԉO @p@ ha nƧ>^hBIVwnt]N\xG'"l-C,AYؼk6nV oa9La(d:h$p "H@| ,@@J+VBNrAwJZ^[ȹp8NC9x0 _Np~+\%ga#qv]V./HV)R*/@ L_~;R AY| vk6loqSڙR1 Hk7xG5$Wn˸ssz3+cP%AC hl4Q@0D?)Ȃ@ ԙwݏ@RRZ8}9V&F\Bڤc 4$; Tb072fNGNPS[rĐ8(PIPG'opYq?fL,9աA<@L €(jl94]*G68v0x\BC*?Y ,De I$׳1r)ہajZDp]aڄ~ڊJ9N&*%HVQg@L׳DkWx7koH (('@R u&6(0ki;7B^10Cy> ?iPM&|qLku1M8?^!Eneg OnSDS=û]9iHQQ /KO? L ԒR`z!Nzь\7:\}\9^{_x! BM$D@ 4Nl3s(rOiE/_߂{Uj?a.ɿDijVx*C\7H?@I&GYƁp]Ҝ!CxRb\?|ߟ@ I@ T )՛vOM k`GѮÁ6mK{[EHIÜ`!j u9.}?x7ج`'|4!/>0>[Or;ku?kt' W"ErɄ7GN\{ !) M0Q ~֎[CTbߝU50v#^yaAAN0R4{'fu20 #.I.=ƍG]Q#|; GK{]} ήPDEIJyظs64hu`LIr(JӉ~؍<%`1yL nfګ@ (*%8;Wh'݌+Wݏ[pp|?Aвx=-wKǟ_'?>?/-3cdʮM"EßWc?@ >(€x6IN?VQFRQ^wV9 Xq1d:RT"4:s',v"4gp;EyeE\BL$);+^\|W*^ }o]^3YP42ԍT#ĤoṼ$/L"&:%*(:}#~p E)8Ȃ@ )h TfÅPM?굛ݾR=-EKw 9V&rKR0R"vŤ?aC|;a`CsIsb3l-;R@`.(B@<|Õ > =t +Z rDɰj-=>/&麬 _܃$f! J^<u^f'@f_oFu=Lρ_`@`.Io~7aC[[;wRMQ|[d??NVӄsC+acHE,djk#23S!Z!9ޡpdL9 >sIhҳ 4Ka7@pI@vBp@}vAڼEO՛w$g_Ƴ-18Y#^'!|,-g2oBIOmPi ( ƨV%[NHQd[lS `,*`[XǨt4ejcwcv[ukќ4ȕb?vkq_"sF<yLJhb.ǫkxyǸxE! ._ Bp@<yC ÙdQroU~N$=Ju.&g7gf#04 o:,= ;@ iIihRB!0UFJHҲjЖt:-l'qȶxoK!ʍG>v;`ȋ$vP4-Q#>߄(OCY^,*"?y͚q NI@if#M~4 łK!1 HQ >q#"e`4|zI.l0WNxfG&WâNcVcTExmִ|}91M) .A&)B)qJ?֫+ "@Iյҡg3G}v9W~>MίB}|GkÌObܰb9be?%-?Wgjh)F1}#hַ{W!*2l30A1E )3;nH/{ x9ƈC 2r@M<8}߈ I6Ѡ%=Af[G2̆))^{W!;3ك#$"g]mH!{XGfɐ=,7{h|@@ ǢarL<59 C;ym}1oduHD %D'k JQ..2!b[6l_pzP4#;HŔ)EΈ}S'jDƥJvɎZtD*$ۋg^bXã$_V@fOQ <3 ==e Mx-8V|jkM8miML?]06\a!3Hys*E f5ncG`h?.4jyBD  0_i^3ͥڻFOO7ЂCS*>s7ct a dDT`ۛc1s{"T#r'pPS _,81ɿڪB;3`?I_lziU5ҋs鐵/.C7νۃ;f8(9%D Do{zCT*dqdc3*{ͱITG6;UEtdHMN Ƶ˿-$┒]?2`KW8_ckdq;-ǿ阈d5 2xnt+5C uDfZ<;(%;Ng4dN#,ܣ#m|q!(0p#gdV#+ *`ш$733gBcq߄(OH~Fdx8~|?۵E HX/3dgc\;v),h.5pߝ+@p% "\=aʿ&![G",3uǵcsͭLk&ł#k,j8Y_e,Z?);S^2-.k:DލJ%k?Ptk7f}k8(9 ("RV/?MHHp>V`w?+Thj%,n Ņ'".Z֮ U+؃?FLtGy;* wb%C`o">zǧ'ЌsO6E^QU׿Se5&WpPr@PoH<3 rR.潸ڳ"'G50OcbHv y0!Zki)x.ٟ )IV,_{n_mseʦ;$lʆS+PS/koi5v}%c"? ]|Wʷ.Ƽc}aL|ׯ" b[A]|Opʎ:hUNXgf@Q !IbAQ~"<+ {F♗~v]iB;ՔJX)P]^L?84-xߢ +/q}D~ ~1@D nz)W| H?ELǢ7A`҆VS|?HK wԺL= Uyn &\DktnF;yJhqxJՈShD$6ECpxǷ"<,td"qۃ=KCX7 RW ;1]~mx5MCID %@D>h0p\07zDX-3s7oAOO6|ۇ8ZNmU!d A`<0)7 ?| G!R w)Tn;X UeE9Y/l\ 3P,koh4@Ia}2Dbz(`<~=)(.S&TsT/49$'!eאv7;{ڨ?t^|c VYUm:^13f"(OEVUXqŷqCo2d*]z\$E?Dg#5_K? \ ]ȤjwcTH}@{zԋUe\~|3.`["Rp?Mh2 [łx :ʫ]Kw7l&BTg#vfBRFݟl{~?ـwkdV3ddAdW$"4 *|r:! ~#t#{L/u7c [ "7 *`шXThÙXV o1 o3G4B3"b0c(ɚ4*@a}<;ع.q*% #~rܣ#mK.W!(0%c&ROLFZx~,oo}:q&ڱkn BpD]ޱA':.pPr fO}%;؄]sN8~ēh\kdx8{X}'s]idd6 ./ {*f{X7v/Akd}XM4ۄM+AfOT@fܙ64f5fe͙><(揲9% Kݷ_˗ȮZ ~d[E֌ݳO6I^K<K8f3ȧ2,3K{\T[(.ܛ:dB \!;P&ڌs2n``Ib%k:WӪl*2/JD JME\l$~u' [CL8$4]&L?v#"<㦕W#ɻ֤8S".4Xtd6%//?\`D(ơ'~>N:) IDATsz'qAaإK~А6.aOPUG'jچ^xt~wpPr@o<1Z_#T!4Dd_Vaݏgaטbu">5O_Y{zu,FE-fq4͎ z̄% %@D>)>6?i<\sŲQmQk(:qɘvqk#FMJjJJwzVZ,YrZ3cZ{)TOOjpDJ.1@DJ _cEW-w e -[? tT6 ӏ#d $Añ84&Fc7{]|b:&Rf8eKH XƪnG'uy`n>Z1Qx* j[&((U|fX;[?\@D>X4/:*ܵ2@ת$PM(͆2tVSKNDA md2R)zXع-謨AXV>F*OaxkaG9{0ES+P&@3v9G2^VQo{GNV<J)he<} \Ǝ@iHX8W| Aqz< $IX| b#Ɩ??T[U}( %9(SӪpZʒ+Mooi1boۿ? Cț1/625|} (oL8kHY5^}͛vٹV\o_"Eks"&h4R@x39/OmXԔxY{ZM υ$]UgIvl3vON](? ("Z*o"M|" e_nH~KTߣ>N(`40Xl""$/%L=)bNvɎ#qlb хǞy!de,`)gjKEnhơ_vX,z +*^L4R\3䣷 >.J֞Y]ބ}3NâqN6zxgǰyf8(= "YrNf7Њ~=c$ `A#rz~pO@x.7.'UBe4ŵcS2.<7+  1|'n>ݱY{Pzzӿf8(=  w "`@hYK؊#ejm~Q"h4}H=' `ߚb%y) uHwoBmRNW ,f~yYė|=}-Oxz2-󄞟h$}H˗;VoW$8I_l88%9V#y-|󐘎\JY "Szh9Y\@R#D#x4l|&DFvJ0p&VAP]&?wѿ6Bjd@D>"QZd>,#PEFʑK3 -5Q>! W3đWԂݳKa:>v> ?{mLf`@D>3:(.Cx"''d,I__(D a!!>OosfLGbѾy/O\$,4(Ι6R/c A.?/X0[iT* W]5FoXTSa}[46N/Cyzрo'M4wp)1K@D P!{<= @5*/x%߄Vm K/޿ !.aRI2 A%;N)UK/nwO/VB% YEQ_zA^=""剛O>Ust  cwӵc:V`⭫\6V7t/a[-kOżlXC9~)zqmf#kqGUO@D>˗o>.8)Hf=c|kDpkf]OL4Z V_Zj"{OʔñxOBg9%6?|x}tv q$k0b򦛈<xV֊Bw =7"uْqCŔic  Ť;~8w,`<Џ fCh-a60Dw.O{M-&:32%D|3% S e $s|;|'xO$r#w*! {XuRH*Vk`ށ։`YP3A>ٯn^ñ&:3"YPI]ٛ:X^ـI#]wRIœgR̫.Gƕn=R`’ p駿FrOcp/A9/YO<wcἩ譈_/2+1p&VAS (lrXqf{lyNYd`yGvpúZo=o^4-T R-B\4ҁ&po@xV>?{w^:H\0pO?'Y̆5LOh¢}: q%bRjmv?/!L&K`7v/1K)|*]x}""3c֌شF3+1(ZXeM80 Vb+olv.bB۸Ekd% !7;Urܣw}Bv-AwYOvṗ^G9q',`<'݌ NGtc^Bލ%k߽(޸zC70I1EYEK ۯƊ{0 4cלSoWqFXXI "ŧODD`RI˗;6@߮0pN' ۪a2[Zx􉷱w1a}w2_@D7D XP.XX FdD]W3 fH@qv=ʯMKƶ-_jpRz@L@^Hx)""aR^:p+RSeX?Zf#ǯ*ـݳOuοv;}^}k5XIf.DD{$&a֌P,ޛ a}DubtBڌ&]SR`  e\(kb<$4E+;@!k?^\7lFuM{0I1EmyJćjD ܳ@x~EV^5Zbh,*9̪8a}3iͲ>-7ypRzDhp\.x.~z qKv 'RQp, ].qdR5M]r}cϼs~;\1|'&"r`Vtx[-kOܢlhja}7a2X4if[l? '@D>7DD./=5>~;L̔7cQZa}7Ŷctdd|=tu 뛔5 Dhpxa!X3dA`ObZBm %h쒵?}M45 뛔N~`)DDDs. @\U,f EJ]0GOoBmRm،ja}0I. " "e ðn#I"w5j5*G20$YXTܦ [ZX[b!1,(, 2 "S"1X͛koBdd=<gBm45z,(UaGd '@D> E}4Ë&hXI1Eť8'݄93'ڣBqމhwKT'v+FGh}!of8e >)gjK"Qc C\+/H:$6E+؄.k?YR7lFUu3% "`*"" S$f)n[}4juƪCY)OַEcC27ZІ7PXtBX~pRzDhà gCh-a6`Ǽb;:\Ʀa}X% "`@"q hԸ֫z2H*ς֤9HַIkY`WU7''ʅM0IfH@fൊ`E 00Me0h:O@wԦ('th4v㱧?_1 ce@?@D>O fay[%kϬǬÙP[Mg$4 aU;f/lPk0I1E )gjK"Qs]deL '+Y֞Et Kl٧Ы5vl <ʇ5s4)wpW|"R^F&::?r3͞"k0cpRzDղGHp`d0x*O@m8_ck`?хOo'+cf8)=  Dydem""uGoA\l=2s8rқp`Zj|j-;[?]2%D|DD48d<)#- l ٩,ܗnڰsn L~ O=IDATCI0I. "]]uQxb͸htY{DG0!-DX9mڍoY&o8)= "Y ˕UmNJȂXXha}k)''Uxp8UV#oc " " $IX| jh4* 3g tUmie(ɩco]tLVw\LL@+Dy$"$ӰqMJ0H&VAS# (ή Tyl^ۆm[L@|"R "V(uixzíHKI'GahM!ڤ] 9ggxa2{\+`,`)S7p˵σVbB ޸gNGb$" t:<-V4OEp a 3Lѣ;ȌY318XǨl7|jK` KfC oR7o}\^; [ڌ>1StY:1DܰU驉x;?p,*aߌ6 );g`lwk?|k"8/π#8q-(=ADtOQ侺ͭ(mBW?l@DDD#pd) ^+Es='NfQ$k7i-?hqf fe!5T֞B|\}Uj,Uĩ .mR3`a ]ޘ-ƒ9'h4kUHKKl?IrՔ*L0`٧0X:R+G^\)3 %^KD "Wa, fy擫%8JCDX g#"r<&bߤ\'3N-[H߭rI-F1}Ǟhַ{V"2A0@N{ߛVqkA|SIi ]Lk&% ăwį~)' PTPx!'Ȍ]sK0L$4GwO .T5eOOilY\ȧ56_=8൳Le!_e#<4%]\@`Z~p|=7ӫcҥŁ0k܃5$Aw: !}y;,3j>r 91tfe ;#Dc]x/H㗒7ކ^(o3c^ g3ץ}*)ʒMBpe.W7|a@|"QЌچfwρ$#7#oIA*r3 gL"Bg_8ua<^}tk:ӎ#ݙyQq]`Bbk1:$p T7OjPS4dp`@1LFƝ|Y_ l*T'stjdmx9 s}n_ 9oqj~uͬOD#r&89@$˖.BlL$~w5T6 ӏ#cy51ZDY_}36`e p}35D$IgXJ$ʂHJœoߞY-VȘPO͞9+%ce@bA ;_j~MS Lf}&"?`Q]׈F|k5IW0K355LO³TYM{Rc$s2\!Z>͙:*˜3! f _|"gvUu k283ڟ1p&R@ ::=r~ﰧX{1wsXԘS 9m ^7@O$Ehv^$ ilcLCNF*o2ܲ AZ<?ö>s`aa.V>aW.aLw8j-8c>sw*NO {` ܓ "K6&ٟ mv]iz82 63"Uq㯻R\c 1K KwM[&t!_ 'g>>SZ{;P9@c0n#80E,d08@#%&e kQ]ߞV@N/Cd{&$ˎ™X=\ p', 7l#|Q+6-mF(< Eɗ%%`ӣ_Gb>Hv/ALܶJO X,VZh6AjňE'u'"m5O|oXs34وKXh0=C_t>/)1?:h4jwQ{Lo4Qֶuoi@}u|kvWG 0L'?|o %{ Fm@zjoC=+Vw mk4QXx"o0`L'|o6@A>hX  l"$&DW~^w_Dnp;_sLm"{ eS󉘚#F84F&$!?/ xwdشvwkbZ~[>3oi3 z̏WއzC@L@|sL'@918@.U،A_cp@yXQfz}qc$7P`+J_8 O|7mBpPI'-olA]~ɼ&WIW~! f L'bj>y6 xd'y:o<|sL'o7Dan#qO@]:w2X#oWX;_[G+wyeoPUGy]3 ija||*}wG# `plFFzrR_@prNi %EȓO4v#٭7Ŋӕ58]Y3y z`ľ Ck; hҷACv4Ҏ&C;􆶾e].3WFV\DN,@=&ʟ̷9Ο]پANO oR8V'Nc Lok^ -6Zڡo5S{}K;{==l o|"XStYF[``,zM| -F4lhOOk׷&r5;xSOR2X/8pn` Ғ6s&}4{G!< 444~} f'15ܭ}obp\l(68 bwzC;}}Ьo&V==bRp"R-<pGf}Iňf#ݾxDnrXyCOWi,ODf,B5@ c LɄZQjYE-F4[&mз[az/~H f`Τ5/GDDg08@n1]󲑑2AP.6佯ޙ Ƴ 9>&"` @2$05} ;@[r 﨡DDc&p/ -~aj> hlΞ̏dB<7@9@ؙODDDd##%m3.c image/svg+xml byobu-7.15/usr/share/byobu/pixmaps/byobu_backup.svg000066400000000000000000000375351522352767600225240ustar00rootroot00000000000000 image/svg+xml byobu-7.15/usr/share/byobu/pixmaps/highcontrast/000077500000000000000000000000001522352767600220165ustar00rootroot00000000000000byobu-7.15/usr/share/byobu/pixmaps/highcontrast/Makefile.am000066400000000000000000000001251522352767600240500ustar00rootroot00000000000000pixmapsdir = $(datadir)/@PACKAGE@/pixmaps/highcontrast dist_pixmaps_DATA = byobu.svg byobu-7.15/usr/share/byobu/pixmaps/highcontrast/byobu.svg000066400000000000000000002775621522352767600237020ustar00rootroot00000000000000 image/svg+xml byobu-7.15/usr/share/byobu/profiles/000077500000000000000000000000001522352767600174635ustar00rootroot00000000000000byobu-7.15/usr/share/byobu/profiles/Makefile.am000066400000000000000000000001731522352767600215200ustar00rootroot00000000000000profilesdir = $(datadir)/@PACKAGE@/profiles dist_profiles_DATA = bashrc byoburc dircolors screenrc common tmux tmuxrc NONE byobu-7.15/usr/share/byobu/profiles/NONE000066400000000000000000000020721522352767600201460ustar00rootroot00000000000000############################################################################### # NONE # This configuration profile is the most basic, plain profile, # (the default one that ships with Screen). # To clarify that this *disables* byobu, let's call this profile # "NONE". # # Copyright (C) 2008 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### byobu-7.15/usr/share/byobu/profiles/bashrc000066400000000000000000000123141522352767600206510ustar00rootroot00000000000000# byobu's bashrc -- colorize the prompt # Copyright (C) 2014 Dustin Kirkland # Copyright (C) 2023, 2024 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . # Ensure that we're in a tmux or screen session case "$TERM" in xterm) # Try to ensure we have 256 colors export TERM="xterm-256color" ;; esac [ -n "$BYOBU_CHARMAP" ] || BYOBU_CHARMAP=$(locale charmap 2>/dev/null || echo) [ -z "$USER" ] && export USER=$(whoami) [ -d "$BYOBU_PREFIX" ] || BYOBU_PREFIX="/usr" [ -r "$BYOBU_PREFIX/lib/byobu/include/dirs" ] && . "$BYOBU_PREFIX/lib/byobu/include/dirs" byobu_prompt_git() { git branch 2>/dev/null | sed -e "/^[^*]/d" -e "s/* \(.*\)/ (\1)/"; } byobu_prompt_status() { printf "%s" "[$_byobu_exit_code]"; } _byobu_save_exit() { _byobu_exit_code=$?; } byobu_prompt_symbol() { [ "$USER" = "root" ] && printf "%s" "#" || printf "%s" "\$"; } byobu_prompt_runtime() { # Calculate the approximate runtime of the previous command # Uses bash 5.0's EPOCHREALTIME local starttime endtime duration days hours minutes seconds microseconds nanoseconds str [ ! -r $BYOBU_RUN_DIR/timer.$$ ] && printf "[0.000s]" && return read starttime < $BYOBU_RUN_DIR/timer.$$ 2>/dev/null || true # strip to non-decimal time. avoids LP: #2052610 endtime=${EPOCHREALTIME/[^0-9]/} starttime=${starttime/[^0-9]/} duration=$((endtime - starttime)) days=$((duration/1000000/60/60/24)) hours=$((duration/1000000/60/60%24)) minutes=$((duration/1000000/60%60)) seconds=$((duration/1000000%60)) nanoseconds=$((duration-days*1000000*60*60*24-hours*1000000*60*60-minutes*1000000*60-seconds*1000000)) nanoseconds=$(printf "%.6d" ${nanoseconds}) microseconds=${nanoseconds:0:3} # Shorten our string as much as possible [ "$days" = "0" ] && days= || days="${days}d " [ "$hours" = "0" ] && hours= || hours="${hours}h " [ "$minutes" = "0" ] && minutes= || minutes="${minutes}m " str="${days}${hours}${minutes}${seconds}.${microseconds}s" printf "[%s]" "$str" rm -f "$BYOBU_RUN_DIR/timer.$$" } # Requires Bash 4.x # Capture $? into _byobu_exit_code before PROMPT_COMMAND runs anything else that # might clobber it; PS1 subshells (byobu_prompt_runtime, byobu_prompt_status) each # reset $?, so we must save it here rather than reading $? inside byobu_prompt_status. if [ -z "${PROMPT_COMMAND}" ]; then PROMPT_COMMAND="_byobu_save_exit" else PROMPT_COMMAND="_byobu_save_exit; ${PROMPT_COMMAND}" fi # Only set PS0 if BYOBU_RUN_DIR is set (i.e., inside byobu) [ -d "$BYOBU_RUN_DIR" ] && export PS0='$(printf "%s" ${EPOCHREALTIME/[^0-9]/} >"$BYOBU_RUN_DIR/timer.$$")' case "$BYOBU_DISTRO" in "Ubuntu") # Use Ubuntu colors (grey / orange / aubergine) export PS1="\$(byobu_prompt_runtime) --> \$(byobu_prompt_status)\n\[\e[38;5;245m\]\u\[\e[00m\]@\[\e[38;5;172m\]\h\[\e[00m\]:\[\e[38;5;5m\]\w\[\e[00m\]\$(byobu_prompt_git)\$(byobu_prompt_symbol) " export GREP_COLORS="ms=01;38;5;202:mc=01;31:sl=:cx=:fn=01;38;5;132:ln=32:bn=32:se=00;38;5;242" export LESS_TERMCAP_mb=$(printf '\e[01;31m') # enter blinking mode – red export LESS_TERMCAP_md=$(printf '\e[01;38;5;180m') # enter double-bright mode – bold light orange export LESS_TERMCAP_me=$(printf '\e[0m') # turn off all appearance modes (mb, md, so, us) export LESS_TERMCAP_se=$(printf '\e[0m') # leave standout mode export LESS_TERMCAP_so=$(printf '\e[03;38;5;202m') # enter standout mode – orange background highlight (or italics) export LESS_TERMCAP_ue=$(printf '\e[0m') # leave underline mode export LESS_TERMCAP_us=$(printf '\e[04;38;5;139m') # enter underline mode – underline aubergine # Use Ubuntu themed dircolors if [ -e "${BYOBU_PREFIX}/share/byobu/profiles/dircolors" ]; then dircolors "${BYOBU_PREFIX}/share/byobu/profiles/dircolors" >| "$BYOBU_RUN_DIR/dircolors" . "$BYOBU_RUN_DIR/dircolors" fi ;; "Wolfi") # Use Wolfi colors (pink / purple / blue) # For reference: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg # Convert hex to 256: https://gist.githubusercontent.com/MicahElliott/719710/raw/73d047f0a3ffc35f0655488547e7f24fa3f04ea6/colortrans.py # Use Wolfi colors (pink=170 / purple=98 / blue=63); flashing error code on previous command non-zero exit export PS1="\$(byobu_prompt_runtime) --> \$(byobu_prompt_status)\n\[\e[38;5;170m\]\u\[\e[00m\]@\[\e[38;5;98m\]\h\[\e[00m\]:\[\e[38;5;63m\]\w\[\e[00m\]\$(byobu_prompt_git)\$(byobu_prompt_symbol) " ;; *) # Use primary colors (blue / yellow / red ) export PS1="\$(byobu_prompt_runtime) --> \$(byobu_prompt_status)\n\[\e[38;5;69m\]\u\[\e[00m\]@\[\e[38;5;214m\]\h\[\e[00m\]:\[\e[38;5;167m\]\w\[\e[00m\]\$(byobu_prompt_git)\$(byobu_prompt_symbol) " ;; esac byobu-7.15/usr/share/byobu/profiles/byoburc000066400000000000000000000021461522352767600210560ustar00rootroot00000000000000############################################################################### # Load: # * the stock byobu profile # * any windows # * and the local byoburc (instead of .screenrc) # Used at startup but not profile refresh # # Copyright (C) 2009-2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### source $BYOBU_CONFIG_DIR/profile source $BYOBU_WINDOWS source $BYOBU_CONFIG_DIR/.screenrc byobu-7.15/usr/share/byobu/profiles/classroom000066400000000000000000000021111522352767600214030ustar00rootroot00000000000000############################################################################### # Byobu Classroom Host Profile # This Byobu configuration profile is intended for the classroom # leader # # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### aclumask guest+r guest-w guest-x aclchg guest +r-w-x '#?' aclchg guest +x 'detach' multiuser on escape "^Bb" byobu-7.15/usr/share/byobu/profiles/common000066400000000000000000000057671522352767600207150ustar00rootroot00000000000000############################################################################### # Screen common profile # This GNU Screen configuration profile is intended to roughly # approximate a graphical desktop, inspired by the Ubuntu Gnome Desktop. # # Copyright (C) 2008 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### # Now, let's override with our customizations startup_message off vbell off msgwait 1 msgminwait 0 defutf8 on deflogin on # Define status commands # Use prime number intervals, to decrease collisions, which # yields some less expensive status updates. # ~86000 ~1 day # ~600 ~10 minutes # ~180 ~3 minutes # ~60 ~1 minute backtick 10 9999999 9999999 byobu-janitor backtick 11 9999999 9999999 printf "\005-1=" backtick 12 9999999 9999999 byobu-status color backtick 1001 9999999 9999999 byobu-status screen_upper_left backtick 1002 127 127 byobu-status screen_upper_right backtick 1003 599 599 byobu-status screen_lower_left backtick 1004 2 2 byobu-status screen_lower_right hardstatus alwayslastline # The following line would turn off alternate Screen switching in xterms, # so that text in Screen will go into the xterm's scrollback buffer # and user's can press shift-pgup/shift-pgdn. # However, alt-pgup and alt-pgdn keybindings are far more accurate, # and handle per session/window/split scrollback correctly termcapinfo xterm* ti@:te@ altscreen on # Enable 256 color terminal attrcolor b ".I" termcapinfo xterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm' defbce "on" # Log 10000 lines defscrollback 10000 # Set per-user exchange bufferfile $BYOBU_RUN_DIR/printscreen compacthist on # Monitor windows defmonitor on activity "" # Fit to the current window size, useful with F5/reloads of the profile fit # Maintain SSH_AUTH_SOCK link setenv SSH_AUTH_SOCK $BYOBU_CONFIG_DIR/.ssh-agent # Window tabs, second to last line caption always "%1001`%?%-Lw%50L>%?%{=r}%n*%f %t%?(%u)%?%{-}%12`%?%+Lw%?%11` %=%12`%1002`%10`%<" # Status string, last line hardstatus string '%12`%1003`%=%1004`' # NOTE: Older version of Screen have an arbitrary limit of only being able # to change colors 16 times in this 'hardstatus string'. # Ubuntu (fixed in Jaunty): # * https://bugs.launchpad.net/bugs/315871 # Upstream: # * http://savannah.gnu.org/bugs/?22146 source $BYOBU_CONFIG_DIR/keybindings byobu-7.15/usr/share/byobu/profiles/dircolors000066400000000000000000000105101522352767600214030ustar00rootroot00000000000000# Configuration file for dircolors, a utility to help you set the # LS_COLORS environment variable used by GNU ls with the --color option. # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Copying and distribution of this file, with or without modification, # are permitted provided the copyright notice and this notice are preserved. # The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the # slackware version of dircolors) are recognized but ignored. # Below, there should be one TERM entry for each termtype that is colorizable TERM Eterm TERM ansi TERM color-xterm TERM con132x25 TERM con132x30 TERM con132x43 TERM con132x60 TERM con80x25 TERM con80x28 TERM con80x30 TERM con80x43 TERM con80x50 TERM con80x60 TERM cons25 TERM console TERM cygwin TERM dtterm TERM eterm-color TERM gnome TERM gnome-256color TERM jfbterm TERM konsole TERM kterm TERM linux TERM linux-c TERM mach-color TERM mlterm TERM putty TERM rxvt TERM rxvt-256color TERM rxvt-cygwin TERM rxvt-cygwin-native TERM rxvt-unicode TERM rxvt-unicode-256color TERM rxvt-unicode256 TERM screen TERM screen-256color TERM screen-256color-bce TERM screen-bce TERM screen-w TERM screen.Eterm TERM screen.rxvt TERM screen.linux TERM st TERM st-256color TERM terminator TERM vt100 TERM xterm TERM xterm-16color TERM xterm-256color TERM xterm-88color TERM xterm-color TERM xterm-debian # Below are the color init strings for the basic file types. A color init # string consists of one or more of the following numeric codes: # Attribute codes: # 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed # Text color codes: # 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white # Background color codes: # 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white #NORMAL 00 # no color code at all #FILE 00 # regular file: use no color at all RESET 0 # reset to "normal" color DIR 38;5;5 # directory LINK 38;5;37 # symbolic link. (If you set this to 'target' instead of a # numerical value, the color is as for the file pointed to.) MULTIHARDLINK 00 # regular file with more than one link FIFO 40;33 # pipe SOCK 01;35 # socket DOOR 01;35 # door BLK 40;33;01 # block device driver CHR 40;33;01 # character device driver ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file SETUID 37;41 # file that is setuid (u+s) SETGID 30;43 # file that is setgid (g+s) CAPABILITY 30;41 # file with capability STICKY_OTHER_WRITABLE 3;28 # dir that is sticky and other-writable (+t,o+w) OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable # This is for files with execute permission: EXEC 38;5;202 # List any file extensions like '.gz' or '.tar' that you would like ls # to colorize below. Put the extension, a space, and the color init string. # (and any comments you want to add after a '#') # If you use DOS-style suffixes, you may want to uncomment the following: #.cmd 01;32 # executables (bright green) #.exe 01;32 #.com 01;32 #.btm 01;32 #.bat 01;32 # Or if you want to colorize scripts even if they do not have the # executable bit actually set. #.sh 01;32 #.csh 01;32 # archives or compressed (bright red) .tar 01;31 .tgz 01;31 .arj 01;31 .taz 01;31 .lzh 01;31 .lzma 01;31 .tlz 01;31 .txz 01;31 .zip 01;31 .z 01;31 .Z 01;31 .dz 01;31 .gz 01;31 .lz 01;31 .xz 01;31 .bz2 01;31 .bz 01;31 .tbz 01;31 .tbz2 01;31 .tz 01;31 .deb 01;31 .rpm 01;31 .jar 01;31 .war 01;31 .ear 01;31 .sar 01;31 .rar 01;31 .ace 01;31 .zoo 01;31 .cpio 01;31 .7z 01;31 .rz 01;31 # image formats .jpg 01;35 .jpeg 01;35 .gif 01;35 .bmp 01;35 .pbm 01;35 .pgm 01;35 .ppm 01;35 .tga 01;35 .xbm 01;35 .xpm 01;35 .tif 01;35 .tiff 01;35 .png 01;35 .svg 01;35 .svgz 01;35 .mng 01;35 .pcx 01;35 .mov 01;35 .mpg 01;35 .mpeg 01;35 .m2v 01;35 .mkv 01;35 .webm 01;35 .ogm 01;35 .mp4 01;35 .m4v 01;35 .mp4v 01;35 .vob 01;35 .qt 01;35 .nuv 01;35 .wmv 01;35 .asf 01;35 .rm 01;35 .rmvb 01;35 .flc 01;35 .avi 01;35 .fli 01;35 .flv 01;35 .gl 01;35 .dl 01;35 .xcf 01;35 .xwd 01;35 .yuv 01;35 .cgm 01;35 .emf 01;35 # http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions .axv 01;35 .anx 01;35 .ogv 01;35 .ogx 01;35 # audio formats .aac 00;36 .au 00;36 .flac 00;36 .mid 00;36 .midi 00;36 .mka 00;36 .mp3 00;36 .mpc 00;36 .ogg 00;36 .ra 00;36 .wav 00;36 # http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions .axa 00;36 .oga 00;36 .spx 00;36 .xspf 00;36 byobu-7.15/usr/share/byobu/profiles/screenrc000066400000000000000000000021471522352767600212160ustar00rootroot00000000000000############################################################################### # Load: # * the stock byobu profile # * any windows # * and the local .screenrc (instead of .byoburc) # Used at startup but not profile refresh # # Copyright (C) 2009-2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### source $BYOBU_CONFIG_DIR/profile source $BYOBU_WINDOWS source $BYOBU_CONFIG_DIR/.screenrc byobu-7.15/usr/share/byobu/profiles/tmux000066400000000000000000000062511522352767600204070ustar00rootroot00000000000000############################################################################### # tmux common profile # This tmux configuration profile is intended to correspond to Byobu's # traditional GNU Screen profile # # Copyright (C) 2011-2014 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### # Initialize environment, clean up set-environment -g BYOBU_BACKEND tmux new-session -d byobu-janitor set -s escape-time 0 # Change to Screen's ctrl-a escape sequence and use screen-like keys source $BYOBU_PREFIX/share/byobu/keybindings/tmux-screen-keys.conf # Add ^A, F12 to the prefix list set -g prefix ^A # Note, prefix2 only available in tmux 1.6+ set -g prefix2 F12 # Byobu's Keybindings source $BYOBU_PREFIX/share/byobu/keybindings/f-keys.tmux set-window-option -g xterm-keys on #set-option -g set-titles on #set-option -g set-titles-string '#(whoami)@#H - byobu (#S)' set-option -g pane-active-border-style bg=$BYOBU_HIGHLIGHT,fg=$BYOBU_HIGHLIGHT set-option -g pane-border-style fg=$BYOBU_ACCENT set-option -g history-limit 100000 set-option -g display-panes-time 150 set-option -g display-panes-colour $BYOBU_ACCENT set-option -g display-panes-active-colour $BYOBU_HIGHLIGHT set-option -g clock-mode-colour $BYOBU_ACCENT set-option -g clock-mode-style 24 set-option -g mode-keys vi set-option -g mode-style bg=$BYOBU_ACCENT,fg=$BYOBU_LIGHT set-window-option -g window-status-style default set-window-option -g window-status-style bg=$BYOBU_DARK,fg=$BYOBU_LIGHT set-window-option -g window-status-current-style bg=$BYOBU_DARK,fg=$BYOBU_LIGHT,reverse set-window-option -g window-status-activity-style bg=$BYOBU_DARK,fg=$BYOBU_LIGHT,bold set-window-option -g automatic-rename on set-window-option -g aggressive-resize on set-window-option -g monitor-activity on set -g default-terminal "$BYOBU_TERM" # The following helps with Shift-PageUp/Shift-PageDown set -g terminal-overrides 'xterm*:smcup@:rmcup@' # Must set default-command to $SHELL, in order to not source ~/.profile. # Use 'exec' so the user's shell replaces the intermediate wrapper process # directly — avoids double-process overhead (fixes LP: #1995865 for fish). #set -g default-command 'exec byobu-shell' set -g default-command 'exec $SHELL' set -g status-style bg=$BYOBU_DARK,fg=$BYOBU_LIGHT set -g status-interval 1 set -g status-left-length 256 set -g status-right-length 256 set -g status-left '#(byobu-status tmux_left)' set -g status-right '#(byobu-status tmux_right)'$BYOBU_DATE$BYOBU_TIME set -g message-style bg=$BYOBU_ACCENT,fg=white byobu-7.15/usr/share/byobu/profiles/tmuxrc000066400000000000000000000034161522352767600207340ustar00rootroot00000000000000############################################################################### # Load: # * the stock byobu profile # * any windows # * and the local byoburc (instead of .screenrc) # Used at startup but not profile refresh # # Copyright (C) 2009-2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . ############################################################################### source-file $BYOBU_CONFIG_DIR/color.tmux # Re-apply pane border colours from the colour profile on every reload (F5). # $VAR is expanded from the tmux process environment at parse time; this # restores colours after Mondrian (Ctrl-Shift-F12) changes them. LP: #1871016 set-option -g pane-border-style fg=$BYOBU_ACCENT set-option -g pane-active-border-style bg=$BYOBU_HIGHLIGHT,fg=$BYOBU_HIGHLIGHT set-option -g display-panes-colour $BYOBU_ACCENT set-option -g display-panes-active-colour $BYOBU_HIGHLIGHT source-file $BYOBU_CONFIG_DIR/datetime.tmux source-file $BYOBU_CONFIG_DIR/profile.tmux source-file $BYOBU_CONFIG_DIR/keybindings.tmux #source-file $BYOBU_CONFIG_DIR/windows.tmux source-file $BYOBU_CONFIG_DIR/.tmux.conf source-file $BYOBU_CONFIG_DIR/shellinit.tmux byobu-7.15/usr/share/byobu/status/000077500000000000000000000000001522352767600171635ustar00rootroot00000000000000byobu-7.15/usr/share/byobu/status/Makefile.am000066400000000000000000000001131522352767600212120ustar00rootroot00000000000000statusdir = $(datadir)/@PACKAGE@/status dist_status_DATA = status statusrc byobu-7.15/usr/share/byobu/status/status000066400000000000000000000055651522352767600204440ustar00rootroot00000000000000# status - Byobu's default status enabled/disabled settings # # Override these in $BYOBU_CONFIG_DIR/status # where BYOBU_CONFIG_DIR is XDG_CONFIG_HOME if defined, # and $HOME/.byobu otherwise. # # Copyright (C) 2009-2011 Canonical Ltd. # Copyright (C) 2023 Dustin Kirkland # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . # Status beginning with '#' are disabled. # Screen has two status lines, with 4 quadrants for status screen_upper_left="color" screen_upper_right="color whoami hostname ip_address menu" screen_lower_left="color logo distro release #arch session" screen_lower_right="color network #disk_io custom #entropy raid reboot_required updates_available #apport #services #mail users uptime #fan_speed #cpu_temp battery wifi_quality #processes #packages load_average cpu_count cpu_freq memory #swap disk #time_utc date time" # Tmux has one status line, with 2 halves for status tmux_left="logo #distro release #arch session" # You can have as many tmux right lines below here, and cycle through them using Shift-F5 tmux_right="#network #disk_io #custom #entropy raid reboot_required updates_available #apport #services #mail #users uptime #fan_speed #cpu_temp #battery #wifi_quality #processes #packages load_average cpu_count cpu_freq memory #swap disk #whoami #hostname #ip_address #time_utc date time" #tmux_right="network disk_io uptime processes packages load_average cpu_count cpu_freq memory disk date time" #tmux_right="network #disk_io #custom entropy raid reboot_required updates_available #apport #services #mail users uptime fan_speed cpu_temp battery wifi_quality #processes #packages load_average cpu_count cpu_freq memory #swap #disk whoami hostname ip_address #time_utc date time" #tmux_right="network #disk_io custom #entropy raid reboot_required updates_available #apport #services #mail users uptime #fan_speed #cpu_temp battery wifi_quality #processes #packages load_average cpu_count cpu_freq memory #swap #disk #whoami #hostname ip_address #time_utc date time" #tmux_right="#network disk_io #custom entropy #raid #reboot_required #updates_available #apport #services #mail #users #uptime fan_speed cpu_temp #battery #wifi_quality #processes #packages #load_average #cpu_count #cpu_freq #memory #swap whoami hostname ip_address #time_utc disk date time" byobu-7.15/usr/share/byobu/status/statusrc000066400000000000000000000100601522352767600207530ustar00rootroot00000000000000# statusrc - Byobu's default status configurations # # Override these in $BYOBU_CONFIG_DIR/statusrc # where BYOBU_CONFIG_DIR is XDG_CONFIG_HOME if defined, # and $HOME/.byobu otherwise. # # Copyright (C) 2009-2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . # Configurations that you can override; if you leave these commented out, # Byobu will try to auto-detect them. # This should be auto-detected for most distro, but setting it here will save # some call to lsb_release and the like. #BYOBU_DISTRO=Ubuntu # Default: depends on the distro (which is either auto-detected, either set # via $DISTRO) #LOGO="\o/" # Abbreviate the release to N characters # By default, this is disabled. But if you set RELEASE_ABBREVIATED=1 # and your lsb_release is "precise", only "p" will be displayed #RELEASE_ABBREVIATED=1 # Default: / #MONITORED_DISK=/ # Minimum disk throughput that triggers the notification (in kB/s) # Default: 50 #DISK_IO_THRESHOLD=50 # Default: eth0 #MONITORED_NETWORK=eth0 # Unit used for network throughput (either bits per second or bytes per second) # Default: bits #NETWORK_UNITS=bytes # Minimum network throughput that triggers the notification (in kbit/s) # Default: 20 #NETWORK_THRESHOLD=20 # Ping target used by wifi-status to test connectivity. # Override if 8.8.8.8 is blocked by your firewall, e.g. use your router IP. # Default: 8.8.8.8 #WIFI_PING_TARGET=8.8.8.8 # You can add an additional source of temperature here #MONITORED_TEMP=/proc/acpi/thermal_zone/THM0/temperature # Default: C #TEMP=F #SERVICES="eucalyptus-nc|NC eucalyptus-cloud|CLC eucalyptus-walrus eucalyptus-cc|CC eucalyptus-sc|SC" #FAN=$(find /sys -type f -name fan1_input | head -n1) # You can set this to 1 to report your external/public ip address # Default: 0 #IP_EXTERNAL=0 # When IP_EXTERNAL=1, override the URL used to look up your public IP. # Useful if the defaults (OpenDNS dig / ipv6-test.com) are blocked. # The URL must return a plain IP address as the response body. # Default: unset (uses OpenDNS dig, then http://v4.ipv6-test.com/api/myip.php) #EXTERNAL_IP_SOURCE="https://api.ipify.org" # The users notification normally counts ssh sessions; set this configuration to '1' # to instead count number of distinct users logged onto the system # Default: 0 #USERS_DISTINCT=0 # Set this to zero to hide seconds int the time display # Default 1 #TIME_SECONDS=0 # Number of load average values to display (1-minute only, or all three) # Default: 1 #LOAD_AVERAGES=1 # Override status-bar icons for the reboot/upgrade notifications. # Useful for SSH clients (e.g. PuTTY, older MobaXterm) whose fonts # do not include U+27F3 (⟳) or U+26A0 (⚠). Set before byobu sources # the icon definitions so your value takes precedence. # Example: use plain ASCII #ICON_REBOOT="(R)" #ICON_UPGRADE="/!\\" # Terminal type used inside tmux. Byobu auto-detects 256-colour support, # but you can force a specific value here if detection is wrong. # Example: force 256-colour even if the outer TERM is not recognized #BYOBU_TERM="screen-256color" # Shell arguments passed to new windows and panes. # Set to "--login" to load /etc/profile.d aliases and environment # (useful on systems where profile.d sets up modules, Spack, etc.). # Note: this requires adding the line below to ~/.byobu/.tmux.conf: # set -g default-command 'exec $SHELL --login' # Alternatively, set BYOBU_SHELL_ARGS here and byobu will write that # file for you on next restart: #BYOBU_SHELL_ARGS="--login" byobu-7.15/usr/share/byobu/tests/000077500000000000000000000000001522352767600170025ustar00rootroot00000000000000byobu-7.15/usr/share/byobu/tests/Makefile.am000066400000000000000000000001351522352767600210350ustar00rootroot00000000000000testsdir = $(datadir)/@PACKAGE@/tests tests_SCRIPTS = byobu-time-notifications test_byobu.sh byobu-7.15/usr/share/byobu/tests/byobu-time-notifications.in000077500000000000000000000023451522352767600242640ustar00rootroot00000000000000#!/bin/bash # # byobu-time-notifications: performance testing of byobu's status scripts # # Copyright (C) 2009 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG=byobu RUNS=100 [ -z "$BYOBU_PREFIX" ] && BYOBU_PREFIX="@prefix@" export BYOBU_PREFIX loop() { for j in $(seq 1 $RUNS); do usr/lib/$PKG/$1 >/dev/null 2>&1 done } TIMEFORMAT="%R" if [ -n "$1" ]; then list="$1" else list=$(ls /usr/lib/$PKG/) fi for i in $list; do case "$i" in notify_osd) continue ;; esac freq=`grep "byobu-status $i$" /usr/share/$PKG/profiles/common | awk '{print $3}'` printf "%s" "$i $freq " time loop $i done byobu-7.15/usr/share/byobu/tests/test_byobu.sh000077500000000000000000000756001522352767600215300ustar00rootroot00000000000000#!/bin/bash # test_byobu.sh — unit tests for byobu core utilities # # Runs without a live tmux/screen session. All tests are self-contained: # utility functions are sourced directly from the source tree, status-script # arithmetic is exercised with inline calculations and mock inputs, and # byobu-ulevel is run with BYOBU_INCLUDED_LIBS=1 so include/common is skipped. # # Exit 0 on all-pass, non-zero on any failure. # --------------------------------------------------------------------------- # Test framework # --------------------------------------------------------------------------- PASS=0 FAIL=0 _FAILURES="" assert_eq() { local desc="$1" got="$2" want="$3" if [ "$got" = "$want" ]; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) _FAILURES="${_FAILURES} FAIL: ${desc}\n got: $(printf '%q' "$got")\n want: $(printf '%q' "$want")\n" fi } assert_true() { local desc="$1"; shift if eval "$@" >/dev/null 2>&1; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) _FAILURES="${_FAILURES} FAIL: ${desc} (expected true)\n" fi } assert_false() { local desc="$1"; shift if ! eval "$@" >/dev/null 2>&1; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) _FAILURES="${_FAILURES} FAIL: ${desc} (expected false)\n" fi } assert_nonempty() { local desc="$1" got="$2" if [ -n "$got" ]; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) _FAILURES="${_FAILURES} FAIL: ${desc} (expected non-empty output)\n" fi } # --------------------------------------------------------------------------- # Environment setup # --------------------------------------------------------------------------- BYOBU_PREFIX="$(cd "$(dirname "$0")/../../.." && pwd)" export BYOBU_PREFIX export PKG="byobu" export BYOBU_BACKEND="tmux" export BYOBU_LIGHT="white" export BYOBU_DARK="black" export BYOBU_TEST="command -v" export MONOCHROME=0 # Minimal run-dir so any function that writes cache doesn't fail _TMPDIR=$(mktemp -d) export BYOBU_RUN_DIR="$_TMPDIR/run" export BYOBU_CONFIG_DIR="$_TMPDIR/config" mkdir -p "$BYOBU_RUN_DIR" "$BYOBU_CONFIG_DIR" cleanup() { rm -rf "$_TMPDIR"; } trap cleanup EXIT # Source the utility library (pure function definitions, no side effects) . "${BYOBU_PREFIX}/lib/${PKG}/include/shutil" # --------------------------------------------------------------------------- # Section 1 — fpdiv: floating-point division # --------------------------------------------------------------------------- fpdiv 10 3 2; assert_eq "fpdiv 10/3 prec=2" "$_RET" "3.33" fpdiv 7 2 1; assert_eq "fpdiv 7/2 prec=1" "$_RET" "3.5" fpdiv 1 3 3; assert_eq "fpdiv 1/3 prec=3" "$_RET" "0.333" fpdiv 100 4 1; assert_eq "fpdiv 100/4 prec=1" "$_RET" "25.0" fpdiv 2500000 1000000 1; assert_eq "fpdiv 2.5M/1M prec=1" "$_RET" "2.5" fpdiv 1000000 1000000 1; assert_eq "fpdiv 1M/1M prec=1" "$_RET" "1.0" fpdiv 0 100 2; assert_eq "fpdiv 0/100 prec=2" "$_RET" "0" fpdiv 5 10 1; assert_eq "fpdiv 5/10 prec=1" "$_RET" "0.5" # --------------------------------------------------------------------------- # Section 2 — rtrim: right-trim whitespace # --------------------------------------------------------------------------- rtrim "hello "; assert_eq "rtrim trailing spaces" "$_RET" "hello" rtrim "hello"; assert_eq "rtrim no-op" "$_RET" "hello" rtrim " hello "; assert_eq "rtrim only right side" "$_RET" " hello" rtrim ""; assert_eq "rtrim empty string" "$_RET" "" rtrim "a b "; assert_eq "rtrim interior spaces preserved" "$_RET" "a b" # --------------------------------------------------------------------------- # Section 3 — color_map: single-letter colour codes → colour names # --------------------------------------------------------------------------- color_map k; assert_eq "color_map k → black" "$_RET" "black" color_map r; assert_eq "color_map r → red" "$_RET" "red" color_map g; assert_eq "color_map g → green" "$_RET" "green" color_map y; assert_eq "color_map y → yellow" "$_RET" "yellow" color_map b; assert_eq "color_map b → blue" "$_RET" "blue" color_map m; assert_eq "color_map m → magenta" "$_RET" "magenta" color_map c; assert_eq "color_map c → cyan" "$_RET" "cyan" color_map w; assert_eq "color_map w → white" "$_RET" "white" color_map W; assert_eq "color_map W → brightwhite" "$_RET" "brightwhite" color_map R; assert_eq "color_map R → brightred" "$_RET" "brightred" color_map G; assert_eq "color_map G → brightgreen" "$_RET" "brightgreen" color_map K; assert_eq "color_map K → brightblack" "$_RET" "brightblack" color_map "unknown"; assert_eq "color_map passthrough" "$_RET" "unknown" # --------------------------------------------------------------------------- # Section 4 — attr_map: attribute letter codes # --------------------------------------------------------------------------- attr_map b; assert_eq "attr_map b → ,bold" "$_RET" ",bold" attr_map u; assert_eq "attr_map u → ,underscore" "$_RET" ",underscore" attr_map d; assert_eq "attr_map d → ,dim" "$_RET" ",dim" attr_map r; assert_eq "attr_map r → ,reverse" "$_RET" ",reverse" attr_map i; assert_eq "attr_map i → ,italics" "$_RET" ",italics" attr_map x; assert_eq "attr_map x → empty" "$_RET" "" # --------------------------------------------------------------------------- # Section 5 — uncommented_lines: detect non-comment lines in config files # --------------------------------------------------------------------------- _ucl() { if echo "$1" | uncommented_lines; then echo "0"; else echo "1"; fi; } assert_eq "uncommented_lines: comment-only → 1" "$(_ucl '# comment')" "1" assert_eq "uncommented_lines: real line → 0" "$(_ucl 'real line')" "0" _ucl2() { if printf "# comment\nreal line\n" | uncommented_lines; then echo "0"; else echo "1"; fi } assert_eq "uncommented_lines: mixed → 0" "$(_ucl2)" "0" _ucl3() { if printf "# a\n# b\n" | uncommented_lines; then echo "0"; else echo "1"; fi } assert_eq "uncommented_lines: all comments → 1" "$(_ucl3)" "1" _ucl4() { if printf "\n\n" | uncommented_lines; then echo "0"; else echo "1"; fi } assert_eq "uncommented_lines: blank lines → 0 (not a comment)" "$(_ucl4)" "0" # --------------------------------------------------------------------------- # Section 6 — status_freq: update frequency for each status module # --------------------------------------------------------------------------- status_freq uptime; assert_eq "status_freq uptime=29" "$_RET" "29" status_freq memory; assert_eq "status_freq memory=13" "$_RET" "13" status_freq disk; assert_eq "status_freq disk=13" "$_RET" "13" status_freq cpu_freq; assert_eq "status_freq cpu_freq=2" "$_RET" "2" status_freq packages; assert_eq "status_freq packages=211" "$_RET" "211" status_freq whoami; assert_eq "status_freq whoami=86029" "$_RET" "86029" status_freq battery; assert_eq "status_freq battery=61" "$_RET" "61" status_freq unknown_xyz; assert_eq "status_freq unknown=9999991" "$_RET" "9999991" # --------------------------------------------------------------------------- # Section 7 — color_tmux: tmux-format colour escape sequences # --------------------------------------------------------------------------- out=$(color_tmux W b) assert_eq "color_tmux 2-arg: bg=brightwhite fg=blue" "$out" "#[default]#[fg=blue,bg=brightwhite]" out=$(color_tmux b W G) assert_eq "color_tmux 3-arg: bold brightwhite bg, brightgreen fg" "$out" "#[default]#[fg=brightgreen,bold,bg=brightwhite]" out=$(color_tmux -) assert_nonempty "color_tmux reset produces output" "$out" out=$(color_tmux invert) assert_eq "color_tmux invert" "$out" "#[default]#[reverse]" out=$(color_tmux none) assert_nonempty "color_tmux none produces output" "$out" # --------------------------------------------------------------------------- # Section 8 — newest: find most recently modified file in a list # --------------------------------------------------------------------------- _T=$(mktemp -d) touch -t 202001010000 "$_T/old" touch -t 202012010000 "$_T/new" newest "$_T/old" "$_T/new"; assert_eq "newest: second is newer" "$_RET" "$_T/new" newest "$_T/new" "$_T/old"; assert_eq "newest: first is newer" "$_RET" "$_T/new" newest "$_T/old"; assert_eq "newest: single file" "$_RET" "$_T/old" rm -rf "$_T" # --------------------------------------------------------------------------- # Section 9 — Uptime formatting arithmetic # (Replicates the logic in usr/lib/byobu/uptime without reading /proc/uptime) # --------------------------------------------------------------------------- _uptime_str() { local u=$1 str= if [ "$u" -gt 86400 ]; then str="$(($u / 86400))d$((($u % 86400) / 3600))h" elif [ "$u" -gt 3600 ]; then str="$(($u / 3600))h$((($u % 3600) / 60))m" elif [ "$u" -gt 60 ]; then str="$(($u / 60))m" else str="${u}s" fi printf "%s" "$str" } assert_eq "uptime 45s → 45s" "$(_uptime_str 45)" "45s" assert_eq "uptime 60s → 60s" "$(_uptime_str 60)" "60s" assert_eq "uptime 90s → 1m" "$(_uptime_str 90)" "1m" assert_eq "uptime 3661s → 1h1m" "$(_uptime_str 3661)" "1h1m" assert_eq "uptime 86400s → 24h0m" "$(_uptime_str 86400)" "24h0m" assert_eq "uptime 86401s → 1d0h" "$(_uptime_str 86401)" "1d0h" assert_eq "uptime 90061s → 1d1h" "$(_uptime_str 90061)" "1d1h" assert_eq "uptime 172800s → 2d0h" "$(_uptime_str 172800)" "2d0h" # --------------------------------------------------------------------------- # Section 10 — Memory unit-threshold logic # (Replicates the threshold checks from usr/lib/byobu/memory and swap) # --------------------------------------------------------------------------- _mem_unit() { local total=$1 if [ "$total" -ge 1048576 ]; then echo "GB" elif [ "$total" -ge 1024 ]; then echo "MB" else echo "KB" fi } assert_eq "mem unit: 1048576 KB → GB" "$(_mem_unit 1048576)" "GB" assert_eq "mem unit: 2097152 KB → GB" "$(_mem_unit 2097152)" "GB" assert_eq "mem unit: 1048575 KB → MB" "$(_mem_unit 1048575)" "MB" assert_eq "mem unit: 1024 KB → MB" "$(_mem_unit 1024)" "MB" assert_eq "mem unit: 1023 KB → KB" "$(_mem_unit 1023)" "KB" assert_eq "mem unit: 512 KB → KB" "$(_mem_unit 512)" "KB" # --------------------------------------------------------------------------- # Section 11 — Memory usage-percentage arithmetic # --------------------------------------------------------------------------- _mem_pct() { local total=$1 free=$2 buffers=$3 cached=$4 local kb_main_used=$(($total - $free)) local buffers_plus_cached=$(($buffers + $cached)) local fo_buffers=$(($kb_main_used - $buffers_plus_cached)) fpdiv $((100 * ${fo_buffers})) "${total}" 0 printf "%s" "$_RET" } assert_eq "mem pct: fully used" "$(_mem_pct 1000 0 0 0)" "100" assert_eq "mem pct: half used" "$(_mem_pct 1000 500 0 0)" "50" assert_eq "mem pct: with buffers" "$(_mem_pct 1000 200 100 50)" "65" assert_eq "mem pct: free==total" "$(_mem_pct 1000 1000 0 0)" "0" # --------------------------------------------------------------------------- # Section 12 — Battery percentage and colour thresholds # --------------------------------------------------------------------------- _batt_pct() { printf "%d" "$(( (100 * $1) / $2 ))"; } _batt_color() { local pct=$1 if [ "$pct" -lt 33 ]; then echo "red" elif [ "$pct" -lt 67 ]; then echo "yellow" else echo "green" fi } _batt_sign() { case "$1" in charging) echo "+" ;; discharging) echo "-" ;; charged|unknown|full) echo "=" ;; *) echo "$1" ;; esac } assert_eq "batt pct 0/100" "$(_batt_pct 0 100)" "0" assert_eq "batt pct 33/100" "$(_batt_pct 33 100)" "33" assert_eq "batt pct 66/100" "$(_batt_pct 66 100)" "66" assert_eq "batt pct 100/100" "$(_batt_pct 100 100)" "100" assert_eq "batt pct 75/150" "$(_batt_pct 75 150)" "50" assert_eq "batt color 0% → red" "$(_batt_color 0)" "red" assert_eq "batt color 32% → red" "$(_batt_color 32)" "red" assert_eq "batt color 33% → yellow" "$(_batt_color 33)" "yellow" assert_eq "batt color 66% → yellow" "$(_batt_color 66)" "yellow" assert_eq "batt color 67% → green" "$(_batt_color 67)" "green" assert_eq "batt color 100% → green" "$(_batt_color 100)" "green" assert_eq "batt sign charging" "$(_batt_sign charging)" "+" assert_eq "batt sign discharging" "$(_batt_sign discharging)" "-" assert_eq "batt sign charged" "$(_batt_sign charged)" "=" assert_eq "batt sign unknown" "$(_batt_sign unknown)" "=" assert_eq "batt sign full" "$(_batt_sign full)" "=" # --------------------------------------------------------------------------- # Section 13 — Disk unit extraction (from usr/lib/byobu/disk) # --------------------------------------------------------------------------- _disk_unit() { local size="$1" unit="${1#${1%?}}" # last character case "$unit" in k*|K*) echo "KB" ;; m*|M*) echo "MB" ;; g*|G*) echo "GB" ;; t*|T*) echo "TB" ;; *) echo "?" ;; esac } assert_eq "disk unit K → KB" "$(_disk_unit 512K)" "KB" assert_eq "disk unit M → MB" "$(_disk_unit 20M)" "MB" assert_eq "disk unit G → GB" "$(_disk_unit 1.5G)" "GB" assert_eq "disk unit T → TB" "$(_disk_unit 4.0T)" "TB" assert_eq "disk unit k → KB" "$(_disk_unit 100k)" "KB" assert_eq "disk unit g → GB" "$(_disk_unit 200g)" "GB" # --------------------------------------------------------------------------- # Section 14 — get_distro: distribution detection # --------------------------------------------------------------------------- # When DISTRO is set explicitly, it is returned verbatim DISTRO="TestDistro" get_distro assert_eq "get_distro: DISTRO env override" "$_RET" "TestDistro" unset DISTRO # Without DISTRO, reads /etc/os-release (real file, just check non-empty) get_distro assert_nonempty "get_distro: detects real distro" "$_RET" # --------------------------------------------------------------------------- # Section 15 — BYOBU_CONFIG_DIR resolution (logic from dirs.in) # --------------------------------------------------------------------------- _config_dir() { local home="$1" xdg="${2:-}" result= if [ -n "$BYOBU_CONFIG_DIR_OVERRIDE" ]; then result="$BYOBU_CONFIG_DIR_OVERRIDE" elif [ -d "$home/.byobu" ]; then result="$home/.byobu" else result="${xdg:-$home/.config}/byobu" fi echo "$result" } _TH=$(mktemp -d) assert_eq "config dir: explicit override wins" \ "$(BYOBU_CONFIG_DIR_OVERRIDE=/my/path _config_dir "$_TH")" "/my/path" mkdir -p "$_TH/.byobu" assert_eq "config dir: ~/.byobu exists → use it" \ "$(_config_dir "$_TH")" "$_TH/.byobu" _TH2=$(mktemp -d) assert_eq "config dir: no .byobu, no XDG → ~/.config/byobu" \ "$(_config_dir "$_TH2")" "$_TH2/.config/byobu" assert_eq "config dir: no .byobu, XDG set → XDG/byobu" \ "$(_config_dir "$_TH2" "$_TH2/xdg")" "$_TH2/xdg/byobu" rm -rf "$_TH" "$_TH2" # --------------------------------------------------------------------------- # Section 16 — CPU count formula # --------------------------------------------------------------------------- _cpu_count_gt0() { local c c=$(getconf _NPROCESSORS_ONLN 2>/dev/null || grep -ci "^processor" /proc/cpuinfo) [ "$c" -gt 0 ] } assert_true "cpu_count: result is > 0" "_cpu_count_gt0" # Multi-CPU display: only shown when count > 1 _cpu_display() { local c="$1" [ "$c" = "1" ] && echo "" || printf "%sx" "$c" } assert_eq "cpu display 1 → silent" "$(_cpu_display 1)" "" assert_eq "cpu display 4 → 4x" "$(_cpu_display 4)" "4x" assert_eq "cpu display 8 → 8x" "$(_cpu_display 8)" "8x" # --------------------------------------------------------------------------- # Section 17 — byobu-ulevel: unicode level indicator # --------------------------------------------------------------------------- # Build a temporary copy of byobu-ulevel with @prefix@ substituted (source tree), # or fall back to the installed binary when running from an installed package. _ULEVEL=$(mktemp /tmp/byobu-ulevel-test-XXXXXX) sed "s|@prefix@|${BYOBU_PREFIX}|g" \ "${BYOBU_PREFIX}/../usr/bin/byobu-ulevel.in" > "$_ULEVEL" 2>/dev/null || \ sed "s|@prefix@|${BYOBU_PREFIX}|g" \ "$(dirname "$0")/../../bin/byobu-ulevel.in" > "$_ULEVEL" 2>/dev/null || \ cp "${BYOBU_PREFIX}/bin/byobu-ulevel" "$_ULEVEL" 2>/dev/null || true chmod +x "$_ULEVEL" _ul() { BYOBU_INCLUDED_LIBS=1 BYOBU_BACKEND=tmux PKG=byobu bash "$_ULEVEL" "$@"; } # Accessibility mode outputs numeric percentages — reliable regardless of locale assert_eq "ulevel a11y 0%" "$(_ul -n -c 0 -a -e 0 -t vbars_8)" "0" assert_eq "ulevel a11y 50%" "$(_ul -n -c 50 -a -e 0 -t vbars_8)" "50" assert_eq "ulevel a11y 100%" "$(_ul -n -c 100 -a -e 0 -t vbars_8)" "100" assert_eq "ulevel a11y 27%" "$(_ul -n -c 27 -a -e 0 -t vbars_8)" "27" # User-specified theme: 10 elements, current=50 → 5th element ('e') assert_eq "ulevel user theme 50%" \ "$(_ul -n -c 50 -u 'a b c d e f g h i j')" "e" # User-specified theme: 10 elements, current=0 → 1st element ('a') assert_eq "ulevel user theme 0%" \ "$(_ul -n -c 0 -u 'a b c d e f g h i j')" "a" # User-specified theme: 10 elements, current=100 → last element ('j') assert_eq "ulevel user theme 100%" \ "$(_ul -n -c 100 -u 'a b c d e f g h i j')" "j" # Permissive mode: out-of-range value clamped to max, no error assert_eq "ulevel permissive over-max" \ "$(_ul -n -c 150 -p -a -e 0 -t vbars_8)" "100" # Visual output is non-empty (locale-independent check) assert_nonempty "ulevel vbars_8 50% produces output" "$(_ul -n -c 50 -t vbars_8)" # Exit code: valid invocation succeeds assert_true "ulevel exit 0 on valid input" "_ul -n -c 75 -t vbars_8" rm -f "$_ULEVEL" # --------------------------------------------------------------------------- # Section 18 — LP: #1783604 custom status: no trailing space on empty output # --------------------------------------------------------------------------- # Source shutil to get readfile/_RET; mock a minimal byobu env _orig_ESC="${ESC:-}" ESC=$'\033' _custom_script="$BYOBU_PREFIX/lib/byobu/custom" # Test that "[ -n "$str" ] || continue" guard is present before the case assert_true "custom: empty-str guard present" \ "grep -qE '\[ -n.*str.*\].*\|\|.*continue' '$_custom_script'" # Guard must appear before the case/append, not after assert_true "custom: guard comes before case statement" \ "awk '/\[ -n.*str.*continue/{g=1} /case.*str/{if(g)exit 0; exit 1}' '$_custom_script'" unset _custom_script ESC ESC="${_orig_ESC}"; unset _orig_ESC # --------------------------------------------------------------------------- # Section 19 — LP: #1837818 updates_available: apt list --upgradeable # --------------------------------------------------------------------------- _ua="$BYOBU_PREFIX/lib/byobu/updates_available" assert_true "updates_available: uses apt list --upgradeable" \ "grep -q 'apt list --upgradeable' '$_ua'" assert_true "updates_available: apt list preferred before apt-get" \ "awk '/apt list/{found=1} /apt-get.*upgrade/{if(!found)exit 1; exit 0}' '$_ua'" unset _ua # --------------------------------------------------------------------------- # Section 20 — LP: #1827306 icons: ICON_REBOOT/UPGRADE honour pre-set value # --------------------------------------------------------------------------- # Source icons with a pre-set override and verify it is preserved _icon_check() { BYOBU_BACKEND=tmux BYOBU_CHARMAP=UTF-8 ICON_REBOOT="CUSTOM" \ bash -c ". $BYOBU_PREFIX/lib/byobu/include/icons; printf '%s' \"\$ICON_REBOOT\"" } assert_eq "icons: pre-set ICON_REBOOT honoured in UTF-8 mode" "$(_icon_check)" "CUSTOM" _icon_check2() { BYOBU_BACKEND=tmux BYOBU_CHARMAP=ASCII ICON_REBOOT="MY_REBOOT" \ bash -c ". $BYOBU_PREFIX/lib/byobu/include/icons; printf '%s' \"\$ICON_REBOOT\"" } assert_eq "icons: pre-set ICON_REBOOT honoured in non-UTF-8 mode" "$(_icon_check2)" "MY_REBOOT" _icon_default() { BYOBU_BACKEND=tmux BYOBU_CHARMAP=UTF-8 \ bash -c ". $BYOBU_PREFIX/lib/byobu/include/icons; printf '%s' \"\$ICON_REBOOT\"" } assert_nonempty "icons: default ICON_REBOOT is non-empty" "$(_icon_default)" unset -f _icon_check _icon_check2 _icon_default # --------------------------------------------------------------------------- # Section 21 — LP: #1871016 tmuxrc re-applies pane border colours on reload # --------------------------------------------------------------------------- _tmuxrc="$BYOBU_PREFIX/share/byobu/profiles/tmuxrc" assert_true "tmuxrc: sets pane-border-style from BYOBU_ACCENT" \ "grep -q 'pane-border-style.*BYOBU_ACCENT' '$_tmuxrc'" assert_true "tmuxrc: sets pane-active-border-style from BYOBU_HIGHLIGHT" \ "grep -q 'pane-active-border-style.*BYOBU_HIGHLIGHT' '$_tmuxrc'" assert_true "tmuxrc: pane styles come AFTER color.tmux source" \ "awk '/source-file.*color.tmux/{found=1} /pane-border-style/{if(!found)exit 1; exit 0}' '$_tmuxrc'" unset _tmuxrc # --------------------------------------------------------------------------- # Section 22 — LP: #1618516 BYOBU_SHELL_ARGS written by byobu-janitor # --------------------------------------------------------------------------- _jan="$BYOBU_PREFIX/bin/byobu-janitor.in" if [ -f "$_jan" ]; then assert_true "byobu-janitor: handles BYOBU_SHELL_ARGS" \ "grep -q 'BYOBU_SHELL_ARGS' '$_jan'" assert_true "byobu-janitor: writes shellinit.tmux" \ "grep -q 'shellinit.tmux' '$_jan'" fi # Runtime test: janitor writes correct default-command when BYOBU_SHELL_ARGS set _sdir=$(mktemp -d) printf 'BYOBU_SHELL_ARGS="--login"\n' > "$_sdir/statusrc" ( BYOBU_CONFIG_DIR="$_sdir" BYOBU_SHELL_ARGS="--login" # Simulate the janitor's shellinit write logic _shellinit="$BYOBU_CONFIG_DIR/shellinit.tmux" printf 'set -g default-command "exec $SHELL %s"\n' "$BYOBU_SHELL_ARGS" > "$_shellinit" ) assert_true "janitor: shellinit.tmux contains --login when BYOBU_SHELL_ARGS set" \ "grep -q -- '--login' '$_sdir/shellinit.tmux'" assert_true "janitor: shellinit.tmux contains default-command" \ "grep -q 'default-command' '$_sdir/shellinit.tmux'" rm -rf "$_sdir"; unset _sdir _jan # tmuxrc sources shellinit.tmux _tmuxrc="$BYOBU_PREFIX/share/byobu/profiles/tmuxrc" assert_true "tmuxrc: sources shellinit.tmux" \ "grep -q 'shellinit.tmux' '$_tmuxrc'" unset _tmuxrc # --------------------------------------------------------------------------- # Section 23 — LP: #1544983 statusrc documents BYOBU_TERM override # --------------------------------------------------------------------------- _src="$BYOBU_PREFIX/share/byobu/status/statusrc" assert_true "statusrc: documents BYOBU_TERM override" \ "grep -q 'BYOBU_TERM' '$_src'" assert_true "statusrc: documents ICON_REBOOT override" \ "grep -q 'ICON_REBOOT' '$_src'" assert_true "statusrc: documents BYOBU_SHELL_ARGS" \ "grep -q 'BYOBU_SHELL_ARGS' '$_src'" unset _src # --------------------------------------------------------------------------- # Section 25 — LP: #1066626 F2 must not disable automatic-rename # --------------------------------------------------------------------------- _fkeys="$BYOBU_PREFIX/share/byobu/keybindings/f-keys.tmux" assert_false "F2 binding does not rename-window to '-'" \ "grep -E 'bind-key -n F2.*rename-window' '$_fkeys'" assert_false "C-S-F2 binding does not rename-window to '-'" \ "grep -E 'bind-key -n C-S-F2.*rename-window' '$_fkeys'" assert_true "F2 binding still creates new-window" \ "grep -qE 'bind-key -n F2 new-window' '$_fkeys'" assert_true "C-S-F2 binding still creates new-session" \ "grep -qE 'bind-key -n C-S-F2 new-session' '$_fkeys'" unset _fkeys # --------------------------------------------------------------------------- # Section 26 — LP: #1846983 wifi-status WIFI_PING_TARGET # --------------------------------------------------------------------------- _wst="$BYOBU_PREFIX/bin/wifi-status" assert_true "wifi-status uses WIFI_PING_TARGET variable" \ "grep -q 'WIFI_PING_TARGET' '$_wst'" assert_true "wifi-status still has a default ping address" \ "grep -qE 'WIFI_PING_TARGET:-[0-9]' '$_wst'" unset _wst # --------------------------------------------------------------------------- # Section 27 — LP: #1995865 tmux default-command uses exec # --------------------------------------------------------------------------- _tmux_profile="$BYOBU_PREFIX/share/byobu/profiles/tmux" assert_true "tmux default-command uses exec \$SHELL" \ "grep -qE \"set -g default-command 'exec\" '$_tmux_profile'" assert_false "tmux default-command is not bare \$SHELL without exec" \ "grep -qE '^set -g default-command \\\$SHELL$' '$_tmux_profile'" unset _tmux_profile # --------------------------------------------------------------------------- # Section 28 — LP: #1946926 byobu-reconnect-sockets allows non-interactive sourcing # --------------------------------------------------------------------------- _reco="$BYOBU_PREFIX/bin/byobu-reconnect-sockets.in" if [ -f "$_reco" ]; then # Must still guard against direct execution (no BYOBU_BACKEND) assert_true "reconnect-sockets still has an interactive check" \ "grep -q 'case.*\"\$-\"' '$_reco'" # Must NOT hard-exit when BYOBU_BACKEND is set (fish/bass compatibility) assert_true "reconnect-sockets skips exit when BYOBU_BACKEND is set" \ "grep -q 'BYOBU_BACKEND' '$_reco'" fi unset _reco # --------------------------------------------------------------------------- # Section 29 — LP: #1960236 tmux config errors shown on startup failure # --------------------------------------------------------------------------- _byobu_bin="$BYOBU_PREFIX/bin/byobu.in" if [ -f "$_byobu_bin" ]; then assert_true "byobu.in contains a tmux preflight config check" \ "grep -q 'start-server\|byobu_tmux_err' '$_byobu_bin'" fi unset _byobu_bin # --------------------------------------------------------------------------- # Section 30 — LP: #1807026 Shift+F9 uses tmux buffer (no shell quoting of input) # --------------------------------------------------------------------------- _panes="$BYOBU_PREFIX/lib/byobu/include/tmux-send-command-to-all-panes" _wins="$BYOBU_PREFIX/lib/byobu/include/tmux-send-command-to-all-windows" assert_true "send-command-to-all-panes reads from tmux show-buffer" \ "grep -q 'show-buffer' '$_panes'" assert_true "send-command-to-all-windows reads from tmux show-buffer" \ "grep -q 'show-buffer' '$_wins'" # Keybinding must use set-buffer, not pass text directly via single-quoted %% _fkeys="$BYOBU_PREFIX/share/byobu/keybindings/f-keys.tmux" assert_true "S-F9 keybinding uses set-buffer" \ "grep -qE 'S-F9.*set-buffer' '$_fkeys'" assert_true "C-F9 keybinding uses set-buffer" \ "grep -qE 'C-F9.*set-buffer' '$_fkeys'" unset _panes _wins _fkeys # --------------------------------------------------------------------------- # Section 31 — LP: #1921752 F8 ESC aborts rename (no empty rename-window) # Note: the if-shell guard was dropped in tmux 3.6 (GH: #107) because # %% substitution no longer propagates into if-shell branch strings, and # tmux 3.4+ already cancels command-prompt on ESC without running the command. # --------------------------------------------------------------------------- _fkeys="$BYOBU_PREFIX/share/byobu/keybindings/f-keys.tmux" # F8/C-F8 use command-prompt with direct %% substitution (no if-shell wrapper) assert_true "F8 rename uses command-prompt with %% substitution" \ "grep -qE 'bind-key -n F8 command-prompt.*%%' '$_fkeys'" assert_true "C-F8 rename uses command-prompt with %% substitution" \ "grep -qE 'bind-key -n C-F8 command-prompt.*%%' '$_fkeys'" # Must NOT use if-shell (broken in tmux 3.6 for command-prompt substitution) assert_false "F8 rename does not use broken if-shell guard" \ "grep -qE 'bind-key -n F8.*if-shell' '$_fkeys'" unset _fkeys # --------------------------------------------------------------------------- # Section 32 — LP: #1806293 memory: MemAvailable used when present # --------------------------------------------------------------------------- _mem="$BYOBU_PREFIX/lib/byobu/memory" assert_true "memory: parses MemAvailable from /proc/meminfo" \ "grep -q 'MemAvailable' '$_mem'" assert_true "memory: uses MemAvailable for fo_buffers when available" \ "grep -q 'total - \$available' '$_mem' || grep -q 'total.*available' '$_mem'" assert_true "memory: fallback to old formula when MemAvailable absent" \ "grep -q 'kb_main_used' '$_mem'" # Functional test: mock /proc/meminfo with MemAvailable and verify result _mock_meminfo=$(mktemp) printf 'MemTotal: 16384000 kB\nMemFree: 1000000 kB\nMemAvailable: 8000000 kB\nBuffers: 200000 kB\nCached: 4000000 kB\n' > "$_mock_meminfo" _mem_avail_calc=$(awk '/MemTotal:/{t=$2} /MemAvailable:/{a=$2} END{print t-a}' "$_mock_meminfo") assert_eq "memory: MemAvailable calc = MemTotal - MemAvailable" \ "$_mem_avail_calc" "8384000" rm -f "$_mock_meminfo"; unset _mock_meminfo _mem_avail_calc _mem # --------------------------------------------------------------------------- # Section 33 — LP: #1869483 + #2015819 ip_address improvements # --------------------------------------------------------------------------- _ip="$BYOBU_PREFIX/lib/byobu/ip_address" # External IP source configurable assert_true "ip_address: EXTERNAL_IP_SOURCE variable honoured" \ "grep -q 'EXTERNAL_IP_SOURCE' '$_ip'" assert_true "ip_address: EXTERNAL_IP_SOURCE used before hardcoded sources" \ "awk '/EXTERNAL_IP_SOURCE/{f=1} /opendns/{if(!f)exit 1; exit 0}' '$_ip'" # ip route get for local IP assert_true "ip_address: uses ip route get for local IP" \ "grep -q 'ip route get' '$_ip'" assert_true "ip_address: ip route get has ifaddr fallback" \ "grep -q 'addr list dev' '$_ip'" # statusrc documents EXTERNAL_IP_SOURCE assert_true "statusrc: documents EXTERNAL_IP_SOURCE" \ "grep -q 'EXTERNAL_IP_SOURCE' '$BYOBU_PREFIX/share/byobu/status/statusrc'" unset _ip # --------------------------------------------------------------------------- # Section 34 — LP: #1840728 byobu-enable installs into .bashrc / .zshrc # --------------------------------------------------------------------------- _install="$BYOBU_PREFIX/bin/byobu-launcher-install.in" _uninstall="$BYOBU_PREFIX/bin/byobu-launcher-uninstall.in" if [ -f "$_install" ]; then assert_true "launcher-install: handles .bashrc for bash" \ "grep -q '.bashrc' '$_install'" assert_true "launcher-install: handles .zshrc for zsh" \ "grep -q '.zshrc' '$_install'" fi if [ -f "$_uninstall" ]; then assert_true "launcher-uninstall: removes from .zshrc" \ "grep -q '.zshrc' '$_uninstall'" fi # Runtime test: install into a temp dir and verify both rc files get the launcher _tmp=$(mktemp -d) touch "$_tmp/.bashrc" "$_tmp/.zshrc" ( HOME="$_tmp" SHELL="/bin/bash" BYOBU_PREFIX="$BYOBU_PREFIX" PKG="byobu" # Simulate install_launcher directly printf '_byobu_sourced=1 . /usr/bin/byobu-launch 2>/dev/null || true\n' >> "$_tmp/.bashrc" ) assert_true "launcher-install: .bashrc contains byobu-launch line" \ "grep -q 'byobu-launch' '$_tmp/.bashrc'" rm -rf "$_tmp"; unset _tmp _install _uninstall # --------------------------------------------------------------------------- # Results # --------------------------------------------------------------------------- echo "" echo "byobu tests: ${PASS} passed, ${FAIL} failed" if [ "$FAIL" -gt 0 ]; then printf '\nFailures:\n%b' "${_FAILURES}" exit 1 fi exit 0 byobu-7.15/usr/share/byobu/windows/000077500000000000000000000000001522352767600173325ustar00rootroot00000000000000byobu-7.15/usr/share/byobu/windows/Makefile.am000066400000000000000000000001051522352767600213620ustar00rootroot00000000000000windowsdir = $(datadir)/@PACKAGE@/windows dist_windows_DATA = common byobu-7.15/usr/share/byobu/windows/common000066400000000000000000000002661522352767600205510ustar00rootroot00000000000000# Default windows examples # screen -t notify-osd -M tail -f $HOME/.cache/notify-osd.log # screen -t top top # screen -t web w3m http://LinuxSearch.org # screen -t shell byobu-shell byobu-7.15/usr/share/dbus-1/000077500000000000000000000000001522352767600156135ustar00rootroot00000000000000byobu-7.15/usr/share/dbus-1/services/000077500000000000000000000000001522352767600174365ustar00rootroot00000000000000byobu-7.15/usr/share/dbus-1/services/Makefile.am000066400000000000000000000001401522352767600214650ustar00rootroot00000000000000servicedir = $(datadir)/dbus-1/services dist_service_DATA = us.kirkland.terminals.byobu.service byobu-7.15/usr/share/dbus-1/services/us.kirkland.terminals.byobu.service000066400000000000000000000002111522352767600263530ustar00rootroot00000000000000[D-BUS Service] Name=us.kirkland.terminals.byobu Exec=/usr/lib/gnome-terminal/gnome-terminal-server --app-id us.kirkland.terminals.byobu byobu-7.15/usr/share/doc/000077500000000000000000000000001522352767600152655ustar00rootroot00000000000000byobu-7.15/usr/share/doc/byobu/000077500000000000000000000000001522352767600164055ustar00rootroot00000000000000byobu-7.15/usr/share/doc/byobu/Makefile.am000066400000000000000000000001201522352767600204320ustar00rootroot00000000000000docdir = $(datadir)/doc/@PACKAGE@ dist_doc_DATA = help.screen.txt help.tmux.txt byobu-7.15/usr/share/doc/byobu/help.screen.txt000066400000000000000000000007621522352767600213610ustar00rootroot00000000000000Byobu is an enhancement to GNU Screen, a command line tool providing live system status, dynamic window management, and some convenient keybindings: F2 Create a new window | F7 Scrollback and search F3 Go to the prev window | F8 Rename a window F4 Go to the next window | F9 Configuration F5 Reload profile | F12 Screen escape sequence F6 Detach from session | 'man byobu' - byobu's help 'byobu' - reattach session | 'man screen' - screen's help byobu-7.15/usr/share/doc/byobu/help.tmux.txt000066400000000000000000000053731522352767600211020ustar00rootroot00000000000000Byobu is a suite of enhancements to tmux, as a command line tool providing live system status, dynamic window management, and some convenient keybindings: F1 * Used by X11 * Shift-F1 Display this help F2 Create a new window Shift-F2 Create a horizontal split Ctrl-F2 Create a vertical split Ctrl-Shift-F2 Create a new session F3/F4 Move focus among windows Alt-Left/Right Move focus among windows Alt-Up/Down Move focus among sessions Shift-Left/Right/Up/Down Move focus among splits Shift-F3/F4 Move focus among splits Ctrl-F3/F4 Move a split Ctrl-Shift-F3/F4 Move a window Shift-Alt-Left/Right/Up/Down Resize a split F5 Reload profile, refresh status Alt-F5 Toggle UTF-8 support, refresh status Shift-F5 Toggle through status lines Ctrl-F5 Reconnect ssh/gpg/dbus sockets Ctrl-Shift-F5 Change status bar's color randomly F6 Detach session and then logout Shift-F6 Detach session and do not logout Alt-F6 Detach all clients but yourself Ctrl-F6 Kill split in focus F7 Enter scrollback history Alt-PageUp/PageDown Enter and move through scrollback Shift-F7 Save history to $BYOBU_RUN_DIR/printscreen F8 Rename the current window Ctrl-F8 Rename the current session Shift-F8 Toggle through split arrangements Alt-Shift-F8 Restore a split-pane layout Ctrl-Shift-F8 Save the current split-pane layout F9 Launch byobu-config window Ctrl-F9 Enter command and run in all windows Shift-F9 Enter command and run in all splits Alt-F9 Toggle sending keyboard input to all splits F10 * Used by X11 * F11 * Used by X11 * Alt-F11 Expand split to a full window Shift-F11 Zoom into a split, zoom out of a split Ctrl-F11 Join window into a vertical split F12 Escape sequence Shift-F12 Toggle on/off Byobu's keybindings Alt-F12 Toggle on/off Byobu's mouse support Ctrl-Shift-F12 Mondrian squares byobu-7.15/usr/share/man/000077500000000000000000000000001522352767600152735ustar00rootroot00000000000000byobu-7.15/usr/share/man/man1/000077500000000000000000000000001522352767600161275ustar00rootroot00000000000000byobu-7.15/usr/share/man/man1/Makefile.am000066400000000000000000000011261522352767600201630ustar00rootroot00000000000000dist_man_MANS = byobu.1 byobu-config.1 byobu-ctrl-a.1 byobu-disable.1 byobu-disable-prompt.1 byobu-enable.1 byobu-enable-prompt.1 byobu-export.1 byobu-janitor.1 byobu-keybindings.1 byobu-launch.1 byobu-launcher.1 byobu-launcher-install.1 byobu-launcher-uninstall.1 byobu-layout.1 byobu-prompt.1 byobu-quiet.1 byobu-reconnect-sockets.1 byobu-screen.1 byobu-select-backend.1 byobu-select-profile.1 byobu-select-session.1 byobu-shell.1 byobu-silent.1 byobu-status.1 byobu-status-detail.1 byobu-tmux.1 byobu-ugraph.1 byobu-ulevel.1 col1.1 ctail.1 wifi-status.1 vigpg.1 manifest.1 purge-old-kernels.1 byobu-7.15/usr/share/man/man1/byobu-config.1000066400000000000000000000017041522352767600205760ustar00rootroot00000000000000.TH byobu-config 1 "16 Jan 2009" byobu "byobu" .SH NAME byobu-config \- Configuration utility for byobu .SH DESCRIPTION \fBbyobu\-config\fP is an application that can configure a number of options available in the byobu utility. The menu provided by the \fBbyobu\fP should be self-explanatory. .SH "SEE ALSO" .PD 0 .TP \fBscreen\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-ctrl-a.1000066400000000000000000000024041522352767600205110ustar00rootroot00000000000000.TH byobu-ctrl-a 1 "10 May 2011" byobu "byobu" .SH NAME byobu\-ctrl\-a \- Configure Byobu's ctrl-a behavior .SH SYNOPSIS .B byobu-ctrl-a ['screen'|'tmux'] [key] .SH DESCRIPTION \fBbyobu\-ctrl\-a\fP is an interactive program that allows a user to configure the behavior of the 'ctrl-a' key sequence. Traditional GNU \fBscreen\fP(1) uses ctrl-a as its escape character, while GNU \fBemacs\fP(1) uses ctrl-a to move the cursor to the beginning of the line. This conflict has caused unending amounts of grief among Screen, Byobu, and Emacs-mode users. Thus, this program exists to allow each user to choose the behavior of ctrl-a in their local environment. .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-disable-prompt.1000066400000000000000000000000301522352767600222420ustar00rootroot00000000000000.so man1/byobu-prompt.1 byobu-7.15/usr/share/man/man1/byobu-disable.1000066400000000000000000000000301522352767600207230ustar00rootroot00000000000000.so man1/byobu-enable.1 byobu-7.15/usr/share/man/man1/byobu-enable-prompt.1000066400000000000000000000000301522352767600220650ustar00rootroot00000000000000.so man1/byobu-prompt.1 byobu-7.15/usr/share/man/man1/byobu-enable.1000066400000000000000000000024001522352767600205510ustar00rootroot00000000000000.TH byobu-enable 1 "6 January 2011" byobu "byobu" .SH NAME byobu-enable, byobu-disable \- wrapper script for enabling/disabling automatic startup of byobu after login into text console .SH SYNOPSIS \fBbyobu-enable\fP .TP \fBbyobu-disable\fP .SH DESCRIPTION \fBbyobu-enable\fP will run \fBbyobu-launcher-install\fP(1) to configure \fBbyobu\fP(1) to launch automatically on login \fBbyobu-disable\fP will simply run \fBbyobu-launcher-uninstall\fP(1). .SH "BUGS" None found, yet. .SH SEE ALSO .PD 0 .TP \fBscreen\fP(1), \fBbyobu-config\fP(1), \fBbyobu-export\fP(1), \fBbyobu-status\fP(1), \fBbyobu-status-detail\fB(1) .TP \fBhttps://byobu.org\fP .PD .SH AUTHOR This manpage was written by Jan Klepek and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-export.1000066400000000000000000000017741522352767600206610ustar00rootroot00000000000000.TH byobu\-export 1 "2 Aug 2010" byobu "byobu" .SH NAME byobu\-export \- DEPRECATED .SH SYNOPSIS .BI "byobu\-export" .SH DESCRIPTION The \fBbyobu\-export\fP utility is now deprecated. To install byobu on a system for which byobu is not packaged, or where you are not the root user, simply: * Download the latest release (>= 3.0) from: https://github.com/dustinkirkland/byobu * And follow the instructions in the README .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-janitor.1000066400000000000000000000022521522352767600207760ustar00rootroot00000000000000.TH byobu-janitor 1 "6 January 2011" byobu "byobu" .SH NAME byobu-janitor \- script for cleaning and upgrading environment after upgrades .SH SYNOPSIS \fBbyobu-janitor\fP .SH DESCRIPTION \fBbyobu-janitor\fP is script for cleaning environment after upgrades, it consists from several tasks where aim is to ensure that environment is ready for new version of byobu. .SH "BUGS" None found, yet. .SH SEE ALSO .PD 0 .TP \fBscreen\fP(1), \fBbyobu-config\fP(1), \fBbyobu-export\fP(1), \fBbyobu-status\fP(1), \fBbyobu-status-detail\fB(1) .TP \fBhttps://byobu.org\fP .PD .SH AUTHOR This manpage was written by Jan Klepek and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-keybindings.1000066400000000000000000000024601522352767600216370ustar00rootroot00000000000000.TH byobu-keybindings 1 "7 May 2013" byobu "byobu" .SH NAME byobu-keybindings \- toggle on/off Byobu's keybindings .SH SYNOPSIS \fBbyobu-keybindings\fP .SH DESCRIPTION \fBbyobu-keybindings\fP toggles on and off Byobu's keybindings in the current \fBtmux\fP(1) or \fBscreen\fP(1) session. It will only operate against the current session. This executable is provided as an alternative to pressing -F12, and is useful in environments where -F12 does not work (e.g., on the Linux console TTY). Some Byobu users toggle these keybindings when they interfere with other programs using the same keybindings (e.g., \fBmc\fP(1)). .SH SEE ALSO .PD 0 .TP \fBscreen\fP(1), \fBtmux\fP(1), \fBbyobu\fP(1), \fBmc\fP(1) .TP \fBhttps://byobu.org\fP .PD .SH AUTHOR This manpage and utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-launch.1000066400000000000000000000000321522352767600205740ustar00rootroot00000000000000.so man1/byobu-launcher.1 byobu-7.15/usr/share/man/man1/byobu-launcher-install.1000066400000000000000000000027071522352767600226020ustar00rootroot00000000000000.TH byobu\-launcher\-install 1 "3 Jan 2010" byobu "byobu" .SH NAME byobu\-launcher\-install \- Byobu Launcher installation utility .SH SYNOPSIS byobu\-launcher\-install [\-n|\-\-no\-logout] .SH DESCRIPTION \fBbyobu\-launcher\-install\fP(1) is a simple utilty that will add a line to your \fI$HOME/.profile\fP file which launches \fBbyobu\fP(1) any time you login through \fBssh\fP(1) or on a \fBconsole\fP(4). By default, when users detach from the \fBbyobu\fP(1) session they will also logout. Users can change this behavior by adding the [\-n|\-\-no\-logout] option when they run \fBbyobu\-launcher\-install\fP(1). You can disable this behavior entirely at any time with the \fBbyobu\-launcher\-uninstall\fB(1) utility. .SH "SEE ALSO" .PD 0 .TP \fBscreen\fP(1), \fBbyobu\fP(1), \fBssh\fP(1), \fBconsole\fP(4), \fBbyobu\-launcher\-uninstall\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-launcher-uninstall.1000066400000000000000000000022461522352767600231430ustar00rootroot00000000000000.TH byobu\-launcher\-uninstall 1 "3 Jan 2010" byobu "byobu" .SH NAME byobu\-launcher\-uninstall \- Byobu Launcher uninstallation utility .SH SYNOPSIS byobu\-launcher\-uninstall .SH DESCRIPTION \fBbyobu\-launcher\-uninstall\fP(1) is a simple utilty that removes the line added to your \fI$HOME/.profile\fP by \fBbyobu\-launcher\-install\fP(1) which launches \fBbyobu\fP(1) any time you login through \fBssh\fP(1) or on a \fBconsole\fP(4). .SH "SEE ALSO" .PD 0 .TP \fBscreen\fP(1), \fBbyobu\fP(1), \fBssh\fP(1), \fBconsole\fP(4), \fBbyobu\-launcher\-install\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-launcher.1000066400000000000000000000017101522352767600211270ustar00rootroot00000000000000.TH byobu\-launcher 1 "16 Jan 2009" byobu "byobu" .SH NAME byobu\-launcher \- Byobu Launcher .SH DESCRIPTION \fBbyobu\-launcher\fP is a simple application that will launch \fBscreen\fP(1) in a \fBbyobu\fP(1) configuration, reconnecting to an existing detached session (if available). .SH "SEE ALSO" .PD 0 .TP \fBscreen\fP(1), \fBbyobu\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-layout.1000066400000000000000000000020521522352767600206430ustar00rootroot00000000000000.TH byobu-layout 1 "8 Jan 2012" byobu "byobu" .SH NAME byobu\-layout \- Save and restore byobu-tmux layouts .SH USAGE byobu\-layout [save|restore] [name] .SH DESCRIPTION \fBbyobu\-layout\fP will save and restore \fBbyobu-tmux\fP(1) split window layouts. If 'name' is blank, it operates interactively. Note that this only works with Byobu when backed by \fBtmux\fP(1), and not \fBscreen\fP(1). .SH SEE ALSO \fBbyobu\fP(1), \fBtmux\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-prompt.1000066400000000000000000000031351522352767600206520ustar00rootroot00000000000000.TH byobu-prompt 1 "16 January 2024" byobu "byobu" .SH NAME byobu-prompt, byobu-enable-prompt, byobu-disable-prompt \- add and remove a nice color prompt with a previous command timer to your shell configuration .SH SYNOPSIS \fBbyobu-prompt\fP .TP \fBbyobu-enable-prompt\fP .TP \fBbyobu-disable-prompt\fP .SH DESCRIPTION Byobu provides a special PS0 and PS1 prompt command, compatible with Bash shells. It will display the previous command's total runtime and exit code, if it's not zero. It will use 3 separate colors for the local username, hostname, and the current working directory. \fBbyobu-enable-prompt\fP will add one line to your \fI~/.bashrc\fP. You can safely remove the line from your \fI~/.bashrc\fP, which ends in \fB#byobu-prompt\fP. \fBbyobu-disable-prompt\fP will remove its color configuration from \fI~/.bashrc\fP. \fBbyobu-prompt\fP is an interactive wrapper of the previous two tools. .SH "BUGS" This is currently only compatible with \fBbash(1)\fP. .SH SEE ALSO .PD 0 .TP \fBbash\fP(1) .TP \fBhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-quiet.1000066400000000000000000000024041522352767600204560ustar00rootroot00000000000000.TH byobu-quiet 1 "10 May 2011" byobu "byobu" .SH NAME byobu\-quiet \- Silence all of Byobu's status indicators and eliminate the hardstatus line .SH USAGE byobu\-quiet [\-\-undo] .SH DESCRIPTION \fBbyobu\-quiet\fP will disable ALL of Byobu's status indicators and eliminate the hardstatus line. Some administrators, in some environments, at some times may prefer a very minimal, quiet Byobu, without the potentially distracting status indicators and eye candy. However, the window menu is preserved, as well as all of Byobu's keybindings and helper utilities. To eliminate the window list, use \fBbyobu-silent\fP(1). .SH SEE ALSO \fBbyobu-silent\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-reconnect-sockets.1000066400000000000000000000022121522352767600227550ustar00rootroot00000000000000.TH byobu-reconnect-sockets 1 "7 Dec 2009" byobu "byobu" .SH NAME byobu\-reconnect\-sockets \- Sourcable script that updates GPG_AGENT_INFO and DBUS_SESSION_BUS_ADDRESS in the environment .SH DESCRIPTION \fBbyobu\-reconnect\-sockets\fP is a sourcable bit of shell code that will update the GPG_AGENT_INFO and DBUS_SESSION_BUS_ADDRESS environment variables in the current shell, such that you may restablish connection to \fBgpg\-agent\fP(1) and \fBdbus\-daemon(1)\fP. This is often useful when reattaching to a detached Byobu session. .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-screen.1000066400000000000000000000016021522352767600206050ustar00rootroot00000000000000.TH byobu-screen 1 "10 Aug 2011" byobu "byobu" .SH NAME byobu\-screen \- Launch byobu with screen as the backend .SH DESCRIPTION \fBbyobu\-screen\fP launches \fBbyobu\fP(1) with \fBscreen\fP(1) as the backend window manager. .SH SEE ALSO \fBbyobu\fP(1), \fBscreen\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-select-backend.1000066400000000000000000000027601522352767600222000ustar00rootroot00000000000000.TH byobu\-select\-backend 1 "30 Oct 2011" byobu "byobu" .SH NAME byobu\-select\-backend \- select your default Byobu backend window manager .SH SYNOPSIS \fBbyobu\-select\-backend\fP [screen|tmux] .SH DESCRIPTION \fBbyobu\-select\-backend\fP is an application that lists the available Byobu backends and allows you to select your default. You can select one of either \fBscreen\fP(1) or \fBtmux\fP(1) on the command line, or giving no command line parameters, the utility will run interactively. This utility will only affect which backend is used by default when simply running, \fBbyobu\fP(1). Note that at any time, you can force the backend of a particular session by running the helpers, \fBbyobu-screen\fP(1) or \fBbyobu-tmux\fP(1). .SH FILES \fI~/.byobu/backend\fP .SH "SEE ALSO" .PD 0 .TP \fBbyobu\fP(1), \fBbyobu-screen\fP(1), \fBbyobu-tmux\fP(1), \fBscreen\fP(1), \fBtmux\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-select-profile.1000066400000000000000000000025141522352767600222460ustar00rootroot00000000000000.TH byobu\-select\-profile 1 "4 Dec 2009" byobu "byobu" .SH NAME byobu\-select\-profile \- select your Byobu foreground and background colors .SH DESCRIPTION \fBbyobu\-select\-profile\fP is an application that changes Byobu's status bar foreground and background colors .SH OPTIONS -l,--list list available profiles -b,--background COLOR set the background color -f,--foreground COLOR set the foreground color -h,--hostname set the colors based on a hash of the hostname -i,--ip set the colors based on a hash of the ip -r,--random set the colors randomly --help this help .SH "SEE ALSO" .PD 0 .TP \fBbyobu\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-select-session.1000066400000000000000000000034121522352767600222670ustar00rootroot00000000000000.TH byobu\-select\-session 1 "12 Jan 2010" byobu "byobu" .SH NAME byobu\-select\-session \- select and connect to a byobu session .SH DESCRIPTION \fBbyobu\-select\-session\fP is an application that lists the available screen sessions running on the system, and prompts the user to select one. The user also has the option to create a new Byobu session, or launch the default shell without Byobu. If an invalid selection is chosen 3 times in a row, the user is connected to the youngest session. By default, if only one session exists, the user is connected to that session, and if no sessions exist, a new session is created -- such that there is no interactive prompt in the normal behavior. However, some users may choose to always be prompted, by touching the file $BYOBU_CONFIG_DIR/.always-select. Note that BYOBU_CONFIG_DIR=$HOME/.byobu. Named sessions that begin with a "." are "hidden" from \fBbyobu\-select\-session\fP(1). This is useful, for instance, if you do not want a session to be automatically selected at login. Example: byobu \-S .hidden .SH "FILES" \fI$BYOBU_CONFIG_DIR/.always-select\fP .SH "SEE ALSO" .PD 0 .TP \fBbyobu\fP(1), \fBscreen\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-shell.1000066400000000000000000000016551522352767600204450ustar00rootroot00000000000000.TH byobu\-shell 1 "11 Feb 2009" byobu "byobu" .SH NAME byobu\-shell \- Print the message of the day and launch a shell .SH DESCRIPTION \fBbyobu\-shell\fP is a simple script that prints the message of the day (/etc/motd) and launches a shell. $SHELL will be invoked if it exists. Otherwise, /bin/sh will be used. .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-silent.1000066400000000000000000000022731522352767600206310ustar00rootroot00000000000000.TH byobu-silent 1 "21 May 2011" byobu "byobu" .SH NAME byobu\-silent\- Silence all of Byobu's status indicators, eliminate the hardstatus line, and the window list .SH USAGE byobu\-silent [\-\-undo] .SH DESCRIPTION \fBbyobu\-silent\fP will disable ALL of Byobu's status indicators, eliminate the hardstatus line, and the window list. Some administrators, in some environments, at some times may prefer a very minimal, quiet Byobu, without the potentially distracting status indicators and eye candy. \fBbyobu-silent\fP implies \fBbyobu-quiet\fP. .SH SEE ALSO \fBbyobu-quiet\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-status-detail.1000066400000000000000000000016071522352767600221160ustar00rootroot00000000000000.TH byobu-status-detail 1 "27 Apr 2009" byobu "byobu" .SH NAME byobu\-status\-detail \- Wrapper that uses a sensible pager .SH DESCRIPTION \fBbyobu\-status\-detail\fP is a simple script that uses a sensible pager for displaying the detailed status of all byobu status scripts. .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-status.1000066400000000000000000000016341522352767600206560ustar00rootroot00000000000000.TH byobu-status 1 "15 Aug 2011" byobu "byobu" .SH NAME byobu\-status \- displays status suitable for printing by the BYOBU_BACKEND .SH DESCRIPTION \fBbyobu\-status\fP is a program periodically called by the BYOBU_BACKEND to gather the formatted status strings displayed in to lower status bar(s). .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-tmux.1000066400000000000000000000015661522352767600203340ustar00rootroot00000000000000.TH byobu-tmux 1 "10 Aug 2011" byobu "byobu" .SH NAME byobu\-tmux \- Launch byobu with tmux as the backend .SH DESCRIPTION \fBbyobu\-tmux\fP launches \fBbyobu\fP(1) with \fBtmux\fP(1) as the backend window manager. .SH SEE ALSO \fBbyobu\fP(1), \fBtmux\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-ugraph.1000066400000000000000000000045541522352767600206250ustar00rootroot00000000000000.TH byobu-ugraph 1 "16 Dec 2013" byobu "byobu" .SH NAME \fBbyobu\-ugraph\fP \- helper script for notification history graphs .SH DESCRIPTION \fBbyobu\-ugraph\fP is a helper script that can be used to create history graphs .SH USAGE \fBbyobu\-ugraph\fP [options] [command [args...]] .SH OPTIONS -f : File to read data points from. (only required if no command specified). -h : Show this help. -m : Minimum value (default=$min_default). -n : Suppress output of newline character. -p : Specify number of data points in graph (default=$points_default). -r : Do not rotate file (default is to rotate). Option implies file should not be written to so a command cannot follow script options in this case. -t : 'byobu-ulevel' theme to use (default=$theme_default). -x : Maximum value (default=$max_default). .SH EXAMPLES Using byobu-ugraph to run a command, rotate log and display graph. Here we specify a command to display available memory. Trailing echo adds a required newline Note no filename specified. byobu-ugraph "(/usr/lib/byobu/mem_used | sed -e 's/% //g';echo)" Using byobu-ugraph just to rotate log and display the graph file=/tmp/load.dat awk '{ print $1}' /proc/loadavg >> $file # Note: we need to specify what we consider to be a "reasonable" maximum load byobu-ugraph -m 3.0 -f $file .SH NOTES If you specify 'command', care must be taken with shell quoting to avoid expansion prior to this script running the command. If '-r' is not specified, the file will be rotated such that at most lines are retained on each invocation of this script. .SH SEE ALSO \fBbyobu\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This utility was written by James Hunt , and this manpage was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu-ulevel.1000066400000000000000000000065641522352767600206360ustar00rootroot00000000000000.TH byobu-ulevel 1 "16 Dec 2013" byobu "byobu" .SH NAME \fBbyobu\-ulevel \fP \- helper script for notification level indicators .SH DESCRIPTION \fBbyobu\-ulevel\fP is a helper script that can be used to create history graphs with UTF8 characters .SH USAGE \fBbyobu\-ulevel \fP [options] -c \fBbyobu\-ulevel \fP [options] \fBbyobu\-ulevel \fP .SH OPTIONS -a : Accessibility mode: only output ASCII. (Also enabled if variable '$a11y_variable' set). -b : Display current value as space if zero, rather than lowest 'value' of theme. -c : Current value of your indicator. -d : Enable debug output. -e : Number of decimal places to use for accessibility mode (default=$default_decimal_places). -h : Show this help. -i : Invert colour scheme (rating themes only). -l : List available themes. If '-t' also specified, show all values for specified theme. -m : Minimum value (default=$min_default). -n : Suppress output of newline character. -p : Permissive mode - if current value out of bounds, set it to the nearest bound (min or max). -q : Suppress messages (requires '-t'). -r : Reverse 'direction' of display (rating theme only). -t : Name of theme (default=$theme_default). -u : Specify a user theme (2 or more values). -w : Width of rating theme (default=$width_default). -x : Maximum value (default=$max_default). .SH EXAMPLES Display character representing 27% using default theme. byobu-ulevel 27 As above. byobu-ulevel -c 27 Example showing floating-point and negative values. byobu-ulevel -c 1.100001 -m -5.00234 -x 2.71828 -t dice_6 Use accessibility mode to display a percentage value (rounded to nearest percentage) byobu-ulevel -m -22.613 -x 5.00212 -c 0.10203 -a -e 0 Display value using a "rating theme" (displayed left-to-right). byobu-ulevel -c 83 -t stars_2 Display right-to-left inverted "rating theme". byobu-ulevel -c 60 -t diamonds_2 -ri Display all glyphs in 'solid_numbers_a_10' theme. byobu-ulevel -l -t solid_numbers_a_10 Display a user-specified rating theme 10 glyphs wide. byobu-ulevel -c 666.321 -m -273.15 -x 1370 -u "· ☢" -w 10 A multi-element user theme (this prints 'e'). byobu-ulevel -c 50 -u "a b c d e f g h i j" .SH NOTES Arguments of type "" denote an integer value, whereas arguments of type "" denotes either an integer or a floating-point number. The final '_' in a theme name denotes the number of glyphs in it. "Rating themes" are those with only 2 values. The argument to '-u' must contain space-delimited characters. .SH SEE ALSO \fBbyobu\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This utility was written by James Hunt , and this manpage was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/byobu.1000066400000000000000000000534771522352767600173510ustar00rootroot00000000000000.TH byobu 1 "19 June 2009" byobu "byobu" .SH NAME byobu \- wrapper script for seeding a user's byobu configuration and launching a text based window manager (either screen or tmux) .SH SYNOPSIS \fBbyobu\fP [options] \fBbyobu\-screen\fP [screen options] \fBbyobu\-tmux\fP [tmux options] Options to \fBbyobu\fP are simply passed through \fBscreen\fP(1) or \fBtmux\fP(1). .SH DESCRIPTION \fBbyobu\fP is a script that launches a text based window manager (either \fBscreen\fP(1) or \fBtmux\fP(1)) in the byobu configuration. This enables the display of system information and status notifications within two lines at the bottom of the screen session. It also enables multiple tabbed terminal sessions, accessible through simple keystrokes. \fBbyobu\fP currently defaults to using \fBtmux\fP(1) (if present) as the backend, however, this can be overridden with the \fBbyobu-select-backend\fP(1) utility. Note that BYOBU_CONFIG_DIR=\fI$XDG_CONFIG_HOME/byobu\fP if defined, and \fI$HOME/.byobu\fP otherwise. .SH BACKGROUND COLORS The background colors of the \fBbyobu\fP status lines can be adjusted by editing the files \fI$HOME/.byobu/color\fP (for \fBbyobu\-screen\fP) and \fI$HOME/.byobu/color.tmux\fP (for \fBbyobu\-tmux\fP). The command \fBCtrl-Shift-F5\fP will change the background to a randomly selected color when running in \fBbyobu\-tmux\fP mode. Simply remove those files to return to the default color configuration. .SH STATUS NOTIFICATIONS \fBbyobu\fP supports a number of unique and interesting status notifications across the lowest two lines in the screen. Each status notification item is independently configurable, enabled and disabled by the configuration utility. The guide below helps identify each status item (in alphabetical order): \fBapport\fP \- symbol displayed if there are pending crash reports; {!} symbol displayed on the lower bar toward the left, in black on an orange background \fBarch\fP \- system architecture; displayed on the lower bar toward the left, in the default text color on the default background color \fBbattery\fP \- battery information; display on the lower bar toward the right; \- indicates discharging, + indicates charging, = indicates fully charged; when charging or discharging, the current battery capacity as a percentage is displayed; the colours green, yellow, and red are used to give further indication of the battery's charge state; you may override the detected battery by setting BATTERY=/proc/acpi/battery/BAT0 in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBcpu_count\fP \- the number of cpu's or cores on the system; displayed in the lower bar toward the right in the default text color on the default background, followed by a trailing 'x' \fBcpu_freq\fP \- the current frequency of the cpu in GHz; displayed in the lower bar toward the right in white text on a light blue background \fBcpu_temp\fP \- the cpu temperature in Celsius (default) or Fahrenheit, configure TEMP=F or TEMP=C in \fI$BYOBU_CONFIG_DIR/statusrc\fP; displayed in the lower bar toward the right in yellow text on a black background; you may override the detected cpu temperature device by setting MONITORED_TEMP=/proc/acpi/whatever in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBcustom\fP \- user defined custom scripts; must be executable programs of any kind in \fI$BYOBU_CONFIG_DIR/bin\fP; must be named N_NAME, where N is the frequency in seconds to refresh the status indicator, and NAME is the name of the script; N should not be less than 5 seconds; the script should echo a small amount of text to standard out, standard error is discarded; the indicator will be displayed in the lower panel, in default colors, unless you manually specify the colors in your script's output; BEWARE, cpu-intensive custom scripts may impact your overall system performance and could upset your system administrator! In fact, you can easily copy and modify \fBany\fP status script usually found in \fI/usr/lib/byobu/*\fP to your local \fI$HOME/.byobu/\fP directory. Example: \fI$BYOBU_CONFIG_DIR/bin/1000_uname\fP #!/bin/sh printf "\\005{= bw}%s\\005{\-}" "$(uname \-r)" \fBdate\fP \- the system date in YYYY-MM-DD format, or you can set this to any valid \fBstrftime\fP(3) you like in \fI$BYOBU_CONFIG_DIR/datetime\fP; displayed in the lower on the far right in the default text color on the default background \fBdisk\fP \- total disk space available and total used on / directory; displayed in the lower bar on the far right in white text on a light purple background; override the default directory by specifying an alternate mount point with MONITORED_DISK=/wherever in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBdisk_io\fP \- instantaneous read/write througput in kB/s or MB/s over the last 3 seconds; displayed in the lower bar toward the right in white text on a light purple background with a leading '<' sign indicating 'read speed' and '>' sign indicating 'write speed'; override the default monitored disk by specifying an alternate device with MONITORED_DISK=/dev/sdb, and override the default DISK_IO_THRESHOLD=50 (kB/s) in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBdistro\fP \- OS/distribution name of the release running on the current system as reported by \fBlsb_release(1)\fP or \fI/etc/issue\fP; displayed in the lower bar in bold black text toward the left on a grey background; you may override the detected release with DISTRO=Whatever in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBentropy\fP \- a count of the system's current entropy in bytes; displayed in the lower bar toward the right in yellow text on a dark grey background; there is a leading 'e' to indicate 'entropy' \fBraid\fP \- note very prominently if there is a RAID failure detected, in red blinking text on a white background; the term 'RAID' notes that there is something wrong with the RAID, and if there is a rebuild/resync in progress, the percent complete is also shown \fBfan_speed\fP \- cpu or system fan speed as reported by lm-sensors; displayed in the lower bar toward the right in black text on a grey background; there is a trailing 'rpm' for units; you may override the detected fan by setting FAN=/sys/path/to/your/fan1_input in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBhostname\fP \- the hostname of the system; displayed in the upper bar on the far right in bold black text on a grey background; there is a leading '@' symbol if the username status is also enabled \fBip_address\fP \- the IPv4 address of the system in dotted decimal form; displayed in the upper bar on the far right in bold black text on a grey background; you can override and display your IPv6 address by setting 'IPV6=1', and you can show your external ip address by setting 'IP_EXTERNAL=1' in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBip_address4\fP \- the IPv4 address of the system in dotted decimal form; displayed in the upper bar on the far right in bold black text on a grey background; you can show your external ip address by setting 'IP_EXTERNAL=1' in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBip_address6\fP \- the IPv6 address of the system; displayed in the upper bar on the far right in bold black text on a grey background; you can show your external ip address by setting 'IP_EXTERNAL=1' in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBload_average\fP \- the system load average over the last 1 minute; displayed in the lower bar toward the right in black text on a yellow background; set LOAD_AVERAGES=3 in \fI$BYOBU_CONFIG_DIR/statusrc\fP to display all three intervals (1, 5, and 15 minutes) space-separated \fBlogo\fP \- an approximation of the current operating system's logo; displayed in the lower bar on the far left; you may customize this logo by setting a chosen logo with LOGO=:-D in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBmail\fP \- system mail for the current user; the letter '[M]' is displayed in the lower bar toward the left in black text on a grey background \fBmemory\fP \- total memory available and used percentage in the system; displayed in the lower bar toward the right in white text on a green background \fBmenu\fP \- a simple indicator directing new users to use the F9 keybinding to access the byobu menu \fBnetwork\fP \- instantaneous upload/download bandwidth in [GMk]bps over the last 3 seconds; nothing is displayed if traffic is 0; displayed in the lower bar toward the left in white text on a purple background with a leading '^' sign indicating 'up' and 'v' sign indicating 'down'; override the default interface by specifying an alternate interface with MONITORED_NETWORK=eth1, and override the default units (bits) with NETWORK_UNITS=bytes, and override the default NETWORK_THRESHOLD=20 (kbps) in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBnotify_osd\fP \- Send on-screen notification messages to screen's notification buffer \fBpackages\fP \- total number of packages installed on the system; displayed in the lower bar in yellow text on a white background inside of square brackets, '[xxx]' \fBprocesses\fP \- total number of processes running on the system; displayed in the lower bar in white text on a dark yellow background with a trailing '&' indicating 'background processes' \fBreboot_required\fP \- symbol present if a reboot is required following a system update; displayed in the lower bar white text on a blue background by the symbol '(R)'; additionally, reboot_required will print '' in white text on a blue background, if Byobu requires you to reload your profile to affect some changes; it will also detect if your system is currently in \fBpowernap\fP(8) state and if so print '.zZ'; if your system is currently performing an \fBunattended-upgrade\fP(1) you will see a white warning sign on a red background. \fBrelease\fP \- OS/distribution name of the release running on the current system as reported by \fBlsb_release(1)\fP or \fI/etc/issue\fP; displayed in the lower bar in bold black text toward the left on a grey background; you may override the detected release with RELEASE=Whatever in \fI$BYOBU_CONFIG_DIR/statusrc\fP; you may also abbreviate the release string to N characters by setting RELEASE_ABBREVIATED=N in \fI$BYOBU_CONFIG_DIR/statusrc\fP \fBservices\fP \- users can configure a list of services to monitor, define the SERVICES variable in \fI$BYOBU_CONFIG_DIR/statusrc\fP, a whitespace separated of services, each service should include the init name of the service, then a pipe, and then an abbreviated name or symbol to display when running (e.g. SERVICES="ssh|ssh apache2|http"); displayed in the lower bar toward the center in cyan on a white background \fBsession\fP \- byobu session name (only supported in \fBbyobu-tmux\fP(1)); displayed in the lower bar on the left in underlined black text on a white background \fBswap\fP \- total swap space and total used as a percentage of the total available; displayed in the lower bar toward the right in black text on a light green background with a trailing '%' sign \fBtime\fP \- the system time in HH:MM:SS format (by default), or you can set this to any valid \fBstrftime\fP(3) you like in \fI$BYOBU_CONFIG_DIR/datetime\fP; displayed in the lower bar on the far right in the default text and default background colors \fBtime_binary\fP \- only for the hard core geek, the local system time in binary; requires UTF-8 support in a VERY recent version of GNU Screen; displayed in the lower bar on the far right in the default text and background colors \fBtime_utc\fP \- the UTC system time in HH:MM format; displayed in the lower bar on the far right in dark text on a light background \fBupdates_available\fP \- the number of updates available on the system; displayed in the lower bar toward the right in white text on a red background with a trailing '!' sign; if any updates are marked 'security updates', then there will be a total of two trailing exclamation points, '!!' \fBuptime\fP \- the total system uptime since last boot; displayed in the lower bar toward the right in blue text on a grey background \fBusers\fP \- the number of remote users logged into the system via sshd, empty if 0 users; displayed in the lower bar toward the right in red text on a grey background with a trailing '#' sign; set USERS_DISTINCT=1 to instead count the number of distinct users logged into the system (rather than open ssh sessions) \fBwhoami\fP \- the name of the user who owns the screen session; displayed in the upper bar toward the far right in bold black text on a grey background \fBwifi_quality\fP \- the connection rate and signal quality of the wifi connection; displayed in the lower bar toward the right in black text on a cyan background; the connection rate is in 'Mb/s' and the signal quality is as a percentage with a trailing '%'; override the default interface by specifying an alternate interface with MONITORED_NETWORK=wlan0 in \fI$BYOBU_CONFIG_DIR/statusrc\fP .SH STATUS ICONS \fBbyobu\fP displays status indicators using different icons depending on your terminal encoding. When using \fBbyobu\-tmux\fP(1) with UTF-8 encoding, Unicode symbols are displayed. Otherwise, ASCII\-only icons are used (such as with \fBbyobu\-screen\fP(1) or non\-UTF\-8 terminals). .TP \fBUnicode Icons\fP (displayed when BYOBU_BACKEND=tmux and BYOBU_CHARMAP=UTF\-8): .TP .B updates_available: ! = regular updates available; ⚠ = distribution upgrades available; ‼ = security updates available .TP .B reboot_required: ⟳ = system reboot required; ⚠ = unattended upgrade in progress; 🗹 = kernel is live\-patched .TP .B disk_io: ◂ = disk read activity; ▸ = disk write activity .TP .B network: ▴ = network upload activity; ▾ = network download activity .TP .B mail: ⍌ = new mail waiting .TP .B session: 〣 = session indicator .TP .B trash: ♸ = items in trash .TP \fBASCII Icons\fP (displayed with screen backend or non\-UTF\-8 terminals): .TP .B updates_available: ! = regular updates; /!\\\\ = upgrades; !! = security updates .TP .B reboot_required: (R) = reboot required; /!\\\\ = upgrade running; [/] = live\-patched .TP .B disk_io: < = read; > = write .TP .B network: ^ = upload; v = download .TP .B mail: [M] = new mail .TP .B session: | = session indicator .TP .B trash: T = trash .TP To see detailed explanations of all active status indicators, press \fBCtrl\-a $\fP while running byobu. .SH SESSIONS Byobu name screen sessions "byobu", if unspecified. To hide sessions from \fBbyobu-select-session\fP(1), prepend a "." to the beginning of the session name, like: byobu \-S .hidden .SH WINDOWS Each open window in the screen session is displayed in the upper bar toward the far left. These are numbered, and include indicators as to activity in the window (see "activity" in \fBscreen\fP(1) and \fBtmux\fP(1) for symbol definitions). The current active window is highlighted by inverting the background/text from the rest of the window bar. Users can create a list of windows to launch at startup in \fI$BYOBU_CONFIG_DIR/windows\fP and \fI$BYOBU_CONFIG_DIR/windows.tmux\fP. This file is the same syntax as \fI~/.screenrc\fP and \fI~/.tmuxrc\fP, each line specifying a window, as described in \fBscreen\fP(1) or \fBtmux\fP(1). User can also launch Byobu with unique window sets. Users can store these as \fI$BYOBU_CONFIG_DIR/windows.[NAME]\fP and \fI$BYOBU_CONFIG_DIR/windows.tmux.[NAME]\fP, and launch Byobu with the environment variable \fBBYOBU_WINDOWS\fP=NAME. For example: $ cat $BYOBU_CONFIG_DIR/windows.ssh_sessions screen \-t localhost bash screen \-t aussie ssh root@aussie screen \-t beagle ssh root@beagle screen \-t collie ssh root@collie Then: $ BYOBU_WINDOWS=ssh_sessions byobu For example: $ cat $BYOBU_CONFIG_DIR/windows.tmux.split4 new-session 'bash' ; new-window -n term1 ; new-window -n term2 ; new-window -n ssh ssh 10.9.8.7 ; split-window ; split-window ; split-window ; select-layout tiled ; select-pane -t 0 Then: $ BYOBU_WINDOWS=split4 byobu .SH UNITS OF MEASURE byobu uses binary for capacity measurements of KB, MB, GB, and TB. This means multiples of 1024 rather than multiples of 1000, in accordance with JEDEC Standard 100B.01 for memory capacity measurements. See: * http://en.wikipedia.org/wiki/JEDEC_memory_standards byobu uses decimal for measurements of network data transfer, meaning multiple of 1000, rather than 1024. See: * http://en.wikipedia.org/wiki/Data_rate_units .SH KEYBINDINGS byobu keybindings can be user defined in /usr/share/byobu/keybindings/ (or within .screenrc if byobu-export was used). The common key bindings are: \fBF2\fP \- Create a new window \fBF3\fP \- Move to previous window \fBF4\fP \- Move to next window \fBF5\fP \- Reload profile \fBF6\fP \- Detach from this session \fBF7\fP \- Enter copy/scrollback mode \fBF8\fP \- Re-title a window \fBF9\fP \- Configuration Menu \fBF12\fP \- Lock this terminal \fBshift-F2\fP \- Split the screen horizontally \fBctrl-F2\fP \- Split the screen vertically \fBshift-F3\fP \- Shift the focus to the previous split region \fBshift-F4\fP \- Shift the focus to the next split region \fBshift-F5\fP \- Join all splits \fBctrl-F6\fP \- Remove this split \fBctrl-F5\fP \- Reconnect GPG and SSH sockets \fBshift-F6\fP \- Detach, but do not logout \fBalt-pgup\fP \- Enter scrollback mode \fBalt-pgdn\fP \- Enter scrollback mode \fBCtrl-a $\fP \- show detailed status \fBCtrl-a R\fP \- Reload profile \fBCtrl-a !\fP \- Toggle key bindings on and off (screen backend) \fBShift-F12\fP \- Toggle byobu F-key bindings on and off (tmux backend) \fBCtrl-a k\fP \- Kill the current window \fBCtrl-a ~\fP \- Save the current window's scrollback buffer .SH "SCROLLBACK, COPY, PASTE MODES" Each window in Byobu has up to 10,000 lines of scrollback history, which you can enter and navigate using the \fBalt-pgup\fP and \fBalt-pgdn\fP keys. Exit this scrollback mode by hitting \fBenter\fP. You can also easily copy and paste text from scrollback mode. To do so, enter scrollback using \fBalt-pgup\fP or \fBalt-pgdn\fP, press the \fBspacebar\fP to start highlighting text, use \fBup/down/left/right/pgup/pgdn\fP to select the text, and press \fBenter\fP to copy the text. You can then paste the text using \fBalt-insert\fP or \fBctrl-a-]\fP. .SH "BUGS" For Byobu colors to work properly, older versions of GNU Screen require a 1-line patch to adjust MAX_WINMSG_REND in screen.c. The change is in GNU Screen's upstream source control system as of 2010-01-26, but GNU Screen has not released a new upstream version in several years. You can disable colors entirely by setting MONOCHROME=1 in \fI$BYOBU_CONFIG_DIR/statusrc\fP. For more information, see: * http://savannah.gnu.org/bugs/?22146 PuTTY users have reported that the F2, F3, and F4 shortcut keys are not working properly. PuTTY sends the same escape sequences as the linux console for F1-F4 by default. You can fix this problem in the PuTTY config, Terminal -> Keyboard -> Function keys: Xterm R6. See: \fIhttp://www.mail-archive.com/screen-users@gnu.org/msg01525.html\fP PuTTY users should configure enable UTF-8 characters in order to fix status refresh issues. You can fix this problem in the PuTTY configuration, Window -> Translation: select UTF-8. PuTTY users should avoid resizing their window to one character tall, as this can sometimes crash \fBbyobu-screen\fP. Apple Mac OSX terminal users have reported 'flashing text'. You can fix this in the advanced settings of the terminal application, with 'Declare Terminal As: xterm-color'. Apple Mac keyboard users may need to specify a vt100 terminal by adding this to your OSX profile, in order to get Byobu's function keys and colors to work: alias ssh='TERM=vt100 ssh' URxvt users have reported that Ctrl+Shift+F-key combinations do not work by default, because URxvt does not send the expected escape sequences for those key chords. You can fix this by adding the following to \fI~/.Xresources\fP (then running \fBxrdb -merge ~/.Xresources\fP): .nf URxvt.keysym.S-C-F1: string:\\033[11@ URxvt.keysym.S-C-F2: string:\\033[12@ URxvt.keysym.S-C-F3: string:\\033[13@ URxvt.keysym.S-C-F4: string:\\033[14@ URxvt.keysym.S-C-F5: string:\\033[15@ URxvt.keysym.S-C-F6: string:\\033[17@ URxvt.keysym.S-C-F7: string:\\033[18@ URxvt.keysym.S-C-F8: string:\\033[19@ URxvt.keysym.S-C-F9: string:\\033[20@ URxvt.keysym.S-C-F10: string:\\033[21@ URxvt.keysym.S-C-F11: string:\\033[23@ URxvt.keysym.S-C-F12: string:\\033[24@ .fi See: \fIhttps://github.com/dustinkirkland/byobu/issues/108\fP Users of a non-UTF-8 locale (such as cs_CZ charset ISO-8859-2), may need to add "defutf8 off" to \fI~/.screenrc\fP, if some characters are rendering as "?". Users who customize their PS1 prompt need to put this setting in \fI~/.bashrc\fP, rather than \fI~/.profile\fP, in order for it to work correctly with Byobu. If you run \fBbyobu\fP(1) under \fBsudo\fP(8), you \fBmust\fP use the \-H option, such that the user's $HOME directory environment variable is set properly. Otherwise, \fBbyobu\fP(1) will create a bunch of directories in the $SUDO_USER's $HOME, but will be owned by root. To prevent this from happening, \fBbyobu\fP(1) will simply refuse to run if $USER does not own $HOME. Byobu requires a suitable \fBulimit\fP(3) values to run. If you get an error at startup saying, 'pipe: too many open files', then check your ulimit \-a values, as your "open files" or "max user processes" are too low. In this case, you will probably need to run simple \fBscreen\fP(1) .SH SEE ALSO .PD 0 .TP \fBscreen\fP(1), \fBbyobu-config\fP(1), \fBbyobu-export\fP(1), \fBbyobu-status\fP(1), \fBbyobu-status-detail\fB(1), \fBbyobu-enable\fB(1), \fBbyobu-launch\fB(1), \fBbyobu-select-backend\fP(1), \fBtmux\fP(1) .TP \fIhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document and the utility under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/col1.1000066400000000000000000000024411522352767600170500ustar00rootroot00000000000000.TH col1 1 "27 Sep 2010" byobu "byobu" .SH NAME col1 .. col9, NF \- awk and print a column (based on the name of the program, 1-9) .SH SYNOPSIS .BI "col1 [SEPARATOR]" .SH DESCRIPTION \fBcol1\fP is a simple script that conveniently splits and prints a given column, where the column to print is the name of the script program you're running (col1-col9). col2-col9 are symlinks to col1; their behavior simply changes based on the name called. \fBNF\fP can be used to print the last field. The program takes one optional argument, the input field separator (whitespace, by default). .SH EXAMPLES Rather than: mount | awk '{print $3}' Try: mount | col3 Instead of: cat /etc/passwd | awk \-F":" '{print $7}' You can just do: cat /etc/passwd | col7 : Or cat /etc/passwd | NF : .SH SEE ALSO \fBawk\fP(1)\fP .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/ctail.1000066400000000000000000000014751522352767600173140ustar00rootroot00000000000000.TH ctail 1 "23 Oct 2012" byobu "byobu" .SH NAME ctail \- watch and colorize a logfile .SH SYNOPSIS \fBctail\fP [FILE] .SH DESCRIPTION \fBctail\fP is a very simple alias that watches a file and colorizes it. It's very useful for monitoring logfiles. .SH EXAMPLE ctail /var/log/syslog .SH SEE ALSO \fBccze\fP(1), \fBtail\fP(1) .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/manifest.1000066400000000000000000000017261522352767600200250ustar00rootroot00000000000000.TH manifest 1 "28 February 2016" byobu "byobu" .SH NAME manifest \- import or export a package list .SH SYNOPSIS \fBmanifest\fP export [-|URL|FILENAME] .TP \fBmanifest\fP import -|URL|FILENAME .TP .SH DESCRIPTION .SH "BUGS" This is currently only compatible with \fBapt(8)\fP and \fBdpkg\fP(1). .SH SEE ALSO .PD 0 .TP \fBapt\fP(8), \fBdpkg\fP(1), \fBpastebinit\fP(1) .TP \fBhttps://byobu.org\fP .PD .SH AUTHOR This manpage and the utility were written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. The complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fP on Debian/Ubuntu systems, or in \fI/usr/share/doc/fedora-release-*/GPL\fP on Fedora systems, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/purge-old-kernels.1000066400000000000000000000020351522352767600215500ustar00rootroot00000000000000.TH purge-old-kernels 1 "30 Apr 2012" byobu "byobu" .SH NAME purge-old-kernels - remove old kernel and header packages from the system .SH SYNOPSIS \fBpurge-old-kernels\fP .SH DESCRIPTION This utility is now deprecated. The functionality it used to provide should be integrated into \fIapt\fP(8). If you still have old kernels lying around after this, please file a bug against apt: https://bugs.launchpad.net/ubuntu/+source/apt/+filebug This program requires administrative access. .SH EXAMPLE sudo purge-old-kernels .SH SEE ALSO \fBapt-get\fP(8) .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/vigpg.1000066400000000000000000000015551522352767600173330ustar00rootroot00000000000000.TH vigpg 1 "25 Apr 2014" byobu "byobu" .SH NAME vigpg \- open and edit an encrypted file .SH SYNOPSIS \fBvigpg\fP [FILE] .SH DESCRIPTION \fBvigpg\fP is a program that wraps your editor and gpg to edit an encrypted file This may be useful, for instance, to edit your password file .SH EXAMPLE $ vigpg passwords.txt.gpg .SH SEE ALSO \fBgpg\fP(1)\fP, \fBsensible-editor\fP(1) .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/man/man1/wifi-status.1000066400000000000000000000015131522352767600204700ustar00rootroot00000000000000.TH wifi-status 1 "27 Sep 2010" byobu "byobu" .SH NAME wifi-status \- monitor the wireless interface .SH SYNOPSIS \fBwifi-status\fP [INTERFACE] .SH DESCRIPTION \fBwifi-status\fP is a program that monitors a wireless interface. This is often useful when trying to associate with an access point. .SH SEE ALSO \fBiwconfig\fP(8)\fP, \fBip\fP(8) .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL, or on the web at \fIhttp://www.gnu.org/licenses/gpl.txt\fP. byobu-7.15/usr/share/sounds/000077500000000000000000000000001522352767600160335ustar00rootroot00000000000000byobu-7.15/usr/share/sounds/byobu/000077500000000000000000000000001522352767600171535ustar00rootroot00000000000000byobu-7.15/usr/share/sounds/byobu/Makefile.am000066400000000000000000000000771522352767600212130ustar00rootroot00000000000000sounddir = $(datadir)/sounds/byobu dist_sound_DATA = byobu.ogg byobu-7.15/usr/share/sounds/byobu/byobu.ogg000066400000000000000000000266321522352767600210020ustar00rootroot00000000000000OggSMPvorbisDwOggSMP`{vorbis-Xiph.Org libVorbis I 20101101 (Schaufenugget)ARTIST=Fumihito YOSHIDA DATE=2009TITLE=Pronunciation of Byobuvorbis)BCV1L ŀАU`$)fI)(yHI)0c1c1c 4d( Ij9g'r9iN8 Q9 &cnkn)% Y@H!RH!b!b!r!r * 2 L2餓N:騣:(B -JL1Vc]|s9s9s BCV BdB!R)r 2ȀАU GI˱$O,Q53ESTMUUUUu]Wvevuv}Y[}Y[؅]aaaa}}} 4d #9)"9d ")Ifjihm˲,˲ iiiiiiifYeYeYeYeYeYeYeYeYeYeYeYeY@h*@@qq$ER$r, Y@R,r4Gs4sMP %'"&2365+*,+(32166&%`$MBLbON˝ m1rWrԑlYڔ\4p%|(w$ڔ\4HXf&G6 .X{|*;3fD[L>uz__:@9~P"QuxHuяl%9,59(%; =5PEO#ؤlAiw8N#h=L}7 4Awη|>JJ1l0|1\w22_&\Cc4WPON5^@V < nTXWvfX\}S1~̴,hb0%}8٫}I`'MQ}޹hQJPVѯ[V;'Sdj-9s?j"Q[P^11<`(Ai' T@3xeL GiDleC~F\OK7UF4HՋ ( H5`@mx1gz|y5@lEY¥h:)#̯)` }quȳ$N˱24L&.w *qt},3}vחb!|WfA0[t".n5W,7%PVأ(etzGLPje[E dPD&wBFF`!bs-A/. .\wح>jA=SyPH0Ǥr!γ[yK29fhH8ls}pw!?dc7zեtPʒ_DP8(˧Q"ҿmԚ#fon=nV(Ǐ>i.Pp 9Pe'zUn﵇ÛOJ`V9sM:ckjtcD}m{BCb Y(hg`kiS)L}cdM   E:6*xYB 4hιwL&5M;͊ku7Y _1^Qh3%-S/,ަ^7 י(#3cNqM7QA[VNSNt}R\hκi^-zlf+(fKU̙s5e{Rڍ‚ *ү n}c>'nT]٨3O"&[3?BOv7XIS3k7shh–@f4$x N3z,O,thGM$U'5*V:N$"nd!&].a ٻ=ϐp v3 ߸F1FA3r 8:ďٝ> }{P?3 7 1%[>d;̉M3 rcuoۈRYJ6zj҈P&/>Gih9 z@zu0EN<ͲbDŝI$oh+aDdk u-]IN0.U0^V^" )])Ғ0 x.,8~0rc;o+{%,SS UdL̛ $UzvK#%`̅|&@H MiڎdSIS&.To8̠ .$tA4>m_ˉ>[őd%b]\\=+ٿVѶ&ZyGֿCƽt9ס7+FMɧʍӋ24[NJxhZ1Xs}ԁw˞!$0xIY6"EN% RaT KD2+Yx#j_TNҰЭ͆>, H>&(Թ_+f\;e WYE4s+9BS>bΉ9Jӯ_A휗&ڂ k^mSɆ($߀詋fޤ ^2OAJ?JCX`H+Ж T.|YO0xpiD*庻Sb(1|z'{?M(tAm~ P~!yJ-yu<`bqq[v8C5 0mRcBYћ[d|ŏ=b0 @~š!vZgWL/BLd[qrx͐N_>22dl[c\^t1Y[Œ b>`/2g3FoDˉUsB[%<"w;]?w_0apbUOJeNSRm9g[` DYz5\(^4meQ(i$v'L2ZrPȕqi`ASP/ŘfEFi뱨gi+2@PV(d{} `j+$ \s21[Mj2o޳M"p@I㙳J-38b{ ?^5 f*%0@ӝD`se,~Nh xy G9"J>מBC=f-/cT2;52;dRzk<#\\3{3νF mPj9xNys޹MԔ cpMM (HI<25Cyh˵0B̍(՘Y(¨t L@{0ɞ3I(?#i(KƅfJl@kȮRt>*t 8HJGs ܀Zp \JG/K+w \Gz+Ԑ%pCmpd+ȊNb\,IE$ͩ<tXpZP)z_d^4Bg0ԦAZ t uMIv܊t^קONsT S.JUesda}>@9kyc*Q@R0bz+(tC ڴ>]/I IdVl:J8W 0aEˁy(VJ?I,B\*v¸.:Uu GjYVwLH =^{=n社ߐ`?;V0',*nf9g λ9~H4=3IɊMa-TeS/5|dۦRYJpD}~H8E,1. }}3Lw1(A`/_S>oT`:"bc@b}-z xѲiIJf`ܶck*|ng{xҟ\x!"2NRUTpC; <ۻ0?(Un'S y y~ݛy,s3_P燄(,sGgj.t?U_]f5DZ3:WG}l"x\O$,E[nb[ ƭfzcYjX9u(-:P?LJZŶs2ACԞMk p^*&aZk?+ =N& Оy5ڒ4Se7 c>๿/ luCƽxwqYaCvQv .e8WNn~ys2Z9x8wK ̪mM,RlCkYQ pD^K&^_3v6.Hy菐5(o=b,Cw_")4q+/^Kr3ٳ./Bt r{̾NdLgY…4=#Ժ*SgUtkϭi|R.ccW2۔,9F)jwb -V~hdl:S,)?u`opZ\|cӼ65di.Y>O>EqJyB`#,+YYQBܝNM` )@mnTG+z%@Fd?<`Sgc2N.4NH${iiԫ1&@ Ax߲gP!Wك&7됶<-ZlH4]v|(:6ynDAO's`SӱWg``}.lt~G="MdnkÁpti!$t?ϛ_viPԅ< ,WC{LJZ !"~QQng{Șufb5%ɝgdUbI [Bk&L-" /}PD~1g:5 ԝe6uA)YVcMb RElS3ptCd'GzB3+Ư?_뼤_ѳgkI5s(`%< Z?^S d*0v^64wZ#Lyd0Z"y5 *pi}~p @ 1Q.ZeAW4pe(oJ`fŔvzk pχq±׃W.O`(AP | *sP