line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::RecordStream::Operation::annotate; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = "4.0.23"; |
4
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
7510
|
use strict; |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
123
|
|
6
|
|
|
|
|
|
|
|
7
|
2
|
|
|
2
|
|
15
|
use base qw(App::RecordStream::Operation); |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
663
|
|
8
|
|
|
|
|
|
|
|
9
|
2
|
|
|
2
|
|
935
|
use App::RecordStream::Executor::Getopt; |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
71
|
|
10
|
2
|
|
|
2
|
|
16
|
use App::RecordStream::Executor; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
50
|
|
11
|
2
|
|
|
2
|
|
12
|
use App::RecordStream::Record; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
2728
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub init { |
14
|
4
|
|
|
4
|
0
|
15
|
my $this = shift; |
15
|
4
|
|
|
|
|
13
|
my $args = shift; |
16
|
|
|
|
|
|
|
|
17
|
4
|
|
|
|
|
52
|
my $key_groups = App::RecordStream::KeyGroups->new(); |
18
|
|
|
|
|
|
|
|
19
|
4
|
|
|
|
|
63
|
my $executor_options = App::RecordStream::Executor::Getopt->new(); |
20
|
|
|
|
|
|
|
my $spec = { |
21
|
|
|
|
|
|
|
$executor_options->arguments(), |
22
|
4
|
|
|
4
|
|
7515
|
'keys|k=s' => sub { $key_groups->add_groups($_[1]); }, |
23
|
4
|
|
|
|
|
27
|
}; |
24
|
|
|
|
|
|
|
|
25
|
4
|
|
|
|
|
53
|
$this->parse_options($args, $spec, ['bundling']); |
26
|
|
|
|
|
|
|
|
27
|
4
|
|
|
|
|
43
|
my $expression = $executor_options->get_string($args); |
28
|
4
|
|
|
|
|
121
|
my $executor = App::RecordStream::Executor->new(<<" CODE"); |
29
|
|
|
|
|
|
|
$expression |
30
|
|
|
|
|
|
|
; # Safe from a trailing comment in \$expression |
31
|
|
|
|
|
|
|
\$r |
32
|
|
|
|
|
|
|
CODE |
33
|
|
|
|
|
|
|
|
34
|
4
|
50
|
|
|
|
33
|
if ( ! $key_groups->has_any_group() ) { |
35
|
0
|
|
|
|
|
0
|
die "Must specify at least one --key, maybe you want recs-xform instead?\n"; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
4
|
|
|
|
|
24
|
$this->{'EXECUTOR'} = $executor; |
39
|
4
|
|
|
|
|
16
|
$this->{'KEYGROUP'} = $key_groups; |
40
|
4
|
|
|
|
|
173
|
$this->{'ANNOTATIONS'} = {}; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub accept_record { |
44
|
19
|
|
|
19
|
0
|
58
|
my $this = shift; |
45
|
19
|
|
|
|
|
49
|
my $record = shift; |
46
|
|
|
|
|
|
|
|
47
|
19
|
|
|
|
|
119
|
my $specs = $this->{'KEYGROUP'}->get_keyspecs_for_record($record); |
48
|
|
|
|
|
|
|
|
49
|
19
|
|
|
|
|
50
|
my @values; |
50
|
19
|
|
|
|
|
84
|
foreach my $key (sort @$specs) { |
51
|
19
|
|
|
|
|
50
|
my $value = ${$record->guess_key_from_spec($key)}; |
|
19
|
|
|
|
|
93
|
|
52
|
19
|
|
|
|
|
83
|
push @values, $value; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# Join keys with the ASCII record separator character (30) |
56
|
19
|
|
|
|
|
87
|
my $synthetic_key = join(chr(30), @values); |
57
|
|
|
|
|
|
|
|
58
|
19
|
100
|
|
|
|
93
|
if ( exists $this->{'ANNOTATIONS'}->{$synthetic_key} ) { |
59
|
12
|
|
|
|
|
65
|
$this->apply_annotation($synthetic_key, $record); |
60
|
12
|
|
|
|
|
86
|
$this->push_record($record); |
61
|
12
|
|
|
|
|
114
|
return 1; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
7
|
|
|
|
|
27
|
my $executor = $this->{'EXECUTOR'}; |
65
|
|
|
|
|
|
|
|
66
|
7
|
|
|
|
|
24
|
my $store = {}; |
67
|
|
|
|
|
|
|
|
68
|
7
|
|
|
|
|
49
|
my $hash = create_recorder({$record->as_hash()}, $store); |
69
|
|
|
|
|
|
|
|
70
|
7
|
|
|
|
|
82
|
my $new_record = App::RecordStream::Record->new($hash); |
71
|
|
|
|
|
|
|
|
72
|
7
|
|
|
|
|
57
|
my $returned_record = $executor->execute_code($new_record); |
73
|
|
|
|
|
|
|
|
74
|
7
|
|
|
|
|
40
|
$this->{'ANNOTATIONS'}->{$synthetic_key} = $store; |
75
|
|
|
|
|
|
|
|
76
|
7
|
|
|
|
|
65
|
$this->push_record($returned_record); |
77
|
|
|
|
|
|
|
|
78
|
7
|
|
|
|
|
114
|
return 1; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub apply_annotation { |
82
|
12
|
|
|
12
|
0
|
35
|
my $this = shift; |
83
|
12
|
|
|
|
|
30
|
my $annotation_key = shift; |
84
|
12
|
|
|
|
|
28
|
my $record = shift; |
85
|
|
|
|
|
|
|
|
86
|
12
|
|
|
|
|
42
|
my $stores = $this->{'ANNOTATIONS'}->{$annotation_key}; |
87
|
|
|
|
|
|
|
|
88
|
12
|
|
|
|
|
62
|
foreach my $keyspec (keys %$stores) { |
89
|
16
|
|
|
|
|
49
|
my $value = $stores->{$keyspec}; |
90
|
16
|
|
|
|
|
36
|
${$record->guess_key_from_spec($keyspec)} = $value; |
|
16
|
|
|
|
|
71
|
|
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub add_help_types { |
95
|
4
|
|
|
4
|
0
|
17
|
my $this = shift; |
96
|
4
|
|
|
|
|
34
|
$this->use_help_type('snippet'); |
97
|
4
|
|
|
|
|
24
|
$this->use_help_type('keyspecs'); |
98
|
4
|
|
|
|
|
24
|
$this->use_help_type('keygroups'); |
99
|
4
|
|
|
|
|
19
|
$this->use_help_type('keys'); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub usage { |
103
|
0
|
|
|
0
|
0
|
0
|
my $this = shift; |
104
|
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
0
|
my $options = [ |
106
|
|
|
|
|
|
|
App::RecordStream::Executor::options_help(), |
107
|
|
|
|
|
|
|
['keys', 'Keys to match records by, maybe specified multiple times, may be a keygroup or keyspec'], |
108
|
|
|
|
|
|
|
]; |
109
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
0
|
my $args_string = $this->options_string($options); |
111
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
0
|
return <
|
113
|
|
|
|
|
|
|
Usage: recs-annotate [] |
114
|
|
|
|
|
|
|
__FORMAT_TEXT__ |
115
|
|
|
|
|
|
|
is evaluated as perl on each record of input (or records from |
116
|
|
|
|
|
|
|
) with \$r set to a App::RecordStream::Record object and \$line set |
117
|
|
|
|
|
|
|
to the current line number (starting at 1). Records are analyzed for |
118
|
|
|
|
|
|
|
changes, those changes are applied to each successive record that matches |
119
|
|
|
|
|
|
|
--keys |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
Only use this script if you have --keys fields that are repeated, otherwise |
122
|
|
|
|
|
|
|
recs-xform will be faster |
123
|
|
|
|
|
|
|
__FORMAT_TEXT__ |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
IMPORTANT SNIPPET NOTE |
126
|
|
|
|
|
|
|
__FORMAT_TEXT__ |
127
|
|
|
|
|
|
|
Because of the way annotations are recorded, you cannot use UNSHIFT or |
128
|
|
|
|
|
|
|
SPLICE on array refs that already exist in the record you are modifiying. |
129
|
|
|
|
|
|
|
Additionally, deletes, removes, unshifts, and other 'removing' operations |
130
|
|
|
|
|
|
|
will not apply to later records. If you need this behavior, consider using |
131
|
|
|
|
|
|
|
recs-xform |
132
|
|
|
|
|
|
|
__FORMAT_TEXT__ |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
$args_string |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Examples: |
137
|
|
|
|
|
|
|
# Annotate records with IPs with hostnames, only doing lookup once |
138
|
|
|
|
|
|
|
... | recs-annotate --key ip '{{hostname}} = `host {{ip}}`' |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# Record md5sums of files |
141
|
|
|
|
|
|
|
... | recs-annotate --key filename '{{md5}} = `md5sum {{filename}}`' |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Add url contents to records |
144
|
|
|
|
|
|
|
... | recs-annotate --key url '{{contents}} = `curl {{url}}`' |
145
|
|
|
|
|
|
|
USAGE |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub create_recorder { |
149
|
19
|
|
|
19
|
0
|
57
|
my $data = shift; |
150
|
19
|
|
|
|
|
48
|
my $store = shift; |
151
|
19
|
|
|
|
|
46
|
my $current_keyspec = shift; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
#Nothing todo, what happened here? |
154
|
19
|
50
|
66
|
|
|
109
|
if ( ref($data) ne 'HASH' && ref($data) ne 'ARRAY' ) { |
155
|
0
|
|
|
|
|
0
|
warn "create_recorder called on non HASH or ARRAY data!\n"; |
156
|
0
|
|
|
|
|
0
|
return $data; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
19
|
|
|
|
|
119
|
my $recorder = KeyspecRecorder->new($current_keyspec, $store); |
160
|
|
|
|
|
|
|
|
161
|
19
|
|
|
|
|
57
|
my $spec = ''; |
162
|
19
|
100
|
|
|
|
124
|
if ( defined $current_keyspec ) { |
163
|
12
|
|
|
|
|
41
|
$spec = $current_keyspec . '/'; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
19
|
100
|
|
|
|
89
|
if ( ref($data) eq 'HASH' ) { |
167
|
13
|
|
|
|
|
32
|
my %new_hash; |
168
|
13
|
|
|
|
|
73
|
foreach my $key (keys %$data) { |
169
|
43
|
|
|
|
|
128
|
my $value = $data->{$key}; |
170
|
43
|
|
|
|
|
98
|
my $new_value = $value; |
171
|
43
|
100
|
100
|
|
|
250
|
if ( ref($value) eq 'HASH' || ref($value) eq 'ARRAY' ) { |
172
|
12
|
|
|
|
|
71
|
my $new_data = create_recorder($value, $store, $spec . $key); |
173
|
12
|
|
|
|
|
43
|
$new_value = $new_data; |
174
|
|
|
|
|
|
|
} |
175
|
43
|
|
|
|
|
214
|
$new_hash{$key} = $new_value; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
13
|
|
|
|
|
40
|
my %hash; |
179
|
13
|
|
|
|
|
144
|
my $recorder = tie %hash, 'RecordingHash', \%new_hash, $recorder; |
180
|
|
|
|
|
|
|
|
181
|
13
|
|
|
|
|
64
|
return \%hash; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
else { #Must be an array |
184
|
6
|
|
|
|
|
17
|
my @new_array; |
185
|
6
|
|
|
|
|
20
|
my $index = 0; |
186
|
6
|
|
|
|
|
24
|
foreach my $value (@$data) { |
187
|
6
|
|
|
|
|
20
|
my $new_value = $value; |
188
|
6
|
50
|
33
|
|
|
49
|
if ( ref($value) eq 'HASH' || ref($value) eq 'ARRAY' ) { |
189
|
0
|
|
|
|
|
0
|
my $new_data = create_recorder($value, $store, $spec . '#' . $index); |
190
|
0
|
|
|
|
|
0
|
$new_value = $new_data; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
6
|
|
|
|
|
32
|
push @new_array, $new_value; |
194
|
6
|
|
|
|
|
19
|
$index++; |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
6
|
|
|
|
|
17
|
my @array; |
198
|
6
|
|
|
|
|
65
|
my $recorder = tie @array, 'RecordingArray', \@new_array, $recorder; |
199
|
|
|
|
|
|
|
|
200
|
6
|
|
|
|
|
31
|
return \@array; |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
1; |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
package KeyspecRecorder; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub new { |
211
|
19
|
|
|
19
|
|
54
|
my $class = shift; |
212
|
19
|
|
|
|
|
54
|
my $current_keyspec = shift; |
213
|
19
|
|
|
|
|
40
|
my $store = shift; |
214
|
|
|
|
|
|
|
|
215
|
19
|
|
|
|
|
114
|
my $this = bless { |
216
|
|
|
|
|
|
|
KEYSPEC => $current_keyspec, |
217
|
|
|
|
|
|
|
STORES => $store, |
218
|
|
|
|
|
|
|
}, $class; |
219
|
|
|
|
|
|
|
|
220
|
19
|
|
|
|
|
70
|
return $this; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub get_stores { |
224
|
8
|
|
|
8
|
|
24
|
my $this = shift; |
225
|
8
|
|
|
|
|
178
|
return $this->{'STORES'}; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub get_keyspec { |
229
|
14
|
|
|
14
|
|
35
|
my $this = shift; |
230
|
14
|
|
|
|
|
78
|
return $this->{'KEYSPEC'}; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub add_store { |
234
|
8
|
|
|
8
|
|
25
|
my $this = shift; |
235
|
8
|
|
|
|
|
23
|
my $sub_spec = shift; |
236
|
8
|
|
|
|
|
22
|
my $value = shift; |
237
|
|
|
|
|
|
|
|
238
|
8
|
|
|
|
|
22
|
my $spec = $sub_spec; |
239
|
8
|
100
|
|
|
|
33
|
if ( defined $this->get_keyspec() ) { |
240
|
6
|
|
|
|
|
20
|
$spec = $this->get_keyspec() . '/' . $sub_spec; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
8
|
|
|
|
|
36
|
$this->get_stores()->{$spec} = $value; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
1; |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
package RecordingHash; |
249
|
|
|
|
|
|
|
|
250
|
2
|
|
|
2
|
|
1660
|
use Tie::Hash; |
|
2
|
|
|
|
|
2911
|
|
|
2
|
|
|
|
|
80
|
|
251
|
2
|
|
|
2
|
|
17
|
use base qw(Tie::ExtraHash); |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
995
|
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub TIEHASH { |
254
|
13
|
|
|
13
|
|
49
|
my $class = shift; |
255
|
13
|
|
|
|
|
41
|
my $hash = shift; |
256
|
13
|
|
|
|
|
33
|
my $recorder = shift; |
257
|
|
|
|
|
|
|
|
258
|
13
|
|
|
|
|
59
|
my $this = bless [ $hash, $recorder ], $class; |
259
|
13
|
|
|
|
|
61
|
return $this; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub STORE { |
263
|
2
|
|
|
2
|
|
12
|
my ($this, $key, $value) = @_; |
264
|
2
|
|
|
|
|
9
|
my ($hash, $data) = @$this; |
265
|
2
|
|
|
|
|
8
|
$hash->{$key} = $value; |
266
|
2
|
|
|
|
|
13
|
$this->get_recorder()->add_store($key, $value); |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub get_recorder { |
270
|
2
|
|
|
2
|
|
13
|
return $_[0]->[1]; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
package RecordingArray; |
274
|
|
|
|
|
|
|
|
275
|
2
|
|
|
2
|
|
1123
|
use Tie::Array; |
|
2
|
|
|
|
|
3544
|
|
|
2
|
|
|
|
|
73
|
|
276
|
2
|
|
|
2
|
|
17
|
use base qw(Tie::Array); |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
1030
|
|
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
#sub TIEARRAY { bless [], $_[0] } |
279
|
|
|
|
|
|
|
sub TIEARRAY { |
280
|
6
|
|
|
6
|
|
21
|
my $class = shift; |
281
|
6
|
|
|
|
|
17
|
my $array = shift; |
282
|
6
|
|
|
|
|
15
|
my $recorder = shift; |
283
|
|
|
|
|
|
|
|
284
|
6
|
|
|
|
|
28
|
my $this = bless [ $array, $recorder ], $class; |
285
|
6
|
|
|
|
|
29
|
return $this; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
#sub STORE { $_[0]->[$_[1]] = $_[2] } |
289
|
2
|
|
|
2
|
|
37
|
sub STORE { my ($this, $index, $value) = @_; my ($array, $recorder) = @$this; |
|
2
|
|
|
|
|
9
|
|
290
|
2
|
|
|
|
|
7
|
$array->[$index] = $value; |
291
|
2
|
|
|
|
|
12
|
$this->get_recorder()->add_store('#' . $index, $value); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub PUSH { |
295
|
2
|
|
|
2
|
|
35
|
my ($this, @new_items) = @_; |
296
|
2
|
|
|
|
|
9
|
my ($array, $recorder) = @$this; |
297
|
2
|
|
|
|
|
8
|
my $start_index = scalar @$array; |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
#First modify the array |
300
|
2
|
|
|
|
|
10
|
push @$array, @new_items; |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
#Now record the new indexes |
303
|
2
|
|
|
|
|
7
|
my $num_to_push = scalar @new_items; |
304
|
2
|
|
|
|
|
6
|
my $item_index = 0; |
305
|
|
|
|
|
|
|
|
306
|
2
|
|
|
|
|
16
|
foreach my $index ($start_index..($start_index+$num_to_push-1)) { |
307
|
4
|
|
|
|
|
29
|
$recorder->add_store('#' . $index, $new_items[$item_index]); |
308
|
4
|
|
|
|
|
86
|
$item_index++; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# These methods are copied from Tie::StdArray, Except modified to work on the |
313
|
|
|
|
|
|
|
# first array, like ExtraHash (there is no ExtraArray) |
314
|
16
|
|
|
16
|
|
12285
|
sub FETCHSIZE { scalar @{$_[0]->[0]} } |
|
16
|
|
|
|
|
84
|
|
315
|
0
|
|
|
0
|
|
0
|
sub STORESIZE { $#{$_[0]->[0]} = $_[1]-1 } |
|
0
|
|
|
|
|
0
|
|
316
|
10
|
|
|
10
|
|
99
|
sub FETCH { $_[0]->[0]->[$_[1]] } |
317
|
0
|
|
|
0
|
|
0
|
sub CLEAR { @{$_[0]->[0]} = () } |
|
0
|
|
|
|
|
0
|
|
318
|
0
|
|
|
0
|
|
0
|
sub POP { pop(@{$_[0]->[0]}) } |
|
0
|
|
|
|
|
0
|
|
319
|
0
|
|
|
0
|
|
0
|
sub SHIFT { shift(@{$_[0]->[0]}) } |
|
0
|
|
|
|
|
0
|
|
320
|
0
|
|
|
0
|
|
0
|
sub EXISTS { exists $_[0]->[0]->[$_[1]] } |
321
|
0
|
|
|
0
|
|
0
|
sub DELETE { delete $_[0]->[0]->[$_[1]] } |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# Die on unsupported methods |
324
|
0
|
|
|
0
|
|
0
|
sub UNSHIFT { die "UNSHIFT Unsupported in annotate, consider using xform" } |
325
|
0
|
|
|
0
|
|
0
|
sub SPLICE { die "SPLICE Unsupported in annotate, consider using xform" } |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub get_recorder { |
328
|
2
|
|
|
2
|
|
13
|
return $_[0][1]; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
1; |