|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #############################################################################  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Output an Graph::Easy object as textual description  | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Graph::Easy::As_txt;  | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 $VERSION = '0.76';  | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #############################################################################  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #############################################################################  | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Graph::Easy;  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
14
 | 
15
 | 
 
 | 
 
 | 
  
15
  
 | 
 
 | 
7485
 | 
 use strict;  | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
    | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
425
 | 
    | 
| 
15
 | 
15
 | 
 
 | 
 
 | 
  
15
  
 | 
 
 | 
45
 | 
 use warnings;  | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7804
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _as_txt  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
19
 | 
211
 | 
 
 | 
 
 | 
  
211
  
 | 
 
 | 
616
 | 
   my ($self) = @_;  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Convert the graph to a textual representation - does not need layout().  | 
| 
22
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
699
 | 
   $self->_assign_ranks();  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # generate the class attributes first  | 
| 
25
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
236
 | 
   my $txt = '';  | 
| 
26
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
295
 | 
   my $att =  $self->{att};  | 
| 
27
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
639
 | 
   for my $class (sort keys %$att)  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $out = $self->_remap_attributes(  | 
| 
31
 | 
544
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1770
 | 
      $class, $att->{$class}, {}, 'noquote', 'encode' );  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
33
 | 
544
 | 
 
 | 
 
 | 
 
 | 
 
 | 
623
 | 
     my $att = '';  | 
| 
34
 | 
544
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1121
 | 
     for my $atr (sort keys %$out)  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # border is handled special below  | 
| 
37
 | 
302
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
431
 | 
       next if $atr =~ /^border/;  | 
| 
38
 | 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
594
 | 
       $att .= "  $atr: $out->{$atr};\n";  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # edges do not have a border  | 
| 
42
 | 
544
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1072
 | 
     if ($class !~ /^edge/)  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
44
 | 
437
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
1037
 | 
       my $border = $self->border_attribute($class) || '';  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # 'solid 1px #000000' =~ /^solid/;  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # 'solid 1px #000000' =~ /^solid 1px #000000/;  | 
| 
48
 | 
437
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
998
 | 
       $border = '' if $self->default_attribute($class,'border') =~ /^$border/;  | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
50
 | 
437
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
953
 | 
       $att .= "  border: $border;\n" if $border ne '';  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
53
 | 
544
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1339
 | 
     if ($att ne '')  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # the following makes short, single definitions to fit on one line  | 
| 
56
 | 
170
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
805
 | 
       if ($att !~ /\n.*\n/ && length($att) < 40)  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
58
 | 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
267
 | 
         $att =~ s/\n/ /; $att =~ s/^  / /;  | 
| 
 
 | 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
265
 | 
    | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       else  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
62
 | 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
117
 | 
         $att = "\n$att";  | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
64
 | 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
570
 | 
       $txt .= "$class {$att}\n";  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
68
 | 
211
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
427
 | 
   $txt .= "\n" if $txt ne '';		# insert newline  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
70
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
543
 | 
   my @nodes = $self->sorted_nodes('name','id');  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
72
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
318
 | 
   my $count = 0;  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # output nodes with attributes first, sorted by their name  | 
| 
74
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
351
 | 
   foreach my $n (@nodes)  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
76
 | 
860
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1032
 | 
     $n->{_p} = undef;			# mark as not yet processed  | 
| 
77
 | 
860
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1450
 | 
     my $att = $n->attributes_as_txt();  | 
| 
78
 | 
860
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1620
 | 
     if ($att ne '')  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
80
 | 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
302
 | 
       $n->{_p} = 1;			# mark as processed  | 
| 
81
 | 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
243
 | 
       $count++;  | 
| 
82
 | 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
442
 | 
       $txt .= $n->as_pure_txt() . $att . "\n";  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
86
 | 
211
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
426
 | 
   $txt .= "\n" if $count > 0;		# insert a newline  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # output groups first, with their nodes  | 
| 
89
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
209
 | 
   foreach my $gn (sort keys %{$self->{groups}})  | 
| 
 
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
711
 | 
    | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
91
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
     my $group = $self->{groups}->{$gn};  | 
| 
92
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
107
 | 
     $txt .= $group->as_txt();		# marks nodes as processed if nec.  | 
