line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
############################################################################### |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# LaTeX::TOM::Tree |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
# This package defines a TOM Tree object. |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
############################################################################### |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
package LaTeX::TOM::Tree; |
10
|
|
|
|
|
|
|
|
11
|
10
|
|
|
10
|
|
88
|
use strict; |
|
10
|
|
|
|
|
24
|
|
|
10
|
|
|
|
|
337
|
|
12
|
|
|
|
|
|
|
|
13
|
10
|
|
|
10
|
|
59
|
use Carp qw(croak); |
|
10
|
|
|
|
|
16
|
|
|
10
|
|
|
|
|
20628
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.08'; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# "constructor" |
18
|
|
|
|
|
|
|
# |
19
|
|
|
|
|
|
|
sub _new { |
20
|
186
|
|
|
186
|
|
304
|
my $class = shift; |
21
|
186
|
|
50
|
|
|
362
|
my $nodes = shift || []; # empty array for tree structure |
22
|
|
|
|
|
|
|
|
23
|
186
|
|
|
|
|
411
|
my $self = { |
24
|
|
|
|
|
|
|
nodes => $nodes, |
25
|
|
|
|
|
|
|
}; |
26
|
|
|
|
|
|
|
|
27
|
186
|
|
|
|
|
788
|
return bless $self; |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# make a copy of a tree, recursively |
31
|
|
|
|
|
|
|
# |
32
|
|
|
|
|
|
|
sub copy { |
33
|
13
|
|
|
13
|
0
|
21
|
my $tree = shift; # input tree |
34
|
|
|
|
|
|
|
|
35
|
13
|
|
|
|
|
19
|
my @output; # output array (to become tree) |
36
|
|
|
|
|
|
|
|
37
|
13
|
|
|
|
|
14
|
foreach my $node (@{$tree->{nodes}}) { |
|
13
|
|
|
|
|
24
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# make a copy of the node's hash definition |
40
|
|
|
|
|
|
|
# |
41
|
25
|
|
|
|
|
55
|
my $nodecopy = $node->copy(); |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# grab a copy of children, if any exist |
44
|
|
|
|
|
|
|
# |
45
|
25
|
100
|
|
|
|
45
|
if ($node->{children}) { |
46
|
6
|
|
|
|
|
13
|
my $children = $node->{children}->copy(); |
47
|
6
|
|
|
|
|
18
|
$nodecopy->{children} = $children; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# add hashref to new node to array for this level |
51
|
25
|
|
|
|
|
43
|
push @output, $nodecopy; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# each subtree is a tree |
55
|
13
|
|
|
|
|
39
|
return __PACKAGE__->_new([@output]); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub print { |
59
|
0
|
|
|
0
|
0
|
0
|
shift->_debug_tree(@_, sub { print STDOUT $_[0] }); |
|
0
|
|
|
0
|
|
0
|
|
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
sub _warn { |
62
|
0
|
|
|
0
|
|
0
|
shift->_debug_tree(@_, sub { print STDERR $_[0] }); |
|
0
|
|
|
0
|
|
0
|
|
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Print out the LaTeX "TOM" tree. Good for debugging our parser. |
66
|
|
|
|
|
|
|
# |
67
|
|
|
|
|
|
|
sub _debug_tree { |
68
|
0
|
|
|
0
|
|
0
|
my $tree = shift; |
69
|
0
|
|
|
|
|
0
|
my $output_handler = pop; |
70
|
0
|
|
|
|
|
0
|
my ($level) = @_; |
71
|
|
|
|
|
|
|
|
72
|
0
|
|
0
|
|
|
0
|
$level ||= 0; |
73
|
|
|
|
|
|
|
|
74
|
0
|
|
|
|
|
0
|
foreach my $node (@{$tree->{nodes}}) { |
|
0
|
|
|
|
|
0
|
|
75
|
0
|
|
|
|
|
0
|
my $spacer = ' ' x ($level * 2); |
76
|
|
|
|
|
|
|
|
77
|
0
|
|
|
|
|
0
|
$output_handler->($spacer); |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# print grouping/command info |
80
|
0
|
0
|
|
|
|
0
|
if ($node->{type} eq 'COMMAND') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
81
|
|
|
|
|
|
|
$output_handler->(sprintf |
82
|
|
|
|
|
|
|
"($node->{type}) \\$node->{command} %s @ [$node->{start}, $node->{end}]", |
83
|
0
|
0
|
|
|
|
0
|
$node->{opts} ? "[$node->{opts}]" : "\b", |
84
|
|
|
|
|
|
|
); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
elsif ($node->{type} eq 'GROUP') { |
88
|
0
|
|
|
|
|
0
|
$output_handler->("($node->{type}) [$node->{start}, $node->{end}]"); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
elsif ($node->{type} eq 'ENVIRONMENT') { |
92
|
0
|
|
|
|
|
0
|
$output_handler->("($node->{type}) $node->{class} @ inner [$node->{start}, $node->{end}] outer [$node->{ostart}, $node->{oend}]"); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
elsif ($node->{type} =~ /^(?:TEXT|COMMENT)$/) { |
96
|
0
|
|
|
|
|
0
|
my $space_out = do { |
97
|
0
|
|
|
|
|
0
|
local $_ = "$spacer $node->{type} |"; |
98
|
0
|
|
|
|
|
0
|
s/[A-Z]/ /go; |
99
|
0
|
|
|
|
|
0
|
$_; |
100
|
|
|
|
|
|
|
}; |
101
|
0
|
|
|
|
|
0
|
my $max_len = 80 - length($space_out); |
102
|
0
|
|
|
|
|
0
|
my $print_text = do { |
103
|
0
|
|
|
|
|
0
|
local $_ = $node->{content}; |
104
|
0
|
|
|
|
|
0
|
s/^(.{0,$max_len}).*$/$1/gm; |
105
|
0
|
|
|
|
|
0
|
s/\n/\n$space_out/gs; |
106
|
0
|
|
|
|
|
0
|
$_; |
107
|
|
|
|
|
|
|
}; |
108
|
0
|
|
|
|
|
0
|
$output_handler->("($node->{type}) |$print_text\""); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
0
|
0
|
|
|
|
0
|
$output_handler->(' ** math mode **') if $node->{math}; |
112
|
0
|
0
|
|
|
|
0
|
$output_handler->(' ** plaintext **') if $node->{plaintext}; |
113
|
|
|
|
|
|
|
|
114
|
0
|
|
|
|
|
0
|
$output_handler->("\n"); |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# recur |
117
|
0
|
0
|
|
|
|
0
|
if (defined $node->{children}) { |
118
|
0
|
|
|
|
|
0
|
my ($wrapper) = (caller(1))[3] =~ /.+::(.+)$/; |
119
|
0
|
|
|
|
|
0
|
$node->{children}->$wrapper($level + 1); |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# pull out the plain text (non-math) TEXT nodes. returns an array of strings. |
125
|
|
|
|
|
|
|
# |
126
|
|
|
|
|
|
|
sub plainText { |
127
|
14
|
|
|
14
|
0
|
25
|
my $tree = shift; |
128
|
|
|
|
|
|
|
|
129
|
14
|
|
|
|
|
33
|
my $stringlist = []; |
130
|
|
|
|
|
|
|
|
131
|
14
|
|
|
|
|
20
|
foreach my $node (@{$tree->{nodes}}) { |
|
14
|
|
|
|
|
25
|
|
132
|
|
|
|
|
|
|
|
133
|
38
|
100
|
100
|
|
|
96
|
if ($node->{type} eq 'TEXT' && $node->{plaintext}) { |
134
|
8
|
|
|
|
|
18
|
push @$stringlist, $node->{content}; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
38
|
100
|
|
|
|
63
|
if ($node->{children}) { |
138
|
12
|
|
|
|
|
17
|
push @$stringlist, @{$node->{children}->plainText()}; |
|
12
|
|
|
|
|
32
|
|
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
14
|
|
|
|
|
41
|
return $stringlist; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# Get the plaintext of a LaTeX DOM and whittle it down into a word list |
146
|
|
|
|
|
|
|
# suitable for indexing. |
147
|
|
|
|
|
|
|
# |
148
|
|
|
|
|
|
|
sub indexableText { |
149
|
1
|
|
|
1
|
0
|
2
|
my $tree = shift; |
150
|
|
|
|
|
|
|
|
151
|
1
|
|
|
|
|
3
|
my $pt = $tree->plainText(); |
152
|
1
|
|
|
|
|
4
|
my $text = join (' ', @$pt); |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# kill leftover commands |
155
|
1
|
|
|
|
|
10
|
$text =~ s/\\\w+\*?//gso; |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# kill nonpunctuation |
158
|
1
|
|
|
|
|
4
|
$text =~ s/[^\w\-0-9\s]//gso; |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# kill non-intraword hyphens |
161
|
1
|
|
|
|
|
2
|
$text =~ s/(\W)\-+(\W)/$1 $2/gso; |
162
|
1
|
|
|
|
|
2
|
$text =~ s/(\w)\-+(\W)/$1 $2/gso; |
163
|
1
|
|
|
|
|
2
|
$text =~ s/(\W)\-+(\w)/$1 $2/gso; |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# kill small words |
166
|
1
|
|
|
|
|
4
|
$text =~ s/\b[^\s]{1,2}\b//gso; |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# kill purely numerical "words" |
169
|
1
|
|
|
|
|
4
|
$text =~ s/\b[0-9]+\b//gso; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# compress whitespace |
172
|
1
|
|
|
|
|
4
|
$text =~ s/\s+/ /gso; |
173
|
|
|
|
|
|
|
|
174
|
1
|
|
|
|
|
6
|
return $text; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# Convert tree to LaTeX. If our output doesn't compile to the same final |
178
|
|
|
|
|
|
|
# document, something is amiss (we don't, however, guarantee that the output |
179
|
|
|
|
|
|
|
# TeX will be identical to the input, due to certain normalizations.) |
180
|
|
|
|
|
|
|
# |
181
|
|
|
|
|
|
|
sub toLaTeX { |
182
|
57
|
|
|
57
|
0
|
113
|
my $tree = shift; |
183
|
57
|
|
|
|
|
69
|
my $parent = shift; |
184
|
|
|
|
|
|
|
|
185
|
57
|
|
|
|
|
87
|
my $str = ""; |
186
|
|
|
|
|
|
|
|
187
|
57
|
|
|
|
|
76
|
foreach my $node (@{$tree->{nodes}}) { |
|
57
|
|
|
|
|
100
|
|
188
|
|
|
|
|
|
|
|
189
|
162
|
100
|
66
|
|
|
468
|
if ($node->{type} eq 'TEXT' || |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
190
|
|
|
|
|
|
|
$node->{type} eq 'COMMENT') { |
191
|
|
|
|
|
|
|
|
192
|
118
|
|
|
|
|
204
|
$str .= $node->{content}; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
elsif ($node->{type} eq 'GROUP') { |
196
|
2
|
|
|
|
|
8
|
$str .= '{' . $node->{children}->toLaTeX($node) . '}'; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
elsif ($node->{type} eq 'COMMAND') { |
200
|
23
|
|
|
|
|
51
|
my $cmd = "\\$node->{command}"; |
201
|
23
|
100
|
|
|
|
67
|
$cmd .= "[$node->{opts}]" if (defined $node->{opts}); |
202
|
|
|
|
|
|
|
|
203
|
23
|
100
|
|
|
|
69
|
if ($node->{position} eq 'outer') { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
204
|
21
|
|
|
|
|
95
|
$str .= $cmd . '{' . $node->{children}->toLaTeX($node) . '}'; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
elsif ($node->{position} eq 'inner') { |
207
|
2
|
50
|
33
|
|
|
13
|
if (defined $parent && # dont add superfluous braces |
|
|
|
33
|
|
|
|
|
208
|
|
|
|
|
|
|
$parent->{start} == $node->{start} && |
209
|
|
|
|
|
|
|
$parent->{end} == $node->{end}) { |
210
|
0
|
|
|
|
|
0
|
$str .= $cmd . ' ' . $node->{children}->toLaTeX($node); |
211
|
|
|
|
|
|
|
} else { |
212
|
2
|
|
|
|
|
7
|
$str .= '{' . $cmd . $node->{children}->toLaTeX($node) . '}'; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
elsif ($node->{braces} == 0) { |
216
|
0
|
|
|
|
|
0
|
$str .= $cmd . ' ' . $node->{children}->toLaTeX($node); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
elsif ($node->{type} eq 'ENVIRONMENT') { |
221
|
|
|
|
|
|
|
# handle special math mode envs |
222
|
19
|
|
|
|
|
34
|
my $MATHBRACKETS = \%LaTeX::TOM::MATHBRACKETS; |
223
|
19
|
50
|
|
|
|
48
|
if (defined $MATHBRACKETS->{$node->{class}}) { |
224
|
|
|
|
|
|
|
# print with left and lookup right brace. |
225
|
0
|
|
|
|
|
0
|
$str .= $node->{class} . $node->{children}->toLaTeX($node) . $MATHBRACKETS->{$node->{class}}; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# standard \begin/\end envs |
229
|
|
|
|
|
|
|
else { |
230
|
19
|
|
|
|
|
80
|
$str .= "\\begin{$node->{class}}" . $node->{children}->toLaTeX($node) . "\\end{$node->{class}}"; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
57
|
|
|
|
|
362
|
return $str; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# Augment the nodes in the tree with pointers to all neighboring nodes, so |
239
|
|
|
|
|
|
|
# traversal is easier for the user who is given a lone node. This is a hack, |
240
|
|
|
|
|
|
|
# we should really be maintaining this all along. |
241
|
|
|
|
|
|
|
# |
242
|
|
|
|
|
|
|
# Note that child pointers are already taken care of. |
243
|
|
|
|
|
|
|
# |
244
|
|
|
|
|
|
|
sub listify { |
245
|
111
|
|
|
111
|
0
|
189
|
my $tree = shift; |
246
|
111
|
|
|
|
|
153
|
my $parent = shift; |
247
|
|
|
|
|
|
|
|
248
|
111
|
|
|
|
|
156
|
for (my $i = 0; $i < scalar @{$tree->{nodes}}; $i++) { |
|
410
|
|
|
|
|
877
|
|
249
|
|
|
|
|
|
|
|
250
|
299
|
|
|
|
|
379
|
my $prev = undef; |
251
|
299
|
|
|
|
|
353
|
my $next = undef; |
252
|
|
|
|
|
|
|
|
253
|
299
|
100
|
|
|
|
590
|
$prev = $tree->{nodes}[$i - 1] if ($i > 0); |
254
|
299
|
100
|
|
|
|
417
|
$next = $tree->{nodes}[$i + 1] if ($i + 1 < scalar @{$tree->{nodes}}); |
|
299
|
|
|
|
|
692
|
|
255
|
|
|
|
|
|
|
|
256
|
299
|
|
|
|
|
510
|
$tree->{nodes}[$i]->{'prev'} = $prev; |
257
|
299
|
|
|
|
|
598
|
$tree->{nodes}[$i]->{'next'} = $next; |
258
|
299
|
|
|
|
|
431
|
$tree->{nodes}[$i]->{'parent'} = $parent; |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# recur, with parent info |
261
|
299
|
100
|
|
|
|
618
|
if ($tree->{nodes}[$i]->{children}) { |
262
|
84
|
|
|
|
|
254
|
$tree->{nodes}[$i]->{children}->listify($tree->{nodes}[$i]); |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
############################################################################### |
268
|
|
|
|
|
|
|
# "Tree walking" methods. |
269
|
|
|
|
|
|
|
# |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub getTopLevelNodes { |
272
|
2
|
|
|
2
|
0
|
6
|
my $tree = shift; |
273
|
|
|
|
|
|
|
|
274
|
2
|
|
|
|
|
4
|
return @{$tree->{nodes}}; |
|
2
|
|
|
|
|
18
|
|
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
sub getAllNodes { |
278
|
14
|
|
|
14
|
0
|
64
|
my $tree = shift; |
279
|
|
|
|
|
|
|
|
280
|
14
|
|
|
|
|
19
|
my @nodelist; |
281
|
|
|
|
|
|
|
|
282
|
14
|
|
|
|
|
18
|
foreach my $node (@{$tree->{nodes}}) { |
|
14
|
|
|
|
|
34
|
|
283
|
|
|
|
|
|
|
|
284
|
38
|
|
|
|
|
58
|
push @nodelist, $node; |
285
|
|
|
|
|
|
|
|
286
|
38
|
100
|
|
|
|
74
|
if ($node->{children}) { |
287
|
12
|
|
|
|
|
18
|
push @nodelist, @{$node->{children}->getAllNodes()}; |
|
12
|
|
|
|
|
26
|
|
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
14
|
|
|
|
|
47
|
return [@nodelist]; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub getNodesByCondition { |
295
|
35
|
|
|
35
|
0
|
58
|
my $tree = shift; |
296
|
35
|
|
|
|
|
43
|
my $condition = shift; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# XXX rt #48551 - string eval no longer supported (12/08/2009) |
299
|
35
|
50
|
|
|
|
90
|
unless (ref $condition eq 'CODE') { |
300
|
0
|
|
|
|
|
0
|
croak 'getNodesByCondition(): code reference expected'; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
35
|
|
|
|
|
43
|
my @nodelist; |
304
|
|
|
|
|
|
|
|
305
|
35
|
|
|
|
|
42
|
foreach my $node (@{$tree->{nodes}}) { |
|
35
|
|
|
|
|
70
|
|
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
# evaluate the perl code condition and if the result evaluates to true, |
308
|
|
|
|
|
|
|
# push this node |
309
|
|
|
|
|
|
|
# |
310
|
93
|
100
|
|
|
|
141
|
if ($condition->($node)) { |
311
|
8
|
|
|
|
|
13
|
push @nodelist, $node; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
93
|
100
|
|
|
|
238
|
if ($node->{children}) { |
315
|
29
|
|
|
|
|
39
|
push @nodelist, @{$node->{children}->getNodesByCondition($condition)}; |
|
29
|
|
|
|
|
74
|
|
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
35
|
|
|
|
|
92
|
return [@nodelist]; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub getCommandNodesByName { |
323
|
2
|
|
|
2
|
0
|
18
|
my $tree = shift; |
324
|
2
|
|
|
|
|
5
|
my $name = shift; |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
return $tree->getNodesByCondition( |
327
|
29
|
|
100
|
29
|
|
41
|
sub { my $node = shift; return ($node->{type} eq 'COMMAND' && $node->{command} eq $name); } |
|
29
|
|
|
|
|
85
|
|
328
|
2
|
|
|
|
|
28
|
); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
sub getEnvironmentsByName { |
332
|
2
|
|
|
2
|
0
|
794
|
my $tree = shift; |
333
|
2
|
|
|
|
|
4
|
my $name = shift; |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
return $tree->getNodesByCondition( |
336
|
29
|
|
66
|
29
|
|
38
|
sub { my $node = shift; return ($node->{type} eq 'ENVIRONMENT' && $node->{class} eq $name); } |
|
29
|
|
|
|
|
85
|
|
337
|
2
|
|
|
|
|
15
|
); |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub getFirstNode { |
341
|
0
|
|
|
0
|
0
|
|
my $tree = shift; |
342
|
0
|
|
|
|
|
|
return $tree->{nodes}[0]; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
1; |