PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /usr/share/graphviz/lefty
Viewing File: /usr/share/graphviz/lefty/dotty.lefty
# # DOTTY # dotty = [ 'keys' = [ 'nid' = 'nid'; 'eid' = 'eid'; 'gid' = 'gid'; 'name' = 'name'; 'attr' = 'attr'; 'gattr' = 'graphattr'; 'eattr' = 'edgeattr'; 'nattr' = 'nodeattr'; 'edges' = 'edges'; 'tail' = 'tail'; 'tport' = 'tport'; 'head' = 'head'; 'hport' = 'hport'; 'pos' = 'pos'; 'size' = 'size'; 'rect' = 'rect'; 'fname' = 'fontname'; 'fsize' = 'fontsize'; 'fcolor' = 'fontcolor'; 'dcolor' = 'drawcolor'; 'bcolor' = 'fillcolor'; ]; 'maps' = [ 'X11' = [ 'fontmap' = [ 'Times-Roman' = '-*-times-medium-r-*--%d-*-*-*-*-*-*-1'; 'Times-Italic' = '-*-times-medium-i-*--%d-*-*-*-*-*-*-1'; 'Times-Bold' = '-*-times-bold-r-*--%d-*-*-*-*-*-*-1'; 'Courier' = '-*-courier-bold-r-*--%d-*-*-*-*-*-*-1'; 'Courier-Bold' = '-*-courier-bold-r-*--%d-*-*-*-*-*-*-1'; 'Helvetica' = ( '-*-helvetica-medium-r-normal--%d-*-*-*-p-*-iso8859-1' ); 'Helvetica-Bold' = ( '-*-helvetica-bold-r-normal--%d-*-*-*-p-*-iso8859-1' ); ]; 'psfontmap' = [ 'Times-Roman' = 'Times-Roman'; 'Times-Italic' = 'Times-Italic'; 'Times-Bold' = 'Times-Bold'; 'Courier' = 'Courier'; 'Courier-Bold' = 'Courier-Bold'; 'Helvetica' = 'Helvetica'; 'Helvetica-Bold' = 'Helvetica-Bold'; ]; ]; 'mswin' = [ 'fontmap' = [ 'Times-Roman' = 'Times New Roman'; 'Times-Italic' = 'Times New Roman Italic'; 'Times-Bold' = 'Times New Roman Bold'; 'Courier' = 'Courier New'; 'Courier-Bold' = 'Courier New Bold'; 'Helvetica' = 'Arial'; 'Helvetica-Bold' = 'Arial Bold'; ]; 'psfontmap' = [ 'Times-Roman' = 'Times New Roman'; 'Times-Italic' = 'Times New Roman Italic'; 'Times-Bold' = 'Times New Roman Bold'; 'Courier' = 'Courier New'; 'Courier-Bold' = 'Courier New Bold'; 'Helvetica' = 'Arial'; 'Helvetica-Bold' = 'Arial Bold'; ]; ]; ]; 'protogt' = [ 'graph' = [ 'graphattr' = [ 'fontsize' = '14'; 'fontname' = 'Times-Roman'; 'fontcolor' = 'black'; ]; 'nodeattr' = [ 'shape' = 'ellipse'; 'fontsize' = '14'; 'fontname' = 'Times-Roman'; 'fontcolor' = 'black'; 'style' = 'solid'; ]; 'edgeattr' = [ 'fontsize' = '14'; 'fontname' = 'Times-Roman'; 'fontcolor' = 'black'; 'style' = 'solid'; ]; 'graphdict' = []; 'nodedict' = []; 'graphs' = []; 'nodes' = []; 'edges' = []; 'maxgid' = 0; 'maxnid' = 0; 'maxeid' = 0; 'type' = 'digraph'; ]; 'layoutmode' = 'sync'; 'lserver' = 'dot'; 'edgehandles' = 1; 'noundo' = 0; ]; 'lservers' = []; 'mlevel' = 0; 'graphs' = []; 'views' = []; 'protovt' = [ 'normal' = [ 'name' = 'DOTTY'; 'orig' = ['x' = 1; 'y' = 1;]; 'size' = ['x' = 420; 'y' = 520;]; 'wrect' = [ 0 = ['x' = 0; 'y' = 0;]; 1 = ['x' = 400; 'y' = 500;]; ]; 'vsize' = ['x' = 400; 'y' = 500;]; 'w2v' = 1; ]; 'birdseye' = [ 'type' = 'birdseye'; 'name' = 'DOTTY birdseye view'; 'orig' = ['x' = 1; 'y' = 1;]; 'size' = ['x' = 220; 'y' = 260;]; 'wrect' = [ 0 = ['x' = 0; 'y' = 0;]; 1 = ['x' = 200; 'y' = 250;]; ]; 'vsize' = ['x' = 200; 'y' = 250;]; 'w2v' = 1; ]; ]; 'pagesizes' = [ '8.5x11' = ['x' = 8; 'y' = 10.5;]; '11x17' = ['x' = 10.5; 'y' = 16.5;]; '36x50' = ['x' = 35.5; 'y' = 49.5;]; ]; ]; load ('dotty_draw.lefty'); load ('dotty_edit.lefty'); load ('dotty_layout.lefty'); load ('dotty_ui.lefty'); # # initialization functions # dotty.init = function () { dotty.fontmap = dotty.maps[getenv ('LEFTYWINSYS')].fontmap; dotty.clipgt = dotty.protogt.creategraph (['noundo' = 1;]); dotty.inited = 1; }; dotty.simple = function (file) { if (dotty.inited ~= 1) dotty.init (); dotty.createviewandgraph (file, 'file', null, null); txtview ('off'); }; # # main operations # dotty.protogt.creategraph = function (protogt) { local gt, id, gtid; if (~protogt) protogt = dotty.protogt; for (gtid = 0; dotty.graphs[gtid]; gtid = gtid + 1) ; gt = (dotty.graphs[gtid] = []); if (protogt.mode ~= 'replace') { for (id in dotty.protogt) gt[id] = copy (dotty.protogt[id]); } for (id in protogt) gt[id] = copy (protogt[id]); gt.gtid = gtid; gt.views = []; gt.undoarray = ['level' = 0; 'entries' = [];]; gt.busy = 0; return gt; }; dotty.protogt.copygraph = function (ogt) { local gt, gtid, id; for (gtid = 0; dotty.graphs[gtid]; gtid = gtid + 1) ; gt = (dotty.graphs[gtid] = []); for (id in ogt) gt[id] = copy (ogt[id]); gt.gtid = gtid; gt.views = []; gt.undoarray = ['level' = 0; 'entries' = [];]; gt.busy = 0; return gt; }; dotty.protogt.destroygraph = function (gt) { local vid, vlist; if (gt.layoutpending > 0) gt.cancellayout (gt); for (vid in gt.views) vlist[vid] = gt.views[vid]; for (vid in gt.views) gt.destroyview (gt, vlist[vid]); remove (gt.gtid, dotty.graphs); }; dotty.protogt.loadgraph = function (gt, name, type, protograph, layoutflag) { local fd, vid, vt, graph, nid, eid, gid; if (gt.layoutpending > 0) gt.cancellayout (gt); if (~name) if (~(name = ask ('file name:', 'file', ''))) return; dotty.pushbusy (gt, gt.views); dotty.message (1, 'loading'); if (~protograph) protograph = dotty.protogt.graph; if ( ~((fd = dotty.openio (name, type, 'r')) >= 0) | ~(graph = readgraph (fd, protograph)) ) { dotty.message (0, 'cannot load graph'); dotty.popbusy (gt, gt.views); return; } for (vid in gt.views) { vt = gt.views[vid]; vt.colors = []; vt.colorn = 2; } gt.graph = graph; gt.name = name; gt.type = type; gt.undoarray = ['level' = 0; 'entries' = [];]; if (~(type == 'file' & name == '-')) closeio (fd); graph.maxgid = tablesize (graph.graphs); graph.maxnid = tablesize (graph.nodes); graph.maxeid = tablesize (graph.edges); for (nid in graph.nodes) graph.nodes[nid][dotty.keys.nid] = nid; for (eid in graph.edges) graph.edges[eid][dotty.keys.eid] = eid; for (gid in graph.graphs) graph.graphs[gid][dotty.keys.gid] = gid; gt.unpackattr (gt); if (layoutflag) { dotty.message (1, 'generating layout'); gt.layoutgraph (gt); } dotty.popbusy (gt, gt.views); return gt.graph; }; dotty.protogt.savegraph = function (gt, name, type) { local fd; if (~name) if (~(name = ask ('file name:', 'file', ''))) return; if ( ~((fd = dotty.openio (name, type, 'w')) >= 0) | ~writegraph (fd, gt.graph, 0) ) { dotty.message (0, 'cannot save graph'); return; } if (~(type == 'file' & name == '-')) closeio (fd); }; dotty.protogt.setgraph = function (gt, graph) { local vid, vt, nid, eid, gid; if (gt.layoutpending > 0) gt.cancellayout (gt); for (vid in gt.views) { vt = gt.views[vid]; vt.colors = []; vt.colorn = 2; } gt.graph = copy (graph); gt.undoarray = ['level' = 0; 'entries' = [];]; gt.unpackattr (gt); gt.graph.maxgid = tablesize (graph.graphs); gt.graph.maxnid = tablesize (graph.nodes); gt.graph.maxeid = tablesize (graph.edges); for (nid in gt.graph.nodes) gt.graph.nodes[nid][dotty.keys.nid] = nid; for (eid in gt.graph.edges) gt.graph.edges[eid][dotty.keys.eid] = eid; for (gid in gt.graph.graphs) gt.graph.graphs[gid][dotty.keys.gid] = gid; gt.unpackattr (gt); dotty.message (1, 'generating layout'); gt.layoutgraph (gt); return gt.graph; }; dotty.protogt.erasegraph = function (gt, protogt, protovt) { local vid, vt; if (gt.layoutpending > 0) gt.cancellayout (gt); for (vid in gt.views) { vt = gt.views[vid]; vt.colors = []; vt.colorn = 2; clear (vt.canvas); } if (~protogt) protogt = dotty.protogt; gt.graph = copy (protogt.graph); gt.undoarray = ['level' = 0; 'entries' = [];]; }; dotty.protogt.layoutgraph = function (gt) { if (gt.graph.graphattr.xdotversion) { gt.unpacklayout (gt, gt.graph); gt.setviewsize (gt.views, gt.graph.rect); gt.redrawgraph (gt, gt.views); return; } if (gt.layoutmode == 'async') { if (~gt.haveinput) { gt.startlayout (gt); return; } if (~gt.finishlayout (gt)) return; gt.setviewsize (gt.views, gt.graph.rect); gt.redrawgraph (gt, gt.views); } else { if (~gt.startlayout (gt)) return; else while (~gt.finishlayout (gt)) ; gt.setviewsize (gt.views, gt.graph.rect); gt.redrawgraph (gt, gt.views); } }; dotty.protogt.createview = function (gt, protovt) { local vt, ovt, id, t; vt = []; vt.colors = []; vt.colorn = 2; if (~protovt) protovt = dotty.protovt.normal; if (protovt.mode ~= 'replace') { for (id in dotty.protovt[protovt.type]) vt[id] = copy (dotty.protovt[protovt.type][id]); } for (id in protovt) vt[id] = copy (protovt[id]); if (~(vt.parent >= 0)) { vt.view = createwidget (-1, [ 'type' = 'view'; 'name' = vt.name; 'origin' = vt.orig; 'size' = vt.size; ]); vt.scroll = createwidget (vt.view, ['type' = 'scroll';]); } else { vt.view = -1; vt.scroll = createwidget (vt.parent, [ 'type' = 'scroll'; 'size' = vt.size; ]); } vt.canvas = createwidget (vt.scroll, [ 'type' = 'canvas'; 'color' = [0 = protovt.bgcolor; 1 = protovt.fgcolor;]; ]); setwidgetattr (vt.canvas, [ 'window' = vt.wrect; 'viewport' = vt.vsize; ]); clear (vt.canvas); dotty.views[vt.canvas] = vt; vt.vtid = vt.canvas; vt.gtid = gt.gtid; gt.views[vt.vtid] = vt; dotty.views[vt.scroll] = vt; if (vt.view ~= -1) dotty.views[vt.view] = vt; if (protovt.colors & tablesize (protovt.colors) > 0) { for (id in protovt.colors) if (id == '_bgcolor_') setwidgetattr (vt.canvas, [ 'color' = [0 = protovt.colors[id];]; ]); else if (setwidgetattr (vt.canvas, ['color' = [ protovt.colors[id] = id; ];]) ~= 1) { t = split (id, ' '); if (tablesize (t) ~= 3 | setwidgetattr (vt.canvas, [ 'color' = [protovt.colors[id] = [ 'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]); ];]; ]) ~= 1) { dotty.message ( 0, concat ('unknown color ', id, ' using #1') ); } } vt.colors = copy (protovt.colors); vt.colorn = protovt.colorn; } else if (tablesize (gt.views) > 1) { for (id in gt.views) if (gt.views[id] ~= vt) break; ovt = gt.views[id]; for (id in ovt.colors) if (id == '_bgcolor_') setwidgetattr (vt.canvas, ['color' = [0 = ovt.colors[id];];]); else if (setwidgetattr (vt.canvas, ['color' = [ ovt.colors[id] = id; ];]) ~= 1) { t = split (id, ' '); if (tablesize (t) ~= 3 | setwidgetattr (vt.canvas, [ 'color' = [ovt.colors[id] = [ 'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]); ];]; ]) ~= 1) { dotty.message ( 0, concat ('unknown color ', id, ' using #1') ); } } vt.colors = copy (ovt.colors); vt.colorn = ovt.colorn; } if (gt.graph.rect) gt.setviewsize ([vt.vtid = vt;], gt.graph.rect); gt.drawgraph (gt, [vt.vtid = vt;]); for (id in vt.uifuncs) if (id == 'closeview') widgets[vt.view][id] = vt.uifuncs[id]; else widgets[vt.canvas][id] = vt.uifuncs[id]; return vt; }; dotty.protogt.destroyview = function (gt, vt) { destroywidget (vt.canvas); destroywidget (vt.scroll); if (vt.view ~= -1) { destroywidget (vt.view); remove (vt.view, dotty.views); } remove (vt.scroll, dotty.views); remove (vt.canvas, dotty.views); if (vt.gtid >= 0) remove (vt.vtid, gt.views); if (tablesize (dotty.views) == 0) exit (); }; dotty.protogt.zoom = function (gt, vt, factor, pos) { gt.setviewscale ([vt.vtid = vt;], factor); if (pos) gt.setviewcenter ([vt.vtid = vt;], pos); gt.redrawgraph (gt, [vt.vtid = vt;]); }; dotty.protogt.findnode = function (gt, vt) { local key, node, node1, nid; if (~(key = ask ('give node name or label'))) return; if (gt.graph.nodedict[key] >= 0) node = gt.graph.nodes[gt.graph.nodedict[key]]; else if (gt.graph.nodedict[ston (key)] >= 0) node = gt.graph.nodes[gt.graph.nodedict[ston (key)]]; else { for (nid in gt.graph.nodes) { node1 = gt.graph.nodes[nid]; if (node1.attr.label == key | node1.attr.label == ston (key)) { node = node1; break; } } } if (~node) { dotty.message (0, concat ('cannot find node: ', key)); return; } gt.setviewcenter ([vt.vtid = vt;], node.pos); }; dotty.protogt.setattr = function (gt, obj) { local kv, t, attr, value, n, i, s; if (~(kv = ask ('give attr/value, eg. color=blue'))) return; t = split (kv, '='); attr = t[0]; value = t[1]; if ((n = tablesize (t)) > 2) for (i = 2; i < n; i = i + 1) value = concat (value, '=', t[i]); # Check for HTML string and convert using lefty convention s = split (value, ''); n = tablesize (s); if ((s[0] == '<') & (s[n-1] == '>')) { s[0] = '>'; s[n-1] = '<'; value = s[0]; for (i = 1; i < n; i = i + 1) value = concat (value, s[i]); } if ( obj.attr == gt.graph.graphattr | obj.attr == gt.graph.edgeattr | obj.attr == gt.graph.nodeattr ) { obj.attr[attr] = value; return; } if (obj.nid >= 0) { gt.undrawnode (gt, gt.views, obj); obj.attr[attr] = value; gt.unpacknodeattr (gt, obj); gt.drawnode (gt, gt.views, obj); } else if (obj.eid >= 0) { gt.undrawedge (gt, gt.views, obj); obj.attr[attr] = value; gt.unpackedgeattr (gt, obj); gt.drawedge (gt, gt.views, obj); } }; dotty.protogt.getattr = function (gt, node) { local kv; if (~(kv.key = ask ('give attr name'))) return null; if ((kv.val = node.attr[kv.key])) return kv; return null; }; # # utilities # dotty.createviewandgraph = function (name, type, protogt, protovt) { local vt, gt; if (~protogt) protogt = dotty.protogt; if (protogt.creategraph) gt = protogt.creategraph (protogt); else gt = dotty.protogt.creategraph (protogt); vt = gt.createview (gt, protovt); if (~protogt.graph) protogt.graph = copy (dotty.protogt.graph); if (name) gt.loadgraph (gt, name, type, protogt.graph, 1); return ['gt' = gt; 'vt' = vt;]; }; dotty.openio = function (name, type, mode) { local fd; if (~name) return null; if (type == 'file') { if (name == '-') { if (mode == 'r' | mode == 'r+') fd = 0; else fd = 1; } else if (~((fd = openio ('file', name, mode)) >= 0)) { dotty.message (0, concat ('cannot open file: ', name)); return null; } } else if (type == 'pipe') { if (~((fd = openio ( 'pipe', 'ksh', mode, concat ("%e ", name) )) >= 0)) { dotty.message (0, concat ('cannot run command: ', name)); return null; } } else return null; return fd; }; dotty.pushbusy = function (gt, views) { local vid; if (gt.busy == 0) for (vid in gt.views) setwidgetattr (vid, ['cursor' = 'watch';]); gt.busy = gt.busy + 1; }; dotty.popbusy = function (gt, views) { local vid; gt.busy = gt.busy - 1; if (gt.busy == 0) for (vid in gt.views) setwidgetattr (vid, ['cursor' = 'default';]); }; dotty.message = function (level, text) { if (level <= dotty.mlevel) echo ('dotty.lefty: ', text); }; # # printing or saving to file # dotty.protogt.printorsave = function (gt, vt, otype, name, mode, ptype) { local pr, wrect, vsize, xy, psize, canvas, pscanvas, cid, cname, t; local graph, edgehandles, fontmap, eid, edge, nid, node, gid, sgraph; local did, draw, i; if (~otype) if (~(otype = ask ('print to', 'choice', 'file|printer'))) return; if (otype == 'printer') { if (~getenv ('TMPDIR')) name = concat (getenv ('HOME'), '/.dottyout.ps'); else name = concat (getenv ('TMPDIR'), '/.dottyout.ps', random (10000)); if (getenv ('LEFTYWINSYS') ~= 'mswin' & ~pr) if (~(pr = ask ('printer command', 'string', 'lpr'))) return; } if (~name) if (~(name = ask ('postscript file', 'file', 'out.ps'))) return; if (~ptype) if (~(ptype = ask ('page size', 'choice', '8.5x11|11x17|36x50'))) return; if (~mode) if (~(mode = ask ('mode', 'choice', 'portrait|landscape|best fit'))) return; wrect = copy (vt.wrect); wrect[0].x = wrect[0].x - 1; wrect[1].x = wrect[1].x + 1; wrect[0].y = wrect[0].y - 1; wrect[1].y = wrect[1].y + 1; vsize = copy (vt.vsize); if (vsize.x == 0) vsize.x = 1; if (vsize.y == 0) vsize.y = 1; xy = vsize.x / vsize.y; if (mode == 'best fit') { if (xy < 1) mode = 'portrait'; else mode = 'landscape'; } psize = dotty.pagesizes[ptype]; if (mode == 'portrait') { if (xy < psize.x / psize.y) { vsize.y = psize.y * 300; vsize.x = vsize.y * xy; } else { vsize.x = psize.x * 300; vsize.y = vsize.x / xy; } } else { if (xy < psize.y / psize.x) { vsize.y = psize.x * 300; vsize.x = vsize.y * xy; } else { vsize.x = psize.y * 300; vsize.y = vsize.x / xy; } } if (~((pscanvas = createwidget (-1, [ 'type' = 'ps'; 'origin' = ['x' = 0; 'y' = 0;]; 'size' = vsize; 'mode' = mode; 'name' = name; ])) >= 0)) { dotty.message (0, 'cannot open printer device'); return; } for (cname in vt.colors) { cid = vt.colors[cname]; if (cname == '_bgcolor_') setwidgetattr (pscanvas, ['color' = [0 = cid;];]); else if (setwidgetattr (pscanvas, ['color' = [cid = cname;];]) ~= 1) { t = split (cname, ' '); if (tablesize (t) ~= 3 | setwidgetattr (pscanvas, [ 'color' = [cid = [ 'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]); ];]; ]) ~= 1) { dotty.message ( 0, concat ('unknown color ', cname, ' using #1') ); } } } setwidgetattr (pscanvas, ['window' = wrect;]); graph = copy (gt.graph); canvas = vt.canvas; vt.canvas = pscanvas; edgehandles = gt.edgehandles; gt.edgehandles = 0; fontmap = dotty.maps[getenv ('LEFTYWINSYS')].psfontmap; for (eid in graph.edges) { edge = graph.edges[eid]; edge.fontname = fontmap[edge.attr.fontname]; for (did in edge.draws) { if (did == 'ep') continue; draw = edge.draws[did]; for (i = 0; draw[i]; i = i + 1) if (draw[i].type == 'F') draw[i].fn = fontmap[draw[i].ofn]; } gt.drawedge (gt, [0 = vt;], edge); } for (nid in graph.nodes) { node = graph.nodes[nid]; node.fontname = fontmap[node.attr.fontname]; for (did in node.draws) { if (did == 'ep') continue; draw = node.draws[did]; for (i = 0; draw[i]; i = i + 1) if (draw[i].type == 'F') draw[i].fn = fontmap[draw[i].ofn]; } gt.drawnode (gt, [0 = vt;], node); } for (gid in graph.graphs) { sgraph = graph.graphs[gid]; sgraph.fontname = fontmap[sgraph.graphattr.fontname]; for (did in sgraph.draws) { if (did == 'ep') continue; draw = sgraph.draws[did]; for (i = 0; draw[i]; i = i + 1) if (draw[i].type == 'F') draw[i].fn = fontmap[draw[i].ofn]; } gt.drawsgraph (gt, [0 = vt;], sgraph); } graph.fontname = fontmap[graph.graphattr.fontname]; gt.drawsgraph (gt, [0 = vt;], graph); gt.edgehandles = edgehandles; vt.canvas = canvas; destroywidget (pscanvas); if (otype == 'printer' & getenv ('LEFTYWINSYS') ~= 'mswin') system (concat (pr, ' ', name, '; rm ',name)); };