| 
93
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
57
 | 
     $count++;  | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # XXX TODO:  | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Output all nodes with rank=0 first, and also follow their successors  | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # What is left will then be done next, with rank=1 etc.  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # This output order let's us output node chains in compact form as:  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # [A]->[B]->[C]->[D]  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # [B]->[E]  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # instead of having:  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # [A]->[B]  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # [B]->[E]  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # [B]->[C] etc  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
107
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
554
 | 
   @nodes = $self->sorted_nodes('rank','name');  | 
| 
108
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
358
 | 
   foreach my $n (@nodes)  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
110
 | 
860
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1933
 | 
     my @out = $n->sorted_successors();  | 
| 
111
 | 
860
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1339
 | 
     my $first = $n->as_pure_txt(); 		# [ A | B ]  | 
| 
112
 | 
860
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
2933
 | 
     if ( defined $n->{autosplit} || ((@out == 0) && ( (scalar $n->predecessors() || 0) == 0)))  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # single node without any connections (unless already output)  | 
| 
115
 | 
134
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
437
 | 
       next if exists $n->{autosplit} && !defined $n->{autosplit};  | 
| 
116
 | 
75
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
170
 | 
       $txt .= $first . "\n" unless defined $n->{_p};  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
119
 | 
801
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1327
 | 
     $first = $n->_as_part_txt();		# [ A.0 ]  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # for all outgoing connections  | 
| 
121
 | 
801
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1123
 | 
     foreach my $other (@out)  | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # in case there exists more than one edge from $n --> $other  | 
| 
124
 | 
576
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1229
 | 
       my @edges = $n->edges_to($other);  | 
| 
125
 | 
576
 | 
 
 | 
 
 | 
 
 | 
 
 | 
821
 | 
       for my $edge (sort { $a->{id} <=> $b->{id} } @edges)  | 
| 
 
 | 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
    | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
127
 | 
612
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1375
 | 
         $txt .= $first . $edge->as_txt() . $other->_as_part_txt() . "\n";  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
132
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
262
 | 
   foreach my $n (@nodes)  | 
| 
133
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
134
 | 
860
 | 
 
 | 
 
 | 
 
 | 
 
 | 
793
 | 
     delete $n->{_p};			# clean up  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
137
 | 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
899
 | 
   $txt;  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #############################################################################  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Graph::Easy::Group;  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
144
 | 
15
 | 
 
 | 
 
 | 
  
15
  
 | 
 
 | 
66
 | 
 use strict;  | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2659
 | 
    | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub as_txt  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
148
 | 
45
 | 
 
 | 
 
 | 
  
45
  
 | 
  
1
  
 | 
419
 | 
   my $self = shift;  | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
150
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
49
 | 
   my $n = '';  | 
| 
151
 | 
45
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
250
 | 
   if (!$self->isa('Graph::Easy::Group::Anon'))  | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
153
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
54
 | 
     $n = $self->{name};  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # quote special chars in name  | 
| 
155
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
99
 | 
     $n =~ s/([\[\]\(\)\{\}\#])/\\$1/g;  | 
| 
156
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
80
 | 
     $n = ' ' . $n;  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
158
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
159
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
   my $txt = "($n";  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
161
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
54
 | 
   $n = $self->{nodes};  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
163
 | 
45
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
134
 | 
   $txt .= (keys %$n > 0 ? "\n" : ' ');  | 
| 
164
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
122
 | 
   for my $name ( sort keys %$n )  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
166
 | 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
122
 | 
     $n->{$name}->{_p} = 1;                              # mark as processed  | 
| 
167
 | 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
165
 | 
     $txt .= '  ' . $n->{$name}->as_pure_txt() . "\n";  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
169
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
113
 | 
   $txt .= ")" . $self->attributes_as_txt() . "\n\n";  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # insert all the edges of the group  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   #  | 
| 
174
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
75
 | 
   $txt;  | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #############################################################################  | 
| 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Graph::Easy::Node;  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
181
 | 
15
 | 
 
 | 
 
 | 
  
15
  
 | 
 
 | 
62
 | 
 use strict;  | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
123
 | 
    | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14449
 | 
    | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub attributes_as_txt  | 
| 
184
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # return the attributes of this node as text description  | 
| 
186
 | 
1553
 | 
 
 | 
 
 | 
  
1553
  
 | 
  
1
  
 | 
1890
 | 
   my ($self, $remap) = @_;  | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # nodes that were autosplit  | 
| 
189
 | 
1553
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2202
 | 
   if (exists $self->{autosplit})  | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # other nodes are invisible in as_txt:  | 
| 
192
 | 
128
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
242
 | 
     return '' unless defined $self->{autosplit};  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # the first one might have had a label set  | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
196
 | 
1470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1197
 | 
   my $att = '';  | 
| 
197
 | 
1470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2712
 | 
   my $class = $self->class();  | 
| 
198
 | 
1470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1402
 | 
   my $g = $self->{graph};  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # XXX TODO: remove atttributes that are simple the default attributes  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
202
 | 
1470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1333
 | 
   my $attributes = $self->{att};  | 
| 
203
 | 
1470
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2064
 | 
   if (exists $self->{autosplit})  | 
| 
204
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # for the first node in a row of autosplit nodes, we need to create  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # the correct attributes, e.g. "silver|red|" instead of just silver:  | 
| 
207
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
     my $basename = $self->{autosplit_basename};  | 
| 
208
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
51
 | 
     $attributes = { };  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
210
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
87
 | 
     my $parts = $self->{autosplit_parts};  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # gather all possible attribute names, otherwise an attribute set  | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # on only one part (like via "color: |red;" would not show up:  | 
| 
213
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
     my $names = {};  | 
| 
214
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
566
 | 
     for my $child ($self, @$parts)  | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
216
 | 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
112
 | 
       for my $k (sort keys %{$child->{att}})  | 
| 
 
 | 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
268
 | 
    | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
218
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
67
 | 
         $names->{$k} = undef;  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
222
 | 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
     for my $k (sort keys %$names)  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
224
 | 
32
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
64
 | 
       next if $k eq 'basename';  | 
| 
225
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
       my $val = $self->{att}->{$k};  | 
| 
226
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
22
 | 
       $val = '' unless defined $val;  | 
| 
227
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
       my $first = $val; my $not_equal = 0;  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
    | 
| 
228
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
       $val .= '|';  | 
| 
229
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
       for my $child (@$parts)  | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
231
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # only consider our own autosplit parts (check should not be nec.)  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #        next if !exists $child->{autosplit_basename} ||  | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #                        $child->{autosplit_basename} ne $basename;  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
235
 | 
21
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
21
 | 
         my $v = $child->{att}->{$k}; $v = '' if !defined $v;  | 
| 
 
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
    | 
| 
236
 | 
21
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
26
 | 
         $not_equal ++ if $v ne $first;  | 
| 
237
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
         $val .= $v . '|';  | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # all parts equal, so do "red|red|red" => "red"  | 
| 
240
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
25
 | 
       $val = $first if $not_equal == 0;  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
242
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
       $val =~ s/\|+\z/\|/;				# "silver|||" => "silver|"  | 
| 
243
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
39
 | 
       $val =~ s/\|\z// if $val =~ /\|.*\|/;		# "silver|" => "silver|"  | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       							# but "red|blue|" => "red|blue"  | 
| 
245
 | 
14
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
39
 | 
       $attributes->{$k} = $val unless $val eq '|';	# skip '|'  | 
| 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
247
 | 
45
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
174
 | 
     $attributes->{basename} = $self->{att}->{basename} if defined $self->{att}->{basename};  | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
250
 | 
1470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3201
 | 
   my $new = $g->_remap_attributes( $self, $attributes, $remap, 'noquote', 'encode' );  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # For nodes, we do not output their group attribute, since they simple appear  | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # at the right place in the txt:  | 
| 
254
 | 
1470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1435
 | 
   delete $new->{group};  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # for groups inside groups, insert their group attribute  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $new->{group} = $self->{group}->{name}  | 
| 
258
 | 
1470
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
5955
 | 
     if $self->isa('Graph::Easy::Group') && exists $self->{group};  | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
260
 | 
1470
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2256
 | 
   if (defined $self->{origin})  | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
262
 | 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
112
 | 
     $new->{origin} = $self->{origin}->{name};  | 
| 
263
 | 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
201
 | 
     $new->{offset} = join(',', $self->offset());  | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # shorten output for multi-celled nodes  | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # for "rows: 2;" still output "rows: 2;", because it is shorter  | 
| 
268
 | 
1470
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1878
 | 
   if (exists $new->{columns})  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
270
 | 
18
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
80
 | 
     $new->{size} = ($new->{columns}||1) . ',' . ($new->{rows}||1);  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
271
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
     delete $new->{rows};  | 
| 
272
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
     delete $new->{columns};  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # don't output the default size  | 
| 
274
 | 
18
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
44
 | 
     delete $new->{size} if $new->{size} eq '1,1';  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
277
 | 
1470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2667
 | 
   for my $atr (sort keys %$new)  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
279
 | 
542
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
905
 | 
     next if $atr =~ /^border/;                  # handled special  | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
281
 | 
491
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1131
 | 
     $att .= "$atr: $new->{$atr}; ";  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
284
 | 
1470
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
3221
 | 
   if (!$self->isa_cell())  | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
286
 | 
848
 | 
 
 | 
 
 | 
 
 | 
 
 | 
612
 | 
     my $border;  | 
| 
287
 | 
848
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1108
 | 
     if (!exists $self->{autosplit})  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
289
 | 
803
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1574
 | 
       $border = $self->border_attribute();  | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     else  | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       $border = Graph::Easy::_border_attribute(  | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	$attributes->{borderstyle}||'',  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	$attributes->{borderwidth}||'',  | 
| 
296
 | 
45
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
344
 | 
 	$attributes->{bordercolor}||'');  | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # XXX TODO: should do this for all attributes, not only for border  | 
| 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # XXX TODO: this seems wrong anyway  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # don't include default border  | 
| 
303
 | 
848
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
2352
 | 
     $border = '' if ref $g && $g->attribute($class,'border') eq $border;  | 
| 
304
 | 
848
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1517
 | 
     $att .= "border: $border; " if $border ne '';  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
306
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
307
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # if we have a subclass, we probably need to include it  | 
| 
308
 | 
1470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1289
 | 
   my $c = '';  | 
| 
309
 | 
1470
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2756
 | 
   $c = $1 if $class =~ /\.(\w+)/;  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # but we do not need to include it if our group has a nodeclass attribute  | 
| 
312
 | 
1470
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
2999
 | 
   $c = '' if ref($self->{group}) && $self->{group}->attribute('nodeclass') eq $c;  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # include our subclass as attribute  | 
| 
315
 | 
1470
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
2599
 | 
   $att .= "class: $c; " if $c ne '' && $c ne 'anon';  | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # generate attribute text if nec.  | 
| 
318
 | 
1470
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2363
 | 
   $att = ' { ' . $att . '}' if $att ne '';  | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
320
 | 
1470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3169
 | 
   $att;  | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _as_part_txt  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # for edges, we need the name of the part of the first part, not the entire  | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # autosplit text  | 
| 
327
 | 
1403
 | 
 
 | 
 
 | 
  
1403
  
 | 
 
 | 
1095
 | 
   my $self = shift;  | 
| 
328
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
329
 | 
1403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1391
 | 
   my $name = $self->{name};  | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # quote special chars in name  | 
| 
332
 | 
1403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1621
 | 
   $name =~ s/([\[\]\|\{\}\#])/\\$1/g;  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
334
 | 
1403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3222
 | 
   '[ ' .  $name . ' ]';  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub as_pure_txt  | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
339
 | 
1194
 | 
 
 | 
 
 | 
  
1194
  
 | 
  
1
  
 | 
1025
 | 
   my $self = shift;  | 
| 
340
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
341
 | 
1194
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
2661
 | 
   if (exists $self->{autosplit} && defined $self->{autosplit})  | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
343
 | 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
102
 | 
     my $name = $self->{autosplit};  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # quote special chars in name (but not |)  | 
| 
346
 | 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
124
 | 
     $name =~ s/([\[\]\{\}\#])/\\$1/g;  | 
| 
347
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
348
 | 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
200
 | 
     return '[ '. $name .' ]'  | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
351
 | 
1120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1202
 | 
   my $name = $self->{name};  | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # quote special chars in name  | 
| 
354
 | 
1120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1542
 | 
   $name =~ s/([\[\]\|\{\}\#])/\\$1/g;  | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
356
 | 
1120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2423
 | 
   '[ ' .  $name . ' ]';  | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub as_txt  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
361
 | 
23
 | 
 
 | 
 
 | 
  
23
  
 | 
  
1
  
 | 
595
 | 
   my $self = shift;  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
363
 | 
23
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
43
 | 
   if (exists $self->{autosplit})  | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
365
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return '' unless defined $self->{autosplit};  | 
| 
366
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $name = $self->{autosplit};  | 
| 
367
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # quote special chars in name (but not |)  | 
| 
368
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $name =~ s/([\[\]\{\}\#])/\\$1/g;  | 
| 
369
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return '[ ' . $name . ' ]'  | 
| 
370
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
371
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
372
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
   my $name = $self->{name};  | 
| 
373
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
374
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # quote special chars in name  | 
| 
375
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
122
 | 
   $name =~ s/([\[\]\|\{\}\#])/\\$1/g;  | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
377
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
   '[ ' .  $name . ' ]' . $self->attributes_as_txt();  | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
379
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
380
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #############################################################################  | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Graph::Easy::Edge;  | 
| 
383
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
384
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $styles = {  | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   solid => '--',  | 
| 
386
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   dotted => '..',  | 
| 
387
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   double => '==',  | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   'double-dash' => '= ',  | 
| 
389
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   dashed => '- ',  | 
| 
390
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   'dot-dash' => '.-',  | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   'dot-dot-dash' => '..-',  | 
| 
392
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   wave => '~~',  | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   };  | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _as_txt  | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
397
 | 
622
 | 
 
 | 
 
 | 
  
622
  
 | 
 
 | 
520
 | 
   my $self = shift;  | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
399
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # '- Name ' or ''  | 
| 
400
 | 
622
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
789
 | 
   my $n = $self->{att}->{label}; $n = '' unless defined $n;  | 
| 
 
 | 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1059
 | 
    | 
| 
401
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
402
 | 
622
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
489
 | 
   my $left = ' '; $left = ' <' if $self->{bidirectional};  | 
| 
 
 | 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1066
 | 
    | 
| 
403
 | 
622
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
479
 | 
   my $right = '> '; $right = ' ' if $self->{undirected};  | 
| 
 
 | 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
903
 | 
    | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
405
 | 
622
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
1096
 | 
   my $s = $self->style() || 'solid';  | 
| 
406
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
407
 | 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
571
 | 
   my $style = '--';  | 
| 
408
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # suppress border on edges  | 
| 
410
 | 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1386
 | 
   my $suppress = { all => { label => undef } };  | 
| 
411
 | 
622
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1499
 | 
   if ($s =~ /^(bold|bold-dash|broad|wide|invisible)\z/)  | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # output "--> { style: XXX; }"  | 
| 
414
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
     $style = '--';  | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   else  | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
418
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # output "-->" or "..>" etc  | 
| 
419
 | 
607
 | 
 
 | 
 
 | 
 
 | 
 
 | 
724
 | 
     $suppress->{all}->{style} = undef;  | 
| 
420
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
421
 | 
607
 | 
 
 | 
 
 | 
 
 | 
 
 | 
703
 | 
     $style = $styles->{ $s };  | 
| 
422
 | 
607
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
961
 | 
     if (!defined $style)  | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
424
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       require Carp;  | 
| 
425
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       Carp::confess ("Unknown edge style '$s'\n");  | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
429
 | 
622
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1138
 | 
   $n = $style . " $n " if $n ne '';  | 
| 
430
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # make " -  " into " - -  "  | 
| 
432
 | 
622
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
1192
 | 
   $style = $style . $style if $self->{undirected} && substr($style,1,1) eq ' ';  | 
| 
433
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # ' - Name -->' or ' --> ' or ' -- '  | 
| 
435
 | 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1003
 | 
   my $a = $self->attributes_as_txt($suppress) . ' '; $a =~ s/^\s//;  | 
| 
 
 | 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1725
 | 
    | 
| 
436
 | 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2273
 | 
   $left . $n . $style . $right . $a;  | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
439
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
440
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |